1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1985-2010 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Common Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.opensource.org/licenses/cpl1.0.txt *
11 * (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <gsf@research.att.com> *
18 * David Korn <dgk@research.att.com> *
19 * Phong Vo <kpv@research.att.com> *
20 * *
21 ***********************************************************************/
22 #pragma prototyped
23 /*
24 * mime base64 encode/decode
25 *
26 * Glenn Fowler
27 * David Korn
28 * AT&T Research
29 */
30
31 #include <ast.h>
32
33 #define PAD '='
34
35 #define B64_UC 3
36 #define B64_EC 4
37 #define B64_CHUNK 15
38 #define B64_PAD 64
39 #define B64_SPC 65
40 #define B64_IGN 66
41
42 static unsigned char map[UCHAR_MAX+1];
43
44 static const char alp[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45
46 /*
47 * mime base64 encode
48 */
49
50 ssize_t
base64encode(const void * fb,size_t fz,void ** fn,void * tb,size_t tz,void ** tn)51 base64encode(const void* fb, size_t fz, void** fn, void* tb, size_t tz, void** tn)
52 {
53 register unsigned char* fp;
54 register unsigned char* tp;
55 register unsigned char* fe;
56 register unsigned char* te;
57 register unsigned char* tc;
58 register unsigned char* m;
59 register unsigned long b;
60 size_t n;
61 unsigned char tmp[B64_EC * B64_CHUNK];
62
63 m = (unsigned char*)alp;
64 fp = fe = (unsigned char*)fb;
65 if (fz >= 3)
66 {
67 n = fz % 3;
68 fe += fz - n;
69 fz = n;
70 }
71 if (tp = (unsigned char*)tb)
72 {
73 te = tp + tz - B64_EC + 1;
74 n = 0;
75 }
76 else
77 {
78 if (fn)
79 *fn = fp;
80 if (tn)
81 *tn = 0;
82 tp = tmp;
83 te = tp + sizeof(tmp) - B64_EC + 1;
84 n = 1;
85 }
86 for (;;)
87 {
88 tc = tp + B64_EC * B64_CHUNK;
89 do
90 {
91 if (fp >= fe)
92 goto done;
93 if (tp >= te)
94 {
95 if (fn)
96 *fn = fp;
97 if (tn)
98 *tn = tp;
99 n = tp - (unsigned char*)tb + 1;
100 tp = tmp;
101 te = tp + sizeof(tmp) - B64_EC + 1;
102 }
103 b = *fp++ << 16;
104 b |= *fp++ << 8;
105 b |= *fp++;
106 *tp++ = m[b >> 18];
107 *tp++ = m[(b >> 12) & 077];
108 *tp++ = m[(b >> 6) & 077];
109 *tp++ = m[b & 077];
110 } while (tp < tc);
111 if (n)
112 {
113 n += tp - tmp + (fp < fe);
114 tp = tmp;
115 }
116 else
117 *tp++ = '\n';
118 }
119 done:
120 if (fz)
121 {
122 if (tp >= te)
123 {
124 if (fn)
125 *fn = fp;
126 if (tn)
127 *tn = tp;
128 n = tp - (unsigned char*)tb + 1;
129 tp = tmp;
130 te = tp + sizeof(tmp) - B64_EC + 1;
131 }
132 b = *fp++ << 16;
133 if (fz == 2)
134 b |= *fp++ << 8;
135 *tp++ = m[b >> 18];
136 *tp++ = m[(b >> 12) & 077];
137 *tp++ = (fz == 2) ? m[(b >> 6) & 077] : PAD;
138 *tp++ = PAD;
139 }
140 if (n)
141 n += (tp - tmp) - 1;
142 else
143 {
144 if (tp > (unsigned char*)tb && *(tp - 1) == '\n')
145 tp--;
146 if (tp < te)
147 *tp = 0;
148 n = tp - (unsigned char*)tb;
149 if (tn)
150 *tn = tp;
151 if (fn)
152 *fn = fp;
153 }
154 return n;
155 }
156
157 /*
158 * mime base64 decode
159 */
160
161 ssize_t
base64decode(const void * fb,size_t fz,void ** fn,void * tb,size_t tz,void ** tn)162 base64decode(const void* fb, size_t fz, void** fn, void* tb, size_t tz, void** tn)
163 {
164 register unsigned char* fp;
165 register unsigned char* tp;
166 register unsigned char* fe;
167 register unsigned char* te;
168 register unsigned char* tx;
169 register unsigned char* m;
170 register int c;
171 register int state;
172 register unsigned long v;
173 unsigned char* fc;
174 ssize_t n;
175
176 if (!(m = map)[0])
177 {
178 memset(m, B64_IGN, sizeof(map));
179 for (tp = (unsigned char*)alp; c = *tp; tp++)
180 m[c] = tp - (unsigned char*)alp;
181 m[PAD] = B64_PAD;
182 m[' '] = m['\t'] = m['\n'] = B64_SPC;
183 }
184 fp = (unsigned char*)fb;
185 fe = fp + fz;
186 if (tp = (unsigned char*)tb)
187 {
188 te = tp + tz;
189 if (tz > 2)
190 tz = 2;
191 tx = te - tz;
192 n = 0;
193 }
194 else
195 {
196 te = tx = tp;
197 n = 1;
198 }
199 for (;;)
200 {
201 fc = fp;
202 state = 0;
203 v = 0;
204 while (fp < fe)
205 {
206 if ((c = m[*fp++]) < 64)
207 {
208 v = (v << 6) | c;
209 if (++state == 4)
210 {
211 if (tp >= tx)
212 {
213 if (n)
214 n += 3;
215 else
216 {
217 n = tp - (unsigned char*)tb + 4;
218 if (tp < te)
219 {
220 *tp++ = (v >> 16);
221 if (tp < te)
222 {
223 *tp++ = (v >> 8);
224 if (tp < te)
225 *tp++ = (v);
226 }
227 }
228 if (tn)
229 *tn = tp;
230 if (fn)
231 *fn = fc;
232 }
233 }
234 else
235 {
236 *tp++ = (v >> 16);
237 *tp++ = (v >> 8);
238 *tp++ = (v);
239 }
240 fc = fp;
241 state = 0;
242 v = 0;
243 }
244 }
245 else if (c == B64_PAD)
246 break;
247 }
248 switch (state)
249 {
250 case 0:
251 goto done;
252 case 2:
253 if (tp < te)
254 *tp++ = v >> 4;
255 else if (n)
256 n++;
257 else
258 {
259 n = tp - (unsigned char*)tb + 2;
260 if (tn)
261 *tn = tp;
262 if (fn)
263 *fn = fc;
264 }
265 break;
266 case 3:
267 if (tp < te)
268 {
269 *tp++ = v >> 10;
270 if (tp < te)
271 *tp++ = v >> 2;
272 else
273 {
274 n = tp - (unsigned char*)tb + 2;
275 if (tn)
276 *tn = tp;
277 if (fn)
278 *fn = fc;
279 }
280 }
281 else if (n)
282 n += 2;
283 else
284 {
285 n = tp - (unsigned char*)tb + 3;
286 if (tn)
287 *tn = tp;
288 if (fn)
289 *fn = fc;
290 }
291 break;
292 }
293 while (fp < fe && ((c = m[*fp++]) == B64_PAD || c == B64_SPC));
294 if (fp >= fe || c >= 64)
295 break;
296 fp--;
297 }
298 done:
299 if (n)
300 n--;
301 else
302 {
303 if (tp < te)
304 *tp = 0;
305 n = tp - (unsigned char*)tb;
306 if (fn)
307 *fn = fp;
308 if (tn)
309 *tn = tp;
310 }
311 return n;
312 }
313