version bump 0.10.9: pin dependencies

- updated SSF 0.10.0, codepage 1.10.1, CFB 0.12.0, CRC32 / ADLER32 1.1.0
- pinned all devDependencies (fixes  h/t @the-spyke)
- flow type updates
- clarified meteor usage (fixes  h/t @NorthDecoder)
This commit is contained in:
SheetJS 2017-07-28 19:27:16 -04:00
parent 6732eb76f8
commit ce37f99ec3
20 changed files with 964 additions and 694 deletions

@ -6,6 +6,7 @@ node_modules/
types/ types/
tests/ tests/
test_files test_files
*.md
*.json *.json
*.log *.log

@ -28,6 +28,7 @@ tmp
*.sheetjs *.sheetjs
*.exe *.exe
.gitignore .gitignore
.fossaignore
.eslintrc .eslintrc
.jshintrc .jshintrc
CONTRIBUTING.md CONTRIBUTING.md

@ -5,7 +5,7 @@ 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. changes may not be included if they are not expected to break existing code.
## Unreleased (2017-??-??) ## 0.10.9 (2017-07-28)
* XLML/HTML resolution logic looks further into the data stream to decide type * XLML/HTML resolution logic looks further into the data stream to decide type
* Errors thrown on suspected RTF files * Errors thrown on suspected RTF files

@ -14,7 +14,7 @@ FLOWTARGET=$(LIB).flow.js
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS)) FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
AUXSCPTS=xlsxworker1.js xlsxworker2.js xlsxworker.js AUXSCPTS=xlsxworker1.js xlsxworker2.js xlsxworker.js
FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS) FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS)
UGLIFYOPTS=--support-ie8 -c -m UGLIFYOPTS=--support-ie8
CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar CLOSURE=/usr/local/lib/node_modules/google-closure-compiler/compiler.jar
## Main Targets ## Main Targets

@ -1 +1 @@
XLSX.version = '0.10.8'; XLSX.version = '0.10.9';

@ -1,8 +1,8 @@
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */ /*jshint -W041 */
var SSF = {}; var SSF/*:SSFModule*/ = ({}/*:any*/);
var make_ssf = function make_ssf(SSF){ var make_ssf = function make_ssf(SSF/*:SSFModule*/){
SSF.version = '0.9.4'; SSF.version = '0.10.0';
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; } function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@ -13,16 +13,9 @@ function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=
var p2_32 = Math.pow(2,32); var p2_32 = Math.pow(2,32);
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); } function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; } function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
/* Options */ /*::
var opts_fmt/*:Array<Array<any> >*/ = [ type SSF_write_num = {(type:string, fmt:string, val:number):string};
["date1904", 0], */
["output", ""],
["WTF", false]
];
function fixopts(o){
for(var y = 0; y != opts_fmt.length; ++y) if(o[opts_fmt[y][0]]===undefined) o[opts_fmt[y][0]]=opts_fmt[y][1];
}
SSF.opts = opts_fmt;
var days/*:Array<Array<string> >*/ = [ var days/*:Array<Array<string> >*/ = [
['Sun', 'Sunday'], ['Sun', 'Sunday'],
['Mon', 'Monday'], ['Mon', 'Monday'],
@ -101,7 +94,47 @@ function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/
var q = Math.floor(sgn * P/Q); var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q]; return [q, sgn*P - q*Q, Q];
} }
function general_fmt_int(v/*:number*/)/*:string*/ { return ""+v; } function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
if(opts && opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
var basedate = new Date(1899, 11, 31, 0, 0, 0);
var dnthresh = basedate.getTime();
var base1904 = new Date(1900, 2, 1, 0, 0, 0);
function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = v.getTime();
if(date1904) epoch -= 1461*24*60*60*1000;
else if(v >= base1904) epoch += 24*60*60*1000;
return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
}
function general_fmt_int(v/*:number*/)/*:string*/ { return v.toString(10); }
SSF._general_int = general_fmt_int; SSF._general_int = general_fmt_int;
var general_fmt_num = (function make_general_fmt_num() { var general_fmt_num = (function make_general_fmt_num() {
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/; var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
@ -132,50 +165,20 @@ return function general_fmt_num(v/*:number*/)/*:string*/ {
return gfn5(gfn4(o)); return gfn5(gfn4(o));
};})(); };})();
SSF._general_num = general_fmt_num; SSF._general_num = general_fmt_num;
function general_fmt(v/*:any*/) { function general_fmt(v/*:any*/, opts/*:any*/) {
switch(typeof v) { switch(typeof v) {
case 'string': return v; case 'string': return v;
case 'boolean': return v ? "TRUE" : "FALSE"; case 'boolean': return v ? "TRUE" : "FALSE";
case 'number': return (v|0) === v ? general_fmt_int(v/*, opts*/) : general_fmt_num(v/*, opts*/); case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
case 'undefined': return ""; case 'undefined': return "";
case 'object': if(v == null) return ""; case 'object':
if(v == null) return "";
if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
} }
throw new Error("unsupported value in General format: " + v); throw new Error("unsupported value in General format: " + v);
} }
SSF._general = general_fmt; SSF._general = general_fmt;
function fix_hijri(/*date, o*/) { return 0; } function fix_hijri(/*::date, o*/) { return 0; }
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
fixopts(opts != null ? opts : (opts=[]));
if(opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
/*jshint -W086 */ /*jshint -W086 */
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ { function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
var o="", ss=0, tt=0, y = val.y, out, outl = 0; var o="", ss=0, tt=0, y = val.y, out, outl = 0;
@ -217,23 +220,17 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
default: throw 'bad minute format: ' + fmt; default: throw 'bad minute format: ' + fmt;
} break; } break;
case 115: /* 's' seconds */ case 115: /* 's' seconds */
if(val.u === 0) switch(fmt) { if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
case 's': case 'ss': return pad0(val.S, fmt.length); if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
case '.0': case '.00': case '.000': /*::if(!ss0) ss0 = 0; */
} if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
switch(fmt) { else tt = ss0 === 1 ? 10 : 1;
case 's': case 'ss': case '.0': case '.00': case '.000': ss = Math.round((tt)*(val.S + val.u));
/*::if(!ss0) ss0 = 0; */ if(ss >= 60*tt) ss = 0;
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100; if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
else tt = ss0 === 1 ? 10 : 1; o = pad0(ss,2 + ss0);
ss = Math.round((tt)*(val.S + val.u)); if(fmt === 'ss') return o.substr(0,2);
if(ss >= 60*tt) ss = 0; return "." + o.substr(2,fmt.length-1);
if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
o = pad0(ss,2 + ss0);
if(fmt === 'ss') return o.substr(0,2);
return "." + o.substr(2,fmt.length-1);
default: throw 'bad second format: ' + fmt;
}
case 90: /* 'Z' absolute time */ case 90: /* 'Z' absolute time */
switch(fmt) { switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break; case '[h]': case '[hh]': out = val.D*24+val.H; break;
@ -248,12 +245,13 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
} }
/*jshint +W086 */ /*jshint +W086 */
function commaify(s/*:string*/)/*:string*/ { function commaify(s/*:string*/)/*:string*/ {
if(s.length <= 3) return s; var w = 3;
var j = (s.length % 3), o = s.substr(0,j); if(s.length <= w) return s;
for(; j!=s.length; j+=3) o+=(o.length > 0 ? "," : "") + s.substr(j,3); var j = (s.length % w), o = s.substr(0,j);
for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
return o; return o;
} }
var write_num = (function make_write_num(){ var write_num/*:SSF_write_num*/ = (function make_write_num(){
var pct1 = /%/g; var pct1 = /%/g;
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{ function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length; var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
@ -591,7 +589,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
} }
SSF.is_date = fmt_is_date; SSF.is_date = fmt_is_date;
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc; var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
var hr='H'; var hr='H';
/* Tokenize */ /* Tokenize */
while(i < fmt.length) { while(i < fmt.length) {
@ -619,12 +617,12 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
if(v < 0) return ""; if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; } if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c; o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
if(c === 'h') c = hr; if(c === 'h') c = hr;
out[out.length] = {t:c, v:o}; lst = c; break; out[out.length] = {t:c, v:o}; lst = c; break;
case 'A': case 'a': case 'A': case 'a':
q={t:c, v:c}; var q={t:c, v:c};
if(dt==null) dt=parse_date_code(v, opts); if(dt==null) dt=parse_date_code(v, opts);
if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;} if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
@ -647,7 +645,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
/* Numbers */ /* Numbers */
case '.': case '.':
if(dt != null) { if(dt != null) {
o = c; while((c=fmt.charAt(++i)) === "0") o += c; o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
out[out.length] = {t:'s', v:o}; break; out[out.length] = {t:'s', v:o}; break;
} }
/* falls through */ /* falls through */
@ -656,7 +654,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
out[out.length] = {t:'n', v:o}; break; out[out.length] = {t:'n', v:o}; break;
case '?': case '?':
o = c; while(fmt.charAt(++i) === c) o+=c; o = c; while(fmt.charAt(++i) === c) o+=c;
q={t:c, v:o}; out[out.length] = q; lst = c; break; out[out.length] = {t:c, v:o}; lst = c; break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // ** case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break; case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
@ -807,7 +805,7 @@ function chkcond(v, rr) {
} }
return false; return false;
} }
function choose_fmt(f/*:string*/, v) { function choose_fmt(f/*:string*/, v/*:any*/) {
var fmt = split_fmt(f); var fmt = split_fmt(f);
var l = fmt.length, lat = fmt[l-1].indexOf("@"); var l = fmt.length, lat = fmt[l-1].indexOf("@");
if(l<4 && lat>-1) --l; if(l<4 && lat>-1) --l;
@ -842,17 +840,37 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
break; break;
} }
if(isgeneral(sfmt,0)) return general_fmt(v, o); if(isgeneral(sfmt,0)) return general_fmt(v, o);
if(v instanceof Date) v = datenum_local(v, o.date1904);
var f = choose_fmt(sfmt, v); var f = choose_fmt(sfmt, v);
if(isgeneral(f[1])) return general_fmt(v, o); if(isgeneral(f[1])) return general_fmt(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE"; if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
else if(v === "" || v == null) return ""; else if(v === "" || v == null) return "";
return eval_fmt(f[1], v, o, f[0]); return eval_fmt(f[1], v, o, f[0]);
} }
function load_entry(fmt/*:string*/, idx/*:?number*/)/*:number*/ {
if(typeof idx != 'number') {
idx = +idx || -1;
/*::if(typeof idx != 'number') return 0x188; */
for(var i = 0; i < 0x0188; ++i) {
/*::if(typeof idx != 'number') return 0x188; */
if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
if(table_fmt[i] == fmt) { idx = i; break; }
}
/*::if(typeof idx != 'number') return 0x188; */
if(idx < 0) idx = 0x187;
}
/*::if(typeof idx != 'number') return 0x188; */
table_fmt[idx] = fmt;
return idx;
}
SSF.load = load_entry;
SSF._table = table_fmt; SSF._table = table_fmt;
SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; }; SSF.get_table = function get_table()/*:SSFTable*/ { return table_fmt; };
SSF.format = format; SSF.load_table = function load_table(tbl/*:SSFTable*/)/*:void*/ {
SSF.get_table = function get_table() { return table_fmt; }; for(var i=0; i!=0x0188; ++i)
SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); }; if(tbl[i] !== undefined) load_entry(tbl[i], i);
};
SSF.init_table = init_table; SSF.init_table = init_table;
SSF.format = format;
}; };
make_ssf(SSF); make_ssf(SSF);

