forked from sheetjs/sheetjs
		
	TXT/PRN
- UTF-16 Unicode Text (TXT) write - Lotus Formatted Text (PRN) read/write - DBF version 2 field length adjustments - throw errors if SheetNames is invalid (fixes #376 h/t @pietersv)
This commit is contained in:
		
							parent
							
								
									3a310bd3a7
								
							
						
					
					
						commit
						b9dae134f2
					
				| @ -9,6 +9,7 @@ changes may not be included if they are not expected to break existing code. | ||||
| 
 | ||||
| * default output format changed to XLSB | ||||
| * comment text line endings are now normalized | ||||
| * errors thrown on write when worksheets have invalid names | ||||
| 
 | ||||
| ## 0.9.7 (2017-03-28) | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										7
									
								
								Makefile
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								Makefile
									
									
									
									
									
								
							| @ -75,9 +75,12 @@ bytes: ## display minified and gzipped file sizes | ||||
| 	for i in dist/xlsx.min.js dist/xlsx.{core,full}.min.js; do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done | ||||
| 
 | ||||
| .PHONY: graph | ||||
| graph: formats.png ## Rebuild format conversion graph
 | ||||
| graph: formats.png legend.png ## Rebuild format conversion graph
 | ||||
| formats.png: formats.dot | ||||
| 	circo -Tpng -o$@ $< | ||||
| legend.png: misc/legend.dot | ||||
| 	dot -Tpng -o$@ $< | ||||
| 
 | ||||
| 
 | ||||
| .PHONY: nexe | ||||
| nexe: xlsx.exe ## Build nexe standalone executable
 | ||||
| @ -176,7 +179,7 @@ readme: README.md ## Update README Table of Contents | ||||
| 	markdown-toc -i README.md | ||||
| 
 | ||||
| .PHONY: book | ||||
| book: README.md ## Update summary for documentation
 | ||||
| book: readme ## Update summary for documentation
 | ||||
| 	printf "# Summary\n\n- [xlsx](README.md#xlsx)\n" > misc/docs/SUMMARY.md | ||||
| 	markdown-toc README.md | sed 's/(#/(README.md#/g'>> misc/docs/SUMMARY.md | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										54
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										54
									
								
								README.md
									
									
									
									
									
								
							| @ -15,6 +15,7 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 
 | ||||
| ## Table of Contents | ||||
| @ -32,7 +33,7 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
|   * [Parsing functions](#parsing-functions) | ||||
|   * [Writing functions](#writing-functions) | ||||
|   * [Utilities](#utilities) | ||||
| - [Workbook / Worksheet / Cell Object Description](#workbook--worksheet--cell-object-description) | ||||
| - [Common Spreadsheet Format](#common-spreadsheet-format) | ||||
|   * [General Structures](#general-structures) | ||||
|   * [Cell Object](#cell-object) | ||||
|     + [Data Types](#data-types) | ||||
| @ -58,7 +59,8 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
|   * [Array of Arrays Input](#array-of-arrays-input) | ||||
|   * [HTML Table Input](#html-table-input) | ||||
|   * [Formulae Output](#formulae-output) | ||||
|   * [CSV and general DSV Output](#csv-and-general-dsv-output) | ||||
|   * [Delimiter-Separated Output](#delimiter-separated-output) | ||||
|     + [UTF-16 Unicode Text](#utf-16-unicode-text) | ||||
|   * [JSON](#json) | ||||
| - [File Formats](#file-formats) | ||||
|   * [Excel 2007+ XML (XLSX/XLSM)](#excel-2007-xml-xlsxxlsm) | ||||
| @ -66,11 +68,13 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
|   * [Excel 97-2004 Binary (BIFF8)](#excel-97-2004-binary-biff8) | ||||
|   * [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) | ||||
|   * [Comma-Separated Values (CSV)](#comma-separated-values-csv) | ||||
|   * [OpenDocument Spreadsheet (ODS/FODS)](#opendocument-spreadsheet-odsfods) | ||||
|     + [Uniform Office Spreadsheet (UOS1/2)](#uniform-office-spreadsheet-uos12) | ||||
|   * [Delimiter-Separated Values (CSV/TXT)](#delimiter-separated-values-csvtxt) | ||||
|   * [Other Single-Worksheet Formats](#other-single-worksheet-formats) | ||||
|     + [dBASE and Visual FoxPro (DBF)](#dbase-and-visual-foxpro-dbf) | ||||
|     + [Symbolic Link (SYLK)](#symbolic-link-sylk) | ||||
|     + [Lotus Formatted Text (PRN)](#lotus-formatted-text-prn) | ||||
|     + [Data Interchange Format (DIF)](#data-interchange-format-dif) | ||||
|     + [HTML](#html) | ||||
| - [Testing](#testing) | ||||
| @ -429,7 +433,7 @@ Exporters are described in the [Utility Functions](#utility-functions) section. | ||||
| - `{en,de}code_cell` converts cell addresses | ||||
| - `{en,de}code_range` converts cell ranges | ||||
| 
 | ||||
| ## Workbook / Worksheet / Cell Object Description | ||||
| ## Common Spreadsheet Format | ||||
| 
 | ||||
| js-xlsx conforms to the Common Spreadsheet Format (CSF): | ||||
| 
 | ||||
| @ -879,6 +883,12 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| DBF files are detected based on the first byte as well as the third and fourth | ||||
| bytes (corresponding to month and day of the file date) | ||||
| 
 | ||||
| Plaintext format guessing follows the priority order: | ||||
| 
 | ||||
| | Format | Test                                                                | | ||||
| |:-------|:--------------------------------------------------------------------| | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| ## Writing Options | ||||
| 
 | ||||
| The exported `write` and `writeFile` functions accept an options argument: | ||||
| @ -910,16 +920,22 @@ output formats.  The specific file type is controlled with `bookType` option: | ||||
| | `xlsx`   | `.xlsx`  |    ZIP    | multi  | Excel 2007+ XML Format            | | ||||
| | `xlsm`   | `.xlsm`  |    ZIP    | multi  | Excel 2007+ Macro XML Format      | | ||||
| | `xlsb`   | `.xlsb`  |    ZIP    | multi  | Excel 2007+ Binary Format         | | ||||
| | `ods`    | `.ods`   |    ZIP    | multi  | OpenDocument Spreadsheet          | | ||||
| | `biff2`  | `.xls`   |   none    | single | Excel 2.0 Worksheet format        | | ||||
| | `xlml`   | `.xls`   |   none    | multi  | Excel 2003-2004 (SpreadsheetML)   | | ||||
| | `ods`    | `.ods`   |    ZIP    | multi  | OpenDocument Spreadsheet          | | ||||
| | `fods`   | `.fods`  |   none    | multi  | Flat OpenDocument Spreadsheet     | | ||||
| | `csv`    | `.csv`   |   none    | single | Comma Separated Values            | | ||||
| | `txt`    | `.txt`   |   none    | single | UTF-16 Unicode Text (TXT)         | | ||||
| | `sylk`   | `.sylk`  |   none    | single | Symbolic Link (SYLK)              | | ||||
| | `dif`    | `.dif`   |   none    | single | Data Interchange Format (DIF)     | | ||||
| | `prn`    | `.prn`   |   none    | single | Lotus Formatted Text              | | ||||
| 
 | ||||
| - `compression` only applies to formats with ZIP containers. | ||||
| - Formats that only support a single sheet require a `sheet` option specifying | ||||
|   the worksheet.  If the string is empty, the first worksheet is used. | ||||
| - `writeFile` will automatically guess the output file format based on the file | ||||
|   extension if `bookType` is not specified.  It will choose the first format in | ||||
|   the aforementioned table that matches the extension. | ||||
| 
 | ||||
| ### Output Type | ||||
| 
 | ||||
| @ -1013,7 +1029,7 @@ accordance with Excel.  For the example sheet: | ||||
| [ 'A1=\'S', 'F1=\'J', 'D2=4', 'B3=3', 'G3=8' ] | ||||
| ``` | ||||
| 
 | ||||
| ### CSV and general DSV Output | ||||
| ### Delimiter-Separated Output | ||||
| 
 | ||||
| As an alternative to the `writeFile` CSV type, `XLSX.utils.sheet_to_csv` also | ||||
| produces CSV output.  The function takes an options argument: | ||||
| @ -1044,6 +1060,12 @@ S	h	e	e	t	J	S | ||||
| S:h:e:e:t:J:S|1:2:3:4:5:6:7|2:3:4:5:6:7:8| | ||||
| ``` | ||||
| 
 | ||||
| #### UTF-16 Unicode Text | ||||
| 
 | ||||
| The `txt` output type uses the tab character as the field separator.  If the | ||||
| codepage library is available (included in the full distribution but not core), | ||||
| the output will be encoded in codepage `1200` and the BOM will be prepended. | ||||
| 
 | ||||
| ### JSON | ||||
| 
 | ||||
| `XLSX.utils.sheet_to_json` and the alias `XLSX.utils.sheet_to_row_object_array` | ||||
| @ -1145,9 +1167,11 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats: | ||||
| | Excel 3.0 (XLS BIFF3)                                        |  :o:  |       | | ||||
| | Excel 2.0/2.1 (XLS BIFF2)                                    |  :o:  |  :o:  | | ||||
| | **Excel Supported Text Formats**                             |:-----:|:-----:| | ||||
| | Delimiter-Separated Values (CSV/TSV/DSV)                     |       |  :o:  | | ||||
| | Delimiter-Separated Values (CSV/TXT)                         |       |  :o:  | | ||||
| | Data Interchange Format (DIF)                                |  :o:  |  :o:  | | ||||
| | Symbolic Link (SYLK/SLK)                                     |  :o:  |  :o:  | | ||||
| | Lotus Formatted Text (PRN)                                   |  :o:  |  :o:  | | ||||
| | UTF-16 Unicode Text (TXT)                                    |       |  :o:  | | ||||
| | **Other Workbook/Worksheet Formats**                         |:-----:|:-----:| | ||||
| | OpenDocument Spreadsheet (ODS)                               |  :o:  |  :o:  | | ||||
| | Flat XML ODF Spreadsheet (FODS)                              |  :o:  |  :o:  | | ||||
| @ -1203,22 +1227,26 @@ in an XLSX sub-file can be mapped to XLSB records in a corresponding sub-file. | ||||
| The `MS-XLSB` specification covers the basics of the file format, and other | ||||
| specifications expand on serialization of features like properties. | ||||
| 
 | ||||
| ### OpenDocument Spreadsheet (ODS/FODS) and Uniform Office Spreadsheet (UOS1/2) | ||||
| ### OpenDocument Spreadsheet (ODS/FODS) | ||||
| 
 | ||||
| ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to | ||||
| SpreadsheetML.  Both are detailed in the OASIS standard, but tools like LO/OO | ||||
| add undocumented extensions. | ||||
| 
 | ||||
| #### Uniform Office Spreadsheet (UOS1/2) | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| ### Comma-Separated Values (CSV) | ||||
| ### Delimiter-Separated Values (CSV/TXT) | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| Excel TXT uses tab as the delimiter and codepage 1200. | ||||
| 
 | ||||
| ### Other Single-Worksheet Formats | ||||
| 
 | ||||
| Many older formats supported only one worksheet: | ||||
| @ -1237,6 +1265,12 @@ limited by the general ability to read arbitrary files in the web browser. | ||||
| There is no real documentation.  All knowledge was gathered by saving files in | ||||
| various versions of Excel to deduce the meaning of fields. | ||||
| 
 | ||||
| #### Lotus Formatted Text (PRN) | ||||
| 
 | ||||
| There is no real documentation, and in fact Excel treats PRN as an output-only | ||||
| file format.  Nevertheless we can guess the column widths and reverse-engineer | ||||
| the original layout. | ||||
| 
 | ||||
| #### Data Interchange Format (DIF) | ||||
| 
 | ||||
| There is no unified definition.  Visicalc DIF differs from Lotus DIF, and both | ||||
|  | ||||
| @ -21,7 +21,7 @@ program | ||||
| 	.option('-Y, --ods',  'emit ODS  to <sheetname> or <file>.ods') | ||||
| 	.option('-2, --biff2','emit XLS  to <sheetname> or <file>.xls (BIFF2)') | ||||
| 	.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)') | ||||
| 	.option('-T, --fods', 'emit FODS to <sheetname> or <file>.xls (Flat ODS)') | ||||
| 	.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)') | ||||
| 
 | ||||
| 	.option('-S, --formulae', 'print formulae') | ||||
| 	.option('-j, --json', 'emit formatted JSON (all fields text)') | ||||
| @ -29,6 +29,8 @@ program | ||||
| 	.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('-P, --prn', 'emit formatted text (prn)') | ||||
| 	.option('-t, --txt', 'emit delimited text (txt)') | ||||
| 
 | ||||
| 	.option('-F, --field-sep <sep>', 'CSV field separator', ",") | ||||
| 	.option('-R, --row-sep <sep>', 'CSV row separator', "\n") | ||||
| @ -163,10 +165,12 @@ try { | ||||
| 
 | ||||
| if(program.perf) process.exit(0); | ||||
| 
 | ||||
| /* single worksheet XLS formats */ | ||||
| /* single worksheet formats */ | ||||
| [ | ||||
| 	['biff2', '.xls'], | ||||
| 	['sylk', '.slk'], | ||||
| 	['prn', '.prn'], | ||||
| 	['txt', '.txt'], | ||||
| 	['dif', '.dif'] | ||||
| ].forEach(function(m) { if(program[m[0]]) { | ||||
| 		wopts.bookType = m[0]; | ||||
|  | ||||
| @ -14,4 +14,6 @@ type EvertNumType = {[string]:number}; | ||||
| type EvertArrType = {[string]:Array<string>}; | ||||
| 
 | ||||
| type StringConv = {(string):string}; | ||||
| 
 | ||||
| type WriteObjStrFactory = {from_sheet(ws:Worksheet, o:any):string}; | ||||
| */ | ||||
|  | ||||
| @ -22,9 +22,8 @@ function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			else if(typeof cell.v === 'boolean') cell.t = 'b'; | ||||
| 			else if(cell.v instanceof Date) { | ||||
| 				cell.z = o.dateNF || SSF._table[14]; | ||||
| 				if(o.cellDates) cell.t = 'd'; | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); } | ||||
| 				cell.w = SSF.format(cell.z, cell.v); | ||||
| 				if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); } | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); } | ||||
| 			} | ||||
| 			else cell.t = 's'; | ||||
| 			ws[cell_ref] = cell; | ||||
|  | ||||
| @ -57,7 +57,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 	var memo = false; | ||||
| 	var vfp = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x03: break; | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| @ -65,33 +65,38 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1)); | ||||
| 	var nrow = d.read_shift(4); | ||||
| 	var fpos = d.read_shift(2); | ||||
| 	var filedate = new Date(), nrow = 0, fpos = 0; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1)); | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l+=16; | ||||
| 
 | ||||
| 	var flags = d.read_shift(1); | ||||
| 	var flags = 0, current_cp = 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	flags = d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	var current_cp = 1252; | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 	} | ||||
| 	var fields = [], field = {}; | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0); | ||||
| 	while(d.l < hend) { | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 		field = {}; | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+10)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += 11; | ||||
| 		field.type = String.fromCharCode(d.read_shift(1)); | ||||
| 		field.offset = d.read_shift(4); | ||||
| 		if(ft != 0x02) field.offset = d.read_shift(4); | ||||
| 		field.len = d.read_shift(1); | ||||
| 		if(ft == 0x02) field.offset = d.read_shift(2); | ||||
| 		field.dec = d.read_shift(1); | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		d.l += 14; | ||||
| 		if(ft != 0x02) d.l += 14; | ||||
| 		switch(field.type) { | ||||
| 			// case 'B': break; // Binary
 | ||||
| 			case 'C': break; // character
 | ||||
| @ -113,8 +118,11 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		} | ||||
| 	} | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| @ -162,7 +170,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); | ||||
| 	if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| @ -374,8 +382,9 @@ var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/) { | ||||
| 		if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){} | ||||
| 		else if(+data == +data) arr[R][C] = +data; | ||||
| 		else if(data !== "") arr[R][C] = data; | ||||
| 		else arr[R][C] = data; | ||||
| 	} | ||||
| 
 | ||||
| 	function prn_to_aoa_str(f/*:string*/, opts)/*:AOA*/ { | ||||
| @ -406,9 +415,27 @@ var PRN = (function() { | ||||
| 
 | ||||
| 	function prn_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(prn_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	function sheet_to_prn(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 		var o/*:Array<string>*/ = []; | ||||
| 		var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			var oo = []; | ||||
| 			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) { oo.push("          "); continue; } | ||||
| 				var w = (cell.w || (format_cell(cell), cell.w) || "").substr(0,10); | ||||
| 				while(w.length < 10) w += " "; | ||||
| 				oo.push(w + (C == 0 ? " " : "")); | ||||
| 			} | ||||
| 			o.push(oo.join("")); | ||||
| 		} | ||||
| 		return o.join("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		to_workbook: prn_to_workbook, | ||||
| 		to_sheet: prn_to_sheet | ||||
| 		to_sheet: prn_to_sheet, | ||||
| 		from_sheet: sheet_to_prn | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
|  | ||||
| @ -20,8 +20,9 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array<Comment>*/ { | ||||
| 		var cell = decode_cell(y.ref); | ||||
| 		if(opts.sheetRows && opts.sheetRows <= cell.r) return; | ||||
| 		var textMatch = x.match(/<(?:\w+:)?text>([^\u2603]*)<\/(?:\w+:)?text>/); | ||||
| 		var rt = (!textMatch || !textMatch[1]) ? {r:"",t:"",h:""} : parse_si(textMatch[1]); | ||||
| 		var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""}; | ||||
| 		comment.r = rt.r; | ||||
| 		if(rt.r == "<t></t>") rt.t = rt.h = ""; | ||||
| 		comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"); | ||||
| 		if(opts.cellHTML) comment.h = rt.h; | ||||
| 		commentList.push(comment); | ||||
| @ -48,7 +49,7 @@ function write_comments_xml(data, opts) { | ||||
| 		d[1].forEach(function(c) { | ||||
| 			/* 18.7.3 CT_Comment */ | ||||
| 			o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>'); | ||||
| 			o.push(writetag("t", c.t)); | ||||
| 			o.push(writetag("t", c.t == null ? "" : c.t)); | ||||
| 			o.push('</text></comment>'); | ||||
| 		}); | ||||
| 	}); | ||||
|  | ||||
| @ -11,7 +11,7 @@ function parse_BrtBeginComment(data, length) { | ||||
| function write_BrtBeginComment(data, o) { | ||||
| 	if(o == null) o = new_buf(36); | ||||
| 	o.write_shift(4, data[1].iauthor); | ||||
| 	write_UncheckedRfX(data[0], o); | ||||
| 	write_UncheckedRfX((data[0]/*:any*/), o); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| @ -74,7 +74,7 @@ function write_comments_bin(data, opts) { | ||||
| 		data.forEach(function(comment) { | ||||
| 			comment[1].forEach(function(c) { | ||||
| 				c.iauthor = iauthor.indexOf(c.a); | ||||
| 				var range = {s:decode_cell(comment[0])}; range.e = range.s; | ||||
| 				var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])}; | ||||
| 				write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c])); | ||||
| 				if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_RichStr(c)); | ||||
| 				write_record(ba, "BrtEndComment"); | ||||
|  | ||||
| @ -99,9 +99,16 @@ function parse_wb_defaults(wb) { | ||||
| 	_ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904, 'date1904'); | ||||
| } | ||||
| 
 | ||||
| /* TODO: validate workbook */ | ||||
| function check_wb_names(N) { | ||||
| 	var badchars = "][*?\/\\".split(""); | ||||
| 	N.forEach(function(n,i) { | ||||
| 		badchars.forEach(function(c) { if(n.indexOf(c) > -1) throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); }); | ||||
| 		if(n.length > 31) throw new Error("Sheet names cannot exceed 31 chars"); | ||||
| 		for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n); | ||||
| 	}); | ||||
| } | ||||
| function check_wb(wb) { | ||||
| 	if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook"); | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) for(var j = 0; j < i; ++j) | ||||
| 		if(wb.SheetNames[i] == wb.SheetNames[j]) throw new Error("Duplicate Sheet Name: " + wb.SheetNames[i]); | ||||
| 	check_wb_names(wb.SheetNames); | ||||
| 	/* TODO: validate workbook */ | ||||
| } | ||||
|  | ||||
| @ -25,7 +25,7 @@ var parse_content_xml = (function() { | ||||
| 		var sheetag/*:: = {name:"", '名称':""}*/; | ||||
| 		var rowtag/*:: = {'行号':""}*/; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {}; | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/; | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:"",c:[]}:any)*/; | ||||
| 		var ctag = {value:""}; | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/; | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| @ -80,7 +80,7 @@ var parse_content_xml = (function() { | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					comments = []; comment = {}; | ||||
| 					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/); | ||||
| 					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:"",c:[]*/}/*:any*/); | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag.formula) ctag.formula = unescapexml(ctag.formula); | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| @ -138,7 +138,7 @@ var parse_content_xml = (function() { | ||||
| 							if(range.e.c <= C) range.e.c = C; | ||||
| 						} | ||||
| 					} else { C += rept; rept = 0; } | ||||
| 					q = {/*:: t:"", v:null, z:null, w:""*/}; | ||||
| 					q = {/*:: t:"", v:null, z:null, w:"",c:[]*/}; | ||||
| 					textp = ""; | ||||
| 				} | ||||
| 				break; // 9.1.4 <table:table-cell>
 | ||||
| @ -162,7 +162,7 @@ var parse_content_xml = (function() { | ||||
| 					comments.push(comment); | ||||
| 				} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);} | ||||
| 				creator = ""; creatorpidx = 0; | ||||
| 				creator = ""; creatoridx = 0; | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
|  | ||||
| @ -1,13 +1,6 @@ | ||||
| /* actual implementation in utils, wrappers are for read/write */ | ||||
| function write_csv_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 sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| } | ||||
| 
 | ||||
| function write_obj_str(factory) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| /* actual implementation elsewhere, wrappers are for read/write */ | ||||
| function write_obj_str(factory/*:WriteObjStrFactory*/) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/)/*:string*/ { | ||||
| 		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); | ||||
| @ -15,5 +8,8 @@ function write_obj_str(factory) { | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_csv_str = write_obj_str({from_sheet:sheet_to_csv}); | ||||
| var write_slk_str = write_obj_str(SYLK); | ||||
| var write_dif_str = write_obj_str(DIF); | ||||
| var write_prn_str = write_obj_str(PRN); | ||||
| var write_txt_str = write_obj_str({from_sheet:sheet_to_txt}); | ||||
|  | ||||
| @ -34,9 +34,10 @@ 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; | ||||
| 	if(wb.Props && wb.Props.SheetNames){} | ||||
| 	else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	else wb.Props.SheetNames = wb.SheetNames.map(function(x,i) { return [(wb.Workbook.Sheets[i]||{}).Hidden != 2, x];}).filter(function(x) { return x[0]; }).map(function(x) { return x[1]; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
|  | ||||
| @ -38,10 +38,11 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		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); | ||||
| 		case 0x30: case 0x31: if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); break; | ||||
| 		default: throw new Error("Unsupported file " + n.join("|")); | ||||
| 	} | ||||
| 	throw new Error("Unsupported file format " + n.join("|")); | ||||
| 	if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); | ||||
| 	if(0x20>n[0]||n[0]>0x7F) throw new Error("Unsupported file " + n.join("|")); | ||||
| 	/* TODO: CSV / TXT */ | ||||
| 	return PRN.to_workbook(d, o); | ||||
| } | ||||
| 
 | ||||
| function readFileSync(filename/*:string*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
|  | ||||
| @ -14,6 +14,20 @@ function write_zip_type(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 	return z.generate(oopts); | ||||
| } | ||||
| 
 | ||||
| /* TODO: test consistency */ | ||||
| function write_bstr_type(out/*:string*/, opts/*:WriteOpts*/) { | ||||
| 	switch(opts.type) { | ||||
| 		case "base64": return Base64.encode(out); | ||||
| 		case "binary": return out; | ||||
| 		case "file": return _fs.writeFileSync(opts.file, out, 'binary'); | ||||
| 		case "buffer": { | ||||
| 			if(has_buf) return new Buffer(out, 'utf8'); | ||||
| 			else return out.split("").map(function(c) { return c.charCodeAt(0); }); | ||||
| 		} | ||||
| 	} | ||||
| 	throw new Error("Unrecognized type " + opts.type); | ||||
| } | ||||
| 
 | ||||
| /* TODO: test consistency */ | ||||
| function write_string_type(out/*:string*/, opts/*:WriteOpts*/) { | ||||
| 	switch(opts.type) { | ||||
| @ -50,8 +64,10 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 		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 'txt': return write_bstr_type(write_txt_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 'prn': return write_string_type(write_prn_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': | ||||
| @ -74,7 +90,9 @@ function resolve_book_type(o/*?WriteFileOpts*/) { | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| 		case '.ods': o.bookType = 'ods'; break; | ||||
| 		case '.csv': o.bookType = 'csv'; break; | ||||
| 		case '.txt': o.bookType = 'txt'; break; | ||||
| 		case '.dif': o.bookType = 'dif'; break; | ||||
| 		case '.prn': o.bookType = 'prn'; break; | ||||
| 		case '.slk': o.bookType = 'sylk'; break; | ||||
| 	} | ||||
| } | ||||
|  | ||||
| @ -188,6 +188,13 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	return out; | ||||
| } | ||||
| var make_csv = sheet_to_csv; | ||||
| function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n"; | ||||
| 	var s = sheet_to_csv(sheet, opts); | ||||
| 	if(typeof cptable == 'undefined') return s; | ||||
| 	var o = cptable.utils.encode(1200, s); | ||||
| 	return "\xff\xfe" + o; | ||||
| } | ||||
| 
 | ||||
| function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ { | ||||
| 	var y = "", x, val=""; | ||||
|  | ||||
| @ -15,5 +15,6 @@ with a unified JS representation, and ES3/ES5 browser compatibility back to IE6. | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
|  | ||||
| 
 | ||||
| 
 | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| ## Workbook / Worksheet / Cell Object Description | ||||
| ## Common Spreadsheet Format | ||||
| 
 | ||||
| js-xlsx conforms to the Common Spreadsheet Format (CSF): | ||||
| 
 | ||||
|  | ||||
| @ -72,3 +72,9 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| DBF files are detected based on the first byte as well as the third and fourth | ||||
| bytes (corresponding to month and day of the file date) | ||||
| 
 | ||||
| Plaintext format guessing follows the priority order: | ||||
| 
 | ||||
| | Format | Test                                                                | | ||||
| |:-------|:--------------------------------------------------------------------| | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
|  | ||||
| @ -29,16 +29,22 @@ output formats.  The specific file type is controlled with `bookType` option: | ||||
| | `xlsx`   | `.xlsx`  |    ZIP    | multi  | Excel 2007+ XML Format            | | ||||
| | `xlsm`   | `.xlsm`  |    ZIP    | multi  | Excel 2007+ Macro XML Format      | | ||||
| | `xlsb`   | `.xlsb`  |    ZIP    | multi  | Excel 2007+ Binary Format         | | ||||
| | `ods`    | `.ods`   |    ZIP    | multi  | OpenDocument Spreadsheet          | | ||||
| | `biff2`  | `.xls`   |   none    | single | Excel 2.0 Worksheet format        | | ||||
| | `xlml`   | `.xls`   |   none    | multi  | Excel 2003-2004 (SpreadsheetML)   | | ||||
| | `ods`    | `.ods`   |    ZIP    | multi  | OpenDocument Spreadsheet          | | ||||
| | `fods`   | `.fods`  |   none    | multi  | Flat OpenDocument Spreadsheet     | | ||||
| | `csv`    | `.csv`   |   none    | single | Comma Separated Values            | | ||||
| | `txt`    | `.txt`   |   none    | single | UTF-16 Unicode Text (TXT)         | | ||||
| | `sylk`   | `.sylk`  |   none    | single | Symbolic Link (SYLK)              | | ||||
| | `dif`    | `.dif`   |   none    | single | Data Interchange Format (DIF)     | | ||||
| | `prn`    | `.prn`   |   none    | single | Lotus Formatted Text              | | ||||
| 
 | ||||
| - `compression` only applies to formats with ZIP containers. | ||||
| - Formats that only support a single sheet require a `sheet` option specifying | ||||
|   the worksheet.  If the string is empty, the first worksheet is used. | ||||
| - `writeFile` will automatically guess the output file format based on the file | ||||
|   extension if `bookType` is not specified.  It will choose the first format in | ||||
|   the aforementioned table that matches the extension. | ||||
| 
 | ||||
| ### Output Type | ||||
| 
 | ||||
|  | ||||
| @ -78,7 +78,7 @@ accordance with Excel.  For the example sheet: | ||||
| [ 'A1=\'S', 'F1=\'J', 'D2=4', 'B3=3', 'G3=8' ] | ||||
| ``` | ||||
| 
 | ||||
| ### CSV and general DSV Output | ||||
| ### Delimiter-Separated Output | ||||
| 
 | ||||
| As an alternative to the `writeFile` CSV type, `XLSX.utils.sheet_to_csv` also | ||||
| produces CSV output.  The function takes an options argument: | ||||
| @ -109,6 +109,12 @@ S	h	e	e	t	J	S | ||||
| S:h:e:e:t:J:S|1:2:3:4:5:6:7|2:3:4:5:6:7:8| | ||||
| ``` | ||||
| 
 | ||||
| #### UTF-16 Unicode Text | ||||
| 
 | ||||
| The `txt` output type uses the tab character as the field separator.  If the | ||||
| codepage library is available (included in the full distribution but not core), | ||||
| the output will be encoded in codepage `1200` and the BOM will be prepended. | ||||
| 
 | ||||
| ### JSON | ||||
| 
 | ||||
| `XLSX.utils.sheet_to_json` and the alias `XLSX.utils.sheet_to_row_object_array` | ||||
|  | ||||
| @ -14,9 +14,11 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats: | ||||
| | Excel 3.0 (XLS BIFF3)                                        |  :o:  |       | | ||||
| | Excel 2.0/2.1 (XLS BIFF2)                                    |  :o:  |  :o:  | | ||||
| | **Excel Supported Text Formats**                             |:-----:|:-----:| | ||||
| | Delimiter-Separated Values (CSV/TSV/DSV)                     |       |  :o:  | | ||||
| | Delimiter-Separated Values (CSV/TXT)                         |       |  :o:  | | ||||
| | Data Interchange Format (DIF)                                |  :o:  |  :o:  | | ||||
| | Symbolic Link (SYLK/SLK)                                     |  :o:  |  :o:  | | ||||
| | Lotus Formatted Text (PRN)                                   |  :o:  |  :o:  | | ||||
| | UTF-16 Unicode Text (TXT)                                    |       |  :o:  | | ||||
| | **Other Workbook/Worksheet Formats**                         |:-----:|:-----:| | ||||
| | OpenDocument Spreadsheet (ODS)                               |  :o:  |  :o:  | | ||||
| | Flat XML ODF Spreadsheet (FODS)                              |  :o:  |  :o:  | | ||||
| @ -72,22 +74,26 @@ in an XLSX sub-file can be mapped to XLSB records in a corresponding sub-file. | ||||
| The `MS-XLSB` specification covers the basics of the file format, and other | ||||
| specifications expand on serialization of features like properties. | ||||
| 
 | ||||
| ### OpenDocument Spreadsheet (ODS/FODS) and Uniform Office Spreadsheet (UOS1/2) | ||||
| ### OpenDocument Spreadsheet (ODS/FODS) | ||||
| 
 | ||||
| ODS is an XML-in-ZIP format akin to XLSX while FODS is an XML format akin to | ||||
| SpreadsheetML.  Both are detailed in the OASIS standard, but tools like LO/OO | ||||
| add undocumented extensions. | ||||
| 
 | ||||
| #### Uniform Office Spreadsheet (UOS1/2) | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| ### Comma-Separated Values (CSV) | ||||
| ### Delimiter-Separated Values (CSV/TXT) | ||||
| 
 | ||||
| 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. | ||||
| 
 | ||||
| Excel TXT uses tab as the delimiter and codepage 1200. | ||||
| 
 | ||||
| ### Other Single-Worksheet Formats | ||||
| 
 | ||||
| Many older formats supported only one worksheet: | ||||
| @ -106,6 +112,12 @@ limited by the general ability to read arbitrary files in the web browser. | ||||
| There is no real documentation.  All knowledge was gathered by saving files in | ||||
| various versions of Excel to deduce the meaning of fields. | ||||
| 
 | ||||
| #### Lotus Formatted Text (PRN) | ||||
| 
 | ||||
| There is no real documentation, and in fact Excel treats PRN as an output-only | ||||
| file format.  Nevertheless we can guess the column widths and reverse-engineer | ||||
| the original layout. | ||||
| 
 | ||||
| #### Data Interchange Format (DIF) | ||||
| 
 | ||||
| There is no unified definition.  Visicalc DIF differs from Lotus DIF, and both | ||||
|  | ||||
							
								
								
									
										30
									
								
								formats.dot
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										30
									
								
								formats.dot
									
									
									
									
									
								
							| @ -16,7 +16,7 @@ digraph G { | ||||
| 	subgraph OD { | ||||
| 		node  [style=filled,color=yellow]; | ||||
| 		ods   [label="ODS"]; | ||||
| 		fods  [label="Flat\nODS"]; | ||||
| 		fods  [label="FODS"]; | ||||
| 		uos   [label="UOS"]; | ||||
| 	} | ||||
| 
 | ||||
| @ -24,12 +24,14 @@ digraph G { | ||||
| 		node  [style=filled,color=cyan]; | ||||
| 		html  [label="HTML\nTable"]; | ||||
| 		csv   [label="CSV"]; | ||||
| 		txt   [label="TXT\nUTF-16"]; | ||||
| 		dbf   [label="DBF"]; | ||||
| 		dif   [label="DIF"]; | ||||
| 		slk   [label="SYLK"]; | ||||
| 		prn   [label="PRN"]; | ||||
| 	} | ||||
| 
 | ||||
| 	subgraph JSXLSX { | ||||
| 	subgraph WORKBOOK { | ||||
| 		edge [color=blue]; | ||||
| 		csf -> xlsx | ||||
| 		xlsx -> csf | ||||
| @ -37,22 +39,28 @@ digraph G { | ||||
| 		xlsb -> csf | ||||
| 		csf -> xlml | ||||
| 		xlml -> csf | ||||
| 		xls2 -> csf | ||||
| 		csf -> xls2 | ||||
| 		xls3 -> csf | ||||
| 		xls4 -> csf | ||||
| 		xls5 -> csf | ||||
| 		xls8 -> csf | ||||
| 		csf -> slk | ||||
| 		slk -> csf | ||||
| 		csf -> dif | ||||
| 		dif -> csf | ||||
| 		csf -> csv | ||||
| 		ods -> csf | ||||
| 		csf -> ods | ||||
| 		fods -> csf | ||||
| 		csf -> fods | ||||
| 		uos -> csf | ||||
| 	} | ||||
| 	subgraph WORKSHEET { | ||||
| 		edge [color=aquamarine4]; | ||||
| 		xls2 -> csf | ||||
| 		csf -> xls2 | ||||
| 		xls3 -> csf | ||||
| 		xls4 -> csf | ||||
| 		csf -> slk | ||||
| 		slk -> csf | ||||
| 		csf -> dif | ||||
| 		dif -> csf | ||||
| 		prn -> csf | ||||
| 		csf -> prn | ||||
| 		csf -> csv | ||||
| 		csf -> txt | ||||
| 		dbf -> csf | ||||
| 		html -> csf | ||||
| 	} | ||||
|  | ||||
							
								
								
									
										
											BIN
										
									
								
								formats.png
									
									
									
									
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								formats.png
									
									
									
									
									
								
							
										
											Binary file not shown.
										
									
								
							| Before Width: | Height: | Size: 94 KiB After Width: | Height: | Size: 119 KiB | 
							
								
								
									
										
											BIN
										
									
								
								legend.png
									
									
									
									
									
										Normal file
									
								
							
							
								
									
								
								
								
								
								
									
									
								
							
						
						
									
										
											BIN
										
									
								
								legend.png
									
									
									
									
									
										Normal file
									
								
							
										
											Binary file not shown.
										
									
								
							| After Width: | Height: | Size: 47 KiB | 
| @ -12,7 +12,7 @@ | ||||
|   * [Parsing functions](README.md#parsing-functions) | ||||
|   * [Writing functions](README.md#writing-functions) | ||||
|   * [Utilities](README.md#utilities) | ||||
| - [Workbook / Worksheet / Cell Object Description](README.md#workbook--worksheet--cell-object-description) | ||||
| - [Common Spreadsheet Format](README.md#common-spreadsheet-format) | ||||
|   * [General Structures](README.md#general-structures) | ||||
|   * [Cell Object](README.md#cell-object) | ||||
|     + [Data Types](README.md#data-types) | ||||
| @ -38,7 +38,8 @@ | ||||
|   * [Array of Arrays Input](README.md#array-of-arrays-input) | ||||
|   * [HTML Table Input](README.md#html-table-input) | ||||
|   * [Formulae Output](README.md#formulae-output) | ||||
|   * [CSV and general DSV Output](README.md#csv-and-general-dsv-output) | ||||
|   * [Delimiter-Separated Output](README.md#delimiter-separated-output) | ||||
|     + [UTF-16 Unicode Text](README.md#utf-16-unicode-text) | ||||
|   * [JSON](README.md#json) | ||||
| - [File Formats](README.md#file-formats) | ||||
|   * [Excel 2007+ XML (XLSX/XLSM)](README.md#excel-2007-xml-xlsxxlsm) | ||||
| @ -46,11 +47,13 @@ | ||||
|   * [Excel 97-2004 Binary (BIFF8)](README.md#excel-97-2004-binary-biff8) | ||||
|   * [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) | ||||
|   * [Comma-Separated Values (CSV)](README.md#comma-separated-values-csv) | ||||
|   * [OpenDocument Spreadsheet (ODS/FODS)](README.md#opendocument-spreadsheet-odsfods) | ||||
|     + [Uniform Office Spreadsheet (UOS1/2)](README.md#uniform-office-spreadsheet-uos12) | ||||
|   * [Delimiter-Separated Values (CSV/TXT)](README.md#delimiter-separated-values-csvtxt) | ||||
|   * [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) | ||||
|     + [Lotus Formatted Text (PRN)](README.md#lotus-formatted-text-prn) | ||||
|     + [Data Interchange Format (DIF)](README.md#data-interchange-format-dif) | ||||
|     + [HTML](README.md#html) | ||||
| - [Testing](README.md#testing) | ||||
|  | ||||
							
								
								
									
										1
									
								
								misc/docs/legend.png
									
									
									
									
									
										Symbolic link
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										1
									
								
								misc/docs/legend.png
									
									
									
									
									
										Symbolic link
									
								
							| @ -0,0 +1 @@ | ||||
| ../../legend.png | ||||
							
								
								
									
										42
									
								
								misc/legend.dot
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										42
									
								
								misc/legend.dot
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,42 @@ | ||||
| digraph G { | ||||
| 	graph [mindist=0]; | ||||
| 	labelloc=t; | ||||
| 	label="Legend" | ||||
| 
 | ||||
| 	subgraph cluster_0 { | ||||
| 		label="Supported Format Types" | ||||
| 		color="white" | ||||
| 		XL[label="Excel",style=filled,color=green]; | ||||
| 		OD[label="ODF",style=filled,color=yellow]; | ||||
| 		OLD[label="Other",style=filled,color=cyan]; | ||||
| 		{ edge[style=invis] XL -> OD -> OLD[constraint=false]} | ||||
| 	} | ||||
| 
 | ||||
| 	subgraph cluster_1 { | ||||
| 		label="Workbook Format Conversions (blue arrow)" | ||||
| 		color="white" | ||||
| 		x1i[label="XLSX"] | ||||
| 		c1[shape=doublecircle,label="CSF"]; | ||||
| 		x1o[label="XLSB"] | ||||
| 		{ edge[color=blue] | ||||
| 			x1i->c1[constraint=false,label="read"] | ||||
| 			c1->x1o[constraint=false,label="write"]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	subgraph cluster_2 { | ||||
| 		label="Single-Worksheet Format Conversions (green arrow)" | ||||
| 		color="white" | ||||
| 		x2i[label="SYLK"] | ||||
| 		c2[shape=doublecircle,label="CSF"]; | ||||
| 		x2o[label="CSV"] | ||||
| 		{ edge[color=aquamarine4] | ||||
| 			x2i->c2[constraint=false,label="read"] | ||||
| 			c2->x2o[constraint=false,label="write"]; | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	{ edge[style=invis] XL -> x1i -> x2i; } | ||||
| 	{ edge[style=invis] OD -> c1 -> c2; } | ||||
| 	{ edge[style=invis] OLD -> x1o -> x2o; } | ||||
| } | ||||
							
								
								
									
										10
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										10
									
								
								test.js
									
									
									
									
									
								
							| @ -510,16 +510,6 @@ describe('input formats', function() { | ||||
| 		X.read(fs.readFileSync(paths.cstxlsx)); | ||||
| 		X.read(fs.readFileSync(paths.cstxlsb)); | ||||
| 	}); | ||||
| 	it('should default to base64 type', function() { | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxls, 'binary')); }); | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxml, 'binary')); }); | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsx, 'binary')); }); | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsb, 'binary')); }); | ||||
| 		X.read(fs.readFileSync(paths.cstxls, 'base64')); | ||||
| 		X.read(fs.readFileSync(paths.cstxml, 'base64')); | ||||
| 		X.read(fs.readFileSync(paths.cstxlsx, 'base64')); | ||||
| 		X.read(fs.readFileSync(paths.cstxlsb, 'base64')); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| describe('output formats', function() { | ||||
|  | ||||
| @ -838,7 +838,7 @@ apachepoi_60273.xls | ||||
| # apachepoi_60284.xls | ||||
| apachepoi_AbnormalSharedFormulaFlag.xls | ||||
| apachepoi_AreaErrPtg.xls | ||||
| apachepoi_BOOK_in_capitals.xls | ||||
| # apachepoi_BOOK_in_capitals.xls # note: worksheet length exceeds 31 chars | ||||
| apachepoi_Basic_Expense_Template_2011.xls | ||||
| apachepoi_CodeFunctionTestCaseData.xls | ||||
| apachepoi_ColumnStyle1dp.xls | ||||
|  | ||||
| @ -34,6 +34,7 @@ var paths = { | ||||
| 	cstxml: dir + 'comments_stress_test.xls.xml', | ||||
| 	cstxlsx: dir + 'comments_stress_test.xlsx', | ||||
| 	cstxlsb: dir + 'comments_stress_test.xlsb', | ||||
| 	cstods: dir + 'comments_stress_test.ods', | ||||
| 	fstxls: dir + 'formula_stress_test.xls', | ||||
| 	fstxml: dir + 'formula_stress_test.xls.xml', | ||||
| 	fstxlsx: dir + 'formula_stress_test.xlsx', | ||||
| @ -79,6 +80,21 @@ var N2 = 'XLSB'; | ||||
| var N3 = 'XLS'; | ||||
| var N4 = 'XML'; | ||||
| 
 | ||||
| /* comments_stress_test family */ | ||||
| function check_comments(wb) { | ||||
| 	var ws0 = wb.Sheets.Sheet2; | ||||
| 	assert.equal(ws0.A1.c[0].a, 'Author'); | ||||
| 	assert.equal(ws0.A1.c[0].t, 'Author:\nGod thinks this is good'); | ||||
| 	assert.equal(ws0.C1.c[0].a, 'Author'); | ||||
| 	assert.equal(ws0.C1.c[0].t, 'I really hope that xlsx decides not to use magic like rPr'); | ||||
| 
 | ||||
| 	var ws3 = wb.Sheets.Sheet4; | ||||
| 	assert.equal(ws3.B1.c[0].a, 'Author'); | ||||
| 	assert.equal(ws3.B1.c[0].t, 'The next comment is empty'); | ||||
| 	assert.equal(ws3.B2.c[0].a, 'Author'); | ||||
| 	assert.equal(ws3.B2.c[0].t, ''); | ||||
| } | ||||
| 
 | ||||
| describe('parse options', function() { | ||||
| 	var html_cell_types = ['s']; | ||||
| 	var bef = (function() { | ||||
| @ -347,10 +363,6 @@ describe('input formats', function() { | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsb), {type: 'dafuq'}); }); | ||||
| 	}); | ||||
| 	it('should default to base64 type', function() { | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxls, 'binary')); }); | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxml, 'binary')); }); | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsx, 'binary')); }); | ||||
| 		assert.throws(function() { X.read(fs.readFileSync(paths.cstxlsb, 'binary')); }); | ||||
| 		X.read(fs.readFileSync(paths.cstxls, 'base64')); | ||||
| 		X.read(fs.readFileSync(paths.cstxml, 'base64')); | ||||
| 		X.read(fs.readFileSync(paths.cstxlsx, 'base64')); | ||||
| @ -512,6 +524,21 @@ describe('parse features', function() { | ||||
| 				assert.equal(ws.B1.c[0].h, '<span style="font-weight: bold;">Yegor Kozlov:</span><span style=""><br/>first cell</span>', "must have the html representation"); | ||||
| 			}); | ||||
| 		}); | ||||
| 		[ | ||||
| 			['xlsx', paths.cstxlsx], | ||||
| 			['xlsb', paths.cstxlsb], | ||||
| 			['xls', paths.cstxls], | ||||
| 			['xlml', paths.cstxml], | ||||
| 			['ods', paths.cstods] | ||||
| 		].forEach(function(m) { it(m[0] + ' stress test', function() { | ||||
| 			var wb = X.read(fs.readFileSync(m[1]), {type:'binary'}); | ||||
| 			check_comments(wb); | ||||
| 			var ws0 = wb.Sheets.Sheet2; | ||||
| 			assert.equal(ws0.A1.c[0].a, 'Author'); | ||||
| 			assert.equal(ws0.A1.c[0].t, 'Author:\nGod thinks this is good'); | ||||
| 			assert.equal(ws0.C1.c[0].a, 'Author'); | ||||
| 			assert.equal(ws0.C1.c[0].t, 'I really hope that xlsx decides not to use magic like rPr'); | ||||
| 		}); }); | ||||
| 	}); | ||||
| 
 | ||||
| 	describe('should parse core properties and custom properties', function() { | ||||
| @ -793,7 +820,7 @@ 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() { | ||||
| 	describe('should preserve core properties and custom properties', function() { | ||||
| 		var wb1, wb2, base = './tmp/cp'; | ||||
| 		var bef = (function() { | ||||
| 			wb1 = X.read(fs.readFileSync(paths.cpxlsx), {type:"binary"}); | ||||
| @ -879,6 +906,7 @@ describe('roundtrip features', function() { | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	describe('should preserve sheet visibility', function() { [ | ||||
| 			['xlml', paths.svxml], | ||||
| 			['xlsx', paths.svxlsx], | ||||
| @ -897,6 +925,22 @@ describe('roundtrip features', function() { | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| 
 | ||||
| 	describe('should preserve cell comments', function() { [ | ||||
| 			['xlsx', paths.cstxlsx], | ||||
| 			['xlsb', paths.cstxlsb], | ||||
| 			//['xls', paths.cstxlsx],
 | ||||
| 			['xlml', paths.cstxml] | ||||
| 			//['ods', paths.cstods]
 | ||||
| 	].forEach(function(w) { | ||||
| 			it(w[0], function() { | ||||
| 				var wb1 = X.read(fs.readFileSync(w[1]), {type:"binary"}); | ||||
| 				var wb2 = X.read(X.write(wb1, {bookType:w[0], type:"binary"}), {type:"binary"}); | ||||
| 				check_comments(wb1); | ||||
| 				check_comments(wb2); | ||||
| 			}); | ||||
| 		}); | ||||
| 	}); | ||||
| }); | ||||
| 
 | ||||
| function password_file(x){return x.match(/^password.*\.xls$/); } | ||||
| @ -907,7 +951,7 @@ describe('invalid files', function() { | ||||
| 			['passwords', 'apachepoi_xor-encryption-abc.xls'], | ||||
| 			['DOC files', 'word_doc.doc'] | ||||
| 		].forEach(function(w) { it('should fail on ' + w[0], function() { | ||||
| 			assert.throws(function() { X.read(fs.readFileSync(dir + w[1]), {type:"binary"}); }); | ||||
| 			assert.throws(function() { X.read(fs.readFileSync(dir + w[1], {type:"binary"}), {type:"binary"}); }); | ||||
| 			assert.throws(function() { X.read(fs.readFileSync(dir+w[1], 'base64'), {type:'base64'}); }); | ||||
| 		}); }); | ||||
| 	}); | ||||
|  | ||||
										
											
												File diff suppressed because one or more lines are too long
											
										
									
								
							| @ -10,6 +10,7 @@ | ||||
| ./test_files/comments_stress_test.xls.xml | ||||
| ./test_files/comments_stress_test.xlsx | ||||
| ./test_files/comments_stress_test.xlsb | ||||
| ./test_files/comments_stress_test.ods | ||||
| ./test_files/formula_stress_test.xls | ||||
| ./test_files/formula_stress_test.xls.xml | ||||
| ./test_files/formula_stress_test.xlsx | ||||
|  | ||||
| @ -71,11 +71,12 @@ ws['!rows'] = wsrows; | ||||
| ws['A3'].l = { Target: "http://sheetjs.com", Tooltip: "Visit us <SheetJS.com!>" }; | ||||
| 
 | ||||
| /* TEST: built-in format */ | ||||
| //ws['A1'].z = "0%"; wb.SSF[9] = "0%"; // Format Code 9
 | ||||
| ws['B1'].z = "0%"; // Format Code 9
 | ||||
| 
 | ||||
| /* TEST: custom format */ | ||||
| //ws['B2'].z = "0.0"; wb.SSF[60] = "0.0"; // Custom
 | ||||
| console.log("JSON Data: "); console.log(XLSX.utils.sheet_to_json(ws, {header:1})); | ||||
| 
 | ||||
| console.log("JSON Data:");console.log(XLSX.utils.sheet_to_json(ws, {header:1})); | ||||
| 
 | ||||
| /* TEST: hidden sheets */ | ||||
| wb.SheetNames.push("Hidden"); | ||||
| @ -99,7 +100,7 @@ wb.Props = { | ||||
| 
 | ||||
| /* TEST: comments */ | ||||
| ws['A4'].c = []; | ||||
| ws['A4'].c.push({a:"SheetJS",t:"I'm a little comment, short and stout!"}); | ||||
| ws['A4'].c.push({a:"SheetJS",t:"I'm a little comment, short and stout!\n\nWell, Stout may be the wrong word"}); | ||||
| 
 | ||||
| console.log("Worksheet Model:") | ||||
| console.log(ws); | ||||
| @ -114,6 +115,8 @@ XLSX.writeFile(wb, 'sheetjs.ods'); | ||||
| XLSX.writeFile(wb, 'sheetjs.fods'); | ||||
| XLSX.writeFile(wb, 'sheetjs.slk'); | ||||
| XLSX.writeFile(wb, 'sheetjs.csv'); | ||||
| XLSX.writeFile(wb, 'sheetjs.txt'); | ||||
| XLSX.writeFile(wb, 'sheetjs.prn'); | ||||
| 
 | ||||
| /* test by reading back files */ | ||||
| XLSX.readFile('sheetjs.xlsx'); | ||||
| @ -125,3 +128,5 @@ XLSX.readFile('sheetjs.ods'); | ||||
| XLSX.readFile('sheetjs.fods'); | ||||
| XLSX.readFile('sheetjs.slk'); | ||||
| //XLSX.readFile('sheetjs.csv');
 | ||||
| //XLSX.readFile('sheetjs.txt');
 | ||||
| XLSX.readFile('sheetjs.prn'); | ||||
|  | ||||
							
								
								
									
										147
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										147
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -109,6 +109,8 @@ type EvertNumType = {[string]:number}; | ||||
| type EvertArrType = {[string]:Array<string>}; | ||||
| 
 | ||||
| type StringConv = {(string):string}; | ||||
| 
 | ||||
| type WriteObjStrFactory = {from_sheet(ws:Worksheet, o:any):string}; | ||||
| */ | ||||
| /* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /*jshint -W041 */ | ||||
| @ -2106,9 +2108,8 @@ function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { | ||||
| 			else if(typeof cell.v === 'boolean') cell.t = 'b'; | ||||
| 			else if(cell.v instanceof Date) { | ||||
| 				cell.z = o.dateNF || SSF._table[14]; | ||||
| 				if(o.cellDates) cell.t = 'd'; | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); } | ||||
| 				cell.w = SSF.format(cell.z, cell.v); | ||||
| 				if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); } | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); } | ||||
| 			} | ||||
| 			else cell.t = 's'; | ||||
| 			ws[cell_ref] = cell; | ||||
| @ -4816,7 +4817,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 	var memo = false; | ||||
| 	var vfp = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x03: break; | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| @ -4824,33 +4825,38 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1)); | ||||
| 	var nrow = d.read_shift(4); | ||||
| 	var fpos = d.read_shift(2); | ||||
| 	var filedate = new Date(), nrow = 0, fpos = 0; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1)); | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l+=16; | ||||
| 
 | ||||
| 	var flags = d.read_shift(1); | ||||
| 	var flags = 0, current_cp = 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	flags = d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	var current_cp = 1252; | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 	} | ||||
| 	var fields = [], field = {}; | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0); | ||||
| 	while(d.l < hend) { | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 		field = {}; | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+10)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += 11; | ||||
| 		field.type = String.fromCharCode(d.read_shift(1)); | ||||
| 		field.offset = d.read_shift(4); | ||||
| 		if(ft != 0x02) field.offset = d.read_shift(4); | ||||
| 		field.len = d.read_shift(1); | ||||
| 		if(ft == 0x02) field.offset = d.read_shift(2); | ||||
| 		field.dec = d.read_shift(1); | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		d.l += 14; | ||||
| 		if(ft != 0x02) d.l += 14; | ||||
| 		switch(field.type) { | ||||
| 			// case 'B': break; // Binary
 | ||||
| 			case 'C': break; // character
 | ||||
| @ -4872,8 +4878,11 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		} | ||||
| 	} | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| @ -4921,7 +4930,7 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); | ||||
| 	if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| @ -5133,8 +5142,9 @@ var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/) { | ||||
| 		if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){} | ||||
| 		else if(+data == +data) arr[R][C] = +data; | ||||
| 		else if(data !== "") arr[R][C] = data; | ||||
| 		else arr[R][C] = data; | ||||
| 	} | ||||
| 
 | ||||
| 	function prn_to_aoa_str(f/*:string*/, opts)/*:AOA*/ { | ||||
| @ -5165,9 +5175,27 @@ var PRN = (function() { | ||||
| 
 | ||||
| 	function prn_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(prn_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	function sheet_to_prn(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ { | ||||
| 		var o/*:Array<string>*/ = []; | ||||
| 		var r = decode_range(ws['!ref']), cell/*:Cell*/; | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			var oo = []; | ||||
| 			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) { oo.push("          "); continue; } | ||||
| 				var w = (cell.w || (format_cell(cell), cell.w) || "").substr(0,10); | ||||
| 				while(w.length < 10) w += " "; | ||||
| 				oo.push(w + (C == 0 ? " " : "")); | ||||
| 			} | ||||
| 			o.push(oo.join("")); | ||||
| 		} | ||||
| 		return o.join("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		to_workbook: prn_to_workbook, | ||||
| 		to_sheet: prn_to_sheet | ||||
| 		to_sheet: prn_to_sheet, | ||||
| 		from_sheet: sheet_to_prn | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| @ -6741,8 +6769,9 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array<Comment>*/ { | ||||
| 		var cell = decode_cell(y.ref); | ||||
| 		if(opts.sheetRows && opts.sheetRows <= cell.r) return; | ||||
| 		var textMatch = x.match(/<(?:\w+:)?text>([^\u2603]*)<\/(?:\w+:)?text>/); | ||||
| 		var rt = (!textMatch || !textMatch[1]) ? {r:"",t:"",h:""} : parse_si(textMatch[1]); | ||||
| 		var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""}; | ||||
| 		comment.r = rt.r; | ||||
| 		if(rt.r == "<t></t>") rt.t = rt.h = ""; | ||||
| 		comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"); | ||||
| 		if(opts.cellHTML) comment.h = rt.h; | ||||
| 		commentList.push(comment); | ||||
| @ -6769,7 +6798,7 @@ function write_comments_xml(data, opts) { | ||||
| 		d[1].forEach(function(c) { | ||||
| 			/* 18.7.3 CT_Comment */ | ||||
| 			o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>'); | ||||
| 			o.push(writetag("t", c.t)); | ||||
| 			o.push(writetag("t", c.t == null ? "" : c.t)); | ||||
| 			o.push('</text></comment>'); | ||||
| 		}); | ||||
| 	}); | ||||
| @ -6790,7 +6819,7 @@ function parse_BrtBeginComment(data, length) { | ||||
| function write_BrtBeginComment(data, o) { | ||||
| 	if(o == null) o = new_buf(36); | ||||
| 	o.write_shift(4, data[1].iauthor); | ||||
| 	write_UncheckedRfX(data[0], o); | ||||
| 	write_UncheckedRfX((data[0]/*:any*/), o); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| @ -6853,7 +6882,7 @@ function write_comments_bin(data, opts) { | ||||
| 		data.forEach(function(comment) { | ||||
| 			comment[1].forEach(function(c) { | ||||
| 				c.iauthor = iauthor.indexOf(c.a); | ||||
| 				var range = {s:decode_cell(comment[0])}; range.e = range.s; | ||||
| 				var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])}; | ||||
| 				write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c])); | ||||
| 				if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_RichStr(c)); | ||||
| 				write_record(ba, "BrtEndComment"); | ||||
| @ -10522,11 +10551,18 @@ function parse_wb_defaults(wb) { | ||||
| 	_ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904, 'date1904'); | ||||
| } | ||||
| 
 | ||||
| /* TODO: validate workbook */ | ||||
| function check_wb_names(N) { | ||||
| 	var badchars = "][*?\/\\".split(""); | ||||
| 	N.forEach(function(n,i) { | ||||
| 		badchars.forEach(function(c) { if(n.indexOf(c) > -1) throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); }); | ||||
| 		if(n.length > 31) throw new Error("Sheet names cannot exceed 31 chars"); | ||||
| 		for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n); | ||||
| 	}); | ||||
| } | ||||
| function check_wb(wb) { | ||||
| 	if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook"); | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) for(var j = 0; j < i; ++j) | ||||
| 		if(wb.SheetNames[i] == wb.SheetNames[j]) throw new Error("Duplicate Sheet Name: " + wb.SheetNames[i]); | ||||
| 	check_wb_names(wb.SheetNames); | ||||
| 	/* TODO: validate workbook */ | ||||
| } | ||||
| /* 18.2 Workbook */ | ||||
| var wbnsregex = /<\w+:workbook/; | ||||
| @ -14152,7 +14188,7 @@ var parse_content_xml = (function() { | ||||
| 		var sheetag/*:: = {name:"", '名称':""}*/; | ||||
| 		var rowtag/*:: = {'行号':""}*/; | ||||
| 		var Sheets = {}, SheetNames/*:Array<string>*/ = [], ws = {}; | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:""}:any)*/; | ||||
| 		var Rn, q/*:: = ({t:"", v:null, z:null, w:"",c:[]}:any)*/; | ||||
| 		var ctag = {value:""}; | ||||
| 		var textp = "", textpidx = 0, textptag/*:: = {}*/; | ||||
| 		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; | ||||
| @ -14207,7 +14243,7 @@ var parse_content_xml = (function() { | ||||
| 					if(R < range.s.r) range.s.r = R; | ||||
| 					ctag = parsexmltag(Rn[0], false); | ||||
| 					comments = []; comment = {}; | ||||
| 					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:""*/}/*:any*/); | ||||
| 					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:"",c:[]*/}/*:any*/); | ||||
| 					if(opts.cellFormula) { | ||||
| 						if(ctag.formula) ctag.formula = unescapexml(ctag.formula); | ||||
| 						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) { | ||||
| @ -14265,7 +14301,7 @@ var parse_content_xml = (function() { | ||||
| 							if(range.e.c <= C) range.e.c = C; | ||||
| 						} | ||||
| 					} else { C += rept; rept = 0; } | ||||
| 					q = {/*:: t:"", v:null, z:null, w:""*/}; | ||||
| 					q = {/*:: t:"", v:null, z:null, w:"",c:[]*/}; | ||||
| 					textp = ""; | ||||
| 				} | ||||
| 				break; // 9.1.4 <table:table-cell>
 | ||||
| @ -14289,7 +14325,7 @@ var parse_content_xml = (function() { | ||||
| 					comments.push(comment); | ||||
| 				} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);} | ||||
| 				creator = ""; creatorpidx = 0; | ||||
| 				creator = ""; creatoridx = 0; | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
| @ -14614,16 +14650,9 @@ var write_content_xml/*:{(wb:any, opts:any):string}*/ = (function() { | ||||
| 		return o.join(""); | ||||
| 	}; | ||||
| })(); | ||||
| /* actual implementation in utils, wrappers are for read/write */ | ||||
| function write_csv_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 sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| } | ||||
| 
 | ||||
| function write_obj_str(factory) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/) { | ||||
| /* actual implementation elsewhere, wrappers are for read/write */ | ||||
| function write_obj_str(factory/*:WriteObjStrFactory*/) { | ||||
| 	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/)/*:string*/ { | ||||
| 		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); | ||||
| @ -14631,8 +14660,11 @@ function write_obj_str(factory) { | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_csv_str = write_obj_str({from_sheet:sheet_to_csv}); | ||||
| var write_slk_str = write_obj_str(SYLK); | ||||
| var write_dif_str = write_obj_str(DIF); | ||||
| var write_prn_str = write_obj_str(PRN); | ||||
| var write_txt_str = write_obj_str({from_sheet:sheet_to_txt}); | ||||
| /* Part 3: Packages */ | ||||
| function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/) { | ||||
| 	opts = opts || ({}/*:any*/); | ||||
| @ -14925,9 +14957,10 @@ 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; | ||||
| 	if(wb.Props && wb.Props.SheetNames){} | ||||
| 	else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	else wb.Props.SheetNames = wb.SheetNames.map(function(x,i) { return [(wb.Workbook.Sheets[i]||{}).Hidden != 2, x];}).filter(function(x) { return x[0]; }).map(function(x) { return x[1]; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| @ -15045,10 +15078,11 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		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); | ||||
| 		case 0x30: case 0x31: if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); break; | ||||
| 		default: throw new Error("Unsupported file " + n.join("|")); | ||||
| 	} | ||||
| 	throw new Error("Unsupported file format " + n.join("|")); | ||||
| 	if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); | ||||
| 	if(0x20>n[0]||n[0]>0x7F) throw new Error("Unsupported file " + n.join("|")); | ||||
| 	/* TODO: CSV / TXT */ | ||||
| 	return PRN.to_workbook(d, o); | ||||
| } | ||||
| 
 | ||||
| function readFileSync(filename/*:string*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| @ -15071,6 +15105,20 @@ function write_zip_type(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 	return z.generate(oopts); | ||||
| } | ||||
| 
 | ||||
| /* TODO: test consistency */ | ||||
| function write_bstr_type(out/*:string*/, opts/*:WriteOpts*/) { | ||||
| 	switch(opts.type) { | ||||
| 		case "base64": return Base64.encode(out); | ||||
| 		case "binary": return out; | ||||
| 		case "file": return _fs.writeFileSync(opts.file, out, 'binary'); | ||||
| 		case "buffer": { | ||||
| 			if(has_buf) return new Buffer(out, 'utf8'); | ||||
| 			else return out.split("").map(function(c) { return c.charCodeAt(0); }); | ||||
| 		} | ||||
| 	} | ||||
| 	throw new Error("Unrecognized type " + opts.type); | ||||
| } | ||||
| 
 | ||||
| /* TODO: test consistency */ | ||||
| function write_string_type(out/*:string*/, opts/*:WriteOpts*/) { | ||||
| 	switch(opts.type) { | ||||
| @ -15107,8 +15155,10 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { | ||||
| 		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 'txt': return write_bstr_type(write_txt_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 'prn': return write_string_type(write_prn_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': | ||||
| @ -15131,7 +15181,9 @@ function resolve_book_type(o/*?WriteFileOpts*/) { | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| 		case '.ods': o.bookType = 'ods'; break; | ||||
| 		case '.csv': o.bookType = 'csv'; break; | ||||
| 		case '.txt': o.bookType = 'txt'; break; | ||||
| 		case '.dif': o.bookType = 'dif'; break; | ||||
| 		case '.prn': o.bookType = 'prn'; break; | ||||
| 		case '.slk': o.bookType = 'sylk'; break; | ||||
| 	} | ||||
| } | ||||
| @ -15341,6 +15393,13 @@ function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	return out; | ||||
| } | ||||
| var make_csv = sheet_to_csv; | ||||
| function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { | ||||
| 	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n"; | ||||
| 	var s = sheet_to_csv(sheet, opts); | ||||
| 	if(typeof cptable == 'undefined') return s; | ||||
| 	var o = cptable.utils.encode(1200, s); | ||||
| 	return "\xff\xfe" + o; | ||||
| } | ||||
| 
 | ||||
| function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ { | ||||
| 	var y = "", x, val=""; | ||||
|  | ||||
							
								
								
									
										135
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										135
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -2054,9 +2054,8 @@ function aoa_to_sheet(data, opts) { | ||||
| 			else if(typeof cell.v === 'boolean') cell.t = 'b'; | ||||
| 			else if(cell.v instanceof Date) { | ||||
| 				cell.z = o.dateNF || SSF._table[14]; | ||||
| 				if(o.cellDates) cell.t = 'd'; | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); } | ||||
| 				cell.w = SSF.format(cell.z, cell.v); | ||||
| 				if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); } | ||||
| 				else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); } | ||||
| 			} | ||||
| 			else cell.t = 's'; | ||||
| 			ws[cell_ref] = cell; | ||||
| @ -4762,7 +4761,7 @@ function dbf_to_aoa(buf, opts) { | ||||
| 	var memo = false; | ||||
| 	var vfp = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x03: break; | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| @ -4770,33 +4769,38 @@ function dbf_to_aoa(buf, opts) { | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1)); | ||||
| 	var nrow = d.read_shift(4); | ||||
| 	var fpos = d.read_shift(2); | ||||
| 	var filedate = new Date(), nrow = 0, fpos = 0; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1)); | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l+=16; | ||||
| 
 | ||||
| 	var flags = d.read_shift(1); | ||||
| 	var flags = 0, current_cp = 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	flags = d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	var current_cp = 1252; | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 	} | ||||
| 	var fields = [], field = {}; | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0); | ||||
| 	while(d.l < hend) { | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 		field = {}; | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+10)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += 11; | ||||
| 		field.type = String.fromCharCode(d.read_shift(1)); | ||||
| 		field.offset = d.read_shift(4); | ||||
| 		if(ft != 0x02) field.offset = d.read_shift(4); | ||||
| 		field.len = d.read_shift(1); | ||||
| 		if(ft == 0x02) field.offset = d.read_shift(2); | ||||
| 		field.dec = d.read_shift(1); | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		d.l += 14; | ||||
| 		if(ft != 0x02) d.l += 14; | ||||
| 		switch(field.type) { | ||||
| 			// case 'B': break; // Binary
 | ||||
| 			case 'C': break; // character
 | ||||
| @ -4818,8 +4822,11 @@ function dbf_to_aoa(buf, opts) { | ||||
| 		} | ||||
| 	} | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| @ -4867,7 +4874,7 @@ function dbf_to_aoa(buf, opts) { | ||||
| 			} | ||||
| 		} | ||||
| 	} | ||||
| 	if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); | ||||
| 	if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16)); | ||||
| 	return out; | ||||
| } | ||||
| 
 | ||||
