version bump 0.20.0

This commit is contained in:
SheetJS 2023-06-23 05:48:47 -04:00
parent 36c5b7c0f5
commit 955543147d
52 changed files with 8034 additions and 2893 deletions

1
.gitignore vendored

@ -28,6 +28,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]

@ -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]

@ -4,6 +4,10 @@ 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.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

@ -107,13 +107,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 esbuild@0.14.14 --bundle misc/import.js | wc -c)"
@npx printj "%-30s %10d" "treeshake" "$$(npx -y esbuild@0.14.14 --bundle misc/import.js | wc -c)"
.PHONY: git
@ -141,6 +141,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 $<
@ -165,6 +169,11 @@ TESTFMT=$(patsubst %,test_%,$(FMT))
$(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_%:

@ -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.19.3';
XLSX.version = '0.20.0';

@ -203,15 +203,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 +260,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);
}
@ -957,7 +948,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;

@ -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*/ {
@ -170,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[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(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);
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(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);
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;
}
@ -208,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()));
}

@ -162,6 +162,7 @@ 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); }
}

@ -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);
@ -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;
@ -1029,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;
}
@ -1076,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
@ -1089,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;
@ -1097,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 };
}

@ -179,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;
@ -202,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; }
@ -473,10 +481,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;
@ -577,7 +584,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':
@ -585,7 +592,7 @@ 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 '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;
@ -622,6 +629,7 @@ 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*/;
@ -629,34 +637,44 @@ var SYLK = /*#__PURE__*/(function() {
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 = [];
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));
}
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(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
/* Excel has been inconsistent in comment placement, */
for(var R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
var p = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
if(!cell || !cell.c) continue;
p.push(write_ws_cmnt_sylk(cell.c, R, C)); // TODO: pass date1904 info
}
o.push(p.join(RS));
}
for(var R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
var p = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
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;
}
@ -696,7 +714,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:
@ -977,9 +998,11 @@ 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; }
@ -989,14 +1012,14 @@ var PRN = /*#__PURE__*/(function() {
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';

@ -24,6 +24,22 @@ 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 || {};
@ -34,6 +50,7 @@ var WK_ = /*#__PURE__*/(function() {
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) {
@ -65,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) {
@ -86,15 +103,25 @@ var WK_ = /*#__PURE__*/(function() {
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(!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;
@ -171,10 +198,17 @@ var WK_ = /*#__PURE__*/(function() {
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)));
}
@ -308,11 +342,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 +395,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 +409,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 +467,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 +477,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 +819,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,6 +966,24 @@ 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",
/*::[*/0x22/*::*/: "0.00",
/*::[*/0x32/*::*/: "0.00;[Red]0.00",
/*::[*/0x42/*::*/: "0.00;\(0.00\)",
/*::[*/0x52/*::*/: "0.00;[Red]\(0.00\)",
/*::[*/162/*::*/: '"$"#,##0;\\("$"#,##0\\)' // slightly different from SSF 5
};
/* QPW uses a different set of record types */
function qpw_to_workbook_buf(d, opts)/*:Workbook*/ {
prep_blob(d, 0);
@ -924,6 +994,7 @@ var WK_ = /*#__PURE__*/(function() {
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 +1005,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;
@ -996,18 +1083,21 @@ var WK_ = /*#__PURE__*/(function() {
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;
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;
@ -1016,10 +1106,14 @@ var WK_ = /*#__PURE__*/(function() {
default: throw "Unsupported delta for QPW cell type " + (flags & 0x1F);
}
if(!(!o.sheetStubs && cell.t == "z")) {
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] = cell;
} else s[CC + encode_row(R)] = cell;
s["!data"][R][C] = newcell;
} else s[CC + encode_row(R)] = newcell;
}
++R; --cnt;
while(mul-- > 0 && cnt >= 0) {
@ -1034,6 +1128,7 @@ 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(s["!data"] != null) {
if(!s["!data"][R]) s["!data"][R] = [];

@ -5,6 +5,7 @@ function parse_vml(data/*:string*/, sheet, comments) {
(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);

@ -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;

@ -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);
@ -76,6 +76,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
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;
@ -261,7 +262,7 @@ 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 = "";
@ -274,11 +275,14 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
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;
@ -321,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;
@ -332,6 +336,7 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
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;
@ -476,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':
@ -496,8 +501,8 @@ 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;
@ -522,6 +527,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
var o/*:Array<string>*/ = [], r/*:Array<string>*/ = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols/*:Array<string>*/ = [], R=0, C=0, rows = ws['!rows'];
var dense = ws["!data"] != null;
var 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 = [];
@ -530,7 +536,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
ref = cols[C] + rr;
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*/);

@ -542,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;
@ -585,7 +586,7 @@ 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["!data"][R]) s["!data"][R] = []; s["!data"][R][C] = p; }
else s[encode_col(C) + rr] = p;
@ -606,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;
@ -809,7 +810,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
}
/* 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;
@ -819,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;
@ -872,8 +873,9 @@ 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 = ws["!data"] != null;
var cap = range.e.r;
@ -891,7 +893,7 @@ function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Work
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 */);

@ -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);
@ -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'*/:

@ -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)); }
}
}
@ -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;
@ -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--;
@ -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;
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 */
@ -369,19 +373,19 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 0x0203 /* Number */: case 0x0003 /* BIFF2NUM */: case 0x0002 /* BIFF2INT */: {
if(out["!type"] == "chart") if(options.dense ? (out["!data"][val.r]||[])[val.c]: out[encode_col(val.c) + encode_row(val.r)]) ++val.c;
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);
}
@ -407,7 +411,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
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;
@ -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);

@ -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 },
@ -1260,7 +1260,7 @@ var XLSRecordEnum = {
/* - - - */
/*::[*/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);
@ -67,29 +58,48 @@ function write_comments_biff2(ba/*:BufArray*/, comments/*:Array<[Comment[], numb
});
}
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*//*::, opts*/) {
/* 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':
// 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*/) {
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) {
@ -97,7 +107,9 @@ function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
}
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] || [];
@ -106,7 +118,7 @@ function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/
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]);
}
}
@ -119,14 +131,32 @@ function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/
/* Based on test files */
function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
var o = opts || {};
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();
}
@ -147,7 +177,7 @@ function write_MsoDrawingGroup() {
{
buf.write_shift(4, b8oid);
buf.write_shift(4, b8ocnts.length+1);
buf.write_shift(4, b8ocnts.reduce(function(acc,x) { return acc+x[1]; }, 0));
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 + */
@ -185,7 +215,7 @@ function write_comments_biff8(ba/*:BufArray*/, comments/*:Array<[Comment[], numb
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("");
var text = c[0].map(function(t) { if(t.a && !author) author = t.a; return t.t; }).join("");
++b8oid;
/* 2.2.14 OfficeArtSpContainer */
@ -336,7 +366,7 @@ function write_comments_biff8(ba/*:BufArray*/, comments/*:Array<[Comment[], numb
/* [MS-ODRAW] 2.2.13 OfficeArtDgContainer */
{
var hdr = new_buf(80);
hdr.write_shift(2, 0x0F)
hdr.write_shift(2, 0x0F);
hdr.write_shift(2, 0xF002);
hdr.write_shift(4, sz + hdr.length - 8);
/* [MS-ODRAW] 2.2.49 OfficeArtFDG */
@ -443,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));
@ -452,7 +482,7 @@ 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 */
@ -513,6 +543,7 @@ 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 = [];
@ -525,7 +556,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
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(cell.c) comments.push([cell.c, R, C]);
}

@ -45,9 +45,11 @@ 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(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;
@ -81,7 +83,8 @@ 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="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
}
@ -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];
}

@ -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(/_.*$/,""))) {
@ -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';
@ -579,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;

@ -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,7 +211,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
};
var null_cell_xml = ' <table: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');
@ -264,9 +271,9 @@ 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': // TODO: translate to ODS errors
@ -436,7 +443,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');

