version bump 0.9.0: merged ODS into XLSX

The optional ODS module has been completely merged into xlsx.js and the
corresponding scripts have been removed.  The new xlsx.js file provides
appropriate ODS exports, so fixing is a matter of removing ods.js refs.
This commit is contained in:
SheetJS 2017-03-09 20:09:18 -05:00
parent 7b6fb7b327
commit 54b528eaed
61 changed files with 2220 additions and 2711 deletions

View File

@ -1,6 +1,7 @@
[ignore]
.*/node_modules/.*
.*/dist/.*
.*/tmp/.*
.*/test.js
.*/bits/.*
@ -11,8 +12,6 @@
.*/demo/browser.js
.*/shim.js
.*/odsbits/.*
.*/ods.js
.*/xlsx.js
.*/xlsxworker.js
.*/xlsxworker1.js
@ -27,7 +26,6 @@ xlsxworker.flow.js
xlsxworker1.flow.js
xlsxworker2.flow.js
xlsx.flow.js
ods.flow.js
.*/bin/.*.njs
.*/demo/browser.flow.js

1
.gitignore vendored
View File

@ -18,3 +18,4 @@ tmp
*.htm
*.html
*.sheetjs
*.exe

12
CHANGELOG.md Normal file
View File

@ -0,0 +1,12 @@
# CHANGELOG
This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code.
## 0.9.0 (2017-03-09)
* Removed ods.js source. The xlsx.js source absorbed the ODS logic and exposes
the ODS variable, so projects should remove references to ods.js

View File

