version bump 1.0.6: performance

- `unsafe` option to `cfb_add` for bulk write (see #2)
- use `lastIndexOf` to save operations in BFP queue
This commit is contained in:
SheetJS 2018-04-09 02:33:22 -04:00
parent 17b1a8de5a
commit 35d59c57bf
17 changed files with 71 additions and 47 deletions

@ -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.0.6 (2018-04-09)
* `lastIndexOf` in FAT builder enables larger file parsing at minor cost
## 1.0.0 (2017-11-05)
* Actually walk mini-fat

@ -111,6 +111,7 @@ accept a `name` argument strictly deal with absolute file names:
- `.cfb_new(?opts)` creates a new container object.
- `.cfb_add(cfb, name, ?content, ?opts)` adds a new file to the `cfb`.
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

@ -1 +1 @@
exports.version = '1.0.5';
exports.version = '1.0.6';

@ -13,8 +13,8 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];

@ -5,8 +5,9 @@ function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
}
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath/*:string*/ = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -17,7 +18,7 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
file = ({name: filename(name), type: 2}/*:any*/);
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
/*:: if(!file) throw new Error("unreachable"); */
file.content = (content/*:any*/);

@ -177,7 +177,7 @@ type CFBFiles = {[n:string]:CFBEntry};
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.0.5';
exports.version = '1.0.6';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -355,8 +355,8 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -823,8 +823,9 @@ function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
}
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath/*:string*/ = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -835,7 +836,7 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
file = ({name: filename(name), type: 2}/*:any*/);
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
/*:: if(!file) throw new Error("unreachable"); */
file.content = (content/*:any*/);

13
cfb.js

@ -159,7 +159,7 @@ function new_buf(sz) {
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '1.0.5';
exports.version = '1.0.6';
/* [MS-CFB] 2.6.4 */
function namecmp(l, r) {
var L = l.split("/"), R = r.split("/");
@ -337,8 +337,8 @@ function build_full_paths(FI, FP, Paths) {
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -799,8 +799,9 @@ function cfb_new(opts) {
}
function cfb_add(cfb, name, content, opts) {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -811,7 +812,7 @@ function cfb_add(cfb, name, content, opts) {
file = ({name: filename(name), type: 2});
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
file.content = (content);
file.size = content ? content.length : 0;

13
dist/cfb.js vendored

@ -159,7 +159,7 @@ function new_buf(sz) {
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '1.0.5';
exports.version = '1.0.6';
/* [MS-CFB] 2.6.4 */
function namecmp(l, r) {
var L = l.split("/"), R = r.split("/");
@ -337,8 +337,8 @@ function build_full_paths(FI, FP, Paths) {
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -799,8 +799,9 @@ function cfb_new(opts) {
}
function cfb_add(cfb, name, content, opts) {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -811,7 +812,7 @@ function cfb_add(cfb, name, content, opts) {
file = ({name: filename(name), type: 2});
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
file.content = (content);
file.size = content ? content.length : 0;

2
dist/cfb.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/cfb.min.map vendored

File diff suppressed because one or more lines are too long

13
dist/xlscfb.js vendored

@ -38,7 +38,7 @@ type CFBFiles = {[n:string]:CFBEntry};
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.0.5';
exports.version = '1.0.6';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -216,8 +216,8 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -684,8 +684,9 @@ function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
}
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath/*:string*/ = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -696,7 +697,7 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
file = ({name: filename(name), type: 2}/*:any*/);
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
/*:: if(!file) throw new Error("unreachable"); */
file.content = (content/*:any*/);

@ -1,6 +1,6 @@
{
"name": "cfb",
"version": "1.0.5",
"version": "1.0.6",
"author": "sheetjs",
"description": "Compound File Binary File Format extractor",
"keywords": [

@ -18,6 +18,12 @@ if(!Array.prototype.indexOf) Array.prototype.indexOf = function(needle) {
return -1;
};
if(!Array.prototype.lastIndexOf) Array.prototype.lastIndexOf = function(needle) {
var len = (this.length>>>0), i = len - 1;
for(; i>=0; --i) if(this[i] === needle) return i;
return -1;
};
if(!Array.isArray) Array.isArray = function(obj) { return Object.prototype.toString.call(obj) === "[object Array]"; };
if(typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) ArrayBuffer.prototype.slice = function(start, end) {

8
types/index.d.ts vendored

@ -91,10 +91,16 @@ export interface CFB$Container {
};
}
/** cfb_add options */
export interface CFB$AddOpts {
/** Skip existence and safety checks (best for bulk write operations) */
unsafe?: boolean;
}
/** General utilities */
export interface CFB$Utils {
cfb_new(opts?: any): CFB$Container;
cfb_add(cfb: CFB$Container, name: string, content: any, opts?: any): CFB$Entry;
cfb_add(cfb: CFB$Container, name: string, content: any, opts?: CFB$AddOpts): CFB$Entry;
cfb_del(cfb: CFB$Container, name: string): boolean;
cfb_mov(cfb: CFB$Container, old_name: string, new_name: string): boolean;
cfb_gc(cfb: CFB$Container): void;

@ -61,7 +61,7 @@ const old_cfb = CFB.read("t2.xls", {type:"file"});
const new_cfb = CFB.utils.cfb_new({root:"R", clsid: old_cfb.FileIndex[0].clsid });
old_cfb.FullPaths.forEach((p, i) => {
if(p.slice(-1) === "/") return;
CFB.utils.cfb_add(new_cfb, p.replace(/^[^/]*/,"R"), old_cfb.FileIndex[i].content);
CFB.utils.cfb_add(new_cfb, p.replace(/^[^/]*/,"R"), old_cfb.FileIndex[i].content, {unsafe: true});
});
dumpit(new_cfb);
CFB.writeFile(new_cfb, "t3.xls");

@ -38,7 +38,7 @@ type CFBFiles = {[n:string]:CFBEntry};
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.0.5';
exports.version = '1.0.6';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -216,8 +216,8 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Arr
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -684,8 +684,9 @@ function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
}
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath/*:string*/ = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -696,7 +697,7 @@ function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, o
file = ({name: filename(name), type: 2}/*:any*/);
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
/*:: if(!file) throw new Error("unreachable"); */
file.content = (content/*:any*/);

@ -8,7 +8,7 @@ var DO_NOT_EXPORT_CFB = true;
/* [MS-CFB] v20171201 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '1.0.5';
exports.version = '1.0.6';
/* [MS-CFB] 2.6.4 */
function namecmp(l, r) {
var L = l.split("/"), R = r.split("/");
@ -186,8 +186,8 @@ function build_full_paths(FI, FP, Paths) {
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
}
for(i=1; i < pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
@ -648,8 +648,9 @@ function cfb_new(opts) {
}
function cfb_add(cfb, name, content, opts) {
init_cfb(cfb);
var file = CFB.find(cfb, name);
var unsafe = opts && opts.unsafe;
if(!unsafe) init_cfb(cfb);
var file = !unsafe && CFB.find(cfb, name);
if(!file) {
var fpath = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
@ -660,7 +661,7 @@ function cfb_add(cfb, name, content, opts) {
file = ({name: filename(name), type: 2});
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
if(!unsafe) CFB.utils.cfb_gc(cfb);
}
file.content = (content);
file.size = content ? content.length : 0;