@ -566,10 +566,10 @@ function numbers_format_cell(cell, t, flags, ofmt, nfmt) {
cell.w = cell.w.replace(/:(\d\d\d)$/, ".$1");
}
}
function parse_old_storage(buf, lut, v) {
function parse_old_storage(buf, lut, v, opts) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(4, true);
var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dt = new Date(2001, 0, 1);
var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dc = 0, dt = new Date(Date.UTC(2001, 0, 1));
var doff = v > 1 ? 12 : 8;
if (flags & 2) {
zidx = dv.getUint32(doff, true);
@ -590,7 +590,7 @@ function parse_old_storage(buf, lut, v) {
doff += 8;
}
if (flags & 64) {
dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3);
dt.setTime(dt.getTime() + (dc = dv.getFloat64(doff, true)) * 1e3);
doff += 8;
}
if (v > 1) {
@ -613,7 +613,12 @@ function parse_old_storage(buf, lut, v) {
ret = { t: "s", v: lut.sst[sidx] };
break;
case 5:
{
if (opts == null ? void 0 : opts.cellDates)
ret = { t: "d", v: dt };
else
ret = { t: "n", v: dc / 86400 + 35430, z: table_fmt[14] };
}
break;
case 6:
ret = { t: "b", v: ieee > 0 };
@ -644,12 +649,12 @@ function parse_old_storage(buf, lut, v) {
ret.v /= 86400;
return ret;
}
function parse_new_storage(buf, lut) {
function parse_new_storage(buf, lut, opts) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(4, true);
var fields = dv.getUint32(8, true);
var doff = 12;
var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1), eidx = -1, fidx = -1;
var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dc = 0, dt = new Date(Date.UTC(2001, 0, 1)), eidx = -1, fidx = -1;
if (fields & 1) {
d128 = readDecimal128LE(buf, doff);
doff += 16;
@ -659,7 +664,7 @@ function parse_new_storage(buf, lut) {
doff += 8;
}
if (fields & 4) {
dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3);
dt.setTime(dt.getTime() + (dc = dv.getFloat64(doff, true)) * 1e3);
doff += 8;
}
if (fields & 8) {
@ -693,7 +698,12 @@ function parse_new_storage(buf, lut) {
ret = { t: "s", v: lut.sst[sidx] };
break;
case 5:
{
if (opts == null ? void 0 : opts.cellDates)
ret = { t: "d", v: dt };
else
ret = { t: "n", v: dc / 86400 + 35430, z: table_fmt[14] };
}
break;
case 6:
ret = { t: "b", v: ieee > 0 };
@ -744,10 +754,18 @@ function write_new_storage(cell, lut) {
out[0] = 5;
switch (cell.t) {
case "n":
if (cell.z && fmt_is_date(cell.z)) {
out[1] = 5;
dv.setFloat64(l, (numdate(cell.v + 1462).getTime() - Date.UTC(2001, 0, 1)) / 1e3, true);
fields |= 4;
l += 8;
break;
} else {
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
fields |= 1;
l += 16;
}
break;
case "b":
out[1] = 6;
@ -780,6 +798,12 @@ function write_new_storage(cell, lut) {
}
}
break;
case "d":
out[1] = 5;
dv.setFloat64(l, (cell.v.getTime() - Date.UTC(2001, 0, 1)) / 1e3, true);
fields |= 4;
l += 8;
break;
case "z":
out[1] = 0;
break;
@ -796,7 +820,7 @@ function write_new_storage(cell, lut) {
return out[subarray](0, l);
}
function write_old_storage(cell, lut) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0;
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0, s = "";
out[0] = 4;
switch (cell.t) {
case "n":
@ -805,7 +829,7 @@ function write_old_storage(cell, lut) {
break;
case "s":
{
var s = cell.v == null ? "" : String(cell.v);
s = cell.v == null ? "" : String(cell.v);
if (cell.l) {
var irsst = lut.rsst.findIndex(function(v) {
var _a;
@ -821,6 +845,10 @@ function write_old_storage(cell, lut) {
}
}
break;
case "d":
break;
case "e":
break;
case "z":
break;
default:
@ -846,7 +874,7 @@ function write_old_storage(cell, lut) {
break;
case "s":
{
var s = cell.v == null ? "" : String(cell.v);
s = cell.v == null ? "" : String(cell.v);
if (cell.l) {
} else {
var isst = lut.sst.indexOf(s);
@ -859,6 +887,12 @@ function write_old_storage(cell, lut) {
}
}
break;
case "d":
out[1] = 5;
dv.setFloat64(l, (cell.v.getTime() - Date.UTC(2001, 0, 1)) / 1e3, true);
fields |= 64;
l += 8;
break;
case "z":
out[1] = 0;
break;
@ -868,16 +902,16 @@ function write_old_storage(cell, lut) {
dv.setUint32(8, fields, true);
return out[subarray](0, l);
}
function parse_cell_storage(buf, lut) {
function parse_cell_storage(buf, lut, opts) {
switch (buf[0]) {
case 0:
case 1:
case 2:
case 3:
case 4:
return parse_old_storage(buf, lut, buf[0]);
return parse_old_storage(buf, lut, buf[0], opts);
case 5:
return parse_new_storage(buf, lut);
return parse_new_storage(buf, lut, opts);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -1082,7 +1116,7 @@ function s5s_to_iwa_comment(s5s) {
}
return out;
}
function parse_TST_TableModelArchive(M, root, ws) {
function parse_TST_TableModelArchive(M, root, ws, opts) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var pb = parse_shallow(root.data);
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
@ -1121,7 +1155,7 @@ function parse_TST_TableModelArchive(M, root, ws) {
var _tile = parse_TST_Tile(M, ref2);
_tile.data.forEach(function(row, R) {
row.forEach(function(buf, C) {
var res = parse_cell_storage(buf, lut);
var res = parse_cell_storage(buf, lut, opts);
if (res) {
if (dense) {
if (!dws["!data"][_R + R])
@ -1162,7 +1196,7 @@ function parse_TST_TableInfoArchive(M, root, opts) {
var mtype = varint_to_i32(tableref[0].meta[1][0].data);
if (mtype != 6001)
throw new Error("6000 unexpected reference to ".concat(mtype));
parse_TST_TableModelArchive(M, tableref[0], out);
parse_TST_TableModelArchive(M, tableref[0], out, opts);
return out;
}
function parse_TN_SheetArchive(M, root, opts) {
@ -1185,6 +1219,7 @@ function parse_TN_SheetArchive(M, root, opts) {
function parse_TN_DocumentArchive(M, root, opts) {
var _a;
var out = book_new();
out.Workbook = { WBProps: { date1904: true } };
var pb = parse_shallow(root.data);
if ((_a = pb[2]) == null ? void 0 : _a[0])
throw new Error("Keynote presentations are not supported");
@ -1300,8 +1335,8 @@ function write_TST_TileRowInfo(data, lut, wide) {
switch (data[C].t) {
case "d":
if (data[C].v instanceof Date) {
celload = write_new_storage({ t: "s", v: data[C].v.toISOString() }, lut);
_celload = write_old_storage({ t: "s", v: data[C].v.toISOString() }, lut);
celload = write_new_storage(data[C], lut);
_celload = write_old_storage(data[C], lut);
break;
}
celload = write_new_storage(data[C], lut);

@ -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)) v = utc_to_local(v); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -234,6 +239,7 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet
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]);
}

32
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

2209
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

@ -566,10 +566,10 @@ function numbers_format_cell(cell, t, flags, ofmt, nfmt) {
cell.w = cell.w.replace(/:(\d\d\d)$/, ".$1");
}
}
function parse_old_storage(buf, lut, v) {
function parse_old_storage(buf, lut, v, opts) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(4, true);
var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dt = new Date(2001, 0, 1);
var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dc = 0, dt = new Date(Date.UTC(2001, 0, 1));
var doff = v > 1 ? 12 : 8;
if (flags & 2) {
zidx = dv.getUint32(doff, true);
@ -590,7 +590,7 @@ function parse_old_storage(buf, lut, v) {
doff += 8;
}
if (flags & 64) {
dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3);
dt.setTime(dt.getTime() + (dc = dv.getFloat64(doff, true)) * 1e3);
doff += 8;
}
if (v > 1) {
@ -613,7 +613,12 @@ function parse_old_storage(buf, lut, v) {
ret = { t: "s", v: lut.sst[sidx] };
break;
case 5:
{
if (opts == null ? void 0 : opts.cellDates)
ret = { t: "d", v: dt };
else
ret = { t: "n", v: dc / 86400 + 35430, z: table_fmt[14] };
}
break;
case 6:
ret = { t: "b", v: ieee > 0 };
@ -644,12 +649,12 @@ function parse_old_storage(buf, lut, v) {
ret.v /= 86400;
return ret;
}
function parse_new_storage(buf, lut) {
function parse_new_storage(buf, lut, opts) {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(4, true);
var fields = dv.getUint32(8, true);
var doff = 12;
var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1), eidx = -1, fidx = -1;
var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dc = 0, dt = new Date(Date.UTC(2001, 0, 1)), eidx = -1, fidx = -1;
if (fields & 1) {
d128 = readDecimal128LE(buf, doff);
doff += 16;
@ -659,7 +664,7 @@ function parse_new_storage(buf, lut) {
doff += 8;
}
if (fields & 4) {
dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1e3);
dt.setTime(dt.getTime() + (dc = dv.getFloat64(doff, true)) * 1e3);
doff += 8;
}
if (fields & 8) {
@ -693,7 +698,12 @@ function parse_new_storage(buf, lut) {
ret = { t: "s", v: lut.sst[sidx] };
break;
case 5:
{
if (opts == null ? void 0 : opts.cellDates)
ret = { t: "d", v: dt };
else
ret = { t: "n", v: dc / 86400 + 35430, z: table_fmt[14] };
}
break;
case 6:
ret = { t: "b", v: ieee > 0 };
@ -744,10 +754,18 @@ function write_new_storage(cell, lut) {
out[0] = 5;
switch (cell.t) {
case "n":
if (cell.z && fmt_is_date(cell.z)) {
out[1] = 5;
dv.setFloat64(l, (numdate(cell.v + 1462).getTime() - Date.UTC(2001, 0, 1)) / 1e3, true);
fields |= 4;
l += 8;
break;
} else {
out[1] = 2;
writeDecimal128LE(out, l, cell.v);
fields |= 1;
l += 16;
}
break;
case "b":
out[1] = 6;
@ -780,6 +798,12 @@ function write_new_storage(cell, lut) {
}
}
break;
case "d":
out[1] = 5;
dv.setFloat64(l, (cell.v.getTime() - Date.UTC(2001, 0, 1)) / 1e3, true);
fields |= 4;
l += 8;
break;
case "z":
out[1] = 0;
break;
@ -796,7 +820,7 @@ function write_new_storage(cell, lut) {
return out[subarray](0, l);
}
function write_old_storage(cell, lut) {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0;
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0, s = "";
out[0] = 4;
switch (cell.t) {
case "n":
@ -805,7 +829,7 @@ function write_old_storage(cell, lut) {
break;
case "s":
{
var s = cell.v == null ? "" : String(cell.v);
s = cell.v == null ? "" : String(cell.v);
if (cell.l) {
var irsst = lut.rsst.findIndex(function(v) {
var _a;
@ -821,6 +845,10 @@ function write_old_storage(cell, lut) {
}
}
break;
case "d":
break;
case "e":
break;
case "z":
break;
default:
@ -846,7 +874,7 @@ function write_old_storage(cell, lut) {
break;
case "s":
{
var s = cell.v == null ? "" : String(cell.v);
s = cell.v == null ? "" : String(cell.v);
if (cell.l) {
} else {
var isst = lut.sst.indexOf(s);
@ -859,6 +887,12 @@ function write_old_storage(cell, lut) {
}
}
break;
case "d":
out[1] = 5;
dv.setFloat64(l, (cell.v.getTime() - Date.UTC(2001, 0, 1)) / 1e3, true);
fields |= 64;
l += 8;
break;
case "z":
out[1] = 0;
break;
@ -868,16 +902,16 @@ function write_old_storage(cell, lut) {
dv.setUint32(8, fields, true);
return out[subarray](0, l);
}
function parse_cell_storage(buf, lut) {
function parse_cell_storage(buf, lut, opts) {
switch (buf[0]) {
case 0:
case 1:
case 2:
case 3:
case 4:
return parse_old_storage(buf, lut, buf[0]);
return parse_old_storage(buf, lut, buf[0], opts);
case 5:
return parse_new_storage(buf, lut);
return parse_new_storage(buf, lut, opts);
default:
throw new Error("Unsupported payload version ".concat(buf[0]));
}
@ -1082,7 +1116,7 @@ function s5s_to_iwa_comment(s5s) {
}
return out;
}
function parse_TST_TableModelArchive(M, root, ws) {
function parse_TST_TableModelArchive(M, root, ws, opts) {
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
var pb = parse_shallow(root.data);
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
@ -1121,7 +1155,7 @@ function parse_TST_TableModelArchive(M, root, ws) {
var _tile = parse_TST_Tile(M, ref2);
_tile.data.forEach(function(row, R) {
row.forEach(function(buf, C) {
var res = parse_cell_storage(buf, lut);
var res = parse_cell_storage(buf, lut, opts);
if (res) {
if (dense) {
if (!dws["!data"][_R + R])
@ -1162,7 +1196,7 @@ function parse_TST_TableInfoArchive(M, root, opts) {
var mtype = varint_to_i32(tableref[0].meta[1][0].data);
if (mtype != 6001)
throw new Error("6000 unexpected reference to ".concat(mtype));
parse_TST_TableModelArchive(M, tableref[0], out);
parse_TST_TableModelArchive(M, tableref[0], out, opts);
return out;
}
function parse_TN_SheetArchive(M, root, opts) {
@ -1185,6 +1219,7 @@ function parse_TN_SheetArchive(M, root, opts) {
function parse_TN_DocumentArchive(M, root, opts) {
var _a;
var out = book_new();
out.Workbook = { WBProps: { date1904: true } };
var pb = parse_shallow(root.data);
if ((_a = pb[2]) == null ? void 0 : _a[0])
throw new Error("Keynote presentations are not supported");
@ -1300,8 +1335,8 @@ function write_TST_TileRowInfo(data, lut, wide) {
switch (data[C].t) {
case "d":
if (data[C].v instanceof Date) {
celload = write_new_storage({ t: "s", v: data[C].v.toISOString() }, lut);
_celload = write_old_storage({ t: "s", v: data[C].v.toISOString() }, lut);
celload = write_new_storage(data[C], lut);
_celload = write_old_storage(data[C], lut);
break;
}
celload = write_new_storage(data[C], lut);

@ -4,7 +4,7 @@
/* these are type imports and do not show up in the generated JS */
import { CFB$Container, CFB$Entry } from 'cfb';
import { WorkBook, WorkSheet, Range, CellObject, ParsingOptions, WritingOptions, DenseWorkSheet, Comments } from '../';
import type { utils } from "../";
import type { utils, NumberFormat } from "../";
declare var encode_col: typeof utils.encode_col;
declare var encode_row: typeof utils.encode_row;
@ -12,6 +12,9 @@ declare var encode_range: typeof utils.encode_range;
declare var book_new: typeof utils.book_new;
declare var book_append_sheet: typeof utils.book_append_sheet;
declare var decode_range: typeof utils.decode_range;
declare var numdate: (num: number) => Date;
declare var table_fmt: {[nf: number]: string};
declare function fmt_is_date(fmt: NumberFormat): boolean;
import * as _CFB from 'cfb';
declare var CFB: typeof _CFB;
//<<import { utils } from "../../";
@ -487,11 +490,11 @@ function numbers_format_cell(cell: CellObject, t: number, flags: number, ofmt: P
}
/** Parse "old storage" (version 0..4) */
function parse_old_storage(buf: Uint8Array, lut: DataLUT, v: 0|1|2|3|4): CellObject | void {
function parse_old_storage(buf: Uint8Array, lut: DataLUT, v: 0|1|2|3|4, opts?: ParsingOptions): CellObject | void {
var dv = u8_to_dataview(buf);
var flags = dv.getUint32(4, true);
var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dt = new Date(2001, 0, 1);
var ridx = -1, sidx = -1, zidx = -1, ieee = NaN, dc = 0, dt = new Date(Date.UTC(2001, 0, 1));
var doff = (v > 1 ? 12 : 8);
if(flags & 0x0002) { zidx = dv.getUint32(doff, true); doff += 4;}
doff += popcnt(flags & (v > 1 ? 0x0D8C : 0x018C)) * 4;
@ -500,7 +503,7 @@ function parse_old_storage(buf: Uint8Array, lut: DataLUT, v: 0|1|2|3|4): CellObj
doff += popcnt(flags & (v > 1 ? 0x3000 : 0x1000)) * 4;
if(flags & 0x0010) { sidx = dv.getUint32(doff, true); doff += 4; }
if(flags & 0x0020) { ieee = dv.getFloat64(doff, true); doff += 8; }
if(flags & 0x0040) { dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1000); doff += 8; }
if(flags & 0x0040) { dt.setTime(dt.getTime() + (dc = dv.getFloat64(doff, true)) * 1000); doff += 8; }
if(v > 1) {
flags = dv.getUint32(8, true) >>> 16;
@ -514,7 +517,10 @@ function parse_old_storage(buf: Uint8Array, lut: DataLUT, v: 0|1|2|3|4): CellObj
case 0: return void 0; // return { t: "z" }; // blank?
case 2: ret = { t: "n", v: ieee }; break; // number
case 3: ret = { t: "s", v: lut.sst[sidx] }; break; // string
case 5: ret = { t: "d", v: dt }; break; // date-time
case 5: { // date-time
if(opts?.cellDates) ret = { t: "d", v: dt };
else ret = ({ t: "n", v: dc/(86400)+35430, z: table_fmt[14]});
} break;
case 6: ret = { t: "b", v: ieee > 0 }; break; // boolean
case 7: ret = { t: "n", v: ieee }; break; // duration in seconds
case 8: ret = { t: "e", v: 0}; break; // "formula error" TODO: enumerate and map errors to csf equivalents
@ -534,19 +540,19 @@ function parse_old_storage(buf: Uint8Array, lut: DataLUT, v: 0|1|2|3|4): CellObj
}
/** Parse "new storage" (version 5) */
function parse_new_storage(buf: Uint8Array, lut: DataLUT): CellObject | void {
function parse_new_storage(buf: Uint8Array, lut: DataLUT, opts?: ParsingOptions): CellObject | void {
var dv = u8_to_dataview(buf);
// TODO: bytes 2:3 appear to be unused?
var flags = dv.getUint32(4, true);
var fields = dv.getUint32(8, true);
var doff = 12;
var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1), eidx = -1, fidx = -1;
var ridx = -1, sidx = -1, zidx = -1, d128 = NaN, ieee = NaN, dc = 0, dt = new Date(Date.UTC(2001, 0, 1)), eidx = -1, fidx = -1;
// 0x00001F data
if(fields & 0x000001) { d128 = readDecimal128LE(buf, doff); doff += 16; }
if(fields & 0x000002) { ieee = dv.getFloat64(doff, true); doff += 8; }
if(fields & 0x000004) { dt.setTime(dt.getTime() + dv.getFloat64(doff, true) * 1000); doff += 8; }
if(fields & 0x000004) { dt.setTime(dt.getTime() + (dc = dv.getFloat64(doff, true)) * 1000); doff += 8; }
if(fields & 0x000008) { sidx = dv.getUint32(doff, true); doff += 4; }
if(fields & 0x000010) { ridx = dv.getUint32(doff, true); doff += 4; }
@ -564,7 +570,10 @@ function parse_new_storage(buf: Uint8Array, lut: DataLUT): CellObject | void {
case 0: ret = { t: "z" }; break;
case 2: ret = { t: "n", v: d128 }; break; // number
case 3: ret = { t: "s", v: lut.sst[sidx] }; break; // string
case 5: ret = { t: "d", v: dt }; break; // date-time
case 5: { // date-time
if(opts?.cellDates) ret = { t: "d", v: dt };
else ret = ({ t: "n", v: dc/(86400)+35430, z: table_fmt[14]});
} break;
case 6: ret = { t: "b", v: ieee > 0 }; break; // boolean
case 7: ret = { t: "n", v: ieee }; break; // duration in "s", fixed later
case 8: ret = { t: "e", v: 0 }; break; // "formula error" TODO: enumerate and map errors to csf equivalents
@ -603,7 +612,11 @@ function write_new_storage(cell: CellObject, lut: DataLUT): Uint8Array {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0;
out[0] = 5;
switch(cell.t) {
case "n": out[1] = 2; writeDecimal128LE(out, l, cell.v as number); fields |= 1; l += 16; break;
case "n": if(cell.z && fmt_is_date(cell.z)) {
out[1] = 5; dv.setFloat64(l, ((numdate((cell.v as number) + 1462)).getTime() - Date.UTC(2001, 0, 1))/1000, true); fields |= 4; l += 8; break
} else {
out[1] = 2; writeDecimal128LE(out, l, cell.v as number); fields |= 1; l += 16;
} break
case "b": out[1] = 6; dv.setFloat64(l, cell.v ? 1 : 0, true); fields |= 2; l += 8; break;
case "s": {
var s = cell.v == null ? "" : String(cell.v);
@ -617,6 +630,8 @@ function write_new_storage(cell: CellObject, lut: DataLUT): Uint8Array {
out[1] = 3; dv.setUint32(l, isst, true); fields |= 8; l += 4;
}
} break;
case "d": out[1] = 5; dv.setFloat64(l, ((cell.v as Date).getTime() - Date.UTC(2001, 0, 1))/1000, true); fields |= 4; l += 8; break;
case "z": out[1] = 0; break;
default: throw "unsupported cell type " + cell.t;
}
@ -629,20 +644,22 @@ function write_new_storage(cell: CellObject, lut: DataLUT): Uint8Array {
}
/** Write a cell "old storage" (version 4) */
function write_old_storage(cell: CellObject, lut: DataLUT): Uint8Array {
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0;
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, fields = 0, s = "";
out[0] = 4;
/* note: rich text appears *before* comments */
switch(cell.t) {
case "n": break;
case "b": break;
case "s": {
var s = cell.v == null ? "" : String(cell.v);
s = cell.v == null ? "" : String(cell.v);
if(cell.l) {
var irsst = lut.rsst.findIndex(v => v.v == s && v.l == cell.l?.Target);
if(irsst == -1) lut.rsst[irsst = lut.rsst.length] = { v: s, l: cell.l.Target };
out[1] = 9; dv.setUint32(l, irsst, true); fields |= 0x200; l += 4;
} else { }
} break;
case "d": break;
case "e": break;
case "z": break;
default: throw "unsupported cell type " + cell.t;
}
@ -654,13 +671,14 @@ function write_old_storage(cell: CellObject, lut: DataLUT): Uint8Array {
case "n": out[1] = 2; dv.setFloat64(l, cell.v as number, true); fields |= 0x20; l += 8; break;
case "b": out[1] = 6; dv.setFloat64(l, cell.v ? 1 : 0, true); fields |= 0x20; l += 8; break;
case "s": {
var s = cell.v == null ? "" : String(cell.v);
s = cell.v == null ? "" : String(cell.v);
if(cell.l) { } else {
var isst = lut.sst.indexOf(s);
if(isst == -1) lut.sst[isst = lut.sst.length] = s;
out[1] = 3; dv.setUint32(l, isst, true); fields |= 0x10; l += 4;
}
} break;
case "d": out[1] = 5; dv.setFloat64(l, ((cell.v as Date).getTime() - Date.UTC(2001, 0, 1))/1000, true); fields |= 0x40; l += 8; break;
case "z": out[1] = 0; break;
default: throw "unsupported cell type " + cell.t;
}
@ -668,11 +686,11 @@ function write_old_storage(cell: CellObject, lut: DataLUT): Uint8Array {
return out[subarray](0, l);
}
//<<export { write_new_storage, write_old_storage };
function parse_cell_storage(buf: Uint8Array, lut: DataLUT): CellObject | void {
function parse_cell_storage(buf: Uint8Array, lut: DataLUT, opts?: ParsingOptions): CellObject | void {
switch(buf[0]) {
case 0: case 1:
case 2: case 3: case 4: return parse_old_storage(buf, lut, buf[0]);
case 5: return parse_new_storage(buf, lut);
case 2: case 3: case 4: return parse_old_storage(buf, lut, buf[0], opts);
case 5: return parse_new_storage(buf, lut, opts);
default: throw new Error(`Unsupported payload version ${buf[0]}`);
}
}
@ -885,7 +903,7 @@ function s5s_to_iwa_comment(s5s: Comments): IWAComment {
}
/** Parse .TST.TableModelArchive (6001) */
function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: WorkSheet) {
function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: WorkSheet, opts?: ParsingOptions) {
var pb = parse_shallow(root.data);
var range: Range = { s: {r:0, c:0}, e: {r:0, c:0} };
range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1;
@ -918,7 +936,7 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work
var _tile = parse_TST_Tile(M, ref);
_tile.data.forEach((row, R) => {
row.forEach((buf, C) => {
var res = parse_cell_storage(buf, lut);
var res = parse_cell_storage(buf, lut, opts);
if(res) {
if(dense) {
if(!dws["!data"][_R + R]) dws["!data"][_R + R] = [];
@ -959,7 +977,7 @@ function parse_TST_TableInfoArchive(M: MessageSpace, root: IWAMessage, opts?: Pa
var tableref = M[parse_TSP_Reference(pb[2][0].data)];
var mtype = varint_to_i32(tableref[0].meta[1][0].data);
if(mtype != 6001) throw new Error(`6000 unexpected reference to ${mtype}`);
parse_TST_TableModelArchive(M, tableref[0], out);
parse_TST_TableModelArchive(M, tableref[0], out, opts);
return out;
}
@ -987,6 +1005,7 @@ function parse_TN_SheetArchive(M: MessageSpace, root: IWAMessage, opts?: Parsing
/** Parse .TN.DocumentArchive */
function parse_TN_DocumentArchive(M: MessageSpace, root: IWAMessage, opts?: ParsingOptions): WorkBook {
var out = book_new();
out.Workbook = { WBProps: { date1904: true } };
var pb = parse_shallow(root.data);
if(pb[2]?.[0]) throw new Error("Keynote presentations are not supported");
@ -1093,10 +1112,9 @@ function write_TST_TileRowInfo(data: CellObject[], lut: DataLUT, wide: boolean):
var celload: Uint8Array, _celload: Uint8Array;
switch(data[C].t) {
case "d":
// TODO: write the actual date code
if(data[C].v instanceof Date) {
celload = write_new_storage({t: "s", v: (data[C].v as Date).toISOString()}, lut);
/*if(!wide)*/ _celload = write_old_storage({t: "s", v: (data[C].v as Date).toISOString()}, lut);
celload = write_new_storage(data[C], lut);
/*if(!wide)*/ _celload = write_old_storage(data[C], lut);
break;
}
/* TODO: can esbuild preserve falls through comments ? */

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.19.3",
"version": "0.20.0",
"author": "sheetjs",
"description": "SheetJS Spreadsheet data parser and writer",
"keywords": [

129
test.js

@ -1554,7 +1554,7 @@ describe('write features', function() {
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
["Date", new Date()]
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
@ -1571,28 +1571,30 @@ function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str/*:string|Date*/)/*:Date*/ {
var d = new Date(str);
if(good_pd) 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1816,7 +1818,7 @@ describe('roundtrip features', function() {
];
var o = X.utils.sheet_to_json(X.utils.json_to_sheet(data, {cellDates:true}));
data.forEach(function(row, i) {
Object.keys(row).forEach(function(k) { assert.equal(row[k], o[i][k]); });
Object.keys(row).forEach(function(k) { assert.equal(row[k].valueOf(), o[i][k].valueOf()); });
});
});
@ -2189,7 +2191,15 @@ describe('CSV', function() {
assert.equal(cell.w, '2/19/14');
});
it('should honor dateNF override', function() {
var opts = ({type:"binary", dateNF:"YYYY-MM-DD"}/*:any*/);
var opts = ({type:"binary", dateNF:"YYYY-MM-DD", cellNF: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.ok(cell.w == '14-02-19' || cell.w == "2/19/14");
var opts = ({type:"binary", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19');
@ -2203,10 +2213,18 @@ describe('CSV', function() {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2236,7 +2254,8 @@ describe('CSV', function() {
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
@ -2244,14 +2263,46 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
@ -2402,19 +2453,31 @@ describe('dbf', function() {
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]/*:any*/);
var wbsfalse = ([]);
var wbstrue = ([]);
var bef = (function() {
wbs = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: true })]; });
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it(wbs[1][0], function() {
var ws = wbs[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
[
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "v", 6260], ["E2", "w", "19170219"],
["F2", "v", 6260], ["F2", "w", "19170219"],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) {
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[2]);
});
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
[
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"]
].forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {

158
test.mjs generated

@ -1550,6 +1550,22 @@ describe('write features', function() {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(wb2.Workbook.Names.length, wb3.Workbook.Names.length);
}); });
it('should handle non-string values for "s" cells', function() {[
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
].forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
@ -1559,28 +1575,30 @@ function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str/*:string|Date*/)/*:Date*/ {
var d = new Date(str);
if(good_pd) 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1804,7 +1822,7 @@ describe('roundtrip features', function() {
];
var o = X.utils.sheet_to_json(X.utils.json_to_sheet(data, {cellDates:true}));
data.forEach(function(row, i) {
Object.keys(row).forEach(function(k) { assert.equal(row[k], o[i][k]); });
Object.keys(row).forEach(function(k) { assert.equal(row[k].valueOf(), o[i][k].valueOf()); });
});
});
@ -1891,6 +1909,21 @@ describe('invalid files', function() {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
it('should fail if sheet name is not valid', function() {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2162,7 +2195,15 @@ describe('CSV', function() {
assert.equal(cell.w, '2/19/14');
});
it('should honor dateNF override', function() {
var opts = ({type:"binary", dateNF:"YYYY-MM-DD"}/*:any*/);
var opts = ({type:"binary", dateNF:"YYYY-MM-DD", cellNF: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.ok(cell.w == '14-02-19' || cell.w == "2/19/14");
var opts = ({type:"binary", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19');
@ -2176,10 +2217,18 @@ describe('CSV', function() {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2209,7 +2258,8 @@ describe('CSV', function() {
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
@ -2217,14 +2267,46 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
@ -2375,19 +2457,31 @@ describe('dbf', function() {
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]/*:any*/);
var wbsfalse = ([]);
var wbstrue = ([]);
var bef = (function() {
wbs = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: true })]; });
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it(wbs[1][0], function() {
var ws = wbs[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
[
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "v", 6260], ["E2", "w", "19170219"],
["F2", "v", 6260], ["F2", "w", "19170219"],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) {
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[2]);
});
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
[
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"],
].forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {

163
test.mts

@ -1006,7 +1006,7 @@ describe('parse features', function() {
describe('sheetRows', function() {
it('should use original range if not set', function() {
var opts = {type:TYPE};
var opts: X.ParsingOptions = {type:TYPE};
FSTPaths.map(function(p) { return X.read(fs.readFileSync(p), opts); }).forEach(function(wb) {
assert.equal(wb.Sheets["Text"]["!ref"],"A1:F49");
});
@ -1510,6 +1510,22 @@ describe('write features', function() {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(((wb2.Workbook as any).Names as any).length, ((wb3.Workbook as any).Names as any).length);
}); });
it('should handle non-string values for "s" cells', function() {([
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
] as Array<X.BookType>).forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end: number, start?: number): Array<number> {
@ -1519,28 +1535,30 @@ function seq(end: number, start?: number): Array<number> {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str: string|Date): Date {
var d = new Date(str);
if(good_pd) 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|Date, 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1851,6 +1869,21 @@ describe('invalid files', function() {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
it('should fail if sheet name is not valid', function() {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb: X.WorkBook = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2118,9 +2151,17 @@ describe('CSV', function() {
assert.equal(cell.w, '2/19/14');
});
it('should honor dateNF override', function() {
var opts: X.ParsingOptions = ({type:"binary", dateNF:"YYYY-MM-DD"});
var opts: X.ParsingOptions = ({type:"binary", dateNF:"YYYY-MM-DD", cellNF: true});
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.ok(cell.w == '14-02-19' || cell.w == "2/19/14");
opts = ({type:"binary", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19');
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
@ -2132,10 +2173,18 @@ describe('CSV', function() {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2163,9 +2212,10 @@ describe('CSV', function() {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
@ -2173,14 +2223,46 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
@ -2317,18 +2399,31 @@ describe('numbers', function() {
});
describe('dbf', function() {
var wbs: Array<[string, X.WorkBook]> = ([
var wbs: Array<[string, string]> = ([
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]).map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
]);
var wbsfalse: Array<[string, X.WorkBook]> = ([]);
var wbstrue: Array<[string, X.WorkBook]> = ([]);
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: true })]; });
it(wbs[1][0], function() {
var ws = wbs[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
([
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "v", 6260], ["E2", "w", "19170219"],
["F2", "v", 6260], ["F2", "w", "19170219"],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) {
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[2]);
});
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
([
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"],
] as Array<[string, string, any]>).forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});
});
it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) {

163
test.ts

@ -1006,7 +1006,7 @@ Deno.test('parse features', async function(t) {
await t.step('sheetRows', async function(t) {
await t.step('should use original range if not set', async function(t) {
var opts = {type:TYPE};
var opts: X.ParsingOptions = {type:TYPE};
FSTPaths.map(function(p) { return X.read(fs.readFileSync(p), opts); }).forEach(function(wb) {
assert.equal(wb.Sheets["Text"]["!ref"],"A1:F49");
});
@ -1510,6 +1510,22 @@ Deno.test('write features', async function(t) {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(((wb2.Workbook as any).Names as any).length, ((wb3.Workbook as any).Names as any).length);
}); });
await t.step('should handle non-string values for "s" cells', async function(t) {([
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
] as Array<X.BookType>).forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end: number, start?: number): Array<number> {
@ -1519,28 +1535,30 @@ function seq(end: number, start?: number): Array<number> {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str: string|Date): Date {
var d = new Date(str);
if(good_pd) 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|Date, 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1851,6 +1869,21 @@ Deno.test('invalid files', async function(t) {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
await t.step('should fail if sheet name is not valid', async function(t) {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb: X.WorkBook = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2118,9 +2151,17 @@ Deno.test('CSV', async function(t) {
assert.equal(cell.w, '2/19/14');
});
await t.step('should honor dateNF override', async function(t) {
var opts: X.ParsingOptions = ({type:"binary", dateNF:"YYYY-MM-DD"});
var opts: X.ParsingOptions = ({type:"binary", dateNF:"YYYY-MM-DD", cellNF: true});
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.assert(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.assert(cell.w == '14-02-19' || cell.w == "2/19/14");
opts = ({type:"binary", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.assert(cell.w == '2014-02-19' || cell.w == '1914-02-19');
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
@ -2132,10 +2173,18 @@ Deno.test('CSV', async function(t) {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
await t.step('should interpret values by default', async function(t) { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
await t.step('should generate strings if raw option is passed', async function(t) { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2163,9 +2212,10 @@ Deno.test('CSV', async function(t) {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
@ -2173,14 +2223,46 @@ Deno.test('CSV', async function(t) {
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
@ -2317,18 +2399,31 @@ Deno.test('numbers', async function(t) {
});
Deno.test('dbf', async function(t) {
var wbs: Array<[string, X.WorkBook]> = ([
var wbs: Array<[string, string]> = ([
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]).map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
]);
var wbsfalse: Array<[string, X.WorkBook]> = ([]);
var wbstrue: Array<[string, X.WorkBook]> = ([]);
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: true })]; });
await t.step(wbs[1][0], async function(t) {
var ws = wbs[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
([
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "v", 6260], ["E2", "w", "19170219"],
["F2", "v", 6260], ["F2", "w", "19170219"],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) {
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[2]);
});
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
([
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"],
] as Array<[string, string, any]>).forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});
});
await t.step("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", async function(t) {
([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) {

183
testbun.mjs generated

@ -684,6 +684,7 @@ describe('parse options', function() {
}); });
});
});
describe('input formats', function() {
if(false) it('should read binary strings', function() { artifax.forEach(function(p) {
X.read(fs.readFileSync(p, 'binary'), {type: 'binary'});
@ -691,6 +692,22 @@ describe('input formats', function() {
if(false) it('should read base64 strings', function() { artifax.forEach(function(p) {
X.read(fs.readFileSync(p, 'base64'), {type: 'base64'});
}); });
it('handles base64 within data URI scheme (gh-2762)', function() {
var data = 'TmFtZXMNCkhhZmV6DQpTYW0NCg==';
var wb0 = X.read(data, { type: 'base64' }); // raw base64 string
var wb1 = X.read('data:;base64,' + data, { type: 'base64' }); // data URI, no media type
var wb2 = X.read('data:text/csv;base64,' + data, { type: 'base64' }); // data URI, CSV type
var wb3 = X.read('data:application/vnd.ms-excel;base64,' + data, { type: 'base64' }); // data URI, Excel
[wb0, wb1, wb2, wb3].forEach(function(wb) {
var ws = wb.Sheets.Sheet1;
assert.equal(ws["!ref"], "A1:A3");
assert.equal(get_cell(ws, "A1").v, "Names");
assert.equal(get_cell(ws, "A2").v, "Hafez");
assert.equal(get_cell(ws, "A3").v, "Sam");
});
});
if(false) if(typeof Uint8Array !== 'undefined') it('should read array', function() { artifax.forEach(function(p) {
X.read(fs.readFileSync(p, 'binary').split("").map(function(x) { return x.charCodeAt(0); }), {type:'array'});
}); });
@ -1538,6 +1555,22 @@ describe('write features', function() {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(wb2.Workbook.Names.length, wb3.Workbook.Names.length);
}); });
it('should handle non-string values for "s" cells', function() {[
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
].forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
@ -1547,28 +1580,30 @@ function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str/*:string|Date*/)/*:Date*/ {
var d = new Date(str);
if(good_pd) 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1791,7 +1826,7 @@ describe('roundtrip features', function() {
];
var o = X.utils.sheet_to_json(X.utils.json_to_sheet(data, {cellDates:true}));
data.forEach(function(row, i) {
Object.keys(row).forEach(function(k) { assert.equal(row[k], o[i][k]); });
Object.keys(row).forEach(function(k) { assert.equal(row[k].valueOf(), o[i][k].valueOf()); });
});
});
@ -1878,6 +1913,21 @@ describe('invalid files', function() {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
it('should fail if sheet name is not valid', function() {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2149,7 +2199,15 @@ describe('CSV', function() {
assert.equal(cell.w, '2/19/14');
});
it('should honor dateNF override', function() {
var opts = ({type:"buffer", dateNF:"YYYY-MM-DD"}/*:any*/);
var opts = ({type:"buffer", dateNF:"YYYY-MM-DD", cellNF: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.ok(cell.w == '14-02-19' || cell.w == "2/19/14");
var opts = ({type:"buffer", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19');
@ -2163,10 +2221,18 @@ describe('CSV', function() {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"buffer", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"buffer", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"buffer"}), false); });
it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2190,6 +2256,48 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "j" + m[1] + "l");
});
});
it('should parse date-less meridien time values', function() {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
/* this particular case is not well-defined */
//var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal((24 + Math.round(B1.v * 24)) % 24, Math.round(3 + 24 + new Date(1899,11,31,0,0,0,0).getTimezoneOffset()/60) % 24);
//var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal((24 + Math.round(B3.v * 24)) % 24, Math.round(15 + 24 + new Date(1899,11,31,0,0,0,0).getTimezoneOffset()/60) % 24);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
describe('output', function(){
var data, ws;
@ -2338,19 +2446,36 @@ describe('dbf', function() {
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]/*:any*/);
var wbstrue = ([]);
var wbsfalse = ([]);
var bef = (function() {
wbs = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, UTC: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, UTC: true })]; });
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it(wbs[1][0], function() {
var ws = wbs[1][1].Sheets["Sheet1"];
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
[
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "w", "19170219", (new Date(1917,1,19).getTimezoneOffset() > 0 ? "19170218" : "19170219")],
["F2", "w", "19170219", (new Date(1917,1,19).getTimezoneOffset() > 0 ? "19170218" : "19170219")],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]], r[2]);
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[3] || r[2]);
});
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {
var book = X.utils.book_new();
var sheet = X.utils.aoa_to_sheet([["ASCII", "encoded"], ["Test", r[1]]]);
X.utils.book_append_sheet(book, sheet, "sheet1");
var data = X.write(book, {type: TYPE, bookType: "dbf", codepage:r[0]});
var wb = X.read(data, {type: TYPE});
assert.equal(wb.Sheets.Sheet1.B2.v, r[1]);
});
});
});
//import { JSDOM } from 'jsdom';

@ -1005,7 +1005,7 @@ Deno.test('parse features', async function(t) {
await t.step('sheetRows', async function(t) {
await t.step('should use original range if not set', async function(t) {
var opts = {type:TYPE};
var opts: X.ParsingOptions = {type:TYPE};
FSTPaths.map(function(p) { return X.read(fs.readFileSync(p), opts); }).forEach(function(wb) {
assert.equal(wb.Sheets["Text"]["!ref"],"A1:F49");
});
@ -1509,6 +1509,22 @@ Deno.test('write features', async function(t) {
assert.equal(Name.Ref, "Sheet1!$A$1:$C$3");
assert.equal(((wb2.Workbook as any).Names as any).length, ((wb3.Workbook as any).Names as any).length);
}); });
await t.step('should handle non-string values for "s" cells', async function(t) {([
"xlsx", "xlsb", "xls", "biff5", "biff2", "xlml", "numbers", "ods", "fods", "wk3", "csv", "txt", "sylk", "html", "dif", "dbf", "wk1", "rtf", "prn"
] as Array<X.BookType>).forEach(function(fmt) {
if(fmt == "numbers" && !can_write_numbers) return;
var ws = X.utils.aoa_to_sheet([
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
X.utils.book_append_sheet(wb, ws, "Sheet1");
X.write(wb, {type: TYPE, bookType: fmt, bookSST: false, numbers:XLSX_ZAHL});
X.write(wb, {type: TYPE, bookType: fmt, bookSST: true, numbers:XLSX_ZAHL});
}); });
});
function seq(end: number, start?: number): Array<number> {
@ -1518,28 +1534,30 @@ function seq(end: number, start?: number): Array<number> {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str: string|Date): Date {
var d = new Date(str);
if(good_pd) 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|Date, 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1850,6 +1868,21 @@ Deno.test('invalid files', async function(t) {
wb.SheetNames.push(wb.SheetNames[0]);
assert.throws(function() { X.write(wb, {type:'binary'}); });
});
await t.step('should fail if sheet name is not valid', async function(t) {
var names = [
"", // cannot be blank
"abcdefghijklmnopqrstuvwxyz1234567890", // cannot exceed 31 chars
"'sheetjs", "sheetjs'", // cannot start or end with apostrophe
"History", // cannot be History
"Sheet:JS", "Sheet]JS", "Sheet[JS", "Sheet*JS", // bad characters
"Sheet?JS", "Sheet\\JS", "Sheet\/JS"
];
names.forEach(function(n) { assert.throws(function() {
var wb: X.WorkBook = { SheetNames: [n], Sheets: {} };
wb.Sheets[n] = X.utils.aoa_to_sheet([["SheetJS"]]);
X.write(wb, {type:"binary", bookType:"xlsx"});
}); });
});
});
});
@ -2117,9 +2150,17 @@ Deno.test('CSV', async function(t) {
assert.equal(cell.w, '2/19/14');
});
await t.step('should honor dateNF override', async function(t) {
var opts: X.ParsingOptions = ({type:"binary", dateNF:"YYYY-MM-DD"});
var opts: X.ParsingOptions = ({type:"binary", dateNF:"YYYY-MM-DD", cellNF: true});
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.assert(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.assert(cell.w == '14-02-19' || cell.w == "2/19/14");
opts = ({type:"binary", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.assert(cell.w == '2014-02-19' || cell.w == '1914-02-19');
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
@ -2131,10 +2172,18 @@ Deno.test('CSV', async function(t) {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
await t.step('should interpret values by default', async function(t) { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
await t.step('should generate strings if raw option is passed', async function(t) { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2162,9 +2211,10 @@ Deno.test('CSV', async function(t) {
var aoa = [
["3a", "3 a", "3 a-1"],
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
@ -2172,14 +2222,46 @@ Deno.test('CSV', async function(t) {
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
@ -2316,18 +2398,31 @@ Deno.test('numbers', async function(t) {
});
Deno.test('dbf', async function(t) {
var wbs: Array<[string, X.WorkBook]> = ([
var wbs: Array<[string, string]> = ([
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]).map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
]);
var wbsfalse: Array<[string, X.WorkBook]> = ([]);
var wbstrue: Array<[string, X.WorkBook]> = ([]);
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: true })]; });
await t.step(wbs[1][0], async function(t) {
var ws = wbs[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
([
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "v", 6260], ["E2", "w", "19170219"],
["F2", "v", 6260], ["F2", "w", "19170219"],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
] as Array<[string, string, any]>).forEach(function(r) {
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[2]);
});
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
([
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"],
] as Array<[string, string, any]>).forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});
});
if(false) await t.step("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", async function(t) {
([ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ] as Array<[number,string]>).forEach(function(r) {

129
tests/core.js generated

@ -1554,7 +1554,7 @@ describe('write features', function() {
["String", "123"],
["Number", 123],
["Boolean", true],
["Date", new Date()],
["Date", new Date()]
], { cellDates: true });
ws["B2"].t = ws["B3"].t = ws["B4"].t = "s"
var wb = X.utils.book_new();
@ -1571,28 +1571,30 @@ function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {
return o;
}
var basedate = 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 = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
var epoch = /*#__PURE__*/v.getTime();
var res = (epoch - dnthresh) / (24 * 60 * 60 * 1000);
if(date1904) return res - 1462;
return res < 60 ? res - 1 : res;
}
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2017-02-19T19:06:09');
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
var good_pd = good_pd_date.getFullYear() == 2017;
function parseDate(str/*:string|Date*/)/*:Date*/ {
var d = new Date(str);
if(good_pd) 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"];
return new Date(Date.UTC(+n[0], +n[1] - 1, +n[2], +n[3], +n[4], +n[5]));
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));
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;
}
var fixdate = browser ? parseDate("2014-02-19T14:30:00.000Z") : new Date("2014-02-19T14:30Z");
@ -1816,7 +1818,7 @@ describe('roundtrip features', function() {
];
var o = X.utils.sheet_to_json(X.utils.json_to_sheet(data, {cellDates:true}));
data.forEach(function(row, i) {
Object.keys(row).forEach(function(k) { assert.equal(row[k], o[i][k]); });
Object.keys(row).forEach(function(k) { assert.equal(row[k].valueOf(), o[i][k].valueOf()); });
});
});
@ -2189,7 +2191,15 @@ describe('CSV', function() {
assert.equal(cell.w, '2/19/14');
});
it('should honor dateNF override', function() {
var opts = ({type:"binary", dateNF:"YYYY-MM-DD"}/*:any*/);
var opts = ({type:"binary", dateNF:"YYYY-MM-DD", cellNF: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19' || cell.w == "2/19/14");
assert.equal(cell.z, "YYYY-MM-DD");
opts.cellDates = true; opts.dateNF = "YY-MM-DD";
cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
assert.ok(cell.w == '14-02-19' || cell.w == "2/19/14");
var opts = ({type:"binary", dateNF:"YYYY-MM-DD", UTC: true}/*:any*/);
var cell = get_cell(X.read(b, opts).Sheets["Sheet1"], "C3");
/* NOTE: IE interprets 2-digit years as 19xx */
assert.ok(cell.w == '2014-02-19' || cell.w == '1914-02-19');
@ -2203,10 +2213,18 @@ describe('CSV', function() {
var cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'d/m/yy'};
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getMonth(), 2);
assert.equal(cell.w, "2/3/14");
opts = {type:"binary", cellDates:true, dateNF:'m/d/yy', UTC: true};
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 1);
assert.equal(cell.w, "2/3/14");
opts.dateNF = 'd/m/yy';
cell = get_cell(X.read(bb, opts).Sheets["Sheet1"], "C3");
assert.equal(cell.v.getUTCMonth(), 2);
assert.equal(cell.w, "2/3/14");
});
it('should interpret values by default', function() { plaintext_test(X.read(csv_bstr, {type:"binary"}), false); });
it('should generate strings if raw option is passed', function() { plaintext_test(X.read(csv_str, {type:"string", raw:true}), true); });
@ -2236,7 +2254,8 @@ describe('CSV', function() {
["3b", "3 b", "3 b-1"],
["3p", "3 P", "3 p-1"]
];
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
var ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
@ -2244,14 +2263,46 @@ describe('CSV', function() {
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getHours(), 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false, UTC: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: true}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "d"); assert.equal(B1.v.getUTCHours(), 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "d"); assert.equal(B3.v.getUTCHours(), 15);
ws = X.read(aoa.map(function(row) { return row.join(","); }).join("\n"), {type: "string", cellDates: false}).Sheets.Sheet1;
for(var R = 0; R < 3; ++R) {
assert.equal(get_cell(ws, "A" + (R+1)).v, aoa[R][0]);
assert.equal(get_cell(ws, "C" + (R+1)).v, aoa[R][2]);
}
assert.equal(get_cell(ws, "B2").v, "3 b");
var B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
var B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
B1 = get_cell(ws, "B1"); assert.equal(B1.t, "n"); assert.equal(B1.v * 24, 3);
B3 = get_cell(ws, "B3"); assert.equal(B3.t, "n"); assert.equal(B3.v * 24, 15);
});
});
@ -2402,19 +2453,31 @@ describe('dbf', function() {
['d11', dir + 'dbf/d11.dbf'],
['vfp3', dir + 'dbf/vfp3.dbf']
]/*:any*/);
var wbsfalse = ([]);
var wbstrue = ([]);
var bef = (function() {
wbs = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), {type:TYPE})]; });
wbsfalse = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: false })]; });
wbstrue = wbs.map(function(x) { return [x[0], X.read(fs.readFileSync(x[1]), { type:TYPE, cellDates: true })]; });
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
it(wbs[1][0], function() {
var ws = wbs[1][1].Sheets["Sheet1"];
var wsfalse = wbsfalse[1][1].Sheets["Sheet1"];
[
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45],
["C2", "v", 12.345], ["D2", "v", 1234.1], ["E2", "w", "19170219"],
/* [F2", "w", "19170219"], */ ["G2", "v", 1231.4], ["H2", "v", 123234],
["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) { assert.equal(get_cell(ws, r[0])[r[1]], r[2]); });
["A1", "v", "CHAR10"], ["A2", "v", "test1"], ["B2", "v", 123.45], ["C2", "v", 12.345], ["D2", "v", 1234.1],
["E2", "v", 6260], ["E2", "w", "19170219"],
["F2", "v", 6260], ["F2", "w", "19170219"],
["G2", "v", 1231.4], ["H2", "v", 123234], ["I2", "v", true], ["L2", "v", "SheetJS"]
].forEach(function(r) {
assert.equal(get_cell(wsfalse, r[0])[r[1]], r[2]);
});
var wstrue = wbstrue[1][1].Sheets["Sheet1"];
[
["E2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["E2", "w", "19170219"],
["F2", "v", Date.UTC(1917,1,19,0,0,0,0)], ["F2", "w", "19170219"]
].forEach(function(r) {
assert.equal(get_cell(wstrue, r[0])[r[1]].valueOf(), r[2].valueOf());
});
});
if(!browser || typeof cptable !== 'undefined') it("Ś╫êëτ⌡ś and Š╫ěéτ⌡š", function() {
[ [620, "Ś╫êëτ⌡ś"], [895, "Š╫ěéτ⌡š"] ].forEach(function(r) {

59
types/index.d.ts vendored

@ -139,8 +139,20 @@ export interface DateNFOption {
dateNF?: NumberFormat;
}
export interface UTCOption {
/**
* For plaintext formats, interpret ambiguous datetimes in UTC
* If explicitly set to `false`, dates will be parsed in local time.
*
* The `true` option is consistent with spreadsheet application export.
*
* @default true
*/
UTC?: boolean;
}
/** Options for read and readFile */
export interface ParsingOptions extends CommonOptions {
export interface ParsingOptions extends UTCOption, CommonOptions {
/** Input data encoding */
type?: 'base64' | 'binary' | 'buffer' | 'file' | 'array' | 'string';
@ -294,6 +306,12 @@ export interface WritingOptions extends CommonOptions {
* If this option is omitted, the first worksheet will be exported.
*/
sheet?: string | number;
/** Field Separator ("delimiter") for CSV / Text output */
FS?: string;
/** Record Separator ("row separator") for CSV / Text output */
RS?: string;
}
/** Workbook Object */
@ -803,9 +821,27 @@ export interface Sheet2JSONOpts extends DateNFOption {
/** if true, return raw numbers; if false, return formatted numbers */
rawNumbers?: boolean;
/**
* If true, return dates whose UTC interpretation is correct
* By default, return dates whose local interpretation is correct
*
* @default false
*/
UTC?: boolean;
}
export interface AOA2SheetOpts extends CommonOptions, DateNFOption {
export interface UTCDateOption {
/**
* If true, dates are interpreted using the UTC methods
* By default, dates are interpreted in the local timezone
*
* @default false
*/
UTC?: boolean;
}
export interface AOA2SheetOpts extends CommonOptions, UTCDateOption, DateNFOption {
/**
* Create cell objects for stub cells
* @default false
@ -815,7 +851,7 @@ export interface AOA2SheetOpts extends CommonOptions, DateNFOption {
export interface SheetAOAOpts extends AOA2SheetOpts, OriginOption {}
export interface JSON2SheetOpts extends CommonOptions, DateNFOption, OriginOption {
export interface JSON2SheetOpts extends CommonOptions, UTCDateOption, DateNFOption, OriginOption {
/** Use specified column order */
header?: string[];
@ -841,6 +877,14 @@ export interface Table2SheetOpts extends CommonOptions, DateNFOption, OriginOpti
* @default "Sheet1"
*/
sheet?: string;
/**
* If true, interpret date strings as if they are UTC.
* By default, date strings are interpreted in the local timezone.
*
* @default false
*/
UTC?: boolean;
}
export interface Table2BookOpts extends Table2SheetOpts {
@ -887,15 +931,6 @@ export interface XLSX$Utils {
/** Generates a list of the formulae (with value fallbacks) */
sheet_to_formulae(worksheet: WorkSheet): string[];
/** Generates DIF */
sheet_to_dif(worksheet: WorkSheet, options?: Sheet2HTMLOpts): string;
/** Generates SYLK (Symbolic Link) */
sheet_to_slk(worksheet: WorkSheet, options?: Sheet2HTMLOpts): string;
/** Generates ETH */
sheet_to_eth(worksheet: WorkSheet, options?: Sheet2HTMLOpts): string;
/* --- Cell Address Utilities --- */
/** Converts 0-indexed cell address to A1 form */

@ -21,9 +21,6 @@ interface Tester {
const jsonvalues: Tester[] = XLSX.utils.sheet_to_json<Tester>(firstworksheet);
const csv: string = XLSX.utils.sheet_to_csv(firstworksheet);
const txt: string = XLSX.utils.sheet_to_txt(firstworksheet);
const dif: string = XLSX.utils.sheet_to_dif(firstworksheet);
const slk: string = XLSX.utils.sheet_to_slk(firstworksheet);
const eth: string = XLSX.utils.sheet_to_eth(firstworksheet);
const formulae: string[] = XLSX.utils.sheet_to_formulae(firstworksheet);
const aoa: any[][] = XLSX.utils.sheet_to_json<any[]>(firstworksheet, {raw:true, header:1});

File diff suppressed because it is too large Load Diff

2209
xlsx.js generated

File diff suppressed because it is too large Load Diff

@ -1,10 +1,10 @@
/*! 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){
XLSX.version = '0.19.3';
XLSX.version = '0.20.0';
var current_codepage = 1200, current_ansi = 1252;
/*:: declare var cptable:any; */
/*global cptable:true, window */
@ -135,6 +135,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;
@ -494,15 +514,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 */
@ -560,7 +571,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);
}
@ -1248,7 +1259,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";
@ -1335,6 +1346,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*/ {
@ -1347,6 +1359,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;
@ -3274,7 +3287,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) {
@ -3284,6 +3297,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
@ -3342,22 +3359,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;
}
@ -3388,28 +3402,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*/ {
@ -3440,8 +3448,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("");
}
@ -3471,32 +3489,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[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(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);
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(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);
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;
}
@ -3509,6 +3544,13 @@ 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()));
}
function getdatastr(data)/*:?string*/ {
if(!data) return null;
if(data.content && data.type) return cc2str(data.content, true);
@ -4439,6 +4481,7 @@ 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); }
}
@ -5705,7 +5748,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;
@ -5728,7 +5774,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; }
@ -5931,6 +5982,8 @@ var SYLK = /*#__PURE__*/(function() {
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) {
@ -5983,8 +6036,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;
@ -5996,10 +6050,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;
@ -6035,6 +6088,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;
@ -6096,7 +6153,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':
@ -6104,12 +6161,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 '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) + " ";
@ -6134,6 +6198,7 @@ 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*/;
@ -6141,23 +6206,44 @@ var SYLK = /*#__PURE__*/(function() {
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 = [];
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));
}
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(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
for(var R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
var p = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
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;
}
@ -6197,7 +6283,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:
@ -6478,9 +6567,11 @@ 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; }
@ -6490,14 +6581,14 @@ var PRN = /*#__PURE__*/(function() {
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';
@ -7821,7 +7912,45 @@ function parse_drawing(data, rels/*:any*/) {
}
/* 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(",");
@ -7843,7 +7972,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";
@ -7981,6 +8110,7 @@ function write_comments_xml(data/*::, opts*/) {
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";
@ -8219,7 +8349,7 @@ function ods_to_csf_3D(r/*:string*/)/*:[string, string]*/ {
}
function csf_to_ods_3D(r/*:string*/)/*:string*/ {
return r.replace(/!/,".");
return r.replace(/!/,".").replace(/:/, ":.");
}
var strs = {}; // shared strings
@ -8305,7 +8435,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; }
@ -8320,14 +8450,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;
@ -8407,7 +8537,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);
@ -8427,6 +8557,10 @@ 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"]) {
@ -8443,6 +8577,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;
}
@ -8609,21 +8744,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;
@ -8666,7 +8807,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;
@ -8677,6 +8818,7 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
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;
@ -8744,7 +8886,14 @@ 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] !== '') {
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);
@ -8758,6 +8907,7 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
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]);
if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
@ -8813,8 +8963,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':
@ -8833,8 +8983,8 @@ 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;
@ -8859,6 +9009,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
var o/*:Array<string>*/ = [], r/*:Array<string>*/ = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols/*:Array<string>*/ = [], R=0, C=0, rows = ws['!rows'];
var dense = ws["!data"] != null;
var 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 = [];
@ -8867,7 +9018,7 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook
ref = cols[C] + rr;
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*/);
@ -9600,9 +9751,11 @@ 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(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;
@ -9636,7 +9789,8 @@ 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="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
}
@ -9742,6 +9896,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];
}
@ -10046,8 +10201,8 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
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 = {};
@ -10061,7 +10216,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(/_.*$/,""))) {
@ -10132,7 +10286,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
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;
@ -10168,19 +10322,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';
@ -10241,10 +10399,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]);}
creator = ""; creatoridx = 0;
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 = [];
}
creator = ""; creatoridx = 0;
break;
case 'creator': // 4.3.2.7 <dc:creator>
@ -10370,9 +10535,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;
@ -10394,6 +10557,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>
@ -10678,7 +10844,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;
@ -10705,7 +10873,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; }
@ -10761,10 +10929,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,
@ -10783,8 +10956,7 @@ 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');
@ -10815,7 +10987,7 @@ 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; }
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));
@ -10844,13 +11016,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) {
@ -10861,7 +11033,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');
}
@ -11006,7 +11188,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');
@ -11120,6 +11302,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);
@ -11158,6 +11347,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; }
}
@ -11460,6 +11650,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]];
@ -11479,6 +11672,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);
@ -11534,6 +11738,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));
@ -12047,7 +12258,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
}
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 === undefined || val.t === undefined) {
if(val == null || val.t === undefined) {
if(defval === undefined) continue;
if(hdr[C] != null) { row[hdr[C]] = defval; }
continue;
@ -12056,7 +12267,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)) v = utc_to_local(v); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -12266,6 +12482,7 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet
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]);
}

@ -1,10 +1,10 @@
/*! 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){
XLSX.version = '0.19.3';
XLSX.version = '0.20.0';
var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true, window */
var $cptable;
@ -134,6 +134,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;
@ -474,15 +494,6 @@ function SSF_parse_date_code(v,opts,b2) {
out.q = dow;
return out;
}
var SSFbasedate = new Date(1899, 11, 31, 0, 0, 0);
var SSFdnthresh = SSFbasedate.getTime();
var SSFbase1904 = new Date(1900, 2, 1, 0, 0, 0);
function datenum_local(v, date1904) {
var epoch = v.getTime();
if(date1904) epoch -= 1461*24*60*60*1000;
else if(v >= SSFbase1904) epoch += 24*60*60*1000;
return (epoch - (SSFdnthresh + (v.getTimezoneOffset() - 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 */
@ -540,7 +551,7 @@ function SSF_general(v, opts) {
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);
}
@ -1222,7 +1233,7 @@ function SSF_format(fmt,v,o) {
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";
@ -1305,6 +1316,7 @@ var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
function dateNF_regex(dateNF) {
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, dateNF, match) {
@ -1317,6 +1329,7 @@ function dateNF_fix(str, dateNF, match) {
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;
@ -3202,7 +3215,7 @@ if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
var url = URL.createObjectURL(blob);
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) {
@ -3211,6 +3224,10 @@ document.body.removeChild(a);
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
@ -3269,22 +3286,19 @@ function evert_arr(obj) {
return o;
}
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
var dnthresh = Date.UTC(1899, 11, 30, 0, 0, 0); // -2209161600000
var dnthresh1 = Date.UTC(1899, 11, 31, 0, 0, 0); // -2209075200000
var dnthresh2 = Date.UTC(1904, 0, 1, 0, 0, 0); // -2209075200000
function datenum(v, date1904) {
var epoch = v.getTime();
if(date1904) epoch -= 1462*24*60*60*1000;
var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - 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 = new Date();
var dnthresh = basedate.getTime() + (refdate.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
var refoffset = refdate.getTimezoneOffset();
function numdate(v) {
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;
}
@ -3315,27 +3329,22 @@ function parse_isodur(s) {
return sec;
}
var good_pd_date_1 = new Date('2017-02-19T19:06:09.000Z');
var good_pd_date = isNaN(good_pd_date_1.getFullYear()) ? new Date('2/19/17') : good_pd_date_1;
var good_pd = good_pd_date.getFullYear() == 2017;
/* parses a date as a local date */
function parseDate(str, fixdate) {
var d = new Date(str);
if(good_pd) {
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, date1904) {
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, debomit) {
@ -3366,8 +3375,18 @@ function cc2str(arr, debomit) {
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("");
}
@ -3397,32 +3416,49 @@ function fuzzynum(s) {
/* 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) {
/* 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[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(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);
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(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);
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) {
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) {
// 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;
}
@ -3435,6 +3471,13 @@ var split_regex = (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()));
}
function getdatastr(data) {
if(!data) return null;
if(data.content && data.type) return cc2str(data.content, true);
@ -4354,6 +4397,7 @@ function sheet_add_aoa(_ws, data, opts) {
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); }
}
@ -5619,7 +5663,10 @@ var fields = [], field = ({});
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;
@ -5642,7 +5689,12 @@ var fields = [], field = ({});
// 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; }
@ -5845,6 +5897,8 @@ var SYLK = (function() {
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, opts) {
switch(opts.type) {
@ -5897,8 +5951,9 @@ var SYLK = (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;
@ -5910,10 +5965,9 @@ var SYLK = (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;
@ -5949,6 +6003,10 @@ var SYLK = (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;
@ -6010,7 +6068,7 @@ var SYLK = (function() {
return outwb;
}
function write_ws_cell_sylk(cell, ws, R, C) {
function write_ws_cell_sylk(cell, ws, R, C, opts, date1904) {
var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
switch(cell.t) {
case 'n':
@ -6018,12 +6076,19 @@ var SYLK = (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 '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, R, C) {
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) + " ";
@ -6048,6 +6113,7 @@ var SYLK = (function() {
}
function sheet_to_sylk(ws, opts, wb) {
if(!opts) opts = {}; opts._formats = ["General"];
/* TODO: codepage */
var preamble = ["ID;PSheetJS;N;E"], o = [];
var r = safe_decode_range(ws['!ref']), cell;
@ -6055,23 +6121,44 @@ var SYLK = (function() {
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 = [];
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));
}
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(" "));
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
for(var R = r.s.r; R <= r.e.r; ++R) {
if(dense && !ws["!data"][R]) continue;
var p = [];
for(var C = r.s.c; C <= r.e.c; ++C) {
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
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;
}
@ -6111,7 +6198,10 @@ var DIF = (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:
@ -6392,9 +6482,11 @@ var PRN = (function() {
var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0, startcc=str.charCodeAt(0);
var _re = 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 = ({});
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; }
@ -6404,14 +6496,14 @@ var PRN = (function() {
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';
@ -7735,7 +7827,45 @@ function parse_drawing(data, rels) {
}
/* L.5.5.2 SpreadsheetML Comments + VML Schema */
function write_vml(rId, comments) {
var shapevmlregex = /<(?:\w+:)?shape(?:[^\w][^>]*)?>([\s\S]*?)<\/(?:\w+:)?shape>/g;
function parse_vml(data, 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, idx) {
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, 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(",");
@ -7757,7 +7887,7 @@ function write_vml(rId, comments) {
return o.join("");
}
function write_vml_comment(x, _shapeid) {
function write_vml_comment(x, _shapeid, ws) {
var c = decode_cell(x[0]);
var fillopts = {'color2':"#BEFF82", 'type':"gradient"};
if(fillopts.type == "gradient") fillopts.angle = "-180";
@ -7895,6 +8025,7 @@ function write_comments_xml(data) {
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";
@ -8133,7 +8264,7 @@ function ods_to_csf_3D(r) {
}
function csf_to_ods_3D(r) {
return r.replace(/!/,".");
return r.replace(/!/,".").replace(/:/, ":.");
}
var strs = {}; // shared strings
@ -8219,7 +8350,7 @@ function get_cell_style(styles, cell, opts) {
return len;
}
function safe_format(p, fmtid, fillid, opts, themes, styles) {
function safe_format(p, fmtid, fillid, opts, themes, styles, date1904) {
try {
if(opts.cellNF) p.z = table_fmt[fmtid];
} catch(e) { if(opts.WTF) throw e; }
@ -8234,14 +8365,14 @@ function safe_format(p, fmtid, fillid, opts, themes, styles) {
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;
@ -8321,7 +8452,7 @@ function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
}
/* 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);
@ -8341,6 +8472,10 @@ function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
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"]) {
@ -8357,6 +8492,7 @@ function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
}
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;
}
@ -8523,21 +8659,27 @@ function write_ws_xml_sheetviews(ws, opts, idx, wb) {
return writextag("sheetViews", writextag("sheetView", null, sview), {});
}
function write_ws_xml_cell(cell, ref, ws, opts) {
function write_ws_xml_cell(cell, ref, ws, opts, idx, wb, date1904) {
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;
@ -8580,7 +8722,7 @@ var parse_ws_xml_data = (function() {
var refregex = /ref=["']([^"']*)["']/;
var match_v = matchtag("v"), match_f = matchtag("f");
return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles, wb) {
var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
var tag, tagr = 0, tagc = 0;
var sstr, ftag;
@ -8591,6 +8733,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
var dense = s["!data"] != null;
var rows = [], 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;
@ -8658,7 +8801,14 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
if(opts.cellFormula) {
if((cref=d.match(match_f))!= null && cref[1] !== '') {
if((cref=d.match(match_f))!= null ) {
if(cref[1] == "") {
if(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);
@ -8672,6 +8822,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
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]);
if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
@ -8727,8 +8878,8 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
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':
@ -8747,8 +8898,8 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
}
}
}
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;
@ -8773,6 +8924,7 @@ function write_ws_xml_data(ws, opts, idx, wb) {
var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
var dense = ws["!data"] != null;
var params = ({r:rr}), row, 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 = [];
@ -8781,7 +8933,7 @@ function write_ws_xml_data(ws, opts, idx, wb) {
ref = cols[C] + rr;
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});
@ -9512,9 +9664,11 @@ function html_to_sheet(str, _opts) {
else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
else if(!isNaN(fuzzydate(m).getDate())) {
o = ({t:'d', v:parseDate(m)});
if(opts.UTC === false) o.v = utc_to_local(o.v);
if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
o.z = opts.dateNF || table_fmt[14];
}
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;
@ -9548,7 +9702,8 @@ function make_html_row(ws, r, R, o) {
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="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
}
@ -9654,6 +9809,7 @@ function sheet_add_dom(ws, table, _opts) {
else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
else if(!isNaN(fuzzydate(v).getDate())) {
o = ({t:'d', v:parseDate(v)});
if(opts.UTC) o.v = local_to_utc(o.v);
if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
o.z = opts.dateNF || table_fmt[14];
}
@ -9958,8 +10114,8 @@ function parse_content_xml(d, _opts, _nfm) {
var ws = ({}); if(opts.dense) ws["!data"] = [];
var Rn, q;
var ctag = ({value:""});
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 = {};
@ -9973,7 +10129,6 @@ function parse_content_xml(d, _opts, _nfm) {
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(/_.*$/,""))) {
@ -10044,7 +10199,7 @@ function parse_content_xml(d, _opts, _nfm) {
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;
@ -10080,19 +10235,23 @@ function parse_content_xml(d, _opts, _nfm) {
/* 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';
@ -10153,10 +10312,17 @@ function parse_content_xml(d, _opts, _nfm) {
if(textR.length) comment.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]);}
creator = ""; creatoridx = 0;
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 = [];
}
creator = ""; creatoridx = 0;
break;
case 'creator': // 4.3.2.7 <dc:creator>
@ -10282,9 +10448,7 @@ function parse_content_xml(d, _opts, _nfm) {
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;
@ -10306,6 +10470,9 @@ function parse_content_xml(d, _opts, _nfm) {
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>
@ -10590,7 +10757,9 @@ function write_number_format_ods(nf, nfidx) {
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;
@ -10617,7 +10786,7 @@ function write_number_format_ods(nf, nfidx) {
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; }
@ -10673,10 +10842,15 @@ function write_number_format_ods(nf, nfidx) {
}
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,
@ -10695,8 +10869,7 @@ var write_content_ods = /* @__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, i, opts, nfs) {
var write_ws = function(ws, wb, i, opts, nfs, date1904) {
/* Section 9 Tables */
var o = [];
o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="ta1">\n');
@ -10727,7 +10900,7 @@ var write_content_ods = /* @__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; }
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));
@ -10756,13 +10929,13 @@ var write_content_ods = /* @__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) {
@ -10773,7 +10946,17 @@ var write_content_ods = /* @__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');
}
@ -10918,7 +11101,7 @@ var write_content_ods = /* @__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');
@ -11032,6 +11215,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, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
try {
sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
@ -11070,6 +11260,7 @@ function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, st
}
});
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; }
}
@ -11369,6 +11560,9 @@ f = "docProps/app.xml";
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]];
@ -11388,6 +11582,17 @@ f = "docProps/app.xml";
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);
@ -11443,6 +11648,13 @@ f = "docProps/app.xml";
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));
@ -11948,7 +12160,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
}
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 === undefined || val.t === undefined) {
if(val == null || val.t === undefined) {
if(defval === undefined) continue;
if(hdr[C] != null) { row[hdr[C]] = defval; }
continue;
@ -11957,7 +12169,12 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
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)) v = utc_to_local(v); break;
default: throw new Error('unrecognized type ' + val.t);
}
if(hdr[C] != null) {
@ -12167,6 +12384,7 @@ function sheet_add_json(_ws, js, opts) {
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]);
}

823
xlsx.mjs generated

File diff suppressed because it is too large Load Diff