]> mj.ucw.cz Git - libucw.git/blob - ucw/base64.c
Updated TODO
[libucw.git] / ucw / base64.c
1 /*
2  *      UCW Library -- Base 64 Encoding & Decoding
3  *
4  *      (c) 2002, Robert Spalek <robert@ucw.cz>
5  *
6  *      This software may be freely distributed and used according to the terms
7  *      of the GNU Lesser General Public License.
8  */
9
10 #undef LOCAL_DEBUG
11
12 #include <ucw/lib.h>
13 #include <ucw/base64.h>
14 #include <ucw/threads.h>
15
16 #include <string.h>
17
18 static const byte base64_table[] =
19         { 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',
20           'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',
21           'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
22           'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',
23           '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', '+', '/', '\0'
24         };
25 static const byte base64_pad = '=';
26
27 uns
28 base64_encode(byte *dest, const byte *src, uns len)
29 {
30         const byte *current = src;
31         uns i = 0;
32
33         while (len > 2) { /* keep going until we have less than 24 bits */
34                 dest[i++] = base64_table[current[0] >> 2];
35                 dest[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
36                 dest[i++] = base64_table[((current[1] & 0x0f) << 2) + (current[2] >> 6)];
37                 dest[i++] = base64_table[current[2] & 0x3f];
38
39                 current += 3;
40                 len -= 3; /* we just handle 3 octets of data */
41         }
42
43         /* now deal with the tail end of things */
44         if (len != 0) {
45                 dest[i++] = base64_table[current[0] >> 2];
46                 if (len > 1) {
47                         dest[i++] = base64_table[((current[0] & 0x03) << 4) + (current[1] >> 4)];
48                         dest[i++] = base64_table[(current[1] & 0x0f) << 2];
49                         dest[i++] = base64_pad;
50                 }
51                 else {
52                         dest[i++] = base64_table[(current[0] & 0x03) << 4];
53                         dest[i++] = base64_pad;
54                         dest[i++] = base64_pad;
55                 }
56         }
57         return i;
58 }
59
60 /* as above, but backwards. :) */
61 uns
62 base64_decode(byte *dest, const byte *src, uns len)
63 {
64         const byte *current = src;
65         uns ch;
66         uns i = 0, j = 0;
67         static byte reverse_table[256];
68         static uns table_built = 0;
69
70         if (table_built == 0) {
71                 ucwlib_lock();
72                 for(ch = 0; ch < 256; ch++) {
73                         byte *chp = strchr(base64_table, ch);
74                         if(chp) {
75                                 reverse_table[ch] = chp - base64_table;
76                         } else {
77                                 reverse_table[ch] = 0xff;
78                         }
79                 }
80                 table_built = 1;
81                 ucwlib_unlock();
82         }
83
84         /* run through the whole string, converting as we go */
85         ch = 0;
86         while (len > 0) {
87                 len--;
88                 ch = *current++;
89                 if (ch == base64_pad) break;
90
91                 /* When Base64 gets POSTed, all pluses are interpreted as spaces.
92                    This line changes them back.  It's not exactly the Base64 spec,
93                    but it is completely compatible with it (the spec says that
94                    spaces are invalid).  This will also save many people considerable
95                    headache.  - Turadg Aleahmad <turadg@wise.berkeley.edu>
96                  */
97
98                 if (ch == ' ') ch = '+';
99
100                 ch = reverse_table[ch];
101                 if (ch == 0xff) continue;
102
103                 switch(i % 4) {
104                 case 0:
105                         dest[j] = ch << 2;
106                         break;
107                 case 1:
108                         dest[j++] |= ch >> 4;
109                         dest[j] = (ch & 0x0f) << 4;
110                         break;
111                 case 2:
112                         dest[j++] |= ch >>2;
113                         dest[j] = (ch & 0x03) << 6;
114                         break;
115                 case 3:
116                         dest[j++] |= ch;
117                         break;
118                 }
119                 i++;
120         }
121         return j;
122 }