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