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