forked from sheetjs/sheetjs
		
	version bump 0.7.0: Basic write support
- very basic XLSX / XLSM write support with roundtrip tests (XLSB stubs)
- reorganized source tree
- new XLSB range check ensures that A1 is not emitted for empty sheets
- SSF table emitted in output (consistent with js-xls)
- CLI supports writing
Backwards-incompatible changes:
o new Property aliases (see CORE_PROPS and EXT_PROPS)
o FILETIME custom properties parsed as JS Dates
o `xlsx2csv` -> `xlsx` (and `bin/xlsx{2csv,}.njs`)
			
			
This commit is contained in:
		
							parent
							
								
									b645f6ef98
								
							
						
					
					
						commit
						d15b81e0e9
					
				
							
								
								
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							@ -1,2 +1,3 @@
 | 
			
		||||
node_modules
 | 
			
		||||
misc/coverage.html
 | 
			
		||||
tmp
 | 
			
		||||
 | 
			
		||||
@ -5,6 +5,7 @@ node_js:
 | 
			
		||||
before_install:
 | 
			
		||||
  - "npm install -g mocha"
 | 
			
		||||
  - "npm install blanket"
 | 
			
		||||
  - "npm install xlsjs"
 | 
			
		||||
  - "npm install coveralls mocha-lcov-reporter"
 | 
			
		||||
before_script:
 | 
			
		||||
  - "make init"
 | 
			
		||||
 | 
			
		||||
@ -5,7 +5,7 @@ order to maintain that, every contributor must be vigilant.
 | 
			
		||||
 | 
			
		||||
There have been many projects in the past that have been very lax regarding
 | 
			
		||||
licensing, and we are of the opinion that those are ticking timebombs and that
 | 
			
		||||
no corporate product should depend on them.  
 | 
			
		||||
no corporate product should depend on them.
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Required Reading
 | 
			
		||||
@ -23,7 +23,7 @@ Before thinking about contributing, make sure that:
 | 
			
		||||
 | 
			
		||||
- You are not, nor have ever been, an employee of Microsoft Corporation.
 | 
			
		||||
 | 
			
		||||
- You have not signed any NDAs or Shared Source Agreements with Microsoft 
 | 
			
		||||
- You have not signed any NDAs or Shared Source Agreements with Microsoft
 | 
			
		||||
  Corporation or a subsidiary
 | 
			
		||||
 | 
			
		||||
- You have not consulted any existing relevant codebase (if you have, please
 | 
			
		||||
@ -42,11 +42,11 @@ Keep these in mind as you work:
 | 
			
		||||
  consult in the process (and be extra careful not to use unlicensed code on
 | 
			
		||||
  the internet.
 | 
			
		||||
 | 
			
		||||
- You are working on your own time.  Unless they explicitly grant permission, 
 | 
			
		||||
- You are working on your own time.  Unless they explicitly grant permission,
 | 
			
		||||
  your employer may be the ultimate owner of your IP
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
# Post-Contribution 
 | 
			
		||||
# Post-Contribution
 | 
			
		||||
 | 
			
		||||
Before contributions are merged, you will receive an email (at the address
 | 
			
		||||
associated with the git commit) and will be asked to confirm the aforementioned
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								LICENSE
									
									
									
									
									
								
							@ -1,4 +1,4 @@
 | 
			
		||||
Copyright (C) 2012-2014 SheetJS 
 | 
			
		||||
Copyright (C) 2012-2014  SheetJS
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										8
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										8
									
								
								Makefile
									
									
									
									
									
								
							@ -1,7 +1,7 @@
 | 
			
		||||
LIB=xlsx
 | 
			
		||||
DEPS=$(wildcard bits/*.js)
 | 
			
		||||
TARGET=$(LIB).js
 | 
			
		||||
FMT=xlsx xlsm xlsb misc
 | 
			
		||||
FMT=xlsx xlsm xlsb misc full
 | 
			
		||||
REQS=jszip.js
 | 
			
		||||
ADDONS=dist/cpexcel.js
 | 
			
		||||
 | 
			
		||||
@ -25,6 +25,7 @@ init:
 | 
			
		||||
 | 
			
		||||
.PHONY: test mocha
 | 
			
		||||
test mocha: test.js
 | 
			
		||||
	mkdir -p tmp
 | 
			
		||||
	mocha -R spec
 | 
			
		||||
 | 
			
		||||
TESTFMT=$(patsubst %,test_%,$(FMT))
 | 
			
		||||
@ -42,6 +43,11 @@ cov: misc/coverage.html
 | 
			
		||||
cov-spin:
 | 
			
		||||
	make cov & bash misc/spin.sh $$!
 | 
			
		||||
 | 
			
		||||
COVFMT=$(patsubst %,cov_%,$(FMT))
 | 
			
		||||
.PHONY: $(COVFMT)
 | 
			
		||||
$(COVFMT): cov_%:
 | 
			
		||||
	FMTS=$* make cov
 | 
			
		||||
 | 
			
		||||
misc/coverage.html: $(TARGET) test.js
 | 
			
		||||
	mocha --require blanket -R html-cov > $@
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										44
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										44
									
								
								README.md
									
									
									
									
									
								
							@ -1,6 +1,6 @@
 | 
			
		||||
# xlsx
 | 
			
		||||
 | 
			
		||||
Currently a parser for XLSX/XLSM/XLSB files.  Cleanroom implementation from the
 | 
			
		||||
Parser and writer for XLSX/XLSM/XLSB files.  Cleanroom implementation from the
 | 
			
		||||
ISO 29500  Office Open XML specifications, [MS-XLSB], and related documents.
 | 
			
		||||
 | 
			
		||||
## Installation
 | 
			
		||||
@ -45,7 +45,7 @@ The complete single-file version is generated at `dist/xlsx.full.min.js`
 | 
			
		||||
 | 
			
		||||
Simple usage (walks through every cell of every sheet and dumps the values):
 | 
			
		||||
 | 
			
		||||
    var XLSX = require('xlsx');
 | 
			
		||||
    if(typeof require !== 'undefined') XLSX = require('xlsx');
 | 
			
		||||
    var workbook = XLSX.readFile('test.xlsx');
 | 
			
		||||
    var sheet_name_list = workbook.SheetNames;
 | 
			
		||||
    sheet_name_list.forEach(function(y) {
 | 
			
		||||
@ -56,9 +56,9 @@ Simple usage (walks through every cell of every sheet and dumps the values):
 | 
			
		||||
      }
 | 
			
		||||
    });
 | 
			
		||||
 | 
			
		||||
The node version installs a binary `xlsx2csv` which can read XLSX/XLSM/XLSB
 | 
			
		||||
The node version installs a binary `xlsx` which can read XLSX/XLSM/XLSB
 | 
			
		||||
files and output the contents in various formats.  The source is available at
 | 
			
		||||
`xlsx2csv.njs` in the bin directory.
 | 
			
		||||
`xlsx.njs` in the bin directory.
 | 
			
		||||
 | 
			
		||||
See <http://oss.sheetjs.com/js-xlsx/> for a browser example.
 | 
			
		||||
 | 
			
		||||
@ -76,12 +76,27 @@ Some helper functions in `XLSX.utils` generate different views of the sheets:
 | 
			
		||||
 | 
			
		||||
For more details:
 | 
			
		||||
 | 
			
		||||
- `bin/xlsx2csv.njs` is a tool for node
 | 
			
		||||
- `bin/xlsx.njs` is a tool for node
 | 
			
		||||
- `index.html` is the live demo
 | 
			
		||||
- `bits/90_utils.js` contains the logic for generating CSV and JSON from sheets
 | 
			
		||||
 | 
			
		||||
## Interface
 | 
			
		||||
 | 
			
		||||
`XLSX` is the exposed variable in the browser and the exported variable in node
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
`XLSX.read(data, read_opts)` attempts to parse `data`.
 | 
			
		||||
 | 
			
		||||
`XLSX.readFile(filename, read_opts)` attempts to read `filename` and parse.
 | 
			
		||||
 | 
			
		||||
`XLSX.write(wb, write_opts)` attempts to write the workbook `wb`
 | 
			
		||||
 | 
			
		||||
`XLSX.writeFile(wb, filename, write_opts)` attempts to write `wb` to `filename`
 | 
			
		||||
 | 
			
		||||
## Cell Object Description
 | 
			
		||||
 | 
			
		||||
js-xlsx conforms to the Common Spreadsheet Format (CSF):
 | 
			
		||||
 | 
			
		||||
`.SheetNames` is an ordered list of the sheets in the workbook
 | 
			
		||||
 | 
			
		||||
`.Sheets[sheetname]` returns a data structure representing the sheet.  Each key
 | 
			
		||||
@ -102,7 +117,7 @@ that does not start with `!` corresponds to a cell (using `A-1` notation).
 | 
			
		||||
 | 
			
		||||
For dates, `.v` holds the raw date code from the sheet and `.w` holds the text
 | 
			
		||||
 | 
			
		||||
## Options
 | 
			
		||||
## Parsing Options
 | 
			
		||||
 | 
			
		||||
The exported `read` and `readFile` functions accept an options argument:
 | 
			
		||||
 | 
			
		||||
@ -133,6 +148,21 @@ The exported `read` and `readFile` functions accept an options argument:
 | 
			
		||||
 | 
			
		||||
The defaults are enumerated in bits/84_defaults.js
 | 
			
		||||
 | 
			
		||||
## Writing Options
 | 
			
		||||
 | 
			
		||||
The exported `write` and `writeFile` functions accept an options argument:
 | 
			
		||||
 | 
			
		||||
| Option Name | Default | Description |
 | 
			
		||||
| :---------- | ------: | :---------- |
 | 
			
		||||
| bookSST     | false   | Generate Shared String Table ** |
 | 
			
		||||
| bookType    | 'xlsx'  | Type of Workbook ("xlsx" or "xlsm" or "xlsb") |
 | 
			
		||||
 | 
			
		||||
- `bookSST` is slower and more memory intensive, but has better compatibility
 | 
			
		||||
  with iOS Numbers
 | 
			
		||||
- `bookType = 'xlsb'` is stubbed and far from complete 
 | 
			
		||||
- The raw data is the only thing guaranteed to be saved.  Formulae, formatting,
 | 
			
		||||
  and other niceties are not serialized (pending CSF standardization)
 | 
			
		||||
 | 
			
		||||
## Tested Environments
 | 
			
		||||
 | 
			
		||||
 - Node 0.8, 0.10 (latest release)
 | 
			
		||||
@ -165,6 +195,8 @@ $ simplehttpserver # or "python -mSimpleHTTPServer" or "serve"
 | 
			
		||||
$ open -a Chromium.app http://localhost:8000/stress.html
 | 
			
		||||
```
 | 
			
		||||
 | 
			
		||||
For a much smaller test, run `make test_misc`.
 | 
			
		||||
 | 
			
		||||
## Contributing
 | 
			
		||||
 | 
			
		||||
Due to the precarious nature of the Open Specifications Promise, it is very
 | 
			
		||||
 | 
			
		||||
@ -10,9 +10,13 @@ program
 | 
			
		||||
	.option('-f, --file <file>', 'use specified workbook')
 | 
			
		||||
	.option('-s, --sheet <sheet>', 'print specified sheet (default first sheet)')
 | 
			
		||||
	.option('-l, --list-sheets', 'list sheet names and exit')
 | 
			
		||||
	.option('-o, --output <file>', 'output to specified file')
 | 
			
		||||
	/*.option('-B, --xlsb', 'emit XLSB to <sheetname> or <file>.xlsb') */
 | 
			
		||||
	.option('-M, --xlsm', 'emit XLSM to <sheetname> or <file>.xlsm')
 | 
			
		||||
	.option('-X, --xlsx', 'emit XLSX to <sheetname> or <file>.xlsx')
 | 
			
		||||
	.option('-S, --formulae', 'print formulae')
 | 
			
		||||
	.option('-j, --json', 'emit formatted JSON rather than CSV (all fields text)')
 | 
			
		||||
	.option('-J, --raw-js', 'emit raw JS object rather than CSV (raw numbers)')
 | 
			
		||||
	.option('-j, --json', 'emit formatted JSON (all fields text)')
 | 
			
		||||
	.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
 | 
			
		||||
	.option('-F, --field-sep <sep>', 'CSV field separator', ",")
 | 
			
		||||
	.option('-R, --row-sep <sep>', 'CSV row separator', "\n")
 | 
			
		||||
	.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)')
 | 
			
		||||
@ -21,6 +25,7 @@ program
 | 
			
		||||
	.option('-q, --quiet', 'quiet mode');
 | 
			
		||||
 | 
			
		||||
program.on('--help', function() {
 | 
			
		||||
	console.log('  Default output format is CSV');
 | 
			
		||||
	console.log('  Support email: dev@sheetjs.com');
 | 
			
		||||
	console.log('  Web Demo: http://oss.sheetjs.com/js-'+n+'/');
 | 
			
		||||
});
 | 
			
		||||
@ -36,19 +41,22 @@ if(program.sheet) sheetname = program.sheet;
 | 
			
		||||
if(program.file) filename = program.file;
 | 
			
		||||
 | 
			
		||||
if(!filename) {
 | 
			
		||||
	console.error(n + "2csv: must specify a filename");
 | 
			
		||||
	console.error(n + ": must specify a filename");
 | 
			
		||||
	process.exit(1);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if(!fs.existsSync(filename)) {
 | 
			
		||||
	console.error(n + "2csv: " + filename + ": No such file or directory");
 | 
			
		||||
	console.error(n + ": " + filename + ": No such file or directory");
 | 
			
		||||
	process.exit(2);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var opts = {}, wb;
 | 
			
		||||
if(program.listSheets) opts.bookSheets = true;
 | 
			
		||||
if(program.sheetRows) opts.sheetRows = program.sheetRows;
 | 
			
		||||
 | 
			
		||||
if(program.xlsx || program.xlsm || program.xlsb) {
 | 
			
		||||
	opts.cellNF = true;
 | 
			
		||||
	if(program.output) sheetname = program.output;
 | 
			
		||||
}
 | 
			
		||||
if(program.dev) {
 | 
			
		||||
	X.verbose = 2;
 | 
			
		||||
	opts.WTF = true;
 | 
			
		||||
@ -57,7 +65,7 @@ if(program.dev) {
 | 
			
		||||
else try {
 | 
			
		||||
	wb = X.readFile(filename, opts);
 | 
			
		||||
} catch(e) {
 | 
			
		||||
	var msg = (program.quiet) ? "" : n + "2csv: error parsing ";
 | 
			
		||||
	var msg = (program.quiet) ? "" : n + ": error parsing ";
 | 
			
		||||
	msg += filename + ": " + e;
 | 
			
		||||
	console.error(msg);
 | 
			
		||||
	process.exit(3);
 | 
			
		||||
@ -69,6 +77,12 @@ if(program.listSheets) {
 | 
			
		||||
	process.exit(0);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var wopts = {WTF:opts.WTF};
 | 
			
		||||
 | 
			
		||||
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);
 | 
			
		||||
 | 
			
		||||
var target_sheet = sheetname || '';
 | 
			
		||||
if(target_sheet === '') target_sheet = wb.SheetNames[0];
 | 
			
		||||
 | 
			
		||||
@ -77,12 +91,15 @@ try {
 | 
			
		||||
	ws = wb.Sheets[target_sheet];
 | 
			
		||||
	if(!ws) throw "Sheet " + target_sheet + " cannot be found";
 | 
			
		||||
} catch(e) {
 | 
			
		||||
	console.error(n + "2csv: error parsing "+filename+" "+target_sheet+": " + e);
 | 
			
		||||
	console.error(n + ": error parsing "+filename+" "+target_sheet+": " + e);
 | 
			
		||||
	process.exit(4);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
if(!program.quiet) console.error(target_sheet);
 | 
			
		||||
if(program.formulae) console.log(X.utils.get_formulae(ws).join("\n"));
 | 
			
		||||
else if(program.json) console.log(JSON.stringify(X.utils.sheet_to_row_object_array(ws)));
 | 
			
		||||
else if(program.rawJs) console.log(JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true})));
 | 
			
		||||
else console.log(X.utils.make_csv(ws, {FS:program.fieldSep, RS:program.rowSep}));
 | 
			
		||||
var oo = ""; 
 | 
			
		||||
if(program.formulae) oo = X.utils.get_formulae(ws).join("\n");
 | 
			
		||||
else if(program.json) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws));
 | 
			
		||||
else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true}));
 | 
			
		||||
