forked from sheetjs/sheetjs
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:
parent
ab2ecebac9
commit
d7ecca0e8b
18
.gitignore
vendored
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
|
||||
|
19
.npmignore
19
.npmignore
@ -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"
|
||||
|
44
README.md
44
README.md
@ -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);
|
||||
}
|
||||
|
465
bits/62_fxls.js
465
bits/62_fxls.js
@ -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':
|
||||