Переглянути джерело

Improved compression performance and ratio

Arjun Barrett 4 роки тому
батько
коміт
3362e391d5
8 змінених файлів з 106 додано та 345 видалено
  1. 3 0
      .gitignore
  2. 3 1
      README.md
  3. 0 248
      index.ts
  4. 3 2
      package.json
  5. 86 89
      src/flate.ts
  6. 1 0
      src/index.ts
  7. 1 1
      tsconfig.json
  8. 9 4
      yarn.lock

+ 3 - 0
.gitignore

@@ -1,4 +1,7 @@
 node_modules/
 lib/
 esm/
+# following two are temporary before official tests
+tmp/
+test.js
 .DS_STORE

+ 3 - 1
README.md

@@ -1,2 +1,4 @@
 # fflate
-Native performance (de)compression in a 5 kB package
+Native performance (de)compression in a 3 kB package
+
+## Purpose

+ 0 - 248
index.ts

@@ -1,248 +0,0 @@
-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 };

+ 3 - 2
package.json

@@ -1,7 +1,7 @@
 {
   "name": "fflate",
   "version": "0.0.1",
-  "description": "Native performance (de)compression in a 5kB package",
+  "description": "Native performance (de)compression in a 3kB package",
   "main": "lib/index.js",
   "module": "esm/index.js",
   "types": "lib/index.d.ts",
@@ -14,7 +14,8 @@
     "prepublish": "yarn build"
   },
   "devDependencies": {
+    "pako": "^1.0.11",
     "typescript": "^4.0.2",
-    "uzip": "^0.20200905.0"
+    "uzip": "^0.20200919.0"
   }
 }

+ 86 - 89
src/flate.ts

