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. | ||||
| 
 | ||||
| [](https://travis-ci.org/SheetJS/js-cfb) | ||||
| [](https://coveralls.io/r/SheetJS/js-cfb?branch=master) | ||||
| [](https://david-dm.org/sheetjs/js-cfb) | ||||
| [](https://npmjs.org/package/cfb) | ||||
| [](https://ghit.me/repo/sheetjs/js-xlsx) | ||||
| [](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