// $Id: base64.c,v 1.7 2005/11/13 19:52:44 lynx Exp $ // vim:syntax=lpc // // base64 encoder/decoder // 2004 - Dan@Gueldenland - df@erinye.com // #include volatile string * char64 = efun::explode("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/", ""); volatile mapping deco64 = funcall( (: mapping x = ([ ]); int i; for(i=0; i<64; ++i) { x[char64[i][0]] = i+1; } x['='] = 1; return x; :) ); static int deco(int i) { i = deco64[i]; if(!i) raise_error("Oh crap.\n"); return i-1; } string encode_base64(int * b) { int bbb, i=0, s=sizeof(b); string res = ""; while(i+3 <= s) { bbb = (b[i++] & 0xff) << 16; bbb |= (b[i++] & 0xff) << 8; bbb |= b[i++] & 0xff; res += char64[(bbb & 0xfc0000) >> 18] + char64[(bbb & 0x3f000) >> 12] + char64[(bbb & 0xfc0) >> 6] + char64[bbb & 0x3f]; } if(s - i == 2) { bbb = ((b[i++] & 0xff) << 16) | ((b[i++] & 0xff) << 8); res += char64[(bbb & 0xfc0000) >> 18] + char64[(bbb & 0x3f000) >> 12] + char64[(bbb & 0xfc0) >> 6] + "="; } else if(s - i == 1) { bbb = ((b[i] & 0xff) << 16); res += char64[(bbb & 0xfc0000) >> 18] + char64[(bbb & 0x3f000) >> 12] + "=="; } return res; } // this doesn't really enforce base64, but if it finds = on positions they // shouldn't be on, this'll get sullen. int * decode_base64(string b) { int * res = ({ }); int i=0, s, next; b = replace(b, "\n", ""); b = replace(b, "\r", ""); s = strlen(b); while(i+4 <= s) { res += ({ (deco(b[i]) << 2) | (deco(b[i+1]) >> 4) }); next = ((deco(b[i+1]) << 4) & 0xff) | (deco(b[i+2]) >> 2); unless (!next && b[i+2] == '=') { res += ({ next }); } else { return res; } next = ((deco(b[i+2]) << 6) & 0xc0) | deco(b[i+3]); unless (!next && b[i+3] == '=') { res += ({ next }); } else { return res; } i += 4; } return res; } #if DEBUG > 1 void base64_self_test() { int i, j, cool; string x, y, z; for(i=0; i<10; ++i) { x = ""; j = random(100) + 5; while(j>0) { x += to_string(({ 32 + random(96) })); --j; } y = encode_base64(to_array(x)); z = to_string(decode_base64(y)); if(z == x) ++cool; else { P2(("uncool:\n%O !=\n%O\n", x, z)); P3(("base: %O\n", y)) P3(("strlen: %O, %O, last: %O\n", strlen(x), strlen(z), z[<1])) } } P2(("base64_self_test: %d out of 10 successful.\n", cool)); } #endif