version bump 1.1.0: zip support
This commit is contained in:
parent
8ee792f343
commit
d9b99d68a7
12
.gitignore
vendored
12
.gitignore
vendored
@ -10,18 +10,26 @@ test_files_pres
|
||||
*.[cC][sS][vV]
|
||||
*.[dD][iIbB][fF]
|
||||
*.[pP][rR][nN]
|
||||
*.[pP][mM][dD]*
|
||||
*.[pP][dD][fF]
|
||||
*.[sS][lL][kK]
|
||||
*.socialcalc
|
||||
*.[xX][lL][sSwWcC]
|
||||
*.[xX][lL][sS][xXmMbB]
|
||||
*.[xX][lL][sSwWcCaAtTmM]
|
||||
*.[xX][lL][sSaAtT][xXmMbB]
|
||||
*.[oO][dD][sS]
|
||||
*.[fF][oO][dD][sS]
|
||||
*.[xX][mM][lL]
|
||||
*.[uU][oO][sS]
|
||||
*.[wW][kKqQbB][S1234567890]
|
||||
*.[qQ][pP][wW]
|
||||
*.[bB][iI][fF][fF][23458]
|
||||
*.[rR][tT][fF]
|
||||
*.[eE][tT][hH]
|
||||
*.[zZ][iI][pP]
|
||||
*.[mM][sS][iI]
|
||||
*.123
|
||||
*.htm
|
||||
*.html
|
||||
*.sheetjs
|
||||
*.exe
|
||||
*.img
|
||||
|
@ -4,6 +4,10 @@ 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.1.0 (2018-09-04)
|
||||
|
||||
* Support for ZIP file format
|
||||
|
||||
## 1.0.6 (2018-04-09)
|
||||
|
||||
* `lastIndexOf` in FAT builder enables larger file parsing at minor cost
|
||||
|
55
README.md
55
README.md
@ -1,13 +1,11 @@
|
||||
# Compound File Binary Format
|
||||
# Container File Blobs
|
||||
|
||||
Pure JS implementation of MS-CFB: Compound File Binary File Format, a container
|
||||
format used in many Microsoft file types (XLS, DOC, VBA blobs in XLSX and XLSB)
|
||||
Pure JS implementation of various container file formats, including ZIP and CFB.
|
||||
|
||||
[![Build Status](https://travis-ci.org/SheetJS/js-cfb.svg?branch=master)](https://travis-ci.org/SheetJS/js-cfb)
|
||||
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-cfb/master.svg)](https://coveralls.io/r/SheetJS/js-cfb?branch=master)
|
||||
[![Dependencies Status](https://david-dm.org/sheetjs/js-cfb/status.svg)](https://david-dm.org/sheetjs/js-cfb)
|
||||
[![NPM Downloads](https://img.shields.io/npm/dt/cfb.svg)](https://npmjs.org/package/cfb)
|
||||
[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-cfb?pixel)](https://github.com/SheetJS/js-cfb)
|
||||
|
||||
## Installation
|
||||
@ -79,29 +77,48 @@ The CFB object exposes the following methods and properties:
|
||||
`CFB.parse(blob)` takes a nodejs Buffer or an array of bytes and returns an
|
||||
parsed representation of the data.
|
||||
|
||||
`CFB.read(blob, opts)` wraps `parse`. `opts.type` controls the behavior:
|
||||
`CFB.read(blob, opts)` wraps `parse`.
|
||||
|
||||
`CFB.find(cfb, path)` performs a case-insensitive match for the path (or file
|
||||
name, if there are no slashes) and returns an entry object or null if not found.
|
||||
|
||||
`CFB.write(cfb, opts)` generates a file based on the container.
|
||||
|
||||
`CFB.writeFile(cfb, filename, opts)` creates a file with the specified name.
|
||||
|
||||
### Parse Options
|
||||
|
||||
`CFB.read` takes an options argument. `opts.type` controls the behavior:
|
||||
|
||||
| `type` | expected input |
|
||||
|------------|-----------------------------------------------------------------|
|
||||
|------------|:----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| `"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]`) |
|
||||
|
||||
`CFB.find(cfb, path)` performs a case-insensitive match for the path (or file
|
||||
name, if there are no slashes) and returns an entry object or null if not found.
|
||||
|
||||
`CFB.write(cfb, opts)` generates a file based on the container. `opts.type`
|
||||
controls the behavior:
|
||||
### Write Options
|
||||
|
||||
`CFB.write` and `CFB.writeFile` take options argument.
|
||||
|
||||
`opts.type` controls the behavior:
|
||||
|
||||
| `type` | output |
|
||||
|------------|-----------------------------------------------------------------|
|
||||
|------------|:----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| `"file"` | string: path of file that will be created (nodejs only) |
|
||||
| (default) | buffer if available, array of 8-bit unsigned int otherwise |
|
||||
|
||||
`CFB.writeFile(cfb, filename, opts)` creates a file with the specified name.
|
||||
`opts.fileType` controls the output file type:
|
||||
|
||||
| `fileType` | output |
|
||||
|:-------------------|:--------------|
|
||||
| `'cfb'` (default) | CFB container |
|
||||
| `'zip'` | ZIP file |
|
||||
|
||||
`opts.compression` enables DEFLATE compression for ZIP file type.
|
||||
|
||||
|
||||
## Utility Functions
|
||||
@ -114,6 +131,12 @@ accept a `name` argument strictly deal with absolute file names:
|
||||
Set the option `{unsafe:true}` to skip existence checks (for bulk additions)
|
||||
- `.cfb_del(cfb, name)` deletes the specified file
|
||||
- `.cfb_mov(cfb, old_name, new_name)` moves the old file to new path and name
|
||||
- `.use_zlib(require("zlib"))` loads a nodejs zlib instance.
|
||||
|
||||
By default, the library uses a pure JS inflate/deflate implementation. NodeJS
|
||||
`zlib.InflateRaw` exposes the number of bytes read in versions after `8.11.0`.
|
||||
If a supplied `zlib` does not support the required features, a warning will be
|
||||
displayed in the console and the pure JS fallback will be used.
|
||||
|
||||
|
||||
## Container Object Description
|
||||
@ -146,11 +169,7 @@ granted by the Apache 2.0 License are reserved by the Original Author.
|
||||
|
||||
## References
|
||||
|
||||
|
||||
<details>
|
||||
<summary><b>OSP-covered Specifications</b> (click to show)</summary>
|
||||
|
||||
- [MS-CFB]: Compound File Binary File Format
|
||||
|
||||
</details>
|
||||
- ZIP `APPNOTE.TXT`: https://pkware.cachefly.net/webdocs/APPNOTE/APPNOTE-6.3.4.TXT
|
||||
- RFC1951: https://www.ietf.org/rfc/rfc1951.txt
|
||||
|
||||
|
59
bin/cfb.njs
59
bin/cfb.njs
@ -19,11 +19,16 @@ program
|
||||
.option('-O, --to-stdout', 'extract raw contents to stdout')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('--here', 'skip the CFB root name when extracting')
|
||||
.option('--osx', 'use OSX-style unzip listing')
|
||||
.option('--zlib', 'use native zlib')
|
||||
.option('--local', 'print times in local timezone')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents');
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
if(program.zlib) X.utils.use_zlib(require('zlib'));
|
||||
|
||||
var exit = process.exit;
|
||||
var die = function(errno/*:number*/, msg/*:string*/) { console.error(n + ": " + msg); exit(errno); };
|
||||
var logit = function(cmd/*:string*/, f/*:string*/) { console.error(sprintf("%-6s %s", cmd, f)); };
|
||||
@ -53,16 +58,32 @@ if(program.dump) {
|
||||
}
|
||||
if(program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
|
||||
|
||||
var rlen = cfb.FullPaths[0].length;
|
||||
|
||||
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/g, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
|
||||
var format_date = function(date/*:Date*/)/*:string*/ {
|
||||
return sprintf("%02u-%02u-%02u %02u:%02u", date.getUTCMonth()+1, date.getUTCDate(), date.getUTCFullYear()%100, date.getUTCHours(), date.getUTCMinutes());
|
||||
var format_date = function(date/*:Date*/, osx/*:?any*/)/*:string*/ {
|
||||
var datefmt = osx ? "%02u-%02u-%04u %02u:%02u": "%02u-%02u-%02u %02u:%02u";
|
||||
var MM = program.local ? date.getMonth() + 1 : date.getUTCMonth() + 1;
|
||||
var DD = program.local ? date.getDate() : date.getUTCDate();
|
||||
var YY = (program.local ? date.getFullYear() : date.getUTCFullYear())%(osx ? 10000 : 100);
|
||||
var hh = program.local ? date.getHours() : date.getUTCHours();
|
||||
var mm = program.local ? date.getMinutes() : date.getUTCMinutes();
|
||||
return sprintf(datefmt, MM, DD, YY, hh, mm);
|
||||
};
|
||||
|
||||
if(program.listFiles) {
|
||||
var basetime = new Date(1980,0,1);
|
||||
var basetime = new Date(Date.UTC(1980,0,1));
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
var fmtstr = "%9lu %s %s";
|
||||
if(program.osx) {
|
||||
console.log("Archive: " + program.args[0]);
|
||||
console.log(" Length Date Time Name");
|
||||
console.log("--------- ---------- ----- ----");
|
||||
fmtstr = "%9lu %s %s";
|
||||
} else {
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
}
|
||||
cfb.FileIndex.forEach(function(file/*:CFBEntry*/, i/*:number*/) {
|
||||
switch(file.type) {
|
||||
case 5:
|
||||
@ -70,13 +91,22 @@ if(program.listFiles) {
|
||||
rootsize = file.size;
|
||||
break;
|
||||
case 2:
|
||||
console.log(sprintf("%9lu %s %s", file.size, format_date(basetime), fix_string(cfb.FullPaths[i])));
|
||||
var fixname = fix_string(cfb.FullPaths[i]);
|
||||
if(program.osx && fixname.match(/\\u0001Sh33tJ5/)) return;
|
||||
if(program.here) fixname = fixname.slice(rlen);
|
||||
console.log(sprintf(fmtstr, file.size, format_date(file.mt || basetime, program.osx), fixname));
|
||||
filesize += file.size;
|
||||
++cnt;
|
||||
}
|
||||
});
|
||||
console.log(" -------- -------");
|
||||
console.log(sprintf("%9lu %lu file%s", rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
|
||||
var outfmt = "%9lu %lu file%s";
|
||||
if(program.osx) {
|
||||
console.log("--------- -------");
|
||||
outfmt = "%9lu %lu file%s";
|
||||
} else {
|
||||
console.log(" -------- -------");
|
||||
}
|
||||
console.log(sprintf(outfmt, rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
|
||||
|
||||
exit(0);
|
||||
}
|
||||
@ -124,8 +154,13 @@ if(program.args.length > 1) {
|
||||
}
|
||||
|
||||
if(program.toStdout) exit(0);
|
||||
for(var i=0; i!==cfb.FullPaths.length; ++i) {
|
||||
for(var i=program.here ? 1 : 0; i!==cfb.FullPaths.length; ++i) {
|
||||
if(!cfb.FileIndex[i].name) continue;
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") mkdirp(cfb.FullPaths[i]);
|
||||
else write(cfb.FullPaths[i], cfb.FileIndex[i]);
|
||||
var fp = cfb.FullPaths[i];
|
||||
if(program.here) fp = fp.slice(rlen);
|
||||
if(fp.slice(-1) === "/") mkdirp(fp);
|
||||
else {
|
||||
if(fp.indexOf("/") > -1) mkdirp(fp.slice(0, fp.lastIndexOf("/")));
|
||||
write(fp, cfb.FileIndex[i]);
|
||||
}
|
||||
}
|
||||
|
@ -2,5 +2,5 @@
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
|
@ -5,9 +5,11 @@ var Buffer_from = /*::(*/function(){}/*:: :any)*/;
|
||||
if(typeof Buffer !== 'undefined') {
|
||||
var nbfs = !Buffer.from;
|
||||
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);
|
||||
Buffer_from = /*::((*/nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer)/*::) :any)*/;
|
||||
// $FlowIgnore
|
||||
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
|
||||
// $FlowIgnore
|
||||
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
|
||||
}
|
||||
|
||||
function new_raw_buf(len/*:number*/) {
|
||||
@ -16,8 +18,14 @@ function new_raw_buf(len/*:number*/) {
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s/*:string*/) {
|
||||
if(has_buf) return Buffer.from(s, "binary");
|
||||
function new_unsafe_buf(len/*:number*/) {
|
||||
/* jshint -W056 */
|
||||
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s/*:string*/)/*:any*/ {
|
||||
if(has_buf) return Buffer_from(s, "binary");
|
||||
return s.split("").map(function(x/*:string*/)/*:number*/{ return x.charCodeAt(0) & 0xff; });
|
||||
};
|
||||
|
||||
|
@ -22,7 +22,6 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
|
||||
};
|
||||
__hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { return Buffer.isBuffer(b)/*:: && b instanceof Buffer*/ ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
|
||||
__toBuffer = function(bufs/*:Array<Array<RawBytes>>*/)/*:RawBytes*/ { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0]/*:any*/)) : ___toBuffer(bufs);};
|
||||
// $FlowIgnore
|
||||
s2a = function(s/*:string*/)/*:RawBytes*/ { return Buffer_from(s, "binary"); };
|
||||
bconcat = function(bufs/*:Array<RawBytes>*/)/*:RawBytes*/ { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(/*::(*/bufs/*:: :any)*/) : __bconcat(bufs); };
|
||||
}
|
||||
|
101
bits/21_crc32.js
Normal file
101
bits/21_crc32.js
Normal file
@ -0,0 +1,101 @@
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table()/*:any*/ {
|
||||
var c = 0, table/*:Array<number>*/ = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
@ -1 +1 @@
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
|
38
bits/37_dosdates.js
Normal file
38
bits/37_dosdates.js
Normal file
@ -0,0 +1,38 @@
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms/*:number*/ = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd/*:number*/ = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
27
bits/38_extrafield.js
Normal file
27
bits/38_extrafield.js
Normal file
@ -0,0 +1,27 @@
|
||||
function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
|
||||
prep_blob(blob, 0);
|
||||
var o = /*::(*/{}/*:: :any)*/;
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
@ -1,4 +1,5 @@
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -19,6 +20,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
|
22
bits/78_zlib.js
Normal file
22
bits/78_zlib.js
Normal file
@ -0,0 +1,22 @@
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
70
bits/79_flate.js
Normal file
70
bits/79_flate.js
Normal file
@ -0,0 +1,70 @@
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
function zero_fill_array(n) {
|
||||
var o = new Array(n);
|
||||
for(var i = 0; i < n; ++i) o[i] = 0;
|
||||
return o;
|
||||
}
|
23
bits/80_deflate.js
Normal file
23
bits/80_deflate.js
Normal file
@ -0,0 +1,23 @@
|
||||
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);
|
||||
};
|
||||
})();
|
226
bits/81_inflate.js
Normal file
226
bits/81_inflate.js
Normal file
@ -0,0 +1,226 @@
|
||||
/* modified inflate function also moves original read head */
|
||||
|
||||
/* build tree (used for literals and lengths) */
|
||||
function build_tree(clens, cmap, MAX/*:number*/)/*:number*/ {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens/*:Array<number>*/ = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens/*:Array<number>*/ = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff/*:number*/) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes/*:Array<number>*/ = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz/*:number*/) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
103
bits/82_zparse.js
Normal file
103
bits/82_zparse.js
Normal file
@ -0,0 +1,103 @@
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/);
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
102
bits/83_zwrite.js
Normal file
102
bits/83_zwrite.js
Normal file
@ -0,0 +1,102 @@
|
||||
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o/*:CFBlob*/ = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
|
||||
|
||||
var outbuf = fi.content/*::||[]*/;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
|
||||
}
|
@ -25,6 +25,8 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
@ -13,6 +13,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
740
cfb.flow.js
740
cfb.flow.js
@ -2,7 +2,7 @@
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
var Base64 = (function make_b64(){
|
||||
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
@ -55,9 +55,11 @@ var Buffer_from = /*::(*/function(){}/*:: :any)*/;
|
||||
if(typeof Buffer !== 'undefined') {
|
||||
var nbfs = !Buffer.from;
|
||||
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);
|
||||
Buffer_from = /*::((*/nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer)/*::) :any)*/;
|
||||
// $FlowIgnore
|
||||
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
|
||||
// $FlowIgnore
|
||||
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
|
||||
}
|
||||
|
||||
function new_raw_buf(len/*:number*/) {
|
||||
@ -66,8 +68,14 @@ function new_raw_buf(len/*:number*/) {
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s/*:string*/) {
|
||||
if(has_buf) return Buffer.from(s, "binary");
|
||||
function new_unsafe_buf(len/*:number*/) {
|
||||
/* jshint -W056 */
|
||||
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s/*:string*/)/*:any*/ {
|
||||
if(has_buf) return Buffer_from(s, "binary");
|
||||
return s.split("").map(function(x/*:string*/)/*:number*/{ return x.charCodeAt(0) & 0xff; });
|
||||
};
|
||||
|
||||
@ -96,7 +104,6 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
|
||||
};
|
||||
__hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { return Buffer.isBuffer(b)/*:: && b instanceof Buffer*/ ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
|
||||
__toBuffer = function(bufs/*:Array<Array<RawBytes>>*/)/*:RawBytes*/ { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0]/*:any*/)) : ___toBuffer(bufs);};
|
||||
// $FlowIgnore
|
||||
s2a = function(s/*:string*/)/*:RawBytes*/ { return Buffer_from(s, "binary"); };
|
||||
bconcat = function(bufs/*:Array<RawBytes>*/)/*:RawBytes*/ { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(/*::(*/bufs/*:: :any)*/) : __bconcat(bufs); };
|
||||
}
|
||||
@ -184,10 +191,111 @@ type SectorList = {
|
||||
}
|
||||
type CFBFiles = {[n:string]:CFBEntry};
|
||||
*/
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table()/*:any*/ {
|
||||
var c = 0, table/*:Array<number>*/ = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -208,9 +316,75 @@ function filename(p/*:string*/)/*:string*/ {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms/*:number*/ = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd/*:number*/ = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
||||
function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
|
||||
prep_blob(blob, 0);
|
||||
var o = /*::(*/{}/*:: :any)*/;
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -231,6 +405,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -309,6 +485,7 @@ return o;
|
||||
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
@ -626,6 +803,7 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
|
||||
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
|
||||
var mini_size = 0, fat_size = 0;
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
@ -826,6 +1004,551 @@ function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
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*/ {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens/*:Array<number>*/ = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens/*:Array<number>*/ = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff/*:number*/) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes/*:Array<number>*/ = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz/*:number*/) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/);
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
||||
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o/*:CFBlob*/ = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
|
||||
|
||||
var outbuf = fi.content/*::||[]*/;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
|
||||
}
|
||||
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
|
||||
var o/*:CFBContainer*/ = ({}/*:any*/);
|
||||
init_cfb(o, opts);
|
||||
@ -853,6 +1576,8 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@ -896,6 +1621,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
736
cfb.js
736
cfb.js
@ -2,7 +2,7 @@
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
var Base64 = (function make_b64(){
|
||||
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
@ -58,6 +58,8 @@ if(typeof Buffer !== 'undefined') {
|
||||
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); };
|
||||
// $FlowIgnore
|
||||
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
|
||||
}
|
||||
|
||||
function new_raw_buf(len) {
|
||||
@ -66,8 +68,14 @@ function new_raw_buf(len) {
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
function new_unsafe_buf(len) {
|
||||
/* jshint -W056 */
|
||||
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s) {
|
||||
if(has_buf) return Buffer.from(s, "binary");
|
||||
if(has_buf) return Buffer_from(s, "binary");
|
||||
return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
|
||||
};
|
||||
|
||||
@ -96,7 +104,6 @@ if(has_buf) {
|
||||
};
|
||||
__hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
|
||||
__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0])) : ___toBuffer(bufs);};
|
||||
// $FlowIgnore
|
||||
s2a = function(s) { return Buffer_from(s, "binary"); };
|
||||
bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : __bconcat(bufs); };
|
||||
}
|
||||
@ -166,10 +173,111 @@ function new_buf(sz) {
|
||||
return o;
|
||||
}
|
||||
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table() {
|
||||
var c = 0, table = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr, seed) {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf, seed) {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf, seed) {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str, seed) {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports = {};
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l, r) {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -190,9 +298,75 @@ function filename(p) {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf, date) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf) {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
||||
function parse_extra_field(blob) {
|
||||
prep_blob(blob, 0);
|
||||
var o = {};
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file, options) {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -213,6 +387,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -291,6 +467,7 @@ return o;
|
||||
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob) {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
@ -608,6 +785,7 @@ function rebuild_cfb(cfb, f) {
|
||||
function _write(cfb, options) {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
var L = (function(cfb){
|
||||
var mini_size = 0, fat_size = 0;
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
@ -802,6 +980,551 @@ function write(cfb, options) {
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
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) {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file, options) {
|
||||
var blob = file;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex = [], FullPaths = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob, csz, usz, o, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
||||
function write_zip(cfb, options) {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(fi.content, 0);
|
||||
|
||||
var outbuf = fi.content;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, fi.content.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, fi.content.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out)), bconcat(cdirs), o]));
|
||||
}
|
||||
function cfb_new(opts) {
|
||||
var o = ({});
|
||||
init_cfb(o, opts);
|
||||
@ -828,6 +1551,8 @@ file.content = (content);
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@ -871,6 +1596,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
736
dist/cfb.js
vendored
736
dist/cfb.js
vendored
@ -2,7 +2,7 @@
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
var Base64 = (function make_b64(){
|
||||
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
|
||||
@ -58,6 +58,8 @@ if(typeof Buffer !== 'undefined') {
|
||||
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); };
|
||||
// $FlowIgnore
|
||||
if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
|
||||
}
|
||||
|
||||
function new_raw_buf(len) {
|
||||
@ -66,8 +68,14 @@ function new_raw_buf(len) {
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
function new_unsafe_buf(len) {
|
||||
/* jshint -W056 */
|
||||
return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
|
||||
/* jshint +W056 */
|
||||
}
|
||||
|
||||
var s2a = function s2a(s) {
|
||||
if(has_buf) return Buffer.from(s, "binary");
|
||||
if(has_buf) return Buffer_from(s, "binary");
|
||||
return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
|
||||
};
|
||||
|
||||
@ -96,7 +104,6 @@ if(has_buf) {
|
||||
};
|
||||
__hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
|
||||
__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat((bufs[0])) : ___toBuffer(bufs);};
|
||||
// $FlowIgnore
|
||||
s2a = function(s) { return Buffer_from(s, "binary"); };
|
||||
bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : __bconcat(bufs); };
|
||||
}
|
||||
@ -166,10 +173,111 @@ function new_buf(sz) {
|
||||
return o;
|
||||
}
|
||||
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table() {
|
||||
var c = 0, table = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr, seed) {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf, seed) {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf, seed) {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str, seed) {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports = {};
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l, r) {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -190,9 +298,75 @@ function filename(p) {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf, date) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf) {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
||||
function parse_extra_field(blob) {
|
||||
prep_blob(blob, 0);
|
||||
var o = {};
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file, options) {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -213,6 +387,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -291,6 +467,7 @@ return o;
|
||||
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob) {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
@ -608,6 +785,7 @@ function rebuild_cfb(cfb, f) {
|
||||
function _write(cfb, options) {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
var L = (function(cfb){
|
||||
var mini_size = 0, fat_size = 0;
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
@ -802,6 +980,551 @@ function write(cfb, options) {
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
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) {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file, options) {
|
||||
var blob = file;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex = [], FullPaths = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob, csz, usz, o, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
||||
function write_zip(cfb, options) {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(fi.content, 0);
|
||||
|
||||
var outbuf = fi.content;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, fi.content.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, fi.content.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out)), bconcat(cdirs), o]));
|
||||
}
|
||||
function cfb_new(opts) {
|
||||
var o = ({});
|
||||
init_cfb(o, opts);
|
||||
@ -828,6 +1551,8 @@ file.content = (content);
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@ -871,6 +1596,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
2
dist/cfb.min.js
vendored
2
dist/cfb.min.js
vendored
File diff suppressed because one or more lines are too long
2
dist/cfb.min.map
vendored
2
dist/cfb.min.map
vendored
File diff suppressed because one or more lines are too long
728
dist/xlscfb.js
vendored
728
dist/xlscfb.js
vendored
@ -12,13 +12,16 @@ declare var bconcat:any;
|
||||
declare var s2a:any;
|
||||
declare var chr0:any;
|
||||
declare var chr1:any;
|
||||
declare var has_buf:boolean;
|
||||
declare var new_buf:any;
|
||||
declare var new_raw_buf:any;
|
||||
declare var new_unsafe_buf:any;
|
||||
*/
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
/*::
|
||||
declare var DO_NOT_EXPORT_CFB:?boolean;
|
||||
@ -35,10 +38,111 @@ type SectorList = {
|
||||
}
|
||||
type CFBFiles = {[n:string]:CFBEntry};
|
||||
*/
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table()/*:any*/ {
|
||||
var c = 0, table/*:Array<number>*/ = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -59,9 +163,75 @@ function filename(p/*:string*/)/*:string*/ {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms/*:number*/ = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd/*:number*/ = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
||||
function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
|
||||
prep_blob(blob, 0);
|
||||
var o = /*::(*/{}/*:: :any)*/;
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -82,6 +252,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -160,6 +332,7 @@ return o;
|
||||
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
@ -477,6 +650,7 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
|
||||
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
|
||||
var mini_size = 0, fat_size = 0;
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
@ -677,6 +851,551 @@ function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
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*/ {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens/*:Array<number>*/ = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens/*:Array<number>*/ = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff/*:number*/) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes/*:Array<number>*/ = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz/*:number*/) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/);
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
||||
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o/*:CFBlob*/ = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
|
||||
|
||||
var outbuf = fi.content/*::||[]*/;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
|
||||
}
|
||||
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
|
||||
var o/*:CFBContainer*/ = ({}/*:any*/);
|
||||
init_cfb(o, opts);
|
||||
@ -704,6 +1423,8 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@ -747,6 +1468,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
11
fails.lst
11
fails.lst
@ -1,6 +1,13 @@
|
||||
# not CFB or ZIP
|
||||
apachepoi_testEXCEL_3.xls
|
||||
apachepoi_testEXCEL_4.xls
|
||||
xlrd_biff4_no_format_no_window2.xls
|
||||
roo_type_excelx.xls
|
||||
roo_type_openoffice.xls
|
||||
libreoffice_calc_csv-import_malformed-quotes.xls
|
||||
# file exceeding 31 chars
|
||||
apachepoi_59746_NoRowNums.xlsx
|
||||
apachepoi_WithEmbeded.xlsx
|
||||
apachepoi_picture.xlsx
|
||||
roo_name_with_leading_slash.xlsx
|
||||
spout-xlsx_sheet_with_prefixed_xml_files.xlsx
|
||||
# not a valid file
|
||||
openpyxl_r_null_archive.xlsx
|
||||
|
18
index.html
18
index.html
@ -32,7 +32,9 @@ a { text-decoration: none }
|
||||
<b>Advanced Demo Options:</b>
|
||||
Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" checked>
|
||||
|
||||
<a id="saveit" onclick="savefile();" href="#">Export data</a>
|
||||
<b>Export Current File</b>
|
||||
- <a id="savecfb" onclick="savefile('cfb');" href="#">Export data as CFB</a>
|
||||
- <a id="savezip" onclick="savefile('zip');" href="#">Export data as ZIP</a>
|
||||
</pre>
|
||||
<pre id="out"></pre>
|
||||
<br />
|
||||
@ -40,7 +42,7 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
|
||||
<script src="https://unpkg.com/printj/dist/printj.min.js"></script>
|
||||
<script src="cfb.js"></script>
|
||||
<script src="//rawgit.com/eligrey/Blob.js/master/Blob.js"></script>
|
||||
<script src="//rawgit.com/eligrey/FileSaver.js/master/FileSaver.js"></script>
|
||||
<script src="//unpkg.com/filesaver.js/FileSaver.js"></script>
|
||||
<script>
|
||||
/*jshint browser:true */
|
||||
/* eslint-env browser */
|
||||
@ -58,6 +60,7 @@ var get_manifest = (function() {
|
||||
};
|
||||
return function get_manifest(cfb) {
|
||||
var out = [];
|
||||
var rlen = cfb.FullPaths[0].length;
|
||||
|
||||
var basetime = new Date(1980,0,1);
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
@ -70,7 +73,10 @@ var get_manifest = (function() {
|
||||
rootsize = file.size;
|
||||
break;
|
||||
case 2:
|
||||
out.push(sprintf("%9lu %s <a href=\"#\" onclick=\"download_file(%d);\">%s</a>", file.size, format_date(basetime), i, fix_string(cfb.FullPaths[i])));
|
||||
var fixname = fix_string(cfb.FullPaths[i]);
|
||||
if(fixname.match(/\\u0001Sh33tJ5/)) return;
|
||||
fixname = fixname.slice(rlen);
|
||||
out.push(sprintf("%9lu %s <a href=\"#\" onclick=\"download_file(%d);\">%s</a>", file.size, format_date(basetime), i, fixname));
|
||||
filesize += file.size;
|
||||
++cnt;
|
||||
}
|
||||
@ -149,12 +155,12 @@ var savefile = (function() {
|
||||
}
|
||||
};
|
||||
|
||||
return function savefile() {
|
||||
return function savefile(type) {
|
||||
if(!global_cfb) return alert("Must load a file first!");
|
||||
if(typeof console !== 'undefined') console.log(global_cfb);
|
||||
var data = CFB.write(global_cfb, {type:'binary'});
|
||||
var data = CFB.write(global_cfb, {type:'binary', fileType: type});
|
||||
if(typeof console !== 'undefined') console.log(data);
|
||||
saveAs(new Blob([s2ab(data)],{type:"application/octet-stream"}), "sheetjs.xls");
|
||||
saveAs(new Blob([s2ab(data)],{type:"application/octet-stream"}), "SheetJSCFBDemo." + type);
|
||||
};
|
||||
})();
|
||||
|
||||
|
@ -64,6 +64,7 @@ type CFBWriteOpts = any;
|
||||
|
||||
interface CFBReadOpts {
|
||||
type?:string;
|
||||
root?:string;
|
||||
};
|
||||
|
||||
type CFBFileIndex = Array<CFBEntry>;
|
||||
|
@ -12,5 +12,8 @@ declare var bconcat:any;
|
||||
declare var s2a:any;
|
||||
declare var chr0:any;
|
||||
declare var chr1:any;
|
||||
declare var has_buf:boolean;
|
||||
declare var new_buf:any;
|
||||
declare var new_raw_buf:any;
|
||||
declare var new_unsafe_buf:any;
|
||||
*/
|
||||
|
13
package.json
13
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cfb",
|
||||
"version": "1.0.8",
|
||||
"version": "1.1.0",
|
||||
"author": "sheetjs",
|
||||
"description": "Compound File Binary File Format extractor",
|
||||
"keywords": [
|
||||
@ -19,17 +19,18 @@
|
||||
"fs": false
|
||||
},
|
||||
"dependencies": {
|
||||
"commander": "^2.14.1",
|
||||
"adler-32": "~1.2.0",
|
||||
"commander": "^2.16.0",
|
||||
"crc-32": "~1.2.0",
|
||||
"printj": "~1.1.2"
|
||||
},
|
||||
"devDependencies": {
|
||||
"crc-32": "~1.2.0",
|
||||
"mocha": "~2.5.3",
|
||||
"blanket": "~1.2.3",
|
||||
"@sheetjs/uglify-js": "~2.7.3",
|
||||
"@types/node": "^8.5.9",
|
||||
"@types/commander": "^2.9.0",
|
||||
"@types/node": "^8.10.25",
|
||||
"blanket": "~1.2.3",
|
||||
"dtslint": "~0.1.2",
|
||||
"mocha": "~2.5.3",
|
||||
"typescript": "2.2.0"
|
||||
},
|
||||
"repository": {
|
||||
|
166
test.js
166
test.js
@ -12,9 +12,11 @@ declare var before:(test:EmptyFunc)=>void;
|
||||
*/
|
||||
var CFB;
|
||||
var fs = require('fs');
|
||||
describe('source', function() { it('should load', function() { CFB = require('./'); }); });
|
||||
describe('source', function() { it('should load', function() { CFB = require('./'); if(zlibify) CFB.utils.use_zlib(require("zlib")); }); });
|
||||
var CRC32 = require('crc-32');
|
||||
|
||||
var WTF = !!process.env.WTF;
|
||||
var zlibify = !!process.env.ZLIB;
|
||||
var ex = [".xls",".doc",".ppt"];
|
||||
if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
|
||||
if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
|
||||
@ -26,12 +28,12 @@ var files = fs.readdirSync('test_files').filter(ffunc);
|
||||
var f2011 = fs.readdirSync('test_files/2011').filter(ffunc);
|
||||
var f2013 = fs.readdirSync('test_files/2013').filter(ffunc);
|
||||
var fpres = fs.readdirSync('test_files_pres').filter(ffunc);
|
||||
var fxlsx = fs.readdirSync('test_files').filter(function(x) { return x.slice(-5) == ".xlsx"; });
|
||||
var fxlsx = fs.readdirSync('test_files').filter(function(x) { return x.slice(-5) == ".xlsx" && fails.indexOf(x) === -1; });
|
||||
|
||||
var dir = "./test_files/";
|
||||
var TYPE = "buffer";
|
||||
|
||||
var names = [
|
||||
var names/*:Array<Array<string>>*/ = [
|
||||
["!DocumentSummaryInformation", "\u0005"],
|
||||
["!SummaryInformation", "\u0005"],
|
||||
["!CompObj", "\u0001"],
|
||||
@ -41,23 +43,45 @@ var names = [
|
||||
["!Ole", "\u0001"]
|
||||
].map(function(x) { return [x[0], x[0].replace("!", x[1])]; });
|
||||
|
||||
/* [ rel, abs ] */
|
||||
var ENTRIES/*:Array<Array<string>>*/ = [
|
||||
/* DOC */
|
||||
["WordDocument", "/WordDocument"],
|
||||
/* PPT */
|
||||
["PowerPoint Document", "/PowerPoint Document"],
|
||||
/* XLS */
|
||||
["Workbook", "/Workbook"],
|
||||
["Book", "/Book"],
|
||||
/* OPC */
|
||||
["[Content_Types].xml", "/[Content_Types].xml"],
|
||||
/* ODF */
|
||||
["content.xml", "/content.xml"],
|
||||
/* XLSX */
|
||||
["workbook.xml", "/xl/workbook.xml"],
|
||||
/* Encrypted */
|
||||
["EncryptedPackage", "/EncryptedPackage"],
|
||||
["EncryptionInfo", "/EncryptionInfo"]
|
||||
];
|
||||
|
||||
var REL_FILES = ENTRIES.map(function(e) { return e[0]; });
|
||||
var ABS_FILES = ENTRIES.map(function(e) { return e[1]; });
|
||||
|
||||
function has_file(cfb, files/*:Array<string>*/)/*:string*/ {
|
||||
for(var i = 0; i < files.length; ++i) if(CFB.find(cfb, files[i])) return files[i];
|
||||
return "";
|
||||
}
|
||||
|
||||
function zero_dates(cfb) {
|
||||
cfb.FileIndex.forEach(function(f) { delete f.mt; delete f.ct; });
|
||||
}
|
||||
|
||||
function parsetest(x, cfb) {
|
||||
describe(x + ' should have basic parts', function() {
|
||||
it('should find relative path', function() {
|
||||
switch(x.substr(-4)) {
|
||||
case '.xls': if(!CFB.find(cfb, 'Workbook') && !CFB.find(cfb, 'Book')) throw new Error("Cannot find workbook for " + x); break;
|
||||
case '.ppt': if(!CFB.find(cfb, 'PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break;
|
||||
case '.doc': if(!CFB.find(cfb, 'WordDocument') && !CFB.find(cfb, 'Word Document')) throw new Error("Cannot find doc for " + x); break;
|
||||
case 'xlsx': if(!CFB.find(cfb, 'Workbook') && !CFB.find(cfb, 'Book') && !CFB.find(cfb, 'WordDocument') && !CFB.find(cfb, 'EncryptedPackage') && !CFB.find(cfb, 'EncryptionInfo')) throw new Error("Cannot find workbook or encryption for " + x); break;
|
||||
}
|
||||
if(!has_file(cfb, REL_FILES)) throw new Error("Cannot find content for " + x);
|
||||
});
|
||||
it('should find absolute path', function() {
|
||||
switch(x.substr(-4)) {
|
||||
case '.xls': if(!CFB.find(cfb, '/Workbook') && !CFB.find(cfb, '/Book')) throw new Error("Cannot find workbook for " + x); break;
|
||||
case '.ppt': if(!CFB.find(cfb, '/PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break;
|
||||
case '.doc': if(!CFB.find(cfb, '/WordDocument') && !CFB.find(cfb, '/Word Document')) throw new Error("Cannot find doc for " + x); break;
|
||||
case 'xlsx': if(!CFB.find(cfb, '/Workbook') && !CFB.find(cfb, '/Book') && !CFB.find(cfb, '/WordDocument') && !CFB.find(cfb, '/EncryptedPackage') && !CFB.find(cfb, '/EncryptionInfo')) throw new Error("Cannot find workbook or encryption for " + x); break;
|
||||
}
|
||||
if(!has_file(cfb, ABS_FILES)) throw new Error("Cannot find content for " + x);
|
||||
});
|
||||
it('should handle "!" aliases', function() {
|
||||
names.forEach(function(n) { if(CFB.find(cfb,n[0]) != CFB.find(cfb,n[1])) throw new Error("Bad name: " + n.join(" != ")); });
|
||||
@ -67,33 +91,50 @@ function parsetest(x, cfb) {
|
||||
});
|
||||
});
|
||||
describe(x + ' should roundtrip', function() {
|
||||
var data, newcfb;
|
||||
it('should roundtrip safely', function() {
|
||||
data = CFB.write(cfb, {type:TYPE});
|
||||
newcfb = CFB.read(data, {type:TYPE});
|
||||
var datacfb, newcfb;
|
||||
var datazip, newzip;
|
||||
var datacmp, newcmp;
|
||||
before(function() {
|
||||
/* cfb */
|
||||
zero_dates(cfb);
|
||||
datacfb = CFB.write(cfb, {type:TYPE});
|
||||
newcfb = CFB.read(datacfb, {type:TYPE});
|
||||
zero_dates(newcfb);
|
||||
|
||||
/* zip */
|
||||
zero_dates(cfb);
|
||||
datazip = CFB.write(cfb, {type:TYPE, fileType:"zip"});
|
||||
newzip = CFB.read(datazip, {type:TYPE});
|
||||
zero_dates(newzip);
|
||||
|
||||
/* zip with compression */
|
||||
zero_dates(cfb);
|
||||
datacmp = CFB.write(cfb, {type:TYPE, fileType:"zip", compression:1});
|
||||
newcmp = CFB.read(datacmp, {type:TYPE});
|
||||
zero_dates(newcmp);
|
||||
});
|
||||
if(x.substr(-4) !== "xlsx") it('should preserve content', function() {
|
||||
var _old, _new;
|
||||
switch(x.substr(-4)) {
|
||||
case '.xls':
|
||||
_old = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
|
||||
_new = CFB.find(newcfb, '/Workbook') || CFB.find(newcfb, '/Book');
|
||||
break;
|
||||
case '.ppt':
|
||||
_old = CFB.find(cfb, '/PowerPoint Document');
|
||||
_new = CFB.find(newcfb, '/PowerPoint Document');
|
||||
break;
|
||||
case '.doc':
|
||||
_old = CFB.find(cfb, '/WordDocument') || CFB.find(cfb, '/Word Document');
|
||||
_new = CFB.find(newcfb, '/WordDocument') || CFB.find(newcfb, '/Word Document');
|
||||
break;
|
||||
}
|
||||
/*:: if(!_old || !_new) throw "unreachable"; */
|
||||
if(CRC32.buf(_old.content) != CRC32.buf(_new.content)) throw new Error(x + " failed roundtrip test");
|
||||
it('should preserve content', function() {
|
||||
var path = has_file(cfb, REL_FILES);
|
||||
var _old = CFB.find(cfb, path);
|
||||
var _cfb = CFB.find(newcfb, path);
|
||||
var _zip = CFB.find(newzip, path);
|
||||
var _cmp = CFB.find(newcmp, path);
|
||||
/*:: if(!_old || !_cfb || !_zip || !_cmp) throw "unreachable"; */
|
||||
var c1 = CRC32.buf(_old.content);
|
||||
var c2 = CRC32.buf(_cfb.content);
|
||||
var c3 = CRC32.buf(_zip.content);
|
||||
var c4 = CRC32.buf(_cmp.content);
|
||||
if(c1 != c2) throw new Error(x + " failed CFB roundtrip test");
|
||||
if(c1 != c3) throw new Error(x + " failed ZIP roundtrip test");
|
||||
if(c1 != c4) throw new Error(x + " failed ZIP compression roundtrip test");
|
||||
});
|
||||
it('should be idempotent', function() {
|
||||
var dat2 = CFB.write(newcfb, {type:TYPE});
|
||||
if(CRC32.buf(data) != CRC32.buf(dat2)) throw new Error(x + " failed idempotent test");
|
||||
if(CRC32.buf(datacfb) != CRC32.buf(dat2)) throw new Error(x + " failed CFB idempotent test");
|
||||
var dat2zip = CFB.write(newzip, {type:TYPE, fileType:"zip"});
|
||||
if(CRC32.buf(datazip) != CRC32.buf(dat2zip)) throw new Error(x + " failed ZIP idempotent test");
|
||||
var dat2cmp = CFB.write(newcmp, {type:TYPE, fileType:"zip", compression:1});
|
||||
if(CRC32.buf(datacmp) != CRC32.buf(dat2cmp)) throw new Error(x + " failed ZIP idempotent test");
|
||||
});
|
||||
});
|
||||
}
|
||||
@ -101,32 +142,32 @@ function parsetest(x, cfb) {
|
||||
describe('should parse test files', function() {
|
||||
files.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
fpres.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files_pres/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files_pres/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
f2011.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files/2011/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/2011/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
f2013.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
var cfb = CFB.read('./test_files/2013/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/2013/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
});
|
||||
});
|
||||
fxlsx.forEach(function(x) {
|
||||
it('should parse ' + x, function() {
|
||||
try {
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file"});
|
||||
var cfb = CFB.read('./test_files/' + x, {type: "file", WTF: WTF});
|
||||
parsetest(x, cfb);
|
||||
} catch(e) {
|
||||
if(e.message.match(/CFB file size /)) return;
|
||||
@ -147,16 +188,53 @@ describe('should parse test files', function() {
|
||||
});
|
||||
|
||||
var cp = 'custom_properties.xls';
|
||||
|
||||
var xl = 'custom_properties.xlsx';
|
||||
describe('input formats', function() {
|
||||
it('should read binary strings', function() {
|
||||
CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'});
|
||||
CFB.read(fs.readFileSync(dir + '/' + xl, 'binary'), {type: 'binary'});
|
||||
});
|
||||
it('should read base64 strings', function() {
|
||||
CFB.read(fs.readFileSync(dir + '/' + cp, 'base64'), {type: 'base64'});
|
||||
CFB.read(fs.readFileSync(dir + '/' + xl, 'base64'), {type: 'base64'});
|
||||
});
|
||||
it('should read buffers', function() {
|
||||
CFB.read(fs.readFileSync(dir + '/' + cp), {type: 'buffer'});
|
||||
CFB.read(fs.readFileSync(dir + '/' + xl), {type: 'buffer'});
|
||||
});
|
||||
});
|
||||
describe('output formats', function() {
|
||||
it('should write binary strings', function() {
|
||||
var t = [
|
||||
[ "CFB", CFB.write(CFB.read(fs.readFileSync(dir + '/' + cp, 'binary'), {type: 'binary'}), {type: 'binary'})],
|
||||
[ "ZIP", CFB.write(CFB.read(fs.readFileSync(dir + '/' + xl, 'binary'), {type: 'binary'}), {type: 'binary', fileType: 'zip'})]
|
||||
];
|
||||
t.forEach(function(r) {
|
||||
if(typeof r[1] != "string") throw new Error(r[0] + " binary write failed");
|
||||
var good = false;
|
||||
for(var i = 0; i < r[1].length; ++i) {
|
||||
if(r[1].charCodeAt(i) == 0x00) good = true;
|
||||
else if(r[1].charCodeAt(i) > 0xFF) { good = false; break; }
|
||||
}
|
||||
if(!good) throw new Error(r[0] + " binary write failed");
|
||||
});
|
||||
});
|
||||
it('should write base64 strings', function() {
|
||||
var t = [
|
||||
[ "CFB", CFB.write(CFB.read(fs.readFileSync(dir + '/' + cp, 'base64'), {type: 'base64'}), {type: 'base64'})],
|
||||
[ "ZIP", CFB.write(CFB.read(fs.readFileSync(dir + '/' + xl, 'base64'), {type: 'base64'}), {type: 'base64', fileType: 'zip'})]
|
||||
];
|
||||
t.forEach(function(r) {
|
||||
if(typeof r[1] != "string") throw new Error(r[0] + " base64 write failed");
|
||||
var good = false;
|
||||
if(r[1].match(/[^a-zA-Z0-9+\/\+\.=]/)) throw new Error(r[0] + " base64 write failed");
|
||||
});
|
||||
});
|
||||
it('should write buffers', function() {
|
||||
var t1 = CFB.write(CFB.read(fs.readFileSync(dir + '/' + cp), {type: 'buffer'}), {type: 'buffer'});
|
||||
var t2 = CFB.write(CFB.read(fs.readFileSync(dir + '/' + xl), {type: 'buffer'}), {type: 'buffer'});
|
||||
if(!Buffer.isBuffer(t1)) throw new Error("CFB buffer write failed");
|
||||
if(!Buffer.isBuffer(t2)) throw new Error("ZIP buffer write failed");
|
||||
});
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
/// <reference types="../node_modules/@types/node" />
|
||||
const n = "cfb";
|
||||
import * as X from 'cfb';
|
||||
import fs = require('fs');
|
||||
|
23
types/index.d.ts
vendored
23
types/index.d.ts
vendored
@ -14,27 +14,40 @@ export function read(f: CFB$Blob | string, options?: CFB$ParsingOptions): CFB$Co
|
||||
export function find(cfb: CFB$Container, path: string): CFB$Entry | null;
|
||||
|
||||
/** Generate a container file */
|
||||
export function write(cfb: CFB$Container, options?: any): any;
|
||||
export function write(cfb: CFB$Container, options?: CFB$WritingOptions): any;
|
||||
|
||||
/** Write a container file to the filesystem */
|
||||
export function writeFile(cfb: CFB$Container, filename: string, options?: any): any;
|
||||
export function writeFile(cfb: CFB$Container, filename: string, options?: CFB$WritingOptions): any;
|
||||
|
||||
/** Utility functions */
|
||||
export const utils: CFB$Utils;
|
||||
|
||||
|
||||
/** Options for read and readFile */
|
||||
export interface CFB$ParsingOptions {
|
||||
export interface CFB$CommonOptions {
|
||||
/** Input data encoding */
|
||||
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array';
|
||||
|
||||
/** If true, throw errors when features are not understood */
|
||||
WTF?: boolean;
|
||||
}
|
||||
|
||||
/** Options for read and readFile */
|
||||
export interface CFB$ParsingOptions extends CFB$CommonOptions {
|
||||
/** If true, include raw data in output */
|
||||
raw?: boolean;
|
||||
}
|
||||
|
||||
/** Options for write and writeFile */
|
||||
export interface CFB$WritingOptions extends CFB$CommonOptions {
|
||||
/** Output file type */
|
||||
fileType?: 'cfb' | 'zip';
|
||||
|
||||
/** Override default root entry name (CFB only) */
|
||||
root?: string;
|
||||
|
||||
/** Enable compression (ZIP only) */
|
||||
compression?: boolean;
|
||||
}
|
||||
|
||||
export type CFB$Blob = number[] | Uint8Array;
|
||||
|
||||
export enum CFB$EntryType { unknown, storage, stream, lockbytes, property, root }
|
||||
|
@ -6,6 +6,8 @@
|
||||
"only-arrow-functions": false,
|
||||
"no-consecutive-blank-lines": false,
|
||||
"prefer-conditional-expression": false,
|
||||
"one-variable-per-declaration": false
|
||||
"one-variable-per-declaration": false,
|
||||
"no-implicit-dependencies": false,
|
||||
"prefer-template": false
|
||||
}
|
||||
}
|
||||
|
728
xlscfb.flow.js
728
xlscfb.flow.js
@ -12,13 +12,16 @@ declare var bconcat:any;
|
||||
declare var s2a:any;
|
||||
declare var chr0:any;
|
||||
declare var chr1:any;
|
||||
declare var has_buf:boolean;
|
||||
declare var new_buf:any;
|
||||
declare var new_raw_buf:any;
|
||||
declare var new_unsafe_buf:any;
|
||||
*/
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
/*::
|
||||
declare var DO_NOT_EXPORT_CFB:?boolean;
|
||||
@ -35,10 +38,111 @@ type SectorList = {
|
||||
}
|
||||
type CFBFiles = {[n:string]:CFBEntry};
|
||||
*/
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table()/*:any*/ {
|
||||
var c = 0, table/*:Array<number>*/ = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf/*:Uint8Array|Array<number>*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str/*:string*/, seed/*:number*/)/*:number*/ {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -59,9 +163,75 @@ function filename(p/*:string*/)/*:string*/ {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf/*:CFBlob*/, date/*:Date|string*/) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms/*:number*/ = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd/*:number*/ = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf/*:CFBlob*/)/*:Date*/ {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
||||
function parse_extra_field(blob/*:CFBlob*/)/*:any*/ {
|
||||
prep_blob(blob, 0);
|
||||
var o = /*::(*/{}/*:: :any)*/;
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -82,6 +252,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -160,6 +332,7 @@ return o;
|
||||
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
@ -477,6 +650,7 @@ function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
|
||||
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
|
||||
var mini_size = 0, fat_size = 0;
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
@ -677,6 +851,551 @@ function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
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*/ {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens/*:Array<number>*/ = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens/*:Array<number>*/ = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff/*:number*/) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes/*:Array<number>*/ = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz/*:number*/) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var blob/*:CFBlob*/ = /*::(*/file/*:: :any)*/;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(/*::(*/blob.slice(blob.l+namelen, blob.l+namelen+efsz)/*:: :any)*/);
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob/*:CFBlob*/, csz/*:number*/, usz/*:number*/, o/*:CFBContainer*/, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(/*::(*/blob.slice(blob.l, blob.l + efsz)/*:: :any)*/);
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
||||
function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o/*:CFBlob*/ = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
|
||||
|
||||
var outbuf = fi.content/*::||[]*/;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, /*::(*/fi.content/*::||[])*/.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out/*:any*/)), bconcat(cdirs), o]/*:any*/));
|
||||
}
|
||||
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
|
||||
var o/*:CFBContainer*/ = ({}/*:any*/);
|
||||
init_cfb(o, opts);
|
||||
@ -704,6 +1423,8 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@ -747,6 +1468,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
725
xlscfb.js
725
xlscfb.js
@ -3,12 +3,113 @@ var DO_NOT_EXPORT_CFB = true;
|
||||
/* vim: set ts=2: */
|
||||
/*jshint eqnull:true */
|
||||
/*exported CFB */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
|
||||
/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
|
||||
|
||||
/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported CRC32 */
|
||||
var CRC32;
|
||||
(function (factory) {
|
||||
/*jshint ignore:start */
|
||||
/*eslint-disable */
|
||||
factory(CRC32 = {});
|
||||
/*eslint-enable */
|
||||
/*jshint ignore:end */
|
||||
}(function(CRC32) {
|
||||
CRC32.version = '1.2.0';
|
||||
/* see perf/crc32table.js */
|
||||
/*global Int32Array */
|
||||
function signed_crc_table() {
|
||||
var c = 0, table = new Array(256);
|
||||
|
||||
for(var n =0; n != 256; ++n){
|
||||
c = n;
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
|
||||
table[n] = c;
|
||||
}
|
||||
|
||||
return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
|
||||
}
|
||||
|
||||
var T = signed_crc_table();
|
||||
function crc32_bstr(bstr, seed) {
|
||||
var C = seed ^ -1, L = bstr.length - 1;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
|
||||
}
|
||||
if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf(buf, seed) {
|
||||
if(buf.length > 10000) return crc32_buf_8(buf, seed);
|
||||
var C = seed ^ -1, L = buf.length - 3;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_buf_8(buf, seed) {
|
||||
var C = seed ^ -1, L = buf.length - 7;
|
||||
for(var i = 0; i < L;) {
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
}
|
||||
while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
|
||||
return C ^ -1;
|
||||
}
|
||||
|
||||
function crc32_str(str, seed) {
|
||||
var C = seed ^ -1;
|
||||
for(var i = 0, L=str.length, c, d; i < L;) {
|
||||
c = str.charCodeAt(i++);
|
||||
if(c < 0x80) {
|
||||
C = (C>>>8) ^ T[(C ^ c)&0xFF];
|
||||
} else if(c < 0x800) {
|
||||
C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
} else if(c >= 0xD800 && c < 0xE000) {
|
||||
c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
|
||||
C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
|
||||
} else {
|
||||
C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
|
||||
C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
|
||||
}
|
||||
}
|
||||
return C ^ -1;
|
||||
}
|
||||
CRC32.table = T;
|
||||
CRC32.bstr = crc32_bstr;
|
||||
CRC32.buf = crc32_buf;
|
||||
CRC32.str = crc32_str;
|
||||
}));
|
||||
/* [MS-CFB] v20171201 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports = {};
|
||||
exports.version = '1.0.8';
|
||||
exports.version = '1.1.0';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l, r) {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -29,9 +130,75 @@ function filename(p) {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
/* -------------------------------------------------------------------------- */
|
||||
/* DOS Date format:
|
||||
high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
|
||||
add 1980 to stored year
|
||||
stored second should be doubled
|
||||
*/
|
||||
|
||||
/* write JS date to buf as a DOS date */
|
||||
function write_dos_date(buf, date) {
|
||||
if(typeof date === "string") date = new Date(date);
|
||||
var hms = date.getHours();
|
||||
hms = hms << 6 | date.getMinutes();
|
||||
hms = hms << 5 | (date.getSeconds()>>>1);
|
||||
buf.write_shift(2, hms);
|
||||
var ymd = (date.getFullYear() - 1980);
|
||||
ymd = ymd << 4 | (date.getMonth()+1);
|
||||
ymd = ymd << 5 | date.getDate();
|
||||
buf.write_shift(2, ymd);
|
||||
}
|
||||
|
||||
/* read four bytes from buf and interpret as a DOS date */
|
||||
function parse_dos_date(buf) {
|
||||
var hms = buf.read_shift(2) & 0xFFFF;
|
||||
var ymd = buf.read_shift(2) & 0xFFFF;
|
||||
var val = new Date();
|
||||
var d = ymd & 0x1F; ymd >>>= 5;
|
||||
var m = ymd & 0x0F; ymd >>>= 4;
|
||||
val.setMilliseconds(0);
|
||||
val.setFullYear(ymd + 1980);
|
||||
val.setMonth(m-1);
|
||||
val.setDate(d);
|
||||
var S = hms & 0x1F; hms >>>= 5;
|
||||
var M = hms & 0x3F; hms >>>= 6;
|
||||
val.setHours(hms);
|
||||
val.setMinutes(M);
|
||||
val.setSeconds(S<<1);
|
||||
return val;
|
||||
}
|
||||
function parse_extra_field(blob) {
|
||||
prep_blob(blob, 0);
|
||||
var o = {};
|
||||
var flags = 0;
|
||||
while(blob.l <= blob.length - 4) {
|
||||
var type = blob.read_shift(2);
|
||||
var sz = blob.read_shift(2), tgt = blob.l + sz;
|
||||
var p = {};
|
||||
switch(type) {
|
||||
/* UNIX-style Timestamps */
|
||||
case 0x5455: {
|
||||
flags = blob.read_shift(1);
|
||||
if(flags & 1) p.mtime = blob.read_shift(4);
|
||||
/* for some reason, CD flag corresponds to LFH */
|
||||
if(sz > 5) {
|
||||
if(flags & 2) p.atime = blob.read_shift(4);
|
||||
if(flags & 4) p.ctime = blob.read_shift(4);
|
||||
}
|
||||
if(p.mtime) p.mt = new Date(p.mtime*1000);
|
||||
}
|
||||
break;
|
||||
}
|
||||
blob.l = tgt;
|
||||
o[type] = p;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file, options) {
|
||||
if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
|
||||
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -52,6 +219,8 @@ var mv = check_get_mver(blob);
|
||||
mver = mv[0];
|
||||
switch(mver) {
|
||||
case 3: ssz = 512; break; case 4: ssz = 4096; break;
|
||||
case 0: if(mv[1] == 0) return parse_zip(file, options);
|
||||
/* falls through */
|
||||
default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
|
||||
}
|
||||
|
||||
@ -130,6 +299,7 @@ return o;
|
||||
|
||||
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
|
||||
function check_get_mver(blob) {
|
||||
if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
|
||||
// header signature 8
|
||||
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
|
||||
|
||||
@ -447,6 +617,7 @@ function rebuild_cfb(cfb, f) {
|
||||
function _write(cfb, options) {
|
||||
var _opts = options || {};
|
||||
rebuild_cfb(cfb);
|
||||
if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
|
||||
var L = (function(cfb){
|
||||
var mini_size = 0, fat_size = 0;
|
||||
for(var i = 0; i < cfb.FileIndex.length; ++i) {
|
||||
@ -641,6 +812,551 @@ function write(cfb, options) {
|
||||
}
|
||||
return o;
|
||||
}
|
||||
/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
|
||||
var _zlib;
|
||||
function use_zlib(zlib) { try {
|
||||
var InflateRaw = zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
|
||||
if(InflRaw.bytesRead) _zlib = zlib;
|
||||
else throw new Error("zlib does not expose bytesRead");
|
||||
} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
|
||||
|
||||
function _inflateRawSync(payload, usz) {
|
||||
if(!_zlib) return _inflate(payload, usz);
|
||||
var InflateRaw = _zlib.InflateRaw;
|
||||
var InflRaw = new InflateRaw();
|
||||
var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
|
||||
payload.l += InflRaw.bytesRead;
|
||||
return out;
|
||||
}
|
||||
|
||||
function _deflateRawSync(payload) {
|
||||
return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
|
||||
}
|
||||
var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
|
||||
|
||||
/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
|
||||
var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
|
||||
|
||||
/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
|
||||
var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
|
||||
|
||||
function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
|
||||
|
||||
var use_typed_arrays = typeof Uint8Array !== 'undefined';
|
||||
|
||||
var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
|
||||
for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
|
||||
|
||||
function bit_swap_n(n, b) {
|
||||
var rev = bitswap8[n & 0xFF];
|
||||
if(b <= 8) return rev >>> (8-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
|
||||
if(b <= 16) return rev >>> (16-b);
|
||||
rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
|
||||
return rev >>> (24-b);
|
||||
}
|
||||
|
||||
/* helpers for unaligned bit reads */
|
||||
function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
|
||||
function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
|
||||
function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
|
||||
function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
|
||||
function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
|
||||
|
||||
/* works up to n = 3 * 8 + 1 = 25 */
|
||||
function read_bits_n(buf, bl, n) {
|
||||
var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
|
||||
var v = buf[h] >>> w;
|
||||
if(n < 8 - w) return v & f;
|
||||
v |= buf[h+1]<<(8-w);
|
||||
if(n < 16 - w) return v & f;
|
||||
v |= buf[h+2]<<(16-w);
|
||||
if(n < 24 - w) return v & f;
|
||||
v |= buf[h+3]<<(24-w);
|
||||
return v & f;
|
||||
}
|
||||
|
||||
/* 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;
|
||||
if(L >= sz) return b;
|
||||
if(has_buf) {
|
||||
var o = new_unsafe_buf(M);
|
||||
// $FlowIgnore
|
||||
if(b.copy) b.copy(o);
|
||||
else for(; i < b.length; ++i) o[i] = b[i];
|
||||
return o;
|
||||
} 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];
|
||||
return a;
|
||||
}
|
||||
b.length = M;
|
||||
return b;
|
||||
}
|
||||
|
||||
/* zero-filled arrays for older browsers */
|
||||
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) {
|
||||
var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
|
||||
|
||||
var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
for(i = 0; i < 32; ++i) bl_count[i] = 0;
|
||||
|
||||
for(i = L; i < MAX; ++i) clens[i] = 0;
|
||||
L = clens.length;
|
||||
|
||||
var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
|
||||
|
||||
/* build code tree */
|
||||
for(i = 0; i < L; ++i) {
|
||||
bl_count[(w = clens[i])]++;
|
||||
if(maxlen < w) maxlen = w;
|
||||
ctree[i] = 0;
|
||||
}
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
|
||||
for(i = 0; i < L; ++i) {
|
||||
ccode = clens[i];
|
||||
if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
|
||||
}
|
||||
|
||||
/* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
|
||||
for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
|
||||
cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
|
||||
}
|
||||
}
|
||||
return maxlen;
|
||||
}
|
||||
|
||||
var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
|
||||
var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
|
||||
if(!use_typed_arrays) {
|
||||
for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
|
||||
for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
|
||||
}
|
||||
(function() {
|
||||
var dlens = [];
|
||||
var i = 0;
|
||||
for(;i<32; i++) dlens.push(5);
|
||||
build_tree(dlens, fix_dmap, 32);
|
||||
|
||||
var clens = [];
|
||||
i = 0;
|
||||
for(; i<=143; i++) clens.push(8);
|
||||
for(; i<=255; i++) clens.push(9);
|
||||
for(; i<=279; i++) clens.push(7);
|
||||
for(; i<=287; i++) clens.push(8);
|
||||
build_tree(clens, fix_lmap, 288);
|
||||
})();
|
||||
|
||||
var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
|
||||
var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
|
||||
var dyn_len_1 = 1, dyn_len_2 = 1;
|
||||
|
||||
/* 5.5.3 Expanding Huffman Codes */
|
||||
function dyn(data, boff) {
|
||||
/* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
|
||||
var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
|
||||
var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
|
||||
var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
|
||||
var w = 0;
|
||||
|
||||
/* grab and store code lengths */
|
||||
var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
|
||||
var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
|
||||
var maxlen = 1;
|
||||
var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
|
||||
var L = clens.length; /* 19 */
|
||||
for(var i = 0; i < _HCLEN; ++i) {
|
||||
clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
|
||||
if(maxlen < w) maxlen = w;
|
||||
bl_count[w]++;
|
||||
boff += 3;
|
||||
}
|
||||
|
||||
/* build code tree */
|
||||
var ccode = 0;
|
||||
bl_count[0] = 0;
|
||||
for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
|
||||
for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
|
||||
/* cmap[7 bits from stream] = (off&7) + (lit<<3) */
|
||||
var cleni = 0;
|
||||
for(i = 0; i < L; ++i) {
|
||||
cleni = clens[i];
|
||||
if(cleni != 0) {
|
||||
ccode = bitswap8[ctree[i]]>>(8-cleni);
|
||||
for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
|
||||
}
|
||||
}
|
||||
|
||||
/* read literal and dist codes at once */
|
||||
var hcodes = [];
|
||||
maxlen = 1;
|
||||
for(; hcodes.length < _HLIT + _HDIST;) {
|
||||
ccode = dyn_cmap[read_bits_7(data, boff)];
|
||||
boff += ccode & 7;
|
||||
switch((ccode >>>= 3)) {
|
||||
case 16:
|
||||
w = 3 + read_bits_2(data, boff); boff += 2;
|
||||
ccode = hcodes[hcodes.length - 1];
|
||||
while(w-- > 0) hcodes.push(ccode);
|
||||
break;
|
||||
case 17:
|
||||
w = 3 + read_bits_3(data, boff); boff += 3;
|
||||
while(w-- > 0) hcodes.push(0);
|
||||
break;
|
||||
case 18:
|
||||
w = 11 + read_bits_7(data, boff); boff += 7;
|
||||
while(w -- > 0) hcodes.push(0);
|
||||
break;
|
||||
default:
|
||||
hcodes.push(ccode);
|
||||
if(maxlen < ccode) maxlen = ccode;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* build literal / length trees */
|
||||
var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
|
||||
for(i = _HLIT; i < 286; ++i) h1[i] = 0;
|
||||
for(i = _HDIST; i < 30; ++i) h2[i] = 0;
|
||||
dyn_len_1 = build_tree(h1, dyn_lmap, 286);
|
||||
dyn_len_2 = build_tree(h2, dyn_dmap, 30);
|
||||
return boff;
|
||||
}
|
||||
|
||||
/* return [ data, bytesRead ] */
|
||||
function inflate(data, usz) {
|
||||
/* shortcircuit for empty buffer [0x03, 0x00] */
|
||||
if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
|
||||
|
||||
/* bit offset */
|
||||
var boff = 0;
|
||||
|
||||
/* header includes final bit and type bits */
|
||||
var header = 0;
|
||||
|
||||
var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
|
||||
var woff = 0;
|
||||
var OL = outbuf.length>>>0;
|
||||
var max_len_1 = 0, max_len_2 = 0;
|
||||
|
||||
while((header&1) == 0) {
|
||||
header = read_bits_3(data, boff); boff += 3;
|
||||
if((header >>> 1) == 0) {
|
||||
/* Stored block */
|
||||
if(boff & 7) boff += 8 - (boff&7);
|
||||
/* 2 bytes sz, 2 bytes bit inverse */
|
||||
var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
|
||||
boff += 32;
|
||||
/* push sz bytes */
|
||||
if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
|
||||
if(typeof data.copy === 'function') {
|
||||
// $FlowIgnore
|
||||
data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
|
||||
woff += sz; boff += 8*sz;
|
||||
} else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
|
||||
continue;
|
||||
} else if((header >>> 1) == 1) {
|
||||
/* Fixed Huffman */
|
||||
max_len_1 = 9; max_len_2 = 5;
|
||||
} else {
|
||||
/* Dynamic Huffman */
|
||||
boff = dyn(data, boff);
|
||||
max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
|
||||
}
|
||||
if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
|
||||
for(;;) { // while(true) is apparently out of vogue in modern JS circles
|
||||
/* ingest code and move read head */
|
||||
var bits = read_bits_n(data, boff, max_len_1);
|
||||
var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
/* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
|
||||
if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
|
||||
else if(code == 256) break;
|
||||
else {
|
||||
code -= 257;
|
||||
var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
|
||||
var tgt = woff + LEN_LN[code];
|
||||
/* length extra bits */
|
||||
if(len_eb > 0) {
|
||||
tgt += read_bits_n(data, boff, len_eb);
|
||||
boff += len_eb;
|
||||
}
|
||||
|
||||
/* dist code */
|
||||
bits = read_bits_n(data, boff, max_len_2);
|
||||
code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
|
||||
boff += code & 15; code >>>= 4;
|
||||
var dst_eb = (code < 4 ? 0 : (code-2)>>1);
|
||||
var dst = DST_LN[code];
|
||||
/* dist extra bits */
|
||||
if(dst_eb > 0) {
|
||||
dst += read_bits_n(data, boff, dst_eb);
|
||||
boff += dst_eb;
|
||||
}
|
||||
|
||||
/* in the common case, manual byte copy is faster than TA set / Buffer copy */
|
||||
if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
|
||||
while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
|
||||
}
|
||||
}
|
||||
}
|
||||
return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
|
||||
}
|
||||
|
||||
function _inflate(payload, usz) {
|
||||
var data = payload.slice(payload.l||0);
|
||||
var out = inflate(data, usz);
|
||||
payload.l += out[1];
|
||||
return out[0];
|
||||
}
|
||||
|
||||
function warn_or_throw(wrn, msg) {
|
||||
if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
|
||||
else throw new Error(msg);
|
||||
}
|
||||
|
||||
function parse_zip(file, options) {
|
||||
var blob = file;
|
||||
prep_blob(blob, 0);
|
||||
|
||||
var FileIndex = [], FullPaths = [];
|
||||
var o = {
|
||||
FileIndex: FileIndex,
|
||||
FullPaths: FullPaths
|
||||
};
|
||||
init_cfb(o, { root: options.root });
|
||||
|
||||
/* find end of central directory, start just after signature */
|
||||
var i = blob.length - 4;
|
||||
while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
|
||||
blob.l = i + 4;
|
||||
|
||||
/* parse end of central directory */
|
||||
blob.l += 4;
|
||||
var fcnt = blob.read_shift(2);
|
||||
blob.l += 6;
|
||||
var start_cd = blob.read_shift(4);
|
||||
|
||||
/* parse central directory */
|
||||
blob.l = start_cd;
|
||||
|
||||
for(i = 0; i < fcnt; ++i) {
|
||||
/* trust local file header instead of CD entry */
|
||||
blob.l += 20;
|
||||
var csz = blob.read_shift(4);
|
||||
var usz = blob.read_shift(4);
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
var fcsz = blob.read_shift(2);
|
||||
blob.l += 8;
|
||||
var offset = blob.read_shift(4);
|
||||
var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
|
||||
blob.l += namelen + efsz + fcsz;
|
||||
|
||||
var L = blob.l;
|
||||
blob.l = offset + 4;
|
||||
parse_local_file(blob, csz, usz, o, EF);
|
||||
blob.l = L;
|
||||
}
|
||||
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* head starts just after local file header signature */
|
||||
function parse_local_file(blob, csz, usz, o, EF) {
|
||||
/* [local file header] */
|
||||
blob.l += 2;
|
||||
var flags = blob.read_shift(2);
|
||||
var meth = blob.read_shift(2);
|
||||
var date = parse_dos_date(blob);
|
||||
|
||||
if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
|
||||
var crc32 = blob.read_shift(4);
|
||||
var _csz = blob.read_shift(4);
|
||||
var _usz = blob.read_shift(4);
|
||||
|
||||
var namelen = blob.read_shift(2);
|
||||
var efsz = blob.read_shift(2);
|
||||
|
||||
// TODO: flags & (1<<11) // UTF8
|
||||
var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
|
||||
if(efsz) {
|
||||
var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
|
||||
if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
|
||||
if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
|
||||
}
|
||||
blob.l += efsz;
|
||||
|
||||
/* [encryption header] */
|
||||
|
||||
/* [file data] */
|
||||
var data = blob.slice(blob.l, blob.l + _csz);
|
||||
switch(meth) {
|
||||
case 8: data = _inflateRawSync(blob, _usz); break;
|
||||
case 0: break;
|
||||
default: throw new Error("Unsupported ZIP Compression method " + meth);
|
||||
}
|
||||
|
||||
/* [data descriptor] */
|
||||
var wrn = false;
|
||||
if(flags & 8) {
|
||||
crc32 = blob.read_shift(4);
|
||||
if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
|
||||
_csz = blob.read_shift(4);
|
||||
_usz = blob.read_shift(4);
|
||||
}
|
||||
|
||||
if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
|
||||
if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
|
||||
var _crc32 = CRC32.buf(data, 0);
|
||||
if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
|
||||
cfb_add(o, name, data, {unsafe: true, mt: date});
|
||||
}
|
||||
function write_zip(cfb, options) {
|
||||
var _opts = options || {};
|
||||
var out = [], cdirs = [];
|
||||
var o = new_buf(1);
|
||||
var method = (_opts.compression ? 8 : 0), flags = 0;
|
||||
var desc = false;
|
||||
if(desc) flags |= 8;
|
||||
var i = 0, j = 0;
|
||||
|
||||
var start_cd = 0, fcnt = 0;
|
||||
var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
|
||||
var crcs = [];
|
||||
var sz_cd = 0;
|
||||
|
||||
for(i = 1; i < cfb.FullPaths.length; ++i) {
|
||||
fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
|
||||
if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
|
||||
var start = start_cd;
|
||||
|
||||
/* TODO: CP437 filename */
|
||||
var namebuf = new_buf(fp.length);
|
||||
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
|
||||
namebuf = namebuf.slice(0, namebuf.l);
|
||||
crcs[fcnt] = CRC32.buf(fi.content, 0);
|
||||
|
||||
var outbuf = fi.content;
|
||||
if(method == 8) outbuf = _deflateRawSync(outbuf);
|
||||
|
||||
/* local file header */
|
||||
o = new_buf(30);
|
||||
o.write_shift(4, 0x04034b50);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
/* TODO: last mod file time/date */
|
||||
if(fi.mt) write_dos_date(o, fi.mt);
|
||||
else o.write_shift(4, 0);
|
||||
o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
|
||||
o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
|
||||
o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
start_cd += o.length;
|
||||
out.push(o);
|
||||
start_cd += namebuf.length;
|
||||
out.push(namebuf);
|
||||
|
||||
/* TODO: encryption header ? */
|
||||
start_cd += outbuf.length;
|
||||
out.push(outbuf);
|
||||
|
||||
/* data descriptor */
|
||||
if(flags & 8) {
|
||||
o = new_buf(12);
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, fi.content.length);
|
||||
start_cd += o.l;
|
||||
out.push(o);
|
||||
}
|
||||
|
||||
/* central directory */
|
||||
o = new_buf(46);
|
||||
o.write_shift(4, 0x02014b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 20);
|
||||
o.write_shift(2, flags);
|
||||
o.write_shift(2, method);
|
||||
o.write_shift(4, 0); /* TODO: last mod file time/date */
|
||||
o.write_shift(-4, crcs[fcnt]);
|
||||
|
||||
o.write_shift(4, outbuf.length);
|
||||
o.write_shift(4, fi.content.length);
|
||||
o.write_shift(2, namebuf.length);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, start);
|
||||
|
||||
sz_cd += o.l;
|
||||
cdirs.push(o);
|
||||
sz_cd += namebuf.length;
|
||||
cdirs.push(namebuf);
|
||||
++fcnt;
|
||||
}
|
||||
|
||||
/* end of central directory */
|
||||
o = new_buf(22);
|
||||
o.write_shift(4, 0x06054b50);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(2, fcnt);
|
||||
o.write_shift(4, sz_cd);
|
||||
o.write_shift(4, start_cd);
|
||||
o.write_shift(2, 0);
|
||||
|
||||
return bconcat(([bconcat((out)), bconcat(cdirs), o]));
|
||||
}
|
||||
function cfb_new(opts) {
|
||||
var o = ({});
|
||||
init_cfb(o, opts);
|
||||
@ -667,6 +1383,8 @@ file.content = (content);
|
||||
file.size = content ? content.length : 0;
|
||||
if(opts) {
|
||||
if(opts.CLSID) file.clsid = opts.CLSID;
|
||||
if(opts.mt) file.mt = opts.mt;
|
||||
if(opts.ct) file.ct = opts.ct;
|
||||
}
|
||||
return file;
|
||||
}
|
||||
@ -710,6 +1428,9 @@ exports.utils = {
|
||||
CheckField: CheckField,
|
||||
prep_blob: prep_blob,
|
||||
bconcat: bconcat,
|
||||
use_zlib: use_zlib,
|
||||
_deflateRaw: _deflate,
|
||||
_inflateRaw: _inflate,
|
||||
consts: consts
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user