/** * @license * Copyright 2022-2026 Matter.js Authors * SPDX-License-Identifier: Apache-2.0 */ function cp(text: string) { return text.codePointAt(0) ?? 0; } const A2B = []; const B2A = new Uint8Array(64); const B2A_URL = new Uint8Array(64); const PAD = cp("="); { let pos = 0; function addRange(start: string, stop: string) { const end = cp(stop) + 1; for (let i = cp(start); i < end; i++) { A2B[i] = pos; B2A[pos++] = i; } } addRange("A", "Z"); addRange("a", "z"); addRange("0", "9"); addRange("+", "+"); addRange("/", "/"); // base64url const slashValue = A2B[cp("/")]; const plusValue = A2B[cp("+")]; A2B[cp("_")] = slashValue; A2B[cp("-")] = plusValue; B2A_URL.set(B2A); B2A_URL[slashValue] = cp("_"); B2A_URL[plusValue] = cp("-"); } export namespace Base64 { /** * Encodes base64. * * @param input an indexable sequence of bytes * @param url set to true to encode as base46url * @returns an encoded string */ export function encode(input: ArrayLike, url = false) { const dict = url ? B2A_URL : B2A; let outLength = Math.trunc(input.length / 3) * 4; if (url) { const partial = input.length % 3; if (partial) outLength += partial + 1; } else { outLength += input.length % 3 ? 4 : 0; } const out = new Uint8Array(outLength); for (let inPos = 0, outPos = 0; outPos < outLength; ) { const n = (input[inPos++] << 16) + ((input[inPos++] ?? 0) << 8) + (input[inPos++] ?? 0); out[outPos++] = dict[n >>> 18]; out[outPos++] = dict[(n >>> 12) & 0o77]; if (inPos - input.length === 2) { if (!url) out[outPos++] = PAD; } else { out[outPos++] = dict[(n >>> 6) & 0o77]; } if (inPos > input.length) { if (!url) out[outPos++] = PAD; } else { out[outPos++] = dict[n & 0o77]; } } return new TextDecoder().decode(out); } /** * Decodes base64. * * @param input binary data encoded as a base64 or base64url string * @returns decoded bytes in a ByteArray */ export function decode(input: string) { if (!input.length) { return new Uint8Array(); } let inputLength = input.length; while (input.codePointAt(inputLength - 1) === PAD) inputLength--; let outLength = Math.trunc(inputLength / 4) * 3; switch (inputLength % 4) { case 3: outLength += 2; break; case 2: outLength += 1; break; case 1: throw new SyntaxError("Invalid base-64 encoding"); } const out = new Uint8Array(outLength); for (let inPos = 0, outPos = 0; ; ) { function lookup() { if (inPos >= inputLength) return 0; const v = A2B[input.codePointAt(inPos++) ?? -1]; if (v === undefined) { throw new SyntaxError("Invalid base-64 encoding"); } return v; } const n = (lookup() << 18) + (lookup() << 12) + (lookup() << 6) + lookup(); out[outPos++] = n >>> 16; if (outPos < outLength) { out[outPos++] = (n >>> 8) & 0xff; } else { break; } if (outPos < outLength) { out[outPos++] = n & 0xff; } else { break; } } return out; } }