]> mj.ucw.cz Git - libucw.git/blob - ucw/base64.c
Tests: xtypes-test sets an explicit timezone
[libucw.git] / ucw / base64.c
1 /*
2  *      UCW Library -- Base 64 Encoding & Decoding
3  *
4  *      (c) 2002, Robert Spalek <robert@ucw.cz>
5  *      (c) 2018, Pavel Charvat <pchar@ucw.cz>
6  *
7  *      This software may be freely distributed and used according to the terms
8  *      of the GNU Lesser General Public License.
9  */
10
11 #undef LOCAL_DEBUG
12
13 #include <ucw/lib.h>
14 #include <ucw/base64.h>
15
16 const byte base64_enc_table[65] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
17 const byte base64_dec_table[256] = {
18   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
19   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
20   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x3e, 0x80, 0x80, 0x80, 0x3f,
21   0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x80, 0x80, 0x80, 0x40, 0x80, 0x80,
22   0x80, 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e,
23   0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x80, 0x80, 0x80, 0x80, 0x80,
24   0x80, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28,
25   0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x80, 0x80, 0x80, 0x80, 0x80,
26   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
27   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
28   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
29   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
30   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
31   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
32   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
33   0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80, 0x80,
34 };
35
36 uint base64_encode(byte *dest, const byte *src, uint len)
37 {
38   const byte *ptr = src;
39   const byte *end = src + len;
40   byte *out = dest;
41
42   /* keep going until we have less than 24 bits */
43   if (end - ptr >= 3)
44     for (const byte *x = end - 2; ptr < x; )
45       {
46         out[0] = base64_enc_table[ptr[0] >> 2];
47         out[1] = base64_enc_table[((ptr[0] & 0x03) << 4) + (ptr[1] >> 4)];
48         out[2] = base64_enc_table[((ptr[1] & 0x0f) << 2) + (ptr[2] >> 6)];
49         out[3] = base64_enc_table[ptr[2] & 0x3f];
50         out += 4;
51         ptr += 3;
52       }
53
54   /* now deal with the tail end of things */
55   if (ptr != end)
56     {
57       out[0] = base64_enc_table[ptr[0] >> 2];
58       out[3] = BASE64_PADDING;
59       if (end - ptr >= 2)
60         {
61           out[1] = base64_enc_table[((ptr[0] & 0x03) << 4) + (ptr[1] >> 4)];
62           out[2] = base64_enc_table[(ptr[1] & 0x0f) << 2];
63         }
64       else
65         {
66           out[1] = base64_enc_table[(ptr[0] & 0x03) << 4];
67           out[2] = BASE64_PADDING;
68         }
69       out += 4;
70     }
71
72   return out - dest;
73 }
74
75 uint base64_decode(byte *dest, const byte *src, uint len)
76 {
77   const byte *ptr = src;
78   const byte *end = src + len;
79   byte *out = dest;
80   while (1)
81     {
82       uint val, ch;
83       do
84         {
85           if (ptr == end || (ch = base64_dec_table[*ptr++]) == BASE64_DEC_PADDING)
86             goto end;
87         }
88       while (ch > BASE64_DEC_PADDING);
89       val = ch;
90       do
91         {
92           if (ptr == end || (ch = base64_dec_table[*ptr++]) == BASE64_DEC_PADDING)
93             goto end; // Broken base64 encoding, we only have 6 bits
94         }
95       while (ch > BASE64_DEC_PADDING);
96       val = (val << 6) | ch;
97       do
98         {
99           if (ptr == end || (ch = base64_dec_table[*ptr++]) == BASE64_DEC_PADDING)
100             {
101               out[0] = val >> 4;
102               out += 1;
103               goto end;
104             }
105         }
106       while (ch > BASE64_DEC_PADDING);
107       val = (val << 6) | ch;
108       do
109         {
110           if (ptr == end || (ch = base64_dec_table[*ptr++]) == BASE64_DEC_PADDING)
111             {
112               out[0] = val >> 10;
113               out[1] = val >> 2;
114               out += 2;
115               goto end;
116             }
117         }
118       while (ch > BASE64_DEC_PADDING);
119       val = (val << 6) | ch;
120       out[0] = val >> 16;
121       out[1] = val >> 8;
122       out[2] = val;
123       out += 3;
124     }
125 end:
126   return out - dest;
127 }