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
42static unsigned char	map[UCHAR_MAX+1];
43
44static const char	alp[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
45
46/*
47 * mime base64 encode
48 */
49
50ssize_t
51base64encode(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
161ssize_t
162base64decode(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