Merge changes from upsteam

This commit is contained in:
Pieter Sheth-Voss 2015-04-15 16:40:26 -04:00
commit 0b1a0408cb
72 changed files with 20394 additions and 871 deletions

15
.gitignore vendored

@ -3,8 +3,19 @@ misc/coverage.html
misc/prof.js
v8.log
tmp
*.txt
*.csv
*.dif
*.prn
*.slk
*.socialcalc
*.xls
*.xlsb
*.xlsm
*.xlsx
*.xlsm
*.xlsb
lab/
.idea/
*.xml
*.htm
*.html
*.sheetjs

4
.jshintrc Normal file

@ -0,0 +1,4 @@
{
"bitwise": false,
"curly": false
}

@ -4,11 +4,20 @@ index.html
misc/
node_modules
tmp
*.txt
*.csv
*.dif
*.prn
*.slk
*.socialcalc
*.xls
*.xlsb
*.xlsm
*.xlsx
*.xml
*.htm
*.html
*.sheetjs
.gitignore
.jshintrc
CONTRIBUTING.md

@ -1,8 +1,9 @@
language: node_js
node_js:
- "0.11"
- "iojs"
- "0.11.14"
- "0.10"
- "0.8"
# - "0.8" # commented because of npm issue with camelcase
before_install:
- "npm install -g mocha"
- "npm install blanket"

@ -5,7 +5,7 @@ order to maintain that, every contributor must be vigilant.
There have been many projects in the past that have been very lax regarding
licensing, and we are of the opinion that those are ticking timebombs and that
no corporate product should depend on them.
no commercial product should depend on them.
# Required Reading
@ -17,6 +17,17 @@ These are pretty short reads and emphasize the importance of proper licensing:
- http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html
# Raising Issues
Issues should generally be accompanied by test files. Since github does not
support attachments, the best method is to send files to <sheetjs@gmail.com>
(subject line should contain issue number or message) or to share using some
storage service. Unless expressly permitted, any attachments will not be
shared or included in a test suite (although I will ask :)
If sending email to a gmail account is problematic, the <dev@sheetjs.com> email
inbox is self-hosted.
# Pre-Contribution Checklist
Before thinking about contributing, make sure that:
@ -27,7 +38,7 @@ Before thinking about contributing, make sure that:
Corporation or a subsidiary
- You have not consulted any existing relevant codebase (if you have, please
take note of which codebases were consulted).
take note of which codebases were consulted).
If you cannot attest to each of these items, the best approach is to raise an
issue. If it is a particularly high-priority issue, please drop an email to
@ -45,9 +56,8 @@ Keep these in mind as you work:
- You are working on your own time. Unless they explicitly grant permission,
your employer may be the ultimate owner of your IP
# Post-Contribution
Before contributions are merged, you will receive an email (at the address
associated with the git commit) and will be asked to confirm the aforementioned
items.
items. Ensure that the email addresses associated with the commits is valid.

@ -1,4 +1,4 @@
Copyright (C) 2012-2014 SheetJS
Copyright (C) 2012-2015 SheetJS
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

@ -1,5 +1,5 @@
LIB=xlsx
FMT=xlsx xlsm xlsb ods misc full
FMT=xlsx xlsm xlsb ods xls xml misc full
REQS=jszip.js
ADDONS=dist/cpexcel.js
AUXTARGETS=ods.js
@ -17,6 +17,9 @@ $(TARGET): $(DEPS)
bits/01_version.js: package.json
echo "$(ULIB).version = '"`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`"';" > $@
bits/18_cfb.js: node_modules/cfb/dist/xlscfb.js
cp $^ $@
.PHONY: clean
clean:
rm -f $(TARGET)
@ -52,6 +55,7 @@ $(TESTFMT): test_%:
.PHONY: lint
lint: $(TARGET)
jshint --show-non-errors $(TARGET) $(AUXTARGETS)
jshint --show-non-errors package.json bower.json
jscs $(TARGET) $(AUXTARGETS)
.PHONY: test-osx
@ -88,8 +92,11 @@ dist: dist-deps $(TARGET) bower.json
cp $(TARGET) dist/
cp LICENSE dist/
uglifyjs $(TARGET) -o dist/$(LIB).min.js --source-map dist/$(LIB).min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/$(LIB).min.js
uglifyjs $(REQS) $(TARGET) -o dist/$(LIB).core.min.js --source-map dist/$(LIB).core.min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/$(LIB).core.min.js
uglifyjs $(REQS) $(ADDONS) $(TARGET) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/$(LIB).full.min.js
.PHONY: aux
aux: $(AUXTARGETS)

