]> git.sur5r.net Git - bacula/bacula/blob - bacula/src/lib/base64.c
Backport from BEE
[bacula/bacula] / bacula / src / lib / base64.c
1 /*
2    Bacula® - The Network Backup Solution
3
4    Copyright (C) 2000-2014 Free Software Foundation Europe e.V.
5
6    The main author of Bacula is Kern Sibbald, with contributions from many
7    others, a complete list can be found in the file AUTHORS.
8
9    You may use this file and others of this release according to the
10    license defined in the LICENSE file, which includes the Affero General
11    Public License, v3.0 ("AGPLv3") and some additional permissions and
12    terms pursuant to its AGPLv3 Section 7.
13
14    Bacula® is a registered trademark of Kern Sibbald.
15 */
16 /*
17  *   Generic base 64 input and output routines
18  *
19  *    Written by Kern E. Sibbald, March MM.
20  *
21  *   Version $Id$
22  */
23
24
25 #include "bacula.h"
26
27
28 #ifdef TEST_MODE
29 #include <glob.h>
30 #endif
31
32
33 static uint8_t const base64_digits[64] =
34 {
35   'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
36   'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
37   'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
38   'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
39   '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/'
40 };
41
42 static int base64_inited = 0;
43 static uint8_t base64_map[256];
44
45
46 /* Initialize the Base 64 conversion routines */
47 void
48 base64_init(void)
49 {
50    int i;
51    memset(base64_map, 0, sizeof(base64_map));
52    for (i=0; i<64; i++)
53       base64_map[(uint8_t)base64_digits[i]] = i;
54    base64_inited = 1;
55 }
56
57 /* Convert a value to base64 characters.
58  * The result is stored in where, which
59  * must be at least 8 characters long.
60  *
61  * Returns the number of characters
62  * stored (not including the EOS).
63  */
64 int
65 to_base64(int64_t value, char *where)
66 {
67    uint64_t val;
68    int i = 0;
69    int n;
70
71    /* Handle negative values */
72    if (value < 0) {
73       where[i++] = '-';
74       value = -value;
75    }
76
77    /* Determine output size */
78    val = value;
79    do {
80       val >>= 6;
81       i++;
82    } while (val);
83    n = i;
84
85    /* Output characters */
86    val = value;
87    where[i] = 0;
88    do {
89       where[--i] = base64_digits[val & (uint64_t)0x3F];
90       val >>= 6;
91    } while (val);
92    return n;
93 }
94
95 /*
96  * Convert the Base 64 characters in where to
97  * a value. No checking is done on the validity
98  * of the characters!!
99  *
100  * Returns the value.
101  */
102 int
103 from_base64(int64_t *value, char *where)
104 {
105    uint64_t val = 0;
106    int i, neg;
107
108    if (!base64_inited)
109       base64_init();
110    /* Check if it is negative */
111    i = neg = 0;
112    if (where[i] == '-') {
113       i++;
114       neg = 1;
115    }
116    /* Construct value */
117    while (where[i] != 0 && where[i] != ' ') {
118       val <<= 6;
119       val += base64_map[(uint8_t)where[i++]];
120    }
121
122    *value = neg ? -(int64_t)val : (int64_t)val;
123    return i;
124 }
125
126
127 /*
128  * Encode binary data in bin of len bytes into
129  * buf as base64 characters.
130  *
131  * If compatible is true, the bin_to_base64 routine will be compatible
132  * with what the rest of the world uses.
133  *
134  *  Returns: the number of characters stored not
135  *           including the EOS
136  */
137 int
138 bin_to_base64(char *buf, int buflen, char *bin, int binlen, int compatible)
139 {
140    uint32_t reg, save, mask;
141    int rem, i;
142    int j = 0;
143
144    reg = 0;
145    rem = 0;
146    buflen--;                       /* allow for storing EOS */
147    for (i=0; i < binlen; ) {
148       if (rem < 6) {
149          reg <<= 8;
150          if (compatible) {
151             reg |= (uint8_t)bin[i++];
152          } else {
153             reg |= (int8_t)bin[i++];
154          }
155          rem += 8;
156       }
157       save = reg;
158       reg >>= (rem - 6);
159       if (j < buflen) {
160          buf[j++] = base64_digits[reg & 0x3F];
161       }
162       reg = save;
163       rem -= 6;
164    }
165    if (rem && j < buflen) {
166       mask = (1 << rem) - 1;
167       if (compatible) {
168          buf[j++] = base64_digits[(reg & mask) << (6 - rem)];
169       } else {
170          buf[j++] = base64_digits[reg & mask];
171       }
172    }
173    buf[j] = 0;
174    return j;
175 }
176
177 /*
178  * Decode base64 data in bin of len bytes into
179  * buf as binary characters.
180  *
181  * the base64_to_bin routine is compatible with what the rest of the world
182  * uses.
183  *
184  *  Returns: the number of characters stored not
185  *           including the EOS
186  */
187 int base64_to_bin(char *dest, int dest_size, char *src, int srclen)
188 {
189    int nprbytes;
190    uint8_t *bufout;
191    uint8_t *bufplain = (uint8_t*) dest;
192    const uint8_t *bufin;
193
194    if (!base64_inited)
195       base64_init();
196
197    if (dest_size < (((srclen + 3) / 4) * 3)) {
198       /* dest buffer too small */
199       *dest = 0;
200       return 0;
201    }
202
203    bufin = (const uint8_t *) src;
204    while ((*bufin != ' ') && (srclen != 0)) {
205       bufin++;
206       srclen--;
207    }
208
209    nprbytes = bufin - (const uint8_t *) src;
210    bufin = (const uint8_t *) src;
211    bufout = (uint8_t *) bufplain;
212
213    while (nprbytes > 4)
214    {
215       *(bufout++) = (base64_map[bufin[0]] << 2 | base64_map[bufin[1]] >> 4);
216       *(bufout++) = (base64_map[bufin[1]] << 4 | base64_map[bufin[2]] >> 2);
217       *(bufout++) = (base64_map[bufin[2]] << 6 | base64_map[bufin[3]]);
218       bufin += 4;
219       nprbytes -= 4;
220    }
221
222    /* Bacula base64 strings are not always padded with = */
223    if (nprbytes > 1) {
224       *(bufout++) = (base64_map[bufin[0]] << 2 | base64_map[bufin[1]] >> 4);
225    }
226    if (nprbytes > 2) {
227       *(bufout++) = (base64_map[bufin[1]] << 4 | base64_map[bufin[2]] >> 2);
228    }
229    if (nprbytes > 3) {
230       *(bufout++) = (base64_map[bufin[2]] << 6 | base64_map[bufin[3]]);
231    }
232    *bufout = 0;
233
234    return (bufout - (uint8_t *) dest);
235 }
236
237 #ifdef BIN_TEST
238 int main(int argc, char *argv[])
239 {
240    int xx = 0;
241    int len;
242    char buf[100];
243    char junk[100];
244    int i;
245
246 #ifdef xxxx
247    for (i=0; i < 1000; i++) {
248       bin_to_base64(buf, sizeof(buf), (char *)&xx, 4, true);
249       printf("xx=%s\n", buf);
250       xx++;
251    }
252 #endif
253    junk[0] = 0xFF;
254    for (i=1; i<100; i++) {
255       junk[i] = junk[i-1]-1;
256    }
257    len = bin_to_base64(buf, sizeof(buf), junk, 16, true);
258    printf("len=%d junk=%s\n", len, buf);
259
260    strcpy(junk, "This is a sample stringa");
261    len = bin_to_base64(buf, sizeof(buf), junk, strlen(junk), true);
262    buf[len] = 0;
263    base64_to_bin(junk, sizeof(junk), buf, len);
264    printf("buf=<%s>\n", junk);
265    return 0;
266 }
267 #endif
268
269 #ifdef TEST_MODE
270 static int errfunc(const char *epath, int eernoo)
271 {
272   printf("in errfunc\n");
273   return 1;
274 }
275
276
277 /*
278  * Test the base64 routines by encoding and decoding
279  * lstat() packets.
280  */
281 int main(int argc, char *argv[])
282 {
283    char where[500];
284    int i;
285    glob_t my_glob;
286    char *fname;
287    struct stat statp;
288    struct stat statn;
289    int debug_level = 0;
290    char *p;
291    int32_t j;
292    time_t t = 1028712799;
293
294    if (argc > 1 && strcmp(argv[1], "-v") == 0)
295       debug_level++;
296
297    base64_init();
298
299    my_glob.gl_offs = 0;
300    glob("/etc/grub.conf", GLOB_MARK, errfunc, &my_glob);
301
302    for (i=0; my_glob.gl_pathv[i]; i++) {
303       fname = my_glob.gl_pathv[i];
304       if (lstat(fname, &statp) < 0) {
305          berrno be;
306          printf("Cannot stat %s: %s\n", fname, be.bstrerror(errno));
307          continue;
308       }
309       encode_stat(where, &statp, sizeof(statp), 0, 0);
310
311       printf("Encoded stat=%s\n", where);
312
313 #ifdef xxx
314       p = where;
315       p += to_base64((int64_t)(statp.st_atime), p);
316       *p++ = ' ';
317       p += to_base64((int64_t)t, p);
318       printf("%s %s\n", fname, where);
319
320       printf("%s %lld\n", "st_dev", (int64_t)statp.st_dev);
321       printf("%s %lld\n", "st_ino", (int64_t)statp.st_ino);
322       printf("%s %lld\n", "st_mode", (int64_t)statp.st_mode);
323       printf("%s %lld\n", "st_nlink", (int64_t)statp.st_nlink);
324       printf("%s %lld\n", "st_uid", (int64_t)statp.st_uid);
325       printf("%s %lld\n", "st_gid", (int64_t)statp.st_gid);
326       printf("%s %lld\n", "st_rdev", (int64_t)statp.st_rdev);
327       printf("%s %lld\n", "st_size", (int64_t)statp.st_size);
328       printf("%s %lld\n", "st_blksize", (int64_t)statp.st_blksize);
329       printf("%s %lld\n", "st_blocks", (int64_t)statp.st_blocks);
330       printf("%s %lld\n", "st_atime", (int64_t)statp.st_atime);
331       printf("%s %lld\n", "st_mtime", (int64_t)statp.st_mtime);
332       printf("%s %lld\n", "st_ctime", (int64_t)statp.st_ctime);
333 #endif
334
335       if (debug_level)
336          printf("%s: len=%d val=%s\n", fname, strlen(where), where);
337
338       decode_stat(where, &statn, sizeof(statn), &j);
339
340       if (statp.st_dev != statn.st_dev ||
341           statp.st_ino != statn.st_ino ||
342           statp.st_mode != statn.st_mode ||
343           statp.st_nlink != statn.st_nlink ||
344           statp.st_uid != statn.st_uid ||
345           statp.st_gid != statn.st_gid ||
346           statp.st_rdev != statn.st_rdev ||
347           statp.st_size != statn.st_size ||
348           statp.st_blksize != statn.st_blksize ||
349           statp.st_blocks != statn.st_blocks ||
350           statp.st_atime != statn.st_atime ||
351           statp.st_mtime != statn.st_mtime ||
352           statp.st_ctime != statn.st_ctime) {
353
354          printf("%s: %s\n", fname, where);
355          encode_stat(where, &statn, sizeof(statn), 0, 0);
356          printf("%s: %s\n", fname, where);
357          printf("NOT EQAL\n");
358       }
359
360    }
361    globfree(&my_glob);
362
363    printf("%d files examined\n", i);
364
365    to_base64(UINT32_MAX, where);
366    printf("UINT32_MAX=%s\n", where);
367
368    return 0;
369 }
370 #endif