else oo = X.utils.make_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
 | 
			
		||||
 | 
			
		||||
if(program.output) fs.writeFileSync(program.output, oo);
 | 
			
		||||
@ -1 +1 @@
 | 
			
		||||
XLSX.version = '0.6.2';
 | 
			
		||||
XLSX.version = '0.7.0';
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										13
									
								
								bits/30_jsutils.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										13
									
								
								bits/30_jsutils.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,13 @@
 | 
			
		||||
function isval(x) { return typeof x !== "undefined" && x !== null; }
 | 
			
		||||
 | 
			
		||||
function keys(o) { return Object.keys(o).filter(function(x) { return o.hasOwnProperty(x); }); }
 | 
			
		||||
 | 
			
		||||
function evert(obj, arr) {
 | 
			
		||||
	var o = {};
 | 
			
		||||
	keys(obj).forEach(function(k) {
 | 
			
		||||
		if(!obj.hasOwnProperty(k)) return;
 | 
			
		||||
		if(!arr) o[obj[k]] = k;
 | 
			
		||||
		else (o[obj[k]]=o[obj[k]]||[]).push(k);
 | 
			
		||||
	});
 | 
			
		||||
	return o;
 | 
			
		||||
}
 | 
			
		||||
@ -1,4 +1,5 @@
 | 
			
		||||
var _chr = function(c) { return String.fromCharCode(c); };
 | 
			
		||||
var _ord = function(c) { return c.charCodeAt(0); };
 | 
			
		||||
var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
 | 
			
		||||
var attregex=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
 | 
			
		||||
