xref: /onnv-gate/usr/src/lib/libast/common/string/base64.c (revision 12068:08a39a083754)
14887Schin /***********************************************************************
24887Schin *                                                                      *
34887Schin *               This software is part of the ast package               *
4*12068SRoger.Faulkner@Oracle.COM *          Copyright (c) 1985-2010 AT&T Intellectual Property          *
54887Schin *                      and is licensed under the                       *
64887Schin *                  Common Public License, Version 1.0                  *
78462SApril.Chin@Sun.COM *                    by AT&T Intellectual Property                     *
84887Schin *                                                                      *
94887Schin *                A copy of the License is available at                 *
104887Schin *            http://www.opensource.org/licenses/cpl1.0.txt             *
114887Schin *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
124887Schin *                                                                      *
134887Schin *              Information and Software Systems Research               *
144887Schin *                            AT&T Research                             *
154887Schin *                           Florham Park NJ                            *
164887Schin *                                                                      *
174887Schin *                 Glenn Fowler <gsf@research.att.com>                  *
184887Schin *                  David Korn <dgk@research.att.com>                   *
194887Schin *                   Phong Vo <kpv@research.att.com>                    *
204887Schin *                                                                      *
214887Schin ***********************************************************************/
224887Schin #pragma prototyped
234887Schin /*
244887Schin  * mime base64 encode/decode
254887Schin  *
264887Schin  * Glenn Fowler
274887Schin  * David Korn
284887Schin  * AT&T Research
294887Schin  */
304887Schin 
314887Schin #include <ast.h>
324887Schin 
334887Schin #define PAD		'='
344887Schin 
354887Schin #define B64_UC		3
364887Schin #define B64_EC		4
374887Schin #define B64_CHUNK	15
384887Schin #define B64_PAD		64
394887Schin #define B64_SPC		65
404887Schin #define B64_IGN		66
414887Schin 
424887Schin static unsigned char	map[UCHAR_MAX+1];
434887Schin 
444887Schin static const char	alp[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
454887Schin 
464887Schin /*
474887Schin  * mime base64 encode
484887Schin  */
494887Schin 
504887Schin ssize_t
base64encode(const void * fb,size_t fz,void ** fn,void * tb,size_t tz,void ** tn)514887Schin base64encode(const void* fb, size_t fz, void** fn, void* tb, size_t tz, void** tn)
524887Schin {
534887Schin 	register unsigned char*	fp;
544887Schin 	register unsigned char*	tp;
554887Schin 	register unsigned char*	fe;
564887Schin 	register unsigned char*	te;
574887Schin 	register unsigned char*	tc;
584887Schin 	register unsigned char*	m;
594887Schin 	register unsigned long	b;
604887Schin 	size_t			n;
614887Schin 	unsigned char		tmp[B64_EC * B64_CHUNK];
624887Schin 
634887Schin 	m = (unsigned char*)alp;
644887Schin 	fp = fe = (unsigned char*)fb;
654887Schin 	if (fz >= 3)
664887Schin 	{
674887Schin 		n = fz % 3;
684887Schin 		fe += fz - n;
694887Schin 		fz = n;
704887Schin 	}
714887Schin 	if (tp = (unsigned char*)tb)
724887Schin 	{
734887Schin 		te = tp + tz - B64_EC + 1;
744887Schin 		n = 0;
754887Schin 	}
764887Schin 	else
774887Schin 	{
784887Schin 		if (fn)
794887Schin 			*fn = fp;
804887Schin 		if (tn)
814887Schin 			*tn = 0;
824887Schin 		tp = tmp;
834887Schin 		te = tp + sizeof(tmp) - B64_EC + 1;
844887Schin 		n = 1;
854887Schin 	}
864887Schin 	for (;;)
874887Schin 	{
884887Schin 		tc = tp + B64_EC * B64_CHUNK;
894887Schin 		do
904887Schin 		{
914887Schin 			if (fp >= fe)
924887Schin 				goto done;
934887Schin 			if (tp >= te)
944887Schin 			{
954887Schin 				if (fn)
964887Schin 					*fn = fp;
974887Schin 				if (tn)
984887Schin 					*tn = tp;
994887Schin 				n = tp - (unsigned char*)tb + 1;
1004887Schin 				tp = tmp;
1014887Schin 				te = tp + sizeof(tmp) - B64_EC + 1;
1024887Schin 			}
1034887Schin 			b = *fp++ << 16;
1044887Schin 			b |= *fp++ << 8;
1054887Schin 			b |= *fp++;
1064887Schin 			*tp++ = m[b >> 18];
1074887Schin 			*tp++ = m[(b >> 12) & 077];
1084887Schin 			*tp++ = m[(b >> 6) & 077];
1094887Schin 			*tp++ = m[b & 077];
1104887Schin 		} while (tp < tc);
1114887Schin 		if (n)
1124887Schin 		{
1134887Schin 			n += tp - tmp + (fp < fe);
1144887Schin 			tp = tmp;
1154887Schin 		}
1164887Schin 		else
1174887Schin 			*tp++ = '\n';
1184887Schin 	}
1194887Schin  done:
1204887Schin 	if (fz)
1214887Schin 	{
122*12068SRoger.Faulkner@Oracle.COM 		if (tp >= te)
123*12068SRoger.Faulkner@Oracle.COM 		{
124*12068SRoger.Faulkner@Oracle.COM 			if (fn)
125*12068SRoger.Faulkner@Oracle.COM 				*fn = fp;
126*12068SRoger.Faulkner@Oracle.COM 			if (tn)
127*12068SRoger.Faulkner@Oracle.COM 				*tn = tp;
128*12068SRoger.Faulkner@Oracle.COM 			n = tp - (unsigned char*)tb + 1;
129*12068SRoger.Faulkner@Oracle.COM 			tp = tmp;
130*12068SRoger.Faulkner@Oracle.COM 			te = tp + sizeof(tmp) - B64_EC + 1;
131*12068SRoger.Faulkner@Oracle.COM 		}
1324887Schin 		b = *fp++ << 16;
1334887Schin 		if (fz == 2)
1344887Schin 			b |= *fp++ << 8;
1354887Schin 		*tp++ = m[b >> 18];
1364887Schin 		*tp++ = m[(b >> 12) & 077];
1374887Schin 		*tp++ = (fz == 2) ? m[(b >> 6) & 077] : PAD;
1384887Schin 		*tp++ = PAD;
1394887Schin 	}
1404887Schin 	if (n)
1414887Schin 		n += (tp - tmp) - 1;
1424887Schin 	else
1434887Schin 	{
1444887Schin 		if (tp > (unsigned char*)tb && *(tp - 1) == '\n')
1454887Schin 			tp--;
1464887Schin 		if (tp < te)
1474887Schin 			*tp = 0;
1484887Schin 		n = tp - (unsigned char*)tb;
1494887Schin 		if (tn)
1504887Schin 			*tn = tp;
1514887Schin 		if (fn)
1524887Schin 			*fn = fp;
1534887Schin 	}
1544887Schin 	return n;
1554887Schin }
1564887Schin 
1574887Schin /*
1584887Schin  * mime base64 decode
1594887Schin  */
1604887Schin 
1614887Schin ssize_t
base64decode(const void * fb,size_t fz,void ** fn,void * tb,size_t tz,void ** tn)1624887Schin base64decode(const void* fb, size_t fz, void** fn, void* tb, size_t tz, void** tn)
1634887Schin {
1644887Schin 	register unsigned char*	fp;
1654887Schin 	register unsigned char*	tp;
1664887Schin 	register unsigned char*	fe;
1674887Schin 	register unsigned char*	te;
1684887Schin 	register unsigned char*	tx;
1694887Schin 	register unsigned char*	m;
1704887Schin 	register int		c;
1714887Schin 	register int		state;
1724887Schin 	register unsigned long	v;
1734887Schin 	unsigned char*		fc;
1744887Schin 	ssize_t			n;
1754887Schin 
1764887Schin 	if (!(m = map)[0])
1774887Schin 	{
1784887Schin 		memset(m, B64_IGN, sizeof(map));
1794887Schin 		for (tp = (unsigned char*)alp; c = *tp; tp++)
1804887Schin 			m[c] =  tp - (unsigned char*)alp;
1814887Schin 		m[PAD] = B64_PAD;
1824887Schin 		m[' '] = m['\t'] = m['\n'] = B64_SPC;
1834887Schin 	}
1844887Schin 	fp = (unsigned char*)fb;
1854887Schin 	fe = fp + fz;
1864887Schin 	if (tp = (unsigned char*)tb)
1874887Schin 	{
1884887Schin 		te = tp + tz;
1894887Schin 		if (tz > 2)
1904887Schin 			tz = 2;
1914887Schin 		tx = te - tz;
1924887Schin 		n = 0;
1934887Schin 	}
1944887Schin 	else
1954887Schin 	{
1964887Schin 		te = tx = tp;
1974887Schin 		n = 1;
1984887Schin 	}
1994887Schin 	for (;;)
2004887Schin 	{
2014887Schin 		fc = fp;
2024887Schin 		state = 0;
2034887Schin 		v = 0;
2044887Schin 		while (fp < fe)
2054887Schin 		{
2064887Schin 			if ((c = m[*fp++]) < 64)
2074887Schin 			{
2084887Schin 				v = (v << 6) | c;
2094887Schin 				if (++state == 4)
2104887Schin 				{
2114887Schin 					if (tp >= tx)
2124887Schin 					{
2134887Schin 						if (n)
2144887Schin 							n += 3;
2154887Schin 						else
2164887Schin 						{
2174887Schin 							n = tp - (unsigned char*)tb + 4;
2184887Schin 							if (tp < te)
2194887Schin 							{
2204887Schin 								*tp++ = (v >> 16);
2214887Schin 								if (tp < te)
2224887Schin 								{
2234887Schin 									*tp++ = (v >> 8);
2244887Schin 									if (tp < te)
2254887Schin 										*tp++ = (v);
2264887Schin 								}
2274887Schin 							}
2284887Schin 							if (tn)
2294887Schin 								*tn = tp;
2304887Schin 							if (fn)
2314887Schin 								*fn = fc;
2324887Schin 						}
2334887Schin 					}
2344887Schin 					else
2354887Schin 					{
2364887Schin 						*tp++ = (v >> 16);
2374887Schin 						*tp++ = (v >> 8);
2384887Schin 						*tp++ = (v);
2394887Schin 					}
2404887Schin 					fc = fp;
2414887Schin 					state = 0;
2424887Schin 					v = 0;
2434887Schin 				}
2444887Schin 			}
2454887Schin 			else if (c == B64_PAD)
2464887Schin 				break;
2474887Schin 		}
2484887Schin 		switch (state)
2494887Schin 		{
2504887Schin 		case 0:
2514887Schin 			goto done;
2524887Schin 		case 2:
2534887Schin 			if (tp < te)
2544887Schin 				*tp++ = v >> 4;
2554887Schin 			else if (n)
2564887Schin 				n++;
2574887Schin 			else
2584887Schin 			{
2594887Schin 				n = tp - (unsigned char*)tb + 2;
2604887Schin 				if (tn)
2614887Schin 					*tn = tp;
2624887Schin 				if (fn)
2634887Schin 					*fn = fc;
2644887Schin 			}
2654887Schin 			break;
2664887Schin 		case 3:
2674887Schin 			if (tp < te)
2684887Schin 			{
2694887Schin 				*tp++ = v >> 10;
2704887Schin 				if (tp < te)
2714887Schin 					*tp++ = v >> 2;
2724887Schin 				else
2734887Schin 				{
2744887Schin 					n = tp - (unsigned char*)tb + 2;
2754887Schin 					if (tn)
2764887Schin 						*tn = tp;
2774887Schin 					if (fn)
2784887Schin 						*fn = fc;
2794887Schin 				}
2804887Schin 			}
2814887Schin 			else if (n)
2824887Schin 				n += 2;
2834887Schin 			else
2844887Schin 			{
2854887Schin 				n = tp - (unsigned char*)tb + 3;
2864887Schin 				if (tn)
2874887Schin 					*tn = tp;
2884887Schin 				if (fn)
2894887Schin 					*fn = fc;
2904887Schin 			}
2914887Schin 			break;
2924887Schin 		}
2934887Schin 		while (fp < fe && ((c = m[*fp++]) == B64_PAD || c == B64_SPC));
2944887Schin 		if (fp >= fe || c >= 64)
2954887Schin 			break;
2964887Schin 		fp--;
2974887Schin 	}
2984887Schin  done:
2994887Schin 	if (n)
3004887Schin 		n--;
3014887Schin 	else
3024887Schin 	{
3034887Schin 		if (tp < te)
3044887Schin 			*tp = 0;
3054887Schin 		n = tp - (unsigned char*)tb;
3064887Schin 		if (fn)
3074887Schin 			*fn = fp;
3084887Schin 		if (tn)
3094887Schin 			*tn = tp;
3104887Schin 	}
3114887Schin 	return n;
3124887Schin }
313