123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248 |
- const u8 = Uint8Array, u16 = Uint16Array;
- // fixed lengths
- const fl = new u16([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, /* unused */ 258, 258, /* impossible */ 258]);
- // fixed length extra bits
- // yes, this can be calculated, but hardcoding is more efficient
- const fleb = new u8([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, /* unused */ 0, 0, /* impossible */ 0]);
- // fixed distances
- const fd = new u16([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, /* unused */ 32768, 32768]);
- // fixed distance extra bits
- // see fleb note
- const fdeb = new u8([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, /* unused */ 13, 13]);
- // code length index map
- const clim = new u8([16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]);
- // map of value to reverse (assuming 16 bits)
- const rev = new u16(32768);
- for (let i = 0; i < 32768; ++i) {
- // reverse table algorithm from UZIP.js
- let x = i;
- x = ((x & 0xaaaaaaaa) >>> 1) | ((x & 0x55555555) << 1);
- x = ((x & 0xcccccccc) >>> 2) | ((x & 0x33333333) << 2);
- x = ((x & 0xf0f0f0f0) >>> 4) | ((x & 0x0f0f0f0f) << 4);
- rev[i] = ((x & 0xff00ff00) >>> 8) | ((x & 0x00ff00ff) << 8);
- }
- // create huffman tree from u8 "map": index -> code length for code index
- // mb (max bits) must be at most 15
- const hTree = (cd: Uint8Array, mb: number) => {
- // index
- let i = 0;
- // u8 "map": index -> # of codes with bit length = index
- const l = new u8(mb);
- // length of cd must be 288 (total # of codes)
- for (; i < cd.length; ++i) ++l[cd[i] - 1];
- // u16 "map": index -> minimum code for bit length = index
- const le = new u16(mb);
- for (i = 0; i < mb; ++i) {
- le[i] = (le[i - 1] + l[i - 1]) << 1;
- }
- // u16 "map": index -> number of actual bits, symbol for code
- const co = new u16(1 << mb);
- for (i = 0; i < cd.length; ++i) {
- // ignore 0 lengths
- if (cd[i]) {
- // num encoding both symbol and bits read
- const sv = (i << 4) | cd[i];
- // free bits
- const r = mb - cd[i];
- // bits to remove for reverser
- const rvb = 16 - mb;
- // start value
- let v = le[cd[i] - 1]++ << r;
- // m is end value
- for (const m = v | ((1 << r) - 1); v <= m; ++v) {
- // every 16 bit value starting with the code yields the same result
- co[rev[v] >>> rvb] = sv;
- }
- }
- }
- return co;
- }
- // fixed length tree
- const flt = new u8(288);
- for (let i = 0; i < 144; ++i) flt[i] = 8;
- for (let i = 144; i < 256; ++i) flt[i] = 9;
- for (let i = 256; i < 280; ++i) flt[i] = 7;
- for (let i = 280; i < 288; ++i) flt[i] = 8;
- // fixed distance tree
- const fdt = new u8(32);
- for (let i = 0; i < 32; ++i) fdt[i] = 5;
- // fixed length map
- const flm = hTree(flt, 9);
- // fixed distance map
- const fdm = hTree(fdt, 5);
- // fixed length mask
- const fml = (1 << 9) - 1;
- // fixed dist mask
- const fmd = (1 << 5) - 1;
- // find max of array
- const max = (a: Uint8Array) => {
- let m = a[0];
- for (let i = 0; i < a.length; ++i) {
- if (a[i] > m) m = a[i];
- }
- return m;
- };
- // read d, starting at bit p continuing for l bits
- const bits = (d: Uint8Array, p: number, l: number) => {
- const o = p >>> 3;
- return ((d[o] | (d[o + 1] << 8)) >>> (p & 7)) & ((1 << l) - 1);
- }
- // read d, starting at bit p continuing for at least 16 bits
- const bits16 = (d: Uint8Array, p: number) => {
- const o = p >>> 3;
- return ((d[o] | (d[o + 1] << 8) | (d[o + 2] << 16) | (d[o + 3] << 24)) >>> (p & 7));
- }
- // maximum chunk size (practically, theoretically infinite)
- const MC = 1 << 17;
- const inflate = (dat: Uint8Array, buf?: Uint8Array) => {
- // have to estimate size
- const noBuf = buf == null;
- // Slightly less than 2x - assumes ~60% compression ratio
- if (noBuf) buf = new u8((dat.length >>> 2) << 3);
- // ensure buffer can fit at least l elements
- const cbuf = (l: number) => {
- let bl = buf.length;
- // need to increase size to fit
- if (l > bl) {
- // Double or set to necessary, whichever is greater
- const nbuf = new u8(Math.max(bl << 1, l));
- nbuf.set(buf);
- buf = nbuf;
- }
- }
- // last chunk chunktype literal dist lengths lmask dmask
- let final = false, type = 0, hLit = 0, hDist = 0, hcLen = 0, ml = 0, md = 0;
- // bitpos bytes
- let pos = 0, bt = 0;
- // len dist
- let lm: Uint16Array, dm: Uint16Array;
- while (!final) {
- // BFINAL - this is only 1 when last chunk is next
- final = bits(dat, pos, 1) as unknown as boolean;
- // type: 0 = no compression, 1 = fixed huffman, 2 = dynamic huffman
- type = bits(dat, pos + 1, 2);
- pos += 3;
- if (!type) {
- // go to end of byte boundary
- if (pos & 7) pos += 8 - (pos & 7);
- const s = (pos >>> 3) + 4, l = dat[s - 4] | (dat[s - 3] << 8);
- // ensure size
- if (noBuf) cbuf(bt + l);
- // Copy over uncompressed data
- buf.set(dat.subarray(s, s + l), bt);
- // Get new bitpos, update byte count
- pos = (s + l) << 3, bt += l;
- continue;
- }
- // Make sure the buffer can hold this + the largest possible addition
- if (noBuf) cbuf(bt + MC);
- if (type == 1) {
- lm = flm;
- dm = fdm;
- ml = fml;
- md = fmd;
- }
- else if (type == 2) {
- hLit = bits(dat, pos, 5) + 257;
- hDist = bits(dat, pos + 5, 5) + 1;
- hcLen = bits(dat, pos + 10, 4) + 4;
- pos += 14;
- // length+distance tree
- const ldt = new u8(hLit + hDist);
- // code length tree
- const clt = new u8(19);
- for (let i = 0; i < hcLen; ++i) {
- // use index map to get real code
- clt[clim[i]] = bits(dat, pos + i * 3, 3);
- }
- pos += hcLen * 3;
- // code lengths bits
- const clb = max(clt);
- // code lengths map
- const clm = hTree(clt, clb);
- for (let i = 0; i < ldt.length;) {
- const r = clm[bits(dat, pos, clb)];
- // bits read
- pos += r & 15;
- // symbol
- const s = r >>> 4;
- // code length to copy
- if (s < 16) {
- ldt[i++] = s;
- } else {
- // copy count
- let c = 0, n = 0;
- if (s == 16) n = 3 + bits(dat, pos, 2), pos += 2, c = ldt[i - 1];
- else if (s == 17) n = 3 + bits(dat, pos, 3), pos += 3;
- else if (s == 18) n = 11 + bits(dat, pos, 7), pos += 7;
- while (n--) ldt[i++] = c;
- }
- }
- // length tree distance tree
- const lt = ldt.subarray(0, hLit), dt = ldt.subarray(hLit);
- // max length bits
- const mlb = max(lt)
- // max dist bits
- const mdb = max(dt);
- ml = (1 << mlb) - 1;
- lm = hTree(lt, mlb);
- md = (1 << mdb) - 1;
- dm = hTree(dt, mdb);
- }
- while (1) {
- // bits read, code
- const c = lm[bits16(dat, pos) & ml];
- pos += c & 15;
- // code
- const sym = c >>> 4;
- if (sym < 256) buf[bt++] = sym;
- else if (sym == 256) break;
- else {
- let end = bt + sym - 254;
- // no extra bits needed if less
- if (sym > 264) {
- // index
- const i = sym - 257;
- end = bt + bits(dat, pos, fleb[i]) + fl[i];
- pos += fleb[i];
- }
- // dist
- const d = dm[bits16(dat, pos) & md];
- pos += d & 15;
- const dsym = d >>> 4;
- let dt = fd[dsym];
- if (dsym > 3) {
- dt += bits16(dat, pos) & ((1 << fdeb[dsym]) - 1);
- pos += fdeb[dsym];
- }
- if (noBuf) cbuf(bt + MC);
- while (bt < end) {
- buf[bt] = buf[bt++-dt];
- buf[bt] = buf[bt++-dt];
- buf[bt] = buf[bt++-dt];
- buf[bt] = buf[bt++-dt];
- }
- bt = end;
- }
- }
- }
- return buf.slice(0, bt);
- }
- export { inflate };
|