@ -18,20 +18,25 @@ declare var chr1:any;
/*jshint eqnull:true */ /*jshint eqnull:true */
/*:: /*::
declare var DO_NOT_EXPORT_CFB:any; declare var DO_NOT_EXPORT_CFB:?boolean;
type SectorEntry = any; type SectorEntry = {
name?:string;
nodes?:Array<number>;
data:RawBytes;
};
type SectorList = { type SectorList = {
(k:string|number):SectorEntry; [k:string|number]:SectorEntry;
name:?string; name:?string;
fat_addrs:any; fat_addrs:Array<number>;
ssz:number; ssz:number;
} }
type CFBFiles = {[n:string]:CFBEntry};
*/ */
/* [MS-CFB] v20130118 */ /* [MS-CFB] v20130118 */
var CFB = (function _CFB(){ var CFB = (function _CFB(){
var exports = {}; var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '0.11.1'; exports.version = '0.12.0';
function parse(file) { function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
var mver = 3; // major version var mver = 3; // major version
var ssz = 512; // sector size var ssz = 512; // sector size
var nmfs = 0; // number of mini FAT sectors var nmfs = 0; // number of mini FAT sectors
@ -40,10 +45,10 @@ var dir_start = 0; // first directory sector location
var minifat_start = 0; // first mini FAT sector location var minifat_start = 0; // first mini FAT sector location
var difat_start = 0; // first mini FAT sector location var difat_start = 0; // first mini FAT sector location
var fat_addrs = []; // locations of FAT sectors var fat_addrs/*:Array<number>*/ = []; // locations of FAT sectors
/* [MS-CFB] 2.2 Compound File Header */ /* [MS-CFB] 2.2 Compound File Header */
var blob/*:any*/ = file.slice(0,512); var blob/*:CFBlob*/ = /*::(*/file.slice(0,512)/*:: :any)*/;
prep_blob(blob, 0); prep_blob(blob, 0);
/* major version */ /* major version */
@ -55,14 +60,14 @@ switch(mver) {
} }
/* reprocess header */ /* reprocess header */
if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); } if(ssz !== 512) { blob = /*::(*/file.slice(0,ssz)/*:: :any)*/; prep_blob(blob, 28 /* blob.l */); }
/* Save header for final object */ /* Save header for final object */
var header = file.slice(0,ssz); var header/*:RawBytes*/ = file.slice(0,ssz);
check_shifts(blob, mver); check_shifts(blob, mver);
// Number of Directory Sectors // Number of Directory Sectors
var nds = blob.read_shift(4, 'i'); var nds/*:number*/ = blob.read_shift(4, 'i');
if(mver === 3 && nds !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + nds); if(mver === 3 && nds !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + nds);
// Number of FAT Sectors // Number of FAT Sectors
@ -91,14 +96,14 @@ difat_start = blob.read_shift(4, 'i');
ndfs = blob.read_shift(4, 'i'); ndfs = blob.read_shift(4, 'i');
// Grab FAT Sector Locations // Grab FAT Sector Locations
for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */ for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
q = blob.read_shift(4, 'i'); q = blob.read_shift(4, 'i');
if(q<0) break; if(q<0) break;
fat_addrs[j] = q; fat_addrs[j] = q;
} }
/** Break the file up into sectors */ /** Break the file up into sectors */
var sectors = sectorify(file, ssz); var sectors/*:Array<RawBytes>*/ = sectorify(file, ssz);
sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs); sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs);
@ -112,13 +117,12 @@ sector_list.fat_addrs = fat_addrs;
sector_list.ssz = ssz; sector_list.ssz = ssz;
/* [MS-CFB] 2.6.1 Compound File Directory Entry */ /* [MS-CFB] 2.6.1 Compound File Directory Entry */
var files = {}, Paths/*:any*/ = [], FileIndex = [], FullPaths = [], FullPathDir = {}; var files/*:CFBFiles*/ = {}, Paths/*:Array<string>*/ = [], FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [], FullPathDir = {};
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex); read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
build_full_paths(FileIndex, FullPathDir, FullPaths, Paths); build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
var root_name = Paths.shift(); var root_name/*:string*/ = Paths.shift();
Paths.root = root_name;
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name); var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name);
@ -133,7 +137,7 @@ return {
} // parse } // parse
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */ /* [MS-CFB] 2.2 Compound File Header -- read up to major version */
function check_get_mver(blob) { function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
// header signature 8 // header signature 8
blob.chk(HEADER_SIGNATURE, 'Header Signature: '); blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
@ -141,11 +145,11 @@ function check_get_mver(blob) {
blob.chk(HEADER_CLSID, 'CLSID: '); blob.chk(HEADER_CLSID, 'CLSID: ');
// minor version 2 // minor version 2
var mver = blob.read_shift(2, 'u'); var mver/*:number*/ = blob.read_shift(2, 'u');
return [blob.read_shift(2,'u'), mver]; return [blob.read_shift(2,'u'), mver];
} }
function check_shifts(blob, mver) { function check_shifts(blob/*:CFBlob*/, mver/*:number*/)/*:void*/ {
var shift = 0x09; var shift = 0x09;
// Byte Order // Byte Order
@ -167,18 +171,18 @@ function check_shifts(blob, mver) {
} }
/** Break the file up into sectors */ /** Break the file up into sectors */
function sectorify(file, ssz) { function sectorify(file/*:RawBytes*/, ssz/*:number*/)/*:Array<RawBytes>*/ {
var nsectors = Math.ceil(file.length/ssz)-1; var nsectors = Math.ceil(file.length/ssz)-1;
var sectors = new Array(nsectors); var sectors/*:Array<RawBytes>*/ = [];
for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
sectors[nsectors-1] = file.slice(nsectors*ssz); sectors[nsectors-1] = file.slice(nsectors*ssz);
return sectors; return sectors;
} }
/* [MS-CFB] 2.6.4 Red-Black Tree */ /* [MS-CFB] 2.6.4 Red-Black Tree */
function build_full_paths(FI, FPD, FP, Paths) { function build_full_paths(FI/*:CFBFileIndex*/, FPD/*:CFBFullPathDir*/, FP/*:Array<string>*/, Paths/*:Array<string>*/)/*:void*/ {
var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length; var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
var dad = new Array(pl), q = new Array(pl); var dad/*:Array<number>*/ = [], q/*:Array<number>*/ = [];
for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; } for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
@ -217,17 +221,17 @@ function build_full_paths(FI, FPD, FP, Paths) {
} }
/* [MS-CFB] 2.6.4 */ /* [MS-CFB] 2.6.4 */
function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { function make_find_path(FullPaths/*:Array<string>*/, Paths/*:Array<string>*/, FileIndex/*:CFBFileIndex*/, files/*:CFBFiles*/, root_name/*:string*/)/*:CFBFindPath*/ {
var UCFullPaths = new Array(FullPaths.length); var UCFullPaths/*:Array<string>*/ = [];
var UCPaths = new Array(Paths.length), i; var UCPaths/*:Array<string>*/ = [], i = 0;
for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
return function find_path(path/*:string*/) { return function find_path(path/*:string*/)/*:?CFBEntry*/ {
var k; var k/*:boolean*/ = false;
if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; }
else k = path.indexOf("/") !== -1; else k = path.indexOf("/") !== -1;
var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); var UCPath/*:string*/ = path.toUpperCase().replace(chr0,'').replace(chr1,'!');
var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
if(w === -1) return null; if(w === -1) return null;
return k === true ? FileIndex[w] : files[Paths[w]]; return k === true ? FileIndex[w] : files[Paths[w]];
}; };
@ -235,8 +239,8 @@ function make_find_path(FullPaths, Paths, FileIndex, files, root_name) {
/** Chase down the rest of the DIFAT chain to build a comprehensive list /** Chase down the rest of the DIFAT chain to build a comprehensive list
DIFAT chains by storing the next sector number as the last 32 bytes */ DIFAT chains by storing the next sector number as the last 32 bytes */
function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/, ssz/*:number*/, fat_addrs)/*:void*/ {
var q; var q/*:number*/ = ENDOFCHAIN;
if(idx === ENDOFCHAIN) { if(idx === ENDOFCHAIN) {
if(cnt !== 0) throw new Error("DIFAT chain shorter than expected"); if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
} else if(idx !== -1 /*FREESECT*/) { } else if(idx !== -1 /*FREESECT*/) {
@ -251,13 +255,11 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
} }
/** Follow the linked list of sectors for a given starting point */ /** Follow the linked list of sectors for a given starting point */
function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { function get_sector_list(sectors/*:Array<RawBytes>*/, start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/, chkd/*:?Array<boolean>*/)/*:SectorEntry*/ {
var sl = sectors.length; var sl = sectors.length;
var buf, buf_chain; var buf/*:Array<number>*/ = [], buf_chain/*:Array<any>*/ = [];
if(!chkd) chkd = new Array(sl); if(!chkd) chkd = [];
var modulus = ssz - 1, j, jj; var modulus = ssz - 1, j = 0, jj = 0;
buf = [];
buf_chain = [];
for(j=start; j>=0;) { for(j=start; j>=0;) {
chkd[j] = true; chkd[j] = true;
buf[buf.length] = j; buf[buf.length] = j;
@ -272,44 +274,43 @@ function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
} }
/** Chase down the sector linked lists */ /** Chase down the sector linked lists */
function make_sector_list(sectors, dir_start, fat_addrs, ssz/*:number*/)/*:any*/ { function make_sector_list(sectors/*:Array<RawBytes>*/, dir_start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/)/*:SectorList*/ {
var sl = sectors.length, sector_list = new Array(sl); var sl = sectors.length, sector_list/*:SectorList*/ = ([]/*:any*/);
var chkd = new Array(sl), buf, buf_chain; var chkd/*:Array<boolean>*/ = [], buf/*:Array<number>*/ = [], buf_chain/*:Array<RawBytes>*/ = [];
var modulus = ssz - 1, i, j, k, jj; var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
for(i=0; i < sl; ++i) { for(i=0; i < sl; ++i) {
buf = []; buf = ([]/*:Array<number>*/);
k = (i + dir_start); if(k >= sl) k-=sl; k = (i + dir_start); if(k >= sl) k-=sl;
if(chkd[k] === true) continue; if(chkd[k]) continue;
buf_chain = []; buf_chain = [];
for(j=k; j>=0;) { for(j=k; j>=0;) {
chkd[j] = true; chkd[j] = true;
buf[buf.length] = j; buf[buf.length] = j;
buf_chain.push(sectors[j]); buf_chain.push(sectors[j]);
var addr = fat_addrs[Math.floor(j*4/ssz)]; var addr/*:number*/ = fat_addrs[Math.floor(j*4/ssz)];
jj = ((j*4) & modulus); jj = ((j*4) & modulus);
if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz); if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
if(!sectors[addr]) break; if(!sectors[addr]) break;
j = __readInt32LE(sectors[addr], jj); j = __readInt32LE(sectors[addr], jj);
} }
sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])}; sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])}/*:SectorEntry*/);
} }
return sector_list; return sector_list;
} }
/* [MS-CFB] 2.6.1 Compound File Directory Entry */ /* [MS-CFB] 2.6.1 Compound File Directory Entry */
function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) { function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array<RawBytes>*/, Paths/*:Array<string>*/, nmfs, files, FileIndex) {
var blob;
var minifat_store = 0, pl = (Paths.length?2:0); var minifat_store = 0, pl = (Paths.length?2:0);
var sector = sector_list[dir_start].data; var sector = sector_list[dir_start].data;
var i = 0, namelen = 0, name, o, ctime, mtime; var i = 0, namelen = 0, name;
for(; i < sector.length; i+= 128) { for(; i < sector.length; i+= 128) {
blob = sector.slice(i, i+128); var blob/*:CFBlob*/ = /*::(*/sector.slice(i, i+128)/*:: :any)*/;
prep_blob(blob, 64); prep_blob(blob, 64);
namelen = blob.read_shift(2); namelen = blob.read_shift(2);
if(namelen === 0) continue; if(namelen === 0) continue;
name = __utf16le(blob,0,namelen-pl); name = __utf16le(blob,0,namelen-pl);
Paths.push(name); Paths.push(name);
o = ({ var o/*:CFBEntry*/ = ({
name: name, name: name,
type: blob.read_shift(1), type: blob.read_shift(1),
color: blob.read_shift(1), color: blob.read_shift(1),
@ -317,16 +318,14 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
R: blob.read_shift(4, 'i'), R: blob.read_shift(4, 'i'),
C: blob.read_shift(4, 'i'), C: blob.read_shift(4, 'i'),
clsid: blob.read_shift(16), clsid: blob.read_shift(16),
state: blob.read_shift(4, 'i') state: blob.read_shift(4, 'i'),
}/*:any*/); start: 0,
ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); size: 0
if(ctime !== 0) { });
o.ctime = ctime; o.ct = read_date(blob, blob.l-8); var ctime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
} if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); var mtime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
if(mtime !== 0) { if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
o.mtime = mtime; o.mt = read_date(blob, blob.l-8);
}
o.start = blob.read_shift(4, 'i'); o.start = blob.read_shift(4, 'i');
o.size = blob.read_shift(4, 'i'); o.size = blob.read_shift(4, 'i');
if(o.type === 5) { /* root */ if(o.type === 5) { /* root */
@ -337,12 +336,12 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
o.storage = 'fat'; o.storage = 'fat';
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
sector_list[o.start].name = o.name; sector_list[o.start].name = o.name;
o.content = sector_list[o.start].data.slice(0,o.size); o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/);
prep_blob(o.content, 0); prep_blob(o.content, 0);
} else { } else {
o.storage = 'minifat'; o.storage = 'minifat';
if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) { if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) {
o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size); o.content = (sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size)/*:any*/);
prep_blob(o.content, 0); prep_blob(o.content, 0);
} }
} }
@ -351,23 +350,23 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
} }
} }
function read_date(blob, offset) { 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); return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
} }
var fs; var fs/*:: = require('fs'); */;
function readFileSync(filename/*:string*/, options/*:any*/) { function readFileSync(filename/*:string*/, options/*:CFBReadOpts*/) {
if(fs === undefined) fs = require('fs'); if(fs == null) fs = require('fs');
return parse(fs.readFileSync(filename), options); return parse(fs.readFileSync(filename), options);
} }
function readSync(blob/*:any*/, options/*:any*/) { function readSync(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
switch(options !== undefined && options.type !== undefined ? options.type : "base64") { switch(options && options.type || "base64") {
case "file": return readFileSync(blob, options); case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return readFileSync(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options); case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options);
case "binary": return parse(s2a(blob), options); case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options);
} }
return parse(blob); return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options);
} }
/** CFB Constants */ /** CFB Constants */

