forked from sheetjs/sheetjs
		
	version bump 0.9.3: multiformat alignment
- merge cells and stubs consistency - character entity decoding - cellDates processing for other formats
This commit is contained in:
		
							parent
							
								
									d3eaa62d45
								
							
						
					
					
						commit
						ea1873e572
					
				| @ -5,7 +5,7 @@ but not limited to API changes and file location changes.  Minor behavioral | ||||
| changes may not be included if they are not expected to break existing code. | ||||
| 
 | ||||
| 
 | ||||
| ## Unreleased | ||||
| ## 0.9.3 (2017-03-15) | ||||
| 
 | ||||
| * XLML property names are more closely mapped to the XLSX equivalent | ||||
| * Stub cells are now cell type `z` | ||||
|  | ||||
| @ -479,7 +479,7 @@ avoid possible confusion. | ||||
| 
 | ||||
| Type `z` represents blank stub cells.  These do not have any data or type, and | ||||
| are not processed by any of the core library functions.  By default these cells | ||||
| will not be generated; the parser `cellStubs` option must be set to `true`. | ||||
| will not be generated; the parser `sheetStubs` option must be set to `true`. | ||||
| 
 | ||||
| ### Formulae | ||||
| 
 | ||||
|  | ||||
| @ -103,6 +103,8 @@ if(program.all) { | ||||
| 	opts.cellFormula = true; | ||||
| 	opts.cellNF = true; | ||||
| 	opts.cellStyles = true; | ||||
| 	opts.sheetStubs = true; | ||||
| 	opts.cellDates = true; | ||||
| } | ||||
| 
 | ||||
