Lotus WK1 worksheet writer [ci skip]
- unpack errors from WK3 long double - explicitly ignore ss:Null in XLML (fixes #2447)
This commit is contained in:
parent
c1f5f041a4
commit
29e3bb4c1f
@ -56,6 +56,7 @@ program
|
||||
.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('-z, --dump', 'dump internal representation as JSON')
|
||||
.option('--props', 'dump workbook properties as CSV')
|
||||
|
||||
@ -229,6 +230,7 @@ if(!program.quiet && !program.book) console.error(target_sheet);
|
||||
['rtf', '.rtf'],
|
||||
['txt', '.txt'],
|
||||
['dbf', '.dbf'],
|
||||
['wk1', '.wk1'],
|
||||
['dif', '.dif']
|
||||
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {
|
||||
wopts.bookType = m[0];
|
||||
|
@ -12,7 +12,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;
|
||||
}
|
||||
|
259
bits/41_lotus.js
259
bits/41_lotus.js
@ -1,16 +1,16 @@
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
@ -34,12 +34,9 @@ var WK_ = (function() {
|
||||
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) {
|
||||
if(d[2] == 0x02) {
|
||||
o.Enum = WK1Enum;
|
||||
lotushopper(d, function(val, R, RT) { switch(RT) {
|
||||
case 0x00:
|
||||
o.vers = val;
|
||||
if(val >= 0x1000) o.qpro = true;
|
||||
@ -62,7 +59,11 @@ var WK_ = (function() {
|
||||
s[val[0].r][val[0].c] = val[1];
|
||||
} else s[encode_cell(val[0])] = val[1];
|
||||
break;
|
||||
} else switch(RT) {
|
||||
}}, 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 */
|
||||
@ -89,14 +90,53 @@ var WK_ = (function() {
|
||||
if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
|
||||
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 };
|
||||
}
|
||||
|
||||
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");
|
||||
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;
|
||||
/* write cell */
|
||||
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 write_BOF_WK1(v/*:number*/) {
|
||||
var out = new_buf(2);
|
||||
out.write_shift(2, v);
|
||||
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);
|
||||
@ -106,6 +146,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];
|
||||
@ -135,18 +183,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;
|
||||
@ -178,15 +256,16 @@ var WK_ = (function() {
|
||||
var o = parse_cell_3(blob, length);
|
||||
o[1].v = blob.read_shift(2);
|
||||
var v = o[1].v >> 1;
|
||||
/* TODO: figure out all of the corner cases */
|
||||
if(o[1].v & 0x1) {
|
||||
switch(v & 0x07) {
|
||||
case 0: v = (v >> 3) * 5000; break;
|
||||
case 1: v = (v >> 3) * 500; break;
|
||||
case 2: v = (v >> 3) / 20; break;
|
||||
case 3: v = (v >> 3) / 200; break;
|
||||
case 4: v = (v >> 3) / 2000; break;
|
||||
case 5: v = (v >> 3) / 20000; break;
|
||||
case 6: v = (v >> 3) / 16; break;
|
||||
case 7: v = (v >> 3) / 64; break;
|
||||
default: throw "unknown NUMBER_18 encoding " + (v & 0x07);
|
||||
}
|
||||
}
|
||||
o[1].v = v;
|
||||
@ -198,9 +277,14 @@ var WK_ = (function() {
|
||||
var v1 = blob.read_shift(4);
|
||||
var v2 = blob.read_shift(4);
|
||||
var e = blob.read_shift(2);
|
||||
if(e == 0xFFFF) { o[1].v = 0; return o; }
|
||||
if(e == 0xFFFF) {
|
||||
if(v1 === 0 && v2 === 0xC0000000) { o[1].t = "e"; o[1].v = 0x0F; } // ERR -> #VALUE!
|
||||
else if(v1 === 0 && v2 === 0xD0000000) { o[1].t = "e"; o[1].v = 0x2A; } // NA -> #N/A
|
||||
else o[1].v = 0;
|
||||
return o;
|
||||
}
|
||||
var s = e & 0x8000; e = (e&0x7FFF) - 16446;
|
||||
o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
|
||||
o[1].v = (1 - s*2) * ( /*(e > 0 ? (v2 << e) : (v2 >>> -e))*/ v2 * Math.pow(2, e+32) + v1 * Math.pow(2, e));
|
||||
return o;
|
||||
}
|
||||
|
||||
@ -288,45 +372,138 @@ var WK_ = (function() {
|
||||
/*::[*/0x0048/*::]*/: { n:"ACOMM" },
|
||||
/*::[*/0x0049/*::]*/: { n:"AMACRO" },
|
||||
/*::[*/0x004A/*::]*/: { n:"PARSE" },
|
||||
/*::[*/0x00FF/*::]*/: { n:"", f:parsenoop }
|
||||
/*::[*/0x0066/*::]*/: { n:"PRANGES??" },
|
||||
/*::[*/0x0067/*::]*/: { n:"RRANGES??" },
|
||||
/*::[*/0x0068/*::]*/: { n:"FNAME??" },
|
||||
/*::[*/0x0069/*::]*/: { n:"MRANGES??" },
|
||||
/*::[*/0xFFFF/*::]*/: { n:"" }
|
||||
};
|
||||
|
||||
var WK3Enum = {
|
||||
/*::[*/0x0000/*::]*/: { n:"BOF" },
|
||||
/*::[*/0x0001/*::]*/: { n:"EOF" },
|
||||
/*::[*/0x0003/*::]*/: { n:"??" },
|
||||
/*::[*/0x0004/*::]*/: { n:"??" },
|
||||
/*::[*/0x0005/*::]*/: { n:"??" },
|
||||
/*::[*/0x0006/*::]*/: { n:"??" },
|
||||
/*::[*/0x0007/*::]*/: { n:"??" },
|
||||
/*::[*/0x0009/*::]*/: { n:"??" },
|
||||
/*::[*/0x000a/*::]*/: { n:"??" },
|
||||
/*::[*/0x000b/*::]*/: { n:"??" },
|
||||
/*::[*/0x000c/*::]*/: { n:"??" },
|
||||
/*::[*/0x000e/*::]*/: { n:"??" },
|
||||
/*::[*/0x000f/*::]*/: { n:"??" },
|
||||
/*::[*/0x0010/*::]*/: { n:"??" },
|
||||
/*::[*/0x0011/*::]*/: { n:"??" },
|
||||
/*::[*/0x0012/*::]*/: { n:"??" },
|
||||
/*::[*/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:"??" },
|
||||
/*::[*/0x0015/*::]*/: { 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:"??" },
|
||||
/*::[*/0x001b/*::]*/: { n:"??" },
|
||||
/*::[*/0x001c/*::]*/: { n:"??" },
|
||||
/*::[*/0x001d/*::]*/: { n:"??" },
|
||||
/*::[*/0x001e/*::]*/: { n:"??" },
|
||||
/*::[*/0x001f/*::]*/: { n:"??" },
|
||||
/*::[*/0x0021/*::]*/: { n:"??" },
|
||||
/*::[*/0x001A/*::]*/: { n:"FORMULA1A" },
|
||||
/*::[*/0x001B/*::]*/: { n:"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 },
|
||||
/*::[*/0x00FF/*::]*/: { n:"", f:parsenoop }
|
||||
/*::[*/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:"??" },
|
||||
/*::[*/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:"??" },
|
||||
/*::[*/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:"" }
|
||||
};
|
||||
return {
|
||||
sheet_to_wk1: sheet_to_wk1,
|
||||
to_workbook: lotus_to_workbook
|
||||
};
|
||||
})();
|
||||
|
@ -472,6 +472,8 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
|
||||
else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
|
||||
break;
|
||||
|
||||
case 'null' /*case 'Null'*/: break;
|
||||
|
||||
default:
|
||||
/* FODS file root is <office:document> */
|
||||
if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts);
|
||||
|
@ -1,5 +1,5 @@
|
||||
function write_biff_rec(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/)/*:void*/ {
|
||||
var t/*:number*/ = +type || +XLSRE[/*::String(*/type/*::)*/];
|
||||
var t/*:number*/ = typeof type == "number" ? type : (+type || +XLSRE[/*::String(*/type/*::)*/]);
|
||||
if(isNaN(t)) return;
|
||||
var len = length || (payload||[]).length || 0;
|
||||
var o = ba.next(4);
|
||||
|
@ -21,4 +21,5 @@ var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {});
|
||||
var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
|
||||
var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {});
|
||||
var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {});
|
||||
var write_wk1_buf = write_obj_str(typeof WK_ !== "undefined" ? {from_sheet:WK_.sheet_to_wk1} : {});
|
||||
|
||||
|
@ -96,6 +96,7 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
|
||||
case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
|
||||
case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
|
||||
case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
|
||||
case 0x89: if(n[1] === 0x50 && n[2] === 0x4E && n[3] === 0x47) throw new Error("PNG Image File is not a spreadsheet"); break;
|
||||
}
|
||||
if(DBF.versions.indexOf(n[0]) > -1 && n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
|
||||
return read_prn(data, d, o, str);
|
||||
|
@ -105,6 +105,7 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
|
||||
case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
|
||||
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 '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);
|
||||
|
@ -53,6 +53,7 @@ output formats. The specific file type is controlled with `bookType` option:
|
||||
| `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) |
|
||||
|
@ -24,7 +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 (WKS/WK1/WK2/WK3/WK4/123) | ✔ | |
|
||||
| Lotus 1-2-3 (WK1) | ✔ | ✔ |
|
||||
| Lotus 1-2-3 (WKS/WK2/WK3/WK4/123) | ✔ | |
|
||||
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | ✔ | |
|
||||
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
|
||||
| HTML Tables | ✔ | ✔ |
|
||||
@ -162,6 +163,8 @@ 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.
|
||||
|
||||
</details>
|
||||
|
||||
#### Quattro Pro (WQ1/WQ2/WB1/WB2/WB3/QPW)
|
||||
|
BIN
formats.png
BIN
formats.png
Binary file not shown.
Before Width: | Height: | Size: 439 KiB After Width: | Height: | Size: 444 KiB |
@ -66,6 +66,7 @@ digraph G {
|
||||
slk -> csf
|
||||
csf -> dif
|
||||
wk1 -> csf
|
||||
csf -> wk1
|
||||
wqb -> csf
|
||||
dif -> csf
|
||||
csf -> rtf
|
||||
|
@ -44,6 +44,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('-z, --dump', 'dump internal representation as JSON')
|
||||
.option('--props', 'dump workbook properties as CSV')
|
||||
|
||||
@ -221,6 +222,7 @@ function run() {
|
||||
['rtf', '.rtf'],
|
||||
['txt', '.txt'],
|
||||
['dbf', '.dbf'],
|
||||
['wk1', '.wk1'],
|
||||
['dif', '.dif']
|
||||
].forEach(function (m) {
|
||||
if (program[m[0]] || isfmt(m[1])) {
|
||||
|
Loading…
Reference in New Issue
Block a user