| @ -5079,8 +5086,9 @@ var PRN = (function() { | ||||
| 	function set_text_arr(data, arr, R, C) { | ||||
| 		if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){} | ||||
| 		else if(+data == +data) arr[R][C] = +data; | ||||
| 		else if(data !== "") arr[R][C] = data; | ||||
| 		else arr[R][C] = data; | ||||
| 	} | ||||
| 
 | ||||
| 	function prn_to_aoa_str(f, opts) { | ||||
| @ -5111,9 +5119,27 @@ var PRN = (function() { | ||||
| 
 | ||||
| 	function prn_to_workbook(str, opts) { return sheet_to_workbook(prn_to_sheet(str, opts), opts); } | ||||
| 
 | ||||
| 	function sheet_to_prn(ws, opts) { | ||||
| 		var o = []; | ||||
| 		var r = decode_range(ws['!ref']), cell; | ||||
| 		for(var R = r.s.r; R <= r.e.r; ++R) { | ||||
| 			var oo = []; | ||||
| 			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) { oo.push("          "); continue; } | ||||
| 				var w = (cell.w || (format_cell(cell), cell.w) || "").substr(0,10); | ||||
| 				while(w.length < 10) w += " "; | ||||
| 				oo.push(w + (C == 0 ? " " : "")); | ||||
| 			} | ||||
| 			o.push(oo.join("")); | ||||
| 		} | ||||
| 		return o.join("\n"); | ||||
| 	} | ||||
| 
 | ||||
| 	return { | ||||
| 		to_workbook: prn_to_workbook, | ||||
| 		to_sheet: prn_to_sheet | ||||
| 		to_sheet: prn_to_sheet, | ||||
| 		from_sheet: sheet_to_prn | ||||
| 	}; | ||||
| })(); | ||||
| 
 | ||||
