forked from sheetjs/sheetjs
Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
5ef49e2b96 | |||
947a5178bd | |||
87a695747e | |||
a0bed2a97d | |||
0941ff97a3 | |||
e4a66516e4 | |||
d4d4ff3da2 | |||
29d46c07a8 | |||
9199c2600c | |||
cd5fafda32 | |||
|
c8e6d5c20f | ||
ad0fb7766b | |||
4cc980975b | |||
432ac1fda7 | |||
53283217e9 | |||
248108b667 | |||
|
766fc4f4d2 | ||
485a4f30f1 | |||
68cce77d23 | |||
c0b9e229a0 | |||
955543147d | |||
36c5b7c0f5 | |||
6e260c9185 |
6
.github/ISSUE_TEMPLATE/config.yml
vendored
6
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,6 +0,0 @@
|
||||
blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Issues and Questions
|
||||
url: https://git.sheetjs.com/sheetjs/sheetjs/issues
|
||||
about: Please report issues to the official code repository.
|
||||
|
4
.gitignore
vendored
4
.gitignore
vendored
@ -23,14 +23,16 @@ tmp
|
||||
*.[xX][mM][lL]
|
||||
*.[xX][lL][mM][lL]
|
||||
*.[uU][oO][sS]
|
||||
*.[wW][kKqQbB][S1234567890]
|
||||
*.[wW][kKqQbB][sS1234567890]
|
||||
*.[qQ][pP][wW]
|
||||
*.[fF][mM][3tT]
|
||||
*.[bB][iI][fF][fF][23458]
|
||||
*.[rR][tT][fF]
|
||||
*.[eE][tT]
|
||||
*.[eE][tT][hH]
|
||||
*.[nN][uU][mM][bB][eE][rR][sS]
|
||||
*.[mM][oO][dD]
|
||||
*.[dD][tT][aA]
|
||||
*.123
|
||||
*.htm
|
||||
*.html
|
||||
|
@ -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]
|
||||
|
22
CHANGELOG.md
22
CHANGELOG.md
@ -4,6 +4,28 @@ 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.2
|
||||
|
||||
* Reworked parsing methods to avoid slow regexes (CVE-2024-22363)
|
||||
* HTML properly encode data-v attribute
|
||||
* SYLK read and write error cells
|
||||
|
||||
## v0.20.1
|
||||
|
||||
* `init` use packaged test files to work around GitHub breaking changes
|
||||
* SSF date code rounding to 15 decimal digits (h/t @davidtamaki)
|
||||
* `sheet_to_json` force UTC interpretation for formatted strings (h/t @Blanay)
|
||||
* QPW extract result of string formula
|
||||
* XLSX parse non-compliant merge cell expressions
|
||||
* NUMBERS correctly handle rows omitted from official exports
|
||||
* DBF parse empty logical field (h/t @Roman91)
|
||||
* `dense` option added to types
|
||||
* package.json add mini and core scripts to export map (h/t @stof)
|
||||
|
||||
## v0.20.0
|
||||
|
||||
* Use UTC interpretation of Date objects for date cells (potentially breaking)
|
||||
* API functions support UTC and local time value interpretations
|
||||
* Export `NaN` values to `#NUM!` and infinite values to `#DIV/0!`
|
||||
|
||||
## v0.19.3
|
||||
|
@ -4,17 +4,17 @@ The SheetJS Libraries should be free and clear to use in your projects. In
|
||||
order to maintain that, every contributor must be vigilant.
|
||||
|
||||
There have been many projects in the past that have been very lax regarding
|
||||
licensing, and we are of the opinion that those are ticking timebombs and that
|
||||
no commercial product should depend on them.
|
||||
licensing. We are of the opinion that those are ticking timebombs and that no
|
||||
commercial product should depend on them.
|
||||
|
||||
|
||||
# Required Reading
|
||||
|
||||
These are pretty short reads and emphasize the importance of proper licensing:
|
||||
|
||||
- https://github.com/kennethreitz/tablib/issues/114 (discussion of other tools)
|
||||
- https://github.com/jazzband/tablib/issues/114 (discussion of other tools)
|
||||
|
||||
- http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html
|
||||
- https://web.archive.org/web/20120615223756/http://www.codinghorror.com/blog/2007/04/pick-a-license-any-license.html
|
||||
|
||||
|
||||
# Raising Issues
|
||||
@ -30,10 +30,9 @@ inbox is self-hosted.
|
||||
|
||||
# Opening Pull Requests
|
||||
|
||||
Before opening a pull request, [squash all commits into
|
||||
one](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History). If the pull
|
||||
request addresses documentation or demos, add `[ci skip]` in the body or title
|
||||
of your commit message to skip Travis checks.
|
||||
[Squash commits](https://git-scm.com/book/en/v2/Git-Tools-Rewriting-History)
|
||||
before opening a pull request, If the pull request addresses documentation or
|
||||
demos, add `[ci skip]` in the body or title of the commit message to skip tests.
|
||||
|
||||
# Pre-Contribution Checklist
|
||||
|
||||
@ -57,8 +56,8 @@ issue. If it is a particularly high-priority issue, please drop an email to
|
||||
Keep these in mind as you work:
|
||||
|
||||
- Your contributions are your original work. Take note of any resources you
|
||||
consult in the process (and be extra careful not to use unlicensed code on
|
||||
the internet.
|
||||
consult in the process. Be extra careful not to use unlicensed code on the
|
||||
Internet or code generated by a large language model or other AI tool.
|
||||
|
||||
- You are working on your own time. Unless they explicitly grant permission,
|
||||
your employer may be the ultimate owner of your IP
|
||||
|
22
Makefile
22
Makefile
@ -67,10 +67,9 @@ clean-data:
|
||||
|
||||
.PHONY: init
|
||||
init: ## Initial setup for development
|
||||
git submodule init
|
||||
git submodule update
|
||||
#git submodule foreach git pull origin master
|
||||
git submodule foreach make all
|
||||
rm -rf test_files
|
||||
if [ ! -e test_files.zip ]; then curl -LO https://test-files.sheetjs.com/test_files.zip; fi
|
||||
unzip test_files.zip
|
||||
mkdir -p tmp
|
||||
|
||||
DISTHDR=misc/suppress_export.js
|
||||
@ -107,13 +106,13 @@ dist-deps: ## Copy dependencies for distribution
|
||||
.PHONY: aux
|
||||
aux: $(AUXTARGETS)
|
||||
|
||||
BYTEFILEC=dist/xlsx.{full,core,mini}.min.js
|
||||
BYTEFILER=dist/xlsx.extendscript.js xlsx.mjs
|
||||
BYTEFILEC=dist/xlsx.{full,core,mini}.min.js xlsx.mjs
|
||||
BYTEFILER=dist/xlsx.extendscript.js
|
||||
.PHONY: bytes
|
||||
bytes: ## Display minified and gzipped file sizes
|
||||
@for i in $(BYTEFILEC); do npx printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done
|
||||
@for i in $(BYTEFILER); do npx printj "%-30s %7d" $$i $$(wc -c < $$i); done
|
||||
@npx printj "%-30s %10d" "treeshake" "$$(npx 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 +140,10 @@ test mocha: test.js ## Run test suite
|
||||
#* To run tests for one format, make test_<fmt>
|
||||
#* To run the core test suite, make test_misc
|
||||
|
||||
.PHONY: testdot
|
||||
testdot: test.js ## Run test suite using dot reporter
|
||||
mocha -R dot -t 30000
|
||||
|
||||
.PHONY: test-esm
|
||||
test-esm: test.mjs ## Run Node ESM test suite
|
||||
npx -y mocha@9 -R spec -t 30000 $<
|
||||
@ -165,6 +168,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_%:
|
||||
|
19
README.md
19
README.md
@ -9,29 +9,30 @@ Edit complex templates with ease; let out your inner Picasso with styling; make
|
||||
custom sheets with images/graphs/PivotTables; evaluate formula expressions and
|
||||
port calculations to web apps; automate common spreadsheet tasks, and much more!
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/sheetjs?pixel)](https://git.sheetjs.com/SheetJS/sheetjs)
|
||||
|
||||
[![Build Status](https://saucelabs.com/browser-matrix/sheetjs.svg)](https://saucelabs.com/u/sheetjs)
|
||||
|
||||
## Documentation
|
||||
|
||||
- [API and Usage Documentation](https://docs.sheetjs.com)
|
||||
|
||||
- [Downloadable Scripts and Modules](https://cdn.sheetjs.com)
|
||||
|
||||
## Related Projects
|
||||
## Constellation
|
||||
|
||||
- <https://oss.sheetjs.com/notes/>: File Format Notes
|
||||
|
||||
- [`ssf`](packages/ssf): Format data using ECMA-376 spreadsheet format codes
|
||||
|
||||
- [`xlsx-cli`](packages/xlsx-cli/): NodeJS command-line tool for processing files
|
||||
- [`xlsx-cli`](packages/xlsx-cli): NodeJS command-line tool for processing files
|
||||
|
||||
- [`test_files`](https://github.com/SheetJS/test_files): Sample spreadsheets
|
||||
- [`cfb`](https://git.sheetjs.com/SheetJS/js-cfb): Container (OLE/ZIP) file
|
||||
processing library
|
||||
|
||||
- [`cfb`](https://git.sheetjs.com/SheetJS/js-cfb): Container (OLE/ZIP) format library
|
||||
- [`codepage`](https://git.sheetjs.com/SheetJS/js-codepage): Legacy text
|
||||
encodings for XLS and other legacy spreadsheet formats
|
||||
|
||||
- [`codepage`](https://git.sheetjs.com/SheetJS/js-codepage): Legacy text encodings
|
||||
- [`dta`](packages/dta): Stata DTA file processor
|
||||
|
||||
- [`test_files`](https://github.com/sheetjs/test_files): Test files and various
|
||||
plaintext baselines.
|
||||
|
||||
## License
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
|
||||
/* vim: set ts=2: */
|
||||
/*exported XLSX */
|
||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
|
||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Set:false, Float32Array:false */
|
||||
var XLSX = {};
|
||||
function make_xlsx_lib(XLSX){
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.19.3';
|
||||
XLSX.version = '0.20.2';
|
||||
|
@ -6,26 +6,26 @@ var $cptable;
|
||||
var VALID_ANSI = [ 874, 932, 936, 949, 950, 1250, 1251, 1252, 1253, 1254, 1255, 1256, 1257, 1258, 10000 ];
|
||||
/* ECMA-376 Part I 18.4.1 charset to codepage mapping */
|
||||
var CS2CP = ({
|
||||
/*::[*/0/*::]*/: 1252, /* ANSI */
|
||||
/*::[*/1/*::]*/: 65001, /* DEFAULT */
|
||||
/*::[*/2/*::]*/: 65001, /* SYMBOL */
|
||||
/*::[*/77/*::]*/: 10000, /* MAC */
|
||||
/*::[*/128/*::]*/: 932, /* SHIFTJIS */
|
||||
/*::[*/129/*::]*/: 949, /* HANGUL */
|
||||
/*::[*/130/*::]*/: 1361, /* JOHAB */
|
||||
/*::[*/134/*::]*/: 936, /* GB2312 */
|
||||
/*::[*/136/*::]*/: 950, /* CHINESEBIG5 */
|
||||
/*::[*/161/*::]*/: 1253, /* GREEK */
|
||||
/*::[*/162/*::]*/: 1254, /* TURKISH */
|
||||
/*::[*/163/*::]*/: 1258, /* VIETNAMESE */
|
||||
/*::[*/177/*::]*/: 1255, /* HEBREW */
|
||||
/*::[*/178/*::]*/: 1256, /* ARABIC */
|
||||
/*::[*/186/*::]*/: 1257, /* BALTIC */
|
||||
/*::[*/204/*::]*/: 1251, /* RUSSIAN */
|
||||
/*::[*/222/*::]*/: 874, /* THAI */
|
||||
/*::[*/238/*::]*/: 1250, /* EASTEUROPE */
|
||||
/*::[*/255/*::]*/: 1252, /* OEM */
|
||||
/*::[*/69/*::]*/: 6969 /* MISC */
|
||||
0: 1252, /* ANSI */
|
||||
1: 65001, /* DEFAULT */
|
||||
2: 65001, /* SYMBOL */
|
||||
77: 10000, /* MAC */
|
||||
128: 932, /* SHIFTJIS */
|
||||
129: 949, /* HANGUL */
|
||||
130: 1361, /* JOHAB */
|
||||
134: 936, /* GB2312 */
|
||||
136: 950, /* CHINESEBIG5 */
|
||||
161: 1253, /* GREEK */
|
||||
162: 1254, /* TURKISH */
|
||||
163: 1258, /* VIETNAMESE */
|
||||
177: 1255, /* HEBREW */
|
||||
178: 1256, /* ARABIC */
|
||||
186: 1257, /* BALTIC */
|
||||
204: 1251, /* RUSSIAN */
|
||||
222: 874, /* THAI */
|
||||
238: 1250, /* EASTEUROPE */
|
||||
255: 1252, /* OEM */
|
||||
69: 6969 /* MISC */
|
||||
}/*:any*/);
|
||||
|
||||
var set_ansi = function(cp/*:number*/) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; };
|
||||
|
@ -45,10 +45,35 @@ 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;
|
||||
input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, "");
|
||||
if (input.slice(0, 5) == "data:") {
|
||||
var i = input.slice(0, 1024).indexOf(";base64,");
|
||||
if (i > -1)
|
||||
input = input.slice(i + 8);
|
||||
}
|
||||
input = input.replace(/[^\w\+\/\=]/g, "");
|
||||
for (var i = 0; i < input.length; ) {
|
||||
e1 = Base64_map.indexOf(input.charAt(i++));
|
||||
e2 = Base64_map.indexOf(input.charAt(i++));
|
||||
|
@ -173,8 +173,20 @@ function SSF_frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number
|
||||
var q = Math.floor(sgn * P/Q);
|
||||
return [q, sgn*P - q*Q, Q];
|
||||
}
|
||||
function SSF_normalize_xl_unsafe(v/*:number*/)/*:number*/ {
|
||||
var s = v.toPrecision(16);
|
||||
if(s.indexOf("e") > -1) {
|
||||
var m = s.slice(0, s.indexOf("e"));
|
||||
m = m.indexOf(".") > -1 ? m.slice(0, (m.slice(0,2) == "0." ? 17 : 16)) : (m.slice(0,15) + fill("0", m.length - 15));
|
||||
return m + s.slice(s.indexOf("e"));
|
||||
}
|
||||
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
|
||||
return Number(n);
|
||||
}
|
||||
|
||||
function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
|
||||
if(v > 2958465 || v < 0) return null;
|
||||
v = SSF_normalize_xl_unsafe(v);
|
||||
var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
|
||||
var dout=[];
|
||||
var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
|
||||
@ -203,15 +215,6 @@ function SSF_parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
|
||||
out.q = dow;
|
||||
return out;
|
||||
}
|
||||
var SSFbasedate = /*#__PURE__*/new Date(1899, 11, 31, 0, 0, 0);
|
||||
var SSFdnthresh = /*#__PURE__*/SSFbasedate.getTime();
|
||||
var SSFbase1904 = /*#__PURE__*/new Date(1900, 2, 1, 0, 0, 0);
|
||||
function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
|
||||
var epoch = /*#__PURE__*/v.getTime();
|
||||
if(date1904) epoch -= 1461*24*60*60*1000;
|
||||
else if(v >= SSFbase1904) epoch += 24*60*60*1000;
|
||||
return (epoch - (SSFdnthresh + (/*#__PURE__*/v.getTimezoneOffset() - /*#__PURE__*/SSFbasedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
/* ECMA-376 18.8.30 numFmt*/
|
||||
/* Note: `toPrecision` uses standard form when prec > E and E >= -6 */
|
||||
/* exponent >= -9 and <= 9 */
|
||||
@ -240,6 +243,7 @@ function SSF_large_exp(v/*:number*/)/*:string*/ {
|
||||
}
|
||||
|
||||
function SSF_general_num(v/*:number*/)/*:string*/ {
|
||||
if(!isFinite(v)) return isNaN(v) ? "#VALUE!" : "#DIV/0!";
|
||||
var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
|
||||
|
||||
if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
|
||||
@ -269,7 +273,7 @@ function SSF_general(v/*:any*/, opts/*:any*/) {
|
||||
case 'undefined': return "";
|
||||
case 'object':
|
||||
if(v == null) return "";
|
||||
if(v instanceof Date) return SSF_format(14, datenum_local(v, opts && opts.date1904), opts);
|
||||
if(v instanceof Date) return SSF_format(14, datenum(v, opts && opts.date1904), opts);
|
||||
}
|
||||
throw new Error("unsupported value in General format: " + v);
|
||||
}
|
||||
@ -337,7 +341,7 @@ function SSF_write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*
|
||||
switch(fmt) {
|
||||
case '[h]': case '[hh]': out = val.D*24+val.H; break;
|
||||
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
|
||||
default: throw 'bad abstime format: ' + fmt;
|
||||
} outl = fmt.length === 3 ? 1 : 2; break;
|
||||
case 101: /* 'e' era */
|
||||
@ -405,7 +409,7 @@ function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:s
|
||||
return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
|
||||
}
|
||||
var dec1 = /^#*0*\.([0#]+)/;
|
||||
var closeparen = /\).*[0#]/;
|
||||
var closeparen = /\)[^)]*[0#]/;
|
||||
var phone = /\(###\) ###\\?-####/;
|
||||
function hashq(str/*:string*/)/*:string*/ {
|
||||
var o = "", cc;
|
||||
@ -785,10 +789,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
switch(out[i].t) {
|
||||
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
|
||||
case 's':
|
||||
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
|
||||
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
|
||||
if(bt < 3) bt = 3;
|
||||
/* falls through */
|
||||
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
|
||||
case 'd': case 'y': case 'e': lst=out[i].t; break;
|
||||
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
|
||||
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
|
||||
case 'X': /*if(out[i].v === "B2");*/
|
||||
break;
|
||||
@ -798,19 +803,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* time rounding depends on presence of minute / second / usec fields */
|
||||
var _dt;
|
||||
switch(bt) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
/*::if(!dt) break;*/
|
||||
case 2:
|
||||
case 3:
|
||||
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
|
||||
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
|
||||
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
|
||||
break;
|
||||
case 2:
|
||||
/*::if(!dt) break;*/
|
||||
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
case 4:
|
||||
switch(ss0) {
|
||||
case 1: dt.u = Math.round(dt.u * 10)/10; break;
|
||||
case 2: dt.u = Math.round(dt.u * 100)/100; break;
|
||||
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
|
||||
}
|
||||
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
|
||||
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
|
||||
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
|
||||
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = SSF_parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
|
||||
break;
|
||||
}
|
||||
|
||||
@ -926,6 +941,8 @@ function choose_fmt(f/*:string*/, v/*:any*/) {
|
||||
if(l<4 && lat>-1) --l;
|
||||
if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
|
||||
if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
|
||||
/* NOTE: most spreadsheet software do not support NaN or infinities */
|
||||
if(typeof v === "number" && !isFinite(v)) v = 0;
|
||||
switch(fmt.length) {
|
||||
case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
|
||||
case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
|
||||
@ -957,11 +974,13 @@ 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";
|
||||
else if(v === "" || v == null) return "";
|
||||
else if(isNaN(v) && f[1].indexOf("0") > -1) return "#VALUE!";
|
||||
else if(!isFinite(v) && f[1].indexOf("0") > -1) return "#DIV/0!";
|
||||
return eval_fmt(f[1], v, o, f[0]);
|
||||
}
|
||||
function SSF_load(fmt/*:string*/, idx/*:?number*/)/*:number*/ {
|
||||
|
@ -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;
|
||||
|
@ -769,9 +769,9 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|strin
|
||||
file = cfb.FileIndex[i];
|
||||
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
|
||||
var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
|
||||
if(_nm.length > 32) {
|
||||
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,32));
|
||||
_nm = _nm.slice(0, 32);
|
||||
if(_nm.length > 31) {
|
||||
console.error("Name " + _nm + " will be truncated to " + _nm.slice(0,31));
|
||||
_nm = _nm.slice(0, 31);
|
||||
}
|
||||
flen = 2*(_nm.length+1);
|
||||
o.write_shift(64, _nm, "utf16le");
|
||||
@ -1683,7 +1683,7 @@ function parse_mime(cfb/*:CFBContainer*/, data/*:Array<string>*/, root/*:string*
|
||||
for(;di < 10; ++di) {
|
||||
var line = data[di];
|
||||
if(!line || line.match(/^\s*$/)) break;
|
||||
var m = line.match(/^(.*?):\s*([^\s].*)$/);
|
||||
var m = line.match(/^([^:]*?):\s*([^\s].*)$/);
|
||||
if(m) switch(m[1].toLowerCase()) {
|
||||
case "content-location": fname = m[2].trim(); break;
|
||||
case "content-type": ctype = m[2].trim(); break;
|
||||
|
@ -35,7 +35,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
||||
/*:: declare var chrome: any; */
|
||||
if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
|
||||
if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
|
||||
return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
|
||||
return chrome.downloads.download({ url: url, filename: fname, saveAs: true });
|
||||
}
|
||||
var a = document.createElement("a");
|
||||
if(a.download != null) {
|
||||
@ -45,6 +45,10 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
||||
if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
|
||||
return url;
|
||||
}
|
||||
} else if(typeof URL !== 'undefined' && !URL.createObjectURL && typeof chrome === 'object') {
|
||||
/* manifest v3 extensions -- no URL.createObjectURL */
|
||||
var b64 = "data:application/octet-stream;base64," + Base64_encode_arr(new Uint8Array(blobify(data)));
|
||||
return chrome.downloads.download({ url: b64, filename: fname, saveAs: true });
|
||||
}
|
||||
}
|
||||
// $FlowIgnore
|
||||
@ -53,7 +57,7 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
|
||||
var out = File(fname); out.open("w"); out.encoding = "binary";
|
||||
if(Array.isArray(payload)) payload = a2s(payload);
|
||||
out.write(payload); out.close(); return payload;
|
||||
} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
|
||||
} catch(e) { if(!e.message || e.message.indexOf("onstruct") == -1) throw e; }
|
||||
throw new Error("cannot save file " + fname);
|
||||
}
|
||||
|
||||
@ -67,6 +71,6 @@ function read_binary(path/*:string*/) {
|
||||
var infile = File(path); infile.open("r"); infile.encoding = "binary";
|
||||
var data = infile.read(); infile.close();
|
||||
return data;
|
||||
} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
|
||||
} catch(e) { if(!e.message || e.message.indexOf("onstruct") == -1) throw e; }
|
||||
throw new Error("Cannot access file " + path);
|
||||
}
|
||||
|
@ -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] + "0000").slice(1,4), 10))||0)));
|
||||
var d = new Date(str);
|
||||
return d;
|
||||
}
|
||||
|
||||
function cc2str(arr/*:Array<number>*/, debomit)/*:string*/ {
|
||||
@ -129,8 +120,18 @@ function cc2str(arr/*:Array<number>*/, debomit)/*:string*/ {
|
||||
return new TextDecoder("latin1").decode(arr).replace(/[€‚ƒ„…†‡ˆ‰Š‹ŒŽ‘’“”•–—˜™š›œžŸ]/g, function(c) { return rev[c] || c; });
|
||||
} catch(e) {}
|
||||
|
||||
var o = [];
|
||||
for(var i = 0; i != arr.length; ++i) o.push(String.fromCharCode(arr[i]));
|
||||
var o = [], i = 0;
|
||||
// this cascade is for the browsers and runtimes of antiquity (and for modern runtimes that lack TextEncoder)
|
||||
try {
|
||||
for(i = 0; i < arr.length - 65536; i+=65536) o.push(String.fromCharCode.apply(0, arr.slice(i, i + 65536)));
|
||||
o.push(String.fromCharCode.apply(0, arr.slice(i)));
|
||||
} catch(e) { try {
|
||||
for(; i < arr.length - 16384; i+=16384) o.push(String.fromCharCode.apply(0, arr.slice(i, i + 16384)));
|
||||
o.push(String.fromCharCode.apply(0, arr.slice(i)));
|
||||
} catch(e) {
|
||||
for(; i != arr.length; ++i) o.push(String.fromCharCode(arr[i]));
|
||||
}
|
||||
}
|
||||
return o.join("");
|
||||
}
|
||||
|
||||
@ -153,39 +154,56 @@ function fuzzynum(s/*:string*/)/*:number*/ {
|
||||
var wt = 1;
|
||||
var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
|
||||
if(!isNaN(v = Number(ss))) return v / wt;
|
||||
ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
|
||||
ss = ss.replace(/[(]([^()]*)[)]/,function($$, $1) { wt = -wt; return $1;});
|
||||
if(!isNaN(v = Number(ss))) return v / wt;
|
||||
return v;
|
||||
}
|
||||
|
||||
/* 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] + "0000").slice(1,4), 10))||0)));
|
||||
var o = new Date(utc_append_works && s.indexOf("UTC") == -1 ? s + " UTC": s), n = new Date(NaN);
|
||||
var y = o.getYear(), m = o.getMonth(), d = o.getDate();
|
||||
if(isNaN(d)) return n;
|
||||
if(lower.match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) {
|
||||
lower = lower.replace(/[^a-z]/g,"").replace(/([^a-z]|^)[ap]m?([^a-z]|$)/,"");
|
||||
if(lower.length > 3 && lower_months.indexOf(lower) == -1) return n;
|
||||
} else if(lower.replace(/[ap]m?/, "").match(/[a-z]/)) return n;
|
||||
if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\]/)) return n;
|
||||
if(y < 0 || y > 8099 || s.match(/[^-0-9:,\/\\\ ]/)) return n;
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -198,3 +216,165 @@ 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 remove_doctype(str) {
|
||||
var preamble = str.slice(0, 1024);
|
||||
var si = preamble.indexOf("<!DOCTYPE");
|
||||
if(si == -1) return str;
|
||||
var m = str.match(/<[\w]/);
|
||||
if(!m) return str;
|
||||
return str.slice(0, si) + str.slice(m.index);
|
||||
}
|
||||
|
||||
/* str.match(/<!--[\s\S]*?-->/g) --> str_match_ng(str, "<!--", "-->") */
|
||||
function str_match_ng(str, s, e) {
|
||||
var out = [];
|
||||
|
||||
var si = str.indexOf(s);
|
||||
while(si > -1) {
|
||||
var ei = str.indexOf(e, si + s.length);
|
||||
if(ei == -1) break;
|
||||
|
||||
out.push(str.slice(si, ei + e.length));
|
||||
si = str.indexOf(s, ei + e.length);
|
||||
}
|
||||
|
||||
return out.length > 0 ? out : null;
|
||||
}
|
||||
|
||||
/* str.replace(/<!--[\s\S]*?-->/g, "") --> str_remove_ng(str, "<!--", "-->") */
|
||||
function str_remove_ng(str, s, e) {
|
||||
var out = [], last = 0;
|
||||
|
||||
var si = str.indexOf(s);
|
||||
if(si == -1) return str;
|
||||
while(si > -1) {
|
||||
out.push(str.slice(last, si));
|
||||
var ei = str.indexOf(e, si + s.length);
|
||||
if(ei == -1) break;
|
||||
|
||||
if((si = str.indexOf(s, (last = ei + e.length))) == -1) out.push(str.slice(last));
|
||||
}
|
||||
|
||||
return out.join("");
|
||||
}
|
||||
|
||||
/* str.match(/<tag\b[^>]*?>([\s\S]*?)</tag>/) --> str_match_xml(str, "tag") */
|
||||
var xml_boundary = { " ": 1, "\t": 1, "\r": 1, "\n": 1, ">": 1 };
|
||||
function str_match_xml(str, tag) {
|
||||
var si = str.indexOf('<' + tag), w = tag.length + 1, L = str.length;
|
||||
while(si >= 0 && si <= L - w && !xml_boundary[str.charAt(si + w)]) si = str.indexOf('<' + tag, si+1);
|
||||
if(si === -1) return null;
|
||||
var sf = str.indexOf(">", si + tag.length);
|
||||
if(sf === -1) return null;
|
||||
var et = "</" + tag + ">";
|
||||
var ei = str.indexOf(et, sf);
|
||||
if(ei == -1) return null;
|
||||
return [str.slice(si, ei + et.length), str.slice(sf + 1, ei)];
|
||||
}
|
||||
|
||||
/* str.match(/<(?:\w+:)?tag\b[^<>]*?>([\s\S]*?)<\/(?:\w+:)?tag>/) --> str_match_xml(str, "tag") */
|
||||
var str_match_xml_ns = /*#__PURE__*/(function() {
|
||||
var str_match_xml_ns_cache = {};
|
||||
return function str_match_xml_ns(str, tag) {
|
||||
var res = str_match_xml_ns_cache[tag];
|
||||
if(!res) str_match_xml_ns_cache[tag] = res = [
|
||||
new RegExp('<(?:\\w+:)?'+tag+'\\b[^<>]*>', "g"),
|
||||
new RegExp('</(?:\\w+:)?'+tag+'>', "g")
|
||||
];
|
||||
res[0].lastIndex = res[1].lastIndex = 0;
|
||||
var m = res[0].exec(str);
|
||||
if(!m) return null;
|
||||
var si = m.index;
|
||||
var sf = res[0].lastIndex;
|
||||
res[1].lastIndex = res[0].lastIndex;
|
||||
m = res[1].exec(str);
|
||||
if(!m) return null;
|
||||
var ei = m.index;
|
||||
var ef = res[1].lastIndex;
|
||||
return [str.slice(si, ef), str.slice(sf, ei)];
|
||||
};
|
||||
})();
|
||||
|
||||
/* str.match(/<(?:\w+:)?tag\b[^<>]*?>([\s\S]*?)<\/(?:\w+:)?tag>/g) --> str_match_xml_ns_g(str, "tag") */
|
||||
var str_match_xml_ns_g = /*#__PURE__*/(function() {
|
||||
var str_match_xml_ns_cache = {};
|
||||
return function str_match_xml_ns(str, tag) {
|
||||
var out = [];
|
||||
var res = str_match_xml_ns_cache[tag];
|
||||
if(!res) str_match_xml_ns_cache[tag] = res = [
|
||||
new RegExp('<(?:\\w+:)?'+tag+'\\b[^<>]*>', "g"),
|
||||
new RegExp('</(?:\\w+:)?'+tag+'>', "g")
|
||||
];
|
||||
res[0].lastIndex = res[1].lastIndex = 0;
|
||||
var m;
|
||||
while((m = res[0].exec(str))) {
|
||||
var si = m.index;
|
||||
res[1].lastIndex = res[0].lastIndex;
|
||||
m = res[1].exec(str);
|
||||
if(!m) return null;
|
||||
var ef = res[1].lastIndex;
|
||||
out.push(str.slice(si, ef));
|
||||
res[0].lastIndex = res[1].lastIndex;
|
||||
}
|
||||
return out.length == 0 ? null : out;
|
||||
};
|
||||
})();
|
||||
var str_remove_xml_ns_g = /*#__PURE__*/(function() {
|
||||
var str_remove_xml_ns_cache = {};
|
||||
return function str_remove_xml_ns_g(str, tag) {
|
||||
var out = [];
|
||||
var res = str_remove_xml_ns_cache[tag];
|
||||
if(!res) str_remove_xml_ns_cache[tag] = res = [
|
||||
new RegExp('<(?:\\w+:)?'+tag+'\\b[^<>]*>', "g"),
|
||||
new RegExp('</(?:\\w+:)?'+tag+'>', "g")
|
||||
];
|
||||
res[0].lastIndex = res[1].lastIndex = 0;
|
||||
var m;
|
||||
var si = 0, ef = 0;
|
||||
while((m = res[0].exec(str))) {
|
||||
si = m.index;
|
||||
out.push(str.slice(ef, si));
|
||||
ef = si;
|
||||
res[1].lastIndex = res[0].lastIndex;
|
||||
m = res[1].exec(str);
|
||||
if(!m) return null;
|
||||
ef = res[1].lastIndex;
|
||||
res[0].lastIndex = res[1].lastIndex;
|
||||
}
|
||||
out.push(str.slice(ef));
|
||||
return out.length == 0 ? "" : out.join("");
|
||||
};
|
||||
})();
|
||||
|
||||
/* str.match(/<(?:\w+:)?tag\b[^>]*?>([\s\S]*?)<\/(?:\w+:)?tag>/gi) --> str_match_xml_ns_ig(str, "tag") */
|
||||
var str_match_xml_ig = /*#__PURE__*/(function() {
|
||||
var str_match_xml_ns_cache = {};
|
||||
return function str_match_xml_ns(str, tag) {
|
||||
var out = [];
|
||||
var res = str_match_xml_ns_cache[tag];
|
||||
if(!res) str_match_xml_ns_cache[tag] = res = [
|
||||
new RegExp('<'+tag+'\\b[^<>]*>', "ig"),
|
||||
new RegExp('</'+tag+'>', "ig")
|
||||
];
|
||||
res[0].lastIndex = res[1].lastIndex = 0;
|
||||
var m;
|
||||
while((m = res[0].exec(str))) {
|
||||
var si = m.index;
|
||||
res[1].lastIndex = res[0].lastIndex;
|
||||
m = res[1].exec(str);
|
||||
if(!m) return null;
|
||||
var ef = res[1].lastIndex;
|
||||
out.push(str.slice(si, ef));
|
||||
res[0].lastIndex = res[1].lastIndex;
|
||||
}
|
||||
return out.length == 0 ? null : out;
|
||||
};
|
||||
})();
|
||||
|
@ -1,6 +1,6 @@
|
||||
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
|
||||
var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
|
||||
var tagregex1=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s*[\/\?]?>/mg, tagregex2 = /<[^>]*>/g;
|
||||
var attregexg=/\s([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
|
||||
var tagregex1=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?<>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'"<>\s=]+))*\s*[\/\?]?>/mg, tagregex2 = /<[^<>]*>/g;
|
||||
var tagregex = /*#__PURE__*/XML_HEADER.match(tagregex1) ? tagregex1 : tagregex2;
|
||||
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
|
||||
function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?boolean*/)/*:any*/ {
|
||||
@ -11,7 +11,7 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/, skip_LC/*:?boolean*
|
||||
if(eq === tag.length) return z;
|
||||
var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
|
||||
if(m) for(i = 0; i != m.length; ++i) {
|
||||
cc = m[i];
|
||||
cc = m[i].slice(1);
|
||||
for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
|
||||
q = cc.slice(0,c).trim();
|
||||
while(cc.charCodeAt(c+1) == 32) ++c;
|
||||
@ -161,16 +161,6 @@ var utf8write/*:StringConv*/ = has_buf ? function(data) { return Buffer_from(dat
|
||||
return out.join("");
|
||||
};
|
||||
|
||||
// matches <foo>...</foo> extracts content
|
||||
var matchtag = /*#__PURE__*/(function() {
|
||||
var mtcache/*:{[k:string]:RegExp}*/ = ({}/*:any*/);
|
||||
return function matchtag(f/*:string*/,g/*:?string*/)/*:RegExp*/ {
|
||||
var t = f+"|"+(g||"");
|
||||
if(mtcache[t]) return mtcache[t];
|
||||
return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||"")/*:any*/)));
|
||||
};
|
||||
})();
|
||||
|
||||
var htmldecode/*:{(s:string):string}*/ = /*#__PURE__*/(function() {
|
||||
var entities/*:Array<[RegExp, string]>*/ = [
|
||||
['nbsp', ' '], ['middot', '·'],
|
||||
@ -181,30 +171,25 @@ var htmldecode/*:{(s:string):string}*/ = /*#__PURE__*/(function() {
|
||||
// Remove new lines and spaces from start of content
|
||||
.replace(/^[\t\n\r ]+/, "")
|
||||
// Remove new lines and spaces from end of content
|
||||
.replace(/[\t\n\r ]+$/,"")
|
||||
.replace(/(^|[^\t\n\r ])[\t\n\r ]+$/,"$1")
|
||||
// Added line which removes any white space characters after and before html tags
|
||||
.replace(/>\s+/g,">").replace(/\s+</g,"<")
|
||||
.replace(/>\s+/g,">").replace(/\b\s+</g,"<")
|
||||
// Replace remaining new lines and spaces with space
|
||||
.replace(/[\t\n\r ]+/g, " ")
|
||||
// Replace <br> tags with new lines
|
||||
.replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
|
||||
// Strip HTML elements
|
||||
.replace(/<[^>]*>/g,"");
|
||||
.replace(/<[^<>]*>/g,"");
|
||||
for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
|
||||
return o;
|
||||
};
|
||||
})();
|
||||
|
||||
var vtregex = /*#__PURE__*/(function(){ var vt_cache = {};
|
||||
return function vt_regex(bt) {
|
||||
if(vt_cache[bt] !== undefined) return vt_cache[bt];
|
||||
return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
|
||||
};})();
|
||||
var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
|
||||
var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^<"'>]*)>([\s\S]*)</;
|
||||
function parseVector(data/*:string*/, opts)/*:Array<{v:string,t:string}>*/ {
|
||||
var h = parsexmltag(data);
|
||||
|
||||
var matches/*:Array<string>*/ = data.match(vtregex(h.baseType))||[];
|
||||
var matches/*:Array<string>*/ = str_match_xml_ns_g(data, h.baseType)||[];
|
||||
var res/*:Array<any>*/ = [];
|
||||
if(matches.length != h.size) {
|
||||
if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
|
||||
@ -245,9 +230,8 @@ function xlml_normalize(d)/*:string*/ {
|
||||
if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d)));
|
||||
throw new Error("Bad input format: expected Buffer or string");
|
||||
}
|
||||
/* UOS uses CJK in tags */
|
||||
var xlmlregex = /<(\/?)([^\s?><!\/:]*:|)([^\s?<>:\/]+)(?:[\s?:\/](?:[^>=]|="[^"]*?")*)?>/mg;
|
||||
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
|
||||
/* UOS uses CJK in tags, ODS uses invalid XML */
|
||||
var xlmlregex = /<([\/]?)([^\s?><!\/:"]*:|)([^\s?<>:\/"]+)(?:\s+[^<>=?"'\s]+="[^"]*?")*\s*[\/]?>/mg;
|
||||
|
||||
var XMLNS = ({
|
||||
CORE_PROPS: 'http://schemas.openxmlformats.org/package/2006/metadata/core-properties',
|
||||
|
@ -108,6 +108,13 @@ function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
|
||||
return { SheetNames: [n], Sheets: sheets };
|
||||
}
|
||||
|
||||
function sheet_new(opts) {
|
||||
var out = {};
|
||||
var o = opts || {};
|
||||
if(o.dense) out["!data"] = [];
|
||||
return out;
|
||||
}
|
||||
|
||||
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
|
||||
var o = opts || {};
|
||||
var dense = _ws ? (_ws["!data"] != null) : o.dense;
|
||||
@ -121,18 +128,19 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
|
||||
var _origin/*:CellAddress*/ = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
|
||||
_R = _origin.r; _C = _origin.c;
|
||||
}
|
||||
if(!ws["!ref"]) ws["!ref"] = "A1:A1";
|
||||
}
|
||||
var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/);
|
||||
if(ws['!ref']) {
|
||||
if(ws["!ref"]){
|
||||
var _range = safe_decode_range(ws['!ref']);
|
||||
range.s.c = _range.s.c;
|
||||
range.s.r = _range.s.r;
|
||||
range.e.c = Math.max(range.e.c, _range.e.c);
|
||||
range.e.r = Math.max(range.e.r, _range.e.r);
|
||||
if(_R == -1) range.e.r = _R = _range.e.r + 1;
|
||||
if(_R == -1) range.e.r = _R = (ws["!ref"] ? _range.e.r + 1 : 0);
|
||||
} else {
|
||||
range.s.c = range.e.c = range.s.r = range.e.r = 0;
|
||||
}
|
||||
var row = [];
|
||||
var row = [], seen = false;
|
||||
for(var R = 0; R != data.length; ++R) {
|
||||
if(!data[R]) continue;
|
||||
if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
|
||||
@ -149,6 +157,7 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
|
||||
if(range.s.c > __C) range.s.c = __C;
|
||||
if(range.e.r < __R) range.e.r = __R;
|
||||
if(range.e.c < __C) range.e.c = __C;
|
||||
seen = true;
|
||||
if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
|
||||
else {
|
||||
if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
|
||||
@ -158,10 +167,15 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
|
||||
else if(!o.sheetStubs) continue;
|
||||
else cell.t = 'z';
|
||||
}
|
||||
else if(typeof cell.v === 'number') cell.t = 'n';
|
||||
else if(typeof cell.v === 'number') {
|
||||
if(isFinite(cell.v)) cell.t = 'n';
|
||||
else if(isNaN(cell.v)) { cell.t = 'e'; cell.v = 0x0F; /* #VALUE! */ }
|
||||
else { cell.t = 'e'; cell.v = 0x07; /*# DIV/0 */ }
|
||||
}
|
||||
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); }
|
||||
}
|
||||
@ -177,8 +191,7 @@ function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksh
|
||||
}
|
||||
}
|
||||
}
|
||||
if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
|
||||
if(seen && range.s.c < 10400000) ws['!ref'] = encode_range(range);
|
||||
return ws;
|
||||
}
|
||||
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
|
||||
|
||||
|
@ -44,118 +44,118 @@ var VT_CUSTOM = [VT_STRING, VT_USTR];
|
||||
|
||||
/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
|
||||
var DocSummaryPIDDSI = {
|
||||
/*::[*/0x01/*::]*/: { n: 'CodePage', t: VT_I2 },
|
||||
/*::[*/0x02/*::]*/: { n: 'Category', t: VT_STRING },
|
||||
/*::[*/0x03/*::]*/: { n: 'PresentationFormat', t: VT_STRING },
|
||||
/*::[*/0x04/*::]*/: { n: 'ByteCount', t: VT_I4 },
|
||||
/*::[*/0x05/*::]*/: { n: 'LineCount', t: VT_I4 },
|
||||
/*::[*/0x06/*::]*/: { n: 'ParagraphCount', t: VT_I4 },
|
||||
/*::[*/0x07/*::]*/: { n: 'SlideCount', t: VT_I4 },
|
||||
/*::[*/0x08/*::]*/: { n: 'NoteCount', t: VT_I4 },
|
||||
/*::[*/0x09/*::]*/: { n: 'HiddenCount', t: VT_I4 },
|
||||
/*::[*/0x0a/*::]*/: { n: 'MultimediaClipCount', t: VT_I4 },
|
||||
/*::[*/0x0b/*::]*/: { n: 'ScaleCrop', t: VT_BOOL },
|
||||
/*::[*/0x0c/*::]*/: { n: 'HeadingPairs', t: VT_VECTOR_VARIANT /* VT_VECTOR | VT_VARIANT */ },
|
||||
/*::[*/0x0d/*::]*/: { n: 'TitlesOfParts', t: VT_VECTOR_LPSTR /* VT_VECTOR | VT_LPSTR */ },
|
||||
/*::[*/0x0e/*::]*/: { n: 'Manager', t: VT_STRING },
|
||||
/*::[*/0x0f/*::]*/: { n: 'Company', t: VT_STRING },
|
||||
/*::[*/0x10/*::]*/: { n: 'LinksUpToDate', t: VT_BOOL },
|
||||
/*::[*/0x11/*::]*/: { n: 'CharacterCount', t: VT_I4 },
|
||||
/*::[*/0x13/*::]*/: { n: 'SharedDoc', t: VT_BOOL },
|
||||
/*::[*/0x16/*::]*/: { n: 'HyperlinksChanged', t: VT_BOOL },
|
||||
/*::[*/0x17/*::]*/: { n: 'AppVersion', t: VT_I4, p: 'version' },
|
||||
/*::[*/0x18/*::]*/: { n: 'DigSig', t: VT_BLOB },
|
||||
/*::[*/0x1A/*::]*/: { n: 'ContentType', t: VT_STRING },
|
||||
/*::[*/0x1B/*::]*/: { n: 'ContentStatus', t: VT_STRING },
|
||||
/*::[*/0x1C/*::]*/: { n: 'Language', t: VT_STRING },
|
||||
/*::[*/0x1D/*::]*/: { n: 'Version', t: VT_STRING },
|
||||
/*::[*/0xFF/*::]*/: {},
|
||||
0x01: { n: 'CodePage', t: VT_I2 },
|
||||
0x02: { n: 'Category', t: VT_STRING },
|
||||
0x03: { n: 'PresentationFormat', t: VT_STRING },
|
||||
0x04: { n: 'ByteCount', t: VT_I4 },
|
||||
0x05: { n: 'LineCount', t: VT_I4 },
|
||||
0x06: { n: 'ParagraphCount', t: VT_I4 },
|
||||
0x07: { n: 'SlideCount', t: VT_I4 },
|
||||
0x08: { n: 'NoteCount', t: VT_I4 },
|
||||
0x09: { n: 'HiddenCount', t: VT_I4 },
|
||||
0x0a: { n: 'MultimediaClipCount', t: VT_I4 },
|
||||
0x0b: { n: 'ScaleCrop', t: VT_BOOL },
|
||||
0x0c: { n: 'HeadingPairs', t: VT_VECTOR_VARIANT /* VT_VECTOR | VT_VARIANT */ },
|
||||
0x0d: { n: 'TitlesOfParts', t: VT_VECTOR_LPSTR /* VT_VECTOR | VT_LPSTR */ },
|
||||
0x0e: { n: 'Manager', t: VT_STRING },
|
||||
0x0f: { n: 'Company', t: VT_STRING },
|
||||
0x10: { n: 'LinksUpToDate', t: VT_BOOL },
|
||||
0x11: { n: 'CharacterCount', t: VT_I4 },
|
||||
0x13: { n: 'SharedDoc', t: VT_BOOL },
|
||||
0x16: { n: 'HyperlinksChanged', t: VT_BOOL },
|
||||
0x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
|
||||
0x18: { n: 'DigSig', t: VT_BLOB },
|
||||
0x1A: { n: 'ContentType', t: VT_STRING },
|
||||
0x1B: { n: 'ContentStatus', t: VT_STRING },
|
||||
0x1C: { n: 'Language', t: VT_STRING },
|
||||
0x1D: { n: 'Version', t: VT_STRING },
|
||||
0xFF: {},
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
/*::[*/0x80000000/*::]*/: { n: 'Locale', t: VT_UI4 },
|
||||
/*::[*/0x80000003/*::]*/: { n: 'Behavior', t: VT_UI4 },
|
||||
/*::[*/0x72627262/*::]*/: {}
|
||||
0x80000000: { n: 'Locale', t: VT_UI4 },
|
||||
0x80000003: { n: 'Behavior', t: VT_UI4 },
|
||||
0x72627262: {}
|
||||
};
|
||||
|
||||
/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
|
||||
var SummaryPIDSI = {
|
||||
/*::[*/0x01/*::]*/: { n: 'CodePage', t: VT_I2 },
|
||||
/*::[*/0x02/*::]*/: { n: 'Title', t: VT_STRING },
|
||||
/*::[*/0x03/*::]*/: { n: 'Subject', t: VT_STRING },
|
||||
/*::[*/0x04/*::]*/: { n: 'Author', t: VT_STRING },
|
||||
/*::[*/0x05/*::]*/: { n: 'Keywords', t: VT_STRING },
|
||||
/*::[*/0x06/*::]*/: { n: 'Comments', t: VT_STRING },
|
||||
/*::[*/0x07/*::]*/: { n: 'Template', t: VT_STRING },
|
||||
/*::[*/0x08/*::]*/: { n: 'LastAuthor', t: VT_STRING },
|
||||
/*::[*/0x09/*::]*/: { n: 'RevNumber', t: VT_STRING },
|
||||
/*::[*/0x0A/*::]*/: { n: 'EditTime', t: VT_FILETIME },
|
||||
/*::[*/0x0B/*::]*/: { n: 'LastPrinted', t: VT_FILETIME },
|
||||
/*::[*/0x0C/*::]*/: { n: 'CreatedDate', t: VT_FILETIME },
|
||||
/*::[*/0x0D/*::]*/: { n: 'ModifiedDate', t: VT_FILETIME },
|
||||
/*::[*/0x0E/*::]*/: { n: 'PageCount', t: VT_I4 },
|
||||
/*::[*/0x0F/*::]*/: { n: 'WordCount', t: VT_I4 },
|
||||
/*::[*/0x10/*::]*/: { n: 'CharCount', t: VT_I4 },
|
||||
/*::[*/0x11/*::]*/: { n: 'Thumbnail', t: VT_CF },
|
||||
/*::[*/0x12/*::]*/: { n: 'Application', t: VT_STRING },
|
||||
/*::[*/0x13/*::]*/: { n: 'DocSecurity', t: VT_I4 },
|
||||
/*::[*/0xFF/*::]*/: {},
|
||||
0x01: { n: 'CodePage', t: VT_I2 },
|
||||
0x02: { n: 'Title', t: VT_STRING },
|
||||
0x03: { n: 'Subject', t: VT_STRING },
|
||||
0x04: { n: 'Author', t: VT_STRING },
|
||||
0x05: { n: 'Keywords', t: VT_STRING },
|
||||
0x06: { n: 'Comments', t: VT_STRING },
|
||||
0x07: { n: 'Template', t: VT_STRING },
|
||||
0x08: { n: 'LastAuthor', t: VT_STRING },
|
||||
0x09: { n: 'RevNumber', t: VT_STRING },
|
||||
0x0A: { n: 'EditTime', t: VT_FILETIME },
|
||||
0x0B: { n: 'LastPrinted', t: VT_FILETIME },
|
||||
0x0C: { n: 'CreatedDate', t: VT_FILETIME },
|
||||
0x0D: { n: 'ModifiedDate', t: VT_FILETIME },
|
||||
0x0E: { n: 'PageCount', t: VT_I4 },
|
||||
0x0F: { n: 'WordCount', t: VT_I4 },
|
||||
0x10: { n: 'CharCount', t: VT_I4 },
|
||||
0x11: { n: 'Thumbnail', t: VT_CF },
|
||||
0x12: { n: 'Application', t: VT_STRING },
|
||||
0x13: { n: 'DocSecurity', t: VT_I4 },
|
||||
0xFF: {},
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
/*::[*/0x80000000/*::]*/: { n: 'Locale', t: VT_UI4 },
|
||||
/*::[*/0x80000003/*::]*/: { n: 'Behavior', t: VT_UI4 },
|
||||
/*::[*/0x72627262/*::]*/: {}
|
||||
0x80000000: { n: 'Locale', t: VT_UI4 },
|
||||
0x80000003: { n: 'Behavior', t: VT_UI4 },
|
||||
0x72627262: {}
|
||||
};
|
||||
|
||||
/* [MS-XLS] 2.4.63 Country/Region codes */
|
||||
var CountryEnum = {
|
||||
/*::[*/0x0001/*::]*/: "US", // United States
|
||||
/*::[*/0x0002/*::]*/: "CA", // Canada
|
||||
/*::[*/0x0003/*::]*/: "", // Latin America (except Brazil)
|
||||
/*::[*/0x0007/*::]*/: "RU", // Russia
|
||||
/*::[*/0x0014/*::]*/: "EG", // Egypt
|
||||
/*::[*/0x001E/*::]*/: "GR", // Greece
|
||||
/*::[*/0x001F/*::]*/: "NL", // Netherlands
|
||||
/*::[*/0x0020/*::]*/: "BE", // Belgium
|
||||
/*::[*/0x0021/*::]*/: "FR", // France
|
||||
/*::[*/0x0022/*::]*/: "ES", // Spain
|
||||
/*::[*/0x0024/*::]*/: "HU", // Hungary
|
||||
/*::[*/0x0027/*::]*/: "IT", // Italy
|
||||
/*::[*/0x0029/*::]*/: "CH", // Switzerland
|
||||
/*::[*/0x002B/*::]*/: "AT", // Austria
|
||||
/*::[*/0x002C/*::]*/: "GB", // United Kingdom
|
||||
/*::[*/0x002D/*::]*/: "DK", // Denmark
|
||||
/*::[*/0x002E/*::]*/: "SE", // Sweden
|
||||
/*::[*/0x002F/*::]*/: "NO", // Norway
|
||||
/*::[*/0x0030/*::]*/: "PL", // Poland
|
||||
/*::[*/0x0031/*::]*/: "DE", // Germany
|
||||
/*::[*/0x0034/*::]*/: "MX", // Mexico
|
||||
/*::[*/0x0037/*::]*/: "BR", // Brazil
|
||||
/*::[*/0x003d/*::]*/: "AU", // Australia
|
||||
/*::[*/0x0040/*::]*/: "NZ", // New Zealand
|
||||
/*::[*/0x0042/*::]*/: "TH", // Thailand
|
||||
/*::[*/0x0051/*::]*/: "JP", // Japan
|
||||
/*::[*/0x0052/*::]*/: "KR", // Korea
|
||||
/*::[*/0x0054/*::]*/: "VN", // Viet Nam
|
||||
/*::[*/0x0056/*::]*/: "CN", // China
|
||||
/*::[*/0x005A/*::]*/: "TR", // Turkey
|
||||
/*::[*/0x0069/*::]*/: "JS", // Ramastan
|
||||
/*::[*/0x00D5/*::]*/: "DZ", // Algeria
|
||||
/*::[*/0x00D8/*::]*/: "MA", // Morocco
|
||||
/*::[*/0x00DA/*::]*/: "LY", // Libya
|
||||
/*::[*/0x015F/*::]*/: "PT", // Portugal
|
||||
/*::[*/0x0162/*::]*/: "IS", // Iceland
|
||||
/*::[*/0x0166/*::]*/: "FI", // Finland
|
||||
/*::[*/0x01A4/*::]*/: "CZ", // Czech Republic
|
||||
/*::[*/0x0376/*::]*/: "TW", // Taiwan
|
||||
/*::[*/0x03C1/*::]*/: "LB", // Lebanon
|
||||
/*::[*/0x03C2/*::]*/: "JO", // Jordan
|
||||
/*::[*/0x03C3/*::]*/: "SY", // Syria
|
||||
/*::[*/0x03C4/*::]*/: "IQ", // Iraq
|
||||
/*::[*/0x03C5/*::]*/: "KW", // Kuwait
|
||||
/*::[*/0x03C6/*::]*/: "SA", // Saudi Arabia
|
||||
/*::[*/0x03CB/*::]*/: "AE", // United Arab Emirates
|
||||
/*::[*/0x03CC/*::]*/: "IL", // Israel
|
||||
/*::[*/0x03CE/*::]*/: "QA", // Qatar
|
||||
/*::[*/0x03D5/*::]*/: "IR", // Iran
|
||||
/*::[*/0xFFFF/*::]*/: "US" // United States
|
||||
0x0001: "US", // United States
|
||||
0x0002: "CA", // Canada
|
||||
0x0003: "", // Latin America (except Brazil)
|
||||
0x0007: "RU", // Russia
|
||||
0x0014: "EG", // Egypt
|
||||
0x001E: "GR", // Greece
|
||||
0x001F: "NL", // Netherlands
|
||||
0x0020: "BE", // Belgium
|
||||
0x0021: "FR", // France
|
||||
0x0022: "ES", // Spain
|
||||
0x0024: "HU", // Hungary
|
||||
0x0027: "IT", // Italy
|
||||
0x0029: "CH", // Switzerland
|
||||
0x002B: "AT", // Austria
|
||||
0x002C: "GB", // United Kingdom
|
||||
0x002D: "DK", // Denmark
|
||||
0x002E: "SE", // Sweden
|
||||
0x002F: "NO", // Norway
|
||||
0x0030: "PL", // Poland
|
||||
0x0031: "DE", // Germany
|
||||
0x0034: "MX", // Mexico
|
||||
0x0037: "BR", // Brazil
|
||||
0x003d: "AU", // Australia
|
||||
0x0040: "NZ", // New Zealand
|
||||
0x0042: "TH", // Thailand
|
||||
0x0051: "JP", // Japan
|
||||
0x0052: "KR", // Korea
|
||||
0x0054: "VN", // Viet Nam
|
||||
0x0056: "CN", // China
|
||||
0x005A: "TR", // Turkey
|
||||
0x0069: "JS", // Ramastan
|
||||
0x00D5: "DZ", // Algeria
|
||||
0x00D8: "MA", // Morocco
|
||||
0x00DA: "LY", // Libya
|
||||
0x015F: "PT", // Portugal
|
||||
0x0162: "IS", // Iceland
|
||||
0x0166: "FI", // Finland
|
||||
0x01A4: "CZ", // Czech Republic
|
||||
0x0376: "TW", // Taiwan
|
||||
0x03C1: "LB", // Lebanon
|
||||
0x03C2: "JO", // Jordan
|
||||
0x03C3: "SY", // Syria
|
||||
0x03C4: "IQ", // Iraq
|
||||
0x03C5: "KW", // Kuwait
|
||||
0x03C6: "SA", // Saudi Arabia
|
||||
0x03CB: "AE", // United Arab Emirates
|
||||
0x03CC: "IL", // Israel
|
||||
0x03CE: "QA", // Qatar
|
||||
0x03D5: "IR", // Iran
|
||||
0xFFFF: "US" // United States
|
||||
};
|
||||
|
||||
/* [MS-XLS] 2.5.127 */
|
||||
@ -281,15 +281,15 @@ var XLSIcv = /*#__PURE__*/dup(_XLSIcv);
|
||||
|
||||
/* [MS-XLSB] 2.5.97.2 */
|
||||
var BErr = {
|
||||
/*::[*/0x00/*::]*/: "#NULL!",
|
||||
/*::[*/0x07/*::]*/: "#DIV/0!",
|
||||
/*::[*/0x0F/*::]*/: "#VALUE!",
|
||||
/*::[*/0x17/*::]*/: "#REF!",
|
||||
/*::[*/0x1D/*::]*/: "#NAME?",
|
||||
/*::[*/0x24/*::]*/: "#NUM!",
|
||||
/*::[*/0x2A/*::]*/: "#N/A",
|
||||
/*::[*/0x2B/*::]*/: "#GETTING_DATA",
|
||||
/*::[*/0xFF/*::]*/: "#WTF?"
|
||||
0x00: "#NULL!",
|
||||
0x07: "#DIV/0!",
|
||||
0x0F: "#VALUE!",
|
||||
0x17: "#REF!",
|
||||
0x1D: "#NAME?",
|
||||
0x24: "#NUM!",
|
||||
0x2A: "#N/A",
|
||||
0x2B: "#GETTING_DATA",
|
||||
0xFF: "#WTF?"
|
||||
};
|
||||
//var RBErr = evert_num(BErr);
|
||||
var RBErr = {
|
||||
|
@ -18,22 +18,12 @@ var CORE_PROPS/*:Array<Array<string> >*/ = [
|
||||
["dcterms:modified", "ModifiedDate", 'date']
|
||||
];
|
||||
|
||||
var CORE_PROPS_REGEX/*:Array<RegExp>*/ = /*#__PURE__*/(function() {
|
||||
var r = new Array(CORE_PROPS.length);
|
||||
for(var i = 0; i < CORE_PROPS.length; ++i) {
|
||||
var f = CORE_PROPS[i];
|
||||
var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
|
||||
r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
|
||||
}
|
||||
return r;
|
||||
})();
|
||||
|
||||
function parse_core_props(data) {
|
||||
var p = {};
|
||||
data = utf8read(data);
|
||||
|
||||
for(var i = 0; i < CORE_PROPS.length; ++i) {
|
||||
var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
|
||||
var f = CORE_PROPS[i], cur = str_match_xml(data, f[0]);
|
||||
if(cur != null && cur.length > 0) p[f[1]] = unescapexml(cur[1]);
|
||||
if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
|
||||
}
|
||||
|
@ -71,12 +71,12 @@ function parse_ext_props(data, p, opts) {
|
||||
data = utf8read(data);
|
||||
|
||||
EXT_PROPS.forEach(function(f) {
|
||||
var xml = (data.match(matchtag(f[0]))||[])[1];
|
||||
var xml = (str_match_xml_ns(data, f[0])||[])[1];
|
||||
switch(f[2]) {
|
||||
case "string": if(xml) p[f[1]] = unescapexml(xml); break;
|
||||
case "bool": p[f[1]] = xml === "true"; break;
|
||||
case "raw":
|
||||
var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
|
||||
var cur = str_match_xml(data, f[0]);
|
||||
if(cur && cur.length > 0) q[f[1]] = cur[1];
|
||||
break;
|
||||
}
|
||||
|
@ -1,5 +1,5 @@
|
||||
/* 15.2.12.2 Custom File Properties Part */
|
||||
var custregex = /<[^>]+>[^<]*/g;
|
||||
var custregex = /<[^<>]+>[^<]*/g;
|
||||
function parse_cust_props(data/*:string*/, opts) {
|
||||
var p = {}, name = "";
|
||||
var m = data.match(custregex);
|
||||
|
@ -123,8 +123,8 @@ function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
|
||||
case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
|
||||
case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
|
||||
case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
|
||||
case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
|
||||
case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
|
||||
case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break;
|
||||
case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break;
|
||||
case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
|
||||
case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
|
||||
case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
|
||||
@ -233,8 +233,8 @@ function parse_PropertySet(blob, PIDSI) {
|
||||
/* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
|
||||
switch(blob[blob.l]) {
|
||||
case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
|
||||
case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
|
||||
case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
|
||||
case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break;
|
||||
case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break;
|
||||
case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
|
||||
case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
|
||||
case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
|
||||
|
@ -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);
|
||||
@ -111,25 +122,25 @@ function parse_FtCf(blob) {
|
||||
/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
|
||||
function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
|
||||
var FtTab = {
|
||||
/*::[*/0x00/*::]*/: parse_FtSkip, /* FtEnd */
|
||||
/*::[*/0x04/*::]*/: parse_FtSkip, /* FtMacro */
|
||||
/*::[*/0x05/*::]*/: parse_FtSkip, /* FtButton */
|
||||
/*::[*/0x06/*::]*/: parse_FtSkip, /* FtGmo */
|
||||
/*::[*/0x07/*::]*/: parse_FtCf, /* FtCf */
|
||||
/*::[*/0x08/*::]*/: parse_FtSkip, /* FtPioGrbit */
|
||||
/*::[*/0x09/*::]*/: parse_FtSkip, /* FtPictFmla */
|
||||
/*::[*/0x0A/*::]*/: parse_FtSkip, /* FtCbls */
|
||||
/*::[*/0x0B/*::]*/: parse_FtSkip, /* FtRbo */
|
||||
/*::[*/0x0C/*::]*/: parse_FtSkip, /* FtSbs */
|
||||
/*::[*/0x0D/*::]*/: parse_FtNts, /* FtNts */
|
||||
/*::[*/0x0E/*::]*/: parse_FtSkip, /* FtSbsFmla */
|
||||
/*::[*/0x0F/*::]*/: parse_FtSkip, /* FtGboData */
|
||||
/*::[*/0x10/*::]*/: parse_FtSkip, /* FtEdoData */
|
||||
/*::[*/0x11/*::]*/: parse_FtSkip, /* FtRboData */
|
||||
/*::[*/0x12/*::]*/: parse_FtSkip, /* FtCblsData */
|
||||
/*::[*/0x13/*::]*/: parse_FtSkip, /* FtLbsData */
|
||||
/*::[*/0x14/*::]*/: parse_FtSkip, /* FtCblsFmla */
|
||||
/*::[*/0x15/*::]*/: parse_FtCmo
|
||||
0x00: parse_FtSkip, /* FtEnd */
|
||||
0x04: parse_FtSkip, /* FtMacro */
|
||||
0x05: parse_FtSkip, /* FtButton */
|
||||
0x06: parse_FtSkip, /* FtGmo */
|
||||
0x07: parse_FtCf, /* FtCf */
|
||||
0x08: parse_FtSkip, /* FtPioGrbit */
|
||||
0x09: parse_FtSkip, /* FtPictFmla */
|
||||
0x0A: parse_FtSkip, /* FtCbls */
|
||||
0x0B: parse_FtSkip, /* FtRbo */
|
||||
0x0C: parse_FtSkip, /* FtSbs */
|
||||
0x0D: parse_FtNts, /* FtNts */
|
||||
0x0E: parse_FtSkip, /* FtSbsFmla */
|
||||
0x0F: parse_FtSkip, /* FtGboData */
|
||||
0x10: parse_FtSkip, /* FtEdoData */
|
||||
0x11: parse_FtSkip, /* FtRboData */
|
||||
0x12: parse_FtSkip, /* FtCblsData */
|
||||
0x13: parse_FtSkip, /* FtLbsData */
|
||||
0x14: parse_FtSkip, /* FtCblsFmla */
|
||||
0x15: parse_FtCmo
|
||||
};
|
||||
function parse_FtArray(blob, length/*::, ot*/) {
|
||||
var tgt = blob.l + length;
|
||||
@ -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;
|
||||
@ -752,21 +818,34 @@ function parse_MTRSettings(blob) {
|
||||
return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
|
||||
}
|
||||
|
||||
/* [MS-XLS] 2.5.186 TODO: BIFF5 */
|
||||
/* [MS-XLS] 2.5.186 */
|
||||
function parse_NoteSh(blob, length, opts) {
|
||||
if(opts.biff < 8) return;
|
||||
var row = blob.read_shift(2), col = blob.read_shift(2);
|
||||
var flags = blob.read_shift(2), idObj = blob.read_shift(2);
|
||||
var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
|
||||
if(opts.biff < 8) blob.read_shift(1);
|
||||
return [{r:row,c:col}, stAuthor, idObj, flags];
|
||||
}
|
||||
|
||||
/* [MS-XLS] 2.4.179 */
|
||||
function parse_Note(blob, length, opts) {
|
||||
if(opts && (opts.biff < 8)) {
|
||||
var row = blob.read_shift(2), col = blob.read_shift(2);
|
||||
if(row == 0xFFFF || row == -1) return; // TODO: test continuation
|
||||
var cch = blob.read_shift(2);
|
||||
var cmnt = blob.read_shift(Math.min(cch,2048), 'cpstr');
|
||||
return [{r:row, c:col}, cmnt];
|
||||
}
|
||||
/* TODO: Support revisions */
|
||||
return parse_NoteSh(blob, length, opts);
|
||||
}
|
||||
function write_NOTE_BIFF2(text/*:string*/, R/*:number*/, C/*:number*/, len/*?:number*/) {
|
||||
var o = new_buf(6 + (len || text.length));
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(2, C);
|
||||
o.write_shift(2, len || text.length);
|
||||
o.write_shift(text.length, text, "sbcs");
|
||||
return o;
|
||||
}
|
||||
|
||||
/* [MS-XLS] 2.4.168 */
|
||||
function parse_MergeCells(blob, length)/*:Array<Range>*/ {
|
||||
@ -1016,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;
|
||||
}
|
||||
@ -1063,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
|
||||
@ -1076,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;
|
||||
@ -1084,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 };
|
||||
}
|
241
bits/40_harb.js
241
bits/40_harb.js
@ -2,60 +2,60 @@ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5];
|
||||
var DBF = /*#__PURE__*/(function() {
|
||||
var dbf_codepage_map = {
|
||||
/* Code Pages Supported by Visual FoxPro */
|
||||
/*::[*/0x01/*::]*/: 437, /*::[*/0x02/*::]*/: 850,
|
||||
/*::[*/0x03/*::]*/: 1252, /*::[*/0x04/*::]*/: 10000,
|
||||
/*::[*/0x64/*::]*/: 852, /*::[*/0x65/*::]*/: 866,
|
||||
/*::[*/0x66/*::]*/: 865, /*::[*/0x67/*::]*/: 861,
|
||||
/*::[*/0x68/*::]*/: 895, /*::[*/0x69/*::]*/: 620,
|
||||
/*::[*/0x6A/*::]*/: 737, /*::[*/0x6B/*::]*/: 857,
|
||||
/*::[*/0x78/*::]*/: 950, /*::[*/0x79/*::]*/: 949,
|
||||
/*::[*/0x7A/*::]*/: 936, /*::[*/0x7B/*::]*/: 932,
|
||||
/*::[*/0x7C/*::]*/: 874, /*::[*/0x7D/*::]*/: 1255,
|
||||
/*::[*/0x7E/*::]*/: 1256, /*::[*/0x96/*::]*/: 10007,
|
||||
/*::[*/0x97/*::]*/: 10029, /*::[*/0x98/*::]*/: 10006,
|
||||
/*::[*/0xC8/*::]*/: 1250, /*::[*/0xC9/*::]*/: 1251,
|
||||
/*::[*/0xCA/*::]*/: 1254, /*::[*/0xCB/*::]*/: 1253,
|
||||
0x01: 437, 0x02: 850,
|
||||
0x03: 1252, 0x04: 10000,
|
||||
0x64: 852, 0x65: 866,
|
||||
0x66: 865, 0x67: 861,
|
||||
0x68: 895, 0x69: 620,
|
||||
0x6A: 737, 0x6B: 857,
|
||||
0x78: 950, 0x79: 949,
|
||||
0x7A: 936, 0x7B: 932,
|
||||
0x7C: 874, 0x7D: 1255,
|
||||
0x7E: 1256, 0x96: 10007,
|
||||
0x97: 10029, 0x98: 10006,
|
||||
0xC8: 1250, 0xC9: 1251,
|
||||
0xCA: 1254, 0xCB: 1253,
|
||||
|
||||
/* shapefile DBF extension */
|
||||
/*::[*/0x00/*::]*/: 20127, /*::[*/0x08/*::]*/: 865,
|
||||
/*::[*/0x09/*::]*/: 437, /*::[*/0x0A/*::]*/: 850,
|
||||
/*::[*/0x0B/*::]*/: 437, /*::[*/0x0D/*::]*/: 437,
|
||||
/*::[*/0x0E/*::]*/: 850, /*::[*/0x0F/*::]*/: 437,
|
||||
/*::[*/0x10/*::]*/: 850, /*::[*/0x11/*::]*/: 437,
|
||||
/*::[*/0x12/*::]*/: 850, /*::[*/0x13/*::]*/: 932,
|
||||
/*::[*/0x14/*::]*/: 850, /*::[*/0x15/*::]*/: 437,
|
||||
/*::[*/0x16/*::]*/: 850, /*::[*/0x17/*::]*/: 865,
|
||||
/*::[*/0x18/*::]*/: 437, /*::[*/0x19/*::]*/: 437,
|
||||
/*::[*/0x1A/*::]*/: 850, /*::[*/0x1B/*::]*/: 437,
|
||||
/*::[*/0x1C/*::]*/: 863, /*::[*/0x1D/*::]*/: 850,
|
||||
/*::[*/0x1F/*::]*/: 852, /*::[*/0x22/*::]*/: 852,
|
||||
/*::[*/0x23/*::]*/: 852, /*::[*/0x24/*::]*/: 860,
|
||||
/*::[*/0x25/*::]*/: 850, /*::[*/0x26/*::]*/: 866,
|
||||
/*::[*/0x37/*::]*/: 850, /*::[*/0x40/*::]*/: 852,
|
||||
/*::[*/0x4D/*::]*/: 936, /*::[*/0x4E/*::]*/: 949,
|
||||
/*::[*/0x4F/*::]*/: 950, /*::[*/0x50/*::]*/: 874,
|
||||
/*::[*/0x57/*::]*/: 1252, /*::[*/0x58/*::]*/: 1252,
|
||||
/*::[*/0x59/*::]*/: 1252, /*::[*/0x6C/*::]*/: 863,
|
||||
/*::[*/0x86/*::]*/: 737, /*::[*/0x87/*::]*/: 852,
|
||||
/*::[*/0x88/*::]*/: 857, /*::[*/0xCC/*::]*/: 1257,
|
||||
0x00: 20127, 0x08: 865,
|
||||
0x09: 437, 0x0A: 850,
|
||||
0x0B: 437, 0x0D: 437,
|
||||
0x0E: 850, 0x0F: 437,
|
||||
0x10: 850, 0x11: 437,
|
||||
0x12: 850, 0x13: 932,
|
||||
0x14: 850, 0x15: 437,
|
||||
0x16: 850, 0x17: 865,
|
||||
0x18: 437, 0x19: 437,
|
||||
0x1A: 850, 0x1B: 437,
|
||||
0x1C: 863, 0x1D: 850,
|
||||
0x1F: 852, 0x22: 852,
|
||||
0x23: 852, 0x24: 860,
|
||||
0x25: 850, 0x26: 866,
|
||||
0x37: 850, 0x40: 852,
|
||||
0x4D: 936, 0x4E: 949,
|
||||
0x4F: 950, 0x50: 874,
|
||||
0x57: 1252, 0x58: 1252,
|
||||
0x59: 1252, 0x6C: 863,
|
||||
0x86: 737, 0x87: 852,
|
||||
0x88: 857, 0xCC: 1257,
|
||||
|
||||
/*::[*/0xFF/*::]*/: 16969
|
||||
0xFF: 16969
|
||||
};
|
||||
var dbf_reverse_map = evert({
|
||||
/*::[*/0x01/*::]*/: 437, /*::[*/0x02/*::]*/: 850,
|
||||
/*::[*/0x03/*::]*/: 1252, /*::[*/0x04/*::]*/: 10000,
|
||||
/*::[*/0x64/*::]*/: 852, /*::[*/0x65/*::]*/: 866,
|
||||
/*::[*/0x66/*::]*/: 865, /*::[*/0x67/*::]*/: 861,
|
||||
/*::[*/0x68/*::]*/: 895, /*::[*/0x69/*::]*/: 620,
|
||||
/*::[*/0x6A/*::]*/: 737, /*::[*/0x6B/*::]*/: 857,
|
||||
/*::[*/0x78/*::]*/: 950, /*::[*/0x79/*::]*/: 949,
|
||||
/*::[*/0x7A/*::]*/: 936, /*::[*/0x7B/*::]*/: 932,
|
||||
/*::[*/0x7C/*::]*/: 874, /*::[*/0x7D/*::]*/: 1255,
|
||||
/*::[*/0x7E/*::]*/: 1256, /*::[*/0x96/*::]*/: 10007,
|
||||
/*::[*/0x97/*::]*/: 10029, /*::[*/0x98/*::]*/: 10006,
|
||||
/*::[*/0xC8/*::]*/: 1250, /*::[*/0xC9/*::]*/: 1251,
|
||||
/*::[*/0xCA/*::]*/: 1254, /*::[*/0xCB/*::]*/: 1253,
|
||||
/*::[*/0x00/*::]*/: 20127
|
||||
0x01: 437, 0x02: 850,
|
||||
0x03: 1252, 0x04: 10000,
|
||||
0x64: 852, 0x65: 866,
|
||||
0x66: 865, 0x67: 861,
|
||||
0x68: 895, 0x69: 620,
|
||||
0x6A: 737, 0x6B: 857,
|
||||
0x78: 950, 0x79: 949,
|
||||
0x7A: 936, 0x7B: 932,
|
||||
0x7C: 874, 0x7D: 1255,
|
||||
0x7E: 1256, 0x96: 10007,
|
||||
0x97: 10029, 0x98: 10006,
|
||||
0xC8: 1250, 0xC9: 1251,
|
||||
0xCA: 1254, 0xCB: 1253,
|
||||
0x00: 20127
|
||||
});
|
||||
/* TODO: find an actual specification */
|
||||
function dbf_to_aoa(buf, opts)/*:AOA*/ {
|
||||
@ -118,7 +118,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
|
||||
var ww = l7 ? 32 : 11;
|
||||
while(d.l < hend && d[d.l] != 0x0d) {
|
||||
field = ({}/*:any*/);
|
||||
field.name = (typeof $cptable !== "undefined" ? $cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)) : a2s(d.slice(d.l, d.l + ww))).replace(/[\u0000\r\n].*$/g,"");
|
||||
field.name = (typeof $cptable !== "undefined" ? $cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)) : a2s(d.slice(d.l, d.l + ww))).replace(/[\u0000\r\n][\S\s]*$/g,"");
|
||||
d.l += ww;
|
||||
field.type = String.fromCharCode(d.read_shift(1));
|
||||
if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
|
||||
@ -176,10 +176,13 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
|
||||
switch(fields[C].type) {
|
||||
case 'C':
|
||||
// NOTE: it is conventional to write ' / / ' for empty dates
|
||||
if(s.trim().length) out[R][C] = s.replace(/\s+$/,"");
|
||||
if(s.trim().length) out[R][C] = s.replace(/([^\s])\s+$/,"$1");
|
||||
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;
|
||||
@ -187,7 +190,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ {
|
||||
case 'L': switch(s.trim().toUpperCase()) {
|
||||
case 'Y': case 'T': out[R][C] = true; break;
|
||||
case 'N': case 'F': out[R][C] = false; break;
|
||||
case '': case '?': break;
|
||||
case '': case '\x00': case '?': break;
|
||||
default: throw new Error("DBF Unrecognized L:|" + s + "|");
|
||||
} break;
|
||||
case 'M': /* TODO: handle memo files */
|
||||
@ -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; }
|
||||
@ -244,6 +252,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
|
||||
|
||||
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
|
||||
function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
|
||||
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DBF");
|
||||
var o = opts || {};
|
||||
var old_cp = current_codepage;
|
||||
if(+o.codepage >= 0) set_cp(+o.codepage);
|
||||
@ -395,16 +404,21 @@ var SYLK = /*#__PURE__*/(function() {
|
||||
KC:'Ç', Kc:'ç', q:'æ', z:'œ', a:'Æ', j:'Œ',
|
||||
DN:209, Dn:241, Hy:255,
|
||||
S:169, c:170, R:174, "B ":180,
|
||||
/*::[*/0/*::]*/:176, /*::[*/1/*::]*/:177, /*::[*/2/*::]*/:178,
|
||||
/*::[*/3/*::]*/:179, /*::[*/5/*::]*/:181, /*::[*/6/*::]*/:182,
|
||||
/*::[*/7/*::]*/:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
|
||||
0:176, 1:177, 2:178,
|
||||
3:179, 5:181, 6:182,
|
||||
7:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
|
||||
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
|
||||
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
|
||||
}/*:any*/);
|
||||
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
|
||||
var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1").replace("{", "\\{") + "|\\|)", "gm");
|
||||
try {
|
||||
sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
|
||||
} catch(e) {}
|
||||
var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
|
||||
var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
|
||||
sylk_escapes["|"] = 254;
|
||||
/* TODO: evert the escape map */
|
||||
var encode_sylk_str = function($$) { return $$.replace(/\n/g, "\x1b :").replace(/\r/g, "\x1b ="); };
|
||||
/* https://oss.sheetjs.com/notes/sylk/ for more details */
|
||||
function sylk_to_aoa(d/*:RawData*/, opts)/*:[AOA, Worksheet]*/ {
|
||||
switch(opts.type) {
|
||||
@ -457,8 +471,9 @@ var SYLK = /*#__PURE__*/(function() {
|
||||
// case 'NU': // ??
|
||||
case 'C': /* cell */
|
||||
var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1, formula = "", cell_t = "z";
|
||||
var cmnt = "";
|
||||
for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
|
||||
case 'A': break; // TODO: comment
|
||||
case 'A': cmnt = record[rj].slice(1); break; // TODO: comment
|
||||
case 'X': C = parseInt(record[rj].slice(1), 10)-1; C_seen_X = true; break;
|
||||
case 'Y':
|
||||
R = parseInt(record[rj].slice(1), 10)-1; if(!C_seen_X) C = 0;
|
||||
@ -468,12 +483,12 @@ var SYLK = /*#__PURE__*/(function() {
|
||||
val = record[rj].slice(1);
|
||||
if(val.charAt(0) === '"') { val = val.slice(1,val.length - 1); cell_t = "s"; }
|
||||
else if(val === 'TRUE' || val === 'FALSE') { val = val === 'TRUE'; cell_t = "b"; }
|
||||
else if(val.charAt(0) == "#" && RBErr[val] != null) { cell_t = "e"; val = RBErr[val]; }
|
||||
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;
|
||||
@ -509,6 +524,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;
|
||||
@ -570,20 +589,27 @@ 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':
|
||||
o += (cell.v||0);
|
||||
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 'e': o += cell.w || BErr[cell.v] || 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) + " ";
|
||||
@ -608,30 +634,52 @@ var SYLK = /*#__PURE__*/(function() {
|
||||
}
|
||||
|
||||
function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/, wb/*:?WorkBook*/)/*:string*/ {
|
||||
if(!opts) opts = {}; opts._formats = ["General"];
|
||||
/* TODO: codepage */
|
||||
var preamble/*:Array<string>*/ = ["ID;PSheetJS;N;E"], o/*:Array<string>*/ = [];
|
||||
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
|
||||
var r = safe_decode_range(ws['!ref']||"A1"), cell/*:Cell*/;
|
||||
var dense = ws["!data"] != null;
|
||||
var RS = "\r\n";
|
||||
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
|
||||
|
||||
var _lastfmt = "General";
|
||||
preamble.push("P;PGeneral");
|
||||
/* Excel has been inconsistent in comment placement */
|
||||
var R = r.s.r, C = r.s.c, p = [];
|
||||
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
|
||||
if(dense && !ws["!data"][R]) continue;
|
||||
p = [];
|
||||
for(C = r.s.c; C <= r.e.c; ++C) {
|
||||
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
|
||||
if(!cell || !cell.c) continue;
|
||||
p.push(write_ws_cmnt_sylk(cell.c, R, C));
|
||||
}
|
||||
if(p.length) o.push(p.join(RS));
|
||||
}
|
||||
if(ws["!ref"]) for(R = r.s.r; R <= r.e.r; ++R) {
|
||||
if(dense && !ws["!data"][R]) continue;
|
||||
p = [];
|
||||
for(C = r.s.c; C <= r.e.c; ++C) {
|
||||
cell = dense ? ws["!data"][R][C] : ws[encode_col(C) + encode_row(R)];
|
||||
if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
|
||||
if((cell.z||(cell.t == "d" ? table_fmt[14] : "General")) != _lastfmt) {
|
||||
var ifmt = opts._formats.indexOf(cell.z);
|
||||
if(ifmt == -1) { opts._formats.push(cell.z); ifmt = opts._formats.length - 1; preamble.push("P;P" + cell.z.replace(/;/g, ";;")); }
|
||||
p.push("F;P" + ifmt + ";Y" + (R+1) + ";X" + (C+1));
|
||||
}
|
||||
p.push(write_ws_cell_sylk(cell, ws, R, C, opts, d1904));
|
||||
}
|
||||
o.push(p.join(RS));
|
||||
}
|
||||
|
||||
preamble.push("F;P0;DG0G8;M255");
|
||||
if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
|
||||
if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
|
||||
|
||||
preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
|
||||
if(ws["!ref"]) preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
|
||||
preamble.push("O;L;D;B" + (d1904 ? ";V4" : "") + ";K47;G100 0.001");
|
||||
for(var R = r.s.r; R <= r.e.r; ++R) {
|
||||
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;
|
||||
}
|
||||
|
||||
@ -671,7 +719,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:
|
||||
@ -698,6 +749,7 @@ var DIF = /*#__PURE__*/(function() {
|
||||
function make_value_str(s/*:string*/)/*:string*/ { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
|
||||
function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
|
||||
var _DIF_XL = DIF_XL;
|
||||
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to DIF");
|
||||
var r = safe_decode_range(ws['!ref']);
|
||||
var dense = ws["!data"] != null;
|
||||
var o/*:Array<string>*/ = [
|
||||
@ -889,18 +941,18 @@ var PRN = /*#__PURE__*/(function() {
|
||||
|
||||
// List of accepted CSV separators
|
||||
var guess_seps = {
|
||||
/*::[*/0x2C/*::]*/: ',',
|
||||
/*::[*/0x09/*::]*/: "\t",
|
||||
/*::[*/0x3B/*::]*/: ';',
|
||||
/*::[*/0x7C/*::]*/: '|'
|
||||
0x2C: ',',
|
||||
0x09: "\t",
|
||||
0x3B: ';',
|
||||
0x7C: '|'
|
||||
};
|
||||
|
||||
// CSV separator weights to be used in case of equal numbers
|
||||
var guess_sep_weights = {
|
||||
/*::[*/0x2C/*::]*/: 3,
|
||||
/*::[*/0x09/*::]*/: 2,
|
||||
/*::[*/0x3B/*::]*/: 1,
|
||||
/*::[*/0x7C/*::]*/: 0
|
||||
0x2C: 3,
|
||||
0x09: 2,
|
||||
0x3B: 1,
|
||||
0x7C: 0
|
||||
};
|
||||
|
||||
function guess_sep(str) {
|
||||
@ -952,26 +1004,28 @@ var PRN = /*#__PURE__*/(function() {
|
||||
var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0, startcc=str.charCodeAt(0);
|
||||
var _re/*:?RegExp*/ = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
|
||||
function finish_cell() {
|
||||
/* TODO: fuzzy parsers should pass back assumed number format */
|
||||
var s = str.slice(start, end); if(s.slice(-1) == "\r") s = s.slice(0, -1);
|
||||
var cell = ({}/*:any*/);
|
||||
if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
|
||||
if(o.cellText !== false) cell.w = s;
|
||||
if(s.length === 0) cell.t = 'z';
|
||||
else if(o.raw) { cell.t = 's'; cell.v = s; }
|
||||
else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
|
||||
else if(s.charCodeAt(0) == 0x3D) {
|
||||
if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
|
||||
else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
|
||||
else if(fuzzyfmla(s)) { cell.t = 's'; cell.f = s.slice(1); cell.v = s; }
|
||||
else { cell.t = 's'; cell.v = s; } }
|
||||
else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
|
||||
else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
|
||||
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
|
||||
else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; cell.v = v; }
|
||||
else if(!isNaN((v = fuzzydate(s)).getDate()) || _re && s.match(_re)) {
|
||||
cell.z = o.dateNF || table_fmt[14];
|
||||
var k = 0;
|
||||
if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; v = parseDate(s, k); }
|
||||
if(_re && s.match(_re)){ var news=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); v = parseDate(news); if(o && o.UTC === false) v = utc_to_local(v); }
|
||||
else if(o && o.UTC === false) v = utc_to_local(v);
|
||||
else if(o.cellText !== false && o.dateNF) cell.w = SSF_format(cell.z, v);
|
||||
if(o.cellDates) { cell.t = 'd'; cell.v = v; }
|
||||
else { cell.t = 'n'; cell.v = datenum(v); }
|
||||
if(o.cellText !== false) cell.w = SSF_format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
|
||||
if(!o.cellNF) delete cell.z;
|
||||
} else {
|
||||
cell.t = 's';
|
||||
@ -1033,6 +1087,7 @@ var PRN = /*#__PURE__*/(function() {
|
||||
|
||||
function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
|
||||
var o/*:Array<string>*/ = [];
|
||||
if(!ws["!ref"]) return "";
|
||||
var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
|
||||
var dense = ws["!data"] != null;
|
||||
for(var R = r.s.r; R <= r.e.r; ++R) {
|
||||
@ -1066,7 +1121,7 @@ function read_wb_ID(d, opts) {
|
||||
return out;
|
||||
} catch(e) {
|
||||
o.WTF = OLD_WTF;
|
||||
if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
|
||||
if((e.message.indexOf("SYLK bad record ID") == -1) && OLD_WTF) throw e;
|
||||
return PRN.to_workbook(d, opts);
|
||||
}
|
||||
}
|
||||
|
543
bits/41_lotus.js
543
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;
|
||||
@ -157,6 +184,7 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
if(+o.codepage >= 0) set_cp(+o.codepage);
|
||||
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
|
||||
var ba = buf_array();
|
||||
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to WK1");
|
||||
var range = safe_decode_range(ws["!ref"]);
|
||||
var dense = ws["!data"] != null;
|
||||
var cols = [];
|
||||
@ -171,10 +199,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 +343,18 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
return o;
|
||||
}
|
||||
|
||||
function get_wk1_fmt(cell)/*:number*/ {
|
||||
/* TODO: some fuzzy matching on the number format */
|
||||
if(cell.z && fmt_is_date(cell.z)) {
|
||||
return 0xf0 | (LOTUS_DATE_FMTS.indexOf(cell.z) + 1 || 2);
|
||||
}
|
||||
return 0xFF;
|
||||
}
|
||||
function parse_LABEL(blob, length, opts) {
|
||||
var tgt = blob.l + length;
|
||||
var o = parse_cell(blob, length, opts);
|
||||
o[1].t = 's';
|
||||
if(opts.vers == 0x5120) {
|
||||
if((opts.vers & 0xFFFE) == 0x5120) { // WQ1 / WQ2
|
||||
blob.l++;
|
||||
var len = blob.read_shift(1);
|
||||
o[1].v = blob.read_shift(len, 'utf8');
|
||||
@ -354,12 +396,12 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
o[1].v = blob.read_shift(2, 'i');
|
||||
return o;
|
||||
}
|
||||
function write_INTEGER(R, C, v) {
|
||||
function write_INTEGER(R, C, cell) {
|
||||
var o = new_buf(7);
|
||||
o.write_shift(1, 0xFF);
|
||||
o.write_shift(1, get_wk1_fmt(cell));
|
||||
o.write_shift(2, C);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(2, v, 'i');
|
||||
o.write_shift(2, cell.v, 'i');
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -368,12 +410,12 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
o[1].v = blob.read_shift(8, 'f');
|
||||
return o;
|
||||
}
|
||||
function write_NUMBER(R, C, v) {
|
||||
function write_NUMBER(R, C, cell) {
|
||||
var o = new_buf(13);
|
||||
o.write_shift(1, 0xFF);
|
||||
o.write_shift(1, get_wk1_fmt(cell));
|
||||
o.write_shift(2, C);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(8, v, 'f');
|
||||
o.write_shift(8, cell.v, 'f');
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -426,7 +468,7 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
0x33: ["FALSE", 0],
|
||||
0x34: ["TRUE", 0],
|
||||
0x35: ["RAND", 0],
|
||||
// 0x36 DATE
|
||||
0x36: ["DATE", 3],
|
||||
// 0x37 NOW
|
||||
// 0x38 PMT
|
||||
// 0x39 PV
|
||||
@ -436,7 +478,7 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
// 0x3D MONTH
|
||||
// 0x3E YEAR
|
||||
0x3F: ["ROUND", 2],
|
||||
// 0x40 TIME
|
||||
0x40: ["TIME", 3],
|
||||
// 0x41 HOUR
|
||||
// 0x42 MINUTE
|
||||
// 0x43 SECOND
|
||||
@ -721,199 +763,240 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
}
|
||||
|
||||
var WK1Enum = {
|
||||
/*::[*/0x0000/*::]*/: { n:"BOF", f:parseuint16 },
|
||||
/*::[*/0x0001/*::]*/: { n:"EOF" },
|
||||
/*::[*/0x0002/*::]*/: { n:"CALCMODE" },
|
||||
/*::[*/0x0003/*::]*/: { n:"CALCORDER" },
|
||||
/*::[*/0x0004/*::]*/: { n:"SPLIT" },
|
||||
/*::[*/0x0005/*::]*/: { n:"SYNC" },
|
||||
/*::[*/0x0006/*::]*/: { n:"RANGE", f:parse_RANGE },
|
||||
/*::[*/0x0007/*::]*/: { n:"WINDOW1" },
|
||||
/*::[*/0x0008/*::]*/: { n:"COLW1" },
|
||||
/*::[*/0x0009/*::]*/: { n:"WINTWO" },
|
||||
/*::[*/0x000A/*::]*/: { n:"COLW2" },
|
||||
/*::[*/0x000B/*::]*/: { n:"NAME" },
|
||||
/*::[*/0x000C/*::]*/: { n:"BLANK" },
|
||||
/*::[*/0x000D/*::]*/: { n:"INTEGER", f:parse_INTEGER },
|
||||
/*::[*/0x000E/*::]*/: { n:"NUMBER", f:parse_NUMBER },
|
||||
/*::[*/0x000F/*::]*/: { n:"LABEL", f:parse_LABEL },
|
||||
/*::[*/0x0010/*::]*/: { n:"FORMULA", f:parse_FORMULA },
|
||||
/*::[*/0x0018/*::]*/: { n:"TABLE" },
|
||||
/*::[*/0x0019/*::]*/: { n:"ORANGE" },
|
||||
/*::[*/0x001A/*::]*/: { n:"PRANGE" },
|
||||
/*::[*/0x001B/*::]*/: { n:"SRANGE" },
|
||||
/*::[*/0x001C/*::]*/: { n:"FRANGE" },
|
||||
/*::[*/0x001D/*::]*/: { n:"KRANGE1" },
|
||||
/*::[*/0x0020/*::]*/: { n:"HRANGE" },
|
||||
/*::[*/0x0023/*::]*/: { n:"KRANGE2" },
|
||||
/*::[*/0x0024/*::]*/: { n:"PROTEC" },
|
||||
/*::[*/0x0025/*::]*/: { n:"FOOTER" },
|
||||
/*::[*/0x0026/*::]*/: { n:"HEADER" },
|
||||
/*::[*/0x0027/*::]*/: { n:"SETUP" },
|
||||
/*::[*/0x0028/*::]*/: { n:"MARGINS" },
|
||||
/*::[*/0x0029/*::]*/: { n:"LABELFMT" },
|
||||
/*::[*/0x002A/*::]*/: { n:"TITLES" },
|
||||
/*::[*/0x002B/*::]*/: { n:"SHEETJS" },
|
||||
/*::[*/0x002D/*::]*/: { n:"GRAPH" },
|
||||
/*::[*/0x002E/*::]*/: { n:"NGRAPH" },
|
||||
/*::[*/0x002F/*::]*/: { n:"CALCCOUNT" },
|
||||
/*::[*/0x0030/*::]*/: { n:"UNFORMATTED" },
|
||||
/*::[*/0x0031/*::]*/: { n:"CURSORW12" },
|
||||
/*::[*/0x0032/*::]*/: { n:"WINDOW" },
|
||||
/*::[*/0x0033/*::]*/: { n:"STRING", f:parse_STRING },
|
||||
/*::[*/0x0037/*::]*/: { n:"PASSWORD" },
|
||||
/*::[*/0x0038/*::]*/: { n:"LOCKED" },
|
||||
/*::[*/0x003C/*::]*/: { n:"QUERY" },
|
||||
/*::[*/0x003D/*::]*/: { n:"QUERYNAME" },
|
||||
/*::[*/0x003E/*::]*/: { n:"PRINT" },
|
||||
/*::[*/0x003F/*::]*/: { n:"PRINTNAME" },
|
||||
/*::[*/0x0040/*::]*/: { n:"GRAPH2" },
|
||||
/*::[*/0x0041/*::]*/: { n:"GRAPHNAME" },
|
||||
/*::[*/0x0042/*::]*/: { n:"ZOOM" },
|
||||
/*::[*/0x0043/*::]*/: { n:"SYMSPLIT" },
|
||||
/*::[*/0x0044/*::]*/: { n:"NSROWS" },
|
||||
/*::[*/0x0045/*::]*/: { n:"NSCOLS" },
|
||||
/*::[*/0x0046/*::]*/: { n:"RULER" },
|
||||
/*::[*/0x0047/*::]*/: { n:"NNAME" },
|
||||
/*::[*/0x0048/*::]*/: { n:"ACOMM" },
|
||||
/*::[*/0x0049/*::]*/: { n:"AMACRO" },
|
||||
/*::[*/0x004A/*::]*/: { n:"PARSE" },
|
||||
/*::[*/0x0066/*::]*/: { n:"PRANGES??" },
|
||||
/*::[*/0x0067/*::]*/: { n:"RRANGES??" },
|
||||
/*::[*/0x0068/*::]*/: { n:"FNAME??" },
|
||||
/*::[*/0x0069/*::]*/: { n:"MRANGES??" },
|
||||
/*::[*/0x00CC/*::]*/: { n:"SHEETNAMECS", f:parse_SHEETNAMECS },
|
||||
/*::[*/0x00DE/*::]*/: { n:"SHEETNAMELP", f:parse_SHEETNAMELP },
|
||||
/*::[*/0x00FF/*::]*/: { n:"BOF", f:parseuint16 },
|
||||
/*::[*/0xFFFF/*::]*/: { n:"" }
|
||||
0x0000: { n:"BOF", f:parseuint16 },
|
||||
0x0001: { n:"EOF" },
|
||||
0x0002: { n:"CALCMODE" },
|
||||
0x0003: { n:"CALCORDER" },
|
||||
0x0004: { n:"SPLIT" },
|
||||
0x0005: { n:"SYNC" },
|
||||
0x0006: { n:"RANGE", f:parse_RANGE },
|
||||
0x0007: { n:"WINDOW1" },
|
||||
0x0008: { n:"COLW1" },
|
||||
0x0009: { n:"WINTWO" },
|
||||
0x000A: { n:"COLW2" },
|
||||
0x000B: { n:"NAME" },
|
||||
0x000C: { n:"BLANK" },
|
||||
0x000D: { n:"INTEGER", f:parse_INTEGER },
|
||||
0x000E: { n:"NUMBER", f:parse_NUMBER },
|
||||
0x000F: { n:"LABEL", f:parse_LABEL },
|
||||
0x0010: { n:"FORMULA", f:parse_FORMULA },
|
||||
0x0018: { n:"TABLE" },
|
||||
0x0019: { n:"ORANGE" },
|
||||
0x001A: { n:"PRANGE" },
|
||||
0x001B: { n:"SRANGE" },
|
||||
0x001C: { n:"FRANGE" },
|
||||
0x001D: { n:"KRANGE1" },
|
||||
0x0020: { n:"HRANGE" },
|
||||
0x0023: { n:"KRANGE2" },
|
||||
0x0024: { n:"PROTEC" },
|
||||
0x0025: { n:"FOOTER" },
|
||||
0x0026: { n:"HEADER" },
|
||||
0x0027: { n:"SETUP" },
|
||||
0x0028: { n:"MARGINS" },
|
||||
0x0029: { n:"LABELFMT" },
|
||||
0x002A: { n:"TITLES" },
|
||||
0x002B: { n:"SHEETJS" },
|
||||
0x002D: { n:"GRAPH" },
|
||||
0x002E: { n:"NGRAPH" },
|
||||
0x002F: { n:"CALCCOUNT" },
|
||||
0x0030: { n:"UNFORMATTED" },
|
||||
0x0031: { n:"CURSORW12" },
|
||||
0x0032: { n:"WINDOW" },
|
||||
0x0033: { n:"STRING", f:parse_STRING },
|
||||
0x0037: { n:"PASSWORD" },
|
||||
0x0038: { n:"LOCKED" },
|
||||
0x003C: { n:"QUERY" },
|
||||
0x003D: { n:"QUERYNAME" },
|
||||
0x003E: { n:"PRINT" },
|
||||
0x003F: { n:"PRINTNAME" },
|
||||
0x0040: { n:"GRAPH2" },
|
||||
0x0041: { n:"GRAPHNAME" },
|
||||
0x0042: { n:"ZOOM" },
|
||||
0x0043: { n:"SYMSPLIT" },
|
||||
0x0044: { n:"NSROWS" },
|
||||
0x0045: { n:"NSCOLS" },
|
||||
0x0046: { n:"RULER" },
|
||||
0x0047: { n:"NNAME" },
|
||||
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:"" }
|
||||
};
|
||||
|
||||
var WK3Enum = {
|
||||
/*::[*/0x0000/*::]*/: { n:"BOF" },
|
||||
/*::[*/0x0001/*::]*/: { n:"EOF" },
|
||||
/*::[*/0x0002/*::]*/: { n:"PASSWORD" },
|
||||
/*::[*/0x0003/*::]*/: { n:"CALCSET" },
|
||||
/*::[*/0x0004/*::]*/: { n:"WINDOWSET" },
|
||||
/*::[*/0x0005/*::]*/: { n:"SHEETCELLPTR" },
|
||||
/*::[*/0x0006/*::]*/: { n:"SHEETLAYOUT" },
|
||||
/*::[*/0x0007/*::]*/: { n:"COLUMNWIDTH" },
|
||||
/*::[*/0x0008/*::]*/: { n:"HIDDENCOLUMN" },
|
||||
/*::[*/0x0009/*::]*/: { n:"USERRANGE" },
|
||||
/*::[*/0x000A/*::]*/: { n:"SYSTEMRANGE" },
|
||||
/*::[*/0x000B/*::]*/: { n:"ZEROFORCE" },
|
||||
/*::[*/0x000C/*::]*/: { n:"SORTKEYDIR" },
|
||||
/*::[*/0x000D/*::]*/: { n:"FILESEAL" },
|
||||
/*::[*/0x000E/*::]*/: { n:"DATAFILLNUMS" },
|
||||
/*::[*/0x000F/*::]*/: { n:"PRINTMAIN" },
|
||||
/*::[*/0x0010/*::]*/: { n:"PRINTSTRING" },
|
||||
/*::[*/0x0011/*::]*/: { n:"GRAPHMAIN" },
|
||||
/*::[*/0x0012/*::]*/: { n:"GRAPHSTRING" },
|
||||
/*::[*/0x0013/*::]*/: { n:"??" },
|
||||
/*::[*/0x0014/*::]*/: { n:"ERRCELL" },
|
||||
/*::[*/0x0015/*::]*/: { n:"NACELL" },
|
||||
/*::[*/0x0016/*::]*/: { n:"LABEL16", f:parse_LABEL_16},
|
||||
/*::[*/0x0017/*::]*/: { n:"NUMBER17", f:parse_NUMBER_17 },
|
||||
/*::[*/0x0018/*::]*/: { n:"NUMBER18", f:parse_NUMBER_18 },
|
||||
/*::[*/0x0019/*::]*/: { n:"FORMULA19", f:parse_FORMULA_19},
|
||||
/*::[*/0x001A/*::]*/: { n:"FORMULA1A" },
|
||||
/*::[*/0x001B/*::]*/: { n:"XFORMAT", f:parse_XFORMAT },
|
||||
/*::[*/0x001C/*::]*/: { n:"DTLABELMISC" },
|
||||
/*::[*/0x001D/*::]*/: { n:"DTLABELCELL" },
|
||||
/*::[*/0x001E/*::]*/: { n:"GRAPHWINDOW" },
|
||||
/*::[*/0x001F/*::]*/: { n:"CPA" },
|
||||
/*::[*/0x0020/*::]*/: { n:"LPLAUTO" },
|
||||
/*::[*/0x0021/*::]*/: { n:"QUERY" },
|
||||
/*::[*/0x0022/*::]*/: { n:"HIDDENSHEET" },
|
||||
/*::[*/0x0023/*::]*/: { n:"??" },
|
||||
/*::[*/0x0025/*::]*/: { n:"NUMBER25", f:parse_NUMBER_25 },
|
||||
/*::[*/0x0026/*::]*/: { n:"??" },
|
||||
/*::[*/0x0027/*::]*/: { n:"NUMBER27", f:parse_NUMBER_27 },
|
||||
/*::[*/0x0028/*::]*/: { n:"FORMULA28", f:parse_FORMULA_28 },
|
||||
/*::[*/0x008E/*::]*/: { n:"??" },
|
||||
/*::[*/0x0093/*::]*/: { n:"??" },
|
||||
/*::[*/0x0096/*::]*/: { n:"??" },
|
||||
/*::[*/0x0097/*::]*/: { n:"??" },
|
||||
/*::[*/0x0098/*::]*/: { n:"??" },
|
||||
/*::[*/0x0099/*::]*/: { n:"??" },
|
||||
/*::[*/0x009A/*::]*/: { n:"??" },
|
||||
/*::[*/0x009B/*::]*/: { n:"??" },
|
||||
/*::[*/0x009C/*::]*/: { n:"??" },
|
||||
/*::[*/0x00A3/*::]*/: { n:"??" },
|
||||
/*::[*/0x00AE/*::]*/: { n:"??" },
|
||||
/*::[*/0x00AF/*::]*/: { n:"??" },
|
||||
/*::[*/0x00B0/*::]*/: { n:"??" },
|
||||
/*::[*/0x00B1/*::]*/: { n:"??" },
|
||||
/*::[*/0x00B8/*::]*/: { n:"??" },
|
||||
/*::[*/0x00B9/*::]*/: { n:"??" },
|
||||
/*::[*/0x00BA/*::]*/: { n:"??" },
|
||||
/*::[*/0x00BB/*::]*/: { n:"??" },
|
||||
/*::[*/0x00BC/*::]*/: { n:"??" },
|
||||
/*::[*/0x00C3/*::]*/: { n:"??" },
|
||||
/*::[*/0x00C9/*::]*/: { n:"??" },
|
||||
/*::[*/0x00CC/*::]*/: { n:"SHEETNAMECS", f:parse_SHEETNAMECS },
|
||||
/*::[*/0x00CD/*::]*/: { n:"??" },
|
||||
/*::[*/0x00CE/*::]*/: { n:"??" },
|
||||
/*::[*/0x00CF/*::]*/: { n:"??" },
|
||||
/*::[*/0x00D0/*::]*/: { n:"??" },
|
||||
/*::[*/0x0100/*::]*/: { n:"??" },
|
||||
/*::[*/0x0103/*::]*/: { n:"??" },
|
||||
/*::[*/0x0104/*::]*/: { n:"??" },
|
||||
/*::[*/0x0105/*::]*/: { n:"??" },
|
||||
/*::[*/0x0106/*::]*/: { n:"??" },
|
||||
/*::[*/0x0107/*::]*/: { n:"??" },
|
||||
/*::[*/0x0109/*::]*/: { n:"??" },
|
||||
/*::[*/0x010A/*::]*/: { n:"??" },
|
||||
/*::[*/0x010B/*::]*/: { n:"??" },
|
||||
/*::[*/0x010C/*::]*/: { n:"??" },
|
||||
/*::[*/0x010E/*::]*/: { n:"??" },
|
||||
/*::[*/0x010F/*::]*/: { n:"??" },
|
||||
/*::[*/0x0180/*::]*/: { n:"??" },
|
||||
/*::[*/0x0185/*::]*/: { n:"??" },
|
||||
/*::[*/0x0186/*::]*/: { n:"??" },
|
||||
/*::[*/0x0189/*::]*/: { n:"??" },
|
||||
/*::[*/0x018C/*::]*/: { n:"??" },
|
||||
/*::[*/0x0200/*::]*/: { n:"??" },
|
||||
/*::[*/0x0202/*::]*/: { n:"??" },
|
||||
/*::[*/0x0201/*::]*/: { n:"??" },
|
||||
/*::[*/0x0204/*::]*/: { n:"??" },
|
||||
/*::[*/0x0205/*::]*/: { n:"??" },
|
||||
/*::[*/0x0280/*::]*/: { n:"??" },
|
||||
/*::[*/0x0281/*::]*/: { n:"??" },
|
||||
/*::[*/0x0282/*::]*/: { n:"??" },
|
||||
/*::[*/0x0283/*::]*/: { n:"??" },
|
||||
/*::[*/0x0284/*::]*/: { n:"??" },
|
||||
/*::[*/0x0285/*::]*/: { n:"??" },
|
||||
/*::[*/0x0286/*::]*/: { n:"??" },
|
||||
/*::[*/0x0287/*::]*/: { n:"??" },
|
||||
/*::[*/0x0288/*::]*/: { n:"??" },
|
||||
/*::[*/0x0292/*::]*/: { n:"??" },
|
||||
/*::[*/0x0293/*::]*/: { n:"??" },
|
||||
/*::[*/0x0294/*::]*/: { n:"??" },
|
||||
/*::[*/0x0295/*::]*/: { n:"??" },
|
||||
/*::[*/0x0296/*::]*/: { n:"??" },
|
||||
/*::[*/0x0299/*::]*/: { n:"??" },
|
||||
/*::[*/0x029A/*::]*/: { n:"??" },
|
||||
/*::[*/0x0300/*::]*/: { n:"??" },
|
||||
/*::[*/0x0304/*::]*/: { n:"??" },
|
||||
/*::[*/0x0601/*::]*/: { n:"SHEETINFOQP", f:parse_SHEETINFOQP },
|
||||
/*::[*/0x0640/*::]*/: { n:"??" },
|
||||
/*::[*/0x0642/*::]*/: { n:"??" },
|
||||
/*::[*/0x0701/*::]*/: { n:"??" },
|
||||
/*::[*/0x0702/*::]*/: { n:"??" },
|
||||
/*::[*/0x0703/*::]*/: { n:"??" },
|
||||
/*::[*/0x0704/*::]*/: { n:"??" },
|
||||
/*::[*/0x0780/*::]*/: { n:"??" },
|
||||
/*::[*/0x0800/*::]*/: { n:"??" },
|
||||
/*::[*/0x0801/*::]*/: { n:"??" },
|
||||
/*::[*/0x0804/*::]*/: { n:"??" },
|
||||
/*::[*/0x0A80/*::]*/: { n:"??" },
|
||||
/*::[*/0x2AF6/*::]*/: { n:"??" },
|
||||
/*::[*/0x3231/*::]*/: { n:"??" },
|
||||
/*::[*/0x6E49/*::]*/: { n:"??" },
|
||||
/*::[*/0x6F44/*::]*/: { n:"??" },
|
||||
/*::[*/0xFFFF/*::]*/: { n:"" }
|
||||
0x0000: { n:"BOF" },
|
||||
0x0001: { n:"EOF" },
|
||||
0x0002: { n:"PASSWORD" },
|
||||
0x0003: { n:"CALCSET" },
|
||||
0x0004: { n:"WINDOWSET" },
|
||||
0x0005: { n:"SHEETCELLPTR" },
|
||||
0x0006: { n:"SHEETLAYOUT" },
|
||||
0x0007: { n:"COLUMNWIDTH" },
|
||||
0x0008: { n:"HIDDENCOLUMN" },
|
||||
0x0009: { n:"USERRANGE" },
|
||||
0x000A: { n:"SYSTEMRANGE" },
|
||||
0x000B: { n:"ZEROFORCE" },
|
||||
0x000C: { n:"SORTKEYDIR" },
|
||||
0x000D: { n:"FILESEAL" },
|
||||
0x000E: { n:"DATAFILLNUMS" },
|
||||
0x000F: { n:"PRINTMAIN" },
|
||||
0x0010: { n:"PRINTSTRING" },
|
||||
0x0011: { n:"GRAPHMAIN" },
|
||||
0x0012: { n:"GRAPHSTRING" },
|
||||
0x0013: { n:"??" },
|
||||
0x0014: { n:"ERRCELL" },
|
||||
0x0015: { n:"NACELL" },
|
||||
0x0016: { n:"LABEL16", f:parse_LABEL_16},
|
||||
0x0017: { n:"NUMBER17", f:parse_NUMBER_17 },
|
||||
0x0018: { n:"NUMBER18", f:parse_NUMBER_18 },
|
||||
0x0019: { n:"FORMULA19", f:parse_FORMULA_19},
|
||||
0x001A: { n:"FORMULA1A" },
|
||||
0x001B: { n:"XFORMAT", f:parse_XFORMAT },
|
||||
0x001C: { n:"DTLABELMISC" },
|
||||
0x001D: { n:"DTLABELCELL" },
|
||||
0x001E: { n:"GRAPHWINDOW" },
|
||||
0x001F: { n:"CPA" },
|
||||
0x0020: { n:"LPLAUTO" },
|
||||
0x0021: { n:"QUERY" },
|
||||
0x0022: { n:"HIDDENSHEET" },
|
||||
0x0023: { n:"??" },
|
||||
0x0025: { n:"NUMBER25", f:parse_NUMBER_25 },
|
||||
0x0026: { n:"??" },
|
||||
0x0027: { n:"NUMBER27", f:parse_NUMBER_27 },
|
||||
0x0028: { n:"FORMULA28", f:parse_FORMULA_28 },
|
||||
0x008E: { n:"??" },
|
||||
0x0093: { n:"??" },
|
||||
0x0096: { n:"??" },
|
||||
0x0097: { n:"??" },
|
||||
0x0098: { n:"??" },
|
||||
0x0099: { n:"??" },
|
||||
0x009A: { n:"??" },
|
||||
0x009B: { n:"??" },
|
||||
0x009C: { n:"??" },
|
||||
0x00A3: { n:"??" },
|
||||
0x00AE: { n:"??" },
|
||||
0x00AF: { n:"??" },
|
||||
0x00B0: { n:"??" },
|
||||
0x00B1: { n:"??" },
|
||||
0x00B8: { n:"??" },
|
||||
0x00B9: { n:"??" },
|
||||
0x00BA: { n:"??" },
|
||||
0x00BB: { n:"??" },
|
||||
0x00BC: { n:"??" },
|
||||
0x00C3: { n:"??" },
|
||||
0x00C9: { n:"??" },
|
||||
0x00CC: { n:"SHEETNAMECS", f:parse_SHEETNAMECS },
|
||||
0x00CD: { n:"??" },
|
||||
0x00CE: { n:"??" },
|
||||
0x00CF: { n:"??" },
|
||||
0x00D0: { n:"??" },
|
||||
0x0100: { n:"??" },
|
||||
0x0103: { n:"??" },
|
||||
0x0104: { n:"??" },
|
||||
0x0105: { n:"??" },
|
||||
0x0106: { n:"??" },
|
||||
0x0107: { n:"??" },
|
||||
0x0109: { n:"??" },
|
||||
0x010A: { n:"??" },
|
||||
0x010B: { n:"??" },
|
||||
0x010C: { n:"??" },
|
||||
0x010E: { n:"??" },
|
||||
0x010F: { n:"??" },
|
||||
0x0180: { n:"??" },
|
||||
0x0185: { n:"??" },
|
||||
0x0186: { n:"??" },
|
||||
0x0189: { n:"??" },
|
||||
0x018C: { n:"??" },
|
||||
0x0200: { n:"??" },
|
||||
0x0202: { n:"??" },
|
||||
0x0201: { n:"??" },
|
||||
0x0204: { n:"??" },
|
||||
0x0205: { n:"??" },
|
||||
0x0280: { n:"??" },
|
||||
0x0281: { n:"??" },
|
||||
0x0282: { n:"??" },
|
||||
0x0283: { n:"??" },
|
||||
0x0284: { n:"??" },
|
||||
0x0285: { n:"??" },
|
||||
0x0286: { n:"??" },
|
||||
0x0287: { n:"??" },
|
||||
0x0288: { n:"??" },
|
||||
0x0292: { n:"??" },
|
||||
0x0293: { n:"??" },
|
||||
0x0294: { n:"??" },
|
||||
0x0295: { n:"??" },
|
||||
0x0296: { n:"??" },
|
||||
0x0299: { n:"??" },
|
||||
0x029A: { n:"??" },
|
||||
0x0300: { n:"??" },
|
||||
0x0304: { n:"??" },
|
||||
0x0601: { n:"SHEETINFOQP", f:parse_SHEETINFOQP },
|
||||
0x0640: { n:"??" },
|
||||
0x0642: { n:"??" },
|
||||
0x0701: { n:"??" },
|
||||
0x0702: { n:"??" },
|
||||
0x0703: { n:"??" },
|
||||
0x0704: { n:"??" },
|
||||
0x0780: { n:"??" },
|
||||
0x0800: { n:"??" },
|
||||
0x0801: { n:"??" },
|
||||
0x0804: { n:"??" },
|
||||
0x0A80: { n:"??" },
|
||||
0x2AF6: { n:"??" },
|
||||
0x3231: { n:"??" },
|
||||
0x6E49: { n:"??" },
|
||||
0x6F44: { n:"??" },
|
||||
0xFFFF: { n:"" }
|
||||
};
|
||||
|
||||
/* TODO: fill out and verify this table across QP versions */
|
||||
var QPWNFTable = {
|
||||
0x05: "dd-mmm-yy",
|
||||
0x06: "dd-mmm",
|
||||
0x07: "mmm-yy",
|
||||
0x08: "mm/dd/yy", // Long Date Intl
|
||||
0x0A: "hh:mm:ss AM/PM",
|
||||
0x0B: "hh:mm AM/PM",
|
||||
0x0E: "dd-mmm-yyyy",
|
||||
0x0F: "mmm-yyyy",
|
||||
|
||||
/* It is suspected that the the low nybble specifies decimal places */
|
||||
0x0022: "0.00",
|
||||
0x0032: "0.00;[Red]0.00",
|
||||
0x0042: "0.00;\(0.00\)",
|
||||
0x0052: "0.00;[Red]\(0.00\)",
|
||||
0x00A2: '"$"#,##0.00;\\("$"#,##0.00\\)',
|
||||
0x0120: '0%',
|
||||
0x0130: '0E+00',
|
||||
0x0140: '# ?/?'
|
||||
};
|
||||
|
||||
function parse_qpw_str(p) {
|
||||
var cch = p.read_shift(2);
|
||||
var flags = p.read_shift(1);
|
||||
/* TODO: find examples with nonzero flags */
|
||||
if(flags != 0) throw "unsupported QPW string type " + flags.toString(16);
|
||||
return p.read_shift(cch, "sbcs-cont");
|
||||
}
|
||||
|
||||
/* QPW uses a different set of record types */
|
||||
function qpw_to_workbook_buf(d, opts)/*:Workbook*/ {
|
||||
prep_blob(d, 0);
|
||||
@ -924,6 +1007,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 +1018,22 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
break;
|
||||
case 0x02: /* EOF */ break outer;
|
||||
|
||||
case 0x08: /* NF */ break; // TODO: this is tied to custom number formats
|
||||
|
||||
case 0x0A: /* FORMATS */ {
|
||||
var fcnt = p.read_shift(4);
|
||||
var step = ((p.length - p.l)/ fcnt)|0;
|
||||
for(var ifmt = 0; ifmt < fcnt; ++ifmt) {
|
||||
var end = p.l + step;
|
||||
var fmt = {};
|
||||
p.l += 2;
|
||||
fmt.numFmtId = p.read_shift(2);
|
||||
if(QPWNFTable[fmt.numFmtId]) fmt.z = QPWNFTable[fmt.numFmtId];
|
||||
p.l = end;
|
||||
FMTS.push(fmt);
|
||||
}
|
||||
} break;
|
||||
|
||||
/* TODO: The behavior here should be consistent with Numbers: QP Notebook ~ .TN.SheetArchive, QP Sheet ~ .TST.TableModelArchive */
|
||||
case 0x0401: /* BON */ break;
|
||||
case 0x0402: /* EON */ /* TODO: backfill missing sheets based on BON cnt */ break;
|
||||
@ -996,18 +1096,25 @@ 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;
|
||||
case 8:
|
||||
cell = { t: "n", v: p.read_shift(8, 'f') };
|
||||
p.l += 2; /* cell.f = formulae[p.read_shift(4)]; */ p.l += 4;
|
||||
if(isNaN(cell.v)) cell = { t: "e", v: 0x0F }; // #VALUE!
|
||||
break;
|
||||
default: throw "Unrecognized QPW cell type " + (flags & 0x1F);
|
||||
}
|
||||
if(fmtidx != -1 && (FMTS[fmtidx - 1]||{}).z) cell.z = FMTS[fmtidx-1].z;
|
||||
var delta = 0;
|
||||
if(flags & 0x20) switch(flags & 0x1F) {
|
||||
case 2: delta = p.read_shift(2); break;
|
||||
@ -1016,10 +1123,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 +1145,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] = [];
|
||||
@ -1045,6 +1157,17 @@ var WK_ = /*#__PURE__*/(function() {
|
||||
}
|
||||
} break;
|
||||
|
||||
case 0x0C02: { /* String (result of string formula expression) */
|
||||
C = p.read_shift(2);
|
||||
R = p.read_shift(4);
|
||||
var str = parse_qpw_str(p);
|
||||
/* TODO: QP10 record has an additional unknown character after the string */
|
||||
if(s["!data"] != null) {
|
||||
if(!s["!data"][R]) s["!data"][R] = [];
|
||||
s["!data"][R][C] = { t:"s", v:str };
|
||||
} else s[encode_col(C) + encode_row(R)] = { t:"s", v:str };
|
||||
} break;
|
||||
|
||||
default: break;
|
||||
}
|
||||
d.l += length;
|
||||
|
@ -4,7 +4,7 @@ function parse_rpr(rpr) {
|
||||
var pass = false;
|
||||
if(m) for(;i!=m.length; ++i) {
|
||||
var y = parsexmltag(m[i]);
|
||||
switch(y[0].replace(/\w*:/g,"")) {
|
||||
switch(y[0].replace(/<\w*:/g,"<")) {
|
||||
/* 18.8.12 condense CT_BooleanProperty */
|
||||
/* ** not required . */
|
||||
case '<condense': break;
|
||||
@ -107,15 +107,14 @@ function parse_rpr(rpr) {
|
||||
}
|
||||
|
||||
var parse_rs = /*#__PURE__*/(function() {
|
||||
var tregex = matchtag("t"), rpregex = matchtag("rPr");
|
||||
/* 18.4.4 r CT_RElt */
|
||||
function parse_r(r) {
|
||||
/* 18.4.12 t ST_Xstring */
|
||||
var t = r.match(tregex)/*, cp = 65001*/;
|
||||
var t = str_match_xml_ns(r, "t")/*, cp = 65001*/;
|
||||
if(!t) return {t:"s", v:""};
|
||||
|
||||
var o/*:Cell*/ = ({t:'s', v:unescapexml(t[1])}/*:any*/);
|
||||
var rpr = r.match(rpregex);
|
||||
var rpr = str_match_xml_ns(r, "rPr");
|
||||
if(rpr) o.s = parse_rpr(rpr[1]);
|
||||
return o;
|
||||
}
|
||||
@ -168,8 +167,7 @@ var rs_to_html = /*#__PURE__*/(function parse_rs_factory() {
|
||||
})();
|
||||
|
||||
/* 18.4.8 si CT_Rst */
|
||||
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r\b[^>]*>/;
|
||||
var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
|
||||
var sitregex = /<(?:\w+:)?t\b[^<>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r\b[^<>]*>/;
|
||||
function parse_si(x, opts) {
|
||||
var html = opts ? opts.cellHTML : true;
|
||||
var z = {};
|
||||
@ -185,7 +183,7 @@ function parse_si(x, opts) {
|
||||
/* 18.4.4 r CT_RElt (Rich Text Run) */
|
||||
else if((/*y = */x.match(sirregex))) {
|
||||
z.r = utf8read(x);
|
||||
z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")), true);
|
||||
z.t = unescapexml(utf8read((str_remove_xml_ns_g(x, "rPh").match(sitregex)||[]).join("").replace(tagregex,"")), true);
|
||||
if(html) z.h = rs_to_html(parse_rs(z.r));
|
||||
}
|
||||
/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
|
||||
@ -194,21 +192,20 @@ function parse_si(x, opts) {
|
||||
}
|
||||
|
||||
/* 18.4 Shared String Table */
|
||||
var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
|
||||
var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
|
||||
var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
|
||||
function parse_sst_xml(data/*:string*/, opts)/*:SST*/ {
|
||||
var s/*:SST*/ = ([]/*:any*/), ss = "";
|
||||
if(!data) return s;
|
||||
/* 18.4.9 sst CT_Sst */
|
||||
var sst = data.match(sstr0);
|
||||
var sst = str_match_xml_ns(data, "sst");
|
||||
if(sst) {
|
||||
ss = sst[2].replace(sstr1,"").split(sstr2);
|
||||
ss = sst[1].replace(sstr1,"").split(sstr2);
|
||||
for(var i = 0; i != ss.length; ++i) {
|
||||
var o = parse_si(ss[i].trim(), opts);
|
||||
if(o != null) s[s.length] = o;
|
||||
}
|
||||
sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
|
||||
sst = parsexmltag(sst[0].slice(0, sst[0].indexOf(">"))); s.Count = sst.count; s.Unique = sst.uniqueCount;
|
||||
}
|
||||
return s;
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ function rtf_to_sheet_str(str, opts) {
|
||||
var dense = o.dense;
|
||||
if (dense)
|
||||
ws["!data"] = [];
|
||||
var rows = str.match(/\\trowd[\s\S]*?\\row\b/g);
|
||||
var rows = str_match_ng(str, "\\trowd", "\\row");
|
||||
if (!rows)
|
||||
throw new Error("RTF missing table");
|
||||
var range = { s: { c: 0, r: 0 }, e: { c: 0, r: rows.length - 1 } };
|
||||
|
@ -3,7 +3,7 @@ function parse_borders(t, styles, themes, opts) {
|
||||
styles.Borders = [];
|
||||
var border = {};
|
||||
var pass = false;
|
||||
(t[0].match(tagregex)||[]).forEach(function(x) {
|
||||
(t.match(tagregex)||[]).forEach(function(x) {
|
||||
var y = parsexmltag(x);
|
||||
switch(strip_ns(y[0])) {
|
||||
case '<borders': case '<borders>': case '</borders>': break;
|
||||
@ -78,7 +78,7 @@ function parse_fills(t, styles, themes, opts) {
|
||||
styles.Fills = [];
|
||||
var fill = {};
|
||||
var pass = false;
|
||||
(t[0].match(tagregex)||[]).forEach(function(x) {
|
||||
(t.match(tagregex)||[]).forEach(function(x) {
|
||||
var y = parsexmltag(x);
|
||||
switch(strip_ns(y[0])) {
|
||||
case '<fills': case '<fills>': case '</fills>': break;
|
||||
@ -144,7 +144,7 @@ function parse_fonts(t, styles, themes, opts) {
|
||||
styles.Fonts = [];
|
||||
var font = {};
|
||||
var pass = false;
|
||||
(t[0].match(tagregex)||[]).forEach(function(x) {
|
||||
(t.match(tagregex)||[]).forEach(function(x) {
|
||||
var y = parsexmltag(x);
|
||||
switch(strip_ns(y[0])) {
|
||||
case '<fonts': case '<fonts>': case '</fonts>': break;
|
||||
@ -264,7 +264,7 @@ function parse_numFmts(t, styles, opts) {
|
||||
styles.NumberFmt = [];
|
||||
var k/*Array<number>*/ = (keys(table_fmt)/*:any*/);
|
||||
for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = table_fmt[k[i]];
|
||||
var m = t[0].match(tagregex);
|
||||
var m = t.match(tagregex);
|
||||
if(!m) return;
|
||||
for(i=0; i < m.length; ++i) {
|
||||
var y = parsexmltag(m[i]);
|
||||
@ -305,13 +305,13 @@ function parse_cellXfs(t, styles, opts) {
|
||||
styles.CellXf = [];
|
||||
var xf;
|
||||
var pass = false;
|
||||
(t[0].match(tagregex)||[]).forEach(function(x) {
|
||||
(t.match(tagregex)||[]).forEach(function(x) {
|
||||
var y = parsexmltag(x), i = 0;
|
||||
switch(strip_ns(y[0])) {
|
||||
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
|
||||
|
||||
/* 18.8.45 xf CT_Xf */
|
||||
case '<xf': case '<xf/>':
|
||||
case '<xf': case '<xf/>': case '<xf>':
|
||||
xf = y;
|
||||
delete xf[0];
|
||||
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
|
||||
@ -325,7 +325,7 @@ function parse_cellXfs(t, styles, opts) {
|
||||
case '</xf>': break;
|
||||
|
||||
/* 18.8.1 alignment CT_CellAlignment */
|
||||
case '<alignment': case '<alignment/>':
|
||||
case '<alignment': case '<alignment/>': case '<alignment>':
|
||||
var alignment = {};
|
||||
if(y.vertical) alignment.vertical = y.vertical;
|
||||
if(y.horizontal) alignment.horizontal = y.horizontal;
|
||||
@ -337,12 +337,12 @@ function parse_cellXfs(t, styles, opts) {
|
||||
case '</alignment>': break;
|
||||
|
||||
/* 18.8.33 protection CT_CellProtection */
|
||||
case '<protection':
|
||||
case '<protection': case '<protection>':
|
||||
break;
|
||||
case '</protection>': case '<protection/>': break;
|
||||
|
||||
/* note: sometimes mc:AlternateContent appears bare */
|
||||
case '<AlternateContent': pass = true; break;
|
||||
case '<AlternateContent': case '<AlternateContent>': pass = true; break;
|
||||
case '</AlternateContent>': pass = false; break;
|
||||
|
||||
/* 18.2.10 extLst CT_ExtensionList ? */
|
||||
@ -370,36 +370,31 @@ function write_cellXfs(cellXfs)/*:string*/ {
|
||||
|
||||
/* 18.8 Styles CT_Stylesheet*/
|
||||
var parse_sty_xml= /*#__PURE__*/(function make_pstyx() {
|
||||
var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
|
||||
var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
|
||||
var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
|
||||
var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
|
||||
var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
|
||||
|
||||
return function parse_sty_xml(data, themes, opts) {
|
||||
var styles = {};
|
||||
if(!data) return styles;
|
||||
data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
|
||||
data = remove_doctype(str_remove_ng(data, "<!--", "-->"));
|
||||
/* 18.8.39 styleSheet CT_Stylesheet */
|
||||
var t;
|
||||
|
||||
/* 18.8.31 numFmts CT_NumFmts ? */
|
||||
if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
|
||||
if((t=str_match_xml_ns(data, "numFmts"))) parse_numFmts(t[0], styles, opts);
|
||||
|
||||
/* 18.8.23 fonts CT_Fonts ? */
|
||||
if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
|
||||
if((t=str_match_xml_ns(data, "fonts"))) parse_fonts(t[0], styles, themes, opts);
|
||||
|
||||
/* 18.8.21 fills CT_Fills ? */
|
||||
if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
|
||||
if((t=str_match_xml_ns(data, "fills"))) parse_fills(t[0], styles, themes, opts);
|
||||
|
||||
/* 18.8.5 borders CT_Borders ? */
|
||||
if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
|
||||
if((t=str_match_xml_ns(data, "borders"))) parse_borders(t[0], styles, themes, opts);
|
||||
|
||||
/* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
|
||||
/* 18.8.8 cellStyles CT_CellStyles ? */
|
||||
|
||||
/* 18.8.10 cellXfs CT_CellXfs ? */
|
||||
if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
|
||||
if((t=str_match_xml_ns(data, "cellXfs"))) parse_cellXfs(t[0], styles, opts);
|
||||
|
||||
/* 18.8.15 dxfs CT_Dxfs ? */
|
||||
/* 18.8.42 tableStyles CT_TableStyles ? */
|
||||
|
@ -18,10 +18,12 @@ function parse_clrScheme(t, themes, opts) {
|
||||
/* 20.1.2.3.32 srgbClr CT_SRgbColor */
|
||||
case '<a:srgbClr':
|
||||
color.rgb = y.val; break;
|
||||
case '</a:srgbClr>': break;
|
||||
|
||||
/* 20.1.2.3.33 sysClr CT_SystemColor */
|
||||
case '<a:sysClr':
|
||||
color.rgb = y.lastClr; break;
|
||||
case '</a:sysClr>': break;
|
||||
|
||||
/* 20.1.4.1.1 accent1 (Accent 1) */
|
||||
/* 20.1.4.1.2 accent2 (Accent 2) */
|
||||
@ -35,8 +37,10 @@ function parse_clrScheme(t, themes, opts) {
|
||||
/* 20.1.4.1.19 hlink (Hyperlink) */
|
||||
/* 20.1.4.1.22 lt1 (Light 1) */
|
||||
/* 20.1.4.1.23 lt2 (Light 2) */
|
||||
case '<a:dk1>': case '</a:dk1>':
|
||||
case '<a:lt1>': case '</a:lt1>':
|
||||
case '</a:dk1>':
|
||||
case '</a:lt1>':
|
||||
case '<a:dk1>':
|
||||
case '<a:lt1>':
|
||||
case '<a:dk2>': case '</a:dk2>':
|
||||
case '<a:lt2>': case '</a:lt2>':
|
||||
case '<a:accent1>': case '</a:accent1>':
|
||||
@ -66,30 +70,24 @@ function parse_fontScheme(/*::t, themes, opts*/) { }
|
||||
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
|
||||
function parse_fmtScheme(/*::t, themes, opts*/) { }
|
||||
|
||||
var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
|
||||
var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
|
||||
var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
|
||||
|
||||
/* 20.1.6.10 themeElements CT_BaseStyles */
|
||||
function parse_themeElements(data, themes, opts) {
|
||||
themes.themeElements = {};
|
||||
|
||||
var t;
|
||||
|
||||
[
|
||||
/* clrScheme CT_ColorScheme */
|
||||
['clrScheme', clrsregex, parse_clrScheme],
|
||||
/* fontScheme CT_FontScheme */
|
||||
['fontScheme', fntsregex, parse_fontScheme],
|
||||
/* fmtScheme CT_StyleMatrix */
|
||||
['fmtScheme', fmtsregex, parse_fmtScheme]
|
||||
].forEach(function(m) {
|
||||
if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
|
||||
m[2](t, themes, opts);
|
||||
});
|
||||
}
|
||||
/* clrScheme CT_ColorScheme */
|
||||
if(!(t=str_match_xml(data, "a:clrScheme"))) throw new Error('clrScheme not found in themeElements');
|
||||
parse_clrScheme(t, themes, opts);
|
||||
|
||||
var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
|
||||
/* fontScheme CT_FontScheme */
|
||||
if(!(t=str_match_xml(data, "a:fontScheme"))) throw new Error('fontScheme not found in themeElements');
|
||||
parse_fontScheme(t, themes, opts);
|
||||
|
||||
/* fmtScheme CT_StyleMatrix */
|
||||
if(!(t=str_match_xml(data, "a:fmtScheme"))) throw new Error('fmtScheme not found in themeElements');
|
||||
parse_fmtScheme(t, themes, opts);
|
||||
}
|
||||
|
||||
/* 14.2.7 Theme Part */
|
||||
function parse_theme_xml(data/*:string*/, opts) {
|
||||
@ -100,7 +98,7 @@ function parse_theme_xml(data/*:string*/, opts) {
|
||||
var themes = {};
|
||||
|
||||
/* themeElements CT_BaseStyles */
|
||||
if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
|
||||
if(!(t=str_match_xml(data, "a:themeElements"))) throw new Error('themeElements not found in theme');
|
||||
parse_themeElements(t[0], themes, opts);
|
||||
themes.raw = data;
|
||||
return themes;
|
||||
|
@ -13,7 +13,7 @@ function parse_drawing(data, rels/*:any*/) {
|
||||
the actual type is based on the URI of the graphicData
|
||||
TODO: handle embedded charts and other types of graphics
|
||||
*/
|
||||
var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
|
||||
var id = (data.match(/<c:chart [^<>]*r:id="([^<>"]*)"/)||["",""])[1];
|
||||
|
||||
return rels['!id'][id].Target;
|
||||
}
|
||||
|
@ -1,5 +1,42 @@
|
||||
/* L.5.5.2 SpreadsheetML Comments + VML Schema */
|
||||
function write_vml(rId/*:number*/, comments) {
|
||||
function parse_vml(data/*:string*/, sheet, comments) {
|
||||
var cidx = 0;
|
||||
(str_match_xml_ns_g(data, "shape")||[]).forEach(function(m) {
|
||||
var type = "";
|
||||
var hidden = true;
|
||||
var aidx = -1;
|
||||
var R = -1, C = -1;
|
||||
m.replace(tagregex, function(x/*:string*/, idx/*:number*/) {
|
||||
var y = parsexmltag(x);
|
||||
switch(strip_ns(y[0])) {
|
||||
case '<ClientData': if(y.ObjectType) type = y.ObjectType; break;
|
||||
|
||||
case '<Visible': case '<Visible/>': hidden = false; break;
|
||||
|
||||
case '<Row': case '<Row>': aidx = idx + x.length; break;
|
||||
case '</Row>': R = +m.slice(aidx, idx).trim(); break;
|
||||
|
||||
case '<Column': case '<Column>': aidx = idx + x.length; break;
|
||||
case '</Column>': C = +m.slice(aidx, idx).trim(); break;
|
||||
}
|
||||
return "";
|
||||
});
|
||||
switch(type) {
|
||||
case 'Note':
|
||||
var cell = ws_get_cell_stub(sheet, ((R>=0 && C>=0) ? encode_cell({r:R,c:C}) : comments[cidx].ref));
|
||||
if(cell.c) {
|
||||
cell.c.hidden = hidden;
|
||||
}
|
||||
++cidx;
|
||||
break;
|
||||
}
|
||||
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
/* comment boxes */
|
||||
function write_vml(rId/*:number*/, comments, ws) {
|
||||
var csize = [21600, 21600];
|
||||
/* L.5.2.1.2 Path Attribute */
|
||||
var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
|
||||
@ -21,7 +58,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";
|
||||
|
@ -4,22 +4,22 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array<RawComment>*/ {
|
||||
if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
|
||||
var authors/*:Array<string>*/ = [];
|
||||
var commentList/*:Array<RawComment>*/ = [];
|
||||
var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
|
||||
var authtag = str_match_xml_ns(data, "authors");
|
||||
if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
|
||||
if(x === "" || x.trim() === "") return;
|
||||
var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
|
||||
var a = x.match(/<(?:\w+:)?author[^<>]*>(.*)/);
|
||||
if(a) authors.push(a[1]);
|
||||
});
|
||||
var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
|
||||
var cmnttag = str_match_xml_ns(data, "commentList");
|
||||
if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
|
||||
if(x === "" || x.trim() === "") return;
|
||||
var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
|
||||
var cm = x.match(/<(?:\w+:)?comment[^<>]*>/);
|
||||
if(!cm) return;
|
||||
var y = parsexmltag(cm[0]);
|
||||
var comment/*:RawComment*/ = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/);
|
||||
var cell = decode_cell(y.ref);
|
||||
if(opts.sheetRows && opts.sheetRows <= cell.r) return;
|
||||
var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
|
||||
var textMatch = str_match_xml_ns(x, "text");
|
||||
var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
|
||||
comment.r = rt.r;
|
||||
if(rt.r == "<t></t>") rt.t = rt.h = "";
|
||||
@ -64,6 +64,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";
|
||||
|
@ -74,6 +74,10 @@ function write_comments_bin(data/*::, opts*/) {
|
||||
if(iauthor.indexOf(c.a) > -1) return;
|
||||
iauthor.push(c.a.slice(0,54));
|
||||
write_record(ba, 0x0278 /* BrtCommentAuthor */, write_BrtCommentAuthor(c.a));
|
||||
if(c.T && c.ID && iauthor.indexOf("tc=" + c.ID) == -1) {
|
||||
iauthor.push("tc=" + c.ID);
|
||||
write_record(ba, 0x0278 /* BrtCommentAuthor */, write_BrtCommentAuthor("tc=" + c.ID));
|
||||
}
|
||||
});
|
||||
});
|
||||
write_record(ba, 0x0277 /* BrtEndCommentAuthors */);
|
||||
@ -81,7 +85,11 @@ function write_comments_bin(data/*::, opts*/) {
|
||||
write_record(ba, 0x0279 /* BrtBeginCommentList */);
|
||||
data.forEach(function(comment) {
|
||||
comment[1].forEach(function(c) {
|
||||
c.iauthor = iauthor.indexOf(c.a);
|
||||
var _ia = -1;
|
||||
if(c.ID) _ia = iauthor.indexOf("tc=" + c.ID);
|
||||
if(_ia == -1 && comment[1][0].T && comment[1][0].ID) _ia = iauthor.indexOf("tc=" + comment[1][0].ID);
|
||||
if(_ia == -1) _ia = iauthor.indexOf(c.a);
|
||||
c.iauthor = _ia;
|
||||
var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
|
||||
write_record(ba, 0x027B /* BrtBeginComment */, write_BrtBeginComment([range, c]));
|
||||
if(c.t && c.t.length > 0) write_record(ba, 0x027D /* BrtCommentText */, write_BrtCommentText(c));
|
||||
|
@ -13,7 +13,7 @@ function fill_vba_xls(cfb, vba) {
|
||||
vba.FullPaths.forEach(function(p, i) {
|
||||
if (i == 0)
|
||||
return;
|
||||
var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
|
||||
var newpath = p.replace(/^[\/]*[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
|
||||
if (newpath.slice(-1) !== "/")
|
||||
CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
|
||||
});
|
||||
|
@ -23,7 +23,10 @@ var rc_to_a1 = /*#__PURE__*/(function(){
|
||||
};
|
||||
})();
|
||||
|
||||
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
|
||||
var crefregex = /(^|[^._A-Z0-9])(\$?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])(\$?)(\d{1,7})(?![_.\(A-Za-z0-9])/g;
|
||||
try {
|
||||
crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
|
||||
}catch(e){}
|
||||
var a1_to_rc = /*#__PURE__*/(function(){
|
||||
return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) {
|
||||
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
|
||||
|
196
bits/62_fxls.js
196
bits/62_fxls.js
@ -495,112 +495,112 @@ function parse_PtgAttrNoop(blob/*::, length, opts*/) {
|
||||
|
||||
/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
|
||||
var PtgTypes = {
|
||||
/*::[*/0x01/*::]*/: { n:'PtgExp', f:parse_PtgExp },
|
||||
/*::[*/0x02/*::]*/: { n:'PtgTbl', f:parse_PtgTbl },
|
||||
/*::[*/0x03/*::]*/: { n:'PtgAdd', f:parseread1 },
|
||||
/*::[*/0x04/*::]*/: { n:'PtgSub', f:parseread1 },
|
||||
/*::[*/0x05/*::]*/: { n:'PtgMul', f:parseread1 },
|
||||
/*::[*/0x06/*::]*/: { n:'PtgDiv', f:parseread1 },
|
||||
/*::[*/0x07/*::]*/: { n:'PtgPower', f:parseread1 },
|
||||
/*::[*/0x08/*::]*/: { n:'PtgConcat', f:parseread1 },
|
||||
/*::[*/0x09/*::]*/: { n:'PtgLt', f:parseread1 },
|
||||
/*::[*/0x0A/*::]*/: { n:'PtgLe', f:parseread1 },
|
||||
/*::[*/0x0B/*::]*/: { n:'PtgEq', f:parseread1 },
|
||||
/*::[*/0x0C/*::]*/: { n:'PtgGe', f:parseread1 },
|
||||
/*::[*/0x0D/*::]*/: { n:'PtgGt', f:parseread1 },
|
||||
/*::[*/0x0E/*::]*/: { n:'PtgNe', f:parseread1 },
|
||||
/*::[*/0x0F/*::]*/: { n:'PtgIsect', f:parseread1 },
|
||||
/*::[*/0x10/*::]*/: { n:'PtgUnion', f:parseread1 },
|
||||
/*::[*/0x11/*::]*/: { n:'PtgRange', f:parseread1 },
|
||||
/*::[*/0x12/*::]*/: { n:'PtgUplus', f:parseread1 },
|
||||
/*::[*/0x13/*::]*/: { n:'PtgUminus', f:parseread1 },
|
||||
/*::[*/0x14/*::]*/: { n:'PtgPercent', f:parseread1 },
|
||||
/*::[*/0x15/*::]*/: { n:'PtgParen', f:parseread1 },
|
||||
/*::[*/0x16/*::]*/: { n:'PtgMissArg', f:parseread1 },
|
||||
/*::[*/0x17/*::]*/: { n:'PtgStr', f:parse_PtgStr },
|
||||
/*::[*/0x1A/*::]*/: { n:'PtgSheet', f:parse_PtgSheet },
|
||||
/*::[*/0x1B/*::]*/: { n:'PtgEndSheet', f:parse_PtgEndSheet },
|
||||
/*::[*/0x1C/*::]*/: { n:'PtgErr', f:parse_PtgErr },
|
||||
/*::[*/0x1D/*::]*/: { n:'PtgBool', f:parse_PtgBool },
|
||||
/*::[*/0x1E/*::]*/: { n:'PtgInt', f:parse_PtgInt },
|
||||
/*::[*/0x1F/*::]*/: { n:'PtgNum', f:parse_PtgNum },
|
||||
/*::[*/0x20/*::]*/: { n:'PtgArray', f:parse_PtgArray },
|
||||
/*::[*/0x21/*::]*/: { n:'PtgFunc', f:parse_PtgFunc },
|
||||
/*::[*/0x22/*::]*/: { n:'PtgFuncVar', f:parse_PtgFuncVar },
|
||||
/*::[*/0x23/*::]*/: { n:'PtgName', f:parse_PtgName },
|
||||
/*::[*/0x24/*::]*/: { n:'PtgRef', f:parse_PtgRef },
|
||||
/*::[*/0x25/*::]*/: { n:'PtgArea', f:parse_PtgArea },
|
||||
/*::[*/0x26/*::]*/: { n:'PtgMemArea', f:parse_PtgMemArea },
|
||||
/*::[*/0x27/*::]*/: { n:'PtgMemErr', f:parse_PtgMemErr },
|
||||
/*::[*/0x28/*::]*/: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
|
||||
/*::[*/0x29/*::]*/: { n:'PtgMemFunc', f:parse_PtgMemFunc },
|
||||
/*::[*/0x2A/*::]*/: { n:'PtgRefErr', f:parse_PtgRefErr },
|
||||
/*::[*/0x2B/*::]*/: { n:'PtgAreaErr', f:parse_PtgAreaErr },
|
||||
/*::[*/0x2C/*::]*/: { n:'PtgRefN', f:parse_PtgRefN },
|
||||
/*::[*/0x2D/*::]*/: { n:'PtgAreaN', f:parse_PtgAreaN },
|
||||
/*::[*/0x2E/*::]*/: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
|
||||
/*::[*/0x2F/*::]*/: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
|
||||
/*::[*/0x39/*::]*/: { n:'PtgNameX', f:parse_PtgNameX },
|
||||
/*::[*/0x3A/*::]*/: { n:'PtgRef3d', f:parse_PtgRef3d },
|
||||
/*::[*/0x3B/*::]*/: { n:'PtgArea3d', f:parse_PtgArea3d },
|
||||
/*::[*/0x3C/*::]*/: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
|
||||
/*::[*/0x3D/*::]*/: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
0x01: { n:'PtgExp', f:parse_PtgExp },
|
||||
0x02: { n:'PtgTbl', f:parse_PtgTbl },
|
||||
0x03: { n:'PtgAdd', f:parseread1 },
|
||||
0x04: { n:'PtgSub', f:parseread1 },
|
||||
0x05: { n:'PtgMul', f:parseread1 },
|
||||
0x06: { n:'PtgDiv', f:parseread1 },
|
||||
0x07: { n:'PtgPower', f:parseread1 },
|
||||
0x08: { n:'PtgConcat', f:parseread1 },
|
||||
0x09: { n:'PtgLt', f:parseread1 },
|
||||
0x0A: { n:'PtgLe', f:parseread1 },
|
||||
0x0B: { n:'PtgEq', f:parseread1 },
|
||||
0x0C: { n:'PtgGe', f:parseread1 },
|
||||
0x0D: { n:'PtgGt', f:parseread1 },
|
||||
0x0E: { n:'PtgNe', f:parseread1 },
|
||||
0x0F: { n:'PtgIsect', f:parseread1 },
|
||||
0x10: { n:'PtgUnion', f:parseread1 },
|
||||
0x11: { n:'PtgRange', f:parseread1 },
|
||||
0x12: { n:'PtgUplus', f:parseread1 },
|
||||
0x13: { n:'PtgUminus', f:parseread1 },
|
||||
0x14: { n:'PtgPercent', f:parseread1 },
|
||||
0x15: { n:'PtgParen', f:parseread1 },
|
||||
0x16: { n:'PtgMissArg', f:parseread1 },
|
||||
0x17: { n:'PtgStr', f:parse_PtgStr },
|
||||
0x1A: { n:'PtgSheet', f:parse_PtgSheet },
|
||||
0x1B: { n:'PtgEndSheet', f:parse_PtgEndSheet },
|
||||
0x1C: { n:'PtgErr', f:parse_PtgErr },
|
||||
0x1D: { n:'PtgBool', f:parse_PtgBool },
|
||||
0x1E: { n:'PtgInt', f:parse_PtgInt },
|
||||
0x1F: { n:'PtgNum', f:parse_PtgNum },
|
||||
0x20: { n:'PtgArray', f:parse_PtgArray },
|
||||
0x21: { n:'PtgFunc', f:parse_PtgFunc },
|
||||
0x22: { n:'PtgFuncVar', f:parse_PtgFuncVar },
|
||||
0x23: { n:'PtgName', f:parse_PtgName },
|
||||
0x24: { n:'PtgRef', f:parse_PtgRef },
|
||||
0x25: { n:'PtgArea', f:parse_PtgArea },
|
||||
0x26: { n:'PtgMemArea', f:parse_PtgMemArea },
|
||||
0x27: { n:'PtgMemErr', f:parse_PtgMemErr },
|
||||
0x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
|
||||
0x29: { n:'PtgMemFunc', f:parse_PtgMemFunc },
|
||||
0x2A: { n:'PtgRefErr', f:parse_PtgRefErr },
|
||||
0x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr },
|
||||
0x2C: { n:'PtgRefN', f:parse_PtgRefN },
|
||||
0x2D: { n:'PtgAreaN', f:parse_PtgAreaN },
|
||||
0x2E: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
|
||||
0x2F: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
|
||||
0x39: { n:'PtgNameX', f:parse_PtgNameX },
|
||||
0x3A: { n:'PtgRef3d', f:parse_PtgRef3d },
|
||||
0x3B: { n:'PtgArea3d', f:parse_PtgArea3d },
|
||||
0x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
|
||||
0x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
|
||||
0xFF: {}
|
||||
};
|
||||
/* These are duplicated in the PtgTypes table */
|
||||
var PtgDupes = {
|
||||
/*::[*/0x40/*::]*/: 0x20, /*::[*/0x60/*::]*/: 0x20,
|
||||
/*::[*/0x41/*::]*/: 0x21, /*::[*/0x61/*::]*/: 0x21,
|
||||
/*::[*/0x42/*::]*/: 0x22, /*::[*/0x62/*::]*/: 0x22,
|
||||
/*::[*/0x43/*::]*/: 0x23, /*::[*/0x63/*::]*/: 0x23,
|
||||
/*::[*/0x44/*::]*/: 0x24, /*::[*/0x64/*::]*/: 0x24,
|
||||
/*::[*/0x45/*::]*/: 0x25, /*::[*/0x65/*::]*/: 0x25,
|
||||
/*::[*/0x46/*::]*/: 0x26, /*::[*/0x66/*::]*/: 0x26,
|
||||
/*::[*/0x47/*::]*/: 0x27, /*::[*/0x67/*::]*/: 0x27,
|
||||
/*::[*/0x48/*::]*/: 0x28, /*::[*/0x68/*::]*/: 0x28,
|
||||
/*::[*/0x49/*::]*/: 0x29, /*::[*/0x69/*::]*/: 0x29,
|
||||
/*::[*/0x4A/*::]*/: 0x2A, /*::[*/0x6A/*::]*/: 0x2A,
|
||||
/*::[*/0x4B/*::]*/: 0x2B, /*::[*/0x6B/*::]*/: 0x2B,
|
||||
/*::[*/0x4C/*::]*/: 0x2C, /*::[*/0x6C/*::]*/: 0x2C,
|
||||
/*::[*/0x4D/*::]*/: 0x2D, /*::[*/0x6D/*::]*/: 0x2D,
|
||||
/*::[*/0x4E/*::]*/: 0x2E, /*::[*/0x6E/*::]*/: 0x2E,
|
||||
/*::[*/0x4F/*::]*/: 0x2F, /*::[*/0x6F/*::]*/: 0x2F,
|
||||
/*::[*/0x58/*::]*/: 0x22, /*::[*/0x78/*::]*/: 0x22,
|
||||
/*::[*/0x59/*::]*/: 0x39, /*::[*/0x79/*::]*/: 0x39,
|
||||
/*::[*/0x5A/*::]*/: 0x3A, /*::[*/0x7A/*::]*/: 0x3A,
|
||||
/*::[*/0x5B/*::]*/: 0x3B, /*::[*/0x7B/*::]*/: 0x3B,
|
||||
/*::[*/0x5C/*::]*/: 0x3C, /*::[*/0x7C/*::]*/: 0x3C,
|
||||
/*::[*/0x5D/*::]*/: 0x3D, /*::[*/0x7D/*::]*/: 0x3D
|
||||
0x40: 0x20, 0x60: 0x20,
|
||||
0x41: 0x21, 0x61: 0x21,
|
||||
0x42: 0x22, 0x62: 0x22,
|
||||
0x43: 0x23, 0x63: 0x23,
|
||||
0x44: 0x24, 0x64: 0x24,
|
||||
0x45: 0x25, 0x65: 0x25,
|
||||
0x46: 0x26, 0x66: 0x26,
|
||||
0x47: 0x27, 0x67: 0x27,
|
||||
0x48: 0x28, 0x68: 0x28,
|
||||
0x49: 0x29, 0x69: 0x29,
|
||||
0x4A: 0x2A, 0x6A: 0x2A,
|
||||
0x4B: 0x2B, 0x6B: 0x2B,
|
||||
0x4C: 0x2C, 0x6C: 0x2C,
|
||||
0x4D: 0x2D, 0x6D: 0x2D,
|
||||
0x4E: 0x2E, 0x6E: 0x2E,
|
||||
0x4F: 0x2F, 0x6F: 0x2F,
|
||||
0x58: 0x22, 0x78: 0x22,
|
||||
0x59: 0x39, 0x79: 0x39,
|
||||
0x5A: 0x3A, 0x7A: 0x3A,
|
||||
0x5B: 0x3B, 0x7B: 0x3B,
|
||||
0x5C: 0x3C, 0x7C: 0x3C,
|
||||
0x5D: 0x3D, 0x7D: 0x3D
|
||||
};
|
||||
|
||||
var Ptg18 = {
|
||||
/*::[*/0x01/*::]*/: { n:'PtgElfLel', f:parse_PtgElfLel },
|
||||
/*::[*/0x02/*::]*/: { n:'PtgElfRw', f:parse_PtgElfRw },
|
||||
/*::[*/0x03/*::]*/: { n:'PtgElfCol', f:parse_PtgElfCol },
|
||||
/*::[*/0x06/*::]*/: { n:'PtgElfRwV', f:parse_PtgElfRwV },
|
||||
/*::[*/0x07/*::]*/: { n:'PtgElfColV', f:parse_PtgElfColV },
|
||||
/*::[*/0x0A/*::]*/: { n:'PtgElfRadical', f:parse_PtgElfRadical },
|
||||
/*::[*/0x0B/*::]*/: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
|
||||
/*::[*/0x0D/*::]*/: { n:'PtgElfColS', f:parse_PtgElfColS },
|
||||
/*::[*/0x0F/*::]*/: { n:'PtgElfColSV', f:parse_PtgElfColSV },
|
||||
/*::[*/0x10/*::]*/: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
|
||||
/*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList },
|
||||
/*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
0x01: { n:'PtgElfLel', f:parse_PtgElfLel },
|
||||
0x02: { n:'PtgElfRw', f:parse_PtgElfRw },
|
||||
0x03: { n:'PtgElfCol', f:parse_PtgElfCol },
|
||||
0x06: { n:'PtgElfRwV', f:parse_PtgElfRwV },
|
||||
0x07: { n:'PtgElfColV', f:parse_PtgElfColV },
|
||||
0x0A: { n:'PtgElfRadical', f:parse_PtgElfRadical },
|
||||
0x0B: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
|
||||
0x0D: { n:'PtgElfColS', f:parse_PtgElfColS },
|
||||
0x0F: { n:'PtgElfColSV', f:parse_PtgElfColSV },
|
||||
0x10: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
|
||||
0x19: { n:'PtgList', f:parse_PtgList },
|
||||
0x1D: { n:'PtgSxName', f:parse_PtgSxName },
|
||||
0xFF: {}
|
||||
};
|
||||
var Ptg19 = {
|
||||
/*::[*/0x00/*::]*/: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
|
||||
/*::[*/0x01/*::]*/: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
|
||||
/*::[*/0x02/*::]*/: { n:'PtgAttrIf', f:parse_PtgAttrIf },
|
||||
/*::[*/0x04/*::]*/: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
|
||||
/*::[*/0x08/*::]*/: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
|
||||
/*::[*/0x10/*::]*/: { n:'PtgAttrSum', f:parse_PtgAttrSum },
|
||||
/*::[*/0x20/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
|
||||
/*::[*/0x21/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
|
||||
/*::[*/0x40/*::]*/: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
|
||||
/*::[*/0x41/*::]*/: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
|
||||
/*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
0x00: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
|
||||
0x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
|
||||
0x02: { n:'PtgAttrIf', f:parse_PtgAttrIf },
|
||||
0x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
|
||||
0x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
|
||||
0x10: { n:'PtgAttrSum', f:parse_PtgAttrSum },
|
||||
0x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
|
||||
0x21: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
|
||||
0x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
|
||||
0x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
|
||||
0x80: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
|
||||
0xFF: {}
|
||||
};
|
||||
|
||||
/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
|
||||
|
@ -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;
|
||||
|
100
bits/67_wsxml.js
100
bits/67_wsxml.js
@ -2,16 +2,13 @@ function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
|
||||
var d = safe_decode_range(s);
|
||||
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
|
||||
}
|
||||
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
|
||||
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
|
||||
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
|
||||
var mergecregex = /<(?:\w+:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
|
||||
var hlinkregex = /<(?:\w+:)?hyperlink [^<>]*>/mg;
|
||||
var dimregex = /"(\w*:\w*)"/;
|
||||
var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
|
||||
var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
|
||||
var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
|
||||
var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
|
||||
var sheetprregex2= /<(?:\w:)?sheetPr[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetPr)>/;
|
||||
var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
|
||||
var colregex = /<(?:\w+:)?col\b[^<>]*[\/]?>/g;
|
||||
var afregex = /<(?:\w+:)?autoFilter[^>]*/g;
|
||||
var marginregex= /<(?:\w+:)?pageMargins[^<>]*\/>/g;
|
||||
var sheetprregex = /<(?:\w+:)?sheetPr\b[^<>]*?\/>/;
|
||||
|
||||
/* 18.3 Worksheets */
|
||||
function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ {
|
||||
@ -24,7 +21,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
|
||||
var refguess/*:Range*/ = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} }/*:any*/);
|
||||
|
||||
var data1 = "", data2 = "";
|
||||
var mtch/*:?any*/ = data.match(sheetdataregex);
|
||||
var mtch/*:?any*/ = str_match_xml_ns(data, "sheetData");
|
||||
if(mtch) {
|
||||
data1 = data.slice(0, mtch.index);
|
||||
data2 = data.slice(mtch.index + mtch[0].length);
|
||||
@ -33,7 +30,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
|
||||
/* 18.3.1.82 sheetPr CT_SheetPr */
|
||||
var sheetPr = data1.match(sheetprregex);
|
||||
if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
|
||||
else if((sheetPr = data1.match(sheetprregex2))) parse_ws_xml_sheetpr2(sheetPr[0], sheetPr[1]||"", s, wb, idx, styles, themes);
|
||||
else if((sheetPr = str_match_xml_ns(data1, "sheetPr"))) parse_ws_xml_sheetpr2(sheetPr[0], sheetPr[1]||"", s, wb, idx, styles, themes);
|
||||
|
||||
/* 18.3.1.35 dimension CT_SheetDimension */
|
||||
var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
|
||||
@ -43,7 +40,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
|
||||
}
|
||||
|
||||
/* 18.3.1.88 sheetViews CT_SheetViews */
|
||||
var svs = data1.match(svsregex);
|
||||
var svs = str_match_xml_ns(data1, "sheetViews");
|
||||
if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
|
||||
|
||||
/* 18.3.1.17 cols CT_Cols */
|
||||
@ -55,7 +52,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
|
||||
}
|
||||
|
||||
/* 18.3.1.80 sheetData CT_SheetData ? */
|
||||
if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
|
||||
if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles, wb);
|
||||
|
||||
/* 18.3.1.2 autoFilter CT_AutoFilter */
|
||||
var afilter = data2.match(afregex);
|
||||
@ -75,6 +72,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"]) {
|
||||
@ -91,6 +92,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;
|
||||
}
|
||||
|
||||
@ -237,7 +239,7 @@ function write_ws_xml_autofilter(data, ws, wb, idx)/*:string*/ {
|
||||
|
||||
/* 18.3.1.88 sheetViews CT_SheetViews */
|
||||
/* 18.3.1.87 sheetView CT_SheetView */
|
||||
var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/g;
|
||||
var sviewregex = /<(?:\w:)?sheetView(?:[^<>a-z][^<>]*)?\/?>/g;
|
||||
function parse_ws_xml_sheetviews(data, wb/*:WBWBProps*/) {
|
||||
if(!wb.Views) wb.Views = [{}];
|
||||
(data.match(sviewregex)||[]).forEach(function(r/*:string*/, i/*:number*/) {
|
||||
@ -257,7 +259,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 = "";
|
||||
@ -270,11 +272,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;
|
||||
@ -313,11 +318,10 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string
|
||||
|
||||
var parse_ws_xml_data = /*#__PURE__*/(function() {
|
||||
var cellregex = /<(?:\w+:)?c[ \/>]/, rowregex = /<\/(?:\w+:)?row>/;
|
||||
var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
|
||||
var rregex = /r=["']([^"']*)["']/;
|
||||
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;
|
||||
@ -328,6 +332,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;
|
||||
@ -393,23 +398,31 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
|
||||
d = x.slice(i);
|
||||
p = ({t:""}/*:any*/);
|
||||
|
||||
if((cref=d.match(match_v))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]);
|
||||
if((cref=str_match_xml_ns(d, "v"))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]);
|
||||
if(opts.cellFormula) {
|
||||
if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') {
|
||||
/* TODO: match against XLSXFutureFunctions */
|
||||
p.f=unescapexml(utf8read(cref[1]), true);
|
||||
if(!opts.xlfn) p.f = _xlfn(p.f);
|
||||
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) {
|
||||
p.F = (d.match(refregex)||[])[1];
|
||||
if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
|
||||
} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
|
||||
// TODO: parse formula
|
||||
ftag = parsexmltag(cref[0]);
|
||||
var ___f = unescapexml(utf8read(cref[1]));
|
||||
if(!opts.xlfn) ___f = _xlfn(___f);
|
||||
sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r];
|
||||
if((cref=str_match_xml_ns(d, "f"))!= null /*:: && cref != null*/) {
|
||||
if(cref[1] == "") {
|
||||
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
|
||||
// TODO: parse formula
|
||||
ftag = parsexmltag(cref[0]);
|
||||
if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
|
||||
}
|
||||
} else {
|
||||
/* TODO: match against XLSXFutureFunctions */
|
||||
p.f=unescapexml(utf8read(cref[1]), true);
|
||||
if(!opts.xlfn) p.f = _xlfn(p.f);
|
||||
if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) {
|
||||
p.F = (d.match(refregex)||[])[1];
|
||||
if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
|
||||
} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
|
||||
// TODO: parse formula
|
||||
ftag = parsexmltag(cref[0]);
|
||||
var ___f = unescapexml(utf8read(cref[1]));
|
||||
if(!opts.xlfn) ___f = _xlfn(___f);
|
||||
sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r];
|
||||
}
|
||||
}
|
||||
} else if((cref=d.match(/<f[^>]*\/>/))) {
|
||||
} 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);
|
||||
}
|
||||
@ -455,7 +468,7 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th
|
||||
if(opts.cellHTML) p.h = escapehtml(p.v);
|
||||
break;
|
||||
case 'inlineStr':
|
||||
cref = d.match(isregex);
|
||||
cref = str_match_xml_ns(d, "is");
|
||||
p.t = 's';
|
||||
if(cref != null && (sstr = parse_si(cref[1]))) {
|
||||
p.v = sstr.t;
|
||||
@ -464,8 +477,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':
|
||||
@ -484,8 +497,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;
|
||||
@ -510,6 +523,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 = [];
|
||||
@ -518,7 +532,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*/);
|
||||
@ -619,7 +633,7 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
|
||||
if(!l[1].Target) return;
|
||||
rel = ({"ref":l[0]}/*:any*/);
|
||||
if(l[1].Target.charAt(0) != "#") {
|
||||
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
|
||||
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#[\s\S]*$/, ""), RELS.HLINK);
|
||||
rel["r:id"] = "rId"+rId;
|
||||
}
|
||||
if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
|
||||
|
@ -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;
|
||||
@ -686,6 +687,10 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
||||
}
|
||||
break;
|
||||
|
||||
case 0x0227: /* 'BrtLegacyDrawing' */
|
||||
if(val) s["!legrel"] = val;
|
||||
break;
|
||||
|
||||
case 0x00A1: /* 'BrtBeginAFilter' */
|
||||
s['!autofilter'] = { ref:encode_range(val) };
|
||||
break;
|
||||
@ -742,7 +747,6 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
||||
case 0x0499: /* 'BrtFilter14' */
|
||||
case 0x00A9: /* 'BrtIconFilter' */
|
||||
case 0x049D: /* 'BrtIconFilter14' */
|
||||
case 0x0227: /* 'BrtLegacyDrawing' */
|
||||
case 0x0228: /* 'BrtLegacyDrawingHF' */
|
||||
case 0x0295: /* 'BrtListPart' */
|
||||
case 0x027F: /* 'BrtOleObject' */
|
||||
@ -801,11 +805,12 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/
|
||||
if(merges.length > 0) s["!merges"] = merges;
|
||||
if(colinfo.length > 0) s["!cols"] = colinfo;
|
||||
if(rowinfo.length > 0) s["!rows"] = rowinfo;
|
||||
if(rels['!id'][s['!legrel']]) s['!legdrawel'] = rels['!id'][s['!legrel']];
|
||||
return s;
|
||||
}
|
||||
|
||||
/* TODO: something useful -- this is a stub */
|
||||
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/, last_seen/*:boolean*/)/*:boolean*/ {
|
||||
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/, last_seen/*:boolean*/, date1904/*:boolean*/)/*:boolean*/ {
|
||||
var o/*:any*/ = ({r:R, c:C}/*:any*/);
|
||||
if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
|
||||
if(cell.v === undefined) return false;
|
||||
@ -815,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;
|
||||
@ -868,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;
|
||||
@ -887,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 */);
|
||||
@ -918,7 +924,7 @@ function write_HLINKS(ba, ws/*:Worksheet*/, rels) {
|
||||
/* *BrtHLink */
|
||||
ws['!links'].forEach(function(l) {
|
||||
if(!l[1].Target) return;
|
||||
var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK);
|
||||
var rId = add_rels(rels, -1, l[1].Target.replace(/#[\s\S]*$/, ""), RELS.HLINK);
|
||||
write_record(ba, 0x01EE /* BrtHLink */, write_BrtHLink(l, rId));
|
||||
});
|
||||
delete ws['!links'];
|
||||
|
@ -4,16 +4,16 @@ function parse_Cache(data/*:string*/)/*:[Array<number|string>, string, ?string]*
|
||||
var f;
|
||||
|
||||
/* 21.2.2.150 pt CT_NumVal */
|
||||
(data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
|
||||
var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
|
||||
(data.match(/<c:pt idx="(\d*)"[^<>\/]*><c:v>([^<])<\/c:v><\/c:pt>/mg)||[]).forEach(function(pt) {
|
||||
var q = pt.match(/<c:pt idx="(\d*)"[^<>\/]*><c:v>([^<]*)<\/c:v><\/c:pt>/);
|
||||
if(!q) return;
|
||||
col[+q[1]] = num ? +q[2] : q[2];
|
||||
});
|
||||
|
||||
/* 21.2.2.71 formatCode CT_Xstring */
|
||||
var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
|
||||
var nf = unescapexml((str_match_xml(data, "c:formatCode") || ["","General"])[1]);
|
||||
|
||||
(data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); });
|
||||
(str_match_ng(data, "<c:f>", "</c:f>")||[]).forEach(function(F) { f = F.replace(/<[^<>]*>/g,""); });
|
||||
|
||||
return [col, nf, f];
|
||||
}
|
||||
@ -28,7 +28,7 @@ function parse_chart(data/*:?string*/, name/*:string*/, opts, rels, wb, csheet)
|
||||
var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
|
||||
|
||||
/* 21.2.2.120 numCache CT_NumData */
|
||||
(data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
|
||||
(str_match_ng(data, "<c:numCache>", "</c:numCache>")||[]).forEach(function(nc) {
|
||||
var cache = parse_Cache(nc);
|
||||
refguess.s.r = refguess.s.c = 0;
|
||||
refguess.e.c = C;
|
||||
|
@ -69,8 +69,14 @@ function parse_BrtName(data, length, opts) {
|
||||
data.l += 1; //var chKey = data.read_shift(1);
|
||||
var itab = data.read_shift(4);
|
||||
var name = parse_XLNameWideString(data);
|
||||
var formula = parse_XLSBNameParsedFormula(data, 0, opts);
|
||||
var comment = parse_XLNullableWideString(data);
|
||||
var formula;
|
||||
var comment = "";
|
||||
try {
|
||||
formula = parse_XLSBNameParsedFormula(data, 0, opts);
|
||||
try {
|
||||
comment = parse_XLNullableWideString(data);
|
||||
} catch(e){}
|
||||
} catch(e) { console.error("Could not parse defined name " + name); }
|
||||
if(flags & 0x20) name = "_xlnm." + name;
|
||||
//if(0 /* fProc */) {
|
||||
// unusedstring1: XLNullableWideString
|
||||
@ -141,7 +147,7 @@ function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
|
||||
|
||||
case 0x0027: /* 'BrtName' */
|
||||
if(val.Sheet != null) opts.SID = val.Sheet;
|
||||
val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts);
|
||||
val.Ref = val.Ptg ? stringify_formula(val.Ptg, null, null, supbooks, opts) : "#REF!";
|
||||
delete opts.SID;
|
||||
delete val.Ptg;
|
||||
Names.push(val);
|
||||
|
@ -1,5 +1,5 @@
|
||||
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
|
||||
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
|
||||
var attregexg2=/\b((?:\w+:)?[\w]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
|
||||
var attregex2=/\b((?:\w+:)?[\w]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
|
||||
function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) {
|
||||
var words = tag.split(/\s+/);
|
||||
var z/*:any*/ = ([]/*:any*/); if(!skip_root) z[0] = words[0];
|
||||
@ -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,17 +92,18 @@ 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;
|
||||
if(sid === undefined && row) sid = row.StyleID;
|
||||
if(sid === undefined && csty) sid = csty.StyleID;
|
||||
while(styles[sid] !== undefined) {
|
||||
if(styles[sid].nf) nf = styles[sid].nf;
|
||||
if(styles[sid].Interior) interiors.push(styles[sid].Interior);
|
||||
if(!styles[sid].Parent) break;
|
||||
sid = styles[sid].Parent;
|
||||
var ssid = styles[sid];
|
||||
if(ssid.nf) nf = ssid.nf;
|
||||
if(ssid.Interior) interiors.push(ssid.Interior);
|
||||
if(!ssid.Parent) break;
|
||||
sid = ssid.Parent;
|
||||
}
|
||||
switch(data.Type) {
|
||||
case 'Boolean':
|
||||
@ -111,13 +112,12 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a
|
||||
break;
|
||||
case 'String':
|
||||
cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
|
||||
cell.v = (xml.indexOf("<") > -1 ? unescapexml(ss||xml).replace(/<.*?>/g, "") : cell.r); // todo: BR etc
|
||||
cell.v = (xml.indexOf("<") > -1 ? unescapexml(ss||xml).replace(/<[^<>]*>/g, "") : cell.r); // todo: BR etc
|
||||
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 +130,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);
|
||||
@ -222,7 +222,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
|
||||
var rowinfo/*:Array<RowInfo>*/ = [], rowobj = {}, cc = 0, rr = 0;
|
||||
var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false} }/*:any*/), wsprops = {};
|
||||
xlmlregex.lastIndex = 0;
|
||||
str = str.replace(/<!--([\s\S]*?)-->/mg,"");
|
||||
str = str_remove_ng(str, "<!--", "-->");
|
||||
var raw_Rn3 = "";
|
||||
while((Rn = xlmlregex.exec(str))) switch((Rn[3] = (raw_Rn3 = Rn[3]).toLowerCase())) {
|
||||
case 'data' /*case 'Data'*/:
|
||||
@ -232,7 +232,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'*/:
|
||||
@ -443,6 +443,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
|
||||
} else {
|
||||
state.push([Rn[3], false]);
|
||||
tmp = xlml_parsexmltag(Rn[0]);
|
||||
if(!parsexmlbool(tmp["ShowAlways"]||"0")) comments.hidden = true;
|
||||
comment = ({a:tmp.Author}/*:any*/);
|
||||
}
|
||||
break;
|
||||
@ -534,6 +535,9 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
|
||||
/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */
|
||||
Workbook.WBProps.date1904 = true;
|
||||
break;
|
||||
case 'hidehorizontalscrollbar' /*case 'HideHorizontalScrollBar'*/: break;
|
||||
case 'hideverticalscrollbar' /*case 'HideVerticalScrollBar'*/: break;
|
||||
case 'hideworkbooktabs' /*case 'HideWorkbookTabs'*/: break;
|
||||
case 'windowheight' /*case 'WindowHeight'*/: break;
|
||||
case 'windowwidth' /*case 'WindowWidth'*/: break;
|
||||
case 'windowtopx' /*case 'WindowTopX'*/: break;
|
||||
@ -1102,11 +1106,15 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb
|
||||
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
|
||||
}
|
||||
function write_ws_xlml_comment(comments/*:Array<any>*/)/*:string*/ {
|
||||
/* TODO: test multiple comments */
|
||||
return comments.map(function(c) {
|
||||
// TODO: formatted text
|
||||
var t = xlml_unfixstr(c.t||"");
|
||||
var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
|
||||
return writextag("Comment", d, {"ss:Author":c.a});
|
||||
var p = {};
|
||||
if(c.a) p["ss:Author"] = c.a;
|
||||
if(!comments.hidden) p["ss:ShowAlways"] = "1";
|
||||
return writextag("Comment", d, p);
|
||||
}).join("");
|
||||
}
|
||||
function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, addr)/*:string*/{
|
||||
@ -1178,9 +1186,12 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
|
||||
o.push(writextag("Column",null,k));
|
||||
});
|
||||
var dense = ws["!data"] != null;
|
||||
var addr = {r:0,c:0};
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
|
||||
addr.r = R;
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
addr.c = C;
|
||||
var skip = false;
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
@ -1191,7 +1202,6 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
|
||||
break;
|
||||
}
|
||||
if(skip) continue;
|
||||
var addr = {r:R,c:C};
|
||||
var ref = encode_col(C) + encode_row(R), cell = dense ? (ws["!data"][R]||[])[C] : ws[ref];
|
||||
row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
|
||||
}
|
||||
@ -1215,7 +1225,7 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
|
||||
/* WorksheetOptions */
|
||||
o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
|
||||
|
||||
if(ws["!autofilter"]) o.push('<AutoFilter x:Range="' + a1_to_rc(fix_range(ws["!autofilter"].ref), {r:0,c:0}) + '" xmlns="urn:schemas-microsoft-com:office:excel"></AutoFilter>');
|
||||
if(ws && ws["!autofilter"]) o.push('<AutoFilter x:Range="' + a1_to_rc(fix_range(ws["!autofilter"].ref), {r:0,c:0}) + '" xmlns="urn:schemas-microsoft-com:office:excel"></AutoFilter>');
|
||||
|
||||
return o.join("");
|
||||
}
|
||||
@ -1234,11 +1244,10 @@ function write_xlml(wb, opts)/*:string*/ {
|
||||
d.push(write_props_xlml(wb, opts));
|
||||
d.push(write_wb_xlml(wb, opts));
|
||||
d.push("");
|
||||
d.push("");
|
||||
d.push(write_names_xlml(wb, opts));
|
||||
for(var i = 0; i < wb.SheetNames.length; ++i)
|
||||
d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
|
||||
d[2] = write_sty_xlml(wb, opts);
|
||||
d[3] = write_names_xlml(wb, opts);
|
||||
return XML_HEADER + writextag("Workbook", d.join(""), {
|
||||
'xmlns': XLMLNS.ss,
|
||||
'xmlns:o': XLMLNS.o,
|
||||
|
@ -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,12 +119,13 @@ 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];
|
||||
return XLSIcv[icv];
|
||||
};
|
||||
var process_cell_style = function pcs(cell, line/*:any*/, options) {
|
||||
var process_cell_style = function pcs(line/*:any*/, options) {
|
||||
var xfd = line.XF.data;
|
||||
if(!xfd || !xfd.patternType || !options || !options.cellStyles) return;
|
||||
line.s = ({}/*:any*/);
|
||||
@ -134,9 +135,9 @@ 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);
|
||||
if(options.cellStyles && line.XF && line.XF.data) process_cell_style(line, options);
|
||||
delete line.ixfe; delete line.XF;
|
||||
lastcell = cell;
|
||||
last_cell = encode_cell(cell);
|
||||
@ -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--;
|
||||
@ -328,27 +330,29 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
} break;
|
||||
case 0x0009: case 0x0209: case 0x0409: case 0x0809 /* BOF */: {
|
||||
if(opts.biff === 8) opts.biff = {
|
||||
/*::[*/0x0009/*::]*/:2,
|
||||
/*::[*/0x0209/*::]*/:3,
|
||||
/*::[*/0x0409/*::]*/:4
|
||||
0x0009: 2,
|
||||
0x0209: 3,
|
||||
0x0409: 4
|
||||
}[RecordType] || {
|
||||
/*::[*/0x0200/*::]*/:2,
|
||||
/*::[*/0x0300/*::]*/:3,
|
||||
/*::[*/0x0400/*::]*/:4,
|
||||
/*::[*/0x0500/*::]*/:5,
|
||||
/*::[*/0x0600/*::]*/:8,
|
||||
/*::[*/0x0002/*::]*/:2,
|
||||
/*::[*/0x0007/*::]*/:2
|
||||
0x0200: 2,
|
||||
0x0300: 3,
|
||||
0x0400: 4,
|
||||
0x0500: 5,
|
||||
0x0600: 8,
|
||||
0x0002: 2,
|
||||
0x0007: 2
|
||||
}[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);
|
||||
@ -520,9 +524,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
}
|
||||
} break;
|
||||
case 0x001c /* Note */: {
|
||||
if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
|
||||
/* TODO: comment continuation (row == -1 / 0xFFFF) */
|
||||
cc = options.dense ? (out["!data"][val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
|
||||
var noteobj = objects[val[2]];
|
||||
if(!cc) {
|
||||
if(options.dense) {
|
||||
if(!out["!data"][val[0].r]) out["!data"][val[0].r] = [];
|
||||
@ -536,7 +539,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
|
||||
range.s.c = Math.min(range.s.c, val[0].c);
|
||||
}
|
||||
if(!cc.c) cc.c = [];
|
||||
cmnt = {a:val[1],t:noteobj.TxO.t};
|
||||
if(opts.biff <= 5 && opts.biff >= 2) cmnt = {a:"SheetJ5", t:val[1]};
|
||||
else {
|
||||
var noteobj = objects[val[2]];
|
||||
cmnt = {a:val[1],t:noteobj.TxO.t};
|
||||
if(val[3] != null && !(val[3] & 0x02)) cc.c.hidden = true;
|
||||
}
|
||||
cc.c.push(cmnt);
|
||||
} break;
|
||||
case 0x087d /* XFExt */: update_xfext(XFs[val.ixfe], val.ext); break;
|
||||
|
2624
bits/77_parsetab.js
2624
bits/77_parsetab.js
File diff suppressed because it is too large
Load Diff
@ -31,15 +31,6 @@ 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*/) {
|
||||
var out = new_buf(9);
|
||||
write_BIFF2Cell(out, r, c);
|
||||
@ -56,37 +47,69 @@ function write_BIFF2LABEL(r/*:number*/, c/*:number*/, val) {
|
||||
return out.l < out.length ? out.slice(0, out.l) : out;
|
||||
}
|
||||
|
||||
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*//*::, opts*/) {
|
||||
function write_comments_biff2(ba/*:BufArray*/, comments/*:Array<[Comment[], number, number]>*/) {
|
||||
comments.forEach(function(data) {
|
||||
var text = data[0].map(function(cc) { return cc.t; }).join("");
|
||||
// TODO: should '\n' be translated to '\r' to correct for Excel 5.0 bug when exporting to BIFF2/3 ?
|
||||
if(text.length <= 2048) return write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text, data[1], data[2]));
|
||||
write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text.slice(0, 2048), data[1], data[2], text.length));
|
||||
for(var i = 2048; i < text.length; i += 2048)
|
||||
write_biff_rec(ba, 0x001C, write_NOTE_BIFF2(text.slice(i, Math.min(i+2048, text.length)), -1, -1, Math.min(2048, text.length - i)));
|
||||
});
|
||||
}
|
||||
|
||||
/* TODO: BIFF3/4 use different records -- see comments*/
|
||||
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, date1904/*:boolean*/) {
|
||||
var ifmt = 0;
|
||||
if(cell.z != null) {
|
||||
ifmt = opts._BIFF2FmtTable.indexOf(cell.z);
|
||||
if(ifmt == -1) { opts._BIFF2FmtTable.push(cell.z); ifmt = opts._BIFF2FmtTable.length - 1; }
|
||||
}
|
||||
var ixfe = 0;
|
||||
if(cell.z != null) {
|
||||
for(; ixfe < opts.cellXfs.length; ++ixfe) if(opts.cellXfs[ixfe].numFmtId == ifmt) break;
|
||||
if(ixfe == opts.cellXfs.length) opts.cellXfs.push({numFmtId: ifmt});
|
||||
}
|
||||
if(cell.v != null) switch(cell.t) {
|
||||
case 'd': case 'n':
|
||||
var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
|
||||
if((v == (v|0)) && (v >= 0) && (v < 65536))
|
||||
write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
|
||||
var v = cell.t == 'd' ? datenum(parseDate(cell.v, date1904), date1904) : cell.v;
|
||||
if(opts.biff == 2 && (v == (v|0)) && (v >= 0) && (v < 65536))
|
||||
// 0x027E (RK) in BIFF3/4
|
||||
write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v, ixfe, ifmt));
|
||||
else if(isNaN(v))
|
||||
// 0x0205 in BIFF3/4
|
||||
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x24, "e")); // #NUM!
|
||||
else if(!isFinite(v))
|
||||
// 0x0205 in BIFF3/4
|
||||
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, 0x07, "e")); // #DIV/0!
|
||||
else
|
||||
write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
|
||||
// 0x0203 in BIFF3/4
|
||||
write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v, ixfe, ifmt));
|
||||
return;
|
||||
case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
|
||||
case 'b': case 'e':
|
||||
// 0x0205 in BIFF3/4
|
||||
write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
|
||||
/* TODO: codepage, sst */
|
||||
case 's': case 'str':
|
||||
// 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>*/ = [];
|
||||
var range = safe_decode_range(ws['!ref'] || "A1"), rr = "", cols/*:Array<string>*/ = [];
|
||||
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
|
||||
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
|
||||
range.e.c = Math.min(range.e.c, 0xFF);
|
||||
range.e.r = Math.min(range.e.c, 0x3FFF);
|
||||
range.e.r = Math.min(range.e.r, 0x3FFF);
|
||||
}
|
||||
var row = [];
|
||||
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] || [];
|
||||
@ -95,26 +118,300 @@ 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]);
|
||||
}
|
||||
}
|
||||
|
||||
/* ... 0x12 0x19 0x13 (Password) */
|
||||
write_comments_biff2(ba, comments);
|
||||
/* 0x3d (Window1) ... */
|
||||
}
|
||||
|
||||
/* Based on test files */
|
||||
function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
|
||||
var o = opts || {};
|
||||
|
||||
var ba = buf_array();
|
||||
var idx = 0;
|
||||
for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
|
||||
if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
|
||||
write_biff_rec(ba, (o.biff == 4 ? 0x0409 : (o.biff == 3 ? 0x0209 : 0x0009)), write_BOF(wb, 0x10, o));
|
||||
/* ... */
|
||||
write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
|
||||
/* ... */
|
||||
if(((wb.Workbook||{}).WBProps||{}).date1904) write_biff_rec(ba, 0x0022, writebool(true));
|
||||
o.cellXfs = [{numFmtId: 0}];
|
||||
o._BIFF2FmtTable/*:Array<string>*/ = ["General"]; o._Fonts = [];
|
||||
var body = buf_array();
|
||||
write_ws_biff2(body, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
|
||||
|
||||
o._BIFF2FmtTable.forEach(function(f) {
|
||||
if(o.biff <= 3) write_biff_rec(ba, 0x001E, write_BIFF2Format(f));
|
||||
else write_biff_rec(ba, 0x041E, write_BIFF4Format(f));
|
||||
});
|
||||
o.cellXfs.forEach(function(xf) {
|
||||
switch(o.biff) {
|
||||
case 2: write_biff_rec(ba, 0x0043, write_BIFF2XF(xf)); break;
|
||||
case 3: write_biff_rec(ba, 0x0243, write_BIFF3XF(xf)); break;
|
||||
case 4: write_biff_rec(ba, 0x0443, write_BIFF4XF(xf)); break;
|
||||
}
|
||||
});
|
||||
delete o._BIFF2FmtTable; delete o.cellXfs; delete o._Fonts;
|
||||
|
||||
ba.push(body.end());
|
||||
write_biff_rec(ba, 0x000A);
|
||||
return ba.end();
|
||||
}
|
||||
|
||||
var b8oid = 1, b8ocnts/*:Array<[number, number, number]>*/ = [];
|
||||
function write_MsoDrawingGroup() {
|
||||
var buf = new_buf(82 + 8 * b8ocnts.length);
|
||||
/* [MS-ODRAW] 2.2.12 OfficeArtDggContainer */
|
||||
buf.write_shift(2, 0x0F);
|
||||
buf.write_shift(2, 0xF000);
|
||||
buf.write_shift(4, 74 + 8 * b8ocnts.length);
|
||||
/* 2.2.48 OfficeArtFDGGBlock */
|
||||
{
|
||||
buf.write_shift(2, 0);
|
||||
buf.write_shift(2, 0xF006);
|
||||
buf.write_shift(4, 16 + 8 * b8ocnts.length);
|
||||
/* 2.2.47 OfficeArtFDGG */
|
||||
{
|
||||
buf.write_shift(4, b8oid);
|
||||
buf.write_shift(4, b8ocnts.length+1);
|
||||
var acc = 0; for(var i = 0; i < b8ocnts.length; ++i) acc += (b8ocnts[i] && b8ocnts[i][1] || 0); buf.write_shift(4, acc);
|
||||
buf.write_shift(4, b8ocnts.length);
|
||||
}
|
||||
/* 2.2.46 OfficeArtIDCL + */
|
||||
b8ocnts.forEach(function(b8) {
|
||||
buf.write_shift(4, b8[0]);
|
||||
buf.write_shift(4, b8[2]);
|
||||
});
|
||||
}
|
||||
/* 2.2.9 OfficeArtFOPT */
|
||||
{
|
||||
buf.write_shift(2, 0x33); // 0x03 | (3 << 4)
|
||||
buf.write_shift(2, 0xF00B);
|
||||
buf.write_shift(4, 0x12); // 3 * 6
|
||||
/* 2.3.21.15 Text Boolean Properties */
|
||||
buf.write_shift(2, 0xBF); buf.write_shift(4, 0x00080008);
|
||||
/* 2.3.7.2 fillColor */
|
||||
buf.write_shift(2, 0x0181); buf.write_shift(4, 0x08000041);
|
||||
/* 2.3.8.1 lineColor */
|
||||
buf.write_shift(2, 0x01C0); buf.write_shift(4, 0x08000040);
|
||||
}
|
||||
/* 2.2.45 OfficeArtSplitMenuColorContainer */
|
||||
{
|
||||
buf.write_shift(2, 0x40);
|
||||
buf.write_shift(2, 0xF11E);
|
||||
buf.write_shift(4, 16);
|
||||
buf.write_shift(4, 0x0800000D);
|
||||
buf.write_shift(4, 0x0800000C);
|
||||
buf.write_shift(4, 0x08000017);
|
||||
buf.write_shift(4, 0x100000F7);
|
||||
}
|
||||
return buf;
|
||||
}
|
||||
function write_comments_biff8(ba/*:BufArray*/, comments/*:Array<[Comment[], number, number]>*/) {
|
||||
var notes/*:Array<RawData>*/ = [], sz = 0, pl = buf_array(), baseid = b8oid;
|
||||
var _oasc;
|
||||
comments.forEach(function(c, ci) {
|
||||
var author = "";
|
||||
var text = c[0].map(function(t) { if(t.a && !author) author = t.a; return t.t; }).join("");
|
||||
++b8oid;
|
||||
|
||||
/* 2.2.14 OfficeArtSpContainer */
|
||||
{
|
||||
var oasc = new_buf(0x96);
|
||||
oasc.write_shift(2, 0x0F);
|
||||
oasc.write_shift(2, 0xF004);
|
||||
oasc.write_shift(4, 0x96);
|
||||
/* 2.2.40 OfficeArtFSP */
|
||||
{
|
||||
oasc.write_shift(2, 0xca2); // 0x02 | (0xca << 4)
|
||||
oasc.write_shift(2, 0xF00A);
|
||||
oasc.write_shift(4, 8);
|
||||
oasc.write_shift(4, b8oid);
|
||||
oasc.write_shift(4, 0xA00);
|
||||
}
|
||||
/* 2.2.9 OfficeArtFOPT */
|
||||
{
|
||||
oasc.write_shift(2, 0xE3); // 0x03 | (14 << 4)
|
||||
oasc.write_shift(2, 0xF00B);
|
||||
oasc.write_shift(4, 0x54); // 14 * 6
|
||||
/* 2.3.21.1 ITxid */
|
||||
oasc.write_shift(2, 0x80); oasc.write_shift(4, 0);
|
||||
/* 2.3.21.12 txdir */
|
||||
oasc.write_shift(2, 0x8B); oasc.write_shift(4, 0x02);
|
||||
/* 2.3.21.15 Text Boolean Properties */
|
||||
oasc.write_shift(2, 0xBF); oasc.write_shift(4, 0x00080008);
|
||||
/* 2.3.6.30 cxk */
|
||||
oasc.write_shift(2, 0x0158); oasc.l += 4;
|
||||
/* 2.3.7.2 fillColor */
|
||||
oasc.write_shift(2, 0x0181); oasc.write_shift(4, 0x08000050);
|
||||
/* 2.3.7.4 fillBackColor */
|
||||
oasc.write_shift(2, 0x0183); oasc.write_shift(4, 0x08000050);
|
||||
/* 2.3.7.6 fillCrMod */
|
||||
oasc.write_shift(2, 0x0185); oasc.write_shift(4, 0x100000F4);
|
||||
/* 2.3.7.43 Fill Style Boolean Properties */
|
||||
oasc.write_shift(2, 0x01BF); oasc.write_shift(4, 0x00100010);
|
||||
/* 2.3.8.1 lineColor */
|
||||
oasc.write_shift(2, 0x01C0); oasc.write_shift(4, 0x08000051);
|
||||
/* 2.3.8.4 lineCrMod */
|
||||
oasc.write_shift(2, 0x01C3); oasc.write_shift(4, 0x100000F4);
|
||||
/* 2.3.13.2 shadowColor */
|
||||
oasc.write_shift(2, 0x0201); oasc.write_shift(4, 0x08000051);
|
||||
/* 2.3.13.4 shadowCrMod */
|
||||
oasc.write_shift(2, 0x0203); oasc.write_shift(4, 0x100000F4);
|
||||
/* 2.3.13.23 Shadow Style Boolean Properties */
|
||||
oasc.write_shift(2, 0x023F); oasc.write_shift(4, 0x00030001);
|
||||
/* 2.3.4.44 Group Shape Boolean Properties */
|
||||
oasc.write_shift(2, 0x03BF); oasc.write_shift(4, 0x00020000 | (c[0].hidden ? 2 : 0));
|
||||
}
|
||||
/* [MS-XLS] 2.5.193 OfficeArtClientAnchorSheet */
|
||||
{
|
||||
oasc.l += 2;
|
||||
oasc.write_shift(2, 0xF010);
|
||||
oasc.write_shift(4, 0x12);
|
||||
oasc.write_shift(2, 0x3); // do not move or size with cells
|
||||
oasc.write_shift(2, c[2] + 2); oasc.l += 2;
|
||||
oasc.write_shift(2, c[1] + 1); oasc.l += 2;
|
||||
oasc.write_shift(2, c[2] + 4); oasc.l += 2;
|
||||
oasc.write_shift(2, c[1] + 5); oasc.l += 2;
|
||||
}
|
||||
/* [MS-XLS] 2.5.194 OfficeArtClientData */
|
||||
{
|
||||
oasc.l += 2;
|
||||
oasc.write_shift(2, 0xF011);
|
||||
oasc.l += 4;
|
||||
}
|
||||
oasc.l = 0x96;
|
||||
if(ci == 0) /* write_biff_rec(pl, 0x003C, oasc); */ _oasc = oasc;
|
||||
else write_biff_rec(pl, 0x00EC, oasc);
|
||||
}
|
||||
sz += 0x96;
|
||||
|
||||
/* [MS-XLS] 2.4.181 Obj */
|
||||
{
|
||||
var obj = new_buf(52); // 22 + 26 + 4
|
||||
/* [MS-XLS] 2.5.143 FtCmo */
|
||||
obj.write_shift(2, 0x15);
|
||||
obj.write_shift(2, 0x12);
|
||||
obj.write_shift(2, 0x19);
|
||||
obj.write_shift(2, b8oid);
|
||||
obj.write_shift(2, 0);
|
||||
obj.l = 22;
|
||||
/* [MS-XLS] 2.5.149 FtNts */
|
||||
obj.write_shift(2, 0x0D);
|
||||
obj.write_shift(2, 0x16);
|
||||
obj.write_shift(4, 0x62726272);
|
||||
obj.write_shift(4, 0x95374305);
|
||||
obj.write_shift(4, 0x80301328);
|
||||
obj.write_shift(4, 0x69696904 + b8oid*256);
|
||||
obj.write_shift(2,0);
|
||||
obj.write_shift(4,0);
|
||||
// reserved
|
||||
obj.l += 4;
|
||||
write_biff_rec(pl, 0x005D, obj);
|
||||
}
|
||||
|
||||
/* [MS-XLS] 2.5.195 OfficeArtClientTextbox */
|
||||
{
|
||||
var oact = new_buf(8);
|
||||
oact.l += 2;
|
||||
oact.write_shift(2, 0xF00D);
|
||||
oact.l += 4;
|
||||
write_biff_rec(pl, 0x00EC, oact);
|
||||
}
|
||||
sz += 8;
|
||||
|
||||
/* [MS-XLS] 2.4.329 TxO */
|
||||
{
|
||||
var txo = new_buf(18);
|
||||
txo.write_shift(2, 0x12);
|
||||
txo.l += 8;
|
||||
txo.write_shift(2, text.length);
|
||||
txo.write_shift(2, 0x10);
|
||||
txo.l += 4;
|
||||
write_biff_rec(pl, 0x01b6, txo);
|
||||
/* text continue record TODO: switch to wide strings */
|
||||
{
|
||||
var cont = new_buf(1 + text.length);
|
||||
cont.write_shift(1, 0);
|
||||
cont.write_shift(text.length, text, "sbcs");
|
||||
write_biff_rec(pl, 0x003C, cont);
|
||||
}
|
||||
/* formatting continue records */
|
||||
{
|
||||
var conf = new_buf(0x10);
|
||||
conf.l += 8;
|
||||
conf.write_shift(2, text.length);
|
||||
conf.l += 6;
|
||||
write_biff_rec(pl, 0x003C, conf);
|
||||
}
|
||||
}
|
||||
|
||||
/* 2.4.179 Note */
|
||||
{
|
||||
var notesh = new_buf(12 + author.length);
|
||||
notesh.write_shift(2, c[1]);
|
||||
notesh.write_shift(2, c[2]);
|
||||
notesh.write_shift(2, 0 | (c[0].hidden ? 0 : 2));
|
||||
notesh.write_shift(2, b8oid);
|
||||
notesh.write_shift(2, author.length);
|
||||
notesh.write_shift(1, 0);
|
||||
notesh.write_shift(author.length, author, "sbcs");
|
||||
notesh.l ++;
|
||||
notes.push(notesh);
|
||||
}
|
||||
});
|
||||
/* [MS-ODRAW] 2.2.13 OfficeArtDgContainer */
|
||||
{
|
||||
var hdr = new_buf(80);
|
||||
hdr.write_shift(2, 0x0F);
|
||||
hdr.write_shift(2, 0xF002);
|
||||
hdr.write_shift(4, sz + hdr.length - 8);
|
||||
/* [MS-ODRAW] 2.2.49 OfficeArtFDG */
|
||||
{
|
||||
hdr.write_shift(2, 0x10);
|
||||
hdr.write_shift(2, 0xF008);
|
||||
hdr.write_shift(4, 0x08);
|
||||
hdr.write_shift(4, comments.length + 1);
|
||||
hdr.write_shift(4, b8oid);
|
||||
}
|
||||
/* [MS-ODRAW] 2.2.16 OfficeArtSpgrContainer */
|
||||
{
|
||||
hdr.write_shift(2, 0x0f);
|
||||
hdr.write_shift(2, 0xF003);
|
||||
hdr.write_shift(4, sz + 0x30);
|
||||
/* [MS-ODRAW] 2.2.14 OfficeArtSpContainer */
|
||||
{
|
||||
hdr.write_shift(2, 0x0f);
|
||||
hdr.write_shift(2, 0xF004);
|
||||
hdr.write_shift(4, 0x28);
|
||||
/* [MS-ODRAW] 2.2.38 OfficeArtFSPGR */
|
||||
{
|
||||
hdr.write_shift(2, 0x01);
|
||||
hdr.write_shift(2, 0xF009);
|
||||
hdr.write_shift(4, 0x10);
|
||||
hdr.l += 16;
|
||||
}
|
||||
/* [MS-ODRAW] 2.2.40 OfficeArtFSP */
|
||||
{
|
||||
hdr.write_shift(2, 0x02);
|
||||
hdr.write_shift(2, 0xF00A);
|
||||
hdr.write_shift(4, 0x08);
|
||||
hdr.write_shift(4, baseid);
|
||||
hdr.write_shift(4, 0x05);
|
||||
}
|
||||
}
|
||||
}
|
||||
write_biff_rec(ba, 0x00EC, /* hdr */ _oasc ? bconcat([hdr, _oasc]) : hdr);
|
||||
}
|
||||
ba.push(pl.end());
|
||||
notes.forEach(function(n) { write_biff_rec(ba, 0x001C, n); });
|
||||
b8ocnts.push([baseid, comments.length + 1, b8oid]);
|
||||
++b8oid;
|
||||
}
|
||||
|
||||
function write_FONTS_biff8(ba, data, opts) {
|
||||
write_biff_rec(ba, 0x0031 /* Font */, write_Font({
|
||||
sz:12,
|
||||
@ -176,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));
|
||||
@ -185,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 */
|
||||
@ -218,9 +515,9 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
|
||||
var range = safe_decode_range(ws['!ref'] || "A1");
|
||||
var MAX_ROWS = b8 ? 65536 : 16384;
|
||||
if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
|
||||
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
|
||||
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV" + MAX_ROWS);
|
||||
range.e.c = Math.min(range.e.c, 0xFF);
|
||||
range.e.r = Math.min(range.e.c, MAX_ROWS-1);
|
||||
range.e.r = Math.min(range.e.r, MAX_ROWS-1);
|
||||
}
|
||||
|
||||
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
|
||||
@ -246,26 +543,26 @@ 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'] = [];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
|
||||
var comments = [];
|
||||
var row = [];
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
if(dense) row = ws["!data"][R] || [];
|
||||
rr = encode_row(R);
|
||||
for(C = range.s.c; C <= range.e.c; ++C) {
|
||||
ref = cols[C] + rr;
|
||||
var cell = dense ? row[C] : ws[ref];
|
||||
var cell = dense ? row[C] : ws[cols[C] + rr];
|
||||
if(!cell) continue;
|
||||
/* write cell */
|
||||
write_ws_biff8_cell(ba, cell, R, C, opts);
|
||||
if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
|
||||
if(b8 && cell.c) comments.push([ref, cell.c]);
|
||||
write_ws_biff8_cell(ba, cell, R, C, opts, date1904);
|
||||
if(b8 && cell.l) ws['!links'].push([cols[C] + rr, cell.l]);
|
||||
if(cell.c) comments.push([cell.c, R, C]);
|
||||
}
|
||||
}
|
||||
var cname/*:string*/ = _sheet.CodeName || _sheet.name || s;
|
||||
/* ... */
|
||||
// if(b8) comments.forEach(function(comment) { write_biff_rec(ba, 0x001c /* Note */, write_NoteSh(comment)); });
|
||||
if(b8) write_comments_biff8(ba, comments); else write_comments_biff2(ba, comments);
|
||||
/* ... */
|
||||
if(b8) write_biff_rec(ba, 0x023e /* Window2 */, write_Window2((_WB.Views||[])[0]));
|
||||
/* ... */
|
||||
@ -335,8 +632,10 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
|
||||
var C = buf_array();
|
||||
/* METADATA [MTRSettings] [ForceFullCalculation] */
|
||||
if(b8) write_biff_rec(C, 0x008C /* Country */, write_Country());
|
||||
/* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture *MSODRAWINGGROUP */
|
||||
/* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture */
|
||||
|
||||
/* BIFF8: MsoDrawingGroup [*Continue] */
|
||||
if(b8 && b8ocnts.length) write_biff_rec(C, 0x00EB /* MsoDrawingGroup */, write_MsoDrawingGroup());
|
||||
/* BIFF8: [SST *Continue] ExtSST */
|
||||
if(b8 && opts.Strings) write_biff_continue(C, 0x00FC /* SST */, write_SST(opts.Strings, opts));
|
||||
|
||||
@ -379,6 +678,7 @@ function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
|
||||
o.ssf = wb.SSF;
|
||||
}
|
||||
|
||||
b8oid = 1; b8ocnts = [];
|
||||
o.Strings = /*::((*/[]/*:: :any):SST)*/; o.Strings.Count = 0; o.Strings.Unique = 0;
|
||||
fix_write_opts(o);
|
||||
|
||||
@ -400,6 +700,9 @@ function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
|
||||
if(range.e.c > 255) { // note: 255 is IV
|
||||
if(typeof console != "undefined" && console.error) console.error("Worksheet '" + wb.SheetNames[i] + "' extends beyond column IV (255). Data may be lost.");
|
||||
}
|
||||
if(range.e.r > 65535) {
|
||||
if(typeof console != "undefined" && console.error) console.error("Worksheet '" + wb.SheetNames[i] + "' extends beyond row 65536. Data may be lost.");
|
||||
}
|
||||
}
|
||||
|
||||
var o = opts || {};
|
||||
|
@ -3,12 +3,12 @@ function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ {
|
||||
var opts = _opts || {};
|
||||
var dense = (opts.dense != null) ? opts.dense : DENSE;
|
||||
var ws/*:Worksheet*/ = ({}/*:any*/); if(dense) ws["!data"] = [];
|
||||
str = str.replace(/<!--.*?-->/g, "");
|
||||
str = str_remove_ng(str, "<!--", "-->");
|
||||
var mtch/*:any*/ = str.match(/<table/i);
|
||||
if(!mtch) throw new Error("Invalid HTML: could not find <table>");
|
||||
var mtch2/*:any*/ = str.match(/<\/table/i);
|
||||
var i/*:number*/ = mtch.index, j/*:number*/ = mtch2 && mtch2.index || str.length;
|
||||
var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
|
||||
var rows = split_regex(str.slice(i, j), /(:?<tr[^<>]*>)/i, "<tr>");
|
||||
var R = -1, C = 0, RS = 0, CS = 0;
|
||||
var range/*:Range*/ = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
|
||||
var merges/*:Array<Range>*/ = [];
|
||||
@ -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"] = escapehtml(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>';
|
||||
}
|
||||
@ -96,7 +99,7 @@ var HTML_BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export
|
||||
var HTML_END = '</body></html>';
|
||||
|
||||
function html_to_workbook(str/*:string*/, opts)/*:Workbook*/ {
|
||||
var mtch = str.match(/<table[\s\S]*?>[\s\S]*?<\/table>/gi);
|
||||
var mtch = str_match_xml_ig(str, "table");
|
||||
if(!mtch || mtch.length == 0) throw new Error("Invalid HTML: could not find <table>");
|
||||
if(mtch.length == 1) {
|
||||
var w = sheet_to_workbook(html_to_sheet(mtch[0], opts), opts);
|
||||
@ -119,9 +122,9 @@ function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workboo
|
||||
var header = o.header != null ? o.header : HTML_BEGIN;
|
||||
var footer = o.footer != null ? o.footer : HTML_END;
|
||||
var out/*:Array<string>*/ = [header];
|
||||
var r = decode_range(ws['!ref']);
|
||||
var r = decode_range(ws['!ref'] || "A1");
|
||||
out.push(make_html_preamble(ws, r, o));
|
||||
for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
|
||||
if(ws["!ref"]) for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
|
||||
out.push("</table>" + footer);
|
||||
return out.join("");
|
||||
}
|
||||
@ -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];
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ function parse_text_p(text/*:string*//*::, tag*/)/*:Array<any>*/ {
|
||||
.replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
|
||||
.replace(/<text:s\/>/g," ")
|
||||
.replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
|
||||
.replace(/<text:tab[^>]*\/>/g,"\t")
|
||||
.replace(/<text:tab[^<>]*\/>/g,"\t")
|
||||
.replace(/<text:line-break\/>/g,"\n");
|
||||
var v = unescapexml(fixed.replace(/<[^>]*>/g,""));
|
||||
var v = unescapexml(fixed.replace(/<[^<>]*>/g,""));
|
||||
|
||||
return [v];
|
||||
}
|
||||
@ -17,10 +17,10 @@ function parse_ods_styles(d/*:string*/, _opts, _nfm) {
|
||||
var number_format_map = _nfm || {};
|
||||
var str = xlml_normalize(d);
|
||||
xlmlregex.lastIndex = 0;
|
||||
str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
|
||||
str = remove_doctype(str_remove_ng(str, "<!--", "-->"));
|
||||
var Rn, NFtag, NF = "", tNF = "", y, etpos = 0, tidx = -1, infmt = false, payload = "";
|
||||
while((Rn = xlmlregex.exec(str))) {
|
||||
switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
|
||||
switch((Rn[3]=Rn[3].replace(/_[\s\S]*$/,""))) {
|
||||
/* Number Format Definitions */
|
||||
case 'number-style': // <number:number-style> 16.29.2
|
||||
case 'currency-style': // <number:currency-style> 16.29.8
|
||||
@ -248,8 +248,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 = {};
|
||||
@ -263,10 +263,9 @@ 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(/_.*$/,""))) {
|
||||
str = remove_doctype(str_remove_ng(str, "<!--", "-->"));
|
||||
while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_[\s\S]*$/,""))) {
|
||||
|
||||
case 'table': case '工作表': // 9.1.2 <table:table>
|
||||
if(Rn[1]==='/') {
|
||||
@ -334,7 +333,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;
|
||||
@ -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';
|
||||
@ -443,10 +446,17 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
|
||||
if(textR.length) /*::(*/comment/*:: :any)*/.R = textR;
|
||||
comment.a = creator;
|
||||
comments.push(comment);
|
||||
textp = oldtextp; textpidx = oldtextpidx; textR = oldtextR;
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
|
||||
state.push([Rn[3], false]);
|
||||
var annotag = parsexmltag(Rn[0], true);
|
||||
/* office:display TODO: check if there is a global override */
|
||||
if(!(annotag["display"] && parsexmlbool(annotag["display"]))) comments.hidden = true;
|
||||
oldtextp = textp; oldtextpidx = textpidx; oldtextR = textR;
|
||||
textp = ""; textpidx = 0; textR = [];
|
||||
}
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
|
||||
creator = ""; creatoridx = 0;
|
||||
textp = ""; textpidx = 0; textR = [];
|
||||
break;
|
||||
|
||||
case 'creator': // 4.3.2.7 <dc:creator>
|
||||
@ -572,9 +582,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
|
||||
case 'null-date': // 9.4.2 <table:null-date>
|
||||
tag = parsexmltag(Rn[0], false);
|
||||
switch(tag["date-value"]) {
|
||||
case "1904-01-01": WB.WBProps.date1904 = true;
|
||||
/* falls through */
|
||||
case "1900-01-01": baddate = 0;
|
||||
case "1904-01-01": WB.WBProps.date1904 = true; break;
|
||||
}
|
||||
break;
|
||||
|
||||
@ -628,10 +636,13 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
|
||||
case 'help-message': break; // 9.4.6 <table:
|
||||
case 'error-message': break; // 9.4.7 <table:
|
||||
case 'database-ranges': break; // 9.4.14 <table:database-ranges>
|
||||
|
||||
/* 9.5 Filters */
|
||||
case 'filter': break; // 9.5.2 <table:filter>
|
||||
case 'filter-and': break; // 9.5.3 <table:filter-and>
|
||||
case 'filter-or': break; // 9.5.4 <table:filter-or>
|
||||
case 'filter-condition': break; // 9.5.5 <table:filter-condition>
|
||||
case 'filter-set-item': break; // 9.5.6 <table:filter-condition>
|
||||
|
||||
case 'list-level-style-bullet': break; // 16.31 <text:
|
||||
case 'list-level-style-number': break; // 16.32 <text:
|
||||
|
@ -67,7 +67,7 @@ function write_number_format_ods(nf/*:string*/, nfidx/*:string*/)/*:string*/ {
|
||||
if((t=nf.match(/# (\?+)\/(\d+)/))) { payload += writextag("number:fraction", null, {"number:min-integer-digits":0, "number:min-numerator-digits": t[1].length, "number:denominator-value": +t[2]}); break j; }
|
||||
|
||||
/* percentages */
|
||||
if((t=nf.match(/(\d+)(|\.\d+)%/))) { type = "percentage"; payload += writextag("number:number", null, {"number:decimal-places": t[2] && t.length - 1 || 0, "number:min-decimal-places": t[2] && t.length - 1 || 0, "number:min-integer-digits": t[1].length }) + "<number:text>%</number:text>"; break j; }
|
||||
if((t=nf.match(/\b(\d+)(|\.\d+)%/))) { type = "percentage"; payload += writextag("number:number", null, {"number:decimal-places": t[2] && t.length - 1 || 0, "number:min-decimal-places": t[2] && t.length - 1 || 0, "number:min-integer-digits": t[1].length }) + "<number:text>%</number:text>"; break j; }
|
||||
|
||||
/* datetime */
|
||||
var has_time = false;
|
||||
@ -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,30 +184,34 @@ 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,
|
||||
"table:base-cell-address": odsref.replace(/[\.]?[^\.]*$/, ".$A$1")
|
||||
"table:base-cell-address": odsref.replace(/[\.][^\.]*$/, ".$A$1")
|
||||
});
|
||||
}).join("\n") + "\n </table:named-expressions>\n";
|
||||
}
|
||||
var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function() {
|
||||
/* 6.1.2 White Space Characters */
|
||||
var write_text_p = function(text/*:string*/)/*:string*/ {
|
||||
var write_text_p = function(text/*:string*/, span)/*:string*/ {
|
||||
return escapexml(text)
|
||||
.replace(/ +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
|
||||
.replace(/\t/g, "<text:tab/>")
|
||||
.replace(/\n/g, "</text:p><text:p>")
|
||||
.replace(/\n/g, span ? "<text:line-break/>": "</text:p><text:p>")
|
||||
.replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
|
||||
};
|
||||
|
||||
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');
|
||||
@ -236,7 +242,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));
|
||||
@ -265,13 +271,13 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
|
||||
ct['office:value-type'] = "string";
|
||||
break;
|
||||
case 'd':
|
||||
textp = (cell.w||(parseDate(cell.v).toISOString()));
|
||||
textp = (cell.w||(parseDate(cell.v, date1904).toISOString()));
|
||||
ct['office:value-type'] = "date";
|
||||
ct['office:date-value'] = (parseDate(cell.v).toISOString());
|
||||
ct['office:date-value'] = (parseDate(cell.v, date1904).toISOString());
|
||||
ct['table:style-name'] = "ce1";
|
||||
break;
|
||||
//case 'e':
|
||||
default: o.push(null_cell_xml); continue;
|
||||
//case 'e': // TODO: translate to ODS errors
|
||||
default: o.push(null_cell_xml); continue; // TODO: empty cell with comments
|
||||
}
|
||||
var text_p = write_text_p(textp);
|
||||
if(cell.l && cell.l.Target) {
|
||||
@ -282,7 +288,17 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
|
||||
text_p = writextag('text:a', text_p, {'xlink:href': _tgt.replace(/&/g, "&")});
|
||||
}
|
||||
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');
|
||||
}
|
||||
@ -348,6 +364,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
|
||||
wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
|
||||
if(!ws) return;
|
||||
var dense = (ws["!data"] != null);
|
||||
if(!ws["!ref"]) return;
|
||||
var range = decode_range(ws["!ref"]);
|
||||
for(var R = 0; R <= range.e.r; ++R) for(var C = 0; C <= range.e.c; ++C) {
|
||||
var c = dense ? (ws["!data"][R]||[])[C] : ws[encode_cell({r:R,c:C})];
|
||||
@ -419,7 +436,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
|
||||
|
||||
if(opts.bookType == "fods") {
|
||||
o.push('<office:document' + attr + fods + '>\n');
|
||||
o.push(write_meta_ods().replace(/<office:document-meta.*?>/, "").replace(/<\/office:document-meta>/, "") + "\n");
|
||||
o.push(write_meta_ods().replace(/<office:document-meta[^<>]*?>/, "").replace(/<\/office:document-meta>/, "") + "\n");
|
||||
// TODO: settings (equiv of settings.xml for ODS)
|
||||
} else o.push('<office:document-content' + attr + '>\n');
|
||||
// o.push(' <office:scripts/>\n');
|
||||
@ -427,7 +444,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
|
||||
o.push(' <office:body>\n');
|
||||
o.push(' <office:spreadsheet>\n');
|
||||
if(((wb.Workbook||{}).WBProps||{}).date1904) o.push(' <table:calculation-settings table:case-sensitive="false" table:search-criteria-must-apply-to-whole-cell="true" table:use-wildcards="true" table:use-regular-expressions="false" table:automatic-find-labels="false">\n <table:null-date table:date-value="1904-01-01"/>\n </table:calculation-settings>\n');
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts, nfs));
|
||||
for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts, nfs, ((wb.Workbook||{}).WBProps||{}).date1904));
|
||||
if((wb.Workbook||{}).Names) o.push(write_names_ods(wb.Workbook.Names, wb.SheetNames, -1));
|
||||
o.push(' </office:spreadsheet>\n');
|
||||
o.push(' </office:body>\n');
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -13,6 +13,13 @@ function safe_parse_wbrels(wbrels, sheets) {
|
||||
return !wbrels || wbrels.length === 0 ? null : wbrels;
|
||||
}
|
||||
|
||||
function parse_sheet_legacy_drawing(sheet, type, zip, path, idx, opts, wb, comments) {
|
||||
if(!sheet || !sheet['!legdrawel']) return;
|
||||
var dfile = resolve_path(sheet['!legdrawel'].Target, path);
|
||||
var draw = getzipstr(zip, dfile, true);
|
||||
if(draw) parse_vml(utf8read(draw), sheet, comments||[]);
|
||||
}
|
||||
|
||||
function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/*:number*/, sheetRels, sheets, stype/*:string*/, opts, wb, themes, styles) {
|
||||
try {
|
||||
sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
|
||||
@ -51,6 +58,7 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/
|
||||
}
|
||||
});
|
||||
if(tcomments && tcomments.length) sheet_insert_comments(_ws, tcomments, true, opts.people || []);
|
||||
parse_sheet_legacy_drawing(_ws, stype, zip, path, idx, opts, wb, comments);
|
||||
} catch(e) { if(opts.WTF) throw e; }
|
||||
}
|
||||
|
||||
@ -196,7 +204,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
||||
if(wbrels && wbrels[i]) {
|
||||
path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
|
||||
if(!safegetzipfile(zip, path)) path = wbrels[i][1];
|
||||
if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
|
||||
if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/[\S\s]*$/,"") + wbrels[i][1];
|
||||
stype = wbrels[i][2];
|
||||
} else {
|
||||
path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
|
||||
@ -249,7 +257,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
||||
if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
|
||||
else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
|
||||
}
|
||||
// TODO: pass back content types metdata for xlsm/xlsx resolution
|
||||
// TODO: pass back content types metadata for xlsm/xlsx resolution
|
||||
out.bookType = xlsb ? "xlsb" : "xlsx";
|
||||
return out;
|
||||
}
|
||||
|
@ -51,6 +51,9 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
|
||||
}
|
||||
|
||||
var people = ["SheetJ5"];
|
||||
opts.tcid = 0;
|
||||
|
||||
for(rId=1;rId <= wb.SheetNames.length; ++rId) {
|
||||
var wsrels = {'!id':{}};
|
||||
var ws = wb.Sheets[wb.SheetNames[rId-1]];
|
||||
@ -70,6 +73,17 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
var need_vml = false;
|
||||
var cf = "";
|
||||
if(comments && comments.length > 0) {
|
||||
var needtc = false;
|
||||
comments.forEach(function(carr) {
|
||||
carr[1].forEach(function(c) { if(c.T == true) needtc = true; });
|
||||
});
|
||||
if(needtc) {
|
||||
cf = "xl/threadedComments/threadedComment" + rId + ".xml";
|
||||
zip_add_file(zip, cf, write_tcmnt_xml(comments, people, opts));
|
||||
ct.threadedcomments.push(cf);
|
||||
add_rels(wsrels, -1, "../threadedComments/threadedComment" + rId + ".xml", RELS.TCMNT);
|
||||
}
|
||||
|
||||
cf = "xl/comments" + rId + "." + wbext;
|
||||
zip_add_file(zip, cf, write_comments_bin(comments, opts));
|
||||
ct.comments.push(cf);
|
||||
@ -125,6 +139,13 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
|
||||
ct.metadata.push(f);
|
||||
add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA);
|
||||
|
||||
if(people.length > 1) {
|
||||
f = "xl/persons/person.xml";
|
||||
zip_add_file(zip, f, write_people_xml(people, opts));
|
||||
ct.people.push(f);
|
||||
add_rels(opts.wbrels, -1, "persons/person.xml", RELS.PEOPLE);
|
||||
}
|
||||
|
||||
zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
|
||||
zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
|
||||
zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
|
||||
|
@ -15,7 +15,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;
|
||||
@ -24,7 +24,12 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
|
||||
switch(val.t){
|
||||
case 'z': if(v == null) break; continue;
|
||||
case 'e': v = (v == 0 ? null : void 0); break;
|
||||
case 's': case 'd': case 'b': case 'n': break;
|
||||
case 's': case 'b':
|
||||
case 'n': if(!val.z || !fmt_is_date(val.z)) break;
|
||||
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
|
||||
if(typeof v == "number") break;
|
||||
/* falls through */
|
||||
case 'd': if(!(o && (o.UTC||(o.raw === false)))) v = utc_to_local(new Date(v)); break;
|
||||
default: throw new Error('unrecognized type ' + val.t);
|
||||
}
|
||||
if(hdr[C] != null) {
|
||||
@ -34,7 +39,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
|
||||
else if(raw && v === null) row[hdr[C]] = null;
|
||||
else continue;
|
||||
} else {
|
||||
row[hdr[C]] = raw && (val.t !== "n" || (val.t === "n" && o.rawNumbers !== false)) ? v : format_cell(val,v,o);
|
||||
row[hdr[C]] = (val.t === 'n' && typeof o.rawNumbers === 'boolean' ? o.rawNumbers : raw) ? v : format_cell(val, v, o);
|
||||
}
|
||||
if(v != null) isempty = false;
|
||||
}
|
||||
@ -99,7 +104,7 @@ function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) {
|
||||
}
|
||||
|
||||
var qreg = /"/g;
|
||||
function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, fs/*:number*/, rs/*:number*/, FS/*:string*/, o/*:Sheet2CSVOpts*/)/*:?string*/ {
|
||||
function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, fs/*:number*/, rs/*:number*/, FS/*:string*/, w/*:number*/, o/*:Sheet2CSVOpts*/)/*:?string*/ {
|
||||
var isempty = true;
|
||||
var row/*:Array<string>*/ = [], txt = "", rr = encode_row(R);
|
||||
var dense = sheet["!data"] != null;
|
||||
@ -112,7 +117,7 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr
|
||||
isempty = false;
|
||||
txt = ''+(o.rawNumbers && val.t == "n" ? val.v : format_cell(val, null, o));
|
||||
for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34 || o.forceQuotes) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
|
||||
if(txt == "ID") txt = '"ID"';
|
||||
if(txt == "ID" && w == 0 && row.length == 0) txt = '"ID"';
|
||||
} else if(val.f != null && !val.F) {
|
||||
isempty = false;
|
||||
txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
|
||||
@ -120,6 +125,7 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr
|
||||
/* NOTE: Excel CSV does not support array formulae */
|
||||
row.push(txt);
|
||||
}
|
||||
if(o.strip) while(row[row.length - 1] === "") --row.length;
|
||||
if(o.blankrows === false && isempty) return null;
|
||||
return row.join(FS);
|
||||
}
|
||||
@ -131,7 +137,6 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ {
|
||||
var r = safe_decode_range(sheet["!ref"]);
|
||||
var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
|
||||
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
|
||||
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
|
||||
var row = "", cols/*:Array<string>*/ = [];
|
||||
var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
|
||||
var rowinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!rows"] || [];
|
||||
@ -139,9 +144,8 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ {
|
||||
var w = 0;
|
||||
for(var R = r.s.r; R <= r.e.r; ++R) {
|
||||
if ((rowinfo[R]||{}).hidden) continue;
|
||||
row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
|
||||
row = make_csv_row(sheet, r, R, cols, fs, rs, FS, w, o);
|
||||
if(row == null) { continue; }
|
||||
if(o.strip) row = row.replace(endregex,"");
|
||||
if(row || (o.blankrows !== false)) out.push((w++ ? RS : "") + row);
|
||||
}
|
||||
return out.join("");
|
||||
@ -234,6 +238,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]);
|
||||
}
|
||||
@ -291,9 +296,11 @@ function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
|
||||
} else throw new Error("Cannot find sheet |" + sh + "|");
|
||||
}
|
||||
|
||||
/* simple blank workbook object */
|
||||
function book_new()/*:Workbook*/ {
|
||||
return { SheetNames: [], Sheets: {} };
|
||||
/* simple blank or single-sheet workbook object */
|
||||
function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ {
|
||||
var wb = { SheetNames: [], Sheets: {} };
|
||||
if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
|
||||
return wb;
|
||||
}
|
||||
|
||||
/* add a worksheet to the end of a given workbook */
|
||||
@ -301,10 +308,10 @@ function book_append_sheet(wb/*:Workbook*/, ws/*:Worksheet*/, name/*:?string*/,
|
||||
var i = 1;
|
||||
if(!name) for(; i <= 0xFFFF; ++i, name = undefined) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
|
||||
if(!name || wb.SheetNames.length >= 0xFFFF) throw new Error("Too many worksheets");
|
||||
if(roll && wb.SheetNames.indexOf(name) >= 0) {
|
||||
var m = name.match(/(^.*?)(\d+)$/);
|
||||
i = m && +m[2] || 0;
|
||||
var root = m && m[1] || name;
|
||||
if(roll && wb.SheetNames.indexOf(name) >= 0 && name.length < 32) {
|
||||
var m = name.match(/\d+$/); // at this point, name length is capped at 32
|
||||
i = m && +m[0] || 0;
|
||||
var root = m && name.slice(0, m.index) || name;
|
||||
for(++i; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = root + i) == -1) break;
|
||||
}
|
||||
check_ws_name(name);
|
||||
|
@ -9,6 +9,7 @@ var utils/*:any*/ = {
|
||||
decode_cell: decode_cell,
|
||||
decode_range: decode_range,
|
||||
format_cell: format_cell,
|
||||
sheet_new: sheet_new,
|
||||
sheet_add_aoa: sheet_add_aoa,
|
||||
sheet_add_json: sheet_add_json,
|
||||
sheet_add_dom: sheet_add_dom,
|
||||
|
160
bits/97_node.js
160
bits/97_node.js
@ -8,7 +8,6 @@ function write_csv_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
|
||||
var r = safe_decode_range(sheet["!ref"]);
|
||||
var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
|
||||
var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
|
||||
var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
|
||||
var row/*:?string*/ = "", cols/*:Array<string>*/ = [];
|
||||
var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
|
||||
var rowinfo/*:Array<RowInfo>*/ = o.skipHidden && sheet["!rows"] || [];
|
||||
@ -20,9 +19,8 @@ function write_csv_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
|
||||
while(R <= r.e.r) {
|
||||
++R;
|
||||
if ((rowinfo[R-1]||{}).hidden) continue;
|
||||
row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o);
|
||||
row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, w, o);
|
||||
if(row != null) {
|
||||
if(o.strip) row = row.replace(endregex,"");
|
||||
if(row || (o.blankrows !== false)) return stream.push((w++ ? RS : "") + row);
|
||||
}
|
||||
}
|
||||
@ -118,9 +116,165 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
|
||||
return stream;
|
||||
}
|
||||
|
||||
function write_xlml_stream(wb/*:Workbook*/, o/*:?Sheet2XLMLOpts*/) {
|
||||
var stream = _Readable();
|
||||
var opts = o == null ? {} : o;
|
||||
if(!wb.SSF) wb.SSF = dup(table_fmt);
|
||||
if(wb.SSF) {
|
||||
make_ssf(); SSF_load_table(wb.SSF);
|
||||
// $FlowIgnore
|
||||
opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
|
||||
opts.ssf = wb.SSF;
|
||||
opts.cellXfs = [];
|
||||
get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
|
||||
}
|
||||
|
||||
/* do one pass to determine styles since they must be added before tables */
|
||||
wb.SheetNames.forEach(function(n) {
|
||||
var ws = wb.Sheets[n];
|
||||
if(!ws || !ws["!ref"]) return;
|
||||
var range = decode_range(ws["!ref"]);
|
||||
var dense = ws["!data"] != null;
|
||||
var ddata = dense ? ws["!data"] : [];
|
||||
var addr = {r:0,c:0};
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
addr.r = R;
|
||||
if(dense && !ddata[R]) continue;
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
addr.c = C;
|
||||
var cell = dense ? ddata[R][C] : ws[encode_col(C) + encode_row(R)];
|
||||
if(!cell) continue;
|
||||
if(cell.t == "d" && cell.z == null) { cell = dup(cell); cell.z = table_fmt[14]; }
|
||||
void get_cell_style(opts.cellXfs, cell, opts);
|
||||
}
|
||||
}
|
||||
});
|
||||
var sty = write_sty_xlml(wb, opts);
|
||||
|
||||
var stage = 0, wsidx = 0, ws = wb.Sheets[wb.SheetNames[wsidx]], range = safe_decode_range(ws), R = -1, T = false;
|
||||
|
||||
var marr = [], mi = 0, dense = false, darr = [], addr = {r:0,c:0};
|
||||
|
||||
stream._read = function() { switch(stage) {
|
||||
/* header */
|
||||
case 0: {
|
||||
stage = 1;
|
||||
stream.push(XML_HEADER);
|
||||
stream.push("<Workbook" + wxt_helper({
|
||||
'xmlns': XLMLNS.ss,
|
||||
'xmlns:o': XLMLNS.o,
|
||||
'xmlns:x': XLMLNS.x,
|
||||
'xmlns:ss': XLMLNS.ss,
|
||||
'xmlns:dt': XLMLNS.dt,
|
||||
'xmlns:html': XLMLNS.html
|
||||
}) + ">");
|
||||
} break;
|
||||
|
||||
/* preamble */
|
||||
case 1: {
|
||||
stage = 2;
|
||||
stream.push(write_props_xlml(wb, opts));
|
||||
stream.push(write_wb_xlml(wb, opts));
|
||||
} break;
|
||||
|
||||
/* style and name tables */
|
||||
case 2: {
|
||||
stage = 3;
|
||||
stream.push(sty);
|
||||
stream.push(write_names_xlml(wb, opts));
|
||||
} break;
|
||||
|
||||
/* worksheet preamble */
|
||||
case 3: {
|
||||
T = false;
|
||||
if(wsidx >= wb.SheetNames.length) { stage = -1; stream.push(""); break; }
|
||||
|
||||
stream.push("<Worksheet" + wxt_helper({ "ss:Name": escapexml(wb.SheetNames[wsidx])}) + ">");
|
||||
|
||||
ws = wb.Sheets[wb.SheetNames[wsidx]];
|
||||
if(!ws) { stream.push("</Worksheet>"); return void ++wsidx; }
|
||||
|
||||
var names = write_ws_xlml_names(ws, opts, wsidx, wb);
|
||||
if(names.length) stream.push("<Names>" + names + "</Names>");
|
||||
|
||||
if(!ws["!ref"]) return (stage = 5);
|
||||
range = safe_decode_range(ws["!ref"]);
|
||||
R = range.s.r;
|
||||
stage = 4;
|
||||
} break;
|
||||
|
||||
/* worksheet intramble */
|
||||
case 4: {
|
||||
if(R < 0 || R > range.e.r) { stream.push(T ? "</Table>" : ""); return void (stage = 5); }
|
||||
|
||||
if(R <= range.s.r) {
|
||||
if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
|
||||
process_col(n);
|
||||
var w = !!n.width;
|
||||
var p = col_obj_w(i, n);
|
||||
var k/*:any*/ = {"ss:Index":i+1};
|
||||
if(w) k['ss:Width'] = width2px(p.width);
|
||||
if(n.hidden) k['ss:Hidden']="1";
|
||||
if(!T) { T = true; stream.push("<Table>"); }
|
||||
stream.push(writextag("Column",null,k));
|
||||
});
|
||||
dense = ws["!data"] != null;
|
||||
if(dense) darr = ws["!data"];
|
||||
addr.r = addr.c = 0;
|
||||
}
|
||||
|
||||
/* process 10 rows per invocation */
|
||||
for(var cnt = 0; R <= range.e.r && cnt < 10; ++R, ++cnt) {
|
||||
var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
|
||||
addr.r = R;
|
||||
if(!(dense && !darr[R])) for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
addr.c = C;
|
||||
var skip = false;
|
||||
for(mi = 0; mi != marr.length; ++mi) {
|
||||
if(marr[mi].s.c > C) continue;
|
||||
if(marr[mi].s.r > R) continue;
|
||||
if(marr[mi].e.c < C) continue;
|
||||
if(marr[mi].e.r < R) continue;
|
||||
if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
|
||||
break;
|
||||
}
|
||||
if(skip) continue;
|
||||
var ref = encode_col(C) + encode_row(R), cell = dense ? darr[R][C] : ws[ref];
|
||||
row.push(write_ws_xlml_cell(cell, ref, ws, opts, wsidx, wb, addr));
|
||||
}
|
||||
row.push("</Row>");
|
||||
if(row.length > 2) {
|
||||
if(!T) { T = true; stream.push("<Table>"); }
|
||||
stream.push(row.join(""));
|
||||
}
|
||||
}
|
||||
} break;
|
||||
|
||||
/* worksheet postamble */
|
||||
case 5: {
|
||||
stream.push(write_ws_xlml_wsopts(ws, opts, wsidx, wb));
|
||||
if(ws && ws["!autofilter"]) stream.push('<AutoFilter x:Range="' + a1_to_rc(fix_range(ws["!autofilter"].ref), {r:0,c:0}) + '" xmlns="urn:schemas-microsoft-com:office:excel"></AutoFilter>');
|
||||
stream.push("</Worksheet>");
|
||||
wsidx++; R = -1;
|
||||
return void (stage = 3);
|
||||
}
|
||||
|
||||
/* footer */
|
||||
case -1: {
|
||||
stage = -2;
|
||||
stream.push("</Workbook>");
|
||||
} break;
|
||||
|
||||
/* exeunt */
|
||||
case -2: stream.push(null); break;
|
||||
}};
|
||||
return stream;
|
||||
}
|
||||
|
||||
var __stream = {
|
||||
to_json: write_json_stream,
|
||||
to_html: write_html_stream,
|
||||
to_csv: write_csv_stream,
|
||||
to_xlml: write_xlml_stream,
|
||||
set_readable: set_readable
|
||||
};
|
||||
|
32
dist/xlsx.core.min.js
generated
vendored
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
2
dist/xlsx.core.min.map
generated
vendored
File diff suppressed because one or more lines are too long
6474
dist/xlsx.extendscript.js
generated
vendored
6474
dist/xlsx.extendscript.js
generated
vendored
File diff suppressed because it is too large
Load Diff
35
dist/xlsx.full.min.js
generated
vendored
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
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
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
2
dist/xlsx.mini.min.map
generated
vendored
File diff suppressed because one or more lines are too long
@ -45,10 +45,35 @@ 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;
|
||||
input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/, "").replace(/[^\w\+\/\=]/g, "");
|
||||
if (input.slice(0, 5) == "data:") {
|
||||
var i = input.slice(0, 1024).indexOf(";base64,");
|
||||
if (i > -1)
|
||||
input = input.slice(i + 8);
|
||||
}
|
||||
input = input.replace(/[^\w\+\/\=]/g, "");
|
||||
for (var i = 0; i < input.length; ) {
|
||||
e1 = Base64_map.indexOf(input.charAt(i++));
|
||||
e2 = Base64_map.indexOf(input.charAt(i++));
|
||||
|
@ -37,11 +37,33 @@ function Base64_encode_pass(input: string): string {
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function Base64_encode_arr(input: Uint8Array|number[]): string {
|
||||
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: string): string {
|
||||
var o = "";
|
||||
var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
|
||||
input = input.replace(/^data:([^\/]+\/[^\/]+)?;base64\,/,'')
|
||||
.replace(/[^\w\+\/\=]/g, "")
|
||||
if(input.slice(0,5) == "data:") {
|
||||
var i = input.slice(0, 1024).indexOf(";base64,");
|
||||
if(i > -1) input = input.slice(i+8);
|
||||
}
|
||||
input = input.replace(/[^\w\+\/\=]/g, "");
|
||||
for(var i = 0; i < input.length;) {
|
||||
e1 = Base64_map.indexOf(input.charAt(i++));
|
||||
e2 = Base64_map.indexOf(input.charAt(i++));
|
||||
|
@ -17,7 +17,7 @@ function rtf_to_sheet_str(str, opts) {
|
||||
var dense = o.dense;
|
||||
if (dense)
|
||||
ws["!data"] = [];
|
||||
var rows = str.match(/\\trowd[\s\S]*?\\row\b/g);
|
||||
var rows = str_match_ng(str, "\\trowd", "\\row");
|
||||
if (!rows)
|
||||
throw new Error("RTF missing table");
|
||||
var range = { s: { c: 0, r: 0 }, e: { c: 0, r: rows.length - 1 } };
|
||||
|
@ -31,7 +31,7 @@ function rtf_to_sheet_str(str: string, opts: ParsingOptions): WorkSheet {
|
||||
var dense = o.dense;
|
||||
if(dense) ws["!data"] = [];
|
||||
|
||||
var rows = str.match(/\\trowd[\s\S]*?\\row\b/g);
|
||||
var rows = str_match_ng(str, "\\trowd", "\\row");
|
||||
if(!rows) throw new Error("RTF missing table");
|
||||
var range: Range = {s: {c:0, r:0}, e: {c:0, r:rows.length - 1}};
|
||||
var row: CellObject[] = [];
|
||||
|
@ -13,7 +13,7 @@ function fill_vba_xls(cfb, vba) {
|
||||
vba.FullPaths.forEach(function(p, i) {
|
||||
if (i == 0)
|
||||
return;
|
||||
var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
|
||||
var newpath = p.replace(/^[\/]*[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
|
||||
if (newpath.slice(-1) !== "/")
|
||||
CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
|
||||
});
|
||||
|
@ -16,7 +16,7 @@ function make_vba_xls(cfb: CFBModule.CFB$Container) {
|
||||
function fill_vba_xls(cfb: CFBModule.CFB$Container, vba: CFBModule.CFB$Container): void {
|
||||
vba.FullPaths.forEach(function(p, i) {
|
||||
if(i == 0) return;
|
||||
var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
|
||||
var newpath = p.replace(/^[\/]*[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
|
||||
if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
|
||||
});
|
||||
}
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,16 +3,18 @@
|
||||
|
||||
/* 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 } from '../';
|
||||
import type { utils } from "../";
|
||||
import { WorkBook, WorkSheet, Range, CellObject, ParsingOptions, WritingOptions, DenseWorkSheet, Comments } from '../';
|
||||
import type { utils, NumberFormat } from "../";
|
||||
|
||||
declare var encode_col: typeof utils.encode_col;
|
||||
declare var encode_row: typeof utils.encode_row;
|
||||
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 sheet_to_json: typeof utils.sheet_to_json;
|
||||
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 "../../";
|
||||
@ -389,6 +391,14 @@ interface RichText {
|
||||
l?: string;
|
||||
}
|
||||
|
||||
/** IWA tree-style comment */
|
||||
interface IWAComment {
|
||||
/** text */
|
||||
t?: string;
|
||||
/** author */
|
||||
a?: string;
|
||||
replies?: IWAComment[];
|
||||
}
|
||||
/** .TST.DataStore */
|
||||
interface DataLUT {
|
||||
/** shared string table */
|
||||
@ -403,8 +413,10 @@ interface DataLUT {
|
||||
fmla: ProtoMessage[];
|
||||
/** formula errors */
|
||||
ferr: ProtoMessage[];
|
||||
/** comment table */
|
||||
cmnt: IWAComment[];
|
||||
}
|
||||
var numbers_lut_new = (): DataLUT => ({ sst: [], rsst: [], ofmt: [], nfmt: [], fmla: [], ferr: [] });
|
||||
var numbers_lut_new = (): DataLUT => ({ sst: [], rsst: [], ofmt: [], nfmt: [], fmla: [], ferr: [], cmnt: [] });
|
||||
|
||||
function numbers_format_cell(cell: CellObject, t: number, flags: number, ofmt: ProtoMessage, nfmt: ProtoMessage): void {
|
||||
var ctype = t & 0xFF, ver = t >> 8;
|
||||
@ -478,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;
|
||||
@ -491,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;
|
||||
@ -505,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
|
||||
@ -525,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; }
|
||||
|
||||
@ -552,10 +567,13 @@ function parse_new_storage(buf: Uint8Array, lut: DataLUT): CellObject | void {
|
||||
var ret: CellObject;
|
||||
var t = buf[1];
|
||||
switch(t) {
|
||||
case 0: return void 0; // return { t: "z" }; // blank?
|
||||
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
|
||||
@ -578,6 +596,10 @@ function parse_new_storage(buf: Uint8Array, lut: DataLUT): CellObject | void {
|
||||
if(fields & 0x07E000) { if(zidx == -1) zidx = dv.getUint32(doff, true); doff += 4; }
|
||||
|
||||
// 0x080000 comment
|
||||
if(fields & 0x080000) {
|
||||
var cmntidx = dv.getUint32(doff, true); doff += 4;
|
||||
if(lut.cmnt[cmntidx]) ret.c = iwa_to_s5s_comment(lut.cmnt[cmntidx]);
|
||||
}
|
||||
// 0x100000 warning
|
||||
|
||||
if(zidx > -1) numbers_format_cell(ret, t | (5<<8), fields >> 13, lut.ofmt[zidx], lut.nfmt[zidx] );
|
||||
@ -586,59 +608,89 @@ function parse_new_storage(buf: Uint8Array, lut: DataLUT): CellObject | void {
|
||||
}
|
||||
|
||||
/** Write a cell "new storage" (version 5) */
|
||||
function write_new_storage(cell: CellObject, sst: string[], rsst: RichText[]): Uint8Array {
|
||||
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
|
||||
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); flags |= 1; l += 16; break;
|
||||
case "b": out[1] = 6; dv.setFloat64(l, cell.v ? 1 : 0, true); flags |= 2; l += 8; 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);
|
||||
if(cell.l) {
|
||||
var irsst = rsst.findIndex(v => v.v == s && v.l == cell.l?.Target);
|
||||
if(irsst == -1) rsst[irsst = rsst.length] = { v: s , l: cell.l.Target };
|
||||
out[1] = 9; dv.setUint32(l, irsst, true); flags |= 0x10; l += 4;
|
||||
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 |= 0x10; l += 4;
|
||||
} else {
|
||||
var isst = sst.indexOf(s);
|
||||
if(isst == -1) sst[isst = sst.length] = s;
|
||||
out[1] = 3; dv.setUint32(l, isst, true); flags |= 8; l += 4;
|
||||
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 |= 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;
|
||||
}
|
||||
dv.setUint32(8, flags, true);
|
||||
if(cell.c) {
|
||||
lut.cmnt.push(s5s_to_iwa_comment(cell.c));
|
||||
dv.setUint32(l, lut.cmnt.length - 1, true); fields |= 0x80000; l += 4;
|
||||
}
|
||||
dv.setUint32(8, fields, true);
|
||||
return out[subarray](0, l);
|
||||
}
|
||||
/** Write a cell "old storage" (version 4) */
|
||||
function write_old_storage(cell: CellObject, sst: string[], rsst: RichText[]): Uint8Array {
|
||||
var out = new Uint8Array(32), dv = u8_to_dataview(out), l = 12, flags = 0;
|
||||
function write_old_storage(cell: CellObject, lut: DataLUT): Uint8Array {
|
||||
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": out[1] = 2; dv.setFloat64(l, cell.v as number, true); flags |= 0x20; l += 8; break;
|
||||
case "b": out[1] = 6; dv.setFloat64(l, cell.v ? 1 : 0, true); flags |= 0x20; l += 8; break;
|
||||
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 = rsst.findIndex(v => v.v == s && v.l == cell.l?.Target);
|
||||
if(irsst == -1) rsst[irsst = rsst.length] = { v: s, l: cell.l.Target };
|
||||
out[1] = 9; dv.setUint32(l, irsst, true); flags |= 0x200; l += 4;
|
||||
} else {
|
||||
var isst = sst.indexOf(s);
|
||||
if(isst == -1) sst[isst = sst.length] = s;
|
||||
out[1] = 3; dv.setUint32(l, isst, true); flags |= 0x10; l += 4;
|
||||
}
|
||||
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;
|
||||
}
|
||||
dv.setUint32(8, flags, true);
|
||||
if(cell.c) {
|
||||
/* NOTE: THIS ASSUMES write_new_storage was called */
|
||||
dv.setUint32(l, lut.cmnt.length - 1, true); fields |= 0x1000; l += 4;
|
||||
}
|
||||
switch(cell.t) {
|
||||
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": {
|
||||
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;
|
||||
}
|
||||
dv.setUint32(8, fields, true);
|
||||
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]}`);
|
||||
}
|
||||
}
|
||||
@ -655,8 +707,7 @@ function parse_TSP_Reference(buf: Uint8Array): number {
|
||||
}
|
||||
/** Write .TSP.Reference */
|
||||
function write_TSP_Reference(idx: number): Uint8Array {
|
||||
return write_shallow([
|
||||
[],
|
||||
return write_shallow([ [],
|
||||
[ { type: 0, data: write_varint49(idx) } ]
|
||||
]);
|
||||
}
|
||||
@ -736,6 +787,11 @@ function parse_TST_TableDataList(M: MessageSpace, root: IWAMessage): any[] {
|
||||
} break;
|
||||
case 2: data[key] = parse_shallow(le[6][0].data); break;
|
||||
case 3: data[key] = parse_shallow(le[5][0].data); break;
|
||||
case 10: {
|
||||
// .TSD.CommentStorageArchive
|
||||
var cs = M[parse_TSP_Reference(le[10][0].data)][0];
|
||||
data[key] = parse_TSD_CommentStorageArchive(M, cs.data);
|
||||
} break;
|
||||
default: throw type;
|
||||
}
|
||||
});
|
||||
@ -804,8 +860,50 @@ function parse_TST_Tile(M: MessageSpace, root: IWAMessage): TileInfo {
|
||||
};
|
||||
}
|
||||
|
||||
/** Parse .TSD.CommentStorageArchive (3056) */
|
||||
function parse_TSD_CommentStorageArchive(M: MessageSpace, data: Uint8Array): IWAComment {
|
||||
var out: IWAComment = { t: "", a: ""};
|
||||
var csp = parse_shallow(data);
|
||||
if(csp?.[1]?.[0]?.data) out.t = u8str(csp?.[1]?.[0]?.data) || "";
|
||||
if(csp?.[3]?.[0]?.data) {
|
||||
/* .TSK.AnnotationAuthorArchive (212) */
|
||||
var as = M[parse_TSP_Reference(csp?.[3]?.[0]?.data)][0];
|
||||
var asp = parse_shallow(as.data);
|
||||
if(asp[1]?.[0]?.data) out.a = u8str(asp[1][0].data)
|
||||
}
|
||||
if(csp?.[4]) {
|
||||
out.replies = [];
|
||||
csp[4].forEach(pi => {
|
||||
var cs = M[parse_TSP_Reference(pi.data)][0];
|
||||
out.replies!.push(parse_TSD_CommentStorageArchive(M, cs.data));
|
||||
});
|
||||
}
|
||||
return out;
|
||||
}
|
||||
/** Create SheetJS threaded comment structure from IWA comment */
|
||||
function iwa_to_s5s_comment(iwa: IWAComment): Comments {
|
||||
var out: Comments = [];
|
||||
out.push({t: iwa.t||"", a: iwa.a, T: iwa.replies && (iwa.replies.length > 0) });
|
||||
/* TODO: do apps support a tree of replies? */
|
||||
if(iwa.replies) iwa.replies.forEach(reply => {
|
||||
out.push({t: reply.t ||"", a: reply.a, T:true });
|
||||
});
|
||||
return out;
|
||||
}
|
||||
/** Create IWA comment from SheetJS threaded comment structure */
|
||||
function s5s_to_iwa_comment(s5s: Comments): IWAComment {
|
||||
var out: IWAComment = {a: "", t:"", replies:[]};
|
||||
for(var i = 0; i < s5s.length; ++i) {
|
||||
if(i == 0) { out.a = s5s[i].a; out.t = s5s[i].t; }
|
||||
else {
|
||||
out.replies!.push({a: s5s[i].a, t: s5s[i].t});
|
||||
}
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
||||
/** 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;
|
||||
@ -822,13 +920,24 @@ function parse_TST_TableModelArchive(M: MessageSpace, root: IWAMessage, ws: Work
|
||||
if(store[11]?.[0]) lut.ofmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[11][0].data)][0]);
|
||||
if(store[12]?.[0]) lut.ferr = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[12][0].data)][0]);
|
||||
if(store[17]?.[0]) lut.rsst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]);
|
||||
if(store[19]?.[0]) lut.cmnt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[19][0].data)][0]);
|
||||
if(store[22]?.[0]) lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]);
|
||||
|
||||
// .TST.TileStorage
|
||||
var tile = parse_shallow(store[3][0].data);
|
||||
var _R = 0;
|
||||
/* TODO: should this list be sorted by id ? */
|
||||
tile[1].forEach(t => {
|
||||
|
||||
// .TST.TableRBTree
|
||||
if(!store[9]?.[0]) throw "NUMBERS file missing row tree";
|
||||
var rtt = parse_shallow(store[9][0].data)[1].map(p => parse_shallow(p.data));
|
||||
|
||||
/* TODO: check examples with ctt */
|
||||
rtt.forEach(kv => {
|
||||
// .TST.TableRBTree.Node
|
||||
_R = varint_to_i32(kv[1][0].data);
|
||||
var tidx = varint_to_i32(kv[2][0].data);
|
||||
var t = tile[1][tidx];
|
||||
if(!t) throw "NUMBERS missing tile " + tidx;
|
||||
var tl = (parse_shallow(t.data));
|
||||
// var id = varint_to_i32(tl[1][0].data);
|
||||
var ref = M[parse_TSP_Reference(tl[2][0].data)][0];
|
||||
@ -837,7 +946,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] = [];
|
||||
@ -878,7 +987,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;
|
||||
}
|
||||
|
||||
@ -906,6 +1015,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");
|
||||
|
||||
@ -973,7 +1083,7 @@ interface DependentInfo {
|
||||
type: number;
|
||||
}
|
||||
/** Write .TST.TileRowInfo */
|
||||
function write_TST_TileRowInfo(data: CellObject[], SST: string[], RSST: RichText[], wide: boolean): ProtoMessage {
|
||||
function write_TST_TileRowInfo(data: CellObject[], lut: DataLUT, wide: boolean): ProtoMessage {
|
||||
var tri: ProtoMessage = [
|
||||
[],
|
||||
[ { type: 0, data: write_varint49(0) }],
|
||||
@ -1005,25 +1115,25 @@ function write_TST_TileRowInfo(data: CellObject[], SST: string[], RSST: RichText
|
||||
var _dv = u8_to_dataview(tri[4][0].data), _last_offset = 0, _cell_storage: Uint8Array[] = [];
|
||||
var width = wide ? 4 : 1;
|
||||
for(var C = 0; C < data.length; ++C) {
|
||||
if(data[C] == null || data[C].t == "z" || data[C].t == "e") { dv.setUint16(C*2, 0xFFFF, true); _dv.setUint16(C*2, 0xFFFF); continue; }
|
||||
/* TODO: serialize errors */
|
||||
if(data[C] == null || (data[C].t == "z" && !data[C].c?.length) || data[C].t == "e") { dv.setUint16(C*2, 0xFFFF, true); _dv.setUint16(C*2, 0xFFFF); continue; }
|
||||
dv.setUint16(C*2, last_offset / width, true);
|
||||
/*if(!wide)*/ _dv.setUint16(C*2, _last_offset / width, true);
|
||||
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()}, SST, RSST);
|
||||
/*if(!wide)*/ _celload = write_old_storage({t: "s", v: (data[C].v as Date).toISOString()}, SST, RSST);
|
||||
celload = write_new_storage(data[C], lut);
|
||||
/*if(!wide)*/ _celload = write_old_storage(data[C], lut);
|
||||
break;
|
||||
}
|
||||
/* TODO: can esbuild preserve falls through comments ? */
|
||||
celload = write_new_storage(data[C], SST, RSST);
|
||||
/*if(!wide)*/ _celload = write_old_storage(data[C], SST, RSST);
|
||||
celload = write_new_storage(data[C], lut);
|
||||
/*if(!wide)*/ _celload = write_old_storage(data[C], lut);
|
||||
break;
|
||||
case "s": case "n": case "b":
|
||||
celload = write_new_storage(data[C], SST, RSST);
|
||||
/*if(!wide)*/ _celload = write_old_storage(data[C], SST, RSST);
|
||||
case "s": case "n": case "b": case "z":
|
||||
celload = write_new_storage(data[C], lut);
|
||||
/*if(!wide)*/ _celload = write_old_storage(data[C], lut);
|
||||
break;
|
||||
default:
|
||||
throw new Error("Unsupported value " + data[C]);
|
||||
@ -1102,6 +1212,27 @@ function build_numbers_deps(cfb: CFB$Container): Dependents {
|
||||
return dependents;
|
||||
}
|
||||
|
||||
/** Generate .TSP.Color from r/g/b (0-255) */
|
||||
function write_TSP_Color_RGB(r: number, g: number, b: number): Uint8Array { return write_shallow([[],
|
||||
[{ type: 0, data: write_varint49(1) }],
|
||||
[],
|
||||
[{ type: 5, data: new Uint8Array(Float32Array.from([r/255]).buffer)}],
|
||||
[{ type: 5, data: new Uint8Array(Float32Array.from([g/255]).buffer)}],
|
||||
[{ type: 5, data: new Uint8Array(Float32Array.from([b/255]).buffer)}],
|
||||
[{ type: 5, data: new Uint8Array(Float32Array.from([1]).buffer)}],
|
||||
[], [], [], [], [],
|
||||
[{ type: 0, data: write_varint49(1) }]
|
||||
]); }
|
||||
|
||||
function get_author_color(n: number): Uint8Array {
|
||||
switch(n) {
|
||||
case 0: return write_TSP_Color_RGB(0x63, 0xDE, 0xAB);
|
||||
case 1: return write_TSP_Color_RGB(0xA2, 0xC5, 0xF0);
|
||||
case 2: return write_TSP_Color_RGB(0xFF, 0xBD, 0xBD);
|
||||
}
|
||||
return write_TSP_Color_RGB(Math.random()*255, Math.random()*255, Math.random()*255);
|
||||
}
|
||||
|
||||
/** Write NUMBERS workbook */
|
||||
function write_numbers_iwa(wb: WorkBook, opts?: WritingOptions): CFB$Container {
|
||||
if(!opts || !opts.numbers) throw new Error("Must pass a `numbers` option -- check the README");
|
||||
@ -1147,6 +1278,21 @@ function numbers_iwa_find(cfb: CFB$Container, deps: Dependents, id: number) {
|
||||
return ainfo;
|
||||
}
|
||||
|
||||
function numbers_add_meta(mlist: ProtoMessage, newid: number, newloc: string) {
|
||||
mlist[3].push({type: 2, data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(newid)}],
|
||||
[{type: 2, data: stru8(newloc.replace(/-[\s\S]*$/, "")) }],
|
||||
[{type: 2, data: stru8(newloc)}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[], [], [], [], // skip fields 6-9
|
||||
[{type: 0, data: write_varint49(0)}],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0 /* TODO: save_token */)}],
|
||||
])});
|
||||
mlist[1] = [{type: 0, data: write_varint49(Math.max(newid + 1, varint_to_i32(mlist[1][0].data) ))}];
|
||||
}
|
||||
|
||||
function numbers_add_msg(cfb: CFB$Container, type: number, msg: ProtoMessage, path: string, deps: Dependents, id?: number): number {
|
||||
if(!id) id = get_unique_msgid({ deps: [], location: "", type }, deps);
|
||||
var loc = `${path}-${id}.iwa`;
|
||||
@ -1158,25 +1304,50 @@ function numbers_add_msg(cfb: CFB$Container, type: number, msg: ProtoMessage, pa
|
||||
var newloc = loc.replace(/^[\/]/, "").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
numbers_iwa_doit(cfb, deps, 2, ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
|
||||
mlist[3].push({type: 2, data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(id as number)}],
|
||||
[{type: 2, data: stru8(newloc.replace(/-.*$/, "")) }],
|
||||
[{type: 2, data: stru8(newloc)}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[], [], [], [],
|
||||
[{type: 0, data: write_varint49(0)}],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0 /* TODO: save_token */)}],
|
||||
])});
|
||||
mlist[1] = [{type: 0, data: write_varint49(Math.max((id as number) + 1, varint_to_i32(mlist[1][0].data) ))}];
|
||||
numbers_add_meta(mlist, id||0, newloc);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
})
|
||||
return id;
|
||||
}
|
||||
|
||||
/** Add dependency to metadata */
|
||||
function numbers_meta_add_dep(mlist: ProtoMessage, deps: Dependents, id: number, dep: number|number[]) {
|
||||
var loc = deps[id].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
(Array.isArray(dep) ? dep : [dep]).forEach(dep => {
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(dep) }]
|
||||
])
|
||||
});
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
}
|
||||
|
||||
/** Remove dependency from metadata */
|
||||
function numbers_meta_del_dep(mlist: ProtoMessage, deps: Dependents, id: number, dep: number|number[]) {
|
||||
var loc = deps[id].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6] = parent[6].filter(m => varint_to_i32(parse_shallow(m.data)[1][0].data) != dep);
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
}
|
||||
|
||||
/** Deep copy of the essential parts of a worksheet */
|
||||
function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
var sheetref = -1, newsheetref = -1;
|
||||
@ -1226,29 +1397,12 @@ function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
tia.id = tiaref;
|
||||
if(deps[drawables[0]].location == deps[newsheetref].location) arch.push(tia);
|
||||
else {
|
||||
var loc = deps[newsheetref].location;
|
||||
loc = loc.replace(/^Root Entry\//,""); // NOTE: the Root Entry prefix is an artifact of the CFB container library
|
||||
loc = loc.replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
/* TODO: there are a number of places that assume the metadata record has ID=2 */
|
||||
numbers_iwa_doit(cfb, deps, 2, (ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
|
||||
/* add reference from SheetArchive file to TIA */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([
|
||||
[],
|
||||
[{type: 0, data: write_varint49(tiaref) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, newsheetref, tiaref);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
}));
|
||||
@ -1289,11 +1443,6 @@ function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
tiaroot.messages[0].data = write_shallow(tia);
|
||||
});
|
||||
|
||||
/* identifier for finding the TableModelArchive in the archive */
|
||||
var loc = deps[tmaref].location;
|
||||
loc = loc.replace(/^Root Entry\//,""); // NOTE: the Root Entry prefix is an artifact of the CFB container library
|
||||
loc = loc.replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
|
||||
/* .TST.TableModelArchive */
|
||||
numbers_iwa_doit(cfb, deps, tmaref, (tmaroot: IWAArchiveInfo, arch: IWAArchiveInfo[]) => {
|
||||
/* TODO: formulae currently break due to missing CE details */
|
||||
@ -1361,46 +1510,14 @@ function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
if(deps[newref].location == deps[oldref].location) deps[newref].location = deps[newref].location.replace(/\.iwa/, `-${newref}.iwa`);
|
||||
CFB.utils.cfb_add(cfb, deps[newref].location, compress_iwa_file(write_iwa_file([ msg ])));
|
||||
|
||||
var newloc = deps[newref].location;
|
||||
newloc = newloc.replace(/^Root Entry\//,""); // NOTE: the Root Entry prefix is an artifact of the CFB container library
|
||||
newloc = newloc.replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
var newloc = deps[newref].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
|
||||
numbers_iwa_doit(cfb, deps, 2, ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
mlist[3].push({type: 2, data: write_shallow([
|
||||
[],
|
||||
[{type: 0, data: write_varint49(newref)}],
|
||||
[{type: 2, data: stru8(newloc.replace(/-.*$/, "")) }],
|
||||
[{type: 2, data: stru8(newloc)}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0)}],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0 /* TODO: save_token */)}],
|
||||
])});
|
||||
mlist[1] = [{type: 0, data: write_varint49(Math.max(newref + 1, varint_to_i32(mlist[1][0].data) ))}];
|
||||
numbers_add_meta(mlist, newref, newloc);
|
||||
|
||||
/* add reference from TableModelArchive file to Tile */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([
|
||||
[],
|
||||
[{type: 0, data: write_varint49(newref) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, tmaref, newref);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
});
|
||||
@ -1426,45 +1543,14 @@ function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
if(deps[newref].location == deps[oldref].location) deps[newref].location = deps[newref].location.replace(/\.iwa/, `-${newref}.iwa`);
|
||||
CFB.utils.cfb_add(cfb, deps[newref].location, compress_iwa_file(write_iwa_file([ msg ])));
|
||||
|
||||
var newloc = deps[newref].location;
|
||||
newloc = newloc.replace(/^Root Entry\//,""); // NOTE: the Root Entry prefix is an artifact of the CFB container library
|
||||
newloc = newloc.replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
var newloc = deps[newref].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
|
||||
numbers_iwa_doit(cfb, deps, 2, (ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
mlist[3].push({type: 2, data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(newref)}],
|
||||
[{type: 2, data: stru8(newloc.replace(/-.*$/, "")) }],
|
||||
[{type: 2, data: stru8(newloc)}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0)}],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0 /* TODO: save_token */)}],
|
||||
])});
|
||||
mlist[1] = [{type: 0, data: write_varint49(Math.max(newref + 1, varint_to_i32(mlist[1][0].data) ))}];
|
||||
numbers_add_meta(mlist, newref, newloc);
|
||||
|
||||
/* add reference from TableModelArchive file to Tile */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([
|
||||
[],
|
||||
[{type: 0, data: write_varint49(newref) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, tmaref, newref);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
}));
|
||||
@ -1501,10 +1587,7 @@ function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
[{type: 2, data: stru8(`Tables/Tile-${newtileref}`)}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[{type: 2, data: new Uint8Array([2, 0, 0])}],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[],
|
||||
[], [], [], [], // skip fields 6-9
|
||||
[{type: 0, data: write_varint49(0)}],
|
||||
[],
|
||||
[{type: 0, data: write_varint49(0 /* TODO: save_token */)}],
|
||||
@ -1512,22 +1595,7 @@ function numbers_add_ws(cfb: CFB$Container, deps: Dependents, wsidx: number) {
|
||||
mlist[1] = [{type: 0, data: write_varint49(Math.max(newtileref + 1, varint_to_i32(mlist[1][0].data) ))}];
|
||||
|
||||
/* add reference from TableModelArchive file to Tile */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([
|
||||
[],
|
||||
[{type: 0, data: write_varint49(newtileref) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, tmaref, newtileref);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
}));
|
||||
@ -1573,6 +1641,7 @@ var USE_WIDE_ROWS = true;
|
||||
|
||||
/** Write .TST.TableModelArchive */
|
||||
function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet, tmaroot: IWAArchiveInfo, tmafile: IWAArchiveInfo[], tmaref: number) {
|
||||
if(!ws["!ref"]) throw new Error("Cannot export empty sheet to NUMBERS");
|
||||
var range = decode_range(ws["!ref"] as string);
|
||||
range.s.r = range.s.c = 0;
|
||||
|
||||
@ -1597,14 +1666,17 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
data[R_][_C] = _cell;
|
||||
}
|
||||
}
|
||||
} sheet_to_json<any>(ws, { range, header: 1 });
|
||||
var SST: string[] = ["~Sh33tJ5~"];
|
||||
var RSST: RichText[] = [{v:"~54ee77S~", l: "https://sheetjs.com/"}];
|
||||
}
|
||||
var LUT: DataLUT = {
|
||||
cmnt: [{a: "~54ee77S~", t: "... the people who are crazy enough to think they can change the world, are the ones who do."}],
|
||||
ferr: [],
|
||||
fmla: [],
|
||||
nfmt: [],
|
||||
ofmt: [],
|
||||
rsst: [{v:"~54ee77S~", l: "https://sheetjs.com/"}],
|
||||
sst: ["~Sh33tJ5~"]
|
||||
};
|
||||
|
||||
/* identifier for finding the TableModelArchive in the archive */
|
||||
var loc = deps[tmaref].location;
|
||||
loc = loc.replace(/^Root Entry\//,""); // NOTE: the Root Entry prefix is an artifact of the CFB container library
|
||||
loc = loc.replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
|
||||
var pb = parse_shallow(tmaroot.messages[0].data);
|
||||
{
|
||||
@ -1670,23 +1742,15 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
{
|
||||
CFB.utils.cfb_del(cfb, deps[tileref].location);
|
||||
|
||||
/* remove existing tile from reference -- TODO: can this have an id other than 2? */
|
||||
/* remove existing tile from reference */
|
||||
numbers_iwa_doit(cfb, deps, 2, (ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
|
||||
/* remove metadata entry for tile */
|
||||
mlist[3] = mlist[3].filter(m => varint_to_i32(parse_shallow(m.data)[1][0].data) != tileref);
|
||||
|
||||
/* remove reference from TableModelArchive file to Tile */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6] = parent[6].filter(m => varint_to_i32(parse_shallow(m.data)[1][0].data) != tileref);
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_del_dep(mlist, deps, tmaref, tileref);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
}));
|
||||
@ -1718,7 +1782,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
[{type: 0, data: write_varint49(USE_WIDE_ROWS ? 1 : 0)}]
|
||||
];
|
||||
for(var R = tidx * tstride; R <= Math.min(range.e.r, (tidx + 1) * tstride - 1); ++R) {
|
||||
var tilerow = write_TST_TileRowInfo(data[R], SST, RSST, USE_WIDE_ROWS);
|
||||
var tilerow = write_TST_TileRowInfo(data[R], LUT, USE_WIDE_ROWS);
|
||||
tilerow[1][0].data = write_varint49(R - tidx * tstride);
|
||||
tiledata[5].push({data: write_shallow(tilerow), type: 2});
|
||||
}
|
||||
@ -1737,7 +1801,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
var tilecontent = compress_iwa_file(write_iwa_file([newtile]));
|
||||
CFB.utils.cfb_add(cfb, `/Index/Tables/Tile-${newtileid}.iwa`, tilecontent);
|
||||
|
||||
/* update metadata -- TODO: can this have an id other than 2? */
|
||||
/* update metadata */
|
||||
numbers_iwa_doit(cfb, deps, 2, (ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
mlist[3].push({type: 2, data: write_shallow([ [],
|
||||
@ -1754,21 +1818,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
mlist[1] = [{type: 0, data: write_varint49(Math.max(newtileid + 1, varint_to_i32(mlist[1][0].data) ))}];
|
||||
|
||||
/* add reference from TableModelArchive file to Tile */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(newtileid) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, tmaref, newtileid);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
}));
|
||||
@ -1814,22 +1864,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
|
||||
/* add reference from TableModelArchive file to merge */
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([
|
||||
[],
|
||||
[{type: 0, data: write_varint49(mergeid) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, tmaref, mergeid);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
}));
|
||||
@ -1845,7 +1880,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
var sstdata = parse_shallow(sstroot.messages[0].data);
|
||||
{
|
||||
sstdata[3] = [];
|
||||
SST.forEach((str, i) => {
|
||||
LUT.sst.forEach((str, i) => {
|
||||
if(i == 0) return; // Numbers will assert if index zero
|
||||
sstdata[3].push({type: 2, data: write_shallow([ [],
|
||||
[ { type: 0, data: write_varint49(i) } ],
|
||||
@ -1872,7 +1907,7 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
903845 // character style
|
||||
];
|
||||
|
||||
RSST.forEach((rsst, i) => {
|
||||
LUT.rsst.forEach((rsst, i) => {
|
||||
if(i == 0) return;
|
||||
|
||||
/* create .TSWP.StorageArchive (2001) */
|
||||
@ -1948,70 +1983,117 @@ function write_numbers_tma(cfb: CFB$Container, deps: Dependents, ws: WorkSheet,
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
|
||||
/* rsst -> rich text payload */
|
||||
var loc = deps[rsstref].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
var parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
var parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(rtpaid) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, rsstref, rtpaid);
|
||||
|
||||
/* rich text payload -> storage archive */
|
||||
loc = deps[rtpaid].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(tswpsaid) }]
|
||||
])
|
||||
});
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, rtpaid, tswpsaid);
|
||||
|
||||
/* storage archive -> smart fields */
|
||||
loc = deps[tswpsaid].location.replace(/^Root Entry\//,"").replace(/^Index\//, "").replace(/\.iwa$/,"");
|
||||
parentidx = mlist[3].findIndex(m => {
|
||||
var mm = parse_shallow(m.data);
|
||||
if(mm[3]?.[0]) return u8str(mm[3][0].data) == loc;
|
||||
if(mm[2]?.[0] && u8str(mm[2][0].data) == loc) return true;
|
||||
return false;
|
||||
});
|
||||
parent = parse_shallow(mlist[3][parentidx].data);
|
||||
if(!parent[6]) parent[6] = [];
|
||||
tswpsarefs.forEach(id => parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(id) }]
|
||||
])
|
||||
}));
|
||||
style_indices.forEach(n => parent[6].push({
|
||||
type: 2,
|
||||
data: write_shallow([ [],
|
||||
[{type: 0, data: write_varint49(n) }]
|
||||
])
|
||||
}));
|
||||
mlist[3][parentidx].data = write_shallow(parent);
|
||||
numbers_meta_add_dep(mlist, deps, tswpsaid, tswpsarefs);
|
||||
numbers_meta_add_dep(mlist, deps, tswpsaid, style_indices);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
});
|
||||
});
|
||||
rsstroot.messages[0].data = write_shallow(rsstdata);
|
||||
});
|
||||
|
||||
/* rebuild comment table */
|
||||
if(LUT.cmnt.length > 1) {
|
||||
/* TODO: verify zahl has a comment storage */
|
||||
var cmntref = parse_TSP_Reference(store[19][0].data);
|
||||
var authors: {[a: string]: number} = {}, iauthor = 0; /* TODO: this should be a Map */
|
||||
numbers_iwa_doit(cfb, deps, cmntref, (cmntroot) => {
|
||||
var cmntdata = parse_shallow(cmntroot.messages[0].data);
|
||||
{
|
||||
cmntdata[3] = [];
|
||||
LUT.cmnt.forEach((cc,i) => {
|
||||
if(i == 0) return;
|
||||
var replies: number[] = [];
|
||||
/* TODO: this assumes one level of replies */
|
||||
if(cc.replies) cc.replies.forEach(c => {
|
||||
/* .TSK.AnnotationAuthorArchive (212) TODO: unify names across book */
|
||||
if(!authors[c.a||""]) authors[c.a||""] = numbers_add_msg(cfb, 212, [ [],
|
||||
[ { type: 2, data: stru8(c.a||"") }],
|
||||
[ { type: 2, data: get_author_color(++iauthor) }],
|
||||
[],
|
||||
[ { type: 0, data: write_varint49(0) } ]
|
||||
], "/Index/Tables/DataList", deps);
|
||||
var aaaid = authors[c.a||""];
|
||||
|
||||
/* .TSD.CommentStorageArchive (3056) */
|
||||
var csaid = numbers_add_msg(cfb, 3056, [ [],
|
||||
[ { type: 2, data: stru8(c.t||"") }],
|
||||
[ { type: 2, data: write_shallow([[],
|
||||
[ { type: 1, data: new Uint8Array([0, 0, 0, 128, 116, 109, 182, 65]) }]
|
||||
]) }],
|
||||
[ { type: 2, data: write_TSP_Reference(aaaid) }]
|
||||
], "/Index/Tables/DataList", deps);
|
||||
numbers_iwa_doit(cfb, deps, csaid, iwa => numbers_add_oref(iwa, aaaid));
|
||||
replies.push(csaid);
|
||||
|
||||
/* meta deps */
|
||||
numbers_iwa_doit(cfb, deps, 2, ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
|
||||
/* CSA -> AAA */
|
||||
numbers_meta_add_dep(mlist, deps, csaid, aaaid);
|
||||
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
});
|
||||
});
|
||||
|
||||
/* .TSK.AnnotationAuthorArchive (212) TODO: unify names across book */
|
||||
if(!authors[cc.a||""]) authors[cc.a||""] = numbers_add_msg(cfb, 212, [ [],
|
||||
[ { type: 2, data: stru8(cc.a||"") }],
|
||||
[ { type: 2, data: get_author_color(++iauthor) }],
|
||||
[],
|
||||
[ { type: 0, data: write_varint49(0) } ]
|
||||
], "/Index/Tables/DataList", deps);
|
||||
var aaaid = authors[cc.a||""];
|
||||
|
||||
/* .TSD.CommentStorageArchive (3056) */
|
||||
var csaid = numbers_add_msg(cfb, 3056, [ [],
|
||||
[ { type: 2, data: stru8(cc.t||"") }],
|
||||
[ { type: 2, data: write_shallow([[],
|
||||
[ { type: 1, data: new Uint8Array([0, 0, 0, 128, 116, 109, 182, 65]) }]
|
||||
]) }],
|
||||
[ { type: 2, data: write_TSP_Reference(aaaid) }],
|
||||
replies.map(r => ({type: 2, data: write_TSP_Reference(r)})),
|
||||
[ { type: 2, data: write_shallow([[],
|
||||
[ { type: 0, data: write_varint49(i) }],
|
||||
[ { type: 0, data: write_varint49(0) }]
|
||||
]) }],
|
||||
], "/Index/Tables/DataList", deps);
|
||||
numbers_iwa_doit(cfb, deps, csaid, iwa => {
|
||||
numbers_add_oref(iwa, aaaid);
|
||||
replies.forEach(r => numbers_add_oref(iwa, r));
|
||||
});
|
||||
|
||||
/* add to TableDataList */
|
||||
cmntdata[3].push({type: 2, data: write_shallow([ [],
|
||||
[ { type: 0, data: write_varint49(i) } ],
|
||||
[ { type: 0, data: write_varint49(1) } ],
|
||||
[], [], [], [], [], [], [], // skip fields 3-9
|
||||
[ { type: 2, data: write_TSP_Reference(csaid) } ]
|
||||
])});
|
||||
numbers_add_oref(cmntroot, csaid);
|
||||
|
||||
/* meta deps */
|
||||
numbers_iwa_doit(cfb, deps, 2, ai => {
|
||||
var mlist = parse_shallow(ai.messages[0].data);
|
||||
numbers_meta_add_dep(mlist, deps, cmntref, csaid); // table -> CSA
|
||||
numbers_meta_add_dep(mlist, deps, csaid, aaaid); // CSA -> author
|
||||
if(replies.length) numbers_meta_add_dep(mlist, deps, csaid, replies); // CSA -> replies
|
||||
ai.messages[0].data = write_shallow(mlist);
|
||||
});
|
||||
|
||||
});
|
||||
}
|
||||
cmntdata[2][0].data = write_varint49(LUT.cmnt.length + 1);
|
||||
cmntroot.messages[0].data = write_shallow(cmntdata);
|
||||
});
|
||||
}
|
||||
}
|
||||
pb[4][0].data = write_shallow(store);
|
||||
}
|
||||
|
38
package.json
38
package.json
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.19.3",
|
||||
"version": "0.20.2",
|
||||
"author": "sheetjs",
|
||||
"description": "SheetJS Spreadsheet data parser and writer",
|
||||
"keywords": [
|
||||
@ -39,6 +39,36 @@
|
||||
"require": "./xlsx.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.core.min": {
|
||||
"import": "./dist/xlsx.core.min.js",
|
||||
"require": "./dist/xlsx.core.min.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.core.min.js": {
|
||||
"import": "./dist/xlsx.core.min.js",
|
||||
"require": "./dist/xlsx.core.min.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.full.min": {
|
||||
"import": "./dist/xlsx.full.min.js",
|
||||
"require": "./dist/xlsx.full.min.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.full.min.js": {
|
||||
"import": "./dist/xlsx.full.min.js",
|
||||
"require": "./dist/xlsx.full.min.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.mini.min": {
|
||||
"import": "./dist/xlsx.mini.min.js",
|
||||
"require": "./dist/xlsx.mini.min.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.mini.min.js": {
|
||||
"import": "./dist/xlsx.mini.min.js",
|
||||
"require": "./dist/xlsx.mini.min.js",
|
||||
"types": "./types/index.d.ts"
|
||||
},
|
||||
"./dist/xlsx.zahl": {
|
||||
"import": "./dist/xlsx.zahl.mjs",
|
||||
"require": "./dist/xlsx.zahl.js",
|
||||
@ -137,6 +167,12 @@
|
||||
]
|
||||
},
|
||||
"homepage": "https://sheetjs.com/",
|
||||
"files": [
|
||||
"CHANGELOG.md", "LICENSE", "README.md", "bower.json", "package.json", "xlsx.js", "xlsx.mjs", "xlsxworker.js",
|
||||
"bin/xlsx.njs",
|
||||
"dist/LICENSE", "dist/*.mjs", "dist/*.js", "dist/*.map", "dist/*.d.ts",
|
||||
"types/index.d.ts", "types/tsconfig.json"
|
||||
],
|
||||
"bugs": {
|
||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs/issues"
|
||||
},
|
||||
|
26
packages/dta/.eslintrc
Normal file
26
packages/dta/.eslintrc
Normal file
@ -0,0 +1,26 @@
|
||||
{
|
||||
"env": { "shared-node-browser":true },
|
||||
"globals": {},
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 6
|
||||
},
|
||||
"plugins": [ "html", "json" ],
|
||||
"extends": "eslint:recommended",
|
||||
"rules": {
|
||||
"comma-style": [ 2, "last" ],
|
||||
"comma-dangle": [ 2, "never" ],
|
||||
"curly": 0,
|
||||
"no-bitwise": 0,
|
||||
"no-cond-assign": 1,
|
||||
"no-console": 0,
|
||||
"no-control-regex": 0,
|
||||
"no-unused-vars": 1,
|
||||
"no-empty": 0,
|
||||
"no-trailing-spaces": 2,
|
||||
"no-use-before-define": [ 1, {
|
||||
"functions":false, "classes":true, "variables":false
|
||||
}],
|
||||
"no-useless-escape": 0,
|
||||
"semi": [ 2, "always" ]
|
||||
}
|
||||
}
|
1
packages/dta/.gitignore
vendored
Normal file
1
packages/dta/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
misc/
|
35
packages/dta/Makefile
Normal file
35
packages/dta/Makefile
Normal file
@ -0,0 +1,35 @@
|
||||
.PHONY: build
|
||||
build: node browser types
|
||||
|
||||
.PHONY: clean
|
||||
clean:
|
||||
rm dist/dta.*
|
||||
|
||||
## Types
|
||||
.PHONY: types
|
||||
types: dta.ts
|
||||
tsc -d --emitDeclarationOnly --declarationDir types $<
|
||||
mv types/dta.d.ts types/index.d.ts
|
||||
|
||||
## NodeJS target
|
||||
|
||||
.PHONY: node
|
||||
node: dist/dta.js
|
||||
|
||||
dist/dta.js: dta.ts
|
||||
npx esbuild@0.14.14 $< --bundle --outfile=$@ --platform=node
|
||||
|
||||
.PHONY: test-node
|
||||
test-node: dist/dta.js test.js
|
||||
npx mocha@2.5.3 test.js
|
||||
|
||||
## Browser target
|
||||
.PHONY: browser
|
||||
browser: dist/dta.min.js
|
||||
|
||||
dist/dta.min.js: dta.ts
|
||||
npx esbuild@0.14.14 $< --bundle --outfile=$@ --minify --sourcemap --global-name=DTA
|
||||
|
||||
dist/dta.mjs: dta.ts
|
||||
npx esbuild@0.14.14 $< --bundle --outfile=$@ --minify --sourcemap --format=esm
|
||||
|
69
packages/dta/README.md
Normal file
69
packages/dta/README.md
Normal file
@ -0,0 +1,69 @@
|
||||
# DTA Data File Codec
|
||||
|
||||
Codec for reading Stata .DTA files and generating CSF workbook objects
|
||||
compatible with the [SheetJS](https://sheetjs.com) library constellation.
|
||||
|
||||
DTA datasets can support millions of observations and over 32767 variables.
|
||||
The codec will truncate data to 1048576 observations and 16384 variables.
|
||||
|
||||
<https://docs.sheetjs.com/docs/constellation/dta> includes a live demo.
|
||||
|
||||
## Installation
|
||||
|
||||
Using NodeJS package manager:
|
||||
|
||||
```bash
|
||||
npm install --save https://cdn.sheetjs.com/dta-0.0.2/dta-0.0.2.tgz
|
||||
```
|
||||
|
||||
The standalone script is also hosted on the SheetJS CDN:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.sheetjs.com/dta-0.0.2/package/dist/dta.min.js"></script>
|
||||
```
|
||||
|
||||
## Usage
|
||||
|
||||
The `parse` method accepts a `Uint8Array` representing the file data. It returns
|
||||
a ["Common Spreadsheet Format"](https://docs.sheetjs.com/docs/csf/) workbook
|
||||
object.
|
||||
|
||||
The `set_utils` method accepts a `utils` object from SheetJS CE or a SheetJS
|
||||
Pro build. `parse` will use methods from the `utils` object.
|
||||
|
||||
### NodeJS
|
||||
|
||||
```js
|
||||
const XLSX = require("xlsx"), DTA = require("dta");
|
||||
DTA.set_utils(XLSX.utils);
|
||||
|
||||
const wb = DTA.parse(fs.readFileSync("auto.dta"));
|
||||
```
|
||||
|
||||
### Browser
|
||||
|
||||
`dist/dta.min.js` is a standalone build designed to be added with `<script>`.
|
||||
|
||||
```html
|
||||
<script lang="javascript" src="https://cdn.sheetjs.com/xlsx-latest/package/dist/xlsx.full.min.js"></script>
|
||||
<script src="dist/dta.min.js"></script>
|
||||
<div id="out"></div>
|
||||
<script>
|
||||
DTA.set_utils(XLSX.utils);
|
||||
(async() => {
|
||||
/* fetch file */
|
||||
const data = await (await fetch("test.dta")).arrayBuffer();
|
||||
/* parse */
|
||||
const wb = DTA.parse(new Uint8Array(data));
|
||||
/* wb is a SheetJS workbook object */
|
||||
const html = XLSX.utils.sheet_to_html(wb.Sheets[wb.SheetNames[0]]);
|
||||
out.innerHTML = html;
|
||||
})();
|
||||
</script>
|
||||
```
|
||||
|
||||
`dist/dta.mjs` is a ECMAScript Module build designed to be used with bundlers:
|
||||
|
||||
```js
|
||||
import * as DTA from 'dta';
|
||||
```
|
19
packages/dta/bin/dta2csv.njs
Executable file
19
packages/dta/bin/dta2csv.njs
Executable file
@ -0,0 +1,19 @@
|
||||
#!/usr/bin/env node
|
||||
/* eslint-env node, es6 */
|
||||
const DTA = require("../");
|
||||
const XLSX = (() => {
|
||||
try {
|
||||
const XLSX = require("xlsx");
|
||||
DTA.set_utils(XLSX.utils);
|
||||
return XLSX;
|
||||
} catch(e) {
|
||||
throw new Error("Must install the SheetJS file processing library! See https://docs.sheetjs.com/docs/getting-started/installation/nodejs for more details");
|
||||
}
|
||||
})();
|
||||
const fs = require("fs");
|
||||
|
||||
const buf = fs.readFileSync(process.argv[2]);
|
||||
const wb = DTA.parse(buf);
|
||||
// translate stub cells to single blanks
|
||||
//wb.Sheets[wb.SheetNames[0]]["!data"].forEach(row => row.forEach(cell => {if(cell.t == "z") {cell.t = "s"; cell.v = " ";}}));
|
||||
console.log(XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]));
|
688
packages/dta/dist/dta.js
vendored
Normal file
688
packages/dta/dist/dta.js
vendored
Normal file
@ -0,0 +1,688 @@
|
||||
var __defProp = Object.defineProperty;
|
||||
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
||||
var __getOwnPropNames = Object.getOwnPropertyNames;
|
||||
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
||||
var __markAsModule = (target) => __defProp(target, "__esModule", { value: true });
|
||||
var __export = (target, all) => {
|
||||
for (var name in all)
|
||||
__defProp(target, name, { get: all[name], enumerable: true });
|
||||
};
|
||||
var __reExport = (target, module2, copyDefault, desc) => {
|
||||
if (module2 && typeof module2 === "object" || typeof module2 === "function") {
|
||||
for (let key of __getOwnPropNames(module2))
|
||||
if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default"))
|
||||
__defProp(target, key, { get: () => module2[key], enumerable: !(desc = __getOwnPropDesc(module2, key)) || desc.enumerable });
|
||||
}
|
||||
return target;
|
||||
};
|
||||
var __toCommonJS = /* @__PURE__ */ ((cache) => {
|
||||
return (module2, temp) => {
|
||||
return cache && cache.get(module2) || (temp = __reExport(__markAsModule({}), module2, 1), cache && cache.set(module2, temp), temp);
|
||||
};
|
||||
})(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0);
|
||||
|
||||
// dta.ts
|
||||
var dta_exports = {};
|
||||
__export(dta_exports, {
|
||||
parse: () => parse,
|
||||
set_utils: () => set_utils,
|
||||
version: () => version
|
||||
});
|
||||
var version = "0.0.2";
|
||||
var _utils;
|
||||
function set_utils(utils) {
|
||||
_utils = utils;
|
||||
}
|
||||
function u8_to_str(u8) {
|
||||
return new TextDecoder().decode(u8);
|
||||
}
|
||||
function u8_to_latin1(u8) {
|
||||
return new TextDecoder("latin1").decode(u8);
|
||||
}
|
||||
function format_number_dta(value, format, t) {
|
||||
if (value < 0) {
|
||||
const res = format_number_dta(-value, format, t);
|
||||
res.w = "-" + res.w;
|
||||
return res;
|
||||
}
|
||||
const o = { t: "n", v: value };
|
||||
switch (t) {
|
||||
case 251:
|
||||
case 98:
|
||||
case 65530:
|
||||
format = "%8.0g";
|
||||
break;
|
||||
case 252:
|
||||
case 105:
|
||||
case 65529:
|
||||
format = "%8.0g";
|
||||
break;
|
||||
case 253:
|
||||
case 108:
|
||||
case 65528:
|
||||
format = "%12.0g";
|
||||
break;
|
||||
case 254:
|
||||
case 102:
|
||||
case 65527:
|
||||
format = "%9.0g";
|
||||
break;
|
||||
case 255:
|
||||
case 100:
|
||||
case 65526:
|
||||
format = "%10.0g";
|
||||
break;
|
||||
default:
|
||||
throw t;
|
||||
}
|
||||
try {
|
||||
let w = +(format.match(/%(\d+)/) || [])[1] || 8;
|
||||
let k = 0;
|
||||
if (value < 1)
|
||||
++k;
|
||||
if (value < 0.1)
|
||||
++k;
|
||||
if (value < 0.01)
|
||||
++k;
|
||||
if (value < 1e-3)
|
||||
++k;
|
||||
const e = value.toExponential();
|
||||
const exp = e.indexOf("e") == -1 ? 0 : +e.slice(e.indexOf("e") + 1);
|
||||
let h = w - 2 - exp;
|
||||
if (h < 0)
|
||||
h = 0;
|
||||
var m = format.match(/%\d+\.(\d+)/);
|
||||
if (m && +m[1])
|
||||
h = +m[1];
|
||||
o.w = (Math.round(value * 10 ** h) / 10 ** h).toFixed(h).replace(/^([-]?)0\./, "$1.");
|
||||
o.w = o.w.slice(0, w + k);
|
||||
if (o.w.indexOf(".") > -1)
|
||||
o.w = o.w.replace(/0+$/, "");
|
||||
o.w = o.w.replace(/\.$/, "");
|
||||
if (o.w == "")
|
||||
o.w = "0";
|
||||
} catch (e) {
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function u8_to_dataview(array) {
|
||||
return new DataView(array.buffer, array.byteOffset, array.byteLength);
|
||||
}
|
||||
function valid_inc(p, n) {
|
||||
if (u8_to_str(p.raw.slice(p.ptr, p.ptr + n.length)) != n)
|
||||
return false;
|
||||
p.ptr += n.length;
|
||||
return true;
|
||||
}
|
||||
function read_f64(p, LE) {
|
||||
p.ptr += 8;
|
||||
const d = p.dv.getFloat64(p.ptr - 8, LE);
|
||||
return d > 8988e304 ? null : d;
|
||||
}
|
||||
function read_f32(p, LE) {
|
||||
p.ptr += 4;
|
||||
const d = p.dv.getFloat32(p.ptr - 4, LE);
|
||||
return d > 1701e35 ? null : d;
|
||||
}
|
||||
function read_u32(p, LE) {
|
||||
p.ptr += 4;
|
||||
return p.dv.getUint32(p.ptr - 4, LE);
|
||||
}
|
||||
function read_i32(p, LE) {
|
||||
p.ptr += 4;
|
||||
const u = p.dv.getInt32(p.ptr - 4, LE);
|
||||
return u > 2147483620 ? null : u;
|
||||
}
|
||||
function read_u16(p, LE) {
|
||||
p.ptr += 2;
|
||||
return p.dv.getUint16(p.ptr - 2, LE);
|
||||
}
|
||||
function read_i16(p, LE) {
|
||||
p.ptr += 2;
|
||||
const u = p.dv.getInt16(p.ptr - 2, LE);
|
||||
return u > 32740 ? null : u;
|
||||
}
|
||||
function read_u8(p) {
|
||||
return p.raw[p.ptr++];
|
||||
}
|
||||
function read_i8(p) {
|
||||
let u = p.raw[p.ptr++];
|
||||
u = u < 128 ? u : u - 256;
|
||||
return u > 100 ? null : u;
|
||||
}
|
||||
var SUPPORTED_VERSIONS_TAGGED = [
|
||||
"117",
|
||||
"118",
|
||||
"119",
|
||||
"120",
|
||||
"121"
|
||||
];
|
||||
var SUPPORTED_VERSIONS_LEGACY = [
|
||||
102,
|
||||
103,
|
||||
104,
|
||||
105,
|
||||
108,
|
||||
110,
|
||||
111,
|
||||
112,
|
||||
113,
|
||||
114,
|
||||
115
|
||||
];
|
||||
function parse_tagged(raw) {
|
||||
const err = "Not a DTA file";
|
||||
const d = {
|
||||
ptr: 0,
|
||||
raw,
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
let vers = 118;
|
||||
let LE = true;
|
||||
let nvar = 0, nobs = 0, nobs_lo = 0, nobs_hi = 0;
|
||||
let label = "", timestamp = "";
|
||||
const var_types = [];
|
||||
const var_names = [];
|
||||
const formats = [];
|
||||
if (!valid_inc(d, "<stata_dta>"))
|
||||
throw err;
|
||||
{
|
||||
if (!valid_inc(d, "<header>"))
|
||||
throw err;
|
||||
{
|
||||
if (!valid_inc(d, "<release>"))
|
||||
throw err;
|
||||
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + 3));
|
||||
d.ptr += 3;
|
||||
if (!valid_inc(d, "</release>"))
|
||||
throw err;
|
||||
if (SUPPORTED_VERSIONS_TAGGED.indexOf(res) == -1)
|
||||
throw `Unsupported DTA ${res} file`;
|
||||
vers = +res;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<byteorder>"))
|
||||
throw err;
|
||||
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + 3));
|
||||
d.ptr += 3;
|
||||
if (!valid_inc(d, "</byteorder>"))
|
||||
throw err;
|
||||
switch (res) {
|
||||
case "MSF":
|
||||
LE = false;
|
||||
break;
|
||||
case "LSF":
|
||||
LE = true;
|
||||
break;
|
||||
default:
|
||||
throw `Unsupported byteorder ${res}`;
|
||||
}
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<K>"))
|
||||
throw err;
|
||||
nvar = vers === 119 || vers >= 121 ? read_u32(d, LE) : read_u16(d, LE);
|
||||
if (!valid_inc(d, "</K>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<N>"))
|
||||
throw err;
|
||||
if (vers == 117)
|
||||
nobs = nobs_lo = read_u32(d, LE);
|
||||
else {
|
||||
const lo = read_u32(d, LE), hi = read_u32(d, LE);
|
||||
nobs = LE ? (nobs_lo = lo) + (nobs_hi = hi) * Math.pow(2, 32) : (nobs_lo = hi) + (nobs_hi = lo) * Math.pow(2, 32);
|
||||
}
|
||||
if (nobs > 1e6)
|
||||
console.error(`More than 1 million observations -- extra rows will be dropped`);
|
||||
if (!valid_inc(d, "</N>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<label>"))
|
||||
throw err;
|
||||
const w = vers >= 118 ? 2 : 1;
|
||||
const strlen = w == 1 ? read_u8(d) : read_u16(d, LE);
|
||||
if (strlen > 0)
|
||||
label = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
|
||||
d.ptr += strlen;
|
||||
if (!valid_inc(d, "</label>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<timestamp>"))
|
||||
throw err;
|
||||
const strlen = read_u8(d);
|
||||
timestamp = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + strlen));
|
||||
d.ptr += strlen;
|
||||
if (!valid_inc(d, "</timestamp>"))
|
||||
throw err;
|
||||
}
|
||||
if (!valid_inc(d, "</header>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<map>"))
|
||||
throw err;
|
||||
d.ptr += 8 * 14;
|
||||
if (!valid_inc(d, "</map>"))
|
||||
throw err;
|
||||
}
|
||||
let stride = 0;
|
||||
{
|
||||
if (!valid_inc(d, "<variable_types>"))
|
||||
throw err;
|
||||
for (var i = 0; i < nvar; ++i) {
|
||||
const type = read_u16(d, LE);
|
||||
var_types.push(type);
|
||||
if (type >= 1 && type <= 2045)
|
||||
stride += type;
|
||||
else
|
||||
switch (type) {
|
||||
case 32768:
|
||||
stride += 8;
|
||||
break;
|
||||
case 65525:
|
||||
stride += 0;
|
||||
break;
|
||||
case 65526:
|
||||
stride += 8;
|
||||
break;
|
||||
case 65527:
|
||||
stride += 4;
|
||||
break;
|
||||
case 65528:
|
||||
stride += 4;
|
||||
break;
|
||||
case 65529:
|
||||
stride += 2;
|
||||
break;
|
||||
case 65530:
|
||||
stride += 1;
|
||||
break;
|
||||
default:
|
||||
throw `Unsupported field type ${type}`;
|
||||
}
|
||||
}
|
||||
if (!valid_inc(d, "</variable_types>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<varnames>"))
|
||||
throw err;
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
for (let i2 = 0; i2 < nvar; ++i2) {
|
||||
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
|
||||
d.ptr += w;
|
||||
var_names.push(name.replace(/\x00[\s\S]*/, ""));
|
||||
}
|
||||
if (!valid_inc(d, "</varnames>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<sortlist>"))
|
||||
throw err;
|
||||
d.ptr += (2 * nvar + 2) * (vers == 119 || vers == 121 ? 2 : 1);
|
||||
if (!valid_inc(d, "</sortlist>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<formats>"))
|
||||
throw err;
|
||||
const w = vers >= 118 ? 57 : 49;
|
||||
for (let i2 = 0; i2 < nvar; ++i2) {
|
||||
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
|
||||
d.ptr += w;
|
||||
formats.push(name.replace(/\x00[\s\S]*/, ""));
|
||||
}
|
||||
if (!valid_inc(d, "</formats>"))
|
||||
throw err;
|
||||
}
|
||||
const value_label_names = [];
|
||||
{
|
||||
if (!valid_inc(d, "<value_label_names>"))
|
||||
throw err;
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
for (let i2 = 0; i2 < nvar; ++i2, d.ptr += w)
|
||||
value_label_names[i2] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/, "");
|
||||
if (!valid_inc(d, "</value_label_names>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<variable_labels>"))
|
||||
throw err;
|
||||
const w = vers >= 118 ? 321 : 81;
|
||||
d.ptr += w * nvar;
|
||||
if (!valid_inc(d, "</variable_labels>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<characteristics>"))
|
||||
throw err;
|
||||
while (valid_inc(d, "<ch>")) {
|
||||
const len = read_u32(d, LE);
|
||||
d.ptr += len;
|
||||
if (!valid_inc(d, "</ch>"))
|
||||
throw err;
|
||||
}
|
||||
if (!valid_inc(d, "</characteristics>"))
|
||||
throw err;
|
||||
}
|
||||
const ws = _utils.aoa_to_sheet([var_names], { dense: true });
|
||||
var ptrs = [];
|
||||
{
|
||||
if (!valid_inc(d, "<data>"))
|
||||
throw err;
|
||||
for (let R = 0; R < nobs; ++R) {
|
||||
const row = [];
|
||||
for (let C = 0; C < nvar; ++C) {
|
||||
let t = var_types[C];
|
||||
if (t >= 1 && t <= 2045) {
|
||||
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
|
||||
s = s.replace(/\x00[\s\S]*/, "");
|
||||
row[C] = s;
|
||||
d.ptr += t;
|
||||
} else
|
||||
switch (t) {
|
||||
case 65525:
|
||||
d.ptr += 0;
|
||||
break;
|
||||
case 65530:
|
||||
row[C] = read_i8(d);
|
||||
break;
|
||||
case 65529:
|
||||
row[C] = read_i16(d, LE);
|
||||
break;
|
||||
case 65528:
|
||||
row[C] = read_i32(d, LE);
|
||||
break;
|
||||
case 65527:
|
||||
row[C] = read_f32(d, LE);
|
||||
break;
|
||||
case 65526:
|
||||
row[C] = read_f64(d, LE);
|
||||
break;
|
||||
case 32768:
|
||||
{
|
||||
row[C] = "##SheetJStrL##";
|
||||
ptrs.push([R + 1, C, d.raw.slice(d.ptr, d.ptr + 8)]);
|
||||
d.ptr += 8;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
throw `Unsupported field type ${t} for ${var_names[C]}`;
|
||||
}
|
||||
if (typeof row[C] == "number" && formats[C])
|
||||
row[C] = format_number_dta(row[C], formats[C], t);
|
||||
}
|
||||
_utils.sheet_add_aoa(ws, [row], { origin: -1, sheetStubs: true });
|
||||
}
|
||||
if (!valid_inc(d, "</data>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<strls>"))
|
||||
throw err;
|
||||
const strl_tbl = [];
|
||||
while (d.raw[d.ptr] == 71) {
|
||||
if (!valid_inc(d, "GSO"))
|
||||
throw err;
|
||||
const v = read_u32(d, LE);
|
||||
let o = 0;
|
||||
if (vers == 117)
|
||||
o = read_u32(d, LE);
|
||||
else {
|
||||
const lo = read_u32(d, LE), hi = read_u32(d, LE);
|
||||
o = LE ? lo + hi * Math.pow(2, 32) : hi + lo * Math.pow(2, 32);
|
||||
if (o > 1e6)
|
||||
console.error(`More than 1 million observations -- data will be dropped`);
|
||||
}
|
||||
const t = read_u8(d);
|
||||
const len = read_u32(d, LE);
|
||||
if (!strl_tbl[o])
|
||||
strl_tbl[o] = [];
|
||||
let str = "";
|
||||
if (t == 129) {
|
||||
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
|
||||
d.ptr += len;
|
||||
} else {
|
||||
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/, "");
|
||||
d.ptr += len;
|
||||
}
|
||||
strl_tbl[o][v] = str;
|
||||
}
|
||||
if (!valid_inc(d, "</strls>"))
|
||||
throw err;
|
||||
ptrs.forEach(([R, C, buf]) => {
|
||||
const dv = u8_to_dataview(buf);
|
||||
let v = 0, o = 0;
|
||||
switch (vers) {
|
||||
case 117:
|
||||
{
|
||||
v = dv.getUint32(0, LE);
|
||||
o = dv.getUint32(4, LE);
|
||||
}
|
||||
break;
|
||||
case 118:
|
||||
case 120:
|
||||
{
|
||||
v = dv.getUint16(0, LE);
|
||||
const o1 = dv.getUint16(2, LE), o2 = dv.getUint32(4, LE);
|
||||
o = LE ? o1 + o2 * 65536 : o2 + o1 * 2 ** 32;
|
||||
}
|
||||
break;
|
||||
case 119:
|
||||
case 121: {
|
||||
const v1 = dv.getUint16(0, LE), v2 = buf[2];
|
||||
v = LE ? v1 + (v2 << 16) : v2 + (v1 << 8);
|
||||
const o1 = buf[3], o2 = dv.getUint32(4, LE);
|
||||
o = LE ? o1 + o2 * 256 : o2 + o1 * 2 ** 32;
|
||||
}
|
||||
}
|
||||
ws["!data"][R][C].v = strl_tbl[o][v];
|
||||
});
|
||||
}
|
||||
{
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
if (!valid_inc(d, "<value_labels>"))
|
||||
throw err;
|
||||
while (valid_inc(d, "<lbl>")) {
|
||||
let len = read_u32(d, LE);
|
||||
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/, "");
|
||||
d.ptr += w;
|
||||
d.ptr += 3;
|
||||
const labels = [];
|
||||
{
|
||||
const n = read_u32(d, LE);
|
||||
const txtlen = read_u32(d, LE);
|
||||
const off = [], val = [];
|
||||
for (let i2 = 0; i2 < n; ++i2)
|
||||
off.push(read_u32(d, LE));
|
||||
for (let i2 = 0; i2 < n; ++i2)
|
||||
val.push(read_u32(d, LE));
|
||||
const str = u8_to_str(d.raw.slice(d.ptr, d.ptr + txtlen));
|
||||
d.ptr += txtlen;
|
||||
for (let i2 = 0; i2 < n; ++i2)
|
||||
labels[val[i2]] = str.slice(off[i2], str.indexOf("\0", off[i2]));
|
||||
}
|
||||
const C = value_label_names.indexOf(labname);
|
||||
if (C == -1)
|
||||
throw new Error(`unexpected value label |${labname}|`);
|
||||
for (let R = 1; R < ws["!data"].length; ++R) {
|
||||
const cell = ws["!data"][R][C];
|
||||
cell.t = "s";
|
||||
cell.v = cell.w = labels[cell.v || 0];
|
||||
}
|
||||
if (!valid_inc(d, "</lbl>"))
|
||||
throw err;
|
||||
}
|
||||
if (!valid_inc(d, "</value_labels>"))
|
||||
throw err;
|
||||
}
|
||||
if (!valid_inc(d, "</stata_dta>"))
|
||||
throw err;
|
||||
const wb = _utils.book_new();
|
||||
_utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
wb.bookType = "dta";
|
||||
return wb;
|
||||
}
|
||||
function parse_legacy(raw) {
|
||||
let vers = raw[0];
|
||||
if (SUPPORTED_VERSIONS_LEGACY.indexOf(vers) == -1)
|
||||
throw new Error("Not a DTA file");
|
||||
const d = {
|
||||
ptr: 1,
|
||||
raw,
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
let LE = true;
|
||||
let nvar = 0, nobs = 0;
|
||||
let label = "", timestamp = "";
|
||||
const var_types = [];
|
||||
const var_names = [];
|
||||
const formats = [];
|
||||
{
|
||||
const byteorder = read_u8(d);
|
||||
switch (byteorder) {
|
||||
case 1:
|
||||
LE = false;
|
||||
break;
|
||||
case 2:
|
||||
LE = true;
|
||||
break;
|
||||
default:
|
||||
throw `DTA ${vers} Unexpected byteorder ${byteorder}`;
|
||||
}
|
||||
let byte = read_u8(d);
|
||||
if (byte != 1)
|
||||
throw `DTA ${vers} Unexpected filetype ${byte}`;
|
||||
d.ptr++;
|
||||
nvar = read_u16(d, LE);
|
||||
nobs = read_u32(d, LE);
|
||||
d.ptr += vers >= 108 ? 81 : vers >= 103 ? 32 : 30;
|
||||
if (vers >= 105)
|
||||
d.ptr += 18;
|
||||
}
|
||||
const value_label_names = [];
|
||||
{
|
||||
let C = 0;
|
||||
for (C = 0; C < nvar; ++C)
|
||||
var_types.push(read_u8(d));
|
||||
const w = vers >= 110 ? 33 : 9;
|
||||
for (C = 0; C < nvar; ++C) {
|
||||
var_names.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00[\s\S]*$/, ""));
|
||||
d.ptr += w;
|
||||
}
|
||||
d.ptr += 2 * (nvar + 1);
|
||||
const fw = vers >= 114 ? 49 : vers >= 105 ? 12 : 7;
|
||||
for (C = 0; C < nvar; ++C) {
|
||||
formats.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + fw)).replace(/\x00[\s\S]*$/, ""));
|
||||
d.ptr += fw;
|
||||
}
|
||||
const lw = vers >= 110 ? 33 : 9;
|
||||
for (let i = 0; i < nvar; ++i, d.ptr += lw)
|
||||
value_label_names[i] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + lw)).replace(/\x00.*$/, "");
|
||||
}
|
||||
d.ptr += (vers >= 106 ? 81 : 32) * nvar;
|
||||
if (vers >= 105)
|
||||
while (d.ptr < d.raw.length) {
|
||||
const dt = read_u8(d), len = (vers >= 110 ? read_u32 : read_u16)(d, LE);
|
||||
if (dt == 0 && len == 0)
|
||||
break;
|
||||
d.ptr += len;
|
||||
}
|
||||
const ws = _utils.aoa_to_sheet([var_names], { dense: true });
|
||||
for (let R = 0; R < nobs; ++R) {
|
||||
const row = [];
|
||||
for (let C = 0; C < nvar; ++C) {
|
||||
let t = var_types[C];
|
||||
if ((vers == 111 || vers >= 113) && t >= 1 && t <= 244) {
|
||||
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
|
||||
s = s.replace(/\x00[\s\S]*/, "");
|
||||
row[C] = s;
|
||||
d.ptr += t;
|
||||
} else if ((vers == 112 || vers <= 110) && t >= 128) {
|
||||
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t - 127));
|
||||
s = s.replace(/\x00[\s\S]*/, "");
|
||||
row[C] = s;
|
||||
d.ptr += t - 127;
|
||||
} else
|
||||
switch (t) {
|
||||
case 251:
|
||||
case 98:
|
||||
row[C] = read_i8(d);
|
||||
break;
|
||||
case 252:
|
||||
case 105:
|
||||
row[C] = read_i16(d, LE);
|
||||
break;
|
||||
case 253:
|
||||
case 108:
|
||||
row[C] = read_i32(d, LE);
|
||||
break;
|
||||
case 254:
|
||||
case 102:
|
||||
row[C] = read_f32(d, LE);
|
||||
break;
|
||||
case 255:
|
||||
case 100:
|
||||
row[C] = read_f64(d, LE);
|
||||
break;
|
||||
default:
|
||||
throw `Unsupported field type ${t} for ${var_names[C]}`;
|
||||
}
|
||||
if (typeof row[C] == "number" && formats[C])
|
||||
row[C] = format_number_dta(row[C], formats[C], t);
|
||||
}
|
||||
_utils.sheet_add_aoa(ws, [row], { origin: -1, sheetStubs: true });
|
||||
}
|
||||
if (vers >= 115)
|
||||
while (d.ptr < d.raw.length) {
|
||||
const w = 33;
|
||||
let len = read_u32(d, LE);
|
||||
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/, "");
|
||||
d.ptr += w;
|
||||
d.ptr += 3;
|
||||
const labels = [];
|
||||
{
|
||||
const n = read_u32(d, LE);
|
||||
const txtlen = read_u32(d, LE);
|
||||
const off = [], val = [];
|
||||
for (let i = 0; i < n; ++i)
|
||||
off.push(read_u32(d, LE));
|
||||
for (let i = 0; i < n; ++i)
|
||||
val.push(read_u32(d, LE));
|
||||
const str = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + txtlen));
|
||||
d.ptr += txtlen;
|
||||
for (let i = 0; i < n; ++i)
|
||||
labels[val[i]] = str.slice(off[i], str.indexOf("\0", off[i]));
|
||||
}
|
||||
const C = value_label_names.indexOf(labname);
|
||||
if (C == -1)
|
||||
throw new Error(`unexpected value label |${labname}|`);
|
||||
for (let R = 1; R < ws["!data"].length; ++R) {
|
||||
const cell = ws["!data"][R][C];
|
||||
cell.t = "s";
|
||||
cell.v = cell.w = labels[cell.v || 0];
|
||||
}
|
||||
}
|
||||
const wb = _utils.book_new();
|
||||
_utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
wb.bookType = "dta";
|
||||
return wb;
|
||||
}
|
||||
function parse(data) {
|
||||
if (data[0] >= 102 && data[0] <= 115)
|
||||
return parse_legacy(data);
|
||||
if (data[0] === 60)
|
||||
return parse_tagged(data);
|
||||
throw new Error("Not a DTA file");
|
||||
}
|
||||
module.exports = __toCommonJS(dta_exports);
|
||||
// Annotate the CommonJS export names for ESM import in node:
|
||||
0 && (module.exports = {
|
||||
parse,
|
||||
set_utils,
|
||||
version
|
||||
});
|
2
packages/dta/dist/dta.min.js
vendored
Normal file
2
packages/dta/dist/dta.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
7
packages/dta/dist/dta.min.js.map
vendored
Normal file
7
packages/dta/dist/dta.min.js.map
vendored
Normal file
File diff suppressed because one or more lines are too long
2
packages/dta/dist/dta.mjs
generated
vendored
Normal file
2
packages/dta/dist/dta.mjs
generated
vendored
Normal file
File diff suppressed because one or more lines are too long
7
packages/dta/dist/dta.mjs.map
vendored
Normal file
7
packages/dta/dist/dta.mjs.map
vendored
Normal file
File diff suppressed because one or more lines are too long
629
packages/dta/dta.ts
Normal file
629
packages/dta/dta.ts
Normal file
@ -0,0 +1,629 @@
|
||||
import { CellObject, DenseWorkSheet, WorkBook, type utils } from 'xlsx';
|
||||
export { parse, set_utils, version };
|
||||
|
||||
const version = "0.0.2";
|
||||
|
||||
let _utils: typeof utils;
|
||||
/** Set internal instance of `utils`
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```js
|
||||
* const XLSX = require("xlsx");
|
||||
* const DTA = require("dta");
|
||||
* DTA.set_utils(XLSX.utils);
|
||||
* ```
|
||||
*
|
||||
* @param utils utils object
|
||||
*/
|
||||
function set_utils(utils: any): void {
|
||||
_utils = utils;
|
||||
}
|
||||
|
||||
function u8_to_str(u8: Uint8Array): string {
|
||||
return new TextDecoder().decode(u8);
|
||||
}
|
||||
|
||||
/* sadly the web zealots decided to abandon binary strings */
|
||||
function u8_to_latin1(u8: Uint8Array): string {
|
||||
return new TextDecoder("latin1").decode(u8);
|
||||
}
|
||||
|
||||
|
||||
/* TODO: generalize and map to SSF */
|
||||
function format_number_dta(value: number, format: string, t: number): CellObject {
|
||||
if(value < 0) { const res = format_number_dta(-value, format, t); res.w = "-" + res.w; return res; }
|
||||
const o: CellObject = { t: "n", v: value };
|
||||
/* NOTE: The Stata CSV exporter appears to ignore the column formats, instead using these defaults */
|
||||
switch(t) {
|
||||
case 251: case 0x62: case 65530: format = "%8.0g"; break; // byte
|
||||
case 252: case 0x69: case 65529: format = "%8.0g"; break; // int
|
||||
case 253: case 0x6c: case 65528: format = "%12.0g"; break; // long
|
||||
case 254: case 0x66: case 65527: format = "%9.0g"; break; // float
|
||||
case 255: case 0x64: case 65526: format = "%10.0g"; break; // double
|
||||
default: throw t;
|
||||
}
|
||||
try {
|
||||
let w = +((format.match(/%(\d+)/)||[])[1]) || 8;
|
||||
let k = 0;
|
||||
if(value < 1) ++k;
|
||||
if(value < 0.1) ++k;
|
||||
if(value < 0.01) ++k;
|
||||
if(value < 0.001) ++k;
|
||||
const e = value.toExponential();
|
||||
const exp = e.indexOf("e") == -1 ? 0 : +e.slice(e.indexOf("e")+1);
|
||||
let h = w - 2 - exp;
|
||||
if(h < 0) h = 0;
|
||||
var m = format.match(/%\d+\.(\d+)/);
|
||||
if(m && +m[1]) h = +m[1];
|
||||
o.w = (Math.round(value * 10**(h))/10**(h)).toFixed(h).replace(/^([-]?)0\./,"$1.");
|
||||
o.w = o.w.slice(0, w + k);
|
||||
if(o.w.indexOf(".") > -1) o.w = o.w.replace(/0+$/,"");
|
||||
o.w = o.w.replace(/\.$/,"");
|
||||
if(o.w == "") o.w = "0";
|
||||
} catch(e) {}
|
||||
return o;
|
||||
}
|
||||
|
||||
interface Payload {
|
||||
/** Offset */
|
||||
ptr: number;
|
||||
|
||||
/** Raw data */
|
||||
raw: Uint8Array;
|
||||
|
||||
/** DataView */
|
||||
dv: DataView;
|
||||
}
|
||||
|
||||
function u8_to_dataview(array: Uint8Array): DataView { return new DataView(array.buffer, array.byteOffset, array.byteLength); }
|
||||
function valid_inc(p: Payload, n: string): boolean {
|
||||
if(u8_to_str(p.raw.slice(p.ptr, p.ptr + n.length)) != n) return false;
|
||||
p.ptr += n.length;
|
||||
return true;
|
||||
}
|
||||
|
||||
function read_f64(p: Payload, LE: boolean): number | null {
|
||||
p.ptr += 8;
|
||||
const d = p.dv.getFloat64(p.ptr - 8, LE);
|
||||
return d > 8.988e+307 ? null : d;
|
||||
}
|
||||
function read_f32(p: Payload, LE: boolean): number | null {
|
||||
p.ptr += 4;
|
||||
const d = p.dv.getFloat32(p.ptr - 4, LE);
|
||||
return d > 1.701e+38 ? null : d;
|
||||
}
|
||||
function read_u32(p: Payload, LE: boolean) {
|
||||
p.ptr += 4;
|
||||
return p.dv.getUint32(p.ptr - 4, LE);
|
||||
}
|
||||
function read_i32(p: Payload, LE: boolean): number | null {
|
||||
p.ptr += 4;
|
||||
const u = p.dv.getInt32(p.ptr - 4, LE);
|
||||
return u > 0x7fffffe4 ? null : u;
|
||||
}
|
||||
function read_u16(p: Payload, LE: boolean) {
|
||||
p.ptr += 2;
|
||||
return p.dv.getUint16(p.ptr - 2, LE);
|
||||
}
|
||||
function read_i16(p: Payload, LE: boolean): number | null {
|
||||
p.ptr += 2;
|
||||
const u = p.dv.getInt16(p.ptr - 2, LE);
|
||||
return u > 32740 ? null : u;
|
||||
}
|
||||
function read_u8(p: Payload) {
|
||||
return p.raw[p.ptr++];
|
||||
}
|
||||
function read_i8(p: Payload): number | null {
|
||||
let u = p.raw[p.ptr++];
|
||||
u = u < 128 ? u : u - 256;
|
||||
return u > 100 ? null : u;
|
||||
}
|
||||
|
||||
/* the annotations are from `dtaversion` */
|
||||
const SUPPORTED_VERSIONS_TAGGED = [
|
||||
"117", // stata 13
|
||||
"118", // stata 14-18
|
||||
"119", // stata 15-18 (> 32767 variables)
|
||||
"120", // stata 18 (<= 32767, with aliases)
|
||||
"121", // stata 18 (> 32767, with aliases)
|
||||
];
|
||||
const SUPPORTED_VERSIONS_LEGACY = [
|
||||
102, // stata 1
|
||||
103, // stata 2/3
|
||||
104, // stata 4
|
||||
105, // stata 5
|
||||
108, // stata 6
|
||||
110, // stata 7
|
||||
111, // stata 7
|
||||
112, // stata 8/9
|
||||
113, // stata 8/9
|
||||
114, // stata 10/11
|
||||
115, // stata 12
|
||||
];
|
||||
|
||||
function parse_tagged(raw: Uint8Array): WorkBook {
|
||||
const err = ("Not a DTA file");
|
||||
|
||||
const d: Payload = {
|
||||
ptr: 0,
|
||||
raw,
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
|
||||
let vers: number = 118;
|
||||
let LE: boolean = true;
|
||||
let nvar: number = 0, nobs: number = 0, nobs_lo = 0, nobs_hi = 0;
|
||||
let label: string = "", timestamp: string = "";
|
||||
const var_types: number[] = [];
|
||||
const var_names: string[] = [];
|
||||
const formats: string[] = [];
|
||||
|
||||
/* 5. Dataset format definition */
|
||||
if(!valid_inc(d, "<stata_dta>")) throw err;
|
||||
|
||||
/* 5.1 Header <header> */
|
||||
{
|
||||
if(!valid_inc(d, "<header>")) throw err;
|
||||
|
||||
/* <release> */
|
||||
{
|
||||
if(!valid_inc(d, "<release>")) throw err;
|
||||
/* NOTE: this assumes the version is 3 characters wide */
|
||||
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr+3));
|
||||
d.ptr += 3;
|
||||
if(!valid_inc(d, "</release>")) throw err;
|
||||
if(SUPPORTED_VERSIONS_TAGGED.indexOf(res) == -1) throw (`Unsupported DTA ${res} file`);
|
||||
vers = +res;
|
||||
}
|
||||
|
||||
/* <byteorder> */
|
||||
{
|
||||
if(!valid_inc(d, "<byteorder>")) throw err;
|
||||
/* NOTE: this assumes the byte order is 3 characters wide */
|
||||
const res = u8_to_latin1(d.raw.slice(d.ptr, d.ptr+3));
|
||||
d.ptr += 3;
|
||||
if(!valid_inc(d, "</byteorder>")) throw err;
|
||||
switch(res) {
|
||||
case "MSF": LE = false; break;
|
||||
case "LSF": LE = true; break;
|
||||
default: throw (`Unsupported byteorder ${res}`);
|
||||
}
|
||||
}
|
||||
|
||||
/* <K> */
|
||||
{
|
||||
if(!valid_inc(d, "<K>")) throw err;
|
||||
nvar = (vers === 119 || vers >= 121) ? read_u32(d, LE) : read_u16(d, LE);
|
||||
if(!valid_inc(d, "</K>")) throw err;
|
||||
}
|
||||
|
||||
/* <N> */
|
||||
{
|
||||
if(!valid_inc(d, "<N>")) throw err;
|
||||
if(vers == 117) nobs = nobs_lo = read_u32(d, LE);
|
||||
else {
|
||||
const lo = read_u32(d, LE), hi = read_u32(d, LE);
|
||||
nobs = LE ? ((nobs_lo = lo) + (nobs_hi = hi) * Math.pow(2,32)) : ((nobs_lo = hi) + (nobs_hi = lo) * Math.pow(2,32));
|
||||
}
|
||||
if(nobs > 1e6) console.error(`More than 1 million observations -- extra rows will be dropped`);
|
||||
if(!valid_inc(d, "</N>")) throw err;
|
||||
}
|
||||
|
||||
/* <label> */
|
||||
{
|
||||
if(!valid_inc(d, "<label>")) throw err;
|
||||
const w = vers >= 118 ? 2 : 1;
|
||||
const strlen = w == 1 ? read_u8(d) : read_u16(d, LE);
|
||||
if(strlen > 0) label = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
|
||||
d.ptr += strlen;
|
||||
if(!valid_inc(d, "</label>")) throw err;
|
||||
}
|
||||
|
||||
/* <timestamp> */
|
||||
{
|
||||
if(!valid_inc(d, "<timestamp>")) throw err;
|
||||
const strlen = read_u8(d);
|
||||
timestamp = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + strlen));
|
||||
d.ptr += strlen;
|
||||
if(!valid_inc(d, "</timestamp>")) throw err;
|
||||
}
|
||||
|
||||
if(!valid_inc(d, "</header>")) throw err;
|
||||
}
|
||||
|
||||
/* 5.2 Map <map> */
|
||||
{
|
||||
/* TODO: validate map? */
|
||||
if(!valid_inc(d, "<map>")) throw err;
|
||||
/* 14 8-byte offsets for:
|
||||
<stata_data>
|
||||
<map>
|
||||
<variable_types>
|
||||
<varnames>
|
||||
<sortlist>
|
||||
<formats>
|
||||
<value_label_names>
|
||||
<variable_labels>
|
||||
<characteristics>
|
||||
<data>
|
||||
<strls>
|
||||
<value_labels>
|
||||
</stata_data>
|
||||
EOF
|
||||
*/
|
||||
d.ptr += 8 * 14;
|
||||
if(!valid_inc(d, "</map>")) throw err;
|
||||
}
|
||||
|
||||
let stride = 0;
|
||||
/* 5.3 Variable types <variable_types> */
|
||||
{
|
||||
if(!valid_inc(d, "<variable_types>")) throw err;
|
||||
for(var i = 0; i < nvar; ++i) {
|
||||
const type = read_u16(d, LE);
|
||||
var_types.push(type);
|
||||
if(type >= 1 && type <= 2045) stride += type;
|
||||
else switch(type) {
|
||||
case 32768: stride += 8; break;
|
||||
case 65525: stride += 0; break; // alias
|
||||
case 65526: stride += 8; break;
|
||||
case 65527: stride += 4; break;
|
||||
case 65528: stride += 4; break;
|
||||
case 65529: stride += 2; break;
|
||||
case 65530: stride += 1; break;
|
||||
default: throw (`Unsupported field type ${type}`);
|
||||
}
|
||||
}
|
||||
if(!valid_inc(d, "</variable_types>")) throw err;
|
||||
}
|
||||
|
||||
/* 5.4 Variable names <varnames> */
|
||||
{
|
||||
if(!valid_inc(d, "<varnames>")) throw err;
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
for(let i = 0; i < nvar; ++i) {
|
||||
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
|
||||
d.ptr += w;
|
||||
var_names.push(name.replace(/\x00[\s\S]*/,""));
|
||||
}
|
||||
if(!valid_inc(d, "</varnames>")) throw err;
|
||||
}
|
||||
|
||||
/* 5.5 Sort order of observations <sortlist> */
|
||||
{
|
||||
/* TODO: check sort list? */
|
||||
if(!valid_inc(d, "<sortlist>")) throw err;
|
||||
d.ptr += (2 * nvar + 2) * ((vers == 119 || vers == 121) ? 2 : 1);
|
||||
if(!valid_inc(d, "</sortlist>")) throw err;
|
||||
}
|
||||
|
||||
/* 5.6 Display formats <formats> */
|
||||
{
|
||||
if(!valid_inc(d, "<formats>")) throw err;
|
||||
const w = vers >= 118 ? 57 : 49;
|
||||
for(let i = 0; i < nvar; ++i) {
|
||||
const name = u8_to_str(d.raw.slice(d.ptr, d.ptr + w));
|
||||
d.ptr += w;
|
||||
formats.push(name.replace(/\x00[\s\S]*/,""));
|
||||
}
|
||||
if(!valid_inc(d, "</formats>")) throw err;
|
||||
}
|
||||
|
||||
const value_label_names: string[] = [];
|
||||
/* TODO: <value_label_names> */
|
||||
{
|
||||
if(!valid_inc(d, "<value_label_names>")) throw err;
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
for(let i = 0; i < nvar; ++i, d.ptr += w) value_label_names[i] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/,"");
|
||||
if(!valid_inc(d, "</value_label_names>")) throw err;
|
||||
}
|
||||
|
||||
/* TODO: <variable_labels> */
|
||||
{
|
||||
if(!valid_inc(d, "<variable_labels>")) throw err;
|
||||
const w = vers >= 118 ? 321 : 81;
|
||||
d.ptr += w * nvar;
|
||||
if(!valid_inc(d, "</variable_labels>")) throw err;
|
||||
}
|
||||
|
||||
/* 5.9 Characteristics <characteristics> */
|
||||
{
|
||||
if(!valid_inc(d, "<characteristics>")) throw err;
|
||||
while(valid_inc(d, "<ch>")) {
|
||||
const len = read_u32(d, LE);
|
||||
d.ptr += len;
|
||||
if(!valid_inc(d, "</ch>")) throw err;
|
||||
}
|
||||
if(!valid_inc(d, "</characteristics>")) throw err;
|
||||
}
|
||||
|
||||
const ws: DenseWorkSheet = (_utils.aoa_to_sheet([var_names], {dense: true} as any) as DenseWorkSheet);
|
||||
|
||||
var ptrs: Array<[number, number, Uint8Array]> = []
|
||||
/* 5.10 Data <data> */
|
||||
{
|
||||
if(!valid_inc(d, "<data>")) throw err;
|
||||
for(let R = 0; R < nobs; ++R) {
|
||||
const row: any[] = [];
|
||||
for(let C = 0; C < nvar; ++C) {
|
||||
let t = var_types[C];
|
||||
// TODO: formats, dta_12{0,1} aliases?
|
||||
if(t >= 1 && t <= 2045) {
|
||||
/* NOTE: dta_117 restricts strf to ASCII */
|
||||
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
|
||||
s = s.replace(/\x00[\s\S]*/,"");
|
||||
row[C] = s;
|
||||
d.ptr += t;
|
||||
} else switch(t) {
|
||||
case 65525: d.ptr += 0; break; // alias
|
||||
case 65530: row[C] = read_i8(d); break; // byte
|
||||
case 65529: row[C] = read_i16(d, LE); break; // int
|
||||
case 65528: row[C] = read_i32(d, LE); break; // long
|
||||
case 65527: row[C] = read_f32(d, LE); break; // float
|
||||
case 65526: row[C] = read_f64(d, LE); break; // double
|
||||
case 32768: {
|
||||
row[C] = "##SheetJStrL##";
|
||||
ptrs.push([R+1,C, d.raw.slice(d.ptr, d.ptr + 8)]);
|
||||
d.ptr += 8;
|
||||
} break;
|
||||
default: throw (`Unsupported field type ${t} for ${var_names[C]}`);
|
||||
}
|
||||
if(typeof row[C] == "number" && formats[C]) row[C] = format_number_dta(row[C], formats[C], t);
|
||||
}
|
||||
_utils.sheet_add_aoa(ws, [row], {origin: -1, sheetStubs: true});
|
||||
}
|
||||
if(!valid_inc(d, "</data>")) throw err;
|
||||
}
|
||||
|
||||
/* 5.11 StrLs <strls> */
|
||||
{
|
||||
if(!valid_inc(d, "<strls>")) throw err;
|
||||
|
||||
const strl_tbl: string[][] = [];
|
||||
while(d.raw[d.ptr] == 71 /* G */) {
|
||||
if(!valid_inc(d, "GSO")) throw err;
|
||||
const v = read_u32(d, LE);
|
||||
let o = 0;
|
||||
if(vers == 117) o = read_u32(d, LE);
|
||||
else {
|
||||
const lo = read_u32(d, LE), hi = read_u32(d, LE);
|
||||
o = LE ? (lo + hi * Math.pow(2,32)) : (hi + lo * Math.pow(2,32));
|
||||
if(o > 1e6) console.error(`More than 1 million observations -- data will be dropped`);
|
||||
}
|
||||
const t = read_u8(d);
|
||||
const len = read_u32(d, LE);
|
||||
if(!strl_tbl[o]) strl_tbl[o] = [];
|
||||
let str = "";
|
||||
if(t == 129) {
|
||||
// TODO: dta_117 codepage
|
||||
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
|
||||
d.ptr += len;
|
||||
} else {
|
||||
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/,"");
|
||||
d.ptr += len;
|
||||
}
|
||||
strl_tbl[o][v] = str;
|
||||
}
|
||||
if(!valid_inc(d, "</strls>")) throw err;
|
||||
|
||||
ptrs.forEach(([R,C,buf]) => {
|
||||
const dv = u8_to_dataview(buf);
|
||||
let v = 0, o = 0;
|
||||
switch(vers) {
|
||||
case 117: { // v(4) o(4)
|
||||
v = dv.getUint32(0, LE);
|
||||
o = dv.getUint32(4, LE);
|
||||
} break;
|
||||
|
||||
case 118: case 120: { // v(2) o(6)
|
||||
v = dv.getUint16(0, LE);
|
||||
const o1 = dv.getUint16(2, LE), o2 = dv.getUint32(4, LE);
|
||||
o = LE ? o1 + o2 * 65536 : o2 + o1 * (2**32);
|
||||
} break;
|
||||
|
||||
case 119: case 121: { // v(3) o(5)
|
||||
const v1 = dv.getUint16(0, LE), v2 = buf[2];
|
||||
v = LE ? v1 + (v2 << 16) : v2 + (v1 << 8);
|
||||
const o1 = buf[3], o2 = dv.getUint32(4, LE);
|
||||
o = LE ? o1 + o2 * 256 : o2 + o1 * (2**32);
|
||||
}
|
||||
}
|
||||
ws["!data"][R][C].v = strl_tbl[o][v];
|
||||
});
|
||||
}
|
||||
|
||||
/* 5.12 Value labels <value_labels> */
|
||||
{
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
if(!valid_inc(d, "<value_labels>")) throw err;
|
||||
while(valid_inc(d, "<lbl>")) {
|
||||
let len = read_u32(d, LE);
|
||||
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/,"");
|
||||
d.ptr += w;
|
||||
d.ptr += 3; // padding
|
||||
const labels: string[] = [];
|
||||
{
|
||||
const n = read_u32(d, LE);
|
||||
const txtlen = read_u32(d, LE);
|
||||
const off: number[] = [], val: number[] = [];
|
||||
for(let i = 0; i < n; ++i) off.push(read_u32(d, LE));
|
||||
for(let i = 0; i < n; ++i) val.push(read_u32(d, LE));
|
||||
const str = u8_to_str(d.raw.slice(d.ptr, d.ptr + txtlen));
|
||||
d.ptr += txtlen;
|
||||
for(let i = 0; i < n; ++i) labels[val[i]] = str.slice(off[i], str.indexOf("\x00", off[i]));
|
||||
}
|
||||
const C = value_label_names.indexOf(labname);
|
||||
if(C == -1) throw new Error(`unexpected value label |${labname}|`);
|
||||
for(let R = 1; R < ws["!data"].length; ++R) {
|
||||
const cell = ws["!data"][R][C];
|
||||
cell.t = "s"; cell.v = cell.w = labels[(cell.v as number)||0];
|
||||
}
|
||||
//d.ptr += len; // value_label_table
|
||||
if(!valid_inc(d, "</lbl>")) throw err;
|
||||
}
|
||||
if(!valid_inc(d, "</value_labels>")) throw err;
|
||||
}
|
||||
|
||||
if(!valid_inc(d, "</stata_dta>")) throw err;
|
||||
const wb = _utils.book_new();
|
||||
_utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
wb.bookType = "dta" as any;
|
||||
return wb;
|
||||
}
|
||||
|
||||
function parse_legacy(raw: Uint8Array): WorkBook {
|
||||
let vers: number = raw[0];
|
||||
if(SUPPORTED_VERSIONS_LEGACY.indexOf(vers) == -1) throw new Error("Not a DTA file");
|
||||
|
||||
const d: Payload = {
|
||||
ptr: 1,
|
||||
raw,
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
|
||||
let LE: boolean = true;
|
||||
let nvar: number = 0, nobs: number = 0;
|
||||
let label: string = "", timestamp: string = "";
|
||||
const var_types: number[] = [];
|
||||
const var_names: string[] = [];
|
||||
const formats: string[] = [];
|
||||
|
||||
/* 5.1 Header */
|
||||
{
|
||||
const byteorder = read_u8(d);
|
||||
switch(byteorder) {
|
||||
case 1: LE = false; break;
|
||||
case 2: LE = true; break;
|
||||
default: throw (`DTA ${vers} Unexpected byteorder ${byteorder}`);
|
||||
}
|
||||
|
||||
let byte = read_u8(d);
|
||||
if(byte != 1) throw (`DTA ${vers} Unexpected filetype ${byte}`);
|
||||
// NOTE: dta_105 technically supports filetype 2
|
||||
|
||||
d.ptr++; // "unused"
|
||||
nvar = read_u16(d, LE);
|
||||
nobs = read_u32(d, LE);
|
||||
d.ptr += (vers >= 108 ? 81 : vers >= 103 ? 32 : 30); // TODO: data_label
|
||||
if(vers >= 105) d.ptr += 18; // TODO: time_stamp
|
||||
}
|
||||
|
||||
/* 5.2 Descriptors */
|
||||
const value_label_names: string[] = [];
|
||||
{
|
||||
let C = 0;
|
||||
|
||||
// typlist
|
||||
for(C = 0; C < nvar; ++C) var_types.push(read_u8(d));
|
||||
|
||||
// varlist
|
||||
const w = vers >= 110 ? 33 : 9;
|
||||
for(C = 0; C < nvar; ++C) {
|
||||
var_names.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00[\s\S]*$/,""));
|
||||
d.ptr += w;
|
||||
}
|
||||
|
||||
// srtlist
|
||||
d.ptr += 2*(nvar + 1);
|
||||
|
||||
// fmtlist
|
||||
const fw = (vers >= 114 ? 49 : vers >= 105 ? 12 : 7);
|
||||
for(C = 0; C < nvar; ++C) {
|
||||
formats.push(u8_to_str(d.raw.slice(d.ptr, d.ptr + fw)).replace(/\x00[\s\S]*$/,""));
|
||||
d.ptr += fw;
|
||||
}
|
||||
// lbllist
|
||||
const lw = vers >= 110 ? 33 : 9;
|
||||
for(let i = 0; i < nvar; ++i, d.ptr += lw) value_label_names[i] = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + lw)).replace(/\x00.*$/,"");
|
||||
}
|
||||
|
||||
/* 5.3 Variable labels */
|
||||
// TODO: should these names be used in the worksheet?
|
||||
d.ptr += (vers >= 106 ? 81 : 32) * nvar;
|
||||
|
||||
/* 5.4 Expansion fields */
|
||||
if(vers >= 105) while(d.ptr < d.raw.length) {
|
||||
const dt = read_u8(d), len = (vers >= 110 ? read_u32 : read_u16)(d, LE);
|
||||
if(dt == 0 && len == 0) break;
|
||||
d.ptr += len;
|
||||
}
|
||||
|
||||
const ws: DenseWorkSheet = (_utils.aoa_to_sheet([var_names], {dense: true} as any) as DenseWorkSheet);
|
||||
|
||||
/* 5.5 Data */
|
||||
for(let R = 0; R < nobs; ++R) {
|
||||
const row: any[] = [];
|
||||
for(let C = 0; C < nvar; ++C) {
|
||||
let t = var_types[C];
|
||||
// TODO: data type processing
|
||||
if((vers == 111 || vers >= 113) && t >= 1 && t <= 244) {
|
||||
/* NOTE: dta_117 restricts strf to ASCII */
|
||||
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t));
|
||||
s = s.replace(/\x00[\s\S]*/,"");
|
||||
row[C] = s;
|
||||
d.ptr += t;
|
||||
} else if((vers == 112 || vers <= 110) && t >= 0x80) {
|
||||
/* NOTE: dta_105 restricts strf to ASCII */
|
||||
let s = u8_to_str(d.raw.slice(d.ptr, d.ptr + t - 0x7F));
|
||||
s = s.replace(/\x00[\s\S]*/,"");
|
||||
row[C] = s;
|
||||
d.ptr += t - 0x7F;
|
||||
} else switch(t) {
|
||||
case 251: case 0x62: row[C] = read_i8(d); break; // byte
|
||||
case 252: case 0x69: row[C] = read_i16(d, LE); break; // int
|
||||
case 253: case 0x6c: row[C] = read_i32(d, LE); break; // long
|
||||
case 254: case 0x66: row[C] = read_f32(d, LE); break; // float
|
||||
case 255: case 0x64: row[C] = read_f64(d, LE); break; // double
|
||||
default: throw (`Unsupported field type ${t} for ${var_names[C]}`);
|
||||
}
|
||||
if(typeof row[C] == "number" && formats[C]) row[C] = format_number_dta(row[C], formats[C], t);
|
||||
}
|
||||
_utils.sheet_add_aoa(ws, [row], {origin: -1, sheetStubs: true});
|
||||
}
|
||||
|
||||
/* 5.6 Value labels */
|
||||
// TODO: < 115
|
||||
if(vers >= 115) while(d.ptr < d.raw.length) {
|
||||
const w = 33;
|
||||
let len = read_u32(d, LE);
|
||||
const labname = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + w)).replace(/\x00.*$/,"");
|
||||
d.ptr += w;
|
||||
d.ptr += 3; // padding
|
||||
const labels: string[] = [];
|
||||
{
|
||||
const n = read_u32(d, LE);
|
||||
const txtlen = read_u32(d, LE);
|
||||
const off: number[] = [], val: number[] = [];
|
||||
for(let i = 0; i < n; ++i) off.push(read_u32(d, LE));
|
||||
for(let i = 0; i < n; ++i) val.push(read_u32(d, LE));
|
||||
const str = u8_to_latin1(d.raw.slice(d.ptr, d.ptr + txtlen));
|
||||
d.ptr += txtlen;
|
||||
for(let i = 0; i < n; ++i) labels[val[i]] = str.slice(off[i], str.indexOf("\x00", off[i]));
|
||||
}
|
||||
const C = value_label_names.indexOf(labname);
|
||||
if(C == -1) throw new Error(`unexpected value label |${labname}|`);
|
||||
for(let R = 1; R < ws["!data"].length; ++R) {
|
||||
const cell = ws["!data"][R][C];
|
||||
cell.t = "s"; cell.v = cell.w = labels[(cell.v as number)||0];
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const wb: WorkBook = _utils.book_new();
|
||||
_utils.book_append_sheet(wb, ws, "Sheet1");
|
||||
wb.bookType = "dta" as any;
|
||||
return wb;
|
||||
}
|
||||
|
||||
/** Parse DTA file
|
||||
*
|
||||
* NOTE: In NodeJS, `Buffer` extends `Uint8Array`
|
||||
*
|
||||
* @param {Uint8Array} data File data
|
||||
*/
|
||||
function parse(data: Uint8Array): WorkBook {
|
||||
if(data[0] >= 102 && data[0] <= 115) return parse_legacy(data);
|
||||
if(data[0] === 60) return parse_tagged(data);
|
||||
throw new Error("Not a DTA file");
|
||||
}
|
39
packages/dta/package.json
Normal file
39
packages/dta/package.json
Normal file
@ -0,0 +1,39 @@
|
||||
{
|
||||
"name": "dta",
|
||||
"version": "0.0.2",
|
||||
"author": "sheetjs",
|
||||
"description": "Stata .dta codecs for SheetJS Common Spreadsheet Format",
|
||||
"bin": {
|
||||
"dta2csv": "./bin/dta2csv.njs"
|
||||
},
|
||||
"main": "dist/dta.js",
|
||||
"module": "dist/dta.mjs",
|
||||
"types": "types",
|
||||
"files": [
|
||||
"bin/",
|
||||
"dist/",
|
||||
"types/"
|
||||
],
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs",
|
||||
"directory": "packages/dta"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "make test",
|
||||
"build": "make",
|
||||
"lint": "make fullint",
|
||||
"dtslint": "dtslint types"
|
||||
},
|
||||
"homepage": "https://sheetjs.com/",
|
||||
"bugs": {
|
||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
"node": ">=12.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.1/xlsx-0.20.1.tgz"
|
||||
}
|
||||
}
|
32
packages/dta/test.js
Normal file
32
packages/dta/test.js
Normal file
@ -0,0 +1,32 @@
|
||||
/* eslint-env mocha, node, es6 */
|
||||
const fs = require("fs"), assert = require("assert");
|
||||
|
||||
const DTA = require("./");
|
||||
const XLSX = require("xlsx");
|
||||
DTA.set_utils(XLSX.utils);
|
||||
|
||||
const test_folders = [
|
||||
"test_files"
|
||||
];
|
||||
for(let tF of test_folders) describe(tF, () => {
|
||||
const test_files = fs.readdirSync(tF);
|
||||
for(let tf of test_files) {
|
||||
if(tf.endsWith("csv")) it(`${tf.replace(".csv", "")} [CSV]`, () => {
|
||||
const buf = fs.readFileSync(`${tF}/${tf.replace(".csv", "")}`);
|
||||
const wb = DTA.parse(buf);
|
||||
assert(wb.SheetNames.length > 0);
|
||||
/* stata will represent unspecified values as single spaces */
|
||||
//wb.Sheets[wb.SheetNames[0]]["!data"].forEach(row => row.forEach(cell => {if(cell.t == "z") {cell.t = "s"; cell.v = " ";}}));
|
||||
const csvstr = XLSX.utils.sheet_to_csv(wb.Sheets[wb.SheetNames[0]]);
|
||||
const baseline = fs.readFileSync(`${tF}/${tf}`, "utf8").replace(/[\r\n]+/g,"\n");
|
||||
assert.equal(csvstr.trim(), baseline.trim());
|
||||
});
|
||||
if(!tf.endsWith("dta")) continue;
|
||||
it(tf, () => {
|
||||
const buf = fs.readFileSync(`${tF}/${tf}`);
|
||||
const wb = DTA.parse(buf);
|
||||
assert(wb.SheetNames.length > 0);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
23
packages/dta/types/index.d.ts
vendored
Normal file
23
packages/dta/types/index.d.ts
vendored
Normal file
@ -0,0 +1,23 @@
|
||||
import { WorkBook } from 'xlsx';
|
||||
export { parse, set_utils, version };
|
||||
declare const version = "0.0.2";
|
||||
/** Set internal instance of `utils`
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* ```js
|
||||
* const XLSX = require("xlsx");
|
||||
* const DTA = require("dta");
|
||||
* DTA.set_utils(XLSX.utils);
|
||||
* ```
|
||||
*
|
||||
* @param utils utils object
|
||||
*/
|
||||
declare function set_utils(utils: any): void;
|
||||
/** Parse DTA file
|
||||
*
|
||||
* NOTE: In NodeJS, `Buffer` extends `Uint8Array`
|
||||
*
|
||||
* @param {Uint8Array} data File data
|
||||
*/
|
||||
declare function parse(data: Uint8Array): WorkBook;
|
@ -59,7 +59,7 @@ ctest: ## Build browser test fixtures
|
||||
|
||||
.PHONY: ctestserv
|
||||
ctestserv: ## Start a test server on port 8000
|
||||
@cd ctest && python -mSimpleHTTPServer
|
||||
@cd ctest && python -mSimpleHTTPServer || python3 -mhttp.server || npx -y http-server -p 8000 .
|
||||
|
||||
|
||||
## Code Checking
|
||||
|
@ -8,16 +8,14 @@ features like international support as well as dedicated support.
|
||||
|
||||
## Installation
|
||||
|
||||
With [npm](https://www.npmjs.org/package/ssf):
|
||||
|
||||
```bash
|
||||
$ npm install ssf
|
||||
$ npm install https://cdn.sheetjs.com/ssf-0.11.3/ssf-0.11.3.tgz
|
||||
```
|
||||
|
||||
In the browser:
|
||||
|
||||
```html
|
||||
<script src="ssf.js"></script>
|
||||
<script src="https://cdn.sheetjs.com/ssf-0.11.3/ssf.js"></script>
|
||||
```
|
||||
|
||||
The browser exposes a variable `SSF`
|
||||
@ -107,13 +105,3 @@ granted by the Apache 2.0 license are reserved by the Original Author.
|
||||
## Badges
|
||||
|
||||
[![Sauce Test Status](https://saucelabs.com/browser-matrix/ssfjs.svg)](https://saucelabs.com/u/ssfjs)
|
||||
|
||||
[![Build Status](https://travis-ci.org/SheetJS/ssf.svg?branch=master)](https://travis-ci.org/SheetJS/ssf)
|
||||
|
||||
[![Coverage Status](http://img.shields.io/coveralls/SheetJS/ssf/master.svg)](https://coveralls.io/r/SheetJS/ssf?branch=master)
|
||||
|
||||
[![NPM Downloads](https://img.shields.io/npm/dt/ssf.svg)](https://npmjs.org/package/ssf)
|
||||
|
||||
[![Dependencies Status](https://david-dm.org/sheetjs/ssf/status.svg)](https://david-dm.org/sheetjs/ssf)
|
||||
|
||||
[![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/ssf?pixel)](https://github.com/SheetJS/ssf)
|
||||
|
@ -1 +1 @@
|
||||
SSF.version = '0.11.2';
|
||||
SSF.version = '0.11.3';
|
||||
|
@ -5,6 +5,6 @@ function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t
|
||||
function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
|
||||
function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
var p2_32 = Math.pow(2,32);
|
||||
var p2_32 = /*#__PURE__*/Math.pow(2,32);
|
||||
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
|
||||
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
|
||||
|
@ -1,4 +1,5 @@
|
||||
function init_table(t/*:any*/) {
|
||||
if(!t) t = {};
|
||||
t[0]= 'General';
|
||||
t[1]= '0';
|
||||
t[2]= '0.00';
|
||||
@ -28,6 +29,7 @@ function init_table(t/*:any*/) {
|
||||
t[48]= '##0.0E+0';
|
||||
t[49]= '@';
|
||||
t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
|
||||
return t;
|
||||
}
|
||||
|
||||
var table_fmt = {};
|
||||
|
20
packages/ssf/bits/27_normalize.js
Normal file
20
packages/ssf/bits/27_normalize.js
Normal file
@ -0,0 +1,20 @@
|
||||
function normalize_xl_unsafe(v/*:number*/)/*:number*/ {
|
||||
if(v == 0) return 0;
|
||||
var s = v.toPrecision(17);
|
||||
if(s.indexOf("e") > -1) {
|
||||
var m = s.slice(0, s.indexOf("e"));
|
||||
if(m.indexOf(".") > -1) {
|
||||
var tail = m.charAt(0) + m.slice(2, 17);
|
||||
m = m.slice(0, 16);
|
||||
if(tail.length == 16) {
|
||||
m = String(Math.round(Number(tail.slice(0,15) + "." + tail.slice(15))));
|
||||
if(m.length == 16) m = m.slice(0,2) + "." + m.slice(2);
|
||||
else m = m.charAt(0) + "." + m.slice(1);
|
||||
}
|
||||
}
|
||||
else m = m.slice(0,15) + fill("0", m.length - 15);
|
||||
return Number(m + s.slice(s.indexOf("e")));
|
||||
}
|
||||
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
|
||||
return Number(n);
|
||||
}
|
@ -29,6 +29,7 @@ var general_fmt_num = (function make_general_fmt_num() {
|
||||
}
|
||||
|
||||
function general_fmt_num_base(v/*:number*/)/*:string*/ {
|
||||
if(!isFinite(v)) return isNaN(v) ? "#VALUE!" : "#DIV/0!";
|
||||
var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
|
||||
|
||||
if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
|
||||
|
@ -54,7 +54,7 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
|
||||
switch(fmt) {
|
||||
case '[h]': case '[hh]': out = val.D*24+val.H; break;
|
||||
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
|
||||
default: throw 'bad abstime format: ' + fmt;
|
||||
} outl = fmt.length === 3 ? 1 : 2; break;
|
||||
case 101: /* 'e' era */
|
||||
|
@ -39,7 +39,7 @@ function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:s
|
||||
return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
|
||||
}
|
||||
var dec1 = /^#*0*\.([0#]+)/;
|
||||
var closeparen = /\).*[0#]/;
|
||||
var closeparen = /\)[^)]*[0#]/;
|
||||
var phone = /\(###\) ###\\?-####/;
|
||||
function hashq(str/*:string*/)/*:string*/ {
|
||||
var o = "", cc;
|
||||
|
@ -1,4 +1,5 @@
|
||||
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
if(typeof v == "number") v = normalize_xl_unsafe(v);
|
||||
var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
|
||||
var hr='H';
|
||||
/* Tokenize */
|
||||
@ -85,10 +86,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
switch(out[i].t) {
|
||||
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
|
||||
case 's':
|
||||
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
|
||||
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
|
||||
if(bt < 3) bt = 3;
|
||||
/* falls through */
|
||||
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
|
||||
case 'd': case 'y': case 'e': lst=out[i].t; break;
|
||||
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
|
||||
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
|
||||
case 'X': /*if(out[i].v === "B2");*/
|
||||
break;
|
||||
@ -98,19 +100,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* time rounding depends on presence of minute / second / usec fields */
|
||||
var _dt;
|
||||
switch(bt) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
/*::if(!dt) break;*/
|
||||
case 2:
|
||||
case 3:
|
||||
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
|
||||
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
|
||||
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
|
||||
break;
|
||||
case 2:
|
||||
/*::if(!dt) break;*/
|
||||
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
case 4:
|
||||
switch(ss0) {
|
||||
case 1: dt.u = Math.round(dt.u * 10)/10; break;
|
||||
case 2: dt.u = Math.round(dt.u * 100)/100; break;
|
||||
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
|
||||
}
|
||||
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
|
||||
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
|
||||
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
|
||||
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -4,6 +4,8 @@ function choose_fmt(f/*:string*/, v/*:any*/) {
|
||||
if(l<4 && lat>-1) --l;
|
||||
if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
|
||||
if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
|
||||
/* NOTE: most spreadsheet software do not support NaN or infinities */
|
||||
if(typeof v === "number" && !isFinite(v)) v = 0;
|
||||
switch(fmt.length) {
|
||||
case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
|
||||
case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
|
||||
@ -40,5 +42,7 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
|
||||
if(isgeneral(f[1])) return general_fmt(v, o);
|
||||
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
|
||||
else if(v === "" || v == null) return "";
|
||||
else if(isNaN(v) && f[1].indexOf("0") > -1) return "#VALUE!";
|
||||
else if(!isFinite(v) && f[1].indexOf("0") > -1) return "#DIV/0!";
|
||||
return eval_fmt(f[1], v, o, f[0]);
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "ssf",
|
||||
"version": "0.11.2",
|
||||
"version": "0.11.3",
|
||||
"author": "sheetjs",
|
||||
"description": "Format data using ECMA-376 spreadsheet Format Codes",
|
||||
"keywords": [
|
||||
@ -19,11 +19,12 @@
|
||||
"blanket": "~1.2.3",
|
||||
"dtslint": "^0.1.2",
|
||||
"mocha": "~2.5.3",
|
||||
"typescript": "2.2.0"
|
||||
"typescript": "2.2.0",
|
||||
"xlsx": "https://cdn.sheetjs.com/xlsx-0.20.2/xlsx-0.20.2.tgz"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git://github.com/SheetJS/sheetjs.git",
|
||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs",
|
||||
"directory": "packages/ssf"
|
||||
},
|
||||
"scripts": {
|
||||
@ -48,9 +49,9 @@
|
||||
"holes"
|
||||
]
|
||||
},
|
||||
"homepage": "http://sheetjs.com/",
|
||||
"homepage": "https://sheetjs.com/",
|
||||
"bugs": {
|
||||
"url": "https://github.com/SheetJS/sheetjs/issues"
|
||||
"url": "https://git.sheetjs.com/SheetJS/sheetjs/issues"
|
||||
},
|
||||
"license": "Apache-2.0",
|
||||
"engines": {
|
||||
|
@ -3,8 +3,8 @@
|
||||
/*jshint -W041 */
|
||||
/*:: declare var DO_NOT_EXPORT_SSF: any; */
|
||||
var SSF/*:SSFModule*/ = ({}/*:any*/);
|
||||
var make_ssf = function make_ssf(SSF/*:SSFModule*/){
|
||||
SSF.version = '0.11.2';
|
||||
function make_ssf(SSF/*:SSFModule*/){
|
||||
SSF.version = '0.11.3';
|
||||
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
|
||||
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
|
||||
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
@ -12,7 +12,7 @@ function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t
|
||||
function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
|
||||
function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
|
||||
var p2_32 = Math.pow(2,32);
|
||||
var p2_32 = /*#__PURE__*/Math.pow(2,32);
|
||||
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
|
||||
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
|
||||
/*::
|
||||
@ -42,6 +42,7 @@ var months/*:Array<Array<string> >*/ = [
|
||||
['D', 'Dec', 'December']
|
||||
];
|
||||
function init_table(t/*:any*/) {
|
||||
if(!t) t = {};
|
||||
t[0]= 'General';
|
||||
t[1]= '0';
|
||||
t[2]= '0.00';
|
||||
@ -71,6 +72,7 @@ function init_table(t/*:any*/) {
|
||||
t[48]= '##0.0E+0';
|
||||
t[49]= '@';
|
||||
t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
|
||||
return t;
|
||||
}
|
||||
|
||||
var table_fmt = {};
|
||||
@ -141,6 +143,26 @@ var default_str = {
|
||||
44: '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)'
|
||||
};
|
||||
|
||||
function normalize_xl_unsafe(v/*:number*/)/*:number*/ {
|
||||
if(v == 0) return 0;
|
||||
var s = v.toPrecision(17);
|
||||
if(s.indexOf("e") > -1) {
|
||||
var m = s.slice(0, s.indexOf("e"));
|
||||
if(m.indexOf(".") > -1) {
|
||||
var tail = m.charAt(0) + m.slice(2, 17);
|
||||
m = m.slice(0, 16);
|
||||
if(tail.length == 16) {
|
||||
m = String(Math.round(Number(tail.slice(0,15) + "." + tail.slice(15))));
|
||||
if(m.length == 16) m = m.slice(0,2) + "." + m.slice(2);
|
||||
else m = m.charAt(0) + "." + m.slice(1);
|
||||
}
|
||||
}
|
||||
else m = m.slice(0,15) + fill("0", m.length - 15);
|
||||
return Number(m + s.slice(s.indexOf("e")));
|
||||
}
|
||||
var n = s.indexOf(".") > -1 ? s.slice(0, (s.slice(0,2) == "0." ? 17 : 16)) : (s.slice(0,15) + fill("0", s.length - 15));
|
||||
return Number(n);
|
||||
}
|
||||
function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/ {
|
||||
var sgn = x < 0 ? -1 : 1;
|
||||
var B = x * sgn;
|
||||
@ -201,10 +223,6 @@ function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
|
||||
else if(v >= base1904) epoch += 24*60*60*1000;
|
||||
return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
|
||||
}
|
||||
/* The longest 32-bit integer text is "-4294967296", exactly 11 chars */
|
||||
function general_fmt_int(v/*:number*/)/*:string*/ { return v.toString(10); }
|
||||
SSF._general_int = general_fmt_int;
|
||||
|
||||
/* ECMA-376 18.8.30 numFmt*/
|
||||
/* Note: `toPrecision` uses standard form when prec > E and E >= -6 */
|
||||
var general_fmt_num = (function make_general_fmt_num() {
|
||||
@ -236,6 +254,7 @@ var general_fmt_num = (function make_general_fmt_num() {
|
||||
}
|
||||
|
||||
function general_fmt_num_base(v/*:number*/)/*:string*/ {
|
||||
if(!isFinite(v)) return isNaN(v) ? "#VALUE!" : "#DIV/0!";
|
||||
var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
|
||||
|
||||
if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
|
||||
@ -257,6 +276,7 @@ SSF._general_num = general_fmt_num;
|
||||
- "up to 11 characters" displayed for numbers
|
||||
- Default date format (code 14) used for Dates
|
||||
|
||||
The longest 32-bit integer text is "-2147483648", exactly 11 chars
|
||||
TODO: technically the display depends on the width of the cell
|
||||
*/
|
||||
function general_fmt(v/*:any*/, opts/*:any*/) {
|
||||
@ -336,7 +356,7 @@ function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:str
|
||||
switch(fmt) {
|
||||
case '[h]': case '[hh]': out = val.D*24+val.H; break;
|
||||
case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
|
||||
case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+(ss0 == 0 ? Math.round(val.S+val.u) : val.S); break;
|
||||
default: throw 'bad abstime format: ' + fmt;
|
||||
} outl = fmt.length === 3 ? 1 : 2; break;
|
||||
case 101: /* 'e' era */
|
||||
@ -400,7 +420,7 @@ function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:s
|
||||
return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
|
||||
}
|
||||
var dec1 = /^#*0*\.([0#]+)/;
|
||||
var closeparen = /\).*[0#]/;
|
||||
var closeparen = /\)[^)]*[0#]/;
|
||||
var phone = /\(###\) ###\\?-####/;
|
||||
function hashq(str/*:string*/)/*:string*/ {
|
||||
var o = "", cc;
|
||||
@ -694,6 +714,7 @@ function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
|
||||
}
|
||||
SSF.is_date = fmt_is_date;
|
||||
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
if(typeof v == "number") v = normalize_xl_unsafe(v);
|
||||
var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
|
||||
var hr='H';
|
||||
/* Tokenize */
|
||||
@ -780,10 +801,11 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
switch(out[i].t) {
|
||||
case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
|
||||
case 's':
|
||||
if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
|
||||
if((ssm=out[i].v.match(/\.0+$/))) { ss0=Math.max(ss0,ssm[0].length-1); bt = 4;}
|
||||
if(bt < 3) bt = 3;
|
||||
/* falls through */
|
||||
case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
|
||||
case 'd': case 'y': case 'e': lst=out[i].t; break;
|
||||
case 'M': lst=out[i].t; if(bt < 2) bt = 2; break;
|
||||
case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
|
||||
case 'X': /*if(out[i].v === "B2");*/
|
||||
break;
|
||||
@ -793,19 +815,29 @@ function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
|
||||
if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
|
||||
}
|
||||
}
|
||||
|
||||
/* time rounding depends on presence of minute / second / usec fields */
|
||||
var _dt;
|
||||
switch(bt) {
|
||||
case 0: break;
|
||||
case 1:
|
||||
/*::if(!dt) break;*/
|
||||
case 2:
|
||||
case 3:
|
||||
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
|
||||
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
|
||||
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
|
||||
break;
|
||||
case 2:
|
||||
/*::if(!dt) break;*/
|
||||
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
case 4:
|
||||
switch(ss0) {
|
||||
case 1: dt.u = Math.round(dt.u * 10)/10; break;
|
||||
case 2: dt.u = Math.round(dt.u * 100)/100; break;
|
||||
case 3: dt.u = Math.round(dt.u * 1000)/1000; break;
|
||||
}
|
||||
if(dt.u >= 1) { dt.u = 0; ++dt.S; }
|
||||
if(dt.S >= 60) { dt.S = 0; ++dt.M; }
|
||||
if(dt.M >= 60) { dt.M = 0; ++dt.H; }
|
||||
if(dt.H >= 24) { dt.H = 0; ++dt.D; _dt = parse_date_code(dt.D); _dt.u = dt.u; _dt.S = dt.S; _dt.M = dt.M; _dt.H = dt.H; dt = _dt; }
|
||||
break;
|
||||
}
|
||||
|
||||
@ -922,6 +954,8 @@ function choose_fmt(f/*:string*/, v/*:any*/) {
|
||||
if(l<4 && lat>-1) --l;
|
||||
if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
|
||||
if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
|
||||
/* NOTE: most spreadsheet software do not support NaN or infinities */
|
||||
if(typeof v === "number" && !isFinite(v)) v = 0;
|
||||
switch(fmt.length) {
|
||||
case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
|
||||
case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
|
||||
@ -958,6 +992,8 @@ function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
|
||||
if(isgeneral(f[1])) return general_fmt(v, o);
|
||||
if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
|
||||
else if(v === "" || v == null) return "";
|
||||
else if(isNaN(v) && f[1].indexOf("0") > -1) return "#VALUE!";
|
||||
else if(!isFinite(v) && f[1].indexOf("0") > -1) return "#DIV/0!";
|
||||
return eval_fmt(f[1], v, o, f[0]);
|
||||
}
|
||||
function load_entry(fmt/*:string*/, idx/*:?number*/)/*:number*/ {
|
||||
@ -985,7 +1021,8 @@ SSF.load_table = function load_table(tbl/*:SSFTable*/)/*:void*/ {
|
||||
};
|
||||
SSF.init_table = init_table;
|
||||
SSF.format = format;
|
||||
};
|
||||
SSF.choose_format = choose_fmt;
|
||||
}
|
||||
make_ssf(SSF);
|
||||
/*global module */
|
||||
if(typeof module !== 'undefined' && typeof DO_NOT_EXPORT_SSF === 'undefined') module.exports = SSF;
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user