// Base 64 encoding const BASE_64_CHARS = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; const BASE_64_VALS = Object.create(null); const getChar = val => BASE_64_CHARS.charAt(val); const getVal = ch => ch === '=' ? -1 : BASE_64_VALS[ch]; for (let i = 0; i < BASE_64_CHARS.length; i++) { BASE_64_VALS[getChar(i)] = i; }; const encode = array => { if (typeof array === "string") { const str = array; array = newBinary(str.length); for (let i = 0; i < str.length; i++) { const ch = str.charCodeAt(i); if (ch > 0xFF) { throw new Error( "Not ascii. Base64.encode can only take ascii strings."); } array[i] = ch; } } const answer = []; let a = null; let b = null; let c = null; let d = null; for (let i = 0; i < array.length; i++) { switch (i % 3) { case 0: a = (array[i] >> 2) & 0x3F; b = (array[i] & 0x03) << 4; break; case 1: b = b | (array[i] >> 4) & 0xF; c = (array[i] & 0xF) << 2; break; case 2: c = c | (array[i] >> 6) & 0x03; d = array[i] & 0x3F; answer.push(getChar(a)); answer.push(getChar(b)); answer.push(getChar(c)); answer.push(getChar(d)); a = null; b = null; c = null; d = null; break; } } if (a != null) { answer.push(getChar(a)); answer.push(getChar(b)); if (c == null) { answer.push('='); } else { answer.push(getChar(c)); } if (d == null) { answer.push('='); } } return answer.join(""); }; // XXX This is a weird place for this to live, but it's used both by // this package and 'ejson', and we can't put it in 'ejson' without // introducing a circular dependency. It should probably be in its own // package or as a helper in a package that both 'base64' and 'ejson' // use. const newBinary = len => { if (typeof Uint8Array === 'undefined' || typeof ArrayBuffer === 'undefined') { const ret = []; for (let i = 0; i < len; i++) { ret.push(0); } ret.$Uint8ArrayPolyfill = true; return ret; } return new Uint8Array(new ArrayBuffer(len)); }; const decode = str => { let len = Math.floor((str.length * 3) / 4); if (str.charAt(str.length - 1) == '=') { len--; if (str.charAt(str.length - 2) == '=') { len--; } } const arr = newBinary(len); let one = null; let two = null; let three = null; let j = 0; for (let i = 0; i < str.length; i++) { const c = str.charAt(i); const v = getVal(c); switch (i % 4) { case 0: if (v < 0) { throw new Error('invalid base64 string'); } one = v << 2; break; case 1: if (v < 0) { throw new Error('invalid base64 string'); } one = one | (v >> 4); arr[j++] = one; two = (v & 0x0F) << 4; break; case 2: if (v >= 0) { two = two | (v >> 2); arr[j++] = two; three = (v & 0x03) << 6; } break; case 3: if (v >= 0) { arr[j++] = three | v; } break; } } return arr; }; export const Base64 = { encode, decode, newBinary };