[4.0] Use strip (instead of eu-strip) to support --strip-debug of *.so at build time
[platform/upstream/rpm.git] / rpmio / base64.c
1 /* base64 encoder/decoder based on public domain implementation
2  * by Chris Venter */
3
4 #include <arpa/inet.h>
5 #include <stdlib.h>
6
7 #include <rpm/rpmbase64.h>
8
9
10 static char base64_encode_value(char value_in)
11 {
12         static const char encoding[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
13         if (value_in > 63) return '=';
14         return encoding[(int)value_in];
15 }
16
17 static char *base64_encode_block(const char *plaintext_in, int length_in, char *codechar)
18 {
19         const char *plainchar = plaintext_in;
20         const char *const plaintextend = plaintext_in + length_in;
21         char result;
22         char fragment;
23         
24         while (1) {
25                 if (plainchar == plaintextend) {
26                         return codechar;
27                 }
28                 fragment = *plainchar++;
29                 result = (fragment & 0x0fc) >> 2;
30                 *codechar++ = base64_encode_value(result);
31                 result = (fragment & 0x003) << 4;
32                 if (plainchar == plaintextend)
33                 {
34                         *codechar++ = base64_encode_value(result);
35                         *codechar++ = '=';
36                         *codechar++ = '=';
37                         return codechar;
38                 }
39                 fragment = *plainchar++;
40                 result |= (fragment & 0x0f0) >> 4;
41                 *codechar++ = base64_encode_value(result);
42                 result = (fragment & 0x00f) << 2;
43                 if (plainchar == plaintextend)
44                 {
45                         *codechar++ = base64_encode_value(result);
46                         *codechar++ = '=';
47                         return codechar;
48                 }
49                 fragment = *plainchar++;
50                 result |= (fragment & 0x0c0) >> 6;
51                 *codechar++ = base64_encode_value(result);
52                 result  = (fragment & 0x03f) >> 0;
53                 *codechar++ = base64_encode_value(result);
54         }
55         /* control should not reach here */
56         return codechar;
57 }
58
59 #define BASE64_DEFAULT_LINE_LENGTH 64
60
61 char *rpmBase64Encode(const void *data, size_t len, int linelen)
62 {
63         size_t encodedlen;
64         const char *dataptr = data;
65         char *output;
66         char *outptr;
67         
68         if (data == NULL)
69                 return NULL;
70
71         if (linelen < 0)
72                 linelen = BASE64_DEFAULT_LINE_LENGTH;
73
74         linelen /= 4;
75         encodedlen = ((len + 2) / 3) * 4;
76         if (linelen > 0) {
77                 encodedlen += encodedlen/(linelen * 4) + 1;
78         }
79         ++encodedlen; /* for zero termination */
80
81         output = malloc(encodedlen);
82         if (output == NULL)
83                 return NULL;
84                 
85         outptr = output;        
86         while (len > 0) {
87                 if (linelen > 0 && len > linelen * 3) {
88                         outptr = base64_encode_block(dataptr, linelen * 3, outptr);
89                         len -= linelen * 3;
90                         dataptr += linelen * 3;
91                 } else {
92                         outptr = base64_encode_block(dataptr, len, outptr);
93                         len = 0;
94                 }
95                 if (linelen > 0) {
96                         *outptr++ = '\n';
97                 }
98         }
99         *outptr = '\0';
100         return output;
101 }
102
103 static int base64_decode_value(unsigned char value_in)
104 {
105         static const int decoding[] = {62,-1,-1,-1,63,52,53,54,55,56,57,58,59,60,61,-1,-1,-1,-2,-1,-1,-1,0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,-1,-1,-1,-1,-1,-1,26,27,28,29,30,31,32,33,34,35,36,37,38,39,40,41,42,43,44,45,46,47,48,49,50,51};
106         value_in -= 43;
107         if (value_in > sizeof(decoding)/sizeof(int))
108                 return -1;
109         return decoding[value_in];
110 }
111
112 static size_t base64_decode_block(const char *code_in, const size_t length_in, char *plaintext_out)
113 {
114         const char *codechar = code_in;
115         char *plainchar = plaintext_out;
116         int fragment;
117         
118         *plainchar = 0;
119         
120         while (1)
121         {
122                 do {
123                         if (codechar == code_in+length_in)
124                         {
125                                 return plainchar - plaintext_out;
126                         }
127                         fragment = base64_decode_value(*codechar++);
128                 } while (fragment < 0);
129                 *plainchar    = (char)((fragment & 0x03f) << 2);
130
131                 do {
132                         if (codechar == code_in+length_in)
133                         {
134                                 return plainchar - plaintext_out;
135                         }
136                         fragment = base64_decode_value(*codechar++);
137                 } while (fragment < 0);
138                 *plainchar++ |= (char)((fragment & 0x030) >> 4);
139                 *plainchar    = (char)((fragment & 0x00f) << 4);
140
141                 do {
142                         if (codechar == code_in+length_in)
143                         {
144                                 return plainchar - plaintext_out;
145                         }
146                         fragment = base64_decode_value(*codechar++);
147                 } while (fragment < 0);
148                 *plainchar++ |= (char)((fragment & 0x03c) >> 2);
149                 *plainchar    = (char)((fragment & 0x003) << 6);
150
151                 do {
152                         if (codechar == code_in+length_in)
153                         {
154                                 return plainchar - plaintext_out;
155                         }
156                         fragment = base64_decode_value(*codechar++);
157                 } while (fragment < 0);
158                 *plainchar++   |= (char)(fragment & 0x03f);
159         }
160         /* control should not reach here */
161         return plainchar - plaintext_out;
162 }
163
164 int rpmBase64Decode(const char *in, void **out, size_t *outlen)
165 {
166         size_t outcnt = 0;
167         const char *inptr = in;
168
169         *out = NULL;
170
171         if (in == NULL) {
172                 return 1;
173         }
174         
175         while (*inptr != '\0') {
176                 /* assume all ASCII control chars as whitespace */
177                 if (*inptr > 32) {
178                         if (base64_decode_value(*inptr) != -1) {
179                                 ++outcnt;
180                         } else {
181                                 return 3;
182                         }
183                 }
184                 ++inptr;
185         }
186         
187         if (outcnt % 4 != 0)
188                 return 2;
189         
190         outcnt = (outcnt / 4) * 3;
191         
192         *out = malloc(outcnt + 1); /* base64_decode_block can write one extra character */
193         
194         if (*out == NULL)
195                 return 4;
196         
197         *outlen = base64_decode_block(in, inptr - in, *out);
198
199         return 0;
200 }
201
202 #define CRC24_INIT 0xb704ce
203 #define CRC24_POLY 0x1864cfb
204
205 char *rpmBase64CRC(const unsigned char *data, size_t len)
206 {
207         uint32_t crc = CRC24_INIT;
208         int i;
209
210         while (len--) {
211                 crc ^= (*data++) << 16;
212                 for (i = 0; i < 8; i++) {
213                         crc <<= 1;
214                         if (crc & 0x1000000)
215                                 crc ^= CRC24_POLY;
216                 }
217         }
218         crc = htonl(crc & 0xffffff);
219         data = (unsigned char *)&crc;
220         ++data;
221         return rpmBase64Encode(data, 3, 0);
222 }
223
224 #ifdef BASE64_TEST
225 #include <stdio.h>
226 #include <string.h>
227
228 int main(int argc, char *argv[]) 
229 {
230         static char tst[]="wtrt8122čLýáj\x20s ~ýhž\t4\x02šjjmBvž^%$RTš#á.íěj\x1hčýčŤc+";
231         char *encoded;
232         void *decoded;
233         size_t size;
234         int err;
235         printf("Original: %lu\n%s\n", sizeof(tst)-1, tst);
236         encoded = rpmBase64Encode(tst, sizeof(tst)-1, 64);
237         printf("Encoded: %lu\n%s\n", strlen(encoded), encoded);
238         if ((err = rpmBase64Decode(encoded, &decoded, &size)) != 0) {
239                 fprintf(stderr, "Error in decode: %d\n", err);
240                 return 1;
241         }
242         printf("Decoded:\n%.*s\n", (int)size, (char *)decoded);
243         if (size != sizeof(tst)-1) {
244                 fprintf(stderr, "Size differs orig: %lu new: %lu\n", sizeof(tst)-1, size);
245                 return 1;
246         }
247         if (memcmp(tst, decoded, size) != 0) {
248                 fprintf(stderr, "Decoded data differs.\n");
249                 return 1;
250         }
251         fprintf(stderr, "OK\n");
252         return 0;
253 }
254 #endif
255