forked from sheetjs/sheetjs
version bump 0.20.1
This commit is contained in:
parent
9199c2600c
commit
29d46c07a8
12
CHANGELOG.md
12
CHANGELOG.md
@ -4,6 +4,18 @@ This log is intended to keep track of backwards-incompatible changes, including
|
||||
but not limited to API changes and file location changes. Minor behavioral
|
||||
changes may not be included if they are not expected to break existing code.
|
||||
|
||||
## v0.20.1
|
||||
|
||||
* `init` use packaged test files to work around GitHub breaking changes
|
||||
* SSF date code rounding to 15 decimal digits (h/t @davidtamaki)
|
||||
* `sheet_to_json` force UTC interpretation for formatted strings (h/t @Blanay)
|
||||
* QPW extract result of string formula
|
||||
* XLSX parse non-compliant merge cell expressions
|
||||
* NUMBERS correctly handle rows omitted from official exports
|
||||
* DBF parse empty logical field (h/t @Roman91)
|
||||
* `dense` option added to types
|
||||
* package.json add mini and core scripts to export map (h/t @stof)
|
||||
|
||||
## v0.20.0
|
||||
|
||||
* Use UTC interpretation of Date objects for date cells (potentially breaking)
|
||||
|
7
Makefile
7
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
|
||||
|
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!
|
||||
|
||||
[](https://git.sheetjs.com/SheetJS/sheetjs)
|
||||
|
||||
[](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 +1 @@
|
||||
XLSX.version = '0.20.0';
|
||||
XLSX.version = '0.20.1';
|
||||
|
@ -29,7 +29,7 @@ function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Ar
|
||||
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
|
||||
if(typeof v == "number") break;
|
||||
/* falls through */
|
||||
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
|
||||
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) {
|
||||
|
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
162
dist/xlsx.extendscript.js
generated
vendored
162
dist/xlsx.extendscript.js
generated
vendored
@ -160,7 +160,7 @@ var DO_NOT_EXPORT_CODEPAGE = true;
|
||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false, Float32Array:false */
|
||||
var XLSX = {};
|
||||
function make_xlsx_lib(XLSX){
|
||||
XLSX.version = '0.20.0';
|
||||
XLSX.version = '0.20.1';
|
||||
var current_codepage = 1200, current_ansi = 1252;
|
||||
/*global cptable:true, window */
|
||||
var $cptable;
|
||||
@ -620,8 +620,20 @@ function SSF_frac(x, D, mixed) {
|
||||
var q = Math.floor(sgn * P/Q);
|
||||
return [q, sgn*P - q*Q, Q];
|
||||
}
|
||||
function SSF_normalize_xl_unsafe(v) {
|
||||
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,opts,b2) {
|
||||
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};
|
||||
@ -774,7 +786,7 @@ if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
|
||||
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 */
|
||||
@ -1220,10 +1232,11 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
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;
|
||||
@ -1233,17 +1246,29 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
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.u >= 0.5) { dt.u = 0; ++dt.S; }
|
||||
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.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;
|
||||
}
|
||||
|
||||
@ -4503,6 +4528,13 @@ function sheet_to_workbook(sheet, opts) {
|
||||
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, data, opts) {
|
||||
var o = opts || {};
|
||||
var dense = _ws ? (_ws["!data"] != null) : o.dense;
|
||||
@ -8059,7 +8091,7 @@ var fields = [], field = ({});
|
||||
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 */
|
||||
@ -8121,6 +8153,7 @@ function dbf_to_workbook(buf, opts) {
|
||||
|
||||
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
|
||||
function sheet_to_dbf(ws, opts) {
|
||||
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);
|
||||
@ -8278,7 +8311,10 @@ var SYLK = (function() {
|
||||
"!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
|
||||
"+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
|
||||
});
|
||||
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;
|
||||
@ -8501,7 +8537,7 @@ var SYLK = (function() {
|
||||
if(!opts) opts = {}; opts._formats = ["General"];
|
||||
/* TODO: codepage */
|
||||
var preamble = ["ID;PSheetJS;N;E"], o = [];
|
||||
var r = safe_decode_range(ws['!ref']), cell;
|
||||
var r = safe_decode_range(ws['!ref']||"A1"), cell;
|
||||
var dense = ws["!data"] != null;
|
||||
var RS = "\r\n";
|
||||
var d1904 = (((wb||{}).Workbook||{}).WBProps||{}).date1904;
|
||||
@ -8510,7 +8546,7 @@ var SYLK = (function() {
|
||||
preamble.push("P;PGeneral");
|
||||
/* Excel has been inconsistent in comment placement */
|
||||
var R = r.s.r, C = r.s.c, p = [];
|
||||
for(R = r.s.r; R <= r.e.r; ++R) {
|
||||
if(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) {
|
||||
@ -8520,7 +8556,7 @@ var SYLK = (function() {
|
||||
}
|
||||
if(p.length) o.push(p.join(RS));
|
||||
}
|
||||
for(R = r.s.r; R <= r.e.r; ++R) {
|
||||
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) {
|
||||
@ -8540,7 +8576,7 @@ var SYLK = (function() {
|
||||
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");
|
||||
|
||||
delete opts._formats;
|
||||
@ -8613,6 +8649,7 @@ var DIF = (function() {
|
||||
function make_value_str(s) { return "1,0\r\n\"" + s.replace(/"/g,'""') + '"'; }
|
||||
function sheet_to_dif(ws) {
|
||||
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 = [
|
||||
@ -8950,6 +8987,7 @@ var PRN = (function() {
|
||||
|
||||
function sheet_to_prn(ws) {
|
||||
var o = [];
|
||||
if(!ws["!ref"]) return "";
|
||||
var r = safe_decode_range(ws['!ref']), cell;
|
||||
var dense = ws["!data"] != null;
|
||||
for(var R = r.s.r; R <= r.e.r; ++R) {
|
||||
@ -9174,6 +9212,7 @@ var WK_ = (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 = [];
|
||||
@ -9967,13 +10006,25 @@ var WK_ = (function() {
|
||||
0x0E: "dd-mmm-yyyy",
|
||||
0x0F: "mmm-yyyy",
|
||||
|
||||
0x22: "0.00",
|
||||
0x32: "0.00;[Red]0.00",
|
||||
0x42: "0.00;\(0.00\)",
|
||||
0x52: "0.00;[Red]\(0.00\)",
|
||||
|
||||
162: '"$"#,##0;\\("$"#,##0\\)' // slightly different from SSF 5
|
||||
/* 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) {
|
||||
prep_blob(d, 0);
|
||||
@ -10084,7 +10135,11 @@ var WK_ = (function() {
|
||||
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;
|
||||
@ -10130,6 +10185,17 @@ var WK_ = (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;
|
||||
@ -11281,7 +11347,7 @@ function parse_cellXfs(t, styles, opts) {
|
||||
case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
|
||||
|
||||
/* 18.8.45 xf CT_Xf */
|
||||
case '<xf': case '<xf/>':
|
||||
case '<xf': case '<xf/>': case '<xf>':
|
||||
xf = y;
|
||||
delete xf[0];
|
||||
for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
|
||||
@ -11295,7 +11361,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;
|
||||
@ -11307,12 +11373,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 ? */
|
||||
@ -12951,7 +13017,10 @@ var rc_to_a1 = (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 = (function(){
|
||||
return function a1_to_rc(fstr, base) {
|
||||
return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
|
||||
@ -15664,7 +15733,7 @@ function parse_ws_xml_dim(ws, s) {
|
||||
var d = safe_decode_range(s);
|
||||
if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
|
||||
}
|
||||
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
|
||||
var mergecregex = /<(?:\w:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
|
||||
var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
|
||||
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
|
||||
var dimregex = /"(\w*:\w*)"/;
|
||||
@ -22507,9 +22576,9 @@ function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
|
||||
var header = o.header != null ? o.header : HTML_BEGIN;
|
||||
var footer = o.footer != null ? o.footer : HTML_END;
|
||||
var out = [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("");
|
||||
}
|
||||
@ -23268,10 +23337,13 @@ function parse_content_xml(d, _opts, _nfm) {
|
||||
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:
|
||||
@ -23788,6 +23860,7 @@ var write_content_ods = /* @__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})];
|
||||
@ -25039,7 +25112,7 @@ function s5s_to_iwa_comment(s5s) {
|
||||
return out;
|
||||
}
|
||||
function parse_TST_TableModelArchive(M, root, ws, opts) {
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _i;
|
||||
var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j;
|
||||
var pb = parse_shallow(root.data);
|
||||
var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } };
|
||||
range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1;
|
||||
@ -25068,7 +25141,17 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
|
||||
lut.nfmt = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[22][0].data)][0]);
|
||||
var tile = parse_shallow(store[3][0].data);
|
||||
var _R = 0;
|
||||
tile[1].forEach(function(t) {
|
||||
if (!((_h = store[9]) == null ? void 0 : _h[0]))
|
||||
throw "NUMBERS file missing row tree";
|
||||
var rtt = parse_shallow(store[9][0].data)[1].map(function(p) {
|
||||
return parse_shallow(p.data);
|
||||
});
|
||||
rtt.forEach(function(kv) {
|
||||
_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 ref2 = M[parse_TSP_Reference(tl[2][0].data)][0];
|
||||
var mtype2 = varint_to_i32(ref2.meta[1][0].data);
|
||||
@ -25091,12 +25174,12 @@ function parse_TST_TableModelArchive(M, root, ws, opts) {
|
||||
});
|
||||
_R += _tile.nrows;
|
||||
});
|
||||
if ((_h = store[13]) == null ? void 0 : _h[0]) {
|
||||
if ((_i = store[13]) == null ? void 0 : _i[0]) {
|
||||
var ref = M[parse_TSP_Reference(store[13][0].data)][0];
|
||||
var mtype = varint_to_i32(ref.meta[1][0].data);
|
||||
if (mtype != 6144)
|
||||
throw new Error("Expected merge type 6144, found ".concat(mtype));
|
||||
ws["!merges"] = (_i = parse_shallow(ref.data)) == null ? void 0 : _i[1].map(function(pi) {
|
||||
ws["!merges"] = (_j = parse_shallow(ref.data)) == null ? void 0 : _j[1].map(function(pi) {
|
||||
var merge = parse_shallow(pi.data);
|
||||
var origin = u8_to_dataview(parse_shallow(merge[1][0].data)[1][0].data), size = u8_to_dataview(parse_shallow(merge[2][0].data)[1][0].data);
|
||||
return {
|
||||
@ -25758,6 +25841,8 @@ function write_numbers_ws(cfb, deps, ws, wsname, sheetidx, rootref) {
|
||||
}
|
||||
var USE_WIDE_ROWS = true;
|
||||
function write_numbers_tma(cfb, deps, ws, tmaroot, tmafile, tmaref) {
|
||||
if (!ws["!ref"])
|
||||
throw new Error("Cannot export empty sheet to NUMBERS");
|
||||
var range = decode_range(ws["!ref"]);
|
||||
range.s.r = range.s.c = 0;
|
||||
var trunc = false;
|
||||
@ -27192,7 +27277,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
|
||||
v = numdate(v); // TODO: date1904 setting should also be stored in worksheet object
|
||||
if(typeof v == "number") break;
|
||||
/* falls through */
|
||||
case 'd': if(!(o && o.UTC)) v = utc_to_local(v); break;
|
||||
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) {
|
||||
@ -27202,7 +27287,7 @@ function make_json_row(sheet, r, R, cols, header, hdr, o) {
|
||||
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;
|
||||
}
|
||||
@ -27460,9 +27545,11 @@ function wb_sheet_idx(wb, sh) {
|
||||
} else throw new Error("Cannot find sheet |" + sh + "|");
|
||||
}
|
||||
|
||||
/* simple blank workbook object */
|
||||
function book_new() {
|
||||
return { SheetNames: [], Sheets: {} };
|
||||
/* simple blank or single-sheet workbook object */
|
||||
function book_new(ws, wsname) {
|
||||
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 */
|
||||
@ -27559,6 +27646,7 @@ var utils = {
|
||||
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,
|
||||
|
34
dist/xlsx.full.min.js
generated
vendored
34
dist/xlsx.full.min.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.full.min.map
generated
vendored
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
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.20.0+csv",
|
||||
"version": "0.20.1",
|
||||
"author": "sheetjs",
|
||||
"description": "SheetJS Spreadsheet data parser and writer",
|
||||
"keywords": [
|
||||
@ -167,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"
|
||||
},
|
||||
|
1
packages/dta/.gitignore
vendored
Normal file
1
packages/dta/.gitignore
vendored
Normal file
@ -0,0 +1 @@
|
||||
misc/
|
@ -1,5 +1,15 @@
|
||||
.PHONY: build
|
||||
build: node browser
|
||||
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
|
||||
|
||||
|
@ -6,4 +6,58 @@ 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.
|
||||
<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.1/dta-0.0.1.tgz
|
||||
```
|
||||
|
||||
The standalone script is also hosted on the SheetJS CDN:
|
||||
|
||||
```html
|
||||
<script src="https://cdn.sheetjs.com/dta-0.0.1/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>
|
||||
```
|
@ -15,5 +15,5 @@ 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 = " ";}}));
|
||||
//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]]));
|
372
packages/dta/dist/dta.js
vendored
372
packages/dta/dist/dta.js
vendored
@ -25,41 +25,95 @@ var __toCommonJS = /* @__PURE__ */ ((cache) => {
|
||||
var dta_exports = {};
|
||||
__export(dta_exports, {
|
||||
parse: () => parse,
|
||||
set_utils: () => set_utils
|
||||
set_utils: () => set_utils,
|
||||
version: () => version
|
||||
});
|
||||
var version = "0.0.1";
|
||||
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 (p.str.slice(p.ptr, p.ptr + n.length) != n)
|
||||
if (u8_to_str(p.raw.slice(p.ptr, p.ptr + n.length)) != n)
|
||||
return false;
|
||||
p.ptr += n.length;
|
||||
return true;
|
||||
}
|
||||
function skip_end(p, n) {
|
||||
const idx = p.str.indexOf(n, p.ptr);
|
||||
if (idx == -1)
|
||||
throw new Error(`Expected ${n} after offset ${p.ptr}`);
|
||||
p.ptr = idx + n.length;
|
||||
}
|
||||
function slice_end(p, n) {
|
||||
const idx = p.str.indexOf(n, p.ptr);
|
||||
if (idx == -1)
|
||||
throw new Error(`Expected ${n} after offset ${p.ptr}`);
|
||||
const raw = p.raw.slice(p.ptr, idx);
|
||||
const res = {
|
||||
ptr: 0,
|
||||
raw,
|
||||
str: p.str.slice(p.ptr, idx),
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
p.ptr = idx + n.length;
|
||||
return res;
|
||||
}
|
||||
function read_f64(p, LE) {
|
||||
p.ptr += 8;
|
||||
const d = p.dv.getFloat64(p.ptr - 8, LE);
|
||||
@ -98,15 +152,29 @@ function read_i8(p) {
|
||||
}
|
||||
var SUPPORTED_VERSIONS_TAGGED = [
|
||||
"117",
|
||||
"118"
|
||||
"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 str = new TextDecoder("latin1").decode(raw);
|
||||
const d = {
|
||||
ptr: 0,
|
||||
raw,
|
||||
str,
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
let vers = 118;
|
||||
@ -124,16 +192,22 @@ function parse_tagged(raw) {
|
||||
{
|
||||
if (!valid_inc(d, "<release>"))
|
||||
throw err;
|
||||
const res = slice_end(d, "</release>");
|
||||
if (SUPPORTED_VERSIONS_TAGGED.indexOf(res.str) == -1)
|
||||
throw `Unsupported DTA ${res.str} file`;
|
||||
vers = +res.str;
|
||||
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 = slice_end(d, "</byteorder>");
|
||||
switch (res.str) {
|
||||
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;
|
||||
@ -141,48 +215,49 @@ function parse_tagged(raw) {
|
||||
LE = true;
|
||||
break;
|
||||
default:
|
||||
throw `Unsupported byteorder ${res.str}`;
|
||||
throw `Unsupported byteorder ${res}`;
|
||||
}
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<K>"))
|
||||
throw err;
|
||||
const res = slice_end(d, "</K>");
|
||||
nvar = read_u16(res, LE);
|
||||
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;
|
||||
const res = slice_end(d, "</N>");
|
||||
if (vers == 117)
|
||||
nobs = nobs_lo = read_u32(res, LE);
|
||||
nobs = nobs_lo = read_u32(d, LE);
|
||||
else {
|
||||
const lo = read_u32(res, LE), hi = read_u32(res, LE);
|
||||
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 res = slice_end(d, "</label>");
|
||||
const w = vers >= 118 ? 2 : 1;
|
||||
const strlen = w == 1 ? read_u8(res) : read_u16(res, LE);
|
||||
if (strlen + w != res.str.length)
|
||||
throw `Expected string length ${strlen} but actual length was ${res.str.length - w}`;
|
||||
const strlen = w == 1 ? read_u8(d) : read_u16(d, LE);
|
||||
if (strlen > 0)
|
||||
label = new TextDecoder().decode(res.raw.slice(w));
|
||||
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 res = slice_end(d, "</timestamp>");
|
||||
const strlen = read_u8(res);
|
||||
if (strlen + 1 != res.str.length)
|
||||
throw `Expected string length ${strlen} but actual length was ${res.str.length - 1}`;
|
||||
if (strlen > 0)
|
||||
timestamp = res.str.slice(1);
|
||||
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;
|
||||
@ -190,17 +265,16 @@ function parse_tagged(raw) {
|
||||
{
|
||||
if (!valid_inc(d, "<map>"))
|
||||
throw err;
|
||||
skip_end(d, "</map>");
|
||||
d.ptr += 8 * 14;
|
||||
if (!valid_inc(d, "</map>"))
|
||||
throw err;
|
||||
}
|
||||
let stride = 0;
|
||||
{
|
||||
if (!valid_inc(d, "<variable_types>"))
|
||||
throw err;
|
||||
const res = slice_end(d, "</variable_types>");
|
||||
if (res.raw.length != 2 * nvar)
|
||||
throw `Expected variable_types length ${nvar * 2}, found ${res.raw.length}`;
|
||||
while (res.ptr < res.raw.length) {
|
||||
const type = read_u16(res, LE);
|
||||
for (var i = 0; i < nvar; ++i) {
|
||||
const type = read_u16(d, LE);
|
||||
var_types.push(type);
|
||||
if (type >= 1 && type <= 2045)
|
||||
stride += type;
|
||||
@ -209,6 +283,9 @@ function parse_tagged(raw) {
|
||||
case 32768:
|
||||
stride += 8;
|
||||
break;
|
||||
case 65525:
|
||||
stride += 0;
|
||||
break;
|
||||
case 65526:
|
||||
stride += 8;
|
||||
break;
|
||||
@ -228,57 +305,62 @@ function parse_tagged(raw) {
|
||||
throw `Unsupported field type ${type}`;
|
||||
}
|
||||
}
|
||||
if (!valid_inc(d, "</variable_types>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<varnames>"))
|
||||
throw err;
|
||||
const res = slice_end(d, "</varnames>");
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
if (res.raw.length != w * nvar)
|
||||
throw `Expected variable_types length ${nvar * w}, found ${res.raw.length}`;
|
||||
while (res.ptr < res.raw.length) {
|
||||
const name = new TextDecoder().decode(res.raw.slice(res.ptr, res.ptr + w));
|
||||
res.ptr += w;
|
||||
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;
|
||||
const res = slice_end(d, "</sortlist>");
|
||||
if (res.raw.length != 2 * nvar + 2)
|
||||
throw `Expected sortlist length ${nvar * 2 + 2}, found ${res.raw.length}`;
|
||||
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 res = slice_end(d, "</formats>");
|
||||
const w = vers >= 118 ? 57 : 49;
|
||||
if (res.raw.length != w * nvar)
|
||||
throw `Expected formats length ${nvar * w}, found ${res.raw.length}`;
|
||||
while (res.ptr < res.raw.length) {
|
||||
const name = new TextDecoder().decode(res.raw.slice(res.ptr, res.ptr + w));
|
||||
res.ptr += w;
|
||||
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;
|
||||
const res = slice_end(d, "</value_label_names>");
|
||||
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;
|
||||
const res = slice_end(d, "</variable_labels>");
|
||||
d.ptr += w * nvar;
|
||||
if (!valid_inc(d, "</variable_labels>"))
|
||||
throw err;
|
||||
}
|
||||
{
|
||||
if (!valid_inc(d, "<characteristics>"))
|
||||
throw err;
|
||||
while (d.str.slice(d.ptr, d.ptr + 4) == "<ch>") {
|
||||
d.ptr += 4;
|
||||
while (valid_inc(d, "<ch>")) {
|
||||
const len = read_u32(d, LE);
|
||||
d.ptr += len;
|
||||
if (!valid_inc(d, "</ch>"))
|
||||
@ -297,26 +379,29 @@ function parse_tagged(raw) {
|
||||
for (let C = 0; C < nvar; ++C) {
|
||||
let t = var_types[C];
|
||||
if (t >= 1 && t <= 2045) {
|
||||
let s = new TextDecoder().decode(d.raw.slice(d.ptr, d.ptr + t));
|
||||
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 65526:
|
||||
row[C] = read_f64(d, LE);
|
||||
case 65525:
|
||||
d.ptr += 0;
|
||||
break;
|
||||
case 65527:
|
||||
row[C] = read_f32(d, LE);
|
||||
break;
|
||||
case 65528:
|
||||
row[C] = read_i32(d, LE);
|
||||
case 65530:
|
||||
row[C] = read_i8(d);
|
||||
break;
|
||||
case 65529:
|
||||
row[C] = read_i16(d, LE);
|
||||
break;
|
||||
case 65530:
|
||||
row[C] = read_i8(d);
|
||||
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:
|
||||
{
|
||||
@ -328,6 +413,8 @@ function parse_tagged(raw) {
|
||||
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 });
|
||||
}
|
||||
@ -355,15 +442,15 @@ function parse_tagged(raw) {
|
||||
const len = read_u32(d, LE);
|
||||
if (!strl_tbl[o])
|
||||
strl_tbl[o] = [];
|
||||
let str2 = "";
|
||||
let str = "";
|
||||
if (t == 129) {
|
||||
str2 = new TextDecoder("latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
|
||||
str = new TextDecoder(vers >= 118 ? "utf8" : "latin1").decode(d.raw.slice(d.ptr, d.ptr + len));
|
||||
d.ptr += len;
|
||||
} else {
|
||||
str2 = new TextDecoder("latin1").decode(d.raw.slice(d.ptr, d.ptr + len)).replace(/\x00$/, "");
|
||||
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] = str2;
|
||||
strl_tbl[o][v] = str;
|
||||
}
|
||||
if (!valid_inc(d, "</strls>"))
|
||||
throw err;
|
||||
@ -397,9 +484,41 @@ function parse_tagged(raw) {
|
||||
});
|
||||
}
|
||||
{
|
||||
const w = vers >= 118 ? 129 : 33;
|
||||
if (!valid_inc(d, "<value_labels>"))
|
||||
throw err;
|
||||
const res = slice_end(d, "</value_labels>");
|
||||
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;
|
||||
@ -409,27 +528,11 @@ function parse_tagged(raw) {
|
||||
}
|
||||
function parse_legacy(raw) {
|
||||
let vers = raw[0];
|
||||
switch (vers) {
|
||||
case 102:
|
||||
case 112:
|
||||
throw `Unsupported DTA ${vers} file`;
|
||||
case 103:
|
||||
case 104:
|
||||
case 105:
|
||||
case 108:
|
||||
case 110:
|
||||
case 111:
|
||||
case 113:
|
||||
case 114:
|
||||
case 115:
|
||||
break;
|
||||
default:
|
||||
throw new Error("Not a DTA file");
|
||||
}
|
||||
if (SUPPORTED_VERSIONS_LEGACY.indexOf(vers) == -1)
|
||||
throw new Error("Not a DTA file");
|
||||
const d = {
|
||||
ptr: 1,
|
||||
raw,
|
||||
str: "",
|
||||
dv: u8_to_dataview(raw)
|
||||
};
|
||||
let LE = true;
|
||||
@ -456,31 +559,34 @@ function parse_legacy(raw) {
|
||||
d.ptr++;
|
||||
nvar = read_u16(d, LE);
|
||||
nobs = read_u32(d, LE);
|
||||
d.ptr += vers >= |