@ -3,7 +3,7 @@ LIB=xlsx
FMT=xlsx xlsm xlsb ods xls xml misc full
REQS=jszip.js
ADDONS=dist/cpexcel.js
AUXTARGETS=ods.js
AUXTARGETS=
CMDS=bin/xlsx.njs
HTMLLINT=index.html
@ -62,23 +62,18 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution
cat <(head -n 1 bits/00_header.js) $(REQS) $(ADDONS) $(TARGET) $(AUXTARGETS) > demos/requirejs/$(LIB).full.js
.PHONY: dist-deps
dist-deps: ods.js ## Copy dependencies for distribution
dist-deps: ## Copy dependencies for distribution
cp node_modules/codepage/dist/cpexcel.full.js dist/cpexcel.js
cp jszip.js dist/jszip.js
cp ods.js dist/ods.js
uglifyjs $(UGLIFYOPTS) ods.js -o dist/ods.min.js --source-map dist/ods.min.map --preamble "$$(head -n 1 bits/00_header.js)"
misc/strip_sourcemap.sh dist/ods.min.js
.PHONY: aux
aux: $(AUXTARGETS)
.PHONY: ods
ods: ods.js
ODSDEPS=$(sort $(wildcard odsbits/*.js))
ods.flow.js: $(ODSDEPS) ## Build ODS support library
cat $^ | tr -d '\15\32' > $@
.PHONY: nexe
nexe: xlsx.exe
xlsx.exe: bin/xlsx.js xlsx.js
nexe -i bin/xlsx.njs -o xlsx.exe
## Testing
@ -92,6 +87,9 @@ TESTFMT=$(patsubst %,test_%,$(FMT))
$(TESTFMT): test_%:
FMTS=$* make test
.PHONY: demos
demos: demo-browserify demo-webpack demo-requirejs
.PHONY: demo-browserify
demo-browserify: ## Run browserify demo build
make -C demos/browserify
@ -102,6 +100,11 @@ demo-webpack: ## Run webpack demo build
make -C demos/webpack
@echo "start a local server and go to demos/webpack/webpack.html"
.PHONY: demo-requirejs
demo-requirejs: ## Run requirejs demo build
make -C demos/requirejs
@echo "start a local server and go to demos/requirejs/requirejs.html"
## Code Checking
.PHONY: lint

View File

@ -67,8 +67,6 @@ be included directly:
```html
<!-- international support from js-codepage -->
<script src="dist/cpexcel.js"></script>
<!-- ODS support -->
<script src="dist/ods.js"></script>
```
An appropriate version for each dependency is included in the dist/ directory.

View File

@ -2,5 +2,6 @@
/* vim: set ts=2: */
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true */
/*exported XLSX */
var XLSX = {};
(function make_xlsx(XLSX){

View File

@ -1 +1 @@
XLSX.version = '0.8.8';
XLSX.version = '0.9.0';

View File

@ -35,6 +35,33 @@ function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
function cc2str(arr/*:Array<number>*/)/*:string*/ {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);

View File

@ -22,6 +22,7 @@ function getdatabin(data) {
function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
/* OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file/*:string*/) {
var k = keys(zip.files);
var f = file.toLowerCase(), g = f.replace(/\//g,'\\');

View File

@ -1,4 +1,4 @@
var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var attregexg=/([^\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ {
@ -7,14 +7,21 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ {
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) z[q] = v;
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
if(j===q.length) {
//if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_")); // from ods
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
//if(z[k] && q.substr(j-3,3) == "ext") continue; // from ods
z[k] = v;
}
}
return z;
}

View File

@ -1,3 +1,4 @@
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
@ -27,3 +28,30 @@ function write_manifest(manifest/*:Array<Array<string> >*/, opts)/*:string*/ {
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base/*:string*/, file/*:string*/) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}

View File

@ -249,6 +249,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
case 'n': p.v = parseFloat(p.v); break;
case 's':
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
}
p.v = sstr.t;
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;

View File

@ -85,6 +85,7 @@ function process_style_xlml(styles, stag, opts) {
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o)/*:Workbook*/ {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
var i = 0;
if(sid === undefined && row) sid = row.StyleID;
if(sid === undefined && csty) sid = csty.StyleID;
while(styles[sid] !== undefined) {
@ -150,13 +151,15 @@ function xlml_clean_comment(comment/*:any*/) {
}
function xlml_normalize(d)/*:string*/ {
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw new Error("Bad input format: expected Buffer or string");
}
/* TODO: Everything */
var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
/* UOS uses CJK in tags */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts)/*:Workbook*/ {
var str = debom(xlml_normalize(d));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);

View File

@ -1,5 +1,9 @@
var parse_content_xml = (function() {
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
@ -35,7 +39,7 @@ var parse_content_xml = (function() {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
@ -76,7 +80,7 @@ var parse_content_xml = (function() {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
q.F = encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
@ -119,8 +123,8 @@ var parse_content_xml = (function() {
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }

View File

@ -4,13 +4,13 @@ var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
var R=0,C=0, range = decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;

View File

@ -1,21 +1,44 @@
/* Helper functions to call out to ODS */
/* Part 3: Packages */
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) {
opts = opts || ({}/*:any*/);
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data/*:string*/, opts/*:?ParseOpts*/) {
return parse_content_xml(data, opts);
}
function get_ods() {
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./ods.js');
return ODS;
}
function parse_ods(zip, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
return ODS.parse_ods(zip, opts);
}
function write_ods(wb, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
return ODS.write_ods(wb, opts);
}
function parse_fods(data, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_fods) throw new Error("Unsupported ODS");
return ODS.parse_fods(data, opts);
function write_ods(wb/*:any*/, opts/*:any*/) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
/*:: if(!jszip) throw new Error("JSZip is not available"); */
var zip = new jszip();
var f = "";
var manifest/*:Array<Array<string> >*/ = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}

View File

@ -1,4 +1,7 @@
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
XLSX.parse_fods = parse_fods;
XLSX.write_ods = write_ods;
XLSX.parse_zip = parse_zip;
XLSX.read = readSync; //xlsread
XLSX.readFile = readFileSync; //readFile

View File

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

View File

@ -41,6 +41,8 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<br />
<script src="browserify.min.js"></script>
<script>
/*jshint browser:true */
/*global require */
var X = require('xlsx');
var XW = {
/* worker message */

View File

@ -7,4 +7,4 @@ $(TOOL).min.js: $(TOOL).js
.PHONY: $(TOOL).js
$(TOOL).js:
webpack main.js --output-filename $@ --display-modules
webpack main.js --output-filename $@ --display-modules --profile

View File

@ -12,8 +12,7 @@ module.exports = {
},
externals: [
{
'./cptable': 'var cptable',
'../xlsx.js': 'var _XLSX'
'./cptable': 'var cptable'
}
]
}

View File

@ -41,6 +41,8 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<br />
<script src="webpack.min.js"></script>
<script>
/*jshint browser:true */
/*global XLSX */
var X = XLSX;
var XW = {
/* worker message */

745
dist/ods.js vendored
View File

@ -1,745 +0,0 @@
/* ods.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint -W041 */
var ODS = {};
(function make_ods(ODS) {
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
var get_utils = function() {
if(typeof XLSX !== 'undefined') return XLSX.utils;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../xlsx.js').utils;
} catch(e) {
return require('./xlsx.js').utils;
}
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}
function dup(o) {
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
if(typeof o != 'object' || !o) return o;
var out = {};
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
return out;
}
function getdatastr(data) {
if(!data) return null;
if(data.data) return data.data;
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
if(data.asBinary) return data.asBinary();
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
return null;
}
/* ODS and friends only use text files in container */
function getdata(data) { return getdatastr(data); }
/* NOTE: unlike ECMA-376, OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file) {
var f = file; if(zip.files[f]) return zip.files[f];
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
return null;
}
function getzipfile(zip, file) {
var o = safegetzipfile(zip, file);
if(o == null) throw new Error("Cannot find file " + file + " in zip");
return o;
}
function getzipdata(zip, file, safe) {
if(!safe) return getdata(getzipfile(zip, file));
if(!file) return null;
try { return getzipdata(zip, file); } catch(e) { return null; }
}
var _fs, jszip;
if(typeof JSZip !== 'undefined') jszip = JSZip;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
if(typeof jszip === 'undefined') jszip = require('./jszip.js');
_fs = require('fs');
}
}
var attregexg=/[^\s?>\/]+=["'][^"]*['"]/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
var z = [];
var eq = 0, c = 0;
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) {
if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_"));
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
if(z[k] && q.substr(j-3,3) == "ext") continue;
z[k] = v;
}
}
return z;
}
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
var encodings = {
'&quot;': '"',
'&apos;': "'",
'&gt;': '>',
'&lt;': '<',
'&amp;': '&'
};
var rencoding = {
'"': '&quot;',
"'": '&apos;',
'>': '&gt;',
'<': '&lt;',
'&': '&amp;'
};
var rencstr = "&<>'\"".split("");
// TODO: CP remap (need to read file version to determine OS)
/* 22.4.2.4 bstr (Basic String) */
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
function unescapexml(text){
var s = text + '';
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
}
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
function escapexml(text){
var s = text + '';
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
}
function parsexmlbool(value) {
switch(value) {
case '1': case 'true': case 'TRUE': return true;
/* case '0': case 'false': case 'FALSE':*/
default: return false;
}
}
function datenum(v, date1904) {
var epoch = v.getTime();
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
/* copied from js-xls (C) SheetJS Apache2 license */
function xlml_normalize(d) {
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw "badf";
}
/* UOS uses CJK in tags, original regex /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/ */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
}
function write_manifest(manifest, opts) {
var o = [XML_HEADER];
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file, res, tag) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base, file) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig) {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f) {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var parse_content_xml = (function() {
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
month: ["m", "mm"],
year: ["y", "yy"],
hours: ["h", "hh"],
minutes: ["m", "mm"],
seconds: ["s", "ss"],
"am-pm": ["A/P", "AM/PM"],
"day-of-week": ["ddd", "dddd"]
};
return function pcx(d, _opts) {
var opts = _opts || {};
var str = xlml_normalize(d);
var state = [], tmp;
var tag;
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag;
var rowtag;
var Sheets = {}, SheetNames = [], ws = {};
var Rn, q;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {}; merges = [];
}
break;
case 'table-row': case '行': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
rept = 1;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
if(ctag['string-value'] != null) textp = ctag['string-value'];
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {};
textp = "";
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document': // TODO: <office:document> is the root for FODS
case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
case 'styles': // TODO <office:styles>
case 'font-face-decls': // 3.14 <office:font-face-decls>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
case 'settings': // TODO: <office:settings>
case 'config-item-set': // TODO: <office:config-item-set>
case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
case 'config-item-map-named': // TODO: <office:config-item-map-entry>
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
case 'text-box': // 10.4.3 <draw:text-box>
case 'image': // 10.4.4 <draw:image>
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
case 'list-style': // 16.30 <text:list-style>
case 'form': // 13.13 <form:form>
case 'dde-links': // 9.8 <table:dde-links>
case 'annotation': // 14.1 <office:annotation>
case 'event-listeners': // TODO
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'scientific-number': // TODO: <number:scientific-number>
break;
case 'currency-symbol': // TODO: <number:currency-symbol>
break;
case 'currency-style': // TODO: <number:currency-style>
break;
case 'number-style': // 16.27.2 <number:number-style>
case 'percentage-style': // 16.27.9 <number:percentage-style>
case 'date-style': // 16.27.10 <number:date-style>
case 'time-style': // 16.27.18 <number:time-style>
if(Rn[1]==='/'){
number_format_map[NFtag.name] = NF;
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
NF = "";
NFtag = parsexmltag(Rn[0], false);
state.push([Rn[3], true]);
} break;
case 'script': break; // 3.13 <office:script>
case 'libraries': break; // TODO: <ooo:libraries>
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
case 'master-styles': break; // TODO: <office:automatic-styles>
case 'default-style': // TODO: <style:default-style>
case 'page-layout': break; // TODO: <style:page-layout>
case 'style': break; // 16.2 <style:style>
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
case 'number': // 16.27.3 <number:number>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'fraction': break; // TODO 16.27.6 <number:fraction>
case 'day': // 16.27.11 <number:day>
case 'month': // 16.27.12 <number:month>
case 'year': // 16.27.13 <number:year>
case 'era': // 16.27.14 <number:era>
case 'day-of-week': // 16.27.15 <number:day-of-week>
case 'week-of-year': // 16.27.16 <number:week-of-year>
case 'quarter': // 16.27.17 <number:quarter>
case 'hours': // 16.27.19 <number:hours>
case 'minutes': // 16.27.20 <number:minutes>
case 'seconds': // 16.27.21 <number:seconds>
case 'am-pm': // 16.27.22 <number:am-pm>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
case 'boolean': break; // 16.27.24 <number:boolean>
case 'text-style': break; // 16.27.25 <number:text-style>
case 'text': // 16.27.26 <number:text>
if(Rn[0].slice(-2) === "/>") break;
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
case 'number-style':
case 'date-style':
case 'time-style':
NF += str.slice(pidx, Rn.index);
break;
}
else pidx = Rn.index + Rn[0].length;
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
case 'forms': break; // 12.25.2 13.2
case 'table-column': break; // 9.1.6 <table:table-column>
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'named-expression': break; // 9.4.13 <table:named-expression>
case 'sort': break; // 9.4.19 <table:sort>
case 'sort-by': break; // 9.4.20 <table:sort-by>
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
case 'span': break; // <text:span>
case 'line-break': break; // 6.1.5 <text:line-break>
case 'p': case '文本串':
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': case '标题': break; // <*:title> OR <uof:标题>
case 'desc': break; // <*:desc>
case 'table-source': break; // 9.2.6
case 'iteration': break; // 9.4.3 <table:iteration>
case 'content-validations': break; // 9.4.4 <table:
case 'content-validation': break; // 9.4.5 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
case 'list-level-properties': break; // 17.19 <style:
/* 7.3 Document Fields */
case 'sender-firstname': // 7.3.6.2
case 'sender-lastname': // 7.3.6.3
case 'sender-initials': // 7.3.6.4
case 'sender-title': // 7.3.6.5
case 'sender-position': // 7.3.6.6
case 'sender-email': // 7.3.6.7
case 'sender-phone-private': // 7.3.6.8
case 'sender-fax': // 7.3.6.9
case 'sender-company': // 7.3.6.10
case 'sender-phone-work': // 7.3.6.11
case 'sender-street': // 7.3.6.12
case 'sender-city': // 7.3.6.13
case 'sender-postal-code': // 7.3.6.14
case 'sender-country': // 7.3.6.15
case 'sender-state-or-province': // 7.3.6.16
case 'author-name': // 7.3.7.1
case 'author-initials': // 7.3.7.2
case 'chapter': // 7.3.8
case 'file-name': // 7.3.9
case 'template-name': // 7.3.9
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
/* TODO: FODS Properties */
case 'initial-creator':
case 'creator':
case 'creation-date':
case 'generator':
case 'document-statistic':
case 'user-defined':
break;
/* TODO: FODS Config */
case 'config-item':
break;
/* TODO: style tokens */
case 'page-number': break; // TODO <text:page-number>
case 'page-count': break; // TODO <text:page-count>
case 'time': break; // TODO <text:time>
/* 9.6 Data Pilot Tables <table: */
case 'data-pilot-table': // 9.6.3
case 'source-cell-range': // 9.6.5
case 'source-service': // 9.6.6
case 'data-pilot-field': // 9.6.7
case 'data-pilot-level': // 9.6.8
case 'data-pilot-subtotals': // 9.6.9
case 'data-pilot-subtotal': // 9.6.10
case 'data-pilot-members': // 9.6.11
case 'data-pilot-member': // 9.6.12
case 'data-pilot-display-info': // 9.6.13
case 'data-pilot-sort-info': // 9.6.14
case 'data-pilot-layout-info': // 9.6.15
case 'data-pilot-field-reference': // 9.6.16
case 'data-pilot-groups': // 9.6.17
case 'data-pilot-group': // 9.6.18
case 'data-pilot-group-member': // 9.6.19
break;
/* 10.3 Drawing Shapes */
case 'rect': // 10.3.2
break;
/* 14.6 DDE Connections */
case 'dde-connection-decls': // 14.6.2 <text:
case 'dde-connection-decl': // 14.6.3 <text:
case 'dde-link': // 14.6.4 <table:
case 'dde-source': // 14.6.5 <office:
break;
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
/* non-standard */
case 'table-protection': break;
case 'data-pilot-grand-total': break; // <table:
default:
if(Rn[2] === 'dc:') break; // TODO: properties
if(Rn[2] === 'draw:') break; // TODO: drawing
if(Rn[2] === 'style:') break; // TODO: styles
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
if(Rn[2] === 'loext:') break; // ignore undocumented extensions
if(Rn[2] === 'uof:') break; // TODO: uof
if(Rn[2] === '表:') break; // TODO: uof
if(Rn[2] === '字:') break; // TODO: uof
if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
SheetNames: SheetNames
};
return out;
};
})();
var write_content_xml = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var write_ws = function(ws, wb, i, opts) {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
//case 'd': // TODO
//case 'e':
default: o.push(null_cell_xml);
} else o.push(null_cell_xml);
}
o.push(' </table:table-row>\n');
}
o.push(' </table:table>\n');
return o.join("");
};
return function wcx(wb, opts) {
var o = [XML_HEADER];
/* 3.1.3.2 */
if(opts.bookType == "fods") o.push('<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">');
else o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');
if(opts.bookType == "fods") o.push('</office:document>');
else o.push('</office:document-content>');
return o.join("");
};
})();
/* Part 3: Packages */
function parse_ods(zip, opts) {
opts = opts || ({});
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data, opts) {
return parse_content_xml(data, opts);
}
function write_ods(wb, opts) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
var zip = new jszip();
var f = "";
var manifest = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
ODS.parse_ods = parse_ods;
ODS.write_ods = write_ods;
ODS.parse_fods = parse_fods;
})(typeof exports !== 'undefined' ? exports : ODS);

2
dist/ods.min.js vendored

File diff suppressed because one or more lines are too long

1
dist/ods.min.map vendored

File diff suppressed because one or more lines are too long

22
dist/xlsx.core.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

24
dist/xlsx.full.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

622
dist/xlsx.js vendored
View File

@ -2,9 +2,10 @@
/* vim: set ts=2: */
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true */
/*exported XLSX */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.8.8';
XLSX.version = '0.9.0';
var current_codepage = 1200, current_cptable;
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
@ -1299,6 +1300,33 @@ function datenum(v, date1904) {
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
@ -1344,6 +1372,7 @@ function getdatabin(data) {
function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
/* OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file) {
var k = keys(zip.files);
var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
@ -1380,7 +1409,7 @@ if (typeof exports !== 'undefined') {
_fs = require('fs');
}
}
var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var attregexg=/([^\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
@ -1389,14 +1418,21 @@ function parsexmltag(tag, skip_root) {
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) z[q] = v;
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
if(j===q.length) {
//if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_")); // from ods
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
//if(z[k] && q.substr(j-3,3) == "ext") continue; // from ods
z[k] = v;
}
}
return z;
}
@ -2640,6 +2676,63 @@ function write_rels(rels) {
if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
return o.join("");
}
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
}
function write_manifest(manifest, opts) {
var o = [XML_HEADER];
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file, res, tag) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base, file) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}
/* ECMA-376 Part II 11.1 Core Properties Part */
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
var CORE_PROPS = [
@ -7833,6 +7926,17 @@ var XLSXFutureFunctions = {
"_xlfn.Z.TEST": "Z.TEST"
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f) {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var strs = {}; // shared strings
var _ssfopts = {}; // spreadsheet formatting options
@ -8141,6 +8245,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
case 'n': p.v = parseFloat(p.v); break;
case 's':
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
}
p.v = sstr.t;
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;
@ -9412,6 +9520,7 @@ function process_style_xlml(styles, stag, opts) {
function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o) {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
var i = 0;
if(sid === undefined && row) sid = row.StyleID;
if(sid === undefined && csty) sid = csty.StyleID;
while(styles[sid] !== undefined) {
@ -9483,7 +9592,9 @@ function xlml_normalize(d) {
}
/* TODO: Everything */
var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
/* UOS uses CJK in tags */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts) {
var str = debom(xlml_normalize(d));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);
@ -12145,6 +12256,443 @@ function parse_html(str, opts) {
ws['!ref'] = encode_range(range);
return o;
}
var parse_content_xml = (function() {
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
month: ["m", "mm"],
year: ["y", "yy"],
hours: ["h", "hh"],
minutes: ["m", "mm"],
seconds: ["s", "ss"],
"am-pm": ["A/P", "AM/PM"],
"day-of-week": ["ddd", "dddd"]
};
return function pcx(d, _opts) {
var opts = _opts || {};
var str = xlml_normalize(d);
var state = [], tmp;
var tag;
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag;
var rowtag;
var Sheets = {}, SheetNames = [], ws = {};
var Rn, q;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {}; merges = [];
}
break;
case 'table-row': case '行': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
rept = 1;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
if(ctag['string-value'] != null) textp = ctag['string-value'];
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {};
textp = "";
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document': // TODO: <office:document> is the root for FODS
case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
case 'styles': // TODO <office:styles>
case 'font-face-decls': // 3.14 <office:font-face-decls>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
case 'settings': // TODO: <office:settings>
case 'config-item-set': // TODO: <office:config-item-set>
case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
case 'config-item-map-named': // TODO: <office:config-item-map-entry>
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
case 'text-box': // 10.4.3 <draw:text-box>
case 'image': // 10.4.4 <draw:image>
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
case 'list-style': // 16.30 <text:list-style>
case 'form': // 13.13 <form:form>
case 'dde-links': // 9.8 <table:dde-links>
case 'annotation': // 14.1 <office:annotation>
case 'event-listeners': // TODO
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'scientific-number': // TODO: <number:scientific-number>
break;
case 'currency-symbol': // TODO: <number:currency-symbol>
break;
case 'currency-style': // TODO: <number:currency-style>
break;
case 'number-style': // 16.27.2 <number:number-style>
case 'percentage-style': // 16.27.9 <number:percentage-style>
case 'date-style': // 16.27.10 <number:date-style>
case 'time-style': // 16.27.18 <number:time-style>
if(Rn[1]==='/'){
number_format_map[NFtag.name] = NF;
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
NF = "";
NFtag = parsexmltag(Rn[0], false);
state.push([Rn[3], true]);
} break;
case 'script': break; // 3.13 <office:script>
case 'libraries': break; // TODO: <ooo:libraries>
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
case 'master-styles': break; // TODO: <office:automatic-styles>
case 'default-style': // TODO: <style:default-style>
case 'page-layout': break; // TODO: <style:page-layout>
case 'style': break; // 16.2 <style:style>
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
case 'number': // 16.27.3 <number:number>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'fraction': break; // TODO 16.27.6 <number:fraction>
case 'day': // 16.27.11 <number:day>
case 'month': // 16.27.12 <number:month>
case 'year': // 16.27.13 <number:year>
case 'era': // 16.27.14 <number:era>
case 'day-of-week': // 16.27.15 <number:day-of-week>
case 'week-of-year': // 16.27.16 <number:week-of-year>
case 'quarter': // 16.27.17 <number:quarter>
case 'hours': // 16.27.19 <number:hours>
case 'minutes': // 16.27.20 <number:minutes>
case 'seconds': // 16.27.21 <number:seconds>
case 'am-pm': // 16.27.22 <number:am-pm>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
case 'boolean': break; // 16.27.24 <number:boolean>
case 'text-style': break; // 16.27.25 <number:text-style>
case 'text': // 16.27.26 <number:text>
if(Rn[0].slice(-2) === "/>") break;
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
case 'number-style':
case 'date-style':
case 'time-style':
NF += str.slice(pidx, Rn.index);
break;
}
else pidx = Rn.index + Rn[0].length;
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
case 'forms': break; // 12.25.2 13.2
case 'table-column': break; // 9.1.6 <table:table-column>
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'named-expression': break; // 9.4.13 <table:named-expression>
case 'sort': break; // 9.4.19 <table:sort>
case 'sort-by': break; // 9.4.20 <table:sort-by>
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
case 'span': break; // <text:span>
case 'line-break': break; // 6.1.5 <text:line-break>
case 'p': case '文本串':
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': case '标题': break; // <*:title> OR <uof:标题>
case 'desc': break; // <*:desc>
case 'table-source': break; // 9.2.6
case 'iteration': break; // 9.4.3 <table:iteration>
case 'content-validations': break; // 9.4.4 <table:
case 'content-validation': break; // 9.4.5 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
case 'list-level-properties': break; // 17.19 <style:
/* 7.3 Document Fields */
case 'sender-firstname': // 7.3.6.2
case 'sender-lastname': // 7.3.6.3
case 'sender-initials': // 7.3.6.4
case 'sender-title': // 7.3.6.5
case 'sender-position': // 7.3.6.6
case 'sender-email': // 7.3.6.7
case 'sender-phone-private': // 7.3.6.8
case 'sender-fax': // 7.3.6.9
case 'sender-company': // 7.3.6.10
case 'sender-phone-work': // 7.3.6.11
case 'sender-street': // 7.3.6.12
case 'sender-city': // 7.3.6.13
case 'sender-postal-code': // 7.3.6.14
case 'sender-country': // 7.3.6.15
case 'sender-state-or-province': // 7.3.6.16
case 'author-name': // 7.3.7.1
case 'author-initials': // 7.3.7.2
case 'chapter': // 7.3.8
case 'file-name': // 7.3.9
case 'template-name': // 7.3.9
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
/* TODO: FODS Properties */
case 'initial-creator':
case 'creator':
case 'creation-date':
case 'generator':
case 'document-statistic':
case 'user-defined':
break;
/* TODO: FODS Config */
case 'config-item':
break;
/* TODO: style tokens */
case 'page-number': break; // TODO <text:page-number>
case 'page-count': break; // TODO <text:page-count>
case 'time': break; // TODO <text:time>
/* 9.6 Data Pilot Tables <table: */
case 'data-pilot-table': // 9.6.3
case 'source-cell-range': // 9.6.5
case 'source-service': // 9.6.6
case 'data-pilot-field': // 9.6.7
case 'data-pilot-level': // 9.6.8
case 'data-pilot-subtotals': // 9.6.9
case 'data-pilot-subtotal': // 9.6.10
case 'data-pilot-members': // 9.6.11
case 'data-pilot-member': // 9.6.12
case 'data-pilot-display-info': // 9.6.13
case 'data-pilot-sort-info': // 9.6.14
case 'data-pilot-layout-info': // 9.6.15
case 'data-pilot-field-reference': // 9.6.16
case 'data-pilot-groups': // 9.6.17
case 'data-pilot-group': // 9.6.18
case 'data-pilot-group-member': // 9.6.19
break;
/* 10.3 Drawing Shapes */
case 'rect': // 10.3.2
break;
/* 14.6 DDE Connections */
case 'dde-connection-decls': // 14.6.2 <text:
case 'dde-connection-decl': // 14.6.3 <text:
case 'dde-link': // 14.6.4 <table:
case 'dde-source': // 14.6.5 <office:
break;
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
/* non-standard */
case 'table-protection': break;
case 'data-pilot-grand-total': break; // <table:
default:
if(Rn[2] === 'dc:') break; // TODO: properties
if(Rn[2] === 'draw:') break; // TODO: drawing
if(Rn[2] === 'style:') break; // TODO: styles
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
if(Rn[2] === 'loext:') break; // ignore undocumented extensions
if(Rn[2] === 'uof:') break; // TODO: uof
if(Rn[2] === '表:') break; // TODO: uof
if(Rn[2] === '字:') break; // TODO: uof
if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
SheetNames: SheetNames
};
return out;
};
})();
var write_content_xml = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var write_ws = function(ws, wb, i, opts) {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
//case 'd': // TODO
//case 'e':
default: o.push(null_cell_xml);
} else o.push(null_cell_xml);
}
o.push(' </table:table-row>\n');
}
o.push(' </table:table>\n');
return o.join("");
};
return function wcx(wb, opts) {
var o = [XML_HEADER];
/* 3.1.3.2 */
if(opts.bookType == "fods") o.push('<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">');
else o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');
if(opts.bookType == "fods") o.push('</office:document>');
else o.push('</office:document-content>');
return o.join("");
};
})();
/* actual implementation in utils, wrappers are for read/write */
function write_csv_str(wb, o) {
var idx = 0;
@ -12152,26 +12700,48 @@ function write_csv_str(wb, o) {
if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
return sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o);
}
/* Helper functions to call out to ODS */
function get_ods() {
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./ods.js');
return ODS;
}
/* Part 3: Packages */
function parse_ods(zip, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
return ODS.parse_ods(zip, opts);
}
function write_ods(wb, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
return ODS.write_ods(wb, opts);
opts = opts || ({});
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_fods) throw new Error("Unsupported ODS");
return ODS.parse_fods(data, opts);
return parse_content_xml(data, opts);
}
function write_ods(wb, opts) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
var zip = new jszip();
var f = "";
var manifest = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
function fix_opts_func(defaults) {
return function fix_opts(opts) {
@ -12783,6 +13353,9 @@ var utils = {
sheet_to_row_object_array: sheet_to_row_object_array
};
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
XLSX.parse_fods = parse_fods;
XLSX.write_ods = write_ods;
XLSX.parse_zip = parse_zip;
XLSX.read = readSync; //xlsread
XLSX.readFile = readFileSync; //readFile
@ -12794,4 +13367,7 @@ XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;
})(typeof exports !== 'undefined' ? exports : XLSX);
/*exported XLS */
var XLS = XLSX;
/*exported ODS */
var ODS = XLSX;

