Compare commits

..

1 Commits

Author SHA1 Message Date
saitulasiram94
bd26e174f2 fix #2752 sheet_to_csv skips first blank line with blankrows: true option
sheet_to_csv skips first blank line with blankrows: true option
2022-08-26 22:10:19 +02:00
86 changed files with 5967 additions and 11413 deletions

@ -11,7 +11,6 @@
"comma-dangle": [ 2, "never" ],
"curly": 0,
"no-bitwise": 0,
"no-cond-assign": 1,
"no-console": 0,
"no-control-regex": 0,
"no-unused-vars": 1,

@ -1,6 +0,0 @@
blank_issues_enabled: false
contact_links:
- name: Issues and Questions
url: https://git.sheetjs.com/sheetjs/sheetjs/issues
about: Please report issues to the official code repository.

1
.gitmodules vendored

@ -1,4 +1,3 @@
[submodule "test_files"]
path = test_files
url = https://github.com/SheetJS/test_files
ignore = dirty

@ -58,11 +58,11 @@ make.cmd
xlsworker.js
shim.js
test.js
hotcross.mjs
test.mjs
test.ts
test.mts
testnocp.ts
testbun.mjs
.jscs.json
.gitmodules
.travis.yml

@ -54,7 +54,6 @@ Rollup
SessionStorage
SQLite
SystemJS
Vite
VueJS
WebKit
WebSQL

