190 lines · 7.0 KB
const MAX_BITS = 15;
const ZLIB_HEADER_BYTES = 2;
const ADLER_BYTES = 4;
const END_OF_BLOCK = 256;
const REPEAT_PREVIOUS = 16;
const REPEAT_ZERO_SHORT = 17;
const LENGTH_BASE = [
  3, 4, 5, 6, 7, 8, 9, 10, 11, 13, 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258,
];
const LENGTH_EXTRA = [0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 5, 5, 5, 5, 0];
const DIST_BASE = [
  1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145,
  8193, 12289, 16385, 24577,
];
const DIST_EXTRA = [0, 0, 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13];
const CODE_LENGTH_ORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15];

type Huffman = { counts: Uint16Array; symbols: Uint16Array };

function buildHuffman(lengths: Uint8Array, offset: number, count: number): Huffman {
  const counts = new Uint16Array(MAX_BITS + 1);
  for (let index = 0; index < count; index++) counts[lengths[offset + index]]++;
  counts[0] = 0;
  const offsets = new Uint16Array(MAX_BITS + 1);
  for (let bits = 1; bits < MAX_BITS; bits++) offsets[bits + 1] = offsets[bits] + counts[bits];
  const symbols = new Uint16Array(count);
  for (let index = 0; index < count; index++) {
    const length = lengths[offset + index];
    if (length) symbols[offsets[length]++] = index;
  }
  return { counts, symbols };
}

const FIXED = (() => {
  const lengths = new Uint8Array(288 + 30);
  lengths.fill(8, 0, 144);
  lengths.fill(9, 144, 256);
  lengths.fill(7, 256, 280);
  lengths.fill(8, 280, 288);
  lengths.fill(5, 288, 318);