227 lines
7.1 KiB
JavaScript
227 lines
7.1 KiB
JavaScript
/* modified inflate function also moves original read head */
|
|
|
|
/* build tree (used for literals and lengths) */
|
|
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
|
|
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
|
|
|
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
|
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
|
|
|
for(i = L; i < MAX; ++i) clens[i] = 0;
|
|
L = clens.length;
|
|
|
|
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
|
|
|
/* build code tree */
|
|
for(i = 0; i < L; ++i) {
|
|
bl_count[(w = clens[i])]++;
|
|
if(maxlen < w) maxlen = w;
|
|
ctree[i] = 0;
|
|
}
|
|
bl_count[0] = 0;
|
|
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
|
for(i = 0; i < L; ++i) {
|
|
ccode = clens[i];
|
|
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
|
}
|
|
|
|
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
|
var cleni = 0;
|
|
for(i = 0; i < L; ++i) {
|
|
cleni = clens[i];
|
|
if(cleni != 0) {
|
|
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
|
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
|
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
|
}
|
|
}
|
|
return maxlen;
|
|
}
|
|
|
|
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
|
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
|
if(!use_typed_arrays) {
|
|
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
|
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
|
}
|
|
(function() {
|
|
var dlens/*:Array<number>*/ = [];
|
|
var i = 0;
|
|
for(;i<32; i++) dlens.push(5);
|
|
build_tree(dlens, fix_dmap, 32);
|
|
|
|
var clens/*:Array<number>*/ = [];
|
|
i = 0;
|
|
for(; i<=143; i++) clens.push(8);
|
|
for(; i<=255; i++) clens.push(9);
|
|
for(; i<=279; i++) clens.push(7);
|
|
for(; i<=287; i++) clens.push(8);
|
|
build_tree(clens, fix_lmap, 288);
|
|
})();
|
|
|
|
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
|
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
|
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
|
var dyn_len_1 = 1, dyn_len_2 = 1;
|
|
|
|
/* 5.5.3 Expanding Huffman Codes */
|
|
function dyn(data, boff/*:number*/) {
|
|
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
|
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
|
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
|
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
|
var w = 0;
|
|
|
|
/* grab and store code lengths */
|
|
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
|
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
|
var maxlen = 1;
|
|
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
|
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
|
var L = clens.length; /* 19 */
|
|
for(var i = 0; i < _HCLEN; ++i) {
|
|
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
|
if(maxlen < w) maxlen = w;
|
|
bl_count[w]++;
|
|
boff += 3;
|
|
}
|
|
|
|
/* build code tree */
|
|
var ccode = 0;
|
|
bl_count[0] = 0;
|
|
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
|
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
|
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
|
var cleni = 0;
|
|
for(i = 0; i < L; ++i) {
|
|
cleni = clens[i];
|
|
if(cleni != 0) {
|
|
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
|
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
|
}
|
|
}
|
|
|
|
/* read literal and dist codes at once */
|
|
var hcodes/*:Array<number>*/ = [];
|
|
maxlen = 1;
|
|
for(; hcodes.length < _HLIT + _HDIST;) {
|
|
ccode = dyn_cmap[read_bits_7(data, boff)];
|
|
boff += ccode & 7;
|
|
switch((ccode >>>= 3)) {
|
|
case 16:
|
|
w = 3 + read_bits_2(data, boff); boff += 2;
|
|
ccode = hcodes[hcodes.length - 1];
|
|
while(w-- > 0) hcodes.push(ccode);
|
|
break;
|
|
case 17:
|
|
w = 3 + read_bits_3(data, boff); boff += 3;
|
|
while(w-- > 0) hcodes.push(0);
|
|
break;
|
|
case 18:
|
|
w = 11 + read_bits_7(data, boff); boff += 7;
|
|
while(w -- > 0) hcodes.push(0);
|
|
break;
|
|
default:
|
|
hcodes.push(ccode);
|
|
if(maxlen < ccode) maxlen = ccode;
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* build literal / length trees */
|
|
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
|
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
|
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
|
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
|
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
|
return boff;
|
|
}
|
|
|
|
/* return [ data, bytesRead ] */
|
|
function inflate(data, usz/*:number*/) {
|
|
/* shortcircuit for empty buffer [0x03, 0x00] */
|
|
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
|
|
|
/* bit offset */
|
|
var boff = 0;
|
|
|
|
/* header includes final bit and type bits */
|
|
var header = 0;
|
|
|
|
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
|
var woff = 0;
|
|
var OL = outbuf.length>>>0;
|
|
var max_len_1 = 0, max_len_2 = 0;
|
|
|
|
while((header&1) == 0) {
|
|
header = read_bits_3(data, boff); boff += 3;
|
|
if((header >>> 1) == 0) {
|
|
/* Stored block */
|
|
if(boff & 7) boff += 8 - (boff&7);
|
|
/* 2 bytes sz, 2 bytes bit inverse */
|
|
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
|
boff += 32;
|
|
/* push sz bytes */
|
|
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
|
if(typeof data.copy === 'function') {
|
|
// $FlowIgnore
|
|
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
|
woff += sz; boff += 8*sz;
|
|
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
|
continue;
|
|
} else if((header >>> 1) == 1) {
|
|
/* Fixed Huffman */
|
|
max_len_1 = 9; max_len_2 = 5;
|
|
} else {
|
|
/* Dynamic Huffman */
|
|
boff = dyn(data, boff);
|
|
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
|
}
|
|
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
|
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
|
/* ingest code and move read head */
|
|
var bits = read_bits_n(data, boff, max_len_1);
|
|
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
|
boff += code & 15; code >>>= 4;
|
|
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
|
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
|
else if(code == 256) break;
|
|
else {
|
|
code -= 257;
|
|
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
|
var tgt = woff + LEN_LN[code];
|
|
/* length extra bits */
|
|
if(len_eb > 0) {
|
|
tgt += read_bits_n(data, boff, len_eb);
|
|
boff += len_eb;
|
|
}
|
|
|
|
/* dist code */
|
|
bits = read_bits_n(data, boff, max_len_2);
|
|
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
|
boff += code & 15; code >>>= 4;
|
|
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
|
var dst = DST_LN[code];
|
|
/* dist extra bits */
|
|
if(dst_eb > 0) {
|
|
dst += read_bits_n(data, boff, dst_eb);
|
|
boff += dst_eb;
|
|
}
|
|
|
|
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
|
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
|
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
|
}
|
|
}
|
|
}
|
|
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
|
}
|
|
|
|
function _inflate(payload, usz) {
|
|
var data = payload.slice(payload.l||0);
|
|
var out = inflate(data, usz);
|
|
payload.l += out[1];
|
|
return out[0];
|
|
}
|
|
|