@ -1,8 +1,22 @@
# xlsx
Parser and writer for Excel 2007+ (XLSX/XLSM/XLSB) files and parser for ODS.
Pure-JS cleanroom implementation from the Office Open XML spec, [MS-XLSB], ODF
specifications and related documents.
Parser and writer for various spreadsheet formats. Pure-JS cleanroom
implementation from official specifications and related documents.
Supported read formats:
- Excel 2007+ XML Formats (XLSX/XLSM)
- Excel 2007+ Binary Format (XLSB)
- Excel 2003-2004 XML Format (XML "SpreadsheetML")
- Excel 97-2004 (XLS BIFF8)
- Excel 5.0/95 (XLS BIFF5)
- OpenDocument Spreadsheet (ODS)
Supported write formats:
- XLSX
- CSV (and general DSV)
- JSON and JS objects (various styles)
Demo: <http://oss.sheetjs.com/js-xlsx>
@ -10,7 +24,7 @@ Source: <http://git.io/xlsx>
## Installation
In [nodejs](https://www.npmjs.org/package/xlsx):
With [npm](https://www.npmjs.org/package/xlsx):
npm install xlsx
@ -18,7 +32,7 @@ In the browser:
<script lang="javascript" src="dist/xlsx.core.min.js"></script>
In [bower](http://bower.io/search/?q=js-xlsx):
With [bower](http://bower.io/search/?q=js-xlsx):
bower install js-xlsx
@ -27,7 +41,7 @@ CDNjs automatically pulls the latest version and makes all versions available at
## Optional Modules
The nodejs version automatically requires modules for additional features. Some
The node version automatically requires modules for additional features. Some
of these modules are rather large in size and are only needed in special
circumstances, so they do not ship with the core. For browser use, they must
be included directly:
@ -56,7 +70,7 @@ To use the shim, add the shim before the script tag that loads xlsx.js:
For parsing, the first step is to read the file. This involves acquiring the
data and feeding it into the library. Here are a few common scenarios:
- nodejs readFile:
- node readFile:
```
if(typeof require !== 'undefined') XLSX = require('xlsx');
@ -142,13 +156,32 @@ input_dom_element.addEventListener('change', handleFile, false);
## Working with the Workbook
This example walks through every cell of every sheet and dumps the values:
The full object format is described later in this README.
This example extracts the value stored in cell A1 from the first worksheet:
```
var first_sheet_name = workbook.SheetNames[0];
var address_of_cell = 'A1';
/* Get worksheet */
var worksheet = workbook.Sheets[first_sheet_name];
/* Find desired cell */
var desired_cell = worksheet[address_of_cell];
/* Get the value */
var desired_value = desired_cell.v;
```
This example iterates through every nonempty of every sheet and dumps values:
```
var sheet_name_list = workbook.SheetNames;
sheet_name_list.forEach(function(y) {
sheet_name_list.forEach(function(y) { /* iterate through sheets */
var worksheet = workbook.Sheets[y];
for (z in worksheet) {
/* all keys that do not begin with "!" correspond to cell addresses */
if(z[0] === '!') continue;
console.log(y + "!" + z + "=" + JSON.stringify(worksheet[z].v));
}
@ -166,9 +199,9 @@ mode is provided for testing. On OSX you can get the base64 encoding with:
- <http://oss.sheetjs.com/js-xlsx/ajax.html> XMLHttpRequest
- <https://github.com/SheetJS/js-xlsx/blob/master/bin/xlsx.njs> nodejs
- <https://github.com/SheetJS/js-xlsx/blob/master/bin/xlsx.njs> node
The nodejs version installs a binary `xlsx` which can read XLSX/XLSM/XLSB
The node version installs a command line tool `xlsx` which can read spreadsheet
files and output the contents in various formats. The source is available at
`xlsx.njs` in the bin directory.
@ -220,7 +253,7 @@ Complete examples:
## Interface
`XLSX` is the exposed variable in the browser and the exported nodejs variable
`XLSX` is the exposed variable in the browser and the exported node variable
`XLSX.version` is the version of the library (added by the build script).
@ -374,7 +407,8 @@ Special worksheet keys (accessible as `worksheet[key]`, each starting with `!`):
`wb.Sheets[sheetname]` returns an object representing the worksheet.
`wb.Props` is an object storing the standard properties. `wb.Custprops` stores
custom properties.
custom properties. Since the XLS standard properties deviate from the XLSX
standard, XLS parsing stores core properties in both places. .
## Parsing Options
@ -383,7 +417,7 @@ The exported `read` and `readFile` functions accept an options argument:
| Option Name | Default | Description |
| :---------- | ------: | :---------- |
| cellFormula | true | Save formulae to the .f field |
| cellFormula | true | Save formulae to the .f field ** |
| cellHTML | true | Parse rich text and save HTML to the .h field |
| cellNF | false | Save number format string to the .z field |
| cellStyles | false | Save style/theme info to the .s field |
@ -395,17 +429,24 @@ The exported `read` and `readFile` functions accept an options argument:
| bookProps | false | If true, only parse enough to get book metadata ** |
| bookSheets | false | If true, only parse enough to get the sheet names |
| bookVBA | false | If true, expose vbaProject.bin to `vbaraw` field ** |
| password | "" | If defined and file is encrypted, use password ** |
- `cellFormula` option only applies to formats that require extra processing to
parse formulae (XLS/XLSB).
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
- In some cases, sheets may be parsed even if `bookSheets` is false.
- `bookSheets` and `bookProps` combine to give both sets of information
- `Deps` will be an empty object if `bookDeps` is falsy
- `bookFiles` adds a `keys` array (paths in the ZIP) and a `files` hash (whose
keys are paths and values are objects representing the files)
- `bookFiles` behavior depends on file type:
* `keys` array (paths in the ZIP) for ZIP-based formats
* `files` hash (mapping paths to objects representing the files) for ZIP
* `cfb` object for formats using CFB containers
- `sheetRows-1` rows will be generated when looking at the JSON object output
(since the header row is counted as a row when parsing the data)
- `bookVBA` merely exposes the raw vba object. It does not parse the data.
- `cellDates` currently does not convert numerical dates to JS dates.
- Currently only XOR encryption is supported. Unsupported error will be thrown
for files employing other encryption methods.
The defaults are enumerated in bits/84_defaults.js
@ -502,7 +543,7 @@ Borders for merged areas are specified for each cell within the merged area. So
## Tested Environments
- NodeJS 0.8, 0.10 (latest release), 0.11 (unstable)
- NodeJS 0.8, 0.10 (latest release), 0.11.14 (unstable), io.js
- IE 6/7/8/9/10/11 using Base64 mode (IE10/11 using HTML5 mode)
- FF 18 using Base64 or HTML5 mode
- Chrome 24 using Base64 or HTML5 mode
@ -521,7 +562,7 @@ Running `make init` will refresh the `test_files` submodule and get the files.
## Testing
`make test` will run the nodejs-based tests. To run the in-browser tests, clone
`make test` will run the node-based tests. To run the in-browser tests, clone
[the oss.sheetjs.com repo](https://github.com/SheetJS/SheetJS.github.io) and
replace the xlsx.js file (then fire up the browser and go to `stress.html`):
@ -553,10 +594,6 @@ $ diff xlsx.js xlsx.new.js
To produce the dist files, run `make dist`. The dist files are updated in each
version release and should not be committed between versions.
## XLS Support
XLS is available in [js-xls](http://git.io/xls).
## License
Please consult the attached LICENSE file for details. All rights not explicitly
@ -578,7 +615,18 @@ OSP-covered specifications:
- [MS-XLSB]: Excel (.xlsb) Binary File Format
- [MS-XLSX]: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
- [MS-OE376]: Office Implementation Information for ECMA-376 Standards Support
- [MS-CFB]: Compound File Binary File Format
- [MS-XLS]: Excel Binary File Format (.xls) Structure Specification
- [MS-ODATA]: Open Data Protocol (OData)
- [MS-OFFCRYPTO]: Office Document Cryptography Structure
- [MS-OLEDS]: Object Linking and Embedding (OLE) Data Structures
- [MS-OLEPS]: Object Linking and Embedding (OLE) Property Set Data Structures
- [MS-OSHARED]: Office Common Data Types and Objects Structures
- [MS-OVBA]: Office VBA File Format Structure
- [MS-CTXLS]: Excel Custom Toolbar Binary File Format
- [MS-XLDM]: Spreadsheet Data Model File Format
- [MS-EXSPXML3]: Excel Calculation Version 2 Web Service XML Schema
- [XLS]: Microsoft Office Excel 97-2007 Binary File Format Specification
Open Document Format for Office Applications Version 1.2 (29 September 2011)

@ -1,5 +1,5 @@
#!/usr/bin/env node
/* xlsx.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/* xlsx.js (C) 2013-2015 SheetJS -- http://sheetjs.com */
var n = "xlsx";
/* vim: set ts=2 ft=javascript: */
var X = require('../');
@ -9,6 +9,7 @@ program
.usage('[options] <file> [sheetname]')
.option('-f, --file <file>', 'use specified workbook')
.option('-s, --sheet <sheet>', 'print specified sheet (default first sheet)')
.option('-p, --password <pw>', 'if file is encrypted, try with specified pw')
.option('-l, --list-sheets', 'list sheet names and exit')
.option('-o, --output <file>', 'output to specified file')
.option('-B, --xlsb', 'emit XLSB to <sheetname> or <file>.xlsb')
@ -67,6 +68,7 @@ if(!fs.existsSync(filename)) {
var opts = {}, wb;
if(program.listSheets) opts.bookSheets = true;
if(program.sheetRows) opts.sheetRows = program.sheetRows;
if(program.password) opts.password = program.password;
if(program.xlsx || program.xlsm || program.xlsb) {
opts.cellNF = true;
if(program.output) sheetname = program.output;

1
bits/.npmignore Normal file

@ -0,0 +1 @@
*.js

@ -1,5 +1,6 @@
/* xlsx.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/* xlsx.js (C) 2013-2015 SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true */
var XLSX = {};
(function(XLSX){
(function make_xlsx(XLSX){

@ -1 +1 @@
XLSX.version = '0.7.12';
XLSX.version = '0.8.0';

@ -1,18 +1,23 @@
var current_codepage = 1252, current_cptable;
var current_codepage = 1200, current_cptable;
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
current_cptable = cptable[current_codepage];
}
function reset_cp() { set_cp(1252); }
function reset_cp() { set_cp(1200); }
var set_cp = function(cp) { current_codepage = cp; };
function char_codes(data) { var o = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
var debom_xml = function(data) { return data; };
var _getchar = function _gc1(x) { return String.fromCharCode(x); };
if(typeof cptable !== 'undefined') {
set_cp = function(cp) { current_codepage = cp; current_cptable = cptable[cp]; };
debom_xml = function(data) {
if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.substr(2))); }
return data;
};
_getchar = function _gc2(x) {
if(current_codepage === 1200) return String.fromCharCode(x);
return cptable.utils.decode(current_codepage, [x&255,x>>8])[0];
};
}

41
bits/04_base64.js Normal file

@ -0,0 +1,41 @@
var Base64 = (function make_b64(){
var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
return {
encode: function(input, utf8) {
var o = "";
var c1, c2, c3, e1, e2, e3, e4;
for(var i = 0; i < input.length; ) {
c1 = input.charCodeAt(i++);
c2 = input.charCodeAt(i++);
c3 = input.charCodeAt(i++);
e1 = c1 >> 2;
e2 = (c1 & 3) << 4 | c2 >> 4;
e3 = (c2 & 15) << 2 | c3 >> 6;
e4 = c3 & 63;
if (isNaN(c2)) { e3 = e4 = 64; }
else if (isNaN(c3)) { e4 = 64; }
o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
}
return o;
},
decode: function b64_decode(input, utf8) {
var o = "";
var c1, c2, c3;
var e1, e2, e3, e4;
input = input.replace(/[^A-Za-z0-9\+\/\=]/g, "");
for(var i = 0; i < input.length;) {
e1 = map.indexOf(input.charAt(i++));
e2 = map.indexOf(input.charAt(i++));
e3 = map.indexOf(input.charAt(i++));
e4 = map.indexOf(input.charAt(i++));
c1 = e1 << 2 | e2 >> 4;
c2 = (e2 & 15) << 4 | e3 >> 2;
c3 = (e3 & 3) << 6 | e4;
o += String.fromCharCode(c1);
if (e3 != 64) { o += String.fromCharCode(c2); }
if (e4 != 64) { o += String.fromCharCode(c3); }
}
return o;
}
};
})();

16
bits/05_buf.js Normal file

@ -0,0 +1,16 @@
var has_buf = (typeof Buffer !== 'undefined');
function new_raw_buf(len) {
/* jshint -W056 */
return new (has_buf ? Buffer : Array)(len);
/* jshint +W056 */
}
function s2a(s) {
if(has_buf) return new Buffer(s, "binary");
return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
}
var bconcat = function(bufs) { return [].concat.apply([], bufs); };
var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/;

20
bits/11_ssfutils.js Normal file

@ -0,0 +1,20 @@
/* map from xlml named formats to SSF TODO: localize */
var XLMLFormatMap = {
"General Number": "General",
"General Date": SSF._table[22],
"Long Date": "dddd, mmmm dd, yyyy",
"Medium Date": SSF._table[15],
"Short Date": SSF._table[14],
"Long Time": SSF._table[19],
"Medium Time": SSF._table[18],
"Short Time": SSF._table[20],
"Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
"Fixed": SSF._table[2],
"Standard": SSF._table[4],
"Percent": SSF._table[10],
"Scientific": SSF._table[11],
"Yes/No": '"Yes";"Yes";"No";@',
"True/False": '"True";"True";"False";@',
"On/Off": '"Yes";"Yes";"No";@'
};

383
bits/18_cfb.js Normal file

@ -0,0 +1,383 @@
var DO_NOT_EXPORT_CFB = true;
/* cfb.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint eqnull:true */
/* [MS-CFB] v20130118 */
var CFB = (function _CFB(){
var exports = {};
exports.version = '0.10.2';
function parse(file) {
var mver = 3; // major version
var ssz = 512; // sector size
var nmfs = 0; // number of mini FAT sectors
var ndfs = 0; // number of DIFAT sectors
var dir_start = 0; // first directory sector location
var minifat_start = 0; // first mini FAT sector location
var difat_start = 0; // first mini FAT sector location
var fat_addrs = []; // locations of FAT sectors
/* [MS-CFB] 2.2 Compound File Header */
var blob = file.slice(0,512);
prep_blob(blob, 0);
/* major version */
var mv = check_get_mver(blob);
mver = mv[0];
switch(mver) {
case 3: ssz = 512; break; case 4: ssz = 4096; break;
default: throw "Major Version: Expected 3 or 4 saw " + mver;
}
/* reprocess header */
if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
/* Save header for final object */
var header = file.slice(0,ssz);
check_shifts(blob, mver);
// Number of Directory Sectors
var nds = blob.read_shift(4, 'i');
if(mver === 3 && nds !== 0) throw '# Directory Sectors: Expected 0 saw ' + nds;
// Number of FAT Sectors
//var nfs = blob.read_shift(4, 'i');
blob.l += 4;
// First Directory Sector Location
dir_start = blob.read_shift(4, 'i');
// Transaction Signature
blob.l += 4;
// Mini Stream Cutoff Size
blob.chk('00100000', 'Mini Stream Cutoff Size: ');
// First Mini FAT Sector Location
minifat_start = blob.read_shift(4, 'i');
// Number of Mini FAT Sectors
nmfs = blob.read_shift(4, 'i');
// First DIFAT sector location
difat_start = blob.read_shift(4, 'i');
// Number of DIFAT Sectors
ndfs = blob.read_shift(4, 'i');
// Grab FAT Sector Locations
for(var q, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
q = blob.read_shift(4, 'i');
if(q<0) break;
fat_addrs[j] = q;
}
/** Break the file up into sectors */
var sectors = sectorify(file, ssz);
sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs);
/** Chains */
var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);
sector_list[dir_start].name = "!Directory";
if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
sector_list[fat_addrs[0]].name = "!FAT";
sector_list.fat_addrs = fat_addrs;
sector_list.ssz = ssz;
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {};
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
var root_name = Paths.shift();
Paths.root = root_name;
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name);
return {
raw: {header: header, sectors: sectors},
FileIndex: FileIndex,
FullPaths: FullPaths,
FullPathDir: FullPathDir,
find: find_path
};
} // parse
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
function check_get_mver(blob) {
// header signature 8
blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
// clsid 16
blob.chk(HEADER_CLSID, 'CLSID: ');
// minor version 2
var mver = blob.read_shift(2, 'u');
return [blob.read_shift(2,'u'), mver];
}
function check_shifts(blob, mver) {
var shift = 0x09;
// Byte Order
blob.chk('feff', 'Byte Order: ');
// Sector Shift
switch((shift = blob.read_shift(2))) {
case 0x09: if(mver !== 3) throw 'MajorVersion/SectorShift Mismatch'; break;
case 0x0c: if(mver !== 4) throw 'MajorVersion/SectorShift Mismatch'; break;
default: throw 'Sector Shift: Expected 9 or 12 saw ' + shift;
}
// Mini Sector Shift
blob.chk('0600', 'Mini Sector Shift: ');
// Reserved
blob.chk('000000000000', 'Reserved: ');
}
/** Break the file up into sectors */
function sectorify(file, ssz) {
var nsectors = Math.ceil(file.length/ssz)-1;
var sectors = new Array(nsectors);
for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
sectors[nsectors-1] = file.slice(nsectors*ssz);
return sectors;
}
/* [MS-CFB] 2.6.4 Red-Black Tree */
function build_full_paths(FI, FPD, FP, Paths) {
var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
var dad = new Array(pl), q = new Array(pl);
for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
for(; j < q.length; ++j) {
i = q[j];
L = FI[i].L; R = FI[i].R; C = FI[i].C;
if(dad[i] === i) {
if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
}
if(C !== -1 /*NOSTREAM*/) dad[C] = i;
if(L !== -1) { dad[L] = dad[i]; q.push(L); }
if(R !== -1) { dad[R] = dad[i]; q.push(R); }
}
for(i=1; i !== pl; ++i) if(dad[i] === i) {
if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
}
for(i=1; i < pl; ++i) {
if(FI[i].type === 0 /* unknown */) continue;
j = dad[i];
if(j === 0) FP[i] = FP[0] + "/" + FP[i];
else while(j !== 0) {
FP[i] = FP[j] + "/" + FP[i];
j = dad[j];
}
dad[i] = 0;
}
FP[0] += "/";
for(i=1; i < pl; ++i) {
if(FI[i].type !== 2 /* stream */) FP[i] += "/";
FPD[FP[i]] = FI[i];
}
}
/* [MS-CFB] 2.6.4 */
function make_find_path(FullPaths, Paths, FileIndex, files, root_name) {
var UCFullPaths = new Array(FullPaths.length);
var UCPaths = new Array(Paths.length), i;
for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
return function find_path(path) {
var k;
if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; }
else k = path.indexOf("/") !== -1;
var UCPath = path.toUpperCase().replace(chr0,'').replace(chr1,'!');
var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
if(w === -1) return null;
return k === true ? FileIndex[w] : files[Paths[w]];
};
}
/** Chase down the rest of the DIFAT chain to build a comprehensive list
DIFAT chains by storing the next sector number as the last 32 bytes */
function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
var q;
if(idx === ENDOFCHAIN) {
if(cnt !== 0) throw "DIFAT chain shorter than expected";
} else if(idx !== -1 /*FREESECT*/) {
var sector = sectors[idx], m = (ssz>>>2)-1;
for(var i = 0; i < m; ++i) {
if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
fat_addrs.push(q);
}
sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
}
}
/** Follow the linked list of sectors for a given starting point */
function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
var sl = sectors.length;
var buf, buf_chain;
if(!chkd) chkd = new Array(sl);
var modulus = ssz - 1, j, jj;
buf = [];
buf_chain = [];
for(j=start; j>=0;) {
chkd[j] = true;
buf[buf.length] = j;
buf_chain.push(sectors[j]);
var addr = fat_addrs[Math.floor(j*4/ssz)];
jj = ((j*4) & modulus);
if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz;
j = __readInt32LE(sectors[addr], jj);
}
return {nodes: buf, data:__toBuffer([buf_chain])};
}
/** Chase down the sector linked lists */
function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
var sl = sectors.length, sector_list = new Array(sl);
var chkd = new Array(sl), buf, buf_chain;
var modulus = ssz - 1, i, j, k, jj;
for(i=0; i < sl; ++i) {
buf = [];
k = (i + dir_start); if(k >= sl) k-=sl;
if(chkd[k] === true) continue;
buf_chain = [];
for(j=k; j>=0;) {
chkd[j] = true;
buf[buf.length] = j;
buf_chain.push(sectors[j]);
var addr = fat_addrs[Math.floor(j*4/ssz)];
jj = ((j*4) & modulus);
if(ssz < 4 + jj) throw "FAT boundary crossed: " + j + " 4 "+ssz;
j = __readInt32LE(sectors[addr], jj);
}
sector_list[k] = {nodes: buf, data:__toBuffer([buf_chain])};
}
return sector_list;
}
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex) {
var blob;
var minifat_store = 0, pl = (Paths.length?2:0);
var sector = sector_list[dir_start].data;
var i = 0, namelen = 0, name, o, ctime, mtime;
for(; i < sector.length; i+= 128) {
blob = sector.slice(i, i+128);
prep_blob(blob, 64);
namelen = blob.read_shift(2);
if(namelen === 0) continue;
name = __utf16le(blob,0,namelen-pl);
Paths.push(name);
o = {
name: name,
type: blob.read_shift(1),
color: blob.read_shift(1),
L: blob.read_shift(4, 'i'),
R: blob.read_shift(4, 'i'),
C: blob.read_shift(4, 'i'),
clsid: blob.read_shift(16),
state: blob.read_shift(4, 'i')
};
ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
if(ctime !== 0) {
o.ctime = ctime; o.ct = read_date(blob, blob.l-8);
}
mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
if(mtime !== 0) {
o.mtime = mtime; o.mt = read_date(blob, blob.l-8);
}
o.start = blob.read_shift(4, 'i');
o.size = blob.read_shift(4, 'i');
if(o.type === 5) { /* root */
minifat_store = o.start;
if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
/*minifat_size = o.size;*/
} else if(o.size >= 4096 /* MSCSZ */) {
o.storage = 'fat';
if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
sector_list[o.start].name = o.name;
o.content = sector_list[o.start].data.slice(0,o.size);
prep_blob(o.content, 0);
} else {
o.storage = 'minifat';
if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN) {
o.content = sector_list[minifat_store].data.slice(o.start*MSSZ,o.start*MSSZ+o.size);
prep_blob(o.content, 0);
}
}
files[name] = o;
FileIndex.push(o);
}
}
function read_date(blob, offset) {
return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
}
var fs;
function readFileSync(filename, options) {
if(fs === undefined) fs = require('fs');
return parse(fs.readFileSync(filename), options);
}
function readSync(blob, options) {
switch(options !== undefined && options.type !== undefined ? options.type : "base64") {
case "file": return readFileSync(blob, options);
case "base64": return parse(s2a(Base64.decode(blob)), options);
case "binary": return parse(s2a(blob), options);
}
return parse(blob);
}
/** CFB Constants */
var MSSZ = 64; /* Mini Sector Size = 1<<6 */
//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
/* 2.1 Compound File Sector Numbers and Types */
var ENDOFCHAIN = -2;
/* 2.2 Compound File Header */
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
var HEADER_CLSID = '00000000000000000000000000000000';
var consts = {
/* 2.1 Compund File Sector Numbers and Types */
MAXREGSECT: -6,
DIFSECT: -4,
FATSECT: -3,
ENDOFCHAIN: ENDOFCHAIN,
FREESECT: -1,
/* 2.2 Compound File Header */
HEADER_SIGNATURE: HEADER_SIGNATURE,
HEADER_MINOR_VERSION: '3e00',
MAXREGSID: -6,
NOSTREAM: -1,
HEADER_CLSID: HEADER_CLSID,
/* 2.6.1 Compound File Directory Entry */
EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
};
exports.read = readSync;
exports.parse = parse;
exports.utils = {
ReadShift: ReadShift,
CheckField: CheckField,
prep_blob: prep_blob,
bconcat: bconcat,
consts: consts
};
return exports;
})();
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }

@ -42,4 +42,3 @@ function cc2str(arr) {
return o;
}
var has_buf = (typeof Buffer !== 'undefined');

@ -1,4 +1,4 @@
var attregexg=/\b[\w:]+=["'][^"]*['"]/g;
var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
@ -31,17 +31,27 @@ var rencoding = evert(encodings);
var rencstr = "&<>'\"".split("");
// TODO: CP remap (need to read file version to determine OS)
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]+)_/g;
function unescapexml(text){
var s = text + '';
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
}
var unescapexml = (function() {
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]+)_/g;
return function unescapexml(text){
var s = text + '';
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
};
})();
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
function escapexml(text){
var s = text + '';
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
}
/* TODO: handle codepages */
var xlml_fixstr = (function() {
var entregex = /&#(\d+);/g;
function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
})();
function parsexmlbool(value, tag) {
switch(value) {
case '1': case 'true': case 'TRUE': return true;
@ -158,3 +168,4 @@ XMLNS.main = [
'http://schemas.microsoft.com/office/excel/2006/main',
'http://schemas.microsoft.com/office/excel/2006/2'
];

@ -18,16 +18,39 @@ function readIEEE754(buf, idx, isLE, nl, ml) {
var __toBuffer, ___toBuffer;
__toBuffer = ___toBuffer = function toBuffer_(bufs) { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; };
var __utf16le, ___utf16le;
__utf16le = ___utf16le = function utf16le_(b,s,e) { var ss=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join(""); };
var __hexlify, ___hexlify;
__hexlify = ___hexlify = function hexlify_(b,s,l) { return b.slice(s,(s+l)).map(function(x){return (x<16?"0":"") + x.toString(16);}).join(""); };
var __utf8, ___utf8;
__utf8 = ___utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
var __lpstr, ___lpstr;
__lpstr = ___lpstr = function lpstr_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
var __lpwstr, ___lpwstr;
__lpwstr = ___lpwstr = function lpwstr_(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
var __double, ___double;
__double = ___double = function(b, idx) { return readIEEE754(b, idx);};
var is_buf = function is_buf_a(a) { return Array.isArray(a); };
if(has_buf) {
__utf16le = function utf16le_b(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e); };
__hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
__lpstr = function lpstr_b(b,i) { if(!Buffer.isBuffer(b)) return ___lpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
__lpwstr = function lpwstr_b(b,i) { if(!Buffer.isBuffer(b)) return ___lpwstr(b, i); var len = 2*b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len-1);};
__utf8 = function utf8_b(s,e) { return this.toString('utf8',s,e); };
__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
__double = function double_(b,i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
}
/* from js-xls */
if(typeof cptable !== 'undefined') {
__utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)); };
__utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
__lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";};
__lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len-1)) : "";};
}
var __readUInt8 = function(b, idx) { return b[idx]; };
var __readUInt16LE = function(b, idx) { return b[idx+1]*(1<<8)+b[idx]; };
@ -35,20 +58,70 @@ var __readInt16LE = function(b, idx) { var u = b[idx+1]*(1<<8)+b[idx]; return (u
var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
var ___unhexlify = function(s) { return s.match(/../g).map(function(x) { return parseInt(x,16);}); };
var __unhexlify = typeof Buffer !== "undefined" ? function(s) { return Buffer.isBuffer(s) ? new Buffer(s, 'hex') : ___unhexlify(s); } : ___unhexlify;
function ReadShift(size, t) {
var o="", oo=[], w, vv, i, loc;
if(t === 'dbcs') {
loc = this.l;
if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
else for(i = 0; i != size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
size *= 2;
} else switch(size) {
case 1: o = __readUInt8(this, this.l); break;
case 2: o = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); break;
case 4: o = __readUInt32LE(this, this.l); break;
case 8: if(t === 'f') { o = __double(this, this.l); break; }
}
var o="", oI, oR, oo=[], w, vv, i, loc;
switch(t) {
case 'dbcs':
loc = this.l;
if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
else for(i = 0; i != size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
size *= 2;
break;
case 'utf8': o = __utf8(this, this.l, this.l + size); break;
case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break;
/* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
case 'lpwstr': o = __lpwstr(this, this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break;
case 'cstr': size = 0; o = "";
while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
o = oo.join(""); break;
case 'wstr': size = 0; o = "";
while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
size+=2; o = oo.join(""); break;
/* sbcs and dbcs support continue records in the SST way TODO codepages */
case 'dbcs-cont': o = ""; loc = this.l;
for(i = 0; i != size; ++i) {
if(this.lens && this.lens.indexOf(loc) !== -1) {
w = __readUInt8(this, loc);
this.l = loc + 1;
vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
return oo.join("") + vv;
}
oo.push(_getchar(__readUInt16LE(this, loc)));
loc+=2;
} o = oo.join(""); size *= 2; break;
case 'sbcs-cont': o = ""; loc = this.l;
for(i = 0; i != size; ++i) {
if(this.lens && this.lens.indexOf(loc) !== -1) {
w = __readUInt8(this, loc);
this.l = loc + 1;
vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
return oo.join("") + vv;
}
oo.push(_getchar(__readUInt8(this, loc)));
loc+=1;
} o = oo.join(""); break;
default:
switch(size) {
case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
case 4:
if(t === 'i' || (this[this.l+3] & 0x80)===0) { oI = __readInt32LE(this, this.l); this.l += 4; return oI; }
else { oR = __readUInt32LE(this, this.l); this.l += 4; return oR; } break;
case 8: if(t === 'f') { oR = __double(this, this.l); this.l += 8; return oR; }
/* falls through */
case 16: o = __hexlify(this, this.l, size); break;
}}
this.l+=size; return o;
}
@ -69,9 +142,16 @@ function WriteShift(t, val, f) {
this.l += size; return this;
}
function CheckField(hexstr, fld) {
var m = __hexlify(this,this.l,hexstr.length>>1);
if(m !== hexstr) throw fld + 'Expected ' + hexstr + ' saw ' + m;
this.l += hexstr.length>>1;
}
function prep_blob(blob, pos) {
blob.l = pos;
blob.read_shift = ReadShift;
blob.chk = CheckField;
blob.write_shift = WriteShift;
}
@ -80,7 +160,7 @@ function parsenoop(blob, length) { blob.l += length; }
function writenoop(blob, length) { blob.l += length; }
function new_buf(sz) {
var o = has_buf ? new Buffer(sz) : new Array(sz);
var o = new_raw_buf(sz);
prep_blob(o, 0);
return o;
}

@ -5,7 +5,7 @@ function recordhopper(data, cb, opts) {
while(data.l < data.length) {
var RT = data.read_shift(1);
if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
var R = RecordEnum[RT] || RecordEnum[0xFFFF];
var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
tmpbyte = data.read_shift(1);
length = tmpbyte & 0x7F;
for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
@ -49,7 +49,7 @@ function buf_array() {
function write_record(ba, type, payload, length) {
var t = evert_RE[type], l;
if(!length) length = RecordEnum[t].p || (payload||[]).length || 0;
if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
l = 1 + (t >= 0x80 ? 1 : 0) + 1 + length;
if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
var o = ba.next(l);

21
bits/25_cellutils.js Normal file

@ -0,0 +1,21 @@
/* XLS ranges enforced */
function shift_cell_xls(cell, tgt) {
if(tgt.s) {
if(cell.cRel) cell.c += tgt.s.c;
if(cell.rRel) cell.r += tgt.s.r;
} else {
cell.c += tgt.c;
cell.r += tgt.r;
}
cell.cRel = cell.rRel = 0;
while(cell.c >= 0x100) cell.c -= 0x100;
while(cell.r >= 0x10000) cell.r -= 0x10000;
return cell;
}
function shift_range_xls(cell, range) {
cell.s = shift_cell_xls(cell.s, range.s);
cell.e = shift_cell_xls(cell.e, range.s);
return cell;
}

35
bits/26_crypto.js Normal file

@ -0,0 +1,35 @@
var OFFCRYPTO = {};
var make_offcrypto = function(O, _crypto) {
var crypto;
if(typeof _crypto !== 'undefined') crypto = _crypto;
else if(typeof require !== 'undefined') {
try { crypto = require('cry'+'pto'); }
catch(e) { crypto = null; }
}
O.rc4 = function(key, data) {
var S = new Array(256);
var c = 0, i = 0, j = 0, t = 0;
for(i = 0; i != 256; ++i) S[i] = i;
for(i = 0; i != 256; ++i) {
j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
t = S[i]; S[i] = S[j]; S[j] = t;
}
i = j = 0; out = Buffer(data.length);
for(c = 0; c != data.length; ++c) {
i = (i + 1)&255;
j = (j + S[i])%256;
t = S[i]; S[i] = S[j]; S[j] = t;
out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
}
return out;
};
if(crypto) {
O.md5 = function(hex) { return crypto.createHash('md5').update(hex).digest('hex'); };
} else {
O.md5 = function(hex) { throw "unimplemented"; };
}
};
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);

@ -33,14 +33,14 @@ function write_RichStr(str, o) {
}
/* [MS-XLSB] 2.5.9 */
function parse_Cell(data) {
function parse_XLSBCell(data) {
var col = data.read_shift(4);
var iStyleRef = data.read_shift(2);
iStyleRef += data.read_shift(1) <<16;
var fPhShow = data.read_shift(1);
return { c:col, iStyleRef: iStyleRef };
}
function write_Cell(cell, o) {
function write_XLSBCell(cell, o) {
if(o == null) o = new_buf(8);
o.write_shift(-4, cell.c);
o.write_shift(3, cell.iStyleRef === undefined ? cell.iStyleRef : cell.s);
@ -50,7 +50,7 @@ function write_Cell(cell, o) {
/* [MS-XLSB] 2.5.21 */
function parse_CodeName (data, length) { return parse_XLWideString(data, length); }
function parse_XLSBCodeName (data, length) { return parse_XLWideString(data, length); }
/* [MS-XLSB] 2.5.166 */
function parse_XLNullableWideString(data) {
@ -82,11 +82,12 @@ var write_RelID = write_XLNullableWideString;
/* [MS-XLSB] 2.5.122 */
/* [MS-XLS] 2.5.217 */
function parse_RkNumber(data) {
var b = data.slice(data.l, data.l+4);
var fX100 = b[0] & 1, fInt = b[0] & 2;
data.l+=4;
b[0] &= 0xFC;
b[0] &= 0xFC; // b[0] &= ~3;
var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
return fX100 ? RK/100 : RK;
}
@ -111,6 +112,7 @@ function write_UncheckedRfX(r, o) {
}
/* [MS-XLSB] 2.5.171 */
/* [MS-XLS] 2.5.342 */
function parse_Xnum(data, length) { return data.read_shift(8, 'f'); }
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, 'f', data); }

265
bits/29_xlsenum.js Normal file

@ -0,0 +1,265 @@
/* [MS-OLEPS] 2.2 PropertyType */
{
var VT_EMPTY = 0x0000;
var VT_NULL = 0x0001;
var VT_I2 = 0x0002;
var VT_I4 = 0x0003;
var VT_R4 = 0x0004;
var VT_R8 = 0x0005;
var VT_CY = 0x0006;
var VT_DATE = 0x0007;
var VT_BSTR = 0x0008;
var VT_ERROR = 0x000A;
var VT_BOOL = 0x000B;
var VT_VARIANT = 0x000C;
var VT_DECIMAL = 0x000E;
var VT_I1 = 0x0010;
var VT_UI1 = 0x0011;
var VT_UI2 = 0x0012;
var VT_UI4 = 0x0013;
var VT_I8 = 0x0014;
var VT_UI8 = 0x0015;
var VT_INT = 0x0016;
var VT_UINT = 0x0017;
var VT_LPSTR = 0x001E;
var VT_LPWSTR = 0x001F;
var VT_FILETIME = 0x0040;
var VT_BLOB = 0x0041;
var VT_STREAM = 0x0042;
var VT_STORAGE = 0x0043;
var VT_STREAMED_Object = 0x0044;
var VT_STORED_Object = 0x0045;
var VT_BLOB_Object = 0x0046;
var VT_CF = 0x0047;
var VT_CLSID = 0x0048;
var VT_VERSIONED_STREAM = 0x0049;
var VT_VECTOR = 0x1000;
var VT_ARRAY = 0x2000;
var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
var VT_CUSTOM = [VT_STRING, VT_USTR];
}
/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
var DocSummaryPIDDSI = {
0x01: { n: 'CodePage', t: VT_I2 },
0x02: { n: 'Category', t: VT_STRING },
0x03: { n: 'PresentationFormat', t: VT_STRING },
0x04: { n: 'ByteCount', t: VT_I4 },
0x05: { n: 'LineCount', t: VT_I4 },
0x06: { n: 'ParagraphCount', t: VT_I4 },
0x07: { n: 'SlideCount', t: VT_I4 },
0x08: { n: 'NoteCount', t: VT_I4 },
0x09: { n: 'HiddenCount', t: VT_I4 },
0x0a: { n: 'MultimediaClipCount', t: VT_I4 },
0x0b: { n: 'Scale', t: VT_BOOL },
0x0c: { n: 'HeadingPair', t: VT_VECTOR | VT_VARIANT },
0x0d: { n: 'DocParts', t: VT_VECTOR | VT_LPSTR },
0x0e: { n: 'Manager', t: VT_STRING },
0x0f: { n: 'Company', t: VT_STRING },
0x10: { n: 'LinksDirty', t: VT_BOOL },
0x11: { n: 'CharacterCount', t: VT_I4 },
0x13: { n: 'SharedDoc', t: VT_BOOL },
0x16: { n: 'HLinksChanged', t: VT_BOOL },
0x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
0x1A: { n: 'ContentType', t: VT_STRING },
0x1B: { n: 'ContentStatus', t: VT_STRING },
0x1C: { n: 'Language', t: VT_STRING },
0x1D: { n: 'Version', t: VT_STRING },
0xFF: {}
};
/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
var SummaryPIDSI = {
0x01: { n: 'CodePage', t: VT_I2 },
0x02: { n: 'Title', t: VT_STRING },
0x03: { n: 'Subject', t: VT_STRING },
0x04: { n: 'Author', t: VT_STRING },
0x05: { n: 'Keywords', t: VT_STRING },
0x06: { n: 'Comments', t: VT_STRING },
0x07: { n: 'Template', t: VT_STRING },
0x08: { n: 'LastAuthor', t: VT_STRING },
0x09: { n: 'RevNumber', t: VT_STRING },
0x0A: { n: 'EditTime', t: VT_FILETIME },
0x0B: { n: 'LastPrinted', t: VT_FILETIME },
0x0C: { n: 'CreatedDate', t: VT_FILETIME },
0x0D: { n: 'ModifiedDate', t: VT_FILETIME },
0x0E: { n: 'PageCount', t: VT_I4 },
0x0F: { n: 'WordCount', t: VT_I4 },
0x10: { n: 'CharCount', t: VT_I4 },
0x11: { n: 'Thumbnail', t: VT_CF },
0x12: { n: 'ApplicationName', t: VT_LPSTR },
0x13: { n: 'DocumentSecurity', t: VT_I4 },
0xFF: {}
};
/* [MS-OLEPS] 2.18 */
var SpecialProperties = {
0x80000000: { n: 'Locale', t: VT_UI4 },
0x80000003: { n: 'Behavior', t: VT_UI4 },
0x72627262: {}
};
(function() {
for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
})();
/* [MS-XLS] 2.4.63 Country/Region codes */
var CountryEnum = {
0x0001: "US", // United States
0x0002: "CA", // Canada
0x0003: "", // Latin America (except Brazil)
0x0007: "RU", // Russia
0x0014: "EG", // Egypt
0x001E: "GR", // Greece
0x001F: "NL", // Netherlands
0x0020: "BE", // Belgium
0x0021: "FR", // France
0x0022: "ES", // Spain
0x0024: "HU", // Hungary
0x0027: "IT", // Italy
0x0029: "CH", // Switzerland
0x002B: "AT", // Austria
0x002C: "GB", // United Kingdom
0x002D: "DK", // Denmark
0x002E: "SE", // Sweden
0x002F: "NO", // Norway
0x0030: "PL", // Poland
0x0031: "DE", // Germany
0x0034: "MX", // Mexico
0x0037: "BR", // Brazil
0x003d: "AU", // Australia
0x0040: "NZ", // New Zealand
0x0042: "TH", // Thailand
0x0051: "JP", // Japan
0x0052: "KR", // Korea
0x0054: "VN", // Viet Nam
0x0056: "CN", // China
0x005A: "TR", // Turkey
0x0069: "JS", // Ramastan
0x00D5: "DZ", // Algeria
0x00D8: "MA", // Morocco
0x00DA: "LY", // Libya
0x015F: "PT", // Portugal
0x0162: "IS", // Iceland
0x0166: "FI", // Finland
0x01A4: "CZ", // Czech Republic
0x0376: "TW", // Taiwan
0x03C1: "LB", // Lebanon
0x03C2: "JO", // Jordan
0x03C3: "SY", // Syria
0x03C4: "IQ", // Iraq
0x03C5: "KW", // Kuwait
0x03C6: "SA", // Saudi Arabia
0x03CB: "AE", // United Arab Emirates
0x03CC: "IL", // Israel
0x03CE: "QA", // Qatar
0x03D5: "IR", // Iran
0xFFFF: "US" // United States
};
/* [MS-XLS] 2.5.127 */
var XLSFillPattern = [
null,
'solid',
'mediumGray',
'darkGray',
'lightGray',
'darkHorizontal',
'darkVertical',
'darkDown',
'darkUp',
'darkGrid',
'darkTrellis',
'lightHorizontal',
'lightVertical',
'lightDown',
'lightUp',
'lightGrid',
'lightTrellis',
'gray125',
'gray0625'
];
function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
/* [MS-XLS] 2.5.161 */
var XLSIcv = rgbify([
/* Color Constants */
0x000000,
0xFFFFFF,
0xFF0000,
0x00FF00,
0x0000FF,
0xFFFF00,
0xFF00FF,
0x00FFFF,
/* Defaults */
0x000000,
0xFFFFFF,
0xFF0000,
0x00FF00,
0x0000FF,
0xFFFF00,
0xFF00FF,
0x00FFFF,
0x800000,
0x008000,
0x000080,
0x808000,
0x800080,
0x008080,
0xC0C0C0,
0x808080,
0x9999FF,
0x993366,
0xFFFFCC,
0xCCFFFF,
0x660066,
0xFF8080,
0x0066CC,
0xCCCCFF,
0x000080,
0xFF00FF,
0xFFFF00,
0x00FFFF,
0x800080,
0x800000,
0x008080,
0x0000FF,
0x00CCFF,
0xCCFFFF,
0xCCFFCC,
0xFFFF99,
0x99CCFF,
0xFF99CC,
0xCC99FF,
0xFFCC99,
0x3366FF,
0x33CCCC,
0x99CC00,
0xFFCC00,
0xFF9900,
0xFF6600,
0x666699,
0x969696,
0x003366,
0x339966,
0x003300,
0x333300,
0x993300,
0x993366,
0x333399,
0x333333,
/* Sheet */
0xFFFFFF,
0x000000
]);

8
bits/36_xlsprops.js Normal file

@ -0,0 +1,8 @@
function xlml_set_prop(Props, tag, val) {
/* TODO: Normalize the properties */
switch(tag) {
case 'Description': tag = 'Comments'; break;
}
Props[tag] = val;
}

440
bits/38_xlstypes.js Normal file

@ -0,0 +1,440 @@
/* [MS-DTYP] 2.3.3 FILETIME */
/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
function parse_FILETIME(blob) {
var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
}
/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
function parse_lpstr(blob, type, pad) {
var str = blob.read_shift(0, 'lpstr');
if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
return str;
}
/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
function parse_lpwstr(blob, type, pad) {
var str = blob.read_shift(0, 'lpwstr');
if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
return str;
}
/* [MS-OSHARED] 2.3.3.1.11 VtString */
/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
function parse_VtStringBase(blob, stringType, pad) {
if(stringType === 0x1F /*VT_LPWSTR*/) return parse_lpwstr(blob);
return parse_lpstr(blob, stringType, pad);
}
function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("dafuq?"); return parse_VtStringBase(blob, t, 0); }
/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
function parse_VtVecUnalignedLpstrValue(blob) {
var length = blob.read_shift(4);
var ret = [];
for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr');
return ret;
}
/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
function parse_VtVecUnalignedLpstr(blob) {
return parse_VtVecUnalignedLpstrValue(blob);
}
/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
function parse_VtHeadingPair(blob) {
var headingString = parse_TypedPropertyValue(blob, VT_USTR);
var headerParts = parse_TypedPropertyValue(blob, VT_I4);
return [headingString, headerParts];
}
/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
function parse_VtVecHeadingPairValue(blob) {
var cElements = blob.read_shift(4);
var out = [];
for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
return out;
}
/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
function parse_VtVecHeadingPair(blob) {
// NOTE: When invoked, wType & padding were already consumed
return parse_VtVecHeadingPairValue(blob);
}
/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
function parse_dictionary(blob,CodePage) {
var cnt = blob.read_shift(4);
var dict = {};
for(var j = 0; j != cnt; ++j) {
var pid = blob.read_shift(4);
var len = blob.read_shift(4);
dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
}
if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
return dict;
}
/* [MS-OLEPS] 2.9 BLOB */
function parse_BLOB(blob) {
var size = blob.read_shift(4);
var bytes = blob.slice(blob.l,blob.l+size);
if(size & 3 > 0) blob.l += (4 - (size & 3)) & 3;
return bytes;
}
/* [MS-OLEPS] 2.11 ClipboardData */
function parse_ClipboardData(blob) {
// TODO
var o = {};
o.Size = blob.read_shift(4);
//o.Format = blob.read_shift(4);
blob.l += o.Size;
return o;
}
/* [MS-OLEPS] 2.14 Vector and Array Property Types */
function parse_VtVector(blob, cb) {
/* [MS-OLEPS] 2.14.2 VectorHeader */
/* var Length = blob.read_shift(4);
var o = [];
for(var i = 0; i != Length; ++i) {
o.push(cb(blob));
}
return o;*/
}
/* [MS-OLEPS] 2.15 TypedPropertyValue */
function parse_TypedPropertyValue(blob, type, _opts) {
var t = blob.read_shift(2), ret, opts = _opts||{};
blob.l += 2;
if(type !== VT_VARIANT)
if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
switch(type === VT_VARIANT ? t : type) {
case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw && 4).replace(chr0,'');
case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t, 4).replace(chr0,'');
case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
}
}
/* [MS-OLEPS] 2.14.2 VectorHeader */
/*function parse_VTVectorVariant(blob) {
var Length = blob.read_shift(4);
if(Length & 1 !== 0) throw new Error("VectorHeader Length=" + Length + " must be even");
var o = [];
for(var i = 0; i != Length; ++i) {
o.push(parse_TypedPropertyValue(blob, VT_VARIANT));
}
return o;
}*/
/* [MS-OLEPS] 2.20 PropertySet */
function parse_PropertySet(blob, PIDSI) {
var start_addr = blob.l;
var size = blob.read_shift(4);
var NumProps = blob.read_shift(4);
var Props = [], i = 0;
var CodePage = 0;
var Dictionary = -1, DictObj;
for(i = 0; i != NumProps; ++i) {
var PropID = blob.read_shift(4);
var Offset = blob.read_shift(4);
Props[i] = [PropID, Offset + start_addr];
}
var PropH = {};
for(i = 0; i != NumProps; ++i) {
if(blob.l !== Props[i][1]) {
var fail = true;
if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
case 0x02 /*VT_I2*/: if(blob.l +2 === Props[i][1]) { blob.l+=2; fail = false; } break;
case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
}
if(!PIDSI && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
}
if(PIDSI) {
var piddsi = PIDSI[Props[i][0]];
PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + String(PropH[piddsi.n] & 0xFFFF);
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
set_cp(CodePage = PropH[piddsi.n]); break;
default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
}
} else {
if(Props[i][0] === 0x1) {
CodePage = PropH.CodePage = parse_TypedPropertyValue(blob, VT_I2);
set_cp(CodePage);
if(Dictionary !== -1) {
var oldpos = blob.l;
blob.l = Props[Dictionary][1];
DictObj = parse_dictionary(blob,CodePage);
blob.l = oldpos;
}
} else if(Props[i][0] === 0) {
if(CodePage === 0) { Dictionary = i; blob.l = Props[i+1][1]; continue; }
DictObj = parse_dictionary(blob,CodePage);
} else {
var name = DictObj[Props[i][0]];
var val;
/* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
switch(blob[blob.l]) {
case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]); break;
case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]); break;
case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
case 0x0B /*VT_BOOL*/: blob.l += 4; val = parsebool(blob, 4); break;
case 0x40 /*VT_FILETIME*/: blob.l += 4; val = new Date(parse_FILETIME(blob)); break;
default: throw new Error("unparsed value: " + blob[blob.l]);
}
PropH[name] = val;
}
}
}
blob.l = start_addr + size; /* step ahead to skip padding */
return PropH;
}
/* [MS-OLEPS] 2.21 PropertySetStream */
function parse_PropertySetStream(file, PIDSI) {
var blob = file.content;
prep_blob(blob, 0);
var NumSets, FMTID0, FMTID1, Offset0, Offset1;
blob.chk('feff', 'Byte Order: ');
var vers = blob.read_shift(2); // TODO: check version
var SystemIdentifier = blob.read_shift(4);
blob.chk(CFB.utils.consts.HEADER_CLSID, 'CLSID: ');
NumSets = blob.read_shift(4);
if(NumSets !== 1 && NumSets !== 2) throw "Unrecognized #Sets: " + NumSets;
FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
if(NumSets === 1 && Offset0 !== blob.l) throw "Length mismatch";
else if(NumSets === 2) { FMTID1 = blob.read_shift(16); Offset1 = blob.read_shift(4); }
var PSet0 = parse_PropertySet(blob, PIDSI);
var rval = { SystemIdentifier: SystemIdentifier };
for(var y in PSet0) rval[y] = PSet0[y];
//rval.blob = blob;
rval.FMTID = FMTID0;
//rval.PSet0 = PSet0;
if(NumSets === 1) return rval;
if(blob.l !== Offset1) throw "Length mismatch 2: " + blob.l + " !== " + Offset1;
var PSet1;
try { PSet1 = parse_PropertySet(blob, null); } catch(e) { }
for(y in PSet1) rval[y] = PSet1[y];
rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
return rval;
}
function parsenoop2(blob, length) { blob.read_shift(length); return null; }
function parslurp(blob, length, cb) {
var arr = [], target = blob.l + length;
while(blob.l < target) arr.push(cb(blob, target - blob.l));
if(target !== blob.l) throw new Error("Slurp error");
return arr;
}
function parslurp2(blob, length, cb) {
var arr = [], target = blob.l + length, len = blob.read_shift(2);
while(len-- !== 0) arr.push(cb(blob, target - blob.l));
if(target !== blob.l) throw new Error("Slurp error");
return arr;
}
function parsebool(blob, length) { return blob.read_shift(length) === 0x1; }
function parseuint16(blob) { return blob.read_shift(2, 'u'); }
function parseuint16a(blob, length) { return parslurp(blob,length,parseuint16);}
/* --- 2.5 Structures --- */
/* [MS-XLS] 2.5.14 Boolean */
var parse_Boolean = parsebool;
/* [MS-XLS] 2.5.10 Bes (boolean or error) */
function parse_Bes(blob) {
var v = blob.read_shift(1), t = blob.read_shift(1);
return t === 0x01 ? v : v === 0x01;
}
/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
function parse_ShortXLUnicodeString(blob, length, opts) {
var cch = blob.read_shift(1);
var width = 1, encoding = 'sbcs-cont';
var cp = current_codepage;
if(opts && opts.biff >= 8) current_codepage = 1200;
if(opts === undefined || opts.biff !== 5) {
var fHighByte = blob.read_shift(1);
if(fHighByte) { width = 2; encoding = 'dbcs-cont'; }
}
var o = cch ? blob.read_shift(cch, encoding) : "";
current_codepage = cp;
return o;
}
/* 2.5.293 XLUnicodeRichExtendedString */
function parse_XLUnicodeRichExtendedString(blob) {
var cp = current_codepage;
current_codepage = 1200;
var cch = blob.read_shift(2), flags = blob.read_shift(1);
var fHighByte = flags & 0x1, fExtSt = flags & 0x4, fRichSt = flags & 0x8;
var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
var cRun, cbExtRst;
var z = {};
if(fRichSt) cRun = blob.read_shift(2);
if(fExtSt) cbExtRst = blob.read_shift(4);
var encoding = (flags & 0x1) ? 'dbcs-cont' : 'sbcs-cont';
var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
if(fExtSt) blob.l += cbExtRst; //TODO: parse this
z.t = msg;
if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
current_codepage = cp;
return z;
}
/* 2.5.296 XLUnicodeStringNoCch */
function parse_XLUnicodeStringNoCch(blob, cch, opts) {
var retval;
var fHighByte = blob.read_shift(1);
if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
else { retval = blob.read_shift(cch, 'dbcs-cont'); }
return retval;
}
/* 2.5.294 XLUnicodeString */
function parse_XLUnicodeString(blob, length, opts) {
var cch = blob.read_shift(opts !== undefined && opts.biff > 0 && opts.biff < 8 ? 1 : 2);
if(cch === 0) { blob.l++; return ""; }
return parse_XLUnicodeStringNoCch(blob, cch, opts);
}
/* BIFF5 override */
function parse_XLUnicodeString2(blob, length, opts) {
if(opts.biff !== 5 && opts.biff !== 2) return parse_XLUnicodeString(blob, length, opts);
var cch = blob.read_shift(1);
if(cch === 0) { blob.l++; return ""; }
return blob.read_shift(cch, 'sbcs-cont');
}
/* [MS-XLS] 2.5.61 ControlInfo */
var parse_ControlInfo = parsenoop;
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
var parse_URLMoniker = function(blob, length) {
var len = blob.read_shift(4), start = blob.l;
var extra = false;
if(len > 24) {
/* look ahead */
blob.l += len - 24;
if(blob.read_shift(16) === "795881f43b1d7f48af2c825dc4852763") extra = true;
blob.l = start;
}
var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
if(extra) blob.l += 24;
return url;
};
/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
var parse_FileMoniker = function(blob, length) {
var cAnti = blob.read_shift(2);
var ansiLength = blob.read_shift(4);
var ansiPath = blob.read_shift(ansiLength, 'cstr');
var endServer = blob.read_shift(2);
var versionNumber = blob.read_shift(2);
var cbUnicodePathSize = blob.read_shift(4);
if(cbUnicodePathSize === 0) return ansiPath.replace(/\\/g,"/");
var cbUnicodePathBytes = blob.read_shift(4);
var usKeyValue = blob.read_shift(2);
var unicodePath = blob.read_shift(cbUnicodePathBytes>>1, 'utf16le').replace(chr0,"");
return unicodePath;
};
/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
var parse_HyperlinkMoniker = function(blob, length) {
var clsid = blob.read_shift(16); length -= 16;
switch(clsid) {
case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
default: throw "unsupported moniker " + clsid;
}
};
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
var parse_HyperlinkString = function(blob, length) {
var len = blob.read_shift(4);
var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
return o;
};
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
var parse_Hyperlink = function(blob, length) {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
var flags = blob.read_shift(2);
blob.l += 2;
var displayName, targetFrameName, moniker, oleMoniker, location, guid, fileTime;
if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0020) guid = blob.read_shift(16);
if(flags & 0x0040) fileTime = parse_FILETIME(blob, 8);
blob.l = end;
var target = (targetFrameName||moniker||oleMoniker);
if(location) target+="#"+location;
return {Target: target};
};
/* 2.5.178 LongRGBA */
function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
/* 2.5.177 LongRGB */
function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }

917
bits/39_xlsbiff.js Normal file

@ -0,0 +1,917 @@
/* --- MS-XLS --- */
/* 2.5.19 */
function parse_XLSCell(blob, length) {
var rw = blob.read_shift(2); // 0-indexed
var col = blob.read_shift(2);
var ixfe = blob.read_shift(2);
return {r:rw, c:col, ixfe:ixfe};
}
/* 2.5.134 */
function parse_frtHeader(blob) {
var rt = blob.read_shift(2);
var flags = blob.read_shift(2); // TODO: parse these flags
blob.l += 8;
return {type: rt, flags: flags};
}
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
/* 2.5.158 */
var HIDEOBJENUM = ['SHOWALL', 'SHOWPLACEHOLDER', 'HIDEALL'];
var parse_HideObjEnum = parseuint16;
/* 2.5.344 */
function parse_XTI(blob, length) {
var iSupBook = blob.read_shift(2), itabFirst = blob.read_shift(2,'i'), itabLast = blob.read_shift(2,'i');
return [iSupBook, itabFirst, itabLast];
}
/* 2.5.218 */
function parse_RkRec(blob, length) {
var ixfe = blob.read_shift(2);
var RK = parse_RkNumber(blob);
//console.log("::", ixfe, RK,";;");
return [ixfe, RK];
}
/* 2.5.1 */
function parse_AddinUdf(blob, length) {
blob.l += 4; length -= 4;
var l = blob.l + length;
var udfName = parse_ShortXLUnicodeString(blob, length);
var cb = blob.read_shift(2);
l -= blob.l;
if(cb !== l) throw "Malformed AddinUdf: padding = " + l + " != " + cb;
blob.l += cb;
return udfName;
}
/* 2.5.209 TODO: Check sizes */
function parse_Ref8U(blob, length) {
var rwFirst = blob.read_shift(2);
var rwLast = blob.read_shift(2);
var colFirst = blob.read_shift(2);
var colLast = blob.read_shift(2);
return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
}
/* 2.5.211 */
function parse_RefU(blob, length) {
var rwFirst = blob.read_shift(2);
var rwLast = blob.read_shift(2);
var colFirst = blob.read_shift(1);
var colLast = blob.read_shift(1);
return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
}
/* 2.5.207 */
var parse_Ref = parse_RefU;
/* 2.5.143 */
function parse_FtCmo(blob, length) {
blob.l += 4;
var ot = blob.read_shift(2);
var id = blob.read_shift(2);
var flags = blob.read_shift(2);
blob.l+=12;
return [id, ot, flags];
}
/* 2.5.149 */
function parse_FtNts(blob, length) {
var out = {};
blob.l += 4;
blob.l += 16; // GUID TODO
out.fSharedNote = blob.read_shift(2);
blob.l += 4;
return out;
}
/* 2.5.142 */
function parse_FtCf(blob, length) {
var out = {};
blob.l += 4;
blob.cf = blob.read_shift(2);
return out;
}
/* 2.5.140 - 2.5.154 and friends */
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 */
};
function parse_FtArray(blob, length, ot) {
var s = blob.l;
var fts = [];
while(blob.l < s + length) {
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; }
}
if(blob.l != s + length) blob.l = s + length; //throw "bad Object Ft-sequence";
return fts;
}
/* 2.5.129 */
var parse_FontIndex = parseuint16;
/* --- 2.4 Records --- */
/* 2.4.21 */
function parse_BOF(blob, length) {
var o = {};
o.BIFFVer = blob.read_shift(2); length -= 2;
switch(o.BIFFVer) {
case 0x0600: /* BIFF8 */
case 0x0500: /* BIFF5 */
case 0x0002: case 0x0007: /* BIFF2 */
break;
default: throw "Unexpected BIFF Ver " + o.BIFFVer;
}
blob.read_shift(length);
return o;
}
/* 2.4.146 */
function parse_InterfaceHdr(blob, length) {
if(length === 0) return 0x04b0;
var q;
if((q=blob.read_shift(2))!==0x04b0) throw 'InterfaceHdr codePage ' + q;
return 0x04b0;
}
/* 2.4.349 */
function parse_WriteAccess(blob, length, opts) {
if(opts.enc) { blob.l += length; return ""; }
var l = blob.l;
// TODO: make sure XLUnicodeString doesnt overrun
var UserName = parse_XLUnicodeString(blob, 0, opts);
blob.read_shift(length + l - blob.l);
return UserName;
}
/* 2.4.28 */
function parse_BoundSheet8(blob, length, opts) {
var pos = blob.read_shift(4);
var hidden = blob.read_shift(1) >> 6;
var dt = blob.read_shift(1);
switch(dt) {
case 0: dt = 'Worksheet'; break;
case 1: dt = 'Macrosheet'; break;
case 2: dt = 'Chartsheet'; break;
case 6: dt = 'VBAModule'; break;
}
var name = parse_ShortXLUnicodeString(blob, 0, opts);
if(name.length === 0) name = "Sheet1";
return { pos:pos, hs:hidden, dt:dt, name:name };
}
/* 2.4.265 TODO */
function parse_SST(blob, length) {
var cnt = blob.read_shift(4);
var ucnt = blob.read_shift(4);
var strs = [];
for(var i = 0; i != ucnt; ++i) {
strs.push(parse_XLUnicodeRichExtendedString(blob));
}
strs.Count = cnt; strs.Unique = ucnt;
return strs;
}
/* 2.4.107 */
function parse_ExtSST(blob, length) {
var extsst = {};
extsst.dsst = blob.read_shift(2);
blob.l += length-2;
return extsst;
}
/* 2.4.221 TODO*/
function parse_Row(blob, length) {
var rw = blob.read_shift(2), col = blob.read_shift(2), Col = blob.read_shift(2), rht = blob.read_shift(2);
blob.read_shift(4); // reserved(2), unused(2)
var flags = blob.read_shift(1); // various flags
blob.read_shift(1); // reserved
blob.read_shift(2); //ixfe, other flags
return {r:rw, c:col, cnt:Col-col};
}
/* 2.4.125 */
function parse_ForceFullCalculation(blob, length) {
var header = parse_frtHeader(blob);
if(header.type != 0x08A3) throw "Invalid Future Record " + header.type;
var fullcalc = blob.read_shift(4);
return fullcalc !== 0x0;
}
var parse_CompressPictures = parsenoop2; /* 2.4.55 Not interesting */
/* 2.4.215 rt */
function parse_RecalcId(blob, length) {
blob.read_shift(2);
return blob.read_shift(4);
}
/* 2.4.87 */
function parse_DefaultRowHeight (blob, length) {
var f = blob.read_shift(2), miyRw;
miyRw = blob.read_shift(2); // flags & 0x02 -> hidden, else empty
var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
return [fl, miyRw];
}
/* 2.4.345 TODO */
function parse_Window1(blob, length) {
var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
}
/* 2.4.122 TODO */
function parse_Font(blob, length, opts) {
blob.l += 14;
var name = parse_ShortXLUnicodeString(blob, 0, opts);
return name;
}
/* 2.4.149 */
function parse_LabelSst(blob, length) {
var cell = parse_XLSCell(blob);
cell.isst = blob.read_shift(4);
return cell;
}
/* 2.4.148 */
function parse_Label(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
var str = parse_XLUnicodeString(blob, length-6, opts);
cell.val = str;
return cell;
}
/* 2.4.126 Number Formats */
function parse_Format(blob, length, opts) {
var ifmt = blob.read_shift(2);
var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
return [ifmt, fmtstr];
}
/* 2.4.90 */
function parse_Dimensions(blob, length) {
var w = length === 10 ? 2 : 4;
var r = blob.read_shift(w), R = blob.read_shift(w),
c = blob.read_shift(2), C = blob.read_shift(2);
blob.l += 2;
return {s: {r:r, c:c}, e: {r:R, c:C}};
}
/* 2.4.220 */
function parse_RK(blob, length) {
var rw = blob.read_shift(2), col = blob.read_shift(2);
var rkrec = parse_RkRec(blob);
return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
}
/* 2.4.175 */
function parse_MulRk(blob, length) {
var target = blob.l + length - 2;
var rw = blob.read_shift(2), col = blob.read_shift(2);
var rkrecs = [];
while(blob.l < target) rkrecs.push(parse_RkRec(blob));
if(blob.l !== target) throw "MulRK read error";
var lastcol = blob.read_shift(2);
if(rkrecs.length != lastcol - col + 1) throw "MulRK length mismatch";
return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
}
/* 2.5.20 2.5.249 TODO */
function parse_CellStyleXF(blob, length, style) {
var o = {};
var a = blob.read_shift(4), b = blob.read_shift(4);
var c = blob.read_shift(4), d = blob.read_shift(2);
o.patternType = XLSFillPattern[c >> 26];
o.icvFore = d & 0x7F;
o.icvBack = (d >> 7) & 0x7F;
return o;
}
function parse_CellXF(blob, length) {return parse_CellStyleXF(blob,length,0);}
function parse_StyleXF(blob, length) {return parse_CellStyleXF(blob,length,1);}
/* 2.4.353 TODO: actually do this right */
function parse_XF(blob, length) {
var o = {};
o.ifnt = blob.read_shift(2); o.ifmt = blob.read_shift(2); o.flags = blob.read_shift(2);
o.fStyle = (o.flags >> 2) & 0x01;
length -= 6;
o.data = parse_CellStyleXF(blob, length, o.fStyle);
return o;
}
/* 2.4.134 */
function parse_Guts(blob, length) {
blob.l += 4;
var out = [blob.read_shift(2), blob.read_shift(2)];
if(out[0] !== 0) out[0]--;
if(out[1] !== 0) out[1]--;
if(out[0] > 7 || out[1] > 7) throw "Bad Gutters: " + out;
return out;
}
/* 2.4.24 */
function parse_BoolErr(blob, length) {
var cell = parse_XLSCell(blob, 6);
var val = parse_Bes(blob, 2);
cell.val = val;
cell.t = (val === true || val === false) ? 'b' : 'e';
return cell;
}
/* 2.4.180 Number */
function parse_Number(blob, length) {
var cell = parse_XLSCell(blob, 6);
var xnum = parse_Xnum(blob, 8);
cell.val = xnum;
return cell;
}
var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
/* 2.4.271 */
function parse_SupBook(blob, length, opts) {
var end = blob.l + length;
var ctab = blob.read_shift(2);
var cch = blob.read_shift(2);
var virtPath;
if(cch >=0x01 && cch <=0xff) virtPath = parse_XLUnicodeStringNoCch(blob, cch);
var rgst = blob.read_shift(end - blob.l);
opts.sbcch = cch;
return [cch, ctab, virtPath, rgst];
}
/* 2.4.105 TODO */
function parse_ExternName(blob, length, opts) {
var flags = blob.read_shift(2);
var body;
var o = {
fBuiltIn: flags & 0x01,
fWantAdvise: (flags >>> 1) & 0x01,
fWantPict: (flags >>> 2) & 0x01,
fOle: (flags >>> 3) & 0x01,
fOleLink: (flags >>> 4) & 0x01,
cf: (flags >>> 5) & 0x3FF,
fIcon: flags >>> 15 & 0x01
};
if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2);
//else throw new Error("unsupported SupBook cch: " + opts.sbcch);
o.body = body || blob.read_shift(length-2);
return o;
}
/* 2.4.150 TODO */
function parse_Lbl(blob, length, opts) {
if(opts.biff < 8) return parse_Label(blob, length, opts);
var target = blob.l + length;
var flags = blob.read_shift(2);
var chKey = blob.read_shift(1);
var cch = blob.read_shift(1);
var cce = blob.read_shift(2);
blob.l += 2;
var itab = blob.read_shift(2);
blob.l += 4;
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
var rgce = parse_NameParsedFormula(blob, target - blob.l, opts, cce);
return {
chKey: chKey,
Name: name,
rgce: rgce
};
}
/* 2.4.106 TODO: verify supbook manipulation */
function parse_ExternSheet(blob, length, opts) {
if(opts.biff < 8) return parse_ShortXLUnicodeString(blob, length, opts);
var o = parslurp2(blob,length,parse_XTI);
var oo = [];
if(opts.sbcch === 0x0401) {
for(var i = 0; i != o.length; ++i) oo.push(opts.snames[o[i][1]]);
return oo;
}
else return o;
}
/* 2.4.260 */
function parse_ShrFmla(blob, length, opts) {
var ref = parse_RefU(blob, 6);
blob.l++;
var cUse = blob.read_shift(1);
length -= 8;
return [parse_SharedParsedFormula(blob, length, opts), cUse];
}
/* 2.4.4 TODO */
function parse_Array(blob, length, opts) {
var ref = parse_Ref(blob, 6);
blob.l += 6; length -= 12; /* TODO: fAlwaysCalc */
return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
}
/* 2.4.173 */
function parse_MTRSettings(blob, length) {
var fMTREnabled = blob.read_shift(4) !== 0x00;
var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
var cUserThreadCount = blob.read_shift(4);
return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
}
/* 2.5.186 TODO: BIFF5 */
function parse_NoteSh(blob, length, opts) {
if(opts.biff < 8) return;
var row = blob.read_shift(2), col = blob.read_shift(2);
var flags = blob.read_shift(2), idObj = blob.read_shift(2);
var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
if(opts.biff < 8) blob.read_shift(1);
return [{r:row,c:col}, stAuthor, idObj, flags];
}
/* 2.4.179 */
function parse_Note(blob, length, opts) {
/* TODO: Support revisions */
return parse_NoteSh(blob, length, opts);
}
/* 2.4.168 */
function parse_MergeCells(blob, length) {
var merges = [];
var cmcs = blob.read_shift(2);
while (cmcs--) merges.push(parse_Ref8U(blob,length));
return merges;
}
/* 2.4.181 TODO: parse all the things! */
function parse_Obj(blob, length) {
var cmo = parse_FtCmo(blob, 22); // id, ot, flags
var fts = parse_FtArray(blob, length-22, cmo[1]);
return { cmo: cmo, ft:fts };
}
/* 2.4.329 TODO: parse properly */
function parse_TxO(blob, length, opts) {
var s = blob.l;
try {
blob.l += 4;
var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
var controlInfo;
if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
else controlInfo = parse_ControlInfo(blob, 6, opts);
var cchText = blob.read_shift(2);
var cbRuns = blob.read_shift(2);
var ifntEmpty = parse_FontIndex(blob, 2);
var len = blob.read_shift(2);
blob.l += len;
//var fmla = parse_ObjFmla(blob, s + length - blob.l);
var texts = "";
for(var i = 1; i < blob.lens.length-1; ++i) {
if(blob.l-s != blob.lens[i]) throw "TxO: bad continue record";
var hdr = blob[blob.l];
var t = parse_XLUnicodeStringNoCch(blob, blob.lens[i+1]-blob.lens[i]-1);
texts += t;
if(texts.length >= (hdr ? cchText : 2*cchText)) break;
}
if(texts.length !== cchText && texts.length !== cchText*2) {
throw "cchText: " + cchText + " != " + texts.length;
}
blob.l = s + length;
/* 2.5.272 TxORuns */
// var rgTxoRuns = [];
// for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
// var cchText2 = blob.read_shift(2);
// if(cchText2 !== cchText) throw "TxOLastRun mismatch: " + cchText2 + " " + cchText;
// blob.l += 6;
// if(s + length != blob.l) throw "TxO " + (s + length) + ", at " + blob.l;
return { t: texts };
} catch(e) { blob.l = s + length; return { t: texts||"" }; }
}
/* 2.4.140 */
var parse_HLink = function(blob, length) {
var ref = parse_Ref8U(blob, 8);
blob.l += 16; /* CLSID */
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
};
/* 2.4.141 */
var parse_HLinkTooltip = function(blob, length) {
var end = blob.l + length;
blob.read_shift(2);
var ref = parse_Ref8U(blob, 8);
var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
};
/* 2.4.63 */
function parse_Country(blob, length) {
var o = [], d;
d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
return o;
}
/* 2.4.50 ClrtClient */
function parse_ClrtClient(blob, length) {
var ccv = blob.read_shift(2);
var o = [];
while(ccv-->0) o.push(parse_LongRGB(blob, 8));
return o;
}
/* 2.4.188 */
function parse_Palette(blob, length) {
var ccv = blob.read_shift(2);
var o = [];
while(ccv-->0) o.push(parse_LongRGB(blob, 8));
return o;
}
/* 2.4.354 */
function parse_XFCRC(blob, length) {
blob.l += 2;
var o = {cxfs:0, crc:0};
o.cxfs = blob.read_shift(2);
o.crc = blob.read_shift(4);
return o;
}
var parse_Style = parsenoop;
var parse_StyleExt = parsenoop;
var parse_ColInfo = 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 */
var parse_BuiltInFnGroupCount = parseuint16; /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */
var parse_CalcCount = parseuint16; /* 2.4.31 #Iterations */
var parse_CalcDelta = parse_Xnum; /* 2.4.32 */
var parse_CalcIter = parsebool; /* 2.4.33 1=iterative calc */
var parse_CalcMode = parseuint16; /* 2.4.34 0=manual, 1=auto (def), 2=table */
var parse_CalcPrecision = parsebool; /* 2.4.35 */
var parse_CalcRefMode = parsenoop2; /* 2.4.36 */
var parse_CalcSaveRecalc = parsebool; /* 2.4.37 */
var parse_CodePage = parseuint16; /* 2.4.52 */
var parse_Compat12 = parsebool; /* 2.4.54 true = no compatibility check */
var parse_Date1904 = parsebool; /* 2.4.77 - 1=1904,0=1900 */
var parse_DefColWidth = parseuint16; /* 2.4.89 */
var parse_DSF = parsenoop2; /* 2.4.94 -- MUST be ignored */
var parse_EntExU2 = parsenoop2; /* 2.4.102 -- Explicitly says to ignore */
var parse_EOF = parsenoop2; /* 2.4.103 */
var parse_Excel9File = parsenoop2; /* 2.4.104 -- Optional and unused */
var parse_FeatHdr = parsenoop2; /* 2.4.112 */
var parse_FontX = parseuint16; /* 2.4.123 */
var parse_Footer = parse_XLHeaderFooter; /* 2.4.124 */
var parse_GridSet = parseuint16; /* 2.4.132, =1 */
var parse_HCenter = parsebool; /* 2.4.135 sheet centered horizontal on print */
var parse_Header = parse_XLHeaderFooter; /* 2.4.136 */
var parse_HideObj = parse_HideObjEnum; /* 2.4.139 */
var parse_InterfaceEnd = parsenoop2; /* 2.4.145 -- noop */
var parse_LeftMargin = parse_Xnum; /* 2.4.151 */
var parse_Mms = parsenoop2; /* 2.4.169 -- Explicitly says to ignore */
var parse_ObjProtect = parsebool; /* 2.4.183 -- must be 1 if present */
var parse_Password = parseuint16; /* 2.4.191 */
var parse_PrintGrid = parsebool; /* 2.4.202 */
var parse_PrintRowCol = parsebool; /* 2.4.203 */
var parse_PrintSize = parseuint16; /* 2.4.204 0:3 */
var parse_Prot4Rev = parsebool; /* 2.4.205 */
var parse_Prot4RevPass = parseuint16; /* 2.4.206 */
var parse_Protect = parsebool; /* 2.4.207 */
var parse_RefreshAll = parsebool; /* 2.4.217 -- must be 0 if not template */
var parse_RightMargin = parse_Xnum; /* 2.4.219 */
var parse_RRTabId = parseuint16a; /* 2.4.241 */
var parse_ScenarioProtect = parsebool; /* 2.4.245 */
var parse_Scl = parseuint16a; /* 2.4.247 num, den */
var parse_String = parse_XLUnicodeString; /* 2.4.268 */
var parse_SxBool = parsebool; /* 2.4.274 */
var parse_TopMargin = parse_Xnum; /* 2.4.328 */
var parse_UsesELFs = parsebool; /* 2.4.337 -- should be 0 */
var parse_VCenter = parsebool; /* 2.4.342 */
var parse_WinProtect = parsebool; /* 2.4.347 */
var parse_WriteProtect = parsenoop; /* 2.4.350 empty record */
/* ---- */
var parse_VerticalPageBreaks = parsenoop;
var parse_HorizontalPageBreaks = parsenoop;
var parse_Selection = parsenoop;
var parse_Continue = parsenoop;
var parse_Pane = parsenoop;
var parse_Pls = parsenoop;
var parse_DCon = parsenoop;
var parse_DConRef = parsenoop;
var parse_DConName = parsenoop;
var parse_XCT = parsenoop;
var parse_CRN = parsenoop;
var parse_FileSharing = parsenoop;
var parse_Uncalced = parsenoop;
var parse_Template = parsenoop;
var parse_Intl = parsenoop;
var parse_WsBool = parsenoop;
var parse_Sort = parsenoop;
var parse_Sync = parsenoop;
var parse_LPr = parsenoop;
var parse_DxGCol = parsenoop;
var parse_FnGroupName = parsenoop;
var parse_FilterMode = parsenoop;
var parse_AutoFilterInfo = parsenoop;
var parse_AutoFilter = parsenoop;
var parse_Setup = parsenoop;
var parse_ScenMan = parsenoop;
var parse_SCENARIO = parsenoop;
var parse_SxView = parsenoop;
var parse_Sxvd = parsenoop;
var parse_SXVI = parsenoop;
var parse_SxIvd = parsenoop;
var parse_SXLI = parsenoop;
var parse_SXPI = parsenoop;
var parse_DocRoute = parsenoop;
var parse_RecipName = parsenoop;
var parse_MulBlank = parsenoop;
var parse_SXDI = parsenoop;
var parse_SXDB = parsenoop;
var parse_SXFDB = parsenoop;
var parse_SXDBB = parsenoop;
var parse_SXNum = parsenoop;
var parse_SxErr = parsenoop;
var parse_SXInt = parsenoop;
var parse_SXString = parsenoop;
var parse_SXDtr = parsenoop;
var parse_SxNil = parsenoop;
var parse_SXTbl = parsenoop;
var parse_SXTBRGIITM = parsenoop;
var parse_SxTbpg = parsenoop;
var parse_ObProj = parsenoop;
var parse_SXStreamID = parsenoop;
var parse_DBCell = parsenoop;
var parse_SXRng = parsenoop;
var parse_SxIsxoper = parsenoop;
var parse_BookBool = parsenoop;
var parse_DbOrParamQry = parsenoop;
var parse_OleObjectSize = parsenoop;
var parse_SXVS = parsenoop;
var parse_BkHim = parsenoop;
var parse_MsoDrawingGroup = parsenoop;
var parse_MsoDrawing = parsenoop;
var parse_MsoDrawingSelection = parsenoop;
var parse_PhoneticInfo = parsenoop;
var parse_SxRule = parsenoop;
var parse_SXEx = parsenoop;
var parse_SxFilt = parsenoop;
var parse_SxDXF = parsenoop;
var parse_SxItm = parsenoop;
var parse_SxName = parsenoop;
var parse_SxSelect = parsenoop;
var parse_SXPair = parsenoop;
var parse_SxFmla = parsenoop;
var parse_SxFormat = parsenoop;
var parse_SXVDEx = parsenoop;
var parse_SXFormula = parsenoop;
var parse_SXDBEx = parsenoop;
var parse_RRDInsDel = parsenoop;
var parse_RRDHead = parsenoop;
var parse_RRDChgCell = parsenoop;
var parse_RRDRenSheet = parsenoop;
var parse_RRSort = parsenoop;
var parse_RRDMove = parsenoop;
var parse_RRFormat = parsenoop;
var parse_RRAutoFmt = parsenoop;
var parse_RRInsertSh = parsenoop;
var parse_RRDMoveBegin = parsenoop;
var parse_RRDMoveEnd = parsenoop;
var parse_RRDInsDelBegin = parsenoop;
var parse_RRDInsDelEnd = parsenoop;
var parse_RRDConflict = parsenoop;
var parse_RRDDefName = parsenoop;
var parse_RRDRstEtxp = parsenoop;
var parse_LRng = parsenoop;
var parse_CUsr = parsenoop;
var parse_CbUsr = parsenoop;
var parse_UsrInfo = parsenoop;
var parse_UsrExcl = parsenoop;
var parse_FileLock = parsenoop;
var parse_RRDInfo = parsenoop;
var parse_BCUsrs = parsenoop;
var parse_UsrChk = parsenoop;
var parse_UserBView = parsenoop;
var parse_UserSViewBegin = parsenoop; // overloaded
var parse_UserSViewEnd = parsenoop;
var parse_RRDUserView = parsenoop;
var parse_Qsi = parsenoop;
var parse_CondFmt = parsenoop;
var parse_CF = parsenoop;
var parse_DVal = parsenoop;
var parse_DConBin = parsenoop;
var parse_Lel = parsenoop;
var parse_XLSCodeName = parse_XLUnicodeString;
var parse_SXFDBType = parsenoop;
var parse_ObNoMacros = parsenoop;
var parse_Dv = parsenoop;
var parse_Index = parsenoop;
var parse_Table = parsenoop;
var parse_BigName = parsenoop;
var parse_ContinueBigName = parsenoop;
var parse_WebPub = parsenoop;
var parse_QsiSXTag = parsenoop;
var parse_DBQueryExt = parsenoop;
var parse_ExtString = parsenoop;
var parse_TxtQry = parsenoop;
var parse_Qsir = parsenoop;
var parse_Qsif = parsenoop;
var parse_RRDTQSIF = parsenoop;
var parse_OleDbConn = parsenoop;
var parse_WOpt = parsenoop;
var parse_SXViewEx = parsenoop;
var parse_SXTH = parsenoop;
var parse_SXPIEx = parsenoop;
var parse_SXVDTEx = parsenoop;
var parse_SXViewEx9 = parsenoop;
var parse_ContinueFrt = parsenoop;
var parse_RealTimeData = parsenoop;
var parse_ChartFrtInfo = parsenoop;
var parse_FrtWrapper = parsenoop;
var parse_StartBlock = parsenoop;
var parse_EndBlock = parsenoop;
var parse_StartObject = parsenoop;
var parse_EndObject = parsenoop;
var parse_CatLab = parsenoop;
var parse_YMult = parsenoop;
var parse_SXViewLink = parsenoop;
var parse_PivotChartBits = parsenoop;
var parse_FrtFontList = parsenoop;
var parse_SheetExt = parsenoop;
var parse_BookExt = parsenoop;
var parse_SXAddl = parsenoop;
var parse_CrErr = parsenoop;
var parse_HFPicture = parsenoop;
var parse_Feat = parsenoop;
var parse_DataLabExt = parsenoop;
var parse_DataLabExtContents = parsenoop;
var parse_CellWatch = parsenoop;
var parse_FeatHdr11 = parsenoop;
var parse_Feature11 = parsenoop;
var parse_DropDownObjIds = parsenoop;
var parse_ContinueFrt11 = parsenoop;
var parse_DConn = parsenoop;
var parse_List12 = parsenoop;
var parse_Feature12 = parsenoop;
var parse_CondFmt12 = parsenoop;
var parse_CF12 = parsenoop;
var parse_CFEx = parsenoop;
var parse_AutoFilter12 = parsenoop;
var parse_ContinueFrt12 = parsenoop;
var parse_MDTInfo = parsenoop;
var parse_MDXStr = parsenoop;
var parse_MDXTuple = parsenoop;
var parse_MDXSet = parsenoop;
var parse_MDXProp = parsenoop;
var parse_MDXKPI = parsenoop;
var parse_MDB = parsenoop;
var parse_PLV = parsenoop;
var parse_DXF = parsenoop;
var parse_TableStyles = parsenoop;
var parse_TableStyle = parsenoop;
var parse_TableStyleElement = parsenoop;
var parse_NamePublish = parsenoop;
var parse_NameCmt = parsenoop;
var parse_SortData = parsenoop;
var parse_GUIDTypeLib = parsenoop;
var parse_FnGrp12 = parsenoop;
var parse_NameFnGrp12 = parsenoop;
var parse_HeaderFooter = parsenoop;
var parse_CrtLayout12 = parsenoop;
var parse_CrtMlFrt = parsenoop;
var parse_CrtMlFrtContinue = parsenoop;
var parse_ShapePropsStream = parsenoop;
var parse_TextPropsStream = parsenoop;
var parse_RichTextStream = parsenoop;
var parse_CrtLayout12A = parsenoop;
var parse_Units = parsenoop;
var parse_Chart = parsenoop;
var parse_Series = parsenoop;
var parse_DataFormat = parsenoop;
var parse_LineFormat = parsenoop;
var parse_MarkerFormat = parsenoop;
var parse_AreaFormat = parsenoop;
var parse_PieFormat = parsenoop;
var parse_AttachedLabel = parsenoop;
var parse_SeriesText = parsenoop;
var parse_ChartFormat = parsenoop;
var parse_Legend = parsenoop;
var parse_SeriesList = parsenoop;
var parse_Bar = parsenoop;
var parse_Line = parsenoop;
var parse_Pie = parsenoop;
var parse_Area = parsenoop;
var parse_Scatter = parsenoop;
var parse_CrtLine = parsenoop;
var parse_Axis = parsenoop;
var parse_Tick = parsenoop;
var parse_ValueRange = parsenoop;
var parse_CatSerRange = parsenoop;
var parse_AxisLine = parsenoop;
var parse_CrtLink = parsenoop;
var parse_DefaultText = parsenoop;
var parse_Text = parsenoop;
var parse_ObjectLink = parsenoop;
var parse_Frame = parsenoop;
var parse_Begin = parsenoop;
var parse_End = parsenoop;
var parse_PlotArea = parsenoop;
var parse_Chart3d = parsenoop;
var parse_PicF = parsenoop;
var parse_DropBar = parsenoop;
var parse_Radar = parsenoop;
var parse_Surf = parsenoop;
var parse_RadarArea = parsenoop;
var parse_AxisParent = parsenoop;
var parse_LegendException = parsenoop;
var parse_ShtProps = parsenoop;
var parse_SerToCrt = parsenoop;
var parse_AxesUsed = parsenoop;
var parse_SBaseRef = parsenoop;
var parse_SerParent = parsenoop;
var parse_SerAuxTrend = parsenoop;
var parse_IFmtRecord = parsenoop;
var parse_Pos = parsenoop;
var parse_AlRuns = parsenoop;
var parse_BRAI = parsenoop;
var parse_SerAuxErrBar = parsenoop;
var parse_SerFmt = parsenoop;
var parse_Chart3DBarShape = parsenoop;
var parse_Fbi = parsenoop;
var parse_BopPop = parsenoop;
var parse_AxcExt = parsenoop;
var parse_Dat = parsenoop;
var parse_PlotGrowth = parsenoop;
var parse_SIIndex = parsenoop;
var parse_GelFrame = parsenoop;
var parse_BopPopCustom = parsenoop;
var parse_Fbi2 = parsenoop;
/* --- Specific to versions before BIFF8 --- */
function parse_BIFF5String(blob) {
var len = blob.read_shift(1);
return blob.read_shift(len, 'sbcs-cont');
}
/* BIFF2_??? where ??? is the name from [XLS] */
function parse_BIFF2STR(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var str = parse_XLUnicodeString2(blob, length-7, opts);
cell.val = str;
return cell;
}
function parse_BIFF2NUM(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
var num = parse_Xnum(blob, 8);
cell.val = num;
return cell;
}