| if(program.dev) { | ||||
|  | ||||
| @ -1 +1 @@ | ||||
| XLSX.version = '0.9.2'; | ||||
| XLSX.version = '0.9.3'; | ||||
|  | ||||
| @ -40,15 +40,15 @@ var rencstr = "&<>'\"".split(""); | ||||
| // TODO: CP remap (need to read file version to determine OS)
 | ||||
| var unescapexml/*:StringConv*/ = (function() { | ||||
| 	/* 22.4.2.4 bstr (Basic String) */ | ||||
| 	var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	return function unescapexml(text/*:string*/)/*:string*/ { | ||||
| 		var s = text + ''; | ||||
| 		return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 		return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g; | ||||
| function escapexml(text/*:string*/)/*:string*/{ | ||||
| function escapexml(text/*:string*/, xml/*:?boolean*/)/*:string*/{ | ||||
| 	var s = text + ''; | ||||
| 	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";}); | ||||
| } | ||||
|  | ||||
| @ -209,6 +209,13 @@ function parse_BrtFmlaString(data, length, opts) { | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.676 BrtMergeCell */ | ||||
| var parse_BrtMergeCell = parse_UncheckedRfX; | ||||
| var write_BrtMergeCell = write_UncheckedRfX; | ||||
| /* [MS-XLSB] 2.4.108 BrtBeginMergeCells */ | ||||
| function write_BrtBeginMergeCells(cnt, o) { | ||||
| 	if(o == null) o = new_buf(4); | ||||
| 	o.write_shift(4, cnt); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.656 BrtHLink */ | ||||
| function parse_BrtHLink(data, length, opts) { | ||||
| @ -550,7 +557,14 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) { | ||||
| 	write_record(ba, 'BrtEndSheetData'); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx, opts, wb) { | ||||
| function write_MERGECELLS(ba, ws/*:Worksheet*/) { | ||||
| 	if(!ws || !ws['!merges']) return; | ||||
| 	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length)); | ||||
| 	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); }); | ||||
| 	write_record(ba, 'BrtEndMergeCells'); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var ba = buf_array(); | ||||
| 	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; | ||||
| 	var r = safe_decode_range(ws['!ref'] || "A1"); | ||||
| @ -569,7 +583,7 @@ function write_ws_bin(idx, opts, wb) { | ||||
| 	/* [SORTSTATE] */ | ||||
| 	/* [DCON] */ | ||||
| 	/* [USERSHVIEWS] */ | ||||
| 	/* [MERGECELLS] */ | ||||
| 	write_MERGECELLS(ba, ws); | ||||
| 	/* [BrtPhoneticInfo] */ | ||||
| 	/* *CONDITIONALFORMATTING */ | ||||
| 	/* [DVALS] */ | ||||
|  | ||||
| @ -764,6 +764,15 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| 	var attr = {}; | ||||
| 	if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr)); | ||||
| 
 | ||||
| 	if(ws['!merges']) { | ||||
| 		var marr = ws['!merges']; | ||||
| 		for(var mi = 0; mi != marr.length; ++mi) { | ||||
| 			if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue; | ||||
| 			if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c; | ||||
| 			if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var t = "", p = ""; | ||||
| 	switch(cell.t) { | ||||
| 		case 'z': return ""; | ||||
| @ -771,7 +780,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| 		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break; | ||||
| 		case 'e': t = 'Error'; p = BErr[cell.v]; break; | ||||
| 		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break; | ||||
| 		default:  t = 'String'; p = escapexml(cell.v||""); | ||||
| 		case 's':  t = 'String'; p = escapexml(cell.v||""); break; | ||||
| 	} | ||||
| 	var m = '<Data ss:Type="' + t + '">' + p + '</Data>'; | ||||
| 
 | ||||
| @ -781,16 +790,27 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ { | ||||
| 	if(!ws['!ref']) return ""; | ||||
| 	var range = safe_decode_range(ws['!ref']); | ||||
| 	var marr = ws['!merges'] || [], mi = 0; | ||||
| 	var o = []; | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		var row = ["<Row>"]; | ||||
| 		var row = ['<Row ss:Index="' + (R+1) + '">']; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			var skip = false; | ||||
| 			for(mi = 0; mi != marr.length; ++mi) { | ||||
| 				if(marr[mi].s.c > C) continue; | ||||
| 				if(marr[mi].s.r > R) continue; | ||||
| 				if(marr[mi].e.c < C) continue; | ||||
| 				if(marr[mi].e.r < R) continue; | ||||
| 				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 				break; | ||||
| 			} | ||||
| 			if(skip) continue; | ||||
| 			var addr = {r:R,c:C}; | ||||
| 			var ref = encode_cell(addr), cell = ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr)); | ||||
| 		} | ||||
| 		row.push("</Row>"); | ||||
| 		o.push(row.join("")); | ||||
| 		if(row.length > 2) o.push(row.join("")); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
|  | ||||
| @ -107,13 +107,15 @@ var parse_content_xml = (function() { | ||||
| 						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break; | ||||
| 						case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']); | ||||
| 							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); } | ||||
| 							q.z = 'm/d/yy'; break; | ||||
| 						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break; | ||||
| 						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break; | ||||
| 						default: | ||||
| 							if(q.t === 'string' || q.t === 'text' || !q.t) { | ||||
| 								q.t = 's'; | ||||
| 								if(ctag['string-value'] != null) textp = ctag['string-value']; | ||||
| 								if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']); | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
|  | ||||
| @ -1,21 +1,37 @@ | ||||
| var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 	var null_cell_xml = '          <table:table-cell />\n'; | ||||
| 	var covered_cell_xml = '          <table:covered-table-cell/>\n'; | ||||
| 	var cell_begin = '          <table:table-cell ', cell_end = '</table:table-cell>\n'; | ||||
| 	var vt = 'office:value-type='; | ||||
| 	var p_begin = '<text:p>', p_end = '</text:p>'; | ||||
| 	var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ { | ||||
| 		/* Section 9 Tables */ | ||||
| 		var o = []; | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']); | ||||
| 		var marr = ws['!merges'] || [], mi = 0; | ||||
| 		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n'); | ||||
| 		for(; R <= range.e.r; ++R) { | ||||
| 			o.push('        <table:table-row>\n'); | ||||
| 			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml); | ||||
| 			for(; C <= range.e.c; ++C) { | ||||
| 				var skip = false, mxml = ""; | ||||
| 				for(mi = 0; mi != marr.length; ++mi) { | ||||
| 					if(marr[mi].s.c > C) continue; | ||||
| 					if(marr[mi].s.r > R) continue; | ||||
| 					if(marr[mi].e.c < C) continue; | ||||
| 					if(marr[mi].e.r < R) continue; | ||||
| 					if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 					mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" '; | ||||
| 					break; | ||||
| 				} | ||||
| 				if(skip) { o.push(covered_cell_xml); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = ws[ref]; | ||||
| 				if(cell) switch(cell.t) { | ||||
| 					case 'b': o.push('          <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 'n': o.push('          <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 's': case 'str': o.push('          <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					//case 'd': // TODO
 | ||||
| 					case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break; | ||||
| 					case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break; | ||||
| 					case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break; | ||||
| 					case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break; | ||||
| 					//case 'e':
 | ||||
| 					default: o.push(null_cell_xml); | ||||
| 				} else o.push(null_cell_xml); | ||||
|  | ||||
							
								
								
									
										23
									
								
								dist/xlsx.core.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										23
									
								
								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
											
										
									
								
							
							
								
								
									
										24
									
								
								dist/xlsx.full.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										24
									
								
								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
											
										
									
								
							
							
								
								
									
										347
									
								
								dist/xlsx.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										347
									
								
								dist/xlsx.js
									
									
									
									
										vendored
									
									
								
							| @ -5,7 +5,7 @@ | ||||
| /*exported XLSX */ | ||||
| var XLSX = {}; | ||||
| (function make_xlsx(XLSX){ | ||||
| XLSX.version = '0.9.2'; | ||||
| XLSX.version = '0.9.3'; | ||||
| var current_codepage = 1200, current_cptable; | ||||
| if(typeof module !== "undefined" && typeof require !== 'undefined') { | ||||
| 	if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js'); | ||||
| @ -1453,18 +1453,19 @@ var rencstr = "&<>'\"".split(""); | ||||
| // TODO: CP remap (need to read file version to determine OS)
 | ||||
| var unescapexml = (function() { | ||||
| 	/* 22.4.2.4 bstr (Basic String) */ | ||||
| 	var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	return function unescapexml(text) { | ||||
| 		var s = text + ''; | ||||
| 		return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 		return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g; | ||||
| function escapexml(text){ | ||||
| function escapexml(text, xml){ | ||||
| 	var s = text + ''; | ||||
| 	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";}); | ||||
| } | ||||
| function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); } | ||||
| 
 | ||||
| /* TODO: handle codepages */ | ||||
| var xlml_fixstr = (function() { | ||||
| @ -1591,6 +1592,13 @@ XMLNS.main = [ | ||||
| 	'http://schemas.microsoft.com/office/excel/2006/2' | ||||
| ]; | ||||
| 
 | ||||
| var XLMLNS = ({ | ||||
| 	'o':    'urn:schemas-microsoft-com:office:office', | ||||
| 	'x':    'urn:schemas-microsoft-com:office:excel', | ||||
| 	'ss':   'urn:schemas-microsoft-com:office:spreadsheet', | ||||
| 	'dt':   'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882', | ||||
| 	'html': 'http://www.w3.org/TR/REC-html40' | ||||
| }); | ||||
| function read_double_le(b, idx) { | ||||
| 	var s = 1 - 2 * (b[idx + 7] >>> 7); | ||||
| 	var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f); | ||||
| @ -2968,10 +2976,67 @@ function xlml_set_prop(Props, tag, val) { | ||||
| 	/* TODO: Normalize the properties */ | ||||
| 	switch(tag) { | ||||
| 		case 'Description': tag = 'Comments'; break; | ||||
| 		case 'Created': tag = 'CreatedDate'; break; | ||||
| 		case 'LastSaved': tag = 'ModifiedDate'; break; | ||||
| 	} | ||||
| 	Props[tag] = val; | ||||
| } | ||||
| 
 | ||||
| var XLMLDocumentProperties = [ | ||||
| 	['Title', 'Title'], | ||||
| 	['Subject', 'Subject'], | ||||
| 	['Author', 'Author'], | ||||
| 	['Keywords', 'Keywords'], | ||||
| 	['Comments', 'Description'], | ||||
| 	['LastAuthor', 'LastAuthor'], | ||||
| 	['CreatedDate', 'Created', 'date'], | ||||
| 	['ModifiedDate', 'LastSaved', 'date'], | ||||
| 	['Category', 'Category'], | ||||
| 	['Manager', 'Manager'], | ||||
| 	['Company', 'Company'], | ||||
| 	['AppVersion', 'Version'] | ||||
| ]; | ||||
| 
 | ||||
| /* TODO: verify */ | ||||
| function xlml_write_docprops(Props) { | ||||
| 	var T = 'DocumentProperties'; | ||||
| 	var o = []; | ||||
| 	XLMLDocumentProperties.forEach(function(p) { | ||||
| 		if(!Props[p[0]]) return; | ||||
| 		var m = Props[p[0]]; | ||||
| 		switch(p[2]) { | ||||
| 			case 'date': m = new Date(m).toISOString(); break; | ||||
| 		} | ||||
| 		o.push(writetag(p[1], m)); | ||||
| 	}); | ||||
| 	return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>'; | ||||
| } | ||||
| function xlml_write_custprops(Props, Custprops) { | ||||
| 	var T = 'CustomDocumentProperties'; | ||||
| 	var o = []; | ||||
| 	if(Props) keys(Props).forEach(function(k) { | ||||
| if(!Props.hasOwnProperty(k)) return; | ||||
| 		for(var i = 0; i < XLMLDocumentProperties.length; ++i) | ||||
| 			if(k == XLMLDocumentProperties[i][0]) return; | ||||
| 		var m = Props[k]; | ||||
| 		var t = "string"; | ||||
| 		if(typeof m == 'number') { t = "float"; m = String(m); } | ||||
| 		else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; } | ||||
| 		else m = String(m); | ||||
| 		o.push(writextag(escapexmltag(k), m, {"dt:dt":t})); | ||||
| 	}); | ||||
| 	if(Custprops) keys(Custprops).forEach(function(k) { | ||||
| if(!Custprops.hasOwnProperty(k)) return; | ||||
| 		var m = Custprops[k]; | ||||
| 		var t = "string"; | ||||
| 		if(typeof m == 'number') { t = "float"; m = String(m); } | ||||
| 		else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; } | ||||
| 		else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); } | ||||
| 		else m = String(m); | ||||
| 		o.push(writextag(escapexmltag(k), m, {"dt:dt":t})); | ||||
| 	}); | ||||
| 	return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>'; | ||||
| } | ||||
| /* [MS-DTYP] 2.3.3 FILETIME */ | ||||
| /* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */ | ||||
| /* [MS-OLEPS] 2.8 FILETIME (Packet Version) */ | ||||
| @ -3735,15 +3800,56 @@ function parse_MulRk(blob, length) { | ||||
| 	if(rkrecs.length != lastcol - col + 1) throw "MulRK length mismatch"; | ||||
| 	return {r:rw, c:col, C:lastcol, rkrec:rkrecs}; | ||||
| } | ||||
| /* 2.4.174 */ | ||||
| function parse_MulBlank(blob, length) { | ||||
| 	var target = blob.l + length - 2; | ||||
| 	var rw = blob.read_shift(2), col = blob.read_shift(2); | ||||
| 	var ixfes = []; | ||||
| 	while(blob.l < target) ixfes.push(blob.read_shift(2)); | ||||
| 	if(blob.l !== target) throw "MulBlank read error"; | ||||
| 	var lastcol = blob.read_shift(2); | ||||
| 	if(ixfes.length != lastcol - col + 1) throw "MulBlank length mismatch"; | ||||
| 	return {r:rw, c:col, C:lastcol, ixfe:ixfes}; | ||||
| } | ||||
| 
 | ||||
| /* 2.5.20 2.5.249 TODO */ | ||||
| /* 2.5.20 2.5.249 TODO: interpret values here */ | ||||
| function parse_CellStyleXF(blob, length, style) { | ||||
| 	var o = {}; | ||||
| 	var a = blob.read_shift(4), b = blob.read_shift(4); | ||||
| 	var c = blob.read_shift(4), d = blob.read_shift(2); | ||||
| 	o.patternType = XLSFillPattern[c >> 26]; | ||||
| 
 | ||||
| 	o.alc = a & 0x07; | ||||
| 	o.fWrap = (a >> 3) & 0x01; | ||||
| 	o.alcV = (a >> 4) & 0x07; | ||||
| 	o.fJustLast = (a >> 7) & 0x01; | ||||
| 	o.trot = (a >> 8) & 0xFF; | ||||
| 	o.cIndent = (a >> 16) & 0x0F; | ||||
| 	o.fShrinkToFit = (a >> 20) & 0x01; | ||||
| 	o.iReadOrder = (a >> 22) & 0x02; | ||||
| 	o.fAtrNum = (a >> 26) & 0x01; | ||||
| 	o.fAtrFnt = (a >> 27) & 0x01; | ||||
| 	o.fAtrAlc = (a >> 28) & 0x01; | ||||
| 	o.fAtrBdr = (a >> 29) & 0x01; | ||||
| 	o.fAtrPat = (a >> 30) & 0x01; | ||||
| 	o.fAtrProt = (a >> 31) & 0x01; | ||||
| 
 | ||||
| 	o.dgLeft = b & 0x0F; | ||||
| 	o.dgRight = (b >> 4) & 0x0F; | ||||
| 	o.dgTop = (b >> 8) & 0x0F; | ||||
| 	o.dgBottom = (b >> 12) & 0x0F; | ||||
| 	o.icvLeft = (b >> 16) & 0x7F; | ||||
| 	o.icvRight = (b >> 23) & 0x7F; | ||||
| 	o.grbitDiag = (b >> 30) & 0x03; | ||||
| 
 | ||||
| 	o.icvTop = c & 0x7F; | ||||
| 	o.icvBottom = (c >> 7) & 0x7F; | ||||
| 	o.icvDiag = (c >> 14) & 0x7F; | ||||
| 	o.dgDiag = (c >> 21) & 0x0F; | ||||
| 
 | ||||
| 	o.icvFore = d & 0x7F; | ||||
| 	o.icvBack = (d >> 7) & 0x7F; | ||||
| 	o.fsxButton = (d >> 14) & 0x01; | ||||
| 	return o; | ||||
| } | ||||
| function parse_CellXF(blob, length) {return parse_CellStyleXF(blob,length,0);} | ||||
| @ -4101,7 +4207,6 @@ var parse_SXLI = parsenoop; | ||||
| var parse_SXPI = parsenoop; | ||||
| var parse_DocRoute = parsenoop; | ||||
| var parse_RecipName = parsenoop; | ||||
| var parse_MulBlank = parsenoop; | ||||
| var parse_SXDI = parsenoop; | ||||
| var parse_SXDB = parsenoop; | ||||
| var parse_SXFDB = parsenoop; | ||||
| @ -5766,8 +5871,19 @@ var rc_to_a1 = (function(){ | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| /* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */ | ||||
| var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)([1-9]\d{0,5}|10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6])(?![_.\(A-Za-z0-9])/g; | ||||
| var a1_to_rc =(function(){ | ||||
| 	return function a1_to_rc(fstr, base) { | ||||
| 		return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5, off, str) { | ||||
| 			/* TODO: handle fixcol / fixrow */ | ||||
| 			var c = decode_col($3) - base.c; | ||||
| 			var r = decode_row($5) - base.r; | ||||
| 			return $1 + "R" + (r == 0 ? "" : "[" + r + "]") + "C" + (c == 0 ? "" : "[" + c + "]"); | ||||
| 		}); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| /* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */ | ||||
| function shift_formula_str(f, delta) { | ||||
| 	return f.replace(crefregex, 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)); | ||||
| @ -8060,6 +8176,7 @@ function get_cell_style(styles, cell, opts) { | ||||
| } | ||||
| 
 | ||||
| function safe_format(p, fmtid, fillid, opts) { | ||||
| 	if(p.t === 'z') return; | ||||
| 	if(p.t === 'd' && typeof p.v === 'string') p.v = new Date(p.v); | ||||
| 	try { | ||||
| 		if(p.t === 'e') p.w = p.w || BErr[p.v]; | ||||
| @ -8181,7 +8298,7 @@ function parse_ws_xml_hlinks(s, data, rels) { | ||||
| 		var rng = safe_decode_range(val.ref); | ||||
| 		for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) { | ||||
| 			var addr = encode_cell({c:C,r:R}); | ||||
| 			if(!s[addr]) s[addr] = {t:"stub",v:undefined}; | ||||
| 			if(!s[addr]) s[addr] = {t:"z",v:undefined}; | ||||
| 			s[addr].l = val; | ||||
| 		} | ||||
| 	} | ||||
| @ -8220,7 +8337,7 @@ function write_ws_xml_cols(ws, cols) { | ||||
| } | ||||
| 
 | ||||
| function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) { | ||||
| 	if(cell.v === undefined) return ""; | ||||
| 	if(cell.v === undefined || cell.t === 'z') return ""; | ||||
| 	var vv = ""; | ||||
| 	var oldt = cell.t, oldv = cell.v; | ||||
| 	switch(cell.t) { | ||||
| @ -8333,7 +8450,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) { | ||||
| 			/* SCHEMA IS ACTUALLY INCORRECT HERE.  IF A CELL HAS NO T, EMIT "" */ | ||||
| 			if(tag.t === undefined && p.v === undefined) { | ||||
| 				if(!opts.sheetStubs) continue; | ||||
| 				p.t = "stub"; | ||||
| 				p.t = "z"; | ||||
| 			} | ||||
| 			else p.t = tag.t || "n"; | ||||
| 			if(guess.s.c > idx) guess.s.c = idx; | ||||
| @ -8345,7 +8462,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess) { | ||||
| 					sstr = strs[parseInt(p.v, 10)]; | ||||
| 					if(typeof p.v == 'undefined') { | ||||
| 						if(!opts.sheetStubs) continue; | ||||
| 						p.t = "stub"; | ||||
| 						p.t = 'z'; | ||||
| 					} | ||||
| 					p.v = sstr.t; | ||||
| 					p.r = sstr.r; | ||||
| @ -8636,6 +8753,13 @@ function parse_BrtFmlaString(data, length, opts) { | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.676 BrtMergeCell */ | ||||
| var parse_BrtMergeCell = parse_UncheckedRfX; | ||||
| var write_BrtMergeCell = write_UncheckedRfX; | ||||
| /* [MS-XLSB] 2.4.108 BrtBeginMergeCells */ | ||||
| function write_BrtBeginMergeCells(cnt, o) { | ||||
| 	if(o == null) o = new_buf(4); | ||||
| 	o.write_shift(4, cnt); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.656 BrtHLink */ | ||||
| function parse_BrtHLink(data, length, opts) { | ||||
| @ -8751,7 +8875,7 @@ function parse_ws_bin(data, opts, rels, wb) { | ||||
| 				break; | ||||
| 
 | ||||
| 			case 'BrtCellBlank': if(!opts.sheetStubs) break; | ||||
| 				p = ({t:'s',v:undefined}); | ||||
| 				p = ({t:'z',v:undefined}); | ||||
| 				s[encode_col(C=val[0].c) + rr] = p; | ||||
| 				if(refguess.s.r > row.r) refguess.s.r = row.r; | ||||
| 				if(refguess.s.c > C) refguess.s.c = C; | ||||
| @ -8977,6 +9101,13 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) { | ||||
| 	write_record(ba, 'BrtEndSheetData'); | ||||
| } | ||||
| 
 | ||||
| function write_MERGECELLS(ba, ws) { | ||||
| 	if(!ws || !ws['!merges']) return; | ||||
| 	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length)); | ||||
| 	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); }); | ||||
| 	write_record(ba, 'BrtEndMergeCells'); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx, opts, wb) { | ||||
| 	var ba = buf_array(); | ||||
| 	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; | ||||
| @ -8996,7 +9127,7 @@ function write_ws_bin(idx, opts, wb) { | ||||
| 	/* [SORTSTATE] */ | ||||
| 	/* [DCON] */ | ||||
| 	/* [USERSHVIEWS] */ | ||||
| 	/* [MERGECELLS] */ | ||||
| 	write_MERGECELLS(ba, ws); | ||||
| 	/* [BrtPhoneticInfo] */ | ||||
| 	/* *CONDITIONALFORMATTING */ | ||||
| 	/* [DVALS] */ | ||||
| @ -9606,6 +9737,7 @@ function xlml_set_custprop(Custprops, Rn, cp, val) { | ||||
| } | ||||
| 
 | ||||
| function safe_format_xlml(cell, nf, o) { | ||||
| 	if(cell.t === 'z') return; | ||||
| 	try { | ||||
| 		if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; } | ||||
| 		else if(nf === "General") { | ||||
| @ -9748,8 +9880,16 @@ function parse_xlml_xml(d, opts) { | ||||
| 					var rr = r + (parseInt(cell.MergeDown,10)|0); | ||||
| 					mergecells.push({s:{c:c,r:r},e:{c:cc,r:rr}}); | ||||
| 				} | ||||
| 				++c; | ||||
| 				if(cell.MergeAcross) c += +cell.MergeAcross; | ||||
| 				if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; } | ||||
| 				else if(cell.MergeAcross || cell.MergeDown) { | ||||
| for(var cma = c; cma <= cc; ++cma) { | ||||
| 						for(var cmd = r; cmd <= rr; ++cmd) { | ||||
| 							if(cma > c || cmd > r) cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'}; | ||||
| 						} | ||||
| 					} | ||||
| 					c = cc + 1; | ||||
| 				} | ||||
| 				else ++c; | ||||
| 			} else { | ||||
| 				cell = xlml_parsexmltagobj(Rn[0]); | ||||
| 				if(cell.Index) c = +cell.Index - 1; | ||||
| @ -10275,10 +10415,109 @@ function parse_xlml(data, opts) { | ||||
| } | ||||
| 
 | ||||
| /* TODO */ | ||||
| function write_xlml(wb, opts) { | ||||
| 	var o = [XML_HEADER]; | ||||
| function write_props_xlml(wb, opts) { | ||||
| 	var o = []; | ||||
| 	/* DocumentProperties */ | ||||
| 	if(wb.Props) o.push(xlml_write_docprops(wb.Props)); | ||||
| 	/* CustomDocumentProperties */ | ||||
| 	if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops)); | ||||
| 	return o.join(""); | ||||
| } | ||||
| /* TODO */ | ||||
| function write_wb_xlml(wb, opts) { | ||||
| 	/* OfficeDocumentSettings */ | ||||
| 	/* ExcelWorkbook */ | ||||
| 	return ""; | ||||
| } | ||||
| /* TODO */ | ||||
| function write_sty_xlml(wb, opts) { | ||||
| 	/* Styles */ | ||||
| 	return ""; | ||||
| } | ||||
| /* TODO */ | ||||
| function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){ | ||||
| 	if(!cell || cell.v === undefined) return "<Cell></Cell>"; | ||||
| 
 | ||||
| 	var attr = {}; | ||||
| 	if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr)); | ||||
| 
 | ||||
| 	if(ws['!merges']) { | ||||
| 		var marr = ws['!merges']; | ||||
| 		for(var mi = 0; mi != marr.length; ++mi) { | ||||
| 			if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue; | ||||
| 			if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c; | ||||
| 			if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var t = "", p = ""; | ||||
| 	switch(cell.t) { | ||||
| 		case 'z': return ""; | ||||
| 		case 'n': t = 'Number'; p = String(cell.v); break; | ||||
| 		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break; | ||||
| 		case 'e': t = 'Error'; p = BErr[cell.v]; break; | ||||
| 		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break; | ||||
| 		case 's':  t = 'String'; p = escapexml(cell.v||""); break; | ||||
| 	} | ||||
| 	var m = '<Data ss:Type="' + t + '">' + p + '</Data>'; | ||||
| 
 | ||||
| 	return writextag("Cell", m, attr); | ||||
| } | ||||
| /* TODO */ | ||||
| function write_ws_xlml_table(ws, opts, idx, wb) { | ||||
| 	if(!ws['!ref']) return ""; | ||||
| 	var range = safe_decode_range(ws['!ref']); | ||||
| 	var marr = ws['!merges'] || [], mi = 0; | ||||
| 	var o = []; | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		var row = ['<Row ss:Index="' + (R+1) + '">']; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			var skip = false; | ||||
| 			for(mi = 0; mi != marr.length; ++mi) { | ||||
| 				if(marr[mi].s.c > C) continue; | ||||
| 				if(marr[mi].s.r > R) continue; | ||||
| 				if(marr[mi].e.c < C) continue; | ||||
| 				if(marr[mi].e.r < R) continue; | ||||
| 				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 				break; | ||||
| 			} | ||||
| 			if(skip) continue; | ||||
| 			var addr = {r:R,c:C}; | ||||
| 			var ref = encode_cell(addr), cell = ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr)); | ||||
| 		} | ||||
| 		row.push("</Row>"); | ||||
| 		if(row.length > 2) o.push(row.join("")); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_ws_xlml(idx, opts, wb) { | ||||
| 	var o = []; | ||||
| 	var s = wb.SheetNames[idx]; | ||||
| 	var ws = wb.Sheets[s]; | ||||
| 
 | ||||
| 	/* Table */ | ||||
| 	var t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : ""; | ||||
| 	if(t.length > 0) o.push("<Table>" + t + "</Table>"); | ||||
| 	/* WorksheetOptions */ | ||||
| 	return o.join(""); | ||||
| } | ||||
| function write_xlml(wb, opts) { | ||||
| 	var d = []; | ||||
| 	d.push(write_props_xlml(wb, opts)); | ||||
| 	d.push(write_wb_xlml(wb, opts)); | ||||
| 	d.push(write_sty_xlml(wb, opts)); | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) | ||||
| 		d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])})); | ||||
| 	return XML_HEADER + writextag("Workbook", d.join(""), { | ||||
| 		'xmlns':      XLMLNS.ss, | ||||
| 		'xmlns:o':    XLMLNS.o, | ||||
| 		'xmlns:x':    XLMLNS.x, | ||||
| 		'xmlns:ss':   XLMLNS.ss, | ||||
| 		'xmlns:dt':   XLMLNS.dt, | ||||
| 		'xmlns:html': XLMLNS.html | ||||
| 	}); | ||||
| } | ||||
| /* [MS-OLEDS] 2.3.8 CompObjStream */ | ||||
| function parse_compobj(obj) { | ||||
| 	var v = {}; | ||||
| @ -10334,6 +10573,7 @@ function slurp(R, blob, length, opts) { | ||||
| } | ||||
| 
 | ||||
| function safe_format_xf(p, opts, date1904) { | ||||
| 	if(p.t === 'z') return; | ||||
| 	if(p.t === 'e') { p.w = p.w || BErr[p.v]; } | ||||
| 	if(!p.XF) return; | ||||
| 	try { | ||||
| @ -10590,9 +10830,9 @@ function parse_workbook(blob, options) { | ||||
| 								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); | ||||
| 									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); | ||||
| 								} 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); | ||||
| @ -10604,7 +10844,7 @@ function parse_workbook(blob, options) { | ||||
| 						last_formula.val = val; | ||||
| 						temp_val = ({v:last_formula.val, ixfe:last_formula.cell.ixfe, t:'s'}); | ||||
| 						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; | ||||
| @ -10615,7 +10855,7 @@ function parse_workbook(blob, options) { | ||||
| 					if(options.cellFormula && out[last_cell]) { | ||||
| 						if(!last_formula) break; /* technically unreachable */ | ||||
| 						if(!last_cell || !out[last_cell]) break; /* technically unreachable */ | ||||
| 						out[last_cell].f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts); | ||||
| 						out[last_cell].f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts); | ||||
| 						out[last_cell].F = encode_range(val[0]); | ||||
| 					} | ||||
| 				} break; | ||||
| @ -10626,7 +10866,7 @@ function parse_workbook(blob, options) { | ||||
| 						/* TODO: capture range */ | ||||
| 						if(!last_formula) break; /* technically unreachable */ | ||||
| 						shared_formulae[encode_cell(last_formula.cell)]= val[0]; | ||||
| 						(out[encode_cell(last_formula.cell)]||{}).f = stringify_formula(val[0], range, lastcell, supbooks, opts); | ||||
| 						(out[encode_cell(last_formula.cell)]||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 'LabelSst': | ||||
| @ -10635,6 +10875,19 @@ function parse_workbook(blob, options) { | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 					break; | ||||
| 				case 'Blank': if(options.sheetStubs) { | ||||
| 					temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'}; | ||||
| 					safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 					addcell({c:val.c, r:val.r}, temp_val, options); | ||||
| 				} break; | ||||
| 				case 'MulBlank': if(options.sheetStubs) { | ||||
| 					for(var _j = val.c; _j <= val.C; ++_j) { | ||||
| 						var _ixfe = val.ixfe[_j-val.c]; | ||||
| 						temp_val= {ixfe:_ixfe, XF:XFs[_ixfe], t:'z'}; | ||||
| 						safe_format_xf(temp_val, options, wb.opts.Date1904); | ||||
| 						addcell({c:_j, r:val.r}, temp_val, options); | ||||
| 					} | ||||
| 				} break; | ||||
| 				case 'RString': | ||||
| 				case 'Label': case 'BIFF2STR': | ||||
| 					temp_val=make_cell(val.val, val.ixfe, 's'); | ||||
| @ -10701,7 +10954,6 @@ function parse_workbook(blob, options) { | ||||
| 				case 'ColInfo': break; // TODO
 | ||||
| 				case 'Row': break; // TODO
 | ||||
| 				case 'DBCell': break; // TODO
 | ||||
| 				case 'MulBlank': break; // TODO
 | ||||
| 				case 'EntExU2': break; // TODO
 | ||||
| 				case 'SxView': break; // TODO
 | ||||
| 				case 'Sxvd': break; // TODO
 | ||||
| @ -10716,7 +10968,6 @@ function parse_workbook(blob, options) { | ||||
| 				case 'Feat': break; | ||||
| 				case 'FeatHdr': case 'FeatHdr11': break; | ||||
| 				case 'Feature11': case 'Feature12': case 'List12': break; | ||||
| 				case 'Blank': break; | ||||
| 				case 'Country': country = val; break; | ||||
| 				case 'RecalcId': break; | ||||
| 				case 'DefaultRowHeight': case 'DxGCol': break; // TODO: htmlify
 | ||||
| @ -12433,8 +12684,10 @@ var parse_content_xml = (function() { | ||||
| 				rowtag = parsexmltag(Rn[0], false); | ||||
| 				if(rowtag['行号']) R = rowtag['行号'] - 1; else ++R; | ||||
| 				C = -1; break; | ||||
| 			case 'covered-table-cell': // 9.1.5 table:covered-table-cell
 | ||||
| 				++C; break; /* stub */ | ||||
| 			case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
 | ||||
| 				++C; | ||||
| 				if(opts.sheetStubs) ws[encode_cell({r:R,c:C})] = {t:'z'}; | ||||
| 				break; /* stub */ | ||||
| 			case 'table-cell': case '数据': | ||||
| 				if(Rn[0].charAt(Rn[0].length-2) === '/') { | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| @ -12480,13 +12733,15 @@ var parse_content_xml = (function() { | ||||
| 						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break; | ||||
| 						case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']); | ||||
| 							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); } | ||||
| 							q.z = 'm/d/yy'; break; | ||||
| 						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break; | ||||
| 						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break; | ||||
| 						default: | ||||
| 							if(q.t === 'string' || q.t === 'text' || !q.t) { | ||||
| 								q.t = 's'; | ||||
| 								if(ctag['string-value'] != null) textp = ctag['string-value']; | ||||
| 								if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']); | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| @ -12496,7 +12751,7 @@ var parse_content_xml = (function() { | ||||
| 						isstub = textpidx == 0; | ||||
| 					} | ||||
| 					if(textp) q.w = textp; | ||||
| 					if(!isstub || opts.cellStubs) { | ||||
| 					if(!isstub || opts.sheetStubs) { | ||||
| 						if(!(opts.sheetRows && opts.sheetRows < R)) { | ||||
| 							ws[encode_cell({r:R,c:C})] = q; | ||||
| 							while(--rept > 0) ws[encode_cell({r:R,c:++C})] = dup(q); | ||||
| @ -12769,22 +13024,38 @@ var parse_content_xml = (function() { | ||||
| })(); | ||||
| var write_content_xml = (function() { | ||||
| 	var null_cell_xml = '          <table:table-cell />\n'; | ||||
| 	var covered_cell_xml = '          <table:covered-table-cell/>\n'; | ||||
| 	var cell_begin = '          <table:table-cell ', cell_end = '</table:table-cell>\n'; | ||||
| 	var vt = 'office:value-type='; | ||||
| 	var p_begin = '<text:p>', p_end = '</text:p>'; | ||||
| 	var write_ws = function(ws, wb, i, opts) { | ||||
| 		/* Section 9 Tables */ | ||||
| 		var o = []; | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']); | ||||
| 		var marr = ws['!merges'] || [], mi = 0; | ||||
| 		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n'); | ||||
| 		for(; R <= range.e.r; ++R) { | ||||
| 			o.push('        <table:table-row>\n'); | ||||
| 			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml); | ||||
| 			for(; C <= range.e.c; ++C) { | ||||
| 				var skip = false, mxml = ""; | ||||
| 				for(mi = 0; mi != marr.length; ++mi) { | ||||
| 					if(marr[mi].s.c > C) continue; | ||||
| 					if(marr[mi].s.r > R) continue; | ||||
| 					if(marr[mi].e.c < C) continue; | ||||
| 					if(marr[mi].e.r < R) continue; | ||||
| 					if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 					mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" '; | ||||
| 					break; | ||||
| 				} | ||||
| 				if(skip) { o.push(covered_cell_xml); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = ws[ref]; | ||||
| 				if(cell) switch(cell.t) { | ||||
| 					case 'b': o.push('          <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 'n': o.push('          <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 's': case 'str': o.push('          <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					//case 'd': // TODO
 | ||||
| 					case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break; | ||||
| 					case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break; | ||||
| 					case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break; | ||||
| 					case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break; | ||||
| 					//case 'e':
 | ||||
| 					default: o.push(null_cell_xml); | ||||
| 				} else o.push(null_cell_xml); | ||||
| @ -13039,7 +13310,7 @@ function parse_zip(zip, opts) { | ||||
| 		out.files = zip.files; | ||||
| 	} | ||||
| 	if(opts.bookVBA) { | ||||
| 		if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,dir.vba[0],true); | ||||
| 		if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,dir.vba[0].replace(/^\//,''),true); | ||||
| 		else if(dir.defaults && dir.defaults.bin === 'application/vnd.ms-office.vbaProject') out.vbaraw = getzipdata(zip,'xl/vbaProject.bin',true); | ||||
| 	} | ||||
| 	return out; | ||||
| @ -13228,7 +13499,8 @@ function writeSync(wb, opts) { | ||||
| 	check_wb(wb); | ||||
| 	var o = opts||{}; | ||||
| 	switch(o.bookType || 'xlsx') { | ||||
| 		case 'xml': return write_string_type(write_xlml(wb, o), o); | ||||
| 		case 'xml': | ||||
| 		case 'xlml': return write_string_type(write_xlml(wb, o), o); | ||||
| 		case 'csv': return write_string_type(write_csv_str(wb, o), o); | ||||
| 		case 'fods': return write_string_type(write_ods(wb, o), o); | ||||
| 		case 'biff2': return write_binary_type(write_biff_buf(wb, o), o); | ||||
| @ -13248,6 +13520,7 @@ function writeFileSync(wb, filename, opts) { | ||||
| 		case '.xlsm': o.bookType = 'xlsm'; break; | ||||
| 		case '.xlsb': o.bookType = 'xlsb'; break; | ||||
| 		case '.fods': o.bookType = 'fods'; break; | ||||
| 		case '.xlml': o.bookType = 'xlml'; break; | ||||
| 	default: switch(o.file.slice(-4).toLowerCase()) { | ||||
| 		case '.xls': o.bookType = 'biff2'; break; | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| @ -13321,7 +13594,7 @@ function safe_format_cell(cell, v) { | ||||
| } | ||||
| 
 | ||||
| function format_cell(cell, v) { | ||||
| 	if(cell == null || cell.t == null) return ""; | ||||
| 	if(cell == null || cell.t == null || cell.t == 'z') return ""; | ||||
| 	if(cell.w !== undefined) return cell.w; | ||||
| 	if(v === undefined) return safe_format_cell(cell, cell.v); | ||||
| 	return safe_format_cell(cell, v); | ||||
| @ -13376,6 +13649,7 @@ function sheet_to_json(sheet, opts){ | ||||
| 			if(val === undefined || val.t === undefined) continue; | ||||
| 			v = val.v; | ||||
| 			switch(val.t){ | ||||
| 				case 'z': continue; | ||||
| 				case 'e': continue; | ||||
| 				case 's': break; | ||||
| 				case 'b': case 'n': break; | ||||
| @ -13442,6 +13716,7 @@ function sheet_to_formulae(sheet) { | ||||
| 				if(y.indexOf(":") == -1) y = y + ":" + y; | ||||
| 			} | ||||
| 			if(x.f != null) val = x.f; | ||||
| 			else if(x.t == 'z') continue; | ||||
| 			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; | ||||
|  | ||||
							
								
								
									
										22
									
								
								dist/xlsx.min.js
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										22
									
								
								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
											
										
									
								
							
							
								
								
									
										31
									
								
								multiformat.lst
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										31
									
								
								multiformat.lst
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,31 @@ | ||||
| # This file controls the multiformat tests | ||||
| # Format: <basename> <ext> <ext> [ext..] | ||||
| AutoFilter              	.xls .xlsb .xlsx .xml | ||||
| #BlankSheetTypes         	.xls .xlsb .xlsx .xml | ||||
| NumberFormatCondition   	.xls .xlsb .xlsm .xml | ||||
| RkNumber                	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| #calendar_stress_test    	.xls .xlsb .xlsx .xml | ||||
| cell_style_simple       	.xls .xlsb .xlsx .xml | ||||
| # no-csv (newline character \r vs \n) | ||||
| comments_stress_test    	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| # yes-csv | ||||
| custom_properties       	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| defined_names_simple    	.xls .xlsb .xlsx .xml | ||||
| #formula_stress_test     	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| formulae_test_simple    	.xls .xlsb .xlsx .xml | ||||
| hyperlink_stress_test_2011	.xls .xlsb .xlsx .xml | ||||
| #large_strings           	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| merge_cells             	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| named_ranges_2011       	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| # no-csv (macro serialization in xml) | ||||
| number_format           	.xls .xlsb .xlsm .xls.xml .xlsb.xml .xlsm.xml | ||||
| number_format_entities  	.xls .xlsb .xlsx .xml | ||||
| # yes-csv | ||||
| pivot_table_named_range 	.xls .xlsb .xlsx .xml | ||||
| pivot_table_test        	.xls .xlsb .xlsm | ||||
| rich_text_stress        	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| smart_tags_2007         	.xls .xlsb .xlsx .xml | ||||
| sushi                   	.xls .xlsb .xlsx .xml | ||||
| text_and_numbers        	.xls .xlsb .xlsx .xml | ||||
| #time_stress_test_1      	.xls .xlsb .xlsx .xml | ||||
| xlsx-stream-d-date-cell 	.xls .xlsb .xlsx .xls.xml .xlsb.xml .xlsx.xml | ||||
| @ -1,6 +1,6 @@ | ||||
| { | ||||
| 	"name": "xlsx", | ||||
| 	"version": "0.9.2", | ||||
| 	"version": "0.9.3", | ||||
| 	"author": "sheetjs", | ||||
| 	"description": "Excel (XLSB/XLSX/XLSM/XLS/XML) and ODS (ODS/FODS/UOS) spreadsheet parser and writer", | ||||
| 	"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "office", "spreadsheet" ], | ||||
|  | ||||
							
								
								
									
										49
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										49
									
								
								test.js
									
									
									
									
									
								
							| @ -866,13 +866,14 @@ describe('roundtrip features', function() { | ||||
| 
 | ||||
| 	describe('should preserve features', function() { | ||||
| 		it('merge cells', function() { | ||||
| 		["xlsx", "xlsb", "xlml", "ods"].forEach(function(f) { | ||||
| 			var wb1 = X.readFile(paths.mcxlsx); | ||||
| 			var wb2 = X.read(X.write(wb1, {type:'binary'}), {type:'binary'}); | ||||
| 			var wb2 = X.read(X.write(wb1,{bookType:f,type:'binary'}),{type:'binary'}); | ||||
| 			var m1 = wb1.Sheets.Merge['!merges'].map(X.utils.encode_range); | ||||
| 			var m2 = wb2.Sheets.Merge['!merges'].map(X.utils.encode_range); | ||||
| 			assert.equal(m1.length, m2.length); | ||||
| 			for(var i = 0; i < m1.length; ++i) assert.equal(m1[i], m2[i]); | ||||
| 		}); | ||||
| 			for(var i = 0; i < m1.length; ++i) assert(m1.indexOf(m2[i]) > -1); | ||||
| 		}); }); | ||||
| 	}); | ||||
| 
 | ||||
| 	describe('should preserve dates', function() { | ||||
| @ -1204,3 +1205,45 @@ describe('encryption', function() { | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| describe('multiformat tests', function() { | ||||
| var mfopts = opts; | ||||
| var mft = fs.readFileSync('multiformat.lst','utf-8').split("\n"); | ||||
| var csv = true; | ||||
| mft.forEach(function(x) { | ||||
| 	if(x[0]!="#") describe('MFT ' + x, function() { | ||||
| 		var fil = {}, f = [], r = x.split(/\s+/); | ||||
| 		if(r.length < 3) return; | ||||
| 		it('should parse all', function() { | ||||
| 			for(var j = 1; j != r.length; ++j) f[j-1] = X.readFile(dir + r[0] + r[j], mfopts); | ||||
| 		}); | ||||
| 		it('should have the same sheetnames', function() { | ||||
| 			cmparr(f.map(function(x) { return x.SheetNames; })); | ||||
| 		}); | ||||
| 		it('should have the same ranges', function() { | ||||
| 			f[0].SheetNames.forEach(function(s) { | ||||
| 				var ss = f.map(function(x) { return x.Sheets[s]; }); | ||||
| 				cmparr(ss.map(function(s) { return s['!ref']; })); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should have the same merges', function() { | ||||
| 			f[0].SheetNames.forEach(function(s) { | ||||
| 				var ss = f.map(function(x) { return x.Sheets[s]; }); | ||||
| 				cmparr(ss.map(function(s) { return (s['!merges']||[]).map(function(y) { return X.utils.encode_range(y); }).sort(); })); | ||||
| 			}); | ||||
| 		}); | ||||
| 		it('should have the same CSV', csv ? function() { | ||||
| 			cmparr(f.map(function(x) { return x.SheetNames; })); | ||||
| 			var names = f[0].SheetNames; | ||||
| 			names.forEach(function(name) { | ||||
| 				cmparr(f.map(function(x) { return X.utils.sheet_to_csv(x.Sheets[name]); })); | ||||
| 			}); | ||||
| 		} : null); | ||||
| 	}); | ||||
| 	else x.split(/\s+/).forEach(function(w) { switch(w) { | ||||
| 		case "no-csv": csv = false; break; | ||||
| 		case "yes-csv": csv = true; break; | ||||
| 	}}); | ||||
| }); | ||||
| }); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										82
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										82
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ | ||||
| /*exported XLSX */ | ||||
| var XLSX = {}; | ||||
| (function make_xlsx(XLSX){ | ||||
| XLSX.version = '0.9.2'; | ||||
| XLSX.version = '0.9.3'; | ||||
| var current_codepage = 1200, current_cptable; | ||||
| /*:: declare var cptable:any; */ | ||||
| if(typeof module !== "undefined" && typeof require !== 'undefined') { | ||||
| @ -1500,15 +1500,15 @@ var rencstr = "&<>'\"".split(""); | ||||
| // TODO: CP remap (need to read file version to determine OS)
 | ||||
| var unescapexml/*:StringConv*/ = (function() { | ||||
| 	/* 22.4.2.4 bstr (Basic String) */ | ||||
| 	var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	return function unescapexml(text/*:string*/)/*:string*/ { | ||||
| 		var s = text + ''; | ||||
| 		return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 		return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g; | ||||
| function escapexml(text/*:string*/)/*:string*/{ | ||||
| function escapexml(text/*:string*/, xml/*:?boolean*/)/*:string*/{ | ||||
| 	var s = text + ''; | ||||
| 	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";}); | ||||
| } | ||||
| @ -8806,6 +8806,13 @@ function parse_BrtFmlaString(data, length, opts) { | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.676 BrtMergeCell */ | ||||
| var parse_BrtMergeCell = parse_UncheckedRfX; | ||||
| var write_BrtMergeCell = write_UncheckedRfX; | ||||
| /* [MS-XLSB] 2.4.108 BrtBeginMergeCells */ | ||||
| function write_BrtBeginMergeCells(cnt, o) { | ||||
| 	if(o == null) o = new_buf(4); | ||||
| 	o.write_shift(4, cnt); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.656 BrtHLink */ | ||||
| function parse_BrtHLink(data, length, opts) { | ||||
| @ -9147,7 +9154,14 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) { | ||||
| 	write_record(ba, 'BrtEndSheetData'); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx, opts, wb) { | ||||
| function write_MERGECELLS(ba, ws/*:Worksheet*/) { | ||||
| 	if(!ws || !ws['!merges']) return; | ||||
| 	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length)); | ||||
| 	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); }); | ||||
| 	write_record(ba, 'BrtEndMergeCells'); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/) { | ||||
| 	var ba = buf_array(); | ||||
| 	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; | ||||
| 	var r = safe_decode_range(ws['!ref'] || "A1"); | ||||
| @ -9166,7 +9180,7 @@ function write_ws_bin(idx, opts, wb) { | ||||
| 	/* [SORTSTATE] */ | ||||
| 	/* [DCON] */ | ||||
| 	/* [USERSHVIEWS] */ | ||||
| 	/* [MERGECELLS] */ | ||||
| 	write_MERGECELLS(ba, ws); | ||||
| 	/* [BrtPhoneticInfo] */ | ||||
| 	/* *CONDITIONALFORMATTING */ | ||||
| 	/* [DVALS] */ | ||||
| @ -10484,6 +10498,15 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| 	var attr = {}; | ||||
| 	if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr)); | ||||
| 
 | ||||
| 	if(ws['!merges']) { | ||||
| 		var marr = ws['!merges']; | ||||
| 		for(var mi = 0; mi != marr.length; ++mi) { | ||||
| 			if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue; | ||||
| 			if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c; | ||||
| 			if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var t = "", p = ""; | ||||
| 	switch(cell.t) { | ||||
| 		case 'z': return ""; | ||||
| @ -10491,7 +10514,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| 		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break; | ||||
| 		case 'e': t = 'Error'; p = BErr[cell.v]; break; | ||||
| 		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break; | ||||
| 		default:  t = 'String'; p = escapexml(cell.v||""); | ||||
| 		case 's':  t = 'String'; p = escapexml(cell.v||""); break; | ||||
| 	} | ||||
| 	var m = '<Data ss:Type="' + t + '">' + p + '</Data>'; | ||||
| 
 | ||||
| @ -10501,16 +10524,27 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{ | ||||
| function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ { | ||||
| 	if(!ws['!ref']) return ""; | ||||
| 	var range = safe_decode_range(ws['!ref']); | ||||
| 	var marr = ws['!merges'] || [], mi = 0; | ||||
| 	var o = []; | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		var row = ["<Row>"]; | ||||
| 		var row = ['<Row ss:Index="' + (R+1) + '">']; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			var skip = false; | ||||
| 			for(mi = 0; mi != marr.length; ++mi) { | ||||
| 				if(marr[mi].s.c > C) continue; | ||||
| 				if(marr[mi].s.r > R) continue; | ||||
| 				if(marr[mi].e.c < C) continue; | ||||
| 				if(marr[mi].e.r < R) continue; | ||||
| 				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 				break; | ||||
| 			} | ||||
| 			if(skip) continue; | ||||
| 			var addr = {r:R,c:C}; | ||||
| 			var ref = encode_cell(addr), cell = ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr)); | ||||
| 		} | ||||
| 		row.push("</Row>"); | ||||
| 		o.push(row.join("")); | ||||
| 		if(row.length > 2) o.push(row.join("")); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -12756,13 +12790,15 @@ var parse_content_xml = (function() { | ||||
| 						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break; | ||||
| 						case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']); | ||||
| 							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); } | ||||
| 							q.z = 'm/d/yy'; break; | ||||
| 						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break; | ||||
| 						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break; | ||||
| 						default: | ||||
| 							if(q.t === 'string' || q.t === 'text' || !q.t) { | ||||
| 								q.t = 's'; | ||||
| 								if(ctag['string-value'] != null) textp = ctag['string-value']; | ||||
| 								if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']); | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| @ -13045,22 +13081,38 @@ var parse_content_xml = (function() { | ||||
| })(); | ||||
| var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 	var null_cell_xml = '          <table:table-cell />\n'; | ||||
| 	var covered_cell_xml = '          <table:covered-table-cell/>\n'; | ||||
| 	var cell_begin = '          <table:table-cell ', cell_end = '</table:table-cell>\n'; | ||||
| 	var vt = 'office:value-type='; | ||||
| 	var p_begin = '<text:p>', p_end = '</text:p>'; | ||||
| 	var write_ws = function(ws, wb, i/*:number*/, opts)/*:string*/ { | ||||
| 		/* Section 9 Tables */ | ||||
| 		var o = []; | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']); | ||||
| 		var marr = ws['!merges'] || [], mi = 0; | ||||
| 		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n'); | ||||
| 		for(; R <= range.e.r; ++R) { | ||||
| 			o.push('        <table:table-row>\n'); | ||||
| 			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml); | ||||
| 			for(; C <= range.e.c; ++C) { | ||||
| 				var skip = false, mxml = ""; | ||||
| 				for(mi = 0; mi != marr.length; ++mi) { | ||||
| 					if(marr[mi].s.c > C) continue; | ||||
| 					if(marr[mi].s.r > R) continue; | ||||
| 					if(marr[mi].e.c < C) continue; | ||||
| 					if(marr[mi].e.r < R) continue; | ||||
| 					if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 					mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" '; | ||||
| 					break; | ||||
| 				} | ||||
| 				if(skip) { o.push(covered_cell_xml); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = ws[ref]; | ||||
| 				if(cell) switch(cell.t) { | ||||
| 					case 'b': o.push('          <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 'n': o.push('          <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 's': case 'str': o.push('          <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					//case 'd': // TODO
 | ||||
| 					case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break; | ||||
| 					case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break; | ||||
| 					case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break; | ||||
| 					case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break; | ||||
| 					//case 'e':
 | ||||
| 					default: o.push(null_cell_xml); | ||||
| 				} else o.push(null_cell_xml); | ||||
|  | ||||
							
								
								
									
										80
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										80
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -5,7 +5,7 @@ | ||||
| /*exported XLSX */ | ||||
| var XLSX = {}; | ||||
| (function make_xlsx(XLSX){ | ||||
| XLSX.version = '0.9.2'; | ||||
| XLSX.version = '0.9.3'; | ||||
| var current_codepage = 1200, current_cptable; | ||||
| if(typeof module !== "undefined" && typeof require !== 'undefined') { | ||||
| 	if(typeof cptable === 'undefined') cptable = require('./dist/cpexcel.js'); | ||||
| @ -1453,15 +1453,15 @@ var rencstr = "&<>'\"".split(""); | ||||
| // TODO: CP remap (need to read file version to determine OS)
 | ||||
| var unescapexml = (function() { | ||||
| 	/* 22.4.2.4 bstr (Basic String) */ | ||||
| 	var encregex = /&[a-z]*;/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g; | ||||
| 	return function unescapexml(text) { | ||||
| 		var s = text + ''; | ||||
| 		return s.replace(encregex, function($$) { return encodings[$$]; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 		return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));}); | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g; | ||||
| function escapexml(text){ | ||||
| function escapexml(text, xml){ | ||||
| 	var s = text + ''; | ||||
| 	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";}); | ||||
| } | ||||
| @ -8753,6 +8753,13 @@ function parse_BrtFmlaString(data, length, opts) { | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.676 BrtMergeCell */ | ||||
| var parse_BrtMergeCell = parse_UncheckedRfX; | ||||
| var write_BrtMergeCell = write_UncheckedRfX; | ||||
| /* [MS-XLSB] 2.4.108 BrtBeginMergeCells */ | ||||
| function write_BrtBeginMergeCells(cnt, o) { | ||||
| 	if(o == null) o = new_buf(4); | ||||
| 	o.write_shift(4, cnt); | ||||
| 	return o; | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLSB] 2.4.656 BrtHLink */ | ||||
| function parse_BrtHLink(data, length, opts) { | ||||
| @ -9094,6 +9101,13 @@ function write_CELLTABLE(ba, ws, idx, opts, wb) { | ||||
| 	write_record(ba, 'BrtEndSheetData'); | ||||
| } | ||||
| 
 | ||||
| function write_MERGECELLS(ba, ws) { | ||||
| 	if(!ws || !ws['!merges']) return; | ||||
| 	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length)); | ||||
| 	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); }); | ||||
| 	write_record(ba, 'BrtEndMergeCells'); | ||||
| } | ||||
| 
 | ||||
| function write_ws_bin(idx, opts, wb) { | ||||
| 	var ba = buf_array(); | ||||
| 	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; | ||||
| @ -9113,7 +9127,7 @@ function write_ws_bin(idx, opts, wb) { | ||||
| 	/* [SORTSTATE] */ | ||||
| 	/* [DCON] */ | ||||
| 	/* [USERSHVIEWS] */ | ||||
| 	/* [MERGECELLS] */ | ||||
| 	write_MERGECELLS(ba, ws); | ||||
| 	/* [BrtPhoneticInfo] */ | ||||
| 	/* *CONDITIONALFORMATTING */ | ||||
| 	/* [DVALS] */ | ||||
| @ -10427,6 +10441,15 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){ | ||||
| 	var attr = {}; | ||||
| 	if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr)); | ||||
| 
 | ||||
| 	if(ws['!merges']) { | ||||
| 		var marr = ws['!merges']; | ||||
| 		for(var mi = 0; mi != marr.length; ++mi) { | ||||
| 			if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue; | ||||
| 			if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c; | ||||
| 			if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	var t = "", p = ""; | ||||
| 	switch(cell.t) { | ||||
| 		case 'z': return ""; | ||||
| @ -10434,7 +10457,7 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){ | ||||
| 		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break; | ||||
| 		case 'e': t = 'Error'; p = BErr[cell.v]; break; | ||||
| 		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break; | ||||
| 		default:  t = 'String'; p = escapexml(cell.v||""); | ||||
| 		case 's':  t = 'String'; p = escapexml(cell.v||""); break; | ||||
| 	} | ||||
| 	var m = '<Data ss:Type="' + t + '">' + p + '</Data>'; | ||||
| 
 | ||||
| @ -10444,16 +10467,27 @@ function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){ | ||||
| function write_ws_xlml_table(ws, opts, idx, wb) { | ||||
| 	if(!ws['!ref']) return ""; | ||||
| 	var range = safe_decode_range(ws['!ref']); | ||||
| 	var marr = ws['!merges'] || [], mi = 0; | ||||
| 	var o = []; | ||||
| 	for(var R = range.s.r; R <= range.e.r; ++R) { | ||||
| 		var row = ["<Row>"]; | ||||
| 		var row = ['<Row ss:Index="' + (R+1) + '">']; | ||||
| 		for(var C = range.s.c; C <= range.e.c; ++C) { | ||||
| 			var skip = false; | ||||
| 			for(mi = 0; mi != marr.length; ++mi) { | ||||
| 				if(marr[mi].s.c > C) continue; | ||||
| 				if(marr[mi].s.r > R) continue; | ||||
| 				if(marr[mi].e.c < C) continue; | ||||
| 				if(marr[mi].e.r < R) continue; | ||||
| 				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 				break; | ||||
| 			} | ||||
| 			if(skip) continue; | ||||
| 			var addr = {r:R,c:C}; | ||||
| 			var ref = encode_cell(addr), cell = ws[ref]; | ||||
| 			row.push(write_ws_xlml_cell(ws[ref], ref, ws, opts, idx, wb, addr)); | ||||
| 		} | ||||
| 		row.push("</Row>"); | ||||
| 		o.push(row.join("")); | ||||
| 		if(row.length > 2) o.push(row.join("")); | ||||
| 	} | ||||
| 	return o.join(""); | ||||
| } | ||||
| @ -12699,13 +12733,15 @@ var parse_content_xml = (function() { | ||||
| 						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break; | ||||
| 						case 'date': q.t = 'n'; q.v = datenum(new Date(ctag['date-value'])); q.z = 'm/d/yy'; break; | ||||
| 						case 'date': q.t = 'd'; q.v = new Date(ctag['date-value']); | ||||
| 							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); } | ||||
| 							q.z = 'm/d/yy'; break; | ||||
| 						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break; | ||||
| 						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break; | ||||
| 						default: | ||||
| 							if(q.t === 'string' || q.t === 'text' || !q.t) { | ||||
| 								q.t = 's'; | ||||
| 								if(ctag['string-value'] != null) textp = ctag['string-value']; | ||||
| 								if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']); | ||||
| 							} else throw new Error('Unsupported value type ' + q.t); | ||||
| 					} | ||||
| 				} else { | ||||
| @ -12988,22 +13024,38 @@ var parse_content_xml = (function() { | ||||
| })(); | ||||
| var write_content_xml = (function() { | ||||
| 	var null_cell_xml = '          <table:table-cell />\n'; | ||||
| 	var covered_cell_xml = '          <table:covered-table-cell/>\n'; | ||||
| 	var cell_begin = '          <table:table-cell ', cell_end = '</table:table-cell>\n'; | ||||
| 	var vt = 'office:value-type='; | ||||
| 	var p_begin = '<text:p>', p_end = '</text:p>'; | ||||
| 	var write_ws = function(ws, wb, i, opts) { | ||||
| 		/* Section 9 Tables */ | ||||
| 		var o = []; | ||||
| 		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n'); | ||||
| 		var R=0,C=0, range = decode_range(ws['!ref']); | ||||
| 		var marr = ws['!merges'] || [], mi = 0; | ||||
| 		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n'); | ||||
| 		for(; R <= range.e.r; ++R) { | ||||
| 			o.push('        <table:table-row>\n'); | ||||
| 			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml); | ||||
| 			for(; C <= range.e.c; ++C) { | ||||
| 				var skip = false, mxml = ""; | ||||
| 				for(mi = 0; mi != marr.length; ++mi) { | ||||
| 					if(marr[mi].s.c > C) continue; | ||||
| 					if(marr[mi].s.r > R) continue; | ||||
| 					if(marr[mi].e.c < C) continue; | ||||
| 					if(marr[mi].e.r < R) continue; | ||||
| 					if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true; | ||||
| 					mxml = 'table:number-columns-spanned="' + (marr[mi].e.c - marr[mi].s.c + 1) + '" table:number-rows-spanned="' + (marr[mi].e.r - marr[mi].s.r + 1) + '" '; | ||||
| 					break; | ||||
| 				} | ||||
| 				if(skip) { o.push(covered_cell_xml); continue; } | ||||
| 				var ref = encode_cell({r:R, c:C}), cell = ws[ref]; | ||||
| 				if(cell) switch(cell.t) { | ||||
| 					case 'b': o.push('          <table:table-cell office:value-type="boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '"><text:p>' + (cell.v ? 'TRUE' : 'FALSE') + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 'n': o.push('          <table:table-cell office:value-type="float" office:value="' + cell.v + '"><text:p>' + (cell.w||cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					case 's': case 'str': o.push('          <table:table-cell office:value-type="string"><text:p>' + escapexml(cell.v) + '</text:p></table:table-cell>\n'); break; | ||||
| 					//case 'd': // TODO
 | ||||
| 					case 'b': o.push(cell_begin + mxml + vt + '"boolean" office:boolean-value="' + (cell.v ? 'true' : 'false') + '">' + p_begin + (cell.v ? 'TRUE' : 'FALSE') + p_end + cell_end); break; | ||||
| 					case 'n': o.push(cell_begin + mxml + vt + '"float" office:value="' + cell.v + '">' + p_begin + (cell.w||cell.v) + p_end + cell_end); break; | ||||
| 					case 's': case 'str': o.push(cell_begin + mxml + vt + '"string">' + p_begin + escapexml(cell.v) + p_end + cell_end); break; | ||||
| 					case 'd': o.push(cell_begin + mxml + vt + '"date" office:date-value="' + (new Date(cell.v).toISOString()) + '">' + p_begin + (cell.w||(new Date(cell.v).toISOString())) + p_end + cell_end); break; | ||||
| 					//case 'e':
 | ||||
| 					default: o.push(null_cell_xml); | ||||
| 				} else o.push(null_cell_xml); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user