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