version bump 0.12.1: BIFF5 features

- BIFF5 write number formats and other features
- XLSX/XLSB/BIFF8 Suppress "Number stored as Text" errors
- codename awareness (fixes #992 h/t @samusstrike)
- updated CFB to 1.0.3
- demo refresh
This commit is contained in:
SheetJS 2018-02-14 15:06:35 -05:00
parent f002afae4b
commit 19620da30b
62 changed files with 2609 additions and 1836 deletions

@ -62,6 +62,7 @@ APIs
ArrayBuffer
Base64
Booleans
FileReader
JS
NoSQL
README

@ -430,6 +430,8 @@ function handleFile(e) {
input_dom_element.addEventListener('change', handleFile, false);
```
The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
</details>
More specialized cases, including mobile app file processing, are covered in the
@ -849,11 +851,13 @@ for(var R = range.s.r; R <= range.e.r; ++R) {
### Cell Object
Cell objects are plain JS objects with keys and values following the convention:
| 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 |
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
| `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) |
@ -873,11 +877,18 @@ 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.
The raw value is stored in the `v` value property, interpreted based on the `t`
type property. This separation allows for representation of numbers as well as
numeric text. There are 6 valid cell types:
Type `b` is the Boolean type. `v` is interpreted according to JS truth tables.
Type `e` is the Error type. `v` holds the number and `w` holds the common name:
| Type | Description |
| :--: | :-------------------------------------------------------------------- |
| `b` | Boolean: value interpreted as JS `boolean` |
| `e` | Error: value is a numeric code and `w` property stores common name ** |
| `n` | Number: value is a JS `number` ** |
| `d` | Date: value is a JS `Date` object or string to be parsed as Date ** |
| `s` | Text: value interpreted as JS `string` and written as text ** |
| `z` | Stub: blank stub cell that is ignored by data processing utilities ** |
<details>
<summary><b>Error values and interpretation</b> (click to show)</summary>
@ -906,14 +917,17 @@ Since JSON does not have a natural Date type, parsers are generally expected to
store ISO 8601 Date strings like you would get from `date.toISOString()`. On
the other hand, writers and exporters should be able to handle date strings and
JS Date objects. Note that Excel disregards timezone modifiers and treats all
dates in the local timezone. js-xlsx does not correct for this error.
dates in the local timezone. The library does not correct for this error.
Type `s` is the String type. `v` should be explicitly stored as a string to
avoid possible confusion.
Type `s` is the String type. Values are explicitly stored as text. Excel will
interpret these cells as "number stored as text". Generated Excel files
automatically suppress that class of error, but other formats may elicit errors.
Type `z` represents blank stub cells. They are generated in cases where cells
have no assigned value but hold comments or other metadata. They are ignored by
the core library data processing utility functions. By default these cells are
not generated; the parser `sheetStubs` option must be set to `true`.
Type `z` represents blank stub cells. These do not have any data or type, and
are not processed by any of the core library functions. By default these cells
will not be generated; the parser `sheetStubs` option must be set to `true`.
#### Dates

@ -1 +1 @@
XLSX.version = '0.12.0';
XLSX.version = '0.12.1';

@ -18,6 +18,46 @@ var XLMLFormatMap/*{[string]:string}*/ = ({
"On/Off": '"Yes";"Yes";"No";@'
}/*:any*/);
var SSFImplicit/*{[number]:string}*/ = ({
"5": '"$"#,##0_);\\("$"#,##0\\)',
"6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
"7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
"8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
"23": 'General', "24": 'General', "25": 'General', "26": 'General',
"27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
"32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
"36": 'm/d/yy',
"41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
"42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
"43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
"44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
"50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
"55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
"59": '0',
"60": '0.00',
"61": '#,##0',
"62": '#,##0.00',
"63": '"$"#,##0_);\\("$"#,##0\\)',
"64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
"65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
"66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
"67": '0%',
"68": '0.00%',
"69": '# ?/?',
"70": '# ??/??',
"71": 'm/d/yy',
"72": 'm/d/yy',
"73": 'd-mmm-yy',
"74": 'd-mmm',
"75": 'mmm-yy',
"76": 'h:mm',
"77": 'h:mm:ss',
"78": 'm/d/yy h:mm',
"79": 'mm:ss',
"80": '[h]:mm:ss',
"81": 'mmss.0'
}/*:any*/);
/* dateNF parse TODO: move to SSF */
var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
function dateNF_regex(dateNF/*:string|number*/)/*:RegExp*/ {

@ -38,7 +38,7 @@ type CFBFiles = {[n:string]:CFBEntry};
/* [MS-CFB] v20130118 */
var CFB = (function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '1.0.2';
exports.version = '1.0.3';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
@ -353,14 +353,14 @@ function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sector
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
sector_list[o.start].name = o.name;
o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/);
prep_blob(o.content, 0);
} else {
o.storage = 'minifat';
if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
if(o.size < 0) o.size = 0;
else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
prep_blob(o.content, 0);
}
}
if(o.content) prep_blob(o.content, 0);
files[name] = o;
FileIndex.push(o);
}

@ -2,7 +2,7 @@ function keys(o/*:any*/)/*:Array<any>*/ { return Object.keys(o); }
function evert_key(obj/*:any*/, key/*:string*/)/*:EvertType*/ {
var o = ([]/*:any*/), K = keys(obj);
for(var i = 0; i !== K.length; ++i) o[obj[K[i]][key]] = K[i];
for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
return o;
}

