1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2011 AT&T Intellectual Property          *
5 *                      and is licensed under the                       *
6 *                 Eclipse Public License, Version 1.0                  *
7 *                    by AT&T Intellectual Property                     *
8 *                                                                      *
9 *                A copy of the License is available at                 *
10 *          http://www.eclipse.org/org/documents/epl-v10.html           *
11 *         (with md5 checksum b35adb5213ca9657e911e9befb180842)         *
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