21
dist/xlsx.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map vendored

File diff suppressed because one or more lines are too long

View File

@ -44,9 +44,9 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<script src="shim.js"></script>
<script src="jszip.js"></script>
<script src="xlsx.js"></script>
<!-- uncomment the next line here and in xlsxworker.js for ODS support -->
<script src="ods.js"></script>
<script>
/*jshint browser:true */
/*global XLSX */
var X = XLSX;
var XW = {
/* worker message */

View File

@ -6,6 +6,9 @@ declare module '../' { declare var exports:XLSXModule; };
declare module 'commander' { declare var exports:any; };
declare module './jszip.js' { declare var exports:any; };
declare module './dist/cpexcel.js' { declare var exports:any; };
declare module 'crypto' { declare var exports:any; };
declare module 'fs' { declare var exports:any; };
type ZIP = any;
*/

View File

@ -1,748 +0,0 @@
/* ods.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint -W041 */
var ODS = {};
(function make_ods(ODS) {
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
/*:: declare var XLSX: any; */
var get_utils = function() {
if(typeof XLSX !== 'undefined') return XLSX.utils;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../xlsx.js').utils;
} catch(e) {
return require('./xlsx.js').utils;
}
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr)/*:string*/ {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}
function dup(o/*:any*/)/*:any*/ {
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
if(typeof o != 'object' || !o) return o;
var out = {};
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
return out;
}
function getdatastr(data)/*:?string*/ {
if(!data) return null;
if(data.data) return data.data;
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
if(data.asBinary) return data.asBinary();
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
return null;
}
/* ODS and friends only use text files in container */
function getdata(data) { return getdatastr(data); }
/* NOTE: unlike ECMA-376, OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file/*:string*/) {
var f = file; if(zip.files[f]) return zip.files[f];
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
return null;
}
function getzipfile(zip, file/*:string*/) {
var o = safegetzipfile(zip, file);
if(o == null) throw new Error("Cannot find file " + file + " in zip");
return o;
}
function getzipdata(zip, file/*:string*/, safe/*:?boolean*/) {
if(!safe) return getdata(getzipfile(zip, file));
if(!file) return null;
try { return getzipdata(zip, file); } catch(e) { return null; }
}
var _fs, jszip;
/*:: declare var JSZip:any; */
if(typeof JSZip !== 'undefined') jszip = JSZip;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
if(typeof jszip === 'undefined') jszip = require('./jszip.js');
_fs = require('fs');
}
}
var attregexg=/[^\s?>\/]+=["'][^"]*['"]/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
var z/*:any*/ = [];
var eq = 0, c = 0;
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) {
if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_"));
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
if(z[k] && q.substr(j-3,3) == "ext") continue;
z[k] = v;
}
}
return z;
}
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
var encodings = {
'&quot;': '"',
'&apos;': "'",
'&gt;': '>',
'&lt;': '<',
'&amp;': '&'
};
var rencoding = {
'"': '&quot;',
"'": '&apos;',
'>': '&gt;',
'<': '&lt;',
'&': '&amp;'
};
var rencstr = "&<>'\"".split("");
// TODO: CP remap (need to read file version to determine OS)
/* 22.4.2.4 bstr (Basic String) */
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
function unescapexml(text){
var s = text + '';
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
}
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
function escapexml(text){
var s = text + '';
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
}
function parsexmlbool(value) {
switch(value) {
case '1': case 'true': case 'TRUE': return true;
/* case '0': case 'false': case 'FALSE':*/
default: return false;
}
}
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = v.getTime();
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
/* copied from js-xls (C) SheetJS Apache2 license */
function xlml_normalize(d)/*:string*/ {
if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw "badf";
}
/* UOS uses CJK in tags, original regex /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/ */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
}
function write_manifest(manifest/*:Array<Array<string> >*/, opts)/*:string*/ {
var o = [XML_HEADER];
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base/*:string*/, file/*:string*/) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig/*:string*/)/*:string*/ {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f/*:string*/)/*:string*/ {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var parse_content_xml = (function() {
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
month: ["m", "mm"],
year: ["y", "yy"],
hours: ["h", "hh"],
minutes: ["m", "mm"],
seconds: ["s", "ss"],
"am-pm": ["A/P", "AM/PM"],
"day-of-week": ["ddd", "dddd"]
};
return function pcx(d, _opts) {
var opts = _opts || {};
var str = xlml_normalize(d);
var state/*:Array<any>*/ = [], tmp;
var tag/*:: = {}*/;
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag/*:: = {name:"", '名称':""}*/;
var rowtag/*:: = {'行号':""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {};
var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {}; merges = [];
}
break;
case 'table-row': case '行': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
rept = 1;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/);
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
if(ctag['string-value'] != null) textp = ctag['string-value'];
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {/*:: t:"", v:null, z:null, w:""*/};
textp = "";
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document': // TODO: <office:document> is the root for FODS
case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
case 'styles': // TODO <office:styles>
case 'font-face-decls': // 3.14 <office:font-face-decls>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
case 'settings': // TODO: <office:settings>
case 'config-item-set': // TODO: <office:config-item-set>
case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
case 'config-item-map-named': // TODO: <office:config-item-map-entry>
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
case 'text-box': // 10.4.3 <draw:text-box>
case 'image': // 10.4.4 <draw:image>
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
case 'list-style': // 16.30 <text:list-style>
case 'form': // 13.13 <form:form>
case 'dde-links': // 9.8 <table:dde-links>
case 'annotation': // 14.1 <office:annotation>
case 'event-listeners': // TODO
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'scientific-number': // TODO: <number:scientific-number>
break;
case 'currency-symbol': // TODO: <number:currency-symbol>
break;
case 'currency-style': // TODO: <number:currency-style>
break;
case 'number-style': // 16.27.2 <number:number-style>
case 'percentage-style': // 16.27.9 <number:percentage-style>
case 'date-style': // 16.27.10 <number:date-style>
case 'time-style': // 16.27.18 <number:time-style>
if(Rn[1]==='/'){
number_format_map[NFtag.name] = NF;
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
NF = "";
NFtag = parsexmltag(Rn[0], false);
state.push([Rn[3], true]);
} break;
case 'script': break; // 3.13 <office:script>
case 'libraries': break; // TODO: <ooo:libraries>
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
case 'master-styles': break; // TODO: <office:automatic-styles>
case 'default-style': // TODO: <style:default-style>
case 'page-layout': break; // TODO: <style:page-layout>
case 'style': break; // 16.2 <style:style>
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
case 'number': // 16.27.3 <number:number>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'fraction': break; // TODO 16.27.6 <number:fraction>
case 'day': // 16.27.11 <number:day>
case 'month': // 16.27.12 <number:month>
case 'year': // 16.27.13 <number:year>
case 'era': // 16.27.14 <number:era>
case 'day-of-week': // 16.27.15 <number:day-of-week>
case 'week-of-year': // 16.27.16 <number:week-of-year>
case 'quarter': // 16.27.17 <number:quarter>
case 'hours': // 16.27.19 <number:hours>
case 'minutes': // 16.27.20 <number:minutes>
case 'seconds': // 16.27.21 <number:seconds>
case 'am-pm': // 16.27.22 <number:am-pm>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
case 'boolean': break; // 16.27.24 <number:boolean>
case 'text-style': break; // 16.27.25 <number:text-style>
case 'text': // 16.27.26 <number:text>
if(Rn[0].slice(-2) === "/>") break;
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
case 'number-style':
case 'date-style':
case 'time-style':
NF += str.slice(pidx, Rn.index);
break;
}
else pidx = Rn.index + Rn[0].length;
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
case 'forms': break; // 12.25.2 13.2
case 'table-column': break; // 9.1.6 <table:table-column>
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'named-expression': break; // 9.4.13 <table:named-expression>
case 'sort': break; // 9.4.19 <table:sort>
case 'sort-by': break; // 9.4.20 <table:sort-by>
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
case 'span': break; // <text:span>
case 'line-break': break; // 6.1.5 <text:line-break>
case 'p': case '文本串':
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': case '标题': break; // <*:title> OR <uof:标题>
case 'desc': break; // <*:desc>
case 'table-source': break; // 9.2.6
case 'iteration': break; // 9.4.3 <table:iteration>
case 'content-validations': break; // 9.4.4 <table:
case 'content-validation': break; // 9.4.5 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
case 'list-level-properties': break; // 17.19 <style:
/* 7.3 Document Fields */
case 'sender-firstname': // 7.3.6.2
case 'sender-lastname': // 7.3.6.3
case 'sender-initials': // 7.3.6.4
case 'sender-title': // 7.3.6.5
case 'sender-position': // 7.3.6.6
case 'sender-email': // 7.3.6.7
case 'sender-phone-private': // 7.3.6.8
case 'sender-fax': // 7.3.6.9
case 'sender-company': // 7.3.6.10
case 'sender-phone-work': // 7.3.6.11
case 'sender-street': // 7.3.6.12
case 'sender-city': // 7.3.6.13
case 'sender-postal-code': // 7.3.6.14
case 'sender-country': // 7.3.6.15
case 'sender-state-or-province': // 7.3.6.16
case 'author-name': // 7.3.7.1
case 'author-initials': // 7.3.7.2
case 'chapter': // 7.3.8
case 'file-name': // 7.3.9
case 'template-name': // 7.3.9
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
/* TODO: FODS Properties */
case 'initial-creator':
case 'creator':
case 'creation-date':
case 'generator':
case 'document-statistic':
case 'user-defined':
break;
/* TODO: FODS Config */
case 'config-item':
break;
/* TODO: style tokens */
case 'page-number': break; // TODO <text:page-number>
case 'page-count': break; // TODO <text:page-count>
case 'time': break; // TODO <text:time>
/* 9.6 Data Pilot Tables <table: */
case 'data-pilot-table': // 9.6.3
case 'source-cell-range': // 9.6.5
case 'source-service': // 9.6.6
case 'data-pilot-field': // 9.6.7
case 'data-pilot-level': // 9.6.8
case 'data-pilot-subtotals': // 9.6.9
case 'data-pilot-subtotal': // 9.6.10
case 'data-pilot-members': // 9.6.11
case 'data-pilot-member': // 9.6.12
case 'data-pilot-display-info': // 9.6.13
case 'data-pilot-sort-info': // 9.6.14
case 'data-pilot-layout-info': // 9.6.15
case 'data-pilot-field-reference': // 9.6.16
case 'data-pilot-groups': // 9.6.17
case 'data-pilot-group': // 9.6.18
case 'data-pilot-group-member': // 9.6.19
break;
/* 10.3 Drawing Shapes */
case 'rect': // 10.3.2
break;
/* 14.6 DDE Connections */
case 'dde-connection-decls': // 14.6.2 <text:
case 'dde-connection-decl': // 14.6.3 <text:
case 'dde-link': // 14.6.4 <table:
case 'dde-source': // 14.6.5 <office:
break;
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
/* non-standard */
case 'table-protection': break;
case 'data-pilot-grand-total': break; // <table:
default:
if(Rn[2] === 'dc:') break; // TODO: properties
if(Rn[2] === 'draw:') break; // TODO: drawing
if(Rn[2] === 'style:') break; // TODO: styles
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
if(Rn[2] === 'loext:') break; // ignore undocumented extensions
if(Rn[2] === 'uof:') break; // TODO: uof
if(Rn[2] === '表:') break; // TODO: uof
if(Rn[2] === '字:') break; // TODO: uof
if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
SheetNames: SheetNames
};
return out;
};
})();
var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
//case 'd': // TODO
//case 'e':
default: o.push(null_cell_xml);
} else o.push(null_cell_xml);
}
o.push(' </table:table-row>\n');
}
o.push(' </table:table>\n');
return o.join("");
};
return function wcx(wb, opts) {
var o = [XML_HEADER];
/* 3.1.3.2 */
if(opts.bookType == "fods") o.push('<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">');
else o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');
if(opts.bookType == "fods") o.push('</office:document>');
else o.push('</office:document-content>');
return o.join("");
};
})();
/* Part 3: Packages */
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) {
opts = opts || ({}/*:any*/);
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data/*:string*/, opts/*:?ParseOpts*/) {
return parse_content_xml(data, opts);
}
function write_ods(wb/*:any*/, opts/*:any*/) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
/*:: if(!jszip) throw new Error("JSZip is not available"); */
var zip = new jszip();
var f = "";
var manifest/*:Array<Array<string> >*/ = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
ODS.parse_ods = parse_ods;
ODS.write_ods = write_ods;
ODS.parse_fods = parse_fods;
})(typeof exports !== 'undefined' ? exports : ODS);

745
ods.js
View File