@ -188,7 +188,7 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/
} return this;
} else if(f === 'utf16le') {
/*:: if(typeof val !== "string") throw new Error("unreachable"); */
var end/*:number*/ = this.l + t;
var end/*:number*/ = Math.min(this.l + t, this.length);
for(i = 0; i < Math.min(val.length, t); ++i) {
var cc = val.charCodeAt(i);
this[this.l++] = (cc & 0xff);

@ -27,7 +27,7 @@ function write_StrRun(run, o) {
return o;
}
/* [MS-XLSB] 2.1.7.121 */
/* [MS-XLSB] 2.5.121 */
function parse_RichStr(data, length/*:number*/)/*:XLString*/ {
var start = data.l;
var flags = data.read_shift(1);
@ -54,7 +54,7 @@ function write_RichStr(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
write_XLWideString(str.t, o);
return _null ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.325 BrtCommentText (RichStr w/1 run) */
/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
var parse_BrtCommentText = parse_RichStr;
function write_BrtCommentText(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
/* TODO: formatted string */
@ -108,8 +108,7 @@ var parse_RelID = parse_XLNullableWideString;
var write_RelID = write_XLNullableWideString;
/* [MS-XLSB] 2.5.122 */
/* [MS-XLS] 2.5.217 */
/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
function parse_RkNumber(data)/*:number*/ {
var b = data.slice(data.l, data.l+4);
var fX100 = (b[0] & 1), fInt = (b[0] & 2);
@ -137,7 +136,6 @@ function parse_RfX(data /*::, length*/)/*:Range*/ {
cell.e.c = data.read_shift(4);
return cell;
}
function write_RfX(r/*:Range*/, o) {
if(!o) o = new_buf(16);
o.write_shift(4, r.s.r);
@ -151,13 +149,12 @@ function write_RfX(r/*:Range*/, o) {
var parse_UncheckedRfX = parse_RfX;
var write_UncheckedRfX = write_RfX;
/* [MS-XLSB] 2.5.171 */
/* [MS-XLS] 2.5.342 */
/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
function parse_Xnum(data/*::, length*/) { return data.read_shift(8, 'f'); }
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
/* [MS-XLSB] 2.5.198.2 */
/* [MS-XLSB] 2.5.97.2 */
var BErr = {
/*::[*/0x00/*::]*/: "#NULL!",
/*::[*/0x07/*::]*/: "#DIV/0!",
@ -171,7 +168,7 @@ var BErr = {
};
var RBErr = evert_num(BErr);
/* [MS-XLSB] 2.4.321 BrtColor */
/* [MS-XLSB] 2.4.324 BrtColor */
function parse_BrtColor(data/*::, length*/) {
var out = {};
var d = data.read_shift(1);

@ -184,7 +184,7 @@ var XLSFillPattern = [
function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
/* [MS-XLS] 2.5.161 */
/* [MS-XLSB] 2.5.75 */
/* [MS-XLSB] 2.5.75 Icv */
var XLSIcv = rgbify([
/* Color Constants */
0x000000,

@ -1,8 +1,7 @@
/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
/* 12.3 Part Summary <SpreadsheetML> */
/* 14.2 Part Summary <DrawingML> */
/* [MS-XLSX] 2.1 Part Enumerations */
/* [MS-XLSB] 2.1.7 Part Enumeration */
/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
var ct2type/*{[string]:string}*/ = ({
/* Workbook */
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",

@ -213,7 +213,7 @@ function parse_PropertySet(blob, PIDSI) {
}
/* [MS-OLEPS] 2.21 PropertySetStream */
function parse_PropertySetStream(file, PIDSI) {
function parse_PropertySetStream(file, PIDSI, clsid) {
var blob = file.content;
if(!blob) return ({}/*:any*/);
prep_blob(blob, 0);
@ -223,7 +223,8 @@ function parse_PropertySetStream(file, PIDSI) {
/*var vers = */blob.read_shift(2); // TODO: check version
var SystemIdentifier = blob.read_shift(4);
blob.chk(CFB.utils.consts.HEADER_CLSID, 'CLSID: ');
var CLSID = blob.read_shift(16);
if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
NumSets = blob.read_shift(4);
if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
@ -274,7 +275,7 @@ function parse_Bes(blob/*::, length*/) {
function write_Bes(v, t/*:string*/, o) {
if(!o) o = new_buf(2);
o.write_shift(1, +v);
o.write_shift(1, t == 'e' ? 1 : 0);
o.write_shift(1, ((t == 'e') ? 1 : 0));
return o;
}

@ -1,6 +1,4 @@
/* --- MS-XLS --- */
/* 2.5.19 */
/* [MS-XLS] 2.5.19 */
function parse_XLSCell(blob/*::, length*/)/*:Cell*/ {
var rw = blob.read_shift(2); // 0-indexed
var col = blob.read_shift(2);
@ -15,7 +13,7 @@ function write_XLSCell(R/*:number*/, C/*:number*/, ixfe/*:?number*/, o) {
return o;
}
/* 2.5.134 */
/* [MS-XLS] 2.5.134 */
function parse_frtHeader(blob) {
var rt = blob.read_shift(2);
var flags = blob.read_shift(2); // TODO: parse these flags
@ -27,21 +25,21 @@ function parse_frtHeader(blob) {
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
/* 2.5.344 */
/* [MS-XLS] 2.5.344 */
function parse_XTI(blob, length, opts) {
var w = opts.biff > 8 ? 4 : 2;
var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
return [iSupBook, itabFirst, itabLast];
}
/* 2.5.218 */
/* [MS-XLS] 2.5.218 */
function parse_RkRec(blob) {
var ixfe = blob.read_shift(2);
var RK = parse_RkNumber(blob);
return [ixfe, RK];
}
/* 2.5.1 */
/* [MS-XLS] 2.5.1 */
function parse_AddinUdf(blob, length, opts) {
blob.l += 4; length -= 4;
var l = blob.l + length;
@ -53,7 +51,7 @@ function parse_AddinUdf(blob, length, opts) {
return udfName;
}
/* 2.5.209 TODO: Check sizes */
/* [MS-XLS] 2.5.209 TODO: Check sizes */
function parse_Ref8U(blob/*::, length*/) {
var rwFirst = blob.read_shift(2);
var rwLast = blob.read_shift(2);
@ -70,7 +68,7 @@ function write_Ref8U(r/*:Range*/, o) {
return o;
}
/* 2.5.211 */
/* [MS-XLS] 2.5.211 */
function parse_RefU(blob/*::, length*/) {
var rwFirst = blob.read_shift(2);
var rwLast = blob.read_shift(2);
@ -79,10 +77,10 @@ function parse_RefU(blob/*::, length*/) {
return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
}
/* 2.5.207 */
/* [MS-XLS] 2.5.207 */
var parse_Ref = parse_RefU;
/* 2.5.143 */
/* [MS-XLS] 2.5.143 */
function parse_FtCmo(blob/*::, length*/) {
blob.l += 4;
var ot = blob.read_shift(2);
@ -92,7 +90,7 @@ function parse_FtCmo(blob/*::, length*/) {
return [id, ot, flags];
}
/* 2.5.149 */
/* [MS-XLS] 2.5.149 */
function parse_FtNts(blob) {
var out = {};
blob.l += 4;
@ -102,7 +100,7 @@ function parse_FtNts(blob) {
return out;
}
/* 2.5.142 */
/* [MS-XLS] 2.5.142 */
function parse_FtCf(blob) {
var out = {};
blob.l += 4;
@ -110,7 +108,7 @@ function parse_FtCf(blob) {
return out;
}
/* 2.5.140 - 2.5.154 and friends */
/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
var FtTab = {
/*::[*/0x00/*::]*/: parse_FtSkip, /* FtEnd */
@ -149,7 +147,7 @@ function parse_FtArray(blob, length/*::, ot*/) {
/* --- 2.4 Records --- */
/* 2.4.21 */
/* [MS-XLS] 2.4.21 */
function parse_BOF(blob, length) {
var o = {BIFFVer:0, dt:0};
o.BIFFVer = blob.read_shift(2); length -= 2;
@ -191,7 +189,7 @@ function write_BOF(wb/*:Workbook*/, t/*:number*/, o) {
}
/* 2.4.146 */
/* [MS-XLS] 2.4.146 */
function parse_InterfaceHdr(blob, length) {
if(length === 0) return 0x04b0;
if((blob.read_shift(2))!==0x04b0){/* empty */}
@ -199,7 +197,7 @@ function parse_InterfaceHdr(blob, length) {
}
/* 2.4.349 */
/* [MS-XLS] 2.4.349 */
function parse_WriteAccess(blob, length, opts) {
if(opts.enc) { blob.l += length; return ""; }
var l = blob.l;
@ -212,20 +210,20 @@ function write_WriteAccess(s/*:string*/, opts) {
var b8 = !opts || opts.biff == 8;
var o = new_buf(b8 ? 112 : 54);
o.write_shift(opts.biff == 8 ? 2 : 1, 7);
o.write_shift(1, 0);
if(b8) o.write_shift(1, 0);
o.write_shift(4, 0x33336853);
o.write_shift(4, 0x00534A74);
while(o.l < o.length) o.write_shift(1, 0);
o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
return o;
}
/* 2.4.351 */
/* [MS-XLS] 2.4.351 */
function parse_WsBool(blob, length, opts) {
var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
return { fDialog: flags & 0x10 };
}
/* 2.4.28 */
/* [MS-XLS] 2.4.28 */
function parse_BoundSheet8(blob, length, opts) {
var pos = blob.read_shift(4);
var hidden = blob.read_shift(1) & 0x03;
@ -253,7 +251,7 @@ function write_BoundSheet8(data, opts) {
out.l = o.l; return out;
}
/* 2.4.265 TODO */
/* [MS-XLS] 2.4.265 TODO */
function parse_SST(blob, length)/*:SST*/ {
var end = blob.l + length;
var cnt = blob.read_shift(4);
@ -266,7 +264,7 @@ function parse_SST(blob, length)/*:SST*/ {
return strs;
}
/* 2.4.107 */
/* [MS-XLS] 2.4.107 */
function parse_ExtSST(blob, length) {
var extsst = {};
extsst.dsst = blob.read_shift(2);
@ -275,7 +273,7 @@ function parse_ExtSST(blob, length) {
}
/* 2.4.221 TODO: check BIFF2-4 */
/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
function parse_Row(blob) {
var z = ({}/*:any*/);
z.r = blob.read_shift(2);
@ -293,7 +291,7 @@ function parse_Row(blob) {
}
/* 2.4.125 */
/* [MS-XLS] 2.4.125 */
function parse_ForceFullCalculation(blob) {
var header = parse_frtHeader(blob);
if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
@ -305,13 +303,13 @@ function parse_ForceFullCalculation(blob) {
/* 2.4.215 rt */
/* [MS-XLS] 2.4.215 rt */
function parse_RecalcId(blob) {
blob.read_shift(2);
return blob.read_shift(4);
}
/* 2.4.87 */
/* [MS-XLS] 2.4.87 */
function parse_DefaultRowHeight(blob, length, opts) {
var f = 0;
if(!(opts && opts.biff == 2)) {
@ -325,7 +323,7 @@ function parse_DefaultRowHeight(blob, length, opts) {
return [fl, miyRw];
}
/* 2.4.345 TODO */
/* [MS-XLS] 2.4.345 TODO */
function parse_Window1(blob) {
var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
@ -346,7 +344,7 @@ function write_Window1(/*::opts*/) {
o.write_shift(2, 0x01f4);
return o;
}
/* 2.4.346 TODO */
/* [MS-XLS] 2.4.346 TODO */
function parse_Window2(blob, length, opts) {
if(opts && opts.biff >= 2 && opts.biff < 8) return {};
var f = blob.read_shift(2);
@ -363,13 +361,13 @@ function write_Window2(view) {
return o;
}
/* 2.4.122 TODO */
/* [MS-XLS] 2.4.122 TODO */
function parse_Font(blob, length, opts) {
var o/*:any*/ = {
dyHeight: blob.read_shift(2),
fl: blob.read_shift(2)
};
switch(opts && opts.biff || 8) {
switch((opts && opts.biff) || 8) {
case 2: break;
case 3: case 4: blob.l += 2; break;
default: blob.l += 10; break;
@ -377,15 +375,29 @@ function parse_Font(blob, length, opts) {
o.name = parse_ShortXLUnicodeString(blob, 0, opts);
return o;
}
function write_Font(data, opts) {
var name = data.name || "Arial";
var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
var o = new_buf(w);
o.write_shift(2, (data.sz || 12) * 20);
o.write_shift(4, 0);
o.write_shift(2, 400);
o.write_shift(4, 0);
o.write_shift(2, 0);
o.write_shift(1, name.length);
if(!b5) o.write_shift(1, 1);
o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
return o;
}
/* 2.4.149 */
/* [MS-XLS] 2.4.149 */
function parse_LabelSst(blob) {
var cell = parse_XLSCell(blob);
cell.isst = blob.read_shift(4);
return cell;
}
/* 2.4.148 */
/* [MS-XLS] 2.4.148 */
function parse_Label(blob, length, opts) {
var target = blob.l + length;
var cell = parse_XLSCell(blob, 6);
@ -405,23 +417,26 @@ function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, os/*:number*/, op
}
/* 2.4.126 Number Formats */
/* [MS-XLS] 2.4.126 Number Formats */
function parse_Format(blob, length, opts) {
var numFmtId = blob.read_shift(2);
var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
return [numFmtId, fmtstr];
}
function write_Format(i/*:number*/, f/*:string*/, o) {
if(!o) o = new_buf(6 + 4 * f.length);
function write_Format(i/*:number*/, f/*:string*/, opts, o) {
var b5 = (opts && (opts.biff == 5));
if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
o.write_shift(2, i);
write_XLUnicodeString(f, null, o);
o.write_shift((b5 ? 1 : 2), f.length);
if(!b5) o.write_shift(1, 1);
o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
var out = (o.length > o.l) ? o.slice(0, o.l) : o;
if(o.l == null) o.l = o.length;
if(out.l == null) out.l = out.length;
return out;
}
var parse_BIFF2Format = parse_XLUnicodeString2;
/* 2.4.90 */
/* [MS-XLS] 2.4.90 */
function parse_Dimensions(blob, length, opts) {
var end = blob.l + length;
var w = opts.biff == 8 || !opts.biff ? 4 : 2;
@ -441,14 +456,14 @@ function write_Dimensions(range, opts) {
return o;
}
/* 2.4.220 */
/* [MS-XLS] 2.4.220 */
function parse_RK(blob) {
var rw = blob.read_shift(2), col = blob.read_shift(2);
var rkrec = parse_RkRec(blob);
return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
}
/* 2.4.175 */
/* [MS-XLS] 2.4.175 */
function parse_MulRk(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
@ -459,7 +474,7 @@ function parse_MulRk(blob, length) {
if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
}
/* 2.4.174 */
/* [MS-XLS] 2.4.174 */
function parse_MulBlank(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
@ -471,7 +486,7 @@ function parse_MulBlank(blob, length) {
return {r:rw, c:col, C:lastcol, ixfe:ixfes};
}
/* 2.5.20 2.5.249 TODO: interpret values here */
/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
function parse_CellStyleXF(blob, length, style, opts) {
var o = {};
var a = blob.read_shift(4), b = blob.read_shift(4);
@ -515,7 +530,7 @@ function parse_CellStyleXF(blob, length, style, opts) {
//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
/* 2.4.353 TODO: actually do this right */
/* [MS-XLS] 2.4.353 TODO: actually do this right */
function parse_XF(blob, length, opts) {
var o = {};
o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
@ -524,19 +539,25 @@ function parse_XF(blob, length, opts) {
o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
return o;
}
function write_XF(data, ixfeP, o) {
if(!o) o = new_buf(20);
o.write_shift(2, 0);
o.write_shift(2, data.numFmtId||0);
function write_XF(data, ixfeP, opts, o) {
var b5 = (opts && (opts.biff == 5));
if(!o) o = new_buf(b5 ? 16 : 20);
o.write_shift(2, 0);
if(data.style) {
o.write_shift(2, (data.numFmtId||0));
o.write_shift(2, 0xFFF4);
} else {
o.write_shift(2, (data.numFmtId||0));
o.write_shift(2, (ixfeP<<4));
}
o.write_shift(4, 0);
o.write_shift(4, 0);
o.write_shift(4, 0);
if(!b5) o.write_shift(4, 0);
o.write_shift(2, 0);
return o;
}
/* 2.4.134 */
/* [MS-XLS] 2.4.134 */
function parse_Guts(blob) {
blob.l += 4;
var out = [blob.read_shift(2), blob.read_shift(2)];
@ -553,7 +574,7 @@ function write_Guts(guts/*:Array<number>*/) {
return o;
}
/* 2.4.24 */
/* [MS-XLS] 2.4.24 */
function parse_BoolErr(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) ++blob.l;
@ -569,7 +590,7 @@ function write_BoolErr(R/*:number*/, C/*:number*/, v, os/*:number*/, opts, t/*:s
return o;
}
/* 2.4.180 Number */
/* [MS-XLS] 2.4.180 Number */
function parse_Number(blob) {
var cell = parse_XLSCell(blob, 6);
var xnum = parse_Xnum(blob, 8);
@ -585,7 +606,7 @@ function write_Number(R/*:number*/, C/*:number*/, v, os/*:: :number, opts*/) {
var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
/* 2.4.271 */
/* [MS-XLS] 2.4.271 */
function parse_SupBook(blob, length, opts) {
var end = blob.l + length;
var ctab = blob.read_shift(2);
@ -600,7 +621,7 @@ function parse_SupBook(blob, length, opts) {
return [cch, ctab, virtPath, rgst];
}
/* 2.4.105 TODO */
/* [MS-XLS] 2.4.105 TODO */
function parse_ExternName(blob, length, opts) {
var flags = blob.read_shift(2);
var body;
@ -620,7 +641,7 @@ function parse_ExternName(blob, length, opts) {
return o;
}
/* 2.4.150 TODO */
/* [MS-XLS] 2.4.150 TODO */
var XLSLblBuiltIn = [
"_xlnm.Consolidate_Area",
"_xlnm.Auto_Open",
@ -662,7 +683,7 @@ function parse_Lbl(blob, length, opts) {
};
}
/* 2.4.106 TODO: verify filename encoding */
/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
function parse_ExternSheet(blob, length, opts) {
if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
@ -677,7 +698,7 @@ function parse_BIFF5ExternSheet(blob, length, opts) {
return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
}
/* 2.4.176 TODO: check older biff */
/* [MS-XLS] 2.4.176 TODO: check older biff */
function parse_NameCmt(blob, length, opts) {
if(opts.biff < 8) { blob.l += length; return; }
var cchName = blob.read_shift(2);
@ -687,7 +708,7 @@ function parse_NameCmt(blob, length, opts) {
return [name, comment];
}
/* 2.4.260 */
/* [MS-XLS] 2.4.260 */
function parse_ShrFmla(blob, length, opts) {
var ref = parse_RefU(blob, 6);
blob.l++;
@ -696,7 +717,7 @@ function parse_ShrFmla(blob, length, opts) {
return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
}
/* 2.4.4 TODO */
/* [MS-XLS] 2.4.4 TODO */
function parse_Array(blob, length, opts) {
var ref = parse_Ref(blob, 6);
/* TODO: fAlwaysCalc */
@ -708,7 +729,7 @@ function parse_Array(blob, length, opts) {
return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
}
/* 2.4.173 */
/* [MS-XLS] 2.4.173 */
function parse_MTRSettings(blob) {
var fMTREnabled = blob.read_shift(4) !== 0x00;
var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
@ -716,7 +737,7 @@ function parse_MTRSettings(blob) {
return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
}
/* 2.5.186 TODO: BIFF5 */
/* [MS-XLS] 2.5.186 TODO: BIFF5 */
function parse_NoteSh(blob, length, opts) {
if(opts.biff < 8) return;
var row = blob.read_shift(2), col = blob.read_shift(2);
@ -726,13 +747,13 @@ function parse_NoteSh(blob, length, opts) {
return [{r:row,c:col}, stAuthor, idObj, flags];
}
/* 2.4.179 */
/* [MS-XLS] 2.4.179 */
function parse_Note(blob, length, opts) {
/* TODO: Support revisions */
return parse_NoteSh(blob, length, opts);
}
/* 2.4.168 */
/* [MS-XLS] 2.4.168 */
function parse_MergeCells(blob, length)/*:Array<Range>*/ {
var merges/*:Array<Range>*/ = [];
var cmcs = blob.read_shift(2);
@ -746,7 +767,7 @@ function write_MergeCells(merges/*:Array<Range>*/) {
return o;
}
/* 2.4.181 TODO: parse all the things! */
/* [MS-XLS] 2.4.181 TODO: parse all the things! */
function parse_Obj(blob, length, opts) {
if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
var cmo = parse_FtCmo(blob, 22); // id, ot, flags
@ -791,7 +812,7 @@ function parse_BIFF5Obj(blob, length, opts) {
return { cmo: [id, ot, grbit], ft:fts };
}
/* 2.4.329 TODO: parse properly */
/* [MS-XLS] 2.4.329 TODO: parse properly */
function parse_TxO(blob, length, opts) {
var s = blob.l;
var texts = "";
@ -820,7 +841,7 @@ try {
}
blob.l = s + length;
/* 2.5.272 TxORuns */
/* [MS-XLS] 2.5.272 TxORuns */
// var rgTxoRuns = [];
// for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
// var cchText2 = blob.read_shift(2);
@ -831,7 +852,7 @@ try {
} catch(e) { blob.l = s + length; return { t: texts }; }
}
/* 2.4.140 */
/* [MS-XLS] 2.4.140 */
function parse_HLink(blob, length) {
var ref = parse_Ref8U(blob, 8);
blob.l += 16; /* CLSID */
@ -849,7 +870,7 @@ function write_HLink(hl) {
}
/* 2.4.141 */
/* [MS-XLS] 2.4.141 */
function parse_HLinkTooltip(blob, length) {
blob.read_shift(2);
var ref = parse_Ref8U(blob, 8);
@ -869,7 +890,7 @@ function write_HLinkTooltip(hl) {
return O;
}
/* 2.4.63 */
/* [MS-XLS] 2.4.63 */
function parse_Country(blob)/*:[string|number, string|number]*/ {
var o = [0,0], d;
d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
@ -883,7 +904,7 @@ function write_Country(o) {
return o;
}
/* 2.4.50 ClrtClient */
/* [MS-XLS] 2.4.50 ClrtClient */
function parse_ClrtClient(blob) {
var ccv = blob.read_shift(2);
var o = [];
@ -891,7 +912,7 @@ function parse_ClrtClient(blob) {
return o;
}
/* 2.4.188 */
/* [MS-XLS] 2.4.188 */
function parse_Palette(blob) {
var ccv = blob.read_shift(2);
var o = [];
@ -899,7 +920,7 @@ function parse_Palette(blob) {
return o;
}
/* 2.4.354 */
/* [MS-XLS] 2.4.354 */
function parse_XFCRC(blob) {
blob.l += 2;
var o = {cxfs:0, crc:0};
@ -908,7 +929,7 @@ function parse_XFCRC(blob) {
return o;
}
/* 2.4.53 TODO: parse flags */
/* [MS-XLS] 2.4.53 TODO: parse flags */
/* [MS-XLSB] 2.4.323 TODO: parse flags */
function parse_ColInfo(blob, length, opts) {
if(!opts.cellStyles) return parsenoop(blob, length);
@ -922,9 +943,10 @@ function parse_ColInfo(blob, length, opts) {
return {s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags};
}
/* 2.4.257 */
function parse_Setup(blob/*, length*/) {
/* [MS-XLS] 2.4.257 */
function parse_Setup(blob, length) {
var o = {};
if(length < 32) return o;
blob.l += 16;
o.header = parse_Xnum(blob, 8);
o.footer = parse_Xnum(blob, 8);
@ -932,7 +954,7 @@ function parse_Setup(blob/*, length*/) {
return o;
}
/* 2.4.261 */
/* [MS-XLS] 2.4.261 */
function parse_ShtProps(blob, length, opts) {
var def = {area:false};
if(opts.biff != 5) { blob.l += length; return def; }
@ -941,16 +963,16 @@ function parse_ShtProps(blob, length, opts) {
return def;
}
/* 2.4.241 */
/* [MS-XLS] 2.4.241 */
function write_RRTabId(n/*:number*/) {
var out = new_buf(2 * n);
for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
return out;
}
var parse_Blank = parse_XLSCell; /* 2.4.20 Just the cell */
var parse_Scl = parseuint16a; /* 2.4.247 num, den */
var parse_String = parse_XLUnicodeString; /* 2.4.268 */
var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
/* --- Specific to versions before BIFF8 --- */
function parse_ImData(blob) {

@ -1,4 +1,4 @@
/* [MS-XLSB] 2.4.219 BrtBeginSst */
/* [MS-XLSB] 2.4.221 BrtBeginSst */
function parse_BrtBeginSst(data) {
return [data.read_shift(4), data.read_shift(4)];
}

@ -1,4 +1,4 @@
/* [MS-XLSB] 2.4.651 BrtFmt */
/* [MS-XLSB] 2.4.657 BrtFmt */
function parse_BrtFmt(data, length/*:number*/) {
var numFmtId = data.read_shift(2);
var stFmtCode = parse_XLWideString(data,length-2);
@ -13,7 +13,7 @@ function write_BrtFmt(i/*:number*/, f/*:string*/, o) {
return out;
}
/* [MS-XLSB] 2.4.653 BrtFont TODO */
/* [MS-XLSB] 2.4.659 BrtFont TODO */
function parse_BrtFont(data, length/*:number*/, opts) {
var out = ({}/*:any*/);
@ -80,7 +80,7 @@ function write_BrtFont(font, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.644 BrtFill */
/* [MS-XLSB] 2.4.650 BrtFill */
var XLSBFillPTNames = [
"none",
"solid",
@ -134,7 +134,7 @@ function write_BrtFill(fill, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.816 BrtXF */
/* [MS-XLSB] 2.4.824 BrtXF */
function parse_BrtXF(data, length/*:number*/) {
var tgt = data.l + length;
var ixfeParent = data.read_shift(2);
@ -167,7 +167,7 @@ function write_Blxf(data, o) {
o.write_shift(4, 0); /* color */
return o;
}
/* [MS-XLSB] 2.4.299 BrtBorder TODO */
/* [MS-XLSB] 2.4.302 BrtBorder TODO */
var parse_BrtBorder = parsenoop;
function write_BrtBorder(border, o) {
if(!o) o = new_buf(51);
@ -180,7 +180,7 @@ function write_BrtBorder(border, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.755 BrtStyle TODO */
/* [MS-XLSB] 2.4.763 BrtStyle TODO */
function write_BrtStyle(style, o) {
if(!o) o = new_buf(12+4*10);
o.write_shift(4, style.xfId);
@ -191,7 +191,7 @@ function write_BrtStyle(style, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.269 BrtBeginTableStyles */
/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
var o = new_buf(4+256*2*4);
o.write_shift(4, cnt);

@ -41,17 +41,17 @@ function parse_XFExtGradient(blob, length) {
return parsenoop(blob, length);
}
/* 2.5.108 */
/* [MS-XLS] 2.5.108 */
function parse_ExtProp(blob/*::, length*/)/*:Array<any>*/ {
var extType = blob.read_shift(2);
var cb = blob.read_shift(2);
var cb = blob.read_shift(2) - 4;
var o = [extType];
switch(extType) {
case 0x04: case 0x05: case 0x07: case 0x08:
case 0x09: case 0x0A: case 0x0B: case 0x0D:
o[1] = parse_FullColorExt(blob, cb); break;
case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 5 ? 1 : 2); break;
case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
}
return o;

@ -19,7 +19,7 @@ function write_BrtBeginComment(data, o) {
return o;
}
/* [MS-XLSB] 2.4.324 BrtCommentAuthor */
/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
var parse_BrtCommentAuthor = parse_XLWideString;
function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }

@ -1,17 +1,12 @@
/* --- formula references point to MS-XLS --- */
/* Small helpers */
function parseread1(blob) { blob.l+=1; return; }
/* Rgce Helpers */
/* 2.5.51 */
/* [MS-XLS] 2.5.51 */
function parse_ColRelU(blob, length) {
var c = blob.read_shift(length == 1 ? 1 : 2);
return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
}
/* [MS-XLS] 2.5.198.105 */
/* [MS-XLSB] 2.5.97.89 */
/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.89 */
function parse_RgceArea(blob, length, opts) {
var w = 2;
if(opts) {
@ -31,7 +26,7 @@ function parse_RgceArea_BIFF2(blob/*::, length, opts*/) {
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 */
/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.90 */
function parse_RgceAreaRel(blob, length/*::, opts*/) {
var r=blob.read_shift(length == 12 ? 4 : 2), R=blob.read_shift(length == 12 ? 4 : 2);
var c=parse_ColRelU(blob, 2);
@ -39,7 +34,7 @@ function parse_RgceAreaRel(blob, length/*::, opts*/) {
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]} };
}
/* 2.5.198.109 */
/* [MS-XLS] 2.5.198.109 ; [MS-XLSB] 2.5.97.91 */
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);
@ -52,15 +47,14 @@ function parse_RgceLoc_BIFF2(blob/*::, length, opts*/) {
return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
}
/* 2.5.198.107 , 2.5.47 */
/* [MS-XLS] 2.5.198.107, 2.5.47 */
function parse_RgceElfLoc(blob/*::, length, opts*/) {
var r = blob.read_shift(2);
var c = blob.read_shift(2);
return {r:r, c:c & 0xFF, fQuoted:!!(c & 0x4000), cRel:c>>15, rRel:c>>15 };
}
/* [MS-XLS] 2.5.198.111 TODO */
/* [MS-XLSB] 2.5.97.92 TODO */
/* [MS-XLS] 2.5.198.111 ; [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);
@ -82,17 +76,14 @@ function parse_RgceLocRel_BIFF2(blob/*::, length:number, opts*/) {
return {r:rl,c:c,cRel:cRel,rRel:rRel};
}
/* Ptg Tokens */
/* 2.5.198.27 */
/* [MS-XLS] 2.5.198.27 ; [MS-XLSB] 2.5.97.18 */
function parse_PtgArea(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
return [type, area];
}
/* [MS-XLS] 2.5.198.28 */
/* [MS-XLSB] 2.5.97.19 */
/* [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, 'i');
@ -105,13 +96,13 @@ function parse_PtgArea3d(blob, length, opts) {
return [type, ixti, area];
}
/* 2.5.198.29 */
/* [MS-XLS] 2.5.198.29 ; [MS-XLSB] 2.5.97.20 */
function parse_PtgAreaErr(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
blob.l += opts && opts.biff > 8 ? 12 : 8;
return [type];
}
/* 2.5.198.30 */
/* [MS-XLS] 2.5.198.30 ; [MS-XLSB] 2.5.97.21 */
function parse_PtgAreaErr3d(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var ixti = blob.read_shift(2);
@ -124,22 +115,21 @@ function parse_PtgAreaErr3d(blob, length, opts) {
return [type, ixti];
}
/* 2.5.198.31 */
/* [MS-XLS] 2.5.198.31 ; [MS-XLSB] 2.5.97.22 */
function parse_PtgAreaN(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var area = parse_RgceAreaRel(blob, opts && opts.biff > 8 ? 12 : 8, opts);
return [type, area];
}
/* [MS-XLS] 2.5.198.32 */
/* [MS-XLSB] 2.5.97.23 */
/* [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 += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
return [type];
}
/* 2.5.198.33 */
/* [MS-XLS] 2.5.198.33 ; [MS-XLSB] 2.5.97.24 */
function parse_PtgAttrBaxcel(blob) {
var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
var bitBaxcel = 1;
@ -147,7 +137,7 @@ function parse_PtgAttrBaxcel(blob) {
return [bitSemi, bitBaxcel];
}
/* 2.5.198.34 */
/* [MS-XLS] 2.5.198.34 ; [MS-XLSB] 2.5.97.25 */
function parse_PtgAttrChoose(blob, length, opts)/*:Array<number>*/ {
blob.l +=2;
var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
@ -157,14 +147,14 @@ function parse_PtgAttrChoose(blob, length, opts)/*:Array<number>*/ {
return o;
}
/* 2.5.198.35 */
/* [MS-XLS] 2.5.198.35 ; [MS-XLSB] 2.5.97.26 */
function parse_PtgAttrGoto(blob, length, opts) {
var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
}
/* 2.5.198.36 */
/* [MS-XLS] 2.5.198.36 ; [MS-XLSB] 2.5.97.27 */
function parse_PtgAttrIf(blob, length, opts) {
var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
@ -178,32 +168,32 @@ function parse_PtgAttrIfError(blob) {
return [bitIf, blob.read_shift(2)];
}
/* 2.5.198.37 */
/* [MS-XLS] 2.5.198.37 ; [MS-XLSB] 2.5.97.29 */
function parse_PtgAttrSemi(blob, length, opts) {
var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += opts && opts.biff == 2 ? 3 : 4;
return [bitSemi];
}
/* 2.5.198.40 (used by PtgAttrSpace and PtgAttrSpaceSemi) */
/* [MS-XLS] 2.5.198.40 ; [MS-XLSB] 2.5.97.32 */
function parse_PtgAttrSpaceType(blob/*::, length*/) {
var type = blob.read_shift(1), cch = blob.read_shift(1);
return [type, cch];
}
/* 2.5.198.38 */
/* [MS-XLS] 2.5.198.38 ; [MS-XLSB] 2.5.97.30 */
function parse_PtgAttrSpace(blob) {
blob.read_shift(2);
return parse_PtgAttrSpaceType(blob, 2);
}
/* 2.5.198.39 */
/* [MS-XLS] 2.5.198.39 ; [MS-XLSB] 2.5.97.31 */
function parse_PtgAttrSpaceSemi(blob) {
blob.read_shift(2);
return parse_PtgAttrSpaceType(blob, 2);
}
/* 2.5.198.84 TODO */
/* [MS-XLS] 2.5.198.84 ; [MS-XLSB] 2.5.97.68 TODO */
function parse_PtgRef(blob, length, opts) {
//var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
@ -212,7 +202,7 @@ function parse_PtgRef(blob, length, opts) {
return [type, loc];
}
/* 2.5.198.88 TODO */
/* [MS-XLS] 2.5.198.88 ; [MS-XLSB] 2.5.97.72 TODO */
function parse_PtgRefN(blob, length, opts) {
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
@ -220,17 +210,18 @@ function parse_PtgRefN(blob, length, opts) {
return [type, loc];
}
/* 2.5.198.85 TODO */
/* [MS-XLS] 2.5.198.85 ; [MS-XLSB] 2.5.97.69 TODO */
function parse_PtgRef3d(blob, length, opts) {
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var ixti = blob.read_shift(2); // XtiIndex
if(opts && opts.biff == 5) blob.l += 12;
var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
return [type, ixti, loc];
}
/* 2.5.198.62 TODO */
/* [MS-XLS] 2.5.198.62 ; [MS-XLSB] 2.5.97.45 TODO */
function parse_PtgFunc(blob, length, opts) {
//var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
@ -238,7 +229,7 @@ function parse_PtgFunc(blob, length, opts) {
var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
return [FtabArgc[iftab], Ftab[iftab], type];
}
/* 2.5.198.63 TODO */
/* [MS-XLS] 2.5.198.63 ; [MS-XLSB] 2.5.97.46 TODO */
function parse_PtgFuncVar(blob, length, opts) {
blob.l++;
var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [0, blob.read_shift(1)]: parsetab(blob);
@ -249,12 +240,12 @@ function parsetab(blob) {
return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
}
/* 2.5.198.41 */
/* [MS-XLS] 2.5.198.41 ; [MS-XLSB] 2.5.97.33 */
function parse_PtgAttrSum(blob, length, opts) {
blob.l += opts && opts.biff == 2 ? 3 : 4; return;
}
/* 2.5.198.58 */
/* [MS-XLS] 2.5.198.58 ; [MS-XLSB] 2.5.97.40 */
function parse_PtgExp(blob, length, opts) {
blob.l++;
if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
@ -263,19 +254,19 @@ function parse_PtgExp(blob, length, opts) {
return [row, col];
}
/* 2.5.198.57 */
/* [MS-XLS] 2.5.198.57 ; [MS-XLSB] 2.5.97.39 */
function parse_PtgErr(blob) { blob.l++; return BErr[blob.read_shift(1)]; }
/* 2.5.198.66 */
/* [MS-XLS] 2.5.198.66 ; [MS-XLSB] 2.5.97.49 */
function parse_PtgInt(blob) { blob.l++; return blob.read_shift(2); }
/* 2.5.198.42 */
/* [MS-XLS] 2.5.198.42 ; [MS-XLSB] 2.5.97.34 */
function parse_PtgBool(blob) { blob.l++; return blob.read_shift(1)!==0;}
/* 2.5.198.79 */
/* [MS-XLS] 2.5.198.79 ; [MS-XLSB] 2.5.97.63 */
function parse_PtgNum(blob) { blob.l++; return parse_Xnum(blob, 8); }
/* 2.5.198.89 */
/* [MS-XLS] 2.5.198.89 ; [MS-XLSB] 2.5.97.74 */
function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
@ -289,37 +280,32 @@ function parse_SerAr(blob, biff/*:number*/) {
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';
blob.l += 7; break;
/* 2.5.192.114 */
if(biff != 12) blob.l += 7; break;
case 0x10: /* SerErr -- error */
val[1] = BErr[blob[blob.l]];
blob.l += 8; break;
/* 2.5.192.115 */
blob.l += ((biff == 12) ? 4 : 8); break;
case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
blob.l += 8; break;
/* 2.5.192.116 */
case 0x01: /* SerNum -- Xnum */
val[1] = parse_Xnum(blob, 8); break;
/* 2.5.192.117 */
case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
// default: throw "Bad SerAr: " + val[0]; /* Unreachable */
default: throw "Bad SerAr: " + val[0]; /* Unreachable */
}
return val;
}
/* 2.5.198.61 */
function parse_PtgExtraMem(blob/*::, cce*/) {
var count = blob.read_shift(2);
/* [MS-XLS] 2.5.198.61 ; [MS-XLSB] 2.5.97.44 */
function parse_PtgExtraMem(blob, cce, opts) {
var count = blob.read_shift((opts.biff == 12) ? 4 : 2);
var out/*:Array<Range>*/ = [];
for(var i = 0; i != count; ++i) out.push(parse_Ref8U(blob, 8));
for(var i = 0; i != count; ++i) out.push(((opts.biff == 12) ? parse_UncheckedRfX : parse_Ref8U)(blob, 8));
return out;
}
/* 2.5.198.59 */
/* [MS-XLS] 2.5.198.59 ; [MS-XLSB] 2.5.97.41 */
function parse_PtgExtraArray(blob, length, opts) {
var rows = 0, cols = 0;
if(opts.biff == 12) {
@ -336,7 +322,7 @@ function parse_PtgExtraArray(blob, length, opts) {
return o;
}
/* 2.5.198.76 */
/* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 */
function parse_PtgName(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
@ -349,7 +335,7 @@ function parse_PtgName(blob, length, opts) {
return [type, 0, nameindex];
}
/* 2.5.198.77 */
/* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 */
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;
@ -366,7 +352,7 @@ function parse_PtgNameX_BIFF5(blob/*::, length, opts*/) {
return [type, ixti, nameindex];
}
/* 2.5.198.70 */
/* [MS-XLS] 2.5.198.70 ; [MS-XLSB] 2.5.97.54 */
function parse_PtgMemArea(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
blob.l += (opts && opts.biff == 2 ? 3 : 4);
@ -374,7 +360,7 @@ function parse_PtgMemArea(blob, length, opts) {
return [type, cce];
}
/* 2.5.198.72 */
/* [MS-XLS] 2.5.198.72 ; [MS-XLSB] 2.5.97.56 */
function parse_PtgMemFunc(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
@ -382,7 +368,7 @@ function parse_PtgMemFunc(blob, length, opts) {
}
/* 2.5.198.86 */
/* [MS-XLS] 2.5.198.86 ; [MS-XLSB] 2.5.97.69 */
function parse_PtgRefErr(blob, length, opts) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
blob.l += 4;
@ -390,24 +376,24 @@ function parse_PtgRefErr(blob, length, opts) {
return [type];
}
/* 2.5.198.87 */
/* [MS-XLS] 2.5.198.87 ; [MS-XLSB] 2.5.97.71 */
function parse_PtgRefErr3d(blob, length, opts) {
var type = (blob[blob.l++] & 0x60) >> 5;
var ixti = blob.read_shift(2);
var w = 4;
if(opts) switch(opts.biff) {
case 5: throw new Error("PtgRefErr3d -- 5"); // TODO: find test case
case 5: w = 15; break;
case 12: w = 6; break;
}
blob.l += w;
return [type, ixti];
}
/* 2.5.198.71 */
/* [MS-XLS] 2.5.198.71 ; [MS-XLSB] 2.5.97.55 */
var parse_PtgMemErr = parsenoop;
/* 2.5.198.73 */
/* [MS-XLS] 2.5.198.73 ; [MS-XLSB] 2.5.97.57 */
var parse_PtgMemNoMem = parsenoop;
/* 2.5.198.92 */
/* [MS-XLS] 2.5.198.92 */
var parse_PtgTbl = parsenoop;
function parse_PtgElfLoc(blob, length, opts) {
@ -418,28 +404,28 @@ function parse_PtgElfNoop(blob/*::, length, opts*/) {
blob.l += 6;
return [];
}
/* 2.5.198.46 */
/* [MS-XLS] 2.5.198.46 */
var parse_PtgElfCol = parse_PtgElfLoc;
/* 2.5.198.47 */
/* [MS-XLS] 2.5.198.47 */
var parse_PtgElfColS = parse_PtgElfNoop;
/* 2.5.198.48 */
/* [MS-XLS] 2.5.198.48 */
var parse_PtgElfColSV = parse_PtgElfNoop;
/* 2.5.198.49 */
/* [MS-XLS] 2.5.198.49 */
var parse_PtgElfColV = parse_PtgElfLoc;
/* 2.5.198.50 */
/* [MS-XLS] 2.5.198.50 */
function parse_PtgElfLel(blob/*::, length, opts*/) {
blob.l += 2;
return [parseuint16(blob), blob.read_shift(2) & 0x01];
}
/* 2.5.198.51 */
/* [MS-XLS] 2.5.198.51 */
var parse_PtgElfRadical = parse_PtgElfLoc;
/* 2.5.198.52 */
/* [MS-XLS] 2.5.198.52 */
var parse_PtgElfRadicalLel = parse_PtgElfLel;
/* 2.5.198.53 */
/* [MS-XLS] 2.5.198.53 */
var parse_PtgElfRadicalS = parse_PtgElfNoop;
/* 2.5.198.54 */
/* [MS-XLS] 2.5.198.54 */
var parse_PtgElfRw = parse_PtgElfLoc;
/* 2.5.198.55 */
/* [MS-XLS] 2.5.198.55 */
var parse_PtgElfRwV = parse_PtgElfLoc;
/* [MS-XLSB] 2.5.97.52 */
@ -449,13 +435,13 @@ function parse_PtgList(blob/*::, length, opts*/) {
blob.l += 10;
return {ixti: ixti};
}
/* 2.5.198.91 */
/* [MS-XLS] 2.5.198.91 ; [MS-XLSB] 2.5.97.76 */
function parse_PtgSxName(blob/*::, length, opts*/) {
blob.l += 2;
return [blob.read_shift(4)];
}
/* 2.5.198.25 */
/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
var PtgTypes = {
/*::[*/0x01/*::]*/: { n:'PtgExp', f:parse_PtgExp },
/*::[*/0x02/*::]*/: { n:'PtgTbl', f:parse_PtgTbl },
@ -558,7 +544,7 @@ var Ptg19 = {
};
Ptg19[0x21] = Ptg19[0x20];
/* 2.5.198.103 */
/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
function parse_RgbExtra(blob, length, rgce, opts) {
if(opts.biff < 8) return parsenoop(blob, length);
var target = blob.l + length;
@ -570,7 +556,7 @@ function parse_RgbExtra(blob, length, rgce, opts) {
o.push(rgce[i][1]);
break;
case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1]);
rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1], opts);
o.push(rgce[i][2]);
break;
case 'PtgExp': /* PtgExp -> PtgExtraCol */
@ -593,7 +579,7 @@ function parse_RgbExtra(blob, length, rgce, opts) {
return o;
}
/* 2.5.198.104 */
/* [MS-XLS] 2.5.198.104 ; [MS-XLSB] 2.5.97.88 */
function parse_Rgce(blob, length, opts) {
var target = blob.l + length;
var R, id, ptgs = [];
@ -631,8 +617,7 @@ function stringify_array(f/*:Array<Array<string>>*/)/*:string*/ {
return o.join(";");
}
/* [MS-XLS] 2.2.2 TODO */
/* [MS-XLSB] 2.2.2 */
/* [MS-XLS] 2.2.2 ; [MS-XLSB] 2.2.2 TODO */
var PtgBinOp = {
PtgAdd: "+",
PtgConcat: "&",
@ -697,25 +682,25 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
var f = formula[0][ff];
switch(f[0]) {
case 'PtgUminus': /* 2.5.198.93 */
case 'PtgUminus': /* [MS-XLS] 2.5.198.93 */
stack.push("-" + stack.pop()); break;
case 'PtgUplus': /* 2.5.198.95 */
case 'PtgUplus': /* [MS-XLS] 2.5.198.95 */
stack.push("+" + stack.pop()); break;
case 'PtgPercent': /* 2.5.198.81 */
case 'PtgPercent': /* [MS-XLS] 2.5.198.81 */
stack.push(stack.pop() + "%"); break;
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 */
case 'PtgAdd': /* [MS-XLS] 2.5.198.26 */
case 'PtgConcat': /* [MS-XLS] 2.5.198.43 */
case 'PtgDiv': /* [MS-XLS] 2.5.198.45 */
case 'PtgEq': /* [MS-XLS] 2.5.198.56 */
case 'PtgGe': /* [MS-XLS] 2.5.198.64 */
case 'PtgGt': /* [MS-XLS] 2.5.198.65 */
case 'PtgLe': /* [MS-XLS] 2.5.198.68 */
case 'PtgLt': /* [MS-XLS] 2.5.198.69 */
case 'PtgMul': /* [MS-XLS] 2.5.198.75 */
case 'PtgNe': /* [MS-XLS] 2.5.198.78 */
case 'PtgPower': /* [MS-XLS] 2.5.198.82 */
case 'PtgSub': /* [MS-XLS] 2.5.198.90 */
e1 = stack.pop(); e2 = stack.pop();
if(last_sp >= 0) {
switch(formula[0][last_sp][1][0]) {
@ -736,46 +721,46 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(e2+PtgBinOp[f[0]]+e1);
break;
case 'PtgIsect': /* 2.5.198.67 */
case 'PtgIsect': /* [MS-XLS] 2.5.198.67 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+" "+e1);
break;
case 'PtgUnion': /* 2.5.198.94 */
case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+","+e1);
break;
case 'PtgRange': /* 2.5.198.83 */
case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+":"+e1);
break;
case 'PtgAttrChoose': /* 2.5.198.34 */
case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */
break;
case 'PtgAttrGoto': /* 2.5.198.35 */
case 'PtgAttrGoto': /* [MS-XLS] 2.5.198.35 */
break;
case 'PtgAttrIf': /* 2.5.198.36 */
case 'PtgAttrIf': /* [MS-XLS] 2.5.198.36 */
break;
case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
break;
case 'PtgRef': /* 2.5.198.84 */
case 'PtgRef': /* [MS-XLS] 2.5.198.84 */
/*::type = f[1][0]; */c = shift_cell_xls((f[1][1]/*:any*/), _range, opts);
stack.push(encode_cell_xls(c));
break;
case 'PtgRefN': /* 2.5.198.88 */
case 'PtgRefN': /* [MS-XLS] 2.5.198.88 */
/*::type = f[1][0]; */c = cell ? shift_cell_xls((f[1][1]/*:any*/), cell, opts) : (f[1][1]/*:any*/);
stack.push(encode_cell_xls(c));
break;
case 'PtgRef3d': /* 2.5.198.85 */
case 'PtgRef3d': /* [MS-XLS] 2.5.198.85 */
/*::type = f[1][0]; */ixti = /*::Number(*/f[1][1]/*::)*/; c = shift_cell_xls((f[1][2]/*:any*/), _range, opts);
sname = get_ixti(supbooks, ixti, opts);
var w = sname; /* IE9 fails on defined names */ // eslint-disable-line no-unused-vars
stack.push(sname + "!" + encode_cell_xls(c));
break;
case 'PtgFunc': /* 2.5.198.62 */
case 'PtgFuncVar': /* 2.5.198.63 */
case 'PtgFunc': /* [MS-XLS] 2.5.198.62 */
case 'PtgFuncVar': /* [MS-XLS] 2.5.198.63 */
/* f[1] = [argc, func, type] */
var argc/*:number*/ = (f[1][0]/*:any*/), func/*:string*/ = (f[1][1]/*:any*/);
if(!argc) argc = 0;
@ -785,38 +770,38 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(func + "(" + args.join(",") + ")");
break;
case 'PtgBool': /* 2.5.198.42 */
case 'PtgBool': /* [MS-XLS] 2.5.198.42 */
stack.push(f[1] ? "TRUE" : "FALSE"); break;
case 'PtgInt': /* 2.5.198.66 */
case 'PtgInt': /* [MS-XLS] 2.5.198.66 */
stack.push(/*::String(*/f[1]/*::)*/); break;
case 'PtgNum': /* 2.5.198.79 TODO: precision? */
case 'PtgNum': /* [MS-XLS] 2.5.198.79 TODO: precision? */
stack.push(String(f[1])); break;
case 'PtgStr': /* 2.5.198.89 */
case 'PtgStr': /* [MS-XLS] 2.5.198.89 */
// $FlowIgnore
stack.push('"' + f[1] + '"'); break;
case 'PtgErr': /* 2.5.198.57 */
case 'PtgErr': /* [MS-XLS] 2.5.198.57 */
stack.push(/*::String(*/f[1]/*::)*/); break;
case 'PtgAreaN': /* 2.5.198.31 TODO */
case 'PtgAreaN': /* [MS-XLS] 2.5.198.31 TODO */
/*::type = f[1][0]; */r = shift_range_xls(f[1][1], cell ? {s:cell} : _range, opts);
stack.push(encode_range_xls((r/*:any*/), opts));
break;
case 'PtgArea': /* 2.5.198.27 TODO: fixed points */
case 'PtgArea': /* [MS-XLS] 2.5.198.27 TODO: fixed points */
/*::type = f[1][0]; */r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls((r/*:any*/), opts));
break;
case 'PtgArea3d': /* 2.5.198.28 TODO */
case 'PtgArea3d': /* [MS-XLS] 2.5.198.28 TODO */
/*::type = f[1][0]; */ixti = /*::Number(*/f[1][1]/*::)*/; r = f[1][2];
sname = get_ixti(supbooks, ixti, opts);
stack.push(sname + "!" + encode_range_xls((r/*:any*/), opts));
break;
case 'PtgAttrSum': /* 2.5.198.41 */
case 'PtgAttrSum': /* [MS-XLS] 2.5.198.41 */
stack.push("SUM(" + stack.pop() + ")");
break;
case 'PtgAttrSemi': /* 2.5.198.37 */
case 'PtgAttrSemi': /* [MS-XLS] 2.5.198.37 */
break;
case 'PtgName': /* 2.5.97.60 TODO: revisions */
case 'PtgName': /* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 TODO: revisions */
/* f[1] = type, 0, nameindex */
nameidx = (f[1][2]/*:any*/);
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
@ -825,7 +810,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(name);
break;
case 'PtgNameX': /* 2.5.97.61 TODO: revisions */
case 'PtgNameX': /* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 TODO: revisions */
/* f[1] = type, ixti, nameindex */
var bookidx/*:number*/ = (f[1][1]/*:any*/); nameidx = (f[1][2]/*:any*/); var externbook;
/* TODO: Properly handle missing values */
@ -851,7 +836,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(externbook.Name);
break;
case 'PtgParen': /* 2.5.198.80 */
case 'PtgParen': /* [MS-XLS] 2.5.198.80 */
var lp = '(', rp = ')';
if(last_sp >= 0) {
sp = "";
@ -872,13 +857,13 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
}
stack.push(lp + stack.pop() + rp); break;
case 'PtgRefErr': /* 2.5.198.86 */
case 'PtgRefErr': /* [MS-XLS] 2.5.198.86 */
stack.push('#REF!'); break;
case 'PtgRefErr3d': /* 2.5.198.87 */
case 'PtgRefErr3d': /* [MS-XLS] 2.5.198.87 */
stack.push('#REF!'); break;
case 'PtgExp': /* 2.5.198.58 TODO */
case 'PtgExp': /* [MS-XLS] 2.5.198.58 TODO */
c = {c:(f[1][1]/*:any*/),r:(f[1][0]/*:any*/)};
var q = ({c: cell.c, r:cell.r}/*:any*/);
if(supbooks.sharedf[encode_cell(c)]) {
@ -900,55 +885,55 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
}
break;
case 'PtgArray': /* 2.5.198.32 TODO */
case 'PtgArray': /* [MS-XLS] 2.5.198.32 TODO */
stack.push("{" + stringify_array(/*::(*/f[1]/*:: :any)*/) + "}");
break;
case 'PtgMemArea': /* 2.5.198.70 TODO: confirm this is a non-display */
case 'PtgMemArea': /* [MS-XLS] 2.5.198.70 TODO: confirm this is a non-display */
//stack.push("(" + f[2].map(encode_range).join(",") + ")");
break;
case 'PtgAttrSpace': /* 2.5.198.38 */
case 'PtgAttrSpaceSemi': /* 2.5.198.39 */
case 'PtgAttrSpace': /* [MS-XLS] 2.5.198.38 */
case 'PtgAttrSpaceSemi': /* [MS-XLS] 2.5.198.39 */
last_sp = ff;
break;
case 'PtgTbl': /* 2.5.198.92 TODO */
case 'PtgTbl': /* [MS-XLS] 2.5.198.92 TODO */
break;
case 'PtgMemErr': /* 2.5.198.71 */
case 'PtgMemErr': /* [MS-XLS] 2.5.198.71 */
break;
case 'PtgMissArg': /* 2.5.198.74 */
case 'PtgMissArg': /* [MS-XLS] 2.5.198.74 */
stack.push("");
break;
case 'PtgAreaErr': /* 2.5.198.29 */
case 'PtgAreaErr': /* [MS-XLS] 2.5.198.29 */
stack.push("#REF!"); break;
case 'PtgAreaErr3d': /* 2.5.198.30 */
case 'PtgAreaErr3d': /* [MS-XLS] 2.5.198.30 */
stack.push("#REF!"); break;
case 'PtgMemFunc': /* 2.5.198.72 TODO */
case 'PtgMemFunc': /* [MS-XLS] 2.5.198.72 TODO */
break;
case 'PtgMemNoMem': /* [MS-XLS] 2.5.198.73 TODO */
break;
case 'PtgMemNoMem': /* 2.5.198.73 TODO -- find a test case */
throw new Error('Unrecognized Formula Token: ' + String(f));
case 'PtgElfCol': /* 2.5.198.46 */
case 'PtgElfColS': /* 2.5.198.47 */
case 'PtgElfColSV': /* 2.5.198.48 */
case 'PtgElfColV': /* 2.5.198.49 */
case 'PtgElfLel': /* 2.5.198.50 */
case 'PtgElfRadical': /* 2.5.198.51 */
case 'PtgElfRadicalLel': /* 2.5.198.52 */
case 'PtgElfRadicalS': /* 2.5.198.53 */
case 'PtgElfRw': /* 2.5.198.54 */
case 'PtgElfRwV': /* 2.5.198.55 */
case 'PtgElfCol': /* [MS-XLS] 2.5.198.46 */
case 'PtgElfColS': /* [MS-XLS] 2.5.198.47 */
case 'PtgElfColSV': /* [MS-XLS] 2.5.198.48 */
case 'PtgElfColV': /* [MS-XLS] 2.5.198.49 */
case 'PtgElfLel': /* [MS-XLS] 2.5.198.50 */
case 'PtgElfRadical': /* [MS-XLS] 2.5.198.51 */
case 'PtgElfRadicalLel': /* [MS-XLS] 2.5.198.52 */
case 'PtgElfRadicalS': /* [MS-XLS] 2.5.198.53 */
case 'PtgElfRw': /* [MS-XLS] 2.5.198.54 */
case 'PtgElfRwV': /* [MS-XLS] 2.5.198.55 */
throw new Error("Unsupported ELFs");
case 'PtgAttrBaxcel': /* 2.5.198.33 TODO -- find a test case*/
case 'PtgAttrBaxcel': /* [MS-XLS] 2.5.198.33 TODO -- find a test case*/
throw new Error('Unrecognized Formula Token: ' + String(f));
case 'PtgSxName': /* 2.5.198.91 TODO -- find a test case */
case 'PtgSxName': /* [MS-XLS] 2.5.198.91 TODO -- find a test case */
throw new Error('Unrecognized Formula Token: ' + String(f));
case 'PtgList': /* [MS-XLSB] 2.5.97.52 TODO -- find a test case */
throw new Error('Unrecognized Formula Token: ' + String(f));

@ -71,7 +71,6 @@ function parse_Formula(blob, length, opts) {
/* 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);
var rgce = parse_Rgce(data, cce, opts);
var cb = data.read_shift(4);

@ -68,6 +68,7 @@ function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, the
if(opts.cellNF) p.z = SSF._table[fmtid];
} catch(e) { if(opts.WTF) throw e; }
if(!opts || opts.cellText !== false) try {
if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
if(p.t === 'e') p.w = p.w || BErr[p.v];
else if(fmtid === 0) {
if(p.t === 'n') {

@ -474,9 +474,11 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
ws['!comments'] = [];
ws['!drawing'] = [];
var cname = wb.SheetNames[idx];
try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
o[o.length] = (writextag('sheetPr', null, {'codeName': escapexml(cname)}));
if(opts.bookType !== 'xlsx' && wb.vbaraw) {
var cname = wb.SheetNames[idx];
try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
o[o.length] = (writextag('sheetPr', null, {'codeName': escapexml(cname)}));
}
o[o.length] = (writextag('dimension', null, {'ref': ref}));
@ -547,7 +549,9 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
/* colBreaks */
/* customProperties */
/* cellWatches */
/* ignoredErrors */
o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
/* smartTags */
if(ws['!drawing'].length > 0) {

@ -1,5 +1,5 @@
/* [MS-XLSB] 2.4.718 BrtRowHdr */
/* [MS-XLSB] 2.4.726 BrtRowHdr */
function parse_BrtRowHdr(data, length) {
var z = ({}/*:any*/);
var tgt = data.l + length;
@ -67,16 +67,16 @@ function write_row_header(ba, ws, range, R) {
if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o);
}
/* [MS-XLSB] 2.4.812 BrtWsDim */
/* [MS-XLSB] 2.4.820 BrtWsDim */
var parse_BrtWsDim = parse_UncheckedRfX;
var write_BrtWsDim = write_UncheckedRfX;
/* [MS-XLSB] 2.4.813 BrtWsFmtInfo */
/* [MS-XLSB] 2.4.821 BrtWsFmtInfo */
function parse_BrtWsFmtInfo(/*::data, length*/) {
}
//function write_BrtWsFmtInfo(ws, o) { }
/* [MS-XLSB] 2.4.815 BrtWsProp */
/* [MS-XLSB] 2.4.823 BrtWsProp */
function parse_BrtWsProp(data, length) {
var z = {};
/* TODO: pull flags */
@ -94,7 +94,7 @@ function write_BrtWsProp(str, o) {
return o.slice(0, o.l);
}
/* [MS-XLSB] 2.4.303 BrtCellBlank */
/* [MS-XLSB] 2.4.306 BrtCellBlank */
function parse_BrtCellBlank(data) {
var cell = parse_XLSBCell(data);
return [cell];
@ -105,7 +105,7 @@ function write_BrtCellBlank(cell, ncell, o) {
}
/* [MS-XLSB] 2.4.304 BrtCellBool */
/* [MS-XLSB] 2.4.307 BrtCellBool */
function parse_BrtCellBool(data) {
var cell = parse_XLSBCell(data);
var fBool = data.read_shift(1);
@ -118,14 +118,14 @@ function write_BrtCellBool(cell, ncell, o) {
return o;
}
/* [MS-XLSB] 2.4.305 BrtCellError */
/* [MS-XLSB] 2.4.308 BrtCellError */
function parse_BrtCellError(data) {
var cell = parse_XLSBCell(data);
var bError = data.read_shift(1);
return [cell, bError, 'e'];
}
/* [MS-XLSB] 2.4.308 BrtCellIsst */
/* [MS-XLSB] 2.4.311 BrtCellIsst */
function parse_BrtCellIsst(data) {
var cell = parse_XLSBCell(data);
var isst = data.read_shift(4);
@ -138,7 +138,7 @@ function write_BrtCellIsst(cell, ncell, o) {
return o;
}
/* [MS-XLSB] 2.4.310 BrtCellReal */
/* [MS-XLSB] 2.4.313 BrtCellReal */
function parse_BrtCellReal(data) {
var cell = parse_XLSBCell(data);
var value = parse_Xnum(data);
@ -151,7 +151,7 @@ function write_BrtCellReal(cell, ncell, o) {
return o;
}
/* [MS-XLSB] 2.4.311 BrtCellRk */
/* [MS-XLSB] 2.4.314 BrtCellRk */
function parse_BrtCellRk(data) {
var cell = parse_XLSBCell(data);
var value = parse_RkNumber(data);
@ -165,7 +165,7 @@ function write_BrtCellRk(cell, ncell, o) {
}
/* [MS-XLSB] 2.4.314 BrtCellSt */
/* [MS-XLSB] 2.4.317 BrtCellSt */
function parse_BrtCellSt(data) {
var cell = parse_XLSBCell(data);
var value = parse_XLWideString(data);
@ -178,7 +178,7 @@ function write_BrtCellSt(cell, ncell, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
/* [MS-XLSB] 2.4.653 BrtFmlaBool */
function parse_BrtFmlaBool(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
@ -194,7 +194,7 @@ function parse_BrtFmlaBool(data, length, opts) {
return o;
}
/* [MS-XLSB] 2.4.648 BrtFmlaError */
/* [MS-XLSB] 2.4.654 BrtFmlaError */
function parse_BrtFmlaError(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
@ -210,7 +210,7 @@ function parse_BrtFmlaError(data, length, opts) {
return o;
}
/* [MS-XLSB] 2.4.649 BrtFmlaNum */
/* [MS-XLSB] 2.4.655 BrtFmlaNum */
function parse_BrtFmlaNum(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
@ -226,7 +226,7 @@ function parse_BrtFmlaNum(data, length, opts) {
return o;
}
/* [MS-XLSB] 2.4.650 BrtFmlaString */
/* [MS-XLSB] 2.4.656 BrtFmlaString */
function parse_BrtFmlaString(data, length, opts) {
var end = data.l + length;
var cell = parse_XLSBCell(data);
@ -242,17 +242,17 @@ function parse_BrtFmlaString(data, length, opts) {
return o;
}
/* [MS-XLSB] 2.4.676 BrtMergeCell */
/* [MS-XLSB] 2.4.682 BrtMergeCell */
var parse_BrtMergeCell = parse_UncheckedRfX;
var write_BrtMergeCell = write_UncheckedRfX;
/* [MS-XLSB] 2.4.108 BrtBeginMergeCells */
/* [MS-XLSB] 2.4.107 BrtBeginMergeCells */
function write_BrtBeginMergeCells(cnt, o) {
if(o == null) o = new_buf(4);
o.write_shift(4, cnt);
return o;
}
/* [MS-XLSB] 2.4.656 BrtHLink */
/* [MS-XLSB] 2.4.662 BrtHLink */
function parse_BrtHLink(data, length/*::, opts*/) {
var end = data.l + length;
var rfx = parse_UncheckedRfX(data, 16);
@ -290,7 +290,7 @@ function parse_BrtArrFmla(data, length, opts) {
return o;
}
/* [MS-XLSB] 2.4.742 BrtShrFmla */
/* [MS-XLSB] 2.4.750 BrtShrFmla */
function parse_BrtShrFmla(data, length, opts) {
var end = data.l + length;
var rfx = parse_UncheckedRfX(data, 16);
@ -320,7 +320,7 @@ function write_BrtColInfo(C/*:number*/, col, o) {
return o;
}
/* [MS-XLSB] 2.4.672 BrtMargins */
/* [MS-XLSB] 2.4.678 BrtMargins */
var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
function parse_BrtMargins(data/*::, length, opts*/)/*:Margins*/ {
var margins = ({}/*:any*/);
@ -334,7 +334,7 @@ function write_BrtMargins(margins/*:Margins*/, o) {
return o;
}
/* [MS-XLSB] 2.4.292 BrtBeginWsView */
/* [MS-XLSB] 2.4.299 BrtBeginWsView */
function parse_BrtBeginWsView(data/*::, length, opts*/) {
var f = data.read_shift(2);
data.l += 28;
@ -360,7 +360,16 @@ function write_BrtBeginWsView(ws, Workbook, o) {
return o;
}
/* [MS-XLSB] 2.4.740 BrtSheetProtection */
/* [MS-XLSB] 2.4.309 BrtCellIgnoreEC */
function write_BrtCellIgnoreEC(ref) {
var o = new_buf(24);
o.write_shift(4, 4);
o.write_shift(4, 1);
write_UncheckedRfX(ref, o);
return o;
}
/* [MS-XLSB] 2.4.748 BrtSheetProtection */
function write_BrtSheetProtection(sp, o) {
if(o == null) o = new_buf(16*4+2);
o.write_shift(2, sp.password ? crypto_CreatePasswordVerifier_Method1(sp.password) : 0);
@ -736,6 +745,13 @@ function write_COLINFOS(ba, ws/*:Worksheet*//*::, idx:number, opts, wb:Workbook*
write_record(ba, 'BrtEndColInfos');
}
function write_IGNOREECS(ba, ws/*:Worksheet*/) {
if(!ws || !ws['!ref']) return;
write_record(ba, 'BrtBeginCellIgnoreECs');
write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref'])));
write_record(ba, 'BrtEndCellIgnoreECs');
}
function write_HLINKS(ba, ws/*:Worksheet*/, rels) {
/* *BrtHLink */
ws['!links'].forEach(function(l) {
@ -756,7 +772,7 @@ function write_LEGACYDRAWING(ba, ws/*:Worksheet*/, idx/*:number*/, rels) {
function write_AUTOFILTER(ba, ws) {
if(!ws['!autofilter']) return;
write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(decode_range(ws['!autofilter'].ref)));
write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ws['!autofilter'].ref)));
/* *FILTERCOLUMN */
/* [SORTSTATE] */
/* BrtEndAFilter */
@ -798,7 +814,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
/* passed back to write_zip and removed there */
ws['!comments'] = [];
write_record(ba, "BrtBeginSheet");
write_record(ba, "BrtWsProp", write_BrtWsProp(c));
if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
write_record(ba, "BrtWsDim", write_BrtWsDim(r));
write_WSVIEWS2(ba, ws, wb.Workbook);
write_WSFMTINFO(ba, ws);
@ -825,7 +841,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
/* [COLBRK] */
/* *BrtBigName */
/* [CELLWATCHES] */
/* [IGNOREECS] */
write_IGNOREECS(ba, ws);
/* [SMARTTAGS] */
/* [BrtDrawing] */
write_LEGACYDRAWING(ba, ws, idx, rels);

@ -124,15 +124,20 @@ function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ {
});
return _good;
}
function check_wb_names(N) {
function check_wb_names(N, S, codes) {
N.forEach(function(n,i) {
check_ws_name(n);
for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
if(codes) {
var cn = (S && S[i] && S[i].CodeName) || n;
if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
}
});
}
function check_wb(wb) {
if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
if(!wb.SheetNames.length) throw new Error("Workbook is empty");
check_wb_names(wb.SheetNames);
var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
/* TODO: validate workbook */
}

@ -1,4 +1,4 @@
/* [MS-XLSB] 2.4.301 BrtBundleSh */
/* [MS-XLSB] 2.4.304 BrtBundleSh */
function parse_BrtBundleSh(data, length/*:number*/) {
var z = {};
z.Hidden = data.read_shift(4); //hsState ST_SheetState
@ -16,7 +16,7 @@ function write_BrtBundleSh(data, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.807 BrtWbProp */
/* [MS-XLSB] 2.4.815 BrtWbProp */
function parse_BrtWbProp(data, length)/*:WBProps*/ {
var o/*:WBProps*/ = ({}/*:any*/);
var flags = data.read_shift(4);
@ -61,7 +61,7 @@ function parse_BrtFRTArchID$(data, length) {
return o;
}
/* [MS-XLSB] 2.4.680 BrtName */
/* [MS-XLSB] 2.4.687 BrtName */
function parse_BrtName(data, length, opts) {
var end = data.l + length;
data.l += 4; //var flags = data.read_shift(4);
@ -83,7 +83,7 @@ function parse_BrtName(data, length, opts) {
return out;
}
/* [MS-XLSB] 2.1.7.60 Workbook */
/* [MS-XLSB] 2.1.7.61 Workbook */
function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
var pass = false;
@ -185,7 +185,6 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
return wb;
}
/* [MS-XLSB] 2.1.7.60 Workbook */
function write_BUNDLESHS(ba, wb/*::, opts*/) {
write_record(ba, "BrtBeginBundleShs");
for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
@ -196,7 +195,7 @@ function write_BUNDLESHS(ba, wb/*::, opts*/) {
write_record(ba, "BrtEndBundleShs");
}
/* [MS-XLSB] 2.4.643 BrtFileVersion */
/* [MS-XLSB] 2.4.649 BrtFileVersion */
function write_BrtFileVersion(data, o) {
if(!o) o = new_buf(127);
for(var i = 0; i != 4; ++i) o.write_shift(4, 0);
@ -208,7 +207,7 @@ function write_BrtFileVersion(data, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.298 BrtBookView */
/* [MS-XLSB] 2.4.301 BrtBookView */
function write_BrtBookView(idx, o) {
if(!o) o = new_buf(29);
o.write_shift(-4, 0);
@ -223,7 +222,6 @@ function write_BrtBookView(idx, o) {
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.1.7.60 Workbook */
function write_BOOKVIEWS(ba, wb/*::, opts*/) {
/* required if hidden tab appears before visible tab */
if(!wb.Workbook || !wb.Workbook.Sheets) return;
@ -240,7 +238,7 @@ function write_BOOKVIEWS(ba, wb/*::, opts*/) {
write_record(ba, "BrtEndBookViews");
}
/* [MS-XLSB] 2.4.302 BrtCalcProp */
/* [MS-XLSB] 2.4.305 BrtCalcProp */
/*function write_BrtCalcProp(data, o) {
if(!o) o = new_buf(26);
o.write_shift(4,0); // force recalc
@ -253,14 +251,14 @@ function write_BOOKVIEWS(ba, wb/*::, opts*/) {
return o;
}*/
/* [MS-XLSB] 2.4.640 BrtFileRecover */
/* [MS-XLSB] 2.4.646 BrtFileRecover */
/*function write_BrtFileRecover(data, o) {
if(!o) o = new_buf(1);
o.write_shift(1,0);
return o;
}*/
/* [MS-XLSB] 2.1.7.60 Workbook */
/* [MS-XLSB] 2.1.7.61 Workbook */
function write_wb_bin(wb, opts) {
var ba = buf_array();
write_record(ba, "BrtBeginBook");

@ -837,15 +837,15 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
function parse_props(cfb/*:CFBContainer*/, props, o) {
/* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
var DSI = CFB.find(cfb, '!DocumentSummaryInformation');
if(DSI) try {
var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI);
if(DSI && DSI.size > 0) try {
var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, "02d5cdd59c2e1b10939708002b2cf9ae");
for(var d in DocSummary) props[d] = DocSummary[d];
} catch(e) {if(o.WTF) throw e;/* empty */}
/* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
var SI = CFB.find(cfb, '!SummaryInformation');
if(SI) try {
var Summary = parse_PropertySetStream(SI, SummaryPIDSI);
if(SI && SI.size > 0) try {
var Summary = parse_PropertySetStream(SI, SummaryPIDSI, "e0859ff2f94f6810ab9108002b27b3d9");
for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
} catch(e) {if(o.WTF) throw e;/* empty */}
}

@ -631,8 +631,10 @@ var XLSBRecordEnum = {
/*::[*/0x0422/*::]*/: { n:"BrtBeginSparklineGroups" },
/*::[*/0x0423/*::]*/: { n:"BrtEndSparklineGroups" },
/*::[*/0x0425/*::]*/: { n:"BrtSXVD14" },
/*::[*/0x0426/*::]*/: { n:"BrtBeginSxview14" },
/*::[*/0x0427/*::]*/: { n:"BrtEndSxview14" },
/*::[*/0x0426/*::]*/: { n:"BrtBeginSXView14" },
/*::[*/0x0427/*::]*/: { n:"BrtEndSXView14" },
/*::[*/0x0428/*::]*/: { n:"BrtBeginSXView16" },
/*::[*/0x0429/*::]*/: { n:"BrtEndSXView16" },
/*::[*/0x042A/*::]*/: { n:"BrtBeginPCD14" },
/*::[*/0x042B/*::]*/: { n:"BrtEndPCD14" },
/*::[*/0x042C/*::]*/: { n:"BrtBeginExtConn14" },
@ -819,6 +821,12 @@ var XLSBRecordEnum = {
/*::[*/0x0856/*::]*/: { n:"BrtFieldListActiveItem" },
/*::[*/0x0857/*::]*/: { n:"BrtPivotCacheIdVersion" },
/*::[*/0x0858/*::]*/: { n:"BrtSXDI15" },
/*::[*/0x0859/*::]*/: { n:"BrtBeginModelTimeGroupings" },
/*::[*/0x085A/*::]*/: { n:"BrtEndModelTimeGroupings" },
/*::[*/0x085B/*::]*/: { n:"BrtBeginModelTimeGrouping" },
/*::[*/0x085C/*::]*/: { n:"BrtEndModelTimeGrouping" },
/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
/*::[*/0xFFFF/*::]*/: { n:"" }
};

@ -84,16 +84,45 @@ function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
return ba.end();
}
function write_FMTS_biff8(ba, NF/*:?SSFTable*/) {
function write_FONTS_biff8(ba, data, opts) {
write_biff_rec(ba, "Font", write_Font({
sz:12,
color: {theme:1},
name: "Arial",
family: 2,
scheme: "minor"
}, opts));
}
function write_FMTS_biff8(ba, NF/*:?SSFTable*/, opts) {
if(!NF) return;
[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
/*:: if(!NF) return; */
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i]));
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts));
});
}
function write_CELLXFS_biff8(ba, data) {
data.forEach(function(c) {
write_biff_rec(ba, "XF", write_XF(c,0));
function write_FEAT(ba, ws) {
/* [MS-XLS] 2.4.112 */
var o = new_buf(19);
o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
write_biff_rec(ba, "FeatHdr", o);
/* [MS-XLS] 2.4.111 */
o = new_buf(39);
o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0);
o.write_shift(2, 3); o.write_shift(1, 0); o.write_shift(4, 0);
o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0);
write_Ref8U(safe_decode_range(ws['!ref']), o);
o.write_shift(4, 4);
write_biff_rec(ba, "Feat", o);
}
function write_CELLXFS_biff8(ba, opts) {
for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts));
opts.cellXfs.forEach(function(c) {
write_biff_rec(ba, "XF", write_XF(c, 0, opts));
});
}
@ -107,14 +136,14 @@ function write_ws_biff8_hlinks(ba/*:BufArray*/, ws) {
}
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
var os = get_cell_style(opts.cellXfs, cell, opts);
var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
/* TODO: emit RK as appropriate */
write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts));
return;
case 'b': case 'e': write_biff_rec(ba, "BoolErr", write_BoolErr(R, C, cell.v, os, opts, cell.t)); return;
case 'b': case 'e': write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t)); return;
/* TODO: codepage, sst */
case 's': case 'str':
write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts));
@ -169,12 +198,14 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
/* ... */
if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0]));
/* ... */
if(b8) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']||[]));
if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']));
/* ... */
if(b8) write_ws_biff8_hlinks(ba, ws);
/* ... */
write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
/* ... */
if(b8) write_FEAT(ba, ws);
/* ... */
write_biff_rec(ba, "EOF");
return ba.end();
}
@ -182,7 +213,9 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
/* [MS-XLS] 2.1.7.20.3 */
function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
var A = buf_array();
var _wb/*:WBWBProps*/ = /*::((*/(wb.Workbook||{}).WBProps||{/*::CodeName:"ThisWorkbook"*/}/*:: ):any)*/;
var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
var _sheets/*:Array<WBWSProp>*/ = (_WB.Sheets||[]);
var _wb/*:WBProps*/ = /*::((*/_WB.WBProps||{/*::CodeName:"ThisWorkbook"*/}/*:: ):any)*/;
var b8 = opts.biff == 8, b5 = opts.biff == 5;
write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
if(opts.bookType == "xla") write_biff_rec(A, "Addin");
@ -194,10 +227,10 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4));
if(b8) write_biff_rec(A, "DSF", writeuint16(0));
if(b8) write_biff_rec(A, "Excel9File");
write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
if(b8 && wb.vbaraw) {
write_biff_rec(A, "ObProj");
// $FlowIgnore
var cname/*:string*/ = _wb.CodeName || "ThisWorkbook";
write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts));
}
@ -215,8 +248,9 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
if(b8) write_biff_rec(A, "RefreshAll", writebool(false));
write_biff_rec(A, "BookBool", writeuint16(0));
/* ... */
if(b8) write_FMTS_biff8(A, wb.SSF);
if(b8) write_CELLXFS_biff8(A, opts.cellXfs);
write_FONTS_biff8(A, wb, opts);
write_FMTS_biff8(A, wb.SSF, opts);
write_CELLXFS_biff8(A, opts);
/* ... */
if(b8) write_biff_rec(A, "UsesELFs", writebool(false));
var a = A.end();
@ -232,7 +266,8 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
for(j = 0; j < wb.SheetNames.length; ++j) blen += (b8 ? 12 : 11) + (b8 ? 2 : 1) * wb.SheetNames[j].length;
var start = a.length + blen + c.length;
for(j = 0; j < wb.SheetNames.length; ++j) {
write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:0, dt:0, name:wb.SheetNames[j]}, opts));
var _sheet/*:WBWSProp*/ = _sheets[j] || ({}/*:any*/);
write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts));
start += bufs[j].length;
}
/* 1*BoundSheet8 */

@ -1,5 +1,5 @@
jvm-npm.js
sheetjs.*
SheetJSSwift
duk*
*.class
*.jar

@ -0,0 +1,3 @@
disabled_rules:
- trailing_semicolon
- identifier_name

@ -4,49 +4,47 @@ all: duktape nashorn rhinojs swift
.PHONY: base
base:
if [ ! -e sheetjs.xlsx ]; then node ../../tests/write.js; fi
if [ ! -e xlsx.full.min.js ]; then cp ../../dist/xlsx.full.min.js .; fi
.PHONY: duktape
duktape: base ## duktape demo
bash ./duktape.sh
gcc -std=c99 -Wall -osheetjs.duk sheetjs.duk.c duktape.c -lm
if [ ! -e xlsx.duktape.js ]; then cp ../../dist/xlsx.full.min.js xlsx.duktape.js; fi
./sheetjs.duk
.PHONY: nashorn
nashorn: base ## nashorn demo
if [ ! -e jvm-npm.js ]; then curl -O https://rawgit.com/nodyn/jvm-npm/master/src/main/javascript/jvm-npm.js; fi
jjs nashorn.js
.PHONY: swift
swift: base ## swift demo
if [ ! -e xlsx.swift.js ]; then cp ../../dist/xlsx.full.min.js xlsx.swift.js; fi
./SheetJSCore.swift
swiftc SheetJSCore.swift main.swift -o SheetJSSwift
./SheetJSSwift
.PHONY: chakra
chakra: base ## Chakra demo
node -pe "fs.writeFileSync('payload.js', 'var payload = \"' + fs.readFileSync('sheetjs.xlsx').toString('base64') + '\";')"
cat global.js ../../dist/xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
cat global.js xlsx.full.min.js payload.js chakra.js > xlsx.chakra.js
chakra ./xlsx.chakra.js
.PHONY: rhinojs ## rhino demo
rhinojs: base SheetJSRhino.class
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xlsx
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xlsb
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xls
java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.xml.xls
for ext in xlsx xlsb biff8.xls xml.xls; do java -cp .:SheetJS.jar:rhino.jar SheetJSRhino sheetjs.$$ext; done
RHDEPS=$(filter-out SheetJSRhino.class,$(patsubst %.java,%.class,$(wildcard com/sheetjs/*.java)))
$(RHDEPS): %.class: %.java rhino.jar
javac -cp .:SheetJS.jar:rhino.jar $*.java
SheetJSRhino.class: $(RHDEPS)
jar -cf SheetJS.jar $^ ../../dist/xlsx.full.min.js
jar -cf SheetJS.jar $^ xlsx.full.min.js
javac -cp .:SheetJS.jar:rhino.jar SheetJSRhino.java
rhino.jar:
if [ ! -e rhino ]; then git clone https://github.com/mozilla/rhino; fi
if [ ! -e rhino/build/rhino*/js.jar ]; then cd rhino; ant jar; fi
cp rhino/build/rhino*/js.jar rhino.jar
#if [ ! -e rhino/build/rhino*/js.jar ]; then cd rhino; ant jar; fi
#cp rhino/build/rhino*/js.jar rhino.jar
if [ ! -e rhino/buildGradle/libs/rhino*.jar ]; then cd rhino; ./gradlew jar; fi
cp rhino/buildGradle/libs/rhino*.jar rhino.jar
.PHONY: clean
clean:

@ -31,7 +31,7 @@ let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory;
let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js");
/* prepare JS context */
var context:JSContext! = JSContext();
var context: JSContext! = JSContext();
var src = "var global = (function(){ return this; }).call(null);";
context.evaluateScript(src);
@ -50,17 +50,17 @@ Binary strings can be passed back and forth using `String.Encoding.isoLatin1`:
```swift
/* parse sheetjs.xls */
let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
let data:String! = try String(contentsOf: file_path, encoding:String.Encoding.isoLatin1);
context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1);
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)!);
src = "var wb = XLSX.read(payload, {type:'binary'});";
context.evaluateScript(src);
/* write to sheetjs.xlsx */
let out_path = shared_dir.appendingPathComponent("sheetjs.xlsx");
/* write to sheetjsw.xlsx */
let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx");
src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})";
context.evaluateScript(src);
let outvalue: JSValue! = context.objectForKeyedSubscript("out");
var out:String! = outvalue.toString();
var out: String! = outvalue.toString();
try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);
```
@ -70,9 +70,12 @@ try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLat
Nashorn ships with Java 8. It includes a command-line tool `jjs` for running JS
scripts. It is somewhat limited but does offer access to the full Java runtime.
`jjs` does not provide a CommonJS `require` implementation. This demo uses a
[`shim`](https://rawgit.com/nodyn/jvm-npm/master/src/main/javascript/jvm-npm.js)
and manually requires the library.
The `load` function in `jjs` can load the minified source directly:
```js
var global = (function(){ return this; }).call(null);
load('xlsx.full.min.js');
```
The Java `nio` API provides the `Files.readAllBytes` method to read a file into
a byte array. To use in `XLSX.read`, the demo copies the bytes into a plain JS
@ -115,7 +118,7 @@ duk_put_global_string(ctx, "buf");
duk_eval_string_noresult("workbook = XLSX.read(buf, {type:'buffer'});");
/* write a workbook object to a C char array */
duk_eval_string(ctx, "XLSX.write(workbook, {type:'buffer', bookType:'xlsx'})");
duk_eval_string(ctx, "XLSX.write(workbook, {type:'array', bookType:'xlsx'})");
duk_size_t sz;
char *buf = (char *)duk_get_buffer_data(ctx, -1, sz);
duk_pop(ctx);

@ -8,7 +8,7 @@ let shared_dir = PlaygroundSupport.playgroundSharedDataDirectory;
let lib_path = shared_dir.appendingPathComponent("xlsx.full.min.js");
/* prepare JS context */
var context:JSContext! = JSContext();
var context: JSContext! = JSContext();
var src = "var global = (function(){ return this; }).call(null);";
context.evaluateScript(src);
@ -23,15 +23,15 @@ var version = XLSXversion.toString();
/* parse sheetjs.xls */
let file_path = shared_dir.appendingPathComponent("sheetjs.xls");
let data:String! = try String(contentsOf: file_path, encoding:String.Encoding.isoLatin1);
context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
let data: String! = try String(contentsOf: file_path, encoding: String.Encoding.isoLatin1);
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)!);
src = "var wb = XLSX.read(payload, {type:'binary'});";
context.evaluateScript(src);
/* write to sheetjs.xlsx */
let out_path = shared_dir.appendingPathComponent("sheetjs.xlsx");
/* write to sheetjsw.xlsx */
let out_path = shared_dir.appendingPathComponent("sheetjsw.xlsx");
src = "var out = XLSX.write(wb, {type:'binary', bookType:'xlsx'})";
context.evaluateScript(src);
let outvalue: JSValue! = context.objectForKeyedSubscript("out");
var out:String! = outvalue.toString();
var out: String! = outvalue.toString();
try? out.write(to: out_path, atomically: false, encoding: String.Encoding.isoLatin1);

@ -1,62 +1,96 @@
#!/usr/bin/env xcrun swift
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
import JavaScriptCore;
class SheetJS {
enum SJSError: Error {
case badJSContext;
case badJSWorkbook;
case badJSWorksheet;
};
class SJSWorksheet {
var context: JSContext!;
var wb: JSValue!; var ws: JSValue!;
var idx: Int32;
func toCSV() throws -> String {
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
let utils: JSValue! = XLSX.objectForKeyedSubscript("utils");
let sheet_to_csv: JSValue! = utils.objectForKeyedSubscript("sheet_to_csv");
return sheet_to_csv.call(withArguments: [ws]).toString();
}
init(ctx: JSContext, workbook: JSValue, worksheet: JSValue, idx: Int32) throws {
self.context = ctx; self.wb = workbook; self.ws = worksheet; self.idx = idx;
}
}
class SJSWorkbook {
var context: JSContext!;
var wb: JSValue!; var SheetNames: JSValue!; var Sheets: JSValue!;
func getSheetAtIndex(idx: Int32) throws -> SJSWorksheet {
let SheetName: String = SheetNames.atIndex(Int(idx)).toString();
let ws: JSValue! = Sheets.objectForKeyedSubscript(SheetName);
return try SJSWorksheet(ctx: context, workbook: wb, worksheet: ws, idx: idx);
}
func writeBStr(bookType: String = "xlsx") throws -> String {
let XLSX: JSValue! = context.objectForKeyedSubscript("XLSX");
context.evaluateScript(String(format: "var writeopts = {type:'binary', bookType:'%@'}", bookType));
let writeopts: JSValue! = context.objectForKeyedSubscript("writeopts");
let writefunc: JSValue! = XLSX.objectForKeyedSubscript("write");
return writefunc.call(withArguments: [wb, writeopts]).toString();
}
init(ctx: JSContext, wb: JSValue) throws {
self.context = ctx;
self.wb = wb;
self.SheetNames = wb.objectForKeyedSubscript("SheetNames");
self.Sheets = wb.objectForKeyedSubscript("Sheets");
}
}
class SheetJSCore {
var context: JSContext!;
var XLSX: JSValue!;
enum SJSError: Error {
case badJSContext;
};
func init_context() throws -> JSContext {
var context: JSContext!
do {
context = JSContext();
context.exceptionHandler = { ctx, X in if let e = X { print(e.toString()); }; }
var src = "var global = (function(){ return this; }).call(null);";
context.evaluateScript(src);
src = try String(contentsOfFile: "xlsx.swift.js");
context.exceptionHandler = { ctx, X in if let e = X { print(e.toString()); }; };
context.evaluateScript("var global = (function(){ return this; }).call(null);");
context.evaluateScript("if(typeof wbs == 'undefined') wbs = [];");
let src = try String(contentsOfFile: "xlsx.full.min.js");
context.evaluateScript(src);
if context != nil { return context!; }
} catch { print(error.localizedDescription); }
throw SheetJS.SJSError.badJSContext;
throw SJSError.badJSContext;
}
func version() throws -> String {
if let version = XLSX.objectForKeyedSubscript("version") { return version.toString(); }
throw SheetJS.SJSError.badJSContext;
throw SJSError.badJSContext;
}
func readFileToCSV(file: String) throws -> String {
let data:String! = try String(contentsOfFile: file, encoding:String.Encoding.isoLatin1);
self.context.setObject(data, forKeyedSubscript:"payload" as (NSCopying & NSObjectProtocol)!);
func readFile(file: String) throws -> SJSWorkbook {
let data: String! = try String(contentsOfFile: file, encoding: String.Encoding.isoLatin1);
return try readBStr(data: data);
}
let src = [
"var wb = XLSX.read(payload, {type:'binary'});",
"var ws = wb.Sheets[wb.SheetNames[0]];",
"var result = XLSX.utils.sheet_to_csv(ws);"
].joined(separator: "\n");
self.context.evaluateScript(src);
return context.objectForKeyedSubscript("result").toString();
func readBStr(data: String) throws -> SJSWorkbook {
context.setObject(data, forKeyedSubscript: "payload" as (NSCopying & NSObjectProtocol)!);
context.evaluateScript("var wb = XLSX.read(payload, {type:'binary'});");
let wb: JSValue! = context.objectForKeyedSubscript("wb");
if wb == nil { throw SJSError.badJSWorkbook; }
return try SJSWorkbook(ctx: context, wb: wb);
}
init() throws {
do {
self.context = try init_context();
self.XLSX = context.objectForKeyedSubscript("XLSX");
if self.XLSX == nil {
throw SheetJS.SJSError.badJSContext;
}
self.XLSX = self.context.objectForKeyedSubscript("XLSX");
if self.XLSX == nil { throw SJSError.badJSContext; }
} catch { print(error.localizedDescription); }
}
}
let sheetjs = try SheetJS();
try print(sheetjs.version());
try print(sheetjs.readFileToCSV(file:"sheetjs.xlsx"));
try print(sheetjs.readFileToCSV(file:"sheetjs.xlsb"));
try print(sheetjs.readFileToCSV(file:"sheetjs.xls"));
try print(sheetjs.readFileToCSV(file:"sheetjs.xml.xls"));

@ -17,7 +17,7 @@ public class JSHelper {
byte[] b = Files.readAllBytes(Paths.get(file));
System.out.println(b.length);
StringBuilder sb = new StringBuilder();
for(int i = 0; i < b.length; ++i) sb.append(Character.toString((char)b[i]));
for(int i = 0; i < b.length; ++i) sb.append(Character.toString((char)(b[i] < 0 ? b[i] + 256 : b[i])));
return sb.toString();
}

@ -26,7 +26,7 @@ public class SheetJS {
cx.evaluateString(scope, s, "<cmd>", 1, null);
/* eval library */
s = new Scanner(SheetJS.class.getResourceAsStream("/dist/xlsx.full.min.js")).useDelimiter("\\Z").next();
s = new Scanner(SheetJS.class.getResourceAsStream("/xlsx.full.min.js")).useDelimiter("\\Z").next();
//s = new Scanner(new File("xlsx.full.min.js")).useDelimiter("\\Z").next();
cx.evaluateString(scope, s, "<cmd>", 1, null);
@ -41,14 +41,14 @@ public class SheetJS {
String d = JSHelper.read_file(filename);
/* options argument */
NativeObject q = (NativeObject)this.cx.evaluateString(this.scope, "q = {'type':'binary'};", "<cmd>", 2, null);
NativeObject q = (NativeObject)this.cx.evaluateString(this.scope, "q = {'type':'binary', 'WTF':1};", "<cmd>", 2, null);
/* set up function arguments */
Object functionArgs[] = {d, q};
Object args[] = {d, q};
/* call read -> wb workbook */
Function readfunc = (Function)JSHelper.get_object("XLSX.read",this.scope);
NativeObject wb = (NativeObject)readfunc.call(this.cx, this.scope, this.nXLSX, functionArgs);
NativeObject wb = (NativeObject)readfunc.call(this.cx, this.scope, this.nXLSX, args);
return new SheetJSFile(wb, this);
}

@ -1,5 +1,5 @@
#!/bin/bash
DUKTAPE_VER=2.1.1
DUKTAPE_VER=2.2.0
if [ ! -e duktape-$DUKTAPE_VER ]; then
if [ ! -e duktape-$DUKTAPE_VER.tar ]; then
if [ ! -e duktape-$DUKTAPE_VER.tar.xz ]; then
@ -14,4 +14,3 @@ for f in duktape.{c,h} duk_config.h; do
cp duktape-$DUKTAPE_VER/src/$f .
done

21
demos/altjs/main.swift Executable file

@ -0,0 +1,21 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
let sheetjs = try SheetJSCore();
try print(sheetjs.version());
let filenames: [[String]] = [
["xlsx", "xlsx"],
["xlsb", "xlsb"],
["biff8.xls", "xls"],
["xml.xls", "xlml"]
];
for fn in filenames {
let wb: SJSWorkbook = try sheetjs.readFile(file: "sheetjs." + fn[0]);
let ws: SJSWorksheet = try wb.getSheetAtIndex(idx: 0);
let csv: String = try ws.toCSV();
print(csv);
let wbout: String = try wb.writeBStr(bookType: fn[1]);
try wbout.write(toFile: "sheetjsswift." + fn[0], atomically: false, encoding: String.Encoding.isoLatin1);
}

@ -1,29 +1,36 @@
#!/usr/bin/env jjs
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* read file */
var path = java.nio.file.Paths.get('sheetjs.xlsx');
var fileArray = java.nio.file.Files.readAllBytes(path);
/* convert to plain JS array */
function b2a(b) {
var out = new Array(b.length);
for(var i = 0; i < out.length; i++) out[i] = b[i];
return out;
}
var u8a = b2a(fileArray);
/* load module */
load('./jvm-npm.js');
JSZip = require('../../jszip.js');
cptable = require('../../dist/cpexcel.js');
XLSX = require('../../xlsx.js');
var global = (function(){ return this; }).call(null);
load('xlsx.full.min.js');
/* read file */
var wb = XLSX.read(u8a, {type:"array"});
/* helper to convert byte array to plain JS array */
function b2a(b) {
var out = new Array(b.length);
for(var i = 0; i < out.length; i++) out[i] = (b[i] < 0 ? b[i] + 256 : b[i]);
return out;
}
/* get first worksheet */
var ws = wb.Sheets[wb.SheetNames[0]];
var js = XLSX.utils.sheet_to_json(ws, {header:1});
function process_file(path) {
java.lang.System.out.println(path);
/* print out every line */
js.forEach(function(l) { java.lang.System.out.println(JSON.stringify(l)); });
/* read file */
var path = java.nio.file.Paths.get(path);
var bytes = java.nio.file.Files.readAllBytes(path);
var u8a = b2a(bytes);
/* read data */
var wb = XLSX.read(u8a, {type:"array"});
/* get first worksheet as an array of arrays */
var ws = wb.Sheets[wb.SheetNames[0]];
var js = XLSX.utils.sheet_to_json(ws, {header:1});
/* print out every line */
js.forEach(function(l) { java.lang.System.out.println(JSON.stringify(l)); });
}
process_file('sheetjs.xlsx');
process_file('sheetjs.xlsb');
process_file('sheetjs.biff8.xls');

@ -66,7 +66,7 @@ int main(int argc, char *argv[]) {
DOIT("var global = (function(){ return this; }).call(null);");
/* load library */
res = eval_file(ctx, "xlsx.duktape.js");
res = eval_file(ctx, "xlsx.full.min.js");
if(res != 0) FAIL("library load")
/* get version string */
@ -75,11 +75,12 @@ int main(int argc, char *argv[]) {
duk_pop(ctx);
/* read file */
res = load_file(ctx, "sheetjs.xlsx", "buf");
if(res != 0) FAIL("load sheetjs.xlsx")
#define INFILE "sheetjs.xlsx"
res = load_file(ctx, INFILE, "buf");
if(res != 0) FAIL("load " INFILE)
/* parse workbook */
DOIT("wb = XLSX.read(buf, {type:'buffer'});");
DOIT("wb = XLSX.read(buf, {type:'buffer', cellNF:true});");
DOIT("ws = wb.Sheets[wb.SheetNames[0]]");
/* print CSV */
@ -91,9 +92,15 @@ int main(int argc, char *argv[]) {
DOIT("ws['A1'].v = 3; delete ws['A1'].w;");
/* write file */
DOIT("newbuf = XLSX.write(wb, {type:'buffer', bookType:'xlsx'})");
res = save_file(ctx, "sheetjsw.xlsx", "newbuf");
if(res != 0) FAIL("save sheetjsw.xlsx")
#define WRITE_TYPE(BOOKTYPE) \
DOIT("newbuf = (XLSX.write(wb, {type:'array', bookType:'" BOOKTYPE "'}));");\
res = save_file(ctx, "sheetjsw." BOOKTYPE, "newbuf");\
if(res != 0) FAIL("save sheetjsw." BOOKTYPE)
WRITE_TYPE("xlsb")
WRITE_TYPE("xlsx")
WRITE_TYPE("xls")
WRITE_TYPE("csv")
/* cleanup */
duk_destroy_heap(ctx);

@ -2,10 +2,54 @@
Despite the efforts to deprecate the pertinent operating systems, IE is still
very popular, required for various government and corporate websites throughout
the world. The modern download strategies are not available in older versions
of IE, but there are alternative approaches.
the world. The modern upload and download strategies are not available in older
versions of IE, but there are alternative approaches.
## Strategies
## Upload Strategies
#### IE10 and IE11 FileReader
IE10 and IE11 support the standard HTML5 FileReader API:
```js
function handle_fr(e) {
var files = e.target.files, f = files[0];
var reader = new FileReader();
var rABS = !!reader.readAsBinaryString;
reader.onload = function(e) {
var data = e.target.result;
if(!rABS) data = new Uint8Array(data);
var wb = XLSX.read(data, {type: rABS ? 'binary' : 'array'});
process_wb(wb);
};
if(rABS) reader.readAsBinaryString(f); else reader.readAsArrayBuffer(f);
}
input_dom_element.addEventListener('change', handle_fr, false);
```
#### ActiveX-based Upload
Through the `Scripting.FileSystemObject` object model, a script in the VBScript
scripting language can read from an arbitrary path on the filesystem. The shim
includes a special `IE_LoadFile` function to read binary strings from file. This
should be called from a file input `onchange` event:
```js
var input_dom_element = document.getElementById("file");
function handle_ie() {
/* get data from selected file */
var path = input_dom_element.value;
var bstr = IE_LoadFile(path);
/* read workbook */
var wb = XLSX.read(bstr, {type:'binary'});
/* DO SOMETHING WITH workbook HERE */
}
input_dom_element.attachEvent('onchange', handle_ie);
```
## Download Strategies
#### IE10 and IE11 File API
@ -30,8 +74,11 @@ This approach can be triggered, but it requires the user to enable ActiveX. It
is embedded as a strategy in `writeFile` and used only if the shim script is
included in the page and the relevant features are enabled on the target system.
## Demo
#### Download
The included demo starts from an array of arrays, generating an editable HTML
table with `aoa_to_sheet` and adding it to the page:
@ -67,4 +114,20 @@ Downloadify.create(element_id, {
});
```
The demo also includes an HTML file input element for updating the data table:
```js
var ws = wb.Sheets[wb.SheetNames[0]];
var html_string = XLSX.utils.sheet_to_html(ws, { id: "table", editable: true });
document.getElementById("container").innerHTML = html_string;
```
The specific strategy is determined based on the presence of `IE_LoadFile`:
```js
var handler = typeof IE_LoadFile !== 'undefined' ? handle_ie : handle_fr;
if(input_dom_element.attachEvent) input_dom_element.attachEvent('onchange', handler);
else input_dom_element.addEventListener('change', handler, false);
```
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -3,7 +3,7 @@
<!-- vim: set ts=2: -->
<html>
<head>
<title>SheetJS JS-XLSX In-Browser HTML Table Export Demo</title>
<title>SheetJS JS-XLSX In-Browser HTML Table Demo</title>
<meta charset="utf-8" />
<style>
.xport, .btn {
@ -36,12 +36,15 @@ function doit(type, fn, dl) {
}
</script>
<pre>
<h3><a href="//sheetjs.com/">SheetJS</a> JS-XLSX In-Browser HTML Table Export Demo</h3>
<h3><a href="//sheetjs.com/">SheetJS</a> JS-XLSX In-Browser HTML Table Demo</h3>
<b>Compatibility notes:</b>
- Editable table leverages the HTML5 contenteditable feature, supported in most browsers.
- IE6-9 requires ActiveX or Flash to download files.
- IE6-9 requires ActiveX to upload files and ActiveX or Flash to download files.
- iOS Safari file download may not work. <a href="http://git.io/ios_save">This is a known issue</a>.
<b>Update Spreadsheet:</b> (submit file to update table; file parsed in browser)
<input type="file" id="file" />
<b>Editable Data Table:</b> (click a cell to edit it)
</pre>
<div id="container"></div>
@ -83,6 +86,34 @@ document.getElementById("container").innerHTML = html_string;
</table>
<pre><b>Powered by the <a href="//sheetjs.com/opensource">community version of js-xlsx</a></b></pre>
<script type="text/javascript">
var input_dom_element = document.getElementById("file");
function process_wb(wb) {
var ws = wb.Sheets[wb.SheetNames[0]];
var html_string = XLSX.utils.sheet_to_html(ws, { id: "data-table", editable: true });
document.getElementById("container").innerHTML = html_string;
}
function handle_ie() {
var path = input_dom_element.value;
var data = IE_LoadFile(path);
var wb = XLSX.read(data, {type:'binary'});
process_wb(wb);
}
function handle_fr(e) {
var files = e.target.files, f = files[0];
var reader = new FileReader();
var rABS = !!reader.readAsBinaryString;
reader.onload = function(e) {
var data = e.target.result;
if(!rABS) data = new Uint8Array(data);
var wb = XLSX.read(data, {type: rABS ? 'binary' : 'array'});
process_wb(wb);
};
if(rABS) reader.readAsBinaryString(f); else reader.readAsArrayBuffer(f);
}
var handler = typeof IE_LoadFile !== 'undefined' ? handle_ie : handle_fr;
if(input_dom_element.attachEvent) input_dom_element.attachEvent('onchange', handler);
else input_dom_element.addEventListener('change', handler, false);
function tableau(pid, iid, fmt, ofile) {
if(typeof Downloadify !== 'undefined') Downloadify.create(pid,{
swf: 'downloadify.swf',

2
dist/shim.min.js generated vendored

File diff suppressed because one or more lines are too long

30
dist/xlsx.core.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.core.min.map generated vendored

File diff suppressed because one or more lines are too long

775
dist/xlsx.extendscript.js generated vendored

File diff suppressed because it is too large Load Diff

32
dist/xlsx.full.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.full.min.map generated vendored

File diff suppressed because one or more lines are too long

760
dist/xlsx.js generated vendored

File diff suppressed because it is too large Load Diff

24
dist/xlsx.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map generated vendored

File diff suppressed because one or more lines are too long

@ -131,6 +131,8 @@ function handleFile(e) {
input_dom_element.addEventListener('change', handleFile, false);
```
The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
</details>
More specialized cases, including mobile app file processing, are covered in the

@ -1,10 +1,12 @@
### Cell Object
Cell objects are plain JS objects with keys and values following the convention:
| 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 |
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
| `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) |

@ -1,10 +1,17 @@
#### Data Types
The raw value is stored in the `v` field, interpreted based on the `t` field.
The raw value is stored in the `v` value property, interpreted based on the `t`
type property. This separation allows for representation of numbers as well as
numeric text. There are 6 valid cell types:
Type `b` is the Boolean type. `v` is interpreted according to JS truth tables.
Type `e` is the Error type. `v` holds the number and `w` holds the common name:
| Type | Description |
| :--: | :-------------------------------------------------------------------- |
| `b` | Boolean: value interpreted as JS `boolean` |
| `e` | Error: value is a numeric code and `w` property stores common name ** |
| `n` | Number: value is a JS `number` ** |
| `d` | Date: value is a JS `Date` object or string to be parsed as Date ** |
| `s` | Text: value interpreted as JS `string` and written as text ** |
| `z` | Stub: blank stub cell that is ignored by data processing utilities ** |
<details>
<summary><b>Error values and interpretation</b> (click to show)</summary>
@ -33,14 +40,17 @@ Since JSON does not have a natural Date type, parsers are generally expected to
store ISO 8601 Date strings like you would get from `date.toISOString()`. On
the other hand, writers and exporters should be able to handle date strings and
JS Date objects. Note that Excel disregards timezone modifiers and treats all
dates in the local timezone. js-xlsx does not correct for this error.
dates in the local timezone. The library does not correct for this error.
Type `s` is the String type. `v` should be explicitly stored as a string to
avoid possible confusion.
Type `s` is the String type. Values are explicitly stored as text. Excel will
interpret these cells as "number stored as text". Generated Excel files
automatically suppress that class of error, but other formats may elicit errors.
Type `z` represents blank stub cells. They are generated in cases where cells
have no assigned value but hold comments or other metadata. They are ignored by
the core library data processing utility functions. By default these cells are
not generated; the parser `sheetStubs` option must be set to `true`.
Type `z` represents blank stub cells. These do not have any data or type, and
are not processed by any of the core library functions. By default these cells
will not be generated; the parser `sheetStubs` option must be set to `true`.
#### Dates

@ -398,6 +398,8 @@ function handleFile(e) {
input_dom_element.addEventListener('change', handleFile, false);
```
The [`oldie` demo](demos/oldie/) shows an IE-compatible fallback scenario.
More specialized cases, including mobile app file processing, are covered in the
[included demos](demos/)
@ -777,11 +779,13 @@ for(var R = range.s.r; R <= range.e.r; ++R) {
### Cell Object
Cell objects are plain JS objects with keys and values following the convention:
| 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 |
| `t` | type: `b` Boolean, `e` Error, `n` Number, `d` Date, `s` Text, `z` Stub |
| `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) |
@ -801,11 +805,18 @@ 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.
The raw value is stored in the `v` value property, interpreted based on the `t`
type property. This separation allows for representation of numbers as well as
numeric text. There are 6 valid cell types:
Type `b` is the Boolean type. `v` is interpreted according to JS truth tables.
Type `e` is the Error type. `v` holds the number and `w` holds the common name:
| Type | Description |
| :--: | :-------------------------------------------------------------------- |
| `b` | Boolean: value interpreted as JS `boolean` |
| `e` | Error: value is a numeric code and `w` property stores common name ** |
| `n` | Number: value is a JS `number` ** |
| `d` | Date: value is a JS `Date` object or string to be parsed as Date ** |
| `s` | Text: value interpreted as JS `string` and written as text ** |
| `z` | Stub: blank stub cell that is ignored by data processing utilities ** |
| Value | Error Meaning |
@ -831,14 +842,17 @@ Since JSON does not have a natural Date type, parsers are generally expected to
store ISO 8601 Date strings like you would get from `date.toISOString()`. On
the other hand, writers and exporters should be able to handle date strings and
JS Date objects. Note that Excel disregards timezone modifiers and treats all
dates in the local timezone. js-xlsx does not correct for this error.
dates in the local timezone. The library does not correct for this error.
Type `s` is the String type. `v` should be explicitly stored as a string to
avoid possible confusion.
Type `s` is the String type. Values are explicitly stored as text. Excel will
interpret these cells as "number stored as text". Generated Excel files
automatically suppress that class of error, but other formats may elicit errors.
Type `z` represents blank stub cells. They are generated in cases where cells
have no assigned value but hold comments or other metadata. They are ignored by
the core library data processing utility functions. By default these cells are
not generated; the parser `sheetStubs` option must be set to `true`.
Type `z` represents blank stub cells. These do not have any data or type, and
are not processed by any of the core library functions. By default these cells
will not be generated; the parser `sheetStubs` option must be set to `true`.
#### Dates

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.12.0",
"version": "0.12.1",
"author": "sheetjs",
"description": "SheetJS Spreadsheet data parser and writer",
"keywords": [
@ -31,7 +31,7 @@
},
"dependencies": {
"adler-32": "~1.2.0",
"cfb": "~1.0.2",
"cfb": "~1.0.3",
"codepage": "~1.12.0",
"commander": "~2.13.0",
"crc-32": "~1.2.0",

15
shim.js

@ -368,3 +368,18 @@ var IE_SaveFile = (function() { try {
}
return function(data, filename) { return IE_SaveFile_Impl(IE_GetPath(filename), fix_data(data)); };
} catch(e) { return void 0; }})();
var IE_LoadFile = (function() { try {
if(typeof IE_LoadFile_Impl == "undefined") document.write([
'<script type="text/vbscript" language="vbscript">',
'Function IE_LoadFile_Impl(FileName): Dim out(), plen, i, cc: Set fso = CreateObject("Scripting.FileSystemObject"): Set f = fso.GetFile(FileName): Set stream = f.OpenAsTextStream(1, 0): plen = f.Size: ReDim out(plen): For i = 1 To plen Step 1: cc = Hex(Asc(stream.read(1))): If Len(cc) < 2 Then: cc = "0" & cc: End If: out(i) = cc: Next: IE_LoadFile_Impl = Join(out,""): End Function',
'|/script>'.replace("|","<")
].join("\r\n"));
if(typeof IE_LoadFile_Impl == "undefined") return void 0;
function fix_data(data) {
var out = [];
for(var i = 0; i < data.length; i+=2) out.push(String.fromCharCode(parseInt(data.slice(i, i+2), 16)));
var o = out.join("");
return o;
}
return function(filename) { return fix_data(IE_LoadFile_Impl(filename)); };
} catch(e) { return void 0; }})();

@ -39,9 +39,6 @@
<script src="fs_.js"></script>
<script src="fixtures.js"></script>
<script src="xlsx.full.min.js"></script>
<!--[if IE]>
<script type="text/javascript" src="xhr-hack.js"></script>
<![endif]-->
<div id="mocha"></div>
<script src="mocha.js"></script>
<script>

@ -39,9 +39,6 @@
<script src="fs_.js"></script>
<script src="fixtures.js"></script>
<script src="xlsx.full.min.js"></script>
<!--[if IE]>
<script type="text/javascript" src="xhr-hack.js"></script>
<![endif]-->
<div id="mocha"></div>
<script src="sauce-client.js"></script>
<script src="mocha.js"></script>

@ -1,17 +0,0 @@
var IEBinaryToArray_ByteStr_Script =
"<!-- IEBinaryToArray_ByteStr -->\r\n"+
"<script type='text/vbscript'>\r\n"+
"Function IEBinaryToArray_ByteStr(Binary) : IEBinaryToArray_ByteStr = CStr(Binary) : End Function\r\n"+
"Function IEBinaryToArray_ByteStr_Last(Binary)\r\n"+
" Dim lastIndex\r\n"+
" lastIndex = LenB(Binary)\r\n"+
" if lastIndex mod 2 Then\r\n"+
" IEBinaryToArray_ByteStr_Last = Chr( AscB( MidB( Binary, lastIndex, 1 ) ) )\r\n"+
" Else\r\n"+
" IEBinaryToArray_ByteStr_Last = "+'""'+"\r\n"+
" End If\r\n"+
"End Function\r\n"+
"</script>\r\n";
document.write(IEBinaryToArray_ByteStr_Script);

3
types/index.d.ts vendored

@ -1,5 +1,6 @@
/* index.d.ts (C) 2015-present SheetJS and contributors */
// TypeScript Version: 2.2
import * as CFB from "cfb";
/** Version string */
export const version: string;
@ -8,7 +9,7 @@ export const version: string;
export const SSF: any;
/** CFB Library */
export const CFB: any;
export { CFB };
/** NODE ONLY! Attempts to read filename and parse */
export function readFile(filename: string, opts?: ParsingOptions): WorkBook;

@ -48,3 +48,9 @@ const newwb = XLSX.utils.book_new();
XLSX.utils.book_append_sheet(newwb, aoa2, "AOA");
XLSX.utils.book_append_sheet(newwb, js2ws, "JSON");
const bstrxlsx: string = XLSX.write(newwb, {type: "binary", bookType: "xlsx" });
const CFB = XLSX.CFB;
const vbawb = XLSX.readFile("test.xlsm", {bookVBA:true});
if(vbawb.vbaraw) {
const cfb: XLSX.CFB.CFB$Container = CFB.read(vbawb.vbaraw, {type: "buffer"});
}

File diff suppressed because it is too large Load Diff

760
xlsx.js generated

File diff suppressed because it is too large Load Diff