
#include "sys"

/* =========================================================================
 * The remainder of the code originates from http://base64.sourceforge.net/.
 * The original version was written by Bob Trower.
 * Adapted for C++ by me [kk]
 * =========================================================================
 */

/*
** Translation Table as described in RFC1113
** Not used during decode phase
static
const char *xx_cb64 =   "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
                        "abcdefghijklmnopqrstuvwxyz"
                        "0123456789+/";
*/

/*
** Translation Table to decode (created by author)
*/
static
const char *xx_cd64 =   "|$$$}rstuvwxyz{$$$$$$$>?@"
                        "ABCDEFGHIJKLMNOPQRSTUVW$$$$$$XYZ"
                        "[\\]^_`abcdefghijklmnopq";

/*
** decodeblock
**
** decode 4 '6-bit' characters into 3 8-bit binary bytes
*/
static void decodeblock(char in[4], char out[4])
{   
    out[0] = (unsigned char ) (in[0] << 2 | in[1] >> 4);
    out[1] = (unsigned char ) (in[1] << 4 | in[2] >> 2);
    out[2] = (unsigned char ) (((in[2] << 6) & 0xc0) | in[3]);
}

/*
** decode
**
** decode a base64 encoded stream discarding padding, line breaks and noise
*/
static
string base64_decode(char const *srcstr, int srclen) {
    char in[4], out[4], v;
    int i, j, len, morechars;
    string decbuf;
    int declen = 0;

    /* Initialize. Only the first 3 chars of out will get overwritten. */
    out[3] = 0;

    /* Examine all characters. */
    j = 0;
    morechars = 1;
    while (morechars) {
	for (len = 0, i = 0; i < 4 && morechars; i++) {
	    v = 0;

	    while (morechars && !v) {
		v = (unsigned char) srcstr[j++];
		if (j > srclen)
		    morechars = 0;
                v = (unsigned char) ((v < 43 || v > 122) ?
				     0 :
				     xx_cd64[v - 43]);
                if (v)
                    v = (unsigned char) ((v == '$') ? 0 : v - 61);
	    }
	    if (morechars) {
		len++;
		if (v)
		    in[i] = (unsigned char) (v - 1);
	    }
	    else
		in[i] = 0;
	}
	if (len) {
	    decodeblock (in, out);
	    decbuf += string(out);
	    declen += len - 1;
	}
    }

    /* All done. */
    return (decbuf);
}

string base64_decode(string const &s) {
    return base64_decode(s.c_str(), s.length());
}
