Created
April 13, 2024 07:27
-
-
Save JTRNS/ed7c6a8d800e5bedc13d2b5644e60326 to your computer and use it in GitHub Desktop.
base64 encoder and decoder
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
function base64ToBytes(base64: string): Uint8Array { | |
const binString = atob(base64); | |
return Uint8Array.from(binString, (m) => m.codePointAt(0) || 0); | |
} | |
function bytesToBase64(bytes: Uint8Array): string { | |
const binString = String.fromCodePoint(...bytes); | |
return btoa(binString); | |
} | |
function ensureWellFormed(str: string | Uint8Array): void { | |
if (typeof str === "string" && !isWellFormed(str)) { | |
throw new Error("Cannot process a string with lone surrogates"); | |
} | |
} | |
function isWellFormed(str: string) { | |
/// @ts-expect-error Missing type definition | |
// https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/isWellFormed | |
if (typeof (str.isWellFormed) != "undefined") { | |
/// @ts-expect-error Missing type definition | |
return str.isWellFormed(); | |
} else { | |
try { | |
encodeURIComponent(str); | |
return true; | |
} catch (error) { | |
return false; | |
} | |
} | |
} | |
const encoder = new TextEncoder(); | |
export function validateBinaryLike(source: unknown): Uint8Array { | |
if (typeof source === "string") { | |
return encoder.encode(source); | |
} else if (source instanceof Uint8Array) { | |
return source; | |
} else if (source instanceof ArrayBuffer) { | |
return new Uint8Array(source); | |
} | |
throw new TypeError( | |
`The input must be a Uint8Array, a string, or an ArrayBuffer. Received a value of the type ${typeof source} | |
}.`, | |
); | |
} | |
export const base64 = { | |
encode(binaryData: Uint8Array | ArrayBuffer | string): string { | |
const bytes = validateBinaryLike(binaryData); | |
ensureWellFormed(bytes); | |
return bytesToBase64(bytes); | |
}, | |
decode(value: string): Uint8Array { | |
ensureWellFormed(value); | |
return base64ToBytes(value); | |
}, | |
}; | |
export const base64url = { | |
encode(binaryData: Uint8Array | ArrayBuffer | string): string { | |
const bytes = validateBinaryLike(binaryData); | |
ensureWellFormed(bytes); | |
return bytesToBase64(bytes) | |
.replace(/\+/g, "-") | |
.replace(/\//g, "_") | |
.replace(/=/g, ""); | |
}, | |
decode(value: string): Uint8Array { | |
ensureWellFormed(value); | |
return base64ToBytes( | |
value | |
.replace(/-/g, "+") | |
.replace(/_/g, "/") | |
.padEnd((value.length + 3) & ~3, "="), | |
); | |
}, | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment