version bump 0.10.0: cleanup

- updated SSF to 0.9.2
- XLSB style records and number format writing
- CSV avoid parseFloat (fixes #646 h/t @jabbermarky)
- CSV recognize mac line ending (fixes #648 h/t @charlesread)
- BIFF2 format table refactored to align with SSF
- BIFF5 image data exposure
- SSF custom format auto table update (fixes #267 h/t @Fangmingdu)
- eslint more checks
- browser test timeout extended to 10 seconds
This commit is contained in:
SheetJS 2017-05-09 14:07:57 -04:00
parent 810c447bf9
commit a8736580a5
62 changed files with 3896 additions and 1733 deletions

@ -5,10 +5,12 @@
"ecmaVersion": 3,
},
"plugins": [ "html", "json" ],
"!extends": "eslint:recommended",
"rules": {
"no-use-before-define": [ 1, {
"functions":false, "classes":true, "variables":false
}],
"no-console": 0,
"no-bitwise": 0,
"curly": 0,
"comma-style": [ 2, "last" ],

110
README.md

@ -6,7 +6,8 @@ Emphasis on parsing and writing robustness, cross-format feature compatibility
with a unified JS representation, and ES3/ES5 browser compatibility back to IE6.
This is the community version. We also offer a pro version with performance
enhancements and additional features by request.
enhancements, additional features by request, and dedicated support.
[**Pro Version**](http://sheetjs.com/pro)
@ -18,17 +19,33 @@ enhancements and additional features by request.
[**Source Code**](http://git.io/xlsx)
[**Issues and Bug Reports**](https://github.com/sheetjs/js-xlsx/issues)
[**Other General Support Issues**](https://discourse.sheetjs.com)
[**File format support for known spreadsheet data formats:**](#file-formats)
![circo graph of format support](formats.png)
<details>
<summary>Graph Legend</summary>
<summary><b>Graph of supported formats</b> (click to show)</summary>
![circo graph of format support](formats.png)
![graph legend](legend.png)
</details>
[**Browser Test**](http://oss.sheetjs.com/js-xlsx/tests/)
[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
[![Build Status](https://travis-ci.org/SheetJS/js-xlsx.svg?branch=master)](https://travis-ci.org/SheetJS/js-xlsx)
[![Build Status](https://semaphoreci.com/api/v1/sheetjs/js-xlsx/branches/master/shields_badge.svg)](https://semaphoreci.com/sheetjs/js-xlsx)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-xlsx/master.svg)](https://coveralls.io/r/SheetJS/js-xlsx?branch=master)
[![Dependencies Status](https://david-dm.org/sheetjs/js-xlsx/status.svg)](https://david-dm.org/sheetjs/js-xlsx)
[![NPM Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
## Table of Contents
<details>
@ -40,6 +57,7 @@ enhancements and additional features by request.
* [JS Ecosystem Demos](#js-ecosystem-demos)
* [Optional Modules](#optional-modules)
* [ECMAScript 5 Compatibility](#ecmascript-5-compatibility)
- [Philosophy](#philosophy)
- [Parsing Workbooks](#parsing-workbooks)
* [Complete Examples](#complete-examples)
* [Note on Streaming Read](#note-on-streaming-read)
@ -114,7 +132,6 @@ enhancements and additional features by request.
* [Windows](#windows)
- [License](#license)
- [References](#references)
- [Badges](#badges)
<!-- tocstop -->
@ -122,18 +139,18 @@ enhancements and additional features by request.
## Installation
In the browser, just add a script tag:
```html
<script lang="javascript" src="dist/xlsx.full.min.js"></script>
```
With [npm](https://www.npmjs.org/package/xlsx):
```bash
$ npm install xlsx
```
In the browser:
```html
<script lang="javascript" src="dist/xlsx.core.min.js"></script>
```
With [bower](http://bower.io/search/?q=js-xlsx):
```bash
@ -194,6 +211,41 @@ To use the shim, add the shim before the script tag that loads xlsx.js:
<script type="text/javascript" src="/path/to/shim.js"></script>
```
## Philosophy
<details>
<summary><b>Philosophy</b> (click to show)</summary>
Prior to SheetJS, APIs for processing spreadsheet files were format-specific.
Third-party libraries either supported one format, or they involved a separate
set of classes for each supported file type. Even though XLSB was introduced in
Excel 2007, nothing outside of SheetJS or Excel supported the format.
To promote a format-agnostic view, js-xlsx starts from a pure-JS representation
that we call the ["Common Spreadsheet Format"](#common-spreadsheet-format).
Emphasizing a uniform object representation enables radical features like format
conversion (e.g. reading an XLSX template and saving as XLS) and circumvents the
"class trap". By abstracting the complexities of the various formats, tools
need not worry about the specific file type!
A simple object representation combined with careful coding practices enables
use cases in older browsers and in alternative environments like ExtendScript
and Web Workers. It is always tempting to use the latest and greatest features,
but they tend to require the latest versions of browsers, limiting usability.
Utility functions capture common use cases like generating JS objects or HTML.
Most simple operations should only require a few lines of code. More complex
operations generally should be straightforward to implement.
Excel pushes the XLSX format as default starting in Excel 2007. However, there
are other formats with more appealing properties. For example, the XLSB format
is spiritually similar to XLSX but files often tend up taking less than half the
space and open much faster! Even though an XLSX writer is available, other
format writers are available so users can take advantage of the unique
characteristics of each format.
</details>
## Parsing Workbooks
For parsing, the first step is to read the file. This involves acquiring the
@ -505,7 +557,6 @@ Utilities are available in the `XLSX.utils` object:
**Exporting:**
- `sheet_to_json` converts a worksheet object to an array of JSON objects.
`sheet_to_row_object_array` is an alias that will be removed in the future.
- `sheet_to_csv` generates delimiter-separated-values output.
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
@ -1008,17 +1059,14 @@ at index 164. The following example creates a custom format from scratch:
```js
var tbl = {};
XLSX.SSF.init_table(tbl); // <-- load builtin formats
tbl[164] = "\"T\"\ #0.00";
var wb = {
SSF: tbl,
SheetNames: ["Sheet1"],
Sheets: {
Sheet1: {
"!ref":"A1:C1",
A1: { t:"n", v:10000 }, // <-- General format
B1: { t:"n", v:10000, z: tbl[4] }, // <-- Builtin format
C1: { t:"n", v:10000, z: tbl[164] } // <-- Custom format
A1: { t:"n", v:10000 }, // <-- General format
B1: { t:"n", v:10000, z: "0%" }, // <-- Builtin format
C1: { t:"n", v:10000, z: "\"T\"\ #0.00" } // <-- Custom format
}
}
}
@ -1439,8 +1487,8 @@ the output will be encoded in codepage `1200` and the BOM will be prepended.
### JSON
`XLSX.utils.sheet_to_json` and the alias `XLSX.utils.sheet_to_row_object_array`
generate different types of JS objects. The function takes an options argument:
`XLSX.utils.sheet_to_json` generates different types of JS objects. The function
takes an options argument:
| Option Name | Default | Description |
| :---------- | :------: | :-------------------------------------------------- |
@ -1834,6 +1882,9 @@ $ open -a Chromium.app http://localhost:8000/stress.html
### Tested Environments
<details>
<summary>(click to show)</summary>
- NodeJS 0.8, 0.9, 0.10, 0.11, 0.12, 4.x, 5.x, 6.x, 7.x
- IE 6/7/8/9/10/11 (IE6-9 browsers require shims for interacting with client)
- Chrome 24+
@ -1847,6 +1898,8 @@ Tests utilize the mocha testing framework. Travis-CI and Sauce Labs links:
- <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS\* modules
- <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs
</details>
### Test Files
Test files are housed in [another repo](https://github.com/SheetJS/test_files).
@ -1980,20 +2033,3 @@ granted by the Apache 2.0 License are reserved by the Original Author.
- Worksheet File Format (From Lotus) December 1984
## Badges
[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
[![Build Status](https://travis-ci.org/SheetJS/js-xlsx.svg?branch=master)](https://travis-ci.org/SheetJS/js-xlsx)
[![Build Status](https://semaphoreci.com/api/v1/sheetjs/js-xlsx/branches/master/shields_badge.svg)](https://semaphoreci.com/sheetjs/js-xlsx)
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-xlsx/master.svg)](https://coveralls.io/r/SheetJS/js-xlsx?branch=master)
[![NPM Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
[![Dependencies Status](https://david-dm.org/sheetjs/js-xlsx/status.svg)](https://david-dm.org/sheetjs/js-xlsx)
[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,5 +1,6 @@
#!/usr/bin/env node
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* eslint-env node */
var n = "xlsx";
/* vim: set ts=2 ft=javascript: */
var X = require('../');
@ -176,9 +177,9 @@ var oo = "";
var strm = false;
if(!program.quiet) console.error(target_sheet);
if(program.formulae) oo = X.utils.get_formulae(ws).join("\n");
else if(program.json) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws));
else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true}));
else if(program.arrays) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true, header:1}));
else if(program.json) oo = JSON.stringify(X.utils.sheet_to_json(ws));
else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_json(ws,{raw:true}));
else if(program.arrays) oo = JSON.stringify(X.utils.sheet_to_json(ws,{raw:true, header:1}));
else {
strm = true;
var stream = X.stream.to_csv(ws, {FS:program.fieldSep, RS:program.rowSep});

@ -3,5 +3,6 @@
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true */
/*exported XLSX */
/*global exports, module, require:false, process:false, Buffer:false */
var XLSX = {};
(function make_xlsx(XLSX){

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

@ -1,8 +1,8 @@
var current_codepage = 1200, current_cptable;
var current_codepage = 1200;
/*:: declare var cptable:any; */
/*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
current_cptable = cptable[current_codepage];
}
function reset_cp() { set_cp(1200); }
var set_cp = function(cp) { current_codepage = cp; };
@ -18,7 +18,7 @@ var debom = function(data/*:string*/)/*:string*/ {
var _getchar = function _gc1(x) { return String.fromCharCode(x); };
if(typeof cptable !== 'undefined') {
set_cp = function(cp) { current_codepage = cp; current_cptable = cptable[cp]; };
set_cp = function(cp) { current_codepage = cp; };
debom = function(data) {
if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.substr(2))); }
return data;

@ -1,7 +1,7 @@
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input/*:string*/, utf8)/*:string*/ {
encode: function(input/*:string*/)/*:string*/ {
var o = "";
var c1, c2, c3, e1, e2, e3, e4;
for(var i = 0; i < input.length; ) {
@ -18,7 +18,7 @@ var Base64 = (function make_b64(){
}
return o;
},
decode: function b64_decode(input/*:string*/, utf8)/*:string*/ {
decode: function b64_decode(input/*:string*/)/*:string*/ {
var o = "";
var c1, c2, c3;
var e1, e2, e3, e4;

@ -2,7 +2,7 @@
/*jshint -W041 */
var SSF = {};
var make_ssf = function make_ssf(SSF){
SSF.version = '0.9.1';
SSF.version = '0.9.2';
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
@ -270,12 +270,14 @@ function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
var o/*:string*/;
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt.match(/^#+0.0E\+0$/)) {
if(val == 0) return "0.0E+0";
else if(val < 0) return "-" + write_num_exp(fmt, -val);
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
if(ee < 0) ee += period;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
if(o.indexOf("e") === -1) {
var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
var fakee = Math.floor(Math.log(val)*Math.LOG10E);
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else o += "E+" + (fakee - ee);
while(o.substr(0,2) === "0.") {
@ -353,7 +355,7 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if((r = fmt.match(/^(0*)\.(#*)$/))) {
return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
}
if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
}
@ -401,7 +403,12 @@ function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
}
switch(fmt) {
case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
case "###,###":
case "##,###":
case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
default:
}
throw new Error("unsupported format |" + fmt + "|");
@ -419,12 +426,14 @@ function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
var o/*:string*/;
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
if(fmt.match(/^#+0.0E\+0$/)) {
if(val == 0) return "0.0E+0";
else if(val < 0) return "-" + write_num_exp2(fmt, -val);
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
var ee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E)%period;
var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
if(ee < 0) ee += period;
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
if(!o.match(/[Ee]/)) {
var fakee = Math.floor(Math.log(Math.abs(val))*Math.LOG10E);
var fakee = Math.floor(Math.log(val)*Math.LOG10E);
if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
else o += "E+" + (fakee - ee);
o = o.replace(/\+-/,"-");
@ -446,7 +455,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
var o;
var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
if(fmt.match(/^[#?]+$/)) {
o = (""+val); if(val === 0) o = "";
@ -466,7 +475,7 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
if((r = fmt.match(/^(0*)\.(#*)$/))) {
return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
}
if((r = fmt.match(/^#,##0(\.?)$/))) return sign + commaify((""+aval));
if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
}
@ -482,12 +491,12 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
}
var oa = "";
if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
ri = Math.min(r[4].length,7);
ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
ff = frac(aval, Math.pow(10,ri)-1, false);
o = "" + sign;
oa = write_num("n", r[1], ff[1]);
oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
o += oa + r[2] + "/" + r[3];
o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
oa = rpad_(ff[2],ri);
if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
o += oa;
@ -513,8 +522,12 @@ function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string
return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
}
switch(fmt) {
case "###,###":
case "##,###":
case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
default:
if(fmt.slice(-3) == ".00") return write_num_int(type, fmt.slice(0,-3), val) + ".00";
if(fmt.slice(-2) == ".0") return write_num_int(type, fmt.slice(0,-2), val) + ".0";
}
throw new Error("unsupported format |" + fmt + "|");
}
@ -610,7 +623,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(v < 0) return "";
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
o = c; while(++i<fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
if(c === 'h') c = hr;
out[out.length] = {t:c, v:o}; lst = c; break;
case 'A':
@ -628,6 +641,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(o.match(abstime)) {
if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
out[out.length] = {t:'Z', v:o.toLowerCase()};
lst = o.charAt(1);
} else if(o.indexOf("$") > -1) {
o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
@ -641,7 +655,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
}
/* falls through */
case '0': case '#':
o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1 || c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1) o += c;
out[out.length] = {t:'n', v:o}; break;
case '?':
o = c; while(fmt.charAt(++i) === c) o+=c;
@ -705,7 +719,7 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
(c=out[jj].t) === "?" || c === "D" ||
(c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/') ||
out[i].t === '(' && (c === ' ' || c === 'n' || c === ')') ||
c === 't' && (out[jj].v === '/' || '$€'.indexOf(out[jj].v) > -1 || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?')
)) {
out[i].v += out[jj].v;
out[jj] = {v:"", t:";"}; ++jj;
@ -819,7 +833,6 @@ function choose_fmt(f/*:string*/, v) {
}
function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
if(o == null) o = {};
//fixopts(o != null ? o : (o=[]));
var sfmt = "";
switch(typeof fmt) {
case "string":

@ -53,6 +53,7 @@ function getzipstr(zip, file/*:string*/, safe/*:?boolean*/)/*:?string*/ {
var _fs, jszip;
/*:: declare var JSZip:any; */
/*global JSZip:true */
if(typeof JSZip !== 'undefined') jszip = JSZip;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {

@ -37,7 +37,7 @@ var encodings = {
'&amp;': '&'
};
var rencoding = evert(encodings);
var rencstr = "&<>'\"".split("");
//var rencstr = "&<>'\"".split("");
// TODO: CP remap (need to read file version to determine OS)
var unescapexml/*:StringConv*/ = (function() {

@ -33,5 +33,6 @@ var make_offcrypto = function(O, _crypto) {
};
};
/*:: declare var crypto:any; */
/*global crypto:true */
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);

@ -1,8 +1,31 @@
function write_UInt32LE(x/*:number*/, o) {
if(!o) o = new_buf(4);
o.write_shift(4, x);
return o;
}
/* [MS-XLSB] 2.5.168 */
function parse_XLWideString(data)/*:string*/ {
var cchCharacters = data.read_shift(4);
return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
}
function write_XLWideString(data/*:string*/, o) {
var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
o.write_shift(4, data.length);
if(data.length > 0) o.write_shift(0, data, 'dbcs');
return _null ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.5.143 */
function parse_StrRun(data, length/*:?number*/) {
return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
}
function write_StrRun(run, o) {
if(!o) o = new_buf(4);
o.write_shift(2, run.ich || 0);
o.write_shift(2, run.ifnt || 0);
return o;
}
/* [MS-XLSB] 2.1.7.121 */
function parse_RichStr(data, length/*:number*/)/*:XLString*/ {
@ -31,6 +54,17 @@ 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) */
var parse_BrtCommentText = parse_RichStr;
function write_BrtCommentText(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
/* TODO: formatted string */
var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
o.write_shift(1,1);
write_XLWideString(str.t, o);
o.write_shift(4,1);
write_StrRun({ich:0,ifnt:0}, o);
return _null ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.5.9 */
function parse_XLSBCell(data)/*:any*/ {
@ -65,18 +99,6 @@ function write_XLNullableWideString(data/*:string*/, o) {
return _null ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.5.168 */
function parse_XLWideString(data)/*:string*/ {
var cchCharacters = data.read_shift(4);
return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
}
function write_XLWideString(data/*:string*/, o) {
var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
o.write_shift(4, data.length);
if(data.length > 0) o.write_shift(0, data, 'dbcs');
return _null ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.5.165 */
var parse_XLNameWideString = parse_XLWideString;
var write_XLNameWideString = write_XLWideString;
@ -153,23 +175,75 @@ var RBErr = evert_num(BErr);
function parse_BrtColor(data, length/*:number*/) {
var out = {};
var d = data.read_shift(1);
out.fValidRGB = d & 1;
out.xColorType = d >>> 1;
out.index = data.read_shift(1);
out.nTintAndShade = data.read_shift(2, 'i');
out.bRed = data.read_shift(1);
out.bGreen = data.read_shift(1);
out.bBlue = data.read_shift(1);
out.bAlpha = data.read_shift(1);
var fValidRGB = d & 1;
var xColorType = d >>> 1;
var index = data.read_shift(1);
var nTS = data.read_shift(2, 'i');
var bR = data.read_shift(1);
var bG = data.read_shift(1);
var bB = data.read_shift(1);
var bAlpha = data.read_shift(1);
switch(xColorType) {
case 0: out.auto = 1; break;
case 1:
out.index = index;
var icv = XLSIcv[index];
/* automatic pseudo index 81 */
if(icv) out.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
break;
case 2:
/* if(!fValidRGB) throw new Error("invalid"); */
out.rgb = bR.toString(16) + bG.toString(16) + bB.toString(16);
break;
case 3: out.theme = index; break;
}
if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
return out;
}
function write_BrtColor(color, o) {
if(!o) o = new_buf(8);
if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
if(color.index) {
o.write_shift(1, 0x02);
o.write_shift(1, color.index);
} else if(color.theme) {
o.write_shift(1, 0x06);
o.write_shift(1, color.theme);
} else {
o.write_shift(1, 0x05);
o.write_shift(1, 0);
}
var nTS = color.tint || 0;
if(nTS > 0) nTS *= 32767;
else if(nTS < 0) nTS *= 32768;
o.write_shift(2, nTS);
if(!color.rgb) {
o.write_shift(2, 0);
o.write_shift(1, 0);
o.write_shift(1, 0);
} else {
var rgb = (color.rgb || 'FFFFFF');
o.write_shift(1, parseInt(rgb.substr(0,2),16));
o.write_shift(1, parseInt(rgb.substr(2,2),16));
o.write_shift(1, parseInt(rgb.substr(4,2),16));
o.write_shift(1, 0xFF);
}
return o;
}
/* [MS-XLSB] 2.5.52 */
function parse_FontFlags(data, length/*:number*/) {
function parse_FontFlags(data, length/*:number*/, opts) {
var d = data.read_shift(1);
data.l++;
var out = {
fItalic: d & 0x2,
fStrikeout: d & 0x8,
/* fBold: d & 0x01 */
fItalic: d & 0x02,
/* fUnderline: d & 0x04 */
fStrikeout: d & 0x08,
fOutline: d & 0x10,
fShadow: d & 0x20,
fCondense: d & 0x40,
@ -177,3 +251,17 @@ function parse_FontFlags(data, length/*:number*/) {
};
return out;
}
function write_FontFlags(font, o) {
if(!o) o = new_buf(2);
var grbit =
(font.italic ? 0x02 : 0) |
(font.strike ? 0x08 : 0) |
(font.outline ? 0x10 : 0) |
(font.shadow ? 0x20 : 0) |
(font.condense ? 0x40 : 0) |
(font.extend ? 0x80 : 0);
o.write_shift(1, grbit);
o.write_shift(1, 0);
return o;
}

@ -1,40 +1,40 @@
/* [MS-OLEPS] 2.2 PropertyType */
{
var VT_EMPTY = 0x0000;
var VT_NULL = 0x0001;
//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_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_DECIMAL = 0x000E;
//var VT_I1 = 0x0010;
//var VT_UI1 = 0x0011;
//var VT_UI2 = 0x0012;
var VT_UI4 = 0x0013;
var VT_I8 = 0x0014;
//var VT_I8 = 0x0014;
var VT_UI8 = 0x0015;
var VT_INT = 0x0016;
var VT_UINT = 0x0017;
//var VT_INT = 0x0016;
//var VT_UINT = 0x0017;
var VT_LPSTR = 0x001E;
var VT_LPWSTR = 0x001F;
//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_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_CLSID = 0x0048;
//var VT_VERSIONED_STREAM = 0x0049;
var VT_VECTOR = 0x1000;
var VT_ARRAY = 0x2000;
//var VT_ARRAY = 0x2000;
var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
@ -186,6 +186,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 */
var XLSIcv = rgbify([
/* Color Constants */
0x000000,
@ -197,7 +198,7 @@ var XLSIcv = rgbify([
0xFF00FF,
0x00FFFF,
/* Defaults */
/* Overridable Defaults */
0x000000,
0xFFFFFF,
0xFF0000,
@ -258,8 +259,24 @@ var XLSIcv = rgbify([
0x333399,
0x333333,
/* Sheet */
0xFFFFFF,
0x000000
/* Other entries to appease BIFF8/12 */
0xFFFFFF, /* 0x40 icvForeground ?? */
0x000000, /* 0x41 icvBackground ?? */
0x000000, /* 0x42 icvFrame ?? */
0x000000, /* 0x43 icv3D ?? */
0x000000, /* 0x44 icv3DText ?? */
0x000000, /* 0x45 icv3DHilite ?? */
0x000000, /* 0x46 icv3DShadow ?? */
0x000000, /* 0x47 icvHilite ?? */
0x000000, /* 0x48 icvCtlText ?? */
0x000000, /* 0x49 icvCtlScrl ?? */
0x000000, /* 0x4A icvCtlInv ?? */
0x000000, /* 0x4B icvCtlBody ?? */
0x000000, /* 0x4C icvCtlFrame ?? */
0x000000, /* 0x4D icvCtlFore ?? */
0x000000, /* 0x4E icvCtlBack ?? */
0x000000, /* 0x4F icvCtlNeutral */
0x000000, /* 0x50 icvInfoBk ?? */
0x000000 /* 0x51 icvInfoText ?? */
]);

@ -55,7 +55,7 @@ function write_rels(rels)/*:string*/ {
function add_rels(rels, rId, f, type, relobj)/*:number*/ {
if(!relobj) relobj = {};
if(!rels['!id']) rels['!id'] = {};
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){}
if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
relobj.Id = 'rId' + rId;
relobj.Type = type;
relobj.Target = f;

@ -39,7 +39,7 @@ function parse_cust_props(data/*:string*/, opts) {
default:
if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
}
} else if(x.substr(0,2) === "</") {
} else if(x.substr(0,2) === "</") {/* empty */
} else if(opts.WTF) throw new Error(x);
}
}

@ -174,28 +174,25 @@ function parse_PropertySet(blob, PIDSI) {
if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
case 0: PropH[piddsi.n] = 1252;
/* falls through */
case 10000: // OSX Roman
case 1252: // Windows Latin
case 874: // SB Windows Thai
case 1250: // SB Windows Central Europe
case 1251: // SB Windows Cyrillic
case 1253: // SB Windows Greek
case 1254: // SB Windows Turkish
case 1255: // SB Windows Hebrew
case 1256: // SB Windows Arabic
case 1257: // SB Windows Baltic
case 1258: // SB Windows Vietnam
case 932: // DB Windows Japanese Shift-JIS
case 936: // DB Windows Simplified Chinese GBK
case 949: // DB Windows Korean
case 950: // DB Windows Traditional Chinese Big5
case 1200: // UTF16LE
case 1201: // UTF16BE
case 65000: case -536: // UTF-7
case 65001: case -535: // UTF-8
case 874:
case 932:
case 936:
case 949:
case 950:
case 1250:
case 1251:
case 1253:
case 1254:
case 1255:
case 1256:
case 1257:
case 1258:
case 10000:
case 1200:
case 1201:
case 1252:
case 65000: case -536:
case 65001: case -535:
set_cp(CodePage = PropH[piddsi.n]); break;
default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
}
@ -262,7 +259,7 @@ function parse_PropertySetStream(file, PIDSI) {
if(NumSets === 1) return rval;
if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
var PSet1;
try { PSet1 = parse_PropertySet(blob, null); } catch(e) { }
try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
for(y in PSet1) rval[y] = PSet1[y];
rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
return rval;
@ -363,7 +360,7 @@ function parse_XLUnicodeString2(blob, length, opts) {
var parse_ControlInfo = parsenoop;
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
var parse_URLMoniker = function(blob, length) {
var parse_URLMoniker = function(blob/*, length, opts*/) {
var len = blob.read_shift(4), start = blob.l;
var extra = false;
if(len > 24) {

@ -21,7 +21,7 @@ function parse_frtHeader(blob) {
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
/* 2.5.158 */
var HIDEOBJENUM = ['SHOWALL', 'SHOWPLACEHOLDER', 'HIDEALL'];
//var HIDEOBJENUM = ['SHOWALL', 'SHOWPLACEHOLDER', 'HIDEALL'];
var parse_HideObjEnum = parseuint16;
/* 2.5.344 */
@ -99,35 +99,39 @@ function parse_FtCf(blob, length) {
}
/* 2.5.140 - 2.5.154 and friends */
function parse_FtSkip(blob, length) { blob.l += 2; blob.l += blob.read_shift(2); }
var FtTab = {
/*::[*/0x15/*::]*/: parse_FtCmo,
/*::[*/0x13/*::]*/: parsenoop, /* FtLbsData */
/*::[*/0x12/*::]*/: function(blob, length) { blob.l += 12; }, /* FtCblsData */
/*::[*/0x11/*::]*/: function(blob, length) { blob.l += 8; }, /* FtRboData */
/*::[*/0x10/*::]*/: parsenoop, /* FtEdoData */
/*::[*/0x0F/*::]*/: parsenoop, /* FtGboData */
/*::[*/0x0D/*::]*/: parse_FtNts, /* FtNts */
/*::[*/0x0C/*::]*/: function(blob, length) { blob.l += 24; }, /* FtSbs */
/*::[*/0x0B/*::]*/: function(blob, length) { blob.l += 10; }, /* FtRbo */
/*::[*/0x0A/*::]*/: function(blob, length) { blob.l += 16; }, /* FtCbls */
/*::[*/0x09/*::]*/: parsenoop, /* FtPictFmla */
/*::[*/0x08/*::]*/: function(blob, length) { blob.l += 6; }, /* FtPioGrbit */
/*::[*/0x07/*::]*/: parse_FtCf, /* FtCf */
/*::[*/0x06/*::]*/: function(blob, length) { blob.l += 6; }, /* FtGmo */
/*::[*/0x04/*::]*/: parsenoop, /* FtMacro */
/*::[*/0x00/*::]*/: function(blob, length) { blob.l += 4; } /* FtEnding */
/*::[*/0x00/*::]*/: parse_FtSkip, /* FtEnd */
/*::[*/0x04/*::]*/: parse_FtSkip, /* FtMacro */
/*::[*/0x05/*::]*/: parse_FtSkip, /* FtButton */
/*::[*/0x06/*::]*/: parse_FtSkip, /* FtGmo */
/*::[*/0x07/*::]*/: parse_FtCf, /* FtCf */
/*::[*/0x08/*::]*/: parse_FtSkip, /* FtPioGrbit */
/*::[*/0x09/*::]*/: parse_FtSkip, /* FtPictFmla */
/*::[*/0x0A/*::]*/: parse_FtSkip, /* FtCbls */
/*::[*/0x0B/*::]*/: parse_FtSkip, /* FtRbo */
/*::[*/0x0C/*::]*/: parse_FtSkip, /* FtSbs */
/*::[*/0x0D/*::]*/: parse_FtNts, /* FtNts */
/*::[*/0x0E/*::]*/: parse_FtSkip, /* FtSbsFmla */
/*::[*/0x0F/*::]*/: parse_FtSkip, /* FtGboData */
/*::[*/0x10/*::]*/: parse_FtSkip, /* FtEdoData */
/*::[*/0x11/*::]*/: parse_FtSkip, /* FtRboData */
/*::[*/0x12/*::]*/: parse_FtSkip, /* FtCblsData */
/*::[*/0x13/*::]*/: parse_FtSkip, /* FtLbsData */
/*::[*/0x14/*::]*/: parse_FtSkip, /* FtCblsFmla */
/*::[*/0x15/*::]*/: parse_FtCmo
};
function parse_FtArray(blob, length, ot) {
var s = blob.l;
var tgt = blob.l + length;
var fts = [];
while(blob.l < s + length) {
while(blob.l < tgt) {
var ft = blob.read_shift(2);
blob.l-=2;
try {
fts.push(FtTab[ft](blob, s + length - blob.l));
} catch(e) { blob.l = s + length; return fts; }
fts.push(FtTab[ft](blob, tgt - blob.l));
} catch(e) { blob.l = tgt; return fts; }
}
if(blob.l != s + length) blob.l = s + length; //throw new Error("bad Object Ft-sequence");
if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
return fts;
}
@ -158,7 +162,7 @@ function parse_BOF(blob, length) {
function parse_InterfaceHdr(blob, length) {
if(length === 0) return 0x04b0;
var q;
if((q=blob.read_shift(2))!==0x04b0){}
if((q=blob.read_shift(2))!==0x04b0){/* empty */}
return 0x04b0;
}
@ -246,11 +250,16 @@ function parse_RecalcId(blob, length) {
}
/* 2.4.87 */
function parse_DefaultRowHeight(blob, length) {
var f = blob.read_shift(2);
var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
/* char is misleading, miyRw and miyRwHidden overlap */
function parse_DefaultRowHeight(blob, length, opts) {
var f = 0;
if(!(opts && opts.biff == 2)) {
f = blob.read_shift(2);
}
var miyRw = blob.read_shift(2);
if((opts && opts.biff == 2)) {
f = 1 - (miyRw >> 15); miyRw &= 0x7fff;
}
var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
return [fl, miyRw];
}
@ -265,9 +274,17 @@ function parse_Window1(blob, length) {
/* 2.4.122 TODO */
function parse_Font(blob, length, opts) {
blob.l += 14;
var name = parse_ShortXLUnicodeString(blob, 0, opts);
return name;
var o = {
dyHeight: blob.read_shift(2),
fl: blob.read_shift(2)
};
switch(opts && opts.biff || 8) {
case 2: break;
case 3: case 4: blob.l += 2; break;
default: blob.l += 10; break;
}
o.name = parse_ShortXLUnicodeString(blob, 0, opts);
return o;
}
/* 2.4.149 */
@ -299,8 +316,8 @@ var parse_BIFF2Format = parse_XLUnicodeString2;
function parse_Dimensions(blob, length, opts) {
var end = blob.l + length;
var w = opts.biff == 8 || !opts.biff ? 4 : 2;
var r = blob.read_shift(w), R = blob.read_shift(w),
c = blob.read_shift(2), C = blob.read_shift(2);
var r = blob.read_shift(w), R = blob.read_shift(w);
var c = blob.read_shift(2), C = blob.read_shift(2);
blob.l = end;
return {s: {r:r, c:c}, e: {r:R, c:C}};
}
@ -549,11 +566,49 @@ function parse_MergeCells(blob, length) {
}
/* 2.4.181 TODO: parse all the things! */
function parse_Obj(blob, length) {
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
var fts = parse_FtArray(blob, length-22, cmo[1]);
return { cmo: cmo, ft:fts };
}
/* from older spec */
var parse_BIFF5OT = [];
parse_BIFF5OT[0x08] = function(blob, length, opts) {
var tgt = blob.l + length;
blob.l += 10; // todo
var cf = blob.read_shift(2);
blob.l += 4;
var cbPictFmla = blob.read_shift(2);
blob.l += 2;
var grbit = blob.read_shift(2);
blob.l += 4;
var cchName = blob.read_shift(1);
blob.l += cchName; // TODO: stName
blob.l = tgt; // TODO: fmla
return { fmt:cf };
};
function parse_BIFF5Obj(blob, length, opts) {
var cnt = blob.read_shift(4);
var ot = blob.read_shift(2);
var id = blob.read_shift(2);
var grbit = blob.read_shift(2);
var colL = blob.read_shift(2);
var dxL = blob.read_shift(2);
var rwT = blob.read_shift(2);
var dyT = blob.read_shift(2);
var colR = blob.read_shift(2);
var dxR = blob.read_shift(2);
var rwB = blob.read_shift(2);
var dyB = blob.read_shift(2);
var cbMacro = blob.read_shift(2);
blob.l += 6;
length -= 36;
var fts = [];
fts.push((parse_BIFF5OT[ot]||parsenoop)(blob, length, opts));
return { cmo: [id, ot, grbit], ft:fts };
}
/* 2.4.329 TODO: parse properly */
function parse_TxO(blob, length, opts) {
@ -684,7 +739,6 @@ var parse_StyleExt = parsenoop;
var parse_Window2 = parsenoop;
var parse_Backup = parsebool; /* 2.4.14 */
var parse_Blank = parse_XLSCell; /* 2.4.20 Just the cell */
var parse_BottomMargin = parse_Xnum; /* 2.4.27 */
@ -991,6 +1045,16 @@ var parse_BopPopCustom = parsenoop;
var parse_Fbi2 = parsenoop;
/* --- Specific to versions before BIFF8 --- */
function parse_ImData(blob, length, opts) {
var tgt = blob.l + length;
var cf = blob.read_shift(2);
var env = blob.read_shift(2);
var lcb = blob.read_shift(4);
var o = {fmt:cf, env:env, len:lcb, data:blob.slice(blob.l,blob.l+lcb)};
blob.l += lcb;
return o;
}
function parse_BIFF5String(blob) {
var len = blob.read_shift(1);
return blob.read_shift(len, 'sbcs-cont');
@ -1037,7 +1101,7 @@ function parse_BIFF2FONTXTRA(blob, length) {
blob.l += 1; // charset
blob.l += 3; // unknown
blob.l += 1; // font family
blob.l += length - 9;
blob.l += length - 13;
}
/* TODO: parse rich text runs */

@ -210,17 +210,23 @@ var SYLK = (function() {
var Mval = 0, j;
for (; ri !== records.length; ++ri) {
Mval = 0;
var record = records[ri].trim().split(";");
var RT = record[0], val;
switch(RT) {
case 'P': if(record[1].charAt(0) == 'P') formats.push(records[ri].trim().substr(3).replace(/;;/g, ";"));
var rstr=records[ri].trim(), record=rstr.split(";"), RT=record[0], val;
if(rstr.length > 0) switch(RT) {
case 'ID': break; /* header */
case 'E': break; /* EOF */
case 'B': break; /* dimensions */
case 'O': break; /* options? */
case 'P':
if(record[1].charAt(0) == 'P')
formats.push(rstr.substr(3).replace(/;;/g, ";"));
break;
case 'C': case 'F': for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
case 'C':
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
case 'X': C = parseInt(record[rj].substr(1))-1; break;
case 'Y':
R = parseInt(record[rj].substr(1))-1; C = 0;
for(j = arr.length; j <= R; ++j) arr[j] = [];
break;
case 'X': C = parseInt(record[rj].substr(1))-1; break;
case 'K':
val = record[rj].substr(1);
if(val.charAt(0) === '"') val = val.substr(1,val.length - 2);
@ -233,13 +239,27 @@ var SYLK = (function() {
arr[R][C] = val;
next_cell_format = null;
break;
case 'P':
if(RT !== 'F') break;
next_cell_format = formats[parseInt(record[rj].substr(1))];
case 'E':
/* formula = record[rj].substr(1); */
break; /* TODO: formula */
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
} break;
case 'F':
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
case 'X': C = parseInt(record[rj].substr(1))-1; break;
case 'Y':
R = parseInt(record[rj].substr(1))-1; C = 0;
for(j = arr.length; j <= R; ++j) arr[j] = [];
break;
case 'M': Mval = parseInt(record[rj].substr(1)) / 20; break;
case 'F': break; /* ??? */
case 'P':
next_cell_format = formats[parseInt(record[rj].substr(1))];
break;
case 'S': break; /* cell style */
case 'D': break; /* column */
case 'N': break; /* font */
case 'W':
if(RT !== 'F') break;
cw = record[rj].substr(1).split(" ");
for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
Mval = parseInt(cw[2], 10);
@ -250,8 +270,10 @@ var SYLK = (function() {
rowinfo[R] = {};
if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
else if(Mval == 0) rowinfo[R].hidden = true;
break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
} break;
default: break;
default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
}
}
if(rowinfo.length > 0) sht['!rows'] = rowinfo;
@ -297,7 +319,7 @@ var SYLK = (function() {
});
}
function write_ws_rows_sylk(out, rows) {
function write_ws_rows_sylk(out/*:Array<string>*/, rows/*:Array<RowInfo>*/) {
rows.forEach(function(row, i) {
var rec = "F;";
if(row.hidden) rec += "M0;";