var Buffer = require("buffer").Buffer; function JSInflater(/*Buffer*/input) { var WSIZE = 0x8000, slide = Buffer.alloc(0x10000), windowPos = 0, fixedTableList = null, fixedTableDist, fixedLookup, bitBuf = 0, bitLen = 0, method = -1, eof = false, copyLen = 0, copyDist = 0, tblList, tblDist, bitList, bitdist, inputPosition = 0, MASK_BITS = [0x0000, 0x0001, 0x0003, 0x0007, 0x000f, 0x001f, 0x003f, 0x007f, 0x00ff, 0x01ff, 0x03ff, 0x07ff, 0x0fff, 0x1fff, 0x3fff, 0x7fff, 0xffff], LENS = [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, 0, 0], LEXT = [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, 99, 99], DISTS = [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], DEXT = [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], BITORDER = [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15]; function HuffTable(clen, cnum, cval, blist, elist, lookupm) { this.status = 0; this.r = null; this.maxbit = 0; var el, f, tail, offsets = [], countTbl = [], sTbl = [], values = [], tentry = {extra: 0, bitcnt: 0, lbase: 0, next: null}; tail = this.r = null; for (var i = 0; i < 0x11; i++) { countTbl[i] = 0; sTbl[i] = 0; offsets[i] = 0; } for (i = 0; i < 0x120; i++) values[i] = 0; el = cnum > 256 ? clen[256] : 16; var pidx = -1; while (++pidx < cnum) countTbl[clen[pidx]]++; if (countTbl[0] === cnum) return; for (var j = 1; j <= 16; j++) if (countTbl[j] !== 0) break; var bitLen = j; for (i = 16; i !== 0; i--) if (countTbl[i] !== 0) break; var maxLen = i; lookupm < j && (lookupm = j); var dCodes = 1 << j; for (; j < i; j++, dCodes <<= 1) if ((dCodes -= countTbl[j]) < 0) { this.status = 2; this.maxbit = lookupm; return; } if ((dCodes -= countTbl[i]) < 0) { this.status = 2; this.maxbit = lookupm; return; } countTbl[i] += dCodes; offsets[1] = j = 0; pidx = 1; var xp = 2; while (--i > 0) offsets[xp++] = (j += countTbl[pidx++]); pidx = 0; i = 0; do { (j = clen[pidx++]) && (values[offsets[j]++] = i); } while (++i < cnum); cnum = offsets[maxLen]; offsets[0] = i = 0; pidx = 0; var level = -1, w = sTbl[0] = 0, cnode = null, tblCnt = 0, tblStack = []; for (; bitLen <= maxLen; bitLen++) { var kccnt = countTbl[bitLen]; while (kccnt-- > 0) { while (bitLen > w + sTbl[1 + level]) { w += sTbl[1 + level]; level++; tblCnt = (tblCnt = maxLen - w) > lookupm ? lookupm : tblCnt; if ((f = 1 << (j = bitLen - w)) > kccnt + 1) { f -= kccnt + 1; xp = bitLen; while (++j < tblCnt) { if ((f <<= 1) <= countTbl[++xp]) break; f -= countTbl[xp]; } } if (w + j > el && w < el) j = el - w; tblCnt = 1 << j; sTbl[1 + level] = j; cnode = []; while (cnode.length < tblCnt) cnode.push({extra: 0, bitcnt: 0, lbase: 0, next: null}); if (tail == null) { tail = this.r = {next: null, list: null}; } else { tail = tail.next = {next: null, list: null} } tail.next = null; tail.list = cnode; tblStack[level] = cnode; if (level > 0) { offsets[level] = i; tentry.bitcnt = sTbl[level]; tentry.extra = 16 + j; tentry.next = cnode; j = (i & ((1 << w) - 1)) >> (w - sTbl[level]); tblStack[level - 1][j].extra = tentry.extra; tblStack[level - 1][j].bitcnt = tentry.bitcnt; tblStack[level - 1][j].lbase = tentry.lbase; tblStack[level - 1][j].next = tentry.next; } } tentry.bitcnt = bitLen - w; if (pidx >= cnum) tentry.extra = 99; else if (values[pidx] < cval) { tentry.extra = (values[pidx] < 256 ? 16 : 15); tentry.lbase = values[pidx++]; } else { tentry.extra = elist[values[pidx] - cval]; tentry.lbase = blist[values[pidx++] - cval]; } f = 1 << (bitLen - w); for (j = i >> w; j < tblCnt; j += f) { cnode[j].extra = tentry.extra; cnode[j].bitcnt = tentry.bitcnt; cnode[j].lbase = tentry.lbase; cnode[j].next = tentry.next; } for (j = 1 << (bitLen - 1); (i & j) !== 0; j >>= 1) i ^= j; i ^= j; while ((i & ((1 << w) - 1)) !== offsets[level]) { w -= sTbl[level]; level--; } } } this.maxbit = sTbl[1]; this.status = ((dCodes !== 0 && maxLen !== 1) ? 1 : 0); } function addBits(n) { while (bitLen < n) { bitBuf |= input[inputPosition++] << bitLen; bitLen += 8; } return bitBuf; } function cutBits(n) { bitLen -= n; return bitBuf >>= n; } function maskBits(n) { while (bitLen < n) { bitBuf |= input[inputPosition++] << bitLen; bitLen += 8; } var res = bitBuf & MASK_BITS[n]; bitBuf >>= n; bitLen -= n; return res; } function codes(buff, off, size) { var e, t; if (size === 0) return 0; var n = 0; for (; ;) { t = tblList.list[addBits(bitList) & MASK_BITS[bitList]]; e = t.extra; while (e > 16) { if (e === 99) return -1; cutBits(t.bitcnt); e -= 16; t = t.next[addBits(e) & MASK_BITS[e]]; e = t.extra; } cutBits(t.bitcnt); if (e === 16) { windowPos &= WSIZE - 1; buff[off + n++] = slide[windowPos++] = t.lbase; if (n === size) return size; continue; } if (e === 15) break; copyLen = t.lbase + maskBits(e); t = tblDist.list[addBits(bitdist) & MASK_BITS[bitdist]]; e = t.extra; while (e > 16) { if (e === 99) return -1; cutBits(t.bitcnt); e -= 16; t = t.next[addBits(e) & MASK_BITS[e]]; e = t.extra } cutBits(t.bitcnt); copyDist = windowPos - t.lbase - maskBits(e); while (copyLen > 0 && n < size) { copyLen--; copyDist &= WSIZE - 1; windowPos &= WSIZE - 1; buff[off + n++] = slide[windowPos++] = slide[copyDist++]; } if (n === size) return size; } method = -1; // done return n; } function stored(buff, off, size) { cutBits(bitLen & 7); var n = maskBits(0x10); if (n !== ((~maskBits(0x10)) & 0xffff)) return -1; copyLen = n; n = 0; while (copyLen > 0 && n < size) { copyLen--; windowPos &= WSIZE - 1; buff[off + n++] = slide[windowPos++] = maskBits(8); } if (copyLen === 0) method = -1; return n; } function fixed(buff, off, size) { var fixed_bd = 0; if (fixedTableList == null) { var lengths = []; for (var symbol = 0; symbol < 144; symbol++) lengths[symbol] = 8; for (; symbol < 256; symbol++) lengths[symbol] = 9; for (; symbol < 280; symbol++) lengths[symbol] = 7; for (; symbol < 288; symbol++) lengths[symbol] = 8; fixedLookup = 7; var htbl = new HuffTable(lengths, 288, 257, LENS, LEXT, fixedLookup); if (htbl.status !== 0) return -1; fixedTableList = htbl.r; fixedLookup = htbl.maxbit; for (symbol = 0; symbol < 30; symbol++) lengths[symbol] = 5; fixed_bd = 5; htbl = new HuffTable(lengths, 30, 0, DISTS, DEXT, fixed_bd); if (htbl.status > 1) { fixedTableList = null; return -1; } fixedTableDist = htbl.r; fixed_bd = htbl.maxbit; } tblList = fixedTableList; tblDist = fixedTableDist; bitList = fixedLookup; bitdist = fixed_bd; return codes(buff, off, size); } function dynamic(buff, off, size) { var ll = new Array(0x023C); for (var m = 0; m < 0x023C; m++) ll[m] = 0; var llencnt = 257 + maskBits(5), dcodescnt = 1 + maskBits(5), bitlencnt = 4 + maskBits(4); if (llencnt > 286 || dcodescnt > 30) return -1; for (var j = 0; j < bitlencnt; j++) ll[BITORDER[j]] = maskBits(3); for (; j < 19; j++) ll[BITORDER[j]] = 0; // build decoding table for trees--single level, 7 bit lookup bitList = 7; var hufTable = new HuffTable(ll, 19, 19, null, null, bitList); if (hufTable.status !== 0) return -1; // incomplete code set tblList = hufTable.r; bitList = hufTable.maxbit; var lencnt = llencnt + dcodescnt, i = 0, lastLen = 0; while (i < lencnt) { var hufLcode = tblList.list[addBits(bitList) & MASK_BITS[bitList]]; j = hufLcode.bitcnt; cutBits(j); j = hufLcode.lbase; if (j < 16) ll[i++] = lastLen = j; else if (j === 16) { j = 3 + maskBits(2); if (i + j > lencnt) return -1; while (j-- > 0) ll[i++] = lastLen; } else if (j === 17) { j = 3 + maskBits(3); if (i + j > lencnt) return -1; while (j-- > 0) ll[i++] = 0; lastLen = 0; } else { j = 11 + maskBits(7); if (i + j > lencnt) return -1; while (j-- > 0) ll[i++] = 0; lastLen = 0; } } bitList = 9; hufTable = new HuffTable(ll, llencnt, 257, LENS, LEXT, bitList); bitList === 0 && (hufTable.status = 1); if (hufTable.status !== 0) return -1; tblList = hufTable.r; bitList = hufTable.maxbit; for (i = 0; i < dcodescnt; i++) ll[i] = ll[i + llencnt]; bitdist = 6; hufTable = new HuffTable(ll, dcodescnt, 0, DISTS, DEXT, bitdist); tblDist = hufTable.r; bitdist = hufTable.maxbit; if ((bitdist === 0 && llencnt > 257) || hufTable.status !== 0) return -1; return codes(buff, off, size); } return { inflate: function (/*Buffer*/outputBuffer) { tblList = null; var size = outputBuffer.length, offset = 0, i; while (offset < size) { if (eof && method === -1) return; if (copyLen > 0) { if (method !== 0) { while (copyLen > 0 && offset < size) { copyLen--; copyDist &= WSIZE - 1; windowPos &= WSIZE - 1; outputBuffer[offset++] = (slide[windowPos++] = slide[copyDist++]); } } else { while (copyLen > 0 && offset < size) { copyLen--; windowPos &= WSIZE - 1; outputBuffer[offset++] = (slide[windowPos++] = maskBits(8)); } copyLen === 0 && (method = -1); // done } if (offset === size) return; } if (method === -1) { if (eof) break; eof = maskBits(1) !== 0; method = maskBits(2); tblList = null; copyLen = 0; } switch (method) { case 0: i = stored(outputBuffer, offset, size - offset); break; case 1: i = tblList != null ? codes(outputBuffer, offset, size - offset) : fixed(outputBuffer, offset, size - offset); break; case 2: i = tblList != null ? codes(outputBuffer, offset, size - offset) : dynamic(outputBuffer, offset, size - offset); break; default: i = -1; break; } if (i === -1) return; offset += i; } } }; } module.exports = function (/*Buffer*/inbuf) { var zlib = require("zlib"); return { inflateAsync: function (/*Function*/callback) { var tmp = zlib.createInflateRaw(), parts = [], total = 0; tmp.on('data', function (data) { parts.push(data); total += data.length; }); tmp.on('end', function () { var buf = Buffer.alloc(total), written = 0; buf.fill(0); for (var i = 0; i < parts.length; i++) { var part = parts[i]; part.copy(buf, written); written += part.length; } callback && callback(buf); }); tmp.end(inbuf) }, inflate: function (/*Buffer*/outputBuffer) { var x = { x: new JSInflater(inbuf) }; x.x.inflate(outputBuffer); delete(x.x); } } };