| @ -6687,8 +6713,9 @@ function parse_comments_xml(data, opts) { | ||||
| 		var cell = decode_cell(y.ref); | ||||
| 		if(opts.sheetRows && opts.sheetRows <= cell.r) return; | ||||
| 		var textMatch = x.match(/<(?:\w+:)?text>([^\u2603]*)<\/(?:\w+:)?text>/); | ||||
| 		var rt = (!textMatch || !textMatch[1]) ? {r:"",t:"",h:""} : parse_si(textMatch[1]); | ||||
| 		var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""}; | ||||
| 		comment.r = rt.r; | ||||
| 		if(rt.r == "<t></t>") rt.t = rt.h = ""; | ||||
| 		comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n"); | ||||
| 		if(opts.cellHTML) comment.h = rt.h; | ||||
| 		commentList.push(comment); | ||||
| @ -6715,7 +6742,7 @@ function write_comments_xml(data, opts) { | ||||
| 		d[1].forEach(function(c) { | ||||
| 			/* 18.7.3 CT_Comment */ | ||||
| 			o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>'); | ||||
| 			o.push(writetag("t", c.t)); | ||||
| 			o.push(writetag("t", c.t == null ? "" : c.t)); | ||||
| 			o.push('</text></comment>'); | ||||
| 		}); | ||||
| 	}); | ||||
| @ -6736,7 +6763,7 @@ function parse_BrtBeginComment(data, length) { | ||||
| function write_BrtBeginComment(data, o) { | ||||
| 	if(o == null) o = new_buf(36); | ||||
| 	o.write_shift(4, data[1].iauthor); | ||||
| 	write_UncheckedRfX(data[0], o); | ||||
| 	write_UncheckedRfX((data[0]), o); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| 	o.write_shift(4, 0); | ||||
| @ -6799,7 +6826,7 @@ function write_comments_bin(data, opts) { | ||||
| 		data.forEach(function(comment) { | ||||
| 			comment[1].forEach(function(c) { | ||||
| 				c.iauthor = iauthor.indexOf(c.a); | ||||
| 				var range = {s:decode_cell(comment[0])}; range.e = range.s; | ||||
| 				var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])}; | ||||
| 				write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c])); | ||||
| 				if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_RichStr(c)); | ||||
| 				write_record(ba, "BrtEndComment"); | ||||
| @ -10467,11 +10494,18 @@ function parse_wb_defaults(wb) { | ||||
| 	_ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904, 'date1904'); | ||||
| } | ||||
| 
 | ||||