@ -4,41 +4,6 @@ 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.
## v0.19.3
* XLSX Ensure comment address is valid (h/t @slonser)
* Enforce Excel worksheet name restrictions
## v0.19.2
* XLSX proper decoding of hyperlinks (h/t @tw-yaxu)
* XLSX ignore unexpected attributes in rich text (h/t @colin4)
* `sheet_to_json` type fix (h/t @chsdwn)
## v0.19.1
* Fixed types issue in strict mode (h/t @younes-io)
* Numbers 12.2 parsing skip ActivityStream.iwa
## v0.19.0
* XLSX export hyperlinks compatible with google sheets (h/t Evan Bovie)
* NUMBERS export multiple sheets, full worksheet range
* formalized `dense` mode
## v0.18.12
* `package.json` added types in `exports` structure
* uncapped NUMBERS single-sheet single-table export
* DBF export records using supported codepages
## v0.18.11
* Base64 input ignore data URI wrapper
* Parse ZIP files that use ZIP64 extended information field
* More precise handling of time-only values
* Threaded Comment fallback text for older Excel
## v0.18.10
* `exports` field in package.json to satiate ViteJS and newer tooling
@ -56,7 +21,7 @@ changes may not be included if they are not expected to break existing code.
## v0.18.8
* Plaintext parsing of dateless meridien time values (`1:23:45 PM`)
* Legacy format (SYLK / WK# / Multiplan) minutiae
* Legacy format (SYLK / WK# / Multiplan) minutiae
## v0.18.7

@ -113,7 +113,6 @@ BYTEFILER=dist/xlsx.extendscript.js xlsx.mjs
bytes: ## Display minified and gzipped file sizes
@for i in $(BYTEFILEC); do npx printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
@for i in $(BYTEFILER); do npx printj "%-30s %7d" $$i $$(wc -c < $$i); done
@npx printj "%-30s %10d" "treeshake" "$$(npx esbuild@0.14.14 --bundle misc/import.js | wc -c)"
.PHONY: git
@ -149,16 +148,16 @@ test.ts: test.mts
node -pe 'var data = fs.readFileSync("'$<'", "utf8"); data.split("\n").map(function(l) { return l.replace(/^describe\((.*?)function\(\)/, "Deno.test($$1async function(t)").replace(/\b(?:it|describe)\((.*?)function\(\)/g, "await t.step($$1async function(t)").replace("assert.ok", "assert.assert"); }).join("\n")' > $@
.PHONY: test-bun
test-bun: testbun.mjs ## Run Bun test suite
test-bun: hotcross.mjs ## Run Bun test suite
bun $<
.PHONY: test-deno
test-deno: test.ts ## Run Deno test suite
deno test --check --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
deno test --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
.PHONY: test-denocp
test-denocp: testnocp.ts ## Run Deno test suite (without codepage)
deno test --check --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
deno test --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
TESTFMT=$(patsubst %,test_%,$(FMT))
.PHONY: $(TESTFMT)

@ -9,6 +9,12 @@ Edit complex templates with ease; let out your inner Picasso with styling; make
custom sheets with images/graphs/PivotTables; evaluate formula expressions and
port calculations to web apps; automate common spreadsheet tasks, and much more!
[![License](https://img.shields.io/github/license/SheetJS/sheetjs)](https://github.com/SheetJS/sheetjs/blob/master/LICENSE)
[![Build Status](https://img.shields.io/github/workflow/status/sheetjs/sheetjs/Tests:%20node.js)](https://github.com/SheetJS/sheetjs/actions)
[![Snyk Vulnerabilities](https://img.shields.io/snyk/vulnerabilities/github/SheetJS/sheetjs)](https://snyk.io/test/github/SheetJS/sheetjs)
[![npm Downloads](https://img.shields.io/npm/dm/xlsx.svg)](https://cdn.sheetjs.com/)
[![GitHub Repo stars](https://img.shields.io/github/stars/SheetJS/sheetjs?style=social)](https://github.com/SheetJS/sheetjs)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/sheetjs?pixel)](https://github.com/SheetJS/sheetjs)
[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)

@ -1 +1 @@
XLSX.version = '0.19.3';
XLSX.version = '0.18.10';

@ -41,11 +41,6 @@ function utf16leread(data/*:string*/)/*:string*/ {
for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8));
return o.join("");
}
function utf16lereadu(data/*:Uint8Array*/)/*:string*/ {
var o/*:Array<string>*/ = [];
for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data[2*i] + (data[2*i+1]<<8));
return o.join("");
}
function utf16beread(data/*:string*/)/*:string*/ {
var o/*:Array<string>*/ = [];
for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8));

@ -71,7 +71,7 @@ var bconcat = has_buf ? function(bufs) { return Buffer.concat(bufs.map(function(
for(i = 0, maxlen = 0; i < bufs.length; maxlen += len, ++i) {
len = bufs[i].length;
if(bufs[i] instanceof Uint8Array) o.set(bufs[i], maxlen);
else if(typeof bufs[i] == "string") o.set(new Uint8Array(s2a(bufs[i])), maxlen);
else if(typeof bufs[i] == "string") { throw "wtf"; }
else o.set(new Uint8Array(bufs[i]), maxlen);
}
return o;

@ -73,7 +73,7 @@ function slice_by_16_tables(T) {
for(c = 256 + n; c < 4096; c += 256) v = table[c] = (v >>> 8) ^ T[v & 0xFF];
}
var out = [];
for(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' && typeof table.subarray == "function" ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256);
for(n = 1; n != 16; ++n) out[n - 1] = typeof Int32Array !== 'undefined' ? table.subarray(n * 256, n * 256 + 256) : table.slice(n * 256, n * 256 + 256);
return out;
}
var TT = slice_by_16_tables(T0);
@ -306,7 +306,7 @@ sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
/** Chains */
var sector_list/*:SectorList*/ = make_sector_list(sectors, dir_start, fat_addrs, ssz);
if(dir_start < sector_list.length) sector_list[dir_start].name = "!Directory";
sector_list[dir_start].name = "!Directory";
if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
sector_list[fat_addrs[0]].name = "!FAT";
sector_list.fat_addrs = fat_addrs;
@ -1500,9 +1500,9 @@ function write_zip(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/
var namebuf = new_buf(fp.length);
for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
namebuf = namebuf.slice(0, namebuf.l);
crcs[fcnt] = typeof fi.content == "string" ? CRC32.bstr(fi.content, 0) : CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
crcs[fcnt] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
var outbuf = typeof fi.content == "string" ? s2a(fi.content) : fi.content/*::||[]*/;
var outbuf = fi.content/*::||[]*/;
if(method == 8) outbuf = _deflateRawSync(outbuf);
/* local file header */

@ -181,29 +181,21 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
size = 2 * val.length;
} else if(f === 'sbcs' || f == 'cpstr') {
} else if(f === 'sbcs') {
if(typeof $cptable !== 'undefined' && current_ansi == 874) {
/* TODO: use tables directly, don't encode */
/*:: if(typeof val !== "string") throw new Error("unreachable"); */
for(i = 0; i != val.length; ++i) {
var cpp = $cptable.utils.encode(current_ansi, val.charAt(i));
this[this.l + i] = cpp[0];
var cppayload = $cptable.utils.encode(current_ansi, val.charAt(i));
this[this.l + i] = cppayload[0];
}
size = val.length;
} else if(typeof $cptable !== 'undefined' && f == 'cpstr') {
cpp = $cptable.utils.encode(current_codepage, val);
/* replace null bytes with _ when relevant */
if(cpp.length == val.length) for(i = 0; i < val.length; ++i) if(cpp[i] == 0 && val.charCodeAt(i) != 0) cpp[i] = 0x5F;
if(cpp.length == 2 * val.length) for(i = 0; i < val.length; ++i) if(cpp[2*i] == 0 && cpp[2*i+1] == 0 && val.charCodeAt(i) != 0) cpp[2*i] = 0x5F;
for(i = 0; i < cpp.length; ++i) this[this.l + i] = cpp[i];
size = cpp.length;
} else {
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
val = val.replace(/[^\x00-\x7F]/g, "_");
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
size = val.length;
}
size = val.length;
} else if(f === 'hex') {
for(; i < t; ++i) {
/*:: if(typeof val !== "string") throw new Error("unreachable"); */

@ -9,6 +9,7 @@ function fix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^([A-Z])/,"$
function unfix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^\$([A-Z])/,"$1"); }
function split_cell(cstr/*:string*/)/*:Array<string>*/ { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
//function decode_cell(cstr/*:string*/)/*:CellAddress*/ { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
function decode_cell(cstr/*:string*/)/*:CellAddress*/ {
var R = 0, C = 0;
for(var i = 0; i < cstr.length; ++i) {
@ -18,6 +19,7 @@ function decode_cell(cstr/*:string*/)/*:CellAddress*/ {
}
return { c: C - 1, r:R - 1 };
}
//function encode_cell(cell/*:CellAddress*/)/*:string*/ { return encode_col(cell.c) + encode_row(cell.r); }
function encode_cell(cell/*:CellAddress*/)/*:string*/ {
var col = cell.c + 1;
var s="";
@ -110,10 +112,9 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
var dense = _ws ? Array.isArray(_ws) : o.dense;
if(DENSE != null && dense == null) dense = DENSE;
var ws/*:Worksheet*/ = _ws || ({}/*:any*/);
if(dense && !ws["!data"]) ws["!data"] = [];
var ws/*:Worksheet*/ = _ws || (dense ? ([]/*:any*/) : ({}/*:any*/));
var _R = 0, _C = 0;
if(ws && o.origin != null) {
if(typeof o.origin == 'number') _R = o.origin;
@ -132,19 +133,13 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
range.e.r = Math.max(range.e.r, _range.e.r);
if(_R == -1) range.e.r = _R = _range.e.r + 1;
}
var row = [];
for(var R = 0; R != data.length; ++R) {
if(!data[R]) continue;
if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
var __R = _R + R, __Rstr = "" + (__R + 1);
if(dense) {
if(!ws["!data"][__R]) ws["!data"][__R] = [];
row = ws["!data"][__R];
}
for(var C = 0; C != data[R].length; ++C) {
if(typeof data[R][C] === 'undefined') continue;
var cell/*:Cell*/ = ({v: data[R][C] }/*:any*/);
var __C = _C + C;
var __R = _R + R, __C = _C + C;
if(range.s.r > __R) range.s.r = __R;
if(range.s.c > __C) range.s.c = __C;
if(range.e.r < __R) range.e.r = __R;
@ -168,16 +163,21 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
else cell.t = 's';
}
if(dense) {
if(row[__C] && row[__C].z) cell.z = row[__C].z;
row[__C] = cell;
if(!ws[__R]) ws[__R] = [];
if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z;
ws[__R][__C] = cell;
} else {
var cell_ref = encode_col(__C) + __Rstr/*:any*/;
var cell_ref = encode_cell(({c:__C,r:__R}/*:any*/));
if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z;
ws[cell_ref] = cell;
}
}
}
if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
if (range.s.c < 10000000) {
if (range.s.c > _C) range.s.c = _C;
if (range.s.r > _R) range.s.r = _R;
ws['!ref'] = encode_range(range);
}
return ws;
}
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }

@ -52,7 +52,7 @@ function parse_rels(data/*:?string*/, currentFilePath/*:string*/) {
var y = parsexmltag(x);
/* 9.3.2.2 OPC_Relationships */
if (y[0] === '<Relationship') {
var rel = {}; rel.Type = y.Type; rel.Target = unescapexml(y.Target); rel.Id = y.Id; if(y.TargetMode) rel.TargetMode = y.TargetMode;
var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; if(y.TargetMode) rel.TargetMode = y.TargetMode;
var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
rels[canonictarget] = rel;
hash[y.Id] = rel;

@ -1,61 +1,62 @@
/* 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;
case "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":
case "algorithm":
case "start-key-generation":
case "key-derivation":
throw new Error("Unsupported ODS Encryption");
default:
if (opts && opts.WTF)
throw Rn;
}
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) {
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("");
function write_manifest(manifest/*:Array<Array<string> >*/)/*: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("");
}
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("");
/* 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, 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_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) {
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 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("");
}
function write_meta_ods(wb, opts) {
return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>SheetJS ' + XLSX.version + "</meta:generator></office:meta></office:document-meta>";
/* TODO: pull properties */
function write_meta_ods(/*:: wb: Workbook, opts: any*/)/*:string*/ {
return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>';
}

@ -138,7 +138,7 @@ function parse_FtArray(blob, length/*::, ot*/) {
var ft = blob.read_shift(2);
blob.l-=2;
try {
fts[ft] = FtTab[ft](blob, tgt - blob.l);
fts.push(FtTab[ft](blob, tgt - blob.l));
} catch(e) { blob.l = tgt; return fts; }
}
if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
@ -696,11 +696,9 @@ function parse_Lbl(blob, length, opts) {
};
}
/* [MS-XLS] 2.4.106 TODO: legacy record filename encoding */
/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
function parse_ExternSheet(blob, length, opts) {
if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
/* see issue 2907 */
if(!(opts.biff > 8) && (length == blob[blob.l] + (blob[blob.l+1] == 0x03 ? 1 : 0) + 1)) return parse_BIFF5ExternSheet(blob, length, opts);
var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
// [iSupBook, itabFirst, itabLast];

@ -1,3 +1,4 @@
/* from js-harb (C) 2014-present SheetJS */
var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5];
var DBF = /*#__PURE__*/(function() {
var dbf_codepage_map = {
@ -238,14 +239,14 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
var o = sheet_to_workbook(dbf_to_sheet(buf, opts), opts);
o.bookType = "dbf";
return o;
} catch(e) { if(opts && opts.WTF) throw e; }
}
catch(e) { if(opts && opts.WTF) throw e; }
return ({SheetNames:[],Sheets:{}});
}
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
var o = opts || {};
var old_cp = current_codepage;
if(+o.codepage >= 0) set_cp(+o.codepage);
if(o.type == "string") throw new Error("Cannot write DBF to JS string");
var ba = buf_array();
@ -281,8 +282,7 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
default: _guess = 'C';
}
/* TODO: cache the values instead of encoding twice */
maxlen = Math.max(maxlen, (typeof $cptable !== "undefined" && typeof col[j] == "string" ? $cptable.utils.encode(current_ansi, col[j]): String(col[j])).length);
maxlen = Math.max(maxlen, String(col[j]).length);
guess = guess && guess != _guess ? 'C' : _guess;
//if(guess == 'C') break;
}
@ -308,17 +308,11 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
h.write_shift(2, 296 + 32 * hcnt);
h.write_shift(2, rlen);
for(i=0; i < 4; ++i) h.write_shift(4, 0);
var cp = +dbf_reverse_map[/*::String(*/current_codepage/*::)*/] || 0x03;
h.write_shift(4, 0x00000000 | (cp<<8));
if(dbf_codepage_map[cp] != +o.codepage) {
if(o.codepage) console.error("DBF Unsupported codepage " + current_codepage + ", using 1252");
current_codepage = 1252;
}
h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[/*::String(*/current_ansi/*::)*/] || 0x03)<<8));
for(i = 0, j = 0; i < headers.length; ++i) {
if(headers[i] == null) continue;
var hf = ba.next(32);
/* TODO: test how applications handle non-ASCII field names */
var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
hf.write_shift(1, _f, "sbcs");
hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
@ -347,7 +341,6 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
case 'N':
var _n = "0";
if(typeof data[i][j] == "number") _n = data[i][j].toFixed(coldecimals[j]||0);
if(_n.length > colwidths[j]) _n = _n.slice(0, colwidths[j]); // addresses decimal > width
for(hcnt=0; hcnt < colwidths[j]-_n.length; ++hcnt) rout.write_shift(1, 0x20);
rout.write_shift(1, _n, "sbcs");
break;
@ -359,16 +352,13 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
} break;
case 'C':
var _l = rout.l;
var _s = String(data[i][j] != null ? data[i][j] : "").slice(0, colwidths[j]);
rout.write_shift(1, _s, "cpstr");
_l += colwidths[j] - rout.l;
for(hcnt=0; hcnt < _l; ++hcnt) rout.write_shift(1, 0x20); break;
rout.write_shift(1, _s, "sbcs");
for(hcnt=0; hcnt < colwidths[j]-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
}
}
// data
}
current_codepage = old_cp;
ba.next(1).write_shift(1, 0x1A);
return ba.end();
}
@ -579,7 +569,7 @@ var SYLK = /*#__PURE__*/(function() {
case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
case 'e': o += cell.w || cell.v; break;
case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
case 's': o += '"' + (cell.v == null ? "" : String(cell.v)).replace(/"/g,"").replace(/;/g, ";;") + '"'; break;
case 's': o += '"' + cell.v.replace(/"/g,"").replace(/;/g, ";;") + '"'; break;
}
return o;
}
@ -608,10 +598,9 @@ var SYLK = /*#__PURE__*/(function() {
}
function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/, wb/*:?WorkBook*/)/*:string*/ {
/* TODO: codepage */
var preamble/*:Array<string>*/ = ["ID;PSheetJS;N;E"], o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
@ -623,10 +612,10 @@ var SYLK = /*#__PURE__*/(function() {
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
for(var R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
var p = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws[R]||[])[C]: ws[coord];
if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
p.push(write_ws_cell_sylk(cell, ws, R, C, opts)); // TODO: pass date1904 info
}
@ -694,55 +683,62 @@ var DIF = /*#__PURE__*/(function() {
return o;
}
function make_value(v/*:number*/, s/*:string*/)/*:string*/ { return "0," + String(v) + "\r\n" + s; }
function make_value_str(s/*:string*/)/*:string*/ { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var _DIF_XL = DIF_XL;
var r = safe_decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var o/*:Array<string>*/ = [
"TABLE\r\n0,1\r\n\"sheetjs\"\r\n",
"VECTORS\r\n0," + (r.e.r - r.s.r + 1) + "\r\n\"\"\r\n",
"TUPLES\r\n0," + (r.e.c - r.s.c + 1) + "\r\n\"\"\r\n",
"DATA\r\n0,0\r\n\"\"\r\n"
];
for(var R = r.s.r; R <= r.e.r; ++R) {
var row = dense ? ws["!data"][R] : [];
var p = "-1,0\r\nBOT\r\n";
for(var C = r.s.c; C <= r.e.c; ++C) {
var cell/*:Cell*/ = dense ? (row && row[C]) : ws[encode_cell({r:R,c:C})];
if(cell == null) { p +=("1,0\r\n\"\"\r\n"); continue;}
switch(cell.t) {
case 'n':
if(_DIF_XL) {
if(cell.w != null) p +=("0," + cell.w + "\r\nV");
else if(cell.v != null) p +=(make_value(cell.v, "V")); // TODO: should this call SSF_format?
else if(cell.f != null && !cell.F) p +=(make_value_str("=" + cell.f));
else p +=("1,0\r\n\"\"");
} else {
if(cell.v == null) p +=("1,0\r\n\"\"");
else p +=(make_value(cell.v, "V"));
}
break;
case 'b':
p +=(cell.v ? make_value(1, "TRUE") : make_value(0, "FALSE"));
break;
case 's':
p +=(make_value_str((!_DIF_XL || isNaN(+cell.v)) ? cell.v : '="' + cell.v + '"'));
break;
case 'd':
if(!cell.w) cell.w = SSF_format(cell.z || table_fmt[14], datenum(parseDate(cell.v)));
if(_DIF_XL) p +=(make_value(cell.w, "V"));
else p +=(make_value_str(cell.w));
break;
default: p +=("1,0\r\n\"\"");
var sheet_to_dif = /*#__PURE__*/(function() {
var push_field = function pf(o/*:Array<string>*/, topic/*:string*/, v/*:number*/, n/*:number*/, s/*:string*/) {
o.push(topic);
o.push(v + "," + n);
o.push('"' + s.replace(/"/g,'""') + '"');
};
var push_value = function po(o/*:Array<string>*/, type/*:number*/, v/*:any*/, s/*:string*/) {
o.push(type + "," + v);
o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
};
return function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = Array.isArray(ws);
push_field(o, "TABLE", 0, 1, "sheetjs");
push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
push_field(o, "DATA", 0, 0,"");
for(var R = r.s.r; R <= r.e.r; ++R) {
push_value(o, -1, 0, "BOT");
for(var C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws[R]||[])[C] : ws[coord];
if(!cell) { push_value(o, 1, 0, ""); continue;}
switch(cell.t) {
case 'n':
var val = DIF_XL ? cell.w : cell.v;
if(!val && cell.v != null) val = cell.v;
if(val == null) {
if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
else push_value(o, 1, 0, "");
}
else push_value(o, 0, val, "V");
break;
case 'b':
push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
break;
case 's':
push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
break;
case 'd':
if(!cell.w) cell.w = SSF_format(cell.z || table_fmt[14], datenum(parseDate(cell.v)));
if(DIF_XL) push_value(o, 0, cell.w, "V");
else push_value(o, 1, 0, cell.w);
break;
default: push_value(o, 1, 0, "");
}
}
p += "\r\n";
}
o.push(p);
}
return o.join("") + "-1,0\r\nEOD";
}
push_value(o, -1, 0, "EOD");
var RS = "\r\n";
var oo = o.join(RS);
//while((oo.length & 0x7F) != 0) oo += "\0";
return oo;
};
})();
return {
to_workbook: dif_to_workbook,
to_sheet: dif_to_sheet,
@ -805,11 +801,11 @@ var ETH = /*#__PURE__*/(function() {
if(!ws || !ws['!ref']) return "";
var o/*:Array<string>*/ = [], oo/*:Array<string>*/ = [], cell, coord = "";
var r = decode_range(ws['!ref']);
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
for(var R = r.s.r; R <= r.e.r; ++R) {
for(var C = r.s.c; C <= r.e.c; ++C) {
coord = encode_cell({r:R,c:C});
cell = dense ? (ws["!data"][R]||[])[C] : ws[coord];
cell = dense ? (ws[R]||[])[C] : ws[coord];
if(!cell || cell.v == null || cell.t === 'z') continue;
oo = ["cell", coord, 't'];
switch(cell.t) {
@ -931,8 +927,7 @@ var PRN = /*#__PURE__*/(function() {
var o = opts || {};
var sep = "";
if(DENSE != null && o.dense == null) o.dense = DENSE;
var ws/*:Worksheet*/ = ({}/*:any*/);
if(o.dense) ws["!data"] = [];
var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
if(str.slice(0,4) == "sep=") {
@ -978,7 +973,7 @@ var PRN = /*#__PURE__*/(function() {
cell.v = s;
}
if(cell.t == 'z'){}
else if(o.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = cell; }
else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
else ws[encode_cell({c:C,r:R})] = cell;
start = end+1; startcc = str.charCodeAt(start);
if(range.e.c < C) range.e.c = C;
@ -1034,12 +1029,12 @@ var PRN = /*#__PURE__*/(function() {
function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
for(var R = r.s.r; R <= r.e.r; ++R) {
var oo/*:Array<string>*/ = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws["!data"][R]||[])[C] : ws[coord];
cell = dense ? (ws[R]||[])[C] : ws[coord];
if(!cell || cell.v == null) { oo.push(" "); continue; }
var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
while(w.length < 10) w += " ";

@ -28,9 +28,8 @@ var WK_ = /*#__PURE__*/(function() {
if(!d) return d;
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
var s/*:Worksheet*/ = ({}/*:any*/), n = "Sheet1", next_n = "", sidx = 0;
var sheets = {}, snames = [], realnames = [], sdata = [];
if(o.dense) sdata = s["!data"] = [];
var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/), n = "Sheet1", next_n = "", sidx = 0;
var sheets = {}, snames = [], realnames = [];
var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
var sheetRows = o.sheetRows || 0;
@ -75,13 +74,13 @@ var WK_ = /*#__PURE__*/(function() {
s["!ref"] = encode_range(refguess);
sheets[n] = s;
snames.push(n);
s = ({}/*:any*/); if(o.dense) sdata = s["!data"] = [];
s = (o.dense ? [] : {});
refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
sidx = val[3]; n = next_n || "Sheet" + (sidx + 1); next_n = "";
}
}
var tmpcell = o.dense ? (sdata[val[0].r]||[])[val[0].c] : s[encode_cell(val[0])];
var tmpcell = o.dense ? (s[val[0].r]||[])[val[0].c] : s[encode_cell(val[0])];
if(tmpcell) {
tmpcell.t = val[1].t; tmpcell.v = val[1].v;
if(val[1].z != null) tmpcell.z = val[1].z;
@ -89,8 +88,8 @@ var WK_ = /*#__PURE__*/(function() {
break;
}
if(o.dense) {
if(!sdata[val[0].r]) sdata[val[0].r] = [];
sdata[val[0].r][val[0].c] = val[1];
if(!s[val[0].r]) s[val[0].r] = [];
s[val[0].r][val[0].c] = val[1];
} else s[encode_cell(val[0])] = val[1];
break;
case 0x5405: o.works2 = true; break;
@ -116,14 +115,14 @@ var WK_ = /*#__PURE__*/(function() {
s["!ref"] = encode_range(refguess);
sheets[n] = s;
snames.push(n);
s = ({}/*:any*/); if(o.dense) sdata = s["!data"] = [];
s = (o.dense ? [] : {});
refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
sidx = val[3]; n = "Sheet" + (sidx + 1);
}
if(sheetRows > 0 && val[0].r >= sheetRows) break;
if(o.dense) {
if(!sdata[val[0].r]) sdata[val[0].r] = [];
sdata[val[0].r][val[0].c] = val[1];
if(!s[val[0].r]) s[val[0].r] = [];
s[val[0].r][val[0].c] = val[1];
} else s[encode_cell(val[0])] = val[1];
if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
@ -158,17 +157,18 @@ var WK_ = /*#__PURE__*/(function() {
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
var ba = buf_array();
var range = safe_decode_range(ws["!ref"]);
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var cols = [];
write_biff_rec(ba, 0x00, write_BOF_WK1(0x0406));
write_biff_rec(ba, 0x06, write_RANGE(range));
var max_R = Math.min(range.e.r, 8191);
for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(var R = range.s.r; R <= max_R; ++R) {
var rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
var cell = dense ? (ws["!data"][R]||[])[C] : ws[cols[C] + rr];
for(var C = range.s.c; C <= range.e.c; ++C) {
if(R === range.s.r) cols[C] = encode_col(C);
var ref = cols[C] + rr;
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell || cell.t == "z") continue;
/* TODO: formula records */
if(cell.t == "n") {
@ -200,7 +200,7 @@ var WK_ = /*#__PURE__*/(function() {
var ws = wb.Sheets[wb.SheetNames[i]];
if(!ws || !ws["!ref"]) continue;
var range = safe_decode_range(ws["!ref"]);
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var cols = [];
var max_R = Math.min(range.e.r, 8191);
for(var R = range.s.r; R <= max_R; ++R) {
@ -208,7 +208,7 @@ var WK_ = /*#__PURE__*/(function() {
for(var C = range.s.c; C <= range.e.c; ++C) {
if(R === range.s.r) cols[C] = encode_col(C);
var ref = cols[C] + rr;
var cell = dense ? (ws["!data"][R]||[])[C] : ws[ref];
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell || cell.t == "z") continue;
/* TODO: FORMULA19 NUMBER18 records */
if(cell.t == "n") {
@ -919,7 +919,7 @@ var WK_ = /*#__PURE__*/(function() {
prep_blob(d, 0);
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
var s/*:Worksheet*/ = ({}/*:any*/); if(o.dense) s["!data"] = [];
var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/);
var SST = [], sname = "", formulae = [];
var range = {s:{r:-1,c:-1}, e:{r:-1,c:-1}};
var cnt = 0, type = 0, C = 0, R = 0;
@ -956,7 +956,7 @@ var WK_ = /*#__PURE__*/(function() {
case 0x0601: { /* BOS */
var sidx = p.read_shift(2);
s = ({}/*:any*/); if(o.dense) s["!data"] = [];
s = ((o.dense ? [] : {})/*:any*/);
range.s.c = p.read_shift(2);
range.e.c = p.read_shift(2);
range.s.r = p.read_shift(4);
@ -993,7 +993,6 @@ var WK_ = /*#__PURE__*/(function() {
R = p.read_shift(4), cnt = p.read_shift(4);
if(range.s.r > R) range.s.r = R;
if(range.e.r < R + cnt - 1) range.e.r = R + cnt - 1;
var CC = encode_col(C);
while(p.l < p.length) {
var cell = { t: "z" };
var flags = p.read_shift(1);
@ -1016,10 +1015,10 @@ var WK_ = /*#__PURE__*/(function() {
default: throw "Unsupported delta for QPW cell type " + (flags & 0x1F);
}
if(!(!o.sheetStubs && cell.t == "z")) {
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = cell;
} else s[CC + encode_row(R)] = cell;
if(Array.isArray(s)) {
if(!s[R]) s[R] = [];
s[R][C] = cell;
} else s[encode_cell({r:R, c:C})] = cell;
}
++R; --cnt;
while(mul-- > 0 && cnt >= 0) {
@ -1035,10 +1034,10 @@ var WK_ = /*#__PURE__*/(function() {
default: throw "Cannot apply repeat for QPW cell type " + (flags & 0x1F);
}
if(!(!o.sheetStubs && cell.t == "z")) {
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = cell;
} else s[CC + encode_row(R)] = cell;
if(Array.isArray(s)) {
if(!s[R]) s[R] = [];
s[R][C] = cell;
} else s[encode_cell({r:R, c:C})] = cell;
}
++R; --cnt;
}

@ -168,7 +168,7 @@ var rs_to_html = /*#__PURE__*/(function parse_rs_factory() {
})();
/* 18.4.8 si CT_Rst */
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r\b[^>]*>/;
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
function parse_si(x, opts) {
var html = opts ? opts.cellHTML : true;
@ -229,7 +229,6 @@ function write_sst_xml(sst/*:SST*/, opts)/*:string*/ {
else {
sitag += "<t";
if(!s.t) s.t = "";
if(typeof s.t !== "string") s.t = String(s.t);
if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
sitag += ">" + escapexml(s.t) + "</t>";
}

@ -13,18 +13,14 @@ function rtf_to_sheet(d, opts) {
}
function rtf_to_sheet_str(str, opts) {
var o = opts || {};
var ws = {};
var dense = o.dense;
if (dense)
ws["!data"] = [];
var ws = o.dense ? [] : {};
var rows = str.match(/\\trowd[\s\S]*?\\row\b/g);
if (!rows)
throw new Error("RTF missing table");
var range = { s: { c: 0, r: 0 }, e: { c: 0, r: rows.length - 1 } };
var row = [];
rows.forEach(function(rowtf, R) {
if (dense)
row = ws["!data"][R] = [];
if (Array.isArray(ws))
ws[R] = [];
var rtfre = /\\[\w\-]+\b/g;
var last_index = 0;
var res;
@ -50,8 +46,8 @@ function rtf_to_sheet_str(str, opts) {
cell.w = cell.v;
cell.v = fuzzynum(cell.v);
}
if (dense)
row[C] = cell;
if (Array.isArray(ws))
ws[R][C] = cell;
else
ws[encode_cell({ r: R, c: C })] = cell;
}
@ -79,17 +75,15 @@ function sheet_to_rtf(ws, opts) {
if (!ws["!ref"])
return o[0] + "}";
var r = safe_decode_range(ws["!ref"]), cell;
var dense = ws["!data"] != null, row = [];
var dense = Array.isArray(ws);
for (var R = r.s.r; R <= r.e.r; ++R) {
o.push("\\trowd\\trautofit1");
for (var C = r.s.c; C <= r.e.c; ++C)
o.push("\\cellx" + (C + 1));
o.push("\\pard\\intbl");
if (dense)
row = ws["!data"][R] || [];
for (C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({ r: R, c: C });
cell = dense ? row[C] : ws[coord];
cell = dense ? (ws[R] || [])[C] : ws[coord];
if (!cell || cell.v == null && (!cell.f || cell.F)) {
o.push(" \\cell");
continue;

@ -71,7 +71,7 @@ function parse_xlmeta_xml(data, name, opts) {
lastmeta.offsets.push(+y.i);
break;
default:
if (!pass && (opts == null ? void 0 : opts.WTF))
if (!pass && opts.WTF)
throw new Error("unrecognized " + y[0] + " in metadata");
}
return x;

@ -1,16 +1,15 @@
function sheet_insert_comments(sheet/*:WorkSheet*/, comments/*:Array<RawComment>*/, threaded/*:boolean*/, people/*:?Array<any>*/) {
var dense = sheet["!data"] != null;
function sheet_insert_comments(sheet, comments/*:Array<RawComment>*/, threaded/*:boolean*/, people/*:?Array<any>*/) {
var dense = Array.isArray(sheet);
var cell/*:Cell*/;
comments.forEach(function(comment) {
var r = decode_cell(comment.ref);
if(r.r < 0 || r.c < 0) return;
if(dense) {
if(!sheet["!data"][r.r]) sheet["!data"][r.r] = [];
cell = sheet["!data"][r.r][r.c];
if(!sheet[r.r]) sheet[r.r] = [];
cell = sheet[r.r][r.c];
} else cell = sheet[comment.ref];
if (!cell) {
cell = ({t:"z"}/*:any*/);
if(dense) sheet["!data"][r.r][r.c] = cell;
if(dense) sheet[r.r][r.c] = cell;
else sheet[comment.ref] = cell;
var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
if(range.s.r > r.r) range.s.r = r.r;
@ -18,7 +17,7 @@ function sheet_insert_comments(sheet/*:WorkSheet*/, comments/*:Array<RawComment>
if(range.s.c > r.c) range.s.c = r.c;
if(range.e.c < r.c) range.e.c = r.c;
var encoded = encode_range(range);
sheet["!ref"] = encoded;
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
}
if (!cell.c) cell.c = [];
@ -36,3 +35,4 @@ function sheet_insert_comments(sheet/*:WorkSheet*/, comments/*:Array<RawComment>
cell.c.push(o);
});
}

@ -50,27 +50,21 @@ function write_comments_xml(data/*::, opts*/) {
o.push("<commentList>");
data.forEach(function(d) {
/* 18.7.3 CT_Comment */
var lastauthor = 0, ts = [], tcnt = 0;
var lastauthor = 0, ts = [];
if(d[1][0] && d[1][0].T && d[1][0].ID) lastauthor = iauthor.indexOf("tc=" + d[1][0].ID);
d[1].forEach(function(c) {
else d[1].forEach(function(c) {
if(c.a) lastauthor = iauthor.indexOf(escapexml(c.a));
if(c.T) ++tcnt;
ts.push(c.t == null ? "" : escapexml(c.t));
ts.push(c.t||"");
});
if(tcnt === 0) {
d[1].forEach(function(c) {
o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
o.push('</text></comment>');
});
} else {
o.push('<comment ref="' + d[0] + '" authorId="' + lastauthor + '"><text>');
if(ts.length <= 1) o.push(writetag("t", escapexml(ts[0]||"")));
else {
/* based on Threaded Comments -> Comments projection */
o.push('<comment ref="' + d[0] + '" authorId="' + lastauthor + '"><text>');
var t = "Comment:\n " + (ts[0]) + "\n";
for(var i = 1; i < ts.length; ++i) t += "Reply:\n " + ts[i] + "\n";
o.push(writetag("t", escapexml(t)));
o.push('</text></comment>');
}
o.push('</text></comment>');
});
o.push("</commentList>");
if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }

@ -20,7 +20,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
if(DENSE != null && opts.dense == null) opts.dense = DENSE;
/* 18.3.1.99 worksheet CT_Worksheet */
var s = ({}/*:any*/); if(opts.dense) s["!data"] = [];
var s = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var refguess/*:Range*/ = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} }/*:any*/);
var data1 = "", data2 = "";
@ -39,7 +39,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
if(ridx > 0) {
var ref = data1.slice(ridx,ridx+50).match(dimregex);
if(ref && !(opts && opts.nodim)) parse_ws_xml_dim(s, ref[1]);
if(ref) parse_ws_xml_dim(s, ref[1]);
}
/* 18.3.1.88 sheetViews CT_SheetViews */
@ -75,7 +75,6 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
var margins = data2.match(marginregex);
if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
if(opts && opts.nodim) refguess.s.c = refguess.s.r = 0;
if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
if(opts.sheetRows > 0 && s["!ref"]) {
var tmpref = safe_decode_range(s["!ref"]);
@ -150,7 +149,7 @@ function write_ws_xml_protection(sp)/*:string*/ {
}
function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
var dense = s["!data"] != null;
var dense = Array.isArray(s);
for(var i = 0; i != data.length; ++i) {
var val = parsexmltag(utf8read(data[i]), true);
if(!val.ref) return;
@ -166,11 +165,11 @@ function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
var addr = encode_col(C) + encode_row(R);
var addr = encode_cell({c:C,r:R});
if(dense) {
if(!s["!data"][R]) s["!data"][R] = [];
if(!s["!data"][R][C]) s["!data"][R][C] = {t:"z",v:undefined};
s["!data"][R][C].l = val;
if(!s[R]) s[R] = [];
if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
s[R][C].l = val;
} else {
if(!s[addr]) s[addr] = {t:"z",v:undefined};
s[addr].l = val;
@ -264,10 +263,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
var oldt = cell.t, oldv = cell.v;
if(cell.t !== "z") switch(cell.t) {
case 'b': vv = cell.v ? "1" : "0"; break;
case 'n':
if(isNaN(cell.v)) { cell.t = "e"; vv = BErr[cell.v = 0x24]; } // #NUM!
else if(!isFinite(cell.v)) { cell.t = "e"; vv = BErr[cell.v = 0x07]; } // #DIV/0!
else vv = ''+cell.v; break;
case 'n': vv = ''+cell.v; break;
case 'e': vv = BErr[cell.v]; break;
case 'd':
if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
@ -303,10 +299,7 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
}
if(cell.l) {
cell.l.display = escapexml(vv);
ws['!links'].push([ref, cell.l]);
}
if(cell.l) ws['!links'].push([ref, cell.l]);
if(cell.D) o.cm = 1;
return writextag('c', v, o);
}
@ -325,7 +318,7 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
var do_format = Array.isArray(styles.CellXf), cf;
var arrayf/*:Array<[Range, string]>*/ = [];
var sharedf = [];
var dense = s["!data"] != null;
var dense = Array.isArray(s);
var rows/*:Array<RowInfo>*/ = [], rowobj = {}, rowrite = false;
var sheetStubs = !!opts.sheetStubs;
for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
@ -356,10 +349,8 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
tag = parsexmltag(x.slice(rstarti,ri), true);
tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
if(opts.sheetRows && opts.sheetRows < tagr) continue;
if(!opts.nodim) {
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
}
if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
if(opts && opts.cellStyles) {
rowobj = {}; rowrite = false;
@ -490,16 +481,10 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
var cm = (opts.xlmeta.Cell||[])[+tag.cm-1];
if(cm && cm.type == 'XLDAPR') p.D = true;
}
var _r;
if(opts.nodim) {
_r = decode_cell(tag.r);
if(guess.s.r > _r.r) guess.s.r = _r.r;
if(guess.e.r < _r.r) guess.e.r = _r.r;
}
if(dense) {
_r = decode_cell(tag.r);
if(!s["!data"][_r.r]) s["!data"][_r.r] = [];
s["!data"][_r.r][_r.c] = p;
var _r = decode_cell(tag.r);
if(!s[_r.r]) s[_r.r] = [];
s[_r.r][_r.c] = p;
} else s[tag.r] = p;
}
}
@ -508,7 +493,7 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*//*::, rels*/)/*:string*/ {
var o/*:Array<string>*/ = [], r/*:Array<string>*/ = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols/*:Array<string>*/ = [], R=0, C=0, rows = ws['!rows'];
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var params = ({r:rr}/*:any*/), row/*:RowInfo*/, height = -1;
for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(R = range.s.r; R <= range.e.r; ++R) {
@ -516,7 +501,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
var _cell = dense ? (ws["!data"][R]||[])[C]: ws[ref];
var _cell = dense ? (ws[R]||[])[C]: ws[ref];
if(_cell === undefined) continue;
if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
}
@ -624,7 +609,6 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
}
if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
rel.display = l[1].display;
o[o.length] = writextag("hyperlink",null,rel);
});
o[o.length] = "</hyperlinks>";

@ -41,13 +41,12 @@ function write_BrtRowHdr(R/*:number*/, range, ws) {
o.l += 4;
var caddr = {r:R, c:0};
var dense = ws["!data"] != null;
for(var i = 0; i < 16; ++i) {
if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue;
var first = -1, last = -1;
for(var j = (i<<10); j < ((i+1)<<10); ++j) {
caddr.c = j;
var cell = dense ? (ws["!data"][caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
if(cell) { if(first < 0) first = j; last = j; }
}
if(first < 0) continue;
@ -259,10 +258,9 @@ function parse_BrtCellSt(data) {
return [cell, value, 'str'];
}
function write_BrtCellSt(cell, ncell, o) {
var data = cell.v == null ? "" : String(cell.v);
if(o == null) o = new_buf(12 + 4 * cell.v.length);
write_XLSBCell(ncell, o);
write_XLWideString(data, o);
write_XLWideString(cell.v, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
function parse_BrtShortSt(data) {
@ -271,10 +269,9 @@ function parse_BrtShortSt(data) {
return [cell, value, 'str'];
}
function write_BrtShortSt(cell, ncell, o) {
var data = cell.v == null ? "" : String(cell.v);
if(o == null) o = new_buf(8 + 4 * data.length);
if(o == null) o = new_buf(8 + 4 * cell.v.length);
write_XLSBShortCell(ncell, o);
write_XLWideString(data, o);
write_XLWideString(cell.v, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
@ -511,7 +508,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
var opts = _opts || {};
if(!rels) rels = {'!id':{}};
if(DENSE != null && opts.dense == null) opts.dense = DENSE;
var s/*:Worksheet*/ = ({}); if(opts.dense) s["!data"] = [];
var s/*:Worksheet*/ = (opts.dense ? [] : {});
var ref;
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
@ -587,7 +584,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
}
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
C = val[0].c == -1 ? C + 1 : val[0].c;
if(opts.dense) { if(!s["!data"][R]) s["!data"][R] = []; s["!data"][R][C] = p; }
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
else s[encode_col(C) + rr] = p;
if(opts.cellFormula) {
af = false;
@ -620,7 +617,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
if(!opts.sheetStubs || pass) break;
p = ({t:'z',v:void 0}/*:any*/);
C = val[0].c == -1 ? C + 1 : val[0].c;
if(opts.dense) { if(!s["!data"][R]) s["!data"][R] = []; s["!data"][R][C] = p; }
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
else s[encode_col(C) + rr] = p;
if(refguess.s.r > row.r) refguess.s.r = row.r;
if(refguess.s.c > C) refguess.s.c = C;
@ -651,11 +648,11 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
if(opts.dense) {
if(!s["!data"][R]) s["!data"][R] = [];
if(!s["!data"][R][C]) s["!data"][R][C] = {t:'z',v:undefined};
s["!data"][R][C].l = val;
if(!s[R]) s[R] = [];
if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
s[R][C].l = val;
} else {
addr = encode_col(C) + encode_row(R);
addr = encode_cell({c:C,r:R});
if(!s[addr]) s[addr] = {t:'z',v:undefined};
s[addr].l = val;
}
@ -665,14 +662,14 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
case 0x01AA: /* 'BrtArrFmla' */
if(!opts.cellFormula) break;
arrayf.push(val);
cell = ((opts.dense ? s["!data"][R][C] : s[encode_col(C) + rr])/*:any*/);
cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr])/*:any*/);
cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
cell.F = encode_range(val[0]);
break;
case 0x01AB: /* 'BrtShrFmla' */
if(!opts.cellFormula) break;
sharedf[encode_cell(val[0].s)] = val[1];
cell = (opts.dense ? s["!data"][R][C] : s[encode_col(C) + rr]);
cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
break;
@ -827,7 +824,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
switch(cell.t) {
case 's': case 'str':
if(opts.bookSST) {
vv = get_sst_id(opts.Strings, (cell.v == null ? "" : String(cell.v)/*:any*/), opts.revStrings);
vv = get_sst_id(opts.Strings, (cell.v/*:any*/), opts.revStrings);
o.t = "s"; o.v = vv;
if(last_seen) write_record(ba, 0x0012 /* BrtShortIsst */, write_BrtShortIsst(cell, o));
else write_record(ba, 0x0007 /* BrtCellIsst */, write_BrtCellIsst(cell, o));
@ -842,12 +839,6 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) {
if(last_seen) write_record(ba, 0x000D /* BrtShortRk */, write_BrtShortRk(cell, o));
else write_record(ba, 0x0002 /* BrtCellRk */, write_BrtCellRk(cell, o));
} else if(isNaN(cell.v)) {
if(last_seen) write_record(ba, 0x000E /* BrtShortError */, write_BrtShortError({t:"e", v: 0x24}, o)); // #NUM!
else write_record(ba, 0x0003 /* BrtCellError */, write_BrtCellError({t:"e", v: 0x24}, o)); // #NUM!
} else if(!isFinite(cell.v)) {
if(last_seen) write_record(ba, 0x000E /* BrtShortError */, write_BrtShortError({t:"e", v: 0x07}, o)); // #DIV/0!
else write_record(ba, 0x0003 /* BrtCellError */, write_BrtCellError({t:"e", v: 0x07}, o)); // #DIV/0!
} else {
if(last_seen) write_record(ba, 0x0010 /* BrtShortReal */, write_BrtShortReal(cell, o));
else write_record(ba, 0x0005 /* BrtCellReal */, write_BrtCellReal(cell, o));
@ -871,7 +862,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols/*:Array<string>*/ = [];
write_record(ba, 0x0091 /* BrtBeginSheetData */);
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var cap = range.e.r;
if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1);
for(var R = range.s.r; R <= cap; ++R) {
@ -884,7 +875,7 @@ function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Work
/* *16384CELL */
if(R === range.s.r) cols[C] = encode_col(C);
ref = cols[C] + rr;
var cell = dense ? (ws["!data"][R]||[])[C] : ws[ref];
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell) { last_seen = false; continue; }
/* write cell */
last_seen = write_ws_bin_cell(ba, cell, R, C, opts, ws, last_seen);

@ -34,10 +34,7 @@ function parse_chart(data/*:?string*/, name/*:string*/, opts, rels, wb, csheet)
refguess.e.c = C;
col = encode_col(C);
cache[0].forEach(function(n,i) {
if(cs["!data"]) {
if(!cs["!data"][i]) cs["!data"][i] = [];
cs["!data"][i][C] = {t:'n', v:n, z:cache[1] };
} else cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
R = i;
});
if(refguess.e.r < R) refguess.e.r = R;

@ -115,17 +115,14 @@ function safe1904(wb/*:Workbook*/)/*:string*/ {
var badchars = /*#__PURE__*/":][*?\/\\".split("");
function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ {
try {
if(n == "") throw new Error("Sheet name cannot be blank");
if(n.length > 31) throw new Error("Sheet name cannot exceed 31 chars");
if(n.charCodeAt(0) == 0x27 || n.charCodeAt(n.length - 1) == 0x27) throw new Error("Sheet name cannot start or end with apostrophe (')");
if(n.toLowerCase() == "history") throw new Error("Sheet name cannot be 'History'");
badchars.forEach(function(c) {
if(n.indexOf(c) == -1) return;
throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
});
} catch(e) { if(safe) return false; throw e; }
return true;
if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
var _good = true;
badchars.forEach(function(c) {
if(n.indexOf(c) == -1) return;
if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
_good = false;
});
return _good;
}
function check_wb_names(N, S, codes) {
N.forEach(function(n,i) {

@ -207,7 +207,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
var Rn;
var state = [], tmp;
if(DENSE != null && opts.dense == null) opts.dense = DENSE;
var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = ({}), sheetname = ""; if(opts.dense) cursheet["!data"] = [];
var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = (opts.dense ? [] : {}), sheetname = "";
var cell = ({}/*:any*/), row = {};// eslint-disable-line no-unused-vars
var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
var c = 0, r = 0;
@ -240,8 +240,8 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
if(comments.length > 0) cell.c = comments;
if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== void 0) {
if(opts.dense) {
if(!cursheet["!data"][r]) cursheet["!data"][r] = [];
cursheet["!data"][r][c] = cell;
if(!cursheet[r]) cursheet[r] = [];
cursheet[r][c] = cell;
} else cursheet[encode_col(c) + encode_row(r)] = cell;
}
if(cell.HRef) {
@ -261,8 +261,8 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
for(var cmd = r; cmd <= rr; ++cmd) {
if(cma > c || cmd > r) {
if(opts.dense) {
if(!cursheet["!data"][cmd]) cursheet["!data"][cmd] = [];
cursheet["!data"][cmd][cma] = {t:'z'};
if(!cursheet[cmd]) cursheet[cmd] = [];
cursheet[cmd][cma] = {t:'z'};
} else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
}
}
@ -321,7 +321,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
state.push([Rn[3], false]);
tmp = xlml_parsexmltag(Rn[0]);
sheetname = unescapexml(tmp.Name);
cursheet = ({}); if(opts.dense) cursheet["!data"] = [];
cursheet = (opts.dense ? [] : {});
merges = [];
arrayf = [];
rowinfo = [];
@ -1177,7 +1177,7 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
if(n.hidden) k['ss:Hidden']="1";
o.push(writextag("Column",null,k));
});
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
for(var R = range.s.r; R <= range.e.r; ++R) {
var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
for(var C = range.s.c; C <= range.e.c; ++C) {
@ -1192,7 +1192,7 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
}
if(skip) continue;
var addr = {r:R,c:C};
var ref = encode_col(C) + encode_row(R), cell = dense ? (ws["!data"][R]||[])[C] : ws[ref];
var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
}
row.push("</Row>");

@ -104,7 +104,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
var wb = ({opts:{}}/*:any*/);
var Sheets = {};
if(DENSE != null && options.dense == null) options.dense = DENSE;
var out/*:Worksheet*/ = ({}/*:any*/); if(options.dense) out["!data"] = [];
var out/*:Worksheet*/ = ((options.dense ? [] : {})/*:any*/);
var Directory = {};
var range/*:Range*/ = ({}/*:any*/);
var last_formula = null;
@ -157,8 +157,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
}
{
if(options.dense) {
if(!out["!data"][cell.r]) out["!data"][cell.r] = [];
out["!data"][cell.r][cell.c] = line;
if(!out[cell.r]) out[cell.r] = [];
out[cell.r][cell.c] = line;
} else out[last_cell] = line;
}
};
@ -324,7 +324,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
Workbook.Sheets.push(wsprops);
}
if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
out = ({}/*:any*/); if(options.dense) out["!data"] = [];
out = ((options.dense ? [] : {})/*:any*/);
} break;
case 0x0009: case 0x0209: case 0x0409: case 0x0809 /* BOF */: {
if(opts.biff === 8) opts.biff = {
@ -344,7 +344,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
if(val.BIFFVer == 0 && val.dt == 0x1000) { opts.biff = 5; seen_codepage = true; set_cp(opts.codepage = 28591); }
if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
if(file_depth++) break;
out = ({}/*:any*/); if(options.dense) out["!data"] = [];
out = ((options.dense ? [] : {})/*:any*/);
if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
@ -367,7 +367,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
} break;
case 0x0203 /* Number */: case 0x0003 /* BIFF2NUM */: case 0x0002 /* BIFF2INT */: {
if(out["!type"] == "chart") if(options.dense ? (out["!data"][val.r]||[])[val.c]: out[encode_col(val.c) + encode_row(val.r)]) ++val.c;
if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'}/*:any*/);
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
@ -404,7 +404,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
var _fe = encode_cell({r:_fr, c:_fc});
if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
else temp_val.F = ((options.dense ? (out["!data"][_fr]||[])[_fc]: out[_fe]) || {}).F;
else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
}
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
@ -429,7 +429,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 0x0021: case 0x0221 /* Array */: {
arrayf.push(val);
var _arraystart = encode_cell(val[0].s);
cc = options.dense ? (out["!data"][val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
if(options.cellFormula && cc) {
if(!last_formula) break; /* technically unreachable */
if(!_arraystart || !cc) break;
@ -443,7 +443,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
/* TODO: capture range */
if(!last_formula) break; /* technically unreachable */
sharedf[encode_cell(last_formula.cell)]= val[0];
cc = options.dense ? (out["!data"][last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
(cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
}
} break;
@ -508,25 +508,25 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 0x01b8 /* HLink */: {
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
cc = options.dense ? (out["!data"][rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
if(cc) cc.l = val[1];
}
} break;
case 0x0800 /* HLinkTooltip */: {
for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
cc = options.dense ? (out["!data"][rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
if(cc && cc.l) cc.l.Tooltip = val[1];
}
} break;
case 0x001c /* Note */: {
if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
cc = options.dense ? (out["!data"][val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
var noteobj = objects[val[2]];
if(!cc) {
if(options.dense) {
if(!out["!data"][val[0].r]) out["!data"][val[0].r] = [];
cc = out["!data"][val[0].r][val[0].c] = ({t:"z"}/*:any*/);
if(!out[val[0].r]) out[val[0].r] = [];
cc = out[val[0].r][val[0].c] = ({t:"z"}/*:any*/);
} else {
cc = out[encode_cell(val[0])] = ({t:"z"}/*:any*/);
}

@ -62,37 +62,33 @@ function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
if((v == (v|0)) && (v >= 0) && (v < 65536))
write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
else if(isNaN(v))
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x24, "e")); // #NUM!
else if(!isFinite(v))
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x07, "e")); // #DIV/0!
else
write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
return;
case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
/* TODO: codepage, sst */
case 's': case 'str':
write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v == null ? "" : String(cell.v).slice(0,255)));
write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, (cell.v||"").slice(0,255)));
return;
}
write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
}
function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
ref = encode_range(range);
}
var row = [];
for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(var R = range.s.r; R <= range.e.r; ++R) {
if(dense) row = ws["!data"][R] || [];
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
var cell = dense ? row[C] : ws[cols[C] + rr];
for(var C = range.s.c; C <= range.e.c; ++C) {
if(R === range.s.r) cols[C] = encode_col(C);
ref = cols[C] + rr;
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell) continue;
/* write cell */
write_ws_biff2_cell(ba, cell, R, C, opts);
@ -103,6 +99,7 @@ function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/
/* Based on test files */
function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
var ba = buf_array();
var idx = 0;
for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
@ -186,10 +183,8 @@ function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
else switch(cell.t) {
case 'd': case 'n':
var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
if(isNaN(v)) write_biff_rec(ba, 0x0205 /* BoolErr */, write_BoolErr(R, C, 0x24, os, opts, "e")); // #NUM!
else if(!isFinite(v)) write_biff_rec(ba, 0x0205 /* BoolErr */, write_BoolErr(R, C, 0x07, os, opts, "e")); // #DIV/0!
/* TODO: emit RK as appropriate */
else write_biff_rec(ba, 0x0203 /* Number */, write_Number(R, C, v, os, opts));
write_biff_rec(ba, 0x0203 /* Number */, write_Number(R, C, v, os, opts));
break;
case 'b': case 'e':
write_biff_rec(ba, 0x0205 /* BoolErr */, write_BoolErr(R, C, cell.v, os, opts, cell.t));
@ -197,9 +192,9 @@ function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
/* TODO: codepage, sst */
case 's': case 'str':
if(opts.bookSST) {
var isst = get_sst_id(opts.Strings, cell.v == null ? "" : String(cell.v), opts.revStrings);
var isst = get_sst_id(opts.Strings, cell.v, opts.revStrings);
write_biff_rec(ba, 0x00fd /* LabelSst */, write_LabelSst(R, C, isst, os, opts));
} else write_biff_rec(ba, 0x0204 /* Label */, write_Label(R, C, (cell.v == null ? "" : String(cell.v)).slice(0,255), os, opts));
} else write_biff_rec(ba, 0x0204 /* Label */, write_Label(R, C, (cell.v||"").slice(0,255), os, opts));
break;
default:
write_biff_rec(ba, 0x0201 /* Blank */, write_XLSCell(R, C, os));
@ -212,7 +207,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/);
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
var b8 = opts.biff == 8;
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1");
@ -248,14 +243,12 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
if(b8) ws['!links'] = [];
var comments = [];
var row = [];
for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
for(var R = range.s.r; R <= range.e.r; ++R) {
if(dense) row = ws["!data"][R] || [];
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
for(var C = range.s.c; C <= range.e.c; ++C) {
if(R === range.s.r) cols[C] = encode_col(C);
ref = cols[C] + rr;
var cell = dense ? row[C] : ws[ref];
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);

@ -1,8 +1,8 @@
/* note: browser DOM element cannot see mso- style attrs, must parse */
function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ {
var opts = _opts || {};
var dense = (opts.dense != null) ? opts.dense : DENSE;
var ws/*:Worksheet*/ = ({}/*:any*/); if(dense) ws["!data"] = [];
if(DENSE != null && opts.dense == null) opts.dense = DENSE;
var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
str = str.replace(/<!--.*?-->/g, "");
var mtch/*:any*/ = str.match(/<table/i);
if(!mtch) throw new Error("Invalid HTML: could not find <table>");
@ -48,7 +48,7 @@ function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ {
if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/);
o.z = opts.dateNF || table_fmt[14];
}
if(dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = o; }
if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
else ws[encode_cell({r:R, c:C})] = o;
C += CS;
}
@ -61,7 +61,6 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
var M/*:Array<Range>*/ = (ws['!merges'] ||[]);
var oo/*:Array<string>*/ = [];
var sp = ({}/*:any*/);
var dense = ws["!data"] != null;
for(var C = r.s.c; C <= r.e.c; ++C) {
var RS = 0, CS = 0;
for(var j = 0; j < M.length; ++j) {
@ -71,8 +70,8 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
}
if(RS < 0) continue;
var coord = encode_col(C) + encode_row(R);
var cell = dense ? (ws["!data"][R]||[])[C] : ws[coord];
var coord = encode_cell({r:R,c:C});
var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
/* TODO: html entities */
var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
sp = ({}/*:any*/);
@ -83,7 +82,7 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
sp["data-t"] = cell && cell.t || 'z';
if(cell.v != null) sp["data-v"] = cell.v;
if(cell.z != null) sp["data-z"] = cell.z;
if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + cell.l.Target +'">' + w + '</a>';
}
sp.id = (o.id || "sjs") + "-" + coord;
oo.push(writextag('td', w, sp));
@ -120,6 +119,7 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
var footer = o.footer != null ? o.footer : HTML_END;
var out/*:Array<string>*/ = [header];
var r = decode_range(ws['!ref']);
o.dense = Array.isArray(ws);
out.push(make_html_preamble(ws, r, o));
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
@ -134,7 +134,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
}
var opts = _opts || {};
var dense = ws["!data"] != null;
if(DENSE != null) opts.dense = DENSE;
var or_R = 0, or_C = 0;
if(opts.origin != null) {
if(typeof opts.origin == 'number') or_R = opts.origin;
@ -199,7 +199,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break;
}
if(l && l.charAt(0) != "#" && l.slice(0, 11).toLowerCase() != 'javascript:') o.l = ({ Target: l });
if(dense) { if(!ws["!data"][R + or_R]) ws["!data"][R + or_R] = []; ws["!data"][R + or_R][C + or_C] = o; }
if(opts.dense) { if(!ws[R + or_R]) ws[R + or_R] = []; ws[R + or_R][C + or_C] = o; }
else ws[encode_cell({c:C + or_C, r:R + or_R})] = o;
if(range.e.c < C + or_C) range.e.c = C + or_C;
C += CS;
@ -215,7 +215,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ {
var opts = _opts || {};
var ws/*:Worksheet*/ = ({}/*:any*/); if(opts.dense) ws["!data"] = [];
var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
return sheet_add_dom(ws, table, _opts);
}

@ -245,7 +245,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
var sheetag/*:: = {name:"", '名称':""}*/;
var rowtag/*:: = {'行号':""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [];
var ws = ({}/*:any*/); if(opts.dense) ws["!data"] = [];
var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/;
var ctag = ({value:""}/*:any*/);
var textp = "", textpidx = 0, textptag/*:: = {}*/;
@ -289,7 +289,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
sheetag = parsexmltag(Rn[0], false);
R = C = -1;
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = ({}/*:any*/); if(opts.dense) ws["!data"] = []; merges = [];
ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = [];
rowinfo = [];
intable = true;
}
@ -309,7 +309,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
if(Rn[1] !== '/') ++C;
if(opts.sheetStubs) {
if(opts.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = {t:'z'}; }
if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
else ws[encode_cell({r:R,c:C})] = {t:'z'};
}
textp = ""; textR = [];
@ -325,10 +325,10 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
if((ctag['数据类型'] || ctag['value-type']) == "string") {
q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
if(opts.dense) {
if(!ws["!data"][R]) ws["!data"][R] = [];
ws["!data"][R][C] = q;
if(!ws[R]) ws[R] = [];
ws[R][C] = q;
} else {
ws[encode_col(C) + encode_row(R)] = q;
ws[encode_cell({r:R,c:C})] = q;
}
}
C+= colpeat-1;
@ -405,9 +405,9 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
for(var rpt = 0; rpt < rowpeat; ++rpt) {
colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
if(opts.dense) {
if(!ws["!data"][R + rpt]) ws["!data"][R + rpt] = [];
ws["!data"][R + rpt][C] = rpt == 0 ? q : dup(q);
while(--colpeat > 0) ws["!data"][R + rpt][C + colpeat] = dup(q);
if(!ws[R + rpt]) ws[R + rpt] = [];
ws[R + rpt][C] = rpt == 0 ? q : dup(q);
while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
} else {
ws[encode_cell({r:R + rpt,c:C})] = q;
while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);

@ -211,7 +211,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="ta1">\n');
var R=0,C=0, range = decode_range(ws['!ref']||"A1");
var marr/*:Array<Range>*/ = ws['!merges'] || [], mi = 0;
var dense = ws["!data"] != null;
var dense = Array.isArray(ws);
if(ws["!cols"]) {
for(C = 0; C <= range.e.c; ++C) o.push(' <table:table-column' + (ws["!cols"][C] ? ' table:style-name="co' + ws["!cols"][C].ods + '"' : '') + '></table:table-column>\n');
}
@ -237,7 +237,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
break;
}
if(skip) { o.push(covered_cell_xml); continue; }
var ref = encode_cell({r:R, c:C}), cell = dense ? (ws["!data"][R]||[])[C]: ws[ref];
var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
if(cell && cell.f) {
ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
if(cell.F) {
@ -347,10 +347,9 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
var nfi = 69;
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
if(!ws) return;
var dense = (ws["!data"] != null);
var range = decode_range(ws["!ref"]);
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
var c = Array.isArray(ws) ? (ws[R]||[])[C] : ws[encode_cell({r:R,c:C})];
if(!c || !c.z || c.z.toLowerCase() == "general") continue;
if(!nfs[c.z]) {
var out = write_number_format_ods(c.z, "N" + nfi);

File diff suppressed because it is too large Load Diff

@ -36,12 +36,12 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/
sheets[sheet] = _ws;
/* scan rels for comments and threaded comments */
var comments = [], tcomments = [];
var tcomments = [];
if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) {
var dfile = "";
if(sheetRels[sheet][n].Type == RELS.CMNT) {
dfile = resolve_path(sheetRels[sheet][n].Target, path);
comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
var comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
if(!comments || !comments.length) return;
sheet_insert_comments(_ws, comments, false);
}

@ -101,8 +101,7 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
/* TODO: something more intelligent with themes */
f = "xl/theme/theme1.xml";
var ww = write_theme(wb.Themes, opts);
zip_add_file(zip, f, ww);
zip_add_file(zip, f, write_theme(wb.Themes, opts));
ct.themes.push(f);
add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);

@ -50,13 +50,7 @@ function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
function read_utf16(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
var d = data;
if(o.type == 'base64') d = Base64_decode(d);
if(typeof ArrayBuffer !== "undefined" && data instanceof ArrayBuffer) d = new Uint8Array(data);
d = typeof $cptable !== "undefined" ? $cptable.utils.decode(1200, d.slice(2), 'str') : (
(has_buf && Buffer.isBuffer(data)) ? data.slice(2).toString("utf16le") :
(typeof Uint8Array !== "undefined" && d instanceof Uint8Array) ? (
typeof TextDecoder !== "undefined" ? new TextDecoder("utf-16le").decode(d.slice(2)) : utf16lereadu(d.slice(2))
) : utf16leread(d.slice(2))
);
d = typeof $cptable !== "undefined" ? $cptable.utils.decode(1200, d.slice(2), 'str') : utf16leread(d.slice(2));
o.type = "binary";
return read_plaintext(d, o);
}

@ -4,17 +4,17 @@ type MJRObject = {
isempty: boolean;
};
*/
function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ {
function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, dense/*:boolean*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ {
var rr = encode_row(R);
var defval = o.defval, raw = o.raw || !Object.prototype.hasOwnProperty.call(o, "raw");
var isempty = true, dense = (sheet["!data"] != null);
var isempty = true;
var row/*:any*/ = (header === 1) ? [] : {};
if(header !== 1) {
if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
else row.__rowNum__ = R;
}
if(!dense || sheet["!data"][R]) for (var C = r.s.c; C <= r.e.c; ++C) {
var val = dense ? (sheet["!data"][R]||[])[C] : sheet[cols[C] + rr];
if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
if(val === undefined || val.t === undefined) {
if(defval === undefined) continue;
if(hdr[C] != null) { row[hdr[C]] = defval; }
@ -63,16 +63,16 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) {
var cols/*:Array<string>*/ = [];
var out/*:Array<any>*/ = [];
var outi = 0, counter = 0;
var dense = sheet["!data"] != null;
var dense = Array.isArray(sheet);
var R = r.s.r, C = 0;
var header_cnt = {};
if(dense && !sheet["!data"][R]) sheet["!data"][R] = [];
if(dense && !sheet[R]) sheet[R] = [];
var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
var rowinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!rows"] || [];
for(C = r.s.c; C <= r.e.c; ++C) {
if(((colinfo[C]||{}).hidden)) continue;
cols[C] = encode_col(C);
val = dense ? sheet["!data"][R][C] : sheet[cols[C] + rr];
val = dense ? sheet[R][C] : sheet[cols[C] + rr];
switch(header) {
case 1: hdr[C] = C - r.s.c; break;
case 2: hdr[C] = cols[C]; break;
@ -91,7 +91,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) {
}
for (R = r.s.r + offset; R <= r.e.r; ++R) {
if ((rowinfo[R]||{}).hidden) continue;
var row = make_json_row(sheet, r, R, cols, header, hdr, o);
var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
}
out.length = outi;
@ -102,11 +102,9 @@ var qreg = /"/g;
function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, fs/*:number*/, rs/*:number*/, FS/*:string*/, o/*:Sheet2CSVOpts*/)/*:?string*/ {
var isempty = true;
var row/*:Array<string>*/ = [], txt = "", rr = encode_row(R);
var dense = sheet["!data"] != null;
var datarow = dense && sheet["!data"][R] || [];
for(var C = r.s.c; C <= r.e.c; ++C) {
if (!cols[C]) continue;
var val = dense ? datarow[C]: sheet[cols[C] + rr];
var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
if(val == null) txt = "";
else if(val.v != null) {
isempty = false;
@ -133,6 +131,7 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ {
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
var row = "", cols/*:Array<string>*/ = [];
o.dense = Array.isArray(sheet);
var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
var rowinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!rows"] || [];
for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
@ -144,6 +143,7 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ {
if(o.strip) row = row.replace(endregex,"");
if(row || (o.blankrows !== false)) out.push((w++ ? RS : "") + row);
}
delete o.dense;
return out.join("");
}
@ -160,13 +160,13 @@ function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
if(sheet == null || sheet["!ref"] == null) return [];
var r = safe_decode_range(sheet['!ref']), rr = "", cols/*:Array<string>*/ = [], C;
var cmds/*:Array<string>*/ = [];
var dense = sheet["!data"] != null;
var dense = Array.isArray(sheet);
for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
for(var R = r.s.r; R <= r.e.r; ++R) {
rr = encode_row(R);
for(C = r.s.c; C <= r.e.c; ++C) {
y = cols[C] + rr;
x = dense ? (sheet["!data"][R]||[])[C] : sheet[y];
x = dense ? (sheet[R]||[])[C] : sheet[y];
val = "";
if(x === undefined) continue;
else if(x.F != null) {
@ -191,11 +191,10 @@ function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet*/ {
var o = opts || {};
var dense = _ws ? (_ws["!data"] != null) : o.dense;
var dense = _ws ? Array.isArray(_ws) : o.dense;
if(DENSE != null && dense == null) dense = DENSE;
var offset = +!o.skipHeader;
var ws/*:Worksheet*/ = _ws || ({});
if(!_ws && dense) ws["!data"] = [];
var ws/*:Worksheet*/ = _ws || (dense ? ([]/*:any*/) : ({}/*:any*/));
var _R = 0, _C = 0;
if(ws && o.origin != null) {
if(typeof o.origin == 'number') _R = o.origin;
@ -214,20 +213,19 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet
if(_R == -1) { _R = 0; range.e.r = js.length - 1 + offset; }
}
var hdr/*:Array<string>*/ = o.header || [], C = 0;
var ROW = [];
js.forEach(function (JS, R/*:number*/) {
if(dense && !ws["!data"][_R + R + offset]) ws["!data"][_R + R + offset] = [];
if(dense) ROW = ws["!data"][_R + R + offset];
if(!ws[_R + R + offset]) ws[_R + R + offset] = [];
var ROW = ws[_R + R + offset];
keys(JS).forEach(function(k) {
if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
var v = JS[k];
var t = 'z';
var z = "";
var ref = dense ? "" : (encode_col(_C + C) + encode_row(_R + R + offset));
var ref = dense ? "" : encode_cell({c:_C + C,r:_R + R + offset});
var cell/*:Cell*/ = dense ? ROW[_C + C] : ws[ref];
if(v && typeof v === 'object' && !(v instanceof Date)){
if(dense) ROW[_C + C] = v;
else ws[ref] = v;
ws[ref] = v;
} else {
if(typeof v == 'number') t = 'n';
else if(typeof v == 'boolean') t = 'b';
@ -241,7 +239,8 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet
if(!cell) {
if(!dense) ws[ref] = cell = ({t:t, v:v}/*:any*/);
else ROW[_C + C] = cell = ({t:t, v:v}/*:any*/);
} else {
}
else {
cell.t = t; cell.v = v;
delete cell.w; delete cell.R;
if(z) cell.z = z;
@ -252,9 +251,9 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet
});
range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
var __R = encode_row(_R);
if(dense && !ws["!data"][_R]) ws["!data"][_R] = [];
if(dense && !ws[_R]) ws[_R] = [];
if(offset) for(C = 0; C < hdr.length; ++C) {
if(dense) ws["!data"][_R][C + _C] = {t:'s', v:hdr[C]};
if(dense) ws[_R][C + _C] = {t:'s', v:hdr[C]};
else ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
}
ws['!ref'] = encode_range(range);
@ -266,17 +265,18 @@ function json_to_sheet(js/*:Array<any>*/, opts)/*:Worksheet*/ { return sheet_add
function ws_get_cell_stub(ws/*:Worksheet*/, R, C/*:?number*/)/*:Cell*/ {
/* A1 cell address */
if(typeof R == "string") {
if(ws["!data"] != null) {
/* dense */
if(Array.isArray(ws)) {
var RC = decode_cell(R);
if(!ws["!data"][RC.r]) ws["!data"][RC.r] = [];
return ws["!data"][RC.r][RC.c] || (ws["!data"][RC.r][RC.c] = {t:'z'});
if(!ws[RC.r]) ws[RC.r] = [];
return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
}
return ws[R] || (ws[R] = {t:'z'});
}
/* cell address object */
if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
/* R and C are 0-based indices */
return ws_get_cell_stub(ws, encode_col(C||0) + encode_row(R));
return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
}
/* find sheet index for given name / validate index */

@ -10,6 +10,7 @@ function write_csv_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
var row/*:?string*/ = "", cols/*:Array<string>*/ = [];
o.dense = Array.isArray(sheet);
var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
var rowinfo/*:Array<RowInfo>*/ = o.skipHidden && sheet["!rows"] || [];
for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
@ -39,6 +40,7 @@ function write_html_stream(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*/) {
var footer = o.footer != null ? o.footer : HTML_END;
stream.push(header);
var r = decode_range(ws['!ref']);
o.dense = Array.isArray(ws);
stream.push(make_html_preamble(ws, r, o));
var R = r.s.r;
var end = false;
@ -76,16 +78,16 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
var rr = encode_row(r.s.r);
var cols/*:Array<string>*/ = [];
var counter = 0;
var dense = sheet["!data"] != null;
var dense = Array.isArray(sheet);
var R = r.s.r, C = 0;
var header_cnt = {};
if(dense && !sheet["!data"][R]) sheet["!data"][R] = [];
if(dense && !sheet[R]) sheet[R] = [];
var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
var rowinfo/*:Array<RowInfo>*/ = o.skipHidden && sheet["!rows"] || [];
for(C = r.s.c; C <= r.e.c; ++C) {
if(((colinfo[C]||{}).hidden)) continue;
cols[C] = encode_col(C);
val = dense ? sheet["!data"][R][C] : sheet[cols[C] + rr];
val = dense ? sheet[R][C] : sheet[cols[C] + rr];
switch(header) {
case 1: hdr[C] = C - r.s.c; break;
case 2: hdr[C] = cols[C]; break;
@ -106,7 +108,7 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
stream._read = function() {
while(R <= r.e.r) {
if ((rowinfo[R-1]||{}).hidden) continue;
var row = make_json_row(sheet, r, R, cols, header, hdr, o);
var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
++R;
if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
stream.push(row.row);

@ -10,8 +10,6 @@ XLSX.writeFileAsync = writeFileAsync;
XLSX.utils = utils;
XLSX.writeXLSX = writeSyncXLSX;
XLSX.writeFileXLSX = writeFileSyncXLSX;
XLSX.set_fs = set_fs;
XLSX.set_cptable = set_cptable;
XLSX.SSF = SSF;
if(typeof __stream !== "undefined") XLSX.stream = __stream;
if(typeof CFB !== "undefined") XLSX.CFB = CFB;

@ -7,6 +7,6 @@ The ecosystem demos were grouped by type in the new demo site:
- [Nuxt Content](https://docs.sheetjs.com/docs/demos/content#nuxtjs) is now part of "Content and Site Generation"
- [The new iOS app demo](https://docs.sheetjs.com/docs/demos/mobile#quasar) uses the Quasar Framework in a VueJS + Vite project to generate a native iOS app.
- [`vue3-table-lite` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demos/grid#vue3-table-lite) is now part of "Data Grids and UI"
- [`vue3-table-lite` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demo/grid#vue3-table-lite) is now part of "Data Grids and UI"
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

39
dist/cpexcel.d.ts generated vendored

@ -1,39 +0,0 @@
/* codepage.js (C) 2013-present SheetJS -- http://sheetjs.com */
// TypeScript Version: 2.2
/** Codepage index type (integer or string representation) */
export type CP$Index = number | string;
/* Individual codepage converter */
export interface CP$Conv {
enc: {[n: string]: number; };
dec: {[n: number]: string; };
}
/** Encode input type (string, array of characters, Buffer) */
export type CP$String = string | string[] | Uint8Array;
/** Encode output / decode input type */
export type CP$Data = string | number[] | Uint8Array;
/** General utilities */
export interface CP$Utils {
decode(cp: CP$Index, data: CP$Data): string;
encode(cp: CP$Index, data: CP$String, opts?: any): CP$Data;
hascp(n: number): boolean;
magic: {[cp: string]: string};
}
/* note: TS cannot export top-level indexer, hence default workaround */
export interface CP$Module {
/** Version string */
version: string;
/** Utility Functions */
utils: CP$Utils;
/** Codepage Converters */
[cp: number]: CP$Conv;
}
export const cptable: CP$Module;
export default cptable;

31
dist/xlsx.core.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.core.min.map generated vendored

File diff suppressed because one or more lines are too long

2266
dist/xlsx.extendscript.js generated vendored

File diff suppressed because it is too large Load Diff

34
dist/xlsx.full.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.full.min.map generated vendored

File diff suppressed because one or more lines are too long

18
dist/xlsx.mini.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.mini.min.map generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.zahl.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.zahl.mjs generated vendored

File diff suppressed because one or more lines are too long

4
dist/zahl.d.ts generated vendored

@ -1,4 +0,0 @@
/* zahl.d.ts (C) 2022-present SheetJS */
// TypeScript Version: 2.2
declare const XLSX_ZAHL_PAYLOAD: string;
export default XLSX_ZAHL_PAYLOAD;

BIN
formats.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 204 KiB

@ -5,6 +5,13 @@ var it = function(m,cb){console.log(" ".repeat(pdizzle) + m); ++pdizzle; if(cb)
it.skip = function(m,cb){};
var before = function(cb){if(cb) cb();};
var afterEach = function(cb){if(cb) cb();};
try {
new Buffer(925).copy(new Buffer(3072), 2048, 0, 925);
} catch(e) {
Buffer.prototype.copy = function(dst, dstStart, srcStart, srcEnd) {
for(var j = srcStart; j < srcEnd; ++j) dst[j + dstStart] = this[j + srcStart];
};
}
/* xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint mocha:true */

BIN
legend.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

@ -1 +0,0 @@
export { version } from "../";

6
modules/.gitignore vendored

@ -1,3 +1,9 @@
test_files
*.node.js
*.[Pp][Rr][Oo][Tt][Oo]
*.[Ii][Ww][Aa]
*.[Jj][Pp][Gg]
*.[Pp][Ll][Ii][Ss][Tt]
DocumentIdentifier
xlsx.zahl.*
src/numbers.ts

@ -1,61 +0,0 @@
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;
case "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":
case "algorithm":
case "start-key-generation":
case "key-derivation":
throw new Error("Unsupported ODS Encryption");
default:
if (opts && opts.WTF)
throw Rn;
}
}
function write_manifest(manifest) {
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("");
}
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) {
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("");
}
function write_meta_ods(wb, opts) {
return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>SheetJS ' + XLSX.version + "</meta:generator></office:meta></office:document-meta>";
}

@ -1,73 +0,0 @@
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
import { WorkBook, ParsingOptions } from '../';
import * as _XLSX from '../';
declare var XLSX: typeof _XLSX;
type RawData = any;
declare var XML_HEADER: string;
declare var xlmlregex: RegExp;
declare function parsexmltag(tag: string, skip_root?: boolean, skip_LC?: boolean): any;
declare function xlml_normalize(d: RawData): string;
type RDF = [string, string][];
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d: RawData, opts?: ParsingOptions) {
var str = xlml_normalize(d);
var Rn: RegExpExecArray | null;
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: RDF): 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): 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): 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: RDF): string {
var o: string[] = [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("");
}
/* TODO: pull properties */
function write_meta_ods(wb?: WorkBook, opts?: any): string {
return '<office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>';
}

@ -13,18 +13,14 @@ function rtf_to_sheet(d, opts) {
}
function rtf_to_sheet_str(str, opts) {
var o = opts || {};
var ws = {};
var dense = o.dense;
if (dense)
ws["!data"] = [];
var ws = o.dense ? [] : {};
var rows = str.match(/\\trowd[\s\S]*?\\row\b/g);
if (!rows)
throw new Error("RTF missing table");
var range = { s: { c: 0, r: 0 }, e: { c: 0, r: rows.length - 1 } };
var row = [];
rows.forEach(function(rowtf, R) {
if (dense)
row = ws["!data"][R] = [];
if (Array.isArray(ws))
ws[R] = [];
var rtfre = /\\[\w\-]+\b/g;
var last_index = 0;
var res;
@ -50,8 +46,8 @@ function rtf_to_sheet_str(str, opts) {
cell.w = cell.v;
cell.v = fuzzynum(cell.v);
}
if (dense)
row[C] = cell;
if (Array.isArray(ws))
ws[R][C] = cell;
else
ws[encode_cell({ r: R, c: C })] = cell;
}
@ -79,17 +75,15 @@ function sheet_to_rtf(ws, opts) {
if (!ws["!ref"])
return o[0] + "}";
var r = safe_decode_range(ws["!ref"]), cell;
var dense = ws["!data"] != null, row = [];
var dense = Array.isArray(ws);
for (var R = r.s.r; R <= r.e.r; ++R) {
o.push("\\trowd\\trautofit1");
for (var C = r.s.c; C <= r.e.c; ++C)
o.push("\\cellx" + (C + 1));
o.push("\\pard\\intbl");
if (dense)
row = ws["!data"][R] || [];
for (C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({ r: R, c: C });
cell = dense ? row[C] : ws[coord];
cell = dense ? (ws[R] || [])[C] : ws[coord];
if (!cell || cell.v == null && (!cell.f || cell.F)) {
o.push(" \\cell");
continue;

@ -1,6 +1,5 @@
import { WorkBook, WorkSheet, Range, CellObject, DenseSheet, SparseSheet, ParsingOptions, WritingOptions } from '../';
import { WorkBook, WorkSheet, Range, CellObject } from '../';
import type { utils } from "../";
type RawData = any;
declare var encode_cell: typeof utils.encode_cell;
declare var encode_range: typeof utils.encode_range;
@ -13,7 +12,7 @@ declare var has_buf: boolean;
declare function Base64_decode(s: string): string;
declare function fuzzynum(s: string): number;
function rtf_to_sheet(d: RawData, opts: ParsingOptions): WorkSheet {
function rtf_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
switch(opts.type) {
case 'base64': return rtf_to_sheet_str(Base64_decode(d), opts);
case 'binary': return rtf_to_sheet_str(d, opts);
@ -24,19 +23,16 @@ function rtf_to_sheet(d: RawData, opts: ParsingOptions): WorkSheet {
}
/* TODO: this is a stub */
function rtf_to_sheet_str(str: string, opts: ParsingOptions): WorkSheet {
function rtf_to_sheet_str(str: string, opts)/*:Worksheet*/ {
var o = opts || {};
// ESBuild issue 2375
var ws: WorkSheet = {} as WorkSheet;
var dense = o.dense;
if(dense) ws["!data"] = [];
var ws: WorkSheet = o.dense ? [] : ({}/*:any*/);
var rows = str.match(/\\trowd[\s\S]*?\\row\b/g);
if(!rows) throw new Error("RTF missing table");
var range: Range = {s: {c:0, r:0}, e: {c:0, r:rows.length - 1}};
var row: CellObject[] = [];
rows.forEach(function(rowtf, R) {
if(dense) row = (ws as DenseSheet)["!data"][R] = [] as CellObject[];
if(Array.isArray(ws)) ws[R] = [];
var rtfre = /\\[\w\-]+\b/g;
var last_index = 0;
var res;
@ -55,8 +51,8 @@ function rtf_to_sheet_str(str: string, opts: ParsingOptions): WorkSheet {
if(cell.v == "TRUE" || cell.v == "FALSE") { cell.v = cell.v == "TRUE"; cell.t = "b"; }
else if(!isNaN(fuzzynum(cell.v as string))) { cell.t = 'n'; if(o.cellText !== false) cell.w = cell.v as string; cell.v = fuzzynum(cell.v as string); }
if(dense) row[C] = cell;
else (ws as SparseSheet)[encode_cell({r:R, c:C})] = cell;
if(Array.isArray(ws)) ws[R][C] = cell;
else ws[encode_cell({r:R, c:C})] = cell;
}
payload = [];
break;
@ -72,26 +68,25 @@ function rtf_to_sheet_str(str: string, opts: ParsingOptions): WorkSheet {
return ws;
}
function rtf_to_workbook(d: RawData, opts: ParsingOptions): WorkBook {
function rtf_to_workbook(d/*:RawData*/, opts): WorkBook {
var wb: WorkBook = sheet_to_workbook(rtf_to_sheet(d, opts), opts);
wb.bookType = "rtf";
return wb;
}
/* TODO: this is a stub */
function sheet_to_rtf(ws: WorkSheet, opts: WritingOptions): string {
function sheet_to_rtf(ws: WorkSheet, opts): string {
var o: string[] = ["{\\rtf1\\ansi"];
if(!ws["!ref"]) return o[0] + "}";
var r = safe_decode_range(ws['!ref']), cell: CellObject;
var dense = ws["!data"] != null, row: CellObject[] = [];
var dense = Array.isArray(ws);
for(var R = r.s.r; R <= r.e.r; ++R) {
o.push("\\trowd\\trautofit1");
for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
o.push("\\pard\\intbl");
if(dense) row = (ws as DenseSheet)["!data"][R] || ([] as CellObject[])
for(C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? row[C] : (ws as SparseSheet)[coord];
cell = dense ? (ws[R]||[])[C]: ws[coord];
if(!cell || cell.v == null && (!cell.f || cell.F)) { o.push(" \\cell"); continue; }
o.push(" " + (cell.w || (format_cell(cell), cell.w) || "").replace(/[\r\n]/g, "\\par "));
o.push("\\cell");
@ -100,3 +95,4 @@ function sheet_to_rtf(ws: WorkSheet, opts: WritingOptions): string {
}
return o.join("") + "}";
}

@ -61,7 +61,7 @@ function write_BrtBeginEsmdb(cnt: number, cm: boolean): RawData {
}
/* [MS-XLSB] 2.1.7.34 Metadata */
function parse_xlmeta_bin(data: RawData, name: string, _opts?: ParseXLMetaOptions): XLMeta {
function parse_xlmeta_bin(data, name: string, _opts?: ParseXLMetaOptions): XLMeta {
var out: XLMeta = { Types: [], Cell: [], Value: [] };
var opts = _opts || {};
var state: number[] = [];

@ -71,7 +71,7 @@ function parse_xlmeta_xml(data, name, opts) {
lastmeta.offsets.push(+y.i);
break;
default:
if (!pass && (opts == null ? void 0 : opts.WTF))
if (!pass && opts.WTF)
throw new Error("unrecognized " + y[0] + " in metadata");
}
return x;

@ -63,7 +63,7 @@ function parse_xlmeta_xml(data: string, name: string, opts?: ParseXLMetaOptions)
lastmeta.offsets.push(+y.i);
break;
default: if(!pass && opts?.WTF) throw new Error('unrecognized ' + y[0] + ' in metadata');
default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in metadata');
}
return x;
});

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

@ -2,32 +2,24 @@ LIBFILES=src/types.ts
#LIBFILES=$(wildcard src/*.ts)
TSFILES=$(wildcard *.ts)
ENTRIES=$(subst .ts,.js,$(TSFILES))
CC=esbuild@0.14.14
BAREJS=04_base64.js 32_odmanrdf.js 45_rtf.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js 83_numbers.js
BAREJS=04_base64.js 45_rtf.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js 83_numbers.js
.PHONY: all
all: bits xlsx.zahl.js
all: $(ENTRIES) xlsx.zahl.js
.PHONY: lint
lint: $(filter-out $(wildcard *.node.ts),$(TSFILES))
tsc --strict --noEmit $^
.PHONY: bits
bits: $(ENTRIES)
xlsx.zahl.js: test.numbers
xlsx.zahl.js: test.numbers reframe.node.js
bash -c ./reframe.sh
$(BAREJS): %.js: %.ts $(LIBFILES)
npx $(CC) $< --outfile=$@ --platform=browser --target=es5
npx esbuild@0.14.14 $< --outfile=$@ --platform=browser --target=es5
%.node.js: %.node.ts $(LIBFILES) src/numbers.ts
npx $(CC) $< --bundle --external:xlsx --outfile=$@ --platform=node
npx esbuild@0.14.14 $< --bundle --external:xlsx --outfile=$@ --platform=node
sed -i '' 's/ts-node/node/g' $@ || sed -i'' 's/ts-node/node/g' $@ || { echo "sed failed"; exit 1; }
%.js: %.ts $(LIBFILES)
npx $(CC) $< --bundle --outfile=$@ --platform=browser --format=iife --global-name=$* --target=es5
npx esbuild@0.14.14 $< --bundle --outfile=$@ --platform=browser --format=iife --global-name=$* --target=es5
src/numbers.ts: 83_numbers.ts
cat $< | sed 's/^\/\/<<//g' > $@

631
modules/reframe.node.ts Normal file

@ -0,0 +1,631 @@
/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
import { decompress_iwa_file, compress_iwa_file, u8concat, parse_iwa_file, write_iwa_file, varint_to_i32, parse_shallow, write_shallow, u8str, stru8, IWAArchiveInfo, parse_TSP_Reference, write_varint49, u8contains, u8_to_dataview, write_new_storage } from "./src/numbers";
import { read, writeFile, utils, find, CFB$Entry, CFB$Container } from 'cfb';
var f = process.argv[2]; var o = process.argv[3];
var cfb = read(f, {type: "file"});
var nuevo = utils.cfb_new();
interface DependentInfo {
deps: number[];
location: string;
type: number;
}
var dependents: {[x:number]: DependentInfo} = {};
var indices: number[] = [];
/* First Pass: reframe, clean up junk, collect message space */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
/* blank all plist files */
if(fi.name.match(/\.plist/)) {
console.error(`Blanking plist ${fi.name}`);
fi.content = new Uint8Array([
0x62, 0x70, 0x6c, 0x69, 0x73, 0x74, 0x30, 0x30, 0xd0, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x01, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09, 0x0a
]);
utils.cfb_add(nuevo, row[1], fi.content);
return;
}
if(fi.type != 2) return;
/* Remove other metadata */
if(!fi.name.match(/\.iwa/)) {
if(fi.name.match(/Sh33tJ5/)) return;
console.error(`Removing file ${fi.name}`);
return;
}
/* Reframe .iwa files */
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content as Uint8Array);
var new_content = compress_iwa_file(raw1);
var raw2 = decompress_iwa_file(new_content);
for(var i = 0; i < raw1.length; ++i) if(raw1[i] != raw2[i]) throw new Error(`${fi.name} did not properly roundtrip`);
var x = parse_iwa_file(raw2);
x.forEach(ia => {
ia.messages.forEach(m => {
delete m.meta[2];
delete m.meta[4];
delete m.meta[5]; // extremely slow open if deleted
for(var j = 6; j < m.meta.length; ++j) delete m.meta[j];
});
});
x.forEach(packet => {
indices.push(packet.id);
dependents[packet.id] = { deps: [], location: fp, type: varint_to_i32(packet.messages[0].meta[1][0].data) };
});
var y = write_iwa_file(x);
for(var i = 0; i < raw1.length; ++i) if(y[i] != raw1[i]) { console.log(fi.name, i, raw1[i], y[i]); break; }
var raw3 = compress_iwa_file(y);
fi.content = raw3; fi.size = fi.content.length;
// utils.cfb_add(nuevo, row[1], fi.content);
});
indices.sort((x,y) => x-y);
var indices_varint: Array<[number, Uint8Array]> = indices.filter(x => x > 1).map(x => [x, write_varint49(x)] );
/* Second pass: build dependency map */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi?.name?.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
x.forEach(ia => {
ia.messages.forEach(m => {
indices_varint.forEach(([i, vi]) => {
if(ia.messages.some(mess => varint_to_i32(mess.meta[1][0].data) != 11006 && u8contains(mess.data, vi))) {
dependents[i].deps.push(ia.id);
}
})
});
});
});
var deletables = [];
function delete_message(id: number, cfb: CFB$Container) {
var dep = dependents[id];
if(dep?.deps?.length > 0) return console.error(`Message ${id} has dependents ${dep.deps}`);
//delete dependents[id];
indices = indices.filter(x => x != id);
/* TODO: this really should be a forward map */
indices.map(i => dependents[i]).filter(x => x).forEach(dep => {
dep.deps = dep.deps.filter(x => x != id);
});
if(deletables.indexOf(id) == -1) deletables.push(id);
}
function gc(cfb: CFB$Container) {
deletables.forEach(id => {
var dep = dependents[id];
var entry = find(cfb, dep.location);
var x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
/* remove packet */
console.log(`Removing packet ${id} ${dependents[id]?.type || "NaN"}`);
for(var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == id) { x.splice(xi,1); --xi; }
}
delete dependents[id];
entry.content = compress_iwa_file(write_iwa_file(x));
entry.size = entry.content.length;
});
deletables = [];
}
function delete_ref(dmeta: ReturnType<typeof parse_shallow>, j: number, me: number) {
if(!dmeta) return;
if(dmeta[j]) dmeta[j].forEach(pi => {
var target = parse_TSP_Reference(pi.data);
dependents[target].deps = dependents[target].deps.filter(x => x != me);
if(dependents[target].deps.length == 0) delete_message(target, cfb);
});
delete dmeta[j];
}
function shake() {
var done = false;
while(!done) {
done = true;
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(fi.name.match(/\.plist/)) return;
if(!fi.name.match(/\.iwa/)) return;
var old_content = fi.content;
var raw1 = decompress_iwa_file(old_content as Uint8Array);
var x = parse_iwa_file(raw1);
(()=>{
for(var i = 0; i < x.length; ++i) {
var w = x[i];
var type = varint_to_i32(w.messages[0].meta[1][0].data);
if(w.id > 10000 && (!dependents[w.id] || !dependents[w.id]?.deps?.length)) {
console.log(`Deleting orphan ${fp} ${w.id}`);
delete_message(w.id, cfb);
done = false;
}
}
})();
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
//fi.content = raw3;
});
gc(cfb);
}
}
/* Third pass: trim messages */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi?.name?.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
trim(x, fi);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
fi.content = raw3;
});
gc(cfb);
shake();
function mutate_row(tri: ReturnType<typeof parse_shallow>) {
if(!tri[6]?.[0] || !tri[7]?.[0]) throw "Mutation only works on post-BNC storages!";
var wide_offsets = tri[8]?.[0]?.data && varint_to_i32(tri[8][0].data) > 0 || false;
var width = wide_offsets ? 4 : 1;
var dv = u8_to_dataview(tri[7][0].data);
var old_sz = 0, sz = 0;
for(var i = 0; i < tri[7][0].data.length / 2; ++i) {
sz = dv.getUint16(i*2, true);
if(sz < 65535) old_sz = sz;
if(old_sz) break;
}
if(!old_sz) old_sz = sz = tri[6][0].data.length;
var start = 0,
preamble = tri[6][0].data.slice(0, start),
intramble = tri[6][0].data.slice(start, old_sz * width),
postamble = tri[6][0].data.slice(old_sz * width);
var sst = []; sst[69] = "SheetJS";
//intramble = write_new_storage({t:"n", v:12345}, sst);
//intramble = write_new_storage({t:"b", v:false}, sst);
intramble = write_new_storage({t:"s", v:"SheetJS"}, sst);
tri[6][0].data = u8concat([preamble, intramble, postamble]);
var delta = intramble.length / width - old_sz;
for(var i = 0; i < tri[7][0].data.length / 2; ++i) {
sz = dv.getUint16(i*2, true);
if(sz < 65535 && sz > start) dv.setUint16(i*2, sz + delta, true);
}
}
/* Find first sheet -> first table -> add "SheetJS" to data store and set cell A1 */
(function() {
var entry = find(cfb, dependents[1].location);
var x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
var docroot: IWAArchiveInfo;
for(var xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == 1) docroot = packet;
}
var sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[1][0].data);
entry = find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
sheetrootref = parse_TSP_Reference(parse_shallow(docroot.messages[0].data)[2][0].data);
entry = find(cfb, dependents[sheetrootref].location);
x = parse_iwa_file(decompress_iwa_file(entry.content as Uint8Array));
for(xi = 0; xi < x.length; ++xi) {
var packet = x[xi];
if(packet.id == sheetrootref) docroot = packet;
}
var pb = parse_shallow(docroot.messages[0].data);
{
var store = parse_shallow(pb[4][0].data);
{
/* ref to string table */
var sstref = parse_TSP_Reference(store[4][0].data);
(() => {
var sentry = find(cfb, dependents[sstref].location);
var sx = parse_iwa_file(decompress_iwa_file(sentry.content as Uint8Array));
var sstroot: IWAArchiveInfo;
for(var sxi = 0; sxi < sx.length; ++sxi) {
var packet = sx[sxi];
if(packet.id == sstref) sstroot = packet;
}
var sstdata = parse_shallow(sstroot.messages[0].data);
{
if(!sstdata[3]) sstdata[3] = [];
var newsst: ReturnType<typeof parse_shallow> = [];
newsst[1] = [ { type: 0, data: write_varint49(69) } ];
newsst[2] = [ { type: 0, data: write_varint49(1) } ];
newsst[3] = [ { type: 2, data: stru8("SheetJS") } ];
sstdata[3].push({type: 2, data: write_shallow(newsst)});
}
sstroot.messages[0].data = write_shallow(sstdata);
var sy = write_iwa_file(sx);
var raw3 = compress_iwa_file(sy);
sentry.content = raw3; sentry.size = sentry.content.length;
})();
var tile = parse_shallow(store[3][0].data); // TileStorage
{
var t = tile[1][0];
delete tile[2];
var tl = parse_shallow(t.data); // first Tile
{
var tileref = parse_TSP_Reference(tl[2][0].data);
(() => {
var tentry = find(cfb, dependents[tileref].location);
var tx = parse_iwa_file(decompress_iwa_file(tentry.content as Uint8Array));
var tileroot: IWAArchiveInfo;
for(var sxi = 0; sxi < tx.length; ++sxi) {
var packet = tx[sxi];
if(packet.id == tileref) tileroot = packet;
}
// .TST.Tile
var tiledata = parse_shallow(tileroot.messages[0].data);
{
tiledata[5].forEach((row, R) => {
var tilerow = parse_shallow(row.data);
if(R == 0) mutate_row(tilerow);
row.data = write_shallow(tilerow);
})
}
tileroot.messages[0].data = write_shallow(tiledata);
var ty = write_iwa_file(tx);
var raw3 = compress_iwa_file(ty);
tentry.content = raw3; tentry.size = tentry.content.length;
//throw dependents[tileref];
})();
}
t.data = write_shallow(tl);
}
store[3][0].data = write_shallow(tile);
}
pb[4][0].data = write_shallow(store);
}
docroot.messages[0].data = write_shallow(pb);
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
entry.content = raw3; entry.size = entry.content.length;
})();
//console.log(indices.map(i => [i, dependents[i]]).filter(([i, dep]) => dep?.deps && (dep.deps.length == 0 || dep.deps.length == 1 && dep.deps[0] == 1)));
/* Last pass: fix metadata and commit to new file */
cfb.FileIndex.map((fi, idx): [CFB$Entry, string] => ([fi, cfb.FullPaths[idx]])).forEach(row => {
var fi = row[0], fp = row[1];
if(!fi?.name?.match(/\.iwa/)) return;
var x = parse_iwa_file(decompress_iwa_file(fi.content as Uint8Array));
if(fi.name.match(/^Metadata.iwa$/)) {
x.forEach((w: IWAArchiveInfo) => {
var type = varint_to_i32(w.messages[0].meta[1][0].data);
if(type != 11006) return;
var package_metadata = parse_shallow(w.messages[0].data);
[3,11].forEach(x => {
if(!package_metadata[x]) return;
for(var pmj = 0; pmj < package_metadata[x].length; ++pmj) {
var ci = package_metadata[x][pmj];
var comp = parse_shallow(ci.data);
var compid = varint_to_i32(comp[1][0].data);
if(!dependents[compid]) {
console.log(`Removing ${compid} (${u8str(comp[2][0].data)} -> ${comp[3]?.[0] && u8str(comp[3][0].data) || ""}) from metadata`);
package_metadata[x].splice(pmj, 1);
--pmj; continue;
}
[13, 14, 15].forEach(j => delete comp[j]);
ci.data = write_shallow(comp);
}
});
[2, 4, 6, 8, 9].forEach(j => delete package_metadata[j]);
w.messages[0].data = write_shallow(package_metadata);
});
}
var y = write_iwa_file(x);
var raw3 = compress_iwa_file(y);
fi.content = raw3;
if(x.length == 0) {
console.log(`Deleting ${fi.name} (no messages)`);
return;
}
if(fi.name.match(/^Metadata.iwa$/)) {
console.error(`Reframing iwa ${fi.name} (${fi.size} -> ${fi.content.length})`);
fi.size = fi.content.length;
utils.cfb_add(nuevo, row[1], fi.content);
} else {
console.error(`Reframing iwa ${fi.name} (${fi.size} -> ${fi.content.length})`);
fi.size = fi.content.length;
utils.cfb_add(nuevo, row[1], fi.content);
}
});
writeFile(nuevo, o, { fileType: "zip", compression: true });
function process_root(dmeta: ReturnType<typeof parse_shallow>, id: number) {
var tsa = parse_shallow(dmeta[8][0].data);
{
var tsk = parse_shallow(tsa[1][0].data);
{
[7, 8, 14].forEach(j => delete_ref(tsk, j, id)); // annotation_author_storage
[4, 9, 10, 11, 12, 15, 16, 17].forEach(j => delete tsk[j]);
}
tsa[1][0].data = write_shallow(tsk);
[5, 6, 7, 10, 11, 12, 13].forEach(j => delete_ref(tsa, j, 1));
[3, 8, 9, 14, 15, 16].forEach(j => delete tsa[j]);
}
dmeta[8][0].data = write_shallow(tsa);
}
function process_sheet(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[3, 4, 5, 6, 7, 8, 10, 11, 12, 13, 14, 20, 21, 23, 24].forEach(j => delete dmeta[j]);
[15, 16, 17, 18, 19, 22].forEach(j => delete_ref(dmeta, j, id));
}
function process_TST_TableInfoArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[7, 8, 9, 10, 14, 16].forEach(j => delete dmeta[j]);
[3, 4, 5, 6, 15, 17].forEach(j => delete_ref(dmeta, j, id));
}
function process_TST_TableModelArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[90, 91, 92].forEach(j => delete dmeta[j]);
[34, 35, 38, 49].forEach(j => delete_ref(dmeta, j, id));
[60, 61, 62, 63, 64, 65, 66, 67, 68, 69].forEach(j => delete_ref(dmeta, j, id));
[70].forEach(j => delete dmeta[j]);
[71, 72, 73, 74, 75, 76, 77, 78, 79, 80].forEach(j => delete_ref(dmeta, j, id));
[85, 86, 87, 88, 89].forEach(j => delete_ref(dmeta, j, id));
var store = parse_shallow(dmeta[4][0].data);
{ // .TST.DataStore
[12, 13, 15, 16, 17, 18, 19, 20, 21, 22].forEach(j => delete_ref(store, j, id));
var tiles = parse_shallow(store[3][0].data);
{ // .TST.TileStorage
//console.log(parse_TSP_Reference(parse_shallow(tiles[1][0].data)[2][0].data));
}
store[3][0].data = write_shallow(tiles);
// 4 -> sst
// 17 -> rsst
}
dmeta[4][0].data = write_shallow(store);
}
function process_TN_ThemeArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[2].forEach(j => delete_ref(dmeta, j, id));
var tssta = parse_shallow(dmeta[1][0].data);
{
//Object.keys(tssta).filter(x => +x >= 100).forEach(j => delete tssta[j]);
}
dmeta[1][0].data = write_shallow(tssta);
}
function process_TSS_StylesheetArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[7, 8, 9, 10, 11, 12].forEach(j => {
if(!dmeta[j]) return;
var vstyle = parse_shallow(dmeta[j][0].data);
delete_ref(vstyle, 1, id);
if(vstyle[2]) vstyle[2].forEach(ised => {
var ise = parse_shallow(ised.data);
delete_ref(ise, 2, id);
})
if(vstyle[3]) vstyle[3].forEach(sced => {
var sce = parse_shallow(sced.data);
delete_ref(sce, 2, id);
delete_ref(sce, 1, id);
})
delete dmeta[j];
});
dmeta[4] = [{data: write_varint49(0), type: 0}];
[3].forEach(j => delete_ref(dmeta, j, id));
dmeta[5]?.forEach(pi => {
var sce = parse_shallow(pi.data);
delete_ref(sce, 1, id);
delete_ref(sce, 2, id);
}); delete dmeta[5];
var deleted_styles = [];
if(dmeta[2]) for(var pij = 0; pij < dmeta[2].length; ++pij) {
var ise = parse_shallow(dmeta[2][pij].data);
var sname = u8str(ise[1][0].data);
if(sname.match(/_\d*$/) || sname.match(/^(captions|chart|image|movie|stickyComment)/) || sname.match(/evel[2-5]|pivot|liststyle/) ) {
var deletedid = parse_TSP_Reference(ise[2][0].data);
console.log(`Deleting style ${sname} [${deletedid}]`);
deleted_styles.push(deletedid);
delete_ref(ise, 2, id);
dmeta[2].splice(pij,1);
--pij; continue;
} else console.log(`Keeping style ${sname}`)
}
if(dmeta[1]) for(var sj = 0; sj < dmeta[1].length; ++sj) {
var dsid = parse_TSP_Reference(dmeta[1][sj].data);
if(deleted_styles.indexOf(dsid) > -1) {
//console.log(`Really deleting style ${dsid}`);
dependents[dsid].deps = dependents[dsid].deps.filter(x => x != id);
if(dependents[dsid].deps.length == 0) delete_message(dsid, cfb);
dmeta[1].splice(sj, 1); --sj; continue;
}
}
[6].forEach(j => delete dmeta[j]);
}
function process_TSCE_CalculationEngineArchive(dmeta: ReturnType<typeof parse_shallow>, id: number) {
[3, 12, 14, 15].forEach(j => delete_ref(dmeta, j, id));
[1, 4, 5, 6, 7, 9, 10, 11, 13, 16, 17, 18].forEach(i => delete dmeta[i]);
var dta = parse_shallow(dmeta[2][0].data);
delete dta[5]; delete dta[2]; delete dta[4];
delete dta[1]; delete dta[3]; delete_ref(dta, 6, id);
dmeta[2][0].data = write_shallow(dta);
}
function trim(x: IWAArchiveInfo[], fi: CFB$Entry) {
for(var i = 0; i < x.length; ++i) {
var w = x[i];
var type = varint_to_i32(w.messages[0].meta[1][0].data);
var dmeta = parse_shallow(w.messages[0].data);
switch(type) {
case 222: // .TSK.CustomFormatListArchive
case 601: // .TSA.FunctionBrowserStateArchive
x.splice(i, 1); --i; continue;
case 3047: break; // .TSD.GuideStorageArchive
case 205: {
} break; // .TSK.TreeNode
case 1: { // .TN.DocumentArchive
process_root(dmeta, w.id);
} break;
case 2: { // .TN.SheetArchive
process_sheet(dmeta, w.id);
} break;
case 6000: { // .TST.TableInfoArchive
process_TST_TableInfoArchive(dmeta, w.id);
} break;
case 6001: { // .TST.TableModelArchive
process_TST_TableModelArchive(dmeta, w.id)
} break;
case 401: { // .TSS.StylesheetArchive
process_TSS_StylesheetArchive(dmeta, w.id);
break;
}
case 11011: { // .TSP.DocumentMetadata
[1, 3].forEach(i => delete dmeta[i]);
} break;
case 6002: {
//process_TST_Tile(dmeta, w.id);
} break; // .TST.Tile
case 6005: break; // .TST.TableDataList
case 6006: break; // .TST.HeaderStorageBucket
case 2001: break; // .TSWP.StorageArchive
case 12009: process_TN_ThemeArchive(dmeta, w.id); break; // .TN.ThemeArchive
case 3097: break; // .TSD.StandinCaptionArchive
case 4000: process_TSCE_CalculationEngineArchive(dmeta, w.id); break; // .TSCE.CalculationEngineArchive
case 4003: break; // .TSCE.NamedReferenceManagerArchive
case 4004: break; // .TSCE.TrackedReferenceStoreArchive
case 4008: { // .TSCE.FormulaOwnerDependenciesArchive
[11].forEach(j => delete_ref(dmeta, j, w.id));
[3].forEach(i => delete dmeta[i]);
} break;
case 4009: { // .TSCE.CellRecordTileArchive
delete dmeta[4];
} break;
case 6267: { // .TST.ColumnRowUIDMapArchive
// console.log("CRUIDMA", dmeta[1]?.[0], dmeta[2]?.[0], dmeta[3]?.[0]);
//[1,2,3,4,5,6].forEach(j => delete dmeta[j]); break;
} break;
case 6366: break; // .TST.HeaderNameMgrArchive
case 6204: break; // .TST.HiddenStateFormulaOwnerArchive
case 6220: break; // .TST.FilterSetArchive
case 6305: break; // .TST.StrokeSidecarArchive
case 6316: break; // .TST.SummaryModelArchive
case 6317: break; // .TST.SummaryCellVendorArchive
case 6318: break; // .TST.CategoryOrderArchive
case 6372: break; // .TST.CategoryOwnerRefArchive
case 6373: break; // .TST.GroupByArchive
case 2043: [2,3,4].forEach(j => delete dmeta[j]); break; // .TSWP.NumberAttachmentArchive
case 5020: // .TSCH.ChartStylePreset
//[1,2,3,4,5,6].forEach(j => delete_ref(dmeta, j, w.id)); // some part of this is required to auto-save
Object.keys(dmeta).filter(x => +x >= 10000).forEach(j => delete dmeta[j]);
break;
case 5022: // .TSCH.ChartStyleArchive
case 5024: // .TSCH.LegendStyleArchive
case 5026: // .TSCH.ChartAxisStyleArchive
case 5028: // .TSCH.ChartSeriesStyleArchive
case 5030: // .TSCH.ReferenceLineStyleArchive
Object.keys(dmeta).filter(x => +x >= 10000).forEach(j => delete dmeta[j]);
break;
case 2021: break;
case 2022: [10,11,12].forEach(j => delete dmeta[j]); break; // .TSWP.ParagraphStyleArchive
case 2023: [10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25].forEach(j => delete dmeta[j]); break; // .TSWP.ListStyleArchive
case 3016: [10,11].forEach(j => delete dmeta[j]); break; // .TSD.MediaStyleArchive
case 2025: /* [10,11].forEach(j => delete dmeta[j]); */ break; // .TSWP.ShapeStyleArchive
case 6003: /* [10,11].forEach(j => delete dmeta[j]); */ break; // .TST.TableStyleArchive
case 6004: /* [10,11].forEach(j => delete dmeta[j]); */ break; // .TST.CellStyleArchive
case 10024: [10,11,12].forEach(j => delete dmeta[j]); break; // .TN.DropCapStyleArchive
case 12050: /* [2,3].forEach(j => delete dmeta[j]); */ break; // .TN.SheetStyleArchive
case 3045: break; // .TSD.CanvasSelectionArchive
case 6008: {
[1].forEach(j => delete dmeta[j]);
[2].forEach(j => delete_ref(dmeta, j, w.id));
// deleting 3 -> -[TSWPLayoutManager initWithStorage:owner:] /Library/Caches/com.apple.xbs/Sources/iWorkDependenciesMacOS/iWorkDependenciesMacOS-7032.0.145/shared/text/TSWPLayoutManager.mm:82 Cannot initialize with a nil storage.
} break; // .TST.TableStylePresetArchive
case 6247: {
[ 10, 11, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35 ].forEach(j => delete_ref(dmeta, j, w.id));
} break; // .TST.TableStyleNetworkArchive
case 210: { // .TSK.ViewStateArchive
[2, 3].forEach(i => delete dmeta[i]);
} break;
case 12026: { // .TN.UIStateArchive
delete dmeta[13];
} break;
case 219: delete dmeta[1]; break; // .DocumentSelectionArchive
case 12028: break; // .TN.SheetSelectionArchive
case 3061: { // .TSD.DrawableSelectionArchive
[3].forEach(j => delete_ref(dmeta, j, w.id));
} break;
case 3091: { // .TSD.FreehandDrawingToolkitUIState
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15].forEach(i => delete dmeta[i]);
} break;
/* Metadata.iwa */
case 11006: { // .TSP.PackageMetadata
[10].forEach(j => delete_ref(dmeta, j, w.id));
} break;
case 11014: // .TSP.DataMetadata
[1].forEach(j => delete dmeta[j]);
break;
case 11015: // .TSP.DataMetadataMap
dmeta?.[1]?.forEach((r, idx) => {
var ddmeta = parse_shallow(r.data);
[2].forEach(j => delete_ref(ddmeta, j, w.id));
});
delete dmeta[1];
dmeta.length = 0;
break;
/* AnnotationAuthorStorage.iwa */
case 213: break; // TSK.AnnotationAuthorStorageArchive
default:
console.log("!!", fi.name, type, w.id, w.messages.length);
}
w.messages[0].data = write_shallow(dmeta);
}
}

@ -2,13 +2,13 @@
set -eo pipefail
INF=${1:-test.numbers}
OUTF=${2:-reframed.numbers}
make reframe.node.js
node reframe.node.js "$INF" "$OUTF"
chmod a+w "$OUTF"
cp "$INF" "$OUTF"
chmod a-w "$OUTF"
sleep 0.1
# open "$OUTF"
unzip -l "$OUTF"
(base64 "$OUTF" || base64 -i "$OUTF") | tr -d '\n' > xlsx.zahl.js
base64 "$OUTF" | tr -d '\n' > xlsx.zahl.js
sed -i.bak 's/^/var XLSX_ZAHL_PAYLOAD = "/g;s/$/";\n/g' xlsx.zahl.js
cp xlsx.zahl.js xlsx.zahl.mjs
cat >> xlsx.zahl.js <<EOF

Binary file not shown.

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.19.3",
"version": "0.18.10",
"author": "sheetjs",
"description": "SheetJS Spreadsheet data parser and writer",
"keywords": [
@ -28,47 +28,22 @@
"exports": {
".": {
"import": "./xlsx.mjs",
"require": "./xlsx.js",
"types": "./types/index.d.ts"
"require": "./xlsx.js"
},
"./xlsx.mjs": {
"import": "./xlsx.mjs",
"types": "./types/index.d.ts"
},
"./xlsx.js": {
"require": "./xlsx.js",
"types": "./types/index.d.ts"
"import": "./xlsx.mjs"
},
"./dist/xlsx.zahl": {
"import": "./dist/xlsx.zahl.mjs",
"require": "./dist/xlsx.zahl.js",
"types": "./dist/zahl.d.ts"
},
"./dist/xlsx.zahl.mjs": {
"import": "./dist/xlsx.zahl.mjs",
"types": "./dist/zahl.d.ts"
},
"./dist/xlsx.zahl.js": {
"require": "./dist/xlsx.zahl.js",
"types": "./dist/zahl.d.ts"
"require": "./dist/xlsx.zahl.js"
},
"./dist/cpexcel": {
"import": "./dist/cpexcel.full.mjs",
"require": "./dist/cpexcel.js",
"types": "./dist/cpexcel.d.ts"
},
"./dist/cpexcel.js": {
"require": "./dist/cpexcel.js",
"types": "./dist/cpexcel.d.ts"
"require": "./dist/cpexcel.js"
},
"./dist/cpexcel.full": {
"import": "./dist/cpexcel.full.mjs",
"require": "./dist/cpexcel.js",
"types": "./dist/cpexcel.d.ts"
},
"./dist/cpexcel.full.mjs": {
"import": "./dist/cpexcel.full.mjs",
"types": "./dist/cpexcel.d.ts"
"require": "./dist/cpexcel.js"
}
},
"browser": {
@ -109,7 +84,7 @@
},
"repository": {
"type": "git",
"url": "https://git.sheetjs.com/SheetJS/sheetjs"
"url": "git://github.com/SheetJS/sheetjs.git"
},
"scripts": {
"pretest": "npm run lint",
@ -138,7 +113,7 @@
},
"homepage": "https://sheetjs.com/",
"bugs": {
"url": "https://git.sheetjs.com/SheetJS/sheetjs/issues"
"url": "https://github.com/SheetJS/sheetjs/issues"
},
"license": "Apache-2.0",
"engines": {

@ -1,610 +0,0 @@
#!/usr/bin/env -S deno run -A
/*! otorp (C) 2021-present SheetJS -- http://sheetjs.com */
import { resolve } from "https://deno.land/std@0.171.0/path/mod.ts";
import { TerminalSpinner } from "https://deno.land/x/spinners/mod.ts";
// #region util.ts
var u8_to_dataview = (array: Uint8Array): DataView => new DataView(array.buffer, array.byteOffset, array.byteLength);
var u8str = (u8: Uint8Array): string => new TextDecoder().decode(u8);
var u8concat = (u8a: Uint8Array[]): Uint8Array => {
var len = u8a.reduce((acc: number, x: Uint8Array) => acc + x.length, 0);
var out = new Uint8Array(len);
var off = 0;
u8a.forEach(u8 => { out.set(u8, off); off += u8.length; });
return out;
};
var indent = (str: string, depth: number /* = 1 */): string => str.split(/\n/g).map(x => x && " ".repeat(depth) + x).join("\n");
function u8indexOf(u8: Uint8Array, data: string | number | Uint8Array, byteOffset?: number): number {
//if(Buffer.isBuffer(u8)) return u8.indexOf(data, byteOffset);
if(typeof data == "number") return u8.indexOf(data, byteOffset);
var l = byteOffset;
if(typeof data == "string") {
outs: while((l = u8.indexOf(data.charCodeAt(0), l)) > -1) {
++l;
for(var j = 1; j < data.length; ++j) if(u8[l+j-1] != data.charCodeAt(j)) continue outs;
return l - 1;
}
} else {
outb: while((l = u8.indexOf(data[0], l)) > -1) {
++l;
for(var j = 1; j < data.length; ++j) if(u8[l+j-1] != data[j]) continue outb;
return l - 1;
}
}
return -1;
}
// #endregion
// #region proto.ts
type Ptr = [number];
/** Parse an integer from the varint that can be exactly stored in a double */
function parse_varint49(buf: Uint8Array, ptr?: Ptr): number {
var l = ptr ? ptr[0] : 0;
var usz = buf[l] & 0x7F;
varint: if(buf[l++] >= 0x80) {
usz |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint;
usz |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint;
usz |= (buf[l] & 0x7F) << 21; if(buf[l++] < 0x80) break varint;
usz += (buf[l] & 0x7F) * Math.pow(2, 28); ++l; if(buf[l++] < 0x80) break varint;
usz += (buf[l] & 0x7F) * Math.pow(2, 35); ++l; if(buf[l++] < 0x80) break varint;
usz += (buf[l] & 0x7F) * Math.pow(2, 42); ++l; if(buf[l++] < 0x80) break varint;
}
if(ptr) ptr[0] = l;
return usz;
}
function write_varint49(v: number): Uint8Array {
var usz = new Uint8Array(7);
usz[0] = (v & 0x7F);
var L = 1;
sz: if(v > 0x7F) {
usz[L-1] |= 0x80; usz[L] = (v >> 7) & 0x7F; ++L;
if(v <= 0x3FFF) break sz;
usz[L-1] |= 0x80; usz[L] = (v >> 14) & 0x7F; ++L;
if(v <= 0x1FFFFF) break sz;
usz[L-1] |= 0x80; usz[L] = (v >> 21) & 0x7F; ++L;
if(v <= 0xFFFFFFF) break sz;
usz[L-1] |= 0x80; usz[L] = ((v/0x100) >>> 21) & 0x7F; ++L;
if(v <= 0x7FFFFFFFF) break sz;
usz[L-1] |= 0x80; usz[L] = ((v/0x10000) >>> 21) & 0x7F; ++L;
if(v <= 0x3FFFFFFFFFF) break sz;
usz[L-1] |= 0x80; usz[L] = ((v/0x1000000) >>> 21) & 0x7F; ++L;
}
return usz.slice(0, L);
}
/** Parse a 32-bit signed integer from the raw varint */
function varint_to_i32(buf: Uint8Array): number {
var l = 0, i32 = buf[l] & 0x7F;
varint: if(buf[l++] >= 0x80) {
i32 |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint;
i32 |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint;
i32 |= (buf[l] & 0x7F) << 21; if(buf[l++] < 0x80) break varint;
i32 |= (buf[l] & 0x7F) << 28;
}
return i32;
}
interface ProtoItem {
offset?: number;
data: Uint8Array;
type: number;
}
type ProtoField = Array<ProtoItem>
type ProtoMessage = Array<ProtoField>;
/** Shallow parse of a message */
function parse_shallow(buf: Uint8Array): ProtoMessage {
var out: ProtoMessage = [], ptr: Ptr = [0];
while(ptr[0] < buf.length) {
var off = ptr[0];
var num = parse_varint49(buf, ptr);
var type = num & 0x07; num = Math.floor(num / 8);
var len = 0;
var res: Uint8Array;
if(num == 0) break;
switch(type) {
case 0: {
var l = ptr[0];
while(buf[ptr[0]++] >= 0x80);
res = buf.slice(l, ptr[0]);
} break;
case 5: len = 4; res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break;
case 1: len = 8; res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break;
case 2: len = parse_varint49(buf, ptr); res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break;
case 3: // Start group
case 4: // End group
default: throw new Error(`PB Type ${type} for Field ${num} at offset ${off}`);
}
var v: ProtoItem = { offset: off, data: res, type };
if(out[num] == null) out[num] = [v];
else out[num].push(v);
}
return out;
}
/** Serialize a shallow parse */
function write_shallow(proto: ProtoMessage): Uint8Array {
var out: Uint8Array[] = [];
proto.forEach((field, idx) => {
field.forEach(item => {
out.push(write_varint49(idx * 8 + item.type));
out.push(item.data);
});
});
return u8concat(out);
}
function mappa<U>(data: ProtoField, cb:(_:Uint8Array) => U): U[] {
if(!data) return [];
return data.map((d) => { try {
return cb(d.data);
} catch(e) {
var m = e.message?.match(/at offset (\d+)/);
if(m) e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + (d.offset||0)));
throw e;
}});
}
// #endregion
// #region descriptor.ts
var TYPES = [
"error",
"double",
"float",
"int64",
"uint64",
"int32",
"fixed64",
"fixed32",
"bool",
"string",
"group",
"message",
"bytes",
"uint32",
"enum",
"sfixed32",
"sfixed64",
"sint32",
"sint64"
];
interface FileOptions {
javaPackage?: string;
javaOuterClassname?: string;
javaMultipleFiles?: string;
goPackage?: string;
}
function parse_FileOptions(buf: Uint8Array): FileOptions {
var data = parse_shallow(buf);
var out: FileOptions = {};
if(data[1]?.[0]) out.javaPackage = u8str(data[1][0].data);
if(data[8]?.[0]) out.javaOuterClassname = u8str(data[8][0].data);
if(data[11]?.[0]) out.goPackage = u8str(data[11][0].data);
return out;
}
interface EnumValue {
name?: string;
number?: number;
}
function parse_EnumValue(buf: Uint8Array): EnumValue {
var data = parse_shallow(buf);
var out: EnumValue = {};
if(data[1]?.[0]) out.name = u8str(data[1][0].data);
if(data[2]?.[0]) out.number = varint_to_i32(data[2][0].data);
return out;
}
interface Enum {
name?: string;
value?: EnumValue[];
}
function parse_Enum(buf: Uint8Array): Enum {
var data = parse_shallow(buf);
var out: Enum = {};
if(data[1]?.[0]) out.name = u8str(data[1][0].data);
out.value = mappa(data[2], parse_EnumValue);
return out;
}
var write_Enum = (en: Enum): string => {
var out = [`enum ${en.name} {`];
en.value?.forEach(({name, number}) => out.push(` ${name} = ${number};`));
return out.concat(`}`).join("\n");
};
interface FieldOptions {
packed?: boolean;
deprecated?: boolean;
}
function parse_FieldOptions(buf: Uint8Array): FieldOptions {
var data = parse_shallow(buf);
var out: FieldOptions = {};
if(data[2]?.[0]) out.packed = !!data[2][0].data;
if(data[3]?.[0]) out.deprecated = !!data[3][0].data;
return out;
}
interface Field {
name?: string;
extendee?: string;
number?: number;
label?: number;
type?: number;
typeName?: string;
defaultValue?: string;
options?: FieldOptions;
}
function parse_Field(buf: Uint8Array): Field {
var data = parse_shallow(buf);
var out: Field = {};
if(data[1]?.[0]) out.name = u8str(data[1][0].data);
if(data[2]?.[0]) out.extendee = u8str(data[2][0].data);
if(data[3]?.[0]) out.number = varint_to_i32(data[3][0].data);
if(data[4]?.[0]) out.label = varint_to_i32(data[4][0].data);
if(data[5]?.[0]) out.type = varint_to_i32(data[5][0].data);
if(data[6]?.[0]) out.typeName = u8str(data[6][0].data);
if(data[7]?.[0]) out.defaultValue = u8str(data[7][0].data);
if(data[8]?.[0]) out.options = parse_FieldOptions(data[8][0].data);
return out;
}
function write_Field(field: Field): string {
var out = [];
var label = ["", "optional ", "required ", "repeated "][field.label||0] || "";
var type = field.typeName || TYPES[field.type||69] || "s5s";
var opts = [];
if(field.defaultValue) opts.push(`default = ${field.defaultValue}`);
if(field.options?.packed) opts.push(`packed = true`);
if(field.options?.deprecated) opts.push(`deprecated = true`);
var os = opts.length ? ` [${opts.join(", ")}]`: "";
out.push(`${label}${type} ${field.name} = ${field.number}${os};`);
return out.length ? indent(out.join("\n"), 1) : "";
}
function write_extensions(ext: Field[], xtra = false, coalesce = true): string {
var res: string[] = [];
var xt: Array<[string, Array<Field>]> = [];
ext.forEach(ext => {
if(!ext.extendee) return;
var row = coalesce ?
xt.find(x => x[0] == ext.extendee) :
(xt[xt.length - 1]?.[0] == ext.extendee ? xt[xt.length - 1]: null);
if(row) row[1].push(ext);
else xt.push([ext.extendee, [ext]]);
});
xt.forEach(extrow => {
var out = [`extend ${extrow[0]} {`];
extrow[1].forEach(ext => out.push(write_Field(ext)));
res.push(out.concat(`}`).join("\n") + (xtra ? "\n" : ""));
});
return res.join("\n");
}
interface ExtensionRange { start?: number; end?: number; }
interface MessageType {
name?: string;
nestedType?: MessageType[];
enumType?: Enum[];
field?: Field[];
extension?: Field[];
extensionRange?: ExtensionRange[];
}
function parse_mtype(buf: Uint8Array): MessageType {
var data = parse_shallow(buf);
var out: MessageType = {};
if(data[1]?.[0]) out.name = u8str(data[1][0].data);
if(data[2]?.length >= 1) out.field = mappa(data[2], parse_Field);
if(data[3]?.length >= 1) out.nestedType = mappa(data[3], parse_mtype);
if(data[4]?.length >= 1) out.enumType = mappa(data[4], parse_Enum);
if(data[6]?.length >= 1) out.extension = mappa(data[6], parse_Field);
if(data[5]?.length >= 1) out.extensionRange = data[5].map(d => {
var data = parse_shallow(d.data);
var out: ExtensionRange = {};
if(data[1]?.[0]) out.start = varint_to_i32(data[1][0].data);
if(data[2]?.[0]) out.end = varint_to_i32(data[2][0].data);
return out;
});
return out;
}
var write_mtype = (message: MessageType): string => {
var out = [ `message ${message.name} {` ];
message.nestedType?.forEach(m => out.push(indent(write_mtype(m), 1)));
message.enumType?.forEach(en => out.push(indent(write_Enum(en), 1)));
message.field?.forEach(field => out.push(write_Field(field)));
if(message.extensionRange) message.extensionRange.forEach(er => out.push(` extensions ${er.start} to ${(er.end||0) - 1};`));
if(message.extension?.length) out.push(indent(write_extensions(message.extension), 1));
return out.concat(`}`).join("\n");
};
interface Descriptor {
name?: string;
package?: string;
dependency?: string[];
messageType?: MessageType[];
enumType?: Enum[];
extension?: Field[];
options?: FileOptions;
}
function parse_FileDescriptor(buf: Uint8Array): Descriptor {
var data = parse_shallow(buf);
var out: Descriptor = {};
if(data[1]?.[0]) out.name = u8str(data[1][0].data);
if(data[2]?.[0]) out.package = u8str(data[2][0].data);
if(data[3]?.[0]) out.dependency = data[3].map(x => u8str(x.data));
if(data[4]?.length >= 1) out.messageType = mappa(data[4], parse_mtype);
if(data[5]?.length >= 1) out.enumType = mappa(data[5], parse_Enum);
if(data[7]?.length >= 1) out.extension = mappa(data[7], parse_Field);
if(data[8]?.[0]) out.options = parse_FileOptions(data[8][0].data);
return out;
}
var write_FileDescriptor = (pb: Descriptor): string => {
var out = [
'syntax = "proto2";',
''
];
if(pb.dependency) pb.dependency.forEach((n: string) => { if(n) out.push(`import "${n}";`); });
if(pb.package) out.push(`package ${pb.package};\n`);
if(pb.options) {
var o = out.length;
if(pb.options.javaPackage) out.push(`option java_package = "${pb.options.javaPackage}";`);
if(pb.options.javaOuterClassname?.replace(/\W/g, "")) out.push(`option java_outer_classname = "${pb.options.javaOuterClassname}";`);
if(pb.options.javaMultipleFiles) out.push(`option java_multiple_files = true;`);
if(pb.options.goPackage) out.push(`option go_package = "${pb.options.goPackage}";`);
if(out.length > o) out.push('');
}
pb.enumType?.forEach(en => { if(en.name) out.push(write_Enum(en) + "\n"); });
pb.messageType?.forEach(m => { if(m.name) { var o = write_mtype(m); if(o) out.push(o + "\n"); }});
if(pb.extension?.length) {
var e = write_extensions(pb.extension, true, false);
if(e) out.push(e);
}
return out.join("\n") + "\n";
};
// #endregion
// #region macho.ts
interface MachOEntry {
type: number;
subtype: number;
offset: number;
size: number;
align?: number;
data: Uint8Array;
}
var parse_fat = (buf: Uint8Array): MachOEntry[] => {
var dv = u8_to_dataview(buf);
if(dv.getUint32(0, false) !== 0xCAFEBABE) throw new Error("Unsupported file");
var nfat_arch = dv.getUint32(4, false);
var out: MachOEntry[] = [];
for(var i = 0; i < nfat_arch; ++i) {
var start = i * 20 + 8;
var cputype = dv.getUint32(start, false);
var cpusubtype = dv.getUint32(start+4, false);
var offset = dv.getUint32(start+8, false);
var size = dv.getUint32(start+12, false);
var align = dv.getUint32(start+16, false);
out.push({
type: cputype,
subtype: cpusubtype,
offset,
size,
align,
data: buf.slice(offset, offset + size)
});
}
return out;
};
var parse_macho = (buf: Uint8Array): MachOEntry[] => {
var dv = u8_to_dataview(buf);
var magic = dv.getUint32(0, false);
switch(magic) {
// fat binary (x86_64 / aarch64)
case 0xCAFEBABE: return parse_fat(buf);
// x86_64
case 0xCFFAEDFE: return [{
type: dv.getUint32(4, false),
subtype: dv.getUint32(8, false),
offset: 0,
size: buf.length,
data: buf
}];
}
throw new Error("Unsupported file");
};
// #endregion
// #region otorp.ts
interface OtorpEntry {
name: string;
proto: string;
}
/** Find and stringify all relevant protobuf defs */
function otorp(buf: Uint8Array, builtins = false): OtorpEntry[] {
var res = proto_offsets(buf);
var registry: {[key: string]: Descriptor} = {};
var names: Set<string> = new Set();
var out: OtorpEntry[] = [];
res.forEach((r, i) => {
if(!builtins && r[1].startsWith("google/protobuf/")) return;
var b = buf.slice(r[0], i < res.length - 1 ? res[i+1][0] : buf.length);
var pb = parse_FileDescriptorProto(b/*, r[1]*/);
names.add(r[1]);
registry[r[1]] = pb;
});
names.forEach(name => {
/* ensure partial ordering by dependencies */
names.delete(name);
var pb = registry[name];
var doit = (pb.dependency||[]).every((d: string) => !names.has(d));
if(!doit) { names.add(name); return; }
var dups = res.filter(r => r[1] == name);
if(dups.length == 1) return out.push({ name, proto: write_FileDescriptor(pb) });
/* in a fat binary, compare the defs for x86_64/aarch64 */
var pbs = dups.map(r => {
var i = res.indexOf(r);
var b = buf.slice(r[0], i < res.length - 1 ? res[i+1][0] : buf.length);
var pb = parse_FileDescriptorProto(b/*, r[1]*/);
return write_FileDescriptor(pb);
});
for(var l = 1; l < pbs.length; ++l) if(pbs[l] != pbs[0]) throw new Error(`Conflicting definitions for ${name} at offsets 0x${dups[0][0].toString(16)} and 0x${dups[l][0].toString(16)}`);
return out.push({ name, proto: pbs[0] });
});
return out;
}
export default otorp;
/** Determine if an address is being referenced */
var is_referenced = (buf: Uint8Array, pos: number): boolean => {
var dv = u8_to_dataview(buf);
/* Search for LEA reference (x86) */
for(var leaddr = 0; leaddr > -1 && leaddr < pos; leaddr = u8indexOf(buf, 0x8D, leaddr + 1))
if(dv.getUint32(leaddr + 2, true) == pos - leaddr - 6) return true;
/* Search for absolute reference to address */
try {
var headers = parse_macho(buf);
for(var i = 0; i < headers.length; ++i) {
if(pos < headers[i].offset || pos > headers[i].offset + headers[i].size) continue;
var b = headers[i].data;
var p = pos - headers[i].offset;
var ref = new Uint8Array([0,0,0,0,0,0,0,0]);
var dv = u8_to_dataview(ref);
dv.setUint32(0, p, true);
if(u8indexOf(b, ref, 0) > 0) return true;
ref[4] = 0x01;
if(u8indexOf(b, ref, 0) > 0) return true;
ref[4] = 0x00; ref[6] = 0x10;
if(u8indexOf(b, ref, 0) > 0) return true;
}
} catch(e) {throw e}
return false;
};
type OffsetList = Array<[number, string, number, number]>;
/** Generate a list of potential starting points */
var proto_offsets = (buf: Uint8Array): OffsetList => {
var meta = parse_macho(buf);
var out: OffsetList = [];
var off = 0;
/* note: this loop only works for names < 128 chars */
search: while((off = u8indexOf(buf, ".proto", off + 1)) > -1) {
var pos = off;
off += 6;
while(off - pos < 256 && buf[pos] != off - pos - 1) {
if(buf[pos] > 0x7F || buf[pos] < 0x20) continue search;
--pos;
}
if(off - pos > 250) continue;
var name = u8str(buf.slice(pos + 1, off));
if(buf[--pos] != 0x0A) continue;
if(!is_referenced(buf, pos)) { console.error(`Reference to ${name} at ${pos} not found`); continue; }
var bin = meta.find(m => m.offset <= pos && m.offset + m.size >= pos);
out.push([pos, name, bin?.type || -1, bin?.subtype || -1]);
}
return out;
};
/** Parse a descriptor that starts with the first byte of the supplied buffer */
var parse_FileDescriptorProto = (buf: Uint8Array): Descriptor => {
var l = buf.length;
while(l > 0) try {
var b = buf.slice(0,l);
var o = parse_FileDescriptor(b);
return o;
} catch(e) {
var m = e.message.match(/at offset (\d+)/);
if(m && parseInt(m[1], 10) < buf.length) l = parseInt(m[1], 10) - 1;
else --l;
}
throw new RangeError("no protobuf message in range");
};
// #endregion
let spin: TerminalSpinner;
const width = Deno.consoleSize().columns;
function process(inf: string, outf: string) {
const fi = Deno.statSync(inf);
if(fi.isDirectory) for(let info of Deno.readDirSync(inf)) {
if(spin) spin.set(inf.length > width - 4 ? "…" + inf.slice(-(width-4)) : inf);
process(inf + (inf.slice(-1) == "/" ? "" : "/") + info.name, outf);
}
try {
const buf: Uint8Array = Deno.readFileSync(inf);
var dv = u8_to_dataview(buf);
var magic = dv.getUint32(0, false);
if(![0xCAFEBABE, 0xCFFAEDFE].includes(magic)) return;
otorp(buf).forEach(({name, proto}) => {
if(!outf) return console.log(proto);
var pth = resolve(outf || "./", name.replace(/[/]/g, "$"));
try {
const str = Deno.readTextFileSync(pth);
if(str == proto) return;
throw `${pth} definition diverges!`;
} catch(e) { if(typeof e == "string") throw e; }
console.error(`writing ${name} to ${pth}`);
Deno.writeTextFileSync(pth, proto);
});
} catch(e) {}
}
function doit() {
const [ inf, outf ] = Deno.args;
if(!inf || inf == "-h" || inf == "--help") {
console.log(`usage: otorp.ts <path/to/bin> [output/folder]
if no output folder specified, log all discovered defs
if output folder specified, attempt to write defs in the folder
$ otorp.ts /Applications/Numbers.app out/ # search all files
$ otorp.ts /Applications/Numbers.app/Contents/MacOS/Numbers # search one file
`);
Deno.exit(1);
}
if(Deno.statSync(inf).isDirectory) (spin = new TerminalSpinner("")).start();
if(outf) try { Deno.mkdirSync(outf, { recursive: true }); } catch(e) {}
process(inf, outf);
if(spin) spin.stop();
}
doit();

69
test.js

@ -13,8 +13,10 @@ declare var before:(test:EmptyFunc)=>void;
declare var afterEach:(test:EmptyFunc)=>void;
declare var cptable: any;
*/
var X = require("./"), XLSX_ZAHL = require("./dist/xlsx.zahl");
var X, XLSX_ZAHL;
var modp = './';
var fs = require('fs'), assert = require('assert');
describe('source',function(){it('should load',function(){X=require(modp);});});
var DIF_XL = true;
var browser = typeof document !== 'undefined';
@ -54,8 +56,6 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x/*:string*/)/*:string*/ { return x.substr(0,31); }
@ -396,6 +396,11 @@ function check_comments(wb) {
describe('parse options', function() {
var html_cell_types = ['s'];
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.read(fs.readFileSync(paths.cstxlsx), {type:TYPE});
@ -743,6 +748,7 @@ describe('output formats', function() {
["prn", false, true]
];
function RT(T) {
if(!X) X = require(modp);
fmts.forEach(function(fmt) {
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([['R',"\u2603"],["\u0BEE",2]]), "Sheet1");
@ -921,6 +927,7 @@ describe('parse features', function() {
describe('comments', function() {
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
X = require(modp);
var sheet = 'Sheet1';
var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:TYPE});
var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:TYPE});
@ -1025,6 +1032,7 @@ describe('parse features', function() {
describe('column properties', function() {
var wbs = [], wbs_no_slk = [];
var bef = (function() {
X = require(modp);
wbs = CWPaths.map(function(n) { return X.read(fs.readFileSync(n), {type:TYPE, cellStyles:true}); });
wbs_no_slk = wbs.slice(0, 5);
});
@ -1067,6 +1075,7 @@ describe('parse features', function() {
var wbs = [], ols = [];
var ol = fs.existsSync(paths.olxls);
var bef = (function() {
X = require(modp);
wbs = RHPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, cellStyles:true}); });
/* */
if(!ol) return;
@ -1112,6 +1121,7 @@ describe('parse features', function() {
describe('merge cells',function() {
var wbs=[];
var bef = (function() {
X = require(modp);
wbs = MCPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
});
if(typeof before != 'undefined') before(bef);
@ -1130,6 +1140,7 @@ describe('parse features', function() {
describe('should find hyperlinks', function() {
var wb1, wb2;
var bef = (function() {
X = require(modp);
wb1 = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:true}); });
wb2 = ILPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:true}); });
});
@ -1441,7 +1452,7 @@ describe('parse features', function() {
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
].forEach(function(r) {
if(r == "numbers" && !can_write_numbers) return;
if(!XLSX_ZAHL) XLSX_ZAHL=require("./dist/xlsx.zahl");
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
@ -1469,6 +1480,7 @@ describe('write features', function() {
};
var ws;
var bef = (function() {
X = require(modp);
ws = X.utils.aoa_to_sheet([["a","b","c"],[1,2,3]]);
});
if(typeof before != 'undefined') before(bef);
@ -1546,22 +1558,6 @@ describe('write features', function() {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(wb2.Workbook.Names.length, wb3.Workbook.Names.length);
}); });
it('should handle non-string values for "s" cells', function() {[
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
].forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
@ -1598,6 +1594,9 @@ function parseDate(str/*:string|Date*/)/*:Date*/ {
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
describe('roundtrip features', function() {
var bef = (function() { X = require(modp); XLSX_ZAHL=require("./dist/xlsx.zahl"); });
if(typeof before != 'undefined') before(bef);
else it('before', bef);
describe('should preserve core properties', function() { [
['xls', paths.cpxls],
['xlml', paths.cpxml],
@ -1628,7 +1627,6 @@ describe('roundtrip features', function() {
describe('should preserve merge cells', function() {
["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"].forEach(function(f) { it(f, function() {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]['!merges'].map(X.utils.encode_range);
@ -1903,21 +1901,6 @@ describe('invalid files', function() {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
it('should fail if sheet name is not valid', function() {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2242,7 +2225,7 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
@ -2380,7 +2363,7 @@ describe('numbers', function() {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
if(can_write_numbers) it('should cap cols at 1000 (ALL)', function() {
it('should cap cols at 1000 (ALL)', function() {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");
@ -2416,16 +2399,6 @@ describe('dbf', function() {
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
var JSDOM = null;
// $FlowIgnore

20
test.mjs generated

@ -58,8 +58,6 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Set !== "undefined" && typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x/*:string*/)/*:string*/ { return x.substr(0,31); }
@ -1445,7 +1443,6 @@ describe('parse features', function() {
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
].forEach(function(r) {
if(r == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
@ -1616,7 +1613,6 @@ describe('roundtrip features', function() {
describe('should preserve merge cells', function() {
["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"].forEach(function(f) { it(f, function() {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]['!merges'].map(X.utils.encode_range);
@ -2208,14 +2204,14 @@ describe('CSV', function() {
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"]
];
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
@ -2353,7 +2349,7 @@ describe('numbers', function() {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
if(can_write_numbers) it('should cap cols at 1000 (ALL)', function() {
it('should cap cols at 1000 (ALL)', function() {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");
@ -2389,16 +2385,6 @@ describe('dbf', function() {
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
import { JSDOM } from 'jsdom';
var domtest = true;

@ -78,8 +78,6 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Set !== "undefined" && typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x: string): string { return x.substr(0,31); }
@ -1410,7 +1408,6 @@ describe('parse features', function() {
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
] as X.BookType[]).forEach(function(r: X.BookType) {
if(r == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
@ -1576,7 +1573,6 @@ describe('roundtrip features', function() {
describe('should preserve merge cells', function() {
var mcf = ["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"] as Array<X.BookType>; for(let mci = 0; mci < mcf.length; ++mci) { let f = mcf[mci]; it(f, function() {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]?.['!merges']?.map(X.utils.encode_range);
@ -2164,14 +2160,14 @@ describe('CSV', function() {
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
];
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
@ -2299,7 +2295,7 @@ describe('numbers', function() {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
if(can_write_numbers) it('should cap cols at 1000 (ALL)', function() {
it('should cap cols at 1000 (ALL)', function() {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");
@ -2330,18 +2326,8 @@ describe('dbf', function() {
["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
});
it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
const JSDOM = false; //import { JSDOM } from 'jsdom'; // breaks in latest deno
import { JSDOM } from 'jsdom';
var domtest = false; // error: Error: Not implemented: isContext
var inserted_dom_elements = [];
@ -2354,7 +2340,6 @@ function get_dom_element(html: string) {
return domelt.children[0];
}
if(!JSDOM) throw new Error("Browser test fail");
// @ts-ignore
return new JSDOM(html).window.document.body.children[0];
}

23
test.ts

@ -78,8 +78,6 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Set !== "undefined" && typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x: string): string { return x.substr(0,31); }
@ -1410,7 +1408,6 @@ Deno.test('parse features', async function(t) {
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
] as X.BookType[]).forEach(function(r: X.BookType) {
if(r == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
@ -1576,7 +1573,6 @@ Deno.test('roundtrip features', async function(t) {
await t.step('should preserve merge cells', async function(t) {
var mcf = ["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"] as Array<X.BookType>; for(let mci = 0; mci < mcf.length; ++mci) { let f = mcf[mci]; await t.step(f, async function(t) {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]?.['!merges']?.map(X.utils.encode_range);
@ -2164,14 +2160,14 @@ Deno.test('CSV', async function(t) {
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
];
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
@ -2299,7 +2295,7 @@ Deno.test('numbers', async function(t) {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
if(can_write_numbers) await t.step('should cap cols at 1000 (ALL)', async function(t) {
await t.step('should cap cols at 1000 (ALL)', async function(t) {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");
@ -2330,18 +2326,8 @@ Deno.test('dbf', async function(t) {
["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
});
await t.step("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", async function(t) {
([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
const JSDOM = false; //import { JSDOM } from 'jsdom'; // breaks in latest deno
import { JSDOM } from 'jsdom';
var domtest = false; // error: Error: Not implemented: isContext
var inserted_dom_elements = [];
@ -2354,7 +2340,6 @@ function get_dom_element(html: string) {
return domelt.children[0];
}
if(!JSDOM) throw new Error("Browser test fail");
// @ts-ignore
return new JSDOM(html).window.document.body.children[0];
}

@ -1 +1 @@
Subproject commit 1ea05a3eee0a746c102dea42e729b31e4ebfca35
Subproject commit f91c73f99ccb7919b7992e720f9ba7a730071770

@ -77,8 +77,6 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Set !== "undefined" && typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x: string): string { return x.substr(0,31); }
@ -1409,7 +1407,6 @@ Deno.test('parse features', async function(t) {
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
] as X.BookType[]).forEach(function(r: X.BookType) {
if(r == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
@ -1575,7 +1572,6 @@ Deno.test('roundtrip features', async function(t) {
await t.step('should preserve merge cells', async function(t) {
var mcf = ["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"] as Array<X.BookType>; for(let mci = 0; mci < mcf.length; ++mci) { let f = mcf[mci]; await t.step(f, async function(t) {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]?.['!merges']?.map(X.utils.encode_range);
@ -2163,14 +2159,14 @@ Deno.test('CSV', async function(t) {
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
];
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
@ -2298,7 +2294,7 @@ Deno.test('numbers', async function(t) {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
if(can_write_numbers) await t.step('should cap cols at 1000 (ALL)', async function(t) {
await t.step('should cap cols at 1000 (ALL)', async function(t) {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");
@ -2329,18 +2325,8 @@ Deno.test('dbf', async function(t) {
["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
});
if(false) await t.step("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", async function(t) {
([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
const JSDOM = false; //import { JSDOM } from 'jsdom'; // breaks in latest deno
import { JSDOM } from 'jsdom';
var domtest = false; // error: Error: Not implemented: isContext
var inserted_dom_elements = [];
@ -2353,7 +2339,6 @@ function get_dom_element(html: string) {
return domelt.children[0];
}
if(!JSDOM) throw new Error("Browser test fail");
// @ts-ignore
return new JSDOM(html).window.document.body.children[0];
}

74
tests/core.js generated

@ -13,8 +13,10 @@ declare var before:(test:EmptyFunc)=>void;
declare var afterEach:(test:EmptyFunc)=>void;
declare var cptable: any;
*/
var X = require("./"), XLSX_ZAHL = require("./dist/xlsx.zahl");
var X, XLSX_ZAHL = XLSX_ZAHL_PAYLOAD;
var modp = './';
var fs = require('fs'), assert = require('assert');
describe('source',function(){it('should load',function(){X=require(modp);});});
var DIF_XL = true;
var browser = typeof document !== 'undefined';
@ -25,7 +27,7 @@ var Buffer_from = /*::(*/function(){}/*:: :any)*/;
if(typeof Buffer !== 'undefined') {
var nbfs = !Buffer.from;
if(!nbfs) try { Buffer.from("foo", "utf-8"); } catch(e) { nbfs = true; }
if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
// $FlowIgnore
if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
@ -54,8 +56,6 @@ if(!browser) {
for(var _fileAi = 0; _fileAi < _fileA.length; ++_fileAi) if(test_file(_fileA[_fileAi])) fileA.push(_fileA[_fileAi]);
}
var can_write_numbers = typeof Array.prototype.findIndex == "function" && typeof Uint8Array !== "undefined" && typeof Uint8Array.prototype.indexOf == "function";
/* Excel enforces 31 character sheet limit, although technical file limit is 255 */
function fixsheetname(x/*:string*/)/*:string*/ { return x.substr(0,31); }
@ -396,6 +396,11 @@ function check_comments(wb) {
describe('parse options', function() {
var html_cell_types = ['s'];
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.read(fs.readFileSync(paths.cstxlsx), {type:TYPE});
@ -743,6 +748,7 @@ describe('output formats', function() {
["prn", false, true]
];
function RT(T) {
if(!X) X = require(modp);
fmts.forEach(function(fmt) {
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, X.utils.aoa_to_sheet([['R',"\u2603"],["\u0BEE",2]]), "Sheet1");
@ -921,6 +927,7 @@ describe('parse features', function() {
describe('comments', function() {
if(fs.existsSync(paths.swcxlsx)) it('should have comment as part of cell properties', function(){
X = require(modp);
var sheet = 'Sheet1';
var wb1=X.read(fs.readFileSync(paths.swcxlsx), {type:TYPE});
var wb2=X.read(fs.readFileSync(paths.swcxlsb), {type:TYPE});
@ -1025,6 +1032,7 @@ describe('parse features', function() {
describe('column properties', function() {
var wbs = [], wbs_no_slk = [];
var bef = (function() {
X = require(modp);
wbs = CWPaths.map(function(n) { return X.read(fs.readFileSync(n), {type:TYPE, cellStyles:true}); });
wbs_no_slk = wbs.slice(0, 5);
});
@ -1067,6 +1075,7 @@ describe('parse features', function() {
var wbs = [], ols = [];
var ol = fs.existsSync(paths.olxls);
var bef = (function() {
X = require(modp);
wbs = RHPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, cellStyles:true}); });
/* */
if(!ol) return;
@ -1112,6 +1121,7 @@ describe('parse features', function() {
describe('merge cells',function() {
var wbs=[];
var bef = (function() {
X = require(modp);
wbs = MCPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
});
if(typeof before != 'undefined') before(bef);
@ -1130,6 +1140,7 @@ describe('parse features', function() {
describe('should find hyperlinks', function() {
var wb1, wb2;
var bef = (function() {
X = require(modp);
wb1 = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:true}); });
wb2 = ILPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE, WTF:true}); });
});
@ -1441,7 +1452,6 @@ describe('parse features', function() {
// TODO: keep in sync with BookType, support other formats
"xlsx"/*, "xlsm" */, "xlsb"/* xls / xla / biff# */, "xlml", "ods", "fods"/*, "csv", "txt", */, "sylk", "html", "dif", "rtf"/*, "prn", "eth"*/, "dbf", "numbers"
].forEach(function(r) {
if(r == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([ ["a", "b", "c"], [1, 2, 3] ]);
var wb = X.utils.book_new(); X.utils.book_append_sheet(wb, ws, "Sheet1");
var data = X.write(wb, {type: TYPE, bookType: r, WTF: true, numbers:XLSX_ZAHL });
@ -1469,6 +1479,7 @@ describe('write features', function() {
};
var ws;
var bef = (function() {
X = require(modp);
ws = X.utils.aoa_to_sheet([["a","b","c"],[1,2,3]]);
});
if(typeof before != 'undefined') before(bef);
@ -1546,22 +1557,6 @@ describe('write features', function() {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(wb2.Workbook.Names.length, wb3.Workbook.Names.length);
}); });
it('should handle non-string values for "s" cells', function() {[
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
].forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
@ -1598,6 +1593,9 @@ function parseDate(str/*:string|Date*/)/*:Date*/ {
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
describe('roundtrip features', function() {
var bef = (function() { X = require(modp); XLSX_ZAHL=require("./dist/xlsx.zahl"); });
if(typeof before != 'undefined') before(bef);
else it('before', bef);
describe('should preserve core properties', function() { [
['xls', paths.cpxls],
['xlml', paths.cpxml],
@ -1628,7 +1626,6 @@ describe('roundtrip features', function() {
describe('should preserve merge cells', function() {
["xlsx", "xlsb", "xlml", "ods", "biff8", "numbers"].forEach(function(f) { it(f, function() {
if(f == "numbers" && !can_write_numbers) return;
var wb1 = X.read(fs.readFileSync(paths.mcxlsx), {type:TYPE});
var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary',numbers:XLSX_ZAHL}),{type:'binary'});
var m1 = wb1.Sheets["Merge"]['!merges'].map(X.utils.encode_range);
@ -1903,21 +1900,6 @@ describe('invalid files', function() {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
it('should fail if sheet name is not valid', function() {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2142,7 +2124,7 @@ function plaintext_test(wb, raw) {
var sheet = wb.Sheets[wb.SheetNames[0]];
plaintext_val.forEach(function(x) {
var cell = get_cell(sheet, x[0]);
var tcval = x[2+(raw ? 1 : 0)];
var tcval = x[2+(!!raw ? 1 : 0)];
var type = raw ? 's' : x[1];
if(x.length == 1) { if(cell) { assert.equal(cell.t, 'z'); assert.ok(!cell.v); } return; }
assert.equal(cell.v, tcval); assert.equal(cell.t, type);
@ -2235,14 +2217,14 @@ describe('CSV', function() {
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"]
];
]
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B1 = get_cell(ws, "B1"); console.log(B1); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
@ -2380,7 +2362,7 @@ describe('numbers', function() {
assert.equal(get_cell(ws, "B11").v, true);
assert.equal(get_cell(ws, "B13").v, 50);
});
if(can_write_numbers) it('should cap cols at 1000 (ALL)', function() {
it('should cap cols at 1000 (ALL)', function() {
var aoa = [[1], [], []]; aoa[1][999] = 2; aoa[2][1000] = 3;
var ws1 = X.utils.aoa_to_sheet(aoa);
var wb1 = X.utils.book_new(); X.utils.book_append_sheet(wb1, ws1, "Sheet1");
@ -2416,16 +2398,6 @@ describe('dbf', function() {
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
var JSDOM = null;
// $FlowIgnore

129
types/index.d.ts vendored

@ -14,9 +14,9 @@ export const SSF: any;
// export { CFB };
export const CFB: any;
/** Set internal `fs` instance */
/** ESM ONLY! Set internal `fs` instance */
export function set_fs(fs: any): void;
/** Set internal codepage tables */
/** ESM ONLY! Set internal codepage tables */
export function set_cptable(cptable: any): void;
/** NODE ONLY! Attempts to read filename and parse */
@ -144,15 +144,7 @@ export interface ParsingOptions extends CommonOptions {
/** Input data encoding */
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array' | 'string';
/**
* Default codepage for legacy files
*
* This requires encoding support to be loaded. It is automatically loaded
* in `xlsx.full.min.js` and in CommonJS / Extendscript, but an extra step
* is required in React / Angular / Webpack ESM deployments.
*
* Check the relevant guide https://docs.sheetjs.com/docs/getting-started/
*/
/** Default codepage */
codepage?: number;
/**
@ -221,27 +213,24 @@ export interface ParsingOptions extends CommonOptions {
/** If true, plaintext parsing will not parse values */
raw?: boolean;
/** If true, ignore "dimensions" records and guess range using every cell */
nodim?: boolean;
/** If true, preserve _xlfn. prefixes in formula function names */
xlfn?: boolean;
/** If true, generate dense-mode worksheets */
dense?: boolean;
/**
* For single-sheet formats (including CSV), override the worksheet name
* @default "Sheet1"
*/
sheet?: string;
PRN?: boolean;
}
export interface SheetOption {
/**
* Name of Worksheet (for single-sheet formats)
* @default ''
*/
sheet?: string;
}
/** Options for write and writeFile */
export interface WritingOptions extends CommonOptions {
export interface WritingOptions extends CommonOptions, SheetOption {
/** Output data encoding */
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array' | 'string';
@ -272,28 +261,8 @@ export interface WritingOptions extends CommonOptions {
/** Override workbook properties on save */
Props?: Properties;
/**
* Desired codepage for legacy file formats
*
* This requires encoding support to be loaded. It is automatically loaded
* in `xlsx.full.min.js` and in CommonJS / Extendscript, but an extra step
* is required in React / Angular / Webpack / ESM deployments.
*
* Check the relevant guide https://docs.sheetjs.com/docs/getting-started/
*/
codepage?: number;
/** Base64 encoding of NUMBERS base for exports */
numbers?: string;
/**
* For single-sheet formats, export the specified worksheet.
*
* The property must be a string (sheet name) or number (`SheetNames` index).
*
* If this option is omitted, the first worksheet will be exported.
*/
sheet?: string | number;
}
/** Workbook Object */
@ -548,52 +517,20 @@ export type SheetKeys = string | MarginInfo | SheetType;
/** General object representing a Sheet (worksheet or chartsheet) */
export interface Sheet {
/**
* Sparse-mode store cells with keys corresponding to A1-style address
* Dense-mode store cells in the '!data' key
* Indexing with a cell address string maps to a cell object
* Special keys start with '!'
*/
[cell: string]: CellObject | CellObject[][] | SheetKeys | any;
/**
* Dense-mode worksheets store data in an array of arrays
*
* Cells are accessed with sheet['!data'][R][C] (where R and C are 0-indexed)
*/
'!data'?: CellObject[][];
[cell: string]: CellObject | SheetKeys | any;
/** Sheet type */
'!type'?: SheetType;
/** Sheet Range (A1-style) */
/** Sheet Range */
'!ref'?: string;
/** Page Margins */
'!margins'?: MarginInfo;
}
/** General object representing a dense Sheet (worksheet or chartsheet) */
export interface DenseSheet extends Sheet {
/**
* Special keys start with '!'
* Dense-mode worksheets store data in the '!data' key
*/
[cell: string]: CellObject[][] | SheetKeys | any;
/**
* Dense-mode worksheets store data in an array of arrays
*
* Cells are accessed with sheet['!data'][R][C] (where R and C are 0-indexed)
*/
'!data': CellObject[][];
}
/** General object representing a sparse Sheet (worksheet or chartsheet) */
export interface SparseSheet extends Sheet {
/**
* Sparse-mode store cells with keys corresponding to A1-style address
* Cells are accessed with sheet[addr]
*/
'!data': never;
}
/** AutoFilter properties */
export interface AutoFilterInfo {
@ -626,15 +563,6 @@ export interface WorkSheet extends Sheet {
/** AutoFilter info */
'!autofilter'?: AutoFilterInfo;
}
/** Dense Worksheet Object */
export interface DenseWorkSheet extends DenseSheet {
/**
* Dense-mode worksheets store data in an array of arrays
*
* Cells are accessed with sheet['!data'][R][C] (where R and C are 0-indexed)
*/
'!data': CellObject[][];
}
/**
* Worksheet Object with CellObject type
@ -702,9 +630,6 @@ export interface CellObject {
/** Range of enclosing array if formula is array formula (if applicable) */
F?: string;
/** If true, cell is a dynamic array formula (for supported file formats) */
D?: boolean;
/** Rich text encoding (if applicable) */
r?: any;
@ -815,7 +740,7 @@ export interface AOA2SheetOpts extends CommonOptions, DateNFOption {
export interface SheetAOAOpts extends AOA2SheetOpts, OriginOption {}
export interface JSON2SheetOpts extends CommonOptions, DateNFOption, OriginOption {
export interface JSON2SheetOpts extends CommonOptions, DateNFOption {
/** Use specified column order */
header?: string[];
@ -823,7 +748,9 @@ export interface JSON2SheetOpts extends CommonOptions, DateNFOption, OriginOptio
skipHeader?: boolean;
}
export interface Table2SheetOpts extends CommonOptions, DateNFOption, OriginOption {
export interface SheetJSONOpts extends JSON2SheetOpts, OriginOption {}
export interface Table2SheetOpts extends CommonOptions, DateNFOption, OriginOption, SheetOption {
/** If true, plaintext parsing will not parse values */
raw?: boolean;
@ -835,20 +762,6 @@ export interface Table2SheetOpts extends CommonOptions, DateNFOption, OriginOpti
/** If true, hidden rows and cells will not be parsed */
display?: boolean;
/**
* Override the worksheet name
* @default "Sheet1"
*/
sheet?: string;
}
export interface Table2BookOpts extends Table2SheetOpts {
/**
* Override the worksheet name
* @default "Sheet1"
*/
sheet?: string;
}
/** General utilities */
@ -865,7 +778,7 @@ export interface XLSX$Utils {
/** BROWSER ONLY! Converts a TABLE DOM element to a worksheet. */
table_to_sheet(data: any, opts?: Table2SheetOpts): WorkSheet;
table_to_book(data: any, opts?: Table2BookOpts): WorkBook;
table_to_book(data: any, opts?: Table2SheetOpts): WorkBook;
sheet_add_dom(ws: WorkSheet, data: any, opts?: Table2SheetOpts): WorkSheet;
/* --- Export Functions --- */
@ -957,8 +870,8 @@ export interface XLSX$Utils {
sheet_add_aoa(ws: WorkSheet, data: any[][], opts?: SheetAOAOpts): WorkSheet;
/** Add an array of JS objects to a worksheet */
sheet_add_json(ws: WorkSheet, data: any[], opts?: JSON2SheetOpts): WorkSheet;
sheet_add_json<T>(ws: WorkSheet, data: T[], opts?: JSON2SheetOpts): WorkSheet;
sheet_add_json(ws: WorkSheet, data: any[], opts?: SheetJSONOpts): WorkSheet;
sheet_add_json<T>(ws: WorkSheet, data: T[], opts?: SheetJSONOpts): WorkSheet;
consts: XLSX$Consts;

File diff suppressed because it is too large Load Diff

2233
xlsx.js generated

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

2258
xlsx.mjs generated

File diff suppressed because it is too large Load Diff