180
bits/44_offcrypto.js Normal file

@ -0,0 +1,180 @@
function _JS2ANSI(str) { if(typeof cptable !== 'undefined') return cptable.utils.encode(1252, str); return str.split("").map(function(x) { return x.charCodeAt(0); }); }
/* [MS-OFFCRYPTO] 2.1.4 Version */
function parse_Version(blob, length) {
var o = {};
o.Major = blob.read_shift(2);
o.Minor = blob.read_shift(2);
return o;
}
/* [MS-OFFCRYPTO] 2.3.2 Encryption Header */
function parse_EncryptionHeader(blob, length) {
var o = {};
o.Flags = blob.read_shift(4);
// Check if SizeExtra is 0x00000000
var tmp = blob.read_shift(4);
if(tmp !== 0) throw 'Unrecognized SizeExtra: ' + tmp;
o.AlgID = blob.read_shift(4);
switch(o.AlgID) {
case 0: case 0x6801: case 0x660E: case 0x660F: case 0x6610: break;
default: throw 'Unrecognized encryption algorithm: ' + o.AlgID;
}
parsenoop(blob, length-12);
return o;
}
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
function parse_EncryptionVerifier(blob, length) {
return parsenoop(blob, length);
}
/* [MS-OFFCRYPTO] 2.3.5.1 RC4 CryptoAPI Encryption Header */
function parse_RC4CryptoHeader(blob, length) {
var o = {};
var vers = o.EncryptionVersionInfo = parse_Version(blob, 4); length -= 4;
if(vers.Minor != 2) throw 'unrecognized minor version code: ' + vers.Minor;
if(vers.Major > 4 || vers.Major < 2) throw 'unrecognized major version code: ' + vers.Major;
o.Flags = blob.read_shift(4); length -= 4;
var sz = blob.read_shift(4); length -= 4;
o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
o.EncryptionVerifier = parse_EncryptionVerifier(blob, length);
return o;
}
/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
function parse_RC4Header(blob, length) {
var o = {};
var vers = o.EncryptionVersionInfo = parse_Version(blob, 4); length -= 4;
if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
o.Salt = blob.read_shift(16);
o.EncryptedVerifier = blob.read_shift(16);
o.EncryptedVerifierHash = blob.read_shift(16);
return o;
}
/* [MS-OFFCRYPTO] 2.3.7.1 Binary Document Password Verifier Derivation */
function crypto_CreatePasswordVerifier_Method1(Password) {
var Verifier = 0x0000, PasswordArray;
var PasswordDecoded = _JS2ANSI(Password);
var len = PasswordDecoded.length + 1, i, PasswordByte;
var Intermediate1, Intermediate2, Intermediate3;
PasswordArray = new_raw_buf(len);
PasswordArray[0] = PasswordDecoded.length;
for(i = 1; i != len; ++i) PasswordArray[i] = PasswordDecoded[i-1];
for(i = len-1; i >= 0; --i) {
PasswordByte = PasswordArray[i];
Intermediate1 = ((Verifier & 0x4000) === 0x0000) ? 0 : 1;
Intermediate2 = (Verifier << 1) & 0x7FFF;
Intermediate3 = Intermediate1 | Intermediate2;
Verifier = Intermediate3 ^ PasswordByte;
}
return Verifier ^ 0xCE4B;
}
/* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */
var crypto_CreateXorArray_Method1 = (function() {
var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00];
var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3];
var XorMatrix = [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09, 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF, 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0, 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40, 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5, 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A, 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9, 0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0, 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC, 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10, 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168, 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C, 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD, 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC, 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4];
var Ror = function(Byte) { return ((Byte/2) | (Byte*128)) & 0xFF; };
var XorRor = function(byte1, byte2) { return Ror(byte1 ^ byte2); };
var CreateXorKey_Method1 = function(Password) {
var XorKey = InitialCode[Password.length - 1];
var CurrentElement = 0x68;
for(var i = Password.length-1; i >= 0; --i) {
var Char = Password[i];
for(var j = 0; j != 7; ++j) {
if(Char & 0x40) XorKey ^= XorMatrix[CurrentElement];
Char *= 2; --CurrentElement;
}
}
return XorKey;
};
return function(password) {
var Password = _JS2ANSI(password);
var XorKey = CreateXorKey_Method1(Password);
var Index = Password.length;
var ObfuscationArray = new_raw_buf(16);
for(var i = 0; i != 16; ++i) ObfuscationArray[i] = 0x00;
var Temp, PasswordLastChar, PadIndex;
if((Index & 1) === 1) {
Temp = XorKey >> 8;
ObfuscationArray[Index] = XorRor(PadArray[0], Temp);
--Index;
Temp = XorKey & 0xFF;
PasswordLastChar = Password[Password.length - 1];
ObfuscationArray[Index] = XorRor(PasswordLastChar, Temp);
}
while(Index > 0) {
--Index;
Temp = XorKey >> 8;
ObfuscationArray[Index] = XorRor(Password[Index], Temp);
--Index;
Temp = XorKey & 0xFF;
ObfuscationArray[Index] = XorRor(Password[Index], Temp);
}
Index = 15;
PadIndex = 15 - Password.length;
while(PadIndex > 0) {
Temp = XorKey >> 8;
ObfuscationArray[Index] = XorRor(PadArray[PadIndex], Temp);
--Index;
--PadIndex;
Temp = XorKey & 0xFF;
ObfuscationArray[Index] = XorRor(Password[Index], Temp);
--Index;
--PadIndex;
}
return ObfuscationArray;
};
})();
/* [MS-OFFCRYPTO] 2.3.7.3 Binary Document XOR Data Transformation Method 1 */
var crypto_DecryptData_Method1 = function(password, Data, XorArrayIndex, XorArray, O) {
/* If XorArray is set, use it; if O is not set, make changes in-place */
if(!O) O = Data;
if(!XorArray) XorArray = crypto_CreateXorArray_Method1(password);
var Index, Value;
for(Index = 0; Index != Data.length; ++Index) {
Value = Data[Index];
Value ^= XorArray[XorArrayIndex];
Value = ((Value>>5) | (Value<<3)) & 0xFF;
O[Index] = Value;
++XorArrayIndex;
}
return [O, XorArrayIndex, XorArray];
};
var crypto_MakeXorDecryptor = function(password) {
var XorArrayIndex = 0, XorArray = crypto_CreateXorArray_Method1(password);
return function(Data) {
var O = crypto_DecryptData_Method1(null, Data, XorArrayIndex, XorArray);
XorArrayIndex = O[1];
return O[0];
};
};
/* 2.5.343 */
function parse_XORObfuscation(blob, length, opts, out) {
var o = { key: parseuint16(blob), verificationBytes: parseuint16(blob) };
if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
out.valid = o.verificationBytes === o.verifier;
if(out.valid) out.insitu_decrypt = crypto_MakeXorDecryptor(opts.password);
return o;
}
/* 2.4.117 */
function parse_FilePassHeader(blob, length, oo) {
var o = oo || {}; o.Info = blob.read_shift(2); blob.l -= 2;
if(o.Info === 1) o.Data = parse_RC4Header(blob, length);
else o.Data = parse_RC4CryptoHeader(blob, length);
return o;
}
function parse_FilePass(blob, length, opts) {
var o = { Type: blob.read_shift(2) }; /* wEncryptionType */
if(o.Type) parse_FilePassHeader(blob, length-2, o);
else parse_XORObfuscation(blob, length-2, opts, o);
return o;
}

@ -62,3 +62,23 @@ function find_mdw(collw, coll) {
if(MDW === MAX_MDW) MDW = DEF_MDW;
}
}
/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
var XLMLPatternTypeMap = {
"None": "none",
"Solid": "solid",
"Gray50": "mediumGray",
"Gray75": "darkGray",
"Gray25": "lightGray",
"HorzStripe": "darkHorizontal",
"VertStripe": "darkVertical",
"ReverseDiagStripe": "darkDown",
"DiagStripe": "darkUp",
"DiagCross": "darkGrid",
"ThickDiagCross": "darkTrellis",
"ThinHorzStripe": "lightHorizontal",
"ThinVertStripe": "lightVertical",
"ThinReverseDiagStripe": "lightDown",
"ThinHorzCross": "lightGrid"
};

