forked from sheetjs/sheetjs
		
	version bump 0.8.4: formula parsing
- BIFF 2-12 formula parsing - more content type coverage - unified `.f` form: A1-style string - `.F` field for array formulae - formula output groups array formulae - bin script -A --arrays output JS row objects - whitespace robustness in inline string xml - UTF-8 parsing in rich text runs (fixes #505 h/t @fuchsc) - bold/italic/underline accept null val attr (h/t @qqilihq) - sst trimming (fixes #176 h/t @shakhal @oising)
This commit is contained in:
		
							parent
							
								
									ab2ecebac9
								
							
						
					
					
						commit
						d7ecca0e8b
					
				
							
								
								
									
										18
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										18
									
								
								.gitignore
									
									
									
									
										vendored
									
									
								
							| @ -4,17 +4,15 @@ misc/prof.js | ||||
| v8.log | ||||
| tmp | ||||
| *.txt | ||||
| *.csv | ||||
| *.dif | ||||
| *.prn | ||||
| *.slk | ||||
| *.[cC][sS][vV] | ||||
| *.[dD][iI][fF] | ||||
| *.[pP][rR][nN] | ||||
| *.[sS][lL][kK] | ||||
| *.socialcalc | ||||
| *.xls | ||||
| *.xlsb | ||||
| *.xlsm | ||||
| *.xlsx | ||||
| *.ods | ||||
| *.xml | ||||
| *.[xX][lL][sSwW] | ||||
| *.[xX][lL][sS][xXmMbB] | ||||
| *.[oO][dD][sS] | ||||
| *.[xX][mM][lL] | ||||
| *.htm | ||||
| *.html | ||||
| *.sheetjs | ||||
|  | ||||
							
								
								
									
										19
									
								
								.npmignore
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										19
									
								
								.npmignore
									
									
									
									
									
								
							| @ -5,18 +5,15 @@ misc/ | ||||
| node_modules | ||||
| tmp | ||||
| *.txt | ||||
| *.csv | ||||
| *.dif | ||||
| *.prn | ||||
| *.slk | ||||
| *.[cC][sS][vV] | ||||
| *.[dD][iI][fF] | ||||
| *.[pP][rR][nN] | ||||
| *.[sS][lL][kK] | ||||
| *.socialcalc | ||||
| *.XLS | ||||
| *.xls | ||||
| *.xlsb | ||||
| *.xlsm | ||||
| *.xlsx | ||||
| *.ods | ||||
| *.xml | ||||
| *.[xX][lL][sSwW] | ||||
| *.[xX][lL][sS][xXmMbB] | ||||
| *.[oO][dD][sS] | ||||
| *.[xX][mM][lL] | ||||
| *.htm | ||||
| *.html | ||||
| *.sheetjs | ||||
|  | ||||
| @ -3,7 +3,7 @@ node_js: | ||||
|   - "7" | ||||
|   - "6" | ||||
|   - "5" | ||||
|   - "4.2" | ||||
|   - "4" | ||||
|   - "0.12" | ||||
|   - "0.10" | ||||
|   - "0.9" | ||||
|  | ||||
							
								
								
									
										44
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										44
									
								
								README.md
									
									
									
									
									
								
							| @ -366,24 +366,28 @@ for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 
 | ||||
| ### Cell Object | ||||
| 
 | ||||
| | Key | Description | | ||||
| | --- | ----------- | | ||||
| | `v` | raw value (see Data Types section for more info) | | ||||
| | `w` | formatted text (if applicable) | | ||||
| | `t` | cell type: `b` Boolean, `n` Number, `e` error, `s` String, `d` Date | | ||||
| | `f` | cell formula (if applicable) | | ||||
| | `r` | rich text encoding (if applicable) | | ||||
| | `h` | HTML rendering of the rich text (if applicable) | | ||||
| | `c` | comments associated with the cell ** | | ||||
| | `z` | number format string associated with the cell (if requested) | | ||||
| | `l` | cell hyperlink object (.Target holds link, .tooltip is tooltip) | | ||||
| | `s` | the style/theme of the cell (if applicable) | | ||||
| | Key | Description                                                            | | ||||
| | --- | ---------------------------------------------------------------------- | | ||||
| | `v` | raw value (see Data Types section for more info)                       | | ||||
| | `w` | formatted text (if applicable)                                         | | ||||
| | `t` | cell type: `b` Boolean, `n` Number, `e` error, `s` String, `d` Date    | | ||||
| | `f` | cell formula encoded as an A1-style string (if applicable)             | | ||||
| | `F` | range of enclosing array if formula is array formula (if applicable)   | | ||||
| | `r` | rich text encoding (if applicable)                                     | | ||||
| | `h` | HTML rendering of the rich text (if applicable)                        | | ||||
| | `c` | comments associated with the cell                                      | | ||||
| | `z` | number format string associated with the cell (if requested)           | | ||||
| | `l` | cell hyperlink object (.Target holds link, .tooltip is tooltip)        | | ||||
| | `s` | the style/theme of the cell (if applicable)                            | | ||||
| 
 | ||||
| Built-in export utilities (such as the CSV exporter) will use the `w` text if it | ||||
| is available.  To change a value, be sure to delete `cell.w` (or set it to | ||||
| `undefined`) before attempting to export.  The utilities will regenerate the `w` | ||||
| text from the number format (`cell.z`) and the raw value if possible. | ||||
| 
 | ||||
| The actual array formula is stored in the `f` field of the first cell in the | ||||
| array range.  Other cells in the range will omit the `f` field. | ||||
| 
 | ||||
| ### Data Types | ||||
| 
 | ||||
| The raw value is stored in the `v` field, interpreted based on the `t` field. | ||||
| @ -418,6 +422,20 @@ dates in the local timezone.  js-xlsx does not correct for this error. | ||||
| Type `s` is the String type.  `v` should be explicitly stored as a string to | ||||
| avoid possible confusion. | ||||
| 
 | ||||
| ### Formulae | ||||
| 
 | ||||
| The A1-style formula string is stored in the `f` field.  Even though different | ||||
| file formats store the formulae in different ways, the formats are converted. | ||||
| 
 | ||||
| Shared formulae are decompressed and each cell has the correct formula. | ||||
| 
 | ||||
| Array formulae are stored in the top-left cell of the array block.  All cells | ||||
| of an array formula have a `F` field corresponding to the range.  A single-cell | ||||
| formula can be distinguished from a plain formula by the presence of `F` field. | ||||
| 
 | ||||
| The `sheet_to_formulae` method generates one line per formula or array formula. | ||||
| Array formulae are rendered in the form `range=formula` while plain cells are | ||||
| rendered in the form `cell=formula or value`. | ||||
| 
 | ||||
| ### Worksheet Object | ||||
| 
 | ||||
| @ -619,6 +637,8 @@ OSP-covered specifications: | ||||
|  - [MS-OLEDS]: Object Linking and Embedding (OLE) Data Structures | ||||
|  - [MS-OLEPS]: Object Linking and Embedding (OLE) Property Set Data Structures | ||||
|  - [MS-OSHARED]: Office Common Data Types and Objects Structures | ||||
|  - [MS-ODRAW]: Office Drawing Binary File Format | ||||
|  - [MS-ODRAWXML]: Office Drawing Extensions to Office Open XML Structure | ||||
|  - [MS-OVBA]: Office VBA File Format Structure | ||||
|  - [MS-CTXLS]: Excel Custom Toolbar Binary File Format | ||||
|  - [MS-XLDM]: Spreadsheet Data Model File Format | ||||
|  | ||||
| @ -21,6 +21,7 @@ program | ||||
| 	.option('-S, --formulae', 'print formulae') | ||||
| 	.option('-j, --json', 'emit formatted JSON (all fields text)') | ||||
| 	.option('-J, --raw-js', 'emit raw JS object (raw numbers)') | ||||
| 	.option('-A, --arrays', 'emit rows as JS objects (raw numbers)') | ||||
| 	.option('-F, --field-sep <sep>', 'CSV field separator', ",") | ||||
| 	.option('-R, --row-sep <sep>', 'CSV row separator', "\n") | ||||
| 	.option('-n, --sheet-rows <num>', 'Number of rows to process (0=all rows)') | ||||
| @ -77,7 +78,7 @@ if(program.xlsx || program.xlsm || program.xlsb) { | ||||
| 	opts.cellNF = true; | ||||
| 	if(program.output) sheetname = program.output; | ||||
| } | ||||
| else if(program.formulae); | ||||
| else if(program.formulae) opts.cellFormula = true; | ||||
| else opts.cellFormula = false; | ||||
| 
 | ||||
| if(program.all) { | ||||
| @ -142,6 +143,7 @@ if(!program.quiet) console.error(target_sheet); | ||||
| if(program.formulae) oo = X.utils.get_formulae(ws).join("\n"); | ||||
| else if(program.json) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws)); | ||||
| else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true})); | ||||
| else if(program.arrays) oo = JSON.stringify(X.utils.sheet_to_row_object_array(ws,{raw:true, header:1})); | ||||
| else oo = X.utils.make_csv(ws, {FS:program.fieldSep, RS:program.rowSep}); | ||||
| 
 | ||||
