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