From 1e70aae159e29df32d420f4242efb19edb05fc61 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Mon, 6 Sep 2021 15:53:23 -0400 Subject: [PATCH] version bump 1.2.1: DEFLATE --- CHANGELOG.md | 7 ++ README.md | 2 + bits/31_version.js | 2 +- bits/49_readutils.js | 6 +- bits/79_flate.js | 96 ++++++++++++++++- bits/80_deflate.js | 105 ++++++++++++++++-- bits/81_inflate.js | 63 +---------- bits/82_zparse.js | 2 +- bits/83_zwrite.js | 3 + bits/84_mht.js | 2 +- cfb.flow.js | 196 ++++++++++++++++++++++++++++------ cfb.js | 196 ++++++++++++++++++++++++++++------ dist/cfb.js | 249 +++++++++++++++++++++++++++++++++++-------- dist/cfb.min.js | 4 +- dist/cfb.min.map | 2 +- dist/xlscfb.js | 247 ++++++++++++++++++++++++++++++++++-------- index.html | 21 ++-- package.json | 6 +- xlscfb.flow.js | 196 ++++++++++++++++++++++++++++------ xlscfb.js | 196 ++++++++++++++++++++++++++++------ 20 files changed, 1298 insertions(+), 303 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2ff5950..651a75f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,13 @@ This log is intended to keep track of backwards-incompatible changes, including but not limited to API changes and file location changes. Minor behavioral changes may not be included if they are not expected to break existing code. +## 1.2.1 (2021-09-06) + +* CFB write optimizations (h/t @rossj Ross Johnson) +* `read` in NodeJS will treat `Buffer` input as type `"buffer"` by default +* `deflate` / ZIP support fixed Huffman compression +* `inflate` more aggressive reallocs + ## 1.2.0 (2020-07-09) * Support for MAD file format (MIME aggregate document) diff --git a/README.md b/README.md index 3967f4a..65e86b6 100644 --- a/README.md +++ b/README.md @@ -74,6 +74,7 @@ name, if there are no slashes) and returns an entry object or null if not found. |------------|:----------------------------------------------------------------| | `"base64"` | string: Base64 encoding of the file | | `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) | +| `"buffer"` | nodejs Buffer | | `"file"` | string: path of file that will be read (nodejs only) | | (default) | buffer or array of 8-bit unsigned int (byte `n` is `data[n]`) | @@ -88,6 +89,7 @@ name, if there are no slashes) and returns an entry object or null if not found. |------------|:----------------------------------------------------------------| | `"base64"` | string: Base64 encoding of the file | | `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) | +| `"buffer"` | nodejs Buffer | | `"file"` | string: path of file that will be created (nodejs only) | | (default) | buffer if available, array of 8-bit unsigned int otherwise | diff --git a/bits/31_version.js b/bits/31_version.js index 79633f6..668f4a1 100644 --- a/bits/31_version.js +++ b/bits/31_version.js @@ -1 +1 @@ -exports.version = '1.2.0'; +exports.version = '1.2.1'; diff --git a/bits/49_readutils.js b/bits/49_readutils.js index a80b454..3508016 100644 --- a/bits/49_readutils.js +++ b/bits/49_readutils.js @@ -4,7 +4,11 @@ function read_file(filename/*:string*/, options/*:CFBReadOpts*/) { } function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) { - switch(options && options.type || "base64") { + var type = options && options.type; + if(!type) { + if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; + } + switch(type || "base64") { case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options); case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options); case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options); diff --git a/bits/79_flate.js b/bits/79_flate.js index d516ccc..2394ce9 100644 --- a/bits/79_flate.js +++ b/bits/79_flate.js @@ -42,6 +42,38 @@ function read_bits_n(buf, bl, n) { return v & f; } +/* helpers for unaligned bit writes */ +function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz/*:number*/) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -55,7 +87,7 @@ function realloc(b, sz/*:number*/) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -67,4 +99,64 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -} \ No newline at end of file +} + +/* 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<*/ = []; + var i = 0; + for(;i<32; i++) dlens.push(5); + build_tree(dlens, fix_dmap, 32); + + var clens/*:Array*/ = []; + 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); +})(); \ No newline at end of file diff --git a/bits/80_deflate.js b/bits/80_deflate.js index dacac21..ec27913 100644 --- a/bits/80_deflate.js +++ b/bits/80_deflate.js @@ -1,23 +1,116 @@ -var _deflate = (function() { var _deflateRaw = (function() { - return function deflateRaw(data, out) { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { var boff = 0; while(boff < data.length) { var L = Math.min(0xFFFF, data.length - boff); var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ out.write_shift(1, +h); out.write_shift(2, L); out.write_shift(2, (~L) & 0xFFFF); while(L-- > 0) out[out.l++] = data[boff++]; } return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); }; })(); -return function(data) { +function _deflate(data) { var buf = new_buf(50+Math.floor(data.length*1.1)); var off = _deflateRaw(data, buf); return buf.slice(0, off); -}; -})(); +} diff --git a/bits/81_inflate.js b/bits/81_inflate.js index 0424fe0..4580e70 100644 --- a/bits/81_inflate.js +++ b/bits/81_inflate.js @@ -1,64 +1,5 @@ /* 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<*/ = []; - var i = 0; - for(;i<32; i++) dlens.push(5); - build_tree(dlens, fix_dmap, 32); - - var clens/*:Array*/ = []; - 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); @@ -177,8 +118,8 @@ function inflate(data, usz/*:number*/) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -209,7 +150,7 @@ function inflate(data, usz/*:number*/) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } diff --git a/bits/82_zparse.js b/bits/82_zparse.js index e56c846..7fbd34c 100644 --- a/bits/82_zparse.js +++ b/bits/82_zparse.js @@ -82,7 +82,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } diff --git a/bits/83_zwrite.js b/bits/83_zwrite.js index 6797bee..82ad702 100644 --- a/bits/83_zwrite.js +++ b/bits/83_zwrite.js @@ -46,7 +46,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); diff --git a/bits/84_mht.js b/bits/84_mht.js index 8edb6db..96ca019 100644 --- a/bits/84_mht.js +++ b/bits/84_mht.js @@ -203,4 +203,4 @@ function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -} \ No newline at end of file +} diff --git a/cfb.flow.js b/cfb.flow.js index 3cc8e23..0143a34 100644 --- a/cfb.flow.js +++ b/cfb.flow.js @@ -295,7 +295,7 @@ CRC32.str = crc32_str; /* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/; -exports.version = '1.2.0'; +exports.version = '1.2.1'; /* [MS-CFB] 2.6.4 */ function namecmp(l/*:string*/, r/*:string*/)/*:number*/ { var L = l.split("/"), R = r.split("/"); @@ -707,7 +707,11 @@ function read_file(filename/*:string*/, options/*:CFBReadOpts*/) { } function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) { - switch(options && options.type || "base64") { + var type = options && options.type; + if(!type) { + if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; + } + switch(type || "base64") { case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options); case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options); case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options); @@ -1105,6 +1109,38 @@ function read_bits_n(buf, bl, n) { return v & f; } +/* helpers for unaligned bit writes */ +function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz/*:number*/) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -1118,7 +1154,7 @@ function realloc(b, sz/*:number*/) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -1130,30 +1166,7 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -}var _deflate = (function() { -var _deflateRaw = (function() { - return function deflateRaw(data, out) { - var boff = 0; - while(boff < data.length) { - var L = Math.min(0xFFFF, data.length - boff); - var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ - out.write_shift(1, +h); - out.write_shift(2, L); - out.write_shift(2, (~L) & 0xFFFF); - while(L-- > 0) out[out.l++] = data[boff++]; - } - return out.l; - }; -})(); - -return function(data) { - var buf = new_buf(50+Math.floor(data.length*1.1)); - var off = _deflateRaw(data, buf); - return buf.slice(0, off); -}; -})(); -/* modified inflate function also moves original read head */ +} /* build tree (used for literals and lengths) */ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { @@ -1193,6 +1206,7 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { return maxlen; } +/* Fixed Huffman */ 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) { @@ -1212,8 +1226,124 @@ if(!use_typed_arrays) { for(; i<=279; i++) clens.push(7); for(; i<=287; i++) clens.push(8); build_tree(clens, fix_lmap, 288); +})();var _deflateRaw = (function() { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { + var boff = 0; + while(boff < data.length) { + var L = Math.min(0xFFFF, data.length - boff); + var h = boff + L == data.length; + out.write_shift(1, +h); + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + } + return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); + }; })(); +function _deflate(data) { + var buf = new_buf(50+Math.floor(data.length*1.1)); + var off = _deflateRaw(data, buf); + return buf.slice(0, off); +} +/* modified inflate function also moves original read head */ + 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); @@ -1332,8 +1462,8 @@ function inflate(data, usz/*:number*/) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -1364,7 +1494,7 @@ function inflate(data, usz/*:number*/) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } @@ -1463,7 +1593,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } @@ -1530,7 +1660,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); @@ -1789,7 +1922,8 @@ function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -}function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { +} +function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { var o/*:CFBContainer*/ = ({}/*:any*/); init_cfb(o, opts); return o; diff --git a/cfb.js b/cfb.js index c4267b2..fb58011 100644 --- a/cfb.js +++ b/cfb.js @@ -277,7 +277,7 @@ CRC32.str = crc32_str; /* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '1.2.0'; +exports.version = '1.2.1'; /* [MS-CFB] 2.6.4 */ function namecmp(l, r) { var L = l.split("/"), R = r.split("/"); @@ -689,7 +689,11 @@ function read_file(filename, options) { } function read(blob, options) { - switch(options && options.type || "base64") { + var type = options && options.type; + if(!type) { + if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; + } + switch(type || "base64") { case "file": return read_file(blob, options); case "base64": return parse(s2a(Base64.decode(blob)), options); case "binary": return parse(s2a(blob), options); @@ -1081,6 +1085,38 @@ function read_bits_n(buf, bl, n) { return v & f; } +/* helpers for unaligned bit writes */ +function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -1094,7 +1130,7 @@ function realloc(b, sz) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -1106,30 +1142,7 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -}var _deflate = (function() { -var _deflateRaw = (function() { - return function deflateRaw(data, out) { - var boff = 0; - while(boff < data.length) { - var L = Math.min(0xFFFF, data.length - boff); - var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ - out.write_shift(1, +h); - out.write_shift(2, L); - out.write_shift(2, (~L) & 0xFFFF); - while(L-- > 0) out[out.l++] = data[boff++]; - } - return out.l; - }; -})(); - -return function(data) { - var buf = new_buf(50+Math.floor(data.length*1.1)); - var off = _deflateRaw(data, buf); - return buf.slice(0, off); -}; -})(); -/* modified inflate function also moves original read head */ +} /* build tree (used for literals and lengths) */ function build_tree(clens, cmap, MAX) { @@ -1169,6 +1182,7 @@ function build_tree(clens, cmap, MAX) { return maxlen; } +/* Fixed Huffman */ 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) { @@ -1188,8 +1202,124 @@ if(!use_typed_arrays) { for(; i<=279; i++) clens.push(7); for(; i<=287; i++) clens.push(8); build_tree(clens, fix_lmap, 288); +})();var _deflateRaw = (function() { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { + var boff = 0; + while(boff < data.length) { + var L = Math.min(0xFFFF, data.length - boff); + var h = boff + L == data.length; + out.write_shift(1, +h); + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + } + return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); + }; })(); +function _deflate(data) { + var buf = new_buf(50+Math.floor(data.length*1.1)); + var off = _deflateRaw(data, buf); + return buf.slice(0, off); +} +/* modified inflate function also moves original read head */ + 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); @@ -1308,8 +1438,8 @@ function inflate(data, usz) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -1340,7 +1470,7 @@ function inflate(data, usz) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } @@ -1439,7 +1569,7 @@ function parse_local_file(blob, csz, usz, o, EF) { var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } @@ -1506,7 +1636,10 @@ function write_zip(cfb, options) { start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); @@ -1765,7 +1898,8 @@ function write_mad(cfb, options) { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -}function cfb_new(opts) { +} +function cfb_new(opts) { var o = ({}); init_cfb(o, opts); return o; diff --git a/dist/cfb.js b/dist/cfb.js index 7882e20..fb58011 100644 --- a/dist/cfb.js +++ b/dist/cfb.js @@ -57,7 +57,7 @@ if(typeof Buffer !== 'undefined') { if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; } Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer); // $FlowIgnore - if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); }; + if(!Buffer.alloc) Buffer.alloc = function(n) { var b = new Buffer(n); b.fill(0); return b; }; // $FlowIgnore if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); }; } @@ -277,7 +277,7 @@ CRC32.str = crc32_str; /* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '1.2.0'; +exports.version = '1.2.1'; /* [MS-CFB] 2.6.4 */ function namecmp(l, r) { var L = l.split("/"), R = r.split("/"); @@ -689,7 +689,11 @@ function read_file(filename, options) { } function read(blob, options) { - switch(options && options.type || "base64") { + var type = options && options.type; + if(!type) { + if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; + } + switch(type || "base64") { case "file": return read_file(blob, options); case "base64": return parse(s2a(Base64.decode(blob)), options); case "binary": return parse(s2a(blob), options); @@ -738,22 +742,28 @@ function rebuild_cfb(cfb, f) { if(!gc && !f) return; var now = new Date(1987, 1, 19), j = 0; + // Track which names exist + var fullPaths = Object.create ? Object.create(null) : {}; var data = []; for(i = 0; i < cfb.FullPaths.length; ++i) { + fullPaths[cfb.FullPaths[i]] = true; if(cfb.FileIndex[i].type === 0) continue; data.push([cfb.FullPaths[i], cfb.FileIndex[i]]); } for(i = 0; i < data.length; ++i) { var dad = dirname(data[i][0]); - s = false; - for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true; - if(!s) data.push([dad, ({ - name: filename(dad).replace("/",""), - type: 1, - clsid: HEADER_CLSID, - ct: now, mt: now, - content: null - })]); + s = fullPaths[dad]; + if(!s) { + data.push([dad, ({ + name: filename(dad).replace("/",""), + type: 1, + clsid: HEADER_CLSID, + ct: now, mt: now, + content: null + })]); + // Add name to set + fullPaths[dad] = true; + } } data.sort(function(x,y) { return namecmp(x[0], y[0]); }); @@ -908,18 +918,35 @@ flen = file.content.length; file = cfb.FileIndex[i]; if(file.size >= 0x1000) { o.l = (file.start+1) << 9; - for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); - for(; j & 0x1FF; ++j) o.write_shift(1, 0); + if (has_buf && Buffer.isBuffer(file.content)) { + file.content.copy(o, o.l, 0, file.size); + // o is a 0-filled Buffer so just set next offset + o.l += (file.size + 511) & -512; + } else { + for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); + for(; j & 0x1FF; ++j) o.write_shift(1, 0); + } } } for(i = 1; i < cfb.FileIndex.length; ++i) { file = cfb.FileIndex[i]; if(file.size > 0 && file.size < 0x1000) { - for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); - for(; j & 0x3F; ++j) o.write_shift(1, 0); + if (has_buf && Buffer.isBuffer(file.content)) { + file.content.copy(o, o.l, 0, file.size); + // o is a 0-filled Buffer so just set next offset + o.l += (file.size + 63) & -64; + } else { + for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); + for(; j & 0x3F; ++j) o.write_shift(1, 0); + } } } - while(o.l < o.length) o.write_shift(1, 0); + if (has_buf) { + o.l = o.length; + } else { + // When using Buffer, already 0-filled + while(o.l < o.length) o.write_shift(1, 0); + } return o; } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ @@ -1058,6 +1085,38 @@ function read_bits_n(buf, bl, n) { return v & f; } +/* helpers for unaligned bit writes */ +function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -1071,7 +1130,7 @@ function realloc(b, sz) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -1083,30 +1142,7 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -}var _deflate = (function() { -var _deflateRaw = (function() { - return function deflateRaw(data, out) { - var boff = 0; - while(boff < data.length) { - var L = Math.min(0xFFFF, data.length - boff); - var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ - out.write_shift(1, +h); - out.write_shift(2, L); - out.write_shift(2, (~L) & 0xFFFF); - while(L-- > 0) out[out.l++] = data[boff++]; - } - return out.l; - }; -})(); - -return function(data) { - var buf = new_buf(50+Math.floor(data.length*1.1)); - var off = _deflateRaw(data, buf); - return buf.slice(0, off); -}; -})(); -/* modified inflate function also moves original read head */ +} /* build tree (used for literals and lengths) */ function build_tree(clens, cmap, MAX) { @@ -1146,6 +1182,7 @@ function build_tree(clens, cmap, MAX) { return maxlen; } +/* Fixed Huffman */ 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) { @@ -1165,8 +1202,124 @@ if(!use_typed_arrays) { for(; i<=279; i++) clens.push(7); for(; i<=287; i++) clens.push(8); build_tree(clens, fix_lmap, 288); +})();var _deflateRaw = (function() { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { + var boff = 0; + while(boff < data.length) { + var L = Math.min(0xFFFF, data.length - boff); + var h = boff + L == data.length; + out.write_shift(1, +h); + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + } + return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); + }; })(); +function _deflate(data) { + var buf = new_buf(50+Math.floor(data.length*1.1)); + var off = _deflateRaw(data, buf); + return buf.slice(0, off); +} +/* modified inflate function also moves original read head */ + 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); @@ -1285,8 +1438,8 @@ function inflate(data, usz) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -1317,7 +1470,7 @@ function inflate(data, usz) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } @@ -1416,7 +1569,7 @@ function parse_local_file(blob, csz, usz, o, EF) { var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } @@ -1483,7 +1636,10 @@ function write_zip(cfb, options) { start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); @@ -1742,7 +1898,8 @@ function write_mad(cfb, options) { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -}function cfb_new(opts) { +} +function cfb_new(opts) { var o = ({}); init_cfb(o, opts); return o; diff --git a/dist/cfb.min.js b/dist/cfb.min.js index 1c2e21f..bdc7632 100644 --- a/dist/cfb.min.js +++ b/dist/cfb.min.js @@ -1,3 +1,3 @@ /* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var Base64=function e(){var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){var t="";var i=0,n=0,a=0,f=0,s=0,h=0,l=0;for(var o=0;o>2;n=r.charCodeAt(o++);s=(i&3)<<4|n>>4;a=r.charCodeAt(o++);h=(n&15)<<2|a>>6;l=a&63;if(isNaN(n)){h=l=64}else if(isNaN(a)){l=64}t+=e.charAt(f)+e.charAt(s)+e.charAt(h)+e.charAt(l)}return t},decode:function r(t){var i="";var n=0,a=0,f=0,s=0,h=0,l=0,o=0;t=t.replace(/[^\w\+\/\=]/g,"");for(var u=0;u>4;i+=String.fromCharCode(n);l=e.indexOf(t.charAt(u++));a=(h&15)<<4|l>>2;if(l!==64){i+=String.fromCharCode(a)}o=e.indexOf(t.charAt(u++));f=(l&3)<<6|o;if(o!==64){i+=String.fromCharCode(f)}}return i}}}();var has_buf=typeof Buffer!=="undefined"&&typeof process!=="undefined"&&typeof process.versions!=="undefined"&&process.versions.node;var Buffer_from=function(){};if(typeof Buffer!=="undefined"){var nbfs=!Buffer.from;if(!nbfs)try{Buffer.from("foo","utf8")}catch(e){nbfs=true}Buffer_from=nbfs?function(e,r){return r?new Buffer(e,r):new Buffer(e)}:Buffer.from.bind(Buffer);if(!Buffer.alloc)Buffer.alloc=function(e){return new Buffer(e)};if(!Buffer.allocUnsafe)Buffer.allocUnsafe=function(e){return new Buffer(e)}}function new_raw_buf(e){return has_buf?Buffer.alloc(e):new Array(e)}function new_unsafe_buf(e){return has_buf?Buffer.allocUnsafe(e):new Array(e)}var s2a=function r(e){if(has_buf)return Buffer_from(e,"binary");return e.split("").map(function(e){return e.charCodeAt(0)&255})};var chr0=/\u0000/g,chr1=/[\u0001-\u0006]/g;var __toBuffer=function(e){var r=[];for(var t=0;t0&&Buffer.isBuffer(e[0][0])?Buffer.concat(e[0]):___toBuffer(e)};s2a=function(e){return Buffer_from(e,"binary")};bconcat=function(e){return Buffer.isBuffer(e[0])?Buffer.concat(e):__bconcat(e)}}var __readUInt8=function(e,r){return e[r]};var __readUInt16LE=function(e,r){return e[r+1]*(1<<8)+e[r]};var __readInt16LE=function(e,r){var t=e[r+1]*(1<<8)+e[r];return t<32768?t:(65535-t+1)*-1};var __readUInt32LE=function(e,r){return e[r+3]*(1<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};var __readInt32LE=function(e,r){return(e[r+3]<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};function ReadShift(e,r){var t,i,n=0;switch(e){case 1:t=__readUInt8(this,this.l);break;case 2:t=(r!=="i"?__readUInt16LE:__readInt16LE)(this,this.l);break;case 4:t=__readInt32LE(this,this.l);break;case 16:n=2;i=__hexlify(this,this.l,e);}this.l+=e;if(n===0)return t;return i}var __writeUInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>>8&255;e[t+2]=r>>>16&255;e[t+3]=r>>>24&255};var __writeInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>8&255;e[t+2]=r>>16&255;e[t+3]=r>>24&255};function WriteShift(e,r,t){var i=0,n=0;switch(t){case"hex":for(;n>8}while(this.l>>=8;this[this.l+1]=r&255;break;case 4:i=4;__writeUInt32LE(this,r,this.l);break;case-4:i=4;__writeInt32LE(this,r,this.l);break;}this.l+=i;return this}function CheckField(e,r){var t=__hexlify(this,this.l,e.length>>1);if(t!==e)throw new Error(r+"Expected "+e+" saw "+t);this.l+=e.length>>1}function prep_blob(e,r){e.l=r;e.read_shift=ReadShift;e.chk=CheckField;e.write_shift=WriteShift}function new_buf(e){var r=new_raw_buf(e);prep_blob(r,0);return r}var CRC32;(function(e){e(CRC32={})})(function(e){e.version="1.2.0";function r(){var e=0,r=new Array(256);for(var t=0;t!=256;++t){e=t;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;r[t]=e}return typeof Int32Array!=="undefined"?new Int32Array(r):r}var t=r();function i(e,r){var i=r^-1,n=e.length-1;for(var a=0;a>>8^t[(i^e.charCodeAt(a++))&255];i=i>>>8^t[(i^e.charCodeAt(a++))&255]}if(a===n)i=i>>>8^t[(i^e.charCodeAt(a))&255];return i^-1}function n(e,r){if(e.length>1e4)return a(e,r);var i=r^-1,n=e.length-3;for(var f=0;f>>8^t[(i^e[f++])&255];i=i>>>8^t[(i^e[f++])&255];i=i>>>8^t[(i^e[f++])&255];i=i>>>8^t[(i^e[f++])&255]}while(f>>8^t[(i^e[f++])&255];return i^-1}function a(e,r){var i=r^-1,n=e.length-7;for(var a=0;a>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255]}while(a>>8^t[(i^e[a++])&255];return i^-1}function f(e,r){var i=r^-1;for(var n=0,a=e.length,f,s;n>>8^t[(i^f)&255]}else if(f<2048){i=i>>>8^t[(i^(192|f>>6&31))&255];i=i>>>8^t[(i^(128|f&63))&255]}else if(f>=55296&&f<57344){f=(f&1023)+64;s=e.charCodeAt(n++)&1023;i=i>>>8^t[(i^(240|f>>8&7))&255];i=i>>>8^t[(i^(128|f>>2&63))&255];i=i>>>8^t[(i^(128|s>>6&15|(f&3)<<4))&255];i=i>>>8^t[(i^(128|s&63))&255]}else{i=i>>>8^t[(i^(224|f>>12&15))&255];i=i>>>8^t[(i^(128|f>>6&63))&255];i=i>>>8^t[(i^(128|f&63))&255]}}return i^-1}e.table=t;e.bstr=i;e.buf=n;e.str=f});var CFB=function t(){var e={};e.version="1.2.0";function r(e,r){var t=e.split("/"),i=r.split("/");for(var n=0,a=0,f=Math.min(t.length,i.length);n>>1;e.write_shift(2,t);var i=r.getFullYear()-1980;i=i<<4|r.getMonth()+1;i=i<<5|r.getDate();e.write_shift(2,i)}function a(e){var r=e.read_shift(2)&65535;var t=e.read_shift(2)&65535;var i=new Date;var n=t&31;t>>>=5;var a=t&15;t>>>=4;i.setMilliseconds(0);i.setFullYear(t+1980);i.setMonth(a-1);i.setDate(n);var f=r&31;r>>>=5;var s=r&63;r>>>=6;i.setHours(r);i.setMinutes(s);i.setSeconds(f<<1);return i}function f(e){prep_blob(e,0);var r={};var t=0;while(e.l<=e.length-4){var i=e.read_shift(2);var n=e.read_shift(2),a=e.l+n;var f={};switch(i){case 21589:{t=e.read_shift(1);if(t&1)f.mtime=e.read_shift(4);if(n>5){if(t&2)f.atime=e.read_shift(4);if(t&4)f.ctime=e.read_shift(4)}if(f.mtime)f.mt=new Date(f.mtime*1e3)}break;}e.l=a;r[i]=f}return r}var s;function h(){return s||(s=require("fs"))}function l(e,r){if(e[0]==80&&e[1]==75)return we(e,r);if((e[0]|32)==109&&(e[1]|32)==105)return Ie(e,r);if(e.length<512)throw new Error("CFB file size "+e.length+" < 512");var t=3;var i=512;var n=0;var a=0;var f=0;var s=0;var h=0;var l=[];var _=e.slice(0,512);prep_blob(_,0);var w=o(_);t=w[0];switch(t){case 3:i=512;break;case 4:i=4096;break;case 0:if(w[1]==0)return we(e,r);default:throw new Error("Major Version: Expected 3 or 4 saw "+t);}if(i!==512){_=e.slice(0,i);prep_blob(_,28)}var b=e.slice(0,i);u(_,t);var F=_.read_shift(4,"i");if(t===3&&F!==0)throw new Error("# Directory Sectors: Expected 0 saw "+F);_.l+=4;f=_.read_shift(4,"i");_.l+=4;_.chk("00100000","Mini Stream Cutoff Size: ");s=_.read_shift(4,"i");n=_.read_shift(4,"i");h=_.read_shift(4,"i");a=_.read_shift(4,"i");for(var y=-1,m=0;m<109;++m){y=_.read_shift(4,"i");if(y<0)break;l[m]=y}var x=c(e,i);d(h,a,x,i,l);var C=p(x,f,l,i);C[f].name="!Directory";if(n>0&&s!==B)C[s].name="!MiniFAT";C[l[0]].name="!FAT";C.fat_addrs=l;C.ssz=i;var I={},A=[],E=[],S=[];g(f,C,x,A,n,I,E,s);v(E,S,A);A.shift();var k={FileIndex:E,FullPaths:S};if(r&&r.raw)k.raw={header:b,sectors:x};return k}function o(e){if(e[e.l]==80&&e[e.l+1]==75)return[0,0];e.chk(S,"Header Signature: ");e.l+=16;var r=e.read_shift(2,"u");return[e.read_shift(2,"u"),r]}function u(e,r){var t=9;e.l+=2;switch(t=e.read_shift(2)){case 9:if(r!=3)throw new Error("Sector Shift: Expected 9 saw "+t);break;case 12:if(r!=4)throw new Error("Sector Shift: Expected 12 saw "+t);break;default:throw new Error("Sector Shift: Expected 9 or 12 saw "+t);}e.chk("0600","Mini Sector Shift: ");e.chk("000000000000","Reserved: ")}function c(e,r){var t=Math.ceil(e.length/r)-1;var i=[];for(var n=1;n0&&f>=0){a.push(r.slice(f*E,f*E+E));n-=E;f=__readInt32LE(t,f*4)}if(a.length===0)return new_buf(0);return bconcat(a).slice(0,e.size)}function d(e,r,t,i,n){var a=B;if(e===B){if(r!==0)throw new Error("DIFAT chain shorter than expected")}else if(e!==-1){var f=t[e],s=(i>>>2)-1;if(!f)return;for(var h=0;h=0;){n[h]=true;a[a.length]=h;f.push(e[h]);var o=t[Math.floor(h*4/i)];l=h*4&s;if(i<4+l)throw new Error("FAT boundary crossed: "+h+" 4 "+i);if(!e[o])break;h=__readInt32LE(e[o],l)}return{nodes:a,data:__toBuffer([f])}}function p(e,r,t,i){var n=e.length,a=[];var f=[],s=[],h=[];var l=i-1,o=0,u=0,c=0,v=0;for(o=0;o=n)c-=n;if(f[c])continue;h=[];var _=[];for(u=c;u>=0;){_[u]=true;f[u]=true;s[s.length]=u;h.push(e[u]);var d=t[Math.floor(u*4/i)];v=u*4&l;if(i<4+v)throw new Error("FAT boundary crossed: "+u+" 4 "+i);if(!e[d])break;u=__readInt32LE(e[d],v);if(_[u])break}a[c]={nodes:s,data:__toBuffer([h])}}return a}function g(e,r,t,i,n,a,f,s){var h=0,l=i.length?2:0;var o=r[e].data;var u=0,c=0,v;for(;u0&&h!==B)r[h].name="!StreamData"}else if(p.size>=4096){p.storage="fat";if(r[p.start]===undefined)r[p.start]=w(t,p.start,r.fat_addrs,r.ssz);r[p.start].name=p.name;p.content=r[p.start].data.slice(0,p.size)}else{p.storage="minifat";if(p.size<0)p.size=0;else if(h!==B&&p.start!==B&&r[h]){p.content=_(p,r[h].data,(r[s]||{}).data)}}if(p.content)prep_blob(p.content,0);a[v]=p;f.push(p)}}function b(e,r){return new Date((__readUInt32LE(e,r+4)/1e7*Math.pow(2,32)+__readUInt32LE(e,r)/1e7-11644473600)*1e3)}function F(e,r){h();return l(s.readFileSync(e),r)}function y(e,r){switch(r&&r.type||"base64"){case"file":return F(e,r);case"base64":return l(s2a(Base64.decode(e)),r);case"binary":return l(s2a(e),r);}return l(e,r)}function m(e,r){var t=r||{},i=t.root||"Root Entry";if(!e.FullPaths)e.FullPaths=[];if(!e.FileIndex)e.FileIndex=[];if(e.FullPaths.length!==e.FileIndex.length)throw new Error("inconsistent CFB structure");if(e.FullPaths.length===0){e.FullPaths[0]=i+"/";e.FileIndex[0]={name:i,type:5}}if(t.CLSID)e.FileIndex[0].clsid=t.CLSID;x(e)}function x(e){var r="Sh33tJ5";if(CFB.find(e,"/"+r))return;var t=new_buf(4);t[0]=55;t[1]=t[3]=50;t[2]=54;e.FileIndex.push({name:r,type:2,content:t,size:4,L:69,R:69,C:69});e.FullPaths.push(e.FullPaths[0]+r);C(e)}function C(e,n){m(e);var a=false,f=false;for(var s=e.FullPaths.length-1;s>=0;--s){var h=e.FileIndex[s];switch(h.type){case 0:if(f)a=true;else{e.FileIndex.pop();e.FullPaths.pop()}break;case 1:;case 2:;case 5:f=true;if(isNaN(h.R*h.L*h.C))a=true;if(h.R>-1&&h.L>-1&&h.R==h.L)a=true;break;default:a=true;break;}}if(!a&&!n)return;var l=new Date(1987,1,19),o=0;var u=[];for(s=0;s1?1:-1;v.size=0;v.type=5}else if(_.slice(-1)=="/"){for(o=s+1;o=u.length?-1:o;for(o=s+1;o=u.length?-1:o;v.type=1}else{if(t(e.FullPaths[s+1]||"")==t(_))v.R=s+1;v.type=2}}}function I(e,r){var t=r||{};if(t.fileType=="mad")return Ae(e,t);C(e);switch(t.fileType){case"zip":return ge(e,t);}var i=function(e){var r=0,t=0;for(var i=0;i0){if(a<4096)r+=a+63>>6;else t+=a+511>>9}}var f=e.FullPaths.length+3>>2;var s=r+7>>3;var h=r+127>>7;var l=s+t+f+h;var o=l+127>>7;var u=o<=109?0:Math.ceil((o-109)/127);while(l+o+u+127>>7>o)u=++o<=109?0:Math.ceil((o-109)/127);var c=[1,u,o,h,f,t,r,0];e.FileIndex[0].size=r<<6;c[7]=(e.FileIndex[0].start=c[0]+c[1]+c[2]+c[3]+c[4]+c[5])+(c[6]+7>>3);return c}(e);var n=new_buf(i[7]<<9);var a=0,f=0;{for(a=0;a<8;++a)n.write_shift(1,k[a]);for(a=0;a<8;++a)n.write_shift(2,0);n.write_shift(2,62);n.write_shift(2,3);n.write_shift(2,65534);n.write_shift(2,9);n.write_shift(2,6);for(a=0;a<3;++a)n.write_shift(2,0);n.write_shift(4,0);n.write_shift(4,i[2]);n.write_shift(4,i[0]+i[1]+i[2]+i[3]-1);n.write_shift(4,0);n.write_shift(4,1<<12);n.write_shift(4,i[3]?i[0]+i[1]+i[2]-1:B);n.write_shift(4,i[3]);n.write_shift(-4,i[1]?i[0]-1:B);n.write_shift(4,i[1]);for(a=0;a<109;++a)n.write_shift(-4,a>9)}s(i[6]+7>>3);while(n.l&511)n.write_shift(-4,L.ENDOFCHAIN);f=a=0;for(h=0;h=4096)continue;o.start=f;s(l+63>>6)}while(n.l&511)n.write_shift(-4,L.ENDOFCHAIN);for(a=0;a=4096){n.l=o.start+1<<9;for(h=0;h0&&o.size<4096){for(h=0;h>16|r>>8|r)&255}var J=typeof Uint8Array!=="undefined";var q=J?new Uint8Array(1<<8):[];for(var G=0;G<1<<8;++G)q[G]=$(G);function V(e,r){var t=q[e&255];if(r<=8)return t>>>8-r;t=t<<8|q[e>>8&255];if(r<=16)return t>>>16-r;t=t<<8|q[e>>16&255];return t>>>24-r}function X(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=6?0:e[i+1]<<8))>>>t&3}function W(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=5?0:e[i+1]<<8))>>>t&7}function Y(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=4?0:e[i+1]<<8))>>>t&15}function Z(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=3?0:e[i+1]<<8))>>>t&31}function K(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=1?0:e[i+1]<<8))>>>t&127}function Q(e,r,t){var i=r&7,n=r>>>3,a=(1<>>i;if(t<8-i)return f&a;f|=e[n+1]<<8-i;if(t<16-i)return f&a;f|=e[n+2]<<16-i;if(t<24-i)return f&a;f|=e[n+3]<<24-i;return f&a}function ee(e,r){var t=e.length,i=2*t>r?2*t:r+5,n=0;if(t>=r)return e;if(has_buf){var a=new_unsafe_buf(i);if(e.copy)e.copy(a);else for(;n0)t[t.l++]=r[i++]}return t.l}}();return function(r){var t=new_buf(50+Math.floor(r.length*1.1));var i=e(r,t);return t.slice(0,i)}}();function ie(e,r,t){var i=1,n=0,a=0,f=0,s=0,h=e.length;var l=J?new Uint16Array(32):re(32);for(a=0;a<32;++a)l[a]=0;for(a=h;a>i-u;for(f=(1<=0;--f)r[s|f<>8-_;for(var d=(1<<7-_)-1;d>=0;--d)le[v|d<<_]=_&7|c<<3}}var w=[];h=1;for(;w.length>>=3){case 16:a=3+X(e,r);r+=2;v=w[w.length-1];while(a-- >0)w.push(v);break;case 17:a=3+W(e,r);r+=3;while(a-- >0)w.push(0);break;case 18:a=11+K(e,r);r+=7;while(a-- >0)w.push(0);break;default:w.push(v);if(h>>0;var s=0,h=0;while((i&1)==0){i=W(e,t);t+=3;if(i>>>1==0){if(t&7)t+=8-(t&7);var l=e[t>>>3]|e[(t>>>3)+1]<<8;t+=32;if(!r&&f>>3,(t>>>3)+l);a+=l;t+=8*l}else while(l-- >0){n[a++]=e[t>>>3];t+=8}continue}else if(i>>>1==1){s=9;h=5}else{t=ce(e,t);s=oe;h=ue}if(!r&&f>>1==1?ne[o]:se[o];t+=u&15;u>>>=4;if((u>>>8&255)===0)n[a++]=u;else if(u==256)break;else{u-=257;var c=u<8?0:u-4>>2;if(c>5)c=0;var v=a+j[u];if(c>0){v+=Q(e,t,c);t+=c}o=Q(e,t,h);u=i>>>1==1?ae[o]:he[o];t+=u&15;u>>>=4;var _=u<4?0:u-2>>1;var d=H[u];if(_>0){d+=Q(e,t,_);t+=_}if(!r&&f>>3]}function _e(e,r){var t=e.slice(e.l||0);var i=ve(t,r);e.l+=i[1];return i[0]}function de(e,r){if(e){if(typeof console!=="undefined")console.error(r)}else throw new Error(r)}function we(e,r){var t=e;prep_blob(t,0);var i=[],n=[];var a={FileIndex:i,FullPaths:n};m(a,{root:r.root});var s=t.length-4;while((t[s]!=80||t[s+1]!=75||t[s+2]!=5||t[s+3]!=6)&&s>=0)--s;t.l=s+4;t.l+=4;var h=t.read_shift(2);t.l+=6;var l=t.read_shift(4);t.l=l;for(s=0;s0){t=t.slice(0,t.length-1);t=t.slice(0,t.lastIndexOf("/")+1);if(a.slice(0,t.length)==t)break}}var f=(i[1]||"").match(/boundary="(.*?)"/);if(!f)throw new Error("MAD cannot find boundary");var s="--"+(f[1]||"");var h=[],l=[];var o={FileIndex:h,FullPaths:l};m(o);var u,c=0;for(n=0;n=32&&v<128)++u;var d=u>=c*4/5;n.push(i);n.push("Content-Location: "+(t.root||"file:///C:/SheetJS/")+f);n.push("Content-Transfer-Encoding: "+(d?"quoted-printable":"base64"));n.push("Content-Type: "+Fe(s,f));n.push("");n.push(d?me(o):ye(o))}n.push(i+"--\r\n");return n.join("\r\n")}function Ee(e){var r={};m(r,e);return r}function Be(e,r,t,n){var a=n&&n.unsafe;if(!a)m(e);var f=!a&&CFB.find(e,r);if(!f){var s=e.FullPaths[0];if(r.slice(0,s.length)==s)s=r;else{if(s.slice(-1)!="/")s+="/";s=(s+r).replace("//","/")}f={name:i(r),type:2};e.FileIndex.push(f);e.FullPaths.push(s);if(!a)CFB.utils.cfb_gc(e)}f.content=t;f.size=t?t.length:0;if(n){if(n.CLSID)f.clsid=n.CLSID;if(n.mt)f.mt=n.mt;if(n.ct)f.ct=n.ct}return f}function Se(e,r){m(e);var t=CFB.find(e,r);if(t)for(var i=0;i>2;n=r.charCodeAt(o++);s=(i&3)<<4|n>>4;a=r.charCodeAt(o++);l=(n&15)<<2|a>>6;h=a&63;if(isNaN(n)){l=h=64}else if(isNaN(a)){h=64}t+=e.charAt(f)+e.charAt(s)+e.charAt(l)+e.charAt(h)}return t},decode:function r(t){var i="";var n=0,a=0,f=0,s=0,l=0,h=0,o=0;t=t.replace(/[^\w\+\/\=]/g,"");for(var u=0;u>4;i+=String.fromCharCode(n);h=e.indexOf(t.charAt(u++));a=(l&15)<<4|h>>2;if(h!==64){i+=String.fromCharCode(a)}o=e.indexOf(t.charAt(u++));f=(h&3)<<6|o;if(o!==64){i+=String.fromCharCode(f)}}return i}}}();var has_buf=typeof Buffer!=="undefined"&&typeof process!=="undefined"&&typeof process.versions!=="undefined"&&process.versions.node;var Buffer_from=function(){};if(typeof Buffer!=="undefined"){var nbfs=!Buffer.from;if(!nbfs)try{Buffer.from("foo","utf8")}catch(e){nbfs=true}Buffer_from=nbfs?function(e,r){return r?new Buffer(e,r):new Buffer(e)}:Buffer.from.bind(Buffer);if(!Buffer.alloc)Buffer.alloc=function(e){var r=new Buffer(e);r.fill(0);return r};if(!Buffer.allocUnsafe)Buffer.allocUnsafe=function(e){return new Buffer(e)}}function new_raw_buf(e){return has_buf?Buffer.alloc(e):new Array(e)}function new_unsafe_buf(e){return has_buf?Buffer.allocUnsafe(e):new Array(e)}var s2a=function r(e){if(has_buf)return Buffer_from(e,"binary");return e.split("").map(function(e){return e.charCodeAt(0)&255})};var chr0=/\u0000/g,chr1=/[\u0001-\u0006]/g;var __toBuffer=function(e){var r=[];for(var t=0;t0&&Buffer.isBuffer(e[0][0])?Buffer.concat(e[0]):___toBuffer(e)};s2a=function(e){return Buffer_from(e,"binary")};bconcat=function(e){return Buffer.isBuffer(e[0])?Buffer.concat(e):__bconcat(e)}}var __readUInt8=function(e,r){return e[r]};var __readUInt16LE=function(e,r){return e[r+1]*(1<<8)+e[r]};var __readInt16LE=function(e,r){var t=e[r+1]*(1<<8)+e[r];return t<32768?t:(65535-t+1)*-1};var __readUInt32LE=function(e,r){return e[r+3]*(1<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};var __readInt32LE=function(e,r){return(e[r+3]<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};function ReadShift(e,r){var t,i,n=0;switch(e){case 1:t=__readUInt8(this,this.l);break;case 2:t=(r!=="i"?__readUInt16LE:__readInt16LE)(this,this.l);break;case 4:t=__readInt32LE(this,this.l);break;case 16:n=2;i=__hexlify(this,this.l,e);}this.l+=e;if(n===0)return t;return i}var __writeUInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>>8&255;e[t+2]=r>>>16&255;e[t+3]=r>>>24&255};var __writeInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>8&255;e[t+2]=r>>16&255;e[t+3]=r>>24&255};function WriteShift(e,r,t){var i=0,n=0;switch(t){case"hex":for(;n>8}while(this.l>>=8;this[this.l+1]=r&255;break;case 4:i=4;__writeUInt32LE(this,r,this.l);break;case-4:i=4;__writeInt32LE(this,r,this.l);break;}this.l+=i;return this}function CheckField(e,r){var t=__hexlify(this,this.l,e.length>>1);if(t!==e)throw new Error(r+"Expected "+e+" saw "+t);this.l+=e.length>>1}function prep_blob(e,r){e.l=r;e.read_shift=ReadShift;e.chk=CheckField;e.write_shift=WriteShift}function new_buf(e){var r=new_raw_buf(e);prep_blob(r,0);return r}var CRC32;(function(e){e(CRC32={})})(function(e){e.version="1.2.0";function r(){var e=0,r=new Array(256);for(var t=0;t!=256;++t){e=t;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;e=e&1?-306674912^e>>>1:e>>>1;r[t]=e}return typeof Int32Array!=="undefined"?new Int32Array(r):r}var t=r();function i(e,r){var i=r^-1,n=e.length-1;for(var a=0;a>>8^t[(i^e.charCodeAt(a++))&255];i=i>>>8^t[(i^e.charCodeAt(a++))&255]}if(a===n)i=i>>>8^t[(i^e.charCodeAt(a))&255];return i^-1}function n(e,r){if(e.length>1e4)return a(e,r);var i=r^-1,n=e.length-3;for(var f=0;f>>8^t[(i^e[f++])&255];i=i>>>8^t[(i^e[f++])&255];i=i>>>8^t[(i^e[f++])&255];i=i>>>8^t[(i^e[f++])&255]}while(f>>8^t[(i^e[f++])&255];return i^-1}function a(e,r){var i=r^-1,n=e.length-7;for(var a=0;a>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255];i=i>>>8^t[(i^e[a++])&255]}while(a>>8^t[(i^e[a++])&255];return i^-1}function f(e,r){var i=r^-1;for(var n=0,a=e.length,f,s;n>>8^t[(i^f)&255]}else if(f<2048){i=i>>>8^t[(i^(192|f>>6&31))&255];i=i>>>8^t[(i^(128|f&63))&255]}else if(f>=55296&&f<57344){f=(f&1023)+64;s=e.charCodeAt(n++)&1023;i=i>>>8^t[(i^(240|f>>8&7))&255];i=i>>>8^t[(i^(128|f>>2&63))&255];i=i>>>8^t[(i^(128|s>>6&15|(f&3)<<4))&255];i=i>>>8^t[(i^(128|s&63))&255]}else{i=i>>>8^t[(i^(224|f>>12&15))&255];i=i>>>8^t[(i^(128|f>>6&63))&255];i=i>>>8^t[(i^(128|f&63))&255]}}return i^-1}e.table=t;e.bstr=i;e.buf=n;e.str=f});var CFB=function t(){var e={};e.version="1.2.1";function r(e,r){var t=e.split("/"),i=r.split("/");for(var n=0,a=0,f=Math.min(t.length,i.length);n>>1;e.write_shift(2,t);var i=r.getFullYear()-1980;i=i<<4|r.getMonth()+1;i=i<<5|r.getDate();e.write_shift(2,i)}function a(e){var r=e.read_shift(2)&65535;var t=e.read_shift(2)&65535;var i=new Date;var n=t&31;t>>>=5;var a=t&15;t>>>=4;i.setMilliseconds(0);i.setFullYear(t+1980);i.setMonth(a-1);i.setDate(n);var f=r&31;r>>>=5;var s=r&63;r>>>=6;i.setHours(r);i.setMinutes(s);i.setSeconds(f<<1);return i}function f(e){prep_blob(e,0);var r={};var t=0;while(e.l<=e.length-4){var i=e.read_shift(2);var n=e.read_shift(2),a=e.l+n;var f={};switch(i){case 21589:{t=e.read_shift(1);if(t&1)f.mtime=e.read_shift(4);if(n>5){if(t&2)f.atime=e.read_shift(4);if(t&4)f.ctime=e.read_shift(4)}if(f.mtime)f.mt=new Date(f.mtime*1e3)}break;}e.l=a;r[i]=f}return r}var s;function l(){return s||(s=require("fs"))}function h(e,r){if(e[0]==80&&e[1]==75)return ye(e,r);if((e[0]|32)==109&&(e[1]|32)==105)return ke(e,r);if(e.length<512)throw new Error("CFB file size "+e.length+" < 512");var t=3;var i=512;var n=0;var a=0;var f=0;var s=0;var l=0;var h=[];var _=e.slice(0,512);prep_blob(_,0);var w=o(_);t=w[0];switch(t){case 3:i=512;break;case 4:i=4096;break;case 0:if(w[1]==0)return ye(e,r);default:throw new Error("Major Version: Expected 3 or 4 saw "+t);}if(i!==512){_=e.slice(0,i);prep_blob(_,28)}var b=e.slice(0,i);u(_,t);var F=_.read_shift(4,"i");if(t===3&&F!==0)throw new Error("# Directory Sectors: Expected 0 saw "+F);_.l+=4;f=_.read_shift(4,"i");_.l+=4;_.chk("00100000","Mini Stream Cutoff Size: ");s=_.read_shift(4,"i");n=_.read_shift(4,"i");l=_.read_shift(4,"i");a=_.read_shift(4,"i");for(var y=-1,m=0;m<109;++m){y=_.read_shift(4,"i");if(y<0)break;h[m]=y}var x=c(e,i);d(l,a,x,i,h);var C=p(x,f,h,i);C[f].name="!Directory";if(n>0&&s!==B)C[s].name="!MiniFAT";C[h[0]].name="!FAT";C.fat_addrs=h;C.ssz=i;var I={},A=[],E=[],S=[];g(f,C,x,A,n,I,E,s);v(E,S,A);A.shift();var k={FileIndex:E,FullPaths:S};if(r&&r.raw)k.raw={header:b,sectors:x};return k}function o(e){if(e[e.l]==80&&e[e.l+1]==75)return[0,0];e.chk(S,"Header Signature: ");e.l+=16;var r=e.read_shift(2,"u");return[e.read_shift(2,"u"),r]}function u(e,r){var t=9;e.l+=2;switch(t=e.read_shift(2)){case 9:if(r!=3)throw new Error("Sector Shift: Expected 9 saw "+t);break;case 12:if(r!=4)throw new Error("Sector Shift: Expected 12 saw "+t);break;default:throw new Error("Sector Shift: Expected 9 or 12 saw "+t);}e.chk("0600","Mini Sector Shift: ");e.chk("000000000000","Reserved: ")}function c(e,r){var t=Math.ceil(e.length/r)-1;var i=[];for(var n=1;n0&&f>=0){a.push(r.slice(f*E,f*E+E));n-=E;f=__readInt32LE(t,f*4)}if(a.length===0)return new_buf(0);return bconcat(a).slice(0,e.size)}function d(e,r,t,i,n){var a=B;if(e===B){if(r!==0)throw new Error("DIFAT chain shorter than expected")}else if(e!==-1){var f=t[e],s=(i>>>2)-1;if(!f)return;for(var l=0;l=0;){n[l]=true;a[a.length]=l;f.push(e[l]);var o=t[Math.floor(l*4/i)];h=l*4&s;if(i<4+h)throw new Error("FAT boundary crossed: "+l+" 4 "+i);if(!e[o])break;l=__readInt32LE(e[o],h)}return{nodes:a,data:__toBuffer([f])}}function p(e,r,t,i){var n=e.length,a=[];var f=[],s=[],l=[];var h=i-1,o=0,u=0,c=0,v=0;for(o=0;o=n)c-=n;if(f[c])continue;l=[];var _=[];for(u=c;u>=0;){_[u]=true;f[u]=true;s[s.length]=u;l.push(e[u]);var d=t[Math.floor(u*4/i)];v=u*4&h;if(i<4+v)throw new Error("FAT boundary crossed: "+u+" 4 "+i);if(!e[d])break;u=__readInt32LE(e[d],v);if(_[u])break}a[c]={nodes:s,data:__toBuffer([l])}}return a}function g(e,r,t,i,n,a,f,s){var l=0,h=i.length?2:0;var o=r[e].data;var u=0,c=0,v;for(;u0&&l!==B)r[l].name="!StreamData"}else if(p.size>=4096){p.storage="fat";if(r[p.start]===undefined)r[p.start]=w(t,p.start,r.fat_addrs,r.ssz);r[p.start].name=p.name;p.content=r[p.start].data.slice(0,p.size)}else{p.storage="minifat";if(p.size<0)p.size=0;else if(l!==B&&p.start!==B&&r[l]){p.content=_(p,r[l].data,(r[s]||{}).data)}}if(p.content)prep_blob(p.content,0);a[v]=p;f.push(p)}}function b(e,r){return new Date((__readUInt32LE(e,r+4)/1e7*Math.pow(2,32)+__readUInt32LE(e,r)/1e7-11644473600)*1e3)}function F(e,r){l();return h(s.readFileSync(e),r)}function y(e,r){var t=r&&r.type;if(!t){if(has_buf&&Buffer.isBuffer(e))t="buffer"}switch(t||"base64"){case"file":return F(e,r);case"base64":return h(s2a(Base64.decode(e)),r);case"binary":return h(s2a(e),r);}return h(e,r)}function m(e,r){var t=r||{},i=t.root||"Root Entry";if(!e.FullPaths)e.FullPaths=[];if(!e.FileIndex)e.FileIndex=[];if(e.FullPaths.length!==e.FileIndex.length)throw new Error("inconsistent CFB structure");if(e.FullPaths.length===0){e.FullPaths[0]=i+"/";e.FileIndex[0]={name:i,type:5}}if(t.CLSID)e.FileIndex[0].clsid=t.CLSID;x(e)}function x(e){var r="Sh33tJ5";if(CFB.find(e,"/"+r))return;var t=new_buf(4);t[0]=55;t[1]=t[3]=50;t[2]=54;e.FileIndex.push({name:r,type:2,content:t,size:4,L:69,R:69,C:69});e.FullPaths.push(e.FullPaths[0]+r);C(e)}function C(e,n){m(e);var a=false,f=false;for(var s=e.FullPaths.length-1;s>=0;--s){var l=e.FileIndex[s];switch(l.type){case 0:if(f)a=true;else{e.FileIndex.pop();e.FullPaths.pop()}break;case 1:;case 2:;case 5:f=true;if(isNaN(l.R*l.L*l.C))a=true;if(l.R>-1&&l.L>-1&&l.R==l.L)a=true;break;default:a=true;break;}}if(!a&&!n)return;var h=new Date(1987,1,19),o=0;var u=Object.create?Object.create(null):{};var c=[];for(s=0;s1?1:-1;_.size=0;_.type=5}else if(d.slice(-1)=="/"){for(o=s+1;o=c.length?-1:o;for(o=s+1;o=c.length?-1:o;_.type=1}else{if(t(e.FullPaths[s+1]||"")==t(d))_.R=s+1;_.type=2}}}function I(e,r){var t=r||{};if(t.fileType=="mad")return Re(e,t);C(e);switch(t.fileType){case"zip":return xe(e,t);}var i=function(e){var r=0,t=0;for(var i=0;i0){if(a<4096)r+=a+63>>6;else t+=a+511>>9}}var f=e.FullPaths.length+3>>2;var s=r+7>>3;var l=r+127>>7;var h=s+t+f+l;var o=h+127>>7;var u=o<=109?0:Math.ceil((o-109)/127);while(h+o+u+127>>7>o)u=++o<=109?0:Math.ceil((o-109)/127);var c=[1,u,o,l,f,t,r,0];e.FileIndex[0].size=r<<6;c[7]=(e.FileIndex[0].start=c[0]+c[1]+c[2]+c[3]+c[4]+c[5])+(c[6]+7>>3);return c}(e);var n=new_buf(i[7]<<9);var a=0,f=0;{for(a=0;a<8;++a)n.write_shift(1,k[a]);for(a=0;a<8;++a)n.write_shift(2,0);n.write_shift(2,62);n.write_shift(2,3);n.write_shift(2,65534);n.write_shift(2,9);n.write_shift(2,6);for(a=0;a<3;++a)n.write_shift(2,0);n.write_shift(4,0);n.write_shift(4,i[2]);n.write_shift(4,i[0]+i[1]+i[2]+i[3]-1);n.write_shift(4,0);n.write_shift(4,1<<12);n.write_shift(4,i[3]?i[0]+i[1]+i[2]-1:B);n.write_shift(4,i[3]);n.write_shift(-4,i[1]?i[0]-1:B);n.write_shift(4,i[1]);for(a=0;a<109;++a)n.write_shift(-4,a>9)}s(i[6]+7>>3);while(n.l&511)n.write_shift(-4,U.ENDOFCHAIN);f=a=0;for(l=0;l=4096)continue;o.start=f;s(h+63>>6)}while(n.l&511)n.write_shift(-4,U.ENDOFCHAIN);for(a=0;a=4096){n.l=o.start+1<<9;if(has_buf&&Buffer.isBuffer(o.content)){o.content.copy(n,n.l,0,o.size);n.l+=o.size+511&-512}else{for(l=0;l0&&o.size<4096){if(has_buf&&Buffer.isBuffer(o.content)){o.content.copy(n,n.l,0,o.size);n.l+=o.size+63&-64}else{for(l=0;l>16|r>>8|r)&255}var J=typeof Uint8Array!=="undefined";var q=J?new Uint8Array(1<<8):[];for(var G=0;G<1<<8;++G)q[G]=$(G);function V(e,r){var t=q[e&255];if(r<=8)return t>>>8-r;t=t<<8|q[e>>8&255];if(r<=16)return t>>>16-r;t=t<<8|q[e>>16&255];return t>>>24-r}function X(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=6?0:e[i+1]<<8))>>>t&3}function W(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=5?0:e[i+1]<<8))>>>t&7}function Y(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=4?0:e[i+1]<<8))>>>t&15}function Z(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=3?0:e[i+1]<<8))>>>t&31}function K(e,r){var t=r&7,i=r>>>3;return(e[i]|(t<=1?0:e[i+1]<<8))>>>t&127}function Q(e,r,t){var i=r&7,n=r>>>3,a=(1<>>i;if(t<8-i)return f&a;f|=e[n+1]<<8-i;if(t<16-i)return f&a;f|=e[n+2]<<16-i;if(t<24-i)return f&a;f|=e[n+3]<<24-i;return f&a}function ee(e,r,t){var i=r&7,n=r>>>3;if(i<=5)e[n]|=(t&7)<>8-i}return r+3}function re(e,r,t){var i=r&7,n=r>>>3;t=(t&1)<>>3;t<<=i;e[n]|=t&255;t>>>=8;e[n+1]=t;return r+8}function ie(e,r,t){var i=r&7,n=r>>>3;t<<=i;e[n]|=t&255;t>>>=8;e[n+1]=t&255;e[n+2]=t>>>8;return r+16}function ne(e,r){var t=e.length,i=2*t>r?2*t:r+5,n=0;if(t>=r)return e;if(has_buf){var a=new_unsafe_buf(i);if(e.copy)e.copy(a);else for(;n>i-u;for(f=(1<=0;--f)r[s|f<0)r[r.l++]=e[t++]}return r.l}function a(r,t){var n=0;var a=0;var f=J?new Uint16Array(32768):[];while(a0)t[t.l++]=r[a++];n=t.l*8;continue}n=ee(t,n,+!!(a+s==r.length)+2);var l=0;while(s-- >0){var h=r[a];l=(l<<5^h)&32767;var o=-1,u=0;if(o=f[l]){o|=a&~32767;if(o>a)o-=32768;if(o2){h=i[u];if(h<=22)n=te(t,n,q[h+1]>>1)-1;else{te(t,n,3);n+=5;te(t,n,q[h-23]>>5);n+=3}var c=h<8?0:h-4>>2;if(c>0){ie(t,n,u-j[h]);n+=c}h=e[a-o];n=te(t,n,q[h]>>3);n-=3;var v=h<4?0:h-2>>1;if(v>0){ie(t,n,a-o-H[h]);n+=v}for(var _=0;_>8-_;for(var d=(1<<7-_)-1;d>=0;--d)_e[v|d<<_]=_&7|c<<3}}var w=[];l=1;for(;w.length>>=3){case 16:a=3+X(e,r);r+=2;v=w[w.length-1];while(a-- >0)w.push(v);break;case 17:a=3+W(e,r);r+=3;while(a-- >0)w.push(0);break;case 18:a=11+K(e,r);r+=7;while(a-- >0)w.push(0);break;default:w.push(v);if(l>>0;var s=0,l=0;while((i&1)==0){i=W(e,t);t+=3;if(i>>>1==0){if(t&7)t+=8-(t&7);var h=e[t>>>3]|e[(t>>>3)+1]<<8;t+=32;if(!r&&f>>3,(t>>>3)+h);a+=h;t+=8*h}else while(h-- >0){n[a++]=e[t>>>3];t+=8}continue}else if(i>>>1==1){s=9;l=5}else{t=pe(e,t);s=de;l=we}for(;;){if(!r&&f>>1==1?se[o]:ce[o];t+=u&15;u>>>=4;if((u>>>8&255)===0)n[a++]=u;else if(u==256)break;else{u-=257;var c=u<8?0:u-4>>2;if(c>5)c=0;var v=a+j[u];if(c>0){v+=Q(e,t,c);t+=c}o=Q(e,t,l);u=i>>>1==1?le[o]:ve[o];t+=u&15;u>>>=4;var _=u<4?0:u-2>>1;var d=H[u];if(_>0){d+=Q(e,t,_);t+=_}if(!r&&f>>3]}function be(e,r){var t=e.slice(e.l||0);var i=ge(t,r);e.l+=i[1];return i[0]}function Fe(e,r){if(e){if(typeof console!=="undefined")console.error(r)}else throw new Error(r)}function ye(e,r){var t=e;prep_blob(t,0);var i=[],n=[];var a={FileIndex:i,FullPaths:n};m(a,{root:r.root});var s=t.length-4;while((t[s]!=80||t[s+1]!=75||t[s+2]!=5||t[s+3]!=6)&&s>=0)--s;t.l=s+4;t.l+=4;var l=t.read_shift(2);t.l+=6;var h=t.read_shift(4);t.l=h;for(s=0;s0){t=t.slice(0,t.length-1);t=t.slice(0,t.lastIndexOf("/")+1);if(a.slice(0,t.length)==t)break}}var f=(i[1]||"").match(/boundary="(.*?)"/);if(!f)throw new Error("MAD cannot find boundary");var s="--"+(f[1]||"");var l=[],h=[];var o={FileIndex:l,FullPaths:h};m(o);var u,c=0;for(n=0;n=32&&v<128)++u;var d=u>=c*4/5;n.push(i);n.push("Content-Location: "+(t.root||"file:///C:/SheetJS/")+f);n.push("Content-Transfer-Encoding: "+(d?"quoted-printable":"base64"));n.push("Content-Type: "+Ie(s,f));n.push("");n.push(d?Ee(o):Ae(o))}n.push(i+"--\r\n");return n.join("\r\n")}function Ue(e){var r={};m(r,e);return r}function ze(e,r,t,n){var a=n&&n.unsafe;if(!a)m(e);var f=!a&&CFB.find(e,r);if(!f){var s=e.FullPaths[0];if(r.slice(0,s.length)==s)s=r;else{if(s.slice(-1)!="/")s+="/";s=(s+r).replace("//","/")}f={name:i(r),type:2};e.FileIndex.push(f);e.FullPaths.push(s);if(!a)CFB.utils.cfb_gc(e)}f.content=t;f.size=t?t.length:0;if(n){if(n.CLSID)f.clsid=n.CLSID;if(n.mt)f.mt=n.mt;if(n.ct)f.ct=n.ct}return f}function Le(e,r){m(e);var t=CFB.find(e,r);if(t)for(var i=0;i*/ = []; for(i = 0; i < cfb.FullPaths.length; ++i) { + fullPaths[cfb.FullPaths[i]] = true; if(cfb.FileIndex[i].type === 0) continue; data.push([cfb.FullPaths[i], cfb.FileIndex[i]]); } for(i = 0; i < data.length; ++i) { var dad = dirname(data[i][0]); - s = false; - for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true; - if(!s) data.push([dad, ({ - name: filename(dad).replace("/",""), - type: 1, - clsid: HEADER_CLSID, - ct: now, mt: now, - content: null - }/*:any*/)]); + s = fullPaths[dad]; + if(!s) { + data.push([dad, ({ + name: filename(dad).replace("/",""), + type: 1, + clsid: HEADER_CLSID, + ct: now, mt: now, + content: null + }/*:any*/)]); + // Add name to set + fullPaths[dad] = true; + } } data.sort(function(x,y) { return namecmp(x[0], y[0]); }); @@ -778,19 +788,36 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|strin /*:: if(!file.content) throw new Error("unreachable"); */ if(file.size >= 0x1000) { o.l = (file.start+1) << 9; - for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); - for(; j & 0x1FF; ++j) o.write_shift(1, 0); + if (has_buf && Buffer.isBuffer(file.content)) { + file.content.copy(o, o.l, 0, file.size); + // o is a 0-filled Buffer so just set next offset + o.l += (file.size + 511) & -512; + } else { + for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); + for(; j & 0x1FF; ++j) o.write_shift(1, 0); + } } } for(i = 1; i < cfb.FileIndex.length; ++i) { file = cfb.FileIndex[i]; /*:: if(!file.content) throw new Error("unreachable"); */ if(file.size > 0 && file.size < 0x1000) { - for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); - for(; j & 0x3F; ++j) o.write_shift(1, 0); + if (has_buf && Buffer.isBuffer(file.content)) { + file.content.copy(o, o.l, 0, file.size); + // o is a 0-filled Buffer so just set next offset + o.l += (file.size + 63) & -64; + } else { + for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]); + for(; j & 0x3F; ++j) o.write_shift(1, 0); + } } } - while(o.l < o.length) o.write_shift(1, 0); + if (has_buf) { + o.l = o.length; + } else { + // When using Buffer, already 0-filled + while(o.l < o.length) o.write_shift(1, 0); + } return o; } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ @@ -930,6 +957,38 @@ function read_bits_n(buf, bl, n) { return v & f; } +/* helpers for unaligned bit writes */ +function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz/*:number*/) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -943,7 +1002,7 @@ function realloc(b, sz/*:number*/) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -955,30 +1014,7 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -}var _deflate = (function() { -var _deflateRaw = (function() { - return function deflateRaw(data, out) { - var boff = 0; - while(boff < data.length) { - var L = Math.min(0xFFFF, data.length - boff); - var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ - out.write_shift(1, +h); - out.write_shift(2, L); - out.write_shift(2, (~L) & 0xFFFF); - while(L-- > 0) out[out.l++] = data[boff++]; - } - return out.l; - }; -})(); - -return function(data) { - var buf = new_buf(50+Math.floor(data.length*1.1)); - var off = _deflateRaw(data, buf); - return buf.slice(0, off); -}; -})(); -/* modified inflate function also moves original read head */ +} /* build tree (used for literals and lengths) */ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { @@ -1018,6 +1054,7 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { return maxlen; } +/* Fixed Huffman */ 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) { @@ -1037,8 +1074,124 @@ if(!use_typed_arrays) { for(; i<=279; i++) clens.push(7); for(; i<=287; i++) clens.push(8); build_tree(clens, fix_lmap, 288); +})();var _deflateRaw = (function() { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { + var boff = 0; + while(boff < data.length) { + var L = Math.min(0xFFFF, data.length - boff); + var h = boff + L == data.length; + out.write_shift(1, +h); + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + } + return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); + }; })(); +function _deflate(data) { + var buf = new_buf(50+Math.floor(data.length*1.1)); + var off = _deflateRaw(data, buf); + return buf.slice(0, off); +} +/* modified inflate function also moves original read head */ + 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); @@ -1157,8 +1310,8 @@ function inflate(data, usz/*:number*/) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -1189,7 +1342,7 @@ function inflate(data, usz/*:number*/) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } @@ -1288,7 +1441,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } @@ -1355,7 +1508,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); @@ -1614,7 +1770,8 @@ function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -}function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { +} +function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { var o/*:CFBContainer*/ = ({}/*:any*/); init_cfb(o, opts); return o; diff --git a/index.html b/index.html index 06df8c6..5ff18fc 100644 --- a/index.html +++ b/index.html @@ -53,6 +53,12 @@ Use readAsBinaryString: (when available) >> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz/*:number*/) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -966,7 +1002,7 @@ function realloc(b, sz/*:number*/) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -978,30 +1014,7 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -}var _deflate = (function() { -var _deflateRaw = (function() { - return function deflateRaw(data, out) { - var boff = 0; - while(boff < data.length) { - var L = Math.min(0xFFFF, data.length - boff); - var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ - out.write_shift(1, +h); - out.write_shift(2, L); - out.write_shift(2, (~L) & 0xFFFF); - while(L-- > 0) out[out.l++] = data[boff++]; - } - return out.l; - }; -})(); - -return function(data) { - var buf = new_buf(50+Math.floor(data.length*1.1)); - var off = _deflateRaw(data, buf); - return buf.slice(0, off); -}; -})(); -/* modified inflate function also moves original read head */ +} /* build tree (used for literals and lengths) */ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { @@ -1041,6 +1054,7 @@ function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ { return maxlen; } +/* Fixed Huffman */ 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) { @@ -1060,8 +1074,124 @@ if(!use_typed_arrays) { for(; i<=279; i++) clens.push(7); for(; i<=287; i++) clens.push(8); build_tree(clens, fix_lmap, 288); +})();var _deflateRaw = (function() { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { + var boff = 0; + while(boff < data.length) { + var L = Math.min(0xFFFF, data.length - boff); + var h = boff + L == data.length; + out.write_shift(1, +h); + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + } + return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); + }; })(); +function _deflate(data) { + var buf = new_buf(50+Math.floor(data.length*1.1)); + var off = _deflateRaw(data, buf); + return buf.slice(0, off); +} +/* modified inflate function also moves original read head */ + 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); @@ -1180,8 +1310,8 @@ function inflate(data, usz/*:number*/) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -1212,7 +1342,7 @@ function inflate(data, usz/*:number*/) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } @@ -1311,7 +1441,7 @@ function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:C var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } @@ -1378,7 +1508,10 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); @@ -1637,7 +1770,8 @@ function write_mad(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:string*/ { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -}function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { +} +function cfb_new(opts/*:?any*/)/*:CFBContainer*/ { var o/*:CFBContainer*/ = ({}/*:any*/); init_cfb(o, opts); return o; diff --git a/xlscfb.js b/xlscfb.js index 6ec3b27..6d24f0b 100644 --- a/xlscfb.js +++ b/xlscfb.js @@ -109,7 +109,7 @@ CRC32.str = crc32_str; /* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '1.2.0'; +exports.version = '1.2.1'; /* [MS-CFB] 2.6.4 */ function namecmp(l, r) { var L = l.split("/"), R = r.split("/"); @@ -521,7 +521,11 @@ function read_file(filename, options) { } function read(blob, options) { - switch(options && options.type || "base64") { + var type = options && options.type; + if(!type) { + if(has_buf && Buffer.isBuffer(blob)) type = "buffer"; + } + switch(type || "base64") { case "file": return read_file(blob, options); case "base64": return parse(s2a(Base64.decode(blob)), options); case "binary": return parse(s2a(blob), options); @@ -913,6 +917,38 @@ function read_bits_n(buf, bl, n) { return v & f; } +/* helpers for unaligned bit writes */ +function write_bits_3(buf, bl, v) { var w = bl & 7, h = bl >>> 3; + if(w <= 5) buf[h] |= (v & 7) << w; + else { + buf[h] |= (v << w) & 0xFF; + buf[h+1] = (v&7) >> (8-w); + } + return bl + 3; +} + +function write_bits_1(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v = (v&1) << w; + buf[h] |= v; + return bl + 1; +} +function write_bits_8(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v; + return bl + 8; +} +function write_bits_16(buf, bl, v) { + var w = bl & 7, h = bl >>> 3; + v <<= w; + buf[h] |= v & 0xFF; v >>>= 8; + buf[h+1] = v & 0xFF; + buf[h+2] = v >>> 8; + return bl + 16; +} + /* until ArrayBuffer#realloc is a thing, fake a realloc */ function realloc(b, sz) { var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0; @@ -926,7 +962,7 @@ function realloc(b, sz) { } else if(use_typed_arrays) { var a = new Uint8Array(M); if(a.set) a.set(b); - else for(; i < b.length; ++i) a[i] = b[i]; + else for(; i < L; ++i) a[i] = b[i]; return a; } b.length = M; @@ -938,30 +974,7 @@ function zero_fill_array(n) { var o = new Array(n); for(var i = 0; i < n; ++i) o[i] = 0; return o; -}var _deflate = (function() { -var _deflateRaw = (function() { - return function deflateRaw(data, out) { - var boff = 0; - while(boff < data.length) { - var L = Math.min(0xFFFF, data.length - boff); - var h = boff + L == data.length; - /* TODO: this is only type 0 stored */ - out.write_shift(1, +h); - out.write_shift(2, L); - out.write_shift(2, (~L) & 0xFFFF); - while(L-- > 0) out[out.l++] = data[boff++]; - } - return out.l; - }; -})(); - -return function(data) { - var buf = new_buf(50+Math.floor(data.length*1.1)); - var off = _deflateRaw(data, buf); - return buf.slice(0, off); -}; -})(); -/* modified inflate function also moves original read head */ +} /* build tree (used for literals and lengths) */ function build_tree(clens, cmap, MAX) { @@ -1001,6 +1014,7 @@ function build_tree(clens, cmap, MAX) { return maxlen; } +/* Fixed Huffman */ 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) { @@ -1020,8 +1034,124 @@ if(!use_typed_arrays) { for(; i<=279; i++) clens.push(7); for(; i<=287; i++) clens.push(8); build_tree(clens, fix_lmap, 288); +})();var _deflateRaw = (function() { + var DST_LN_RE = use_typed_arrays ? new Uint8Array(0x8000) : []; + for(var j = 0, k = 0; j < DST_LN.length; ++j) { + for(; k < DST_LN[j+1]; ++k) DST_LN_RE[k] = j; + } + for(;k < 32768; ++k) DST_LN_RE[k] = 29; + + var LEN_LN_RE = use_typed_arrays ? new Uint8Array(0x102) : []; + for(j = 0, k = 0; j < LEN_LN.length; ++j) { + for(; k < LEN_LN[j+1]; ++k) LEN_LN_RE[k] = j; + } + + function write_stored(data, out) { + var boff = 0; + while(boff < data.length) { + var L = Math.min(0xFFFF, data.length - boff); + var h = boff + L == data.length; + out.write_shift(1, +h); + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + } + return out.l; + } + + /* Fixed Huffman */ + function write_huff_fixed(data, out) { + var bl = 0; + var boff = 0; + var addrs = use_typed_arrays ? new Uint16Array(0x8000) : []; + while(boff < data.length) { + var L = /* data.length - boff; */ Math.min(0xFFFF, data.length - boff); + + /* write a stored block for short data */ + if(L < 10) { + bl = write_bits_3(out, bl, +!!(boff + L == data.length)); // jshint ignore:line + if(bl & 7) bl += 8 - (bl & 7); + out.l = (bl / 8) | 0; + out.write_shift(2, L); + out.write_shift(2, (~L) & 0xFFFF); + while(L-- > 0) out[out.l++] = data[boff++]; + bl = out.l * 8; + continue; + } + + bl = write_bits_3(out, bl, +!!(boff + L == data.length) + 2); // jshint ignore:line + var hash = 0; + while(L-- > 0) { + var d = data[boff]; + hash = ((hash << 5) ^ d) & 0x7FFF; + + var match = -1, mlen = 0; + + if((match = addrs[hash])) { + match |= boff & ~0x7FFF; + if(match > boff) match -= 0x8000; + if(match < boff) while(data[match + mlen] == data[boff + mlen] && mlen < 250) ++mlen; + } + + if(mlen > 2) { + /* Copy Token */ + d = LEN_LN_RE[mlen]; + if(d <= 22) bl = write_bits_8(out, bl, bitswap8[d+1]>>1) - 1; + else { + write_bits_8(out, bl, 3); + bl += 5; + write_bits_8(out, bl, bitswap8[d-23]>>5); + bl += 3; + } + var len_eb = (d < 8) ? 0 : ((d - 4)>>2); + if(len_eb > 0) { + write_bits_16(out, bl, mlen - LEN_LN[d]); + bl += len_eb; + } + + d = DST_LN_RE[boff - match]; + bl = write_bits_8(out, bl, bitswap8[d]>>3); + bl -= 3; + + var dst_eb = d < 4 ? 0 : (d-2)>>1; + if(dst_eb > 0) { + write_bits_16(out, bl, boff - match - DST_LN[d]); + bl += dst_eb; + } + for(var q = 0; q < mlen; ++q) { + addrs[hash] = boff & 0x7FFF; + hash = ((hash << 5) ^ data[boff]) & 0x7FFF; + ++boff; + } + L-= mlen - 1; + } else { + /* Literal Token */ + if(d <= 143) d = d + 48; + else bl = write_bits_1(out, bl, 1); + bl = write_bits_8(out, bl, bitswap8[d]); + addrs[hash] = boff & 0x7FFF; + ++boff; + } + } + + bl = write_bits_8(out, bl, 0) - 1; + } + out.l = ((bl + 7)/8)|0; + return out.l; + } + return function _deflateRaw(data, out) { + if(data.length < 8) return write_stored(data, out); + return write_huff_fixed(data, out); + }; })(); +function _deflate(data) { + var buf = new_buf(50+Math.floor(data.length*1.1)); + var off = _deflateRaw(data, buf); + return buf.slice(0, off); +} +/* modified inflate function also moves original read head */ + 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); @@ -1140,8 +1270,8 @@ function inflate(data, usz) { 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 + if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; } /* 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]; @@ -1172,7 +1302,7 @@ function inflate(data, usz) { } /* 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; } + if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt + 100); OL = outbuf.length; } while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; } } } @@ -1271,7 +1401,7 @@ function parse_local_file(blob, csz, usz, o, EF) { var data = blob.slice(blob.l, blob.l + _csz); switch(meth) { case 8: data = _inflateRawSync(blob, _usz); break; - case 0: break; + case 0: break; // TODO: scan for magic number default: throw new Error("Unsupported ZIP Compression method " + meth); } @@ -1338,7 +1468,10 @@ function write_zip(cfb, options) { start_cd += namebuf.length; out.push(namebuf); + /* TODO: extra fields? */ + /* TODO: encryption header ? */ + start_cd += outbuf.length; out.push(outbuf); @@ -1597,7 +1730,8 @@ function write_mad(cfb, options) { } out.push(boundary + '--\r\n'); return out.join("\r\n"); -}function cfb_new(opts) { +} +function cfb_new(opts) { var o = ({}); init_cfb(o, opts); return o;