@ -26,6 +26,24 @@ The write demo:
- generates file on client side - generates file on client side
- triggers a download. - triggers a download.
This demo uses the FileSaver.js library for writing files, installed through the
[`pfafman:filesaver` wrapper](https://atmospherejs.com/pfafman/filesaver):
```bash
meteor add pfafman:filesaver
```
## Setup
This tree does not include the `.meteor` structure. Rebuild the project with:
```bash
meteor create .
npm install babel-runtime meteor-node-stubs xlsx
meteor add pfafman:filesaver
meteor
```
## Environment-specific features ## Environment-specific features

2
dist/cpexcel.js vendored

@ -1,6 +1,6 @@
/* cpexcel.js (C) 2013-present SheetJS -- http://sheetjs.com */ /* cpexcel.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W100 */ /*jshint -W100 */
var cptable = {version:"1.9.0"}; var cptable = {version:"1.10.0"};
cptable[437] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); cptable[437] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })();
cptable[620] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàąçêëèïîćÄĄĘęłôöĆûùŚÖܢ٥śƒŹŻóÓńŃźż¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); cptable[620] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàąçêëèïîćÄĄĘęłôöĆûùŚÖܢ٥śƒŹŻóÓńŃźż¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })();
cptable[737] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); cptable[737] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })();

30
dist/xlsx.core.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

32
dist/xlsx.full.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

512
dist/xlsx.js vendored

File diff suppressed because it is too large Load Diff

28
dist/xlsx.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map vendored

File diff suppressed because one or more lines are too long

