xref: /titanic_41/usr/src/lib/libast/common/string/base64.c (revision cde2885fdf538266ee2a3b08dee2d5075ce8fa2b)
1 /***********************************************************************
2 *                                                                      *
3 *               This software is part of the ast package               *
4 *          Copyright (c) 1985-2008 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
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 		b = *fp++ << 16;
123 		if (fz == 2)
124 			b |= *fp++ << 8;
125 		*tp++ = m[b >> 18];
126 		*tp++ = m[(b >> 12) & 077];
127 		*tp++ = (fz == 2) ? m[(b >> 6) & 077] : PAD;
128 		*tp++ = PAD;
129 	}
130 	if (n)
131 		n += (tp - tmp) - 1;
132 	else
133 	{
134 		if (tp > (unsigned char*)tb && *(tp - 1) == '\n')
135 			tp--;
136 		if (tp < te)
137 			*tp = 0;
138 		n = tp - (unsigned char*)tb;
139 		if (tn)
140 			*tn = tp;
141 		if (fn)
142 			*fn = fp;
143 	}
144 	return n;
145 }
146 
147 /*
148  * mime base64 decode
149  */
150 
151 ssize_t
152 base64decode(const void* fb, size_t fz, void** fn, void* tb, size_t tz, void** tn)
153 {
154 	register unsigned char*	fp;
155 	register unsigned char*	tp;
156 	register unsigned char*	fe;
157 	register unsigned char*	te;
158 	register unsigned char*	tx;
159 	register unsigned char*	m;
160 	register int		c;
161 	register int		state;
162 	register unsigned long	v;
163 	unsigned char*		fc;
164 	ssize_t			n;
165 
166 	if (!(m = map)[0])
167 	{
168 		memset(m, B64_IGN, sizeof(map));
169 		for (tp = (unsigned char*)alp; c = *tp; tp++)
170 			m[c] =  tp - (unsigned char*)alp;
171 		m[PAD] = B64_PAD;
172 		m[' '] = m['\t'] = m['\n'] = B64_SPC;
173 	}
174 	fp = (unsigned char*)fb;
175 	fe = fp + fz;
176 	if (tp = (unsigned char*)tb)
177 	{
178 		te = tp + tz;
179 		if (tz > 2)
180 			tz = 2;
181 		tx = te - tz;
182 		n = 0;
183 	}
184 	else
185 	{
186 		te = tx = tp;
187 		n = 1;
188 	}
189 	for (;;)
190 	{
191 		fc = fp;
192 		state = 0;
193 		v = 0;
194 		while (fp < fe)
195 		{
196 			if ((c = m[*fp++]) < 64)
197 			{
198 				v = (v << 6) | c;
199 				if (++state == 4)
200 				{
201 					if (tp >= tx)
202 					{
203 						if (n)
204 							n += 3;
205 						else
206 						{
207 							n = tp - (unsigned char*)tb + 4;
208 							if (tp < te)
209 							{
210 								*tp++ = (v >> 16);
211 								if (tp < te)
212 								{
213 									*tp++ = (v >> 8);
214 									if (tp < te)
215 										*tp++ = (v);
216 								}
217 							}
218 							if (tn)
219 								*tn = tp;
220 							if (fn)
221 								*fn = fc;
222 						}
223 					}
224 					else
225 					{
226 						*tp++ = (v >> 16);
227 						*tp++ = (v >> 8);
228 						*tp++ = (v);
229 					}
230 					fc = fp;
231 					state = 0;
232 					v = 0;
233 				}
234 			}
235 			else if (c == B64_PAD)
236 				break;
237 		}
238 		switch (state)
239 		{
240 		case 0:
241 			goto done;
242 		case 2:
243 			if (tp < te)
244 				*tp++ = v >> 4;
245 			else if (n)
246 				n++;
247 			else
248 			{
249 				n = tp - (unsigned char*)tb + 2;
250 				if (tn)
251 					*tn = tp;
252 				if (fn)
253 					*fn = fc;
254 			}
255 			break;
256 		case 3:
257 			if (tp < te)
258 			{
259 				*tp++ = v >> 10;
260 				if (tp < te)
261 					*tp++ = v >> 2;
262 				else
263 				{
264 					n = tp - (unsigned char*)tb + 2;
265 					if (tn)
266 						*tn = tp;
267 					if (fn)
268 						*fn = fc;
269 				}
270 			}
271 			else if (n)
272 				n += 2;
273 			else
274 			{
275 				n = tp - (unsigned char*)tb + 3;
276 				if (tn)
277 					*tn = tp;
278 				if (fn)
279 					*fn = fc;
280 			}
281 			break;
282 		}
283 		while (fp < fe && ((c = m[*fp++]) == B64_PAD || c == B64_SPC));
284 		if (fp >= fe || c >= 64)
285 			break;
286 		fp--;
287 	}
288  done:
289 	if (n)
290 		n--;
291 	else
292 	{
293 		if (tp < te)
294 			*tp = 0;
295 		n = tp - (unsigned char*)tb;
296 		if (fn)
297 			*fn = fp;
298 		if (tn)
299 			*tn = tp;
300 	}
301 	return n;
302 }
303