forked from sheetjs/sheetjs
		
	SYLK shared formulae
This commit is contained in:
		
							parent
							
								
									c56347eff5
								
							
						
					
					
						commit
						81b7614e45
					
				
							
								
								
									
										3
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										3
									
								
								.gitattributes
									
									
									
									
										vendored
									
									
								
							| @ -1,3 +1,6 @@ | ||||
| *.*s        linguist-documentation | ||||
| *.html      linguist-documentation | ||||
| 
 | ||||
| *.md        text eol=lf | ||||
| bits/*.js   text eol=lf | ||||
| test.js     text eol=lf | ||||
|  | ||||
							
								
								
									
										26
									
								
								README.md
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										26
									
								
								README.md
									
									
									
									
									
								
							| @ -1,4 +1,4 @@ | ||||
| # [SheetJS js-xlsx](http://sheetjs.com) | ||||
| # [SheetJS](http://sheetjs.com) | ||||
| 
 | ||||
| Parser and writer for various spreadsheet formats.  Pure-JS cleanroom | ||||
| implementation from official specifications, related documents, and test files. | ||||
| @ -36,7 +36,6 @@ enhancements, additional features like styling, and dedicated support. | ||||
| 
 | ||||
| [](https://saucelabs.com/u/sheetjs) | ||||
| 
 | ||||
| [](https://travis-ci.org/SheetJS/sheetjs) | ||||
| [](https://semaphoreci.com/sheetjs/sheetjs) | ||||
| [](https://coveralls.io/r/SheetJS/sheetjs?branch=master) | ||||
| [](https://david-dm.org/sheetjs/sheetjs) | ||||
| @ -258,7 +257,7 @@ be configured to remove support with `resolve.alias`: | ||||
| ### ECMAScript 5 Compatibility | ||||
| 
 | ||||
| Since the library uses functions like `Array#forEach`, older browsers require | ||||
| [shims to provide missing functions](http://oss.sheetjs.com/js-xlsx/shim.js). | ||||
| [shims to provide missing functions](http://oss.sheetjs.com/sheetjs/shim.js). | ||||
| 
 | ||||
| To use the shim, add the shim before the script tag that loads `xlsx.js`: | ||||
| 
 | ||||
| @ -283,7 +282,7 @@ Third-party libraries either supported one format, or they involved a separate | ||||
| set of classes for each supported file type.  Even though XLSB was introduced in | ||||
| Excel 2007, nothing outside of SheetJS or Excel supported the format. | ||||
| 
 | ||||
| To promote a format-agnostic view, js-xlsx starts from a pure-JS representation | ||||
| To promote a format-agnostic view, SheetJS starts from a pure-JS representation | ||||
| that we call the ["Common Spreadsheet Format"](#common-spreadsheet-format). | ||||
| Emphasizing a uniform object representation enables new features like format | ||||
| conversion (reading an XLSX template and saving as XLS) and circumvents the mess | ||||
| @ -389,7 +388,7 @@ var workbook = XLSX.read(htmlstr, {type:'string'}); | ||||
|   <summary><b>Browser download file (ajax)</b> (click to show)</summary> | ||||
| 
 | ||||
| Note: for a more complete example that works in older browsers, check the demo | ||||
| at <http://oss.sheetjs.com/js-xlsx/ajax.html>.  The [`xhr` demo](demos/xhr/) | ||||
| at <http://oss.sheetjs.com/sheetjs/ajax.html>.  The [`xhr` demo](demos/xhr/) | ||||
| includes more examples with `XMLHttpRequest` and `fetch`. | ||||
| 
 | ||||
| ```js | ||||
| @ -465,7 +464,7 @@ More specialized cases, including mobile app file processing, are covered in the | ||||
| 
 | ||||
| ### Parsing Examples | ||||
| 
 | ||||
| - <http://oss.sheetjs.com/js-xlsx/> HTML5 File API / Base64 Text / Web Workers | ||||
| - <http://oss.sheetjs.com/sheetjs/> HTML5 File API / Base64 Text / Web Workers | ||||
| 
 | ||||
| Note that older versions of IE do not support HTML5 File API, so the Base64 mode | ||||
| is used for testing. | ||||
| @ -489,7 +488,7 @@ On Windows XP and up you can get the Base64 encoding using `certutil`: | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| - <http://oss.sheetjs.com/js-xlsx/ajax.html> XMLHttpRequest | ||||
| - <http://oss.sheetjs.com/sheetjs/ajax.html> XMLHttpRequest | ||||
| 
 | ||||
| ### Streaming Read | ||||
| 
 | ||||
| @ -627,7 +626,7 @@ error if the workbook is empty. | ||||
| 
 | ||||
| - <http://sheetjs.com/demos/modify.html> read + modify + write files | ||||
| 
 | ||||
| - <https://github.com/SheetJS/js-xlsx/blob/master/bin/xlsx.njs> node | ||||
| - <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node | ||||
| 
 | ||||
| The node version installs a command line tool `xlsx` which can read spreadsheet | ||||
| files and output the contents in various formats.  The source is available at | ||||
| @ -882,7 +881,7 @@ Utilities are available in the `XLSX.utils` object and are described in the | ||||
| 
 | ||||
| ## Common Spreadsheet Format | ||||
| 
 | ||||
| js-xlsx conforms to the Common Spreadsheet Format (CSF): | ||||
| SheetJS conforms to the Common Spreadsheet Format (CSF): | ||||
| 
 | ||||
| ### General Structures | ||||
| 
 | ||||
| @ -1605,7 +1604,7 @@ The visibility setting is stored in the `Hidden` property of sheet props array. | ||||
| |   1   | Hidden      | | ||||
| |   2   | Very Hidden | | ||||
| 
 | ||||
| With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>: | ||||
| With <https://rawgit.com/SheetJS/test_files/HEAD/sheet_visibility.xlsx>: | ||||
| 
 | ||||
| ```js | ||||
| > wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] }) | ||||
| @ -2728,14 +2727,11 @@ $ open -a Chromium.app http://localhost:8000/stress.html | ||||
|  - Safari 6+ (iOS and Desktop) | ||||
|  - Edge 13+, FF 18+, and Opera 12+ | ||||
| 
 | ||||
| Tests utilize the mocha testing framework.  Travis-CI and Sauce Labs links: | ||||
| Tests utilize the mocha testing framework. | ||||
| 
 | ||||
|  - <https://travis-ci.org/SheetJS/js-xlsx> for XLSX module in nodejs | ||||
|  - <https://semaphoreci.com/sheetjs/js-xlsx> for XLSX module in nodejs | ||||
|  - <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS\* modules | ||||
|  - <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs | ||||
| 
 | ||||
| The Travis-CI test suite also includes tests for various time zones.  To change | ||||
| The test suite also includes tests for various time zones.  To change | ||||
| the timezone locally, set the TZ environment variable: | ||||
| 
 | ||||
| ```bash | ||||
|  | ||||
							
								
								
									
										155
									
								
								bits/40_harb.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										155
									
								
								bits/40_harb.js
									
									
									
									
									
								
							| @ -35,7 +35,9 @@ var dbf_codepage_map = { | ||||
| 	/*::[*/0x4D/*::]*/:   936,           /*::[*/0x4E/*::]*/:   949, | ||||
| 	/*::[*/0x4F/*::]*/:   950,           /*::[*/0x50/*::]*/:   874, | ||||
| 	/*::[*/0x57/*::]*/:  1252,           /*::[*/0x58/*::]*/:  1252, | ||||
| 	/*::[*/0x59/*::]*/:  1252, | ||||
| 	/*::[*/0x59/*::]*/:  1252,           /*::[*/0x6C/*::]*/:   863, | ||||
| 	/*::[*/0x86/*::]*/:   737,           /*::[*/0x87/*::]*/:   852, | ||||
| 	/*::[*/0x88/*::]*/:   857,           /*::[*/0xCC/*::]*/:  1257, | ||||
| 
 | ||||
| 	/*::[*/0xFF/*::]*/: 16969 | ||||
| }; | ||||
| @ -59,7 +61,6 @@ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; | ||||
| /* TODO: find an actual specification */ | ||||
| function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 	var out/*:AOA*/ = []; | ||||
| 	/* TODO: browser based */ | ||||
| 	var d/*:Block*/ = (new_raw_buf(1)/*:any*/); | ||||
| 	switch(opts.type) { | ||||
| 		case 'base64': d = s2a(Base64.decode(buf)); break; | ||||
| @ -68,44 +69,55 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		case 'array': d = buf; break; | ||||
| 	} | ||||
| 	prep_blob(d, 0); | ||||
| 
 | ||||
| 	/* header */ | ||||
| 	var ft = d.read_shift(1); | ||||
| 	var memo = false; | ||||
| 	var memo = !!(ft & 0x88); | ||||
| 	var vfp = false, l7 = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| 		case 0x8B: memo = true; break; | ||||
| 		case 0x8C: memo = true; l7 = true; break; | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		case 0x02: break; // dBASE II
 | ||||
| 		case 0x03: break; // dBASE III
 | ||||
| 		case 0x30: vfp = true; memo = true; break; // VFP
 | ||||
| 		case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
 | ||||
| 		// 0x43 dBASE IV SQL table files
 | ||||
| 		// 0x63 dBASE IV SQL system files
 | ||||
| 		case 0x83: break; // dBASE III with memo
 | ||||
| 		case 0x8B: break; // dBASE IV with memo
 | ||||
| 		case 0x8C: l7 = true; break; // dBASE Level 7 with memo
 | ||||
| 		// case 0xCB dBASE IV SQL table files with memo
 | ||||
| 		case 0xF5: break; // FoxPro 2.x with memo
 | ||||
| 		// case 0xFB FoxBASE
 | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var /*filedate = new Date(),*/ nrow = 0, fpos = 0; | ||||
| 
 | ||||
| 	var nrow = 0, fpos = 0x0209; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3; | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); if(nrow > 1048576) nrow = 1e6; | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
 | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(nrow > 1048576) nrow = 1e6; | ||||
| 
 | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); // header length
 | ||||
| 	var rlen = d.read_shift(2); // record length
 | ||||
| 
 | ||||
| 	var /*flags = 0,*/ current_cp = opts.codepage || 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	/*flags = */d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 	if(ft != 0x02) { // 20 reserved bytes
 | ||||
| 		d.l+=16; | ||||
| 		/*flags = */d.read_shift(1); | ||||
| 		//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 		/* codepage present in FoxPro and dBASE Level 7 */ | ||||
| 		if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 		d.l+=1; | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 		d.l+=2; | ||||
| 	} | ||||
| 	if(l7) d.l += 36; | ||||
| 	if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
 | ||||
