version bump 0.8.4: formula parsing

- BIFF 2-12 formula parsing
- more content type coverage
- unified `.f` form: A1-style string
- `.F` field for array formulae
- formula output groups array formulae
- bin script -A --arrays output JS row objects
- whitespace robustness in inline string xml
- UTF-8 parsing in rich text runs (fixes #505 h/t @fuchsc)
- bold/italic/underline accept null val attr (h/t @qqilihq)
- sst trimming (fixes #176 h/t @shakhal @oising)
This commit is contained in:
SheetJS 2017-02-19 12:36:32 -08:00
parent ab2ecebac9
commit d7ecca0e8b
47 changed files with 3402 additions and 1192 deletions

18
.gitignore vendored

@ -4,17 +4,15 @@ misc/prof.js
v8.log
tmp
*.txt
*.csv
*.dif
*.prn
*.slk
*.[cC][sS][vV]
*.[dD][iI][fF]
*.[pP][rR][nN]
*.[sS][lL][kK]
*.socialcalc
*.xls
*.xlsb
*.xlsm
*.xlsx
*.ods
*.xml
*.[xX][lL][sSwW]
*.[xX][lL][sS][xXmMbB]
*.[oO][dD][sS]
*.[xX][mM][lL]
*.htm
*.html
*.sheetjs

@ -5,18 +5,15 @@ misc/
node_modules
tmp
*.txt
*.csv
*.dif
*.prn
*.slk
*.[cC][sS][vV]
*.[dD][iI][fF]
*.[pP][rR][nN]
*.[sS][lL][kK]
*.socialcalc
*.XLS
*.xls
*.xlsb
*.xlsm
*.xlsx
*.ods
*.xml
*.[xX][lL][sSwW]
*.[xX][lL][sS][xXmMbB]
*.[oO][dD][sS]
*.[xX][mM][lL]
*.htm
*.html
*.sheetjs

@ -3,7 +3,7 @@ node_js:
- "7"
- "6"
- "5"
- "4.2"
- "4"
- "0.12"
- "0.10"
- "0.9"

@ -366,24 +366,28 @@ for(var R = range.s.r; R <= range.e.r; ++R) {
### Cell Object
| Key | Description |
| --- | ----------- |
| `v` | raw value (see Data Types section for more info) |
| `w` | formatted text (if applicable) |
| `t` | cell type: `b` Boolean, `n` Number, `e` error, `s` String, `d` Date |
| `f` | cell formula (if applicable) |
| `r` | rich text encoding (if applicable) |
| `h` | HTML rendering of the rich text (if applicable) |
| `c` | comments associated with the cell ** |
| `z` | number format string associated with the cell (if requested) |
| `l` | cell hyperlink object (.Target holds link, .tooltip is tooltip) |
| `s` | the style/theme of the cell (if applicable) |
| Key | Description |
| --- | ---------------------------------------------------------------------- |
| `v` | raw value (see Data Types section for more info) |
| `w` | formatted text (if applicable) |
| `t` | cell type: `b` Boolean, `n` Number, `e` error, `s` String, `d` Date |
| `f` | cell formula encoded as an A1-style string (if applicable) |
| `F` | range of enclosing array if formula is array formula (if applicable) |
| `r` | rich text encoding (if applicable) |
| `h` | HTML rendering of the rich text (if applicable) |
| `c` | comments associated with the cell |
| `z` | number format string associated with the cell (if requested) |
| `l` | cell hyperlink object (.Target holds link, .tooltip is tooltip) |
| `s` | the style/theme of the cell (if applicable) |
Built-in export utilities (such as the CSV exporter) will use the `w` text if it
is available. To change a value, be sure to delete `cell.w` (or set it to
`undefined`) before attempting to export. The utilities will regenerate the `w`
text from the number format (`cell.z`) and the raw value if possible.
The actual array formula is stored in the `f` field of the first cell in the
array range. Other cells in the range will omit the `f` field.
### Data Types
The raw value is stored in the `v` field, interpreted based on the `t` field.
@ -418,6 +422,20 @@ dates in the local timezone. js-xlsx does not correct for this error.
Type `s` is the String type. `v` should be explicitly stored as a string to
avoid possible confusion.
### Formulae
The A1-style formula string is stored in the `f` field. Even though different
file formats store the formulae in different ways, the formats are converted.
Shared formulae are decompressed and each cell has the correct formula.
Array formulae are stored in the top-left cell of the array block. All cells
of an array formula have a `F` field corresponding to the range. A single-cell
formula can be distinguished from a plain formula by the presence of `F` field.
The `sheet_to_formulae` method generates one line per formula or array formula.
Array formulae are rendered in the form `range=formula` while plain cells are
rendered in the form `cell=formula or value`.
### Worksheet Object
@ -619,6 +637,8 @@ OSP-covered specifications:
- [MS-OLEDS]: Object Linking and Embedding (OLE) Data Structures
- [MS-OLEPS]: Object Linking and Embedding (OLE) Property Set Data Structures
- [MS-OSHARED]: Office Common Data Types and Objects Structures
- [MS-ODRAW]: Office Drawing Binary File Format
- [MS-ODRAWXML]: Office Drawing Extensions to Office Open XML Structure
- [MS-OVBA]: Office VBA File Format Structure
- [MS-CTXLS]: Excel Custom Toolbar Binary File Format
- [MS-XLDM]: Spreadsheet Data Model File Format

@ -21,6 +21,7 @@ program
.option('-S, --formulae', 'print formulae')
.option('-j, --json', 'emit formatted JSON (all fields text)')
.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
.option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
.option('-F, --field-sep <sep>', 'CSV field separator', ",")
.option('-R, --row-sep <sep>', 'CSV row separator', "\n")
.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)')
@ -77,7 +78,7 @@ if(program.xlsx || program.xlsm || program.xlsb) {
opts.cellNF = true;
if(program.output) sheetname = program.output;
}
else if(program.formulae);
else if(program.formulae) opts.cellFormula = true;
else opts.cellFormula = false;
if(program.all) {
@ -142,6 +143,7 @@ if(!program.quiet) console.error(target_sheet);
if(program.formulae) oo = X.utils.get_formulae(ws).join("\n");
else if(program.json) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws));
else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true}));
else if(program.arrays) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true, header:1}));
else oo = X.utils.make_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
if(program.output) fs.writeFileSync(program.output, oo);

@ -1 +1 @@
XLSX.version = '0.8.3';
XLSX.version = '0.8.4';

@ -42,3 +42,12 @@ function cc2str(arr/*:Array<number>*/)/*:string*/ {
return o;
}
function dup(o/*:any*/)/*:any*/ {
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
if(typeof o != 'object' || !o) return o;
var out = {};
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
return out;
}
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }

@ -115,9 +115,9 @@ var matchtag = (function() {
var vtregex = (function(){ var vt_cache = {};
return function vt_regex(bt) {
if(vt_cache[bt] !== undefined) return vt_cache[bt];
return (vt_cache[bt] = new RegExp("<vt:" + bt + ">(.*?)</vt:" + bt + ">", 'g') );
return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">(.*?)</(?:vt:)?" + bt + ">", 'g') );
};})();
var vtvregex = /<\/?vt:variant>/g, vtmregex = /<vt:([^>]*)>(.*)</;
var vtvregex = /<\/?(:?vt:)?variant>/g, vtmregex = /<(:?vt:)?([^>]*)>(.*)</;
function parseVector(data) {
var h = parsexmltag(data);

@ -82,6 +82,8 @@ function ReadShift(size, t) {
case 'utf8': o = __utf8(this, this.l, this.l + size); break;
case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
case 'wstr': o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size)); size = 2 * size; break;
/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break;
/* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */

