version bump 0.11.6: ancillary format update

- BIFF5 XLS write (bookType "biff5")
- DBF Level 7 read
- ODS whitespace and repeated rows
- flow and lint cleanup
This commit is contained in:
SheetJS 2017-10-16 20:14:32 -04:00
parent ef9f3f9ca5
commit f968dfe4ed
63 changed files with 2867 additions and 2261 deletions

@ -2,7 +2,6 @@
.*/node_modules/.*
.*/dist/.*
.*/tmp/.*
.*/test.js
.*/bits/.*
.*/ctest/.*
@ -25,6 +24,7 @@ xlsxworker.flow.js
xlsx.flow.js
.*/bin/.*.njs
.*/demo/browser.flow.js
test.js
[libs]
bits/09_types.js

1
.gitignore vendored

@ -27,3 +27,4 @@ tmp
*.html
*.sheetjs
*.exe
*.img

@ -29,6 +29,7 @@ tmp
*.html
*.sheetjs
*.exe
*.img
.gitignore
.fossaignore
.spelling

@ -70,6 +70,8 @@ filesystem
javascript
metadata
natively
pre-built
pre-generated
prepend
prepended
repo

@ -4,6 +4,10 @@ This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code.
## 0.11.6 (2017-10-16)
* Semicolon-delimited files are detected
## 0.11.5 (2017-09-30)
* Bower main script shifted to full version

