All files / base64/src createFromBase64Bin.ts

92.3% Statements 72/78
82.05% Branches 32/39
100% Functions 2/2
100% Lines 63/63

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 741x   1x 1x 1x 64x 1x 123x 64x   1x 1x   1x 200x 200x 200x 69x 69x   131x 131x 131x 69x 69x     200x 200x 200x 200x 200x 200x 200x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x 3332x   200x 138x 66x 66x 66x 66x 66x 66x 66x 66x 66x 66x 66x   72x 72x 72x 72x 72x 72x 72x 72x      
import {alphabet} from './constants';
 
export const createFromBase64Bin = (chars: string = alphabet, pad: string = '=') => {
  Iif (chars.length !== 64) throw new Error('chars must be 64 characters long');
  let max = 0;
  for (let i = 0; i < chars.length; i++) max = Math.max(max, chars.charCodeAt(i));
  const table: number[] = [];
  for (let i = 0; i <= max; i += 1) table[i] = -1;
  for (let i = 0; i < chars.length; i++) table[chars.charCodeAt(i)] = i;
 
  const doExpectPadding = pad.length === 1;
  const PAD = doExpectPadding ? pad.charCodeAt(0) : 0;
 
  return (view: DataView, offset: number, length: number): Uint8Array => {
    Iif (!length) return new Uint8Array(0);
    let padding = 0;
    if (length % 4 !== 0) {
      padding = 4 - (length % 4);
      length += padding;
    } else {
      const end = offset + length;
      const last = end - 1;
      if (view.getUint8(last) === PAD) {
        padding = 1;
        if (length > 1 && view.getUint8(last - 1) === PAD) padding = 2;
      }
    }
    Iif (length % 4 !== 0) throw new Error('Base64 string length must be a multiple of 4');
    const mainEnd = offset + length - (padding ? 4 : 0);
    const bufferLength = (length >> 2) * 3 - padding;
    const buf = new Uint8Array(bufferLength);
    let j = 0;
    let i = offset;
    for (; i < mainEnd; i += 4) {
      const word = view.getUint32(i);
      const octet0 = word >>> 24;
      const octet1 = (word >>> 16) & 0xff;
      const octet2 = (word >>> 8) & 0xff;
      const octet3 = word & 0xff;
      const sextet0 = table[octet0];
      const sextet1 = table[octet1];
      const sextet2 = table[octet2];
      const sextet3 = table[octet3];
      Iif (sextet0 < 0 || sextet1 < 0 || sextet2 < 0 || sextet3 < 0) throw new Error('INVALID_BASE64_SEQ');
      buf[j] = (sextet0 << 2) | (sextet1 >> 4);
      buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2);
      buf[j + 2] = (sextet2 << 6) | sextet3;
      j += 3;
    }
    if (!padding) return buf;
    if (padding === 1) {
      const word = view.getUint16(mainEnd);
      const octet0 = word >> 8;
      const octet1 = word & 0xff;
      const octet2 = view.getUint8(mainEnd + 2);
      const sextet0 = table[octet0];
      const sextet1 = table[octet1];
      const sextet2 = table[octet2];
      Iif (sextet0 < 0 || sextet1 < 0 || sextet2 < 0) throw new Error('INVALID_BASE64_SEQ');
      buf[j] = (sextet0 << 2) | (sextet1 >> 4);
      buf[j + 1] = (sextet1 << 4) | (sextet2 >> 2);
      return buf;
    }
    const word = view.getUint16(mainEnd);
    const octet0 = word >> 8;
    const octet1 = word & 0xff;
    const sextet0 = table[octet0];
    const sextet1 = table[octet1];
    Iif (sextet0 < 0 || sextet1 < 0) throw new Error('INVALID_BASE64_SEQ');
    buf[j] = (sextet0 << 2) | (sextet1 >> 4);
    return buf;
  };
};