function base64_encode(str) { var str = toUTF8(str); var base64EncodeChars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'.split(''); var out, i, j, len, r, l, c; i = j = 0; len = str.length; r = len % 3; len = len - r; l = (len / 3) << 2; if (r > 0) { l += 4; } out = new Array(l); while (i < len) { c = str.charCodeAt(i++) << 16 | str.charCodeAt(i++) << 8 | str.charCodeAt(i++); out[j++] = base64EncodeChars[c >> 18] + base64EncodeChars[c >> 12 & 0x3f] + base64EncodeChars[c >> 6 & 0x3f] + base64EncodeChars[c & 0x3f] ; } if (r == 1) { c = str.charCodeAt(i++); out[j++] = base64EncodeChars[c >> 2] + base64EncodeChars[(c & 0x03) << 4] + "=="; } else if (r == 2) { c = str.charCodeAt(i++) << 8 | str.charCodeAt(i++); out[j++] = base64EncodeChars[c >> 10] + base64EncodeChars[c >> 4 & 0x3f] + base64EncodeChars[(c & 0x0f) << 2] + "="; } return out.join(''); } function base64_decode(str) { var base64DecodeChars = [ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1, -1, -1, -1 ]; var c1, c2, c3, c4; var i, j, len, r, l, out; len = str.length; if (len % 4 != 0) { return ''; } if (/[^ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789\+\/\=]/.test(str)) { return ''; } if (str.charAt(len - 2) == '=') { r = 1; } else if (str.charAt(len - 1) == '=') { r = 2; } else { r = 0; } l = len; if (r > 0) { l -= 4; } l = (l >> 2) * 3 + r; out = new Array(l); i = j = 0; while (i < len) { // c1 c1 = base64DecodeChars[str.charCodeAt(i++)]; if (c1 == -1) break; // c2 c2 = base64DecodeChars[str.charCodeAt(i++)]; if (c2 == -1) break; out[j++] = String.fromCharCode((c1 << 2) | ((c2 & 0x30) >> 4)); // c3 c3 = base64DecodeChars[str.charCodeAt(i++)]; if (c3 == -1) break; out[j++] = String.fromCharCode(((c2 & 0x0f) << 4) | ((c3 & 0x3c) >> 2)); // c4 c4 = base64DecodeChars[str.charCodeAt(i++)]; if (c4 == -1) break; out[j++] = String.fromCharCode(((c3 & 0x03) << 6) | c4); } return toUTF16(out.join('')); } function toUTF8(str) { if (str.match(/^[\x00-\x7f]*$/) != null) { return str.toString(); } var out, i, j, len, c, c2; out = []; len = str.length; for (i = 0, j = 0; i < len; i++, j++) { c = str.charCodeAt(i); if (c <= 0x7f) { out[j] = str.charAt(i); } else if (c <= 0x7ff) { out[j] = String.fromCharCode(0xc0 | (c >>> 6), 0x80 | (c & 0x3f)); } else if (c < 0xd800 || c > 0xdfff) { out[j] = String.fromCharCode(0xe0 | (c >>> 12), 0x80 | ((c >>> 6) & 0x3f), 0x80 | (c & 0x3f)); } else { if (++i < len) { c2 = str.charCodeAt(i); if (c <= 0xdbff && 0xdc00 <= c2 && c2 <= 0xdfff) { c = ((c & 0x03ff) << 10 | (c2 & 0x03ff)) + 0x010000; if (0x010000 <= c && c <= 0x10ffff) { out[j] = String.fromCharCode(0xf0 | ((c >>> 18) & 0x3f), 0x80 | ((c >>> 12) & 0x3f), 0x80 | ((c >>> 6) & 0x3f), 0x80 | (c & 0x3f)); } else { out[j] = '?'; } } else { i--; out[j] = '?'; } } else { i--; out[j] = '?'; } } } return out.join(''); } function toUTF16(str) { if ((str.match(/^[\x00-\x7f]*$/) != null) || (str.match(/^[\x00-\xff]*$/) == null)) { return str.toString(); } var out, i, j, len, c, c2, c3, c4, s; out = []; len = str.length; i = j = 0; while (i < len) { c = str.charCodeAt(i++); switch (c >> 4) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 0xxx xxxx out[j++] = str.charAt(i - 1); break; case 12: case 13: // 110x xxxx 10xx xxxx c2 = str.charCodeAt(i++); out[j++] = String.fromCharCode(((c & 0x1f) << 6) | (c2 & 0x3f)); break; case 14: // 1110 xxxx 10xx xxxx 10xx xxxx c2 = str.charCodeAt(i++); c3 = str.charCodeAt(i++); out[j++] = String.fromCharCode(((c & 0x0f) << 12) | ((c2 & 0x3f) << 6) | (c3 & 0x3f)); break; case 15: switch (c & 0xf) { case 0: case 1: case 2: case 3: case 4: case 5: case 6: case 7: // 1111 0xxx 10xx xxxx 10xx xxxx 10xx xxxx c2 = str.charCodeAt(i++); c3 = str.charCodeAt(i++); c4 = str.charCodeAt(i++); s = ((c & 0x07) << 18) | ((c2 & 0x3f) << 12) | ((c3 & 0x3f) << 6) | (c4 & 0x3f) - 0x10000; if (0 <= s && s <= 0xfffff) { out[j++] = String.fromCharCode(((s >>> 10) & 0x03ff) | 0xd800, (s & 0x03ff) | 0xdc00); } else { out[j++] = '?'; } break; case 8: case 9: case 10: case 11: // 1111 10xx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx i+=4; out[j++] = '?'; break; case 12: case 13: // 1111 110x 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx 10xx xxxx i+=5; out[j++] = '?'; break; } } } return out.join(''); }