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;";
@ -318,6 +340,7 @@ var SYLK = (function() {
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
for(var R = r.s.r; R <= r.e.r; ++R) {
for(var C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
@ -447,7 +470,7 @@ var PRN = (function() {
function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/) {
if(data === 'TRUE') arr[R][C] = true;
else if(data === 'FALSE') arr[R][C] = false;
else if(data === ""){}
else if(data === ""){/* empty */}
else if(+data == +data) arr[R][C] = +data;
else arr[R][C] = data;
}
@ -485,29 +508,36 @@ var PRN = (function() {
/* known sep */
if(str.substr(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.substr(6); }
/* TODO: actually determine the separator */
if(str.substr(0,1024).indexOf("\t") == -1) sep = ","; else sep = "\t";
else if(str.substr(0,1024).indexOf("\t") == -1) sep = ","; else sep = "\t";
var R = 0, C = 0, v = 0;
var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
str = str.replace(/\r\n/g, "\n");
for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
case 0x22: instr = !instr; break;
case sepcc: case 0x0a: if(instr) break;
str = str.replace(/\r\n/mg, "\n");
function finish_cell() {
var s = str.slice(start, end);
var cell = ({}/*:any*/);
if(s.charCodeAt(0) == 0x3D) { cell.t = 'n'; cell.f = s.substr(1); }
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = parseFloat(s))) { cell.t = 'n'; cell.w = s; cell.v = v; }
else { cell.t = 's'; cell.v = s.replace(/^"/,"").replace(/"$/,"").replace(/""/g,'"'); }
else if(!isNaN(v = +s)) { cell.t = 'n'; cell.w = s; cell.v = v; }
else if(!isNaN(new Date(s).getDate())) { cell.t = 'd'; cell.v = parseDate(s); }
else {
cell.t = 's';
if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
cell.v = s;
}
if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
else ws[encode_cell({c:C,r:R})] = cell;
start = end+1;
if(range.e.c < C) range.e.c = C;
if(range.e.r < R) range.e.r = R;
if(cc == sepcc) ++C; else { C = 0; ++R; } break;
if(cc == sepcc) ++C; else { C = 0; ++R; }
}
for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
case 0x22: if(instr || (end - start == 0)) instr = !instr; break;
case sepcc: case 0x0a: case 0x0d: if(!instr) finish_cell(); break;
default: break;
}
if(end - start > 0) finish_cell();
ws['!ref'] = encode_range(range);
return ws;

@ -22,8 +22,8 @@ function parse_sst_bin(data, opts)/*:SST*/ {
pass = false; break;
default:
if(R_n.indexOf("Begin") > 0){}
else if(R_n.indexOf("End") > 0){}
if(R_n.indexOf("Begin") > 0){/* empty */}
else if(R_n.indexOf("End") > 0){/* empty */}
if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
}
});

@ -138,30 +138,47 @@ function parse_fonts(t, styles, themes, opts) {
case '<name': if(y.val) font.name = y.val; break;
case '<name/>': case '</name>': break;
/* 18.8.2 b CT_BooleanProperty */
case '<b': break; // TODO: read val (0 = off)
case '<b/>': font.bold = true; break;
/* 18.8.2 b CT_BooleanProperty */
case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
case '<b/>': font.bold = 1; break;
/* 18.8.26 i CT_BooleanProperty */
case '<i': break; // TODO: read val (0 = off)
case '<i/>': font.italic = true; break;
case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
case '<i/>': font.italic = 1; break;
/* 18.4.13 u CT_UnderlineProperty */
case '<u': font.underline = true; break; // TODO: double underline
case '<u/>': font.underline = true; break;
case '<u':
switch(y.val) {
case "none": font.underline = 0x00; break;
case "single": font.underline = 0x01; break;
case "double": font.underline = 0x02; break;
case "singleAccounting": font.underline = 0x21; break;
case "doubleAccounting": font.underline = 0x22; break;
} break;
case '<u/>': font.underline = 1; break;
/* 18.4.10 strike CT_BooleanProperty */
case '<strike': break; // TODO: read val (0 = off)
case '<strike/>': font.strike = true; break;
case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
case '<strike/>': font.strike = 1; break;
/* 18.4.2 outline CT_BooleanProperty */
case '<outline/>': font.outline = true; break;
/* 18.4.2 outline CT_BooleanProperty */
case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
case '<outline/>': font.outline = 1; break;
/* 18.8.36 shadow CT_BooleanProperty */
case '<shadow/>': font.shadow = true; break;
case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
case '<shadow/>': font.shadow = 1; break;
/* 18.8.12 condense CT_BooleanProperty */
case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
case '<condense/>': font.condense = 1; break;
/* 18.8.17 extend CT_BooleanProperty */
case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
case '<extend/>': font.extend = 1; break;
/* 18.4.11 sz CT_FontSize */
case '<sz': if(y.val) font.sz = y.val; break;
case '<sz': if(y.val) font.sz = +y.val; break;
case '<sz/>': case '</sz>': break;
/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
@ -169,28 +186,39 @@ function parse_fonts(t, styles, themes, opts) {
case '<vertAlign/>': case '</vertAlign>': break;
/* 18.8.18 family CT_FontFamily */
case '<family': if(y.val) font.family = y.val; break;
case '<family': if(y.val) font.family = parseInt(y.val,10); break;
case '<family/>': case '</family>': break;
/* 18.8.35 scheme CT_FontScheme */
case '<scheme': if(y.val) font.scheme = y.val; break;
case '<scheme/>': case '</scheme>': break;
/* 18.4.1 charset CT_IntProperty TODO */
/* 18.4.1 charset CT_IntProperty */
case '<charset':
if(y.val == '1') break;
y.codepage = CS2CP[parseInt(y.val, 10)];
break;
/* 18.?.? color CT_Color TODO */
/* 18.?.? color CT_Color */
case '<color':
if(!font.color) font.color = {};
if(y.theme) font.color.theme = y.theme;
if(y.tint) font.color.tint = y.tint;
if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
}
if(y.auto) font.color.auto = parsexmlbool(y.auto);
if(y.rgb) font.color.rgb = y.rgb;
else if(y.indexed) {
font.color.index = parseInt(y.indexed, 10);
var icv = XLSIcv[font.color.index];
if(font.color.index == 81) icv = XLSIcv[1];
if(!icv) throw new Error(x);
font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
} else if(y.theme) {
font.color.theme = parseInt(y.theme, 10);
if(y.tint) font.color.tint = parseFloat(y.tint);
if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
}
}
break;
case '<color/>': case '</color>': break;
@ -302,17 +330,18 @@ return function parse_sty_xml(data, themes, opts) {
/* 18.8.23 fonts CT_Fonts ? */
if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
/* 18.8.21 fills CT_Fills */
/* 18.8.21 fills CT_Fills ? */
if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
/* 18.8.5 borders CT_Borders ? */
/* 18.8.5 borders CT_Borders ? */
if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
/* 18.8.10 cellXfs CT_CellXfs ? */
if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
/* 18.8.8 cellStyles CT_CellStyles ? */
/* 18.8.15 dxfs CT_Dxfs ? */
/* 18.8.42 tableStyles CT_TableStyles ? */
/* 18.8.11 colors CT_Colors ? */

@ -4,33 +4,132 @@ function parse_BrtFmt(data, length/*:number*/) {
var stFmtCode = parse_XLWideString(data,length-2);
return [ifmt, stFmtCode];
}
function write_BrtFmt(i/*:number*/, f/*:string*/, o) {
if(!o) o = new_buf(6 + 4 * f.length);
o.write_shift(2, i);
write_XLWideString(f, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.653 BrtFont TODO */
function parse_BrtFont(data, length/*:number*/) {
var out = ({flags:{}}/*:any*/);
out.dyHeight = data.read_shift(2);
out.grbit = parse_FontFlags(data, 2);
out.bls = data.read_shift(2);
out.sss = data.read_shift(2);
out.uls = data.read_shift(1);
out.bFamily = data.read_shift(1);
out.bCharSet = data.read_shift(1);
function parse_BrtFont(data, length/*:number*/, opts) {
var out = ({}/*:any*/);
out.sz = data.read_shift(2) / 20;
var grbit = parse_FontFlags(data, 2, opts);
if(grbit.fCondense) out.condense = 1;
if(grbit.fExtend) out.extend = 1;
if(grbit.fShadow) out.shadow = 1;
if(grbit.fOutline) out.outline = 1;
if(grbit.fStrikeout) out.strike = 1;
if(grbit.fItalic) out.italic = 1;
var bls = data.read_shift(2);
if(bls === 0x02BC) out.bold = 1;
switch(data.read_shift(2)) {
/* case 0: out.vertAlign = "baseline"; break; */
case 1: out.vertAlign = "superscript"; break;
case 2: out.vertAlign = "subscript"; break;
}
var underline = data.read_shift(1);
if(underline != 0) out.underline = underline;
var family = data.read_shift(1);
if(family > 0) out.family = family;
var bCharSet = data.read_shift(1);
if(bCharSet > 0) out.charset = bCharSet;
data.l++;
out.brtColor = parse_BrtColor(data, 8);
out.bFontScheme = data.read_shift(1);
out.color = parse_BrtColor(data, 8);
switch(data.read_shift(1)) {
/* case 0: out.scheme = "none": break; */
case 1: out.scheme = "major"; break;
case 2: out.scheme = "minor"; break;
}
out.name = parse_XLWideString(data, length - 21);
out.flags.Bold = out.bls === 0x02BC;
out.flags.Italic = out.grbit.fItalic;
out.flags.Strikeout = out.grbit.fStrikeout;
out.flags.Outline = out.grbit.fOutline;
out.flags.Shadow = out.grbit.fShadow;
out.flags.Condense = out.grbit.fCondense;
out.flags.Extend = out.grbit.fExtend;
out.flags.Sub = out.sss & 0x2;
out.flags.Sup = out.sss & 0x1;
return out;
}
function write_BrtFont(font, o) {
if(!o) o = new_buf(25+4*32);
o.write_shift(2, font.sz * 20);
write_FontFlags(font, o);
o.write_shift(2, font.bold ? 0x02BC : 0x0190);
var sss = 0;
if(font.vertAlign == "superscript") sss = 1;
else if(font.vertAlign == "subscript") sss = 2;
o.write_shift(2, sss);
o.write_shift(1, font.underline || 0);
o.write_shift(1, font.family || 0);
o.write_shift(1, font.charset || 0);
o.write_shift(1, 0);
write_BrtColor(font.color, o);
var scheme = 0;
if(font.scheme == "major") scheme = 1;
if(font.scheme == "minor") scheme = 2;
o.write_shift(1, scheme);
write_XLWideString(font.name, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.644 BrtFill */
var XLSBFillPTNames = [
"none",
"solid",
"mediumGray",
"darkGray",
"lightGray",
"darkHorizontal",
"darkVertical",
"darkDown",
"darkUp",
"darkGrid",
"darkTrellis",
"lightHorizontal",
"lightVertical",
"lightDown",
"lightUp",
"lightGrid",
"lightTrellis",
"gray125",
"gray0625"
];
var rev_XLSBFillPTNames = evert(XLSBFillPTNames);
/* TODO: gradient fill representation */
function write_BrtFill(fill, o) {
if(!o) o = new_buf(4*3 + 8*7 + 16*1);
var fls = rev_XLSBFillPTNames[fill.patternType];
if(fls == null) fls = 0x28;
o.write_shift(4, fls);
var j = 0;
if(fls != 0x28) {
/* TODO: custom FG Color */
write_BrtColor({auto:1}, o);
/* TODO: custom BG Color */
write_BrtColor({auto:1}, o);
for(; j < 12; ++j) o.write_shift(4, 0);
} else {
for(; j < 4; ++j) o.write_shift(4, 0);
for(; j < 12; ++j) o.write_shift(4, 0); /* TODO */
/* iGradientType */
/* xnumDegree */
/* xnumFillToLeft */
/* xnumFillToRight */
/* xnumFillToTop */
/* xnumFillToBottom */
/* cNumStop */
/* xfillGradientStop */
}
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.816 BrtXF */
function parse_BrtXF(data, length/*:number*/) {
@ -39,6 +138,62 @@ function parse_BrtXF(data, length/*:number*/) {
parsenoop(data, length-4);
return {ixfe:ixfeParent, ifmt:ifmt };
}
function write_BrtXF(data, ixfeP, o) {
if(!o) o = new_buf(16);
o.write_shift(2, ixfeP||0);
o.write_shift(2, data.numFmtId||0);
o.write_shift(2, 0); /* iFont */
o.write_shift(2, 0); /* iFill */
o.write_shift(2, 0); /* ixBorder */
o.write_shift(1, 0); /* trot */
o.write_shift(1, 0); /* indent */
o.write_shift(1, 0); /* flags */
o.write_shift(1, 0); /* flags */
o.write_shift(1, 0); /* xfGrbitAtr */
o.write_shift(1, 0);
return o;
}
/* [MS-XLSB] 2.5.4 Blxf TODO */
function write_Blxf(data, o) {
if(!o) o = new_buf(10);
o.write_shift(1, 0); /* dg */
o.write_shift(1, 0);
o.write_shift(4, 0); /* color */
o.write_shift(4, 0); /* color */
return o;
}
/* [MS-XLSB] 2.4.299 BrtBorder TODO */
function write_BrtBorder(border, o) {
if(!o) o = new_buf(51);
o.write_shift(1, 0); /* diagonal */
write_Blxf(null, o); /* top */
write_Blxf(null, o); /* bottom */
write_Blxf(null, o); /* left */
write_Blxf(null, o); /* right */
write_Blxf(null, o); /* diag */
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.755 BrtStyle TODO */
function write_BrtStyle(style, o) {
if(!o) o = new_buf(12+4*10);
o.write_shift(4, style.xfId);
o.write_shift(2, 1);
o.write_shift(1, +style.builtinId);
o.write_shift(1, 0); /* iLevel */
write_XLNullableWideString(style.name || "", o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.4.269 BrtBeginTableStyles */
function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
var o = new_buf(4+256*2*4);
o.write_shift(4, cnt);
write_XLNullableWideString(defTableStyle, o);
write_XLNullableWideString(defPivotStyle, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
/* [MS-XLSB] 2.1.7.50 Styles */
function parse_sty_bin(data, themes, opts) {
@ -57,6 +212,9 @@ function parse_sty_bin(data, themes, opts) {
break;
case 0x002B: /* 'BrtFont' */
styles.Fonts.push(val);
if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) {
val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0);
}
break;
case 0x0401: /* 'BrtKnownFonts' */ break;
case 0x002D: /* 'BrtFill' */ break;
@ -98,20 +256,126 @@ function parse_sty_bin(data, themes, opts) {
return styles;
}
function write_FMTS_bin(ba, NF) {
if(!NF) return;
var cnt = 0;
[[5,8],[23,26],[41,44],[/*63*/57,/*66],[164,*/392]].forEach(function(r) {
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
});
if(cnt == 0) return;
write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
[[5,8],[23,26],[41,44],[/*63*/57,/*66],[164,*/392]].forEach(function(r) {
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
});
write_record(ba, "BrtEndFmts");
}
function write_FONTS_bin(ba, data) {
var cnt = 1;
if(cnt == 0) return;
write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt));
write_record(ba, "BrtFont", write_BrtFont({
sz:12,
color: {theme:1},
name: "Calibri",
family: 2,
scheme: "minor"
}));
/* 1*65491BrtFont [ACFONTS] */
write_record(ba, "BrtEndFonts");
}
function write_FILLS_bin(ba, data) {
var cnt = 2;
if(cnt == 0) return;
write_record(ba, "BrtBeginFills", write_UInt32LE(cnt));
write_record(ba, "BrtFill", write_BrtFill({patternType:"none"}));
write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"}));
/* 1*65431BrtFill */
write_record(ba, "BrtEndFills");
}
function write_BORDERS_bin(ba, data) {
var cnt = 1;
if(cnt == 0) return;
write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt));
write_record(ba, "BrtBorder", write_BrtBorder({}));
/* 1*65430BrtBorder */
write_record(ba, "BrtEndBorders");
}
function write_CELLSTYLEXFS_bin(ba, data) {
var cnt = 1;
write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
write_record(ba, "BrtXF", write_BrtXF({
numFmtId:0,
fontId:0,
fillId:0,
borderId:0
}, 0xFFFF));
/* 1*65430(BrtXF *FRT) */
write_record(ba, "BrtEndCellStyleXFs");
}
function write_CELLXFS_bin(ba, data) {
write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length));
data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); });
/* 1*65430(BrtXF *FRT) */
write_record(ba, "BrtEndCellXFs");
}
function write_STYLES_bin(ba, data) {
var cnt = 1;
write_record(ba, "BrtBeginStyles", write_UInt32LE(1));
write_record(ba, "BrtStyle", write_BrtStyle({
xfId:0,
builtinId:0,
name:"Normal"
}));
/* 1*65430(BrtStyle *FRT) */
write_record(ba, "BrtEndStyles");
}
function write_DXFS_bin(ba, data) {
var cnt = 0;
write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
/* *2147483647(BrtDXF *FRT) */
write_record(ba, "BrtEndDXFs");
}
function write_TABLESTYLES_bin(ba, data) {
var cnt = 0;
write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
/* *TABLESTYLE */
write_record(ba, "BrtEndTableStyles");
}
function write_COLORPALETTE_bin(ba, data) {
return;
/* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
}
/* [MS-XLSB] 2.1.7.50 Styles */
function write_sty_bin(data, opts) {
function write_sty_bin(wb, opts) {
var ba = buf_array();
write_record(ba, "BrtBeginStyleSheet");
/* [FMTS] */
/* [FONTS] */
/* [FILLS] */
/* [BORDERS] */
/* CELLSTYLEXFS */
/* CELLXFS*/
/* STYLES */
/* DXFS */
/* TABLESTYLES */
/* [COLORPALETTE] */
write_FMTS_bin(ba, wb.SSF);
write_FONTS_bin(ba, wb);
write_FILLS_bin(ba, wb);
write_BORDERS_bin(ba, wb);
write_CELLSTYLEXFS_bin(ba, wb);
write_CELLXFS_bin(ba, opts.cellXfs);
write_STYLES_bin(ba, wb);
write_DXFS_bin(ba, wb);
write_TABLESTYLES_bin(ba, wb);
write_COLORPALETTE_bin(ba, wb);
/* FRTSTYLESHEET*/
write_record(ba, "BrtEndStyleSheet");
return ba.end();

@ -7,50 +7,41 @@ function parse_clrScheme(t, themes, opts) {
(t[0].match(tagregex)||[]).forEach(function(x) {
var y = parsexmltag(x);
switch(y[0]) {
/* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
case '<a:clrScheme': case '</a:clrScheme>': break;
/* 20.1.2.3.32 srgbClr CT_SRgbColor */
case '<a:srgbClr': color.rgb = y.val; break;
case '<a:srgbClr':
color.rgb = y.val; break;
/* 20.1.2.3.33 sysClr CT_SystemColor */
case '<a:sysClr': color.rgb = y.lastClr; break;
case '<a:sysClr':
color.rgb = y.lastClr; break;
/* 20.1.4.1.9 dk1 (Dark 1) */
case '<a:dk1>':
case '</a:dk1>':
/* 20.1.4.1.10 dk2 (Dark 2) */
case '<a:dk2>':
case '</a:dk2>':
/* 20.1.4.1.22 lt1 (Light 1) */
case '<a:lt1>':
case '</a:lt1>':
/* 20.1.4.1.23 lt2 (Light 2) */
case '<a:lt2>':
case '</a:lt2>':
/* 20.1.4.1.1 accent1 (Accent 1) */
case '<a:accent1>':
case '</a:accent1>':
/* 20.1.4.1.2 accent2 (Accent 2) */
case '<a:accent2>':
case '</a:accent2>':
/* 20.1.4.1.3 accent3 (Accent 3) */
case '<a:accent3>':
case '</a:accent3>':
/* 20.1.4.1.4 accent4 (Accent 4) */
case '<a:accent4>':
case '</a:accent4>':
/* 20.1.4.1.5 accent5 (Accent 5) */
case '<a:accent5>':
case '</a:accent5>':
/* 20.1.4.1.6 accent6 (Accent 6) */
case '<a:accent6>':
case '</a:accent6>':
/* 20.1.4.1.19 hlink (Hyperlink) */
case '<a:hlink>':
case '</a:hlink>':
/* 20.1.4.1.9 dk1 (Dark 1) */
/* 20.1.4.1.10 dk2 (Dark 2) */
/* 20.1.4.1.15 folHlink (Followed Hyperlink) */
case '<a:folHlink>':
case '</a:folHlink>':
/* 20.1.4.1.19 hlink (Hyperlink) */
/* 20.1.4.1.22 lt1 (Light 1) */
/* 20.1.4.1.23 lt2 (Light 2) */
case '<a:dk1>': case '</a:dk1>':
case '<a:lt1>': case '</a:lt1>':
case '<a:dk2>': case '</a:dk2>':
case '<a:lt2>': case '</a:lt2>':
case '<a:accent1>': case '</a:accent1>':
case '<a:accent2>': case '</a:accent2>':
case '<a:accent3>': case '</a:accent3>':
case '<a:accent4>': case '</a:accent4>':
case '<a:accent5>': case '</a:accent5>':
case '<a:accent6>': case '</a:accent6>':
case '<a:hlink>': case '</a:hlink>':
case '<a:folHlink>': case '</a:folHlink>':
if (y[0][1] === '/') {
themes.themeElements.clrScheme.push(color);
color = {};

@ -22,8 +22,8 @@ function parse_cc_bin(data, opts) {
out.push(val); break;
default:
if((R_n||"").indexOf("Begin") > 0){}
else if((R_n||"").indexOf("End") > 0){}
if((R_n||"").indexOf("Begin") > 0){/* empty */}
else if((R_n||"").indexOf("End") > 0){/* empty */}
else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
}
});

@ -34,6 +34,7 @@ function write_comments_vml(rId, comments) {
writetag('x:AutoFill', "False"),
writetag('x:Row', String(c.r)),
writetag('x:Column', String(c.c)),
'<x:Visible/>',
'</x:ClientData>',
'</v:shape>'
]); });

@ -22,9 +22,6 @@ function write_BrtBeginComment(data, o) {
/* [MS-XLSB] 2.4.324 BrtCommentAuthor */
var parse_BrtCommentAuthor = parse_XLWideString;
/* [MS-XLSB] 2.4.325 BrtCommentText */
var parse_BrtCommentText = parse_RichStr;
/* [MS-XLSB] 2.1.7.8 Comments */
function parse_comments_bin(data, opts) {
var out = [];
@ -57,8 +54,8 @@ function parse_comments_bin(data, opts) {
default:
if((R_n||"").indexOf("Begin") > 0){}
else if((R_n||"").indexOf("End") > 0){}
if((R_n||"").indexOf("Begin") > 0){/* empty */}
else if((R_n||"").indexOf("End") > 0){/* empty */}
else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
}
});
@ -87,7 +84,7 @@ function write_comments_bin(data, opts) {
c.iauthor = iauthor.indexOf(c.a);
var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c]));
if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_RichStr(c));
if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c));
write_record(ba, "BrtEndComment");
delete c.iauthor;
});

@ -1,7 +1,7 @@
/* --- formula references point to MS-XLS --- */
/* Small helpers */
function parseread(l) { return function(blob, length) { blob.l+=l; return; }; }
function parseread1(blob, length) { blob.l+=1; return; }
function parseread1(blob) { blob.l+=1; return; }
/* Rgce Helpers */
@ -25,7 +25,7 @@ function parse_RgceArea(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]} };
}
/* BIFF 2-5 encodes flags in the row field */
function parse_RgceArea_BIFF2(blob, length, opts) {
function parse_RgceArea_BIFF2(blob/*, length, opts*/) {
var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
var c=blob.read_shift(1);
var C=blob.read_shift(1);
@ -33,7 +33,7 @@ function parse_RgceArea_BIFF2(blob, length, opts) {
}
/* 2.5.198.105 TODO */
function parse_RgceAreaRel(blob, length, opts) {
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);
var C=parse_ColRelU(blob, 2);
@ -701,12 +701,12 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
var f = formula[0][ff];
//console.log("++",f, stack)
switch(f[0]) {
/* 2.5.198.93 */
case 'PtgUminus': stack.push("-" + stack.pop()); break;
/* 2.5.198.95 */
case 'PtgUplus': stack.push("+" + stack.pop()); break;
/* 2.5.198.81 */
case 'PtgPercent': stack.push(stack.pop() + "%"); break;
case 'PtgUminus': /* 2.5.198.93 */
stack.push("-" + stack.pop()); break;
case 'PtgUplus': /* 2.5.198.95 */
stack.push("+" + stack.pop()); break;
case 'PtgPercent': /* 2.5.198.81 */
stack.push(stack.pop() + "%"); break;
case 'PtgAdd': /* 2.5.198.26 */
case 'PtgConcat': /* 2.5.198.43 */
@ -723,10 +723,12 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
e1 = stack.pop(); e2 = stack.pop();
if(last_sp >= 0) {
switch(formula[0][last_sp][1][0]) {
// $FlowIgnore
case 0: sp = fill(" ", formula[0][last_sp][1][1]); break;
// $FlowIgnore
case 1: sp = fill("\r", formula[0][last_sp][1][1]); break;
case 0:
// $FlowIgnore
sp = fill(" ", formula[0][last_sp][1][1]); break;
case 1:
// $FlowIgnore
sp = fill("\r", formula[0][last_sp][1][1]); break;
default:
sp = "";
// $FlowIgnore
@ -738,51 +740,46 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(e2+PtgBinOp[f[0]]+e1);
break;
/* 2.5.198.67 */
case 'PtgIsect':
case 'PtgIsect': /* 2.5.198.67 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+" "+e1);
break;
case 'PtgUnion':
case 'PtgUnion': /* 2.5.198.94 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+","+e1);
break;
case 'PtgRange':
case 'PtgRange': /* 2.5.198.83 */
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+":"+e1);
break;
/* 2.5.198.34 */
case 'PtgAttrChoose': break;
/* 2.5.198.35 */
case 'PtgAttrGoto': break;
/* 2.5.198.36 */
case 'PtgAttrIf': break;
/* [MS-XLSB] 2.5.97.28 */
case 'PtgAttrIfError': break;
case 'PtgAttrChoose': /* 2.5.198.34 */
break;
case 'PtgAttrGoto': /* 2.5.198.35 */
break;
case 'PtgAttrIf': /* 2.5.198.36 */
break;
case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
break;
/* 2.5.198.84 */
case 'PtgRef':
case 'PtgRef': /* 2.5.198.84 */
type = f[1][0]; c = shift_cell_xls(f[1][1], _range, opts);
stack.push(encode_cell_xls(c));
break;
/* 2.5.198.88 */
case 'PtgRefN':
case 'PtgRefN': /* 2.5.198.88 */
type = f[1][0]; c = cell ? shift_cell_xls(f[1][1], cell, opts) : f[1][1];
stack.push(encode_cell_xls(c));
break;
case 'PtgRef3d': // TODO: lots of stuff
case 'PtgRef3d': /* 2.5.198.85 */
type = f[1][0]; ixti = /*::Number(*/f[1][1]/*::)*/; c = shift_cell_xls(f[1][2], _range, opts);
sname = supbooks.SheetNames[ixti];
var w = sname; /* IE9 fails on defined names */
stack.push(sname + "!" + encode_cell_xls(c));
break;
/* 2.5.198.62 */
case 'PtgFunc':
/* 2.5.198.63 */
case 'PtgFuncVar':
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], func/*:string*/ = f[1][1];
@ -793,43 +790,38 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(func + "(" + args.join(",") + ")");
break;
/* 2.5.198.42 */
case 'PtgBool': stack.push(f[1] ? "TRUE" : "FALSE"); break;
/* 2.5.198.66 */
case 'PtgInt': stack.push(/*::String(*/f[1]/*::)*/); break;
/* 2.5.198.79 TODO: precision? */
case 'PtgNum': stack.push(String(f[1])); break;
/* 2.5.198.89 */
// $FlowIgnore
case 'PtgStr': stack.push('"' + f[1] + '"'); break;
/* 2.5.198.57 */
case 'PtgErr': stack.push(/*::String(*/f[1]/*::)*/); break;
/* 2.5.198.31 TODO */
case 'PtgAreaN':
case 'PtgBool': /* 2.5.198.42 */
stack.push(f[1] ? "TRUE" : "FALSE"); break;
case 'PtgInt': /* 2.5.198.66 */
stack.push(/*::String(*/f[1]/*::)*/); break;
case 'PtgNum': /* 2.5.198.79 TODO: precision? */
stack.push(String(f[1])); break;
case 'PtgStr': /* 2.5.198.89 */
// $FlowIgnore
stack.push('"' + f[1] + '"'); break;
case 'PtgErr': /* 2.5.198.57 */
stack.push(/*::String(*/f[1]/*::)*/); break;
case 'PtgAreaN': /* 2.5.198.31 TODO */
type = f[1][0]; r = shift_range_xls(f[1][1], _range, opts);
stack.push(encode_range_xls((r/*:any*/), opts));
break;
/* 2.5.198.27 TODO: fixed points */
case 'PtgArea':
case 'PtgArea': /* 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;
/* 2.5.198.28 */
case 'PtgArea3d': // TODO: lots of stuff
case 'PtgArea3d': /* 2.5.198.28 TODO */
type = f[1][0]; ixti = /*::Number(*/f[1][1]/*::)*/; r = f[1][2];
sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**");
stack.push(sname + "!" + encode_range((r/*:any*/)));
break;
/* 2.5.198.41 */
case 'PtgAttrSum':
case 'PtgAttrSum': /* 2.5.198.41 */
stack.push("SUM(" + stack.pop() + ")");
break;
/* 2.5.198.37 */
case 'PtgAttrSemi': break;
case 'PtgAttrSemi': /* 2.5.198.37 */
break;
/* 2.5.97.60 TODO: do something different for revisions */
case 'PtgName':
case 'PtgName': /* 2.5.97.60 TODO: revisions */
/* f[1] = type, 0, nameindex */
nameidx = f[1][2];
var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
@ -838,8 +830,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(name);
break;
/* 2.5.97.61 TODO: do something different for revisions */
case 'PtgNameX':
case 'PtgNameX': /* 2.5.97.61 TODO: revisions */
/* f[1] = type, ixti, nameindex */
var bookidx/*:number*/ = (f[1][1]/*:any*/); nameidx = f[1][2]; var externbook;
/* TODO: Properly handle missing values */
@ -850,7 +841,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
} else {
var pnxname = supbooks.SheetNames[bookidx];
var o = "";
if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){}
if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){/* empty */}
else if(((supbooks[bookidx]||[])[0]||[])[0] == 0x0401){
if(supbooks[bookidx][nameidx] && supbooks[bookidx][nameidx].itab > 0) {
o = supbooks.SheetNames[supbooks[bookidx][nameidx].itab-1] + "!";
@ -867,8 +858,7 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
stack.push(externbook.Name);
break;
/* 2.5.198.80 */
case 'PtgParen':
case 'PtgParen': /* 2.5.198.80 */
var lp = '(', rp = ')';
if(last_sp >= 0) {
sp = "";
@ -889,15 +879,13 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
}
stack.push(lp + stack.pop() + rp); break;
/* 2.5.198.86 */
case 'PtgRefErr': stack.push('#REF!'); break;
case 'PtgRefErr': /* 2.5.198.86 */
stack.push('#REF!'); break;
/* 2.5.198.87 */
case 'PtgRefErr3d': stack.push('#REF!'); break;
case 'PtgRefErr3d': /* 2.5.198.87 */
stack.push('#REF!'); break;
/* */
/* 2.5.198.58 TODO */
case 'PtgExp':
case 'PtgExp': /* 2.5.198.58 TODO */
c = {c:f[1][1],r:f[1][0]};
var q = ({c: cell.c, r:cell.r}/*:any*/);
if(supbooks.sharedf[encode_cell(c)]) {
@ -919,42 +907,37 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
}
break;
/* 2.5.198.32 TODO */
case 'PtgArray':
case 'PtgArray': /* 2.5.198.32 TODO */
stack.push("{" + stringify_array(f[1]) + "}");
break;
/* 2.5.198.70 TODO: confirm this is a non-display */
case 'PtgMemArea':
case 'PtgMemArea': /* 2.5.198.70 TODO: confirm this is a non-display */
//stack.push("(" + f[2].map(encode_range).join(",") + ")");
break;
/* 2.5.198.38 */
case 'PtgAttrSpace':
/* 2.5.198.39 */
case 'PtgAttrSpaceSemi':
case 'PtgAttrSpace': /* 2.5.198.38 */
case 'PtgAttrSpaceSemi': /* 2.5.198.39 */
last_sp = ff;
break;
/* 2.5.198.92 TODO */
case 'PtgTbl': break;
case 'PtgTbl': /* 2.5.198.92 TODO */
break;
/* 2.5.198.71 */
case 'PtgMemErr': break;
case 'PtgMemErr': /* 2.5.198.71 */
break;
/* 2.5.198.74 */
case 'PtgMissArg':
case 'PtgMissArg': /* 2.5.198.74 */
stack.push("");
break;
/* 2.5.198.29 */
case 'PtgAreaErr': stack.push("#REF!"); break;
case 'PtgAreaErr': /* 2.5.198.29 */
stack.push("#REF!"); break;
/* 2.5.198.30 */
case 'PtgAreaErr3d': stack.push("#REF!"); break;
case 'PtgAreaErr3d': /* 2.5.198.30 */
stack.push("#REF!"); break;
/* 2.5.198.72 TODO */
case 'PtgMemFunc': break;
case 'PtgMemFunc': /* 2.5.198.72 TODO */
break;
default: throw new Error('Unrecognized Formula Token: ' + String(f));
}
@ -966,12 +949,14 @@ function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks,
/* note: some bad XLSB files omit the PtgParen */
case 4: _left = false;
/* falls through */
// $FlowIgnore
case 0: sp = fill(" ", f[1][1]); break;
case 0:
// $FlowIgnore
sp = fill(" ", f[1][1]); break;
case 5: _left = false;
/* falls through */
// $FlowIgnore
case 1: sp = fill("\r", f[1][1]); break;
case 1:
// $FlowIgnore
sp = fill("\r", f[1][1]); break;
default:
sp = "";
// $FlowIgnore

@ -39,7 +39,16 @@ function default_margins(margins, mode) {
function get_cell_style(styles, cell, opts) {
var z = opts.revssf[cell.z != null ? cell.z : "General"];
for(var i = 0, len = styles.length; i != len; ++i) if(styles[i].numFmtId === z) return i;
var i = 0x3c, len = styles.length;
if(z == null && opts.ssf) {
for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
SSF.load(cell.z, i);
opts.ssf[i] = cell.z;
opts.revssf[cell.z] = z = i;
break;
}
}
for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
styles[len] = {
numFmtId:z,
fontId:0,
@ -77,7 +86,7 @@ function safe_format(p, fmtid, fillid, opts, themes, styles) {
} catch(e) { if(opts.WTF) throw e; }
if(fillid) try {
p.s = styles.Fills[fillid];
if (p.s.fgColor && p.s.fgColor.theme) {
if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
}

@ -69,6 +69,9 @@ function write_row_header(ba, ws, range, R) {
var parse_BrtWsDim = parse_UncheckedRfX;
var write_BrtWsDim = write_UncheckedRfX;
/* [MS-XLSB] 2.4.813 BrtWsFmtInfo */
//function write_BrtWsFmtInfo(ws, o) { }
/* [MS-XLSB] 2.4.815 BrtWsProp */
function parse_BrtWsProp(data, length) {
var z = {};
@ -78,8 +81,9 @@ function parse_BrtWsProp(data, length) {
return z;
}
function write_BrtWsProp(str, o) {
if(o == null) o = new_buf(80+4*str.length);
for(var i = 0; i < 11; ++i) o.write_shift(1,0);
if(o == null) o = new_buf(84+4*str.length);
for(var i = 0; i < 3; ++i) o.write_shift(1,0);
write_BrtColor({auto:1}, o);
o.write_shift(-4,-1);
o.write_shift(-4,-1);
write_XLSBCodeName(str, o);
@ -260,8 +264,8 @@ function write_BrtHLink(l, rId, o) {
write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
write_RelID("rId" + rId, o);
var locidx = l[1].Target.indexOf("#");
var location = locidx == -1 ? "" : l[1].Target.substr(locidx+1);
write_XLWideString(location || "", o);
var loc = locidx == -1 ? "" : l[1].Target.substr(locidx+1);
write_XLWideString(loc || "", o);
write_XLWideString(l[1].Tooltip || "", o);
write_XLWideString("", o);
return o.slice(0, o.l);
@ -536,6 +540,7 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ {
s['!margins'] = val;
break;
/* case 'BrtUid' */
case 0x00AF: /* 'BrtAFilterDateGroupItem' */
case 0x0284: /* 'BrtActiveX' */
case 0x0271: /* 'BrtBigName' */
@ -585,7 +590,6 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ {
case 0x0413: /* 'BrtSparkline' */
case 0x01AC: /* 'BrtTable' */
case 0x00AA: /* 'BrtTop10Filter' */
/* case 'BrtUid' */
case 0x0032: /* 'BrtValueMeta' */
case 0x0816: /* 'BrtWebExtension' */
case 0x01E5: /* 'BrtWsFmtInfo' */
@ -601,8 +605,8 @@ function parse_ws_bin(data, _opts, rels, wb, themes, styles)/*:Worksheet*/ {
case 0x0026: /* 'BrtACEnd' */ break;
default:
if((R_n||"").indexOf("Begin") > 0){}
else if((R_n||"").indexOf("End") > 0){}
if((R_n||"").indexOf("Begin") > 0){/* empty */}
else if((R_n||"").indexOf("End") > 0){/* empty */}
else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
}
}, opts);
@ -646,7 +650,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
}
var o/*:any*/ = ({r:R, c:C}/*:any*/);
/* TODO: cell style */
//o.s = get_cell_style(opts.cellXfs, cell, opts);
o.s = get_cell_style(opts.cellXfs, cell, opts);
if(cell.l) ws['!links'].push([encode_cell(o), cell.l]);
if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
switch(cell.t) {
@ -753,6 +757,11 @@ function write_WSVIEWS2(ba, ws) {
write_record(ba, "BrtEndWsViews");
}
function write_WSFMTINFO(ba, ws) {
/* [ACWSFMTINFO] */
//write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
}
function write_SHEETPROTECT(ba, ws) {
if(!ws['!protect']) return;
/* [BrtSheetProtectionIso] */
@ -770,7 +779,7 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
write_record(ba, "BrtWsProp", write_BrtWsProp(s));
write_record(ba, "BrtWsDim", write_BrtWsDim(r));
write_WSVIEWS2(ba, ws);
/* [WSFMTINFO] */
write_WSFMTINFO(ba, ws);
write_COLINFOS(ba, ws, idx, opts, wb);
write_CELLTABLE(ba, ws, idx, opts, wb);
/* [BrtSheetCalcProp] */

@ -24,7 +24,7 @@ function parse_BrtWbProp(data, length) {
return [dwThemeVersion, strName];
}
function write_BrtWbProp(data, o) {
if(!o) o = new_buf(68);
if(!o) o = new_buf(72);
o.write_shift(4, 0);
o.write_shift(4, 0);
write_XLSBCodeName("ThisWorkbook", o);
@ -85,6 +85,9 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
break;
case 0x040C: /* 'BrtNameExt' */ break;
/* case 'BrtModelTimeGroupingCalcCol' */
/* case 'BrtRevisionPtr' */
/* case 'BrtUid' */
case 0x0817: /* 'BrtAbsPath15' */
case 0x0216: /* 'BrtBookProtection' */
case 0x02A5: /* 'BrtBookProtectionIso' */
@ -100,11 +103,9 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
case 0x0299: /* 'BrtFnGroup' */
case 0x0850: /* 'BrtModelRelationship' */
case 0x084D: /* 'BrtModelTable' */
/* case 'BrtModelTimeGroupingCalcCol' */
case 0x0225: /* 'BrtOleSize' */
case 0x0805: /* 'BrtPivotTableRef' */
case 0x0169: /* 'BrtPlaceholderName' */
/* case 'BrtRevisionPtr' */
case 0x0254: /* 'BrtSmartTagType' */
case 0x029B: /* 'BrtSupAddin' */
case 0x0163: /* 'BrtSupBookSrc' */
@ -113,7 +114,6 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
case 0x081C: /* 'BrtTableSlicerCacheID' */
case 0x081B: /* 'BrtTableSlicerCacheIDs' */
case 0x0822: /* 'BrtTimelineCachePivotCacheID' */
/* case 'BrtUid' */
case 0x018D: /* 'BrtUserBookView' */
case 0x009A: /* 'BrtWbFactoid' */
case 0x0099: /* 'BrtWbProp' */
@ -132,8 +132,8 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
case 0x0010: /* 'BrtFRTArchID$' */ break;
default:
if((R_n||"").indexOf("Begin") > 0){}
else if((R_n||"").indexOf("End") > 0){}
if((R_n||"").indexOf("Begin") > 0){/* empty */}
else if((R_n||"").indexOf("End") > 0){/* empty */}
else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
}
}, opts);

@ -530,7 +530,7 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
/* WorksheetOptions */
case 'WorksheetOptions': switch(Rn[3]) {
case 'Visible':
if(Rn[0].slice(-2) === "/>"){}
if(Rn[0].slice(-2) === "/>"){/* empty */}
else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
case "SheetHidden": wsprops.Hidden = 1; break;
case "SheetVeryHidden": wsprops.Hidden = 2; break;
@ -729,12 +729,10 @@ function parse_xlml_xml(d, opts)/*:Workbook*/ {
default: seen = false;
} break;
/* Sorting */
case 'Sorting':
/* ConditionalFormatting */
case 'ConditionalFormatting':
/* DataValidation */
case 'DataValidation': switch(Rn[3]) {
case 'DataValidation':
switch(Rn[3]) {
case 'Range': break;
case 'Type': break;
case 'Min': break;
@ -889,7 +887,7 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb
if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
/* Visible */
if(!!wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
if(wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
else {
/* Selected */
for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;

@ -56,7 +56,7 @@ function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
if(p.t === 'z') return;
if(!p.XF) return;
try {
var fmtid = p.XF.ifmt||0;
var fmtid = p.z || p.XF.ifmt || 0;
if(opts.cellNF) p.z = SSF._table[fmtid];
} catch(e) { if(opts.WTF) throw e; }
if(!opts || opts.cellText !== false) try {
@ -179,6 +179,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
var last_Rn = '';
var file_depth = 0; /* TODO: make a real stack */
var BIFF2Fmt = 0;
var BIFF2FmtTable = [];
var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
var last_lbl;
@ -309,7 +310,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
out = options.dense ? [] : {};
} break;
case 'BOF': {
if(opts.biff !== 8){}
if(opts.biff !== 8){/* empty */}
else if(RecordType === 0x0009) opts.biff = 2;
else if(RecordType === 0x0209) opts.biff = 3;
else if(RecordType === 0x0409) opts.biff = 4;
@ -342,17 +343,20 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:'n'};
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'};
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 'BoolErr': {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t};
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 'RK': {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'};
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
@ -360,6 +364,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
for(var j = val.c; j <= val.C; ++j) {
var ixfe = val.rkrec[j-val.c][0];
temp_val= {ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'};
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:j, r:val.r}, temp_val, options);
}
@ -377,6 +382,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
}
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(val.cell, temp_val, options);
last_formula = val;
@ -389,6 +395,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
if(options.cellFormula) {
temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
}
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(last_formula.cell, temp_val, options);
last_formula = null;
@ -419,11 +426,13 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'LabelSst':
temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
temp_val.XF = XFs[temp_val.ixfe];
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'Blank': if(options.sheetStubs) {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'};
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
@ -431,6 +440,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
for(var _j = val.c; _j <= val.C; ++_j) {
var _ixfe = val.ixfe[_j-val.c];
temp_val= {ixfe:_ixfe, XF:XFs[_ixfe], t:'z'};
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:_j, r:val.r}, temp_val, options);
}
@ -439,6 +449,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'Label': case 'BIFF2STR':
temp_val=make_cell(val.val, val.ixfe, 's');
temp_val.XF = XFs[temp_val.ixfe];
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
@ -453,20 +464,23 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
SSF.load(val[1], val[0]);
} break;
case 'BIFF2FORMAT': {
SSF.load(val, BIFF2Fmt++);
BIFF2FmtTable[BIFF2Fmt++] = val;
for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break;
if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163);
} break;
case 'MergeCells': mergecells = mergecells.concat(val); break;
case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break;
case 'TxO': opts.lastobj.TxO = val; break;
case 'ImData': opts.lastobj.ImData = val; break;
case 'HLink': {
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
if(cc) cc.l = val[1];
}
}
} break;
case 'HLinkTooltip': {
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
@ -611,24 +625,24 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
//console.log("Zoom Level:", val[0]/val[1],val);
} break;
case 'SheetExt': {
/* empty */
} break;
case 'SheetExtOptional': {
/* empty */
} break;
/* VBA */
case 'ObNoMacros': {
/* empty */
} break;
case 'ObProj': {
/* empty */
} break;
case 'CodeName': {
/* empty */
} break;
case 'GUIDTypeLib': {
/* empty */
} break;
case 'WOpt': break; // TODO: WTF?
@ -657,7 +671,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
/* Explicitly Ignored */
case 'Excel9File': break;
case 'Units': break;
case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': case 'BuiltInFnGroupCount':
case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': case 'BuiltInFnGroupCount': break;
/* View Stuff */
case 'Window1': case 'Window2': case 'HideObj': case 'GridSet': case 'Guts':
case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd':
@ -724,13 +738,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
/* Drawing */
case 'ShapePropsStream': break;
case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
case 'ImData': break;
/* Pub Stuff */
case 'WebPub': case 'AutoWebPub':
case 'WebPub': case 'AutoWebPub': break;
/* Print Stuff */
case 'HeaderFooter': case 'HFPicture': case 'PLV':
case 'HorizontalPageBreaks': case 'VerticalPageBreaks':
case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break;
/* Behavioral */
case 'Backup': case 'CompressPictures': case 'Compat12': break;
@ -779,11 +792,11 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
function parse_props(cfb) {
/* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
var DSI = cfb.find('!DocumentSummaryInformation');
if(DSI) try { cfb.DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI); } catch(e) {}
if(DSI) try { cfb.DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI); } catch(e) {/* empty */}
/* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
var SI = cfb.find('!SummaryInformation');
if(SI) try { cfb.Summary = parse_PropertySetStream(SI, SummaryPIDSI); } catch(e) {}
if(SI) try { cfb.Summary = parse_PropertySetStream(SI, SummaryPIDSI); } catch(e) {/* empty */}
}
function parse_xlscfb(cfb/*:any*/, options/*:?ParseOpts*/)/*:Workbook*/ {

@ -1192,9 +1192,10 @@ var XLSRecordEnum = {
/*::[*/0x0007/*::]*/: { n:"String", f:parse_BIFF2STRING },
/*::[*/0x0008/*::]*/: { n:"BIFF2ROW", f:parsenoop },
/*::[*/0x000b/*::]*/: { n:"Index", f:parse_Index },
/*::[*/0x0016/*::]*/: { n:"ExternCount", f:parsenoop },
/*::[*/0x001e/*::]*/: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
/*::[*/0x001f/*::]*/: { n:"BIFF2FMTCNT", f:parsenoop }, /* 16-bit cnt of BIFF2FORMAT records */
/*::[*/0x0016/*::]*/: { n:"ExternCount", f:parsenoop },
/*::[*/0x0020/*::]*/: { n:"BIFF2COLINFO", f:parsenoop },
/*::[*/0x0021/*::]*/: { n:"Array", f:parse_Array },
/*::[*/0x0025/*::]*/: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
/*::[*/0x0032/*::]*/: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
@ -1202,7 +1203,7 @@ var XLSRecordEnum = {
/*::[*/0x0045/*::]*/: { n:"BIFF2FONTCLR", f:parsenoop },
/*::[*/0x0056/*::]*/: { n:"BIFF4FMTCNT", f:parsenoop }, /* 16-bit cnt, similar to BIFF2 */
/*::[*/0x007e/*::]*/: { n:"RK", f:parsenoop }, /* Not necessarily same as 0x027e */
/*::[*/0x007f/*::]*/: { n:"ImData", f:parsenoop },
/*::[*/0x007f/*::]*/: { n:"ImData", f:parse_ImData },
/*::[*/0x0087/*::]*/: { n:"Addin", f:parsenoop },
/*::[*/0x0088/*::]*/: { n:"Edg", f:parsenoop },
/*::[*/0x0089/*::]*/: { n:"Pub", f:parsenoop },

@ -312,7 +312,7 @@ var parse_content_xml = (function() {
try {
var AutoFilter = ods_to_csf_range_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[AutoFilter[0]]['!autofilter'] = { ref: AutoFilter[1] };
} catch(e) { }
} catch(e) {/* empty */}
break;
case 's': break; // <text:s>
@ -362,7 +362,8 @@ var parse_content_xml = (function() {
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
case 'event-listener':
break;
/* TODO: FODS Properties */
case 'initial-creator':
case 'creation-date':

@ -9,6 +9,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
make_ssf(SSF); SSF.load_table(wb.SSF);
// $FlowIgnore
opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
opts.ssf = wb.SSF;
}
opts.rels = {}; opts.wbrels = {};
opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0;
@ -37,7 +38,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
/*::if(!wb.Props) throw "unreachable"; */
f = "docProps/app.xml";
if(wb.Props && wb.Props.SheetNames){}
if(wb.Props && wb.Props.SheetNames){/* empty */}
else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
// $FlowIgnore
else wb.Props.SheetNames = wb.SheetNames.map(function(x,i) { return [(wb.Workbook.Sheets[i]||{}).Hidden != 2, x];}).filter(function(x) { return x[0]; }).map(function(x) { return x[1]; });
@ -126,5 +127,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
zip.file("[Content_Types].xml", write_ct(ct, opts));
zip.file('_rels/.rels', write_rels(opts.rels));
zip.file('xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
delete opts.revssf; delete opts.ssf;
return zip;
}

@ -141,7 +141,7 @@ function get_radio_value( radioName ) {
function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}

@ -41,7 +41,7 @@ function get_radio_value( radioName ) {
function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}

@ -141,7 +141,7 @@ function get_radio_value( radioName ) {
function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}

28
dist/xlsx.core.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

29
dist/xlsx.full.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

1286
dist/xlsx.js vendored

File diff suppressed because it is too large Load Diff

28
dist/xlsx.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map vendored

File diff suppressed because one or more lines are too long

@ -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,14 +19,30 @@ 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)

@ -1,17 +1,17 @@
## 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

35
docbits/15_phil.md Normal file

@ -0,0 +1,35 @@
## 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>

@ -38,7 +38,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).

@ -15,17 +15,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
}
}
}

@ -135,8 +135,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 |
| :---------- | :------: | :-------------------------------------------------- |

@ -61,6 +61,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+
@ -74,6 +77,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).

@ -1,17 +0,0 @@
## 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)

@ -54,6 +54,9 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<script src="xlsx.js"></script>
<script>
/*jshint browser:true */
/* eslint-env browser */
/* eslint no-use-before-define:0 */
/*global Uint8Array, Uint16Array, ArrayBuffer */
/*global XLSX */
var X = XLSX;
var XW = {
@ -124,7 +127,7 @@ function xw_xfer(data, cb) {
switch(e.data.t) {
case 'ready': break;
case 'e': console.error(e.data.d); break;
default: xx=ab2str(e.data).replace(/\n/g,"\\n").replace(/\r/g,"\\r"); console.log("done"); cb(JSON.parse(xx)); break;
default: var xx=ab2str(e.data).replace(/\n/g,"\\n").replace(/\r/g,"\\r"); console.log("done"); cb(JSON.parse(xx)); break;
}
};
if(rABS) {
@ -153,7 +156,7 @@ function get_radio_value( radioName ) {
function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = X.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
var roa = X.utils.sheet_to_json(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}
@ -187,12 +190,12 @@ function to_formulae(workbook) {
return result.join("\n");
}
var HTMLOUT = document.getElementById('htmlout');
function to_html(workbook) {
document.getElementById('htmlout').innerHTML = "";
var result = [];
HTMLOUT.innerHTML = "";
workbook.SheetNames.forEach(function(sheetName) {
var htmlstr = X.write(workbook, {sheet:sheetName, type:'binary', bookType:'html'});
document.getElementById('htmlout').innerHTML += htmlstr;
HTMLOUT.innerHTML += htmlstr;
});
}
@ -202,7 +205,9 @@ function b64it() {
var wb = X.read(tarea.value, {type: 'base64',WTF:wtf_mode});
process_wb(wb);
}
window.b64it = b64it;
var OUT = document.getElementById('out');
var global_wb;
function process_wb(wb) {
global_wb = wb;
@ -218,11 +223,12 @@ function process_wb(wb) {
default:
output = to_csv(wb);
}
if(out.innerText === undefined) out.textContent = output;
else out.innerText = output;
if(OUT.innerText === undefined) OUT.textContent = output;
else OUT.innerText = output;
if(typeof console !== 'undefined') console.log("output", new Date());
}
function setfmt() {if(global_wb) process_wb(global_wb); }
window.setfmt = setfmt;
var drop = document.getElementById('drop');
function handleDrop(e) {
@ -234,7 +240,7 @@ function handleDrop(e) {
var f = files[0];
{
var reader = new FileReader();
var name = f.name;
//var name = f.name;
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS, use_worker);
var data = e.target.result;
@ -277,7 +283,7 @@ function handleFile(e) {
var f = files[0];
{
var reader = new FileReader();
var name = f.name;
//var name = f.name;
reader.onload = function(e) {
if(typeof console !== 'undefined') console.log("onload", new Date(), rABS, use_worker);
var data = e.target.result;

@ -5,6 +5,7 @@
* [JS Ecosystem Demos](README.md#js-ecosystem-demos)
* [Optional Modules](README.md#optional-modules)
* [ECMAScript 5 Compatibility](README.md#ecmascript-5-compatibility)
- [Philosophy](README.md#philosophy)
- [Parsing Workbooks](README.md#parsing-workbooks)
* [Complete Examples](README.md#complete-examples)
* [Note on Streaming Read](README.md#note-on-streaming-read)
@ -79,4 +80,3 @@
* [Windows](README.md#windows)
- [License](README.md#license)
- [References](README.md#references)
- [Badges](README.md#badges)

@ -76,12 +76,23 @@ type SST = {
type Comment = any;
type ColInfo = {
MDW?:number; // Excel's "Max Digit Width" unit, always integral
width:number; // width in Excel's "Max Digit Width", width*256 is integral
wpx?:number; // width in screen pixels
wch?:number; // intermediate character calculation
type RowInfo = {
hidden:?boolean; // if true, the row is hidden
hpx?:number; // height in screen pixels
hpt?:number; // height in points
};
type ColInfo = {
hidden:?boolean; // if true, the column is hidden
wpx?:number; // width in screen pixels
width:number; // width in Excel's "Max Digit Width", width*256 is integral
wch?:number; // width in characters
MDW?:number; // Excel's "Max Digit Width" unit, always integral
};
type AOA = Array<Array<any> >;
*/

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.9.13",
"version": "0.10.0",
"author": "sheetjs",
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS (ODS/FODS/UOS) spreadsheet parser and writer",
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
@ -17,7 +17,7 @@
},
"dependencies": {
"exit-on-epipe":"~1.0.0",
"ssf":"~0.9.1",
"ssf":"~0.9.2",
"codepage":"~1.8.0",
"cfb":"~0.11.1",
"crc-32":"~1.0.2",

13
test.js

@ -12,7 +12,7 @@ if(process.env.WTF) {
opts.WTF = true;
opts.cellStyles = true;
}
var fullex = [".xlsb", ".xlsm", ".xlsx"/*, ".xlml"*/];
var fullex = [".xlsb", /*".xlsm",*/ ".xlsx"/*, ".xlml"*/];
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "xlml", "sylk", "dif"];
var ex = fullex.slice(); ex = ex.concat([".ods", ".xls", ".xml", ".fods"]);
if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
@ -1607,7 +1607,7 @@ describe('json output', function() {
});
});
describe('csv output', function() {
describe('csv', function() {
var data, ws;
var bef = (function() {
data = [
@ -1648,6 +1648,15 @@ describe('csv output', function() {
var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\nbaz,,qux,\n";
assert.equal(baseline, X.utils.sheet_to_csv(ws, {blankrows:false}));
});
it('should handle various line endings', function() {
var data = ["1,a", "2,b", "3,c"];
[ "\r", "\n", "\r\n" ].forEach(function(RS) {
var wb = X.read(data.join(RS), {type:'binary'});
assert.equal(get_cell(wb.Sheets.Sheet1, "A1").v, 1);
assert.equal(get_cell(wb.Sheets.Sheet1, "B3").v, "c");
assert.equal(wb.Sheets.Sheet1['!ref'], "A1:B3");
});
});
});
describe('js -> file -> js', function() {

@ -9,7 +9,7 @@ var DIF_XL = true;
var opts = {cellNF: true};
opts.type = "binary";
var fullex = [".xlsb", ".xlsm", ".xlsx"/*, ".xlml"*/];
var fullex = [".xlsb", /*".xlsm",*/ ".xlsx"/*, ".xlml"*/];
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "xlml", "sylk", "dif"];
var ex = fullex.slice(); ex = ex.concat([".ods", ".xls", ".xml", ".fods"]);
var exp = ex.map(function(x){ return x + ".pending"; });
@ -1005,7 +1005,7 @@ describe('parse features', function() {
for(var i = 0; i < names.length; ++i) if(names[i].Name == "SheetJS") break;
assert(i < names.length, "Missing name");
assert.equal(names[i].Sheet, null);
//assert.equal(names[i].Ref, "Sheet1!$A$1");
assert.equal(names[i].Ref, "Sheet1!$A$1");
if(m[2]) assert.equal(names[i].Comment, "defined names just suck excel formulae are bad MS should feel bad");
for(i = 0; i < names.length; ++i) if(names[i].Name == "SHEETjs") break;
@ -1481,7 +1481,7 @@ describe('json output', function() {
data = [
[1,2,3],
[true, false, null, "sheetjs"],
["foo","bar", parseDate("2014-02-19T14:30:00.000Z"), "0.3"],
["foo", "bar", parseDate("2014-02-19T14:30:00.000Z"), "0.3"],
["baz", undefined, "qux"]
];
ws = X.utils.aoa_to_sheet(data);
@ -1610,7 +1610,7 @@ describe('json output', function() {
});
});
describe('csv output', function() {
describe('csv', function() {
var data, ws;
var bef = (function() {
data = [
@ -1651,6 +1651,15 @@ describe('csv output', function() {
var baseline = "1,2,3,\nTRUE,FALSE,,sheetjs\nfoo,bar,2/19/14,0.3\nbaz,,qux,\n";
assert.equal(baseline, X.utils.sheet_to_csv(ws, {blankrows:false}));
});
it('should handle various line endings', function() {
var data = ["1,a", "2,b", "3,c"];
[ "\r", "\n", "\r\n" ].forEach(function(RS) {
var wb = X.read(data.join(RS), {type:'binary'});
assert.equal(get_cell(wb.Sheets.Sheet1, "A1").v, 1);
assert.equal(get_cell(wb.Sheets.Sheet1, "B3").v, "c");
assert.equal(wb.Sheets.Sheet1['!ref'], "A1:B3");
});
});
});
describe('js -> file -> js', function() {

@ -46,7 +46,7 @@
<script src="mocha.js"></script>
<script>
window.initMochaPhantomJS && window.initMochaPhantomJS();
mocha.setup('bdd');
mocha.setup({ui:'bdd', timeout:10000});
</script>
<script src="core.js"></script>
<script>

@ -76,8 +76,8 @@ ws['A3'].l = { Target: "http://sheetjs.com", Tooltip: "Visit us <SheetJS.com!>"
ws['B1'].z = "0%"; // Format Code 9
/* TEST: custom format */
wb.SSF = XLSX.SSF.get_table(); // <-- this will change in the future
ws['C2'].z = "0.0"; wb.SSF[60] = "0.0"; // Custom
var custfmt = "\"This is \"\\ 0.0";
ws['C2'].z = custfmt;
/* TEST: page margins */
ws['!margins'] = { left:1.0, right:1.0, top:1.0, bottom:1.0, header:0.5, footer:0.5 };
@ -122,30 +122,29 @@ ws['!protect'] = {
console.log("Worksheet Model:")
console.log(ws);
/* write file */
XLSX.writeFile(wb, 'sheetjs.xlsx', {bookSST:true});
XLSX.writeFile(wb, 'sheetjs.xlsm');
XLSX.writeFile(wb, 'sheetjs.xlsb'); // no formula
XLSX.writeFile(wb, 'sheetjs.xls', {bookType:'biff2'}); // no formula
XLSX.writeFile(wb, 'sheetjs.xml.xls', {bookType:'xlml'});
XLSX.writeFile(wb, 'sheetjs.ods');
XLSX.writeFile(wb, 'sheetjs.fods');
XLSX.writeFile(wb, 'sheetjs.slk');
XLSX.writeFile(wb, 'sheetjs.csv');
XLSX.writeFile(wb, 'sheetjs.txt');
XLSX.writeFile(wb, 'sheetjs.prn');
XLSX.writeFile(wb, 'sheetjs.dif');
/* test by reading back files */
XLSX.readFile('sheetjs.xlsx');
XLSX.readFile('sheetjs.xlsm');
XLSX.readFile('sheetjs.xlsb');
XLSX.readFile('sheetjs.xls');
XLSX.readFile('sheetjs.xml.xls');
XLSX.readFile('sheetjs.ods');
XLSX.readFile('sheetjs.fods');
XLSX.readFile('sheetjs.slk');
XLSX.readFile('sheetjs.csv');
XLSX.readFile('sheetjs.txt');
XLSX.readFile('sheetjs.prn');
XLSX.readFile('sheetjs.dif');
[
['sheetjs.xlsx', {bookSST:true}],
'sheetjs.xlsm',
'sheetjs.xlsb',
['sheetjs.xls', {bookType:'biff2'}],
['sheetjs.xml.xls', {bookType:'xlml'}],
'sheetjs.ods',
'sheetjs.fods',
'sheetjs.slk',
'sheetjs.csv',
'sheetjs.txt',
'sheetjs.prn',
'sheetjs.dif'
].forEach(function(r) {
if(typeof r == 'string') {
/* write file */
XLSX.writeFile(wb, r);
/* test by reading back files */
XLSX.readFile(r);
} else {
/* write file */
XLSX.writeFile(wb, r[0], r[1]);
/* test by reading back files */
XLSX.readFile(r[0]);
}
});

File diff suppressed because it is too large Load Diff

1287
xlsx.js

File diff suppressed because it is too large Load Diff