@ -1,745 +0,0 @@
/* ods.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint -W041 */
var ODS = {};
(function make_ods(ODS) {
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
var get_utils = function() {
if(typeof XLSX !== 'undefined') return XLSX.utils;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../xlsx.js').utils;
} catch(e) {
return require('./xlsx.js').utils;
}
throw new Error("Cannot find XLSX utils");
};
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}
function dup(o) {
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
if(typeof o != 'object' || !o) return o;
var out = {};
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
return out;
}
function getdatastr(data) {
if(!data) return null;
if(data.data) return data.data;
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
if(data.asBinary) return data.asBinary();
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
return null;
}
/* ODS and friends only use text files in container */
function getdata(data) { return getdatastr(data); }
/* NOTE: unlike ECMA-376, OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file) {
var f = file; if(zip.files[f]) return zip.files[f];
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
return null;
}
function getzipfile(zip, file) {
var o = safegetzipfile(zip, file);
if(o == null) throw new Error("Cannot find file " + file + " in zip");
return o;
}
function getzipdata(zip, file, safe) {
if(!safe) return getdata(getzipfile(zip, file));
if(!file) return null;
try { return getzipdata(zip, file); } catch(e) { return null; }
}
var _fs, jszip;
if(typeof JSZip !== 'undefined') jszip = JSZip;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
if(typeof jszip === 'undefined') jszip = require('./jszip.js');
_fs = require('fs');
}
}
var attregexg=/[^\s?>\/]+=["'][^"]*['"]/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
var z = [];
var eq = 0, c = 0;
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) {
if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_"));
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
if(z[k] && q.substr(j-3,3) == "ext") continue;
z[k] = v;
}
}
return z;
}
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
var encodings = {
'&quot;': '"',
'&apos;': "'",
'&gt;': '>',
'&lt;': '<',
'&amp;': '&'
};
var rencoding = {
'"': '&quot;',
"'": '&apos;',
'>': '&gt;',
'<': '&lt;',
'&': '&amp;'
};
var rencstr = "&<>'\"".split("");
// TODO: CP remap (need to read file version to determine OS)
/* 22.4.2.4 bstr (Basic String) */
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
function unescapexml(text){
var s = text + '';
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
}
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
function escapexml(text){
var s = text + '';
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
}
function parsexmlbool(value) {
switch(value) {
case '1': case 'true': case 'TRUE': return true;
/* case '0': case 'false': case 'FALSE':*/
default: return false;
}
}
function datenum(v, date1904) {
var epoch = v.getTime();
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
/* copied from js-xls (C) SheetJS Apache2 license */
function xlml_normalize(d) {
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw "badf";
}
/* UOS uses CJK in tags, original regex /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/ */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
}
function write_manifest(manifest, opts) {
var o = [XML_HEADER];
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file, res, tag) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base, file) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig) {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f) {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var parse_content_xml = (function() {
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
month: ["m", "mm"],
year: ["y", "yy"],
hours: ["h", "hh"],
minutes: ["m", "mm"],
seconds: ["s", "ss"],
"am-pm": ["A/P", "AM/PM"],
"day-of-week": ["ddd", "dddd"]
};
return function pcx(d, _opts) {
var opts = _opts || {};
var str = xlml_normalize(d);
var state = [], tmp;
var tag;
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag;
var rowtag;
var Sheets = {}, SheetNames = [], ws = {};
var Rn, q;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = get_utils().encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {}; merges = [];
}
break;
case 'table-row': case '行': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
rept = 1;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = get_utils().encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
if(ctag['string-value'] != null) textp = ctag['string-value'];
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[get_utils().encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {};
textp = "";
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document': // TODO: <office:document> is the root for FODS
case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
case 'styles': // TODO <office:styles>
case 'font-face-decls': // 3.14 <office:font-face-decls>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
case 'settings': // TODO: <office:settings>
case 'config-item-set': // TODO: <office:config-item-set>
case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
case 'config-item-map-named': // TODO: <office:config-item-map-entry>
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
case 'text-box': // 10.4.3 <draw:text-box>
case 'image': // 10.4.4 <draw:image>
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
case 'list-style': // 16.30 <text:list-style>
case 'form': // 13.13 <form:form>
case 'dde-links': // 9.8 <table:dde-links>
case 'annotation': // 14.1 <office:annotation>
case 'event-listeners': // TODO
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'scientific-number': // TODO: <number:scientific-number>
break;
case 'currency-symbol': // TODO: <number:currency-symbol>
break;
case 'currency-style': // TODO: <number:currency-style>
break;
case 'number-style': // 16.27.2 <number:number-style>
case 'percentage-style': // 16.27.9 <number:percentage-style>
case 'date-style': // 16.27.10 <number:date-style>
case 'time-style': // 16.27.18 <number:time-style>
if(Rn[1]==='/'){
number_format_map[NFtag.name] = NF;
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
NF = "";
NFtag = parsexmltag(Rn[0], false);
state.push([Rn[3], true]);
} break;
case 'script': break; // 3.13 <office:script>
case 'libraries': break; // TODO: <ooo:libraries>
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
case 'master-styles': break; // TODO: <office:automatic-styles>
case 'default-style': // TODO: <style:default-style>
case 'page-layout': break; // TODO: <style:page-layout>
case 'style': break; // 16.2 <style:style>
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
case 'number': // 16.27.3 <number:number>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'fraction': break; // TODO 16.27.6 <number:fraction>
case 'day': // 16.27.11 <number:day>
case 'month': // 16.27.12 <number:month>
case 'year': // 16.27.13 <number:year>
case 'era': // 16.27.14 <number:era>
case 'day-of-week': // 16.27.15 <number:day-of-week>
case 'week-of-year': // 16.27.16 <number:week-of-year>
case 'quarter': // 16.27.17 <number:quarter>
case 'hours': // 16.27.19 <number:hours>
case 'minutes': // 16.27.20 <number:minutes>
case 'seconds': // 16.27.21 <number:seconds>
case 'am-pm': // 16.27.22 <number:am-pm>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
case 'boolean': break; // 16.27.24 <number:boolean>
case 'text-style': break; // 16.27.25 <number:text-style>
case 'text': // 16.27.26 <number:text>
if(Rn[0].slice(-2) === "/>") break;
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
case 'number-style':
case 'date-style':
case 'time-style':
NF += str.slice(pidx, Rn.index);
break;
}
else pidx = Rn.index + Rn[0].length;
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
case 'forms': break; // 12.25.2 13.2
case 'table-column': break; // 9.1.6 <table:table-column>
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'named-expression': break; // 9.4.13 <table:named-expression>
case 'sort': break; // 9.4.19 <table:sort>
case 'sort-by': break; // 9.4.20 <table:sort-by>
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
case 'span': break; // <text:span>
case 'line-break': break; // 6.1.5 <text:line-break>
case 'p': case '文本串':
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': case '标题': break; // <*:title> OR <uof:标题>
case 'desc': break; // <*:desc>
case 'table-source': break; // 9.2.6
case 'iteration': break; // 9.4.3 <table:iteration>
case 'content-validations': break; // 9.4.4 <table:
case 'content-validation': break; // 9.4.5 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
case 'list-level-properties': break; // 17.19 <style:
/* 7.3 Document Fields */
case 'sender-firstname': // 7.3.6.2
case 'sender-lastname': // 7.3.6.3
case 'sender-initials': // 7.3.6.4
case 'sender-title': // 7.3.6.5
case 'sender-position': // 7.3.6.6
case 'sender-email': // 7.3.6.7
case 'sender-phone-private': // 7.3.6.8
case 'sender-fax': // 7.3.6.9
case 'sender-company': // 7.3.6.10
case 'sender-phone-work': // 7.3.6.11
case 'sender-street': // 7.3.6.12
case 'sender-city': // 7.3.6.13
case 'sender-postal-code': // 7.3.6.14
case 'sender-country': // 7.3.6.15
case 'sender-state-or-province': // 7.3.6.16
case 'author-name': // 7.3.7.1
case 'author-initials': // 7.3.7.2
case 'chapter': // 7.3.8
case 'file-name': // 7.3.9
case 'template-name': // 7.3.9
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
/* TODO: FODS Properties */
case 'initial-creator':
case 'creator':
case 'creation-date':
case 'generator':
case 'document-statistic':
case 'user-defined':
break;
/* TODO: FODS Config */
case 'config-item':
break;
/* TODO: style tokens */
case 'page-number': break; // TODO <text:page-number>
case 'page-count': break; // TODO <text:page-count>
case 'time': break; // TODO <text:time>
/* 9.6 Data Pilot Tables <table: */
case 'data-pilot-table': // 9.6.3
case 'source-cell-range': // 9.6.5
case 'source-service': // 9.6.6
case 'data-pilot-field': // 9.6.7
case 'data-pilot-level': // 9.6.8
case 'data-pilot-subtotals': // 9.6.9
case 'data-pilot-subtotal': // 9.6.10
case 'data-pilot-members': // 9.6.11
case 'data-pilot-member': // 9.6.12
case 'data-pilot-display-info': // 9.6.13
case 'data-pilot-sort-info': // 9.6.14
case 'data-pilot-layout-info': // 9.6.15
case 'data-pilot-field-reference': // 9.6.16
case 'data-pilot-groups': // 9.6.17
case 'data-pilot-group': // 9.6.18
case 'data-pilot-group-member': // 9.6.19
break;
/* 10.3 Drawing Shapes */
case 'rect': // 10.3.2
break;
/* 14.6 DDE Connections */
case 'dde-connection-decls': // 14.6.2 <text:
case 'dde-connection-decl': // 14.6.3 <text:
case 'dde-link': // 14.6.4 <table:
case 'dde-source': // 14.6.5 <office:
break;
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
/* non-standard */
case 'table-protection': break;
case 'data-pilot-grand-total': break; // <table:
default:
if(Rn[2] === 'dc:') break; // TODO: properties
if(Rn[2] === 'draw:') break; // TODO: drawing
if(Rn[2] === 'style:') break; // TODO: styles
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
if(Rn[2] === 'loext:') break; // ignore undocumented extensions
if(Rn[2] === 'uof:') break; // TODO: uof
if(Rn[2] === '表:') break; // TODO: uof
if(Rn[2] === '字:') break; // TODO: uof
if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
SheetNames: SheetNames
};
return out;
};
})();
var write_content_xml = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var write_ws = function(ws, wb, i, opts) {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = get_utils().decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = get_utils().encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
//case 'd': // TODO
//case 'e':
default: o.push(null_cell_xml);
} else o.push(null_cell_xml);
}
o.push(' </table:table-row>\n');
}
o.push(' </table:table>\n');
return o.join("");
};
return function wcx(wb, opts) {
var o = [XML_HEADER];
/* 3.1.3.2 */
if(opts.bookType == "fods") o.push('<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">');
else o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');
if(opts.bookType == "fods") o.push('</office:document>');
else o.push('</office:document-content>');
return o.join("");
};
})();
/* Part 3: Packages */
function parse_ods(zip, opts) {
opts = opts || ({});
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data, opts) {
return parse_content_xml(data, opts);
}
function write_ods(wb, opts) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
var zip = new jszip();
var f = "";
var manifest = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
ODS.parse_ods = parse_ods;
ODS.write_ods = write_ods;
ODS.parse_fods = parse_fods;
})(typeof exports !== 'undefined' ? exports : ODS);

View File

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

View File

@ -1,6 +0,0 @@
/* ods.js (C) 2014-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint -W041 */
var ODS = {};
(function make_ods(ODS) {
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */

View File

@ -1,10 +0,0 @@
/*:: declare var XLSX: any; */
var get_utils = function() {
if(typeof XLSX !== 'undefined') return XLSX.utils;
if(typeof module !== "undefined" && typeof require !== 'undefined') try {
return require('../xlsx.js').utils;
} catch(e) {
return require('./xlsx.js').utils;
}
throw new Error("Cannot find XLSX utils");
};

View File

@ -1,15 +0,0 @@
var has_buf = (typeof Buffer !== 'undefined');
function cc2str(arr)/*:string*/ {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
return o;
}
function dup(o/*:any*/)/*:any*/ {
if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o));
if(typeof o != 'object' || !o) return o;
var out = {};
for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
return out;
}

View File

@ -1,41 +0,0 @@
function getdatastr(data)/*:?string*/ {
if(!data) return null;
if(data.data) return data.data;
if(data.asNodeBuffer && has_buf) return data.asNodeBuffer().toString('binary');
if(data.asBinary) return data.asBinary();
if(data._data && data._data.getContent) return cc2str(Array.prototype.slice.call(data._data.getContent(),0));
return null;
}
/* ODS and friends only use text files in container */
function getdata(data) { return getdatastr(data); }
/* NOTE: unlike ECMA-376, OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file/*:string*/) {
var f = file; if(zip.files[f]) return zip.files[f];
f = file.toLowerCase(); if(zip.files[f]) return zip.files[f];
f = f.replace(/\//g,'\\'); if(zip.files[f]) return zip.files[f];
return null;
}
function getzipfile(zip, file/*:string*/) {
var o = safegetzipfile(zip, file);
if(o == null) throw new Error("Cannot find file " + file + " in zip");
return o;
}
function getzipdata(zip, file/*:string*/, safe/*:?boolean*/) {
if(!safe) return getdata(getzipfile(zip, file));
if(!file) return null;
try { return getzipdata(zip, file); } catch(e) { return null; }
}
var _fs, jszip;
/*:: declare var JSZip:any; */
if(typeof JSZip !== 'undefined') jszip = JSZip;
if (typeof exports !== 'undefined') {
if (typeof module !== 'undefined' && module.exports) {
if(typeof jszip === 'undefined') jszip = require('./jszip.js');
_fs = require('fs');
}
}

View File

@ -1,100 +0,0 @@
var attregexg=/[^\s?>\/]+=["'][^"]*['"]/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
var z/*:any*/ = [];
var eq = 0, c = 0;
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) {
if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_"));
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
if(z[k] && q.substr(j-3,3) == "ext") continue;
z[k] = v;
}
}
return z;
}
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
var encodings = {
'&quot;': '"',
'&apos;': "'",
'&gt;': '>',
'&lt;': '<',
'&amp;': '&'
};
var rencoding = {
'"': '&quot;',
"'": '&apos;',
'>': '&gt;',
'<': '&lt;',
'&': '&amp;'
};
var rencstr = "&<>'\"".split("");
// TODO: CP remap (need to read file version to determine OS)
/* 22.4.2.4 bstr (Basic String) */
var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g;
function unescapexml(text){
var s = text + '';
return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
}
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
function escapexml(text){
var s = text + '';
return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).substr(-4) + "_";});
}
function parsexmlbool(value) {
switch(value) {
case '1': case 'true': case 'TRUE': return true;
/* case '0': case 'false': case 'FALSE':*/
default: return false;
}
}
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = v.getTime();
if(date1904) epoch += 1462*24*60*60*1000;
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';

View File

@ -1,9 +0,0 @@
/* copied from js-xls (C) SheetJS Apache2 license */
function xlml_normalize(d)/*:string*/ {
if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw "badf";
}
/* UOS uses CJK in tags, original regex /<(\/?)([a-z0-9]*:|)([\w-]+)[^>]*>/ */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;

View File

@ -1,26 +0,0 @@
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base/*:string*/, file/*:string*/) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}

View File

@ -1,20 +0,0 @@
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var utf8read = function utf8reada(orig/*:string*/)/*:string*/ {
var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
while (i < orig.length) {
c = orig.charCodeAt(i++);
if (c < 128) { out += String.fromCharCode(c); continue; }
d = orig.charCodeAt(i++);
if (c>191 && c<224) { out += String.fromCharCode(((c & 31) << 6) | (d & 63)); continue; }
e = orig.charCodeAt(i++);
if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
f = orig.charCodeAt(i++);
w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
out += String.fromCharCode(0xDC00 + (w&1023));
}
return out;
};

View File

@ -1,13 +0,0 @@
/* Part 3: Packages */
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) {
opts = opts || ({}/*:any*/);
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data/*:string*/, opts/*:?ParseOpts*/) {
return parse_content_xml(data, opts);
}

View File

@ -1,31 +0,0 @@
function write_ods(wb/*:any*/, opts/*:any*/) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
/*:: if(!jszip) throw new Error("JSZip is not available"); */
var zip = new jszip();
var f = "";
var manifest/*:Array<Array<string> >*/ = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}

View File

