version bump 0.8.2: ODS and cleanup
- README and example cleanup - basic XLSB and ODS write support - flow typecheck for ODS file Note: xlsx.js flow fails: https://github.com/facebook/flow/issues/380 - exposed jszip compression (fixes #220, closes #284) README issues: | id | author | comment | |-----:|:---------------|:---------------------------------------------| | #202 | @sao93859 | closes #202 | | #211 | @alexanderchan | closes #211 corrected examples | | #327 | @cskaandorp | changed saveAs example to match write tests | | #424 | @dskrvk | added note about s2roa h/t @LeonardoPatignio | | #496 | @jimmywarting | closes #496 adapted rABS examples with rAAS | ODS file format issues: | id | author | comment | |-----:|:---------------|:---------------------------------------------| | #148 | @user4815162342| closes #148 h/t @ziacik | | #166 | @paulproteus | closes #166 rudimentary ODS write support | | #177 | @ziacik | closes #177 | | #179 | @ziacik | closes #179 use JSON when available | | #317 | @ziacik | closes #317 | | #328 | @think01 | closes #328 | | #383 | @mdamt | closes #383 duplicate cells should be copied | | #430 | @RB-Lab | closes #430 | | #546 | @lgodard | closes #546 thanks to other changes |
This commit is contained in:
parent
2a756fffcc
commit
86d6a093f0
17
.flowconfig
17
.flowconfig
|
@ -11,8 +11,21 @@
|
|||
.*/demo/browser.js
|
||||
.*/shim.js
|
||||
|
||||
.*/odsbits/.*
|
||||
.*/ods.js
|
||||
.*/xlsx.js
|
||||
.*/xlsxworker.js
|
||||
.*/xlsxworker1.js
|
||||
.*/xlsxworker2.js
|
||||
.*/jszip.js
|
||||
.*/tests/.*
|
||||
|
||||
.*/xlsx.flow.js
|
||||
[include]
|
||||
xlsx.js
|
||||
xlsxworker.flow.js
|
||||
xlsxworker1.flow.js
|
||||
xlsxworker2.flow.js
|
||||
ods.flow.js
|
||||
.*/bin/.*.njs
|
||||
.*/demo/browser.flow.js
|
||||
|
||||
|
@ -23,4 +36,4 @@ misc/flowdeps.js
|
|||
[options]
|
||||
module.file_ext=.js
|
||||
module.file_ext=.njs
|
||||
|
||||
module.ignore_non_literal_requires=true
|
||||
|
|
|
@ -13,8 +13,7 @@ tmp
|
|||
*.xlsb
|
||||
*.xlsm
|
||||
*.xlsx
|
||||
*.xlsm
|
||||
*.xlsb
|
||||
*.ods
|
||||
*.xml
|
||||
*.htm
|
||||
*.html
|
||||
|
|
|
@ -14,6 +14,7 @@ tmp
|
|||
*.xlsb
|
||||
*.xlsm
|
||||
*.xlsx
|
||||
*.ods
|
||||
*.xml
|
||||
*.htm
|
||||
*.html
|
||||
|
|
|
@ -5,7 +5,9 @@ node_js:
|
|||
- "5"
|
||||
- "4.2"
|
||||
- "0.12"
|
||||
- "0.11"
|
||||
- "0.10"
|
||||
- "0.9"
|
||||
- "0.8"
|
||||
before_install:
|
||||
- "npm install -g npm@next"
|
||||
|
|
17
Makefile
17
Makefile
|
@ -11,13 +11,19 @@ ULIB=$(shell echo $(LIB) | tr a-z A-Z)
|
|||
DEPS=$(sort $(wildcard bits/*.js))
|
||||
TARGET=$(LIB).js
|
||||
FLOWTARGET=$(LIB).flow.js
|
||||
FLOWAUX=$(patsubst %.js,%.flow.js,$(AUXTARGETS))
|
||||
AUXSCPTS=xlsxworker1.js xlsxworker2.js xlsxworker.js
|
||||
FLOWTGTS=$(TARGET) $(AUXTARGETS) $(AUXSCPTS)
|
||||
|
||||
## Main Targets
|
||||
|
||||
.PHONY: all
|
||||
all: $(TARGET) $(AUXTARGETS) ## Build library and auxiliary scripts
|
||||
all: $(TARGET) $(AUXTARGETS) $(AUXSCPTS) ## Build library and auxiliary scripts
|
||||
|
||||
$(TARGET): $(DEPS)
|
||||
$(FLOWTGTS): %.js : %.flow.js
|
||||
node -e 'process.stdout.write(require("fs").readFileSync("$<","utf8").replace(/^[ \t]*\/\*[:#][^*]*\*\/\s*(\n)?/gm,"").replace(/\/\*[:#][^*]*\*\//gm,""))' > $@
|
||||
|
||||
$(FLOWTARGET): $(DEPS)
|
||||
cat $^ | tr -d '\15\32' > $@
|
||||
|
||||
bits/01_version.js: package.json
|
||||
|
@ -58,6 +64,8 @@ dist-deps: ods.js ## Copy dependencies for distribution
|
|||
cp node_modules/codepage/dist/cpexcel.full.js dist/cpexcel.js
|
||||
cp jszip.js dist/jszip.js
|
||||
cp ods.js dist/ods.js
|
||||
uglifyjs ods.js -o dist/ods.min.js --source-map dist/ods.min.map --preamble "$$(head -n 1 bits/00_header.js)"
|
||||
misc/strip_sourcemap.sh dist/ods.min.js
|
||||
|
||||
bower.json: misc/_bower.json package.json
|
||||
cat $< | sed 's/_VERSION_/'`grep version package.json | awk '{gsub(/[^0-9a-z\.-]/,"",$$2); print $$2}'`'/' > $@
|
||||
|
@ -69,9 +77,8 @@ aux: $(AUXTARGETS)
|
|||
ods: ods.js
|
||||
|
||||
ODSDEPS=$(sort $(wildcard odsbits/*.js))
|
||||
ods.js: $(ODSDEPS) ## Build ODS support library
|
||||
ods.flow.js: $(ODSDEPS) ## Build ODS support library
|
||||
cat $(ODSDEPS) | tr -d '\15\32' > $@
|
||||
cp ods.js dist/ods.js
|
||||
|
||||
|
||||
## Testing
|
||||
|
@ -90,7 +97,7 @@ $(TESTFMT): test_%:
|
|||
## Code Checking
|
||||
|
||||
.PHONY: lint
|
||||
lint: $(TARGET) ## Run jshint and jscs checks
|
||||
lint: $(TARGET) $(AUXTARGETS) ## Run jshint and jscs checks
|
||||
@jshint --show-non-errors $(TARGET) $(AUXTARGETS)
|
||||
@jshint --show-non-errors $(CMDS)
|
||||
@jshint --show-non-errors package.json bower.json
|
||||
|
|
93
README.md
93
README.md
|
@ -14,14 +14,18 @@ Supported read formats:
|
|||
|
||||
Supported write formats:
|
||||
|
||||
- XLSX
|
||||
- Excel 2007+ XML Formats (XLSX/XLSM)
|
||||
- Excel 2007+ Binary Format (XLSB) nodejs only
|
||||
- CSV (and general DSV)
|
||||
- JSON and JS objects (various styles)
|
||||
- OpenDocument Spreadsheet (ODS)
|
||||
|
||||
Demo: <http://oss.sheetjs.com/js-xlsx>
|
||||
|
||||
Source: <http://git.io/xlsx>
|
||||
|
||||
Paid support available through the [reinforcements program](http://sheetjs.com/reinforcements)
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://www.npmjs.org/package/xlsx):
|
||||
|
@ -53,7 +57,7 @@ circumstances, so they do not ship with the core. For browser use, they must
|
|||
be included directly:
|
||||
|
||||
```html
|
||||
<!-- international support from https://github.com/sheetjs/js-codepage -->
|
||||
<!-- international support from js-codepage -->
|
||||
<script src="dist/cpexcel.js"></script>
|
||||
<!-- ODS support -->
|
||||
<script src="dist/ods.js"></script>
|
||||
|
@ -116,45 +120,75 @@ oReq.onload = function(e) {
|
|||
oReq.send();
|
||||
```
|
||||
|
||||
- HTML5 drag-and-drop using readAsBinaryString:
|
||||
- HTML5 drag-and-drop using readAsBinaryString or readAsArrayBuffer:
|
||||
note: readAsBinaryString and readAsArrayBuffer may not be available in every
|
||||
browser. Use dynamic feature tests to determine which method to use.
|
||||
|
||||
```js
|
||||
/* processing array buffers, only required for readAsArrayBuffer */
|
||||
function fixdata(data) {
|
||||
var o = "", l = 0, w = 10240;
|
||||
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint8Array(data.slice(l*w,l*w+w)));
|
||||
o+=String.fromCharCode.apply(null, new Uint8Array(data.slice(l*w)));
|
||||
return o;
|
||||
}
|
||||
|
||||
var rABS = true; // true: readAsBinaryString ; false: readAsArrayBuffer
|
||||
/* set up drag-and-drop event */
|
||||
function handleDrop(e) {
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
var files = e.dataTransfer.files;
|
||||
var i,f;
|
||||
for (i = 0, f = files[i]; i != files.length; ++i) {
|
||||
for (i = 0; i != files.length; ++i) {
|
||||
f = files[i];
|
||||
var reader = new FileReader();
|
||||
var name = f.name;
|
||||
reader.onload = function(e) {
|
||||
var data = e.target.result;
|
||||
|
||||
/* if binary string, read with type 'binary' */
|
||||
var workbook = XLSX.read(data, {type: 'binary'});
|
||||
var workbook;
|
||||
if(rABS) {
|
||||
/* if binary string, read with type 'binary' */
|
||||
workbook = XLSX.read(data, {type: 'binary'});
|
||||
} else {
|
||||
/* if array buffer, convert to base64 */
|
||||
var arr = fixdata(data);
|
||||
workbook = XLSX.read(btoa(arr), {type: 'base64'});
|
||||
}
|
||||
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
};
|
||||
reader.readAsBinaryString(f);
|
||||
if(rABS) reader.readAsBinaryString(f);
|
||||
else reader.readAsArrayBuffer(f);
|
||||
}
|
||||
}
|
||||
drop_dom_element.addEventListener('drop', handleDrop, false);
|
||||
```
|
||||
|
||||
- HTML5 input file element using readAsBinaryString:
|
||||
- HTML5 input file element using readAsBinaryString or readAsArrayBuffer:
|
||||
|
||||
```js
|
||||
/* fixdata and rABS are defined in the drag and drop example */
|
||||
function handleFile(e) {
|
||||
var files = e.target.files;
|
||||
var i,f;
|
||||
for (i = 0, f = files[i]; i != files.length; ++i) {
|
||||
for (i = 0; i != files.length; ++i) {
|
||||
f = files[i];
|
||||
var reader = new FileReader();
|
||||
var name = f.name;
|
||||
reader.onload = function(e) {
|
||||
var data = e.target.result;
|
||||
|
||||
var workbook = XLSX.read(data, {type: 'binary'});
|
||||
var workbook;
|
||||
if(rABS) {
|
||||
/* if binary string, read with type 'binary' */
|
||||
workbook = XLSX.read(data, {type: 'binary'});
|
||||
} else {
|
||||
/* if array buffer, convert to base64 */
|
||||
var arr = fixdata(data);
|
||||
workbook = XLSX.read(btoa(arr), {type: 'base64'});
|
||||
}
|
||||
|
||||
/* DO SOMETHING WITH workbook HERE */
|
||||
};
|
||||
|
@ -164,6 +198,11 @@ function handleFile(e) {
|
|||
input_dom_element.addEventListener('change', handleFile, false);
|
||||
```
|
||||
|
||||
The readAsArrayBuffer form requires some preprocessing:
|
||||
|
||||
```js
|
||||
```
|
||||
|
||||
## Working with the Workbook
|
||||
|
||||
The full object format is described later in this README.
|
||||
|
@ -254,7 +293,7 @@ function s2ab(s) {
|
|||
}
|
||||
|
||||
/* the saveAs call downloads a file on the local machine */
|
||||
saveAs(new Blob([s2ab(wbout)],{type:""}), "test.xlsx")
|
||||
saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "test.xlsx");
|
||||
```
|
||||
|
||||
Complete examples:
|
||||
|
@ -290,8 +329,11 @@ Utilities are available in the `XLSX.utils` object:
|
|||
Exporting:
|
||||
|
||||
- `sheet_to_json` converts a workbook object to an array of JSON objects.
|
||||
- `sheet_to_csv` generates delimiter-separated-values output
|
||||
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks)
|
||||
`sheet_to_row_object_array` is an alias that will be removed in the future.
|
||||
- `sheet_to_csv` generates delimiter-separated-values output.
|
||||
- `sheet_to_formulae` generates a list of the formulae (with value fallbacks).
|
||||
|
||||
The `sheet_to_*` functions accept a worksheet and an optional options object.
|
||||
|
||||
Cell and cell address manipulation:
|
||||
|
||||
|
@ -371,7 +413,7 @@ Type `d` is the Date type, generated only when the option `cellDates` is passed.
|
|||
Since JSON does not have a natural Date type, parsers are generally expected to
|
||||
store ISO 8601 Date strings like you would get from `date.toISOString()`. On
|
||||
the other hand, writers and exporters should be able to handle date strings and
|
||||
JS Date objects. Note that Excel disregards the timezone modifier and treats all
|
||||
JS Date objects. Note that Excel disregards timezone modifiers and treats all
|
||||
dates in the local timezone. js-xlsx does not correct for this error.
|
||||
|
||||
Type `s` is the String type. `v` should be explicitly stored as a string to
|
||||
|
@ -395,7 +437,7 @@ Special worksheet keys (accessible as `worksheet[key]`, each starting with `!`):
|
|||
Functions that handle worksheets should test for the presence of `!ref` field.
|
||||
If the `!ref` is omitted or is not a valid range, functions are free to treat
|
||||
the sheet as empty or attempt to guess the range. The standard utilities that
|
||||
ship with this library treat sheets as empty (for example, the CSV output is an
|
||||
ship with this library treat sheets as empty (for example, the CSV output is
|
||||
empty string).
|
||||
|
||||
When reading a worksheet with the `sheetRows` property set, the ref parameter
|
||||
|
@ -468,9 +510,10 @@ The exported `write` and `writeFile` functions accept an options argument:
|
|||
|
||||
| Option Name | Default | Description |
|
||||
| :---------- | ------: | :--------------------------------------------------- |
|
||||
| cellDates | false | Store dates as type `d` (default is `n`) |
|
||||
| bookSST | false | Generate Shared String Table ** |
|
||||
| cellDates | `false` | Store dates as type `d` (default is `n`) |
|
||||
| bookSST | `false` | Generate Shared String Table ** |
|
||||
| bookType | 'xlsx' | Type of Workbook ("xlsx" or "xlsm" or "xlsb") |
|
||||
| compression | `false` | Use file compression for formats with ZIP containers |
|
||||
|
||||
- `bookSST` is slower and more memory intensive, but has better compatibility
|
||||
with older versions of iOS Numbers
|
||||
|
@ -483,7 +526,7 @@ The exported `write` and `writeFile` functions accept an options argument:
|
|||
|
||||
## Tested Environments
|
||||
|
||||
- NodeJS 0.8, 0.10 (latest release), 0.11.14 (unstable), io.js
|
||||
- NodeJS 0.8, 0.9, 0.10, 0.11, 0.12, 4.x, 5.x, 6.x, 7.x
|
||||
- IE 6/7/8/9/10/11 using Base64 mode (IE10/11 using HTML5 mode)
|
||||
- FF 18 using Base64 or HTML5 mode
|
||||
- Chrome 24 using Base64 or HTML5 mode
|
||||
|
@ -491,8 +534,8 @@ The exported `write` and `writeFile` functions accept an options argument:
|
|||
Tests utilize the mocha testing framework. Travis-CI and Sauce Labs links:
|
||||
|
||||
- <https://travis-ci.org/SheetJS/js-xlsx> for XLSX module in nodejs
|
||||
- <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS* modules
|
||||
- <https://saucelabs.com/u/sheetjs> for XLS* modules using Sauce Labs
|
||||
- <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS\* modules
|
||||
- <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs
|
||||
|
||||
## Test Files
|
||||
|
||||
|
@ -537,7 +580,7 @@ version release and should not be committed between versions.
|
|||
## License
|
||||
|
||||
Please consult the attached LICENSE file for details. All rights not explicitly
|
||||
granted by the Apache 2.0 license are reserved by the Original Author.
|
||||
granted by the Apache 2.0 License are reserved by the Original Author.
|
||||
|
||||
It is the opinion of the Original Author that this code conforms to the terms of
|
||||
the Microsoft Open Specifications Promise, falling under the same terms as
|
||||
|
@ -573,10 +616,16 @@ Open Document Format for Office Applications Version 1.2 (29 September 2011)
|
|||
|
||||
## Badges
|
||||
|
||||
[![Build Status](https://saucelabs.com/browser-matrix/xlsx.svg)](https://saucelabs.com/u/xlsx)
|
||||
|
||||
[![Build Status](https://travis-ci.org/SheetJS/js-xlsx.svg?branch=master)](https://travis-ci.org/SheetJS/js-xlsx)
|
||||
|
||||
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/js-xlsx/master.svg)](https://coveralls.io/r/SheetJS/js-xlsx?branch=master)
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
[![NPM Downloads](https://img.shields.io/npm/dt/xlsx.svg)](https://npmjs.org/package/xlsx)
|
||||
|
||||
[![Dependencies Status](https://david-dm.org/sheetjs/js-xlsx/status.svg)](https://david-dm.org/sheetjs/js-xlsx)
|
||||
|
||||
[![ghit.me](https://ghit.me/badge.svg?repo=sheetjs/js-xlsx)](https://ghit.me/repo/sheetjs/js-xlsx)
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)
|
||||
|
|
17
bin/xlsx.njs
17
bin/xlsx.njs
|
@ -48,7 +48,7 @@ if(process.version === 'v0.10.31') {
|
|||
process.exit(1);
|
||||
}
|
||||
|
||||
var filename, sheetname = '';
|
||||
var filename/*:?string*/, sheetname = '';
|
||||
if(program.args[0]) {
|
||||
filename = program.args[0];
|
||||
if(program.args[1]) sheetname = program.args[1];
|
||||
|
@ -60,13 +60,13 @@ if(!filename) {
|
|||
console.error(n + ": must specify a filename");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
/*:: if(filename) { */
|
||||
if(!fs.existsSync(filename)) {
|
||||
console.error(n + ": " + filename + ": No such file or directory");
|
||||
process.exit(2);
|
||||
}
|
||||
|
||||
var opts = {}, wb;
|
||||
var opts = {}, wb/*:?Workbook*/;
|
||||
if(program.listSheets) opts.bookSheets = true;
|
||||
if(program.sheetRows) opts.sheetRows = program.sheetRows;
|
||||
if(program.password) opts.password = program.password;
|
||||
|
@ -98,6 +98,7 @@ else try {
|
|||
}
|
||||
if(program.read) process.exit(0);
|
||||
|
||||
/*:: if(wb) { */
|
||||
if(program.listSheets) {
|
||||
console.log(wb.SheetNames.join("\n"));
|
||||
process.exit(0);
|
||||
|
@ -105,9 +106,9 @@ if(program.listSheets) {
|
|||
|
||||
var wopts = {WTF:opts.WTF, bookSST:program.sst};
|
||||
|
||||
if(program.xlsx) return X.writeFile(wb, sheetname || (filename + ".xlsx"), wopts);
|
||||
if(program.xlsm) return X.writeFile(wb, sheetname || (filename + ".xlsm"), wopts);
|
||||
if(program.xlsb) return X.writeFile(wb, sheetname || (filename + ".xlsb"), wopts);
|
||||
if(program.xlsx) { X.writeFile(wb, sheetname || (filename + ".xlsx"), wopts); process.exit(0); }
|
||||
if(program.xlsm) { X.writeFile(wb, sheetname || (filename + ".xlsm"), wopts); process.exit(0); }
|
||||
if(program.xlsb) { X.writeFile(wb, sheetname || (filename + ".xlsb"), wopts); process.exit(0); }
|
||||
|
||||
var target_sheet = sheetname || '';
|
||||
if(target_sheet === '') target_sheet = wb.SheetNames[0];
|
||||
|
@ -121,7 +122,7 @@ try {
|
|||
process.exit(4);
|
||||
}
|
||||
|
||||
if(program.perf) return;
|
||||
if(program.perf) process.exit(0);
|
||||
|
||||
var oo = "";
|
||||
if(!program.quiet) console.error(target_sheet);
|
||||
|
@ -132,3 +133,5 @@ else oo = X.utils.make_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
|
|||
|
||||
if(program.output) fs.writeFileSync(program.output, oo);
|
||||
else console.log(oo);
|
||||
/*:: } */
|
||||
/*:: } */
|
||||
|
|
|
@ -1 +1 @@
|
|||
XLSX.version = '0.8.1';
|
||||
XLSX.version = '0.8.2';
|
||||
|
|
|
@ -0,0 +1,8 @@
|
|||
/*::
|
||||
declare type Block = any;
|
||||
declare type BufArray = {
|
||||
next(sz:number):Block;
|
||||
end():any;
|
||||
push(buf:Block):void;
|
||||
};
|
||||
*/
|
|
@ -1,4 +1,4 @@
|
|||
function isval(x) { return x !== undefined && x !== null; }
|
||||
function isval(x/*:?any*/)/*:boolean*/ { return x !== undefined && x !== null; }
|
||||
|
||||
function keys(o) { return Object.keys(o); }
|
||||
|
||||
|
@ -36,7 +36,7 @@ function datenum(v, date1904) {
|
|||
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
function cc2str(arr) {
|
||||
function cc2str(arr/*:Array<number>*/)/*:string*/ {
|
||||
var o = "";
|
||||
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
|
||||
return o;
|
||||
|
|
|
@ -26,12 +26,13 @@ function getzipfile(zip, file) {
|
|||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
function getzipdata(zip, file, safe/*:?boolean*/) {
|
||||
if(!safe) return getdata(getzipfile(zip, file));
|
||||
if(!file) return null;
|
||||
try { return getzipdata(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
/*:: declare var JSZip:any; */
|
||||
var _fs, jszip;
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
|
|
|
@ -132,7 +132,8 @@ function WriteShift(t, val, f) {
|
|||
size = 2 * val.length;
|
||||
} else switch(t) {
|
||||
case 1: size = 1; this[this.l] = val&255; break;
|
||||
case 3: size = 3; this[this.l+2] = val & 255; val >>>= 8; this[this.l+1] = val&255; val >>>= 8; this[this.l] = val&255; break;
|
||||
case 2: size = 2; this[this.l] = val&255; val >>>= 8; this[this.l+1] = val&255; break;
|
||||
case 3: size = 3; this[this.l] = val&255; val >>>= 8; this[this.l+1] = val&255; val >>>= 8; this[this.l+2] = val&255; break;
|
||||
case 4: size = 4; this.writeUInt32LE(val, this.l); break;
|
||||
case 8: size = 8; if(f === 'f') { this.writeDoubleLE(val, this.l); break; }
|
||||
/* falls through */
|
||||
|
@ -148,16 +149,16 @@ function CheckField(hexstr, fld) {
|
|||
this.l += hexstr.length>>1;
|
||||
}
|
||||
|
||||
function prep_blob(blob, pos) {
|
||||
function prep_blob(blob, pos/*:number*/) {
|
||||
blob.l = pos;
|
||||
blob.read_shift = ReadShift;
|
||||
blob.chk = CheckField;
|
||||
blob.write_shift = WriteShift;
|
||||
}
|
||||
|
||||
function parsenoop(blob, length) { blob.l += length; }
|
||||
function parsenoop(blob, length/*:number*/) { blob.l += length; }
|
||||
|
||||
function writenoop(blob, length) { blob.l += length; }
|
||||
function writenoop(blob, length/*:number*/) { blob.l += length; }
|
||||
|
||||
function new_buf(sz) {
|
||||
var o = new_raw_buf(sz);
|
||||
|
|
|
@ -26,7 +26,7 @@ function buf_array() {
|
|||
var curbuf = newblk(blksz);
|
||||
|
||||
var endbuf = function ba_endbuf() {
|
||||
curbuf.length = curbuf.l;
|
||||
if(curbuf.length > curbuf.l) curbuf = curbuf.slice(0, curbuf.l);
|
||||
if(curbuf.length > 0) bufs.push(curbuf);
|
||||
curbuf = null;
|
||||
};
|
||||
|
@ -47,7 +47,7 @@ function buf_array() {
|
|||
return { next:next, push:push, end:end, _bufs:bufs };
|
||||
}
|
||||
|
||||
function write_record(ba, type, payload, length) {
|
||||
function write_record(ba/*:BufArray*/, type/*:string*/, payload, length/*:?number*/) {
|
||||
var t = evert_RE[type], l;
|
||||
if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
|
||||
l = 1 + (t >= 0x80 ? 1 : 0) + 1 + length;
|
||||
|
@ -62,5 +62,5 @@ function write_record(ba, type, payload, length) {
|
|||
if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
|
||||
else { o.write_shift(1, length); break; }
|
||||
}
|
||||
if(length > 0 && is_buf(payload)) ba.push(payload);
|
||||
if(/*:: length != null &&*/length > 0 && is_buf(payload)) ba.push(payload);
|
||||
}
|
||||
|
|
|
@ -91,6 +91,15 @@ function parse_RkNumber(data) {
|
|||
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;
|
||||
}
|
||||
function write_RkNumber(data/*:number*/, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
var fX100 = 0, fInt = 0, d100 = data * 100;
|
||||
if(data == (data | 0) && data >= -(1<<29) && data < (1 << 29)) { fInt = 1; }
|
||||
else if(d100 == (d100 | 0) && d100 >= -(1<<29) && d100 < (1 << 29)) { fInt = 1; fX100 = 1; }
|
||||
if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
|
||||
else throw new Error("unsupported RkNumber " + data); // TODO
|
||||
}
|
||||
|
||||
|
||||
/* [MS-XLSB] 2.5.153 */
|
||||
function parse_UncheckedRfX(data) {
|
||||
|
@ -113,8 +122,9 @@ function write_UncheckedRfX(r, o) {
|
|||
|
||||
/* [MS-XLSB] 2.5.171 */
|
||||
/* [MS-XLS] 2.5.342 */
|
||||
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
|
||||
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); }
|
||||
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
|
||||
|
||||
/* [MS-XLSB] 2.5.198.2 */
|
||||
var BErr = {
|
||||
|
|
|
@ -40,7 +40,7 @@ function parse_cust_props(data, opts) {
|
|||
p[name] = unescapexml(text);
|
||||
break;
|
||||
default:
|
||||
if(typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
|
||||
if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
|
||||
}
|
||||
} else if(x.substr(0,2) === "</") {
|
||||
} else if(opts.WTF) throw new Error(x);
|
||||
|
|
|
@ -24,7 +24,7 @@ function parse_ws_xml(data, opts, rels) {
|
|||
var mergecells = [];
|
||||
if(data.indexOf("</mergeCells>")!==-1) {
|
||||
var merges = data.match(mergecregex);
|
||||
for(ridx = 0; ridx != merges.length; ++ridx)
|
||||
if(merges) for(ridx = 0; ridx != merges.length; ++ridx)
|
||||
mergecells[ridx] = safe_decode_range(merges[ridx].substr(merges[ridx].indexOf("\"")+1));
|
||||
}
|
||||
|
||||
|
@ -36,7 +36,7 @@ function parse_ws_xml(data, opts, rels) {
|
|||
parse_ws_xml_cols(columns, cols);
|
||||
}
|
||||
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
/* 18.3.1.80 sheetData CT_SheetData ? */
|
||||
var mtch=data.match(sheetdataregex);
|
||||
|
@ -282,7 +282,7 @@ var WS_XML_ROOT = writextag('worksheet', null, {
|
|||
'xmlns:r': XMLNS.r
|
||||
});
|
||||
|
||||
function write_ws_xml(idx, opts, wb) {
|
||||
function write_ws_xml(idx/*:number*/, opts, wb)/*:string*/ {
|
||||
var o = [XML_HEADER, WS_XML_ROOT];
|
||||
var s = wb.SheetNames[idx], sidx = 0, rdata = "";
|
||||
var ws = wb.Sheets[s];
|
||||
|
|
105
bits/68_wsbin.js
105
bits/68_wsbin.js
|
@ -6,6 +6,45 @@ function parse_BrtRowHdr(data, length) {
|
|||
data.l += length-4;
|
||||
return z;
|
||||
}
|
||||
function write_BrtRowHdr(R/*:number*/, range, ws) {
|
||||
var o = new_buf(17+8*16);
|
||||
o.write_shift(4, R);
|
||||
|
||||
/* TODO: flags styles */
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(2, 0x0140);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(1, 0);
|
||||
|
||||
/* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
|
||||
var ncolspan = 0, lcs = o.l;
|
||||
o.l += 4;
|
||||
|
||||
var caddr = {r:R, c:0};
|
||||
for(var i = 0; i < 16; ++i) {
|
||||
if(range.s.c > ((i+1) << 10) || range.e.c < (i << 10)) continue;
|
||||
var first = -1, last = -1;
|
||||
for(var j = (i<<10); j < ((i+1)<<10); ++j) {
|
||||
caddr.c = j;
|
||||
if(ws[encode_cell(caddr)]) { if(first < 0) first = j; last = j; }
|
||||
}
|
||||
if(first < 0) continue;
|
||||
++ncolspan;
|
||||
o.write_shift(4, first);
|
||||
o.write_shift(4, last);
|
||||
}
|
||||
|
||||
var l = o.l;
|
||||
o.l = lcs;
|
||||
o.write_shift(4, ncolspan);
|
||||
o.l = l;
|
||||
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
function write_row_header(ba, ws, range, R) {
|
||||
var o = write_BrtRowHdr(R, range, ws);
|
||||
if(o.length > 17) write_record(ba, 'BrtRowHdr', o);
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.812 BrtWsDim */
|
||||
var parse_BrtWsDim = parse_UncheckedRfX;
|
||||
|
@ -25,9 +64,9 @@ function parse_BrtCellBlank(data, length) {
|
|||
var cell = parse_XLSBCell(data);
|
||||
return [cell];
|
||||
}
|
||||
function write_BrtCellBlank(cell, val, o) {
|
||||
function write_BrtCellBlank(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(8);
|
||||
return write_XLSBCell(val, o);
|
||||
return write_XLSBCell(ncell, o);
|
||||
}
|
||||
|
||||
|
||||
|
@ -37,12 +76,18 @@ function parse_BrtCellBool(data, length) {
|
|||
var fBool = data.read_shift(1);
|
||||
return [cell, fBool, 'b'];
|
||||
}
|
||||
function write_BrtCellBool(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(9);
|
||||
write_XLSBCell(ncell, o);
|
||||
o.write_shift(1, cell.v ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.305 BrtCellError */
|
||||
function parse_BrtCellError(data, length) {
|
||||
var cell = parse_XLSBCell(data);
|
||||
var fBool = data.read_shift(1);
|
||||
return [cell, fBool, 'e'];
|
||||
var bError = data.read_shift(1);
|
||||
return [cell, bError, 'e'];
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.308 BrtCellIsst */
|
||||
|
@ -51,6 +96,12 @@ function parse_BrtCellIsst(data, length) {
|
|||
var isst = data.read_shift(4);
|
||||
return [cell, isst, 's'];
|
||||
}
|
||||
function write_BrtCellIsst(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12);
|
||||
write_XLSBCell(ncell, o);
|
||||
o.write_shift(4, ncell.v);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.310 BrtCellReal */
|
||||
function parse_BrtCellReal(data, length) {
|
||||
|
@ -58,6 +109,12 @@ function parse_BrtCellReal(data, length) {
|
|||
var value = parse_Xnum(data);
|
||||
return [cell, value, 'n'];
|
||||
}
|
||||
function write_BrtCellReal(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(16);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_Xnum(cell.v, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.311 BrtCellRk */
|
||||
function parse_BrtCellRk(data, length) {
|
||||
|
@ -65,6 +122,13 @@ function parse_BrtCellRk(data, length) {
|
|||
var value = parse_RkNumber(data);
|
||||
return [cell, value, 'n'];
|
||||
}
|
||||
function write_BrtCellRk(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_RkNumber(cell.v, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* [MS-XLSB] 2.4.314 BrtCellSt */
|
||||
function parse_BrtCellSt(data, length) {
|
||||
|
@ -72,6 +136,12 @@ function parse_BrtCellSt(data, length) {
|
|||
var value = parse_XLWideString(data);
|
||||
return [cell, value, 'str'];
|
||||
}
|
||||
function write_BrtCellSt(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12 + 4 * cell.v.length);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_XLWideString(cell.v, o);
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
|
||||
function parse_BrtFmlaBool(data, length, opts) {
|
||||
|
@ -147,12 +217,13 @@ function parse_ws_bin(data, opts, rels) {
|
|||
var s = {};
|
||||
|
||||
var ref;
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
var pass = false, end = false;
|
||||
var row, p, cf, R, C, addr, sstr, rr;
|
||||
var mergecells = [];
|
||||
recordhopper(data, function ws_parse(val, R) {
|
||||
//console.log(R);
|
||||
if(end) return;
|
||||
switch(R.n) {
|
||||
case 'BrtWsDim': ref = val; break;
|
||||
|
@ -329,7 +400,7 @@ function parse_ws_bin(data, opts, rels) {
|
|||
default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n);
|
||||
}
|
||||
}, opts);
|
||||
if(!s["!ref"] && (refguess.s.r < 1000000 || ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0)) s["!ref"] = encode_range(ref);
|
||||
if(!s["!ref"] && (refguess.s.r < 2000000 || ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0)) s["!ref"] = encode_range(ref);
|
||||
if(opts.sheetRows && s["!ref"]) {
|
||||
var tmpref = safe_decode_range(s["!ref"]);
|
||||
if(opts.sheetRows < +tmpref.e.r) {
|
||||
|
@ -362,12 +433,23 @@ function write_ws_bin_cell(ba, cell, R, C, opts) {
|
|||
case 's': case 'str':
|
||||
if(opts.bookSST) {
|
||||
vv = get_sst_id(opts.Strings, cell.v);
|
||||
o.t = "s"; break;
|
||||
o.t = "s"; o.v = vv;
|
||||
write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
|
||||
} else {
|
||||
o.t = "str";
|
||||
write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
|
||||
}
|
||||
o.t = "str"; break;
|
||||
case 'n': break;
|
||||
case 'b': o.t = "b"; break;
|
||||
case 'e': o.t = "e"; break;
|
||||
return;
|
||||
case 'n':
|
||||
/* TODO: determine threshold for Real vs RK */
|
||||
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
|
||||
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
|
||||
return;
|
||||
case 'b':
|
||||
o.t = "b";
|
||||
write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
|
||||
return;
|
||||
case 'e': /* TODO: error */ o.t = "e"; break;
|
||||
}
|
||||
write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
|
||||
}
|
||||
|
@ -379,6 +461,7 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
|||
rr = encode_row(R);
|
||||
/* [ACCELLTABLE] */
|
||||
/* BrtRowHdr */
|
||||
write_row_header(ba, ws, range, R);
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
/* *16384CELL */
|
||||
if(R === range.s.r) cols[C] = encode_col(C);
|
||||
|
|
|
@ -13,7 +13,7 @@ function write_BrtBundleSh(data, o) {
|
|||
o.write_shift(4, data.iTabID);
|
||||
write_RelID(data.strRelID, o);
|
||||
write_XLWideString(data.name.substr(0,31), o);
|
||||
return o;
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.807 BrtWbProp */
|
||||
|
@ -121,7 +121,7 @@ function write_BrtFileVersion(data, o) {
|
|||
write_XLWideString(XLSX.version, o);
|
||||
write_XLWideString("7262", o);
|
||||
o.length = o.l;
|
||||
return o;
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.60 Workbook */
|
||||
|
@ -144,6 +144,7 @@ function write_BrtCalcProp(data, o) {
|
|||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.640 BrtFileRecover */
|
||||
function write_BrtFileRecover(data, o) {
|
||||
if(!o) o = new_buf(1);
|
||||
o.write_shift(1,0);
|
||||
|
@ -156,22 +157,22 @@ function write_wb_bin(wb, opts) {
|
|||
write_record(ba, "BrtBeginBook");
|
||||
write_record(ba, "BrtFileVersion", write_BrtFileVersion());
|
||||
/* [[BrtFileSharingIso] BrtFileSharing] */
|
||||
write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
if(0) write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
/* [ACABSPATH] */
|
||||
/* [[BrtBookProtectionIso] BrtBookProtection] */
|
||||
write_BOOKVIEWS(ba, wb, opts);
|
||||
if(0) write_BOOKVIEWS(ba, wb, opts);
|
||||
write_BUNDLESHS(ba, wb, opts);
|
||||
/* [FNGROUP] */
|
||||
/* [EXTERNALS] */
|
||||
/* *BrtName */
|
||||
write_record(ba, "BrtCalcProp", write_BrtCalcProp());
|
||||
if(0) write_record(ba, "BrtCalcProp", write_BrtCalcProp());
|
||||
/* [BrtOleSize] */
|
||||
/* *(BrtUserBookView *FRT) */
|
||||
/* [PIVOTCACHEIDS] */
|
||||
/* [BrtWbFactoid] */
|
||||
/* [SMARTTAGTYPES] */
|
||||
/* [BrtWebOpt] */
|
||||
write_record(ba, "BrtFileRecover", write_BrtFileRecover());
|
||||
if(0) write_record(ba, "BrtFileRecover", write_BrtFileRecover());
|
||||
/* [WEBPUBITEMS] */
|
||||
/* [CRERRS] */
|
||||
/* FRTWORKBOOK */
|
||||
|
|
|
@ -147,7 +147,7 @@ function parse_xlml_xml(d, opts) {
|
|||
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 refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
var styles = {}, stag = {};
|
||||
var ss = "", fidx = 0;
|
||||
var mergecells = [];
|
||||
|
@ -207,7 +207,7 @@ function parse_xlml_xml(d, opts) {
|
|||
if(mergecells.length) cursheet["!merges"] = mergecells;
|
||||
sheets[sheetname] = cursheet;
|
||||
} else {
|
||||
refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
r = c = 0;
|
||||
state.push([Rn[3], false]);
|
||||
tmp = xlml_parsexmltag(Rn[0]);
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
/* Helper functions to call out to ODS */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
||||
function write_ods(wb, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.write_ods(wb, opts);
|
||||
}
|
|
@ -1,6 +0,0 @@
|
|||
/* Helper function to call out to ODS parser */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
|
@ -36,5 +36,7 @@ var fix_write_opts = fix_opts_func([
|
|||
|
||||
['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
|
||||
|
||||
['compression', false], /* Use file compression */
|
||||
|
||||
['WTF', false] /* WTF mode (throws errors) */
|
||||
]);
|
||||
|
|
|
@ -10,6 +10,7 @@ function add_rels(rels, rId, f, type, relobj) {
|
|||
}
|
||||
|
||||
function write_zip(wb, opts) {
|
||||
if(opts.bookType == "ods") return write_ods(wb, opts);
|
||||
if(wb && !wb.SSF) {
|
||||
wb.SSF = SSF.get_table();
|
||||
}
|
||||
|
|
|
@ -1,13 +1,17 @@
|
|||
function write_zip_type(wb, opts) {
|
||||
var o = opts||{};
|
||||
var z = write_zip(wb, o);
|
||||
var oopts = {};
|
||||
if(opts.compression) oopts.compression = 'DEFLATE';
|
||||
switch(o.type) {
|
||||
case "base64": return z.generate({type:"base64"});
|
||||
case "binary": return z.generate({type:"string"});
|
||||
case "buffer": return z.generate({type:"nodebuffer"});
|
||||
case "file": return _fs.writeFileSync(o.file, z.generate({type:"nodebuffer"}));
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "buffer":
|
||||
case "file": oopts.type = "nodebuffer"; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(o.type === "file") return _fs.writeFileSync(o.file, z.generate(oopts));
|
||||
return z.generate(oopts);
|
||||
}
|
||||
|
||||
function writeSync(wb, opts) {
|
||||
|
@ -21,13 +25,14 @@ function writeSync(wb, opts) {
|
|||
function writeFileSync(wb, filename, opts) {
|
||||
var o = opts||{}; o.type = 'file';
|
||||
o.file = filename;
|
||||
switch(o.file.substr(-5).toLowerCase()) {
|
||||
if(!o.bookType) 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;
|
||||
case '.ods': o.bookType = 'ods'; break;
|
||||
}}
|
||||
return writeSync(wb, o);
|
||||
}
|
||||
|
|
|
@ -2,7 +2,7 @@
|
|||
"name": "js-xlsx",
|
||||
"homepage": "https://github.com/SheetJS/js-xlsx",
|
||||
"main": "dist/xlsx.js",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"ignore": [
|
||||
"bin",
|
||||
"bits",
|
||||
|
|
|
@ -21,6 +21,14 @@ function cc2str(arr) {
|
|||
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
|
||||
return o;
|
||||
}
|
||||
|
||||
function dup(o) {
|
||||
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
|
||||
if(typeof o != 'object' || !o) return o;
|
||||
var out = {};
|
||||
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
|
||||
return out;
|
||||
}
|
||||
function getdata(data) {
|
||||
if(!data) return null;
|
||||
if(data.data) return data.data;
|
||||
|
@ -67,7 +75,7 @@ function parsexmltag(tag, skip_root) {
|
|||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
|
||||
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
|
@ -108,7 +116,7 @@ function escapexml(text){
|
|||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value, tag) {
|
||||
function parsexmlbool(value) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
|
@ -147,6 +155,8 @@ function parse_isodur(s) {
|
|||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
|
||||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
|
@ -157,14 +167,14 @@ function xlml_normalize(d) {
|
|||
var xlmlregex = /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/mg;
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
var parse_manifest = function(d, opts) {
|
||||
function parse_manifest(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0]);
|
||||
FEtag = parsexmltag(Rn[0], false);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
|
@ -172,11 +182,46 @@ var parse_manifest = function(d, opts) {
|
|||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: throw Rn;
|
||||
default: if(opts && opts.WTF) throw Rn;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function write_manifest(manifest, opts) {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
|
||||
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
|
||||
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
|
||||
o.push('</manifest:manifest>');
|
||||
return o.join("");
|
||||
}
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
function write_rdf_type(file, res, tag) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + file + '">\n',
|
||||
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf_has(base, file) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + base + '">\n',
|
||||
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf(rdf, opts) {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
|
||||
for(var i = 0; i != rdf.length; ++i) {
|
||||
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
|
||||
o.push(write_rdf_has("",rdf[i][0]));
|
||||
}
|
||||
o.push(write_rdf_type("","Document", "pkg"));
|
||||
o.push('</rdf:RDF>');
|
||||
return o.join("");
|
||||
}
|
||||
var parse_text_p = function(text, tag) {
|
||||
return utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
|
||||
return unescapexml(utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,"")));
|
||||
};
|
||||
|
||||
var utf8read = function utf8reada(orig) {
|
||||
|
@ -213,27 +258,29 @@ var parse_content_xml = (function() {
|
|||
var str = xlml_normalize(d);
|
||||
var state = [], tmp;
|
||||
var tag;
|
||||
var NFtag, NF, pidx;
|
||||
var NFtag = {name:""}, NF = "", pidx = 0;
|
||||
var sheetag;
|
||||
var Sheets = {}, SheetNames = [], ws = {};
|
||||
var Rn, q;
|
||||
var ctag;
|
||||
var textp, textpidx, textptag;
|
||||
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var ctag = {value:""};
|
||||
var textp = "", textpidx = 0, textptag;
|
||||
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
var merges = [], mrange = {}, mR = 0, mC = 0;
|
||||
|
||||
var rept = 1;
|
||||
xlmlregex.lastIndex = 0;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
if(merges.length) ws['!merges'] = merges;
|
||||
sheetag.name = utf8read(sheetag.name);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0]);
|
||||
sheetag = parsexmltag(Rn[0], false);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {}; merges = [];
|
||||
|
@ -247,17 +294,18 @@ var parse_content_xml = (function() {
|
|||
++C; break; /* stub */
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') {
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
|
||||
else ++C;
|
||||
}
|
||||
else if(Rn[1]!=='/') {
|
||||
++C;
|
||||
rept = 1;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
q = {t:ctag['value-type'], v:null};
|
||||
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
|
||||
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
|
||||
|
@ -265,6 +313,10 @@ var parse_content_xml = (function() {
|
|||
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
|
||||
merges.push(mrange);
|
||||
}
|
||||
|
||||
/* 19.675.2 table:number-columns-repeated */
|
||||
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
|
||||
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
|
@ -273,14 +325,22 @@ var parse_content_xml = (function() {
|
|||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'string': q.t = 's'; break;
|
||||
default: throw new Error('Unsupported value type ' + q.t);
|
||||
default:
|
||||
if(q.t === 'string' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 's') q.v = textp;
|
||||
if(q.t === 's') q.v = textp || '';
|
||||
if(textp) q.w = textp;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
q = null;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) {
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
|
||||
if(range.e.c <= C) range.e.c = C;
|
||||
}
|
||||
q = {};
|
||||
textp = "";
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
|
@ -296,6 +356,13 @@ var parse_content_xml = (function() {
|
|||
/* ignore state */
|
||||
case 'shapes': // 9.2.8 <table:shapes>
|
||||
case 'frame': // 10.4.2 <draw:frame>
|
||||
case 'text-box': // 10.4.3 <draw:text-box>
|
||||
case 'image': // 10.4.4 <draw:image>
|
||||
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
|
||||
case 'list-style': // 16.30 <text:list-style>
|
||||
case 'form': // 13.13 <form:form>
|
||||
case 'dde-links': // 9.8 <table:dde-links>
|
||||
case 'annotation': // 14.1 <office:annotation>
|
||||
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], false]);
|
||||
break;
|
||||
|
@ -309,7 +376,7 @@ var parse_content_xml = (function() {
|
|||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0]);
|
||||
NFtag = parsexmltag(Rn[0], false);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
|
@ -317,6 +384,7 @@ var parse_content_xml = (function() {
|
|||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'map': break; // 16.3 <style:map>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
|
@ -329,10 +397,12 @@ var parse_content_xml = (function() {
|
|||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'fraction': break; // TODO 16.27.6 <number:fraction>
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
|
@ -347,7 +417,7 @@ var parse_content_xml = (function() {
|
|||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
|
@ -373,30 +443,114 @@ var parse_content_xml = (function() {
|
|||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'graphic-properties': break;
|
||||
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
|
||||
|
||||
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.11 <table:named-range>
|
||||
case 'named-range': break; // 9.4.12 <table:named-range>
|
||||
case 'named-expression': break; // 9.4.13 <table:named-expression>
|
||||
case 'sort': break; // 9.4.19 <table:sort>
|
||||
case 'sort-by': break; // 9.4.20 <table:sort-by>
|
||||
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
|
||||
|
||||
case 'span': break; // <text:span>
|
||||
case 'line-break': break; // 6.1.5 <text:line-break>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0]); textpidx = Rn.index + Rn[0].length; }
|
||||
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
case 'annotation': break;
|
||||
|
||||
case 'object': break; // 10.4.6.2 <draw:object>
|
||||
case 'title': break; // <*:title>
|
||||
case 'desc': break; // <*:desc>
|
||||
|
||||
case 'table-source': break; // 9.2.6
|
||||
|
||||
case 'iteration': break; // 9.4.3 <table:iteration>
|
||||
case 'content-validations': break; // 9.4.4 <table:
|
||||
case 'content-validation': break; // 9.4.5 <table:
|
||||
case 'error-message': break; // 9.4.7 <table:
|
||||
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
|
||||
case 'database-range': break; // 9.4.15 <table:database-range>
|
||||
case 'filter': break; // 9.5.2 <table:filter>
|
||||
case 'filter-and': break; // 9.5.3 <table:filter-and>
|
||||
case 'filter-or': break; // 9.5.4 <table:filter-or>
|
||||
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
|
||||
default: if(opts.WTF) throw Rn;
|
||||
|
||||
case 'list-level-style-bullet': break; // 16.31 <text:
|
||||
case 'list-level-style-number': break; // 16.32 <text:
|
||||
case 'list-level-properties': break; // 17.19 <style:
|
||||
|
||||
/* 7.3 Document Fields */
|
||||
case 'sender-firstname': // 7.3.6.2
|
||||
case 'sender-lastname': // 7.3.6.3
|
||||
case 'sender-initials': // 7.3.6.4
|
||||
case 'sender-title': // 7.3.6.5
|
||||
case 'sender-position': // 7.3.6.6
|
||||
case 'sender-email': // 7.3.6.7
|
||||
case 'sender-phone-private': // 7.3.6.8
|
||||
case 'sender-fax': // 7.3.6.9
|
||||
case 'sender-company': // 7.3.6.10
|
||||
case 'sender-phone-work': // 7.3.6.11
|
||||
case 'sender-street': // 7.3.6.12
|
||||
case 'sender-city': // 7.3.6.13
|
||||
case 'sender-postal-code': // 7.3.6.14
|
||||
case 'sender-country': // 7.3.6.15
|
||||
case 'sender-state-or-province': // 7.3.6.16
|
||||
case 'author-name': // 7.3.7.1
|
||||
case 'author-initials': // 7.3.7.2
|
||||
case 'chapter': // 7.3.8
|
||||
case 'file-name': // 7.3.9
|
||||
case 'template-name': // 7.3.9
|
||||
case 'sheet-name': // 7.3.9
|
||||
break;
|
||||
|
||||
/* 9.6 Data Pilot Tables <table: */
|
||||
case 'data-pilot-table': // 9.6.3
|
||||
case 'source-cell-range': // 9.6.5
|
||||
case 'source-service': // 9.6.6
|
||||
case 'data-pilot-field': // 9.6.7
|
||||
case 'data-pilot-level': // 9.6.8
|
||||
case 'data-pilot-subtotals': // 9.6.9
|
||||
case 'data-pilot-subtotal': // 9.6.10
|
||||
case 'data-pilot-members': // 9.6.11
|
||||
case 'data-pilot-member': // 9.6.12
|
||||
case 'data-pilot-display-info': // 9.6.13
|
||||
case 'data-pilot-sort-info': // 9.6.14
|
||||
case 'data-pilot-layout-info': // 9.6.15
|
||||
case 'data-pilot-field-reference': // 9.6.16
|
||||
case 'data-pilot-groups': // 9.6.17
|
||||
case 'data-pilot-group': // 9.6.18
|
||||
case 'data-pilot-group-member': // 9.6.19
|
||||
break;
|
||||
|
||||
/* 10.3 Drawing Shapes */
|
||||
case 'rect': // 10.3.2
|
||||
break;
|
||||
|
||||
/* 14.6 DDE Connections */
|
||||
case 'dde-connection-decls': // 14.6.2 <text:
|
||||
case 'dde-connection-decl': // 14.6.3 <text:
|
||||
case 'dde-link': // 14.6.4 <table:
|
||||
case 'dde-source': // 14.6.5 <office:
|
||||
break;
|
||||
|
||||
case 'properties': break; // 13.7 <form:properties>
|
||||
case 'property': break; // 13.8 <form:property>
|
||||
|
||||
case 'a': break; // 6.1.8 hyperlink
|
||||
|
||||
/* non-standard */
|
||||
case 'table-protection': break;
|
||||
case 'data-pilot-grand-total': break; // <table:
|
||||
default:
|
||||
if(Rn[2] === 'dc:') break; // TODO: properties
|
||||
if(Rn[2] === 'draw:') break; // TODO: drawing
|
||||
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
|
||||
if(opts.WTF) throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
|
@ -405,10 +559,81 @@ var parse_content_xml = (function() {
|
|||
return out;
|
||||
};
|
||||
})();
|
||||
var write_content_xml = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var write_ws = function(ws, wb, i, opts) {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
}
|
||||
o.push(' </table:table-row>\n');
|
||||
}
|
||||
o.push(' </table:table>\n');
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
return function wcx(wb, opts) {
|
||||
var o = [XML_HEADER];
|
||||
/* 3.1.3.2 */
|
||||
o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
|
||||
o.push(' <office:body>\n');
|
||||
o.push(' <office:spreadsheet>\n');
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
|
||||
o.push(' </office:spreadsheet>\n');
|
||||
o.push(' </office:body>\n');
|
||||
o.push('</office:document-content>');
|
||||
return o.join("");
|
||||
};
|
||||
})();
|
||||
/* Part 3: Packages */
|
||||
var parse_ods = function(zip, opts) {
|
||||
//var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'));
|
||||
function parse_ods(zip, opts) {
|
||||
opts = opts || ({});
|
||||
var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
|
||||
};
|
||||
}
|
||||
function write_ods(wb, opts) {
|
||||
var zip = new jszip();
|
||||
var f = "";
|
||||
|
||||
var manifest = [];
|
||||
var rdf = [];
|
||||
|
||||
/* 3:3.3 and 2:2.2.4 */
|
||||
f = "mimetype";
|
||||
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
|
||||
|
||||
/* Part 2 Section 2.2 Documents */
|
||||
f = "content.xml";
|
||||
zip.file(f, write_content_xml(wb, opts));
|
||||
manifest.push([f, "text/xml"]);
|
||||
rdf.push([f, "ContentFile"]);
|
||||
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
f = "manifest.rdf";
|
||||
zip.file(f, write_rdf(rdf, opts));
|
||||
manifest.push([f, "application/rdf+xml"]);
|
||||
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
f = "META-INF/manifest.xml";
|
||||
zip.file(f, write_manifest(manifest, opts));
|
||||
|
||||
return zip;
|
||||
}
|
||||
ODS.parse_ods = parse_ods;
|
||||
ODS.write_ods = write_ods;
|
||||
})(typeof exports !== 'undefined' ? exports : ODS);
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -4,7 +4,7 @@
|
|||
/*jshint funcscope:true, eqnull:true */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.8.1';
|
||||
XLSX.version = '0.8.2';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
|
@ -1645,7 +1645,8 @@ function WriteShift(t, val, f) {
|
|||
size = 2 * val.length;
|
||||
} else switch(t) {
|
||||
case 1: size = 1; this[this.l] = val&255; break;
|
||||
case 3: size = 3; this[this.l+2] = val & 255; val >>>= 8; this[this.l+1] = val&255; val >>>= 8; this[this.l] = val&255; break;
|
||||
case 2: size = 2; this[this.l] = val&255; val >>>= 8; this[this.l+1] = val&255; break;
|
||||
case 3: size = 3; this[this.l] = val&255; val >>>= 8; this[this.l+1] = val&255; val >>>= 8; this[this.l+2] = val&255; break;
|
||||
case 4: size = 4; this.writeUInt32LE(val, this.l); break;
|
||||
case 8: size = 8; if(f === 'f') { this.writeDoubleLE(val, this.l); break; }
|
||||
/* falls through */
|
||||
|
@ -1706,7 +1707,7 @@ function buf_array() {
|
|||
var curbuf = newblk(blksz);
|
||||
|
||||
var endbuf = function ba_endbuf() {
|
||||
curbuf.length = curbuf.l;
|
||||
if(curbuf.length > curbuf.l) curbuf = curbuf.slice(0, curbuf.l);
|
||||
if(curbuf.length > 0) bufs.push(curbuf);
|
||||
curbuf = null;
|
||||
};
|
||||
|
@ -1893,6 +1894,15 @@ function parse_RkNumber(data) {
|
|||
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;
|
||||
}
|
||||
function write_RkNumber(data, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
var fX100 = 0, fInt = 0, d100 = data * 100;
|
||||
if(data == (data | 0) && data >= -(1<<29) && data < (1 << 29)) { fInt = 1; }
|
||||
else if(d100 == (d100 | 0) && d100 >= -(1<<29) && d100 < (1 << 29)) { fInt = 1; fX100 = 1; }
|
||||
if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
|
||||
else throw new Error("unsupported RkNumber " + data); // TODO
|
||||
}
|
||||
|
||||
|
||||
/* [MS-XLSB] 2.5.153 */
|
||||
function parse_UncheckedRfX(data) {
|
||||
|
@ -1915,8 +1925,9 @@ function write_UncheckedRfX(r, o) {
|
|||
|
||||
/* [MS-XLSB] 2.5.171 */
|
||||
/* [MS-XLS] 2.5.342 */
|
||||
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
|
||||
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); }
|
||||
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
|
||||
|
||||
/* [MS-XLSB] 2.5.198.2 */
|
||||
var BErr = {
|
||||
|
@ -2730,7 +2741,7 @@ function parse_cust_props(data, opts) {
|
|||
p[name] = unescapexml(text);
|
||||
break;
|
||||
default:
|
||||
if(typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
|
||||
if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
|
||||
}
|
||||
} else if(x.substr(0,2) === "</") {
|
||||
} else if(opts.WTF) throw new Error(x);
|
||||
|
@ -7286,7 +7297,7 @@ function parse_ws_xml(data, opts, rels) {
|
|||
var mergecells = [];
|
||||
if(data.indexOf("</mergeCells>")!==-1) {
|
||||
var merges = data.match(mergecregex);
|
||||
for(ridx = 0; ridx != merges.length; ++ridx)
|
||||
if(merges) for(ridx = 0; ridx != merges.length; ++ridx)
|
||||
mergecells[ridx] = safe_decode_range(merges[ridx].substr(merges[ridx].indexOf("\"")+1));
|
||||
}
|
||||
|
||||
|
@ -7298,7 +7309,7 @@ function parse_ws_xml(data, opts, rels) {
|
|||
parse_ws_xml_cols(columns, cols);
|
||||
}
|
||||
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
/* 18.3.1.80 sheetData CT_SheetData ? */
|
||||
var mtch=data.match(sheetdataregex);
|
||||
|
@ -7573,6 +7584,45 @@ function parse_BrtRowHdr(data, length) {
|
|||
data.l += length-4;
|
||||
return z;
|
||||
}
|
||||
function write_BrtRowHdr(R, range, ws) {
|
||||
var o = new_buf(17+8*16);
|
||||
o.write_shift(4, R);
|
||||
|
||||
/* TODO: flags styles */
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(2, 0x0140);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(1, 0);
|
||||
|
||||
/* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
|
||||
var ncolspan = 0, lcs = o.l;
|
||||
o.l += 4;
|
||||
|
||||
var caddr = {r:R, c:0};
|
||||
for(var i = 0; i < 16; ++i) {
|
||||
if(range.s.c > ((i+1) << 10) || range.e.c < (i << 10)) continue;
|
||||
var first = -1, last = -1;
|
||||
for(var j = (i<<10); j < ((i+1)<<10); ++j) {
|
||||
caddr.c = j;
|
||||
if(ws[encode_cell(caddr)]) { if(first < 0) first = j; last = j; }
|
||||
}
|
||||
if(first < 0) continue;
|
||||
++ncolspan;
|
||||
o.write_shift(4, first);
|
||||
o.write_shift(4, last);
|
||||
}
|
||||
|
||||
var l = o.l;
|
||||
o.l = lcs;
|
||||
o.write_shift(4, ncolspan);
|
||||
o.l = l;
|
||||
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
function write_row_header(ba, ws, range, R) {
|
||||
var o = write_BrtRowHdr(R, range, ws);
|
||||
if(o.length > 17) write_record(ba, 'BrtRowHdr', o);
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.812 BrtWsDim */
|
||||
var parse_BrtWsDim = parse_UncheckedRfX;
|
||||
|
@ -7592,9 +7642,9 @@ function parse_BrtCellBlank(data, length) {
|
|||
var cell = parse_XLSBCell(data);
|
||||
return [cell];
|
||||
}
|
||||
function write_BrtCellBlank(cell, val, o) {
|
||||
function write_BrtCellBlank(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(8);
|
||||
return write_XLSBCell(val, o);
|
||||
return write_XLSBCell(ncell, o);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7604,12 +7654,18 @@ function parse_BrtCellBool(data, length) {
|
|||
var fBool = data.read_shift(1);
|
||||
return [cell, fBool, 'b'];
|
||||
}
|
||||
function write_BrtCellBool(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(9);
|
||||
write_XLSBCell(ncell, o);
|
||||
o.write_shift(1, cell.v ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.305 BrtCellError */
|
||||
function parse_BrtCellError(data, length) {
|
||||
var cell = parse_XLSBCell(data);
|
||||
var fBool = data.read_shift(1);
|
||||
return [cell, fBool, 'e'];
|
||||
var bError = data.read_shift(1);
|
||||
return [cell, bError, 'e'];
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.308 BrtCellIsst */
|
||||
|
@ -7618,6 +7674,12 @@ function parse_BrtCellIsst(data, length) {
|
|||
var isst = data.read_shift(4);
|
||||
return [cell, isst, 's'];
|
||||
}
|
||||
function write_BrtCellIsst(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12);
|
||||
write_XLSBCell(ncell, o);
|
||||
o.write_shift(4, ncell.v);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.310 BrtCellReal */
|
||||
function parse_BrtCellReal(data, length) {
|
||||
|
@ -7625,6 +7687,12 @@ function parse_BrtCellReal(data, length) {
|
|||
var value = parse_Xnum(data);
|
||||
return [cell, value, 'n'];
|
||||
}
|
||||
function write_BrtCellReal(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(16);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_Xnum(cell.v, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.311 BrtCellRk */
|
||||
function parse_BrtCellRk(data, length) {
|
||||
|
@ -7632,6 +7700,13 @@ function parse_BrtCellRk(data, length) {
|
|||
var value = parse_RkNumber(data);
|
||||
return [cell, value, 'n'];
|
||||
}
|
||||
function write_BrtCellRk(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_RkNumber(cell.v, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* [MS-XLSB] 2.4.314 BrtCellSt */
|
||||
function parse_BrtCellSt(data, length) {
|
||||
|
@ -7639,6 +7714,12 @@ function parse_BrtCellSt(data, length) {
|
|||
var value = parse_XLWideString(data);
|
||||
return [cell, value, 'str'];
|
||||
}
|
||||
function write_BrtCellSt(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12 + 4 * cell.v.length);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_XLWideString(cell.v, o);
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
|
||||
function parse_BrtFmlaBool(data, length, opts) {
|
||||
|
@ -7714,12 +7795,13 @@ function parse_ws_bin(data, opts, rels) {
|
|||
var s = {};
|
||||
|
||||
var ref;
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
var pass = false, end = false;
|
||||
var row, p, cf, R, C, addr, sstr, rr;
|
||||
var mergecells = [];
|
||||
recordhopper(data, function ws_parse(val, R) {
|
||||
//console.log(R);
|
||||
if(end) return;
|
||||
switch(R.n) {
|
||||
case 'BrtWsDim': ref = val; break;
|
||||
|
@ -7896,7 +7978,7 @@ function parse_ws_bin(data, opts, rels) {
|
|||
default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n);
|
||||
}
|
||||
}, opts);
|
||||
if(!s["!ref"] && (refguess.s.r < 1000000 || ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0)) s["!ref"] = encode_range(ref);
|
||||
if(!s["!ref"] && (refguess.s.r < 2000000 || ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0)) s["!ref"] = encode_range(ref);
|
||||
if(opts.sheetRows && s["!ref"]) {
|
||||
var tmpref = safe_decode_range(s["!ref"]);
|
||||
if(opts.sheetRows < +tmpref.e.r) {
|
||||
|
@ -7929,12 +8011,23 @@ function write_ws_bin_cell(ba, cell, R, C, opts) {
|
|||
case 's': case 'str':
|
||||
if(opts.bookSST) {
|
||||
vv = get_sst_id(opts.Strings, cell.v);
|
||||
o.t = "s"; break;
|
||||
o.t = "s"; o.v = vv;
|
||||
write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
|
||||
} else {
|
||||
o.t = "str";
|
||||
write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
|
||||
}
|
||||
o.t = "str"; break;
|
||||
case 'n': break;
|
||||
case 'b': o.t = "b"; break;
|
||||
case 'e': o.t = "e"; break;
|
||||
return;
|
||||
case 'n':
|
||||
/* TODO: determine threshold for Real vs RK */
|
||||
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
|
||||
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
|
||||
return;
|
||||
case 'b':
|
||||
o.t = "b";
|
||||
write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
|
||||
return;
|
||||
case 'e': /* TODO: error */ o.t = "e"; break;
|
||||
}
|
||||
write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
|
||||
}
|
||||
|
@ -7946,6 +8039,7 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
|||
rr = encode_row(R);
|
||||
/* [ACCELLTABLE] */
|
||||
/* BrtRowHdr */
|
||||
write_row_header(ba, ws, range, R);
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
/* *16384CELL */
|
||||
if(R === range.s.r) cols[C] = encode_col(C);
|
||||
|
@ -8258,7 +8352,7 @@ function write_BrtBundleSh(data, o) {
|
|||
o.write_shift(4, data.iTabID);
|
||||
write_RelID(data.strRelID, o);
|
||||
write_XLWideString(data.name.substr(0,31), o);
|
||||
return o;
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.807 BrtWbProp */
|
||||
|
@ -8366,7 +8460,7 @@ function write_BrtFileVersion(data, o) {
|
|||
write_XLWideString(XLSX.version, o);
|
||||
write_XLWideString("7262", o);
|
||||
o.length = o.l;
|
||||
return o;
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.60 Workbook */
|
||||
|
@ -8389,6 +8483,7 @@ function write_BrtCalcProp(data, o) {
|
|||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.640 BrtFileRecover */
|
||||
function write_BrtFileRecover(data, o) {
|
||||
if(!o) o = new_buf(1);
|
||||
o.write_shift(1,0);
|
||||
|
@ -8401,22 +8496,22 @@ function write_wb_bin(wb, opts) {
|
|||
write_record(ba, "BrtBeginBook");
|
||||
write_record(ba, "BrtFileVersion", write_BrtFileVersion());
|
||||
/* [[BrtFileSharingIso] BrtFileSharing] */
|
||||
write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
if(0) write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
/* [ACABSPATH] */
|
||||
/* [[BrtBookProtectionIso] BrtBookProtection] */
|
||||
write_BOOKVIEWS(ba, wb, opts);
|
||||
if(0) write_BOOKVIEWS(ba, wb, opts);
|
||||
write_BUNDLESHS(ba, wb, opts);
|
||||
/* [FNGROUP] */
|
||||
/* [EXTERNALS] */
|
||||
/* *BrtName */
|
||||
write_record(ba, "BrtCalcProp", write_BrtCalcProp());
|
||||
if(0) write_record(ba, "BrtCalcProp", write_BrtCalcProp());
|
||||
/* [BrtOleSize] */
|
||||
/* *(BrtUserBookView *FRT) */
|
||||
/* [PIVOTCACHEIDS] */
|
||||
/* [BrtWbFactoid] */
|
||||
/* [SMARTTAGTYPES] */
|
||||
/* [BrtWebOpt] */
|
||||
write_record(ba, "BrtFileRecover", write_BrtFileRecover());
|
||||
if(0) write_record(ba, "BrtFileRecover", write_BrtFileRecover());
|
||||
/* [WEBPUBITEMS] */
|
||||
/* [CRERRS] */
|
||||
/* FRTWORKBOOK */
|
||||
|
@ -8625,7 +8720,7 @@ function parse_xlml_xml(d, opts) {
|
|||
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 refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
var styles = {}, stag = {};
|
||||
var ss = "", fidx = 0;
|
||||
var mergecells = [];
|
||||
|
@ -8685,7 +8780,7 @@ function parse_xlml_xml(d, opts) {
|
|||
if(mergecells.length) cursheet["!merges"] = mergecells;
|
||||
sheets[sheetname] = cursheet;
|
||||
} else {
|
||||
refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
r = c = 0;
|
||||
state.push([Rn[3], false]);
|
||||
tmp = xlml_parsexmltag(Rn[0]);
|
||||
|
@ -11080,12 +11175,17 @@ var XLSRecordEnum = {
|
|||
};
|
||||
|
||||
|
||||
/* Helper function to call out to ODS parser */
|
||||
/* Helper functions to call out to ODS */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
||||
function write_ods(wb, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.write_ods(wb, opts);
|
||||
}
|
||||
function fix_opts_func(defaults) {
|
||||
return function fix_opts(opts) {
|
||||
for(var i = 0; i != defaults.length; ++i) {
|
||||
|
@ -11124,6 +11224,8 @@ var fix_write_opts = fix_opts_func([
|
|||
|
||||
['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
|
||||
|
||||
['compression', false], /* Use file compression */
|
||||
|
||||
['WTF', false] /* WTF mode (throws errors) */
|
||||
]);
|
||||
function safe_parse_wbrels(wbrels, sheets) {
|
||||
|
@ -11278,6 +11380,7 @@ function add_rels(rels, rId, f, type, relobj) {
|
|||
}
|
||||
|
||||
function write_zip(wb, opts) {
|
||||
if(opts.bookType == "ods") return write_ods(wb, opts);
|
||||
if(wb && !wb.SSF) {
|
||||
wb.SSF = SSF.get_table();
|
||||
}
|
||||
|
@ -11405,13 +11508,17 @@ function readFileSync(data, opts) {
|
|||
function write_zip_type(wb, opts) {
|
||||
var o = opts||{};
|
||||
var z = write_zip(wb, o);
|
||||
var oopts = {};
|
||||
if(opts.compression) oopts.compression = 'DEFLATE';
|
||||
switch(o.type) {
|
||||
case "base64": return z.generate({type:"base64"});
|
||||
case "binary": return z.generate({type:"string"});
|
||||
case "buffer": return z.generate({type:"nodebuffer"});
|
||||
case "file": return _fs.writeFileSync(o.file, z.generate({type:"nodebuffer"}));
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "buffer":
|
||||
case "file": oopts.type = "nodebuffer"; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(o.type === "file") return _fs.writeFileSync(o.file, z.generate(oopts));
|
||||
return z.generate(oopts);
|
||||
}
|
||||
|
||||
function writeSync(wb, opts) {
|
||||
|
@ -11425,13 +11532,14 @@ function writeSync(wb, opts) {
|
|||
function writeFileSync(wb, filename, opts) {
|
||||
var o = opts||{}; o.type = 'file';
|
||||
o.file = filename;
|
||||
switch(o.file.substr(-5).toLowerCase()) {
|
||||
if(!o.bookType) 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;
|
||||
case '.ods': o.bookType = 'ods'; break;
|
||||
}}
|
||||
return writeSync(wb, o);
|
||||
}
|
||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
|
@ -21,7 +21,7 @@
|
|||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<b>JS-XLSX (XLSX/XLSB/XLSM/XLS/XML) Live Demo</b><br />
|
||||
<b>JS-XLSX (XLSX/XLSB/XLSM/XLS/XML/ODS) Live Demo</b><br />
|
||||
Output Format:
|
||||
<select name="format">
|
||||
<option value="csv" selected> CSV</option>
|
||||
|
@ -48,7 +48,7 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
|
|||
<script src="jszip.js"></script>
|
||||
<script src="xlsx.js"></script>
|
||||
<!-- uncomment the next line here and in xlsxworker.js for ODS support -->
|
||||
<script src="dist/ods.js"></script>
|
||||
<script src="ods.js"></script>
|
||||
<script>
|
||||
var X = XLSX;
|
||||
var XW = {
|
||||
|
|
|
@ -0,0 +1,12 @@
|
|||
/*::
|
||||
type ZIPFile = any;
|
||||
|
||||
type ParseOpts = any;
|
||||
|
||||
type Workbook = {
|
||||
SheetNames: Array<string>;
|
||||
Sheets: any;
|
||||
};
|
||||
|
||||
type XLSXModule = any;
|
||||
*/
|
|
@ -0,0 +1,8 @@
|
|||
/*::
|
||||
declare module 'exit-on-epipe' {};
|
||||
|
||||
declare module 'xlsx' { declare var exports:XLSXModule; };
|
||||
declare module '../' { declare var exports:XLSXModule; };
|
||||
|
||||
declare module 'commander' { declare var exports:any; };
|
||||
*/
|
|
@ -0,0 +1,642 @@
|
|||
/* ods.js (C) 2014-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*jshint -W041 */
|
||||
var ODS = {};
|
||||
(function make_ods(ODS) {
|
||||
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
|
||||
/*:: declare var XLSX: any; */
|
||||
var get_utils = function() {
|
||||
if(typeof XLSX !== 'undefined') return XLSX.utils;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
|
||||
return require('../' + 'xlsx').utils;
|
||||
} catch(e) {
|
||||
try { return require('./' + 'xlsx').utils; }
|
||||
catch(ee) { return require('xl' + 'sx').utils; }
|
||||
}
|
||||
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 dup(o/*:object*/)/*:object*/ {
|
||||
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
|
||||
if(typeof o != 'object' || !o) return o;
|
||||
var out = {};
|
||||
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
|
||||
return out;
|
||||
}
|
||||
function getdata(data) {
|
||||
if(!data) return null;
|
||||
if(data.data) return data.data;
|
||||
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
|
||||
if(data.asBinary) return data.asBinary();
|
||||
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
|
||||
return null;
|
||||
}
|
||||
|
||||
function safegetzipfile(zip, file) {
|
||||
var f = file; if(zip.files[f]) return zip.files[f];
|
||||
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
|
||||
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
|
||||
return null;
|
||||
}
|
||||
|
||||
function getzipfile(zip, file) {
|
||||
var o = safegetzipfile(zip, file);
|
||||
if(o == null) throw new Error("Cannot find file " + file + " in zip");
|
||||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe/*:?boolean*/) {
|
||||
if(!safe) return getdata(getzipfile(zip, file));
|
||||
if(!file) return null;
|
||||
try { return getzipdata(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
var _fs, jszip;
|
||||
/*:: declare var JSZip:any; */
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
if(has_buf && typeof jszip === 'undefined') jszip = require('js'+'zip');
|
||||
if(typeof jszip === 'undefined') jszip = require('./js'+'zip').JSZip;
|
||||
_fs = require('f'+'s');
|
||||
}
|
||||
}
|
||||
var attregexg=/\b[\w:-]+=["'][^"]*['"]/g;
|
||||
var tagregex=/<[^>]*>/g;
|
||||
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
|
||||
function parsexmltag(tag, skip_root) {
|
||||
var z/*:any*/ = [];
|
||||
var eq = 0, c = 0;
|
||||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
|
||||
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
|
||||
if(j===q.length) z[q] = v;
|
||||
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
|
||||
}
|
||||
return z;
|
||||
}
|
||||
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
|
||||
|
||||
var encodings = {
|
||||
'"': '"',
|
||||
''': "'",
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
var rencoding = {
|
||||
'"': '"',
|
||||
"'": ''',
|
||||
'>': '>',
|
||||
'<': '<',
|
||||
'&': '&'
|
||||
};
|
||||
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 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) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
default: return false;
|
||||
}
|
||||
}
|
||||
|
||||
function datenum(v) {
|
||||
var epoch = Date.parse(v);
|
||||
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
|
||||
/* ISO 8601 Duration */
|
||||
function parse_isodur(s) {
|
||||
var sec = 0, mt = 0, time = false;
|
||||
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
|
||||
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
|
||||
for(var i = 1; i != m.length; ++i) {
|
||||
if(!m[i]) continue;
|
||||
mt = 1;
|
||||
if(i > 3) time = true;
|
||||
switch(m[i].substr(m[i].length-1)) {
|
||||
case 'Y':
|
||||
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
|
||||
case 'D': mt *= 24;
|
||||
/* falls through */
|
||||
case 'H': mt *= 60;
|
||||
/* falls through */
|
||||
case 'M':
|
||||
if(!time) throw new Error("Unsupported ISO Duration Field: M");
|
||||
else mt *= 60;
|
||||
/* falls through */
|
||||
case 'S': break;
|
||||
}
|
||||
sec += mt * parseInt(m[i], 10);
|
||||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
|
||||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
if(typeof d === 'string') return d;
|
||||
throw "badf";
|
||||
}
|
||||
|
||||
var xlmlregex = /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/mg;
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
function parse_manifest(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0], false);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
case 'algorithm': // 4.5 <manifest:algorithm>
|
||||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: if(opts && opts.WTF) throw Rn;
|
||||
}
|
||||
}
|
||||
|
||||
function write_manifest(manifest/*:Array<Array<string> >*/, opts)/*:string*/ {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
|
||||
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
|
||||
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
|
||||
o.push('</manifest:manifest>');
|
||||
return o.join("");
|
||||
}
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + file + '">\n',
|
||||
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf_has(base/*:string*/, file/*:string*/) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + base + '">\n',
|
||||
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf(rdf, opts) {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
|
||||
for(var i = 0; i != rdf.length; ++i) {
|
||||
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
|
||||
o.push(write_rdf_has("",rdf[i][0]));
|
||||
}
|
||||
o.push(write_rdf_type("","Document", "pkg"));
|
||||
o.push('</rdf:RDF>');
|
||||
return o.join("");
|
||||
}
|
||||
var parse_text_p = function(text, tag) {
|
||||
return unescapexml(utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,"")));
|
||||
};
|
||||
|
||||
var utf8read = function utf8reada(orig) {
|
||||
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
|
||||
while (i < orig.length) {
|
||||
c = orig.charCodeAt(i++);
|
||||
if (c < 128) { out += String.fromCharCode(c); continue; }
|
||||
d = orig.charCodeAt(i++);
|
||||
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
|
||||
e = orig.charCodeAt(i++);
|
||||
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
|
||||
f = orig.charCodeAt(i++);
|
||||
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
|
||||
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
|
||||
out += String.fromCharCode(0xDC00 + (w&1023));
|
||||
}
|
||||
return out;
|
||||
};
|
||||
var parse_content_xml = (function() {
|
||||
|
||||
var number_formats = {
|
||||
/* ods name: [short ssf fmt, long ssf fmt] */
|
||||
day: ["d", "dd"],
|
||||
month: ["m", "mm"],
|
||||
year: ["y", "yy"],
|
||||
hours: ["h", "hh"],
|
||||
minutes: ["m", "mm"],
|
||||
seconds: ["s", "ss"],
|
||||
"am-pm": ["A/P", "AM/PM"],
|
||||
"day-of-week": ["ddd", "dddd"]
|
||||
};
|
||||
|
||||
return function pcx(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var state/*:Array<any>*/ = [], tmp;
|
||||
var tag/*:: = {}*/;
|
||||
var NFtag = {name:""}, NF = "", pidx = 0;
|
||||
var sheetag/*:: = {name:""}*/;
|
||||
var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {};
|
||||
var Rn, q/*:: = {t:"", v:null, z:null, w:""}*/;
|
||||
var ctag = {value:""};
|
||||
var textp = "", textpidx = 0, textptag/*:: = {}*/;
|
||||
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
var merges = [], mrange = {}, mR = 0, mC = 0;
|
||||
var rept = 1;
|
||||
xlmlregex.lastIndex = 0;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
if(merges.length) ws['!merges'] = merges;
|
||||
sheetag.name = utf8read(sheetag.name);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0], false);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {}; merges = [];
|
||||
}
|
||||
break;
|
||||
|
||||
case 'table-row': // 9.1.3 <table:table-row>
|
||||
if(Rn[1] === '/') break;
|
||||
++R; C = -1; break;
|
||||
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
|
||||
++C; break; /* stub */
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') {
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
|
||||
else ++C;
|
||||
}
|
||||
else if(Rn[1]!=='/') {
|
||||
++C;
|
||||
rept = 1;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
q = {t:ctag['value-type'], v:null/*:: , z:null, w:""*/};
|
||||
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
|
||||
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
|
||||
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
|
||||
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
|
||||
merges.push(mrange);
|
||||
}
|
||||
|
||||
/* 19.675.2 table:number-columns-repeated */
|
||||
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
|
||||
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
default:
|
||||
if(q.t === 'string' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 's') q.v = textp || '';
|
||||
if(textp) q.w = textp;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) {
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
|
||||
if(range.e.c <= C) range.e.c = C;
|
||||
}
|
||||
q = {/*:: t:"", v:null, z:null, w:""*/};
|
||||
textp = "";
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
/* pure state */
|
||||
case 'document-content': // 3.1.3.2 <office:document-content>
|
||||
case 'spreadsheet': // 3.7 <office:spreadsheet>
|
||||
case 'scripts': // 3.12 <office:scripts>
|
||||
case 'font-face-decls': // 3.14 <office:font-face-decls>
|
||||
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;
|
||||
|
||||
/* ignore state */
|
||||
case 'shapes': // 9.2.8 <table:shapes>
|
||||
case 'frame': // 10.4.2 <draw:frame>
|
||||
case 'text-box': // 10.4.3 <draw:text-box>
|
||||
case 'image': // 10.4.4 <draw:image>
|
||||
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
|
||||
case 'list-style': // 16.30 <text:list-style>
|
||||
case 'form': // 13.13 <form:form>
|
||||
case 'dde-links': // 9.8 <table:dde-links>
|
||||
case 'annotation': // 14.1 <office:annotation>
|
||||
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], false]);
|
||||
break;
|
||||
|
||||
case 'number-style': // 16.27.2 <number:number-style>
|
||||
case 'percentage-style': // 16.27.9 <number:percentage-style>
|
||||
case 'date-style': // 16.27.10 <number:date-style>
|
||||
case 'time-style': // 16.27.18 <number:time-style>
|
||||
if(Rn[1]==='/'){
|
||||
number_format_map[NFtag.name] = NF;
|
||||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0], false);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
case 'script': break; // 3.13 <office:script>
|
||||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'map': break; // 16.3 <style:map>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
case 'table-properties': break; // 17.15 <style:table-properties>
|
||||
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
|
||||
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
|
||||
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
|
||||
|
||||
case 'number': // 16.27.3 <number:number>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'fraction': break; // TODO 16.27.6 <number:fraction>
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
case 'era': // 16.27.14 <number:era>
|
||||
case 'day-of-week': // 16.27.15 <number:day-of-week>
|
||||
case 'week-of-year': // 16.27.16 <number:week-of-year>
|
||||
case 'quarter': // 16.27.17 <number:quarter>
|
||||
case 'hours': // 16.27.19 <number:hours>
|
||||
case 'minutes': // 16.27.20 <number:minutes>
|
||||
case 'seconds': // 16.27.21 <number:seconds>
|
||||
case 'am-pm': // 16.27.22 <number:am-pm>
|
||||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
|
||||
case 'boolean': break; // 16.27.24 <number:boolean>
|
||||
case 'text-style': break; // 16.27.25 <number:text-style>
|
||||
case 'text': // 16.27.26 <number:text>
|
||||
if(Rn[0].substr(-2) === "/>") break;
|
||||
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
|
||||
case 'number-style':
|
||||
case 'date-style':
|
||||
case 'time-style':
|
||||
NF += str.slice(pidx, Rn.index);
|
||||
break;
|
||||
}
|
||||
else pidx = Rn.index + Rn[0].length;
|
||||
break;
|
||||
case 'text-content': break; // 16.27.27 <number:text-content>
|
||||
case 'text-properties': break; // 16.27.27 <style:text-properties>
|
||||
|
||||
case 'body': break; // 3.3 16.9.6 19.726.3
|
||||
|
||||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
|
||||
|
||||
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.12 <table:named-range>
|
||||
case 'named-expression': break; // 9.4.13 <table:named-expression>
|
||||
case 'sort': break; // 9.4.19 <table:sort>
|
||||
case 'sort-by': break; // 9.4.20 <table:sort-by>
|
||||
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
|
||||
|
||||
case 'span': break; // <text:span>
|
||||
case 'line-break': break; // 6.1.5 <text:line-break>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
|
||||
case 'object': break; // 10.4.6.2 <draw:object>
|
||||
case 'title': break; // <*:title>
|
||||
case 'desc': break; // <*:desc>
|
||||
|
||||
case 'table-source': break; // 9.2.6
|
||||
|
||||
case 'iteration': break; // 9.4.3 <table:iteration>
|
||||
case 'content-validations': break; // 9.4.4 <table:
|
||||
case 'content-validation': break; // 9.4.5 <table:
|
||||
case 'error-message': break; // 9.4.7 <table:
|
||||
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
|
||||
case 'database-range': break; // 9.4.15 <table:database-range>
|
||||
case 'filter': break; // 9.5.2 <table:filter>
|
||||
case 'filter-and': break; // 9.5.3 <table:filter-and>
|
||||
case 'filter-or': break; // 9.5.4 <table:filter-or>
|
||||
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
|
||||
|
||||
case 'list-level-style-bullet': break; // 16.31 <text:
|
||||
case 'list-level-style-number': break; // 16.32 <text:
|
||||
case 'list-level-properties': break; // 17.19 <style:
|
||||
|
||||
/* 7.3 Document Fields */
|
||||
case 'sender-firstname': // 7.3.6.2
|
||||
case 'sender-lastname': // 7.3.6.3
|
||||
case 'sender-initials': // 7.3.6.4
|
||||
case 'sender-title': // 7.3.6.5
|
||||
case 'sender-position': // 7.3.6.6
|
||||
case 'sender-email': // 7.3.6.7
|
||||
case 'sender-phone-private': // 7.3.6.8
|
||||
case 'sender-fax': // 7.3.6.9
|
||||
case 'sender-company': // 7.3.6.10
|
||||
case 'sender-phone-work': // 7.3.6.11
|
||||
case 'sender-street': // 7.3.6.12
|
||||
case 'sender-city': // 7.3.6.13
|
||||
case 'sender-postal-code': // 7.3.6.14
|
||||
case 'sender-country': // 7.3.6.15
|
||||
case 'sender-state-or-province': // 7.3.6.16
|
||||
case 'author-name': // 7.3.7.1
|
||||
case 'author-initials': // 7.3.7.2
|
||||
case 'chapter': // 7.3.8
|
||||
case 'file-name': // 7.3.9
|
||||
case 'template-name': // 7.3.9
|
||||
case 'sheet-name': // 7.3.9
|
||||
break;
|
||||
|
||||
/* 9.6 Data Pilot Tables <table: */
|
||||
case 'data-pilot-table': // 9.6.3
|
||||
case 'source-cell-range': // 9.6.5
|
||||
case 'source-service': // 9.6.6
|
||||
case 'data-pilot-field': // 9.6.7
|
||||
case 'data-pilot-level': // 9.6.8
|
||||
case 'data-pilot-subtotals': // 9.6.9
|
||||
case 'data-pilot-subtotal': // 9.6.10
|
||||
case 'data-pilot-members': // 9.6.11
|
||||
case 'data-pilot-member': // 9.6.12
|
||||
case 'data-pilot-display-info': // 9.6.13
|
||||
case 'data-pilot-sort-info': // 9.6.14
|
||||
case 'data-pilot-layout-info': // 9.6.15
|
||||
case 'data-pilot-field-reference': // 9.6.16
|
||||
case 'data-pilot-groups': // 9.6.17
|
||||
case 'data-pilot-group': // 9.6.18
|
||||
case 'data-pilot-group-member': // 9.6.19
|
||||
break;
|
||||
|
||||
/* 10.3 Drawing Shapes */
|
||||
case 'rect': // 10.3.2
|
||||
break;
|
||||
|
||||
/* 14.6 DDE Connections */
|
||||
case 'dde-connection-decls': // 14.6.2 <text:
|
||||
case 'dde-connection-decl': // 14.6.3 <text:
|
||||
case 'dde-link': // 14.6.4 <table:
|
||||
case 'dde-source': // 14.6.5 <office:
|
||||
break;
|
||||
|
||||
case 'properties': break; // 13.7 <form:properties>
|
||||
case 'property': break; // 13.8 <form:property>
|
||||
|
||||
case 'a': break; // 6.1.8 hyperlink
|
||||
|
||||
/* non-standard */
|
||||
case 'table-protection': break;
|
||||
case 'data-pilot-grand-total': break; // <table:
|
||||
default:
|
||||
if(Rn[2] === 'dc:') break; // TODO: properties
|
||||
if(Rn[2] === 'draw:') break; // TODO: drawing
|
||||
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
|
||||
if(opts.WTF) throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
SheetNames: SheetNames
|
||||
};
|
||||
return out;
|
||||
};
|
||||
})();
|
||||
var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
}
|
||||
o.push(' </table:table-row>\n');
|
||||
}
|
||||
o.push(' </table:table>\n');
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
return function wcx(wb, opts) {
|
||||
var o = [XML_HEADER];
|
||||
/* 3.1.3.2 */
|
||||
o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
|
||||
o.push(' <office:body>\n');
|
||||
o.push(' <office:spreadsheet>\n');
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
|
||||
o.push(' </office:spreadsheet>\n');
|
||||
o.push(' </office:body>\n');
|
||||
o.push('</office:document-content>');
|
||||
return o.join("");
|
||||
};
|
||||
})();
|
||||
/* Part 3: Packages */
|
||||
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) {
|
||||
opts = opts || ({}/*:any*/);
|
||||
var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
|
||||
}
|
||||
function write_ods(wb/*:any*/, opts/*:any*/) {
|
||||
/*:: if(!jszip) throw new Error("JSZip is not available"); */
|
||||
var zip = new jszip();
|
||||
var f = "";
|
||||
|
||||
var manifest/*:Array<Array<string> >*/ = [];
|
||||
var rdf = [];
|
||||
|
||||
/* 3:3.3 and 2:2.2.4 */
|
||||
f = "mimetype";
|
||||
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
|
||||
|
||||
/* Part 2 Section 2.2 Documents */
|
||||
f = "content.xml";
|
||||
zip.file(f, write_content_xml(wb, opts));
|
||||
manifest.push([f, "text/xml"]);
|
||||
rdf.push([f, "ContentFile"]);
|
||||
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
f = "manifest.rdf";
|
||||
zip.file(f, write_rdf(rdf, opts));
|
||||
manifest.push([f, "application/rdf+xml"]);
|
||||
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
f = "META-INF/manifest.xml";
|
||||
zip.file(f, write_manifest(manifest, opts));
|
||||
|
||||
return zip;
|
||||
}
|
||||
ODS.parse_ods = parse_ods;
|
||||
ODS.write_ods = write_ods;
|
||||
})(typeof exports !== 'undefined' ? exports : ODS);
|
287
ods.js
287
ods.js
|
@ -21,6 +21,14 @@ function cc2str(arr) {
|
|||
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
|
||||
return o;
|
||||
}
|
||||
|
||||
function dup(o) {
|
||||
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
|
||||
if(typeof o != 'object' || !o) return o;
|
||||
var out = {};
|
||||
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
|
||||
return out;
|
||||
}
|
||||
function getdata(data) {
|
||||
if(!data) return null;
|
||||
if(data.data) return data.data;
|
||||
|
@ -67,7 +75,7 @@ function parsexmltag(tag, skip_root) {
|
|||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
|
||||
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
|
@ -108,7 +116,7 @@ function escapexml(text){
|
|||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value, tag) {
|
||||
function parsexmlbool(value) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
|
@ -147,6 +155,8 @@ function parse_isodur(s) {
|
|||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
|
||||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
|
@ -157,14 +167,14 @@ function xlml_normalize(d) {
|
|||
var xlmlregex = /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/mg;
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
var parse_manifest = function(d, opts) {
|
||||
function parse_manifest(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0]);
|
||||
FEtag = parsexmltag(Rn[0], false);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
|
@ -172,11 +182,46 @@ var parse_manifest = function(d, opts) {
|
|||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: throw Rn;
|
||||
default: if(opts && opts.WTF) throw Rn;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function write_manifest(manifest, opts) {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
|
||||
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
|
||||
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
|
||||
o.push('</manifest:manifest>');
|
||||
return o.join("");
|
||||
}
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
function write_rdf_type(file, res, tag) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + file + '">\n',
|
||||
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf_has(base, file) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + base + '">\n',
|
||||
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf(rdf, opts) {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
|
||||
for(var i = 0; i != rdf.length; ++i) {
|
||||
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
|
||||
o.push(write_rdf_has("",rdf[i][0]));
|
||||
}
|
||||
o.push(write_rdf_type("","Document", "pkg"));
|
||||
o.push('</rdf:RDF>');
|
||||
return o.join("");
|
||||
}
|
||||
var parse_text_p = function(text, tag) {
|
||||
return utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
|
||||
return unescapexml(utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,"")));
|
||||
};
|
||||
|
||||
var utf8read = function utf8reada(orig) {
|
||||
|
@ -213,27 +258,29 @@ var parse_content_xml = (function() {
|
|||
var str = xlml_normalize(d);
|
||||
var state = [], tmp;
|
||||
var tag;
|
||||
var NFtag, NF, pidx;
|
||||
var NFtag = {name:""}, NF = "", pidx = 0;
|
||||
var sheetag;
|
||||
var Sheets = {}, SheetNames = [], ws = {};
|
||||
var Rn, q;
|
||||
var ctag;
|
||||
var textp, textpidx, textptag;
|
||||
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var ctag = {value:""};
|
||||
var textp = "", textpidx = 0, textptag;
|
||||
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
var merges = [], mrange = {}, mR = 0, mC = 0;
|
||||
|
||||
var rept = 1;
|
||||
xlmlregex.lastIndex = 0;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
if(merges.length) ws['!merges'] = merges;
|
||||
sheetag.name = utf8read(sheetag.name);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0]);
|
||||
sheetag = parsexmltag(Rn[0], false);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {}; merges = [];
|
||||
|
@ -247,17 +294,18 @@ var parse_content_xml = (function() {
|
|||
++C; break; /* stub */
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') {
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
|
||||
else ++C;
|
||||
}
|
||||
else if(Rn[1]!=='/') {
|
||||
++C;
|
||||
rept = 1;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
q = {t:ctag['value-type'], v:null};
|
||||
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
|
||||
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
|
||||
|
@ -265,6 +313,10 @@ var parse_content_xml = (function() {
|
|||
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
|
||||
merges.push(mrange);
|
||||
}
|
||||
|
||||
/* 19.675.2 table:number-columns-repeated */
|
||||
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
|
||||
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
|
@ -273,14 +325,22 @@ var parse_content_xml = (function() {
|
|||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'string': q.t = 's'; break;
|
||||
default: throw new Error('Unsupported value type ' + q.t);
|
||||
default:
|
||||
if(q.t === 'string' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 's') q.v = textp;
|
||||
if(q.t === 's') q.v = textp || '';
|
||||
if(textp) q.w = textp;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
q = null;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) {
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
|
||||
if(range.e.c <= C) range.e.c = C;
|
||||
}
|
||||
q = {};
|
||||
textp = "";
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
|
@ -296,6 +356,13 @@ var parse_content_xml = (function() {
|
|||
/* ignore state */
|
||||
case 'shapes': // 9.2.8 <table:shapes>
|
||||
case 'frame': // 10.4.2 <draw:frame>
|
||||
case 'text-box': // 10.4.3 <draw:text-box>
|
||||
case 'image': // 10.4.4 <draw:image>
|
||||
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
|
||||
case 'list-style': // 16.30 <text:list-style>
|
||||
case 'form': // 13.13 <form:form>
|
||||
case 'dde-links': // 9.8 <table:dde-links>
|
||||
case 'annotation': // 14.1 <office:annotation>
|
||||
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], false]);
|
||||
break;
|
||||
|
@ -309,7 +376,7 @@ var parse_content_xml = (function() {
|
|||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0]);
|
||||
NFtag = parsexmltag(Rn[0], false);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
|
@ -317,6 +384,7 @@ var parse_content_xml = (function() {
|
|||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'map': break; // 16.3 <style:map>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
|
@ -329,10 +397,12 @@ var parse_content_xml = (function() {
|
|||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'fraction': break; // TODO 16.27.6 <number:fraction>
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
|
@ -347,7 +417,7 @@ var parse_content_xml = (function() {
|
|||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
|
@ -373,30 +443,114 @@ var parse_content_xml = (function() {
|
|||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'graphic-properties': break;
|
||||
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
|
||||
|
||||
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.11 <table:named-range>
|
||||
case 'named-range': break; // 9.4.12 <table:named-range>
|
||||
case 'named-expression': break; // 9.4.13 <table:named-expression>
|
||||
case 'sort': break; // 9.4.19 <table:sort>
|
||||
case 'sort-by': break; // 9.4.20 <table:sort-by>
|
||||
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
|
||||
|
||||
case 'span': break; // <text:span>
|
||||
case 'line-break': break; // 6.1.5 <text:line-break>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0]); textpidx = Rn.index + Rn[0].length; }
|
||||
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
case 'annotation': break;
|
||||
|
||||
case 'object': break; // 10.4.6.2 <draw:object>
|
||||
case 'title': break; // <*:title>
|
||||
case 'desc': break; // <*:desc>
|
||||
|
||||
case 'table-source': break; // 9.2.6
|
||||
|
||||
case 'iteration': break; // 9.4.3 <table:iteration>
|
||||
case 'content-validations': break; // 9.4.4 <table:
|
||||
case 'content-validation': break; // 9.4.5 <table:
|
||||
case 'error-message': break; // 9.4.7 <table:
|
||||
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
|
||||
case 'database-range': break; // 9.4.15 <table:database-range>
|
||||
case 'filter': break; // 9.5.2 <table:filter>
|
||||
case 'filter-and': break; // 9.5.3 <table:filter-and>
|
||||
case 'filter-or': break; // 9.5.4 <table:filter-or>
|
||||
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
|
||||
default: if(opts.WTF) throw Rn;
|
||||
|
||||
case 'list-level-style-bullet': break; // 16.31 <text:
|
||||
case 'list-level-style-number': break; // 16.32 <text:
|
||||
case 'list-level-properties': break; // 17.19 <style:
|
||||
|
||||
/* 7.3 Document Fields */
|
||||
case 'sender-firstname': // 7.3.6.2
|
||||
case 'sender-lastname': // 7.3.6.3
|
||||
case 'sender-initials': // 7.3.6.4
|
||||
case 'sender-title': // 7.3.6.5
|
||||
case 'sender-position': // 7.3.6.6
|
||||
case 'sender-email': // 7.3.6.7
|
||||
case 'sender-phone-private': // 7.3.6.8
|
||||
case 'sender-fax': // 7.3.6.9
|
||||
case 'sender-company': // 7.3.6.10
|
||||
case 'sender-phone-work': // 7.3.6.11
|
||||
case 'sender-street': // 7.3.6.12
|
||||
case 'sender-city': // 7.3.6.13
|
||||
case 'sender-postal-code': // 7.3.6.14
|
||||
case 'sender-country': // 7.3.6.15
|
||||
case 'sender-state-or-province': // 7.3.6.16
|
||||
case 'author-name': // 7.3.7.1
|
||||
case 'author-initials': // 7.3.7.2
|
||||
case 'chapter': // 7.3.8
|
||||
case 'file-name': // 7.3.9
|
||||
case 'template-name': // 7.3.9
|
||||
case 'sheet-name': // 7.3.9
|
||||
break;
|
||||
|
||||
/* 9.6 Data Pilot Tables <table: */
|
||||
case 'data-pilot-table': // 9.6.3
|
||||
case 'source-cell-range': // 9.6.5
|
||||
case 'source-service': // 9.6.6
|
||||
case 'data-pilot-field': // 9.6.7
|
||||
case 'data-pilot-level': // 9.6.8
|
||||
case 'data-pilot-subtotals': // 9.6.9
|
||||
case 'data-pilot-subtotal': // 9.6.10
|
||||
case 'data-pilot-members': // 9.6.11
|
||||
case 'data-pilot-member': // 9.6.12
|
||||
case 'data-pilot-display-info': // 9.6.13
|
||||
case 'data-pilot-sort-info': // 9.6.14
|
||||
case 'data-pilot-layout-info': // 9.6.15
|
||||
case 'data-pilot-field-reference': // 9.6.16
|
||||
case 'data-pilot-groups': // 9.6.17
|
||||
case 'data-pilot-group': // 9.6.18
|
||||
case 'data-pilot-group-member': // 9.6.19
|
||||
break;
|
||||
|
||||
/* 10.3 Drawing Shapes */
|
||||
case 'rect': // 10.3.2
|
||||
break;
|
||||
|
||||
/* 14.6 DDE Connections */
|
||||
case 'dde-connection-decls': // 14.6.2 <text:
|
||||
case 'dde-connection-decl': // 14.6.3 <text:
|
||||
case 'dde-link': // 14.6.4 <table:
|
||||
case 'dde-source': // 14.6.5 <office:
|
||||
break;
|
||||
|
||||
case 'properties': break; // 13.7 <form:properties>
|
||||
case 'property': break; // 13.8 <form:property>
|
||||
|
||||
case 'a': break; // 6.1.8 hyperlink
|
||||
|
||||
/* non-standard */
|
||||
case 'table-protection': break;
|
||||
case 'data-pilot-grand-total': break; // <table:
|
||||
default:
|
||||
if(Rn[2] === 'dc:') break; // TODO: properties
|
||||
if(Rn[2] === 'draw:') break; // TODO: drawing
|
||||
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
|
||||
if(opts.WTF) throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
|
@ -405,10 +559,81 @@ var parse_content_xml = (function() {
|
|||
return out;
|
||||
};
|
||||
})();
|
||||
var write_content_xml = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var write_ws = function(ws, wb, i, opts) {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
}
|
||||
o.push(' </table:table-row>\n');
|
||||
}
|
||||
o.push(' </table:table>\n');
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
return function wcx(wb, opts) {
|
||||
var o = [XML_HEADER];
|
||||
/* 3.1.3.2 */
|
||||
o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
|
||||
o.push(' <office:body>\n');
|
||||
o.push(' <office:spreadsheet>\n');
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
|
||||
o.push(' </office:spreadsheet>\n');
|
||||
o.push(' </office:body>\n');
|
||||
o.push('</office:document-content>');
|
||||
return o.join("");
|
||||
};
|
||||
})();
|
||||
/* Part 3: Packages */
|
||||
var parse_ods = function(zip, opts) {
|
||||
//var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'));
|
||||
function parse_ods(zip, opts) {
|
||||
opts = opts || ({});
|
||||
var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
|
||||
};
|
||||
}
|
||||
function write_ods(wb, opts) {
|
||||
var zip = new jszip();
|
||||
var f = "";
|
||||
|
||||
var manifest = [];
|
||||
var rdf = [];
|
||||
|
||||
/* 3:3.3 and 2:2.2.4 */
|
||||
f = "mimetype";
|
||||
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
|
||||
|
||||
/* Part 2 Section 2.2 Documents */
|
||||
f = "content.xml";
|
||||
zip.file(f, write_content_xml(wb, opts));
|
||||
manifest.push([f, "text/xml"]);
|
||||
rdf.push([f, "ContentFile"]);
|
||||
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
f = "manifest.rdf";
|
||||
zip.file(f, write_rdf(rdf, opts));
|
||||
manifest.push([f, "application/rdf+xml"]);
|
||||
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
f = "META-INF/manifest.xml";
|
||||
zip.file(f, write_manifest(manifest, opts));
|
||||
|
||||
return zip;
|
||||
}
|
||||
ODS.parse_ods = parse_ods;
|
||||
ODS.write_ods = write_ods;
|
||||
})(typeof exports !== 'undefined' ? exports : ODS);
|
||||
|
|
|
@ -0,0 +1 @@
|
|||
*.js
|
|
@ -1,3 +1,4 @@
|
|||
/*:: declare var XLSX: any; */
|
||||
var get_utils = function() {
|
||||
if(typeof XLSX !== 'undefined') return XLSX.utils;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
|
||||
|
|
|
@ -5,3 +5,11 @@ function cc2str(arr) {
|
|||
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
|
||||
return o;
|
||||
}
|
||||
|
||||
function dup(o/*:object*/)/*:object*/ {
|
||||
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
|
||||
if(typeof o != 'object' || !o) return o;
|
||||
var out = {};
|
||||
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
|
||||
return out;
|
||||
}
|
||||
|
|
|
@ -20,13 +20,14 @@ function getzipfile(zip, file) {
|
|||
return o;
|
||||
}
|
||||
|
||||
function getzipdata(zip, file, safe) {
|
||||
function getzipdata(zip, file, safe/*:?boolean*/) {
|
||||
if(!safe) return getdata(getzipfile(zip, file));
|
||||
if(!file) return null;
|
||||
try { return getzipdata(zip, file); } catch(e) { return null; }
|
||||
}
|
||||
|
||||
var _fs, jszip;
|
||||
/*:: declare var JSZip:any; */
|
||||
if(typeof JSZip !== 'undefined') jszip = JSZip;
|
||||
if (typeof exports !== 'undefined') {
|
||||
if (typeof module !== 'undefined' && module.exports) {
|
||||
|
|
|
@ -2,12 +2,12 @@ var attregexg=/\b[\w:-]+=["'][^"]*['"]/g;
|
|||
var tagregex=/<[^>]*>/g;
|
||||
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
|
||||
function parsexmltag(tag, skip_root) {
|
||||
var z = [];
|
||||
var z/*:any*/ = [];
|
||||
var eq = 0, c = 0;
|
||||
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
|
||||
if(!skip_root) z[0] = tag.substr(0, eq);
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
|
||||
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
|
@ -48,7 +48,7 @@ function escapexml(text){
|
|||
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
|
||||
}
|
||||
|
||||
function parsexmlbool(value, tag) {
|
||||
function parsexmlbool(value) {
|
||||
switch(value) {
|
||||
case '1': case 'true': case 'TRUE': return true;
|
||||
/* case '0': case 'false': case 'FALSE':*/
|
||||
|
@ -87,3 +87,5 @@ function parse_isodur(s) {
|
|||
}
|
||||
return sec;
|
||||
}
|
||||
|
||||
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
/* copied from js-xls (C) SheetJS Apache2 license */
|
||||
function xlml_normalize(d) {
|
||||
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
|
||||
if(typeof d === 'string') return d;
|
||||
throw "badf";
|
||||
}
|
||||
|
|
|
@ -1,13 +1,13 @@
|
|||
/* Part 3 Section 4 Manifest File */
|
||||
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
|
||||
var parse_manifest = function(d, opts) {
|
||||
function parse_manifest(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var Rn;
|
||||
var FEtag;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
case 'manifest': break; // 4.2 <manifest:manifest>
|
||||
case 'file-entry': // 4.3 <manifest:file-entry>
|
||||
FEtag = parsexmltag(Rn[0]);
|
||||
FEtag = parsexmltag(Rn[0], false);
|
||||
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
|
||||
break;
|
||||
case 'encryption-data': // 4.4 <manifest:encryption-data>
|
||||
|
@ -15,6 +15,15 @@ var parse_manifest = function(d, opts) {
|
|||
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
|
||||
case 'key-derivation': // 4.7 <manifest:key-derivation>
|
||||
throw new Error("Unsupported ODS Encryption");
|
||||
default: throw Rn;
|
||||
default: if(opts && opts.WTF) throw Rn;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
function write_manifest(manifest/*:Array<Array<string> >*/, opts)/*:string*/ {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
|
||||
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
|
||||
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
|
||||
o.push('</manifest:manifest>');
|
||||
return o.join("");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,26 @@
|
|||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + file + '">\n',
|
||||
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf_has(base/*:string*/, file/*:string*/) {
|
||||
return [
|
||||
' <rdf:Description rdf:about="' + base + '">\n',
|
||||
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
|
||||
' </rdf:Description>\n'
|
||||
].join("");
|
||||
}
|
||||
function write_rdf(rdf, opts) {
|
||||
var o = [XML_HEADER];
|
||||
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
|
||||
for(var i = 0; i != rdf.length; ++i) {
|
||||
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
|
||||
o.push(write_rdf_has("",rdf[i][0]));
|
||||
}
|
||||
o.push(write_rdf_type("","Document", "pkg"));
|
||||
o.push('</rdf:RDF>');
|
||||
return o.join("");
|
||||
}
|
|
@ -1,5 +1,5 @@
|
|||
var parse_text_p = function(text, tag) {
|
||||
return utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
|
||||
return unescapexml(utf8read(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,"")));
|
||||
};
|
||||
|
||||
var utf8read = function utf8reada(orig) {
|
||||
|
|
|
@ -14,29 +14,31 @@ var parse_content_xml = (function() {
|
|||
|
||||
return function pcx(d, opts) {
|
||||
var str = xlml_normalize(d);
|
||||
var state = [], tmp;
|
||||
var tag;
|
||||
var NFtag, NF, pidx;
|
||||
var sheetag;
|
||||
var Sheets = {}, SheetNames = [], ws = {};
|
||||
var Rn, q;
|
||||
var ctag;
|
||||
var textp, textpidx, textptag;
|
||||
var R, C, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var state/*:Array<any>*/ = [], tmp;
|
||||
var tag/*:: = {}*/;
|
||||
var NFtag = {name:""}, NF = "", pidx = 0;
|
||||
var sheetag/*:: = {name:""}*/;
|
||||
var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {};
|
||||
var Rn, q/*:: = {t:"", v:null, z:null, w:""}*/;
|
||||
var ctag = {value:""};
|
||||
var textp = "", textpidx = 0, textptag/*:: = {}*/;
|
||||
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
|
||||
var number_format_map = {};
|
||||
var merges = [], mrange = {}, mR = 0, mC = 0;
|
||||
|
||||
var rept = 1;
|
||||
xlmlregex.lastIndex = 0;
|
||||
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
|
||||
|
||||
case 'table': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
|
||||
if(merges.length) ws['!merges'] = merges;
|
||||
sheetag.name = utf8read(sheetag.name);
|
||||
SheetNames.push(sheetag.name);
|
||||
Sheets[sheetag.name] = ws;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
sheetag = parsexmltag(Rn[0]);
|
||||
sheetag = parsexmltag(Rn[0], false);
|
||||
R = C = -1;
|
||||
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
|
||||
ws = {}; merges = [];
|
||||
|
@ -50,24 +52,29 @@ var parse_content_xml = (function() {
|
|||
++C; break; /* stub */
|
||||
case 'table-cell':
|
||||
if(Rn[0].charAt(Rn[0].length-2) === '/') {
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
|
||||
else ++C;
|
||||
}
|
||||
else if(Rn[1]!=='/') {
|
||||
++C;
|
||||
rept = 1;
|
||||
if(C > range.e.c) range.e.c = C;
|
||||
if(R > range.e.r) range.e.r = R;
|
||||
if(C < range.s.c) range.s.c = C;
|
||||
if(R < range.s.r) range.s.r = R;
|
||||
ctag = parsexmltag(Rn[0]);
|
||||
q = {t:ctag['value-type'], v:null};
|
||||
ctag = parsexmltag(Rn[0], false);
|
||||
q = {t:ctag['value-type'], v:null/*:: , z:null, w:""*/};
|
||||
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
|
||||
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
|
||||
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
|
||||
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
|
||||
merges.push(mrange);
|
||||
}
|
||||
|
||||
/* 19.675.2 table:number-columns-repeated */
|
||||
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
|
||||
|
||||
/* 19.385 office:value-type */
|
||||
switch(q.t) {
|
||||
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
|
||||
|
@ -76,14 +83,22 @@ var parse_content_xml = (function() {
|
|||
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
|
||||
case 'date': q.t = 'n'; q.v = datenum(ctag['date-value']); q.z = 'm/d/yy'; break;
|
||||
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
|
||||
case 'string': q.t = 's'; break;
|
||||
default: throw new Error('Unsupported value type ' + q.t);
|
||||
default:
|
||||
if(q.t === 'string' || !q.t) {
|
||||
q.t = 's';
|
||||
if(ctag['string-value'] != null) textp = ctag['string-value'];
|
||||
} else throw new Error('Unsupported value type ' + q.t);
|
||||
}
|
||||
} else {
|
||||
if(q.t === 's') q.v = textp;
|
||||
if(q.t === 's') q.v = textp || '';
|
||||
if(textp) q.w = textp;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
q = null;
|
||||
if(!(opts.sheetRows && opts.sheetRows < R)) {
|
||||
ws[get_utils().encode_cell({r:R,c:C})] = q;
|
||||
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
|
||||
if(range.e.c <= C) range.e.c = C;
|
||||
}
|
||||
q = {/*:: t:"", v:null, z:null, w:""*/};
|
||||
textp = "";
|
||||
}
|
||||
break; // 9.1.4 <table:table-cell>
|
||||
|
||||
|
@ -99,6 +114,13 @@ var parse_content_xml = (function() {
|
|||
/* ignore state */
|
||||
case 'shapes': // 9.2.8 <table:shapes>
|
||||
case 'frame': // 10.4.2 <draw:frame>
|
||||
case 'text-box': // 10.4.3 <draw:text-box>
|
||||
case 'image': // 10.4.4 <draw:image>
|
||||
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
|
||||
case 'list-style': // 16.30 <text:list-style>
|
||||
case 'form': // 13.13 <form:form>
|
||||
case 'dde-links': // 9.8 <table:dde-links>
|
||||
case 'annotation': // 14.1 <office:annotation>
|
||||
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], false]);
|
||||
break;
|
||||
|
@ -112,7 +134,7 @@ var parse_content_xml = (function() {
|
|||
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
|
||||
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
NF = "";
|
||||
NFtag = parsexmltag(Rn[0]);
|
||||
NFtag = parsexmltag(Rn[0], false);
|
||||
state.push([Rn[3], true]);
|
||||
} break;
|
||||
|
||||
|
@ -120,6 +142,7 @@ var parse_content_xml = (function() {
|
|||
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
|
||||
|
||||
case 'style': break; // 16.2 <style:style>
|
||||
case 'map': break; // 16.3 <style:map>
|
||||
case 'font-face': break; // 16.21 <style:font-face>
|
||||
|
||||
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
|
||||
|
@ -132,10 +155,12 @@ var parse_content_xml = (function() {
|
|||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
case 'fraction': break; // TODO 16.27.6 <number:fraction>
|
||||
|
||||
case 'day': // 16.27.11 <number:day>
|
||||
case 'month': // 16.27.12 <number:month>
|
||||
case 'year': // 16.27.13 <number:year>
|
||||
|
@ -150,7 +175,7 @@ var parse_content_xml = (function() {
|
|||
switch(state[state.length-1][0]) {
|
||||
case 'time-style':
|
||||
case 'date-style':
|
||||
tag = parsexmltag(Rn[0]);
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
|
||||
} break;
|
||||
|
||||
|
@ -176,30 +201,114 @@ var parse_content_xml = (function() {
|
|||
case 'forms': break; // 12.25.2 13.2
|
||||
case 'table-column': break; // 9.1.6 <table:table-column>
|
||||
|
||||
case 'graphic-properties': break;
|
||||
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
|
||||
|
||||
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
|
||||
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
|
||||
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
|
||||
case 'named-range': break; // 9.4.11 <table:named-range>
|
||||
case 'named-range': break; // 9.4.12 <table:named-range>
|
||||
case 'named-expression': break; // 9.4.13 <table:named-expression>
|
||||
case 'sort': break; // 9.4.19 <table:sort>
|
||||
case 'sort-by': break; // 9.4.20 <table:sort-by>
|
||||
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
|
||||
|
||||
case 'span': break; // <text:span>
|
||||
case 'line-break': break; // 6.1.5 <text:line-break>
|
||||
case 'p':
|
||||
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
|
||||
else { textptag = parsexmltag(Rn[0]); textpidx = Rn.index + Rn[0].length; }
|
||||
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
|
||||
break; // <text:p>
|
||||
case 's': break; // <text:s>
|
||||
case 'date': break; // <*:date>
|
||||
case 'annotation': break;
|
||||
|
||||
case 'object': break; // 10.4.6.2 <draw:object>
|
||||
case 'title': break; // <*:title>
|
||||
case 'desc': break; // <*:desc>
|
||||
|
||||
case 'table-source': break; // 9.2.6
|
||||
|
||||
case 'iteration': break; // 9.4.3 <table:iteration>
|
||||
case 'content-validations': break; // 9.4.4 <table:
|
||||
case 'content-validation': break; // 9.4.5 <table:
|
||||
case 'error-message': break; // 9.4.7 <table:
|
||||
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
|
||||
case 'database-range': break; // 9.4.15 <table:database-range>
|
||||
case 'filter': break; // 9.5.2 <table:filter>
|
||||
case 'filter-and': break; // 9.5.3 <table:filter-and>
|
||||
case 'filter-or': break; // 9.5.4 <table:filter-or>
|
||||
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
|
||||
default: if(opts.WTF) throw Rn;
|
||||
|
||||
case 'list-level-style-bullet': break; // 16.31 <text:
|
||||
case 'list-level-style-number': break; // 16.32 <text:
|
||||
case 'list-level-properties': break; // 17.19 <style:
|
||||
|
||||
/* 7.3 Document Fields */
|
||||
case 'sender-firstname': // 7.3.6.2
|
||||
case 'sender-lastname': // 7.3.6.3
|
||||
case 'sender-initials': // 7.3.6.4
|
||||
case 'sender-title': // 7.3.6.5
|
||||
case 'sender-position': // 7.3.6.6
|
||||
case 'sender-email': // 7.3.6.7
|
||||
case 'sender-phone-private': // 7.3.6.8
|
||||
case 'sender-fax': // 7.3.6.9
|
||||
case 'sender-company': // 7.3.6.10
|
||||
case 'sender-phone-work': // 7.3.6.11
|
||||
case 'sender-street': // 7.3.6.12
|
||||
case 'sender-city': // 7.3.6.13
|
||||
case 'sender-postal-code': // 7.3.6.14
|
||||
case 'sender-country': // 7.3.6.15
|
||||
case 'sender-state-or-province': // 7.3.6.16
|
||||
case 'author-name': // 7.3.7.1
|
||||
case 'author-initials': // 7.3.7.2
|
||||
case 'chapter': // 7.3.8
|
||||
case 'file-name': // 7.3.9
|
||||
case 'template-name': // 7.3.9
|
||||
case 'sheet-name': // 7.3.9
|
||||
break;
|
||||
|
||||
/* 9.6 Data Pilot Tables <table: */
|
||||
case 'data-pilot-table': // 9.6.3
|
||||
case 'source-cell-range': // 9.6.5
|
||||
case 'source-service': // 9.6.6
|
||||
case 'data-pilot-field': // 9.6.7
|
||||
case 'data-pilot-level': // 9.6.8
|
||||
case 'data-pilot-subtotals': // 9.6.9
|
||||
case 'data-pilot-subtotal': // 9.6.10
|
||||
case 'data-pilot-members': // 9.6.11
|
||||
case 'data-pilot-member': // 9.6.12
|
||||
case 'data-pilot-display-info': // 9.6.13
|
||||
case 'data-pilot-sort-info': // 9.6.14
|
||||
case 'data-pilot-layout-info': // 9.6.15
|
||||
case 'data-pilot-field-reference': // 9.6.16
|
||||
case 'data-pilot-groups': // 9.6.17
|
||||
case 'data-pilot-group': // 9.6.18
|
||||
case 'data-pilot-group-member': // 9.6.19
|
||||
break;
|
||||
|
||||
/* 10.3 Drawing Shapes */
|
||||
case 'rect': // 10.3.2
|
||||
break;
|
||||
|
||||
/* 14.6 DDE Connections */
|
||||
case 'dde-connection-decls': // 14.6.2 <text:
|
||||
case 'dde-connection-decl': // 14.6.3 <text:
|
||||
case 'dde-link': // 14.6.4 <table:
|
||||
case 'dde-source': // 14.6.5 <office:
|
||||
break;
|
||||
|
||||
case 'properties': break; // 13.7 <form:properties>
|
||||
case 'property': break; // 13.8 <form:property>
|
||||
|
||||
case 'a': break; // 6.1.8 hyperlink
|
||||
|
||||
/* non-standard */
|
||||
case 'table-protection': break;
|
||||
case 'data-pilot-grand-total': break; // <table:
|
||||
default:
|
||||
if(Rn[2] === 'dc:') break; // TODO: properties
|
||||
if(Rn[2] === 'draw:') break; // TODO: drawing
|
||||
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
|
||||
if(opts.WTF) throw Rn;
|
||||
}
|
||||
var out = {
|
||||
Sheets: Sheets,
|
||||
|
|
|
@ -0,0 +1,41 @@
|
|||
var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
|
||||
var null_cell_xml = ' <table:table-cell />\n';
|
||||
var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ {
|
||||
/* Section 9 Tables */
|
||||
var o = [];
|
||||
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
|
||||
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
|
||||
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
|
||||
for(; R <= range.e.r; ++R) {
|
||||
o.push(' <table:table-row>\n');
|
||||
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
|
||||
for(; C <= range.e.c; ++C) {
|
||||
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
|
||||
if(cell) switch(cell.t) {
|
||||
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
|
||||
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
|
||||
//case 'd': // TODO
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml);
|
||||
} else o.push(null_cell_xml);
|
||||
}
|
||||
o.push(' </table:table-row>\n');
|
||||
}
|
||||
o.push(' </table:table>\n');
|
||||
return o.join("");
|
||||
};
|
||||
|
||||
return function wcx(wb, opts) {
|
||||
var o = [XML_HEADER];
|
||||
/* 3.1.3.2 */
|
||||
o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
|
||||
o.push(' <office:body>\n');
|
||||
o.push(' <office:spreadsheet>\n');
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
|
||||
o.push(' </office:spreadsheet>\n');
|
||||
o.push(' </office:body>\n');
|
||||
o.push('</office:document-content>');
|
||||
return o.join("");
|
||||
};
|
||||
})();
|
|
@ -1,5 +1,6 @@
|
|||
/* Part 3: Packages */
|
||||
var parse_ods = function(zip, opts) {
|
||||
//var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'));
|
||||
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) {
|
||||
opts = opts || ({}/*:any*/);
|
||||
var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
|
||||
return parse_content_xml(getzipdata(zip, 'content.xml'), opts);
|
||||
};
|
||||
}
|
||||
|
|
|
@ -0,0 +1,29 @@
|
|||
function write_ods(wb/*:any*/, opts/*:any*/) {
|
||||
/*:: if(!jszip) throw new Error("JSZip is not available"); */
|
||||
var zip = new jszip();
|
||||
var f = "";
|
||||
|
||||
var manifest/*:Array<Array<string> >*/ = [];
|
||||
var rdf = [];
|
||||
|
||||
/* 3:3.3 and 2:2.2.4 */
|
||||
f = "mimetype";
|
||||
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
|
||||
|
||||
/* Part 2 Section 2.2 Documents */
|
||||
f = "content.xml";
|
||||
zip.file(f, write_content_xml(wb, opts));
|
||||
manifest.push([f, "text/xml"]);
|
||||
rdf.push([f, "ContentFile"]);
|
||||
|
||||
/* Part 3 Section 6 Metadata Manifest File */
|
||||
f = "manifest.rdf";
|
||||
zip.file(f, write_rdf(rdf, opts));
|
||||
manifest.push([f, "application/rdf+xml"]);
|
||||
|
||||
/* Part 3 Section 4 Manifest File */
|
||||
f = "META-INF/manifest.xml";
|
||||
zip.file(f, write_manifest(manifest, opts));
|
||||
|
||||
return zip;
|
||||
}
|
|
@ -1 +1,2 @@
|
|||
ODS.parse_ods = parse_ods;
|
||||
ODS.write_ods = write_ods;
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.8.1",
|
||||
"version": "0.8.2",
|
||||
"author": "sheetjs",
|
||||
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS spreadsheet parser and writer",
|
||||
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
|
||||
|
@ -33,6 +33,7 @@
|
|||
"pattern": "xlsx.js"
|
||||
}
|
||||
},
|
||||
"homepage": "https://oss.sheetjs.com/js-xlsx/",
|
||||
"bugs": { "url": "https://github.com/SheetJS/js-xlsx/issues" },
|
||||
"license": "Apache-2.0",
|
||||
"engines": { "node": ">=0.8" }
|
||||
|
|
3
test.js
3
test.js
|
@ -11,7 +11,7 @@ if(process.env.WTF) {
|
|||
opts.WTF = true;
|
||||
opts.cellStyles = true;
|
||||
}
|
||||
var fullex = [/*TODO: check why write xlsb fails ".xlsb",*/ ".xlsm", ".xlsx"];
|
||||
var fullex = [".xlsb", ".xlsm", ".xlsx"];
|
||||
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;});
|
||||
|
@ -114,6 +114,7 @@ function parsetest(x, wb, full, ext) {
|
|||
if(!full) return;
|
||||
var getfile = function(dir, x, i, type) {
|
||||
var name = (dir + x + '.' + i + type);
|
||||
var root = "";
|
||||
if(x.substr(-5) === ".xlsb") {
|
||||
root = x.slice(0,-5);
|
||||
if(!fs.existsSync(name)) name=(dir + root + '.xlsx.' + i + type);
|
||||
|
|
16
tests.lst
16
tests.lst
|
@ -25,7 +25,7 @@ text_and_numbers.xlsb
|
|||
xlsx-stream-d-date-cell.xlsb
|
||||
2013/apachepoi_29982.xls.xlsb
|
||||
2013/apachepoi_43251.xls.xlsb
|
||||
2013/apachepoi_44593.xls.xlsb
|
||||
#2013/apachepoi_44593.xls.xlsb ## xlsb loop timeout
|
||||
2013/apachepoi_44643.xls.xlsb
|
||||
2013/apachepoi_44958.xls.xlsb
|
||||
2013/apachepoi_46136-NoWarnings.xls.xlsb
|
||||
|
@ -126,7 +126,7 @@ apachepoi_56688_1.xlsx
|
|||
apachepoi_56688_2.xlsx
|
||||
apachepoi_56688_3.xlsx
|
||||
apachepoi_56688_4.xlsx
|
||||
apachepoi_56702.xlsx
|
||||
# apachepoi_56702.xlsx ## xlsb bad xnum
|
||||
apachepoi_56730.xlsx
|
||||
apachepoi_56737.xlsx
|
||||
apachepoi_AverageTaxRates.xlsx
|
||||
|
@ -344,7 +344,7 @@ formula_stress_test.ods
|
|||
merge_cells.ods
|
||||
number_format.ods
|
||||
rich_text_stress.ods
|
||||
roo_Bibelbund.ods
|
||||
# roo_Bibelbund.ods ## timeout
|
||||
roo_Bibelbund1.ods
|
||||
roo_bbu.ods
|
||||
roo_boolean.ods
|
||||
|
@ -475,7 +475,7 @@ apachepoi_44200.xls
|
|||
apachepoi_44201.xls
|
||||
apachepoi_44235.xls
|
||||
apachepoi_44297.xls
|
||||
apachepoi_44593.xls
|
||||
# apachepoi_44593.xls ## xlsb loop timeout
|
||||
apachepoi_44636.xls
|
||||
apachepoi_44643.xls
|
||||
apachepoi_44693.xls
|
||||
|
@ -529,7 +529,7 @@ apachepoi_49529.xls
|
|||
apachepoi_49581.xls
|
||||
apachepoi_49612.xls
|
||||
apachepoi_49751.xls
|
||||
apachepoi_49761.xls
|
||||
# apachepoi_49761.xls ## xlsb bad xnum
|
||||
apachepoi_49896.xls
|
||||
apachepoi_49928.xls
|
||||
apachepoi_49931.xls
|
||||
|
@ -615,12 +615,12 @@ apachepoi_PercentPtg.xls
|
|||
apachepoi_QuotientFunctionTestCaseData.xls
|
||||
apachepoi_RangePtg.xls
|
||||
apachepoi_ReadOnlyRecommended.xls
|
||||
apachepoi_ReferencePtg.xls
|
||||
# apachepoi_ReferencePtg.xls ## xlsb loop timeout
|
||||
apachepoi_RepeatingRowsCols.xls
|
||||
apachepoi_ReptFunctionTestCaseData.xls
|
||||
apachepoi_RomanFunctionTestCaseData.xls
|
||||
apachepoi_SampleSS.xls
|
||||
apachepoi_SharedFormulaTest.xls
|
||||
# apachepoi_SharedFormulaTest.xls ## xlsb loop timeout
|
||||
apachepoi_SheetWithDrawing.xls
|
||||
apachepoi_ShrinkToFit.xls
|
||||
apachepoi_Simple.xls
|
||||
|
@ -899,7 +899,7 @@ 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-heights.xls ## xlsb loop timeout
|
||||
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
|
||||
|
|
|
@ -85,3 +85,7 @@ ws['!cols'] = wscols;
|
|||
|
||||
/* write file */
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsx');
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsm');
|
||||
XLSX.writeFile(wb, 'sheetjs.xlsb');
|
||||
//XLSX.writeFile(wb, 'sheetjs.xls');
|
||||
XLSX.writeFile(wb, 'sheetjs.ods');
|
||||
|
|
File diff suppressed because one or more lines are too long
172
xlsx.js
172
xlsx.js
|
@ -4,7 +4,7 @@
|
|||
/*jshint funcscope:true, eqnull:true */
|
||||
var XLSX = {};
|
||||
(function make_xlsx(XLSX){
|
||||
XLSX.version = '0.8.1';
|
||||
XLSX.version = '0.8.2';
|
||||
var current_codepage = 1200, current_cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel');
|
||||
|
@ -1645,7 +1645,8 @@ function WriteShift(t, val, f) {
|
|||
size = 2 * val.length;
|
||||
} else switch(t) {
|
||||
case 1: size = 1; this[this.l] = val&255; break;
|
||||
case 3: size = 3; this[this.l+2] = val & 255; val >>>= 8; this[this.l+1] = val&255; val >>>= 8; this[this.l] = val&255; break;
|
||||
case 2: size = 2; this[this.l] = val&255; val >>>= 8; this[this.l+1] = val&255; break;
|
||||
case 3: size = 3; this[this.l] = val&255; val >>>= 8; this[this.l+1] = val&255; val >>>= 8; this[this.l+2] = val&255; break;
|
||||
case 4: size = 4; this.writeUInt32LE(val, this.l); break;
|
||||
case 8: size = 8; if(f === 'f') { this.writeDoubleLE(val, this.l); break; }
|
||||
/* falls through */
|
||||
|
@ -1706,7 +1707,7 @@ function buf_array() {
|
|||
var curbuf = newblk(blksz);
|
||||
|
||||
var endbuf = function ba_endbuf() {
|
||||
curbuf.length = curbuf.l;
|
||||
if(curbuf.length > curbuf.l) curbuf = curbuf.slice(0, curbuf.l);
|
||||
if(curbuf.length > 0) bufs.push(curbuf);
|
||||
curbuf = null;
|
||||
};
|
||||
|
@ -1893,6 +1894,15 @@ function parse_RkNumber(data) {
|
|||
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;
|
||||
}
|
||||
function write_RkNumber(data, o) {
|
||||
if(o == null) o = new_buf(4);
|
||||
var fX100 = 0, fInt = 0, d100 = data * 100;
|
||||
if(data == (data | 0) && data >= -(1<<29) && data < (1 << 29)) { fInt = 1; }
|
||||
else if(d100 == (d100 | 0) && d100 >= -(1<<29) && d100 < (1 << 29)) { fInt = 1; fX100 = 1; }
|
||||
if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
|
||||
else throw new Error("unsupported RkNumber " + data); // TODO
|
||||
}
|
||||
|
||||
|
||||
/* [MS-XLSB] 2.5.153 */
|
||||
function parse_UncheckedRfX(data) {
|
||||
|
@ -1915,8 +1925,9 @@ function write_UncheckedRfX(r, o) {
|
|||
|
||||
/* [MS-XLSB] 2.5.171 */
|
||||
/* [MS-XLS] 2.5.342 */
|
||||
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
|
||||
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); }
|
||||
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
|
||||
|
||||
/* [MS-XLSB] 2.5.198.2 */
|
||||
var BErr = {
|
||||
|
@ -2730,7 +2741,7 @@ function parse_cust_props(data, opts) {
|
|||
p[name] = unescapexml(text);
|
||||
break;
|
||||
default:
|
||||
if(typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
|
||||
if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
|
||||
}
|
||||
} else if(x.substr(0,2) === "</") {
|
||||
} else if(opts.WTF) throw new Error(x);
|
||||
|
@ -7286,7 +7297,7 @@ function parse_ws_xml(data, opts, rels) {
|
|||
var mergecells = [];
|
||||
if(data.indexOf("</mergeCells>")!==-1) {
|
||||
var merges = data.match(mergecregex);
|
||||
for(ridx = 0; ridx != merges.length; ++ridx)
|
||||
if(merges) for(ridx = 0; ridx != merges.length; ++ridx)
|
||||
mergecells[ridx] = safe_decode_range(merges[ridx].substr(merges[ridx].indexOf("\"")+1));
|
||||
}
|
||||
|
||||
|
@ -7298,7 +7309,7 @@ function parse_ws_xml(data, opts, rels) {
|
|||
parse_ws_xml_cols(columns, cols);
|
||||
}
|
||||
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
/* 18.3.1.80 sheetData CT_SheetData ? */
|
||||
var mtch=data.match(sheetdataregex);
|
||||
|
@ -7573,6 +7584,45 @@ function parse_BrtRowHdr(data, length) {
|
|||
data.l += length-4;
|
||||
return z;
|
||||
}
|
||||
function write_BrtRowHdr(R, range, ws) {
|
||||
var o = new_buf(17+8*16);
|
||||
o.write_shift(4, R);
|
||||
|
||||
/* TODO: flags styles */
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(2, 0x0140);
|
||||
o.write_shift(2, 0);
|
||||
o.write_shift(1, 0);
|
||||
|
||||
/* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
|
||||
var ncolspan = 0, lcs = o.l;
|
||||
o.l += 4;
|
||||
|
||||
var caddr = {r:R, c:0};
|
||||
for(var i = 0; i < 16; ++i) {
|
||||
if(range.s.c > ((i+1) << 10) || range.e.c < (i << 10)) continue;
|
||||
var first = -1, last = -1;
|
||||
for(var j = (i<<10); j < ((i+1)<<10); ++j) {
|
||||
caddr.c = j;
|
||||
if(ws[encode_cell(caddr)]) { if(first < 0) first = j; last = j; }
|
||||
}
|
||||
if(first < 0) continue;
|
||||
++ncolspan;
|
||||
o.write_shift(4, first);
|
||||
o.write_shift(4, last);
|
||||
}
|
||||
|
||||
var l = o.l;
|
||||
o.l = lcs;
|
||||
o.write_shift(4, ncolspan);
|
||||
o.l = l;
|
||||
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
function write_row_header(ba, ws, range, R) {
|
||||
var o = write_BrtRowHdr(R, range, ws);
|
||||
if(o.length > 17) write_record(ba, 'BrtRowHdr', o);
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.812 BrtWsDim */
|
||||
var parse_BrtWsDim = parse_UncheckedRfX;
|
||||
|
@ -7592,9 +7642,9 @@ function parse_BrtCellBlank(data, length) {
|
|||
var cell = parse_XLSBCell(data);
|
||||
return [cell];
|
||||
}
|
||||
function write_BrtCellBlank(cell, val, o) {
|
||||
function write_BrtCellBlank(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(8);
|
||||
return write_XLSBCell(val, o);
|
||||
return write_XLSBCell(ncell, o);
|
||||
}
|
||||
|
||||
|
||||
|
@ -7604,12 +7654,18 @@ function parse_BrtCellBool(data, length) {
|
|||
var fBool = data.read_shift(1);
|
||||
return [cell, fBool, 'b'];
|
||||
}
|
||||
function write_BrtCellBool(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(9);
|
||||
write_XLSBCell(ncell, o);
|
||||
o.write_shift(1, cell.v ? 1 : 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.305 BrtCellError */
|
||||
function parse_BrtCellError(data, length) {
|
||||
var cell = parse_XLSBCell(data);
|
||||
var fBool = data.read_shift(1);
|
||||
return [cell, fBool, 'e'];
|
||||
var bError = data.read_shift(1);
|
||||
return [cell, bError, 'e'];
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.308 BrtCellIsst */
|
||||
|
@ -7618,6 +7674,12 @@ function parse_BrtCellIsst(data, length) {
|
|||
var isst = data.read_shift(4);
|
||||
return [cell, isst, 's'];
|
||||
}
|
||||
function write_BrtCellIsst(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12);
|
||||
write_XLSBCell(ncell, o);
|
||||
o.write_shift(4, ncell.v);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.310 BrtCellReal */
|
||||
function parse_BrtCellReal(data, length) {
|
||||
|
@ -7625,6 +7687,12 @@ function parse_BrtCellReal(data, length) {
|
|||
var value = parse_Xnum(data);
|
||||
return [cell, value, 'n'];
|
||||
}
|
||||
function write_BrtCellReal(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(16);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_Xnum(cell.v, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.311 BrtCellRk */
|
||||
function parse_BrtCellRk(data, length) {
|
||||
|
@ -7632,6 +7700,13 @@ function parse_BrtCellRk(data, length) {
|
|||
var value = parse_RkNumber(data);
|
||||
return [cell, value, 'n'];
|
||||
}
|
||||
function write_BrtCellRk(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_RkNumber(cell.v, o);
|
||||
return o;
|
||||
}
|
||||
|
||||
|
||||
/* [MS-XLSB] 2.4.314 BrtCellSt */
|
||||
function parse_BrtCellSt(data, length) {
|
||||
|
@ -7639,6 +7714,12 @@ function parse_BrtCellSt(data, length) {
|
|||
var value = parse_XLWideString(data);
|
||||
return [cell, value, 'str'];
|
||||
}
|
||||
function write_BrtCellSt(cell, ncell, o) {
|
||||
if(o == null) o = new_buf(12 + 4 * cell.v.length);
|
||||
write_XLSBCell(ncell, o);
|
||||
write_XLWideString(cell.v, o);
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
|
||||
function parse_BrtFmlaBool(data, length, opts) {
|
||||
|
@ -7714,12 +7795,13 @@ function parse_ws_bin(data, opts, rels) {
|
|||
var s = {};
|
||||
|
||||
var ref;
|
||||
var refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
var pass = false, end = false;
|
||||
var row, p, cf, R, C, addr, sstr, rr;
|
||||
var mergecells = [];
|
||||
recordhopper(data, function ws_parse(val, R) {
|
||||
//console.log(R);
|
||||
if(end) return;
|
||||
switch(R.n) {
|
||||
case 'BrtWsDim': ref = val; break;
|
||||
|
@ -7896,7 +7978,7 @@ function parse_ws_bin(data, opts, rels) {
|
|||
default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n);
|
||||
}
|
||||
}, opts);
|
||||
if(!s["!ref"] && (refguess.s.r < 1000000 || ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0)) s["!ref"] = encode_range(ref);
|
||||
if(!s["!ref"] && (refguess.s.r < 2000000 || ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0)) s["!ref"] = encode_range(ref);
|
||||
if(opts.sheetRows && s["!ref"]) {
|
||||
var tmpref = safe_decode_range(s["!ref"]);
|
||||
if(opts.sheetRows < +tmpref.e.r) {
|
||||
|
@ -7929,12 +8011,23 @@ function write_ws_bin_cell(ba, cell, R, C, opts) {
|
|||
case 's': case 'str':
|
||||
if(opts.bookSST) {
|
||||
vv = get_sst_id(opts.Strings, cell.v);
|
||||
o.t = "s"; break;
|
||||
o.t = "s"; o.v = vv;
|
||||
write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
|
||||
} else {
|
||||
o.t = "str";
|
||||
write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
|
||||
}
|
||||
o.t = "str"; break;
|
||||
case 'n': break;
|
||||
case 'b': o.t = "b"; break;
|
||||
case 'e': o.t = "e"; break;
|
||||
return;
|
||||
case 'n':
|
||||
/* TODO: determine threshold for Real vs RK */
|
||||
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
|
||||
else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
|
||||
return;
|
||||
case 'b':
|
||||
o.t = "b";
|
||||
write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
|
||||
return;
|
||||
case 'e': /* TODO: error */ o.t = "e"; break;
|
||||
}
|
||||
write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
|
||||
}
|
||||
|
@ -7946,6 +8039,7 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) {
|
|||
rr = encode_row(R);
|
||||
/* [ACCELLTABLE] */
|
||||
/* BrtRowHdr */
|
||||
write_row_header(ba, ws, range, R);
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
/* *16384CELL */
|
||||
if(R === range.s.r) cols[C] = encode_col(C);
|
||||
|
@ -8258,7 +8352,7 @@ function write_BrtBundleSh(data, o) {
|
|||
o.write_shift(4, data.iTabID);
|
||||
write_RelID(data.strRelID, o);
|
||||
write_XLWideString(data.name.substr(0,31), o);
|
||||
return o;
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.807 BrtWbProp */
|
||||
|
@ -8366,7 +8460,7 @@ function write_BrtFileVersion(data, o) {
|
|||
write_XLWideString(XLSX.version, o);
|
||||
write_XLWideString("7262", o);
|
||||
o.length = o.l;
|
||||
return o;
|
||||
return o.length > o.l ? o.slice(0, o.l) : o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.60 Workbook */
|
||||
|
@ -8389,6 +8483,7 @@ function write_BrtCalcProp(data, o) {
|
|||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.4.640 BrtFileRecover */
|
||||
function write_BrtFileRecover(data, o) {
|
||||
if(!o) o = new_buf(1);
|
||||
o.write_shift(1,0);
|
||||
|
@ -8401,22 +8496,22 @@ function write_wb_bin(wb, opts) {
|
|||
write_record(ba, "BrtBeginBook");
|
||||
write_record(ba, "BrtFileVersion", write_BrtFileVersion());
|
||||
/* [[BrtFileSharingIso] BrtFileSharing] */
|
||||
write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
if(0) write_record(ba, "BrtWbProp", write_BrtWbProp());
|
||||
/* [ACABSPATH] */
|
||||
/* [[BrtBookProtectionIso] BrtBookProtection] */
|
||||
write_BOOKVIEWS(ba, wb, opts);
|
||||
if(0) write_BOOKVIEWS(ba, wb, opts);
|
||||
write_BUNDLESHS(ba, wb, opts);
|
||||
/* [FNGROUP] */
|
||||
/* [EXTERNALS] */
|
||||
/* *BrtName */
|
||||
write_record(ba, "BrtCalcProp", write_BrtCalcProp());
|
||||
if(0) write_record(ba, "BrtCalcProp", write_BrtCalcProp());
|
||||
/* [BrtOleSize] */
|
||||
/* *(BrtUserBookView *FRT) */
|
||||
/* [PIVOTCACHEIDS] */
|
||||
/* [BrtWbFactoid] */
|
||||
/* [SMARTTAGTYPES] */
|
||||
/* [BrtWebOpt] */
|
||||
write_record(ba, "BrtFileRecover", write_BrtFileRecover());
|
||||
if(0) write_record(ba, "BrtFileRecover", write_BrtFileRecover());
|
||||
/* [WEBPUBITEMS] */
|
||||
/* [CRERRS] */
|
||||
/* FRTWORKBOOK */
|
||||
|
@ -8625,7 +8720,7 @@ function parse_xlml_xml(d, opts) {
|
|||
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 refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
var styles = {}, stag = {};
|
||||
var ss = "", fidx = 0;
|
||||
var mergecells = [];
|
||||
|
@ -8685,7 +8780,7 @@ function parse_xlml_xml(d, opts) {
|
|||
if(mergecells.length) cursheet["!merges"] = mergecells;
|
||||
sheets[sheetname] = cursheet;
|
||||
} else {
|
||||
refguess = {s: {r:1000000, c:1000000}, e: {r:0, c:0} };
|
||||
refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
r = c = 0;
|
||||
state.push([Rn[3], false]);
|
||||
tmp = xlml_parsexmltag(Rn[0]);
|
||||
|
@ -11080,12 +11175,17 @@ var XLSRecordEnum = {
|
|||
};
|
||||
|
||||
|
||||
/* Helper function to call out to ODS parser */
|
||||
/* Helper functions to call out to ODS */
|
||||
function parse_ods(zip, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.parse_ods(zip, opts);
|
||||
}
|
||||
function write_ods(wb, opts) {
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./od' + 's');
|
||||
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
|
||||
return ODS.write_ods(wb, opts);
|
||||
}
|
||||
function fix_opts_func(defaults) {
|
||||
return function fix_opts(opts) {
|
||||
for(var i = 0; i != defaults.length; ++i) {
|
||||
|
@ -11124,6 +11224,8 @@ var fix_write_opts = fix_opts_func([
|
|||
|
||||
['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
|
||||
|
||||
['compression', false], /* Use file compression */
|
||||
|
||||
['WTF', false] /* WTF mode (throws errors) */
|
||||
]);
|
||||
function safe_parse_wbrels(wbrels, sheets) {
|
||||
|
@ -11278,6 +11380,7 @@ function add_rels(rels, rId, f, type, relobj) {
|
|||
}
|
||||
|
||||
function write_zip(wb, opts) {
|
||||
if(opts.bookType == "ods") return write_ods(wb, opts);
|
||||
if(wb && !wb.SSF) {
|
||||
wb.SSF = SSF.get_table();
|
||||
}
|
||||
|
@ -11405,13 +11508,17 @@ function readFileSync(data, opts) {
|
|||
function write_zip_type(wb, opts) {
|
||||
var o = opts||{};
|
||||
var z = write_zip(wb, o);
|
||||
var oopts = {};
|
||||
if(opts.compression) oopts.compression = 'DEFLATE';
|
||||
switch(o.type) {
|
||||
case "base64": return z.generate({type:"base64"});
|
||||
case "binary": return z.generate({type:"string"});
|
||||
case "buffer": return z.generate({type:"nodebuffer"});
|
||||
case "file": return _fs.writeFileSync(o.file, z.generate({type:"nodebuffer"}));
|
||||
case "base64": oopts.type = "base64"; break;
|
||||
case "binary": oopts.type = "string"; break;
|
||||
case "buffer":
|
||||
case "file": oopts.type = "nodebuffer"; break;
|
||||
default: throw new Error("Unrecognized type " + o.type);
|
||||
}
|
||||
if(o.type === "file") return _fs.writeFileSync(o.file, z.generate(oopts));
|
||||
return z.generate(oopts);
|
||||
}
|
||||
|
||||
function writeSync(wb, opts) {
|
||||
|
@ -11425,13 +11532,14 @@ function writeSync(wb, opts) {
|
|||
function writeFileSync(wb, filename, opts) {
|
||||
var o = opts||{}; o.type = 'file';
|
||||
o.file = filename;
|
||||
switch(o.file.substr(-5).toLowerCase()) {
|
||||
if(!o.bookType) 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;
|
||||
case '.ods': o.bookType = 'ods'; break;
|
||||
}}
|
||||
return writeSync(wb, o);
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* uncomment the next line for encoding support */
|
||||
/*:: declare var XLSX: XLSXModule; */
|
||||
/*:: declare var self: DedicatedWorkerGlobalScope; */
|
||||
//importScripts('dist/cpexcel.js');
|
||||
importScripts('jszip.js');
|
||||
importScripts('xlsx.js');
|
||||
/* uncomment the next line for ODS support */
|
||||
importScripts('dist/ods.js');
|
||||
/*::self.*/postMessage({t:"ready"});
|
||||
|
||||
onmessage = function (oEvent) {
|
||||
var v;
|
||||
try {
|
||||
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b ? 'binary' : 'base64'});
|
||||
} catch(e) { /*::self.*/postMessage({t:"e",d:e.stack||e}); }
|
||||
/*::self.*/
|
||||
postMessage({t:"xlsx", d:JSON.stringify(v)});
|
||||
};
|
|
@ -12,5 +12,5 @@ onmessage = function (oEvent) {
|
|||
try {
|
||||
v = XLSX.read(oEvent.data.d, {type: oEvent.data.b ? 'binary' : 'base64'});
|
||||
} catch(e) { postMessage({t:"e",d:e.stack||e}); }
|
||||
postMessage({t:"xlsx", d:JSON.stringify(v)});
|
||||
postMessage({t:"xlsx", d:JSON.stringify(v)});
|
||||
};
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* uncomment the next line for encoding support */
|
||||
/*:: declare var XLSX: XLSXModule; */
|
||||
/*:: declare var self: DedicatedWorkerGlobalScope; */
|
||||
//importScripts('dist/cpexcel.js');
|
||||
importScripts('jszip.js');
|
||||
importScripts('xlsx.js');
|
||||
/* uncomment the next line for ODS support */
|
||||
importScripts('dist/ods.js');
|
||||
/*::self.*/postMessage({t:"ready"});
|
||||
|
||||
function ab2str(data) {
|
||||
var o = "", l = 0, w = 10240;
|
||||
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,/*::(*/new Uint16Array(data.slice(l*w,l*w+w))/*:: :any)*/);
|
||||
o+=String.fromCharCode.apply(null, /*::(*/new Uint16Array(data.slice(l*w))/*:: :any)*/);
|
||||
return o;
|
||||
}
|
||||
|
||||
function s2ab(s/*:string*/) {
|
||||
var b = new ArrayBuffer(s.length*2), v = new Uint16Array(b);
|
||||
for (var i=0; i != s.length; ++i) v[i] = s.charCodeAt(i);
|
||||
return [v, b];
|
||||
}
|
||||
|
||||
onmessage = function (oEvent) {
|
||||
var v;
|
||||
try {
|
||||
v = XLSX.read(ab2str(oEvent.data), {type: 'binary'});
|
||||
} catch(e) { /*::self.*/postMessage({t:"e",d:e.stack}); }
|
||||
var res = {t:"xlsx", d:JSON.stringify(v)};
|
||||
var r = s2ab(res.d)[1];
|
||||
/*::self.*/
|
||||
postMessage(r, [r]);
|
||||
};
|
|
@ -9,8 +9,8 @@ postMessage({t:"ready"});
|
|||
|
||||
function ab2str(data) {
|
||||
var o = "", l = 0, w = 10240;
|
||||
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint8Array(data.slice(l*w,l*w+w)));
|
||||
o+=String.fromCharCode.apply(null, new Uint8Array(data.slice(l*w)));
|
||||
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,new Uint16Array(data.slice(l*w,l*w+w)));
|
||||
o+=String.fromCharCode.apply(null, new Uint16Array(data.slice(l*w)));
|
||||
return o;
|
||||
}
|
||||
|
||||
|
@ -27,5 +27,5 @@ onmessage = function (oEvent) {
|
|||
} catch(e) { postMessage({t:"e",d:e.stack}); }
|
||||
var res = {t:"xlsx", d:JSON.stringify(v)};
|
||||
var r = s2ab(res.d)[1];
|
||||
postMessage(r, [r]);
|
||||
postMessage(r, [r]);
|
||||
};
|
||||
|
|
|
@ -0,0 +1,34 @@
|
|||
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* uncomment the next line for encoding support */
|
||||
/*:: declare var XLSX: XLSXModule; */
|
||||
/*:: declare var self: DedicatedWorkerGlobalScope; */
|
||||
//importScripts('dist/cpexcel.js');
|
||||
importScripts('jszip.js');
|
||||
importScripts('xlsx.js');
|
||||
/* uncomment the next line for ODS support */
|
||||
importScripts('dist/ods.js');
|
||||
/*::self.*/postMessage({t:"ready"});
|
||||
|
||||
function ab2str(data) {
|
||||
var o = "", l = 0, w = 10240;
|
||||
for(; l<data.byteLength/w; ++l) o+=String.fromCharCode.apply(null,/*::(*/new Uint16Array(data.slice(l*w,l*w+w))/*:: :any)*/);
|
||||
o+=String.fromCharCode.apply(null, /*::(*/new Uint16Array(data.slice(l*w))/*:: :any)*/);
|
||||
return o;
|
||||
}
|
||||
|
||||
function s2ab(s/*:string*/) {
|
||||
var b = new ArrayBuffer(s.length*2), v = new Uint16Array(b);
|
||||
for (var i=0; i != s.length; ++i) v[i] = s.charCodeAt(i);
|
||||
return [v, b];
|
||||
}
|
||||
|
||||
onmessage = function (oEvent) {
|
||||
var v;
|
||||
try {
|
||||
v = XLSX.read(ab2str(oEvent.data), {type: 'binary'});
|
||||
} catch(e) { /*::self.*/postMessage({t:"e",d:e.stack}); }
|
||||
var res = {t:"xlsx", d:JSON.stringify(v)};
|
||||
var r = s2ab(res.d)[1];
|
||||
/*::self.*/
|
||||
postMessage(r, [r]);
|
||||
};
|
|
@ -27,5 +27,5 @@ onmessage = function (oEvent) {
|
|||
} catch(e) { postMessage({t:"e",d:e.stack}); }
|
||||
var res = {t:"xlsx", d:JSON.stringify(v)};
|
||||
var r = s2ab(res.d)[1];
|
||||
postMessage(r, [r]);
|
||||
postMessage(r, [r]);
|
||||
};
|
||||
|
|
Loading…
Reference in New Issue