@ -213,7 +213,7 @@ book: readme graph ## Update summary for documentation
<README.md grep -vE "(details|summary)>" > misc/docs/README.md
DEMOMDS=$(sort $(wildcard demos/*/README.md))
MDLINT=$(DEMODS) $(READEPS) demos/README.md
MDLINT=$(DEMOMDS) $(READEPS) demos/README.md
.PHONY: mdlint
mdlint: $(MDLINT) ## Check markdown documents
alex $^

@ -1565,8 +1565,9 @@ Plain text format guessing follows the priority order:
| XML | starts with `<` |
| RTF | starts with `{\rt` |
| DSV | starts with `/sep=.$/`, separator is the specified character |
| CSV | more unquoted `","` characters than `"\t"` chars in the first 1024 |
| TSV | one of the first 1024 characters is a tab char `"\t"` |
| DSV | more unquoted `";"` chars than `"\t"` or `","` in the first 1024 |
| TSV | more unquoted `"\t"` chars than `","` chars in the first 1024 |
| CSV | one of the first 1024 characters is a comma `","` |
| PRN | (default) |
- HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div`
@ -1629,6 +1630,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
| `biff8` | `.xls` | CFB | multi | Excel 97-2004 Workbook Format |
| `biff5` | `.xls` | CFB | multi | Excel 5.0/95 Workbook Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
@ -1638,7 +1640,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
| `html` | `.html` | none | single | HTML Document |
| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
| `rtf` | `.rtf` | none | single | Rich Text Format |
| `rtf` | `.rtf` | none | single | Rich Text Format (RTF) |
| `prn` | `.prn` | none | single | Lotus Formatted Text |
- `compression` only applies to formats with ZIP containers.
@ -1957,7 +1959,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Excel 2007+ Binary Format (XLSB BIFF12) | :o: | :o: |
| Excel 2003-2004 XML Format (XML "SpreadsheetML") | :o: | :o: |
| Excel 97-2004 (XLS BIFF8) | :o: | :o: |
| Excel 5.0/95 (XLS BIFF5) | :o: | |
| Excel 5.0/95 (XLS BIFF5) | :o: | :o: |
| Excel 4.0 (XLS/XLW BIFF4) | :o: | |
| Excel 3.0 (XLS BIFF3) | :o: | |
| Excel 2.0/2.1 (XLS BIFF2) | :o: | :o: |
@ -1976,7 +1978,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | :o: | |
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
| HTML Tables | :o: | :o: |
| RTF Tables | | :o: |
| Rich Text Format tables (RTF) | | :o: |
### Excel 2007+ XML (XLSX/XLSM)

@ -21,7 +21,7 @@ program
.option('-X, --xlsx', 'emit XLSX to <sheetname> or <file>.xlsx')
.option('-Y, --ods', 'emit ODS to <sheetname> or <file>.ods')
.option('-8, --xls', 'emit XLS to <sheetname> or <file>.xls (BIFF8)')
//.option('-5, --biff5','emit XLS to <sheetname> or <file>.xls (BIFF5)')
.option('-5, --biff5','emit XLS to <sheetname> or <file>.xls (BIFF5)')
//.option('-4, --biff4','emit XLS to <sheetname> or <file>.xls (BIFF4)')
//.option('-3, --biff3','emit XLS to <sheetname> or <file>.xls (BIFF3)')
.option('-2, --biff2','emit XLS to <sheetname> or <file>.xls (BIFF2)')
@ -44,11 +44,10 @@ program
.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)')
.option('--sst', 'generate shared string table for XLS* formats')
.option('--compress', 'use compression when writing XLSX/M/B and ODS')
.option('--read-only', 'do not generate output')
.option('--read', 'read but do not generate output')
.option('--all', 'parse everything; write as much as possible')
.option('--dev', 'development mode')
.option('--sparse', 'sparse mode')
.option('--read', 'read but do not print out contents')
.option('-q, --quiet', 'quiet mode');
program.on('--help', function() {
@ -176,9 +175,8 @@ try {
process.exit(4);
}
if(program.readOnly) process.exit(0);
/* single worksheet formats */
/* single worksheet file formats */
[
['biff2', '.xls'],
['biff3', '.xls'],

@ -1,7 +1,5 @@
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true, loopfunc:true */
/*exported XLSX */
/*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {};

@ -1 +1 @@
XLSX.version = '0.11.5';
XLSX.version = '0.11.6';

@ -28,14 +28,14 @@ var debom = function(data/*:string*/)/*:string*/ {
return data;
};
var _getchar = function _gc1(x) { return String.fromCharCode(x); };
var _getchar = function _gc1(x/*:number*/)/*:string*/ { return String.fromCharCode(x); };
if(typeof cptable !== 'undefined') {
set_cp = function(cp) { current_codepage = cp; };
debom = function(data) {
set_cp = function(cp/*:number*/) { current_codepage = cp; };
debom = function(data/*:string*/) {
if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.substr(2))); }
return data;
};
_getchar = function _gc2(x) {
_getchar = function _gc2(x/*:number*/)/*:string*/ {
if(current_codepage === 1200) return String.fromCharCode(x);
return cptable.utils.decode(current_codepage, [x&255,x>>8])[0];
};

@ -102,7 +102,7 @@ var utf8read/*:StringConv*/ = function utf8reada(orig) {
};
var utf8write/*:StringConv*/ = function(orig) {
var out = [], i = 0, c = 0, d = 0;
var out/*:Array<string>*/ = [], i = 0, c = 0, d = 0;
while(i < orig.length) {
c = orig.charCodeAt(i++);
switch(true) {
@ -197,7 +197,7 @@ function writextag(f,g,h) { return '<' + f + (isval(h) /*:: && h */? wxt_helper(
function write_w3cdtf(d/*:Date*/, t/*:?boolean*/)/*:string*/ { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
function write_vt(s) {
function write_vt(s)/*:string*/ {
switch(typeof s) {
case 'string': return writextag('vt:lpwstr', s);
case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));

@ -74,6 +74,7 @@ var __readUInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/
var __readInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { var u = b[idx+1]*(1<<8)+b[idx]; return (u < 0x8000) ? u : (0xffff - u + 1) * -1; };
var __readUInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
var __readInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
var __readInt32BE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
var ___unhexlify = function(s/*:string*/)/*:Array<number>*/ { return (s.match(/../g)||[]).map(function(x) { return parseInt(x,16);}); };
var __unhexlify = typeof Buffer !== "undefined" ? function(s/*:string*/)/*:Array<number>|Buffer*/ { return Buffer.isBuffer(s) ? new Buffer(s, 'hex') : ___unhexlify(s); } : ___unhexlify;
@ -141,10 +142,15 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
switch(size) {
case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
case 4:
if(t === 'i' || (this[this.l+3] & 0x80)===0) { oI = __readInt32LE(this, this.l); this.l += 4; return oI; }
case 4: case -4:
if(t === 'i' || (this[this.l+3] & 0x80)===0) { oI = (size > 0 ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
case 8: if(t === 'f') { oR = __double(this, this.l); this.l += 8; return oR; }
case 8: case -8:
if(t === 'f') {
if(size == 8) oR = __double(this, this.l);
else oR = __double([this[this.l+7],this[this.l+6],this[this.l+5],this[this.l+4],this[this.l+3],this[this.l+2],this[this.l+1],this[this.l+0]], 0);
this.l += 8; return oR;
} else size = 8;
/* falls through */
case 16: o = __hexlify(this, this.l, size); break;
}}
@ -162,6 +168,9 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/
for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
size = 2 * val.length;
} else if(f === 'sbcs') {
/* TODO: codepage */
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
val = val.replace(/[^\x00-\x7F]/g, "_");
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
for(i = 0; i != val.length; ++i) this[this.l + i] = val.charCodeAt(i) & 0xFF;
size = val.length;

@ -1,45 +1,43 @@
/* [MS-OLEPS] 2.2 PropertyType */
{
//var VT_EMPTY = 0x0000;
//var VT_NULL = 0x0001;
var VT_I2 = 0x0002;
var VT_I4 = 0x0003;
//var VT_R4 = 0x0004;
//var VT_R8 = 0x0005;
//var VT_CY = 0x0006;
//var VT_DATE = 0x0007;
//var VT_BSTR = 0x0008;
//var VT_ERROR = 0x000A;
var VT_BOOL = 0x000B;
var VT_VARIANT = 0x000C;
//var VT_DECIMAL = 0x000E;
//var VT_I1 = 0x0010;
//var VT_UI1 = 0x0011;
//var VT_UI2 = 0x0012;
var VT_UI4 = 0x0013;
//var VT_I8 = 0x0014;
var VT_UI8 = 0x0015;
//var VT_INT = 0x0016;
//var VT_UINT = 0x0017;
var VT_LPSTR = 0x001E;
//var VT_LPWSTR = 0x001F;
var VT_FILETIME = 0x0040;
//var VT_BLOB = 0x0041;
//var VT_STREAM = 0x0042;
//var VT_STORAGE = 0x0043;
//var VT_STREAMED_Object = 0x0044;
//var VT_STORED_Object = 0x0045;
//var VT_BLOB_Object = 0x0046;
var VT_CF = 0x0047;
//var VT_CLSID = 0x0048;
//var VT_VERSIONED_STREAM = 0x0049;
var VT_VECTOR = 0x1000;
//var VT_ARRAY = 0x2000;
//var VT_EMPTY = 0x0000;
//var VT_NULL = 0x0001;
var VT_I2 = 0x0002;
var VT_I4 = 0x0003;
//var VT_R4 = 0x0004;
//var VT_R8 = 0x0005;
//var VT_CY = 0x0006;
//var VT_DATE = 0x0007;
//var VT_BSTR = 0x0008;
//var VT_ERROR = 0x000A;
var VT_BOOL = 0x000B;
var VT_VARIANT = 0x000C;
//var VT_DECIMAL = 0x000E;
//var VT_I1 = 0x0010;
//var VT_UI1 = 0x0011;
//var VT_UI2 = 0x0012;
var VT_UI4 = 0x0013;
//var VT_I8 = 0x0014;
var VT_UI8 = 0x0015;
//var VT_INT = 0x0016;
//var VT_UINT = 0x0017;
var VT_LPSTR = 0x001E;
//var VT_LPWSTR = 0x001F;
var VT_FILETIME = 0x0040;
//var VT_BLOB = 0x0041;
//var VT_STREAM = 0x0042;
//var VT_STORAGE = 0x0043;
//var VT_STREAMED_Object = 0x0044;
//var VT_STORED_Object = 0x0045;
//var VT_BLOB_Object = 0x0046;
var VT_CF = 0x0047;
//var VT_CLSID = 0x0048;
//var VT_VERSIONED_STREAM = 0x0049;
var VT_VECTOR = 0x1000;
//var VT_ARRAY = 0x2000;
var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
var VT_CUSTOM = [VT_STRING, VT_USTR];
}
var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
var VT_CUSTOM = [VT_STRING, VT_USTR];
/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
var DocSummaryPIDDSI = {

@ -56,9 +56,9 @@ function write_rdf(rdf, opts) {
return o.join("");
}
/* TODO: pull properties */
var write_meta_ods/*:{(wb:any, opts:any):string}*/ = (function() {
var write_meta_ods/*:{(wb:Workbook, opts:any):string}*/ = (function() {
var payload = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>';
return function wmo(wb, opts) {
return function wmo(wb/*:Workbook*/, opts) {
return payload;
};
})();

@ -108,7 +108,7 @@ function parse_VtVector(blob, cb) {
}
/* [MS-OLEPS] 2.15 TypedPropertyValue */
function parse_TypedPropertyValue(blob, type/*:number*/, _opts) {
function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
var t = blob.read_shift(2), ret, opts = _opts||{};
blob.l += 2;
if(type !== VT_VARIANT)
@ -193,12 +193,12 @@ function parse_PropertySet(blob, PIDSI) {
case 1252:
case 65000: case -536:
case 65001: case -535:
set_cp(CodePage = PropH[piddsi.n]>>>0 & 0xFFFF); break;
set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
}
} else {
if(Props[i][0] === 0x1) {
CodePage = PropH.CodePage = parse_TypedPropertyValue(blob, VT_I2);
CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2)/*:number*/);
set_cp(CodePage);
if(Dictionary !== -1) {
var oldpos = blob.l;

@ -201,7 +201,8 @@ function parse_WriteAccess(blob, length, opts) {
return UserName;
}
function write_WriteAccess(s/*:string*/, opts) {
var o = new_buf(112);
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);
o.write_shift(4, 0x33336853);
@ -226,14 +227,15 @@ function parse_BoundSheet8(blob, length, opts) {
return { pos:pos, hs:hidden, dt:dt, name:name };
}
function write_BoundSheet8(data, opts) {
var o = new_buf(8 + 2 * data.name.length);
var w = (!opts || opts.biff >= 8 ? 2 : 1);
var o = new_buf(8 + w * data.name.length);
o.write_shift(4, data.pos);
o.write_shift(1, data.hs || 0);
o.write_shift(1, data.dt);
o.write_shift(1, data.name.length);
o.write_shift(1, 1);
o.write_shift(2 * data.name.length, data.name, 'utf16le');
return o;
if(opts.biff >= 8) o.write_shift(1, 1);
o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
return o.slice(0, o.l);
}
/* 2.4.265 TODO */
@ -362,11 +364,12 @@ function parse_Label(blob, length, opts) {
return cell;
}
function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, opts) {
var o = new_buf(6 + 3 + 2 * v.length);
var b8 = !opts || opts.biff == 8;
var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
write_XLSCell(R, C, 0, o);
o.write_shift(2, v.length);
o.write_shift(1, 1);
o.write_shift(2 * v.length, v, 'utf16le');
if(b8) o.write_shift(1, 1);
o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
return o;
}
@ -389,9 +392,10 @@ function parse_Dimensions(blob, length, opts) {
return {s: {r:r, c:c}, e: {r:R, c:C}};
}
function write_Dimensions(range, opts) {
var o = new_buf(14);
o.write_shift(4, range.s.r);
o.write_shift(4, range.e.r + 1);
var w = opts.biff == 8 || !opts.biff ? 4 : 2;
var o = new_buf(2*w + 6);
o.write_shift(w, range.s.r);
o.write_shift(w, range.e.r + 1);
o.write_shift(2, range.s.c);
o.write_shift(2, range.e.c + 1);
o.write_shift(2, 0);
@ -598,7 +602,7 @@ function parse_Lbl(blob, length, opts) {
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
var rgce = target == blob.l || cce == 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
var rgce = target == blob.l || cce === 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
return {
chKey: chKey,
Name: name,

@ -55,13 +55,14 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
/* header */
var ft = d.read_shift(1);
var memo = false;
var vfp = false;
var vfp = false, l7 = false;
switch(ft) {
case 0x02: case 0x03: break;
case 0x30: vfp = true; memo = true; break;
case 0x31: vfp = true; break;
case 0x83: memo = true; break;
case 0x8B: memo = true; break;
case 0x8C: memo = true; l7 = true; break;
case 0xF5: memo = true; break;
default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
}
@ -84,36 +85,42 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
d.l+=2;
}
if(l7) d.l += 36;
var fields = [], field = {};
var hend = fpos - 10 - (vfp ? 264 : 0);
var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
field = {};
field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+10)).replace(/[\u0000\r\n].*$/g,"");
d.l += 11;
field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
d.l += ww;
field.type = String.fromCharCode(d.read_shift(1));
if(ft != 0x02) field.offset = d.read_shift(4);
if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
field.len = d.read_shift(1);
if(ft == 0x02) field.offset = d.read_shift(2);
field.dec = d.read_shift(1);
if(field.name.length) fields.push(field);
if(ft != 0x02) d.l += 14;
if(ft != 0x02) d.l += l7 ? 13 : 14;
switch(field.type) {
// case 'B': break; // Binary
case 'C': break; // character
case 'D': break; // date
case 'F': break; // floating point
// case 'G': break; // General
case 'I': break; // long
case 'L': break; // boolean
case 'M': break; // memo
case 'N': break; // number
// case 'O': break; // double
// case 'P': break; // Picture
case 'T': break; // datetime
case 'Y': break; // currency
case '0': break; // null ?
case '+': break; // autoincrement
case '@': break; // timestamp
case 'B': // VFP Double
if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
break;
case 'G': // General
case 'P': // Picture
if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
break;
case 'C': // character
case 'D': // date
case 'F': // floating point
case 'I': // long
case 'L': // boolean
case 'M': // memo
case 'N': // number
case 'O': // double
case 'T': // datetime
case 'Y': // currency
case '0': // VFP _NullFlags
case '@': // timestamp
case '+': // autoincrement
break;
default: throw new Error('Unknown Field Type: ' + field.type);
}
}
@ -145,7 +152,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
else out[R][C] = s;
break;
case 'F': out[R][C] = parseFloat(s.trim()); break;
case 'I': out[R][C] = dd.read_shift(4, 'i'); break;
case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
case 'L': switch(s.toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
@ -154,15 +161,16 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
} break;
case 'M': /* TODO: handle memo files */
if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
out[R][C] = "##MEMO##" + dd.read_shift(4);
out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
break;
case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
case 'T':
var day = dd.read_shift(4), ms = dd.read_shift(4);
throw new Error(day + " | " + ms);
//out[R][C] = new Date(); // TODO
//break;
case 'Y': out[R][C] = dd.read(4,'i')/1e4; break;
case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
/* falls through */
case 'G': case 'P': dd.l += fields[C].len; break;
case '0':
if(fields[C].name === '_NullFlags') break;
/* falls through */
@ -269,7 +277,7 @@ var SYLK = (function() {
cw = record[rj].substr(1).split(" ");
for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
Mval = parseInt(cw[2], 10);
colinfo[j-1] = Mval == 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
} break;
case 'C': /* default column format */
C = parseInt(record[rj].substr(1))-1;
@ -279,7 +287,7 @@ var SYLK = (function() {
R = parseInt(record[rj].substr(1))-1;
if(!rowinfo[R]) rowinfo[R] = {};
if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
else if(Mval == 0) rowinfo[R].hidden = true;
else if(Mval === 0) rowinfo[R].hidden = true;
break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
@ -514,16 +522,16 @@ var PRN = (function() {
// List of accepted CSV separators
var guess_seps = {
0x2C: ',',
0x09: "\t",
0x3B: ';'
/*::[*/0x2C/*::]*/: ',',
/*::[*/0x09/*::]*/: "\t",
/*::[*/0x3B/*::]*/: ';'
};
// CSV separator weights to be used in case of equal numbers
var guess_sep_weights = {
0x2C: 3,
0x09: 2,
0x3B: 1
/*::[*/0x2C/*::]*/: 3,
/*::[*/0x09/*::]*/: 2,
/*::[*/0x3B/*::]*/: 1
};
function guess_sep(str) {
@ -567,9 +575,9 @@ var PRN = (function() {
var s = str.slice(start, end);
var cell = ({}/*:any*/);
if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
if(s.length == 0) cell.t = 'z';
if(s.length === 0) cell.t = 'z';
else if(o.raw) { cell.t = 's'; cell.v = s; }
else if(s.trim().length == 0) { cell.t = 's'; cell.v = s; }
else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
else if(s.charCodeAt(0) == 0x3D) {
if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.substr(1); }
@ -642,7 +650,7 @@ var PRN = (function() {
if(!cell || cell.v == null) { oo.push(" "); continue; }
var w = (cell.w || (format_cell(cell), cell.w) || "").substr(0,10);
while(w.length < 10) w += " ";
oo.push(w + (C == 0 ? " " : ""));
oo.push(w + (C === 0 ? " " : ""));
}
o.push(oo.join(""));
}

@ -127,9 +127,9 @@ function parse_EncryptionVerifier(blob, length/*:number*/) {
function parse_EncryptionInfo(blob, length/*:?number*/) {
var vers = parse_CRYPTOVersion(blob);
switch(vers.Minor) {
case 0x02: return parse_EncInfoStd(blob, vers);
case 0x03: return parse_EncInfoExt(blob, vers);
case 0x04: return parse_EncInfoAgl(blob, vers);
case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
}
throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
}
@ -147,7 +147,10 @@ function parse_EncInfoStd(blob, vers) {
/* [MS-OFFCRYPTO] 2.3.4.6 EncryptionInfo Stream (Extensible Encryption) */
function parse_EncInfoExt(blob, vers) { throw new Error("File is password-protected: ECMA-376 Extensible"); }
/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
function parse_EncInfoAgl(blob, vers) { throw new Error("File is password-protected: ECMA-376 Agile"); }
function parse_EncInfoAgl(blob, vers) {
blob.l+=4;
return blob.read_shift(blob.length - blob.l, 'utf8');
}
@ -282,7 +285,7 @@ function parse_XORObfuscation(blob, length, opts, out) {
var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) }/*:any*/);
if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
out.valid = o.verificationBytes === o.verifier;
if(out.valid) out.insitu_decrypt = crypto_MakeXorDecryptor(opts.password);
if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
return o;
}

@ -53,6 +53,13 @@ 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 */
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 */
function parse_RgceLocRel(blob, length, opts) {
@ -446,6 +453,51 @@ var parse_PtgMemNoMem = parsenoop;
/* 2.5.198.92 */
var parse_PtgTbl = parsenoop;
function parse_PtgElfLoc(blob, length, opts) {
blob.l += 2;
return [parse_RgceElfLoc(blob, 4, opts)];
}
function parse_PtgElfNoop(blob, length, opts) {
blob.l += 6;
return [];
}
/* 2.5.198.46 */
var parse_PtgElfCol = parse_PtgElfLoc;
/* 2.5.198.47 */
var parse_PtgElfColS = parse_PtgElfNoop;
/* 2.5.198.48 */
var parse_PtgElfColSV = parse_PtgElfNoop;
/* 2.5.198.49 */
var parse_PtgElfColV = parse_PtgElfLoc;
/* 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 */
var parse_PtgElfRadical = parse_PtgElfLoc;
/* 2.5.198.52 */
var parse_PtgElfRadicalLel = parse_PtgElfLel;
/* 2.5.198.53 */
var parse_PtgElfRadicalS = parse_PtgElfNoop;
/* 2.5.198.54 */
var parse_PtgElfRw = parse_PtgElfLoc;
/* 2.5.198.55 */
var parse_PtgElfRwV = parse_PtgElfLoc;
/* [MS-XLSB] 2.5.97.52 */
function parse_PtgList(blob, length, opts) {
blob.l += 2;
var ixti = blob.read_shift(2);
blob.l += 10;
return {};
}
/* 2.5.198.91 */
function parse_PtgSxName(blob, length, opts) {
blob.l += 2;
return [blob.read_shift(4)];
}
/* 2.5.198.25 */
var PtgTypes = {
/*::[*/0x01/*::]*/: { n:'PtgExp', f:parse_PtgExp },
@ -521,8 +573,19 @@ var PtgDupes = {
(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
var Ptg18 = {
// /*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList }, // TODO
// /*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName }, // TODO
/*::[*/0x01/*::]*/: { n:'PtgElfLel', f:parse_PtgElfLel },
/*::[*/0x02/*::]*/: { n:'PtgElfRw', f:parse_PtgElfRw },
/*::[*/0x03/*::]*/: { n:'PtgElfCol', f:parse_PtgElfCol },
/*::[*/0x06/*::]*/: { n:'PtgElfRwV', f:parse_PtgElfRwV },
/*::[*/0x07/*::]*/: { n:'PtgElfColV', f:parse_PtgElfColV },
/*::[*/0x0A/*::]*/: { n:'PtgElfRadical', f:parse_PtgElfRadical },
/*::[*/0x0B/*::]*/: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
/*::[*/0x0D/*::]*/: { n:'PtgElfColS', f:parse_PtgElfColS },
/*::[*/0x0F/*::]*/: { n:'PtgElfColSV', f:parse_PtgElfColSV },
/*::[*/0x10/*::]*/: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
/*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList },
/*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName },
/*::[*/0xFF/*::]*/: {}
};
var Ptg19 = {
/*::[*/0x01/*::]*/: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
@ -536,36 +599,7 @@ var Ptg19 = {
/*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
/*::[*/0xFF/*::]*/: {}
};
/* 2.4.127 TODO */
function parse_Formula(blob, length, opts) {
var end = blob.l + length;
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) ++blob.l;
var val = parse_FormulaValue(blob,8);
var flags = blob.read_shift(1);
if(opts.biff != 2) {
blob.read_shift(1);
if(opts.biff >= 5) {
var chn = blob.read_shift(4);
}
}
var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
}
/* 2.5.133 TODO: how to emit empty strings? */
function parse_FormulaValue(blob/*::, length*/) {
var b;
if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
switch(blob[blob.l]) {
case 0x00: blob.l += 8; return ["String", 's'];
case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
case 0x03: blob.l += 8; return ["",'s'];
}
return [];
}
Ptg19[0x21] = Ptg19[0x20];
/* 2.5.198.103 */
function parse_RgbExtra(blob, length, rgce, opts) {
@ -587,6 +621,11 @@ function parse_RgbExtra(blob, length, rgce, opts) {
rgce[i][1][1] = blob.read_shift(4);
o.push(rgce[i][1]);
} break;
case 'PtgList': /* TODO: PtgList -> PtgExtraList */
case 'PtgElfRadicalS': /* TODO: PtgElfRadicalS -> PtgExtraElf */
case 'PtgElfColS': /* TODO: PtgElfColS -> PtgExtraElf */
case 'PtgElfColSV': /* TODO: PtgElfColSV -> PtgExtraElf */
throw "Unsupported " + rgce[i][0];
default: break;
}
}
@ -597,45 +636,6 @@ function parse_RgbExtra(blob, length, rgce, opts) {
return o;
}
/* 2.5.198.21 */
function parse_NameParsedFormula(blob, length, opts, cce) {
var target = blob.l + length;
var rgce = parse_Rgce(blob, cce, opts);
var rgcb;
if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.3 TODO */
function parse_XLSCellParsedFormula(blob, length, opts) {
var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
var rgcb, cce = blob.read_shift(len); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce, opts);
if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.118 TODO */
function parse_SharedParsedFormula(blob, length, opts) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
var rgce = parse_Rgce(blob, cce, opts);
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.1 TODO */
function parse_ArrayParsedFormula(blob, length, opts, ref) {
var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
var rgcb, cce = blob.read_shift(len); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce, opts);
if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.104 */
function parse_Rgce(blob, length, opts) {
var target = blob.l + length;
@ -655,7 +655,7 @@ function parse_Rgce(blob, length, opts) {
return ptgs;
}
function stringify_array(f)/*:string*/ {
function stringify_array(f/*:Array<Array<any>>*/)/*:string*/ {
var o = [];
for(var i = 0; i < f.length; ++i) {
var x = f[i], r = [];
@ -702,15 +702,12 @@ function get_ixti(supbooks, ixti/*:number*/, opts)/*:string*/ {
return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts));
}
function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, opts)/*:string*/ {
//console.log(formula);
var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
var stack/*:Array<string>*/ = [], e1, e2, type, c/*:CellAddress*/, ixti=0, nameidx=0, r, sname="";
if(!formula[0] || !formula[0][0]) return "";
var last_sp = -1, sp = "";
//console.log("--",cell,formula[0])
for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
var f = formula[0][ff];
//console.log("++",f, stack)
switch(f[0]) {
case 'PtgUminus': /* 2.5.198.93 */
stack.push("-" + stack.pop()); break;
@ -791,7 +788,6 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
case 'PtgFunc': /* 2.5.198.62 */
case 'PtgFuncVar': /* 2.5.198.63 */
//console.log(f[1]);
/* f[1] = [argc, func, type] */
var argc/*:number*/ = (f[1][0]/*:any*/), func/*:string*/ = (f[1][1]/*:any*/);
if(!argc) argc = 0;
@ -845,7 +841,6 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
/* f[1] = type, ixti, nameindex */
var bookidx/*:number*/ = (f[1][1]/*:any*/); nameidx = (f[1][2]/*:any*/); var externbook;
/* TODO: Properly handle missing values */
//console.log(bookidx, supbooks);
if(opts.biff <= 5) {
if(bookidx < 0) bookidx = -bookidx;
if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
@ -949,6 +944,27 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
case 'PtgMemFunc': /* 2.5.198.72 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 */
throw new Error("Unsupported ELFs");
case 'PtgAttrBaxcel': /* 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 */
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));
default: throw new Error('Unrecognized Formula Token: ' + String(f));
}
@ -976,9 +992,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push((_left ? sp : "") + stack.pop() + (_left ? "" : sp));
last_sp = -1;
}
//console.log("::",f, stack)
}
//console.log("--",stack);
if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
return stack[0];
}

@ -1,3 +1,72 @@
/* [MS-XLS] 2.5.198.1 TODO */
function parse_ArrayParsedFormula(blob, length, opts, ref) {
var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
var rgcb, cce = blob.read_shift(len); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce, opts);
if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
return [rgce, rgcb];
}
/* [MS-XLS] 2.5.198.3 TODO */
function parse_XLSCellParsedFormula(blob, length, opts) {
var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
var rgcb, cce = blob.read_shift(len); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce, opts);
if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
return [rgce, rgcb];
}
/* [MS-XLS] 2.5.198.21 */
function parse_NameParsedFormula(blob, length, opts, cce) {
var target = blob.l + length;
var rgce = parse_Rgce(blob, cce, opts);
var rgcb;
if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
return [rgce, rgcb];
}
/* [MS-XLS] 2.5.198.118 TODO */
function parse_SharedParsedFormula(blob, length, opts) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
var rgce = parse_Rgce(blob, cce, opts);
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
return [rgce, rgcb];
}
/* [MS-XLS] 2.5.133 TODO: how to emit empty strings? */
function parse_FormulaValue(blob/*::, length*/) {
var b;
if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
switch(blob[blob.l]) {
case 0x00: blob.l += 8; return ["String", 's'];
case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
case 0x03: blob.l += 8; return ["",'s'];
}
return [];
}
/* [MS-XLS] 2.4.127 TODO */
function parse_Formula(blob, length, opts) {
var end = blob.l + length;
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) ++blob.l;
var val = parse_FormulaValue(blob,8);
var flags = blob.read_shift(1);
if(opts.biff != 2) {
blob.read_shift(1);
if(opts.biff >= 5) {
var chn = blob.read_shift(4);
}
}
var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
}
/* XLSB Parsed Formula records have the same shape */
function parse_XLSBParsedFormula(data, length, opts) {
var end = data.l + length;

@ -81,7 +81,7 @@ function parse_ws_xml(data/*:?string*/, opts, rels, wb, themes, styles)/*:Worksh
}
function write_ws_xml_merges(merges) {
if(merges.length == 0) return "";
if(merges.length === 0) return "";
var o = '<mergeCells count="' + merges.length + '">';
for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
return o + '</mergeCells>';
@ -196,6 +196,7 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) {
case 'd':
if(opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
else {
cell = dup(cell);
cell.t = 'n';
vv = ''+(cell.v = datenum(parseDate(cell.v)));
}
@ -384,6 +385,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/, rels)/*:string*/ {
var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
var dense = Array.isArray(ws);
var params = ({r:rr}/*:any*/), row/*:RowInfo*/, height = -1;
for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(R = range.s.r; R <= range.e.r; ++R) {
r = [];
@ -395,11 +397,11 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
}
if(r.length > 0 || rows && rows[R]) {
var params = ({r:rr}/*:any*/);
params = ({r:rr}/*:any*/);
if(rows && rows[R]) {
var row = rows[R];
row = rows[R];
if(row.hidden) params.hidden = 1;
var height = -1;
height = -1;
if (row.hpx) height = px2pt(row.hpx);
else if (row.hpt) height = row.hpt;
if (height > -1) { params.ht = height; params.customHeight = 1; }

@ -261,7 +261,9 @@ function parse_BrtHLink(data, length, opts) {
var tooltip = parse_XLWideString(data);
var display = parse_XLWideString(data);
data.l = end;
return {rfx:rfx, relId:relId, loc:loc, Tooltip:tooltip, display:display};
var o = ({rfx:rfx, relId:relId, loc:loc, display:display}/*:any*/);
if(tooltip) o.Tooltip = tooltip;
return o;
}
function write_BrtHLink(l, rId, o) {
if(o == null) o = new_buf(50+4*l[1].Target.length);
@ -319,25 +321,16 @@ function write_BrtColInfo(C/*:number*/, col, o) {
}
/* [MS-XLSB] 2.4.672 BrtMargins */
function parse_BrtMargins(data, length, opts) {
return {
left: parse_Xnum(data, 8),
right: parse_Xnum(data, 8),
top: parse_Xnum(data, 8),
bottom: parse_Xnum(data, 8),
header: parse_Xnum(data, 8),
footer: parse_Xnum(data, 8)
};
var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
function parse_BrtMargins(data, length, opts)/*:Margins*/ {
var margins = ({}/*:any*/);
BrtMarginKeys.forEach(function(k) { margins[k] = parse_Xnum(data, 8); });
return margins;
}
function write_BrtMargins(margins, o) {
function write_BrtMargins(margins/*:Margins*/, o) {
if(o == null) o = new_buf(6*8);
default_margins(margins);
write_Xnum(margins.left, o);
write_Xnum(margins.right, o);
write_Xnum(margins.top, o);
write_Xnum(margins.bottom, o);
write_Xnum(margins.header, o);
write_Xnum(margins.footer, o);
BrtMarginKeys.forEach(function(k) { write_Xnum((margins/*:any*/)[k], o); });
return o;
}
@ -641,13 +634,13 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ {
/* TODO: something useful -- this is a stub */
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/) {
if(cell.v === undefined) return "";
var vv = ""; var olddate = null;
var vv = "";
switch(cell.t) {
case 'b': vv = cell.v ? "1" : "0"; break;
case 'd': // no BrtCellDate :(
cell = dup(cell);
cell.z = cell.z || SSF._table[14];
olddate = cell.v;
cell.v = datenum((cell.v/*:any*/)); cell.t = 'n';
cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
break;
/* falls through */
case 'n': case 'e': vv = ''+cell.v; break;
@ -673,7 +666,6 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
/* TODO: determine threshold for Real vs RK */
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
if(olddate) { cell.t = 'd'; cell.v = olddate; }
return;
case 'b':
o.t = "b";

@ -196,7 +196,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
var comments = [], comment = {};
var cstys = [], csty, seencol = false;
var arrayf = [];
var rowinfo = [], rowobj = {};
var rowinfo = [], rowobj = {}, cc = 0, rr = 0;
var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false} }/*:any*/), wsprops = {};