version bump 0.10.1: json_to_sheet, misc fmts

- SYLK auto fail into DSV on bad header (fixes #651 h/t @mmancosu)
- CSV automatically wrap `ID` in quotes
- json_to_sheet (see issue #610)
This commit is contained in:
SheetJS 2017-05-11 14:23:21 -04:00
parent 7b4bafba49
commit c3c0bc5266
23 changed files with 592 additions and 172 deletions

@ -98,6 +98,7 @@ enhancements, additional features by request, and dedicated support.
* [Output Type](#output-type)
- [Utility Functions](#utility-functions)
* [Array of Arrays Input](#array-of-arrays-input)
* [Array of Objects Input](#array-of-objects-input)
* [HTML Table Input](#html-table-input)
* [Formulae Output](#formulae-output)
* [Delimiter-Separated Output](#delimiter-separated-output)
@ -553,6 +554,7 @@ Utilities are available in the `XLSX.utils` object:
**Importing:**
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
- `json_to_sheet` converts an array of JS objects to a worksheet.
**Exporting:**
@ -560,7 +562,7 @@ Utilities are available in the `XLSX.utils` object:
- `sheet_to_csv` generates delimiter-separated-values output.
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
Exporters are described in the [Utility Functions](#utility-functions) section.
These utilities are described in [Utility Functions](#utility-functions) below.
**Cell and cell address manipulation:**
@ -1394,6 +1396,25 @@ var ws = XLSX.utils.aoa_to_sheet([
```
</details>
### Array of Objects Input
`XLSX.utils.json_to_sheet` takes an array of objects and returns a worksheet
with automatically-generated "headers" based on the keys of the objects.
<details>
<summary><b>Examples</b> (click to show)</summary>
The original sheet cannot be reproduced because JS object keys must be unique.
After replacing the second `e` and `S` with `e_1` and `S_1`:
```js
var ws = XLSX.utils.json_to_sheet([
{S:1,h:2,e:3,e_1:4,t:5,J:6,S_1:7},
{S:2,h:3,e:4,e_1:5,t:6,J:7,S_1:8}
]);
```
</details>
### HTML Table Input
`XLSX.utils.table_to_sheet` takes a table DOM element and returns a worksheet

@ -1 +1 @@
XLSX.version = '0.10.0';
XLSX.version = '0.10.1';

@ -599,3 +599,17 @@ var PRN = (function() {
};
})();
/* Excel defaults to SYLK but warns if data is not valid */
function read_wb_ID(d, opts) {
var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
try {
var out = SYLK.to_workbook(d, o);
o.WTF = OLD_WTF;
return out;
} catch(e) {
o.WTF = OLD_WTF;
if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
return PRN.to_workbook(d, opts);
}
}

@ -49,7 +49,7 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
case 0xD0: return read_cfb(CFB.read(d, o), o);
case 0x09: return parse_xlscfb(s2a(o.type === 'base64' ? Base64.decode(d) : d), o);
case 0x3C: return parse_xlml(d, o);
case 0x49: if(n[1] == 0x44) return SYLK.to_workbook(d, o); break;
case 0x49: if(n[1] == 0x44) return read_wb_ID(d, o); break;
case 0x54: if(n[1] == 0x41 && n[2] == 0x42 && n[3] == 0x4C) return DIF.to_workbook(d, o); break;
case 0x50: if(n[1] == 0x4B && n[2] < 0x20 && n[3] < 0x20) return read_zip(d, o); break;
case 0xEF: return n[3] == 0x3C ? parse_xlml(d, o) : PRN.to_workbook(d,o);

@ -88,8 +88,8 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr
else if(val.v != null) {
isempty = false;
txt = ''+format_cell(val, null, o);
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {
txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
if(txt == "ID") txt = '"ID"';
} else if(val.f != null && !val.F) {
isempty = false;
txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
@ -166,6 +166,30 @@ function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
return cmds;
}
function json_to_sheet(js/*:Array<any>*/, opts)/*:Worksheet*/ {
var o = opts || {};
var ws = ({}/*:any*/);
var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:js.length}}/*:any*/);
var hdr = o.header || [], C = 0;
for(var R = 0; R != js.length; ++R) {
Object.keys(js[R]).filter(function(x) { return js[R].hasOwnProperty(x); }).forEach(function(k) {
if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
var v = js[R][k];
var t = 'z';
if(typeof v == 'number') t = 'n';
else if(typeof v == 'boolean') t = 'b';
else if(typeof v == 'string') t = 's';
else if(v instanceof Date) t = 'd';
ws[encode_cell({c:C,r:R+1})] = {t:t, v:v};
});
}
range.e.c = hdr.length - 1;
for(C = 0; C < hdr.length; ++C) ws[encode_col(C) + "1"] = {t:'s', v:hdr[C]};
ws['!ref'] = encode_range(range);
return ws;
}
var utils = {
encode_col: encode_col,
encode_row: encode_row,
@ -182,6 +206,7 @@ var utils = {
make_json: sheet_to_json,
make_formulae: sheet_to_formulae,
aoa_to_sheet: aoa_to_sheet,
json_to_sheet: json_to_sheet,
table_to_sheet: parse_dom_table,
table_to_book: table_to_book,
sheet_to_csv: sheet_to_csv,

@ -92,11 +92,11 @@ utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:stri
var cell = ws_get_cell_stub(ws, R, C);
cell.t = 'n';
cell.F = rngstr;
delete cell.v;
delete cell.v;
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
}
return ws;
}
};
return utils;
})(utils);

29
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

30
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

404
dist/xlsx.js vendored

@ -6,7 +6,7 @@
/*global exports, module, require:false, process:false, Buffer:false */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.10.0';
XLSX.version = '0.10.1';
var current_codepage = 1200;
/*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -198,7 +198,7 @@ function frac(x, D, mixed) {
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function general_fmt_int(v, opts) { return ""+v; }
function general_fmt_int(v) { return ""+v; }
SSF._general_int = general_fmt_int;
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)$/;
@ -218,11 +218,9 @@ function gfn4(o) {
return o;
}
function gfn5(o) {
//for(var i = 0; i != o.length; ++i) if(o.charCodeAt(i) === 46) return o.replace(gnr2,"").replace(gnr1,".$1");
//return o;
return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
}
return function general_fmt_num(v, opts) {
return function general_fmt_num(v) {
var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
else if(Math.abs(V) <= 9) o = gfn2(v);
@ -231,18 +229,18 @@ return function general_fmt_num(v, opts) {
return gfn5(gfn4(o));
};})();
SSF._general_num = general_fmt_num;
function general_fmt(v, opts) {
function general_fmt(v) {
switch(typeof v) {
case 'string': return v;
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/*, opts*/) : general_fmt_num(v/*, opts*/);
case 'undefined': return "";
case 'object': if(v == null) return "";
}
throw new Error("unsupported value in General format: " + v);
}
SSF._general = general_fmt;
function fix_hijri(date, o) { return 0; }
function fix_hijri(/*date, o*/) { 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;
@ -620,8 +618,7 @@ return "." + $1 + fill("0", r[1].length-$1.length); });
case "##,###":
case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
default:
if(fmt.slice(-3) == ".00") return write_num_int(type, fmt.slice(0,-3), val) + ".00";
if(fmt.slice(-2) == ".0") return write_num_int(type, fmt.slice(0,-2), val) + ".0";
if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
}
throw new Error("unsupported format |" + fmt + "|");
}
@ -630,8 +627,8 @@ return function write_num(type, fmt, val) {
};})();
function split_fmt(fmt) {
var out = [];
var in_str = false, cc;
for(var i = 0, j = 0; i < fmt.length; ++i) switch((cc=fmt.charCodeAt(i))) {
var in_str = false/*, cc*/;
for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
case 34: /* '"' */
in_str = !in_str; break;
case 95: case 42: case 92: /* '_' '*' '\\' */
@ -647,11 +644,11 @@ function split_fmt(fmt) {
SSF._split = split_fmt;
var abstime = /\[[HhMmSs]*\]/;
function fmt_is_date(fmt) {
var i = 0, cc = 0, c = "", o = "";
var i = 0, /*cc = 0,*/ c = "", o = "";
while(i < fmt.length) {
switch((c = fmt.charAt(i))) {
case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
case '"': for(;(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
case '\\': i+=2; break;
case '_': i+=2; break;
case '@': ++i; break;
@ -673,13 +670,13 @@ function fmt_is_date(fmt) {
case '.':
/* falls through */
case '0': case '#':
while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1)){}
while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || (c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1))){/* empty */}
break;
case '?': while(fmt.charAt(++i) === c){} break;
case '?': while(fmt.charAt(++i) === c){/* empty */} break;
case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
case '(': case ')': ++i; break;
case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){} break;
while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
case ' ': ++i; break;
default: ++i; break;
}
@ -749,7 +746,7 @@ function eval_fmt(fmt, v, opts, flen) {
}
/* falls through */
case '0': case '#':
o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
o = c; while((++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) || (c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1)) o += c;
out[out.length] = {t:'n', v:o}; break;
case '?':
o = c; while(fmt.charAt(++i) === c) o+=c;
@ -808,9 +805,9 @@ out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
jj = i+1;
while(out[jj] != null && (
(c=out[jj].t) === "?" || c === "D" ||
(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
(out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
(c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
)) {
out[i].v += out[jj].v;
out[jj] = {v:"", t:";"}; ++jj;
@ -864,7 +861,7 @@ out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
jj = ostr.indexOf(".")+1;
for(i=decpt; i<out.length; ++i) {
if(out[i] == null || 'n?('.indexOf(out[i].t) === -1 && i !== decpt ) continue;
if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
vv = out[i].v.substr(0,j);
for(; j<out[i].v.length; ++j) {
@ -1463,6 +1460,19 @@ function dup(o) {
}
function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
/* TODO: stress test */
function fuzzydate(s) {
var o = new Date(s), n = new Date(NaN);
var y = o.getYear(), m = o.getMonth(), d = o.getDate();
if(isNaN(d)) return n;
if(y < 0 || y > 8099) return n;
if((m > 0 || d > 1) && y != 101) return o;
if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
if(!s.match(/[a-zA-Z]/)) return o;
return n;
}
function getdatastr(data) {
if(!data) return null;
if(data.data) return debom(data.data);
@ -2178,11 +2188,12 @@ function aoa_to_sheet(data, opts) {
for(var C = 0; C != data[R].length; ++C) {
if(typeof data[R][C] === 'undefined') continue;
var cell = ({v: data[R][C] });
if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
if(range.s.r > R) range.s.r = R;
if(range.s.c > C) range.s.c = C;
if(range.e.r < R) range.e.r = R;
if(range.e.c < C) range.e.c = C;
if(cell.v === null) { if(!o.cellStubs) continue; cell.t = 'z'; }
if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.cellStubs) continue; else cell.t = 'z'; }
else if(typeof cell.v === 'number') cell.t = 'n';
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
@ -3162,6 +3173,14 @@ function write_rdf(rdf, opts) {
o.push('</rdf:RDF>');
return o.join("");
}
/* TODO: pull properties */
var write_meta_ods = (function() {
var payload = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>';
return function wmo(wb, opts) {
return payload;
};
})();
/* ECMA-376 Part II 11.1 Core Properties Part */
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
var CORE_PROPS = [
@ -5217,7 +5236,7 @@ function dbf_to_aoa(buf, opts) {
case 'T':
var day = dd.read_shift(4), ms = dd.read_shift(4);
throw new Error(day + " | " + ms);
//out[R][C] = new Date(); // FIXME!!!
//out[R][C] = new Date(); // TODO
//break;
case 'Y': out[R][C] = dd.read(4,'i')/1e4; break;
case '0':
@ -5267,7 +5286,9 @@ var SYLK = (function() {
var Mval = 0, j;
for (; ri !== records.length; ++ri) {
Mval = 0;
var rstr=records[ri].trim(), record=rstr.split(";"), RT=record[0], val;
var rstr=records[ri].trim();
var record=rstr.replace(/;;/g, "\u0001").split(";").map(function(x) { return x.replace(/\u0001/g, ";"); });
var RT=record[0], val;
if(rstr.length > 0) switch(RT) {
case 'ID': break; /* header */
case 'E': break; /* EOF */
@ -5297,17 +5318,19 @@ var SYLK = (function() {
next_cell_format = null;
break;
case 'E':
/* formula = record[rj].substr(1); */
break; /* TODO: formula */
formula = rc_to_a1(record[rj].substr(1), {r:R,c:C});
arr[R][C] = [arr[R][C], formula];
break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
} break;
case 'F':
var F_seen = 0;
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
case 'X': C = parseInt(record[rj].substr(1))-1; break;
case 'X': C = parseInt(record[rj].substr(1))-1; ++F_seen; break;
case 'Y':
R = parseInt(record[rj].substr(1))-1; C = 0;
R = parseInt(record[rj].substr(1))-1; /*C = 0;*/
for(j = arr.length; j <= R; ++j) arr[j] = [];
break;
++F_seen; break;
case 'M': Mval = parseInt(record[rj].substr(1)) / 20; break;
case 'F': break; /* ??? */
case 'P':
@ -5322,14 +5345,19 @@ var SYLK = (function() {
Mval = parseInt(cw[2], 10);
colinfo[j-1] = Mval == 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
} break;
case 'R':
case 'C': /* default column format */
C = parseInt(record[rj].substr(1))-1;
if(!colinfo[C]) colinfo[C] = {};
break;
case 'R': /* row properties */
R = parseInt(record[rj].substr(1))-1;
rowinfo[R] = {};
if(!rowinfo[R]) rowinfo[R] = {};
if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
else if(Mval == 0) rowinfo[R].hidden = true;
break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
} break;
}
if(F_seen < 2) next_cell_format = null; break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
}
@ -5444,7 +5472,7 @@ var DIF = (function() {
if(data === 'TRUE') arr[R][C] = true;
else if(data === 'FALSE') arr[R][C] = false;
else if(+value == +value) arr[R][C] = +value;
else if(!isNaN(new Date(value).getDate())) arr[R][C] = parseDate(value);
else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
else arr[R][C] = value;
++C; break;
case 1:
@ -5576,7 +5604,7 @@ var PRN = (function() {
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = +s)) { cell.t = 'n'; cell.w = s; cell.v = v; }
else if(!isNaN(new Date(s).getDate())) { cell.t = 'd'; cell.v = parseDate(s); }
else if(!isNaN(fuzzydate(s).getDate())) { cell.t = 'd'; cell.v = parseDate(s); }
else {
cell.t = 's';
if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
@ -5607,13 +5635,16 @@ var PRN = (function() {
}
function prn_to_sheet(d, opts) {
var str = "", bytes = firstbyte(d, opts);
switch(opts.type) {
case 'base64': return prn_to_sheet_str(Base64.decode(d), opts);
case 'binary': return prn_to_sheet_str(d, opts);
case 'buffer': return prn_to_sheet_str(d.toString('binary'), opts);
case 'array': return prn_to_sheet_str(cc2str(d), opts);
case 'base64': str = Base64.decode(d); break;
case 'binary': str = d; break;
case 'buffer': str = d.toString('binary'); break;
case 'array': str = cc2str(d); break;
default: throw new Error("Unrecognized type " + opts.type);
}
throw new Error("Unrecognized type " + opts.type);
if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
return prn_to_sheet_str(str, opts);
}
function prn_to_workbook(str, opts) { return sheet_to_workbook(prn_to_sheet(str, opts), opts); }
@ -5644,6 +5675,20 @@ var PRN = (function() {
};
})();
/* Excel defaults to SYLK but warns if data is not valid */
function read_wb_ID(d, opts) {
var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
try {
var out = SYLK.to_workbook(d, o);
o.WTF = OLD_WTF;
return out;
} catch(e) {
o.WTF = OLD_WTF;
if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
return PRN.to_workbook(d, opts);
}
}
var WK_ = (function() {
function lotushopper(data, cb, opts) {
if(!data) return;
@ -10726,8 +10771,8 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
else {
cell.t = 'n';
vv = ''+(cell.v = datenum(parseDate(cell.v)));
if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
}
if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
break;
default: vv = cell.v; break;
}
@ -10840,8 +10885,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
}
if(tag.t == null && p.v === undefined) {
if(!opts.sheetStubs) continue;
p.t = "z";
if(p.f || p.F) {
p.v = 0; p.t = "n";
} else if(!opts.sheetStubs) continue;
else p.t = "z";
}
else p.t = tag.t || "n";
if(guess.s.c > idx) guess.s.c = idx;
@ -12090,11 +12137,20 @@ function parse_wb_defaults(wb) {
_ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904, 'date1904');
}
var badchars = "][*?\/\\".split("");
function check_ws_name(n, safe) {
if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
var _good = true;
badchars.forEach(function(c) {
if(n.indexOf(c) == -1) return;
if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
_good = false;
});
return _good;
}
function check_wb_names(N) {
var badchars = "][*?\/\\".split("");
N.forEach(function(n,i) {
badchars.forEach(function(c) { if(n.indexOf(c) > -1) throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); });
if(n.length > 31) throw new Error("Sheet names cannot exceed 31 chars");
check_ws_name(n);
for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
});
}
@ -13943,7 +13999,7 @@ function parse_workbook(blob, options) {
opts.enc = val;
if(opts.WTF) console.error(val);
if(!options.password) throw new Error("File is password-protected");
if(val.Type !== 0) throw new Error("Encryption scheme unsupported");
if(val.valid == null) throw new Error("Encryption scheme unsupported");
if(!val.valid) throw new Error("Password is incorrect");
break;
case 'WriteAccess': opts.lastuser = val; break;
@ -13960,7 +14016,7 @@ function parse_workbook(blob, options) {
case 'Template': break; // TODO
case 'RefreshAll': wb.opts.RefreshAll = val; break;
case 'BookBool': break; // TODO
case 'UsesELFs': /* if(val) console.error("Unsupported ELFs"); */ break;
case 'UsesELFs': break;
case 'MTRSettings': break;
case 'CalcCount': wb.opts.CalcCount = val; break;
case 'CalcDelta': wb.opts.CalcDelta = val; break;
@ -16051,6 +16107,7 @@ function parse_dom_table(table, _opts) {
function table_to_book(table, opts) {
return sheet_to_workbook(parse_dom_table(table, opts), opts);
}
/* OpenDocument */
var parse_content_xml = (function() {
var parse_text_p = function(text, tag) {
@ -16490,7 +16547,27 @@ var parse_content_xml = (function() {
return out;
};
})();
var write_content_xml = (function() {
function parse_ods(zip, opts) {
opts = opts || ({});
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipstr(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data, opts) {
return parse_content_xml(data, opts);
}
/* OpenDocument */
var write_styles_ods = (function() {
var payload = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><office:document-styles xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" office:version="1.2"></office:document-styles>';
return function wso(wb, opts) {
return payload;
};
})();
var write_content_ods = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var covered_cell_xml = ' <table:covered-table-cell/>\n';
var write_ws = function(ws, wb, i, opts) {
@ -16553,7 +16630,7 @@ var write_content_xml = (function() {
//case 'e':
default: o.push(null_cell_xml); continue;
}
o.push(writextag('table:table-cell', writextag('text:p', textp, {}), ct));
o.push(' ' + writextag('table:table-cell', writextag('text:p', textp, {}), ct) + '\n');
}
o.push(' </table:table-row>\n');
}
@ -16635,6 +16712,50 @@ var write_content_xml = (function() {
return o.join("");
};
})();
function write_ods(wb, opts) {
if(opts.bookType == "fods") return write_content_ods(wb, opts);
var zip = new jszip();
var f = "";
var manifest = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_ods(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* TODO: these are hard-coded styles to satiate excel */
f = "styles.xml";
zip.file(f, write_styles_ods(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "StylesFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* TODO: this is hard-coded to satiate excel */
f = "meta.xml";
zip.file(f, write_meta_ods(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "MetadataFile"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
/* actual implementation elsewhere, wrappers are for read/write */
function write_obj_str(factory) {
return function write_str(wb, o) {
@ -16651,49 +16772,6 @@ var write_slk_str = write_obj_str(SYLK);
var write_dif_str = write_obj_str(DIF);
var write_prn_str = write_obj_str(PRN);
var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
/* Part 3: Packages */
function parse_ods(zip, opts) {
opts = opts || ({});
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipstr(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data, opts) {
return parse_content_xml(data, opts);
}
function write_ods(wb, opts) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
var zip = new jszip();
var f = "";
var manifest = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
function fix_opts_func(defaults) {
return function fix_opts(opts) {
for(var i = 0; i != defaults.length; ++i) {
@ -17126,10 +17204,10 @@ function readSync(data, opts) {
case 0xD0: return read_cfb(CFB.read(d, o), o);
case 0x09: return parse_xlscfb(s2a(o.type === 'base64' ? Base64.decode(d) : d), o);
case 0x3C: return parse_xlml(d, o);
case 0x49: if(n[1] == 0x44) return SYLK.to_workbook(d, o); break;
case 0x49: if(n[1] == 0x44) return read_wb_ID(d, o); break;
case 0x54: if(n[1] == 0x41 && n[2] == 0x42 && n[3] == 0x4C) return DIF.to_workbook(d, o); break;
case 0x50: if(n[1] == 0x4B && n[2] < 0x20 && n[3] < 0x20) return read_zip(d, o); break;
case 0xEF: return parse_xlml(d, o);
case 0xEF: return n[3] == 0x3C ? parse_xlml(d, o) : PRN.to_workbook(d,o);
case 0xFF: if(n[1] == 0xFE){ return read_utf16(d, o); } break;
case 0x00: if(n[1] == 0x00 && n[2] >= 0x02 && n[3] == 0x00) return WK_.to_workbook(d, o); break;
case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o);
@ -17283,7 +17361,7 @@ function sheet_to_json(sheet, opts){
var outi = 0, counter = 0;
var dense = Array.isArray(sheet);
var R = r.s.r, C = 0, CC = 0;
if(!sheet[R]) sheet[R] = [];
if(dense && !sheet[R]) sheet[R] = [];
for(C = r.s.c; C <= r.e.c; ++C) {
cols[C] = encode_col(C);
val = dense ? sheet[R][C] : sheet[cols[C] + rr];
@ -17350,8 +17428,8 @@ function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
else if(val.v != null) {
isempty = false;
txt = ''+format_cell(val, null, o);
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {
txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
if(txt == "ID") txt = '"ID"';
} else if(val.f != null && !val.F) {
isempty = false;
txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
@ -17428,6 +17506,30 @@ function sheet_to_formulae(sheet) {
return cmds;
}
function json_to_sheet(js, opts) {
var o = opts || {};
var ws = ({});
var range = ({s: {c:0, r:0}, e: {c:0, r:js.length}});
var hdr = o.header || [], C = 0;
for(var R = 0; R != js.length; ++R) {
Object.keys(js[R]).filter(function(x) { return js[R].hasOwnProperty(x); }).forEach(function(k) {
if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
var v = js[R][k];
var t = 'z';
if(typeof v == 'number') t = 'n';
else if(typeof v == 'boolean') t = 'b';
else if(typeof v == 'string') t = 's';
else if(v instanceof Date) t = 'd';
ws[encode_cell({c:C,r:R+1})] = {t:t, v:v};
});
}
range.e.c = hdr.length - 1;
for(C = 0; C < hdr.length; ++C) ws[encode_col(C) + "1"] = {t:'s', v:hdr[C]};
ws['!ref'] = encode_range(range);
return ws;
}
var utils = {
encode_col: encode_col,
encode_row: encode_row,
@ -17444,6 +17546,7 @@ var utils = {
make_json: sheet_to_json,
make_formulae: sheet_to_formulae,
aoa_to_sheet: aoa_to_sheet,
json_to_sheet: json_to_sheet,
table_to_sheet: parse_dom_table,
table_to_book: table_to_book,
sheet_to_csv: sheet_to_csv,
@ -17451,6 +17554,110 @@ var utils = {
sheet_to_formulae: sheet_to_formulae,
sheet_to_row_object_array: sheet_to_json
};
(function(utils) {
utils.consts = utils.consts || {};
function add_consts(R) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
/* get cell, creating a stub if necessary */
function ws_get_cell_stub(ws, R, C) {
/* A1 cell address */
if(typeof R == "string") return ws[R] || (ws[R] = {t:'z'});
/* cell address object */
if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
/* R and C are 0-based indices */
return ws_get_cell_stub(ws, encode_cell({r:R,c:C}));
}
/* find sheet index for given name / validate index */
function wb_sheet_idx(wb, sh) {
if(typeof sh == "number") {
if(sh >= 0 && wb.SheetNames.length > sh) return sh;
throw new Error("Cannot find sheet # " + sh);
} else if(typeof sh == "string") {
var idx = wb.SheetNames.indexOf(sh);
if(idx > -1) return idx;
throw new Error("Cannot find sheet name |" + sh + "|");
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
utils.book_new = function() {
return { SheetNames: [], Sheets: {} };
};
/* add a worksheet to the end of a given workbook */
utils.book_append_sheet = function(wb, ws, name) {
if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf("Sheet" + i) == -1) break;
check_ws_name(name);
if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
wb.SheetNames.push(name);
wb.Sheets[name] = ws;
};
/* set sheet visibility (visible/hidden/very hidden) */
utils.book_set_sheet_visibility = function(wb, sh, vis) {
get_default(wb,"Workbook",{});
get_default(wb.Workbook,"Sheets",[]);
var idx = wb_sheet_idx(wb, sh);
get_default(wb.Workbook.Sheets,idx, {});
switch(vis) {
case 0: case 1: case 2: break;
default: throw new Error("Bad sheet visibility setting " + vis);
}
wb.Workbook.Sheets[idx].Hidden = vis;
};
add_consts([
["SHEET_VISIBLE", 0],
["SHEET_HIDDEN", 1],
["SHEET_VERY_HIDDEN", 2]
]);
/* set number format */
utils.cell_set_number_format = function(cell, fmt) {
cell.z = fmt;
return cell;
};
/* set cell hyperlink */
utils.cell_set_hyperlink = function(cell, target, tooltip) {
if(!target) {
delete cell.l;
} else {
cell.l = { Target: target };
if(tooltip) cell.l.Tooltip = tooltip;
}
return cell;
};
/* add to cell comments */
utils.cell_add_comment = function(cell, text, author) {
if(!cell.c) cell.c = [];
cell.c.push({t:text, a:author||"SheetJS"});
};
/* set array formula and flush related cells */
utils.sheet_set_array_formula = function(ws, range, formula) {
var rng = typeof range != "string" ? range : safe_decode_range(range);
var rngstr = typeof range == "string" ? range : encode_range(range);
for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
var cell = ws_get_cell_stub(ws, R, C);
cell.t = 'n';
cell.F = rngstr;
delete cell.v;
if(R == rng.s.r && C == rng.s.c) cell.f = formula;
}
return ws;
};
return utils;
})(utils);
if(has_buf && typeof require != 'undefined') (function() {
var Readable = require('stream').Readable;
@ -17513,6 +17720,7 @@ if(has_buf && typeof require != 'undefined') (function() {
to_csv: write_csv_stream
};
})();
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
XLSX.parse_fods = parse_fods;

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

@ -34,6 +34,7 @@ Utilities are available in the `XLSX.utils` object:
**Importing:**
- `aoa_to_sheet` converts an array of arrays of JS data to a worksheet.
- `json_to_sheet` converts an array of JS objects to a worksheet.
**Exporting:**
@ -41,7 +42,7 @@ Utilities are available in the `XLSX.utils` object:
- `sheet_to_csv` generates delimiter-separated-values output.
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
Exporters are described in the [Utility Functions](#utility-functions) section.
These utilities are described in [Utility Functions](#utility-functions) below.
**Cell and cell address manipulation:**

@ -42,6 +42,25 @@ var ws = XLSX.utils.aoa_to_sheet([
```
</details>
### Array of Objects Input
`XLSX.utils.json_to_sheet` takes an array of objects and returns a worksheet
with automatically-generated "headers" based on the keys of the objects.
<details>
<summary><b>Examples</b> (click to show)</summary>
The original sheet cannot be reproduced because JS object keys must be unique.
After replacing the second `e` and `S` with `e_1` and `S_1`:
```js
var ws = XLSX.utils.json_to_sheet([
{S:1,h:2,e:3,e_1:4,t:5,J:6,S_1:7},
{S:2,h:3,e:4,e_1:5,t:6,J:7,S_1:8}
]);
```
</details>
### HTML Table Input
`XLSX.utils.table_to_sheet` takes a table DOM element and returns a worksheet

@ -46,6 +46,7 @@
* [Output Type](README.md#output-type)
- [Utility Functions](README.md#utility-functions)
* [Array of Arrays Input](README.md#array-of-arrays-input)
* [Array of Objects Input](README.md#array-of-objects-input)
* [HTML Table Input](README.md#html-table-input)
* [Formulae Output](README.md#formulae-output)
* [Delimiter-Separated Output](README.md#delimiter-separated-output)

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.10.0",
"version": "0.10.1",
"author": "sheetjs",
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS (ODS/FODS/UOS) spreadsheet parser and writer",
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],

15
test.js

@ -1413,6 +1413,21 @@ describe('roundtrip features', function() {
});
});
});
it('should preserve js objects', function() {
var data = [
{a:1},
{b:2,c:3},
{b:"a",d:"b"},
{a:true, c:false},
{c:new Date("2017-02-19T14:30Z")}
];
var wb = X.utils.json_to_sheet(data);
var out = X.utils.sheet_to_json(wb, {raw:true});
data.forEach(function(row, i) {
Object.keys(row).forEach(function(k) { assert.equal(row[k], out[i][k]); });
});
});
});
//function password_file(x){return x.match(/^password.*\.xls$/); }

@ -543,16 +543,19 @@ describe('input formats', function() {
X.read(fs.readFileSync(paths.cstxlsb, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstxls, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstxml, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstods, 'binary'), {type: 'binary'});
});
it('should read base64 strings', function() {
X.read(fs.readFileSync(paths.cstxls, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxml, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstods, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxlsx, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxlsb, 'base64'), {type: 'base64'});
});
(typeof UInt8Array !== 'undefined' ? it : it.skip)('should read arrays', function() {
X.read(fs.readFileSync(paths.cstxls, 'buffer'), {type: 'array'});
X.read(fs.readFileSync(paths.cstxml, 'buffer'), {type: 'array'});
X.read(fs.readFileSync(paths.cstods, 'buffer'), {type: 'array'});
X.read(fs.readFileSync(paths.cstxlsx, 'buffer'), {type: 'array'});
X.read(fs.readFileSync(paths.cstxlsb, 'buffer'), {type: 'array'});
});
@ -566,12 +569,14 @@ describe('input formats', function() {
it('should throw if format is unknown', function() {
assert.throws(function() { X.read(fs.readFileSync(paths.cstxls), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxml), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstods), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsx), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsb), {type: 'dafuq'}); });
});
it('should default to base64 type', function() {
X.read(fs.readFileSync(paths.cstxls, 'base64'));
X.read(fs.readFileSync(paths.cstxml, 'base64'));
X.read(fs.readFileSync(paths.cstods, 'base64'));
X.read(fs.readFileSync(paths.cstxlsx, 'base64'));
X.read(fs.readFileSync(paths.cstxlsb, 'base64'));
});
@ -816,8 +821,9 @@ describe('parse features', function() {
var wb2 = X.read(fs.readFileSync(paths.cstxlsb), opts);
var wb3 = X.read(fs.readFileSync(paths.cstxls), opts);
var wb4 = X.read(fs.readFileSync(paths.cstxml), opts);
var wb5 = X.read(fs.readFileSync(paths.cstods), opts);
/* TODO */
[wb1, wb2 /*, wb3, wb4 */].forEach(function(wb) {
[wb1, wb2 /*, wb3, wb4, wb5 */].forEach(function(wb) {
assert.equal(wb.Sheets.Sheet7["!fullref"],"A1:N34");
assert.equal(wb.Sheets.Sheet7["!ref"],"A1");
});
@ -1401,10 +1407,29 @@ describe('roundtrip features', function() {
});
});
});
it('should preserve js objects', function() {
var data = [
{a:1},
{b:2,c:3},
{b:"a",d:"b"},
{a:true, c:false},
{c:new Date("2017-02-19T14:30Z")}
];
var wb = X.utils.json_to_sheet(data);
var out = X.utils.sheet_to_json(wb, {raw:true});
data.forEach(function(row, i) {
Object.keys(row).forEach(function(k) { assert.equal(row[k], out[i][k]); });
});
});
});
function password_file(x){return x.match(/^password.*\.xls$/); }
var password_files = fs.readdirSync('test_files').filter(password_file);
//function password_file(x){return x.match(/^password.*\.xls$/); }
//var password_files = fs.readdirSync('test_files').filter(password_file);
var password_files = [
//"password_2002_40_972000.xls",
"password_2002_40_xor.xls"
];
describe('invalid files', function() {
describe('parse', function() { [
['password', 'apachepoi_password.xls'],
@ -1768,10 +1793,20 @@ describe('encryption', function() {
password_files.forEach(function(x) {
describe(x, function() {
it('should throw with no password', function() {assert.throws(function() { X.read(fs.readFileSync(dir + x), {type:"binary"}); }); });
it('should throw with wrong password', function() {assert.throws(function() { X.read(fs.readFileSync(dir + x), {type:"binary",password:'passwor',WTF:opts.WTF}); }); });
it('should throw with wrong password', function() {
try {
X.read(fs.readFileSync(dir + x), {type:"binary",password:'passwor',WTF:opts.WTF});
throw new Error("incorrect password was accepted");
} catch(e) {
if(e.message != "Password is incorrect") throw e;
}
});
it('should recognize correct password', function() {
try { X.read(fs.readFileSync(dir + x), {type:"binary",password:'password',WTF:opts.WTF}); }
catch(e) { if(e.message == "Password is incorrect") throw e; }
try {
X.read(fs.readFileSync(dir + x), {type:"binary",password:'password',WTF:opts.WTF});
} catch(e) {
if(e.message == "Password is incorrect") throw e;
}
});
it.skip('should decrypt file', function() {
var wb = X.read(fs.readFileSync(dir + x), {type:"binary",password:'password',WTF:opts.WTF});

File diff suppressed because one or more lines are too long

@ -70,3 +70,4 @@
./test_files/2011/apachepoi_SimpleWithComments.xls.xml
./test_files/apachepoi_SimpleWithComments.xlsx
./test_files/2013/apachepoi_SimpleWithComments.xlsx.xlsb
./test_files/password_2002_40_xor.xls