@@ -307,33 +307,34 @@ const hTree = (d: Uint16Array, mb: number) => {
   // Need extra info to make a tree
   const t: HuffNode[] = [];
   for (let i = 0; i < d.length; ++i) {
-    if (d[i]) {
-      t.push({ s: i, f: d[i] });
-    }
+    if (d[i]) t.push({ s: i, f: d[i] });
   }
   const s = t.length;
   const t2 = t.slice();
-  // after i2 reaches last ind, will be stopped
-  t.push({ s: -1, f: 32768 });
   if (s == 0) return [new u8(0), 0] as const;
-  if (s == 1) return [new u8([!t[0].s as unknown as number]), 1] as const;
+  if (s == 1) {
+    const v = new u8(t[0].s + 1);
+    v[t[0].s] = 1;
+    return [v, 1] as const;
+  }
   t.sort((a, b) => a.f - b.f);
+  // after i2 reaches last ind, will be stopped
+  // freq must be greater than largest possible number of symbols
+  t.push({ s: -1, f: 25001 });
   let l = t[0], r = t[1], i0 = 0, i1 = 1, i2 = 2;
   t[0] = { s: -1, f: l.f + r.f, l, r };
-  // complex algorithm from UZIP.js
+  // efficient algorithm from UZIP.js
   // i0 is lookbehind, i2 is lookahead - after processing two low-freq
   // symbols that combined have high freq, will start processing i2 (high-freq,
   // non-composite) symbols instead
   // see https://reddit.com/r/photopea/comments/ikekht/uzipjs_questions/
 	while (i1 != s - 1) {
-    if (t[i0].f < t[i2].f) l = t[i0++];
-    else l = t[i2++];
-    if (i0 != i1 && t[i0].f < t[i2].f) r = t[i0++];
-    else r = t[i2++];
+    l = t[t[i0].f < t[i2].f ? i0++ : i2++];
+    r = t[i0 != i1 && t[i0].f < t[i2].f ? i0++ : i2++];
     t[i1++] = { s: -1, f: l.f + r.f, l, r };
   }
   let maxSym = t2[0].s;
-  for (let i = 0; i < s; ++i) {
+  for (let i = 1; i < s; ++i) {
     if (t2[i].s > maxSym) maxSym = t2[i].s;
   }
   // code lengths
@@ -345,8 +346,8 @@ const hTree = (d: Uint16Array, mb: number) => {
     // TODO: find out how this code works (debt)
     //  ind    debt
     let i = 0, dt = 0;
-    // cost
-    const cst = 1 << (mbt - mb);
+    //    left            cost
+    const lft = mbt - mb, cst = 1 << lft;
     t2.sort((a, b) => tr[b.s] - tr[a.s] || a.f - b.f);
     for (; i < s; ++i) {
       const i2 = t2[i].s;
@@ -355,13 +356,13 @@ const hTree = (d: Uint16Array, mb: number) => {
         tr[i2] = mb;
       } else break;
     }
-    dt >>>= (mbt - mb);
+    dt >>>= lft;
     while (dt > 0) {
       const i2 = t2[i].s;
       if (tr[i2] < mb) dt -= 1 << (mb - tr[i2]++ - 1);
       else ++i;
     }
-    for (; i >= 0 && !dt; --i) {
+    for (; i >= 0 && dt; --i) {
       const i2 = t2[i].s;
       if (tr[i2] == mb) {
         --tr[i2];
@@ -384,32 +385,30 @@ const lc = (c: Uint8Array) => {
   let s = c.length;
   // Note that the semicolon was intentional
   while (s && !c[--s]);
-  ++s;
-  const cl = new u16(s);
-  //  ind      num      streak
+  const cl = new u16(++s);
+  //  ind      num         streak
   let cli = 0, cln = c[0], cls = 1;
   const w = (v: number) => { cl[cli++] = v; }
-  for (let i = 1; i < s; ++i) {
-    if (c[i] == cln && i != s - 1)
+  for (let i = 1; i <= s; ++i) {
+    if (c[i] == cln && i != s)
       ++cls;
     else {
-      if (!cln && cls > 3) {
-        for (; cls > 138; cls -= 138) w(4082);
-        if (cls > 3) {
-          w(cls > 10 ? ((cls - 11) << 5) | 18 : ((cls - 3) << 5) | 17);
+      if (!cln && cls > 2) {
+        for (; cls > 138; cls -= 138) w(32754);
+        if (cls > 2) {
+          w(cls > 10 ? ((cls - 11) << 5) | 28690 : ((cls - 3) << 5) | 12305);
           cls = 0;
         }
-      } else if (cls > 4) {
+      } else if (cls > 3) {
         w(cln), --cls;
-        for (; cls > 6; cls -= 6) w(112);
-        if (cls > 3) w(((cls - 3) << 5) | 16), cls = 0;
+        for (; cls > 6; cls -= 6) w(8304);
+        if (cls > 2) w(((cls - 3) << 5) | 8208), cls = 0;
       }
-      cl.fill(cln, cli, cli += cls);
+      while (cls--) w(cln);
       cls = 1;
       cln = c[i];
     }
   }
-  w(cln);
   return [cl.slice(0, cli), s] as const;
 }
 
@@ -469,9 +468,7 @@ const wblk = (dat: Uint8Array, out: Uint8Array, final: number, syms: Uint32Array
       for (let i = 0; i < clct.length; ++i) {
         const len = clct[i] & 31;
         wbits(out, p, llm[len]), p += lct[len];
-        if (len > 15) {
-          wbits(out, p, clct[i] >>> 5), p += len == 16 ? 2 : len == 17 ? 3 : 7;
-        }
+        if (len > 15) wbits(out, p, (clct[i] >>> 5) & 127), p += clct[i] >>> 12;
       }
     }
   } else {
@@ -479,12 +476,12 @@ const wblk = (dat: Uint8Array, out: Uint8Array, final: number, syms: Uint32Array
   }
   for (let i = 0; i < li; ++i) {
     if (syms[i] > 255) {
-      const len = syms[i] & 31;
+      const len = (syms[i] >>> 18) & 31;
       wbits16(out, p, lm[len + 257]), p += ll[len + 257];
-      if (len > 7) wbits(out, p, (syms[i] >>> 5) & 31), p += fleb[len];
-      const dst = (syms[i] >>> 10) & 31;
+      if (len > 7) wbits(out, p, (syms[i] >>> 23) & 31), p += fleb[len];
+      const dst = syms[i] & 31;
       wbits16(out, p, dm[dst]), p += dl[dst];
-      if (dst > 3) wbits16(out, p, (syms[i] >>> 15) & 8191), p += fdeb[dst];
+      if (dst > 3) wbits16(out, p, (syms[i] >>> 5) & 8191), p += fdeb[dst];
     } else {
       wbits16(out, p, lm[syms[i]]), p += ll[syms[i]];
     }
@@ -497,9 +494,9 @@ const wblk = (dat: Uint8Array, out: Uint8Array, final: number, syms: Uint32Array
 const deo = new u32([65540, 131080, 131088, 131104, 262176, 1048704, 1048832, 2114560, 2117632]);
 
 // compresses data into a raw DEFLATE buffer
-const deflate = (dat: Uint8Array, lvl: number, pre = 0, post = 0) => {
+const deflate = (dat: Uint8Array, lvl: number, plvl: number, pre: number, post: number) => {
   const s = dat.length;
-  const o = new u8(pre + s + 5 * Math.ceil(s / 16384) + post);
+  const o = new u8(pre + s + 5 * Math.ceil(s / 17000) + post);
   // writing to this writes to the output buffer
   const w = o.subarray(pre, o.length - post);
   if (!lvl || dat.length < 4) {
@@ -519,76 +516,77 @@ const deflate = (dat: Uint8Array, lvl: number, pre = 0, post = 0) => {
   }
   const opt = deo[lvl - 1];
   const n = opt >>> 13, c = opt & 8191;
+  const msk = (1 << plvl) - 1;
   //    prev 2-byte val map    curr 2-byte val map
-  const prev = new u16(32768), head = new u16(32768);
-  // 12288 is an arbitrary choice for max num of symbols per block
-  // 112 extra to never need to create a tiny huffman block near the end
-  const syms = new u32(12400);
+  const prev = new u16(32768), head = new u16(msk + 1);
+  const hsh = (i: number) => (dat[i] | (dat[i + 1] << 8) | (dat[i + 2] << 16)) & msk;
+  // 24576 is an arbitrary number of maximum symbols per block
+  // 423 buffer for last block
+  const syms = new u32(25000);
   // length/literal freq   distance freq
   const lf = new u16(286), df = new u16(30);
-  // punishment for missing a value
-  const pnsh = Math.floor(lvl / 2)
   //  l/lcnt  exbits  index  l/lind  waitdx  bitpos
-  let lc = 0, eb = 0, i = 0, li = 0, wi = 0, bs = 0, pos = 0;
+  let eb = 0, i = 0, li = 0, wi = 0, bs = 0, pos = 0;
   for (; i < s; ++i) {
-    // first 2 bytes
-    const b2 = dat[i] | (dat[i + 1] << 8);
+    // hash value
+    const hv = hsh(i);
     // index mod 32768
     let imod = i & 32767;
     // previous index with this value
-    let pimod = head[b2];
+    let pimod = head[hv];
     prev[imod] = pimod;
-    head[b2] = imod;
+    head[hv] = imod;
     // We always should modify head and prev, but only add symbols if
     // this data is not yet processed ("wait" for wait index)
     if (wi <= i) {
-      // 24573 arbitrary: 24576 - 3
-      if ((li > 12288 || lc > 24573) && s - i > 111) {
+      // bytes remaining
+      const rem = s - i;
+      if (li > 24576 && rem > 423) {
         pos = wblk(dat, w, 0, syms, lf, df, eb, li, bs, i - bs, pos);
-        li = lc = eb = 0, bs = i;
+        li = eb = 0, bs = i;
         for (let j = 0; j < 286; ++j) lf[j] = 0;
         for (let j = 0; j < 30; ++j) df[j] = 0;
       }
-      // bytes remaining
-      const rem = s - i;
       //  len    dist   chain
-      let l = 2, d = 0, ch = c, dif = (imod - pimod + 32768) & 32767;
-      const maxn = Math.min(n, rem);
-      const maxd = Math.min(32767, i);
-      // max possible max length
-      const ml = Math.min(258, rem);
-      while (dif <= maxd && --ch && imod != pimod) {
-        if (dat[i + l] == dat[i + l - dif]) {
-          let nl = 0;
-          // const ml = Math.min(mml, dif);
-          for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl);
-          if (nl > l) {
-            l = nl;
-            d = dif;
-            // break out early when we reach "nice" (we are satisfied enough)
-            if (nl >= maxn) break;
-            // now, find the rarest 2-byte sequence within this
-            // length of literals and search for that instead.
-            // Much faster than just using the start
-            const mmd = nl - 2;
-            let md = 0;
-            for (let j = 0; j < mmd; ++j) {
-              const ti = (i - dif + j + 32768) & 32767;
-              const pti = prev[ti];
-              const cd = (ti - pti + 32768) & 32767;
-              if (cd > md) md = cd, pimod = ti;
+      let l = 0, d = 0, ch = c, dif = (i - pimod) & 32767;
+      if (rem > 2 && hv == hsh(i - dif)) {
+        const maxn = Math.min(n, rem);
+        const maxd = Math.min(32767, i);
+        // max possible max length
+        // not capped at dif because decompressors implement "rolling" index population
+        const ml = Math.min(258, rem);
+        while (dif <= maxd && --ch && imod != pimod) {
+          if (dat[i + l] == dat[i + l - dif]) {
+            let nl = 0;
+            for (; nl < ml && dat[i + nl] == dat[i + nl - dif]; ++nl);
+            if (nl > l) {
+              l = nl;
+              d = dif;
+              // break out early when we reach "nice" (we are satisfied enough)
+              if (nl >= maxn) break;
+              // now, find the rarest 2-byte sequence within this
+              // length of literals and search for that instead.
+              // Much faster than just using the start
+              const mmd = Math.min(dif, nl - 2);
+              let md = 0;
+              for (let j = 0; j < mmd; ++j) {
+                const ti = (i - dif + j + 32768) & 32767;
+                const pti = prev[ti];
+                const cd = (ti - pti + 32768) & 32767;
+                if (cd > md) md = cd, pimod = ti;
+              }
             }
-          } else if (nl < 2) ch >>>= pnsh; // this is cheating, but we need performance :/
+          }
+          // check the previous match
+          imod = pimod, pimod = prev[imod];
+          dif += (imod - pimod + 32768) & 32767;
         }
-        // check the previous match
-        imod = pimod, pimod = prev[pimod];
-        dif += (imod - pimod + 32768) & 32767;
       }
-      // d will be nonzero only when a match was found
-      if (d) {
+      // l will be nonzero only when a match was found
+      if (l) {
         // store both dist and len data in one Uint32
         // Make sure this is recognized as a len/dist with 28th bit (2^28)
-        syms[li++] = 268435456 | (revfd[d] << 10) | revfl[l];
+        syms[li++] = 268435456 | (revfl[l] << 18) | revfd[d];
         const lin = revfl[l] & 31, din = revfd[d] & 31;
         eb += fleb[lin] + fdeb[din];
         ++lf[257 + lin];
@@ -598,11 +596,10 @@ const deflate = (dat: Uint8Array, lvl: number, pre = 0, post = 0) => {
         syms[li++] = dat[i];
         ++lf[dat[i]];
       }
-      ++lc;
     }
   }
   if (bs != i) pos = wblk(dat, w, 1, syms, lf, df, eb, li, bs, i - bs, pos);
-  return o.subarray(0, (pos >>> 3) + 1 + post);
+  return o.slice(0, (pos >>> 3) + 1 + post);
 }
 
 

+ 1 - 0
src/index.ts

@@ -0,0 +1 @@
+export * from './flate';

+ 1 - 1
tsconfig.json

@@ -3,5 +3,5 @@
     "declaration": true,
     "outDir": "lib/"
   },
-  "files": ["index.ts"]
+  "files": ["src/index.ts"]
 }

+ 9 - 4
yarn.lock

@@ -2,12 +2,17 @@
 # yarn lockfile v1
 
 
+pako@^1.0.11:
+  version "1.0.11"
+  resolved "https://registry.yarnpkg.com/pako/-/pako-1.0.11.tgz#6c9599d340d54dfd3946380252a35705a6b992bf"
+  integrity sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==
+
 typescript@^4.0.2:
   version "4.0.2"
   resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.0.2.tgz#7ea7c88777c723c681e33bf7988be5d008d05ac2"
   integrity sha512-e4ERvRV2wb+rRZ/IQeb3jm2VxBsirQLpQhdxplZ2MEzGvDkkMmPglecnNDfSUBivMjP93vRbngYYDQqQ/78bcQ==
 
-uzip@^0.20200905.0:
-  version "0.20200905.0"
-  resolved "https://registry.yarnpkg.com/uzip/-/uzip-0.20200905.0.tgz#d23ba62d775ee81a2b768584db25dd14c20db1a6"
-  integrity sha512-gFDRsTJ2zJsPiZzO48J245DC+75GnpfKg2eLZis3G0VY6zt0z1dvdR5eARZBs+dIz8elKm9XciVdPosPJjV0Cw==
+uzip@^0.20200919.0:
+  version "0.20200919.0"
+  resolved "https://registry.yarnpkg.com/uzip/-/uzip-0.20200919.0.tgz#a4ae1d13265f086021e2e7933412b9b8d9f06155"
+  integrity sha512-bdwScsEC5g17c7qZAHceJAm1TCuJl6f8JvpREkF2voFx00NlqU5yewvJrggXvIddEkxwyJ3e0DSrh6NDul/RHg==