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
|
||||
|
3
.gitignore
vendored
3
.gitignore
vendored
@ -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';
|
||||
|
8
bits/09_types.js
Normal file
8
bits/09_types.js
Normal file
@ -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]);
|
||||
|
11
bits/83_ods.js
Normal file
11
bits/83_ods.js
Normal file
@ -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",
|
||||
|
287
dist/ods.js
vendored
287
dist/ods.js
vendored
@ -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() {
|
||||