function parsexmltag(tag) {
 | 
			
		||||
@ -13,12 +14,6 @@ function parsexmltag(tag) {
 | 
			
		||||
	return z;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function evert(obj) {
 | 
			
		||||
	var o = {};
 | 
			
		||||
	Object.keys(obj).forEach(function(k) { if(obj.hasOwnProperty(k)) o[obj[k]] = k; });
 | 
			
		||||
	return o;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var encodings = {
 | 
			
		||||
	'"': '"',
 | 
			
		||||
	''': "'",
 | 
			
		||||
@ -38,6 +33,7 @@ function unescapexml(text){
 | 
			
		||||
function escapexml(text){
 | 
			
		||||
	var s = text + '';
 | 
			
		||||
	rencstr.forEach(function(y){s=s.replace(new RegExp(y,'g'), rencoding[y]);});
 | 
			
		||||
	s = s.replace(/[\u0000-\u0007]/g,function(s) { return "_x" + ("0000"+_ord(s).toString(16)).substr(-4) + "_";}); /* TODO: verify range */
 | 
			
		||||
	return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -83,4 +79,37 @@ function parseVector(data) {
 | 
			
		||||
	return res;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function isval(x) { return typeof x !== "undefined" && x !== null; }
 | 
			
		||||
function writetag(f,g) {return '<' + f + (g.match(/(^\s|\s$|\n)/)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>';}
 | 
			
		||||
 | 
			
		||||
/*jshint -W041 */
 | 
			
		||||
function writextag(f,g,h) { return '<' + f + (h != null ? keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join("") : "") + (g == null ? "/" : (g.match(/(^\s|\s$|\n)/)?' xml:space="preserve"' : "") + '>' + g + '</' + f) + '>';}
 | 
			
		||||
 | 
			
		||||
function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } }
 | 
			
		||||
 | 
			
		||||
function write_vt(s) {
 | 
			
		||||
	if(typeof s == 'string') return writextag('vt:lpwstr', s);
 | 
			
		||||
	if(typeof s == 'number') return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
 | 
			
		||||
	if(typeof s == 'boolean') return writextag('vt:bool', s?'true':'false');
 | 
			
		||||
	if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
 | 
			
		||||
	throw new Error("Unable to serialize " + s);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
 | 
			
		||||
var XMLNS = {
 | 
			
		||||
	'dc': 'http://purl.org/dc/elements/1.1/',
 | 
			
		||||
	'dcterms': 'http://purl.org/dc/terms/',
 | 
			
		||||
	'dcmitype': 'http://purl.org/dc/dcmitype/',
 | 
			
		||||
	'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
 | 
			
		||||
	'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
 | 
			
		||||
	'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
 | 
			
		||||
	'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
 | 
			
		||||
	'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
 | 
			
		||||
	'xsd': 'http://www.w3.org/2001/XMLSchema'
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
XMLNS.main = [
 | 
			
		||||
	'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
 | 
			
		||||
	'http://purl.oclc.org/ooxml/spreadsheetml/main',
 | 
			
		||||
	'http://schemas.microsoft.com/office/excel/2006/main',
 | 
			
		||||
	'http://schemas.microsoft.com/office/excel/2006/2'
 | 
			
		||||
];
 | 
			
		||||
@ -13,3 +13,8 @@ var recordhopper = function(data, cb, opts) {
 | 
			
		||||
		if(cb(d, R, RT)) return;
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* control buffer usage for fixed-length buffers */
 | 
			
		||||
var blobhopper = function() {
 | 
			
		||||
	var bufs = [];
 | 
			
		||||
};
 | 
			
		||||
@ -5,15 +5,9 @@
 | 
			
		||||
/* [MS-XLSB] 2.1.7 Part Enumeration */
 | 
			
		||||
var ct2type = {
 | 
			
		||||
	/* Workbook */
 | 
			
		||||
	"application/vnd.ms-excel.main": "workbooks",
 | 
			
		||||
	"application/vnd.ms-excel.sheet.macroEnabled.main+xml": "workbooks",
 | 
			
		||||
	"application/vnd.ms-excel.sheet.binary.macroEnabled.main": "workbooks",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml": "TODO", /* Template */
 | 
			
		||||
 | 
			
		||||
	/* Worksheet */
 | 
			
		||||
	"application/vnd.ms-excel.worksheet": "sheets",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml": "sheets",
 | 
			
		||||
	"application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
 | 
			
		||||
 | 
			
		||||
	/* Chartsheet */
 | 
			
		||||
@ -30,14 +24,6 @@ var ct2type = {
 | 
			
		||||
	"application/vnd.ms-excel.intlmacrosheet": "TODO",
 | 
			
		||||
	"application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
 | 
			
		||||
 | 
			
		||||
	/* Shared Strings */
 | 
			
		||||
	"application/vnd.ms-excel.sharedStrings": "strs",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml": "strs",
 | 
			
		||||
 | 
			
		||||
	/* Styles */
 | 
			
		||||
	"application/vnd.ms-excel.styles": "styles",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml": "styles",
 | 
			
		||||
 | 
			
		||||
	/* File Properties */
 | 
			
		||||
	"application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
 | 
			
		||||
@ -151,99 +137,48 @@ var ct2type = {
 | 
			
		||||
	/* VML */
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
 | 
			
		||||
 | 
			
		||||
	"application/vnd.openxmlformats-package.relationships+xml": "TODO",
 | 
			
		||||
	"application/vnd.openxmlformats-package.relationships+xml": "rels",
 | 
			
		||||
	"application/vnd.openxmlformats-officedocument.oleObject": "TODO",
 | 
			
		||||
 | 
			
		||||
	"foo": "bar"
 | 
			
		||||
	"sheet": "js"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var XMLNS_CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
 | 
			
		||||
 | 
			
		||||
function parseProps(data) {
 | 
			
		||||
	var p = { Company:'' }, q = {};
 | 
			
		||||
	var strings = ["Application", "DocSecurity", "Company", "AppVersion"];
 | 
			
		||||
	var bools = ["HyperlinksChanged","SharedDoc","LinksUpToDate","ScaleCrop"];
 | 
			
		||||
	var xtra = ["HeadingPairs", "TitlesOfParts"];
 | 
			
		||||
	var xtracp = ["category", "contentStatus", "lastModifiedBy", "lastPrinted", "revision", "version"];
 | 
			
		||||
	var xtradc = ["creator", "description", "identifier", "language", "subject", "title"];
 | 
			
		||||
	var xtradcterms = ["created", "modified"];
 | 
			
		||||
	xtra = xtra.concat(xtracp.map(function(x) { return "cp:" + x; }));
 | 
			
		||||
	xtra = xtra.concat(xtradc.map(function(x) { return "dc:" + x; }));
 | 
			
		||||
	xtra = xtra.concat(xtradcterms.map(function(x) { return "dcterms:" + x; }));
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
	strings.forEach(function(f){p[f] = (data.match(matchtag(f))||[])[1];});
 | 
			
		||||
	bools.forEach(function(f){p[f] = (data.match(matchtag(f))||[])[1] == "true";});
 | 
			
		||||
	xtra.forEach(function(f) {
 | 
			
		||||
		var cur = data.match(new RegExp("<" + f + "[^>]*>(.*)<\/" + f + ">"));
 | 
			
		||||
		if(cur && cur.length > 0) q[f] = cur[1];
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	if(q.HeadingPairs && q.TitlesOfParts) {
 | 
			
		||||
		var v = parseVector(q.HeadingPairs);
 | 
			
		||||
		var j = 0, widx = 0;
 | 
			
		||||
		for(var i = 0; i !== v.length; ++i) {
 | 
			
		||||
			switch(v[i].v) {
 | 
			
		||||
				case "Worksheets": widx = j; p.Worksheets = +(v[++i].v); break;
 | 
			
		||||
				case "Named Ranges": ++i; break; // TODO: Handle Named Ranges
 | 
			
		||||
			}
 | 
			
		||||
var CT_LIST = (function(){
 | 
			
		||||
	var o = {
 | 
			
		||||
		workbooks: {
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
 | 
			
		||||
			xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
 | 
			
		||||
			xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
 | 
			
		||||
		},
 | 
			
		||||
		strs: { /* Shared Strings */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.sharedStrings"
 | 
			
		||||
		},
 | 
			
		||||
		sheets: {
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.worksheet"
 | 
			
		||||
		},
 | 
			
		||||
		styles: {/* Styles */
 | 
			
		||||
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
 | 
			
		||||
			xlsb: "application/vnd.ms-excel.styles"
 | 
			
		||||
		}
 | 
			
		||||
		var parts = parseVector(q.TitlesOfParts).map(function(x) { return utf8read(x.v); });
 | 
			
		||||
		p.SheetNames = parts.slice(widx, widx + p.Worksheets);
 | 
			
		||||
	}
 | 
			
		||||
	p.Creator = q["dc:creator"];
 | 
			
		||||
	p.LastModifiedBy = q["cp:lastModifiedBy"];
 | 
			
		||||
	p.CreatedDate = new Date(q["dcterms:created"]);
 | 
			
		||||
	p.ModifiedDate = new Date(q["dcterms:modified"]);
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
	};
 | 
			
		||||
	keys(o).forEach(function(k) { if(!o[k].xlsm) o[k].xlsm = o[k].xlsx; });
 | 
			
		||||
	keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
 | 
			
		||||
	return o;
 | 
			
		||||
})();
 | 
			
		||||
 | 
			
		||||
/* 15.2.12.2 Custom File Properties Part */
 | 
			
		||||
function parseCustomProps(data) {
 | 
			
		||||
	var p = {}, name;
 | 
			
		||||
	data.match(/<[^>]+>([^<]*)/g).forEach(function(x) {
 | 
			
		||||
		var y = parsexmltag(x);
 | 
			
		||||
		switch(y[0]) {
 | 
			
		||||
			case '<property': name = y.name; break;
 | 
			
		||||
			case '</property>': name = null; break;
 | 
			
		||||
			default: if (x.indexOf('<vt:') === 0) {
 | 
			
		||||
				var toks = x.split('>');
 | 
			
		||||
				var type = toks[0].substring(4), text = toks[1];
 | 
			
		||||
				/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
 | 
			
		||||
				switch(type) {
 | 
			
		||||
					case 'lpstr': case 'lpwstr': case 'bstr': case 'lpwstr':
 | 
			
		||||
						p[name] = unescapexml(text);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'bool':
 | 
			
		||||
						p[name] = parsexmlbool(text, '<vt:bool>');
 | 
			
		||||
						break;
 | 
			
		||||
					case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
 | 
			
		||||
						p[name] = parseInt(text, 10);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'r4': case 'r8': case 'decimal':
 | 
			
		||||
						p[name] = parseFloat(text);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'filetime': case 'date':
 | 
			
		||||
						p[name] = text; // should we make this into a date?
 | 
			
		||||
						break;
 | 
			
		||||
					case 'cy': case 'error':
 | 
			
		||||
						p[name] = unescapexml(text);
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						console.warn('Unexpected', x, type, toks);
 | 
			
		||||
				}
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
var type2ct = evert(ct2type, true);
 | 
			
		||||
 | 
			
		||||
var ctext = {};
 | 
			
		||||
function parseCT(data, opts) {
 | 
			
		||||
XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
 | 
			
		||||
 | 
			
		||||
function parse_ct(data, opts) {
 | 
			
		||||
	var ctext = {};
 | 
			
		||||
	if(!data || !data.match) return data;
 | 
			
		||||
	var ct = { workbooks: [], sheets: [], calcchains: [], themes: [], styles: [],
 | 
			
		||||
		coreprops: [], extprops: [], custprops: [], strs:[], comments: [], vba: [],
 | 
			
		||||
		TODO:[], xmlns: "" };
 | 
			
		||||
		TODO:[], rels:[], xmlns: "" };
 | 
			
		||||
	(data.match(/<[^>]*>/g)||[]).forEach(function(x) {
 | 
			
		||||
		var y = parsexmltag(x);
 | 
			
		||||
		switch(y[0]) {
 | 
			
		||||
@ -252,11 +187,11 @@ function parseCT(data, opts) {
 | 
			
		||||
			case '<Default': ctext[y.Extension] = y.ContentType; break;
 | 
			
		||||
			case '<Override':
 | 
			
		||||
				if(y.ContentType in ct2type)ct[ct2type[y.ContentType]].push(y.PartName);
 | 
			
		||||
				else if(opts.WTF) console.error(y.ContentType);
 | 
			
		||||
				else if(opts.WTF) console.error(y);
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	if(ct.xmlns !== XMLNS_CT) throw new Error("Unknown Namespace: " + ct.xmlns);
 | 
			
		||||
	if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
 | 
			
		||||
	ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
 | 
			
		||||
	ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
 | 
			
		||||
	ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
 | 
			
		||||
@ -265,44 +200,54 @@ function parseCT(data, opts) {
 | 
			
		||||
	return ct;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var CTYPE_XML_ROOT = writextag('Types', null, {
 | 
			
		||||
	'xmlns': XMLNS.CT,
 | 
			
		||||
	'xmlns:xsd': XMLNS.xsd,
 | 
			
		||||
	'xmlns:xsi': XMLNS.xsi
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var CTYPE_DEFAULTS = [
 | 
			
		||||
	['xml', 'application/xml'],
 | 
			
		||||
	['rels', type2ct.rels[0]]
 | 
			
		||||
].map(function(x) {
 | 
			
		||||
	return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* 9.3.2 OPC Relationships Markup */
 | 
			
		||||
function parseRels(data, currentFilePath) {
 | 
			
		||||
	if (!data) return data;
 | 
			
		||||
	if (currentFilePath.charAt(0) !== '/') {
 | 
			
		||||
		currentFilePath = '/'+currentFilePath;
 | 
			
		||||
	}
 | 
			
		||||
	var rels = {};
 | 
			
		||||
	var hash = {};
 | 
			
		||||
	var resolveRelativePathIntoAbsolute = function (to) {
 | 
			
		||||
		var toksFrom = currentFilePath.split('/');
 | 
			
		||||
		toksFrom.pop(); // folder path
 | 
			
		||||
		var toksTo = to.split('/');
 | 
			
		||||
		var reversed = [];
 | 
			
		||||
		while (toksTo.length !== 0) {
 | 
			
		||||
			var tokTo = toksTo.shift();
 | 
			
		||||
			if (tokTo === '..') {
 | 
			
		||||
				toksFrom.pop();
 | 
			
		||||
			} else if (tokTo !== '.') {
 | 
			
		||||
				toksFrom.push(tokTo);
 | 
			
		||||
			}
 | 
			
		||||
function write_ct(ct, opts) {
 | 
			
		||||
	var o = [], v;
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(CTYPE_XML_ROOT);
 | 
			
		||||
	o = o.concat(CTYPE_DEFAULTS);
 | 
			
		||||
	var f1 = function(w) {
 | 
			
		||||
		if(ct[w] && ct[w].length > 0) {
 | 
			
		||||
			v = ct[w][0];
 | 
			
		||||
			o.push(writextag('Override', null, {
 | 
			
		||||
				'PartName': (v[0] == '/' ? "":"/") + v,
 | 
			
		||||
				'ContentType': CT_LIST[w][opts.bookType || 'xlsx'] 
 | 
			
		||||
			}));
 | 
			
		||||
		}
 | 
			
		||||
		return toksFrom.join('/');
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	data.match(/<[^>]*>/g).forEach(function(x) {
 | 
			
		||||
		var y = parsexmltag(x);
 | 
			
		||||
		/* 9.3.2.2 OPC_Relationships */
 | 
			
		||||
		if (y[0] === '<Relationship') {
 | 
			
		||||
			var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
 | 
			
		||||
			var canonictarget = y.TargetMode === 'External' ? y.Target : resolveRelativePathIntoAbsolute(y.Target);
 | 
			
		||||
			rels[canonictarget] = rel;
 | 
			
		||||
			hash[y.Id] = rel;
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	rels["!id"] = hash;
 | 
			
		||||
	return rels;
 | 
			
		||||
	var f2 = function(w) {
 | 
			
		||||
		ct[w].forEach(function(v) {
 | 
			
		||||
			o.push(writextag('Override', null, {
 | 
			
		||||
				'PartName': (v[0] == '/' ? "":"/") + v,
 | 
			
		||||
				'ContentType': CT_LIST[w][opts.bookType || 'xlsx'] 
 | 
			
		||||
			}));
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
	var f3 = function(t) {
 | 
			
		||||
		(ct[t]||[]).forEach(function(v) {
 | 
			
		||||
			o.push(writextag('Override', null, {
 | 
			
		||||
				'PartName': (v[0] == '/' ? "":"/") + v,
 | 
			
		||||
				'ContentType': type2ct[t][0]
 | 
			
		||||
			}));
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
	f1('workbooks');
 | 
			
		||||
	f2('sheets');
 | 
			
		||||
	f3('themes');	
 | 
			
		||||
	['strs', 'styles'].forEach(f1);
 | 
			
		||||
	['coreprops', 'extprops', 'custprops'].forEach(f3);
 | 
			
		||||
	if(o.length>2){ o.push('</Types>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										61
									
								
								bits/41_rels.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										61
									
								
								bits/41_rels.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,61 @@
 | 
			
		||||
/* 9.3.2 OPC Relationships Markup */
 | 
			
		||||
var RELS = {
 | 
			
		||||
	WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
 | 
			
		||||
	SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument"
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
function parse_rels(data, currentFilePath) {
 | 
			
		||||
	if (!data) return data;
 | 
			
		||||
	if (currentFilePath.charAt(0) !== '/') {
 | 
			
		||||
		currentFilePath = '/'+currentFilePath;
 | 
			
		||||
	}
 | 
			
		||||
	var rels = {};
 | 
			
		||||
	var hash = {};
 | 
			
		||||
	var resolveRelativePathIntoAbsolute = function (to) {
 | 
			
		||||
		var toksFrom = currentFilePath.split('/');
 | 
			
		||||
		toksFrom.pop(); // folder path
 | 
			
		||||
		var toksTo = to.split('/');
 | 
			
		||||
		var reversed = [];
 | 
			
		||||
		while (toksTo.length !== 0) {
 | 
			
		||||
			var tokTo = toksTo.shift();
 | 
			
		||||
			if (tokTo === '..') {
 | 
			
		||||
				toksFrom.pop();
 | 
			
		||||
			} else if (tokTo !== '.') {
 | 
			
		||||
				toksFrom.push(tokTo);
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		return toksFrom.join('/');
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	data.match(/<[^>]*>/g).forEach(function(x) {
 | 
			
		||||
		var y = parsexmltag(x);
 | 
			
		||||
		/* 9.3.2.2 OPC_Relationships */
 | 
			
		||||
		if (y[0] === '<Relationship') {
 | 
			
		||||
			var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
 | 
			
		||||
			var canonictarget = y.TargetMode === 'External' ? y.Target : resolveRelativePathIntoAbsolute(y.Target);
 | 
			
		||||
			rels[canonictarget] = rel;
 | 
			
		||||
			hash[y.Id] = rel;
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	rels["!id"] = hash;
 | 
			
		||||
	return rels;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
 | 
			
		||||
 | 
			
		||||
var RELS_ROOT = writextag('Relationships', null, {
 | 
			
		||||
	//'xmlns:ns0': XMLNS.RELS,
 | 
			
		||||
	'xmlns': XMLNS.RELS
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
/* TODO */
 | 
			
		||||
function write_rels(rels) {
 | 
			
		||||
	var o = [];
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(RELS_ROOT);
 | 
			
		||||
	keys(rels['!id']).forEach(function(rid) { var rel = rels['!id'][rid];
 | 
			
		||||
		o.push(writextag('Relationship', null, rel));
 | 
			
		||||
	});
 | 
			
		||||
	if(o.length>2){ o.push('</Relationships>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										66
									
								
								bits/43_coreprops.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										66
									
								
								bits/43_coreprops.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,66 @@
 | 
			
		||||
/* ECMA-376 Part II 11.1 Core Properties Part */
 | 
			
		||||
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
 | 
			
		||||
var CORE_PROPS = [
 | 
			
		||||
	["cp:category", "Category"],
 | 
			
		||||
	["cp:contentStatus", "ContentStatus"],
 | 
			
		||||
	["cp:keywords", "Keywords"],
 | 
			
		||||
	["cp:lastModifiedBy", "LastAuthor"],
 | 
			
		||||
	["cp:lastPrinted", "LastPrinted"],
 | 
			
		||||
	["cp:revision", "RevNumber"],
 | 
			
		||||
	["cp:version", "Version"],
 | 
			
		||||
	["dc:creator", "Author"],
 | 
			
		||||
	["dc:description", "Comments"],
 | 
			
		||||
	["dc:identifier", "Identifier"],
 | 
			
		||||
	["dc:language", "Language"],
 | 
			
		||||
	["dc:subject", "Subject"],
 | 
			
		||||
	["dc:title", "Title"],
 | 
			
		||||
	["dcterms:created", "CreatedDate", 'date'],
 | 
			
		||||
	["dcterms:modified", "ModifiedDate", 'date']
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
 | 
			
		||||
RELS.CORE_PROPS  = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
function parse_core_props(data) {
 | 
			
		||||
	var p = {};
 | 
			
		||||
 | 
			
		||||
	CORE_PROPS.forEach(function(f) {
 | 
			
		||||
		var g = "(?:"+ f[0].substr(0,f[0].indexOf(":")) +":)"+ f[0].substr(f[0].indexOf(":")+1);
 | 
			
		||||
		var cur = data.match(new RegExp("<" + g + "[^>]*>(.*)<\/" + g + ">"));
 | 
			
		||||
		if(cur && cur.length > 0) p[f[1]] = cur[1];
 | 
			
		||||
		if(f[2] === 'date' && p[f[1]]) p[f[1]] = new Date(p[f[1]]);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
 | 
			
		||||
	//'xmlns': XMLNS.CORE_PROPS,
 | 
			
		||||
	'xmlns:cp': XMLNS.CORE_PROPS,
 | 
			
		||||
	'xmlns:dc': XMLNS.dc,
 | 
			
		||||
	'xmlns:dcterms': XMLNS.dcterms,
 | 
			
		||||
	'xmlns:dcmitype': XMLNS.dcmitype,
 | 
			
		||||
	'xmlns:xsi': XMLNS.xsi
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function write_core_props(cp, opts) {
 | 
			
		||||
	var o = [], p = {};
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(CORE_PROPS_XML_ROOT);
 | 
			
		||||
	if(!cp) return o.join("");
 | 
			
		||||
 | 
			
		||||
	var doit = function(f, g, h) {
 | 
			
		||||
		if(p[f] || typeof g === 'undefined' || g === "") return;
 | 
			
		||||
		if(typeof g !== 'string') g = String(g); /* TODO: remove */
 | 
			
		||||
		p[f] = g;
 | 
			
		||||
		o.push(h ? writextag(f,g,h) : writetag(f,g));
 | 
			
		||||
	};
 | 
			
		||||
 | 
			
		||||
	if(typeof cp.CreatedDate !== 'undefined') doit("dcterms:created", write_w3cdtf(cp.CreatedDate, opts.WTF), {"xsi:type":"dcterms:W3CDTF"});
 | 
			
		||||
	if(typeof cp.ModifiedDate !== 'undefined') doit("dcterms:modified", write_w3cdtf(cp.ModifiedDate, opts.WTF), {"xsi:type":"dcterms:W3CDTF"});
 | 
			
		||||
 | 
			
		||||
	CORE_PROPS.forEach(function(f) { doit(f[0], cp[f[1]]); });
 | 
			
		||||
	if(o.length>2){ o.push('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										75
									
								
								bits/44_extprops.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										75
									
								
								bits/44_extprops.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,75 @@
 | 
			
		||||
/* 15.2.12.3 Extended File Properties Part */
 | 
			
		||||
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
 | 
			
		||||
var EXT_PROPS = [
 | 
			
		||||
	["Application", "Application", "string"],
 | 
			
		||||
	["AppVersion", "AppVersion", "string"],
 | 
			
		||||
	["Company", "Company", "string"],
 | 
			
		||||
	["DocSecurity", "DocSecurity", "string"],
 | 
			
		||||
	["Manager", "Manager", "string"],
 | 
			
		||||
	["HyperlinksChanged", "HyperlinksChanged", "bool"],
 | 
			
		||||
	["SharedDoc", "SharedDoc", "bool"],
 | 
			
		||||
	["LinksUpToDate", "LinksUpToDate", "bool"],
 | 
			
		||||
	["ScaleCrop", "ScaleCrop", "bool"],
 | 
			
		||||
	["HeadingPairs", "HeadingPairs", "raw"],
 | 
			
		||||
	["TitlesOfParts", "TitlesOfParts", "raw"],
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
 | 
			
		||||
RELS.EXT_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
 | 
			
		||||
 | 
			
		||||
function parse_ext_props(data, p) {
 | 
			
		||||
	var q = {}; if(!p) p = {};
 | 
			
		||||
 | 
			
		||||
	EXT_PROPS.forEach(function(f) {
 | 
			
		||||
		switch(f[2]) {
 | 
			
		||||
			case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
 | 
			
		||||
			case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
 | 
			
		||||
			case "raw":
 | 
			
		||||
				var cur = data.match(new RegExp("<" + f[0] + "[^>]*>(.*)<\/" + f[0] + ">"));
 | 
			
		||||
				if(cur && cur.length > 0) q[f[1]] = cur[1];
 | 
			
		||||
				break;
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	if(q.HeadingPairs && q.TitlesOfParts) {
 | 
			
		||||
		var v = parseVector(q.HeadingPairs);
 | 
			
		||||
		var j = 0, widx = 0;
 | 
			
		||||
		for(var i = 0; i !== v.length; ++i) {
 | 
			
		||||
			switch(v[i].v) {
 | 
			
		||||
				case "Worksheets": widx = j; p.Worksheets = +(v[++i].v); break;
 | 
			
		||||
				case "Named Ranges": ++i; break; // TODO: Handle Named Ranges
 | 
			
		||||
			}
 | 
			
		||||
		}
 | 
			
		||||
		var parts = parseVector(q.TitlesOfParts).map(function(x) { return utf8read(x.v); });
 | 
			
		||||
		p.SheetNames = parts.slice(widx, widx + p.Worksheets);
 | 
			
		||||
	}
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
 | 
			
		||||
	'xmlns': XMLNS.EXT_PROPS,
 | 
			
		||||
	'xmlns:vt': XMLNS.vt
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function write_ext_props(cp, opts) {
 | 
			
		||||
	var o = [], p = {}, W = writextag;
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(EXT_PROPS_XML_ROOT);
 | 
			
		||||
	if(!cp) return o.join("");
 | 
			
		||||
 | 
			
		||||
	EXT_PROPS.forEach(function(f) {
 | 
			
		||||
		if(typeof cp[f[1]] === 'undefined') return;
 | 
			
		||||
		var v;
 | 
			
		||||
		switch(f[2]) {
 | 
			
		||||
			case 'string': v = cp[f[1]]; break;
 | 
			
		||||
			case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
 | 
			
		||||
		}
 | 
			
		||||
		if(typeof v !== 'undefined') o.push(W(f[0], v));
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	/* TODO: HeadingPairs, TitlesOfParts */
 | 
			
		||||
	o.push(W('HeadingPairs', W('vt:vector', W('vt:variant', '<vt:lpstr>Worksheets</vt:lpstr>')+W('vt:variant', W('vt:i4', String(cp.Worksheets))), {size:2, baseType:"variant"})));
 | 
			
		||||
	o.push(W('TitlesOfParts', W('vt:vector', cp.SheetNames.map(function(s) { return "<vt:lpstr>" + s + "</vt:lpstr>"; }).join(""), {size: cp.Worksheets, baseType:"lpstr"})));
 | 
			
		||||
	if(o.length>2){ o.push('</Properties>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										70
									
								
								bits/45_custprops.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										70
									
								
								bits/45_custprops.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,70 @@
 | 
			
		||||
/* 15.2.12.2 Custom File Properties Part */
 | 
			
		||||
XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
 | 
			
		||||
RELS.CUST_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
 | 
			
		||||
 | 
			
		||||
function parse_cust_props(data, opts) {
 | 
			
		||||
	var p = {}, name;
 | 
			
		||||
	data.match(/<[^>]+>([^<]*)/g).forEach(function(x) {
 | 
			
		||||
		var y = parsexmltag(x);
 | 
			
		||||
		switch(y[0]) {
 | 
			
		||||
			case '<?xml': break;
 | 
			
		||||
			case '<Properties':
 | 
			
		||||
				if(y.xmlns !== XMLNS.CUST_PROPS) throw "unrecognized xmlns " + y.xmlns;
 | 
			
		||||
				if(y.xmlnsvt && y.xmlnsvt !== XMLNS.vt) throw "unrecognized vt " + y.xmlnsvt;
 | 
			
		||||
				break;
 | 
			
		||||
			case '<property': name = y.name; break;
 | 
			
		||||
			case '</property>': name = null; break;
 | 
			
		||||
			default: if (x.indexOf('<vt:') === 0) {
 | 
			
		||||
				var toks = x.split('>');
 | 
			
		||||
				var type = toks[0].substring(4), text = toks[1];
 | 
			
		||||
				/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
 | 
			
		||||
				switch(type) {
 | 
			
		||||
					case 'lpstr': case 'lpwstr': case 'bstr': case 'lpwstr':
 | 
			
		||||
						p[name] = unescapexml(text);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'bool':
 | 
			
		||||
						p[name] = parsexmlbool(text, '<vt:bool>');
 | 
			
		||||
						break;
 | 
			
		||||
					case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
 | 
			
		||||
						p[name] = parseInt(text, 10);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'r4': case 'r8': case 'decimal':
 | 
			
		||||
						p[name] = parseFloat(text);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'filetime': case 'date':
 | 
			
		||||
						p[name] = new Date(text);
 | 
			
		||||
						break;
 | 
			
		||||
					case 'cy': case 'error':
 | 
			
		||||
						p[name] = unescapexml(text);
 | 
			
		||||
						break;
 | 
			
		||||
					default:
 | 
			
		||||
						console.warn('Unexpected', x, type, toks);
 | 
			
		||||
				}
 | 
			
		||||
			} else if(x.substr(0,2) === "</") {
 | 
			
		||||
			} else if(opts.WTF) throw new Error(x);
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	return p;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
 | 
			
		||||
	'xmlns': XMLNS.CUST_PROPS,
 | 
			
		||||
	'xmlns:vt': XMLNS.vt
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function write_cust_props(cp, opts) {
 | 
			
		||||
	var o = [], p = {};
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(CUST_PROPS_XML_ROOT);
 | 
			
		||||
	if(!cp) return o.join("");
 | 
			
		||||
	var pid = 1;
 | 
			
		||||
	keys(cp).forEach(function(k) { ++pid; 
 | 
			
		||||
		o.push(writextag('property', write_vt(cp[k]), {
 | 
			
		||||
			'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
 | 
			
		||||
			'pid': pid,
 | 
			
		||||
			'name': k
 | 
			
		||||
		}));
 | 
			
		||||
	});
 | 
			
		||||
	if(o.length>2){ o.push('</Properties>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
@ -19,7 +19,7 @@ var CS2CP = {
 | 
			
		||||
	222:   874, /* THAI */
 | 
			
		||||
	238:  1250, /* EASTEUROPE */
 | 
			
		||||
	255:  1252, /* OEM */
 | 
			
		||||
    69:   6969  /* MISC */
 | 
			
		||||
	69:   6969  /* MISC */
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
/* Parse a list of <r> tags */
 | 
			
		||||
@ -169,3 +169,18 @@ var parse_sst_xml = function(data, opts) {
 | 
			
		||||
	return s;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
 | 
			
		||||
 | 
			
		||||
var write_sst_xml = function(sst, opts) {
 | 
			
		||||
	if(!opts.bookSST) return "";
 | 
			
		||||
	var o = [];
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(writextag('sst', null, {
 | 
			
		||||
		xmlns: XMLNS.main[0],
 | 
			
		||||
		count: sst.Count,
 | 
			
		||||
		uniqueCount: sst.Unique
 | 
			
		||||
	}));
 | 
			
		||||
	sst.forEach(function(s) { o.push("<si>" + (s.r ? s.r : "<t>" + escapexml(s.t) + "</t>") + "</si>"); });	
 | 
			
		||||
	if(o.length>2){ o.push('</sst>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -20,3 +20,5 @@ var parse_sst_bin = function(data, opts) {
 | 
			
		||||
	});
 | 
			
		||||
	return s;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var write_sst_bin = function(sst, opts) { };
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,5 @@
 | 
			
		||||
/* 18.8.31 numFmts CT_NumFmts */
 | 
			
		||||
function parseNumFmts(t, opts) {
 | 
			
		||||
function parse_numFmts(t, opts) {
 | 
			
		||||
	styles.NumberFmt = [];
 | 
			
		||||
	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y];
 | 
			
		||||
	t[0].match(/<[^>]*>/g).forEach(function(x) {
 | 
			
		||||
@ -15,8 +15,21 @@ function parseNumFmts(t, opts) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_numFmts(NF, opts) {
 | 
			
		||||
	var o = [];
 | 
			
		||||
	o.push("<numFmts>");
 | 
			
		||||
	[[5,8],[23,26],[41,44],[63,66],[164,392]].forEach(function(r) {
 | 
			
		||||
		for(var i = r[0]; i <= r[1]; ++i) if(NF[i]) 
 | 
			
		||||
		o.push(writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
 | 
			
		||||
	});
 | 
			
		||||
	o.push("</numFmts>");
 | 
			
		||||
	if(o.length === 2) return "";
 | 
			
		||||
	o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 18.8.10 cellXfs CT_CellXfs */
 | 
			
		||||
function parseCXfs(t, opts) {
 | 
			
		||||
function parse_cellXfs(t, opts) {
 | 
			
		||||
	styles.CellXf = [];
 | 
			
		||||
	t[0].match(/<[^>]*>/g).forEach(function(x) {
 | 
			
		||||
		var y = parsexmltag(x);
 | 
			
		||||
@ -42,13 +55,23 @@ function parseCXfs(t, opts) {
 | 
			
		||||
	});
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_cellXfs(cellXfs) {
 | 
			
		||||
	var o = [];
 | 
			
		||||
	o.push(writextag('cellXfs',null));
 | 
			
		||||
	cellXfs.forEach(function(c) { o.push(writextag('xf', null, c)); });
 | 
			
		||||
	o.push("</cellXfs>");
 | 
			
		||||
	if(o.length === 2) return "";
 | 
			
		||||
	o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
/* 18.8 Styles CT_Stylesheet*/
 | 
			
		||||
function parse_sty_xml(data, opts) {
 | 
			
		||||
	/* 18.8.39 styleSheet CT_Stylesheet */
 | 
			
		||||
	var t;
 | 
			
		||||
 | 
			
		||||
	/* numFmts CT_NumFmts ? */
 | 
			
		||||
	if((t=data.match(/<numFmts([^>]*)>.*<\/numFmts>/))) parseNumFmts(t, opts);
 | 
			
		||||
	if((t=data.match(/<numFmts([^>]*)>.*<\/numFmts>/))) parse_numFmts(t, opts);
 | 
			
		||||
 | 
			
		||||
	/* fonts CT_Fonts ? */
 | 
			
		||||
	/* fills CT_Fills ? */
 | 
			
		||||
@ -56,7 +79,7 @@ function parse_sty_xml(data, opts) {
 | 
			
		||||
	/* cellStyleXfs CT_CellStyleXfs ? */
 | 
			
		||||
 | 
			
		||||
	/* cellXfs CT_CellXfs ? */
 | 
			
		||||
	if((t=data.match(/<cellXfs([^>]*)>.*<\/cellXfs>/))) parseCXfs(t, opts);
 | 
			
		||||
	if((t=data.match(/<cellXfs([^>]*)>.*<\/cellXfs>/))) parse_cellXfs(t, opts);
 | 
			
		||||
 | 
			
		||||
	/* dxfs CT_Dxfs ? */
 | 
			
		||||
	/* tableStyles CT_TableStyles ? */
 | 
			
		||||
@ -65,3 +88,28 @@ function parse_sty_xml(data, opts) {
 | 
			
		||||
 | 
			
		||||
	return styles;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var STYLES_XML_ROOT = writextag('styleSheet', null, {
 | 
			
		||||
	'xmlns': XMLNS.main[0],
 | 
			
		||||
	'xmlns:vt': XMLNS.vt
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
 | 
			
		||||
 | 
			
		||||
function write_sty_xml(wb, opts) {
 | 
			
		||||
	var o = [], p = {}, W = writextag, w;
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(STYLES_XML_ROOT);
 | 
			
		||||
	if((w = write_numFmts(wb.SSF))) o.push(w);
 | 
			
		||||
  o.push('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
 | 
			
		||||
  o.push('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
 | 
			
		||||
	o.push('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
 | 
			
		||||
	o.push('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
 | 
			
		||||
	if((w = write_cellXfs(opts.cellXfs))) o.push(w);
 | 
			
		||||
	o.push('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
 | 
			
		||||
	o.push('<dxfs count="0"/>');
 | 
			
		||||
	o.push('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
 | 
			
		||||
 | 
			
		||||
	if(o.length>2){ o.push('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										3
									
								
								bits/59_theme.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								bits/59_theme.js
									
									
									
									
									
										Normal file
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -5,7 +5,7 @@ function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
 | 
			
		||||
		var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
 | 
			
		||||
		if(!comments || !comments.length) continue;
 | 
			
		||||
		// find the sheets targeted by these comments
 | 
			
		||||
		var sheetNames = Object.keys(sheets);
 | 
			
		||||
		var sheetNames = keys(sheets);
 | 
			
		||||
		for(var j = 0; j != sheetNames.length; ++j) {
 | 
			
		||||
			var sheetName = sheetNames[j];
 | 
			
		||||
			var rels = sheetRels[sheetName];
 | 
			
		||||
 | 
			
		||||
@ -1,3 +1,23 @@
 | 
			
		||||
var strs = {}; // shared strings
 | 
			
		||||
var _ssfopts = {}; // spreadsheet formatting options
 | 
			
		||||
 | 
			
		||||
RELS.WS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet";
 | 
			
		||||
 | 
			
		||||
function get_sst_id(sst, str) {
 | 
			
		||||
	for(var i = 0; i != sst.length; ++i) if(sst[i].t === str) { sst.Count ++; return i; }
 | 
			
		||||
	sst[sst.length] = {t:str}; sst.Count ++; sst.Unique ++; return sst.length-1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function get_cell_style(styles, cell, opts) {
 | 
			
		||||
	var z = opts.revssf[cell.z];
 | 
			
		||||
	for(var i = 0; i != styles.length; ++i) if(styles[i].numFmtId === z) return i;
 | 
			
		||||
	styles[styles.length] = {
 | 
			
		||||
		numFmtId:z,
 | 
			
		||||
		fontId:0,
 | 
			
		||||
		fillId:0,
 | 
			
		||||
		borderId:0,
 | 
			
		||||
		xfId:0,
 | 
			
		||||
		applyNumberFormat:1
 | 
			
		||||
	};
 | 
			
		||||
	return styles.length-1;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -12,7 +12,7 @@ function parse_ws_xml(data, opts, rels) {
 | 
			
		||||
	var mergecells = [];
 | 
			
		||||
	if(data.match(/<\/mergeCells>/)) {
 | 
			
		||||
		var merges = data.match(/<mergeCell ref="([A-Z0-9:]+)"\s*\/>/g);
 | 
			
		||||
		mergecells = merges.map(function(range) { 
 | 
			
		||||
		mergecells = merges.map(function(range) {
 | 
			
		||||
			return decode_range(/<mergeCell ref="([A-Z0-9:]+)"\s*\/>/.exec(range)[1]);
 | 
			
		||||
		});
 | 
			
		||||
	}
 | 
			
		||||
@ -123,3 +123,55 @@ function parse_ws_xml(data, opts, rels) {
 | 
			
		||||
	return s;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var WS_XML_ROOT = writextag('worksheet', null, {
 | 
			
		||||
	'xmlns': XMLNS.main[0],
 | 
			
		||||
	'xmlns:r': XMLNS.r
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var write_ws_xml_cell = function(cell, ref, ws, opts, idx, wb) {
 | 
			
		||||
	var v = writextag('v', escapexml(String(cell.v))), o = {r:ref};
 | 
			
		||||
	if(cell.z) o.s = get_cell_style(opts.cellXfs, cell, opts); 
 | 
			
		||||
	/* TODO: cell style */
 | 
			
		||||
	if(typeof cell.v === 'undefined') return "";
 | 
			
		||||
	switch(cell.t) {
 | 
			
		||||
		case 's': case 'str': {
 | 
			
		||||
			if(opts.bookSST) {
 | 
			
		||||
				v = writextag('v', String(get_sst_id(opts.Strings, cell.v)));
 | 
			
		||||
				o.t = "s"; return writextag('c', v, o);
 | 
			
		||||
			} else { o.t = "str"; return writextag('c', v, o); }
 | 
			
		||||
		} break;
 | 
			
		||||
		case 'n': o.t = "n"; return writextag('c', v, o);
 | 
			
		||||
		case 'b': o.t = "b"; return writextag('c', v, o);
 | 
			
		||||
		case 'e': o.t = "e"; return writextag('c', v, o); 
 | 
			
		||||
	}
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var write_ws_xml_data = function(ws, opts, idx, wb) {
 | 
			
		||||
	var o = [], r = [], range = utils.decode_range(ws['!ref']), cell, ref;
 | 
			
		||||
	for(var R = range.s.r; R <= range.e.r; ++R) {
 | 
			
		||||
		r = [];
 | 
			
		||||
		for(var C = range.s.c; C <= range.e.c; ++C) {
 | 
			
		||||
			ref = utils.encode_cell({c:C, r:R});
 | 
			
		||||
			if(!ws[ref]) continue;
 | 
			
		||||
			if((cell = write_ws_xml_cell(ws[ref], ref, ws, opts, idx, wb))) r.push(cell);
 | 
			
		||||
		}
 | 
			
		||||
		if(r.length) o.push(writextag('row', r.join(""), {r:encode_row(R)}));
 | 
			
		||||
	}
 | 
			
		||||
	return o.join("");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var write_ws_xml = function(idx, opts, wb) {
 | 
			
		||||
	var o = [], s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}, sidx = 0, rdata = "";
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(WS_XML_ROOT);
 | 
			
		||||
	o.push(writextag('dimension', null, {'ref': ws['!ref'] || 'A1'}));
 | 
			
		||||
 | 
			
		||||
	sidx = o.length;
 | 
			
		||||
	o.push(writextag('sheetData', null));
 | 
			
		||||
	if(ws['!ref']) rdata = write_ws_xml_data(ws, opts, idx, wb);
 | 
			
		||||
	if(rdata.length) o.push(rdata);
 | 
			
		||||
	if(o.length>sidx+1){ o.push('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
 | 
			
		||||
 | 
			
		||||
	if(o.length>2){ o.push('</worksheet>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -317,7 +317,7 @@ var parse_ws_bin = function(data, opts, rels) {
 | 
			
		||||
			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n);
 | 
			
		||||
		}
 | 
			
		||||
	}, opts);
 | 
			
		||||
	if(!s["!ref"] && ref) s["!ref"] = encode_range(ref);
 | 
			
		||||
	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(opts.sheetRows && s["!ref"]) {
 | 
			
		||||
		var tmpref = decode_range(s["!ref"]);
 | 
			
		||||
		if(opts.sheetRows < +tmpref.e.r) {
 | 
			
		||||
@ -334,3 +334,4 @@ var parse_ws_bin = function(data, opts, rels) {
 | 
			
		||||
	return s;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var write_ws_bin = function(wb, opts, rels) {};
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,3 @@
 | 
			
		||||
var XMLNS_WB = [
 | 
			
		||||
	'http://purl.oclc.org/ooxml/spreadsheetml/main',
 | 
			
		||||
	'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
 | 
			
		||||
	'http://schemas.microsoft.com/office/excel/2006/main',
 | 
			
		||||
	'http://schemas.microsoft.com/office/excel/2006/2'
 | 
			
		||||
];
 | 
			
		||||
 | 
			
		||||
/* 18.2 Workbook */
 | 
			
		||||
function parse_wb_xml(data) {
 | 
			
		||||
	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
 | 
			
		||||
@ -110,7 +103,7 @@ function parse_wb_xml(data) {
 | 
			
		||||
			case '</mc:AlternateContent>': pass=false; break;
 | 
			
		||||
		}
 | 
			
		||||
	});
 | 
			
		||||
	if(XMLNS_WB.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
 | 
			
		||||
	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
 | 
			
		||||
 | 
			
		||||
	var z;
 | 
			
		||||
	/* defaults */
 | 
			
		||||
@ -125,3 +118,28 @@ function parse_wb_xml(data) {
 | 
			
		||||
	return wb;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var WB_XML_ROOT = writextag('workbook', null, {
 | 
			
		||||
	'xmlns': XMLNS.main[0],
 | 
			
		||||
	//'xmlns:mx': XMLNS.mx,
 | 
			
		||||
	//'xmlns:s': XMLNS.main[0],
 | 
			
		||||
	'xmlns:r': XMLNS.r
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
var write_wb_xml = function(wb, opts) {
 | 
			
		||||
	var o = [];
 | 
			
		||||
	o.push(XML_HEADER);
 | 
			
		||||
	o.push(WB_XML_ROOT);
 | 
			
		||||
	/* TODO: put this somewhere else */
 | 
			
		||||
	var date1904 = "false";
 | 
			
		||||
	try { date1904 = parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false"; } catch(e) { date1904 = "false"; }
 | 
			
		||||
	o.push(writextag('workbookPr', null, {date1904:date1904}));
 | 
			
		||||
	o.push("<sheets>");
 | 
			
		||||
	var i = 1;
 | 
			
		||||
	wb.SheetNames.forEach(function(s) {
 | 
			
		||||
		o.push(writextag('sheet',null,{name:s, sheetId:String(i), "r:id":"rId"+i}));
 | 
			
		||||
		++i;
 | 
			
		||||
	});
 | 
			
		||||
	o.push("</sheets>");
 | 
			
		||||
	if(o.length>2){ o.push('</workbook>'); o[1]=o[1].replace("/>",">"); }
 | 
			
		||||
	return o.join("");
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -69,3 +69,7 @@ var parse_wb_bin = function(data, opts) {
 | 
			
		||||
 | 
			
		||||
	return wb;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
var write_wb_bin = function(wb, opts) {
 | 
			
		||||
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
@ -1,23 +1,48 @@
 | 
			
		||||
function parse_wb(data, name, opts) {
 | 
			
		||||
	return name.substr(-4)===".bin" ? parse_wb_bin(data, opts) : parse_wb_xml(data, opts);
 | 
			
		||||
	return (name.substr(-4)===".bin" ? parse_wb_bin : parse_wb_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_ws(data, name, opts, rels) {
 | 
			
		||||
	return name.substr(-4)===".bin" ? parse_ws_bin(data, opts, rels) : parse_ws_xml(data, opts, rels);
 | 
			
		||||
	return (name.substr(-4)===".bin" ? parse_ws_bin : parse_ws_xml)(data, opts, rels);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_sty(data, name, opts) {
 | 
			
		||||
	return name.substr(-4)===".bin" ? parse_sty_bin(data, opts) : parse_sty_xml(data, opts);
 | 
			
		||||
	return (name.substr(-4)===".bin" ? parse_sty_bin : parse_sty_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_sst(data, name, opts) {
 | 
			
		||||
	return name.substr(-4)===".bin" ? parse_sst_bin(data, opts) : parse_sst_xml(data, opts);
 | 
			
		||||
	return (name.substr(-4)===".bin" ? parse_sst_bin : parse_sst_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_cmnt(data, name, opts) {
 | 
			
		||||
	return name.substr(-4)===".bin" ? parse_comments_bin(data, opts) : parse_comments_xml(data, opts);
 | 
			
		||||
	return (name.substr(-4)===".bin" ? parse_comments_bin : parse_comments_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function parse_cc(data, name, opts) {
 | 
			
		||||
	return name.substr(-4)===".bin" ? parse_cc_bin(data, opts) : parse_cc_xml(data, opts);
 | 
			
		||||
	return (name.substr(-4)===".bin" ? parse_cc_bin : parse_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_wb(wb, name, opts) {
 | 
			
		||||
	return (name.substr(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_ws(data, name, opts, wb) {
 | 
			
		||||
	return (name.substr(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_sty(data, name, opts) {
 | 
			
		||||
	return (name.substr(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_sst(data, name, opts) {
 | 
			
		||||
	return (name.substr(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
/*
 | 
			
		||||
function write_cmnt(data, name, opts) {
 | 
			
		||||
	return (name.substr(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_cc(data, name, opts) {
 | 
			
		||||
	return (name.substr(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
 | 
			
		||||
}
 | 
			
		||||
*/
 | 
			
		||||
 | 
			
		||||
@ -1,22 +1,34 @@
 | 
			
		||||
function fixopts(opts) {
 | 
			
		||||
	var defaults = [
 | 
			
		||||
		['cellNF', false], /* emit cell number format string as .z */
 | 
			
		||||
		['cellHTML', true], /* emit html string as .h */
 | 
			
		||||
		['cellFormula', true], /* emit formulae as .f */
 | 
			
		||||
 | 
			
		||||
		['sheetStubs', false], /* emit empty cells */
 | 
			
		||||
		['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
 | 
			
		||||
 | 
			
		||||
		['bookDeps', false], /* parse calculation chains */
 | 
			
		||||
		['bookSheets', false], /* only try to get sheet names (no Sheets) */
 | 
			
		||||
		['bookProps', false], /* only try to get properties (no Sheets) */
 | 
			
		||||
		['bookFiles', false], /* include raw file structure (keys, files) */
 | 
			
		||||
		['bookVBA', false], /* include vba raw data (vbaraw) */
 | 
			
		||||
 | 
			
		||||
		['WTF', false] /* WTF mode (throws errors) */
 | 
			
		||||
	];
 | 
			
		||||
	defaults.forEach(function(d) {
 | 
			
		||||
		if(typeof opts[d[0]] === 'undefined') opts[d[0]] = d[1];
 | 
			
		||||
		if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
 | 
			
		||||
	});
 | 
			
		||||
function fix_opts(defaults) {
 | 
			
		||||
	return function(opts) {
 | 
			
		||||
		defaults.forEach(function(d) {
 | 
			
		||||
			if(typeof opts[d[0]] === 'undefined') opts[d[0]] = d[1];
 | 
			
		||||
			if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
 | 
			
		||||
		});
 | 
			
		||||
	};
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
var fix_read_opts = fix_opts([
 | 
			
		||||
	['cellNF', false], /* emit cell number format string as .z */
 | 
			
		||||
	['cellHTML', true], /* emit html string as .h */
 | 
			
		||||
	['cellFormula', true], /* emit formulae as .f */
 | 
			
		||||
 | 
			
		||||
	['sheetStubs', false], /* emit empty cells */
 | 
			
		||||
	['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
 | 
			
		||||
 | 
			
		||||
	['bookDeps', false], /* parse calculation chains */
 | 
			
		||||
	['bookSheets', false], /* only try to get sheet names (no Sheets) */
 | 
			
		||||
	['bookProps', false], /* only try to get properties (no Sheets) */
 | 
			
		||||
	['bookFiles', false], /* include raw file structure (keys, files) */
 | 
			
		||||
	['bookVBA', false], /* include vba raw data (vbaraw) */
 | 
			
		||||
 | 
			
		||||
	['WTF', false] /* WTF mode (throws errors) */
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
var fix_write_opts = fix_opts([
 | 
			
		||||
	['bookSST', false], /* Generate Shared String Table */
 | 
			
		||||
 | 
			
		||||
	['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
 | 
			
		||||
 | 
			
		||||
	['WTF', false] /* WTF mode (throws errors) */
 | 
			
		||||
]);
 | 
			
		||||
 | 
			
		||||
@ -1,10 +1,10 @@
 | 
			
		||||
function parseZip(zip, opts) {
 | 
			
		||||
function parse_zip(zip, opts) {
 | 
			
		||||
	make_ssf(SSF);
 | 
			
		||||
	opts = opts || {};
 | 
			
		||||
	fixopts(opts);
 | 
			
		||||
	fix_read_opts(opts);
 | 
			
		||||
	reset_cp();
 | 
			
		||||
	var entries = Object.keys(zip.files);
 | 
			
		||||
	var keys = entries.filter(function(x){return x.substr(-1) != '/';}).sort();
 | 
			
		||||
	var dir = parseCT(getzipdata(zip, '[Content_Types].xml'), opts);
 | 
			
		||||
	var entries = keys(zip.files).filter(function(x){return x.substr(-1) != '/';}).sort();
 | 
			
		||||
	var dir = parse_ct(getzipdata(zip, '[Content_Types].xml'), opts);
 | 
			
		||||
	var xlsb = false;
 | 
			
		||||
	var sheets, binname;
 | 
			
		||||
	if(dir.workbooks.length === 0) {
 | 
			
		||||
@ -19,7 +19,7 @@ function parseZip(zip, opts) {
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	if(!opts.bookSheets && !opts.bookProps) {
 | 
			
		||||
		strs = {};
 | 
			
		||||
		strs = [];
 | 
			
		||||
		if(dir.sst) strs=parse_sst(getzipdata(zip, dir.sst.replace(/^\//,'')), dir.sst, opts);
 | 
			
		||||
 | 
			
		||||
		styles = {};
 | 
			
		||||
@ -29,17 +29,21 @@ function parseZip(zip, opts) {
 | 
			
		||||
	var wb = parse_wb(getzipdata(zip, dir.workbooks[0].replace(/^\//,'')), dir.workbooks[0], opts);
 | 
			
		||||
 | 
			
		||||
	var props = {}, propdata = "";
 | 
			
		||||
	try {
 | 
			
		||||
		propdata = dir.coreprops.length !== 0 ? getzipdata(zip, dir.coreprops[0].replace(/^\//,'')) : "";
 | 
			
		||||
		propdata += dir.extprops.length !== 0 ? getzipdata(zip, dir.extprops[0].replace(/^\//,'')) : "";
 | 
			
		||||
		props = propdata !== "" ? parseProps(propdata) : {};
 | 
			
		||||
	} catch(e) { }
 | 
			
		||||
 | 
			
		||||
	if(dir.coreprops.length !== 0) {
 | 
			
		||||
		propdata = getzipdata(zip, dir.coreprops[0].replace(/^\//,''), true);
 | 
			
		||||
		if(propdata) props = parse_core_props(propdata);
 | 
			
		||||
		if(dir.extprops.length !== 0) {
 | 
			
		||||
			propdata = getzipdata(zip, dir.extprops[0].replace(/^\//,''), true);
 | 
			
		||||
			if(propdata) parse_ext_props(propdata, props);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	var custprops = {};
 | 
			
		||||
	if(!opts.bookSheets || opts.bookProps) {
 | 
			
		||||
		if (dir.custprops.length !== 0) {
 | 
			
		||||
			propdata = getzipdata(zip, dir.custprops[0].replace(/^\//,''), true);
 | 
			
		||||
			if(propdata) custprops = parseCustomProps(propdata);
 | 
			
		||||
			if(propdata) custprops = parse_cust_props(propdata, opts);
 | 
			
		||||
		}
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
@ -60,7 +64,6 @@ function parseZip(zip, opts) {
 | 
			
		||||
	var sheetRels = {};
 | 
			
		||||
	var path, relsPath;
 | 
			
		||||
	if(!props.Worksheets) {
 | 
			
		||||
		/* Google Docs doesn't generate the appropriate metadata, so we impute: */
 | 
			
		||||
		var wbsheets = wb.Sheets;
 | 
			
		||||
		props.Worksheets = wbsheets.length;
 | 
			
		||||
		props.SheetNames = [];
 | 
			
		||||
@ -76,7 +79,7 @@ function parseZip(zip, opts) {
 | 
			
		||||
			path = 'xl/worksheets/sheet'+(i+1-nmode)+(xlsb?'.bin':'.xml');
 | 
			
		||||
			path = path.replace(/sheet0\./,"sheet.");
 | 
			
		||||
			relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
 | 
			
		||||
			sheetRels[props.SheetNames[i]]=parseRels(getzipdata(zip, relsPath, true), path);
 | 
			
		||||
			sheetRels[props.SheetNames[i]]=parse_rels(getzipdata(zip, relsPath, true), path);
 | 
			
		||||
			sheets[props.SheetNames[i]]=parse_ws(getzipdata(zip, path),path,opts,sheetRels[props.SheetNames[i]]);
 | 
			
		||||
		} catch(e) { if(opts.WTF) throw e; }
 | 
			
		||||
	}
 | 
			
		||||
@ -93,9 +96,10 @@ function parseZip(zip, opts) {
 | 
			
		||||
		SheetNames: props.SheetNames,
 | 
			
		||||
		Strings: strs,
 | 
			
		||||
		Styles: styles,
 | 
			
		||||
		SSF: SSF.get_table()
 | 
			
		||||
	};
 | 
			
		||||
	if(opts.bookFiles) {
 | 
			
		||||
		out.keys = keys;
 | 
			
		||||
		out.keys = entries;
 | 
			
		||||
		out.files = zip.files;
 | 
			
		||||
	}
 | 
			
		||||
	if(opts.bookVBA) {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										85
									
								
								bits/86_writezip.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										85
									
								
								bits/86_writezip.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,85 @@
 | 
			
		||||
function add_rels(rels, rId, f, type, relobj) {
 | 
			
		||||
	if(!relobj) relobj = {};
 | 
			
		||||
	if(!rels['!id']) rels['!id'] = {};
 | 
			
		||||
	relobj.Id = 'rId' + rId;
 | 
			
		||||
	relobj.Type = type; 
 | 
			
		||||
	relobj.Target = f;
 | 
			
		||||
	if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
 | 
			
		||||
	rels['!id'][relobj.Id] = relobj;
 | 
			
		||||
	rels[('/' + relobj.Target).replace("//","/")] = relobj;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function write_zip(wb, opts) {
 | 
			
		||||
	if(wb && wb.SSF) {
 | 
			
		||||
		make_ssf(SSF); SSF.load_table(wb.SSF);
 | 
			
		||||
		opts.revssf = evert(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
 | 
			
		||||
	}
 | 
			
		||||
	opts.rels = {}; opts.wbrels = {};
 | 
			
		||||
	opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
 | 
			
		||||
	var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
 | 
			
		||||
	var ct = { workbooks: [], sheets: [], calcchains: [], themes: [], styles: [],
 | 
			
		||||
		coreprops: [], extprops: [], custprops: [], strs:[], comments: [], vba: [],
 | 
			
		||||
		TODO:[], rels:[], xmlns: "" };
 | 
			
		||||
	fix_write_opts(opts = opts || {});
 | 
			
		||||
	var zip = new jszip();
 | 
			
		||||
	var f = "", rId = 0;
 | 
			
		||||
 | 
			
		||||
	opts.cellXfs = [];
 | 
			
		||||
 | 
			
		||||
	f = "docProps/core.xml";
 | 
			
		||||
	zip.file(f, write_core_props(wb.Props, opts));
 | 
			
		||||
	ct.coreprops.push(f);
 | 
			
		||||
	add_rels(opts.rels, 3, f, RELS.CORE_PROPS);
 | 
			
		||||
 | 
			
		||||
	f = "docProps/app.xml";
 | 
			
		||||
	wb.Props.SheetNames = wb.SheetNames;
 | 
			
		||||
	wb.Props.Worksheets = wb.SheetNames.length;
 | 
			
		||||
	zip.file(f, write_ext_props(wb.Props, opts));
 | 
			
		||||
	ct.extprops.push(f);
 | 
			
		||||
	add_rels(opts.rels, 4, f, RELS.EXT_PROPS);
 | 
			
		||||
 | 
			
		||||
	if(wb.Custprops !== wb.Props) { /* TODO: fix xlsjs */
 | 
			
		||||
		f = "docProps/custom.xml";
 | 
			
		||||
		zip.file(f, write_cust_props(wb.Custprops, opts));
 | 
			
		||||
		ct.custprops.push(f);
 | 
			
		||||
		add_rels(opts.rels, 5, f, RELS.CUST_PROPS);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	f = "xl/workbook." + wbext;
 | 
			
		||||
	zip.file(f, write_wb(wb, f, opts));
 | 
			
		||||
	ct.workbooks.push(f);
 | 
			
		||||
	add_rels(opts.rels, 1, f, RELS.WB);
 | 
			
		||||
 | 
			
		||||
	wb.SheetNames.forEach(function(s, i) {
 | 
			
		||||
		rId = i+1; f = "xl/worksheets/sheet" + rId + "." + wbext;
 | 
			
		||||
		zip.file(f, write_ws(i, f, opts, wb));
 | 
			
		||||
		ct.sheets.push(f);
 | 
			
		||||
		add_rels(opts.wbrels, rId, "worksheets/sheet" + rId + "." + wbext, RELS.WS);
 | 
			
		||||
	});
 | 
			
		||||
 | 
			
		||||
	if((opts.Strings||[]).length > 0) {
 | 
			
		||||
		f = "xl/sharedStrings." + wbext;
 | 
			
		||||
		zip.file(f, write_sst(opts.Strings, f, opts));
 | 
			
		||||
		ct.strs.push(f);
 | 
			
		||||
		add_rels(opts.wbrels, ++rId, "sharedStrings." + wbext, RELS.SST);
 | 
			
		||||
	}
 | 
			
		||||
 | 
			
		||||
	/* TODO: something more intelligent with themes */
 | 
			
		||||
	
 | 
			
		||||
/*	f = "xl/theme/theme1.xml"
 | 
			
		||||
	zip.file(f, write_theme());
 | 
			
		||||
	ct.themes.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, ++rId, "theme/theme1.xml", RELS.THEME);*/
 | 
			
		||||
 | 
			
		||||
	/* TODO: something more intelligent with styles */
 | 
			
		||||
 | 
			
		||||
	f = "xl/styles.xml";
 | 
			
		||||
	zip.file(f, write_sty(wb, f, opts));
 | 
			
		||||
	ct.styles.push(f);
 | 
			
		||||
	add_rels(opts.wbrels, ++rId, "styles." + wbext, RELS.STY);
 | 
			
		||||
 | 
			
		||||
	zip.file("[Content_Types].xml", write_ct(ct, opts));
 | 
			
		||||
	zip.file('_rels/.rels', write_rels(opts.rels));
 | 
			
		||||
	zip.file('xl/_rels/workbook.xml.rels', write_rels(opts.wbrels));
 | 
			
		||||
	return zip;
 | 
			
		||||
}
 | 
			
		||||
@ -1,19 +1,19 @@
 | 
			
		||||
function readSync(data, options) {
 | 
			
		||||
function readSync(data, opts) {
 | 
			
		||||
	var zip, d = data;
 | 
			
		||||
	var o = options||{};
 | 
			
		||||
	switch((o.type||"base64")){
 | 
			
		||||
		case "file":
 | 
			
		||||
			if(typeof Buffer !== 'undefined') { zip=new jszip(d=_fs.readFileSync(data)); break; }
 | 
			
		||||
			d = _fs.readFileSync(data).toString('base64');
 | 
			
		||||
			/* falls through */
 | 
			
		||||
	var o = opts||{};
 | 
			
		||||
	if(!o.type) o.type = (typeof Buffer !== 'undefined' && data instanceof Buffer) ? "buffer" : "base64";
 | 
			
		||||
	switch(o.type) {
 | 
			
		||||
		case "base64": zip = new jszip(d, { base64:true }); break;
 | 
			
		||||
		case "binary": zip = new jszip(d, { base64:false }); break;
 | 
			
		||||
		case "buffer": zip = new jszip(d); break;
 | 
			
		||||
		case "file": zip=new jszip(d=_fs.readFileSync(data)); break;
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
	return parseZip(zip, o);
 | 
			
		||||
	return parse_zip(zip, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function readFileSync(data, options) {
 | 
			
		||||
	var o = options||{}; o.type = 'file';
 | 
			
		||||
function readFileSync(data, opts) {
 | 
			
		||||
	var o = opts||{}; o.type = 'file';
 | 
			
		||||
	return readSync(data, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										22
									
								
								bits/89_write.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								bits/89_write.js
									
									
									
									
									
										Normal file
									
								
							@ -0,0 +1,22 @@
 | 
			
		||||
function writeSync(wb, opts) {
 | 
			
		||||
	var o = opts||{};
 | 
			
		||||
	var z = write_zip(wb, o);
 | 
			
		||||
	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"}));
 | 
			
		||||
		default: throw new Error("Unrecognized type " + o.type);
 | 
			
		||||
	}
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
function writeFileSync(wb, filename, opts) {
 | 
			
		||||
	var o = opts||{}; o.type = 'file';
 | 
			
		||||
	o.file = filename;
 | 
			
		||||
	switch(o.file.substr(-5).toLowerCase()) {
 | 
			
		||||
		case '.xlsm': o.bookType = 'xlsm'; break;
 | 
			
		||||
		case '.xlsb': o.bookType = 'xlsb'; break;
 | 
			
		||||
	}
 | 
			
		||||
	return writeSync(wb, o);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
@ -1,5 +1,7 @@
 | 
			
		||||
XLSX.parseZip = parseZip;
 | 
			
		||||
XLSX.parseZip = parse_zip;
 | 
			
		||||
XLSX.read = readSync;
 | 
			
		||||
XLSX.readFile = readFileSync;
 | 
			
		||||
XLSX.write = writeSync;
 | 
			
		||||
XLSX.writeFile = writeFileSync;
 | 
			
		||||
XLSX.utils = utils;
 | 
			
		||||
XLSX.SSF = SSF;
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										2
									
								
								dist/LICENSE
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/LICENSE
									
									
									
									
										vendored
									
									
								
							@ -1,4 +1,4 @@
 | 
			
		||||
Copyright (C) 2012-2014 SheetJS 
 | 
			
		||||
Copyright (C) 2012-2014  SheetJS
 | 
			
		||||
 | 
			
		||||
   Licensed under the Apache License, Version 2.0 (the "License");
 | 
			
		||||
   you may not use this file except in compliance with the License.
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										9
									
								
								dist/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										9
									
								
								dist/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										9
									
								
								dist/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										9
									
								
								dist/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1353
									
								
								dist/xlsx.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1353
									
								
								dist/xlsx.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										7
									
								
								dist/xlsx.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								dist/xlsx.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							@ -1,11 +1,11 @@
 | 
			
		||||
{
 | 
			
		||||
	"name": "xlsx",
 | 
			
		||||
	"version": "0.6.2",
 | 
			
		||||
	"version": "0.7.0",
 | 
			
		||||
	"author": "sheetjs",
 | 
			
		||||
	"description": "XLSB / XLSX / XLSM (Excel 2007+ Spreadsheet) parser",
 | 
			
		||||
	"keywords": [ "xlsx", "xlsb", "xlsm", "office", "excel", "spreadsheet" ],
 | 
			
		||||
	"bin": {
 | 
			
		||||
		"xlsx2csv": "./bin/xlsx2csv.njs"
 | 
			
		||||
		"xlsx": "./bin/xlsx.njs"
 | 
			
		||||
	},
 | 
			
		||||
	"main": "./xlsx",
 | 
			
		||||
	"dependencies": {
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										186
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										186
									
								
								test.js
									
									
									
									
									
								
							@ -3,9 +3,11 @@ var X;
 | 
			
		||||
var fs = require('fs'), assert = require('assert');
 | 
			
		||||
describe('source',function(){it('should load',function(){X=require('./');});});
 | 
			
		||||
 | 
			
		||||
var opts = {};
 | 
			
		||||
var opts = {cellNF: true};
 | 
			
		||||
if(process.env.WTF) opts.WTF = true;
 | 
			
		||||
var ex = [".xlsb", ".xlsm", ".xlsx"];
 | 
			
		||||
var fullex = [".xlsb", ".xlsm", ".xlsx"];
 | 
			
		||||
var ex = fullex;
 | 
			
		||||
if(process.env.FMTS === "full") process.env.FMTS = ex.join(":");
 | 
			
		||||
if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;});
 | 
			
		||||
var exp = ex.map(function(x){ return x + ".pending"; });
 | 
			
		||||
function test_file(x){return ex.indexOf(x.substr(-5))>=0||exp.indexOf(x.substr(-13))>=0;}
 | 
			
		||||
@ -43,8 +45,9 @@ var paths = {
 | 
			
		||||
var N1 = 'XLSX';
 | 
			
		||||
var N2 = 'XLSB';
 | 
			
		||||
 | 
			
		||||
function parsetest(x, wb, full) {
 | 
			
		||||
	describe(x + ' should have all bits', function() {
 | 
			
		||||
function parsetest(x, wb, full, ext) {
 | 
			
		||||
	ext = (ext ? " [" + ext + "]": "");
 | 
			
		||||
	describe(x + ext + ' should have all bits', function() {
 | 
			
		||||
		var sname = dir + '2011/' + x + '.sheetnames';
 | 
			
		||||
		it('should have all sheets', function() {
 | 
			
		||||
			wb.SheetNames.forEach(function(y) { assert(wb.Sheets[y], 'bad sheet ' + y); });
 | 
			
		||||
@ -55,21 +58,21 @@ function parsetest(x, wb, full) {
 | 
			
		||||
			assert.equal(names, file);
 | 
			
		||||
		} : null);
 | 
			
		||||
	});
 | 
			
		||||
	describe(x + ' should generate CSV', function() {
 | 
			
		||||
	describe(x + ext + ' should generate CSV', function() {
 | 
			
		||||
		wb.SheetNames.forEach(function(ws, i) {
 | 
			
		||||
			it('#' + i + ' (' + ws + ')', function() {
 | 
			
		||||
				X.utils.make_csv(wb.Sheets[ws]);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
	describe(x + ' should generate JSON', function() {
 | 
			
		||||
	describe(x + ext + ' should generate JSON', function() {
 | 
			
		||||
		wb.SheetNames.forEach(function(ws, i) {
 | 
			
		||||
			it('#' + i + ' (' + ws + ')', function() {
 | 
			
		||||
				X.utils.sheet_to_row_object_array(wb.Sheets[ws]);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
	describe(x + ' should generate formulae', function() {
 | 
			
		||||
	describe(x + ext + ' should generate formulae', function() {
 | 
			
		||||
		wb.SheetNames.forEach(function(ws, i) {
 | 
			
		||||
			it('#' + i + ' (' + ws + ')', function() {
 | 
			
		||||
				X.utils.get_formulae(wb.Sheets[ws]);
 | 
			
		||||
@ -87,7 +90,7 @@ function parsetest(x, wb, full) {
 | 
			
		||||
		}
 | 
			
		||||
		return name;
 | 
			
		||||
	};
 | 
			
		||||
	describe(x + ' should generate correct CSV output', function() {
 | 
			
		||||
	describe(x + ext + ' should generate correct CSV output', function() {
 | 
			
		||||
		wb.SheetNames.forEach(function(ws, i) {
 | 
			
		||||
			var name = getfile(dir, x, i, ".csv");
 | 
			
		||||
			it('#' + i + ' (' + ws + ')', fs.existsSync(name) ? function() {
 | 
			
		||||
@ -97,7 +100,7 @@ function parsetest(x, wb, full) {
 | 
			
		||||
			} : null);
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
	describe(x + ' should generate correct JSON output', function() {
 | 
			
		||||
	describe(x + ext + ' should generate correct JSON output', function() {
 | 
			
		||||
		wb.SheetNames.forEach(function(ws, i) {
 | 
			
		||||
			var rawjson = getfile(dir, x, i, ".rawjson");
 | 
			
		||||
			if(fs.existsSync(rawjson)) it('#' + i + ' (' + ws + ')', function() {
 | 
			
		||||
@ -115,7 +118,7 @@ function parsetest(x, wb, full) {
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
	if(!fs.existsSync(dir + '2013/' + x + '.xlsb')) return;
 | 
			
		||||
	describe(x + '.xlsb from 2013', function() {
 | 
			
		||||
	describe(x + ext + '.xlsb from 2013', function() {
 | 
			
		||||
		it('should parse', function() {
 | 
			
		||||
			var wb = X.readFile(dir + '2013/' + x + '.xlsb', opts);
 | 
			
		||||
		});
 | 
			
		||||
@ -127,6 +130,9 @@ describe('should parse test files', function() {
 | 
			
		||||
		it(x, x.substr(-8) == ".pending" ? null : function() {
 | 
			
		||||
			var wb = X.readFile(dir + x, opts);
 | 
			
		||||
			parsetest(x, wb, true);
 | 
			
		||||
			['.xlsx', '.xlsm'].forEach(function(ext, idx) {
 | 
			
		||||
				parsetest(x, X.read(X.write(wb, {type:"buffer", bookType:ext.replace(/\./,""), bookSST: idx != 1})), true, ext);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
	fileA.forEach(function(x) {
 | 
			
		||||
@ -137,7 +143,7 @@ describe('should parse test files', function() {
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('options', function() {
 | 
			
		||||
describe('parse options', function() {
 | 
			
		||||
	var html_cell_types = ['s'];
 | 
			
		||||
	before(function() {
 | 
			
		||||
		X = require('./');
 | 
			
		||||
@ -308,9 +314,76 @@ describe('input formats', function() {
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst1, 'base64'), {type: 'base64'});
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst2, 'base64'), {type: 'base64'});
 | 
			
		||||
	});
 | 
			
		||||
	it('should read buffers', function() {
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst1), {type: 'buffer'});
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst2), {type: 'buffer'});
 | 
			
		||||
	});
 | 
			
		||||
	it('should throw if format is unknown', function() {
 | 
			
		||||
		assert.throws(function() { X.read(fs.readFileSync(paths.cst1), {type: 'dafuq'}); });
 | 
			
		||||
		assert.throws(function() { X.read(fs.readFileSync(paths.cst2), {type: 'dafuq'}); });
 | 
			
		||||
	});
 | 
			
		||||
	it('should infer buffer type', function() {
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst1));
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst2));
 | 
			
		||||
	});
 | 
			
		||||
	it('should default to base64 type', function() {
 | 
			
		||||
		assert.throws(function() { X.read(fs.readFileSync(paths.cst1, 'binary')); });
 | 
			
		||||
		assert.throws(function() { X.read(fs.readFileSync(paths.cst2, 'binary')); });
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst1, 'base64'));
 | 
			
		||||
		X.read(fs.readFileSync(paths.cst2, 'base64'));
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('features', function() {
 | 
			
		||||
describe('output formats', function() {
 | 
			
		||||
	var wb1, wb2;
 | 
			
		||||
	before(function() {
 | 
			
		||||
		X = require('./');
 | 
			
		||||
		wb1 = X.readFile(paths.cp1);
 | 
			
		||||
		wb2 = X.readFile(paths.cp2);
 | 
			
		||||
	});
 | 
			
		||||
	it('should write binary strings', function() {
 | 
			
		||||
		X.write(wb1, {type: 'binary'});
 | 
			
		||||
		X.write(wb2, {type: 'binary'});
 | 
			
		||||
		X.read(X.write(wb1, {type: 'binary'}), {type: 'binary'});
 | 
			
		||||
		X.read(X.write(wb2, {type: 'binary'}), {type: 'binary'});
 | 
			
		||||
	});
 | 
			
		||||
	it('should write base64 strings', function() {
 | 
			
		||||
		X.write(wb1, {type: 'base64'});
 | 
			
		||||
		X.write(wb2, {type: 'base64'});
 | 
			
		||||
		X.read(X.write(wb1, {type: 'base64'}), {type: 'base64'});
 | 
			
		||||
		X.read(X.write(wb2, {type: 'base64'}), {type: 'base64'});
 | 
			
		||||
	});
 | 
			
		||||
	it('should write buffers', function() {
 | 
			
		||||
		X.write(wb1, {type: 'buffer'});
 | 
			
		||||
		X.write(wb2, {type: 'buffer'});
 | 
			
		||||
		X.read(X.write(wb1, {type: 'buffer'}), {type: 'buffer'});
 | 
			
		||||
		X.read(X.write(wb2, {type: 'buffer'}), {type: 'buffer'});
 | 
			
		||||
	});
 | 
			
		||||
	it('should throw if format is unknown', function() {
 | 
			
		||||
		assert.throws(function() { X.write(wb1, {type: 'dafuq'}); });
 | 
			
		||||
		assert.throws(function() { X.write(wb2, {type: 'dafuq'}); });
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
function coreprop(wb) {
 | 
			
		||||
	assert.equal(wb.Props.Title, 'Example with properties');
 | 
			
		||||
	assert.equal(wb.Props.Subject, 'Test it before you code it');
 | 
			
		||||
	assert.equal(wb.Props.Author, 'Pony Foo');
 | 
			
		||||
	assert.equal(wb.Props.Manager, 'Despicable Drew');
 | 
			
		||||
	assert.equal(wb.Props.Company, 'Vector Inc');
 | 
			
		||||
	assert.equal(wb.Props.Category, 'Quirky');
 | 
			
		||||
	assert.equal(wb.Props.Keywords, 'example humor');
 | 
			
		||||
	assert.equal(wb.Props.Comments, 'some comments');
 | 
			
		||||
	assert.equal(wb.Props.LastAuthor, 'Hugues');
 | 
			
		||||
}
 | 
			
		||||
function custprop(wb) {
 | 
			
		||||
	assert.equal(wb.Custprops['I am a boolean'], true);
 | 
			
		||||
	assert.equal(wb.Custprops['Date completed'].toISOString(), '1967-03-09T16:30:00.000Z');
 | 
			
		||||
	assert.equal(wb.Custprops.Status, 2);
 | 
			
		||||
	assert.equal(wb.Custprops.Counter, -3.14);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
describe('parse features', function() {
 | 
			
		||||
	it('should have comment as part of cell properties', function(){
 | 
			
		||||
		var X = require('./');
 | 
			
		||||
		var sheet = 'Sheet1';
 | 
			
		||||
@ -335,17 +408,6 @@ describe('features', function() {
 | 
			
		||||
			wb2 = X.readFile(paths.cp2);
 | 
			
		||||
		});
 | 
			
		||||
 | 
			
		||||
		function coreprop(wb) {
 | 
			
		||||
			assert.equal(wb.Props.Company, 'Vector Inc');
 | 
			
		||||
			assert.equal(wb.Props.Creator, 'Pony Foo');
 | 
			
		||||
		}
 | 
			
		||||
		function custprop(wb) {
 | 
			
		||||
			assert.equal(wb.Custprops['I am a boolean'], true);
 | 
			
		||||
			assert.equal(wb.Custprops['Date completed'], '1967-03-09T16:30:00Z');
 | 
			
		||||
			assert.equal(wb.Custprops.Status, 2);
 | 
			
		||||
			assert.equal(wb.Custprops.Counter, -3.14);
 | 
			
		||||
		}
 | 
			
		||||
 | 
			
		||||
		it(N1 + ' should parse core properties', function() { coreprop(wb1); });
 | 
			
		||||
		it(N2 + ' should parse core properties', function() { coreprop(wb2); });
 | 
			
		||||
		it(N1 + ' should parse custom properties', function() { custprop(wb1); });
 | 
			
		||||
@ -434,17 +496,75 @@ describe('features', function() {
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('invalid files', function() {
 | 
			
		||||
	it('should fail on passwords', function() {
 | 
			
		||||
		assert.throws(function() { X.readFile(dir + 'excel-reader-xlsx_error03.xlsx'); });
 | 
			
		||||
describe('roundtrip features', function() {
 | 
			
		||||
	before(function() {
 | 
			
		||||
		X = require('./');
 | 
			
		||||
	});
 | 
			
		||||
	it('should fail on XLS files', function() {
 | 
			
		||||
		assert.throws(function() { X.readFile(dir + 'roo_type_excel.xlsx'); });
 | 
			
		||||
	describe('should parse core properties and custom properties', function() {
 | 
			
		||||
		var wb1, wb2, base = './tmp/cp';
 | 
			
		||||
		before(function() {
 | 
			
		||||
			wb1 = X.readFile(paths.cp1);
 | 
			
		||||
			wb2 = X.readFile(paths.cp2);
 | 
			
		||||
			fullex.forEach(function(p) {
 | 
			
		||||
				X.writeFile(wb1, base + '.xlsm' + p);
 | 
			
		||||
				X.writeFile(wb2, base + '.xlsb' + p);
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
		fullex.forEach(function(p) { ['.xlsm','.xlsb'].forEach(function(q) {
 | 
			
		||||
			it(q + p + ' should roundtrip core and custom properties', function() {
 | 
			
		||||
				var wb = X.readFile(base + q + p);
 | 
			
		||||
				coreprop(wb);
 | 
			
		||||
				custprop(wb);
 | 
			
		||||
			}); });
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
	it('should fail on ODS files', function() {
 | 
			
		||||
		assert.throws(function() { X.readFile(dir + 'roo_type_openoffice.xlsx');});
 | 
			
		||||
	});
 | 
			
		||||
	it('should fail on DOC files', function() {
 | 
			
		||||
		assert.throws(function() { X.readFile(dir + 'word_doc.doc');});
 | 
			
		||||
	/* the XLSJS require should not cause the test suite to fail */
 | 
			
		||||
	var XLSJS;
 | 
			
		||||
	try {
 | 
			
		||||
		XLSJS = require('xlsjs');
 | 
			
		||||
		var xls = XLSJS.readFile('./test_files/formula_stress_test.xls');
 | 
			
		||||
		var xml = XLSJS.readFile('./test_files/formula_stress_test.xls.xml');
 | 
			
		||||
	} catch(e) { return; }
 | 
			
		||||
	describe('xlsjs conversions', function() { [
 | 
			
		||||
			['XLS', 'formula_stress_test.xls'],
 | 
			
		||||
			['XML', 'formula_stress_test.xls.xml']
 | 
			
		||||
		].forEach(function(w) {
 | 
			
		||||
			it('should be able to write ' + w[0] + ' files from xlsjs', function() {
 | 
			
		||||
				var xls = XLSJS.readFile('./test_files/' + w[1]);
 | 
			
		||||
				X.writeFile(xls, './tmp/' + w[1] + '.xlsx');
 | 
			
		||||
				X.writeFile(xls, './tmp/' + w[1] + '.xlsb');
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
describe('invalid files', function() {
 | 
			
		||||
	describe('parse', function() { [
 | 
			
		||||
			['passwords', 'excel-reader-xlsx_error03.xlsx'],
 | 
			
		||||
			['XLS files', 'roo_type_excel.xlsx'],
 | 
			
		||||
			['ODS files', 'roo_type_openoffice.xlsx'],
 | 
			
		||||
			['DOC files', 'word_doc.doc']
 | 
			
		||||
		].forEach(function(w) { it('should fail on ' + w[0], function() { assert.throws(function() { X.readFile(dir + w[1]); }); }); });
 | 
			
		||||
	});
 | 
			
		||||
	describe('write', function() {
 | 
			
		||||
		it('should pass', function() { X.write(X.readFile(paths.fst1), {type:'binary'}); });
 | 
			
		||||
		it('should pass if a sheet is missing', function() {
 | 
			
		||||
			var wb = X.readFile(paths.fst1); delete wb.Sheets[wb.SheetNames[0]];
 | 
			
		||||
			X.read(X.write(wb, {type:'binary'}), {type:'binary'});
 | 
			
		||||
		});
 | 
			
		||||
		it('should fail if SheetNames is missing', function() {
 | 
			
		||||
			var wb = X.readFile(paths.fst1);
 | 
			
		||||
			assert.throws(function() {
 | 
			
		||||
				delete wb.SheetNames;
 | 
			
		||||
				X.write(wb, {type:'binary'});
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
		it('should fail if Sheets is missing', function() {
 | 
			
		||||
			var wb = X.readFile(paths.fst1);
 | 
			
		||||
			assert.throws(function() {
 | 
			
		||||
				delete wb.Sheets;
 | 
			
		||||
				X.write(wb, {type:'binary'});
 | 
			
		||||
			});
 | 
			
		||||
		});
 | 
			
		||||
	});
 | 
			
		||||
});
 | 
			
		||||
 | 
			
		||||
@ -1 +1,3 @@
 | 
			
		||||
calendar_stress_test.xlsx
 | 
			
		||||
large_strings.xlsb
 | 
			
		||||
time_stress_test_1.xlsb
 | 
			
		||||
 | 
			
		||||
@ -7,7 +7,6 @@ comments_stress_test.xlsb
 | 
			
		||||
custom_properties.xlsb
 | 
			
		||||
formula_stress_test.xlsb
 | 
			
		||||
hyperlink_stress_test_2011.xlsb
 | 
			
		||||
large_strings.xlsb
 | 
			
		||||
merge_cells.xlsb
 | 
			
		||||
named_ranges_2011.xlsb
 | 
			
		||||
number_format.xlsb
 | 
			
		||||
@ -15,7 +14,6 @@ pivot_table_named_range.xlsb
 | 
			
		||||
pivot_table_test.xlsb
 | 
			
		||||
rich_text_stress.xlsb
 | 
			
		||||
text_and_numbers.xlsb
 | 
			
		||||
time_stress_test_1.xlsb
 | 
			
		||||
xlsx-stream-d-date-cell.xlsb
 | 
			
		||||
2013/apachepoi_29982.xls.xlsb
 | 
			
		||||
2013/apachepoi_43251.xls.xlsb
 | 
			
		||||
 | 
			
		||||
							
								
								
									
										1353
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1353
									
								
								xlsx.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user