@ -12,6 +12,120 @@ declare module 'fs' { declare var exports:any; };
type ZIP = any; type ZIP = any;
type SSFTable = {[key:number|string]:string};
type SSFDate = {
D:number; T:number;
y:number; m:number; d:number; q:number;
H:number; M:number; S:number; u:number;
};
type SSFModule = {
format:(fmt:string|number, v:any, o:any)=>string;
is_date:(fmt:string)=>boolean;
parse_date_code:(v:number,opts:any)=>?SSFDate;
load:(fmt:string, idx:?number)=>number;
get_table:()=>SSFTable;
load_table:(table:any)=>void;
_table:SSFTable;
init_table:any;
_general_int:(v:number)=>string;
_general_num:(v:number)=>string;
_general:(v:number, o:?any)=>string;
_eval:any;
_split:any;
version:string;
};
// ----------------------------------------------------------------------------
// Note: The following override is needed because ReadShift includes more cases
// ----------------------------------------------------------------------------
type CFBModule = {
version:string;
read:(blob:RawBytes|string, opts:CFBReadOpts)=>CFBContainer;
parse:(file:RawBytes, opts:CFBReadOpts)=>CFBContainer;
utils:CFBUtils;
};
type CFBFullPathDir = {
[n:string]: CFBEntry;
}
type CFBUtils = any;
type CheckFieldFunc = {(hexstr:string, fld:string):void;};
type RawBytes = Array<number> | Buffer | Uint8Array;
class CFBlobArray extends Array<number> {
l:number;
read_shift:ReadShiftFunc;
chk:CheckFieldFunc;
};
interface CFBlobBuffer extends Buffer {
l:number;
slice:(start:number, end:?number)=>Buffer;
read_shift:ReadShiftFunc;
chk:CheckFieldFunc;
};
interface CFBlobUint8 extends Uint8Array {
l:number;
slice:(start:number, end:?number)=>Uint8Array;
read_shift:ReadShiftFunc;
chk:CheckFieldFunc;
};
interface CFBlobber {
[n:number]:number;
l:number;
length:number;
slice:(start:number, end:?number)=>RawBytes;
read_shift:ReadShiftFunc;
chk:CheckFieldFunc;
};
type CFBlob = CFBlobArray | CFBlobBuffer | CFBlobUint8;
interface CFBReadOpts {
type?:string;
};
type CFBFileIndex = Array<CFBEntry>;
type CFBFindPath = (n:string)=>?CFBEntry;
type CFBContainer = {
raw:{
header:any;
sectors:Array<any>;
};
FileIndex:CFBFileIndex;
FullPathDir:CFBDirectory;
FullPaths:Array<string>;
find:CFBFindPath;
}
type CFBEntry = {
name: string;
type: number;
ct?: Date;
mt?: Date;
color: number;
clsid: string;
state: number;
start: number;
size: number;
storage?: "fat" | "minifat";
L: number;
R: number;
C: number;
content?: CFBlob;
}
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------
// Note: The following override is needed because Flow is missing Date#getYear // Note: The following override is needed because Flow is missing Date#getYear
// ---------------------------------------------------------------------------- // ----------------------------------------------------------------------------

@ -1,6 +1,6 @@
{ {
"name": "xlsx", "name": "xlsx",
"version": "0.10.8", "version": "0.10.9",
"author": "sheetjs", "author": "sheetjs",
"description": "Excel (XLSB/XLSX/XLS/XML) ODS and other spreadsheet format (CSV/DIF/DBF/SYLK) parser and writer", "description": "Excel (XLSB/XLSX/XLS/XML) ODS and other spreadsheet format (CSV/DIF/DBF/SYLK) parser and writer",
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "csv", "dbf", "dif", "sylk", "office", "spreadsheet" ], "keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "csv", "dbf", "dif", "sylk", "office", "spreadsheet" ],
@ -18,20 +18,19 @@
}, },
"dependencies": { "dependencies": {
"exit-on-epipe":"~1.0.1", "exit-on-epipe":"~1.0.1",
"ssf":"~0.9.4", "ssf":"~0.10.0",
"codepage":"~1.9.0", "codepage":"~1.10.1",
"cfb":"~0.11.1", "cfb":"~0.12.0",
"crc-32":"~1.0.2", "crc-32":"~1.1.0",
"adler-32":"~1.0.0", "adler-32":"~1.1.0",
"commander":"~2.11.0" "commander":"~2.11.0"
}, },
"devDependencies": { "devDependencies": {
"mocha":"~2.5.3", "mocha":"~2.5.3",
"blanket": "~1.2.3", "blanket": "~1.2.3",
"xlsjs":"*", "@sheetjs/uglify-js":"~2.7.3",
"@sheetjs/uglify-js":"*",
"@types/node":"^8.0.7", "@types/node":"^8.0.7",
"@types/commander":"*", "@types/commander":"^2.9.0",
"dtslint": "^0.1.2", "dtslint": "^0.1.2",
"typescript": "2.2.0" "typescript": "2.2.0"
}, },

