forked from sheetjs/sheetjs
version bump 0.20.0
This commit is contained in:
parent
36c5b7c0f5
commit
955543147d
1
.gitignore
vendored
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
|
||||
|
15
Makefile
15
Makefile
@ -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[3]) {
|
||||
if(M[4]) return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000);
|
||||
else return new Date(1899,11,30,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000);
|
||||
}
|
||||
else if(M[5]) return new Date(1899,11,30, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0);
|
||||
else return new Date(1899,11,30,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0);
|
||||
if(!M[2]) return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), 0, 0, 0));
|
||||
if(M[3]) {
|
||||
if(M[4]) return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[4], parseFloat(M[3])*1000));
|
||||
else return new Date(Date.UTC(1899,11,31,(M[7] == "p" ? 12 : 0), +M[1], +M[2], parseFloat(M[3])*1000));
|
||||
}
|
||||
else if(M[5]) return new Date(Date.UTC(1899,11,31, (+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0));
|
||||
else return new Date(Date.UTC(1899,11,31,(+M[1]%12) + (M[7] == "p" ? 12 : 0), +M[2], 0, 0));
|
||||
}
|
||||
function fuzzytime2(M) /*:Date*/ {
|
||||
if(!M[2]) return new Date(Date.UTC(1899,11,31,+M[1], 0, 0, 0));
|
||||
if(M[3]) {
|
||||
if(M[4]) return new Date(Date.UTC(1899,11,31,+M[1], +M[2], +M[4], parseFloat(M[3])*1000));
|
||||
else return new Date(Date.UTC(1899,11,31,0, +M[1], +M[2], parseFloat(M[3])*1000));
|
||||
}
|
||||
else if(M[5]) return new Date(Date.UTC(1899,11,31, +M[1], +M[2], +M[5], M[6] ? parseFloat(M[6]) * 1000 : 0));
|
||||
else return new Date(Date.UTC(1899,11,31,+M[1], +M[2], 0, 0));
|
||||
}
|
||||
var lower_months = ['january', 'february', 'march', 'april', 'may', 'june', 'july', 'august', 'september', 'october', 'november', 'december'];
|
||||
function fuzzydate(s/*:string*/)/*:Date*/ {
|
||||
// See issue 2863 -- this is technically not supported in Excel but is otherwise useful
|
||||
if(FDISO.test(s)) return s.indexOf("Z") == -1 ? local_to_utc(new Date(s)) : new Date(s);
|
||||
var lower = s.toLowerCase();
|
||||
var lnos = lower.replace(/\s+/g, " ").trim();
|
||||
var M = lnos.match(FDRE1);
|
||||
if(M) return fuzzytime1(M);
|
||||
|
||||
var o = new Date(s), n = new Date(NaN);
|
||||
M = lnos.match(FDRE2);
|
||||
if(M) return fuzzytime2(M);
|
||||
M = lnos.match(pdre3);
|
||||
if(M) return new Date(Date.UTC(+M[1], +M[2]-1, +M[3], +M[4], +M[5], ((M[6] && parseInt(M[6].slice(1), 10))|| 0), ((M[7] && parseInt(M[7].slice(1), 10))||0)));
|
||||
var o = new Date(utc_append_works && s.indexOf("UTC") == -1 ? s + " UTC": s), n = new Date(NaN);
|
||||
var y = o.getYear(), m = o.getMonth(), d = o.getDate();
|
||||
if(isNaN(d)) return n;
|
||||
if(lower.match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) {
|
||||
lower = lower.replace(/[^a-z]/g,"").replace(/([^a-z]|^)[ap]m?([^a-z]|$)/,"");
|
||||
if(lower.length > 3 && lower_months.indexOf(lower) == -1) return n;
|
||||
} else if(lower.replace(/[ap]m?/, "").match(/[a-z]/)) return n;
|
||||
if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\]/)) return n;
|
||||
if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\\ ]/)) return n;
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -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';
|
||||
|
137
bits/41_lotus.js
137
bits/41_lotus.js
@ -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(/!/,".");
|
||||