| 
 | ||||
| /*:: type DBFField = { name:string; len:number; type:string; } */ | ||||
| 	var fields/*:Array<DBFField>*/ = [], field/*:DBFField*/ = ({}/*:any*/); | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11; | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 	var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0)))); | ||||
| 	var ww = l7 ? 32 : 11; | ||||
| 	while(d.l < hend && d[d.l] != 0x0d) { | ||||
| 		field = ({}/*:any*/); | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += ww; | ||||
| @ -117,42 +129,45 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		if(ft != 0x02) d.l += l7 ? 13 : 14; | ||||
| 		switch(field.type) { | ||||
| 			case 'B': // VFP Double
 | ||||
| 			case 'B': // Double (VFP) / Binary (dBASE L7)
 | ||||
| 				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'G': // General
 | ||||
| 			case 'P': // Picture
 | ||||
| 			case 'G': // General (FoxPro and dBASE L7)
 | ||||
| 			case 'P': // Picture (FoxPro and dBASE L7)
 | ||||
| 				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'C': // character
 | ||||
| 			case 'D': // date
 | ||||
| 			case 'F': // floating point
 | ||||
| 			case 'I': // long
 | ||||
| 			case 'L': // boolean
 | ||||
| 			case 'M': // memo
 | ||||
| 			case 'N': // number
 | ||||
| 			case 'O': // double
 | ||||
| 			case 'T': // datetime
 | ||||
| 			case 'Y': // currency
 | ||||
| 			case '0': // VFP _NullFlags
 | ||||
| 			case '@': // timestamp
 | ||||
| 			case '+': // autoincrement
 | ||||
| 			case '+': // Autoincrement (dBASE L7 only)
 | ||||
| 			case '0': // _NullFlags (VFP only)
 | ||||
| 			case '@': // Timestamp (dBASE L7 only)
 | ||||
| 			case 'C': // Character (dBASE II)
 | ||||
| 			case 'D': // Date (dBASE III)
 | ||||
| 			case 'F': // Float (dBASE IV)
 | ||||
| 			case 'I': // Long (VFP and dBASE L7)
 | ||||
| 			case 'L': // Logical (dBASE II)
 | ||||
| 			case 'M': // Memo (dBASE III)
 | ||||
| 			case 'N': // Number (dBASE II)
 | ||||
| 			case 'O': // Double (dBASE L7 only)
 | ||||
| 			case 'T': // Datetime (VFP only)
 | ||||
| 			case 'Y': // Currency (VFP only)
 | ||||
| 				break; | ||||
| 			default: throw new Error('Unknown Field Type: ' + field.type); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 
 | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| 	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name; | ||||
| 	while(nrow-- > 0) { | ||||
| 		if(d[d.l] === 0x2A) { d.l+=rlen; continue; } | ||||
| 		if(d[d.l] === 0x2A) { | ||||
| 			// TODO: record marked as deleted -- create a hidden row?
 | ||||
| 			d.l+=rlen; | ||||
| 			continue; | ||||
| 		} | ||||
| 		++d.l; | ||||
| 		out[++R] = []; C = 0; | ||||
| 		for(C = 0; C != fields.length; ++C) { | ||||
| @ -161,8 +176,8 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 			var s = cptable.utils.decode(current_cp, dd); | ||||
| 			switch(fields[C].type) { | ||||
| 				case 'C': | ||||
| 					out[R][C] = cptable.utils.decode(current_cp, dd); | ||||
| 					out[R][C] = out[R][C].trim(); | ||||
| 					// NOTE: it is conventional to write '  /  /  ' for empty dates
 | ||||
| 					if(s.trim().length) out[R][C] = s.replace(/\s+$/,""); | ||||
| 					break; | ||||
| 				case 'D': | ||||
| 					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8)); | ||||
| @ -170,18 +185,24 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 					break; | ||||
| 				case 'F': out[R][C] = parseFloat(s.trim()); break; | ||||
| 				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break; | ||||
| 				case 'L': switch(s.toUpperCase()) { | ||||
| 				case 'L': switch(s.trim().toUpperCase()) { | ||||
| 					case 'Y': case 'T': out[R][C] = true; break; | ||||
| 					case 'N': case 'F': out[R][C] = false; break; | ||||
| 					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */ | ||||
| 					case '': case '?': break; | ||||
| 					default: throw new Error("DBF Unrecognized L:|" + s + "|"); | ||||
| 					} break; | ||||
| 				case 'M': /* TODO: handle memo files */ | ||||
| 					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16)); | ||||
| 					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4)); | ||||
| 					break; | ||||
| 				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break; | ||||
| 				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break; | ||||
| 				case 'N': | ||||
| 					s = s.replace(/\u0000/g,"").trim(); | ||||
| 					// NOTE: dBASE II interprets "  .  " as 0
 | ||||
| 					if(s && s != ".") out[R][C] = +s || 0; break; | ||||
| 				case '@': | ||||
| 					// NOTE: dBASE specs appear to be incorrect
 | ||||
| 					out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); | ||||
| 					break; | ||||
| 				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break; | ||||
| 				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break; | ||||
| 				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break; | ||||
| @ -374,7 +395,7 @@ var SYLK = (function() { | ||||
| 					formats.push(rstr.slice(3).replace(/;;/g, ";")); | ||||
| 				break; | ||||
| 			case 'C': | ||||
| 			var C_seen_K = false, C_seen_X = false; | ||||
| 			var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1; | ||||
| 			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break; | ||||
| 				case 'Y': | ||||
| @ -396,12 +417,30 @@ var SYLK = (function() { | ||||
| 					C_seen_K = true; | ||||
| 					break; | ||||
| 				case 'E': | ||||
| 					C_seen_E = true; | ||||
| 					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C}); | ||||
| 					arr[R][C] = [arr[R][C], formula]; | ||||
| 					break; | ||||
| 				case 'S': | ||||
| 					C_seen_S = true; | ||||
| 					arr[R][C] = [arr[R][C], "S5S"]; | ||||
| 					break; | ||||
| 				case 'G': break; // unknown
 | ||||
| 				case 'R': _R = parseInt(record[rj].slice(1))-1; break; | ||||
| 				case 'C': _C = parseInt(record[rj].slice(1))-1; break; | ||||
| 				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr); | ||||
| 			} | ||||
| 			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; } | ||||
| 			if(C_seen_K) { | ||||
| 				if(arr[R][C] && arr[R][C].length == 2) arr[R][C][0] = val; | ||||
| 				else arr[R][C] = val; | ||||
| 				next_cell_format = null; | ||||
| 			} | ||||
| 			if(C_seen_S) { | ||||
| 				if(C_seen_E) throw new Error("SYLK shared formula cannot have own formula"); | ||||
| 				var shrbase = _R > -1 && arr[_R][_C]; | ||||
| 				if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base"); | ||||
| 				arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C}); | ||||
| 			} | ||||
| 			break; | ||||
| 			case 'F': | ||||
| 			var F_seen = 0; | ||||
| @ -736,9 +775,9 @@ var ETH = (function() { | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data); | ||||
| 		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data); | ||||
| 		else arr[R][C] = data; | ||||
| @ -897,7 +936,7 @@ var PRN = (function() { | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str)); | ||||
| 		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
|  | ||||
| @ -85,7 +85,10 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break; | ||||
| 		case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break; | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break; | ||||
| 		case 0x49: | ||||
| 			if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet"); | ||||
| 			if(n[1] === 0x44) return read_wb_ID(d, o); | ||||
| 			break; | ||||
| 		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str); | ||||
|  | ||||
| @ -116,8 +116,8 @@ in the ZIP file. | ||||
| 
 | ||||
| When reading form data, be sure to include the necessary binary types on the AWS API Gateway console. | ||||
| To do this, navigate to the "Binary Media Types" section in the settings tab of the console. | ||||
| For reading a file, you may need to add "multipart/form-data". | ||||
| For downloading a file, you may need to add "application/vnd.ms-excel". | ||||
| For reading a file, you may need to add `"multipart/form-data"`. | ||||
| For downloading a file, you may need to add `"application/vnd.ms-excel"`. | ||||
| 
 | ||||
| #### Azure Functions | ||||
| 
 | ||||
|  | ||||
							
								
								
									
										7
									
								
								dist/cpexcel.js
									
									
									
										generated
									
									
										vendored
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										7
									
								
								dist/cpexcel.js
									
									
									
										generated
									
									
										vendored
									
									
								
							| @ -1,6 +1,6 @@ | ||||
