UNPKG

js-base64

Version:

Yet another Base64 transcoder in pure-JS

231 lines (230 loc) 7.86 kB
/** * base64.js * * 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) */ ;(function (global, factory) { typeof exports === 'object' && typeof module !== 'undefined' ? module.exports = factory(global) : typeof define === 'function' && define.amd ? define(factory) : factory(global) }(( typeof self !== 'undefined' ? self : typeof window !== 'undefined' ? window : typeof global !== 'undefined' ? global : this ), function(global) { 'use strict'; global = global || {}; // existing version for noConflict() const _Base64 = global.Base64; const version = '3.0.2'; const _b64chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; const _b64tab = ((bin) => { let tab = {}, i = 0; for (const c of bin) tab[c] = i++; return tab; })(_b64chars); const _fromCharCode = String.fromCharCode; const _mkUriSafe = (src) => String(src) .replace(/[+\/]/g, (m0) => m0 == '+' ? '-' : '_') .replace(/=/g, ''); /** * converts a Uint8Array to a Base64 string * @param {Uint8Array} src * @param {Boolean} urisafe URL-and-filename-safe a la RFC4648 * @returns {String} Base64 string */ const fromUint8Array = (src, urisafe) => { let b64 = ''; for (let i = 0, l = src.length; i < l; i += 3) { const a0 = src[i], a1 = src[i+1], a2 = src[i+2]; const ord = a0 << 16 | a1 << 8 | a2; b64 += _b64chars.charAt( ord >>> 18) + _b64chars.charAt((ord >>> 12) & 63) + ( typeof a1 != 'undefined' ? _b64chars.charAt((ord >>> 6) & 63) : '=') + ( typeof a2 != 'undefined' ? _b64chars.charAt( ord & 63) : '='); } return urisafe ? _mkUriSafe(b64) : b64; }; /** * 100% compatibile with `window.btoa` of web browsers * @param {String} src binary string * @returns {String} Base64-encoded string */ const btoa = global.btoa && typeof global.btoa == 'function' ? global.btoa.bind(global) : (src) => { if (src.match(/[^\x00-\xFF]/)) throw new RangeError( 'The string contains invalid characters.' ); return fromUint8Array( Uint8Array.from(src,c => c.charCodeAt(0)) ); }; /** * @deprecated since 3.0.0 * @param {string} src UTF-8 string * @returns {string} UTF-16 string */ const utob = (src) => unescape(encodeURIComponent(src)); /** * converts a UTF-8-encoded string to a Base64 string * @param {String} src the string to convert * @param {Boolean} rfc4648 if `true` make the result URL-safe * @returns {String} Base64 string */ const encode = (src, rfc4648) => { const b64 = btoa(utob(src)); return rfc4648 ? _mkUriSafe(b64) : b64; }; /** * converts a UTF-8-encoded string to URL-safe Base64 RFC4648 * @param {String} src the string to convert * @returns {String} Base64 string */ const encodeURI = (src) => encode(src, true); /** * @deprecated since 3.0.0 * @param {string} src UTF-16 string * @returns {string} UTF-8 string */ const btou = (src) => decodeURIComponent(escape(src)); const _cb_decode = (cccc) => { let len = cccc.length, padlen = len % 4, n = (len > 0 ? _b64tab[cccc.charAt(0)] << 18 : 0) | (len > 1 ? _b64tab[cccc.charAt(1)] << 12 : 0) | (len > 2 ? _b64tab[cccc.charAt(2)] << 6 : 0) | (len > 3 ? _b64tab[cccc.charAt(3)] : 0), chars = [ _fromCharCode( n >>> 16), _fromCharCode((n >>> 8) & 0xff), _fromCharCode( n & 0xff) ]; chars.length -= [0, 0, 2, 1][padlen]; return chars.join(''); }; /** * 100% compatibile with `window.atob` of web browsers * @param {String} src Base64-encoded string * @returns {String} binary string */ const atob = global.atob && typeof global.atob == 'function' ? global.atob.bind(global) : (a) => { return String(a) .replace(/[^A-Za-z0-9\+\/]/g, '') .replace(/\S{1,4}/g, _cb_decode); }; const _decode = (a) => btou(atob(a)); const _fromURI = (a) => { return String(a) .replace(/[-_]/g, (m0) => m0 == '-' ? '+' : '/') .replace(/[^A-Za-z0-9\+\/]/g, ''); }; /** * 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(_fromURI(src)); /** * converts a Base64 string to a Uint8Array * @param {String} src Base64 string. Both normal and URL-safe are supported * @returns {Uint8Array} UTF-8 string */ const toUint8Array = (a) => { return Uint8Array.from(atob(_fromURI(a)), c => c.charCodeAt(0)); }; const noConflict = () => { let Base64 = global.Base64; global.Base64 = _Base64; return Base64; }; // export Base64 global.Base64 = { VERSION: version, atob: atob, btoa: btoa, fromBase64: decode, toBase64: encode, utob: utob, encode: encode, encodeURI: encodeURI, encodeURL: encodeURI, btou: btou, decode: decode, noConflict: noConflict, fromUint8Array: fromUint8Array, toUint8Array: toUint8Array }; // make Base64.extendString() available const _noEnum = (v) => { return { value:v, enumerable:false, writable:true, configurable:true }; }; // make Base64.extendString() available global.Base64.extendString = function() { const _add = (name, body) => Object.defineProperty( String.prototype, name, _noEnum(body) ); _add('fromBase64', function() { return decode(this); }); _add('toBase64', function(rfc4648) { return encode(this, rfc4648); }); _add('toBase64URI', function() { return encode(this, true); }); _add('toBase64URL', function() { return encode(this, true); }); _add('toUint8Array', function() { return toUint8Array(this); }); }; // make Base64.extendUint8Array() available global.Base64.extendUint8Array = function() { const _add = (name, body) => Object.defineProperty( Uint8Array.prototype, name, _noEnum(body) ); _add('toBase64', function(rfc4648) { return fromUint8Array(this, rfc4648); }); _add('toBase64URI', function() { return fromUint8Array(this, true); }); _add('toBase64URL', function() { return fromUint8Array(this, true); }); }; global.Base64.extendBuiltins = () => { global.Base64.extendString(); global.Base64.extendUint8Array(); } // // export Base64 to the namespace // if (global['Meteor']) { // Meteor.js Base64 = global.Base64; } // module.exports and AMD are mutually exclusive. // module.exports has precedence. if (typeof module !== 'undefined' && module.exports) { module.exports.Base64 = global.Base64; } else if (typeof define === 'function' && define.amd) { // AMD. Register as an anonymous module. define([], function(){ return global.Base64 }); } // that's it! return {Base64: global.Base64}; }));