| if(program.output) fs.writeFileSync(program.output, oo); | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| XLSX.version = '0.8.3'; | ||||
| XLSX.version = '0.8.4'; | ||||
|  | ||||
| @ -42,3 +42,12 @@ function cc2str(arr/*:Array<number>*/)/*:string*/ { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| function dup(o/*:any*/)/*:any*/ { | ||||
| 	if(typeof JSON != 'undefined') return JSON.parse(JSON.stringify(o)); | ||||
| 	if(typeof o != 'object' || !o) return o; | ||||
| 	var out = {}; | ||||
| 	for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; } | ||||
|  | ||||
| @ -115,9 +115,9 @@ var matchtag = (function() { | ||||
| var vtregex = (function(){ var vt_cache = {}; | ||||
| 	return function vt_regex(bt) { | ||||
| 		if(vt_cache[bt] !== undefined) return vt_cache[bt]; | ||||
| 		return (vt_cache[bt] = new RegExp("<vt:" + bt + ">(.*?)</vt:" + bt + ">", 'g') ); | ||||
| 		return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">(.*?)</(?:vt:)?" + bt + ">", 'g') ); | ||||
| };})(); | ||||
| var vtvregex = /<\/?vt:variant>/g, vtmregex = /<vt:([^>]*)>(.*)</; | ||||
| var vtvregex = /<\/?(:?vt:)?variant>/g, vtmregex = /<(:?vt:)?([^>]*)>(.*)</; | ||||
| function parseVector(data) { | ||||
| 	var h = parsexmltag(data); | ||||
| 
 | ||||
|  | ||||
| @ -82,6 +82,8 @@ function ReadShift(size, t) { | ||||
| 		case 'utf8': o = __utf8(this, this.l, this.l + size); break; | ||||
| 		case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break; | ||||
| 
 | ||||
| 		case 'wstr': o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size)); size = 2 * size; break; | ||||
| 
 | ||||
| 		/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */ | ||||
| 		case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break; | ||||
| 		/* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */ | ||||
|  | ||||
| @ -1,16 +1,18 @@ | ||||
| /* XLS ranges enforced */ | ||||
| function shift_cell_xls(cell, tgt) { | ||||
| function shift_cell_xls(cell, tgt, opts) { | ||||
| 	var out = dup(cell); | ||||
| 	if(tgt.s) { | ||||
| 		if(cell.cRel) cell.c += tgt.s.c; | ||||
| 		if(cell.rRel) cell.r += tgt.s.r; | ||||
| 		if(out.cRel) out.c += tgt.s.c; | ||||
| 		if(out.rRel) out.r += tgt.s.r; | ||||
| 	} else { | ||||
| 		cell.c += tgt.c; | ||||
| 		cell.r += tgt.r; | ||||
| 		out.c += tgt.c; | ||||
| 		out.r += tgt.r; | ||||
| 	} | ||||
| 	cell.cRel = cell.rRel = 0; | ||||
| 	while(cell.c >= 0x100) cell.c -= 0x100; | ||||
| 	while(cell.r >= 0x10000) cell.r -= 0x10000; | ||||
| 	return cell; | ||||
| 	if(!opts || opts.biff < 12) { | ||||
| 		while(out.c >= 0x100) out.c -= 0x100; | ||||
| 		while(out.r >= 0x10000) out.r -= 0x10000; | ||||
| 	} | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| function shift_range_xls(cell, range) { | ||||
| @ -19,3 +21,13 @@ function shift_range_xls(cell, range) { | ||||
| 	return cell; | ||||
| } | ||||
| 
 | ||||
| function encode_cell_xls(c)/*:string*/ { | ||||
| 	var s = encode_cell(c); | ||||
| 	if(c.cRel === 0) s = fix_col(s); | ||||
| 	if(c.rRel === 0) s = fix_row(s); | ||||
| 	return s; | ||||
| } | ||||
| 
 | ||||
| function encode_range_xls(r)/*:string*/ { | ||||
| 	return encode_cell_xls(r.s) + ":" + encode_cell_xls(r.e); | ||||
| } | ||||
|  | ||||
| @ -76,6 +76,10 @@ function write_XLWideString(data/*:string*/, o) { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.165 */ | ||||
| var parse_XLNameWideString = parse_XLWideString; | ||||
| var write_XLNameWideString = write_XLWideString; | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.114 */ | ||||
| var parse_RelID = parse_XLNullableWideString; | ||||
| var write_RelID = write_XLNullableWideString; | ||||
| @ -101,8 +105,8 @@ function write_RkNumber(data/*:number*/, o) { | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.153 */ | ||||
| function parse_UncheckedRfX(data)/*:Range*/ { | ||||
| /* [MS-XLSB] 2.5.117 RfX */ | ||||
| function parse_RfX(data)/*:Range*/ { | ||||
| 	var cell/*:Range*/ = ({s: {}, e: {}}/*:any*/); | ||||
| 	cell.s.r = data.read_shift(4); | ||||
| 	cell.e.r = data.read_shift(4); | ||||
| @ -111,7 +115,7 @@ function parse_UncheckedRfX(data)/*:Range*/ { | ||||
| 	return cell; | ||||
| } | ||||
| 
 | ||||
| function write_UncheckedRfX(r/*:Range*/, o) { | ||||
| function write_RfX(r/*:Range*/, o) { | ||||
| 	if(!o) o = new_buf(16); | ||||
| 	o.write_shift(4, r.s.r); | ||||
| 	o.write_shift(4, r.e.r); | ||||
| @ -120,6 +124,10 @@ function write_UncheckedRfX(r/*:Range*/, o) { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.153 UncheckedRfX */ | ||||
| var parse_UncheckedRfX = parse_RfX; | ||||
| var write_UncheckedRfX = write_RfX; | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.171 */ | ||||
| /* [MS-XLS] 2.5.342 */ | ||||
| /* TODO: error checking, NaN and Infinity values are not valid Xnum */ | ||||
|  | ||||
| @ -40,6 +40,12 @@ var ct2type/*{[string]:string}*/ = ({ | ||||
| 	"application/vnd.ms-excel.pivotTable": "TODO", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO", | ||||
| 
 | ||||
| 	/* Chart Colors */ | ||||
| 	"application/vnd.ms-office.chartcolorstyle+xml": "TODO", | ||||
| 
 | ||||
| 	/* Chart Style */ | ||||
| 	"application/vnd.ms-office.chartstyle+xml": "TODO", | ||||
| 
 | ||||
| 	/* Calculation Chain */ | ||||
| 	"application/vnd.ms-excel.calcChain": "calcchains", | ||||
| 	"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains", | ||||
|  | ||||
| @ -10,10 +10,7 @@ function parse_cust_props(data/*:string*/, opts) { | ||||
| 		var x = m[i], y = parsexmltag(x); | ||||
| 		switch(y[0]) { | ||||
| 			case '<?xml': break; | ||||
| 			case '<Properties': | ||||
| 				if(y.xmlns !== XMLNS.CUST_PROPS) throw "unrecognized xmlns " + y.xmlns; | ||||
| 				if(y.xmlnsvt && y.xmlnsvt !== XMLNS.vt) throw "unrecognized vt " + y.xmlnsvt; | ||||
| 				break; | ||||
| 			case '<Properties': break; | ||||
| 			case '<property': name = y.name; break; | ||||
| 			case '</property>': name = null; break; | ||||
| 			default: if (x.indexOf('<vt:') === 0) { | ||||
|  | ||||
| @ -303,13 +303,15 @@ function parse_Bes(blob) { | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.240 ShortXLUnicodeString */ | ||||
| function parse_ShortXLUnicodeString(blob, length, opts) { | ||||
| 	var cch = blob.read_shift(1); | ||||
| 	var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1); | ||||
| 	var width = 1, encoding = 'sbcs-cont'; | ||||
| 	var cp = current_codepage; | ||||
| 	if(opts && opts.biff >= 8) current_codepage = 1200; | ||||
| 	if(opts === undefined || opts.biff !== 5) { | ||||
| 	if(!opts || opts.biff == 8 ) { | ||||
| 		var fHighByte = blob.read_shift(1); | ||||
| 		if(fHighByte) { width = 2; encoding = 'dbcs-cont'; } | ||||
| 	} else if(opts.biff == 12) { | ||||
| 		width = 2; encoding = 'wstr'; | ||||
| 	} | ||||
| 	var o = cch ? blob.read_shift(cch, encoding) : ""; | ||||
| 	current_codepage = cp; | ||||
| @ -340,6 +342,10 @@ function parse_XLUnicodeRichExtendedString(blob) { | ||||
| /* 2.5.296 XLUnicodeStringNoCch */ | ||||
| function parse_XLUnicodeStringNoCch(blob, cch, opts) { | ||||
| 	var retval; | ||||
| 	if(opts) { | ||||
| 		if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'sbcs-cont'); | ||||
| 		if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont'); | ||||
| 	} | ||||
| 	var fHighByte = blob.read_shift(1); | ||||
| 	if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); } | ||||
| 	else { retval = blob.read_shift(cch, 'dbcs-cont'); } | ||||
| @ -348,7 +354,7 @@ function parse_XLUnicodeStringNoCch(blob, cch, opts) { | ||||
| 
 | ||||
| /* 2.5.294 XLUnicodeString */ | ||||
| function parse_XLUnicodeString(blob, length, opts) { | ||||
| 	var cch = blob.read_shift(opts !== undefined && opts.biff > 0 && opts.biff < 8 ? 1 : 2); | ||||
| 	var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); | ||||
| 	if(cch === 0) { blob.l++; return ""; } | ||||
| 	return parse_XLUnicodeStringNoCch(blob, cch, opts); | ||||
| } | ||||
|  | ||||
| @ -39,10 +39,10 @@ function parse_RkRec(blob, length) { | ||||
| } | ||||
| 
 | ||||
| /* 2.5.1 */ | ||||
| function parse_AddinUdf(blob, length) { | ||||
| function parse_AddinUdf(blob, length, opts) { | ||||
| 	blob.l += 4; length -= 4; | ||||
| 	var l = blob.l + length; | ||||
| 	var udfName = parse_ShortXLUnicodeString(blob, length); | ||||
| 	var udfName = parse_ShortXLUnicodeString(blob, length, opts); | ||||
| 	var cb = blob.read_shift(2); | ||||
| 	l -= blob.l; | ||||
| 	if(cb !== l) throw "Malformed AddinUdf: padding = " + l + " != " + cb; | ||||
| @ -272,8 +272,10 @@ function parse_LabelSst(blob, length) { | ||||
| 
 | ||||
| /* 2.4.148 */ | ||||
| function parse_Label(blob, length, opts) { | ||||
| 	var target = blob.l + length; | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	var str = parse_XLUnicodeString(blob, length-6, opts); | ||||
| 	if(opts.biff == 2) blob.l++; | ||||
| 	var str = parse_XLUnicodeString(blob, target - blob.l, opts); | ||||
| 	cell.val = str; | ||||
| 	return cell; | ||||
| } | ||||
| @ -287,11 +289,12 @@ function parse_Format(blob, length, opts) { | ||||
| var parse_BIFF2Format = parse_XLUnicodeString2; | ||||
| 
 | ||||
| /* 2.4.90 */ | ||||
| function parse_Dimensions(blob, length) { | ||||
| 	var w = length === 10 ? 2 : 4; | ||||
| function parse_Dimensions(blob, length, opts) { | ||||
| 	var end = blob.l + length; | ||||
| 	var w = opts.biff == 8 || !opts.biff ? 4 : 2; | ||||
| 	var r = blob.read_shift(w), R = blob.read_shift(w), | ||||
| 	    c = blob.read_shift(2), C = blob.read_shift(2); | ||||
| 	blob.l += 2; | ||||
| 	blob.l = end; | ||||
| 	return {s: {r:r, c:c}, e: {r:R, c:C}}; | ||||
| } | ||||
| 
 | ||||
| @ -392,7 +395,7 @@ function parse_ExternName(blob, length, opts) { | ||||
| 		cf: (flags >>> 5) & 0x3FF, | ||||
| 		fIcon: flags >>> 15 & 0x01 | ||||
| 	}/*:any*/); | ||||
| 	if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2); | ||||
| 	if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts); | ||||
| 	//else throw new Error("unsupported SupBook cch: " + opts.sbcch);
 | ||||
| 	o.body = body || blob.read_shift(length-2); | ||||
| 	return o; | ||||
| @ -404,12 +407,15 @@ function parse_Lbl(blob, length, opts) { | ||||
| 	var flags = blob.read_shift(2); | ||||
| 	var chKey = blob.read_shift(1); | ||||
| 	var cch = blob.read_shift(1); | ||||
| 	var cce = blob.read_shift(2); | ||||
| 	blob.l += 2; | ||||
| 	var itab = blob.read_shift(2); | ||||
| 	blob.l += 4; | ||||
| 	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); | ||||
| 	if(!opts || opts.biff >= 5) { | ||||
| 		blob.l += 2; | ||||
| 		var itab = blob.read_shift(2); | ||||
| 		blob.l += 4; | ||||
| 	} | ||||
| 	var name = parse_XLUnicodeStringNoCch(blob, cch, opts); | ||||
| 	var rgce = parse_NameParsedFormula(blob, target - blob.l, opts, cce); | ||||
| 	var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen; | ||||
| 	var rgce = target == blob.l || cce == 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce); | ||||
| 	return { | ||||
| 		chKey: chKey, | ||||
| 		Name: name, | ||||
| @ -441,7 +447,12 @@ function parse_ShrFmla(blob, length, opts) { | ||||
| /* 2.4.4 TODO */ | ||||
| function parse_Array(blob, length, opts) { | ||||
| 	var ref = parse_Ref(blob, 6); | ||||
| 	blob.l += 6; length -= 12; /* TODO: fAlwaysCalc */ | ||||
| 	/* TODO: fAlwaysCalc */ | ||||
| 	switch(opts.biff) { | ||||
| 		case 2: blob.l ++; length -= 7; break; | ||||
| 		case 3: case 4: blob.l += 2; length -= 8; break; | ||||
| 		default: blob.l += 6; length -= 12; | ||||
| 	} | ||||
| 	return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)]; | ||||
| } | ||||
| 
 | ||||
| @ -904,6 +915,7 @@ function parse_BIFF2STR(blob, length, opts) { | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	++blob.l; | ||||
| 	var str = parse_XLUnicodeString2(blob, length-7, opts); | ||||
| 	cell.t = 'str'; | ||||
| 	cell.val = str; | ||||
| 	return cell; | ||||
| } | ||||
| @ -912,6 +924,7 @@ function parse_BIFF2NUM(blob, length, opts) { | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	++blob.l; | ||||
| 	var num = parse_Xnum(blob, 8); | ||||
| 	cell.t = 'n'; | ||||
| 	cell.val = num; | ||||
| 	return cell; | ||||
| } | ||||
| @ -920,6 +933,7 @@ function parse_BIFF2INT(blob, length) { | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	++blob.l; | ||||
| 	var num = blob.read_shift(2); | ||||
| 	cell.t = 'n'; | ||||
| 	cell.val = num; | ||||
| 	return cell; | ||||
| } | ||||
| @ -939,3 +953,15 @@ function parse_BIFF2FONTXTRA(blob, length) { | ||||
| 	blob.l += 1; // font family
 | ||||
| 	blob.l += length - 9; | ||||
| } | ||||
| 
 | ||||
| /* TODO: parse rich text runs */ | ||||
| function parse_RString(blob, length, opts) { | ||||
| 	var end = blob.l + length; | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	var cch = blob.read_shift(2); | ||||
| 	var str = parse_XLUnicodeStringNoCch(blob, cch, opts); | ||||
| 	blob.l = end; | ||||
| 	cell.t = 'str'; | ||||
| 	cell.val = str; | ||||
| 	return cell; | ||||
| } | ||||
|  | ||||
| @ -70,21 +70,21 @@ var parse_rs = (function parse_rs_factory() { | ||||
| 
 | ||||
| 				/* 18.4.13 u CT_UnderlineProperty */ | ||||
| 				case '<u': | ||||
| 					if(!y.val) break; | ||||
| 					if(y.val == '0') break; | ||||
| 					/* falls through */ | ||||
| 				case '<u/>': font.u = 1; break; | ||||
| 				case '</u>': break; | ||||
| 
 | ||||
| 				/* 18.8.2 b */ | ||||
| 				case '<b': | ||||
| 					if(!y.val) break; | ||||
| 					if(y.val == '0') break; | ||||
| 					/* falls through */ | ||||
| 				case '<b/>': font.b = 1; break; | ||||
| 				case '</b>': break; | ||||
| 
 | ||||
| 				/* 18.8.26 i */ | ||||
| 				case '<i': | ||||
| 					if(!y.val) break; | ||||
| 					if(y.val == '0') break; | ||||
| 					/* falls through */ | ||||
| 				case '<i/>': font.i = 1; break; | ||||
| 				case '</i>': break; | ||||
| @ -142,16 +142,17 @@ function parse_si(x, opts) { | ||||
| 	if(!x) return null; | ||||
| 	var y; | ||||
| 	/* 18.4.12 t ST_Xstring (Plaintext String) */ | ||||
| 	if(x.match(/^<(?:\w+:)?t[^>]*>/)) { | ||||
| 	// TODO: is whitespace actually valid here?
 | ||||
| 	if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) { | ||||
| 		z.t = utf8read(unescapexml(x.substr(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0])); | ||||
| 		z.r = x; | ||||
| 		z.r = utf8read(x); | ||||
| 		if(html) z.h = z.t; | ||||
| 	} | ||||
| 	/* 18.4.4 r CT_RElt (Rich Text Run) */ | ||||
| 	else if((y = x.match(sirregex))) { | ||||
| 		z.r = x; | ||||
| 		z.r = utf8read(x); | ||||
| 		z.t = utf8read(unescapexml((x.match(sitregex)||[]).join("").replace(tagregex,""))); | ||||
| 		if(html) z.h = parse_rs(x); | ||||
| 		if(html) z.h = parse_rs(z.r); | ||||
| 	} | ||||
| 	/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */ | ||||
| 	/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */ | ||||
| @ -170,7 +171,7 @@ function parse_sst_xml(data/*:string*/, opts)/*:SST*/ { | ||||
| 	if(isval(sst)/*:: && sst*/) { | ||||
| 		ss = sst[2].replace(sstr1,"").split(sstr2); | ||||
| 		for(var i = 0; i != ss.length; ++i) { | ||||
| 			var o = parse_si(ss[i], opts); | ||||
| 			var o = parse_si(ss[i].trim(), opts); | ||||
| 			if(o != null) s[s.length] = o; | ||||
| 		} | ||||
| 		sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount; | ||||
|  | ||||
| @ -5,9 +5,10 @@ var rc_to_a1 = (function(){ | ||||
| 	function rcfunc($$,$1,$2,$3,$4,$5) { | ||||
| 		var R = $3.length>0?parseInt($3,10)|0:0, C = $5.length>0?parseInt($5,10)|0:0; | ||||
| 		if(C<0 && $4.length === 0) C=0; | ||||
| 		if($4.length > 0) C += rcbase.c; | ||||
| 		if($2.length > 0) R += rcbase.r; | ||||
| 		return $1 + encode_col(C) + encode_row(R); | ||||
| 		var cRel = false, rRel = false; | ||||
| 		if($4.length > 0 || $5.length == 0) cRel = true; if(cRel) C += rcbase.c; else --C; | ||||
| 		if($2.length > 0 || $3.length == 0) rRel = true; if(rRel) R += rcbase.r; else --R; | ||||
| 		return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R); | ||||
| 	} | ||||
| 	return function rc_to_a1(fstr, base) { | ||||
| 		rcbase = base; | ||||
| @ -15,3 +16,15 @@ var rc_to_a1 = (function(){ | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| /* TODO actually parse the formula */ | ||||
| function shift_formula_str(f/*:string*/, delta/*:Cell*/)/*:string*/ { | ||||
| 	return f.replace(/(^|[^A-Z0-9])([$]?)([A-Z]+)([$]?)(\d+)/g, function($0, $1, $2, $3, $4, $5, off, str) { | ||||
| 		return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r)); | ||||
| 	}); | ||||
| } | ||||
| 
 | ||||
| function shift_formula_xlsx(f/*:string*/, range/*:string*/, cell/*:string*/)/*:string*/ { | ||||
| 	var r = decode_range(range), s = r.s, c = decode_cell(cell); | ||||
| 	var delta = {r:c.r - s.r, c:c.c - s.c}; | ||||
| 	return shift_formula_str(f, delta); | ||||
| } | ||||
|  | ||||
							
								
								
									
										465
									
								
								bits/62_fxls.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										465
									
								
								bits/62_fxls.js
									
									
									
									
									
								
							| @ -7,17 +7,30 @@ function parseread1(blob, length) { blob.l+=1; return; } | ||||
| 
 | ||||
| /* 2.5.51 */ | ||||
| function parse_ColRelU(blob, length) { | ||||
| 	var c = blob.read_shift(2); | ||||
| 	var c = blob.read_shift(length == 1 ? 1 : 2); | ||||
| 	return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.105 */ | ||||
| function parse_RgceArea(blob, length) { | ||||
| 	var r=blob.read_shift(2), R=blob.read_shift(2); | ||||
| /* [MS-XLS] 2.5.198.105 */ | ||||
| /* [MS-XLSB] 2.5.97.89 */ | ||||
| function parse_RgceArea(blob, length, opts) { | ||||
| 	var w = 2; | ||||
| 	if(opts) { | ||||
| 		if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts); | ||||
| 		else if(opts.biff == 12) w = 4; | ||||
| 	} | ||||
| 	var r=blob.read_shift(w), R=blob.read_shift(w); | ||||
| 	var c=parse_ColRelU(blob, 2); | ||||
| 	var C=parse_ColRelU(blob, 2); | ||||
| 	return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} }; | ||||
| } | ||||
| /* BIFF 2-5 encodes flags in the row field */ | ||||
| function parse_RgceArea_BIFF2(blob, length, opts) { | ||||
| 	var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2); | ||||
| 	var c=blob.read_shift(1); | ||||
| 	var C=blob.read_shift(1); | ||||
| 	return { s:{r:r[0], c:c, cRel:r[1], rRel:r[2]}, e:{r:R[0], c:C, cRel:R[1], rRel:R[2]} }; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.105 TODO */ | ||||
| function parse_RgceAreaRel(blob, length) { | ||||
| @ -28,36 +41,61 @@ function parse_RgceAreaRel(blob, length) { | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.109 */ | ||||
| function parse_RgceLoc(blob, length) { | ||||
| 	var r = blob.read_shift(2); | ||||
| function parse_RgceLoc(blob, length, opts) { | ||||
| 	if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts); | ||||
| 	var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2); | ||||
| 	var c = parse_ColRelU(blob, 2); | ||||
| 	return {r:r, c:c[0], cRel:c[1], rRel:c[2]}; | ||||
| } | ||||
| function parse_RgceLoc_BIFF2(blob, length, opts) { | ||||
| 	var r = parse_ColRelU(blob, 2); | ||||
| 	var c = blob.read_shift(1); | ||||
| 	return {r:r[0], c:c, cRel:r[1], rRel:r[2]}; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.111 */ | ||||
| function parse_RgceLocRel(blob, length) { | ||||
| 	var r = blob.read_shift(2); | ||||
| /* [MS-XLS] 2.5.198.111 TODO */ | ||||
| /* [MS-XLSB] 2.5.97.92 TODO */ | ||||
| function parse_RgceLocRel(blob, length, opts) { | ||||
| 	var biff = opts && opts.biff ? opts.biff : 8; | ||||
| 	if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts); | ||||
| 	var r = blob.read_shift(biff >= 12 ? 4 : 2); | ||||
| 	var cl = blob.read_shift(2); | ||||
| 	var cRel = (cl & 0x8000) >> 15, rRel = (cl & 0x4000) >> 14; | ||||
| 	cl &= 0x3FFF; | ||||
| 	if(cRel !== 0) while(cl >= 0x100) cl -= 0x100; | ||||
| 	if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000; | ||||
| 	if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000; | ||||
| 	return {r:r,c:cl,cRel:cRel,rRel:rRel}; | ||||
| } | ||||
| function parse_RgceLocRel_BIFF2(blob, length) { | ||||
| 	var rl = blob.read_shift(2); | ||||
| 	var c = blob.read_shift(1); | ||||
| 	var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14; | ||||
| 	rl &= 0x3FFF; | ||||
| 	if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000; | ||||
| 	if(cRel == 1 && c >= 0x80) c = c - 0x100; | ||||
| 	return {r:rl,c:c,cRel:cRel,rRel:rRel}; | ||||
| } | ||||
| 
 | ||||
| /* Ptg Tokens */ | ||||
| 
 | ||||
| /* 2.5.198.27 */ | ||||
| function parse_PtgArea(blob, length) { | ||||
| function parse_PtgArea(blob, length, opts) { | ||||
| 	var type = (blob[blob.l++] & 0x60) >> 5; | ||||
| 	var area = parse_RgceArea(blob, 8); | ||||
| 	var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts); | ||||
| 	return [type, area]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.28 */ | ||||
| function parse_PtgArea3d(blob, length) { | ||||
| /* [MS-XLS] 2.5.198.28 */ | ||||
| /* [MS-XLSB] 2.5.97.19 */ | ||||
| function parse_PtgArea3d(blob, length, opts) { | ||||
| 	var type = (blob[blob.l++] & 0x60) >> 5; | ||||
| 	var ixti = blob.read_shift(2); | ||||
| 	var area = parse_RgceArea(blob, 8); | ||||
| 	var ixti = blob.read_shift(2, 'i'); | ||||
| 	var w = 8; | ||||
| 	if(opts) switch(opts.biff) { | ||||
| 		case 5: blob.l += 12; w = 6; break; | ||||
| 		case 12: w = 12; break; | ||||
| 	} | ||||
| 	var area = parse_RgceArea(blob, w, opts); | ||||
| 	return [type, ixti, area]; | ||||
| } | ||||
| 
 | ||||
| @ -68,10 +106,15 @@ function parse_PtgAreaErr(blob, length) { | ||||
| 	return [type]; | ||||
| } | ||||
| /* 2.5.198.30 */ | ||||
| function parse_PtgAreaErr3d(blob, length) { | ||||
| function parse_PtgAreaErr3d(blob, length, opts) { | ||||
| 	var type = (blob[blob.l++] & 0x60) >> 5; | ||||
| 	var ixti = blob.read_shift(2); | ||||
| 	blob.l += 8; | ||||
| 	var w = 8; | ||||
| 	if(opts) switch(opts.biff) { | ||||
| 		case 5: blob.l += 12; w = 6; break; | ||||
| 		case 12: w = 12; break; | ||||
| 	} | ||||
| 	blob.l += w; | ||||
| 	return [type, ixti]; | ||||
| } | ||||
| 
 | ||||
| @ -82,10 +125,11 @@ function parse_PtgAreaN(blob, length) { | ||||
| 	return [type, area]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.32 -- ignore this and look in PtgExtraArray for shape + values */ | ||||
| function parse_PtgArray(blob, length) { | ||||
| /* [MS-XLS] 2.5.198.32 */ | ||||
| /* [MS-XLSB] 2.5.97.23 */ | ||||
| function parse_PtgArray(blob, length, opts) { | ||||
| 	var type = (blob[blob.l++] & 0x60) >> 5; | ||||
| 	blob.l += 7; | ||||
| 	blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7; | ||||
| 	return [type]; | ||||
| } | ||||
| 
 | ||||
| @ -98,33 +142,40 @@ function parse_PtgAttrBaxcel(blob, length) { | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.34 */ | ||||
| function parse_PtgAttrChoose(blob, length) { | ||||
| function parse_PtgAttrChoose(blob, length, opts) { | ||||
| 	blob.l +=2; | ||||
| 	var offset = blob.read_shift(2); | ||||
| 	var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); | ||||
| 	var o = []; | ||||
| 	/* offset is 1 less than the number of elements */ | ||||
| 	for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(2)); | ||||
| 	for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2)); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.35 */ | ||||
| function parse_PtgAttrGoto(blob, length) { | ||||
| function parse_PtgAttrGoto(blob, length, opts) { | ||||
| 	var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0; | ||||
| 	blob.l += 2; | ||||
| 	return [bitGoto, blob.read_shift(2)]; | ||||
| 	return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.36 */ | ||||
| function parse_PtgAttrIf(blob, length) { | ||||
| function parse_PtgAttrIf(blob, length, opts) { | ||||
| 	var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0; | ||||
| 	blob.l += 2; | ||||
| 	return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.97.28 */ | ||||
| function parse_PtgAttrIfError(blob, length) { | ||||
| 	var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0; | ||||
| 	blob.l += 2; | ||||
| 	return [bitIf, blob.read_shift(2)]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.37 */ | ||||
| function parse_PtgAttrSemi(blob, length) { | ||||
| function parse_PtgAttrSemi(blob, length, opts) { | ||||
| 	var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0; | ||||
| 	blob.l += 4; | ||||
| 	blob.l += opts && opts.biff == 2 ? 3 : 4; | ||||
| 	return [bitSemi]; | ||||
| } | ||||
| 
 | ||||
| @ -147,46 +198,44 @@ function parse_PtgAttrSpaceSemi(blob, length) { | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.84 TODO */ | ||||
| function parse_PtgRef(blob, length) { | ||||
| function parse_PtgRef(blob, length, opts) { | ||||
| 	var ptg = blob[blob.l] & 0x1F; | ||||
| 	var type = (blob[blob.l] & 0x60)>>5; | ||||
| 	blob.l += 1; | ||||
| 	var loc = parse_RgceLoc(blob,4); | ||||
| 	var loc = parse_RgceLoc(blob, 0, opts); | ||||
| 	return [type, loc]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.88 TODO */ | ||||
| function parse_PtgRefN(blob, length) { | ||||
| 	var ptg = blob[blob.l] & 0x1F; | ||||
| function parse_PtgRefN(blob, length, opts) { | ||||
| 	var type = (blob[blob.l] & 0x60)>>5; | ||||
| 	blob.l += 1; | ||||
| 	var loc = parse_RgceLocRel(blob,4); | ||||
| 	var loc = parse_RgceLocRel(blob, 0, opts); | ||||
| 	return [type, loc]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.85 TODO */ | ||||
| function parse_PtgRef3d(blob, length) { | ||||
| 	var ptg = blob[blob.l] & 0x1F; | ||||
| function parse_PtgRef3d(blob, length, opts) { | ||||
| 	var type = (blob[blob.l] & 0x60)>>5; | ||||
| 	blob.l += 1; | ||||
| 	var ixti = blob.read_shift(2); // XtiIndex
 | ||||
| 	var loc = parse_RgceLoc(blob,4); | ||||
| 	var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
 | ||||
| 	return [type, ixti, loc]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* 2.5.198.62 TODO */ | ||||
| function parse_PtgFunc(blob, length) { | ||||
| function parse_PtgFunc(blob, length, opts) { | ||||
| 	var ptg = blob[blob.l] & 0x1F; | ||||
| 	var type = (blob[blob.l] & 0x60)>>5; | ||||
| 	blob.l += 1; | ||||
| 	var iftab = blob.read_shift(2); | ||||
| 	return [FtabArgc[iftab], Ftab[iftab]]; | ||||
| 	var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2); | ||||
| 	return [FtabArgc[iftab], Ftab[iftab], type]; | ||||
| } | ||||
| /* 2.5.198.63 TODO */ | ||||
| function parse_PtgFuncVar(blob, length) { | ||||
| function parse_PtgFuncVar(blob, length, opts) { | ||||
| 	blob.l++; | ||||
| 	var cparams = blob.read_shift(1), tab = parsetab(blob); | ||||
| 	var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [0, blob.read_shift(1)]: parsetab(blob); | ||||
| 	return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]]; | ||||
| } | ||||
| 
 | ||||
| @ -195,22 +244,26 @@ function parsetab(blob, length) { | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.41 */ | ||||
| var parse_PtgAttrSum = parseread(4); | ||||
| function parse_PtgAttrSum(blob, length, opts) { | ||||
| 	blob.l += opts && opts.biff == 2 ? 3 : 4; return; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.43 */ | ||||
| var parse_PtgConcat = parseread1; | ||||
| 
 | ||||
| /* 2.5.198.58 */ | ||||
| function parse_PtgExp(blob, length) { | ||||
| function parse_PtgExp(blob, length, opts) { | ||||
| 	blob.l++; | ||||
| 	if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0]; | ||||
| 	var row = blob.read_shift(2); | ||||
| 	var col = blob.read_shift(2); | ||||
| 	var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); | ||||
| 	return [row, col]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.57 */ | ||||
| function parse_PtgErr(blob, length) { blob.l++; return BErr[blob.read_shift(1)]; } | ||||
| 
 | ||||
| /* 2.5.198.66 TODO */ | ||||
| /* 2.5.198.66 */ | ||||
| function parse_PtgInt(blob, length) { blob.l++; return blob.read_shift(2); } | ||||
| 
 | ||||
| /* 2.5.198.42 */ | ||||
| @ -220,12 +273,19 @@ function parse_PtgBool(blob, length) { blob.l++; return blob.read_shift(1)!==0;} | ||||
| function parse_PtgNum(blob, length) { blob.l++; return parse_Xnum(blob, 8); } | ||||
| 
 | ||||
| /* 2.5.198.89 */ | ||||
| function parse_PtgStr(blob, length) { blob.l++; return parse_ShortXLUnicodeString(blob); } | ||||
| function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); } | ||||
| 
 | ||||
| /* 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */ | ||||
| function parse_SerAr(blob) { | ||||
| 	var val = []; | ||||
| 	switch((val[0] = blob.read_shift(1))) { | ||||
| /* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */ | ||||
| /* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */ | ||||
| function parse_SerAr(blob, biff/*:number*/) { | ||||
| 	var val = [blob.read_shift(1)]; | ||||
| 	if(biff == 12) switch(val[0]) { | ||||
| 		case 0x02: val[0] = 0x04; break; /* SerBool */ | ||||
| 		case 0x04: val[0] = 0x10; break; /* SerErr */ | ||||
| 		case 0x00: val[0] = 0x01; break; /* SerNum */ | ||||
| 		case 0x01: val[0] = 0x02; break; /* SerStr */ | ||||
| 	} | ||||
| 	switch(val[0]) { | ||||
| 		/* 2.5.192.113 */ | ||||
| 		case 0x04: /* SerBool -- boolean */ | ||||
| 			val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE'; | ||||
| @ -242,7 +302,7 @@ function parse_SerAr(blob) { | ||||
| 			val[1] = parse_Xnum(blob, 8); break; | ||||
| 		/* 2.5.192.117 */ | ||||
| 		case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */ | ||||
| 			val[1] = parse_XLUnicodeString(blob); break; | ||||
| 			val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break; | ||||
| 		// default: throw "Bad SerAr: " + val[0]; /* Unreachable */
 | ||||
| 	} | ||||
| 	return val; | ||||
| @ -257,49 +317,72 @@ function parse_PtgExtraMem(blob, cce) { | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.59 */ | ||||
| function parse_PtgExtraArray(blob) { | ||||
| 	var cols = 1 + blob.read_shift(1); //DColByteU
 | ||||
| 	var rows = 1 + blob.read_shift(2); //DRw
 | ||||
| function parse_PtgExtraArray(blob, length, opts) { | ||||
| 	var rows = 0, cols = 0; | ||||
| 	if(opts.biff == 12) { | ||||
| 		rows = blob.read_shift(4); // DRw
 | ||||
| 		cols = blob.read_shift(4); // DCol
 | ||||
| 	} else { | ||||
| 		cols = 1 + blob.read_shift(1); //DColByteU
 | ||||
| 		rows = 1 + blob.read_shift(2); //DRw
 | ||||
| 	} | ||||
| 	if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; } | ||||
| 	for(var i = 0, o=[]; i != rows && (o[i] = []); ++i) | ||||
| 		for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob); | ||||
| 		for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.76 */ | ||||
| function parse_PtgName(blob, length) { | ||||
| function parse_PtgName(blob, length, opts) { | ||||
| 	var type = (blob.read_shift(1) >>> 5) & 0x03; | ||||
| 	var nameindex = blob.read_shift(4); | ||||
| 	var w = (!opts || (opts.biff >= 8)) ? 4 : 2; | ||||
| 	var nameindex = blob.read_shift(w); | ||||
| 	switch(opts.biff) { | ||||
| 		case 2: blob.l += 5; break; | ||||
| 		case 3: case 4: blob.l += 8; break; | ||||
| 		case 5: blob.l += 12; break; | ||||
| 	} | ||||
| 	return [type, 0, nameindex]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.77 */ | ||||
| function parse_PtgNameX(blob, length) { | ||||
| function parse_PtgNameX(blob, length, opts) { | ||||
| 	if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts); | ||||
| 	var type = (blob.read_shift(1) >>> 5) & 0x03; | ||||
| 	var ixti = blob.read_shift(2); // XtiIndex
 | ||||
| 	var nameindex = blob.read_shift(4); | ||||
| 	return [type, ixti, nameindex]; | ||||
| } | ||||
| function parse_PtgNameX_BIFF5(blob, length, opts) { | ||||
| 	var type = (blob.read_shift(1) >>> 5) & 0x03; | ||||
| 	var ixti = blob.read_shift(2, 'i'); // XtiIndex
 | ||||
| 	blob.l += 8; | ||||
| 	var nameindex = blob.read_shift(2); | ||||
| 	blob.l += 12; | ||||
| 	return [type, ixti, nameindex]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.70 */ | ||||
| function parse_PtgMemArea(blob, length) { | ||||
| function parse_PtgMemArea(blob, length, opts) { | ||||
| 	var type = (blob.read_shift(1) >>> 5) & 0x03; | ||||
| 	blob.l += 4; | ||||
| 	var cce = blob.read_shift(2); | ||||
| 	blob.l += (opts && opts.biff == 2 ? 3 : 4); | ||||
| 	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); | ||||
| 	return [type, cce]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.72 */ | ||||
| function parse_PtgMemFunc(blob, length) { | ||||
| function parse_PtgMemFunc(blob, length, opts) { | ||||
| 	var type = (blob.read_shift(1) >>> 5) & 0x03; | ||||
| 	var cce = blob.read_shift(2); | ||||
| 	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); | ||||
| 	return [type, cce]; | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| /* 2.5.198.86 */ | ||||
| function parse_PtgRefErr(blob, length) { | ||||
| function parse_PtgRefErr(blob, length, opts) { | ||||
| 	var type = (blob.read_shift(1) >>> 5) & 0x03; | ||||
| 	blob.l += 4; | ||||
| 	if(opts.biff == 12) blob.l += 2; | ||||
| 	return [type]; | ||||
| } | ||||
| 
 | ||||
| @ -425,7 +508,10 @@ var PtgDupes = { | ||||
| }; | ||||
| (function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})(); | ||||
| 
 | ||||
| var Ptg18 = {}; | ||||
| var Ptg18 = { | ||||
| //	/*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList }, // TODO
 | ||||
| //	/*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName }, // TODO
 | ||||
| }; | ||||
| var Ptg19 = { | ||||
| 	/*::[*/0x01/*::]*/: { n:'PtgAttrSemi', f:parse_PtgAttrSemi }, | ||||
| 	/*::[*/0x02/*::]*/: { n:'PtgAttrIf', f:parse_PtgAttrIf }, | ||||
| @ -435,11 +521,13 @@ var Ptg19 = { | ||||
| 	/*::[*/0x20/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel }, | ||||
| 	/*::[*/0x40/*::]*/: { n:'PtgAttrSpace', f:parse_PtgAttrSpace }, | ||||
| 	/*::[*/0x41/*::]*/: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi }, | ||||
| 	/*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError }, | ||||
| 	/*::[*/0xFF/*::]*/: {} | ||||
| }; | ||||
| 
 | ||||
| /* 2.4.127 TODO */ | ||||
| function parse_Formula(blob, length, opts) { | ||||
| 	var end = blob.l + length; | ||||
| 	var cell = parse_XLSCell(blob, 6); | ||||
| 	if(opts.biff == 2) ++blob.l; | ||||
| 	var val = parse_FormulaValue(blob,8); | ||||
| @ -450,10 +538,7 @@ function parse_Formula(blob, length, opts) { | ||||
| 			var chn = blob.read_shift(4); | ||||
| 		} | ||||
| 	} | ||||
| 	var cbf = ""; | ||||
| 	if(opts.biff < 5) blob.l += length-16; | ||||
| 	else if(opts.biff === 5) blob.l += length-20; | ||||
| 	else cbf = parse_XLSCellParsedFormula(blob, length-20, opts); | ||||
| 	var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts); | ||||
| 	return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]}; | ||||
| } | ||||
| 
 | ||||
| @ -472,23 +557,29 @@ function parse_FormulaValue(blob) { | ||||
| 
 | ||||
| /* 2.5.198.103 */ | ||||
| function parse_RgbExtra(blob, length, rgce, opts) { | ||||
| 	if(opts.biff < 8) return parsenoop(blob, length); | ||||
| 	var target = blob.l + length; | ||||
| 	var o = []; | ||||
| 	for(var i = 0; i !== rgce.length; ++i) { | ||||
| 		switch(rgce[i][0]) { | ||||
| 			case 'PtgArray': /* PtgArray -> PtgExtraArray */ | ||||
| 				rgce[i][1] = parse_PtgExtraArray(blob); | ||||
| 				rgce[i][1] = parse_PtgExtraArray(blob, 0, opts); | ||||
| 				o.push(rgce[i][1]); | ||||
| 				break; | ||||
| 			case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */ | ||||
| 				rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1]); | ||||
| 				o.push(rgce[i][2]); | ||||
| 				break; | ||||
| 			case 'PtgExp': /* PtgExp -> PtgExtraCol */ | ||||
| 				if(opts && opts.biff == 12) { | ||||
| 					rgce[i][1][1] = blob.read_shift(4); | ||||
| 					o.push(rgce[i][1]); | ||||
| 				} break; | ||||
| 			default: break; | ||||
| 		} | ||||
| 	} | ||||
| 	length = target - blob.l; | ||||
| 	/* note: this is technically an error but Excel disregards */ | ||||
| 	//if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
 | ||||
| 	if(length !== 0) o.push(parsenoop(blob, length)); | ||||
| 	return o; | ||||
| } | ||||
| @ -496,7 +587,7 @@ function parse_RgbExtra(blob, length, rgce, opts) { | ||||
| /* 2.5.198.21 */ | ||||
| function parse_NameParsedFormula(blob, length, opts, cce) { | ||||
| 	var target = blob.l + length; | ||||
| 	var rgce = parse_Rgce(blob, cce); | ||||
| 	var rgce = parse_Rgce(blob, cce, opts); | ||||
| 	var rgcb; | ||||
| 	if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts); | ||||
| 	return [rgce, rgcb]; | ||||
| @ -504,11 +595,11 @@ function parse_NameParsedFormula(blob, length, opts, cce) { | ||||
| 
 | ||||
| /* 2.5.198.3 TODO */ | ||||
| function parse_XLSCellParsedFormula(blob, length, opts) { | ||||
| 	var target = blob.l + length; | ||||
| 	var rgcb, cce = blob.read_shift(2); // length of rgce
 | ||||
| 	var target = blob.l + length, len = opts.biff == 2 ? 1 : 2; | ||||
| 	var rgcb, cce = blob.read_shift(len); // length of rgce
 | ||||
| 	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)]; | ||||
| 	var rgce = parse_Rgce(blob, cce); | ||||
| 	if(length !== cce + 2) rgcb = parse_RgbExtra(blob, length - cce - 2, rgce, opts); | ||||
| 	var rgce = parse_Rgce(blob, cce, opts); | ||||
| 	if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts); | ||||
| 	return [rgce, rgcb]; | ||||
| } | ||||
| 
 | ||||
| @ -516,7 +607,7 @@ function parse_XLSCellParsedFormula(blob, length, opts) { | ||||
| function parse_SharedParsedFormula(blob, length, opts) { | ||||
| 	var target = blob.l + length; | ||||
| 	var rgcb, cce = blob.read_shift(2); // length of rgce
 | ||||
| 	var rgce = parse_Rgce(blob, cce); | ||||
| 	var rgce = parse_Rgce(blob, cce, opts); | ||||
| 	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)]; | ||||
| 	if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts); | ||||
| 	return [rgce, rgcb]; | ||||
| @ -524,41 +615,71 @@ function parse_SharedParsedFormula(blob, length, opts) { | ||||
| 
 | ||||
| /* 2.5.198.1 TODO */ | ||||
| function parse_ArrayParsedFormula(blob, length, opts, ref) { | ||||
| 	var target = blob.l + length; | ||||
| 	var rgcb, cce = blob.read_shift(2); // length of rgce
 | ||||
| 	var target = blob.l + length, len = opts.biff == 2 ? 1 : 2; | ||||
| 	var rgcb, cce = blob.read_shift(len); // length of rgce
 | ||||
| 	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)]; | ||||
| 	var rgce = parse_Rgce(blob, cce); | ||||
| 	if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts); | ||||
| 	var rgce = parse_Rgce(blob, cce, opts); | ||||
| 	if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts); | ||||
| 	return [rgce, rgcb]; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.198.104 */ | ||||
| function parse_Rgce(blob, length) { | ||||
| var gcnt = 0; | ||||
| function parse_Rgce(blob, length, opts) { | ||||
| 	var target = blob.l + length; | ||||
| 	var R, id, ptgs = []; | ||||
| 	while(target != blob.l) { | ||||
| 		length = target - blob.l; | ||||
| 		id = blob[blob.l]; | ||||
| 		R = PtgTypes[id]; | ||||
| 		//console.log("ptg", id, R)
 | ||||
| 		if(id === 0x18 || id === 0x19) { | ||||
| 			id = blob[blob.l + 1]; | ||||
| 			R = (id === 0x18 ? Ptg18 : Ptg19)[id]; | ||||
| 		} | ||||
| 		if(!R || !R.f) { ptgs.push(parsenoop(blob, length)); } | ||||
| 		else { ptgs.push([R.n, R.f(blob, length)]); } | ||||
| 		else { ptgs.push([R.n, R.f(blob, length, opts)]); } | ||||
| 	} | ||||
| 	return ptgs; | ||||
| } | ||||
| 
 | ||||
| function mapper(x) { return x.map(function f2(y) { return y[1];}).join(",");} | ||||
| function stringify_array(f) { | ||||
| 	var o = []; | ||||
| 	for(var i = 0; i < f.length; ++i) { | ||||
| 		var x = f[i], r = []; | ||||
| 		for(var j = 0; j < x.length; ++j) { | ||||
| 			var y = x[j]; | ||||
| 			if(y) switch(y[0]) { | ||||
| 				// TODO: handle embedded quotes
 | ||||
| 				case 0x02: r.push('"' + y[1].replace(/"/g,'""') + '"'); break; | ||||
| 				default: r.push(y[1]); | ||||
| 			} else r.push(""); | ||||
| 		} | ||||
| 		o.push(r.join(",")); | ||||
| 	} | ||||
| 	return o.join(";"); | ||||
| } | ||||
| 
 | ||||
| /* 2.2.2 + Magic TODO */ | ||||
| /* [MS-XLS] 2.2.2 TODO */ | ||||
| /* [MS-XLSB] 2.2.2 */ | ||||
| var PtgBinOp = { | ||||
| 	PtgAdd: "+", | ||||
| 	PtgConcat: "&", | ||||
| 	PtgDiv: "/", | ||||
| 	PtgEq: "=", | ||||
| 	PtgGe: ">=", | ||||
| 	PtgGt: ">", | ||||
| 	PtgLe: "<=", | ||||
| 	PtgLt: "<", | ||||
| 	PtgMul: "*", | ||||
| 	PtgNe: "<>", | ||||
| 	PtgPower: "^", | ||||
| 	PtgSub: "-" | ||||
| }; | ||||
| function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 	if(opts !== undefined && opts.biff === 5) return "BIFF5??"; | ||||
| 	var _range = range !== undefined ? range : {s:{c:0, r:0}}; | ||||
| 	var stack = [], e1, e2, type, c, ixti, nameidx, r; | ||||
| 	var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}}; | ||||
| 	var stack = [], e1, e2, type, c, ixti, nameidx, r, sname=""; | ||||
| 	if(!formula[0] || !formula[0][0]) return ""; | ||||
| 	var last_sp = -1, sp = ""; | ||||
| 	//console.log("--",cell,formula[0])
 | ||||
| 	for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) { | ||||
| 		var f = formula[0][ff]; | ||||
| @ -573,65 +694,31 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 			case 'PtgPercent': stack.push(stack.pop() + "%"); break; | ||||
| 
 | ||||
| 		/* 2.2.2.1 Binary Value Operator Token */ | ||||
| 			/* 2.5.198.26 */ | ||||
| 			case 'PtgAdd': | ||||
| 			case 'PtgAdd':    /* 2.5.198.26 */ | ||||
| 			case 'PtgConcat': /* 2.5.198.43 */ | ||||
| 			case 'PtgDiv':    /* 2.5.198.45 */ | ||||
| 			case 'PtgEq':     /* 2.5.198.56 */ | ||||
| 			case 'PtgGe':     /* 2.5.198.64 */ | ||||
| 			case 'PtgGt':     /* 2.5.198.65 */ | ||||
| 			case 'PtgLe':     /* 2.5.198.68 */ | ||||
| 			case 'PtgLt':     /* 2.5.198.69 */ | ||||
| 			case 'PtgMul':    /* 2.5.198.75 */ | ||||
| 			case 'PtgNe':     /* 2.5.198.78 */ | ||||
| 			case 'PtgPower':  /* 2.5.198.82 */ | ||||
| 			case 'PtgSub':    /* 2.5.198.90 */ | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"+"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.90 */ | ||||
| 			case 'PtgSub': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"-"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.75 */ | ||||
| 			case 'PtgMul': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"*"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.45 */ | ||||
| 			case 'PtgDiv': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"/"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.82 */ | ||||
| 			case 'PtgPower': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"^"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.43 */ | ||||
| 			case 'PtgConcat': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"&"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.69 */ | ||||
| 			case 'PtgLt': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"<"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.68 */ | ||||
| 			case 'PtgLe': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"<="+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.56 */ | ||||
| 			case 'PtgEq': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"="+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.64 */ | ||||
| 			case 'PtgGe': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+">="+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.65 */ | ||||
| 			case 'PtgGt': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+">"+e1); | ||||
| 				break; | ||||
| 			/* 2.5.198.78 */ | ||||
| 			case 'PtgNe': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+"<>"+e1); | ||||
| 				if(last_sp >= 0) { | ||||
| 					switch(formula[0][last_sp][1][0]) { | ||||
| 						case 0: sp = fill(" ", formula[0][last_sp][1][1]); break; | ||||
| 						case 1: sp = fill("\r", formula[0][last_sp][1][1]); break; | ||||
| 						default: | ||||
| 							sp = ""; | ||||
| 							if(opts.WTF) throw new Error("Unexpected PtgSpace type " + formula[0][last_sp][1][0]); | ||||
| 					} | ||||
| 					e2 = e2 + sp; | ||||
| 					last_sp = -1; | ||||
| 				} | ||||
| 				stack.push(e2+PtgBinOp[f[0]]+e1); | ||||
| 				break; | ||||
| 
 | ||||
| 		/* 2.2.2.1 Binary Reference Operator Token */ | ||||
| @ -644,7 +731,10 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+","+e1); | ||||
| 				break; | ||||
| 			case 'PtgRange': break; | ||||
| 			case 'PtgRange': | ||||
| 				e1 = stack.pop(); e2 = stack.pop(); | ||||
| 				stack.push(e2+":"+e1); | ||||
| 				break; | ||||
| 
 | ||||
| 		/* 2.2.2.3 Control Tokens "can be ignored" */ | ||||
| 			/* 2.5.198.34 */ | ||||
| @ -653,21 +743,24 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 			case 'PtgAttrGoto': break; | ||||
| 			/* 2.5.198.36 */ | ||||
| 			case 'PtgAttrIf': break; | ||||
| 			/* [MS-XLSB] 2.5.97.28 */ | ||||
| 			case 'PtgAttrIfError': break; | ||||
| 
 | ||||
| 
 | ||||
| 			/* 2.5.198.84 */ | ||||
| 			case 'PtgRef': | ||||
| 				type = f[1][0]; c = shift_cell_xls(decode_cell(encode_cell(f[1][1])), _range); | ||||
| 				stack.push(encode_cell(c)); | ||||
| 				type = f[1][0]; c = shift_cell_xls(f[1][1], _range, opts); | ||||
| 				stack.push(encode_cell_xls(c)); | ||||
| 				break; | ||||
| 			/* 2.5.198.88 */ | ||||
| 			case 'PtgRefN': | ||||
| 				type = f[1][0]; c = shift_cell_xls(decode_cell(encode_cell(f[1][1])), cell); | ||||
| 				stack.push(encode_cell(c)); | ||||
| 				type = f[1][0]; c = shift_cell_xls(f[1][1], cell, opts); | ||||
| 				stack.push(encode_cell_xls(c)); | ||||
| 				break; | ||||
| 			case 'PtgRef3d': // TODO: lots of stuff
 | ||||
| 				type = f[1][0]; ixti = f[1][1]; c = shift_cell_xls(f[1][2], _range); | ||||
| 				stack.push(supbooks[1][ixti+1]+"!"+encode_cell(c)); | ||||
| 				type = f[1][0]; ixti = f[1][1]; c = shift_cell_xls(f[1][2], _range, opts); | ||||
| 				sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**"); | ||||
| 				stack.push(sname + "!" + encode_cell(c)); | ||||
| 				break; | ||||
| 
 | ||||
| 		/* Function Call */ | ||||
| @ -675,10 +768,10 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 			case 'PtgFunc': | ||||
| 			/* 2.5.198.63 */ | ||||
| 			case 'PtgFuncVar': | ||||
| 				/* f[1] = [argc, func] */ | ||||
| 				/* f[1] = [argc, func, type] */ | ||||
| 				var argc = f[1][0], func = f[1][1]; | ||||
| 				if(!argc) argc = 0; | ||||
| 				var args = stack.slice(-argc); | ||||
| 				var args = argc == 0 ? [] : stack.slice(-argc); | ||||
| 				stack.length -= argc; | ||||
| 				if(func === 'User') func = args.shift(); | ||||
| 				stack.push(func + "(" + args.join(",") + ")"); | ||||
| @ -697,12 +790,13 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 			/* 2.5.198.27 TODO: fixed points */ | ||||
| 			case 'PtgArea': | ||||
| 				type = f[1][0]; r = shift_range_xls(f[1][1], _range); | ||||
| 				stack.push(encode_range(r)); | ||||
| 				stack.push(encode_range_xls(r)); | ||||
| 				break; | ||||
| 			/* 2.5.198.28 */ | ||||
| 			case 'PtgArea3d': // TODO: lots of stuff
 | ||||
| 				type = f[1][0]; ixti = f[1][1]; r = f[1][2]; | ||||
| 				stack.push(supbooks[1][ixti+1]+"!"+encode_range(r)); | ||||
| 				sname = (supbooks && supbooks[1] ? supbooks[1][ixti+1] : "**MISSING**"); | ||||
| 				stack.push(sname + "!" + encode_range(r)); | ||||
| 				break; | ||||
| 			/* 2.5.198.41 */ | ||||
| 			case 'PtgAttrSum': | ||||
| @ -718,7 +812,7 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 				/* f[1] = type, 0, nameindex */ | ||||
| 				nameidx = f[1][2]; | ||||
| 				var lbl = supbooks[0][nameidx]; | ||||
| 				var name = lbl.Name; | ||||
| 				var name = lbl ? lbl.Name : "**MISSING**" + nameidx; | ||||
| 				if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name]; | ||||
| 				stack.push(name); | ||||
| 				break; | ||||
| @ -728,15 +822,35 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 				/* f[1] = type, ixti, nameindex */ | ||||
| 				var bookidx = f[1][1]; nameidx = f[1][2]; var externbook; | ||||
| 				/* TODO: Properly handle missing values */ | ||||
| 				if(supbooks[bookidx+1]) externbook = supbooks[bookidx+1][nameidx]; | ||||
| 				else if(supbooks[bookidx-1]) externbook = supbooks[bookidx-1][nameidx]; | ||||
| 				//console.log(bookidx, supbooks);
 | ||||
| 				if(opts.biff == 5) { | ||||
| 					if(bookidx < 0) bookidx = -bookidx; | ||||
| 					if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx]; | ||||
| 				} else { | ||||
| 					if(supbooks[bookidx+1]) externbook = supbooks[bookidx+1][nameidx]; | ||||
| 					else if(supbooks[bookidx-1]) externbook = supbooks[bookidx-1][nameidx]; | ||||
| 				} | ||||
| 				if(!externbook) externbook = {body: "??NAMEX??"}; | ||||
| 				stack.push(externbook.body); | ||||
| 				break; | ||||
| 
 | ||||
| 		/* 2.2.2.4 Display Tokens */ | ||||
| 			/* 2.5.198.80 */ | ||||
| 			case 'PtgParen': stack.push('(' + stack.pop() + ')'); break; | ||||
| 			case 'PtgParen': | ||||
| 				var lp = '(', rp = ')'; | ||||
| 				if(last_sp >= 0) { | ||||
| 					sp = ""; | ||||
| 					switch(formula[0][last_sp][1][0]) { | ||||
| 						case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break; | ||||
| 						case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break; | ||||
| 						case 4: rp = fill(" ", formula[0][last_sp][1][1]) + lp; break; | ||||
| 						case 5: rp = fill("\r", formula[0][last_sp][1][1]) + lp; break; | ||||
| 						default: | ||||
| 							if(opts.WTF) throw new Error("Unexpected PtgSpace type " + formula[0][last_sp][1][0]); | ||||
| 					} | ||||
| 					last_sp = -1; | ||||
| 				} | ||||
| 				stack.push(lp + stack.pop() + rp); break; | ||||
| 
 | ||||
| 			/* 2.5.198.86 */ | ||||
| 			case 'PtgRefErr': stack.push('#REF!'); break; | ||||
| @ -758,6 +872,8 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 						if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue; | ||||
| 						if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue; | ||||
| 						stack.push(stringify_formula(e2[1], _range, q, supbooks, opts)); | ||||
| 						fnd = true; | ||||
| 						break; | ||||
| 					} | ||||
| 					if(!fnd) stack.push(f[1]); | ||||
| 				} | ||||
| @ -765,7 +881,7 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 
 | ||||
| 			/* 2.5.198.32 TODO */ | ||||
| 			case 'PtgArray': | ||||
| 				stack.push("{" + f[1].map(mapper).join(";") + "}"); | ||||
| 				stack.push("{" + stringify_array(f[1]) + "}"); | ||||
| 				break; | ||||
| 
 | ||||
| 		/* 2.2.2.5 Mem Tokens */ | ||||
| @ -774,8 +890,11 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 				//stack.push("(" + f[2].map(encode_range).join(",") + ")");
 | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 2.5.198.38 TODO */ | ||||
| 			case 'PtgAttrSpace': break; | ||||
| 			/* 2.5.198.38 */ | ||||
| 			case 'PtgAttrSpace': | ||||
| 			case 'PtgAttrSpaceSemi': | ||||
| 				last_sp = ff; | ||||
| 				break; | ||||
| 
 | ||||
| 			/* 2.5.198.92 TODO */ | ||||
| 			case 'PtgTbl': break; | ||||
| @ -802,9 +921,23 @@ function stringify_formula(formula, range, cell, supbooks, opts) { | ||||
| 
 | ||||
| 			default: throw 'Unrecognized Formula Token: ' + f; | ||||
| 		} | ||||
| 		var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto']; | ||||
| 		if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) { | ||||
| 			f = formula[0][last_sp]; | ||||
| 			switch(f[1][0]) { | ||||
| 				case 0: sp = fill(" ", f[1][1]); break; | ||||
| 				case 1: sp = fill("\r", f[1][1]); break; | ||||
| 				default: | ||||
| 					sp = ""; | ||||
| 					if(opts.WTF) throw new Error("Unexpected PtgSpace type " + f[1][0]); | ||||
| 			} | ||||
| 			stack.push(sp + stack.pop()); | ||||
| 			last_sp = -1; | ||||
| 		} | ||||
| 		//console.log("::",f, stack)
 | ||||
| 	} | ||||
| 	//console.log("--",stack);
 | ||||
| 	if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack"); | ||||
| 	return stack[0]; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,5 +1,18 @@ | ||||
| /* [MS-XLSB] 2.5.97.4 CellParsedFormula TODO: use similar logic to js-xls */ | ||||
| function parse_XLSBCellParsedFormula(data, length) { | ||||
| /* XLSB Parsed Formula records have the same shape */ | ||||
| function parse_XLSBParsedFormula(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var cce = data.read_shift(4); | ||||
| 	return parsenoop(data, length-4); | ||||
| 	var rgce = parse_Rgce(data, cce, opts); | ||||
| 	var cb = data.read_shift(4); | ||||
| 	var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null; | ||||
| 	return [rgce, rgcb]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */ | ||||
| var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula; | ||||
| /* [MS-XLSB] 2.5.97.4 CellParsedFormula */ | ||||
| var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula; | ||||
| /* [MS-XLSB] 2.5.97.12 NameParsedFormula */ | ||||
| var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula; | ||||
| /* [MS-XLSB] 2.5.97.98 SharedParsedFormula */ | ||||
| var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula; | ||||
|  | ||||
							
								
								
									
										121
									
								
								bits/64_ftab.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										121
									
								
								bits/64_ftab.js
									
									
									
									
									
								
							| @ -406,6 +406,7 @@ var Cetab = { | ||||
| }; | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.198.17 */ | ||||
| /* [MS-XLSB] 2.5.97.10 */ | ||||
| var Ftab = { | ||||
| 	/*::[*/0x0000/*::]*/: 'COUNT', | ||||
| 	/*::[*/0x0001/*::]*/: 'IF', | ||||
| @ -779,7 +780,113 @@ var Ftab = { | ||||
| 	/*::[*/0x0178/*::]*/: 'ROUNDBAHTDOWN', | ||||
| 	/*::[*/0x0179/*::]*/: 'ROUNDBAHTUP', | ||||
| 	/*::[*/0x017A/*::]*/: 'THAIYEAR', | ||||
| 	/*::[*/0x017B/*::]*/: 'RTD' | ||||
| 	/*::[*/0x017B/*::]*/: 'RTD', | ||||
| 
 | ||||
| 	/*::[*/0x017C/*::]*/: 'CUBEVALUE', | ||||
| 	/*::[*/0x017D/*::]*/: 'CUBEMEMBER', | ||||
| 	/*::[*/0x017E/*::]*/: 'CUBEMEMBERPROPERTY', | ||||
| 	/*::[*/0x017F/*::]*/: 'CUBERANKEDMEMBER', | ||||
| 	/*::[*/0x0180/*::]*/: 'HEX2BIN', | ||||
| 	/*::[*/0x0181/*::]*/: 'HEX2DEC', | ||||
| 	/*::[*/0x0182/*::]*/: 'HEX2OCT', | ||||
| 	/*::[*/0x0183/*::]*/: 'DEC2BIN', | ||||
| 	/*::[*/0x0184/*::]*/: 'DEC2HEX', | ||||
| 	/*::[*/0x0185/*::]*/: 'DEC2OCT', | ||||
| 	/*::[*/0x0186/*::]*/: 'OCT2BIN', | ||||
| 	/*::[*/0x0187/*::]*/: 'OCT2HEX', | ||||
| 	/*::[*/0x0188/*::]*/: 'OCT2DEC', | ||||
| 	/*::[*/0x0189/*::]*/: 'BIN2DEC', | ||||
| 	/*::[*/0x018A/*::]*/: 'BIN2OCT', | ||||
| 	/*::[*/0x018B/*::]*/: 'BIN2HEX', | ||||
| 	/*::[*/0x018C/*::]*/: 'IMSUB', | ||||
| 	/*::[*/0x018D/*::]*/: 'IMDIV', | ||||
| 	/*::[*/0x018E/*::]*/: 'IMPOWER', | ||||
| 	/*::[*/0x018F/*::]*/: 'IMABS', | ||||
| 	/*::[*/0x0190/*::]*/: 'IMSQRT', | ||||
| 	/*::[*/0x0191/*::]*/: 'IMLN', | ||||
| 	/*::[*/0x0192/*::]*/: 'IMLOG2', | ||||
| 	/*::[*/0x0193/*::]*/: 'IMLOG10', | ||||
| 	/*::[*/0x0194/*::]*/: 'IMSIN', | ||||
| 	/*::[*/0x0195/*::]*/: 'IMCOS', | ||||
| 	/*::[*/0x0196/*::]*/: 'IMEXP', | ||||
| 	/*::[*/0x0197/*::]*/: 'IMARGUMENT', | ||||
| 	/*::[*/0x0198/*::]*/: 'IMCONJUGATE', | ||||
| 	/*::[*/0x0199/*::]*/: 'IMAGINARY', | ||||
| 	/*::[*/0x019A/*::]*/: 'IMREAL', | ||||
| 	/*::[*/0x019B/*::]*/: 'COMPLEX', | ||||
| 	/*::[*/0x019C/*::]*/: 'IMSUM', | ||||
| 	/*::[*/0x019D/*::]*/: 'IMPRODUCT', | ||||
| 	/*::[*/0x019E/*::]*/: 'SERIESSUM', | ||||
| 	/*::[*/0x019F/*::]*/: 'FACTDOUBLE', | ||||
| 	/*::[*/0x01A0/*::]*/: 'SQRTPI', | ||||
| 	/*::[*/0x01A1/*::]*/: 'QUOTIENT', | ||||
| 	/*::[*/0x01A2/*::]*/: 'DELTA', | ||||
| 	/*::[*/0x01A3/*::]*/: 'GESTEP', | ||||
| 	/*::[*/0x01A4/*::]*/: 'ISEVEN', | ||||
| 	/*::[*/0x01A5/*::]*/: 'ISODD', | ||||
| 	/*::[*/0x01A6/*::]*/: 'MROUND', | ||||
| 	/*::[*/0x01A7/*::]*/: 'ERF', | ||||
| 	/*::[*/0x01A8/*::]*/: 'ERFC', | ||||
| 	/*::[*/0x01A9/*::]*/: 'BESSELJ', | ||||
| 	/*::[*/0x01AA/*::]*/: 'BESSELK', | ||||
| 	/*::[*/0x01AB/*::]*/: 'BESSELY', | ||||
| 	/*::[*/0x01AC/*::]*/: 'BESSELI', | ||||
| 	/*::[*/0x01AD/*::]*/: 'XIRR', | ||||
| 	/*::[*/0x01AE/*::]*/: 'XNPV', | ||||
| 	/*::[*/0x01AF/*::]*/: 'PRICEMAT', | ||||
| 	/*::[*/0x01B0/*::]*/: 'YIELDMAT', | ||||
| 	/*::[*/0x01B1/*::]*/: 'INTRATE', | ||||
| 	/*::[*/0x01B2/*::]*/: 'RECEIVED', | ||||
| 	/*::[*/0x01B3/*::]*/: 'DISC', | ||||
| 	/*::[*/0x01B4/*::]*/: 'PRICEDISC', | ||||
| 	/*::[*/0x01B5/*::]*/: 'YIELDDISC', | ||||
| 	/*::[*/0x01B6/*::]*/: 'TBILLEQ', | ||||
| 	/*::[*/0x01B7/*::]*/: 'TBILLPRICE', | ||||
| 	/*::[*/0x01B8/*::]*/: 'TBILLYIELD', | ||||
| 	/*::[*/0x01B9/*::]*/: 'PRICE', | ||||
| 	/*::[*/0x01BA/*::]*/: 'YIELD', | ||||
| 	/*::[*/0x01BB/*::]*/: 'DOLLARDE', | ||||
| 	/*::[*/0x01BC/*::]*/: 'DOLLARFR', | ||||
| 	/*::[*/0x01BD/*::]*/: 'NOMINAL', | ||||
| 	/*::[*/0x01BE/*::]*/: 'EFFECT', | ||||
| 	/*::[*/0x01BF/*::]*/: 'CUMPRINC', | ||||
| 	/*::[*/0x01C0/*::]*/: 'CUMIPMT', | ||||
| 	/*::[*/0x01C1/*::]*/: 'EDATE', | ||||
| 	/*::[*/0x01C2/*::]*/: 'EOMONTH', | ||||
| 	/*::[*/0x01C3/*::]*/: 'YEARFRAC', | ||||
| 	/*::[*/0x01C4/*::]*/: 'COUPDAYBS', | ||||
| 	/*::[*/0x01C5/*::]*/: 'COUPDAYS', | ||||
| 	/*::[*/0x01C6/*::]*/: 'COUPDAYSNC', | ||||
| 	/*::[*/0x01C7/*::]*/: 'COUPNCD', | ||||
| 	/*::[*/0x01C8/*::]*/: 'COUPNUM', | ||||
| 	/*::[*/0x01C9/*::]*/: 'COUPPCD', | ||||
| 	/*::[*/0x01CA/*::]*/: 'DURATION', | ||||
| 	/*::[*/0x01CB/*::]*/: 'MDURATION', | ||||
| 	/*::[*/0x01CC/*::]*/: 'ODDLPRICE', | ||||
| 	/*::[*/0x01CD/*::]*/: 'ODDLYIELD', | ||||
| 	/*::[*/0x01CE/*::]*/: 'ODDFPRICE', | ||||
| 	/*::[*/0x01CF/*::]*/: 'ODDFYIELD', | ||||
| 	/*::[*/0x01D0/*::]*/: 'RANDBETWEEN', | ||||
| 	/*::[*/0x01D1/*::]*/: 'WEEKNUM', | ||||
| 	/*::[*/0x01D2/*::]*/: 'AMORDEGRC', | ||||
| 	/*::[*/0x01D3/*::]*/: 'AMORLINC', | ||||
| 	/*::[*/0x01D4/*::]*/: 'SHEETJS', | ||||
| 	/*::[*/0x01D5/*::]*/: 'ACCRINT', | ||||
| 	/*::[*/0x01D6/*::]*/: 'ACCRINTM', | ||||
| 	/*::[*/0x01D7/*::]*/: 'WORKDAY', | ||||
| 	/*::[*/0x01D8/*::]*/: 'NETWORKDAYS', | ||||
| 	/*::[*/0x01D9/*::]*/: 'GCD', | ||||
| 	/*::[*/0x01DA/*::]*/: 'MULTINOMIAL', | ||||
| 	/*::[*/0x01DB/*::]*/: 'LCM', | ||||
| 	/*::[*/0x01DC/*::]*/: 'FVSCHEDULE', | ||||
| 	/*::[*/0x01DD/*::]*/: 'CUBEKPIMEMBER', | ||||
| 	/*::[*/0x01DE/*::]*/: 'CUBESET', | ||||
| 	/*::[*/0x01DF/*::]*/: 'CUBESETCOUNT', | ||||
| 	/*::[*/0x01E0/*::]*/: 'IFERROR', | ||||
| 	/*::[*/0x01E1/*::]*/: 'COUNTIFS', | ||||
| 	/*::[*/0x01E2/*::]*/: 'SUMIFS', | ||||
| 	/*::[*/0x01E3/*::]*/: 'AVERAGEIF', | ||||
| 	/*::[*/0x01E4/*::]*/: 'AVERAGEIFS' | ||||
| }; | ||||
| var FtabArgc = { | ||||
| 	/*::[*/0x0002/*::]*/: 1, /* ISNA */ | ||||
| @ -788,6 +895,7 @@ var FtabArgc = { | ||||
| 	/*::[*/0x0010/*::]*/: 1, /* COS */ | ||||
| 	/*::[*/0x0011/*::]*/: 1, /* TAN */ | ||||
| 	/*::[*/0x0012/*::]*/: 1, /* ATAN */ | ||||
| 	/*::[*/0x0013/*::]*/: 0, /* PI */ | ||||
| 	/*::[*/0x0014/*::]*/: 1, /* SQRT */ | ||||
| 	/*::[*/0x0015/*::]*/: 1, /* EXP */ | ||||
| 	/*::[*/0x0016/*::]*/: 1, /* LN */ | ||||
| @ -817,6 +925,7 @@ var FtabArgc = { | ||||
| 	/*::[*/0x0043/*::]*/: 1, /* DAY */ | ||||
| 	/*::[*/0x0044/*::]*/: 1, /* MONTH */ | ||||
| 	/*::[*/0x0045/*::]*/: 1, /* YEAR */ | ||||
| 	/*::[*/0x0046/*::]*/: 1, /* WEEKDAY */ | ||||
| 	/*::[*/0x0047/*::]*/: 1, /* HOUR */ | ||||
| 	/*::[*/0x0048/*::]*/: 1, /* MINUTE */ | ||||
| 	/*::[*/0x0049/*::]*/: 1, /* SECOND */ | ||||
| @ -826,11 +935,14 @@ var FtabArgc = { | ||||
| 	/*::[*/0x004F/*::]*/: 2, /* ABSREF */ | ||||
| 	/*::[*/0x0050/*::]*/: 2, /* RELREF */ | ||||
| 	/*::[*/0x0053/*::]*/: 1, /* TRANSPOSE */ | ||||
| 	/*::[*/0x0055/*::]*/: 0, /* STEP */ | ||||
| 	/*::[*/0x0056/*::]*/: 1, /* TYPE */ | ||||
| 	/*::[*/0x005A/*::]*/: 1, /* DEREF */ | ||||
| 	/*::[*/0x0061/*::]*/: 2, /* ATAN2 */ | ||||
| 	/*::[*/0x0062/*::]*/: 1, /* ASIN */ | ||||
| 	/*::[*/0x0063/*::]*/: 1, /* ACOS */ | ||||
| 	/*::[*/0x0065/*::]*/: 3, /* HLOOKUP */ | ||||
| 	/*::[*/0x0066/*::]*/: 3, /* VLOOKUP */ | ||||
| 	/*::[*/0x0069/*::]*/: 1, /* ISREF */ | ||||
| 	/*::[*/0x006F/*::]*/: 1, /* CHAR */ | ||||
| 	/*::[*/0x0070/*::]*/: 1, /* LOWER */ | ||||
| @ -856,6 +968,7 @@ var FtabArgc = { | ||||
| 	/*::[*/0x008D/*::]*/: 1, /* TIMEVALUE */ | ||||
| 	/*::[*/0x008E/*::]*/: 3, /* SLN */ | ||||
| 	/*::[*/0x008F/*::]*/: 4, /* SYD */ | ||||
| 	/*::[*/0x0090/*::]*/: 4, /* DDB */ | ||||
| 	/*::[*/0x00A2/*::]*/: 1, /* CLEAN */ | ||||
| 	/*::[*/0x00A3/*::]*/: 1, /* MDETERM */ | ||||
| 	/*::[*/0x00A4/*::]*/: 1, /* MINVERSE */ | ||||
| @ -871,6 +984,7 @@ var FtabArgc = { | ||||
| 	/*::[*/0x00BE/*::]*/: 1, /* ISNONTEXT */ | ||||
| 	/*::[*/0x00C3/*::]*/: 3, /* DSTDEVP */ | ||||
| 	/*::[*/0x00C4/*::]*/: 3, /* DVARP */ | ||||
| 	/*::[*/0x00C5/*::]*/: 1, /* TRUNC */ | ||||
| 	/*::[*/0x00C6/*::]*/: 1, /* ISLOGICAL */ | ||||
| 	/*::[*/0x00C7/*::]*/: 3, /* DCOUNTA */ | ||||
| 	/*::[*/0x00C9/*::]*/: 1, /* UNREGISTER */ | ||||
| @ -889,6 +1003,7 @@ var FtabArgc = { | ||||
| 	/*::[*/0x00EA/*::]*/: 1, /* ATANH */ | ||||
| 	/*::[*/0x00EB/*::]*/: 3, /* DGET */ | ||||
| 	/*::[*/0x00F4/*::]*/: 1, /* INFO */ | ||||
| 	/*::[*/0x00F7/*::]*/: 4, /* DB */ | ||||
| 	/*::[*/0x00FC/*::]*/: 2, /* FREQUENCY */ | ||||
| 	/*::[*/0x0101/*::]*/: 1, /* EVALUATE */ | ||||
| 	/*::[*/0x0105/*::]*/: 1, /* ERROR.TYPE */ | ||||
| @ -964,9 +1079,13 @@ var FtabArgc = { | ||||
| 	/*::[*/0x0178/*::]*/: 1, /* ROUNDBAHTDOWN */ | ||||
| 	/*::[*/0x0179/*::]*/: 1, /* ROUNDBAHTUP */ | ||||
| 	/*::[*/0x017A/*::]*/: 1, /* THAIYEAR */ | ||||
| 	/*::[*/0x01A0/*::]*/: 1, /* SQRTPI */ | ||||
| 	/*::[*/0x01C1/*::]*/: 2, /* EDATE */ | ||||
| 	/*::[*/0x01C2/*::]*/: 2, /* EOMONTH */ | ||||
| 	/*::[*/0xFFFF/*::]*/: 0 | ||||
| }; | ||||
| /* [MS-XLSX] 2.2.3 Functions */ | ||||
| /* [MS-XLSB] 2.5.97.10 Ftab */ | ||||
| var XLSXFutureFunctions = { | ||||
| 	"_xlfn.ACOT": "ACOT", | ||||
| 	"_xlfn.ACOTH": "ACOTH", | ||||
|  | ||||
| @ -8,10 +8,10 @@ var hlinkregex = /<(?:\w*:)?hyperlink[^>]*\/>/g; | ||||
| var dimregex = /"(\w*:\w*)"/; | ||||
| var colregex = /<(?:\w*:)?col[^>]*\/>/g; | ||||
| /* 18.3 Worksheets */ | ||||
| function parse_ws_xml(data/*:?string*/, opts, rels) { | ||||
| function parse_ws_xml(data/*:?string*/, opts, rels)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| 	/* 18.3.1.99 worksheet CT_Worksheet */ | ||||
| 	var s = {}; | ||||
| 	var s = ({}/*:any*/); | ||||
| 
 | ||||
| 	/* 18.3.1.35 dimension CT_SheetDimension ? */ | ||||
| 	// $FlowIgnore
 | ||||
| @ -166,13 +166,16 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) { | ||||
| var parse_ws_xml_data = (function parse_ws_xml_data_factory() { | ||||
| 	var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/; | ||||
| 	var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/; | ||||
| 	var refregex = /ref=["']([^"']*)["']/; | ||||
| 	var match_v = matchtag("v"), match_f = matchtag("f"); | ||||
| 
 | ||||
| return function parse_ws_xml_data(sdata, s, opts, guess) { | ||||
| 	var ri = 0, x = "", cells = [], cref = [], idx = 0, i=0, cc=0, d="", p/*:any*/; | ||||
| 	var tag, tagr = 0, tagc = 0; | ||||
| 	var sstr; | ||||
| 	var sstr, ftag; | ||||
| 	var fmtid = 0, fillid = 0, do_format = Array.isArray(styles.CellXf), cf; | ||||
| 	var arrayf = []; | ||||
| 	var sharedf = []; | ||||
| 	for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) { | ||||
| 		x = marr[mt].trim(); | ||||
| 		var xlen = x.length; | ||||
| @ -209,10 +212,29 @@ return function parse_ws_xml_data(sdata, s, opts, guess) { | ||||
| 			d = x.substr(i); | ||||
| 			p = ({t:""}/*:any*/); | ||||
| 
 | ||||
| 			// $FlowIgnore
 | ||||
| 			if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]); | ||||
| 			// $FlowIgnore
 | ||||
| 			if(opts.cellFormula && (cref=d.match(match_f))!= null && cref[1] !== '') p.f=unescapexml(cref[1]); | ||||
| 			if((cref=d.match(match_v))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]); | ||||
| 			if(opts.cellFormula) { | ||||
| 				if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') { | ||||
| 					p.f=unescapexml(utf8read(cref[1])); | ||||
| 					if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) { | ||||
| 						p.F = (d.match(refregex)||[])[1]; | ||||
| 						if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]); | ||||
| 					} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) { | ||||
| 						// TODO: parse formula
 | ||||
| 						ftag = parsexmltag(cref[0]); | ||||
| 						sharedf[parseInt(ftag.si, 10)] = [ftag, unescapexml(utf8read(cref[1]))]; | ||||
| 					} | ||||
| 				} else if((cref=d.match(/<f[^>]*\/>/))) { | ||||
| 					ftag = parsexmltag(cref[0]); | ||||
| 					if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][0].ref, tag.r); | ||||
| 				} | ||||
| 				/* TODO: factor out contains logic */ | ||||
| 				var _tag = decode_cell(tag.r); | ||||
| 				for(i = 0; i < arrayf.length; ++i) | ||||
| 					if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r) | ||||
| 						if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c) | ||||
| 							p.F = arrayf[i][1]; | ||||
| 			} | ||||
| 
 | ||||
| 			/* SCHEMA IS ACTUALLY INCORRECT HERE.  IF A CELL HAS NO T, EMIT "" */ | ||||
| 			if(tag.t === undefined && p.v === undefined) { | ||||
|  | ||||
							
								
								
									
										110
									
								
								bits/68_wsbin.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										110
									
								
								bits/68_wsbin.js
									
									
									
									
									
								
							| @ -145,53 +145,65 @@ function write_BrtCellSt(cell, ncell, o) { | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.647 BrtFmlaBool */ | ||||
| function parse_BrtFmlaBool(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var cell = parse_XLSBCell(data); | ||||
| 	cell.r = opts['!row']; | ||||
| 	var value = data.read_shift(1); | ||||
| 	var o = [cell, value, 'b']; | ||||
| 	if(opts.cellFormula) { | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, length-9); | ||||
| 		o[3] = ""; /* TODO */ | ||||
| 		data.l += 2; | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts); | ||||
| 		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */ | ||||
| 	} | ||||
| 	else data.l += length-9; | ||||
| 	else data.l = end; | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.648 BrtFmlaError */ | ||||
| function parse_BrtFmlaError(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var cell = parse_XLSBCell(data); | ||||
| 	cell.r = opts['!row']; | ||||
| 	var value = data.read_shift(1); | ||||
| 	var o = [cell, value, 'e']; | ||||
| 	if(opts.cellFormula) { | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, length-9); | ||||
| 		o[3] = ""; /* TODO */ | ||||
| 		data.l += 2; | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts); | ||||
| 		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */ | ||||
| 	} | ||||
| 	else data.l += length-9; | ||||
| 	else data.l = end; | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.649 BrtFmlaNum */ | ||||
| function parse_BrtFmlaNum(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var cell = parse_XLSBCell(data); | ||||
| 	cell.r = opts['!row']; | ||||
| 	var value = parse_Xnum(data); | ||||
| 	var o = [cell, value, 'n']; | ||||
| 	if(opts.cellFormula) { | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, length - 16); | ||||
| 		o[3] = ""; /* TODO */ | ||||
| 		data.l += 2; | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts); | ||||
| 		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */ | ||||
| 	} | ||||
| 	else data.l += length-16; | ||||
| 	else data.l = end; | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.650 BrtFmlaString */ | ||||
| function parse_BrtFmlaString(data, length, opts) { | ||||
| 	var start = data.l; | ||||
| 	var end = data.l + length; | ||||
| 	var cell = parse_XLSBCell(data); | ||||
| 	cell.r = opts['!row']; | ||||
| 	var value = parse_XLWideString(data); | ||||
| 	var o = [cell, value, 'str']; | ||||
| 	if(opts.cellFormula) { | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, start + length - data.l); | ||||
| 		data.l += 2; | ||||
| 		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts); | ||||
| 		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */ | ||||
| 	} | ||||
| 	else data.l = start + length; | ||||
| 	else data.l = end; | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| @ -210,8 +222,34 @@ function parse_BrtHLink(data, length, opts) { | ||||
| 	return {rfx:rfx, relId:relId, loc:loc, tooltip:tooltip, display:display}; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.6 BrtArrFmla */ | ||||
| function parse_BrtArrFmla(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var rfx = parse_RfX(data, 16); | ||||
| 	var fAlwaysCalc = data.read_shift(1); | ||||
| 	var o = [rfx, null, fAlwaysCalc]; | ||||
| 	if(opts.cellFormula) { | ||||
| 		var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts); | ||||
| 		o[1] = formula; | ||||
| 	} else data.l = end; | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.742 BrtShrFmla */ | ||||
| function parse_BrtShrFmla(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var rfx = parse_UncheckedRfX(data, 16); | ||||
| 	var o = [rfx, null]; | ||||
| 	if(opts.cellFormula) { | ||||
| 		var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts); | ||||
| 		o[1] = formula; | ||||
| 		data.l = end; | ||||
| 	} else data.l = end; | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.61 Worksheet */ | ||||
| function parse_ws_bin(data, opts, rels) { | ||||
| function parse_ws_bin(data, opts, rels, wb)/*:Worksheet*/ { | ||||
| 	if(!data) return data; | ||||
| 	if(!rels) rels = {'!id':{}}; | ||||
| 	var s = {}; | ||||
| @ -222,8 +260,22 @@ function parse_ws_bin(data, opts, rels) { | ||||
| 	var pass = false, end = false; | ||||
| 	var row, p, cf, R, C, addr, sstr, rr; | ||||
| 	var mergecells = []; | ||||
| 	if(!opts) opts = {}; | ||||
| 	opts.biff = 12; | ||||
| 	opts['!row'] = 0; | ||||
| 
 | ||||
| 	var ai = 0, af = false; | ||||
| 
 | ||||
| 	var array_formulae = []; | ||||
| 	var shared_formulae = {}; | ||||
| 	var supbooks = ([[]]/*:any*/); | ||||
| 	supbooks.sharedf = shared_formulae; | ||||
| 	supbooks.arrayf = array_formulae; | ||||
| 	opts.supbooks = supbooks; | ||||
| 
 | ||||
| 	for(var i = 0; i < wb.Names['!names'].length; ++i) supbooks[0][i+1] = wb.Names[wb.Names['!names'][i]]; | ||||
| 
 | ||||
| 	recordhopper(data, function ws_parse(val, Record) { | ||||
| 		//console.log(Record);
 | ||||
| 		if(end) return; | ||||
| 		switch(Record.n) { | ||||
| 			case 'BrtWsDim': ref = val; break; | ||||
| @ -231,6 +283,7 @@ function parse_ws_bin(data, opts, rels) { | ||||
| 				row = val; | ||||
| 				if(opts.sheetRows && opts.sheetRows <= row.r) end=true; | ||||
| 				rr = encode_row(row.r); | ||||
| 				opts['!row'] = row.r; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtFmlaBool': | ||||
| @ -251,9 +304,19 @@ function parse_ws_bin(data, opts, rels) { | ||||
| 					case 'e': p.v = val[1]; p.w = BErr[p.v]; break; | ||||
| 					case 'str': p.t = 's'; p.v = utf8read(val[1]); break; | ||||
| 				} | ||||
| 				if(opts.cellFormula && val.length > 3) p.f = val[3]; | ||||
| 				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.ifmt,null,opts); | ||||
| 				s[encode_col(C=val[0].c) + rr] = p; | ||||
| 				if(opts.cellFormula) { | ||||
| 					af = false; | ||||
| 					for(ai = 0; ai < array_formulae.length; ++ai) { | ||||
| 						var aii = array_formulae[ai]; | ||||
| 						if(row.r >= aii[0].s.r && row.r <= aii[0].e.r) | ||||
| 							if(C >= aii[0].s.c && C <= aii[0].e.c) { | ||||
| 								p.F = encode_range(aii[0]); af = true; | ||||
| 							} | ||||
| 					} | ||||
| 					if(!af && val.length > 3) p.f = val[3]; | ||||
| 				} | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| 				if(refguess.e.r < row.r) refguess.e.r = row.r; | ||||
| @ -288,8 +351,17 @@ function parse_ws_bin(data, opts, rels) { | ||||
| 				} | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtArrFmla': break; // TODO
 | ||||
| 			case 'BrtShrFmla': break; // TODO
 | ||||
| 			case 'BrtArrFmla': if(!opts.cellFormula) break; | ||||
| 				array_formulae.push(val); | ||||
| 				s[encode_col(C) + rr].f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				s[encode_col(C) + rr].F = encode_range(val[0]); | ||||
| 				break; | ||||
| 			case 'BrtShrFmla': if(!opts.cellFormula) break; | ||||
| 				// TODO
 | ||||
| 				shared_formulae[encode_cell(val[0].s)] = val[1]; | ||||
| 				s[encode_col(C) + rr].f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtBeginSheet': break; | ||||
| 			case 'BrtWsProp': break; // TODO
 | ||||
| 			case 'BrtSheetCalcProp': break; // TODO
 | ||||
| @ -400,6 +472,10 @@ function parse_ws_bin(data, opts, rels) { | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + Record.n); | ||||
| 		} | ||||
| 	}, opts); | ||||
| 
 | ||||
| 	delete opts.supbooks; | ||||
| 	delete opts['!row']; | ||||
| 
 | ||||
| 	if(!s["!ref"] && (refguess.s.r < 2000000 || ref && (ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0))) s["!ref"] = encode_range(ref || refguess); | ||||
| 	if(opts.sheetRows && s["!ref"]) { | ||||
| 		var tmpref = safe_decode_range(s["!ref"]); | ||||
|  | ||||
| @ -38,15 +38,43 @@ function parse_BrtFRTArchID$(data, length) { | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.680 BrtName */ | ||||
| function parse_BrtName(data, length, opts) { | ||||
| 	var end = data.l + length; | ||||
| 	var flags = data.read_shift(4); | ||||
| 	var chKey = data.read_shift(1); | ||||
| 	var itab = data.read_shift(4); | ||||
| 	var name = parse_XLNameWideString(data); | ||||
| 	var formula = parse_XLSBNameParsedFormula(data, 0, opts); | ||||
| 	var comment = parse_XLNullableWideString(data); | ||||
| 	if(0 /* fProc */) { | ||||
| 		// unusedstring1: XLNullableWideString
 | ||||
| 		// description: XLNullableWideString
 | ||||
| 		// helpTopic: XLNullableWideString
 | ||||
| 		// unusedstring2: XLNullableWideString
 | ||||
| 	} | ||||
| 	data.l = end; | ||||
| 	return {Name:name, Ptg:formula, Comment:comment}; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.1.7.60 Workbook */ | ||||
| function parse_wb_bin(data, opts) { | ||||
| 	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" }; | ||||
| 	var pass = false, z; | ||||
| 
 | ||||
| 	if(!opts) opts = {}; | ||||
| 	opts.biff = 12; | ||||
| 
 | ||||
| 	var Names = {}, NameList = []; | ||||
| 
 | ||||
| 	recordhopper(data, function hopper_wb(val, R) { | ||||
| 		switch(R.n) { | ||||
| 			case 'BrtBundleSh': wb.Sheets.push(val); break; | ||||
| 
 | ||||
| 			case 'BrtName': | ||||
| 				Names[val.Name] = val; NameList.push(val.Name); | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtBeginBook': break; | ||||
| 			case 'BrtFileVersion': break; | ||||
| 			case 'BrtWbProp14': case 'BrtWbProp': break; | ||||
| @ -68,7 +96,6 @@ function parse_wb_bin(data, opts) { | ||||
| 			case 'BrtSupBookSrc': break; | ||||
| 			case 'BrtExternSheet': break; | ||||
| 			case 'BrtEndExternals': break; | ||||
| 			case 'BrtName': break; | ||||
| 			case 'BrtCalcProp': break; | ||||
| 			case 'BrtUserBookView': break; | ||||
| 			case 'BrtBeginPivotCacheIDs': break; | ||||
| @ -95,10 +122,13 @@ function parse_wb_bin(data, opts) { | ||||
| 			case 'BrtEndBook': break; | ||||
| 			default: if(!pass || opts.WTF) throw new Error("Unexpected record " + R.n); | ||||
| 		} | ||||
| 	}); | ||||
| 	}, opts); | ||||
| 
 | ||||
| 	parse_wb_defaults(wb); | ||||
| 
 | ||||
| 	Names['!names'] = NameList; | ||||
| 	wb.Names = Names; | ||||
| 
 | ||||
| 	return wb; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -3,9 +3,9 @@ function parse_wb(data, name/*:string*/, opts)/*:Workbook*/ { | ||||
| 	return parse_wb_xml((data/*:any*/), opts); | ||||
| } | ||||
| 
 | ||||
| function parse_ws(data, name/*:string*/, opts, rels)/*:Worksheet*/ { | ||||
| 	if(name.substr(name.length-4)===".bin") return parse_ws_bin((data/*:any*/), opts, rels); | ||||
| 	return parse_ws_xml((data/*:any*/), opts, rels); | ||||
| function parse_ws(data, name/*:string*/, opts, rels, wb)/*:Worksheet*/ { | ||||
| 	if(name.substr(name.length-4)===".bin") return parse_ws_bin((data/*:any*/), opts, rels, wb); | ||||
| 	return parse_ws_xml((data/*:any*/), opts, rels, wb); | ||||
| } | ||||
| 
 | ||||
| function parse_sty(data, name/*:string*/, opts) { | ||||
|  | ||||
| @ -82,7 +82,7 @@ function process_style_xlml(styles, stag, opts) { | ||||
| } | ||||
| 
 | ||||
| /* TODO: there must exist some form of OSP-blessed spec */ | ||||
| function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, o)/*:Workbook*/ { | ||||
| function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o)/*:Workbook*/ { | ||||
| 	var nf = "General", sid = cell.StyleID, S = {}; o = o || {}; | ||||
| 	var interiors = []; | ||||
| 	if(sid === undefined && row) sid = row.StyleID; | ||||
| @ -100,7 +100,7 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, o | ||||
| 			break; | ||||
| 		case 'String': | ||||
| 			cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml)); | ||||
| 			cell.v = xml.indexOf("<") > -1 ? ss : cell.r; | ||||
| 			cell.v = xml.indexOf("<") > -1 ? unescapexml(ss) : cell.r; | ||||
| 			break; | ||||
| 		case 'DateTime': | ||||
| 			cell.v = (Date.parse(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000); | ||||
| @ -116,9 +116,24 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, o | ||||
| 		default: cell.t = 's'; cell.v = xlml_fixstr(ss); break; | ||||
| 	} | ||||
| 	safe_format_xlml(cell, nf, o); | ||||
| 	if(o.cellFormula != null && cell.Formula) { | ||||
| 		cell.f = rc_to_a1(unescapexml(cell.Formula), base); | ||||
| 		cell.Formula = undefined; | ||||
| 	if(o.cellFormula != null) { | ||||
| 		if(cell.Formula) { | ||||
| 			var fstr = unescapexml(cell.Formula); | ||||
| 			/* strictly speaking, the leading = is required but some writers omit */ | ||||
| 			if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.substr(1); | ||||
| 			cell.f = rc_to_a1(fstr, base); | ||||
| 			cell.Formula = undefined; | ||||
| 			if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base); | ||||
| 			else if(cell.ArrayRange) { | ||||
| 				cell.F = rc_to_a1(cell.ArrayRange, base); | ||||
| 				arrayf.push([safe_decode_range(cell.F), cell.F]); | ||||
| 			} | ||||
| 		} else { | ||||
| 			for(i = 0; i < arrayf.length; ++i) | ||||
| 				if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r) | ||||
| 					if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c) | ||||
| 						cell.F = arrayf[i][1]; | ||||
| 		} | ||||
| 	} | ||||
| 	if(o.cellStyles) { | ||||
| 		interiors.forEach(function(x) { | ||||
| @ -157,11 +172,12 @@ function parse_xlml_xml(d, opts) { | ||||
| 	var Props = {}, Custprops = {}, pidx = 0, cp = {}; | ||||
| 	var comments = [], comment = {}; | ||||
| 	var cstys = [], csty; | ||||
| 	var arrayf = []; | ||||
| 	xlmlregex.lastIndex = 0; | ||||
| 	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| 		case 'Data': | ||||
| 			if(state[state.length-1][1]) break; | ||||
| 			if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, opts); | ||||
| 			if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts); | ||||
| 			else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; } | ||||
| 			break; | ||||
| 		case 'Cell': | ||||
|  | ||||
| @ -304,7 +304,15 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						default: | ||||
| 							temp_val = ({v:val.val, ixfe:val.cell.ixfe, t:val.tt}/*:any*/); | ||||
| 							temp_val.XF = XFs[temp_val.ixfe]; | ||||
| 							if(options.cellFormula) temp_val.f = "="+stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 							if(options.cellFormula) { | ||||
| 								var _f = val.formula; | ||||
| 								if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') { | ||||
| 									var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1]; | ||||
| 									var _fe = encode_cell({r:_fr, c:_fc}); | ||||
| 									if(shared_formulae[_fe]) temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 									else temp_val.F = (out[_fe] || {}).F; | ||||
| 								} else temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks, opts); | ||||
| 							} | ||||
| 							safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 							addcell(val.cell, temp_val, options); | ||||
| 							last_formula = val; | ||||
| @ -315,7 +323,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						last_formula.val = val; | ||||
| 						temp_val = ({v:last_formula.val, ixfe:last_formula.cell.ixfe, t:'s'}/*:any*/); | ||||
| 						temp_val.XF = XFs[temp_val.ixfe]; | ||||
| 						if(options.cellFormula) temp_val.f = "="+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts); | ||||
| 						if(options.cellFormula) temp_val.f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts); | ||||
| 						safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 						addcell(last_formula.cell, temp_val, options); | ||||
| 						last_formula = null; | ||||
| @ -323,12 +331,19 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				} break; | ||||
| 				case 'Array': { | ||||
| 					array_formulae.push(val); | ||||
| 					if(options.cellFormula && out[last_cell]) { | ||||
| 						out[last_cell].f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts); | ||||
| 						out[last_cell].F = encode_range(val[0]); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 'ShrFmla': { | ||||
| 					if(!cell_valid) break; | ||||
| 					//if(options.cellFormula) out[last_cell].f = stringify_formula(val[0], range, lastcell, supbooks, opts);
 | ||||
| 					/* TODO: capture range */ | ||||
| 					if(last_formula) shared_formulae[encode_cell(last_formula.cell)]= val[0]; | ||||
| 					if(!options.cellFormula) break; | ||||
| 					if(last_cell) { | ||||
| 						/* TODO: capture range */ | ||||
| 						shared_formulae[encode_cell(last_formula.cell)]= val[0]; | ||||
| 						(out[encode_cell(last_formula.cell)]||{}).f = stringify_formula(val[0], range, lastcell, supbooks, opts); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 'LabelSst': | ||||
| 					temp_val=make_cell(sst[val.isst].t, val.ixfe, 's'); | ||||
| @ -336,6 +351,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 					break; | ||||
| 				case 'RString': | ||||
| 				case 'Label': case 'BIFF2STR': | ||||
| 					temp_val=make_cell(val.val, val.ixfe, 's'); | ||||
| 					temp_val.XF = XFs[temp_val.ixfe]; | ||||
| @ -609,14 +625,12 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				/* BIFF5 records */ | ||||
| 				case 'ExternCount': break; | ||||
| 				case 'RString': break; | ||||
| 				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break; | ||||
| 
 | ||||
| 				/* BIFF2-4 records */ | ||||
| 				case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': break; | ||||
| 				case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break; | ||||
| 				case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break; | ||||
| 				case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break; | ||||
| 				case 'Dimension': break; | ||||
| 
 | ||||
| 				/* Miscellaneous */ | ||||
| 				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt': | ||||
|  | ||||
| @ -33,7 +33,7 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x0024/*::]*/: { n:"BrtFRTEnd", f:parsenoop }, | ||||
| 	/*::[*/0x0025/*::]*/: { n:"BrtACBegin", f:parsenoop }, | ||||
| 	/*::[*/0x0026/*::]*/: { n:"BrtACEnd", f:parsenoop }, | ||||
| 	/*::[*/0x0027/*::]*/: { n:"BrtName", f:parsenoop }, | ||||
| 	/*::[*/0x0027/*::]*/: { n:"BrtName", f:parse_BrtName }, | ||||
| 	/*::[*/0x0028/*::]*/: { n:"BrtIndexRowBlock", f:parsenoop }, | ||||
| 	/*::[*/0x002A/*::]*/: { n:"BrtIndexBlock", f:parsenoop }, | ||||
| 	/*::[*/0x002B/*::]*/: { n:"BrtFont", f:parse_BrtFont }, | ||||
| @ -356,8 +356,8 @@ var XLSBRecordEnum = { | ||||
| 	/*::[*/0x01A7/*::]*/: { n:"BrtBeginUserShView", f:parsenoop }, | ||||
| 	/*::[*/0x01A8/*::]*/: { n:"BrtEndUserShView", f:parsenoop }, | ||||
| 	/*::[*/0x01A9/*::]*/: { n:"BrtEndUserShViews", f:parsenoop }, | ||||
| 	/*::[*/0x01AA/*::]*/: { n:"BrtArrFmla", f:parsenoop }, | ||||
| 	/*::[*/0x01AB/*::]*/: { n:"BrtShrFmla", f:parsenoop }, | ||||
| 	/*::[*/0x01AA/*::]*/: { n:"BrtArrFmla", f:parse_BrtArrFmla }, | ||||
| 	/*::[*/0x01AB/*::]*/: { n:"BrtShrFmla", f:parse_BrtShrFmla }, | ||||
| 	/*::[*/0x01AC/*::]*/: { n:"BrtTable", f:parsenoop }, | ||||
| 	/*::[*/0x01AD/*::]*/: { n:"BrtBeginExtConnections", f:parsenoop }, | ||||
| 	/*::[*/0x01AE/*::]*/: { n:"BrtEndExtConnections", f:parsenoop }, | ||||
| @ -1019,6 +1019,7 @@ var XLSRecordEnum = { | ||||
| 	/*::[*/0x0203/*::]*/: { n:"Number", f:parse_Number }, | ||||
| 	/*::[*/0x0204/*::]*/: { n:"Label", f:parse_Label }, | ||||
| 	/*::[*/0x0205/*::]*/: { n:"BoolErr", f:parse_BoolErr }, | ||||
| 	/*::[*/0x0206/*::]*/: { n:"Formula", f:parse_Formula }, | ||||
| 	/*::[*/0x0207/*::]*/: { n:"String", f:parse_String }, | ||||
| 	/*::[*/0x0208/*::]*/: { n:'Row', f:parse_Row }, | ||||
| 	/*::[*/0x020b/*::]*/: { n:"Index", f:parse_Index }, | ||||
| @ -1028,6 +1029,7 @@ var XLSRecordEnum = { | ||||
| 	/*::[*/0x023e/*::]*/: { n:"Window2", f:parse_Window2 }, | ||||
| 	/*::[*/0x027e/*::]*/: { n:"RK", f:parse_RK }, | ||||
| 	/*::[*/0x0293/*::]*/: { n:"Style", f:parse_Style }, | ||||
| 	/*::[*/0x0406/*::]*/: { n:"Formula", f:parse_Formula }, | ||||
| 	/*::[*/0x0418/*::]*/: { n:"BigName", f:parse_BigName }, | ||||
| 	/*::[*/0x041e/*::]*/: { n:"Format", f:parse_Format }, | ||||
| 	/*::[*/0x043c/*::]*/: { n:"ContinueBigName", f:parse_ContinueBigName }, | ||||
| @ -1184,7 +1186,7 @@ var XLSRecordEnum = { | ||||
| 	/*::[*/0x1068/*::]*/: { n:"Fbi2", f:parse_Fbi2 }, | ||||
| 
 | ||||
| 	/* These are specified in an older version of the spec */ | ||||
| 	/*::[*/0x0000/*::]*/: { n:"Dimension", f:parsenoop }, | ||||
| 	/*::[*/0x0000/*::]*/: { n:"Dimensions", f:parse_Dimensions }, | ||||
| 	/*::[*/0x0002/*::]*/: { n:"BIFF2INT", f:parse_BIFF2INT }, | ||||
| 	/*::[*/0x0005/*::]*/: { n:"BoolErr", f:parse_BoolErr }, | ||||
| 	/*::[*/0x0007/*::]*/: { n:"String", f:parse_BIFF2STRING }, | ||||
| @ -1193,6 +1195,7 @@ var XLSRecordEnum = { | ||||
| 	/*::[*/0x001e/*::]*/: { n:"BIFF2FORMAT", f:parse_BIFF2Format }, | ||||
| 	/*::[*/0x001f/*::]*/: { n:"BIFF2FMTCNT", f:parsenoop }, /* 16-bit cnt of BIFF2FORMAT records */ | ||||
| 	/*::[*/0x0016/*::]*/: { n:"ExternCount", f:parsenoop }, | ||||
| 	/*::[*/0x0021/*::]*/: { n:"Array", f:parse_Array }, | ||||
| 	/*::[*/0x0025/*::]*/: { n:"DefaultRowHeight", f:parse_DefaultRowHeight }, | ||||
| 	/*::[*/0x0032/*::]*/: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA }, | ||||
| 	/*::[*/0x003e/*::]*/: { n:"BIFF2WINDOW2", f:parsenoop }, | ||||
| @ -1212,7 +1215,7 @@ var XLSRecordEnum = { | ||||
| 	/*::[*/0x00bc/*::]*/: { n:"ShrFmla", f:parsenoop }, /* Not necessarily same as 0x04bc */ | ||||
| 	/*::[*/0x00c2/*::]*/: { n:"AddMenu", f:parsenoop }, | ||||
| 	/*::[*/0x00c3/*::]*/: { n:"DelMenu", f:parsenoop }, | ||||
| 	/*::[*/0x00d6/*::]*/: { n:"RString", f:parsenoop }, | ||||
| 	/*::[*/0x00d6/*::]*/: { n:"RString", f:parse_RString }, | ||||
| 	/*::[*/0x00df/*::]*/: { n:"UDDesc", f:parsenoop }, | ||||
| 	/*::[*/0x00ea/*::]*/: { n:"TabIdConf", f:parsenoop }, | ||||
| 	/*::[*/0x0162/*::]*/: { n:"XL5Modify", f:parsenoop }, | ||||
| @ -1221,7 +1224,6 @@ var XLSRecordEnum = { | ||||
| 	/*::[*/0x0218/*::]*/: { n:"Lbl", f:parse_Lbl }, | ||||
| 	/*::[*/0x0223/*::]*/: { n:"ExternName", f:parse_ExternName }, | ||||
| 	/*::[*/0x0231/*::]*/: { n:"Font", f:parsenoop }, | ||||
| 	/*::[*/0x0406/*::]*/: { n:"Formula", f:parse_Formula }, | ||||
| 	/*::[*/0x0409/*::]*/: { n:'BOF', f:parse_BOF }, | ||||
| 	/*::[*/0x086d/*::]*/: { n:"FeatInfo", f:parsenoop }, | ||||
| 	/*::[*/0x0873/*::]*/: { n:"FeatInfo11", f:parsenoop }, | ||||
|  | ||||
| @ -6,10 +6,10 @@ function safe_parse_wbrels(wbrels, sheets) { | ||||
| 	return !wbrels || wbrels.length === 0 ? null : wbrels; | ||||
| } | ||||
| 
 | ||||
| function safe_parse_ws(zip, path/*:string*/, relsPath/*:string*/, sheet, sheetRels, sheets, opts) { | ||||
| function safe_parse_ws(zip, path/*:string*/, relsPath/*:string*/, sheet, sheetRels, sheets, opts, wb) { | ||||
| 	try { | ||||
| 		sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path); | ||||
| 		sheets[sheet]=parse_ws(getzipdata(zip, path),path,opts,sheetRels[sheet]); | ||||
| 		sheets[sheet]=parse_ws(getzipdata(zip, path),path,opts,sheetRels[sheet], wb); | ||||
| 	} catch(e) { if(opts.WTF) throw e; } | ||||
| } | ||||
| 
 | ||||
| @ -110,7 +110,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 			path = path.replace(/sheet0\./,"sheet."); | ||||
| 		} | ||||
| 		relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels"); | ||||
| 		safe_parse_ws(zip, path, relsPath, props.SheetNames[i], sheetRels, sheets, opts); | ||||
| 		safe_parse_ws(zip, path, relsPath, props.SheetNames[i], sheetRels, sheets, opts, wb); | ||||
| 	} | ||||
| 
 | ||||
| 	if(dir.comments) parse_comments(zip, dir.comments, sheets, sheetRels, opts); | ||||
|  | ||||
| @ -156,11 +156,11 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| } | ||||
| var make_csv = sheet_to_csv; | ||||
| 
 | ||||
| function sheet_to_formulae(sheet/*:Worksheet*/) { | ||||
| 	var cmds, y = "", x, val=""; | ||||
| 	if(sheet == null || sheet["!ref"] == null) return ""; | ||||
| function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ { | ||||
| 	var y = "", x, val=""; | ||||
| 	if(sheet == null || sheet["!ref"] == null) return []; | ||||
| 	var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C; | ||||
| 	cmds = new Array((r.e.r-r.s.r+1)*(r.e.c-r.s.c+1)); | ||||
| 	var cmds = new Array((r.e.r-r.s.r+1)*(r.e.c-r.s.c+1)); | ||||
| 	var i = 0; | ||||
| 	for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C); | ||||
| 	for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| @ -170,9 +170,18 @@ function sheet_to_formulae(sheet/*:Worksheet*/) { | ||||
| 			x = sheet[y]; | ||||
| 			val = ""; | ||||
| 			if(x === undefined) continue; | ||||
| 			else if(x.F != null) { | ||||
| 				y = x.F; | ||||
| 				if(!x.f) continue; | ||||
| 				val = x.f; | ||||
| 				if(y.indexOf(":") == -1) y = y + ":" + y; | ||||
| 			} | ||||
| 			if(x.f != null) val = x.f; | ||||
| 			else if(x.t == 'n' && x.v != null) val = "" + x.v; | ||||
| 			else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE"; | ||||
| 			else if(x.w !== undefined) val = "'" + x.w; | ||||
| 			else if(x.v === undefined) continue; | ||||
| 			else if(x.t == 's') val = "'" + x.v; | ||||
| 			else val = ""+x.v; | ||||
| 			cmds[i++] = y + "=" + val; | ||||
| 		} | ||||
|  | ||||
							
								
								
									
										52
									
								
								dist/ods.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										52
									
								
								dist/ods.js
									
									
									
									
										vendored
									
									
								
							| @ -239,6 +239,17 @@ var utf8read = function utf8reada(orig) { | ||||
| 	} | ||||
| 	return out; | ||||
| }; | ||||
| /* Part 3 TODO: actually parse formulae */ | ||||
| function ods_to_csf_formula(f) { | ||||
| 	if(f.substr(0,3) == "of:") f = f.substr(3); | ||||
| 	/* 5.2 Basic Expressions */ | ||||
| 	if(f.charCodeAt(0) == 61) { | ||||
| 		f = f.substr(1); | ||||
| 		if(f.charCodeAt(0) == 61) f = f.substr(1); | ||||
| 	} | ||||
| 	/* Part 3 Section 5.8 References */ | ||||
| 	return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, ""); | ||||
| } | ||||
| var parse_content_xml = (function() { | ||||
| 
 | ||||
| 	var number_formats = { | ||||
| @ -266,7 +277,9 @@ var parse_content_xml = (function() { | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| 		var number_format_map = {}; | ||||
| 		var merges = [], mrange = {}, mR = 0, mC = 0; | ||||
| 		var rept = 1; | ||||
| 		var arrayf = []; | ||||
| 		var rept = 1, isstub = false; | ||||
| 		var i = 0; | ||||
| 		xlmlregex.lastIndex = 0; | ||||
| 		while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| 
 | ||||
| @ -305,7 +318,21 @@ var parse_content_xml = (function() { | ||||
| 					if(C < range.s.c) range.s.c = C; | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					q = {t:ctag['value-type'], v:null}; | ||||
| 					q = ({t:ctag['value-type'], v:null}); | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| 							mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0; | ||||
| 							mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0; | ||||
| 							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; | ||||
| 							q.F = get_utils().encode_range(mrange); | ||||
| 							arrayf.push([mrange, q.F]); | ||||
| 						} | ||||
| 						if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula); | ||||
| 						else for(i = 0; i < arrayf.length; ++i) | ||||
| 							if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r) | ||||
| 								if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c) | ||||
| 									q.F = arrayf[i][1]; | ||||
| 					} | ||||
| 					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) { | ||||
| 						mR = parseInt(ctag['number-rows-spanned'],10) || 0; | ||||
| 						mC = parseInt(ctag['number-columns-spanned'],10) || 0; | ||||
| @ -331,13 +358,19 @@ var parse_content_xml = (function() { | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| 					if(q.t === 's') q.v = textp || ''; | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 						ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 						while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 						if(range.e.c <= C) range.e.c = C; | ||||
| 					isstub = false; | ||||
| 					if(q.t === 's') { | ||||
| 						q.v = textp || ''; | ||||
| 						isstub = textpidx == 0; | ||||
| 					} | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!isstub || opts.cellStubs) { | ||||
| 						if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 							ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 							while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 							if(range.e.c <= C) range.e.c = C; | ||||
| 						} | ||||
| 					} else { C += rept; rept = 0; } | ||||
| 					q = {}; | ||||
| 					textp = ""; | ||||
| 				} | ||||
| @ -364,6 +397,7 @@ var parse_content_xml = (function() { | ||||
| 			case 'annotation': // 14.1 <office:annotation>
 | ||||
| 				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]); | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'number-style': // 16.27.2 <number:number-style>
 | ||||
| @ -616,7 +650,7 @@ var zip = new jszip(); | ||||
| 	f = "mimetype"; | ||||
| 	zip.file(f, "application/vnd.oasis.opendocument.spreadsheet"); | ||||
| 
 | ||||
| 	/* Part 2 Section 2.2 Documents */ | ||||
| 	/* Part 1 Section 2.2 Documents */ | ||||
| 	f = "content.xml"; | ||||
| 	zip.file(f, write_content_xml(wb, opts)); | ||||
| 	manifest.push([f, "text/xml"]); | ||||
|  | ||||
							
								
								
									
										2
									
								
								dist/ods.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/ods.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/ods.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/ods.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										21
									
								
								dist/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										21
									
								
								dist/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.core.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										22
									
								
								dist/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								dist/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.full.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										1052
									
								
								dist/xlsx.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1052
									
								
								dist/xlsx.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
							
								
								
									
										20
									
								
								dist/xlsx.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										20
									
								
								dist/xlsx.min.js
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										2
									
								
								dist/xlsx.min.map
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										2
									
								
								dist/xlsx.min.map
									
									
									
									
										vendored
									
									
								
							
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							
							
								
								
									
										54
									
								
								ods.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										54
									
								
								ods.flow.js
									
									
									
									
									
								
							| @ -241,6 +241,17 @@ var utf8read = function utf8reada(orig) { | ||||
| 	} | ||||
| 	return out; | ||||
| }; | ||||
| /* Part 3 TODO: actually parse formulae */ | ||||
| function ods_to_csf_formula(f/*:string*/)/*:string*/ { | ||||
| 	if(f.substr(0,3) == "of:") f = f.substr(3); | ||||
| 	/* 5.2 Basic Expressions */ | ||||
| 	if(f.charCodeAt(0) == 61) { | ||||
| 		f = f.substr(1); | ||||
| 		if(f.charCodeAt(0) == 61) f = f.substr(1); | ||||
| 	} | ||||
| 	/* Part 3 Section 5.8 References */ | ||||
| 	return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, ""); | ||||
| } | ||||
| var parse_content_xml = (function() { | ||||
| 
 | ||||
| 	var number_formats = { | ||||
| @ -262,13 +273,15 @@ var parse_content_xml = (function() { | ||||
| 		var NFtag = {name:""}, NF = "", pidx = 0; | ||||
| 		var sheetag/*:: = {name:""}*/; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {}; | ||||
| 		var Rn, q/*:: = {t:"", v:null, z:null, w:""}*/; | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/; | ||||
| 		var ctag = {value:""}; | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/; | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| 		var number_format_map = {}; | ||||
| 		var merges = [], mrange = {}, mR = 0, mC = 0; | ||||
| 		var rept = 1; | ||||
| 		var arrayf = []; | ||||
| 		var rept = 1, isstub = false; | ||||
| 		var i = 0; | ||||
| 		xlmlregex.lastIndex = 0; | ||||
| 		while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| 
 | ||||
| @ -307,7 +320,21 @@ var parse_content_xml = (function() { | ||||
| 					if(C < range.s.c) range.s.c = C; | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					q = {t:ctag['value-type'], v:null/*:: , z:null, w:""*/}; | ||||
| 					q = ({t:ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/); | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| 							mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0; | ||||
| 							mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0; | ||||
| 							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; | ||||
| 							q.F = get_utils().encode_range(mrange); | ||||
| 							arrayf.push([mrange, q.F]); | ||||
| 						} | ||||
| 						if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula); | ||||
| 						else for(i = 0; i < arrayf.length; ++i) | ||||
| 							if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r) | ||||
| 								if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c) | ||||
| 									q.F = arrayf[i][1]; | ||||
| 					} | ||||
| 					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) { | ||||
| 						mR = parseInt(ctag['number-rows-spanned'],10) || 0; | ||||
| 						mC = parseInt(ctag['number-columns-spanned'],10) || 0; | ||||
| @ -333,13 +360,19 @@ var parse_content_xml = (function() { | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| 					if(q.t === 's') q.v = textp || ''; | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 						ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 						while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 						if(range.e.c <= C) range.e.c = C; | ||||
| 					isstub = false; | ||||
| 					if(q.t === 's') { | ||||
| 						q.v = textp || ''; | ||||
| 						isstub = textpidx == 0; | ||||
| 					} | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!isstub || opts.cellStubs) { | ||||
| 						if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 							ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 							while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 							if(range.e.c <= C) range.e.c = C; | ||||
| 						} | ||||
| 					} else { C += rept; rept = 0; } | ||||
| 					q = {/*:: t:"", v:null, z:null, w:""*/}; | ||||
| 					textp = ""; | ||||
| 				} | ||||
| @ -366,6 +399,7 @@ var parse_content_xml = (function() { | ||||
| 			case 'annotation': // 14.1 <office:annotation>
 | ||||
| 				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]); | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'number-style': // 16.27.2 <number:number-style>
 | ||||
| @ -619,7 +653,7 @@ function write_ods(wb/*:any*/, opts/*:any*/) { | ||||
| 	f = "mimetype"; | ||||
| 	zip.file(f, "application/vnd.oasis.opendocument.spreadsheet"); | ||||
| 
 | ||||
| 	/* Part 2 Section 2.2 Documents */ | ||||
| 	/* Part 1 Section 2.2 Documents */ | ||||
| 	f = "content.xml"; | ||||
| 	zip.file(f, write_content_xml(wb, opts)); | ||||
| 	manifest.push([f, "text/xml"]); | ||||
|  | ||||
							
								
								
									
										52
									
								
								ods.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										52
									
								
								ods.js
									
									
									
									
									
								
							| @ -239,6 +239,17 @@ var utf8read = function utf8reada(orig) { | ||||
| 	} | ||||
| 	return out; | ||||
| }; | ||||
| /* Part 3 TODO: actually parse formulae */ | ||||
| function ods_to_csf_formula(f) { | ||||
| 	if(f.substr(0,3) == "of:") f = f.substr(3); | ||||
| 	/* 5.2 Basic Expressions */ | ||||
| 	if(f.charCodeAt(0) == 61) { | ||||
| 		f = f.substr(1); | ||||
| 		if(f.charCodeAt(0) == 61) f = f.substr(1); | ||||
| 	} | ||||
| 	/* Part 3 Section 5.8 References */ | ||||
| 	return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, ""); | ||||
| } | ||||
| var parse_content_xml = (function() { | ||||
| 
 | ||||
| 	var number_formats = { | ||||
| @ -266,7 +277,9 @@ var parse_content_xml = (function() { | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| 		var number_format_map = {}; | ||||
| 		var merges = [], mrange = {}, mR = 0, mC = 0; | ||||
| 		var rept = 1; | ||||
| 		var arrayf = []; | ||||
| 		var rept = 1, isstub = false; | ||||
| 		var i = 0; | ||||
| 		xlmlregex.lastIndex = 0; | ||||
| 		while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| 
 | ||||
| @ -305,7 +318,21 @@ var parse_content_xml = (function() { | ||||
| 					if(C < range.s.c) range.s.c = C; | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					q = {t:ctag['value-type'], v:null}; | ||||
| 					q = ({t:ctag['value-type'], v:null}); | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| 							mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0; | ||||
| 							mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0; | ||||
| 							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; | ||||
| 							q.F = get_utils().encode_range(mrange); | ||||
| 							arrayf.push([mrange, q.F]); | ||||
| 						} | ||||
| 						if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula); | ||||
| 						else for(i = 0; i < arrayf.length; ++i) | ||||
| 							if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r) | ||||
| 								if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c) | ||||
| 									q.F = arrayf[i][1]; | ||||
| 					} | ||||
| 					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) { | ||||
| 						mR = parseInt(ctag['number-rows-spanned'],10) || 0; | ||||
| 						mC = parseInt(ctag['number-columns-spanned'],10) || 0; | ||||
| @ -331,13 +358,19 @@ var parse_content_xml = (function() { | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| 					if(q.t === 's') q.v = textp || ''; | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 						ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 						while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 						if(range.e.c <= C) range.e.c = C; | ||||
| 					isstub = false; | ||||
| 					if(q.t === 's') { | ||||
| 						q.v = textp || ''; | ||||
| 						isstub = textpidx == 0; | ||||
| 					} | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!isstub || opts.cellStubs) { | ||||
| 						if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 							ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 							while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 							if(range.e.c <= C) range.e.c = C; | ||||
| 						} | ||||
| 					} else { C += rept; rept = 0; } | ||||
| 					q = {}; | ||||
| 					textp = ""; | ||||
| 				} | ||||
| @ -364,6 +397,7 @@ var parse_content_xml = (function() { | ||||
| 			case 'annotation': // 14.1 <office:annotation>
 | ||||
| 				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]); | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'number-style': // 16.27.2 <number:number-style>
 | ||||
| @ -616,7 +650,7 @@ var zip = new jszip(); | ||||
| 	f = "mimetype"; | ||||
| 	zip.file(f, "application/vnd.oasis.opendocument.spreadsheet"); | ||||
| 
 | ||||
| 	/* Part 2 Section 2.2 Documents */ | ||||
| 	/* Part 1 Section 2.2 Documents */ | ||||
| 	f = "content.xml"; | ||||
| 	zip.file(f, write_content_xml(wb, opts)); | ||||
| 	manifest.push([f, "text/xml"]); | ||||
|  | ||||
							
								
								
									
										11
									
								
								odsbits/50_formula.js
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										11
									
								
								odsbits/50_formula.js
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,11 @@ | ||||
| /* Part 3 TODO: actually parse formulae */ | ||||
| function ods_to_csf_formula(f/*:string*/)/*:string*/ { | ||||
| 	if(f.substr(0,3) == "of:") f = f.substr(3); | ||||
| 	/* 5.2 Basic Expressions */ | ||||
| 	if(f.charCodeAt(0) == 61) { | ||||
| 		f = f.substr(1); | ||||
| 		if(f.charCodeAt(0) == 61) f = f.substr(1); | ||||
| 	} | ||||
| 	/* Part 3 Section 5.8 References */ | ||||
| 	return f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, "$1").replace(/\./g, ""); | ||||
| } | ||||
| @ -19,13 +19,15 @@ var parse_content_xml = (function() { | ||||
| 		var NFtag = {name:""}, NF = "", pidx = 0; | ||||
| 		var sheetag/*:: = {name:""}*/; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {}; | ||||
| 		var Rn, q/*:: = {t:"", v:null, z:null, w:""}*/; | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/; | ||||
| 		var ctag = {value:""}; | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/; | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| 		var number_format_map = {}; | ||||
| 		var merges = [], mrange = {}, mR = 0, mC = 0; | ||||
| 		var rept = 1; | ||||
| 		var arrayf = []; | ||||
| 		var rept = 1, isstub = false; | ||||
| 		var i = 0; | ||||
| 		xlmlregex.lastIndex = 0; | ||||
| 		while((Rn = xlmlregex.exec(str))) switch(Rn[3]) { | ||||
| 
 | ||||
| @ -64,7 +66,21 @@ var parse_content_xml = (function() { | ||||
| 					if(C < range.s.c) range.s.c = C; | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					q = {t:ctag['value-type'], v:null/*:: , z:null, w:""*/}; | ||||
| 					q = ({t:ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/); | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| 							mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0; | ||||
| 							mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0; | ||||
| 							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}}; | ||||
| 							q.F = get_utils().encode_range(mrange); | ||||
| 							arrayf.push([mrange, q.F]); | ||||
| 						} | ||||
| 						if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula); | ||||
| 						else for(i = 0; i < arrayf.length; ++i) | ||||
| 							if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r) | ||||
| 								if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c) | ||||
| 									q.F = arrayf[i][1]; | ||||
| 					} | ||||
| 					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) { | ||||
| 						mR = parseInt(ctag['number-rows-spanned'],10) || 0; | ||||
| 						mC = parseInt(ctag['number-columns-spanned'],10) || 0; | ||||
| @ -90,13 +106,19 @@ var parse_content_xml = (function() { | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| 					if(q.t === 's') q.v = textp || ''; | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 						ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 						while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 						if(range.e.c <= C) range.e.c = C; | ||||
| 					isstub = false; | ||||
| 					if(q.t === 's') { | ||||
| 						q.v = textp || ''; | ||||
| 						isstub = textpidx == 0; | ||||
| 					} | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!isstub || opts.cellStubs) { | ||||
| 						if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 							ws[get_utils().encode_cell({r:R,c:C})] = q; | ||||
| 							while(--rept > 0) ws[get_utils().encode_cell({r:R,c:++C})] = dup(q); | ||||
| 							if(range.e.c <= C) range.e.c = C; | ||||
| 						} | ||||
| 					} else { C += rept; rept = 0; } | ||||
| 					q = {/*:: t:"", v:null, z:null, w:""*/}; | ||||
| 					textp = ""; | ||||
| 				} | ||||
| @ -123,6 +145,7 @@ var parse_content_xml = (function() { | ||||
| 			case 'annotation': // 14.1 <office:annotation>
 | ||||
| 				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]); | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'number-style': // 16.27.2 <number:number-style>
 | ||||
|  | ||||
| @ -10,7 +10,7 @@ function write_ods(wb/*:any*/, opts/*:any*/) { | ||||
| 	f = "mimetype"; | ||||
| 	zip.file(f, "application/vnd.oasis.opendocument.spreadsheet"); | ||||
| 
 | ||||
| 	/* Part 2 Section 2.2 Documents */ | ||||
| 	/* Part 1 Section 2.2 Documents */ | ||||
| 	f = "content.xml"; | ||||
| 	zip.file(f, write_content_xml(wb, opts)); | ||||
| 	manifest.push([f, "text/xml"]); | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
| 	"name": "xlsx", | ||||
| 	"version": "0.8.3", | ||||
| 	"version": "0.8.4", | ||||
| 	"author": "sheetjs", | ||||
| 	"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS spreadsheet parser and writer", | ||||
| 	"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ], | ||||
|  | ||||
							
								
								
									
										1058
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1058
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
										
											
												File diff suppressed because it is too large
												Load Diff
											
										
									
								
							
		Loading…
	
		Reference in New Issue
	
	Block a user