Compare commits

...

49 Commits

Author SHA1 Message Date
29d46c07a8 version bump 0.20.1 2023-12-05 03:19:42 -05:00
9199c2600c dta initial 2023-11-13 06:13:07 -05:00
cd5fafda32 ssf v0.11.3 2023-10-23 21:22:11 -04:00
David Szajngarten
c8e6d5c20f ssf seconds/hours time rounding 2023-10-23 13:25:42 -04:00
ad0fb7766b import and export blank worksheets 2023-10-17 04:53:37 -04:00
4cc980975b QPW string formula results
- mujs-compatible regices
- NUMBERS use row offsets (fixes #3009 h/t @relaxsnow)
2023-10-15 23:03:39 -04:00
432ac1fda7 xlsx-cli v1.1.4 2023-10-11 16:22:42 -04:00
53283217e9 xlsx-cli support dateFormat option (#3005)
Co-authored-by: Marlous Kottenhagen <m.kottenhagen@bigmile.eu>
Reviewed-on: sheetjs/sheetjs#3005
Co-authored-by: MarlousKottenhagen <marlouskottenhagen@noreply.git.sheetjs.com>
Co-committed-by: MarlousKottenhagen <marlouskottenhagen@noreply.git.sheetjs.com>
2023-10-10 06:50:32 +00:00
248108b667 dense types 2023-09-21 04:12:13 -04:00
julitork
766fc4f4d2 allow rawNumber override raw option 2023-08-29 16:04:32 +03:00
485a4f30f1 set CSV formula cell value to raw fmla text 2023-08-23 13:38:14 -04:00
68cce77d23 package.json exports (fixes #2977 h/t @stof) 2023-08-20 21:01:07 -04:00
c0b9e229a0 Delete .github/ISSUE_TEMPLATE/config.yml 2023-08-18 15:26:54 +00:00
955543147d version bump 0.20.0 2023-06-23 05:48:47 -04:00
36c5b7c0f5 NUMBERS read/write threaded comments 2023-06-14 03:47:51 -04:00
6e260c9185 cell comments
- `sheet_to_json` handle arrays (h/t AaronWoodrow)
- XLS parse comment visibility (h/t Godrules500)
- chrome manifest v3 writeFile support
- raw v8 (no TextEncoder/TextDecoder) optimization
- handle empty shared formula body (h/t florian)
2023-06-13 00:49:18 -04:00
d3a480750b NUMBERS read/write external links 2023-05-13 01:23:26 -04:00
5b33acfaf4 parse self-closing text:p uof:文本串 (fixes #2927) 2023-04-30 03:57:30 -04:00
b68eaed726 Export NaN/Infinity to error cells (fixes #2897) 2023-04-23 03:58:36 -04:00
333e4e40f9 version bump 0.19.3 2023-04-17 23:39:28 -04:00
af8e3d9171 build fixes for macOS Ventura 2023-04-14 03:51:02 -04:00
Vsevolod Kokorin
dca90c8024 XLSX Ensure comment address is valid 2023-04-12 03:48:54 -04:00
c06a32043f Add ESM helper methods to CJS build (fixes #2909) 2023-04-10 01:15:44 -04:00
ffbea71bc2 XLS ExternSheet record (fixes #2907) 2023-04-05 15:34:55 -04:00
16dd8a6eae UTF16LE sans codepage (fixes #2898 h/t @brismuth) 2023-03-15 04:17:09 -04:00
0577bb7a45 version bump 0.19.2 2023-01-25 16:17:34 -05:00
b150dea21d denoized otorp [ci skip] 2023-01-06 02:37:53 -05:00
e9cf1ad0fb ignore unexpected attributes in rich text part
Co-authored-by: colin4 <colin4@noreply.sheetjs.com>
2023-01-04 12:35:13 -05:00
5141222c24 sheet_to_json type include origin option
Co-authored-by: Hulusi <chsdwn@noreply.sheetjs.com>
2023-01-01 16:53:44 -05:00
51a8619000 version bump 0.19.1 2022-11-17 04:35:34 -05:00
e7e129e417 type fix (fixes #2828 h/t @younes-io) 2022-11-16 14:03:42 -05:00
df48489211 Numbers 12.2 skip ActivityStream.iwa 2022-11-06 21:58:41 -05:00
050f66ce1b version bump 0.19.0 2022-10-23 21:05:59 -04:00
2f329b64e2 DBF truncate numeric fields 2022-10-04 20:09:43 -04:00
515d1c6f2e mini refresh [ci skip] 2022-10-04 16:50:55 -04:00
654d6f98c3 stringify all 's' cell values (fixes #2795) 2022-09-28 23:08:10 -04:00
4ae4f0fad9 NUMBERS write multiple worksheets [ci skip] 2022-09-26 13:52:50 -04:00
Evan Bovie
1ca49a50bd
add display property to XLSX hyperlinks (#2791)
Resolves import bug in Google Sheets
2022-09-23 13:36:38 -04:00
81b231d866 version bump 0.18.12 2022-09-22 05:06:45 -04:00
1491302aa4 package.json exports types 2022-09-21 18:17:14 -04:00
bd5878e7c7 NUMBERS write up to ALL1000000 (h/t @masaccio) 2022-09-20 01:35:34 -04:00
Evan Bovie
4dd092a076 Add types to subpath exports in package.json 2022-09-18 23:26:24 -04:00
390910131
04dc18e742
fix vue3-table-lite demo url typo 2022-09-13 13:58:09 +08:00
6a5be04e3d Ś╫êëτ⌡ś and Š╫ěéτ⌡š 2022-09-09 16:59:22 -04:00
e90a61bf09 version bump 0.18.11 2022-09-06 02:18:12 -04:00
26cbfe37be DBF write encoding (fixes #2781 h/t @ZJS248) 2022-09-06 00:02:39 -04:00
df0e7b5f25 NUMBERS duration cell number format 2022-09-04 17:51:49 -04:00
6c9010f9d1 comment fallback (fixes #2779 h/t @AbhinanduReddy) 2022-09-02 03:30:10 -04:00
0a6ddcaf44 removed sheet_to_dif IIFE 2022-08-30 03:00:32 -04:00
163 changed files with 23931 additions and 9059 deletions

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

5
.gitignore vendored

@ -14,6 +14,7 @@ tmp
*.[pP][mM][dD]*
*.[pP][dD][fF]
*.[sS][lL][kK]
*.[sS][yY][lL][kK]
*.socialcalc
*.[xX][lL][sSwWcCaAtTmMrR]
*.[xX][lL][sSaAtT][xXmMbB]
@ -22,14 +23,16 @@ tmp
*.[xX][mM][lL]
*.[xX][lL][mM][lL]
*.[uU][oO][sS]
*.[wW][kKqQbB][S1234567890]
*.[wW][kKqQbB][sS1234567890]
*.[qQ][pP][wW]
*.[fF][mM][3tT]
*.[bB][iI][fF][fF][23458]
*.[rR][tT][fF]
*.[eE][tT]
*.[eE][tT][hH]
*.[nN][uU][mM][bB][eE][rR][sS]
*.[mM][oO][dD]
*.[dD][tT][aA]
*.123
*.htm
*.html

1
.gitmodules vendored

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

@ -11,6 +11,7 @@ node_modules
*.jsx
_book
book.json
v8.log
tmp
*.[tT][xX][tT]
*.[cC][sS][vV]
@ -19,6 +20,7 @@ tmp
*.[pP][mM][dD]*
*.[pP][dD][fF]
*.[sS][lL][kK]
*.[sS][yY][lL][kK]
*.socialcalc
*.[xX][lL][sSwWcCaAtTmMrR]
*.[xX][lL][sSaAtT][xXmMbB]
@ -32,6 +34,7 @@ tmp
*.[fF][mM][3tT]
*.[bB][iI][fF][fF][23458]
*.[rR][tT][fF]
*.[eE][tT]
*.[eE][tT][hH]
*.[nN][uU][mM][bB][eE][rR][sS]
*.[mM][oO][dD]
@ -58,11 +61,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,6 +54,7 @@ Rollup
SessionStorage
SQLite
SystemJS
Vite
VueJS
WebKit
WebSQL

@ -4,6 +4,60 @@ 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.20.1
* `init` use packaged test files to work around GitHub breaking changes
* SSF date code rounding to 15 decimal digits (h/t @davidtamaki)
* `sheet_to_json` force UTC interpretation for formatted strings (h/t @Blanay)
* QPW extract result of string formula
* XLSX parse non-compliant merge cell expressions
* NUMBERS correctly handle rows omitted from official exports
* DBF parse empty logical field (h/t @Roman91)
* `dense` option added to types
* package.json add mini and core scripts to export map (h/t @stof)
## v0.20.0
* Use UTC interpretation of Date objects for date cells (potentially breaking)
* API functions support UTC and local time value interpretations
* Export `NaN` values to `#NUM!` and infinite values to `#DIV/0!`
## v0.19.3
* XLSX Ensure comment address is valid (h/t @slonser)
* Enforce Excel worksheet name restrictions
* Fixed "Prototype Pollution" vulnerability (CVE-2023-30533)
## 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
@ -21,7 +75,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

@ -67,10 +67,9 @@ clean-data:
.PHONY: init
init: ## Initial setup for development
git submodule init
git submodule update
#git submodule foreach git pull origin master
git submodule foreach make all
rm -rf test_files
if [ ! -e test_files.zip ]; then curl -LO https://test-files.sheetjs.com/test_files.zip; fi
unzip test_files.zip
mkdir -p tmp
DISTHDR=misc/suppress_export.js
@ -107,12 +106,13 @@ dist-deps: ## Copy dependencies for distribution
.PHONY: aux
aux: $(AUXTARGETS)
BYTEFILEC=dist/xlsx.{full,core,mini}.min.js
BYTEFILER=dist/xlsx.extendscript.js xlsx.mjs
BYTEFILEC=dist/xlsx.{full,core,mini}.min.js xlsx.mjs
BYTEFILER=dist/xlsx.extendscript.js
.PHONY: bytes
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 -y esbuild@0.14.14 --bundle misc/import.js | wc -c)"
.PHONY: git
@ -140,6 +140,10 @@ test mocha: test.js ## Run test suite
#* To run tests for one format, make test_<fmt>
#* To run the core test suite, make test_misc
.PHONY: testdot
testdot: test.js ## Run test suite using dot reporter
mocha -R dot -t 30000
.PHONY: test-esm
test-esm: test.mjs ## Run Node ESM test suite
npx -y mocha@9 -R spec -t 30000 $<
@ -148,22 +152,27 @@ 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: hotcross.mjs ## Run Bun test suite
test-bun: testbun.mjs ## Run Bun test suite
bun $<
.PHONY: test-deno
test-deno: test.ts ## Run Deno test suite
deno test --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
deno test --check --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 --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
deno test --check --allow-env --allow-read --allow-write --config misc/test.deno.jsonc $<
TESTFMT=$(patsubst %,test_%,$(FMT))
.PHONY: $(TESTFMT)
$(TESTFMT): test_%:
FMTS=$* make test
TESTFMT=$(patsubst %,testdot_%,$(FMT))
.PHONY: $(TESTFMT)
$(TESTFMT): testdot_%:
FMTS=$* make testdot
TESTESMFMT=$(patsubst %,test-esm_%,$(FMT))
.PHONY: $(TESTESMFMT)
$(TESTESMFMT): test-esm_%:
@ -245,8 +254,7 @@ misc/coverage.html: $(TARGET) test.js
coveralls: ## Coverage Test + Send to coveralls.io
mocha --require blanket --reporter mocha-lcov-reporter -t 30000 | node ./node_modules/coveralls/bin/coveralls.js
DEMOMDS=$(sort $(wildcard demos/*/README.md))
MDLINT=$(DEMOMDS) README.md demos/README.md
MDLINT=README.md
.PHONY: mdlint
mdlint: $(MDLINT) ## Check markdown documents
./node_modules/.bin/alex $^

@ -9,35 +9,30 @@ 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)
## Documentation
- [API and Usage Documentation](https://docs.sheetjs.com)
- [Downloadable Scripts and Modules](https://cdn.sheetjs.com)
## Related Projects
## Constellation
- <https://oss.sheetjs.com/notes/>: File Format Notes
- [`ssf`](packages/ssf): Format data using ECMA-376 spreadsheet format codes
- [`xlsx-cli`](packages/xlsx-cli/): NodeJS command-line tool for processing files
- [`xlsx-cli`](packages/xlsx-cli): NodeJS command-line tool for processing files
- [`test_files`](https://github.com/SheetJS/test_files): Sample spreadsheets
- [`cfb`](https://git.sheetjs.com/SheetJS/js-cfb): Container (OLE/ZIP) file
processing library
- [`cfb`](https://github.com/SheetJS/js-cfb): Container (OLE/ZIP) format library
- [`codepage`](https://git.sheetjs.com/SheetJS/js-codepage): Legacy text
encodings for XLS and other legacy spreadsheet formats
- [`codepage`](https://github.com/SheetJS/js-codepage): Legacy text encodings
- [`dta`](packages/dta): Stata DTA file processor
- [`test_files`](https://github.com/sheetjs/test_files): Test files and various
plaintext baselines.
## License

@ -1,6 +1,6 @@
/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*exported XLSX */
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
var XLSX = {};
function make_xlsx_lib(XLSX){

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

@ -41,6 +41,11 @@ 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));

@ -45,6 +45,26 @@ function Base64_encode_pass(input) {
}
return o;
}
function Base64_encode_arr(input) {
var o = "";
var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;
for (var i = 0; i < input.length; ) {
c1 = input[i++];
e1 = c1 >> 2;
c2 = input[i++];
e2 = (c1 & 3) << 4 | c2 >> 4;
c3 = input[i++];
e3 = (c2 & 15) << 2 | c3 >> 6;
e4 = c3 & 63;
if (isNaN(c2)) {
e3 = e4 = 64;
} else if (isNaN(c3)) {
e4 = 64;
}
o += Base64_map.charAt(e1) + Base64_map.charAt(e2) + Base64_map.charAt(e3) + Base64_map.charAt(e4);
}
return o;
}
function Base64_decode(input) {
var o = "";
var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;

@ -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") { throw "wtf"; }
else if(typeof bufs[i] == "string") o.set(new Uint8Array(s2a(bufs[i])), maxlen);
else o.set(new Uint8Array(bufs[i]), maxlen);
}
return o;

@ -173,8 +173,20 @@ function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number
var q = Math.floor(sgn * P/Q);
return [q, sgn*P - q*Q, Q];
}
function SSF_normalize_xl_unsafe(v/*:number*/)/*:number*/ {
var s = v.toPrecision(16);
if(s.indexOf("e") > -1) {
var m = s.slice(0, s.indexOf("e"));
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
return m + s.slice(s.indexOf("e"));
}
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
return Number(n);
}
function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
if(v > 2958465 || v < 0) return null;
v = SSF_normalize_xl_unsafe(v);
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
var dout=[];
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
@ -203,15 +215,6 @@ function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
out.q = dow;
return out;
}
var SSFbasedate = /*#__PURE__*/new Date(1899, 11, 31, 0, 0, 0);
var SSFdnthresh = /*#__PURE__*/SSFbasedate.getTime();
var SSFbase1904 = /*#__PURE__*/new Date(1900, 2, 1, 0, 0, 0);
function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = /*#__PURE__*/v.getTime();
if(date1904) epoch -= 1461*24*60*60*1000;
else if(v >= SSFbase1904) epoch += 24*60*60*1000;
return (epoch - (SSFdnthresh + (/*#__PURE__*/v.getTimezoneOffset() - /*#__PURE__*/SSFbasedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
}
/* ECMA-376 18.8.30 numFmt*/
/* Note: `toPrecision` uses standard form when prec > E and E >= -6 */
/* exponent >= -9 and <= 9 */
@ -269,7 +272,7 @@ function SSF_general(v/*:any*/, opts/*:any*/) {
case 'undefined': return "";
case 'object':
if(v == null) return "";
if(v instanceof Date) return SSF_format(14, datenum_local(v, opts && opts.date1904), opts);
if(v instanceof Date) return SSF_format(14, datenum(v, opts && opts.date1904), opts);
}
throw new Error("unsupported value in General format: " + v);
}
@ -337,7 +340,7 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*
switch(fmt) {
case '[h]': case '[hh]': out = val.D*24+val.H; break;
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
default: throw 'bad abstime format: ' + fmt;
} outl = fmt.length === 3 ? 1 : 2; break;
case 101: /* 'e' era */
@ -785,10 +788,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
switch(out[i].t) {
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
case 's':
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
if(bt < 3) bt = 3;
/* falls through */
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
case 'd': case 'y': case 'e': lst=out[i].t; break;
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
case 'X': /*if(out[i].v === "B2");*/
break;
@ -798,19 +802,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
}
}
/* time rounding depends on presence of minute / second / usec fields */
var _dt;
switch(bt) {
case 0: break;
case 1:
/*::if(!dt) break;*/
case 2:
case 3:
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
case 2:
/*::if(!dt) break;*/
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
case 4:
switch(ss0) {
case 1: dt.u = Math.round(dt.u * 10)/10; break;
case 2: dt.u = Math.round(dt.u * 100)/100; break;
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
}
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
break;
}
@ -957,7 +971,7 @@ function SSF_format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
break;
}
if(SSF_isgeneral(sfmt,0)) return SSF_general(v, o);
if(v instanceof Date) v = datenum_local(v, o.date1904);
if(v instanceof Date) v = datenum(v, o.date1904);
var f = choose_fmt(sfmt, v);
if(SSF_isgeneral(f[1])) return SSF_general(v, o);
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";

@ -43,6 +43,7 @@ var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
function dateNF_regex(dateNF/*:string|number*/)/*:RegExp*/ {
var fmt = typeof dateNF == "number" ? table_fmt[dateNF] : dateNF;
fmt = fmt.replace(dateNFregex, "(\\d+)");
dateNFregex.lastIndex = 0;
return new RegExp("^" + fmt + "$");
}
function dateNF_fix(str/*:string*/, dateNF/*:string*/, match/*:Array<string>*/)/*:string*/ {
@ -55,6 +56,7 @@ function dateNF_fix(str/*:string*/, dateNF/*:string*/, match/*:Array<string>*/)/
case 'm': if(H >= 0) M = v; else m = v; break;
}
});
dateNFregex.lastIndex = 0;
if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
if(datestr.length == 7) datestr = "0" + datestr;

@ -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' ? 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' && typeof table.subarray == "function" ? 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);
sector_list[dir_start].name = "!Directory";
if(dir_start < sector_list.length) 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] = CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
crcs[fcnt] = typeof fi.content == "string" ? CRC32.bstr(fi.content, 0) : CRC32.buf(/*::((*/fi.content/*::||[]):any)*/, 0);
var outbuf = fi.content/*::||[]*/;
var outbuf = typeof fi.content == "string" ? s2a(fi.content) : fi.content/*::||[]*/;
if(method == 8) outbuf = _deflateRawSync(outbuf);
/* local file header */

@ -35,7 +35,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
/*:: declare var chrome: any; */
if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
return chrome.downloads.download({ url: url, filename: fname, saveAs: true });
}
var a = document.createElement("a");
if(a.download != null) {
@ -45,6 +45,10 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
return url;
}
} else if(typeof URL !== 'undefined' && !URL.createObjectURL && typeof chrome === 'object') {
/* manifest v3 extensions -- no URL.createObjectURL */
var b64 = "data:application/octet-stream;base64," + Base64_encode_arr(new Uint8Array(blobify(data)));
return chrome.downloads.download({ url: b64, filename: fname, saveAs: true });
}
}
// $FlowIgnore

@ -31,22 +31,19 @@ function evert_arr(obj/*:any*/)/*:EvertArrType*/ {
return o;
}
var basedate = /*#__PURE__*/new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
var dnthresh = /*#__PURE__*/Date.UTC(1899, 11, 30, 0, 0, 0); // -2209161600000
var dnthresh1 = /*#__PURE__*/Date.UTC(1899, 11, 31, 0, 0, 0); // -2209075200000
var dnthresh2 = /*#__PURE__*/Date.UTC(1904, 0, 1, 0, 0, 0); // -2209075200000
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
var epoch = /*#__PURE__*/v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = /*#__PURE__*/basedate.getTime() + (/*#__PURE__*/v.getTimezoneOffset() - /*#__PURE__*/basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) { res -= 1462; return res < -1402 ? res - 1 : res; }
return res < 60 ? res - 1 : res;
}
var refdate = /*#__PURE__*/new Date();
var dnthresh = /*#__PURE__*/basedate.getTime() + (/*#__PURE__*/refdate.getTimezoneOffset() - /*#__PURE__*/basedate.getTimezoneOffset()) * 60000;
var refoffset = /*#__PURE__*/refdate.getTimezoneOffset();
function numdate(v/*:number*/)/*:Date*/ {
function numdate(v/*:number*/)/*:Date|number*/ {
if(v >= 60 && v < 61) return v;
var out = new Date();
out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
if (out.getTimezoneOffset() !== refoffset) {
out.setTime(out.getTime() + (out.getTimezoneOffset() - refoffset) * 60000);
}
out.setTime((v>60 ? v : (v+1)) * 24 * 60 * 60 * 1000 + dnthresh);
return out;
}
@ -77,28 +74,22 @@ function parse_isodur(s) {
return sec;
}
var good_pd_date_1 = /*#__PURE__*/new Date('2017-02-19T19:06:09.000Z');
var good_pd_date = /*#__PURE__*/isNaN(/*#__PURE__*/good_pd_date_1.getFullYear()) ? /*#__PURE__*/new Date('2/19/17') : good_pd_date_1;
var good_pd = /*#__PURE__*/good_pd_date.getFullYear() == 2017;
/* parses a date as a local date */
function parseDate(str/*:string|Date*/, fixdate/*:?number*/)/*:Date*/ {
var d = new Date(str);
if(good_pd) {
/*:: if(fixdate == null) fixdate = 0; */
if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
return d;
}
/* Blame https://bugs.chromium.org/p/v8/issues/detail?id=7863 for the regexide */
var pdre1 = /^(\d+):(\d+)(:\d+)?(\.\d+)?$/; // HH:MM[:SS[.UUU]]
var pdre2 = /^(\d+)-(\d+)-(\d+)$/; // YYYY-mm-dd
var pdre3 = /^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+)(:\d+)?(\.\d+)?$/; // YYYY-mm-dd(T or space)HH:MM[:SS[.UUU]], sans "Z"
/* parses a date string as a UTC date */
function parseDate(str/*:string*/, date1904/*:boolean*/)/*:Date*/ {
if(str instanceof Date) return str;
if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
var s = d.getFullYear();
if(str.indexOf("" + s) > -1) return d;
d.setFullYear(d.getFullYear() + 100); return d;
}
var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
return out;
var m = str.match(pdre1);
if(m) return new Date((date1904 ? dnthresh2 : dnthresh1) + ((parseInt(m[1], 10)*60 + parseInt(m[2], 10))*60 + (m[3] ? parseInt(m[3].slice(1), 10) : 0))*1000 + (m[4] ? parseInt((m[4]+"000").slice(1,4), 10) : 0));
m = str.match(pdre2);
if(m) return new Date(Date.UTC(+m[1], +m[2]-1, +m[3], 0, 0, 0, 0));
/* TODO: 1900-02-29T00:00:00.000 should return a flag to treat as a date code (affects xlml) */
m = str.match(pdre3);
if(m) return new Date(Date.UTC(+m[1], +m[2]-1, +m[3], +m[4], +m[5], ((m[6] && parseInt(m[6].slice(1), 10))|| 0), ((m[7] && parseInt(m[7].slice(1), 10))||0)));
var d = new Date(str);
return d;
}
function cc2str(arr/*:Array<number>*/, debomit)/*:string*/ {
@ -129,8 +120,18 @@ function cc2str(arr/*:Array<number>*/, debomit)/*:string*/ {
return new TextDecoder("latin1").decode(arr).replace(/[€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ]/g, function(c) { return rev[c] || c; });
} catch(e) {}
var o = [];
for(var i = 0; i != arr.length; ++i) o.push(String.fromCharCode(arr[i]));
var o = [], i = 0;
// this cascade is for the browsers and runtimes of antiquity (and for modern runtimes that lack TextEncoder)
try {
for(i = 0; i < arr.length - 65536; i+=65536) o.push(String.fromCharCode.apply(0, arr.slice(i, i + 65536)));
o.push(String.fromCharCode.apply(0, arr.slice(i)));
} catch(e) { try {
for(; i < arr.length - 16384; i+=16384) o.push(String.fromCharCode.apply(0, arr.slice(i, i + 16384)));
o.push(String.fromCharCode.apply(0, arr.slice(i)));
} catch(e) {
for(; i != arr.length; ++i) o.push(String.fromCharCode(arr[i]));
}
}
return o.join("");
}
@ -160,32 +161,49 @@ function fuzzynum(s/*:string*/)/*:number*/ {
/* NOTE: Chrome rejects bare times like 1:23 PM */
var FDRE1 = /^(0?\d|1[0-2])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))\s+([ap])m?$/;
var FDRE2 = /^([01]?\d|2[0-3])(?:|:([0-5]?\d)(?:|(\.\d+)(?:|:([0-5]?\d))|:([0-5]?\d)(|\.\d+)))$/;
var FDISO = /^(\d+)-(\d+)-(\d+)[T ](\d+):(\d+)(:\d+)(\.\d+)?[Z]?$/; // YYYY-mm-dd(T or space)HH:MM:SS[.UUU][Z]
/* TODO: 1904 adjustment */
var utc_append_works = new Date("6/9/69 00:00 UTC").valueOf() == -17798400000;
function fuzzytime1(M) /*:Date*/ {
/* TODO: 1904 adjustment, keep in sync with base date */
if(!M[2]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0);
if(M[3]) {
if(M[4]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
else return new Date(1899,11,30,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
}
else if(M[5]) return new Date(1899,11,30, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
else return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
if(!M[2]) return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0));
if(M[3]) {
if(M[4]) return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000));
else return new Date(Date.UTC(1899,11,31,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000));
}
else if(M[5]) return new Date(Date.UTC(1899,11,31, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0));
else return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0));
}
function fuzzytime2(M) /*:Date*/ {
if(!M[2]) return new Date(Date.UTC(1899,11,31,+M[1], 0, 0, 0));
if(M[3]) {
if(M[4]) return new Date(Date.UTC(1899,11,31,+M[1], +M[2], +M[4], parseFloat(M[3])*1000));
else return new Date(Date.UTC(1899,11,31,0, +M[1], +M[2], parseFloat(M[3])*1000));
}
else if(M[5]) return new Date(Date.UTC(1899,11,31, +M[1], +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0));
else return new Date(Date.UTC(1899,11,31,+M[1], +M[2], 0, 0));
}
var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
function fuzzydate(s/*:string*/)/*:Date*/ {
// See issue 2863 -- this is technically not supported in Excel but is otherwise useful
if(FDISO.test(s)) return s.indexOf("Z") == -1 ? local_to_utc(new Date(s)) : new Date(s);
var lower = s.toLowerCase();
var lnos = lower.replace(/\s+/g, " ").trim();
var M = lnos.match(FDRE1);
if(M) return fuzzytime1(M);
var o = new Date(s), n = new Date(NaN);
M = lnos.match(FDRE2);
if(M) return fuzzytime2(M);
M = lnos.match(pdre3);
if(M) return new Date(Date.UTC(+M[1], +M[2]-1, +M[3], +M[4], +M[5], ((M[6] && parseInt(M[6].slice(1), 10))|| 0), ((M[7] && parseInt(M[7].slice(1), 10))||0)));
var o = new Date(utc_append_works && s.indexOf("UTC") == -1 ? s + " UTC": s), n = new Date(NaN);
var y = o.getYear(), m = o.getMonth(), d = o.getDate();
if(isNaN(d)) return n;
if(lower.match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) {
lower = lower.replace(/[^a-z]/g,"").replace(/([^a-z]|^)[ap]m?([^a-z]|$)/,"");
if(lower.length > 3 && lower_months.indexOf(lower) == -1) return n;
} else if(lower.replace(/[ap]m?/, "").match(/[a-z]/)) return n;
if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\]/)) return n;
if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\\ ]/)) return n;
return o;
}
@ -198,3 +216,10 @@ var split_regex = /*#__PURE__*/(function() {
return o;
};
})();
function utc_to_local(utc) {
return new Date(utc.getUTCFullYear(), utc.getUTCMonth(), utc.getUTCDate(), utc.getUTCHours(), utc.getUTCMinutes(), utc.getUTCSeconds(), utc.getUTCMilliseconds());
}
function local_to_utc(local) {
return new Date(Date.UTC(local.getFullYear(), local.getMonth(), local.getDate(), local.getHours(), local.getMinutes(), local.getSeconds(), local.getMilliseconds()));
}

