| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265 |
- /**
- * Avoid modifying this file. It's part of
- * https://github.com/briven-community/base64url-js. Submit all fixes on
- * that repo!
- */
- /**
- * An array of characters that encode 6 bits into a Base64-URL alphabet
- * character.
- */
- const TO_BASE64URL = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789-_'.split('')
- /**
- * An array of characters that can appear in a Base64-URL encoded string but
- * should be ignored.
- */
- const IGNORE_BASE64URL = ' \t\n\r='.split('')
- /**
- * An array of 128 numbers that map a Base64-URL character to 6 bits, or if -2
- * used to skip the character, or if -1 used to error out.
- */
- const FROM_BASE64URL = (() => {
- const charMap: number[] = new Array(128)
- for (let i = 0; i < charMap.length; i += 1) {
- charMap[i] = -1
- }
- for (let i = 0; i < IGNORE_BASE64URL.length; i += 1) {
- charMap[IGNORE_BASE64URL[i].charCodeAt(0)] = -2
- }
- for (let i = 0; i < TO_BASE64URL.length; i += 1) {
- charMap[TO_BASE64URL[i].charCodeAt(0)] = i
- }
- return charMap
- })()
- /**
- * Converts a byte to a Base64-URL string.
- *
- * @param byte The byte to convert, or null to flush at the end of the byte sequence.
- * @param state The Base64 conversion state. Pass an initial value of `{ queue: 0, queuedBits: 0 }`.
- * @param emit A function called with the next Base64 character when ready.
- */
- export function byteToBase64URL(
- byte: number | null,
- state: { queue: number; queuedBits: number },
- emit: (char: string) => void
- ) {
- if (byte !== null) {
- state.queue = (state.queue << 8) | byte
- state.queuedBits += 8
- while (state.queuedBits >= 6) {
- const pos = (state.queue >> (state.queuedBits - 6)) & 63
- emit(TO_BASE64URL[pos])
- state.queuedBits -= 6
- }
- } else if (state.queuedBits > 0) {
- state.queue = state.queue << (6 - state.queuedBits)
- state.queuedBits = 6
- while (state.queuedBits >= 6) {
- const pos = (state.queue >> (state.queuedBits - 6)) & 63
- emit(TO_BASE64URL[pos])
- state.queuedBits -= 6
- }
- }
- }
- /**
- * Converts a String char code (extracted using `string.charCodeAt(position)`) to a sequence of Base64-URL characters.
- *
- * @param charCode The char code of the JavaScript string.
- * @param state The Base64 state. Pass an initial value of `{ queue: 0, queuedBits: 0 }`.
- * @param emit A function called with the next byte.
- */
- export function byteFromBase64URL(
- charCode: number,
- state: { queue: number; queuedBits: number },
- emit: (byte: number) => void
- ) {
- const bits = FROM_BASE64URL[charCode]
- if (bits > -1) {
- // valid Base64-URL character
- state.queue = (state.queue << 6) | bits
- state.queuedBits += 6
- while (state.queuedBits >= 8) {
- emit((state.queue >> (state.queuedBits - 8)) & 0xff)
- state.queuedBits -= 8
- }
- } else if (bits === -2) {
- // ignore spaces, tabs, newlines, =
- return
- } else {
- throw new Error(`Invalid Base64-URL character "${String.fromCharCode(charCode)}"`)
- }
- }
- /**
- * Converts a JavaScript string (which may include any valid character) into a
- * Base64-URL encoded string. The string is first encoded in UTF-8 which is
- * then encoded as Base64-URL.
- *
- * @param str The string to convert.
- */
- export function stringToBase64URL(str: string) {
- const base64: string[] = []
- const emitter = (char: string) => {
- base64.push(char)
- }
- const state = { queue: 0, queuedBits: 0 }
- stringToUTF8(str, (byte: number) => {
- byteToBase64URL(byte, state, emitter)
- })
- byteToBase64URL(null, state, emitter)
- return base64.join('')
- }
- /**
- * Converts a Base64-URL encoded string into a JavaScript string. It is assumed
- * that the underlying string has been encoded as UTF-8.
- *
- * @param str The Base64-URL encoded string.
- */
- export function stringFromBase64URL(str: string) {
- const conv: string[] = []
- const utf8Emit = (codepoint: number) => {
- conv.push(String.fromCodePoint(codepoint))
- }
- const utf8State = {
- utf8seq: 0,
- codepoint: 0,
- }
- const b64State = { queue: 0, queuedBits: 0 }
- const byteEmit = (byte: number) => {
- stringFromUTF8(byte, utf8State, utf8Emit)
- }
- for (let i = 0; i < str.length; i += 1) {
- byteFromBase64URL(str.charCodeAt(i), b64State, byteEmit)
- }
- return conv.join('')
- }
- /**
- * Converts a Unicode codepoint to a multi-byte UTF-8 sequence.
- *
- * @param codepoint The Unicode codepoint.
- * @param emit Function which will be called for each UTF-8 byte that represents the codepoint.
- */
- export function codepointToUTF8(codepoint: number, emit: (byte: number) => void) {
- if (codepoint <= 0x7f) {
- emit(codepoint)
- return
- } else if (codepoint <= 0x7ff) {
- emit(0xc0 | (codepoint >> 6))
- emit(0x80 | (codepoint & 0x3f))
- return
- } else if (codepoint <= 0xffff) {
- emit(0xe0 | (codepoint >> 12))
- emit(0x80 | ((codepoint >> 6) & 0x3f))
- emit(0x80 | (codepoint & 0x3f))
- return
- } else if (codepoint <= 0x10ffff) {
- emit(0xf0 | (codepoint >> 18))
- emit(0x80 | ((codepoint >> 12) & 0x3f))
- emit(0x80 | ((codepoint >> 6) & 0x3f))
- emit(0x80 | (codepoint & 0x3f))
- return
- }
- throw new Error(`Unrecognized Unicode codepoint: ${codepoint.toString(16)}`)
- }
- /**
- * Converts a JavaScript string to a sequence of UTF-8 bytes.
- *
- * @param str The string to convert to UTF-8.
- * @param emit Function which will be called for each UTF-8 byte of the string.
- */
- export function stringToUTF8(str: string, emit: (byte: number) => void) {
- for (let i = 0; i < str.length; i += 1) {
- let codepoint = str.charCodeAt(i)
- if (codepoint > 0xd7ff && codepoint <= 0xdbff) {
- // most UTF-16 codepoints are Unicode codepoints, except values in this
- // range where the next UTF-16 codepoint needs to be combined with the
- // current one to get the Unicode codepoint
- const highSurrogate = ((codepoint - 0xd800) * 0x400) & 0xffff
- const lowSurrogate = (str.charCodeAt(i + 1) - 0xdc00) & 0xffff
- codepoint = (lowSurrogate | highSurrogate) + 0x10000
- i += 1
- }
- codepointToUTF8(codepoint, emit)
- }
- }
- /**
- * Converts a UTF-8 byte to a Unicode codepoint.
- *
- * @param byte The UTF-8 byte next in the sequence.
- * @param state The shared state between consecutive UTF-8 bytes in the
- * sequence, an object with the shape `{ utf8seq: 0, codepoint: 0 }`.
- * @param emit Function which will be called for each codepoint.
- */
- export function stringFromUTF8(
- byte: number,
- state: { utf8seq: number; codepoint: number },
- emit: (codepoint: number) => void
- ) {
- if (state.utf8seq === 0) {
- if (byte <= 0x7f) {
- emit(byte)
- return
- }
- // count the number of 1 leading bits until you reach 0
- for (let leadingBit = 1; leadingBit < 6; leadingBit += 1) {
- if (((byte >> (7 - leadingBit)) & 1) === 0) {
- state.utf8seq = leadingBit
- break
- }
- }
- if (state.utf8seq === 2) {
- state.codepoint = byte & 31
- } else if (state.utf8seq === 3) {
- state.codepoint = byte & 15
- } else if (state.utf8seq === 4) {
- state.codepoint = byte & 7
- } else {
- throw new Error('Invalid UTF-8 sequence')
- }
- state.utf8seq -= 1
- } else if (state.utf8seq > 0) {
- if (byte <= 0x7f) {
- throw new Error('Invalid UTF-8 sequence')
- }
- state.codepoint = (state.codepoint << 6) | (byte & 63)
- state.utf8seq -= 1
- if (state.utf8seq === 0) {
- emit(state.codepoint)
- }
- }
- }
|