@ -190,6 +190,7 @@ function parse_borders(t, opts) {
if (y.theme) sub_border.color.theme = y.theme;
if (y.tint) sub_border.color.tint = y.tint;
if (y.rgb) sub_border.color.rgb = y.rgb;
if (y.auto) sub_border.color.auto = y.auto;
break;
case '<name/>':
case '</name>':
@ -275,7 +276,8 @@ function parse_cellXfs(t, opts) {
case '<alignment/>':
var alignment = {}
if (y.vertical) { alignment.vertical = y.vertical;}
if (y.horizontal) { alignment.horizontal = y.horizontal;}
if (y.horizontal) { alignment.horizontal = y.horizontal;}
if (y.textRotation != undefined) { alignment.textRotation = y.textRotation; }
if (y.indent) { alignment.indent = y.indent; }
if (y.wrapText) { alignment.wrapText = y.wrapText; }
xf.alignment = alignment;

78
bits/50_styxls.js Normal file

@ -0,0 +1,78 @@
/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
function parse_Theme(blob, length) {
var dwThemeVersion = blob.read_shift(4);
if(dwThemeVersion === 124226) return;
blob.l += length-4;
}
/* 2.5.49 */
function parse_ColorTheme(blob, length) { return blob.read_shift(4); }
/* 2.5.155 */
function parse_FullColorExt(blob, length) {
var o = {};
o.xclrType = blob.read_shift(2);
o.nTintShade = blob.read_shift(2);
switch(o.xclrType) {
case 0: blob.l += 4; break;
case 1: o.xclrValue = parse_IcvXF(blob, 4); break;
case 2: o.xclrValue = parse_LongRGBA(blob, 4); break;
case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
case 4: blob.l += 4; break;
}
blob.l += 8;
return o;
}
/* 2.5.164 TODO: read 7 bits*/
function parse_IcvXF(blob, length) {
return parsenoop(blob, length);
}
/* 2.5.280 */
function parse_XFExtGradient(blob, length) {
return parsenoop(blob, length);
}
/* 2.5.108 */
function parse_ExtProp(blob, length) {
var extType = blob.read_shift(2);
var cb = blob.read_shift(2);
var o = [extType];
switch(extType) {
case 0x04: case 0x05: case 0x07: case 0x08:
case 0x09: case 0x0A: case 0x0B: case 0x0D:
o[1] = parse_FullColorExt(blob, cb); break;
case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 5 ? 1 : 2); break;
default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
}
return o;
}
/* 2.4.355 */
function parse_XFExt(blob, length) {
var end = blob.l + length;
blob.l += 2;
var ixfe = blob.read_shift(2);
blob.l += 2;
var cexts = blob.read_shift(2);
var ext = [];
while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
return {ixfe:ixfe, ext:ext};
}
/* xf is an XF, see parse_XFExt for xfext */
function update_xfext(xf, xfext) {
xfext.forEach(function(xfe) {
switch(xfe[0]) { /* 2.5.108 extPropData */
case 0x04: break; /* foreground color */
case 0x05: break; /* background color */
case 0x07: case 0x08: case 0x09: case 0x0a: break;
case 0x0d: break; /* text color */
case 0x0e: break; /* font scheme */
default: throw "bafuq" + xfe[0].toString(16);
}
});
}

17
bits/61_fcommon.js Normal file

@ -0,0 +1,17 @@
/* TODO: it will be useful to parse the function str */
var rc_to_a1 = (function(){
var rcregex = /(^|[^A-Za-z])R(\[?)(-?\d+|)\]?C(\[?)(-?\d+|)\]?/g;
var rcbase;
function rcfunc($$,$1,$2,$3,$4,$5) {
var R = $3.length>0?parseInt($3,10)|0:0, C = $5.length>0?parseInt($5,10)|0:0;
if(C<0 && $4.length === 0) C=0;
if($4.length > 0) C += rcbase.c;
if($2.length > 0) R += rcbase.r;
return $1 + encode_col(C) + encode_row(R);
}
return function rc_to_a1(fstr, base) {
rcbase = base;
return fstr.replace(rcregex, rcfunc);
};
})();

803
bits/62_fxls.js Normal file

@ -0,0 +1,803 @@
/* --- 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; }
/* Rgce Helpers */
/* 2.5.51 */
function parse_ColRelU(blob, length) {
var c = blob.read_shift(2);
return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
}
/* 2.5.198.105 */
function parse_RgceArea(blob, length) {
var r=blob.read_shift(2), R=blob.read_shift(2);
var c=parse_ColRelU(blob, 2);
var C=parse_ColRelU(blob, 2);
return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
}
/* 2.5.198.105 TODO */
function parse_RgceAreaRel(blob, length) {
var r=blob.read_shift(2), R=blob.read_shift(2);
var c=parse_ColRelU(blob, 2);
var C=parse_ColRelU(blob, 2);
return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
}
/* 2.5.198.109 */
function parse_RgceLoc(blob, length) {
var r = blob.read_shift(2);
var c = parse_ColRelU(blob, 2);
return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
}
/* 2.5.198.111 */
function parse_RgceLocRel(blob, length) {
var r = blob.read_shift(2);
var cl = blob.read_shift(2);
var cRel = (cl & 0x8000) >> 15, rRel = (cl & 0x4000) >> 14;
cl &= 0x3FFF;
if(cRel !== 0) while(cl >= 0x100) cl -= 0x100;
return {r:r,c:cl,cRel:cRel,rRel:rRel};
}
/* Ptg Tokens */
/* 2.5.198.27 */
function parse_PtgArea(blob, length) {
var type = (blob[blob.l++] & 0x60) >> 5;
var area = parse_RgceArea(blob, 8);
return [type, area];
}
/* 2.5.198.28 */
function parse_PtgArea3d(blob, length) {
var type = (blob[blob.l++] & 0x60) >> 5;
var ixti = blob.read_shift(2);
var area = parse_RgceArea(blob, 8);
return [type, ixti, area];
}
/* 2.5.198.29 */
function parse_PtgAreaErr(blob, length) {
var type = (blob[blob.l++] & 0x60) >> 5;
blob.l += 8;
return [type];
}
/* 2.5.198.30 */
function parse_PtgAreaErr3d(blob, length) {
var type = (blob[blob.l++] & 0x60) >> 5;
var ixti = blob.read_shift(2);
blob.l += 8;
return [type, ixti];
}
/* 2.5.198.31 */
function parse_PtgAreaN(blob, length) {
var type = (blob[blob.l++] & 0x60) >> 5;
var area = parse_RgceAreaRel(blob, 8);
return [type, area];
}
/* 2.5.198.32 -- ignore this and look in PtgExtraArray for shape + values */
function parse_PtgArray(blob, length) {
var type = (blob[blob.l++] & 0x60) >> 5;
blob.l += 7;
return [type];
}
/* 2.5.198.33 */
function parse_PtgAttrBaxcel(blob, length) {
var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
var bitBaxcel = 1;
blob.l += 4;
return [bitSemi, bitBaxcel];
}
/* 2.5.198.34 */
function parse_PtgAttrChoose(blob, length) {
blob.l +=2;
var offset = blob.read_shift(2);
var o = [];
/* offset is 1 less than the number of elements */
for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(2));
return o;
}
/* 2.5.198.35 */
function parse_PtgAttrGoto(blob, length) {
var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
return [bitGoto, blob.read_shift(2)];
}
/* 2.5.198.36 */
function parse_PtgAttrIf(blob, length) {
var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 2;
return [bitIf, blob.read_shift(2)];
}
/* 2.5.198.37 */
function parse_PtgAttrSemi(blob, length) {
var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
blob.l += 4;
return [bitSemi];
}
/* 2.5.198.40 (used by PtgAttrSpace and PtgAttrSpaceSemi) */
function parse_PtgAttrSpaceType(blob, length) {
var type = blob.read_shift(1), cch = blob.read_shift(1);
return [type, cch];
}
/* 2.5.198.38 */
function parse_PtgAttrSpace(blob, length) {
blob.read_shift(2);
return parse_PtgAttrSpaceType(blob, 2);
}
/* 2.5.198.39 */
function parse_PtgAttrSpaceSemi(blob, length) {
blob.read_shift(2);
return parse_PtgAttrSpaceType(blob, 2);
}
/* 2.5.198.84 TODO */
function parse_PtgRef(blob, length) {
var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var loc = parse_RgceLoc(blob,4);
return [type, loc];
}
/* 2.5.198.88 TODO */
function parse_PtgRefN(blob, length) {
var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var loc = parse_RgceLocRel(blob,4);
return [type, loc];
}
/* 2.5.198.85 TODO */
function parse_PtgRef3d(blob, length) {
var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var ixti = blob.read_shift(2); // XtiIndex
var loc = parse_RgceLoc(blob,4);
return [type, ixti, loc];
}
/* 2.5.198.62 TODO */
function parse_PtgFunc(blob, length) {
var ptg = blob[blob.l] & 0x1F;
var type = (blob[blob.l] & 0x60)>>5;
blob.l += 1;
var iftab = blob.read_shift(2);
return [FtabArgc[iftab], Ftab[iftab]];
}
/* 2.5.198.63 TODO */
function parse_PtgFuncVar(blob, length) {
blob.l++;
var cparams = blob.read_shift(1), tab = parsetab(blob);
return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
}
function parsetab(blob, length) {
return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
}
/* 2.5.198.41 */
var parse_PtgAttrSum = parseread(4);
/* 2.5.198.43 */
var parse_PtgConcat = parseread1;
/* 2.5.198.58 */
function parse_PtgExp(blob, length) {
blob.l++;
var row = blob.read_shift(2);
var col = blob.read_shift(2);
return [row, col];
}
/* 2.5.198.57 */
function parse_PtgErr(blob, length) { blob.l++; return BErr[blob.read_shift(1)]; }
/* 2.5.198.66 TODO */
function parse_PtgInt(blob, length) { blob.l++; return blob.read_shift(2); }
/* 2.5.198.42 */
function parse_PtgBool(blob, length) { blob.l++; return blob.read_shift(1)!==0;}
/* 2.5.198.79 */
function parse_PtgNum(blob, length) { blob.l++; return parse_Xnum(blob, 8); }
/* 2.5.198.89 */
function parse_PtgStr(blob, length) { blob.l++; return parse_ShortXLUnicodeString(blob); }
/* 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
function parse_SerAr(blob) {
var val = [];
switch((val[0] = blob.read_shift(1))) {
/* 2.5.192.113 */
case 0x04: /* SerBool -- boolean */
val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
blob.l += 7; break;
/* 2.5.192.114 */
case 0x10: /* SerErr -- error */
val[1] = BErr[blob[blob.l]];
blob.l += 8; break;
/* 2.5.192.115 */
case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
blob.l += 8; break;
/* 2.5.192.116 */
case 0x01: /* SerNum -- Xnum */
val[1] = parse_Xnum(blob, 8); break;
/* 2.5.192.117 */
case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
val[1] = parse_XLUnicodeString(blob); break;
// default: throw "Bad SerAr: " + val[0]; /* Unreachable */
}
return val;
}
/* 2.5.198.61 */
function parse_PtgExtraMem(blob, cce) {
var count = blob.read_shift(2);
var out = [];
for(var i = 0; i != count; ++i) out.push(parse_Ref8U(blob, 8));
return out;
}
/* 2.5.198.59 */
function parse_PtgExtraArray(blob) {
var cols = 1 + blob.read_shift(1); //DColByteU
var rows = 1 + blob.read_shift(2); //DRw
for(var i = 0, o=[]; i != rows && (o[i] = []); ++i)
for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob);
return o;
}
/* 2.5.198.76 */
function parse_PtgName(blob, length) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var nameindex = blob.read_shift(4);
return [type, 0, nameindex];
}
/* 2.5.198.77 */
function parse_PtgNameX(blob, length) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var ixti = blob.read_shift(2); // XtiIndex
var nameindex = blob.read_shift(4);
return [type, ixti, nameindex];
}
/* 2.5.198.70 */
function parse_PtgMemArea(blob, length) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
blob.l += 4;
var cce = blob.read_shift(2);
return [type, cce];
}
/* 2.5.198.72 */
function parse_PtgMemFunc(blob, length) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
var cce = blob.read_shift(2);
return [type, cce];
}
/* 2.5.198.86 */
function parse_PtgRefErr(blob, length) {
var type = (blob.read_shift(1) >>> 5) & 0x03;
blob.l += 4;
return [type];
}
/* 2.5.198.26 */
var parse_PtgAdd = parseread1;
/* 2.5.198.45 */
var parse_PtgDiv = parseread1;
/* 2.5.198.56 */
var parse_PtgEq = parseread1;
/* 2.5.198.64 */
var parse_PtgGe = parseread1;
/* 2.5.198.65 */
var parse_PtgGt = parseread1;
/* 2.5.198.67 */
var parse_PtgIsect = parseread1;
/* 2.5.198.68 */
var parse_PtgLe = parseread1;
/* 2.5.198.69 */
var parse_PtgLt = parseread1;
/* 2.5.198.74 */
var parse_PtgMissArg = parseread1;
/* 2.5.198.75 */
var parse_PtgMul = parseread1;
/* 2.5.198.78 */
var parse_PtgNe = parseread1;
/* 2.5.198.80 */
var parse_PtgParen = parseread1;
/* 2.5.198.81 */
var parse_PtgPercent = parseread1;
/* 2.5.198.82 */
var parse_PtgPower = parseread1;
/* 2.5.198.83 */
var parse_PtgRange = parseread1;
/* 2.5.198.90 */
var parse_PtgSub = parseread1;
/* 2.5.198.93 */
var parse_PtgUminus = parseread1;
/* 2.5.198.94 */
var parse_PtgUnion = parseread1;
/* 2.5.198.95 */
var parse_PtgUplus = parseread1;
/* 2.5.198.71 */
var parse_PtgMemErr = parsenoop;
/* 2.5.198.73 */
var parse_PtgMemNoMem = parsenoop;
/* 2.5.198.87 */
var parse_PtgRefErr3d = parsenoop;
/* 2.5.198.92 */
var parse_PtgTbl = parsenoop;
/* 2.5.198.25 */
var PtgTypes = {
0x01: { n:'PtgExp', f:parse_PtgExp },
0x02: { n:'PtgTbl', f:parse_PtgTbl },
0x03: { n:'PtgAdd', f:parse_PtgAdd },
0x04: { n:'PtgSub', f:parse_PtgSub },
0x05: { n:'PtgMul', f:parse_PtgMul },
0x06: { n:'PtgDiv', f:parse_PtgDiv },
0x07: { n:'PtgPower', f:parse_PtgPower },
0x08: { n:'PtgConcat', f:parse_PtgConcat },
0x09: { n:'PtgLt', f:parse_PtgLt },
0x0A: { n:'PtgLe', f:parse_PtgLe },
0x0B: { n:'PtgEq', f:parse_PtgEq },
0x0C: { n:'PtgGe', f:parse_PtgGe },
0x0D: { n:'PtgGt', f:parse_PtgGt },
0x0E: { n:'PtgNe', f:parse_PtgNe },
0x0F: { n:'PtgIsect', f:parse_PtgIsect },
0x10: { n:'PtgUnion', f:parse_PtgUnion },
0x11: { n:'PtgRange', f:parse_PtgRange },
0x12: { n:'PtgUplus', f:parse_PtgUplus },
0x13: { n:'PtgUminus', f:parse_PtgUminus },
0x14: { n:'PtgPercent', f:parse_PtgPercent },
0x15: { n:'PtgParen', f:parse_PtgParen },
0x16: { n:'PtgMissArg', f:parse_PtgMissArg },
0x17: { n:'PtgStr', f:parse_PtgStr },
0x1C: { n:'PtgErr', f:parse_PtgErr },
0x1D: { n:'PtgBool', f:parse_PtgBool },
0x1E: { n:'PtgInt', f:parse_PtgInt },
0x1F: { n:'PtgNum', f:parse_PtgNum },
0x20: { n:'PtgArray', f:parse_PtgArray },
0x21: { n:'PtgFunc', f:parse_PtgFunc },
0x22: { n:'PtgFuncVar', f:parse_PtgFuncVar },
0x23: { n:'PtgName', f:parse_PtgName },
0x24: { n:'PtgRef', f:parse_PtgRef },
0x25: { n:'PtgArea', f:parse_PtgArea },
0x26: { n:'PtgMemArea', f:parse_PtgMemArea },
0x27: { n:'PtgMemErr', f:parse_PtgMemErr },
0x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
0x29: { n:'PtgMemFunc', f:parse_PtgMemFunc },
0x2A: { n:'PtgRefErr', f:parse_PtgRefErr },
0x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr },
0x2C: { n:'PtgRefN', f:parse_PtgRefN },
0x2D: { n:'PtgAreaN', f:parse_PtgAreaN },
0x39: { n:'PtgNameX', f:parse_PtgNameX },
0x3A: { n:'PtgRef3d', f:parse_PtgRef3d },
0x3B: { n:'PtgArea3d', f:parse_PtgArea3d },
0x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
0x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
0xFF: {}
};
/* These are duplicated in the PtgTypes table */
var PtgDupes = {
0x40: 0x20, 0x60: 0x20,
0x41: 0x21, 0x61: 0x21,
0x42: 0x22, 0x62: 0x22,
0x43: 0x23, 0x63: 0x23,
0x44: 0x24, 0x64: 0x24,
0x45: 0x25, 0x65: 0x25,
0x46: 0x26, 0x66: 0x26,
0x47: 0x27, 0x67: 0x27,
0x48: 0x28, 0x68: 0x28,
0x49: 0x29, 0x69: 0x29,
0x4A: 0x2A, 0x6A: 0x2A,
0x4B: 0x2B, 0x6B: 0x2B,
0x4C: 0x2C, 0x6C: 0x2C,
0x4D: 0x2D, 0x6D: 0x2D,
0x59: 0x39, 0x79: 0x39,
0x5A: 0x3A, 0x7A: 0x3A,
0x5B: 0x3B, 0x7B: 0x3B,
0x5C: 0x3C, 0x7C: 0x3C,
0x5D: 0x3D, 0x7D: 0x3D
};
(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
var Ptg18 = {};
var Ptg19 = {
0x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
0x02: { n:'PtgAttrIf', f:parse_PtgAttrIf },
0x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
0x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
0x10: { n:'PtgAttrSum', f:parse_PtgAttrSum },
0x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
0x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
0x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
0xFF: {}
};
/* 2.4.127 TODO */
function parse_Formula(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
var val = parse_FormulaValue(blob,8);
var flags = blob.read_shift(1);
blob.read_shift(1);
var chn = blob.read_shift(4);
var cbf = "";
if(opts.biff === 5) blob.l += length-20;
else cbf = parse_XLSCellParsedFormula(blob, length-20, opts);
return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
}
/* 2.5.133 TODO: how to emit empty strings? */
function parse_FormulaValue(blob) {
var b;
if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
switch(blob[blob.l]) {
case 0x00: blob.l += 8; return ["String", 's'];
case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
case 0x03: blob.l += 8; return ["",'s'];
}
}
/* 2.5.198.103 */
function parse_RgbExtra(blob, length, rgce, opts) {
if(opts.biff < 8) return parsenoop(blob, length);
var target = blob.l + length;
var o = [];
for(var i = 0; i !== rgce.length; ++i) {
switch(rgce[i][0]) {
case 'PtgArray': /* PtgArray -> PtgExtraArray */
rgce[i][1] = parse_PtgExtraArray(blob);
o.push(rgce[i][1]);
break;
case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1]);
o.push(rgce[i][2]);
break;
default: break;
}
}
length = target - blob.l;
if(length !== 0) o.push(parsenoop(blob, length));
return o;
}
/* 2.5.198.21 */
function parse_NameParsedFormula(blob, length, opts, cce) {
var target = blob.l + length;
var rgce = parse_Rgce(blob, cce);
var rgcb;
if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.3 TODO */
function parse_XLSCellParsedFormula(blob, length, opts) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce);
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, length - cce - 2, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.118 TODO */
function parse_SharedParsedFormula(blob, length, opts) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
var rgce = parse_Rgce(blob, cce);
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.1 TODO */
function parse_ArrayParsedFormula(blob, length, opts, ref) {
var target = blob.l + length;
var rgcb, cce = blob.read_shift(2); // length of rgce
if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
var rgce = parse_Rgce(blob, cce);
if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
return [rgce, rgcb];
}
/* 2.5.198.104 */
function parse_Rgce(blob, length) {
var target = blob.l + length;
var R, id, ptgs = [];
while(target != blob.l) {
length = target - blob.l;
id = blob[blob.l];
R = PtgTypes[id];
//console.log("ptg", id, R)
if(id === 0x18 || id === 0x19) {
id = blob[blob.l + 1];
R = (id === 0x18 ? Ptg18 : Ptg19)[id];
}
if(!R || !R.f) { ptgs.push(parsenoop(blob, length)); }
else { ptgs.push([R.n, R.f(blob, length)]); }
}
return ptgs;
}
function mapper(x) { return x.map(function f2(y) { return y[1];}).join(",");}
/* 2.2.2 + Magic TODO */
function stringify_formula(formula, range, cell, supbooks, opts) {
if(opts !== undefined && opts.biff === 5) return "BIFF5??";
var _range = range !== undefined ? range : {s:{c:0, r:0}};
var stack = [], e1, e2, type, c, ixti, nameidx, r;
if(!formula[0] || !formula[0][0]) return "";
//console.log("--",cell,formula[0])
for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
var f = formula[0][ff];
//console.log("++",f, stack)
switch(f[0]) {
/* 2.2.2.1 Unary Operator Tokens */
/* 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;
/* 2.2.2.1 Binary Value Operator Token */
/* 2.5.198.26 */
case 'PtgAdd':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"+"+e1);
break;
/* 2.5.198.90 */
case 'PtgSub':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"-"+e1);
break;
/* 2.5.198.75 */
case 'PtgMul':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"*"+e1);
break;
/* 2.5.198.45 */
case 'PtgDiv':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"/"+e1);
break;
/* 2.5.198.82 */
case 'PtgPower':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"^"+e1);
break;
/* 2.5.198.43 */
case 'PtgConcat':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"&"+e1);
break;
/* 2.5.198.69 */
case 'PtgLt':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"<"+e1);
break;
/* 2.5.198.68 */
case 'PtgLe':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"<="+e1);
break;
/* 2.5.198.56 */
case 'PtgEq':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"="+e1);
break;
/* 2.5.198.64 */
case 'PtgGe':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+">="+e1);
break;
/* 2.5.198.65 */
case 'PtgGt':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+">"+e1);
break;
/* 2.5.198.78 */
case 'PtgNe':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+"<>"+e1);
break;
/* 2.2.2.1 Binary Reference Operator Token */
/* 2.5.198.67 */
case 'PtgIsect':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+" "+e1);
break;
case 'PtgUnion':
e1 = stack.pop(); e2 = stack.pop();
stack.push(e2+","+e1);
break;
case 'PtgRange': break;
/* 2.2.2.3 Control Tokens "can be ignored" */
/* 2.5.198.34 */
case 'PtgAttrChoose': break;
/* 2.5.198.35 */
case 'PtgAttrGoto': break;
/* 2.5.198.36 */
case 'PtgAttrIf': break;
/* 2.5.198.84 */
case 'PtgRef':
type = f[1][0]; c = shift_cell_xls(decode_cell(encode_cell(f[1][1])), _range);
stack.push(encode_cell(c));
break;
/* 2.5.198.88 */
case 'PtgRefN':
type = f[1][0]; c = shift_cell_xls(decode_cell(encode_cell(f[1][1])), cell);
stack.push(encode_cell(c));
break;
case 'PtgRef3d': // TODO: lots of stuff
type = f[1][0]; ixti = f[1][1]; c = shift_cell_xls(f[1][2], _range);
stack.push(supbooks[1][ixti+1]+"!"+encode_cell(c));
break;
/* Function Call */
/* 2.5.198.62 */
case 'PtgFunc':
/* 2.5.198.63 */
case 'PtgFuncVar':
/* f[1] = [argc, func] */
var argc = f[1][0], func = f[1][1];
if(!argc) argc = 0;
var args = stack.slice(-argc);
stack.length -= argc;
if(func === 'User') func = args.shift();
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(f[1]); break;
/* 2.5.198.79 TODO: precision? */
case 'PtgNum': stack.push(String(f[1])); break;
/* 2.5.198.89 */
case 'PtgStr': stack.push('"' + f[1] + '"'); break;
/* 2.5.198.57 */
case 'PtgErr': stack.push(f[1]); break;
/* 2.5.198.27 TODO: fixed points */
case 'PtgArea':
type = f[1][0]; r = shift_range_xls(f[1][1], _range);
stack.push(encode_range(r));
break;
/* 2.5.198.28 */
case 'PtgArea3d': // TODO: lots of stuff
type = f[1][0]; ixti = f[1][1]; r = f[1][2];
stack.push(supbooks[1][ixti+1]+"!"+encode_range(r));
break;
/* 2.5.198.41 */
case 'PtgAttrSum':
stack.push("SUM(" + stack.pop() + ")");
break;
/* Expression Prefixes */
/* 2.5.198.37 */
case 'PtgAttrSemi': break;
/* 2.5.97.60 TODO: do something different for revisions */
case 'PtgName':
/* f[1] = type, 0, nameindex */
nameidx = f[1][2];
var lbl = supbooks[0][nameidx];
var name = lbl.Name;
if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
stack.push(name);
break;
/* 2.5.97.61 TODO: do something different for revisions */
case 'PtgNameX':
/* f[1] = type, ixti, nameindex */
var bookidx = f[1][1]; nameidx = f[1][2]; var externbook;
/* TODO: Properly handle missing values */
if(supbooks[bookidx+1]) externbook = supbooks[bookidx+1][nameidx];
else if(supbooks[bookidx-1]) externbook = supbooks[bookidx-1][nameidx];
if(!externbook) externbook = {body: "??NAMEX??"};
stack.push(externbook.body);
break;
/* 2.2.2.4 Display Tokens */
/* 2.5.198.80 */
case 'PtgParen': stack.push('(' + stack.pop() + ')'); break;
/* 2.5.198.86 */
case 'PtgRefErr': stack.push('#REF!'); break;
/* */
/* 2.5.198.58 TODO */
case 'PtgExp':
c = {c:f[1][1],r:f[1][0]};
var q = {c: cell.c, r:cell.r};
if(supbooks.sharedf[encode_cell(c)]) {
var parsedf = (supbooks.sharedf[encode_cell(c)]);
stack.push(stringify_formula(parsedf, _range, q, supbooks, opts));
}
else {
var fnd = false;
for(e1=0;e1!=supbooks.arrayf.length; ++e1) {
/* TODO: should be something like range_has */
e2 = supbooks.arrayf[e1];
if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
}
if(!fnd) stack.push(f[1]);
}
break;
/* 2.5.198.32 TODO */
case 'PtgArray':
stack.push("{" + f[1].map(mapper).join(";") + "}");
break;
/* 2.2.2.5 Mem Tokens */
/* 2.5.198.70 TODO: confirm this is a non-display */
case 'PtgMemArea':
//stack.push("(" + f[2].map(encode_range).join(",") + ")");
break;
/* 2.5.198.38 TODO */
case 'PtgAttrSpace': break;
/* 2.5.198.92 TODO */
case 'PtgTbl': break;
/* 2.5.198.71 */
case 'PtgMemErr': break;
/* 2.5.198.74 */
case 'PtgMissArg':
stack.push("");
break;
/* 2.5.198.29 TODO */
case 'PtgAreaErr': break;
/* 2.5.198.31 TODO */
case 'PtgAreaN': stack.push(""); break;
/* 2.5.198.87 TODO */
case 'PtgRefErr3d': break;
/* 2.5.198.72 TODO */
case 'PtgMemFunc': break;
default: throw 'Unrecognized Formula Token: ' + f;
}
//console.log("::",f, stack)
}
//console.log("--",stack);
return stack[0];
}

@ -1,5 +1,5 @@
/* [MS-XLSB] 2.5.97.4 CellParsedFormula TODO: use similar logic to js-xls */
function parse_CellParsedFormula(data, length) {
function parse_XLSBCellParsedFormula(data, length) {
var cce = data.read_shift(4);
return parsenoop(data, length-4);
}

1090
bits/64_ftab.js Normal file

File diff suppressed because it is too large Load Diff

@ -16,70 +16,70 @@ function parse_BrtWsProp(data, length) {
var z = {};
/* TODO: pull flags */
data.l += 19;
z.name = parse_CodeName(data, length - 19);
z.name = parse_XLSBCodeName(data, length - 19);
return z;
}
/* [MS-XLSB] 2.4.303 BrtCellBlank */
function parse_BrtCellBlank(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
return [cell];
}
function write_BrtCellBlank(cell, val, o) {
if(o == null) o = new_buf(8);
return write_Cell(val, o);
return write_XLSBCell(val, o);
}
/* [MS-XLSB] 2.4.304 BrtCellBool */
function parse_BrtCellBool(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var fBool = data.read_shift(1);
return [cell, fBool, 'b'];
}
/* [MS-XLSB] 2.4.305 BrtCellError */
function parse_BrtCellError(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var fBool = data.read_shift(1);
return [cell, fBool, 'e'];
}
/* [MS-XLSB] 2.4.308 BrtCellIsst */
function parse_BrtCellIsst(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var isst = data.read_shift(4);
return [cell, isst, 's'];
}
/* [MS-XLSB] 2.4.310 BrtCellReal */
function parse_BrtCellReal(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = parse_Xnum(data);
return [cell, value, 'n'];
}
/* [MS-XLSB] 2.4.311 BrtCellRk */
function parse_BrtCellRk(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = parse_RkNumber(data);
return [cell, value, 'n'];
}
/* [MS-XLSB] 2.4.314 BrtCellSt */
function parse_BrtCellSt(data, length) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = parse_XLWideString(data);
return [cell, value, 'str'];
}
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
function parse_BrtFmlaBool(data, length, opts) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = data.read_shift(1);
var o = [cell, value, 'b'];
if(opts.cellFormula) {
var formula = parse_CellParsedFormula(data, length-9);
var formula = parse_XLSBCellParsedFormula(data, length-9);
o[3] = ""; /* TODO */
}
else data.l += length-9;
@ -88,11 +88,11 @@ function parse_BrtFmlaBool(data, length, opts) {
/* [MS-XLSB] 2.4.648 BrtFmlaError */
function parse_BrtFmlaError(data, length, opts) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = data.read_shift(1);
var o = [cell, value, 'e'];
if(opts.cellFormula) {
var formula = parse_CellParsedFormula(data, length-9);
var formula = parse_XLSBCellParsedFormula(data, length-9);
o[3] = ""; /* TODO */
}
else data.l += length-9;
@ -101,11 +101,11 @@ function parse_BrtFmlaError(data, length, opts) {
/* [MS-XLSB] 2.4.649 BrtFmlaNum */
function parse_BrtFmlaNum(data, length, opts) {
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = parse_Xnum(data);
var o = [cell, value, 'n'];
if(opts.cellFormula) {
var formula = parse_CellParsedFormula(data, length - 16);
var formula = parse_XLSBCellParsedFormula(data, length - 16);
o[3] = ""; /* TODO */
}
else data.l += length-16;
@ -115,11 +115,11 @@ function parse_BrtFmlaNum(data, length, opts) {
/* [MS-XLSB] 2.4.650 BrtFmlaString */
function parse_BrtFmlaString(data, length, opts) {
var start = data.l;
var cell = parse_Cell(data);
var cell = parse_XLSBCell(data);
var value = parse_XLWideString(data);
var o = [cell, value, 'str'];
if(opts.cellFormula) {
var formula = parse_CellParsedFormula(data, start + length - data.l);
var formula = parse_XLSBCellParsedFormula(data, start + length - data.l);
}
else data.l = start + length;
return o;

699
bits/80_xlml.js Normal file

@ -0,0 +1,699 @@
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
var _chr = function(c) { return String.fromCharCode(c); };
function xlml_parsexmltag(tag, skip_root) {
var words = tag.split(/\s+/);
var z = []; if(!skip_root) z[0] = words[0];
if(words.length === 1) return z;
var m = tag.match(attregexg2), y, j, w, i;
if(m) for(i = 0; i != m.length; ++i) {
y = m[i].match(attregex2);
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].substr(1,y[2].length-2);
else {
if(y[1].substr(0,6) === "xmlns:") w = "xmlns"+y[1].substr(6);
else w = y[1].substr(j+1);
z[w] = y[2].substr(1,y[2].length-2);
}
}
return z;
}
function xlml_parsexmltagobj(tag) {
var words = tag.split(/\s+/);
var z = {};
if(words.length === 1) return z;
var m = tag.match(attregexg2), y, j, w, i;
if(m) for(i = 0; i != m.length; ++i) {
y = m[i].match(attregex2);
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].substr(1,y[2].length-2);
else {
if(y[1].substr(0,6) === "xmlns:") w = "xmlns"+y[1].substr(6);
else w = y[1].substr(j+1);
z[w] = y[2].substr(1,y[2].length-2);
}
}
return z;
}
// ----
function xlml_format(format, value) {
var fmt = XLMLFormatMap[format] || unescapexml(format);
if(fmt === "General") return SSF._general(value);
return SSF.format(fmt, value);
}
function xlml_set_custprop(Custprops, Rn, cp, val) {
switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) {
case "boolean": val = parsexmlbool(val); break;
case "i2": case "int": val = parseInt(val, 10); break;
case "r4": case "float": val = parseFloat(val); break;
case "date": case "dateTime.tz": val = new Date(val); break;
case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break;
default: throw "bad custprop:" + cp[0];
}
Custprops[unescapexml(Rn[3])] = val;
}
function safe_format_xlml(cell, nf, o) {
try {
if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
else if(nf === "General") {
if(cell.t === 'n') {
if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v);
else cell.w = SSF._general_num(cell.v);
}
else cell.w = SSF._general(cell.v);
}
else cell.w = xlml_format(nf||"General", cell.v);
if(o.cellNF) cell.z = XLMLFormatMap[nf]||nf||"General";
} catch(e) { if(o.WTF) throw e; }
}
function process_style_xlml(styles, stag, opts) {
if(opts.cellStyles) {
if(stag.Interior) {
var I = stag.Interior;
if(I.Pattern) I.patternType = XLMLPatternTypeMap[I.Pattern] || I.Pattern;
}
}
styles[stag.ID] = stag;
}
/* TODO: there must exist some form of OSP-blessed spec */
function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, o) {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
if(sid === undefined && row) sid = row.StyleID;
if(sid === undefined && csty) sid = csty.StyleID;
while(styles[sid] !== undefined) {
if(styles[sid].nf) nf = styles[sid].nf;
if(styles[sid].Interior) interiors.push(styles[sid].Interior);
if(!styles[sid].Parent) break;
sid = styles[sid].Parent;
}
switch(data.Type) {
case 'Boolean':
cell.t = 'b';
cell.v = parsexmlbool(xml);
break;
case 'String':
cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
cell.v = xml.indexOf("<") > -1 ? ss : cell.r;
break;
case 'DateTime':
cell.v = (Date.parse(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
if(cell.v !== cell.v) cell.v = unescapexml(xml);
else if(cell.v >= 1 && cell.v<60) cell.v = cell.v -1;
if(!nf || nf == "General") nf = "yyyy-mm-dd";
/* falls through */
case 'Number':
if(cell.v === undefined) cell.v=+xml;
if(!cell.t) cell.t = 'n';
break;
case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; cell.w = xml; break;
default: cell.t = 's'; cell.v = xlml_fixstr(ss); break;
}
safe_format_xlml(cell, nf, o);
if(o.cellFormula != null && cell.Formula) {
cell.f = rc_to_a1(unescapexml(cell.Formula), base);
cell.Formula = undefined;
}
if(o.cellStyles) {
interiors.forEach(function(x) {
if(!S.patternType && x.patternType) S.patternType = x.patternType;
});
cell.s = S;
}
cell.ixfe = cell.StyleID !== undefined ? cell.StyleID : 'Default';
}
function xlml_clean_comment(comment) {
comment.t = comment.v;
comment.v = comment.w = comment.ixfe = undefined;
}
function xlml_normalize(d) {
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw "badf";
}
/* TODO: Everything */
var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts) {
var str = xlml_normalize(d);
var Rn;
var state = [], tmp;
var sheets = {}, sheetnames = [], cursheet = {}, sheetname = "";
var table = {}, cell = {}, row = {}, dtag, didx;
var c = 0, r = 0;
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
var styles = {}, stag = {};
var ss = "", fidx = 0;
var mergecells = [];
var Props = {}, Custprops = {}, pidx = 0, cp = {};
var comments = [], comment = {};
var cstys = [], csty;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'Data':
if(state[state.length-1][1]) break;
if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, opts);
else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
break;
case 'Cell':
if(Rn[1]==='/'){
if(comments.length > 0) cell.c = comments;
if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) cursheet[encode_col(c) + encode_row(r)] = cell;
if(cell.HRef) {
cell.l = {Target:cell.HRef, tooltip:cell.HRefScreenTip};
cell.HRef = cell.HRefScreenTip = undefined;
}
if(cell.MergeAcross || cell.MergeDown) {
var cc = c + (parseInt(cell.MergeAcross,10)|0);
var rr = r + (parseInt(cell.MergeDown,10)|0);
mergecells.push({s:{c:c,r:r},e:{c:cc,r:rr}});
}
++c;
if(cell.MergeAcross) c += +cell.MergeAcross;
} else {
cell = xlml_parsexmltagobj(Rn[0]);
if(cell.Index) c = +cell.Index - 1;
if(c < refguess.s.c) refguess.s.c = c;
if(c > refguess.e.c) refguess.e.c = c;
if(Rn[0].substr(-2) === "/>") ++c;
comments = [];
}
break;
case 'Row':
if(Rn[1]==='/' || Rn[0].substr(-2) === "/>") {
if(r < refguess.s.r) refguess.s.r = r;
if(r > refguess.e.r) refguess.e.r = r;
if(Rn[0].substr(-2) === "/>") {
row = xlml_parsexmltag(Rn[0]);
if(row.Index) r = +row.Index - 1;
}
c = 0; ++r;
} else {
row = xlml_parsexmltag(Rn[0]);
if(row.Index) r = +row.Index - 1;
}
break;
case 'Worksheet': /* TODO: read range from FullRows/FullColumns */
if(Rn[1]==='/'){
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
sheetnames.push(sheetname);
if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) cursheet["!ref"] = encode_range(refguess);
if(mergecells.length) cursheet["!merges"] = mergecells;
sheets[sheetname] = cursheet;
} else {
refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
r = c = 0;
state.push([Rn[3], false]);
tmp = xlml_parsexmltag(Rn[0]);
sheetname = tmp.Name;
cursheet = {};
mergecells = [];
}
break;
case 'Table':
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].slice(-2) == "/>") break;
else {
table = xlml_parsexmltag(Rn[0]);
state.push([Rn[3], false]);
cstys = [];
}
break;
case 'Style':
if(Rn[1]==='/') process_style_xlml(styles, stag, opts);
else stag = xlml_parsexmltag(Rn[0]);
break;
case 'NumberFormat':
stag.nf = xlml_parsexmltag(Rn[0]).Format || "General";
break;
case 'Column':
if(state[state.length-1][0] !== 'Table') break;
csty = xlml_parsexmltag(Rn[0]);
cstys[(csty.Index-1||cstys.length)] = csty;
for(var i = 0; i < +csty.Span; ++i) cstys[cstys.length] = csty;
break;
case 'NamedRange': break;
case 'NamedCell': break;
case 'B': break;
case 'I': break;
case 'U': break;
case 'S': break;
case 'Sub': break;
case 'Sup': break;
case 'Span': break;
case 'Border': break;
case 'Alignment': break;
case 'Borders': break;
case 'Font':
if(Rn[0].substr(-2) === "/>") break;
else if(Rn[1]==="/") ss += str.slice(fidx, Rn.index);
else fidx = Rn.index + Rn[0].length;
break;
case 'Interior':
if(!opts.cellStyles) break;
stag.Interior = xlml_parsexmltag(Rn[0]);
break;
case 'Protection': break;
case 'Author':
case 'Title':
case 'Description':
case 'Created':
case 'Keywords':
case 'Subject':
case 'Category':
case 'Company':
case 'LastAuthor':
case 'LastSaved':
case 'LastPrinted':
case 'Version':
case 'Revision':
case 'TotalTime':
case 'HyperlinkBase':
case 'Manager':
if(Rn[0].substr(-2) === "/>") break;
else if(Rn[1]==="/") xlml_set_prop(Props, Rn[3], str.slice(pidx, Rn.index));
else pidx = Rn.index + Rn[0].length;
break;
case 'Paragraphs': break;
case 'Styles':
case 'Workbook':
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else state.push([Rn[3], false]);
break;
case 'Comment':
if(Rn[1]==='/'){
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
xlml_clean_comment(comment);
comments.push(comment);
} else {
state.push([Rn[3], false]);
tmp = xlml_parsexmltag(Rn[0]);
comment = {a:tmp.Author};
}
break;
case 'Name': break;
case 'ComponentOptions':
case 'DocumentProperties':
case 'CustomDocumentProperties':
case 'OfficeDocumentSettings':
case 'PivotTable':
case 'PivotCache':
case 'Names':
case 'MapInfo':
case 'PageBreaks':
case 'QueryTable':
case 'DataValidation':
case 'AutoFilter':
case 'Sorting':
case 'Schema':
case 'data':
case 'ConditionalFormatting':
case 'SmartTagType':
case 'SmartTags':
case 'ExcelWorkbook':
case 'WorkbookOptions':
case 'WorksheetOptions':
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
default:
var seen = true;
switch(state[state.length-1][0]) {
/* OfficeDocumentSettings */
case 'OfficeDocumentSettings': switch(Rn[3]) {
case 'AllowPNG': break;
case 'RemovePersonalInformation': break;
case 'DownloadComponents': break;
case 'LocationOfComponents': break;
case 'Colors': break;
case 'Color': break;
case 'Index': break;
case 'RGB': break;
case 'PixelsPerInch': break;
case 'TargetScreenSize': break;
case 'ReadOnlyRecommended': break;
default: seen = false;
} break;
/* ComponentOptions */
case 'ComponentOptions': switch(Rn[3]) {
case 'Toolbar': break;
case 'HideOfficeLogo': break;
case 'SpreadsheetAutoFit': break;
case 'Label': break;
case 'Caption': break;
case 'MaxHeight': break;
case 'MaxWidth': break;
case 'NextSheetNumber': break;
default: seen = false;
} break;
/* ExcelWorkbook */
case 'ExcelWorkbook': switch(Rn[3]) {
case 'WindowHeight': break;
case 'WindowWidth': break;
case 'WindowTopX': break;
case 'WindowTopY': break;
case 'TabRatio': break;
case 'ProtectStructure': break;
case 'ProtectWindows': break;
case 'ActiveSheet': break;
case 'DisplayInkNotes': break;
case 'FirstVisibleSheet': break;
case 'SupBook': break;
case 'SheetName': break;
case 'SheetIndex': break;
case 'SheetIndexFirst': break;
case 'SheetIndexLast': break;
case 'Dll': break;
case 'AcceptLabelsInFormulas': break;
case 'DoNotSaveLinkValues': break;
case 'Date1904': break;
case 'Iteration': break;
case 'MaxIterations': break;
case 'MaxChange': break;
case 'Path': break;
case 'Xct': break;
case 'Count': break;
case 'SelectedSheets': break;
case 'Calculation': break;
case 'Uncalced': break;
case 'StartupPrompt': break;
case 'Crn': break;
case 'ExternName': break;
case 'Formula': break;
case 'ColFirst': break;
case 'ColLast': break;
case 'WantAdvise': break;
case 'Boolean': break;
case 'Error': break;
case 'Text': break;
case 'OLE': break;
case 'NoAutoRecover': break;
case 'PublishObjects': break;
case 'DoNotCalculateBeforeSave': break;
case 'Number': break;
case 'RefModeR1C1': break;
case 'EmbedSaveSmartTags': break;
default: seen = false;
} break;
/* WorkbookOptions */
case 'WorkbookOptions': switch(Rn[3]) {
case 'OWCVersion': break;
case 'Height': break;
case 'Width': break;
default: seen = false;
} break;
/* WorksheetOptions */
case 'WorksheetOptions': switch(Rn[3]) {
case 'Unsynced': break;
case 'Visible': break;
case 'Print': break;
case 'Panes': break;
case 'Scale': break;
case 'Pane': break;
case 'Number': break;
case 'Layout': break;
case 'Header': break;
case 'Footer': break;
case 'PageSetup': break;
case 'PageMargins': break;
case 'Selected': break;
case 'ProtectObjects': break;
case 'EnableSelection': break;
case 'ProtectScenarios': break;
case 'ValidPrinterInfo': break;
case 'HorizontalResolution': break;
case 'VerticalResolution': break;
case 'NumberofCopies': break;
case 'ActiveRow': break;
case 'ActiveCol': break;
case 'ActivePane': break;
case 'TopRowVisible': break;
case 'TopRowBottomPane': break;
case 'LeftColumnVisible': break;
case 'LeftColumnRightPane': break;
case 'FitToPage': break;
case 'RangeSelection': break;
case 'PaperSizeIndex': break;
case 'PageLayoutZoom': break;
case 'PageBreakZoom': break;
case 'FilterOn': break;
case 'DoNotDisplayGridlines': break;
case 'SplitHorizontal': break;
case 'SplitVertical': break;
case 'FreezePanes': break;
case 'FrozenNoSplit': break;
case 'FitWidth': break;
case 'FitHeight': break;
case 'CommentsLayout': break;
case 'Zoom': break;
case 'LeftToRight': break;
case 'Gridlines': break;
case 'AllowSort': break;
case 'AllowFilter': break;
case 'AllowInsertRows': break;
case 'AllowDeleteRows': break;
case 'AllowInsertCols': break;
case 'AllowDeleteCols': break;
case 'AllowInsertHyperlinks': break;
case 'AllowFormatCells': break;
case 'AllowSizeCols': break;
case 'AllowSizeRows': break;
case 'NoSummaryRowsBelowDetail': break;
case 'TabColorIndex': break;
case 'DoNotDisplayHeadings': break;
case 'ShowPageLayoutZoom': break;
case 'NoSummaryColumnsRightDetail': break;
case 'BlackAndWhite': break;
case 'DoNotDisplayZeros': break;
case 'DisplayPageBreak': break;
case 'RowColHeadings': break;
case 'DoNotDisplayOutline': break;
case 'NoOrientation': break;
case 'AllowUsePivotTables': break;
case 'ZeroHeight': break;
case 'ViewableRange': break;
case 'Selection': break;
case 'ProtectContents': break;
default: seen = false;
} break;
/* PivotTable */
case 'PivotTable': case 'PivotCache': switch(Rn[3]) {
case 'ImmediateItemsOnDrop': break;
case 'ShowPageMultipleItemLabel': break;
case 'CompactRowIndent': break;
case 'Location': break;
case 'PivotField': break;
case 'Orientation': break;
case 'LayoutForm': break;
case 'LayoutSubtotalLocation': break;
case 'LayoutCompactRow': break;
case 'Position': break;
case 'PivotItem': break;
case 'DataType': break;
case 'DataField': break;
case 'SourceName': break;
case 'ParentField': break;
case 'PTLineItems': break;
case 'PTLineItem': break;
case 'CountOfSameItems': break;
case 'Item': break;
case 'ItemType': break;
case 'PTSource': break;
case 'CacheIndex': break;
case 'ConsolidationReference': break;
case 'FileName': break;
case 'Reference': break;
case 'NoColumnGrand': break;
case 'NoRowGrand': break;
case 'BlankLineAfterItems': break;
case 'Hidden': break;
case 'Subtotal': break;
case 'BaseField': break;
case 'MapChildItems': break;
case 'Function': break;
case 'RefreshOnFileOpen': break;
case 'PrintSetTitles': break;
case 'MergeLabels': break;
case 'DefaultVersion': break;
case 'RefreshName': break;
case 'RefreshDate': break;
case 'RefreshDateCopy': break;
case 'VersionLastRefresh': break;
case 'VersionLastUpdate': break;
case 'VersionUpdateableMin': break;
case 'VersionRefreshableMin': break;
case 'Calculation': break;
default: seen = false;
} break;
/* PageBreaks */
case 'PageBreaks': switch(Rn[3]) {
case 'ColBreaks': break;
case 'ColBreak': break;
case 'RowBreaks': break;
case 'RowBreak': break;
case 'ColStart': break;
case 'ColEnd': break;
case 'RowEnd': break;
default: seen = false;
} break;
/* AutoFilter */
case 'AutoFilter': switch(Rn[3]) {
case 'AutoFilterColumn': break;
case 'AutoFilterCondition': break;
case 'AutoFilterAnd': break;
case 'AutoFilterOr': break;
default: seen = false;
} break;
/* QueryTable */
case 'QueryTable': switch(Rn[3]) {
case 'Id': break;
case 'AutoFormatFont': break;
case 'AutoFormatPattern': break;
case 'QuerySource': break;
case 'QueryType': break;
case 'EnableRedirections': break;
case 'RefreshedInXl9': break;
case 'URLString': break;
case 'HTMLTables': break;
case 'Connection': break;
case 'CommandText': break;
case 'RefreshInfo': break;
case 'NoTitles': break;
case 'NextId': break;
case 'ColumnInfo': break;
case 'OverwriteCells': break;
case 'DoNotPromptForFile': break;
case 'TextWizardSettings': break;
case 'Source': break;
case 'Number': break;
case 'Decimal': break;
case 'ThousandSeparator': break;
case 'TrailingMinusNumbers': break;
case 'FormatSettings': break;
case 'FieldType': break;
case 'Delimiters': break;
case 'Tab': break;
case 'Comma': break;
case 'AutoFormatName': break;
case 'VersionLastEdit': break;
case 'VersionLastRefresh': break;
default: seen = false;
} break;
/* Sorting */
case 'Sorting':
/* ConditionalFormatting */
case 'ConditionalFormatting':
/* DataValidation */
case 'DataValidation': switch(Rn[3]) {
case 'Range': break;
case 'Type': break;
case 'Min': break;
case 'Max': break;
case 'Sort': break;
case 'Descending': break;
case 'Order': break;
case 'CaseSensitive': break;
case 'Value': break;
case 'ErrorStyle': break;
case 'ErrorMessage': break;
case 'ErrorTitle': break;
case 'CellRangeList': break;
case 'InputMessage': break;
case 'InputTitle': break;
case 'ComboHide': break;
case 'InputHide': break;
case 'Condition': break;
case 'Qualifier': break;
case 'UseBlank': break;
case 'Value1': break;
case 'Value2': break;
case 'Format': break;
default: seen = false;
} break;
/* MapInfo (schema) */
case 'MapInfo': case 'Schema': case 'data': switch(Rn[3]) {
case 'Map': break;
case 'Entry': break;
case 'Range': break;
case 'XPath': break;
case 'Field': break;
case 'XSDType': break;
case 'FilterOn': break;
case 'Aggregate': break;
case 'ElementType': break;
case 'AttributeType': break;
/* These are from xsd (XML Schema Definition) */
case 'schema':
case 'element':
case 'complexType':
case 'datatype':
case 'all':
case 'attribute':
case 'extends': break;
case 'row': break;
default: seen = false;
} break;
/* SmartTags (can be anything) */
case 'SmartTags': break;
default: seen = false; break;
}
if(seen) break;
/* CustomDocumentProperties */
if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
if(state[state.length-1][0]==='CustomDocumentProperties') {
if(Rn[0].substr(-2) === "/>") break;
else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn, cp, str.slice(pidx, Rn.index));
else { cp = Rn; pidx = Rn.index + Rn[0].length; }
break;
}
if(opts.WTF) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
}
var out = {};
if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
out.SheetNames = sheetnames;
out.SSF = SSF.get_table();
out.Props = Props;
out.Custprops = Custprops;
return out;
}
function parse_xlml(data, opts) {
fix_read_opts(opts=opts||{});
switch(opts.type||"base64") {
case "base64": return parse_xlml_xml(Base64.decode(data), opts);
case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
case "array": return parse_xlml_xml(data.map(_chr).join(""), opts);
}
}
function write_xlml(wb, opts) { }

