forked from sheetjs/sheetjs
		
	miscellany
- systemjs browser example - more precise file type resolution - small corner cases from test corpus - removed neq in tests (fixes #735 h/t @TeamworkGuy2) - package.json devDependencies versions (fixes #740 h/t @the-spyke)
This commit is contained in:
		
							parent
							
								
									6a913d3a7b
								
							
						
					
					
						commit
						807eac273b
					
				| @ -5,6 +5,11 @@ but not limited to API changes and file location changes.  Minor behavioral | ||||
| changes may not be included if they are not expected to break existing code. | ||||
| 
 | ||||
| 
 | ||||
| ## Unreleased  (2017-??-??) | ||||
| 
 | ||||
| * XLML/HTML resolution logic looks further into the data stream to decide type | ||||
| * Errors thrown on suspected RTF files | ||||
| 
 | ||||
| ## 0.10.5 (2017-06-09) | ||||
| 
 | ||||
| * HTML Table output header/footer should not include `<table>` tag | ||||
|  | ||||
							
								
								
									
										16
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										16
									
								
								README.md
									
									
									
									
									
								
							| @ -1381,6 +1381,7 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| | Option Name | Default | Description                                          | | ||||
| | :---------- | ------: | :--------------------------------------------------- | | ||||
| | type        |         | Input data encoding (see Input Type below)           | | ||||
| | raw         |         | If true, plaintext parsing will not parse values **  | | ||||
| | cellFormula | true    | Save formulae to the .f field                        | | ||||
| | cellHTML    | true    | Parse rich text and save HTML to the `.h` field      | | ||||
| | cellNF      | false   | Save number format string to the `.z` field          | | ||||
| @ -1400,6 +1401,8 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| 
 | ||||
| - Even if `cellNF` is false, formatted text will be generated and saved to `.w` | ||||
| - In some cases, sheets may be parsed even if `bookSheets` is false. | ||||
| - Excel aggressively tries to interpret values from CSV and other plaintext. | ||||
|   This leads to surprising behavior! The `raw` option suppresses value parsing. | ||||
| - `bookSheets` and `bookProps` combine to give both sets of information | ||||
| - `Deps` will be an empty object if `bookDeps` is falsy | ||||
| - `bookFiles` behavior depends on file type: | ||||
| @ -1446,8 +1449,13 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| | `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` | UTF16 Encoded | SpreadsheetML or Flat ODS or UOS1 or plaintext      | | ||||
| | `0xEF` | UTF8 Encoded  | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0xFF` | UTF16 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x00` | Record Stream | Lotus WK\* or Quattro Pro or plaintext              | | ||||
| | `0x0A` | Plaintext     | RTF or plaintext                                    | | ||||
| | `0x0A` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x0D` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x20` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| 
 | ||||
| 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) | ||||
| @ -1456,13 +1464,17 @@ Plaintext format guessing follows the priority order: | ||||
| 
 | ||||
| | Format | Test                                                                | | ||||
| |:-------|:--------------------------------------------------------------------| | ||||
| | HTML   | starts with `<html`                                                 | | ||||
| | XML    | `<?xml` appears in the first 1024 characters                        | | ||||
| | HTML   | starts with `<` and HTML tags appear in the first 1024 characters * | | ||||
| | XML    | starts with `<`                                                     | | ||||
| | RTF    | starts with `{\rt`                                                  | | ||||
| | DSV    | starts with `/sep=.$/`, separator is the specified character        | | ||||
| | TSV    | one of the first 1024 characters is a tab char `"\t"`               | | ||||
| | CSV    | one of the first 1024 characters is a comma char `","`              | | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| - HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|  | ||||
| @ -2,6 +2,7 @@ var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' & | ||||
| 
 | ||||
| function new_raw_buf(len/*:number*/) { | ||||
| 	/* jshint -W056 */ | ||||
| 	// $FlowIgnore
 | ||||
| 	return new (has_buf ? Buffer : Array)(len); | ||||
| 	/* jshint +W056 */ | ||||
| } | ||||
|  | ||||
| @ -57,6 +57,7 @@ function parse_ext_props(data, p) { | ||||
| 					break; | ||||
| 
 | ||||
| 				case "Named Ranges": | ||||
| 				case "名前付き一覧": | ||||
| 				case "Benannte Bereiche": | ||||
| 				case "Navngivne områder": | ||||
| 					p.NamedRanges = len; | ||||
|  | ||||
| @ -37,6 +37,7 @@ function parse_cust_props(data/*:string*/, opts) { | ||||
| 						p[name] = unescapexml(text); | ||||
| 						break; | ||||
| 					default: | ||||
| 						if(type.slice(-1) == '/') break; | ||||
| 						if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks); | ||||
| 				} | ||||
| 			} else if(x.substr(0,2) === "</") {/* empty */ | ||||
|  | ||||
| @ -357,7 +357,13 @@ function parse_XLUnicodeString2(blob, length, opts) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.61 ControlInfo */ | ||||
| var parse_ControlInfo = parsenoop; | ||||
| function parse_ControlInfo(blob, length, opts) { | ||||
| 	var flags = blob.read_shift(1); | ||||
| 	blob.l++; | ||||
| 	var accel = blob.read_shift(2); | ||||
| 	blob.l += 2; | ||||
| 	return [flags, accel]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */ | ||||
| var parse_URLMoniker = function(blob/*::, length, opts*/) { | ||||
| @ -420,7 +426,7 @@ var parse_Hyperlink = function(blob, length) { | ||||
| 	if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l); | ||||
| 	if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l); | ||||
| 	if(flags & 0x0020) guid = blob.read_shift(16); | ||||
| 	if(flags & 0x0040) fileTime = parse_FILETIME(blob, 8); | ||||
| 	if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/); | ||||
| 	blob.l = end; | ||||
| 	var target = (targetFrameName||moniker||oleMoniker); | ||||
| 	if(location) target+="#"+location; | ||||
|  | ||||
| @ -477,8 +477,9 @@ var DIF = (function() { | ||||
| })(); | ||||
| 
 | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/) { | ||||
| 		if(data === 'TRUE') arr[R][C] = true; | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(+data == +data) arr[R][C] = +data; | ||||
| @ -487,6 +488,7 @@ var PRN = (function() { | ||||
| 	} | ||||
| 
 | ||||
| 	function prn_to_aoa_str(f/*:string*/, opts)/*:AOA*/ { | ||||
| 		var o = opts || {}; | ||||
| 		var arr/*:AOA*/ = ([]/*:any*/); | ||||
| 		if(!f || f.length === 0) return arr; | ||||
| 		var lines = f.split(/[\r\n]/); | ||||
| @ -503,9 +505,9 @@ var PRN = (function() { | ||||
| 			arr[R] = []; | ||||
| 			/* TODO: confirm that widths are always 10 */ | ||||
| 			var C = 0; | ||||
| 			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C); | ||||
| 			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o); | ||||
| 			for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C) | ||||
| 				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C); | ||||
| 				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o); | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| @ -622,3 +624,4 @@ function read_wb_ID(d, opts) { | ||||
| 		return PRN.to_workbook(d, opts); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -124,7 +124,7 @@ function parse_EncryptionVerifier(blob, length/*:number*/) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */ | ||||
| function parse_EncryptionInfo(blob, length) { | ||||
| function parse_EncryptionInfo(blob, length/*:?number*/) { | ||||
| 	var vers = parse_CRYPTOVersion(blob); | ||||
| 	switch(vers.Minor) { | ||||
| 		case 0x02: return parse_EncInfoStd(blob, vers); | ||||
| @ -156,8 +156,8 @@ function parse_EncInfoAgl(blob, vers) { throw new Error("File is password-protec | ||||
| function parse_RC4CryptoHeader(blob, length/*:number*/) { | ||||
| 	var o = {}; | ||||
| 	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4; | ||||
| 	if(vers.Minor != 2) throw 'unrecognized minor version code: ' + vers.Minor; | ||||
| 	if(vers.Major > 4 || vers.Major < 2) throw 'unrecognized major version code: ' + vers.Major; | ||||
| 	if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor); | ||||
| 	if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major); | ||||
| 	o.Flags = blob.read_shift(4); length -= 4; | ||||
| 	var sz = blob.read_shift(4); length -= 4; | ||||
| 	o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz; | ||||
| @ -294,7 +294,7 @@ function parse_FilePassHeader(blob, length/*:number*/, oo) { | ||||
| 	return o; | ||||
| } | ||||
| function parse_FilePass(blob, length/*:number*/, opts) { | ||||
| 	var o = { Type: blob.read_shift(2) }; /* wEncryptionType */ | ||||
| 	var o = { Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }; /* wEncryptionType */ | ||||
| 	if(o.Type) parse_FilePassHeader(blob, length-2, o); | ||||
| 	else parse_XORObfuscation(blob, length-2, opts, o); | ||||
| 	return o; | ||||
|  | ||||
| @ -8,7 +8,7 @@ function parse_borders(t, styles, themes, opts) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| 
 | ||||
| 			/* 18.8.4 border CT_Border */ | ||||
| 			case '<border': case '<border>': | ||||
| 			case '<border': case '<border>': case '<border/>': | ||||
| 				border = {}; | ||||
| 				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; } | ||||
| 				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; } | ||||
| @ -80,6 +80,7 @@ function parse_fills(t, styles, themes, opts) { | ||||
| 
 | ||||
| 			/* 18.8.24 gradientFill CT_GradientFill */ | ||||
| 			case '<gradientFill>': break; | ||||
| 			case '<gradientFill': | ||||
| 			case '</gradientFill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.32 patternFill CT_PatternFill */ | ||||
| @ -259,7 +260,7 @@ function parse_numFmts(t, styles, opts) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function write_numFmts(NF/*:{[n:number]:string}*/, opts) { | ||||
| function write_numFmts(NF/*:{[n:number|string]:string}*/, opts) { | ||||
| 	var o = ["<numFmts>"]; | ||||
| 	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) { | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
|  | ||||
| @ -410,10 +410,10 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook | ||||
| 	} | ||||
| 	if(rows) for(; R < rows.length; ++R) { | ||||
| 		if(rows && rows[R]) { | ||||
| 			var params = ({r:R+1}/*:any*/); | ||||
| 			var row = rows[R]; | ||||
| 			params = ({r:R+1}/*:any*/); | ||||
| 			row = rows[R]; | ||||
| 			if(row.hidden) params.hidden = 1; | ||||
| 			var height = -1; | ||||
| 			height = -1; | ||||
| 			if (row.hpx) height = px2pt(row.hpx); | ||||
| 			else if (row.hpt) height = row.hpt; | ||||
| 			if (height > -1) { params.ht = height; params.customHeight = 1; } | ||||
|  | ||||
| @ -44,13 +44,13 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 			case '<workbookProtection/>': break; | ||||
| 
 | ||||
| 			/* 18.2.1  bookViews CT_BookViews ? */ | ||||
| 			case '<bookViews>': case '</bookViews>': break; | ||||
| 			case '<bookViews': case '<bookViews>': case '</bookViews>': break; | ||||
| 			/* 18.2.30   workbookView CT_BookView + */ | ||||
| 			case '<workbookView': delete y[0]; wb.WBView.push(y); break; | ||||
| 			case '</workbookView>': break; | ||||
| 
 | ||||
| 			/* 18.2.20 sheets CT_Sheets 1 */ | ||||
| 			case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			/* 18.2.19   sheet CT_Sheet + */ | ||||
| 			case '<sheet': | ||||
| 				switch(y.state) { | ||||
| @ -129,7 +129,7 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 			case '<webPublishObject': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			/* 18.2.7    ext CT_Extension + */ | ||||
| 			case '<ext': pass=true; break; //TODO: check with versions of excel
 | ||||
| 			case '</ext>': pass=false; break; | ||||
|  | ||||
| @ -161,7 +161,7 @@ function xlml_clean_comment(comment/*:any*/) { | ||||
| } | ||||
| 
 | ||||
| function xlml_normalize(d)/*:string*/ { | ||||
| 	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); | ||||
| 	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null && d instanceof Buffer &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); | ||||
| 	if(typeof d === 'string') return d; | ||||
| 	throw new Error("Bad input format: expected Buffer or string"); | ||||
| } | ||||
| @ -175,7 +175,9 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 	make_ssf(SSF); | ||||
| 	var str = debom(xlml_normalize(d)); | ||||
| 	if(opts && opts.type == 'binary' && typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str)); | ||||
| 	if(str.substr(0,1000).indexOf("<html") >= 0) return HTML_.to_workbook(str, opts); | ||||
| 	var opening = str.slice(0, 1024).toLowerCase(), ishtml = false; | ||||
| 	if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; }); | ||||
| 	if(ishtml) return HTML_.to_workbook(str, opts); | ||||
| 	var Rn; | ||||
| 	var state = [], tmp; | ||||
| 	if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
|  | ||||
| @ -25,7 +25,14 @@ function parse_compobj(obj) { | ||||
| 	throw new Error("Unsupported Unicode Extension"); | ||||
| } | ||||
| 
 | ||||
| /* 2.4.58 Continue logic */ | ||||
| /* | ||||
| 	Continue logic for: | ||||
| 	- 2.4.58 Continue | ||||
| 	- 2.4.59 ContinueBigName | ||||
| 	- 2.4.60 ContinueFrt | ||||
| 	- 2.4.61 ContinueFrt11 | ||||
| 	- 2.4.62 ContinueFrt12 | ||||
| */ | ||||
| function slurp(R, blob, length/*:number*/, opts) { | ||||
| 	var l = length; | ||||
| 	var bufs = []; | ||||
| @ -39,9 +46,13 @@ function slurp(R, blob, length/*:number*/, opts) { | ||||
| 	bufs.push(d); | ||||
| 	blob.l += l; | ||||
| 	var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]); | ||||
| 	while(next != null && next.n === 'Continue') { | ||||
| 	var start = 0; | ||||
| 	while(next != null && next.n.slice(0,8) === 'Continue') { | ||||
| 		l = __readUInt16LE(blob,blob.l+2); | ||||
| 		bufs.push(blob.slice(blob.l+4,blob.l+4+l)); | ||||
| 		start = blob.l + 4; | ||||
| 		if(next.n == 'ContinueFrt') start += 4; | ||||
| 		else if(next.n.slice(0,11) == 'ContinueFrt') start += 12; | ||||
| 		bufs.push(blob.slice(start,blob.l+4+l)); | ||||
| 		blob.l += 4+l; | ||||
| 		next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]); | ||||
| 	} | ||||
| @ -278,6 +289,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d') | ||||
| 							FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) }; | ||||
| 					break; | ||||
| 				case 'ExternCount': opts.ExternCount = val; break; | ||||
| 				case 'ExternSheet': | ||||
| 					if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; } | ||||
| 					supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break; | ||||
| @ -557,6 +569,9 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'SXVI': break; // TODO
 | ||||