@ -6,7 +6,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false */ /*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {}; var XLSX = {};
(function make_xlsx(XLSX){ (function make_xlsx(XLSX){
XLSX.version = '0.10.8'; XLSX.version = '0.10.9';
var current_codepage = 1200; var current_codepage = 1200;
/*:: declare var cptable:any; */ /*:: declare var cptable:any; */
/*global cptable:true */ /*global cptable:true */
@ -130,9 +130,9 @@ type WriteObjStrFactory = {from_sheet(ws:Worksheet, o:any, wb:?Workbook):string}
*/ */
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */ /*jshint -W041 */
var SSF = {}; var SSF/*:SSFModule*/ = ({}/*:any*/);
var make_ssf = function make_ssf(SSF){ var make_ssf = function make_ssf(SSF/*:SSFModule*/){
SSF.version = '0.9.4'; SSF.version = '0.10.0';
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; } function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@ -143,16 +143,9 @@ function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=
var p2_32 = Math.pow(2,32); var p2_32 = Math.pow(2,32);
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); } function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; } function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
/* Options */ /*::
var opts_fmt/*:Array<Array<any> >*/ = [ type SSF_write_num = {(type:string, fmt:string, val:number):string};
["date1904", 0], */
["output", ""],
["WTF", false]
];
function fixopts(o){
for(var y = 0; y != opts_fmt.length; ++y) if(o[opts_fmt[y][0]]===undefined) o[opts_fmt[y][0]]=opts_fmt[y][1];
}
SSF.opts = opts_fmt;
var days/*:Array<Array<string> >*/ = [ var days/*:Array<Array<string> >*/ = [
['Sun', 'Sunday'], ['Sun', 'Sunday'],
['Mon', 'Monday'], ['Mon', 'Monday'],
@ -231,7 +224,47 @@ function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/
var q = Math.floor(sgn * P/Q); var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q]; return [q, sgn*P - q*Q, Q];
} }
function general_fmt_int(v/*:number*/)/*:string*/ { return ""+v; } function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
if(opts && opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
var basedate = new Date(1899, 11, 31, 0, 0, 0);
var dnthresh = basedate.getTime();
var base1904 = new Date(1900, 2, 1, 0, 0, 0);
function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = v.getTime();
if(date1904) epoch -= 1461*24*60*60*1000;
else if(v >= base1904) epoch += 24*60*60*1000;
return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
}
function general_fmt_int(v/*:number*/)/*:string*/ { return v.toString(10); }
SSF._general_int = general_fmt_int; SSF._general_int = general_fmt_int;
var general_fmt_num = (function make_general_fmt_num() { var general_fmt_num = (function make_general_fmt_num() {
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/; var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
@ -262,50 +295,20 @@ return function general_fmt_num(v/*:number*/)/*:string*/ {
return gfn5(gfn4(o)); return gfn5(gfn4(o));
};})(); };})();
SSF._general_num = general_fmt_num; SSF._general_num = general_fmt_num;
function general_fmt(v/*:any*/) { function general_fmt(v/*:any*/, opts/*:any*/) {
switch(typeof v) { switch(typeof v) {
case 'string': return v; case 'string': return v;
case 'boolean': return v ? "TRUE" : "FALSE"; case 'boolean': return v ? "TRUE" : "FALSE";
case 'number': return (v|0) === v ? general_fmt_int(v/*, opts*/) : general_fmt_num(v/*, opts*/); case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
case 'undefined': return ""; case 'undefined': return "";
case 'object': if(v == null) return ""; case 'object':
if(v == null) return "";
if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
} }
throw new Error("unsupported value in General format: " + v); throw new Error("unsupported value in General format: " + v);
} }
SSF._general = general_fmt; SSF._general = general_fmt;
function fix_hijri(/*date, o*/) { return 0; } function fix_hijri(/*::date, o*/) { return 0; }
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
fixopts(opts != null ? opts : (opts=[]));
if(opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
/*jshint -W086 */ /*jshint -W086 */
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ { function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
var o="", ss=0, tt=0, y = val.y, out, outl = 0; var o="", ss=0, tt=0, y = val.y, out, outl = 0;
@ -347,23 +350,17 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
default: throw 'bad minute format: ' + fmt; default: throw 'bad minute format: ' + fmt;
} break; } break;
case 115: /* 's' seconds */ case 115: /* 's' seconds */
if(val.u === 0) switch(fmt) { if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
case 's': case 'ss': return pad0(val.S, fmt.length); if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
case '.0': case '.00': case '.000': /*::if(!ss0) ss0 = 0; */
} if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
switch(fmt) { else tt = ss0 === 1 ? 10 : 1;
case 's': case 'ss': case '.0': case '.00': case '.000': ss = Math.round((tt)*(val.S + val.u));
/*::if(!ss0) ss0 = 0; */ if(ss >= 60*tt) ss = 0;
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100; if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
else tt = ss0 === 1 ? 10 : 1; o = pad0(ss,2 + ss0);
ss = Math.round((tt)*(val.S + val.u)); if(fmt === 'ss') return o.substr(0,2);
if(ss >= 60*tt) ss = 0; return "." + o.substr(2,fmt.length-1);
if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
o = pad0(ss,2 + ss0);
if(fmt === 'ss') return o.substr(0,2);
return "." + o.substr(2,fmt.length-1);
default: throw 'bad second format: ' + fmt;
}
case 90: /* 'Z' absolute time */ case 90: /* 'Z' absolute time */
switch(fmt) { switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break; case '[h]': case '[hh]': out = val.D*24+val.H; break;
@ -378,12 +375,13 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
} }
/*jshint +W086 */ /*jshint +W086 */
function commaify(s/*:string*/)/*:string*/ { function commaify(s/*:string*/)/*:string*/ {
if(s.length <= 3) return s; var w = 3;
var j = (s.length % 3), o = s.substr(0,j); if(s.length <= w) return s;
for(; j!=s.length; j+=3) o+=(o.length > 0 ? "," : "") + s.substr(j,3); var j = (s.length % w), o = s.substr(0,j);
for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
return o; return o;
} }
var write_num = (function make_write_num(){ var write_num/*:SSF_write_num*/ = (function make_write_num(){
var pct1 = /%/g; var pct1 = /%/g;
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{ function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length; var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
@ -721,7 +719,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
} }
SSF.is_date = fmt_is_date; SSF.is_date = fmt_is_date;
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) { function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc; var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
var hr='H'; var hr='H';
/* Tokenize */ /* Tokenize */
while(i < fmt.length) { while(i < fmt.length) {
@ -749,12 +747,12 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
if(v < 0) return ""; if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; } if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c; o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
if(c === 'h') c = hr; if(c === 'h') c = hr;
out[out.length] = {t:c, v:o}; lst = c; break; out[out.length] = {t:c, v:o}; lst = c; break;
case 'A': case 'a': case 'A': case 'a':
q={t:c, v:c}; var q={t:c, v:c};
if(dt==null) dt=parse_date_code(v, opts); if(dt==null) dt=parse_date_code(v, opts);
if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;} if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
@ -777,7 +775,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
/* Numbers */ /* Numbers */
case '.': case '.':
if(dt != null) { if(dt != null) {
o = c; while((c=fmt.charAt(++i)) === "0") o += c; o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
out[out.length] = {t:'s', v:o}; break; out[out.length] = {t:'s', v:o}; break;
} }
/* falls through */ /* falls through */
@ -786,7 +784,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
out[out.length] = {t:'n', v:o}; break; out[out.length] = {t:'n', v:o}; break;
case '?': case '?':
o = c; while(fmt.charAt(++i) === c) o+=c; o = c; while(fmt.charAt(++i) === c) o+=c;
q={t:c, v:o}; out[out.length] = q; lst = c; break; out[out.length] = {t:c, v:o}; lst = c; break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // ** case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break; case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
@ -937,7 +935,7 @@ function chkcond(v, rr) {
} }
return false; return false;
} }
function choose_fmt(f/*:string*/, v) { function choose_fmt(f/*:string*/, v/*:any*/) {
var fmt = split_fmt(f); var fmt = split_fmt(f);
var l = fmt.length, lat = fmt[l-1].indexOf("@"); var l = fmt.length, lat = fmt[l-1].indexOf("@");
if(l<4 && lat>-1) --l; if(l<4 && lat>-1) --l;
@ -972,18 +970,38 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
break; break;
} }
if(isgeneral(sfmt,0)) return general_fmt(v, o); if(isgeneral(sfmt,0)) return general_fmt(v, o);
if(v instanceof Date) v = datenum_local(v, o.date1904);
var f = choose_fmt(sfmt, v); var f = choose_fmt(sfmt, v);
if(isgeneral(f[1])) return general_fmt(v, o); if(isgeneral(f[1])) return general_fmt(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE"; if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
else if(v === "" || v == null) return ""; else if(v === "" || v == null) return "";
return eval_fmt(f[1], v, o, f[0]); return eval_fmt(f[1], v, o, f[0]);
} }
function load_entry(fmt/*:string*/, idx/*:?number*/)/*:number*/ {
if(typeof idx != 'number') {
idx = +idx || -1;
/*::if(typeof idx != 'number') return 0x188; */
for(var i = 0; i < 0x0188; ++i) {
/*::if(typeof idx != 'number') return 0x188; */
if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
if(table_fmt[i] == fmt) { idx = i; break; }
}
/*::if(typeof idx != 'number') return 0x188; */
if(idx < 0) idx = 0x187;
}
/*::if(typeof idx != 'number') return 0x188; */
table_fmt[idx] = fmt;
return idx;
}
SSF.load = load_entry;
SSF._table = table_fmt; SSF._table = table_fmt;
SSF.load = function load_entry(fmt/*:string*/, idx/*:number*/) { table_fmt[idx] = fmt; }; SSF.get_table = function get_table()/*:SSFTable*/ { return table_fmt; };
SSF.format = format; SSF.load_table = function load_table(tbl/*:SSFTable*/)/*:void*/ {
SSF.get_table = function get_table() { return table_fmt; }; for(var i=0; i!=0x0188; ++i)
SSF.load_table = function load_table(tbl/*:{[n:number]:string}*/) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); }; if(tbl[i] !== undefined) load_entry(tbl[i], i);
};
SSF.init_table = init_table; SSF.init_table = init_table;
SSF.format = format;
}; };
make_ssf(SSF); make_ssf(SSF);
/* map from xlml named formats to SSF TODO: localize */ /* map from xlml named formats to SSF TODO: localize */
@ -1053,20 +1071,25 @@ declare var chr1:any;
/*jshint eqnull:true */ /*jshint eqnull:true */
/*:: /*::
declare var DO_NOT_EXPORT_CFB:any; declare var DO_NOT_EXPORT_CFB:?boolean;
type SectorEntry = any; type SectorEntry = {
name?:string;
nodes?:Array<number>;
data:RawBytes;
};
type SectorList = { type SectorList = {
(k:string|number):SectorEntry; [k:string|number]:SectorEntry;
name:?string; name:?string;
fat_addrs:any; fat_addrs:Array<number>;
ssz:number; ssz:number;
} }
type CFBFiles = {[n:string]:CFBEntry};
*/ */
/* [MS-CFB] v20130118 */ /* [MS-CFB] v20130118 */
var CFB = (function _CFB(){ var CFB = (function _CFB(){
var exports = {}; var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '0.11.1'; exports.version = '0.12.0';
function parse(file) { function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
var mver = 3; // major version var mver = 3; // major version
var ssz = 512; // sector size var ssz = 512; // sector size
var nmfs = 0; // number of mini FAT sectors var nmfs = 0; // number of mini FAT sectors
@ -1075,10 +1098,10 @@ var dir_start = 0; // first directory sector location
var minifat_start = 0; // first mini FAT sector location var minifat_start = 0; // first mini FAT sector location
var difat_start = 0; // first mini FAT sector location var difat_start = 0; // first mini FAT sector location
var fat_addrs = []; // locations of FAT sectors var fat_addrs/*:Array<number>*/ = []; // locations of FAT sectors
/* [MS-CFB] 2.2 Compound File Header */ /* [MS-CFB] 2.2 Compound File Header */
var blob/*:any*/ = file.slice(0,512); var blob/*:CFBlob*/ = /*::(*/file.slice(0,512)/*:: :any)*/;
prep_blob(blob, 0); prep_blob(blob, 0);
/* major version */ /* major version */
@ -1090,14 +1113,14 @@ switch(mver) {
} }
/* reprocess header */ /* reprocess header */
if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); } if(ssz !== 512) { blob = /*::(*/file.slice(0,ssz)/*:: :any)*/; prep_blob(blob, 28 /* blob.l */); }
/* Save header for final object */ /* Save header for final object */
var header = file.slice(0,ssz); var header/*:RawBytes*/ = file.slice(0,ssz);
check_shifts(blob, mver); check_shifts(blob, mver);
// Number of Directory Sectors // Number of Directory Sectors
var nds = blob.read_shift(4, 'i'); var nds/*:number*/ = blob.read_shift(4, 'i');
if(mver === 3 && nds !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + nds); if(mver === 3 && nds !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + nds);
// Number of FAT Sectors // Number of FAT Sectors
@ -1126,14 +1149,14 @@ difat_start = blob.read_shift(4, 'i');
ndfs = blob.read_shift(4, 'i'); ndfs = blob.read_shift(4, 'i');
// Grab FAT Sector Locations // Grab FAT Sector Locations
for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */ for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
q = blob.read_shift(4, 'i'); q = blob.read_shift(4, 'i');
if(q<0) break; if(q<0) break;
fat_addrs[j] = q; fat_addrs[j] = q;
} }
/** Break the file up into sectors */ /** Break the file up into sectors */
var sectors = sectorify(file, ssz); var sectors/*:Array<RawBytes>*/ = sectorify(file, ssz);
sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs); sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs);
@ -1147,13 +1170,12 @@ sector_list.fat_addrs = fat_addrs;
sector_list.ssz = ssz; sector_list.ssz = ssz;
/* [MS-CFB] 2.6.1 Compound File Directory Entry */ /* [MS-CFB] 2.6.1 Compound File Directory Entry */
var files = {}, Paths/*:any*/ = [], FileIndex = [], FullPaths = [], FullPathDir = {}; var files/*:CFBFiles*/ = {}, Paths/*:Array<string>*/ = [], FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [], FullPathDir = {};
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex); read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
build_full_paths(FileIndex, FullPathDir, FullPaths, Paths); build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
var root_name = Paths.shift(); var root_name/*:string*/ = Paths.shift();
Paths.root = root_name;
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name); var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name);
@ -1168,7 +1190,7 @@ return {
} // parse } // parse
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */ /* [MS-CFB] 2.2 Compound File Header -- read up to major version */
function check_get_mver(blob) { function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
// header signature 8 // header signature 8
blob.chk(HEADER_SIGNATURE, 'Header Signature: '); blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
@ -1176,11 +1198,11 @@ function check_get_mver(blob) {
blob.chk(HEADER_CLSID, 'CLSID: '); blob.chk(HEADER_CLSID, 'CLSID: ');
// minor version 2 // minor version 2
var mver = blob.read_shift(2, 'u'); var mver/*:number*/ = blob.read_shift(2, 'u');
return [blob.read_shift(2,'u'), mver]; return [blob.read_shift(2,'u'), mver];
} }
function check_shifts(blob, mver) { function check_shifts(blob/*:CFBlob*/, mver/*:number*/)/*:void*/ {
var shift = 0x09; var shift = 0x09;
// Byte Order // Byte Order
@ -1202,18 +1224,18 @@ function check_shifts(blob, mver) {
} }
/** Break the file up into sectors */ /** Break the file up into sectors */
function sectorify(file, ssz) { function sectorify(file/*:RawBytes*/, ssz/*:number*/)/*:Array<RawBytes>*/ {
var nsectors = Math.ceil(file.length/ssz)-1; var nsectors = Math.ceil(file.length/ssz)-1;
var sectors = new Array(nsectors); var sectors/*:Array<RawBytes>*/ = [];
for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
sectors[nsectors-1] = file.slice(nsectors*ssz); sectors[nsectors-1] = file.slice(nsectors*ssz);
return sectors; return sectors;
} }
/* [MS-CFB] 2.6.4 Red-Black Tree */ /* [MS-CFB] 2.6.4 Red-Black Tree */
function build_full_paths(FI, FPD, FP, Paths) { function build_full_paths(FI/*:CFBFileIndex*/, FPD/*:CFBFullPathDir*/, FP/*:Array<string>*/, Paths/*:Array<string>*/)/*:void*/ {
var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length; var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
var dad = new Array(pl), q = new Array(pl); var dad/*:Array<number>*/ = [], q/*:Array<number>*/ = [];
for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; } for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
@ -1252,17 +1274,17 @@ function build_full_paths(FI, FPD, FP, Paths) {
} }
/* [MS-CFB] 2.6.4 */ /* [MS-CFB] 2.6.4 */
function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { function make_find_path(FullPaths/*:Array<string>*/, Paths/*:Array<string>*/, FileIndex/*:CFBFileIndex*/, files/*:CFBFiles*/, root_name/*:string*/)/*:CFBFindPath*/ {
var UCFullPaths = new Array(FullPaths.length); var UCFullPaths/*:Array<string>*/ = [];
var UCPaths = new Array(Paths.length), i; var UCPaths/*:Array<string>*/ = [], i = 0;
for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
return function find_path(path/*:string*/) { return function find_path(path/*:string*/)/*:?CFBEntry*/ {
var k; var k/*:boolean*/ = false;
if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; }
else k = path.indexOf("/") !== -1; else k = path.indexOf("/") !== -1;
var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); var UCPath/*:string*/ = path.toUpperCase().replace(chr0,'').replace(chr1,'!');
var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
if(w === -1) return null; if(w === -1) return null;
return k === true ? FileIndex[w] : files[Paths[w]]; return k === true ? FileIndex[w] : files[Paths[w]];
}; };
@ -1270,8 +1292,8 @@ function make_find_path(FullPaths, Paths, FileIndex, files, root_name) {
/** Chase down the rest of the DIFAT chain to build a comprehensive list /** Chase down the rest of the DIFAT chain to build a comprehensive list
DIFAT chains by storing the next sector number as the last 32 bytes */ DIFAT chains by storing the next sector number as the last 32 bytes */
function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/, ssz/*:number*/, fat_addrs)/*:void*/ {
var q; var q/*:number*/ = ENDOFCHAIN;
if(idx === ENDOFCHAIN) { if(idx === ENDOFCHAIN) {
if(cnt !== 0) throw new Error("DIFAT chain shorter than expected"); if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
} else if(idx !== -1 /*FREESECT*/) { } else if(idx !== -1 /*FREESECT*/) {
@ -1286,13 +1308,11 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
} }
/** Follow the linked list of sectors for a given starting point */ /** Follow the linked list of sectors for a given starting point */
function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { function get_sector_list(sectors/*:Array<RawBytes>*/, start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/, chkd/*:?Array<boolean>*/)/*:SectorEntry*/ {
var sl = sectors.length; var sl = sectors.length;
var buf, buf_chain; var buf/*:Array<number>*/ = [], buf_chain/*:Array<any>*/ = [];
if(!chkd) chkd = new Array(sl); if(!chkd) chkd = [];
var modulus = ssz - 1, j, jj; var modulus = ssz - 1, j = 0, jj = 0;
buf = [];
buf_chain = [];
for(j=start; j>=0;) { for(j=start; j>=0;) {
chkd[j] = true; chkd[j] = true;
buf[buf.length] = j; buf[buf.length] = j;
@ -1307,44 +1327,43 @@ function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
} }
/** Chase down the sector linked lists */ /** Chase down the sector linked lists */
function make_sector_list(sectors, dir_start, fat_addrs, ssz/*:number*/)/*:any*/ { function make_sector_list(sectors/*:Array<RawBytes>*/, dir_start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/)/*:SectorList*/ {
var sl = sectors.length, sector_list = new Array(sl); var sl = sectors.length, sector_list/*:SectorList*/ = ([]/*:any*/);
var chkd = new Array(sl), buf, buf_chain; var chkd/*:Array<boolean>*/ = [], buf/*:Array<number>*/ = [], buf_chain/*:Array<RawBytes>*/ = [];
var modulus = ssz - 1, i, j, k, jj; var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
for(i=0; i < sl; ++i) { for(i=0; i < sl; ++i) {
buf = []; buf = ([]/*:Array<number>*/);
k = (i + dir_start); if(k >= sl) k-=sl; k = (i + dir_start); if(k >= sl) k-=sl;
if(chkd[k] === true) continue; if(chkd[k]) continue;
buf_chain = []; buf_chain = [];
for(j=k; j>=0;) { for(j=k; j>=0;) {
chkd[j] = true; chkd[j] = true;
buf[buf.length] = j; buf[buf.length] = j;
buf_chain.push(sectors[j]); buf_chain.push(sectors[j]);
var addr = fat_addrs[Math.floor(j*4/ssz)]; var addr/*:number*/ = fat_addrs[Math.floor(j*4/ssz)];
jj = ((j*4) & modulus); jj = ((j*4) & modulus);
if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz); if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
if(!sectors[addr]) break; if(!sectors[addr]) break;
j = __readInt32LE(sectors[addr], jj); j = __readInt32LE(sectors[addr], jj);
} }
sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])}; sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])}/*:SectorEntry*/);
} }
return sector_list; return sector_list;
} }
/* [MS-CFB] 2.6.1 Compound File Directory Entry */ /* [MS-CFB] 2.6.1 Compound File Directory Entry */
function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) { function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array<RawBytes>*/, Paths/*:Array<string>*/, nmfs, files, FileIndex) {
var blob;
var minifat_store = 0, pl = (Paths.length?2:0); var minifat_store = 0, pl = (Paths.length?2:0);
var sector = sector_list[dir_start].data; var sector = sector_list[dir_start].data;
var i = 0, namelen = 0, name, o, ctime, mtime; var i = 0, namelen = 0, name;
for(; i < sector.length; i+= 128) { for(; i < sector.length; i+= 128) {
blob = sector.slice(i, i+128); var blob/*:CFBlob*/ = /*::(*/sector.slice(i, i+128)/*:: :any)*/;
prep_blob(blob, 64); prep_blob(blob, 64);
namelen = blob.read_shift(2); namelen = blob.read_shift(2);
if(namelen === 0) continue; if(namelen === 0) continue;
name = __utf16le(blob,0,namelen-pl); name = __utf16le(blob,0,namelen-pl);
Paths.push(name); Paths.push(name);
o = ({ var o/*:CFBEntry*/ = ({
name: name, name: name,
type: blob.read_shift(1), type: blob.read_shift(1),
color: blob.read_shift(1), color: blob.read_shift(1),
@ -1352,16 +1371,14 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
R: blob.read_shift(4, 'i'), R: blob.read_shift(4, 'i'),
C: blob.read_shift(4, 'i'), C: blob.read_shift(4, 'i'),
clsid: blob.read_shift(16), clsid: blob.read_shift(16),
state: blob.read_shift(4, 'i') state: blob.read_shift(4, 'i'),
}/*:any*/); start: 0,
ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); size: 0
if(ctime !== 0) { });
o.ctime = ctime; o.ct = read_date(blob, blob.l-8); var ctime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
} if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); var mtime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
if(mtime !== 0) { if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
o.mtime = mtime; o.mt = read_date(blob, blob.l-8);
}
o.start = blob.read_shift(4, 'i'); o.start = blob.read_shift(4, 'i');
o.size = blob.read_shift(4, 'i'); o.size = blob.read_shift(4, 'i');
if(o.type === 5) { /* root */ if(o.type === 5) { /* root */
@ -1372,12 +1389,12 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
o.storage = 'fat'; o.storage = 'fat';
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
sector_list[o.start].name = o.name; sector_list[o.start].name = o.name;
o.content = sector_list[o.start].data.slice(0,o.size); o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/);
prep_blob(o.content, 0); prep_blob(o.content, 0);
} else { } else {
o.storage = 'minifat'; o.storage = 'minifat';
if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) { if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) {
o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size); o.content = (sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size)/*:any*/);
prep_blob(o.content, 0); prep_blob(o.content, 0);
} }
} }
@ -1386,23 +1403,23 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
} }
} }
function read_date(blob, offset) { 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); return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
} }
var fs; var fs/*:: = require('fs'); */;
function readFileSync(filename/*:string*/, options/*:any*/) { function readFileSync(filename/*:string*/, options/*:CFBReadOpts*/) {
if(fs === undefined) fs = require('fs'); if(fs == null) fs = require('fs');
return parse(fs.readFileSync(filename), options); return parse(fs.readFileSync(filename), options);
} }
function readSync(blob/*:any*/, options/*:any*/) { function readSync(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
switch(options !== undefined && options.type !== undefined ? options.type : "base64") { switch(options && options.type || "base64") {
case "file": return readFileSync(blob, options); case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return readFileSync(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options); case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options);
case "binary": return parse(s2a(blob), options); case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options);
} }
return parse(blob); return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options);
} }
/** CFB Constants */ /** CFB Constants */

