/** * base64.ts * * Licensed under the BSD 3-Clause License. * http://opensource.org/licenses/BSD-3-Clause * * References: * http://en.wikipedia.org/wiki/Base64 * * @author Dan Kogai (https://github.com/dankogai) */ const version = '3.4.5'; /** * @deprecated use lowercase `version`. */ const VERSION = version; const _hasatob = typeof atob === 'function'; const _hasbtoa = typeof btoa === 'function'; const _hasBuffer = typeof Buffer === 'function'; const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; const b64chs = [...b64ch]; const b64tab = ((a) => { let tab = {}; a.forEach((c, i) => tab[c] = i); return tab; })(b64chs); const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/; const _fromCC = String.fromCharCode.bind(String); const _U8Afrom = typeof Uint8Array.from === 'function' ? Uint8Array.from.bind(Uint8Array) : (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn)); const _mkUriSafe = (src) => src .replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_') .replace(/=+$/m, ''); const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, ''); /** * polyfill version of `btoa` */ const btoaPolyfill = (bin) => { // console.log('polyfilled'); let u32, c0, c1, c2, asc = ''; const pad = bin.length % 3; for (let i = 0; i < bin.length;) { if ((c0 = bin.charCodeAt(i++)) > 255 || (c1 = bin.charCodeAt(i++)) > 255 || (c2 = bin.charCodeAt(i++)) > 255) throw new TypeError('invalid character found'); u32 = (c0 << 16) | (c1 << 8) | c2; asc += b64chs[u32 >> 18 & 63] + b64chs[u32 >> 12 & 63] + b64chs[u32 >> 6 & 63] + b64chs[u32 & 63]; } return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc; }; /** * does what `window.btoa` of web browsers do. * @param {String} bin binary string * @returns {string} Base64-encoded string */ const _btoa = _hasbtoa ? (bin) => btoa(bin) : _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64') : btoaPolyfill; const _fromUint8Array = _hasBuffer ? (u8a) => Buffer.from(u8a).toString('base64') : (u8a) => { // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326 const maxargs = 0x1000; let strs = []; for (let i = 0, l = u8a.length; i < l; i += maxargs) { strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs))); } return _btoa(strs.join('')); }; /** * converts a Uint8Array to a Base64 string. * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5 * @returns {string} Base64 string */ const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a); /** * @deprecated should have been internal use only. * @param {string} src UTF-8 string * @returns {string} UTF-16 string */ const utob = (src) => unescape(encodeURIComponent(src)); // const _encode = _hasBuffer ? (s) => Buffer.from(s, 'utf8').toString('base64') : (s) => _btoa(utob(s)); /** * converts a UTF-8-encoded string to a Base64 string. * @param {boolean} [urlsafe] if `true` make the result URL-safe * @returns {string} Base64 string */ const encode = (src, urlsafe = false) => urlsafe ? _mkUriSafe(_encode(src)) : _encode(src); /** * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5. * @returns {string} Base64 string */ const encodeURI = (src) => encode(src, true); /** * @deprecated should have been internal use only. * @param {string} src UTF-16 string * @returns {string} UTF-8 string */ const btou = (src) => decodeURIComponent(escape(src)); /** * polyfill version of `atob` */ const atobPolyfill = (asc) => { // console.log('polyfilled'); asc = asc.replace(/\s+/g, ''); if (!b64re.test(asc)) throw new TypeError('malformed base64.'); asc += '=='.slice(2 - (asc.length & 3)); let u24, bin = '', r1, r2; for (let i = 0; i < asc.length;) { u24 = b64tab[asc.charAt(i++)] << 18 | b64tab[asc.charAt(i++)] << 12 | (r1 = b64tab[asc.charAt(i++)]) << 6 | (r2 = b64tab[asc.charAt(i++)]); bin += r1 === 64 ? _fromCC(u24 >> 16 & 255) : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255) : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255); } return bin; }; /** * does what `window.atob` of web browsers do. * @param {String} asc Base64-encoded string * @returns {string} binary string */ const _atob = _hasatob ? (asc) => atob(_tidyB64(asc)) : _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary') : atobPolyfill; const _decode = _hasBuffer ? (a) => Buffer.from(a, 'base64').toString('utf8') : (a) => btou(_atob(a)); const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/')); /** * converts a Base64 string to a UTF-8 string. * @param {String} src Base64 string. Both normal and URL-safe are supported * @returns {string} UTF-8 string */ const decode = (src) => _decode(_unURI(src)); /** * converts a Base64 string to a Uint8Array. */ const toUint8Array = _hasBuffer ? (a) => _U8Afrom(Buffer.from(_unURI(a), 'base64')) : (a) => _U8Afrom(_atob(_unURI(a)), c => c.charCodeAt(0)); const _noEnum = (v) => { return { value: v, enumerable: false, writable: true, configurable: true }; }; /** * extend String.prototype with relevant methods */ const extendString = function () { const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body)); _add('fromBase64', function () { return decode(this); }); _add('toBase64', function (urlsafe) { return encode(this, urlsafe); }); _add('toBase64URI', function () { return encode(this, true); }); _add('toBase64URL', function () { return encode(this, true); }); _add('toUint8Array', function () { return toUint8Array(this); }); }; /** * extend Uint8Array.prototype with relevant methods */ const extendUint8Array = function () { const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body)); _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); }); _add('toBase64URI', function () { return fromUint8Array(this, true); }); _add('toBase64URL', function () { return fromUint8Array(this, true); }); }; /** * extend Builtin prototypes with relevant methods */ const extendBuiltins = () => { extendString(); extendUint8Array(); }; const gBase64 = { version: version, VERSION: VERSION, atob: _atob, atobPolyfill: atobPolyfill, btoa: _btoa, btoaPolyfill: btoaPolyfill, fromBase64: decode, toBase64: encode, encode: encode, encodeURI: encodeURI, encodeURL: encodeURI, utob: utob, btou: btou, decode: decode, fromUint8Array: fromUint8Array, toUint8Array: toUint8Array, extendString: extendString, extendUint8Array: extendUint8Array, extendBuiltins: extendBuiltins, }; // makecjs:CUT // export { version }; export { VERSION }; export { _atob as atob }; export { atobPolyfill }; export { _btoa as btoa }; export { btoaPolyfill }; export { decode as fromBase64 }; export { encode as toBase64 }; export { utob }; export { encode }; export { encodeURI }; export { encodeURI as encodeURL }; export { btou }; export { decode }; export { fromUint8Array }; export { toUint8Array }; export { extendString }; export { extendUint8Array }; export { extendBuiltins }; // and finally, export { gBase64 as Base64 };