| 				case 'SXVDEx': break; // TODO
 | ||||
| 				case 'SxIvd': break; // TODO
 | ||||
| 				case 'SXString': break; // TODO
 | ||||
| 				case 'Sync': break; | ||||
| 				case 'Addin': break; | ||||
| 				case 'SXDI': break; // TODO
 | ||||
| 				case 'SXLI': break; // TODO
 | ||||
| 				case 'SXEx': break; // TODO
 | ||||
| @ -663,6 +678,9 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'DbOrParamQry': break; | ||||
| 				case 'DBQueryExt': break; | ||||
| 
 | ||||
| 				case 'OleDbConn': break; | ||||
| 				case 'ExtString': break; | ||||
| 
 | ||||
| 				/* Formatting */ | ||||
| 				case 'IFmtRecord': break; | ||||
| 				case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break; | ||||
| @ -754,7 +772,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 
 | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				/* BIFF5 records */ | ||||
| 				case 'ExternCount': break; | ||||
| 				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break; | ||||
| 
 | ||||
| 				/* BIFF2-4 records */ | ||||
| @ -766,6 +783,10 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt': | ||||
| 				case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData': | ||||
| 				case 'Name': break; | ||||
| 				case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break; | ||||
| 				case 'ListObj': case 'ListField': break; | ||||
| 				case 'RRSort': break; | ||||
| 				case 'BigName': break; | ||||
| 				default: if(options.WTF) throw 'Unrecognized Record ' + R.n; | ||||
| 			}}}} | ||||
| 		} else blob.l += length; | ||||
| @ -818,7 +839,7 @@ var CompObjP, SummaryP, WorkbookP/*:Workbook*/; | ||||
| if(CompObj) CompObjP = parse_compobj(CompObj); | ||||
| if(options.bookProps && !options.bookSheets) WorkbookP = ({}/*:any*/); | ||||
| else { | ||||
| 	if(Workbook) WorkbookP = parse_workbook(Workbook.content, options, !!Workbook.find); | ||||
| 	if(Workbook) WorkbookP = parse_workbook(Workbook.content, options); | ||||
| 	/* Quattro Pro 7-8 */ | ||||
| 	else if(cfb.find('PerfectOffice_MAIN')) WorkbookP = WK_.to_workbook(cfb.find('PerfectOffice_MAIN').content, options); | ||||
| 	/* Quattro Pro 9 */ | ||||
|  | ||||
| @ -4,20 +4,23 @@ var HTML_ = (function() { | ||||
| 		var opts = _opts || {}; | ||||
| 		if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 		var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var i = str.indexOf("<table"), j = str.indexOf("</table"); | ||||
| 		if(i == -1 || j == -1) throw new Error("Invalid HTML: missing <table> / </table> pair"); | ||||
| 		var rows = str.slice(i, j).split(/(:?<tr[^>]*>)/); | ||||
| 		var mtch = str.match(/<table/i); | ||||
| 		if(!mtch) throw new Error("Invalid HTML: could not find <table>"); | ||||
| 		var mtch2 = str.match(/<\/table/i); | ||||
| 		var i = mtch.index, j = mtch2 && mtch2.index || str.length; | ||||
| 		var rows = str.slice(i, j).split(/(:?<tr[^>]*>)/i); | ||||
| 		var R = -1, C = 0, RS = 0, CS = 0; | ||||
| 		var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; | ||||
| 		var merges = [], midx = 0; | ||||
| 		for(i = 0; i < rows.length; ++i) { | ||||
| 			var row = rows[i].trim(); | ||||
| 			if(row.substr(0,3) == "<tr") { ++R; C = 0; continue; } | ||||
| 			if(row.substr(0,3) != "<td") continue; | ||||
| 			var cells = row.split("</td>"); | ||||
| 			var hd = row.substr(0,3).toLowerCase(); | ||||
| 			if(hd == "<tr") { ++R; C = 0; continue; } | ||||
| 			if(hd != "<td") continue; | ||||
| 			var cells = row.split(/<\/td>/i); | ||||
| 			for(j = 0; j < cells.length; ++j) { | ||||
| 				var cell = cells[j].trim(); | ||||
| 				if(cell.substr(0,3) != "<td") continue; | ||||
| 				if(cell.substr(0,3).toLowerCase() != "<td") continue; | ||||
| 				var m = cell, cc = 0; | ||||
| 				/* TODO: parse styles etc */ | ||||
| 				while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1); | ||||
|  | ||||
| @ -289,9 +289,11 @@ var parse_content_xml = (function() { | ||||
| 
 | ||||
| 			case 'forms': break; // 12.25.2 13.2
 | ||||
| 			case 'table-column': break; // 9.1.6 <table:table-column>
 | ||||
| 			case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
 | ||||
| 			/* TODO: outline levels */ | ||||
| 			case 'table-row-group': break; // 9.1.9 <table:table-row-group>
 | ||||
| 			case 'table-column-group': break; // 9.1.10 <table:table-column-group>
 | ||||
| 			case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
 | ||||
| 
 | ||||
| 			case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
 | ||||
| 
 | ||||
| @ -299,14 +301,17 @@ var parse_content_xml = (function() { | ||||
| 			case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
 | ||||
| 			case 'named-expressions': break; // 9.4.11 <table:named-expressions>
 | ||||
| 			case 'named-range': break; // 9.4.12 <table:named-range>
 | ||||
| 			case 'label-range': break; // 9.4.9 <table:label-range>
 | ||||
| 			case 'label-ranges': break; // 9.4.10 <table:label-ranges>
 | ||||
| 			case 'named-expression': break; // 9.4.13 <table:named-expression>
 | ||||
| 			case 'sort': break; // 9.4.19 <table:sort>
 | ||||
| 			case 'sort-by': break; // 9.4.20 <table:sort-by>
 | ||||
| 			case 'sort-groups': break; // 9.4.22 <table:sort-groups>
 | ||||
| 
 | ||||
| 			case 'span': break; // <text:span>
 | ||||
| 			case 'tab': break; // 6.1.4 <text:tab>
 | ||||
| 			case 'line-break': break; // 6.1.5 <text:line-break>
 | ||||
| 			case 'p': case '文本串': | ||||
| 			case 'span': break; // 6.1.7 <text:span>
 | ||||
| 			case 'p': case '文本串': // 5.1.3 <text:p>
 | ||||
| 				if(Rn[1]==='/') textp = (textp.length > 0 ? textp + "\n" : "") + parse_text_p(str.slice(textpidx,Rn.index), textptag); | ||||
| 				else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; } | ||||
| 				break; // <text:p>
 | ||||
| @ -326,11 +331,14 @@ var parse_content_xml = (function() { | ||||
| 			case 'title': case '标题': break; // <*:title> OR <uof:标题>
 | ||||
| 			case 'desc': break; // <*:desc>
 | ||||
| 
 | ||||
| 			/* 9.2 Advanced Tables */ | ||||
| 			case 'table-source': break; // 9.2.6
 | ||||
| 			case 'scenario': break; // 9.2.6
 | ||||
| 
 | ||||
| 			case 'iteration': break; // 9.4.3 <table:iteration>
 | ||||
| 			case 'content-validations': break; // 9.4.4 <table:
 | ||||
| 			case 'content-validation': break; // 9.4.5 <table:
 | ||||
| 			case 'help-message': break; // 9.4.6 <table:
 | ||||
| 			case 'error-message': break; // 9.4.7 <table:
 | ||||
| 			case 'database-ranges': break; // 9.4.14 <table:database-ranges>
 | ||||
| 			case 'filter': break; // 9.5.2 <table:filter>
 | ||||
| @ -385,6 +393,12 @@ var parse_content_xml = (function() { | ||||
| 			case 'page-count': break; // TODO <text:page-count>
 | ||||
| 			case 'time': break; // TODO <text:time>
 | ||||
| 
 | ||||
| 			/* 9.3 Advanced Table Cells */ | ||||
| 			case 'cell-range-source': break; // 9.3.1 <table:
 | ||||
| 			case 'detective': break; // 9.3.2 <table:
 | ||||
| 			case 'operation': break; // 9.3.3 <table:
 | ||||
| 			case 'highlighted-range': break; // 9.3.4 <table:
 | ||||
| 
 | ||||
| 			/* 9.6 Data Pilot Tables <table: */ | ||||
| 			case 'data-pilot-table': // 9.6.3
 | ||||
| 			case 'source-cell-range': // 9.6.5
 | ||||
| @ -423,10 +437,12 @@ var parse_content_xml = (function() { | ||||
| 			/* non-standard */ | ||||
| 			case 'table-protection': break; | ||||
| 			case 'data-pilot-grand-total': break; // <table:
 | ||||
| 			case 'office-document-common-attrs': break; // bare
 | ||||
| 			default: | ||||
| 				if(Rn[2] === 'dc:') break; // TODO: properties
 | ||||
| 				if(Rn[2] === 'draw:') break; // TODO: drawing
 | ||||
| 				if(Rn[2] === 'style:') break; // TODO: styles
 | ||||
| 				if(Rn[2] === 'form:') break; // TODO: forms
 | ||||
| 				if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
 | ||||
| 				if(Rn[2] === 'loext:') break; // ignore undocumented extensions
 | ||||
| 				if(Rn[2] === 'uof:') break; // TODO: uof
 | ||||
|  | ||||
| @ -173,20 +173,20 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| function parse_xlsxcfb(cfb, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var f = 'Version'; | ||||
| 	var data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var version = parse_DataSpaceVersionInfo(data.content); | ||||
| 
 | ||||
| 	/* 2.3.4.1 */ | ||||
| 	f = 'DataSpaceMap'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var dsm = parse_DataSpaceMap(data.content); | ||||
| 	if(dsm.length != 1 || dsm[0].comps.length != 1 || dsm[0].comps[0].t != 0 || dsm[0].name != "StrongEncryptionDataSpace" || dsm[0].comps[0].v != "EncryptedPackage") | ||||
| 		throw new Error("ECMA-376 Encrypted file bad " + f); | ||||
| 
 | ||||
| 	f = 'StrongEncryptionDataSpace'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var seds = parse_DataSpaceDefinition(data.content); | ||||
| 	if(seds.length != 1 || seds[0] != "StrongEncryptionTransform") | ||||
| 		throw new Error("ECMA-376 Encrypted file bad " + f); | ||||
| @ -194,12 +194,12 @@ function parse_xlsxcfb(cfb, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	/* 2.3.4.3 */ | ||||
| 	f = '!Primary'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var hdr = parse_Primary(data.content); | ||||
| 
 | ||||
| 	f = 'EncryptionInfo'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var einfo = parse_EncryptionInfo(data.content); | ||||
| 
 | ||||
| 	throw new Error("File is password-protected"); | ||||
|  | ||||
| @ -5,7 +5,6 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		wb.SSF = SSF.get_table(); | ||||
| 	} | ||||
| 	if(wb && wb.SSF) { | ||||
| 		// $FlowIgnore
 | ||||
| 		make_ssf(SSF); SSF.load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; | ||||
|  | ||||
| @ -5,7 +5,7 @@ function firstbyte(f/*:RawData*/,o/*:?TypeOpts*/)/*:Array<number>*/ { | ||||
| 		case 'base64': x = Base64.decode(f.substr(0,24)); break; | ||||
| 		case 'binary': x = f; break; | ||||
| 		case 'array':  return [f[0], f[1], f[2], f[3]]; | ||||
| 		default: throw new Error("Unrecognized type " + (o ? o.type : "undefined")); | ||||
| 		default: throw new Error("Unrecognized type " + (o && o.type || "undefined")); | ||||
| 	} | ||||
| 	return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)]; | ||||
| } | ||||
| @ -29,13 +29,35 @@ function read_zip(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	return parse_zip(zip, o); | ||||
| } | ||||
| 
 | ||||
| function read_plaintext(data/*:string*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var i = 0; | ||||
| 	main: while(i < data.length) switch(data.charCodeAt(i)) { | ||||
| 		case 0x0A: case 0x0D: case 0x20: ++i; break; | ||||
| 		case 0x3C: return parse_xlml(data.slice(i),o); | ||||
| 		default: break main; | ||||
| 	} | ||||
| 	return PRN.to_workbook(data, o); | ||||
| } | ||||
| 
 | ||||
| function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var str = "", bytes = firstbyte(data, o); | ||||
| 	switch(o.type) { | ||||
| 		case 'base64': str = Base64.decode(data); break; | ||||
| 		case 'binary': str = data; break; | ||||
| 		case 'buffer': str = data.toString('binary'); break; | ||||
| 		case 'array': str = cc2str(data); break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| function read_utf16(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var d = data; | ||||
| 	if(o.type == 'base64') d = Base64.decode(d); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2)); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2), 'str'); | ||||
| 	o.type = "binary"; | ||||
| 	if(d.charCodeAt(0) == 0x3C) return parse_xlml(d,o); | ||||
| 	return PRN.to_workbook(d, o); | ||||
| 	return read_plaintext(d, o); | ||||
| } | ||||
| 
 | ||||
| function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| @ -56,6 +78,8 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xFF: if(n[1] == 0xFE){ return read_utf16(d, o); } break; | ||||
| 		case 0x00: if(n[1] == 0x00 && n[2] >= 0x02 && n[3] == 0x00) return WK_.to_workbook(d, o); break; | ||||
| 		case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o); | ||||
| 		case 0x7B: if(n[1] == 0x5C && n[2] == 0x72 && n[3] == 0x74) throw new Error("Unsupported RTF"); break; | ||||
| 		case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o); | ||||
| 	} | ||||
| 	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("|")); | ||||
|  | ||||
							
								
								
									
										18
									
								
								demos/systemjs/systemjs.html
									
									
									
									
									
										Normal file
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										18
									
								
								demos/systemjs/systemjs.html
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,18 @@ | ||||
| <script src="https://cdnjs.cloudflare.com/ajax/libs/systemjs/0.20.16/system.js"></script> | ||||
| <script> | ||||
| 	SystemJS.config({ | ||||
| 		meta: { | ||||
| 			'xlsx': { | ||||
| 				exports: 'XLSX' | ||||
| 			} | ||||
| 		}, | ||||
| 		map: { | ||||
| 			'xlsx': 'xlsx.full.min.js', | ||||
| 			'fs': '', | ||||
| 			'crypto': '', | ||||
| 			'stream': '' | ||||
| 		} | ||||
| 	}); | ||||
|   SystemJS.import('main.js'); | ||||
| </script> | ||||
| 
 | ||||
| @ -5,6 +5,7 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| | Option Name | Default | Description                                          | | ||||
| | :---------- | ------: | :--------------------------------------------------- | | ||||
| | type        |         | Input data encoding (see Input Type below)           | | ||||
| | raw         |         | If true, plaintext parsing will not parse values **  | | ||||
| | cellFormula | true    | Save formulae to the .f field                        | | ||||
| | cellHTML    | true    | Parse rich text and save HTML to the `.h` field      | | ||||
| | cellNF      | false   | Save number format string to the `.z` field          | | ||||
| @ -24,6 +25,8 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| 
 | ||||
| - Even if `cellNF` is false, formatted text will be generated and saved to `.w` | ||||
| - In some cases, sheets may be parsed even if `bookSheets` is false. | ||||
| - Excel aggressively tries to interpret values from CSV and other plaintext. | ||||
|   This leads to surprising behavior! The `raw` option suppresses value parsing. | ||||
| - `bookSheets` and `bookProps` combine to give both sets of information | ||||
| - `Deps` will be an empty object if `bookDeps` is falsy | ||||
| - `bookFiles` behavior depends on file type: | ||||
| @ -70,8 +73,13 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| | `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` | UTF16 Encoded | SpreadsheetML or Flat ODS or UOS1 or plaintext      | | ||||
| | `0xEF` | UTF8 Encoded  | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0xFF` | UTF16 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x00` | Record Stream | Lotus WK\* or Quattro Pro or plaintext              | | ||||
| | `0x0A` | Plaintext     | RTF or plaintext                                    | | ||||
| | `0x0A` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x0D` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x20` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| 
 | ||||
| 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) | ||||
| @ -80,13 +88,17 @@ Plaintext format guessing follows the priority order: | ||||
| 
 | ||||
| | Format | Test                                                                | | ||||
| |:-------|:--------------------------------------------------------------------| | ||||
| | HTML   | starts with `<html`                                                 | | ||||
| | XML    | `<?xml` appears in the first 1024 characters                        | | ||||
| | HTML   | starts with `<` and HTML tags appear in the first 1024 characters * | | ||||
| | XML    | starts with `<`                                                     | | ||||
| | RTF    | starts with `{\rt`                                                  | | ||||
| | DSV    | starts with `/sep=.$/`, separator is the specified character        | | ||||
| | TSV    | one of the first 1024 characters is a tab char `"\t"`               | | ||||
| | CSV    | one of the first 1024 characters is a comma char `","`              | | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| - HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div` | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| <details> | ||||
|  | ||||
| @ -1270,6 +1270,7 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| | Option Name | Default | Description                                          | | ||||
| | :---------- | ------: | :--------------------------------------------------- | | ||||
| | type        |         | Input data encoding (see Input Type below)           | | ||||
| | raw         |         | If true, plaintext parsing will not parse values **  | | ||||
| | cellFormula | true    | Save formulae to the .f field                        | | ||||
| | cellHTML    | true    | Parse rich text and save HTML to the `.h` field      | | ||||
| | cellNF      | false   | Save number format string to the `.z` field          | | ||||
| @ -1289,6 +1290,8 @@ The exported `read` and `readFile` functions accept an options argument: | ||||
| 
 | ||||
| - Even if `cellNF` is false, formatted text will be generated and saved to `.w` | ||||
| - In some cases, sheets may be parsed even if `bookSheets` is false. | ||||
| - Excel aggressively tries to interpret values from CSV and other plaintext. | ||||
|   This leads to surprising behavior! The `raw` option suppresses value parsing. | ||||
| - `bookSheets` and `bookProps` combine to give both sets of information | ||||
| - `Deps` will be an empty object if `bookDeps` is falsy | ||||
| - `bookFiles` behavior depends on file type: | ||||
| @ -1333,8 +1336,13 @@ file but Excel will know how to handle it.  This library applies similar logic: | ||||
| | `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` | UTF16 Encoded | SpreadsheetML or Flat ODS or UOS1 or plaintext      | | ||||
| | `0xEF` | UTF8 Encoded  | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0xFF` | UTF16 Encoded | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x00` | Record Stream | Lotus WK\* or Quattro Pro or plaintext              | | ||||
| | `0x0A` | Plaintext     | RTF or plaintext                                    | | ||||
| | `0x0A` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x0D` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| | `0x20` | Plaintext     | SpreadsheetML / Flat ODS / UOS1 / HTML / plaintext  | | ||||
| 
 | ||||
| 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) | ||||
| @ -1343,13 +1351,17 @@ Plaintext format guessing follows the priority order: | ||||
| 
 | ||||
| | Format | Test                                                                | | ||||
| |:-------|:--------------------------------------------------------------------| | ||||
| | HTML   | starts with `<html`                                                 | | ||||
| | XML    | `<?xml` appears in the first 1024 characters                        | | ||||
| | HTML   | starts with `<` and HTML tags appear in the first 1024 characters * | | ||||
| | XML    | starts with `<`                                                     | | ||||
| | RTF    | starts with `{\rt`                                                  | | ||||
| | DSV    | starts with `/sep=.$/`, separator is the specified character        | | ||||
| | TSV    | one of the first 1024 characters is a tab char `"\t"`               | | ||||
| | CSV    | one of the first 1024 characters is a comma char `","`              | | ||||
| | PRN    | (default)                                                           | | ||||
| 
 | ||||
| - HTML tags include: `html`, `table`, `head`, `meta`, `script`, `style`, `div` | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| Excel is extremely aggressive in reading files.  Adding an XLS extension to any | ||||
|  | ||||
							
								
								
									
										15
									
								
								package.json
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										15
									
								
								package.json
									
									
									
									
									
								
							| @ -17,20 +17,21 @@ | ||||
| 		"fs": false | ||||
| 	}, | ||||
| 	"dependencies": { | ||||
| 		"exit-on-epipe":"~1.0.0", | ||||
| 		"exit-on-epipe":"~1.0.1", | ||||
| 		"ssf":"~0.9.4", | ||||
| 		"codepage":"~1.9.0", | ||||
| 		"cfb":"~0.11.1", | ||||
| 		"crc-32":"~1.0.2", | ||||
| 		"adler-32":"~1.0.0", | ||||
| 		"commander":"~2.9.0" | ||||
| 		"commander":"~2.11.0" | ||||
| 	}, | ||||
| 	"devDependencies": { | ||||
| 		"mocha":"", | ||||
| 		"xlsjs":"", | ||||
| 		"@sheetjs/uglify-js":"", | ||||
| 		"@types/node":"", | ||||
| 		"@types/commander":"", | ||||
| 		"mocha":"~2.5.3", | ||||
| 		"blanket": "~1.2.3", | ||||
| 		"xlsjs":"*", | ||||
| 		"@sheetjs/uglify-js":"*", | ||||
| 		"@types/node":"^8.0.7", | ||||
| 		"@types/commander":"*", | ||||
| 		"dtslint": "^0.1.2", | ||||
| 		"typescript": "2.2.0" | ||||
| 	}, | ||||
|  | ||||
							
								
								
									
										4
									
								
								test.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										4
									
								
								test.js
									
									
									
									
									
								
							| @ -683,7 +683,7 @@ function custprop(wb) { | ||||
| 	assert.equal(wb.Custprops.Counter, -3.14); | ||||
| } | ||||
| 
 | ||||
| function cmparr(x){ for(var i=1;i!=x.length;++i) assert.deepEqual(x[0], x[i]); } | ||||
| function cmparr(x){ for(var i=1;i<x.length;++i) assert.deepEqual(x[0], x[i]); } | ||||
| 
 | ||||
| function deepcmp(x,y,k,m,c) { | ||||
| 	var s = k.indexOf("."); | ||||
| @ -1916,7 +1916,7 @@ mft.forEach(function(x) { | ||||
| 		var fil = {}, f = [], r = x.split(/\s+/); | ||||
| 		if(r.length < 3) return; | ||||
| 		it('should parse all', function() { | ||||
| 			for(var j = 1; j != r.length; ++j) f[j-1] = X.readFile(dir + r[0] + r[j], mfopts); | ||||
| 			for(var j = 1; j < r.length; ++j) f[j-1] = X.readFile(dir + r[0] + r[j], mfopts); | ||||
| 		}); | ||||
| 		it('should have the same sheetnames', function() { | ||||
| 			cmparr(f.map(function(x) { return x.SheetNames; })); | ||||
|  | ||||
| @ -678,7 +678,7 @@ function custprop(wb) { | ||||
| 	assert.equal(wb.Custprops.Counter, -3.14); | ||||
| } | ||||
| 
 | ||||
| function cmparr(x){ for(var i=1;i!=x.length;++i) assert.deepEqual(x[0], x[i]); } | ||||
| function cmparr(x){ for(var i=1;i<x.length;++i) assert.deepEqual(x[0], x[i]); } | ||||
| 
 | ||||
| function deepcmp(x,y,k,m,c) { | ||||
| 	var s = k.indexOf("."); | ||||
| @ -1928,7 +1928,7 @@ mft.forEach(function(x) { | ||||
| 		if(r.length < 3) return; | ||||
| 		if(!fs.existsSync(dir + r[0] + r[1])) return; | ||||
| 		it('should parse all', function() { | ||||
| 			for(var j = 1; j != r.length; ++j) f[j-1] = X.read(fs.readFileSync(dir + r[0] + r[j]), mfopts); | ||||
| 			for(var j = 1; j < r.length; ++j) f[j-1] = X.read(fs.readFileSync(dir + r[0] + r[j]), mfopts); | ||||
| 		}); | ||||
| 		it('should have the same sheetnames', function() { | ||||
| 			cmparr(f.map(function(x) { return x.SheetNames; })); | ||||
|  | ||||
| @ -166,11 +166,12 @@ var filenames = [ | ||||
| 	['sheetjs.xml.xls', {bookType:'xlml'}], | ||||
| 	['sheetjs.ods'], | ||||
| 	['sheetjs.fods'], | ||||
| 	['sheetjs.slk'], | ||||
| 	['sheetjs.csv'], | ||||
| 	['sheetjs.txt'], | ||||
| 	['sheetjs.prn'], | ||||
| 	['sheetjs.dif'] | ||||
| 	['sheetjs.slk'], | ||||
| 	['sheetjs.htm'], | ||||
| 	['sheetjs.dif'], | ||||
| 	['sheetjs.prn'] | ||||
| ]; | ||||
| 
 | ||||
| filenames.forEach(function(r) { | ||||
|  | ||||
							
								
								
									
										166
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										166
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -96,6 +96,7 @@ var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' & | ||||
| 
 | ||||
| function new_raw_buf(len/*:number*/) { | ||||
| 	/* jshint -W056 */ | ||||
| 	// $FlowIgnore
 | ||||
| 	return new (has_buf ? Buffer : Array)(len); | ||||
| 	/* jshint +W056 */ | ||||
| } | ||||
| @ -3426,6 +3427,7 @@ function parse_ext_props(data, p) { | ||||
| 					break; | ||||
| 
 | ||||
| 				case "Named Ranges": | ||||
| 				case "名前付き一覧": | ||||
| 				case "Benannte Bereiche": | ||||
| 				case "Navngivne områder": | ||||
| 					p.NamedRanges = len; | ||||
| @ -3512,6 +3514,7 @@ function parse_cust_props(data/*:string*/, opts) { | ||||
| 						p[name] = unescapexml(text); | ||||
| 						break; | ||||
| 					default: | ||||
| 						if(type.slice(-1) == '/') break; | ||||
| 						if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks); | ||||
| 				} | ||||
| 			} else if(x.substr(0,2) === "</") {/* empty */ | ||||
| @ -3990,7 +3993,13 @@ function parse_XLUnicodeString2(blob, length, opts) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.61 ControlInfo */ | ||||
| var parse_ControlInfo = parsenoop; | ||||
| function parse_ControlInfo(blob, length, opts) { | ||||
| 	var flags = blob.read_shift(1); | ||||
| 	blob.l++; | ||||
| 	var accel = blob.read_shift(2); | ||||
| 	blob.l += 2; | ||||
| 	return [flags, accel]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */ | ||||
| var parse_URLMoniker = function(blob/*::, length, opts*/) { | ||||
| @ -4053,7 +4062,7 @@ var parse_Hyperlink = function(blob, length) { | ||||
| 	if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l); | ||||
| 	if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l); | ||||
| 	if(flags & 0x0020) guid = blob.read_shift(16); | ||||
| 	if(flags & 0x0040) fileTime = parse_FILETIME(blob, 8); | ||||
| 	if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/); | ||||
| 	blob.l = end; | ||||
| 	var target = (targetFrameName||moniker||oleMoniker); | ||||
| 	if(location) target+="#"+location; | ||||
| @ -5683,8 +5692,9 @@ var DIF = (function() { | ||||
| })(); | ||||
| 
 | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/) { | ||||
| 		if(data === 'TRUE') arr[R][C] = true; | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(+data == +data) arr[R][C] = +data; | ||||
| @ -5693,6 +5703,7 @@ var PRN = (function() { | ||||
| 	} | ||||
| 
 | ||||
| 	function prn_to_aoa_str(f/*:string*/, opts)/*:AOA*/ { | ||||
| 		var o = opts || {}; | ||||
| 		var arr/*:AOA*/ = ([]/*:any*/); | ||||
| 		if(!f || f.length === 0) return arr; | ||||
| 		var lines = f.split(/[\r\n]/); | ||||
| @ -5709,9 +5720,9 @@ var PRN = (function() { | ||||
| 			arr[R] = []; | ||||
| 			/* TODO: confirm that widths are always 10 */ | ||||
| 			var C = 0; | ||||
| 			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C); | ||||
| 			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o); | ||||
| 			for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C) | ||||
| 				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C); | ||||
| 				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o); | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| @ -5828,6 +5839,7 @@ function read_wb_ID(d, opts) { | ||||
| 		return PRN.to_workbook(d, opts); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var WK_ = (function() { | ||||
| 	function lotushopper(data, cb/*:RecordHopperCB*/, opts/*:any*/) { | ||||
| 		if(!data) return; | ||||
| @ -6565,7 +6577,7 @@ function parse_EncryptionVerifier(blob, length/*:number*/) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */ | ||||
| function parse_EncryptionInfo(blob, length) { | ||||
| function parse_EncryptionInfo(blob, length/*:?number*/) { | ||||
| 	var vers = parse_CRYPTOVersion(blob); | ||||
| 	switch(vers.Minor) { | ||||
| 		case 0x02: return parse_EncInfoStd(blob, vers); | ||||
| @ -6597,8 +6609,8 @@ function parse_EncInfoAgl(blob, vers) { throw new Error("File is password-protec | ||||
| function parse_RC4CryptoHeader(blob, length/*:number*/) { | ||||
| 	var o = {}; | ||||
| 	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4; | ||||
| 	if(vers.Minor != 2) throw 'unrecognized minor version code: ' + vers.Minor; | ||||
| 	if(vers.Major > 4 || vers.Major < 2) throw 'unrecognized major version code: ' + vers.Major; | ||||
| 	if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor); | ||||
| 	if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major); | ||||
| 	o.Flags = blob.read_shift(4); length -= 4; | ||||
| 	var sz = blob.read_shift(4); length -= 4; | ||||
| 	o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz; | ||||
| @ -6735,7 +6747,7 @@ function parse_FilePassHeader(blob, length/*:number*/, oo) { | ||||
| 	return o; | ||||
| } | ||||
| function parse_FilePass(blob, length/*:number*/, opts) { | ||||
| 	var o = { Type: blob.read_shift(2) }; /* wEncryptionType */ | ||||
| 	var o = { Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }; /* wEncryptionType */ | ||||
| 	if(o.Type) parse_FilePassHeader(blob, length-2, o); | ||||
| 	else parse_XORObfuscation(blob, length-2, opts, o); | ||||
| 	return o; | ||||
| @ -6870,7 +6882,7 @@ function parse_borders(t, styles, themes, opts) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| 
 | ||||
| 			/* 18.8.4 border CT_Border */ | ||||
| 			case '<border': case '<border>': | ||||
| 			case '<border': case '<border>': case '<border/>': | ||||
| 				border = {}; | ||||
| 				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; } | ||||
| 				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; } | ||||
| @ -6942,6 +6954,7 @@ function parse_fills(t, styles, themes, opts) { | ||||
| 
 | ||||
| 			/* 18.8.24 gradientFill CT_GradientFill */ | ||||
| 			case '<gradientFill>': break; | ||||
| 			case '<gradientFill': | ||||
| 			case '</gradientFill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.32 patternFill CT_PatternFill */ | ||||
| @ -7121,7 +7134,7 @@ function parse_numFmts(t, styles, opts) { | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| function write_numFmts(NF/*:{[n:number]:string}*/, opts) { | ||||
| function write_numFmts(NF/*:{[n:number|string]:string}*/, opts) { | ||||
| 	var o = ["<numFmts>"]; | ||||
| 	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) { | ||||
| 		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])})); | ||||
| @ -11150,10 +11163,10 @@ function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook | ||||
| 	} | ||||
| 	if(rows) for(; R < rows.length; ++R) { | ||||
| 		if(rows && rows[R]) { | ||||
| 			var params = ({r:R+1}/*:any*/); | ||||
| 			var row = rows[R]; | ||||
| 			params = ({r:R+1}/*:any*/); | ||||
| 			row = rows[R]; | ||||
| 			if(row.hidden) params.hidden = 1; | ||||
| 			var height = -1; | ||||
| 			height = -1; | ||||
| 			if (row.hpx) height = px2pt(row.hpx); | ||||
| 			else if (row.hpt) height = row.hpt; | ||||
| 			if (height > -1) { params.ht = height; params.customHeight = 1; } | ||||
| @ -12412,13 +12425,13 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 			case '<workbookProtection/>': break; | ||||
| 
 | ||||
| 			/* 18.2.1  bookViews CT_BookViews ? */ | ||||
| 			case '<bookViews>': case '</bookViews>': break; | ||||
| 			case '<bookViews': case '<bookViews>': case '</bookViews>': break; | ||||
| 			/* 18.2.30   workbookView CT_BookView + */ | ||||
| 			case '<workbookView': delete y[0]; wb.WBView.push(y); break; | ||||
| 			case '</workbookView>': break; | ||||
| 
 | ||||
| 			/* 18.2.20 sheets CT_Sheets 1 */ | ||||
| 			case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			/* 18.2.19   sheet CT_Sheet + */ | ||||
| 			case '<sheet': | ||||
| 				switch(y.state) { | ||||
| @ -12497,7 +12510,7 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { | ||||
| 			case '<webPublishObject': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			/* 18.2.7    ext CT_Extension + */ | ||||
| 			case '<ext': pass=true; break; //TODO: check with versions of excel
 | ||||
| 			case '</ext>': pass=false; break; | ||||
| @ -13113,7 +13126,7 @@ function xlml_clean_comment(comment/*:any*/) { | ||||
| } | ||||
| 
 | ||||
| function xlml_normalize(d)/*:string*/ { | ||||
| 	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); | ||||
| 	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null && d instanceof Buffer &&*/ Buffer.isBuffer(d)) return d.toString('utf8'); | ||||
| 	if(typeof d === 'string') return d; | ||||
| 	throw new Error("Bad input format: expected Buffer or string"); | ||||
| } | ||||
| @ -13127,7 +13140,9 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { | ||||
| 	make_ssf(SSF); | ||||
| 	var str = debom(xlml_normalize(d)); | ||||
| 	if(opts && opts.type == 'binary' && typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str)); | ||||
| 	if(str.substr(0,1000).indexOf("<html") >= 0) return HTML_.to_workbook(str, opts); | ||||
| 	var opening = str.slice(0, 1024).toLowerCase(), ishtml = false; | ||||
| 	if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; }); | ||||
| 	if(ishtml) return HTML_.to_workbook(str, opts); | ||||
| 	var Rn; | ||||
| 	var state = [], tmp; | ||||
| 	if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| @ -14061,7 +14076,14 @@ function parse_compobj(obj) { | ||||
| 	throw new Error("Unsupported Unicode Extension"); | ||||
| } | ||||
| 
 | ||||
| /* 2.4.58 Continue logic */ | ||||
| /* | ||||
| 	Continue logic for: | ||||
| 	- 2.4.58 Continue | ||||
| 	- 2.4.59 ContinueBigName | ||||
| 	- 2.4.60 ContinueFrt | ||||
| 	- 2.4.61 ContinueFrt11 | ||||
| 	- 2.4.62 ContinueFrt12 | ||||
| */ | ||||
| function slurp(R, blob, length/*:number*/, opts) { | ||||
| 	var l = length; | ||||
| 	var bufs = []; | ||||
| @ -14075,9 +14097,13 @@ function slurp(R, blob, length/*:number*/, opts) { | ||||
| 	bufs.push(d); | ||||
| 	blob.l += l; | ||||
| 	var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]); | ||||
| 	while(next != null && next.n === 'Continue') { | ||||
| 	var start = 0; | ||||
| 	while(next != null && next.n.slice(0,8) === 'Continue') { | ||||
| 		l = __readUInt16LE(blob,blob.l+2); | ||||
| 		bufs.push(blob.slice(blob.l+4,blob.l+4+l)); | ||||
| 		start = blob.l + 4; | ||||
| 		if(next.n == 'ContinueFrt') start += 4; | ||||
| 		else if(next.n.slice(0,11) == 'ContinueFrt') start += 12; | ||||
| 		bufs.push(blob.slice(start,blob.l+4+l)); | ||||
| 		blob.l += 4+l; | ||||
| 		next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]); | ||||
| 	} | ||||
| @ -14314,6 +14340,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 						if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d') | ||||
| 							FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) }; | ||||
| 					break; | ||||
| 				case 'ExternCount': opts.ExternCount = val; break; | ||||
| 				case 'ExternSheet': | ||||
| 					if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; } | ||||
| 					supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break; | ||||
| @ -14593,6 +14620,9 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'SXVI': break; // TODO
 | ||||
| 				case 'SXVDEx': break; // TODO
 | ||||
| 				case 'SxIvd': break; // TODO
 | ||||
| 				case 'SXString': break; // TODO
 | ||||
| 				case 'Sync': break; | ||||
| 				case 'Addin': break; | ||||
| 				case 'SXDI': break; // TODO
 | ||||
| 				case 'SXLI': break; // TODO
 | ||||
| 				case 'SXEx': break; // TODO
 | ||||
| @ -14699,6 +14729,9 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'DbOrParamQry': break; | ||||
| 				case 'DBQueryExt': break; | ||||
| 
 | ||||
| 				case 'OleDbConn': break; | ||||
| 				case 'ExtString': break; | ||||
| 
 | ||||
| 				/* Formatting */ | ||||
| 				case 'IFmtRecord': break; | ||||
| 				case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break; | ||||
| @ -14790,7 +14823,6 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 
 | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				/* BIFF5 records */ | ||||
| 				case 'ExternCount': break; | ||||
| 				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break; | ||||
| 
 | ||||
| 				/* BIFF2-4 records */ | ||||
| @ -14802,6 +14834,10 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt': | ||||
| 				case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData': | ||||
| 				case 'Name': break; | ||||
| 				case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break; | ||||
| 				case 'ListObj': case 'ListField': break; | ||||
| 				case 'RRSort': break; | ||||
| 				case 'BigName': break; | ||||
| 				default: if(options.WTF) throw 'Unrecognized Record ' + R.n; | ||||
| 			}}}} | ||||
| 		} else blob.l += length; | ||||
| @ -14854,7 +14890,7 @@ var CompObjP, SummaryP, WorkbookP/*:Workbook*/; | ||||
| if(CompObj) CompObjP = parse_compobj(CompObj); | ||||
| if(options.bookProps && !options.bookSheets) WorkbookP = ({}/*:any*/); | ||||
| else { | ||||
| 	if(Workbook) WorkbookP = parse_workbook(Workbook.content, options, !!Workbook.find); | ||||
| 	if(Workbook) WorkbookP = parse_workbook(Workbook.content, options); | ||||
| 	/* Quattro Pro 7-8 */ | ||||
| 	else if(cfb.find('PerfectOffice_MAIN')) WorkbookP = WK_.to_workbook(cfb.find('PerfectOffice_MAIN').content, options); | ||||
| 	/* Quattro Pro 9 */ | ||||
| @ -16239,20 +16275,23 @@ var HTML_ = (function() { | ||||
| 		var opts = _opts || {}; | ||||
| 		if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 		var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); | ||||
| 		var i = str.indexOf("<table"), j = str.indexOf("</table"); | ||||
| 		if(i == -1 || j == -1) throw new Error("Invalid HTML: missing <table> / </table> pair"); | ||||
| 		var rows = str.slice(i, j).split(/(:?<tr[^>]*>)/); | ||||
| 		var mtch = str.match(/<table/i); | ||||
| 		if(!mtch) throw new Error("Invalid HTML: could not find <table>"); | ||||
| 		var mtch2 = str.match(/<\/table/i); | ||||
| 		var i = mtch.index, j = mtch2 && mtch2.index || str.length; | ||||
| 		var rows = str.slice(i, j).split(/(:?<tr[^>]*>)/i); | ||||
| 		var R = -1, C = 0, RS = 0, CS = 0; | ||||
| 		var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; | ||||
| 		var merges = [], midx = 0; | ||||
| 		for(i = 0; i < rows.length; ++i) { | ||||
| 			var row = rows[i].trim(); | ||||
| 			if(row.substr(0,3) == "<tr") { ++R; C = 0; continue; } | ||||
| 			if(row.substr(0,3) != "<td") continue; | ||||
| 			var cells = row.split("</td>"); | ||||
| 			var hd = row.substr(0,3).toLowerCase(); | ||||
| 			if(hd == "<tr") { ++R; C = 0; continue; } | ||||
| 			if(hd != "<td") continue; | ||||
| 			var cells = row.split(/<\/td>/i); | ||||
| 			for(j = 0; j < cells.length; ++j) { | ||||
| 				var cell = cells[j].trim(); | ||||
| 				if(cell.substr(0,3) != "<td") continue; | ||||
| 				if(cell.substr(0,3).toLowerCase() != "<td") continue; | ||||
| 				var m = cell, cc = 0; | ||||
| 				/* TODO: parse styles etc */ | ||||
| 				while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1); | ||||
| @ -16678,9 +16717,11 @@ var parse_content_xml = (function() { | ||||
| 
 | ||||
| 			case 'forms': break; // 12.25.2 13.2
 | ||||
| 			case 'table-column': break; // 9.1.6 <table:table-column>
 | ||||
| 			case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
 | ||||
| 			/* TODO: outline levels */ | ||||
| 			case 'table-row-group': break; // 9.1.9 <table:table-row-group>
 | ||||
| 			case 'table-column-group': break; // 9.1.10 <table:table-column-group>
 | ||||
| 			case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
 | ||||
| 
 | ||||
| 			case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
 | ||||
| 
 | ||||
| @ -16688,14 +16729,17 @@ var parse_content_xml = (function() { | ||||
| 			case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
 | ||||
| 			case 'named-expressions': break; // 9.4.11 <table:named-expressions>
 | ||||
| 			case 'named-range': break; // 9.4.12 <table:named-range>
 | ||||
| 			case 'label-range': break; // 9.4.9 <table:label-range>
 | ||||
| 			case 'label-ranges': break; // 9.4.10 <table:label-ranges>
 | ||||
| 			case 'named-expression': break; // 9.4.13 <table:named-expression>
 | ||||
| 			case 'sort': break; // 9.4.19 <table:sort>
 | ||||
| 			case 'sort-by': break; // 9.4.20 <table:sort-by>
 | ||||
| 			case 'sort-groups': break; // 9.4.22 <table:sort-groups>
 | ||||
| 
 | ||||
| 			case 'span': break; // <text:span>
 | ||||
| 			case 'tab': break; // 6.1.4 <text:tab>
 | ||||
| 			case 'line-break': break; // 6.1.5 <text:line-break>
 | ||||
| 			case 'p': case '文本串': | ||||
| 			case 'span': break; // 6.1.7 <text:span>
 | ||||
| 			case 'p': case '文本串': // 5.1.3 <text:p>
 | ||||
| 				if(Rn[1]==='/') textp = (textp.length > 0 ? textp + "\n" : "") + parse_text_p(str.slice(textpidx,Rn.index), textptag); | ||||
| 				else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; } | ||||
| 				break; // <text:p>
 | ||||
| @ -16715,11 +16759,14 @@ var parse_content_xml = (function() { | ||||
| 			case 'title': case '标题': break; // <*:title> OR <uof:标题>
 | ||||
| 			case 'desc': break; // <*:desc>
 | ||||
| 
 | ||||
| 			/* 9.2 Advanced Tables */ | ||||
| 			case 'table-source': break; // 9.2.6
 | ||||
| 			case 'scenario': break; // 9.2.6
 | ||||
| 
 | ||||
| 			case 'iteration': break; // 9.4.3 <table:iteration>
 | ||||
| 			case 'content-validations': break; // 9.4.4 <table:
 | ||||
| 			case 'content-validation': break; // 9.4.5 <table:
 | ||||
| 			case 'help-message': break; // 9.4.6 <table:
 | ||||
| 			case 'error-message': break; // 9.4.7 <table:
 | ||||
| 			case 'database-ranges': break; // 9.4.14 <table:database-ranges>
 | ||||
| 			case 'filter': break; // 9.5.2 <table:filter>
 | ||||
| @ -16774,6 +16821,12 @@ var parse_content_xml = (function() { | ||||
| 			case 'page-count': break; // TODO <text:page-count>
 | ||||
| 			case 'time': break; // TODO <text:time>
 | ||||
| 
 | ||||
| 			/* 9.3 Advanced Table Cells */ | ||||
| 			case 'cell-range-source': break; // 9.3.1 <table:
 | ||||
| 			case 'detective': break; // 9.3.2 <table:
 | ||||
| 			case 'operation': break; // 9.3.3 <table:
 | ||||
| 			case 'highlighted-range': break; // 9.3.4 <table:
 | ||||
| 
 | ||||
| 			/* 9.6 Data Pilot Tables <table: */ | ||||
| 			case 'data-pilot-table': // 9.6.3
 | ||||
| 			case 'source-cell-range': // 9.6.5
 | ||||
| @ -16812,10 +16865,12 @@ var parse_content_xml = (function() { | ||||
| 			/* non-standard */ | ||||
| 			case 'table-protection': break; | ||||
| 			case 'data-pilot-grand-total': break; // <table:
 | ||||
| 			case 'office-document-common-attrs': break; // bare
 | ||||
| 			default: | ||||
| 				if(Rn[2] === 'dc:') break; // TODO: properties
 | ||||
| 				if(Rn[2] === 'draw:') break; // TODO: drawing
 | ||||
| 				if(Rn[2] === 'style:') break; // TODO: styles
 | ||||
| 				if(Rn[2] === 'form:') break; // TODO: forms
 | ||||
| 				if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
 | ||||
| 				if(Rn[2] === 'loext:') break; // ignore undocumented extensions
 | ||||
| 				if(Rn[2] === 'uof:') break; // TODO: uof
 | ||||
| @ -17274,20 +17329,20 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| function parse_xlsxcfb(cfb, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	var f = 'Version'; | ||||
| 	var data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var version = parse_DataSpaceVersionInfo(data.content); | ||||
| 
 | ||||
| 	/* 2.3.4.1 */ | ||||
| 	f = 'DataSpaceMap'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var dsm = parse_DataSpaceMap(data.content); | ||||
| 	if(dsm.length != 1 || dsm[0].comps.length != 1 || dsm[0].comps[0].t != 0 || dsm[0].name != "StrongEncryptionDataSpace" || dsm[0].comps[0].v != "EncryptedPackage") | ||||
| 		throw new Error("ECMA-376 Encrypted file bad " + f); | ||||
| 
 | ||||
| 	f = 'StrongEncryptionDataSpace'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var seds = parse_DataSpaceDefinition(data.content); | ||||
| 	if(seds.length != 1 || seds[0] != "StrongEncryptionTransform") | ||||
| 		throw new Error("ECMA-376 Encrypted file bad " + f); | ||||
| @ -17295,12 +17350,12 @@ function parse_xlsxcfb(cfb, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	/* 2.3.4.3 */ | ||||
| 	f = '!Primary'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var hdr = parse_Primary(data.content); | ||||
| 
 | ||||
| 	f = 'EncryptionInfo'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var einfo = parse_EncryptionInfo(data.content); | ||||
| 
 | ||||
| 	throw new Error("File is password-protected"); | ||||
| @ -17313,7 +17368,6 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { | ||||
| 		wb.SSF = SSF.get_table(); | ||||
| 	} | ||||
| 	if(wb && wb.SSF) { | ||||
| 		// $FlowIgnore
 | ||||
| 		make_ssf(SSF); SSF.load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; | ||||
| @ -17446,7 +17500,7 @@ function firstbyte(f/*:RawData*/,o/*:?TypeOpts*/)/*:Array<number>*/ { | ||||
| 		case 'base64': x = Base64.decode(f.substr(0,24)); break; | ||||
| 		case 'binary': x = f; break; | ||||
| 		case 'array':  return [f[0], f[1], f[2], f[3]]; | ||||
| 		default: throw new Error("Unrecognized type " + (o ? o.type : "undefined")); | ||||
| 		default: throw new Error("Unrecognized type " + (o && o.type || "undefined")); | ||||
| 	} | ||||
| 	return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)]; | ||||
| } | ||||
| @ -17470,13 +17524,35 @@ function read_zip(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 	return parse_zip(zip, o); | ||||
| } | ||||
| 
 | ||||
| function read_plaintext(data/*:string*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var i = 0; | ||||
| 	main: while(i < data.length) switch(data.charCodeAt(i)) { | ||||
| 		case 0x0A: case 0x0D: case 0x20: ++i; break; | ||||
| 		case 0x3C: return parse_xlml(data.slice(i),o); | ||||
| 		default: break main; | ||||
| 	} | ||||
| 	return PRN.to_workbook(data, o); | ||||
| } | ||||
| 
 | ||||
| function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var str = "", bytes = firstbyte(data, o); | ||||
| 	switch(o.type) { | ||||
| 		case 'base64': str = Base64.decode(data); break; | ||||
| 		case 'binary': str = data; break; | ||||
| 		case 'buffer': str = data.toString('binary'); break; | ||||
| 		case 'array': str = cc2str(data); break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| function read_utf16(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ { | ||||
| 	var d = data; | ||||
| 	if(o.type == 'base64') d = Base64.decode(d); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2)); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2), 'str'); | ||||
| 	o.type = "binary"; | ||||
| 	if(d.charCodeAt(0) == 0x3C) return parse_xlml(d,o); | ||||
| 	return PRN.to_workbook(d, o); | ||||
| 	return read_plaintext(d, o); | ||||
| } | ||||
| 
 | ||||
| function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| @ -17497,6 +17573,8 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xFF: if(n[1] == 0xFE){ return read_utf16(d, o); } break; | ||||
| 		case 0x00: if(n[1] == 0x00 && n[2] >= 0x02 && n[3] == 0x00) return WK_.to_workbook(d, o); break; | ||||
| 		case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o); | ||||
| 		case 0x7B: if(n[1] == 0x5C && n[2] == 0x72 && n[3] == 0x74) throw new Error("Unsupported RTF"); break; | ||||
| 		case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o); | ||||
| 	} | ||||
| 	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("|")); | ||||
|  | ||||
							
								
								
									
										160
									
								
								xlsx.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										160
									
								
								xlsx.js
									
									
									
									
									
								
							| @ -95,6 +95,7 @@ var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' & | ||||
| 
 | ||||
| function new_raw_buf(len) { | ||||
| 	/* jshint -W056 */ | ||||
| 	// $FlowIgnore
 | ||||
| 	return new (has_buf ? Buffer : Array)(len); | ||||
| 	/* jshint +W056 */ | ||||
| } | ||||
| @ -3366,6 +3367,7 @@ function parse_ext_props(data, p) { | ||||
| 					break; | ||||
| 
 | ||||
| 				case "Named Ranges": | ||||
| 				case "名前付き一覧": | ||||
| 				case "Benannte Bereiche": | ||||
| 				case "Navngivne områder": | ||||
| 					p.NamedRanges = len; | ||||
| @ -3452,6 +3454,7 @@ function parse_cust_props(data, opts) { | ||||
| 						p[name] = unescapexml(text); | ||||
| 						break; | ||||
| 					default: | ||||
| 						if(type.slice(-1) == '/') break; | ||||
| 						if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks); | ||||
| 				} | ||||
| 			} else if(x.substr(0,2) === "</") {/* empty */ | ||||
| @ -3928,7 +3931,13 @@ function parse_XLUnicodeString2(blob, length, opts) { | ||||
| } | ||||
| 
 | ||||
| /* [MS-XLS] 2.5.61 ControlInfo */ | ||||
| var parse_ControlInfo = parsenoop; | ||||
| function parse_ControlInfo(blob, length, opts) { | ||||
| 	var flags = blob.read_shift(1); | ||||
| 	blob.l++; | ||||
| 	var accel = blob.read_shift(2); | ||||
| 	blob.l += 2; | ||||
| 	return [flags, accel]; | ||||
| } | ||||
| 
 | ||||
| /* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */ | ||||
| var parse_URLMoniker = function(blob) { | ||||
| @ -3991,7 +4000,7 @@ var parse_Hyperlink = function(blob, length) { | ||||
| 	if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l); | ||||
| 	if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l); | ||||
| 	if(flags & 0x0020) guid = blob.read_shift(16); | ||||
| 	if(flags & 0x0040) fileTime = parse_FILETIME(blob, 8); | ||||
| 	if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/); | ||||
| 	blob.l = end; | ||||
| 	var target = (targetFrameName||moniker||oleMoniker); | ||||
| 	if(location) target+="#"+location; | ||||
| @ -5621,8 +5630,9 @@ var DIF = (function() { | ||||
| })(); | ||||
| 
 | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data, arr, R, C) { | ||||
| 		if(data === 'TRUE') arr[R][C] = true; | ||||
| 	function set_text_arr(data, arr, R, C, o) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(+data == +data) arr[R][C] = +data; | ||||
| @ -5631,6 +5641,7 @@ var PRN = (function() { | ||||
| 	} | ||||
| 
 | ||||
| 	function prn_to_aoa_str(f, opts) { | ||||
| 		var o = opts || {}; | ||||
| 		var arr = ([]); | ||||
| 		if(!f || f.length === 0) return arr; | ||||
| 		var lines = f.split(/[\r\n]/); | ||||
| @ -5647,9 +5658,9 @@ var PRN = (function() { | ||||
| 			arr[R] = []; | ||||
| 			/* TODO: confirm that widths are always 10 */ | ||||
| 			var C = 0; | ||||
| 			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C); | ||||
| 			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o); | ||||
| 			for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C) | ||||
| 				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C); | ||||
| 				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o); | ||||
| 		} | ||||
| 		return arr; | ||||
| 	} | ||||
| @ -5766,6 +5777,7 @@ function read_wb_ID(d, opts) { | ||||
| 		return PRN.to_workbook(d, opts); | ||||
| 	} | ||||
| } | ||||
| 
 | ||||
| var WK_ = (function() { | ||||
| 	function lotushopper(data, cb, opts) { | ||||
| 		if(!data) return; | ||||
| @ -6534,8 +6546,8 @@ function parse_EncInfoAgl(blob, vers) { throw new Error("File is password-protec | ||||
| function parse_RC4CryptoHeader(blob, length) { | ||||
| 	var o = {}; | ||||
| 	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4; | ||||
| 	if(vers.Minor != 2) throw 'unrecognized minor version code: ' + vers.Minor; | ||||
| 	if(vers.Major > 4 || vers.Major < 2) throw 'unrecognized major version code: ' + vers.Major; | ||||
| 	if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor); | ||||
| 	if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major); | ||||
| 	o.Flags = blob.read_shift(4); length -= 4; | ||||
| 	var sz = blob.read_shift(4); length -= 4; | ||||
| 	o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz; | ||||
| @ -6672,7 +6684,7 @@ function parse_FilePassHeader(blob, length, oo) { | ||||
| 	return o; | ||||
| } | ||||
| function parse_FilePass(blob, length, opts) { | ||||
| 	var o = { Type: blob.read_shift(2) }; /* wEncryptionType */ | ||||
| 	var o = { Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }; /* wEncryptionType */ | ||||
| 	if(o.Type) parse_FilePassHeader(blob, length-2, o); | ||||
| 	else parse_XORObfuscation(blob, length-2, opts, o); | ||||
| 	return o; | ||||
| @ -6807,7 +6819,7 @@ function parse_borders(t, styles, themes, opts) { | ||||
| 			case '<borders': case '<borders>': case '</borders>': break; | ||||
| 
 | ||||
| 			/* 18.8.4 border CT_Border */ | ||||
| 			case '<border': case '<border>': | ||||
| 			case '<border': case '<border>': case '<border/>': | ||||
| 				border = {}; | ||||
| 				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; } | ||||
| 				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; } | ||||
| @ -6879,6 +6891,7 @@ function parse_fills(t, styles, themes, opts) { | ||||
| 
 | ||||
| 			/* 18.8.24 gradientFill CT_GradientFill */ | ||||
| 			case '<gradientFill>': break; | ||||
| 			case '<gradientFill': | ||||
| 			case '</gradientFill>': styles.Fills.push(fill); fill = {}; break; | ||||
| 
 | ||||
| 			/* 18.8.32 patternFill CT_PatternFill */ | ||||
| @ -11084,10 +11097,10 @@ function write_ws_xml_data(ws, opts, idx, wb, rels) { | ||||
| 	} | ||||
| 	if(rows) for(; R < rows.length; ++R) { | ||||
| 		if(rows && rows[R]) { | ||||
| 			var params = ({r:R+1}); | ||||
| 			var row = rows[R]; | ||||
| 			params = ({r:R+1}); | ||||
| 			row = rows[R]; | ||||
| 			if(row.hidden) params.hidden = 1; | ||||
| 			var height = -1; | ||||
| 			height = -1; | ||||
| 			if (row.hpx) height = px2pt(row.hpx); | ||||
| 			else if (row.hpt) height = row.hpt; | ||||
| 			if (height > -1) { params.ht = height; params.customHeight = 1; } | ||||
| @ -12345,13 +12358,13 @@ function parse_wb_xml(data, opts) { | ||||
| 			case '<workbookProtection/>': break; | ||||
| 
 | ||||
| 			/* 18.2.1  bookViews CT_BookViews ? */ | ||||
| 			case '<bookViews>': case '</bookViews>': break; | ||||
| 			case '<bookViews': case '<bookViews>': case '</bookViews>': break; | ||||
| 			/* 18.2.30   workbookView CT_BookView + */ | ||||
| 			case '<workbookView': delete y[0]; wb.WBView.push(y); break; | ||||
| 			case '</workbookView>': break; | ||||
| 
 | ||||
| 			/* 18.2.20 sheets CT_Sheets 1 */ | ||||
| 			case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
 | ||||
| 			/* 18.2.19   sheet CT_Sheet + */ | ||||
| 			case '<sheet': | ||||
| 				switch(y.state) { | ||||
| @ -12430,7 +12443,7 @@ function parse_wb_xml(data, opts) { | ||||
| 			case '<webPublishObject': break; | ||||
| 
 | ||||
| 			/* 18.2.10 extLst CT_ExtensionList ? */ | ||||
| 			case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break; | ||||
| 			/* 18.2.7    ext CT_Extension + */ | ||||
| 			case '<ext': pass=true; break; //TODO: check with versions of excel
 | ||||
| 			case '</ext>': pass=false; break; | ||||
| @ -13057,7 +13070,9 @@ function parse_xlml_xml(d, _opts) { | ||||
| 	make_ssf(SSF); | ||||
| 	var str = debom(xlml_normalize(d)); | ||||
| 	if(opts && opts.type == 'binary' && typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str)); | ||||
| 	if(str.substr(0,1000).indexOf("<html") >= 0) return HTML_.to_workbook(str, opts); | ||||
| 	var opening = str.slice(0, 1024).toLowerCase(), ishtml = false; | ||||
| 	if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; }); | ||||
| 	if(ishtml) return HTML_.to_workbook(str, opts); | ||||
| 	var Rn; | ||||
| 	var state = [], tmp; | ||||
| 	if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| @ -13988,7 +14003,14 @@ function parse_compobj(obj) { | ||||
| 	throw new Error("Unsupported Unicode Extension"); | ||||
| } | ||||
| 
 | ||||
| /* 2.4.58 Continue logic */ | ||||
| /* | ||||
| 	Continue logic for: | ||||
| 	- 2.4.58 Continue | ||||
| 	- 2.4.59 ContinueBigName | ||||
| 	- 2.4.60 ContinueFrt | ||||
| 	- 2.4.61 ContinueFrt11 | ||||
| 	- 2.4.62 ContinueFrt12 | ||||
| */ | ||||
| function slurp(R, blob, length, opts) { | ||||
| 	var l = length; | ||||
| 	var bufs = []; | ||||
| @ -14002,9 +14024,13 @@ function slurp(R, blob, length, opts) { | ||||
| 	bufs.push(d); | ||||
| 	blob.l += l; | ||||
| 	var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]); | ||||
| 	while(next != null && next.n === 'Continue') { | ||||
| 	var start = 0; | ||||
| 	while(next != null && next.n.slice(0,8) === 'Continue') { | ||||
| 		l = __readUInt16LE(blob,blob.l+2); | ||||
| 		bufs.push(blob.slice(blob.l+4,blob.l+4+l)); | ||||
| 		start = blob.l + 4; | ||||
| 		if(next.n == 'ContinueFrt') start += 4; | ||||
| 		else if(next.n.slice(0,11) == 'ContinueFrt') start += 12; | ||||
| 		bufs.push(blob.slice(start,blob.l+4+l)); | ||||
| 		blob.l += 4+l; | ||||
| 		next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]); | ||||
| 	} | ||||
| @ -14240,6 +14266,7 @@ wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 						if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d') | ||||
| 							FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) }; | ||||
| 					break; | ||||
| 				case 'ExternCount': opts.ExternCount = val; break; | ||||
| 				case 'ExternSheet': | ||||
| 					if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; } | ||||
| 					supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break; | ||||
| @ -14519,6 +14546,9 @@ wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 				case 'SXVI': break; // TODO
 | ||||
| 				case 'SXVDEx': break; // TODO
 | ||||
| 				case 'SxIvd': break; // TODO
 | ||||
| 				case 'SXString': break; // TODO
 | ||||
| 				case 'Sync': break; | ||||
| 				case 'Addin': break; | ||||
| 				case 'SXDI': break; // TODO
 | ||||
| 				case 'SXLI': break; // TODO
 | ||||
| 				case 'SXEx': break; // TODO
 | ||||
| @ -14625,6 +14655,9 @@ wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 				case 'DbOrParamQry': break; | ||||
| 				case 'DBQueryExt': break; | ||||
| 
 | ||||
| 				case 'OleDbConn': break; | ||||
| 				case 'ExtString': break; | ||||
| 
 | ||||
| 				/* Formatting */ | ||||
| 				case 'IFmtRecord': break; | ||||
| 				case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break; | ||||
| @ -14716,7 +14749,6 @@ wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 
 | ||||
| 				default: switch(R.n) { /* nested */ | ||||
| 				/* BIFF5 records */ | ||||
| 				case 'ExternCount': break; | ||||
| 				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break; | ||||
| 
 | ||||
| 				/* BIFF2-4 records */ | ||||
| @ -14728,6 +14760,10 @@ wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break; | ||||
| 				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt': | ||||
| 				case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData': | ||||
| 				case 'Name': break; | ||||
| 				case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break; | ||||
| 				case 'ListObj': case 'ListField': break; | ||||
| 				case 'RRSort': break; | ||||
| 				case 'BigName': break; | ||||
| 				default: if(options.WTF) throw 'Unrecognized Record ' + R.n; | ||||
| 			}}}} | ||||
| 		} else blob.l += length; | ||||
| @ -14780,7 +14816,7 @@ var CompObjP, SummaryP, WorkbookP; | ||||
| if(CompObj) CompObjP = parse_compobj(CompObj); | ||||
| if(options.bookProps && !options.bookSheets) WorkbookP = ({}); | ||||
| else { | ||||
| 	if(Workbook) WorkbookP = parse_workbook(Workbook.content, options, !!Workbook.find); | ||||
| 	if(Workbook) WorkbookP = parse_workbook(Workbook.content, options); | ||||
| 	/* Quattro Pro 7-8 */ | ||||
| 	else if(cfb.find('PerfectOffice_MAIN')) WorkbookP = WK_.to_workbook(cfb.find('PerfectOffice_MAIN').content, options); | ||||
| 	/* Quattro Pro 9 */ | ||||
| @ -16165,20 +16201,23 @@ var HTML_ = (function() { | ||||
| 		var opts = _opts || {}; | ||||
| 		if(DENSE != null && opts.dense == null) opts.dense = DENSE; | ||||
| 		var ws = opts.dense ? ([]) : ({}); | ||||
| 		var i = str.indexOf("<table"), j = str.indexOf("</table"); | ||||
| 		if(i == -1 || j == -1) throw new Error("Invalid HTML: missing <table> / </table> pair"); | ||||
| 		var rows = str.slice(i, j).split(/(:?<tr[^>]*>)/); | ||||
| 		var mtch = str.match(/<table/i); | ||||
| 		if(!mtch) throw new Error("Invalid HTML: could not find <table>"); | ||||
| 		var mtch2 = str.match(/<\/table/i); | ||||
| 		var i = mtch.index, j = mtch2 && mtch2.index || str.length; | ||||
| 		var rows = str.slice(i, j).split(/(:?<tr[^>]*>)/i); | ||||
| 		var R = -1, C = 0, RS = 0, CS = 0; | ||||
| 		var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; | ||||
| 		var merges = [], midx = 0; | ||||
| 		for(i = 0; i < rows.length; ++i) { | ||||
| 			var row = rows[i].trim(); | ||||
| 			if(row.substr(0,3) == "<tr") { ++R; C = 0; continue; } | ||||
| 			if(row.substr(0,3) != "<td") continue; | ||||
| 			var cells = row.split("</td>"); | ||||
| 			var hd = row.substr(0,3).toLowerCase(); | ||||
| 			if(hd == "<tr") { ++R; C = 0; continue; } | ||||
| 			if(hd != "<td") continue; | ||||
| 			var cells = row.split(/<\/td>/i); | ||||
| 			for(j = 0; j < cells.length; ++j) { | ||||
| 				var cell = cells[j].trim(); | ||||
| 				if(cell.substr(0,3) != "<td") continue; | ||||
| 				if(cell.substr(0,3).toLowerCase() != "<td") continue; | ||||
| 				var m = cell, cc = 0; | ||||
| 				/* TODO: parse styles etc */ | ||||
| 				while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1); | ||||
| @ -16604,9 +16643,11 @@ var parse_content_xml = (function() { | ||||
| 
 | ||||
| 			case 'forms': break; // 12.25.2 13.2
 | ||||
| 			case 'table-column': break; // 9.1.6 <table:table-column>
 | ||||
| 			case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
 | ||||
| 			/* TODO: outline levels */ | ||||
| 			case 'table-row-group': break; // 9.1.9 <table:table-row-group>
 | ||||
| 			case 'table-column-group': break; // 9.1.10 <table:table-column-group>
 | ||||
| 			case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
 | ||||
| 
 | ||||
| 			case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
 | ||||
| 
 | ||||
| @ -16614,14 +16655,17 @@ var parse_content_xml = (function() { | ||||
| 			case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
 | ||||
| 			case 'named-expressions': break; // 9.4.11 <table:named-expressions>
 | ||||
| 			case 'named-range': break; // 9.4.12 <table:named-range>
 | ||||
| 			case 'label-range': break; // 9.4.9 <table:label-range>
 | ||||
| 			case 'label-ranges': break; // 9.4.10 <table:label-ranges>
 | ||||
| 			case 'named-expression': break; // 9.4.13 <table:named-expression>
 | ||||
| 			case 'sort': break; // 9.4.19 <table:sort>
 | ||||
| 			case 'sort-by': break; // 9.4.20 <table:sort-by>
 | ||||
| 			case 'sort-groups': break; // 9.4.22 <table:sort-groups>
 | ||||
| 
 | ||||
| 			case 'span': break; // <text:span>
 | ||||
| 			case 'tab': break; // 6.1.4 <text:tab>
 | ||||
| 			case 'line-break': break; // 6.1.5 <text:line-break>
 | ||||
| 			case 'p': case '文本串': | ||||
| 			case 'span': break; // 6.1.7 <text:span>
 | ||||
| 			case 'p': case '文本串': // 5.1.3 <text:p>
 | ||||
| 				if(Rn[1]==='/') textp = (textp.length > 0 ? textp + "\n" : "") + parse_text_p(str.slice(textpidx,Rn.index), textptag); | ||||
| 				else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; } | ||||
| 				break; // <text:p>
 | ||||
| @ -16641,11 +16685,14 @@ var parse_content_xml = (function() { | ||||
| 			case 'title': case '标题': break; // <*:title> OR <uof:标题>
 | ||||
| 			case 'desc': break; // <*:desc>
 | ||||
| 
 | ||||
| 			/* 9.2 Advanced Tables */ | ||||
| 			case 'table-source': break; // 9.2.6
 | ||||
| 			case 'scenario': break; // 9.2.6
 | ||||
| 
 | ||||
| 			case 'iteration': break; // 9.4.3 <table:iteration>
 | ||||
| 			case 'content-validations': break; // 9.4.4 <table:
 | ||||
| 			case 'content-validation': break; // 9.4.5 <table:
 | ||||
| 			case 'help-message': break; // 9.4.6 <table:
 | ||||
| 			case 'error-message': break; // 9.4.7 <table:
 | ||||
| 			case 'database-ranges': break; // 9.4.14 <table:database-ranges>
 | ||||
| 			case 'filter': break; // 9.5.2 <table:filter>
 | ||||
| @ -16700,6 +16747,12 @@ var parse_content_xml = (function() { | ||||
| 			case 'page-count': break; // TODO <text:page-count>
 | ||||
| 			case 'time': break; // TODO <text:time>
 | ||||
| 
 | ||||
| 			/* 9.3 Advanced Table Cells */ | ||||
| 			case 'cell-range-source': break; // 9.3.1 <table:
 | ||||
| 			case 'detective': break; // 9.3.2 <table:
 | ||||
| 			case 'operation': break; // 9.3.3 <table:
 | ||||
| 			case 'highlighted-range': break; // 9.3.4 <table:
 | ||||
| 
 | ||||
| 			/* 9.6 Data Pilot Tables <table: */ | ||||
| 			case 'data-pilot-table': // 9.6.3
 | ||||
| 			case 'source-cell-range': // 9.6.5
 | ||||
| @ -16738,10 +16791,12 @@ var parse_content_xml = (function() { | ||||
| 			/* non-standard */ | ||||
| 			case 'table-protection': break; | ||||
| 			case 'data-pilot-grand-total': break; // <table:
 | ||||
| 			case 'office-document-common-attrs': break; // bare
 | ||||
| 			default: | ||||
| 				if(Rn[2] === 'dc:') break; // TODO: properties
 | ||||
| 				if(Rn[2] === 'draw:') break; // TODO: drawing
 | ||||
| 				if(Rn[2] === 'style:') break; // TODO: styles
 | ||||
| 				if(Rn[2] === 'form:') break; // TODO: forms
 | ||||
| 				if(Rn[2] === 'calcext:') break; // ignore undocumented extensions
 | ||||
| 				if(Rn[2] === 'loext:') break; // ignore undocumented extensions
 | ||||
| 				if(Rn[2] === 'uof:') break; // TODO: uof
 | ||||
| @ -17199,20 +17254,20 @@ function parse_zip(zip, opts) { | ||||
| function parse_xlsxcfb(cfb, opts) { | ||||
| 	var f = 'Version'; | ||||
| 	var data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var version = parse_DataSpaceVersionInfo(data.content); | ||||
| 
 | ||||
| 	/* 2.3.4.1 */ | ||||
| 	f = 'DataSpaceMap'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var dsm = parse_DataSpaceMap(data.content); | ||||
| 	if(dsm.length != 1 || dsm[0].comps.length != 1 || dsm[0].comps[0].t != 0 || dsm[0].name != "StrongEncryptionDataSpace" || dsm[0].comps[0].v != "EncryptedPackage") | ||||
| 		throw new Error("ECMA-376 Encrypted file bad " + f); | ||||
| 
 | ||||
| 	f = 'StrongEncryptionDataSpace'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var seds = parse_DataSpaceDefinition(data.content); | ||||
| 	if(seds.length != 1 || seds[0] != "StrongEncryptionTransform") | ||||
| 		throw new Error("ECMA-376 Encrypted file bad " + f); | ||||
| @ -17220,12 +17275,12 @@ function parse_xlsxcfb(cfb, opts) { | ||||
| 	/* 2.3.4.3 */ | ||||
| 	f = '!Primary'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var hdr = parse_Primary(data.content); | ||||
| 
 | ||||
| 	f = 'EncryptionInfo'; | ||||
| 	data = cfb.find(f); | ||||
| 	if(!data) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f); | ||||
| 	var einfo = parse_EncryptionInfo(data.content); | ||||
| 
 | ||||
| 	throw new Error("File is password-protected"); | ||||
| @ -17238,7 +17293,6 @@ function write_zip(wb, opts) { | ||||
| 		wb.SSF = SSF.get_table(); | ||||
| 	} | ||||
| 	if(wb && wb.SSF) { | ||||
| 		// $FlowIgnore
 | ||||
| 		make_ssf(SSF); SSF.load_table(wb.SSF); | ||||
| 		// $FlowIgnore
 | ||||
| 		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; | ||||
| @ -17369,7 +17423,7 @@ function firstbyte(f,o) { | ||||
| 		case 'base64': x = Base64.decode(f.substr(0,24)); break; | ||||
| 		case 'binary': x = f; break; | ||||
| 		case 'array':  return [f[0], f[1], f[2], f[3]]; | ||||
| 		default: throw new Error("Unrecognized type " + (o ? o.type : "undefined")); | ||||
| 		default: throw new Error("Unrecognized type " + (o && o.type || "undefined")); | ||||
| 	} | ||||
| 	return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)]; | ||||
| } | ||||
| @ -17392,13 +17446,35 @@ var zip, d = data; | ||||
| 	return parse_zip(zip, o); | ||||
| } | ||||
| 
 | ||||
| function read_plaintext(data, o) { | ||||
| 	var i = 0; | ||||
| 	main: while(i < data.length) switch(data.charCodeAt(i)) { | ||||
| 		case 0x0A: case 0x0D: case 0x20: ++i; break; | ||||
| 		case 0x3C: return parse_xlml(data.slice(i),o); | ||||
| 		default: break main; | ||||
| 	} | ||||
| 	return PRN.to_workbook(data, o); | ||||
| } | ||||
| 
 | ||||
| function read_plaintext_raw(data, o) { | ||||
| 	var str = "", bytes = firstbyte(data, o); | ||||
| 	switch(o.type) { | ||||
| 		case 'base64': str = Base64.decode(data); break; | ||||
| 		case 'binary': str = data; break; | ||||
| 		case 'buffer': str = data.toString('binary'); break; | ||||
| 		case 'array': str = cc2str(data); break; | ||||
| 		default: throw new Error("Unrecognized type " + o.type); | ||||
| 	} | ||||
| 	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str); | ||||
| 	return read_plaintext(str, o); | ||||
| } | ||||
| 
 | ||||
| function read_utf16(data, o) { | ||||
| 	var d = data; | ||||
| 	if(o.type == 'base64') d = Base64.decode(d); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2)); | ||||
| 	d = cptable.utils.decode(1200, d.slice(2), 'str'); | ||||
| 	o.type = "binary"; | ||||
| 	if(d.charCodeAt(0) == 0x3C) return parse_xlml(d,o); | ||||
| 	return PRN.to_workbook(d, o); | ||||
| 	return read_plaintext(d, o); | ||||
| } | ||||
| 
 | ||||
| function readSync(data, opts) { | ||||
| @ -17419,6 +17495,8 @@ function readSync(data, opts) { | ||||
| 		case 0xFF: if(n[1] == 0xFE){ return read_utf16(d, o); } break; | ||||
| 		case 0x00: if(n[1] == 0x00 && n[2] >= 0x02 && n[3] == 0x00) return WK_.to_workbook(d, o); break; | ||||
| 		case 0x03: case 0x83: case 0x8B: return DBF.to_workbook(d, o); | ||||
| 		case 0x7B: if(n[1] == 0x5C && n[2] == 0x72 && n[3] == 0x74) throw new Error("Unsupported RTF"); break; | ||||
| 		case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o); | ||||
| 	} | ||||
| 	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("|")); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user