365
/** Decodes base64 to a uint8 array. URL-encoded and unpadded base64 is allowed. */
366
export function decodeBase64(encoded: string) {
368
>
let remainder = 0;
369
>
let bufi = 0;
370
>
371
>
// The simpler way to do this is `Uint8Array.from(atob(str), c => c.charCodeAt(0))`,
372
>
// but that's about 10-20x slower than this function in current Chromium versions.
373
>
374
>
const buffer = new Uint8Array(Math.floor(encoded.length / 4 * 3));
375
>
const append = (value: number) => {
376
>
switch (remainder) {
377
>
case 3:
378
>
buffer[bufi++] = building | value;
379
>
remainder = 0;
380
>
break;
381
>
case 2:
382
>
buffer[bufi++] = building | (value >>> 2);
383
>
building = value << 6;
384
>
remainder = 3;
385
>
break;
386
>
case 1:
387
>
buffer[bufi++] = building | (value >>> 4);
388
>
building = value << 4;
389
>
remainder = 2;
390
>
break;
391
>
default:
392
>
building = value << 2;
393
>
remainder = 1;
394
>
}
395
>
};
396
>
397
>
for (let i = 0; i < encoded.length; i++) {
398
>
const code = encoded.charCodeAt(i);
399
>
// See https://datatracker.ietf.org/doc/html/rfc4648#section-4
400
>
// This branchy code is about 3x faster than an indexOf on a base64 char string.
401
>
if (code >= 65 && code <= 90) {
402
append(code - 65); // A-Z starts ranges from char code 65 to 90
403
>
} else if (code >= 97 && code <= 122) {
buffer.ts
404
append(code - 97 + 26); // a-z starts ranges from char code 97 to 122, starting at byte 26
405
} else if (code >= 48 && code <= 57) {