235
xlsx.js

@ -6,7 +6,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false */ /*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {}; var XLSX = {};
(function make_xlsx(XLSX){ (function make_xlsx(XLSX){
XLSX.version = '0.10.8'; XLSX.version = '0.10.9';
var current_codepage = 1200; var current_codepage = 1200;
/*global cptable:true */ /*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') { if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -110,9 +110,9 @@ var bconcat = function(bufs) { return [].concat.apply([], bufs); };
var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/; var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/;
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
/*jshint -W041 */ /*jshint -W041 */
var SSF = {}; var SSF = ({});
var make_ssf = function make_ssf(SSF){ var make_ssf = function make_ssf(SSF){
SSF.version = '0.9.4'; SSF.version = '0.10.0';
function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; } function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; } function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;} function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@ -123,16 +123,6 @@ function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
var p2_32 = Math.pow(2,32); var p2_32 = Math.pow(2,32);
function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); } function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
function isgeneral(s, i) { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; } function isgeneral(s, i) { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
/* Options */
var opts_fmt = [
["date1904", 0],
["output", ""],
["WTF", false]
];
function fixopts(o){
for(var y = 0; y != opts_fmt.length; ++y) if(o[opts_fmt[y][0]]===undefined) o[opts_fmt[y][0]]=opts_fmt[y][1];
}
SSF.opts = opts_fmt;
var days = [ var days = [
['Sun', 'Sunday'], ['Sun', 'Sunday'],
['Mon', 'Monday'], ['Mon', 'Monday'],
@ -211,7 +201,47 @@ function frac(x, D, mixed) {
var q = Math.floor(sgn * P/Q); var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q]; return [q, sgn*P - q*Q, Q];
} }
function general_fmt_int(v) { return ""+v; } function parse_date_code(v,opts,b2) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
if(opts && opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
var basedate = new Date(1899, 11, 31, 0, 0, 0);
var dnthresh = basedate.getTime();
var base1904 = new Date(1900, 2, 1, 0, 0, 0);
function datenum_local(v, date1904) {
var epoch = v.getTime();
if(date1904) epoch -= 1461*24*60*60*1000;
else if(v >= base1904) epoch += 24*60*60*1000;
return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
}
function general_fmt_int(v) { return v.toString(10); }
SSF._general_int = general_fmt_int; SSF._general_int = general_fmt_int;
var general_fmt_num = (function make_general_fmt_num() { var general_fmt_num = (function make_general_fmt_num() {
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/; var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
@ -242,50 +272,20 @@ return function general_fmt_num(v) {
return gfn5(gfn4(o)); return gfn5(gfn4(o));
};})(); };})();
SSF._general_num = general_fmt_num; SSF._general_num = general_fmt_num;
function general_fmt(v) { function general_fmt(v, opts) {
switch(typeof v) { switch(typeof v) {
case 'string': return v; case 'string': return v;
case 'boolean': return v ? "TRUE" : "FALSE"; case 'boolean': return v ? "TRUE" : "FALSE";
case 'number': return (v|0) === v ? general_fmt_int(v/*, opts*/) : general_fmt_num(v/*, opts*/); case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
case 'undefined': return ""; case 'undefined': return "";
case 'object': if(v == null) return ""; case 'object':
if(v == null) return "";
if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
} }
throw new Error("unsupported value in General format: " + v); throw new Error("unsupported value in General format: " + v);
} }
SSF._general = general_fmt; SSF._general = general_fmt;
function fix_hijri(/*date, o*/) { return 0; } function fix_hijri() { return 0; }
function parse_date_code(v,opts,b2) {
if(v > 2958465 || v < 0) return null;
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
if(Math.abs(out.u) < 1e-6) out.u = 0;
fixopts(opts != null ? opts : (opts=[]));
if(opts.date1904) date += 1462;
if(out.u > 0.9999) {
out.u = 0;
if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
}
if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
else {
if(date > 60) --date;
/* 1 = Jan 1 1900 in Gregorian */
var d = new Date(1900, 0, 1);
d.setDate(d.getDate() + date - 1);
dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
dow = d.getDay();
if(date < 60) dow = (dow + 6) % 7;
if(b2) dow = fix_hijri(d, dout);
}
out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
out.S = time % 60; time = Math.floor(time / 60);
out.M = time % 60; time = Math.floor(time / 60);
out.H = time;
out.q = dow;
return out;
}
SSF.parse_date_code = parse_date_code;
/*jshint -W086 */ /*jshint -W086 */
function write_date(type, fmt, val, ss0) { function write_date(type, fmt, val, ss0) {
var o="", ss=0, tt=0, y = val.y, out, outl = 0; var o="", ss=0, tt=0, y = val.y, out, outl = 0;
@ -327,22 +327,16 @@ function write_date(type, fmt, val, ss0) {
default: throw 'bad minute format: ' + fmt; default: throw 'bad minute format: ' + fmt;
} break; } break;
case 115: /* 's' seconds */ case 115: /* 's' seconds */
if(val.u === 0) switch(fmt) { if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
case 's': case 'ss': return pad0(val.S, fmt.length); if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
case '.0': case '.00': case '.000':
}
switch(fmt) {
case 's': case 'ss': case '.0': case '.00': case '.000':
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100; if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
else tt = ss0 === 1 ? 10 : 1; else tt = ss0 === 1 ? 10 : 1;
ss = Math.round((tt)*(val.S + val.u)); ss = Math.round((tt)*(val.S + val.u));
if(ss >= 60*tt) ss = 0; if(ss >= 60*tt) ss = 0;
if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt; if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
o = pad0(ss,2 + ss0); o = pad0(ss,2 + ss0);
if(fmt === 'ss') return o.substr(0,2); if(fmt === 'ss') return o.substr(0,2);
return "." + o.substr(2,fmt.length-1); return "." + o.substr(2,fmt.length-1);
default: throw 'bad second format: ' + fmt;
}
case 90: /* 'Z' absolute time */ case 90: /* 'Z' absolute time */
switch(fmt) { switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break; case '[h]': case '[hh]': out = val.D*24+val.H; break;
@ -357,9 +351,10 @@ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
} }
/*jshint +W086 */ /*jshint +W086 */
function commaify(s) { function commaify(s) {
if(s.length <= 3) return s; var w = 3;
var j = (s.length % 3), o = s.substr(0,j); if(s.length <= w) return s;
for(; j!=s.length; j+=3) o+=(o.length > 0 ? "," : "") + s.substr(j,3); var j = (s.length % w), o = s.substr(0,j);
for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
return o; return o;
} }
var write_num = (function make_write_num(){ var write_num = (function make_write_num(){
@ -698,7 +693,7 @@ function fmt_is_date(fmt) {
} }
SSF.is_date = fmt_is_date; SSF.is_date = fmt_is_date;
function eval_fmt(fmt, v, opts, flen) { function eval_fmt(fmt, v, opts, flen) {
var out = [], o = "", i = 0, c = "", lst='t', q, dt, j, cc; var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
var hr='H'; var hr='H';
/* Tokenize */ /* Tokenize */
while(i < fmt.length) { while(i < fmt.length) {
@ -726,12 +721,12 @@ function eval_fmt(fmt, v, opts, flen) {
case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
if(v < 0) return ""; if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; } if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c; o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
if(c === 'h') c = hr; if(c === 'h') c = hr;
out[out.length] = {t:c, v:o}; lst = c; break; out[out.length] = {t:c, v:o}; lst = c; break;
case 'A': case 'a': case 'A': case 'a':
q={t:c, v:c}; var q={t:c, v:c};
if(dt==null) dt=parse_date_code(v, opts); if(dt==null) dt=parse_date_code(v, opts);
if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;} if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; } else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
@ -754,7 +749,7 @@ function eval_fmt(fmt, v, opts, flen) {
/* Numbers */ /* Numbers */
case '.': case '.':
if(dt != null) { if(dt != null) {
o = c; while((c=fmt.charAt(++i)) === "0") o += c; o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
out[out.length] = {t:'s', v:o}; break; out[out.length] = {t:'s', v:o}; break;
} }
/* falls through */ /* falls through */
@ -763,7 +758,7 @@ function eval_fmt(fmt, v, opts, flen) {
out[out.length] = {t:'n', v:o}; break; out[out.length] = {t:'n', v:o}; break;
case '?': case '?':
o = c; while(fmt.charAt(++i) === c) o+=c; o = c; while(fmt.charAt(++i) === c) o+=c;
q={t:c, v:o}; out[out.length] = q; lst = c; break; out[out.length] = {t:c, v:o}; lst = c; break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // ** case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break; case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
@ -946,18 +941,34 @@ function format(fmt,v,o) {
break; break;
} }
if(isgeneral(sfmt,0)) return general_fmt(v, o); if(isgeneral(sfmt,0)) return general_fmt(v, o);
if(v instanceof Date) v = datenum_local(v, o.date1904);
var f = choose_fmt(sfmt, v); var f = choose_fmt(sfmt, v);
if(isgeneral(f[1])) return general_fmt(v, o); if(isgeneral(f[1])) return general_fmt(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE"; if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
else if(v === "" || v == null) return ""; else if(v === "" || v == null) return "";
return eval_fmt(f[1], v, o, f[0]); return eval_fmt(f[1], v, o, f[0]);
} }
function load_entry(fmt, idx) {
if(typeof idx != 'number') {
idx = +idx || -1;
for(var i = 0; i < 0x0188; ++i) {
if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
if(table_fmt[i] == fmt) { idx = i; break; }
}
if(idx < 0) idx = 0x187;
}
table_fmt[idx] = fmt;
return idx;
}
SSF.load = load_entry;
SSF._table = table_fmt; SSF._table = table_fmt;
SSF.load = function load_entry(fmt, idx) { table_fmt[idx] = fmt; };
SSF.format = format;
SSF.get_table = function get_table() { return table_fmt; }; SSF.get_table = function get_table() { return table_fmt; };
SSF.load_table = function load_table(tbl) { for(var i=0; i!=0x0188; ++i) if(tbl[i] !== undefined) SSF.load(tbl[i], i); }; SSF.load_table = function load_table(tbl) {
for(var i=0; i!=0x0188; ++i)
if(tbl[i] !== undefined) load_entry(tbl[i], i);
};
SSF.init_table = init_table; SSF.init_table = init_table;
SSF.format = format;
}; };
make_ssf(SSF); make_ssf(SSF);
/* map from xlml named formats to SSF TODO: localize */ /* map from xlml named formats to SSF TODO: localize */
@ -1015,8 +1026,8 @@ var DO_NOT_EXPORT_CFB = true;
/* [MS-CFB] v20130118 */ /* [MS-CFB] v20130118 */
var CFB = (function _CFB(){ var CFB = (function _CFB(){
var exports = {}; var exports = {};
exports.version = '0.11.1'; exports.version = '0.12.0';
function parse(file) { function parse(file, options) {
var mver = 3; // major version var mver = 3; // major version
var ssz = 512; // sector size var ssz = 512; // sector size
var nmfs = 0; // number of mini FAT sectors var nmfs = 0; // number of mini FAT sectors
@ -1076,7 +1087,7 @@ difat_start = blob.read_shift(4, 'i');
ndfs = blob.read_shift(4, 'i'); ndfs = blob.read_shift(4, 'i');
// Grab FAT Sector Locations // Grab FAT Sector Locations
for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */ for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
q = blob.read_shift(4, 'i'); q = blob.read_shift(4, 'i');
if(q<0) break; if(q<0) break;
fat_addrs[j] = q; fat_addrs[j] = q;
@ -1103,7 +1114,6 @@ read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
build_full_paths(FileIndex, FullPathDir, FullPaths, Paths); build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
var root_name = Paths.shift(); var root_name = Paths.shift();
Paths.root = root_name;
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name); var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name);
@ -1154,7 +1164,7 @@ function check_shifts(blob, mver) {
/** Break the file up into sectors */ /** Break the file up into sectors */
function sectorify(file, ssz) { function sectorify(file, ssz) {
var nsectors = Math.ceil(file.length/ssz)-1; var nsectors = Math.ceil(file.length/ssz)-1;
var sectors = new Array(nsectors); var sectors = [];
for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
sectors[nsectors-1] = file.slice(nsectors*ssz); sectors[nsectors-1] = file.slice(nsectors*ssz);
return sectors; return sectors;
@ -1163,7 +1173,7 @@ function sectorify(file, ssz) {
/* [MS-CFB] 2.6.4 Red-Black Tree */ /* [MS-CFB] 2.6.4 Red-Black Tree */
function build_full_paths(FI, FPD, FP, Paths) { function build_full_paths(FI, FPD, FP, Paths) {
var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length; var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
var dad = new Array(pl), q = new Array(pl); var dad = [], q = [];
for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; } for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
@ -1203,12 +1213,12 @@ function build_full_paths(FI, FPD, FP, Paths) {
/* [MS-CFB] 2.6.4 */ /* [MS-CFB] 2.6.4 */
function make_find_path(FullPaths, Paths, FileIndex, files, root_name) { function make_find_path(FullPaths, Paths, FileIndex, files, root_name) {
var UCFullPaths = new Array(FullPaths.length); var UCFullPaths = [];
var UCPaths = new Array(Paths.length), i; var UCPaths = [], i = 0;
for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!'); for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
return function find_path(path) { return function find_path(path) {
var k; var k = false;
if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; } if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; }
else k = path.indexOf("/") !== -1; else k = path.indexOf("/") !== -1;
var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!'); var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!');
@ -1221,7 +1231,7 @@ function make_find_path(FullPaths, Paths, FileIndex, files, root_name) {
/** Chase down the rest of the DIFAT chain to build a comprehensive list /** Chase down the rest of the DIFAT chain to build a comprehensive list
DIFAT chains by storing the next sector number as the last 32 bytes */ DIFAT chains by storing the next sector number as the last 32 bytes */
function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) { function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
var q; var q = ENDOFCHAIN;
if(idx === ENDOFCHAIN) { if(idx === ENDOFCHAIN) {
if(cnt !== 0) throw new Error("DIFAT chain shorter than expected"); if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
} else if(idx !== -1 /*FREESECT*/) { } else if(idx !== -1 /*FREESECT*/) {
@ -1238,11 +1248,9 @@ function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
/** Follow the linked list of sectors for a given starting point */ /** Follow the linked list of sectors for a given starting point */
function get_sector_list(sectors, start, fat_addrs, ssz, chkd) { function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
var sl = sectors.length; var sl = sectors.length;
var buf, buf_chain; var buf = [], buf_chain = [];
if(!chkd) chkd = new Array(sl); if(!chkd) chkd = [];
var modulus = ssz - 1, j, jj; var modulus = ssz - 1, j = 0, jj = 0;
buf = [];
buf_chain = [];
for(j=start; j>=0;) { for(j=start; j>=0;) {
chkd[j] = true; chkd[j] = true;
buf[buf.length] = j; buf[buf.length] = j;
@ -1258,13 +1266,13 @@ function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
/** Chase down the sector linked lists */ /** Chase down the sector linked lists */
function make_sector_list(sectors, dir_start, fat_addrs, ssz) { function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
var sl = sectors.length, sector_list = new Array(sl); var sl = sectors.length, sector_list = ([]);
var chkd = new Array(sl), buf, buf_chain; var chkd = [], buf = [], buf_chain = [];
var modulus = ssz - 1, i, j, k, jj; var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
for(i=0; i < sl; ++i) { for(i=0; i < sl; ++i) {
buf = []; buf = ([]);
k = (i + dir_start); if(k >= sl) k-=sl; k = (i + dir_start); if(k >= sl) k-=sl;
if(chkd[k] === true) continue; if(chkd[k]) continue;
buf_chain = []; buf_chain = [];
for(j=k; j>=0;) { for(j=k; j>=0;) {
chkd[j] = true; chkd[j] = true;
@ -1276,25 +1284,24 @@ function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
if(!sectors[addr]) break; if(!sectors[addr]) break;
j = __readInt32LE(sectors[addr], jj); j = __readInt32LE(sectors[addr], jj);
} }
sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])}; sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
} }
return sector_list; return sector_list;
} }
/* [MS-CFB] 2.6.1 Compound File Directory Entry */ /* [MS-CFB] 2.6.1 Compound File Directory Entry */
function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) { function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) {
var blob;
var minifat_store = 0, pl = (Paths.length?2:0); var minifat_store = 0, pl = (Paths.length?2:0);
var sector = sector_list[dir_start].data; var sector = sector_list[dir_start].data;
var i = 0, namelen = 0, name, o, ctime, mtime; var i = 0, namelen = 0, name;
for(; i < sector.length; i+= 128) { for(; i < sector.length; i+= 128) {
blob = sector.slice(i, i+128); var blob = sector.slice(i, i+128);
prep_blob(blob, 64); prep_blob(blob, 64);
namelen = blob.read_shift(2); namelen = blob.read_shift(2);
if(namelen === 0) continue; if(namelen === 0) continue;
name = __utf16le(blob,0,namelen-pl); name = __utf16le(blob,0,namelen-pl);
Paths.push(name); Paths.push(name);
o = ({ var o = ({
name: name, name: name,
type: blob.read_shift(1), type: blob.read_shift(1),
color: blob.read_shift(1), color: blob.read_shift(1),
@ -1302,16 +1309,14 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
R: blob.read_shift(4, 'i'), R: blob.read_shift(4, 'i'),
C: blob.read_shift(4, 'i'), C: blob.read_shift(4, 'i'),
clsid: blob.read_shift(16), clsid: blob.read_shift(16),
state: blob.read_shift(4, 'i') state: blob.read_shift(4, 'i'),
start: 0,
size: 0
}); });
ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2); var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
if(ctime !== 0) { if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
o.ctime = ctime; o.ct = read_date(blob, blob.l-8); var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
} if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
if(mtime !== 0) {
o.mtime = mtime; o.mt = read_date(blob, blob.l-8);
}
o.start = blob.read_shift(4, 'i'); o.start = blob.read_shift(4, 'i');
o.size = blob.read_shift(4, 'i'); o.size = blob.read_shift(4, 'i');
if(o.type === 5) { /* root */ if(o.type === 5) { /* root */
@ -1322,12 +1327,12 @@ function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, Fil
o.storage = 'fat'; o.storage = 'fat';
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz); if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
sector_list[o.start].name = o.name; sector_list[o.start].name = o.name;
o.content = sector_list[o.start].data.slice(0,o.size); o.content = (sector_list[o.start].data.slice(0,o.size));
prep_blob(o.content, 0); prep_blob(o.content, 0);
} else { } else {
o.storage = 'minifat'; o.storage = 'minifat';
if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) { if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) {
o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size); o.content = (sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size));
prep_blob(o.content, 0); prep_blob(o.content, 0);
} }
} }
@ -1342,17 +1347,17 @@ function read_date(blob, offset) {
var fs; var fs;
function readFileSync(filename, options) { function readFileSync(filename, options) {
if(fs === undefined) fs = require('fs'); if(fs == null) fs = require('fs');
return parse(fs.readFileSync(filename), options); return parse(fs.readFileSync(filename), options);
} }
function readSync(blob, options) { function readSync(blob, options) {
switch(options !== undefined && options.type !== undefined ? options.type : "base64") { switch(options && options.type || "base64") {
case "file": return readFileSync(blob, options); case "file": return readFileSync(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options); case "base64": return parse(s2a(Base64.decode(blob)), options);
case "binary": return parse(s2a(blob), options); case "binary": return parse(s2a(blob), options);
} }
return parse(blob); return parse(blob, options);
} }
/** CFB Constants */ /** CFB Constants */