@ -181,21 +181,29 @@ 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') {
} else if(f === 'sbcs' || f == 'cpstr') {
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 cppayload = $cptable.utils.encode(current_ansi, val.charAt(i));
this[this.l + i] = cppayload[0];
var cpp = $cptable.utils.encode(current_ansi, val.charAt(i));
this[this.l + i] = cpp[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,7 +9,6 @@ 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) {
@ -19,7 +18,6 @@ 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,11 +108,19 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
return { SheetNames: [n], Sheets: sheets };
}
function sheet_new(opts) {
var out = {};
var o = opts || {};
if(o.dense) out["!data"] = [];
return out;
}
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
var o = opts || {};
var dense = _ws ? Array.isArray(_ws) : o.dense;
var dense = _ws ? (_ws["!data"] != null) : o.dense;
if(DENSE != null && dense == null) dense = DENSE;
var ws/*:Worksheet*/ = _ws || (dense ? ([]/*:any*/) : ({}/*:any*/));
var ws/*:Worksheet*/ = _ws || ({}/*:any*/);
if(dense && !ws["!data"]) ws["!data"] = [];
var _R = 0, _C = 0;
if(ws && o.origin != null) {
if(typeof o.origin == 'number') _R = o.origin;
@ -133,13 +139,19 @@ 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 __R = _R + R, __C = _C + C;
var __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;
@ -157,17 +169,17 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
else if(typeof cell.v === 'boolean') cell.t = 'b';
else if(cell.v instanceof Date) {
cell.z = o.dateNF || table_fmt[14];
if(!o.UTC) cell.v = local_to_utc(cell.v);
if(o.cellDates) { cell.t = 'd'; cell.w = SSF_format(cell.z, datenum(cell.v, o.date1904)); }
else { cell.t = 'n'; cell.v = datenum(cell.v, o.date1904); cell.w = SSF_format(cell.z, cell.v); }
}
else cell.t = 's';
}
if(dense) {
if(!ws[__R]) ws[__R] = [];
if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z;
ws[__R][__C] = cell;
if(row[__C] && row[__C].z) cell.z = row[__C].z;
row[__C] = cell;
} else {
var cell_ref = encode_cell(({c:__C,r:__R}/*:any*/));
var cell_ref = encode_col(__C) + __Rstr/*:any*/;
if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z;
ws[cell_ref] = cell;
}

@ -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 = y.Target; rel.Id = y.Id; if(y.TargetMode) rel.TargetMode = y.TargetMode;
var rel = {}; rel.Type = y.Type; rel.Target = unescapexml(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,62 +1,61 @@
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
/* Part 3 Section 4 Manifest File */
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
function parse_manifest(d, opts) {
var str = xlml_normalize(d);
var Rn;
var FEtag;
while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
case 'manifest': break; // 4.2 <manifest:manifest>
case 'file-entry': // 4.3 <manifest:file-entry>
FEtag = parsexmltag(Rn[0], false);
if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
break;
case 'encryption-data': // 4.4 <manifest:encryption-data>
case 'algorithm': // 4.5 <manifest:algorithm>
case 'start-key-generation': // 4.6 <manifest:start-key-generation>
case 'key-derivation': // 4.7 <manifest:key-derivation>
throw new Error("Unsupported ODS Encryption");
default: if(opts && opts.WTF) throw Rn;
}
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/*: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_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("");
}
/* 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_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/*: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_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("");
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("");
}
/* 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>';
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,9 +1,20 @@
/* [MS-XLS] 2.5.19 */
function parse_XLSCell(blob/*::, length*/)/*:Cell*/ {
function parse_XLSCell(blob, length, opts)/*:Cell*/ {
var rw = blob.read_shift(2); // 0-indexed
var col = blob.read_shift(2);
var ixfe = blob.read_shift(2);
return ({r:rw, c:col, ixfe:ixfe}/*:any*/);
var ret = ({r:rw, c:col, ixfe:0}/*:any*/);
if(opts && opts.biff == 2 || length == 7) {
/* TODO: pass back flags */
var flags = blob.read_shift(1);
ret.ixfe = flags & 0x3F;
blob.l += 2;
/*
var ifntifmt = blob.read_shift(1);
var ifmt = ifntifmt & 0x3f, ifnt = ifntifmt >> 6;
var flags3 = blob.read_shift(1);
*/
} else ret.ixfe = blob.read_shift(2);
return ret;
}
function write_XLSCell(R/*:number*/, C/*:number*/, ixfe/*:?number*/, o) {
if(!o) o = new_buf(6);
@ -138,7 +149,7 @@ function parse_FtArray(blob, length/*::, ot*/) {
var ft = blob.read_shift(2);
blob.l-=2;
try {
fts.push(FtTab[ft](blob, tgt - blob.l));
fts[ft] = 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");
@ -228,6 +239,12 @@ function parse_WsBool(blob, length, opts) {
/* [MS-XLS] 2.4.28 */
function parse_BoundSheet8(blob, length, opts) {
var name = "";
if(opts.biff == 4) {
name = parse_ShortXLUnicodeString(blob, 0, opts);
if(name.length === 0) name = "Sheet1";
return { name:name };
}
var pos = blob.read_shift(4);
var hidden = blob.read_shift(1) & 0x03;
var dt = blob.read_shift(1);
@ -237,7 +254,7 @@ function parse_BoundSheet8(blob, length, opts) {
case 2: dt = 'Chartsheet'; break;
case 6: dt = 'VBAModule'; break;
}
var name = parse_ShortXLUnicodeString(blob, 0, opts);
name = parse_ShortXLUnicodeString(blob, 0, opts);
if(name.length === 0) name = "Sheet1";
return { pos:pos, hs:hidden, dt:dt, name:name };
}
@ -408,8 +425,8 @@ function write_Font(data, opts) {
}
/* [MS-XLS] 2.4.149 */
function parse_LabelSst(blob) {
var cell = parse_XLSCell(blob);
function parse_LabelSst(blob, length, opts) {
var cell = parse_XLSCell(blob, length, opts);
cell.isst = blob.read_shift(4);
return cell;
}
@ -424,8 +441,7 @@ function write_LabelSst(R/*:number*/, C/*:number*/, v/*:number*/, os/*:number*/
function parse_Label(blob, length, opts) {
if(opts.biffguess && opts.biff == 2) opts.biff = 5;
var target = blob.l + length;
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) blob.l++;
var cell = parse_XLSCell(blob, length, opts);
var str = parse_XLUnicodeString(blob, target - blob.l, opts);
cell.val = str;
return cell;
@ -459,6 +475,19 @@ function write_Format(i/*:number*/, f/*:string*/, opts, o) {
return out;
}
var parse_BIFF2Format = parse_XLUnicodeString2;
function write_BIFF2Format(f/*:string*/) {
var o = new_buf(1 + f.length);
o.write_shift(1, f.length);
o.write_shift(f.length, f, "sbcs");
return o;
}
function write_BIFF4Format(f/*:string*/) {
var o = new_buf(3 + f.length);
o.l += 2;
o.write_shift(1, f.length);
o.write_shift(f.length, f, "sbcs");
return o;
}
/* [MS-XLS] 2.4.90 */
function parse_Dimensions(blob, length, opts) {
@ -582,6 +611,44 @@ function write_XF(data, ixfeP, opts, o) {
o.write_shift(2, 0);
return o;
}
function parse_BIFF2XF(blob/*::, length, opts*/) {
var o = {};
o.ifnt = blob.read_shift(1); blob.l++; o.flags = blob.read_shift(1);
o.numFmtId = o.flags & 0x3F; o.flags>>=6;
o.fStyle = 0;
o.data = {}; // TODO
return o;
}
function write_BIFF2XF(xf) {
var o = new_buf(4);
o.l+=2;
o.write_shift(1, xf.numFmtId);
o.l++;
return o;
}
function write_BIFF3XF(xf) {
var o = new_buf(12);
o.l++;
o.write_shift(1, xf.numFmtId);
o.l += 10;
return o;
}
/* TODO: check other fields */
var write_BIFF4XF = write_BIFF3XF;
function parse_BIFF3XF(blob/*::, length, opts*/) {
var o = {};
o.ifnt = blob.read_shift(1); o.numFmtId = blob.read_shift(1); o.flags = blob.read_shift(2);
o.fStyle = (o.flags >> 2) & 0x01;
o.data = {}; // TODO
return o;
}
function parse_BIFF4XF(blob/*::, length, opts*/) {
var o = {};
o.ifnt = blob.read_shift(1); o.numFmtId = blob.read_shift(1); o.flags = blob.read_shift(2);
o.fStyle = (o.flags >> 2) & 0x01;
o.data = {}; // TODO
return o;
}
/* [MS-XLS] 2.4.134 */
function parse_Guts(blob) {
@ -602,8 +669,7 @@ function write_Guts(guts/*:Array<number>*/) {
/* [MS-XLS] 2.4.24 */
function parse_BoolErr(blob, length, opts) {
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2 || length == 9) ++blob.l;
var cell = parse_XLSCell(blob, 6, opts);
var val = parse_Bes(blob, 2);
cell.val = val;
cell.t = (val === true || val === false) ? 'b' : 'e';
@ -619,7 +685,7 @@ function write_BoolErr(R/*:number*/, C/*:number*/, v, os/*:number*/, opts, t/*:s
/* [MS-XLS] 2.4.180 Number */
function parse_Number(blob, length, opts) {
if(opts.biffguess && opts.biff == 2) opts.biff = 5;
var cell = parse_XLSCell(blob, 6);
var cell = parse_XLSCell(blob, 6, opts);
var xnum = parse_Xnum(blob, 8);
cell.val = xnum;
return cell;
@ -696,9 +762,11 @@ function parse_Lbl(blob, length, opts) {
};
}
/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
/* [MS-XLS] 2.4.106 TODO: legacy record 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];
@ -750,21 +818,34 @@ function parse_MTRSettings(blob) {
return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
}
/* [MS-XLS] 2.5.186 TODO: BIFF5 */
/* [MS-XLS] 2.5.186 */
function parse_NoteSh(blob, length, opts) {
if(opts.biff < 8) return;
var row = blob.read_shift(2), col = blob.read_shift(2);
var flags = blob.read_shift(2), idObj = blob.read_shift(2);
var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
if(opts.biff < 8) blob.read_shift(1);
return [{r:row,c:col}, stAuthor, idObj, flags];
}
/* [MS-XLS] 2.4.179 */
function parse_Note(blob, length, opts) {
if(opts && (opts.biff < 8)) {
var row = blob.read_shift(2), col = blob.read_shift(2);
if(row == 0xFFFF || row == -1) return; // TODO: test continuation
var cch = blob.read_shift(2);
var cmnt = blob.read_shift(Math.min(cch,2048), 'cpstr');
return [{r:row, c:col}, cmnt];
}
/* TODO: Support revisions */
return parse_NoteSh(blob, length, opts);
}
function write_NOTE_BIFF2(text/*:string*/, R/*:number*/, C/*:number*/, len/*?:number*/) {
var o = new_buf(6 + (len || text.length));
o.write_shift(2, R);
o.write_shift(2, C);
o.write_shift(2, len || text.length);
o.write_shift(text.length, text, "sbcs");
return o;
}
/* [MS-XLS] 2.4.168 */
function parse_MergeCells(blob, length)/*:Array<Range>*/ {
@ -1014,43 +1095,50 @@ function parse_ImData(blob) {
return o;
}
function write_BIFF2Cell(out, r/*:number*/, c/*:number*/, ixfe/*:number*/, ifmt/*:number*/) {
if(!out) out = new_buf(7);
out.write_shift(2, r);
out.write_shift(2, c);
out.write_shift(1, ixfe||0/* & 0x3F */);
out.write_shift(1, ifmt||0/* & 0x3F */);
out.write_shift(1, 0);
return out;
}
/* BIFF2_??? where ??? is the name from [XLS] */
function parse_BIFF2STR(blob, length, opts) {
if(opts.biffguess && opts.biff == 5) opts.biff = 2;
var cell = parse_XLSCell(blob, 6);
++blob.l;
var cell = parse_XLSCell(blob, 7, opts);
var str = parse_XLUnicodeString2(blob, length-7, opts);
cell.t = 'str';
cell.val = str;
return cell;
}
function parse_BIFF2NUM(blob/*::, length*/) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
function parse_BIFF2NUM(blob, length, opts) {
var cell = parse_XLSCell(blob, 7, opts);
var num = parse_Xnum(blob, 8);
cell.t = 'n';
cell.val = num;
return cell;
}
function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/) {
function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/, ixfe, ifmt) {
var out = new_buf(15);
write_BIFF2Cell(out, r, c);
write_BIFF2Cell(out, r, c, ixfe||0, ifmt||0);
out.write_shift(8, val, 'f');
return out;
}
function parse_BIFF2INT(blob) {
var cell = parse_XLSCell(blob, 6);
++blob.l;
function parse_BIFF2INT(blob, length, opts) {
var cell = parse_XLSCell(blob, 7, opts);
var num = blob.read_shift(2);
cell.t = 'n';
cell.val = num;
return cell;
}
function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/) {
function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/, ixfe/*:number*/, ifmt/*:number*/) {
var out = new_buf(9);
write_BIFF2Cell(out, r, c);
write_BIFF2Cell(out, r, c, ixfe||0, ifmt||0);
out.write_shift(2, val);
return out;
}
@ -1061,6 +1149,16 @@ function parse_BIFF2STRING(blob) {
return blob.read_shift(cch, 'sbcs-cont');
}
function parse_BIFF2BOOLERR(blob, length, opts) {
var bestart = blob.l + 7;
var cell = parse_XLSCell(blob, 6, opts);
blob.l = bestart;
var val = parse_Bes(blob, 2);
cell.val = val;
cell.t = (val === true || val === false) ? 'b' : 'e';
return cell;
}
/* TODO: convert to BIFF8 font struct */
function parse_BIFF2FONTXTRA(blob, length) {
blob.l += 6; // unknown
@ -1074,7 +1172,7 @@ function parse_BIFF2FONTXTRA(blob, length) {
/* TODO: parse rich text runs */
function parse_RString(blob, length, opts) {
var end = blob.l + length;
var cell = parse_XLSCell(blob, 6);
var cell = parse_XLSCell(blob, 6, opts);
var cch = blob.read_shift(2);
var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
blob.l = end;
@ -1082,3 +1180,10 @@ function parse_RString(blob, length, opts) {
cell.val = str;
return cell;
}
function parse_BIFF4SheetInfo(blob/*::, length, opts*/) {
var flags = blob.read_shift(4);
var cch = blob.read_shift(1), name = blob.read_shift(cch, "sbcs");
if(name.length === 0) name = "Sheet1";
return { flags: flags, name:name };
}

@ -1,4 +1,3 @@
/* 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 = {
@ -180,7 +179,10 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
if(s.trim().length) out[R][C] = s.replace(/\s+$/,"");
break;
case 'D':
if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
if(s.length === 8) {
out[R][C] = new Date(Date.UTC(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8), 0, 0, 0, 0));
if(!(opts && opts.UTC)) { out[R][C] = utc_to_local(out[R][C]); }
}
else out[R][C] = s;
break;
case 'F': out[R][C] = parseFloat(s.trim()); break;
@ -188,7 +190,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
case 'L': switch(s.trim().toUpperCase()) {
case 'Y': case 'T': out[R][C] = true; break;
case 'N': case 'F': out[R][C] = false; break;
case '': case '?': break;
case '': case '\x00': case '?': break;
default: throw new Error("DBF Unrecognized L:|" + s + "|");
} break;
case 'M': /* TODO: handle memo files */
@ -203,7 +205,12 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
// NOTE: dBASE specs appear to be incorrect
out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400);
break;
case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
case 'T': {
var hi = dd.read_shift(4), lo = dd.read_shift(4);
if(hi == 0 && lo == 0) break;
out[R][C] = new Date((hi - 0x253D8C) * 0x5265C00 + lo);
if(!(opts && opts.UTC)) out[R][C] = utc_to_local(out[R][C]);
} break;
case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4 + (dd.read_shift(4, 'i')/1e4)*Math.pow(2,32); break;
case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
@ -239,14 +246,15 @@ 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*/) {
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
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();
@ -282,7 +290,8 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
default: _guess = 'C';
}
maxlen = Math.max(maxlen, String(col[j]).length);
/* 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);
guess = guess && guess != _guess ? 'C' : _guess;
//if(guess == 'C') break;
}
@ -308,11 +317,17 @@ 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);
h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[/*::String(*/current_ansi/*::)*/] || 0x03)<<8));
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;
}
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");
@ -341,6 +356,7 @@ 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;
@ -352,13 +368,16 @@ 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, "sbcs");
for(hcnt=0; hcnt < colwidths[j]-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
rout.write_shift(1, _s, "cpstr");
_l += colwidths[j] - rout.l;
for(hcnt=0; hcnt < _l; ++hcnt) rout.write_shift(1, 0x20); break;
}
}
// data
}
current_codepage = old_cp;
ba.next(1).write_shift(1, 0x1A);
return ba.end();
}
@ -391,10 +410,15 @@ var SYLK = /*#__PURE__*/(function() {
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
}/*:any*/);
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
try {
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
} catch(e) {}
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
sylk_escapes["|"] = 254;
/* TODO: evert the escape map */
var encode_sylk_str = function($$) { return $$.replace(/\n/g, "\x1b :").replace(/\r/g, "\x1b ="); };
/* https://oss.sheetjs.com/notes/sylk/ for more details */
function sylk_to_aoa(d/*:RawData*/, opts)/*:[AOA, Worksheet]*/ {
switch(opts.type) {
@ -447,8 +471,9 @@ var SYLK = /*#__PURE__*/(function() {
// case 'NU': // ??
case 'C': /* cell */
var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1, formula = "", cell_t = "z";
var cmnt = "";
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
case 'A': break; // TODO: comment
case 'A': cmnt = record[rj].slice(1); break; // TODO: comment
case 'X': C = parseInt(record[rj].slice(1), 10)-1; C_seen_X = true; break;
case 'Y':
R = parseInt(record[rj].slice(1), 10)-1; if(!C_seen_X) C = 0;
@ -460,10 +485,9 @@ var SYLK = /*#__PURE__*/(function() {
else if(val === 'TRUE' || val === 'FALSE') { val = val === 'TRUE'; cell_t = "b"; }
else if(!isNaN(fuzzynum(val))) {
val = fuzzynum(val); cell_t = "n";
if(next_cell_format !== null && fmt_is_date(next_cell_format) && opts.cellDates) { val = numdate(wb.Workbook.WBProps.date1904 ? val + 1462 : val); cell_t = "d"; }
} else if(!isNaN(fuzzydate(val).getDate())) {
val = parseDate(val); cell_t = "d";
if(!opts.cellDates) { cell_t = "n"; val = datenum(val, wb.Workbook.WBProps.date1904); }
if(next_cell_format !== null && fmt_is_date(next_cell_format) && opts.cellDates) {
val = numdate(wb.Workbook.WBProps.date1904 ? val + 1462 : val); cell_t = typeof val == "number" ? "n" : "d";
}
}
if(typeof $cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = $cptable.utils.decode(opts.codepage, val);
C_seen_K = true;
@ -499,6 +523,10 @@ var SYLK = /*#__PURE__*/(function() {
if(!arr[R][C]) arr[R][C] = { t: 'n', f: formula };
else arr[R][C].f = formula;
}
if(cmnt) {
if(!arr[R][C]) arr[R][C] = { t: 'z' };
arr[R][C].c = [{a:"SheetJSYLK", t: cmnt}];
}
break;
case 'F': /* Format */
var F_seen = 0;
@ -560,7 +588,7 @@ var SYLK = /*#__PURE__*/(function() {
return outwb;
}
function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*//*::, opts*/)/*:string*/ {
function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*/, opts, date1904/*:boolean*/)/*:string*/ {
var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
switch(cell.t) {
case 'n':
@ -568,12 +596,19 @@ var SYLK = /*#__PURE__*/(function() {
if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
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.replace(/"/g,"").replace(/;/g, ";;") + '"'; break;
case 'd': o += datenum(parseDate(cell.v, date1904), date1904); break;
case 's': o += '"' + (cell.v == null ? "" : String(cell.v)).replace(/"/g,"").replace(/;/g, ";;") + '"'; break;
}
return o;
}
function write_ws_cmnt_sylk(cmnt/*:Comment*/, R/*:number*/, C/*:number*/)/*:string*/ {
var o = "C;Y" + (R+1) + ";X" + (C+1) + ";A";
/* TODO: max length? */
o += encode_sylk_str(cmnt.map(function(c) { return c.t; }).join(""));
return o;
}
function write_ws_cols_sylk(out, cols) {
cols.forEach(function(col, i) {
var rec = "F;W" + (i+1) + " " + (i+1) + " ";
@ -598,29 +633,52 @@ var SYLK = /*#__PURE__*/(function() {
}
function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/, wb/*:?WorkBook*/)/*:string*/ {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble/*:Array<string>*/ = ["ID;PSheetJS;N;E"], o/*:Array<string>*/ = [];
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = Array.isArray(ws);
var r = safe_decode_range(ws['!ref']||"A1"), cell/*:Cell*/;
var dense = ws["!data"] != null;
var RS = "\r\n";
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
var _lastfmt = "General";
preamble.push("P;PGeneral");
/* Excel has been inconsistent in comment placement */
var R = r.s.r, C = r.s.c, p = [];
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
if(!cell || !cell.c) continue;
p.push(write_ws_cmnt_sylk(cell.c, R, C));
}
if(p.length) o.push(p.join(RS));
}
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
p = [];
for(C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
if((cell.z||(cell.t == "d" ? table_fmt[14] : "General")) != _lastfmt) {
var ifmt = opts._formats.indexOf(cell.z);
if(ifmt == -1) { opts._formats.push(cell.z); ifmt = opts._formats.length - 1; preamble.push("P;P" + cell.z.replace(/;/g, ";;")); }
p.push("F;P" + ifmt + ";Y" + (R+1) + ";X" + (C+1));
}
p.push(write_ws_cell_sylk(cell, ws, R, C, opts, d1904));
}
o.push(p.join(RS));
}
preamble.push("F;P0;DG0G8;M255");
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
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(" "));
if(ws["!ref"]) 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) {
var p = [];
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 || (cell.v == null && (!cell.f || cell.F))) continue;
p.push(write_ws_cell_sylk(cell, ws, R, C, opts)); // TODO: pass date1904 info
}
o.push(p.join(RS));
}
delete opts._formats;
return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
}
@ -660,7 +718,10 @@ var DIF = /*#__PURE__*/(function() {
if(data === 'TRUE') arr[R][C] = true;
else if(data === 'FALSE') arr[R][C] = false;
else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
else if(!isNaN(fuzzydate(value).getDate())) {
arr[R][C] = parseDate(value);
if(!(opts && opts.UTC)) { arr[R][C] = utc_to_local(arr[R][C]); }
}
else arr[R][C] = value;
++C; break;
case 1:
@ -683,62 +744,56 @@ var DIF = /*#__PURE__*/(function() {
return o;
}
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, "");
}
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;
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
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\"\"");
}
p += "\r\n";
}
push_value(o, -1, 0, "EOD");
var RS = "\r\n";
var oo = o.join(RS);
//while((oo.length & 0x7F) != 0) oo += "\0";
return oo;
};
})();
o.push(p);
}
return o.join("") + "-1,0\r\nEOD";
}
return {
to_workbook: dif_to_workbook,
to_sheet: dif_to_sheet,
@ -801,11 +856,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 = Array.isArray(ws);
var dense = ws["!data"] != null;
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[R]||[])[C] : ws[coord];
cell = dense ? (ws["!data"][R]||[])[C] : ws[coord];
if(!cell || cell.v == null || cell.t === 'z') continue;
oo = ["cell", coord, 't'];
switch(cell.t) {
@ -927,7 +982,8 @@ var PRN = /*#__PURE__*/(function() {
var o = opts || {};
var sep = "";
if(DENSE != null && o.dense == null) o.dense = DENSE;
var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
var ws/*:Worksheet*/ = ({}/*:any*/);
if(o.dense) ws["!data"] = [];
var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
if(str.slice(0,4) == "sep=") {
@ -947,33 +1003,35 @@ var PRN = /*#__PURE__*/(function() {
var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0, startcc=str.charCodeAt(0);
var _re/*:?RegExp*/ = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
function finish_cell() {
/* TODO: fuzzy parsers should pass back assumed number format */
var s = str.slice(start, end); if(s.slice(-1) == "\r") s = s.slice(0, -1);
var cell = ({}/*:any*/);
if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
if(o.cellText !== false) cell.w = s;
if(s.length === 0) cell.t = 'z';
else if(o.raw) { cell.t = 's'; cell.v = s; }
else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
else if(s.charCodeAt(0) == 0x3D) {
if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
else if(fuzzyfmla(s)) { cell.t = 's'; cell.f = s.slice(1); cell.v = s; }
else { cell.t = 's'; cell.v = s; } }
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; cell.v = v; }
else if(!isNaN((v = fuzzydate(s)).getDate()) || _re && s.match(_re)) {
cell.z = o.dateNF || table_fmt[14];
var k = 0;
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; v = parseDate(s, k); }
if(_re && s.match(_re)){ var news=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); v = parseDate(news); if(o && o.UTC === false) v = utc_to_local(v); }
else if(o && o.UTC === false) v = utc_to_local(v);
else if(o.cellText !== false && o.dateNF) cell.w = SSF_format(cell.z, v);
if(o.cellDates) { cell.t = 'd'; cell.v = v; }
else { cell.t = 'n'; cell.v = datenum(v); }
if(o.cellText !== false) cell.w = SSF_format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
if(!o.cellNF) delete cell.z;
} else {
cell.t = 's';
cell.v = s;
}
if(cell.t == 'z'){}
else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
else if(o.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][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;
@ -1028,13 +1086,14 @@ var PRN = /*#__PURE__*/(function() {
function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
var o/*:Array<string>*/ = [];
if(!ws["!ref"]) return "";
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
var dense = Array.isArray(ws);
var dense = ws["!data"] != null;
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[R]||[])[C] : ws[coord];
cell = dense ? (ws["!data"][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 += " ";

@ -24,15 +24,33 @@ var WK_ = /*#__PURE__*/(function() {
throw "Unsupported type " + opts.type;
}
/* NOTE: this list intentionally starts at 1 */
var LOTUS_DATE_FMTS = [
"mmmm",
"dd-mmm-yyyy",
"dd-mmm",
"mmm-yyyy",
"@", // "text"?
"mm/dd",
"hh:mm:ss AM/PM", // 7
"hh:mm AM/PM",
"mm/dd/yyyy",
"mm/dd",
"hh:mm:ss",
"hh:mm" // 12
];
function lotus_to_workbook_buf(d, opts)/*:Workbook*/ {
if(!d) return d;
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/), n = "Sheet1", next_n = "", sidx = 0;
var sheets = {}, snames = [], realnames = [];
var s/*:Worksheet*/ = ({}/*:any*/), n = "Sheet1", next_n = "", sidx = 0;
var sheets = {}, snames = [], realnames = [], sdata = [];
if(o.dense) sdata = s["!data"] = [];
var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
var sheetRows = o.sheetRows || 0;
var lastcell = {};
if(d[4] == 0x51 && d[5] == 0x50 && d[6] == 0x57) return qpw_to_workbook_buf(d, opts);
if(d[2] == 0x00) {
@ -64,9 +82,9 @@ var WK_ = /*#__PURE__*/(function() {
case 0x0E: /* NUMBER */
case 0x10: /* FORMULA */
/* TODO: actual translation of the format code */
if(RT == 0x0E && (val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
val[1].z = o.dateNF || table_fmt[14];
if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
if((val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
val[1].z = o.dateNF || LOTUS_DATE_FMTS[(val[2] & 0x0F)-1] || table_fmt[14];
if(o.cellDates) { val[1].v = numdate(val[1].v); val[1].t = typeof val[1].v == "number" ? 'n' : 'd'; }
}
if(o.qpro) {
@ -74,26 +92,36 @@ var WK_ = /*#__PURE__*/(function() {
s["!ref"] = encode_range(refguess);
sheets[n] = s;
snames.push(n);
s = (o.dense ? [] : {});
s = ({}/*:any*/); if(o.dense) sdata = s["!data"] = [];
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 ? (s[val[0].r]||[])[val[0].c] : s[encode_cell(val[0])];
var tmpcell = o.dense ? (sdata[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;
if(val[1].f != null) tmpcell.f = val[1].f;
lastcell = tmpcell;
break;
}
if(o.dense) {
if(!s[val[0].r]) s[val[0].r] = [];
s[val[0].r][val[0].c] = val[1];
if(!sdata[val[0].r]) sdata[val[0].r] = [];
sdata[val[0].r][val[0].c] = val[1];
} else s[encode_cell(val[0])] = val[1];
lastcell = val[1];
break;
case 0x5405: o.works2 = true; break;
default:
case 0x5402: {
/* TODO: enumerate all extended number formats */
if(val == 0x14a1) {
lastcell.z = "hh:mm:ss";
if(o.cellDates && lastcell.t == "n") {
lastcell.v = numdate(lastcell.v); lastcell.t = typeof lastcell.v == "number" ? 'n' : 'd';
}
}
} break;
}}, o);
} else if(d[2] == 0x1A || d[2] == 0x0E) {
o.Enum = WK3Enum;
@ -115,14 +143,14 @@ var WK_ = /*#__PURE__*/(function() {
s["!ref"] = encode_range(refguess);
sheets[n] = s;
snames.push(n);
s = (o.dense ? [] : {});
s = ({}/*:any*/); if(o.dense) sdata = s["!data"] = [];
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(!s[val[0].r]) s[val[0].r] = [];
s[val[0].r][val[0].c] = val[1];
if(!sdata[val[0].r]) sdata[val[0].r] = [];
sdata[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;
@ -156,25 +184,32 @@ var WK_ = /*#__PURE__*/(function() {
if(+o.codepage >= 0) set_cp(+o.codepage);
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
var ba = buf_array();
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to WK1");
var range = safe_decode_range(ws["!ref"]);
var dense = Array.isArray(ws);
var dense = ws["!data"] != null;
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(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];
for(C = range.s.c; C <= range.e.c; ++C) {
var cell = dense ? (ws["!data"][R]||[])[C] : ws[cols[C] + rr];
if(!cell || cell.t == "z") continue;
/* TODO: formula records */
if(cell.t == "n") {
if((cell.v|0)==cell.v && cell.v >= -32768 && cell.v <= 32767) write_biff_rec(ba, 0x0d, write_INTEGER(R, C, cell.v));
else write_biff_rec(ba, 0x0e, write_NUMBER(R, C, cell.v));
} else {
switch(cell.t) {
case "n":
if((cell.v|0)==cell.v && cell.v >= -32768 && cell.v <= 32767) write_biff_rec(ba, 0x0d, write_INTEGER(R, C, cell));
else write_biff_rec(ba, 0x0e, write_NUMBER(R, C, cell));
break;
case "d":
var dc = datenum(cell.v);
if((dc|0)==dc && dc >= -32768 && dc <= 32767) write_biff_rec(ba, 0x0d, write_INTEGER(R, C, {t:"n", v:dc, z:cell.z || table_fmt[14]}));
else write_biff_rec(ba, 0x0e, write_NUMBER(R, C, {t:"n", v:dc, z:cell.z || table_fmt[14]}));
break;
default:
var str = format_cell(cell);
write_biff_rec(ba, 0x0F, write_LABEL(R, C, str.slice(0, 239)));
}
@ -200,7 +235,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 = Array.isArray(ws);
var dense = ws["!data"] != null;
var cols = [];
var max_R = Math.min(range.e.r, 8191);
for(var R = range.s.r; R <= max_R; ++R) {
@ -208,7 +243,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[R]||[])[C] : ws[ref];
var cell = dense ? (ws["!data"][R]||[])[C] : ws[ref];
if(!cell || cell.t == "z") continue;
/* TODO: FORMULA19 NUMBER18 records */
if(cell.t == "n") {
@ -308,11 +343,18 @@ var WK_ = /*#__PURE__*/(function() {
return o;
}
function get_wk1_fmt(cell)/*:number*/ {
/* TODO: some fuzzy matching on the number format */
if(cell.z && fmt_is_date(cell.z)) {
return 0xf0 | (LOTUS_DATE_FMTS.indexOf(cell.z) + 1 || 2);
}
return 0xFF;
}
function parse_LABEL(blob, length, opts) {
var tgt = blob.l + length;
var o = parse_cell(blob, length, opts);
o[1].t = 's';
if(opts.vers == 0x5120) {
if((opts.vers & 0xFFFE) == 0x5120) { // WQ1 / WQ2
blob.l++;
var len = blob.read_shift(1);
o[1].v = blob.read_shift(len, 'utf8');
@ -354,12 +396,12 @@ var WK_ = /*#__PURE__*/(function() {
o[1].v = blob.read_shift(2, 'i');
return o;
}
function write_INTEGER(R, C, v) {
function write_INTEGER(R, C, cell) {
var o = new_buf(7);
o.write_shift(1, 0xFF);
o.write_shift(1, get_wk1_fmt(cell));
o.write_shift(2, C);
o.write_shift(2, R);
o.write_shift(2, v, 'i');
o.write_shift(2, cell.v, 'i');
return o;
}
@ -368,12 +410,12 @@ var WK_ = /*#__PURE__*/(function() {
o[1].v = blob.read_shift(8, 'f');
return o;
}
function write_NUMBER(R, C, v) {
function write_NUMBER(R, C, cell) {
var o = new_buf(13);
o.write_shift(1, 0xFF);
o.write_shift(1, get_wk1_fmt(cell));
o.write_shift(2, C);
o.write_shift(2, R);
o.write_shift(8, v, 'f');
o.write_shift(8, cell.v, 'f');
return o;
}
@ -426,7 +468,7 @@ var WK_ = /*#__PURE__*/(function() {
0x33: ["FALSE", 0],
0x34: ["TRUE", 0],
0x35: ["RAND", 0],
// 0x36 DATE
0x36: ["DATE", 3],
// 0x37 NOW
// 0x38 PMT
// 0x39 PV
@ -436,7 +478,7 @@ var WK_ = /*#__PURE__*/(function() {
// 0x3D MONTH
// 0x3E YEAR
0x3F: ["ROUND", 2],
// 0x40 TIME
0x40: ["TIME", 3],
// 0x41 HOUR
// 0x42 MINUTE
// 0x43 SECOND
@ -778,13 +820,24 @@ var WK_ = /*#__PURE__*/(function() {
/*::[*/0x0048/*::]*/: { n:"ACOMM" },
/*::[*/0x0049/*::]*/: { n:"AMACRO" },
/*::[*/0x004A/*::]*/: { n:"PARSE" },
// 0x0064
/*::[*/0x0066/*::]*/: { n:"PRANGES??" },
/*::[*/0x0067/*::]*/: { n:"RRANGES??" },
/*::[*/0x0068/*::]*/: { n:"FNAME??" },
/*::[*/0x0069/*::]*/: { n:"MRANGES??" },
// 0x0096
// 0x0099
// 0x009A
// 0x009B
// 0x009C
// 0x00C0
// 0x00C7
// 0x00C9
/*::[*/0x00CC/*::]*/: { n:"SHEETNAMECS", f:parse_SHEETNAMECS },
// 0x00CD
/*::[*/0x00DE/*::]*/: { n:"SHEETNAMELP", f:parse_SHEETNAMELP },
/*::[*/0x00FF/*::]*/: { n:"BOF", f:parseuint16 },
/*::[*/0x5402/*::]*/: { n:"WKSNF", f:parseuint16 },
/*::[*/0xFFFF/*::]*/: { n:"" }
};
@ -914,16 +967,47 @@ var WK_ = /*#__PURE__*/(function() {
/*::[*/0xFFFF/*::]*/: { n:"" }
};
/* TODO: fill out and verify this table across QP versions */
var QPWNFTable = {
/*::[*/0x05/*::*/: "dd-mmm-yy",
/*::[*/0x06/*::*/: "dd-mmm",
/*::[*/0x07/*::*/: "mmm-yy",
/*::[*/0x08/*::*/: "mm/dd/yy", // Long Date Intl
/*::[*/0x0A/*::*/: "hh:mm:ss AM/PM",
/*::[*/0x0B/*::*/: "hh:mm AM/PM",
/*::[*/0x0E/*::*/: "dd-mmm-yyyy",
/*::[*/0x0F/*::*/: "mmm-yyyy",
/* It is suspected that the the low nybble specifies decimal places */
/*::[*/0x0022/*::*/: "0.00",
/*::[*/0x0032/*::*/: "0.00;[Red]0.00",
/*::[*/0x0042/*::*/: "0.00;\(0.00\)",
/*::[*/0x0052/*::*/: "0.00;[Red]\(0.00\)",
/*::[*/0x00A2/*::*/: '"$"#,##0.00;\\("$"#,##0.00\\)',
/*::[*/0x0120/*::*/: '0%',
/*::[*/0x0130/*::*/: '0E+00',
/*::[*/0x0140/*::*/: '# ?/?'
};
function parse_qpw_str(p) {
var cch = p.read_shift(2);
var flags = p.read_shift(1);
/* TODO: find examples with nonzero flags */
if(flags != 0) throw "unsupported QPW string type " + flags.toString(16);
return p.read_shift(cch, "sbcs-cont");
}
/* QPW uses a different set of record types */
function qpw_to_workbook_buf(d, opts)/*:Workbook*/ {
prep_blob(d, 0);
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/);
var s/*:Worksheet*/ = ({}/*:any*/); if(o.dense) s["!data"] = [];
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;
var wb = { SheetNames: [], Sheets: {} };
var FMTS = [];
outer: while(d.l < d.length) {
var RT = d.read_shift(2), length = d.read_shift(2);
var p = d.slice(d.l, d.l + length);
@ -934,6 +1018,22 @@ var WK_ = /*#__PURE__*/(function() {
break;
case 0x02: /* EOF */ break outer;
case 0x08: /* NF */ break; // TODO: this is tied to custom number formats
case 0x0A: /* FORMATS */ {
var fcnt = p.read_shift(4);
var step = ((p.length - p.l)/ fcnt)|0;
for(var ifmt = 0; ifmt < fcnt; ++ifmt) {
var end = p.l + step;
var fmt = {};
p.l += 2;
fmt.numFmtId = p.read_shift(2);
if(QPWNFTable[fmt.numFmtId]) fmt.z = QPWNFTable[fmt.numFmtId];
p.l = end;
FMTS.push(fmt);
}
} break;
/* TODO: The behavior here should be consistent with Numbers: QP Notebook ~ .TN.SheetArchive, QP Sheet ~ .TST.TableModelArchive */
case 0x0401: /* BON */ break;
case 0x0402: /* EON */ /* TODO: backfill missing sheets based on BON cnt */ break;
@ -956,7 +1056,7 @@ var WK_ = /*#__PURE__*/(function() {
case 0x0601: { /* BOS */
var sidx = p.read_shift(2);
s = ((o.dense ? [] : {})/*:any*/);
s = ({}/*:any*/); if(o.dense) s["!data"] = [];
range.s.c = p.read_shift(2);
range.e.c = p.read_shift(2);
range.s.r = p.read_shift(4);
@ -993,20 +1093,28 @@ 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);
if(flags & 0x80) p.l += 2;
var flags = p.read_shift(1), fmtidx = -1;
if(flags & 0x80) fmtidx = p.read_shift(2);
var mul = (flags & 0x40) ? p.read_shift(2) - 1: 0;
switch(flags & 0x1F) {
case 0: break;
case 1: break;
case 2: cell = { t: "n", v: p.read_shift(2) }; break;
case 3: cell = { t: "n", v: p.read_shift(2, 'i') }; break;
case 4: cell = { t: "n", v: parse_RkNumber(p) }; break;
case 5: cell = { t: "n", v: p.read_shift(8, 'f') }; break;
case 7: cell = { t: "s", v: SST[type = p.read_shift(4) - 1] }; break;
case 8: cell = { t: "n", v: p.read_shift(8, 'f') }; p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4; break;
case 8:
cell = { t: "n", v: p.read_shift(8, 'f') };
p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4;
if(isNaN(cell.v)) cell = { t: "e", v: 0x0F }; // #VALUE!
break;
default: throw "Unrecognized QPW cell type " + (flags & 0x1F);
}
if(fmtidx != -1 && (FMTS[fmtidx - 1]||{}).z) cell.z = FMTS[fmtidx-1].z;
var delta = 0;
if(flags & 0x20) switch(flags & 0x1F) {
case 2: delta = p.read_shift(2); break;
@ -1015,10 +1123,14 @@ var WK_ = /*#__PURE__*/(function() {
default: throw "Unsupported delta for QPW cell type " + (flags & 0x1F);
}
if(!(!o.sheetStubs && cell.t == "z")) {
if(Array.isArray(s)) {
if(!s[R]) s[R] = [];
s[R][C] = cell;
} else s[encode_cell({r:R, c:C})] = cell;
var newcell = dup(cell);
if(cell.t == "n" && cell.z && fmt_is_date(cell.z) && o.cellDates) {
newcell.v = numdate(cell.v); newcell.t = typeof newcell.v == "number" ? 'n' : 'd';
}
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = newcell;
} else s[CC + encode_row(R)] = newcell;
}
++R; --cnt;
while(mul-- > 0 && cnt >= 0) {
@ -1033,17 +1145,29 @@ var WK_ = /*#__PURE__*/(function() {
case 7: cell = { t: "s", v: SST[type = p.read_shift(4) - 1] }; break;
default: throw "Cannot apply repeat for QPW cell type " + (flags & 0x1F);
}
if(fmtidx != -1);
if(!(!o.sheetStubs && cell.t == "z")) {
if(Array.isArray(s)) {
if(!s[R]) s[R] = [];
s[R][C] = cell;
} else s[encode_cell({r:R, c:C})] = cell;
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = cell;
} else s[CC + encode_row(R)] = cell;
}
++R; --cnt;
}
}
} break;
case 0x0C02: { /* String (result of string formula expression) */
C = p.read_shift(2);
R = p.read_shift(4);
var str = parse_qpw_str(p);
/* TODO: QP10 record has an additional unknown character after the string */
if(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];
s["!data"][R][C] = { t:"s", v:str };
} else s[encode_col(C) + encode_row(R)] = { t:"s", v:str };
} break;
default: break;
}
d.l += length;

@ -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>/;
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r\b[^>]*>/;
var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
function parse_si(x, opts) {
var html = opts ? opts.cellHTML : true;
@ -229,6 +229,7 @@ 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,14 +13,18 @@ function rtf_to_sheet(d, opts) {
}
function rtf_to_sheet_str(str, opts) {
var o = opts || {};
var ws = o.dense ? [] : {};
var ws = {};
var dense = o.dense;
if (dense)
ws["!data"] = [];
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 (Array.isArray(ws))
ws[R] = [];
if (dense)
row = ws["!data"][R] = [];
var rtfre = /\\[\w\-]+\b/g;
var last_index = 0;
var res;
@ -46,8 +50,8 @@ function rtf_to_sheet_str(str, opts) {
cell.w = cell.v;
cell.v = fuzzynum(cell.v);
}
if (Array.isArray(ws))
ws[R][C] = cell;
if (dense)
row[C] = cell;
else
ws[encode_cell({ r: R, c: C })] = cell;
}
@ -75,15 +79,17 @@ function sheet_to_rtf(ws, opts) {
if (!ws["!ref"])
return o[0] + "}";
var r = safe_decode_range(ws["!ref"]), cell;
var dense = Array.isArray(ws);
var dense = ws["!data"] != null, row = [];
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 ? (ws[R] || [])[C] : ws[coord];
cell = dense ? row[C] : ws[coord];
if (!cell || cell.v == null && (!cell.f || cell.F)) {
o.push(" \\cell");
continue;

@ -311,7 +311,7 @@ function parse_cellXfs(t, styles, opts) {
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
/* 18.8.45 xf CT_Xf */
case '<xf': case '<xf/>':
case '<xf': case '<xf/>': case '<xf>':
xf = y;
delete xf[0];
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
@ -325,7 +325,7 @@ function parse_cellXfs(t, styles, opts) {
case '</xf>': break;
/* 18.8.1 alignment CT_CellAlignment */
case '<alignment': case '<alignment/>':
case '<alignment': case '<alignment/>': case '<alignment>':
var alignment = {};
if(y.vertical) alignment.vertical = y.vertical;
if(y.horizontal) alignment.horizontal = y.horizontal;
@ -337,12 +337,12 @@ function parse_cellXfs(t, styles, opts) {
case '</alignment>': break;
/* 18.8.33 protection CT_CellProtection */
case '<protection':
case '<protection': case '<protection>':
break;
case '</protection>': case '<protection/>': break;
/* note: sometimes mc:AlternateContent appears bare */
case '<AlternateContent': pass = true; break;
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
case '</AlternateContent>': pass = false; break;
/* 18.2.10 extLst CT_ExtensionList ? */

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

@ -1,5 +1,43 @@
/* L.5.5.2 SpreadsheetML Comments + VML Schema */
function write_vml(rId/*:number*/, comments) {
var shapevmlregex = /<(?:\w+:)?shape(?:[^\w][^>]*)?>([\s\S]*?)<\/(?:\w+:)?shape>/g;
function parse_vml(data/*:string*/, sheet, comments) {
var cidx = 0;
(data.match(shapevmlregex)||[]).forEach(function(m) {
var type = "";
var hidden = true;
var aidx = -1;
var R = -1, C = -1;
m.replace(tagregex, function(x/*:string*/, idx/*:number*/) {
var y = parsexmltag(x);
switch(strip_ns(y[0])) {
case '<ClientData': if(y.ObjectType) type = y.ObjectType; break;
case '<Visible': case '<Visible/>': hidden = false; break;
case '<Row': case '<Row>': aidx = idx + x.length; break;
case '</Row>': R = +m.slice(aidx, idx).trim(); break;
case '<Column': case '<Column>': aidx = idx + x.length; break;
case '</Column>': C = +m.slice(aidx, idx).trim(); break;
}
return "";
});
switch(type) {
case 'Note':
var cell = ws_get_cell_stub(sheet, ((R>=0 && C>=0) ? encode_cell({r:R,c:C}) : comments[cidx].ref));
if(cell.c) {
cell.c.hidden = hidden;
}
++cidx;
break;
}
});
}
/* comment boxes */
function write_vml(rId/*:number*/, comments, ws) {
var csize = [21600, 21600];
/* L.5.2.1.2 Path Attribute */
var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
@ -21,7 +59,7 @@ function write_vml(rId/*:number*/, comments) {
return o.join("");
}
function write_vml_comment(x, _shapeid)/*:string*/ {
function write_vml_comment(x, _shapeid, ws)/*:string*/ {
var c = decode_cell(x[0]);
var fillopts = /*::(*/{'color2':"#BEFF82", 'type':"gradient"}/*:: :any)*/;
if(fillopts.type == "gradient") fillopts.angle = "-180";

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

@ -50,21 +50,28 @@ function write_comments_xml(data/*::, opts*/) {
o.push("<commentList>");
data.forEach(function(d) {
/* 18.7.3 CT_Comment */
var lastauthor = 0, ts = [];
var lastauthor = 0, ts = [], tcnt = 0;
if(d[1][0] && d[1][0].T && d[1][0].ID) lastauthor = iauthor.indexOf("tc=" + d[1][0].ID);
else d[1].forEach(function(c) {
d[1].forEach(function(c) {
if(c.a) lastauthor = iauthor.indexOf(escapexml(c.a));
ts.push(c.t||"");
if(c.T) ++tcnt;
ts.push(c.t == null ? "" : escapexml(c.t));
});
o.push('<comment ref="' + d[0] + '" authorId="' + lastauthor + '"><text>');
if(ts.length <= 1) o.push(writetag("t", escapexml(ts[0]||"")));
else {
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 {
if(d[1][0] && d[1][0].T && d[1][0].ID) lastauthor = iauthor.indexOf("tc=" + d[1][0].ID);
/* 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("/>",">"); }

@ -74,6 +74,10 @@ function write_comments_bin(data/*::, opts*/) {
if(iauthor.indexOf(c.a) > -1) return;
iauthor.push(c.a.slice(0,54));
write_record(ba, 0x0278 /* BrtCommentAuthor */, write_BrtCommentAuthor(c.a));
if(c.T && c.ID && iauthor.indexOf("tc=" + c.ID) == -1) {
iauthor.push("tc=" + c.ID);
write_record(ba, 0x0278 /* BrtCommentAuthor */, write_BrtCommentAuthor("tc=" + c.ID));
}
});
});
write_record(ba, 0x0277 /* BrtEndCommentAuthors */);
@ -81,7 +85,11 @@ function write_comments_bin(data/*::, opts*/) {
write_record(ba, 0x0279 /* BrtBeginCommentList */);
data.forEach(function(comment) {
comment[1].forEach(function(c) {
c.iauthor = iauthor.indexOf(c.a);
var _ia = -1;
if(c.ID) _ia = iauthor.indexOf("tc=" + c.ID);
if(_ia == -1 && comment[1][0].T && comment[1][0].ID) _ia = iauthor.indexOf("tc=" + comment[1][0].ID);
if(_ia == -1) _ia = iauthor.indexOf(c.a);
c.iauthor = _ia;
var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
write_record(ba, 0x027B /* BrtBeginComment */, write_BrtBeginComment([range, c]));
if(c.t && c.t.length > 0) write_record(ba, 0x027D /* BrtCommentText */, write_BrtCommentText(c));

@ -23,7 +23,10 @@ var rc_to_a1 = /*#__PURE__*/(function(){
};
})();
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
try {
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
}catch(e){}
var a1_to_rc = /*#__PURE__*/(function(){
return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) {
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {

@ -68,8 +68,7 @@ function write_FormulaValue(value) {
/* [MS-XLS] 2.4.127 TODO */
function parse_Formula(blob, length, opts) {
var end = blob.l + length;
var cell = parse_XLSCell(blob, 6);
if(opts.biff == 2) ++blob.l;
var cell = parse_XLSCell(blob, 6, opts);
var val = parse_FormulaValue(blob,8);
var flags = blob.read_shift(1);
if(opts.biff != 2) {
@ -263,7 +262,7 @@ function write_XLSBFormulaRangeWS(_str, wb) {
var sname = _str.slice(0, lastbang);
_str = _str.slice(lastbang+1);
if(sname.charAt(0) == "'") sname = sname.slice(1, -1).replace(/''/g, "'");
var parts = _str.split(":"); str = parts[0];
var parts = _str.split(":");
var out = new_buf(27);
out.write_shift(4, 19);

@ -31,6 +31,6 @@ function ods_to_csf_3D(r/*:string*/)/*:[string, string]*/ {
}
function csf_to_ods_3D(r/*:string*/)/*:string*/ {
return r.replace(/!/,".");
return r.replace(/!/,".").replace(/:/, ":.");
}

@ -81,7 +81,7 @@ function get_cell_style(styles/*:Array<any>*/, cell/*:Cell*/, opts) {
return len;
}
function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles) {
function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles, date1904) {
try {
if(opts.cellNF) p.z = table_fmt[fmtid];
} catch(e) { if(opts.WTF) throw e; }
@ -96,14 +96,14 @@ function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, the
else p.w = SSF_general_num(p.v);
}
else if(p.t === 'd') {
var dd = datenum(p.v);
var dd = datenum(p.v, !!date1904);
if((dd|0) === dd) p.w = dd.toString(10);
else p.w = SSF_general_num(dd);
}
else if(p.v === undefined) return "";
else p.w = SSF_general(p.v,_ssfopts);
}
else if(p.t === 'd') p.w = SSF_format(fmtid,datenum(p.v),_ssfopts);
else if(p.t === 'd') p.w = SSF_format(fmtid,datenum(p.v, !!date1904),_ssfopts);
else p.w = SSF_format(fmtid,p.v,_ssfopts);
} catch(e) { if(opts.WTF) throw e; }
if(!opts.cellStyles) return;

@ -2,7 +2,7 @@ function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
var d = safe_decode_range(s);
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
}
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
var dimregex = /"(\w*:\w*)"/;
@ -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 = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var s = ({}/*:any*/); if(opts.dense) s["!data"] = [];
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) parse_ws_xml_dim(s, ref[1]);
if(ref && !(opts && opts.nodim)) parse_ws_xml_dim(s, ref[1]);
}
/* 18.3.1.88 sheetViews CT_SheetViews */
@ -55,7 +55,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
}
/* 18.3.1.80 sheetData CT_SheetData ? */
if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles, wb);
/* 18.3.1.2 autoFilter CT_AutoFilter */
var afilter = data2.match(afregex);
@ -75,6 +75,11 @@ 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]));
/* legacyDrawing */
var m;
if((m = data2.match(/legacyDrawing r:id="(.*?)"/))) s['!legrel'] = m[1];
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"]);
@ -90,6 +95,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
}
if(columns.length > 0) s["!cols"] = columns;
if(merges.length > 0) s["!merges"] = merges;
if(rels['!id'][s['!legrel']]) s['!legdrawel'] = rels['!id'][s['!legrel']];
return s;
}
@ -149,7 +155,7 @@ function write_ws_xml_protection(sp)/*:string*/ {
}
function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
var dense = Array.isArray(s);
var dense = s["!data"] != null;
for(var i = 0; i != data.length; ++i) {
var val = parsexmltag(utf8read(data[i]), true);
if(!val.ref) return;
@ -165,11 +171,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_cell({c:C,r:R});
var addr = encode_col(C) + encode_row(R);
if(dense) {
if(!s[R]) s[R] = [];
if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
s[R][C].l = val;
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;
} else {
if(!s[addr]) s[addr] = {t:"z",v:undefined};
s[addr].l = val;
@ -256,21 +262,27 @@ function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ {
return writextag("sheetViews", writextag("sheetView", null, sview), {});
}
function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string*/ {
function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts, idx, wb, date1904)/*:string*/ {
if(cell.c) ws['!comments'].push([ref, cell.c]);
if((cell.v === undefined || cell.t === "z" && !(opts||{}).sheetStubs) && typeof cell.f !== "string" && typeof cell.z == "undefined") return "";
var vv = "";
var oldt = cell.t, oldv = cell.v;
if(cell.t !== "z") switch(cell.t) {
case 'b': vv = cell.v ? "1" : "0"; break;
case 'n': vv = ''+cell.v; 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 'e': vv = BErr[cell.v]; break;
case 'd':
if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
else {
if(opts && opts.cellDates) {
var _vv = parseDate(cell.v, date1904);
vv = _vv.toISOString();
if(_vv.getUTCFullYear() < 1900) vv = vv.slice(vv.indexOf("T") + 1).replace("Z","");
} else {
cell = dup(cell);
cell.t = 'n';
vv = ''+(cell.v = datenum(parseDate(cell.v)));
vv = ''+(cell.v = datenum(parseDate(cell.v, date1904), date1904));
}
if(typeof cell.z === 'undefined') cell.z = table_fmt[14];
break;
@ -299,7 +311,10 @@ 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) ws['!links'].push([ref, cell.l]);
if(cell.l) {
cell.l.display = escapexml(vv);
ws['!links'].push([ref, cell.l]);
}
if(cell.D) o.cm = 1;
return writextag('c', v, o);
}
@ -310,7 +325,7 @@ var parse_ws_xml_data = /*#__PURE__*/(function() {
var refregex = /ref=["']([^"']*)["']/;
var match_v = matchtag("v"), match_f = matchtag("f");
return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, themes, styles) {
return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, themes, styles, wb) {
var ri = 0, x = "", cells/*:Array<string>*/ = [], cref/*:?Array<string>*/ = [], idx=0, i=0, cc=0, d="", p/*:any*/;
var tag, tagr = 0, tagc = 0;
var sstr, ftag;
@ -318,9 +333,10 @@ 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 = Array.isArray(s);
var dense = s["!data"] != null;
var rows/*:Array<RowInfo>*/ = [], rowobj = {}, rowrite = false;
var sheetStubs = !!opts.sheetStubs;
var date1904 = !!((wb||{}).WBProps||{}).date1904;
for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
x = marr[mt].trim();
var xlen = x.length;
@ -349,8 +365,10 @@ 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(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
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(opts && opts.cellStyles) {
rowobj = {}; rowrite = false;
@ -386,19 +404,27 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
if((cref=d.match(match_v))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]);
if(opts.cellFormula) {
if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') {
/* TODO: match against XLSXFutureFunctions */
p.f=unescapexml(utf8read(cref[1]), true);
if(!opts.xlfn) p.f = _xlfn(p.f);
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) {
p.F = (d.match(refregex)||[])[1];
if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
// TODO: parse formula
ftag = parsexmltag(cref[0]);
var ___f = unescapexml(utf8read(cref[1]));
if(!opts.xlfn) ___f = _xlfn(___f);
sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r];
if((cref=d.match(match_f))!= null /*:: && cref != null*/) {
if(cref[1] == "") {
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
// TODO: parse formula
ftag = parsexmltag(cref[0]);
if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
}
} else {
/* TODO: match against XLSXFutureFunctions */
p.f=unescapexml(utf8read(cref[1]), true);
if(!opts.xlfn) p.f = _xlfn(p.f);
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) {
p.F = (d.match(refregex)||[])[1];
if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
// TODO: parse formula
ftag = parsexmltag(cref[0]);
var ___f = unescapexml(utf8read(cref[1]));
if(!opts.xlfn) ___f = _xlfn(___f);
sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r];
}
}
} else if((cref=d.match(/<f[^>]*\/>/))) {
ftag = parsexmltag(cref[0]);
@ -455,8 +481,8 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
break;
case 'b': p.v = parsexmlbool(p.v); break;
case 'd':
if(opts.cellDates) p.v = parseDate(p.v, 1);
else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
if(opts.cellDates) p.v = parseDate(p.v, date1904);
else { p.v = datenum(parseDate(p.v, date1904), date1904); p.t = 'n'; }
break;
/* error string in .w, number in .v */
case 'e':
@ -475,16 +501,22 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
}
}
}
safe_format(p, fmtid, fillid, opts, themes, styles);
if(opts.cellDates && do_format && p.t == 'n' && fmt_is_date(table_fmt[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
safe_format(p, fmtid, fillid, opts, themes, styles, date1904);
if(opts.cellDates && do_format && p.t == 'n' && fmt_is_date(table_fmt[fmtid])) { p.v = numdate(p.v + (date1904 ? 1462 : 0)); p.t = typeof p.v == "number" ? 'n' : 'd'; }
if(tag.cm && opts.xlmeta) {
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) {
var _r = decode_cell(tag.r);
if(!s[_r.r]) s[_r.r] = [];
s[_r.r][_r.c] = p;
_r = decode_cell(tag.r);
if(!s["!data"][_r.r]) s["!data"][_r.r] = [];
s["!data"][_r.r][_r.c] = p;
} else s[tag.r] = p;
}
}
@ -493,17 +525,18 @@ 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 = Array.isArray(ws);
var dense = ws["!data"] != null;
var params = ({r:rr}/*:any*/), row/*:RowInfo*/, height = -1;
var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
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) {
r = [];
rr = encode_row(R);
for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
var _cell = dense ? (ws[R]||[])[C]: ws[ref];
var _cell = dense ? (ws["!data"][R]||[])[C]: ws[ref];
if(_cell === undefined) continue;
if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb, date1904)) != null) r.push(cell);
}
if(r.length > 0 || (rows && rows[R])) {
params = ({r:rr}/*:any*/);
@ -609,6 +642,7 @@ 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,12 +41,13 @@ 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 = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
var cell = dense ? (ws["!data"][caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
if(cell) { if(first < 0) first = j; last = j; }
}
if(first < 0) continue;
@ -258,9 +259,10 @@ 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(cell.v, o);
write_XLWideString(data, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
function parse_BrtShortSt(data) {
@ -269,9 +271,10 @@ function parse_BrtShortSt(data) {
return [cell, value, 'str'];
}
function write_BrtShortSt(cell, ncell, o) {
if(o == null) o = new_buf(8 + 4 * cell.v.length);
var data = cell.v == null ? "" : String(cell.v);
if(o == null) o = new_buf(8 + 4 * data.length);
write_XLSBShortCell(ncell, o);
write_XLWideString(cell.v, o);
write_XLWideString(data, o);
return o.length > o.l ? o.slice(0, o.l) : o;
}
@ -508,7 +511,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*/ = (opts.dense ? [] : {});
var s/*:Worksheet*/ = ({}); if(opts.dense) s["!data"] = [];
var ref;
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
@ -539,6 +542,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
XLSBRecordEnum[0x0010] = { n:"BrtShortReal", f:parse_BrtShortReal };
var cm, vm;
var date1904 = 1462 * +!!((wb||{}).WBProps||{}).date1904;
recordhopper(data, function ws_parse(val, RR, RT) {
if(end) return;
@ -582,9 +586,9 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
case 'str': p.t = 's'; p.v = val[1]; break;
case 'is': p.t = 's'; p.v = val[1].t; break;
}
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles, date1904>0);
C = val[0].c == -1 ? C + 1 : val[0].c;
if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
if(opts.dense) { if(!s["!data"][R]) s["!data"][R] = []; s["!data"][R][C] = p; }
else s[encode_col(C) + rr] = p;
if(opts.cellFormula) {
af = false;
@ -603,7 +607,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
if(refguess.e.r < row.r) refguess.e.r = row.r;
if(refguess.e.c < C) refguess.e.c = C;
if(opts.cellDates && cf && p.t == 'n' && fmt_is_date(table_fmt[cf.numFmtId])) {
var _d = SSF_parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
var _d = SSF_parse_date_code(p.v + date1904); if(_d) { p.t = 'd'; p.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); }
}
if(cm) {
if(cm.type == 'XLDAPR') p.D = true;
@ -617,7 +621,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[R]) s[R] = []; s[R][C] = p; }
if(opts.dense) { if(!s["!data"][R]) s["!data"][R] = []; s["!data"][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;
@ -648,11 +652,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[R]) s[R] = [];
if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
s[R][C].l = val;
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;
} else {
addr = encode_cell({c:C,r:R});
addr = encode_col(C) + encode_row(R);
if(!s[addr]) s[addr] = {t:'z',v:undefined};
s[addr].l = val;
}
@ -662,14 +666,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[R][C] : s[encode_col(C) + rr])/*:any*/);
cell = ((opts.dense ? s["!data"][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[R][C] : s[encode_col(C) + rr]);
cell = (opts.dense ? s["!data"][R][C] : s[encode_col(C) + rr]);
cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
break;
@ -683,6 +687,10 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
}
break;
case 0x0227: /* 'BrtLegacyDrawing' */
if(val) s["!legrel"] = val;
break;
case 0x00A1: /* 'BrtBeginAFilter' */
s['!autofilter'] = { ref:encode_range(val) };
break;
@ -739,7 +747,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
case 0x0499: /* 'BrtFilter14' */
case 0x00A9: /* 'BrtIconFilter' */
case 0x049D: /* 'BrtIconFilter14' */
case 0x0227: /* 'BrtLegacyDrawing' */
case 0x0228: /* 'BrtLegacyDrawingHF' */
case 0x0295: /* 'BrtListPart' */
case 0x027F: /* 'BrtOleObject' */
@ -798,11 +805,12 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
if(merges.length > 0) s["!merges"] = merges;
if(colinfo.length > 0) s["!cols"] = colinfo;
if(rowinfo.length > 0) s["!rows"] = rowinfo;
if(rels['!id'][s['!legrel']]) s['!legdrawel'] = rels['!id'][s['!legrel']];
return s;
}
/* TODO: something useful -- this is a stub */
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/, last_seen/*:boolean*/)/*:boolean*/ {
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/, last_seen/*:boolean*/, date1904/*:boolean*/)/*:boolean*/ {
var o/*:any*/ = ({r:R, c:C}/*:any*/);
if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
if(cell.v === undefined) return false;
@ -812,7 +820,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
case 'd': // no BrtCellDate :(
cell = dup(cell);
cell.z = cell.z || table_fmt[14];
cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
cell.v = datenum(parseDate(cell.v, date1904), date1904); cell.t = 'n';
break;
/* falls through */
case 'n': case 'e': vv = ''+cell.v; break;
@ -824,7 +832,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/*:any*/), opts.revStrings);
vv = get_sst_id(opts.Strings, (cell.v == null ? "" : String(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));
@ -839,6 +847,12 @@ 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));
@ -859,10 +873,11 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num
return true;
}
function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols/*:Array<string>*/ = [];
var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
write_record(ba, 0x0091 /* BrtBeginSheetData */);
var dense = Array.isArray(ws);
var dense = ws["!data"] != null;
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) {
@ -875,10 +890,10 @@ 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[R]||[])[C] : ws[ref];
var cell = dense ? (ws["!data"][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);
last_seen = write_ws_bin_cell(ba, cell, R, C, opts, ws, last_seen, date1904);
}
}
write_record(ba, 0x0092 /* BrtEndSheetData */);

@ -34,7 +34,10 @@ 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) {
cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
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] };
R = i;
});
if(refguess.e.r < R) refguess.e.r = R;

@ -115,14 +115,17 @@ function safe1904(wb/*:Workbook*/)/*:string*/ {
var badchars = /*#__PURE__*/":][*?\/\\".split("");
function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ {
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;
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;
}
function check_wb_names(N, S, codes) {
N.forEach(function(n,i) {

@ -40,10 +40,10 @@ function xlml_parsexmltagobj(tag/*:string*/) {
/* map from xlml named formats to SSF TODO: localize */
var XLMLFormatMap/*: {[string]:string}*/;
function xlml_format(format, value)/*:string*/ {
function xlml_format(format, value, date1904)/*:string*/ {
var fmt = XLMLFormatMap[format] || unescapexml(format);
if(fmt === "General") return SSF_general(value);
return SSF_format(fmt, value);
return SSF_format(fmt, value, {date1904: !!date1904});
}
function xlml_set_custprop(Custprops, key, cp, val/*:string*/) {
@ -59,7 +59,7 @@ function xlml_set_custprop(Custprops, key, cp, val/*:string*/) {
Custprops[unescapexml(key)] = oval;
}
function safe_format_xlml(cell/*:Cell*/, nf, o) {
function safe_format_xlml(cell/*:Cell*/, nf, o, date1904) {
if(cell.t === 'z') return;
if(!o || o.cellText !== false) try {
if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
@ -70,13 +70,13 @@ function safe_format_xlml(cell/*:Cell*/, nf, o) {
}
else cell.w = SSF_general(cell.v);
}
else cell.w = xlml_format(nf||"General", cell.v);
else cell.w = xlml_format(nf||"General", cell.v, date1904);
} catch(e) { if(o.WTF) throw e; }
try {
var z = XLMLFormatMap[nf]||nf||"General";
if(o.cellNF) cell.z = z;
if(o.cellDates && cell.t == 'n' && fmt_is_date(z)) {
var _d = SSF_parse_date_code(cell.v); if(_d) { cell.t = 'd'; cell.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
var _d = SSF_parse_date_code(cell.v + (date1904 ? 1462 : 0)); if(_d) { cell.t = 'd'; cell.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); }
}
} catch(e) { if(o.WTF) throw e; }
}
@ -92,7 +92,7 @@ function process_style_xlml(styles, stag, opts) {
}
/* TODO: there must exist some form of OSP-blessed spec */
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o) {
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o, date1904) {
var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
var interiors = [];
var i = 0;
@ -115,9 +115,8 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a
break;
case 'DateTime':
if(xml.slice(-1) != "Z") xml += "Z";
cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
cell.v = datenum(parseDate(xml, date1904), date1904);
if(cell.v !== cell.v) cell.v = unescapexml(xml);
else if(cell.v<60) cell.v = cell.v -1;
if(!nf || nf == "General") nf = "yyyy-mm-dd";
/* falls through */
case 'Number':
@ -130,7 +129,7 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a
else { cell.t = 's'; cell.v = xlml_fixstr(ss||xml); }
break;
}
safe_format_xlml(cell, nf, o);
safe_format_xlml(cell, nf, o, date1904);
if(o.cellFormula !== false) {
if(cell.Formula) {
var fstr = unescapexml(cell.Formula);
@ -207,7 +206,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*/ = (opts.dense ? [] : {}), sheetname = "";
var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = ({}), sheetname = ""; if(opts.dense) cursheet["!data"] = [];
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;
@ -232,7 +231,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
break;
}
if(state[state.length-1][1]) break;
if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]==/*"Comment"*/"comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts);
if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]==/*"Comment"*/"comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts, Workbook.WBProps.date1904);
else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
break;
case 'cell' /*case 'Cell'*/:
@ -240,8 +239,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[r]) cursheet[r] = [];
cursheet[r][c] = cell;
if(!cursheet["!data"][r]) cursheet["!data"][r] = [];
cursheet["!data"][r][c] = cell;
} else cursheet[encode_col(c) + encode_row(r)] = cell;
}
if(cell.HRef) {
@ -261,8 +260,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[cmd]) cursheet[cmd] = [];
cursheet[cmd][cma] = {t:'z'};
if(!cursheet["!data"][cmd]) cursheet["!data"][cmd] = [];
cursheet["!data"][cmd][cma] = {t:'z'};
} else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
}
}
@ -321,7 +320,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
state.push([Rn[3], false]);
tmp = xlml_parsexmltag(Rn[0]);
sheetname = unescapexml(tmp.Name);
cursheet = (opts.dense ? [] : {});
cursheet = ({}); if(opts.dense) cursheet["!data"] = [];
merges = [];
arrayf = [];
rowinfo = [];
@ -443,6 +442,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
} else {
state.push([Rn[3], false]);
tmp = xlml_parsexmltag(Rn[0]);
if(!parsexmlbool(tmp["ShowAlways"]||"0")) comments.hidden = true;
comment = ({a:tmp.Author}/*:any*/);
}
break;
@ -534,6 +534,9 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */
Workbook.WBProps.date1904 = true;
break;
case 'hidehorizontalscrollbar' /*case 'HideHorizontalScrollBar'*/: break;
case 'hideverticalscrollbar' /*case 'HideVerticalScrollBar'*/: break;
case 'hideworkbooktabs' /*case 'HideWorkbookTabs'*/: break;
case 'windowheight' /*case 'WindowHeight'*/: break;
case 'windowwidth' /*case 'WindowWidth'*/: break;
case 'windowtopx' /*case 'WindowTopX'*/: break;
@ -1102,11 +1105,15 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
}
function write_ws_xlml_comment(comments/*:Array<any>*/)/*:string*/ {
/* TODO: test multiple comments */
return comments.map(function(c) {
// TODO: formatted text
var t = xlml_unfixstr(c.t||"");
var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
return writextag("Comment", d, {"ss:Author":c.a});
var p = {};
if(c.a) p["ss:Author"] = c.a;
if(!comments.hidden) p["ss:ShowAlways"] = "1";
return writextag("Comment", d, p);
}).join("");
}
function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, addr)/*:string*/{
@ -1177,7 +1184,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 = Array.isArray(ws);
var dense = ws["!data"] != null;
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 +1199,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_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
var ref = encode_col(C) + encode_row(R), cell = dense ? (ws["!data"][R]||[])[C] : ws[ref];
row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
}
row.push("</Row>");

@ -77,7 +77,7 @@ function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
var fmtid = 0;
try {
fmtid = p.z || p.XF.numFmtId || 0;
if(opts.cellNF) p.z = table_fmt[fmtid];
if(opts.cellNF && p.z == null) p.z = table_fmt[fmtid];
} catch(e) { if(opts.WTF) throw e; }
if(!opts || opts.cellText !== false) try {
if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
@ -91,7 +91,7 @@ function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
else p.w = SSF_format(fmtid,p.v, {date1904:!!date1904, dateNF: opts && opts.dateNF});
} catch(e) { if(opts.WTF) throw e; }
if(opts.cellDates && fmtid && p.t == 'n' && fmt_is_date(table_fmt[fmtid] || String(fmtid))) {
var _d = SSF_parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
var _d = SSF_parse_date_code(p.v + (date1904 ? 1462 : 0)); if(_d) { p.t = 'd'; p.v = new Date(Date.UTC(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u)); }
}
}
@ -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*/ = ((options.dense ? [] : {})/*:any*/);
var out/*:Worksheet*/ = ({}/*:any*/); if(options.dense) out["!data"] = [];
var Directory = {};
var range/*:Range*/ = ({}/*:any*/);
var last_formula = null;
@ -119,6 +119,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
var XFs = []; /* XF records */
var palette/*:Array<[number, number, number]>*/ = [];
var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }/*:any*/), wsprops = {};
var biff4w = false;
var get_rgb = function getrgb(icv/*:number*/)/*:[number, number, number]*/ {
if(icv < 8) return XLSIcv[icv];
if(icv < 64) return palette[icv-8] || XLSIcv[icv];
@ -134,7 +135,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
};
var addcell = function addcell(cell/*:any*/, line/*:any*/, options/*:any*/) {
if(file_depth > 1) return;
if(!biff4w && file_depth > 1) return;
if(options.sheetRows && cell.r >= options.sheetRows) return;
if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options);
delete line.ixfe; delete line.XF;
@ -157,8 +158,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
}
{
if(options.dense) {
if(!out[cell.r]) out[cell.r] = [];
out[cell.r][cell.c] = line;
if(!out["!data"][cell.r]) out["!data"][cell.r] = [];
out["!data"][cell.r][cell.c] = line;
} else out[last_cell] = line;
}
};
@ -265,6 +266,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
if(!val.fBelow) (out["!outline"] || (out["!outline"] = {})).above = true;
if(!val.fRight) (out["!outline"] || (out["!outline"] = {})).left = true;
break; // TODO
case 0x0043: /* BIFF2XF */ case 0x0243: /* BIFF3XF */ case 0x0443: /* BIFF4XF */
case 0x00e0 /* XF */:
XFs.push(val); break;
case 0x01ae /* SupBook */:
@ -299,11 +301,11 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 0x0012 /* Protect */: out["!protect"] = val; break; /* for sheet or book */
case 0x0013 /* Password */: if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
case 0x0085 /* BoundSheet8 */: {
Directory[val.pos] = val;
Directory[opts.biff == 4 ? opts.snames.length : val.pos] = val;
opts.snames.push(val.name);
} break;
case 0x000a /* EOF */: {
if(--file_depth) break;
if(--file_depth ? !biff4w : biff4w) break;
if(range.e) {
if(range.e.r > 0 && range.e.c > 0) {
range.e.r--; range.e.c--;
@ -324,7 +326,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
Workbook.Sheets.push(wsprops);
}
if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
out = ((options.dense ? [] : {})/*:any*/);
out = ({}/*:any*/); if(options.dense) out["!data"] = [];
} break;
case 0x0009: case 0x0209: case 0x0409: case 0x0809 /* BOF */: {
if(opts.biff === 8) opts.biff = {
@ -342,13 +344,15 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
}[val.BIFFVer] || 8;
opts.biffguess = val.BIFFVer == 0;
if(val.BIFFVer == 0 && val.dt == 0x1000) { opts.biff = 5; seen_codepage = true; set_cp(opts.codepage = 28591); }
if(opts.biff == 4 && val.dt & 0x100) biff4w = true;
if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
if(file_depth++) break;
out = ((options.dense ? [] : {})/*:any*/);
if(file_depth++ && !biff4w) break;
out = ({}/*:any*/); if(options.dense) out["!data"] = [];
if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
if(opts.biff < 5 || val.BIFFVer == 0 && val.dt == 0x1000) {
if(opts.biff == 4 && biff4w) {
cur_sheet = (Directory[opts.snames.indexOf(cur_sheet)+1] || {name:""}).name;
} else if(opts.biff < 5 || val.BIFFVer == 0 && val.dt == 0x1000) {
if(cur_sheet === "") cur_sheet = "Sheet1";
range = {s:{r:0,c:0},e:{r:0,c:0}};
/* fake BoundSheet8 */
@ -367,21 +371,21 @@ 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[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
if(out["!type"] == "chart") if(options.dense ? (out["!data"][val.r]||[])[val.c]: out[encode_col(val.c) + encode_row(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];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 0x0005: case 0x0205 /* BoolErr */: {
temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t}/*:any*/);
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
case 0x027e /* RK */: {
temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'}/*:any*/);
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
@ -389,7 +393,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
for(var j = val.c; j <= val.C; ++j) {
var ixfe = val.rkrec[j-val.c][0];
temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'}/*:any*/);
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:j, r:val.r}, temp_val, options);
}
@ -404,10 +408,10 @@ 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[_fr]||[])[_fc]: out[_fe]) || {}).F;
else temp_val.F = ((options.dense ? (out["!data"][_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];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(val.cell, temp_val, options);
last_formula = val;
@ -420,7 +424,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
if(options.cellFormula) {
temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
}
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell(last_formula.cell, temp_val, options);
last_formula = null;
@ -429,7 +433,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[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
cc = options.dense ? (out["!data"][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 +447,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[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
cc = options.dense ? (out["!data"][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;
@ -451,13 +455,13 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
if(sst[val.isst].h) temp_val.h = sst[val.isst].h;
temp_val.XF = XFs[temp_val.ixfe];
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
case 0x0201 /* Blank */: if(options.sheetStubs) {
temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'}/*:any*/);
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
} break;
@ -465,7 +469,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
for(var _j = val.c; _j <= val.C; ++_j) {
var _ixfe = val.ixfe[_j-val.c];
temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'}/*:any*/);
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:_j, r:val.r}, temp_val, options);
}
@ -474,7 +478,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 0x0204 /* Label */: case 0x0004 /* BIFF2STR */:
temp_val=make_cell(val.val, val.ixfe, 's');
temp_val.XF = XFs[temp_val.ixfe];
if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
if(BIFF2Fmt > 0) temp_val.z = (temp_val.XF && temp_val.XF.numFmtId) && BIFF2FmtTable[temp_val.XF.numFmtId] || BIFF2FmtTable[(temp_val.ixfe>>8) & 0x3F];
safe_format_xf(temp_val, options, wb.opts.Date1904);
addcell({c:val.c, r:val.r}, temp_val, options);
break;
@ -486,7 +490,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
sst = val;
} break;
case 0x041e /* Format */: { /* val = [id, fmt] */
if(opts.biff == 4) {
if(opts.biff >= 3 && opts.biff <= 4) {
BIFF2FmtTable[BIFF2Fmt++] = val[1];
for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(table_fmt[b4idx] == val[1]) break;
if(b4idx >= 163) SSF__load(val[1], BIFF2Fmt + 163);
@ -508,25 +512,24 @@ 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[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
cc = options.dense ? (out["!data"][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[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
cc = options.dense ? (out["!data"][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[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
var noteobj = objects[val[2]];
/* TODO: comment continuation (row == -1 / 0xFFFF) */
cc = options.dense ? (out["!data"][val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
if(!cc) {
if(options.dense) {
if(!out[val[0].r]) out[val[0].r] = [];
cc = out[val[0].r][val[0].c] = ({t:"z"}/*:any*/);
if(!out["!data"][val[0].r]) out["!data"][val[0].r] = [];
cc = out["!data"][val[0].r][val[0].c] = ({t:"z"}/*:any*/);
} else {
cc = out[encode_cell(val[0])] = ({t:"z"}/*:any*/);
}
@ -536,7 +539,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
range.s.c = Math.min(range.s.c, val[0].c);
}
if(!cc.c) cc.c = [];
cmnt = {a:val[1],t:noteobj.TxO.t};
if(opts.biff <= 5 && opts.biff >= 2) cmnt = {a:"SheetJ5", t:val[1]};
else {
var noteobj = objects[val[2]];
cmnt = {a:val[1],t:noteobj.TxO.t};
if(val[3] != null && !(val[3] & 0x02)) cc.c.hidden = true;
}
cc.c.push(cmnt);
} break;
case 0x087d /* XFExt */: update_xfext(XFs[val.ixfe], val.ext); break;

@ -482,7 +482,7 @@ var XLSBRecordEnum = {
/*::[*/0x0224/*::]*/: { /* n:"BrtFileSharing" */ },
/*::[*/0x0225/*::]*/: { /* n:"BrtOleSize" */ },
/*::[*/0x0226/*::]*/: { /* n:"BrtDrawing", */ f:parse_RelID },
/*::[*/0x0227/*::]*/: { /* n:"BrtLegacyDrawing" */ },
/*::[*/0x0227/*::]*/: { /* n:"BrtLegacyDrawing", */ f:parse_XLNullableWideString },
/*::[*/0x0228/*::]*/: { /* n:"BrtLegacyDrawingHF" */ },
/*::[*/0x0229/*::]*/: { /* n:"BrtWebOpt" */ },
/*::[*/0x022A/*::]*/: { /* n:"BrtBeginWebPubItems", */ T:1 },
@ -1221,7 +1221,7 @@ var XLSRecordEnum = {
/*::[*/0x0002/*::]*/: { /* n:"BIFF2INT", */ f:parse_BIFF2INT },
/*::[*/0x0003/*::]*/: { /* n:"BIFF2NUM", */ f:parse_BIFF2NUM },
/*::[*/0x0004/*::]*/: { /* n:"BIFF2STR", */ f:parse_BIFF2STR },
/*::[*/0x0005/*::]*/: { /* n:"BoolErr", */ f:parse_BoolErr },
/*::[*/0x0005/*::]*/: { /* n:"BIFF2BOOLERR", */ f:parse_BIFF2BOOLERR },
/*::[*/0x0007/*::]*/: { /* n:"String", */ f:parse_BIFF2STRING },
/*::[*/0x0008/*::]*/: { /* n:"BIFF2ROW", */ },
/*::[*/0x0009/*::]*/: { /* n:"BOF", */ f:parse_BOF },
@ -1233,34 +1233,34 @@ var XLSRecordEnum = {
/*::[*/0x0021/*::]*/: { /* n:"Array", */ f:parse_Array },
/*::[*/0x0024/*::]*/: { /* n:"COLWIDTH", */ },
/*::[*/0x0025/*::]*/: { /* n:"DefaultRowHeight", */ f:parse_DefaultRowHeight },
// 0x2c ??
// 0x2d ??
// 0x2e ??
// 0x30 FONTCOUNT: number of fonts
// 0x002c ??
// 0x002d ??
// 0x002e ??
// 0x0030 FONTCOUNT: number of fonts
/*::[*/0x0032/*::]*/: { /* n:"BIFF2FONTXTRA", */ f:parse_BIFF2FONTXTRA },
// 0x35: INFOOPTS
// 0x36: TABLE (BIFF2 only)
// 0x37: TABLE2 (BIFF2 only)
// 0x38: WNDESK
// 0x39 ??
// 0x3a: BEGINPREF
// 0x3b: ENDPREF
// 0x0035: INFOOPTS
// 0x0036: TABLE (BIFF2 only)
// 0x0037: TABLE2 (BIFF2 only)
// 0x0038: WNDESK
// 0x0039 ??
// 0x003a: BEGINPREF
// 0x003b: ENDPREF
/*::[*/0x003e/*::]*/: { /* n:"BIFF2WINDOW2", */ },
// 0x3f ??
// 0x46: SHOWSCROLL
// 0x47: SHOWFORMULA
// 0x48: STATUSBAR
// 0x49: SHORTMENUS
// 0x4A:
// 0x4B:
// 0x4C:
// 0x4E:
// 0x4F:
// 0x58: TOOLBAR (BIFF3)
// 0x003f ??
// 0x0046: SHOWSCROLL
// 0x0047: SHOWFORMULA
// 0x0048: STATUSBAR
// 0x0049: SHORTMENUS
// 0x004A:
// 0x004B:
// 0x004C:
// 0x004E:
// 0x004F:
// 0x0058: TOOLBAR (BIFF3)
/* - - - */
/*::[*/0x0034/*::]*/: { /* n:"DDEObjName", */ },
/*::[*/0x0043/*::]*/: { /* n:"BIFF2XF", */ },
/*::[*/0x0043/*::]*/: { /* n:"BIFF2XF", */ f:parse_BIFF2XF },
/*::[*/0x0044/*::]*/: { /* n:"BIFF2XFINDEX", */ f:parseuint16 },
/*::[*/0x0045/*::]*/: { /* n:"BIFF2FONTCLR", */ },
/*::[*/0x0056/*::]*/: { /* n:"BIFF4FMTCNT", */ }, /* 16-bit cnt, similar to BIFF2 */
@ -1272,7 +1272,7 @@ var XLSRecordEnum = {
// 0x8A
// 0x8B LH: alternate menu key flag (BIFF3/4)
// 0x8E
// 0x8F
/*::[*/0x008F/*::]*/: { /* n:"BIFF4SheetInfo", */ f:parse_BIFF4SheetInfo },
/*::[*/0x0091/*::]*/: { /* n:"Sub", */ },
// 0x93 STYLE
/*::[*/0x0094/*::]*/: { /* n:"LHRecord", */ },
@ -1298,10 +1298,10 @@ var XLSRecordEnum = {
/*::[*/0x0218/*::]*/: { /* n:"Lbl", */ f:parse_Lbl },
/*::[*/0x0223/*::]*/: { /* n:"ExternName", */ f:parse_ExternName },
/*::[*/0x0231/*::]*/: { /* n:"Font", */ },
/*::[*/0x0243/*::]*/: { /* n:"BIFF3XF", */ },
/*::[*/0x0243/*::]*/: { /* n:"BIFF3XF", */ f:parse_BIFF3XF },
/*::[*/0x0406/*::]*/: { /* n:"Formula", */ f:parse_Formula },
/*::[*/0x0409/*::]*/: { /* n:"BOF", */ f:parse_BOF },
/*::[*/0x0443/*::]*/: { /* n:"BIFF4XF", */ },
/*::[*/0x0443/*::]*/: { /* n:"BIFF4XF", */ f:parse_BIFF4XF },
/*::[*/0x086d/*::]*/: { /* n:"FeatInfo", */ },
/*::[*/0x0873/*::]*/: { /* n:"FeatInfo11", */ },
/*::[*/0x0881/*::]*/: { /* n:"SXAddl12", */ },

@ -31,16 +31,7 @@ function write_biff_continue(ba/*:BufArray*/, type/*:number*/, payload, length/*
}
}
function write_BIFF2Cell(out, r/*:number*/, c/*:number*/) {
if(!out) out = new_buf(7);
out.write_shift(2, r);
out.write_shift(2, c);
out.write_shift(2, 0);
out.write_shift(1, 0);
return out;
}
function write_BIFF2BERR(r/*:number*/, c/*:number*/, val, t/*:?string*/) {
function write_BIFF2BERR(r/*:number*/, c/*:number*/, val, t/*:string*/) {
var out = new_buf(9);
write_BIFF2Cell(out, r, c);
write_Bes(val, t || 'b', out);
@ -56,62 +47,371 @@ function write_BIFF2LABEL(r/*:number*/, c/*:number*/, val) {
return out.l < out.length ? out.slice(0, out.l) : out;
}
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*//*::, opts*/) {
function write_comments_biff2(ba/*:BufArray*/, comments/*:Array<[Comment[], number, number]>*/) {
comments.forEach(function(data) {
var text = data[0].map(function(cc) { return cc.t; }).join("");
// TODO: should '\n' be translated to '\r' to correct for Excel 5.0 bug when exporting to BIFF2/3 ?
if(text.length <= 2048) return write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text, data[1], data[2]));
write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text.slice(0, 2048), data[1], data[2], text.length));
for(var i = 2048; i < text.length; i += 2048)
write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text.slice(i, Math.min(i+2048, text.length)), -1, -1, Math.min(2048, text.length - i)));
});
}
/* TODO: BIFF3/4 use different records -- see comments*/
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, date1904/*:boolean*/) {
var ifmt = 0;
if(cell.z != null) {
ifmt = opts._BIFF2FmtTable.indexOf(cell.z);
if(ifmt == -1) { opts._BIFF2FmtTable.push(cell.z); ifmt = opts._BIFF2FmtTable.length - 1; }
}
var ixfe = 0;
if(cell.z != null) {
for(; ixfe < opts.cellXfs.length; ++ixfe) if(opts.cellXfs[ixfe].numFmtId == ifmt) break;
if(ixfe == opts.cellXfs.length) opts.cellXfs.push({numFmtId: ifmt});
}
if(cell.v != null) switch(cell.t) {
case 'd': case '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));
var v = cell.t == 'd' ? datenum(parseDate(cell.v, date1904), date1904) : cell.v;
if(opts.biff == 2 && (v == (v|0)) && (v >= 0) && (v < 65536))
// 0x027E (RK) in BIFF3/4
write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v, ixfe, ifmt));
else if(isNaN(v))
// 0x0205 in BIFF3/4
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x24, "e")); // #NUM!
else if(!isFinite(v))
// 0x0205 in BIFF3/4
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x07, "e")); // #DIV/0!
else
write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
// 0x0203 in BIFF3/4
write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v, ixfe, ifmt));
return;
case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
case 'b': case 'e':
// 0x0205 in BIFF3/4
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||"").slice(0,255)));
// 0x0204 in BIFF3/4
write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v == null ? "" : String(cell.v).slice(0,255)));
return;
}
// 0x0201 in BIFF3/4
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 = Array.isArray(ws);
function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
var dense = ws["!data"] != null;
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 date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
var row = [], comments = [];
/* TODO: 0x0000 / 0x0200 dimensions? */
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(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];
for(C = range.s.c; C <= range.e.c; ++C) {
var cell = dense ? row[C] : ws[cols[C] + rr];
if(!cell) continue;
/* write cell */
write_ws_biff2_cell(ba, cell, R, C, opts);
write_ws_biff2_cell(ba, cell, R, C, opts, date1904);
if(cell.c) comments.push([cell.c, R, C]);
}
}
/* ... 0x12 0x19 0x13 (Password) */
write_comments_biff2(ba, comments);
/* 0x3d (Window1) ... */
}
/* 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;
if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
write_biff_rec(ba, (o.biff == 4 ? 0x0409 : (o.biff == 3 ? 0x0209 : 0x0009)), write_BOF(wb, 0x10, o));
/* ... */
write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
/* ... */
if(((wb.Workbook||{}).WBProps||{}).date1904) write_biff_rec(ba, 0x0022, writebool(true));
o.cellXfs = [{numFmtId: 0}];
o._BIFF2FmtTable/*:Array<string>*/ = ["General"]; o._Fonts = [];
var body = buf_array();
write_ws_biff2(body, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
o._BIFF2FmtTable.forEach(function(f) {
if(o.biff <= 3) write_biff_rec(ba, 0x001E, write_BIFF2Format(f));
else write_biff_rec(ba, 0x041E, write_BIFF4Format(f));
});
o.cellXfs.forEach(function(xf) {
switch(o.biff) {
case 2: write_biff_rec(ba, 0x0043, write_BIFF2XF(xf)); break;
case 3: write_biff_rec(ba, 0x0243, write_BIFF3XF(xf)); break;
case 4: write_biff_rec(ba, 0x0443, write_BIFF4XF(xf)); break;
}
});
delete o._BIFF2FmtTable; delete o.cellXfs; delete o._Fonts;
ba.push(body.end());
write_biff_rec(ba, 0x000A);
return ba.end();
}
var b8oid = 1, b8ocnts/*:Array<[number, number, number]>*/ = [];
function write_MsoDrawingGroup() {
var buf = new_buf(82 + 8 * b8ocnts.length);
/* [MS-ODRAW] 2.2.12 OfficeArtDggContainer */
buf.write_shift(2, 0x0F);
buf.write_shift(2, 0xF000);
buf.write_shift(4, 74 + 8 * b8ocnts.length);
/* 2.2.48 OfficeArtFDGGBlock */
{
buf.write_shift(2, 0);
buf.write_shift(2, 0xF006);
buf.write_shift(4, 16 + 8 * b8ocnts.length);
/* 2.2.47 OfficeArtFDGG */
{
buf.write_shift(4, b8oid);
buf.write_shift(4, b8ocnts.length+1);
var acc = 0; for(var i = 0; i < b8ocnts.length; ++i) acc += (b8ocnts[i] && b8ocnts[i][1] || 0); buf.write_shift(4, acc);
buf.write_shift(4, b8ocnts.length);
}
/* 2.2.46 OfficeArtIDCL + */
b8ocnts.forEach(function(b8) {
buf.write_shift(4, b8[0]);
buf.write_shift(4, b8[2]);
});
}
/* 2.2.9 OfficeArtFOPT */
{
buf.write_shift(2, 0x33); // 0x03 | (3 << 4)
buf.write_shift(2, 0xF00B);
buf.write_shift(4, 0x12); // 3 * 6
/* 2.3.21.15 Text Boolean Properties */
buf.write_shift(2, 0xBF); buf.write_shift(4, 0x00080008);
/* 2.3.7.2 fillColor */
buf.write_shift(2, 0x0181); buf.write_shift(4, 0x08000041);
/* 2.3.8.1 lineColor */
buf.write_shift(2, 0x01C0); buf.write_shift(4, 0x08000040);
}
/* 2.2.45 OfficeArtSplitMenuColorContainer */
{
buf.write_shift(2, 0x40);
buf.write_shift(2, 0xF11E);
buf.write_shift(4, 16);
buf.write_shift(4, 0x0800000D);
buf.write_shift(4, 0x0800000C);
buf.write_shift(4, 0x08000017);
buf.write_shift(4, 0x100000F7);
}
return buf;
}
function write_comments_biff8(ba/*:BufArray*/, comments/*:Array<[Comment[], number, number]>*/) {
var notes/*:Array<RawData>*/ = [], sz = 0, pl = buf_array(), baseid = b8oid;
var _oasc;
comments.forEach(function(c, ci) {
var author = "";
var text = c[0].map(function(t) { if(t.a && !author) author = t.a; return t.t; }).join("");
++b8oid;
/* 2.2.14 OfficeArtSpContainer */
{
var oasc = new_buf(0x96);
oasc.write_shift(2, 0x0F);
oasc.write_shift(2, 0xF004);
oasc.write_shift(4, 0x96);
/* 2.2.40 OfficeArtFSP */
{
oasc.write_shift(2, 0xca2); // 0x02 | (0xca << 4)
oasc.write_shift(2, 0xF00A);
oasc.write_shift(4, 8);
oasc.write_shift(4, b8oid);
oasc.write_shift(4, 0xA00);
}
/* 2.2.9 OfficeArtFOPT */
{
oasc.write_shift(2, 0xE3); // 0x03 | (14 << 4)
oasc.write_shift(2, 0xF00B);
oasc.write_shift(4, 0x54); // 14 * 6
/* 2.3.21.1 ITxid */
oasc.write_shift(2, 0x80); oasc.write_shift(4, 0);
/* 2.3.21.12 txdir */
oasc.write_shift(2, 0x8B); oasc.write_shift(4, 0x02);
/* 2.3.21.15 Text Boolean Properties */
oasc.write_shift(2, 0xBF); oasc.write_shift(4, 0x00080008);
/* 2.3.6.30 cxk */
oasc.write_shift(2, 0x0158); oasc.l += 4;
/* 2.3.7.2 fillColor */
oasc.write_shift(2, 0x0181); oasc.write_shift(4, 0x08000050);
/* 2.3.7.4 fillBackColor */
oasc.write_shift(2, 0x0183); oasc.write_shift(4, 0x08000050);
/* 2.3.7.6 fillCrMod */
oasc.write_shift(2, 0x0185); oasc.write_shift(4, 0x100000F4);
/* 2.3.7.43 Fill Style Boolean Properties */
oasc.write_shift(2, 0x01BF); oasc.write_shift(4, 0x00100010);
/* 2.3.8.1 lineColor */
oasc.write_shift(2, 0x01C0); oasc.write_shift(4, 0x08000051);
/* 2.3.8.4 lineCrMod */
oasc.write_shift(2, 0x01C3); oasc.write_shift(4, 0x100000F4);
/* 2.3.13.2 shadowColor */
oasc.write_shift(2, 0x0201); oasc.write_shift(4, 0x08000051);
/* 2.3.13.4 shadowCrMod */
oasc.write_shift(2, 0x0203); oasc.write_shift(4, 0x100000F4);
/* 2.3.13.23 Shadow Style Boolean Properties */
oasc.write_shift(2, 0x023F); oasc.write_shift(4, 0x00030001);
/* 2.3.4.44 Group Shape Boolean Properties */
oasc.write_shift(2, 0x03BF); oasc.write_shift(4, 0x00020000 | (c[0].hidden ? 2 : 0));
}
/* [MS-XLS] 2.5.193 OfficeArtClientAnchorSheet */
{
oasc.l += 2;
oasc.write_shift(2, 0xF010);
oasc.write_shift(4, 0x12);
oasc.write_shift(2, 0x3); // do not move or size with cells
oasc.write_shift(2, c[2] + 2); oasc.l += 2;
oasc.write_shift(2, c[1] + 1); oasc.l += 2;
oasc.write_shift(2, c[2] + 4); oasc.l += 2;
oasc.write_shift(2, c[1] + 5); oasc.l += 2;
}
/* [MS-XLS] 2.5.194 OfficeArtClientData */
{
oasc.l += 2;
oasc.write_shift(2, 0xF011);
oasc.l += 4;
}
oasc.l = 0x96;
if(ci == 0) /* write_biff_rec(pl, 0x003C, oasc); */ _oasc = oasc;
else write_biff_rec(pl, 0x00EC, oasc);
}
sz += 0x96;
/* [MS-XLS] 2.4.181 Obj */
{
var obj = new_buf(52); // 22 + 26 + 4
/* [MS-XLS] 2.5.143 FtCmo */
obj.write_shift(2, 0x15);
obj.write_shift(2, 0x12);
obj.write_shift(2, 0x19);
obj.write_shift(2, b8oid);
obj.write_shift(2, 0);
obj.l = 22;
/* [MS-XLS] 2.5.149 FtNts */
obj.write_shift(2, 0x0D);
obj.write_shift(2, 0x16);
obj.write_shift(4, 0x62726272);
obj.write_shift(4, 0x95374305);
obj.write_shift(4, 0x80301328);
obj.write_shift(4, 0x69696904 + b8oid*256);
obj.write_shift(2,0);
obj.write_shift(4,0);
// reserved
obj.l += 4;
write_biff_rec(pl, 0x005D, obj);
}
/* [MS-XLS] 2.5.195 OfficeArtClientTextbox */
{
var oact = new_buf(8);
oact.l += 2;
oact.write_shift(2, 0xF00D);
oact.l += 4;
write_biff_rec(pl, 0x00EC, oact);
}
sz += 8;
/* [MS-XLS] 2.4.329 TxO */
{
var txo = new_buf(18);
txo.write_shift(2, 0x12);
txo.l += 8;
txo.write_shift(2, text.length);
txo.write_shift(2, 0x10);
txo.l += 4;
write_biff_rec(pl, 0x01b6, txo);
/* text continue record TODO: switch to wide strings */
{
var cont = new_buf(1 + text.length);
cont.write_shift(1, 0);
cont.write_shift(text.length, text, "sbcs");
write_biff_rec(pl, 0x003C, cont);
}
/* formatting continue records */
{
var conf = new_buf(0x10);
conf.l += 8;
conf.write_shift(2, text.length);
conf.l += 6;
write_biff_rec(pl, 0x003C, conf);
}
}
/* 2.4.179 Note */
{
var notesh = new_buf(12 + author.length);
notesh.write_shift(2, c[1]);
notesh.write_shift(2, c[2]);
notesh.write_shift(2, 0 | (c[0].hidden ? 0 : 2));
notesh.write_shift(2, b8oid);
notesh.write_shift(2, author.length);
notesh.write_shift(1, 0);
notesh.write_shift(author.length, author, "sbcs");
notesh.l ++;
notes.push(notesh);
}
});
/* [MS-ODRAW] 2.2.13 OfficeArtDgContainer */
{
var hdr = new_buf(80);
hdr.write_shift(2, 0x0F);
hdr.write_shift(2, 0xF002);
hdr.write_shift(4, sz + hdr.length - 8);
/* [MS-ODRAW] 2.2.49 OfficeArtFDG */
{
hdr.write_shift(2, 0x10);
hdr.write_shift(2, 0xF008);
hdr.write_shift(4, 0x08);
hdr.write_shift(4, comments.length + 1);
hdr.write_shift(4, b8oid);
}
/* [MS-ODRAW] 2.2.16 OfficeArtSpgrContainer */
{
hdr.write_shift(2, 0x0f);
hdr.write_shift(2, 0xF003);
hdr.write_shift(4, sz + 0x30);
/* [MS-ODRAW] 2.2.14 OfficeArtSpContainer */
{
hdr.write_shift(2, 0x0f);
hdr.write_shift(2, 0xF004);
hdr.write_shift(4, 0x28);
/* [MS-ODRAW] 2.2.38 OfficeArtFSPGR */
{
hdr.write_shift(2, 0x01);
hdr.write_shift(2, 0xF009);
hdr.write_shift(4, 0x10);
hdr.l += 16;
}
/* [MS-ODRAW] 2.2.40 OfficeArtFSP */
{
hdr.write_shift(2, 0x02);
hdr.write_shift(2, 0xF00A);
hdr.write_shift(4, 0x08);
hdr.write_shift(4, baseid);
hdr.write_shift(4, 0x05);
}
}
}
write_biff_rec(ba, 0x00EC, /* hdr */ _oasc ? bconcat([hdr, _oasc]) : hdr);
}
ba.push(pl.end());
notes.forEach(function(n) { write_biff_rec(ba, 0x001C, n); });
b8ocnts.push([baseid, comments.length + 1, b8oid]);
++b8oid;
}
function write_FONTS_biff8(ba, data, opts) {
write_biff_rec(ba, 0x0031 /* Font */, write_Font({
sz:12,
@ -173,7 +473,7 @@ function write_ws_cols_biff8(ba, cols) {
});
}
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, date1904/*:boolean*/) {
var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
if(cell.v == null && !cell.bf) {
write_biff_rec(ba, 0x0201 /* Blank */, write_XLSCell(R, C, os));
@ -182,9 +482,11 @@ function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
if(cell.bf) write_biff_rec(ba, 0x0006 /* Formula */, write_Formula(cell, R, C, opts, os));
else switch(cell.t) {
case 'd': case 'n':
var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
var v = cell.t == 'd' ? datenum(parseDate(cell.v, date1904), date1904) : 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 */
write_biff_rec(ba, 0x0203 /* Number */, write_Number(R, C, v, os, opts));
else 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));
@ -192,9 +494,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, opts.revStrings);
var isst = get_sst_id(opts.Strings, cell.v == null ? "" : String(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||"").slice(0,255), os, opts));
} else write_biff_rec(ba, 0x0204 /* Label */, write_Label(R, C, (cell.v == null ? "" : String(cell.v)).slice(0,255), os, opts));
break;
default:
write_biff_rec(ba, 0x0201 /* Blank */, write_XLSCell(R, C, os));
@ -207,7 +509,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 = Array.isArray(ws);
var dense = ws["!data"] != null;
var b8 = opts.biff == 8;
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1");
@ -241,24 +543,27 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
write_biff_rec(ba, 0x0200 /* Dimensions */, write_Dimensions(range, opts));
/* ... */
var date1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
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(var C = range.s.c; C <= range.e.c; ++C) {
if(R === range.s.r) cols[C] = encode_col(C);
for(C = range.s.c; C <= range.e.c; ++C) {
ref = cols[C] + rr;
var cell = dense ? (ws[R]||[])[C] : ws[ref];
var cell = dense ? row[C] : ws[ref];
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);
write_ws_biff8_cell(ba, cell, R, C, opts, date1904);
if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
if(b8 && cell.c) comments.push([ref, cell.c]);
if(cell.c) comments.push([cell.c, R, C]);
}
}
var cname/*:string*/ = _sheet.CodeName || _sheet.name || s;
/* ... */
// if(b8) comments.forEach(function(comment) { write_biff_rec(ba, 0x001c /* Note */, write_NoteSh(comment)); });
if(b8) write_comments_biff8(ba, comments); else write_comments_biff2(ba, comments);
/* ... */
if(b8) write_biff_rec(ba, 0x023e /* Window2 */, write_Window2((_WB.Views||[])[0]));
/* ... */
@ -328,8 +633,10 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
var C = buf_array();
/* METADATA [MTRSettings] [ForceFullCalculation] */
if(b8) write_biff_rec(C, 0x008C /* Country */, write_Country());
/* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture *MSODRAWINGGROUP */
/* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture */
/* BIFF8: MsoDrawingGroup [*Continue] */
if(b8 && b8ocnts.length) write_biff_rec(C, 0x00EB /* MsoDrawingGroup */, write_MsoDrawingGroup());
/* BIFF8: [SST *Continue] ExtSST */
if(b8 && opts.Strings) write_biff_continue(C, 0x00FC /* SST */, write_SST(opts.Strings, opts));
@ -372,6 +679,7 @@ function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
o.ssf = wb.SSF;
}
b8oid = 1; b8ocnts = [];
o.Strings = /*::((*/[]/*:: :any):SST)*/; o.Strings.Count = 0; o.Strings.Unique = 0;
fix_write_opts(o);

@ -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 || {};
if(DENSE != null && opts.dense == null) opts.dense = DENSE;
var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var dense = (opts.dense != null) ? opts.dense : DENSE;
var ws/*:Worksheet*/ = ({}/*:any*/); if(dense) ws["!data"] = [];
str = str.replace(/<!--.*?-->/g, "");
var mtch/*:any*/ = str.match(/<table/i);
if(!mtch) throw new Error("Invalid HTML: could not find <table>");
@ -45,10 +45,12 @@ function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ {
else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
else if(!isNaN(fuzzydate(m).getDate())) {
o = ({t:'d', v:parseDate(m)}/*:any*/);
if(opts.UTC === false) o.v = utc_to_local(o.v);
if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/);
o.z = opts.dateNF || table_fmt[14];
}
if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
if(o.cellText !== false) o.w = m;
if(dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = o; }
else ws[encode_cell({r:R, c:C})] = o;
C += CS;
}
@ -61,6 +63,7 @@ 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) {
@ -70,8 +73,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_cell({r:R,c:C});
var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
var coord = encode_col(C) + encode_row(R);
var cell = dense ? (ws["!data"][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*/);
@ -80,9 +83,10 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
else if(cell) {
sp["data-t"] = cell && cell.t || 'z';
if(cell.v != null) sp["data-v"] = cell.v;
// note: data-v is unaffected by the timezone interpretation
if(cell.v != null) sp["data-v"] = cell.v instanceof Date ? cell.v.toISOString() : cell.v;
if(cell.z != null) sp["data-z"] = cell.z;
if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + cell.l.Target +'">' + w + '</a>';
if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
}
sp.id = (o.id || "sjs") + "-" + coord;
oo.push(writextag('td', w, sp));
@ -118,10 +122,9 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
var header = o.header != null ? o.header : HTML_BEGIN;
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);
var r = decode_range(ws['!ref'] || "A1");
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));
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
out.push("</table>" + footer);
return out.join("");
}
@ -134,7 +137,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
}
var opts = _opts || {};
if(DENSE != null) opts.dense = DENSE;
var dense = ws["!data"] != null;
var or_R = 0, or_C = 0;
if(opts.origin != null) {
if(typeof opts.origin == 'number') or_R = opts.origin;
@ -187,6 +190,7 @@ function sheet_add_dom(ws/*:Worksheet*/, table/*:HTMLElement*/, _opts/*:?any*/)/
else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
else if(!isNaN(fuzzydate(v).getDate())) {
o = ({t:'d', v:parseDate(v)}/*:any*/);
if(opts.UTC) o.v = local_to_utc(o.v);
if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/);
o.z = opts.dateNF || table_fmt[14];
}
@ -199,7 +203,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(opts.dense) { if(!ws[R + or_R]) ws[R + or_R] = []; ws[R + or_R][C + or_C] = o; }
if(dense) { if(!ws["!data"][R + or_R]) ws["!data"][R + or_R] = []; ws["!data"][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 +219,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*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var ws/*:Worksheet*/ = ({}/*:any*/); if(opts.dense) ws["!data"] = [];
return sheet_add_dom(ws, table, _opts);
}

@ -245,11 +245,11 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
var sheetag/*:: = {name:"", '名称':""}*/;
var rowtag/*:: = {'行号':""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [];
var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var ws = ({}/*:any*/); if(opts.dense) ws["!data"] = [];
var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/;
var ctag = ({value:""}/*:any*/);
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var textR = [];
var textp = "", textpidx = 0, textptag/*:: = {}*/, oldtextp = "", oldtextpidx = 0;
var textR = [], oldtextR = [];
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
var row_ol = 0;
var number_format_map = _nfm || {}, styles = {};
@ -263,7 +263,6 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
var creator = "", creatoridx = 0;
var isstub = false, intable = false;
var i = 0;
var baddate = 0;
xlmlregex.lastIndex = 0;
str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
@ -289,7 +288,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 = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = [];
ws = ({}/*:any*/); if(opts.dense) ws["!data"] = []; merges = [];
rowinfo = [];
intable = true;
}
@ -309,7 +308,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[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
if(opts.dense) { if(!ws["!data"][R]) ws["!data"][R] = []; ws["!data"][R][C] = {t:'z'}; }
else ws[encode_cell({r:R,c:C})] = {t:'z'};
}
textp = ""; textR = [];
@ -325,16 +324,16 @@ 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[R]) ws[R] = [];
ws[R][C] = q;
if(!ws["!data"][R]) ws["!data"][R] = [];
ws["!data"][R][C] = q;
} else {
ws[encode_cell({r:R,c:C})] = q;
ws[encode_col(C) + encode_row(R)] = q;
}
}
C+= colpeat-1;
} else if(Rn[1]!=='/') {
++C;
textp = ""; textpidx = 0; textR = [];
textp = oldtextp = ""; textpidx = oldtextpidx = 0; textR = []; oldtextR = [];
colpeat = 1;
var rptR = rowpeat ? R + rowpeat - 1 : R;
if(C > range.e.c) range.e.c = C;
@ -370,19 +369,23 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
/* 19.675.2 table:number-columns-repeated */
if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
/* 19.385 office:value-type */
/* 19.385 office:value-type TODO: verify ODS and UOS */
switch(q.t) {
case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']) || (+ctag['boolean-value'] >= 1); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'float': q.t = 'n'; q.v = parseFloat(ctag.value);
if(opts.cellDates && q.z && fmt_is_date(q.z)) { q.v = numdate(q.v + (WB.WBProps.date1904 ? 1462 : 0)); q.t = typeof q.v == "number" ? 'n' : 'd'; }
break;
case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v, WB.WBProps.date1904) - baddate; }
case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value'], WB.WBProps.date1904);
if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v, WB.WBProps.date1904); }
if(!q.z) q.z = 'm/d/yy'; break;
/* NOTE: for `time`, Excel ODS export incorrectly uses durations relative to 1900 epoch even if 1904 is specified */
case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400;
if(opts.cellDates) { q.t = 'd'; q.v = numdate(q.v); }
if(opts.cellDates) { q.v = numdate(q.v); q.t = typeof q.v == "number" ? 'n' : 'd'; }
if(!q.z) q.z = 'HH:MM:SS'; break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']);
break;
default:
if(q.t === 'string' || q.t === 'text' || !q.t) {
q.t = 's';
@ -405,9 +408,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[R + rpt]) ws[R + rpt] = [];
ws[R + rpt][C] = rpt == 0 ? q : dup(q);
while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
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);
} else {
ws[encode_cell({r:R + rpt,c:C})] = q;
while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
@ -443,10 +446,17 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
if(textR.length) /*::(*/comment/*:: :any)*/.R = textR;
comment.a = creator;
comments.push(comment);
textp = oldtextp; textpidx = oldtextpidx; textR = oldtextR;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
state.push([Rn[3], false]);
var annotag = parsexmltag(Rn[0], true);
/* office:display TODO: check if there is a global override */
if(!(annotag["display"] && parsexmlbool(annotag["display"]))) comments.hidden = true;
oldtextp = textp; oldtextpidx = textpidx; oldtextR = textR;
textp = ""; textpidx = 0; textR = [];
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
creator = ""; creatoridx = 0;
textp = ""; textpidx = 0; textR = [];
break;
case 'creator': // 4.3.2.7 <dc:creator>
@ -572,9 +582,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'null-date': // 9.4.2 <table:null-date>
tag = parsexmltag(Rn[0], false);
switch(tag["date-value"]) {
case "1904-01-01": WB.WBProps.date1904 = true;
/* falls through */
case "1900-01-01": baddate = 0;
case "1904-01-01": WB.WBProps.date1904 = true; break;
}
break;
@ -596,6 +604,9 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) {
var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0];
} else if(Rn[0].slice(-2) == "/>") {
/* TODO: is self-closing 文本串 valid? */
textp += "\n";
} else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
break; // <text:p>
case 's': break; // <text:s>
@ -625,10 +636,13 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
case 'help-message': break; // 9.4.6 <table:
case 'error-message': break; // 9.4.7 <table:
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
/* 9.5 Filters */
case 'filter': break; // 9.5.2 <table:filter>
case 'filter-and': break; // 9.5.3 <table:filter-and>
case 'filter-or': break; // 9.5.4 <table:filter-or>
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
case 'list-level-style-bullet': break; // 16.31 <text:
case 'list-level-style-number': break; // 16.32 <text:

@ -99,7 +99,9 @@ function write_number_format_ods(nf/*:string*/, nfidx/*:string*/)/*:string*/ {
while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i;
payload += '<number:text>' + escapexml(c.slice(1).replace(/""/g, '"')) + '</number:text>';
break;
case '/': payload += '<number:text>' + escapexml(c) + '</number:text>'; break;
case '\\': c = nf[++i];
payload += '<number:text>' + escapexml(c) + '</number:text>'; break;
case '/': case ':': payload += '<number:text>' + escapexml(c) + '</number:text>'; break;
default: console.error("unrecognized character " + c + " in ODF format " + nf);
}
if(!has_time) break j;
@ -126,7 +128,7 @@ function write_number_format_ods(nf/*:string*/, nfidx/*:string*/)/*:string*/ {
while(nf[++i] != '"' || nf[++i] == '"') c += nf[i]; --i;
payload += '<number:text>' + escapexml(c.slice(1).replace(/""/g, '"')) + '</number:text>';
break;
case '/': payload += '<number:text>' + escapexml(c) + '</number:text>'; break;
case '/': case ':': payload += '<number:text>' + escapexml(c) + '</number:text>'; break;
case "a":
if(nf.slice(i, i+3).toLowerCase() == "a/p") { payload += '<number:am-pm/>'; i += 2; break; } // Note: ODF does not support A/P
if(nf.slice(i, i+5).toLowerCase() == "am/pm") { payload += '<number:am-pm/>'; i += 4; break; }
@ -182,10 +184,15 @@ function write_number_format_ods(nf/*:string*/, nfidx/*:string*/)/*:string*/ {
}
function write_names_ods(Names, SheetNames, idx) {
var scoped = Names.filter(function(name) { return name.Sheet == (idx == -1 ? null : idx); });
//var scoped = Names.filter(function(name) { return name.Sheet == (idx == -1 ? null : idx); });
var scoped = []; for(var namei = 0; namei < Names.length; ++namei) {
var name = Names[namei];
if(!name) continue;
if(name.Sheet == (idx == -1 ? null : idx)) scoped.push(name);
}
if(!scoped.length) return "";
return " <table:named-expressions>\n" + scoped.map(function(name) {
var odsref = csf_to_ods_3D(name.Ref);
var odsref = (idx == -1 ? "$" : "") + csf_to_ods_3D(name.Ref);
return " " + writextag("table:named-range", null, {
"table:name": name.Name,
"table:cell-range-address": odsref,
@ -204,14 +211,13 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
};
var null_cell_xml = ' <table:table-cell />\n';
var covered_cell_xml = ' <table:covered-table-cell/>\n';
var write_ws = function(ws, wb/*:Workbook*/, i/*:number*/, opts, nfs)/*:string*/ {
var write_ws = function(ws, wb/*:Workbook*/, i/*:number*/, opts, nfs, date1904)/*:string*/ {
/* Section 9 Tables */
var o/*:Array<string>*/ = [];
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 = Array.isArray(ws);
var dense = ws["!data"] != null;
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');
}
@ -236,8 +242,8 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
ct['table:number-rows-spanned'] = (marr[mi].e.r - marr[mi].s.r + 1);
break;
}
if(skip) { o.push(covered_cell_xml); continue; }
var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
if(skip) { o.push(' <table:covered-table-cell/>\n'); continue; }
var ref = encode_cell({r:R, c:C}), cell = dense ? (ws["!data"][R]||[])[C]: ws[ref];
if(cell && cell.f) {
ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
if(cell.F) {
@ -265,13 +271,13 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
ct['office:value-type'] = "string";
break;
case 'd':
textp = (cell.w||(parseDate(cell.v).toISOString()));
textp = (cell.w||(parseDate(cell.v, date1904).toISOString()));
ct['office:value-type'] = "date";
ct['office:date-value'] = (parseDate(cell.v).toISOString());
ct['office:date-value'] = (parseDate(cell.v, date1904).toISOString());
ct['table:style-name'] = "ce1";
break;
//case 'e':
default: o.push(null_cell_xml); continue;
//case 'e': // TODO: translate to ODS errors
default: o.push(null_cell_xml); continue; // TODO: empty cell with comments
}
var text_p = write_text_p(textp);
if(cell.l && cell.l.Target) {
@ -282,7 +288,17 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
text_p = writextag('text:a', text_p, {'xlink:href': _tgt.replace(/&/g, "&amp;")});
}
if(nfs[cell.z]) ct["table:style-name"] = "ce" + nfs[cell.z].slice(1);
o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
var payload = writextag('text:p', text_p, {});
if(cell.c) {
var acreator = "", apayload = "", aprops = {};
for(var ci = 0; ci < cell.c.length; ++ci) {
if(!acreator && cell.c[ci].a) acreator = cell.c[ci].a;
apayload += "<text:p>" + write_text_p(cell.c[ci].t) + "</text:p>";
}
if(!cell.c.hidden) aprops["office:display"] = true;
payload = writextag('office:annotation', apayload, aprops) + payload;
}
o.push(' ' + writextag('table:table-cell', payload, ct) + '\n');
}
o.push(' </table:table-row>\n');
}
@ -347,9 +363,11 @@ 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);
if(!ws["!ref"]) return;
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 = Array.isArray(ws) ? (ws[R]||[])[C] : ws[encode_cell({r:R,c:C})];
var c = dense ? (ws["!data"][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);
@ -426,7 +444,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
o.push(' <office:body>\n');
o.push(' <office:spreadsheet>\n');
if(((wb.Workbook||{}).WBProps||{}).date1904) o.push(' <table:calculation-settings table:case-sensitive="false" table:search-criteria-must-apply-to-whole-cell="true" table:use-wildcards="true" table:use-regular-expressions="false" table:automatic-find-labels="false">\n <table:null-date table:date-value="1904-01-01"/>\n </table:calculation-settings>\n');
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts, nfs));
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts, nfs, ((wb.Workbook||{}).WBProps||{}).date1904));
if((wb.Workbook||{}).Names) o.push(write_names_ods(wb.Workbook.Names, wb.SheetNames, -1));
o.push(' </office:spreadsheet>\n');
o.push(' </office:body>\n');

File diff suppressed because it is too large Load Diff

@ -13,6 +13,13 @@ function safe_parse_wbrels(wbrels, sheets) {
return !wbrels || wbrels.length === 0 ? null : wbrels;
}
function parse_sheet_legacy_drawing(sheet, type, zip, path, idx, opts, wb, comments) {
if(!sheet || !sheet['!legdrawel']) return;
var dfile = resolve_path(sheet['!legdrawel'].Target, path);
var draw = getzipstr(zip, dfile, true);
if(draw) parse_vml(utf8read(draw), sheet, comments||[]);
}
function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/*:number*/, sheetRels, sheets, stype/*:string*/, opts, wb, themes, styles) {
try {
sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
@ -36,12 +43,12 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/
sheets[sheet] = _ws;
/* scan rels for comments and threaded comments */
var tcomments = [];
var comments = [], 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);
var comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
if(!comments || !comments.length) return;
sheet_insert_comments(_ws, comments, false);
}
@ -51,6 +58,7 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/
}
});
if(tcomments && tcomments.length) sheet_insert_comments(_ws, tcomments, true, opts.people || []);
parse_sheet_legacy_drawing(_ws, stype, zip, path, idx, opts, wb, comments);
} catch(e) { if(opts.WTF) throw e; }
}

@ -51,6 +51,9 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
}
var people = ["SheetJ5"];
opts.tcid = 0;
for(rId=1;rId <= wb.SheetNames.length; ++rId) {
var wsrels = {'!id':{}};
var ws = wb.Sheets[wb.SheetNames[rId-1]];
@ -70,6 +73,17 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
var need_vml = false;
var cf = "";
if(comments && comments.length > 0) {
var needtc = false;
comments.forEach(function(carr) {
carr[1].forEach(function(c) { if(c.T == true) needtc = true; });
});
if(needtc) {
cf = "xl/threadedComments/threadedComment" + rId + ".xml";
zip_add_file(zip, cf, write_tcmnt_xml(comments, people, opts));
ct.threadedcomments.push(cf);
add_rels(wsrels, -1, "../threadedComments/threadedComment" + rId + ".xml", RELS.TCMNT);
}
cf = "xl/comments" + rId + "." + wbext;
zip_add_file(zip, cf, write_comments_bin(comments, opts));
ct.comments.push(cf);
@ -101,7 +115,8 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
/* TODO: something more intelligent with themes */
f = "xl/theme/theme1.xml";
zip_add_file(zip, f, write_theme(wb.Themes, opts));
var ww = write_theme(wb.Themes, opts);
zip_add_file(zip, f, ww);
ct.themes.push(f);
add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
@ -124,6 +139,13 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
ct.metadata.push(f);
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
if(people.length > 1) {
f = "xl/persons/person.xml";
zip_add_file(zip, f, write_people_xml(people, opts));
ct.people.push(f);
add_rels(opts.wbrels, -1, "persons/person.xml", RELS.PEOPLE);
}
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));

@ -50,7 +50,13 @@ 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);
d = typeof $cptable !== "undefined" ? $cptable.utils.decode(1200, d.slice(2), 'str') : utf16leread(d.slice(2));
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))
);
o.type = "binary";
return read_plaintext(d, o);
}

@ -4,18 +4,18 @@ type MJRObject = {
isempty: boolean;
};
*/
function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, dense/*:boolean*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ {
function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ {
var rr = encode_row(R);
var defval = o.defval, raw = o.raw || !Object.prototype.hasOwnProperty.call(o, "raw");
var isempty = true;
var isempty = true, dense = (sheet["!data"] != null);
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[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(!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(val == null || val.t === undefined) {
if(defval === undefined) continue;
if(hdr[C] != null) { row[hdr[C]] = defval; }
continue;
@ -24,7 +24,12 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
switch(val.t){
case 'z': if(v == null) break; continue;
case 'e': v = (v == 0 ? null : void 0); break;
case 's': case 'd': case 'b': case 'n': break;
case 's': case 'b':
case 'n': if(!val.z || !fmt_is_date(val.z)) break;
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
if(typeof v == "number") break;
/* falls through */
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -34,7 +39,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
else if(raw && v === null) row[hdr[C]] = null;
else continue;
} else {
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
}
if(v != null) isempty = false;
}
@ -63,16 +68,16 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) {
var cols/*:Array<string>*/ = [];
var out/*:Array<any>*/ = [];
var outi = 0, counter = 0;
var dense = Array.isArray(sheet);
var dense = sheet["!data"] != null;
var R = r.s.r, C = 0;
var header_cnt = {};
if(dense && !sheet[R]) sheet[R] = [];
if(dense && !sheet["!data"][R]) sheet["!data"][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[R][C] : sheet[cols[C] + rr];
val = dense ? sheet["!data"][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 +96,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, dense, o);
var row = make_json_row(sheet, r, R, cols, header, hdr, o);
if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
}
out.length = outi;
@ -102,9 +107,11 @@ 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 = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
var val = dense ? datarow[C]: sheet[cols[C] + rr];
if(val == null) txt = "";
else if(val.v != null) {
isempty = false;
@ -131,7 +138,6 @@ 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);
@ -143,7 +149,6 @@ 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 +165,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 = Array.isArray(sheet);
var dense = sheet["!data"] != null;
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[R]||[])[C] : sheet[y];
x = dense ? (sheet["!data"][R]||[])[C] : sheet[y];
val = "";
if(x === undefined) continue;
else if(x.F != null) {
@ -191,10 +196,11 @@ 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 ? Array.isArray(_ws) : o.dense;
var dense = _ws ? (_ws["!data"] != null) : o.dense;
if(DENSE != null && dense == null) dense = DENSE;
var offset = +!o.skipHeader;
var ws/*:Worksheet*/ = _ws || (dense ? ([]/*:any*/) : ({}/*:any*/));
var ws/*:Worksheet*/ = _ws || ({});
if(!_ws && dense) ws["!data"] = [];
var _R = 0, _C = 0;
if(ws && o.origin != null) {
if(typeof o.origin == 'number') _R = o.origin;
@ -213,25 +219,27 @@ 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(!ws[_R + R + offset]) ws[_R + R + offset] = [];
var ROW = ws[_R + R + offset];
if(dense && !ws["!data"][_R + R + offset]) ws["!data"][_R + R + offset] = [];
if(dense) ROW = ws["!data"][_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_cell({c:_C + C,r:_R + R + offset});
var ref = dense ? "" : (encode_col(_C + C) + encode_row(_R + R + offset));
var cell/*:Cell*/ = dense ? ROW[_C + C] : ws[ref];
if(v && typeof v === 'object' && !(v instanceof Date)){
ws[ref] = v;
if(dense) ROW[_C + C] = v;
else ws[ref] = v;
} else {
if(typeof v == 'number') t = 'n';
else if(typeof v == 'boolean') t = 'b';
else if(typeof v == 'string') t = 's';
else if(v instanceof Date) {
t = 'd';
if(!o.UTC) v = local_to_utc(v);
if(!o.cellDates) { t = 'n'; v = datenum(v); }
z = (cell != null && cell.z && fmt_is_date(cell.z)) ? cell.z : (o.dateNF || table_fmt[14]);
}
@ -239,8 +247,7 @@ 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;
@ -251,9 +258,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[_R]) ws[_R] = [];
if(dense && !ws["!data"][_R]) ws["!data"][_R] = [];
if(offset) for(C = 0; C < hdr.length; ++C) {
if(dense) ws[_R][C + _C] = {t:'s', v:hdr[C]};
if(dense) ws["!data"][_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);
@ -265,18 +272,17 @@ 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") {
/* dense */
if(Array.isArray(ws)) {
if(ws["!data"] != null) {
var RC = decode_cell(R);
if(!ws[RC.r]) ws[RC.r] = [];
return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
if(!ws["!data"][RC.r]) ws["!data"][RC.r] = [];
return ws["!data"][RC.r][RC.c] || (ws["!data"][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_cell({r:R,c:C||0}));
return ws_get_cell_stub(ws, encode_col(C||0) + encode_row(R));
}
/* find sheet index for given name / validate index */
@ -291,9 +297,11 @@ function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
} else throw new Error("Cannot find sheet |" + sh + "|");
}
/* simple blank workbook object */
function book_new()/*:Workbook*/ {
return { SheetNames: [], Sheets: {} };
/* simple blank or single-sheet workbook object */
function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ {
var wb = { SheetNames: [], Sheets: {} };
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
return wb;
}
/* add a worksheet to the end of a given workbook */

@ -9,6 +9,7 @@ var utils/*:any*/ = {
decode_cell: decode_cell,
decode_range: decode_range,
format_cell: format_cell,
sheet_new: sheet_new,
sheet_add_aoa: sheet_add_aoa,
sheet_add_json: sheet_add_json,
sheet_add_dom: sheet_add_dom,

@ -10,7 +10,6 @@ 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);
@ -40,7 +39,6 @@ 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;
@ -78,16 +76,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 = Array.isArray(sheet);
var dense = sheet["!data"] != null;
var R = r.s.r, C = 0;
var header_cnt = {};
if(dense && !sheet[R]) sheet[R] = [];
if(dense && !sheet["!data"][R]) sheet["!data"][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[R][C] : sheet[cols[C] + rr];
val = dense ? sheet["!data"][R][C] : sheet[cols[C] + rr];
switch(header) {
case 1: hdr[C] = C - r.s.c; break;
case 2: hdr[C] = cols[C]; break;
@ -108,7 +106,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, dense, o);
var row = make_json_row(sheet, r, R, cols, header, hdr, o);
++R;
if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
stream.push(row.row);

@ -10,6 +10,8 @@ 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;

@ -1,78 +0,0 @@
# Demos
These demos are intended to demonstrate how to load this library in various
ecosystems. The library is designed to be used in the web browser and in node
contexts, using dynamic feature tests to pull in features when necessary. This
works extremely well in common use cases: script tag insertion and node require.
Systems like webpack try to be clever by performing simple static analysis to
pull in code. However, they do not support dynamic type tests, breaking
compatibility with traditional scripts. Configuration is required. The demos
cover basic configuration steps for various systems and should "just work".
Mobile app and other larger demos do not include the full build structure. The
demos have `Makefile` scripts that show how to reproduce the full projects. The
scripts have been tested against iOS and OSX. For Windows platforms, GNU make
can be installed with Bash on Windows or with `cygwin`.
### Included Demos
**JavaScript APIs**
- [`XMLHttpRequest and fetch`](https://docs.sheetjs.com/docs/demos/network)
- [`Clipboard Data`](https://docs.sheetjs.com/docs/demos/clipboard)
- [`Typed Arrays for Machine Learning`](https://docs.sheetjs.com/docs/demos/ml)
- [`LocalStorage and SessionStorage`](https://docs.sheetjs.com/docs/demos/database#localstorage-and-sessionstorage)
- [`Web SQL Database`](https://docs.sheetjs.com/docs/demos/database#websql)
- [`IndexedDB`](https://docs.sheetjs.com/docs/demos/database#indexeddb)
**Frameworks**
- [`Angular 2+ and Ionic`](https://docs.sheetjs.com/docs/demos/angular)
- [`React`](https://docs.sheetjs.com/docs/demos/react)
- [`VueJS`](https://docs.sheetjs.com/docs/demos/vue)
- [`Angular.JS`](https://docs.sheetjs.com/docs/demos/legacy#angularjs)
- [`Knockout`](https://docs.sheetjs.com/docs/demos/legacy#knockoutjs)
**Front-End UI Components**
- [`canvas-datagrid`](https://docs.sheetjs.com/docs/demos/grid#canvas-datagrid)
- [`x-spreadsheet`](https://docs.sheetjs.com/docs/demos/grid#x-spreadsheet)
- [`react-data-grid`](https://docs.sheetjs.com/docs/demos/grid#react-data-grid)
- [`vue3-table-lite`](https://docs.sheetjs.com/docs/demos/grid#vue3-table-lite)
- [`angular-ui-grid`](https://docs.sheetjs.com/docs/demos/grid#angular-ui-grid)
**Platforms and Integrations**
- [`Command-Line Tools`](https://docs.sheetjs.com/docs/demos/cli)
- [`iOS and Android Mobile Applications`](https://docs.sheetjs.com/docs/demos/mobile)
- [`NodeJS Server-Side Processing`](https://docs.sheetjs.com/docs/demos/server#nodejs)
- [`Content Management and Static Sites`](https://docs.sheetjs.com/docs/demos/content)
- [`Electron`](https://docs.sheetjs.com/docs/demos/desktop#electron)
- [`NW.js`](https://docs.sheetjs.com/docs/demos/desktop#nwjs)
- [`Tauri`](https://docs.sheetjs.com/docs/demos/desktop#tauri)
- [`Chrome and Chromium Extensions`](https://docs.sheetjs.com/docs/demos/chromium)
- [`Google Sheets API`](https://docs.sheetjs.com/docs/demos/gsheet)
- [`ExtendScript for Adobe Apps`](https://docs.sheetjs.com/docs/demos/extendscript)
- [`NetSuite SuiteScript`](https://docs.sheetjs.com/docs/demos/netsuite)
- [`SalesForce Lightning Web Components`](https://docs.sheetjs.com/docs/demos/salesforce)
- [`Excel JavaScript API`](https://docs.sheetjs.com/docs/demos/excel)
- [`Headless Automation`](https://docs.sheetjs.com/docs/demos/headless)
- [`Other JavaScript Engines`](https://docs.sheetjs.com/docs/demos/engines)
- [`Azure Functions and Storage`](https://docs.sheetjs.com/docs/demos/azure)
- [`Amazon Web Services`](https://docs.sheetjs.com/docs/demos/aws)
- [`Databases and Structured Data Stores`](https://docs.sheetjs.com/docs/demos/database)
- [`NoSQL and Unstructured Data Stores`](https://docs.sheetjs.com/docs/demos/nosql)
- [`Legacy Internet Explorer`](https://docs.sheetjs.com/docs/demos/legacy#internet-explorer)
**Bundlers and Tooling**
- [`browserify`](https://docs.sheetjs.com/docs/demos/bundler#browserify)
- [`bun`](https://docs.sheetjs.com/docs/demos/bundler#bun)
- [`esbuild`](https://docs.sheetjs.com/docs/demos/bundler#esbuild)
- [`parcel`](https://docs.sheetjs.com/docs/demos/bundler#parcel)
- [`requirejs`](https://docs.sheetjs.com/docs/demos/bundler#requirejs)
- [`rollup`](https://docs.sheetjs.com/docs/demos/bundler#rollup)
- [`snowpack`](https://docs.sheetjs.com/docs/demos/bundler#snowpack)
- [`swc`](https://docs.sheetjs.com/docs/demos/bundler#swc)
- [`systemjs`](https://docs.sheetjs.com/docs/demos/bundler#systemjs)
- [`vite`](https://docs.sheetjs.com/docs/demos/bundler#vite)
- [`webpack`](https://docs.sheetjs.com/docs/demos/bundler#webpack)
- [`wmr`](https://docs.sheetjs.com/docs/demos/bundler#wmr)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +0,0 @@
# Other JS Engines and Deployments
[The new demo](https://docs.sheetjs.com/docs/demos/engines)
includes more detailed instructions and more JS engines.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,10 +0,0 @@
# AngularJS
The content has been reorganized;
- [The "Legacy Frameworks" section](https://docs.sheetjs.com/docs/demos/legacy#angularjs)
covers the AngularJS basics.
- [The "Angular UI Grid" section](https://docs.sheetjs.com/docs/demos/legacy#angularjs)
covers the integration with Angular UI Grid.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,11 +0,0 @@
# Angular 2+
[The new demo](https://docs.sheetjs.com/docs/demos/angular) has an updated
exposition for legacy and modern deployments alike.
The ecosystem demos were grouped by type in the new demo site:
- [NativeScript](https://docs.sheetjs.com/docs/demos/mobile#nativescript) is now part of "iOS and Android Apps"
- [Ionic](https://docs.sheetjs.com/docs/demos/mobile#ionic) is now part of "iOS and Android Apps"
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# Typed Arrays and Math
[The new demo](https://docs.sheetjs.com/docs/demos/ml) includes
interactive examples as well as strategies for CSV and JS Array interchange.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# Browserify
[The new demo](https://docs.sheetjs.com/docs/demos/bundler#browserify)
includes a more concise example.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# Chrome and Chromium
[The new demo](https://docs.sheetjs.com/docs/demos/chromium)
includes more up-to-date details.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,11 +0,0 @@
# Databases
This demo has been split up for clarity:
- <https://docs.sheetjs.com/docs/demos/database> covers SQL and
structured data (including CRUD operations)
- https://docs.sheetjs.com/docs/demos/nosql covers unstructured
data including "NoSQL" data stores.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +0,0 @@
# canvas-datagrid
[The new demo](https://docs.sheetjs.com/docs/demos/grid#canvas-datagrid)
includes a live example and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,13 +0,0 @@
# Deno
Deno is a runtime capable of running JS code including this library.
Demos have been integrated in the [documentation](https://docs.sheetjs.com) :
- <https://docs.sheetjs.com/docs/installation/deno> installation
- <https://docs.sheetjs.com/docs/example> writing JS data to a spreadsheet
- <https://docs.sheetjs.com/docs/solutions/input> input strategies
- <https://docs.sheetjs.com/docs/solutions/output> output strategies
- <https://docs.sheetjs.com/docs/demos/cli#deno> `deno compile`
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# Electron
[The new demo](https://docs.sheetjs.com/docs/demos/desktop#electron)
includes an improved example and detailed explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +0,0 @@
# Adobe ExtendScript
[The new demo](https://docs.sheetjs.com/docs/demos/extendscript)
has a more focused Photoshop example as well as notes about other extensibility
frameworks shipping with newer versions of Creative Cloud apps.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,9 +0,0 @@
# "Serverless" Functions
Cloud services are covered in separate demos:
- [AWS](https://docs.sheetjs.com/docs/demos/aws)
- [Azure](https://docs.sheetjs.com/docs/demos/azure)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,9 +0,0 @@
# Google Sheets API
The old demo used a deprecated version of the Google Sheets API to export data
from Google Sheets Documents.
[The new demo](https://docs.sheetjs.com/docs/demos/gsheet) uses
the new Google Sheets API to read and write data.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,8 +0,0 @@
# Headless Browsers
[The new demo](https://docs.sheetjs.com/docs/demos/headless)
has a more focused table export example as well as a demo script for Chromium
automation with Puppeteer and multi-browser automation with Playwright.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +0,0 @@
# Knockout
[The new demo](https://docs.sheetjs.com/docs/demos/legacy#knockoutjs)
includes a live example and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,8 +0,0 @@
# Meteor
This demo originally covered Meteor's package manager and other nuances. At the
time the demo was written, Meteor had its own ecosystem that clashed with the
burgeoning NodeJS package ecosystem. Eventually, Meteor added proper support
for NodeJS modules. New projects should follow the instructions for packages.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# NW.js
[The new demo](https://docs.sheetjs.com/docs/demos/desktop#nwjs)
includes an improved example and detailed explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# Internet Explorer
[The new demo](https://docs.sheetjs.com/docs/demos/legacy#internet-explorer)
includes a live example and easier integration bundle.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# Parcel
[The new demo](https://docs.sheetjs.com/docs/demos/bundler#parcel)
includes a more concise example.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,12 +0,0 @@
# React
[The new demo](https://docs.sheetjs.com/docs/demos/react) has an updated
exposition for legacy and modern deployments alike.
The ecosystem demos were grouped by type in the new demo site:
- [server-rendered React components with `next.js`](https://docs.sheetjs.com/docs/demos/content#nextjs) is now part of "Content and Site Generation"
- [`react-native` deployment for iOS and android](https://docs.sheetjs.com/docs/demos/mobile#react-native) is now part of "iOS and Android Apps"
- [`react-data-grid` reading, modifying, and writing files](https://docs.sheetjs.com/docs/demo/grid#react-data-grid) 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)

@ -1,7 +0,0 @@
# RequireJS
[The new demo](https://docs.sheetjs.com/docs/demos/bundler#requirejs)
includes a live example and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +0,0 @@
# Rollup
[The new demo](https://docs.sheetjs.com/docs/demos/bundler#rollup)
includes a simple example and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,11 +0,0 @@
# NodeJS Server Deployments
[The new demo](https://docs.sheetjs.com/docs/demos/server) has a more focused
discussion with examples for popular JS server-side frameworks.
Cloud services are covered in separate demos:
- [AWS](https://docs.sheetjs.com/docs/demos/aws)
- [Azure](https://docs.sheetjs.com/docs/demos/azure)
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,6 +0,0 @@
# SystemJS Demos
[The new demo](https://docs.sheetjs.com/docs/demos/bundler#systemjs)
includes a live example and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,9 +0,0 @@
# TypeScript
This demo originally covered direct use of the `tsc` TypeScript compiler. At
the time when the demo was first written, TypeScript 2.2 had a module system
that was incompatible with the pure JS ecosystem. Since then, various
language improvements and compiler changes have obviated this demo. Uses of
TypeScript are scattered throughout other demos.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,12 +0,0 @@
# VueJS
[The new demo](https://docs.sheetjs.com/docs/demos/vue) has an updated
exposition for legacy and modern deployments alike.
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/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)

@ -1,6 +0,0 @@
# Webpack
[The new demo](https://docs.sheetjs.com/docs/demos/bundler#webpack)
reflects the new default behavior to use the ESM build.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,7 +0,0 @@
# XMLHttpRequest and fetch
[The new demo](https://docs.sheetjs.com/docs/demos/network)
includes interactive demos and improved explanations.
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,18 +0,0 @@
# x-spreadsheet
The `sheet_to_json` utility function generates output arrays suitable for use
with other JS libraries such as data grids for previewing data. With a familiar
UI, [`x-spreadsheet`](https://myliang.github.io/x-spreadsheet/) is an excellent
choice for developers looking for a modern editor.
[The new docs](https://docs.sheetjs.com/docs/demos/grid/#x-spreadsheet)
include more detail and examples.
The original demo is available at <https://docs.sheetjs.com/xspreadsheet/>
A hosted version of the `xlsxspread.js` script is available on the SheetJS CDN:
- <https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js> original script
- <https://cdn.sheetjs.com/xspreadsheet/xlsxspread.min.js> minified
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx)

@ -1,133 +0,0 @@
/*! xlsxspread.js (C) SheetJS LLC -- https://sheetjs.com/ */
/* eslint-env browser */
/*global XLSX */
/*exported stox, xtos */
console.log("The latest version of the xlsxspread.js script is at https://cdn.sheetjs.com/xspreadsheet/xlsxspread.js !")
/**
* Converts data from SheetJS to x-spreadsheet
*
* @param {Object} wb SheetJS workbook object
*
* @returns {Object[]} An x-spreadsheet data
*/
function stox(wb) {
var out = [];
wb.SheetNames.forEach(function (name) {
var o = { name: name, rows: {} };
var ws = wb.Sheets[name];
if(!ws || !ws["!ref"]) return;
var range = XLSX.utils.decode_range(ws['!ref']);
// sheet_to_json will lost empty row and col at begin as default
range.s = { r: 0, c: 0 };
var aoa = XLSX.utils.sheet_to_json(ws, {
raw: false,
header: 1,
range: range
});
aoa.forEach(function (r, i) {
var cells = {};
r.forEach(function (c, j) {
cells[j] = { text: c };
var cellRef = XLSX.utils.encode_cell({ r: i, c: j });
if ( ws[cellRef] != null && ws[cellRef].f != null) {
cells[j].text = "=" + ws[cellRef].f;
}
});
o.rows[i] = { cells: cells };
});
o.merges = [];
(ws["!merges"]||[]).forEach(function (merge, i) {
//Needed to support merged cells with empty content
if (o.rows[merge.s.r] == null) {
o.rows[merge.s.r] = { cells: {} };
}
if (o.rows[merge.s.r].cells[merge.s.c] == null) {
o.rows[merge.s.r].cells[merge.s.c] = {};
}
o.rows[merge.s.r].cells[merge.s.c].merge = [
merge.e.r - merge.s.r,
merge.e.c - merge.s.c
];
o.merges[i] = XLSX.utils.encode_range(merge);
});
out.push(o);
});
return out;
}
/**
* Converts data from x-spreadsheet to SheetJS
*
* @param {Object[]} sdata An x-spreadsheet data object
*
* @returns {Object} A SheetJS workbook object
*/
function xtos(sdata) {
var out = XLSX.utils.book_new();
sdata.forEach(function (xws) {
var ws = {};
var rowobj = xws.rows;
var minCoord = { r: 0, c: 0 }, maxCoord = { r: 0, c: 0 };
for (var ri = 0; ri < rowobj.len; ++ri) {
var row = rowobj[ri];
if (!row) continue;
Object.keys(row.cells).forEach(function (k) {
var idx = +k;
if (isNaN(idx)) return;
var lastRef = XLSX.utils.encode_cell({ r: ri, c: idx });
if (ri > maxCoord.r) maxCoord.r = ri;
if (idx > maxCoord.c) maxCoord.c = idx;
var cellText = row.cells[k].text, type = "s";
if (!cellText) {
cellText = "";
type = "z";
} else if (!isNaN(Number(cellText))) {
cellText = Number(cellText);
type = "n";
} else if (cellText.toLowerCase() === "true" || cellText.toLowerCase() === "false") {
cellText = Boolean(cellText);
type = "b";
}
ws[lastRef] = { v: cellText, t: type };
if (type == "s" && cellText[0] == "=") {
ws[lastRef].f = cellText.slice(1);
}
if (row.cells[k].merge != null) {
if (ws["!merges"] == null) ws["!merges"] = [];
ws["!merges"].push({
s: { r: ri, c: idx },
e: {
r: ri + row.cells[k].merge[0],
c: idx + row.cells[k].merge[1]
}
});
}
});
}
ws["!ref"] = minCoord ? XLSX.utils.encode_range({
s: minCoord,
e: maxCoord
}) : "A1";
XLSX.utils.book_append_sheet(out, ws, xws.name);
});
return out;
}

39
dist/cpexcel.d.ts generated vendored Normal file

@ -0,0 +1,39 @@
/* 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

4187
dist/xlsx.extendscript.js generated vendored

File diff suppressed because it is too large Load Diff

35
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 Normal file

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

Binary file not shown.

Before

Width:  |  Height:  |  Size: 204 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Some files were not shown because too many files have changed in this diff Show More