version bump 0.13.2
- file writing includes `fs` as appropriate - CLI modify and write options - infrastructure update
This commit is contained in:
parent
e6d1c8b06e
commit
9e22a4425e
@ -3,7 +3,6 @@
|
||||
.*/dist/.*
|
||||
.*/test_files/.*
|
||||
.*/test_files_pres/.*
|
||||
.*/test.js
|
||||
|
||||
.*/bits/.*
|
||||
.*/ctest/.*
|
||||
@ -23,6 +22,7 @@
|
||||
cfb.flow.js
|
||||
xlscfb.flow.js
|
||||
.*/bin/.*.njs
|
||||
test.js
|
||||
|
||||
[libs]
|
||||
bits/10_types.js
|
||||
|
16
.spelling
Normal file
16
.spelling
Normal file
@ -0,0 +1,16 @@
|
||||
# cfb.js (C) 2013-present SheetJS -- http://sheetjs.com
|
||||
SheetJS
|
||||
js-xlsx
|
||||
|
||||
# CFB-related terms
|
||||
CFB
|
||||
storages
|
||||
|
||||
# Third-party
|
||||
NPM
|
||||
nodejs
|
||||
npm
|
||||
|
||||
# Other terms
|
||||
Base64
|
||||
metadata
|
18
Makefile
18
Makefile
@ -66,6 +66,11 @@ XLSDEPS=misc/suppress_export.js $(filter-out $(XLSSKIP),$(DEPS))
|
||||
xlscfb.flow.js: $(XLSDEPS) ## Build support library
|
||||
cat $^ | tr -d '\15\32' > $@
|
||||
|
||||
BYTEFILE=dist/cfb.min.js dist/xlscfb.js
|
||||
.PHONY: bytes
|
||||
bytes: ## Display minified and gzipped file sizes
|
||||
for i in $(BYTEFILE); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
|
||||
|
||||
|
||||
## Testing
|
||||
|
||||
@ -74,6 +79,7 @@ test mocha: test.js $(TARGET) ## Run test suite
|
||||
mocha -R spec -t 20000
|
||||
|
||||
#* To run tests for one format, make test_<fmt>
|
||||
#* To run the core test suite, make test_misc
|
||||
TESTFMT=$(patsubst %,test_%,$(FMT))
|
||||
.PHONY: $(TESTFMT)
|
||||
$(TESTFMT): test_%:
|
||||
@ -82,6 +88,9 @@ $(TESTFMT): test_%:
|
||||
|
||||
## Code Checking
|
||||
|
||||
.PHONY: fullint
|
||||
fullint: lint old-lint tslint flow mdlint ## Run all checks
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(TARGET) $(AUXTARGETS) ## Run eslint checks
|
||||
@eslint --ext .js,.njs,.json,.html,.htm $(TARGET) $(AUXTARGETS) $(CMDS) $(HTMLLINT) package.json
|
||||
@ -91,9 +100,9 @@ lint: $(TARGET) $(AUXTARGETS) ## Run eslint checks
|
||||
old-lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
|
||||
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
@jshint --show-non-errors $(CMDS)
|
||||
@jshint --show-non-errors package.json
|
||||
@jshint --show-non-errors package.json test.js
|
||||
@jshint --show-non-errors --extract=always $(HTMLLINT)
|
||||
@jscs $(TARGET) $(AUXTARGETS)
|
||||
@jscs $(TARGET) $(AUXTARGETS) test.js
|
||||
if [ -e $(CLOSURE) ]; then java -jar $(CLOSURE) $(REQS) $(FLOWTARGET) --jscomp_warning=reportUnknownTypes >/dev/null; fi
|
||||
|
||||
.PHONY: tslint
|
||||
@ -115,6 +124,11 @@ misc/coverage.html: $(TARGET) test.js
|
||||
coveralls: ## Coverage Test + Send to coveralls.io
|
||||
mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js
|
||||
|
||||
MDLINT=README.md
|
||||
.PHONY: mdlint
|
||||
mdlint: $(MDLINT) ## Check markdown documents
|
||||
alex $^
|
||||
mdspell -a -n -x -r --en-us $^
|
||||
|
||||
.PHONY: help
|
||||
help:
|
||||
|
58
README.md
58
README.md
@ -1,6 +1,6 @@
|
||||
# Compound File Binary Format
|
||||
|
||||
Pure-JS implementation of MS-CFB: Compound File Binary File Format, a container
|
||||
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)
|
||||
|
||||
[![Build Status](https://travis-ci.org/SheetJS/js-cfb.svg?branch=master)](https://travis-ci.org/SheetJS/js-cfb)
|
||||
@ -35,7 +35,7 @@ In node:
|
||||
var CFB = require('cfb');
|
||||
```
|
||||
|
||||
For example, to get the Workbook content from an XLS file:
|
||||
For example, to get the Workbook content from an Excel 2003 XLS file:
|
||||
|
||||
```js
|
||||
var cfb = CFB.read(filename, {type: 'file'});
|
||||
@ -52,15 +52,23 @@ It is preferable to install the library globally with npm:
|
||||
$ npm install -g cfb
|
||||
```
|
||||
|
||||
The global installation adds a command `cfb` which can work with existing files:
|
||||
The global installation adds a command `cfb` which can work with files:
|
||||
|
||||
- `cfb file` will extract the contents of the file to the current directory.
|
||||
It will make the corresponding subdirectories.
|
||||
- `cfb --list-files file` will show a listing of the contained files.
|
||||
The format follows the `unzip -l` "short format".
|
||||
- `cfb --repair file` will attempt to repair by reading and re-writing the file.
|
||||
- `cfb file [names...]` extracts the contents of the file. If additional names
|
||||
are supplied, only the listed files will be extracted.
|
||||
|
||||
- `cfb -l file` lists the contained files (following `unzip -l` "short format")
|
||||
|
||||
- `cfb -r file` attempts to repair by reading and re-writing the file.
|
||||
This fixes some issues with files generated by non-standard tools.
|
||||
|
||||
- `cfb -c file [files...]` creates a new file containing the listed files.
|
||||
The default root entry name is `Root Entry`.
|
||||
|
||||
- `cfb -a file [files...]` adds the listed files to the original file.
|
||||
|
||||
- `cfb -d file [files...]` deletes the listed files from the original file.
|
||||
|
||||
|
||||
## JS API
|
||||
|
||||
@ -73,10 +81,12 @@ parsed representation of the data.
|
||||
|
||||
`CFB.read(blob, opts)` wraps `parse`. `opts.type` controls the behavior:
|
||||
|
||||
- `file`: `blob` is interpreted as a file name that will be read
|
||||
- `base64`: `blob` is interpreted as base64 string
|
||||
- `binary`: `blob` is interpreted as binary string
|
||||
- default: `blob` is interpreted as nodejs buffer or array of bytes
|
||||
| `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.
|
||||
@ -84,9 +94,11 @@ 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:
|
||||
|
||||
- `base64`: returns a base64 string
|
||||
- `binary`: returns a binary string
|
||||
- default: returns a nodejs buffer or array of bytes
|
||||
| `type` | output |
|
||||
|------------|-----------------------------------------------------------------|
|
||||
| `"base64"` | string: Base64 encoding of the file |
|
||||
| `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) |
|
||||
| (default) | buffer if available, array of 8-bit unsigned int otherwise |
|
||||
|
||||
`CFB.writeFile(cfb, filename, opts)` creates a file with the specified name.
|
||||
|
||||
@ -110,19 +122,8 @@ The objects returned by `parse` and `read` have the following properties:
|
||||
storages (directories) in the container. The paths are properly prefixed from
|
||||
the root entry (so the entries are unique)
|
||||
|
||||
- `.FullPathDir` is an object whose keys are entries in `.FullPaths` and whose
|
||||
values are objects with metadata and content (described below)
|
||||
|
||||
- `.FileIndex` is an array of the objects from `.FullPathDir`, in the same order
|
||||
as `.FullPaths`.
|
||||
|
||||
- `.raw` contains the raw header and sectors
|
||||
|
||||
|
||||
## Entry Object Description
|
||||
|
||||
The entry objects are available from `FullPathDir` and `FileIndex` elements of
|
||||
the container object:
|
||||
- `.FileIndex` is an array, in the same order as `.FullPaths`, whose values are
|
||||
objects following the schema:
|
||||
|
||||
```typescript
|
||||
interface CFBEntry {
|
||||
@ -151,4 +152,3 @@ granted by the Apache 2.0 License are reserved by the Original Author.
|
||||
|
||||
</details>
|
||||
|
||||
|
||||
|
106
bin/cfb.njs
106
bin/cfb.njs
@ -2,57 +2,67 @@
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
var n = "cfb";
|
||||
var X = require('../');
|
||||
var fs = require('fs');
|
||||
var program = require('commander');
|
||||
var PRINTJ = require("printj");
|
||||
var sprintf = PRINTJ.sprintf;
|
||||
program
|
||||
.version(X.version)
|
||||
.usage('[options] <file>')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.usage('[options] <file> [subfiles...]')
|
||||
.option('-l, --list-files', 'list files')
|
||||
.option('-d, --dump', 'dump internal representation but do not extract')
|
||||
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
|
||||
.option('-c, --create', 'create file')
|
||||
.option('-a, --append', 'add files to CFB (overwrite existing data)')
|
||||
.option('-d, --delete', 'delete files from CFB')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents');
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
if(program.args.length === 0 || !fs.existsSync(program.args[0])) {
|
||||
console.error("Usage: " + process.argv[1] + " [-q] <cfb_file>");
|
||||
process.exit(1);
|
||||
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)); };
|
||||
|
||||
if(program.args.length === 0) die(1, "must specify a filename");
|
||||
|
||||
if(program.create) {
|
||||
logit("create", program.args[0]);
|
||||
var newcfb = X.utils.cfb_new();
|
||||
X.writeFile(newcfb, program.args[0]);
|
||||
}
|
||||
|
||||
if(!fs.existsSync(program.args[0])) die(1, "must specify a filename");
|
||||
|
||||
var opts = ({type:'file'}/*:any*/);
|
||||
if(program.dev) opts.WTF = true;
|
||||
|
||||
var cfb = X.read(program.args[0], opts);
|
||||
if(program.quiet) process.exit(0);
|
||||
if(program.quiet) exit(0);
|
||||
|
||||
if(program.dump) {
|
||||
console.log("Full Paths:");
|
||||
console.log(cfb.FullPaths.map(function(x) { return " " + x; }).join("\n"));
|
||||
console.log("Full Path Directory:");
|
||||
console.log(cfb.FullPathDir);
|
||||
process.exit(0);
|
||||
}
|
||||
if(program.repair) {
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
process.exit(0);
|
||||
console.log(cfb.FullPaths.map(function(x/*:string*/) { return " " + x; }).join("\n"));
|
||||
console.log("File Index:");
|
||||
console.log(cfb.FileIndex);
|
||||
exit(0);
|
||||
}
|
||||
if(program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
|
||||
|
||||
var sprintf = PRINTJ.sprintf;
|
||||
function fix_string(x/*:string*/)/*:string*/ { return x.replace(/[\u0000-\u001f]/, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
|
||||
if(program.listFiles) {
|
||||
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*/)/*:string*/ {
|
||||
return sprintf("%02u-%02u-%02u %02u:%02u", date.getUTCMonth()+1, date.getUTCDate(), date.getUTCFullYear()%100, date.getUTCHours(), date.getUTCMinutes());
|
||||
};
|
||||
|
||||
if(program.listFiles) {
|
||||
var basetime = new Date(1980,0,1);
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
cfb.FileIndex.forEach(function(file, i/*:number*/) {
|
||||
cfb.FileIndex.forEach(function(file/*:CFBEntry*/, i/*:number*/) {
|
||||
switch(file.type) {
|
||||
case 5:
|
||||
basetime = file.ct || file.mt || basetime;
|
||||
@ -67,14 +77,52 @@ if(program.listFiles) {
|
||||
console.log(" -------- -------");
|
||||
console.log(sprintf("%9lu %lu file%s", rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
|
||||
|
||||
process.exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
function mkdirp(path/*:string*/) { path.split("/").reduce(function(acc/*:string*/, p/*:string*/) {
|
||||
acc += p + "/";
|
||||
if(!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); }
|
||||
return acc;
|
||||
}, ""); }
|
||||
|
||||
function write(path/*:string*/, data/*:CFBEntry*/) {
|
||||
logit("write", fix_string(path));
|
||||
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/);
|
||||
}
|
||||
|
||||
if(program.create || program.append) {
|
||||
program.args.slice(1).forEach(function(x/*:string*/) {
|
||||
logit("append", x);
|
||||
X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x));
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.delete) {
|
||||
program.args.slice(1).forEach(function(x/*:string*/) {
|
||||
logit("delete", x);
|
||||
X.utils.cfb_del(cfb, "/" + x);
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.args.length > 1) {
|
||||
program.args.slice(1).forEach(function(x/*:string*/) {
|
||||
var data/*:?CFBEntry*/ = X.find(cfb, x);
|
||||
if(!data) { console.error(x + ": file not found"); return; }
|
||||
if(data.type !== 2) { console.error(x + ": not a file"); return; }
|
||||
var idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
|
||||
mkdirp(path.slice(0, path.lastIndexOf("/")));
|
||||
write(path, data);
|
||||
});
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(var i=0; i!==cfb.FullPaths.length; ++i) {
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") {
|
||||
console.error("mkdir " + fix_string(cfb.FullPaths[i]));
|
||||
fs.mkdirSync(cfb.FullPaths[i]);
|
||||
} else {
|
||||
console.error("write " + fix_string(cfb.FullPaths[i]));
|
||||
fs.writeFileSync(cfb.FullPaths[i], /*::new Buffer((*/cfb.FileIndex[i].content/*:: :any))*/);
|
||||
}
|
||||
if(!cfb.FileIndex[i].name) continue;
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") mkdirp(cfb.FullPaths[i]);
|
||||
else write(cfb.FullPaths[i], cfb.FileIndex[i]);
|
||||
}
|
||||
|
@ -1 +1 @@
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
|
2
bits/39_fs.js
Normal file
2
bits/39_fs.js
Normal file
@ -0,0 +1,2 @@
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
@ -1,6 +1,5 @@
|
||||
var fs/*:: = require('fs'); */;
|
||||
function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,5 @@
|
||||
function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
/*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
|
||||
fs.writeFileSync(filename, o);
|
||||
@ -13,7 +14,7 @@ function a2s(o/*:RawBytes*/)/*:string*/ {
|
||||
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
|
@ -8,13 +8,13 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
init_cfb(cfb);
|
||||
var file = CFB.find(cfb, name);
|
||||
if(!file) {
|
||||
var fpath = cfb.FullPaths[0];
|
||||
var fpath/*:string*/ = cfb.FullPaths[0];
|
||||
if(name.slice(0, fpath.length) == fpath) fpath = name;
|
||||
else {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)}/*:any*/);
|
||||
file = ({name: filename(name), type: 2}/*:any*/);
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
14
cfb.flow.js
14
cfb.flow.js
@ -179,7 +179,7 @@ type CFBFiles = {[n:string]:CFBEntry};
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -200,6 +200,8 @@ function filename(p/*:string*/)/*:string*/ {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -497,9 +499,8 @@ function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ {
|
||||
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
|
||||
}
|
||||
|
||||
var fs/*:: = require('fs'); */;
|
||||
function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
@ -779,6 +780,7 @@ var consts = {
|
||||
};
|
||||
|
||||
function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
/*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
|
||||
fs.writeFileSync(filename, o);
|
||||
@ -793,7 +795,7 @@ function a2s(o/*:RawBytes*/)/*:string*/ {
|
||||
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
@ -809,13 +811,13 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
init_cfb(cfb);
|
||||
var file = CFB.find(cfb, name);
|
||||
if(!file) {
|
||||
var fpath = cfb.FullPaths[0];
|
||||
var fpath/*:string*/ = cfb.FullPaths[0];
|
||||
if(name.slice(0, fpath.length) == fpath) fpath = name;
|
||||
else {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)}/*:any*/);
|
||||
file = ({name: filename(name), type: 2}/*:any*/);
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
12
cfb.js
12
cfb.js
@ -161,7 +161,7 @@ function new_buf(sz) {
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports = {};
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l, r) {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -182,6 +182,8 @@ function filename(p) {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file, options) {
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -479,9 +481,8 @@ function read_date(blob, offset) {
|
||||
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
|
||||
}
|
||||
|
||||
var fs;
|
||||
function read_file(filename, options) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
@ -756,6 +757,7 @@ var consts = {
|
||||
};
|
||||
|
||||
function write_file(cfb, filename, options) {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
fs.writeFileSync(filename, o);
|
||||
}
|
||||
@ -769,7 +771,7 @@ function a2s(o) {
|
||||
function write(cfb, options) {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
@ -791,7 +793,7 @@ function cfb_add(cfb, name, content, opts) {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)});
|
||||
file = ({name: filename(name), type: 2});
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
12
dist/cfb.js
vendored
12
dist/cfb.js
vendored
@ -161,7 +161,7 @@ function new_buf(sz) {
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports = {};
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l, r) {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -182,6 +182,8 @@ function filename(p) {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file, options) {
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -479,9 +481,8 @@ function read_date(blob, offset) {
|
||||
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
|
||||
}
|
||||
|
||||
var fs;
|
||||
function read_file(filename, options) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
@ -756,6 +757,7 @@ var consts = {
|
||||
};
|
||||
|
||||
function write_file(cfb, filename, options) {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
fs.writeFileSync(filename, o);
|
||||
}
|
||||
@ -769,7 +771,7 @@ function a2s(o) {
|
||||
function write(cfb, options) {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
@ -791,7 +793,7 @@ function cfb_add(cfb, name, content, opts) {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)});
|
||||
file = ({name: filename(name), type: 2});
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
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
14
dist/xlscfb.js
vendored
14
dist/xlscfb.js
vendored
@ -38,7 +38,7 @@ type CFBFiles = {[n:string]:CFBEntry};
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -59,6 +59,8 @@ function filename(p/*:string*/)/*:string*/ {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -356,9 +358,8 @@ function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ {
|
||||
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
|
||||
}
|
||||
|
||||
var fs/*:: = require('fs'); */;
|
||||
function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
@ -638,6 +639,7 @@ var consts = {
|
||||
};
|
||||
|
||||
function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
/*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
|
||||
fs.writeFileSync(filename, o);
|
||||
@ -652,7 +654,7 @@ function a2s(o/*:RawBytes*/)/*:string*/ {
|
||||
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
@ -668,13 +670,13 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
init_cfb(cfb);
|
||||
var file = CFB.find(cfb, name);
|
||||
if(!file) {
|
||||
var fpath = cfb.FullPaths[0];
|
||||
var fpath/*:string*/ = cfb.FullPaths[0];
|
||||
if(name.slice(0, fpath.length) == fpath) fpath = name;
|
||||
else {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)}/*:any*/);
|
||||
file = ({name: filename(name), type: 2}/*:any*/);
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
25
index.html
25
index.html
@ -32,7 +32,7 @@ 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 loaded data</a>
|
||||
<a id="saveit" onclick="savefile();" href="#">Export data</a>
|
||||
</pre>
|
||||
<pre id="out"></pre>
|
||||
<br />
|
||||
@ -61,14 +61,14 @@ var get_manifest = (function() {
|
||||
var cnt = 0, rootsize = 0, filesize = 0;
|
||||
out.push(" Length Date Time Name");
|
||||
out.push(" -------- ---- ---- ----");
|
||||
cfb.FileIndex.forEach(function(file, i/*:number*/) {
|
||||
cfb.FileIndex.forEach(function(file/*:CFBEntry*/, i/*:number*/) {
|
||||
switch(file.type) {
|
||||
case 5:
|
||||
basetime = file.ct || file.mt || basetime;
|
||||
rootsize = file.size;
|
||||
break;
|
||||
case 2:
|
||||
out.push(sprintf("%9lu %s %s", file.size, format_date(basetime), fix_string(cfb.FullPaths[i])));
|
||||
out.push(sprintf("%9lu %s <a href=\"#\" onclick=\"download_file(%d);\">%s</a>", file.size, format_date(basetime), i, fix_string(cfb.FullPaths[i])));
|
||||
filesize += file.size;
|
||||
++cnt;
|
||||
}
|
||||
@ -82,8 +82,7 @@ var get_manifest = (function() {
|
||||
function process_data(cfb) {
|
||||
global_cfb = cfb;
|
||||
var output = get_manifest(cfb);
|
||||
if(out.innerText === undefined) out.textContent = output;
|
||||
else out.innerText = output;
|
||||
out.innerHTML = output;
|
||||
}
|
||||
|
||||
var do_file = (function() {
|
||||
@ -156,6 +155,22 @@ var savefile = (function() {
|
||||
saveAs(new Blob([s2ab(data)],{type:"application/octet-stream"}), "sheetjs.xls");
|
||||
};
|
||||
})();
|
||||
|
||||
var download_file = (function() {
|
||||
var a2ab = function a2ab(a) {
|
||||
var o = new ArrayBuffer(a.length);
|
||||
var view = new Uint8Array(o);
|
||||
for (var i = 0; i!=a.length; ++i) view[i] = a[i];
|
||||
return o;
|
||||
};
|
||||
|
||||
return function download_file(i) {
|
||||
if(!global_cfb) return alert("Must load a file first!");
|
||||
console.log(global_cfb);
|
||||
var file = global_cfb.FileIndex[i], data = file.content;
|
||||
saveAs(new Blob([a2ab(data)],{type:"application/octet-stream"}), file.name);
|
||||
};
|
||||
})();
|
||||
</script>
|
||||
<script type="text/javascript">
|
||||
/* eslint no-use-before-define:0 */
|
||||
|
@ -67,7 +67,7 @@ type CFBlob = CFBlobArray | CFBlobBuffer | CFBlobUint8;
|
||||
type CFBWriteOpts = any;
|
||||
|
||||
interface CFBReadOpts {
|
||||
type:?string;
|
||||
type?:string;
|
||||
};
|
||||
|
||||
type CFBFileIndex = Array<CFBEntry>;
|
||||
|
@ -6,4 +6,5 @@ declare module './' { declare var exports:CFBModule; };
|
||||
|
||||
declare module 'commander' { declare var exports:any; };
|
||||
declare module 'printj' { declare var exports:any; };
|
||||
declare module 'crc-32' { declare var exports: any; };
|
||||
*/
|
||||
|
@ -1,5 +0,0 @@
|
||||
var describe = function(m,cb){if(cb) cb();};
|
||||
describe.skip = function(m,cb){};
|
||||
var it = function(m,cb){if(cb) cb();};
|
||||
it.skip = function(m,cb){};
|
||||
var before = function(cb){if(cb) cb();};
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "cfb",
|
||||
"version": "0.13.1",
|
||||
"version": "0.13.2",
|
||||
"author": "sheetjs",
|
||||
"description": "Compound File Binary File Format extractor",
|
||||
"keywords": [ "cfb", "compression", "office" ],
|
||||
|
15
test.js
15
test.js
@ -1,8 +1,18 @@
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint mocha:true */
|
||||
/*global process, require */
|
||||
/*::
|
||||
declare type EmptyFunc = (() => void) | null;
|
||||
declare type DescribeIt = { (desc:string, test:EmptyFunc):void; skip(desc:string, test:EmptyFunc):void; };
|
||||
declare var describe : DescribeIt;
|
||||
declare var it: DescribeIt;
|
||||
declare var before:(test:EmptyFunc)=>void;
|
||||
*/
|
||||
var CFB;
|
||||
var fs = require('fs');
|
||||
describe('source', function() { it('should load', function() { CFB = require('./'); }); });
|
||||
if(typeof CRC32 === 'undefined') CRC32 = require('crc-32');
|
||||
var CRC32 = require('crc-32');
|
||||
|
||||
var ex = [".xls",".doc",".ppt"];
|
||||
if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
|
||||
@ -71,6 +81,7 @@ function parsetest(x, cfb) {
|
||||
_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 be idempotent', function() {
|
||||
@ -107,7 +118,7 @@ describe('should parse test files', function() {
|
||||
});
|
||||
});
|
||||
|
||||
var cp = 'custom_properties.xls'
|
||||
var cp = 'custom_properties.xls';
|
||||
|
||||
describe('input formats', function() {
|
||||
it('should read binary strings', function() {
|
||||
|
104
types/bin_cfb.ts
104
types/bin_cfb.ts
@ -1,57 +1,67 @@
|
||||
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* eslint-env node */
|
||||
/* vim: set ts=2 ft=javascript: */
|
||||
const n = "cfb";
|
||||
import * as X from 'cfb';
|
||||
import fs = require('fs');
|
||||
import program = require('commander');
|
||||
import PRINTJ = require("printj");
|
||||
const sprintf = PRINTJ.sprintf;
|
||||
program
|
||||
.version(X.version)
|
||||
.usage('[options] <file>')
|
||||
.usage('[options] <file> [subfiles...]')
|
||||
.option('-q, --quiet', 'process but do not report')
|
||||
.option('-l, --list-files', 'list files')
|
||||
.option('-d, --dump', 'dump internal representation but do not extract')
|
||||
.option('-z, --dump', 'dump internal representation but do not extract')
|
||||
.option('-r, --repair', 'attempt to repair and garbage-collect archive')
|
||||
.option('-c, --create', 'create file')
|
||||
.option('-a, --append', 'add files to CFB (overwrite existing data)')
|
||||
.option('-d, --delete', 'delete files from CFB')
|
||||
.option('--dev', 'development mode')
|
||||
.option('--read', 'read but do not print out contents');
|
||||
|
||||
program.parse(process.argv);
|
||||
|
||||
if(program.args.length === 0 || !fs.existsSync(program.args[0])) {
|
||||
console.error("Usage: " + process.argv[1] + " [-q] <cfb_file>");
|
||||
process.exit(1);
|
||||
const exit = process.exit;
|
||||
const die = (errno: number, msg: string) => { console.error(n + ": " + msg); exit(errno); };
|
||||
const logit = (cmd: string, f: string) => { console.error(sprintf("%-6s %s", cmd, f)); };
|
||||
|
||||
if(program.args.length === 0) die(1, "must specify a filename");
|
||||
|
||||
if(program.create) {
|
||||
logit("create", program.args[0]);
|
||||
const newcfb = X.utils.cfb_new();
|
||||
X.writeFile(newcfb, program.args[0]);
|
||||
}
|
||||
|
||||
if(!fs.existsSync(program.args[0])) die(1, "must specify a filename");
|
||||
|
||||
const opts: X.CFBParsingOptions = {type:'file'};
|
||||
if(program.dev) opts.WTF = true;
|
||||
|
||||
const cfb: X.CFBContainer = X.read(program.args[0], opts);
|
||||
if(program.quiet) process.exit(0);
|
||||
if(program.quiet) exit(0);
|
||||
|
||||
if(program.dump) {
|
||||
console.log("Full Paths:");
|
||||
console.log(cfb.FullPaths.map((x) => " " + x).join("\n"));
|
||||
console.log("Full Path Directory:");
|
||||
console.log(cfb.FullPathDir);
|
||||
process.exit(0);
|
||||
}
|
||||
if(program.repair) {
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
process.exit(0);
|
||||
console.log("File Index:");
|
||||
console.log(cfb.FileIndex);
|
||||
exit(0);
|
||||
}
|
||||
if(program.repair) { X.writeFile(cfb, program.args[0]); exit(0); }
|
||||
|
||||
const fix_string = (x: string): string => x.replace(/[\u0000-\u001f]/, ($$) => sprintf("\\u%04X", $$.charCodeAt(0)));
|
||||
const format_date = (date: Date): string => {
|
||||
return sprintf("%02u-%02u-%02u %02u:%02u", date.getUTCMonth()+1, date.getUTCDate(), date.getUTCFullYear()%100, date.getUTCHours(), date.getUTCMinutes());
|
||||
};
|
||||
|
||||
const sprintf = PRINTJ.sprintf;
|
||||
function fix_string(x: string): string { return x.replace(/[\u0000-\u001f]/, function($$) { return sprintf("\\u%04X", $$.charCodeAt(0)); }); }
|
||||
if(program.listFiles) {
|
||||
const 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());
|
||||
};
|
||||
|
||||
let basetime = new Date(1980,0,1);
|
||||
let cnt = 0, rootsize = 0, filesize = 0;
|
||||
console.log(" Length Date Time Name");
|
||||
console.log(" -------- ---- ---- ----");
|
||||
cfb.FileIndex.forEach(function(file: X.CFBEntry, i: number) {
|
||||
cfb.FileIndex.forEach((file: X.CFBEntry, i: number) => {
|
||||
switch(file.type) {
|
||||
case 5:
|
||||
basetime = file.ct || file.mt || basetime;
|
||||
@ -66,14 +76,52 @@ if(program.listFiles) {
|
||||
console.log(" -------- -------");
|
||||
console.log(sprintf("%9lu %lu file%s", rootsize || filesize, cnt, (cnt !== 1 ? "s" : "")));
|
||||
|
||||
process.exit(0);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
const mkdirp = (path: string) => { path.split("/").reduce((acc: string, p: string): string => {
|
||||
acc += p + "/";
|
||||
if(!fs.existsSync(acc)) { logit("mkdir", acc); fs.mkdirSync(acc); }
|
||||
return acc;
|
||||
}, ""); };
|
||||
|
||||
const write = (path: string, data: X.CFBEntry) => {
|
||||
logit("write", fix_string(path));
|
||||
fs.writeFileSync(path, /*::new Buffer((*/data.content/*:: :any))*/);
|
||||
};
|
||||
|
||||
if(program.create || program.append) {
|
||||
program.args.slice(1).forEach((x: string) => {
|
||||
logit("append", x);
|
||||
X.utils.cfb_add(cfb, "/" + x, fs.readFileSync(x));
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.delete) {
|
||||
program.args.slice(1).forEach((x: string) => {
|
||||
logit("delete", x);
|
||||
X.utils.cfb_del(cfb, "/" + x);
|
||||
});
|
||||
X.writeFile(cfb, program.args[0]);
|
||||
exit(0);
|
||||
}
|
||||
|
||||
if(program.args.length > 1) {
|
||||
program.args.slice(1).forEach((x: string) => {
|
||||
const data/*:?CFBEntry*/ = X.find(cfb, x);
|
||||
if(!data) { console.error(x + ": file not found"); return; }
|
||||
if(data.type !== 2) { console.error(x + ": not a file"); return; }
|
||||
const idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx];
|
||||
mkdirp(path.slice(0, path.lastIndexOf("/")));
|
||||
write(path, data);
|
||||
});
|
||||
exit(0);
|
||||
}
|
||||
|
||||
for(let i=0; i!==cfb.FullPaths.length; ++i) {
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") {
|
||||
console.error("mkdir " + fix_string(cfb.FullPaths[i]));
|
||||
fs.mkdirSync(cfb.FullPaths[i]);
|
||||
} else {
|
||||
console.error("write " + fix_string(cfb.FullPaths[i]));
|
||||
fs.writeFileSync(cfb.FullPaths[i], cfb.FileIndex[i].content);
|
||||
}
|
||||
if(!cfb.FileIndex[i].name) continue;
|
||||
if(cfb.FullPaths[i].slice(-1) === "/") mkdirp(cfb.FullPaths[i]);
|
||||
else write(cfb.FullPaths[i], cfb.FileIndex[i]);
|
||||
}
|
||||
|
@ -38,7 +38,7 @@ type CFBFiles = {[n:string]:CFBEntry};
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -59,6 +59,8 @@ function filename(p/*:string*/)/*:string*/ {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
var fs/*:: = require('fs'); */;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -356,9 +358,8 @@ function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ {
|
||||
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
|
||||
}
|
||||
|
||||
var fs/*:: = require('fs'); */;
|
||||
function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
@ -638,6 +639,7 @@ var consts = {
|
||||
};
|
||||
|
||||
function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
/*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
|
||||
fs.writeFileSync(filename, o);
|
||||
@ -652,7 +654,7 @@ function a2s(o/*:RawBytes*/)/*:string*/ {
|
||||
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
@ -668,13 +670,13 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
|
||||
init_cfb(cfb);
|
||||
var file = CFB.find(cfb, name);
|
||||
if(!file) {
|
||||
var fpath = cfb.FullPaths[0];
|
||||
var fpath/*:string*/ = cfb.FullPaths[0];
|
||||
if(name.slice(0, fpath.length) == fpath) fpath = name;
|
||||
else {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)}/*:any*/);
|
||||
file = ({name: filename(name), type: 2}/*:any*/);
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
12
xlscfb.js
12
xlscfb.js
@ -8,7 +8,7 @@ var DO_NOT_EXPORT_CFB = true;
|
||||
/* [MS-CFB] v20130118 */
|
||||
var CFB = (function _CFB(){
|
||||
var exports = {};
|
||||
exports.version = '0.13.1';
|
||||
exports.version = '0.13.2';
|
||||
/* [MS-CFB] 2.6.4 */
|
||||
function namecmp(l, r) {
|
||||
var L = l.split("/"), R = r.split("/");
|
||||
@ -29,6 +29,8 @@ function filename(p) {
|
||||
var c = p.lastIndexOf("/");
|
||||
return (c === -1) ? p : p.slice(c+1);
|
||||
}
|
||||
var fs;
|
||||
function get_fs() { return fs || (fs = require('fs')); }
|
||||
function parse(file, options) {
|
||||
var mver = 3;
|
||||
var ssz = 512;
|
||||
@ -326,9 +328,8 @@ function read_date(blob, offset) {
|
||||
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
|
||||
}
|
||||
|
||||
var fs;
|
||||
function read_file(filename, options) {
|
||||
if(fs == null) fs = require('fs');
|
||||
get_fs();
|
||||
return parse(fs.readFileSync(filename), options);
|
||||
}
|
||||
|
||||
@ -603,6 +604,7 @@ var consts = {
|
||||
};
|
||||
|
||||
function write_file(cfb, filename, options) {
|
||||
get_fs();
|
||||
var o = _write(cfb, options);
|
||||
fs.writeFileSync(filename, o);
|
||||
}
|
||||
@ -616,7 +618,7 @@ function a2s(o) {
|
||||
function write(cfb, options) {
|
||||
var o = _write(cfb, options);
|
||||
switch(options && options.type) {
|
||||
case "file": fs.writeFileSync(options.filename, (o)); return o;
|
||||
case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
|
||||
case "binary": return a2s(o);
|
||||
case "base64": return Base64.encode(a2s(o));
|
||||
}
|
||||
@ -638,7 +640,7 @@ function cfb_add(cfb, name, content, opts) {
|
||||
if(fpath.slice(-1) != "/") fpath += "/";
|
||||
fpath = (fpath + name).replace("//","/");
|
||||
}
|
||||
file = ({name: filename(name)});
|
||||
file = ({name: filename(name), type: 2});
|
||||
cfb.FileIndex.push(file);
|
||||
cfb.FullPaths.push(fpath);
|
||||
CFB.utils.cfb_gc(cfb);
|
||||
|
Loading…
Reference in New Issue
Block a user