| /* TODO: validate workbook */ | ||||
| function check_wb_names(N) { | ||||
| 	var badchars = "][*?\/\\".split(""); | ||||
| 	N.forEach(function(n,i) { | ||||
| 		badchars.forEach(function(c) { if(n.indexOf(c) > -1) throw new Error("Sheet name cannot contain : \\ / ? * [ ]"); }); | ||||
| 		if(n.length > 31) throw new Error("Sheet names cannot exceed 31 chars"); | ||||
| 		for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n); | ||||
| 	}); | ||||
| } | ||||
| function check_wb(wb) { | ||||
| 	if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook"); | ||||
| 	for(var i = 0; i < wb.SheetNames.length; ++i) for(var j = 0; j < i; ++j) | ||||
| 		if(wb.SheetNames[i] == wb.SheetNames[j]) throw new Error("Duplicate Sheet Name: " + wb.SheetNames[i]); | ||||
| 	check_wb_names(wb.SheetNames); | ||||
| 	/* TODO: validate workbook */ | ||||
| } | ||||
| /* 18.2 Workbook */ | ||||
| var wbnsregex = /<\w+:workbook/; | ||||
| @ -14230,7 +14264,7 @@ var parse_content_xml = (function() { | ||||
| 					comments.push(comment); | ||||
| 				} | ||||
| 				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);} | ||||
| 				creator = ""; creatorpidx = 0; | ||||
| 				creator = ""; creatoridx = 0; | ||||
| 				textp = ""; textpidx = 0; | ||||
| 				break; | ||||
| 
 | ||||
