forked from sheetjs/sheetjs
version bump 0.8.0: unification with js-xls 0.7.5
This commit is contained in:
parent
61b17e6d9d
commit
0d38d4c0a0
13
.gitignore
vendored
13
.gitignore
vendored
@ -3,6 +3,19 @@ misc/coverage.html
|
||||
misc/prof.js
|
||||
v8.log
|
||||
tmp
|
||||
*.txt
|
||||
*.csv
|
||||
*.dif
|
||||
*.prn
|
||||
*.slk
|
||||
*.socialcalc
|
||||
*.xls
|
||||
*.xlsb
|
||||
*.xlsm
|
||||
*.xlsx
|
||||
*.xlsm
|
||||
*.xlsb
|
||||
*.xml
|
||||
*.htm
|
||||
*.html
|
||||
*.sheetjs
|
||||
|
4
.jshintrc
Normal file
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,6 +1,7 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "0.11"
|
||||
- "iojs"
|
||||
- "0.11.14"
|
||||
- "0.10"
|
||||
- "0.8"
|
||||
before_install:
|
||||
|
@ -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.
|
||||
|
2
LICENSE
2
LICENSE
@ -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.
|
||||
|
8
Makefile
8
Makefile
@ -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)
|
||||
@ -88,8 +91,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)
|
||||
|
92
README.md
92
README.md
@ -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
|
||||
|
||||
@ -430,7 +471,7 @@ The exported `write` and `writeFile` functions accept an options argument:
|
||||
|
||||
## 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
|
||||
@ -449,7 +490,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`):
|
||||
|
||||
@ -481,10 +522,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
|
||||
@ -506,7 +543,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
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
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
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
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
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
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
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); }
|
||||
|
||||
|