@ -1,3 +0,0 @@
ODS.parse_ods = parse_ods;
ODS.write_ods = write_ods;
ODS.parse_fods = parse_fods;

View File

@ -1 +0,0 @@
})(typeof exports !== 'undefined' ? exports : ODS);

View File

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.8.8",
"version": "0.9.0",
"author": "sheetjs",
"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS (ODS/FODS/UOS) spreadsheet parser and writer",
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ],
@ -11,8 +11,7 @@
"browser": {
"node": false,
"crypto": false,
"fs": false,
"../xlsx.js": false
"fs": false
},
"dependencies": {
"exit-on-epipe":"",

50
test.js
View File

@ -206,9 +206,11 @@ describe('should parse test files', function() {
describe('parse options', function() {
var html_cell_types = ['s'];
before(function() {
var bef = (function() {
X = require(modp);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
describe('cell', function() {
it('XLSX should generate HTML by default', function() {
var wb = X.readFile(paths.cstxlsx);
@ -491,14 +493,22 @@ describe('input formats', function() {
describe('output formats', function() {
var wb1, wb2, wb3, wb4;
before(function() {
var bef = (function() {
X = require(modp);
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
wb3 = X.readFile(paths.cpxls);
wb4 = X.readFile(paths.cpxml);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it('should write binary strings', function() {
if(!wb1) {
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
wb3 = X.readFile(paths.cpxls);
wb4 = X.readFile(paths.cpxml);
}
X.write(wb1, {type: 'binary'});
X.write(wb2, {type: 'binary'});
X.write(wb3, {type: 'binary'});
@ -603,12 +613,14 @@ describe('parse features', function() {
describe('should parse core properties and custom properties', function() {
var wb1, wb2;
before(function() {
var bef = (function() {
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
wb3 = X.readFile(paths.cpxls);
wb4 = X.readFile(paths.cpxml);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it(N1 + ' should parse core properties', function() { coreprop(wb1); });
it(N2 + ' should parse core properties', function() { coreprop(wb2); });
@ -658,8 +670,8 @@ describe('parse features', function() {
});
describe('merge cells',function() {
var wb1, wb2;
before(function() {
var wb1, wb2, wb3, wb4, wb5;
var bef = (function() {
X = require(modp);
wb1 = X.readFile(paths.mcxlsx);
wb2 = X.readFile(paths.mcxlsb);
@ -667,6 +679,8 @@ describe('parse features', function() {
wb4 = X.readFile(paths.mcxls);
wb5 = X.readFile(paths.mcxml);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it('should have !merges', function() {
assert(wb1.Sheets.Merge['!merges']);
assert(wb2.Sheets.Merge['!merges']);
@ -682,14 +696,16 @@ describe('parse features', function() {
});
describe('should find hyperlinks', function() {
var wb1, wb2;
before(function() {
var wb1, wb2, wb3, wb4;
var bef = (function() {
X = require(modp);
wb1 = X.readFile(paths.hlxlsx);
wb2 = X.readFile(paths.hlxlsb);
wb3 = X.readFile(paths.hlxls);
wb4 = X.readFile(paths.hlxml);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
function hlink(wb) {
var ws = wb.Sheets.Sheet1;
@ -730,7 +746,7 @@ describe('parse features', function() {
describe('should correctly handle styles', function() {
var wsxls, wsxlsx, rn, rn2;
before(function() {
var bef = (function() {
wsxls=X.readFile(paths.cssxls, {cellStyles:true,WTF:1}).Sheets.Sheet1;
wsxlsx=X.readFile(paths.cssxlsx, {cellStyles:true,WTF:1}).Sheets.Sheet1;
rn = function(range) {
@ -742,6 +758,8 @@ describe('parse features', function() {
};
rn2 = function(r) { return [].concat.apply([], r.split(",").map(rn)); };
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
var ranges = [
'A1:D1,F1:G1', 'A2:D2,F2:G2', /* rows */
'A3:A10', 'B3:B10', 'E1:E10', 'F6:F8', /* cols */
@ -812,12 +830,14 @@ function seq(end, start) {
}
describe('roundtrip features', function() {
before(function() {
var bef = (function() {
X = require(modp);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
describe('should parse core properties and custom properties', function() {
var wb1, wb2, base = './tmp/cp';
before(function() {
var bef = (function() {
wb1 = X.readFile(paths.cpxlsx);
wb2 = X.readFile(paths.cpxlsb);
fullex.forEach(function(p) {
@ -825,6 +845,8 @@ describe('roundtrip features', function() {
X.writeFile(wb2, base + '.xlsb' + p);
});
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
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);
@ -973,7 +995,7 @@ describe('json output', function() {
}
}
var data, ws;
before(function() {
var bef = (function() {
data = [
[1,2,3],
[true, false, null, "sheetjs"],
@ -982,6 +1004,8 @@ describe('json output', function() {
];
ws = sheet_from_array_of_arrays(data);
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it('should use first-row headers and full sheet by default', function() {
var json = X.utils.sheet_to_json(ws);
assert.equal(json.length, data.length - 1);
@ -1037,7 +1061,7 @@ describe('json output', function() {
describe('js -> file -> js', function() {
var data, ws, wb, BIN="binary";
before(function() {
var bef = (function() {
data = [
[1,2,3],
[true, false, null, "sheetjs"],
@ -1047,6 +1071,8 @@ describe('js -> file -> js', function() {
ws = sheet_from_array_of_arrays(data);
wb = { SheetNames: ['Sheet1'], Sheets: {Sheet1: ws} };
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
function eqcell(wb1, wb2, s, a) {
assert.equal(wb1.Sheets[s][a].v, wb2.Sheets[s][a].v);
assert.equal(wb1.Sheets[s][a].t, wb2.Sheets[s][a].t);

173
tests.lst
View File

@ -11,6 +11,7 @@ custom_properties.xlsb
defined_names_simple.xlsb
formula_stress_test.xlsb
formulae_test_simple.xlsb
hyperlink_no_rels.xlsb
hyperlink_stress_test_2011.xlsb
large_strings.xlsb.pending
merge_cells.xlsb
@ -19,6 +20,7 @@ number_format.xlsb
number_format_entities.xlsb
number_format_russian.xlsb
numfmt_1_russian.xlsb
phonetic_text.xlsb
pivot_table_named_range.xlsb
pivot_table_test.xlsb
rich_text_stress.xlsb
@ -65,6 +67,7 @@ apachepoi_48539.xlsx
apachepoi_48703.xlsx
apachepoi_48779.xlsx
apachepoi_48923.xlsx
apachepoi_48962.xlsx
apachepoi_49156.xlsx
apachepoi_49273.xlsx
apachepoi_49325.xlsx
@ -75,6 +78,7 @@ apachepoi_49928.xlsx
apachepoi_49966.xlsx
apachepoi_50096.xlsx
apachepoi_50299.xlsx
apachepoi_50755_workday_formula_example.xlsx
apachepoi_50784-font_theme_colours.xlsx
apachepoi_50786-indexed_colours.xlsx
apachepoi_50795.xlsx
@ -82,14 +86,20 @@ apachepoi_50846-border_colours.xlsx
apachepoi_50867_with_table.xlsx
apachepoi_51222.xlsx
apachepoi_51470.xlsx
apachepoi_51519.xlsx
apachepoi_51585.xlsx
apachepoi_51626.xlsx
apachepoi_51626_contact.xlsx
apachepoi_51710.xlsx
apachepoi_51850.xlsx
apachepoi_51963.xlsx
apachepoi_51998.xlsx
apachepoi_52348.xlsx
apachepoi_52425.xlsx
apachepoi_52575_main.xlsx
apachepoi_52716.xlsx
apachepoi_53101.xlsx
apachepoi_53105.xlsx
apachepoi_53282.xlsx
apachepoi_53282b.xlsx
apachepoi_53568.xlsx
@ -102,11 +112,13 @@ apachepoi_54084 - Greek - beyond BMP.xlsx
apachepoi_54206.xlsx
apachepoi_54288-ref.xlsx
apachepoi_54288.xlsx
apachepoi_54399.xlsx
apachepoi_54436.xlsx
apachepoi_54524.xlsx
apachepoi_54607.xlsx
apachepoi_54764-2.xlsx
apachepoi_54764.xlsx
apachepoi_55406_Conditional_formatting_sample.xlsx
apachepoi_55640.xlsx
apachepoi_55745.xlsx
apachepoi_55850.xlsx
@ -122,47 +134,105 @@ apachepoi_56169.xlsx
apachepoi_56170.xlsx
apachepoi_56274.xlsx
apachepoi_56278.xlsx
apachepoi_56295.xlsx
apachepoi_56315.xlsx
apachepoi_56420.xlsx
apachepoi_56502.xlsx
apachepoi_56511.xlsx
apachepoi_56514.xlsx
apachepoi_56574.xlsx
apachepoi_56644.xlsx
apachepoi_56688_1.xlsx
apachepoi_56688_2.xlsx
apachepoi_56688_3.xlsx
apachepoi_56688_4.xlsx
# apachepoi_56702.xlsx ## xlsb bad xnum
apachepoi_56702.xlsx
apachepoi_56730.xlsx
apachepoi_56737.xlsx
apachepoi_56822-Countifs.xlsx
apachepoi_56957.xlsx
apachepoi_57171_57163_57165.xlsx
apachepoi_57176.xlsx
apachepoi_57196.xlsx
apachepoi_57236.xlsx
apachepoi_57362.xlsx
apachepoi_57423.xlsx
apachepoi_57482-OnlyNumeric.xlsx
apachepoi_57523.xlsx
apachepoi_57535.xlsx
apachepoi_57798.xlsx
apachepoi_57826.xlsx
apachepoi_57828.xlsx
apachepoi_57838.xlsx
apachepoi_57890.xlsx
apachepoi_57893-many-merges.xlsx.pending
apachepoi_57914.xlsx
apachepoi_58315.xlsx
apachepoi_58325_db.xlsx
apachepoi_58325_lt.xlsx
# apachepoi_58616.xlsx # Cannot find Workbook stream
apachepoi_58648.xlsx
apachepoi_58731.xlsx
apachepoi_58747.xlsx
apachepoi_58760.xlsx
apachepoi_59021.xlsx
apachepoi_59026.xlsx
apachepoi_59106.xlsx
apachepoi_59132.xlsx
apachepoi_59264.xlsx
apachepoi_59687.xlsx
apachepoi_59736.xlsx
apachepoi_59746_NoRowNums.xlsx
apachepoi_59775.xlsx
apachepoi_60255_extra_drawingparts.xlsx
apachepoi_60289.xlsx
#apachepoi_60825.xlsx # Missing worksheet xml file
apachepoi_AverageTaxRates.xlsx
apachepoi_Booleans.xlsx
apachepoi_BrNotClosed.xlsx
apachepoi_ConditionalFormattingSamples.xlsx
apachepoi_CustomXMLMapping-singleattributenamespace.xlsx
apachepoi_CustomXMLMappings-complex-type.xlsx
apachepoi_CustomXMLMappings.xlsx
apachepoi_CustomXmlMappings-inverse-order.xlsx
apachepoi_DataTableCities.xlsx
apachepoi_DataValidationEvaluations.xlsx
apachepoi_DataValidations-49244.xlsx
apachepoi_DateFormatTests.xlsx
apachepoi_ElapsedFormatTests.xlsx
apachepoi_ExcelTables.xlsx
apachepoi_ForShifting.xlsx
apachepoi_FormatChoiceTests.xlsx
apachepoi_FormatConditionTests.xlsx
apachepoi_FormatKM.xlsx
apachepoi_Formatting.xlsx
apachepoi_FormulaEvalTestData_Copy.xlsx
apachepoi_FormulaSheetRange.xlsx
apachepoi_GeneralFormatTests.xlsx
apachepoi_GroupTest.xlsx
apachepoi_InlineStrings.xlsx
apachepoi_Intersection-52111-xssf.xlsx
apachepoi_NewStyleConditionalFormattings.xlsx
apachepoi_NewlineInFormulas.xlsx
apachepoi_NumberFormatApproxTests.xlsx
apachepoi_NumberFormatTests.xlsx
apachepoi_RepeatingRowsCols.xlsx
apachepoi_SampleSS.strict.xlsx
apachepoi_SampleSS.xlsx
apachepoi_SheetTabColors.xlsx
apachepoi_ShrinkToFit.xlsx
apachepoi_SimpleMultiCell.xlsx
apachepoi_SimpleNormal.xlsx
apachepoi_SimpleScatterChart.xlsx
apachepoi_SimpleStrict.xlsx
apachepoi_SimpleWithComments.xlsx
apachepoi_StructuredReferences.xlsx
apachepoi_StructuredRefs-lots-with-lookups.xlsx
apachepoi_Tables.xlsx
apachepoi_TestShiftRowSharedFormula.xlsx
apachepoi_TextFormatTests.xlsx
apachepoi_Themes.xlsx
apachepoi_Themes2.xlsx
apachepoi_TwoSheetsNoneHidden.xlsx
apachepoi_TwoSheetsOneHidden.xlsx
apachepoi_WithChart.xlsx
@ -177,21 +247,34 @@ apachepoi_WithTextBox2.xlsx
apachepoi_WithThreeCharts.xlsx
apachepoi_WithTwoCharts.xlsx
apachepoi_WithVariousData.xlsx
apachepoi_XSSFSheet.copyRows.xlsx
apachepoi_atp.xlsx
apachepoi_chartTitle_noTitle.xlsx
apachepoi_chartTitle_withTitle.xlsx
apachepoi_chart_sheet.xlsx.pending
apachepoi_commentTest.xlsx
apachepoi_comments.xlsx
apachepoi_craftonhills.edu_programreview_report.aspx_goalpriorityreport_0011d159-1eeb-4b63-8833-867b0926e5f3.xlsx
apachepoi_evaluate_formula_with_structured_table_references.xlsx
apachepoi_headerFooterTest.xlsx
apachepoi_noSharedStringTable.xlsx
apachepoi_picture.xlsx
apachepoi_poc-shared-strings.xlsx
apachepoi_poc-xmlbomb.xlsx
# apachepoi_protected_passtika.xlsx # password
apachepoi_ref-56737.xlsx
apachepoi_ref2-56737.xlsx
apachepoi_reordered_sheets.xlsx
apachepoi_resize_compare.xlsx
apachepoi_sample-beta.xlsx
apachepoi_sample.strict.xlsx
apachepoi_sample.xlsx
apachepoi_shared_formulas.xlsx
apachepoi_sheetProtection_allLocked.xlsx
apachepoi_sheetProtection_not_protected.xlsx
apachepoi_styles.xlsx
apachepoi_template.xlsx
apachepoi_unicodeSheetName.xlsx
apachepoi_workbookProtection-sheet_password-2013.xlsx
apachepoi_workbookProtection-workbook_password-2013.xlsx
apachepoi_workbookProtection-workbook_password_user_range-2010.xlsx
@ -219,6 +302,7 @@ excel-reader-xlsx_inline01.xlsx
excel-reader-xlsx_libre01.xlsx
formula_stress_test.xlsx
formulae_test_simple.xlsx
hyperlink_no_rels.xlsx
hyperlink_stress_test_2011.xlsx
interview.xlsx
issue.xlsx
@ -260,6 +344,7 @@ openpyxl_g_empty_with_no_properties.xlsx
openpyxl_g_guess_types.xlsx
openpyxl_g_libreoffice_nrt.xlsx
openpyxl_g_merge_range.xlsx
openpyxl_g_sample.xlsx
openpyxl_r_bigfoot.xlsx
openpyxl_r_bug137.xlsx
openpyxl_r_bug275.xlsx
@ -271,8 +356,10 @@ openpyxl_r_contains_chartsheets.xlsx.pending
openpyxl_r_date_1900.xlsx
openpyxl_r_date_1904.xlsx
openpyxl_r_formulae.xlsx
openpyxl_r_nonstandard_workbook_name.xlsx
openpyxl_r_null_archive.xlsx.pending
openpyxl_r_null_file.xlsx.pending
phonetic_text.xlsx
pivot_table_named_range.xlsx
rich_text_stress.xlsx
roo_1900_base.xlsx
@ -283,25 +370,39 @@ roo_bbu.xlsx
roo_boolean.xlsx
roo_borders.xlsx
roo_bug-numbered-sheet-names.xlsx
roo_chart_sheet.xlsx
roo_comments-google.xlsx
roo_comments.xlsx
roo_datetime.xlsx
roo_emptysheets.xlsx
roo_file_item_error.xlsx
roo_formula.xlsx
roo_formula_cell_types.xlsx
roo_formula_string_error.xlsx
roo_header_offset.xlsx
roo_hidden_sheets.xlsx
roo_html_strings_formatting.xlsx
roo_link.xlsx
roo_merged_ranges.xlsx
roo_name_with_leading_slash.xlsx
roo_named_cells.xlsx
roo_numbers-export.xlsx
roo_numbers1.xlsx
roo_numbers1withnull.xlsx
roo_numeric-link.xlsx
roo_only_one_sheet.xlsx
roo_paragraph.xlsx
roo_parse_clean_with_unicode.xlsx
roo_parse_with_clean_option.xlsx
roo_simple_spreadsheet.xlsx
roo_style.xlsx
roo_style_nodes_with_white_spaces.xlsx
roo_time-test.xlsx
roo_type_excel.xlsx.pending
roo_type_openoffice.xlsx.pending
# roo_type_excel.xlsx # incorrect baseline
# roo_type_openoffice.xlsx # incorrect baseline
roo_whitespace.xlsx
roo_x000D.xlsx
roo_zero-padded-number.xlsx
smart_tags_2007.xlsx
spreadsheet-parsexlsx_Test.xlsx
spreadsheet-parsexlsx_bug-10.xlsx
@ -310,23 +411,45 @@ spreadsheet-parsexlsx_bug-12.xlsx
spreadsheet-parsexlsx_bug-13.xlsx
spreadsheet-parsexlsx_bug-14.xlsx
spreadsheet-parsexlsx_bug-15.xlsx
spreadsheet-parsexlsx_bug-16.xlsx
spreadsheet-parsexlsx_bug-17a.xlsx
spreadsheet-parsexlsx_bug-17b.xlsx
spreadsheet-parsexlsx_bug-2.xlsx
spreadsheet-parsexlsx_bug-29.xlsx
spreadsheet-parsexlsx_bug-3.xlsx
spreadsheet-parsexlsx_bug-32-2.xlsx
spreadsheet-parsexlsx_bug-32.xlsx
spreadsheet-parsexlsx_bug-38.xlsx
spreadsheet-parsexlsx_bug-4.xlsx
spreadsheet-parsexlsx_bug-41.xlsx
spreadsheet-parsexlsx_bug-5.xlsx
spreadsheet-parsexlsx_bug-57.xlsx
spreadsheet-parsexlsx_bug-6-2.xlsx
spreadsheet-parsexlsx_bug-6.xlsx
spreadsheet-parsexlsx_bug-61.xlsx
spreadsheet-parsexlsx_bug-7.xlsx
spreadsheet-parsexlsx_bug-8.xlsx
spreadsheet-parsexlsx_bug-lock.xlsx
spreadsheet-parsexlsx_column-formats.xlsx
# spreadsheet-parsexlsx_encryption-agile-123q.xlsx
# spreadsheet-parsexlsx_encryption-standard-default-password.xlsx
spreadsheet-parsexlsx_hidden-row-and-column.xlsx
spreadsheet-parsexlsx_hidden-sheet.xlsx
spreadsheet-parsexlsx_page-Setup.xlsx
spreadsheet-parsexlsx_tab-color.xlsx
spreadsheet-parsexlsx_target-abspath.xlsx
sushi.xlsx
text_and_numbers.xlsx
write.xlsx
xlrd_apachepoi_49609.xlsx
xlrd_apachepoi_52348.xlsx
xlrd_err_cell_empty.xlsx
xlrd_issue150.xlsx
xlrd_merged_cells.xlsx
xlrd_reveng1.xlsx
xlrd_self_evaluation_report_2014-05-19.xlsx
xlrd_test_comments_excel.xlsx
xlrd_test_comments_excel_sheet2.xlsx
xlrd_test_comments_gdocs.xlsx
xlrd_text_bar.xlsx
xlsx-stream-d-date-cell.xlsx
@ -336,14 +459,49 @@ NumberFormatCondition.xlsm
apachepoi_45431.xlsm
apachepoi_47026.xlsm
apachepoi_47089.xlsm
apachepoi_57181.xlsm
apachepoi_60512.xlsm
apachepoi_ExcelWithAttachments.xlsm
apachepoi_SimpleMacro.xlsm
apachepoi_mv-calculator-final-2-20-2013.xlsm
apachepoi_testNames.xlsm
hyperlink_no_rels.xlsm
number_format.xlsm
number_format_russian.xlsm
numfmt_1_russian.xlsm
openpyxl_r_vba+comments.xlsm
openpyxl_r_vba-comments-saved.xlsm
openpyxl_r_vba-test.xlsm
pivot_table_test.xlsm
roo_1900_base.xlsm
roo_1904_base.xlsm
roo_Bibelbund.xlsm
roo_Pfand_from_windows_phone.xlsm
roo_bbu.xlsm
roo_boolean.xlsm
roo_borders.xlsm
roo_bug-numbered-sheet-names.xlsm
roo_comments.xlsm
roo_datetime.xlsm
roo_emptysheets.xlsm
roo_file_item_error.xlsm
roo_formula.xlsm
roo_formula_string_error.xlsm
roo_link.xlsm
roo_named_cells.xlsm
roo_numbers1.xlsm
roo_numeric-link.xlsm
roo_only_one_sheet.xlsm
roo_paragraph.xlsm
roo_simple_spreadsheet.xlsm
roo_style.xlsm
roo_time-test.xlsm
roo_type_excel.xlsm
roo_type_openoffice.xlsm
roo_whitespace.xlsm
AutoFilter.ods
BlankSheetTypes.ods
apachepoi_SampleSS.ods
cell_style_simple.ods
formula_stress_test.ods
merge_cells.ods
@ -351,6 +509,7 @@ number_format.ods
rich_text_stress.ods
roo_Bibelbund.ods
roo_Bibelbund1.ods
roo_advanced_header.ods
roo_bbu.ods
roo_boolean.ods
roo_borders.ods
@ -358,7 +517,9 @@ roo_comments.ods
roo_datetime.ods
roo_dreimalvier.ods
roo_emptysheets.ods
roo_encrypted-letmein.ods
roo_formula.ods
roo_hidden_sheets.ods
roo_html-escape.ods
roo_matrix.ods
roo_named_cells.ods
@ -370,7 +531,7 @@ roo_simple_spreadsheet.ods
roo_simple_spreadsheet_from_italo.ods
roo_style.ods
roo_time-test.ods
roo_type_excel.ods.pending
roo_type_excel.ods
roo_type_excelx.ods
roo_whitespace.ods
sushi.ods
@ -956,8 +1117,8 @@ roo_simple_spreadsheet.xls
roo_simple_spreadsheet_from_italo.xls
roo_style.xls
roo_time-test.xls
roo_type_excelx.xls.pending
roo_type_openoffice.xls.pending
roo_type_excelx.xls
roo_type_openoffice.xls
roo_whitespace.xls
smart_tags_2007.xls
sushi.xls

View File

@ -2,9 +2,10 @@
/* vim: set ts=2: */
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true */
/*exported XLSX */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.8.8';
XLSX.version = '0.9.0';
var current_codepage = 1200, current_cptable;
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
@ -1340,6 +1341,33 @@ function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
function cc2str(arr/*:Array<number>*/)/*:string*/ {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
@ -1385,6 +1413,7 @@ function getdatabin(data) {
function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
/* OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file/*:string*/) {
var k = keys(zip.files);
var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
@ -1422,7 +1451,7 @@ if (typeof exports !== 'undefined') {
_fs = require('fs');
}
}
var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var attregexg=/([^\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ {
@ -1431,14 +1460,21 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ {
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) z[q] = v;
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
if(j===q.length) {
//if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_")); // from ods
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
//if(z[k] && q.substr(j-3,3) == "ext") continue; // from ods
z[k] = v;
}
}
return z;
}
@ -2682,6 +2718,63 @@ function write_rels(rels)/*:string*/ {
if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
return o.join("");
}
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
}
function write_manifest(manifest/*:Array<Array<string> >*/, opts)/*:string*/ {
var o = [XML_HEADER];
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base/*:string*/, file/*:string*/) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}
/* ECMA-376 Part II 11.1 Core Properties Part */
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
var CORE_PROPS/*:Array<Array<string> >*/ = [
@ -7875,6 +7968,17 @@ var XLSXFutureFunctions = {
"_xlfn.Z.TEST": "Z.TEST"
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f/*:string*/)/*:string*/ {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var strs = {}; // shared strings
var _ssfopts = {}; // spreadsheet formatting options
@ -8183,6 +8287,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
case 'n': p.v = parseFloat(p.v); break;
case 's':
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
}
p.v = sstr.t;
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;
@ -9456,6 +9564,7 @@ function process_style_xlml(styles, stag, opts) {
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o)/*:Workbook*/ {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
var i = 0;
if(sid === undefined && row) sid = row.StyleID;
if(sid === undefined && csty) sid = csty.StyleID;
while(styles[sid] !== undefined) {
@ -9521,13 +9630,15 @@ function xlml_clean_comment(comment/*:any*/) {
}
function xlml_normalize(d)/*:string*/ {
if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
if(typeof d === 'string') return d;
throw new Error("Bad input format: expected Buffer or string");
}
/* TODO: Everything */
var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
/* UOS uses CJK in tags */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts)/*:Workbook*/ {
var str = debom(xlml_normalize(d));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);
@ -12189,6 +12300,443 @@ function parse_html(str/*:string*/, opts)/*:Workbook*/ {
ws['!ref'] = encode_range(range);
return o;
}
var parse_content_xml = (function() {
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
month: ["m", "mm"],
year: ["y", "yy"],
hours: ["h", "hh"],
minutes: ["m", "mm"],
seconds: ["s", "ss"],
"am-pm": ["A/P", "AM/PM"],
"day-of-week": ["ddd", "dddd"]
};
return function pcx(d, _opts) {
var opts = _opts || {};
var str = xlml_normalize(d);
var state/*:Array<any>*/ = [], tmp;
var tag/*:: = {}*/;
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag/*:: = {name:"", '名称':""}*/;
var rowtag/*:: = {'行号':""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {};
var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {}; merges = [];
}
break;
case 'table-row': case '行': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
rept = 1;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/);
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
if(ctag['string-value'] != null) textp = ctag['string-value'];
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {/*:: t:"", v:null, z:null, w:""*/};
textp = "";
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document': // TODO: <office:document> is the root for FODS
case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
case 'styles': // TODO <office:styles>
case 'font-face-decls': // 3.14 <office:font-face-decls>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
case 'settings': // TODO: <office:settings>
case 'config-item-set': // TODO: <office:config-item-set>
case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
case 'config-item-map-named': // TODO: <office:config-item-map-entry>
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
case 'text-box': // 10.4.3 <draw:text-box>
case 'image': // 10.4.4 <draw:image>
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
case 'list-style': // 16.30 <text:list-style>
case 'form': // 13.13 <form:form>
case 'dde-links': // 9.8 <table:dde-links>
case 'annotation': // 14.1 <office:annotation>
case 'event-listeners': // TODO
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'scientific-number': // TODO: <number:scientific-number>
break;
case 'currency-symbol': // TODO: <number:currency-symbol>
break;
case 'currency-style': // TODO: <number:currency-style>
break;
case 'number-style': // 16.27.2 <number:number-style>
case 'percentage-style': // 16.27.9 <number:percentage-style>
case 'date-style': // 16.27.10 <number:date-style>
case 'time-style': // 16.27.18 <number:time-style>
if(Rn[1]==='/'){
number_format_map[NFtag.name] = NF;
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
NF = "";
NFtag = parsexmltag(Rn[0], false);
state.push([Rn[3], true]);
} break;
case 'script': break; // 3.13 <office:script>
case 'libraries': break; // TODO: <ooo:libraries>
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
case 'master-styles': break; // TODO: <office:automatic-styles>
case 'default-style': // TODO: <style:default-style>
case 'page-layout': break; // TODO: <style:page-layout>
case 'style': break; // 16.2 <style:style>
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
case 'number': // 16.27.3 <number:number>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'fraction': break; // TODO 16.27.6 <number:fraction>
case 'day': // 16.27.11 <number:day>
case 'month': // 16.27.12 <number:month>
case 'year': // 16.27.13 <number:year>
case 'era': // 16.27.14 <number:era>
case 'day-of-week': // 16.27.15 <number:day-of-week>
case 'week-of-year': // 16.27.16 <number:week-of-year>
case 'quarter': // 16.27.17 <number:quarter>
case 'hours': // 16.27.19 <number:hours>
case 'minutes': // 16.27.20 <number:minutes>
case 'seconds': // 16.27.21 <number:seconds>
case 'am-pm': // 16.27.22 <number:am-pm>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
case 'boolean': break; // 16.27.24 <number:boolean>
case 'text-style': break; // 16.27.25 <number:text-style>
case 'text': // 16.27.26 <number:text>
if(Rn[0].slice(-2) === "/>") break;
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
case 'number-style':
case 'date-style':
case 'time-style':
NF += str.slice(pidx, Rn.index);
break;
}
else pidx = Rn.index + Rn[0].length;
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
case 'forms': break; // 12.25.2 13.2
case 'table-column': break; // 9.1.6 <table:table-column>
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'named-expression': break; // 9.4.13 <table:named-expression>
case 'sort': break; // 9.4.19 <table:sort>
case 'sort-by': break; // 9.4.20 <table:sort-by>
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
case 'span': break; // <text:span>
case 'line-break': break; // 6.1.5 <text:line-break>
case 'p': case '文本串':
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': case '标题': break; // <*:title> OR <uof:标题>
case 'desc': break; // <*:desc>
case 'table-source': break; // 9.2.6
case 'iteration': break; // 9.4.3 <table:iteration>
case 'content-validations': break; // 9.4.4 <table:
case 'content-validation': break; // 9.4.5 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
case 'list-level-properties': break; // 17.19 <style:
/* 7.3 Document Fields */
case 'sender-firstname': // 7.3.6.2
case 'sender-lastname': // 7.3.6.3
case 'sender-initials': // 7.3.6.4
case 'sender-title': // 7.3.6.5
case 'sender-position': // 7.3.6.6
case 'sender-email': // 7.3.6.7
case 'sender-phone-private': // 7.3.6.8
case 'sender-fax': // 7.3.6.9
case 'sender-company': // 7.3.6.10
case 'sender-phone-work': // 7.3.6.11
case 'sender-street': // 7.3.6.12
case 'sender-city': // 7.3.6.13
case 'sender-postal-code': // 7.3.6.14
case 'sender-country': // 7.3.6.15
case 'sender-state-or-province': // 7.3.6.16
case 'author-name': // 7.3.7.1
case 'author-initials': // 7.3.7.2
case 'chapter': // 7.3.8
case 'file-name': // 7.3.9
case 'template-name': // 7.3.9
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
/* TODO: FODS Properties */
case 'initial-creator':
case 'creator':
case 'creation-date':
case 'generator':
case 'document-statistic':
case 'user-defined':
break;
/* TODO: FODS Config */
case 'config-item':
break;
/* TODO: style tokens */
case 'page-number': break; // TODO <text:page-number>
case 'page-count': break; // TODO <text:page-count>
case 'time': break; // TODO <text:time>
/* 9.6 Data Pilot Tables <table: */
case 'data-pilot-table': // 9.6.3
case 'source-cell-range': // 9.6.5
case 'source-service': // 9.6.6
case 'data-pilot-field': // 9.6.7
case 'data-pilot-level': // 9.6.8
case 'data-pilot-subtotals': // 9.6.9
case 'data-pilot-subtotal': // 9.6.10
case 'data-pilot-members': // 9.6.11
case 'data-pilot-member': // 9.6.12
case 'data-pilot-display-info': // 9.6.13
case 'data-pilot-sort-info': // 9.6.14
case 'data-pilot-layout-info': // 9.6.15
case 'data-pilot-field-reference': // 9.6.16
case 'data-pilot-groups': // 9.6.17
case 'data-pilot-group': // 9.6.18
case 'data-pilot-group-member': // 9.6.19
break;
/* 10.3 Drawing Shapes */
case 'rect': // 10.3.2
break;
/* 14.6 DDE Connections */
case 'dde-connection-decls': // 14.6.2 <text:
case 'dde-connection-decl': // 14.6.3 <text:
case 'dde-link': // 14.6.4 <table:
case 'dde-source': // 14.6.5 <office:
break;
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
/* non-standard */
case 'table-protection': break;
case 'data-pilot-grand-total': break; // <table:
default:
if(Rn[2] === 'dc:') break; // TODO: properties
if(Rn[2] === 'draw:') break; // TODO: drawing
if(Rn[2] === 'style:') break; // TODO: styles
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
if(Rn[2] === 'loext:') break; // ignore undocumented extensions
if(Rn[2] === 'uof:') break; // TODO: uof
if(Rn[2] === '表:') break; // TODO: uof
if(Rn[2] === '字:') break; // TODO: uof
if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
SheetNames: SheetNames
};
return out;
};
})();
var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
//case 'd': // TODO
//case 'e':
default: o.push(null_cell_xml);
} else o.push(null_cell_xml);
}
o.push(' </table:table-row>\n');
}
o.push(' </table:table>\n');
return o.join("");
};
return function wcx(wb, opts) {
var o = [XML_HEADER];
/* 3.1.3.2 */
if(opts.bookType == "fods") o.push('<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">');
else o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');
if(opts.bookType == "fods") o.push('</office:document>');
else o.push('</office:document-content>');
return o.join("");
};
})();
/* actual implementation in utils, wrappers are for read/write */
function write_csv_str(wb/*:Workbook*/, o/*:WriteOpts*/) {
var idx = 0;
@ -12196,26 +12744,49 @@ function write_csv_str(wb/*:Workbook*/, o/*:WriteOpts*/) {
if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
return sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o);
}
/* Helper functions to call out to ODS */
/* Part 3: Packages */
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) {
opts = opts || ({}/*:any*/);
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data/*:string*/, opts/*:?ParseOpts*/) {
return parse_content_xml(data, opts);
}
function get_ods() {
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./ods.js');
return ODS;
}
function parse_ods(zip, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
return ODS.parse_ods(zip, opts);
}
function write_ods(wb, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
return ODS.write_ods(wb, opts);
}
function parse_fods(data, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_fods) throw new Error("Unsupported ODS");
return ODS.parse_fods(data, opts);
function write_ods(wb/*:any*/, opts/*:any*/) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
/*:: if(!jszip) throw new Error("JSZip is not available"); */
var zip = new jszip();
var f = "";
var manifest/*:Array<Array<string> >*/ = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
function fix_opts_func(defaults/*:Array<Array<any> >*/)/*:{(o:any):void}*/ {
return function fix_opts(opts) {
@ -12833,6 +13404,9 @@ var utils = {
sheet_to_row_object_array: sheet_to_row_object_array
};
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
XLSX.parse_fods = parse_fods;
XLSX.write_ods = write_ods;
XLSX.parse_zip = parse_zip;
XLSX.read = readSync; //xlsread
XLSX.readFile = readFileSync; //readFile
@ -12844,4 +13418,7 @@ XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;
})(typeof exports !== 'undefined' ? exports : XLSX);
/*exported XLS */
var XLS = XLSX;
/*exported ODS */
var ODS = XLSX;

622
xlsx.js
View File

@ -2,9 +2,10 @@
/* vim: set ts=2: */
/*jshint -W041 */
/*jshint funcscope:true, eqnull:true */
/*exported XLSX */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.8.8';
XLSX.version = '0.9.0';
var current_codepage = 1200, current_cptable;
if(typeof module !== "undefined" && typeof require !== 'undefined') {
if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js');
@ -1299,6 +1300,33 @@ function datenum(v, date1904) {
return (epoch + 2209161600000) / (24 * 60 * 60 * 1000);
}
/* ISO 8601 Duration */
function parse_isodur(s) {
var sec = 0, mt = 0, time = false;
var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
for(var i = 1; i != m.length; ++i) {
if(!m[i]) continue;
mt = 1;
if(i > 3) time = true;
switch(m[i].substr(m[i].length-1)) {
case 'Y':
throw new Error("Unsupported ISO Duration Field: " + m[i].substr(m[i].length-1));
case 'D': mt *= 24;
/* falls through */
case 'H': mt *= 60;
/* falls through */
case 'M':
if(!time) throw new Error("Unsupported ISO Duration Field: M");
else mt *= 60;
/* falls through */
case 'S': break;
}
sec += mt * parseInt(m[i], 10);
}
return sec;
}
function cc2str(arr) {
var o = "";
for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
@ -1344,6 +1372,7 @@ function getdatabin(data) {
function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
/* OASIS does not comment on filename case sensitivity */
function safegetzipfile(zip, file) {
var k = keys(zip.files);
var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
@ -1380,7 +1409,7 @@ if (typeof exports !== 'undefined') {
_fs = require('fs');
}
}
var attregexg=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var attregexg=/([^\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
var tagregex=/<[^>]*>/g;
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
function parsexmltag(tag, skip_root) {
@ -1389,14 +1418,21 @@ function parsexmltag(tag, skip_root) {
for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
if(!skip_root) z[0] = tag.substr(0, eq);
if(eq === tag.length) return z;
var m = tag.match(attregexg), j=0, w="", v="", i=0, q="", cc="";
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="";
if(m) for(i = 0; i != m.length; ++i) {
cc = m[i];
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
q = cc.substr(0,c); v = cc.substring(c+2, cc.length-1);
for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
if(j===q.length) z[q] = v;
else z[(j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1)] = v;
if(j===q.length) {
//if(q.indexOf("_") > 0) q = q.substr(0, q.indexOf("_")); // from ods
z[q] = v;
}
else {
var k = (j===5 && q.substr(0,5)==="xmlns"?"xmlns":"")+q.substr(j+1);
//if(z[k] && q.substr(j-3,3) == "ext") continue; // from ods
z[k] = v;
}
}
return z;
}
@ -2640,6 +2676,63 @@ function write_rels(rels) {
if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
return o.join("");
}
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
}
function write_manifest(manifest, opts) {
var o = [XML_HEADER];
o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
for(var i = 0; i < manifest.length; ++i) o.push(' <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
o.push('</manifest:manifest>');
return o.join("");
}
/* Part 3 Section 6 Metadata Manifest File */
function write_rdf_type(file, res, tag) {
return [
' <rdf:Description rdf:about="' + file + '">\n',
' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf_has(base, file) {
return [
' <rdf:Description rdf:about="' + base + '">\n',
' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
' </rdf:Description>\n'
].join("");
}
function write_rdf(rdf, opts) {
var o = [XML_HEADER];
o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
for(var i = 0; i != rdf.length; ++i) {
o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
o.push(write_rdf_has("",rdf[i][0]));
}
o.push(write_rdf_type("","Document", "pkg"));
o.push('</rdf:RDF>');
return o.join("");
}
/* ECMA-376 Part II 11.1 Core Properties Part */
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
var CORE_PROPS = [
@ -7833,6 +7926,17 @@ var XLSXFutureFunctions = {
"_xlfn.Z.TEST": "Z.TEST"
};
/* Part 3 TODO: actually parse formulae */
function ods_to_csf_formula(f) {
if(f.substr(0,3) == "of:") f = f.substr(3);
/* 5.2 Basic Expressions */
if(f.charCodeAt(0) == 61) {
f = f.substr(1);
if(f.charCodeAt(0) == 61) f = f.substr(1);
}
/* Part 3 Section 5.8 References */
return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, "");
}
var strs = {}; // shared strings
var _ssfopts = {}; // spreadsheet formatting options
@ -8141,6 +8245,10 @@ return function parse_ws_xml_data(sdata, s, opts, guess) {
case 'n': p.v = parseFloat(p.v); break;
case 's':
sstr = strs[parseInt(p.v, 10)];
if(typeof p.v == 'undefined') {
if(!opts.sheetStubs) continue;
p.t = "stub";
}
p.v = sstr.t;
p.r = sstr.r;
if(opts.cellHTML) p.h = sstr.h;
@ -9412,6 +9520,7 @@ function process_style_xlml(styles, stag, opts) {
function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o) {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
var i = 0;
if(sid === undefined && row) sid = row.StyleID;
if(sid === undefined && csty) sid = csty.StyleID;
while(styles[sid] !== undefined) {
@ -9483,7 +9592,9 @@ function xlml_normalize(d) {
}
/* TODO: Everything */
var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
/* UOS uses CJK in tags */
var xlmlregex = /<(\/?)([^\s?>\/:]*:|)([^\s?>]*[^\s?>\/])[^>]*>/mg;
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
function parse_xlml_xml(d, opts) {
var str = debom(xlml_normalize(d));
if(str.substr(0,1000).indexOf("<html") >= 0) return parse_html(str, opts);
@ -12145,6 +12256,443 @@ function parse_html(str, opts) {
ws['!ref'] = encode_range(range);
return o;
}
var parse_content_xml = (function() {
var parse_text_p = function(text, tag) {
return unescapexml(text.replace(/<text:s\/>/g," ").replace(/<[^>]*>/g,""));
};
var number_formats = {
/* ods name: [short ssf fmt, long ssf fmt] */
day: ["d", "dd"],
month: ["m", "mm"],
year: ["y", "yy"],
hours: ["h", "hh"],
minutes: ["m", "mm"],
seconds: ["s", "ss"],
"am-pm": ["A/P", "AM/PM"],
"day-of-week": ["ddd", "dddd"]
};
return function pcx(d, _opts) {
var opts = _opts || {};
var str = xlml_normalize(d);
var state = [], tmp;
var tag;
var NFtag = {name:""}, NF = "", pidx = 0;
var sheetag;
var rowtag;
var Sheets = {}, SheetNames = [], ws = {};
var Rn, q;
var ctag = {value:""};
var textp = "", textpidx = 0, textptag;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var number_format_map = {};
var merges = [], mrange = {}, mR = 0, mC = 0;
var arrayf = [];
var rept = 1, isstub = false;
var i = 0;
xlmlregex.lastIndex = 0;
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
case 'table': case '工作表': // 9.1.2 <table:table>
if(Rn[1]==='/') {
if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
if(merges.length) ws['!merges'] = merges;
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = {}; merges = [];
}
break;
case 'table-row': case '行': // 9.1.3 <table:table-row>
if(Rn[1] === '/') break;
rowtag = parsexmltag(Rn[0], false);
if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R;
C = -1; break;
case 'covered-table-cell': // 9.1.5 table:covered-table-cell
++C; break; /* stub */
case 'table-cell': case '数据':
if(Rn[0].charAt(Rn[0].length-2) === '/') {
ctag = parsexmltag(Rn[0], false);
if(ctag['number-columns-repeated']) C+= parseInt(ctag['number-columns-repeated'], 10);
else ++C;
}
else if(Rn[1]!=='/') {
++C;
rept = 1;
if(C > range.e.c) range.e.c = C;
if(R > range.e.r) range.e.r = R;
if(C < range.s.c) range.s.c = C;
if(R < range.s.r) range.s.r = R;
ctag = parsexmltag(Rn[0], false);
q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
if(opts.cellFormula) {
if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
q.F = encode_range(mrange);
arrayf.push([mrange, q.F]);
}
if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
else for(i = 0; i < arrayf.length; ++i)
if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
q.F = arrayf[i][1];
}
if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
mR = parseInt(ctag['number-rows-spanned'],10) || 0;
mC = parseInt(ctag['number-columns-spanned'],10) || 0;
mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
merges.push(mrange);
}
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) rept = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break;
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
if(ctag['string-value'] != null) textp = ctag['string-value'];
} else throw new Error('Unsupported value type ' + q.t);
}
} else {
isstub = false;
if(q.t === 's') {
q.v = textp || '';
isstub = textpidx == 0;
}
if(textp) q.w = textp;
if(!isstub || opts.cellStubs) {
if(!(opts.sheetRows && opts.sheetRows < R)) {
ws[encode_cell({r:R,c:C})] = q;
while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q);
if(range.e.c <= C) range.e.c = C;
}
} else { C += rept; rept = 0; }
q = {};
textp = "";
}
break; // 9.1.4 <table:table-cell>
/* pure state */
case 'document': // TODO: <office:document> is the root for FODS
case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
case 'scripts': // 3.12 <office:scripts>
case 'styles': // TODO <office:styles>
case 'font-face-decls': // 3.14 <office:font-face-decls>
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
break;
/* ignore state */
case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
case 'settings': // TODO: <office:settings>
case 'config-item-set': // TODO: <office:config-item-set>
case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
case 'config-item-map-named': // TODO: <office:config-item-map-entry>
case 'shapes': // 9.2.8 <table:shapes>
case 'frame': // 10.4.2 <draw:frame>
case 'text-box': // 10.4.3 <draw:text-box>
case 'image': // 10.4.4 <draw:image>
case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
case 'list-style': // 16.30 <text:list-style>
case 'form': // 13.13 <form:form>
case 'dde-links': // 9.8 <table:dde-links>
case 'annotation': // 14.1 <office:annotation>
case 'event-listeners': // TODO
if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
textp = ""; textpidx = 0;
break;
case 'scientific-number': // TODO: <number:scientific-number>
break;
case 'currency-symbol': // TODO: <number:currency-symbol>
break;
case 'currency-style': // TODO: <number:currency-style>
break;
case 'number-style': // 16.27.2 <number:number-style>
case 'percentage-style': // 16.27.9 <number:percentage-style>
case 'date-style': // 16.27.10 <number:date-style>
case 'time-style': // 16.27.18 <number:time-style>
if(Rn[1]==='/'){
number_format_map[NFtag.name] = NF;
if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
NF = "";
NFtag = parsexmltag(Rn[0], false);
state.push([Rn[3], true]);
} break;
case 'script': break; // 3.13 <office:script>
case 'libraries': break; // TODO: <ooo:libraries>
case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
case 'master-styles': break; // TODO: <office:automatic-styles>
case 'default-style': // TODO: <style:default-style>
case 'page-layout': break; // TODO: <style:page-layout>
case 'style': break; // 16.2 <style:style>
case 'map': break; // 16.3 <style:map>
case 'font-face': break; // 16.21 <style:font-face>
case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
case 'table-properties': break; // 17.15 <style:table-properties>
case 'table-column-properties': break; // 17.16 <style:table-column-properties>
case 'table-row-properties': break; // 17.17 <style:table-row-properties>
case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
case 'number': // 16.27.3 <number:number>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'fraction': break; // TODO 16.27.6 <number:fraction>
case 'day': // 16.27.11 <number:day>
case 'month': // 16.27.12 <number:month>
case 'year': // 16.27.13 <number:year>
case 'era': // 16.27.14 <number:era>
case 'day-of-week': // 16.27.15 <number:day-of-week>
case 'week-of-year': // 16.27.16 <number:week-of-year>
case 'quarter': // 16.27.17 <number:quarter>
case 'hours': // 16.27.19 <number:hours>
case 'minutes': // 16.27.20 <number:minutes>
case 'seconds': // 16.27.21 <number:seconds>
case 'am-pm': // 16.27.22 <number:am-pm>
switch(state[state.length-1][0]) {
case 'time-style':
case 'date-style':
tag = parsexmltag(Rn[0], false);
NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
} break;
case 'boolean-style': break; // 16.27.23 <number:boolean-style>
case 'boolean': break; // 16.27.24 <number:boolean>
case 'text-style': break; // 16.27.25 <number:text-style>
case 'text': // 16.27.26 <number:text>
if(Rn[0].slice(-2) === "/>") break;
else if(Rn[1]==="/") switch(state[state.length-1][0]) {
case 'number-style':
case 'date-style':
case 'time-style':
NF += str.slice(pidx, Rn.index);
break;
}
else pidx = Rn.index + Rn[0].length;
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
case 'forms': break; // 12.25.2 13.2
case 'table-column': break; // 9.1.6 <table:table-column>
case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'named-expression': break; // 9.4.13 <table:named-expression>
case 'sort': break; // 9.4.19 <table:sort>
case 'sort-by': break; // 9.4.20 <table:sort-by>
case 'sort-groups': break; // 9.4.22 <table:sort-groups>
case 'span': break; // <text:span>
case 'line-break': break; // 6.1.5 <text:line-break>
case 'p': case '文本串':
if(Rn[1]==='/') textp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
case 'date': break; // <*:date>
case 'object': break; // 10.4.6.2 <draw:object>
case 'title': case '标题': break; // <*:title> OR <uof:标题>
case 'desc': break; // <*:desc>
case 'table-source': break; // 9.2.6
case 'iteration': break; // 9.4.3 <table:iteration>
case 'content-validations': break; // 9.4.4 <table:
case 'content-validation': break; // 9.4.5 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
case 'database-range': break; // 9.4.15 <table:database-range>
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:
case 'list-level-properties': break; // 17.19 <style:
/* 7.3 Document Fields */
case 'sender-firstname': // 7.3.6.2
case 'sender-lastname': // 7.3.6.3
case 'sender-initials': // 7.3.6.4
case 'sender-title': // 7.3.6.5
case 'sender-position': // 7.3.6.6
case 'sender-email': // 7.3.6.7
case 'sender-phone-private': // 7.3.6.8
case 'sender-fax': // 7.3.6.9
case 'sender-company': // 7.3.6.10
case 'sender-phone-work': // 7.3.6.11
case 'sender-street': // 7.3.6.12
case 'sender-city': // 7.3.6.13
case 'sender-postal-code': // 7.3.6.14
case 'sender-country': // 7.3.6.15
case 'sender-state-or-province': // 7.3.6.16
case 'author-name': // 7.3.7.1
case 'author-initials': // 7.3.7.2
case 'chapter': // 7.3.8
case 'file-name': // 7.3.9
case 'template-name': // 7.3.9
case 'sheet-name': // 7.3.9
break;
case 'event-listener': // TODO
/* TODO: FODS Properties */
case 'initial-creator':
case 'creator':
case 'creation-date':
case 'generator':
case 'document-statistic':
case 'user-defined':
break;
/* TODO: FODS Config */
case 'config-item':
break;
/* TODO: style tokens */
case 'page-number': break; // TODO <text:page-number>
case 'page-count': break; // TODO <text:page-count>
case 'time': break; // TODO <text:time>
/* 9.6 Data Pilot Tables <table: */
case 'data-pilot-table': // 9.6.3
case 'source-cell-range': // 9.6.5
case 'source-service': // 9.6.6
case 'data-pilot-field': // 9.6.7
case 'data-pilot-level': // 9.6.8
case 'data-pilot-subtotals': // 9.6.9
case 'data-pilot-subtotal': // 9.6.10
case 'data-pilot-members': // 9.6.11
case 'data-pilot-member': // 9.6.12
case 'data-pilot-display-info': // 9.6.13
case 'data-pilot-sort-info': // 9.6.14
case 'data-pilot-layout-info': // 9.6.15
case 'data-pilot-field-reference': // 9.6.16
case 'data-pilot-groups': // 9.6.17
case 'data-pilot-group': // 9.6.18
case 'data-pilot-group-member': // 9.6.19
break;
/* 10.3 Drawing Shapes */
case 'rect': // 10.3.2
break;
/* 14.6 DDE Connections */
case 'dde-connection-decls': // 14.6.2 <text:
case 'dde-connection-decl': // 14.6.3 <text:
case 'dde-link': // 14.6.4 <table:
case 'dde-source': // 14.6.5 <office:
break;
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
/* non-standard */
case 'table-protection': break;
case 'data-pilot-grand-total': break; // <table:
default:
if(Rn[2] === 'dc:') break; // TODO: properties
if(Rn[2] === 'draw:') break; // TODO: drawing
if(Rn[2] === 'style:') break; // TODO: styles
if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
if(Rn[2] === 'loext:') break; // ignore undocumented extensions
if(Rn[2] === 'uof:') break; // TODO: uof
if(Rn[2] === '表:') break; // TODO: uof
if(Rn[2] === '字:') break; // TODO: uof
if(opts.WTF) throw Rn;
}
var out = {
Sheets: Sheets,
SheetNames: SheetNames
};
return out;
};
})();
var write_content_xml = (function() {
var null_cell_xml = ' <table:table-cell />\n';
var write_ws = function(ws, wb, i, opts) {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
var R=0,C=0, range = decode_range(ws['!ref']);
for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
for(; R <= range.e.r; ++R) {
o.push(' <table:table-row>\n');
for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
for(; C <= range.e.c; ++C) {
var ref = encode_cell({r:R, c:C}), cell = ws[ref];
if(cell) switch(cell.t) {
case 'b': o.push(' <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break;
case 'n': o.push(' <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break;
case 's': case 'str': o.push(' <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break;
//case 'd': // TODO
//case 'e':
default: o.push(null_cell_xml);
} else o.push(null_cell_xml);
}
o.push(' </table:table-row>\n');
}
o.push(' </table:table>\n');
return o.join("");
};
return function wcx(wb, opts) {
var o = [XML_HEADER];
/* 3.1.3.2 */
if(opts.bookType == "fods") o.push('<office:document xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:style="urn:oasis:names:tc:opendocument:xmlns:style:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:draw="urn:oasis:names:tc:opendocument:xmlns:drawing:1.0" xmlns:fo="urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0" xmlns:xlink="http://www.w3.org/1999/xlink" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:number="urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0" xmlns:presentation="urn:oasis:names:tc:opendocument:xmlns:presentation:1.0" xmlns:svg="urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0" xmlns:chart="urn:oasis:names:tc:opendocument:xmlns:chart:1.0" xmlns:dr3d="urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0" xmlns:math="http://www.w3.org/1998/Math/MathML" xmlns:form="urn:oasis:names:tc:opendocument:xmlns:form:1.0" xmlns:script="urn:oasis:names:tc:opendocument:xmlns:script:1.0" xmlns:config="urn:oasis:names:tc:opendocument:xmlns:config:1.0" xmlns:ooo="http://openoffice.org/2004/office" xmlns:ooow="http://openoffice.org/2004/writer" xmlns:oooc="http://openoffice.org/2004/calc" xmlns:dom="http://www.w3.org/2001/xml-events" xmlns:xforms="http://www.w3.org/2002/xforms" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:rpt="http://openoffice.org/2005/report" xmlns:of="urn:oasis:names:tc:opendocument:xmlns:of:1.2" xmlns:xhtml="http://www.w3.org/1999/xhtml" xmlns:grddl="http://www.w3.org/2003/g/data-view#" xmlns:tableooo="http://openoffice.org/2009/table" xmlns:drawooo="http://openoffice.org/2010/draw" xmlns:calcext="urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0" xmlns:loext="urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0" xmlns:field="urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0" xmlns:formx="urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0" xmlns:css3t="http://www.w3.org/TR/css3-text/" office:version="1.2" office:mimetype="application/vnd.oasis.opendocument.spreadsheet">');
else o.push('<office:document-content office:version="1.2" xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:table="urn:oasis:names:tc:opendocument:xmlns:table:1.0" xmlns:text="urn:oasis:names:tc:opendocument:xmlns:text:1.0">\n'); // TODO
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');
if(opts.bookType == "fods") o.push('</office:document>');
else o.push('</office:document-content>');
return o.join("");
};
})();
/* actual implementation in utils, wrappers are for read/write */
function write_csv_str(wb, o) {
var idx = 0;
@ -12152,26 +12700,48 @@ function write_csv_str(wb, o) {
if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
return sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o);
}
/* Helper functions to call out to ODS */
function get_ods() {
if(typeof module !== "undefined" && typeof require !== 'undefined' && typeof ODS === 'undefined') ODS = require('./ods.js');
return ODS;
}
/* Part 3: Packages */
function parse_ods(zip, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_ods) throw new Error("Unsupported ODS");
return ODS.parse_ods(zip, opts);
}
function write_ods(wb, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.write_ods) throw new Error("Unsupported ODS");
return ODS.write_ods(wb, opts);
opts = opts || ({});
var ods = !!safegetzipfile(zip, 'objectdata');
if(ods) var manifest = parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
var content = getzipdata(zip, 'content.xml');
if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
return parse_content_xml(ods ? content : utf8read(content), opts);
}
function parse_fods(data, opts) {
get_ods();
if(typeof ODS === 'undefined' || !ODS.parse_fods) throw new Error("Unsupported ODS");
return ODS.parse_fods(data, opts);
return parse_content_xml(data, opts);
}
function write_ods(wb, opts) {
if(opts.bookType == "fods") return write_content_xml(wb, opts);
var zip = new jszip();
var f = "";
var manifest = [];
var rdf = [];
/* 3:3.3 and 2:2.2.4 */
f = "mimetype";
zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
/* Part 1 Section 2.2 Documents */
f = "content.xml";
zip.file(f, write_content_xml(wb, opts));
manifest.push([f, "text/xml"]);
rdf.push([f, "ContentFile"]);
/* Part 3 Section 6 Metadata Manifest File */
f = "manifest.rdf";
zip.file(f, write_rdf(rdf, opts));
manifest.push([f, "application/rdf+xml"]);
/* Part 3 Section 4 Manifest File */
f = "META-INF/manifest.xml";
zip.file(f, write_manifest(manifest, opts));
return zip;
}
function fix_opts_func(defaults) {
return function fix_opts(opts) {
@ -12783,6 +13353,9 @@ var utils = {
sheet_to_row_object_array: sheet_to_row_object_array
};
XLSX.parse_xlscfb = parse_xlscfb;
XLSX.parse_ods = parse_ods;
XLSX.parse_fods = parse_fods;
XLSX.write_ods = write_ods;
XLSX.parse_zip = parse_zip;
XLSX.read = readSync; //xlsread
XLSX.readFile = readFileSync; //readFile
@ -12794,4 +13367,7 @@ XLSX.utils = utils;
XLSX.CFB = CFB;
XLSX.SSF = SSF;
})(typeof exports !== 'undefined' ? exports : XLSX);
/*exported XLS */
var XLS = XLSX;
/*exported ODS */
var ODS = XLSX;

View File

@ -5,8 +5,6 @@
importScripts('dist/cpexcel.js');
importScripts('jszip.js');
importScripts('xlsx.js');
/* uncomment the next line for ODS support */
importScripts('dist/ods.js');
/*::self.*/postMessage({t:"ready"});
onmessage = function (oEvent) {

View File

@ -3,8 +3,6 @@
importScripts('dist/cpexcel.js');
importScripts('jszip.js');
importScripts('xlsx.js');
/* uncomment the next line for ODS support */
importScripts('dist/ods.js');
postMessage({t:"ready"});
onmessage = function (oEvent) {

View File

@ -5,8 +5,6 @@
importScripts('dist/cpexcel.js');
importScripts('jszip.js');
importScripts('xlsx.js');
/* uncomment the next line for ODS support */
importScripts('dist/ods.js');
/*::self.*/postMessage({t:"ready"});
function ab2str(data) {

View File

@ -3,8 +3,6 @@
importScripts('dist/cpexcel.js');
importScripts('jszip.js');
importScripts('xlsx.js');
/* uncomment the next line for ODS support */
importScripts('dist/ods.js');
postMessage({t:"ready"});
function ab2str(data) {

View File

@ -5,8 +5,6 @@
importScripts('dist/cpexcel.js');
importScripts('jszip.js');
importScripts('xlsx.js');
/* uncomment the next line for ODS support */
importScripts('dist/ods.js');
/*::self.*/postMessage({t:"ready"});
function ab2str(data) {

View File

@ -3,8 +3,6 @@
importScripts('dist/cpexcel.js');
importScripts('jszip.js');
importScripts('xlsx.js');
/* uncomment the next line for ODS support */
importScripts('dist/ods.js');
postMessage({t:"ready"});
function ab2str(data) {