UNPKG

@woosh/meep-engine

Version:

Pure JavaScript game engine. Fully featured and production ready.

253 lines (197 loc) • 5.65 kB
/** * Adapted from https://github.com/beatgammit/base64-js * @author Jameson Little * @author Alex Goldring */ /** * * @type {string[]} */ const lookup = []; /** * * @type {number[]} */ const revLookup = []; const code = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/'; for (let i = 0, len = code.length; i < len; ++i) { lookup[i] = code[i]; revLookup[code.charCodeAt(i)] = i; } // Support decoding URL-safe base64 strings, as Node.js does. // See: https://en.wikipedia.org/wiki/Base64#URL_applications revLookup['-'.charCodeAt(0)] = 62; revLookup['_'.charCodeAt(0)] = 63; /** * * @param {string} b64 * @return {number[]} */ function getLens(b64) { const len = b64.length; if (len % 4 > 0) { throw new Error('Invalid string. Length must be a multiple of 4'); } // Trim off extra bytes after placeholder bytes are found // See: https://github.com/beatgammit/base64-js/issues/42 let validLen = b64.indexOf('='); if (validLen === -1) { validLen = len; } const placeHoldersLen = validLen === len ? 0 : 4 - (validLen % 4); return [validLen, placeHoldersLen]; } /** * base64 is 4/3 + up to two characters of the original data * @param {number} validLen * @param {number} placeHoldersLen */ function _byteLength(validLen, placeHoldersLen) { return ((validLen + placeHoldersLen) * 3 / 4) - placeHoldersLen; } /** * * @param {string} b64 * @return {Uint8Array} */ function toByteArray(b64) { let tmp; const lens = getLens(b64); const validLen = lens[0]; const placeHoldersLen = lens[1]; const arr = new Uint8Array(_byteLength(validLen, placeHoldersLen)); let curByte = 0; // if there are placeholders, only get up to the last complete 4 chars const len = placeHoldersLen > 0 ? validLen - 4 : validLen; let i = 0; for (; i < len; i += 4) { const char_0 = b64.charCodeAt(i); const char_1 = b64.charCodeAt(i + 1); const char_2 = b64.charCodeAt(i + 2); const char_3 = b64.charCodeAt(i + 3); tmp = (revLookup[char_0] << 18) | (revLookup[char_1] << 12) | (revLookup[char_2] << 6) | revLookup[char_3]; arr[curByte++] = (tmp >> 16) & 0xFF; arr[curByte++] = (tmp >> 8) & 0xFF; arr[curByte++] = tmp & 0xFF; } if (placeHoldersLen === 2) { const char_0 = b64.charCodeAt(i); const char_1 = b64.charCodeAt(i + 1); tmp = (revLookup[char_0] << 2) | (revLookup[char_1] >> 4); arr[curByte++] = tmp & 0xFF; } if (placeHoldersLen === 1) { const char_0 = b64.charCodeAt(i); const char_1 = b64.charCodeAt(i + 1); const char_2 = b64.charCodeAt(i + 2); tmp = (revLookup[char_0] << 10) | (revLookup[char_1] << 4) | (revLookup[char_2] >> 2); arr[curByte++] = (tmp >> 8) & 0xFF; arr[curByte++] = tmp & 0xFF; } return arr; } /** * * @param {number} num * @return {string} */ function tripletToBase64(num) { return lookup[num >> 18 & 0x3F] + lookup[num >> 12 & 0x3F] + lookup[num >> 6 & 0x3F] + lookup[num & 0x3F] ; } /** * * @param {Uint8Array} uint8 * @param {number} start * @param {number} end * @return {string} */ function encodeChunk(uint8, start, end) { const output = []; for (let i = start; i < end; i += 3) { const tmp = ((uint8[i] << 16) & 0xFF0000) + ((uint8[i + 1] << 8) & 0xFF00) + (uint8[i + 2] & 0xFF); output.push(tripletToBase64(tmp)); } return output.join(''); } /** * must be multiple of 3 */ const MAX_CHUNK_LENGTH = 16383; /** * * @param {Uint8Array} uint8 * @return {string} */ function fromByteArray(uint8) { const len = uint8.length; const extraBytes = len % 3; // if we have 1 byte left, pad 2 bytes const parts = []; // go through the array every three bytes, we'll deal with trailing stuff later const len2 = len - extraBytes; for (let i = 0; i < len2; i += MAX_CHUNK_LENGTH) { const end = (i + MAX_CHUNK_LENGTH) > len2 ? len2 : (i + MAX_CHUNK_LENGTH); const chunk = encodeChunk(uint8, i, end); parts.push(chunk); } // pad the end with zeros, but make sure to not forget the extra bytes if (extraBytes === 1) { const tmp = uint8[len - 1]; parts.push( lookup[tmp >> 2] + lookup[(tmp << 4) & 0x3F] + '==' ); } else if (extraBytes === 2) { const tmp = (uint8[len - 2] << 8) + uint8[len - 1]; parts.push( lookup[tmp >> 10] + lookup[(tmp >> 4) & 0x3F] + lookup[(tmp << 2) & 0x3F] + '=' ); } return parts.join(''); } export class Base64 { /** * * @param {ArrayBuffer} value * @returns {string} */ static encode(value) { const array = new Uint8Array(value); return fromByteArray(array); } /** * * @param {string} value * @returns {ArrayBuffer} */ static decode(value) { /** * * @type {Uint8Array} */ const array = toByteArray(value); return array.buffer; } }