675
bits/81_xls.js Normal file

@ -0,0 +1,675 @@
/* [MS-OLEDS] 2.3.8 CompObjStream */
function parse_compobj(obj) {
var v = {};
var o = obj.content;
/* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
var l = 28, m;
m = __lpstr(o, l);
l += 4 + __readUInt32LE(o,l);
v.UserType = m;
/* [MS-OLEDS] 2.3.1 ClipboardFormatOrAnsiString */
m = __readUInt32LE(o,l); l+= 4;
switch(m) {
case 0x00000000: break;
case 0xffffffff: case 0xfffffffe: l+=4; break;
default:
if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
l += m;
}
m = __lpstr(o, l); l += m.length === 0 ? 0 : 5 + m.length; v.Reserved1 = m;
if((m = __readUInt32LE(o,l)) !== 0x71b2e9f4) return v;
throw "Unsupported Unicode Extension";
}
/* 2.4.58 Continue logic */
function slurp(R, blob, length, opts) {
var l = length;
var bufs = [];
var d = blob.slice(blob.l,blob.l+l);
if(opts && opts.enc && opts.enc.insitu_decrypt) switch(R.n) {
case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': break;
default:
if(d.length === 0) break;
opts.enc.insitu_decrypt(d);
}
bufs.push(d);
blob.l += l;
var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]);
while(next != null && next.n === 'Continue') {
l = __readUInt16LE(blob,blob.l+2);
bufs.push(blob.slice(blob.l+4,blob.l+4+l));
blob.l += 4+l;
next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]);
}
var b = bconcat(bufs);
prep_blob(b, 0);
var ll = 0; b.lens = [];
for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; }
return R.f(b, b.length, opts);
}
function safe_format_xf(p, opts, date1904) {
if(!p.XF) return;
try {
var fmtid = p.XF.ifmt||0;
if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
else if(fmtid === 0) {
if(p.t === 'n') {
if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
else p.w = SSF._general_num(p.v);
}
else p.w = SSF._general(p.v);
}
else p.w = SSF.format(fmtid,p.v, {date1904:date1904||false});
if(opts.cellNF) p.z = SSF._table[fmtid];
} catch(e) { if(opts.WTF) throw e; }
}
function make_cell(val, ixfe, t) {
return {v:val, ixfe:ixfe, t:t};
}
// 2.3.2
function parse_workbook(blob, options) {
var wb = {opts:{}};
var Sheets = {};
var out = {};
var Directory = {};
var found_sheet = false;
var range = {};
var last_formula = null;
var sst = [];
var cur_sheet = "";
var Preamble = {};
var lastcell, last_cell, cc, cmnt, rng, rngC, rngR;
var shared_formulae = {};
var array_formulae = []; /* TODO: something more clever */
var temp_val;
var country;
var cell_valid = true;
var XFs = []; /* XF records */
var palette = [];
var get_rgb = function getrgb(icv) {
if(icv < 8) return XLSIcv[icv];
if(icv < 64) return palette[icv-8] || XLSIcv[icv];
return XLSIcv[icv];
};
var process_cell_style = function pcs(cell, line) {
var xfd = line.XF.data;
if(!xfd || !xfd.patternType) return;
line.s = {};
line.s.patternType = xfd.patternType;
var t;
if((t = rgb2Hex(get_rgb(xfd.icvFore)))) { line.s.fgColor = {rgb:t}; }
if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
};
var addcell = function addcell(cell, line, options) {
if(!cell_valid) return;
if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line);
lastcell = cell;
last_cell = encode_cell(cell);
if(range.s) {
if(cell.r < range.s.r) range.s.r = cell.r;
if(cell.c < range.s.c) range.s.c = cell.c;
}
if(range.e) {
if(cell.r + 1 > range.e.r) range.e.r = cell.r + 1;
if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1;
}
if(options.sheetRows && lastcell.r >= options.sheetRows) cell_valid = false;
else out[last_cell] = line;
};
var opts = {
enc: false, // encrypted
sbcch: 0, // cch in the preceding SupBook
snames: [], // sheetnames
sharedf: shared_formulae, // shared formulae by address
arrayf: array_formulae, // array formulae array
rrtabid: [], // RRTabId
lastuser: "", // Last User from WriteAccess
biff: 8, // BIFF version
codepage: 0, // CP from CodePage record
winlocked: 0, // fLockWn from WinProtect
wtf: false
};
if(options.password) opts.password = options.password;
var mergecells = [];
var objects = [];
var supbooks = [[]]; // 1-indexed, will hold extern names
var sbc = 0, sbci = 0, sbcli = 0;
supbooks.SheetNames = opts.snames;
supbooks.sharedf = opts.sharedf;
supbooks.arrayf = opts.arrayf;
var last_Rn = '';
var file_depth = 0; /* TODO: make a real stack */
/* explicit override for some broken writers */
opts.codepage = 1200;
set_cp(1200);
while(blob.l < blob.length - 1) {
var s = blob.l;
var RecordType = blob.read_shift(2);
if(RecordType === 0 && last_Rn === 'EOF') break;
var length = (blob.l === blob.length ? 0 : blob.read_shift(2)), y;
var R = XLSRecordEnum[RecordType];
if(R && R.f) {
if(options.bookSheets) {
if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
}
last_Rn = R.n;
if(R.r === 2 || R.r == 12) {
var rt = blob.read_shift(2); length -= 2;
if(!opts.enc && rt !== RecordType) throw "rt mismatch";
if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
}
//console.error(R,blob.l,length,blob.length);
var val;
if(R.n === 'EOF') val = R.f(blob, length, opts);
else val = slurp(R, blob, length, opts);
var Rn = R.n;
/* BIFF5 overrides */
if(opts.biff === 5 || opts.biff === 2) switch(Rn) {
case 'Lbl': Rn = 'Label'; break;
}
/* nested switch statements to workaround V8 128 limit */
switch(Rn) {
/* Workbook Options */
case 'Date1904': wb.opts.Date1904 = val; break;
case 'WriteProtect': wb.opts.WriteProtect = true; break;
case 'FilePass':
if(!opts.enc) blob.l = 0;
opts.enc = val;
if(opts.WTF) console.error(val);
if(!options.password) throw new Error("File is password-protected");
if(val.Type !== 0) throw new Error("Encryption scheme unsupported");
if(!val.valid) throw new Error("Password is incorrect");
break;
case 'WriteAccess': opts.lastuser = val; break;
case 'FileSharing': break; //TODO
case 'CodePage':
/* overrides based on test cases */
if(val === 0x5212) val = 1200;
else if(val === 0x8001) val = 1252;
opts.codepage = val;
set_cp(val);
break;
case 'RRTabId': opts.rrtabid = val; break;
case 'WinProtect': opts.winlocked = val; break;
case 'Template': break; // TODO
case 'RefreshAll': wb.opts.RefreshAll = val; break;
case 'BookBool': break; // TODO
case 'UsesELFs': /* if(val) console.error("Unsupported ELFs"); */ break;
case 'MTRSettings': {
if(val[0] && val[1]) throw "Unsupported threads: " + val;
} break; // TODO: actually support threads
case 'CalcCount': wb.opts.CalcCount = val; break;
case 'CalcDelta': wb.opts.CalcDelta = val; break;
case 'CalcIter': wb.opts.CalcIter = val; break;
case 'CalcMode': wb.opts.CalcMode = val; break;
case 'CalcPrecision': wb.opts.CalcPrecision = val; break;
case 'CalcSaveRecalc': wb.opts.CalcSaveRecalc = val; break;
case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
case 'Uncalced': break;
case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
case 'WsBool': break; // TODO
case 'XF': XFs.push(val); break;
case 'ExtSST': break; // TODO
case 'BookExt': break; // TODO
case 'RichTextStream': break;
case 'BkHim': break;
case 'SupBook': supbooks[++sbc] = [val]; sbci = 0; break;
case 'ExternName': supbooks[sbc][++sbci] = val; break;
case 'Index': break; // TODO
case 'Lbl': supbooks[0][++sbcli] = val; break;
case 'ExternSheet': supbooks[sbc] = supbooks[sbc].concat(val); sbci += val.length; break;
case 'Protect': out["!protect"] = val; break; /* for sheet or book */
case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/
case 'BoundSheet8': {
Directory[val.pos] = val;
opts.snames.push(val.name);
} break;
case 'EOF': {
if(--file_depth) break;
if(range.e) {
out["!range"] = range;
if(range.e.r > 0 && range.e.c > 0) {
range.e.r--; range.e.c--;
out["!ref"] = encode_range(range);
range.e.r++; range.e.c++;
}
if(mergecells.length > 0) out["!merges"] = mergecells;
if(objects.length > 0) out["!objects"] = objects;
}
if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
out = {};
} break;
case 'BOF': {
if(opts.biff !== 8);
else if(val.BIFFVer === 0x0500) opts.biff = 5;
else if(val.BIFFVer === 0x0002) opts.biff = 2;
else if(val.BIFFVer === 0x0007) opts.biff = 2;
if(file_depth++) break;
cell_valid = true;
out = {};
if(opts.biff === 2) {
if(cur_sheet === "") cur_sheet = "Sheet1";
range = {s:{r:0,c:0},e:{r:0,c:0}};
}
else cur_sheet = (Directory[s] || {name:""}).name;
mergecells = [];
objects = [];
} break;
case 'Number': case 'BIFF2NUM': {
temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:'n'};
if(temp_val.XF) 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(temp_val.XF) 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(temp_val.XF) safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 'MulRk': {
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(temp_val.XF) safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:j, r:val.r}, temp_val, options);
}
} break;
case 'Formula': {
switch(val.val) {
case 'String': last_formula = val; break;
case 'Array Formula': throw "Array Formula unsupported";
default:
temp_val = {v:val.val, ixfe:val.cell.ixfe, t:val.tt};
temp_val.XF = XFs[temp_val.ixfe];
if(options.cellFormula) temp_val.f = "="+stringify_formula(val.formula,range,val.cell,supbooks, opts);
if(temp_val.XF) safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(val.cell, temp_val, options);
last_formula = val;
}
} break;
case 'String': {
if(last_formula) {
last_formula.val = val;
temp_val = {v:last_formula.val, ixfe:last_formula.cell.ixfe, t:'s'};
temp_val.XF = XFs[temp_val.ixfe];
if(options.cellFormula) temp_val.f = "="+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
if(temp_val.XF) safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(last_formula.cell, temp_val, options);
last_formula = null;
}
} break;
case 'Array': {
array_formulae.push(val);
} break;
case 'ShrFmla': {
if(!cell_valid) break;
//if(options.cellFormula) out[last_cell].f = stringify_formula(val[0], range, lastcell, supbooks, opts);
/* TODO: capture range */
shared_formulae[encode_cell(last_formula.cell)]= val[0];
} break;
case 'LabelSst':
//temp_val={v:sst[val.isst].t, ixfe:val.ixfe, t:'s'};
temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
temp_val.XF = XFs[temp_val.ixfe];
if(temp_val.XF) safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'Label': case 'BIFF2STR':
/* Some writers erroneously write Label */
temp_val=make_cell(val.val, val.ixfe, 's');
temp_val.XF = XFs[temp_val.ixfe];
if(temp_val.XF) safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 'Dimensions': {
if(file_depth === 1) range = val; /* TODO: stack */
} break;
case 'SST': {
sst = val;
} break;
case 'Format': { /* val = [id, fmt] */
SSF.load(val[1], val[0]);
} 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 '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)
if(out[encode_cell({c:rngC,r:rngR})])
out[encode_cell({c:rngC,r:rngR})].l = val[1];
} break;
case 'HLinkTooltip': {
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC)
if(out[encode_cell({c:rngC,r:rngR})])
out[encode_cell({c:rngC,r:rngR})].l.tooltip = val[1];
} break;
/* Comments */
case 'Note': {
if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
cc = out[encode_cell(val[0])];
var noteobj = objects[val[2]];
if(!cc) break;
if(!cc.c) cc.c = [];
cmnt = {a:val[1],t:noteobj.TxO.t};
cc.c.push(cmnt);
} break;
default: switch(R.n) { /* nested */
case 'ClrtClient': break;
case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break;
case 'NameCmt': break;
case 'Header': break; // TODO
case 'Footer': break; // TODO
case 'HCenter': break; // TODO
case 'VCenter': break; // TODO
case 'Pls': break; // TODO
case 'Setup': break; // TODO
case 'DefColWidth': break; // TODO
case 'GCW': break;
case 'LHRecord': break;
case 'ColInfo': break; // TODO
case 'Row': break; // TODO
case 'DBCell': break; // TODO
case 'MulBlank': break; // TODO
case 'EntExU2': break; // TODO
case 'SxView': break; // TODO
case 'Sxvd': break; // TODO
case 'SXVI': break; // TODO
case 'SXVDEx': break; // TODO
case 'SxIvd': break; // TODO
case 'SXDI': break; // TODO
case 'SXLI': break; // TODO
case 'SXEx': break; // TODO
case 'QsiSXTag': break; // TODO
case 'Selection': break;
case 'Feat': break;
case 'FeatHdr': case 'FeatHdr11': break;
case 'Feature11': case 'Feature12': case 'List12': break;
case 'Blank': break;
case 'Country': country = val; break;
case 'RecalcId': break;
case 'DefaultRowHeight': case 'DxGCol': break; // TODO: htmlify
case 'Fbi': case 'Fbi2': case 'GelFrame': break;
case 'Font': break; // TODO
case 'XFCRC': break; // TODO
case 'Style': break; // TODO
case 'StyleExt': break; // TODO
case 'Palette': palette = val; break; // TODO
case 'Theme': break; // TODO
/* Protection */
case 'ScenarioProtect': break;
case 'ObjProtect': break;
/* Conditional Formatting */
case 'CondFmt12': break;
/* Table */
case 'Table': break; // TODO
case 'TableStyles': break; // TODO
case 'TableStyle': break; // TODO
case 'TableStyleElement': break; // TODO
/* PivotTable */
case 'SXStreamID': break; // TODO
case 'SXVS': break; // TODO
case 'DConRef': break; // TODO
case 'SXAddl': break; // TODO
case 'DConBin': break; // TODO
case 'DConName': break; // TODO
case 'SXPI': break; // TODO
case 'SxFormat': break; // TODO
case 'SxSelect': break; // TODO
case 'SxRule': break; // TODO
case 'SxFilt': break; // TODO
case 'SxItm': break; // TODO
case 'SxDXF': break; // TODO
/* Scenario Manager */
case 'ScenMan': break;
/* Data Consolidation */
case 'DCon': break;
/* Watched Cell */
case 'CellWatch': break;
/* Print Settings */
case 'PrintRowCol': break;
case 'PrintGrid': break;
case 'PrintSize': break;
case 'XCT': break;
case 'CRN': break;
case 'Scl': {
//console.log("Zoom Level:", val[0]/val[1],val);
} break;
case 'SheetExt': {
} break;
case 'SheetExtOptional': {
} break;
/* VBA */
case 'ObNoMacros': {
} break;
case 'ObProj': {
} break;
case 'CodeName': {
} break;
case 'GUIDTypeLib': {
} break;
case 'WOpt': break; // TODO: WTF?
case 'PhoneticInfo': break;
case 'OleObjectSize': break;
/* Differential Formatting */
case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break;
/* Data Validation */
case 'Dv': case 'DVal': break;
/* Data Series */
case 'BRAI': case 'Series': case 'SeriesText': break;
/* Data Connection */
case 'DConn': break;
case 'DbOrParamQry': break;
case 'DBQueryExt': break;
/* Formatting */
case 'IFmtRecord': break;
case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
/* Explicitly Ignored */
case 'Excel9File': break;
case 'Units': break;
case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': case 'BuiltInFnGroupCount':
/* View Stuff */
case 'Window1': case 'Window2': case 'HideObj': case 'GridSet': case 'Guts':
case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd':
case 'Pane': break;
default: switch(R.n) { /* nested */
/* Chart */
case 'Dat':
case 'Begin': case 'End':
case 'StartBlock': case 'EndBlock':
case 'Frame': case 'Area':
case 'Axis': case 'AxisLine': case 'Tick': break;
case 'AxesUsed':
case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break;
case 'LineFormat': case 'AreaFormat':
case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break;
case 'PlotArea': case 'PlotGrowth': break;
case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break;
case 'DataFormat': case 'SerToCrt': case 'FontX': break;
case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
case 'ShtProps': break;
case 'DefaultText': case 'Text': case 'CatLab': break;
case 'DataLabExtContents': break;
case 'Legend': case 'LegendException': break;
case 'Pie': case 'Scatter': break;
case 'PieFormat': case 'MarkerFormat': break;
case 'StartObject': case 'EndObject': break;
case 'AlRuns': case 'ObjectLink': break;
case 'SIIndex': break;
case 'AttachedLabel': case 'YMult': break;
/* Chart Group */
case 'Line': case 'Bar': break;
case 'Surf': break;
/* Axis Group */
case 'AxisParent': break;
case 'Pos': break;
case 'ValueRange': break;
/* Pivot Chart */
case 'SXViewEx9': break; // TODO
case 'SXViewLink': break;
case 'PivotChartBits': break;
case 'SBaseRef': break;
case 'TextPropsStream': break;
/* Chart Misc */
case 'LnExt': break;
case 'MkrExt': break;
case 'CrtCoopt': break;
/* Query Table */
case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break;
case 'TxtQry': break;
/* Filter */
case 'FilterMode': break;
case 'AutoFilter': case 'AutoFilterInfo': break;
case 'AutoFilter12': break;
case 'DropDownObjIds': break;
case 'Sort': break;
case 'SortData': break;
/* Drawing */
case 'ShapePropsStream': break;
case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
case 'ImData': break;
/* Pub Stuff */
case 'WebPub': case 'AutoWebPub':
/* Print Stuff */
case 'RightMargin': case 'LeftMargin': case 'TopMargin': case 'BottomMargin':
case 'HeaderFooter': case 'HFPicture': case 'PLV':
case 'HorizontalPageBreaks': case 'VerticalPageBreaks':
/* Behavioral */
case 'Backup': case 'CompressPictures': case 'Compat12': break;
/* Should not Happen */
case 'Continue': case 'ContinueFrt12': break;
/* Future Records */
case 'FrtFontList': case 'FrtWrapper': break;
/* BIFF5 records */
case 'ExternCount': break;
case 'RString': break;
case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
default: switch(R.n) { /* nested */
/* Miscellaneous */
case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':
case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData':
case 'Name': break;
default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
}}}}
} else blob.l += length;
}
var sheetnamesraw = opts.biff === 2 ? ['Sheet1'] : Object.keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;});
var sheetnames = sheetnamesraw.slice();
wb.Directory=sheetnamesraw;
wb.SheetNames=sheetnamesraw;
if(!options.bookSheets) wb.Sheets=Sheets;
wb.Preamble=Preamble;
wb.Strings = sst;
wb.SSF = SSF.get_table();
if(opts.enc) wb.Encryption = opts.enc;
wb.Metadata = {};
if(country !== undefined) wb.Metadata.Country = country;
return wb;
}
function parse_xlscfb(cfb, options) {
if(!options) options = {};
fix_read_opts(options);
reset_cp();
var CompObj, Summary, Workbook;
if(cfb.find) {
CompObj = cfb.find('!CompObj');
Summary = cfb.find('!SummaryInformation');
Workbook = cfb.find('/Workbook');
} else {
prep_blob(cfb, 0);
Workbook = {content: cfb};
}
if(!Workbook) Workbook = cfb.find('/Book');
var CompObjP, SummaryP, WorkbookP;
if(CompObj) CompObjP = parse_compobj(CompObj);
if(options.bookProps && !options.bookSheets) WorkbookP = {};
else {
if(Workbook) WorkbookP = parse_workbook(Workbook.content, options, !!Workbook.find);
else throw new Error("Cannot find Workbook stream");
}
if(cfb.find) parse_props(cfb);
var props = {};
for(var y in cfb.Summary) props[y] = cfb.Summary[y];
for(y in cfb.DocSummary) props[y] = cfb.DocSummary[y];
WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
if(options.bookFiles) WorkbookP.cfb = cfb;
WorkbookP.CompObjP = CompObjP;
return WorkbookP;
}
/* TODO: WTF */
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) {}
/* [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) {}
}

@ -1,5 +1,5 @@
/* [MS-XLSB] 2.3 Record Enumeration */
var RecordEnum = {
var XLSBRecordEnum = {
0x0000: { n:"BrtRowHdr", f:parse_BrtRowHdr },
0x0001: { n:"BrtCellBlank", f:parse_BrtCellBlank },
0x0002: { n:"BrtCellRk", f:parse_BrtCellRk },
@ -822,4 +822,409 @@ var RecordEnum = {
0xFFFF: { n:"", f:parsenoop }
};
var evert_RE = evert_key(RecordEnum, 'n');
var evert_RE = evert_key(XLSBRecordEnum, 'n');
/* [MS-XLS] 2.3 Record Enumeration */
var XLSRecordEnum = {
0x0003: { n:"BIFF2NUM", f:parse_BIFF2NUM },
0x0004: { n:"BIFF2STR", f:parse_BIFF2STR },
0x0006: { n:"Formula", f:parse_Formula },
0x0009: { n:'BOF', f:parse_BOF },
0x000a: { n:'EOF', f:parse_EOF },
0x000c: { n:"CalcCount", f:parse_CalcCount },
0x000d: { n:"CalcMode", f:parse_CalcMode },
0x000e: { n:"CalcPrecision", f:parse_CalcPrecision },
0x000f: { n:"CalcRefMode", f:parse_CalcRefMode },
0x0010: { n:"CalcDelta", f:parse_CalcDelta },
0x0011: { n:"CalcIter", f:parse_CalcIter },
0x0012: { n:"Protect", f:parse_Protect },
0x0013: { n:"Password", f:parse_Password },
0x0014: { n:"Header", f:parse_Header },
0x0015: { n:"Footer", f:parse_Footer },
0x0017: { n:"ExternSheet", f:parse_ExternSheet },
0x0018: { n:"Lbl", f:parse_Lbl },
0x0019: { n:"WinProtect", f:parse_WinProtect },
0x001a: { n:"VerticalPageBreaks", f:parse_VerticalPageBreaks },
0x001b: { n:"HorizontalPageBreaks", f:parse_HorizontalPageBreaks },
0x001c: { n:"Note", f:parse_Note },
0x001d: { n:"Selection", f:parse_Selection },
0x0022: { n:"Date1904", f:parse_Date1904 },
0x0023: { n:"ExternName", f:parse_ExternName },
0x0026: { n:"LeftMargin", f:parse_LeftMargin },
0x0027: { n:"RightMargin", f:parse_RightMargin },
0x0028: { n:"TopMargin", f:parse_TopMargin },
0x0029: { n:"BottomMargin", f:parse_BottomMargin },
0x002a: { n:"PrintRowCol", f:parse_PrintRowCol },
0x002b: { n:"PrintGrid", f:parse_PrintGrid },
0x002f: { n:"FilePass", f:parse_FilePass },
0x0031: { n:"Font", f:parse_Font },
0x0033: { n:"PrintSize", f:parse_PrintSize },
0x003c: { n:"Continue", f:parse_Continue },
0x003d: { n:"Window1", f:parse_Window1 },
0x0040: { n:"Backup", f:parse_Backup },
0x0041: { n:"Pane", f:parse_Pane },
0x0042: { n:'CodePage', f:parse_CodePage },
0x004d: { n:"Pls", f:parse_Pls },
0x0050: { n:"DCon", f:parse_DCon },
0x0051: { n:"DConRef", f:parse_DConRef },
0x0052: { n:"DConName", f:parse_DConName },
0x0055: { n:"DefColWidth", f:parse_DefColWidth },
0x0059: { n:"XCT", f:parse_XCT },
0x005a: { n:"CRN", f:parse_CRN },
0x005b: { n:"FileSharing", f:parse_FileSharing },
0x005c: { n:'WriteAccess', f:parse_WriteAccess },
0x005d: { n:"Obj", f:parse_Obj },
0x005e: { n:"Uncalced", f:parse_Uncalced },
0x005f: { n:"CalcSaveRecalc", f:parse_CalcSaveRecalc },
0x0060: { n:"Template", f:parse_Template },
0x0061: { n:"Intl", f:parse_Intl },
0x0063: { n:"ObjProtect", f:parse_ObjProtect },
0x007d: { n:"ColInfo", f:parse_ColInfo },
0x0080: { n:"Guts", f:parse_Guts },
0x0081: { n:"WsBool", f:parse_WsBool },
0x0082: { n:"GridSet", f:parse_GridSet },
0x0083: { n:"HCenter", f:parse_HCenter },
0x0084: { n:"VCenter", f:parse_VCenter },
0x0085: { n:'BoundSheet8', f:parse_BoundSheet8 },
0x0086: { n:"WriteProtect", f:parse_WriteProtect },
0x008c: { n:"Country", f:parse_Country },
0x008d: { n:"HideObj", f:parse_HideObj },
0x0090: { n:"Sort", f:parse_Sort },
0x0092: { n:"Palette", f:parse_Palette },
0x0097: { n:"Sync", f:parse_Sync },
0x0098: { n:"LPr", f:parse_LPr },
0x0099: { n:"DxGCol", f:parse_DxGCol },
0x009a: { n:"FnGroupName", f:parse_FnGroupName },
0x009b: { n:"FilterMode", f:parse_FilterMode },
0x009c: { n:"BuiltInFnGroupCount", f:parse_BuiltInFnGroupCount },
0x009d: { n:"AutoFilterInfo", f:parse_AutoFilterInfo },
0x009e: { n:"AutoFilter", f:parse_AutoFilter },
0x00a0: { n:"Scl", f:parse_Scl },
0x00a1: { n:"Setup", f:parse_Setup },
0x00ae: { n:"ScenMan", f:parse_ScenMan },
0x00af: { n:"SCENARIO", f:parse_SCENARIO },
0x00b0: { n:"SxView", f:parse_SxView },
0x00b1: { n:"Sxvd", f:parse_Sxvd },
0x00b2: { n:"SXVI", f:parse_SXVI },
0x00b4: { n:"SxIvd", f:parse_SxIvd },
0x00b5: { n:"SXLI", f:parse_SXLI },
0x00b6: { n:"SXPI", f:parse_SXPI },
0x00b8: { n:"DocRoute", f:parse_DocRoute },
0x00b9: { n:"RecipName", f:parse_RecipName },
0x00bd: { n:"MulRk", f:parse_MulRk },
0x00be: { n:"MulBlank", f:parse_MulBlank },
0x00c1: { n:'Mms', f:parse_Mms },
0x00c5: { n:"SXDI", f:parse_SXDI },
0x00c6: { n:"SXDB", f:parse_SXDB },
0x00c7: { n:"SXFDB", f:parse_SXFDB },
0x00c8: { n:"SXDBB", f:parse_SXDBB },
0x00c9: { n:"SXNum", f:parse_SXNum },
0x00ca: { n:"SxBool", f:parse_SxBool },
0x00cb: { n:"SxErr", f:parse_SxErr },
0x00cc: { n:"SXInt", f:parse_SXInt },
0x00cd: { n:"SXString", f:parse_SXString },
0x00ce: { n:"SXDtr", f:parse_SXDtr },
0x00cf: { n:"SxNil", f:parse_SxNil },
0x00d0: { n:"SXTbl", f:parse_SXTbl },
0x00d1: { n:"SXTBRGIITM", f:parse_SXTBRGIITM },
0x00d2: { n:"SxTbpg", f:parse_SxTbpg },
0x00d3: { n:"ObProj", f:parse_ObProj },
0x00d5: { n:"SXStreamID", f:parse_SXStreamID },
0x00d7: { n:"DBCell", f:parse_DBCell },
0x00d8: { n:"SXRng", f:parse_SXRng },
0x00d9: { n:"SxIsxoper", f:parse_SxIsxoper },
0x00da: { n:"BookBool", f:parse_BookBool },
0x00dc: { n:"DbOrParamQry", f:parse_DbOrParamQry },
0x00dd: { n:"ScenarioProtect", f:parse_ScenarioProtect },
0x00de: { n:"OleObjectSize", f:parse_OleObjectSize },
0x00e0: { n:"XF", f:parse_XF },
0x00e1: { n:'InterfaceHdr', f:parse_InterfaceHdr },
0x00e2: { n:'InterfaceEnd', f:parse_InterfaceEnd },
0x00e3: { n:"SXVS", f:parse_SXVS },
0x00e5: { n:"MergeCells", f:parse_MergeCells },
0x00e9: { n:"BkHim", f:parse_BkHim },
0x00eb: { n:"MsoDrawingGroup", f:parse_MsoDrawingGroup },
0x00ec: { n:"MsoDrawing", f:parse_MsoDrawing },
0x00ed: { n:"MsoDrawingSelection", f:parse_MsoDrawingSelection },
0x00ef: { n:"PhoneticInfo", f:parse_PhoneticInfo },
0x00f0: { n:"SxRule", f:parse_SxRule },
0x00f1: { n:"SXEx", f:parse_SXEx },
0x00f2: { n:"SxFilt", f:parse_SxFilt },
0x00f4: { n:"SxDXF", f:parse_SxDXF },
0x00f5: { n:"SxItm", f:parse_SxItm },
0x00f6: { n:"SxName", f:parse_SxName },
0x00f7: { n:"SxSelect", f:parse_SxSelect },
0x00f8: { n:"SXPair", f:parse_SXPair },
0x00f9: { n:"SxFmla", f:parse_SxFmla },
0x00fb: { n:"SxFormat", f:parse_SxFormat },
0x00fc: { n:"SST", f:parse_SST },
0x00fd: { n:"LabelSst", f:parse_LabelSst },
0x00ff: { n:"ExtSST", f:parse_ExtSST },
0x0100: { n:"SXVDEx", f:parse_SXVDEx },
0x0103: { n:"SXFormula", f:parse_SXFormula },
0x0122: { n:"SXDBEx", f:parse_SXDBEx },
0x0137: { n:"RRDInsDel", f:parse_RRDInsDel },
0x0138: { n:"RRDHead", f:parse_RRDHead },
0x013b: { n:"RRDChgCell", f:parse_RRDChgCell },
0x013d: { n:"RRTabId", f:parse_RRTabId },
0x013e: { n:"RRDRenSheet", f:parse_RRDRenSheet },
0x013f: { n:"RRSort", f:parse_RRSort },
0x0140: { n:"RRDMove", f:parse_RRDMove },
0x014a: { n:"RRFormat", f:parse_RRFormat },
0x014b: { n:"RRAutoFmt", f:parse_RRAutoFmt },
0x014d: { n:"RRInsertSh", f:parse_RRInsertSh },
0x014e: { n:"RRDMoveBegin", f:parse_RRDMoveBegin },
0x014f: { n:"RRDMoveEnd", f:parse_RRDMoveEnd },
0x0150: { n:"RRDInsDelBegin", f:parse_RRDInsDelBegin },
0x0151: { n:"RRDInsDelEnd", f:parse_RRDInsDelEnd },
0x0152: { n:"RRDConflict", f:parse_RRDConflict },
0x0153: { n:"RRDDefName", f:parse_RRDDefName },
0x0154: { n:"RRDRstEtxp", f:parse_RRDRstEtxp },
0x015f: { n:"LRng", f:parse_LRng },
0x0160: { n:"UsesELFs", f:parse_UsesELFs },
0x0161: { n:"DSF", f:parse_DSF },
0x0191: { n:"CUsr", f:parse_CUsr },
0x0192: { n:"CbUsr", f:parse_CbUsr },
0x0193: { n:"UsrInfo", f:parse_UsrInfo },
0x0194: { n:"UsrExcl", f:parse_UsrExcl },
0x0195: { n:"FileLock", f:parse_FileLock },
0x0196: { n:"RRDInfo", f:parse_RRDInfo },
0x0197: { n:"BCUsrs", f:parse_BCUsrs },
0x0198: { n:"UsrChk", f:parse_UsrChk },
0x01a9: { n:"UserBView", f:parse_UserBView },
0x01aa: { n:"UserSViewBegin", f:parse_UserSViewBegin },
0x01ab: { n:"UserSViewEnd", f:parse_UserSViewEnd },
0x01ac: { n:"RRDUserView", f:parse_RRDUserView },
0x01ad: { n:"Qsi", f:parse_Qsi },
0x01ae: { n:"SupBook", f:parse_SupBook },
0x01af: { n:"Prot4Rev", f:parse_Prot4Rev },
0x01b0: { n:"CondFmt", f:parse_CondFmt },
0x01b1: { n:"CF", f:parse_CF },
0x01b2: { n:"DVal", f:parse_DVal },
0x01b5: { n:"DConBin", f:parse_DConBin },
0x01b6: { n:"TxO", f:parse_TxO },
0x01b7: { n:"RefreshAll", f:parse_RefreshAll },
0x01b8: { n:"HLink", f:parse_HLink },
0x01b9: { n:"Lel", f:parse_Lel },
0x01ba: { n:"CodeName", f:parse_XLSCodeName },
0x01bb: { n:"SXFDBType", f:parse_SXFDBType },
0x01bc: { n:"Prot4RevPass", f:parse_Prot4RevPass },
0x01bd: { n:"ObNoMacros", f:parse_ObNoMacros },
0x01be: { n:"Dv", f:parse_Dv },
0x01c0: { n:"Excel9File", f:parse_Excel9File },
0x01c1: { n:"RecalcId", f:parse_RecalcId, r:2},
0x01c2: { n:"EntExU2", f:parse_EntExU2 },
0x0200: { n:"Dimensions", f:parse_Dimensions },
0x0201: { n:"Blank", f:parse_Blank },
0x0203: { n:"Number", f:parse_Number },
0x0204: { n:"Label", f:parse_Label },
0x0205: { n:"BoolErr", f:parse_BoolErr },
0x0207: { n:"String", f:parse_String },
0x0208: { n:'Row', f:parse_Row },
0x020b: { n:"Index", f:parse_Index },
0x0221: { n:"Array", f:parse_Array },
0x0225: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
0x0236: { n:"Table", f:parse_Table },
0x023e: { n:"Window2", f:parse_Window2 },
0x027e: { n:"RK", f:parse_RK },
0x0293: { n:"Style", f:parse_Style },
0x0418: { n:"BigName", f:parse_BigName },
0x041e: { n:"Format", f:parse_Format },
0x043c: { n:"ContinueBigName", f:parse_ContinueBigName },
0x04bc: { n:"ShrFmla", f:parse_ShrFmla },
0x0800: { n:"HLinkTooltip", f:parse_HLinkTooltip },
0x0801: { n:"WebPub", f:parse_WebPub },
0x0802: { n:"QsiSXTag", f:parse_QsiSXTag },
0x0803: { n:"DBQueryExt", f:parse_DBQueryExt },
0x0804: { n:"ExtString", f:parse_ExtString },
0x0805: { n:"TxtQry", f:parse_TxtQry },
0x0806: { n:"Qsir", f:parse_Qsir },
0x0807: { n:"Qsif", f:parse_Qsif },
0x0808: { n:"RRDTQSIF", f:parse_RRDTQSIF },
0x0809: { n:'BOF', f:parse_BOF },
0x080a: { n:"OleDbConn", f:parse_OleDbConn },
0x080b: { n:"WOpt", f:parse_WOpt },
0x080c: { n:"SXViewEx", f:parse_SXViewEx },
0x080d: { n:"SXTH", f:parse_SXTH },
0x080e: { n:"SXPIEx", f:parse_SXPIEx },
0x080f: { n:"SXVDTEx", f:parse_SXVDTEx },
0x0810: { n:"SXViewEx9", f:parse_SXViewEx9 },
0x0812: { n:"ContinueFrt", f:parse_ContinueFrt },
0x0813: { n:"RealTimeData", f:parse_RealTimeData },
0x0850: { n:"ChartFrtInfo", f:parse_ChartFrtInfo },
0x0851: { n:"FrtWrapper", f:parse_FrtWrapper },
0x0852: { n:"StartBlock", f:parse_StartBlock },
0x0853: { n:"EndBlock", f:parse_EndBlock },
0x0854: { n:"StartObject", f:parse_StartObject },
0x0855: { n:"EndObject", f:parse_EndObject },
0x0856: { n:"CatLab", f:parse_CatLab },
0x0857: { n:"YMult", f:parse_YMult },
0x0858: { n:"SXViewLink", f:parse_SXViewLink },
0x0859: { n:"PivotChartBits", f:parse_PivotChartBits },
0x085a: { n:"FrtFontList", f:parse_FrtFontList },
0x0862: { n:"SheetExt", f:parse_SheetExt },
0x0863: { n:"BookExt", f:parse_BookExt, r:12},
0x0864: { n:"SXAddl", f:parse_SXAddl },
0x0865: { n:"CrErr", f:parse_CrErr },
0x0866: { n:"HFPicture", f:parse_HFPicture },
0x0867: { n:'FeatHdr', f:parse_FeatHdr },
0x0868: { n:"Feat", f:parse_Feat },
0x086a: { n:"DataLabExt", f:parse_DataLabExt },
0x086b: { n:"DataLabExtContents", f:parse_DataLabExtContents },
0x086c: { n:"CellWatch", f:parse_CellWatch },
0x0871: { n:"FeatHdr11", f:parse_FeatHdr11 },
0x0872: { n:"Feature11", f:parse_Feature11 },
0x0874: { n:"DropDownObjIds", f:parse_DropDownObjIds },
0x0875: { n:"ContinueFrt11", f:parse_ContinueFrt11 },
0x0876: { n:"DConn", f:parse_DConn },
0x0877: { n:"List12", f:parse_List12 },
0x0878: { n:"Feature12", f:parse_Feature12 },
0x0879: { n:"CondFmt12", f:parse_CondFmt12 },
0x087a: { n:"CF12", f:parse_CF12 },
0x087b: { n:"CFEx", f:parse_CFEx },
0x087c: { n:"XFCRC", f:parse_XFCRC, r:12 },
0x087d: { n:"XFExt", f:parse_XFExt, r:12 },
0x087e: { n:"AutoFilter12", f:parse_AutoFilter12 },
0x087f: { n:"ContinueFrt12", f:parse_ContinueFrt12 },
0x0884: { n:"MDTInfo", f:parse_MDTInfo },
0x0885: { n:"MDXStr", f:parse_MDXStr },
0x0886: { n:"MDXTuple", f:parse_MDXTuple },
0x0887: { n:"MDXSet", f:parse_MDXSet },
0x0888: { n:"MDXProp", f:parse_MDXProp },
0x0889: { n:"MDXKPI", f:parse_MDXKPI },
0x088a: { n:"MDB", f:parse_MDB },
0x088b: { n:"PLV", f:parse_PLV },
0x088c: { n:"Compat12", f:parse_Compat12, r:12 },
0x088d: { n:"DXF", f:parse_DXF },
0x088e: { n:"TableStyles", f:parse_TableStyles, r:12 },
0x088f: { n:"TableStyle", f:parse_TableStyle },
0x0890: { n:"TableStyleElement", f:parse_TableStyleElement },
0x0892: { n:"StyleExt", f:parse_StyleExt },
0x0893: { n:"NamePublish", f:parse_NamePublish },
0x0894: { n:"NameCmt", f:parse_NameCmt },
0x0895: { n:"SortData", f:parse_SortData },
0x0896: { n:"Theme", f:parse_Theme, r:12 },
0x0897: { n:"GUIDTypeLib", f:parse_GUIDTypeLib },
0x0898: { n:"FnGrp12", f:parse_FnGrp12 },
0x0899: { n:"NameFnGrp12", f:parse_NameFnGrp12 },
0x089a: { n:"MTRSettings", f:parse_MTRSettings, r:12 },
0x089b: { n:"CompressPictures", f:parse_CompressPictures },
0x089c: { n:"HeaderFooter", f:parse_HeaderFooter },
0x089d: { n:"CrtLayout12", f:parse_CrtLayout12 },
0x089e: { n:"CrtMlFrt", f:parse_CrtMlFrt },
0x089f: { n:"CrtMlFrtContinue", f:parse_CrtMlFrtContinue },
0x08a3: { n:"ForceFullCalculation", f:parse_ForceFullCalculation },
0x08a4: { n:"ShapePropsStream", f:parse_ShapePropsStream },
0x08a5: { n:"TextPropsStream", f:parse_TextPropsStream },
0x08a6: { n:"RichTextStream", f:parse_RichTextStream },
0x08a7: { n:"CrtLayout12A", f:parse_CrtLayout12A },
0x1001: { n:"Units", f:parse_Units },
0x1002: { n:"Chart", f:parse_Chart },
0x1003: { n:"Series", f:parse_Series },
0x1006: { n:"DataFormat", f:parse_DataFormat },
0x1007: { n:"LineFormat", f:parse_LineFormat },
0x1009: { n:"MarkerFormat", f:parse_MarkerFormat },
0x100a: { n:"AreaFormat", f:parse_AreaFormat },
0x100b: { n:"PieFormat", f:parse_PieFormat },
0x100c: { n:"AttachedLabel", f:parse_AttachedLabel },
0x100d: { n:"SeriesText", f:parse_SeriesText },
0x1014: { n:"ChartFormat", f:parse_ChartFormat },
0x1015: { n:"Legend", f:parse_Legend },
0x1016: { n:"SeriesList", f:parse_SeriesList },
0x1017: { n:"Bar", f:parse_Bar },
0x1018: { n:"Line", f:parse_Line },
0x1019: { n:"Pie", f:parse_Pie },
0x101a: { n:"Area", f:parse_Area },
0x101b: { n:"Scatter", f:parse_Scatter },
0x101c: { n:"CrtLine", f:parse_CrtLine },
0x101d: { n:"Axis", f:parse_Axis },
0x101e: { n:"Tick", f:parse_Tick },
0x101f: { n:"ValueRange", f:parse_ValueRange },
0x1020: { n:"CatSerRange", f:parse_CatSerRange },
0x1021: { n:"AxisLine", f:parse_AxisLine },
0x1022: { n:"CrtLink", f:parse_CrtLink },
0x1024: { n:"DefaultText", f:parse_DefaultText },
0x1025: { n:"Text", f:parse_Text },
0x1026: { n:"FontX", f:parse_FontX },
0x1027: { n:"ObjectLink", f:parse_ObjectLink },
0x1032: { n:"Frame", f:parse_Frame },
0x1033: { n:"Begin", f:parse_Begin },
0x1034: { n:"End", f:parse_End },
0x1035: { n:"PlotArea", f:parse_PlotArea },
0x103a: { n:"Chart3d", f:parse_Chart3d },
0x103c: { n:"PicF", f:parse_PicF },
0x103d: { n:"DropBar", f:parse_DropBar },
0x103e: { n:"Radar", f:parse_Radar },
0x103f: { n:"Surf", f:parse_Surf },
0x1040: { n:"RadarArea", f:parse_RadarArea },
0x1041: { n:"AxisParent", f:parse_AxisParent },
0x1043: { n:"LegendException", f:parse_LegendException },
0x1044: { n:"ShtProps", f:parse_ShtProps },
0x1045: { n:"SerToCrt", f:parse_SerToCrt },
0x1046: { n:"AxesUsed", f:parse_AxesUsed },
0x1048: { n:"SBaseRef", f:parse_SBaseRef },
0x104a: { n:"SerParent", f:parse_SerParent },
0x104b: { n:"SerAuxTrend", f:parse_SerAuxTrend },
0x104e: { n:"IFmtRecord", f:parse_IFmtRecord },
0x104f: { n:"Pos", f:parse_Pos },
0x1050: { n:"AlRuns", f:parse_AlRuns },
0x1051: { n:"BRAI", f:parse_BRAI },
0x105b: { n:"SerAuxErrBar", f:parse_SerAuxErrBar },
0x105c: { n:"ClrtClient", f:parse_ClrtClient },
0x105d: { n:"SerFmt", f:parse_SerFmt },
0x105f: { n:"Chart3DBarShape", f:parse_Chart3DBarShape },
0x1060: { n:"Fbi", f:parse_Fbi },
0x1061: { n:"BopPop", f:parse_BopPop },
0x1062: { n:"AxcExt", f:parse_AxcExt },
0x1063: { n:"Dat", f:parse_Dat },
0x1064: { n:"PlotGrowth", f:parse_PlotGrowth },
0x1065: { n:"SIIndex", f:parse_SIIndex },
0x1066: { n:"GelFrame", f:parse_GelFrame },
0x1067: { n:"BopPopCustom", f:parse_BopPopCustom },
0x1068: { n:"Fbi2", f:parse_Fbi2 },
/* These are specified in an older version of the spec */
0x0016: { n:"ExternCount", f:parsenoop },
0x007e: { n:"RK", f:parsenoop }, /* Not necessarily same as 0x027e */
0x007f: { n:"ImData", f:parsenoop },
0x0087: { n:"Addin", f:parsenoop },
0x0088: { n:"Edg", f:parsenoop },
0x0089: { n:"Pub", f:parsenoop },
0x0091: { n:"Sub", f:parsenoop },
0x0094: { n:"LHRecord", f:parsenoop },
0x0095: { n:"LHNGraph", f:parsenoop },
0x0096: { n:"Sound", f:parsenoop },
0x00a9: { n:"CoordList", f:parsenoop },
0x00ab: { n:"GCW", f:parsenoop },
0x00bc: { n:"ShrFmla", f:parsenoop }, /* Not necessarily same as 0x04bc */
0x00c2: { n:"AddMenu", f:parsenoop },
0x00c3: { n:"DelMenu", f:parsenoop },
0x00d6: { n:"RString", f:parsenoop },
0x00df: { n:"UDDesc", f:parsenoop },
0x00ea: { n:"TabIdConf", f:parsenoop },
0x0162: { n:"XL5Modify", f:parsenoop },
0x01a5: { n:"FileSharing2", f:parsenoop },
0x0218: { n:"Name", f:parsenoop },
0x0223: { n:"ExternName", f:parse_ExternName },
0x0231: { n:"Font", f:parsenoop },
0x0406: { n:"Formula", f:parse_Formula },
0x086d: { n:"FeatInfo", f:parsenoop },
0x0873: { n:"FeatInfo11", f:parsenoop },
0x0881: { n:"SXAddl12", f:parsenoop },
0x08c0: { n:"AutoWebPub", f:parsenoop },
0x08c1: { n:"ListObj", f:parsenoop },
0x08c2: { n:"ListField", f:parsenoop },
0x08c3: { n:"ListDV", f:parsenoop },
0x08c4: { n:"ListCondFmt", f:parsenoop },
0x08c5: { n:"ListCF", f:parsenoop },
0x08c6: { n:"FMQry", f:parsenoop },
0x08c7: { n:"FMSQry", f:parsenoop },
0x08c8: { n:"PLV", f:parsenoop }, /* supposedly PLV for Excel 11 */
0x08c9: { n:"LnExt", f:parsenoop },
0x08ca: { n:"MkrExt", f:parsenoop },
0x08cb: { n:"CrtCoopt", f:parsenoop },
0x0000: {}
};

@ -21,9 +21,10 @@ var fix_read_opts = fix_opts_func([
['bookDeps', false], /* parse calculation chains */
['bookSheets', false], /* only try to get sheet names (no Sheets) */
['bookProps', false], /* only try to get properties (no Sheets) */
['bookFiles', false], /* include raw file structure (keys, files) */
['bookFiles', false], /* include raw file structure (keys, files, cfb) */
['bookVBA', false], /* include vba raw data (vbaraw) */
['password',''], /* password */
['WTF', false] /* WTF mode (throws errors) */
]);

@ -1,10 +1,20 @@
function readSync(data, opts) {
function firstbyte(f,o) {
switch((o||{}).type || "base64") {
case 'buffer': return f[0];
case 'base64': return Base64.decode(f.substr(0,12)).charCodeAt(0);
case 'binary': return f.charCodeAt(0);
case 'array': return f[0];
default: throw new Error("Unrecognized type " + o.type);
}
}
function read_zip(data, opts) {
var zip, d = data;
var o = opts||{};
if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
switch(o.type) {
case "base64": zip = new jszip(d, { base64:true }); break;
case "binary": zip = new jszip(d, { base64:false }); break;
case "binary": case "array": zip = new jszip(d, { base64:false }); break;
case "buffer": zip = new jszip(d); break;
case "file": zip=new jszip(d=_fs.readFileSync(data)); break;
default: throw new Error("Unrecognized type " + o.type);
@ -12,10 +22,27 @@ function readSync(data, opts) {
return parse_zip(zip, o);
}
function readSync(data, opts) {
var zip, d = data, isfile = false, n;
var o = opts||{};
if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
if(o.type == "file") { isfile = true; o.type = "buffer"; d = _fs.readFileSync(data); }
switch((n = firstbyte(d, o))) {
case 0xD0:
if(isfile) o.type = "file";
return parse_xlscfb(CFB.read(data, o), o);
case 0x09: return parse_xlscfb(s2a(o.type === 'base64' ? Base64.decode(data) : data), o);
case 0x3C: return parse_xlml(d, o);
case 0x50:
if(isfile) o.type = "file";
return read_zip(data, opts);
default: throw new Error("Unsupported file " + n);
}
}
function readFileSync(data, opts) {
var o = opts||{}; o.type = 'file'
var wb = readSync(data, o);
wb.FILENAME = data;
return wb;
}

@ -1,4 +1,4 @@
function writeSync(wb, opts) {
function write_zip_type(wb, opts) {
var o = opts||{};
style_builder = new StyleBuilder(opts);
@ -12,14 +12,26 @@ function writeSync(wb, opts) {
}
}
function writeSync(wb, opts) {
var o = opts||{};
switch(o.bookType) {
case 'xml': return write_xlml(wb, o);
default: return write_zip_type(wb, o);
}
}
function writeFileSync(wb, filename, opts) {
var o = opts||{}; o.type = 'file';
o.file = filename;
switch(o.file.substr(-5).toLowerCase()) {
case '.xlsx': o.bookType = 'xlsx'; break;
case '.xlsm': o.bookType = 'xlsm'; break;
case '.xlsb': o.bookType = 'xlsb'; break;
}
default: switch(o.file.substr(-4).toLowerCase()) {
case '.xls': o.bookType = 'xls'; break;
case '.xml': o.bookType = 'xml'; break;
}}
return writeSync(wb, o);
}

@ -100,7 +100,12 @@ function sheet_to_json(sheet, opts){
for (R = r.s.r + offset; R <= r.e.r; ++R) {
rr = encode_row(R);
isempty = true;
row = header === 1 ? [] : Object.create({ __rowNum__ : R });
if(header === 1) row = [];
else {
row = {};
if(Object.defineProperty) Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false});
else row.__rowNum__ = R;
}
for (C = r.s.c; C <= r.e.c; ++C) {
val = sheet[cols[C] + rr];
if(val === undefined || val.t === undefined) continue;
@ -116,7 +121,7 @@ function sheet_to_json(sheet, opts){
isempty = false;
}
}
if(isempty === false) out[outi++] = row;
if(isempty === false || header === 1) out[outi++] = row;
}
out.length = outi;
return out;

@ -192,7 +192,7 @@ if ((typeof 'module' != 'undefined' && typeof require != 'undefined') || (typeo
if (attributes.alignment.vertical) { $alignment.attr('vertical', attributes.alignment.vertical);}
if (attributes.alignment.indent) { $alignment.attr('indent', attributes.alignment.indent);}
if (attributes.alignment.wrapText) { $alignment.attr('wrapText', attributes.alignment.wrapText);}
if (attributes.alignment.textRotation) { $alignment.attr('textRotation', attributes.alignment.textRotation);}
if (attributes.alignment.textRotation!=undefined) { $alignment.attr('textRotation', attributes.alignment.textRotation);}
$xf.append($alignment).attr('applyAlignment',1)

@ -1,7 +1,11 @@
XLSX.parseZip = parse_zip;
XLSX.read = readSync;
XLSX.readFile = readFileSync;
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_zip = parse_zip;
XLSX.read = readSync; //xlsread
XLSX.readFile = readFileSync; //readFile
XLSX.readFileSync = readFileSync;
XLSX.write = writeSync;
XLSX.writeFile = writeFileSync;
XLSX.writeFileSync = writeFileSync;
XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;

@ -1 +1,2 @@
})(typeof exports !== 'undefined' ? exports : XLSX);
var XLS = XLSX;

@ -2,7 +2,7 @@
"name": "js-xlsx",
"homepage": "https://github.com/SheetJS/js-xlsx",
"main": "dist/xlsx.js",
"version": "0.7.12",
"version": "0.8.0",
"ignore": [
"bin",
"bits",
@ -11,10 +11,13 @@
],
"keywords": [
"excel",
"xls",
"xml",
"xlsx",
"xlsm",
"xlsb",
"ods",
"js-xls",
"js-xlsx"
]
}

2
dist/LICENSE vendored

@ -1,4 +1,4 @@
Copyright (C) 2012-2014 SheetJS
Copyright (C) 2012-2015 SheetJS
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.

6
dist/ods.js vendored

@ -15,6 +15,12 @@ var get_utils = function() {
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}
function getdata(data) {
if(!data) return null;
if(data.data) return data.data;

17
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

18
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

6779
dist/xlsx.js vendored

File diff suppressed because one or more lines are too long

16
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

@ -1,5 +1,5 @@
<!DOCTYPE html>
<!-- xlsx.js (C) 2013-2014 SheetJS http://sheetjs.com -->
<!-- xlsx.js (C) 2013-2015 SheetJS http://sheetjs.com -->
<!-- vim: set ts=2: -->
<html>
<head>
@ -21,7 +21,7 @@
</style>
</head>
<body>
<b>JS-XLSX (XLSX/XLSB/XLSM) Live Demo</b><br />
<b>JS-XLSX (XLSX/XLSB/XLSM/XLS/XML) Live Demo</b><br />
Output Format:
<select name="format">
<option value="csv" selected> CSV</option>
@ -32,7 +32,7 @@ Output Format:
<input type="radio" name="format" value="json"> JSON<br>
<input type="radio" name="format" value="form"> FORMULAE<br> -->
<div id="drop">Drop an XLSX / XLSM / XLSB / ODS file here to see sheet data</div>
<div id="drop">Drop an XLSX / XLSM / XLSB / ODS / XLS / XML file here to see sheet data</div>
<p><input type="file" name="xlfile" id="xlf" /> ... or click here to select a file</p>
<textarea id="b64data">... or paste a base64-encoding here</textarea>
<input type="button" id="dotext" value="Click here to process the base64 text" onclick="b64it();"/><br />
@ -50,6 +50,16 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<!-- uncomment the next line here and in xlsxworker.js for ODS support -->
<script src="dist/ods.js"></script>
<script>
var X = XLSX;
var XW = {
/* worker message */
msg: 'xlsx',
/* worker scripts */
rABS: './xlsxworker2.js',
norABS: './xlsxworker1.js',
noxfer: './xlsxworker.js'
};
var rABS = typeof FileReader !== "undefined" && typeof FileReader.prototype !== "undefined" && typeof FileReader.prototype.readAsBinaryString !== "undefined";
if(!rABS) {
document.getElementsByName("userabs")[0].disabled = true;
@ -90,21 +100,21 @@ function s2ab(s) {
return [v, b];
}
function xlsxworker_noxfer(data, cb) {
var worker = new Worker('./xlsxworker.js');
function xw_noxfer(data, cb) {
var worker = new Worker(XW.noxfer);
worker.onmessage = function(e) {
switch(e.data.t) {
case 'ready': break;
case 'e': console.error(e.data.d); break;
case 'xlsx': cb(JSON.parse(e.data.d)); break;
case XW.msg: cb(JSON.parse(e.data.d)); break;
}
};
var arr = rABS ? data : btoa(fixdata(data));
worker.postMessage({d:arr,b:rABS});
}
function xlsxworker_xfer(data, cb) {
var worker = new Worker(rABS ? './xlsxworker2.js' : './xlsxworker1.js');
function xw_xfer(data, cb) {
var worker = new Worker(rABS ? XW.rABS : XW.norABS);
worker.onmessage = function(e) {
switch(e.data.t) {
case 'ready': break;
@ -120,10 +130,10 @@ function xlsxworker_xfer(data, cb) {
}
}
function xlsxworker(data, cb) {
function xw(data, cb) {
transferable = document.getElementsByName("xferable")[0].checked;
if(transferable) xlsxworker_xfer(data, cb);
else xlsxworker_noxfer(data, cb);
if(transferable) xw_xfer(data, cb);
else xw_noxfer(data, cb);
}
function get_radio_value( radioName ) {
@ -138,7 +148,7 @@ function get_radio_value( radioName ) {
function to_json(workbook) {
var result = {};
workbook.SheetNames.forEach(function(sheetName) {
var roa = XLSX.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
var roa = X.utils.sheet_to_row_object_array(workbook.Sheets[sheetName]);
if(roa.length > 0){
result[sheetName] = roa;
}
@ -149,7 +159,7 @@ function to_json(workbook) {
function to_csv(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var csv = XLSX.utils.sheet_to_csv(workbook.Sheets[sheetName]);
var csv = X.utils.sheet_to_csv(workbook.Sheets[sheetName]);
if(csv.length > 0){
result.push("SHEET: " + sheetName);
result.push("");
@ -162,7 +172,7 @@ function to_csv(workbook) {
function to_formulae(workbook) {
var result = [];
workbook.SheetNames.forEach(function(sheetName) {
var formulae = XLSX.utils.get_formulae(workbook.Sheets[sheetName]);
var formulae = X.utils.get_formulae(workbook.Sheets[sheetName]);
if(formulae.length > 0){
result.push("SHEET: " + sheetName);
result.push("");
@ -175,7 +185,7 @@ function to_formulae(workbook) {
var tarea = document.getElementById('b64data');
function b64it() {
if(typeof console !== 'undefined') console.log("onload", new Date());
var wb = XLSX.read(tarea.value, {type: 'base64',WTF:wtf_mode});
var wb = X.read(tarea.value, {type: 'base64',WTF:wtf_mode});
process_wb(wb);
}
@ -203,22 +213,22 @@ function handleDrop(e) {
rABS = document.getElementsByName("userabs")[0].checked;
use_worker = document.getElementsByName("useworker")[0].checked;
var files = e.dataTransfer.files;
var i,f;
for (i = 0, f = files[i]; i != files.length; ++i) {
var f = files[0];
{
var reader = new FileReader();
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;
if(use_worker) {
xlsxworker(data, process_wb);
xw(data, process_wb);
} else {
var wb;
if(rABS) {
wb = XLSX.read(data, {type: 'binary'});
wb = X.read(data, {type: 'binary'});
} else {
var arr = fixdata(data);
wb = XLSX.read(btoa(arr), {type: 'base64'});
wb = X.read(btoa(arr), {type: 'base64'});
}
process_wb(wb);
}
@ -246,22 +256,22 @@ function handleFile(e) {
rABS = document.getElementsByName("userabs")[0].checked;
use_worker = document.getElementsByName("useworker")[0].checked;
var files = e.target.files;
var i,f;
for (i = 0, f = files[i]; i != files.length; ++i) {
var f = files[0];
{
var reader = new FileReader();
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;
if(use_worker) {
xlsxworker(data, process_wb);
xw(data, process_wb);
} else {
var wb;
if(rABS) {
wb = XLSX.read(data, {type: 'binary'});
wb = X.read(data, {type: 'binary'});
} else {
var arr = fixdata(data);
wb = XLSX.read(btoa(arr), {type: 'base64'});
wb = X.read(btoa(arr), {type: 'base64'});
}
process_wb(wb);
}
@ -273,6 +283,5 @@ function handleFile(e) {
if(xlf.addEventListener) xlf.addEventListener('change', handleFile, false);
</script>
</script>
</body>
</html>

@ -11,10 +11,13 @@
],
"keywords": [
"excel",
"xls",
"xml",
"xlsx",
"xlsm",
"xlsb",
"ods",
"js-xls",
"js-xlsx"
]
}

104
misc/cfb.d.ts vendored Normal file

@ -0,0 +1,104 @@
declare enum CFBEntryType { unknown, storage, stream, lockbytes, property, root }
declare enum CFBStorageType { fat, minifat }
/* CFB Entry Object demanded by write functions */
interface CFBEntryMin {
/* Raw Content (Buffer when available, Array of bytes otherwise) */
content:any;
}
/* CFB Entry Object returned by parse functions */
interface CFBEntry extends CFBEntryMin {
/* Case-sensitive internal name */
name:string;
/* CFB type (salient types: stream, storage) -- see CFBEntryType */
type:string;
/* Creation Time */
ct:Date;
/* Modification Time */
mt:Date;
/* Raw creation time -- see [MS-DTYP] 2.3.3 FILETIME */
mtime:string;
/* Raw modification time -- see [MS-DTYP] 2.3.3 FILETIME */
ctime:string;
/* RBT color: 0 = red, 1 = black */
color:number;
/* Class ID represented as hex string */
clsid:string;
/* User-Defined State Bits */
state:number;
/* Starting Sector */
start:number;
/* Data Size */
size:number;
/* Storage location -- see CFBStorageType */
storage:string;
}
/* cfb.FullPathDir as demanded by write functions */
interface CFBDirectoryMin {
/* keys are unix-style paths */
[key:string]: CFBEntryMin;
}
/* cfb.FullPathDir Directory object */
interface CFBDirectory extends CFBDirectoryMin {
/* cfb.FullPathDir keys are paths; cfb.Directory keys are file names */
[key:string]: CFBEntry;
}
/* cfb object demanded by write functions */
interface CFBContainerMin {
/* Path -> CFB object mapping */
FullPathDir:CFBDirectoryMin;
}
/* cfb object returned by read and parse functions */
interface CFBContainer extends CFBContainerMin {
/* search by path or file name */
find(string):CFBEntry;
/* list of streams and storages */
FullPaths:string[];
/* Path -> CFB object mapping */
FullPathDir:CFBDirectory;
/* Array of entries in the same order as FullPaths */
FileIndex:CFBEntry[];
/* Raw Content, in chunks (Buffer when available, Array of bytes otherwise) */
raw:any[];
}
interface CFB {
read(f:any, options:any):CFBContainer;
parse(f:any):CFBContainer;
utils: {
ReadShift(size:any,t?:any):any;
WarnField(hexstr:string,fld?:string);
CheckField(hexstr:string,fld?:string);
prep_blob(blob:any, pos?:number):any;
bconcat(bufs:any[]):any;
};
main;
}

11
misc/strip_sourcemap.sh Executable file

@ -0,0 +1,11 @@
#!/bin/bash
# strip_sourcemap.sh -- strip sourcemaps from a JS file (missing from uglifyjs)
# Copyright (C) 2014-2015 SheetJS
if [ $# -gt 0 ]; then
if [ -e "$1" ]; then
sed -i .sheetjs '/sourceMappingURL/d' "$1"
fi
else
cat - | sed '/sourceMappingURL/d'
fi

37
misc/xl.d.ts vendored

@ -1,3 +1,5 @@
///<reference path='cfb.d.ts'/>
interface Cell {
v;
w?: string;
@ -7,9 +9,25 @@ interface Cell {
h?: string;
c?: any;
z?: string;
ixfe?: number;
}
interface Worksheet {
interface CellAddress {
c: number;
r: number;
}
interface CellRange {
s: CellAddress;
e: CellAddress;
}
interface WorksheetBase {
'!range':CellRange;
'!ref':string;
}
interface Worksheet extends WorksheetBase {
[key: string]: Cell;
}
@ -23,10 +41,25 @@ interface Workbook {
}
interface XLSX {
verbose: Number;
parse_xlscfb(cfb:CFBContainer): Workbook;
read;
readFile(filename: string): Workbook;
utils: {
encode_col(col: number): string;
encode_row(row: number): string;
encode_cell(cell: CellAddress): string;
encode_range;
decode_col(col: string): number;
decode_row(row: string): number;
split_cell(cell: string): string[];
decode_cell(cell: string): CellAddress;
decode_range(cell: string): CellRange;
sheet_to_csv(worksheet: Worksheet): string;
get_formulae(worksheet: Worksheet): string[];
make_csv(worksheet: Worksheet): string;
sheet_to_row_object_array(worksheet: Worksheet): Object[];
};
verbose: Number;
CFB:CFB;
main;
}

6
ods.js

@ -15,6 +15,12 @@ var get_utils = function() {
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}
function getdata(data) {
if(!data) return null;
if(data.data) return data.data;

@ -1 +1,7 @@
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}

@ -1,9 +1,9 @@
{
"name": "xlsx",
"version": "0.7.12",
"version": "0.8.0",
"author": "sheetjs",
"description": "Excel 2007+ spreadsheet (XLSB/XLSX/XLSM) and ODS parser and writer",
"keywords": [ "excel", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS spreadsheet parser and writer",
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
"bin": {
"xlsx": "./bin/xlsx.njs"
},
@ -20,14 +20,12 @@
"devDependencies": {
"mocha":"",
"xlsjs":"",
"uglify-js":"",
"jasmine-node": "x"
"uglify-js":""
},
"repository": { "type":"git", "url":"git://github.com/SheetJS/js-xlsx.git" },
"scripts": {
"pretest": "git submodule init && git submodule update",
"test": "make test",
"test-jasmine": "jasmine-node --verbose tests/"
"test": "make test"
},
"config": {
"blanket": {

@ -12,6 +12,8 @@ function JSDateToExcelDate(inDate) {
var defaultCellStyle = { font: { name: "Verdana", sz: 11, color: "FF00FF88"}, fill: {fgColor: {rgb: "FFFFAA00"}}};
// test to see if everything on the left equals its counterpart on the right
// but the right hand object may have other attributes which we might not care about
function basicallyEquals(left, right) {
if (Array.isArray(left) && Array.isArray(right)) {
for (var i=0; i<left.length; i++) {
@ -23,8 +25,10 @@ function basicallyEquals(left, right) {
}
else if (typeof left == 'object' && typeof right == 'object') {
for (var key in left) {
if (key != 'border' && key!='alignment' && key != 'bgColor') {
if (key != 'bgColor') {
if (!basicallyEquals(left[key], right[key] )) {
if (JSON.stringify(left[key])=="{}" && right[key] == undefined) return true;
if (JSON.stringify(right[key])=="{}" && left[key] == undefined) return true;
return false;
}
}
@ -419,7 +423,7 @@ describe("Export styles", function () {
"s": {
"alignment": {
"wrapText": 1,
"alignment": "right",
"horizontal": "right",
"vertical": "center",
"indent": 1
}

525
test.js

@ -1,4 +1,6 @@
/* vim: set ts=2: */
/*jshint loopfunc:true, eqnull:true */
var X;
var X; var XLSX = require('./')
var modp = './';
//var modp = 'xlsx';
@ -11,7 +13,7 @@ if(process.env.WTF) {
opts.cellStyles = true;
}
var fullex = [".xlsb", ".xlsm", ".xlsx"];
var ex = fullex.slice(); ex.push(".ods");
var ex = fullex.slice(); ex.push(".ods"); ex.push(".xls"); ex.push("xml");
if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
var exp = ex.map(function(x){ return x + ".pending"; });
@ -30,40 +32,56 @@ function fixjson(x) { return x.replace(/[\r\n]+$/,""); }
var dir = "./test_files/";
var paths = {
cp1: dir + 'custom_properties.xlsx',
cp2: dir + 'custom_properties.xlsb',
css1: dir + 'cell_style_simple.xlsx',
css2: dir + 'cell_style_simple.xlsb',
cst1: dir + 'comments_stress_test.xlsx',
cst2: dir + 'comments_stress_test.xlsb',
fst1: dir + 'formula_stress_test.xlsx',
fst2: dir + 'formula_stress_test.xlsb',
fst3: dir + 'formula_stress_test.ods',
fstb: dir + 'formula_stress_test.xlsb',
hl1: dir + 'hyperlink_stress_test_2011.xlsx',
hl2: dir + 'hyperlink_stress_test_2011.xlsb',
lon1: dir + 'LONumbers.xlsx',
mc1: dir + 'merge_cells.xlsx',
mc2: dir + 'merge_cells.xlsb',
mc3: dir + 'merge_cells.ods',
nf1: dir + 'number_format.xlsm',
nf2: dir + 'number_format.xlsb',
dt1: dir + 'xlsx-stream-d-date-cell.xlsx',
dt2: dir + 'xlsx-stream-d-date-cell.xlsb',
swc1: dir + 'apachepoi_SimpleWithComments.xlsx',
swc2: dir + '2013/apachepoi_SimpleWithComments.xlsx.xlsb'
cpxls: dir + 'custom_properties.xls',
cpxml: dir + 'custom_properties.xls.xml',
cpxlsx: dir + 'custom_properties.xlsx',
cpxlsb: dir + 'custom_properties.xlsb',
cssxls: dir + 'cell_style_simple.xls',
cssxml: dir + 'cell_style_simple.xml',
cssxlsx: dir + 'cell_style_simple.xlsx',
cssxlsb: dir + 'cell_style_simple.xlsb',
cstxls: dir + 'comments_stress_test.xls',
cstxml: dir + 'comments_stress_test.xls.xml',
cstxlsx: dir + 'comments_stress_test.xlsx',
cstxlsb: dir + 'comments_stress_test.xlsb',
fstxls: dir + 'formula_stress_test.xls',
fstxml: dir + 'formula_stress_test.xls.xml',
fstxlsx: dir + 'formula_stress_test.xlsx',
fstxlsb: dir + 'formula_stress_test.xlsb',
fstods: dir + 'formula_stress_test.ods',
hlxls: dir + 'hyperlink_stress_test_2011.xls',
hlxml: dir + 'hyperlink_stress_test_2011.xml',
hlxlsx: dir + 'hyperlink_stress_test_2011.xlsx',
hlxlsb: dir + 'hyperlink_stress_test_2011.xlsb',
lonxls: dir + 'LONumbers.xls',
lonxlsx: dir + 'LONumbers.xlsx',
mcxls: dir + 'merge_cells.xls',
mcxml: dir + 'merge_cells.xls.xml',
mcxlsx: dir + 'merge_cells.xlsx',
mcxlsb: dir + 'merge_cells.xlsb',
mcods: dir + 'merge_cells.ods',
nfxls: dir + 'number_format.xls',
nfxml: dir + 'number_format.xls.xml',
nfxlsx: dir + 'number_format.xlsm',
nfxlsb: dir + 'number_format.xlsb',
dtxlsx: dir + 'xlsx-stream-d-date-cell.xlsx',
dtxlsb: dir + 'xlsx-stream-d-date-cell.xlsb',
swcxls: dir + 'apachepoi_SimpleWithComments.xls',
swcxml: dir + '2011/apachepoi_SimpleWithComments.xls.xml',
swcxlsx: dir + 'apachepoi_SimpleWithComments.xlsx',
swcxlsb: dir + '2013/apachepoi_SimpleWithComments.xlsx.xlsb'
};
var N1 = 'XLSX';
var N2 = 'XLSB';
var N3 = 'XLS';
var N4 = 'XML';
function parsetest(x, wb, full, ext) {
ext = (ext ? " [" + ext + "]": "");
if(!full && ext) return;
describe(x + ext + ' should have all bits', function() {
var sname = dir + '2011/' + x + '.sheetnames';
var sname = dir + '2011/' + x.substr(x.lastIndexOf('/')+1) + '.sheetnames';
it('should have all sheets', function() {
wb.SheetNames.forEach(function(y) { assert(wb.Sheets[y], 'bad sheet ' + y); });
});
@ -103,6 +121,12 @@ function parsetest(x, wb, full, ext) {
if(!fs.existsSync(name)) name=(dir + root + '.xlsm.' + i + type);
if(!fs.existsSync(name)) name=(dir + root + '.xls.' + i + type);
}
if(x.substr(-4) === ".xls") {
root = x.slice(0,-4);
if(!fs.existsSync(name)) name=(dir + root + '.xlsx.' + i + type);
if(!fs.existsSync(name)) name=(dir + root + '.xlsm.' + i + type);
if(!fs.existsSync(name)) name=(dir + root + '.xlsb.' + i + type);
}
return name;
};
describe(x + ext + ' should generate correct CSV output', function() {
@ -146,12 +170,24 @@ function parsetest(x, wb, full, ext) {
});
});
});
if(fs.existsSync(dir + '2011/' + x + '.xml'))
describe(x + ext + '.xml from 2011', function() {
it('should parse', function() {
var wb = X.readFile(dir + '2011/' + x + '.xml', opts);
});
});
if(fs.existsSync(dir + '2013/' + x + '.xlsb'))
describe(x + ext + '.xlsb from 2013', function() {
it('should parse', function() {
var wb = X.readFile(dir + '2013/' + x + '.xlsb', opts);
});
});
if(fs.existsSync(dir + x + '.xml' + ext))
describe(x + '.xml', function() {
it('should parse', function() {
var wb = X.readFile(dir + x + '.xml', opts);
});
});
}
var wbtable = {};
@ -192,16 +228,16 @@ describe('parse options', function() {
X = require(modp);
});
describe('cell', function() {
it('should generate HTML by default', function() {
var wb = X.readFile(paths.cst1);
it('XLSX should generate HTML by default', function() {
var wb = X.readFile(paths.cstxlsx);
var ws = wb.Sheets.Sheet1;
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(html_cell_types.indexOf(ws[addr].t) === -1 || ws[addr].h);
});
});
it('should not generate HTML when requested', function() {
var wb = X.readFile(paths.cst1, {cellHTML:false});
it('XLSX should not generate HTML when requested', function() {
var wb = X.readFile(paths.cstxlsx, {cellHTML:false});
var ws = wb.Sheets.Sheet1;
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
@ -209,75 +245,84 @@ describe('parse options', function() {
});
});
it('should generate formulae by default', function() {
var wb = X.readFile(paths.fstb);
var found = false;
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
if (!ws) { console.log("wb not defined"); console.log(paths.fstb); console.log(s); console.log(wb.SheetNames); }
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
if(typeof ws[addr].f !== 'undefined') return found = true;
[paths.fstxls, paths.fstxlsb].forEach(function(p) {
var wb = X.readFile(p);
var found = false;
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
if(typeof ws[addr].f !== 'undefined') return (found = true);
});
});
assert(found);
});
assert(found);
});
it('should not generate formulae when requested', function() {
var wb =X.readFile(paths.fstb,{cellFormula:false});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(typeof ws[addr].f === 'undefined');
[paths.fstxls, paths.fstxlsb].forEach(function(p) {
var wb =X.readFile(p,{cellFormula:false});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(typeof ws[addr].f === 'undefined');
});
});
});
});
it('should not generate number formats by default', function() {
var wb = X.readFile(paths.nf1);
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(typeof ws[addr].z === 'undefined');
[paths.nfxls, paths.nfxlsx].forEach(function(p) {
var wb = X.readFile(p);
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(typeof ws[addr].z === 'undefined');
});
});
});
});
it('should generate number formats when requested', function() {
var wb = X.readFile(paths.nf1, {cellNF: true});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(ws[addr].t!== 'n' || typeof ws[addr].z !== 'undefined');
[paths.nfxls, paths.nfxlsx].forEach(function(p) {
var wb = X.readFile(p, {cellNF: true});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
assert(ws[addr].t!== 'n' || typeof ws[addr].z !== 'undefined');
});
});
});
});
it('should not generate cell styles by default', function() {
var wb = X.readFile(paths.css1);
[paths.cssxlsx, paths.cssxls, paths.cssxml].forEach(function(p) {
var wb = X.readFile(p);
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
if (typeof ws[addr].s !== 'undefined') {
console.log(paths.css1);
}
assert(typeof ws[addr].s === 'undefined');
});
});
});
});
it('XLSX should generate cell styles when requested', function() {
var wb = X.readFile(paths.css1, {cellStyles:true});
it('should generate cell styles when requested', function() {
/* TODO: XLS / XLML */
[paths.cssxlsx, /*paths.cssxls, paths.cssxml*/].forEach(function(p) {
var wb = X.readFile(p, {cellStyles:true});
var found = false;
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
if(typeof ws[addr].s !== 'undefined') return found = true;
if(typeof ws[addr].s !== 'undefined') return (found = true);
});
});
assert(found);
});
});
it('should not generate cell dates by default', function() {
var wb = X.readFile(paths.dt1);
var wb = X.readFile(paths.dtxlsx);
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
@ -287,7 +332,7 @@ describe('parse options', function() {
});
});
it('XLSB should not generate cell dates', function() {
var wb = X.readFile(paths.dt2, {cellDates: true});
var wb = X.readFile(paths.dtxlsb, {cellDates: true});
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
@ -297,13 +342,13 @@ describe('parse options', function() {
});
});
it('XLSX should generate cell dates when requested', function() {
var wb = X.readFile(paths.dt1, {cellDates: true});
var wb = X.readFile(paths.dtxlsx, {cellDates: true});
var found = false;
wb.SheetNames.forEach(function(s) {
var ws = wb.Sheets[s];
Object.keys(ws).forEach(function(addr) {
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
if(ws[addr].t === 'd') return found = true;
if(ws[addr].t === 'd') return (found = true);
});
});
assert(found);
@ -311,19 +356,17 @@ describe('parse options', function() {
});
describe('sheet', function() {
it('should not generate sheet stubs by default', function() {
var wb = X.readFile(paths.mc1);
assert.throws(function() { wb.Sheets.Merge.A2.v; });
wb = X.readFile(paths.mc2);
assert.throws(function() { wb.Sheets.Merge.A2.v; });
wb = X.readFile(paths.mc3);
assert.throws(function() { wb.Sheets.Merge.A2.v; });
[paths.mcxlsx, paths.mcxlsb, paths.mcods, paths.mcxls, paths.mcxml].forEach(function(p) {
var wb = X.readFile(p);
assert.throws(function() { return wb.Sheets.Merge.A2.v; });
});
});
it('should generate sheet stubs when requested', function() {
var wb = X.readFile(paths.mc1, {sheetStubs:true});
assert(typeof wb.Sheets.Merge.A2.t !== 'undefined');
wb = X.readFile(paths.mc2, {sheetStubs:true});
assert(typeof wb.Sheets.Merge.A2.t !== 'undefined');
/* TODO: ODS */
/* TODO: ODS/XLS/XML */
[paths.mcxlsx, paths.mcxlsb /*, paths.mcods, paths.mcxls, paths.mcxml*/].forEach(function(p) {
var wb = X.readFile(p, {sheetStubs:true});
assert(typeof wb.Sheets.Merge.A2.t !== 'undefined');
});
});
function checkcells(wb, A46, B26, C16, D2) {
assert((typeof wb.Sheets.Text.A46 !== 'undefined') == A46);
@ -332,84 +375,83 @@ describe('parse options', function() {
assert((typeof wb.Sheets.Text.D2 !== 'undefined') == D2);
}
it('should read all cells by default', function() {
var wb = X.readFile(paths.fst1);
checkcells(wb, true, true, true, true);
wb = X.readFile(paths.fst2);
checkcells(wb, true, true, true, true);
wb = X.readFile(paths.fst3);
checkcells(wb, true, true, true, true);
[paths.fstxlsx, paths.fstxlsb, paths.fstods, paths.fstxls, paths.fstxml].forEach(function(p) {
checkcells(X.readFile(p), true, true, true, true);
});
});
it('sheetRows n=20', function() {
var wb = X.readFile(paths.fst1, {sheetRows:20});
checkcells(wb, false, false, true, true);
wb = X.readFile(paths.fst2, {sheetRows:20});
checkcells(wb, false, false, true, true);
wb = X.readFile(paths.fst3, {sheetRows:20});
checkcells(wb, false, false, true, true);
[paths.fstxlsx, paths.fstxlsb, paths.fstods, paths.fstxls, paths.fstxml].forEach(function(p) {
checkcells(X.readFile(p, {sheetRows:20}), false, false, true, true);
});
});
it('sheetRows n=10', function() {
var wb = X.readFile(paths.fst1, {sheetRows:10});
checkcells(wb, false, false, false, true);
wb = X.readFile(paths.fst2, {sheetRows:10});
checkcells(wb, false, false, false, true);
wb = X.readFile(paths.fst3, {sheetRows:10});
checkcells(wb, false, false, false, true);
[paths.fstxlsx, paths.fstxlsb, paths.fstods, paths.fstxls, paths.fstxml].forEach(function(p) {
checkcells(X.readFile(p, {sheetRows:10}), false, false, false, true);
});
});
});
describe('book', function() {
it('bookSheets should not generate sheets', function() {
var wb = X.readFile(paths.mc1, {bookSheets:true});
assert(typeof wb.Sheets === 'undefined');
var wb = X.readFile(paths.mc2, {bookSheets:true});
assert(typeof wb.Sheets === 'undefined');
[paths.mcxlsx, paths.mcxlsb, paths.mcxls, paths.mcxml].forEach(function(p) {
var wb = X.readFile(p, {bookSheets:true});
assert(typeof wb.Sheets === 'undefined');
});
});
it('bookProps should not generate sheets', function() {
var wb = X.readFile(paths.nf1, {bookProps:true});
assert(typeof wb.Sheets === 'undefined');
wb = X.readFile(paths.nf2, {bookProps:true});
assert(typeof wb.Sheets === 'undefined');
[paths.nfxlsx, paths.nfxlsb, paths.nfxls, paths.nfxml].forEach(function(p) {
var wb = X.readFile(p, {bookProps:true});
assert(typeof wb.Sheets === 'undefined');
});
});
it('bookProps && bookSheets should not generate sheets', function() {
var wb = X.readFile(paths.lon1, {bookProps:true, bookSheets:true});
assert(typeof wb.Sheets === 'undefined');
[paths.lonxlsx, paths.lonxls].forEach(function(p) {
var wb = X.readFile(p, {bookProps:true, bookSheets:true});
assert(typeof wb.Sheets === 'undefined');
});
});
it('should not generate deps by default', function() {
var wb = X.readFile(paths.fst1);
assert(typeof wb.Deps === 'undefined' || !(wb.Deps.length>0));
wb = X.readFile(paths.fst2);
assert(typeof wb.Deps === 'undefined' || !(wb.Deps.length>0));
[paths.fstxlsx, paths.fstxlsb, paths.fstxls, paths.fstxml].forEach(function(p) {
var wb = X.readFile(p);
assert(typeof wb.Deps === 'undefined' || !(wb.Deps && wb.Deps.length>0));
});
});
it('bookDeps should generate deps', function() {
var wb = X.readFile(paths.fst1, {bookDeps:true});
assert(typeof wb.Deps !== 'undefined' && wb.Deps.length > 0);
wb = X.readFile(paths.fst2, {bookDeps:true});
assert(typeof wb.Deps !== 'undefined' && wb.Deps.length > 0);
it('bookDeps should generate deps (XLSX/XLSB)', function() {
[paths.fstxlsx, paths.fstxlsb].forEach(function(p) {
var wb = X.readFile(p, {bookDeps:true});
assert(typeof wb.Deps !== 'undefined' && wb.Deps.length > 0);
});
});
var ckf = function(wb, fields, exists) { fields.forEach(function(f) {
assert((typeof wb[f] !== 'undefined') == exists);
}); };
it('should not generate book files by default', function() {
var wb = X.readFile(paths.fst1);
var wb;
wb = X.readFile(paths.fstxlsx);
ckf(wb, ['files', 'keys'], false);
wb = X.readFile(paths.fst2);
wb = X.readFile(paths.fstxlsb);
ckf(wb, ['files', 'keys'], false);
wb = X.readFile(paths.fstxls);
ckf(wb, ['cfb'], false);
});
it('bookFiles should generate book files', function() {
var wb = X.readFile(paths.fst1, {bookFiles:true});
var wb;
wb = X.readFile(paths.fstxlsx, {bookFiles:true});
ckf(wb, ['files', 'keys'], true);
wb = X.readFile(paths.fst2, {bookFiles:true});
wb = X.readFile(paths.fstxlsb, {bookFiles:true});
ckf(wb, ['files', 'keys'], true);
wb = X.readFile(paths.fstxls, {bookFiles:true});
ckf(wb, ['cfb'], true);
});
it('should not generate VBA by default', function() {
var wb = X.readFile(paths.nf1);
var wb = X.readFile(paths.nfxlsx);
assert(typeof wb.vbaraw === 'undefined');
wb = X.readFile(paths.nf2);
wb = X.readFile(paths.nfxlsb);
assert(typeof wb.vbaraw === 'undefined');
});
it('bookVBA should generate vbaraw', function() {
var wb = X.readFile(paths.nf1,{bookVBA:true});
it('bookVBA should generate vbaraw (XLSX/XLSB)', function() {
var wb = X.readFile(paths.nfxlsx,{bookVBA:true});
assert(typeof wb.vbaraw !== 'undefined');
wb = X.readFile(paths.nf2,{bookVBA:true});
wb = X.readFile(paths.nfxlsb,{bookVBA:true});
assert(typeof wb.vbaraw !== 'undefined');
});
});
@ -417,61 +459,98 @@ describe('parse options', function() {
describe('input formats', function() {
it('should read binary strings', function() {
X.read(fs.readFileSync(paths.cst1, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cst2, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstxlsx, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstxlsb, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstxls, 'binary'), {type: 'binary'});
X.read(fs.readFileSync(paths.cstxml, 'binary'), {type: 'binary'});
});
it('should read base64 strings', function() {
X.read(fs.readFileSync(paths.cst1, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cst2, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxls, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxml, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxlsx, 'base64'), {type: 'base64'});
X.read(fs.readFileSync(paths.cstxlsb, 'base64'), {type: 'base64'});
});
it('should read buffers', function() {
X.read(fs.readFileSync(paths.cst1), {type: 'buffer'});
X.read(fs.readFileSync(paths.cst2), {type: 'buffer'});
X.read(fs.readFileSync(paths.cstxls), {type: 'buffer'});
X.read(fs.readFileSync(paths.cstxml), {type: 'buffer'});
X.read(fs.readFileSync(paths.cstxlsx), {type: 'buffer'});
X.read(fs.readFileSync(paths.cstxlsb), {type: 'buffer'});
});
it('should read array', function() {
X.read(fs.readFileSync(paths.mcxls, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
X.read(fs.readFileSync(paths.mcxml, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
X.read(fs.readFileSync(paths.mcxlsx, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
X.read(fs.readFileSync(paths.mcxlsb, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
X.read(fs.readFileSync(paths.mcods, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
});
it('should throw if format is unknown', function() {
assert.throws(function() { X.read(fs.readFileSync(paths.cst1), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cst2), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxls), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxml), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsx), {type: 'dafuq'}); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsb), {type: 'dafuq'}); });
});
it('should infer buffer type', function() {
X.read(fs.readFileSync(paths.cst1));
X.read(fs.readFileSync(paths.cst2));
X.read(fs.readFileSync(paths.cstxls));
X.read(fs.readFileSync(paths.cstxml));
X.read(fs.readFileSync(paths.cstxlsx));
X.read(fs.readFileSync(paths.cstxlsb));
});
it('should default to base64 type', function() {
assert.throws(function() { X.read(fs.readFileSync(paths.cst1, 'binary')); });
assert.throws(function() { X.read(fs.readFileSync(paths.cst2, 'binary')); });
X.read(fs.readFileSync(paths.cst1, 'base64'));
X.read(fs.readFileSync(paths.cst2, 'base64'));
assert.throws(function() { X.read(fs.readFileSync(paths.cstxls, 'binary')); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxml, 'binary')); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsx, 'binary')); });
assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsb, 'binary')); });
X.read(fs.readFileSync(paths.cstxls, 'base64'));
X.read(fs.readFileSync(paths.cstxml, 'base64'));
X.read(fs.readFileSync(paths.cstxlsx, 'base64'));
X.read(fs.readFileSync(paths.cstxlsb, 'base64'));
});
});
describe('output formats', function() {
var wb1, wb2;
var wb1, wb2, wb3, wb4;
before(function() {
X = require(modp);
wb1 = X.readFile(paths.cp1);
wb2 = X.readFile(paths.cp2);
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
wb3 = X.readFile(paths.cpxls);
wb4 = X.readFile(paths.cpxml);
});
it('should write binary strings', function() {
X.write(wb1, {type: 'binary'});
X.write(wb2, {type: 'binary'});
X.write(wb3, {type: 'binary'});
X.write(wb4, {type: 'binary'});
X.read(X.write(wb1, {type: 'binary'}), {type: 'binary'});
X.read(X.write(wb2, {type: 'binary'}), {type: 'binary'});
X.read(X.write(wb3, {type: 'binary'}), {type: 'binary'});
X.read(X.write(wb4, {type: 'binary'}), {type: 'binary'});
});
it('should write base64 strings', function() {
X.write(wb1, {type: 'base64'});
X.write(wb2, {type: 'base64'});
X.write(wb3, {type: 'base64'});
X.write(wb4, {type: 'base64'});
X.read(X.write(wb1, {type: 'base64'}), {type: 'base64'});
X.read(X.write(wb2, {type: 'base64'}), {type: 'base64'});
X.read(X.write(wb3, {type: 'base64'}), {type: 'base64'});
X.read(X.write(wb4, {type: 'base64'}), {type: 'base64'});
});
it('should write buffers', function() {
X.write(wb1, {type: 'buffer'});
X.write(wb2, {type: 'buffer'});
X.write(wb3, {type: 'buffer'});
X.write(wb4, {type: 'buffer'});
X.read(X.write(wb1, {type: 'buffer'}), {type: 'buffer'});
X.read(X.write(wb2, {type: 'buffer'}), {type: 'buffer'});
X.read(X.write(wb3, {type: 'buffer'}), {type: 'buffer'});
X.read(X.write(wb4, {type: 'buffer'}), {type: 'buffer'});
});
it('should throw if format is unknown', function() {
assert.throws(function() { X.write(wb1, {type: 'dafuq'}); });
assert.throws(function() { X.write(wb2, {type: 'dafuq'}); });
assert.throws(function() { X.write(wb3, {type: 'dafuq'}); });
assert.throws(function() { X.write(wb4, {type: 'dafuq'}); });
});
});
@ -499,25 +578,24 @@ function deepcmp(x,y,k,m,c) {
var s = k.indexOf(".");
m = (m||"") + "|" + (s > -1 ? k.substr(0,s) : k);
if(s < 0) return assert[c<0?'notEqual':'equal'](x[k], y[k], m);
return deepcmp(x[k.substr(0,s)],y[k.substr(0,s)],k.substr(s+1),m,c)
return deepcmp(x[k.substr(0,s)],y[k.substr(0,s)],k.substr(s+1),m,c);
}
var styexc = [
'A2|H10|bgColor.rgb',
'F6|H1|patternType'
]
];
var stykeys = [
"patternType",
"fgColor.rgb",
"bgColor.rgb"
];
function diffsty(ws, r1,r2) {
var c1 = ws[r1].s.fill, c2 = ws[r2].s.fill;
var c1 = ws[r1].s, c2 = ws[r2].s;
stykeys.forEach(function(m) {
var c = -1;
if(styexc.indexOf(r1+"|"+r2+"|"+m) > -1) c = 1;
else if(styexc.indexOf(r2+"|"+r1+"|"+m) > -1) c = 1;
deepcmp(c1,c2,m,r1+","+r2,c);
});
}
@ -526,10 +604,12 @@ describe('parse features', function() {
it('should have comment as part of cell properties', function(){
var X = require(modp);
var sheet = 'Sheet1';
var wb1=X.readFile(paths.swc1);
var wb2=X.readFile(paths.swc2);
var wb1=X.readFile(paths.swcxlsx);
var wb2=X.readFile(paths.swcxlsb);
var wb3=X.readFile(paths.swcxls);
var wb4=X.readFile(paths.swcxml);
[wb1,wb2].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
[wb1,wb2,wb3,wb4].map(function(wb) { return wb.Sheets[sheet]; }).forEach(function(ws, i) {
assert.equal(ws.B1.c.length, 1,"must have 1 comment");
assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author");
assert.equal(ws.B1.c[0].t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"), "Yegor Kozlov:\nfirst cell", "must have the concatenated texts");
@ -542,40 +622,53 @@ describe('parse features', function() {
describe('should parse core properties and custom properties', function() {
var wb1, wb2;
before(function() {
X = require(modp);
wb1 = X.readFile(paths.cp1);
wb2 = X.readFile(paths.cp2);
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
wb3 = X.readFile(paths.cpxls);
wb4 = X.readFile(paths.cpxml);
});
it(N1 + ' should parse core properties', function() { coreprop(wb1); });
it(N2 + ' should parse core properties', function() { coreprop(wb2); });
it(N3 + ' should parse core properties', function() { coreprop(wb3); });
it(N4 + ' should parse core properties', function() { coreprop(wb4); });
it(N1 + ' should parse custom properties', function() { custprop(wb1); });
it(N2 + ' should parse custom properties', function() { custprop(wb2); });
it(N3 + ' should parse custom properties', function() { custprop(wb3); });
it(N4 + ' should parse custom properties', function() { custprop(wb4); });
});
describe('sheetRows', function() {
it('should use original range if not set', function() {
var opts = {};
var wb1 = X.readFile(paths.fst1, opts);
var wb2 = X.readFile(paths.fst2, opts);
[wb1, wb2].forEach(function(wb) {
var wb1 = X.readFile(paths.fstxlsx, opts);
var wb2 = X.readFile(paths.fstxlsb, opts);
var wb3 = X.readFile(paths.fstxls, opts);
var wb4 = X.readFile(paths.fstxml, opts);
[wb1, wb2, wb3, wb4].forEach(function(wb) {
assert.equal(wb.Sheets.Text["!ref"],"A1:F49");
});
});
it('should adjust range if set', function() {
var opts = {sheetRows:10};
var wb1 = X.readFile(paths.fst1, opts);
var wb2 = X.readFile(paths.fst2, opts);
[wb1, wb2].forEach(function(wb) {
var wb1 = X.readFile(paths.fstxlsx, opts);
var wb2 = X.readFile(paths.fstxlsb, opts);
var wb3 = X.readFile(paths.fstxls, opts);
var wb4 = X.readFile(paths.fstxml, opts);
/* TODO */
[wb1, wb2 /*, wb3, wb4 */].forEach(function(wb) {
assert.equal(wb.Sheets.Text["!fullref"],"A1:F49");
assert.equal(wb.Sheets.Text["!ref"],"A1:F10");
});
});
it('should not generate comment cells', function() {
var opts = {sheetRows:10};
var wb1 = X.readFile(paths.cst1, opts);
var wb2 = X.readFile(paths.cst2, opts);
[wb1, wb2].forEach(function(wb) {
var wb1 = X.readFile(paths.cstxlsx, opts);
var wb2 = X.readFile(paths.cstxlsb, opts);
var wb3 = X.readFile(paths.cstxls, opts);
var wb4 = X.readFile(paths.cstxml, opts);
/* TODO */
[wb1, wb2 /*, wb3, wb4 */].forEach(function(wb) {
assert.equal(wb.Sheets.Sheet7["!fullref"],"A1:N34");
assert.equal(wb.Sheets.Sheet7["!ref"],"A1");
});
@ -586,17 +679,23 @@ describe('parse features', function() {
var wb1, wb2;
before(function() {
X = require(modp);
wb1 = X.readFile(paths.mc1);
wb2 = X.readFile(paths.mc2);
wb3 = X.readFile(paths.mc3);
wb1 = X.readFile(paths.mcxlsx);
wb2 = X.readFile(paths.mcxlsb);
wb3 = X.readFile(paths.mcods);
wb4 = X.readFile(paths.mcxls);
wb5 = X.readFile(paths.mcxml);
});
it('should have !merges', function() {
assert(wb1.Sheets.Merge['!merges']);
assert(wb2.Sheets.Merge['!merges']);
assert(wb3.Sheets.Merge['!merges']);
var m = [wb1, wb2, wb3].map(function(x) { return x.Sheets.Merge['!merges'].map(function(y) { return X.utils.encode_range(y); });});
assert(wb4.Sheets.Merge['!merges']);
assert(wb5.Sheets.Merge['!merges']);
var m = [wb1, wb2, wb3, wb4, wb5].map(function(x) { return x.Sheets.Merge['!merges'].map(function(y) { return X.utils.encode_range(y); });});
assert.deepEqual(m[0].sort(),m[1].sort());
assert.deepEqual(m[0].sort(),m[2].sort());
assert.deepEqual(m[0].sort(),m[3].sort());
assert.deepEqual(m[0].sort(),m[4].sort());
});
});
@ -604,8 +703,10 @@ describe('parse features', function() {
var wb1, wb2;
before(function() {
X = require(modp);
wb1 = X.readFile(paths.hl1);
wb2 = X.readFile(paths.hl2);
wb1 = X.readFile(paths.hlxlsx);
wb2 = X.readFile(paths.hlxlsb);
wb3 = X.readFile(paths.hlxls);
wb4 = X.readFile(paths.hlxml);
});
function hlink(wb) {
@ -621,14 +722,15 @@ describe('parse features', function() {
it(N1, function() { hlink(wb1); });
it(N2, function() { hlink(wb2); });
it(N3, function() { hlink(wb3); });
it(N4, function() { hlink(wb4); });
});
describe('should parse cells with date type (XLSX/XLSM)', function() {
it('Must have read the date', function() {
var wb, ws;
X = require(modp);
wb = X.readFile(paths.dt1);
var sheetName = 'Sheet1';
wb = X.readFile(paths.dtxlsx);
ws = wb.Sheets[sheetName];
var sheet = X.utils.sheet_to_row_object_array(ws);
assert.equal(sheet[3]['てすと'], '2/14/14');
@ -636,10 +738,9 @@ describe('parse features', function() {
it('cellDates should not affect formatted text', function() {
var wb1, ws1, wb2, ws2;
var sheetName = 'Sheet1';
X = require(modp);
wb1 = X.readFile(paths.dt1);
wb1 = X.readFile(paths.dtxlsx);
ws1 = wb1.Sheets[sheetName];
wb2 = X.readFile(paths.dt2);
wb2 = X.readFile(paths.dtxlsb);
ws2 = wb2.Sheets[sheetName];
assert.equal(X.utils.sheet_to_csv(ws1),X.utils.sheet_to_csv(ws2));
});
@ -711,6 +812,7 @@ describe('parse features', function() {
// }
// });
// });
});
function seq(end, start) {
@ -727,8 +829,8 @@ describe('roundtrip features', function() {
describe('should parse core properties and custom properties', function() {
var wb1, wb2, base = './tmp/cp';
before(function() {
wb1 = X.readFile(paths.cp1);
wb2 = X.readFile(paths.cp2);
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
fullex.forEach(function(p) {
X.writeFile(wb1, base + '.xlsm' + p);
X.writeFile(wb2, base + '.xlsb' + p);
@ -745,7 +847,7 @@ describe('roundtrip features', function() {
describe('should preserve features', function() {
it('merge cells', function() {
var wb1 = X.readFile(paths.mc1);
var wb1 = X.readFile(paths.mcxlsx);
var wb2 = X.read(X.write(wb1, {type:'binary'}), {type:'binary'});
var m1 = wb1.Sheets.Merge['!merges'].map(X.utils.encode_range);
var m2 = wb2.Sheets.Merge['!merges'].map(X.utils.encode_range);
@ -761,8 +863,8 @@ describe('roundtrip features', function() {
var b = (n & 4) ? 'd' : 'n', di = b === 'd';
var a = (n & 8) ? 'd' : 'n', dh = a === 'd';
var f, sheet, addr;
if(dh) { f = paths.dt1; sheet = 'Sheet1'; addr = 'B5'; }
else { f = paths.nf1; sheet = '2011'; addr = 'J36'; }
if(dh) { f = paths.dtxlsx; sheet = 'Sheet1'; addr = 'B5'; }
else { f = paths.nfxlsx; sheet = '2011'; addr = 'J36'; }
it('[' + a + '] -> (' + b + ') -> [' + c + '] -> (' + d + ')', function() {
var wb1 = X.readFile(f, {cellNF: true, cellDates: di, WTF: opts.WTF});
var wb2 = X.read(X.write(wb1, {type:'binary', cellDates:dj, WTF:opts.WTF}), {type:'binary', cellDates: dk, WTF: opts.WTF});
@ -779,24 +881,17 @@ describe('roundtrip features', function() {
else assert.equal(m[1].t, 'n');
if(m[0].t === m[1].t) assert.equal(m[0].v, m[1].v);
else if(m[0].t === 'd') assert(Math.abs(datenum(new Date(m[0].v)) - m[1].v)) < .01; /* TODO: 1sec adjustment */
else if(m[0].t === 'd') assert(Math.abs(datenum(new Date(m[0].v)) - m[1].v) < 0.01); /* TODO: 1sec adjustment */
});
});
});
/* the XLSJS require should not cause the test suite to fail */
var XLSJS;
try {
XLSJS = require('xlsjs');
var xls = XLSJS.readFile('./test_files/formula_stress_test.xls');
var xml = XLSJS.readFile('./test_files/formula_stress_test.xls.xml');
} catch(e) { return; }
describe('xlsjs conversions', function() { [
describe('xls to xlsx conversions', function() { [
['XLS', 'formula_stress_test.xls'],
['XML', 'formula_stress_test.xls.xml']
].forEach(function(w) {
it('should be able to write ' + w[0] + ' files from xlsjs', function() {
var xls = XLSJS.readFile('./test_files/' + w[1], {cellNF:true});
it('should be able to write ' + w[0] + ' files', function() {
var xls = X.readFile('./test_files/' + w[1], {cellNF:true});
X.writeFile(xls, './tmp/' + w[1] + '.xlsx', {bookSST:true});
X.writeFile(xls, './tmp/' + w[1] + '.xlsb', {bookSST:true});
});
@ -804,10 +899,12 @@ describe('roundtrip features', function() {
});
});
function password_file(x){return x.match(/^password.*\.xls$/); }
var password_files = fs.readdirSync('test_files').filter(password_file);
describe('invalid files', function() {
describe('parse', function() { [
['passwords', 'excel-reader-xlsx_error03.xlsx'],
['XLS files', 'roo_type_excel.xlsx'],
['password', 'apachepoi_password.xls'],
['passwords', 'apachepoi_xor-encryption-abc.xls'],
['DOC files', 'word_doc.doc']
].forEach(function(w) { it('should fail on ' + w[0], function() {
assert.throws(function() { X.readFile(dir + w[1]); });
@ -815,14 +912,19 @@ describe('invalid files', function() {
}); });
});
describe('write', function() {
it('should pass', function() { X.write(X.readFile(paths.fst1), {type:'binary'}); });
it('should pass -> XLSX', function() {
X.write(X.readFile(paths.fstxlsb), {type:'binary'});
X.write(X.readFile(paths.fstxlsx), {type:'binary'});
X.write(X.readFile(paths.fstxls), {type:'binary'});
X.write(X.readFile(paths.fstxml), {type:'binary'});
});
it('should pass if a sheet is missing', function() {
var wb = X.readFile(paths.fst1); delete wb.Sheets[wb.SheetNames[0]];
var wb = X.readFile(paths.fstxlsx); delete wb.Sheets[wb.SheetNames[0]];
X.read(X.write(wb, {type:'binary'}), {type:'binary'});
});
['Props', 'Custprops', 'SSF'].forEach(function(t) {
it('should pass if ' + t + ' is missing', function() {
var wb = X.readFile(paths.fst1);
var wb = X.readFile(paths.fstxlsx);
assert.doesNotThrow(function() {
delete wb[t];
X.write(wb, {type:'binary'});
@ -831,7 +933,7 @@ describe('invalid files', function() {
});
['SheetNames', 'Sheets'].forEach(function(t) {
it('should fail if ' + t + ' is missing', function() {
var wb = X.readFile(paths.fst1);
var wb = X.readFile(paths.fstxlsx);
assert.throws(function() {
delete wb[t];
X.write(wb, {type:'binary'});
@ -912,9 +1014,9 @@ describe('json output', function() {
it('should use column names if header == "A"', function() {
var json = X.utils.sheet_to_json(ws, {header:'A'});
assert.equal(json.length, data.length);
assert.equal(json[1]['A'], true);
assert.equal(json[2]['B'], "bar");
assert.equal(json[3]['C'], "qux");
assert.equal(json[1].A, true);
assert.equal(json[2].B, "bar");
assert.equal(json[3].C, "qux");
assert.doesNotThrow(function() { seeker(json, "ABC", "sheetjs"); });
assert.throws(function() { seeker(json, "ABCD", "sheetjs"); });
assert.throws(function() { seeker(json, "ABC", "baz"); });
@ -922,9 +1024,9 @@ describe('json output', function() {
it('should use column labels if specified', function() {
var json = X.utils.sheet_to_json(ws, {header:["O","D","I","N"]});
assert.equal(json.length, data.length);
assert.equal(json[1]['O'], true);
assert.equal(json[2]['D'], "bar");
assert.equal(json[3]['I'], "qux");
assert.equal(json[1].O, true);
assert.equal(json[2].D, "bar");
assert.equal(json[3].I, "qux");
assert.doesNotThrow(function() { seeker(json, "ODI", "sheetjs"); });
assert.throws(function() { seeker(json, "ODIN", "sheetjs"); });
assert.throws(function() { seeker(json, "ODIN", "baz"); });
@ -990,4 +1092,27 @@ describe('corner cases', function() {
}
});
});
it('CFB', function() {
var cfb = X.CFB.read(paths.swcxls, {type:"file"});
var xls = X.parse_xlscfb(cfb);
});
it('codepage', function() {
X.readFile(dir + "biff5/number_format_greek.xls");
});
});
describe('encryption', function() {
password_files.forEach(function(x) {
describe(x, function() {
it('should throw with no password', function() {assert.throws(function() { X.readFile(dir + x); }); });
it('should throw with wrong password', function() {assert.throws(function() { X.readFile(dir + x, {password:'passwor',WTF:opts.WTF}); }); });
it('should recognize correct password', function() {
try { X.readFile(dir + x, {password:'password',WTF:opts.WTF}); }
catch(e) { if(e.message == "Password is incorrect") throw e; }
});
it.skip('should decrypt file', function() {
var wb = X.readFile(dir + x, {password:'password',WTF:opts.WTF});
});
});
});
});

694
tests.lst

@ -368,3 +368,697 @@ roo_type_excel.ods.pending
roo_type_excelx.ods
roo_whitespace.ods
sushi.ods
biff5/NumberFormatCondition.xls
biff5/RkNumber.xls
biff5/cell_style_simple.xls
biff5/comments_stress_test.xls
biff5/custom_properties.xls
biff5/defined_names_simple.xls
biff5/hyperlink_stress_test_2011.xls
biff5/large_strings.xls.pending
biff5/merge_cells.xls
biff5/named_ranges_2011.xls
biff5/number_format.xls
biff5/number_format_estonian.xls
biff5/number_format_greek.xls.pending
biff5/number_format_vietnamese.xls
biff5/pivot_table_test.xls
biff5/rich_text_stress.xls
biff5/sushi.xls
biff5/text_and_numbers.xls
comments_stress_test.xls.b64
formula_stress_test.xls.b64
A4X_2013.xls
A4X_gnumeric.xls
AutoFilter.xls
BlankSheetTypes.xls
ErrorTypes.xls
LONumbers-2010.xls
LONumbers-2011.xls
LONumbers.xls
NumberFormatCondition.xls
RkNumber.xls
apachepoi_12561-1.xls
apachepoi_12561-2.xls
apachepoi_12843-1.xls
apachepoi_12843-2.xls
apachepoi_13224.xls
apachepoi_13796.xls
apachepoi_14330-1.xls
apachepoi_14330-2.xls
apachepoi_14460.xls
apachepoi_15228.xls
apachepoi_15375.xls
apachepoi_15556.xls
apachepoi_15573.xls
apachepoi_1900DateWindowing.xls
apachepoi_1904DateWindowing.xls
apachepoi_19599-1.xls
apachepoi_19599-2.xls
apachepoi_22742.xls
apachepoi_24207.xls
apachepoi_24215.xls
apachepoi_25183.xls
apachepoi_25695.xls
apachepoi_26100.xls
apachepoi_27272_1.xls
apachepoi_27272_2.xls
apachepoi_27349-vlookupAcrossSheets.xls
apachepoi_27364.xls
apachepoi_27394.xls
apachepoi_27852.xls
apachepoi_27933.xls
apachepoi_28772.xls
apachepoi_28774.xls
apachepoi_29675.xls
apachepoi_29942.xls
apachepoi_29982.xls
apachepoi_30070.xls
apachepoi_30540.xls
apachepoi_30978-alt.xls
apachepoi_30978-deleted.xls
apachepoi_31661.xls
apachepoi_31749.xls
apachepoi_31979.xls
apachepoi_32822.xls
apachepoi_33082.xls
apachepoi_34775.xls
apachepoi_35564.xls
apachepoi_35565.xls
apachepoi_36947.xls
apachepoi_37376.xls
apachepoi_37630.xls
apachepoi_37684-1.xls
apachepoi_37684-2.xls
apachepoi_37684.xls
apachepoi_39234.xls
apachepoi_39512.xls
apachepoi_39634.xls
apachepoi_3dFormulas.xls
apachepoi_40285.xls
apachepoi_41139.xls
apachepoi_41546.xls
apachepoi_42016.xls
apachepoi_42464-ExpPtg-bad.xls
apachepoi_42464-ExpPtg-ok.xls
apachepoi_42726.xls
apachepoi_42844.xls
apachepoi_43251.xls
apachepoi_43493.xls
apachepoi_43623.xls
apachepoi_43902.xls
apachepoi_44010-SingleChart.xls
apachepoi_44010-TwoCharts.xls
apachepoi_44167.xls
apachepoi_44200.xls
apachepoi_44201.xls
apachepoi_44235.xls
apachepoi_44297.xls
apachepoi_44593.xls
apachepoi_44636.xls
apachepoi_44643.xls
apachepoi_44693.xls
apachepoi_44840.xls
apachepoi_44861.xls
apachepoi_44891.xls
apachepoi_44958.xls
apachepoi_45129.xls
apachepoi_45290.xls
apachepoi_45322.xls
apachepoi_45365-2.xls
apachepoi_45365.xls
apachepoi_45492.xls
apachepoi_45538_classic_Footer.xls
apachepoi_45538_classic_Header.xls
apachepoi_45538_form_Footer.xls
apachepoi_45538_form_Header.xls
apachepoi_45672.xls
apachepoi_45720.xls
apachepoi_45761.xls
apachepoi_45784.xls
apachepoi_46136-NoWarnings.xls
apachepoi_46136-WithWarnings.xls
apachepoi_46137.xls
apachepoi_46250.xls
apachepoi_46368.xls
apachepoi_46445.xls
apachepoi_46670_http.xls
apachepoi_46670_local.xls
apachepoi_46670_ref_airline.xls
apachepoi_46904.xls
apachepoi_47034.xls
apachepoi_47154.xls
apachepoi_47251.xls
apachepoi_47251_1.xls
apachepoi_47701.xls
apachepoi_47847.xls
apachepoi_47920.xls
apachepoi_47924.xls
apachepoi_48026.xls
apachepoi_48180.xls
apachepoi_48325.xls
apachepoi_48703.xls
apachepoi_48968.xls
apachepoi_49096.xls
apachepoi_49185.xls
apachepoi_49219.xls
apachepoi_49237.xls
apachepoi_49524.xls
apachepoi_49529.xls
apachepoi_49581.xls
apachepoi_49612.xls
apachepoi_49751.xls
apachepoi_49761.xls
apachepoi_49896.xls
apachepoi_49928.xls
apachepoi_49931.xls
apachepoi_50020.xls
apachepoi_50298.xls
apachepoi_50426.xls
apachepoi_50756.xls
apachepoi_50779_1.xls
apachepoi_50779_2.xls
apachepoi_50833.xls.pending
apachepoi_50939.xls
apachepoi_51143.xls
apachepoi_51461.xls
apachepoi_51498.xls
apachepoi_51535.xls.pending
apachepoi_51670.xls
apachepoi_51675.xls
apachepoi_51832.xls.pending
apachepoi_52527.xls
apachepoi_52575_main.xls
apachepoi_52575_source.xls
apachepoi_53404.xls
apachepoi_53433.xls
apachepoi_53446.xls
apachepoi_53588.xls
apachepoi_53691.xls
apachepoi_53798_shiftNegative_TMPL.xls
apachepoi_53972.xls
apachepoi_53984.xls
apachepoi_54016.xls
apachepoi_54206.xls
apachepoi_54500.xls
apachepoi_54686_fraction_formats.xls
apachepoi_55341_CellStyleBorder.xls
apachepoi_55906-MultiSheetRefs.xls
apachepoi_56325.xls
apachepoi_56450.xls
apachepoi_56482.xls
apachepoi_56563a.xls
apachepoi_56563b.xls
apachepoi_56737.xls
apachepoi_AbnormalSharedFormulaFlag.xls
apachepoi_AreaErrPtg.xls
apachepoi_BOOK_in_capitals.xls
apachepoi_CodeFunctionTestCaseData.xls
apachepoi_ColumnStyle1dp.xls
apachepoi_ColumnStyle1dpColoured.xls
apachepoi_ColumnStyleNone.xls
apachepoi_ComplexFunctionTestCaseData.xls
apachepoi_ContinueRecordProblem.xls
apachepoi_DBCSHeader.xls
apachepoi_DBCSSheetName.xls
apachepoi_DateFormats.xls
apachepoi_DeltaFunctionTestCaseData.xls
apachepoi_DrawingAndComments.xls
apachepoi_DrawingContinue.xls
apachepoi_EmbeddedChartHeaderTest.xls
apachepoi_Employee.xls
apachepoi_ErrPtg.xls
apachepoi_FactDoubleFunctionTestCaseData.xls
apachepoi_ForShifting.xls
apachepoi_FormatChoiceTests.xls
apachepoi_Formatting.xls
apachepoi_FormulaEvalTestData.xls
apachepoi_FormulaRefs.xls
apachepoi_FormulaSheetRange.xls
apachepoi_HyperlinksOnManySheets.xls
apachepoi_IfFormulaTest.xls
apachepoi_ImRealFunctionTestCaseData.xls
apachepoi_ImaginaryFunctionTestCaseData.xls
apachepoi_IndexFunctionTestCaseData.xls
apachepoi_IndirectFunctionTestCaseData.xls
apachepoi_Intersection-52111.xls
apachepoi_IntersectionPtg.xls
apachepoi_IrrNpvTestCaseData.xls
apachepoi_LookupFunctionsTestCaseData.xls
apachepoi_MRExtraLines.xls
apachepoi_MatchFunctionTestCaseData.xls
apachepoi_MissingBits.xls
apachepoi_NoGutsRecords.xls
apachepoi_OddStyleRecord.xls
apachepoi_PercentPtg.xls
apachepoi_QuotientFunctionTestCaseData.xls
apachepoi_RangePtg.xls
apachepoi_ReadOnlyRecommended.xls
apachepoi_ReferencePtg.xls
apachepoi_RepeatingRowsCols.xls
apachepoi_ReptFunctionTestCaseData.xls
apachepoi_RomanFunctionTestCaseData.xls
apachepoi_SampleSS.xls
apachepoi_SharedFormulaTest.xls
apachepoi_SheetWithDrawing.xls
apachepoi_ShrinkToFit.xls
apachepoi_Simple.xls
apachepoi_SimpleChart.xls
apachepoi_SimpleMultiCell.xls
apachepoi_SimpleWithAutofilter.xls
apachepoi_SimpleWithChoose.xls
apachepoi_SimpleWithColours.xls
apachepoi_SimpleWithComments.xls
apachepoi_SimpleWithDataFormat.xls
apachepoi_SimpleWithFormula.xls
apachepoi_SimpleWithImages-mac.xls
apachepoi_SimpleWithImages.xls
apachepoi_SimpleWithPageBreaks.xls
apachepoi_SimpleWithPrintArea.xls
apachepoi_SimpleWithSkip.xls
apachepoi_SimpleWithStyling.xls
apachepoi_SingleLetterRanges.xls
apachepoi_SolverContainerAfterSPGR.xls
apachepoi_SquareMacro.xls
apachepoi_StringContinueRecords.xls
apachepoi_StringFormulas.xls
apachepoi_SubtotalsNested.xls
apachepoi_TestRandBetween.xls
apachepoi_TwoSheetsNoneHidden.xls
apachepoi_TwoSheetsOneHidden.xls
apachepoi_UncalcedRecord.xls
apachepoi_UnionPtg.xls
apachepoi_WORKBOOK_in_capitals.xls
apachepoi_WeekNumFunctionTestCaseData.xls
apachepoi_WeekNumFunctionTestCaseData2013.xls
apachepoi_WithChart.xls
apachepoi_WithCheckBoxes.xls
apachepoi_WithConditionalFormatting.xls
apachepoi_WithEmbeddedObjects.xls
apachepoi_WithExtendedStyles.xls
apachepoi_WithFormattedGraphTitle.xls
apachepoi_WithHyperlink.xls
apachepoi_WithThreeCharts.xls
apachepoi_WithTwoCharts.xls
apachepoi_WithTwoHyperLinks.xls
apachepoi_WrongFormulaRecordType.xls
apachepoi_XRefCalc.xls
apachepoi_XRefCalcData.xls
apachepoi_atp.xls
apachepoi_blankworkbook.xls
apachepoi_bug_42794.xls
apachepoi_colwidth.xls
apachepoi_comments.xls
apachepoi_countblankExamples.xls
apachepoi_countifExamples.xls
apachepoi_dg-text.xls
apachepoi_drawings.xls
apachepoi_duprich1.xls
apachepoi_duprich2.xls
apachepoi_dvEmpty.xls
apachepoi_empty.xls
apachepoi_ex41187-19267.xls
apachepoi_ex42564-21435.xls
apachepoi_ex42564-21503.xls
apachepoi_ex42564-elementOrder.xls
apachepoi_ex42570-20305.xls
apachepoi_ex44921-21902.xls
apachepoi_ex45046-21984.xls
apachepoi_ex45582-22397.xls
apachepoi_ex45672.xls
apachepoi_ex45698-22488.xls.pending
apachepoi_ex45978-extraLinkTableSheets.xls
apachepoi_ex46548-23133.xls
apachepoi_ex47747-sharedFormula.xls
apachepoi_excel_with_embeded.xls
apachepoi_excelant.xls.pending
apachepoi_externalFunctionExample.xls
apachepoi_finance.xls
apachepoi_intercept.xls
apachepoi_mirrTest.xls
apachepoi_missingFuncs44675.xls
apachepoi_mortgage-calculation.xls
apachepoi_multibookFormulaA.xls
apachepoi_multibookFormulaB.xls
apachepoi_namedinput.xls
apachepoi_noHeaderFooter47244.xls
apachepoi_ole2-embedding.xls
apachepoi_overlapSharedFormula.xls
apachepoi_password.xls.pending
apachepoi_rank.xls
apachepoi_rk.xls
apachepoi_shared_formulas.xls
apachepoi_sumifformula.xls
apachepoi_sumifs.xls
apachepoi_templateExcelWithAutofilter.xls
apachepoi_testArraysAndTables.xls
apachepoi_testNames.xls
apachepoi_testRRaC.xls
apachepoi_testRVA.xls
apachepoi_text.xls
apachepoi_unicodeNameRecord.xls
apachepoi_xor-encryption-abc.xls.pending
apachepoi_yearfracExamples.xls
calendar_stress_test.xls.pending
cell_style_simple.xls
comments_stress_test.xls
custom_properties.xls
defined_names_simple.xls
formula_stress_test.xls
formulae_test_simple.xls
hyperlink_stress_test_2011.xls
jxls-core_array.xls
jxls-core_beandata.xls
jxls-core_beanwithlist.xls
jxls-core_doubleForEachOneRow.xls
jxls-core_dynamicColumns.xls
jxls-core_employeeNotes.xls
jxls-core_expressions1.xls
jxls-core_fixedsizelist.xls
jxls-core_forOneRow.xls
jxls-core_forOneRowMerge.xls
jxls-core_forOneRowMerge2.xls
jxls-core_forgroup.xls
jxls-core_foriftag2.xls
jxls-core_foriftag3.xls
jxls-core_foriftag3OutTag.xls
jxls-core_foriftagHor.xls
jxls-core_foriftagOneRow.xls
jxls-core_foriftagOneRow2.xls
jxls-core_foriftagmerge.xls
jxls-core_formatterbean.xls
jxls-core_formula3.xls
jxls-core_formula4.xls
jxls-core_formulas.xls
jxls-core_formulas2.xls
jxls-core_grouping1.xls
jxls-core_grouping2.xls
jxls-core_grouping3.xls
jxls-core_grouping4.xls
jxls-core_groupingformulas.xls
jxls-core_grouptag.xls
jxls-core_hidesheets.xls
jxls-core_iftag.xls
jxls-core_iftagempty.xls
jxls-core_jexl.xls
jxls-core_mergecellslist.xls
jxls-core_mergemultiplelistrows.xls
jxls-core_multi-tab-template.xls
jxls-core_multipleSheetList.xls
jxls-core_multiplelistrows.xls
jxls-core_outline.xls
jxls-core_outtaginonerow.xls
jxls-core_paralleltables.xls
jxls-core_poiobjects.xls
jxls-core_repeatedFormula.xls
jxls-core_report.xls
jxls-core_reportTimestamp.xls
jxls-core_select.xls
jxls-core_select2.xls
jxls-core_severallistsinrow.xls
jxls-core_severalpropertiesincell.xls
jxls-core_simplebean.xls
jxls-core_sqltagreport.xls
jxls-core_stress.xls
jxls-core_syntaxerror.xls
jxls-core_twoIfTagsIn1Row.xls
jxls-core_varstatus.xls
jxls-examples_adjacentlists.xls
jxls-examples_basictags.xls
jxls-examples_chart.xls
jxls-examples_colouring.xls
jxls-examples_department.xls
jxls-examples_dynamicolumns.xls
jxls-examples_employees.xls
jxls-examples_ex_temp.xls
jxls-examples_grouping.xls
jxls-examples_multiplelistrows.xls
jxls-examples_report.xls
jxls-examples_rowstyle.xls
jxls-examples_stress1.xls
jxls-examples_stress2.xls
jxls-reader_departmentData.xls
jxls-reader_employeesData.xls
jxls-reader_emptyrowdata.xls
jxls-reader_error1.xls
jxls-reader_formulasData.xls
jxls-reader_ids.xls
jxls-src_adjacentlist_output.xls
jxls-src_adjacentlists.xls
jxls-src_basictags.xls
jxls-src_basictags_output.xls
jxls-src_chart.xls
jxls-src_chart_output.xls
jxls-src_colouring.xls
jxls-src_colouring_output.xls
jxls-src_department.xls
jxls-src_department_output.xls
jxls-src_departmentdata.xls
jxls-src_dynamiccolumns_output.xls
jxls-src_dynamiccolumns_template.xls
jxls-src_employees.xls
jxls-src_employees_output.xls
jxls-src_grouping.xls
jxls-src_grouping_output.xls
jxls-src_hiddencolumn_output.xls
jxls-src_multiplelistrows.xls
jxls-src_multiplelistrows_output.xls
jxls-src_report.xls
jxls-src_report_output.xls
jxls-src_rowstyle.xls
jxls-src_rowstyle_output.xls
large_strings.xls.pending
libreoffice_calc_cell-value-validation.xls
libreoffice_calc_chart-percent-stacked-with-line-chart.xls
libreoffice_calc_chart-update-invisible-cells.xls
libreoffice_calc_chart_complex-category-column-graph-repeating-values.xls
libreoffice_calc_chart_complex-category-column-graph.xls
libreoffice_calc_cjk-text_cell-justify-distributed-single.xls
libreoffice_calc_cjk-text_cell-justify-distributed.xls
libreoffice_calc_conditional-formatting.xls
libreoffice_calc_csv-import_malformed-quotes.xls.pending
libreoffice_calc_data-pilot_field-cell-format.xls
libreoffice_calc_data-pilot_getpivotdata-cell-function.xls
libreoffice_calc_data-pilot_named-range-as-data-source.xls
libreoffice_calc_data-pilot_simple-range-as-data-source.xls
libreoffice_calc_data-pilot_unlimited-data-fields.xls
libreoffice_calc_dbf_numeric-field-with-zero.xls
libreoffice_calc_drawing-object_connector-arrows.xls
libreoffice_calc_drawing-object_rectangle-over-sized-rows-columns.xls
libreoffice_calc_drawing-object_round-rectangle.xls
libreoffice_calc_drawing-object_shapes.xls
libreoffice_calc_equation-single.xls
libreoffice_calc_external-ref_access-basic-range-func.xls
libreoffice_calc_external-ref_access-basic-single-cell.xls
libreoffice_calc_external-ref_access-basic-single-func.xls
libreoffice_calc_external-ref_access-basic.xls
libreoffice_calc_external-ref_circular-link-doc1.xls
libreoffice_calc_external-ref_circular-link-doc2.xls
libreoffice_calc_external-ref_extdata.xls
libreoffice_calc_external-ref_range-name-extdata.xls
libreoffice_calc_external-ref_range-name.xls
libreoffice_calc_function_linest-excel.xls
libreoffice_calc_function_logest-excel.xls
libreoffice_calc_function_matrix_inline-array-single.xls
libreoffice_calc_function_matrix_inline-arrays-softmaker.xls
libreoffice_calc_function_matrix_inline-arrays.xls
libreoffice_calc_function_n.xls
libreoffice_calc_function_phonetic-richtext.xls
libreoffice_calc_function_phonetic-single.xls
libreoffice_calc_function_phonetic.xls
libreoffice_calc_function_trend-growth-excel.xls
libreoffice_calc_import-wrapped-text.xls
libreoffice_calc_named-range_sheet-local.xls
libreoffice_calc_outline_col-outline-nested.xls
libreoffice_calc_outline_col-outline-single-left-button.xls
libreoffice_calc_outline_col-outline-single.xls
libreoffice_calc_outline_row-outline-nested.xls
libreoffice_calc_outline_row-outline-single-top-button.xls
libreoffice_calc_outline_row-outline-single.xls
libreoffice_calc_print-layout_arial-10-1p.xls
libreoffice_calc_print-layout_arial-10-2p.xls
libreoffice_calc_print-layout_arial-11-1p.xls
libreoffice_calc_print-layout_arial-11-2p.xls
libreoffice_calc_print-layout_arial-12-1p.xls
libreoffice_calc_print-layout_arial-8-1p.xls
libreoffice_calc_print-layout_arial-9-1p.xls
libreoffice_calc_string-number.xls
libreoffice_calc_subtotals_two-on-one-sheet.xls
libreoffice_calc_tab-color.xls
libreoffice_calc_text-angled-with-border.xls
libreoffice_calc_xls-import_300-worksheets.xls
libreoffice_calc_xls-import_autofilter-range.xls
libreoffice_calc_xls-import_cell-border-thickness.xls
libreoffice_calc_xls-import_encryption_export-conditional-formatting.xls.pending
libreoffice_calc_xls-import_paste-link_link.xls
libreoffice_calc_xls-import_paste-link_src.xls
libreoffice_calc_xls-import_pivot-cache-has-source.xls
libreoffice_calc_xls-import_pivot-cache-no-source.xls
libreoffice_calc_xls-import_pivot-dup-data-fields.xls
libreoffice_calc_xls-import_pivot-layout-field-non-default.xls
libreoffice_calc_xls-import_row-attributes_row-all-hidden.xls
libreoffice_calc_xls-import_row-attributes_row-filtered.xls
libreoffice_calc_xls-import_row-attributes_row-heights.xls
libreoffice_calc_xls-import_row-attributes_row-tail-hidden-2.xls
libreoffice_calc_xls-import_row-attributes_row-tail-hidden-last-row-visible.xls
libreoffice_calc_xls-import_row-attributes_row-tail-hidden.xls
libreoffice_calc_xls-import_row-attributes_row-top-bottom-hidden.xls
libreoffice_calc_xls-import_shared-formula_1.xls
libreoffice_calc_xls-import_shared-formulas-simple.xls
merge_cells.xls
named_ranges_2011.xls
number_format.xls
number_format_entities.xls
number_format_russian.xls
numfmt_1_russian.xls
phonetic_text.xls
phpexcel_bad_cfb_dir.xls
pivot_table_named_range.xls
pivot_table_test.xls
pyExcelerator_P-0508-0000507647-3280-5298.xls
pyExcelerator_chart1v8.xls
pyExcelerator_excel2003.xls
pyExcelerator_frmla.xls
pyExcelerator_macro2v8.xls
pyExcelerator_mini-mini.xls
pyExcelerator_mini.xls
pyExcelerator_oo14.xls
rich_text_stress.xls
roo_1900_base.xls
roo_1904_base.xls
roo_Bibelbund.xls
roo_bad_excel_date.xls
roo_bbu.xls
roo_boolean.xls
roo_borders.xls
roo_bug-row-column-fixnum-float.xls
roo_comments.xls
roo_datetime.xls
roo_datetime_floatconv.xls
roo_emptysheets.xls
roo_false_encoding.xls
roo_formula.xls
roo_formula_parse_error.xls
roo_link.xls
roo_matrix.xls
roo_named_cells.xls
roo_numbers1.xls
roo_only_one_sheet.xls
roo_paragraph.xls
roo_prova.xls
roo_simple_spreadsheet.xls
roo_simple_spreadsheet_from_italo.xls
roo_style.xls
roo_time-test.xls
roo_type_excelx.xls.pending
roo_type_openoffice.xls.pending
roo_whitespace.xls
smart_tags_2007.xls
sushi.xls
text_and_numbers.xls
write.xls
xlrd_Formate.xls
xlrd_formula_test_names.xls
xlrd_formula_test_sjmachin.xls
xlrd_issue20.xls
xlrd_picture_in_cell.xls
xlrd_profiles.xls
xlrd_ragged.xls
xlrd_xf_class.xls
xlsx-stream-d-date-cell.xls
AutoFilter.xml
BlankSheetTypes.xml
ErrorTypes.xml
LONumbers-2010.xls.xml
LONumbers-2010.xlsx.xml
LONumbers-2011.xls.xml
LONumbers-2011.xlsx.xml
LONumbers.xls.xml
NumberFormatCondition.xml
RkNumber.xls.xml
RkNumber.xlsb.xml
RkNumber.xlsx.xml
calendar_stress_test.xml.pending
cell_style_simple.xml
comments_stress_test.xls.xml
comments_stress_test.xlsb.xml
comments_stress_test.xlsx.xml
custom_properties.xls.xml
custom_properties.xlsb.xml
custom_properties.xlsx.xml
defined_names_simple.xml
formula_stress_test.xls.xml
formula_stress_test.xlsb.xml
formula_stress_test.xlsx.xml
formulae_test_simple.xml
hyperlink_stress_test_2011.xml
interview.xlsx.xml
issue.xlsx.xml
large_strings.xls.xml
large_strings.xlsb.xml
large_strings.xlsx.xml
merge_cells.xls.xml
merge_cells.xlsb.xml
merge_cells.xlsx.xml
mixed_sheets.xlsx.xml
named_ranges_2011.xls.xml
named_ranges_2011.xlsb.xml
named_ranges_2011.xlsx.xml
number_format.xls.xml
number_format.xlsb.xml
number_format.xlsm.xml
number_format_entities.xml
number_format_russian.xml
numfmt_1_russian.xml
oo34xml_cell_pattern.xml
oo34xml_cellstyle.xml
oo34xml_conditionalformat.xml
oo34xml_dataformat.xml
oo34xml_dataformat2.xml
oo34xml_datarange.xml
oo34xml_font.xml
oo34xml_formula.xml
oo34xml_headerfooter.xml
oo34xml_merge.xml
oo34xml_pagebreak.xml
oo34xml_pagesheet.xml
oo34xml_rowcolumn.xml
oo34xml_solvsamp.xml
phonetic_text.xml
pivot_table_named_range.xml
protect_stress_test_xml.xml
rich_text_stress.xls.xml
rich_text_stress.xlsb.xml
rich_text_stress.xlsx.xml
roo_Bibelbund.xml
roo_bbu.xml
roo_boolean.xml
roo_borders.xml
roo_bug-row-column-fixnum-float.xml
roo_datetime.xml
roo_datetime_floatconv.xml
roo_emptysheets.xml
roo_excel2003.xml
roo_false_encoding.xml
roo_formula.xml
roo_formula_parse_error.xml
roo_numbers1.xml
roo_only_one_sheet.xml
roo_paragraph.xml
roo_simple_spreadsheet.xml
roo_simple_spreadsheet_from_italo.xml
roo_style.xml
roo_time-test.xml
roo_whitespace.xml
smart_tags_2007.xml
sushi.xml
text_and_numbers.xml
xlsx-stream-d-date-cell.xls.xml
xlsx-stream-d-date-cell.xlsb.xml
xlsx-stream-d-date-cell.xlsx.xml
2011/apachepoi_53568.xlsx.xls
2011/apachepoi_WithChartSheet.xlsx.xml
2011/apachepoi_picture.xlsx.xml
2011/apachepoi_styles.xlsx.xml
2011/openpyxl_r_conditional-formatting.xlsx.xls
2011/roo_file_item_error.xlsx.xml

6393
xlsx.js

File diff suppressed because one or more lines are too long

@ -1,4 +1,4 @@
/* xlsx.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/* xlsx.js (C) 2013-2015 SheetJS -- http://sheetjs.com */
/* uncomment the next line for encoding support */
//importScripts('dist/cpexcel.js');
importScripts('jszip.js');

@ -1,4 +1,4 @@
/* xlsx.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/* xlsx.js (C) 2013-2015 SheetJS -- http://sheetjs.com */
/* uncomment the next line for encoding support */
//importScripts('dist/cpexcel.js');
importScripts('jszip.js');

@ -1,4 +1,4 @@
/* xlsx.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
/* xlsx.js (C) 2013-2015 SheetJS -- http://sheetjs.com */
/* uncomment the next line for encoding support */
//importScripts('dist/cpexcel.js');
importScripts('jszip.js');