Skip to content

Commit a2e981d

Browse files
committed
updates
1 parent fab7ab7 commit a2e981d

1 file changed

Lines changed: 29 additions & 24 deletions

File tree

base64.js

Lines changed: 29 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -58,33 +58,38 @@ export function fromBase64url(str, format = 'uint8') {
5858
return fromTypedArray(fromBase64common(str, true), format)
5959
}
6060

61-
function fromBase64common(str, isBase64url) {
62-
if (Uint8Array.fromBase64) {
63-
const options = { alphabet: isBase64url ? 'base64url' : 'base64', lastChunkHandling: 'strict' }
61+
let fromBase64common
62+
if (Uint8Array.fromBase64) {
63+
// NOTICE: this is actually slower than our JS impl in JavaScriptCore and SpiderMonkey (but faster on V8)
64+
fromBase64common = (str, isBase64url) => {
65+
const alphabet = isBase64url ? 'base64url' : 'base64'
6466
const padded = str.length % 4 > 0 ? `${str}${'='.repeat(4 - (str.length % 4))}` : str
65-
return Uint8Array.fromBase64(padded, options)
67+
return Uint8Array.fromBase64(padded, { alphabet, lastChunkHandling: 'strict' })
6668
}
69+
} else {
70+
fromBase64common = (str, isBase64url) => {
71+
let arr
72+
if (!haveNativeBuffer && atob) {
73+
// atob is faster than manual parsing on Hermes
74+
const raw = atob(isBase64url ? str.replaceAll('-', '+').replaceAll('_', '/') : str)
75+
arr = new Uint8Array(raw.length)
76+
for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i)
77+
} else {
78+
// base64url is already checked to have no padding
79+
if (!isBase64url) assert(!str.includes('=') || !/=[^=]/iu.test(str), 'Invalid padding')
80+
arr = haveNativeBuffer ? Buffer.from(str, 'base64') : fromBase64js(str)
81+
}
6782

68-
let arr
69-
if (!haveNativeBuffer && atob) {
70-
// atob is faster than manual parsing on Hermes
71-
const raw = atob(isBase64url ? str.replaceAll('-', '+').replaceAll('_', '/') : str)
72-
arr = new Uint8Array(raw.length)
73-
for (let i = 0; i < raw.length; i++) arr[i] = raw.charCodeAt(i)
74-
} else {
75-
assert(!str.includes('=') || !/=[^=]/iu.test(str), 'Invalid input after padding')
76-
arr = haveNativeBuffer ? Buffer.from(str, 'base64') : fromBase64js(str)
77-
}
83+
if (arr.length % 3 !== 0) {
84+
// Check last chunk to be strict if it was incomplete
85+
const expected = toBase64(arr.subarray(-(arr.length % 3)))
86+
const end = str.length % 4 === 0 ? str.slice(-4) : str.slice(-(str.length % 4)).padEnd(4, '=')
87+
const actual = isBase64url ? end.replaceAll('-', '+').replaceAll('_', '/') : end
88+
if (expected !== actual) throw new Error('Invalid last chunk')
89+
}
7890

79-
if (arr.length % 3 !== 0) {
80-
// Check last chunk to be strict if it was incomplete
81-
const expected = toBase64(arr.subarray(-(arr.length % 3)))
82-
const last = str.length % 4 === 0 ? str.slice(-4) : str.slice(-(str.length % 4)).padEnd(4, '=')
83-
const actual = isBase64url ? last.replaceAll('-', '+').replaceAll('_', '/') : last
84-
if (expected !== actual) throw new Error('Invalid last chunk')
91+
return arr
8592
}
86-
87-
return arr
8893
}
8994

9095
const BASE64 = [...'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/']
@@ -143,8 +148,8 @@ function fromBase64js(str) {
143148
if (!fromBase64jsMap) {
144149
fromBase64jsMap = map
145150
BASE64.forEach((c, i) => (map[c.charCodeAt(0)] = i))
146-
map['-'.charCodeAt(0)] = 62 // two last chars of BASE64
147-
map['_'.charCodeAt(0)] = 63 // two last chars of BASE64
151+
map['-'.charCodeAt(0)] = 62 // two last chars of BASE64URL
152+
map['_'.charCodeAt(0)] = 63 // two last chars of BASE64URL
148153
}
149154

150155
let inputLength = str.length

0 commit comments

Comments
 (0)