1. /**
    
  2.  *  base64.ts
    
  3.  *
    
  4.  *  Licensed under the BSD 3-Clause License.
    
  5.  *    http://opensource.org/licenses/BSD-3-Clause
    
  6.  *
    
  7.  *  References:
    
  8.  *    http://en.wikipedia.org/wiki/Base64
    
  9.  *
    
  10.  * @author Dan Kogai (https://github.com/dankogai)
    
  11.  */
    
  12. const version = '3.7.4';
    
  13. /**
    
  14.  * @deprecated use lowercase `version`.
    
  15.  */
    
  16. const VERSION = version;
    
  17. const _hasatob = typeof atob === 'function';
    
  18. const _hasbtoa = typeof btoa === 'function';
    
  19. const _hasBuffer = typeof Buffer === 'function';
    
  20. const _TD = typeof TextDecoder === 'function' ? new TextDecoder() : undefined;
    
  21. const _TE = typeof TextEncoder === 'function' ? new TextEncoder() : undefined;
    
  22. const b64ch = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=';
    
  23. const b64chs = Array.prototype.slice.call(b64ch);
    
  24. const b64tab = ((a) => {
    
  25.     let tab = {};
    
  26.     a.forEach((c, i) => tab[c] = i);
    
  27.     return tab;
    
  28. })(b64chs);
    
  29. const b64re = /^(?:[A-Za-z\d+\/]{4})*?(?:[A-Za-z\d+\/]{2}(?:==)?|[A-Za-z\d+\/]{3}=?)?$/;
    
  30. const _fromCC = String.fromCharCode.bind(String);
    
  31. const _U8Afrom = typeof Uint8Array.from === 'function'
    
  32.     ? Uint8Array.from.bind(Uint8Array)
    
  33.     : (it, fn = (x) => x) => new Uint8Array(Array.prototype.slice.call(it, 0).map(fn));
    
  34. const _mkUriSafe = (src) => src
    
  35.     .replace(/=/g, '').replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_');
    
  36. const _tidyB64 = (s) => s.replace(/[^A-Za-z0-9\+\/]/g, '');
    
  37. /**
    
  38.  * polyfill version of `btoa`
    
  39.  */
    
  40. const btoaPolyfill = (bin) => {
    
  41.     // console.log('polyfilled');
    
  42.     let u32, c0, c1, c2, asc = '';
    
  43.     const pad = bin.length % 3;
    
  44.     for (let i = 0; i < bin.length;) {
    
  45.         if ((c0 = bin.charCodeAt(i++)) > 255 ||
    
  46.             (c1 = bin.charCodeAt(i++)) > 255 ||
    
  47.             (c2 = bin.charCodeAt(i++)) > 255)
    
  48.             throw new TypeError('invalid character found');
    
  49.         u32 = (c0 << 16) | (c1 << 8) | c2;
    
  50.         asc += b64chs[u32 >> 18 & 63]
    
  51.             + b64chs[u32 >> 12 & 63]
    
  52.             + b64chs[u32 >> 6 & 63]
    
  53.             + b64chs[u32 & 63];
    
  54.     }
    
  55.     return pad ? asc.slice(0, pad - 3) + "===".substring(pad) : asc;
    
  56. };
    
  57. /**
    
  58.  * does what `window.btoa` of web browsers do.
    
  59.  * @param {String} bin binary string
    
  60.  * @returns {string} Base64-encoded string
    
  61.  */
    
  62. const _btoa = _hasbtoa ? (bin) => btoa(bin)
    
  63.     : _hasBuffer ? (bin) => Buffer.from(bin, 'binary').toString('base64')
    
  64.         : btoaPolyfill;
    
  65. const _fromUint8Array = _hasBuffer
    
  66.     ? (u8a) => Buffer.from(u8a).toString('base64')
    
  67.     : (u8a) => {
    
  68.         // cf. https://stackoverflow.com/questions/12710001/how-to-convert-uint8-array-to-base64-encoded-string/12713326#12713326
    
  69.         const maxargs = 0x1000;
    
  70.         let strs = [];
    
  71.         for (let i = 0, l = u8a.length; i < l; i += maxargs) {
    
  72.             strs.push(_fromCC.apply(null, u8a.subarray(i, i + maxargs)));
    
  73.         }
    
  74.         return _btoa(strs.join(''));
    
  75.     };
    
  76. /**
    
  77.  * converts a Uint8Array to a Base64 string.
    
  78.  * @param {boolean} [urlsafe] URL-and-filename-safe a la RFC4648 §5
    
  79.  * @returns {string} Base64 string
    
  80.  */
    
  81. const fromUint8Array = (u8a, urlsafe = false) => urlsafe ? _mkUriSafe(_fromUint8Array(u8a)) : _fromUint8Array(u8a);
    
  82. // This trick is found broken https://github.com/dankogai/js-base64/issues/130
    
  83. // const utob = (src: string) => unescape(encodeURIComponent(src));
    
  84. // reverting good old fationed regexp
    
  85. const cb_utob = (c) => {
    
  86.     if (c.length < 2) {
    
  87.         var cc = c.charCodeAt(0);
    
  88.         return cc < 0x80 ? c
    
  89.             : cc < 0x800 ? (_fromCC(0xc0 | (cc >>> 6))
    
  90.                 + _fromCC(0x80 | (cc & 0x3f)))
    
  91.                 : (_fromCC(0xe0 | ((cc >>> 12) & 0x0f))
    
  92.                     + _fromCC(0x80 | ((cc >>> 6) & 0x3f))
    
  93.                     + _fromCC(0x80 | (cc & 0x3f)));
    
  94.     }
    
  95.     else {
    
  96.         var cc = 0x10000
    
  97.             + (c.charCodeAt(0) - 0xD800) * 0x400
    
  98.             + (c.charCodeAt(1) - 0xDC00);
    
  99.         return (_fromCC(0xf0 | ((cc >>> 18) & 0x07))
    
  100.             + _fromCC(0x80 | ((cc >>> 12) & 0x3f))
    
  101.             + _fromCC(0x80 | ((cc >>> 6) & 0x3f))
    
  102.             + _fromCC(0x80 | (cc & 0x3f)));
    
  103.     }
    
  104. };
    
  105. const re_utob = /[\uD800-\uDBFF][\uDC00-\uDFFFF]|[^\x00-\x7F]/g;
    
  106. /**
    
  107.  * @deprecated should have been internal use only.
    
  108.  * @param {string} src UTF-8 string
    
  109.  * @returns {string} UTF-16 string
    
  110.  */
    
  111. const utob = (u) => u.replace(re_utob, cb_utob);
    
  112. //
    
  113. const _encode = _hasBuffer
    
  114.     ? (s) => Buffer.from(s, 'utf8').toString('base64')
    
  115.     : _TE
    
  116.         ? (s) => _fromUint8Array(_TE.encode(s))
    
  117.         : (s) => _btoa(utob(s));
    
  118. /**
    
  119.  * converts a UTF-8-encoded string to a Base64 string.
    
  120.  * @param {boolean} [urlsafe] if `true` make the result URL-safe
    
  121.  * @returns {string} Base64 string
    
  122.  */
    
  123. const encode = (src, urlsafe = false) => urlsafe
    
  124.     ? _mkUriSafe(_encode(src))
    
  125.     : _encode(src);
    
  126. /**
    
  127.  * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 §5.
    
  128.  * @returns {string} Base64 string
    
  129.  */
    
  130. const encodeURI = (src) => encode(src, true);
    
  131. // This trick is found broken https://github.com/dankogai/js-base64/issues/130
    
  132. // const btou = (src: string) => decodeURIComponent(escape(src));
    
  133. // reverting good old fationed regexp
    
  134. const re_btou = /[\xC0-\xDF][\x80-\xBF]|[\xE0-\xEF][\x80-\xBF]{2}|[\xF0-\xF7][\x80-\xBF]{3}/g;
    
  135. const cb_btou = (cccc) => {
    
  136.     switch (cccc.length) {
    
  137.         case 4:
    
  138.             var cp = ((0x07 & cccc.charCodeAt(0)) << 18)
    
  139.                 | ((0x3f & cccc.charCodeAt(1)) << 12)
    
  140.                 | ((0x3f & cccc.charCodeAt(2)) << 6)
    
  141.                 | (0x3f & cccc.charCodeAt(3)), offset = cp - 0x10000;
    
  142.             return (_fromCC((offset >>> 10) + 0xD800)
    
  143.                 + _fromCC((offset & 0x3FF) + 0xDC00));
    
  144.         case 3:
    
  145.             return _fromCC(((0x0f & cccc.charCodeAt(0)) << 12)
    
  146.                 | ((0x3f & cccc.charCodeAt(1)) << 6)
    
  147.                 | (0x3f & cccc.charCodeAt(2)));
    
  148.         default:
    
  149.             return _fromCC(((0x1f & cccc.charCodeAt(0)) << 6)
    
  150.                 | (0x3f & cccc.charCodeAt(1)));
    
  151.     }
    
  152. };
    
  153. /**
    
  154.  * @deprecated should have been internal use only.
    
  155.  * @param {string} src UTF-16 string
    
  156.  * @returns {string} UTF-8 string
    
  157.  */
    
  158. const btou = (b) => b.replace(re_btou, cb_btou);
    
  159. /**
    
  160.  * polyfill version of `atob`
    
  161.  */
    
  162. const atobPolyfill = (asc) => {
    
  163.     // console.log('polyfilled');
    
  164.     asc = asc.replace(/\s+/g, '');
    
  165.     if (!b64re.test(asc))
    
  166.         throw new TypeError('malformed base64.');
    
  167.     asc += '=='.slice(2 - (asc.length & 3));
    
  168.     let u24, bin = '', r1, r2;
    
  169.     for (let i = 0; i < asc.length;) {
    
  170.         u24 = b64tab[asc.charAt(i++)] << 18
    
  171.             | b64tab[asc.charAt(i++)] << 12
    
  172.             | (r1 = b64tab[asc.charAt(i++)]) << 6
    
  173.             | (r2 = b64tab[asc.charAt(i++)]);
    
  174.         bin += r1 === 64 ? _fromCC(u24 >> 16 & 255)
    
  175.             : r2 === 64 ? _fromCC(u24 >> 16 & 255, u24 >> 8 & 255)
    
  176.                 : _fromCC(u24 >> 16 & 255, u24 >> 8 & 255, u24 & 255);
    
  177.     }
    
  178.     return bin;
    
  179. };
    
  180. /**
    
  181.  * does what `window.atob` of web browsers do.
    
  182.  * @param {String} asc Base64-encoded string
    
  183.  * @returns {string} binary string
    
  184.  */
    
  185. const _atob = _hasatob ? (asc) => atob(_tidyB64(asc))
    
  186.     : _hasBuffer ? (asc) => Buffer.from(asc, 'base64').toString('binary')
    
  187.         : atobPolyfill;
    
  188. //
    
  189. const _toUint8Array = _hasBuffer
    
  190.     ? (a) => _U8Afrom(Buffer.from(a, 'base64'))
    
  191.     : (a) => _U8Afrom(_atob(a), c => c.charCodeAt(0));
    
  192. /**
    
  193.  * converts a Base64 string to a Uint8Array.
    
  194.  */
    
  195. const toUint8Array = (a) => _toUint8Array(_unURI(a));
    
  196. //
    
  197. const _decode = _hasBuffer
    
  198.     ? (a) => Buffer.from(a, 'base64').toString('utf8')
    
  199.     : _TD
    
  200.         ? (a) => _TD.decode(_toUint8Array(a))
    
  201.         : (a) => btou(_atob(a));
    
  202. const _unURI = (a) => _tidyB64(a.replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/'));
    
  203. /**
    
  204.  * converts a Base64 string to a UTF-8 string.
    
  205.  * @param {String} src Base64 string.  Both normal and URL-safe are supported
    
  206.  * @returns {string} UTF-8 string
    
  207.  */
    
  208. const decode = (src) => _decode(_unURI(src));
    
  209. /**
    
  210.  * check if a value is a valid Base64 string
    
  211.  * @param {String} src a value to check
    
  212.   */
    
  213. const isValid = (src) => {
    
  214.     if (typeof src !== 'string')
    
  215.         return false;
    
  216.     const s = src.replace(/\s+/g, '').replace(/={0,2}$/, '');
    
  217.     return !/[^\s0-9a-zA-Z\+/]/.test(s) || !/[^\s0-9a-zA-Z\-_]/.test(s);
    
  218. };
    
  219. //
    
  220. const _noEnum = (v) => {
    
  221.     return {
    
  222.         value: v, enumerable: false, writable: true, configurable: true
    
  223.     };
    
  224. };
    
  225. /**
    
  226.  * extend String.prototype with relevant methods
    
  227.  */
    
  228. const extendString = function () {
    
  229.     const _add = (name, body) => Object.defineProperty(String.prototype, name, _noEnum(body));
    
  230.     _add('fromBase64', function () { return decode(this); });
    
  231.     _add('toBase64', function (urlsafe) { return encode(this, urlsafe); });
    
  232.     _add('toBase64URI', function () { return encode(this, true); });
    
  233.     _add('toBase64URL', function () { return encode(this, true); });
    
  234.     _add('toUint8Array', function () { return toUint8Array(this); });
    
  235. };
    
  236. /**
    
  237.  * extend Uint8Array.prototype with relevant methods
    
  238.  */
    
  239. const extendUint8Array = function () {
    
  240.     const _add = (name, body) => Object.defineProperty(Uint8Array.prototype, name, _noEnum(body));
    
  241.     _add('toBase64', function (urlsafe) { return fromUint8Array(this, urlsafe); });
    
  242.     _add('toBase64URI', function () { return fromUint8Array(this, true); });
    
  243.     _add('toBase64URL', function () { return fromUint8Array(this, true); });
    
  244. };
    
  245. /**
    
  246.  * extend Builtin prototypes with relevant methods
    
  247.  */
    
  248. const extendBuiltins = () => {
    
  249.     extendString();
    
  250.     extendUint8Array();
    
  251. };
    
  252. const gBase64 = {
    
  253.     version: version,
    
  254.     VERSION: VERSION,
    
  255.     atob: _atob,
    
  256.     atobPolyfill: atobPolyfill,
    
  257.     btoa: _btoa,
    
  258.     btoaPolyfill: btoaPolyfill,
    
  259.     fromBase64: decode,
    
  260.     toBase64: encode,
    
  261.     encode: encode,
    
  262.     encodeURI: encodeURI,
    
  263.     encodeURL: encodeURI,
    
  264.     utob: utob,
    
  265.     btou: btou,
    
  266.     decode: decode,
    
  267.     isValid: isValid,
    
  268.     fromUint8Array: fromUint8Array,
    
  269.     toUint8Array: toUint8Array,
    
  270.     extendString: extendString,
    
  271.     extendUint8Array: extendUint8Array,
    
  272.     extendBuiltins: extendBuiltins,
    
  273. };
    
  274. // makecjs:CUT //
    
  275. export { version };
    
  276. export { VERSION };
    
  277. export { _atob as atob };
    
  278. export { atobPolyfill };
    
  279. export { _btoa as btoa };
    
  280. export { btoaPolyfill };
    
  281. export { decode as fromBase64 };
    
  282. export { encode as toBase64 };
    
  283. export { utob };
    
  284. export { encode };
    
  285. export { encodeURI };
    
  286. export { encodeURI as encodeURL };
    
  287. export { btou };
    
  288. export { decode };
    
  289. export { isValid };
    
  290. export { fromUint8Array };
    
  291. export { toUint8Array };
    
  292. export { extendString };
    
  293. export { extendUint8Array };
    
  294. export { extendBuiltins };
    
  295. // and finally,
    
  296. export { gBase64 as Base64 };