version bump 0.17.4: Lotus WK3 workbook writer
This commit is contained in:
parent
9e9e4bcb45
commit
fcf9182fa6
@ -49,6 +49,7 @@ SQLite
|
||||
SystemJS
|
||||
VueJS
|
||||
WebSQL
|
||||
WK_
|
||||
iOS
|
||||
nodejs
|
||||
node.js
|
||||
|
@ -4,6 +4,10 @@ This log is intended to keep track of backwards-incompatible changes, including
|
||||
but not limited to API changes and file location changes. Minor behavioral
|
||||
changes may not be included if they are not expected to break existing code.
|
||||
|
||||
## v0.17.4
|
||||
|
||||
* CLI script moved to `xlsx-cli` package
|
||||
|
||||
## v0.17.3
|
||||
|
||||
* `window.XLSX` explicit assignment to satiate LWC
|
||||
|
15
README.md
15
README.md
@ -1381,11 +1381,12 @@ prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
| RC-style strings | XLML and plain text | โ | โ |
|
||||
| BIFF Parsed formulae | XLSB and all XLS formats | โ | |
|
||||
| OpenFormula formulae | ODS/FODS/UOS | โ | โ |
|
||||
| Lotus Parsed formulae | All Lotus WK_ formats | โ | |
|
||||
|
||||
Since Excel prohibits named cells from colliding with names of A1 or RC style
|
||||
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
|
||||
formulae have to be explicitly unwound. OpenFormula formulae can be converted
|
||||
with regular expressions.
|
||||
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
|
||||
formulae can be converted with regular expressions.
|
||||
</details>
|
||||
|
||||
#### Column Properties
|
||||
@ -1776,6 +1777,7 @@ The exported `read` and `readFile` functions accept an options argument:
|
||||
|`sheets` | | If specified, only parse specified sheets ** |
|
||||
|`PRN` | false | If true, allow parsing of PRN files ** |
|
||||
|`xlfn` | false | If true, preserve `_xlfn.` prefixes in formulae ** |
|
||||
|`FS` | | DSV Field Separator override |
|
||||
|
||||
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
|
||||
- In some cases, sheets may be parsed even if `bookSheets` is false.
|
||||
@ -1939,12 +1941,14 @@ output formats. The specific file type is controlled with `bookType` option:
|
||||
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
|
||||
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
|
||||
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
|
||||
| `wk3` | `.wk3` | none | single | Lotus Workbook (WK3) |
|
||||
| `csv` | `.csv` | none | single | Comma Separated Values |
|
||||
| `txt` | `.txt` | none | single | UTF-16 Unicode Text (TXT) |
|
||||
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
|
||||
| `html` | `.html` | none | single | HTML Document |
|
||||
| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
|
||||
| `dbf` | `.dbf` | none | single | dBASE II + VFP Extensions (DBF) |
|
||||
| `wk1` | `.wk1` | none | single | Lotus Worksheet (WK1) |
|
||||
| `rtf` | `.rtf` | none | single | Rich Text Format (RTF) |
|
||||
| `prn` | `.prn` | none | single | Lotus Formatted Text |
|
||||
| `eth` | `.eth` | none | single | Ethercalc Record Format (ETH) |
|
||||
@ -2481,7 +2485,8 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
|
||||
| Flat XML ODF Spreadsheet (FODS) | โ | โ |
|
||||
| Uniform Office Format Spreadsheet (ๆ ๆ้ UOS1/UOS2) | โ | |
|
||||
| dBASE II/III/IV / Visual FoxPro (DBF) | โ | โ |
|
||||
| Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123) | โ | |
|
||||
| Lotus 1-2-3 (WK1/WK3) | โ | โ |
|
||||
| Lotus 1-2-3 (WKS/WK2/WK4/123) | โ | |
|
||||
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | โ | |
|
||||
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
|
||||
| HTML Tables | โ | โ |
|
||||
@ -2619,6 +2624,10 @@ The Lotus formats consist of binary records similar to the BIFF structure. Lotus
|
||||
did release a specification decades ago covering the original WK1 format. Other
|
||||
features were deduced by producing files and comparing to Excel support.
|
||||
|
||||
Generated WK1 worksheets are compatible with Lotus 1-2-3 R2 and Excel 5.0.
|
||||
|
||||
Generated WK3 workbooks are compatible with Lotus 1-2-3 R9 and Excel 5.0.
|
||||
|
||||
</details>
|
||||
|
||||
#### Quattro Pro (WQ1/WQ2/WB1/WB2/WB3/QPW)
|
||||
|
@ -43,6 +43,7 @@ program
|
||||
.option('-i, --xla', 'emit XLA to <sheetname> or <file>.xla')
|
||||
.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)')
|
||||
.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)')
|
||||
.option('--wk3', 'emit WK3 to <sheetname> or <file>.txt (Lotus WK3)')
|
||||
|
||||
.option('-S, --formulae', 'emit list of values and formulae')
|
||||
.option('-j, --json', 'emit formatted JSON (all fields text)')
|
||||
@ -90,7 +91,8 @@ var workbook_formats = [
|
||||
['xla', 'xla', 'xla'],
|
||||
['biff5', 'biff5', 'xls'],
|
||||
['ods', 'ods', 'ods'],
|
||||
['fods', 'fods', 'fods']
|
||||
['fods', 'fods', 'fods'],
|
||||
['wk3', 'wk3', 'wk3']
|
||||
];
|
||||
var wb_formats_2 = [
|
||||
['xlml', 'xlml', 'xls']
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.17.3';
|
||||
XLSX.version = '0.17.4';
|
||||
|
@ -66,7 +66,11 @@ var DocSummaryPIDDSI = {
|
||||
/*::[*/0x1B/*::]*/: { n: 'ContentStatus', t: VT_STRING },
|
||||
/*::[*/0x1C/*::]*/: { n: 'Language', t: VT_STRING },
|
||||
/*::[*/0x1D/*::]*/: { n: 'Version', t: VT_STRING },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
/*::[*/0xFF/*::]*/: {},
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
/*::[*/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 */
|
||||
@ -90,21 +94,13 @@ var SummaryPIDSI = {
|
||||
/*::[*/0x11/*::]*/: { n: 'Thumbnail', t: VT_CF },
|
||||
/*::[*/0x12/*::]*/: { n: 'Application', t: VT_STRING },
|
||||
/*::[*/0x13/*::]*/: { n: 'DocSecurity', t: VT_I4 },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
};
|
||||
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
var SpecialProperties = {
|
||||
/*::[*/0xFF/*::]*/: {},
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
/*::[*/0x80000000/*::]*/: { n: 'Locale', t: VT_UI4 },
|
||||
/*::[*/0x80000003/*::]*/: { n: 'Behavior', t: VT_UI4 },
|
||||
/*::[*/0x72627262/*::]*/: {}
|
||||
};
|
||||
|
||||
(function() {
|
||||
for(var y in SpecialProperties) if(Object.prototype.hasOwnProperty.call(SpecialProperties, y))
|
||||
DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
|
||||
})();
|
||||
|
||||
var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n");
|
||||
var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n");
|
||||
|
||||
|
266
bits/41_lotus.js
266
bits/41_lotus.js
@ -29,7 +29,7 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
var o = opts || {};
|
||||
if(DENSE != null && o.dense == null) o.dense = DENSE;
|
||||
var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/), n = "Sheet1", sidx = 0;
|
||||
var sheets = {}, snames = [n];
|
||||
var sheets = {}, snames = [n], realnames = [];
|
||||
|
||||
var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
|
||||
var sheetRows = o.sheetRows || 0;
|
||||
@ -37,28 +37,36 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
if(d[2] == 0x02) {
|
||||
o.Enum = WK1Enum;
|
||||
lotushopper(d, function(val, R, RT) { switch(RT) {
|
||||
case 0x00:
|
||||
case 0x00: /* BOF */
|
||||
o.vers = val;
|
||||
if(val >= 0x1000) o.qpro = true;
|
||||
break;
|
||||
case 0x06: refguess = val; break; /* RANGE */
|
||||
case 0x0F: /* LABEL */
|
||||
case 0x33: /* STRING */
|
||||
if(!o.qpro) val[1].v = val[1].v.slice(1);
|
||||
/* falls through */
|
||||
case 0x0D: /* INTEGER */
|
||||
case 0x0E: /* NUMBER */
|
||||
case 0x10: /* FORMULA */
|
||||
case 0x33: /* STRING */
|
||||
/* 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 || SSF._table[14];
|
||||
if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
|
||||
}
|
||||
var tmpcell = o.dense ? (s[val[0].r]||[])[val[0].c] : s[encode_cell(val[0])];
|
||||
if(tmpcell) {
|
||||
tmpcell.t = val[1].t; tmpcell.v = val[1].v;
|
||||
if(val[1].z != null) tmpcell.z = val[1].z;
|
||||
if(val[1].f != null) tmpcell.f = val[1].f;
|
||||
break;
|
||||
}
|
||||
if(o.dense) {
|
||||
if(!s[val[0].r]) s[val[0].r] = [];
|
||||
s[val[0].r][val[0].c] = val[1];
|
||||
} else s[encode_cell(val[0])] = val[1];
|
||||
break;
|
||||
default:
|
||||
}}, o);
|
||||
} else if(d[2] == 0x1A || d[2] == 0x0E) {
|
||||
o.Enum = WK3Enum;
|
||||
@ -89,19 +97,28 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
|
||||
if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
|
||||
break;
|
||||
case 0x1B: /* XFORMAT */
|
||||
if(val[0x36b0]) realnames[val[0x36b0][0]] = val[0x36b0][1];
|
||||
break;
|
||||
default: break;
|
||||
}}, o);
|
||||
} else throw new Error("Unrecognized LOTUS BOF " + d[2]);
|
||||
|
||||
s["!ref"] = encode_range(refguess);
|
||||
sheets[n] = s;
|
||||
return { SheetNames: snames, Sheets:sheets };
|
||||
if(!realnames.length) return { SheetNames: snames, Sheets: sheets };
|
||||
var osheets = {}, rnames = [];
|
||||
for(var i = 0; i < realnames.length; ++i) if(sheets[snames[i]]) {
|
||||
rnames.push(realnames[i]);
|
||||
osheets[realnames[i]] = sheets[snames[i]];
|
||||
}
|
||||
return { SheetNames: rnames, Sheets: osheets };
|
||||
}
|
||||
|
||||
function sheet_to_wk1(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
|
||||
var o = opts || {};
|
||||
if(+o.codepage >= 0) set_cp(+o.codepage);
|
||||
if(o.type == "string") throw new Error("Cannot write DBF to JS string");
|
||||
if(o.type == "string") throw new Error("Cannot write WK1 to JS string");
|
||||
var ba = buf_array();
|
||||
var range = safe_decode_range(ws["!ref"]);
|
||||
var dense = Array.isArray(ws);
|
||||
@ -116,7 +133,7 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
var ref = cols[C] + rr;
|
||||
var cell = dense ? (ws[R]||[])[C] : ws[ref];
|
||||
if(!cell || cell.t == "z") continue;
|
||||
/* write cell */
|
||||
/* 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));
|
||||
@ -131,12 +148,81 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
return ba.end();
|
||||
}
|
||||
|
||||
function book_to_wk3(wb/*:Workbook*/, opts/*:WriteOpts*/) {
|
||||
var o = opts || {};
|
||||
if(+o.codepage >= 0) set_cp(+o.codepage);
|
||||
if(o.type == "string") throw new Error("Cannot write WK3 to JS string");
|
||||
var ba = buf_array();
|
||||
|
||||
write_biff_rec(ba, 0x00, write_BOF_WK3(wb));
|
||||
|
||||
for(var i = 0, cnt = 0; i < wb.SheetNames.length; ++i) if((wb.Sheets[wb.SheetNames[i]] || {})["!ref"]) write_biff_rec(ba, 0x1b, write_XFORMAT_SHEETNAME(wb.SheetNames[i], cnt++));
|
||||
|
||||
var wsidx = 0;
|
||||
for(i = 0; i < wb.SheetNames.length; ++i) {
|
||||
var ws = wb.Sheets[wb.SheetNames[i]];
|
||||
if(!ws || !ws["!ref"]) continue;
|
||||
var range = safe_decode_range(ws["!ref"]);
|
||||
var dense = Array.isArray(ws);
|
||||
var cols = [];
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var rr = encode_row(R);
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
if(R === range.s.r) cols[C] = encode_col(C);
|
||||
var ref = cols[C] + rr;
|
||||
var cell = dense ? (ws[R]||[])[C] : ws[ref];
|
||||
if(!cell || cell.t == "z") continue;
|
||||
/* TODO: FORMULA19 NUMBER18 records */
|
||||
if(cell.t == "n") {
|
||||
write_biff_rec(ba, 0x17, write_NUMBER_17(R, C, wsidx, cell.v));
|
||||
} else {
|
||||
var str = format_cell(cell);
|
||||
/* TODO: max len? */
|
||||
write_biff_rec(ba, 0x16, write_LABEL_16(R, C, wsidx, str.slice(0, 239)));
|
||||
}
|
||||
}
|
||||
}
|
||||
++wsidx;
|
||||
}
|
||||
|
||||
write_biff_rec(ba, 0x01);
|
||||
return ba.end();
|
||||
}
|
||||
|
||||
|
||||
function write_BOF_WK1(v/*:number*/) {
|
||||
var out = new_buf(2);
|
||||
out.write_shift(2, v);
|
||||
return out;
|
||||
}
|
||||
|
||||
function write_BOF_WK3(wb/*:Workbook*/) {
|
||||
var out = new_buf(26);
|
||||
out.write_shift(2, 0x1000);
|
||||
out.write_shift(2, 0x0004);
|
||||
out.write_shift(4, 0x0000);
|
||||
var rows = 0, cols = 0, wscnt = 0;
|
||||
for(var i = 0; i < wb.SheetNames.length; ++i) {
|
||||
var name = wb.SheetNames[i];
|
||||
var ws = wb.Sheets[name];
|
||||
if(!ws || !ws["!ref"]) continue;
|
||||
++wscnt;
|
||||
var range = decode_range(ws["!ref"]);
|
||||
if(rows < range.e.r) rows = range.e.r;
|
||||
if(cols < range.e.c) cols = range.e.c;
|
||||
}
|
||||
out.write_shift(2, rows);
|
||||
out.write_shift(1, wscnt);
|
||||
out.write_shift(1, cols);
|
||||
out.write_shift(2, 0x00);
|
||||
out.write_shift(2, 0x00);
|
||||
out.write_shift(1, 0x01);
|
||||
out.write_shift(1, 0x02);
|
||||
out.write_shift(4, 0);
|
||||
out.write_shift(4, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
function parse_RANGE(blob) {
|
||||
var o = {s:{c:0,r:0},e:{c:0,r:0}};
|
||||
o.s.c = blob.read_shift(2);
|
||||
@ -234,11 +320,105 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
if(opts.qpro) blob.l = tgt;
|
||||
else {
|
||||
var flen = blob.read_shift(2);
|
||||
wk1_fmla_to_csf(blob.slice(blob.l, blob.l + flen), o);
|
||||
blob.l += flen;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
function wk1_parse_rc(B, V, col) {
|
||||
var rel = V & 0x8000;
|
||||
V &= ~0x8000;
|
||||
V = (rel ? B : 0) + ((V >= 0x2000) ? V - 0x4000 : V);
|
||||
return (rel ? "" : "$") + (col ? encode_col(V) : encode_row(V));
|
||||
}
|
||||
var oprec = [
|
||||
8, 8, 8, 8, 8, 8, 8, 8, 6, 4, 4, 5, 5, 7, 3, 3,
|
||||
3, 3, 3, 3, 1, 1, 2, 6, 8, 8, 8, 8, 8, 8, 8, 8
|
||||
];
|
||||
/* TODO: flesh out */
|
||||
var FuncTab = {
|
||||
0x33: ["FALSE", 0],
|
||||
0x34: ["TRUE", 0],
|
||||
0x46: ["LEN", 1],
|
||||
0x50: ["SUM", 69],
|
||||
0x51: ["AVERAGEA", 69],
|
||||
0x52: ["COUNTA", 69],
|
||||
0x53: ["MINA", 69],
|
||||
0x54: ["MAXA", 69],
|
||||
0x6F: ["T", 1]
|
||||
};
|
||||
var BinOpTab = [
|
||||
"", "", "", "", "", "", "", "",
|
||||
"", "+", "-", "*", "/", "^", "=", "<>",
|
||||
"<=", ">=", "<", ">", "", "", "", "",
|
||||
"&", "", "", "", "", "", "", ""
|
||||
];
|
||||
|
||||
function wk1_fmla_to_csf(blob, o) {
|
||||
prep_blob(blob, 0);
|
||||
var out = [], argc = 0, R = "", C = "";
|
||||
while(blob.l < blob.length) {
|
||||
var cc = blob[blob.l++];
|
||||
switch(cc) {
|
||||
case 0x00: out.push(blob.read_shift(8, 'f')); break;
|
||||
case 0x01: {
|
||||
C = wk1_parse_rc(o[0].c, blob.read_shift(2), true);
|
||||
R = wk1_parse_rc(o[0].r, blob.read_shift(2), false);
|
||||
out.push(C + R);
|
||||
} break;
|
||||
case 0x02: {
|
||||
var c = wk1_parse_rc(o[0].c, blob.read_shift(2), true);
|
||||
var r = wk1_parse_rc(o[0].r, blob.read_shift(2), false);
|
||||
C = wk1_parse_rc(o[0].c, blob.read_shift(2), true);
|
||||
R = wk1_parse_rc(o[0].r, blob.read_shift(2), false);
|
||||
out.push(c + r + ":" + C + R);
|
||||
} break;
|
||||
case 0x03:
|
||||
if(blob.l < blob.length) { console.error("WK1 premature formula end"); return; }
|
||||
break;
|
||||
case 0x04: out.push("(" + out.pop() + ")"); break;
|
||||
case 0x05: out.push(blob.read_shift(2)); break;
|
||||
case 0x06: {
|
||||
/* TODO: text encoding */
|
||||
var Z = ""; while((cc = blob[blob.l++])) Z += String.fromCharCode(cc);
|
||||
out.push('"' + Z.replace(/"/g, '""') + '"'); break;
|
||||
} break;
|
||||
|
||||
case 0x08: out.push("-" + out.pop()); break;
|
||||
case 0x17: out.push("+" + out.pop()); break;
|
||||
case 0x16: out.push("NOT(" + out.pop() + ")"); break;
|
||||
|
||||
case 0x14: case 0x15: {
|
||||
var argR = out.pop(), argL = out.pop();
|
||||
out.push(["AND", "OR"][cc - 0x14] + "(" + argL + "," + argR + ")");
|
||||
} break;
|
||||
|
||||
default:
|
||||
if(cc < 0x20 && BinOpTab[cc]) {
|
||||
argR = out.pop(); argL = out.pop();
|
||||
out.push(argL + BinOpTab[cc] + argR);
|
||||
} else if(FuncTab[cc]) {
|
||||
argc = FuncTab[cc][1];
|
||||
if(argc == 69) argc = blob[blob.l++];
|
||||
if(argc > out.length) { console.error("WK1 bad formula parse 0x" + cc.toString(16) + ":|" + out.join("|") + "|"); return; }
|
||||
var args = out.slice(-argc);
|
||||
out.length -= argc;
|
||||
out.push(FuncTab[cc][0] + "(" + args.join(",") + ")");
|
||||
}
|
||||
else if(cc <= 0x07) return console.error("WK1 invalid opcode " + cc.toString(16));
|
||||
else if(cc <= 0x18) return console.error("WK1 unsupported op " + cc.toString(16));
|
||||
else if(cc <= 0x1E) return console.error("WK1 invalid opcode " + cc.toString(16));
|
||||
else if(cc <= 0x73) return console.error("WK1 unsupported function opcode " + cc.toString(16));
|
||||
// possible future functions ??
|
||||
else return console.error("WK1 unrecognized opcode " + cc.toString(16));
|
||||
}
|
||||
}
|
||||
if(out.length == 1) o[1].f = "" + out[0];
|
||||
else console.error("WK1 bad formula parse |" + out.join("|") + "|");
|
||||
}
|
||||
|
||||
|
||||
function parse_cell_3(blob/*::, length*/) {
|
||||
var o = [{c:0,r:0}, {t:'n',v:0}, 0];
|
||||
o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
|
||||
@ -251,6 +431,20 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
o[1].v = blob.read_shift(length - 4, 'cstr');
|
||||
return o;
|
||||
}
|
||||
function write_LABEL_16(R, C, wsidx, s) {
|
||||
/* TODO: encoding */
|
||||
var o = new_buf(6 + s.length);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(1, wsidx);
|
||||
o.write_shift(1, C);
|
||||
o.write_shift(1, 0x27);
|
||||
for(var i = 0; i < s.length; ++i) {
|
||||
var cc = s.charCodeAt(i);
|
||||
o.write_shift(1, cc >= 0x80 ? 0x5F : cc);
|
||||
}
|
||||
o.write_shift(1, 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
function parse_NUMBER_18(blob, length) {
|
||||
var o = parse_cell_3(blob, length);
|
||||
@ -284,13 +478,41 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
return o;
|
||||
}
|
||||
var s = e & 0x8000; e = (e&0x7FFF) - 16446;
|
||||
o[1].v = (1 - s*2) * ( /*(e > 0 ? (v2 << e) : (v2 >>> -e))*/ v2 * Math.pow(2, e+32) + v1 * Math.pow(2, e));
|
||||
o[1].v = (1 - s*2) * (v2 * Math.pow(2, e+32) + v1 * Math.pow(2, e));
|
||||
return o;
|
||||
}
|
||||
function write_NUMBER_17(R, C, wsidx, v) {
|
||||
var o = new_buf(14);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(1, wsidx);
|
||||
o.write_shift(1, C);
|
||||
if(v == 0) {
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(4, 0);
|
||||
o.write_shift(2, 0xFFFF);
|
||||
return o;
|
||||
}
|
||||
var s = 0, e = 0, v1 = 0, v2 = 0;
|
||||
if(v < 0) { s = 1; v = -v; }
|
||||
e = Math.log2(v) | 0;
|
||||
v /= Math.pow(2, e-31);
|
||||
v2 = (v)>>>0;
|
||||
if((v2&0x80000000) == 0) { v/=2; ++e; v2 = v >>> 0; }
|
||||
v -= v2;
|
||||
v2 |= 0x80000000;
|
||||
v2 >>>= 0;
|
||||
v *= Math.pow(2, 32);
|
||||
v1 = v>>>0;
|
||||
o.write_shift(4, v1);
|
||||
o.write_shift(4, v2);
|
||||
e += 0x3FFF + (s ? 0x8000 : 0);
|
||||
o.write_shift(2, e);
|
||||
return o;
|
||||
}
|
||||
|
||||
function parse_FORMULA_19(blob, length) {
|
||||
var o = parse_NUMBER_17(blob, 14);
|
||||
blob.l += length - 14; /* TODO: formula */
|
||||
blob.l += length - 14; /* TODO: WK3 formula */
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -314,6 +536,31 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
return o;
|
||||
}
|
||||
|
||||
function parse_XFORMAT(blob, length) {
|
||||
var o = {}, tgt = blob.l + length;
|
||||
while(blob.l < tgt) {
|
||||
var dt = blob.read_shift(2);
|
||||
if(dt == 0x36b0) {
|
||||
o[dt] = [0, ""];
|
||||
o[dt][0] = blob.read_shift(2);
|
||||
while(blob[blob.l]) { o[dt][1] += String.fromCharCode(blob[blob.l]); blob.l++; } blob.l++;
|
||||
}
|
||||
// TODO: 0x3a99 ??
|
||||
}
|
||||
return o;
|
||||
}
|
||||
function write_XFORMAT_SHEETNAME(name, wsidx) {
|
||||
var out = new_buf(5 + name.length);
|
||||
out.write_shift(2, 0x36b0);
|
||||
out.write_shift(2, wsidx);
|
||||
for(var i = 0; i < name.length; ++i) {
|
||||
var cc = name.charCodeAt(i);
|
||||
out[out.l++] = cc > 0x7F ? 0x5F : cc;
|
||||
}
|
||||
out[out.l++] = 0;
|
||||
return out;
|
||||
}
|
||||
|
||||
var WK1Enum = {
|
||||
/*::[*/0x0000/*::]*/: { n:"BOF", f:parseuint16 },
|
||||
/*::[*/0x0001/*::]*/: { n:"EOF" },
|
||||
@ -407,7 +654,7 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
/*::[*/0x0018/*::]*/: { n:"NUMBER18", f:parse_NUMBER_18 },
|
||||
/*::[*/0x0019/*::]*/: { n:"FORMULA19", f:parse_FORMULA_19},
|
||||
/*::[*/0x001A/*::]*/: { n:"FORMULA1A" },
|
||||
/*::[*/0x001B/*::]*/: { n:"XFORMAT" },
|
||||
/*::[*/0x001B/*::]*/: { n:"XFORMAT", f:parse_XFORMAT },
|
||||
/*::[*/0x001C/*::]*/: { n:"DTLABELMISC" },
|
||||
/*::[*/0x001D/*::]*/: { n:"DTLABELCELL" },
|
||||
/*::[*/0x001E/*::]*/: { n:"GRAPHWINDOW" },
|
||||
@ -504,6 +751,7 @@ var WK_ = /*#__PURE__*/ (function() {
|
||||
};
|
||||
return {
|
||||
sheet_to_wk1: sheet_to_wk1,
|
||||
book_to_wk3: book_to_wk3,
|
||||
to_workbook: lotus_to_workbook
|
||||
};
|
||||
})();
|
||||
|
@ -106,6 +106,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
|
||||
case 'eth': return write_string_type(write_eth_str(wb, o), o);
|
||||
case 'fods': return write_string_type(write_ods(wb, o), o);
|
||||
case 'wk1': return write_binary_type(write_wk1_buf(wb, o), o);
|
||||
case 'wk3': return write_binary_type(WK_.book_to_wk3(wb, o), o);
|
||||
case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
|
||||
case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
|
||||
case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
|
||||
|
33
dist/xlsx.core.min.js
generated
vendored
33
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
640
dist/xlsx.extendscript.js
generated
vendored
640
dist/xlsx.extendscript.js
generated
vendored
File diff suppressed because it is too large
Load Diff
28
dist/xlsx.full.min.js
generated
vendored
28
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
640
dist/xlsx.js
generated
vendored
640
dist/xlsx.js
generated
vendored
File diff suppressed because it is too large
Load Diff
28
dist/xlsx.min.js
generated
vendored
28
dist/xlsx.min.js
generated
vendored
File diff suppressed because one or more lines are too long
2
dist/xlsx.min.map
generated
vendored
2
dist/xlsx.min.map
generated
vendored
File diff suppressed because one or more lines are too long
16
dist/xlsx.mini.min.js
generated
vendored
16
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
@ -86,10 +86,11 @@ prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
| RC-style strings | XLML and plain text | โ | โ |
|
||||
| BIFF Parsed formulae | XLSB and all XLS formats | โ | |
|
||||
| OpenFormula formulae | ODS/FODS/UOS | โ | โ |
|
||||
| Lotus Parsed formulae | All Lotus WK_ formats | โ | |
|
||||
|
||||
Since Excel prohibits named cells from colliding with names of A1 or RC style
|
||||
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
|
||||
formulae have to be explicitly unwound. OpenFormula formulae can be converted
|
||||
with regular expressions.
|
||||
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
|
||||
formulae can be converted with regular expressions.
|
||||
</details>
|
||||
|
||||
|
@ -47,6 +47,7 @@ output formats. The specific file type is controlled with `bookType` option:
|
||||
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
|
||||
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
|
||||
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
|
||||
| `wk3` | `.wk3` | none | single | Lotus Workbook (WK3) |
|
||||
| `csv` | `.csv` | none | single | Comma Separated Values |
|
||||
| `txt` | `.txt` | none | single | UTF-16 Unicode Text (TXT) |
|
||||
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
|
||||
|
@ -24,8 +24,8 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
|
||||
| Flat XML ODF Spreadsheet (FODS) | โ | โ |
|
||||
| Uniform Office Format Spreadsheet (ๆ ๆ้ UOS1/UOS2) | โ | |
|
||||
| dBASE II/III/IV / Visual FoxPro (DBF) | โ | โ |
|
||||
| Lotus 1-2-3 (WK1) | โ | โ |
|
||||
| Lotus 1-2-3 (WKS/WK2/WK3/WK4/123) | โ | |
|
||||
| Lotus 1-2-3 (WK1/WK3) | โ | โ |
|
||||
| Lotus 1-2-3 (WKS/WK2/WK4/123) | โ | |
|
||||
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | โ | |
|
||||
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
|
||||
| HTML Tables | โ | โ |
|
||||
@ -163,7 +163,9 @@ The Lotus formats consist of binary records similar to the BIFF structure. Lotus
|
||||
did release a specification decades ago covering the original WK1 format. Other
|
||||
features were deduced by producing files and comparing to Excel support.
|
||||
|
||||
Generated WK1 files are compatible with Lotus 1-2-3 v2 and Excel 5.0.
|
||||
Generated WK1 worksheets are compatible with Lotus 1-2-3 R2 and Excel 5.0.
|
||||
|
||||
Generated WK3 workbooks are compatible with Lotus 1-2-3 R9 and Excel 5.0.
|
||||
|
||||
</details>
|
||||
|
||||
|
BIN
formats.png
BIN
formats.png
Binary file not shown.
Before Width: | Height: | Size: 444 KiB After Width: | Height: | Size: 443 KiB |
@ -1266,11 +1266,12 @@ prefixed with an apostrophe `'`, consistent with Excel's formula bar display.
|
||||
| RC-style strings | XLML and plain text | โ | โ |
|
||||
| BIFF Parsed formulae | XLSB and all XLS formats | โ | |
|
||||
| OpenFormula formulae | ODS/FODS/UOS | โ | โ |
|
||||
| Lotus Parsed formulae | All Lotus WK_ formats | โ | |
|
||||
|
||||
Since Excel prohibits named cells from colliding with names of A1 or RC style
|
||||
cell references, a (not-so-simple) regex conversion is possible. BIFF Parsed
|
||||
formulae have to be explicitly unwound. OpenFormula formulae can be converted
|
||||
with regular expressions.
|
||||
formulae and Lotus Parsed formulae have to be explicitly unwound. OpenFormula
|
||||
formulae can be converted with regular expressions.
|
||||
|
||||
#### Column Properties
|
||||
|
||||
@ -1630,6 +1631,7 @@ The exported `read` and `readFile` functions accept an options argument:
|
||||
|`sheets` | | If specified, only parse specified sheets ** |
|
||||
|`PRN` | false | If true, allow parsing of PRN files ** |
|
||||
|`xlfn` | false | If true, preserve `_xlfn.` prefixes in formulae ** |
|
||||
|`FS` | | DSV Field Separator override |
|
||||
|
||||
- Even if `cellNF` is false, formatted text will be generated and saved to `.w`
|
||||
- In some cases, sheets may be parsed even if `bookSheets` is false.
|
||||
@ -1787,12 +1789,14 @@ output formats. The specific file type is controlled with `bookType` option:
|
||||
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
|
||||
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
|
||||
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
|
||||
| `wk3` | `.wk3` | none | single | Lotus Workbook (WK3) |
|
||||
| `csv` | `.csv` | none | single | Comma Separated Values |
|
||||
| `txt` | `.txt` | none | single | UTF-16 Unicode Text (TXT) |
|
||||
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
|
||||
| `html` | `.html` | none | single | HTML Document |
|
||||
| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
|
||||
| `dbf` | `.dbf` | none | single | dBASE II + VFP Extensions (DBF) |
|
||||
| `wk1` | `.wk1` | none | single | Lotus Worksheet (WK1) |
|
||||
| `rtf` | `.rtf` | none | single | Rich Text Format (RTF) |
|
||||
| `prn` | `.prn` | none | single | Lotus Formatted Text |
|
||||
| `eth` | `.eth` | none | single | Ethercalc Record Format (ETH) |
|
||||
@ -2299,7 +2303,8 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
|
||||
| Flat XML ODF Spreadsheet (FODS) | โ | โ |
|
||||
| Uniform Office Format Spreadsheet (ๆ ๆ้ UOS1/UOS2) | โ | |
|
||||
| dBASE II/III/IV / Visual FoxPro (DBF) | โ | โ |
|
||||
| Lotus 1-2-3 (WKS/WK1/WK2/WK3/WK4/123) | โ | |
|
||||
| Lotus 1-2-3 (WK1/WK3) | โ | โ |
|
||||
| Lotus 1-2-3 (WKS/WK2/WK4/123) | โ | |
|
||||
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | โ | |
|
||||
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
|
||||
| HTML Tables | โ | โ |
|
||||
@ -2414,6 +2419,10 @@ The Lotus formats consist of binary records similar to the BIFF structure. Lotus
|
||||
did release a specification decades ago covering the original WK1 format. Other
|
||||
features were deduced by producing files and comparing to Excel support.
|
||||
|
||||
Generated WK1 worksheets are compatible with Lotus 1-2-3 R2 and Excel 5.0.
|
||||
|
||||
Generated WK3 workbooks are compatible with Lotus 1-2-3 R9 and Excel 5.0.
|
||||
|
||||
|
||||
#### Quattro Pro (WQ1/WQ2/WB1/WB2/WB3/QPW)
|
||||
|
||||
|
@ -52,6 +52,7 @@ digraph G {
|
||||
csf -> fods
|
||||
uos -> csf
|
||||
wk3 -> csf
|
||||
csf -> wk3
|
||||
qpw -> csf
|
||||
}
|
||||
subgraph WORKSHEET {
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.17.3",
|
||||
"version": "0.17.4",
|
||||
"author": "sheetjs",
|
||||
"description": "SheetJS Spreadsheet data parser and writer",
|
||||
"keywords": [
|
||||
|
@ -31,6 +31,7 @@ function run() {
|
||||
.option('-i, --xla', 'emit XLA to <sheetname> or <file>.xla')
|
||||
.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)')
|
||||
.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)')
|
||||
.option('--wk3', 'emit WK3 to <sheetname> or <file>.txt (Lotus WK3)')
|
||||
|
||||
.option('-S, --formulae', 'emit list of values and formulae')
|
||||
.option('-j, --json', 'emit formatted JSON (all fields text)')
|
||||
@ -44,7 +45,7 @@ function run() {
|
||||
.option('-E, --eth', 'emit ETH to <sheetname> or <file>.eth (Ethercalc)')
|
||||
.option('-t, --txt', 'emit TXT to <sheetname> or <file>.txt (UTF-8 TSV)')
|
||||
.option('-r, --rtf', 'emit RTF to <sheetname> or <file>.txt (Table RTF)')
|
||||
.option('--wk1', 'emit WK1 to <sheetname> or <file>.txt (Lotus WK1)')
|
||||
.option('--wk1', 'emit WK1 to <sheetname> or <file>.txt (Lotus WK1)')
|
||||
.option('-z, --dump', 'dump internal representation as JSON')
|
||||
.option('--props', 'dump workbook properties as CSV')
|
||||
|
||||
@ -63,9 +64,6 @@ function run() {
|
||||
.option('-q, --quiet', 'quiet mode');
|
||||
|
||||
program.on('--help', function () {
|
||||
console.log(' Default output format is CSV');
|
||||
console.log(' Support email: dev@sheetjs.com');
|
||||
console.log(' Web Demo: http://oss.sheetjs.com/js-' + n + '/');
|
||||
});
|
||||
|
||||
/* flag, bookType, default ext */
|
||||
@ -78,7 +76,8 @@ function run() {
|
||||
['xla', 'xla', 'xla'],
|
||||
['biff5', 'biff5', 'xls'],
|
||||
['ods', 'ods', 'ods'],
|
||||
['fods', 'fods', 'fods']
|
||||
['fods', 'fods', 'fods'],
|
||||
['wk3', 'wk3', 'wk3']
|
||||
];
|
||||
var wb_formats_2 = [
|
||||
['xlml', 'xlml', 'xls']
|
||||
|
8
test.js
8
test.js
@ -2160,16 +2160,16 @@ describe('HTML', function() {
|
||||
var wb = X.read(table, {type:"string"});
|
||||
assert.equal(get_cell(wb.Sheets.Sheet1, "A1").v, "foo\nbar");
|
||||
});
|
||||
it.skip('should generate multi-sheet workbooks', function() {
|
||||
it('should generate multi-sheet workbooks', function() {
|
||||
var table = "";
|
||||
for(var i = 0; i < 4; ++i) table += "<table><tr><td>" + X.utils.encode_col(i) + "</td><td>" + i + "</td></tr></table>";
|
||||
table += table; table += table;
|
||||
var wb = X.read(table, {type: "string"});
|
||||
assert.equal(wb.SheetNames.length, 4);
|
||||
assert.equal(wb.SheetNames.length, 16);
|
||||
assert.equal(wb.SheetNames[1], "Sheet2");
|
||||
for(var j = 0; j < 4; ++j) {
|
||||
assert.equal(get_cell(wb.Sheets.Sheet + (j+1), "A1"), X.utils.encode_col(j));
|
||||
assert.equal(get_cell(wb.Sheets.Sheet + (j+1), "B1"), j);
|
||||
assert.equal(get_cell(wb.Sheets["Sheet" + (j+1)], "A1").v, X.utils.encode_col(j));
|
||||
assert.equal(get_cell(wb.Sheets["Sheet" + (j+1)], "B1").v, j);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
12
tests/core.js
generated
12
tests/core.js
generated
@ -2160,6 +2160,18 @@ describe('HTML', function() {
|
||||
var wb = X.read(table, {type:"string"});
|
||||
assert.equal(get_cell(wb.Sheets.Sheet1, "A1").v, "foo\nbar");
|
||||
});
|
||||
it('should generate multi-sheet workbooks', function() {
|
||||
var table = "";
|
||||
for(var i = 0; i < 4; ++i) table += "<table><tr><td>" + X.utils.encode_col(i) + "</td><td>" + i + "</td></tr></table>";
|
||||
table += table; table += table;
|
||||
var wb = X.read(table, {type: "string"});
|
||||
assert.equal(wb.SheetNames.length, 16);
|
||||
assert.equal(wb.SheetNames[1], "Sheet2");
|
||||
for(var j = 0; j < 4; ++j) {
|
||||
assert.equal(get_cell(wb.Sheets["Sheet" + (j+1)], "A1").v, X.utils.encode_col(j));
|
||||
assert.equal(get_cell(wb.Sheets["Sheet" + (j+1)], "B1").v, j);
|
||||
}
|
||||
});
|
||||
});
|
||||
(domtest ? describe : describe.skip)('input DOM', function() {
|
||||
it('should interpret values by default', function() { plaintext_test(X.utils.table_to_book(get_dom_element(html_str)), false); });
|
||||
|
636
xlsx.esm.mjs
generated
636
xlsx.esm.mjs
generated
@ -3,7 +3,7 @@
|
||||
/*exported XLSX */
|
||||
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
|
||||
var XLSX = {};
|
||||
XLSX.version = '0.17.3';
|
||||
XLSX.version = '0.17.4';
|
||||
var current_codepage = 1200, current_ansi = 1252;
|
||||
|
||||
var VALID_ANSI = [ 874, 932, 936, 949, 950 ];
|
||||
@ -3561,7 +3561,7 @@ function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) {
|
||||
length = tmpbyte & 0x7F;
|
||||
for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
|
||||
tgt = data.l + length;
|
||||
var d = (R.f||parsenoop)(data, length, opts);
|
||||
var d = R.f && R.f(data, length, opts);
|
||||
data.l = tgt;
|
||||
if(cb(d, R.n, RT)) return;
|
||||
}
|
||||
@ -4210,7 +4210,11 @@ var DocSummaryPIDDSI = {
|
||||
/*::[*/0x1B/*::]*/: { n: 'ContentStatus', t: VT_STRING },
|
||||
/*::[*/0x1C/*::]*/: { n: 'Language', t: VT_STRING },
|
||||
/*::[*/0x1D/*::]*/: { n: 'Version', t: VT_STRING },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
/*::[*/0xFF/*::]*/: {},
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
/*::[*/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 */
|
||||
@ -4234,21 +4238,13 @@ var SummaryPIDSI = {
|
||||
/*::[*/0x11/*::]*/: { n: 'Thumbnail', t: VT_CF },
|
||||
/*::[*/0x12/*::]*/: { n: 'Application', t: VT_STRING },
|
||||
/*::[*/0x13/*::]*/: { n: 'DocSecurity', t: VT_I4 },
|
||||
/*::[*/0xFF/*::]*/: {}
|
||||
};
|
||||
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
var SpecialProperties = {
|
||||
/*::[*/0xFF/*::]*/: {},
|
||||
/* [MS-OLEPS] 2.18 */
|
||||
/*::[*/0x80000000/*::]*/: { n: 'Locale', t: VT_UI4 },
|
||||
/*::[*/0x80000003/*::]*/: { n: 'Behavior', t: VT_UI4 },
|
||||
/*::[*/0x72627262/*::]*/: {}
|
||||
};
|
||||
|
||||
(function() {
|
||||
for(var y in SpecialProperties) if(Object.prototype.hasOwnProperty.call(SpecialProperties, y))
|
||||
DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
|
||||
})();
|
||||
|
||||
var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n");
|
||||
var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n");
|
||||
|
||||
@ -7852,6 +7848,7 @@ var PRN = (function() {
|
||||
}
|
||||
else sep = guess_sep(str.slice(0,1024));
|
||||
}
|
||||
else if(o && o.FS) sep = o.FS;
|
||||
else sep = guess_sep(str.slice(0,1024));
|
||||
var R = 0, C = 0, v = 0;
|
||||
var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0, startcc=str.charCodeAt(0);
|
||||
@ -7904,6 +7901,7 @@ var PRN = (function() {
|
||||
|
||||
function prn_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
|
||||
if(!(opts && opts.PRN)) return dsv_to_sheet_str(str, opts);
|
||||
if(opts.FS) return dsv_to_sheet_str(str, opts);
|
||||
if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
|
||||
if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
|
||||
return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
|
||||
@ -7972,19 +7970,19 @@ function read_wb_ID(d, opts) {
|
||||
}
|
||||
}
|
||||
|
||||
var WK_ = (function() {
|
||||
var WK_ = /*#__PURE__*/ (function() {
|
||||
function lotushopper(data, cb/*:RecordHopperCB*/, opts/*:any*/) {
|
||||
if(!data) return;
|
||||
prep_blob(data, data.l || 0);
|
||||
var Enum = opts.Enum || WK1Enum;
|
||||
while(data.l < data.length) {
|
||||
var RT = data.read_shift(2);
|
||||
var R = Enum[RT] || Enum[0xFF];
|
||||
var R = Enum[RT] || Enum[0xFFFF];
|
||||
var length = data.read_shift(2);
|
||||
var tgt = data.l + length;
|
||||
var d = (R.f||parsenoop)(data, length, opts);
|
||||
var d = R.f && R.f(data, length, opts);
|
||||
data.l = tgt;
|
||||
if(cb(d, R.n, RT)) return;
|
||||
if(cb(d, R, RT)) return;
|
||||
}
|
||||
}
|
||||
|
||||
@ -8003,40 +8001,49 @@ var WK_ = (function() {
|
||||
var o = opts || {};
|
||||
if(DENSE != null && o.dense == null) o.dense = DENSE;
|
||||
var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/), n = "Sheet1", sidx = 0;
|
||||
var sheets = {}, snames = [n];
|
||||
var sheets = {}, snames = [n], realnames = [];
|
||||
|
||||
var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
|
||||
var sheetRows = o.sheetRows || 0;
|
||||
|
||||
if(d[2] == 0x02) o.Enum = WK1Enum;
|
||||
else if(d[2] == 0x1a) o.Enum = WK3Enum;
|
||||
else if(d[2] == 0x0e) { o.Enum = WK3Enum; o.qpro = true; d.l = 0; }
|
||||
else throw new Error("Unrecognized LOTUS BOF " + d[2]);
|
||||
lotushopper(d, function(val, Rn, RT) {
|
||||
if(d[2] == 0x02) switch(RT) {
|
||||
case 0x00:
|
||||
if(d[2] == 0x02) {
|
||||
o.Enum = WK1Enum;
|
||||
lotushopper(d, function(val, R, RT) { switch(RT) {
|
||||
case 0x00: /* BOF */
|
||||
o.vers = val;
|
||||
if(val >= 0x1000) o.qpro = true;
|
||||
break;
|
||||
case 0x06: refguess = val; break; /* RANGE */
|
||||
case 0x0F: /* LABEL */
|
||||
case 0x33: /* STRING */
|
||||
if(!o.qpro) val[1].v = val[1].v.slice(1);
|
||||
/* falls through */
|
||||
case 0x0D: /* INTEGER */
|
||||
case 0x0E: /* NUMBER */
|
||||
case 0x10: /* FORMULA */
|
||||
case 0x33: /* STRING */
|
||||
/* 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 || SSF._table[14];
|
||||
if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
|
||||
}
|
||||
var tmpcell = o.dense ? (s[val[0].r]||[])[val[0].c] : s[encode_cell(val[0])];
|
||||
if(tmpcell) {
|
||||
tmpcell.t = val[1].t; tmpcell.v = val[1].v;
|
||||
if(val[1].z != null) tmpcell.z = val[1].z;
|
||||
if(val[1].f != null) tmpcell.f = val[1].f;
|
||||
break;
|
||||
}
|
||||
if(o.dense) {
|
||||
if(!s[val[0].r]) s[val[0].r] = [];
|
||||
s[val[0].r][val[0].c] = val[1];
|
||||
} else s[encode_cell(val[0])] = val[1];
|
||||
break;
|
||||
} else switch(RT) {
|
||||
default:
|
||||
}}, o);
|
||||
} else if(d[2] == 0x1A || d[2] == 0x0E) {
|
||||
o.Enum = WK3Enum;
|
||||
if(d[2] == 0x0E) { o.qpro = true; d.l = 0; }
|
||||
lotushopper(d, function(val, R, RT) { switch(RT) {
|
||||
case 0x16: /* LABEL16 */
|
||||
val[1].v = val[1].v.slice(1);
|
||||
/* falls through */
|
||||
@ -8062,13 +8069,130 @@ var WK_ = (function() {
|
||||
if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
|
||||
if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
|
||||
break;
|
||||
case 0x1B: /* XFORMAT */
|
||||
if(val[0x36b0]) realnames[val[0x36b0][0]] = val[0x36b0][1];
|
||||
break;
|
||||
default: break;
|
||||
}
|
||||
}, o);
|
||||
}}, o);
|
||||
} else throw new Error("Unrecognized LOTUS BOF " + d[2]);
|
||||
|
||||
s["!ref"] = encode_range(refguess);
|
||||
sheets[n] = s;
|
||||
return { SheetNames: snames, Sheets:sheets };
|
||||
if(!realnames.length) return { SheetNames: snames, Sheets: sheets };
|
||||
var osheets = {}, rnames = [];
|
||||
for(var i = 0; i < realnames.length; ++i) if(sheets[snames[i]]) {
|
||||
rnames.push(realnames[i]);
|
||||
osheets[realnames[i]] = sheets[snames[i]];
|
||||
}
|
||||
return { SheetNames: rnames, Sheets: osheets };
|
||||
}
|
||||
|
||||
function sheet_to_wk1(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
|
||||
var o = opts || {};
|
||||
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();
|
||||
var range = safe_decode_range(ws["!ref"]);
|
||||
var dense = Array.isArray(ws);
|
||||
var cols = [];
|
||||
|
||||
write_biff_rec(ba, 0x00, write_BOF_WK1(0x0406));
|
||||
write_biff_rec(ba, 0x06, write_RANGE(range));
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var rr = encode_row(R);
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
if(R === range.s.r) cols[C] = encode_col(C);
|
||||
var ref = cols[C] + rr;
|
||||
var cell = dense ? (ws[R]||[])[C] : ws[ref];
|
||||
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 {
|
||||
var str = format_cell(cell);
|
||||
write_biff_rec(ba, 0x0F, write_LABEL(R, C, str.slice(0, 239)));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
write_biff_rec(ba, 0x01);
|
||||
return ba.end();
|
||||
}
|
||||
|
||||
function book_to_wk3(wb/*:Workbook*/, opts/*:WriteOpts*/) {
|
||||
var o = opts || {};
|
||||
if(+o.codepage >= 0) set_cp(+o.codepage);
|
||||
if(o.type == "string") throw new Error("Cannot write WK3 to JS string");
|
||||
var ba = buf_array();
|
||||
|
||||
write_biff_rec(ba, 0x00, write_BOF_WK3(wb));
|
||||
|
||||
for(var i = 0, cnt = 0; i < wb.SheetNames.length; ++i) if((wb.Sheets[wb.SheetNames[i]] || {})["!ref"]) write_biff_rec(ba, 0x1b, write_XFORMAT_SHEETNAME(wb.SheetNames[i], cnt++));
|
||||
|
||||
var wsidx = 0;
|
||||
for(i = 0; i < wb.SheetNames.length; ++i) {
|
||||
var ws = wb.Sheets[wb.SheetNames[i]];
|
||||
if(!ws || !ws["!ref"]) continue;
|
||||
var range = safe_decode_range(ws["!ref"]);
|
||||
var dense = Array.isArray(ws);
|
||||
var cols = [];
|
||||
for(var R = range.s.r; R <= range.e.r; ++R) {
|
||||
var rr = encode_row(R);
|
||||
for(var C = range.s.c; C <= range.e.c; ++C) {
|
||||
if(R === range.s.r) cols[C] = encode_col(C);
|
||||
var ref = cols[C] + rr;
|
||||
var cell = dense ? (ws[R]||[])[C] : ws[ref];
|
||||
if(!cell || cell.t == "z") continue;
|
||||
/* TODO: FORMULA19 NUMBER18 records */
|
||||
if(cell.t == "n") {
|
||||
write_biff_rec(ba, 0x17, write_NUMBER_17(R, C, wsidx, cell.v));
|
||||
} else {
|
||||
var str = format_cell(cell);
|
||||
/* TODO: max len? */
|
||||
write_biff_rec(ba, 0x16, write_LABEL_16(R, C, wsidx, str.slice(0, 239)));
|
||||
}
|
||||
}
|
||||
}
|
||||
++wsidx;
|
||||
}
|
||||
|
||||
write_biff_rec(ba, 0x01);
|
||||
return ba.end();
|
||||
}
|
||||
|
||||
|
||||
function write_BOF_WK1(v/*:number*/) {
|
||||
var out = new_buf(2);
|
||||
out.write_shift(2, v);
|
||||
return out;
|
||||
}
|
||||
|
||||
function write_BOF_WK3(wb/*:Workbook*/) {
|
||||
var out = new_buf(26);
|
||||
out.write_shift(2, 0x1000);
|
||||
out.write_shift(2, 0x0004);
|
||||
out.write_shift(4, 0x0000);
|
||||
var rows = 0, cols = 0, wscnt = 0;
|
||||
for(var i = 0; i < wb.SheetNames.length; ++i) {
|
||||
var name = wb.SheetNames[i];
|
||||
var ws = wb.Sheets[name];
|
||||
if(!ws || !ws["!ref"]) continue;
|
||||
++wscnt;
|
||||
var range = decode_range(ws["!ref"]);
|
||||
if(rows < range.e.r) rows = range.e.r;
|
||||
if(cols < range.e.c) cols = range.e.c;
|
||||
}
|
||||
out.write_shift(2, rows);
|
||||
out.write_shift(1, wscnt);
|
||||
out.write_shift(1, cols);
|
||||
out.write_shift(2, 0x00);
|
||||
out.write_shift(2, 0x00);
|
||||
out.write_shift(1, 0x01);
|
||||
out.write_shift(1, 0x02);
|
||||
out.write_shift(4, 0);
|
||||
out.write_shift(4, 0);
|
||||
return out;
|
||||
}
|
||||
|
||||
function parse_RANGE(blob) {
|
||||
@ -8080,6 +8204,14 @@ var WK_ = (function() {
|
||||
if(o.s.c == 0xFFFF) o.s.c = o.e.c = o.s.r = o.e.r = 0;
|
||||
return o;
|
||||
}
|
||||
function write_RANGE(range) {
|
||||
var out = new_buf(8);
|
||||
out.write_shift(2, range.s.c);
|
||||
out.write_shift(2, range.s.r);
|
||||
out.write_shift(2, range.e.c);
|
||||
out.write_shift(2, range.e.r);
|
||||
return out;
|
||||
}
|
||||
|
||||
function parse_cell(blob, length, opts) {
|
||||
var o = [{c:0,r:0}, {t:'n',v:0}, 0];
|
||||
@ -8109,18 +8241,48 @@ var WK_ = (function() {
|
||||
o[1].v = blob.read_shift(tgt - blob.l, 'cstr');
|
||||
return o;
|
||||
}
|
||||
function write_LABEL(R, C, s) {
|
||||
/* TODO: encoding */
|
||||
var o = new_buf(7 + s.length);
|
||||
o.write_shift(1, 0xFF);
|
||||
o.write_shift(2, C);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(1, 0x27); // ??
|
||||
for(var i = 0; i < o.length; ++i) {
|
||||
var cc = s.charCodeAt(i);
|
||||
o.write_shift(1, cc >= 0x80 ? 0x5F : cc);
|
||||
}
|
||||
o.write_shift(1, 0);
|
||||
return o;
|
||||
}
|
||||
|
||||
function parse_INTEGER(blob, length, opts) {
|
||||
var o = parse_cell(blob, length, opts);
|
||||
o[1].v = blob.read_shift(2, 'i');
|
||||
return o;
|
||||
}
|
||||
function write_INTEGER(R, C, v) {
|
||||
var o = new_buf(7);
|
||||
o.write_shift(1, 0xFF);
|
||||
o.write_shift(2, C);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(2, v, 'i');
|
||||
return o;
|
||||
}
|
||||
|
||||
function parse_NUMBER(blob, length, opts) {
|
||||
var o = parse_cell(blob, length, opts);
|
||||
o[1].v = blob.read_shift(8, 'f');
|
||||
return o;
|
||||
}
|
||||
function write_NUMBER(R, C, v) {
|
||||
var o = new_buf(13);
|
||||
o.write_shift(1, 0xFF);
|
||||
o.write_shift(2, C);
|
||||
o.write_shift(2, R);
|
||||
o.write_shift(8, v, 'f');
|
||||
return o;
|
||||
}
|
||||
|
||||
function parse_FORMULA(blob, length, opts) {
|
||||
var tgt = blob.l + length;
|
||||