| /* cpexcel.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /*! cpexcel.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /*jshint -W100 */ | ||||
| var cptable = {version:"1.14.0"}; | ||||
| var cptable = {version:"1.15.0"}; | ||||
| cptable[437] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàåçêëèïîìÄÅÉæÆôöòûùÿÖÜ¢£¥₧ƒáíóúñѪº¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| cptable[620] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÇüéâäàąçêëèïîćÄĄĘęłôöĆûùŚÖܢ٥śƒŹŻóÓńŃźż¿⌐¬½¼¡«»░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀αßΓπΣσµτΦΘΩδ∞φε∩≡±≥≤⌠⌡÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| cptable[737] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ΑΒΓΔΕΖΗΘΙΚΛΜΝΞΟΠΡΣΤΥΦΧΨΩαβγδεζηθικλμνξοπρσςτυφχψ░▒▓│┤╡╢╖╕╣║╗╝╜╛┐└┴┬├─┼╞╟╚╔╩╦╠═╬╧╨╤╥╙╘╒╓╫╪┘┌█▄▌▐▀ωάέήϊίόύϋώΆΈΉΊΌΎΏ±≥≤ΪΫ÷≈°∙·√ⁿ²■ ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| @ -973,9 +973,10 @@ return {"enc": e, "dec": d }; })(); | ||||
| cptable[10029] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄĀāÉĄÖÜáąČäčĆć鏟ĎíďĒēĖóėôöõúĚěü†°Ę£§•¶ß®©™ę¨≠ģĮįĪ≤≥īĶ∂∑łĻļĽľĹĺŅņѬ√ńŇ∆«»… ňŐÕőŌ–—“”‘’÷◊ōŔŕŘ‹›řŖŗŠ‚„šŚśÁŤťÍŽžŪÓÔūŮÚůŰűŲųÝýķŻŁżĢˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| cptable[10079] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûüݰ¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸ⁄¤ÐðÞþý·‚„‰ÂÊÁËÈÍÎÏÌÓÔ<C393>ÒÚÛÙıˆ˜¯˘˙˚¸˝˛ˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| cptable[10081] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~ÄÅÇÉÑÖÜáàâäãåçéèêëíìîïñóòôöõúùûü†°¢£§•¶ß®©™´¨≠ÆØ∞±≤≥¥µ∂∑∏π∫ªºΩæø¿¡¬√ƒ≈∆«»… ÀÃÕŒœ–—“”‘’÷◊ÿŸĞğİıŞş‡·‚„‰ÂÊÁËÈÍÎÏÌÓÔ<C393>ÒÚÛÙ<C39B>ˆ˜¯˘˙˚¸˝˛ˇ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| cptable[28591] = (function(){ var d = "\u0000\u0001\u0002\u0003\u0004\u0005\u0006\u0007\b\t\n\u000b\f\r\u000e\u000f\u0010\u0011\u0012\u0013\u0014\u0015\u0016\u0017\u0018\u0019\u001a\u001b\u001c\u001d\u001e\u001f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~
 ¡¢£¤¥¦§¨©ª«¬®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖרÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ", D = [], e = {}; for(var i=0;i!=d.length;++i) { if(d.charCodeAt(i) !== 0xFFFD) e[d.charAt(i)] = i; D[i] = d.charAt(i); } return {"enc": e, "dec": D }; })(); | ||||
| // eslint-disable-next-line no-undef
 | ||||
| if (typeof module !== 'undefined' && module.exports && typeof DO_NOT_EXPORT_CODEPAGE === 'undefined') module.exports = cptable; | ||||
| /* cputils.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /*! cputils.js (C) 2013-present SheetJS -- http://sheetjs.com */ | ||||
| /* vim: set ft=javascript: */ | ||||
| /*jshint newcap: false */ | ||||
| (function(root, factory) { | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| # [SheetJS js-xlsx](http://sheetjs.com) | ||||
| # [SheetJS](http://sheetjs.com) | ||||
| 
 | ||||
| Parser and writer for various spreadsheet formats.  Pure-JS cleanroom | ||||
| implementation from official specifications, related documents, and test files. | ||||
| @ -36,7 +36,6 @@ enhancements, additional features like styling, and dedicated support. | ||||
| 
 | ||||
| [](https://saucelabs.com/u/sheetjs) | ||||
| 
 | ||||
| [](https://travis-ci.org/SheetJS/sheetjs) | ||||
| [](https://semaphoreci.com/sheetjs/sheetjs) | ||||
| [](https://coveralls.io/r/SheetJS/sheetjs?branch=master) | ||||
| [](https://david-dm.org/sheetjs/sheetjs) | ||||
|  | ||||
| @ -34,7 +34,7 @@ be configured to remove support with `resolve.alias`: | ||||
| ### ECMAScript 5 Compatibility | ||||
| 
 | ||||
| Since the library uses functions like `Array#forEach`, older browsers require | ||||
| [shims to provide missing functions](http://oss.sheetjs.com/js-xlsx/shim.js). | ||||
| [shims to provide missing functions](http://oss.sheetjs.com/sheetjs/shim.js). | ||||
| 
 | ||||
| To use the shim, add the shim before the script tag that loads `xlsx.js`: | ||||
| 
 | ||||
|  | ||||
| @ -8,7 +8,7 @@ Third-party libraries either supported one format, or they involved a separate | ||||
| set of classes for each supported file type.  Even though XLSB was introduced in | ||||
| Excel 2007, nothing outside of SheetJS or Excel supported the format. | ||||
| 
 | ||||
| To promote a format-agnostic view, js-xlsx starts from a pure-JS representation | ||||
| To promote a format-agnostic view, SheetJS starts from a pure-JS representation | ||||
| that we call the ["Common Spreadsheet Format"](#common-spreadsheet-format). | ||||
| Emphasizing a uniform object representation enables new features like format | ||||
| conversion (reading an XLSX template and saving as XLS) and circumvents the mess | ||||
|  | ||||
| @ -75,7 +75,7 @@ var workbook = XLSX.read(htmlstr, {type:'string'}); | ||||
|   <summary><b>Browser download file (ajax)</b> (click to show)</summary> | ||||
| 
 | ||||
| Note: for a more complete example that works in older browsers, check the demo | ||||
| at <http://oss.sheetjs.com/js-xlsx/ajax.html>.  The [`xhr` demo](demos/xhr/) | ||||
| at <http://oss.sheetjs.com/sheetjs/ajax.html>.  The [`xhr` demo](demos/xhr/) | ||||
| includes more examples with `XMLHttpRequest` and `fetch`. | ||||
| 
 | ||||
| ```js | ||||
| @ -151,7 +151,7 @@ More specialized cases, including mobile app file processing, are covered in the | ||||
| 
 | ||||
| ### Parsing Examples | ||||
| 
 | ||||
| - <http://oss.sheetjs.com/js-xlsx/> HTML5 File API / Base64 Text / Web Workers | ||||
| - <http://oss.sheetjs.com/sheetjs/> HTML5 File API / Base64 Text / Web Workers | ||||
| 
 | ||||
| Note that older versions of IE do not support HTML5 File API, so the Base64 mode | ||||
| is used for testing. | ||||
| @ -175,5 +175,5 @@ On Windows XP and up you can get the Base64 encoding using `certutil`: | ||||
| 
 | ||||
| </details> | ||||
| 
 | ||||
| - <http://oss.sheetjs.com/js-xlsx/ajax.html> XMLHttpRequest | ||||
| - <http://oss.sheetjs.com/sheetjs/ajax.html> XMLHttpRequest | ||||
| 
 | ||||
|  | ||||
| @ -67,7 +67,7 @@ error if the workbook is empty. | ||||
| 
 | ||||
| - <http://sheetjs.com/demos/modify.html> read + modify + write files | ||||
| 
 | ||||
| - <https://github.com/SheetJS/js-xlsx/blob/HEAD/bin/xlsx.njs> node | ||||
| - <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node | ||||
| 
 | ||||
| The node version installs a command line tool `xlsx` which can read spreadsheet | ||||
| files and output the contents in various formats.  The source is available at | ||||
|  | ||||
| @ -1,6 +1,6 @@ | ||||
| ## Common Spreadsheet Format | ||||
| 
 | ||||
| js-xlsx conforms to the Common Spreadsheet Format (CSF): | ||||
| SheetJS conforms to the Common Spreadsheet Format (CSF): | ||||
| 
 | ||||
| ### General Structures | ||||
| 
 | ||||
|  | ||||
| @ -71,14 +71,11 @@ $ open -a Chromium.app http://localhost:8000/stress.html | ||||
|  - Safari 6+ (iOS and Desktop) | ||||
|  - Edge 13+, FF 18+, and Opera 12+ | ||||
| 
 | ||||
| Tests utilize the mocha testing framework.  Travis-CI and Sauce Labs links: | ||||
| Tests utilize the mocha testing framework. | ||||
| 
 | ||||
|  - <https://travis-ci.org/SheetJS/js-xlsx> for XLSX module in nodejs | ||||
|  - <https://semaphoreci.com/sheetjs/js-xlsx> for XLSX module in nodejs | ||||
|  - <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS\* modules | ||||
|  - <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs | ||||
| 
 | ||||
| The Travis-CI test suite also includes tests for various time zones.  To change | ||||
| The test suite also includes tests for various time zones.  To change | ||||
| the timezone locally, set the TZ environment variable: | ||||
| 
 | ||||
| ```bash | ||||
|  | ||||
| @ -1,4 +1,4 @@ | ||||
| # [SheetJS js-xlsx](http://sheetjs.com) | ||||
| # [SheetJS](http://sheetjs.com) | ||||
| 
 | ||||
| Parser and writer for various spreadsheet formats.  Pure-JS cleanroom | ||||
| implementation from official specifications, related documents, and test files. | ||||
| @ -33,7 +33,6 @@ enhancements, additional features like styling, and dedicated support. | ||||
| 
 | ||||
| [](https://saucelabs.com/u/sheetjs) | ||||
| 
 | ||||
| [](https://travis-ci.org/SheetJS/sheetjs) | ||||
| [](https://semaphoreci.com/sheetjs/sheetjs) | ||||
| [](https://coveralls.io/r/SheetJS/sheetjs?branch=master) | ||||
| [](https://david-dm.org/sheetjs/sheetjs) | ||||
| @ -246,7 +245,7 @@ be configured to remove support with `resolve.alias`: | ||||
| ### ECMAScript 5 Compatibility | ||||
| 
 | ||||
| Since the library uses functions like `Array#forEach`, older browsers require | ||||
| [shims to provide missing functions](http://oss.sheetjs.com/js-xlsx/shim.js). | ||||
| [shims to provide missing functions](http://oss.sheetjs.com/sheetjs/shim.js). | ||||
| 
 | ||||
| To use the shim, add the shim before the script tag that loads `xlsx.js`: | ||||
| 
 | ||||
| @ -269,7 +268,7 @@ Third-party libraries either supported one format, or they involved a separate | ||||
| set of classes for each supported file type.  Even though XLSB was introduced in | ||||
| Excel 2007, nothing outside of SheetJS or Excel supported the format. | ||||
| 
 | ||||
| To promote a format-agnostic view, js-xlsx starts from a pure-JS representation | ||||
| To promote a format-agnostic view, SheetJS starts from a pure-JS representation | ||||
| that we call the ["Common Spreadsheet Format"](#common-spreadsheet-format). | ||||
| Emphasizing a uniform object representation enables new features like format | ||||
| conversion (reading an XLSX template and saving as XLS) and circumvents the mess | ||||
| @ -363,7 +362,7 @@ var workbook = XLSX.read(htmlstr, {type:'string'}); | ||||
| 
 | ||||
| 
 | ||||
| Note: for a more complete example that works in older browsers, check the demo | ||||
| at <http://oss.sheetjs.com/js-xlsx/ajax.html>.  The [`xhr` demo](demos/xhr/) | ||||
| at <http://oss.sheetjs.com/sheetjs/ajax.html>.  The [`xhr` demo](demos/xhr/) | ||||
| includes more examples with `XMLHttpRequest` and `fetch`. | ||||
| 
 | ||||
| ```js | ||||
| @ -432,7 +431,7 @@ More specialized cases, including mobile app file processing, are covered in the | ||||
| 
 | ||||
| ### Parsing Examples | ||||
| 
 | ||||
| - <http://oss.sheetjs.com/js-xlsx/> HTML5 File API / Base64 Text / Web Workers | ||||
| - <http://oss.sheetjs.com/sheetjs/> HTML5 File API / Base64 Text / Web Workers | ||||
| 
 | ||||
| Note that older versions of IE do not support HTML5 File API, so the Base64 mode | ||||
| is used for testing. | ||||
| @ -453,7 +452,7 @@ On Windows XP and up you can get the Base64 encoding using `certutil`: | ||||
| (note: You have to open the file and remove the header and footer lines) | ||||
| 
 | ||||
| 
 | ||||
| - <http://oss.sheetjs.com/js-xlsx/ajax.html> XMLHttpRequest | ||||
| - <http://oss.sheetjs.com/sheetjs/ajax.html> XMLHttpRequest | ||||
| 
 | ||||
| ### Streaming Read | ||||
| 
 | ||||
| @ -573,7 +572,7 @@ error if the workbook is empty. | ||||
| 
 | ||||
| - <http://sheetjs.com/demos/modify.html> read + modify + write files | ||||
| 
 | ||||
| - <https://github.com/SheetJS/js-xlsx/blob/master/bin/xlsx.njs> node | ||||
| - <https://github.com/SheetJS/sheetjs/blob/HEAD/bin/xlsx.njs> node | ||||
| 
 | ||||
| The node version installs a command line tool `xlsx` which can read spreadsheet | ||||
| files and output the contents in various formats.  The source is available at | ||||
| @ -804,7 +803,7 @@ Utilities are available in the `XLSX.utils` object and are described in the | ||||
| 
 | ||||
| ## Common Spreadsheet Format | ||||
| 
 | ||||
| js-xlsx conforms to the Common Spreadsheet Format (CSF): | ||||
| SheetJS conforms to the Common Spreadsheet Format (CSF): | ||||
| 
 | ||||
| ### General Structures | ||||
| 
 | ||||
| @ -1471,7 +1470,7 @@ The visibility setting is stored in the `Hidden` property of sheet props array. | ||||
| |   1   | Hidden      | | ||||
| |   2   | Very Hidden | | ||||
| 
 | ||||
| With <https://rawgit.com/SheetJS/test_files/master/sheet_visibility.xlsx>: | ||||
| With <https://rawgit.com/SheetJS/test_files/HEAD/sheet_visibility.xlsx>: | ||||
| 
 | ||||
| ```js | ||||
| > wb.Workbook.Sheets.map(function(x) { return [x.name, x.Hidden] }) | ||||
| @ -2486,14 +2485,11 @@ $ open -a Chromium.app http://localhost:8000/stress.html | ||||
|  - Safari 6+ (iOS and Desktop) | ||||
|  - Edge 13+, FF 18+, and Opera 12+ | ||||
| 
 | ||||
| Tests utilize the mocha testing framework.  Travis-CI and Sauce Labs links: | ||||
| Tests utilize the mocha testing framework. | ||||
| 
 | ||||
|  - <https://travis-ci.org/SheetJS/js-xlsx> for XLSX module in nodejs | ||||
|  - <https://semaphoreci.com/sheetjs/js-xlsx> for XLSX module in nodejs | ||||
|  - <https://travis-ci.org/SheetJS/SheetJS.github.io> for XLS\* modules | ||||
|  - <https://saucelabs.com/u/sheetjs> for XLS\* modules using Sauce Labs | ||||
| 
 | ||||
| The Travis-CI test suite also includes tests for various time zones.  To change | ||||
| The test suite also includes tests for various time zones.  To change | ||||
| the timezone locally, set the TZ environment variable: | ||||
| 
 | ||||
| ```bash | ||||
|  | ||||
| @ -34,7 +34,7 @@ | ||||
| 	"dependencies": { | ||||
| 		"adler-32": "~1.2.0", | ||||
| 		"cfb": "^1.1.4", | ||||
| 		"codepage": "~1.14.0", | ||||
| 		"codepage": "~1.15.0", | ||||
| 		"commander": "~2.17.1", | ||||
| 		"crc-32": "~1.2.0", | ||||
| 		"exit-on-epipe": "~1.0.1", | ||||
|  | ||||
							
								
								
									
										162
									
								
								xlsx.flow.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										162
									
								
								xlsx.flow.js
									
									
									
									
									
								
							| @ -7035,7 +7035,9 @@ var dbf_codepage_map = { | ||||
| 	/*::[*/0x4D/*::]*/:   936,           /*::[*/0x4E/*::]*/:   949, | ||||
| 	/*::[*/0x4F/*::]*/:   950,           /*::[*/0x50/*::]*/:   874, | ||||
| 	/*::[*/0x57/*::]*/:  1252,           /*::[*/0x58/*::]*/:  1252, | ||||
| 	/*::[*/0x59/*::]*/:  1252, | ||||
| 	/*::[*/0x59/*::]*/:  1252,           /*::[*/0x6C/*::]*/:   863, | ||||
| 	/*::[*/0x86/*::]*/:   737,           /*::[*/0x87/*::]*/:   852, | ||||
| 	/*::[*/0x88/*::]*/:   857,           /*::[*/0xCC/*::]*/:  1257, | ||||
| 
 | ||||
| 	/*::[*/0xFF/*::]*/: 16969 | ||||
| }; | ||||
| @ -7059,7 +7061,6 @@ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; | ||||
| /* TODO: find an actual specification */ | ||||
| function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 	var out/*:AOA*/ = []; | ||||
| 	/* TODO: browser based */ | ||||
| 	var d/*:Block*/ = (new_raw_buf(1)/*:any*/); | ||||
| 	switch(opts.type) { | ||||
| 		case 'base64': d = s2a(Base64.decode(buf)); break; | ||||
| @ -7068,44 +7069,55 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		case 'array': d = buf; break; | ||||
| 	} | ||||
| 	prep_blob(d, 0); | ||||
| 
 | ||||
| 	/* header */ | ||||
| 	var ft = d.read_shift(1); | ||||
| 	var memo = false; | ||||
| 	var memo = !!(ft & 0x88); | ||||
| 	var vfp = false, l7 = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| 		case 0x8B: memo = true; break; | ||||
| 		case 0x8C: memo = true; l7 = true; break; | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		case 0x02: break; // dBASE II
 | ||||
| 		case 0x03: break; // dBASE III
 | ||||
| 		case 0x30: vfp = true; memo = true; break; // VFP
 | ||||
| 		case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
 | ||||
| 		// 0x43 dBASE IV SQL table files
 | ||||
| 		// 0x63 dBASE IV SQL system files
 | ||||
| 		case 0x83: break; // dBASE III with memo
 | ||||
| 		case 0x8B: break; // dBASE IV with memo
 | ||||
| 		case 0x8C: l7 = true; break; // dBASE Level 7 with memo
 | ||||
| 		// case 0xCB dBASE IV SQL table files with memo
 | ||||
| 		case 0xF5: break; // FoxPro 2.x with memo
 | ||||
| 		// case 0xFB FoxBASE
 | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var /*filedate = new Date(),*/ nrow = 0, fpos = 0; | ||||
| 
 | ||||
| 	var nrow = 0, fpos = 0x0209; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3; | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); if(nrow > 1048576) nrow = 1e6; | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
 | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(nrow > 1048576) nrow = 1e6; | ||||
| 
 | ||||
| 	var /*flags = 0,*/ current_cp = 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	/*flags = */d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); // header length
 | ||||
| 	var rlen = d.read_shift(2); // record length
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 	var /*flags = 0,*/ current_cp = opts.codepage || 1252; | ||||
| 	if(ft != 0x02) { // 20 reserved bytes
 | ||||
| 		d.l+=16; | ||||
| 		/*flags = */d.read_shift(1); | ||||
| 		//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 		/* codepage present in FoxPro and dBASE Level 7 */ | ||||
| 		if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 		d.l+=1; | ||||
| 
 | ||||
| 		d.l+=2; | ||||
| 	} | ||||
| 	if(l7) d.l += 36; | ||||
| 	if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
 | ||||
| 
 | ||||
| /*:: type DBFField = { name:string; len:number; type:string; } */ | ||||
| 	var fields/*:Array<DBFField>*/ = [], field/*:DBFField*/ = ({}/*:any*/); | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11; | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 	var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0)))); | ||||
| 	var ww = l7 ? 32 : 11; | ||||
| 	while(d.l < hend && d[d.l] != 0x0d) { | ||||
| 		field = ({}/*:any*/); | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += ww; | ||||
| @ -7117,42 +7129,45 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		if(ft != 0x02) d.l += l7 ? 13 : 14; | ||||
| 		switch(field.type) { | ||||
| 			case 'B': // VFP Double
 | ||||
| 			case 'B': // Double (VFP) / Binary (dBASE L7)
 | ||||
| 				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'G': // General
 | ||||
| 			case 'P': // Picture
 | ||||
| 			case 'G': // General (FoxPro and dBASE L7)
 | ||||
| 			case 'P': // Picture (FoxPro and dBASE L7)
 | ||||
| 				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'C': // character
 | ||||
| 			case 'D': // date
 | ||||
| 			case 'F': // floating point
 | ||||
| 			case 'I': // long
 | ||||
| 			case 'L': // boolean
 | ||||
| 			case 'M': // memo
 | ||||
| 			case 'N': // number
 | ||||
| 			case 'O': // double
 | ||||
| 			case 'T': // datetime
 | ||||
| 			case 'Y': // currency
 | ||||
| 			case '0': // VFP _NullFlags
 | ||||
| 			case '@': // timestamp
 | ||||
| 			case '+': // autoincrement
 | ||||
| 			case '+': // Autoincrement (dBASE L7 only)
 | ||||
| 			case '0': // _NullFlags (VFP only)
 | ||||
| 			case '@': // Timestamp (dBASE L7 only)
 | ||||
| 			case 'C': // Character (dBASE II)
 | ||||
| 			case 'D': // Date (dBASE III)
 | ||||
| 			case 'F': // Float (dBASE IV)
 | ||||
| 			case 'I': // Long (VFP and dBASE L7)
 | ||||
| 			case 'L': // Logical (dBASE II)
 | ||||
| 			case 'M': // Memo (dBASE III)
 | ||||
| 			case 'N': // Number (dBASE II)
 | ||||
| 			case 'O': // Double (dBASE L7 only)
 | ||||
| 			case 'T': // Datetime (VFP only)
 | ||||
| 			case 'Y': // Currency (VFP only)
 | ||||
| 				break; | ||||
| 			default: throw new Error('Unknown Field Type: ' + field.type); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 
 | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| 	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name; | ||||
| 	while(nrow-- > 0) { | ||||
| 		if(d[d.l] === 0x2A) { d.l+=rlen; continue; } | ||||
| 		if(d[d.l] === 0x2A) { | ||||
| 			// TODO: record marked as deleted -- create a hidden row?
 | ||||
| 			d.l+=rlen; | ||||
| 			continue; | ||||
| 		} | ||||
| 		++d.l; | ||||
| 		out[++R] = []; C = 0; | ||||
| 		for(C = 0; C != fields.length; ++C) { | ||||
| @ -7161,8 +7176,8 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 			var s = cptable.utils.decode(current_cp, dd); | ||||
| 			switch(fields[C].type) { | ||||
| 				case 'C': | ||||
| 					out[R][C] = cptable.utils.decode(current_cp, dd); | ||||
| 					out[R][C] = out[R][C].trim(); | ||||
| 					// NOTE: it is conventional to write '  /  /  ' for empty dates
 | ||||
| 					if(s.trim().length) out[R][C] = s.replace(/\s+$/,""); | ||||
| 					break; | ||||
| 				case 'D': | ||||
| 					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8)); | ||||
| @ -7170,18 +7185,24 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 					break; | ||||
| 				case 'F': out[R][C] = parseFloat(s.trim()); break; | ||||
| 				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break; | ||||
| 				case 'L': switch(s.toUpperCase()) { | ||||
| 				case 'L': switch(s.trim().toUpperCase()) { | ||||
| 					case 'Y': case 'T': out[R][C] = true; break; | ||||
| 					case 'N': case 'F': out[R][C] = false; break; | ||||
| 					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */ | ||||
| 					case '': case '?': break; | ||||
| 					default: throw new Error("DBF Unrecognized L:|" + s + "|"); | ||||
| 					} break; | ||||
| 				case 'M': /* TODO: handle memo files */ | ||||
| 					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16)); | ||||
| 					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4)); | ||||
| 					break; | ||||
| 				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break; | ||||
| 				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break; | ||||
| 				case 'N': | ||||
| 					s = s.replace(/\u0000/g,"").trim(); | ||||
| 					// NOTE: dBASE II interprets "  .  " as 0
 | ||||
| 					if(s && s != ".") out[R][C] = +s || 0; break; | ||||
| 				case '@': | ||||
| 					// NOTE: dBASE specs appear to be incorrect
 | ||||
| 					out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); | ||||
| 					break; | ||||
| 				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break; | ||||
| 				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break; | ||||
| 				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break; | ||||
| @ -7374,7 +7395,7 @@ var SYLK = (function() { | ||||
| 					formats.push(rstr.slice(3).replace(/;;/g, ";")); | ||||
| 				break; | ||||
| 			case 'C': | ||||
| 			var C_seen_K = false, C_seen_X = false; | ||||
| 			var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1; | ||||
| 			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break; | ||||
| 				case 'Y': | ||||
| @ -7396,12 +7417,30 @@ var SYLK = (function() { | ||||
| 					C_seen_K = true; | ||||
| 					break; | ||||
| 				case 'E': | ||||
| 					C_seen_E = true; | ||||
| 					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C}); | ||||
| 					arr[R][C] = [arr[R][C], formula]; | ||||
| 					break; | ||||
| 				case 'S': | ||||
| 					C_seen_S = true; | ||||
| 					arr[R][C] = [arr[R][C], "S5S"]; | ||||
| 					break; | ||||
| 				case 'G': break; // unknown
 | ||||
| 				case 'R': _R = parseInt(record[rj].slice(1))-1; break; | ||||
| 				case 'C': _C = parseInt(record[rj].slice(1))-1; break; | ||||
| 				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr); | ||||
| 			} | ||||
| 			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; } | ||||
| 			if(C_seen_K) { | ||||
| 				if(arr[R][C] && arr[R][C].length == 2) arr[R][C][0] = val; | ||||
| 				else arr[R][C] = val; | ||||
| 				next_cell_format = null; | ||||
| 			} | ||||
| 			if(C_seen_S) { | ||||
| 				if(C_seen_E) throw new Error("SYLK shared formula cannot have own formula"); | ||||
| 				var shrbase = _R > -1 && arr[_R][_C]; | ||||
| 				if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base"); | ||||
| 				arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C}); | ||||
| 			} | ||||
| 			break; | ||||
| 			case 'F': | ||||
| 			var F_seen = 0; | ||||
| @ -7736,9 +7775,9 @@ var ETH = (function() { | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data); | ||||
| 		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data); | ||||
| 		else arr[R][C] = data; | ||||
| @ -7897,7 +7936,7 @@ var PRN = (function() { | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str)); | ||||
| 		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| @ -21151,7 +21190,10 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break; | ||||
| 		case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break; | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break; | ||||
| 		case 0x49: | ||||
| 			if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet"); | ||||
| 			if(n[1] === 0x44) return read_wb_ID(d, o); | ||||
| 			break; | ||||
| 		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str); | ||||
|  | ||||
							
								
								
									
										160
									
								
								xlsx.js
									
									
									
										generated
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										160
									
								
								xlsx.js
									
									
									
										generated
									
									
									
								
							| @ -6938,7 +6938,9 @@ var dbf_codepage_map = { | ||||
| 0x4D:   936,           0x4E:   949, | ||||
| 0x4F:   950,           0x50:   874, | ||||
| 0x57:  1252,           0x58:  1252, | ||||
| 0x59:  1252, | ||||
| 0x59:  1252,           0x6C:   863, | ||||
| 0x86:   737,           0x87:   852, | ||||
| 0x88:   857,           0xCC:  1257, | ||||
| 
 | ||||
| 0xFF: 16969 | ||||
| }; | ||||
| @ -6962,7 +6964,6 @@ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; | ||||
| /* TODO: find an actual specification */ | ||||
| function dbf_to_aoa(buf, opts) { | ||||
| 	var out = []; | ||||
| 	/* TODO: browser based */ | ||||
| 	var d = (new_raw_buf(1)); | ||||
| 	switch(opts.type) { | ||||
| 		case 'base64': d = s2a(Base64.decode(buf)); break; | ||||
| @ -6971,43 +6972,54 @@ function dbf_to_aoa(buf, opts) { | ||||
| 		case 'array': d = buf; break; | ||||
| 	} | ||||
| 	prep_blob(d, 0); | ||||
| 
 | ||||
| 	/* header */ | ||||
| 	var ft = d.read_shift(1); | ||||
| 	var memo = false; | ||||
| 	var memo = !!(ft & 0x88); | ||||
| 	var vfp = false, l7 = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| 		case 0x8B: memo = true; break; | ||||
| 		case 0x8C: memo = true; l7 = true; break; | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		case 0x02: break; // dBASE II
 | ||||
| 		case 0x03: break; // dBASE III
 | ||||
| 		case 0x30: vfp = true; memo = true; break; // VFP
 | ||||
| 		case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
 | ||||
| 		// 0x43 dBASE IV SQL table files
 | ||||
| 		// 0x63 dBASE IV SQL system files
 | ||||
| 		case 0x83: break; // dBASE III with memo
 | ||||
| 		case 0x8B: break; // dBASE IV with memo
 | ||||
| 		case 0x8C: l7 = true; break; // dBASE Level 7 with memo
 | ||||
| 		// case 0xCB dBASE IV SQL table files with memo
 | ||||
| 		case 0xF5: break; // FoxPro 2.x with memo
 | ||||
| 		// case 0xFB FoxBASE
 | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var /*filedate = new Date(),*/ nrow = 0, fpos = 0; | ||||
| 
 | ||||
| 	var nrow = 0, fpos = 0x0209; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3; | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); if(nrow > 1048576) nrow = 1e6; | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
 | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(nrow > 1048576) nrow = 1e6; | ||||
| 
 | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); // header length
 | ||||
| 	var rlen = d.read_shift(2); // record length
 | ||||
| 
 | ||||
| 	var /*flags = 0,*/ current_cp = opts.codepage || 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	/*flags = */d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 	if(ft != 0x02) { // 20 reserved bytes
 | ||||
| 		d.l+=16; | ||||
| 		/*flags = */d.read_shift(1); | ||||
| 		//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 		/* codepage present in FoxPro and dBASE Level 7 */ | ||||
| 		if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 		d.l+=1; | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 		d.l+=2; | ||||
| 	} | ||||
| 	if(l7) d.l += 36; | ||||
| 	if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
 | ||||
| 
 | ||||
| var fields = [], field = ({}); | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11; | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 	var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0)))); | ||||
| 	var ww = l7 ? 32 : 11; | ||||
| 	while(d.l < hend && d[d.l] != 0x0d) { | ||||
| 		field = ({}); | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += ww; | ||||
| @ -7019,42 +7031,45 @@ var fields = [], field = ({}); | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		if(ft != 0x02) d.l += l7 ? 13 : 14; | ||||
| 		switch(field.type) { | ||||
| 			case 'B': // VFP Double
 | ||||
| 			case 'B': // Double (VFP) / Binary (dBASE L7)
 | ||||
| 				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'G': // General
 | ||||
| 			case 'P': // Picture
 | ||||
| 			case 'G': // General (FoxPro and dBASE L7)
 | ||||
| 			case 'P': // Picture (FoxPro and dBASE L7)
 | ||||
| 				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'C': // character
 | ||||
| 			case 'D': // date
 | ||||
| 			case 'F': // floating point
 | ||||
| 			case 'I': // long
 | ||||
| 			case 'L': // boolean
 | ||||
| 			case 'M': // memo
 | ||||
| 			case 'N': // number
 | ||||
| 			case 'O': // double
 | ||||
| 			case 'T': // datetime
 | ||||
| 			case 'Y': // currency
 | ||||
| 			case '0': // VFP _NullFlags
 | ||||
| 			case '@': // timestamp
 | ||||
| 			case '+': // autoincrement
 | ||||
| 			case '+': // Autoincrement (dBASE L7 only)
 | ||||
| 			case '0': // _NullFlags (VFP only)
 | ||||
| 			case '@': // Timestamp (dBASE L7 only)
 | ||||
| 			case 'C': // Character (dBASE II)
 | ||||
| 			case 'D': // Date (dBASE III)
 | ||||
| 			case 'F': // Float (dBASE IV)
 | ||||
| 			case 'I': // Long (VFP and dBASE L7)
 | ||||
| 			case 'L': // Logical (dBASE II)
 | ||||
| 			case 'M': // Memo (dBASE III)
 | ||||
| 			case 'N': // Number (dBASE II)
 | ||||
| 			case 'O': // Double (dBASE L7 only)
 | ||||
| 			case 'T': // Datetime (VFP only)
 | ||||
| 			case 'Y': // Currency (VFP only)
 | ||||
| 				break; | ||||
| 			default: throw new Error('Unknown Field Type: ' + field.type); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 
 | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| 	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name; | ||||
| 	while(nrow-- > 0) { | ||||
| 		if(d[d.l] === 0x2A) { d.l+=rlen; continue; } | ||||
| 		if(d[d.l] === 0x2A) { | ||||
| 			// TODO: record marked as deleted -- create a hidden row?
 | ||||
| 			d.l+=rlen; | ||||
| 			continue; | ||||
| 		} | ||||
| 		++d.l; | ||||
| 		out[++R] = []; C = 0; | ||||
| 		for(C = 0; C != fields.length; ++C) { | ||||
| @ -7063,8 +7078,8 @@ var fields = [], field = ({}); | ||||
| 			var s = cptable.utils.decode(current_cp, dd); | ||||
| 			switch(fields[C].type) { | ||||
| 				case 'C': | ||||
| 					out[R][C] = cptable.utils.decode(current_cp, dd); | ||||
| 					out[R][C] = out[R][C].trim(); | ||||
| 					// NOTE: it is conventional to write '  /  /  ' for empty dates
 | ||||
| 					if(s.trim().length) out[R][C] = s.replace(/\s+$/,""); | ||||
| 					break; | ||||
| 				case 'D': | ||||
| 					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8)); | ||||
| @ -7072,18 +7087,24 @@ var fields = [], field = ({}); | ||||
| 					break; | ||||
| 				case 'F': out[R][C] = parseFloat(s.trim()); break; | ||||
| 				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break; | ||||
| 				case 'L': switch(s.toUpperCase()) { | ||||
| 				case 'L': switch(s.trim().toUpperCase()) { | ||||
| 					case 'Y': case 'T': out[R][C] = true; break; | ||||
| 					case 'N': case 'F': out[R][C] = false; break; | ||||
| 					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */ | ||||
| 					case '': case '?': break; | ||||
| 					default: throw new Error("DBF Unrecognized L:|" + s + "|"); | ||||
| 					} break; | ||||
| 				case 'M': /* TODO: handle memo files */ | ||||
| 					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16)); | ||||
| 					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4)); | ||||
| 					break; | ||||
| 				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break; | ||||
| 				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break; | ||||
| 				case 'N': | ||||
| 					s = s.replace(/\u0000/g,"").trim(); | ||||
| 					// NOTE: dBASE II interprets "  .  " as 0
 | ||||
| 					if(s && s != ".") out[R][C] = +s || 0; break; | ||||
| 				case '@': | ||||
| 					// NOTE: dBASE specs appear to be incorrect
 | ||||
| 					out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); | ||||
| 					break; | ||||
| 				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break; | ||||
| 				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break; | ||||
| 				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break; | ||||
| @ -7276,7 +7297,7 @@ var SYLK = (function() { | ||||
| 					formats.push(rstr.slice(3).replace(/;;/g, ";")); | ||||
| 				break; | ||||
| 			case 'C': | ||||
| 			var C_seen_K = false, C_seen_X = false; | ||||
| 			var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1; | ||||
| 			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break; | ||||
| 				case 'Y': | ||||
| @ -7298,12 +7319,30 @@ var SYLK = (function() { | ||||
| 					C_seen_K = true; | ||||
| 					break; | ||||
| 				case 'E': | ||||
| 					C_seen_E = true; | ||||
| 					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C}); | ||||
| 					arr[R][C] = [arr[R][C], formula]; | ||||
| 					break; | ||||
| 				case 'S': | ||||
| 					C_seen_S = true; | ||||
| 					arr[R][C] = [arr[R][C], "S5S"]; | ||||
| 					break; | ||||
| 				case 'G': break; // unknown
 | ||||
| 				case 'R': _R = parseInt(record[rj].slice(1))-1; break; | ||||
| 				case 'C': _C = parseInt(record[rj].slice(1))-1; break; | ||||
| 				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr); | ||||
| 			} | ||||
| 			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; } | ||||
| 			if(C_seen_K) { | ||||
| 				if(arr[R][C] && arr[R][C].length == 2) arr[R][C][0] = val; | ||||
| 				else arr[R][C] = val; | ||||
| 				next_cell_format = null; | ||||
| 			} | ||||
| 			if(C_seen_S) { | ||||
| 				if(C_seen_E) throw new Error("SYLK shared formula cannot have own formula"); | ||||
| 				var shrbase = _R > -1 && arr[_R][_C]; | ||||
| 				if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base"); | ||||
| 				arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C}); | ||||
| 			} | ||||
| 			break; | ||||
| 			case 'F': | ||||
| 			var F_seen = 0; | ||||
| @ -7638,9 +7677,9 @@ var ETH = (function() { | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data, arr, R, C, o) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data); | ||||
| 		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data); | ||||
| 		else arr[R][C] = data; | ||||
| @ -7799,7 +7838,7 @@ var PRN = (function() { | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str)); | ||||
| 		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| @ -21027,7 +21066,10 @@ function readSync(data, opts) { | ||||
| 		case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break; | ||||
| 		case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break; | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break; | ||||
| 		case 0x49: | ||||
| 			if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet"); | ||||
| 			if(n[1] === 0x44) return read_wb_ID(d, o); | ||||
| 			break; | ||||
| 		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str); | ||||
|  | ||||
| @ -4809,7 +4809,9 @@ var dbf_codepage_map = { | ||||
| 	/*::[*/0x4D/*::]*/:   936,           /*::[*/0x4E/*::]*/:   949, | ||||
| 	/*::[*/0x4F/*::]*/:   950,           /*::[*/0x50/*::]*/:   874, | ||||
| 	/*::[*/0x57/*::]*/:  1252,           /*::[*/0x58/*::]*/:  1252, | ||||
| 	/*::[*/0x59/*::]*/:  1252, | ||||
| 	/*::[*/0x59/*::]*/:  1252,           /*::[*/0x6C/*::]*/:   863, | ||||
| 	/*::[*/0x86/*::]*/:   737,           /*::[*/0x87/*::]*/:   852, | ||||
| 	/*::[*/0x88/*::]*/:   857,           /*::[*/0xCC/*::]*/:  1257, | ||||
| 
 | ||||
| 	/*::[*/0xFF/*::]*/: 16969 | ||||
| }; | ||||
| @ -4833,7 +4835,6 @@ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; | ||||
| /* TODO: find an actual specification */ | ||||
| function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 	var out/*:AOA*/ = []; | ||||
| 	/* TODO: browser based */ | ||||
| 	var d/*:Block*/ = (new_raw_buf(1)/*:any*/); | ||||
| 	switch(opts.type) { | ||||
| 		case 'base64': d = s2a(Base64.decode(buf)); break; | ||||
| @ -4842,44 +4843,55 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		case 'array': d = buf; break; | ||||
| 	} | ||||
| 	prep_blob(d, 0); | ||||
| 
 | ||||
| 	/* header */ | ||||
| 	var ft = d.read_shift(1); | ||||
| 	var memo = false; | ||||
| 	var memo = !!(ft & 0x88); | ||||
| 	var vfp = false, l7 = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| 		case 0x8B: memo = true; break; | ||||
| 		case 0x8C: memo = true; l7 = true; break; | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		case 0x02: break; // dBASE II
 | ||||
| 		case 0x03: break; // dBASE III
 | ||||
| 		case 0x30: vfp = true; memo = true; break; // VFP
 | ||||
| 		case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
 | ||||
| 		// 0x43 dBASE IV SQL table files
 | ||||
| 		// 0x63 dBASE IV SQL system files
 | ||||
| 		case 0x83: break; // dBASE III with memo
 | ||||
| 		case 0x8B: break; // dBASE IV with memo
 | ||||
| 		case 0x8C: l7 = true; break; // dBASE Level 7 with memo
 | ||||
| 		// case 0xCB dBASE IV SQL table files with memo
 | ||||
| 		case 0xF5: break; // FoxPro 2.x with memo
 | ||||
| 		// case 0xFB FoxBASE
 | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var /*filedate = new Date(),*/ nrow = 0, fpos = 0; | ||||
| 
 | ||||
| 	var nrow = 0, fpos = 0x0209; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3; | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); if(nrow > 1048576) nrow = 1e6; | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
 | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(nrow > 1048576) nrow = 1e6; | ||||
| 
 | ||||
| 	var /*flags = 0,*/ current_cp = 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	/*flags = */d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); // header length
 | ||||
| 	var rlen = d.read_shift(2); // record length
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 	var /*flags = 0,*/ current_cp = opts.codepage || 1252; | ||||
| 	if(ft != 0x02) { // 20 reserved bytes
 | ||||
| 		d.l+=16; | ||||
| 		/*flags = */d.read_shift(1); | ||||
| 		//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 		/* codepage present in FoxPro and dBASE Level 7 */ | ||||
| 		if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 		d.l+=1; | ||||
| 
 | ||||
| 		d.l+=2; | ||||
| 	} | ||||
| 	if(l7) d.l += 36; | ||||
| 	if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
 | ||||
| 
 | ||||
| /*:: type DBFField = { name:string; len:number; type:string; } */ | ||||
| 	var fields/*:Array<DBFField>*/ = [], field/*:DBFField*/ = ({}/*:any*/); | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11; | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 	var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0)))); | ||||
| 	var ww = l7 ? 32 : 11; | ||||
| 	while(d.l < hend && d[d.l] != 0x0d) { | ||||
| 		field = ({}/*:any*/); | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += ww; | ||||
| @ -4891,42 +4903,45 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		if(ft != 0x02) d.l += l7 ? 13 : 14; | ||||
| 		switch(field.type) { | ||||
| 			case 'B': // VFP Double
 | ||||
| 			case 'B': // Double (VFP) / Binary (dBASE L7)
 | ||||
| 				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'G': // General
 | ||||
| 			case 'P': // Picture
 | ||||
| 			case 'G': // General (FoxPro and dBASE L7)
 | ||||
| 			case 'P': // Picture (FoxPro and dBASE L7)
 | ||||
| 				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'C': // character
 | ||||
| 			case 'D': // date
 | ||||
| 			case 'F': // floating point
 | ||||
| 			case 'I': // long
 | ||||
| 			case 'L': // boolean
 | ||||
| 			case 'M': // memo
 | ||||
| 			case 'N': // number
 | ||||
| 			case 'O': // double
 | ||||
| 			case 'T': // datetime
 | ||||
| 			case 'Y': // currency
 | ||||
| 			case '0': // VFP _NullFlags
 | ||||
| 			case '@': // timestamp
 | ||||
| 			case '+': // autoincrement
 | ||||
| 			case '+': // Autoincrement (dBASE L7 only)
 | ||||
| 			case '0': // _NullFlags (VFP only)
 | ||||
| 			case '@': // Timestamp (dBASE L7 only)
 | ||||
| 			case 'C': // Character (dBASE II)
 | ||||
| 			case 'D': // Date (dBASE III)
 | ||||
| 			case 'F': // Float (dBASE IV)
 | ||||
| 			case 'I': // Long (VFP and dBASE L7)
 | ||||
| 			case 'L': // Logical (dBASE II)
 | ||||
| 			case 'M': // Memo (dBASE III)
 | ||||
| 			case 'N': // Number (dBASE II)
 | ||||
| 			case 'O': // Double (dBASE L7 only)
 | ||||
| 			case 'T': // Datetime (VFP only)
 | ||||
| 			case 'Y': // Currency (VFP only)
 | ||||
| 				break; | ||||
| 			default: throw new Error('Unknown Field Type: ' + field.type); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 
 | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| 	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name; | ||||
| 	while(nrow-- > 0) { | ||||
| 		if(d[d.l] === 0x2A) { d.l+=rlen; continue; } | ||||
| 		if(d[d.l] === 0x2A) { | ||||
| 			// TODO: record marked as deleted -- create a hidden row?
 | ||||
| 			d.l+=rlen; | ||||
| 			continue; | ||||
| 		} | ||||
| 		++d.l; | ||||
| 		out[++R] = []; C = 0; | ||||
| 		for(C = 0; C != fields.length; ++C) { | ||||
| @ -4935,8 +4950,8 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 			var s = cptable.utils.decode(current_cp, dd); | ||||
| 			switch(fields[C].type) { | ||||
| 				case 'C': | ||||
| 					out[R][C] = cptable.utils.decode(current_cp, dd); | ||||
| 					out[R][C] = out[R][C].trim(); | ||||
| 					// NOTE: it is conventional to write '  /  /  ' for empty dates
 | ||||
| 					if(s.trim().length) out[R][C] = s.replace(/\s+$/,""); | ||||
| 					break; | ||||
| 				case 'D': | ||||
| 					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8)); | ||||
| @ -4944,18 +4959,24 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { | ||||
| 					break; | ||||
| 				case 'F': out[R][C] = parseFloat(s.trim()); break; | ||||
| 				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break; | ||||
| 				case 'L': switch(s.toUpperCase()) { | ||||
| 				case 'L': switch(s.trim().toUpperCase()) { | ||||
| 					case 'Y': case 'T': out[R][C] = true; break; | ||||
| 					case 'N': case 'F': out[R][C] = false; break; | ||||
| 					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */ | ||||
| 					case '': case '?': break; | ||||
| 					default: throw new Error("DBF Unrecognized L:|" + s + "|"); | ||||
| 					} break; | ||||
| 				case 'M': /* TODO: handle memo files */ | ||||
| 					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16)); | ||||
| 					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4)); | ||||
| 					break; | ||||
| 				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break; | ||||
| 				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break; | ||||
| 				case 'N': | ||||
| 					s = s.replace(/\u0000/g,"").trim(); | ||||
| 					// NOTE: dBASE II interprets "  .  " as 0
 | ||||
| 					if(s && s != ".") out[R][C] = +s || 0; break; | ||||
| 				case '@': | ||||
| 					// NOTE: dBASE specs appear to be incorrect
 | ||||
| 					out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); | ||||
| 					break; | ||||
| 				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break; | ||||
| 				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break; | ||||
| 				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break; | ||||
| @ -5148,7 +5169,7 @@ var SYLK = (function() { | ||||
| 					formats.push(rstr.slice(3).replace(/;;/g, ";")); | ||||
| 				break; | ||||
| 			case 'C': | ||||
| 			var C_seen_K = false, C_seen_X = false; | ||||
| 			var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1; | ||||
| 			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break; | ||||
| 				case 'Y': | ||||
| @ -5170,12 +5191,30 @@ var SYLK = (function() { | ||||
| 					C_seen_K = true; | ||||
| 					break; | ||||
| 				case 'E': | ||||
| 					C_seen_E = true; | ||||
| 					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C}); | ||||
| 					arr[R][C] = [arr[R][C], formula]; | ||||
| 					break; | ||||
| 				case 'S': | ||||
| 					C_seen_S = true; | ||||
| 					arr[R][C] = [arr[R][C], "S5S"]; | ||||
| 					break; | ||||
| 				case 'G': break; // unknown
 | ||||
| 				case 'R': _R = parseInt(record[rj].slice(1))-1; break; | ||||
| 				case 'C': _C = parseInt(record[rj].slice(1))-1; break; | ||||
| 				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr); | ||||
| 			} | ||||
| 			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; } | ||||
| 			if(C_seen_K) { | ||||
| 				if(arr[R][C] && arr[R][C].length == 2) arr[R][C][0] = val; | ||||
| 				else arr[R][C] = val; | ||||
| 				next_cell_format = null; | ||||
| 			} | ||||
| 			if(C_seen_S) { | ||||
| 				if(C_seen_E) throw new Error("SYLK shared formula cannot have own formula"); | ||||
| 				var shrbase = _R > -1 && arr[_R][_C]; | ||||
| 				if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base"); | ||||
| 				arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C}); | ||||
| 			} | ||||
| 			break; | ||||
| 			case 'F': | ||||
| 			var F_seen = 0; | ||||
| @ -5510,9 +5549,9 @@ var ETH = (function() { | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data); | ||||
| 		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data); | ||||
| 		else arr[R][C] = data; | ||||
| @ -5671,7 +5710,7 @@ var PRN = (function() { | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str)); | ||||
| 		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| @ -10040,7 +10079,10 @@ function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { | ||||
| 		case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break; | ||||
| 		case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break; | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break; | ||||
| 		case 0x49: | ||||
| 			if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet"); | ||||
| 			if(n[1] === 0x44) return read_wb_ID(d, o); | ||||
| 			break; | ||||
| 		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str); | ||||
|  | ||||
							
								
								
									
										162
									
								
								xlsx.mini.js
									
									
									
									
									
								
							
							
								
								
								
								
								
									
									
								
							
						
						
									
										162
									
								
								xlsx.mini.js
									
									
									
									
									
								
							| @ -4719,7 +4719,9 @@ var dbf_codepage_map = { | ||||
| 0x4D:   936,           0x4E:   949, | ||||
| 0x4F:   950,           0x50:   874, | ||||
| 0x57:  1252,           0x58:  1252, | ||||
| 0x59:  1252, | ||||
| 0x59:  1252,           0x6C:   863, | ||||
| 0x86:   737,           0x87:   852, | ||||
| 0x88:   857,           0xCC:  1257, | ||||
| 
 | ||||
| 0xFF: 16969 | ||||
| }; | ||||
| @ -4743,7 +4745,6 @@ var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5]; | ||||
| /* TODO: find an actual specification */ | ||||
| function dbf_to_aoa(buf, opts) { | ||||
| 	var out = []; | ||||
| 	/* TODO: browser based */ | ||||
| 	var d = (new_raw_buf(1)); | ||||
| 	switch(opts.type) { | ||||
| 		case 'base64': d = s2a(Base64.decode(buf)); break; | ||||
| @ -4752,43 +4753,54 @@ function dbf_to_aoa(buf, opts) { | ||||
| 		case 'array': d = buf; break; | ||||
| 	} | ||||
| 	prep_blob(d, 0); | ||||
| 
 | ||||
| 	/* header */ | ||||
| 	var ft = d.read_shift(1); | ||||
| 	var memo = false; | ||||
| 	var memo = !!(ft & 0x88); | ||||
| 	var vfp = false, l7 = false; | ||||
| 	switch(ft) { | ||||
| 		case 0x02: case 0x03: break; | ||||
| 		case 0x30: vfp = true; memo = true; break; | ||||
| 		case 0x31: vfp = true; break; | ||||
| 		case 0x83: memo = true; break; | ||||
| 		case 0x8B: memo = true; break; | ||||
| 		case 0x8C: memo = true; l7 = true; break; | ||||
| 		case 0xF5: memo = true; break; | ||||
| 		case 0x02: break; // dBASE II
 | ||||
| 		case 0x03: break; // dBASE III
 | ||||
| 		case 0x30: vfp = true; memo = true; break; // VFP
 | ||||
| 		case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
 | ||||
| 		// 0x43 dBASE IV SQL table files
 | ||||
| 		// 0x63 dBASE IV SQL system files
 | ||||
| 		case 0x83: break; // dBASE III with memo
 | ||||
| 		case 0x8B: break; // dBASE IV with memo
 | ||||
| 		case 0x8C: l7 = true; break; // dBASE Level 7 with memo
 | ||||
| 		// case 0xCB dBASE IV SQL table files with memo
 | ||||
| 		case 0xF5: break; // FoxPro 2.x with memo
 | ||||
| 		// case 0xFB FoxBASE
 | ||||
| 		default: throw new Error("DBF Unsupported Version: " + ft.toString(16)); | ||||
| 	} | ||||
| 	var /*filedate = new Date(),*/ nrow = 0, fpos = 0; | ||||
| 
 | ||||
| 	var nrow = 0, fpos = 0x0209; | ||||
| 	if(ft == 0x02) nrow = d.read_shift(2); | ||||
| 	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3; | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); if(nrow > 1048576) nrow = 1e6; | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); | ||||
| 	var rlen = d.read_shift(2); | ||||
| 	d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
 | ||||
| 	if(ft != 0x02) nrow = d.read_shift(4); | ||||
| 	if(nrow > 1048576) nrow = 1e6; | ||||
| 
 | ||||
| 	var /*flags = 0,*/ current_cp = 1252; | ||||
| 	if(ft != 0x02) { | ||||
| 	d.l+=16; | ||||
| 	/*flags = */d.read_shift(1); | ||||
| 	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 	if(ft != 0x02) fpos = d.read_shift(2); // header length
 | ||||
| 	var rlen = d.read_shift(2); // record length
 | ||||
| 
 | ||||
| 	/* codepage present in FoxPro */ | ||||
| 	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 	d.l+=1; | ||||
| 	var /*flags = 0,*/ current_cp = opts.codepage || 1252; | ||||
| 	if(ft != 0x02) { // 20 reserved bytes
 | ||||
| 		d.l+=16; | ||||
| 		/*flags = */d.read_shift(1); | ||||
| 		//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
 | ||||
| 
 | ||||
| 	d.l+=2; | ||||
| 		/* codepage present in FoxPro and dBASE Level 7 */ | ||||
| 		if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]]; | ||||
| 		d.l+=1; | ||||
| 
 | ||||
| 		d.l+=2; | ||||
| 	} | ||||
| 	if(l7) d.l += 36; | ||||
| 	if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
 | ||||
| 
 | ||||
| var fields = [], field = ({}); | ||||
| 	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11; | ||||
| 	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { | ||||
| 	var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0)))); | ||||
| 	var ww = l7 ? 32 : 11; | ||||
| 	while(d.l < hend && d[d.l] != 0x0d) { | ||||
| 		field = ({}); | ||||
| 		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,""); | ||||
| 		d.l += ww; | ||||
| @ -4800,42 +4812,45 @@ var fields = [], field = ({}); | ||||
| 		if(field.name.length) fields.push(field); | ||||
| 		if(ft != 0x02) d.l += l7 ? 13 : 14; | ||||
| 		switch(field.type) { | ||||
| 			case 'B': // VFP Double
 | ||||
| 			case 'B': // Double (VFP) / Binary (dBASE L7)
 | ||||
| 				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'G': // General
 | ||||
| 			case 'P': // Picture
 | ||||
| 			case 'G': // General (FoxPro and dBASE L7)
 | ||||
| 			case 'P': // Picture (FoxPro and dBASE L7)
 | ||||
| 				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type); | ||||
| 				break; | ||||
| 			case 'C': // character
 | ||||
| 			case 'D': // date
 | ||||
| 			case 'F': // floating point
 | ||||
| 			case 'I': // long
 | ||||
| 			case 'L': // boolean
 | ||||
| 			case 'M': // memo
 | ||||
| 			case 'N': // number
 | ||||
| 			case 'O': // double
 | ||||
| 			case 'T': // datetime
 | ||||
| 			case 'Y': // currency
 | ||||
| 			case '0': // VFP _NullFlags
 | ||||
| 			case '@': // timestamp
 | ||||
| 			case '+': // autoincrement
 | ||||
| 			case '+': // Autoincrement (dBASE L7 only)
 | ||||
| 			case '0': // _NullFlags (VFP only)
 | ||||
| 			case '@': // Timestamp (dBASE L7 only)
 | ||||
| 			case 'C': // Character (dBASE II)
 | ||||
| 			case 'D': // Date (dBASE III)
 | ||||
| 			case 'F': // Float (dBASE IV)
 | ||||
| 			case 'I': // Long (VFP and dBASE L7)
 | ||||
| 			case 'L': // Logical (dBASE II)
 | ||||
| 			case 'M': // Memo (dBASE III)
 | ||||
| 			case 'N': // Number (dBASE II)
 | ||||
| 			case 'O': // Double (dBASE L7 only)
 | ||||
| 			case 'T': // Datetime (VFP only)
 | ||||
| 			case 'Y': // Currency (VFP only)
 | ||||
| 				break; | ||||
| 			default: throw new Error('Unknown Field Type: ' + field.type); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	if(d[d.l] !== 0x0D) d.l = fpos-1; | ||||
| 	else if(ft == 0x02) d.l = 0x209; | ||||
| 	if(ft != 0x02) { | ||||
| 		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 		d.l = fpos; | ||||
| 	} | ||||
| 	if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]); | ||||
| 	d.l = fpos; | ||||
| 
 | ||||
| 	/* data */ | ||||
| 	var R = 0, C = 0; | ||||
| 	out[0] = []; | ||||
| 	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name; | ||||
| 	while(nrow-- > 0) { | ||||
| 		if(d[d.l] === 0x2A) { d.l+=rlen; continue; } | ||||
| 		if(d[d.l] === 0x2A) { | ||||
| 			// TODO: record marked as deleted -- create a hidden row?
 | ||||
| 			d.l+=rlen; | ||||
| 			continue; | ||||
| 		} | ||||
| 		++d.l; | ||||
| 		out[++R] = []; C = 0; | ||||
| 		for(C = 0; C != fields.length; ++C) { | ||||
| @ -4844,8 +4859,8 @@ var fields = [], field = ({}); | ||||
| 			var s = cptable.utils.decode(current_cp, dd); | ||||
| 			switch(fields[C].type) { | ||||
| 				case 'C': | ||||
| 					out[R][C] = cptable.utils.decode(current_cp, dd); | ||||
| 					out[R][C] = out[R][C].trim(); | ||||
| 					// NOTE: it is conventional to write '  /  /  ' for empty dates
 | ||||
| 					if(s.trim().length) out[R][C] = s.replace(/\s+$/,""); | ||||
| 					break; | ||||
| 				case 'D': | ||||
| 					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8)); | ||||
| @ -4853,18 +4868,24 @@ var fields = [], field = ({}); | ||||
| 					break; | ||||
| 				case 'F': out[R][C] = parseFloat(s.trim()); break; | ||||
| 				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break; | ||||
| 				case 'L': switch(s.toUpperCase()) { | ||||
| 				case 'L': switch(s.trim().toUpperCase()) { | ||||
| 					case 'Y': case 'T': out[R][C] = true; break; | ||||
| 					case 'N': case 'F': out[R][C] = false; break; | ||||
| 					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */ | ||||
| 					case '': case '?': break; | ||||
| 					default: throw new Error("DBF Unrecognized L:|" + s + "|"); | ||||
| 					} break; | ||||
| 				case 'M': /* TODO: handle memo files */ | ||||
| 					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16)); | ||||
| 					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4)); | ||||
| 					break; | ||||
| 				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break; | ||||
| 				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break; | ||||
| 				case 'N': | ||||
| 					s = s.replace(/\u0000/g,"").trim(); | ||||
| 					// NOTE: dBASE II interprets "  .  " as 0
 | ||||
| 					if(s && s != ".") out[R][C] = +s || 0; break; | ||||
| 				case '@': | ||||
| 					// NOTE: dBASE specs appear to be incorrect
 | ||||
| 					out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); | ||||
| 					break; | ||||
| 				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break; | ||||
| 				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break; | ||||
| 				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break; | ||||
| @ -5057,7 +5078,7 @@ var SYLK = (function() { | ||||
| 					formats.push(rstr.slice(3).replace(/;;/g, ";")); | ||||
| 				break; | ||||
| 			case 'C': | ||||
| 			var C_seen_K = false, C_seen_X = false; | ||||
| 			var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1; | ||||
| 			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) { | ||||
| 				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break; | ||||
| 				case 'Y': | ||||
| @ -5079,12 +5100,30 @@ var SYLK = (function() { | ||||
| 					C_seen_K = true; | ||||
| 					break; | ||||
| 				case 'E': | ||||
| 					C_seen_E = true; | ||||
| 					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C}); | ||||
| 					arr[R][C] = [arr[R][C], formula]; | ||||
| 					break; | ||||
| 				case 'S': | ||||
| 					C_seen_S = true; | ||||
| 					arr[R][C] = [arr[R][C], "S5S"]; | ||||
| 					break; | ||||
| 				case 'G': break; // unknown
 | ||||
| 				case 'R': _R = parseInt(record[rj].slice(1))-1; break; | ||||
| 				case 'C': _C = parseInt(record[rj].slice(1))-1; break; | ||||
| 				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr); | ||||
| 			} | ||||
| 			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; } | ||||
| 			if(C_seen_K) { | ||||
| 				if(arr[R][C] && arr[R][C].length == 2) arr[R][C][0] = val; | ||||
| 				else arr[R][C] = val; | ||||
| 				next_cell_format = null; | ||||
| 			} | ||||
| 			if(C_seen_S) { | ||||
| 				if(C_seen_E) throw new Error("SYLK shared formula cannot have own formula"); | ||||
| 				var shrbase = _R > -1 && arr[_R][_C]; | ||||
| 				if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base"); | ||||
| 				arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C}); | ||||
| 			} | ||||
| 			break; | ||||
| 			case 'F': | ||||
| 			var F_seen = 0; | ||||
| @ -5419,9 +5458,9 @@ var ETH = (function() { | ||||
| var PRN = (function() { | ||||
| 	function set_text_arr(data, arr, R, C, o) { | ||||
| 		if(o.raw) arr[R][C] = data; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(data === 'TRUE') arr[R][C] = true; | ||||
| 		else if(data === 'FALSE') arr[R][C] = false; | ||||
| 		else if(data === ""){/* empty */} | ||||
| 		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data); | ||||
| 		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data); | ||||
| 		else arr[R][C] = data; | ||||
| @ -5580,7 +5619,7 @@ var PRN = (function() { | ||||
| 			default: throw new Error("Unrecognized type " + opts.type); | ||||
| 		} | ||||
| 		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str)); | ||||
| 		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str)); | ||||
| 		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts); | ||||
| 		return prn_to_sheet_str(str, opts); | ||||
| 	} | ||||
| @ -9941,7 +9980,10 @@ function readSync(data, opts) { | ||||
| 		case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break; | ||||
| 		case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break; | ||||
| 		case 0x3C: return parse_xlml(d, o); | ||||
| 		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break; | ||||
| 		case 0x49: | ||||
| 			if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet"); | ||||
| 			if(n[1] === 0x44) return read_wb_ID(d, o); | ||||
| 			break; | ||||
| 		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break; | ||||
| 		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str); | ||||
| 		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str); | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user