forked from sheetjs/sheetjs
		
	more formats from js-harb
- clarify usage of Props and Custprops (fixes #274 h/t @michahell) - SYLK from js-harb - DIF from js-harb - HTML empty string bug fix
This commit is contained in:
		
							parent
							
								
									e42cf43c02
								
							
						
					
					
						commit
						b93569badf
					
				| @ -39,3 +39,5 @@ test.js | ||||
| bits/ | ||||
| docbits/ | ||||
| tests/ | ||||
| _book | ||||
| book.json | ||||
|  | ||||
							
								
								
									
										85
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										85
									
								
								README.md
									
									
									
									
									
								
							| @ -38,9 +38,10 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
|     + [Data Types](#data-types) | ||||
|     + [Dates](#dates) | ||||
|   * [Sheet Objects](#sheet-objects) | ||||
|   * [Worksheet Object](#worksheet-object) | ||||
|   * [Chartsheet Object](#chartsheet-object) | ||||
|     + [Worksheet Object](#worksheet-object) | ||||
|     + [Chartsheet Object](#chartsheet-object) | ||||
|   * [Workbook Object](#workbook-object) | ||||
|     + [Workbook File Properties](#workbook-file-properties) | ||||
|   * [Document Features](#document-features) | ||||
|     + [Formulae](#formulae) | ||||
|     + [Column Properties](#column-properties) | ||||
| @ -65,9 +66,12 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
|   * [Excel 2003-2004 (SpreadsheetML)](#excel-2003-2004-spreadsheetml) | ||||
|   * [Excel 2007+ Binary (XLSB, BIFF12)](#excel-2007-binary-xlsb-biff12) | ||||
|   * [OpenDocument Spreadsheet (ODS/FODS) and Uniform Office Spreadsheet (UOS1/2)](#opendocument-spreadsheet-odsfods-and-uniform-office-spreadsheet-uos12) | ||||
|   * [dBASE and Visual FoxPro (DBF)](#dbase-and-visual-foxpro-dbf) | ||||
|   * [Comma-Separated Values](#comma-separated-values) | ||||
|   * [HTML](#html) | ||||
|   * [Comma-Separated Values (CSV)](#comma-separated-values-csv) | ||||
|   * [Other Single-Worksheet Formats](#other-single-worksheet-formats) | ||||
|     + [dBASE and Visual FoxPro (DBF)](#dbase-and-visual-foxpro-dbf) | ||||
|     + [Symbolic Link (SYLK)](#symbolic-link-sylk) | ||||
|     + [Data Interchange Format (DIF)](#data-interchange-format-dif) | ||||
|     + [HTML](#html) | ||||
| - [Testing](#testing) | ||||
|   * [Tested Environments](#tested-environments) | ||||
|   * [Test Files](#test-files) | ||||
| @ -545,7 +549,7 @@ Special sheet keys (accessible as `sheet[key]`, each starting with `!`): | ||||
|   When reading a worksheet with the `sheetRows` property set, the ref parameter | ||||
|   will use the restricted range.  The original range is set at `ws['!fullref']` | ||||
| 
 | ||||
| ### Worksheet Object | ||||
| #### Worksheet Object | ||||
| 
 | ||||
| In addition to the base sheet keys, worksheets also add: | ||||
| 
 | ||||
| @ -560,7 +564,7 @@ In addition to the base sheet keys, worksheets also add: | ||||
|   will write all cells in the merge range if they exist, so be sure that only | ||||
|   the first cell (upper-left) in the range is set. | ||||
| 
 | ||||
| ### Chartsheet Object | ||||
| #### Chartsheet Object | ||||
| 
 | ||||
| Chartsheets are represented as standard sheets.  They are distinguished with the | ||||
| `!type` property set to `"chart"`. | ||||
| @ -576,7 +580,7 @@ first row of the chartsheet is the underlying header. | ||||
| 
 | ||||
| `wb.Props` is an object storing the standard properties.  `wb.Custprops` stores | ||||
| custom properties.  Since the XLS standard properties deviate from the XLSX | ||||
| standard, XLS parsing stores core properties in both places.  . | ||||
| standard, XLS parsing stores core properties in both places. | ||||
| 
 | ||||
| `wb.WBProps` includes more workbook-level properties: | ||||
| 
 | ||||
| @ -585,6 +589,38 @@ standard, XLS parsing stores core properties in both places.  . | ||||
|   The workbook's epoch can be determined by examining the workbook's | ||||
|   `wb.WBProps.date1904` property. | ||||
| 
 | ||||
| #### Workbook File Properties | ||||
| 
 | ||||
| The various file formats use different internal names for file properties.  The | ||||
| workbook `Props` object normalizes the names: | ||||
| 
 | ||||
| | JS Name     | Excel Description              | | ||||
| |:------------|:-------------------------------| | ||||
| | Title       | Summary tab "Title"            | | ||||
| | Subject     | Summary tab "Subject"          | | ||||
| | Author      | Summary tab "Author"           | | ||||
| | Manager     | Summary tab "Manager"          | | ||||
| | Company     | Summary tab "Company"          | | ||||
| | Category    | Summary tab "Category"         | | ||||
| | Keywords    | Summary tab "Keywords"         | | ||||
| | Comments    | Summary tab "Comments"         | | ||||
| | LastAuthor  | Statistics tab "Last saved by" | | ||||
| | CreatedDate | Statistics tab "Created"       | | ||||
| 
 | ||||
| For example, to set the workbook title property: | ||||
| 
 | ||||
| ```js | ||||
| if(!wb.Props) wb.Props = {}; | ||||
| wb.Props.Title = "Insert Title Here"; | ||||
| ``` | ||||
| 
 | ||||
| Custom properties are added in the workbook `Custprops` object: | ||||
| 
 | ||||
| ```js | ||||
| if(!wb.Custprops) wb.Custprops = {}; | ||||
| wb.Custprops["Custom Property"] = "Custom Value"; | ||||
| ``` | ||||
| 
 | ||||
| ### Document Features | ||||
| 
 | ||||
| Even for basic features like date storage, the official Excel formats store the | ||||
| @ -818,6 +854,8 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| | `0x09` | BIFF Stream   | BIFF 2/3/4/5                                        | | ||||
| | `0x3C` | XML/HTML      | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x50` | ZIP Archive   | XLSB or XLSX/M or ODS or UOS2 or plaintext          | | ||||
| | `0x49` | Plain Text    | SYLK or plaintext                                   | | ||||
| | `0x54` | Plain Text    | DIF or plaintext                                    | | ||||
| | `0xFE` | UTF8 Text     | SpreadsheetML or Flat ODS or UOS1 or plaintext      | | ||||
| 
 | ||||
| DBF files are detected based on the first byte as well as the third and fourth | ||||
| @ -858,6 +896,8 @@ output formats.  The specific file type is controlled with `bookType` option: | ||||
| | `biff2`  | `.xls`   |   none    | single | Excel 2.0 Worksheet format        | | ||||
| | `fods`   | `.fods`  |   none    | multi  | Flat OpenDocument Spreadsheet     | | ||||
| | `csv`    | `.csv`   |   none    | single | Comma Separated Values            | | ||||
| | `sylk`   | `.sylk`  |   none    | single | Symbolic Link (SYLK)              | | ||||
| | `dif`    | `.dif`   |   none    | single | Data Interchange Format (DIF)     | | ||||
| 
 | ||||
| - `compression` only applies to formats with ZIP containers. | ||||
| - Formats that only support a single sheet require a `sheet` option specifying | ||||
| @ -1088,6 +1128,8 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats: | ||||
| | Excel 2.0/2.1 (XLS BIFF2)                                    |  :o:  |  :o:  | | ||||
| | **Excel Supported Text Formats**                             |:-----:|:-----:| | ||||
| | Delimiter-Separated Values (CSV/TSV/DSV)                     |       |  :o:  | | ||||
| | Data Interchange Format (DIF)                                |  :o:  |  :o:  | | ||||
| | Symbolic Link (SYLK/SLK)                                     |  :o:  |  :o:  | | ||||
| | **Other Workbook/Worksheet Formats**                         |:-----:|:-----:| | ||||
| | OpenDocument Spreadsheet (ODS)                               |  :o:  |  :o:  | | ||||
| | Flat XML ODF Spreadsheet (FODS)                              |  :o:  |  :o:  | | ||||
| @ -1153,7 +1195,17 @@ UOS is a very similar format, and it comes in 2 varieties corresponding to ODS | ||||
| and FODS respectively.  For the most part, the difference between the formats | ||||
| lies in the names of tags and attributes. | ||||
| 
 | ||||
| ### dBASE and Visual FoxPro (DBF) | ||||
| ### Comma-Separated Values (CSV) | ||||
| 
 | ||||
| Excel CSV deviates from RFC4180 in a number of important ways.  The generated | ||||
| CSV files should generally work in Excel although they may not work in RFC4180 | ||||
| compatible readers. | ||||
| 
 | ||||
| ### Other Single-Worksheet Formats | ||||
| 
 | ||||
| Many older formats supported only one worksheet: | ||||
| 
 | ||||
| #### dBASE and Visual FoxPro (DBF) | ||||
| 
 | ||||
| DBF is really a typed table format: each column can only hold one data type and | ||||
| each record omits type information.  The parser generates a header row and | ||||
| @ -1162,13 +1214,18 @@ inserts records starting at the second row of the worksheet. | ||||
| Multi-file extensions like external memos and tables are currently unsupported, | ||||
| limited by the general ability to read arbitrary files in the web browser. | ||||
| 
 | ||||
| ### Comma-Separated Values | ||||
| #### Symbolic Link (SYLK) | ||||
| 
 | ||||
| Excel CSV deviates from RFC4180 in a number of important ways.  The generated | ||||
| CSV files should generally work in Excel although they may not work in RFC4180 | ||||
| compatible readers. | ||||
| There is no real documentation.  All knowledge was gathered by saving files in | ||||
| various versions of Excel to deduce the meaning of fields. | ||||
| 
 | ||||
| ### HTML | ||||
| #### Data Interchange Format (DIF) | ||||
| 
 | ||||
| There is no unified definition.  Visicalc DIF differs from Lotus DIF, and both | ||||
| differ from Excel DIF.  Where ambiguous, the parser/writer follows the expected | ||||
| behavior from Excel. | ||||
| 
 | ||||
| #### HTML | ||||
| 
 | ||||
| Excel HTML worksheets include special metadata encoded in styles.  For example, | ||||
| `mso-number-format` is a localized string containing the number format.  Despite | ||||
|  | ||||
							
								
								
									
										12
									
								
								bin/xlsx.njs
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										12
									
								
								bin/xlsx.njs
									
									
									
									
									
								
							| @ -27,6 +27,8 @@ program | ||||
| 	.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('-D, --dif', 'emit data interchange format (dif)') | ||||
| 	.option('-K, --sylk', 'emit symbolic link (sylk)') | ||||
| 
 | ||||
| 	.option('-F, --field-sep <sep>', 'CSV field separator', ",") | ||||
| 	.option('-R, --row-sep <sep>', 'CSV row separator', "\n") | ||||
| @ -162,9 +164,13 @@ try { | ||||
| if(program.perf) process.exit(0); | ||||
| 
 | ||||
| /* single worksheet XLS formats */ | ||||
| ['biff2'].forEach(function(m) { if(program[m]) { | ||||
| 		wopts.bookType = m; | ||||
| 		X.writeFile(wb, sheetname || ((filename || "") + ".xls"), wopts); | ||||
| [ | ||||
| 	['biff2', '.xls'], | ||||
| 	['sylk', '.slk'], | ||||
| 	['dif', '.dif'] | ||||
| ].forEach(function(m) { if(program[m[0]]) { | ||||
| 		wopts.bookType = m[0]; | ||||
| 		X.writeFile(wb, sheetname || ((filename || "") + m[1]), wopts); | ||||
| 		process.exit(0); | ||||
| } }); | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										177
									
								
								bits/40_harb.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										177
									
								
								bits/40_harb.js
									
									
									
									
									
								
							| @ -182,3 +182,180 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ { | ||||
| 		to_sheet: dbf_to_sheet | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var SYLK = (function() { | ||||
| 	/* TODO: find an actual specification */ | ||||
| 	function sylk_to_aoa(d/*:RawData*/, opts)/*:AOA*/ { | ||||
| 		switch(opts.type) { | ||||
| 			case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts); | ||||
| 			case 'binary': return sylk_to_aoa_str(d, opts); | ||||
| 			case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts); | ||||
| 			case 'array': return sylk_to_aoa_str(cc2str(d), opts); | ||||
| 		} | ||||
| 		throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| 	function sylk_to_aoa_str(str/*:string*/, opts)/*:AOA*/ { | ||||
| 		var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = []; | ||||
| 		var formats = []; | ||||
| 		var next_cell_format = null; | ||||
| 		for (; ri !== records.length; ++ri) { | ||||
| 			var record = records[ri].trim().split(";"); | ||||
| 			var RT = record[0], val; | ||||
| 			if(RT === 'P') for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'P': | ||||
| 					formats.push(record[rj].substr(1)); | ||||
| 					break; | ||||
| 			} | ||||
| 			else if(RT !== 'C' && RT !== 'F') continue; | ||||
| 			else for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'Y': | ||||
| 					R = parseInt(record[rj].substr(1))-1; C = 0; | ||||
| 					for(var j = arr.length; j <= R; ++j) arr[j] = []; | ||||
| 					break; | ||||
| 				case 'X': C = parseInt(record[rj].substr(1))-1; break; | ||||
| 				case 'K': | ||||
| 					val = record[rj].substr(1); | ||||
| 					if(val.charAt(0) === '"') val = val.substr(1,val.length - 2); | ||||
| 					else if(val === 'TRUE') val = true; | ||||
| 					else if(val === 'FALSE') val = false; | ||||
| 					else if(+val === +val) { | ||||
| 						val = +val; | ||||
| 						if(next_cell_format !== null && next_cell_format.match(/[ymdhmsYMDHMS]/)) val = numdate(val); | ||||
| 					} | ||||
| 					arr[R][C] = val; | ||||
| 					next_cell_format = null; | ||||
| 					break; | ||||
| 				case 'P': | ||||
| 					if(RT !== 'F') break; | ||||
| 					next_cell_format = formats[parseInt(record[rj].substr(1))]; | ||||
| 			} | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function sylk_to_sheet(str/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(sylk_to_aoa(str, opts), opts); } | ||||
| 
 | ||||
| 	function sylk_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(sylk_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*/, opts)/*:string*/ { | ||||
| 		var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K"; | ||||
| 		switch(cell.t) { | ||||
| 			case 'n': o += cell.v; break; | ||||
| 			case 'b': o += cell.v ? "TRUE" : "FALSE"; break; | ||||
| 			case 'e': o += cell.w || cell.v; break; | ||||
| 			case 'd': o += '"' + (cell.w || cell.v) + '"'; break; | ||||
| 			case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break; | ||||
| 		} | ||||
| 		return o; | ||||
| 	} | ||||
| 
 | ||||
| 	function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 		var preamble/*:Array<string>*/ = ["ID;PWXL;N;E"], o/*:Array<string>*/ = []; | ||||
| 		preamble.push("P;PGeneral"); | ||||
| 		var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 				var coord = encode_cell({r:R,c:C}); | ||||
| 				if(!(cell = ws[coord]) || cell.v == null) continue; | ||||
| 				o.push(write_ws_cell_sylk(cell, ws, R, C, opts)); | ||||
| 			} | ||||
| 		} | ||||
| 		preamble.push("F;P0;DG0G8;M255"); | ||||
| 		var RS = "\r\n"; | ||||
| 		return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS; | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		to_workbook: sylk_to_workbook, | ||||
| 		to_sheet: sylk_to_sheet, | ||||
| 		from_sheet: sheet_to_sylk | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var DIF = (function() { | ||||
| 	function dif_to_aoa(d/*:RawData*/, opts)/*:AOA*/ { | ||||
| 		switch(opts.type) { | ||||
| 			case 'base64': return dif_to_aoa_str(Base64.decode(d), opts); | ||||
| 			case 'binary': return dif_to_aoa_str(d, opts); | ||||
| 			case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts); | ||||
| 			case 'array': return dif_to_aoa_str(cc2str(d), opts); | ||||
| 		} | ||||
| 		throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| 	function dif_to_aoa_str(str/*:string*/, opts)/*:AOA*/ { | ||||
| 		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = []; | ||||
| 		for (; ri !== records.length; ++ri) { | ||||
| 			if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; } | ||||
| 			if (R < 0) continue; | ||||
| 			var metadata = records[ri].trim().split(","); | ||||
| 			var type = metadata[0], value = metadata[1]; | ||||
| 			++ri; | ||||
| 			var data = records[ri].trim(); | ||||
| 			switch (+type) { | ||||
| 				case -1: | ||||
| 					if (data === 'BOT') { arr[++R] = []; C = 0; continue; } | ||||
| 					else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data); | ||||
| 					break; | ||||
| 				case 0: | ||||
| 					if(data === 'TRUE') arr[R][C] = true; | ||||
| 					else if(data === 'FALSE') arr[R][C] = false; | ||||
| 					else if(+value == +value) arr[R][C] = +value; | ||||
| 					else if(!isNaN(new Date(value).getDate())) arr[R][C] = new Date(value); | ||||
| 					else arr[R][C] = value; | ||||
| 					++C; break; | ||||
| 				case 1: | ||||
| 					data = data.substr(1,data.length-2); | ||||
| 					arr[R][C++] = data !== '' ? data : null; | ||||
| 					break; | ||||
| 			} | ||||
| 			if (data === 'EOD') break; | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function dif_to_sheet(str/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(dif_to_aoa(str, opts), opts); } | ||||
| 	function dif_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(dif_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	var sheet_to_dif = (function() { | ||||
| 		var push_field = function pf(o/*:Array<string>*/, topic/*:string*/, v/*:number*/, n/*:number*/, s/*:string*/) { | ||||
| 			o.push(topic); | ||||
| 			o.push(v + "," + n); | ||||
| 			o.push('"' + s.replace(/"/g,'""') + '"'); | ||||
| 		}; | ||||
| 		var push_value = function po(o/*:Array<string>*/, type/*:number*/, v/*:number*/, s/*:string*/) { | ||||
| 			o.push(type + "," + v); | ||||
| 			o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s); | ||||
| 		}; | ||||
| 		return function sheet_to_dif(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 			var o/*:Array<string>*/ = []; | ||||
| 			var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 			push_field(o, "TABLE", 0, 1, "sheetjs"); | ||||
| 			push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,""); | ||||
| 			push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,""); | ||||
| 			push_field(o, "DATA", 0, 0,""); | ||||
| 			for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 				push_value(o, -1, 0, "BOT"); | ||||
| 				for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 					var coord = encode_cell({r:R,c:C}); | ||||
| 					if(!(cell = ws[coord]) || cell.v == null) { push_value(o, 1, 0, ""); continue;} | ||||
| 					switch(cell.t) { | ||||
| 						case 'n': push_value(o, 0, (/*cell.w ||*/ cell.v), "V"); break; | ||||
| 						case 'b': push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE"); break; | ||||
| 						case 's': push_value(o, 1, 0, cell.v); break; | ||||
| 						default: push_value(o, 1, 0, ""); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			push_value(o, -1, 0, "EOD"); | ||||
| 			var RS = "\r\n"; | ||||
| 			var oo = o.join(RS); | ||||
| 			//while((oo.length & 0x7F) != 0) oo += "\0";
 | ||||
| 			return oo; | ||||
| 		}; | ||||
| 	})(); | ||||
| 	return { | ||||
| 		to_workbook: dif_to_workbook, | ||||
| 		to_sheet: dif_to_sheet, | ||||
| 		from_sheet: sheet_to_dif | ||||
| 	}; | ||||
| })(); | ||||
|  | ||||
| @ -53,12 +53,13 @@ function parse_dom_table(table/*:HTMLElement*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0) merges.push({s:{r:R,c:C},e:{r:R + RS - 1, c:C + CS - 1}}); | ||||
| 			var o = {t:'s', v:v}; | ||||
| 			if(!isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			if(v != null && v.length && !isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			ws[encode_cell({c:C, r:R})] = o; | ||||
| 			C += CS; | ||||
| 		} | ||||
| 	} | ||||
| 	ws['!merges'] = merges; | ||||
| 	ws['!ref'] = encode_range(range); | ||||
| 	return ws; | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -5,3 +5,15 @@ function write_csv_str(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| 	if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 	return sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| } | ||||
| 
 | ||||
| function write_obj_str(factory) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| 		var idx = 0; | ||||
| 		for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i; | ||||
| 		if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 		return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_slk_str = write_obj_str(SYLK); | ||||
| var write_dif_str = write_obj_str(DIF); | ||||
|  | ||||
| @ -34,7 +34,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	/*::if(!wb.Props) throw "unreachable"; */ | ||||
| 	f = "docProps/app.xml"; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	/*:: else if(!wb.Props) throw "unreachable"; */ | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
|  | ||||
| @ -33,6 +33,8 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xD0: return parse_xlscfb(CFB.read(d, o), o); | ||||
| 		case 0x09: return parse_xlscfb(s2a(o.type === 'base64' ? Base64.decode(d) : d), o); | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] == 0x44) return SYLK.to_workbook(d, o); break; | ||||
| 		case 0x54: if(n[1] == 0x41 && n[2] == 0x42 && n[3] == 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: if(n[1] == 0x4B && n[2] < 0x20 && n[3] < 0x20) return read_zip(d, o); break; | ||||
| 		case 0xEF: return parse_xlml(d, o); | ||||
| 		case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o); | ||||
|  | ||||
| @ -48,7 +48,10 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 	switch(o.bookType || 'xlsx') { | ||||
| 		case 'xml': | ||||
| 		case 'xlml': return write_string_type(write_xlml(wb, o), o); | ||||
| 		case 'slk': | ||||
| 		case 'sylk': return write_string_type(write_slk_str(wb, o), o); | ||||
| 		case 'csv': return write_string_type(write_csv_str(wb, o), o); | ||||
| 		case 'dif': return write_string_type(write_dif_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); | ||||
| 		case 'xlsx': | ||||
| @ -66,11 +69,14 @@ function resolve_book_type(o/*?WriteFileOpts*/) { | ||||
| 		case '.xlsb': o.bookType = 'xlsb'; break; | ||||
| 		case '.fods': o.bookType = 'fods'; break; | ||||
| 		case '.xlml': o.bookType = 'xlml'; break; | ||||
| 		case '.sylk': o.bookType = 'sylk'; break; | ||||
| 	default: switch(o.file.slice(-4).toLowerCase()) { | ||||
| 		case '.xls': o.bookType = 'biff2'; break; | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| 		case '.ods': o.bookType = 'ods'; break; | ||||
| 		case '.csv': o.bookType = 'csv'; break; | ||||
| 		case '.dif': o.bookType = 'dif'; break; | ||||
| 		case '.slk': o.bookType = 'sylk'; break; | ||||
| 	}} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| ### Worksheet Object | ||||
| #### Worksheet Object | ||||
| 
 | ||||
| In addition to the base sheet keys, worksheets also add: | ||||
| 
 | ||||
| @ -13,7 +13,7 @@ In addition to the base sheet keys, worksheets also add: | ||||
|   will write all cells in the merge range if they exist, so be sure that only | ||||
|   the first cell (upper-left) in the range is set. | ||||
| 
 | ||||
| ### Chartsheet Object | ||||
| #### Chartsheet Object | ||||
| 
 | ||||
| Chartsheets are represented as standard sheets.  They are distinguished with the | ||||
| `!type` property set to `"chart"`. | ||||
|  | ||||
| @ -6,7 +6,7 @@ | ||||
| 
 | ||||
| `wb.Props` is an object storing the standard properties.  `wb.Custprops` stores | ||||
| custom properties.  Since the XLS standard properties deviate from the XLSX | ||||
| standard, XLS parsing stores core properties in both places.  . | ||||
| standard, XLS parsing stores core properties in both places. | ||||
| 
 | ||||
| `wb.WBProps` includes more workbook-level properties: | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										32
									
								
								docbits/56_wbprops.md
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										32
									
								
								docbits/56_wbprops.md
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,32 @@ | ||||
| #### Workbook File Properties | ||||
| 
 | ||||
| The various file formats use different internal names for file properties.  The | ||||
| workbook `Props` object normalizes the names: | ||||
| 
 | ||||
| | JS Name     | Excel Description              | | ||||
| |:------------|:-------------------------------| | ||||
| | Title       | Summary tab "Title"            | | ||||
| | Subject     | Summary tab "Subject"          | | ||||
| | Author      | Summary tab "Author"           | | ||||
| | Manager     | Summary tab "Manager"          | | ||||
| | Company     | Summary tab "Company"          | | ||||
| | Category    | Summary tab "Category"         | | ||||
| | Keywords    | Summary tab "Keywords"         | | ||||
| | Comments    | Summary tab "Comments"         | | ||||
| | LastAuthor  | Statistics tab "Last saved by" | | ||||
| | CreatedDate | Statistics tab "Created"       | | ||||
| 
 | ||||
| For example, to set the workbook title property: | ||||
| 
 | ||||
| ```js | ||||
| if(!wb.Props) wb.Props = {}; | ||||
| wb.Props.Title = "Insert Title Here"; | ||||
| ``` | ||||
| 
 | ||||
| Custom properties are added in the workbook `Custprops` object: | ||||
| 
 | ||||
| ```js | ||||
| if(!wb.Custprops) wb.Custprops = {}; | ||||
| wb.Custprops["Custom Property"] = "Custom Value"; | ||||
| ``` | ||||
| 
 | ||||
| @ -65,6 +65,8 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| | `0x09` | BIFF Stream   | BIFF 2/3/4/5                                        | | ||||
| | `0x3C` | XML/HTML      | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x50` | ZIP Archive   | XLSB or XLSX/M or ODS or UOS2 or plaintext          | | ||||
| | `0x49` | Plain Text    | SYLK or plaintext                                   | | ||||
| | `0x54` | Plain Text    | DIF or plaintext                                    | | ||||
| | `0xFE` | UTF8 Text     | SpreadsheetML or Flat ODS or UOS1 or plaintext      | | ||||
| 
 | ||||
| DBF files are detected based on the first byte as well as the third and fourth | ||||
|  | ||||
| @ -33,6 +33,8 @@ output formats.  The specific file type is controlled with `bookType` option: | ||||
| | `biff2`  | `.xls`   |   none    | single | Excel 2.0 Worksheet format        | | ||||
| | `fods`   | `.fods`  |   none    | multi  | Flat OpenDocument Spreadsheet     | | ||||
| | `csv`    | `.csv`   |   none    | single | Comma Separated Values            | | ||||
| | `sylk`   | `.sylk`  |   none    | single | Symbolic Link (SYLK)              | | ||||
| | `dif`    | `.dif`   |   none    | single | Data Interchange Format (DIF)     | | ||||
| 
 | ||||
| - `compression` only applies to formats with ZIP containers. | ||||
| - Formats that only support a single sheet require a `sheet` option specifying | ||||
|  | ||||
| @ -15,6 +15,8 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats: | ||||
| | Excel 2.0/2.1 (XLS BIFF2)                                    |  :o:  |  :o:  | | ||||
| | **Excel Supported Text Formats**                             |:-----:|:-----:| | ||||
| | Delimiter-Separated Values (CSV/TSV/DSV)                     |       |  :o:  | | ||||
| | Data Interchange Format (DIF)                                |  :o:  |  :o:  | | ||||
| | Symbolic Link (SYLK/SLK)                                     |  :o:  |  :o:  | | ||||
| | **Other Workbook/Worksheet Formats**                         |:-----:|:-----:| | ||||
| | OpenDocument Spreadsheet (ODS)                               |  :o:  |  :o:  | | ||||
| | Flat XML ODF Spreadsheet (FODS)                              |  :o:  |  :o:  | | ||||
| @ -80,7 +82,17 @@ UOS is a very similar format, and it comes in 2 varieties corresponding to ODS | ||||
| and FODS respectively.  For the most part, the difference between the formats | ||||
| lies in the names of tags and attributes. | ||||
| 
 | ||||
| ### dBASE and Visual FoxPro (DBF) | ||||
| ### Comma-Separated Values (CSV) | ||||
| 
 | ||||
| Excel CSV deviates from RFC4180 in a number of important ways.  The generated | ||||
| CSV files should generally work in Excel although they may not work in RFC4180 | ||||
| compatible readers. | ||||
| 
 | ||||
| ### Other Single-Worksheet Formats | ||||
| 
 | ||||
| Many older formats supported only one worksheet: | ||||
| 
 | ||||
| #### dBASE and Visual FoxPro (DBF) | ||||
| 
 | ||||
| DBF is really a typed table format: each column can only hold one data type and | ||||
| each record omits type information.  The parser generates a header row and | ||||
| @ -89,13 +101,18 @@ inserts records starting at the second row of the worksheet. | ||||
| Multi-file extensions like external memos and tables are currently unsupported, | ||||
| limited by the general ability to read arbitrary files in the web browser. | ||||
| 
 | ||||
| ### Comma-Separated Values | ||||
| #### Symbolic Link (SYLK) | ||||
| 
 | ||||
| Excel CSV deviates from RFC4180 in a number of important ways.  The generated | ||||
| CSV files should generally work in Excel although they may not work in RFC4180 | ||||
| compatible readers. | ||||
| There is no real documentation.  All knowledge was gathered by saving files in | ||||
| various versions of Excel to deduce the meaning of fields. | ||||
| 
 | ||||
| ### HTML | ||||
| #### Data Interchange Format (DIF) | ||||
| 
 | ||||
| There is no unified definition.  Visicalc DIF differs from Lotus DIF, and both | ||||
| differ from Excel DIF.  Where ambiguous, the parser/writer follows the expected | ||||
| behavior from Excel. | ||||
| 
 | ||||
| #### HTML | ||||
| 
 | ||||
| Excel HTML worksheets include special metadata encoded in styles.  For example, | ||||
| `mso-number-format` is a localized string containing the number format.  Despite | ||||
|  | ||||
							
								
								
									
										10
									
								
								formats.dot
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										10
									
								
								formats.dot
									
									
									
									
									
								
							| @ -1,5 +1,5 @@ | ||||
| digraph G { | ||||
| 	graph [mindist=0.1];  | ||||
| 	graph [mindist=0.1]; | ||||
| 	csf [shape=doublecircle,label="Common\nSpreadsheet\nFormat\n(JS Object)"]; | ||||
| 	subgraph XL { | ||||
| 		node  [style=filled,color=green]; | ||||
| @ -17,7 +17,7 @@ digraph G { | ||||
| 		node  [style=filled,color=yellow]; | ||||
| 		ods   [label="ODS"]; | ||||
| 		fods  [label="Flat\nODS"]; | ||||
| 		uos   [label="UOS\n标文通"]; | ||||
| 		uos   [label="UOS"]; | ||||
| 	} | ||||
| 
 | ||||
| 	subgraph OLD { | ||||
| @ -25,6 +25,8 @@ digraph G { | ||||
| 		html  [label="HTML\nTable"]; | ||||
| 		csv   [label="CSV"]; | ||||
| 		dbf   [label="DBF"]; | ||||
| 		dif   [label="DIF"]; | ||||
| 		slk   [label="SYLK"]; | ||||
| 	} | ||||
| 
 | ||||
| 	subgraph JSXLSX { | ||||
| @ -41,6 +43,10 @@ digraph G { | ||||
| 		xls4 -> csf | ||||
| 		xls5 -> csf | ||||
| 		xls8 -> csf | ||||
| 		csf -> slk | ||||
| 		slk -> csf | ||||
| 		csf -> dif | ||||
| 		dif -> csf | ||||
| 		csf -> csv | ||||
| 		ods -> csf | ||||
| 		csf -> ods | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								formats.png
									
									
									
									
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								formats.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 84 KiB After Width: | Height: | Size: 94 KiB | 
| @ -18,9 +18,10 @@ | ||||
|     + [Data Types](README.md#data-types) | ||||
|     + [Dates](README.md#dates) | ||||
|   * [Sheet Objects](README.md#sheet-objects) | ||||
|   * [Worksheet Object](README.md#worksheet-object) | ||||
|   * [Chartsheet Object](README.md#chartsheet-object) | ||||
|     + [Worksheet Object](README.md#worksheet-object) | ||||
|     + [Chartsheet Object](README.md#chartsheet-object) | ||||
|   * [Workbook Object](README.md#workbook-object) | ||||
|     + [Workbook File Properties](README.md#workbook-file-properties) | ||||
|   * [Document Features](README.md#document-features) | ||||
|     + [Formulae](README.md#formulae) | ||||
|     + [Column Properties](README.md#column-properties) | ||||
| @ -45,9 +46,12 @@ | ||||
|   * [Excel 2003-2004 (SpreadsheetML)](README.md#excel-2003-2004-spreadsheetml) | ||||
|   * [Excel 2007+ Binary (XLSB, BIFF12)](README.md#excel-2007-binary-xlsb-biff12) | ||||
|   * [OpenDocument Spreadsheet (ODS/FODS) and Uniform Office Spreadsheet (UOS1/2)](README.md#opendocument-spreadsheet-odsfods-and-uniform-office-spreadsheet-uos12) | ||||
|   * [dBASE and Visual FoxPro (DBF)](README.md#dbase-and-visual-foxpro-dbf) | ||||
|   * [Comma-Separated Values](README.md#comma-separated-values) | ||||
|   * [HTML](README.md#html) | ||||
|   * [Comma-Separated Values (CSV)](README.md#comma-separated-values-csv) | ||||
|   * [Other Single-Worksheet Formats](README.md#other-single-worksheet-formats) | ||||
|     + [dBASE and Visual FoxPro (DBF)](README.md#dbase-and-visual-foxpro-dbf) | ||||
|     + [Symbolic Link (SYLK)](README.md#symbolic-link-sylk) | ||||
|     + [Data Interchange Format (DIF)](README.md#data-interchange-format-dif) | ||||
|     + [HTML](README.md#html) | ||||
| - [Testing](README.md#testing) | ||||
|   * [Tested Environments](README.md#tested-environments) | ||||
|   * [Test Files](README.md#test-files) | ||||
|  | ||||
							
								
								
									
										43
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										43
									
								
								test.js
									
									
									
									
									
								
							| @ -12,7 +12,7 @@ if(process.env.WTF) { | ||||
| 	opts.cellStyles = true; | ||||
| } | ||||
| var fullex = [".xlsb", ".xlsm", ".xlsx"/*, ".xlml"*/]; | ||||
| var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "xlml"]; | ||||
| var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "xlml", "sylk", "dif"]; | ||||
| var ex = fullex.slice(); ex = ex.concat([".ods", ".xls", ".xml", ".fods"]); | ||||
| if(process.env.FMTS === "full") process.env.FMTS = ex.join(":"); | ||||
| if(process.env.FMTS) ex=process.env.FMTS.split(":").map(function(x){return x[0]==="."?x:"."+x;}); | ||||
| @ -951,26 +951,31 @@ describe('roundtrip features', function() { | ||||
| 	var bef = (function() { X = require(modp); }); | ||||
| 	if(typeof before != 'undefined') before(bef); | ||||
| 	else it('before', bef); | ||||
| 	describe('should parse core properties and custom properties', function() { | ||||
| 		var wb1, wb2, base = './tmp/cp'; | ||||
| 		var bef = (function() { | ||||
| 			wb1 = X.readFile(paths.cpxlsx); | ||||
| 			wb2 = X.readFile(paths.cpxlsb); | ||||
| 			fullex.forEach(function(p) { | ||||
| 				X.writeFile(wb1, base + '.xlsm' + p); | ||||
| 				X.writeFile(wb2, base + '.xlsb' + p); | ||||
| 			}); | ||||
| 	describe('should preserve core properties', function() { [ | ||||
| 		['xlml', paths.cpxml], | ||||
| 		['xlsx', paths.cpxlsx], | ||||
| 		['xlsb', paths.cpxlsb] | ||||
| 	].forEach(function(w) { | ||||
| 		it(w[0], function() { | ||||
| 				var wb1 = X.readFile(w[1]); | ||||
| 				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"buffer"}), {type:"buffer"}); | ||||
| 				coreprop(wb1); | ||||
| 				coreprop(wb2); | ||||
| 		}); | ||||
| 		if(typeof before != 'undefined') before(bef); | ||||
| 		else it('before', bef); | ||||
| 		fullex.forEach(function(p) { ['.xlsm','.xlsb'].forEach(function(q) { | ||||
| 			it(q + p + ' should roundtrip core and custom properties', function() { | ||||
| 				var wb = X.readFile(base + q + p); | ||||
| 				coreprop(wb); | ||||
| 				custprop(wb); | ||||
| 			}); }); | ||||
| 	}); }); | ||||
| 
 | ||||
| 	describe('should preserve custom properties', function() { [ | ||||
| 		['xlml', paths.cpxml], | ||||
| 		['xlsx', paths.cpxlsx], | ||||
| 		['xlsb', paths.cpxlsb] | ||||
| 	].forEach(function(w) { | ||||
| 		it(w[0], function() { | ||||
| 				var wb1 = X.readFile(w[1]); | ||||
| 				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"buffer"}), {type:"buffer"}); | ||||
| 				custprop(wb1); | ||||
| 				custprop(wb2); | ||||
| 		}); | ||||
| 	}); | ||||
| 	}); }); | ||||
| 
 | ||||
| 	describe('should preserve features', function() { | ||||
| 		it('merge cells', function() { | ||||
|  | ||||
| @ -81,12 +81,25 @@ console.log("Worksheet Model:") | ||||
| console.log(ws); | ||||
| 
 | ||||
| /* TEST: hidden sheets */ | ||||
| 
 | ||||
| wb.SheetNames.push("Hidden"); | ||||
| wb.Sheets["Hidden"] = XLSX.utils.aoa_to_sheet(["Hidden".split(""), [1,2,3]]); | ||||
| wb.Workbook = {Sheets:[]}; | ||||
| wb.Workbook.Sheets[1] = {Hidden:1}; | ||||
| 
 | ||||
| /* TEST: properties */ | ||||
| wb.Props = { | ||||
| 	Title: "SheetJS Test", | ||||
| 	Subject: "Tests", | ||||
| 	Author: "Devs at SheetJS", | ||||
| 	Manager: "Sheet Manager", | ||||
| 	Company: "SheetJS", | ||||
| 	Category: "Experimentation", | ||||
| 	Keywords: "Test", | ||||
| 	Comments: "Nothing to say here", | ||||
| 	LastAuthor: "Not SheetJS", | ||||
| 	CreatedDate: new Date(2017,1,19) | ||||
| } | ||||
| 
 | ||||
| /* write file */ | ||||
| XLSX.writeFile(wb, 'sheetjs.xlsx', {bookSST:true}); | ||||
| XLSX.writeFile(wb, 'sheetjs.xlsm'); | ||||
| @ -95,6 +108,7 @@ XLSX.writeFile(wb, 'sheetjs.xls', {bookType:'biff2'}); // no formula | ||||
| XLSX.writeFile(wb, 'sheetjs.xml.xls', {bookType:'xlml'}); | ||||
| XLSX.writeFile(wb, 'sheetjs.ods'); | ||||
| XLSX.writeFile(wb, 'sheetjs.fods'); | ||||
| XLSX.writeFile(wb, 'sheetjs.slk'); | ||||
| XLSX.writeFile(wb, 'sheetjs.csv'); | ||||
| 
 | ||||
| /* test by reading back files */ | ||||
| @ -105,4 +119,5 @@ XLSX.readFile('sheetjs.xls'); | ||||
| XLSX.readFile('sheetjs.xml.xls'); | ||||
| XLSX.readFile('sheetjs.ods'); | ||||
| XLSX.readFile('sheetjs.fods'); | ||||
| XLSX.readFile('sheetjs.slk'); | ||||
| //XLSX.readFile('sheetjs.csv');
 | ||||
|  | ||||
							
								
								
									
										202
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										202
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -4932,6 +4932,183 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ { | ||||
| 		to_sheet: dbf_to_sheet | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var SYLK = (function() { | ||||
| 	/* TODO: find an actual specification */ | ||||
| 	function sylk_to_aoa(d/*:RawData*/, opts)/*:AOA*/ { | ||||
| 		switch(opts.type) { | ||||
| 			case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts); | ||||
| 			case 'binary': return sylk_to_aoa_str(d, opts); | ||||
| 			case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts); | ||||
| 			case 'array': return sylk_to_aoa_str(cc2str(d), opts); | ||||
| 		} | ||||
| 		throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| 	function sylk_to_aoa_str(str/*:string*/, opts)/*:AOA*/ { | ||||
| 		var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = []; | ||||
| 		var formats = []; | ||||
| 		var next_cell_format = null; | ||||
| 		for (; ri !== records.length; ++ri) { | ||||
| 			var record = records[ri].trim().split(";"); | ||||
| 			var RT = record[0], val; | ||||
| 			if(RT === 'P') for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'P': | ||||
| 					formats.push(record[rj].substr(1)); | ||||
| 					break; | ||||
| 			} | ||||
| 			else if(RT !== 'C' && RT !== 'F') continue; | ||||
| 			else for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'Y': | ||||
| 					R = parseInt(record[rj].substr(1))-1; C = 0; | ||||
| 					for(var j = arr.length; j <= R; ++j) arr[j] = []; | ||||
| 					break; | ||||
| 				case 'X': C = parseInt(record[rj].substr(1))-1; break; | ||||
| 				case 'K': | ||||
| 					val = record[rj].substr(1); | ||||
| 					if(val.charAt(0) === '"') val = val.substr(1,val.length - 2); | ||||
| 					else if(val === 'TRUE') val = true; | ||||
| 					else if(val === 'FALSE') val = false; | ||||
| 					else if(+val === +val) { | ||||
| 						val = +val; | ||||
| 						if(next_cell_format !== null && next_cell_format.match(/[ymdhmsYMDHMS]/)) val = numdate(val); | ||||
| 					} | ||||
| 					arr[R][C] = val; | ||||
| 					next_cell_format = null; | ||||
| 					break; | ||||
| 				case 'P': | ||||
| 					if(RT !== 'F') break; | ||||
| 					next_cell_format = formats[parseInt(record[rj].substr(1))]; | ||||
| 			} | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function sylk_to_sheet(str/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(sylk_to_aoa(str, opts), opts); } | ||||
| 
 | ||||
| 	function sylk_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(sylk_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*/, opts)/*:string*/ { | ||||
| 		var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K"; | ||||
| 		switch(cell.t) { | ||||
| 			case 'n': o += cell.v; break; | ||||
| 			case 'b': o += cell.v ? "TRUE" : "FALSE"; break; | ||||
| 			case 'e': o += cell.w || cell.v; break; | ||||
| 			case 'd': o += '"' + (cell.w || cell.v) + '"'; break; | ||||
| 			case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break; | ||||
| 		} | ||||
| 		return o; | ||||
| 	} | ||||
| 
 | ||||
| 	function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 		var preamble/*:Array<string>*/ = ["ID;PWXL;N;E"], o/*:Array<string>*/ = []; | ||||
| 		preamble.push("P;PGeneral"); | ||||
| 		var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 				var coord = encode_cell({r:R,c:C}); | ||||
| 				if(!(cell = ws[coord]) || cell.v == null) continue; | ||||
| 				o.push(write_ws_cell_sylk(cell, ws, R, C, opts)); | ||||
| 			} | ||||
| 		} | ||||
| 		preamble.push("F;P0;DG0G8;M255"); | ||||
| 		var RS = "\r\n"; | ||||
| 		return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS; | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		to_workbook: sylk_to_workbook, | ||||
| 		to_sheet: sylk_to_sheet, | ||||
| 		from_sheet: sheet_to_sylk | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var DIF = (function() { | ||||
| 	function dif_to_aoa(d/*:RawData*/, opts)/*:AOA*/ { | ||||
| 		switch(opts.type) { | ||||
| 			case 'base64': return dif_to_aoa_str(Base64.decode(d), opts); | ||||
| 			case 'binary': return dif_to_aoa_str(d, opts); | ||||
| 			case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts); | ||||
| 			case 'array': return dif_to_aoa_str(cc2str(d), opts); | ||||
| 		} | ||||
| 		throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| 	function dif_to_aoa_str(str/*:string*/, opts)/*:AOA*/ { | ||||
| 		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = []; | ||||
| 		for (; ri !== records.length; ++ri) { | ||||
| 			if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; } | ||||
| 			if (R < 0) continue; | ||||
| 			var metadata = records[ri].trim().split(","); | ||||
| 			var type = metadata[0], value = metadata[1]; | ||||
| 			++ri; | ||||
| 			var data = records[ri].trim(); | ||||
| 			switch (+type) { | ||||
| 				case -1: | ||||
| 					if (data === 'BOT') { arr[++R] = []; C = 0; continue; } | ||||
| 					else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data); | ||||
| 					break; | ||||
| 				case 0: | ||||
| 					if(data === 'TRUE') arr[R][C] = true; | ||||
| 					else if(data === 'FALSE') arr[R][C] = false; | ||||
| 					else if(+value == +value) arr[R][C] = +value; | ||||
| 					else if(!isNaN(new Date(value).getDate())) arr[R][C] = new Date(value); | ||||
| 					else arr[R][C] = value; | ||||
| 					++C; break; | ||||
| 				case 1: | ||||
| 					data = data.substr(1,data.length-2); | ||||
| 					arr[R][C++] = data !== '' ? data : null; | ||||
| 					break; | ||||
| 			} | ||||
| 			if (data === 'EOD') break; | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function dif_to_sheet(str/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(dif_to_aoa(str, opts), opts); } | ||||
| 	function dif_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(dif_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	var sheet_to_dif = (function() { | ||||
| 		var push_field = function pf(o/*:Array<string>*/, topic/*:string*/, v/*:number*/, n/*:number*/, s/*:string*/) { | ||||
| 			o.push(topic); | ||||
| 			o.push(v + "," + n); | ||||
| 			o.push('"' + s.replace(/"/g,'""') + '"'); | ||||
| 		}; | ||||
| 		var push_value = function po(o/*:Array<string>*/, type/*:number*/, v/*:number*/, s/*:string*/) { | ||||
| 			o.push(type + "," + v); | ||||
| 			o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s); | ||||
| 		}; | ||||
| 		return function sheet_to_dif(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 			var o/*:Array<string>*/ = []; | ||||
| 			var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 			push_field(o, "TABLE", 0, 1, "sheetjs"); | ||||
| 			push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,""); | ||||
| 			push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,""); | ||||
| 			push_field(o, "DATA", 0, 0,""); | ||||
| 			for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 				push_value(o, -1, 0, "BOT"); | ||||
| 				for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 					var coord = encode_cell({r:R,c:C}); | ||||
| 					if(!(cell = ws[coord]) || cell.v == null) { push_value(o, 1, 0, ""); continue;} | ||||
| 					switch(cell.t) { | ||||
| 						case 'n': push_value(o, 0, (/*cell.w ||*/ cell.v), "V"); break; | ||||
| 						case 'b': push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE"); break; | ||||
| 						case 's': push_value(o, 1, 0, cell.v); break; | ||||
| 						default: push_value(o, 1, 0, ""); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			push_value(o, -1, 0, "EOD"); | ||||
| 			var RS = "\r\n"; | ||||
| 			var oo = o.join(RS); | ||||
| 			//while((oo.length & 0x7F) != 0) oo += "\0";
 | ||||
| 			return oo; | ||||
| 		}; | ||||
| 	})(); | ||||
| 	return { | ||||
| 		to_workbook: dif_to_workbook, | ||||
| 		to_sheet: dif_to_sheet, | ||||
| 		from_sheet: sheet_to_dif | ||||
| 	}; | ||||
| })(); | ||||
| /* 18.4.1 charset to codepage mapping */ | ||||
| var CS2CP = ({ | ||||
| 	/*::[*/0/*::]*/:    1252, /* ANSI */ | ||||
| @ -13729,12 +13906,13 @@ function parse_dom_table(table/*:HTMLElement*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0) merges.push({s:{r:R,c:C},e:{r:R + RS - 1, c:C + CS - 1}}); | ||||
| 			var o = {t:'s', v:v}; | ||||
| 			if(!isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			if(v != null && v.length && !isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			ws[encode_cell({c:C, r:R})] = o; | ||||
| 			C += CS; | ||||
| 		} | ||||
| 	} | ||||
| 	ws['!merges'] = merges; | ||||
| 	ws['!ref'] = encode_range(range); | ||||
| 	return ws; | ||||
| } | ||||
| 
 | ||||
| @ -14218,6 +14396,18 @@ function write_csv_str(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| 	if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 	return sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| } | ||||
| 
 | ||||
| function write_obj_str(factory) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| 		var idx = 0; | ||||
| 		for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i; | ||||
| 		if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 		return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_slk_str = write_obj_str(SYLK); | ||||
| var write_dif_str = write_obj_str(DIF); | ||||
| /* Part 3: Packages */ | ||||
| function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) { | ||||
| 	opts = opts || ({}/*:any*/); | ||||
| @ -14510,7 +14700,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 	/*::if(!wb.Props) throw "unreachable"; */ | ||||
| 	f = "docProps/app.xml"; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	/*:: else if(!wb.Props) throw "unreachable"; */ | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| @ -14606,6 +14796,8 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xD0: return parse_xlscfb(CFB.read(d, o), o); | ||||
| 		case 0x09: return parse_xlscfb(s2a(o.type === 'base64' ? Base64.decode(d) : d), o); | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] == 0x44) return SYLK.to_workbook(d, o); break; | ||||
| 		case 0x54: if(n[1] == 0x41 && n[2] == 0x42 && n[3] == 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: if(n[1] == 0x4B && n[2] < 0x20 && n[3] < 0x20) return read_zip(d, o); break; | ||||
| 		case 0xEF: return parse_xlml(d, o); | ||||
| 		case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o); | ||||
| @ -14669,7 +14861,10 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 	switch(o.bookType || 'xlsx') { | ||||
| 		case 'xml': | ||||
| 		case 'xlml': return write_string_type(write_xlml(wb, o), o); | ||||
| 		case 'slk': | ||||
| 		case 'sylk': return write_string_type(write_slk_str(wb, o), o); | ||||
| 		case 'csv': return write_string_type(write_csv_str(wb, o), o); | ||||
| 		case 'dif': return write_string_type(write_dif_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); | ||||
| 		case 'xlsx': | ||||
| @ -14687,11 +14882,14 @@ function resolve_book_type(o/*?WriteFileOpts*/) { | ||||
| 		case '.xlsb': o.bookType = 'xlsb'; break; | ||||
| 		case '.fods': o.bookType = 'fods'; break; | ||||
| 		case '.xlml': o.bookType = 'xlml'; break; | ||||
| 		case '.sylk': o.bookType = 'sylk'; break; | ||||
| 	default: switch(o.file.slice(-4).toLowerCase()) { | ||||
| 		case '.xls': o.bookType = 'biff2'; break; | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| 		case '.ods': o.bookType = 'ods'; break; | ||||
| 		case '.csv': o.bookType = 'csv'; break; | ||||
| 		case '.dif': o.bookType = 'dif'; break; | ||||
| 		case '.slk': o.bookType = 'sylk'; break; | ||||
| 	}} | ||||
| } | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										203
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										203
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -4878,6 +4878,183 @@ function dbf_to_workbook(buf, opts) { | ||||
| 		to_sheet: dbf_to_sheet | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var SYLK = (function() { | ||||
| 	/* TODO: find an actual specification */ | ||||
| 	function sylk_to_aoa(d, opts) { | ||||
| 		switch(opts.type) { | ||||
| 			case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts); | ||||
| 			case 'binary': return sylk_to_aoa_str(d, opts); | ||||
| 			case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts); | ||||
| 			case 'array': return sylk_to_aoa_str(cc2str(d), opts); | ||||
| 		} | ||||
| 		throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| 	function sylk_to_aoa_str(str, opts) { | ||||
| 		var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = []; | ||||
| 		var formats = []; | ||||
| 		var next_cell_format = null; | ||||
| 		for (; ri !== records.length; ++ri) { | ||||
| 			var record = records[ri].trim().split(";"); | ||||
| 			var RT = record[0], val; | ||||
| 			if(RT === 'P') for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'P': | ||||
| 					formats.push(record[rj].substr(1)); | ||||
| 					break; | ||||
| 			} | ||||
| 			else if(RT !== 'C' && RT !== 'F') continue; | ||||
| 			else for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'Y': | ||||
| 					R = parseInt(record[rj].substr(1))-1; C = 0; | ||||
| 					for(var j = arr.length; j <= R; ++j) arr[j] = []; | ||||
| 					break; | ||||
| 				case 'X': C = parseInt(record[rj].substr(1))-1; break; | ||||
| 				case 'K': | ||||
| 					val = record[rj].substr(1); | ||||
| 					if(val.charAt(0) === '"') val = val.substr(1,val.length - 2); | ||||
| 					else if(val === 'TRUE') val = true; | ||||
| 					else if(val === 'FALSE') val = false; | ||||
| 					else if(+val === +val) { | ||||
| 						val = +val; | ||||
| 						if(next_cell_format !== null && next_cell_format.match(/[ymdhmsYMDHMS]/)) val = numdate(val); | ||||
| 					} | ||||
| 					arr[R][C] = val; | ||||
| 					next_cell_format = null; | ||||
| 					break; | ||||
| 				case 'P': | ||||
| 					if(RT !== 'F') break; | ||||
| 					next_cell_format = formats[parseInt(record[rj].substr(1))]; | ||||
| 			} | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function sylk_to_sheet(str, opts) { return aoa_to_sheet(sylk_to_aoa(str, opts), opts); } | ||||
| 
 | ||||
| 	function sylk_to_workbook(str, opts) { return sheet_to_workbook(sylk_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	function write_ws_cell_sylk(cell, ws, R, C, opts) { | ||||
| 		var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K"; | ||||
| 		switch(cell.t) { | ||||
| 			case 'n': o += cell.v; break; | ||||
| 			case 'b': o += cell.v ? "TRUE" : "FALSE"; break; | ||||
| 			case 'e': o += cell.w || cell.v; break; | ||||
| 			case 'd': o += '"' + (cell.w || cell.v) + '"'; break; | ||||
| 			case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break; | ||||
| 		} | ||||
| 		return o; | ||||
| 	} | ||||
| 
 | ||||
| 	function sheet_to_sylk(ws, opts) { | ||||
| 		var preamble = ["ID;PWXL;N;E"], o = []; | ||||
| 		preamble.push("P;PGeneral"); | ||||
| 		var r = decode_range(ws['!ref']), cell; | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 				var coord = encode_cell({r:R,c:C}); | ||||
| 				if(!(cell = ws[coord]) || cell.v == null) continue; | ||||
| 				o.push(write_ws_cell_sylk(cell, ws, R, C, opts)); | ||||
| 			} | ||||
| 		} | ||||
| 		preamble.push("F;P0;DG0G8;M255"); | ||||
| 		var RS = "\r\n"; | ||||
| 		return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS; | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		to_workbook: sylk_to_workbook, | ||||
| 		to_sheet: sylk_to_sheet, | ||||
| 		from_sheet: sheet_to_sylk | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| var DIF = (function() { | ||||
| 	function dif_to_aoa(d, opts) { | ||||
| 		switch(opts.type) { | ||||
| 			case 'base64': return dif_to_aoa_str(Base64.decode(d), opts); | ||||
| 			case 'binary': return dif_to_aoa_str(d, opts); | ||||
| 			case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts); | ||||
| 			case 'array': return dif_to_aoa_str(cc2str(d), opts); | ||||
| 		} | ||||
| 		throw new Error("Unrecognized type " + opts.type); | ||||
| 	} | ||||
| 	function dif_to_aoa_str(str, opts) { | ||||
| 		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = []; | ||||
| 		for (; ri !== records.length; ++ri) { | ||||
| 			if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; } | ||||
| 			if (R < 0) continue; | ||||
| 			var metadata = records[ri].trim().split(","); | ||||
| 			var type = metadata[0], value = metadata[1]; | ||||
| 			++ri; | ||||
| 			var data = records[ri].trim(); | ||||
| 			switch (+type) { | ||||
| 				case -1: | ||||
| 					if (data === 'BOT') { arr[++R] = []; C = 0; continue; } | ||||
| 					else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data); | ||||
| 					break; | ||||
| 				case 0: | ||||
| 					if(data === 'TRUE') arr[R][C] = true; | ||||
| 					else if(data === 'FALSE') arr[R][C] = false; | ||||
| 					else if(+value == +value) arr[R][C] = +value; | ||||
| 					else if(!isNaN(new Date(value).getDate())) arr[R][C] = new Date(value); | ||||
| 					else arr[R][C] = value; | ||||
| 					++C; break; | ||||
| 				case 1: | ||||
| 					data = data.substr(1,data.length-2); | ||||
| 					arr[R][C++] = data !== '' ? data : null; | ||||
| 					break; | ||||
| 			} | ||||
| 			if (data === 'EOD') break; | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| 
 | ||||
| 	function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); } | ||||
| 	function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	var sheet_to_dif = (function() { | ||||
| 		var push_field = function pf(o, topic, v, n, s) { | ||||
| 			o.push(topic); | ||||
| 			o.push(v + "," + n); | ||||
| 			o.push('"' + s.replace(/"/g,'""') + '"'); | ||||
| 		}; | ||||
| 		var push_value = function po(o, type, v, s) { | ||||
| 			o.push(type + "," + v); | ||||
| 			o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s); | ||||
| 		}; | ||||
| 		return function sheet_to_dif(ws, opts) { | ||||
| 			var o = []; | ||||
| 			var r = decode_range(ws['!ref']), cell; | ||||
| 			push_field(o, "TABLE", 0, 1, "sheetjs"); | ||||
| 			push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,""); | ||||
| 			push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,""); | ||||
| 			push_field(o, "DATA", 0, 0,""); | ||||
| 			for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 				push_value(o, -1, 0, "BOT"); | ||||
| 				for(var C = r.s.c; C <= r.e.c; ++C) { | ||||
| 					var coord = encode_cell({r:R,c:C}); | ||||
| 					if(!(cell = ws[coord]) || cell.v == null) { push_value(o, 1, 0, ""); continue;} | ||||
| 					switch(cell.t) { | ||||
| 						case 'n': push_value(o, 0, (/*cell.w ||*/ cell.v), "V"); break; | ||||
| 						case 'b': push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE"); break; | ||||
| 						case 's': push_value(o, 1, 0, cell.v); break; | ||||
| 						default: push_value(o, 1, 0, ""); | ||||
| 					} | ||||
| 				} | ||||
| 			} | ||||
| 			push_value(o, -1, 0, "EOD"); | ||||
| 			var RS = "\r\n"; | ||||
| 			var oo = o.join(RS); | ||||
| 			//while((oo.length & 0x7F) != 0) oo += "\0";
 | ||||
| 			return oo; | ||||
| 		}; | ||||
| 	})(); | ||||
| 	return { | ||||
| 		to_workbook: dif_to_workbook, | ||||
| 		to_sheet: dif_to_sheet, | ||||
| 		from_sheet: sheet_to_dif | ||||
| 	}; | ||||
| })(); | ||||
| /* 18.4.1 charset to codepage mapping */ | ||||
| var CS2CP = ({ | ||||
| 0:    1252, /* ANSI */ | ||||
| @ -13670,12 +13847,13 @@ function parse_dom_table(table, opts) { | ||||
| 			CS = +elt.getAttribute("colspan") || 1; | ||||
| 			if((RS = +elt.getAttribute("rowspan"))>0) merges.push({s:{r:R,c:C},e:{r:R + RS - 1, c:C + CS - 1}}); | ||||
| 			var o = {t:'s', v:v}; | ||||
| 			if(!isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			if(v != null && v.length && !isNaN(Number(v))) o = {t:'n', v:Number(v)}; | ||||
| 			ws[encode_cell({c:C, r:R})] = o; | ||||
| 			C += CS; | ||||
| 		} | ||||
| 	} | ||||
| 	ws['!merges'] = merges; | ||||
| 	ws['!ref'] = encode_range(range); | ||||
| 	return ws; | ||||
| } | ||||
| 
 | ||||
| @ -14159,6 +14337,18 @@ function write_csv_str(wb, o) { | ||||
| 	if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 	return sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| } | ||||
| 
 | ||||
| function write_obj_str(factory) { | ||||
| 	return function write_str(wb, o) { | ||||
| 		var idx = 0; | ||||
| 		for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i; | ||||
| 		if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet); | ||||
| 		return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_slk_str = write_obj_str(SYLK); | ||||
| var write_dif_str = write_obj_str(DIF); | ||||
| /* Part 3: Packages */ | ||||
| function parse_ods(zip, opts) { | ||||
| 	opts = opts || ({}); | ||||
| @ -14448,7 +14638,8 @@ var zip = new jszip(); | ||||
| 
 | ||||
| f = "docProps/app.xml"; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| @ -14542,6 +14733,8 @@ function readSync(data, opts) { | ||||
| 		case 0xD0: return parse_xlscfb(CFB.read(d, o), o); | ||||
| 		case 0x09: return parse_xlscfb(s2a(o.type === 'base64' ? Base64.decode(d) : d), o); | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] == 0x44) return SYLK.to_workbook(d, o); break; | ||||
| 		case 0x54: if(n[1] == 0x41 && n[2] == 0x42 && n[3] == 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: if(n[1] == 0x4B && n[2] < 0x20 && n[3] < 0x20) return read_zip(d, o); break; | ||||
| 		case 0xEF: return parse_xlml(d, o); | ||||
| 		case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o); | ||||
| @ -14605,7 +14798,10 @@ function writeSync(wb, opts) { | ||||
| 	switch(o.bookType || 'xlsx') { | ||||
| 		case 'xml': | ||||
| 		case 'xlml': return write_string_type(write_xlml(wb, o), o); | ||||
| 		case 'slk': | ||||
| 		case 'sylk': return write_string_type(write_slk_str(wb, o), o); | ||||
| 		case 'csv': return write_string_type(write_csv_str(wb, o), o); | ||||
| 		case 'dif': return write_string_type(write_dif_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); | ||||
| 		case 'xlsx': | ||||
| @ -14623,11 +14819,14 @@ function resolve_book_type(o/*?WriteFileOpts*/) { | ||||
| 		case '.xlsb': o.bookType = 'xlsb'; break; | ||||
| 		case '.fods': o.bookType = 'fods'; break; | ||||
| 		case '.xlml': o.bookType = 'xlml'; break; | ||||
| 		case '.sylk': o.bookType = 'sylk'; break; | ||||
| 	default: switch(o.file.slice(-4).toLowerCase()) { | ||||
| 		case '.xls': o.bookType = 'biff2'; break; | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| 		case '.ods': o.bookType = 'ods'; break; | ||||
| 		case '.csv': o.bookType = 'csv'; break; | ||||
| 		case '.dif': o.bookType = 'dif'; break; | ||||
| 		case '.slk': o.bookType = 'sylk'; break; | ||||
| 	}} | ||||
| } | ||||
| 
 | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user