| @ -14555,14 +14589,7 @@ var write_content_xml = (function() { | ||||
| 		return o.join(""); | ||||
| 	}; | ||||
| })(); | ||||
| /* actual implementation in utils, wrappers are for read/write */ | ||||
| function write_csv_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 sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o); | ||||
| } | ||||
| 
 | ||||
| /* actual implementation elsewhere, wrappers are for read/write */ | ||||
| function write_obj_str(factory) { | ||||
| 	return function write_str(wb, o) { | ||||
| 		var idx = 0; | ||||
| @ -14572,8 +14599,11 @@ function write_obj_str(factory) { | ||||
| 	}; | ||||
| } | ||||
| 
 | ||||
| var write_csv_str = write_obj_str({from_sheet:sheet_to_csv}); | ||||
| var write_slk_str = write_obj_str(SYLK); | ||||
| var write_dif_str = write_obj_str(DIF); | ||||
| var write_prn_str = write_obj_str(PRN); | ||||
| var write_txt_str = write_obj_str({from_sheet:sheet_to_txt}); | ||||
| /* Part 3: Packages */ | ||||
| function parse_ods(zip, opts) { | ||||
| 	opts = opts || ({}); | ||||
| @ -14863,9 +14893,10 @@ var zip = new jszip(); | ||||
| 	add_rels(opts.rels, 2, f, RELS.CORE_PROPS); | ||||
| 
 | ||||
| f = "docProps/app.xml"; | ||||
| 	if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	if(wb.Props && wb.Props.SheetNames){} | ||||
| 	else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames; | ||||
| 	// $FlowIgnore
 | ||||
| 	else wb.Props.SheetNames = wb.Workbook.Sheets.filter(function(x) { return x.Hidden != 2; }).map(function(x) { return x.name; }); | ||||
| 	else wb.Props.SheetNames = wb.SheetNames.map(function(x,i) { return [(wb.Workbook.Sheets[i]||{}).Hidden != 2, x];}).filter(function(x) { return x[0]; }).map(function(x) { return x[1]; }); | ||||
| 	wb.Props.Worksheets = wb.Props.SheetNames.length; | ||||
| 	zip.file(f, write_ext_props(wb.Props, opts)); | ||||
| 	ct.extprops.push(f); | ||||
| @ -14982,10 +15013,11 @@ function readSync(data, opts) { | ||||
| 		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); | ||||
| 		case 0x30: case 0x31: if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); break; | ||||
| 		default: throw new Error("Unsupported file " + n.join("|")); | ||||
| 	} | ||||
| 	throw new Error("Unsupported file format " + n.join("|")); | ||||
| 	if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o); | ||||
| 	if(0x20>n[0]||n[0]>0x7F) throw new Error("Unsupported file " + n.join("|")); | ||||
| 	/* TODO: CSV / TXT */ | ||||
| 	return PRN.to_workbook(d, o); | ||||
| } | ||||
| 
 | ||||
