forked from sheetjs/sheetjs
		
	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