@ -1,16 +1,18 @@
/* XLS ranges enforced */
function shift_cell_xls(cell, tgt) {
function shift_cell_xls(cell, tgt, opts) {
var out = dup(cell);
if(tgt.s) {
if(cell.cRel) cell.c += tgt.s.c;
if(cell.rRel) cell.r += tgt.s.r;
if(out.cRel) out.c += tgt.s.c;
if(out.rRel) out.r += tgt.s.r;
} else {
cell.c += tgt.c;
cell.r += tgt.r;
out.c += tgt.c;
out.r += tgt.r;
}
cell.cRel = cell.rRel = 0;
while(cell.c >= 0x100) cell.c -= 0x100;
while(cell.r >= 0x10000) cell.r -= 0x10000;
return cell;
if(!opts || opts.biff < 12) {
while(out.c >= 0x100) out.c -= 0x100;
while(out.r >= 0x10000) out.r -= 0x10000;
}
return out;
}
function shift_range_xls(cell, range) {
@ -19,3 +21,13 @@ function shift_range_xls(cell, range) {
return cell;
}
function encode_cell_xls(c)/*:string*/ {
var s = encode_cell(c);
if(c.cRel === 0) s = fix_col(s);
if(c.rRel === 0) s = fix_row(s);
return s;
}
function encode_range_xls(r)/*:string*/ {
return encode_cell_xls(r.s) + ":" + encode_cell_xls(r.e);
}

@ -76,6 +76,10 @@ function write_XLWideString(data/*:string*/, o) {
return o;
}
/* [MS-XLSB] 2.5.165 */
var parse_XLNameWideString = parse_XLWideString;
var write_XLNameWideString = write_XLWideString;
/* [MS-XLSB] 2.5.114 */
var parse_RelID = parse_XLNullableWideString;
var write_RelID = write_XLNullableWideString;
@ -101,8 +105,8 @@ function write_RkNumber(data/*:number*/, o) {
}
/* [MS-XLSB] 2.5.153 */
function parse_UncheckedRfX(data)/*:Range*/ {
/* [MS-XLSB] 2.5.117 RfX */
function parse_RfX(data)/*:Range*/ {
var cell/*:Range*/ = ({s: {}, e: {}}/*:any*/);
cell.s.r = data.read_shift(4);
cell.e.r = data.read_shift(4);
@ -111,7 +115,7 @@ function parse_UncheckedRfX(data)/*:Range*/ {
return cell;
}
function write_UncheckedRfX(r/*:Range*/, o) {
function write_RfX(r/*:Range*/, o) {
if(!o) o = new_buf(16);
o.write_shift(4, r.s.r);
o.write_shift(4, r.e.r);
@ -120,6 +124,10 @@ function write_UncheckedRfX(r/*:Range*/, o) {
return o;
}
/* [MS-XLSB] 2.5.153 UncheckedRfX */
var parse_UncheckedRfX = parse_RfX;
var write_UncheckedRfX = write_RfX;
/* [MS-XLSB] 2.5.171 */
/* [MS-XLS] 2.5.342 */
/* TODO: error checking, NaN and Infinity values are not valid Xnum */

@ -40,6 +40,12 @@ var ct2type/*{[string]:string}*/ = ({
"application/vnd.ms-excel.pivotTable": "TODO",
"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
/* Chart Colors */
"application/vnd.ms-office.chartcolorstyle+xml": "TODO",
/* Chart Style */
"application/vnd.ms-office.chartstyle+xml": "TODO",
/* Calculation Chain */
"application/vnd.ms-excel.calcChain": "calcchains",
"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",

@ -10,10 +10,7 @@ function parse_cust_props(data/*:string*/, opts) {
var x = m[i], y = parsexmltag(x);
switch(y[0]) {
case '<?xml': break;
case '<Properties':
if(y.xmlns !== XMLNS.CUST_PROPS) throw "unrecognized xmlns " + y.xmlns;
if(y.xmlnsvt && y.xmlnsvt !== XMLNS.vt) throw "unrecognized vt " + y.xmlnsvt;
break;
case '<Properties': break;
case '<property': name = y.name; break;
case '</property>': name = null; break;
default: if (x.indexOf('<vt:') === 0) {

@ -303,13 +303,15 @@ function parse_Bes(blob) {
/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
function parse_ShortXLUnicodeString(blob, length, opts) {
var cch = blob.read_shift(1);
var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1);
var width = 1, encoding = 'sbcs-cont';
var cp = current_codepage;
if(opts && opts.biff >= 8) current_codepage = 1200;
if(opts === undefined || opts.biff !== 5) {
if(!opts || opts.biff == 8 ) {
var fHighByte = blob.read_shift(1);
if(fHighByte) { width = 2; encoding = 'dbcs-cont'; }
} else if(opts.biff == 12) {
width = 2; encoding = 'wstr';
}
var o = cch ? blob.read_shift(cch, encoding) : "";
current_codepage = cp;
@ -340,6 +342,10 @@ function parse_XLUnicodeRichExtendedString(blob) {
/* 2.5.296 XLUnicodeStringNoCch */
function parse_XLUnicodeStringNoCch(blob, cch, opts) {
var retval;
if(opts) {
if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'sbcs-cont');
if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
}
var fHighByte = blob.read_shift(1);
if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
else { retval = blob.read_shift(cch, 'dbcs-cont'); }
@ -348,7 +354,7 @@ function parse_XLUnicodeStringNoCch(blob, cch, opts) {
/* 2.5.294 XLUnicodeString */
function parse_XLUnicodeString(blob, length, opts) {
var cch = blob.read_shift(opts !== undefined && opts.biff > 0 && opts.biff < 8 ? 1 : 2);
var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
if(cch === 0) { blob.l++; return ""; }
return parse_XLUnicodeStringNoCch(blob, cch, opts);
}

@ -39,10 +39,10 @@ function parse_RkRec(blob, length) {
}
/* 2.5.1 */
function parse_AddinUdf(blob, length) {
function parse_AddinUdf(blob, length, opts) {
blob.l += 4; length -= 4;
var l = blob.l + length;
var udfName = parse_ShortXLUnicodeString(blob, length);
var udfName = parse_ShortXLUnicodeString(blob, length, opts);
var cb = blob.read_shift(2);
l -= blob.l;
if(cb !== l) throw "Malformed AddinUdf: padding = " + l + " != " + cb;
@ -272,8 +272,10 @@ function parse_LabelSst(blob, length) {
/* 2.4.148 */
function parse_Label(blob, length, opts) {
var target = blob.l + length;
var cell = parse_XLSCell(blob, 6);
var str = parse_XLUnicodeString(blob, length-6, opts);
if(opts.biff == 2) blob.l++;
var str = parse_XLUnicodeString(blob, target - blob.l, opts);
cell.val = str;
return cell;
}
@ -287,11 +289,12 @@ function parse_Format(blob, length, opts) {
var parse_BIFF2Format = parse_XLUnicodeString2;
/* 2.4.90 */
function parse_Dimensions(blob, length) {
var w = length === 10 ? 2 : 4;
function parse_Dimensions(blob, length, opts) {
var end = blob.l + length;
var w = opts.biff == 8 || !opts.biff ? 4 : 2;
var r = blob.read_shift(w), R = blob.read_shift(w),
c = blob.read_shift(2), C = blob.read_shift(2);
blob.l += 2;
blob.l = end;
return {s: {r:r, c:c}, e: {r:R, c:C}};
}
@ -392,7 +395,7 @@ function parse_ExternName(blob, length, opts) {
cf: (flags >>> 5) & 0x3FF,
fIcon: flags >>> 15 & 0x01
}/*:any*/);
if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2);
if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts);
//else throw new Error("unsupported SupBook cch: " + opts.sbcch);
o.body = body || blob.read_shift(length-2);
return o;
@ -404,12 +407,15 @@ function parse_Lbl(blob, length, opts) {
var flags = blob.read_shift(2);
var chKey = blob.read_shift(1);
var cch = blob.read_shift(1);
var cce = blob.read_shift(2);
blob.l += 2;
var itab = blob.read_shift(2);
blob.l += 4;
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
if(!opts || opts.biff >= 5) {
blob.l += 2;
var itab = blob.read_shift(2);
blob.l += 4;
}
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
var rgce = parse_NameParsedFormula(blob, target - blob.l, opts, cce);
var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
var rgce = target == blob.l || cce == 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
return {
chKey: chKey,
Name: name,
@ -441,7 +447,12 @@ function parse_ShrFmla(blob, length, opts) {
/* 2.4.4 TODO */
function parse_Array(blob, length, opts) {
var ref = parse_Ref(blob, 6);
blob.l += 6; length -= 12; /* TODO: fAlwaysCalc */
/* TODO: fAlwaysCalc */
switch(opts.biff) {
case 2: blob.l ++; length -= 7; break;
case 3: case 4: blob.l += 2; length -= 8; break;
default: blob.l += 6; length -= 12;
}
return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
}
@ -904,6 +915,7 @@ function parse_BIFF2STR(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var str = parse_XLUnicodeString2(blob, length-7, opts);
cell.t = 'str';
cell.val = str;
return cell;
}
@ -912,6 +924,7 @@ function parse_BIFF2NUM(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var num = parse_Xnum(blob, 8);
cell.t = 'n';
cell.val = num;
return cell;
}
@ -920,6 +933,7 @@ function parse_BIFF2INT(blob, length) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var num = blob.read_shift(2);
cell.t = 'n';
cell.val = num;
return cell;
}
@ -939,3 +953,15 @@ function parse_BIFF2FONTXTRA(blob, length) {
blob.l += 1; // font family
blob.l += length - 9;
}
/* TODO: parse rich text runs */
function parse_RString(blob, length, opts) {
var end = blob.l + length;
var cell = parse_XLSCell(blob, 6);
var cch = blob.read_shift(2);
var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
blob.l = end;
cell.t = 'str';
cell.val = str;
return cell;
}

@ -70,21 +70,21 @@ var parse_rs = (function parse_rs_factory() {
/* 18.4.13 u CT_UnderlineProperty */
case '<u':
if(!y.val) break;
if(y.val == '0') break;
/* falls through */
case '<u/>': font.u = 1; break;
case '</u>': break;
/* 18.8.2 b */
case '<b':
if(!y.val) break;
if(y.val == '0') break;
/* falls through */
case '<b/>': font.b = 1; break;
case '</b>': break;
/* 18.8.26 i */
case '<i':
if(!y.val) break;
if(y.val == '0') break;
/* falls through */
case '<i/>': font.i = 1; break;
case '</i>': break;
@ -142,16 +142,17 @@ function parse_si(x, opts) {
if(!x) return null;
var y;
/* 18.4.12 t ST_Xstring (Plaintext String) */
if(x.match(/^<(?:\w+:)?t[^>]*>/)) {
// TODO: is whitespace actually valid here?
if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
z.t = utf8read(unescapexml(x.substr(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]));
z.r = x;
z.r = utf8read(x);
if(html) z.h = z.t;
}
/* 18.4.4 r CT_RElt (Rich Text Run) */
else if((y = x.match(sirregex))) {
z.r = x;
z.r = utf8read(x);
z.t = utf8read(unescapexml((x.match(sitregex)||[]).join("").replace(tagregex,"")));
if(html) z.h = parse_rs(x);
if(html) z.h = parse_rs(z.r);
}
/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
@ -170,7 +171,7 @@ function parse_sst_xml(data/*:string*/, opts)/*:SST*/ {
if(isval(sst)/*:: && sst*/) {
ss = sst[2].replace(sstr1,"").split(sstr2);
for(var i = 0; i != ss.length; ++i) {
var o = parse_si(ss[i], opts);
var o = parse_si(ss[i].trim(), opts);
if(o != null) s[s.length] = o;
}
sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;

@ -5,9 +5,10 @@ var rc_to_a1 = (function(){
function rcfunc($$,$1,$2,$3,$4,$5) {
var R = $3.length>0?parseInt($3,10)|0:0, C = $5.length>0?parseInt($5,10)|0:0;
if(C<0 && $4.length === 0) C=0;
if($4.length > 0) C += rcbase.c;
if($2.length > 0) R += rcbase.r;
return $1 + encode_col(C) + encode_row(R);
var cRel = false, rRel = false;
if($4.length > 0 || $5.length == 0) cRel = true; if(cRel) C += rcbase.c; else --C;
if($2.length > 0 || $3.length == 0) rRel = true; if(rRel) R += rcbase.r; else --R;
return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
}
return function rc_to_a1(fstr, base) {
rcbase = base;
@ -15,3 +16,15 @@ var rc_to_a1 = (function(){
};
})();
/* TODO actually parse the formula */
function shift_formula_str(f/*:string*/, delta/*:Cell*/)/*:string*/ {
return f.replace(/(^|[^A-Z0-9])([$]?)([A-Z]+)([$]?)(\d+)/g, function($0, $1, $2, $3, $4, $5, off, str) {
return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
});
}
function shift_formula_xlsx(f/*:string*/, range/*:string*/, cell/*:string*/)/*:string*/ {
var r = decode_range(range), s = r.s, c = decode_cell(cell);
var delta = {r:c.r - s.r, c:c.c - s.c};
return shift_formula_str(f, delta);
}

@ -7,17 +7,30 @@ function parseread1(blob, length) { blob.l+=1; return; }
/* 2.5.51 */
function parse_ColRelU(blob, length) {
var c = blob.read_shift(2);
var c = blob.read_shift(length == 1 ? 1 : 2);
return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
}
/* 2.5.198.105 */
function parse_RgceArea(blob, length) {
var r=blob.read_shift(2), R=blob.read_shift(2);
/* [MS-XLS] 2.5.198.105 */
/* [MS-XLSB] 2.5.97.89 */
function parse_RgceArea(blob, length, opts) {
var w = 2;
if(opts) {
if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts);
else if(opts.biff == 12) w = 4;
}
var r=blob.read_shift(w), R=blob.read_shift(w);
var c=parse_ColRelU(blob, 2);
var C=parse_ColRelU(blob, 2);
return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
}
/* BIFF 2-5 encodes flags in the row field */
function parse_RgceArea_BIFF2(blob, length, opts) {
var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
var c=blob.read_shift(1);
var C=blob.read_shift(1);
return { s:{r:r[0], c:c, cRel:r[1], rRel:r[2]}, e:{r:R[0], c:C, cRel:R[1], rRel:R[2]} };
}
/* 2.5.198.105 TODO */
function parse_RgceAreaRel(blob, length) {
@ -28,36 +41,61 @@ function parse_RgceAreaRel(blob, length) {
}
/* 2.5.198.109 */
function parse_RgceLoc(blob, length) {
var r = blob.read_shift(2);
function parse_RgceLoc(blob, length, opts) {
if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts);
var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2);
var c = parse_ColRelU(blob, 2);
return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
}
function parse_RgceLoc_BIFF2(blob, length, opts) {
var r = parse_ColRelU(blob, 2);
var c = blob.read_shift(1);
return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
}
/* 2.5.198.111 */
function parse_RgceLocRel(blob, length) {
var r = blob.read_shift(2);
/* [MS-XLS] 2.5.198.111 TODO */
/* [MS-XLSB] 2.5.97.92 TODO */
function parse_RgceLocRel(blob, length, opts) {
var biff = opts && opts.biff ? opts.biff : 8;
if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts);
var r = blob.read_shift(biff >= 12 ? 4 : 2);
var cl = blob.read_shift(2);
var cRel = (cl & 0x8000) >> 15, rRel = (cl & 0x4000) >> 14;
cl &= 0x3FFF;
if(cRel !== 0) while(cl >= 0x100) cl -= 0x100;
if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000;
if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000;
return {r:r,c:cl,cRel:cRel,rRel:rRel};
}
function parse_RgceLocRel_BIFF2(blob, length) {
var rl = blob.read_shift(2);
var c = blob.read_shift(1);
var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14;
rl &= 0x3FFF;
if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000;
if(cRel == 1 && c >= 0x80) c = c - 0x100;
return {r:rl,c:c,cRel:cRel,rRel:rRel};
}
/* Ptg Tokens */
/* 2.5.198.27 */
function parse_PtgArea(blob, length) {
function parse_PtgArea(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var area = parse_RgceArea(blob, 8);
var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
return [type, area];
}
/* 2.5.198.28 */
function parse_PtgArea3d(blob, length) {
/* [MS-XLS] 2.5.198.28 */
/* [MS-XLSB] 2.5.97.19 */
function parse_PtgArea3d(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var ixti = blob.read_shift(2);
var area = parse_RgceArea(blob, 8);
var ixti = blob.read_shift(2, 'i');
var w = 8;
if(opts) switch(opts.biff) {
case 5: blob.l += 12; w = 6; break;
case 12: w = 12; break;
}
var area = parse_RgceArea(blob, w, opts);
return [type, ixti, area];
}
@ -68,10 +106,15 @@ function parse_PtgAreaErr(blob, length) {
return [type];
}
/* 2.5.198.30 */
function parse_PtgAreaErr3d(blob, length) {
function parse_PtgAreaErr3d(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var ixti = blob.read_shift(2);
blob.l += 8;
var w = 8;
if(opts) switch(opts.biff) {
case 5: blob.l += 12; w = 6; break;
case 12: w = 12; break;
}
blob.l += w;
return [type, ixti];
}
@ -82,10 +125,11 @@ function parse_PtgAreaN(blob, length) {
return [type, area];
}
/* 2.5.198.32 -- ignore this and look in PtgExtraArray for shape + values */
function parse_PtgArray(blob, length) {
/* [MS-XLS] 2.5.198.32 */
/* [MS-XLSB] 2.5.97.23 */
function parse_PtgArray(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
blob.l += 7;
blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
return [type];
}
@ -98,33 +142,40 @@ function parse_PtgAttrBaxcel(blob, length) {
}
/* 2.5.198.34 */
function parse_PtgAttrChoose(blob, length) {
function parse_PtgAttrChoose(blob, length, opts) {
blob.l +=2;
var offset = blob.read_shift(2);
var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
var o = [];
/* offset is 1 less than the number of elements */
for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(2));
for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2));
return o;
}
/* 2.5.198.35 */
function parse_PtgAttrGoto(blob, length) {
function parse_PtgAttrGoto(blob, length, opts) {
var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
return [bitGoto, blob.read_shift(2)];
return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
}
/* 2.5.198.36 */
function parse_PtgAttrIf(blob, length) {
function parse_PtgAttrIf(blob, length, opts) {
var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
}
/* [MS-XLSB] 2.5.97.28 */
function parse_PtgAttrIfError(blob, length) {
var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
return [bitIf, blob.read_shift(2)];
}
/* 2.5.198.37 */
function parse_PtgAttrSemi(blob, length) {
function parse_PtgAttrSemi(blob, length, opts) {
var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 4;
blob.l += opts && opts.biff == 2 ? 3 : 4;
return [bitSemi];
}
@ -147,46 +198,44 @@ function parse_PtgAttrSpaceSemi(blob, length) {
}
/* 2.5.198.84 TODO */
function parse_PtgRef(blob, length) {
function parse_PtgRef(blob, length, opts) {
var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var loc = parse_RgceLoc(blob,4);
var loc = parse_RgceLoc(blob, 0, opts);
return [type, loc];
}
/* 2.5.198.88 TODO */
function parse_PtgRefN(blob, length) {
var ptg = blob[blob.l] & 0x1F;
function parse_PtgRefN(blob, length, opts) {
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var loc = parse_RgceLocRel(blob,4);
var loc = parse_RgceLocRel(blob, 0, opts);
return [type, loc];
}
/* 2.5.198.85 TODO */
function parse_PtgRef3d(blob, length) {
var ptg = blob[blob.l] & 0x1F;
function parse_PtgRef3d(blob, length, opts) {
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var ixti = blob.read_shift(2); // XtiIndex
var loc = parse_RgceLoc(blob,4);
var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
return [type, ixti, loc];
}
/* 2.5.198.62 TODO */
function parse_PtgFunc(blob, length) {
function parse_PtgFunc(blob, length, opts) {
var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var iftab = blob.read_shift(2);
return [FtabArgc[iftab], Ftab[iftab]];
var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
return [FtabArgc[iftab], Ftab[iftab], type];
}
/* 2.5.198.63 TODO */
function parse_PtgFuncVar(blob, length) {
function parse_PtgFuncVar(blob, length, opts) {
blob.l++;
var cparams = blob.read_shift(1), tab = parsetab(blob);
var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [0, blob.read_shift(1)]: parsetab(blob);
return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
}
@ -195,22 +244,26 @@ function parsetab(blob, length) {
}
/* 2.5.198.41 */
var parse_PtgAttrSum = parseread(4);
function parse_PtgAttrSum(blob, length, opts) {
blob.l += opts && opts.biff == 2 ? 3 : 4; return;
}
/* 2.5.198.43 */
var parse_PtgConcat = parseread1;
/* 2.5.198.58 */
function parse_PtgExp(blob, length) {
function parse_PtgExp(blob, length, opts) {
blob.l++;
if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
var row = blob.read_shift(2);
var col = blob.read_shift(2);
var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
return [row, col];
}
/* 2.5.198.57 */
function parse_PtgErr(blob, length) { blob.l++; return BErr[blob.read_shift(1)]; }
/* 2.5.198.66 TODO */
/* 2.5.198.66 */
function parse_PtgInt(blob, length) { blob.l++; return blob.read_shift(2); }
/* 2.5.198.42 */
@ -220,12 +273,19 @@ function parse_PtgBool(blob, length) { blob.l++; return blob.read_shift(1)!==0;}
function parse_PtgNum(blob, length) { blob.l++; return parse_Xnum(blob, 8); }
/* 2.5.198.89 */
function parse_PtgStr(blob, length) { blob.l++; return parse_ShortXLUnicodeString(blob); }
function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
/* 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
function parse_SerAr(blob) {
var val = [];
switch((val[0] = blob.read_shift(1))) {
/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
/* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */
function parse_SerAr(blob, biff/*:number*/) {
var val = [blob.read_shift(1)];
if(biff == 12) switch(val[0]) {
case 0x02: val[0] = 0x04; break; /* SerBool */
case 0x04: val[0] = 0x10; break; /* SerErr */
case 0x00: val[0] = 0x01; break; /* SerNum */
case 0x01: val[0] = 0x02; break; /* SerStr */
}
switch(val[0]) {
/* 2.5.192.113 */
case 0x04: /* SerBool -- boolean */
val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
@ -242,7 +302,7 @@ function parse_SerAr(blob) {
val[1] = parse_Xnum(blob, 8); break;
/* 2.5.192.117 */
case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
val[1] = parse_XLUnicodeString(blob); break;
val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
// default: throw "Bad SerAr: " + val[0]; /* Unreachable */
}
return val;
@ -257,49 +317,72 @@ function parse_PtgExtraMem(blob, cce) {
}
/* 2.5.198.59 */
function parse_PtgExtraArray(blob) {
var cols = 1 + blob.read_shift(1); //DColByteU
var rows = 1 + blob.read_shift(2); //DRw
function parse_PtgExtraArray(blob, length, opts) {
var rows = 0, cols = 0;
if(opts.biff == 12) {
rows = blob.read_shift(4); // DRw
cols = blob.read_shift(4); // DCol
} else {
cols = 1 + blob.read_shift(1); //DColByteU
rows = 1 + blob.read_shift(2); //DRw
}
if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; }
for(var i = 0, o=[]; i != rows && (o[i] = []); ++i)
for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob);
for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff);
return o;
}
/* 2.5.198.76 */
function parse_PtgName(blob, length) {
function parse_PtgName(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var nameindex = blob.read_shift(4);
var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
var nameindex = blob.read_shift(w);
switch(opts.biff) {
case 2: blob.l += 5; break;
case 3: case 4: blob.l += 8; break;
case 5: blob.l += 12; break;
}
return [type, 0, nameindex];
}
/* 2.5.198.77 */
function parse_PtgNameX(blob, length) {
function parse_PtgNameX(blob, length, opts) {
if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts);
var type = (blob.read_shift(1) >>> 5) & 0x03;
var ixti = blob.read_shift(2); // XtiIndex
var nameindex = blob.read_shift(4);
return [type, ixti, nameindex];
}
function parse_PtgNameX_BIFF5(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var ixti = blob.read_shift(2, 'i'); // XtiIndex
blob.l += 8;
var nameindex = blob.read_shift(2);
blob.l += 12;
return [type, ixti, nameindex];
}
/* 2.5.198.70 */
function parse_PtgMemArea(blob, length) {
function parse_PtgMemArea(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
blob.l += 4;
var cce = blob.read_shift(2);
blob.l += (opts && opts.biff == 2 ? 3 : 4);
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
return [type, cce];
}
/* 2.5.198.72 */
function parse_PtgMemFunc(blob, length) {
function parse_PtgMemFunc(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var cce = blob.read_shift(2);
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
return [type, cce];
}
/* 2.5.198.86 */
function parse_PtgRefErr(blob, length) {
function parse_PtgRefErr(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
blob.l += 4;
if(opts.biff == 12) blob.l += 2;
return [type];
}
@ -425,7 +508,10 @@ var PtgDupes = {
};
(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
var Ptg18 = {};
var Ptg18 = {
// /*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList }, // TODO
// /*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName }, // TODO
};
var Ptg19 = {
/*::[*/0x01/*::]*/: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
/*::[*/0x02/*::]*/: { n:'PtgAttrIf', f:parse_PtgAttrIf },
@ -435,11 +521,13 @@ var Ptg19 = {
/*::[*/0x20/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
/*::[*/0x40/*::]*/: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
/*::[*/0x41/*::]*/: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
/*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
/*::[*/0xFF/*::]*/: {}
};
/* 2.4.127 TODO */
function parse_Formula(blob, length, opts) {
var end = blob.l + length;
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) ++blob.l;
var val = parse_FormulaValue(blob,8);
@ -450,10 +538,7 @@ function parse_Formula(blob, length, opts) {
var chn = blob.read_shift(4);
}
}
var cbf = "";
if(opts.biff < 5) blob.l += length-16;
else if(opts.biff === 5) blob.l += length-20;
else cbf = parse_XLSCellParsedFormula(blob, length-20, opts);
var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
}
@ -472,23 +557,29 @@ function parse_FormulaValue(blob) {
/* 2.5.198.103 */
function parse_RgbExtra(blob, length, rgce, opts) {
if(opts.biff < 8) return parsenoop(blob, length);
var target = blob.l + length;
var o = [];
for(var i = 0; i !== rgce.length; ++i) {
switch(rgce[i][0]) {
case 'PtgArray': /* PtgArray -> PtgExtraArray */
rgce[i][1] = parse_PtgExtraArray(blob);
rgce[i][1] = parse_PtgExtraArray(blob, 0, opts);
o.push(rgce[i][1]);
break;
case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1]);
o.push(rgce[i][2]);
break;
case 'PtgExp': /* PtgExp -> PtgExtraCol */
if(opts && opts.biff == 12) {
rgce[i][1][1] = blob.read_shift(4);
o.push(rgce[i][1]);
} break;
default: break;
}
}
length = target - blob.l;
/* note: this is technically an error but Excel disregards */
//if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
if(length !== 0) o.push(parsenoop(blob, length));
return o;
}
@ -496,7 +587,7 @@ function parse_RgbExtra(blob, length, rgce, opts) {
/* 2.5.198.21 */
function parse_NameParsedFormula(blob, length, opts, cce) {
var target = blob.l + length;
var rgce = parse_Rgce(blob, cce);
var rgce = parse_Rgce(blob, cce, opts);
var rgcb;
if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
return [rgce, rgcb];
@ -504,11 +595,11 @@ function parse_NameParsedFormula(blob, length, opts, cce) {
/* 2.5.198.3 TODO */
function parse_XLSCellParsedFormula(blob, length, opts) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
var rgcb, cce = blob.read_shift(len); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce);
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, length - cce - 2, rgce, opts);
var rgce = parse_Rgce(blob, cce, opts);
if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
return [rgce, rgcb];
}
@ -516,7 +607,7 @@ function parse_XLSCellParsedFormula(blob, length, opts) {
function parse_SharedParsedFormula(blob, length, opts) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
var rgce = parse_Rgce(blob, cce);
var rgce = parse_Rgce(blob, cce, opts);
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
return [rgce, rgcb];
@ -524,41 +615,71 @@ function parse_SharedParsedFormula(blob, length, opts) {
/* 2.5.198.1 TODO */
function parse_ArrayParsedFormula(blob, length, opts, ref) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
var rgcb, cce = blob.read_shift(len); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce);
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
var rgce = parse_Rgce(blob, cce, opts);
if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.104 */
function parse_Rgce(blob, length) {
var gcnt = 0;
function parse_Rgce(blob, length, opts) {
var target = blob.l + length;
var R, id, ptgs = [];
while(target != blob.l) {
length = target - blob.l;
id = blob[blob.l];
R = PtgTypes[id];
//console.log("ptg", id, R)
if(id === 0x18 || id === 0x19) {
id = blob[blob.l + 1];
R = (id === 0x18 ? Ptg18 : Ptg19)[id];
}
if(!R || !R.f) { ptgs.push(parsenoop(blob, length)); }
else { ptgs.push([R.n, R.f(blob, length)]); }
else { ptgs.push([R.n, R.f(blob, length, opts)]); }
}
return ptgs;
}
function mapper(x) { return x.map(function f2(y) { return y[1];}).join(",");}
function stringify_array(f) {
var o = [];
for(var i = 0; i < f.length; ++i) {
var x = f[i], r = [];
for(var j = 0; j < x.length; ++j) {
var y = x[j];
if(y) switch(y[0]) {
// TODO: handle embedded quotes
case 0x02: r.push('"' + y[1].replace(/"/g,'""') + '"'); break;
default: r.push(y[1]);
} else r.push("");
}
o.push(r.join(","));
}
return o.join(";");
}
/* 2.2.2 + Magic TODO */
/* [MS-XLS] 2.2.2 TODO */
/* [MS-XLSB] 2.2.2 */
var PtgBinOp = {
PtgAdd: "+",
PtgConcat: "&",
PtgDiv: "/",
PtgEq: "=",
PtgGe: ">=",
PtgGt: ">",
PtgLe: "<=",
PtgLt: "<",
PtgMul: "*",
PtgNe: "<>",
PtgPower: "^",
PtgSub: "-"
};
function stringify_formula(formula, range, cell, supbooks, opts) {
if(opts !== undefined && opts.biff === 5) return "BIFF5??";
var _range = range !== undefined ? range : {s:{c:0, r:0}};
var stack = [], e1, e2, type, c, ixti, nameidx, r;
var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
var stack = [], e1, e2, type, c, ixti, nameidx, r, sname="";
if(!formula[0] || !formula[0][0]) return "";
var last_sp = -1, sp = "";
//console.log("--",cell,formula[0])
for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
var f = formula[0][ff];
@ -573,65 +694,31 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
case 'PtgPercent': stack.push(stack.pop() + "%"); break;
/* 2.2.2.1 Binary Value Operator Token */
/* 2.5.198.26 */
case 'PtgAdd':
case 'PtgAdd': /* 2.5.198.26 */
case 'PtgConcat': /* 2.5.198.43 */
case 'PtgDiv': /* 2.5.198.45 */
case 'PtgEq': /* 2.5.198.56 */
case 'PtgGe': /* 2.5.198.64 */
case 'PtgGt': /* 2.5.198.65 */
case 'PtgLe': /* 2.5.198.68 */
case 'PtgLt': /* 2.5.198.69 */
case 'PtgMul': /* 2.5.198.75 */
case 'PtgNe': /* 2.5.198.78 */
case 'PtgPower': /* 2.5.198.82 */
case 'PtgSub': /* 2.5.198.90 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"+"+e1);
break;
/* 2.5.198.90 */
case 'PtgSub':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"-"+e1);
break;
/* 2.5.198.75 */
case 'PtgMul':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"*"+e1);
break;
/* 2.5.198.45 */
case 'PtgDiv':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"/"+e1);
break;
/* 2.5.198.82 */
case 'PtgPower':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"^"+e1);
break;
/* 2.5.198.43 */
case 'PtgConcat':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"&"+e1);
break;
/* 2.5.198.69 */
case 'PtgLt':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"<"+e1);
break;
/* 2.5.198.68 */
case 'PtgLe':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"<="+e1);
break;
/* 2.5.198.56 */
case 'PtgEq':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"="+e1);
break;
/* 2.5.198.64 */
case 'PtgGe':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+">="+e1);
break;
/* 2.5.198.65 */
case 'PtgGt':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+">"+e1);
break;
/* 2.5.198.78 */
case 'PtgNe':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"<>"+e1);
if(last_sp >= 0) {
switch(formula[0][last_sp][1][0]) {
case 0: sp = fill(" ", formula[0][last_sp][1][1]); break;
case 1: sp = fill("\r", formula[0][last_sp][1][1]); break;
default:
sp = "";
if(opts.WTF) throw new Error("Unexpected PtgSpace type " + formula[0][last_sp][1][0]);
}
e2 = e2 + sp;
last_sp = -1;
}
stack.push(e2+PtgBinOp[f[0]]+e1);
break;
/* 2.2.2.1 Binary Reference Operator Token */
@ -644,7 +731,10 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+","+e1);
break;
case 'PtgRange': break;
case 'PtgRange':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+":"+e1);
break;
/* 2.2.2.3 Control Tokens "can be ignored" */
/* 2.5.198.34 */
@ -653,21 +743,24 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
case 'PtgAttrGoto': break;
/* 2.5.198.36 */
case 'PtgAttrIf': break;
/* [MS-XLSB] 2.5.97.28 */
case 'PtgAttrIfError': break;
/* 2.5.198.84 */
case 'PtgRef':
type = f[1][0]; c = shift_cell_xls(decode_cell(encode_cell(f[1][1])), _range);
stack.push(encode_cell(c));
type = f[1][0]; c = shift_cell_xls(f[1][1], _range, opts);
stack.push(encode_cell_xls(c));
break;
/* 2.5.198.88 */
case 'PtgRefN':
type = f[1][0]; c = shift_cell_xls(decode_cell(encode_cell(f[1][1])), cell);
stack.push(encode_cell(c));
type = f[1][0]; c = shift_cell_xls(f[1][1], cell, opts);
stack.push(encode_cell_xls(c));
break;
case 'PtgRef3d': // TODO: lots of stuff
type = f[1][0]; ixti = f[1][1]; c = shift_cell_xls(f[1][2], _range);
stack.push(supbooks[1][ixti+1]+"!"+encode_cell(c));
type = f[1][0]; ixti = f[1][1]; c = shift_cell_xls(f[1][2], _range, opts);
sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**");
stack.push(sname + "!" + encode_cell(c));
break;
/* Function Call */
@ -675,10 +768,10 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
case 'PtgFunc':
/* 2.5.198.63 */
case 'PtgFuncVar':
/* f[1] = [argc, func] */
/* f[1] = [argc, func, type] */
var argc = f[1][0], func = f[1][1];
if(!argc) argc = 0;
var args = stack.slice(-argc);
var args = argc == 0 ? [] : stack.slice(-argc);
stack.length -= argc;
if(func === 'User') func = args.shift();
stack.push(func + "(" + args.join(",") + ")");
@ -697,12 +790,13 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
/* 2.5.198.27 TODO: fixed points */
case 'PtgArea':
type = f[1][0]; r = shift_range_xls(f[1][1], _range);
stack.push(encode_range(r));
stack.push(encode_range_xls(r));
break;
/* 2.5.198.28 */
case 'PtgArea3d': // TODO: lots of stuff
type = f[1][0]; ixti = f[1][1]; r = f[1][2];
stack.push(supbooks[1][ixti+1]+"!"+encode_range(r));
sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**");
stack.push(sname + "!" + encode_range(r));
break;
/* 2.5.198.41 */
case 'PtgAttrSum':
@ -718,7 +812,7 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
/* f[1] = type, 0, nameindex */
nameidx = f[1][2];
var lbl = supbooks[0][nameidx];
var name = lbl.Name;
var name = lbl ? lbl.Name : "**MISSING**" + nameidx;
if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
stack.push(name);
break;
@ -728,15 +822,35 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
/* f[1] = type, ixti, nameindex */
var bookidx = f[1][1]; nameidx = f[1][2]; var externbook;
/* TODO: Properly handle missing values */
if(supbooks[bookidx+1]) externbook = supbooks[bookidx+1][nameidx];
else if(supbooks[bookidx-1]) externbook = supbooks[bookidx-1][nameidx];
//console.log(bookidx, supbooks);
if(opts.biff == 5) {
if(bookidx < 0) bookidx = -bookidx;
if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
} else {
if(supbooks[bookidx+1]) externbook = supbooks[bookidx+1][nameidx];
else if(supbooks[bookidx-1]) externbook = supbooks[bookidx-1][nameidx];
}
if(!externbook) externbook = {body: "??NAMEX??"};
stack.push(externbook.body);
break;
/* 2.2.2.4 Display Tokens */
/* 2.5.198.80 */
case 'PtgParen': stack.push('(' + stack.pop() + ')'); break;
case 'PtgParen':
var lp = '(', rp = ')';
if(last_sp >= 0) {
sp = "";
switch(formula[0][last_sp][1][0]) {
case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
case 4: rp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
case 5: rp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
default:
if(opts.WTF) throw new Error("Unexpected PtgSpace type " + formula[0][last_sp][1][0]);
}
last_sp = -1;
}
stack.push(lp + stack.pop() + rp); break;
/* 2.5.198.86 */
case 'PtgRefErr': stack.push('#REF!'); break;
@ -758,6 +872,8 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
fnd = true;
break;
}
if(!fnd) stack.push(f[1]);
}
@ -765,7 +881,7 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
/* 2.5.198.32 TODO */
case 'PtgArray':
stack.push("{" + f[1].map(mapper).join(";") + "}");
stack.push("{" + stringify_array(f[1]) + "}");
break;
/* 2.2.2.5 Mem Tokens */
@ -774,8 +890,11 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
//stack.push("(" + f[2].map(encode_range).join(",") + ")");
break;
/* 2.5.198.38 TODO */
case 'PtgAttrSpace': break;
/* 2.5.198.38 */
case 'PtgAttrSpace':
case 'PtgAttrSpaceSemi':
last_sp = ff;
break;
/* 2.5.198.92 TODO */
case 'PtgTbl': break;
@ -802,9 +921,23 @@ function stringify_formula(formula, range, cell, supbooks, opts) {
default: throw 'Unrecognized Formula Token: ' + f;
}
var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto'];
if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) {
f = formula[0][last_sp];
switch(f[1][0]) {
case 0: sp = fill(" ", f[1][1]); break;
case 1: sp = fill("\r", f[1][1]); break;
default:
sp = "";
if(opts.WTF) throw new Error("Unexpected PtgSpace type " + f[1][0]);
}
stack.push(sp + stack.pop());
last_sp = -1;
}
//console.log("::",f, stack)
}
//console.log("--",stack);
if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
return stack[0];
}

@ -1,5 +1,18 @@
/* [MS-XLSB] 2.5.97.4 CellParsedFormula TODO: use similar logic to js-xls */
function parse_XLSBCellParsedFormula(data, length) {
/* XLSB Parsed Formula records have the same shape */
function parse_XLSBParsedFormula(data, length, opts) {
var end = data.l + length;
var cce = data.read_shift(4);
return parsenoop(data, length-4);
var rgce = parse_Rgce(data, cce, opts);
var cb = data.read_shift(4);
var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null;
return [rgce, rgcb];
}
/* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */
var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula;
/* [MS-XLSB] 2.5.97.4 CellParsedFormula */
var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula;
/* [MS-XLSB] 2.5.97.12 NameParsedFormula */
var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula;
/* [MS-XLSB] 2.5.97.98 SharedParsedFormula */
var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula;

@ -406,6 +406,7 @@ var Cetab = {
};
/* [MS-XLS] 2.5.198.17 */
/* [MS-XLSB] 2.5.97.10 */
var Ftab = {
/*::[*/0x0000/*::]*/: 'COUNT',
/*::[*/0x0001/*::]*/: 'IF',
@ -779,7 +780,113 @@ var Ftab = {
/*::[*/0x0178/*::]*/: 'ROUNDBAHTDOWN',
/*::[*/0x0179/*::]*/: 'ROUNDBAHTUP',
/*::[*/0x017A/*::]*/: 'THAIYEAR',
/*::[*/0x017B/*::]*/: 'RTD'
/*::[*/0x017B/*::]*/: 'RTD',
/*::[*/0x017C/*::]*/: 'CUBEVALUE',
/*::[*/0x017D/*::]*/: 'CUBEMEMBER',
/*::[*/0x017E/*::]*/: 'CUBEMEMBERPROPERTY',
/*::[*/0x017F/*::]*/: 'CUBERANKEDMEMBER',
/*::[*/0x0180/*::]*/: 'HEX2BIN',
/*::[*/0x0181/*::]*/: 'HEX2DEC',
/*::[*/0x0182/*::]*/: 'HEX2OCT',
/*::[*/0x0183/*::]*/: 'DEC2BIN',
/*::[*/0x0184/*::]*/: 'DEC2HEX',
/*::[*/0x0185/*::]*/: 'DEC2OCT',
/*::[*/0x0186/*::]*/: 'OCT2BIN',
/*::[*/0x0187/*::]*/: 'OCT2HEX',
/*::[*/0x0188/*::]*/: 'OCT2DEC',
/*::[*/0x0189/*::]*/: 'BIN2DEC',
/*::[*/0x018A/*::]*/: 'BIN2OCT',
/*::[*/0x018B/*::]*/: 'BIN2HEX',
/*::[*/0x018C/*::]*/: 'IMSUB',
/*::[*/0x018D/*::]*/: 'IMDIV',
/*::[*/0x018E/*::]*/: 'IMPOWER',
/*::[*/0x018F/*::]*/: 'IMABS',
/*::[*/0x0190/*::]*/: 'IMSQRT',
/*::[*/0x0191/*::]*/: 'IMLN',
/*::[*/0x0192/*::]*/: 'IMLOG2',
/*::[*/0x0193/*::]*/: 'IMLOG10',
/*::[*/0x0194/*::]*/: 'IMSIN',
/*::[*/0x0195/*::]*/: 'IMCOS',
/*::[*/0x0196/*::]*/: 'IMEXP',
/*::[*/0x0197/*::]*/: 'IMARGUMENT',
/*::[*/0x0198/*::]*/: 'IMCONJUGATE',
/*::[*/0x0199/*::]*/: 'IMAGINARY',
/*::[*/0x019A/*::]*/: 'IMREAL',
/*::[*/0x019B/*::]*/: 'COMPLEX',
/*::[*/0x019C/*::]*/: 'IMSUM',
/*::[*/0x019D/*::]*/: 'IMPRODUCT',
/*::[*/0x019E/*::]*/: 'SERIESSUM',
/*::[*/0x019F/*::]*/: 'FACTDOUBLE',
/*::[*/0x01A0/*::]*/: 'SQRTPI',
/*::[*/0x01A1/*::]*/: 'QUOTIENT',
/*::[*/0x01A2/*::]*/: 'DELTA',
/*::[*/0x01A3/*::]*/: 'GESTEP',
/*::[*/0x01A4/*::]*/: 'ISEVEN',
/*::[*/0x01A5/*::]*/: 'ISODD',
/*::[*/0x01A6/*::]*/: 'MROUND',
/*::[*/0x01A7/*::]*/: 'ERF',
/*::[*/0x01A8/*::]*/: 'ERFC',
/*::[*/0x01A9/*::]*/: 'BESSELJ',
/*::[*/0x01AA/*::]*/: 'BESSELK',
/*::[*/0x01AB/*::]*/: 'BESSELY',
/*::[*/0x01AC/*::]*/: 'BESSELI',
/*::[*/0x01AD/*::]*/: 'XIRR',
/*::[*/0x01AE/*::]*/: 'XNPV',
/*::[*/0x01AF/*::]*/: 'PRICEMAT',
/*::[*/0x01B0/*::]*/: 'YIELDMAT',
/*::[*/0x01B1/*::]*/: 'INTRATE',
/*::[*/0x01B2/*::]*/: 'RECEIVED',
/*::[*/0x01B3/*::]*/: 'DISC',
/*::[*/0x01B4/*::]*/: 'PRICEDISC',
/*::[*/0x01B5/*::]*/: 'YIELDDISC',
/*::[*/0x01B6/*::]*/: 'TBILLEQ',
/*::[*/0x01B7/*::]*/: 'TBILLPRICE',
/*::[*/0x01B8/*::]*/: 'TBILLYIELD',
/*::[*/0x01B9/*::]*/: 'PRICE',
/*::[*/0x01BA/*::]*/: 'YIELD',
/*::[*/0x01BB/*::]*/: 'DOLLARDE',
/*::[*/0x01BC/*::]*/: 'DOLLARFR',
/*::[*/0x01BD/*::]*/: 'NOMINAL',
/*::[*/0x01BE/*::]*/: 'EFFECT',
/*::[*/0x01BF/*::]*/: 'CUMPRINC',
/*::[*/0x01C0/*::]*/: 'CUMIPMT',
/*::[*/0x01C1/*::]*/: 'EDATE',
/*::[*/0x01C2/*::]*/: 'EOMONTH',
/*::[*/0x01C3/*::]*/: 'YEARFRAC',
/*::[*/0x01C4/*::]*/: 'COUPDAYBS',
/*::[*/0x01C5/*::]*/: 'COUPDAYS',
/*::[*/0x01C6/*::]*/: 'COUPDAYSNC',
/*::[*/0x01C7/*::]*/: 'COUPNCD',
/*::[*/0x01C8/*::]*/: 'COUPNUM',
/*::[*/0x01C9/*::]*/: 'COUPPCD',
/*::[*/0x01CA/*::]*/: 'DURATION',
/*::[*/0x01CB/*::]*/: 'MDURATION',
/*::[*/0x01CC/*::]*/: 'ODDLPRICE',
/*::[*/0x01CD/*::]*/: 'ODDLYIELD',
/*::[*/0x01CE/*::]*/: 'ODDFPRICE',
/*::[*/0x01CF/*::]*/: 'ODDFYIELD',
/*::[*/0x01D0/*::]*/: 'RANDBETWEEN',
/*::[*/0x01D1/*::]*/: 'WEEKNUM',
/*::[*/0x01D2/*::]*/: 'AMORDEGRC',
/*::[*/0x01D3/*::]*/: 'AMORLINC',
/*::[*/0x01D4/*::]*/: 'SHEETJS',
/*::[*/0x01D5/*::]*/: 'ACCRINT',
/*::[*/0x01D6/*::]*/: 'ACCRINTM',
/*::[*/0x01D7/*::]*/: 'WORKDAY',
/*::[*/0x01D8/*::]*/: 'NETWORKDAYS',
/*::[*/0x01D9/*::]*/: 'GCD',
/*::[*/0x01DA/*::]*/: 'MULTINOMIAL',
/*::[*/0x01DB/*::]*/: 'LCM',
/*::[*/0x01DC/*::]*/: 'FVSCHEDULE',
/*::[*/0x01DD/*::]*/: 'CUBEKPIMEMBER',
/*::[*/0x01DE/*::]*/: 'CUBESET',
/*::[*/0x01DF/*::]*/: 'CUBESETCOUNT',
/*::[*/0x01E0/*::]*/: 'IFERROR',
/*::[*/0x01E1/*::]*/: 'COUNTIFS',
/*::[*/0x01E2/*::]*/: 'SUMIFS',
/*::[*/0x01E3/*::]*/: 'AVERAGEIF',
/*::[*/0x01E4/*::]*/: 'AVERAGEIFS'
};
var FtabArgc = {
/*::[*/0x0002/*::]*/: 1, /* ISNA */
@ -788,6 +895,7 @@ var FtabArgc = {
/*::[*/0x0010/*::]*/: 1, /* COS */
/*::[*/0x0011/*::]*/: 1, /* TAN */
/*::[*/0x0012/*::]*/: 1, /* ATAN */
/*::[*/0x0013/*::]*/: 0, /* PI */
/*::[*/0x0014/*::]*/: 1, /* SQRT */
/*::[*/0x0015/*::]*/: 1, /* EXP */
/*::[*/0x0016/*::]*/: 1, /* LN */
@ -817,6 +925,7 @@ var FtabArgc = {
/*::[*/0x0043/*::]*/: 1, /* DAY */
/*::[*/0x0044/*::]*/: 1, /* MONTH */
/*::[*/0x0045/*::]*/: 1, /* YEAR */
/*::[*/0x0046/*::]*/: 1, /* WEEKDAY */
/*::[*/0x0047/*::]*/: 1, /* HOUR */
/*::[*/0x0048/*::]*/: 1, /* MINUTE */
/*::[*/0x0049/*::]*/: 1, /* SECOND */
@ -826,11 +935,14 @@ var FtabArgc = {
/*::[*/0x004F/*::]*/: 2, /* ABSREF */
/*::[*/0x0050/*::]*/: 2, /* RELREF */
/*::[*/0x0053/*::]*/: 1, /* TRANSPOSE */
/*::[*/0x0055/*::]*/: 0, /* STEP */
/*::[*/0x0056/*::]*/: 1, /* TYPE */
/*::[*/0x005A/*::]*/: 1, /* DEREF */
/*::[*/0x0061/*::]*/: 2, /* ATAN2 */
/*::[*/0x0062/*::]*/: 1, /* ASIN */
/*::[*/0x0063/*::]*/: 1, /* ACOS */
/*::[*/0x0065/*::]*/: 3, /* HLOOKUP */
/*::[*/0x0066/*::]*/: 3, /* VLOOKUP */
/*::[*/0x0069/*::]*/: 1, /* ISREF */
/*::[*/0x006F/*::]*/: 1, /* CHAR */
/*::[*/0x0070/*::]*/: 1, /* LOWER */
@ -856,6 +968,7 @@ var FtabArgc = {
/*::[*/0x008D/*::]*/: 1, /* TIMEVALUE */
/*::[*/0x008E/*::]*/: 3, /* SLN */
/*::[*/0x008F/*::]*/: 4, /* SYD */
/*::[*/0x0090/*::]*/: 4, /* DDB */
/*::[*/0x00A2/*::]*/: 1, /* CLEAN */
/*::[*/0x00A3/*::]*/: 1, /* MDETERM */
/*::[*/0x00A4/*::]*/: 1, /* MINVERSE */
@ -871,6 +984,7 @@ var FtabArgc = {
/*::[*/0x00BE/*::]*/: 1, /* ISNONTEXT */
/*::[*/0x00C3/*::]*/: 3, /* DSTDEVP */
/*::[*/0x00C4/*::]*/: 3, /* DVARP */
/*::[*/0x00C5/*::]*/: 1, /* TRUNC */
/*::[*/0x00C6/*::]*/: 1, /* ISLOGICAL */
/*::[*/0x00C7/*::]*/: 3, /* DCOUNTA */
/*::[*/0x00C9/*::]*/: 1, /* UNREGISTER */
@ -889,6 +1003,7 @@ var FtabArgc = {
/*::[*/0x00EA/*::]*/: 1, /* ATANH */
/*::[*/0x00EB/*::]*/: 3, /* DGET */
/*::[*/0x00F4/*::]*/: 1, /* INFO */
/*::[*/0x00F7/*::]*/: 4, /* DB */
/*::[*/0x00FC/*::]*/: 2, /* FREQUENCY */
/*::[*/0x0101/*::]*/: 1, /* EVALUATE */
/*::[*/0x0105/*::]*/: 1, /* ERROR.TYPE */
@ -964,9 +1079,13 @@ var FtabArgc = {
/*::[*/0x0178/*::]*/: 1, /* ROUNDBAHTDOWN */
/*::[*/0x0179/*::]*/: 1, /* ROUNDBAHTUP */
/*::[*/0x017A/*::]*/: 1, /* THAIYEAR */
/*::[*/0x01A0/*::]*/: 1, /* SQRTPI */
/*::[*/0x01C1/*::]*/: 2, /* EDATE */
/*::[*/0x01C2/*::]*/: 2, /* EOMONTH */
/*::[*/0xFFFF/*::]*/: 0
};
/* [MS-XLSX] 2.2.3 Functions */
/* [MS-XLSB] 2.5.97.10 Ftab */
var XLSXFutureFunctions = {
"_xlfn.ACOT": "ACOT",
"_xlfn.ACOTH": "ACOTH",

@ -8,10 +8,10 @@ var hlinkregex = /<(?:\w*:)?hyperlink[^>]*\/>/g;
var dimregex = /"(\w*:\w*)"/;
var colregex = /<(?:\w*:)?col[^>]*\/>/g;
/* 18.3 Worksheets */
function parse_ws_xml(data/*:?string*/, opts, rels) {
function parse_ws_xml(data/*:?string*/, opts, rels)/*:Worksheet*/ {
if(!data) return data;
/* 18.3.1.99 worksheet CT_Worksheet */
var s = {};
var s = ({}/*:any*/);
/* 18.3.1.35 dimension CT_SheetDimension ? */
// $FlowIgnore
@ -166,13 +166,16 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
var parse_ws_xml_data = (function parse_ws_xml_data_factory() {
var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
var refregex = /ref=["']([^"']*)["']/;
var match_v = matchtag("v"), match_f = matchtag("f");
return function parse_ws_xml_data(sdata, s, opts, guess) {
var ri = 0, x = "", cells = [], cref = [], idx = 0, i=0, cc=0, d="", p/*:any*/;
var tag, tagr = 0, tagc = 0;
var sstr;
var sstr, ftag;
var fmtid = 0, fillid = 0, do_format = Array.isArray(styles.CellXf), cf;
var arrayf = [];
var sharedf = [];
for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
x = marr[mt].trim();
var xlen = x.length;
@ -209,10 +212,29 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
d = x.substr(i);
p = ({t:""}/*:any*/);
// $FlowIgnore
if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
// $FlowIgnore
if(opts.cellFormula && (cref=d.match(match_f))!= null && cref[1] !== '') p.f=unescapexml(cref[1]);
if((cref=d.match(match_v))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]);
if(opts.cellFormula) {
if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') {
p.f=unescapexml(utf8read(cref[1]));
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) {
p.F = (d.match(refregex)||[])[1];
if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
// TODO: parse formula
ftag = parsexmltag(cref[0]);
sharedf[parseInt(ftag.si, 10)] = [ftag, unescapexml(utf8read(cref[1]))];
}
} else if((cref=d.match(/<f[^>]*\/>/))) {
ftag = parsexmltag(cref[0]);
if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][0].ref, tag.r);
}
/* TODO: factor out contains logic */
var _tag = decode_cell(tag.r);
for(i = 0; i < arrayf.length; ++i)
if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
p.F = arrayf[i][1];
}
/* SCHEMA IS ACTUALLY INCORRECT HERE. IF A CELL HAS NO T, EMIT "" */
if(tag.t === undefined && p.v === undefined) {

@ -145,53 +145,65 @@ function write_BrtCellSt(cell, ncell, o) {
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
function parse_BrtFmlaBool(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
cell.r = opts['!row'];
var value = data.read_shift(1);
var o = [cell, value, 'b'];
if(opts.cellFormula) {
var formula = parse_XLSBCellParsedFormula(data, length-9);
o[3] = ""; /* TODO */
data.l += 2;
var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
}
else data.l += length-9;
else data.l = end;
return o;
}
/* [MS-XLSB] 2.4.648 BrtFmlaError */
function parse_BrtFmlaError(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
cell.r = opts['!row'];
var value = data.read_shift(1);
var o = [cell, value, 'e'];
if(opts.cellFormula) {
var formula = parse_XLSBCellParsedFormula(data, length-9);
o[3] = ""; /* TODO */
data.l += 2;
var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
}
else data.l += length-9;
else data.l = end;
return o;
}
/* [MS-XLSB] 2.4.649 BrtFmlaNum */
function parse_BrtFmlaNum(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
cell.r = opts['!row'];
var value = parse_Xnum(data);
var o = [cell, value, 'n'];
if(opts.cellFormula) {
var formula = parse_XLSBCellParsedFormula(data, length - 16);
o[3] = ""; /* TODO */
data.l += 2;
var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
}
else data.l += length-16;
else data.l = end;
return o;
}
/* [MS-XLSB] 2.4.650 BrtFmlaString */
function parse_BrtFmlaString(data, length, opts) {
var start = data.l;
var end = data.l + length;
var cell = parse_XLSBCell(data);
cell.r = opts['!row'];
var value = parse_XLWideString(data);
var o = [cell, value, 'str'];
if(opts.cellFormula) {
var formula = parse_XLSBCellParsedFormula(data, start + length - data.l);
data.l += 2;
var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
}
else data.l = start + length;
else data.l = end;
return o;
}
@ -210,8 +222,34 @@ function parse_BrtHLink(data, length, opts) {
return {rfx:rfx, relId:relId, loc:loc, tooltip:tooltip, display:display};
}
/* [MS-XLSB] 2.4.6 BrtArrFmla */
function parse_BrtArrFmla(data, length, opts) {
var end = data.l + length;
var rfx = parse_RfX(data, 16);
var fAlwaysCalc = data.read_shift(1);
var o = [rfx, null, fAlwaysCalc];
if(opts.cellFormula) {
var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts);
o[1] = formula;
} else data.l = end;
return o;
}
/* [MS-XLSB] 2.4.742 BrtShrFmla */
function parse_BrtShrFmla(data, length, opts) {
var end = data.l + length;
var rfx = parse_UncheckedRfX(data, 16);
var o = [rfx, null];
if(opts.cellFormula) {
var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts);
o[1] = formula;
data.l = end;
} else data.l = end;
return o;
}
/* [MS-XLSB] 2.1.7.61 Worksheet */
function parse_ws_bin(data, opts, rels) {
function parse_ws_bin(data, opts, rels, wb)/*:Worksheet*/ {
if(!data) return data;
if(!rels) rels = {'!id':{}};
var s = {};
@ -222,8 +260,22 @@ function parse_ws_bin(data, opts, rels) {
var pass = false, end = false;
var row, p, cf, R, C, addr, sstr, rr;
var mergecells = [];
if(!opts) opts = {};
opts.biff = 12;
opts['!row'] = 0;
var ai = 0, af = false;
var array_formulae = [];
var shared_formulae = {};
var supbooks = ([[]]/*:any*/);
supbooks.sharedf = shared_formulae;
supbooks.arrayf = array_formulae;
opts.supbooks = supbooks;
for(var i = 0; i < wb.Names['!names'].length; ++i) supbooks[0][i+1] = wb.Names[wb.Names['!names'][i]];
recordhopper(data, function ws_parse(val, Record) {
//console.log(Record);
if(end) return;
switch(Record.n) {
case 'BrtWsDim': ref = val; break;
@ -231,6 +283,7 @@ function parse_ws_bin(data, opts, rels) {
row = val;
if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
rr = encode_row(row.r);
opts['!row'] = row.r;
break;
case 'BrtFmlaBool':
@ -251,9 +304,19 @@ function parse_ws_bin(data, opts, rels) {
case 'e': p.v = val[1]; p.w = BErr[p.v]; break;
case 'str': p.t = 's'; p.v = utf8read(val[1]); break;
}
if(opts.cellFormula && val.length > 3) p.f = val[3];
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts);
s[encode_col(C=val[0].c) + rr] = p;
if(opts.cellFormula) {
af = false;
for(ai = 0; ai < array_formulae.length; ++ai) {
var aii = array_formulae[ai];
if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
if(C >= aii[0].s.c && C <= aii[0].e.c) {
p.F = encode_range(aii[0]); af = true;
}
}
if(!af && val.length > 3) p.f = val[3];
}
if(refguess.s.r > row.r) refguess.s.r = row.r;
if(refguess.s.c > C) refguess.s.c = C;
if(refguess.e.r < row.r) refguess.e.r = row.r;
@ -288,8 +351,17 @@ function parse_ws_bin(data, opts, rels) {
}
break;
case 'BrtArrFmla': break; // TODO
case 'BrtShrFmla': break; // TODO
case 'BrtArrFmla': if(!opts.cellFormula) break;
array_formulae.push(val);
s[encode_col(C) + rr].f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
s[encode_col(C) + rr].F = encode_range(val[0]);
break;
case 'BrtShrFmla': if(!opts.cellFormula) break;
// TODO
shared_formulae[encode_cell(val[0].s)] = val[1];
s[encode_col(C) + rr].f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
break;
case 'BrtBeginSheet': break;
case 'BrtWsProp': break; // TODO
case 'BrtSheetCalcProp': break; // TODO
@ -400,6 +472,10 @@ function parse_ws_bin(data, opts, rels) {
default: if(!pass || opts.WTF) throw new Error("Unexpected record " + Record.n);
}
}, opts);
delete opts.supbooks;
delete opts['!row'];
if(!s["!ref"] && (refguess.s.r < 2000000 || ref && (ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0))) s["!ref"] = encode_range(ref || refguess);
if(opts.sheetRows && s["!ref"]) {
var tmpref = safe_decode_range(s["!ref"]);

@ -38,15 +38,43 @@ function parse_BrtFRTArchID$(data, length) {
return o;
}
/* [MS-XLSB] 2.4.680 BrtName */
function parse_BrtName(data, length, opts) {
var end = data.l + length;
var flags = data.read_shift(4);
var chKey = data.read_shift(1);
var itab = data.read_shift(4);
var name = parse_XLNameWideString(data);
var formula = parse_XLSBNameParsedFormula(data, 0, opts);
var comment = parse_XLNullableWideString(data);
if(0 /* fProc */) {
// unusedstring1: XLNullableWideString
// description: XLNullableWideString
// helpTopic: XLNullableWideString
// unusedstring2: XLNullableWideString
}
data.l = end;
return {Name:name, Ptg:formula, Comment:comment};
}
/* [MS-XLSB] 2.1.7.60 Workbook */
function parse_wb_bin(data, opts) {
var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
var pass = false, z;
if(!opts) opts = {};
opts.biff = 12;
var Names = {}, NameList = [];
recordhopper(data, function hopper_wb(val, R) {
switch(R.n) {
case 'BrtBundleSh': wb.Sheets.push(val); break;
case 'BrtName':
Names[val.Name] = val; NameList.push(val.Name);
break;
case 'BrtBeginBook': break;
case 'BrtFileVersion': break;
case 'BrtWbProp14': case 'BrtWbProp': break;
@ -68,7 +96,6 @@ function parse_wb_bin(data, opts) {
case 'BrtSupBookSrc': break;
case 'BrtExternSheet': break;
case 'BrtEndExternals': break;
case 'BrtName': break;
case 'BrtCalcProp': break;
case 'BrtUserBookView': break;
case 'BrtBeginPivotCacheIDs': break;
@ -95,10 +122,13 @@ function parse_wb_bin(data, opts) {
case 'BrtEndBook': break;
default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n);
}
});
}, opts);
parse_wb_defaults(wb);
Names['!names'] = NameList;
wb.Names = Names;
return wb;
}

@ -3,9 +3,9 @@ function parse_wb(data, name/*:string*/, opts)/*:Workbook*/ {
return parse_wb_xml((data/*:any*/), opts);
}
function parse_ws(data, name/*:string*/, opts, rels)/*:Worksheet*/ {
if(name.substr(name.length-4)===".bin") return parse_ws_bin((data/*:any*/), opts, rels);
return parse_ws_xml((data/*:any*/), opts, rels);
function parse_ws(data, name/*:string*/, opts, rels, wb)/*:Worksheet*/ {
if(name.substr(name.length-4)===".bin") return parse_ws_bin((data/*:any*/), opts, rels, wb);
return parse_ws_xml((data/*:any*/), opts, rels, wb);
}
function parse_sty(data, name/*:string*/, opts) {

@ -82,7 +82,7 @@ function process_style_xlml(styles, stag, opts) {
}
/* TODO: there must exist some form of OSP-blessed spec */
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, o)/*:Workbook*/ {
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o)/*:Workbook*/ {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
if(sid === undefined && row) sid = row.StyleID;
@ -100,7 +100,7 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, o
break;
case 'String':
cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
cell.v = xml.indexOf("<") > -1 ? ss : cell.r;
cell.v = xml.indexOf("<") > -1 ? unescapexml(ss) : cell.r;
break;
case 'DateTime':
cell.v = (Date.parse(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
@ -116,9 +116,24 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, o
default: cell.t = 's'; cell.v = xlml_fixstr(ss); break;
}
safe_format_xlml(cell, nf, o);
if(o.cellFormula != null && cell.Formula) {
cell.f = rc_to_a1(unescapexml(cell.Formula), base);
cell.Formula = undefined;
if(o.cellFormula != null) {
if(cell.Formula) {
var fstr = unescapexml(cell.Formula);
/* strictly speaking, the leading = is required but some writers omit */
if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.substr(1);
cell.f = rc_to_a1(fstr, base);
cell.Formula = undefined;
if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base);
else if(cell.ArrayRange) {
cell.F = rc_to_a1(cell.ArrayRange, base);
arrayf.push([safe_decode_range(cell.F), cell.F]);
}
} else {
for(i = 0; i < arrayf.length; ++i)
if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r)
if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c)
cell.F = arrayf[i][1];
}
}
if(o.cellStyles) {
interiors.forEach(function(x) {
@ -157,11 +172,12 @@ function parse_xlml_xml(d, opts) {
var Props = {}, Custprops = {}, pidx = 0, cp = {};
var comments = [], comment = {};
var cstys = [], csty;
var arrayf = [];
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'Data':
if(state[state.length-1][1]) break;
if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, opts);
if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts);
else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
break;
case 'Cell':

@ -304,7 +304,15 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
default:
temp_val = ({v:val.val, ixfe:val.cell.ixfe, t:val.tt}/*:any*/);
temp_val.XF = XFs[temp_val.ixfe];
if(options.cellFormula) temp_val.f = "="+stringify_formula(val.formula,range,val.cell,supbooks, opts);
if(options.cellFormula) {
var _f = val.formula;
if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
var _fe = encode_cell({r:_fr, c:_fc});
if(shared_formulae[_fe]) temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks, opts);
else temp_val.F = (out[_fe] || {}).F;
} else temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks, opts);
}
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(val.cell, temp_val, options);
last_formula = val;
@ -315,7 +323,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
last_formula.val = val;
temp_val = ({v:last_formula.val, ixfe:last_formula.cell.ixfe, t:'s'}/*:any*/);
temp_val.XF = XFs[temp_val.ixfe];
if(options.cellFormula) temp_val.f = "="+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
if(options.cellFormula) temp_val.f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(last_formula.cell, temp_val, options);
last_formula = null;
@ -323,12 +331,19 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
} break;
case 'Array': {
array_formulae.push(val);
if(options.cellFormula && out[last_cell]) {
out[last_cell].f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
out[last_cell].F = encode_range(val[0]);
}
} break;
case 'ShrFmla': {
if(!cell_valid) break;
//if(options.cellFormula) out[last_cell].f = stringify_formula(val[0], range, lastcell, supbooks, opts);
/* TODO: capture range */
if(last_formula) shared_formulae[encode_cell(last_formula.cell)]= val[0];
if(!options.cellFormula) break;
if(last_cell) {
/* TODO: capture range */
shared_formulae[encode_cell(last_formula.cell)]= val[0];
(out[encode_cell(last_formula.cell)]||{}).f = stringify_formula(val[0], range, lastcell, supbooks, opts);
}
} break;
case 'LabelSst':
temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
@ -336,6 +351,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'RString':
case 'Label': case 'BIFF2STR':
temp_val=make_cell(val.val, val.ixfe, 's');
temp_val.XF = XFs[temp_val.ixfe];
@ -609,14 +625,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
default: switch(R.n) { /* nested */
/* BIFF5 records */
case 'ExternCount': break;
case 'RString': break;
case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
/* BIFF2-4 records */
case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': break;
case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break;
case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break;
case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break;
case 'Dimension': break;
/* Miscellaneous */
case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':

@ -33,7 +33,7 @@ var XLSBRecordEnum = {
/*::[*/0x0024/*::]*/: { n:"BrtFRTEnd", f:parsenoop },
/*::[*/0x0025/*::]*/: { n:"BrtACBegin", f:parsenoop },
/*::[*/0x0026/*::]*/: { n:"BrtACEnd", f:parsenoop },
/*::[*/0x0027/*::]*/: { n:"BrtName", f:parsenoop },
/*::[*/0x0027/*::]*/: { n:"BrtName", f:parse_BrtName },
/*::[*/0x0028/*::]*/: { n:"BrtIndexRowBlock", f:parsenoop },
/*::[*/0x002A/*::]*/: { n:"BrtIndexBlock", f:parsenoop },
/*::[*/0x002B/*::]*/: { n:"BrtFont", f:parse_BrtFont },
@ -356,8 +356,8 @@ var XLSBRecordEnum = {
/*::[*/0x01A7/*::]*/: { n:"BrtBeginUserShView", f:parsenoop },
/*::[*/0x01A8/*::]*/: { n:"BrtEndUserShView", f:parsenoop },
/*::[*/0x01A9/*::]*/: { n:"BrtEndUserShViews", f:parsenoop },
/*::[*/0x01AA/*::]*/: { n:"BrtArrFmla", f:parsenoop },
/*::[*/0x01AB/*::]*/: { n:"BrtShrFmla", f:parsenoop },
/*::[*/0x01AA/*::]*/: { n:"BrtArrFmla", f:parse_BrtArrFmla },
/*::[*/0x01AB/*::]*/: { n:"BrtShrFmla", f:parse_BrtShrFmla },
/*::[*/0x01AC/*::]*/: { n:"BrtTable", f:parsenoop },
/*::[*/0x01AD/*::]*/: { n:"BrtBeginExtConnections", f:parsenoop },
/*::[*/0x01AE/*::]*/: { n:"BrtEndExtConnections", f:parsenoop },
@ -1019,6 +1019,7 @@ var XLSRecordEnum = {
/*::[*/0x0203/*::]*/: { n:"Number", f:parse_Number },
/*::[*/0x0204/*::]*/: { n:"Label", f:parse_Label },
/*::[*/0x0205/*::]*/: { n:"BoolErr", f:parse_BoolErr },
/*::[*/0x0206/*::]*/: { n:"Formula", f:parse_Formula },
/*::[*/0x0207/*::]*/: { n:"String", f:parse_String },
/*::[*/0x0208/*::]*/: { n:'Row', f:parse_Row },
/*::[*/0x020b/*::]*/: { n:"Index", f:parse_Index },
@ -1028,6 +1029,7 @@ var XLSRecordEnum = {
/*::[*/0x023e/*::]*/: { n:"Window2", f:parse_Window2 },
/*::[*/0x027e/*::]*/: { n:"RK", f:parse_RK },
/*::[*/0x0293/*::]*/: { n:"Style", f:parse_Style },
/*::[*/0x0406/*::]*/: { n:"Formula", f:parse_Formula },
/*::[*/0x0418/*::]*/: { n:"BigName", f:parse_BigName },
/*::[*/0x041e/*::]*/: { n:"Format", f:parse_Format },
/*::[*/0x043c/*::]*/: { n:"ContinueBigName", f:parse_ContinueBigName },
@ -1184,7 +1186,7 @@ var XLSRecordEnum = {
/*::[*/0x1068/*::]*/: { n:"Fbi2", f:parse_Fbi2 },
/* These are specified in an older version of the spec */
/*::[*/0x0000/*::]*/: { n:"Dimension", f:parsenoop },
/*::[*/0x0000/*::]*/: { n:"Dimensions", f:parse_Dimensions },
/*::[*/0x0002/*::]*/: { n:"BIFF2INT", f:parse_BIFF2INT },
/*::[*/0x0005/*::]*/: { n:"BoolErr", f:parse_BoolErr },
/*::[*/0x0007/*::]*/: { n:"String", f:parse_BIFF2STRING },
@ -1193,6 +1195,7 @@ var XLSRecordEnum = {
/*::[*/0x001e/*::]*/: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
/*::[*/0x001f/*::]*/: { n:"BIFF2FMTCNT", f:parsenoop }, /* 16-bit cnt of BIFF2FORMAT records */
/*::[*/0x0016/*::]*/: { n:"ExternCount", f:parsenoop },
/*::[*/0x0021/*::]*/: { n:"Array", f:parse_Array },
/*::[*/0x0025/*::]*/: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
/*::[*/0x0032/*::]*/: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
/*::[*/0x003e/*::]*/: { n:"BIFF2WINDOW2", f:parsenoop },
@ -1212,7 +1215,7 @@ var XLSRecordEnum = {
/*::[*/0x00bc/*::]*/: { n:"ShrFmla", f:parsenoop }, /* Not necessarily same as 0x04bc */
/*::[*/0x00c2/*::]*/: { n:"AddMenu", f:parsenoop },
/*::[*/0x00c3/*::]*/: { n:"DelMenu", f:parsenoop },
/*::[*/0x00d6/*::]*/: { n:"RString", f:parsenoop },
/*::[*/0x00d6/*::]*/: { n:"RString", f:parse_RString },
/*::[*/0x00df/*::]*/: { n:"UDDesc", f:parsenoop },
/*::[*/0x00ea/*::]*/: { n:"TabIdConf", f:parsenoop },
/*::[*/0x0162/*::]*/: { n:"XL5Modify", f:parsenoop },
@ -1221,7 +1224,6 @@ var XLSRecordEnum = {
/*::[*/0x0218/*::]*/: { n:"Lbl", f:parse_Lbl },
/*::[*/0x0223/*::]*/: { n:"ExternName", f:parse_ExternName },
/*::[*/0x0231/*::]*/: { n:"Font", f:parsenoop },
/*::[*/0x0406/*::]*/: { n:"Formula", f:parse_Formula },
/*::[*/0x0409/*::]*/: { n:'BOF', f:parse_BOF },
/*::[*/0x086d/*::]*/: { n:"FeatInfo", f:parsenoop },
/*::[*/0x0873/*::]*/: { n:"FeatInfo11", f:parsenoop },

@ -6,10 +6,10 @@ function safe_parse_wbrels(wbrels, sheets) {
return !wbrels || wbrels.length === 0 ? null : wbrels;
}
function safe_parse_ws(zip, path/*:string*/, relsPath/*:string*/, sheet, sheetRels, sheets, opts) {
function safe_parse_ws(zip, path/*:string*/, relsPath/*:string*/, sheet, sheetRels, sheets, opts, wb) {
try {
sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
sheets[sheet]=parse_ws(getzipdata(zip, path),path,opts,sheetRels[sheet]);
sheets[sheet]=parse_ws(getzipdata(zip, path),path,opts,sheetRels[sheet], wb);
} catch(e) { if(opts.WTF) throw e; }
}
@ -110,7 +110,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
path = path.replace(/sheet0\./,"sheet.");
}
relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
safe_parse_ws(zip, path, relsPath, props.SheetNames[i], sheetRels, sheets, opts);
safe_parse_ws(zip, path, relsPath, props.SheetNames[i], sheetRels, sheets, opts, wb);
}
if(dir.comments) parse_comments(zip, dir.comments, sheets, sheetRels, opts);

@ -156,11 +156,11 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
}
var make_csv = sheet_to_csv;
function sheet_to_formulae(sheet/*:Worksheet*/) {
var cmds, y = "", x, val="";
if(sheet == null || sheet["!ref"] == null) return "";
function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
var y = "", x, val="";
if(sheet == null || sheet["!ref"] == null) return [];
var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
cmds = new Array((r.e.r-r.s.r+1)*(r.e.c-r.s.c+1));
var cmds = new Array((r.e.r-r.s.r+1)*(r.e.c-r.s.c+1));
var i = 0;
for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
for(var R = r.s.r; R <= r.e.r; ++R) {
@ -170,9 +170,18 @@ function sheet_to_formulae(sheet/*:Worksheet*/) {
x = sheet[y];
val = "";
if(x === undefined) continue;
else if(x.F != null) {
y = x.F;
if(!x.f) continue;
val = x.f;
if(y.indexOf(":") == -1) y = y + ":" + y;
}
if(x.f != null) val = x.f;
else if(x.t == 'n' && x.v != null) val = "" + x.v;
else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
else if(x.w !== undefined) val = "'" + x.w;
else if(x.v === undefined) continue;
else if(x.t == 's') val = "'" + x.v;
else val = ""+x.v;
cmds[i++] = y + "=" + val;
}

52
dist/ods.js vendored

@ -239,6 +239,17 @@ var utf8read = function utf8reada(orig) {
}
return out;
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f) {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var parse_content_xml = (function() {
var number_formats = {
@ -266,7 +277,9 @@ var parse_content_xml = (function() {
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var rept = 1;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
@ -305,7 +318,21 @@ var parse_content_xml = (function() {
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = {t:ctag['value-type'], v:null};
q = ({t:ctag['value-type'], v:null});
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
@ -331,13 +358,19 @@ var parse_content_xml = (function() {
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 's') q.v = textp || '';
if(textp) q.w = textp;
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {};
textp = "";
}
@ -364,6 +397,7 @@ var parse_content_xml = (function() {
case 'annotation': // 14.1 <office:annotation>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'number-style': // 16.27.2 <number:number-style>
@ -616,7 +650,7 @@ var zip = new jszip();
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 2 Section 2.2 Documents */
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);

2
dist/ods.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/ods.min.map vendored

File diff suppressed because one or more lines are too long

21
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

22
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

1052
dist/xlsx.js vendored

File diff suppressed because it is too large Load Diff

20
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

@ -241,6 +241,17 @@ var utf8read = function utf8reada(orig) {
}
return out;
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f/*:string*/)/*:string*/ {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var parse_content_xml = (function() {
var number_formats = {
@ -262,13 +273,15 @@ var parse_content_xml = (function() {
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag/*:: = {name:""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {};
var Rn, q/*:: = {t:"", v:null, z:null, w:""}*/;
var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var rept = 1;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
@ -307,7 +320,21 @@ var parse_content_xml = (function() {
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = {t:ctag['value-type'], v:null/*:: , z:null, w:""*/};
q = ({t:ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/);
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
@ -333,13 +360,19 @@ var parse_content_xml = (function() {
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 's') q.v = textp || '';
if(textp) q.w = textp;
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {/*:: t:"", v:null, z:null, w:""*/};
textp = "";
}
@ -366,6 +399,7 @@ var parse_content_xml = (function() {
case 'annotation': // 14.1 <office:annotation>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'number-style': // 16.27.2 <number:number-style>
@ -619,7 +653,7 @@ function write_ods(wb/*:any*/, opts/*:any*/) {
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 2 Section 2.2 Documents */
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);

52
ods.js

@ -239,6 +239,17 @@ var utf8read = function utf8reada(orig) {
}
return out;
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f) {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var parse_content_xml = (function() {
var number_formats = {
@ -266,7 +277,9 @@ var parse_content_xml = (function() {
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var rept = 1;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
@ -305,7 +318,21 @@ var parse_content_xml = (function() {
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = {t:ctag['value-type'], v:null};
q = ({t:ctag['value-type'], v:null});
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
@ -331,13 +358,19 @@ var parse_content_xml = (function() {
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 's') q.v = textp || '';
if(textp) q.w = textp;
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {};
textp = "";
}
@ -364,6 +397,7 @@ var parse_content_xml = (function() {
case 'annotation': // 14.1 <office:annotation>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'number-style': // 16.27.2 <number:number-style>
@ -616,7 +650,7 @@ var zip = new jszip();
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 2 Section 2.2 Documents */
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);

11
odsbits/50_formula.js Normal file

@ -0,0 +1,11 @@
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f/*:string*/)/*:string*/ {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}

@ -19,13 +19,15 @@ var parse_content_xml = (function() {
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag/*:: = {name:""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {};
var Rn, q/*:: = {t:"", v:null, z:null, w:""}*/;
var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var rept = 1;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
@ -64,7 +66,21 @@ var parse_content_xml = (function() {
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = {t:ctag['value-type'], v:null/*:: , z:null, w:""*/};
q = ({t:ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/);
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
@ -90,13 +106,19 @@ var parse_content_xml = (function() {
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
if(q.t === 's') q.v = textp || '';
if(textp) q.w = textp;
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {/*:: t:"", v:null, z:null, w:""*/};
textp = "";
}
@ -123,6 +145,7 @@ var parse_content_xml = (function() {
case 'annotation': // 14.1 <office:annotation>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'number-style': // 16.27.2 <number:number-style>

@ -10,7 +10,7 @@ function write_ods(wb/*:any*/, opts/*:any*/) {
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 2 Section 2.2 Documents */
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);

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

File diff suppressed because it is too large Load Diff

1052
xlsx.js

File diff suppressed because it is too large Load Diff