| function readFileSync(filename, opts) { | ||||
| @ -15008,6 +15040,20 @@ function write_zip_type(wb, opts) { | ||||
| 	return z.generate(oopts); | ||||
| } | ||||
| 
 | ||||
| /* TODO: test consistency */ | ||||
| function write_bstr_type(out, opts) { | ||||
| 	switch(opts.type) { | ||||
| 		case "base64": return Base64.encode(out); | ||||
| 		case "binary": return out; | ||||
| 		case "file": return _fs.writeFileSync(opts.file, out, 'binary'); | ||||
| 		case "buffer": { | ||||
| 			if(has_buf) return new Buffer(out, 'utf8'); | ||||
| 			else return out.split("").map(function(c) { return c.charCodeAt(0); }); | ||||
| 		} | ||||
| 	} | ||||
| 	throw new Error("Unrecognized type " + opts.type); | ||||
| } | ||||
| 
 | ||||
| /* TODO: test consistency */ | ||||
| function write_string_type(out, opts) { | ||||
| 	switch(opts.type) { | ||||
| @ -15044,8 +15090,10 @@ function writeSync(wb, opts) { | ||||
| 		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 'txt': return write_bstr_type(write_txt_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 'prn': return write_string_type(write_prn_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': | ||||
| @ -15068,7 +15116,9 @@ function resolve_book_type(o/*?WriteFileOpts*/) { | ||||
| 		case '.xml': o.bookType = 'xml'; break; | ||||
| 		case '.ods': o.bookType = 'ods'; break; | ||||
| 		case '.csv': o.bookType = 'csv'; break; | ||||
| 		case '.txt': o.bookType = 'txt'; break; | ||||
| 		case '.dif': o.bookType = 'dif'; break; | ||||
| 		case '.prn': o.bookType = 'prn'; break; | ||||
| 		case '.slk': o.bookType = 'sylk'; break; | ||||
| 	} | ||||
| } | ||||
| @ -15273,6 +15323,13 @@ function sheet_to_csv(sheet, opts) { | ||||
| 	return out; | ||||
| } | ||||
| var make_csv = sheet_to_csv; | ||||
| function sheet_to_txt(sheet, opts) { | ||||
| 	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n"; | ||||
| 	var s = sheet_to_csv(sheet, opts); | ||||
| 	if(typeof cptable == 'undefined') return s; | ||||
| 	var o = cptable.utils.encode(1200, s); | ||||
| 	return "\xff\xfe" + o; | ||||
| } | ||||
| 
 | ||||
| function sheet_to_formulae(sheet) { | ||||
| 	var y = "", x, val=""; | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user