All files base64u.ts

100% Statements 48/48
85.71% Branches 12/14
100% Functions 3/3
100% Lines 45/45

Press n or j to go to the next uncovered block, b, p or k for the previous block.

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 9186x         1x 1x 1x 62x     1x 1x   1x 19x 19x 19x 19x 19x                 19x   492x     492x 492x 492x 492x     492x       19x 5x   5x     5x   5x 14x 6x   6x 6x     6x   6x     19x     2x 12x 12x           12x   12x 336x 336x 336x 336x   336x 336x 336x     12x    
/**
 * Base64u - URL-Safe Base64 variant no padding.
 * Based on https://gist.github.com/jonleighton/958841
 */
 
const baseCharset = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789'
const lookup = new Uint8Array(256)
for (let i = 0; i < 62; i++) {
    lookup[baseCharset.charCodeAt(i)] = i
}
// support both urlsafe and standard base64
lookup[43] = lookup[45] = 62
lookup[47] = lookup[95] = 63
 
export function encode(data: Uint8Array, urlSafe = true): string {
    const byteLength = data.byteLength
    const byteRemainder = byteLength % 3
    const mainLength = byteLength - byteRemainder
    const charset = baseCharset + (urlSafe ? '-_' : '+/')
    const parts: string[] = []
 
    let a: number
    let b: number
    let c: number
    let d: number
    let chunk: number
 
    // Main loop deals with bytes in chunks of 3
    for (let i = 0; i < mainLength; i += 3) {
        // Combine the three bytes into a single integer
        chunk = (data[i] << 16) | (data[i + 1] << 8) | data[i + 2]
 
        // Use bitmasks to extract 6-bit segments from the triplet
        a = (chunk & 16515072) >> 18 // 16515072 = (2^6 - 1) << 18
        b = (chunk & 258048) >> 12 // 258048   = (2^6 - 1) << 12
        c = (chunk & 4032) >> 6 // 4032     = (2^6 - 1) << 6
        d = chunk & 63 // 63       =  2^6 - 1
 
        // Convert the raw binary segments to the appropriate ASCII encoding
        parts.push(charset[a] + charset[b] + charset[c] + charset[d])
    }
 
    // Deal with the remaining bytes
    if (byteRemainder === 1) {
        chunk = data[mainLength]
 
        a = (chunk & 252) >> 2 // 252 = (2^6 - 1) << 2
 
        // Set the 4 least significant bits to zero
        b = (chunk & 3) << 4 // 3   = 2^2 - 1
 
        parts.push(charset[a] + charset[b])
    } else if (byteRemainder === 2) {
        chunk = (data[mainLength] << 8) | data[mainLength + 1]
 
        a = (chunk & 64512) >> 10 // 64512 = (2^6 - 1) << 10
        b = (chunk & 1008) >> 4 // 1008  = (2^6 - 1) << 4
 
        // Set the 2 least significant bits to zero
        c = (chunk & 15) << 2 // 15    = 2^4 - 1
 
        parts.push(charset[a] + charset[b] + charset[c])
    }
 
    return parts.join('')
}
 
export function decode(input: string): Uint8Array {
    const byteLength = input.length * 0.75
    const data = new Uint8Array(byteLength)
 
    let a: number
    let b: number
    let c: number
    let d: number
    let p = 0
 
    for (let i = 0; i < input.length; i += 4) {
        a = lookup[input.charCodeAt(i)]
        b = lookup[input.charCodeAt(i + 1)]
        c = lookup[input.charCodeAt(i + 2)]
        d = lookup[input.charCodeAt(i + 3)]
 
        data[p++] = (a << 2) | (b >> 4)
        data[p++] = ((b & 15) << 4) | (c >> 2)
        data[p++] = ((c & 3) << 6) | (d & 63)
    }
 
    return data
}