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