GitHub Access Token became invalid

It seems like the GitHub access token used for retrieving details about this repository from GitHub became invalid. This might prevent certain types of inspections from being run (in particular, everything related to pull requests).
Please ask an admin of your repository to re-new the access token on this website.

Code Duplication    Length = 20242-20369 lines in 2 locations

third-party/js-xlsx/js-xlsx-0.13.5/xlsx.flow.js 1 location

@@ 5-20373 (lines=20369) @@
2
/* vim: set ts=2: */
3
/*exported XLSX */
4
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
5
var XLSX = {};
6
function make_xlsx_lib(XLSX){
7
XLSX.version = '0.13.5';
8
var current_codepage = 1200, current_ansi = 1252;
9
/*:: declare var cptable:any; */
10
/*global cptable:true, window */
11
if(typeof module !== "undefined" && typeof require !== 'undefined') {
12
	if(typeof cptable === 'undefined') {
13
		if(typeof global !== 'undefined') global.cptable = require('./dist/cpexcel.js');
14
		else if(typeof window !== 'undefined') window.cptable = require('./dist/cpexcel.js');
15
	}
16
}
17
18
var VALID_ANSI = [ 874, 932, 936, 949, 950 ];
19
for(var i = 0; i <= 8; ++i) VALID_ANSI.push(1250 + i);
20
/* ECMA-376 Part I 18.4.1 charset to codepage mapping */
21
var CS2CP = ({
22
	/*::[*/0/*::]*/:    1252, /* ANSI */
23
	/*::[*/1/*::]*/:   65001, /* DEFAULT */
24
	/*::[*/2/*::]*/:   65001, /* SYMBOL */
25
	/*::[*/77/*::]*/:  10000, /* MAC */
26
	/*::[*/128/*::]*/:   932, /* SHIFTJIS */
27
	/*::[*/129/*::]*/:   949, /* HANGUL */
28
	/*::[*/130/*::]*/:  1361, /* JOHAB */
29
	/*::[*/134/*::]*/:   936, /* GB2312 */
30
	/*::[*/136/*::]*/:   950, /* CHINESEBIG5 */
31
	/*::[*/161/*::]*/:  1253, /* GREEK */
32
	/*::[*/162/*::]*/:  1254, /* TURKISH */
33
	/*::[*/163/*::]*/:  1258, /* VIETNAMESE */
34
	/*::[*/177/*::]*/:  1255, /* HEBREW */
35
	/*::[*/178/*::]*/:  1256, /* ARABIC */
36
	/*::[*/186/*::]*/:  1257, /* BALTIC */
37
	/*::[*/204/*::]*/:  1251, /* RUSSIAN */
38
	/*::[*/222/*::]*/:   874, /* THAI */
39
	/*::[*/238/*::]*/:  1250, /* EASTEUROPE */
40
	/*::[*/255/*::]*/:  1252, /* OEM */
41
	/*::[*/69/*::]*/:   6969  /* MISC */
42
}/*:any*/);
43
44
var set_ansi = function(cp/*:number*/) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; };
45
function reset_ansi() { set_ansi(1252); }
46
47
var set_cp = function(cp/*:number*/) { current_codepage = cp; set_ansi(cp); };
48
function reset_cp() { set_cp(1200); reset_ansi(); }
49
50
function char_codes(data/*:string*/)/*:Array<number>*/ { var o/*:Array<number>*/ = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
51
52
function utf16leread(data/*:string*/)/*:string*/ {
53
	var o/*:Array<string>*/ = [];
54
	for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8));
55
	return o.join("");
56
}
57
function utf16beread(data/*:string*/)/*:string*/ {
58
	var o/*:Array<string>*/ = [];
59
	for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8));
60
	return o.join("");
61
}
62
63
var debom = function(data/*:string*/)/*:string*/ {
64
	var c1 = data.charCodeAt(0), c2 = data.charCodeAt(1);
65
	if(c1 == 0xFF && c2 == 0xFE) return utf16leread(data.slice(2));
66
	if(c1 == 0xFE && c2 == 0xFF) return utf16beread(data.slice(2));
67
	if(c1 == 0xFEFF) return data.slice(1);
68
	return data;
69
};
70
71
var _getchar = function _gc1(x/*:number*/)/*:string*/ { return String.fromCharCode(x); };
72
if(typeof cptable !== 'undefined') {
73
	set_cp = function(cp/*:number*/) { current_codepage = cp; };
74
	debom = function(data/*:string*/) {
75
		if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.slice(2))); }
76
		return data;
77
	};
78
	_getchar = function _gc2(x/*:number*/)/*:string*/ {
79
		if(current_codepage === 1200) return String.fromCharCode(x);
80
		return cptable.utils.decode(current_codepage, [x&255,x>>8])[0];
81
	};
82
}
83
var DENSE = null;
84
var DIF_XL = true;
85
var Base64 = (function make_b64(){
86
	var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
87
	return {
88
		encode: function(input/*:string*/)/*:string*/ {
89
			var o = "";
90
			var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
91
			for(var i = 0; i < input.length; ) {
92
				c1 = input.charCodeAt(i++);
93
				e1 = (c1 >> 2);
94
95
				c2 = input.charCodeAt(i++);
96
				e2 = ((c1 & 3) << 4) | (c2 >> 4);
97
98
				c3 = input.charCodeAt(i++);
99
				e3 = ((c2 & 15) << 2) | (c3 >> 6);
100
				e4 = (c3 & 63);
101
				if (isNaN(c2)) { e3 = e4 = 64; }
102
				else if (isNaN(c3)) { e4 = 64; }
103
				o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
104
			}
105
			return o;
106
		},
107
		decode: function b64_decode(input/*:string*/)/*:string*/ {
108
			var o = "";
109
			var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
110
			input = input.replace(/[^\w\+\/\=]/g, "");
111
			for(var i = 0; i < input.length;) {
112
				e1 = map.indexOf(input.charAt(i++));
113
				e2 = map.indexOf(input.charAt(i++));
114
				c1 = (e1 << 2) | (e2 >> 4);
115
				o += String.fromCharCode(c1);
116
117
				e3 = map.indexOf(input.charAt(i++));
118
				c2 = ((e2 & 15) << 4) | (e3 >> 2);
119
				if (e3 !== 64) { o += String.fromCharCode(c2); }
120
121
				e4 = map.indexOf(input.charAt(i++));
122
				c3 = ((e3 & 3) << 6) | e4;
123
				if (e4 !== 64) { o += String.fromCharCode(c3); }
124
			}
125
			return o;
126
		}
127
	};
128
})();
129
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
130
131
var Buffer_from = /*::(*/function(){}/*:: :any)*/;
132
133
if(typeof Buffer !== 'undefined') {
134
	var nbfs = !Buffer.from;
135
	if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
136
	Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
137
	// $FlowIgnore
138
	if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
139
}
140
141
function new_raw_buf(len/*:number*/) {
142
	/* jshint -W056 */
143
	return has_buf ? Buffer.alloc(len) : new Array(len);
144
	/* jshint +W056 */
145
}
146
147
var s2a = function s2a(s/*:string*/)/*:any*/ {
148
	// $FlowIgnore
149
	if(has_buf) return Buffer_from(s, "binary");
150
	return s.split("").map(function(x/*:string*/)/*:number*/{ return x.charCodeAt(0) & 0xff; });
151
};
152
153
function s2ab(s/*:string*/)/*:any*/ {
154
	if(typeof ArrayBuffer === 'undefined') return s2a(s);
155
	var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
156
	for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
157
	return buf;
158
}
159
160
function a2s(data/*:any*/)/*:string*/ {
161
	if(Array.isArray(data)) return data.map(_chr).join("");
162
	var o/*:Array<string>*/ = []; for(var i = 0; i < data.length; ++i) o[i] = _chr(data[i]); return o.join("");
163
}
164
165
function a2u(data/*:Array<number>*/)/*:Uint8Array*/ {
166
	if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
167
	return new Uint8Array(data);
168
}
169
170
function ab2a(data/*:ArrayBuffer|Uint8Array*/)/*:Array<number>*/ {
171
	if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
172
	if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
173
	/*:: if(data instanceof ArrayBuffer) throw new Error("unreachable"); */
174
	var o = new Array(data.length);
175
	for(var i = 0; i < data.length; ++i) o[i] = data[i];
176
	return o;
177
}
178
179
var bconcat = function(bufs) { return [].concat.apply([], bufs); };
180
181
var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
182
/*::
183
declare type Block = any;
184
declare type BufArray = {
185
	newblk(sz:number):Block;
186
	next(sz:number):Block;
187
	end():any;
188
	push(buf:Block):void;
189
};
190
191
type RecordHopperCB = {(d:any, Rn:string, RT:number):?boolean;};
192
193
type EvertType = {[string]:string};
194
type EvertNumType = {[string]:number};
195
type EvertArrType = {[string]:Array<string>};
196
197
type StringConv = {(string):string};
198
199
type WriteObjStrFactory = {from_sheet(ws:Worksheet, o:any, wb:?Workbook):string};
200
*/
201
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
202
/*jshint -W041 */
203
var SSF/*:SSFModule*/ = ({}/*:any*/);
204
var make_ssf = function make_ssf(SSF/*:SSFModule*/){
205
SSF.version = '0.10.2';
206
function _strrev(x/*:string*/)/*:string*/ { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
207
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
208
function pad0(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
209
function pad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
210
function rpad_(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
211
function pad0r1(v/*:any*/,d/*:number*/)/*:string*/{var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
212
function pad0r2(v/*:any*/,d/*:number*/)/*:string*/{var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
213
var p2_32 = Math.pow(2,32);
214
function pad0r(v/*:any*/,d/*:number*/)/*:string*/{if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
215
function isgeneral(s/*:string*/, i/*:?number*/)/*:boolean*/ { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
216
/*::
217
type SSF_write_num = {(type:string, fmt:string, val:number):string};
218
*/
219
var days/*:Array<Array<string> >*/ = [
220
	['Sun', 'Sunday'],
221
	['Mon', 'Monday'],
222
	['Tue', 'Tuesday'],
223
	['Wed', 'Wednesday'],
224
	['Thu', 'Thursday'],
225
	['Fri', 'Friday'],
226
	['Sat', 'Saturday']
227
];
228
var months/*:Array<Array<string> >*/ = [
229
	['J', 'Jan', 'January'],
230
	['F', 'Feb', 'February'],
231
	['M', 'Mar', 'March'],
232
	['A', 'Apr', 'April'],
233
	['M', 'May', 'May'],
234
	['J', 'Jun', 'June'],
235
	['J', 'Jul', 'July'],
236
	['A', 'Aug', 'August'],
237
	['S', 'Sep', 'September'],
238
	['O', 'Oct', 'October'],
239
	['N', 'Nov', 'November'],
240
	['D', 'Dec', 'December']
241
];
242
function init_table(t/*:any*/) {
243
	t[0]=  'General';
244
	t[1]=  '0';
245
	t[2]=  '0.00';
246
	t[3]=  '#,##0';
247
	t[4]=  '#,##0.00';
248
	t[9]=  '0%';
249
	t[10]= '0.00%';
250
	t[11]= '0.00E+00';
251
	t[12]= '# ?/?';
252
	t[13]= '# ??/??';
253
	t[14]= 'm/d/yy';
254
	t[15]= 'd-mmm-yy';
255
	t[16]= 'd-mmm';
256
	t[17]= 'mmm-yy';
257
	t[18]= 'h:mm AM/PM';
258
	t[19]= 'h:mm:ss AM/PM';
259
	t[20]= 'h:mm';
260
	t[21]= 'h:mm:ss';
261
	t[22]= 'm/d/yy h:mm';
262
	t[37]= '#,##0 ;(#,##0)';
263
	t[38]= '#,##0 ;[Red](#,##0)';
264
	t[39]= '#,##0.00;(#,##0.00)';
265
	t[40]= '#,##0.00;[Red](#,##0.00)';
266
	t[45]= 'mm:ss';
267
	t[46]= '[h]:mm:ss';
268
	t[47]= 'mmss.0';
269
	t[48]= '##0.0E+0';
270
	t[49]= '@';
271
	t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
272
	t[65535]= 'General';
273
}
274
275
var table_fmt = {};
276
init_table(table_fmt);
277
function frac(x/*:number*/, D/*:number*/, mixed/*:?boolean*/)/*:Array<number>*/ {
278
	var sgn = x < 0 ? -1 : 1;
279
	var B = x * sgn;
280
	var P_2 = 0, P_1 = 1, P = 0;
281
	var Q_2 = 1, Q_1 = 0, Q = 0;
282
	var A = Math.floor(B);
283
	while(Q_1 < D) {
284
		A = Math.floor(B);
285
		P = A * P_1 + P_2;
286
		Q = A * Q_1 + Q_2;
287
		if((B - A) < 0.00000005) break;
288
		B = 1 / (B - A);
289
		P_2 = P_1; P_1 = P;
290
		Q_2 = Q_1; Q_1 = Q;
291
	}
292
	if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
293
	if(!mixed) return [0, sgn * P, Q];
294
	var q = Math.floor(sgn * P/Q);
295
	return [q, sgn*P - q*Q, Q];
296
}
297
function parse_date_code(v/*:number*/,opts/*:?any*/,b2/*:?boolean*/) {
298
	if(v > 2958465 || v < 0) return null;
299
	var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
300
	var dout=[];
301
	var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
302
	if(Math.abs(out.u) < 1e-6) out.u = 0;
303
	if(opts && opts.date1904) date += 1462;
304
	if(out.u > 0.9999) {
305
		out.u = 0;
306
		if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
307
	}
308
	if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
309
	else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
310
	else {
311
		if(date > 60) --date;
312
		/* 1 = Jan 1 1900 in Gregorian */
313
		var d = new Date(1900, 0, 1);
314
		d.setDate(d.getDate() + date - 1);
315
		dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
316
		dow = d.getDay();
317
		if(date < 60) dow = (dow + 6) % 7;
318
		if(b2) dow = fix_hijri(d, dout);
319
	}
320
	out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
321
	out.S = time % 60; time = Math.floor(time / 60);
322
	out.M = time % 60; time = Math.floor(time / 60);
323
	out.H = time;
324
	out.q = dow;
325
	return out;
326
}
327
SSF.parse_date_code = parse_date_code;
328
var basedate = new Date(1899, 11, 31, 0, 0, 0);
329
var dnthresh = basedate.getTime();
330
var base1904 = new Date(1900, 2, 1, 0, 0, 0);
331
function datenum_local(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
332
	var epoch = v.getTime();
333
	if(date1904) epoch -= 1461*24*60*60*1000;
334
	else if(v >= base1904) epoch += 24*60*60*1000;
335
	return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
336
}
337
function general_fmt_int(v/*:number*/)/*:string*/ { return v.toString(10); }
338
SSF._general_int = general_fmt_int;
339
var general_fmt_num = (function make_general_fmt_num() {
340
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
341
function gfn2(v) {
342
	var w = (v<0?12:11);
343
	var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
344
	o = v.toPrecision(10); if(o.length <= w) return o;
345
	return v.toExponential(5);
346
}
347
function gfn3(v) {
348
	var o = v.toFixed(11).replace(gnr1,".$1");
349
	if(o.length > (v<0?12:11)) o = v.toPrecision(6);
350
	return o;
351
}
352
function gfn4(o) {
353
	for(var i = 0; i != o.length; ++i) if((o.charCodeAt(i) | 0x20) === 101) return o.replace(gnr4,".$1").replace(gnr5,"E").replace("e","E").replace(gnr6,"$10$2");
354
	return o;
355
}
356
function gfn5(o) {
357
	return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
358
}
359
return function general_fmt_num(v/*:number*/)/*:string*/ {
360
	var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
361
	if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
362
	else if(Math.abs(V) <= 9) o = gfn2(v);
363
	else if(V === 10) o = v.toFixed(10).substr(0,12);
364
	else o = gfn3(v);
365
	return gfn5(gfn4(o));
366
};})();
367
SSF._general_num = general_fmt_num;
368
function general_fmt(v/*:any*/, opts/*:any*/) {
369
	switch(typeof v) {
370
		case 'string': return v;
371
		case 'boolean': return v ? "TRUE" : "FALSE";
372
		case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
373
		case 'undefined': return "";
374
		case 'object':
375
			if(v == null) return "";
376
			if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
377
	}
378
	throw new Error("unsupported value in General format: " + v);
379
}
380
SSF._general = general_fmt;
381
function fix_hijri(/*::date, o*/) { return 0; }
382
/*jshint -W086 */
383
function write_date(type/*:number*/, fmt/*:string*/, val, ss0/*:?number*/)/*:string*/ {
384
	var o="", ss=0, tt=0, y = val.y, out, outl = 0;
385
	switch(type) {
386
		case 98: /* 'b' buddhist year */
387
			y = val.y + 543;
388
			/* falls through */
389
		case 121: /* 'y' year */
390
		switch(fmt.length) {
391
			case 1: case 2: out = y % 100; outl = 2; break;
392
			default: out = y % 10000; outl = 4; break;
393
		} break;
394
		case 109: /* 'm' month */
395
		switch(fmt.length) {
396
			case 1: case 2: out = val.m; outl = fmt.length; break;
397
			case 3: return months[val.m-1][1];
398
			case 5: return months[val.m-1][0];
399
			default: return months[val.m-1][2];
400
		} break;
401
		case 100: /* 'd' day */
402
		switch(fmt.length) {
403
			case 1: case 2: out = val.d; outl = fmt.length; break;
404
			case 3: return days[val.q][0];
405
			default: return days[val.q][1];
406
		} break;
407
		case 104: /* 'h' 12-hour */
408
		switch(fmt.length) {
409
			case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
410
			default: throw 'bad hour format: ' + fmt;
411
		} break;
412
		case 72: /* 'H' 24-hour */
413
		switch(fmt.length) {
414
			case 1: case 2: out = val.H; outl = fmt.length; break;
415
			default: throw 'bad hour format: ' + fmt;
416
		} break;
417
		case 77: /* 'M' minutes */
418
		switch(fmt.length) {
419
			case 1: case 2: out = val.M; outl = fmt.length; break;
420
			default: throw 'bad minute format: ' + fmt;
421
		} break;
422
		case 115: /* 's' seconds */
423
			if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
424
			if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
425
			/*::if(!ss0) ss0 = 0; */
426
			if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
427
			else tt = ss0 === 1 ? 10 : 1;
428
			ss = Math.round((tt)*(val.S + val.u));
429
			if(ss >= 60*tt) ss = 0;
430
			if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
431
			o = pad0(ss,2 + ss0);
432
			if(fmt === 'ss') return o.substr(0,2);
433
			return "." + o.substr(2,fmt.length-1);
434
		case 90: /* 'Z' absolute time */
435
		switch(fmt) {
436
			case '[h]': case '[hh]': out = val.D*24+val.H; break;
437
			case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
438
			case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
439
			default: throw 'bad abstime format: ' + fmt;
440
		} outl = fmt.length === 3 ? 1 : 2; break;
441
		case 101: /* 'e' era */
442
			out = y; outl = 1;
443
	}
444
	if(outl > 0) return pad0(out, outl); else return "";
445
}
446
/*jshint +W086 */
447
function commaify(s/*:string*/)/*:string*/ {
448
	var w = 3;
449
	if(s.length <= w) return s;
450
	var j = (s.length % w), o = s.substr(0,j);
451
	for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
452
	return o;
453
}
454
var write_num/*:SSF_write_num*/ = (function make_write_num(){
455
var pct1 = /%/g;
456
function write_num_pct(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
457
	var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
458
	return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
459
}
460
function write_num_cm(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
461
	var idx = fmt.length - 1;
462
	while(fmt.charCodeAt(idx-1) === 44) --idx;
463
	return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
464
}
465
function write_num_exp(fmt/*:string*/, val/*:number*/)/*:string*/{
466
	var o/*:string*/;
467
	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
468
	if(fmt.match(/^#+0.0E\+0$/)) {
469
		if(val == 0) return "0.0E+0";
470
		else if(val < 0) return "-" + write_num_exp(fmt, -val);
471
		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
472
		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
473
		if(ee < 0) ee += period;
474
		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
475
		if(o.indexOf("e") === -1) {
476
			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
477
			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
478
			else o += "E+" + (fakee - ee);
479
			while(o.substr(0,2) === "0.") {
480
				o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
481
				o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
482
			}
483
			o = o.replace(/\+-/,"-");
484
		}
485
		o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
486
	} else o = val.toExponential(idx);
487
	if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
488
	if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
489
	return o.replace("e","E");
490
}
491
var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
492
function write_num_f1(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
493
	var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
494
	var myn = (rr - base*den), myd = den;
495
	return sign + (base === 0 ? "" : ""+base) + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad_(myn,r[1].length) + r[2] + "/" + r[3] + pad0(myd,r[4].length));
496
}
497
function write_num_f2(r/*:Array<string>*/, aval/*:number*/, sign/*:string*/)/*:string*/ {
498
	return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
499
}
500
var dec1 = /^#*0*\.([0#]+)/;
501
var closeparen = /\).*[0#]/;
502
var phone = /\(###\) ###\\?-####/;
503
function hashq(str/*:string*/)/*:string*/ {
504
	var o = "", cc;
505
	for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
506
		case 35: break;
507
		case 63: o+= " "; break;
508
		case 48: o+= "0"; break;
509
		default: o+= String.fromCharCode(cc);
510
	}
511
	return o;
512
}
513
function rnd(val/*:number*/, d/*:number*/)/*:string*/ { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
514
function dec(val/*:number*/, d/*:number*/)/*:number*/ {
515
	if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
516
		return 0;
517
	}
518
	return Math.round((val-Math.floor(val))*Math.pow(10,d));
519
}
520
function carry(val/*:number*/, d/*:number*/)/*:number*/ {
521
	if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
522
		return 1;
523
	}
524
	return 0;
525
}
526
function flr(val/*:number*/)/*:string*/ { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
527
function write_num_flt(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
528
	if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
529
		var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
530
		if(val >= 0) return write_num_flt('n', ffmt, val);
531
		return '(' + write_num_flt('n', ffmt, -val) + ')';
532
	}
533
	if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
534
	if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
535
	if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
536
	if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
537
	var o;
538
	var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
539
	if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
540
	if(fmt.match(/^[#?]+$/)) {
541
		o = pad0r(val,0); if(o === "0") o = "";
542
		return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
543
	}
544
	if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
545
	if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
546
	if((r = fmt.match(dec1))) {
547
		o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(/*::(*/r/*::||[""])*/[1]).length-$1.length); });
548
		return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
549
	}
550
	fmt = fmt.replace(/^#+([0.])/, "$1");
551
	if((r = fmt.match(/^(0*)\.(#*)$/))) {
552
		return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
553
	}
554
	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
555
	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
556
		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
557
	}
558
	if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
559
	if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
560
		o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
561
		ri = 0;
562
		return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
563
	}
564
	if(fmt.match(phone)) {
565
		o = write_num_flt(type, "##########", val);
566
		return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
567
	}
568
	var oa = "";
569
	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
570
		ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
571
		ff = frac(aval, Math.pow(10,ri)-1, false);
572
		o = "" + sign;
573
		oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
574
		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
575
		o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
576
		oa = rpad_(ff[2],ri);
577
		if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
578
		o += oa;
579
		return o;
580
	}
581
	if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
582
		ri = Math.min(Math.max(r[1].length, r[4].length),7);
583
		ff = frac(aval, Math.pow(10,ri)-1, true);
584
		return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
585
	}
586
	if((r = fmt.match(/^[#0?]+$/))) {
587
		o = pad0r(val, 0);
588
		if(fmt.length <= o.length) return o;
589
		return hashq(fmt.substr(0,fmt.length-o.length)) + o;
590
	}
591
	if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
592
		o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
593
		ri = o.indexOf(".");
594
		var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
595
		return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
596
	}
597
	if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
598
		ri = dec(val, r[1].length);
599
		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
600
	}
601
	switch(fmt) {
602
		case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
603
		case "###,###":
604
		case "##,###":
605
		case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
606
		case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
607
		case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
608
		default:
609
	}
610
	throw new Error("unsupported format |" + fmt + "|");
611
}
612
function write_num_cm2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
613
	var idx = fmt.length - 1;
614
	while(fmt.charCodeAt(idx-1) === 44) --idx;
615
	return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
616
}
617
function write_num_pct2(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/{
618
	var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
619
	return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
620
}
621
function write_num_exp2(fmt/*:string*/, val/*:number*/)/*:string*/{
622
	var o/*:string*/;
623
	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
624
	if(fmt.match(/^#+0.0E\+0$/)) {
625
		if(val == 0) return "0.0E+0";
626
		else if(val < 0) return "-" + write_num_exp2(fmt, -val);
627
		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
628
		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
629
		if(ee < 0) ee += period;
630
		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
631
		if(!o.match(/[Ee]/)) {
632
			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
633
			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
634
			else o += "E+" + (fakee - ee);
635
			o = o.replace(/\+-/,"-");
636
		}
637
		o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
638
	} else o = val.toExponential(idx);
639
	if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
640
	if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
641
	return o.replace("e","E");
642
}
643
function write_num_int(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
644
	if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
645
		var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
646
		if(val >= 0) return write_num_int('n', ffmt, val);
647
		return '(' + write_num_int('n', ffmt, -val) + ')';
648
	}
649
	if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
650
	if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
651
	if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
652
	if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
653
	var o;
654
	var r/*:?Array<string>*/, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
655
	if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
656
	if(fmt.match(/^[#?]+$/)) {
657
		o = (""+val); if(val === 0) o = "";
658
		return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
659
	}
660
	if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
661
	if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
662
	if((r = fmt.match(dec1))) {
663
		/*:: if(!Array.isArray(r)) throw new Error("unreachable"); */
664
		o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
665
		o = o.replace(/\.(\d*)$/,function($$, $1) {
666
		/*:: if(!Array.isArray(r)) throw new Error("unreachable"); */
667
			return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
668
		return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
669
	}
670
	fmt = fmt.replace(/^#+([0.])/, "$1");
671
	if((r = fmt.match(/^(0*)\.(#*)$/))) {
672
		return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
673
	}
674
	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
675
	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
676
		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
677
	}
678
	if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
679
	if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
680
		o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
681
		ri = 0;
682
		return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
683
	}
684
	if(fmt.match(phone)) {
685
		o = write_num_int(type, "##########", val);
686
		return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
687
	}
688
	var oa = "";
689
	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
690
		ri = Math.min(/*::String(*/r[4]/*::)*/.length,7);
691
		ff = frac(aval, Math.pow(10,ri)-1, false);
692
		o = "" + sign;
693
		oa = write_num("n", /*::String(*/r[1]/*::)*/, ff[1]);
694
		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
695
		o += oa + /*::String(*/r[2]/*::)*/ + "/" + /*::String(*/r[3]/*::)*/;
696
		oa = rpad_(ff[2],ri);
697
		if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
698
		o += oa;
699
		return o;
700
	}
701
	if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
702
		ri = Math.min(Math.max(r[1].length, r[4].length),7);
703
		ff = frac(aval, Math.pow(10,ri)-1, true);
704
		return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
705
	}
706
	if((r = fmt.match(/^[#0?]+$/))) {
707
		o = "" + val;
708
		if(fmt.length <= o.length) return o;
709
		return hashq(fmt.substr(0,fmt.length-o.length)) + o;
710
	}
711
	if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
712
		o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
713
		ri = o.indexOf(".");
714
		var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
715
		return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
716
	}
717
	if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
718
		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
719
	}
720
	switch(fmt) {
721
		case "###,###":
722
		case "##,###":
723
		case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
724
		default:
725
			if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
726
	}
727
	throw new Error("unsupported format |" + fmt + "|");
728
}
729
return function write_num(type/*:string*/, fmt/*:string*/, val/*:number*/)/*:string*/ {
730
	return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
731
};})();
732
function split_fmt(fmt/*:string*/)/*:Array<string>*/ {
733
	var out/*:Array<string>*/ = [];
734
	var in_str = false/*, cc*/;
735
	for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
736
		case 34: /* '"' */
737
			in_str = !in_str; break;
738
		case 95: case 42: case 92: /* '_' '*' '\\' */
739
			++i; break;
740
		case 59: /* ';' */
741
			out[out.length] = fmt.substr(j,i-j);
742
			j = i+1;
743
	}
744
	out[out.length] = fmt.substr(j);
745
	if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
746
	return out;
747
}
748
SSF._split = split_fmt;
749
var abstime = /\[[HhMmSs]*\]/;
750
function fmt_is_date(fmt/*:string*/)/*:boolean*/ {
751
	var i = 0, /*cc = 0,*/ c = "", o = "";
752
	while(i < fmt.length) {
753
		switch((c = fmt.charAt(i))) {
754
			case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
755
			case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
756
			case '\\': i+=2; break;
757
			case '_': i+=2; break;
758
			case '@': ++i; break;
759
			case 'B': case 'b':
760
				if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
761
				/* falls through */
762
			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
763
				/* falls through */
764
			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
765
			case 'A': case 'a':
766
				if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
767
				if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
768
				++i; break;
769
			case '[':
770
				o = c;
771
				while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
772
				if(o.match(abstime)) return true;
773
				break;
774
			case '.':
775
				/* falls through */
776
			case '0': case '#':
777
				while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || (c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1))){/* empty */}
778
				break;
779
			case '?': while(fmt.charAt(++i) === c){/* empty */} break;
780
			case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
781
			case '(': case ')': ++i; break;
782
			case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
783
				while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
784
			case ' ': ++i; break;
785
			default: ++i; break;
786
		}
787
	}
788
	return false;
789
}
790
SSF.is_date = fmt_is_date;
791
function eval_fmt(fmt/*:string*/, v/*:any*/, opts/*:any*/, flen/*:number*/) {
792
	var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
793
	var hr='H';
794
	/* Tokenize */
795
	while(i < fmt.length) {
796
		switch((c = fmt.charAt(i))) {
797
			case 'G': /* General */
798
				if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
799
				out[out.length] = {t:'G', v:'General'}; i+=7; break;
800
			case '"': /* Literal text */
801
				for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
802
				out[out.length] = {t:'t', v:o}; ++i; break;
803
			case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
804
				out[out.length] = {t:t, v:w}; ++i; break;
805
			case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
806
			case '@': /* Text Placeholder */
807
				out[out.length] = {t:'T', v:v}; ++i; break;
808
			case 'B': case 'b':
809
				if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
810
					if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
811
					out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
812
				}
813
				/* falls through */
814
			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
815
				c = c.toLowerCase();
816
				/* falls through */
817
			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
818
				if(v < 0) return "";
819
				if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
820
				o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
821
				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
822
				if(c === 'h') c = hr;
823
				out[out.length] = {t:c, v:o}; lst = c; break;
824
			case 'A': case 'a':
825
				var q={t:c, v:c};
826
				if(dt==null) dt=parse_date_code(v, opts);
827
				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
828
				else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
829
				else { q.t = "t"; ++i; }
830
				if(dt==null && q.t === 'T') return "";
831
				out[out.length] = q; lst = c; break;
832
			case '[':
833
				o = c;
834
				while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
835
				if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
836
				if(o.match(abstime)) {
837
					if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
838
					out[out.length] = {t:'Z', v:o.toLowerCase()};
839
					lst = o.charAt(1);
840
				} else if(o.indexOf("$") > -1) {
841
					o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
842
					if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
843
				}
844
				break;
845
			/* Numbers */
846
			case '.':
847
				if(dt != null) {
848
					o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
849
					out[out.length] = {t:'s', v:o}; break;
850
				}
851
				/* falls through */
852
			case '0': case '#':
853
				o = c; while((++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) || (c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1)) o += c;
854
				out[out.length] = {t:'n', v:o}; break;
855
			case '?':
856
				o = c; while(fmt.charAt(++i) === c) o+=c;
857
				out[out.length] = {t:c, v:o}; lst = c; break;
858
			case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
859
			case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
860
			case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
861
				o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
862
				out[out.length] = {t:'D', v:o}; break;
863
			case ' ': out[out.length] = {t:c, v:c}; ++i; break;
864
			default:
865
				if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
866
				out[out.length] = {t:'t', v:c}; ++i; break;
867
		}
868
	}
869
	var bt = 0, ss0 = 0, ssm;
870
	for(i=out.length-1, lst='t'; i >= 0; --i) {
871
		switch(out[i].t) {
872
			case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
873
			case 's':
874
				if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
875
				if(bt < 3) bt = 3;
876
			/* falls through */
877
			case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
878
			case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
879
			case 'X': /*if(out[i].v === "B2");*/
880
				break;
881
			case 'Z':
882
				if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
883
				if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
884
				if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
885
		}
886
	}
887
	switch(bt) {
888
		case 0: break;
889
		case 1:
890
			/*::if(!dt) break;*/
891
			if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
892
			if(dt.S >=  60) { dt.S = 0; ++dt.M; }
893
			if(dt.M >=  60) { dt.M = 0; ++dt.H; }
894
			break;
895
		case 2:
896
			/*::if(!dt) break;*/
897
			if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
898
			if(dt.S >=  60) { dt.S = 0; ++dt.M; }
899
			break;
900
	}
901
	/* replace fields */
902
	var nstr = "", jj;
903
	for(i=0; i < out.length; ++i) {
904
		switch(out[i].t) {
905
			case 't': case 'T': case ' ': case 'D': break;
906
			case 'X': out[i].v = ""; out[i].t = ";"; break;
907
			case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
908
				/*::if(!dt) throw "unreachable"; */
909
				out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
910
				out[i].t = 't'; break;
911
			case 'n': case '(': case '?':
912
				jj = i+1;
913
				while(out[jj] != null && (
914
					(c=out[jj].t) === "?" || c === "D" ||
915
					((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
916
					(out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
917
					(c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
918
				)) {
919
					out[i].v += out[jj].v;
920
					out[jj] = {v:"", t:";"}; ++jj;
921
				}
922
				nstr += out[i].v;
923
				i = jj-1; break;
924
			case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
925
		}
926
	}
927
	var vv = "", myv, ostr;
928
	if(nstr.length > 0) {
929
		if(nstr.charCodeAt(0) == 40) /* '(' */ {
930
			myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
931
			ostr = write_num('(', nstr, myv);
932
		} else {
933
			myv = (v<0 && flen > 1 ? -v : v);
934
			ostr = write_num('n', nstr, myv);
935
			if(myv < 0 && out[0] && out[0].t == 't') {
936
				ostr = ostr.substr(1);
937
				out[0].v = "-" + out[0].v;
938
			}
939
		}
940
		jj=ostr.length-1;
941
		var decpt = out.length;
942
		for(i=0; i < out.length; ++i) if(out[i] != null && out[i].t != 't' && out[i].v.indexOf(".") > -1) { decpt = i; break; }
943
		var lasti=out.length;
944
		if(decpt === out.length && ostr.indexOf("E") === -1) {
945
			for(i=out.length-1; i>= 0;--i) {
946
				if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
947
				if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
948
				else if(jj < 0) out[i].v = "";
949
				else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
950
				out[i].t = 't';
951
				lasti = i;
952
			}
953
			if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
954
		}
955
		else if(decpt !== out.length && ostr.indexOf("E") === -1) {
956
			jj = ostr.indexOf(".")-1;
957
			for(i=decpt; i>= 0; --i) {
958
				if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
959
				j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
960
				vv = out[i].v.substr(j+1);
961
				for(; j>=0; --j) {
962
					if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
963
				}
964
				out[i].v = vv;
965
				out[i].t = 't';
966
				lasti = i;
967
			}
968
			if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
969
			jj = ostr.indexOf(".")+1;
970
			for(i=decpt; i<out.length; ++i) {
971
				if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
972
				j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
973
				vv = out[i].v.substr(0,j);
974
				for(; j<out[i].v.length; ++j) {
975
					if(jj<ostr.length) vv += ostr.charAt(jj++);
976
				}
977
				out[i].v = vv;
978
				out[i].t = 't';
979
				lasti = i;
980
			}
981
		}
982
	}
983
	for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
984
		myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
985
		out[i].v = write_num(out[i].t, out[i].v, myv);
986
		out[i].t = 't';
987
	}
988
	var retval = "";
989
	for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
990
	return retval;
991
}
992
SSF._eval = eval_fmt;
993
var cfregex = /\[[=<>]/;
994
var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
995
function chkcond(v, rr) {
996
	if(rr == null) return false;
997
	var thresh = parseFloat(rr[2]);
998
	switch(rr[1]) {
999
		case "=":  if(v == thresh) return true; break;
1000
		case ">":  if(v >  thresh) return true; break;
1001
		case "<":  if(v <  thresh) return true; break;
1002
		case "<>": if(v != thresh) return true; break;
1003
		case ">=": if(v >= thresh) return true; break;
1004
		case "<=": if(v <= thresh) return true; break;
1005
	}
1006
	return false;
1007
}
1008
function choose_fmt(f/*:string*/, v/*:any*/) {
1009
	var fmt = split_fmt(f);
1010
	var l = fmt.length, lat = fmt[l-1].indexOf("@");
1011
	if(l<4 && lat>-1) --l;
1012
	if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
1013
	if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
1014
	switch(fmt.length) {
1015
		case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
1016
		case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
1017
		case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
1018
		case 4: break;
1019
	}
1020
	var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
1021
	if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
1022
	if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
1023
		var m1 = fmt[0].match(cfregex2);
1024
		var m2 = fmt[1].match(cfregex2);
1025
		return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
1026
	}
1027
	return [l, ff];
1028
}
1029
function format(fmt/*:string|number*/,v/*:any*/,o/*:?any*/) {
1030
	if(o == null) o = {};
1031
	var sfmt = "";
1032
	switch(typeof fmt) {
1033
		case "string":
1034
			if(fmt == "m/d/yy" && o.dateNF) sfmt = o.dateNF;
1035
			else sfmt = fmt;
1036
			break;
1037
		case "number":
1038
			if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
1039
			else sfmt = (o.table != null ? (o.table/*:any*/) : table_fmt)[fmt];
1040
			break;
1041
	}
1042
	if(isgeneral(sfmt,0)) return general_fmt(v, o);
1043
	if(v instanceof Date) v = datenum_local(v, o.date1904);
1044
	var f = choose_fmt(sfmt, v);
1045
	if(isgeneral(f[1])) return general_fmt(v, o);
1046
	if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
1047
	else if(v === "" || v == null) return "";
1048
	return eval_fmt(f[1], v, o, f[0]);
1049
}
1050
function load_entry(fmt/*:string*/, idx/*:?number*/)/*:number*/ {
1051
	if(typeof idx != 'number') {
1052
		idx = +idx || -1;
1053
/*::if(typeof idx != 'number') return 0x188; */
1054
		for(var i = 0; i < 0x0188; ++i) {
1055
/*::if(typeof idx != 'number') return 0x188; */
1056
			if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
1057
			if(table_fmt[i] == fmt) { idx = i; break; }
1058
		}
1059
/*::if(typeof idx != 'number') return 0x188; */
1060
		if(idx < 0) idx = 0x187;
1061
	}
1062
/*::if(typeof idx != 'number') return 0x188; */
1063
	table_fmt[idx] = fmt;
1064
	return idx;
1065
}
1066
SSF.load = load_entry;
1067
SSF._table = table_fmt;
1068
SSF.get_table = function get_table()/*:SSFTable*/ { return table_fmt; };
1069
SSF.load_table = function load_table(tbl/*:SSFTable*/)/*:void*/ {
1070
	for(var i=0; i!=0x0188; ++i)
1071
		if(tbl[i] !== undefined) load_entry(tbl[i], i);
1072
};
1073
SSF.init_table = init_table;
1074
SSF.format = format;
1075
};
1076
make_ssf(SSF);
1077
/* map from xlml named formats to SSF TODO: localize */
1078
var XLMLFormatMap/*{[string]:string}*/ = ({
1079
	"General Number": "General",
1080
	"General Date": SSF._table[22],
1081
	"Long Date": "dddd, mmmm dd, yyyy",
1082
	"Medium Date": SSF._table[15],
1083
	"Short Date": SSF._table[14],
1084
	"Long Time": SSF._table[19],
1085
	"Medium Time": SSF._table[18],
1086
	"Short Time": SSF._table[20],
1087
	"Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1088
	"Fixed": SSF._table[2],
1089
	"Standard": SSF._table[4],
1090
	"Percent": SSF._table[10],
1091
	"Scientific": SSF._table[11],
1092
	"Yes/No": '"Yes";"Yes";"No";@',
1093
	"True/False": '"True";"True";"False";@',
1094
	"On/Off": '"Yes";"Yes";"No";@'
1095
}/*:any*/);
1096
1097
var SSFImplicit/*{[number]:string}*/ = ({
1098
	"5": '"$"#,##0_);\\("$"#,##0\\)',
1099
	"6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1100
	"7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1101
	"8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1102
	"23": 'General', "24": 'General', "25": 'General', "26": 'General',
1103
	"27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
1104
	"32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
1105
	"36": 'm/d/yy',
1106
	"41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
1107
	"42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
1108
	"43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
1109
	"44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
1110
	"50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
1111
	"55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
1112
	"59": '0',
1113
	"60": '0.00',
1114
	"61": '#,##0',
1115
	"62": '#,##0.00',
1116
	"63": '"$"#,##0_);\\("$"#,##0\\)',
1117
	"64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1118
	"65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1119
	"66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1120
	"67": '0%',
1121
	"68": '0.00%',
1122
	"69": '# ?/?',
1123
	"70": '# ??/??',
1124
	"71": 'm/d/yy',
1125
	"72": 'm/d/yy',
1126
	"73": 'd-mmm-yy',
1127
	"74": 'd-mmm',
1128
	"75": 'mmm-yy',
1129
	"76": 'h:mm',
1130
	"77": 'h:mm:ss',
1131
	"78": 'm/d/yy h:mm',
1132
	"79": 'mm:ss',
1133
	"80": '[h]:mm:ss',
1134
	"81": 'mmss.0'
1135
}/*:any*/);
1136
1137
/* dateNF parse TODO: move to SSF */
1138
var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
1139
function dateNF_regex(dateNF/*:string|number*/)/*:RegExp*/ {
1140
	var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF;
1141
	fmt = fmt.replace(dateNFregex, "(\\d+)");
1142
	return new RegExp("^" + fmt + "$");
1143
}
1144
function dateNF_fix(str/*:string*/, dateNF/*:string*/, match/*:Array<string>*/)/*:string*/ {
1145
	var Y = -1, m = -1, d = -1, H = -1, M = -1, S = -1;
1146
	(dateNF.match(dateNFregex)||[]).forEach(function(n, i) {
1147
		var v = parseInt(match[i+1], 10);
1148
		switch(n.toLowerCase().charAt(0)) {
1149
			case 'y': Y = v; break; case 'd': d = v; break;
1150
			case 'h': H = v; break; case 's': S = v; break;
1151
			case 'm': if(H >= 0) M = v; else m = v; break;
1152
		}
1153
	});
1154
	if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
1155
	var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
1156
	if(datestr.length == 7) datestr = "0" + datestr;
1157
	if(datestr.length == 8) datestr = "20" + datestr;
1158
	var timestr = (("00" + (H>=0?H:0)).slice(-2) + ":" + ("00" + (M>=0?M:0)).slice(-2) + ":" + ("00" + (S>=0?S:0)).slice(-2));
1159
	if(H == -1 && M == -1 && S == -1) return datestr;
1160
	if(Y == -1 && m == -1 && d == -1) return timestr;
1161
	return datestr + "T" + timestr;
1162
}
1163
1164
var DO_NOT_EXPORT_CFB = true;
1165
/*::
1166
declare var Base64:any;
1167
declare var ReadShift:any;
1168
declare var CheckField:any;
1169
declare var prep_blob:any;
1170
declare var __readUInt32LE:any;
1171
declare var __readInt32LE:any;
1172
declare var __toBuffer:any;
1173
declare var __utf16le:any;
1174
declare var bconcat:any;
1175
declare var s2a:any;
1176
declare var chr0:any;
1177
declare var chr1:any;
1178
declare var new_buf:any;
1179
*/
1180
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
1181
/* vim: set ts=2: */
1182
/*jshint eqnull:true */
1183
/*exported CFB */
1184
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
1185
1186
/*::
1187
declare var DO_NOT_EXPORT_CFB:?boolean;
1188
type SectorEntry = {
1189
	name?:string;
1190
	nodes?:Array<number>;
1191
	data:RawBytes;
1192
};
1193
type SectorList = {
1194
	[k:string|number]:SectorEntry;
1195
	name:?string;
1196
	fat_addrs:Array<number>;
1197
	ssz:number;
1198
}
1199
type CFBFiles = {[n:string]:CFBEntry};
1200
*/
1201
/* [MS-CFB] v20171201 */
1202
var CFB = (function _CFB(){
1203
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
1204
exports.version = '1.0.8';
1205
/* [MS-CFB] 2.6.4 */
1206
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
1207
	var L = l.split("/"), R = r.split("/");
1208
	for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
1209
		if((c = L[i].length - R[i].length)) return c;
1210
		if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
1211
	}
1212
	return L.length - R.length;
1213
}
1214
function dirname(p/*:string*/)/*:string*/ {
1215
	if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
1216
	var c = p.lastIndexOf("/");
1217
	return (c === -1) ? p : p.slice(0, c+1);
1218
}
1219
1220
function filename(p/*:string*/)/*:string*/ {
1221
	if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
1222
	var c = p.lastIndexOf("/");
1223
	return (c === -1) ? p : p.slice(c+1);
1224
}
1225
var fs/*:: = require('fs'); */;
1226
function get_fs() { return fs || (fs = require('fs')); }
1227
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
1228
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
1229
var mver = 3;
1230
var ssz = 512;
1231
var nmfs = 0; // number of mini FAT sectors
1232
var difat_sec_cnt = 0;
1233
var dir_start = 0;
1234
var minifat_start = 0;
1235
var difat_start = 0;
1236
1237
var fat_addrs/*:Array<number>*/ = []; // locations of FAT sectors
1238
1239
/* [MS-CFB] 2.2 Compound File Header */
1240
var blob/*:CFBlob*/ = /*::(*/file.slice(0,512)/*:: :any)*/;
1241
prep_blob(blob, 0);
1242
1243
/* major version */
1244
var mv = check_get_mver(blob);
1245
mver = mv[0];
1246
switch(mver) {
1247
	case 3: ssz = 512; break; case 4: ssz = 4096; break;
1248
	default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
1249
}
1250
1251
/* reprocess header */
1252
if(ssz !== 512) { blob = /*::(*/file.slice(0,ssz)/*:: :any)*/; prep_blob(blob, 28 /* blob.l */); }
1253
/* Save header for final object */
1254
var header/*:RawBytes*/ = file.slice(0,ssz);
1255
1256
check_shifts(blob, mver);
1257
1258
// Number of Directory Sectors
1259
var dir_cnt/*:number*/ = blob.read_shift(4, 'i');
1260
if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
1261
1262
// Number of FAT Sectors
1263
blob.l += 4;
1264
1265
// First Directory Sector Location
1266
dir_start = blob.read_shift(4, 'i');
1267
1268
// Transaction Signature
1269
blob.l += 4;
1270
1271
// Mini Stream Cutoff Size
1272
blob.chk('00100000', 'Mini Stream Cutoff Size: ');
1273
1274
// First Mini FAT Sector Location
1275
minifat_start = blob.read_shift(4, 'i');
1276
1277
// Number of Mini FAT Sectors
1278
nmfs = blob.read_shift(4, 'i');
1279
1280
// First DIFAT sector location
1281
difat_start = blob.read_shift(4, 'i');
1282
1283
// Number of DIFAT Sectors
1284
difat_sec_cnt = blob.read_shift(4, 'i');
1285
1286
// Grab FAT Sector Locations
1287
for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
1288
	q = blob.read_shift(4, 'i');
1289
	if(q<0) break;
1290
	fat_addrs[j] = q;
1291
}
1292
1293
/** Break the file up into sectors */
1294
var sectors/*:Array<RawBytes>*/ = sectorify(file, ssz);
1295
1296
sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
1297
1298
/** Chains */
1299
var sector_list/*:SectorList*/ = make_sector_list(sectors, dir_start, fat_addrs, ssz);
1300
1301
sector_list[dir_start].name = "!Directory";
1302
if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
1303
sector_list[fat_addrs[0]].name = "!FAT";
1304
sector_list.fat_addrs = fat_addrs;
1305
sector_list.ssz = ssz;
1306
1307
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1308
var files/*:CFBFiles*/ = {}, Paths/*:Array<string>*/ = [], FileIndex/*:CFBFileIndex*/ = [], FullPaths/*:Array<string>*/ = [];
1309
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
1310
1311
build_full_paths(FileIndex, FullPaths, Paths);
1312
Paths.shift();
1313
1314
var o = {
1315
	FileIndex: FileIndex,
1316
	FullPaths: FullPaths
1317
};
1318
1319
// $FlowIgnore
1320
if(options && options.raw) o.raw = {header: header, sectors: sectors};
1321
return o;
1322
} // parse
1323
1324
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
1325
function check_get_mver(blob/*:CFBlob*/)/*:[number, number]*/ {
1326
	// header signature 8
1327
	blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
1328
1329
	// clsid 16
1330
	blob.chk(HEADER_CLSID, 'CLSID: ');
1331
1332
	// minor version 2
1333
	var mver/*:number*/ = blob.read_shift(2, 'u');
1334
1335
	return [blob.read_shift(2,'u'), mver];
1336
}
1337
function check_shifts(blob/*:CFBlob*/, mver/*:number*/)/*:void*/ {
1338
	var shift = 0x09;
1339
1340
	// Byte Order
1341
	//blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff
1342
	blob.l += 2;
1343
1344
	// Sector Shift
1345
	switch((shift = blob.read_shift(2))) {
1346
		case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;
1347
		case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;
1348
		default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);
1349
	}
1350
1351
	// Mini Sector Shift
1352
	blob.chk('0600', 'Mini Sector Shift: ');
1353
1354
	// Reserved
1355
	blob.chk('000000000000', 'Reserved: ');
1356
}
1357
1358
/** Break the file up into sectors */
1359
function sectorify(file/*:RawBytes*/, ssz/*:number*/)/*:Array<RawBytes>*/ {
1360
	var nsectors = Math.ceil(file.length/ssz)-1;
1361
	var sectors/*:Array<RawBytes>*/ = [];
1362
	for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
1363
	sectors[nsectors-1] = file.slice(nsectors*ssz);
1364
	return sectors;
1365
}
1366
1367
/* [MS-CFB] 2.6.4 Red-Black Tree */
1368
function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array<string>*/, Paths/*:Array<string>*/)/*:void*/ {
1369
	var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
1370
	var dad/*:Array<number>*/ = [], q/*:Array<number>*/ = [];
1371
1372
	for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
1373
1374
	for(; j < q.length; ++j) {
1375
		i = q[j];
1376
		L = FI[i].L; R = FI[i].R; C = FI[i].C;
1377
		if(dad[i] === i) {
1378
			if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
1379
			if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
1380
		}
1381
		if(C !== -1 /*NOSTREAM*/) dad[C] = i;
1382
		if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
1383
		if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
1384
	}
1385
	for(i=1; i < pl; ++i) if(dad[i] === i) {
1386
		if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
1387
		else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
1388
	}
1389
1390
	for(i=1; i < pl; ++i) {
1391
		if(FI[i].type === 0 /* unknown */) continue;
1392
		j = dad[i];
1393
		if(j === 0) FP[i] = FP[0] + "/" + FP[i];
1394
		else while(j !== 0 && j !== dad[j]) {
1395
			FP[i] = FP[j] + "/" + FP[i];
1396
			j = dad[j];
1397
		}
1398
		dad[i] = 0;
1399
	}
1400
1401
	FP[0] += "/";
1402
	for(i=1; i < pl; ++i) {
1403
		if(FI[i].type !== 2 /* stream */) FP[i] += "/";
1404
	}
1405
}
1406
1407
function get_mfat_entry(entry/*:CFBEntry*/, payload/*:RawBytes*/, mini/*:?RawBytes*/)/*:CFBlob*/ {
1408
	var start = entry.start, size = entry.size;
1409
	//return (payload.slice(start*MSSZ, start*MSSZ + size)/*:any*/);
1410
	var o = [];
1411
	var idx = start;
1412
	while(mini && size > 0 && idx >= 0) {
1413
		o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
1414
		size -= MSSZ;
1415
		idx = __readInt32LE(mini, idx * 4);
1416
	}
1417
	if(o.length === 0) return (new_buf(0)/*:any*/);
1418
	return (bconcat(o).slice(0, entry.size)/*:any*/);
1419
}
1420
1421
/** Chase down the rest of the DIFAT chain to build a comprehensive list
1422
    DIFAT chains by storing the next sector number as the last 32 bits */
1423
function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/, ssz/*:number*/, fat_addrs)/*:void*/ {
1424
	var q/*:number*/ = ENDOFCHAIN;
1425
	if(idx === ENDOFCHAIN) {
1426
		if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
1427
	} else if(idx !== -1 /*FREESECT*/) {
1428
		var sector = sectors[idx], m = (ssz>>>2)-1;
1429
		if(!sector) return;
1430
		for(var i = 0; i < m; ++i) {
1431
			if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1432
			fat_addrs.push(q);
1433
		}
1434
		sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
1435
	}
1436
}
1437
1438
/** Follow the linked list of sectors for a given starting point */
1439
function get_sector_list(sectors/*:Array<RawBytes>*/, start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/, chkd/*:?Array<boolean>*/)/*:SectorEntry*/ {
1440
	var buf/*:Array<number>*/ = [], buf_chain/*:Array<any>*/ = [];
1441
	if(!chkd) chkd = [];
1442
	var modulus = ssz - 1, j = 0, jj = 0;
1443
	for(j=start; j>=0;) {
1444
		chkd[j] = true;
1445
		buf[buf.length] = j;
1446
		buf_chain.push(sectors[j]);
1447
		var addr = fat_addrs[Math.floor(j*4/ssz)];
1448
		jj = ((j*4) & modulus);
1449
		if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1450
		if(!sectors[addr]) break;
1451
		j = __readInt32LE(sectors[addr], jj);
1452
	}
1453
	return {nodes: buf, data:__toBuffer([buf_chain])};
1454
}
1455
1456
/** Chase down the sector linked lists */
1457
function make_sector_list(sectors/*:Array<RawBytes>*/, dir_start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/)/*:SectorList*/ {
1458
	var sl = sectors.length, sector_list/*:SectorList*/ = ([]/*:any*/);
1459
	var chkd/*:Array<boolean>*/ = [], buf/*:Array<number>*/ = [], buf_chain/*:Array<RawBytes>*/ = [];
1460
	var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
1461
	for(i=0; i < sl; ++i) {
1462
		buf = ([]/*:Array<number>*/);
1463
		k = (i + dir_start); if(k >= sl) k-=sl;
1464
		if(chkd[k]) continue;
1465
		buf_chain = [];
1466
		for(j=k; j>=0;) {
1467
			chkd[j] = true;
1468
			buf[buf.length] = j;
1469
			buf_chain.push(sectors[j]);
1470
			var addr/*:number*/ = fat_addrs[Math.floor(j*4/ssz)];
1471
			jj = ((j*4) & modulus);
1472
			if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1473
			if(!sectors[addr]) break;
1474
			j = __readInt32LE(sectors[addr], jj);
1475
		}
1476
		sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])}/*:SectorEntry*/);
1477
	}
1478
	return sector_list;
1479
}
1480
1481
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1482
function read_directory(dir_start/*:number*/, sector_list/*:SectorList*/, sectors/*:Array<RawBytes>*/, Paths/*:Array<string>*/, nmfs, files, FileIndex, mini) {
1483
	var minifat_store = 0, pl = (Paths.length?2:0);
1484
	var sector = sector_list[dir_start].data;
1485
	var i = 0, namelen = 0, name;
1486
	for(; i < sector.length; i+= 128) {
1487
		var blob/*:CFBlob*/ = /*::(*/sector.slice(i, i+128)/*:: :any)*/;
1488
		prep_blob(blob, 64);
1489
		namelen = blob.read_shift(2);
1490
		name = __utf16le(blob,0,namelen-pl);
1491
		Paths.push(name);
1492
		var o/*:CFBEntry*/ = ({
1493
			name:  name,
1494
			type:  blob.read_shift(1),
1495
			color: blob.read_shift(1),
1496
			L:     blob.read_shift(4, 'i'),
1497
			R:     blob.read_shift(4, 'i'),
1498
			C:     blob.read_shift(4, 'i'),
1499
			clsid: blob.read_shift(16),
1500
			state: blob.read_shift(4, 'i'),
1501
			start: 0,
1502
			size: 0
1503
		});
1504
		var ctime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1505
		if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1506
		var mtime/*:number*/ = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1507
		if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1508
		o.start = blob.read_shift(4, 'i');
1509
		o.size = blob.read_shift(4, 'i');
1510
		if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1511
		if(o.type === 5) { /* root */
1512
			minifat_store = o.start;
1513
			if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1514
			/*minifat_size = o.size;*/
1515
		} else if(o.size >= 4096 /* MSCSZ */) {
1516
			o.storage = 'fat';
1517
			if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1518
			sector_list[o.start].name = o.name;
1519
			o.content = (sector_list[o.start].data.slice(0,o.size)/*:any*/);
1520
		} else {
1521
			o.storage = 'minifat';
1522
			if(o.size < 0) o.size = 0;
1523
			else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1524
				o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1525
			}
1526
		}
1527
		if(o.content) prep_blob(o.content, 0);
1528
		files[name] = o;
1529
		FileIndex.push(o);
1530
	}
1531
}
1532
1533
function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ {
1534
	return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1535
}
1536
1537
function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
1538
	get_fs();
1539
	return parse(fs.readFileSync(filename), options);
1540
}
1541
1542
function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
1543
	switch(options && options.type || "base64") {
1544
		case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options);
1545
		case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options);
1546
		case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options);
1547
	}
1548
	return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options);
1549
}
1550
1551
function init_cfb(cfb/*:CFBContainer*/, opts/*:?any*/)/*:void*/ {
1552
	var o = opts || {}, root = o.root || "Root Entry";
1553
	if(!cfb.FullPaths) cfb.FullPaths = [];
1554
	if(!cfb.FileIndex) cfb.FileIndex = [];
1555
	if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1556
	if(cfb.FullPaths.length === 0) {
1557
		cfb.FullPaths[0] = root + "/";
1558
		cfb.FileIndex[0] = ({ name: root, type: 5 }/*:any*/);
1559
	}
1560
	if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1561
	seed_cfb(cfb);
1562
}
1563
function seed_cfb(cfb/*:CFBContainer*/)/*:void*/ {
1564
	var nm = "\u0001Sh33tJ5";
1565
	if(CFB.find(cfb, "/" + nm)) return;
1566
	var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1567
	cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }/*:any*/));
1568
	cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1569
	rebuild_cfb(cfb);
1570
}
1571
function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
1572
	init_cfb(cfb);
1573
	var gc = false, s = false;
1574
	for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1575
		var _file = cfb.FileIndex[i];
1576
		switch(_file.type) {
1577
			case 0:
1578
				if(s) gc = true;
1579
				else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1580
				break;
1581
			case 1: case 2: case 5:
1582
				s = true;
1583
				if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1584
				if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1585
				break;
1586
			default: gc = true; break;
1587
		}
1588
	}
1589
	if(!gc && !f) return;
1590
1591
	var now = new Date(1987, 1, 19), j = 0;
1592
	var data/*:Array<[string, CFBEntry]>*/ = [];
1593
	for(i = 0; i < cfb.FullPaths.length; ++i) {
1594
		if(cfb.FileIndex[i].type === 0) continue;
1595
		data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1596
	}
1597
	for(i = 0; i < data.length; ++i) {
1598
		var dad = dirname(data[i][0]);
1599
		s = false;
1600
		for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1601
		if(!s) data.push([dad, ({
1602
			name: filename(dad).replace("/",""),
1603
			type: 1,
1604
			clsid: HEADER_CLSID,
1605
			ct: now, mt: now,
1606
			content: null
1607
		}/*:any*/)]);
1608
	}
1609
1610
	data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1611
	cfb.FullPaths = []; cfb.FileIndex = [];
1612
	for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1613
	for(i = 0; i < data.length; ++i) {
1614
		var elt = cfb.FileIndex[i];
1615
		var nm = cfb.FullPaths[i];
1616
1617
		elt.name =  filename(nm).replace("/","");
1618
		elt.L = elt.R = elt.C = -(elt.color = 1);
1619
		elt.size = elt.content ? elt.content.length : 0;
1620
		elt.start = 0;
1621
		elt.clsid = (elt.clsid || HEADER_CLSID);
1622
		if(i === 0) {
1623
			elt.C = data.length > 1 ? 1 : -1;
1624
			elt.size = 0;
1625
			elt.type = 5;
1626
		} else if(nm.slice(-1) == "/") {
1627
			for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1628
			elt.C = j >= data.length ? -1 : j;
1629
			for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1630
			elt.R = j >= data.length ? -1 : j;
1631
			elt.type = 1;
1632
		} else {
1633
			if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1634
			elt.type = 2;
1635
		}
1636
	}
1637
1638
}
1639
1640
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
1641
	var _opts = options || {};
1642
	rebuild_cfb(cfb);
1643
	var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
1644
		var mini_size = 0, fat_size = 0;
1645
		for(var i = 0; i < cfb.FileIndex.length; ++i) {
1646
			var file = cfb.FileIndex[i];
1647
			if(!file.content) continue;
1648
			/*:: if(file.content == null) throw new Error("unreachable"); */
1649
			var flen = file.content.length;
1650
			if(flen > 0){
1651
				if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1652
				else fat_size += (flen + 0x01FF) >> 9;
1653
			}
1654
		}
1655
		var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1656
		var mini_cnt = (mini_size + 7) >> 3;
1657
		var mfat_cnt = (mini_size + 0x7F) >> 7;
1658
		var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1659
		var fat_cnt = (fat_base + 0x7F) >> 7;
1660
		var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1661
		while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1662
		var L =  [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1663
		cfb.FileIndex[0].size = mini_size << 6;
1664
		L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1665
		return L;
1666
	})(cfb);
1667
	var o = new_buf(L[7] << 9);
1668
	var i = 0, T = 0;
1669
	{
1670
		for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1671
		for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1672
		o.write_shift(2, 0x003E);
1673
		o.write_shift(2, 0x0003);
1674
		o.write_shift(2, 0xFFFE);
1675
		o.write_shift(2, 0x0009);
1676
		o.write_shift(2, 0x0006);
1677
		for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1678
		o.write_shift(4, 0);
1679
		o.write_shift(4, L[2]);
1680
		o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1681
		o.write_shift(4, 0);
1682
		o.write_shift(4, 1<<12);
1683
		o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1684
		o.write_shift(4, L[3]);
1685
		o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1686
		o.write_shift(4, L[1]);
1687
		for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1688
	}
1689
	if(L[1]) {
1690
		for(T = 0; T < L[1]; ++T) {
1691
			for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1692
			o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1693
		}
1694
	}
1695
	var chainit = function(w/*:number*/)/*:void*/ {
1696
		for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1697
		if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1698
	};
1699
	T = i = 0;
1700
	for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1701
	for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1702
	chainit(L[3]);
1703
	chainit(L[4]);
1704
	var j/*:number*/ = 0, flen/*:number*/ = 0;
1705
	var file/*:CFBEntry*/ = cfb.FileIndex[0];
1706
	for(; j < cfb.FileIndex.length; ++j) {
1707
		file = cfb.FileIndex[j];
1708
		if(!file.content) continue;
1709
		/*:: if(file.content == null) throw new Error("unreachable"); */
1710
		flen = file.content.length;
1711
		if(flen < 0x1000) continue;
1712
		file.start = T;
1713
		chainit((flen + 0x01FF) >> 9);
1714
	}
1715
	chainit((L[6] + 7) >> 3);
1716
	while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1717
	T = i = 0;
1718
	for(j = 0; j < cfb.FileIndex.length; ++j) {
1719
		file = cfb.FileIndex[j];
1720
		if(!file.content) continue;
1721
		/*:: if(file.content == null) throw new Error("unreachable"); */
1722
		flen = file.content.length;
1723
		if(!flen || flen >= 0x1000) continue;
1724
		file.start = T;
1725
		chainit((flen + 0x3F) >> 6);
1726
	}
1727
	while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1728
	for(i = 0; i < L[4]<<2; ++i) {
1729
		var nm = cfb.FullPaths[i];
1730
		if(!nm || nm.length === 0) {
1731
			for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1732
			for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1733
			for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1734
			continue;
1735
		}
1736
		file = cfb.FileIndex[i];
1737
		if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1738
		var _nm/*:string*/ = (i === 0 && _opts.root) || file.name;
1739
		flen = 2*(_nm.length+1);
1740
		o.write_shift(64, _nm, "utf16le");
1741
		o.write_shift(2, flen);
1742
		o.write_shift(1, file.type);
1743
		o.write_shift(1, file.color);
1744
		o.write_shift(-4, file.L);
1745
		o.write_shift(-4, file.R);
1746
		o.write_shift(-4, file.C);
1747
		if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1748
		else o.write_shift(16, file.clsid, "hex");
1749
		o.write_shift(4, file.state || 0);
1750
		o.write_shift(4, 0); o.write_shift(4, 0);
1751
		o.write_shift(4, 0); o.write_shift(4, 0);
1752
		o.write_shift(4, file.start);
1753
		o.write_shift(4, file.size); o.write_shift(4, 0);
1754
	}
1755
	for(i = 1; i < cfb.FileIndex.length; ++i) {
1756
		file = cfb.FileIndex[i];
1757
		/*:: if(!file.content) throw new Error("unreachable"); */
1758
		if(file.size >= 0x1000) {
1759
			o.l = (file.start+1) << 9;
1760
			for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1761
			for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1762
		}
1763
	}
1764
	for(i = 1; i < cfb.FileIndex.length; ++i) {
1765
		file = cfb.FileIndex[i];
1766
		/*:: if(!file.content) throw new Error("unreachable"); */
1767
		if(file.size > 0 && file.size < 0x1000) {
1768
			for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1769
			for(; j & 0x3F; ++j) o.write_shift(1, 0);
1770
		}
1771
	}
1772
	while(o.l < o.length) o.write_shift(1, 0);
1773
	return o;
1774
}
1775
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1776
function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ {
1777
	var UCFullPaths/*:Array<string>*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1778
	var UCPaths/*:Array<string>*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1779
	var k/*:boolean*/ = false;
1780
	if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1781
	else k = path.indexOf("/") !== -1;
1782
	var UCPath/*:string*/ = path.toUpperCase();
1783
	var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1784
	if(w !== -1) return cfb.FileIndex[w];
1785
1786
	var m = !UCPath.match(chr1);
1787
	UCPath = UCPath.replace(chr0,'');
1788
	if(m) UCPath = UCPath.replace(chr1,'!');
1789
	for(w = 0; w < UCFullPaths.length; ++w) {
1790
		if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1791
		if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1792
	}
1793
	return null;
1794
}
1795
/** CFB Constants */
1796
var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1797
//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1798
/* 2.1 Compound File Sector Numbers and Types */
1799
var ENDOFCHAIN = -2;
1800
/* 2.2 Compound File Header */
1801
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1802
var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1803
var HEADER_CLSID = '00000000000000000000000000000000';
1804
var consts = {
1805
	/* 2.1 Compund File Sector Numbers and Types */
1806
	MAXREGSECT: -6,
1807
	DIFSECT: -4,
1808
	FATSECT: -3,
1809
	ENDOFCHAIN: ENDOFCHAIN,
1810
	FREESECT: -1,
1811
	/* 2.2 Compound File Header */
1812
	HEADER_SIGNATURE: HEADER_SIGNATURE,
1813
	HEADER_MINOR_VERSION: '3e00',
1814
	MAXREGSID: -6,
1815
	NOSTREAM: -1,
1816
	HEADER_CLSID: HEADER_CLSID,
1817
	/* 2.6.1 Compound File Directory Entry */
1818
	EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
1819
};
1820
1821
function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
1822
	get_fs();
1823
	var o = _write(cfb, options);
1824
	/*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
1825
	fs.writeFileSync(filename, o);
1826
}
1827
1828
function a2s(o/*:RawBytes*/)/*:string*/ {
1829
	var out = new Array(o.length);
1830
	for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
1831
	return out.join("");
1832
}
1833
1834
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
1835
	var o = _write(cfb, options);
1836
	switch(options && options.type) {
1837
		case "file": get_fs(); fs.writeFileSync(options.filename, (o/*:any*/)); return o;
1838
		case "binary": return a2s(o);
1839
		case "base64": return Base64.encode(a2s(o));
1840
	}
1841
	return o;
1842
}
1843
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
1844
	var o/*:CFBContainer*/ = ({}/*:any*/);
1845
	init_cfb(o, opts);
1846
	return o;
1847
}
1848
1849
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
1850
	var unsafe = opts && opts.unsafe;
1851
	if(!unsafe) init_cfb(cfb);
1852
	var file = !unsafe && CFB.find(cfb, name);
1853
	if(!file) {
1854
		var fpath/*:string*/ = cfb.FullPaths[0];
1855
		if(name.slice(0, fpath.length) == fpath) fpath = name;
1856
		else {
1857
			if(fpath.slice(-1) != "/") fpath += "/";
1858
			fpath = (fpath + name).replace("//","/");
1859
		}
1860
		file = ({name: filename(name), type: 2}/*:any*/);
1861
		cfb.FileIndex.push(file);
1862
		cfb.FullPaths.push(fpath);
1863
		if(!unsafe) CFB.utils.cfb_gc(cfb);
1864
	}
1865
	/*:: if(!file) throw new Error("unreachable"); */
1866
	file.content = (content/*:any*/);
1867
	file.size = content ? content.length : 0;
1868
	if(opts) {
1869
		if(opts.CLSID) file.clsid = opts.CLSID;
1870
	}
1871
	return file;
1872
}
1873
1874
function cfb_del(cfb/*:CFBContainer*/, name/*:string*/)/*:boolean*/ {
1875
	init_cfb(cfb);
1876
	var file = CFB.find(cfb, name);
1877
	if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
1878
		cfb.FileIndex.splice(j, 1);
1879
		cfb.FullPaths.splice(j, 1);
1880
		return true;
1881
	}
1882
	return false;
1883
}
1884
1885
function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)/*:boolean*/ {
1886
	init_cfb(cfb);
1887
	var file = CFB.find(cfb, old_name);
1888
	if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
1889
		cfb.FileIndex[j].name = filename(new_name);
1890
		cfb.FullPaths[j] = new_name;
1891
		return true;
1892
	}
1893
	return false;
1894
}
1895
1896
function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); }
1897
1898
exports.find = find;
1899
exports.read = read;
1900
exports.parse = parse;
1901
exports.write = write;
1902
exports.writeFile = write_file;
1903
exports.utils = {
1904
	cfb_new: cfb_new,
1905
	cfb_add: cfb_add,
1906
	cfb_del: cfb_del,
1907
	cfb_mov: cfb_mov,
1908
	cfb_gc: cfb_gc,
1909
	ReadShift: ReadShift,
1910
	CheckField: CheckField,
1911
	prep_blob: prep_blob,
1912
	bconcat: bconcat,
1913
	consts: consts
1914
};
1915
1916
return exports;
1917
})();
1918
1919
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
1920
var _fs;
1921
if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
1922
1923
/* normalize data for blob ctor */
1924
function blobify(data) {
1925
	if(typeof data === "string") return s2ab(data);
1926
	if(Array.isArray(data)) return a2u(data);
1927
	return data;
1928
}
1929
/* write or download file */
1930
function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
1931
	/*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File, chrome */
1932
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
1933
	var data = (enc == "utf8") ? utf8write(payload) : payload;
1934
	/*:: declare var IE_SaveFile: any; */
1935
	if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
1936
	if(typeof Blob !== 'undefined') {
1937
		var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
1938
		/*:: declare var navigator: any; */
1939
		if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
1940
		/*:: declare var saveAs: any; */
1941
		if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
1942
		if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
1943
			var url = URL.createObjectURL(blob);
1944
			/*:: declare var chrome: any; */
1945
			if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
1946
				if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
1947
				return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
1948
			}
1949
			var a = document.createElement("a");
1950
			if(a.download != null) {
1951
				/*:: if(document.body == null) throw new Error("unreachable"); */
1952
				a.download = fname; a.href = url; document.body.appendChild(a); a.click();
1953
				/*:: if(document.body == null) throw new Error("unreachable"); */ document.body.removeChild(a);
1954
				if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
1955
				return url;
1956
			}
1957
		}
1958
	}
1959
	// $FlowIgnore
1960
	if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
1961
		// $FlowIgnore
1962
		var out = File(fname); out.open("w"); out.encoding = "binary";
1963
		if(Array.isArray(payload)) payload = a2s(payload);
1964
		out.write(payload); out.close(); return payload;
1965
	} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
1966
	throw new Error("cannot save file " + fname);
1967
}
1968
1969
/* read binary data from file */
1970
function read_binary(path/*:string*/) {
1971
	if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
1972
	// $FlowIgnore
1973
	if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
1974
		// $FlowIgnore
1975
		var infile = File(path); infile.open("r"); infile.encoding = "binary";
1976
		var data = infile.read(); infile.close();
1977
		return data;
1978
	} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
1979
	throw new Error("Cannot access file " + path);
1980
}
1981
function keys(o/*:any*/)/*:Array<any>*/ {
1982
	var ks = Object.keys(o), o2 = [];
1983
	for(var i = 0; i < ks.length; ++i) if(o.hasOwnProperty(ks[i])) o2.push(ks[i]);
1984
	return o2;
1985
}
1986
1987
function evert_key(obj/*:any*/, key/*:string*/)/*:EvertType*/ {
1988
	var o = ([]/*:any*/), K = keys(obj);
1989
	for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
1990
	return o;
1991
}
1992
1993
function evert(obj/*:any*/)/*:EvertType*/ {
1994
	var o = ([]/*:any*/), K = keys(obj);
1995
	for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
1996
	return o;
1997
}
1998
1999
function evert_num(obj/*:any*/)/*:EvertNumType*/ {
2000
	var o = ([]/*:any*/), K = keys(obj);
2001
	for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
2002
	return o;
2003
}
2004
2005
function evert_arr(obj/*:any*/)/*:EvertArrType*/ {
2006
	var o/*:EvertArrType*/ = ([]/*:any*/), K = keys(obj);
2007
	for(var i = 0; i !== K.length; ++i) {
2008
		if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
2009
		o[obj[K[i]]].push(K[i]);
2010
	}
2011
	return o;
2012
}
2013
2014
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
2015
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2016
function datenum(v/*:Date*/, date1904/*:?boolean*/)/*:number*/ {
2017
	var epoch = v.getTime();
2018
	if(date1904) epoch -= 1462*24*60*60*1000;
2019
	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
2020
}
2021
function numdate(v/*:number*/)/*:Date*/ {
2022
	var out = new Date();
2023
	out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
2024
	return out;
2025
}
2026
2027
/* ISO 8601 Duration */
2028
function parse_isodur(s) {
2029
	var sec = 0, mt = 0, time = false;
2030
	var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
2031
	if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
2032
	for(var i = 1; i != m.length; ++i) {
2033
		if(!m[i]) continue;
2034
		mt = 1;
2035
		if(i > 3) time = true;
2036
		switch(m[i].slice(m[i].length-1)) {
2037
			case 'Y':
2038
				throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
2039
			case 'D': mt *= 24;
2040
				/* falls through */
2041
			case 'H': mt *= 60;
2042
				/* falls through */
2043
			case 'M':
2044
				if(!time) throw new Error("Unsupported ISO Duration Field: M");
2045
				else mt *= 60;
2046
				/* falls through */
2047
			case 'S': break;
2048
		}
2049
		sec += mt * parseInt(m[i], 10);
2050
	}
2051
	return sec;
2052
}
2053
2054
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
2055
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
2056
var good_pd = good_pd_date.getFullYear() == 2017;
2057
/* parses a date as a local date */
2058
function parseDate(str/*:string|Date*/, fixdate/*:?number*/)/*:Date*/ {
2059
	var d = new Date(str);
2060
	if(good_pd) {
2061
		/*:: if(fixdate == null) fixdate = 0; */
2062
		if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
2063
		else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
2064
		return d;
2065
	}
2066
	if(str instanceof Date) return str;
2067
	if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
2068
		var s = d.getFullYear();
2069
		if(str.indexOf("" + s) > -1) return d;
2070
		d.setFullYear(d.getFullYear() + 100); return d;
2071
	}
2072
	var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
2073
	var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
2074
	if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
2075
	return out;
2076
}
2077
2078
function cc2str(arr/*:Array<number>*/)/*:string*/ {
2079
	var o = "";
2080
	for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2081
	return o;
2082
}
2083
2084
function dup(o/*:any*/)/*:any*/ {
2085
	if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2086
	if(typeof o != 'object' || o == null) return o;
2087
	if(o instanceof Date) return new Date(o.getTime());
2088
	var out = {};
2089
	for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
2090
	return out;
2091
}
2092
2093
function fill(c/*:string*/,l/*:number*/)/*:string*/ { var o = ""; while(o.length < l) o+=c; return o; }
2094
2095
/* TODO: stress test */
2096
function fuzzynum(s/*:string*/)/*:number*/ {
2097
	var v/*:number*/ = Number(s);
2098
	if(!isNaN(v)) return v;
2099
	var wt = 1;
2100
	var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2101
	if(!isNaN(v = Number(ss))) return v / wt;
2102
	ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2103
	if(!isNaN(v = Number(ss))) return v / wt;
2104
	return v;
2105
}
2106
function fuzzydate(s/*:string*/)/*:Date*/ {
2107
	var o = new Date(s), n = new Date(NaN);
2108
	var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2109
	if(isNaN(d)) return n;
2110
	if(y < 0 || y > 8099) return n;
2111
	if((m > 0 || d > 1) && y != 101) return o;
2112
	if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2113
	if(s.match(/[^-0-9:,\/\\]/)) return n;
2114
	return o;
2115
}
2116
2117
var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2118
function split_regex(str/*:string*/, re, def/*:string*/)/*:Array<string>*/ {
2119
	if(safe_split_regex || typeof re == "string") return str.split(re);
2120
	var p = str.split(re), o = [p[0]];
2121
	for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2122
	return o;
2123
}
2124
function getdatastr(data)/*:?string*/ {
2125
	if(!data) return null;
2126
	if(data.data) return debom(data.data);
2127
	if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2128
	if(data.asBinary) return debom(data.asBinary());
2129
	if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2130
	return null;
2131
}
2132
2133
function getdatabin(data) {
2134
	if(!data) return null;
2135
	if(data.data) return char_codes(data.data);
2136
	if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2137
	if(data._data && data._data.getContent) {
2138
		var o = data._data.getContent();
2139
		if(typeof o == "string") return char_codes(o);
2140
		return Array.prototype.slice.call(o);
2141
	}
2142
	return null;
2143
}
2144
2145
function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2146
2147
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2148
/* OASIS does not comment on filename case sensitivity */
2149
function safegetzipfile(zip, file/*:string*/) {
2150
	var k = keys(zip.files);
2151
	var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
2152
	for(var i=0; i<k.length; ++i) {
2153
		var n = k[i].toLowerCase();
2154
		if(f == n || g == n) return zip.files[k[i]];
2155
	}
2156
	return null;
2157
}
2158
2159
function getzipfile(zip, file/*:string*/) {
2160
	var o = safegetzipfile(zip, file);
2161
	if(o == null) throw new Error("Cannot find file " + file + " in zip");
2162
	return o;
2163
}
2164
2165
function getzipdata(zip, file/*:string*/, safe/*:?boolean*/)/*:any*/ {
2166
	if(!safe) return getdata(getzipfile(zip, file));
2167
	if(!file) return null;
2168
	try { return getzipdata(zip, file); } catch(e) { return null; }
2169
}
2170
2171
function getzipstr(zip, file/*:string*/, safe/*:?boolean*/)/*:?string*/ {
2172
	if(!safe) return getdatastr(getzipfile(zip, file));
2173
	if(!file) return null;
2174
	try { return getzipstr(zip, file); } catch(e) { return null; }
2175
}
2176
2177
function zipentries(zip) {
2178
	var k = keys(zip.files), o = [];
2179
	for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i]);
2180
	return o.sort();
2181
}
2182
2183
var jszip;
2184
/*:: declare var JSZipSync:any; */
2185
/*global JSZipSync:true */
2186
if(typeof JSZipSync !== 'undefined') jszip = JSZipSync;
2187
if(typeof exports !== 'undefined') {
2188
	if(typeof module !== 'undefined' && module.exports) {
2189
		if(typeof jszip === 'undefined') jszip = require('./jszip.js');
2190
	}
2191
}
2192
2193
function resolve_path(path/*:string*/, base/*:string*/)/*:string*/ {
2194
	var result = base.split('/');
2195
	if(base.slice(-1) != "/") result.pop(); // folder path
2196
	var target = path.split('/');
2197
	while (target.length !== 0) {
2198
		var step = target.shift();
2199
		if (step === '..') result.pop();
2200
		else if (step !== '.') result.push(step);
2201
	}
2202
	return result.join('/');
2203
}
2204
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2205
var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2206
var tagregex=/<[\/\?]?[a-zA-Z0-9:]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s?[\/\?]?>/g;
2207
if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2208
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2209
function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ {
2210
	var z = ({}/*:any*/);
2211
	var eq = 0, c = 0;
2212
	for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2213
	if(!skip_root) z[0] = tag.slice(0, eq);
2214
	if(eq === tag.length) return z;
2215
	var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2216
	if(m) for(i = 0; i != m.length; ++i) {
2217
		cc = m[i];
2218
		for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2219
		q = cc.slice(0,c).trim();
2220
		while(cc.charCodeAt(c+1) == 32) ++c;
2221
		quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2222
		v = cc.slice(c+1+quot, cc.length-quot);
2223
		for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2224
		if(j===q.length) {
2225
			if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2226
			z[q] = v;
2227
			z[q.toLowerCase()] = v;
2228
		}
2229
		else {
2230
			var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2231
			if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2232
			z[k] = v;
2233
			z[k.toLowerCase()] = v;
2234
		}
2235
	}
2236
	return z;
2237
}
2238
function strip_ns(x/*:string*/)/*:string*/ { return x.replace(nsregex2, "<$1"); }
2239
2240
var encodings = {
2241
	'&quot;': '"',
2242
	'&apos;': "'",
2243
	'&gt;': '>',
2244
	'&lt;': '<',
2245
	'&amp;': '&'
2246
};
2247
var rencoding = evert(encodings);
2248
//var rencstr = "&<>'\"".split("");
2249
2250
// TODO: CP remap (need to read file version to determine OS)
2251
var unescapexml/*:StringConv*/ = (function() {
2252
	/* 22.4.2.4 bstr (Basic String) */
2253
	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
2254
	return function unescapexml(text/*:string*/)/*:string*/ {
2255
		var s = text + '', i = s.indexOf("<![CDATA[");
2256
		if(i == -1) return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
2257
		var j = s.indexOf("]]>");
2258
		return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
2259
	};
2260
})();
2261
2262
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
2263
function escapexml(text/*:string*/)/*:string*/{
2264
	var s = text + '';
2265
	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
2266
}
2267
function escapexmltag(text/*:string*/)/*:string*/{ return escapexml(text).replace(/ /g,"_x0020_"); }
2268
2269
var htmlcharegex = /[\u0000-\u001f]/g;
2270
function escapehtml(text/*:string*/)/*:string*/{
2271
	var s = text + '';
2272
	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(/\n/g, "<br/>").replace(htmlcharegex,function(s) { return "&#x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + ";"; });
2273
}
2274
2275
function escapexlml(text/*:string*/)/*:string*/{
2276
	var s = text + '';
2277
	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
2278
}
2279
2280
/* TODO: handle codepages */
2281
var xlml_fixstr/*:StringConv*/ = (function() {
2282
	var entregex = /&#(\d+);/g;
2283
	function entrepl($$/*:string*/,$1/*:string*/)/*:string*/ { return String.fromCharCode(parseInt($1,10)); }
2284
	return function xlml_fixstr(str/*:string*/)/*:string*/ { return str.replace(entregex,entrepl); };
2285
})();
2286
var xlml_unfixstr/*:StringConv*/ = (function() {
2287
	return function xlml_unfixstr(str/*:string*/)/*:string*/ { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
2288
})();
2289
2290
function parsexmlbool(value/*:any*/)/*:boolean*/ {
2291
	switch(value) {
2292
		case 1: case true: case '1': case 'true': case 'TRUE': return true;
2293
		/* case '0': case 'false': case 'FALSE':*/
2294
		default: return false;
2295
	}
2296
}
2297
2298
var utf8read/*:StringConv*/ = function utf8reada(orig/*:string*/)/*:string*/ {
2299
	var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
2300
	while (i < orig.length) {
2301
		c = orig.charCodeAt(i++);
2302
		if (c < 128) { out += String.fromCharCode(c); continue; }
2303
		d = orig.charCodeAt(i++);
2304
		if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
2305
		e = orig.charCodeAt(i++);
2306
		if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
2307
		f = orig.charCodeAt(i++);
2308
		w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
2309
		out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
2310
		out += String.fromCharCode(0xDC00 + (w&1023));
2311
	}
2312
	return out;
2313
};
2314
2315
var utf8write/*:StringConv*/ = function(orig/*:string*/)/*:string*/ {
2316
	var out/*:Array<string>*/ = [], i = 0, c = 0, d = 0;
2317
	while(i < orig.length) {
2318
		c = orig.charCodeAt(i++);
2319
		switch(true) {
2320
			case c < 128: out.push(String.fromCharCode(c)); break;
2321
			case c < 2048:
2322
				out.push(String.fromCharCode(192 + (c >> 6)));
2323
				out.push(String.fromCharCode(128 + (c & 63)));
2324
				break;
2325
			case c >= 55296 && c < 57344:
2326
				c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
2327
				out.push(String.fromCharCode(240 + ((d >>18) & 7)));
2328
				out.push(String.fromCharCode(144 + ((d >>12) & 63)));
2329
				out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
2330
				out.push(String.fromCharCode(128 + (d & 63)));
2331
				break;
2332
			default:
2333
				out.push(String.fromCharCode(224 + (c >> 12)));
2334
				out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
2335
				out.push(String.fromCharCode(128 + (c & 63)));
2336
		}
2337
	}
2338
	return out.join("");
2339
};
2340
2341
if(has_buf) {
2342
	var utf8readb = function utf8readb(data) {
2343
		var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
2344
		for(i = 0; i < data.length; i+=j) {
2345
			j = 1;
2346
			if((c=data.charCodeAt(i)) < 128) w = c;
2347
			else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
2348
			else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
2349
			else { j = 4;
2350
				w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
2351
				w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
2352
			}
2353
			if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
2354
			out[k++] = w%256; out[k++] = w>>>8;
2355
		}
2356
		return out.slice(0,k).toString('ucs2');
2357
	};
2358
	var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
2359
	if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
2360
	// $FlowIgnore
2361
	var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
2362
	if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
2363
2364
	// $FlowIgnore
2365
	utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
2366
}
2367
2368
// matches <foo>...</foo> extracts content
2369
var matchtag = (function() {
2370
	var mtcache/*:{[k:string]:RegExp}*/ = ({}/*:any*/);
2371
	return function matchtag(f/*:string*/,g/*:?string*/)/*:RegExp*/ {
2372
		var t = f+"|"+(g||"");
2373
		if(mtcache[t]) return mtcache[t];
2374
		return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||"")/*:any*/)));
2375
	};
2376
})();
2377
2378
var htmldecode/*:{(s:string):string}*/ = (function() {
2379
	var entities/*:Array<[RegExp, string]>*/ = [
2380
		['nbsp', ' '], ['middot', '·'],
2381
		['quot', '"'], ['apos', "'"], ['gt',   '>'], ['lt',   '<'], ['amp',  '&']
2382
	].map(function(x/*:[string, string]*/) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; });
2383
	return function htmldecode(str/*:string*/)/*:string*/ {
2384
		var o = str.replace(/^[\t\n\r ]+/, "").replace(/[\t\n\r ]+$/,"").replace(/[\t\n\r ]+/g, " ").replace(/<\s*[bB][rR]\s*\/?>/g,"\n").replace(/<[^>]*>/g,"");
2385
		for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
2386
		return o;
2387
	};
2388
})();
2389
2390
var vtregex = (function(){ var vt_cache = {};
2391
	return function vt_regex(bt) {
2392
		if(vt_cache[bt] !== undefined) return vt_cache[bt];
2393
		return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
2394
};})();
2395
var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
2396
function parseVector(data/*:string*/, opts)/*:Array<{v:string,t:string}>*/ {
2397
	var h = parsexmltag(data);
2398
2399
	var matches/*:Array<string>*/ = data.match(vtregex(h.baseType))||[];
2400
	var res/*:Array<any>*/ = [];
2401
	if(matches.length != h.size) {
2402
		if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
2403
		return res;
2404
	}
2405
	matches.forEach(function(x/*:string*/) {
2406
		var v = x.replace(vtvregex,"").match(vtmregex);
2407
		if(v) res.push({v:utf8read(v[2]), t:v[1]});
2408
	});
2409
	return res;
2410
}
2411
2412
var wtregex = /(^\s|\s$|\n)/;
2413
function writetag(f/*:string*/,g/*:string*/)/*:string*/ { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
2414
2415
function wxt_helper(h)/*:string*/ { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
2416
function writextag(f/*:string*/,g/*:?string*/,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
2417
2418
function write_w3cdtf(d/*:Date*/, t/*:?boolean*/)/*:string*/ { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
2419
2420
function write_vt(s)/*:string*/ {
2421
	switch(typeof s) {
2422
		case 'string': return writextag('vt:lpwstr', s);
2423
		case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
2424
		case 'boolean': return writextag('vt:bool',s?'true':'false');
2425
	}
2426
	if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
2427
	throw new Error("Unable to serialize " + s);
2428
}
2429
2430
var XMLNS = ({
2431
	'dc': 'http://purl.org/dc/elements/1.1/',
2432
	'dcterms': 'http://purl.org/dc/terms/',
2433
	'dcmitype': 'http://purl.org/dc/dcmitype/',
2434
	'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
2435
	'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
2436
	'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
2437
	'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
2438
	'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
2439
	'xsd': 'http://www.w3.org/2001/XMLSchema'
2440
}/*:any*/);
2441
2442
XMLNS.main = [
2443
	'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
2444
	'http://purl.oclc.org/ooxml/spreadsheetml/main',
2445
	'http://schemas.microsoft.com/office/excel/2006/main',
2446
	'http://schemas.microsoft.com/office/excel/2006/2'
2447
];
2448
2449
var XLMLNS = ({
2450
	'o':    'urn:schemas-microsoft-com:office:office',
2451
	'x':    'urn:schemas-microsoft-com:office:excel',
2452
	'ss':   'urn:schemas-microsoft-com:office:spreadsheet',
2453
	'dt':   'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
2454
	'mv':   'http://macVmlSchemaUri',
2455
	'v':    'urn:schemas-microsoft-com:vml',
2456
	'html': 'http://www.w3.org/TR/REC-html40'
2457
}/*:any*/);
2458
function read_double_le(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ {
2459
	var s = 1 - 2 * (b[idx + 7] >>> 7);
2460
	var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
2461
	var m = (b[idx+6]&0x0f);
2462
	for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
2463
	if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
2464
	if(e == 0) e = -1022;
2465
	else { e -= 1023; m += Math.pow(2,52); }
2466
	return s * Math.pow(2, e - 52) * m;
2467
}
2468
2469
function write_double_le(b/*:RawBytes|CFBlob*/, v/*:number*/, idx/*:number*/) {
2470
	var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
2471
	var av = bs ? (-v) : v;
2472
	if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
2473
	else if(av == 0) e = m = 0;
2474
	else {
2475
		e = Math.floor(Math.log(av) / Math.LN2);
2476
		m = av * Math.pow(2, 52 - e);
2477
		if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
2478
		else { m -= Math.pow(2,52); e+=1023; }
2479
	}
2480
	for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
2481
	b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
2482
	b[idx + 7] = (e >> 4) | bs;
2483
}
2484
2485
var __toBuffer = function(bufs/*:Array<Array<RawBytes> >*/)/*:RawBytes*/ { var x=[],w=10240; for(var i=0;i<bufs[0].length;++i) if(bufs[0][i]) for(var j=0,L=bufs[0][i].length;j<L;j+=w) x.push.apply(x, bufs[0][i].slice(j,j+w)); return x; };
2486
var ___toBuffer = __toBuffer;
2487
var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join("").replace(chr0,''); };
2488
var ___utf16le = __utf16le;
2489
var __hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<s+l; ++i) ss.push(("0" + b[i].toString(16)).slice(-2)); return ss.join(""); };
2490
var ___hexlify = __hexlify;
2491
var __utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
2492
var ___utf8 = __utf8;
2493
var __lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
2494
var ___lpstr = __lpstr;
2495
var __cpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
2496
var ___cpstr = __cpstr;
2497
var __lpwstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
2498
var ___lpwstr = __lpwstr;
2499
var __lpp4, ___lpp4;
2500
__lpp4 = ___lpp4 = function lpp4_(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
2501
var __8lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
2502
var ___8lpp4 = __8lpp4;
2503
var __double, ___double;
2504
__double = ___double = function(b/*:RawBytes|CFBlob*/, idx/*:number*/) { return read_double_le(b, idx);};
2505
var is_buf = function is_buf_a(a) { return Array.isArray(a); };
2506
2507
if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
2508
	__utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
2509
	__hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { return Buffer.isBuffer(b)/*:: && b instanceof Buffer*/ ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
2510
	__lpstr = function lpstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
2511
	__cpstr = function cpstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___cpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
2512
	__lpwstr = function lpwstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpwstr(b, i); var len = 2*b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len-1);};
2513
	__lpp4 = function lpp4_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len);};
2514
	__8lpp4 = function lpp4_8b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___8lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf8',i+4,i+4+len);};
2515
	__utf8 = function utf8_b(b/*:RawBytes|CFBlob*/, s/*:number*/, e/*:number*/) { return (Buffer.isBuffer(b)/*:: && (b instanceof Buffer)*/) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
2516
	__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
2517
	bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
2518
	__double = function double_(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(Buffer.isBuffer(b)/*::&& b instanceof Buffer*/) return b.readDoubleLE(i); return ___double(b,i); };
2519
	is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
2520
}
2521
2522
/* from js-xls */
2523
if(typeof cptable !== 'undefined') {
2524
	__utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
2525
	__utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(65001, b.slice(s,e)); };
2526
	__lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_ansi, b.slice(i+4, i+4+len-1)) : "";};
2527
	__cpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";};
2528
	__lpwstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = 2*__readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len-1)) : "";};
2529
	__lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
2530
	__8lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
2531
}
2532
2533
var __readUInt8 = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx]; };
2534
var __readUInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+1]*(1<<8))+b[idx]; };
2535
var __readInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
2536
var __readUInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
2537
var __readInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
2538
var __readInt32BE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
2539
2540
function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
2541
	var o="", oI/*:: :number = 0*/, oR, oo=[], w, vv, i, loc;
2542
	switch(t) {
2543
		case 'dbcs':
2544
			loc = this.l;
2545
			if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
2546
			else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
2547
			size *= 2;
2548
			break;
2549
2550
		case 'utf8': o = __utf8(this, this.l, this.l + size); break;
2551
		case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
2552
2553
		case 'wstr':
2554
			if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
2555
			else return ReadShift.call(this, size, 'dbcs');
2556
			size = 2 * size; break;
2557
2558
		/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
2559
		case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
2560
		case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
2561
		/* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
2562
		case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
2563
		/* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
2564
		case 'lpp4': size = 4 +  __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
2565
		/* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
2566
		case '8lpp4': size = 4 +  __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
2567
2568
		case 'cstr': size = 0; o = "";
2569
			while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
2570
			o = oo.join(""); break;
2571
		case '_wstr': size = 0; o = "";
2572
			while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
2573
			size+=2; o = oo.join(""); break;
2574
2575
		/* sbcs and dbcs support continue records in the SST way TODO codepages */
2576
		case 'dbcs-cont': o = ""; loc = this.l;
2577
			for(i = 0; i < size; ++i) {
2578
				if(this.lens && this.lens.indexOf(loc) !== -1) {
2579
					w = __readUInt8(this, loc);
2580
					this.l = loc + 1;
2581
					vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
2582
					return oo.join("") + vv;
2583
				}
2584
				oo.push(_getchar(__readUInt16LE(this, loc)));
2585
				loc+=2;
2586
			} o = oo.join(""); size *= 2; break;
2587
2588
		case 'cpstr':
2589
			if(typeof cptable !== 'undefined') {
2590
				o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
2591
				break;
2592
			}
2593
		/* falls through */
2594
		case 'sbcs-cont': o = ""; loc = this.l;
2595
			for(i = 0; i != size; ++i) {
2596
				if(this.lens && this.lens.indexOf(loc) !== -1) {
2597
					w = __readUInt8(this, loc);
2598
					this.l = loc + 1;
2599
					vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
2600
					return oo.join("") + vv;
2601
				}
2602
				oo.push(_getchar(__readUInt8(this, loc)));
2603
				loc+=1;
2604
			} o = oo.join(""); break;
2605
2606
		default:
2607
	switch(size) {
2608
		case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
2609
		case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
2610
		case 4: case -4:
2611
			if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
2612
			else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
2613
		case 8: case -8:
2614
			if(t === 'f') {
2615
				if(size == 8) oR = __double(this, this.l);
2616
				else oR = __double([this[this.l+7],this[this.l+6],this[this.l+5],this[this.l+4],this[this.l+3],this[this.l+2],this[this.l+1],this[this.l+0]], 0);
2617
				this.l += 8; return oR;
2618
			} else size = 8;
2619
		/* falls through */
2620
		case 16: o = __hexlify(this, this.l, size); break;
2621
	}}
2622
	this.l+=size; return o;
2623
}
2624
2625
var __writeUInt32LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); };
2626
var __writeInt32LE  = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); };
2627
var __writeUInt16LE = function(b/*:RawBytes|CFBlob*/, val/*:number*/, idx/*:number*/)/*:void*/ { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
2628
2629
function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/ {
2630
	var size = 0, i = 0;
2631
	if(f === 'dbcs') {
2632
		/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
2633
		for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
2634
		size = 2 * val.length;
2635
	} else if(f === 'sbcs') {
2636
		/* TODO: codepage */
2637
		/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
2638
		val = val.replace(/[^\x00-\x7F]/g, "_");
2639
		/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
2640
		for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
2641
		size = val.length;
2642
	} else if(f === 'hex') {
2643
		for(; i < t; ++i) {
2644
			/*:: if(typeof val !== "string") throw new Error("unreachable"); */
2645
			this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
2646
		} return this;
2647
	} else if(f === 'utf16le') {
2648
			/*:: if(typeof val !== "string") throw new Error("unreachable"); */
2649
			var end/*:number*/ = Math.min(this.l + t, this.length);
2650
			for(i = 0; i < Math.min(val.length, t); ++i) {
2651
				var cc = val.charCodeAt(i);
2652
				this[this.l++] = (cc & 0xff);
2653
				this[this.l++] = (cc >> 8);
2654
			}
2655
			while(this.l < end) this[this.l++] = 0;
2656
			return this;
2657
	} else /*:: if(typeof val === 'number') */ switch(t) {
2658
		case  1: size = 1; this[this.l] = val&0xFF; break;
2659
		case  2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
2660
		case  3: size = 3; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; val >>>= 8; this[this.l+2] = val&0xFF; break;
2661
		case  4: size = 4; __writeUInt32LE(this, val, this.l); break;
2662
		case  8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
2663
		/* falls through */
2664
		case 16: break;
2665
		case -4: size = 4; __writeInt32LE(this, val, this.l); break;
2666
	}
2667
	this.l += size; return this;
2668
}
2669
2670
function CheckField(hexstr/*:string*/, fld/*:string*/)/*:void*/ {
2671
	var m = __hexlify(this,this.l,hexstr.length>>1);
2672
	if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
2673
	this.l += hexstr.length>>1;
2674
}
2675
2676
function prep_blob(blob, pos/*:number*/)/*:void*/ {
2677
	blob.l = pos;
2678
	blob.read_shift = /*::(*/ReadShift/*:: :any)*/;
2679
	blob.chk = CheckField;
2680
	blob.write_shift = WriteShift;
2681
}
2682
2683
function parsenoop(blob, length/*:: :number, opts?:any */) { blob.l += length; }
2684
2685
function new_buf(sz/*:number*/)/*:Block*/ {
2686
	var o = new_raw_buf(sz);
2687
	prep_blob(o, 0);
2688
	return o;
2689
}
2690
2691
/* [MS-XLSB] 2.1.4 Record */
2692
function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) {
2693
	if(!data) return;
2694
	var tmpbyte, cntbyte, length;
2695
	prep_blob(data, data.l || 0);
2696
	var L = data.length, RT = 0, tgt = 0;
2697
	while(data.l < L) {
2698
		RT = data.read_shift(1);
2699
		if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
2700
		var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
2701
		tmpbyte = data.read_shift(1);
2702
		length = tmpbyte & 0x7F;
2703
		for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
2704
		tgt = data.l + length;
2705
		var d = (R.f||parsenoop)(data, length, opts);
2706
		data.l = tgt;
2707
		if(cb(d, R.n, RT)) return;
2708
	}
2709
}
2710
2711
/* control buffer usage for fixed-length buffers */
2712
function buf_array()/*:BufArray*/ {
2713
	var bufs/*:Array<Block>*/ = [], blksz = has_buf ? 256 : 2048;
2714
	var newblk = function ba_newblk(sz/*:number*/)/*:Block*/ {
2715
		var o/*:Block*/ = (new_buf(sz)/*:any*/);
2716
		prep_blob(o, 0);
2717
		return o;
2718
	};
2719
2720
	var curbuf/*:Block*/ = newblk(blksz);
2721
2722
	var endbuf = function ba_endbuf() {
2723
		if(!curbuf) return;
2724
		if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
2725
		if(curbuf.length > 0) bufs.push(curbuf);
2726
		curbuf = null;
2727
	};
2728
2729
	var next = function ba_next(sz/*:number*/)/*:Block*/ {
2730
		if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
2731
		endbuf();
2732
		return (curbuf = newblk(Math.max(sz+1, blksz)));
2733
	};
2734
2735
	var end = function ba_end() {
2736
		endbuf();
2737
		return __toBuffer([bufs]);
2738
	};
2739
2740
	var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
2741
2742
	return ({ next:next, push:push, end:end, _bufs:bufs }/*:any*/);
2743
}
2744
2745
function write_record(ba/*:BufArray*/, type/*:string*/, payload, length/*:?number*/) {
2746
	var t/*:number*/ = +XLSBRE[type], l;
2747
	if(isNaN(t)) return; // TODO: throw something here?
2748
	if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
2749
	l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
2750
	if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
2751
	var o = ba.next(l);
2752
	if(t <= 0x7F) o.write_shift(1, t);
2753
	else {
2754
		o.write_shift(1, (t & 0x7F) + 0x80);
2755
		o.write_shift(1, (t >> 7));
2756
	}
2757
	for(var i = 0; i != 4; ++i) {
2758
		if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
2759
		else { o.write_shift(1, length); break; }
2760
	}
2761
	if(/*:: length != null &&*/length > 0 && is_buf(payload)) ba.push(payload);
2762
}
2763
/* XLS ranges enforced */
2764
function shift_cell_xls(cell/*:CellAddress*/, tgt/*:any*/, opts/*:?any*/)/*:CellAddress*/ {
2765
	var out = dup(cell);
2766
	if(tgt.s) {
2767
		if(out.cRel) out.c += tgt.s.c;
2768
		if(out.rRel) out.r += tgt.s.r;
2769
	} else {
2770
		if(out.cRel) out.c += tgt.c;
2771
		if(out.rRel) out.r += tgt.r;
2772
	}
2773
	if(!opts || opts.biff < 12) {
2774
		while(out.c >= 0x100) out.c -= 0x100;
2775
		while(out.r >= 0x10000) out.r -= 0x10000;
2776
	}
2777
	return out;
2778
}
2779
2780
function shift_range_xls(cell, range, opts) {
2781
	var out = dup(cell);
2782
	out.s = shift_cell_xls(out.s, range.s, opts);
2783
	out.e = shift_cell_xls(out.e, range.s, opts);
2784
	return out;
2785
}
2786
2787
function encode_cell_xls(c/*:CellAddress*/, biff/*:number*/)/*:string*/ {
2788
	if(c.cRel && c.c < 0) { c = dup(c); c.c += (biff > 8) ? 0x4000 : 0x100; }
2789
	if(c.rRel && c.r < 0) { c = dup(c); c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
2790
	var s = encode_cell(c);
2791
	if(c.cRel === 0) s = fix_col(s);
2792
	if(c.rRel === 0) s = fix_row(s);
2793
	return s;
2794
}
2795
2796
function encode_range_xls(r, opts)/*:string*/ {
2797
	if(r.s.r == 0 && !r.s.rRel) {
2798
		if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
2799
			return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
2800
		}
2801
	}
2802
	if(r.s.c == 0 && !r.s.cRel) {
2803
		if(r.e.c == (opts.biff >= 12 ? 0xFFFF : 0xFF) && !r.e.cRel) {
2804
			return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
2805
		}
2806
	}
2807
	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
2808
}
2809
var OFFCRYPTO = {};
2810
2811
var make_offcrypto = function(O, _crypto) {
2812
	var crypto;
2813
	if(typeof _crypto !== 'undefined') crypto = _crypto;
2814
	else if(typeof require !== 'undefined') {
2815
		try { crypto = require('crypto'); }
2816
		catch(e) { crypto = null; }
2817
	}
2818
2819
	O.rc4 = function(key, data) {
2820
		var S = new Array(256);
2821
		var c = 0, i = 0, j = 0, t = 0;
2822
		for(i = 0; i != 256; ++i) S[i] = i;
2823
		for(i = 0; i != 256; ++i) {
2824
			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
2825
			t = S[i]; S[i] = S[j]; S[j] = t;
2826
		}
2827
		// $FlowIgnore
2828
		i = j = 0; var out = Buffer(data.length);
2829
		for(c = 0; c != data.length; ++c) {
2830
			i = (i + 1)&255;
2831
			j = (j + S[i])%256;
2832
			t = S[i]; S[i] = S[j]; S[j] = t;
2833
			out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
2834
		}
2835
		return out;
2836
	};
2837
2838
	O.md5 = function(hex) {
2839
		if(!crypto) throw new Error("Unsupported crypto");
2840
		return crypto.createHash('md5').update(hex).digest('hex');
2841
	};
2842
};
2843
/*:: declare var crypto:any; */
2844
/*global crypto:true */
2845
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
2846
2847
function decode_row(rowstr/*:string*/)/*:number*/ { return parseInt(unfix_row(rowstr),10) - 1; }
2848
function encode_row(row/*:number*/)/*:string*/ { return "" + (row + 1); }
2849
function fix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
2850
function unfix_row(cstr/*:string*/)/*:string*/ { return cstr.replace(/\$(\d+)$/,"$1"); }
2851
2852
function decode_col(colstr/*:string*/)/*:number*/ { var c = unfix_col(colstr), d = 0, i = 0; for(; i !== c.length; ++i) d = 26*d + c.charCodeAt(i) - 64; return d - 1; }
2853
function encode_col(col/*:number*/)/*:string*/ { var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
2854
function fix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^([A-Z])/,"$$$1"); }
2855
function unfix_col(cstr/*:string*/)/*:string*/ { return cstr.replace(/^\$([A-Z])/,"$1"); }
2856
2857
function split_cell(cstr/*:string*/)/*:Array<string>*/ { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
2858
function decode_cell(cstr/*:string*/)/*:CellAddress*/ { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
2859
function encode_cell(cell/*:CellAddress*/)/*:string*/ { return encode_col(cell.c) + encode_row(cell.r); }
2860
function decode_range(range/*:string*/)/*:Range*/ { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
2861
/*# if only one arg, it is assumed to be a Range.  If 2 args, both are cell addresses */
2862
function encode_range(cs/*:CellAddrSpec|Range*/,ce/*:?CellAddrSpec*/)/*:string*/ {
2863
	if(typeof ce === 'undefined' || typeof ce === 'number') {
2864
/*:: if(!(cs instanceof Range)) throw "unreachable"; */
2865
		return encode_range(cs.s, cs.e);
2866
	}
2867
/*:: if((cs instanceof Range)) throw "unreachable"; */
2868
	if(typeof cs !== 'string') cs = encode_cell((cs/*:any*/));
2869
	if(typeof ce !== 'string') ce = encode_cell((ce/*:any*/));
2870
/*:: if(typeof cs !== 'string') throw "unreachable"; */
2871
/*:: if(typeof ce !== 'string') throw "unreachable"; */
2872
	return cs == ce ? cs : cs + ":" + ce;
2873
}
2874
2875
function safe_decode_range(range/*:string*/)/*:Range*/ {
2876
	var o = {s:{c:0,r:0},e:{c:0,r:0}};
2877
	var idx = 0, i = 0, cc = 0;
2878
	var len = range.length;
2879
	for(idx = 0; i < len; ++i) {
2880
		if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
2881
		idx = 26*idx + cc;
2882
	}
2883
	o.s.c = --idx;
2884
2885
	for(idx = 0; i < len; ++i) {
2886
		if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
2887
		idx = 10*idx + cc;
2888
	}
2889
	o.s.r = --idx;
2890
2891
	if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
2892
2893
	for(idx = 0; i != len; ++i) {
2894
		if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
2895
		idx = 26*idx + cc;
2896
	}
2897
	o.e.c = --idx;
2898
2899
	for(idx = 0; i != len; ++i) {
2900
		if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
2901
		idx = 10*idx + cc;
2902
	}
2903
	o.e.r = --idx;
2904
	return o;
2905
}
2906
2907
function safe_format_cell(cell/*:Cell*/, v/*:any*/) {
2908
	var q = (cell.t == 'd' && v instanceof Date);
2909
	if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
2910
	try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0),  q ? datenum(v) : v)); } catch(e) { return ''+v; }
2911
}
2912
2913
function format_cell(cell/*:Cell*/, v/*:any*/, o/*:any*/) {
2914
	if(cell == null || cell.t == null || cell.t == 'z') return "";
2915
	if(cell.w !== undefined) return cell.w;
2916
	if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
2917
	if(v == undefined) return safe_format_cell(cell, cell.v);
2918
	return safe_format_cell(cell, v);
2919
}
2920
2921
function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
2922
	var n = opts && opts.sheet ? opts.sheet : "Sheet1";
2923
	var sheets = {}; sheets[n] = sheet;
2924
	return { SheetNames: [n], Sheets: sheets };
2925
}
2926
2927
function sheet_add_aoa(_ws/*:?Worksheet*/, data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ {
2928
	var o = opts || {};
2929
	var dense = _ws ? Array.isArray(_ws) : o.dense;
2930
	if(DENSE != null && dense == null) dense = DENSE;
2931
	var ws/*:Worksheet*/ = _ws || (dense ? ([]/*:any*/) : ({}/*:any*/));
2932
	var _R = 0, _C = 0;
2933
	if(ws && o.origin != null) {
2934
		if(typeof o.origin == 'number') _R = o.origin;
2935
		else {
2936
			var _origin/*:CellAddress*/ = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
2937
			_R = _origin.r; _C = _origin.c;
2938
		}
2939
	}
2940
	var range/*:Range*/ = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}}/*:any*/);
2941
	if(ws['!ref']) {
2942
		var _range = safe_decode_range(ws['!ref']);
2943
		range.s.c = _range.s.c;
2944
		range.s.r = _range.s.r;
2945
		range.e.c = Math.max(range.e.c, _range.e.c);
2946
		range.e.r = Math.max(range.e.r, _range.e.r);
2947
		if(_R == -1) range.e.r = _R = _range.e.r + 1;
2948
	}
2949
	for(var R = 0; R != data.length; ++R) {
2950
		if(!data[R]) continue;
2951
		if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
2952
		for(var C = 0; C != data[R].length; ++C) {
2953
			if(typeof data[R][C] === 'undefined') continue;
2954
			var cell/*:Cell*/ = ({v: data[R][C] }/*:any*/);
2955
			if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
2956
			var __R = _R + R, __C = _C + C;
2957
			if(range.s.r > __R) range.s.r = __R;
2958
			if(range.s.c > __C) range.s.c = __C;
2959
			if(range.e.r < __R) range.e.r = __R;
2960
			if(range.e.c < __C) range.e.c = __C;
2961
			if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.cellStubs) continue; else cell.t = 'z'; }
2962
			else if(typeof cell.v === 'number') cell.t = 'n';
2963
			else if(typeof cell.v === 'boolean') cell.t = 'b';
2964
			else if(cell.v instanceof Date) {
2965
				cell.z = o.dateNF || SSF._table[14];
2966
				if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
2967
				else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
2968
			}
2969
			else cell.t = 's';
2970
			if(dense) {
2971
				if(!ws[__R]) ws[__R] = [];
2972
				ws[__R][__C] = cell;
2973
			} else {
2974
				var cell_ref = encode_cell(({c:__C,r:__R}/*:any*/));
2975
				ws[cell_ref] = cell;
2976
			}
2977
		}
2978
	}
2979
	if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
2980
	return ws;
2981
}
2982
function aoa_to_sheet(data/*:AOA*/, opts/*:?any*/)/*:Worksheet*/ { return sheet_add_aoa(null, data, opts); }
2983
2984
function write_UInt32LE(x/*:number*/, o) {
2985
	if(!o) o = new_buf(4);
2986
	o.write_shift(4, x);
2987
	return o;
2988
}
2989
2990
/* [MS-XLSB] 2.5.168 */
2991
function parse_XLWideString(data/*::, length*/)/*:string*/ {
2992
	var cchCharacters = data.read_shift(4);
2993
	return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
2994
}
2995
function write_XLWideString(data/*:string*/, o) {
2996
	var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
2997
	o.write_shift(4, data.length);
2998
	if(data.length > 0) o.write_shift(0, data, 'dbcs');
2999
	return _null ? o.slice(0, o.l) : o;
3000
}
3001
3002
/* [MS-XLSB] 2.5.143 */
3003
function parse_StrRun(data) {
3004
	return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
3005
}
3006
function write_StrRun(run, o) {
3007
	if(!o) o = new_buf(4);
3008
	o.write_shift(2, run.ich || 0);
3009
	o.write_shift(2, run.ifnt || 0);
3010
	return o;
3011
}
3012
3013
/* [MS-XLSB] 2.5.121 */
3014
function parse_RichStr(data, length/*:number*/)/*:XLString*/ {
3015
	var start = data.l;
3016
	var flags = data.read_shift(1);
3017
	var str = parse_XLWideString(data);
3018
	var rgsStrRun = [];
3019
	var z = ({ t: str, h: str }/*:any*/);
3020
	if((flags & 1) !== 0) { /* fRichStr */
3021
		/* TODO: formatted string */
3022
		var dwSizeStrRun = data.read_shift(4);
3023
		for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
3024
		z.r = rgsStrRun;
3025
	}
3026
	else z.r = [{ich:0, ifnt:0}];
3027
	//if((flags & 2) !== 0) { /* fExtStr */
3028
	//	/* TODO: phonetic string */
3029
	//}
3030
	data.l = start + length;
3031
	return z;
3032
}
3033
function write_RichStr(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
3034
	/* TODO: formatted string */
3035
	var _null = false; if(o == null) { _null = true; o = new_buf(15+4*str.t.length); }
3036
	o.write_shift(1,0);
3037
	write_XLWideString(str.t, o);
3038
	return _null ? o.slice(0, o.l) : o;
3039
}
3040
/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
3041
var parse_BrtCommentText = parse_RichStr;
3042
function write_BrtCommentText(str/*:XLString*/, o/*:?Block*/)/*:Block*/ {
3043
	/* TODO: formatted string */
3044
	var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
3045
	o.write_shift(1,1);
3046
	write_XLWideString(str.t, o);
3047
	o.write_shift(4,1);
3048
	write_StrRun({ich:0,ifnt:0}, o);
3049
	return _null ? o.slice(0, o.l) : o;
3050
}
3051
3052
/* [MS-XLSB] 2.5.9 */
3053
function parse_XLSBCell(data)/*:any*/ {
3054
	var col = data.read_shift(4);
3055
	var iStyleRef = data.read_shift(2);
3056
	iStyleRef += data.read_shift(1) <<16;
3057
	data.l++; //var fPhShow = data.read_shift(1);
3058
	return { c:col, iStyleRef: iStyleRef };
3059
}
3060
function write_XLSBCell(cell/*:any*/, o/*:?Block*/) {
3061
	if(o == null) o = new_buf(8);
3062
	o.write_shift(-4, cell.c);
3063
	o.write_shift(3, cell.iStyleRef || cell.s);
3064
	o.write_shift(1, 0); /* fPhShow */
3065
	return o;
3066
}
3067
3068
3069
/* [MS-XLSB] 2.5.21 */
3070
var parse_XLSBCodeName = parse_XLWideString;
3071
var write_XLSBCodeName = write_XLWideString;
3072
3073
/* [MS-XLSB] 2.5.166 */
3074
function parse_XLNullableWideString(data/*::, length*/)/*:string*/ {
3075
	var cchCharacters = data.read_shift(4);
3076
	return cchCharacters === 0 || cchCharacters === 0xFFFFFFFF ? "" : data.read_shift(cchCharacters, 'dbcs');
3077
}
3078
function write_XLNullableWideString(data/*:string*/, o) {
3079
	var _null = false; if(o == null) { _null = true; o = new_buf(127); }
3080
	o.write_shift(4, data.length > 0 ? data.length : 0xFFFFFFFF);
3081
	if(data.length > 0) o.write_shift(0, data, 'dbcs');
3082
	return _null ? o.slice(0, o.l) : o;
3083
}
3084
3085
/* [MS-XLSB] 2.5.165 */
3086
var parse_XLNameWideString = parse_XLWideString;
3087
//var write_XLNameWideString = write_XLWideString;
3088
3089
/* [MS-XLSB] 2.5.114 */
3090
var parse_RelID = parse_XLNullableWideString;
3091
var write_RelID = write_XLNullableWideString;
3092
3093
3094
/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
3095
function parse_RkNumber(data)/*:number*/ {
3096
	var b = data.slice(data.l, data.l+4);
3097
	var fX100 = (b[0] & 1), fInt = (b[0] & 2);
3098
	data.l+=4;
3099
	b[0] &= 0xFC; // b[0] &= ~3;
3100
	var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
3101
	return fX100 ? (RK/100) : RK;
3102
}
3103
function write_RkNumber(data/*:number*/, o) {
3104
	if(o == null) o = new_buf(4);
3105
	var fX100 = 0, fInt = 0, d100 = data * 100;
3106
	if((data == (data | 0)) && (data >= -(1<<29)) && (data < (1 << 29))) { fInt = 1; }
3107
	else if((d100 == (d100 | 0)) && (d100 >= -(1<<29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
3108
	if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
3109
	else throw new Error("unsupported RkNumber " + data); // TODO
3110
}
3111
3112
3113
/* [MS-XLSB] 2.5.117 RfX */
3114
function parse_RfX(data /*::, length*/)/*:Range*/ {
3115
	var cell/*:Range*/ = ({s: {}, e: {}}/*:any*/);
3116
	cell.s.r = data.read_shift(4);
3117
	cell.e.r = data.read_shift(4);
3118
	cell.s.c = data.read_shift(4);
3119
	cell.e.c = data.read_shift(4);
3120
	return cell;
3121
}
3122
function write_RfX(r/*:Range*/, o) {
3123
	if(!o) o = new_buf(16);
3124
	o.write_shift(4, r.s.r);
3125
	o.write_shift(4, r.e.r);
3126
	o.write_shift(4, r.s.c);
3127
	o.write_shift(4, r.e.c);
3128
	return o;
3129
}
3130
3131
/* [MS-XLSB] 2.5.153 UncheckedRfX */
3132
var parse_UncheckedRfX = parse_RfX;
3133
var write_UncheckedRfX = write_RfX;
3134
3135
/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
3136
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
3137
function parse_Xnum(data/*::, length*/) { return data.read_shift(8, 'f'); }
3138
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
3139
3140
/* [MS-XLSB] 2.5.97.2 */
3141
var BErr = {
3142
	/*::[*/0x00/*::]*/: "#NULL!",
3143
	/*::[*/0x07/*::]*/: "#DIV/0!",
3144
	/*::[*/0x0F/*::]*/: "#VALUE!",
3145
	/*::[*/0x17/*::]*/: "#REF!",
3146
	/*::[*/0x1D/*::]*/: "#NAME?",
3147
	/*::[*/0x24/*::]*/: "#NUM!",
3148
	/*::[*/0x2A/*::]*/: "#N/A",
3149
	/*::[*/0x2B/*::]*/: "#GETTING_DATA",
3150
	/*::[*/0xFF/*::]*/: "#WTF?"
3151
};
3152
var RBErr = evert_num(BErr);
3153
3154
/* [MS-XLSB] 2.4.324 BrtColor */
3155
function parse_BrtColor(data/*::, length*/) {
3156
	var out = {};
3157
	var d = data.read_shift(1);
3158
3159
	//var fValidRGB = d & 1;
3160
	var xColorType = d >>> 1;
3161
3162
	var index = data.read_shift(1);
3163
	var nTS = data.read_shift(2, 'i');
3164
	var bR = data.read_shift(1);
3165
	var bG = data.read_shift(1);
3166
	var bB = data.read_shift(1);
3167
	data.l++; //var bAlpha = data.read_shift(1);
3168
3169
	switch(xColorType) {
3170
		case 0: out.auto = 1; break;
3171
		case 1:
3172
			out.index = index;
3173
			var icv = XLSIcv[index];
3174
			/* automatic pseudo index 81 */
3175
			if(icv) out.rgb = rgb2Hex(icv);
3176
			break;
3177
		case 2:
3178
			/* if(!fValidRGB) throw new Error("invalid"); */
3179
			out.rgb = rgb2Hex([bR, bG, bB]);
3180
			break;
3181
		case 3: out.theme = index; break;
3182
	}
3183
	if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
3184
3185
	return out;
3186
}
3187
function write_BrtColor(color, o) {
3188
	if(!o) o = new_buf(8);
3189
	if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
3190
	if(color.index) {
3191
		o.write_shift(1, 0x02);
3192
		o.write_shift(1, color.index);
3193
	} else if(color.theme) {
3194
		o.write_shift(1, 0x06);
3195
		o.write_shift(1, color.theme);
3196
	} else {
3197
		o.write_shift(1, 0x05);
3198
		o.write_shift(1, 0);
3199
	}
3200
	var nTS = color.tint || 0;
3201
	if(nTS > 0) nTS *= 32767;
3202
	else if(nTS < 0) nTS *= 32768;
3203
	o.write_shift(2, nTS);
3204
	if(!color.rgb) {
3205
		o.write_shift(2, 0);
3206
		o.write_shift(1, 0);
3207
		o.write_shift(1, 0);
3208
	} else {
3209
		var rgb = (color.rgb || 'FFFFFF');
3210
		o.write_shift(1, parseInt(rgb.slice(0,2),16));
3211
		o.write_shift(1, parseInt(rgb.slice(2,4),16));
3212
		o.write_shift(1, parseInt(rgb.slice(4,6),16));
3213
		o.write_shift(1, 0xFF);
3214
	}
3215
	return o;
3216
}
3217
3218
/* [MS-XLSB] 2.5.52 */
3219
function parse_FontFlags(data/*::, length, opts*/) {
3220
	var d = data.read_shift(1);
3221
	data.l++;
3222
	var out = {
3223
		/* fBold: d & 0x01 */
3224
		fItalic: d & 0x02,
3225
		/* fUnderline: d & 0x04 */
3226
		fStrikeout: d & 0x08,
3227
		fOutline: d & 0x10,
3228
		fShadow: d & 0x20,
3229
		fCondense: d & 0x40,
3230
		fExtend: d & 0x80
3231
	};
3232
	return out;
3233
}
3234
function write_FontFlags(font, o) {
3235
	if(!o) o = new_buf(2);
3236
	var grbit =
3237
		(font.italic   ? 0x02 : 0) |
3238
		(font.strike   ? 0x08 : 0) |
3239
		(font.outline  ? 0x10 : 0) |
3240
		(font.shadow   ? 0x20 : 0) |
3241
		(font.condense ? 0x40 : 0) |
3242
		(font.extend   ? 0x80 : 0);
3243
	o.write_shift(1, grbit);
3244
	o.write_shift(1, 0);
3245
	return o;
3246
}
3247
3248
/* [MS-OLEDS] 2.3.1 and 2.3.2 */
3249
function parse_ClipboardFormatOrString(o, w/*:number*/)/*:string*/ {
3250
	// $FlowIgnore
3251
	var ClipFmt = {2:"BITMAP",3:"METAFILEPICT",8:"DIB",14:"ENHMETAFILE"};
3252
	var m/*:number*/ = o.read_shift(4);
3253
	switch(m) {
3254
		case 0x00000000: return "";
3255
		case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)]||"";
3256
	}
3257
	if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
3258
	o.l -= 4;
3259
	return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr");
3260
}
3261
function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); }
3262
function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); }
3263
3264
/* [MS-OLEPS] 2.2 PropertyType */
3265
//var VT_EMPTY    = 0x0000;
3266
//var VT_NULL     = 0x0001;
3267
var VT_I2       = 0x0002;
3268
var VT_I4       = 0x0003;
3269
//var VT_R4       = 0x0004;
3270
//var VT_R8       = 0x0005;
3271
//var VT_CY       = 0x0006;
3272
//var VT_DATE     = 0x0007;
3273
//var VT_BSTR     = 0x0008;
3274
//var VT_ERROR    = 0x000A;
3275
var VT_BOOL     = 0x000B;
3276
var VT_VARIANT  = 0x000C;
3277
//var VT_DECIMAL  = 0x000E;
3278
//var VT_I1       = 0x0010;
3279
//var VT_UI1      = 0x0011;
3280
//var VT_UI2      = 0x0012;
3281
var VT_UI4      = 0x0013;
3282
//var VT_I8       = 0x0014;
3283
//var VT_UI8      = 0x0015;
3284
//var VT_INT      = 0x0016;
3285
//var VT_UINT     = 0x0017;
3286
var VT_LPSTR    = 0x001E;
3287
//var VT_LPWSTR   = 0x001F;
3288
var VT_FILETIME = 0x0040;
3289
var VT_BLOB     = 0x0041;
3290
//var VT_STREAM   = 0x0042;
3291
//var VT_STORAGE  = 0x0043;
3292
//var VT_STREAMED_Object  = 0x0044;
3293
//var VT_STORED_Object    = 0x0045;
3294
//var VT_BLOB_Object      = 0x0046;
3295
var VT_CF       = 0x0047;
3296
//var VT_CLSID    = 0x0048;
3297
//var VT_VERSIONED_STREAM = 0x0049;
3298
var VT_VECTOR   = 0x1000;
3299
//var VT_ARRAY    = 0x2000;
3300
3301
var VT_STRING   = 0x0050; // 2.3.3.1.11 VtString
3302
var VT_USTR     = 0x0051; // 2.3.3.1.12 VtUnalignedString
3303
var VT_CUSTOM   = [VT_STRING, VT_USTR];
3304
3305
/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
3306
var DocSummaryPIDDSI = {
3307
	/*::[*/0x01/*::]*/: { n: 'CodePage', t: VT_I2 },
3308
	/*::[*/0x02/*::]*/: { n: 'Category', t: VT_STRING },
3309
	/*::[*/0x03/*::]*/: { n: 'PresentationFormat', t: VT_STRING },
3310
	/*::[*/0x04/*::]*/: { n: 'ByteCount', t: VT_I4 },
3311
	/*::[*/0x05/*::]*/: { n: 'LineCount', t: VT_I4 },
3312
	/*::[*/0x06/*::]*/: { n: 'ParagraphCount', t: VT_I4 },
3313
	/*::[*/0x07/*::]*/: { n: 'SlideCount', t: VT_I4 },
3314
	/*::[*/0x08/*::]*/: { n: 'NoteCount', t: VT_I4 },
3315
	/*::[*/0x09/*::]*/: { n: 'HiddenCount', t: VT_I4 },
3316
	/*::[*/0x0a/*::]*/: { n: 'MultimediaClipCount', t: VT_I4 },
3317
	/*::[*/0x0b/*::]*/: { n: 'ScaleCrop', t: VT_BOOL },
3318
	/*::[*/0x0c/*::]*/: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
3319
	/*::[*/0x0d/*::]*/: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
3320
	/*::[*/0x0e/*::]*/: { n: 'Manager', t: VT_STRING },
3321
	/*::[*/0x0f/*::]*/: { n: 'Company', t: VT_STRING },
3322
	/*::[*/0x10/*::]*/: { n: 'LinksUpToDate', t: VT_BOOL },
3323
	/*::[*/0x11/*::]*/: { n: 'CharacterCount', t: VT_I4 },
3324
	/*::[*/0x13/*::]*/: { n: 'SharedDoc', t: VT_BOOL },
3325
	/*::[*/0x16/*::]*/: { n: 'HyperlinksChanged', t: VT_BOOL },
3326
	/*::[*/0x17/*::]*/: { n: 'AppVersion', t: VT_I4, p: 'version' },
3327
	/*::[*/0x18/*::]*/: { n: 'DigSig', t: VT_BLOB },
3328
	/*::[*/0x1A/*::]*/: { n: 'ContentType', t: VT_STRING },
3329
	/*::[*/0x1B/*::]*/: { n: 'ContentStatus', t: VT_STRING },
3330
	/*::[*/0x1C/*::]*/: { n: 'Language', t: VT_STRING },
3331
	/*::[*/0x1D/*::]*/: { n: 'Version', t: VT_STRING },
3332
	/*::[*/0xFF/*::]*/: {}
3333
};
3334
3335
/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
3336
var SummaryPIDSI = {
3337
	/*::[*/0x01/*::]*/: { n: 'CodePage', t: VT_I2 },
3338
	/*::[*/0x02/*::]*/: { n: 'Title', t: VT_STRING },
3339
	/*::[*/0x03/*::]*/: { n: 'Subject', t: VT_STRING },
3340
	/*::[*/0x04/*::]*/: { n: 'Author', t: VT_STRING },
3341
	/*::[*/0x05/*::]*/: { n: 'Keywords', t: VT_STRING },
3342
	/*::[*/0x06/*::]*/: { n: 'Comments', t: VT_STRING },
3343
	/*::[*/0x07/*::]*/: { n: 'Template', t: VT_STRING },
3344
	/*::[*/0x08/*::]*/: { n: 'LastAuthor', t: VT_STRING },
3345
	/*::[*/0x09/*::]*/: { n: 'RevNumber', t: VT_STRING },
3346
	/*::[*/0x0A/*::]*/: { n: 'EditTime', t: VT_FILETIME },
3347
	/*::[*/0x0B/*::]*/: { n: 'LastPrinted', t: VT_FILETIME },
3348
	/*::[*/0x0C/*::]*/: { n: 'CreatedDate', t: VT_FILETIME },
3349
	/*::[*/0x0D/*::]*/: { n: 'ModifiedDate', t: VT_FILETIME },
3350
	/*::[*/0x0E/*::]*/: { n: 'PageCount', t: VT_I4 },
3351
	/*::[*/0x0F/*::]*/: { n: 'WordCount', t: VT_I4 },
3352
	/*::[*/0x10/*::]*/: { n: 'CharCount', t: VT_I4 },
3353
	/*::[*/0x11/*::]*/: { n: 'Thumbnail', t: VT_CF },
3354
	/*::[*/0x12/*::]*/: { n: 'Application', t: VT_STRING },
3355
	/*::[*/0x13/*::]*/: { n: 'DocSecurity', t: VT_I4 },
3356
	/*::[*/0xFF/*::]*/: {}
3357
};
3358
3359
/* [MS-OLEPS] 2.18 */
3360
var SpecialProperties = {
3361
	/*::[*/0x80000000/*::]*/: { n: 'Locale', t: VT_UI4 },
3362
	/*::[*/0x80000003/*::]*/: { n: 'Behavior', t: VT_UI4 },
3363
	/*::[*/0x72627262/*::]*/: {}
3364
};
3365
3366
(function() {
3367
	for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
3368
	DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
3369
})();
3370
3371
var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n");
3372
var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n");
3373
3374
/* [MS-XLS] 2.4.63 Country/Region codes */
3375
var CountryEnum = {
3376
	/*::[*/0x0001/*::]*/: "US", // United States
3377
	/*::[*/0x0002/*::]*/: "CA", // Canada
3378
	/*::[*/0x0003/*::]*/: "", // Latin America (except Brazil)
3379
	/*::[*/0x0007/*::]*/: "RU", // Russia
3380
	/*::[*/0x0014/*::]*/: "EG", // Egypt
3381
	/*::[*/0x001E/*::]*/: "GR", // Greece
3382
	/*::[*/0x001F/*::]*/: "NL", // Netherlands
3383
	/*::[*/0x0020/*::]*/: "BE", // Belgium
3384
	/*::[*/0x0021/*::]*/: "FR", // France
3385
	/*::[*/0x0022/*::]*/: "ES", // Spain
3386
	/*::[*/0x0024/*::]*/: "HU", // Hungary
3387
	/*::[*/0x0027/*::]*/: "IT", // Italy
3388
	/*::[*/0x0029/*::]*/: "CH", // Switzerland
3389
	/*::[*/0x002B/*::]*/: "AT", // Austria
3390
	/*::[*/0x002C/*::]*/: "GB", // United Kingdom
3391
	/*::[*/0x002D/*::]*/: "DK", // Denmark
3392
	/*::[*/0x002E/*::]*/: "SE", // Sweden
3393
	/*::[*/0x002F/*::]*/: "NO", // Norway
3394
	/*::[*/0x0030/*::]*/: "PL", // Poland
3395
	/*::[*/0x0031/*::]*/: "DE", // Germany
3396
	/*::[*/0x0034/*::]*/: "MX", // Mexico
3397
	/*::[*/0x0037/*::]*/: "BR", // Brazil
3398
	/*::[*/0x003d/*::]*/: "AU", // Australia
3399
	/*::[*/0x0040/*::]*/: "NZ", // New Zealand
3400
	/*::[*/0x0042/*::]*/: "TH", // Thailand
3401
	/*::[*/0x0051/*::]*/: "JP", // Japan
3402
	/*::[*/0x0052/*::]*/: "KR", // Korea
3403
	/*::[*/0x0054/*::]*/: "VN", // Viet Nam
3404
	/*::[*/0x0056/*::]*/: "CN", // China
3405
	/*::[*/0x005A/*::]*/: "TR", // Turkey
3406
	/*::[*/0x0069/*::]*/: "JS", // Ramastan
3407
	/*::[*/0x00D5/*::]*/: "DZ", // Algeria
3408
	/*::[*/0x00D8/*::]*/: "MA", // Morocco
3409
	/*::[*/0x00DA/*::]*/: "LY", // Libya
3410
	/*::[*/0x015F/*::]*/: "PT", // Portugal
3411
	/*::[*/0x0162/*::]*/: "IS", // Iceland
3412
	/*::[*/0x0166/*::]*/: "FI", // Finland
3413
	/*::[*/0x01A4/*::]*/: "CZ", // Czech Republic
3414
	/*::[*/0x0376/*::]*/: "TW", // Taiwan
3415
	/*::[*/0x03C1/*::]*/: "LB", // Lebanon
3416
	/*::[*/0x03C2/*::]*/: "JO", // Jordan
3417
	/*::[*/0x03C3/*::]*/: "SY", // Syria
3418
	/*::[*/0x03C4/*::]*/: "IQ", // Iraq
3419
	/*::[*/0x03C5/*::]*/: "KW", // Kuwait
3420
	/*::[*/0x03C6/*::]*/: "SA", // Saudi Arabia
3421
	/*::[*/0x03CB/*::]*/: "AE", // United Arab Emirates
3422
	/*::[*/0x03CC/*::]*/: "IL", // Israel
3423
	/*::[*/0x03CE/*::]*/: "QA", // Qatar
3424
	/*::[*/0x03D5/*::]*/: "IR", // Iran
3425
	/*::[*/0xFFFF/*::]*/: "US"  // United States
3426
};
3427
3428
/* [MS-XLS] 2.5.127 */
3429
var XLSFillPattern = [
3430
	null,
3431
	'solid',
3432
	'mediumGray',
3433
	'darkGray',
3434
	'lightGray',
3435
	'darkHorizontal',
3436
	'darkVertical',
3437
	'darkDown',
3438
	'darkUp',
3439
	'darkGrid',
3440
	'darkTrellis',
3441
	'lightHorizontal',
3442
	'lightVertical',
3443
	'lightDown',
3444
	'lightUp',
3445
	'lightGrid',
3446
	'lightTrellis',
3447
	'gray125',
3448
	'gray0625'
3449
];
3450
3451
function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
3452
3453
/* [MS-XLS] 2.5.161 */
3454
/* [MS-XLSB] 2.5.75 Icv */
3455
var XLSIcv = rgbify([
3456
	/* Color Constants */
3457
	0x000000,
3458
	0xFFFFFF,
3459
	0xFF0000,
3460
	0x00FF00,
3461
	0x0000FF,
3462
	0xFFFF00,
3463
	0xFF00FF,
3464
	0x00FFFF,
3465
3466
	/* Overridable Defaults */
3467
	0x000000,
3468
	0xFFFFFF,
3469
	0xFF0000,
3470
	0x00FF00,
3471
	0x0000FF,
3472
	0xFFFF00,
3473
	0xFF00FF,
3474
	0x00FFFF,
3475
3476
	0x800000,
3477
	0x008000,
3478
	0x000080,
3479
	0x808000,
3480
	0x800080,
3481
	0x008080,
3482
	0xC0C0C0,
3483
	0x808080,
3484
	0x9999FF,
3485
	0x993366,
3486
	0xFFFFCC,
3487
	0xCCFFFF,
3488
	0x660066,
3489
	0xFF8080,
3490
	0x0066CC,
3491
	0xCCCCFF,
3492
3493
	0x000080,
3494
	0xFF00FF,
3495
	0xFFFF00,
3496
	0x00FFFF,
3497
	0x800080,
3498
	0x800000,
3499
	0x008080,
3500
	0x0000FF,
3501
	0x00CCFF,
3502
	0xCCFFFF,
3503
	0xCCFFCC,
3504
	0xFFFF99,
3505
	0x99CCFF,
3506
	0xFF99CC,
3507
	0xCC99FF,
3508
	0xFFCC99,
3509
3510
	0x3366FF,
3511
	0x33CCCC,
3512
	0x99CC00,
3513
	0xFFCC00,
3514
	0xFF9900,
3515
	0xFF6600,
3516
	0x666699,
3517
	0x969696,
3518
	0x003366,
3519
	0x339966,
3520
	0x003300,
3521
	0x333300,
3522
	0x993300,
3523
	0x993366,
3524
	0x333399,
3525
	0x333333,
3526
3527
	/* Other entries to appease BIFF8/12 */
3528
	0xFFFFFF, /* 0x40 icvForeground ?? */
3529
	0x000000, /* 0x41 icvBackground ?? */
3530
	0x000000, /* 0x42 icvFrame ?? */
3531
	0x000000, /* 0x43 icv3D ?? */
3532
	0x000000, /* 0x44 icv3DText ?? */
3533
	0x000000, /* 0x45 icv3DHilite ?? */
3534
	0x000000, /* 0x46 icv3DShadow ?? */
3535
	0x000000, /* 0x47 icvHilite ?? */
3536
	0x000000, /* 0x48 icvCtlText ?? */
3537
	0x000000, /* 0x49 icvCtlScrl ?? */
3538
	0x000000, /* 0x4A icvCtlInv ?? */
3539
	0x000000, /* 0x4B icvCtlBody ?? */
3540
	0x000000, /* 0x4C icvCtlFrame ?? */
3541
	0x000000, /* 0x4D icvCtlFore ?? */
3542
	0x000000, /* 0x4E icvCtlBack ?? */
3543
	0x000000, /* 0x4F icvCtlNeutral */
3544
	0x000000, /* 0x50 icvInfoBk ?? */
3545
	0x000000 /* 0x51 icvInfoText ?? */
3546
]);
3547
3548
/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
3549
/* 12.3 Part Summary <SpreadsheetML> */
3550
/* 14.2 Part Summary <DrawingML> */
3551
/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
3552
var ct2type/*{[string]:string}*/ = ({
3553
	/* Workbook */
3554
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
3555
3556
	/* Worksheet */
3557
	"application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
3558
3559
	/* Macrosheet */
3560
	"application/vnd.ms-excel.intlmacrosheet": "TODO",
3561
	"application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
3562
3563
	/* File Properties */
3564
	"application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
3565
	"application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
3566
	"application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
3567
3568
	/* Custom Data Properties */
3569
	"application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
3570
	"application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
3571
3572
	/* PivotTable */
3573
	"application/vnd.ms-excel.pivotTable": "TODO",
3574
	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
3575
3576
	/* Chart Colors */
3577
	"application/vnd.ms-office.chartcolorstyle+xml": "TODO",
3578
3579
	/* Chart Style */
3580
	"application/vnd.ms-office.chartstyle+xml": "TODO",
3581
3582
	/* Calculation Chain */
3583
	"application/vnd.ms-excel.calcChain": "calcchains",
3584
	"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
3585
3586
	/* Printer Settings */
3587
	"application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
3588
3589
	/* ActiveX */
3590
	"application/vnd.ms-office.activeX": "TODO",
3591
	"application/vnd.ms-office.activeX+xml": "TODO",
3592
3593
	/* Custom Toolbars */
3594
	"application/vnd.ms-excel.attachedToolbars": "TODO",
3595
3596
	/* External Data Connections */
3597
	"application/vnd.ms-excel.connections": "TODO",
3598
	"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
3599
3600
	/* External Links */
3601
	"application/vnd.ms-excel.externalLink": "links",
3602
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
3603
3604
	/* Metadata */
3605
	"application/vnd.ms-excel.sheetMetadata": "TODO",
3606
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
3607
3608
	/* PivotCache */
3609
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
3610
	"application/vnd.ms-excel.pivotCacheRecords": "TODO",
3611
	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
3612
	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
3613
3614
	/* Query Table */
3615
	"application/vnd.ms-excel.queryTable": "TODO",
3616
	"application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
3617
3618
	/* Shared Workbook */
3619
	"application/vnd.ms-excel.userNames": "TODO",
3620
	"application/vnd.ms-excel.revisionHeaders": "TODO",
3621
	"application/vnd.ms-excel.revisionLog": "TODO",
3622
	"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
3623
	"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
3624
	"application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
3625
3626
	/* Single Cell Table */
3627
	"application/vnd.ms-excel.tableSingleCells": "TODO",
3628
	"application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
3629
3630
	/* Slicer */
3631
	"application/vnd.ms-excel.slicer": "TODO",
3632
	"application/vnd.ms-excel.slicerCache": "TODO",
3633
	"application/vnd.ms-excel.slicer+xml": "TODO",
3634
	"application/vnd.ms-excel.slicerCache+xml": "TODO",
3635
3636
	/* Sort Map */
3637
	"application/vnd.ms-excel.wsSortMap": "TODO",
3638
3639
	/* Table */
3640
	"application/vnd.ms-excel.table": "TODO",
3641
	"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
3642
3643
	/* Themes */
3644
	"application/vnd.openxmlformats-officedocument.theme+xml": "themes",
3645
3646
	/* Theme Override */
3647
	"application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
3648
3649
	/* Timeline */
3650
	"application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
3651
	"application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
3652
3653
	/* VBA */
3654
	"application/vnd.ms-office.vbaProject": "vba",
3655
	"application/vnd.ms-office.vbaProjectSignature": "vba",
3656
3657
	/* Volatile Dependencies */
3658
	"application/vnd.ms-office.volatileDependencies": "TODO",
3659
	"application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
3660
3661
	/* Control Properties */
3662
	"application/vnd.ms-excel.controlproperties+xml": "TODO",
3663
3664
	/* Data Model */
3665
	"application/vnd.openxmlformats-officedocument.model+data": "TODO",
3666
3667
	/* Survey */
3668
	"application/vnd.ms-excel.Survey+xml": "TODO",
3669
3670
	/* Drawing */
3671
	"application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
3672
	"application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
3673
	"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
3674
	"application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
3675
	"application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
3676
	"application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
3677
	"application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
3678
3679
	/* VML */
3680
	"application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
3681
3682
	"application/vnd.openxmlformats-package.relationships+xml": "rels",
3683
	"application/vnd.openxmlformats-officedocument.oleObject": "TODO",
3684
3685
	/* Image */
3686
	"image/png": "TODO",
3687
3688
	"sheet": "js"
3689
}/*:any*/);
3690
3691
var CT_LIST = (function(){
3692
	var o = {
3693
		workbooks: {
3694
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
3695
			xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
3696
			xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
3697
			xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
3698
			xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
3699
		},
3700
		strs: { /* Shared Strings */
3701
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
3702
			xlsb: "application/vnd.ms-excel.sharedStrings"
3703
		},
3704
		comments: { /* Comments */
3705
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
3706
			xlsb: "application/vnd.ms-excel.comments"
3707
		},
3708
		sheets: { /* Worksheet */
3709
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
3710
			xlsb: "application/vnd.ms-excel.worksheet"
3711
		},
3712
		charts: { /* Chartsheet */
3713
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
3714
			xlsb: "application/vnd.ms-excel.chartsheet"
3715
		},
3716
		dialogs: { /* Dialogsheet */
3717
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
3718
			xlsb: "application/vnd.ms-excel.dialogsheet"
3719
		},
3720
		macros: { /* Macrosheet (Excel 4.0 Macros) */
3721
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
3722
			xlsb: "application/vnd.ms-excel.macrosheet"
3723
		},
3724
		styles: { /* Styles */
3725
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3726
			xlsb: "application/vnd.ms-excel.styles"
3727
		}
3728
	};
3729
	keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
3730
	keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
3731
	return o;
3732
})();
3733
3734
var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
3735
3736
XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
3737
3738
function new_ct()/*:any*/ {
3739
	return ({
3740
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
3741
		rels:[], strs:[], comments:[], links:[],
3742
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
3743
		calcchains:[], vba: [], drawings: [],
3744
		TODO:[], xmlns: "" }/*:any*/);
3745
}
3746
3747
function parse_ct(data/*:?string*/) {
3748
	var ct = new_ct();
3749
	if(!data || !data.match) return ct;
3750
	var ctext = {};
3751
	(data.match(tagregex)||[]).forEach(function(x) {
3752
		var y = parsexmltag(x);
3753
		switch(y[0].replace(nsregex,"<")) {
3754
			case '<?xml': break;
3755
			case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
3756
			case '<Default': ctext[y.Extension] = y.ContentType; break;
3757
			case '<Override':
3758
				if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
3759
				break;
3760
		}
3761
	});
3762
	if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
3763
	ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
3764
	ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
3765
	ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
3766
	ct.defaults = ctext;
3767
	delete ct.calcchains;
3768
	return ct;
3769
}
3770
3771
var CTYPE_XML_ROOT = writextag('Types', null, {
3772
	'xmlns': XMLNS.CT,
3773
	'xmlns:xsd': XMLNS.xsd,
3774
	'xmlns:xsi': XMLNS.xsi
3775
});
3776
3777
var CTYPE_DEFAULTS = [
3778
	['xml', 'application/xml'],
3779
	['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
3780
	['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
3781
	/* from test files */
3782
	['bmp', 'image/bmp'],
3783
	['png', 'image/png'],
3784
	['gif', 'image/gif'],
3785
	['emf', 'image/x-emf'],
3786
	['wmf', 'image/x-wmf'],
3787
	['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
3788
	['tif', 'image/tiff'], ['tiff', 'image/tiff'],
3789
	['pdf', 'application/pdf'],
3790
	['rels', type2ct.rels[0]]
3791
].map(function(x) {
3792
	return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
3793
});
3794
3795
function write_ct(ct, opts)/*:string*/ {
3796
	var o/*:Array<string>*/ = [], v;
3797
	o[o.length] = (XML_HEADER);
3798
	o[o.length] = (CTYPE_XML_ROOT);
3799
	o = o.concat(CTYPE_DEFAULTS);
3800
	var f1 = function(w) {
3801
		if(ct[w] && ct[w].length > 0) {
3802
			v = ct[w][0];
3803
			o[o.length] = (writextag('Override', null, {
3804
				'PartName': (v[0] == '/' ? "":"/") + v,
3805
				'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
3806
			}));
3807
		}
3808
	};
3809
	var f2 = function(w) {
3810
		(ct[w]||[]).forEach(function(v) {
3811
			o[o.length] = (writextag('Override', null, {
3812
				'PartName': (v[0] == '/' ? "":"/") + v,
3813
				'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
3814
			}));
3815
		});
3816
	};
3817
	var f3 = function(t) {
3818
		(ct[t]||[]).forEach(function(v) {
3819
			o[o.length] = (writextag('Override', null, {
3820
				'PartName': (v[0] == '/' ? "":"/") + v,
3821
				'ContentType': type2ct[t][0]
3822
			}));
3823
		});
3824
	};
3825
	f1('workbooks');
3826
	f2('sheets');
3827
	f2('charts');
3828
	f3('themes');
3829
	['strs', 'styles'].forEach(f1);
3830
	['coreprops', 'extprops', 'custprops'].forEach(f3);
3831
	f3('vba');
3832
	f3('comments');
3833
	f3('drawings');
3834
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
3835
	return o.join("");
3836
}
3837
/* 9.3 Relationships */
3838
var RELS = ({
3839
	WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
3840
	SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
3841
	HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
3842
	VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
3843
	VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
3844
}/*:any*/);
3845
3846
/* 9.3.3 Representing Relationships */
3847
function get_rels_path(file/*:string*/)/*:string*/ {
3848
	var n = file.lastIndexOf("/");
3849
	return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
3850
}
3851
3852
function parse_rels(data/*:?string*/, currentFilePath/*:string*/) {
3853
	if (!data) return data;
3854
	if (currentFilePath.charAt(0) !== '/') {
3855
		currentFilePath = '/'+currentFilePath;
3856
	}
3857
	var rels = {};
3858
	var hash = {};
3859
3860
	(data.match(tagregex)||[]).forEach(function(x) {
3861
		var y = parsexmltag(x);
3862
		/* 9.3.2.2 OPC_Relationships */
3863
		if (y[0] === '<Relationship') {
3864
			var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
3865
			var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
3866
			rels[canonictarget] = rel;
3867
			hash[y.Id] = rel;
3868
		}
3869
	});
3870
	rels["!id"] = hash;
3871
	return rels;
3872
}
3873
3874
XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
3875
3876
var RELS_ROOT = writextag('Relationships', null, {
3877
	//'xmlns:ns0': XMLNS.RELS,
3878
	'xmlns': XMLNS.RELS
3879
});
3880
3881
/* TODO */
3882
function write_rels(rels)/*:string*/ {
3883
	var o = [XML_HEADER, RELS_ROOT];
3884
	keys(rels['!id']).forEach(function(rid) {
3885
		o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
3886
	});
3887
	if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
3888
	return o.join("");
3889
}
3890
3891
function add_rels(rels, rId, f, type, relobj)/*:number*/ {
3892
	if(!relobj) relobj = {};
3893
	if(!rels['!id']) rels['!id'] = {};
3894
	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
3895
	relobj.Id = 'rId' + rId;
3896
	relobj.Type = type;
3897
	relobj.Target = f;
3898
	if(relobj.Type == RELS.HLINK) relobj.TargetMode = "External";
3899
	if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
3900
	rels['!id'][relobj.Id] = relobj;
3901
	rels[('/' + relobj.Target).replace("//","/")] = relobj;
3902
	return rId;
3903
}
3904
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
3905
/* Part 3 Section 4 Manifest File */
3906
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
3907
function parse_manifest(d, opts) {
3908
	var str = xlml_normalize(d);
3909
	var Rn;
3910
	var FEtag;
3911
	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
3912
		case 'manifest': break; // 4.2 <manifest:manifest>
3913
		case 'file-entry': // 4.3 <manifest:file-entry>
3914
			FEtag = parsexmltag(Rn[0], false);
3915
			if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
3916
			break;
3917
		case 'encryption-data': // 4.4 <manifest:encryption-data>
3918
		case 'algorithm': // 4.5 <manifest:algorithm>
3919
		case 'start-key-generation': // 4.6 <manifest:start-key-generation>
3920
		case 'key-derivation': // 4.7 <manifest:key-derivation>
3921
			throw new Error("Unsupported ODS Encryption");
3922
		default: if(opts && opts.WTF) throw Rn;
3923
	}
3924
}
3925
3926
function write_manifest(manifest/*:Array<Array<string> >*/)/*:string*/ {
3927
	var o = [XML_HEADER];
3928
	o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
3929
	o.push('  <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
3930
	for(var i = 0; i < manifest.length; ++i) o.push('  <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
3931
	o.push('</manifest:manifest>');
3932
	return o.join("");
3933
}
3934
3935
/* Part 3 Section 6 Metadata Manifest File */
3936
function write_rdf_type(file/*:string*/, res/*:string*/, tag/*:?string*/) {
3937
	return [
3938
		'  <rdf:Description rdf:about="' + file + '">\n',
3939
		'    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
3940
		'  </rdf:Description>\n'
3941
	].join("");
3942
}
3943
function write_rdf_has(base/*:string*/, file/*:string*/) {
3944
	return [
3945
		'  <rdf:Description rdf:about="' + base + '">\n',
3946
		'    <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
3947
		'  </rdf:Description>\n'
3948
	].join("");
3949
}
3950
function write_rdf(rdf) {
3951
	var o = [XML_HEADER];
3952
	o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
3953
	for(var i = 0; i != rdf.length; ++i) {
3954
		o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
3955
		o.push(write_rdf_has("",rdf[i][0]));
3956
	}
3957
	o.push(write_rdf_type("","Document", "pkg"));
3958
	o.push('</rdf:RDF>');
3959
	return o.join("");
3960
}
3961
/* TODO: pull properties */
3962
var write_meta_ods/*:{(wb:Workbook, opts:any):string}*/ = (function() {
3963
	var payload = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>';
3964
	return function wmo(/*:: wb: Workbook, opts: any*/)/*:string*/ {
3965
		return payload;
3966
	};
3967
})();
3968
3969
/* ECMA-376 Part II 11.1 Core Properties Part */
3970
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
3971
var CORE_PROPS/*:Array<Array<string> >*/ = [
3972
	["cp:category", "Category"],
3973
	["cp:contentStatus", "ContentStatus"],
3974
	["cp:keywords", "Keywords"],
3975
	["cp:lastModifiedBy", "LastAuthor"],
3976
	["cp:lastPrinted", "LastPrinted"],
3977
	["cp:revision", "RevNumber"],
3978
	["cp:version", "Version"],
3979
	["dc:creator", "Author"],
3980
	["dc:description", "Comments"],
3981
	["dc:identifier", "Identifier"],
3982
	["dc:language", "Language"],
3983
	["dc:subject", "Subject"],
3984
	["dc:title", "Title"],
3985
	["dcterms:created", "CreatedDate", 'date'],
3986
	["dcterms:modified", "ModifiedDate", 'date']
3987
];
3988
3989
XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
3990
RELS.CORE_PROPS  = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
3991
3992
var CORE_PROPS_REGEX/*:Array<RegExp>*/ = (function() {
3993
	var r = new Array(CORE_PROPS.length);
3994
	for(var i = 0; i < CORE_PROPS.length; ++i) {
3995
		var f = CORE_PROPS[i];
3996
		var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
3997
		r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
3998
	}
3999
	return r;
4000
})();
4001
4002
function parse_core_props(data) {
4003
	var p = {};
4004
	data = utf8read(data);
4005
4006
	for(var i = 0; i < CORE_PROPS.length; ++i) {
4007
		var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4008
		if(cur != null && cur.length > 0) p[f[1]] = cur[1];
4009
		if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4010
	}
4011
4012
	return p;
4013
}
4014
4015
var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4016
	//'xmlns': XMLNS.CORE_PROPS,
4017
	'xmlns:cp': XMLNS.CORE_PROPS,
4018
	'xmlns:dc': XMLNS.dc,
4019
	'xmlns:dcterms': XMLNS.dcterms,
4020
	'xmlns:dcmitype': XMLNS.dcmitype,
4021
	'xmlns:xsi': XMLNS.xsi
4022
});
4023
4024
function cp_doit(f, g, h, o, p) {
4025
	if(p[f] != null || g == null || g === "") return;
4026
	p[f] = g;
4027
	o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4028
}
4029
4030
function write_core_props(cp, _opts) {
4031
	var opts = _opts || {};
4032
	var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4033
	if(!cp && !opts.Props) return o.join("");
4034
4035
	if(cp) {
4036
		if(cp.CreatedDate != null) cp_doit("dcterms:created", typeof cp.CreatedDate === "string" ? cp.CreatedDate : write_w3cdtf(cp.CreatedDate, opts.WTF), {"xsi:type":"dcterms:W3CDTF"}, o, p);
4037
		if(cp.ModifiedDate != null) cp_doit("dcterms:modified", typeof cp.ModifiedDate === "string" ? cp.ModifiedDate : write_w3cdtf(cp.ModifiedDate, opts.WTF), {"xsi:type":"dcterms:W3CDTF"}, o, p);
4038
	}
4039
4040
	for(var i = 0; i != CORE_PROPS.length; ++i) {
4041
		var f = CORE_PROPS[i];
4042
		var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4043
		if(v === true) v = "1";
4044
		else if(v === false) v = "0";
4045
		else if(typeof v == "number") v = String(v);
4046
		if(v != null) cp_doit(f[0], v, null, o, p);
4047
	}
4048
	if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4049
	return o.join("");
4050
}
4051
/* 15.2.12.3 Extended File Properties Part */
4052
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4053
var EXT_PROPS/*:Array<Array<string> >*/ = [
4054
	["Application", "Application", "string"],
4055
	["AppVersion", "AppVersion", "string"],
4056
	["Company", "Company", "string"],
4057
	["DocSecurity", "DocSecurity", "string"],
4058
	["Manager", "Manager", "string"],
4059
	["HyperlinksChanged", "HyperlinksChanged", "bool"],
4060
	["SharedDoc", "SharedDoc", "bool"],
4061
	["LinksUpToDate", "LinksUpToDate", "bool"],
4062
	["ScaleCrop", "ScaleCrop", "bool"],
4063
	["HeadingPairs", "HeadingPairs", "raw"],
4064
	["TitlesOfParts", "TitlesOfParts", "raw"]
4065
];
4066
4067
XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4068
RELS.EXT_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4069
4070
var PseudoPropsPairs = [
4071
	"Worksheets",  "SheetNames",
4072
	"NamedRanges", "DefinedNames",
4073
	"Chartsheets", "ChartNames"
4074
];
4075
function load_props_pairs(HP/*:string|Array<Array<any>>*/, TOP, props, opts) {
4076
	var v = [];
4077
	if(typeof HP == "string") v = parseVector(HP, opts);
4078
	else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4079
	var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4080
	var idx = 0, len = 0;
4081
	if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4082
		len = +(v[i+1].v);
4083
		switch(v[i].v) {
4084
			case "Worksheets":
4085
			case "工作表":
4086
			case "Листы":
4087
			case "أوراق العمل":
4088
			case "ワークシート":
4089
			case "גליונות עבודה":
4090
			case "Arbeitsblätter":
4091
			case "Çalışma Sayfaları":
4092
			case "Feuilles de calcul":
4093
			case "Fogli di lavoro":
4094
			case "Folhas de cálculo":
4095
			case "Planilhas":
4096
			case "Regneark":
4097
			case "Werkbladen":
4098
				props.Worksheets = len;
4099
				props.SheetNames = parts.slice(idx, idx + len);
4100
				break;
4101
4102
			case "Named Ranges":
4103
			case "名前付き一覧":
4104
			case "Benannte Bereiche":
4105
			case "Navngivne områder":
4106
				props.NamedRanges = len;
4107
				props.DefinedNames = parts.slice(idx, idx + len);
4108
				break;
4109
4110
			case "Charts":
4111
			case "Diagramme":
4112
				props.Chartsheets = len;
4113
				props.ChartNames = parts.slice(idx, idx + len);
4114
				break;
4115
		}
4116
		idx += len;
4117
	}
4118
}
4119
4120
function parse_ext_props(data, p, opts) {
4121
	var q = {}; if(!p) p = {};
4122
	data = utf8read(data);
4123
4124
	EXT_PROPS.forEach(function(f) {
4125
		switch(f[2]) {
4126
			case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
4127
			case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
4128
			case "raw":
4129
				var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4130
				if(cur && cur.length > 0) q[f[1]] = cur[1];
4131
				break;
4132
		}
4133
	});
4134
4135
	if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4136
4137
	return p;
4138
}
4139
4140
var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4141
	'xmlns': XMLNS.EXT_PROPS,
4142
	'xmlns:vt': XMLNS.vt
4143
});
4144
4145
function write_ext_props(cp/*::, opts*/)/*:string*/ {
4146
	var o/*:Array<string>*/ = [], W = writextag;
4147
	if(!cp) cp = {};
4148
	cp.Application = "SheetJS";
4149
	o[o.length] = (XML_HEADER);
4150
	o[o.length] = (EXT_PROPS_XML_ROOT);
4151
4152
	EXT_PROPS.forEach(function(f) {
4153
		if(cp[f[1]] === undefined) return;
4154
		var v;
4155
		switch(f[2]) {
4156
			case 'string': v = String(cp[f[1]]); break;
4157
			case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4158
		}
4159
		if(v !== undefined) o[o.length] = (W(f[0], v));
4160
	});
4161
4162
	/* TODO: HeadingPairs, TitlesOfParts */
4163
	o[o.length] = (W('HeadingPairs', W('vt:vector', W('vt:variant', '<vt:lpstr>Worksheets</vt:lpstr>')+W('vt:variant', W('vt:i4', String(cp.Worksheets))), {size:2, baseType:"variant"})));
4164
	o[o.length] = (W('TitlesOfParts', W('vt:vector', cp.SheetNames.map(function(s) { return "<vt:lpstr>" + escapexml(s) + "</vt:lpstr>"; }).join(""), {size: cp.Worksheets, baseType:"lpstr"})));
4165
	if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4166
	return o.join("");
4167
}
4168
/* 15.2.12.2 Custom File Properties Part */
4169
XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4170
RELS.CUST_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4171
4172
var custregex = /<[^>]+>[^<]*/g;
4173
function parse_cust_props(data/*:string*/, opts) {
4174
	var p = {}, name = "";
4175
	var m = data.match(custregex);
4176
	if(m) for(var i = 0; i != m.length; ++i) {
4177
		var x = m[i], y = parsexmltag(x);
4178
		switch(y[0]) {
4179
			case '<?xml': break;
4180
			case '<Properties': break;
4181
			case '<property': name = y.name; break;
4182
			case '</property>': name = null; break;
4183
			default: if (x.indexOf('<vt:') === 0) {
4184
				var toks = x.split('>');
4185
				var type = toks[0].slice(4), text = toks[1];
4186
				/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4187
				switch(type) {
4188
					case 'lpstr': case 'bstr': case 'lpwstr':
4189
						p[name] = unescapexml(text);
4190
						break;
4191
					case 'bool':
4192
						p[name] = parsexmlbool(text);
4193
						break;
4194
					case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4195
						p[name] = parseInt(text, 10);
4196
						break;
4197
					case 'r4': case 'r8': case 'decimal':
4198
						p[name] = parseFloat(text);
4199
						break;
4200
					case 'filetime': case 'date':
4201
						p[name] = parseDate(text);
4202
						break;
4203
					case 'cy': case 'error':
4204
						p[name] = unescapexml(text);
4205
						break;
4206
					default:
4207
						if(type.slice(-1) == '/') break;
4208
						if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4209
				}
4210
			} else if(x.slice(0,2) === "</") {/* empty */
4211
			} else if(opts.WTF) throw new Error(x);
4212
		}
4213
	}
4214
	return p;
4215
}
4216
4217
var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4218
	'xmlns': XMLNS.CUST_PROPS,
4219
	'xmlns:vt': XMLNS.vt
4220
});
4221
4222
function write_cust_props(cp/*::, opts*/)/*:string*/ {
4223
	var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4224
	if(!cp) return o.join("");
4225
	var pid = 1;
4226
	keys(cp).forEach(function custprop(k) { ++pid;
4227
		o[o.length] = (writextag('property', write_vt(cp[k]), {
4228
			'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4229
			'pid': pid,
4230
			'name': k
4231
		}));
4232
	});
4233
	if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4234
	return o.join("");
4235
}
4236
/* Common Name -> XLML Name */
4237
var XLMLDocPropsMap = {
4238
	Title: 'Title',
4239
	Subject: 'Subject',
4240
	Author: 'Author',
4241
	Keywords: 'Keywords',
4242
	Comments: 'Description',
4243
	LastAuthor: 'LastAuthor',
4244
	RevNumber: 'Revision',
4245
	Application: 'AppName',
4246
	/* TotalTime: 'TotalTime', */
4247
	LastPrinted: 'LastPrinted',
4248
	CreatedDate: 'Created',
4249
	ModifiedDate: 'LastSaved',
4250
	/* Pages */
4251
	/* Words */
4252
	/* Characters */
4253
	Category: 'Category',
4254
	/* PresentationFormat */
4255
	Manager: 'Manager',
4256
	Company: 'Company',
4257
	/* Guid */
4258
	/* HyperlinkBase */
4259
	/* Bytes */
4260
	/* Lines */
4261
	/* Paragraphs */
4262
	/* CharactersWithSpaces */
4263
	AppVersion: 'Version',
4264
4265
	ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
4266
	Identifier: 'Identifier', /* NOTE: missing from schema */
4267
	Language: 'Language' /* NOTE: missing from schema */
4268
};
4269
var evert_XLMLDPM = evert(XLMLDocPropsMap);
4270
4271
function xlml_set_prop(Props, tag/*:string*/, val) {
4272
	tag = evert_XLMLDPM[tag] || tag;
4273
	Props[tag] = val;
4274
}
4275
4276
function xlml_write_docprops(Props, opts) {
4277
	var o/*:Array<string>*/ = [];
4278
	keys(XLMLDocPropsMap).map(function(m) {
4279
		for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
4280
		for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
4281
		throw m;
4282
	}).forEach(function(p) {
4283
		if(Props[p[1]] == null) return;
4284
		var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
4285
		switch(p[2]) {
4286
			case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
4287
		}
4288
		if(typeof m == 'number') m = String(m);
4289
		else if(m === true || m === false) { m = m ? "1" : "0"; }
4290
		else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
4291
		o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
4292
	});
4293
	return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
4294
}
4295
function xlml_write_custprops(Props, Custprops/*::, opts*/) {
4296
	var BLACKLIST = ["Worksheets","SheetNames"];
4297
	var T = 'CustomDocumentProperties';
4298
	var o/*:Array<string>*/ = [];
4299
	if(Props) keys(Props).forEach(function(k) {
4300
		/*:: if(!Props) return; */
4301
		if(!Props.hasOwnProperty(k)) return;
4302
		for(var i = 0; i < CORE_PROPS.length; ++i) if(k == CORE_PROPS[i][1]) return;
4303
		for(i = 0; i < EXT_PROPS.length; ++i) if(k == EXT_PROPS[i][1]) return;
4304
		for(i = 0; i < BLACKLIST.length; ++i) if(k == BLACKLIST[i]) return;
4305
4306
		var m = Props[k];
4307
		var t = "string";
4308
		if(typeof m == 'number') { t = "float"; m = String(m); }
4309
		else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
4310
		else m = String(m);
4311
		o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
4312
	});
4313
	if(Custprops) keys(Custprops).forEach(function(k) {
4314
		/*:: if(!Custprops) return; */
4315
		if(!Custprops.hasOwnProperty(k)) return;
4316
		if(Props && Props.hasOwnProperty(k)) return;
4317
		var m = Custprops[k];
4318
		var t = "string";
4319
		if(typeof m == 'number') { t = "float"; m = String(m); }
4320
		else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
4321
		else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); }
4322
		else m = String(m);
4323
		o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
4324
	});
4325
	return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
4326
}
4327
/* [MS-DTYP] 2.3.3 FILETIME */
4328
/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
4329
/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
4330
function parse_FILETIME(blob) {
4331
	var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
4332
	return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
4333
}
4334
function write_FILETIME(time/*:string|Date*/) {
4335
	var date = (typeof time == "string") ? new Date(Date.parse(time)) : time;
4336
	var t = date.getTime() / 1000 + 11644473600;
4337
	var l = t % Math.pow(2,32), h = (t - l) / Math.pow(2,32);
4338
	l *= 1e7; h *= 1e7;
4339
	var w = (l / Math.pow(2,32)) | 0;
4340
	if(w > 0) { l = l % Math.pow(2,32); h += w; }
4341
	var o = new_buf(8); o.write_shift(4, l); o.write_shift(4, h); return o;
4342
}
4343
4344
/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
4345
function parse_lpstr(blob, type, pad/*:?number*/) {
4346
	var start = blob.l;
4347
	var str = blob.read_shift(0, 'lpstr-cp');
4348
	if(pad) while((blob.l - start) & 3) ++blob.l;
4349
	return str;
4350
}
4351
4352
/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
4353
function parse_lpwstr(blob, type, pad) {
4354
	var str = blob.read_shift(0, 'lpwstr');
4355
	if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
4356
	return str;
4357
}
4358
4359
4360
/* [MS-OSHARED] 2.3.3.1.11 VtString */
4361
/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
4362
function parse_VtStringBase(blob, stringType, pad) {
4363
	if(stringType === 0x1F /*VT_LPWSTR*/) return parse_lpwstr(blob);
4364
	return parse_lpstr(blob, stringType, pad);
4365
}
4366
4367
function parse_VtString(blob, t/*:number*/, pad/*:?boolean*/) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
4368
function parse_VtUnalignedString(blob, t/*:number*/) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); }
4369
4370
/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
4371
function parse_VtVecUnalignedLpstrValue(blob)/*:Array<string>*/ {
4372
	var length = blob.read_shift(4);
4373
	var ret/*:Array<string>*/ = [];
4374
	for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,'');
4375
	return ret;
4376
}
4377
4378
/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
4379
function parse_VtVecUnalignedLpstr(blob)/*:Array<string>*/ {
4380
	return parse_VtVecUnalignedLpstrValue(blob);
4381
}
4382
4383
/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
4384
function parse_VtHeadingPair(blob) {
4385
	var headingString = parse_TypedPropertyValue(blob, VT_USTR);
4386
	var headerParts = parse_TypedPropertyValue(blob, VT_I4);
4387
	return [headingString, headerParts];
4388
}
4389
4390
/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
4391
function parse_VtVecHeadingPairValue(blob) {
4392
	var cElements = blob.read_shift(4);
4393
	var out = [];
4394
	for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
4395
	return out;
4396
}
4397
4398
/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
4399
function parse_VtVecHeadingPair(blob) {
4400
	// NOTE: When invoked, wType & padding were already consumed
4401
	return parse_VtVecHeadingPairValue(blob);
4402
}
4403
4404
/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
4405
function parse_dictionary(blob,CodePage) {
4406
	var cnt = blob.read_shift(4);
4407
	var dict/*:{[number]:string}*/ = ({}/*:any*/);
4408
	for(var j = 0; j != cnt; ++j) {
4409
		var pid = blob.read_shift(4);
4410
		var len = blob.read_shift(4);
4411
		dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
4412
		if(CodePage === 0x4B0 && (len % 2)) blob.l += 2;
4413
	}
4414
	if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
4415
	return dict;
4416
}
4417
4418
/* [MS-OLEPS] 2.9 BLOB */
4419
function parse_BLOB(blob) {
4420
	var size = blob.read_shift(4);
4421
	var bytes = blob.slice(blob.l,blob.l+size);
4422
	blob.l += size;
4423
	if((size & 3) > 0) blob.l += (4 - (size & 3)) & 3;
4424
	return bytes;
4425
}
4426
4427
/* [MS-OLEPS] 2.11 ClipboardData */
4428
function parse_ClipboardData(blob) {
4429
	// TODO
4430
	var o = {};
4431
	o.Size = blob.read_shift(4);
4432
	//o.Format = blob.read_shift(4);
4433
	blob.l += o.Size + 3 - (o.Size - 1) % 4;
4434
	return o;
4435
}
4436
4437
/* [MS-OLEPS] 2.15 TypedPropertyValue */
4438
function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
4439
	var t = blob.read_shift(2), ret, opts = _opts||{};
4440
	blob.l += 2;
4441
	if(type !== VT_VARIANT)
4442
	if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
4443
	switch(type === VT_VARIANT ? t : type) {
4444
		case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
4445
		case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
4446
		case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
4447
		case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
4448
		case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
4449
		case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
4450
		case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
4451
		case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
4452
		case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
4453
		case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw).replace(chr0,'');
4454
		case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t/*, 4*/).replace(chr0,'');
4455
		case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
4456
		case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
4457
		default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
4458
	}
4459
}
4460
function write_TypedPropertyValue(type/*:number*/, value) {
4461
	var o = new_buf(4), p = new_buf(4);
4462
	o.write_shift(4, type == 0x50 ? 0x1F : type);
4463
	switch(type) {
4464
		case 0x03 /*VT_I4*/: p.write_shift(-4, value); break;
4465
		case 0x05 /*VT_I4*/: p = new_buf(8); p.write_shift(8, value, 'f'); break;
4466
		case 0x0B /*VT_BOOL*/: p.write_shift(4, value ? 0x01 : 0x00); break;
4467
		case 0x40 /*VT_FILETIME*/: /*:: if(typeof value !== "string" && !(value instanceof Date)) throw "unreachable"; */ p = write_FILETIME(value); break;
4468
		case 0x1F /*VT_LPWSTR*/:
4469
		case 0x50 /*VT_STRING*/:
4470
			/*:: if(typeof value !== "string") throw "unreachable"; */
4471
			p = new_buf(4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
4472
			p.write_shift(4, value.length + 1);
4473
			p.write_shift(0, value, "dbcs");
4474
			while(p.l != p.length) p.write_shift(1, 0);
4475
			break;
4476
		default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + value);
4477
	}
4478
	return bconcat([o, p]);
4479
}
4480
4481
/* [MS-OLEPS] 2.20 PropertySet */
4482
function parse_PropertySet(blob, PIDSI) {
4483
	var start_addr = blob.l;
4484
	var size = blob.read_shift(4);
4485
	var NumProps = blob.read_shift(4);
4486
	var Props = [], i = 0;
4487
	var CodePage = 0;
4488
	var Dictionary = -1, DictObj/*:{[number]:string}*/ = ({}/*:any*/);
4489
	for(i = 0; i != NumProps; ++i) {
4490
		var PropID = blob.read_shift(4);
4491
		var Offset = blob.read_shift(4);
4492
		Props[i] = [PropID, Offset + start_addr];
4493
	}
4494
	Props.sort(function(x,y) { return x[1] - y[1]; });
4495
	var PropH = {};
4496
	for(i = 0; i != NumProps; ++i) {
4497
		if(blob.l !== Props[i][1]) {
4498
			var fail = true;
4499
			if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
4500
				case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break;
4501
				case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
4502
				case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
4503
			}
4504
			if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
4505
			if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
4506
		}
4507
		if(PIDSI) {
4508
			var piddsi = PIDSI[Props[i][0]];
4509
			PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
4510
			if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + ("0000" + String(PropH[piddsi.n] & 0xFFFF)).slice(-4);
4511
			if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
4512
				case 0: PropH[piddsi.n] = 1252;
4513
					/* falls through */
4514
				case 874:
4515
				case 932:
4516
				case 936:
4517
				case 949:
4518
				case 950:
4519
				case 1250:
4520
				case 1251:
4521
				case 1253:
4522
				case 1254:
4523
				case 1255:
4524
				case 1256:
4525
				case 1257:
4526
				case 1258:
4527
				case 10000:
4528
				case 1200:
4529
				case 1201:
4530
				case 1252:
4531
				case 65000: case -536:
4532
				case 65001: case -535:
4533
					set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
4534
				default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
4535
			}
4536
		} else {
4537
			if(Props[i][0] === 0x1) {
4538
				CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2)/*:number*/);
4539
				set_cp(CodePage);
4540
				if(Dictionary !== -1) {
4541
					var oldpos = blob.l;
4542
					blob.l = Props[Dictionary][1];
4543
					DictObj = parse_dictionary(blob,CodePage);
4544
					blob.l = oldpos;
4545
				}
4546
			} else if(Props[i][0] === 0) {
4547
				if(CodePage === 0) { Dictionary = i; blob.l = Props[i+1][1]; continue; }
4548
				DictObj = parse_dictionary(blob,CodePage);
4549
			} else {
4550
				var name = DictObj[Props[i][0]];
4551
				var val;
4552
				/* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
4553
				switch(blob[blob.l]) {
4554
					case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
4555
					case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
4556
					case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
4557
					case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
4558
					case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
4559
					case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
4560
					case 0x0B /*VT_BOOL*/: blob.l += 4; val = parsebool(blob, 4); break;
4561
					case 0x40 /*VT_FILETIME*/: blob.l += 4; val = parseDate(parse_FILETIME(blob)); break;
4562
					default: throw new Error("unparsed value: " + blob[blob.l]);
4563
				}
4564
				PropH[name] = val;
4565
			}
4566
		}
4567
	}
4568
	blob.l = start_addr + size; /* step ahead to skip padding */
4569
	return PropH;
4570
}
4571
var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs);
4572
function guess_property_type(val/*:any*/)/*:number*/ {
4573
	switch(typeof val) {
4574
		case "boolean": return 0x0B;
4575
		case "number": return ((val|0)==val) ? 0x03 : 0x05;
4576
		case "string": return 0x1F;
4577
		case "object": if(val instanceof Date) return 0x40; break;
4578
	}
4579
	return -1;
4580
}
4581
function write_PropertySet(entries, RE, PIDSI) {
4582
	var hdr = new_buf(8), piao = [], prop = [];
4583
	var sz = 8, i = 0;
4584
4585
	var pr = new_buf(8), pio = new_buf(8);
4586
	pr.write_shift(4, 0x0002);
4587
	pr.write_shift(4, 0x04B0);
4588
	pio.write_shift(4, 0x0001);
4589
	prop.push(pr); piao.push(pio);
4590
	sz += 8 + pr.length;
4591
4592
	if(!RE) {
4593
		pio = new_buf(8);
4594
		pio.write_shift(4, 0);
4595
		piao.unshift(pio);
4596
4597
		var bufs = [new_buf(4)];
4598
		bufs[0].write_shift(4, entries.length);
4599
		for(i = 0; i < entries.length; ++i) {
4600
			var value = entries[i][0];
4601
			pr = new_buf(4 + 4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
4602
			pr.write_shift(4, i+2);
4603
			pr.write_shift(4, value.length + 1);
4604
			pr.write_shift(0, value, "dbcs");
4605
			while(pr.l != pr.length) pr.write_shift(1, 0);
4606
			bufs.push(pr);
4607
		}
4608
		pr = bconcat(bufs);
4609
		prop.unshift(pr);
4610
		sz += 8 + pr.length;
4611
	}
4612
4613
	for(i = 0; i < entries.length; ++i) {
4614
		if(RE && !RE[entries[i][0]]) continue;
4615
		if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue;
4616
		if(entries[i][1] == null) continue;
4617
4618
		var val = entries[i][1], idx = 0;
4619
		if(RE) {
4620
			idx = +RE[entries[i][0]];
4621
			var pinfo = (PIDSI/*:: || {}*/)[idx]/*:: || {} */;
4622
			if(pinfo.p == "version" && typeof val == "string") {
4623
				/*:: if(typeof val !== "string") throw "unreachable"; */
4624
				var arr = val.split(".");
4625
				val = ((+arr[0])<<16) + ((+arr[1])||0);
4626
			}
4627
			pr = write_TypedPropertyValue(pinfo.t, val);
4628
		} else {
4629
			var T = guess_property_type(val);
4630
			if(T == -1) { T = 0x1F; val = String(val); }
4631
			pr = write_TypedPropertyValue(T, val);
4632
		}
4633
		prop.push(pr);
4634
4635
		pio = new_buf(8);
4636
		pio.write_shift(4, !RE ? 2+i : idx);
4637
		piao.push(pio);
4638
4639
		sz += 8 + pr.length;
4640
	}
4641
4642
	var w = 8 * (prop.length + 1);
4643
	for(i = 0; i < prop.length; ++i) { piao[i].write_shift(4, w); w += prop[i].length; }
4644
	hdr.write_shift(4, sz);
4645
	hdr.write_shift(4, prop.length);
4646
	return bconcat([hdr].concat(piao).concat(prop));
4647
}
4648
4649
/* [MS-OLEPS] 2.21 PropertySetStream */
4650
function parse_PropertySetStream(file, PIDSI, clsid) {
4651
	var blob = file.content;
4652
	if(!blob) return ({}/*:any*/);
4653
	prep_blob(blob, 0);
4654
4655
	var NumSets, FMTID0, FMTID1, Offset0, Offset1 = 0;
4656
	blob.chk('feff', 'Byte Order: ');
4657
4658
	/*var vers = */blob.read_shift(2); // TODO: check version
4659
	var SystemIdentifier = blob.read_shift(4);
4660
	var CLSID = blob.read_shift(16);
4661
	if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
4662
	NumSets = blob.read_shift(4);
4663
	if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
4664
	FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
4665
4666
	if(NumSets === 1 && Offset0 !== blob.l) throw new Error("Length mismatch: " + Offset0 + " !== " + blob.l);
4667
	else if(NumSets === 2) { FMTID1 = blob.read_shift(16); Offset1 = blob.read_shift(4); }
4668
	var PSet0 = parse_PropertySet(blob, PIDSI);
4669
4670
	var rval = ({ SystemIdentifier: SystemIdentifier }/*:any*/);
4671
	for(var y in PSet0) rval[y] = PSet0[y];
4672
	//rval.blob = blob;
4673
	rval.FMTID = FMTID0;
4674
	//rval.PSet0 = PSet0;
4675
	if(NumSets === 1) return rval;
4676
	if(Offset1 - blob.l == 2) blob.l += 2;
4677
	if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
4678
	var PSet1;
4679
	try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
4680
	for(y in PSet1) rval[y] = PSet1[y];
4681
	rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
4682
	return rval;
4683
}
4684
function write_PropertySetStream(entries, clsid, RE, PIDSI/*:{[key:string|number]:any}*/, entries2/*:?any*/, clsid2/*:?any*/) {
4685
	var hdr = new_buf(entries2 ? 68 : 48);
4686
	var bufs = [hdr];
4687
	hdr.write_shift(2, 0xFFFE);
4688
	hdr.write_shift(2, 0x0000); /* TODO: type 1 props */
4689
	hdr.write_shift(4, 0x32363237);
4690
	hdr.write_shift(16, CFB.utils.consts.HEADER_CLSID, "hex");
4691
	hdr.write_shift(4, (entries2 ? 2 : 1));
4692
	hdr.write_shift(16, clsid, "hex");
4693
	hdr.write_shift(4, (entries2 ? 68 : 48));
4694
	var ps0 = write_PropertySet(entries, RE, PIDSI);
4695
	bufs.push(ps0);
4696
4697
	if(entries2) {
4698
		var ps1 = write_PropertySet(entries2, null, null);
4699
		hdr.write_shift(16, clsid2, "hex");
4700
		hdr.write_shift(4, 68 + ps0.length);
4701
		bufs.push(ps1);
4702
	}
4703
	return bconcat(bufs);
4704
}
4705
4706
function parsenoop2(blob, length) { blob.read_shift(length); return null; }
4707
function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j<n; ++j) o.write_shift(1, 0); return o; }
4708
4709
function parslurp(blob, length, cb) {
4710
	var arr = [], target = blob.l + length;
4711
	while(blob.l < target) arr.push(cb(blob, target - blob.l));
4712
	if(target !== blob.l) throw new Error("Slurp error");
4713
	return arr;
4714
}
4715
4716
function parsebool(blob, length/*:number*/) { return blob.read_shift(length) === 0x1; }
4717
function writebool(v/*:any*/, o) { if(!o) o=new_buf(2); o.write_shift(2, +!!v); return o; }
4718
4719
function parseuint16(blob/*::, length:?number, opts:?any*/) { return blob.read_shift(2, 'u'); }
4720
function writeuint16(v/*:number*/, o) { if(!o) o=new_buf(2); o.write_shift(2, v); return o; }
4721
function parseuint16a(blob, length/*:: :?number, opts:?any*/) { return parslurp(blob,length,parseuint16);}
4722
4723
/* --- 2.5 Structures --- */
4724
4725
/* [MS-XLS] 2.5.10 Bes (boolean or error) */
4726
function parse_Bes(blob/*::, length*/) {
4727
	var v = blob.read_shift(1), t = blob.read_shift(1);
4728
	return t === 0x01 ? v : v === 0x01;
4729
}
4730
function write_Bes(v, t/*:string*/, o) {
4731
	if(!o) o = new_buf(2);
4732
	o.write_shift(1, +v);
4733
	o.write_shift(1, ((t == 'e') ? 1 : 0));
4734
	return o;
4735
}
4736
4737
/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
4738
function parse_ShortXLUnicodeString(blob, length, opts) {
4739
	var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1);
4740
	var encoding = 'sbcs-cont';
4741
	var cp = current_codepage;
4742
	if(opts && opts.biff >= 8) current_codepage = 1200;
4743
	if(!opts || opts.biff == 8 ) {
4744
		var fHighByte = blob.read_shift(1);
4745
		if(fHighByte) { encoding = 'dbcs-cont'; }
4746
	} else if(opts.biff == 12) {
4747
		encoding = 'wstr';
4748
	}
4749
	if(opts.biff >= 2 && opts.biff <= 5) encoding = 'cpstr';
4750
	var o = cch ? blob.read_shift(cch, encoding) : "";
4751
	current_codepage = cp;
4752
	return o;
4753
}
4754
4755
/* 2.5.293 XLUnicodeRichExtendedString */
4756
function parse_XLUnicodeRichExtendedString(blob) {
4757
	var cp = current_codepage;
4758
	current_codepage = 1200;
4759
	var cch = blob.read_shift(2), flags = blob.read_shift(1);
4760
	var /*fHighByte = flags & 0x1,*/ fExtSt = flags & 0x4, fRichSt = flags & 0x8;
4761
	var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
4762
	var cRun = 0, cbExtRst;
4763
	var z = {};
4764
	if(fRichSt) cRun = blob.read_shift(2);
4765
	if(fExtSt) cbExtRst = blob.read_shift(4);
4766
	var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont';
4767
	var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
4768
	if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
4769
	if(fExtSt) blob.l += cbExtRst; //TODO: parse this
4770
	z.t = msg;
4771
	if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
4772
	current_codepage = cp;
4773
	return z;
4774
}
4775
4776
/* 2.5.296 XLUnicodeStringNoCch */
4777
function parse_XLUnicodeStringNoCch(blob, cch, opts) {
4778
	var retval;
4779
	if(opts) {
4780
		if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'cpstr');
4781
		if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
4782
	}
4783
	var fHighByte = blob.read_shift(1);
4784
	if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
4785
	else { retval = blob.read_shift(cch, 'dbcs-cont'); }
4786
	return retval;
4787
}
4788
4789
/* 2.5.294 XLUnicodeString */
4790
function parse_XLUnicodeString(blob, length, opts) {
4791
	var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
4792
	if(cch === 0) { blob.l++; return ""; }
4793
	return parse_XLUnicodeStringNoCch(blob, cch, opts);
4794
}
4795
/* BIFF5 override */
4796
function parse_XLUnicodeString2(blob, length, opts) {
4797
	if(opts.biff > 5) return parse_XLUnicodeString(blob, length, opts);
4798
	var cch = blob.read_shift(1);
4799
	if(cch === 0) { blob.l++; return ""; }
4800
	return blob.read_shift(cch, (opts.biff <= 4 || !blob.lens ) ? 'cpstr' : 'sbcs-cont');
4801
}
4802
/* TODO: BIFF5 and lower, codepage awareness */
4803
function write_XLUnicodeString(str, opts, o) {
4804
	if(!o) o = new_buf(3 + 2 * str.length);
4805
	o.write_shift(2, str.length);
4806
	o.write_shift(1, 1);
4807
	o.write_shift(31, str, 'utf16le');
4808
	return o;
4809
}
4810
4811
/* [MS-XLS] 2.5.61 ControlInfo */
4812
function parse_ControlInfo(blob/*::, length, opts*/) {
4813
	var flags = blob.read_shift(1);
4814
	blob.l++;
4815
	var accel = blob.read_shift(2);
4816
	blob.l += 2;
4817
	return [flags, accel];
4818
}
4819
4820
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
4821
function parse_URLMoniker(blob/*::, length, opts*/) {
4822
	var len = blob.read_shift(4), start = blob.l;
4823
	var extra = false;
4824
	if(len > 24) {
4825
		/* look ahead */
4826
		blob.l += len - 24;
4827
		if(blob.read_shift(16) === "795881f43b1d7f48af2c825dc4852763") extra = true;
4828
		blob.l = start;
4829
	}
4830
	var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
4831
	if(extra) blob.l += 24;
4832
	return url;
4833
}
4834
4835
/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
4836
function parse_FileMoniker(blob/*::, length*/) {
4837
	blob.l += 2; //var cAnti = blob.read_shift(2);
4838
	var ansiPath = blob.read_shift(0, 'lpstr-ansi');
4839
	blob.l += 2; //var endServer = blob.read_shift(2);
4840
	if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker");
4841
	var sz = blob.read_shift(4);
4842
	if(sz === 0) return ansiPath.replace(/\\/g,"/");
4843
	var bytes = blob.read_shift(4);
4844
	if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker");
4845
	var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,"");
4846
	return unicodePath;
4847
}
4848
4849
/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
4850
function parse_HyperlinkMoniker(blob, length) {
4851
	var clsid = blob.read_shift(16); length -= 16;
4852
	switch(clsid) {
4853
		case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
4854
		case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
4855
		default: throw new Error("Unsupported Moniker " + clsid);
4856
	}
4857
}
4858
4859
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
4860
function parse_HyperlinkString(blob/*::, length*/) {
4861
	var len = blob.read_shift(4);
4862
	var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
4863
	return o;
4864
}
4865
4866
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
4867
function parse_Hyperlink(blob, length)/*:Hyperlink*/ {
4868
	var end = blob.l + length;
4869
	var sVer = blob.read_shift(4);
4870
	if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
4871
	var flags = blob.read_shift(2);
4872
	blob.l += 2;
4873
	var displayName, targetFrameName, moniker, oleMoniker, Loc="", guid, fileTime;
4874
	if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
4875
	if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
4876
	if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
4877
	if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
4878
	if(flags & 0x0008) Loc = parse_HyperlinkString(blob, end - blob.l);
4879
	if(flags & 0x0020) guid = blob.read_shift(16);
4880
	if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
4881
	blob.l = end;
4882
	var target = targetFrameName||moniker||oleMoniker||"";
4883
	if(target && Loc) target+="#"+Loc;
4884
	if(!target) target = "#" + Loc;
4885
	var out = ({Target:target}/*:any*/);
4886
	if(guid) out.guid = guid;
4887
	if(fileTime) out.time = fileTime;
4888
	if(displayName) out.Tooltip = displayName;
4889
	return out;
4890
}
4891
function write_Hyperlink(hl) {
4892
	var out = new_buf(512), i = 0;
4893
	var Target = hl.Target;
4894
	var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
4895
	switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
4896
	out.write_shift(4,2); out.write_shift(4, F);
4897
	var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
4898
	if(F == 0x1C) {
4899
		Target = Target.slice(1);
4900
		out.write_shift(4, Target.length + 1);
4901
		for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
4902
		out.write_shift(2, 0);
4903
	} else if(F & 0x02) {
4904
		data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
4905
		for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
4906
		out.write_shift(4, 2*(Target.length + 1));
4907
		for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
4908
		out.write_shift(2, 0);
4909
	} else {
4910
		data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
4911
		for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
4912
		var P = 0;
4913
		while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
4914
		out.write_shift(2, P);
4915
		out.write_shift(4, Target.length + 1);
4916
		for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
4917
		out.write_shift(1, 0);
4918
		out.write_shift(2, 0xFFFF);
4919
		out.write_shift(2, 0xDEAD);
4920
		for(i = 0; i < 6; ++i) out.write_shift(4, 0);
4921
	}
4922
	return out.slice(0, out.l);
4923
}
4924
4925
/* 2.5.178 LongRGBA */
4926
function parse_LongRGBA(blob/*::, length*/) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
4927
4928
/* 2.5.177 LongRGB */
4929
function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
4930
4931
4932
/* [MS-XLS] 2.5.19 */
4933
function parse_XLSCell(blob/*::, length*/)/*:Cell*/ {
4934
	var rw = blob.read_shift(2); // 0-indexed
4935
	var col = blob.read_shift(2);
4936
	var ixfe = blob.read_shift(2);
4937
	return ({r:rw, c:col, ixfe:ixfe}/*:any*/);
4938
}
4939
function write_XLSCell(R/*:number*/, C/*:number*/, ixfe/*:?number*/, o) {
4940
	if(!o) o = new_buf(6);
4941
	o.write_shift(2, R);
4942
	o.write_shift(2, C);
4943
	o.write_shift(2, ixfe||0);
4944
	return o;
4945
}
4946
4947
/* [MS-XLS] 2.5.134 */
4948
function parse_frtHeader(blob) {
4949
	var rt = blob.read_shift(2);
4950
	var flags = blob.read_shift(2); // TODO: parse these flags
4951
	blob.l += 8;
4952
	return {type: rt, flags: flags};
4953
}
4954
4955
4956
4957
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
4958
4959
/* [MS-XLS] 2.5.344 */
4960
function parse_XTI(blob, length, opts) {
4961
	var w = opts.biff > 8 ? 4 : 2;
4962
	var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
4963
	return [iSupBook, itabFirst, itabLast];
4964
}
4965
4966
/* [MS-XLS] 2.5.218 */
4967
function parse_RkRec(blob) {
4968
	var ixfe = blob.read_shift(2);
4969
	var RK = parse_RkNumber(blob);
4970
	return [ixfe, RK];
4971
}
4972
4973
/* [MS-XLS] 2.5.1 */
4974
function parse_AddinUdf(blob, length, opts) {
4975
	blob.l += 4; length -= 4;
4976
	var l = blob.l + length;
4977
	var udfName = parse_ShortXLUnicodeString(blob, length, opts);
4978
	var cb = blob.read_shift(2);
4979
	l -= blob.l;
4980
	if(cb !== l) throw new Error("Malformed AddinUdf: padding = " + l + " != " + cb);
4981
	blob.l += cb;
4982
	return udfName;
4983
}
4984
4985
/* [MS-XLS] 2.5.209 TODO: Check sizes */
4986
function parse_Ref8U(blob/*::, length*/) {
4987
	var rwFirst = blob.read_shift(2);
4988
	var rwLast = blob.read_shift(2);
4989
	var colFirst = blob.read_shift(2);
4990
	var colLast = blob.read_shift(2);
4991
	return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
4992
}
4993
function write_Ref8U(r/*:Range*/, o) {
4994
	if(!o) o = new_buf(8);
4995
	o.write_shift(2, r.s.r);
4996
	o.write_shift(2, r.e.r);
4997
	o.write_shift(2, r.s.c);
4998
	o.write_shift(2, r.e.c);
4999
	return o;
5000
}
5001
5002
/* [MS-XLS] 2.5.211 */
5003
function parse_RefU(blob/*::, length*/) {
5004
	var rwFirst = blob.read_shift(2);
5005
	var rwLast = blob.read_shift(2);
5006
	var colFirst = blob.read_shift(1);
5007
	var colLast = blob.read_shift(1);
5008
	return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5009
}
5010
5011
/* [MS-XLS] 2.5.207 */
5012
var parse_Ref = parse_RefU;
5013
5014
/* [MS-XLS] 2.5.143 */
5015
function parse_FtCmo(blob/*::, length*/) {
5016
	blob.l += 4;
5017
	var ot = blob.read_shift(2);
5018
	var id = blob.read_shift(2);
5019
	var flags = blob.read_shift(2);
5020
	blob.l+=12;
5021
	return [id, ot, flags];
5022
}
5023
5024
/* [MS-XLS] 2.5.149 */
5025
function parse_FtNts(blob) {
5026
	var out = {};
5027
	blob.l += 4;
5028
	blob.l += 16; // GUID TODO
5029
	out.fSharedNote = blob.read_shift(2);
5030
	blob.l += 4;
5031
	return out;
5032
}
5033
5034
/* [MS-XLS] 2.5.142 */
5035
function parse_FtCf(blob) {
5036
	var out = {};
5037
	blob.l += 4;
5038
	blob.cf = blob.read_shift(2);
5039
	return out;
5040
}
5041
5042
/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
5043
function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
5044
var FtTab = {
5045
	/*::[*/0x00/*::]*/: parse_FtSkip,      /* FtEnd */
5046
	/*::[*/0x04/*::]*/: parse_FtSkip,      /* FtMacro */
5047
	/*::[*/0x05/*::]*/: parse_FtSkip,      /* FtButton */
5048
	/*::[*/0x06/*::]*/: parse_FtSkip,      /* FtGmo */
5049
	/*::[*/0x07/*::]*/: parse_FtCf,        /* FtCf */
5050
	/*::[*/0x08/*::]*/: parse_FtSkip,      /* FtPioGrbit */
5051
	/*::[*/0x09/*::]*/: parse_FtSkip,      /* FtPictFmla */
5052
	/*::[*/0x0A/*::]*/: parse_FtSkip,      /* FtCbls */
5053
	/*::[*/0x0B/*::]*/: parse_FtSkip,      /* FtRbo */
5054
	/*::[*/0x0C/*::]*/: parse_FtSkip,      /* FtSbs */
5055
	/*::[*/0x0D/*::]*/: parse_FtNts,       /* FtNts */
5056
	/*::[*/0x0E/*::]*/: parse_FtSkip,      /* FtSbsFmla */
5057
	/*::[*/0x0F/*::]*/: parse_FtSkip,      /* FtGboData */
5058
	/*::[*/0x10/*::]*/: parse_FtSkip,      /* FtEdoData */
5059
	/*::[*/0x11/*::]*/: parse_FtSkip,      /* FtRboData */
5060
	/*::[*/0x12/*::]*/: parse_FtSkip,      /* FtCblsData */
5061
	/*::[*/0x13/*::]*/: parse_FtSkip,      /* FtLbsData */
5062
	/*::[*/0x14/*::]*/: parse_FtSkip,      /* FtCblsFmla */
5063
	/*::[*/0x15/*::]*/: parse_FtCmo
5064
};
5065
function parse_FtArray(blob, length/*::, ot*/) {
5066
	var tgt = blob.l + length;
5067
	var fts = [];
5068
	while(blob.l < tgt) {
5069
		var ft = blob.read_shift(2);
5070
		blob.l-=2;
5071
		try {
5072
			fts.push(FtTab[ft](blob, tgt - blob.l));
5073
		} catch(e) { blob.l = tgt; return fts; }
5074
	}
5075
	if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
5076
	return fts;
5077
}
5078
5079
/* --- 2.4 Records --- */
5080
5081
/* [MS-XLS] 2.4.21 */
5082
function parse_BOF(blob, length) {
5083
	var o = {BIFFVer:0, dt:0};
5084
	o.BIFFVer = blob.read_shift(2); length -= 2;
5085
	if(length >= 2) { o.dt = blob.read_shift(2); blob.l -= 2; }
5086
	switch(o.BIFFVer) {
5087
		case 0x0600: /* BIFF8 */
5088
		case 0x0500: /* BIFF5 */
5089
		case 0x0400: /* BIFF4 */
5090
		case 0x0300: /* BIFF3 */
5091
		case 0x0200: /* BIFF2 */
5092
		case 0x0002: case 0x0007: /* BIFF2 */
5093
			break;
5094
		default: if(length > 6) throw new Error("Unexpected BIFF Ver " + o.BIFFVer);
5095
	}
5096
5097
	blob.read_shift(length);
5098
	return o;
5099
}
5100
function write_BOF(wb/*:Workbook*/, t/*:number*/, o) {
5101
	var h = 0x0600, w = 16;
5102
	switch(o.bookType) {
5103
		case 'biff8': break;
5104
		case 'biff5': h = 0x0500; w = 8; break;
5105
		case 'biff4': h = 0x0004; w = 6; break;
5106
		case 'biff3': h = 0x0003; w = 6; break;
5107
		case 'biff2': h = 0x0002; w = 4; break;
5108
		case 'xla': break;
5109
		default: throw new Error("unsupported BIFF version");
5110
	}
5111
	var out = new_buf(w);
5112
	out.write_shift(2, h);
5113
	out.write_shift(2, t);
5114
	if(w > 4) out.write_shift(2, 0x7262);
5115
	if(w > 6) out.write_shift(2, 0x07CD);
5116
	if(w > 8) {
5117
		out.write_shift(2, 0xC009);
5118
		out.write_shift(2, 0x0001);
5119
		out.write_shift(2, 0x0706);
5120
		out.write_shift(2, 0x0000);
5121
	}
5122
	return out;
5123
}
5124
5125
5126
/* [MS-XLS] 2.4.146 */
5127
function parse_InterfaceHdr(blob, length) {
5128
	if(length === 0) return 0x04b0;
5129
	if((blob.read_shift(2))!==0x04b0){/* empty */}
5130
	return 0x04b0;
5131
}
5132
5133
5134
/* [MS-XLS] 2.4.349 */
5135
function parse_WriteAccess(blob, length, opts) {
5136
	if(opts.enc) { blob.l += length; return ""; }
5137
	var l = blob.l;
5138
	// TODO: make sure XLUnicodeString doesnt overrun
5139
	var UserName = parse_XLUnicodeString2(blob, 0, opts);
5140
	blob.read_shift(length + l - blob.l);
5141
	return UserName;
5142
}
5143
function write_WriteAccess(s/*:string*/, opts) {
5144
	var b8 = !opts || opts.biff == 8;
5145
	var o = new_buf(b8 ? 112 : 54);
5146
	o.write_shift(opts.biff == 8 ? 2 : 1, 7);
5147
	if(b8) o.write_shift(1, 0);
5148
	o.write_shift(4, 0x33336853);
5149
	o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
5150
	while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
5151
	return o;
5152
}
5153
5154
/* [MS-XLS] 2.4.351 */
5155
function parse_WsBool(blob, length, opts) {
5156
	var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
5157
	return { fDialog: flags & 0x10 };
5158
}
5159
5160
/* [MS-XLS] 2.4.28 */
5161
function parse_BoundSheet8(blob, length, opts) {
5162
	var pos = blob.read_shift(4);
5163
	var hidden = blob.read_shift(1) & 0x03;
5164
	var dt = blob.read_shift(1);
5165
	switch(dt) {
5166
		case 0: dt = 'Worksheet'; break;
5167
		case 1: dt = 'Macrosheet'; break;
5168
		case 2: dt = 'Chartsheet'; break;
5169
		case 6: dt = 'VBAModule'; break;
5170
	}
5171
	var name = parse_ShortXLUnicodeString(blob, 0, opts);
5172
	if(name.length === 0) name = "Sheet1";
5173
	return { pos:pos, hs:hidden, dt:dt, name:name };
5174
}
5175
function write_BoundSheet8(data, opts) {
5176
	var w = (!opts || opts.biff >= 8 ? 2 : 1);
5177
	var o = new_buf(8 + w * data.name.length);
5178
	o.write_shift(4, data.pos);
5179
	o.write_shift(1, data.hs || 0);
5180
	o.write_shift(1, data.dt);
5181
	o.write_shift(1, data.name.length);
5182
	if(opts.biff >= 8) o.write_shift(1, 1);
5183
	o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
5184
	var out = o.slice(0, o.l);
5185
	out.l = o.l; return out;
5186
}
5187
5188
/* [MS-XLS] 2.4.265 TODO */
5189
function parse_SST(blob, length)/*:SST*/ {
5190
	var end = blob.l + length;
5191
	var cnt = blob.read_shift(4);
5192
	var ucnt = blob.read_shift(4);
5193
	var strs/*:SST*/ = ([]/*:any*/);
5194
	for(var i = 0; i != ucnt && blob.l < end; ++i) {
5195
		strs.push(parse_XLUnicodeRichExtendedString(blob));
5196
	}
5197
	strs.Count = cnt; strs.Unique = ucnt;
5198
	return strs;
5199
}
5200
5201
/* [MS-XLS] 2.4.107 */
5202
function parse_ExtSST(blob, length) {
5203
	var extsst = {};
5204
	extsst.dsst = blob.read_shift(2);
5205
	blob.l += length-2;
5206
	return extsst;
5207
}
5208
5209
5210
/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
5211
function parse_Row(blob) {
5212
	var z = ({}/*:any*/);
5213
	z.r = blob.read_shift(2);
5214
	z.c = blob.read_shift(2);
5215
	z.cnt = blob.read_shift(2) - z.c;
5216
	var miyRw = blob.read_shift(2);
5217
	blob.l += 4; // reserved(2), unused(2)
5218
	var flags = blob.read_shift(1); // various flags
5219
	blob.l += 3; // reserved(8), ixfe(12), flags(4)
5220
	if(flags & 0x07) z.level = flags & 0x07;
5221
	// collapsed: flags & 0x10
5222
	if(flags & 0x20) z.hidden = true;
5223
	if(flags & 0x40) z.hpt = miyRw / 20;
5224
	return z;
5225
}
5226
5227
5228
/* [MS-XLS] 2.4.125 */
5229
function parse_ForceFullCalculation(blob) {
5230
	var header = parse_frtHeader(blob);
5231
	if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
5232
	var fullcalc = blob.read_shift(4);
5233
	return fullcalc !== 0x0;
5234
}
5235
5236
5237
5238
5239
5240
/* [MS-XLS] 2.4.215 rt */
5241
function parse_RecalcId(blob) {
5242
	blob.read_shift(2);
5243
	return blob.read_shift(4);
5244
}
5245
5246
/* [MS-XLS] 2.4.87 */
5247
function parse_DefaultRowHeight(blob, length, opts) {
5248
	var f = 0;
5249
	if(!(opts && opts.biff == 2)) {
5250
		f = blob.read_shift(2);
5251
	}
5252
	var miyRw = blob.read_shift(2);
5253
	if((opts && opts.biff == 2)) {
5254
		f = 1 - (miyRw >> 15); miyRw &= 0x7fff;
5255
	}
5256
	var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
5257
	return [fl, miyRw];
5258
}
5259
5260
/* [MS-XLS] 2.4.345 TODO */
5261
function parse_Window1(blob) {
5262
	var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
5263
	var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
5264
	var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
5265
	return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
5266
		FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
5267
}
5268
function write_Window1(/*::opts*/) {
5269
	var o = new_buf(18);
5270
	o.write_shift(2, 0);
5271
	o.write_shift(2, 0);
5272
	o.write_shift(2, 0x7260);
5273
	o.write_shift(2, 0x44c0);
5274
	o.write_shift(2, 0x38);
5275
	o.write_shift(2, 0);
5276
	o.write_shift(2, 0);
5277
	o.write_shift(2, 1);
5278
	o.write_shift(2, 0x01f4);
5279
	return o;
5280
}
5281
/* [MS-XLS] 2.4.346 TODO */
5282
function parse_Window2(blob, length, opts) {
5283
	if(opts && opts.biff >= 2 && opts.biff < 8) return {};
5284
	var f = blob.read_shift(2);
5285
	return { RTL: f & 0x40 };
5286
}
5287
function write_Window2(view) {
5288
	var o = new_buf(18), f = 0x6b6;
5289
	if(view && view.RTL) f |= 0x40;
5290
	o.write_shift(2, f);
5291
	o.write_shift(4, 0);
5292
	o.write_shift(4, 64);
5293
	o.write_shift(4, 0);
5294
	o.write_shift(4, 0);
5295
	return o;
5296
}
5297
5298
/* [MS-XLS] 2.4.122 TODO */
5299
function parse_Font(blob, length, opts) {
5300
	var o/*:any*/ = {
5301
		dyHeight: blob.read_shift(2),
5302
		fl: blob.read_shift(2)
5303
	};
5304
	switch((opts && opts.biff) || 8) {
5305
		case 2: break;
5306
		case 3: case 4: blob.l += 2; break;
5307
		default: blob.l += 10; break;
5308
	}
5309
	o.name = parse_ShortXLUnicodeString(blob, 0, opts);
5310
	return o;
5311
}
5312
function write_Font(data, opts) {
5313
	var name = data.name || "Arial";
5314
	var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
5315
	var o = new_buf(w);
5316
	o.write_shift(2, (data.sz || 12) * 20);
5317
	o.write_shift(4, 0);
5318
	o.write_shift(2, 400);
5319
	o.write_shift(4, 0);
5320
	o.write_shift(2, 0);
5321
	o.write_shift(1, name.length);
5322
	if(!b5) o.write_shift(1, 1);
5323
	o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
5324
	return o;
5325
}
5326
5327
/* [MS-XLS] 2.4.149 */
5328
function parse_LabelSst(blob) {
5329
	var cell = parse_XLSCell(blob);
5330
	cell.isst = blob.read_shift(4);
5331
	return cell;
5332
}
5333
5334
/* [MS-XLS] 2.4.148 */
5335
function parse_Label(blob, length, opts) {
5336
	var target = blob.l + length;
5337
	var cell = parse_XLSCell(blob, 6);
5338
	if(opts.biff == 2) blob.l++;
5339
	var str = parse_XLUnicodeString(blob, target - blob.l, opts);
5340
	cell.val = str;
5341
	return cell;
5342
}
5343
function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, os/*:number*/, opts) {
5344
	var b8 = !opts || opts.biff == 8;
5345
	var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
5346
	write_XLSCell(R, C, os, o);
5347
	o.write_shift(2, v.length);
5348
	if(b8) o.write_shift(1, 1);
5349
	o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
5350
	return o;
5351
}
5352
5353
5354
/* [MS-XLS] 2.4.126 Number Formats */
5355
function parse_Format(blob, length, opts) {
5356
	var numFmtId = blob.read_shift(2);
5357
	var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
5358
	return [numFmtId, fmtstr];
5359
}
5360
function write_Format(i/*:number*/, f/*:string*/, opts, o) {
5361
	var b5 = (opts && (opts.biff == 5));
5362
	if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
5363
	o.write_shift(2, i);
5364
	o.write_shift((b5 ? 1 : 2), f.length);
5365
	if(!b5) o.write_shift(1, 1);
5366
	o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
5367
	var out = (o.length > o.l) ? o.slice(0, o.l) : o;
5368
	if(out.l == null) out.l = out.length;
5369
	return out;
5370
}
5371
var parse_BIFF2Format = parse_XLUnicodeString2;
5372
5373
/* [MS-XLS] 2.4.90 */
5374
function parse_Dimensions(blob, length, opts) {
5375
	var end = blob.l + length;
5376
	var w = opts.biff == 8 || !opts.biff ? 4 : 2;
5377
	var r = blob.read_shift(w), R = blob.read_shift(w);
5378
	var c = blob.read_shift(2), C = blob.read_shift(2);
5379
	blob.l = end;
5380
	return {s: {r:r, c:c}, e: {r:R, c:C}};
5381
}
5382
function write_Dimensions(range, opts) {
5383
	var w = opts.biff == 8 || !opts.biff ? 4 : 2;
5384
	var o = new_buf(2*w + 6);
5385
	o.write_shift(w, range.s.r);
5386
	o.write_shift(w, range.e.r + 1);
5387
	o.write_shift(2, range.s.c);
5388
	o.write_shift(2, range.e.c + 1);
5389
	o.write_shift(2, 0);
5390
	return o;
5391
}
5392
5393
/* [MS-XLS] 2.4.220 */
5394
function parse_RK(blob) {
5395
	var rw = blob.read_shift(2), col = blob.read_shift(2);
5396
	var rkrec = parse_RkRec(blob);
5397
	return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
5398
}
5399
5400
/* [MS-XLS] 2.4.175 */
5401
function parse_MulRk(blob, length) {
5402
	var target = blob.l + length - 2;
5403
	var rw = blob.read_shift(2), col = blob.read_shift(2);
5404
	var rkrecs = [];
5405
	while(blob.l < target) rkrecs.push(parse_RkRec(blob));
5406
	if(blob.l !== target) throw new Error("MulRK read error");
5407
	var lastcol = blob.read_shift(2);
5408
	if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
5409
	return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
5410
}
5411
/* [MS-XLS] 2.4.174 */
5412
function parse_MulBlank(blob, length) {
5413
	var target = blob.l + length - 2;
5414
	var rw = blob.read_shift(2), col = blob.read_shift(2);
5415
	var ixfes = [];
5416
	while(blob.l < target) ixfes.push(blob.read_shift(2));
5417
	if(blob.l !== target) throw new Error("MulBlank read error");
5418
	var lastcol = blob.read_shift(2);
5419
	if(ixfes.length != lastcol - col + 1) throw new Error("MulBlank length mismatch");
5420
	return {r:rw, c:col, C:lastcol, ixfe:ixfes};
5421
}
5422
5423
/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
5424
function parse_CellStyleXF(blob, length, style, opts) {
5425
	var o = {};
5426
	var a = blob.read_shift(4), b = blob.read_shift(4);
5427
	var c = blob.read_shift(4), d = blob.read_shift(2);
5428
	o.patternType = XLSFillPattern[c >> 26];
5429
5430
	if(!opts.cellStyles) return o;
5431
	o.alc = a & 0x07;
5432
	o.fWrap = (a >> 3) & 0x01;
5433
	o.alcV = (a >> 4) & 0x07;
5434
	o.fJustLast = (a >> 7) & 0x01;
5435
	o.trot = (a >> 8) & 0xFF;
5436
	o.cIndent = (a >> 16) & 0x0F;
5437
	o.fShrinkToFit = (a >> 20) & 0x01;
5438
	o.iReadOrder = (a >> 22) & 0x02;
5439
	o.fAtrNum = (a >> 26) & 0x01;
5440
	o.fAtrFnt = (a >> 27) & 0x01;
5441
	o.fAtrAlc = (a >> 28) & 0x01;
5442
	o.fAtrBdr = (a >> 29) & 0x01;
5443
	o.fAtrPat = (a >> 30) & 0x01;
5444
	o.fAtrProt = (a >> 31) & 0x01;
5445
5446
	o.dgLeft = b & 0x0F;
5447
	o.dgRight = (b >> 4) & 0x0F;
5448
	o.dgTop = (b >> 8) & 0x0F;
5449
	o.dgBottom = (b >> 12) & 0x0F;
5450
	o.icvLeft = (b >> 16) & 0x7F;
5451
	o.icvRight = (b >> 23) & 0x7F;
5452
	o.grbitDiag = (b >> 30) & 0x03;
5453
5454
	o.icvTop = c & 0x7F;
5455
	o.icvBottom = (c >> 7) & 0x7F;
5456
	o.icvDiag = (c >> 14) & 0x7F;
5457
	o.dgDiag = (c >> 21) & 0x0F;
5458
5459
	o.icvFore = d & 0x7F;
5460
	o.icvBack = (d >> 7) & 0x7F;
5461
	o.fsxButton = (d >> 14) & 0x01;
5462
	return o;
5463
}
5464
//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
5465
//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
5466
5467
/* [MS-XLS] 2.4.353 TODO: actually do this right */
5468
function parse_XF(blob, length, opts) {
5469
	var o = {};
5470
	o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
5471
	o.fStyle = (o.flags >> 2) & 0x01;
5472
	length -= 6;
5473
	o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
5474
	return o;
5475
}
5476
function write_XF(data, ixfeP, opts, o) {
5477
	var b5 = (opts && (opts.biff == 5));
5478
	if(!o) o = new_buf(b5 ? 16 : 20);
5479
	o.write_shift(2, 0);
5480
	if(data.style) {
5481
		o.write_shift(2, (data.numFmtId||0));
5482
		o.write_shift(2, 0xFFF4);
5483
	} else {
5484
		o.write_shift(2, (data.numFmtId||0));
5485
		o.write_shift(2, (ixfeP<<4));
5486
	}
5487
	o.write_shift(4, 0);
5488
	o.write_shift(4, 0);
5489
	if(!b5) o.write_shift(4, 0);
5490
	o.write_shift(2, 0);
5491
	return o;
5492
}
5493
5494
/* [MS-XLS] 2.4.134 */
5495
function parse_Guts(blob) {
5496
	blob.l += 4;
5497
	var out = [blob.read_shift(2), blob.read_shift(2)];
5498
	if(out[0] !== 0) out[0]--;
5499
	if(out[1] !== 0) out[1]--;
5500
	if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
5501
	return out;
5502
}
5503
function write_Guts(guts/*:Array<number>*/) {
5504
	var o = new_buf(8);
5505
	o.write_shift(4, 0);
5506
	o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
5507
	o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
5508
	return o;
5509
}
5510
5511
/* [MS-XLS] 2.4.24 */
5512
function parse_BoolErr(blob, length, opts) {
5513
	var cell = parse_XLSCell(blob, 6);
5514
	if(opts.biff == 2) ++blob.l;
5515
	var val = parse_Bes(blob, 2);
5516
	cell.val = val;
5517
	cell.t = (val === true || val === false) ? 'b' : 'e';
5518
	return cell;
5519
}
5520
function write_BoolErr(R/*:number*/, C/*:number*/, v, os/*:number*/, opts, t/*:string*/) {
5521
	var o = new_buf(8);
5522
	write_XLSCell(R, C, os, o);
5523
	write_Bes(v, t, o);
5524
	return o;
5525
}
5526
5527
/* [MS-XLS] 2.4.180 Number */
5528
function parse_Number(blob) {
5529
	var cell = parse_XLSCell(blob, 6);
5530
	var xnum = parse_Xnum(blob, 8);
5531
	cell.val = xnum;
5532
	return cell;
5533
}
5534
function write_Number(R/*:number*/, C/*:number*/, v, os/*:: :number, opts*/) {
5535
	var o = new_buf(14);
5536
	write_XLSCell(R, C, os, o);
5537
	write_Xnum(v, o);
5538
	return o;
5539
}
5540
5541
var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
5542
5543
/* [MS-XLS] 2.4.271 */
5544
function parse_SupBook(blob, length, opts) {
5545
	var end = blob.l + length;
5546
	var ctab = blob.read_shift(2);
5547
	var cch = blob.read_shift(2);
5548
	opts.sbcch = cch;
5549
	if(cch == 0x0401 || cch == 0x3A01) return [cch, ctab];
5550
	if(cch < 0x01 || cch >0xff) throw new Error("Unexpected SupBook type: "+cch);
5551
	var virtPath = parse_XLUnicodeStringNoCch(blob, cch);
5552
	/* TODO: 2.5.277 Virtual Path */
5553
	var rgst = [];
5554
	while(end > blob.l) rgst.push(parse_XLUnicodeString(blob));
5555
	return [cch, ctab, virtPath, rgst];
5556
}
5557
5558
/* [MS-XLS] 2.4.105 TODO */
5559
function parse_ExternName(blob, length, opts) {
5560
	var flags = blob.read_shift(2);
5561
	var body;
5562
	var o = ({
5563
		fBuiltIn: flags & 0x01,
5564
		fWantAdvise: (flags >>> 1) & 0x01,
5565
		fWantPict: (flags >>> 2) & 0x01,
5566
		fOle: (flags >>> 3) & 0x01,
5567
		fOleLink: (flags >>> 4) & 0x01,
5568
		cf: (flags >>> 5) & 0x3FF,
5569
		fIcon: flags >>> 15 & 0x01
5570
	}/*:any*/);
5571
	if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts);
5572
	//else throw new Error("unsupported SupBook cch: " + opts.sbcch);
5573
	o.body = body || blob.read_shift(length-2);
5574
	if(typeof body === "string") o.Name = body;
5575
	return o;
5576
}
5577
5578
/* [MS-XLS] 2.4.150 TODO */
5579
var XLSLblBuiltIn = [
5580
	"_xlnm.Consolidate_Area",
5581
	"_xlnm.Auto_Open",
5582
	"_xlnm.Auto_Close",
5583
	"_xlnm.Extract",
5584
	"_xlnm.Database",
5585
	"_xlnm.Criteria",
5586
	"_xlnm.Print_Area",
5587
	"_xlnm.Print_Titles",
5588
	"_xlnm.Recorder",
5589
	"_xlnm.Data_Form",
5590
	"_xlnm.Auto_Activate",
5591
	"_xlnm.Auto_Deactivate",
5592
	"_xlnm.Sheet_Title",
5593
	"_xlnm._FilterDatabase"
5594
];
5595
function parse_Lbl(blob, length, opts) {
5596
	var target = blob.l + length;
5597
	var flags = blob.read_shift(2);
5598
	var chKey = blob.read_shift(1);
5599
	var cch = blob.read_shift(1);
5600
	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
5601
	var itab = 0;
5602
	if(!opts || opts.biff >= 5) {
5603
		if(opts.biff != 5) blob.l += 2;
5604
		itab = blob.read_shift(2);
5605
		if(opts.biff == 5) blob.l += 2;
5606
		blob.l += 4;
5607
	}
5608
	var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
5609
	if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
5610
	var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
5611
	var rgce = target == blob.l || cce === 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
5612
	return {
5613
		chKey: chKey,
5614
		Name: name,
5615
		itab: itab,
5616
		rgce: rgce
5617
	};
5618
}
5619
5620
/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
5621
function parse_ExternSheet(blob, length, opts) {
5622
	if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
5623
	var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
5624
	while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
5625
		// [iSupBook, itabFirst, itabLast];
5626
	if(blob.l != target) throw new Error("Bad ExternSheet: " + blob.l + " != " + target);
5627
	return o;
5628
}
5629
function parse_BIFF5ExternSheet(blob, length, opts) {
5630
	if(blob[blob.l + 1] == 0x03) blob[blob.l]++;
5631
	var o = parse_ShortXLUnicodeString(blob, length, opts);
5632
	return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
5633
}
5634
5635
/* [MS-XLS] 2.4.176 TODO: check older biff */
5636
function parse_NameCmt(blob, length, opts) {
5637
	if(opts.biff < 8) { blob.l += length; return; }
5638
	var cchName = blob.read_shift(2);
5639
	var cchComment = blob.read_shift(2);
5640
	var name = parse_XLUnicodeStringNoCch(blob, cchName, opts);
5641
	var comment = parse_XLUnicodeStringNoCch(blob, cchComment, opts);
5642
	return [name, comment];
5643
}
5644
5645
/* [MS-XLS] 2.4.260 */
5646
function parse_ShrFmla(blob, length, opts) {
5647
	var ref = parse_RefU(blob, 6);
5648
	blob.l++;
5649
	var cUse = blob.read_shift(1);
5650
	length -= 8;
5651
	return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
5652
}
5653
5654
/* [MS-XLS] 2.4.4 TODO */
5655
function parse_Array(blob, length, opts) {
5656
	var ref = parse_Ref(blob, 6);
5657
	/* TODO: fAlwaysCalc */
5658
	switch(opts.biff) {
5659
		case 2: blob.l ++; length -= 7; break;
5660
		case 3: case 4: blob.l += 2; length -= 8; break;
5661
		default: blob.l += 6; length -= 12;
5662
	}
5663
	return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
5664
}
5665
5666
/* [MS-XLS] 2.4.173 */
5667
function parse_MTRSettings(blob) {
5668
	var fMTREnabled = blob.read_shift(4) !== 0x00;
5669
	var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
5670
	var cUserThreadCount = blob.read_shift(4);
5671
	return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
5672
}
5673
5674
/* [MS-XLS] 2.5.186 TODO: BIFF5 */
5675
function parse_NoteSh(blob, length, opts) {
5676
	if(opts.biff < 8) return;
5677
	var row = blob.read_shift(2), col = blob.read_shift(2);
5678
	var flags = blob.read_shift(2), idObj = blob.read_shift(2);
5679
	var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
5680
	if(opts.biff < 8) blob.read_shift(1);
5681
	return [{r:row,c:col}, stAuthor, idObj, flags];
5682
}
5683
5684
/* [MS-XLS] 2.4.179 */
5685
function parse_Note(blob, length, opts) {
5686
	/* TODO: Support revisions */
5687
	return parse_NoteSh(blob, length, opts);
5688
}
5689
5690
/* [MS-XLS] 2.4.168 */
5691
function parse_MergeCells(blob, length)/*:Array<Range>*/ {
5692
	var merges/*:Array<Range>*/ = [];
5693
	var cmcs = blob.read_shift(2);
5694
	while (cmcs--) merges.push(parse_Ref8U(blob,length));
5695
	return merges;
5696
}
5697
function write_MergeCells(merges/*:Array<Range>*/) {
5698
	var o = new_buf(2 + merges.length * 8);
5699
	o.write_shift(2, merges.length);
5700
	for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o);
5701
	return o;
5702
}
5703
5704
/* [MS-XLS] 2.4.181 TODO: parse all the things! */
5705
function parse_Obj(blob, length, opts) {
5706
	if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
5707
	var cmo = parse_FtCmo(blob, 22); // id, ot, flags
5708
	var fts = parse_FtArray(blob, length-22, cmo[1]);
5709
	return { cmo: cmo, ft:fts };
5710
}
5711
/* from older spec */
5712
var parse_BIFF5OT = [];
5713
parse_BIFF5OT[0x08] = function(blob, length) {
5714
	var tgt = blob.l + length;
5715
	blob.l += 10; // todo
5716
	var cf = blob.read_shift(2);
5717
	blob.l += 4;
5718
	blob.l += 2; //var cbPictFmla = blob.read_shift(2);
5719
	blob.l += 2;
5720
	blob.l += 2; //var grbit = blob.read_shift(2);
5721
	blob.l += 4;
5722
	var cchName = blob.read_shift(1);
5723
	blob.l += cchName; // TODO: stName
5724
	blob.l = tgt; // TODO: fmla
5725
	return { fmt:cf };
5726
};
5727
5728
function parse_BIFF5Obj(blob, length, opts) {
5729
	blob.l += 4; //var cnt = blob.read_shift(4);
5730
	var ot = blob.read_shift(2);
5731
	var id = blob.read_shift(2);
5732
	var grbit = blob.read_shift(2);
5733
	blob.l += 2; //var colL = blob.read_shift(2);
5734
	blob.l += 2; //var dxL = blob.read_shift(2);
5735
	blob.l += 2; //var rwT = blob.read_shift(2);
5736
	blob.l += 2; //var dyT = blob.read_shift(2);
5737
	blob.l += 2; //var colR = blob.read_shift(2);
5738
	blob.l += 2; //var dxR = blob.read_shift(2);
5739
	blob.l += 2; //var rwB = blob.read_shift(2);
5740
	blob.l += 2; //var dyB = blob.read_shift(2);
5741
	blob.l += 2; //var cbMacro = blob.read_shift(2);
5742
	blob.l += 6;
5743
	length -= 36;
5744
	var fts = [];
5745
	fts.push((parse_BIFF5OT[ot]||parsenoop)(blob, length, opts));
5746
	return { cmo: [id, ot, grbit], ft:fts };
5747
}
5748
5749
/* [MS-XLS] 2.4.329 TODO: parse properly */
5750
function parse_TxO(blob, length, opts) {
5751
	var s = blob.l;
5752
	var texts = "";
5753
try {
5754
	blob.l += 4;
5755
	var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
5756
	var controlInfo; // eslint-disable-line no-unused-vars
5757
	if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
5758
	else controlInfo = parse_ControlInfo(blob, 6, opts);
5759
	var cchText = blob.read_shift(2);
5760
	/*var cbRuns = */blob.read_shift(2);
5761
	/*var ifntEmpty = */parseuint16(blob, 2);
5762
	var len = blob.read_shift(2);
5763
	blob.l += len;
5764
	//var fmla = parse_ObjFmla(blob, s + length - blob.l);
5765
5766
	for(var i = 1; i < blob.lens.length-1; ++i) {
5767
		if(blob.l-s != blob.lens[i]) throw new Error("TxO: bad continue record");
5768
		var hdr = blob[blob.l];
5769
		var t = parse_XLUnicodeStringNoCch(blob, blob.lens[i+1]-blob.lens[i]-1);
5770
		texts += t;
5771
		if(texts.length >= (hdr ? cchText : 2*cchText)) break;
5772
	}
5773
	if(texts.length !== cchText && texts.length !== cchText*2) {
5774
		throw new Error("cchText: " + cchText + " != " + texts.length);
5775
	}
5776
5777
	blob.l = s + length;
5778
	/* [MS-XLS] 2.5.272 TxORuns */
5779
//	var rgTxoRuns = [];
5780
//	for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
5781
//	var cchText2 = blob.read_shift(2);
5782
//	if(cchText2 !== cchText) throw new Error("TxOLastRun mismatch: " + cchText2 + " " + cchText);
5783
//	blob.l += 6;
5784
//	if(s + length != blob.l) throw new Error("TxO " + (s + length) + ", at " + blob.l);
5785
	return { t: texts };
5786
} catch(e) { blob.l = s + length; return { t: texts }; }
5787
}
5788
5789
/* [MS-XLS] 2.4.140 */
5790
function parse_HLink(blob, length) {
5791
	var ref = parse_Ref8U(blob, 8);
5792
	blob.l += 16; /* CLSID */
5793
	var hlink = parse_Hyperlink(blob, length-24);
5794
	return [ref, hlink];
5795
}
5796
function write_HLink(hl) {
5797
	var O = new_buf(24);
5798
	var ref = decode_cell(hl[0]);
5799
	O.write_shift(2, ref.r); O.write_shift(2, ref.r);
5800
	O.write_shift(2, ref.c); O.write_shift(2, ref.c);
5801
	var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
5802
	for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
5803
	return bconcat([O, write_Hyperlink(hl[1])]);
5804
}
5805
5806
5807
/* [MS-XLS] 2.4.141 */
5808
function parse_HLinkTooltip(blob, length) {
5809
	blob.read_shift(2);
5810
	var ref = parse_Ref8U(blob, 8);
5811
	var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
5812
	wzTooltip = wzTooltip.replace(chr0,"");
5813
	return [ref, wzTooltip];
5814
}
5815
function write_HLinkTooltip(hl) {
5816
	var TT = hl[1].Tooltip;
5817
	var O = new_buf(10 + 2 * (TT.length + 1));
5818
	O.write_shift(2, 0x0800);
5819
	var ref = decode_cell(hl[0]);
5820
	O.write_shift(2, ref.r); O.write_shift(2, ref.r);
5821
	O.write_shift(2, ref.c); O.write_shift(2, ref.c);
5822
	for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
5823
	O.write_shift(2, 0);
5824
	return O;
5825
}
5826
5827
/* [MS-XLS] 2.4.63 */
5828
function parse_Country(blob)/*:[string|number, string|number]*/ {
5829
	var o = [0,0], d;
5830
	d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
5831
	d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
5832
	return o;
5833
}
5834
function write_Country(o) {
5835
	if(!o) o = new_buf(4);
5836
	o.write_shift(2, 0x01);
5837
	o.write_shift(2, 0x01);
5838
	return o;
5839
}
5840
5841
/* [MS-XLS] 2.4.50 ClrtClient */
5842
function parse_ClrtClient(blob) {
5843
	var ccv = blob.read_shift(2);
5844
	var o = [];
5845
	while(ccv-->0) o.push(parse_LongRGB(blob, 8));
5846
	return o;
5847
}
5848
5849
/* [MS-XLS] 2.4.188 */
5850
function parse_Palette(blob) {
5851
	var ccv = blob.read_shift(2);
5852
	var o = [];
5853
	while(ccv-->0) o.push(parse_LongRGB(blob, 8));
5854
	return o;
5855
}
5856
5857
/* [MS-XLS] 2.4.354 */
5858
function parse_XFCRC(blob) {
5859
	blob.l += 2;
5860
	var o = {cxfs:0, crc:0};
5861
	o.cxfs = blob.read_shift(2);
5862
	o.crc = blob.read_shift(4);
5863
	return o;
5864
}
5865
5866
/* [MS-XLS] 2.4.53 TODO: parse flags */
5867
/* [MS-XLSB] 2.4.323 TODO: parse flags */
5868
function parse_ColInfo(blob, length, opts) {
5869
	if(!opts.cellStyles) return parsenoop(blob, length);
5870
	var w = opts && opts.biff >= 12 ? 4 : 2;
5871
	var colFirst = blob.read_shift(w);
5872
	var colLast = blob.read_shift(w);
5873
	var coldx = blob.read_shift(w);
5874
	var ixfe = blob.read_shift(w);
5875
	var flags = blob.read_shift(2);
5876
	if(w == 2) blob.l += 2;
5877
	return {s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags};
5878
}
5879
5880
/* [MS-XLS] 2.4.257 */
5881
function parse_Setup(blob, length) {
5882
	var o = {};
5883
	if(length < 32) return o;
5884
	blob.l += 16;
5885
	o.header = parse_Xnum(blob, 8);
5886
	o.footer = parse_Xnum(blob, 8);
5887
	blob.l += 2;
5888
	return o;
5889
}
5890
5891
/* [MS-XLS] 2.4.261 */
5892
function parse_ShtProps(blob, length, opts) {
5893
	var def = {area:false};
5894
	if(opts.biff != 5) { blob.l += length; return def; }
5895
	var d = blob.read_shift(1); blob.l += 3;
5896
	if((d & 0x10)) def.area = true;
5897
	return def;
5898
}
5899
5900
/* [MS-XLS] 2.4.241 */
5901
function write_RRTabId(n/*:number*/) {
5902
	var out = new_buf(2 * n);
5903
	for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
5904
	return out;
5905
}
5906
5907
var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
5908
var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
5909
var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
5910
5911
/* --- Specific to versions before BIFF8 --- */
5912
function parse_ImData(blob) {
5913
	var cf = blob.read_shift(2);
5914
	var env = blob.read_shift(2);
5915
	var lcb = blob.read_shift(4);
5916
	var o = {fmt:cf, env:env, len:lcb, data:blob.slice(blob.l,blob.l+lcb)};
5917
	blob.l += lcb;
5918
	return o;
5919
}
5920
5921
/* BIFF2_??? where ??? is the name from [XLS] */
5922
function parse_BIFF2STR(blob, length, opts) {
5923
	var cell = parse_XLSCell(blob, 6);
5924
	++blob.l;
5925
	var str = parse_XLUnicodeString2(blob, length-7, opts);
5926
	cell.t = 'str';
5927
	cell.val = str;
5928
	return cell;
5929
}
5930
5931
function parse_BIFF2NUM(blob/*::, length*/) {
5932
	var cell = parse_XLSCell(blob, 6);
5933
	++blob.l;
5934
	var num = parse_Xnum(blob, 8);
5935
	cell.t = 'n';
5936
	cell.val = num;
5937
	return cell;
5938
}
5939
function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/) {
5940
	var out = new_buf(15);
5941
	write_BIFF2Cell(out, r, c);
5942
	out.write_shift(8, val, 'f');
5943
	return out;
5944
}
5945
5946
function parse_BIFF2INT(blob) {
5947
	var cell = parse_XLSCell(blob, 6);
5948
	++blob.l;
5949
	var num = blob.read_shift(2);
5950
	cell.t = 'n';
5951
	cell.val = num;
5952
	return cell;
5953
}
5954
function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/) {
5955
	var out = new_buf(9);
5956
	write_BIFF2Cell(out, r, c);
5957
	out.write_shift(2, val);
5958
	return out;
5959
}
5960
5961
function parse_BIFF2STRING(blob) {
5962
	var cch = blob.read_shift(1);
5963
	if(cch === 0) { blob.l++; return ""; }
5964
	return blob.read_shift(cch, 'sbcs-cont');
5965
}
5966
5967
/* TODO: convert to BIFF8 font struct */
5968
function parse_BIFF2FONTXTRA(blob, length) {
5969
	blob.l += 6; // unknown
5970
	blob.l += 2; // font weight "bls"
5971
	blob.l += 1; // charset
5972
	blob.l += 3; // unknown
5973
	blob.l += 1; // font family
5974
	blob.l += length - 13;
5975
}
5976
5977
/* TODO: parse rich text runs */
5978
function parse_RString(blob, length, opts) {
5979
	var end = blob.l + length;
5980
	var cell = parse_XLSCell(blob, 6);
5981
	var cch = blob.read_shift(2);
5982
	var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
5983
	blob.l = end;
5984
	cell.t = 'str';
5985
	cell.val = str;
5986
	return cell;
5987
}
5988
/* from js-harb (C) 2014-present  SheetJS */
5989
var DBF = (function() {
5990
var dbf_codepage_map = {
5991
	/* Code Pages Supported by Visual FoxPro */
5992
	/*::[*/0x01/*::]*/:   437,           /*::[*/0x02/*::]*/:   850,
5993
	/*::[*/0x03/*::]*/:  1252,           /*::[*/0x04/*::]*/: 10000,
5994
	/*::[*/0x64/*::]*/:   852,           /*::[*/0x65/*::]*/:   866,
5995
	/*::[*/0x66/*::]*/:   865,           /*::[*/0x67/*::]*/:   861,
5996
	/*::[*/0x68/*::]*/:   895,           /*::[*/0x69/*::]*/:   620,
5997
	/*::[*/0x6A/*::]*/:   737,           /*::[*/0x6B/*::]*/:   857,
5998
	/*::[*/0x78/*::]*/:   950,           /*::[*/0x79/*::]*/:   949,
5999
	/*::[*/0x7A/*::]*/:   936,           /*::[*/0x7B/*::]*/:   932,
6000
	/*::[*/0x7C/*::]*/:   874,           /*::[*/0x7D/*::]*/:  1255,
6001
	/*::[*/0x7E/*::]*/:  1256,           /*::[*/0x96/*::]*/: 10007,
6002
	/*::[*/0x97/*::]*/: 10029,           /*::[*/0x98/*::]*/: 10006,
6003
	/*::[*/0xC8/*::]*/:  1250,           /*::[*/0xC9/*::]*/:  1251,
6004
	/*::[*/0xCA/*::]*/:  1254,           /*::[*/0xCB/*::]*/:  1253,
6005
6006
	/* shapefile DBF extension */
6007
	/*::[*/0x00/*::]*/: 20127,           /*::[*/0x08/*::]*/:   865,
6008
	/*::[*/0x09/*::]*/:   437,           /*::[*/0x0A/*::]*/:   850,
6009
	/*::[*/0x0B/*::]*/:   437,           /*::[*/0x0D/*::]*/:   437,
6010
	/*::[*/0x0E/*::]*/:   850,           /*::[*/0x0F/*::]*/:   437,
6011
	/*::[*/0x10/*::]*/:   850,           /*::[*/0x11/*::]*/:   437,
6012
	/*::[*/0x12/*::]*/:   850,           /*::[*/0x13/*::]*/:   932,
6013
	/*::[*/0x14/*::]*/:   850,           /*::[*/0x15/*::]*/:   437,
6014
	/*::[*/0x16/*::]*/:   850,           /*::[*/0x17/*::]*/:   865,
6015
	/*::[*/0x18/*::]*/:   437,           /*::[*/0x19/*::]*/:   437,
6016
	/*::[*/0x1A/*::]*/:   850,           /*::[*/0x1B/*::]*/:   437,
6017
	/*::[*/0x1C/*::]*/:   863,           /*::[*/0x1D/*::]*/:   850,
6018
	/*::[*/0x1F/*::]*/:   852,           /*::[*/0x22/*::]*/:   852,
6019
	/*::[*/0x23/*::]*/:   852,           /*::[*/0x24/*::]*/:   860,
6020
	/*::[*/0x25/*::]*/:   850,           /*::[*/0x26/*::]*/:   866,
6021
	/*::[*/0x37/*::]*/:   850,           /*::[*/0x40/*::]*/:   852,
6022
	/*::[*/0x4D/*::]*/:   936,           /*::[*/0x4E/*::]*/:   949,
6023
	/*::[*/0x4F/*::]*/:   950,           /*::[*/0x50/*::]*/:   874,
6024
	/*::[*/0x57/*::]*/:  1252,           /*::[*/0x58/*::]*/:  1252,
6025
	/*::[*/0x59/*::]*/:  1252,
6026
6027
	/*::[*/0xFF/*::]*/: 16969
6028
};
6029
6030
/* TODO: find an actual specification */
6031
function dbf_to_aoa(buf, opts)/*:AOA*/ {
6032
	var out/*:AOA*/ = [];
6033
	/* TODO: browser based */
6034
	var d/*:Block*/ = (new_raw_buf(1)/*:any*/);
6035
	switch(opts.type) {
6036
		case 'base64': d = s2a(Base64.decode(buf)); break;
6037
		case 'binary': d = s2a(buf); break;
6038
		case 'buffer':
6039
		case 'array': d = buf; break;
6040
	}
6041
	prep_blob(d, 0);
6042
	/* header */
6043
	var ft = d.read_shift(1);
6044
	var memo = false;
6045
	var vfp = false, l7 = false;
6046
	switch(ft) {
6047
		case 0x02: case 0x03: break;
6048
		case 0x30: vfp = true; memo = true; break;
6049
		case 0x31: vfp = true; break;
6050
		case 0x83: memo = true; break;
6051
		case 0x8B: memo = true; break;
6052
		case 0x8C: memo = true; l7 = true; break;
6053
		case 0xF5: memo = true; break;
6054
		default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
6055
	}
6056
	var /*filedate = new Date(),*/ nrow = 0, fpos = 0;
6057
	if(ft == 0x02) nrow = d.read_shift(2);
6058
	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3;
6059
	if(ft != 0x02) nrow = d.read_shift(4);
6060
	if(ft != 0x02) fpos = d.read_shift(2);
6061
	var rlen = d.read_shift(2);
6062
6063
	var /*flags = 0,*/ current_cp = 1252;
6064
	if(ft != 0x02) {
6065
	d.l+=16;
6066
	/*flags = */d.read_shift(1);
6067
	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
6068
6069
	/* codepage present in FoxPro */
6070
	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
6071
	d.l+=1;
6072
6073
	d.l+=2;
6074
	}
6075
	if(l7) d.l += 36;
6076
/*:: type DBFField = { name:string; len:number; type:string; } */
6077
	var fields/*:Array<DBFField>*/ = [], field/*:DBFField*/ = ({}/*:any*/);
6078
	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
6079
	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
6080
		field = ({}/*:any*/);
6081
		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
6082
		d.l += ww;
6083
		field.type = String.fromCharCode(d.read_shift(1));
6084
		if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
6085
		field.len = d.read_shift(1);
6086
		if(ft == 0x02) field.offset = d.read_shift(2);
6087
		field.dec = d.read_shift(1);
6088
		if(field.name.length) fields.push(field);
6089
		if(ft != 0x02) d.l += l7 ? 13 : 14;
6090
		switch(field.type) {
6091
			case 'B': // VFP Double
6092
				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6093
				break;
6094
			case 'G': // General
6095
			case 'P': // Picture
6096
				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6097
				break;
6098
			case 'C': // character
6099
			case 'D': // date
6100
			case 'F': // floating point
6101
			case 'I': // long
6102
			case 'L': // boolean
6103
			case 'M': // memo
6104
			case 'N': // number
6105
			case 'O': // double
6106
			case 'T': // datetime
6107
			case 'Y': // currency
6108
			case '0': // VFP _NullFlags
6109
			case '@': // timestamp
6110
			case '+': // autoincrement
6111
				break;
6112
			default: throw new Error('Unknown Field Type: ' + field.type);
6113
		}
6114
	}
6115
	if(d[d.l] !== 0x0D) d.l = fpos-1;
6116
	else if(ft == 0x02) d.l = 0x209;
6117
	if(ft != 0x02) {
6118
		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
6119
		d.l = fpos;
6120
	}
6121
	/* data */
6122
	var R = 0, C = 0;
6123
	out[0] = [];
6124
	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
6125
	while(nrow-- > 0) {
6126
		if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
6127
		++d.l;
6128
		out[++R] = []; C = 0;
6129
		for(C = 0; C != fields.length; ++C) {
6130
			var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
6131
			prep_blob(dd, 0);
6132
			var s = cptable.utils.decode(current_cp, dd);
6133
			switch(fields[C].type) {
6134
				case 'C':
6135
					out[R][C] = cptable.utils.decode(current_cp, dd);
6136
					out[R][C] = out[R][C].trim();
6137
					break;
6138
				case 'D':
6139
					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
6140
					else out[R][C] = s;
6141
					break;
6142
				case 'F': out[R][C] = parseFloat(s.trim()); break;
6143
				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
6144
				case 'L': switch(s.toUpperCase()) {
6145
					case 'Y': case 'T': out[R][C] = true; break;
6146
					case 'N': case 'F': out[R][C] = false; break;
6147
					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
6148
					default: throw new Error("DBF Unrecognized L:|" + s + "|");
6149
					} break;
6150
				case 'M': /* TODO: handle memo files */
6151
					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
6152
					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
6153
					break;
6154
				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
6155
				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
6156
				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
6157
				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
6158
				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
6159
				case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
6160
					/* falls through */
6161
				case 'G': case 'P': dd.l += fields[C].len; break;
6162
				case '0':
6163
					if(fields[C].name === '_NullFlags') break;
6164
					/* falls through */
6165
				default: throw new Error("DBF Unsupported data type " + fields[C].type);
6166
			}
6167
		}
6168
	}
6169
	if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16));
6170
	if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
6171
	return out;
6172
}
6173
6174
function dbf_to_sheet(buf, opts)/*:Worksheet*/ {
6175
	var o = opts || {};
6176
	if(!o.dateNF) o.dateNF = "yyyymmdd";
6177
	return aoa_to_sheet(dbf_to_aoa(buf, o), o);
6178
}
6179
6180
function dbf_to_workbook(buf, opts)/*:Workbook*/ {
6181
	try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
6182
	catch(e) { if(opts && opts.WTF) throw e; }
6183
	return ({SheetNames:[],Sheets:{}});
6184
}
6185
6186
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
6187
function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) {
6188
	var o = opts || {};
6189
	if(o.type == "string") throw new Error("Cannot write DBF to JS string");
6190
	var ba = buf_array();
6191
	var aoa/*:AOA*/ = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
6192
	var headers = aoa[0], data = aoa.slice(1);
6193
	var i = 0, j = 0, hcnt = 0, rlen = 1;
6194
	for(i = 0; i < headers.length; ++i) {
6195
		if(i == null) continue;
6196
		++hcnt;
6197
		if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
6198
		if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
6199
		if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
6200
			if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
6201
	}
6202
	var range = safe_decode_range(ws['!ref']);
6203
	var coltypes/*:Array<string>*/ = [];
6204
	for(i = 0; i <= range.e.c - range.s.c; ++i) {
6205
		var col/*:Array<any>*/ = [];
6206
		for(j=0; j < data.length; ++j) {
6207
			if(data[j][i] != null) col.push(data[j][i]);
6208
		}
6209
		if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
6210
		var guess = '', _guess = '';
6211
		for(j = 0; j < col.length; ++j) {
6212
			switch(typeof col[j]) {
6213
				/* TODO: check if L2 compat is desired */
6214
				case 'number': _guess = 'B'; break;
6215
				case 'string': _guess = 'C'; break;
6216
				case 'boolean': _guess = 'L'; break;
6217
				case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
6218
				default: _guess = 'C';
6219
			}
6220
			guess = guess && guess != _guess ? 'C' : _guess;
6221
			if(guess == 'C') break;
6222
		}
6223
		rlen += _RLEN[guess] || 0;
6224
		coltypes[i] = guess;
6225
	}
6226
6227
	var h = ba.next(32);
6228
	h.write_shift(4, 0x13021130);
6229
	h.write_shift(4, data.length);
6230
	h.write_shift(2, 296 + 32 * hcnt);
6231
	h.write_shift(2, rlen);
6232
	for(i=0; i < 4; ++i) h.write_shift(4, 0);
6233
	h.write_shift(4, 0x00000300); // TODO: CP
6234
6235
	for(i = 0, j = 0; i < headers.length; ++i) {
6236
		if(headers[i] == null) continue;
6237
		var hf = ba.next(32);
6238
		var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
6239
		hf.write_shift(1, _f, "sbcs");
6240
		hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
6241
		hf.write_shift(4, j);
6242
		hf.write_shift(1, _RLEN[coltypes[i]] || 0);
6243
		hf.write_shift(1, 0);
6244
		hf.write_shift(1, 0x02);
6245
		hf.write_shift(4, 0);
6246
		hf.write_shift(1, 0);
6247
		hf.write_shift(4, 0);
6248
		hf.write_shift(4, 0);
6249
		j += _RLEN[coltypes[i]] || 0;
6250
	}
6251
6252
	var hb = ba.next(264);
6253
	hb.write_shift(4, 0x0000000D);
6254
	for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
6255
	for(i=0; i < data.length; ++i) {
6256
		var rout = ba.next(rlen);
6257
		rout.write_shift(1, 0);
6258
		for(j=0; j<headers.length; ++j) {
6259
			if(headers[j] == null) continue;
6260
			switch(coltypes[j]) {
6261
				case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
6262
				case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
6263
				case 'D':
6264
					if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
6265
					else {
6266
						rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
6267
						rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
6268
						rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
6269
					} break;
6270
				case 'C':
6271
					var _s = String(data[i][j]||"");
6272
					rout.write_shift(1, _s, "sbcs");
6273
					for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
6274
			}
6275
		}
6276
		// data
6277
	}
6278
	ba.next(1).write_shift(1, 0x1A);
6279
	return ba.end();
6280
}
6281
	return {
6282
		to_workbook: dbf_to_workbook,
6283
		to_sheet: dbf_to_sheet,
6284
		from_sheet: sheet_to_dbf
6285
	};
6286
})();
6287
6288
var SYLK = (function() {
6289
	/* TODO: find an actual specification */
6290
	function sylk_to_aoa(d/*:RawData*/, opts)/*:[AOA, Worksheet]*/ {
6291
		switch(opts.type) {
6292
			case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
6293
			case 'binary': return sylk_to_aoa_str(d, opts);
6294
			case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts);
6295
			case 'array': return sylk_to_aoa_str(cc2str(d), opts);
6296
		}
6297
		throw new Error("Unrecognized type " + opts.type);
6298
	}
6299
	function sylk_to_aoa_str(str/*:string*/, opts)/*:[AOA, Worksheet]*/ {
6300
		var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr/*:AOA*/ = [];
6301
		var formats/*:Array<string>*/ = [];
6302
		var next_cell_format/*:string|null*/ = null;
6303
		var sht = {}, rowinfo/*:Array<RowInfo>*/ = [], colinfo/*:Array<ColInfo>*/ = [], cw/*:Array<string>*/ = [];
6304
		var Mval = 0, j;
6305
		for (; ri !== records.length; ++ri) {
6306
			Mval = 0;
6307
			var rstr=records[ri].trim();
6308
			var record=rstr.replace(/;;/g, "\u0001").split(";").map(function(x) { return x.replace(/\u0001/g, ";"); });
6309
			var RT=record[0], val;
6310
			if(rstr.length > 0) switch(RT) {
6311
			case 'ID': break; /* header */
6312
			case 'E': break; /* EOF */
6313
			case 'B': break; /* dimensions */
6314
			case 'O': break; /* options? */
6315
			case 'P':
6316
				if(record[1].charAt(0) == 'P')
6317
					formats.push(rstr.slice(3).replace(/;;/g, ";"));
6318
				break;
6319
			case 'C':
6320
			var C_seen_K = false, C_seen_X = false;
6321
			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
6322
				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
6323
				case 'Y':
6324
					R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
6325
					for(j = arr.length; j <= R; ++j) arr[j] = [];
6326
					break;
6327
				case 'K':
6328
					val = record[rj].slice(1);
6329
					if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
6330
					else if(val === 'TRUE') val = true;
6331
					else if(val === 'FALSE') val = false;
6332
					else if(!isNaN(fuzzynum(val))) {
6333
						val = fuzzynum(val);
6334
						if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
6335
					} else if(!isNaN(fuzzydate(val).getDate())) {
6336
						val = parseDate(val);
6337
					}
6338
					if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
6339
					C_seen_K = true;
6340
					break;
6341
				case 'E':
6342
					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
6343
					arr[R][C] = [arr[R][C], formula];
6344
					break;
6345
				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
6346
			}
6347
			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; }
6348
			break;
6349
			case 'F':
6350
			var F_seen = 0;
6351
			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
6352
				case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
6353
				case 'Y':
6354
					R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
6355
					for(j = arr.length; j <= R; ++j) arr[j] = [];
6356
					break;
6357
				case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
6358
				case 'F': break; /* ??? */
6359
				case 'G': break; /* hide grid */
6360
				case 'P':
6361
					next_cell_format = formats[parseInt(record[rj].slice(1))];
6362
					break;
6363
				case 'S': break; /* cell style */
6364
				case 'D': break; /* column */
6365
				case 'N': break; /* font */
6366
				case 'W':
6367
					cw = record[rj].slice(1).split(" ");
6368
					for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
6369
						Mval = parseInt(cw[2], 10);
6370
						colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
6371
					} break;
6372
				case 'C': /* default column format */
6373
					C = parseInt(record[rj].slice(1))-1;
6374
					if(!colinfo[C]) colinfo[C] = {};
6375
					break;
6376
				case 'R': /* row properties */
6377
					R = parseInt(record[rj].slice(1))-1;
6378
					if(!rowinfo[R]) rowinfo[R] = {};
6379
					if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
6380
					else if(Mval === 0) rowinfo[R].hidden = true;
6381
					break;
6382
				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
6383
			}
6384
			if(F_seen < 1) next_cell_format = null; break;
6385
			default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
6386
			}
6387
		}
6388
		if(rowinfo.length > 0) sht['!rows'] = rowinfo;
6389
		if(colinfo.length > 0) sht['!cols'] = colinfo;
6390
		if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
6391
		return [arr, sht];
6392
	}
6393
6394
	function sylk_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
6395
		var aoasht = sylk_to_aoa(d, opts);
6396
		var aoa = aoasht[0], ws = aoasht[1];
6397
		var o = aoa_to_sheet(aoa, opts);
6398
		keys(ws).forEach(function(k) { o[k] = ws[k]; });
6399
		return o;
6400
	}
6401
6402
	function sylk_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
6403
6404
	function write_ws_cell_sylk(cell/*:Cell*/, ws/*:Worksheet*/, R/*:number*/, C/*:number*//*::, opts*/)/*:string*/ {
6405
		var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
6406
		switch(cell.t) {
6407
			case 'n':
6408
				o += (cell.v||0);
6409
				if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
6410
			case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
6411
			case 'e': o += cell.w || cell.v; break;
6412
			case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
6413
			case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
6414
		}
6415
		return o;
6416
	}
6417
6418
	function write_ws_cols_sylk(out, cols) {
6419
		cols.forEach(function(col, i) {
6420
			var rec = "F;W" + (i+1) + " " + (i+1) + " ";
6421
			if(col.hidden) rec += "0";
6422
			else {
6423
				if(typeof col.width == 'number') col.wpx = width2px(col.width);
6424
				if(typeof col.wpx == 'number') col.wch = px2char(col.wpx);
6425
				if(typeof col.wch == 'number') rec += Math.round(col.wch);
6426
			}
6427
			if(rec.charAt(rec.length - 1) != " ") out.push(rec);
6428
		});
6429
	}
6430
6431
	function write_ws_rows_sylk(out/*:Array<string>*/, rows/*:Array<RowInfo>*/) {
6432
		rows.forEach(function(row, i) {
6433
			var rec = "F;";
6434
			if(row.hidden) rec += "M0;";
6435
			else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
6436
			else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
6437
			if(rec.length > 2) out.push(rec + "R" + (i+1));
6438
		});
6439
	}
6440
6441
	function sheet_to_sylk(ws/*:Worksheet*/, opts/*:?any*/)/*:string*/ {
6442
		var preamble/*:Array<string>*/ = ["ID;PWXL;N;E"], o/*:Array<string>*/ = [];
6443
		var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
6444
		var dense = Array.isArray(ws);
6445
		var RS = "\r\n";
6446
6447
		preamble.push("P;PGeneral");
6448
		preamble.push("F;P0;DG0G8;M255");
6449
		if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
6450
		if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
6451
6452
		preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
6453
		for(var R = r.s.r; R <= r.e.r; ++R) {
6454
			for(var C = r.s.c; C <= r.e.c; ++C) {
6455
				var coord = encode_cell({r:R,c:C});
6456
				cell = dense ? (ws[R]||[])[C]: ws[coord];
6457
				if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
6458
				o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
6459
			}
6460
		}
6461
		return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
6462
	}
6463
6464
	return {
6465
		to_workbook: sylk_to_workbook,
6466
		to_sheet: sylk_to_sheet,
6467
		from_sheet: sheet_to_sylk
6468
	};
6469
})();
6470
6471
var DIF = (function() {
6472
	function dif_to_aoa(d/*:RawData*/, opts)/*:AOA*/ {
6473
		switch(opts.type) {
6474
			case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
6475
			case 'binary': return dif_to_aoa_str(d, opts);
6476
			case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts);
6477
			case 'array': return dif_to_aoa_str(cc2str(d), opts);
6478
		}
6479
		throw new Error("Unrecognized type " + opts.type);
6480
	}
6481
	function dif_to_aoa_str(str/*:string*/, opts)/*:AOA*/ {
6482
		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr/*:AOA*/ = [];
6483
		for (; ri !== records.length; ++ri) {
6484
			if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
6485
			if (R < 0) continue;
6486
			var metadata = records[ri].trim().split(",");
6487
			var type = metadata[0], value = metadata[1];
6488
			++ri;
6489
			var data = records[ri].trim();
6490
			switch (+type) {
6491
				case -1:
6492
					if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
6493
					else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
6494
					break;
6495
				case 0:
6496
					if(data === 'TRUE') arr[R][C] = true;
6497
					else if(data === 'FALSE') arr[R][C] = false;
6498
					else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
6499
					else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
6500
					else arr[R][C] = value;
6501
					++C; break;
6502
				case 1:
6503
					data = data.slice(1,data.length-1);
6504
					arr[R][C++] = data !== '' ? data : null;
6505
					break;
6506
			}
6507
			if (data === 'EOD') break;
6508
		}
6509
		if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
6510
		return arr;
6511
	}
6512
6513
	function dif_to_sheet(str/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
6514
	function dif_to_workbook(str/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
6515
6516
	var sheet_to_dif = (function() {
6517
		var push_field = function pf(o/*:Array<string>*/, topic/*:string*/, v/*:number*/, n/*:number*/, s/*:string*/) {
6518
			o.push(topic);
6519
			o.push(v + "," + n);
6520
			o.push('"' + s.replace(/"/g,'""') + '"');
6521
		};
6522
		var push_value = function po(o/*:Array<string>*/, type/*:number*/, v/*:any*/, s/*:string*/) {
6523
			o.push(type + "," + v);
6524
			o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
6525
		};
6526
		return function sheet_to_dif(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
6527
			var o/*:Array<string>*/ = [];
6528
			var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
6529
			var dense = Array.isArray(ws);
6530
			push_field(o, "TABLE", 0, 1, "sheetjs");
6531
			push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
6532
			push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
6533
			push_field(o, "DATA", 0, 0,"");
6534
			for(var R = r.s.r; R <= r.e.r; ++R) {
6535
				push_value(o, -1, 0, "BOT");
6536
				for(var C = r.s.c; C <= r.e.c; ++C) {
6537
					var coord = encode_cell({r:R,c:C});
6538
					cell = dense ? (ws[R]||[])[C] : ws[coord];
6539
					if(!cell) { push_value(o, 1, 0, ""); continue;}
6540
					switch(cell.t) {
6541
						case 'n':
6542
							var val = DIF_XL ? cell.w : cell.v;
6543
							if(!val && cell.v != null) val = cell.v;
6544
							if(val == null) {
6545
								if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
6546
								else push_value(o, 1, 0, "");
6547
							}
6548
							else push_value(o, 0, val, "V");
6549
							break;
6550
						case 'b':
6551
							push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
6552
							break;
6553
						case 's':
6554
							push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
6555
							break;
6556
						case 'd':
6557
							if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
6558
							if(DIF_XL) push_value(o, 0, cell.w, "V");
6559
							else push_value(o, 1, 0, cell.w);
6560
							break;
6561
						default: push_value(o, 1, 0, "");
6562
					}
6563
				}
6564
			}
6565
			push_value(o, -1, 0, "EOD");
6566
			var RS = "\r\n";
6567
			var oo = o.join(RS);
6568
			//while((oo.length & 0x7F) != 0) oo += "\0";
6569
			return oo;
6570
		};
6571
	})();
6572
	return {
6573
		to_workbook: dif_to_workbook,
6574
		to_sheet: dif_to_sheet,
6575
		from_sheet: sheet_to_dif
6576
	};
6577
})();
6578
6579
var ETH = (function() {
6580
	function decode(s/*:string*/)/*:string*/ { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
6581
	function encode(s/*:string*/)/*:string*/ { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
6582
6583
	function eth_to_aoa(str/*:string*/, opts)/*:AOA*/ {
6584
		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr/*:AOA*/ = [];
6585
		for (; ri !== records.length; ++ri) {
6586
			var record = records[ri].trim().split(":");
6587
			if(record[0] !== 'cell') continue;
6588
			var addr = decode_cell(record[1]);
6589
			if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
6590
			R = addr.r; C = addr.c;
6591
			switch(record[2]) {
6592
				case 't': arr[R][C] = decode(record[3]); break;
6593
				case 'v': arr[R][C] = +record[3]; break;
6594
				case 'vtf': var _f = record[record.length - 1];
6595
					/* falls through */
6596
				case 'vtc':
6597
					switch(record[3]) {
6598
						case 'nl': arr[R][C] = +record[4] ? true : false; break;
6599
						default: arr[R][C] = +record[4]; break;
6600
					}
6601
					if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
6602
			}
6603
		}
6604
		if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
6605
		return arr;
6606
	}
6607
6608
	function eth_to_sheet(d/*:string*/, opts)/*:Worksheet*/ { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
6609
	function eth_to_workbook(d/*:string*/, opts)/*:Workbook*/ { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
6610
6611
	var header = [
6612
		"socialcalc:version:1.5",
6613
		"MIME-Version: 1.0",
6614
		"Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
6615
	].join("\n");
6616
6617
	var sep = [
6618
		"--SocialCalcSpreadsheetControlSave",
6619
		"Content-type: text/plain; charset=UTF-8"
6620
	].join("\n") + "\n";
6621
6622
	/* TODO: the other parts */
6623
	var meta = [
6624
		"# SocialCalc Spreadsheet Control Save",
6625
		"part:sheet"
6626
	].join("\n");
6627
6628
	var end = "--SocialCalcSpreadsheetControlSave--";
6629
6630
	function sheet_to_eth_data(ws/*:Worksheet*/)/*:string*/ {
6631
		if(!ws || !ws['!ref']) return "";
6632
		var o/*:Array<string>*/ = [], oo/*:Array<string>*/ = [], cell, coord = "";
6633
		var r = decode_range(ws['!ref']);
6634
		var dense = Array.isArray(ws);
6635
		for(var R = r.s.r; R <= r.e.r; ++R) {
6636
			for(var C = r.s.c; C <= r.e.c; ++C) {
6637
				coord = encode_cell({r:R,c:C});
6638
				cell = dense ? (ws[R]||[])[C] : ws[coord];
6639
				if(!cell || cell.v == null || cell.t === 'z') continue;
6640
				oo = ["cell", coord, 't'];
6641
				switch(cell.t) {
6642
					case 's': case 'str': oo.push(encode(cell.v)); break;
6643
					case 'n':
6644
						if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
6645
						else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
6646
						break;
6647
					case 'b':
6648
						oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
6649
						oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
6650
						break;
6651
					case 'd':
6652
						var t = datenum(parseDate(cell.v));
6653
						oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
6654
						oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
6655
						break;
6656
					case 'e': continue;
6657
				}
6658
				o.push(oo.join(":"));
6659
			}
6660
		}
6661
		o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
6662
		o.push("valueformat:1:text-wiki");
6663
		//o.push("copiedfrom:" + ws['!ref']); // clipboard only
6664
		return o.join("\n");
6665
	}
6666
6667
	function sheet_to_eth(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
6668
		return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
6669
		// return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
6670
	}
6671
6672
	return {
6673
		to_workbook: eth_to_workbook,
6674
		to_sheet: eth_to_sheet,
6675
		from_sheet: sheet_to_eth
6676
	};
6677
})();
6678
6679
var PRN = (function() {
6680
	function set_text_arr(data/*:string*/, arr/*:AOA*/, R/*:number*/, C/*:number*/, o/*:any*/) {
6681
		if(o.raw) arr[R][C] = data;
6682
		else if(data === 'TRUE') arr[R][C] = true;
6683
		else if(data === 'FALSE') arr[R][C] = false;
6684
		else if(data === ""){/* empty */}
6685
		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
6686
		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
6687
		else arr[R][C] = data;
6688
	}
6689
6690
	function prn_to_aoa_str(f/*:string*/, opts)/*:AOA*/ {
6691
		var o = opts || {};
6692
		var arr/*:AOA*/ = ([]/*:any*/);
6693
		if(!f || f.length === 0) return arr;
6694
		var lines = f.split(/[\r\n]/);
6695
		var L = lines.length - 1;
6696
		while(L >= 0 && lines[L].length === 0) --L;
6697
		var start = 10, idx = 0;
6698
		var R = 0;
6699
		for(; R <= L; ++R) {
6700
			idx = lines[R].indexOf(" ");
6701
			if(idx == -1) idx = lines[R].length; else idx++;
6702
			start = Math.max(start, idx);
6703
		}
6704
		for(R = 0; R <= L; ++R) {
6705
			arr[R] = [];
6706
			/* TODO: confirm that widths are always 10 */
6707
			var C = 0;
6708
			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
6709
			for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
6710
				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
6711
		}
6712
		if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
6713
		return arr;
6714
	}
6715
6716
	// List of accepted CSV separators
6717
	var guess_seps = {
6718
		/*::[*/0x2C/*::]*/: ',',
6719
		/*::[*/0x09/*::]*/: "\t",
6720
		/*::[*/0x3B/*::]*/: ';'
6721
	};
6722
6723
	// CSV separator weights to be used in case of equal numbers
6724
	var guess_sep_weights = {
6725
		/*::[*/0x2C/*::]*/: 3,
6726
		/*::[*/0x09/*::]*/: 2,
6727
		/*::[*/0x3B/*::]*/: 1
6728
	};
6729
6730
	function guess_sep(str) {
6731
		var cnt = {}, instr = false, end = 0, cc = 0;
6732
		for(;end < str.length;++end) {
6733
			if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
6734
			else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
6735
		}
6736
6737
		cc = [];
6738
		for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
6739
			cc.push([ cnt[end], end ]);
6740
		}
6741
6742
		if ( !cc.length ) {
6743
			cnt = guess_sep_weights;
6744
			for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
6745
				cc.push([ cnt[end], end ]);
6746
			}
6747
		}
6748
6749
		cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
6750
6751
		return guess_seps[cc.pop()[1]];
6752
	}
6753
6754
	function dsv_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
6755
		var o = opts || {};
6756
		var sep = "";
6757
		if(DENSE != null && o.dense == null) o.dense = DENSE;
6758
		var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
6759
		var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
6760
6761
		if(str.slice(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.slice(6); }
6762
		else sep = guess_sep(str.slice(0,1024));
6763
		var R = 0, C = 0, v = 0;
6764
		var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
6765
		str = str.replace(/\r\n/mg, "\n");
6766
		var _re/*:?RegExp*/ = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
6767
		function finish_cell() {
6768
			var s = str.slice(start, end);
6769
			var cell = ({}/*:any*/);
6770
			if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
6771
			if(s.length === 0) cell.t = 'z';
6772
			else if(o.raw) { cell.t = 's'; cell.v = s; }
6773
			else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
6774
			else if(s.charCodeAt(0) == 0x3D) {
6775
				if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
6776
				else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
6777
				else { cell.t = 's'; cell.v = s; } }
6778
			else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
6779
			else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
6780
			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
6781
			else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
6782
				cell.z = o.dateNF || SSF._table[14];
6783
				var k = 0;
6784
				if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
6785
				if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
6786
				else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
6787
				if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
6788
				if(!o.cellNF) delete cell.z;
6789
			} else {
6790
				cell.t = 's';
6791
				cell.v = s;
6792
			}
6793
			if(cell.t == 'z'){}
6794
			else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
6795
			else ws[encode_cell({c:C,r:R})] = cell;
6796
			start = end+1;
6797
			if(range.e.c < C) range.e.c = C;
6798
			if(range.e.r < R) range.e.r = R;
6799
			if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
6800
		}
6801
		outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
6802
			case 0x22: instr = !instr; break;
6803
			case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
6804
			default: break;
6805
		}
6806
		if(end - start > 0) finish_cell();
6807
6808
		ws['!ref'] = encode_range(range);
6809
		return ws;
6810
	}
6811
6812
	function prn_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
6813
		if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
6814
		if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
6815
		return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
6816
	}
6817
6818
	function prn_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
6819
		var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
6820
		switch(opts.type) {
6821
			case 'base64': str = Base64.decode(d); break;
6822
			case 'binary': str = d; break;
6823
			case 'buffer':
6824
				if(opts.codepage == 65001) str = d.toString('utf8');
6825
				else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
6826
				else str = d.toString('binary');
6827
				break;
6828
			case 'array': str = cc2str(d); break;
6829
			case 'string': str = d; break;
6830
			default: throw new Error("Unrecognized type " + opts.type);
6831
		}
6832
		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
6833
		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str));
6834
		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
6835
		return prn_to_sheet_str(str, opts);
6836
	}
6837
6838
	function prn_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
6839
6840
	function sheet_to_prn(ws/*:Worksheet*//*::, opts:?any*/)/*:string*/ {
6841
		var o/*:Array<string>*/ = [];
6842
		var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
6843
		var dense = Array.isArray(ws);
6844
		for(var R = r.s.r; R <= r.e.r; ++R) {
6845
			var oo/*:Array<string>*/ = [];
6846
			for(var C = r.s.c; C <= r.e.c; ++C) {
6847
				var coord = encode_cell({r:R,c:C});
6848
				cell = dense ? (ws[R]||[])[C] : ws[coord];
6849
				if(!cell || cell.v == null) { oo.push("          "); continue; }
6850
				var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
6851
				while(w.length < 10) w += " ";
6852
				oo.push(w + (C === 0 ? " " : ""));
6853
			}
6854
			o.push(oo.join(""));
6855
		}
6856
		return o.join("\n");
6857
	}
6858
6859
	return {
6860
		to_workbook: prn_to_workbook,
6861
		to_sheet: prn_to_sheet,
6862
		from_sheet: sheet_to_prn
6863
	};
6864
})();
6865
6866
/* Excel defaults to SYLK but warns if data is not valid */
6867
function read_wb_ID(d, opts) {
6868
	var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
6869
	try {
6870
		var out = SYLK.to_workbook(d, o);
6871
		o.WTF = OLD_WTF;
6872
		return out;
6873
	} catch(e) {
6874
		o.WTF = OLD_WTF;
6875
		if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
6876
		return PRN.to_workbook(d, opts);
6877
	}
6878
}
6879
var WK_ = (function() {
6880
	function lotushopper(data, cb/*:RecordHopperCB*/, opts/*:any*/) {
6881
		if(!data) return;
6882
		prep_blob(data, data.l || 0);
6883
		var Enum = opts.Enum || WK1Enum;
6884
		while(data.l < data.length) {
6885
			var RT = data.read_shift(2);
6886
			var R = Enum[RT] || Enum[0xFF];
6887
			var length = data.read_shift(2);
6888
			var tgt = data.l + length;
6889
			var d = (R.f||parsenoop)(data, length, opts);
6890
			data.l = tgt;
6891
			if(cb(d, R.n, RT)) return;
6892
		}
6893
	}
6894
6895
	function lotus_to_workbook(d/*:RawData*/, opts) {
6896
		switch(opts.type) {
6897
			case 'base64': return lotus_to_workbook_buf(s2a(Base64.decode(d)), opts);
6898
			case 'binary': return lotus_to_workbook_buf(s2a(d), opts);
6899
			case 'buffer':
6900
			case 'array': return lotus_to_workbook_buf(d, opts);
6901
		}
6902
		throw "Unsupported type " + opts.type;
6903
	}
6904
6905
	function lotus_to_workbook_buf(d, opts)/*:Workbook*/ {
6906
		if(!d) return d;
6907
		var o = opts || {};
6908
		if(DENSE != null && o.dense == null) o.dense = DENSE;
6909
		var s/*:Worksheet*/ = ((o.dense ? [] : {})/*:any*/), n = "Sheet1", sidx = 0;
6910
		var sheets = {}, snames = [n];
6911
6912
		var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
6913
		var sheetRows = o.sheetRows || 0;
6914
6915
		if(d[2] == 0x02) o.Enum = WK1Enum;
6916
		else if(d[2] == 0x1a) o.Enum = WK3Enum;
6917
		else if(d[2] == 0x0e) { o.Enum = WK3Enum; o.qpro = true; d.l = 0; }
6918
		else throw new Error("Unrecognized LOTUS BOF " + d[2]);
6919
		lotushopper(d, function(val, Rn, RT) {
6920
			if(d[2] == 0x02) switch(RT) {
6921
				case 0x00:
6922
					o.vers = val;
6923
					if(val >= 0x1000) o.qpro = true;
6924
					break;
6925
				case 0x06: refguess = val; break; /* RANGE */
6926
				case 0x0F: /* LABEL */
6927
					if(!o.qpro) val[1].v = val[1].v.slice(1);
6928
					/* falls through */
6929
				case 0x0D: /* INTEGER */
6930
				case 0x0E: /* NUMBER */
6931
				case 0x10: /* FORMULA */
6932
				case 0x33: /* STRING */
6933
					/* TODO: actual translation of the format code */
6934
					if(RT == 0x0E && (val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
6935
						val[1].z = o.dateNF || SSF._table[14];
6936
						if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
6937
					}
6938
					if(o.dense) {
6939
						if(!s[val[0].r]) s[val[0].r] = [];
6940
						s[val[0].r][val[0].c] = val[1];
6941
					} else s[encode_cell(val[0])] = val[1];
6942
					break;
6943
			} else switch(RT) {
6944
				case 0x16: /* LABEL16 */
6945
					val[1].v = val[1].v.slice(1);
6946
					/* falls through */
6947
				case 0x17: /* NUMBER17 */
6948
				case 0x18: /* NUMBER18 */
6949
				case 0x19: /* FORMULA19 */
6950
				case 0x25: /* NUMBER25 */
6951
				case 0x27: /* NUMBER27 */
6952
				case 0x28: /* FORMULA28 */
6953
					if(val[3] > sidx) {
6954
						s["!ref"] = encode_range(refguess);
6955
						sheets[n] = s;
6956
						s = (o.dense ? [] : {});
6957
						refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
6958
						sidx = val[3]; n = "Sheet" + (sidx + 1);
6959
						snames.push(n);
6960
					}
6961
					if(sheetRows > 0 && val[0].r >= sheetRows) break;
6962
					if(o.dense) {
6963
						if(!s[val[0].r]) s[val[0].r] = [];
6964
						s[val[0].r][val[0].c] = val[1];
6965
					} else s[encode_cell(val[0])] = val[1];
6966
					if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
6967
					if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
6968
					break;
6969
				default: break;
6970
			}
6971
		}, o);
6972
6973
		s["!ref"] = encode_range(refguess);
6974
		sheets[n] = s;
6975
		return { SheetNames: snames, Sheets:sheets };
6976
	}
6977
6978
	function parse_RANGE(blob) {
6979
		var o = {s:{c:0,r:0},e:{c:0,r:0}};
6980
		o.s.c = blob.read_shift(2);
6981
		o.s.r = blob.read_shift(2);
6982
		o.e.c = blob.read_shift(2);
6983
		o.e.r = blob.read_shift(2);
6984
		if(o.s.c == 0xFFFF) o.s.c = o.e.c = o.s.r = o.e.r = 0;
6985
		return o;
6986
	}
6987
6988
	function parse_cell(blob, length, opts) {
6989
		var o = [{c:0,r:0}, {t:'n',v:0}, 0];
6990
		if(opts.qpro && opts.vers != 0x5120) {
6991
			o[0].c = blob.read_shift(1);
6992
			blob.l++;
6993
			o[0].r = blob.read_shift(2);
6994
			blob.l+=2;
6995
		} else {
6996
			o[2] = blob.read_shift(1);
6997
			o[0].c = blob.read_shift(2); o[0].r = blob.read_shift(2);
6998
		}
6999
		return o;
7000
	}
7001
7002
	function parse_LABEL(blob, length, opts) {
7003
		var tgt = blob.l + length;
7004
		var o = parse_cell(blob, length, opts);
7005
		o[1].t = 's';
7006
		if(opts.vers == 0x5120) {
7007
			blob.l++;
7008
			var len = blob.read_shift(1);
7009
			o[1].v = blob.read_shift(len, 'utf8');
7010
			return o;
7011
		}
7012
		if(opts.qpro) blob.l++;
7013
		o[1].v = blob.read_shift(tgt - blob.l, 'cstr');
7014
		return o;
7015
	}
7016
7017
	function parse_INTEGER(blob, length, opts) {
7018
		var o = parse_cell(blob, length, opts);
7019
		o[1].v = blob.read_shift(2, 'i');
7020
		return o;
7021
	}
7022
7023
	function parse_NUMBER(blob, length, opts) {
7024
		var o = parse_cell(blob, length, opts);
7025
		o[1].v = blob.read_shift(8, 'f');
7026
		return o;
7027
	}
7028
7029
	function parse_FORMULA(blob, length, opts) {
7030
		var tgt = blob.l + length;
7031
		var o = parse_cell(blob, length, opts);
7032
		/* TODO: formula */
7033
		o[1].v = blob.read_shift(8, 'f');
7034
		if(opts.qpro) blob.l = tgt;
7035
		else {
7036
			var flen = blob.read_shift(2);
7037
			blob.l += flen;
7038
		}
7039
		return o;
7040
	}
7041
7042
	function parse_cell_3(blob/*::, length*/) {
7043
		var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7044
		o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
7045
		return o;
7046
	}
7047
7048
	function parse_LABEL_16(blob, length) {
7049
		var o = parse_cell_3(blob, length);
7050
		o[1].t = 's';
7051
		o[1].v = blob.read_shift(length - 4, 'cstr');
7052
		return o;
7053
	}
7054
7055
	function parse_NUMBER_18(blob, length) {
7056
		var o = parse_cell_3(blob, length);
7057
		o[1].v = blob.read_shift(2);
7058
		var v = o[1].v >> 1;
7059
		/* TODO: figure out all of the corner cases */
7060
		if(o[1].v & 0x1) {
7061
			switch(v & 0x07) {
7062
				case 1: v = (v >> 3) * 500; break;
7063
				case 2: v = (v >> 3) / 20; break;
7064
				case 4: v = (v >> 3) / 2000; break;
7065
				case 6: v = (v >> 3) / 16; break;
7066
				case 7: v = (v >> 3) / 64; break;
7067
				default: throw "unknown NUMBER_18 encoding " + (v & 0x07);
7068
			}
7069
		}
7070
		o[1].v = v;
7071
		return o;
7072
	}
7073
7074
	function parse_NUMBER_17(blob, length) {
7075
		var o = parse_cell_3(blob, length);
7076
		var v1 = blob.read_shift(4);
7077
		var v2 = blob.read_shift(4);
7078
		var e = blob.read_shift(2);
7079
		if(e == 0xFFFF) { o[1].v = 0; return o; }
7080
		var s = e & 0x8000; e = (e&0x7FFF) - 16446;
7081
		o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
7082
		return o;
7083
	}
7084
7085
	function parse_FORMULA_19(blob, length) {
7086
		var o = parse_NUMBER_17(blob, 14);
7087
		blob.l += length - 14; /* TODO: formula */
7088
		return o;
7089
	}
7090
7091
	function parse_NUMBER_25(blob, length) {
7092
		var o = parse_cell_3(blob, length);
7093
		var v1 = blob.read_shift(4);
7094
		o[1].v = v1 >> 6;
7095
		return o;
7096
	}
7097
7098
	function parse_NUMBER_27(blob, length) {
7099
		var o = parse_cell_3(blob, length);
7100
		var v1 = blob.read_shift(8,'f');
7101
		o[1].v = v1;
7102
		return o;
7103
	}
7104
7105
	function parse_FORMULA_28(blob, length) {
7106
		var o = parse_NUMBER_27(blob, 14);
7107
		blob.l += length - 10; /* TODO: formula */
7108
		return o;
7109
	}
7110
7111
	var WK1Enum = {
7112
		/*::[*/0x0000/*::]*/: { n:"BOF", f:parseuint16 },
7113
		/*::[*/0x0001/*::]*/: { n:"EOF" },
7114
		/*::[*/0x0002/*::]*/: { n:"CALCMODE" },
7115
		/*::[*/0x0003/*::]*/: { n:"CALCORDER" },
7116
		/*::[*/0x0004/*::]*/: { n:"SPLIT" },
7117
		/*::[*/0x0005/*::]*/: { n:"SYNC" },
7118
		/*::[*/0x0006/*::]*/: { n:"RANGE", f:parse_RANGE },
7119
		/*::[*/0x0007/*::]*/: { n:"WINDOW1" },
7120
		/*::[*/0x0008/*::]*/: { n:"COLW1" },
7121
		/*::[*/0x0009/*::]*/: { n:"WINTWO" },
7122
		/*::[*/0x000A/*::]*/: { n:"COLW2" },
7123
		/*::[*/0x000B/*::]*/: { n:"NAME" },
7124
		/*::[*/0x000C/*::]*/: { n:"BLANK" },
7125
		/*::[*/0x000D/*::]*/: { n:"INTEGER", f:parse_INTEGER },
7126
		/*::[*/0x000E/*::]*/: { n:"NUMBER", f:parse_NUMBER },
7127
		/*::[*/0x000F/*::]*/: { n:"LABEL", f:parse_LABEL },
7128
		/*::[*/0x0010/*::]*/: { n:"FORMULA", f:parse_FORMULA },
7129
		/*::[*/0x0018/*::]*/: { n:"TABLE" },
7130
		/*::[*/0x0019/*::]*/: { n:"ORANGE" },
7131
		/*::[*/0x001A/*::]*/: { n:"PRANGE" },
7132
		/*::[*/0x001B/*::]*/: { n:"SRANGE" },
7133
		/*::[*/0x001C/*::]*/: { n:"FRANGE" },
7134
		/*::[*/0x001D/*::]*/: { n:"KRANGE1" },
7135
		/*::[*/0x0020/*::]*/: { n:"HRANGE" },
7136
		/*::[*/0x0023/*::]*/: { n:"KRANGE2" },
7137
		/*::[*/0x0024/*::]*/: { n:"PROTEC" },
7138
		/*::[*/0x0025/*::]*/: { n:"FOOTER" },
7139
		/*::[*/0x0026/*::]*/: { n:"HEADER" },
7140
		/*::[*/0x0027/*::]*/: { n:"SETUP" },
7141
		/*::[*/0x0028/*::]*/: { n:"MARGINS" },
7142
		/*::[*/0x0029/*::]*/: { n:"LABELFMT" },
7143
		/*::[*/0x002A/*::]*/: { n:"TITLES" },
7144
		/*::[*/0x002B/*::]*/: { n:"SHEETJS" },
7145
		/*::[*/0x002D/*::]*/: { n:"GRAPH" },
7146
		/*::[*/0x002E/*::]*/: { n:"NGRAPH" },
7147
		/*::[*/0x002F/*::]*/: { n:"CALCCOUNT" },
7148
		/*::[*/0x0030/*::]*/: { n:"UNFORMATTED" },
7149
		/*::[*/0x0031/*::]*/: { n:"CURSORW12" },
7150
		/*::[*/0x0032/*::]*/: { n:"WINDOW" },
7151
		/*::[*/0x0033/*::]*/: { n:"STRING", f:parse_LABEL },
7152
		/*::[*/0x0037/*::]*/: { n:"PASSWORD" },
7153
		/*::[*/0x0038/*::]*/: { n:"LOCKED" },
7154
		/*::[*/0x003C/*::]*/: { n:"QUERY" },
7155
		/*::[*/0x003D/*::]*/: { n:"QUERYNAME" },
7156
		/*::[*/0x003E/*::]*/: { n:"PRINT" },
7157
		/*::[*/0x003F/*::]*/: { n:"PRINTNAME" },
7158
		/*::[*/0x0040/*::]*/: { n:"GRAPH2" },
7159
		/*::[*/0x0041/*::]*/: { n:"GRAPHNAME" },
7160
		/*::[*/0x0042/*::]*/: { n:"ZOOM" },
7161
		/*::[*/0x0043/*::]*/: { n:"SYMSPLIT" },
7162
		/*::[*/0x0044/*::]*/: { n:"NSROWS" },
7163
		/*::[*/0x0045/*::]*/: { n:"NSCOLS" },
7164
		/*::[*/0x0046/*::]*/: { n:"RULER" },
7165
		/*::[*/0x0047/*::]*/: { n:"NNAME" },
7166
		/*::[*/0x0048/*::]*/: { n:"ACOMM" },
7167
		/*::[*/0x0049/*::]*/: { n:"AMACRO" },
7168
		/*::[*/0x004A/*::]*/: { n:"PARSE" },
7169
		/*::[*/0x00FF/*::]*/: { n:"", f:parsenoop }
7170
	};
7171
7172
	var WK3Enum = {
7173
		/*::[*/0x0000/*::]*/: { n:"BOF" },
7174
		/*::[*/0x0001/*::]*/: { n:"EOF" },
7175
		/*::[*/0x0003/*::]*/: { n:"??" },
7176
		/*::[*/0x0004/*::]*/: { n:"??" },
7177
		/*::[*/0x0005/*::]*/: { n:"??" },
7178
		/*::[*/0x0006/*::]*/: { n:"??" },
7179
		/*::[*/0x0007/*::]*/: { n:"??" },
7180
		/*::[*/0x0009/*::]*/: { n:"??" },
7181
		/*::[*/0x000a/*::]*/: { n:"??" },
7182
		/*::[*/0x000b/*::]*/: { n:"??" },
7183
		/*::[*/0x000c/*::]*/: { n:"??" },
7184
		/*::[*/0x000e/*::]*/: { n:"??" },
7185
		/*::[*/0x000f/*::]*/: { n:"??" },
7186
		/*::[*/0x0010/*::]*/: { n:"??" },
7187
		/*::[*/0x0011/*::]*/: { n:"??" },
7188
		/*::[*/0x0012/*::]*/: { n:"??" },
7189
		/*::[*/0x0013/*::]*/: { n:"??" },
7190
		/*::[*/0x0015/*::]*/: { n:"??" },
7191
		/*::[*/0x0016/*::]*/: { n:"LABEL16", f:parse_LABEL_16},
7192
		/*::[*/0x0017/*::]*/: { n:"NUMBER17", f:parse_NUMBER_17 },
7193
		/*::[*/0x0018/*::]*/: { n:"NUMBER18", f:parse_NUMBER_18 },
7194
		/*::[*/0x0019/*::]*/: { n:"FORMULA19", f:parse_FORMULA_19},
7195
		/*::[*/0x001a/*::]*/: { n:"??" },
7196
		/*::[*/0x001b/*::]*/: { n:"??" },
7197
		/*::[*/0x001c/*::]*/: { n:"??" },
7198
		/*::[*/0x001d/*::]*/: { n:"??" },
7199
		/*::[*/0x001e/*::]*/: { n:"??" },
7200
		/*::[*/0x001f/*::]*/: { n:"??" },
7201
		/*::[*/0x0021/*::]*/: { n:"??" },
7202
		/*::[*/0x0025/*::]*/: { n:"NUMBER25", f:parse_NUMBER_25 },
7203
		/*::[*/0x0027/*::]*/: { n:"NUMBER27", f:parse_NUMBER_27 },
7204
		/*::[*/0x0028/*::]*/: { n:"FORMULA28", f:parse_FORMULA_28 },
7205
		/*::[*/0x00FF/*::]*/: { n:"", f:parsenoop }
7206
	};
7207
	return {
7208
		to_workbook: lotus_to_workbook
7209
	};
7210
})();
7211
/* Parse a list of <r> tags */
7212
var parse_rs = (function parse_rs_factory() {
7213
	var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g;
7214
	/* 18.4.7 rPr CT_RPrElt */
7215
	var parse_rpr = function parse_rpr(rpr, intro, outro) {
7216
		var font = {}, cp = 65001, align = "";
7217
		var pass = false;
7218
		var m = rpr.match(tagregex), i = 0;
7219
		if(m) for(;i!=m.length; ++i) {
7220
			var y = parsexmltag(m[i]);
7221
			switch(y[0].replace(/\w*:/g,"")) {
7222
				/* 18.8.12 condense CT_BooleanProperty */
7223
				/* ** not required . */
7224
				case '<condense': break;
7225
				/* 18.8.17 extend CT_BooleanProperty */
7226
				/* ** not required . */
7227
				case '<extend': break;
7228
				/* 18.8.36 shadow CT_BooleanProperty */
7229
				/* ** not required . */
7230
				case '<shadow':
7231
					if(!y.val) break;
7232
					/* falls through */
7233
				case '<shadow>':
7234
				case '<shadow/>': font.shadow = 1; break;
7235
				case '</shadow>': break;
7236
7237
				/* 18.4.1 charset CT_IntProperty TODO */
7238
				case '<charset':
7239
					if(y.val == '1') break;
7240
					cp = CS2CP[parseInt(y.val, 10)];
7241
					break;
7242
7243
				/* 18.4.2 outline CT_BooleanProperty TODO */
7244
				case '<outline':
7245
					if(!y.val) break;
7246
					/* falls through */
7247
				case '<outline>':
7248
				case '<outline/>': font.outline = 1; break;
7249
				case '</outline>': break;
7250
7251
				/* 18.4.5 rFont CT_FontName */
7252
				case '<rFont': font.name = y.val; break;
7253
7254
				/* 18.4.11 sz CT_FontSize */
7255
				case '<sz': font.sz = y.val; break;
7256
7257
				/* 18.4.10 strike CT_BooleanProperty */
7258
				case '<strike':
7259
					if(!y.val) break;
7260
					/* falls through */
7261
				case '<strike>':
7262
				case '<strike/>': font.strike = 1; break;
7263
				case '</strike>': break;
7264
7265
				/* 18.4.13 u CT_UnderlineProperty */
7266
				case '<u':
7267
					if(!y.val) break;
7268
					switch(y.val) {
7269
						case 'double': font.uval = "double"; break;
7270
						case 'singleAccounting': font.uval = "single-accounting"; break;
7271
						case 'doubleAccounting': font.uval = "double-accounting"; break;
7272
					}
7273
					/* falls through */
7274
				case '<u>':
7275
				case '<u/>': font.u = 1; break;
7276
				case '</u>': break;
7277
7278
				/* 18.8.2 b */
7279
				case '<b':
7280
					if(y.val == '0') break;
7281
					/* falls through */
7282
				case '<b>':
7283
				case '<b/>': font.b = 1; break;
7284
				case '</b>': break;
7285
7286
				/* 18.8.26 i */
7287
				case '<i':
7288
					if(y.val == '0') break;
7289
					/* falls through */
7290
				case '<i>':
7291
				case '<i/>': font.i = 1; break;
7292
				case '</i>': break;
7293
7294
				/* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
7295
				case '<color':
7296
					if(y.rgb) font.color = y.rgb.slice(2,8);
7297
					break;
7298
7299
				/* 18.8.18 family ST_FontFamily */
7300
				case '<family': font.family = y.val; break;
7301
7302
				/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
7303
				case '<vertAlign': align = y.val; break;
7304
7305
				/* 18.8.35 scheme CT_FontScheme TODO */
7306
				case '<scheme': break;
7307
7308
				/* 18.2.10 extLst CT_ExtensionList ? */
7309
				case '<extLst': case '<extLst>': case '</extLst>': break;
7310
				case '<ext': pass = true; break;
7311
				case '</ext>': pass = false; break;
7312
				default:
7313
					if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
7314
			}
7315
		}
7316
		var style/*:Array<string>*/ = [];
7317
7318
		if(font.u) style.push("text-decoration: underline;");
7319
		if(font.uval) style.push("text-underline-style:" + font.uval + ";");
7320
		if(font.sz) style.push("font-size:" + font.sz + "pt;");
7321
		if(font.outline) style.push("text-effect: outline;");
7322
		if(font.shadow) style.push("text-shadow: auto;");
7323
		intro.push('<span style="' + style.join("") + '">');
7324
7325
		if(font.b) { intro.push("<b>"); outro.push("</b>"); }
7326
		if(font.i) { intro.push("<i>"); outro.push("</i>"); }
7327
		if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
7328
7329
		if(align == "superscript") align = "sup";
7330
		else if(align == "subscript") align = "sub";
7331
		if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
7332
7333
		outro.push("</span>");
7334
		return cp;
7335
	};
7336
7337
	/* 18.4.4 r CT_RElt */
7338
	function parse_r(r) {
7339
		var terms/*:[Array<string>, string, Array<string>]*/ = [[],"",[]];
7340
		/* 18.4.12 t ST_Xstring */
7341
		var t = r.match(tregex)/*, cp = 65001*/;
7342
		if(!t) return "";
7343
		terms[1] = t[1];
7344
7345
		var rpr = r.match(rpregex);
7346
		if(rpr) /*cp = */parse_rpr(rpr[1], terms[0], terms[2]);
7347
7348
		return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
7349
	}
7350
	return function parse_rs(rs) {
7351
		return rs.replace(rregex,"").split(rend).map(parse_r).join("");
7352
	};
7353
})();
7354
7355
/* 18.4.8 si CT_Rst */
7356
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
7357
var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
7358
function parse_si(x, opts) {
7359
	var html = opts ? opts.cellHTML : true;
7360
	var z = {};
7361
	if(!x) return null;
7362
	//var y;
7363
	/* 18.4.12 t ST_Xstring (Plaintext String) */
7364
	// TODO: is whitespace actually valid here?
7365
	if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
7366
		z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
7367
		z.r = utf8read(x);
7368
		if(html) z.h = escapehtml(z.t);
7369
	}
7370
	/* 18.4.4 r CT_RElt (Rich Text Run) */
7371
	else if((/*y = */x.match(sirregex))) {
7372
		z.r = utf8read(x);
7373
		z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
7374
		if(html) z.h = parse_rs(z.r);
7375
	}
7376
	/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
7377
	/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
7378
	return z;
7379
}
7380
7381
/* 18.4 Shared String Table */
7382
var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
7383
var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
7384
var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
7385
function parse_sst_xml(data/*:string*/, opts)/*:SST*/ {
7386
	var s/*:SST*/ = ([]/*:any*/), ss = "";
7387
	if(!data) return s;
7388
	/* 18.4.9 sst CT_Sst */
7389
	var sst = data.match(sstr0);
7390
	if(sst) {
7391
		ss = sst[2].replace(sstr1,"").split(sstr2);
7392
		for(var i = 0; i != ss.length; ++i) {
7393
			var o = parse_si(ss[i].trim(), opts);
7394
			if(o != null) s[s.length] = o;
7395
		}
7396
		sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
7397
	}
7398
	return s;
7399
}
7400
7401
RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
7402
var straywsregex = /^\s|\s$|[\t\n\r]/;
7403
function write_sst_xml(sst/*:SST*/, opts)/*:string*/ {
7404
	if(!opts.bookSST) return "";
7405
	var o = [XML_HEADER];
7406
	o[o.length] = (writextag('sst', null, {
7407
		xmlns: XMLNS.main[0],
7408
		count: sst.Count,
7409
		uniqueCount: sst.Unique
7410
	}));
7411
	for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
7412
		var s/*:XLString*/ = sst[i];
7413
		var sitag = "<si>";
7414
		if(s.r) sitag += s.r;
7415
		else {
7416
			sitag += "<t";
7417
			if(!s.t) s.t = "";
7418
			if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
7419
			sitag += ">" + escapexml(s.t) + "</t>";
7420
		}
7421
		sitag += "</si>";
7422
		o[o.length] = (sitag);
7423
	}
7424
	if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
7425
	return o.join("");
7426
}
7427
/* [MS-XLSB] 2.4.221 BrtBeginSst */
7428
function parse_BrtBeginSst(data) {
7429
	return [data.read_shift(4), data.read_shift(4)];
7430
}
7431
7432
/* [MS-XLSB] 2.1.7.45 Shared Strings */
7433
function parse_sst_bin(data, opts)/*:SST*/ {
7434
	var s/*:SST*/ = ([]/*:any*/);
7435
	var pass = false;
7436
	recordhopper(data, function hopper_sst(val, R_n, RT) {
7437
		switch(RT) {
7438
			case 0x009F: /* 'BrtBeginSst' */
7439
				s.Count = val[0]; s.Unique = val[1]; break;
7440
			case 0x0013: /* 'BrtSSTItem' */
7441
				s.push(val); break;
7442
			case 0x00A0: /* 'BrtEndSst' */
7443
				return true;
7444
7445
			case 0x0023: /* 'BrtFRTBegin' */
7446
				pass = true; break;
7447
			case 0x0024: /* 'BrtFRTEnd' */
7448
				pass = false; break;
7449
7450
			default:
7451
				if(R_n.indexOf("Begin") > 0){/* empty */}
7452
				else if(R_n.indexOf("End") > 0){/* empty */}
7453
				if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
7454
		}
7455
	});
7456
	return s;
7457
}
7458
7459
function write_BrtBeginSst(sst, o) {
7460
	if(!o) o = new_buf(8);
7461
	o.write_shift(4, sst.Count);
7462
	o.write_shift(4, sst.Unique);
7463
	return o;
7464
}
7465
7466
var write_BrtSSTItem = write_RichStr;
7467
7468
function write_sst_bin(sst/*::, opts*/) {
7469
	var ba = buf_array();
7470
	write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst));
7471
	for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i]));
7472
	/* FRTSST */
7473
	write_record(ba, "BrtEndSst");
7474
	return ba.end();
7475
}
7476
function _JS2ANSI(str/*:string*/)/*:Array<number>*/ {
7477
	if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str);
7478
	var o/*:Array<number>*/ = [], oo = str.split("");
7479
	for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0);
7480
	return o;
7481
}
7482
7483
/* [MS-OFFCRYPTO] 2.1.4 Version */
7484
function parse_CRYPTOVersion(blob, length/*:?number*/) {
7485
	var o/*:any*/ = {};
7486
	o.Major = blob.read_shift(2);
7487
	o.Minor = blob.read_shift(2);
7488
	/*:: if(length == null) return o; */
7489
	if(length >= 4) blob.l += length - 4;
7490
	return o;
7491
}
7492
7493
/* [MS-OFFCRYPTO] 2.1.5 DataSpaceVersionInfo */
7494
function parse_DataSpaceVersionInfo(blob) {
7495
	var o = {};
7496
	o.id = blob.read_shift(0, 'lpp4');
7497
	o.R = parse_CRYPTOVersion(blob, 4);
7498
	o.U = parse_CRYPTOVersion(blob, 4);
7499
	o.W = parse_CRYPTOVersion(blob, 4);
7500
	return o;
7501
}
7502
7503
/* [MS-OFFCRYPTO] 2.1.6.1 DataSpaceMapEntry Structure */
7504
function parse_DataSpaceMapEntry(blob) {
7505
	var len = blob.read_shift(4);
7506
	var end = blob.l + len - 4;
7507
	var o = {};
7508
	var cnt = blob.read_shift(4);
7509
	var comps/*:Array<{t:number, v:string}>*/ = [];
7510
	/* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
7511
	while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') });
7512
	o.name = blob.read_shift(0, 'lpp4');
7513
	o.comps = comps;
7514
	if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end);
7515
	return o;
7516
}
7517
7518
/* [MS-OFFCRYPTO] 2.1.6 DataSpaceMap */
7519
function parse_DataSpaceMap(blob) {
7520
	var o = [];
7521
	blob.l += 4; // must be 0x8
7522
	var cnt = blob.read_shift(4);
7523
	while(cnt-- > 0) o.push(parse_DataSpaceMapEntry(blob));
7524
	return o;
7525
}
7526
7527
/* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */
7528
function parse_DataSpaceDefinition(blob)/*:Array<string>*/ {
7529
	var o/*:Array<string>*/ = [];
7530
	blob.l += 4; // must be 0x8
7531
	var cnt = blob.read_shift(4);
7532
	while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4'));
7533
	return o;
7534
}
7535
7536
/* [MS-OFFCRYPTO] 2.1.8 DataSpaceDefinition */
7537
function parse_TransformInfoHeader(blob) {
7538
	var o = {};
7539
	/*var len = */blob.read_shift(4);
7540
	blob.l += 4; // must be 0x1
7541
	o.id = blob.read_shift(0, 'lpp4');
7542
	o.name = blob.read_shift(0, 'lpp4');
7543
	o.R = parse_CRYPTOVersion(blob, 4);
7544
	o.U = parse_CRYPTOVersion(blob, 4);
7545
	o.W = parse_CRYPTOVersion(blob, 4);
7546
	return o;
7547
}
7548
7549
function parse_Primary(blob) {
7550
	/* [MS-OFFCRYPTO] 2.2.6 IRMDSTransformInfo */
7551
	var hdr = parse_TransformInfoHeader(blob);
7552
	/* [MS-OFFCRYPTO] 2.1.9 EncryptionTransformInfo */
7553
	hdr.ename = blob.read_shift(0, '8lpp4');
7554
	hdr.blksz = blob.read_shift(4);
7555
	hdr.cmode = blob.read_shift(4);
7556
	if(blob.read_shift(4) != 0x04) throw new Error("Bad !Primary record");
7557
	return hdr;
7558
}
7559
7560
/* [MS-OFFCRYPTO] 2.3.2 Encryption Header */
7561
function parse_EncryptionHeader(blob, length/*:number*/) {
7562
	var tgt = blob.l + length;
7563
	var o = {};
7564
	o.Flags = (blob.read_shift(4) & 0x3F);
7565
	blob.l += 4;
7566
	o.AlgID = blob.read_shift(4);
7567
	var valid = false;
7568
	switch(o.AlgID) {
7569
		case 0x660E: case 0x660F: case 0x6610: valid = (o.Flags == 0x24); break;
7570
		case 0x6801: valid = (o.Flags == 0x04); break;
7571
		case 0: valid = (o.Flags == 0x10 || o.Flags == 0x04 || o.Flags == 0x24); break;
7572
		default: throw 'Unrecognized encryption algorithm: ' + o.AlgID;
7573
	}
7574
	if(!valid) throw new Error("Encryption Flags/AlgID mismatch");
7575
	o.AlgIDHash = blob.read_shift(4);
7576
	o.KeySize = blob.read_shift(4);
7577
	o.ProviderType = blob.read_shift(4);
7578
	blob.l += 8;
7579
	o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
7580
	blob.l = tgt;
7581
	return o;
7582
}
7583
7584
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
7585
function parse_EncryptionVerifier(blob, length/*:number*/) {
7586
	var o = {}, tgt = blob.l + length;
7587
	blob.l += 4; // SaltSize must be 0x10
7588
	o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
7589
	o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
7590
	/*var sz = */blob.read_shift(4);
7591
	o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
7592
	return o;
7593
}
7594
7595
/* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */
7596
function parse_EncryptionInfo(blob) {
7597
	var vers = parse_CRYPTOVersion(blob);
7598
	switch(vers.Minor) {
7599
		case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
7600
		case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
7601
		case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
7602
	}
7603
	throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
7604
}
7605
7606
/* [MS-OFFCRYPTO] 2.3.4.5  EncryptionInfo Stream (Standard Encryption) */
7607
function parse_EncInfoStd(blob/*::, vers*/) {
7608
	var flags = blob.read_shift(4);
7609
	if((flags & 0x3F) != 0x24) throw new Error("EncryptionInfo mismatch");
7610
	var sz = blob.read_shift(4);
7611
	//var tgt = blob.l + sz;
7612
	var hdr = parse_EncryptionHeader(blob, sz);
7613
	var verifier = parse_EncryptionVerifier(blob, blob.length - blob.l);
7614
	return { t:"Std", h:hdr, v:verifier };
7615
}
7616
/* [MS-OFFCRYPTO] 2.3.4.6  EncryptionInfo Stream (Extensible Encryption) */
7617
function parse_EncInfoExt(/*::blob, vers*/) { throw new Error("File is password-protected: ECMA-376 Extensible"); }
7618
/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
7619
function parse_EncInfoAgl(blob/*::, vers*/) {
7620
	var KeyData = ["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];
7621
	blob.l+=4;
7622
	var xml = blob.read_shift(blob.length - blob.l, 'utf8');
7623
	var o = {};
7624
	xml.replace(tagregex, function xml_agile(x) {
7625
		var y/*:any*/ = parsexmltag(x);
7626
		switch(strip_ns(y[0])) {
7627
			case '<?xml': break;
7628
			case '<encryption': case '</encryption>': break;
7629
			case '<keyData': KeyData.forEach(function(k) { o[k] = y[k]; }); break;
7630
			case '<dataIntegrity': o.encryptedHmacKey = y.encryptedHmacKey; o.encryptedHmacValue = y.encryptedHmacValue; break;
7631
			case '<keyEncryptors>': case '<keyEncryptors': o.encs = []; break;
7632
			case '</keyEncryptors>': break;
7633
7634
			case '<keyEncryptor': o.uri = y.uri; break;
7635
			case '</keyEncryptor>': break;
7636
			case '<encryptedKey': o.encs.push(y); break;
7637
			default: throw y[0];
7638
		}
7639
	});
7640
	return o;
7641
}
7642
7643
/* [MS-OFFCRYPTO] 2.3.5.1 RC4 CryptoAPI Encryption Header */
7644
function parse_RC4CryptoHeader(blob, length/*:number*/) {
7645
	var o = {};
7646
	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4;
7647
	if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor);
7648
	if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major);
7649
	o.Flags = blob.read_shift(4); length -= 4;
7650
	var sz = blob.read_shift(4); length -= 4;
7651
	o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
7652
	o.EncryptionVerifier = parse_EncryptionVerifier(blob, length);
7653
	return o;
7654
}
7655
/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
7656
function parse_RC4Header(blob/*::, length*/) {
7657
	var o = {};
7658
	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4);
7659
	if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
7660
	o.Salt = blob.read_shift(16);
7661
	o.EncryptedVerifier = blob.read_shift(16);
7662
	o.EncryptedVerifierHash = blob.read_shift(16);
7663
	return o;
7664
}
7665
7666
/* [MS-OFFCRYPTO] 2.3.7.1 Binary Document Password Verifier Derivation */
7667
function crypto_CreatePasswordVerifier_Method1(Password/*:string*/) {
7668
	var Verifier = 0x0000, PasswordArray;
7669
	var PasswordDecoded = _JS2ANSI(Password);
7670
	var len = PasswordDecoded.length + 1, i, PasswordByte;
7671
	var Intermediate1, Intermediate2, Intermediate3;
7672
	PasswordArray = new_raw_buf(len);
7673
	PasswordArray[0] = PasswordDecoded.length;
7674
	for(i = 1; i != len; ++i) PasswordArray[i] = PasswordDecoded[i-1];
7675
	for(i = len-1; i >= 0; --i) {
7676
		PasswordByte = PasswordArray[i];
7677
		Intermediate1 = ((Verifier & 0x4000) === 0x0000) ? 0 : 1;
7678
		Intermediate2 = (Verifier << 1) & 0x7FFF;
7679
		Intermediate3 = Intermediate1 | Intermediate2;
7680
		Verifier = Intermediate3 ^ PasswordByte;
7681
	}
7682
	return Verifier ^ 0xCE4B;
7683
}
7684
7685
/* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */
7686
var crypto_CreateXorArray_Method1 = (function() {
7687
	var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00];
7688
	var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3];
7689
	var XorMatrix = [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09, 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF, 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0, 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40, 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5, 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A, 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9, 0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0, 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC, 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10, 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168, 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C, 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD, 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC, 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4];
7690
	var Ror = function(Byte) { return ((Byte/2) | (Byte*128)) & 0xFF; };
7691
	var XorRor = function(byte1, byte2) { return Ror(byte1 ^ byte2); };
7692
	var CreateXorKey_Method1 = function(Password) {
7693
		var XorKey = InitialCode[Password.length - 1];
7694
		var CurrentElement = 0x68;
7695
		for(var i = Password.length-1; i >= 0; --i) {
7696
			var Char = Password[i];
7697
			for(var j = 0; j != 7; ++j) {
7698
				if(Char & 0x40) XorKey ^= XorMatrix[CurrentElement];
7699
				Char *= 2; --CurrentElement;
7700
			}
7701
		}
7702
		return XorKey;
7703
	};
7704
	return function(password/*:string*/) {
7705
		var Password = _JS2ANSI(password);
7706
		var XorKey = CreateXorKey_Method1(Password);
7707
		var Index = Password.length;
7708
		var ObfuscationArray = new_raw_buf(16);
7709
		for(var i = 0; i != 16; ++i) ObfuscationArray[i] = 0x00;
7710
		var Temp, PasswordLastChar, PadIndex;
7711
		if((Index & 1) === 1) {
7712
			Temp = XorKey >> 8;
7713
			ObfuscationArray[Index] = XorRor(PadArray[0], Temp);
7714
			--Index;
7715
			Temp = XorKey & 0xFF;
7716
			PasswordLastChar = Password[Password.length - 1];
7717
			ObfuscationArray[Index] = XorRor(PasswordLastChar, Temp);
7718
		}
7719
		while(Index > 0) {
7720
			--Index;
7721
			Temp = XorKey >> 8;
7722
			ObfuscationArray[Index] = XorRor(Password[Index], Temp);
7723
			--Index;
7724
			Temp = XorKey & 0xFF;
7725
			ObfuscationArray[Index] = XorRor(Password[Index], Temp);
7726
		}
7727
		Index = 15;
7728
		PadIndex = 15 - Password.length;
7729
		while(PadIndex > 0) {
7730
			Temp = XorKey >> 8;
7731
			ObfuscationArray[Index] = XorRor(PadArray[PadIndex], Temp);
7732
			--Index;
7733
			--PadIndex;
7734
			Temp = XorKey & 0xFF;
7735
			ObfuscationArray[Index] = XorRor(Password[Index], Temp);
7736
			--Index;
7737
			--PadIndex;
7738
		}
7739
		return ObfuscationArray;
7740
	};
7741
})();
7742
7743
/* [MS-OFFCRYPTO] 2.3.7.3 Binary Document XOR Data Transformation Method 1 */
7744
var crypto_DecryptData_Method1 = function(password/*:string*/, Data, XorArrayIndex, XorArray, O) {
7745
	/* If XorArray is set, use it; if O is not set, make changes in-place */
7746
	if(!O) O = Data;
7747
	if(!XorArray) XorArray = crypto_CreateXorArray_Method1(password);
7748
	var Index, Value;
7749
	for(Index = 0; Index != Data.length; ++Index) {
7750
		Value = Data[Index];
7751
		Value ^= XorArray[XorArrayIndex];
7752
		Value = ((Value>>5) | (Value<<3)) & 0xFF;
7753
		O[Index] = Value;
7754
		++XorArrayIndex;
7755
	}
7756
	return [O, XorArrayIndex, XorArray];
7757
};
7758
7759
var crypto_MakeXorDecryptor = function(password/*:string*/) {
7760
	var XorArrayIndex = 0, XorArray = crypto_CreateXorArray_Method1(password);
7761
	return function(Data) {
7762
		var O = crypto_DecryptData_Method1("", Data, XorArrayIndex, XorArray);
7763
		XorArrayIndex = O[1];
7764
		return O[0];
7765
	};
7766
};
7767
7768
/* 2.5.343 */
7769
function parse_XORObfuscation(blob, length, opts, out) {
7770
	var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) }/*:any*/);
7771
	if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
7772
	out.valid = o.verificationBytes === o.verifier;
7773
	if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
7774
	return o;
7775
}
7776
7777
/* 2.4.117 */
7778
function parse_FilePassHeader(blob, length/*:number*/, oo) {
7779
	var o = oo || {}; o.Info = blob.read_shift(2); blob.l -= 2;
7780
	if(o.Info === 1) o.Data = parse_RC4Header(blob, length);
7781
	else o.Data = parse_RC4CryptoHeader(blob, length);
7782
	return o;
7783
}
7784
function parse_FilePass(blob, length/*:number*/, opts) {
7785
	var o = ({ Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }/*:any*/); /* wEncryptionType */
7786
	if(o.Type) parse_FilePassHeader(blob, length-2, o);
7787
	else parse_XORObfuscation(blob, opts.biff >= 8 ? length : length - 2, opts, o);
7788
	return o;
7789
}
7790
7791
7792
var RTF = (function() {
7793
	function rtf_to_sheet(d/*:RawData*/, opts)/*:Worksheet*/ {
7794
		switch(opts.type) {
7795
			case 'base64': return rtf_to_sheet_str(Base64.decode(d), opts);
7796
			case 'binary': return rtf_to_sheet_str(d, opts);
7797
			case 'buffer': return rtf_to_sheet_str(d.toString('binary'), opts);
7798
			case 'array':  return rtf_to_sheet_str(cc2str(d), opts);
7799
		}
7800
		throw new Error("Unrecognized type " + opts.type);
7801
	}
7802
7803
	function rtf_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
7804
		var o = opts || {};
7805
		var ws/*:Worksheet*/ = o.dense ? ([]/*:any*/) : ({}/*:any*/);
7806
		var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
7807
7808
		// TODO: parse
7809
		if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
7810
7811
		ws['!ref'] = encode_range(range);
7812
		return ws;
7813
	}
7814
7815
	function rtf_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
7816
7817
	/* TODO: this is a stub */
7818
	function sheet_to_rtf(ws/*:Worksheet*//*::, opts*/)/*:string*/ {
7819
		var o = ["{\\rtf1\\ansi"];
7820
		var r = safe_decode_range(ws['!ref']), cell/*:Cell*/;
7821
		var dense = Array.isArray(ws);
7822
		for(var R = r.s.r; R <= r.e.r; ++R) {
7823
			o.push("\\trowd\\trautofit1");
7824
			for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
7825
			o.push("\\pard\\intbl");
7826
			for(C = r.s.c; C <= r.e.c; ++C) {
7827
				var coord = encode_cell({r:R,c:C});
7828
				cell = dense ? (ws[R]||[])[C]: ws[coord];
7829
				if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
7830
				o.push(" " + (cell.w || (format_cell(cell), cell.w)));
7831
				o.push("\\cell");
7832
			}
7833
			o.push("\\pard\\intbl\\row");
7834
		}
7835
		return o.join("") + "}";
7836
	}
7837
7838
	return {
7839
		to_workbook: rtf_to_workbook,
7840
		to_sheet: rtf_to_sheet,
7841
		from_sheet: sheet_to_rtf
7842
	};
7843
})();
7844
function hex2RGB(h) {
7845
	var o = h.slice(h[0]==="#"?1:0).slice(0,6);
7846
	return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
7847
}
7848
function rgb2Hex(rgb) {
7849
	for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
7850
	return o.toString(16).toUpperCase().slice(1);
7851
}
7852
7853
function rgb2HSL(rgb) {
7854
	var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
7855
	var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
7856
	if(C === 0) return [0, 0, R];
7857
7858
	var H6 = 0, S = 0, L2 = (M + m);
7859
	S = C / (L2 > 1 ? 2 - L2 : L2);
7860
	switch(M){
7861
		case R: H6 = ((G - B) / C + 6)%6; break;
7862
		case G: H6 = ((B - R) / C + 2); break;
7863
		case B: H6 = ((R - G) / C + 4); break;
7864
	}
7865
	return [H6 / 6, S, L2 / 2];
7866
}
7867
7868
function hsl2RGB(hsl){
7869
	var H = hsl[0], S = hsl[1], L = hsl[2];
7870
	var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
7871
	var rgb = [m,m,m], h6 = 6*H;
7872
7873
	var X;
7874
	if(S !== 0) switch(h6|0) {
7875
		case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
7876
		case 1: X = C * (2 - h6);   rgb[0] += X; rgb[1] += C; break;
7877
		case 2: X = C * (h6 - 2);   rgb[1] += C; rgb[2] += X; break;
7878
		case 3: X = C * (4 - h6);   rgb[1] += X; rgb[2] += C; break;
7879
		case 4: X = C * (h6 - 4);   rgb[2] += C; rgb[0] += X; break;
7880
		case 5: X = C * (6 - h6);   rgb[2] += X; rgb[0] += C; break;
7881
	}
7882
	for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
7883
	return rgb;
7884
}
7885
7886
/* 18.8.3 bgColor tint algorithm */
7887
function rgb_tint(hex, tint) {
7888
	if(tint === 0) return hex;
7889
	var hsl = rgb2HSL(hex2RGB(hex));
7890
	if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
7891
	else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
7892
	return rgb2Hex(hsl2RGB(hsl));
7893
}
7894
7895
/* 18.3.1.13 width calculations */
7896
/* [MS-OI29500] 2.1.595 Column Width & Formatting */
7897
var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
7898
function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
7899
function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
7900
function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
7901
//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
7902
//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
7903
function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
7904
/* XLSX/XLSB/XLS specify width in units of MDW */
7905
function find_mdw_colw(collw) {
7906
	var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
7907
	if(delta > 0.005) for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) if(Math.abs(collw - cycle_width(collw)) <= delta) { delta = Math.abs(collw - cycle_width(collw)); _MDW = MDW; }
7908
	MDW = _MDW;
7909
}
7910
/* XLML specifies width in terms of pixels */
7911
/*function find_mdw_wpx(wpx) {
7912
	var delta = Infinity, guess = 0, _MDW = MIN_MDW;
7913
	for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
7914
		guess = char2width_(px2char_(wpx))*256;
7915
		guess = (guess) % 1;
7916
		if(guess > 0.5) guess--;
7917
		if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
7918
	}
7919
	MDW = _MDW;
7920
}*/
7921
7922
function process_col(coll/*:ColInfo*/) {
7923
	if(coll.width) {
7924
		coll.wpx = width2px(coll.width);
7925
		coll.wch = px2char(coll.wpx);
7926
		coll.MDW = MDW;
7927
	} else if(coll.wpx) {
7928
		coll.wch = px2char(coll.wpx);
7929
		coll.width = char2width(coll.wch);
7930
		coll.MDW = MDW;
7931
	} else if(typeof coll.wch == 'number') {
7932
		coll.width = char2width(coll.wch);
7933
		coll.wpx = width2px(coll.width);
7934
		coll.MDW = MDW;
7935
	}
7936
	if(coll.customWidth) delete coll.customWidth;
7937
}
7938
7939
var DEF_PPI = 96, PPI = DEF_PPI;
7940
function px2pt(px) { return px * 96 / PPI; }
7941
function pt2px(pt) { return pt * PPI / 96; }
7942
7943
/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
7944
var XLMLPatternTypeMap = {
7945
	"None": "none",
7946
	"Solid": "solid",
7947
	"Gray50": "mediumGray",
7948
	"Gray75": "darkGray",
7949
	"Gray25": "lightGray",
7950
	"HorzStripe": "darkHorizontal",
7951
	"VertStripe": "darkVertical",
7952
	"ReverseDiagStripe": "darkDown",
7953
	"DiagStripe": "darkUp",
7954
	"DiagCross": "darkGrid",
7955
	"ThickDiagCross": "darkTrellis",
7956
	"ThinHorzStripe": "lightHorizontal",
7957
	"ThinVertStripe": "lightVertical",
7958
	"ThinReverseDiagStripe": "lightDown",
7959
	"ThinHorzCross": "lightGrid"
7960
};
7961
7962
/* 18.8.5 borders CT_Borders */
7963
function parse_borders(t, styles, themes, opts) {
7964
	styles.Borders = [];
7965
	var border = {}/*, sub_border = {}*/;
7966
	var pass = false;
7967
	t[0].match(tagregex).forEach(function(x) {
7968
		var y = parsexmltag(x);
7969
		switch(strip_ns(y[0])) {
7970
			case '<borders': case '<borders>': case '</borders>': break;
7971
7972
			/* 18.8.4 border CT_Border */
7973
			case '<border': case '<border>': case '<border/>':
7974
				border = {};
7975
				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; }
7976
				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; }
7977
				styles.Borders.push(border);
7978
				break;
7979
			case '</border>': break;
7980
7981
			/* note: not in spec, appears to be CT_BorderPr */
7982
			case '<left/>': break;
7983
			case '<left': case '<left>': break;
7984
			case '</left>': break;
7985
7986
			/* note: not in spec, appears to be CT_BorderPr */
7987
			case '<right/>': break;
7988
			case '<right': case '<right>': break;
7989
			case '</right>': break;
7990
7991
			/* 18.8.43 top CT_BorderPr */
7992
			case '<top/>': break;
7993
			case '<top': case '<top>': break;
7994
			case '</top>': break;
7995
7996
			/* 18.8.6 bottom CT_BorderPr */
7997
			case '<bottom/>': break;
7998
			case '<bottom': case '<bottom>': break;
7999
			case '</bottom>': break;
8000
8001
			/* 18.8.13 diagonal CT_BorderPr */
8002
			case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
8003
			case '</diagonal>': break;
8004
8005
			/* 18.8.25 horizontal CT_BorderPr */
8006
			case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
8007
			case '</horizontal>': break;
8008
8009
			/* 18.8.44 vertical CT_BorderPr */
8010
			case '<vertical': case '<vertical>': case '<vertical/>': break;
8011
			case '</vertical>': break;
8012
8013
			/* 18.8.37 start CT_BorderPr */
8014
			case '<start': case '<start>': case '<start/>': break;
8015
			case '</start>': break;
8016
8017
			/* 18.8.16 end CT_BorderPr */
8018
			case '<end': case '<end>': case '<end/>': break;
8019
			case '</end>': break;
8020
8021
			/* 18.8.? color CT_Color */
8022
			case '<color': case '<color>': break;
8023
			case '<color/>': case '</color>': break;
8024
8025
			/* 18.2.10 extLst CT_ExtensionList ? */
8026
			case '<extLst': case '<extLst>': case '</extLst>': break;
8027
			case '<ext': pass = true; break;
8028
			case '</ext>': pass = false; break;
8029
			default: if(opts && opts.WTF) {
8030
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
8031
			}
8032
		}
8033
	});
8034
}
8035
8036
/* 18.8.21 fills CT_Fills */
8037
function parse_fills(t, styles, themes, opts) {
8038
	styles.Fills = [];
8039
	var fill = {};
8040
	var pass = false;
8041
	t[0].match(tagregex).forEach(function(x) {
8042
		var y = parsexmltag(x);
8043
		switch(strip_ns(y[0])) {
8044
			case '<fills': case '<fills>': case '</fills>': break;
8045
8046
			/* 18.8.20 fill CT_Fill */
8047
			case '<fill>': case '<fill': case '<fill/>':
8048
				fill = {}; styles.Fills.push(fill); break;
8049
			case '</fill>': break;
8050
8051
			/* 18.8.24 gradientFill CT_GradientFill */
8052
			case '<gradientFill>': break;
8053
			case '<gradientFill':
8054
			case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
8055
8056
			/* 18.8.32 patternFill CT_PatternFill */
8057
			case '<patternFill': case '<patternFill>':
8058
				if(y.patternType) fill.patternType = y.patternType;
8059
				break;
8060
			case '<patternFill/>': case '</patternFill>': break;
8061
8062
			/* 18.8.3 bgColor CT_Color */
8063
			case '<bgColor':
8064
				if(!fill.bgColor) fill.bgColor = {};
8065
				if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
8066
				if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
8067
				if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
8068
				/* Excel uses ARGB strings */
8069
				if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
8070
				break;
8071
			case '<bgColor/>': case '</bgColor>': break;
8072
8073
			/* 18.8.19 fgColor CT_Color */
8074
			case '<fgColor':
8075
				if(!fill.fgColor) fill.fgColor = {};
8076
				if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
8077
				if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
8078
				/* Excel uses ARGB strings */
8079
				if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6);
8080
				break;
8081
			case '<fgColor/>': case '</fgColor>': break;
8082
8083
			/* 18.8.38 stop CT_GradientStop */
8084
			case '<stop': case '<stop/>': break;
8085
			case '</stop>': break;
8086
8087
			/* 18.8.? color CT_Color */
8088
			case '<color': case '<color/>': break;
8089
			case '</color>': break;
8090
8091
			/* 18.2.10 extLst CT_ExtensionList ? */
8092
			case '<extLst': case '<extLst>': case '</extLst>': break;
8093
			case '<ext': pass = true; break;
8094
			case '</ext>': pass = false; break;
8095
			default: if(opts && opts.WTF) {
8096
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
8097
			}
8098
		}
8099
	});
8100
}
8101
8102
/* 18.8.23 fonts CT_Fonts */
8103
function parse_fonts(t, styles, themes, opts) {
8104
	styles.Fonts = [];
8105
	var font = {};
8106
	var pass = false;
8107
	t[0].match(tagregex).forEach(function(x) {
8108
		var y = parsexmltag(x);
8109
		switch(strip_ns(y[0])) {
8110
			case '<fonts': case '<fonts>': case '</fonts>': break;
8111
8112
			/* 18.8.22 font CT_Font */
8113
			case '<font': case '<font>': break;
8114
			case '</font>': case '<font/>':
8115
				styles.Fonts.push(font);
8116
				font = {};
8117
				break;
8118
8119
			/* 18.8.29 name CT_FontName */
8120
			case '<name': if(y.val) font.name = y.val; break;
8121
			case '<name/>': case '</name>': break;
8122
8123
			/* 18.8.2  b CT_BooleanProperty */
8124
			case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
8125
			case '<b/>': font.bold = 1; break;
8126
8127
			/* 18.8.26 i CT_BooleanProperty */
8128
			case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
8129
			case '<i/>': font.italic = 1; break;
8130
8131
			/* 18.4.13 u CT_UnderlineProperty */
8132
			case '<u':
8133
				switch(y.val) {
8134
					case "none": font.underline = 0x00; break;
8135
					case "single": font.underline = 0x01; break;
8136
					case "double": font.underline = 0x02; break;
8137
					case "singleAccounting": font.underline = 0x21; break;
8138
					case "doubleAccounting": font.underline = 0x22; break;
8139
				} break;
8140
			case '<u/>': font.underline = 1; break;
8141
8142
			/* 18.4.10 strike CT_BooleanProperty */
8143
			case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
8144
			case '<strike/>': font.strike = 1; break;
8145
8146
			/* 18.4.2  outline CT_BooleanProperty */
8147
			case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
8148
			case '<outline/>': font.outline = 1; break;
8149
8150
			/* 18.8.36 shadow CT_BooleanProperty */
8151
			case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
8152
			case '<shadow/>': font.shadow = 1; break;
8153
8154
			/* 18.8.12 condense CT_BooleanProperty */
8155
			case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
8156
			case '<condense/>': font.condense = 1; break;
8157
8158
			/* 18.8.17 extend CT_BooleanProperty */
8159
			case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
8160
			case '<extend/>': font.extend = 1; break;
8161
8162
			/* 18.4.11 sz CT_FontSize */
8163
			case '<sz': if(y.val) font.sz = +y.val; break;
8164
			case '<sz/>': case '</sz>': break;
8165
8166
			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
8167
			case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
8168
			case '<vertAlign/>': case '</vertAlign>': break;
8169
8170
			/* 18.8.18 family CT_FontFamily */
8171
			case '<family': if(y.val) font.family = parseInt(y.val,10); break;
8172
			case '<family/>': case '</family>': break;
8173
8174
			/* 18.8.35 scheme CT_FontScheme */
8175
			case '<scheme': if(y.val) font.scheme = y.val; break;
8176
			case '<scheme/>': case '</scheme>': break;
8177
8178
			/* 18.4.1 charset CT_IntProperty */
8179
			case '<charset':
8180
				if(y.val == '1') break;
8181
				y.codepage = CS2CP[parseInt(y.val, 10)];
8182
				break;
8183
8184
			/* 18.?.? color CT_Color */
8185
			case '<color':
8186
				if(!font.color) font.color = {};
8187
				if(y.auto) font.color.auto = parsexmlbool(y.auto);
8188
8189
				if(y.rgb) font.color.rgb = y.rgb.slice(-6);
8190
				else if(y.indexed) {
8191
					font.color.index = parseInt(y.indexed, 10);
8192
					var icv = XLSIcv[font.color.index];
8193
					if(font.color.index == 81) icv = XLSIcv[1];
8194
					if(!icv) throw new Error(x);
8195
					font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
8196
				} else if(y.theme) {
8197
					font.color.theme = parseInt(y.theme, 10);
8198
					if(y.tint) font.color.tint = parseFloat(y.tint);
8199
					if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
8200
						font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
8201
					}
8202
				}
8203
8204
				break;
8205
			case '<color/>': case '</color>': break;
8206
8207
			/* 18.2.10 extLst CT_ExtensionList ? */
8208
			case '<extLst': case '<extLst>': case '</extLst>': break;
8209
			case '<ext': pass = true; break;
8210
			case '</ext>': pass = false; break;
8211
			default: if(opts && opts.WTF) {
8212
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
8213
			}
8214
		}
8215
	});
8216
}
8217
8218
/* 18.8.31 numFmts CT_NumFmts */
8219
function parse_numFmts(t, styles, opts) {
8220
	styles.NumberFmt = [];
8221
	var k/*Array<number>*/ = (keys(SSF._table)/*:any*/);
8222
	for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
8223
	var m = t[0].match(tagregex);
8224
	if(!m) return;
8225
	for(i=0; i < m.length; ++i) {
8226
		var y = parsexmltag(m[i]);
8227
		switch(strip_ns(y[0])) {
8228
			case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
8229
			case '<numFmt': {
8230
				var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
8231
				styles.NumberFmt[j] = f;
8232
				if(j>0) {
8233
					if(j > 0x188) {
8234
						for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
8235
						styles.NumberFmt[j] = f;
8236
					}
8237
					SSF.load(f,j);
8238
				}
8239
			} break;
8240
			case '</numFmt>': break;
8241
			default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
8242
		}
8243
	}
8244
}
8245
8246
function write_numFmts(NF/*:{[n:number|string]:string}*//*::, opts*/) {
8247
	var o = ["<numFmts>"];
8248
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8249
		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
8250
	});
8251
	if(o.length === 1) return "";
8252
	o[o.length] = ("</numFmts>");
8253
	o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
8254
	return o.join("");
8255
}
8256
8257
/* 18.8.10 cellXfs CT_CellXfs */
8258
var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
8259
var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
8260
function parse_cellXfs(t, styles, opts) {
8261
	styles.CellXf = [];
8262
	var xf;
8263
	var pass = false;
8264
	t[0].match(tagregex).forEach(function(x) {
8265
		var y = parsexmltag(x), i = 0;
8266
		switch(strip_ns(y[0])) {
8267
			case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
8268
8269
			/* 18.8.45 xf CT_Xf */
8270
			case '<xf': case '<xf/>':
8271
				xf = y;
8272
				delete xf[0];
8273
				for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
8274
					xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
8275
				for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
8276
					xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
8277
				if(xf.numFmtId > 0x188) {
8278
					for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
8279
				}
8280
				styles.CellXf.push(xf); break;
8281
			case '</xf>': break;
8282
8283
			/* 18.8.1 alignment CT_CellAlignment */
8284
			case '<alignment': case '<alignment/>':
8285
				var alignment = {};
8286
				if(y.vertical) alignment.vertical = y.vertical;
8287
				if(y.horizontal) alignment.horizontal = y.horizontal;
8288
				if(y.textRotation != null) alignment.textRotation = y.textRotation;
8289
				if(y.indent) alignment.indent = y.indent;
8290
				if(y.wrapText) alignment.wrapText = y.wrapText;
8291
				xf.alignment = alignment;
8292
				break;
8293
			case '</alignment>': break;
8294
8295
			/* 18.8.33 protection CT_CellProtection */
8296
			case '<protection': case '</protection>': case '<protection/>': break;
8297
8298
			/* 18.2.10 extLst CT_ExtensionList ? */
8299
			case '<extLst': case '<extLst>': case '</extLst>': break;
8300
			case '<ext': pass = true; break;
8301
			case '</ext>': pass = false; break;
8302
			default: if(opts && opts.WTF) {
8303
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
8304
			}
8305
		}
8306
	});
8307
}
8308
8309
function write_cellXfs(cellXfs)/*:string*/ {
8310
	var o/*:Array<string>*/ = [];
8311
	o[o.length] = (writextag('cellXfs',null));
8312
	cellXfs.forEach(function(c) { o[o.length] = (writextag('xf', null, c)); });
8313
	o[o.length] = ("</cellXfs>");
8314
	if(o.length === 2) return "";
8315
	o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
8316
	return o.join("");
8317
}
8318
8319
/* 18.8 Styles CT_Stylesheet*/
8320
var parse_sty_xml= (function make_pstyx() {
8321
var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
8322
var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
8323
var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
8324
var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
8325
var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
8326
8327
return function parse_sty_xml(data, themes, opts) {
8328
	var styles = {};
8329
	if(!data) return styles;
8330
	data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
8331
	/* 18.8.39 styleSheet CT_Stylesheet */
8332
	var t;
8333
8334
	/* 18.8.31 numFmts CT_NumFmts ? */
8335
	if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
8336
8337
	/* 18.8.23 fonts CT_Fonts ? */
8338
	if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
8339
8340
	/* 18.8.21 fills CT_Fills ? */
8341
	if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
8342
8343
	/* 18.8.5  borders CT_Borders ? */
8344
	if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
8345
8346
	/* 18.8.9  cellStyleXfs CT_CellStyleXfs ? */
8347
8348
	/* 18.8.10 cellXfs CT_CellXfs ? */
8349
	if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
8350
8351
	/* 18.8.8  cellStyles CT_CellStyles ? */
8352
	/* 18.8.15 dxfs CT_Dxfs ? */
8353
	/* 18.8.42 tableStyles CT_TableStyles ? */
8354
	/* 18.8.11 colors CT_Colors ? */
8355
	/* 18.2.10 extLst CT_ExtensionList ? */
8356
8357
	return styles;
8358
};
8359
})();
8360
8361
var STYLES_XML_ROOT = writextag('styleSheet', null, {
8362
	'xmlns': XMLNS.main[0],
8363
	'xmlns:vt': XMLNS.vt
8364
});
8365
8366
RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
8367
8368
function write_sty_xml(wb/*:Workbook*/, opts)/*:string*/ {
8369
	var o = [XML_HEADER, STYLES_XML_ROOT], w;
8370
	if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
8371
	o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
8372
	o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
8373
	o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
8374
	o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
8375
	if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
8376
	o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
8377
	o[o.length] = ('<dxfs count="0"/>');
8378
	o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
8379
8380
	if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
8381
	return o.join("");
8382
}
8383
/* [MS-XLSB] 2.4.657 BrtFmt */
8384
function parse_BrtFmt(data, length/*:number*/) {
8385
	var numFmtId = data.read_shift(2);
8386
	var stFmtCode = parse_XLWideString(data,length-2);
8387
	return [numFmtId, stFmtCode];
8388
}
8389
function write_BrtFmt(i/*:number*/, f/*:string*/, o) {
8390
	if(!o) o = new_buf(6 + 4 * f.length);
8391
	o.write_shift(2, i);
8392
	write_XLWideString(f, o);
8393
	var out = (o.length > o.l) ? o.slice(0, o.l) : o;
8394
	if(o.l == null) o.l = o.length;
8395
	return out;
8396
}
8397
8398
/* [MS-XLSB] 2.4.659 BrtFont TODO */
8399
function parse_BrtFont(data, length/*:number*/, opts) {
8400
	var out = ({}/*:any*/);
8401
8402
	out.sz = data.read_shift(2) / 20;
8403
8404
	var grbit = parse_FontFlags(data, 2, opts);
8405
	if(grbit.fCondense) out.condense = 1;
8406
	if(grbit.fExtend) out.extend = 1;
8407
	if(grbit.fShadow) out.shadow = 1;
8408
	if(grbit.fOutline) out.outline = 1;
8409
	if(grbit.fStrikeout) out.strike = 1;
8410
	if(grbit.fItalic) out.italic = 1;
8411
8412
	var bls = data.read_shift(2);
8413
	if(bls === 0x02BC) out.bold = 1;
8414
8415
	switch(data.read_shift(2)) {
8416
		/* case 0: out.vertAlign = "baseline"; break; */
8417
		case 1: out.vertAlign = "superscript"; break;
8418
		case 2: out.vertAlign = "subscript"; break;
8419
	}
8420
8421
	var underline = data.read_shift(1);
8422
	if(underline != 0) out.underline = underline;
8423
8424
	var family = data.read_shift(1);
8425
	if(family > 0) out.family = family;
8426
8427
	var bCharSet = data.read_shift(1);
8428
	if(bCharSet > 0) out.charset = bCharSet;
8429
8430
	data.l++;
8431
	out.color = parse_BrtColor(data, 8);
8432
8433
	switch(data.read_shift(1)) {
8434
		/* case 0: out.scheme = "none": break; */
8435
		case 1: out.scheme = "major"; break;
8436
		case 2: out.scheme = "minor"; break;
8437
	}
8438
8439
	out.name = parse_XLWideString(data, length - 21);
8440
8441
	return out;
8442
}
8443
function write_BrtFont(font/*:any*/, o) {
8444
	if(!o) o = new_buf(25+4*32);
8445
	o.write_shift(2, font.sz * 20);
8446
	write_FontFlags(font, o);
8447
	o.write_shift(2, font.bold ? 0x02BC : 0x0190);
8448
	var sss = 0;
8449
	if(font.vertAlign == "superscript") sss = 1;
8450
	else if(font.vertAlign == "subscript") sss = 2;
8451
	o.write_shift(2, sss);
8452
	o.write_shift(1, font.underline || 0);
8453
	o.write_shift(1, font.family || 0);
8454
	o.write_shift(1, font.charset || 0);
8455
	o.write_shift(1, 0);
8456
	write_BrtColor(font.color, o);
8457
	var scheme = 0;
8458
	if(font.scheme == "major") scheme = 1;
8459
	if(font.scheme == "minor") scheme = 2;
8460
	o.write_shift(1, scheme);
8461
	write_XLWideString(font.name, o);
8462
	return o.length > o.l ? o.slice(0, o.l) : o;
8463
}
8464
8465
/* [MS-XLSB] 2.4.650 BrtFill */
8466
var XLSBFillPTNames = [
8467
	"none",
8468
	"solid",
8469
	"mediumGray",
8470
	"darkGray",
8471
	"lightGray",
8472
	"darkHorizontal",
8473
	"darkVertical",
8474
	"darkDown",
8475
	"darkUp",
8476
	"darkGrid",
8477
	"darkTrellis",
8478
	"lightHorizontal",
8479
	"lightVertical",
8480
	"lightDown",
8481
	"lightUp",
8482
	"lightGrid",
8483
	"lightTrellis",
8484
	"gray125",
8485
	"gray0625"
8486
];
8487
var rev_XLSBFillPTNames/*:EvertNumType*/ = (evert(XLSBFillPTNames)/*:any*/);
8488
/* TODO: gradient fill representation */
8489
var parse_BrtFill = parsenoop;
8490
function write_BrtFill(fill, o) {
8491
	if(!o) o = new_buf(4*3 + 8*7 + 16*1);
8492
	var fls/*:number*/ = rev_XLSBFillPTNames[fill.patternType];
8493
	if(fls == null) fls = 0x28;
8494
	o.write_shift(4, fls);
8495
	var j = 0;
8496
	if(fls != 0x28) {
8497
		/* TODO: custom FG Color */
8498
		write_BrtColor({auto:1}, o);
8499
		/* TODO: custom BG Color */
8500
		write_BrtColor({auto:1}, o);
8501
8502
		for(; j < 12; ++j) o.write_shift(4, 0);
8503
	} else {
8504
		for(; j < 4; ++j) o.write_shift(4, 0);
8505
8506
		for(; j < 12; ++j) o.write_shift(4, 0); /* TODO */
8507
		/* iGradientType */
8508
		/* xnumDegree */
8509
		/* xnumFillToLeft */
8510
		/* xnumFillToRight */
8511
		/* xnumFillToTop */
8512
		/* xnumFillToBottom */
8513
		/* cNumStop */
8514
		/* xfillGradientStop */
8515
	}
8516
	return o.length > o.l ? o.slice(0, o.l) : o;
8517
}
8518
8519
/* [MS-XLSB] 2.4.824 BrtXF */
8520
function parse_BrtXF(data, length/*:number*/) {
8521
	var tgt = data.l + length;
8522
	var ixfeParent = data.read_shift(2);
8523
	var ifmt = data.read_shift(2);
8524
	data.l = tgt;
8525
	return {ixfe:ixfeParent, numFmtId:ifmt };
8526
}
8527
function write_BrtXF(data, ixfeP, o) {
8528
	if(!o) o = new_buf(16);
8529
	o.write_shift(2, ixfeP||0);
8530
	o.write_shift(2, data.numFmtId||0);
8531
	o.write_shift(2, 0); /* iFont */
8532
	o.write_shift(2, 0); /* iFill */
8533
	o.write_shift(2, 0); /* ixBorder */
8534
	o.write_shift(1, 0); /* trot */
8535
	o.write_shift(1, 0); /* indent */
8536
	o.write_shift(1, 0); /* flags */
8537
	o.write_shift(1, 0); /* flags */
8538
	o.write_shift(1, 0); /* xfGrbitAtr */
8539
	o.write_shift(1, 0);
8540
	return o;
8541
}
8542
8543
/* [MS-XLSB] 2.5.4 Blxf TODO */
8544
function write_Blxf(data, o) {
8545
	if(!o) o = new_buf(10);
8546
	o.write_shift(1, 0); /* dg */
8547
	o.write_shift(1, 0);
8548
	o.write_shift(4, 0); /* color */
8549
	o.write_shift(4, 0); /* color */
8550
	return o;
8551
}
8552
/* [MS-XLSB] 2.4.302 BrtBorder TODO */
8553
var parse_BrtBorder = parsenoop;
8554
function write_BrtBorder(border, o) {
8555
	if(!o) o = new_buf(51);
8556
	o.write_shift(1, 0); /* diagonal */
8557
	write_Blxf(null, o); /* top */
8558
	write_Blxf(null, o); /* bottom */
8559
	write_Blxf(null, o); /* left */
8560
	write_Blxf(null, o); /* right */
8561
	write_Blxf(null, o); /* diag */
8562
	return o.length > o.l ? o.slice(0, o.l) : o;
8563
}
8564
8565
/* [MS-XLSB] 2.4.763 BrtStyle TODO */
8566
function write_BrtStyle(style, o) {
8567
	if(!o) o = new_buf(12+4*10);
8568
	o.write_shift(4, style.xfId);
8569
	o.write_shift(2, 1);
8570
	o.write_shift(1, +style.builtinId);
8571
	o.write_shift(1, 0); /* iLevel */
8572
	write_XLNullableWideString(style.name || "", o);
8573
	return o.length > o.l ? o.slice(0, o.l) : o;
8574
}
8575
8576
/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
8577
function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
8578
	var o = new_buf(4+256*2*4);
8579
	o.write_shift(4, cnt);
8580
	write_XLNullableWideString(defTableStyle, o);
8581
	write_XLNullableWideString(defPivotStyle, o);
8582
	return o.length > o.l ? o.slice(0, o.l) : o;
8583
}
8584
8585
/* [MS-XLSB] 2.1.7.50 Styles */
8586
function parse_sty_bin(data, themes, opts) {
8587
	var styles = {};
8588
	styles.NumberFmt = ([]/*:any*/);
8589
	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y];
8590
8591
	styles.CellXf = [];
8592
	styles.Fonts = [];
8593
	var state/*:Array<string>*/ = [];
8594
	var pass = false;
8595
	recordhopper(data, function hopper_sty(val, R_n, RT) {
8596
		switch(RT) {
8597
			case 0x002C: /* 'BrtFmt' */
8598
				styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]);
8599
				break;
8600
			case 0x002B: /* 'BrtFont' */
8601
				styles.Fonts.push(val);
8602
				if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) {
8603
					val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0);
8604
				}
8605
				break;
8606
			case 0x0401: /* 'BrtKnownFonts' */ break;
8607
			case 0x002D: /* 'BrtFill' */ break;
8608
			case 0x002E: /* 'BrtBorder' */ break;
8609
			case 0x002F: /* 'BrtXF' */
8610
				if(state[state.length - 1] == "BrtBeginCellXFs") {
8611
					styles.CellXf.push(val);
8612
				}
8613
				break;
8614
			case 0x0030: /* 'BrtStyle' */
8615
			case 0x01FB: /* 'BrtDXF' */
8616
			case 0x023C: /* 'BrtMRUColor' */
8617
			case 0x01DB: /* 'BrtIndexedColor': */
8618
				break;
8619
8620
			case 0x0493: /* 'BrtDXF14' */
8621
			case 0x0836: /* 'BrtDXF15' */
8622
			case 0x046A: /* 'BrtSlicerStyleElement' */
8623
			case 0x0200: /* 'BrtTableStyleElement' */
8624
			case 0x082F: /* 'BrtTimelineStyleElement' */
8625
			case 0x0C00: /* 'BrtUid' */
8626
				break;
8627
8628
			case 0x0023: /* 'BrtFRTBegin' */
8629
				pass = true; break;
8630
			case 0x0024: /* 'BrtFRTEnd' */
8631
				pass = false; break;
8632
			case 0x0025: /* 'BrtACBegin' */
8633
				state.push(R_n); break;
8634
			case 0x0026: /* 'BrtACEnd' */
8635
				state.pop(); break;
8636
8637
			default:
8638
				if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
8639
				else if((R_n||"").indexOf("End") > 0) state.pop();
8640
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
8641
		}
8642
	});
8643
	return styles;
8644
}
8645
8646
function write_FMTS_bin(ba, NF/*:?SSFTable*/) {
8647
	if(!NF) return;
8648
	var cnt = 0;
8649
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8650
		/*:: if(!NF) return; */
8651
		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
8652
	});
8653
8654
	if(cnt == 0) return;
8655
	write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
8656
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8657
		/*:: if(!NF) return; */
8658
		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
8659
	});
8660
	write_record(ba, "BrtEndFmts");
8661
}
8662
8663
function write_FONTS_bin(ba/*::, data*/) {
8664
	var cnt = 1;
8665
8666
	if(cnt == 0) return;
8667
	write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt));
8668
	write_record(ba, "BrtFont", write_BrtFont({
8669
		sz:12,
8670
		color: {theme:1},
8671
		name: "Calibri",
8672
		family: 2,
8673
		scheme: "minor"
8674
	}));
8675
	/* 1*65491BrtFont [ACFONTS] */
8676
	write_record(ba, "BrtEndFonts");
8677
}
8678
8679
function write_FILLS_bin(ba/*::, data*/) {
8680
	var cnt = 2;
8681
8682
	if(cnt == 0) return;
8683
	write_record(ba, "BrtBeginFills", write_UInt32LE(cnt));
8684
	write_record(ba, "BrtFill", write_BrtFill({patternType:"none"}));
8685
	write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"}));
8686
	/* 1*65431BrtFill */
8687
	write_record(ba, "BrtEndFills");
8688
}
8689
8690
function write_BORDERS_bin(ba/*::, data*/) {
8691
	var cnt = 1;
8692
8693
	if(cnt == 0) return;
8694
	write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt));
8695
	write_record(ba, "BrtBorder", write_BrtBorder({}));
8696
	/* 1*65430BrtBorder */
8697
	write_record(ba, "BrtEndBorders");
8698
}
8699
8700
function write_CELLSTYLEXFS_bin(ba/*::, data*/) {
8701
	var cnt = 1;
8702
	write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
8703
	write_record(ba, "BrtXF", write_BrtXF({
8704
		numFmtId:0,
8705
		fontId:0,
8706
		fillId:0,
8707
		borderId:0
8708
	}, 0xFFFF));
8709
	/* 1*65430(BrtXF *FRT) */
8710
	write_record(ba, "BrtEndCellStyleXFs");
8711
}
8712
8713
function write_CELLXFS_bin(ba, data) {
8714
	write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length));
8715
	data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); });
8716
	/* 1*65430(BrtXF *FRT) */
8717
	write_record(ba, "BrtEndCellXFs");
8718
}
8719
8720
function write_STYLES_bin(ba/*::, data*/) {
8721
	var cnt = 1;
8722
8723
	write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt));
8724
	write_record(ba, "BrtStyle", write_BrtStyle({
8725
		xfId:0,
8726
		builtinId:0,
8727
		name:"Normal"
8728
	}));
8729
	/* 1*65430(BrtStyle *FRT) */
8730
	write_record(ba, "BrtEndStyles");
8731
}
8732
8733
function write_DXFS_bin(ba/*::, data*/) {
8734
	var cnt = 0;
8735
8736
	write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
8737
	/* *2147483647(BrtDXF *FRT) */
8738
	write_record(ba, "BrtEndDXFs");
8739
}
8740
8741
function write_TABLESTYLES_bin(ba/*::, data*/) {
8742
	var cnt = 0;
8743
8744
	write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
8745
	/* *TABLESTYLE */
8746
	write_record(ba, "BrtEndTableStyles");
8747
}
8748
8749
function write_COLORPALETTE_bin(/*::ba, data*/) {
8750
	return;
8751
	/* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
8752
}
8753
8754
/* [MS-XLSB] 2.1.7.50 Styles */
8755
function write_sty_bin(wb, opts) {
8756
	var ba = buf_array();
8757
	write_record(ba, "BrtBeginStyleSheet");
8758
	write_FMTS_bin(ba, wb.SSF);
8759
	write_FONTS_bin(ba, wb);
8760
	write_FILLS_bin(ba, wb);
8761
	write_BORDERS_bin(ba, wb);
8762
	write_CELLSTYLEXFS_bin(ba, wb);
8763
	write_CELLXFS_bin(ba, opts.cellXfs);
8764
	write_STYLES_bin(ba, wb);
8765
	write_DXFS_bin(ba, wb);
8766
	write_TABLESTYLES_bin(ba, wb);
8767
	write_COLORPALETTE_bin(ba, wb);
8768
	/* FRTSTYLESHEET*/
8769
	write_record(ba, "BrtEndStyleSheet");
8770
	return ba.end();
8771
}
8772
RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
8773
8774
/* 20.1.6.2 clrScheme CT_ColorScheme */
8775
function parse_clrScheme(t, themes, opts) {
8776
	themes.themeElements.clrScheme = [];
8777
	var color = {};
8778
	(t[0].match(tagregex)||[]).forEach(function(x) {
8779
		var y = parsexmltag(x);
8780
		switch(y[0]) {
8781
			/* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
8782
			case '<a:clrScheme': case '</a:clrScheme>': break;
8783
8784
			/* 20.1.2.3.32 srgbClr CT_SRgbColor */
8785
			case '<a:srgbClr':
8786
				color.rgb = y.val; break;
8787
8788
			/* 20.1.2.3.33 sysClr CT_SystemColor */
8789
			case '<a:sysClr':
8790
				color.rgb = y.lastClr; break;
8791
8792
			/* 20.1.4.1.1 accent1 (Accent 1) */
8793
			/* 20.1.4.1.2 accent2 (Accent 2) */
8794
			/* 20.1.4.1.3 accent3 (Accent 3) */
8795
			/* 20.1.4.1.4 accent4 (Accent 4) */
8796
			/* 20.1.4.1.5 accent5 (Accent 5) */
8797
			/* 20.1.4.1.6 accent6 (Accent 6) */
8798
			/* 20.1.4.1.9 dk1 (Dark 1) */
8799
			/* 20.1.4.1.10 dk2 (Dark 2) */
8800
			/* 20.1.4.1.15 folHlink (Followed Hyperlink) */
8801
			/* 20.1.4.1.19 hlink (Hyperlink) */
8802
			/* 20.1.4.1.22 lt1 (Light 1) */
8803
			/* 20.1.4.1.23 lt2 (Light 2) */
8804
			case '<a:dk1>': case '</a:dk1>':
8805
			case '<a:lt1>': case '</a:lt1>':
8806
			case '<a:dk2>': case '</a:dk2>':
8807
			case '<a:lt2>': case '</a:lt2>':
8808
			case '<a:accent1>': case '</a:accent1>':
8809
			case '<a:accent2>': case '</a:accent2>':
8810
			case '<a:accent3>': case '</a:accent3>':
8811
			case '<a:accent4>': case '</a:accent4>':
8812
			case '<a:accent5>': case '</a:accent5>':
8813
			case '<a:accent6>': case '</a:accent6>':
8814
			case '<a:hlink>': case '</a:hlink>':
8815
			case '<a:folHlink>': case '</a:folHlink>':
8816
				if (y[0].charAt(1) === '/') {
8817
					themes.themeElements.clrScheme.push(color);
8818
					color = {};
8819
				} else {
8820
					color.name = y[0].slice(3, y[0].length - 1);
8821
				}
8822
				break;
8823
8824
			default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
8825
		}
8826
	});
8827
}
8828
8829
/* 20.1.4.1.18 fontScheme CT_FontScheme */
8830
function parse_fontScheme(/*::t, themes, opts*/) { }
8831
8832
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
8833
function parse_fmtScheme(/*::t, themes, opts*/) { }
8834
8835
var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
8836
var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
8837
var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
8838
8839
/* 20.1.6.10 themeElements CT_BaseStyles */
8840
function parse_themeElements(data, themes, opts) {
8841
	themes.themeElements = {};
8842
8843
	var t;
8844
8845
	[
8846
		/* clrScheme CT_ColorScheme */
8847
		['clrScheme', clrsregex, parse_clrScheme],
8848
		/* fontScheme CT_FontScheme */
8849
		['fontScheme', fntsregex, parse_fontScheme],
8850
		/* fmtScheme CT_StyleMatrix */
8851
		['fmtScheme', fmtsregex, parse_fmtScheme]
8852
	].forEach(function(m) {
8853
		if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
8854
		m[2](t, themes, opts);
8855
	});
8856
}
8857
8858
var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
8859
8860
/* 14.2.7 Theme Part */
8861
function parse_theme_xml(data/*:string*/, opts) {
8862
	/* 20.1.6.9 theme CT_OfficeStyleSheet */
8863
	if(!data || data.length === 0) return parse_theme_xml(write_theme());
8864
8865
	var t;
8866
	var themes = {};
8867
8868
	/* themeElements CT_BaseStyles */
8869
	if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
8870
	parse_themeElements(t[0], themes, opts);
8871
8872
	return themes;
8873
}
8874
8875
function write_theme(Themes, opts)/*:string*/ {
8876
	if(opts && opts.themeXLSX) return opts.themeXLSX;
8877
	var o = [XML_HEADER];
8878
	o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
8879
	o[o.length] =  '<a:themeElements>';
8880
8881
	o[o.length] =   '<a:clrScheme name="Office">';
8882
	o[o.length] =    '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
8883
	o[o.length] =    '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
8884
	o[o.length] =    '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
8885
	o[o.length] =    '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
8886
	o[o.length] =    '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
8887
	o[o.length] =    '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
8888
	o[o.length] =    '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
8889
	o[o.length] =    '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
8890
	o[o.length] =    '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
8891
	o[o.length] =    '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
8892
	o[o.length] =    '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
8893
	o[o.length] =    '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
8894
	o[o.length] =   '</a:clrScheme>';
8895
8896
	o[o.length] =   '<a:fontScheme name="Office">';
8897
	o[o.length] =    '<a:majorFont>';
8898
	o[o.length] =     '<a:latin typeface="Cambria"/>';
8899
	o[o.length] =     '<a:ea typeface=""/>';
8900
	o[o.length] =     '<a:cs typeface=""/>';
8901
	o[o.length] =     '<a:font script="Jpan" typeface="MS Pゴシック"/>';
8902
	o[o.length] =     '<a:font script="Hang" typeface="맑은 고딕"/>';
8903
	o[o.length] =     '<a:font script="Hans" typeface="宋体"/>';
8904
	o[o.length] =     '<a:font script="Hant" typeface="新細明體"/>';
8905
	o[o.length] =     '<a:font script="Arab" typeface="Times New Roman"/>';
8906
	o[o.length] =     '<a:font script="Hebr" typeface="Times New Roman"/>';
8907
	o[o.length] =     '<a:font script="Thai" typeface="Tahoma"/>';
8908
	o[o.length] =     '<a:font script="Ethi" typeface="Nyala"/>';
8909
	o[o.length] =     '<a:font script="Beng" typeface="Vrinda"/>';
8910
	o[o.length] =     '<a:font script="Gujr" typeface="Shruti"/>';
8911
	o[o.length] =     '<a:font script="Khmr" typeface="MoolBoran"/>';
8912
	o[o.length] =     '<a:font script="Knda" typeface="Tunga"/>';
8913
	o[o.length] =     '<a:font script="Guru" typeface="Raavi"/>';
8914
	o[o.length] =     '<a:font script="Cans" typeface="Euphemia"/>';
8915
	o[o.length] =     '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
8916
	o[o.length] =     '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
8917
	o[o.length] =     '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
8918
	o[o.length] =     '<a:font script="Thaa" typeface="MV Boli"/>';
8919
	o[o.length] =     '<a:font script="Deva" typeface="Mangal"/>';
8920
	o[o.length] =     '<a:font script="Telu" typeface="Gautami"/>';
8921
	o[o.length] =     '<a:font script="Taml" typeface="Latha"/>';
8922
	o[o.length] =     '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
8923
	o[o.length] =     '<a:font script="Orya" typeface="Kalinga"/>';
8924
	o[o.length] =     '<a:font script="Mlym" typeface="Kartika"/>';
8925
	o[o.length] =     '<a:font script="Laoo" typeface="DokChampa"/>';
8926
	o[o.length] =     '<a:font script="Sinh" typeface="Iskoola Pota"/>';
8927
	o[o.length] =     '<a:font script="Mong" typeface="Mongolian Baiti"/>';
8928
	o[o.length] =     '<a:font script="Viet" typeface="Times New Roman"/>';
8929
	o[o.length] =     '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
8930
	o[o.length] =     '<a:font script="Geor" typeface="Sylfaen"/>';
8931
	o[o.length] =    '</a:majorFont>';
8932
	o[o.length] =    '<a:minorFont>';
8933
	o[o.length] =     '<a:latin typeface="Calibri"/>';
8934
	o[o.length] =     '<a:ea typeface=""/>';
8935
	o[o.length] =     '<a:cs typeface=""/>';
8936
	o[o.length] =     '<a:font script="Jpan" typeface="MS Pゴシック"/>';
8937
	o[o.length] =     '<a:font script="Hang" typeface="맑은 고딕"/>';
8938
	o[o.length] =     '<a:font script="Hans" typeface="宋体"/>';
8939
	o[o.length] =     '<a:font script="Hant" typeface="新細明體"/>';
8940
	o[o.length] =     '<a:font script="Arab" typeface="Arial"/>';
8941
	o[o.length] =     '<a:font script="Hebr" typeface="Arial"/>';
8942
	o[o.length] =     '<a:font script="Thai" typeface="Tahoma"/>';
8943
	o[o.length] =     '<a:font script="Ethi" typeface="Nyala"/>';
8944
	o[o.length] =     '<a:font script="Beng" typeface="Vrinda"/>';
8945
	o[o.length] =     '<a:font script="Gujr" typeface="Shruti"/>';
8946
	o[o.length] =     '<a:font script="Khmr" typeface="DaunPenh"/>';
8947
	o[o.length] =     '<a:font script="Knda" typeface="Tunga"/>';
8948
	o[o.length] =     '<a:font script="Guru" typeface="Raavi"/>';
8949
	o[o.length] =     '<a:font script="Cans" typeface="Euphemia"/>';
8950
	o[o.length] =     '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
8951
	o[o.length] =     '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
8952
	o[o.length] =     '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
8953
	o[o.length] =     '<a:font script="Thaa" typeface="MV Boli"/>';
8954
	o[o.length] =     '<a:font script="Deva" typeface="Mangal"/>';
8955
	o[o.length] =     '<a:font script="Telu" typeface="Gautami"/>';
8956
	o[o.length] =     '<a:font script="Taml" typeface="Latha"/>';
8957
	o[o.length] =     '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
8958
	o[o.length] =     '<a:font script="Orya" typeface="Kalinga"/>';
8959
	o[o.length] =     '<a:font script="Mlym" typeface="Kartika"/>';
8960
	o[o.length] =     '<a:font script="Laoo" typeface="DokChampa"/>';
8961
	o[o.length] =     '<a:font script="Sinh" typeface="Iskoola Pota"/>';
8962
	o[o.length] =     '<a:font script="Mong" typeface="Mongolian Baiti"/>';
8963
	o[o.length] =     '<a:font script="Viet" typeface="Arial"/>';
8964
	o[o.length] =     '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
8965
	o[o.length] =     '<a:font script="Geor" typeface="Sylfaen"/>';
8966
	o[o.length] =    '</a:minorFont>';
8967
	o[o.length] =   '</a:fontScheme>';
8968
8969
	o[o.length] =   '<a:fmtScheme name="Office">';
8970
	o[o.length] =    '<a:fillStyleLst>';
8971
	o[o.length] =     '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
8972
	o[o.length] =     '<a:gradFill rotWithShape="1">';
8973
	o[o.length] =      '<a:gsLst>';
8974
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
8975
	o[o.length] =       '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
8976
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
8977
	o[o.length] =      '</a:gsLst>';
8978
	o[o.length] =      '<a:lin ang="16200000" scaled="1"/>';
8979
	o[o.length] =     '</a:gradFill>';
8980
	o[o.length] =     '<a:gradFill rotWithShape="1">';
8981
	o[o.length] =      '<a:gsLst>';
8982
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="100000"/><a:shade val="100000"/><a:satMod val="130000"/></a:schemeClr></a:gs>';
8983
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="50000"/><a:shade val="100000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
8984
	o[o.length] =      '</a:gsLst>';
8985
	o[o.length] =      '<a:lin ang="16200000" scaled="0"/>';
8986
	o[o.length] =     '</a:gradFill>';
8987
	o[o.length] =    '</a:fillStyleLst>';
8988
	o[o.length] =    '<a:lnStyleLst>';
8989
	o[o.length] =     '<a:ln w="9525" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"><a:shade val="95000"/><a:satMod val="105000"/></a:schemeClr></a:solidFill><a:prstDash val="solid"/></a:ln>';
8990
	o[o.length] =     '<a:ln w="25400" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>';
8991
	o[o.length] =     '<a:ln w="38100" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>';
8992
	o[o.length] =    '</a:lnStyleLst>';
8993
	o[o.length] =    '<a:effectStyleLst>';
8994
	o[o.length] =     '<a:effectStyle>';
8995
	o[o.length] =      '<a:effectLst>';
8996
	o[o.length] =       '<a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="38000"/></a:srgbClr></a:outerShdw>';
8997
	o[o.length] =      '</a:effectLst>';
8998
	o[o.length] =     '</a:effectStyle>';
8999
	o[o.length] =     '<a:effectStyle>';
9000
	o[o.length] =      '<a:effectLst>';
9001
	o[o.length] =       '<a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw>';
9002
	o[o.length] =      '</a:effectLst>';
9003
	o[o.length] =     '</a:effectStyle>';
9004
	o[o.length] =     '<a:effectStyle>';
9005
	o[o.length] =      '<a:effectLst>';
9006
	o[o.length] =       '<a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw>';
9007
	o[o.length] =      '</a:effectLst>';
9008
	o[o.length] =      '<a:scene3d><a:camera prst="orthographicFront"><a:rot lat="0" lon="0" rev="0"/></a:camera><a:lightRig rig="threePt" dir="t"><a:rot lat="0" lon="0" rev="1200000"/></a:lightRig></a:scene3d>';
9009
	o[o.length] =      '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
9010
	o[o.length] =     '</a:effectStyle>';
9011
	o[o.length] =    '</a:effectStyleLst>';
9012
	o[o.length] =    '<a:bgFillStyleLst>';
9013
	o[o.length] =     '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9014
	o[o.length] =     '<a:gradFill rotWithShape="1">';
9015
	o[o.length] =      '<a:gsLst>';
9016
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9017
	o[o.length] =       '<a:gs pos="40000"><a:schemeClr val="phClr"><a:tint val="45000"/><a:shade val="99000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9018
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
9019
	o[o.length] =      '</a:gsLst>';
9020
	o[o.length] =      '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
9021
	o[o.length] =     '</a:gradFill>';
9022
	o[o.length] =     '<a:gradFill rotWithShape="1">';
9023
	o[o.length] =      '<a:gsLst>';
9024
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9025
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
9026
	o[o.length] =      '</a:gsLst>';
9027
	o[o.length] =      '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
9028
	o[o.length] =     '</a:gradFill>';
9029
	o[o.length] =    '</a:bgFillStyleLst>';
9030
	o[o.length] =   '</a:fmtScheme>';
9031
	o[o.length] =  '</a:themeElements>';
9032
9033
	o[o.length] =  '<a:objectDefaults>';
9034
	o[o.length] =   '<a:spDef>';
9035
	o[o.length] =    '<a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="1"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="3"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="2"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></a:style>';
9036
	o[o.length] =   '</a:spDef>';
9037
	o[o.length] =   '<a:lnDef>';
9038
	o[o.length] =    '<a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="2"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="0"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="1"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="tx1"/></a:fontRef></a:style>';
9039
	o[o.length] =   '</a:lnDef>';
9040
	o[o.length] =  '</a:objectDefaults>';
9041
	o[o.length] =  '<a:extraClrSchemeLst/>';
9042
	o[o.length] = '</a:theme>';
9043
	return o.join("");
9044
}
9045
/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
9046
function parse_Theme(blob, length, opts) {
9047
	var end = blob.l + length;
9048
	var dwThemeVersion = blob.read_shift(4);
9049
	if(dwThemeVersion === 124226) return;
9050
	if(!opts.cellStyles || !jszip) { blob.l = end; return; }
9051
	var data = blob.slice(blob.l);
9052
	blob.l = end;
9053
	var zip; try { zip = new jszip(data); } catch(e) { return; }
9054
	var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true);
9055
	if(!themeXML) return;
9056
	return parse_theme_xml(themeXML, opts);
9057
}
9058
9059
/* 2.5.49 */
9060
function parse_ColorTheme(blob/*::, length*/) { return blob.read_shift(4); }
9061
9062
/* 2.5.155 */
9063
function parse_FullColorExt(blob/*::, length*/) {
9064
	var o = {};
9065
	o.xclrType = blob.read_shift(2);
9066
	o.nTintShade = blob.read_shift(2);
9067
	switch(o.xclrType) {
9068
		case 0: blob.l += 4; break;
9069
		case 1: o.xclrValue = parse_IcvXF(blob, 4); break;
9070
		case 2: o.xclrValue = parse_LongRGBA(blob, 4); break;
9071
		case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
9072
		case 4: blob.l += 4; break;
9073
	}
9074
	blob.l += 8;
9075
	return o;
9076
}
9077
9078
/* 2.5.164 TODO: read 7 bits*/
9079
function parse_IcvXF(blob, length) {
9080
	return parsenoop(blob, length);
9081
}
9082
9083
/* 2.5.280 */
9084
function parse_XFExtGradient(blob, length) {
9085
	return parsenoop(blob, length);
9086
}
9087
9088
/* [MS-XLS] 2.5.108 */
9089
function parse_ExtProp(blob/*::, length*/)/*:Array<any>*/ {
9090
	var extType = blob.read_shift(2);
9091
	var cb = blob.read_shift(2) - 4;
9092
	var o = [extType];
9093
	switch(extType) {
9094
		case 0x04: case 0x05: case 0x07: case 0x08:
9095
		case 0x09: case 0x0A: case 0x0B: case 0x0D:
9096
			o[1] = parse_FullColorExt(blob, cb); break;
9097
		case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
9098
		case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
9099
		default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
9100
	}
9101
	return o;
9102
}
9103
9104
/* 2.4.355 */
9105
function parse_XFExt(blob, length) {
9106
	var end = blob.l + length;
9107
	blob.l += 2;
9108
	var ixfe = blob.read_shift(2);
9109
	blob.l += 2;
9110
	var cexts = blob.read_shift(2);
9111
	var ext/*:AOA*/ = [];
9112
	while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
9113
	return {ixfe:ixfe, ext:ext};
9114
}
9115
9116
/* xf is an XF, see parse_XFExt for xfext */
9117
function update_xfext(xf, xfext) {
9118
	xfext.forEach(function(xfe) {
9119
		switch(xfe[0]) { /* 2.5.108 extPropData */
9120
			case 0x04: break; /* foreground color */
9121
			case 0x05: break; /* background color */
9122
			case 0x06: break; /* gradient fill */
9123
			case 0x07: break; /* top cell border color */
9124
			case 0x08: break; /* bottom cell border color */
9125
			case 0x09: break; /* left cell border color */
9126
			case 0x0a: break; /* right cell border color */
9127
			case 0x0b: break; /* diagonal cell border color */
9128
			case 0x0d: break; /* text color */
9129
			case 0x0e: break; /* font scheme */
9130
			case 0x0f: break; /* indentation level */
9131
		}
9132
	});
9133
}
9134
9135
/* 18.6 Calculation Chain */
9136
function parse_cc_xml(data/*::, name, opts*/)/*:Array<any>*/ {
9137
	var d = [];
9138
	if(!data) return d;
9139
	var i = 1;
9140
	(data.match(tagregex)||[]).forEach(function(x) {
9141
		var y = parsexmltag(x);
9142
		switch(y[0]) {
9143
			case '<?xml': break;
9144
			/* 18.6.2  calcChain CT_CalcChain 1 */
9145
			case '<calcChain': case '<calcChain>': case '</calcChain>': break;
9146
			/* 18.6.1  c CT_CalcCell 1 */
9147
			case '<c': delete y[0]; if(y.i) i = y.i; else y.i = i; d.push(y); break;
9148
		}
9149
	});
9150
	return d;
9151
}
9152
9153
//function write_cc_xml(data, opts) { }
9154
9155
/* [MS-XLSB] 2.6.4.1 */
9156
function parse_BrtCalcChainItem$(data) {
9157
	var out = {};
9158
	out.i = data.read_shift(4);
9159
	var cell = {};
9160
	cell.r = data.read_shift(4);
9161
	cell.c = data.read_shift(4);
9162
	out.r = encode_cell(cell);
9163
	var flags = data.read_shift(1);
9164
	if(flags & 0x2) out.l = '1';
9165
	if(flags & 0x8) out.a = '1';
9166
	return out;
9167
}
9168
9169
/* 18.6 Calculation Chain */
9170
function parse_cc_bin(data, name, opts) {
9171
	var out = [];
9172
	var pass = false;
9173
	recordhopper(data, function hopper_cc(val, R_n, RT) {
9174
		switch(RT) {
9175
			case 0x003F: /* 'BrtCalcChainItem$' */
9176
				out.push(val); break;
9177
9178
			default:
9179
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
9180
				else if((R_n||"").indexOf("End") > 0){/* empty */}
9181
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9182
		}
9183
	});
9184
	return out;
9185
}
9186
9187
//function write_cc_bin(data, opts) { }
9188
/* 18.14 Supplementary Workbook Data */
9189
function parse_xlink_xml(/*::data, name:string, _opts*/) {
9190
	//var opts = _opts || {};
9191
	//if(opts.WTF) throw "XLSX External Link";
9192
}
9193
9194
/* [MS-XLSB] 2.1.7.25 External Link */
9195
function parse_xlink_bin(data, name/*:string*/, _opts) {
9196
	if(!data) return data;
9197
	var opts = _opts || {};
9198
9199
	var pass = false, end = false;
9200
9201
	recordhopper(data, function xlink_parse(val, R_n, RT) {
9202
		if(end) return;
9203
		switch(RT) {
9204
			case 0x0167: /* 'BrtSupTabs' */
9205
			case 0x016B: /* 'BrtExternTableStart' */
9206
			case 0x016C: /* 'BrtExternTableEnd' */
9207
			case 0x016E: /* 'BrtExternRowHdr' */
9208
			case 0x016F: /* 'BrtExternCellBlank' */
9209
			case 0x0170: /* 'BrtExternCellReal' */
9210
			case 0x0171: /* 'BrtExternCellBool' */
9211
			case 0x0172: /* 'BrtExternCellError' */
9212
			case 0x0173: /* 'BrtExternCellString' */
9213
			case 0x01D8: /* 'BrtExternValueMeta' */
9214
			case 0x0241: /* 'BrtSupNameStart' */
9215
			case 0x0242: /* 'BrtSupNameValueStart' */
9216
			case 0x0243: /* 'BrtSupNameValueEnd' */
9217
			case 0x0244: /* 'BrtSupNameNum' */
9218
			case 0x0245: /* 'BrtSupNameErr' */
9219
			case 0x0246: /* 'BrtSupNameSt' */
9220
			case 0x0247: /* 'BrtSupNameNil' */
9221
			case 0x0248: /* 'BrtSupNameBool' */
9222
			case 0x0249: /* 'BrtSupNameFmla' */
9223
			case 0x024A: /* 'BrtSupNameBits' */
9224
			case 0x024B: /* 'BrtSupNameEnd' */
9225
				break;
9226
9227
			case 0x0023: /* 'BrtFRTBegin' */
9228
				pass = true; break;
9229
			case 0x0024: /* 'BrtFRTEnd' */
9230
				pass = false; break;
9231
9232
			default:
9233
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
9234
				else if((R_n||"").indexOf("End") > 0){/* empty */}
9235
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
9236
		}
9237
	}, opts);
9238
}
9239
RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
9240
RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
9241
/* 20.5 DrawingML - SpreadsheetML Drawing */
9242
function parse_drawing(data, rels/*:any*/) {
9243
	if(!data) return "??";
9244
	/*
9245
	  Chartsheet Drawing:
9246
	   - 20.5.2.35 wsDr CT_Drawing
9247
	    - 20.5.2.1  absoluteAnchor CT_AbsoluteAnchor
9248
	     - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
9249
	      - 20.1.2.2.16 graphic CT_GraphicalObject
9250
	       - 20.1.2.2.17 graphicData CT_GraphicalObjectData
9251
          - chart reference
9252
	   the actual type is based on the URI of the graphicData
9253
		TODO: handle embedded charts and other types of graphics
9254
	*/
9255
	var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
9256
9257
	return rels['!id'][id].Target;
9258
}
9259
9260
/* L.5.5.2 SpreadsheetML Comments + VML Schema */
9261
var _shapeid = 1024;
9262
function write_comments_vml(rId/*:number*/, comments) {
9263
	var csize = [21600, 21600];
9264
	/* L.5.2.1.2 Path Attribute */
9265
	var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
9266
	var o = [
9267
		writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
9268
		writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
9269
		writextag("v:shapetype", [
9270
			writextag("v:stroke", null, {joinstyle:"miter"}),
9271
			writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
9272
		].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
9273
	];
9274
	while(_shapeid < rId * 1000) _shapeid += 1000;
9275
9276
	comments.forEach(function(x) { var c = decode_cell(x[0]);
9277
	o = o.concat([
9278
	'<v:shape' + wxt_helper({
9279
		id:'_x0000_s' + (++_shapeid),
9280
		type:"#_x0000_t202",
9281
		style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
9282
		fillcolor:"#ECFAD4",
9283
		strokecolor:"#edeaa1"
9284
	}) + '>',
9285
		writextag('v:fill', writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}), {'color2':"#BEFF82", 'angle':"-180", 'type':"gradient"}),
9286
		writextag("v:shadow", null, {on:"t", 'obscured':"t"}),
9287
		writextag("v:path", null, {'o:connecttype':"none"}),
9288
		'<v:textbox><div style="text-align:left"></div></v:textbox>',
9289
		'<x:ClientData ObjectType="Note">',
9290
			'<x:MoveWithCells/>',
9291
			'<x:SizeWithCells/>',
9292
			/* Part 4 19.4.2.3 Anchor (Anchor) */
9293
			writetag('x:Anchor', [c.c, 0, c.r, 0, c.c+3, 100, c.r+5, 100].join(",")),
9294
			writetag('x:AutoFill', "False"),
9295
			writetag('x:Row', String(c.r)),
9296
			writetag('x:Column', String(c.c)),
9297
			x[1].hidden ? '' : '<x:Visible/>',
9298
		'</x:ClientData>',
9299
	'</v:shape>'
9300
	]); });
9301
	o.push('</xml>');
9302
	return o.join("");
9303
}
9304
9305
RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
9306
9307
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
9308
	for(var i = 0; i != dirComments.length; ++i) {
9309
		var canonicalpath=dirComments[i];
9310
		var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
9311
		if(!comments || !comments.length) continue;
9312
		// find the sheets targeted by these comments
9313
		var sheetNames = keys(sheets);
9314
		for(var j = 0; j != sheetNames.length; ++j) {
9315
			var sheetName = sheetNames[j];
9316
			var rels = sheetRels[sheetName];
9317
			if(rels) {
9318
				var rel = rels[canonicalpath];
9319
				if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
9320
			}
9321
		}
9322
	}
9323
}
9324
9325
function insertCommentsIntoSheet(sheetName, sheet, comments/*:Array<RawComment>*/) {
9326
	var dense = Array.isArray(sheet);
9327
	var cell/*:Cell*/, r;
9328
	comments.forEach(function(comment) {
9329
		if(dense) {
9330
			r = decode_cell(comment.ref);
9331
			if(!sheet[r.r]) sheet[r.r] = [];
9332
			cell = sheet[r.r][r.c];
9333
		} else cell = sheet[comment.ref];
9334
		if (!cell) {
9335
			cell = {};
9336
			if(dense) sheet[r.r][r.c] = cell;
9337
			else sheet[comment.ref] = cell;
9338
			var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
9339
			var thisCell = decode_cell(comment.ref);
9340
			if(range.s.r > thisCell.r) range.s.r = thisCell.r;
9341
			if(range.e.r < thisCell.r) range.e.r = thisCell.r;
9342
			if(range.s.c > thisCell.c) range.s.c = thisCell.c;
9343
			if(range.e.c < thisCell.c) range.e.c = thisCell.c;
9344
			var encoded = encode_range(range);
9345
			if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
9346
		}
9347
9348
		if (!cell.c) cell.c = [];
9349
		var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r});
9350
		if(comment.h) o.h = comment.h;
9351
		cell.c.push(o);
9352
	});
9353
}
9354
9355
/* 18.7 Comments */
9356
function parse_comments_xml(data/*:string*/, opts)/*:Array<RawComment>*/ {
9357
	/* 18.7.6 CT_Comments */
9358
	if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
9359
	var authors/*:Array<string>*/ = [];
9360
	var commentList/*:Array<RawComment>*/ = [];
9361
	var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
9362
	if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
9363
		if(x === "" || x.trim() === "") return;
9364
		var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
9365
		if(a) authors.push(a[1]);
9366
	});
9367
	var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
9368
	if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
9369
		if(x === "" || x.trim() === "") return;
9370
		var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
9371
		if(!cm) return;
9372
		var y = parsexmltag(cm[0]);
9373
		var comment/*:RawComment*/ = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/);
9374
		var cell = decode_cell(y.ref);
9375
		if(opts.sheetRows && opts.sheetRows <= cell.r) return;
9376
		var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
9377
		var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
9378
		comment.r = rt.r;
9379
		if(rt.r == "<t></t>") rt.t = rt.h = "";
9380
		comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
9381
		if(opts.cellHTML) comment.h = rt.h;
9382
		commentList.push(comment);
9383
	});
9384
	return commentList;
9385
}
9386
9387
var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
9388
function write_comments_xml(data/*::, opts*/) {
9389
	var o = [XML_HEADER, CMNT_XML_ROOT];
9390
9391
	var iauthor/*:Array<string>*/ = [];
9392
	o.push("<authors>");
9393
	data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
9394
		if(iauthor.indexOf(a) > -1) return;
9395
		iauthor.push(a);
9396
		o.push("<author>" + a + "</author>");
9397
	}); });
9398
	o.push("</authors>");
9399
	o.push("<commentList>");
9400
	data.forEach(function(d) {
9401
		d[1].forEach(function(c) {
9402
			/* 18.7.3 CT_Comment */
9403
			o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
9404
			o.push(writetag("t", c.t == null ? "" : c.t));
9405
			o.push('</text></comment>');
9406
		});
9407
	});
9408
	o.push("</commentList>");
9409
	if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
9410
	return o.join("");
9411
}
9412
/* [MS-XLSB] 2.4.28 BrtBeginComment */
9413
function parse_BrtBeginComment(data) {
9414
	var out = {};
9415
	out.iauthor = data.read_shift(4);
9416
	var rfx = parse_UncheckedRfX(data, 16);
9417
	out.rfx = rfx.s;
9418
	out.ref = encode_cell(rfx.s);
9419
	data.l += 16; /*var guid = parse_GUID(data); */
9420
	return out;
9421
}
9422
function write_BrtBeginComment(data, o) {
9423
	if(o == null) o = new_buf(36);
9424
	o.write_shift(4, data[1].iauthor);
9425
	write_UncheckedRfX((data[0]/*:any*/), o);
9426
	o.write_shift(4, 0);
9427
	o.write_shift(4, 0);
9428
	o.write_shift(4, 0);
9429
	o.write_shift(4, 0);
9430
	return o;
9431
}
9432
9433
/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
9434
var parse_BrtCommentAuthor = parse_XLWideString;
9435
function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
9436
9437
/* [MS-XLSB] 2.1.7.8 Comments */
9438
function parse_comments_bin(data, opts)/*:Array<RawComment>*/ {
9439
	var out/*:Array<RawComment>*/ = [];
9440
	var authors/*:Array<string>*/ = [];
9441
	var c = {};
9442
	var pass = false;
9443
	recordhopper(data, function hopper_cmnt(val, R_n, RT) {
9444
		switch(RT) {
9445
			case 0x0278: /* 'BrtCommentAuthor' */
9446
				authors.push(val); break;
9447
			case 0x027B: /* 'BrtBeginComment' */
9448
				c = val; break;
9449
			case 0x027D: /* 'BrtCommentText' */
9450
				c.t = val.t; c.h = val.h; c.r = val.r; break;
9451
			case 0x027C: /* 'BrtEndComment' */
9452
				c.author = authors[c.iauthor];
9453
				delete c.iauthor;
9454
				if(opts.sheetRows && opts.sheetRows <= c.rfx.r) break;
9455
				if(!c.t) c.t = "";
9456
				delete c.rfx; out.push(c); break;
9457
9458
			case 0x0C00: /* 'BrtUid' */
9459
				break;
9460
9461
			case 0x0023: /* 'BrtFRTBegin' */
9462
				pass = true; break;
9463
			case 0x0024: /* 'BrtFRTEnd' */
9464
				pass = false; break;
9465
			case 0x0025: /* 'BrtACBegin' */ break;
9466
			case 0x0026: /* 'BrtACEnd' */ break;
9467
9468
9469
			default:
9470
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
9471
				else if((R_n||"").indexOf("End") > 0){/* empty */}
9472
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9473
		}
9474
	});
9475
	return out;
9476
}
9477
9478
function write_comments_bin(data/*::, opts*/) {
9479
	var ba = buf_array();
9480
	var iauthor/*:Array<string>*/ = [];
9481
	write_record(ba, "BrtBeginComments");
9482
9483
	write_record(ba, "BrtBeginCommentAuthors");
9484
	data.forEach(function(comment) {
9485
		comment[1].forEach(function(c) {
9486
			if(iauthor.indexOf(c.a) > -1) return;
9487
			iauthor.push(c.a.slice(0,54));
9488
			write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a));
9489
		});
9490
	});
9491
	write_record(ba, "BrtEndCommentAuthors");
9492
9493
	write_record(ba, "BrtBeginCommentList");
9494
	data.forEach(function(comment) {
9495
		comment[1].forEach(function(c) {
9496
			c.iauthor = iauthor.indexOf(c.a);
9497
			var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
9498
			write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c]));
9499
			if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c));
9500
			write_record(ba, "BrtEndComment");
9501
			delete c.iauthor;
9502
		});
9503
	});
9504
	write_record(ba, "BrtEndCommentList");
9505
9506
	write_record(ba, "BrtEndComments");
9507
	return ba.end();
9508
}
9509
var CT_VBA = "application/vnd.ms-office.vbaProject";
9510
function make_vba_xls(cfb/*:CFBContainer*/) {
9511
	var newcfb = CFB.utils.cfb_new({root:"R"});
9512
	cfb.FullPaths.forEach(function(p, i) {
9513
		if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
9514
		var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
9515
		CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
9516
	});
9517
	return CFB.write(newcfb);
9518
}
9519
9520
function fill_vba_xls(cfb/*:CFBContainer*/, vba/*:CFBContainer*/)/*:void*/ {
9521
	vba.FullPaths.forEach(function(p, i) {
9522
		if(i == 0) return;
9523
		var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
9524
		if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
9525
	});
9526
}
9527
9528
var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
9529
9530
RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
9531
RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
9532
9533
/* macro and dialog sheet stubs */
9534
function parse_ds_bin(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'dialog'}; }
9535
function parse_ds_xml(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'dialog'}; }
9536
function parse_ms_bin(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'macro'}; }
9537
function parse_ms_xml(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'macro'}; }
9538
/* TODO: it will be useful to parse the function str */
9539
var rc_to_a1 = (function(){
9540
	var rcregex = /(^|[^A-Za-z])R(\[?)(-?\d+|)\]?C(\[?)(-?\d+|)\]?/g;
9541
	var rcbase/*:Cell*/ = ({r:0,c:0}/*:any*/);
9542
	function rcfunc($$,$1,$2,$3,$4,$5) {
9543
		var R = $3.length>0?parseInt($3,10)|0:0, C = $5.length>0?parseInt($5,10)|0:0;
9544
		if(C<0 && $4.length === 0) C=0;
9545
		var cRel = false, rRel = false;
9546
		if($4.length > 0 || $5.length == 0) cRel = true; if(cRel) C += rcbase.c; else --C;
9547
		if($2.length > 0 || $3.length == 0) rRel = true; if(rRel) R += rcbase.r; else --R;
9548
		return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
9549
	}
9550
	return function rc_to_a1(fstr/*:string*/, base/*:Cell*/)/*:string*/ {
9551
		rcbase = base;
9552
		return fstr.replace(rcregex, rcfunc);
9553
	};
9554
})();
9555
9556
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)([1-9]\d{0,5}|10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6])(?![_.\(A-Za-z0-9])/g;
9557
var a1_to_rc =(function(){
9558
	return function a1_to_rc(fstr/*:string*/, base/*:CellAddress*/) {
9559
		return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
9560
			var c = decode_col($3) - ($2 ? 0 : base.c);
9561
			var r = decode_row($5) - ($4 ? 0 : base.r);
9562
			var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
9563
			var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
9564
			return $1 + "R" + R + "C" + C;
9565
		});
9566
	};
9567
})();
9568
9569
/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
9570
function shift_formula_str(f/*:string*/, delta/*:Cell*/)/*:string*/ {
9571
	return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
9572
		return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
9573
	});
9574
}
9575
9576
function shift_formula_xlsx(f/*:string*/, range/*:string*/, cell/*:string*/)/*:string*/ {
9577
	var r = decode_range(range), s = r.s, c = decode_cell(cell);
9578
	var delta = {r:c.r - s.r, c:c.c - s.c};
9579
	return shift_formula_str(f, delta);
9580
}
9581
9582
/* TODO: parse formula */
9583
function fuzzyfmla(f/*:string*/)/*:boolean*/ {
9584
	if(f.length == 1) return false;
9585
	return true;
9586
}
9587
9588
function _xlfn(f/*:string*/)/*:string*/ {
9589
	return f.replace(/_xlfn\./g,"");
9590
}
9591
function parseread1(blob) { blob.l+=1; return; }
9592
9593
/* [MS-XLS] 2.5.51 */
9594
function parse_ColRelU(blob, length) {
9595
	var c = blob.read_shift(length == 1 ? 1 : 2);
9596
	return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
9597
}
9598
9599
/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.89 */
9600
function parse_RgceArea(blob, length, opts) {
9601
	var w = 2;
9602
	if(opts) {
9603
		if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts);
9604
		else if(opts.biff == 12) w = 4;
9605
	}
9606
	var r=blob.read_shift(w), R=blob.read_shift(w);
9607
	var c=parse_ColRelU(blob, 2);
9608
	var C=parse_ColRelU(blob, 2);
9609
	return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
9610
}
9611
/* BIFF 2-5 encodes flags in the row field */
9612
function parse_RgceArea_BIFF2(blob/*::, length, opts*/) {
9613
	var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
9614
	var c=blob.read_shift(1);
9615
	var C=blob.read_shift(1);
9616
	return { s:{r:r[0], c:c, cRel:r[1], rRel:r[2]}, e:{r:R[0], c:C, cRel:R[1], rRel:R[2]} };
9617
}
9618
9619
/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.90 */
9620
function parse_RgceAreaRel(blob, length, opts) {
9621
	if(opts.biff < 8) return parse_RgceArea_BIFF2(blob, length, opts);
9622
	var r=blob.read_shift(opts.biff == 12 ? 4 : 2), R=blob.read_shift(opts.biff == 12 ? 4 : 2);
9623
	var c=parse_ColRelU(blob, 2);
9624
	var C=parse_ColRelU(blob, 2);
9625
	return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
9626
}
9627
9628
/* [MS-XLS] 2.5.198.109 ; [MS-XLSB] 2.5.97.91 */
9629
function parse_RgceLoc(blob, length, opts) {
9630
	if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts);
9631
	var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2);
9632
	var c = parse_ColRelU(blob, 2);
9633
	return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
9634
}
9635
function parse_RgceLoc_BIFF2(blob/*::, length, opts*/) {
9636
	var r = parse_ColRelU(blob, 2);
9637
	var c = blob.read_shift(1);
9638
	return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
9639
}
9640
9641
/* [MS-XLS] 2.5.198.107, 2.5.47 */
9642
function parse_RgceElfLoc(blob/*::, length, opts*/) {
9643
	var r = blob.read_shift(2);
9644
	var c = blob.read_shift(2);
9645
	return {r:r, c:c & 0xFF, fQuoted:!!(c & 0x4000), cRel:c>>15, rRel:c>>15 };
9646
}
9647
9648
/* [MS-XLS] 2.5.198.111 ; [MS-XLSB] 2.5.97.92 TODO */
9649
function parse_RgceLocRel(blob, length, opts) {
9650
	var biff = opts && opts.biff ? opts.biff : 8;
9651
	if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts);
9652
	var r = blob.read_shift(biff >= 12 ? 4 : 2);
9653
	var cl = blob.read_shift(2);
9654
	var cRel = (cl & 0x4000) >> 14, rRel = (cl & 0x8000) >> 15;
9655
	cl &= 0x3FFF;
9656
	if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000;
9657
	if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000;
9658
	return {r:r,c:cl,cRel:cRel,rRel:rRel};
9659
}
9660
function parse_RgceLocRel_BIFF2(blob/*::, length:number, opts*/) {
9661
	var rl = blob.read_shift(2);
9662
	var c = blob.read_shift(1);
9663
	var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14;
9664
	rl &= 0x3FFF;
9665
	if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000;
9666
	if(cRel == 1 && c >= 0x80) c = c - 0x100;
9667
	return {r:rl,c:c,cRel:cRel,rRel:rRel};
9668
}
9669
9670
/* [MS-XLS] 2.5.198.27 ; [MS-XLSB] 2.5.97.18 */
9671
function parse_PtgArea(blob, length, opts) {
9672
	var type = (blob[blob.l++] & 0x60) >> 5;
9673
	var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
9674
	return [type, area];
9675
}
9676
9677
/* [MS-XLS] 2.5.198.28 ; [MS-XLSB] 2.5.97.19 */
9678
function parse_PtgArea3d(blob, length, opts) {
9679
	var type = (blob[blob.l++] & 0x60) >> 5;
9680
	var ixti = blob.read_shift(2, 'i');
9681
	var w = 8;
9682
	if(opts) switch(opts.biff) {
9683
		case 5: blob.l += 12; w = 6; break;
9684
		case 12: w = 12; break;
9685
	}
9686
	var area = parse_RgceArea(blob, w, opts);
9687
	return [type, ixti, area];
9688
}
9689
9690
/* [MS-XLS] 2.5.198.29 ; [MS-XLSB] 2.5.97.20 */
9691
function parse_PtgAreaErr(blob, length, opts) {
9692
	var type = (blob[blob.l++] & 0x60) >> 5;
9693
	blob.l += opts && (opts.biff > 8) ? 12 : (opts.biff < 8 ? 6 : 8);
9694
	return [type];
9695
}
9696
/* [MS-XLS] 2.5.198.30 ; [MS-XLSB] 2.5.97.21 */
9697
function parse_PtgAreaErr3d(blob, length, opts) {
9698
	var type = (blob[blob.l++] & 0x60) >> 5;
9699
	var ixti = blob.read_shift(2);
9700
	var w = 8;
9701
	if(opts) switch(opts.biff) {
9702
		case 5: blob.l += 12; w = 6; break;
9703
		case 12: w = 12; break;
9704
	}
9705
	blob.l += w;
9706
	return [type, ixti];
9707
}
9708
9709
/* [MS-XLS] 2.5.198.31 ; [MS-XLSB] 2.5.97.22 */
9710
function parse_PtgAreaN(blob, length, opts) {
9711
	var type = (blob[blob.l++] & 0x60) >> 5;
9712
	var area = parse_RgceAreaRel(blob, length - 1, opts);
9713
	return [type, area];
9714
}
9715
9716
/* [MS-XLS] 2.5.198.32 ; [MS-XLSB] 2.5.97.23 */
9717
function parse_PtgArray(blob, length, opts) {
9718
	var type = (blob[blob.l++] & 0x60) >> 5;
9719
	blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
9720
	return [type];
9721
}
9722
9723
/* [MS-XLS] 2.5.198.33 ; [MS-XLSB] 2.5.97.24 */
9724
function parse_PtgAttrBaxcel(blob) {
9725
	var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
9726
	var bitBaxcel = 1;
9727
	blob.l += 4;
9728
	return [bitSemi, bitBaxcel];
9729
}
9730
9731
/* [MS-XLS] 2.5.198.34 ; [MS-XLSB] 2.5.97.25 */
9732
function parse_PtgAttrChoose(blob, length, opts)/*:Array<number>*/ {
9733
	blob.l +=2;
9734
	var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9735
	var o/*:Array<number>*/ = [];
9736
	/* offset is 1 less than the number of elements */
9737
	for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2));
9738
	return o;
9739
}
9740
9741
/* [MS-XLS] 2.5.198.35 ; [MS-XLSB] 2.5.97.26 */
9742
function parse_PtgAttrGoto(blob, length, opts) {
9743
	var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9744
	blob.l += 2;
9745
	return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
9746
}
9747
9748
/* [MS-XLS] 2.5.198.36 ; [MS-XLSB] 2.5.97.27 */
9749
function parse_PtgAttrIf(blob, length, opts) {
9750
	var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9751
	blob.l += 2;
9752
	return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
9753
}
9754
9755
/* [MS-XLSB] 2.5.97.28 */
9756
function parse_PtgAttrIfError(blob) {
9757
	var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9758
	blob.l += 2;
9759
	return [bitIf, blob.read_shift(2)];
9760
}
9761
9762
/* [MS-XLS] 2.5.198.37 ; [MS-XLSB] 2.5.97.29 */
9763
function parse_PtgAttrSemi(blob, length, opts) {
9764
	var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9765
	blob.l += opts && opts.biff == 2 ? 3 : 4;
9766
	return [bitSemi];
9767
}
9768
9769
/* [MS-XLS] 2.5.198.40 ; [MS-XLSB] 2.5.97.32 */
9770
function parse_PtgAttrSpaceType(blob/*::, length*/) {
9771
	var type = blob.read_shift(1), cch = blob.read_shift(1);
9772
	return [type, cch];
9773
}
9774
9775
/* [MS-XLS] 2.5.198.38 ; [MS-XLSB] 2.5.97.30 */
9776
function parse_PtgAttrSpace(blob) {
9777
	blob.read_shift(2);
9778
	return parse_PtgAttrSpaceType(blob, 2);
9779
}
9780
9781
/* [MS-XLS] 2.5.198.39 ; [MS-XLSB] 2.5.97.31 */
9782
function parse_PtgAttrSpaceSemi(blob) {
9783
	blob.read_shift(2);
9784
	return parse_PtgAttrSpaceType(blob, 2);
9785
}
9786
9787
/* [MS-XLS] 2.5.198.84 ; [MS-XLSB] 2.5.97.68 TODO */
9788
function parse_PtgRef(blob, length, opts) {
9789
	//var ptg = blob[blob.l] & 0x1F;
9790
	var type = (blob[blob.l] & 0x60)>>5;
9791
	blob.l += 1;
9792
	var loc = parse_RgceLoc(blob, 0, opts);
9793
	return [type, loc];
9794
}
9795
9796
/* [MS-XLS] 2.5.198.88 ; [MS-XLSB] 2.5.97.72 TODO */
9797
function parse_PtgRefN(blob, length, opts) {
9798
	var type = (blob[blob.l] & 0x60)>>5;
9799
	blob.l += 1;
9800
	var loc = parse_RgceLocRel(blob, 0, opts);
9801
	return [type, loc];
9802
}
9803
9804
/* [MS-XLS] 2.5.198.85 ; [MS-XLSB] 2.5.97.69 TODO */
9805
function parse_PtgRef3d(blob, length, opts) {
9806
	var type = (blob[blob.l] & 0x60)>>5;
9807
	blob.l += 1;
9808
	var ixti = blob.read_shift(2); // XtiIndex
9809
	if(opts && opts.biff == 5) blob.l += 12;
9810
	var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
9811
	return [type, ixti, loc];
9812
}
9813
9814
9815
/* [MS-XLS] 2.5.198.62 ; [MS-XLSB] 2.5.97.45 TODO */
9816
function parse_PtgFunc(blob, length, opts) {
9817
	//var ptg = blob[blob.l] & 0x1F;
9818
	var type = (blob[blob.l] & 0x60)>>5;
9819
	blob.l += 1;
9820
	var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
9821
	return [FtabArgc[iftab], Ftab[iftab], type];
9822
}
9823
/* [MS-XLS] 2.5.198.63 ; [MS-XLSB] 2.5.97.46 TODO */
9824
function parse_PtgFuncVar(blob, length, opts) {
9825
	var type = blob[blob.l++];
9826
	var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [(type == 0x58 ? -1 : 0), blob.read_shift(1)]: parsetab(blob);
9827
	return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
9828
}
9829
9830
function parsetab(blob) {
9831
	return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
9832
}
9833
9834
/* [MS-XLS] 2.5.198.41 ; [MS-XLSB] 2.5.97.33 */
9835
function parse_PtgAttrSum(blob, length, opts) {
9836
	blob.l += opts && opts.biff == 2 ? 3 : 4; return;
9837
}
9838
9839
/* [MS-XLS] 2.5.198.58 ; [MS-XLSB] 2.5.97.40 */
9840
function parse_PtgExp(blob, length, opts) {
9841
	blob.l++;
9842
	if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
9843
	var row = blob.read_shift(2);
9844
	var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9845
	return [row, col];
9846
}
9847
9848
/* [MS-XLS] 2.5.198.57 ; [MS-XLSB] 2.5.97.39 */
9849
function parse_PtgErr(blob) { blob.l++; return BErr[blob.read_shift(1)]; }
9850
9851
/* [MS-XLS] 2.5.198.66 ; [MS-XLSB] 2.5.97.49 */
9852
function parse_PtgInt(blob) { blob.l++; return blob.read_shift(2); }
9853
9854
/* [MS-XLS] 2.5.198.42 ; [MS-XLSB] 2.5.97.34 */
9855
function parse_PtgBool(blob) { blob.l++; return blob.read_shift(1)!==0;}
9856
9857
/* [MS-XLS] 2.5.198.79 ; [MS-XLSB] 2.5.97.63 */
9858
function parse_PtgNum(blob) { blob.l++; return parse_Xnum(blob, 8); }
9859
9860
/* [MS-XLS] 2.5.198.89 ; [MS-XLSB] 2.5.97.74 */
9861
function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
9862
9863
/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
9864
/* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */
9865
function parse_SerAr(blob, biff/*:number*/) {
9866
	var val = [blob.read_shift(1)];
9867
	if(biff == 12) switch(val[0]) {
9868
		case 0x02: val[0] = 0x04; break; /* SerBool */
9869
		case 0x04: val[0] = 0x10; break; /* SerErr */
9870
		case 0x00: val[0] = 0x01; break; /* SerNum */
9871
		case 0x01: val[0] = 0x02; break; /* SerStr */
9872
	}
9873
	switch(val[0]) {
9874
		case 0x04: /* SerBool -- boolean */
9875
			val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
9876
			if(biff != 12) blob.l += 7; break;
9877
		case 0x25: /* appears to be an alias */
9878
		case 0x10: /* SerErr -- error */
9879
			val[1] = BErr[blob[blob.l]];
9880
			blob.l += ((biff == 12) ? 4 : 8); break;
9881
		case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
9882
			blob.l += 8; break;
9883
		case 0x01: /* SerNum -- Xnum */
9884
			val[1] = parse_Xnum(blob, 8); break;
9885
		case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
9886
			val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
9887
		default: throw new Error("Bad SerAr: " + val[0]); /* Unreachable */
9888
	}
9889
	return val;
9890
}
9891
9892
/* [MS-XLS] 2.5.198.61 ; [MS-XLSB] 2.5.97.44 */
9893
function parse_PtgExtraMem(blob, cce, opts) {
9894
	var count = blob.read_shift((opts.biff == 12) ? 4 : 2);
9895
	var out/*:Array<Range>*/ = [];
9896
	for(var i = 0; i != count; ++i) out.push(((opts.biff == 12) ? parse_UncheckedRfX : parse_Ref8U)(blob, 8));
9897
	return out;
9898
}
9899
9900
/* [MS-XLS] 2.5.198.59 ; [MS-XLSB] 2.5.97.41 */
9901
function parse_PtgExtraArray(blob, length, opts) {
9902
	var rows = 0, cols = 0;
9903
	if(opts.biff == 12) {
9904
		rows = blob.read_shift(4); // DRw
9905
		cols = blob.read_shift(4); // DCol
9906
	} else {
9907
		cols = 1 + blob.read_shift(1); //DColByteU
9908
		rows = 1 + blob.read_shift(2); //DRw
9909
	}
9910
	if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; }
9911
	// $FlowIgnore
9912
	for(var i = 0, o/*:Array<Array<any>>*/ = []; i != rows && (o[i] = []); ++i)
9913
		for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff);
9914
	return o;
9915
}
9916
9917
/* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 */
9918
function parse_PtgName(blob, length, opts) {
9919
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9920
	var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
9921
	var nameindex = blob.read_shift(w);
9922
	switch(opts.biff) {
9923
		case 2: blob.l += 5; break;
9924
		case 3: case 4: blob.l += 8; break;
9925
		case 5: blob.l += 12; break;
9926
	}
9927
	return [type, 0, nameindex];
9928
}
9929
9930
/* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 */
9931
function parse_PtgNameX(blob, length, opts) {
9932
	if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts);
9933
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9934
	var ixti = blob.read_shift(2); // XtiIndex
9935
	var nameindex = blob.read_shift(4);
9936
	return [type, ixti, nameindex];
9937
}
9938
function parse_PtgNameX_BIFF5(blob/*::, length, opts*/) {
9939
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9940
	var ixti = blob.read_shift(2, 'i'); // XtiIndex
9941
	blob.l += 8;
9942
	var nameindex = blob.read_shift(2);
9943
	blob.l += 12;
9944
	return [type, ixti, nameindex];
9945
}
9946
9947
/* [MS-XLS] 2.5.198.70 ; [MS-XLSB] 2.5.97.54 */
9948
function parse_PtgMemArea(blob, length, opts) {
9949
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9950
	blob.l += (opts && opts.biff == 2 ? 3 : 4);
9951
	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9952
	return [type, cce];
9953
}
9954
9955
/* [MS-XLS] 2.5.198.72 ; [MS-XLSB] 2.5.97.56 */
9956
function parse_PtgMemFunc(blob, length, opts) {
9957
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9958
	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9959
	return [type, cce];
9960
}
9961
9962
9963
/* [MS-XLS] 2.5.198.86 ; [MS-XLSB] 2.5.97.69 */
9964
function parse_PtgRefErr(blob, length, opts) {
9965
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9966
	blob.l += 4;
9967
	if(opts.biff < 8) blob.l--;
9968
	if(opts.biff == 12) blob.l += 2;
9969
	return [type];
9970
}
9971
9972
/* [MS-XLS] 2.5.198.87 ; [MS-XLSB] 2.5.97.71 */
9973
function parse_PtgRefErr3d(blob, length, opts) {
9974
	var type = (blob[blob.l++] & 0x60) >> 5;
9975
	var ixti = blob.read_shift(2);
9976
	var w = 4;
9977
	if(opts) switch(opts.biff) {
9978
		case 5: w = 15; break;
9979
		case 12: w = 6; break;
9980
	}
9981
	blob.l += w;
9982
	return [type, ixti];
9983
}
9984
9985
/* [MS-XLS] 2.5.198.71 ; [MS-XLSB] 2.5.97.55 */
9986
var parse_PtgMemErr = parsenoop;
9987
/* [MS-XLS] 2.5.198.73  ; [MS-XLSB] 2.5.97.57 */
9988
var parse_PtgMemNoMem = parsenoop;
9989
/* [MS-XLS] 2.5.198.92 */
9990
var parse_PtgTbl = parsenoop;
9991
9992
function parse_PtgElfLoc(blob, length, opts) {
9993
	blob.l += 2;
9994
	return [parse_RgceElfLoc(blob, 4, opts)];
9995
}
9996
function parse_PtgElfNoop(blob/*::, length, opts*/) {
9997
	blob.l += 6;
9998
	return [];
9999
}
10000
/* [MS-XLS] 2.5.198.46 */
10001
var parse_PtgElfCol = parse_PtgElfLoc;
10002
/* [MS-XLS] 2.5.198.47 */
10003
var parse_PtgElfColS = parse_PtgElfNoop;
10004
/* [MS-XLS] 2.5.198.48 */
10005
var parse_PtgElfColSV = parse_PtgElfNoop;
10006
/* [MS-XLS] 2.5.198.49 */
10007
var parse_PtgElfColV = parse_PtgElfLoc;
10008
/* [MS-XLS] 2.5.198.50 */
10009
function parse_PtgElfLel(blob/*::, length, opts*/) {
10010
	blob.l += 2;
10011
	return [parseuint16(blob), blob.read_shift(2) & 0x01];
10012
}
10013
/* [MS-XLS] 2.5.198.51 */
10014
var parse_PtgElfRadical = parse_PtgElfLoc;
10015
/* [MS-XLS] 2.5.198.52 */
10016
var parse_PtgElfRadicalLel = parse_PtgElfLel;
10017
/* [MS-XLS] 2.5.198.53 */
10018
var parse_PtgElfRadicalS = parse_PtgElfNoop;
10019
/* [MS-XLS] 2.5.198.54 */
10020
var parse_PtgElfRw = parse_PtgElfLoc;
10021
/* [MS-XLS] 2.5.198.55 */
10022
var parse_PtgElfRwV = parse_PtgElfLoc;
10023
10024
/* [MS-XLSB] 2.5.97.52 TODO */
10025
var PtgListRT = [
10026
	"Data",
10027
	"All",
10028
	"Headers",
10029
	"??",
10030
	"?Data2",
10031
	"??",
10032
	"?DataHeaders",
10033
	"??",
10034
	"Totals",
10035
	"??",
10036
	"??",
10037
	"??",
10038
	"?DataTotals",
10039
	"??",
10040
	"??",
10041
	"??",
10042
	"?Current"
10043
];
10044
function parse_PtgList(blob/*::, length, opts*/) {
10045
	blob.l += 2;
10046
	var ixti = blob.read_shift(2);
10047
	var flags = blob.read_shift(2);
10048
	var idx = blob.read_shift(4);
10049
	var c = blob.read_shift(2);
10050
	var C = blob.read_shift(2);
10051
	var rt = PtgListRT[(flags >> 2) & 0x1F];
10052
	return {ixti: ixti, coltype:(flags&0x3), rt:rt, idx:idx, c:c, C:C};
10053
}
10054
/* [MS-XLS] 2.5.198.91 ; [MS-XLSB] 2.5.97.76 */
10055
function parse_PtgSxName(blob/*::, length, opts*/) {
10056
	blob.l += 2;
10057
	return [blob.read_shift(4)];
10058
}
10059
10060
/* [XLS] old spec */
10061
function parse_PtgSheet(blob, length, opts) {
10062
	blob.l += 5;
10063
	blob.l += 2;
10064
	blob.l += (opts.biff == 2 ? 1 : 4);
10065
	return ["PTGSHEET"];
10066
}
10067
function parse_PtgEndSheet(blob, length, opts) {
10068
	blob.l += (opts.biff == 2 ? 4 : 5);
10069
	return ["PTGENDSHEET"];
10070
}
10071
function parse_PtgMemAreaN(blob/*::, length, opts*/) {
10072
	var type = (blob.read_shift(1) >>> 5) & 0x03;
10073
	var cce = blob.read_shift(2);
10074
	return [type, cce];
10075
}
10076
function parse_PtgMemNoMemN(blob/*::, length, opts*/) {
10077
	var type = (blob.read_shift(1) >>> 5) & 0x03;
10078
	var cce = blob.read_shift(2);
10079
	return [type, cce];
10080
}
10081
function parse_PtgAttrNoop(blob/*::, length, opts*/) {
10082
	blob.l += 4;
10083
	return [0, 0];
10084
}
10085
10086
/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
10087
var PtgTypes = {
10088
	/*::[*/0x01/*::]*/: { n:'PtgExp', f:parse_PtgExp },
10089
	/*::[*/0x02/*::]*/: { n:'PtgTbl', f:parse_PtgTbl },
10090
	/*::[*/0x03/*::]*/: { n:'PtgAdd', f:parseread1 },
10091
	/*::[*/0x04/*::]*/: { n:'PtgSub', f:parseread1 },
10092
	/*::[*/0x05/*::]*/: { n:'PtgMul', f:parseread1 },
10093
	/*::[*/0x06/*::]*/: { n:'PtgDiv', f:parseread1 },
10094
	/*::[*/0x07/*::]*/: { n:'PtgPower', f:parseread1 },
10095
	/*::[*/0x08/*::]*/: { n:'PtgConcat', f:parseread1 },
10096
	/*::[*/0x09/*::]*/: { n:'PtgLt', f:parseread1 },
10097
	/*::[*/0x0A/*::]*/: { n:'PtgLe', f:parseread1 },
10098
	/*::[*/0x0B/*::]*/: { n:'PtgEq', f:parseread1 },
10099
	/*::[*/0x0C/*::]*/: { n:'PtgGe', f:parseread1 },
10100
	/*::[*/0x0D/*::]*/: { n:'PtgGt', f:parseread1 },
10101
	/*::[*/0x0E/*::]*/: { n:'PtgNe', f:parseread1 },
10102
	/*::[*/0x0F/*::]*/: { n:'PtgIsect', f:parseread1 },
10103
	/*::[*/0x10/*::]*/: { n:'PtgUnion', f:parseread1 },
10104
	/*::[*/0x11/*::]*/: { n:'PtgRange', f:parseread1 },
10105
	/*::[*/0x12/*::]*/: { n:'PtgUplus', f:parseread1 },
10106
	/*::[*/0x13/*::]*/: { n:'PtgUminus', f:parseread1 },
10107
	/*::[*/0x14/*::]*/: { n:'PtgPercent', f:parseread1 },
10108
	/*::[*/0x15/*::]*/: { n:'PtgParen', f:parseread1 },
10109
	/*::[*/0x16/*::]*/: { n:'PtgMissArg', f:parseread1 },
10110
	/*::[*/0x17/*::]*/: { n:'PtgStr', f:parse_PtgStr },
10111
	/*::[*/0x1A/*::]*/: { n:'PtgSheet', f:parse_PtgSheet },
10112
	/*::[*/0x1B/*::]*/: { n:'PtgEndSheet', f:parse_PtgEndSheet },
10113
	/*::[*/0x1C/*::]*/: { n:'PtgErr', f:parse_PtgErr },
10114
	/*::[*/0x1D/*::]*/: { n:'PtgBool', f:parse_PtgBool },
10115
	/*::[*/0x1E/*::]*/: { n:'PtgInt', f:parse_PtgInt },
10116
	/*::[*/0x1F/*::]*/: { n:'PtgNum', f:parse_PtgNum },
10117
	/*::[*/0x20/*::]*/: { n:'PtgArray', f:parse_PtgArray },
10118
	/*::[*/0x21/*::]*/: { n:'PtgFunc', f:parse_PtgFunc },
10119
	/*::[*/0x22/*::]*/: { n:'PtgFuncVar', f:parse_PtgFuncVar },
10120
	/*::[*/0x23/*::]*/: { n:'PtgName', f:parse_PtgName },
10121
	/*::[*/0x24/*::]*/: { n:'PtgRef', f:parse_PtgRef },
10122
	/*::[*/0x25/*::]*/: { n:'PtgArea', f:parse_PtgArea },
10123
	/*::[*/0x26/*::]*/: { n:'PtgMemArea', f:parse_PtgMemArea },
10124
	/*::[*/0x27/*::]*/: { n:'PtgMemErr', f:parse_PtgMemErr },
10125
	/*::[*/0x28/*::]*/: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
10126
	/*::[*/0x29/*::]*/: { n:'PtgMemFunc', f:parse_PtgMemFunc },
10127
	/*::[*/0x2A/*::]*/: { n:'PtgRefErr', f:parse_PtgRefErr },
10128
	/*::[*/0x2B/*::]*/: { n:'PtgAreaErr', f:parse_PtgAreaErr },
10129
	/*::[*/0x2C/*::]*/: { n:'PtgRefN', f:parse_PtgRefN },
10130
	/*::[*/0x2D/*::]*/: { n:'PtgAreaN', f:parse_PtgAreaN },
10131
	/*::[*/0x2E/*::]*/: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
10132
	/*::[*/0x2F/*::]*/: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
10133
	/*::[*/0x39/*::]*/: { n:'PtgNameX', f:parse_PtgNameX },
10134
	/*::[*/0x3A/*::]*/: { n:'PtgRef3d', f:parse_PtgRef3d },
10135
	/*::[*/0x3B/*::]*/: { n:'PtgArea3d', f:parse_PtgArea3d },
10136
	/*::[*/0x3C/*::]*/: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
10137
	/*::[*/0x3D/*::]*/: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
10138
	/*::[*/0xFF/*::]*/: {}
10139
};
10140
/* These are duplicated in the PtgTypes table */
10141
var PtgDupes = {
10142
	/*::[*/0x40/*::]*/: 0x20, /*::[*/0x60/*::]*/: 0x20,
10143
	/*::[*/0x41/*::]*/: 0x21, /*::[*/0x61/*::]*/: 0x21,
10144
	/*::[*/0x42/*::]*/: 0x22, /*::[*/0x62/*::]*/: 0x22,
10145
	/*::[*/0x43/*::]*/: 0x23, /*::[*/0x63/*::]*/: 0x23,
10146
	/*::[*/0x44/*::]*/: 0x24, /*::[*/0x64/*::]*/: 0x24,
10147
	/*::[*/0x45/*::]*/: 0x25, /*::[*/0x65/*::]*/: 0x25,
10148
	/*::[*/0x46/*::]*/: 0x26, /*::[*/0x66/*::]*/: 0x26,
10149
	/*::[*/0x47/*::]*/: 0x27, /*::[*/0x67/*::]*/: 0x27,
10150
	/*::[*/0x48/*::]*/: 0x28, /*::[*/0x68/*::]*/: 0x28,
10151
	/*::[*/0x49/*::]*/: 0x29, /*::[*/0x69/*::]*/: 0x29,
10152
	/*::[*/0x4A/*::]*/: 0x2A, /*::[*/0x6A/*::]*/: 0x2A,
10153
	/*::[*/0x4B/*::]*/: 0x2B, /*::[*/0x6B/*::]*/: 0x2B,
10154
	/*::[*/0x4C/*::]*/: 0x2C, /*::[*/0x6C/*::]*/: 0x2C,
10155
	/*::[*/0x4D/*::]*/: 0x2D, /*::[*/0x6D/*::]*/: 0x2D,
10156
	/*::[*/0x4E/*::]*/: 0x2E, /*::[*/0x6E/*::]*/: 0x2E,
10157
	/*::[*/0x4F/*::]*/: 0x2F, /*::[*/0x6F/*::]*/: 0x2F,
10158
	/*::[*/0x58/*::]*/: 0x22, /*::[*/0x78/*::]*/: 0x22,
10159
	/*::[*/0x59/*::]*/: 0x39, /*::[*/0x79/*::]*/: 0x39,
10160
	/*::[*/0x5A/*::]*/: 0x3A, /*::[*/0x7A/*::]*/: 0x3A,
10161
	/*::[*/0x5B/*::]*/: 0x3B, /*::[*/0x7B/*::]*/: 0x3B,
10162
	/*::[*/0x5C/*::]*/: 0x3C, /*::[*/0x7C/*::]*/: 0x3C,
10163
	/*::[*/0x5D/*::]*/: 0x3D, /*::[*/0x7D/*::]*/: 0x3D
10164
};
10165
(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
10166
10167
var Ptg18 = {
10168
	/*::[*/0x01/*::]*/: { n:'PtgElfLel', f:parse_PtgElfLel },
10169
	/*::[*/0x02/*::]*/: { n:'PtgElfRw', f:parse_PtgElfRw },
10170
	/*::[*/0x03/*::]*/: { n:'PtgElfCol', f:parse_PtgElfCol },
10171
	/*::[*/0x06/*::]*/: { n:'PtgElfRwV', f:parse_PtgElfRwV },
10172
	/*::[*/0x07/*::]*/: { n:'PtgElfColV', f:parse_PtgElfColV },
10173
	/*::[*/0x0A/*::]*/: { n:'PtgElfRadical', f:parse_PtgElfRadical },
10174
	/*::[*/0x0B/*::]*/: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
10175
	/*::[*/0x0D/*::]*/: { n:'PtgElfColS', f:parse_PtgElfColS },
10176
	/*::[*/0x0F/*::]*/: { n:'PtgElfColSV', f:parse_PtgElfColSV },
10177
	/*::[*/0x10/*::]*/: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
10178
	/*::[*/0x19/*::]*/: { n:'PtgList', f:parse_PtgList },
10179
	/*::[*/0x1D/*::]*/: { n:'PtgSxName', f:parse_PtgSxName },
10180
	/*::[*/0xFF/*::]*/: {}
10181
};
10182
var Ptg19 = {
10183
	/*::[*/0x00/*::]*/: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
10184
	/*::[*/0x01/*::]*/: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
10185
	/*::[*/0x02/*::]*/: { n:'PtgAttrIf', f:parse_PtgAttrIf },
10186
	/*::[*/0x04/*::]*/: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
10187
	/*::[*/0x08/*::]*/: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
10188
	/*::[*/0x10/*::]*/: { n:'PtgAttrSum', f:parse_PtgAttrSum },
10189
	/*::[*/0x20/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
10190
	/*::[*/0x40/*::]*/: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
10191
	/*::[*/0x41/*::]*/: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
10192
	/*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
10193
	/*::[*/0xFF/*::]*/: {}
10194
};
10195
Ptg19[0x21] = Ptg19[0x20];
10196
10197
/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
10198
function parse_RgbExtra(blob, length, rgce, opts) {
10199
	if(opts.biff < 8) return parsenoop(blob, length);
10200
	var target = blob.l + length;
10201
	var o = [];
10202
	for(var i = 0; i !== rgce.length; ++i) {
10203
		switch(rgce[i][0]) {
10204
			case 'PtgArray': /* PtgArray -> PtgExtraArray */
10205
				rgce[i][1] = parse_PtgExtraArray(blob, 0, opts);
10206
				o.push(rgce[i][1]);
10207
				break;
10208
			case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
10209
				rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1], opts);
10210
				o.push(rgce[i][2]);
10211
				break;
10212
			case 'PtgExp': /* PtgExp -> PtgExtraCol */
10213
				if(opts && opts.biff == 12) {
10214
					rgce[i][1][1] = blob.read_shift(4);
10215
					o.push(rgce[i][1]);
10216
				} break;
10217
			case 'PtgList': /* TODO: PtgList -> PtgExtraList */
10218
			case 'PtgElfRadicalS': /* TODO: PtgElfRadicalS -> PtgExtraElf */
10219
			case 'PtgElfColS': /* TODO: PtgElfColS -> PtgExtraElf */
10220
			case 'PtgElfColSV': /* TODO: PtgElfColSV -> PtgExtraElf */
10221
				throw "Unsupported " + rgce[i][0];
10222
			default: break;
10223
		}
10224
	}
10225
	length = target - blob.l;
10226
	/* note: this is technically an error but Excel disregards */
10227
	//if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
10228
	if(length !== 0) o.push(parsenoop(blob, length));
10229
	return o;
10230
}
10231
10232
/* [MS-XLS] 2.5.198.104 ; [MS-XLSB] 2.5.97.88 */
10233
function parse_Rgce(blob, length, opts) {
10234
	var target = blob.l + length;
10235
	var R, id, ptgs = [];
10236
	while(target != blob.l) {
10237
		length = target - blob.l;
10238
		id = blob[blob.l];
10239
		R = PtgTypes[id];
10240
		if(id === 0x18 || id === 0x19) R = (id === 0x18 ? Ptg18 : Ptg19)[blob[blob.l + 1]];
10241
		if(!R || !R.f) { /*ptgs.push*/(parsenoop(blob, length)); }
10242
		else { ptgs.push([R.n, R.f(blob, length, opts)]); }
10243
	}
10244
	return ptgs;
10245
}
10246
10247
function stringify_array(f/*:Array<Array<string>>*/)/*:string*/ {
10248
	var o/*:Array<string>*/ = [];
10249
	for(var i = 0; i < f.length; ++i) {
10250
		var x = f[i], r/*:Array<string>*/ = [];
10251
		for(var j = 0; j < x.length; ++j) {
10252
			var y = x[j];
10253
			if(y) switch(y[0]) {
10254
				// TODO: handle embedded quotes
10255
				case 0x02:
10256
					/*:: if(typeof y[1] != 'string') throw "unreachable"; */
10257
					r.push('"' + y[1].replace(/"/g,'""') + '"'); break;
10258
				default: r.push(y[1]);
10259
			} else r.push("");
10260
		}
10261
		o.push(r.join(","));
10262
	}
10263
	return o.join(";");
10264
}
10265
10266
/* [MS-XLS] 2.2.2 ; [MS-XLSB] 2.2.2 TODO */
10267
var PtgBinOp = {
10268
	PtgAdd: "+",
10269
	PtgConcat: "&",
10270
	PtgDiv: "/",
10271
	PtgEq: "=",
10272
	PtgGe: ">=",
10273
	PtgGt: ">",
10274
	PtgLe: "<=",
10275
	PtgLt: "<",
10276
	PtgMul: "*",
10277
	PtgNe: "<>",
10278
	PtgPower: "^",
10279
	PtgSub: "-"
10280
};
10281
function formula_quote_sheet_name(sname/*:string*/, opts)/*:string*/ {
10282
	if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name");
10283
	if(sname.indexOf(" ") > -1) return "'" + sname + "'";
10284
	return sname;
10285
}
10286
function get_ixti_raw(supbooks, ixti/*:number*/, opts)/*:string*/ {
10287
	if(!supbooks) return "SH33TJSERR0";
10288
	if(!supbooks.XTI) return "SH33TJSERR6";
10289
	var XTI = supbooks.XTI[ixti];
10290
	if(opts.biff > 8 && !supbooks.XTI[ixti]) return supbooks.SheetNames[ixti];
10291
	if(opts.biff < 8) {
10292
		if(ixti > 10000) ixti-= 65536;
10293
		if(ixti < 0) ixti = -ixti;
10294
		return ixti == 0 ? "" : supbooks.XTI[ixti - 1];
10295
	}
10296
	if(!XTI) return "SH33TJSERR1";
10297
	var o = "";
10298
	if(opts.biff > 8) switch(supbooks[XTI[0]][0]) {
10299
		case 0x0165: /* 'BrtSupSelf' */
10300
			o = XTI[1] == -1 ? "#REF" : supbooks.SheetNames[XTI[1]];
10301
			return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
10302
		case 0x0166: /* 'BrtSupSame' */
10303
			if(opts.SID != null) return supbooks.SheetNames[opts.SID];
10304
			return "SH33TJSSAME" + supbooks[XTI[0]][0];
10305
		case 0x0163: /* 'BrtSupBookSrc' */
10306
			/* falls through */
10307
		default: return "SH33TJSSRC" + supbooks[XTI[0]][0];
10308
	}
10309
	switch(supbooks[XTI[0]][0][0]) {
10310
		case 0x0401:
10311
			o = XTI[1] == -1 ? "#REF" : (supbooks.SheetNames[XTI[1]] || "SH33TJSERR3");
10312
			return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
10313
		case 0x3A01: return "SH33TJSERR8";
10314
		default:
10315
			if(!supbooks[XTI[0]][0][3]) return "SH33TJSERR2";
10316
			o = XTI[1] == -1 ? "#REF" : (supbooks[XTI[0]][0][3][XTI[1]] || "SH33TJSERR4");
10317
			return XTI[1] == XTI[2] ? o : o + ":" + supbooks[XTI[0]][0][3][XTI[2]];
10318
	}
10319
}
10320
function get_ixti(supbooks, ixti/*:number*/, opts)/*:string*/ {
10321
	return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts), opts);
10322
}
10323
function stringify_formula(formula/*Array<any>*/, range, cell/*:any*/, supbooks, opts)/*:string*/ {
10324
	var biff = (opts && opts.biff) || 8;
10325
	var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
10326
	var stack/*:Array<string>*/ = [], e1, e2, /*::type,*/ c/*:CellAddress*/, ixti=0, nameidx=0, r, sname="";
10327
	if(!formula[0] || !formula[0][0]) return "";
10328
	var last_sp = -1, sp = "";
10329
	for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
10330
		var f = formula[0][ff];
10331
		switch(f[0]) {
10332
			case 'PtgUminus': /* [MS-XLS] 2.5.198.93 */
10333
				stack.push("-" + stack.pop()); break;
10334
			case 'PtgUplus': /* [MS-XLS] 2.5.198.95 */
10335
				stack.push("+" + stack.pop()); break;
10336
			case 'PtgPercent': /* [MS-XLS] 2.5.198.81 */
10337
				stack.push(stack.pop() + "%"); break;
10338
10339
			case 'PtgAdd':    /* [MS-XLS] 2.5.198.26 */
10340
			case 'PtgConcat': /* [MS-XLS] 2.5.198.43 */
10341
			case 'PtgDiv':    /* [MS-XLS] 2.5.198.45 */
10342
			case 'PtgEq':     /* [MS-XLS] 2.5.198.56 */
10343
			case 'PtgGe':     /* [MS-XLS] 2.5.198.64 */
10344
			case 'PtgGt':     /* [MS-XLS] 2.5.198.65 */
10345
			case 'PtgLe':     /* [MS-XLS] 2.5.198.68 */
10346
			case 'PtgLt':     /* [MS-XLS] 2.5.198.69 */
10347
			case 'PtgMul':    /* [MS-XLS] 2.5.198.75 */
10348
			case 'PtgNe':     /* [MS-XLS] 2.5.198.78 */
10349
			case 'PtgPower':  /* [MS-XLS] 2.5.198.82 */
10350
			case 'PtgSub':    /* [MS-XLS] 2.5.198.90 */
10351
				e1 = stack.pop(); e2 = stack.pop();
10352
				if(last_sp >= 0) {
10353
					switch(formula[0][last_sp][1][0]) {
10354
						case 0:
10355
							// $FlowIgnore
10356
							sp = fill(" ", formula[0][last_sp][1][1]); break;
10357
						case 1:
10358
							// $FlowIgnore
10359
							sp = fill("\r", formula[0][last_sp][1][1]); break;
10360
						default:
10361
							sp = "";
10362
							// $FlowIgnore
10363
							if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
10364
					}
10365
					e2 = e2 + sp;
10366
					last_sp = -1;
10367
				}
10368
				stack.push(e2+PtgBinOp[f[0]]+e1);
10369
				break;
10370
10371
			case 'PtgIsect': /* [MS-XLS] 2.5.198.67 */
10372
				e1 = stack.pop(); e2 = stack.pop();
10373
				stack.push(e2+" "+e1);
10374
				break;
10375
			case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
10376
				e1 = stack.pop(); e2 = stack.pop();
10377
				stack.push(e2+","+e1);
10378
				break;
10379
			case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
10380
				e1 = stack.pop(); e2 = stack.pop();
10381
				stack.push(e2+":"+e1);
10382
				break;
10383
10384
			case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */
10385
				break;
10386
			case 'PtgAttrGoto': /* [MS-XLS] 2.5.198.35 */
10387
				break;
10388
			case 'PtgAttrIf': /* [MS-XLS] 2.5.198.36 */
10389
				break;
10390
			case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
10391
				break;
10392
10393
10394
			case 'PtgRef': /* [MS-XLS] 2.5.198.84 */
10395
				/*::type = f[1][0]; */c = shift_cell_xls((f[1][1]/*:any*/), _range, opts);
10396
				stack.push(encode_cell_xls(c, biff));
10397
				break;
10398
			case 'PtgRefN': /* [MS-XLS] 2.5.198.88 */
10399
				/*::type = f[1][0]; */c = cell ? shift_cell_xls((f[1][1]/*:any*/), cell, opts) : (f[1][1]/*:any*/);
10400
				stack.push(encode_cell_xls(c, biff));
10401
				break;
10402
			case 'PtgRef3d': /* [MS-XLS] 2.5.198.85 */
10403
				/*::type = f[1][0]; */ixti = /*::Number(*/f[1][1]/*::)*/; c = shift_cell_xls((f[1][2]/*:any*/), _range, opts);
10404
				sname = get_ixti(supbooks, ixti, opts);
10405
				var w = sname; /* IE9 fails on defined names */ // eslint-disable-line no-unused-vars
10406
				stack.push(sname + "!" + encode_cell_xls(c, biff));
10407
				break;
10408
10409
			case 'PtgFunc': /* [MS-XLS] 2.5.198.62 */
10410
			case 'PtgFuncVar': /* [MS-XLS] 2.5.198.63 */
10411
				/* f[1] = [argc, func, type] */
10412
				var argc/*:number*/ = (f[1][0]/*:any*/), func/*:string*/ = (f[1][1]/*:any*/);
10413
				if(!argc) argc = 0;
10414
				argc &= 0x7F;
10415
				var args = argc == 0 ? [] : stack.slice(-argc);
10416
				stack.length -= argc;
10417
				if(func === 'User') func = args.shift();
10418
				stack.push(func + "(" + args.join(",") + ")");
10419
				break;
10420
10421
			case 'PtgBool': /* [MS-XLS] 2.5.198.42 */
10422
				stack.push(f[1] ? "TRUE" : "FALSE"); break;
10423
			case 'PtgInt': /* [MS-XLS] 2.5.198.66 */
10424
				stack.push(/*::String(*/f[1]/*::)*/); break;
10425
			case 'PtgNum': /* [MS-XLS] 2.5.198.79 TODO: precision? */
10426
				stack.push(String(f[1])); break;
10427
			case 'PtgStr': /* [MS-XLS] 2.5.198.89 */
10428
				// $FlowIgnore
10429
				stack.push('"' + f[1] + '"'); break;
10430
			case 'PtgErr': /* [MS-XLS] 2.5.198.57 */
10431
				stack.push(/*::String(*/f[1]/*::)*/); break;
10432
			case 'PtgAreaN': /* [MS-XLS] 2.5.198.31 TODO */
10433
				/*::type = f[1][0]; */r = shift_range_xls(f[1][1], cell ? {s:cell} : _range, opts);
10434
				stack.push(encode_range_xls((r/*:any*/), opts));
10435
				break;
10436
			case 'PtgArea': /* [MS-XLS] 2.5.198.27 TODO: fixed points */
10437
				/*::type = f[1][0]; */r = shift_range_xls(f[1][1], _range, opts);
10438
				stack.push(encode_range_xls((r/*:any*/), opts));
10439
				break;
10440
			case 'PtgArea3d': /* [MS-XLS] 2.5.198.28 TODO */
10441
				/*::type = f[1][0]; */ixti = /*::Number(*/f[1][1]/*::)*/; r = f[1][2];
10442
				sname = get_ixti(supbooks, ixti, opts);
10443
				stack.push(sname + "!" + encode_range_xls((r/*:any*/), opts));
10444
				break;
10445
			case 'PtgAttrSum': /* [MS-XLS] 2.5.198.41 */
10446
				stack.push("SUM(" + stack.pop() + ")");
10447
				break;
10448
10449
			case 'PtgAttrBaxcel': /* [MS-XLS] 2.5.198.33 */
10450
			case 'PtgAttrSemi': /* [MS-XLS] 2.5.198.37 */
10451
				break;
10452
10453
			case 'PtgName': /* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 TODO: revisions */
10454
				/* f[1] = type, 0, nameindex */
10455
				nameidx = (f[1][2]/*:any*/);
10456
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
10457
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
10458
				if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
10459
				stack.push(name);
10460
				break;
10461
10462
			case 'PtgNameX': /* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 TODO: revisions */
10463
				/* f[1] = type, ixti, nameindex */
10464
				var bookidx/*:number*/ = (f[1][1]/*:any*/); nameidx = (f[1][2]/*:any*/); var externbook;
10465
				/* TODO: Properly handle missing values */
10466
				if(opts.biff <= 5) {
10467
					if(bookidx < 0) bookidx = -bookidx;
10468
					if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
10469
				} else {
10470
					var o = "";
10471
					if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){/* empty */}
10472
					else if(((supbooks[bookidx]||[])[0]||[])[0] == 0x0401){
10473
						if(supbooks[bookidx][nameidx] && supbooks[bookidx][nameidx].itab > 0) {
10474
							o = supbooks.SheetNames[supbooks[bookidx][nameidx].itab-1] + "!";
10475
						}
10476
					}
10477
					else o = supbooks.SheetNames[nameidx-1]+ "!";
10478
					if(supbooks[bookidx] && supbooks[bookidx][nameidx]) o += supbooks[bookidx][nameidx].Name;
10479
					else if(supbooks[0] && supbooks[0][nameidx]) o += supbooks[0][nameidx].Name;
10480
					else o += "SH33TJSERRX";
10481
					stack.push(o);
10482
					break;
10483
				}
10484
				if(!externbook) externbook = {Name: "SH33TJSERRY"};
10485
				stack.push(externbook.Name);
10486
				break;
10487
10488
			case 'PtgParen': /* [MS-XLS] 2.5.198.80 */
10489
				var lp = '(', rp = ')';
10490
				if(last_sp >= 0) {
10491
					sp = "";
10492
					switch(formula[0][last_sp][1][0]) {
10493
						// $FlowIgnore
10494
						case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
10495
						// $FlowIgnore
10496
						case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
10497
						// $FlowIgnore
10498
						case 4: rp = fill(" ", formula[0][last_sp][1][1]) + rp; break;
10499
						// $FlowIgnore
10500
						case 5: rp = fill("\r", formula[0][last_sp][1][1]) + rp; break;
10501
						default:
10502
							// $FlowIgnore
10503
							if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
10504
					}
10505
					last_sp = -1;
10506
				}
10507
				stack.push(lp + stack.pop() + rp); break;
10508
10509
			case 'PtgRefErr': /* [MS-XLS] 2.5.198.86 */
10510
				stack.push('#REF!'); break;
10511
10512
			case 'PtgRefErr3d': /* [MS-XLS] 2.5.198.87 */
10513
				stack.push('#REF!'); break;
10514
10515
			case 'PtgExp': /* [MS-XLS] 2.5.198.58 TODO */
10516
				c = {c:(f[1][1]/*:any*/),r:(f[1][0]/*:any*/)};
10517
				var q = ({c: cell.c, r:cell.r}/*:any*/);
10518
				if(supbooks.sharedf[encode_cell(c)]) {
10519
					var parsedf = (supbooks.sharedf[encode_cell(c)]);
10520
					stack.push(stringify_formula(parsedf, _range, q, supbooks, opts));
10521
				}
10522
				else {
10523
					var fnd = false;
10524
					for(e1=0;e1!=supbooks.arrayf.length; ++e1) {
10525
						/* TODO: should be something like range_has */
10526
						e2 = supbooks.arrayf[e1];
10527
						if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
10528
						if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
10529
						stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
10530
						fnd = true;
10531
						break;
10532
					}
10533
					if(!fnd) stack.push(/*::String(*/f[1]/*::)*/);
10534
				}
10535
				break;
10536
10537
			case 'PtgArray': /* [MS-XLS] 2.5.198.32 TODO */
10538
				stack.push("{" + stringify_array(/*::(*/f[1]/*:: :any)*/) + "}");
10539
				break;
10540
10541
			case 'PtgMemArea': /* [MS-XLS] 2.5.198.70 TODO: confirm this is a non-display */
10542
				//stack.push("(" + f[2].map(encode_range).join(",") + ")");
10543
				break;
10544
10545
			case 'PtgAttrSpace': /* [MS-XLS] 2.5.198.38 */
10546
			case 'PtgAttrSpaceSemi': /* [MS-XLS] 2.5.198.39 */
10547
				last_sp = ff;
10548
				break;
10549
10550
			case 'PtgTbl': /* [MS-XLS] 2.5.198.92 TODO */
10551
				break;
10552
10553
			case 'PtgMemErr': /* [MS-XLS] 2.5.198.71 */
10554
				break;
10555
10556
			case 'PtgMissArg': /* [MS-XLS] 2.5.198.74 */
10557
				stack.push("");
10558
				break;
10559
10560
			case 'PtgAreaErr': /* [MS-XLS] 2.5.198.29 */
10561
				stack.push("#REF!"); break;
10562
10563
			case 'PtgAreaErr3d': /* [MS-XLS] 2.5.198.30 */
10564
				stack.push("#REF!"); break;
10565
10566
			case 'PtgList': /* [MS-XLSB] 2.5.97.52 */
10567
				// $FlowIgnore
10568
				stack.push("Table" + f[1].idx + "[#" + f[1].rt + "]");
10569
				break;
10570
10571
			case 'PtgMemAreaN':
10572
			case 'PtgMemNoMemN':
10573
			case 'PtgAttrNoop':
10574
			case 'PtgSheet':
10575
			case 'PtgEndSheet':
10576
				break;
10577
10578
			case 'PtgMemFunc': /* [MS-XLS] 2.5.198.72 TODO */
10579
				break;
10580
			case 'PtgMemNoMem': /* [MS-XLS] 2.5.198.73 TODO */
10581
				break;
10582
10583
			case 'PtgElfCol': /* [MS-XLS] 2.5.198.46 */
10584
			case 'PtgElfColS': /* [MS-XLS] 2.5.198.47 */
10585
			case 'PtgElfColSV': /* [MS-XLS] 2.5.198.48 */
10586
			case 'PtgElfColV': /* [MS-XLS] 2.5.198.49 */
10587
			case 'PtgElfLel': /* [MS-XLS] 2.5.198.50 */
10588
			case 'PtgElfRadical': /* [MS-XLS] 2.5.198.51 */
10589
			case 'PtgElfRadicalLel': /* [MS-XLS] 2.5.198.52 */
10590
			case 'PtgElfRadicalS': /* [MS-XLS] 2.5.198.53 */
10591
			case 'PtgElfRw': /* [MS-XLS] 2.5.198.54 */
10592
			case 'PtgElfRwV': /* [MS-XLS] 2.5.198.55 */
10593
				throw new Error("Unsupported ELFs");
10594
10595
			case 'PtgSxName': /* [MS-XLS] 2.5.198.91 TODO -- find a test case */
10596
				throw new Error('Unrecognized Formula Token: ' + String(f));
10597
			default: throw new Error('Unrecognized Formula Token: ' + String(f));
10598
		}
10599
		var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto'];
10600
		if(opts.biff != 3) if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) {
10601
			f = formula[0][last_sp];
10602
			var _left = true;
10603
			switch(f[1][0]) {
10604
				/* note: some bad XLSB files omit the PtgParen */
10605
				case 4: _left = false;
10606
				/* falls through */
10607
				case 0:
10608
					// $FlowIgnore
10609
					sp = fill(" ", f[1][1]); break;
10610
				case 5: _left = false;
10611
				/* falls through */
10612
				case 1:
10613
					// $FlowIgnore
10614
					sp = fill("\r", f[1][1]); break;
10615
				default:
10616
					sp = "";
10617
					// $FlowIgnore
10618
					if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + f[1][0]);
10619
			}
10620
			stack.push((_left ? sp : "") + stack.pop() + (_left ? "" : sp));
10621
			last_sp = -1;
10622
		}
10623
	}
10624
	if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
10625
	return stack[0];
10626
}
10627
10628
/* [MS-XLS] 2.5.198.1 TODO */
10629
function parse_ArrayParsedFormula(blob, length, opts/*::, ref*/) {
10630
	var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
10631
	var rgcb, cce = blob.read_shift(len); // length of rgce
10632
	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
10633
	var rgce = parse_Rgce(blob, cce, opts);
10634
	if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
10635
	blob.l = target;
10636
	return [rgce, rgcb];
10637
}
10638
10639
/* [MS-XLS] 2.5.198.3 TODO */
10640
function parse_XLSCellParsedFormula(blob, length, opts) {
10641
	var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
10642
	var rgcb, cce = blob.read_shift(len); // length of rgce
10643
	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
10644
	var rgce = parse_Rgce(blob, cce, opts);
10645
	if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
10646
	blob.l = target;
10647
	return [rgce, rgcb];
10648
}
10649
10650
/* [MS-XLS] 2.5.198.21 */
10651
function parse_NameParsedFormula(blob, length, opts, cce) {
10652
	var target = blob.l + length;
10653
	var rgce = parse_Rgce(blob, cce, opts);
10654
	var rgcb;
10655
	if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
10656
	return [rgce, rgcb];
10657
}
10658
10659
/* [MS-XLS] 2.5.198.118 TODO */
10660
function parse_SharedParsedFormula(blob, length, opts) {
10661
	var target = blob.l + length;
10662
	var rgcb, cce = blob.read_shift(2); // length of rgce
10663
	var rgce = parse_Rgce(blob, cce, opts);
10664
	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
10665
	if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
10666
	return [rgce, rgcb];
10667
}
10668
10669
/* [MS-XLS] 2.5.133 TODO: how to emit empty strings? */
10670
function parse_FormulaValue(blob/*::, length*/) {
10671
	var b;
10672
	if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
10673
	switch(blob[blob.l]) {
10674
		case 0x00: blob.l += 8; return ["String", 's'];
10675
		case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
10676
		case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
10677
		case 0x03: blob.l += 8; return ["",'s'];
10678
	}
10679
	return [];
10680
}
10681
10682
/* [MS-XLS] 2.4.127 TODO */
10683
function parse_Formula(blob, length, opts) {
10684
	var end = blob.l + length;
10685
	var cell = parse_XLSCell(blob, 6);
10686
	if(opts.biff == 2) ++blob.l;
10687
	var val = parse_FormulaValue(blob,8);
10688
	var flags = blob.read_shift(1);
10689
	if(opts.biff != 2) {
10690
		blob.read_shift(1);
10691
		if(opts.biff >= 5) {
10692
			/*var chn = */blob.read_shift(4);
10693
		}
10694
	}
10695
	var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
10696
	return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
10697
}
10698
10699
/* XLSB Parsed Formula records have the same shape */
10700
function parse_XLSBParsedFormula(data, length, opts) {
10701
	var cce = data.read_shift(4);
10702
	var rgce = parse_Rgce(data, cce, opts);
10703
	var cb = data.read_shift(4);
10704
	var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null;
10705
	return [rgce, rgcb];
10706
}
10707
10708
/* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */
10709
var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula;
10710
/* [MS-XLSB] 2.5.97.4 CellParsedFormula */
10711
var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula;
10712
/* [MS-XLSB] 2.5.97.12 NameParsedFormula */
10713
var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula;
10714
/* [MS-XLSB] 2.5.97.98 SharedParsedFormula */
10715
var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula;
10716
/* [MS-XLS] 2.5.198.4 */
10717
var Cetab = {
10718
	/*::[*/0x0000/*::]*/: 'BEEP',
10719
	/*::[*/0x0001/*::]*/: 'OPEN',
10720
	/*::[*/0x0002/*::]*/: 'OPEN.LINKS',
10721
	/*::[*/0x0003/*::]*/: 'CLOSE.ALL',
10722
	/*::[*/0x0004/*::]*/: 'SAVE',
10723
	/*::[*/0x0005/*::]*/: 'SAVE.AS',
10724
	/*::[*/0x0006/*::]*/: 'FILE.DELETE',
10725
	/*::[*/0x0007/*::]*/: 'PAGE.SETUP',
10726
	/*::[*/0x0008/*::]*/: 'PRINT',
10727
	/*::[*/0x0009/*::]*/: 'PRINTER.SETUP',
10728
	/*::[*/0x000A/*::]*/: 'QUIT',
10729
	/*::[*/0x000B/*::]*/: 'NEW.WINDOW',
10730
	/*::[*/0x000C/*::]*/: 'ARRANGE.ALL',
10731
	/*::[*/0x000D/*::]*/: 'WINDOW.SIZE',
10732
	/*::[*/0x000E/*::]*/: 'WINDOW.MOVE',
10733
	/*::[*/0x000F/*::]*/: 'FULL',
10734
	/*::[*/0x0010/*::]*/: 'CLOSE',
10735
	/*::[*/0x0011/*::]*/: 'RUN',
10736
	/*::[*/0x0016/*::]*/: 'SET.PRINT.AREA',
10737
	/*::[*/0x0017/*::]*/: 'SET.PRINT.TITLES',
10738
	/*::[*/0x0018/*::]*/: 'SET.PAGE.BREAK',
10739
	/*::[*/0x0019/*::]*/: 'REMOVE.PAGE.BREAK',
10740
	/*::[*/0x001A/*::]*/: 'FONT',
10741
	/*::[*/0x001B/*::]*/: 'DISPLAY',
10742
	/*::[*/0x001C/*::]*/: 'PROTECT.DOCUMENT',
10743
	/*::[*/0x001D/*::]*/: 'PRECISION',
10744
	/*::[*/0x001E/*::]*/: 'A1.R1C1',
10745
	/*::[*/0x001F/*::]*/: 'CALCULATE.NOW',
10746
	/*::[*/0x0020/*::]*/: 'CALCULATION',
10747
	/*::[*/0x0022/*::]*/: 'DATA.FIND',
10748
	/*::[*/0x0023/*::]*/: 'EXTRACT',
10749
	/*::[*/0x0024/*::]*/: 'DATA.DELETE',
10750
	/*::[*/0x0025/*::]*/: 'SET.DATABASE',
10751
	/*::[*/0x0026/*::]*/: 'SET.CRITERIA',
10752
	/*::[*/0x0027/*::]*/: 'SORT',
10753
	/*::[*/0x0028/*::]*/: 'DATA.SERIES',
10754
	/*::[*/0x0029/*::]*/: 'TABLE',
10755
	/*::[*/0x002A/*::]*/: 'FORMAT.NUMBER',
10756
	/*::[*/0x002B/*::]*/: 'ALIGNMENT',
10757
	/*::[*/0x002C/*::]*/: 'STYLE',
10758
	/*::[*/0x002D/*::]*/: 'BORDER',
10759
	/*::[*/0x002E/*::]*/: 'CELL.PROTECTION',
10760
	/*::[*/0x002F/*::]*/: 'COLUMN.WIDTH',
10761
	/*::[*/0x0030/*::]*/: 'UNDO',
10762
	/*::[*/0x0031/*::]*/: 'CUT',
10763
	/*::[*/0x0032/*::]*/: 'COPY',
10764
	/*::[*/0x0033/*::]*/: 'PASTE',
10765
	/*::[*/0x0034/*::]*/: 'CLEAR',
10766
	/*::[*/0x0035/*::]*/: 'PASTE.SPECIAL',
10767
	/*::[*/0x0036/*::]*/: 'EDIT.DELETE',
10768
	/*::[*/0x0037/*::]*/: 'INSERT',
10769
	/*::[*/0x0038/*::]*/: 'FILL.RIGHT',
10770
	/*::[*/0x0039/*::]*/: 'FILL.DOWN',
10771
	/*::[*/0x003D/*::]*/: 'DEFINE.NAME',
10772
	/*::[*/0x003E/*::]*/: 'CREATE.NAMES',
10773
	/*::[*/0x003F/*::]*/: 'FORMULA.GOTO',
10774
	/*::[*/0x0040/*::]*/: 'FORMULA.FIND',
10775
	/*::[*/0x0041/*::]*/: 'SELECT.LAST.CELL',
10776
	/*::[*/0x0042/*::]*/: 'SHOW.ACTIVE.CELL',
10777
	/*::[*/0x0043/*::]*/: 'GALLERY.AREA',
10778
	/*::[*/0x0044/*::]*/: 'GALLERY.BAR',
10779
	/*::[*/0x0045/*::]*/: 'GALLERY.COLUMN',
10780
	/*::[*/0x0046/*::]*/: 'GALLERY.LINE',
10781
	/*::[*/0x0047/*::]*/: 'GALLERY.PIE',
10782
	/*::[*/0x0048/*::]*/: 'GALLERY.SCATTER',
10783
	/*::[*/0x0049/*::]*/: 'COMBINATION',
10784
	/*::[*/0x004A/*::]*/: 'PREFERRED',
10785
	/*::[*/0x004B/*::]*/: 'ADD.OVERLAY',
10786
	/*::[*/0x004C/*::]*/: 'GRIDLINES',
10787
	/*::[*/0x004D/*::]*/: 'SET.PREFERRED',
10788
	/*::[*/0x004E/*::]*/: 'AXES',
10789
	/*::[*/0x004F/*::]*/: 'LEGEND',
10790
	/*::[*/0x0050/*::]*/: 'ATTACH.TEXT',
10791
	/*::[*/0x0051/*::]*/: 'ADD.ARROW',
10792
	/*::[*/0x0052/*::]*/: 'SELECT.CHART',
10793
	/*::[*/0x0053/*::]*/: 'SELECT.PLOT.AREA',
10794
	/*::[*/0x0054/*::]*/: 'PATTERNS',
10795
	/*::[*/0x0055/*::]*/: 'MAIN.CHART',
10796
	/*::[*/0x0056/*::]*/: 'OVERLAY',
10797
	/*::[*/0x0057/*::]*/: 'SCALE',
10798
	/*::[*/0x0058/*::]*/: 'FORMAT.LEGEND',
10799
	/*::[*/0x0059/*::]*/: 'FORMAT.TEXT',
10800
	/*::[*/0x005A/*::]*/: 'EDIT.REPEAT',
10801
	/*::[*/0x005B/*::]*/: 'PARSE',
10802
	/*::[*/0x005C/*::]*/: 'JUSTIFY',
10803
	/*::[*/0x005D/*::]*/: 'HIDE',
10804
	/*::[*/0x005E/*::]*/: 'UNHIDE',
10805
	/*::[*/0x005F/*::]*/: 'WORKSPACE',
10806
	/*::[*/0x0060/*::]*/: 'FORMULA',
10807
	/*::[*/0x0061/*::]*/: 'FORMULA.FILL',
10808
	/*::[*/0x0062/*::]*/: 'FORMULA.ARRAY',
10809
	/*::[*/0x0063/*::]*/: 'DATA.FIND.NEXT',
10810
	/*::[*/0x0064/*::]*/: 'DATA.FIND.PREV',
10811
	/*::[*/0x0065/*::]*/: 'FORMULA.FIND.NEXT',
10812
	/*::[*/0x0066/*::]*/: 'FORMULA.FIND.PREV',
10813
	/*::[*/0x0067/*::]*/: 'ACTIVATE',
10814
	/*::[*/0x0068/*::]*/: 'ACTIVATE.NEXT',
10815
	/*::[*/0x0069/*::]*/: 'ACTIVATE.PREV',
10816
	/*::[*/0x006A/*::]*/: 'UNLOCKED.NEXT',
10817
	/*::[*/0x006B/*::]*/: 'UNLOCKED.PREV',
10818
	/*::[*/0x006C/*::]*/: 'COPY.PICTURE',
10819
	/*::[*/0x006D/*::]*/: 'SELECT',
10820
	/*::[*/0x006E/*::]*/: 'DELETE.NAME',
10821
	/*::[*/0x006F/*::]*/: 'DELETE.FORMAT',
10822
	/*::[*/0x0070/*::]*/: 'VLINE',
10823
	/*::[*/0x0071/*::]*/: 'HLINE',
10824
	/*::[*/0x0072/*::]*/: 'VPAGE',
10825
	/*::[*/0x0073/*::]*/: 'HPAGE',
10826
	/*::[*/0x0074/*::]*/: 'VSCROLL',
10827
	/*::[*/0x0075/*::]*/: 'HSCROLL',
10828
	/*::[*/0x0076/*::]*/: 'ALERT',
10829
	/*::[*/0x0077/*::]*/: 'NEW',
10830
	/*::[*/0x0078/*::]*/: 'CANCEL.COPY',
10831
	/*::[*/0x0079/*::]*/: 'SHOW.CLIPBOARD',
10832
	/*::[*/0x007A/*::]*/: 'MESSAGE',
10833
	/*::[*/0x007C/*::]*/: 'PASTE.LINK',
10834
	/*::[*/0x007D/*::]*/: 'APP.ACTIVATE',
10835
	/*::[*/0x007E/*::]*/: 'DELETE.ARROW',
10836
	/*::[*/0x007F/*::]*/: 'ROW.HEIGHT',
10837
	/*::[*/0x0080/*::]*/: 'FORMAT.MOVE',
10838
	/*::[*/0x0081/*::]*/: 'FORMAT.SIZE',
10839
	/*::[*/0x0082/*::]*/: 'FORMULA.REPLACE',
10840
	/*::[*/0x0083/*::]*/: 'SEND.KEYS',
10841
	/*::[*/0x0084/*::]*/: 'SELECT.SPECIAL',
10842
	/*::[*/0x0085/*::]*/: 'APPLY.NAMES',
10843
	/*::[*/0x0086/*::]*/: 'REPLACE.FONT',
10844
	/*::[*/0x0087/*::]*/: 'FREEZE.PANES',
10845
	/*::[*/0x0088/*::]*/: 'SHOW.INFO',
10846
	/*::[*/0x0089/*::]*/: 'SPLIT',
10847
	/*::[*/0x008A/*::]*/: 'ON.WINDOW',
10848
	/*::[*/0x008B/*::]*/: 'ON.DATA',
10849
	/*::[*/0x008C/*::]*/: 'DISABLE.INPUT',
10850
	/*::[*/0x008E/*::]*/: 'OUTLINE',
10851
	/*::[*/0x008F/*::]*/: 'LIST.NAMES',
10852
	/*::[*/0x0090/*::]*/: 'FILE.CLOSE',
10853
	/*::[*/0x0091/*::]*/: 'SAVE.WORKBOOK',
10854
	/*::[*/0x0092/*::]*/: 'DATA.FORM',
10855
	/*::[*/0x0093/*::]*/: 'COPY.CHART',
10856
	/*::[*/0x0094/*::]*/: 'ON.TIME',
10857
	/*::[*/0x0095/*::]*/: 'WAIT',
10858
	/*::[*/0x0096/*::]*/: 'FORMAT.FONT',
10859
	/*::[*/0x0097/*::]*/: 'FILL.UP',
10860
	/*::[*/0x0098/*::]*/: 'FILL.LEFT',
10861
	/*::[*/0x0099/*::]*/: 'DELETE.OVERLAY',
10862
	/*::[*/0x009B/*::]*/: 'SHORT.MENUS',
10863
	/*::[*/0x009F/*::]*/: 'SET.UPDATE.STATUS',
10864
	/*::[*/0x00A1/*::]*/: 'COLOR.PALETTE',
10865
	/*::[*/0x00A2/*::]*/: 'DELETE.STYLE',
10866
	/*::[*/0x00A3/*::]*/: 'WINDOW.RESTORE',
10867
	/*::[*/0x00A4/*::]*/: 'WINDOW.MAXIMIZE',
10868
	/*::[*/0x00A6/*::]*/: 'CHANGE.LINK',
10869
	/*::[*/0x00A7/*::]*/: 'CALCULATE.DOCUMENT',
10870
	/*::[*/0x00A8/*::]*/: 'ON.KEY',
10871
	/*::[*/0x00A9/*::]*/: 'APP.RESTORE',
10872
	/*::[*/0x00AA/*::]*/: 'APP.MOVE',
10873
	/*::[*/0x00AB/*::]*/: 'APP.SIZE',
10874
	/*::[*/0x00AC/*::]*/: 'APP.MINIMIZE',
10875
	/*::[*/0x00AD/*::]*/: 'APP.MAXIMIZE',
10876
	/*::[*/0x00AE/*::]*/: 'BRING.TO.FRONT',
10877
	/*::[*/0x00AF/*::]*/: 'SEND.TO.BACK',
10878
	/*::[*/0x00B9/*::]*/: 'MAIN.CHART.TYPE',
10879
	/*::[*/0x00BA/*::]*/: 'OVERLAY.CHART.TYPE',
10880
	/*::[*/0x00BB/*::]*/: 'SELECT.END',
10881
	/*::[*/0x00BC/*::]*/: 'OPEN.MAIL',
10882
	/*::[*/0x00BD/*::]*/: 'SEND.MAIL',
10883
	/*::[*/0x00BE/*::]*/: 'STANDARD.FONT',
10884
	/*::[*/0x00BF/*::]*/: 'CONSOLIDATE',
10885
	/*::[*/0x00C0/*::]*/: 'SORT.SPECIAL',
10886
	/*::[*/0x00C1/*::]*/: 'GALLERY.3D.AREA',
10887
	/*::[*/0x00C2/*::]*/: 'GALLERY.3D.COLUMN',
10888
	/*::[*/0x00C3/*::]*/: 'GALLERY.3D.LINE',
10889
	/*::[*/0x00C4/*::]*/: 'GALLERY.3D.PIE',
10890
	/*::[*/0x00C5/*::]*/: 'VIEW.3D',
10891
	/*::[*/0x00C6/*::]*/: 'GOAL.SEEK',
10892
	/*::[*/0x00C7/*::]*/: 'WORKGROUP',
10893
	/*::[*/0x00C8/*::]*/: 'FILL.GROUP',
10894
	/*::[*/0x00C9/*::]*/: 'UPDATE.LINK',
10895
	/*::[*/0x00CA/*::]*/: 'PROMOTE',
10896
	/*::[*/0x00CB/*::]*/: 'DEMOTE',
10897
	/*::[*/0x00CC/*::]*/: 'SHOW.DETAIL',
10898
	/*::[*/0x00CE/*::]*/: 'UNGROUP',
10899
	/*::[*/0x00CF/*::]*/: 'OBJECT.PROPERTIES',
10900
	/*::[*/0x00D0/*::]*/: 'SAVE.NEW.OBJECT',
10901
	/*::[*/0x00D1/*::]*/: 'SHARE',
10902
	/*::[*/0x00D2/*::]*/: 'SHARE.NAME',
10903
	/*::[*/0x00D3/*::]*/: 'DUPLICATE',
10904
	/*::[*/0x00D4/*::]*/: 'APPLY.STYLE',
10905
	/*::[*/0x00D5/*::]*/: 'ASSIGN.TO.OBJECT',
10906
	/*::[*/0x00D6/*::]*/: 'OBJECT.PROTECTION',
10907
	/*::[*/0x00D7/*::]*/: 'HIDE.OBJECT',
10908
	/*::[*/0x00D8/*::]*/: 'SET.EXTRACT',
10909
	/*::[*/0x00D9/*::]*/: 'CREATE.PUBLISHER',
10910
	/*::[*/0x00DA/*::]*/: 'SUBSCRIBE.TO',
10911
	/*::[*/0x00DB/*::]*/: 'ATTRIBUTES',
10912
	/*::[*/0x00DC/*::]*/: 'SHOW.TOOLBAR',
10913
	/*::[*/0x00DE/*::]*/: 'PRINT.PREVIEW',
10914
	/*::[*/0x00DF/*::]*/: 'EDIT.COLOR',
10915
	/*::[*/0x00E0/*::]*/: 'SHOW.LEVELS',
10916
	/*::[*/0x00E1/*::]*/: 'FORMAT.MAIN',
10917
	/*::[*/0x00E2/*::]*/: 'FORMAT.OVERLAY',
10918
	/*::[*/0x00E3/*::]*/: 'ON.RECALC',
10919
	/*::[*/0x00E4/*::]*/: 'EDIT.SERIES',
10920
	/*::[*/0x00E5/*::]*/: 'DEFINE.STYLE',
10921
	/*::[*/0x00F0/*::]*/: 'LINE.PRINT',
10922
	/*::[*/0x00F3/*::]*/: 'ENTER.DATA',
10923
	/*::[*/0x00F9/*::]*/: 'GALLERY.RADAR',
10924
	/*::[*/0x00FA/*::]*/: 'MERGE.STYLES',
10925
	/*::[*/0x00FB/*::]*/: 'EDITION.OPTIONS',
10926
	/*::[*/0x00FC/*::]*/: 'PASTE.PICTURE',
10927
	/*::[*/0x00FD/*::]*/: 'PASTE.PICTURE.LINK',
10928
	/*::[*/0x00FE/*::]*/: 'SPELLING',
10929
	/*::[*/0x0100/*::]*/: 'ZOOM',
10930
	/*::[*/0x0103/*::]*/: 'INSERT.OBJECT',
10931
	/*::[*/0x0104/*::]*/: 'WINDOW.MINIMIZE',
10932
	/*::[*/0x0109/*::]*/: 'SOUND.NOTE',
10933
	/*::[*/0x010A/*::]*/: 'SOUND.PLAY',
10934
	/*::[*/0x010B/*::]*/: 'FORMAT.SHAPE',
10935
	/*::[*/0x010C/*::]*/: 'EXTEND.POLYGON',
10936
	/*::[*/0x010D/*::]*/: 'FORMAT.AUTO',
10937
	/*::[*/0x0110/*::]*/: 'GALLERY.3D.BAR',
10938
	/*::[*/0x0111/*::]*/: 'GALLERY.3D.SURFACE',
10939
	/*::[*/0x0112/*::]*/: 'FILL.AUTO',
10940
	/*::[*/0x0114/*::]*/: 'CUSTOMIZE.TOOLBAR',
10941
	/*::[*/0x0115/*::]*/: 'ADD.TOOL',
10942
	/*::[*/0x0116/*::]*/: 'EDIT.OBJECT',
10943
	/*::[*/0x0117/*::]*/: 'ON.DOUBLECLICK',
10944
	/*::[*/0x0118/*::]*/: 'ON.ENTRY',
10945
	/*::[*/0x0119/*::]*/: 'WORKBOOK.ADD',
10946
	/*::[*/0x011A/*::]*/: 'WORKBOOK.MOVE',
10947
	/*::[*/0x011B/*::]*/: 'WORKBOOK.COPY',
10948
	/*::[*/0x011C/*::]*/: 'WORKBOOK.OPTIONS',
10949
	/*::[*/0x011D/*::]*/: 'SAVE.WORKSPACE',
10950
	/*::[*/0x0120/*::]*/: 'CHART.WIZARD',
10951
	/*::[*/0x0121/*::]*/: 'DELETE.TOOL',
10952
	/*::[*/0x0122/*::]*/: 'MOVE.TOOL',
10953
	/*::[*/0x0123/*::]*/: 'WORKBOOK.SELECT',
10954
	/*::[*/0x0124/*::]*/: 'WORKBOOK.ACTIVATE',
10955
	/*::[*/0x0125/*::]*/: 'ASSIGN.TO.TOOL',
10956
	/*::[*/0x0127/*::]*/: 'COPY.TOOL',
10957
	/*::[*/0x0128/*::]*/: 'RESET.TOOL',
10958
	/*::[*/0x0129/*::]*/: 'CONSTRAIN.NUMERIC',
10959
	/*::[*/0x012A/*::]*/: 'PASTE.TOOL',
10960
	/*::[*/0x012E/*::]*/: 'WORKBOOK.NEW',
10961
	/*::[*/0x0131/*::]*/: 'SCENARIO.CELLS',
10962
	/*::[*/0x0132/*::]*/: 'SCENARIO.DELETE',
10963
	/*::[*/0x0133/*::]*/: 'SCENARIO.ADD',
10964
	/*::[*/0x0134/*::]*/: 'SCENARIO.EDIT',
10965
	/*::[*/0x0135/*::]*/: 'SCENARIO.SHOW',
10966
	/*::[*/0x0136/*::]*/: 'SCENARIO.SHOW.NEXT',
10967
	/*::[*/0x0137/*::]*/: 'SCENARIO.SUMMARY',
10968
	/*::[*/0x0138/*::]*/: 'PIVOT.TABLE.WIZARD',
10969
	/*::[*/0x0139/*::]*/: 'PIVOT.FIELD.PROPERTIES',
10970
	/*::[*/0x013A/*::]*/: 'PIVOT.FIELD',
10971
	/*::[*/0x013B/*::]*/: 'PIVOT.ITEM',
10972
	/*::[*/0x013C/*::]*/: 'PIVOT.ADD.FIELDS',
10973
	/*::[*/0x013E/*::]*/: 'OPTIONS.CALCULATION',
10974
	/*::[*/0x013F/*::]*/: 'OPTIONS.EDIT',
10975
	/*::[*/0x0140/*::]*/: 'OPTIONS.VIEW',
10976
	/*::[*/0x0141/*::]*/: 'ADDIN.MANAGER',
10977
	/*::[*/0x0142/*::]*/: 'MENU.EDITOR',
10978
	/*::[*/0x0143/*::]*/: 'ATTACH.TOOLBARS',
10979
	/*::[*/0x0144/*::]*/: 'VBAActivate',
10980
	/*::[*/0x0145/*::]*/: 'OPTIONS.CHART',
10981
	/*::[*/0x0148/*::]*/: 'VBA.INSERT.FILE',
10982
	/*::[*/0x014A/*::]*/: 'VBA.PROCEDURE.DEFINITION',
10983
	/*::[*/0x0150/*::]*/: 'ROUTING.SLIP',
10984
	/*::[*/0x0152/*::]*/: 'ROUTE.DOCUMENT',
10985
	/*::[*/0x0153/*::]*/: 'MAIL.LOGON',
10986
	/*::[*/0x0156/*::]*/: 'INSERT.PICTURE',
10987
	/*::[*/0x0157/*::]*/: 'EDIT.TOOL',
10988
	/*::[*/0x0158/*::]*/: 'GALLERY.DOUGHNUT',
10989
	/*::[*/0x015E/*::]*/: 'CHART.TREND',
10990
	/*::[*/0x0160/*::]*/: 'PIVOT.ITEM.PROPERTIES',
10991
	/*::[*/0x0162/*::]*/: 'WORKBOOK.INSERT',
10992
	/*::[*/0x0163/*::]*/: 'OPTIONS.TRANSITION',
10993
	/*::[*/0x0164/*::]*/: 'OPTIONS.GENERAL',
10994
	/*::[*/0x0172/*::]*/: 'FILTER.ADVANCED',
10995
	/*::[*/0x0175/*::]*/: 'MAIL.ADD.MAILER',
10996
	/*::[*/0x0176/*::]*/: 'MAIL.DELETE.MAILER',
10997
	/*::[*/0x0177/*::]*/: 'MAIL.REPLY',
10998
	/*::[*/0x0178/*::]*/: 'MAIL.REPLY.ALL',
10999
	/*::[*/0x0179/*::]*/: 'MAIL.FORWARD',
11000
	/*::[*/0x017A/*::]*/: 'MAIL.NEXT.LETTER',
11001
	/*::[*/0x017B/*::]*/: 'DATA.LABEL',
11002
	/*::[*/0x017C/*::]*/: 'INSERT.TITLE',
11003
	/*::[*/0x017D/*::]*/: 'FONT.PROPERTIES',
11004
	/*::[*/0x017E/*::]*/: 'MACRO.OPTIONS',
11005
	/*::[*/0x017F/*::]*/: 'WORKBOOK.HIDE',
11006
	/*::[*/0x0180/*::]*/: 'WORKBOOK.UNHIDE',
11007
	/*::[*/0x0181/*::]*/: 'WORKBOOK.DELETE',
11008
	/*::[*/0x0182/*::]*/: 'WORKBOOK.NAME',
11009
	/*::[*/0x0184/*::]*/: 'GALLERY.CUSTOM',
11010
	/*::[*/0x0186/*::]*/: 'ADD.CHART.AUTOFORMAT',
11011
	/*::[*/0x0187/*::]*/: 'DELETE.CHART.AUTOFORMAT',
11012
	/*::[*/0x0188/*::]*/: 'CHART.ADD.DATA',
11013
	/*::[*/0x0189/*::]*/: 'AUTO.OUTLINE',
11014
	/*::[*/0x018A/*::]*/: 'TAB.ORDER',
11015
	/*::[*/0x018B/*::]*/: 'SHOW.DIALOG',
11016
	/*::[*/0x018C/*::]*/: 'SELECT.ALL',
11017
	/*::[*/0x018D/*::]*/: 'UNGROUP.SHEETS',
11018
	/*::[*/0x018E/*::]*/: 'SUBTOTAL.CREATE',
11019
	/*::[*/0x018F/*::]*/: 'SUBTOTAL.REMOVE',
11020
	/*::[*/0x0190/*::]*/: 'RENAME.OBJECT',
11021
	/*::[*/0x019C/*::]*/: 'WORKBOOK.SCROLL',
11022
	/*::[*/0x019D/*::]*/: 'WORKBOOK.NEXT',
11023
	/*::[*/0x019E/*::]*/: 'WORKBOOK.PREV',
11024
	/*::[*/0x019F/*::]*/: 'WORKBOOK.TAB.SPLIT',
11025
	/*::[*/0x01A0/*::]*/: 'FULL.SCREEN',
11026
	/*::[*/0x01A1/*::]*/: 'WORKBOOK.PROTECT',
11027
	/*::[*/0x01A4/*::]*/: 'SCROLLBAR.PROPERTIES',
11028
	/*::[*/0x01A5/*::]*/: 'PIVOT.SHOW.PAGES',
11029
	/*::[*/0x01A6/*::]*/: 'TEXT.TO.COLUMNS',
11030
	/*::[*/0x01A7/*::]*/: 'FORMAT.CHARTTYPE',
11031
	/*::[*/0x01A8/*::]*/: 'LINK.FORMAT',
11032
	/*::[*/0x01A9/*::]*/: 'TRACER.DISPLAY',
11033
	/*::[*/0x01AE/*::]*/: 'TRACER.NAVIGATE',
11034
	/*::[*/0x01AF/*::]*/: 'TRACER.CLEAR',
11035
	/*::[*/0x01B0/*::]*/: 'TRACER.ERROR',
11036
	/*::[*/0x01B1/*::]*/: 'PIVOT.FIELD.GROUP',
11037
	/*::[*/0x01B2/*::]*/: 'PIVOT.FIELD.UNGROUP',
11038
	/*::[*/0x01B3/*::]*/: 'CHECKBOX.PROPERTIES',
11039
	/*::[*/0x01B4/*::]*/: 'LABEL.PROPERTIES',
11040
	/*::[*/0x01B5/*::]*/: 'LISTBOX.PROPERTIES',
11041
	/*::[*/0x01B6/*::]*/: 'EDITBOX.PROPERTIES',
11042
	/*::[*/0x01B7/*::]*/: 'PIVOT.REFRESH',
11043
	/*::[*/0x01B8/*::]*/: 'LINK.COMBO',
11044
	/*::[*/0x01B9/*::]*/: 'OPEN.TEXT',
11045
	/*::[*/0x01BA/*::]*/: 'HIDE.DIALOG',
11046
	/*::[*/0x01BB/*::]*/: 'SET.DIALOG.FOCUS',
11047
	/*::[*/0x01BC/*::]*/: 'ENABLE.OBJECT',
11048
	/*::[*/0x01BD/*::]*/: 'PUSHBUTTON.PROPERTIES',
11049
	/*::[*/0x01BE/*::]*/: 'SET.DIALOG.DEFAULT',
11050
	/*::[*/0x01BF/*::]*/: 'FILTER',
11051
	/*::[*/0x01C0/*::]*/: 'FILTER.SHOW.ALL',
11052
	/*::[*/0x01C1/*::]*/: 'CLEAR.OUTLINE',
11053
	/*::[*/0x01C2/*::]*/: 'FUNCTION.WIZARD',
11054
	/*::[*/0x01C3/*::]*/: 'ADD.LIST.ITEM',
11055
	/*::[*/0x01C4/*::]*/: 'SET.LIST.ITEM',
11056
	/*::[*/0x01C5/*::]*/: 'REMOVE.LIST.ITEM',
11057
	/*::[*/0x01C6/*::]*/: 'SELECT.LIST.ITEM',
11058
	/*::[*/0x01C7/*::]*/: 'SET.CONTROL.VALUE',
11059
	/*::[*/0x01C8/*::]*/: 'SAVE.COPY.AS',
11060
	/*::[*/0x01CA/*::]*/: 'OPTIONS.LISTS.ADD',
11061
	/*::[*/0x01CB/*::]*/: 'OPTIONS.LISTS.DELETE',
11062
	/*::[*/0x01CC/*::]*/: 'SERIES.AXES',
11063
	/*::[*/0x01CD/*::]*/: 'SERIES.X',
11064
	/*::[*/0x01CE/*::]*/: 'SERIES.Y',
11065
	/*::[*/0x01CF/*::]*/: 'ERRORBAR.X',
11066
	/*::[*/0x01D0/*::]*/: 'ERRORBAR.Y',
11067
	/*::[*/0x01D1/*::]*/: 'FORMAT.CHART',
11068
	/*::[*/0x01D2/*::]*/: 'SERIES.ORDER',
11069
	/*::[*/0x01D3/*::]*/: 'MAIL.LOGOFF',
11070
	/*::[*/0x01D4/*::]*/: 'CLEAR.ROUTING.SLIP',
11071
	/*::[*/0x01D5/*::]*/: 'APP.ACTIVATE.MICROSOFT',
11072
	/*::[*/0x01D6/*::]*/: 'MAIL.EDIT.MAILER',
11073
	/*::[*/0x01D7/*::]*/: 'ON.SHEET',
11074
	/*::[*/0x01D8/*::]*/: 'STANDARD.WIDTH',
11075
	/*::[*/0x01D9/*::]*/: 'SCENARIO.MERGE',
11076
	/*::[*/0x01DA/*::]*/: 'SUMMARY.INFO',
11077
	/*::[*/0x01DB/*::]*/: 'FIND.FILE',
11078
	/*::[*/0x01DC/*::]*/: 'ACTIVE.CELL.FONT',
11079
	/*::[*/0x01DD/*::]*/: 'ENABLE.TIPWIZARD',
11080
	/*::[*/0x01DE/*::]*/: 'VBA.MAKE.ADDIN',
11081
	/*::[*/0x01E0/*::]*/: 'INSERTDATATABLE',
11082
	/*::[*/0x01E1/*::]*/: 'WORKGROUP.OPTIONS',
11083
	/*::[*/0x01E2/*::]*/: 'MAIL.SEND.MAILER',
11084
	/*::[*/0x01E5/*::]*/: 'AUTOCORRECT',
11085
	/*::[*/0x01E9/*::]*/: 'POST.DOCUMENT',
11086
	/*::[*/0x01EB/*::]*/: 'PICKLIST',
11087
	/*::[*/0x01ED/*::]*/: 'VIEW.SHOW',
11088
	/*::[*/0x01EE/*::]*/: 'VIEW.DEFINE',
11089
	/*::[*/0x01EF/*::]*/: 'VIEW.DELETE',
11090
	/*::[*/0x01FD/*::]*/: 'SHEET.BACKGROUND',
11091
	/*::[*/0x01FE/*::]*/: 'INSERT.MAP.OBJECT',
11092
	/*::[*/0x01FF/*::]*/: 'OPTIONS.MENONO',
11093
	/*::[*/0x0205/*::]*/: 'MSOCHECKS',
11094
	/*::[*/0x0206/*::]*/: 'NORMAL',
11095
	/*::[*/0x0207/*::]*/: 'LAYOUT',
11096
	/*::[*/0x0208/*::]*/: 'RM.PRINT.AREA',
11097
	/*::[*/0x0209/*::]*/: 'CLEAR.PRINT.AREA',
11098
	/*::[*/0x020A/*::]*/: 'ADD.PRINT.AREA',
11099
	/*::[*/0x020B/*::]*/: 'MOVE.BRK',
11100
	/*::[*/0x0221/*::]*/: 'HIDECURR.NOTE',
11101
	/*::[*/0x0222/*::]*/: 'HIDEALL.NOTES',
11102
	/*::[*/0x0223/*::]*/: 'DELETE.NOTE',
11103
	/*::[*/0x0224/*::]*/: 'TRAVERSE.NOTES',
11104
	/*::[*/0x0225/*::]*/: 'ACTIVATE.NOTES',
11105
	/*::[*/0x026C/*::]*/: 'PROTECT.REVISIONS',
11106
	/*::[*/0x026D/*::]*/: 'UNPROTECT.REVISIONS',
11107
	/*::[*/0x0287/*::]*/: 'OPTIONS.ME',
11108
	/*::[*/0x028D/*::]*/: 'WEB.PUBLISH',
11109
	/*::[*/0x029B/*::]*/: 'NEWWEBQUERY',
11110
	/*::[*/0x02A1/*::]*/: 'PIVOT.TABLE.CHART',
11111
	/*::[*/0x02F1/*::]*/: 'OPTIONS.SAVE',
11112
	/*::[*/0x02F3/*::]*/: 'OPTIONS.SPELL',
11113
	/*::[*/0x0328/*::]*/: 'HIDEALL.INKANNOTS'
11114
};
11115
11116
/* [MS-XLS] 2.5.198.17 */
11117
/* [MS-XLSB] 2.5.97.10 */
11118
var Ftab = {
11119
	/*::[*/0x0000/*::]*/: 'COUNT',
11120
	/*::[*/0x0001/*::]*/: 'IF',
11121
	/*::[*/0x0002/*::]*/: 'ISNA',
11122
	/*::[*/0x0003/*::]*/: 'ISERROR',
11123
	/*::[*/0x0004/*::]*/: 'SUM',
11124
	/*::[*/0x0005/*::]*/: 'AVERAGE',
11125
	/*::[*/0x0006/*::]*/: 'MIN',
11126
	/*::[*/0x0007/*::]*/: 'MAX',
11127
	/*::[*/0x0008/*::]*/: 'ROW',
11128
	/*::[*/0x0009/*::]*/: 'COLUMN',
11129
	/*::[*/0x000A/*::]*/: 'NA',
11130
	/*::[*/0x000B/*::]*/: 'NPV',
11131
	/*::[*/0x000C/*::]*/: 'STDEV',
11132
	/*::[*/0x000D/*::]*/: 'DOLLAR',
11133
	/*::[*/0x000E/*::]*/: 'FIXED',
11134
	/*::[*/0x000F/*::]*/: 'SIN',
11135
	/*::[*/0x0010/*::]*/: 'COS',
11136
	/*::[*/0x0011/*::]*/: 'TAN',
11137
	/*::[*/0x0012/*::]*/: 'ATAN',
11138
	/*::[*/0x0013/*::]*/: 'PI',
11139
	/*::[*/0x0014/*::]*/: 'SQRT',
11140
	/*::[*/0x0015/*::]*/: 'EXP',
11141
	/*::[*/0x0016/*::]*/: 'LN',
11142
	/*::[*/0x0017/*::]*/: 'LOG10',
11143
	/*::[*/0x0018/*::]*/: 'ABS',
11144
	/*::[*/0x0019/*::]*/: 'INT',
11145
	/*::[*/0x001A/*::]*/: 'SIGN',
11146
	/*::[*/0x001B/*::]*/: 'ROUND',
11147
	/*::[*/0x001C/*::]*/: 'LOOKUP',
11148
	/*::[*/0x001D/*::]*/: 'INDEX',
11149
	/*::[*/0x001E/*::]*/: 'REPT',
11150
	/*::[*/0x001F/*::]*/: 'MID',
11151
	/*::[*/0x0020/*::]*/: 'LEN',
11152
	/*::[*/0x0021/*::]*/: 'VALUE',
11153
	/*::[*/0x0022/*::]*/: 'TRUE',
11154
	/*::[*/0x0023/*::]*/: 'FALSE',
11155
	/*::[*/0x0024/*::]*/: 'AND',
11156
	/*::[*/0x0025/*::]*/: 'OR',
11157
	/*::[*/0x0026/*::]*/: 'NOT',
11158
	/*::[*/0x0027/*::]*/: 'MOD',
11159
	/*::[*/0x0028/*::]*/: 'DCOUNT',
11160
	/*::[*/0x0029/*::]*/: 'DSUM',
11161
	/*::[*/0x002A/*::]*/: 'DAVERAGE',
11162
	/*::[*/0x002B/*::]*/: 'DMIN',
11163
	/*::[*/0x002C/*::]*/: 'DMAX',
11164
	/*::[*/0x002D/*::]*/: 'DSTDEV',
11165
	/*::[*/0x002E/*::]*/: 'VAR',
11166
	/*::[*/0x002F/*::]*/: 'DVAR',
11167
	/*::[*/0x0030/*::]*/: 'TEXT',
11168
	/*::[*/0x0031/*::]*/: 'LINEST',
11169
	/*::[*/0x0032/*::]*/: 'TREND',
11170
	/*::[*/0x0033/*::]*/: 'LOGEST',
11171
	/*::[*/0x0034/*::]*/: 'GROWTH',
11172
	/*::[*/0x0035/*::]*/: 'GOTO',
11173
	/*::[*/0x0036/*::]*/: 'HALT',
11174
	/*::[*/0x0037/*::]*/: 'RETURN',
11175
	/*::[*/0x0038/*::]*/: 'PV',
11176
	/*::[*/0x0039/*::]*/: 'FV',
11177
	/*::[*/0x003A/*::]*/: 'NPER',
11178
	/*::[*/0x003B/*::]*/: 'PMT',
11179
	/*::[*/0x003C/*::]*/: 'RATE',
11180
	/*::[*/0x003D/*::]*/: 'MIRR',
11181
	/*::[*/0x003E/*::]*/: 'IRR',
11182
	/*::[*/0x003F/*::]*/: 'RAND',
11183
	/*::[*/0x0040/*::]*/: 'MATCH',
11184
	/*::[*/0x0041/*::]*/: 'DATE',
11185
	/*::[*/0x0042/*::]*/: 'TIME',
11186
	/*::[*/0x0043/*::]*/: 'DAY',
11187
	/*::[*/0x0044/*::]*/: 'MONTH',
11188
	/*::[*/0x0045/*::]*/: 'YEAR',
11189
	/*::[*/0x0046/*::]*/: 'WEEKDAY',
11190
	/*::[*/0x0047/*::]*/: 'HOUR',
11191
	/*::[*/0x0048/*::]*/: 'MINUTE',
11192
	/*::[*/0x0049/*::]*/: 'SECOND',
11193
	/*::[*/0x004A/*::]*/: 'NOW',
11194
	/*::[*/0x004B/*::]*/: 'AREAS',
11195
	/*::[*/0x004C/*::]*/: 'ROWS',
11196
	/*::[*/0x004D/*::]*/: 'COLUMNS',
11197
	/*::[*/0x004E/*::]*/: 'OFFSET',
11198
	/*::[*/0x004F/*::]*/: 'ABSREF',
11199
	/*::[*/0x0050/*::]*/: 'RELREF',
11200
	/*::[*/0x0051/*::]*/: 'ARGUMENT',
11201
	/*::[*/0x0052/*::]*/: 'SEARCH',
11202
	/*::[*/0x0053/*::]*/: 'TRANSPOSE',
11203
	/*::[*/0x0054/*::]*/: 'ERROR',
11204
	/*::[*/0x0055/*::]*/: 'STEP',
11205
	/*::[*/0x0056/*::]*/: 'TYPE',
11206
	/*::[*/0x0057/*::]*/: 'ECHO',
11207
	/*::[*/0x0058/*::]*/: 'SET.NAME',
11208
	/*::[*/0x0059/*::]*/: 'CALLER',
11209
	/*::[*/0x005A/*::]*/: 'DEREF',
11210
	/*::[*/0x005B/*::]*/: 'WINDOWS',
11211
	/*::[*/0x005C/*::]*/: 'SERIES',
11212
	/*::[*/0x005D/*::]*/: 'DOCUMENTS',
11213
	/*::[*/0x005E/*::]*/: 'ACTIVE.CELL',
11214
	/*::[*/0x005F/*::]*/: 'SELECTION',
11215
	/*::[*/0x0060/*::]*/: 'RESULT',
11216
	/*::[*/0x0061/*::]*/: 'ATAN2',
11217
	/*::[*/0x0062/*::]*/: 'ASIN',
11218
	/*::[*/0x0063/*::]*/: 'ACOS',
11219
	/*::[*/0x0064/*::]*/: 'CHOOSE',
11220
	/*::[*/0x0065/*::]*/: 'HLOOKUP',
11221
	/*::[*/0x0066/*::]*/: 'VLOOKUP',
11222
	/*::[*/0x0067/*::]*/: 'LINKS',
11223
	/*::[*/0x0068/*::]*/: 'INPUT',
11224
	/*::[*/0x0069/*::]*/: 'ISREF',
11225
	/*::[*/0x006A/*::]*/: 'GET.FORMULA',
11226
	/*::[*/0x006B/*::]*/: 'GET.NAME',
11227
	/*::[*/0x006C/*::]*/: 'SET.VALUE',
11228
	/*::[*/0x006D/*::]*/: 'LOG',
11229
	/*::[*/0x006E/*::]*/: 'EXEC',
11230
	/*::[*/0x006F/*::]*/: 'CHAR',
11231
	/*::[*/0x0070/*::]*/: 'LOWER',
11232
	/*::[*/0x0071/*::]*/: 'UPPER',
11233
	/*::[*/0x0072/*::]*/: 'PROPER',
11234
	/*::[*/0x0073/*::]*/: 'LEFT',
11235
	/*::[*/0x0074/*::]*/: 'RIGHT',
11236
	/*::[*/0x0075/*::]*/: 'EXACT',
11237
	/*::[*/0x0076/*::]*/: 'TRIM',
11238
	/*::[*/0x0077/*::]*/: 'REPLACE',
11239
	/*::[*/0x0078/*::]*/: 'SUBSTITUTE',
11240
	/*::[*/0x0079/*::]*/: 'CODE',
11241
	/*::[*/0x007A/*::]*/: 'NAMES',
11242
	/*::[*/0x007B/*::]*/: 'DIRECTORY',
11243
	/*::[*/0x007C/*::]*/: 'FIND',
11244
	/*::[*/0x007D/*::]*/: 'CELL',
11245
	/*::[*/0x007E/*::]*/: 'ISERR',
11246
	/*::[*/0x007F/*::]*/: 'ISTEXT',
11247
	/*::[*/0x0080/*::]*/: 'ISNUMBER',
11248
	/*::[*/0x0081/*::]*/: 'ISBLANK',
11249
	/*::[*/0x0082/*::]*/: 'T',
11250
	/*::[*/0x0083/*::]*/: 'N',
11251
	/*::[*/0x0084/*::]*/: 'FOPEN',
11252
	/*::[*/0x0085/*::]*/: 'FCLOSE',
11253
	/*::[*/0x0086/*::]*/: 'FSIZE',
11254
	/*::[*/0x0087/*::]*/: 'FREADLN',
11255
	/*::[*/0x0088/*::]*/: 'FREAD',
11256
	/*::[*/0x0089/*::]*/: 'FWRITELN',
11257
	/*::[*/0x008A/*::]*/: 'FWRITE',
11258
	/*::[*/0x008B/*::]*/: 'FPOS',
11259
	/*::[*/0x008C/*::]*/: 'DATEVALUE',
11260
	/*::[*/0x008D/*::]*/: 'TIMEVALUE',
11261
	/*::[*/0x008E/*::]*/: 'SLN',
11262
	/*::[*/0x008F/*::]*/: 'SYD',
11263
	/*::[*/0x0090/*::]*/: 'DDB',
11264
	/*::[*/0x0091/*::]*/: 'GET.DEF',
11265
	/*::[*/0x0092/*::]*/: 'REFTEXT',
11266
	/*::[*/0x0093/*::]*/: 'TEXTREF',
11267
	/*::[*/0x0094/*::]*/: 'INDIRECT',
11268
	/*::[*/0x0095/*::]*/: 'REGISTER',
11269
	/*::[*/0x0096/*::]*/: 'CALL',
11270
	/*::[*/0x0097/*::]*/: 'ADD.BAR',
11271
	/*::[*/0x0098/*::]*/: 'ADD.MENU',
11272
	/*::[*/0x0099/*::]*/: 'ADD.COMMAND',
11273
	/*::[*/0x009A/*::]*/: 'ENABLE.COMMAND',
11274
	/*::[*/0x009B/*::]*/: 'CHECK.COMMAND',
11275
	/*::[*/0x009C/*::]*/: 'RENAME.COMMAND',
11276
	/*::[*/0x009D/*::]*/: 'SHOW.BAR',
11277
	/*::[*/0x009E/*::]*/: 'DELETE.MENU',
11278
	/*::[*/0x009F/*::]*/: 'DELETE.COMMAND',
11279
	/*::[*/0x00A0/*::]*/: 'GET.CHART.ITEM',
11280
	/*::[*/0x00A1/*::]*/: 'DIALOG.BOX',
11281
	/*::[*/0x00A2/*::]*/: 'CLEAN',
11282
	/*::[*/0x00A3/*::]*/: 'MDETERM',
11283
	/*::[*/0x00A4/*::]*/: 'MINVERSE',
11284
	/*::[*/0x00A5/*::]*/: 'MMULT',
11285
	/*::[*/0x00A6/*::]*/: 'FILES',
11286
	/*::[*/0x00A7/*::]*/: 'IPMT',
11287
	/*::[*/0x00A8/*::]*/: 'PPMT',
11288
	/*::[*/0x00A9/*::]*/: 'COUNTA',
11289
	/*::[*/0x00AA/*::]*/: 'CANCEL.KEY',
11290
	/*::[*/0x00AB/*::]*/: 'FOR',
11291
	/*::[*/0x00AC/*::]*/: 'WHILE',
11292
	/*::[*/0x00AD/*::]*/: 'BREAK',
11293
	/*::[*/0x00AE/*::]*/: 'NEXT',
11294
	/*::[*/0x00AF/*::]*/: 'INITIATE',
11295
	/*::[*/0x00B0/*::]*/: 'REQUEST',
11296
	/*::[*/0x00B1/*::]*/: 'POKE',
11297
	/*::[*/0x00B2/*::]*/: 'EXECUTE',
11298
	/*::[*/0x00B3/*::]*/: 'TERMINATE',
11299
	/*::[*/0x00B4/*::]*/: 'RESTART',
11300
	/*::[*/0x00B5/*::]*/: 'HELP',
11301
	/*::[*/0x00B6/*::]*/: 'GET.BAR',
11302
	/*::[*/0x00B7/*::]*/: 'PRODUCT',
11303
	/*::[*/0x00B8/*::]*/: 'FACT',
11304
	/*::[*/0x00B9/*::]*/: 'GET.CELL',
11305
	/*::[*/0x00BA/*::]*/: 'GET.WORKSPACE',
11306
	/*::[*/0x00BB/*::]*/: 'GET.WINDOW',
11307
	/*::[*/0x00BC/*::]*/: 'GET.DOCUMENT',
11308
	/*::[*/0x00BD/*::]*/: 'DPRODUCT',
11309
	/*::[*/0x00BE/*::]*/: 'ISNONTEXT',
11310
	/*::[*/0x00BF/*::]*/: 'GET.NOTE',
11311
	/*::[*/0x00C0/*::]*/: 'NOTE',
11312
	/*::[*/0x00C1/*::]*/: 'STDEVP',
11313
	/*::[*/0x00C2/*::]*/: 'VARP',
11314
	/*::[*/0x00C3/*::]*/: 'DSTDEVP',
11315
	/*::[*/0x00C4/*::]*/: 'DVARP',
11316
	/*::[*/0x00C5/*::]*/: 'TRUNC',
11317
	/*::[*/0x00C6/*::]*/: 'ISLOGICAL',
11318
	/*::[*/0x00C7/*::]*/: 'DCOUNTA',
11319
	/*::[*/0x00C8/*::]*/: 'DELETE.BAR',
11320
	/*::[*/0x00C9/*::]*/: 'UNREGISTER',
11321
	/*::[*/0x00CC/*::]*/: 'USDOLLAR',
11322
	/*::[*/0x00CD/*::]*/: 'FINDB',
11323
	/*::[*/0x00CE/*::]*/: 'SEARCHB',
11324
	/*::[*/0x00CF/*::]*/: 'REPLACEB',
11325
	/*::[*/0x00D0/*::]*/: 'LEFTB',
11326
	/*::[*/0x00D1/*::]*/: 'RIGHTB',
11327
	/*::[*/0x00D2/*::]*/: 'MIDB',
11328
	/*::[*/0x00D3/*::]*/: 'LENB',
11329
	/*::[*/0x00D4/*::]*/: 'ROUNDUP',
11330
	/*::[*/0x00D5/*::]*/: 'ROUNDDOWN',
11331
	/*::[*/0x00D6/*::]*/: 'ASC',
11332
	/*::[*/0x00D7/*::]*/: 'DBCS',
11333
	/*::[*/0x00D8/*::]*/: 'RANK',
11334
	/*::[*/0x00DB/*::]*/: 'ADDRESS',
11335
	/*::[*/0x00DC/*::]*/: 'DAYS360',
11336
	/*::[*/0x00DD/*::]*/: 'TODAY',
11337
	/*::[*/0x00DE/*::]*/: 'VDB',
11338
	/*::[*/0x00DF/*::]*/: 'ELSE',
11339
	/*::[*/0x00E0/*::]*/: 'ELSE.IF',
11340
	/*::[*/0x00E1/*::]*/: 'END.IF',
11341
	/*::[*/0x00E2/*::]*/: 'FOR.CELL',
11342
	/*::[*/0x00E3/*::]*/: 'MEDIAN',
11343
	/*::[*/0x00E4/*::]*/: 'SUMPRODUCT',
11344
	/*::[*/0x00E5/*::]*/: 'SINH',
11345
	/*::[*/0x00E6/*::]*/: 'COSH',
11346
	/*::[*/0x00E7/*::]*/: 'TANH',
11347
	/*::[*/0x00E8/*::]*/: 'ASINH',
11348
	/*::[*/0x00E9/*::]*/: 'ACOSH',
11349
	/*::[*/0x00EA/*::]*/: 'ATANH',
11350
	/*::[*/0x00EB/*::]*/: 'DGET',
11351
	/*::[*/0x00EC/*::]*/: 'CREATE.OBJECT',
11352
	/*::[*/0x00ED/*::]*/: 'VOLATILE',
11353
	/*::[*/0x00EE/*::]*/: 'LAST.ERROR',
11354
	/*::[*/0x00EF/*::]*/: 'CUSTOM.UNDO',
11355
	/*::[*/0x00F0/*::]*/: 'CUSTOM.REPEAT',
11356
	/*::[*/0x00F1/*::]*/: 'FORMULA.CONVERT',
11357
	/*::[*/0x00F2/*::]*/: 'GET.LINK.INFO',
11358
	/*::[*/0x00F3/*::]*/: 'TEXT.BOX',
11359
	/*::[*/0x00F4/*::]*/: 'INFO',
11360
	/*::[*/0x00F5/*::]*/: 'GROUP',
11361
	/*::[*/0x00F6/*::]*/: 'GET.OBJECT',
11362
	/*::[*/0x00F7/*::]*/: 'DB',
11363
	/*::[*/0x00F8/*::]*/: 'PAUSE',
11364
	/*::[*/0x00FB/*::]*/: 'RESUME',
11365
	/*::[*/0x00FC/*::]*/: 'FREQUENCY',
11366
	/*::[*/0x00FD/*::]*/: 'ADD.TOOLBAR',
11367
	/*::[*/0x00FE/*::]*/: 'DELETE.TOOLBAR',
11368
	/*::[*/0x00FF/*::]*/: 'User',
11369
	/*::[*/0x0100/*::]*/: 'RESET.TOOLBAR',
11370
	/*::[*/0x0101/*::]*/: 'EVALUATE',
11371
	/*::[*/0x0102/*::]*/: 'GET.TOOLBAR',
11372
	/*::[*/0x0103/*::]*/: 'GET.TOOL',
11373
	/*::[*/0x0104/*::]*/: 'SPELLING.CHECK',
11374
	/*::[*/0x0105/*::]*/: 'ERROR.TYPE',
11375
	/*::[*/0x0106/*::]*/: 'APP.TITLE',
11376
	/*::[*/0x0107/*::]*/: 'WINDOW.TITLE',
11377
	/*::[*/0x0108/*::]*/: 'SAVE.TOOLBAR',
11378
	/*::[*/0x0109/*::]*/: 'ENABLE.TOOL',
11379
	/*::[*/0x010A/*::]*/: 'PRESS.TOOL',
11380
	/*::[*/0x010B/*::]*/: 'REGISTER.ID',
11381
	/*::[*/0x010C/*::]*/: 'GET.WORKBOOK',
11382
	/*::[*/0x010D/*::]*/: 'AVEDEV',
11383
	/*::[*/0x010E/*::]*/: 'BETADIST',
11384
	/*::[*/0x010F/*::]*/: 'GAMMALN',
11385
	/*::[*/0x0110/*::]*/: 'BETAINV',
11386
	/*::[*/0x0111/*::]*/: 'BINOMDIST',
11387
	/*::[*/0x0112/*::]*/: 'CHIDIST',
11388
	/*::[*/0x0113/*::]*/: 'CHIINV',
11389
	/*::[*/0x0114/*::]*/: 'COMBIN',
11390
	/*::[*/0x0115/*::]*/: 'CONFIDENCE',
11391
	/*::[*/0x0116/*::]*/: 'CRITBINOM',
11392
	/*::[*/0x0117/*::]*/: 'EVEN',
11393
	/*::[*/0x0118/*::]*/: 'EXPONDIST',
11394
	/*::[*/0x0119/*::]*/: 'FDIST',
11395
	/*::[*/0x011A/*::]*/: 'FINV',
11396
	/*::[*/0x011B/*::]*/: 'FISHER',
11397
	/*::[*/0x011C/*::]*/: 'FISHERINV',
11398
	/*::[*/0x011D/*::]*/: 'FLOOR',
11399
	/*::[*/0x011E/*::]*/: 'GAMMADIST',
11400
	/*::[*/0x011F/*::]*/: 'GAMMAINV',
11401
	/*::[*/0x0120/*::]*/: 'CEILING',
11402
	/*::[*/0x0121/*::]*/: 'HYPGEOMDIST',
11403
	/*::[*/0x0122/*::]*/: 'LOGNORMDIST',
11404
	/*::[*/0x0123/*::]*/: 'LOGINV',
11405
	/*::[*/0x0124/*::]*/: 'NEGBINOMDIST',
11406
	/*::[*/0x0125/*::]*/: 'NORMDIST',
11407
	/*::[*/0x0126/*::]*/: 'NORMSDIST',
11408
	/*::[*/0x0127/*::]*/: 'NORMINV',
11409
	/*::[*/0x0128/*::]*/: 'NORMSINV',
11410
	/*::[*/0x0129/*::]*/: 'STANDARDIZE',
11411
	/*::[*/0x012A/*::]*/: 'ODD',
11412
	/*::[*/0x012B/*::]*/: 'PERMUT',
11413
	/*::[*/0x012C/*::]*/: 'POISSON',
11414
	/*::[*/0x012D/*::]*/: 'TDIST',
11415
	/*::[*/0x012E/*::]*/: 'WEIBULL',
11416
	/*::[*/0x012F/*::]*/: 'SUMXMY2',
11417
	/*::[*/0x0130/*::]*/: 'SUMX2MY2',
11418
	/*::[*/0x0131/*::]*/: 'SUMX2PY2',
11419
	/*::[*/0x0132/*::]*/: 'CHITEST',
11420
	/*::[*/0x0133/*::]*/: 'CORREL',
11421
	/*::[*/0x0134/*::]*/: 'COVAR',
11422
	/*::[*/0x0135/*::]*/: 'FORECAST',
11423
	/*::[*/0x0136/*::]*/: 'FTEST',
11424
	/*::[*/0x0137/*::]*/: 'INTERCEPT',
11425
	/*::[*/0x0138/*::]*/: 'PEARSON',
11426
	/*::[*/0x0139/*::]*/: 'RSQ',
11427
	/*::[*/0x013A/*::]*/: 'STEYX',
11428
	/*::[*/0x013B/*::]*/: 'SLOPE',
11429
	/*::[*/0x013C/*::]*/: 'TTEST',
11430
	/*::[*/0x013D/*::]*/: 'PROB',
11431
	/*::[*/0x013E/*::]*/: 'DEVSQ',
11432
	/*::[*/0x013F/*::]*/: 'GEOMEAN',
11433
	/*::[*/0x0140/*::]*/: 'HARMEAN',
11434
	/*::[*/0x0141/*::]*/: 'SUMSQ',
11435
	/*::[*/0x0142/*::]*/: 'KURT',
11436
	/*::[*/0x0143/*::]*/: 'SKEW',
11437
	/*::[*/0x0144/*::]*/: 'ZTEST',
11438
	/*::[*/0x0145/*::]*/: 'LARGE',
11439
	/*::[*/0x0146/*::]*/: 'SMALL',
11440
	/*::[*/0x0147/*::]*/: 'QUARTILE',
11441
	/*::[*/0x0148/*::]*/: 'PERCENTILE',
11442
	/*::[*/0x0149/*::]*/: 'PERCENTRANK',
11443
	/*::[*/0x014A/*::]*/: 'MODE',
11444
	/*::[*/0x014B/*::]*/: 'TRIMMEAN',
11445
	/*::[*/0x014C/*::]*/: 'TINV',
11446
	/*::[*/0x014E/*::]*/: 'MOVIE.COMMAND',
11447
	/*::[*/0x014F/*::]*/: 'GET.MOVIE',
11448
	/*::[*/0x0150/*::]*/: 'CONCATENATE',
11449
	/*::[*/0x0151/*::]*/: 'POWER',
11450
	/*::[*/0x0152/*::]*/: 'PIVOT.ADD.DATA',
11451
	/*::[*/0x0153/*::]*/: 'GET.PIVOT.TABLE',
11452
	/*::[*/0x0154/*::]*/: 'GET.PIVOT.FIELD',
11453
	/*::[*/0x0155/*::]*/: 'GET.PIVOT.ITEM',
11454
	/*::[*/0x0156/*::]*/: 'RADIANS',
11455
	/*::[*/0x0157/*::]*/: 'DEGREES',
11456
	/*::[*/0x0158/*::]*/: 'SUBTOTAL',
11457
	/*::[*/0x0159/*::]*/: 'SUMIF',
11458
	/*::[*/0x015A/*::]*/: 'COUNTIF',
11459
	/*::[*/0x015B/*::]*/: 'COUNTBLANK',
11460
	/*::[*/0x015C/*::]*/: 'SCENARIO.GET',
11461
	/*::[*/0x015D/*::]*/: 'OPTIONS.LISTS.GET',
11462
	/*::[*/0x015E/*::]*/: 'ISPMT',
11463
	/*::[*/0x015F/*::]*/: 'DATEDIF',
11464
	/*::[*/0x0160/*::]*/: 'DATESTRING',
11465
	/*::[*/0x0161/*::]*/: 'NUMBERSTRING',
11466
	/*::[*/0x0162/*::]*/: 'ROMAN',
11467
	/*::[*/0x0163/*::]*/: 'OPEN.DIALOG',
11468
	/*::[*/0x0164/*::]*/: 'SAVE.DIALOG',
11469
	/*::[*/0x0165/*::]*/: 'VIEW.GET',
11470
	/*::[*/0x0166/*::]*/: 'GETPIVOTDATA',
11471
	/*::[*/0x0167/*::]*/: 'HYPERLINK',
11472
	/*::[*/0x0168/*::]*/: 'PHONETIC',
11473
	/*::[*/0x0169/*::]*/: 'AVERAGEA',
11474
	/*::[*/0x016A/*::]*/: 'MAXA',
11475
	/*::[*/0x016B/*::]*/: 'MINA',
11476
	/*::[*/0x016C/*::]*/: 'STDEVPA',
11477
	/*::[*/0x016D/*::]*/: 'VARPA',
11478
	/*::[*/0x016E/*::]*/: 'STDEVA',
11479
	/*::[*/0x016F/*::]*/: 'VARA',
11480
	/*::[*/0x0170/*::]*/: 'BAHTTEXT',
11481
	/*::[*/0x0171/*::]*/: 'THAIDAYOFWEEK',
11482
	/*::[*/0x0172/*::]*/: 'THAIDIGIT',
11483
	/*::[*/0x0173/*::]*/: 'THAIMONTHOFYEAR',
11484
	/*::[*/0x0174/*::]*/: 'THAINUMSOUND',
11485
	/*::[*/0x0175/*::]*/: 'THAINUMSTRING',
11486
	/*::[*/0x0176/*::]*/: 'THAISTRINGLENGTH',
11487
	/*::[*/0x0177/*::]*/: 'ISTHAIDIGIT',
11488
	/*::[*/0x0178/*::]*/: 'ROUNDBAHTDOWN',
11489
	/*::[*/0x0179/*::]*/: 'ROUNDBAHTUP',
11490
	/*::[*/0x017A/*::]*/: 'THAIYEAR',
11491
	/*::[*/0x017B/*::]*/: 'RTD',
11492
11493
	/*::[*/0x017C/*::]*/: 'CUBEVALUE',
11494
	/*::[*/0x017D/*::]*/: 'CUBEMEMBER',
11495
	/*::[*/0x017E/*::]*/: 'CUBEMEMBERPROPERTY',
11496
	/*::[*/0x017F/*::]*/: 'CUBERANKEDMEMBER',
11497
	/*::[*/0x0180/*::]*/: 'HEX2BIN',
11498
	/*::[*/0x0181/*::]*/: 'HEX2DEC',
11499
	/*::[*/0x0182/*::]*/: 'HEX2OCT',
11500
	/*::[*/0x0183/*::]*/: 'DEC2BIN',
11501
	/*::[*/0x0184/*::]*/: 'DEC2HEX',
11502
	/*::[*/0x0185/*::]*/: 'DEC2OCT',
11503
	/*::[*/0x0186/*::]*/: 'OCT2BIN',
11504
	/*::[*/0x0187/*::]*/: 'OCT2HEX',
11505
	/*::[*/0x0188/*::]*/: 'OCT2DEC',
11506
	/*::[*/0x0189/*::]*/: 'BIN2DEC',
11507
	/*::[*/0x018A/*::]*/: 'BIN2OCT',
11508
	/*::[*/0x018B/*::]*/: 'BIN2HEX',
11509
	/*::[*/0x018C/*::]*/: 'IMSUB',
11510
	/*::[*/0x018D/*::]*/: 'IMDIV',
11511
	/*::[*/0x018E/*::]*/: 'IMPOWER',
11512
	/*::[*/0x018F/*::]*/: 'IMABS',
11513
	/*::[*/0x0190/*::]*/: 'IMSQRT',
11514
	/*::[*/0x0191/*::]*/: 'IMLN',
11515
	/*::[*/0x0192/*::]*/: 'IMLOG2',
11516
	/*::[*/0x0193/*::]*/: 'IMLOG10',
11517
	/*::[*/0x0194/*::]*/: 'IMSIN',
11518
	/*::[*/0x0195/*::]*/: 'IMCOS',
11519
	/*::[*/0x0196/*::]*/: 'IMEXP',
11520
	/*::[*/0x0197/*::]*/: 'IMARGUMENT',
11521
	/*::[*/0x0198/*::]*/: 'IMCONJUGATE',
11522
	/*::[*/0x0199/*::]*/: 'IMAGINARY',
11523
	/*::[*/0x019A/*::]*/: 'IMREAL',
11524
	/*::[*/0x019B/*::]*/: 'COMPLEX',
11525
	/*::[*/0x019C/*::]*/: 'IMSUM',
11526
	/*::[*/0x019D/*::]*/: 'IMPRODUCT',
11527
	/*::[*/0x019E/*::]*/: 'SERIESSUM',
11528
	/*::[*/0x019F/*::]*/: 'FACTDOUBLE',
11529
	/*::[*/0x01A0/*::]*/: 'SQRTPI',
11530
	/*::[*/0x01A1/*::]*/: 'QUOTIENT',
11531
	/*::[*/0x01A2/*::]*/: 'DELTA',
11532
	/*::[*/0x01A3/*::]*/: 'GESTEP',
11533
	/*::[*/0x01A4/*::]*/: 'ISEVEN',
11534
	/*::[*/0x01A5/*::]*/: 'ISODD',
11535
	/*::[*/0x01A6/*::]*/: 'MROUND',
11536
	/*::[*/0x01A7/*::]*/: 'ERF',
11537
	/*::[*/0x01A8/*::]*/: 'ERFC',
11538
	/*::[*/0x01A9/*::]*/: 'BESSELJ',
11539
	/*::[*/0x01AA/*::]*/: 'BESSELK',
11540
	/*::[*/0x01AB/*::]*/: 'BESSELY',
11541
	/*::[*/0x01AC/*::]*/: 'BESSELI',
11542
	/*::[*/0x01AD/*::]*/: 'XIRR',
11543
	/*::[*/0x01AE/*::]*/: 'XNPV',
11544
	/*::[*/0x01AF/*::]*/: 'PRICEMAT',
11545
	/*::[*/0x01B0/*::]*/: 'YIELDMAT',
11546
	/*::[*/0x01B1/*::]*/: 'INTRATE',
11547
	/*::[*/0x01B2/*::]*/: 'RECEIVED',
11548
	/*::[*/0x01B3/*::]*/: 'DISC',
11549
	/*::[*/0x01B4/*::]*/: 'PRICEDISC',
11550
	/*::[*/0x01B5/*::]*/: 'YIELDDISC',
11551
	/*::[*/0x01B6/*::]*/: 'TBILLEQ',
11552
	/*::[*/0x01B7/*::]*/: 'TBILLPRICE',
11553
	/*::[*/0x01B8/*::]*/: 'TBILLYIELD',
11554
	/*::[*/0x01B9/*::]*/: 'PRICE',
11555
	/*::[*/0x01BA/*::]*/: 'YIELD',
11556
	/*::[*/0x01BB/*::]*/: 'DOLLARDE',
11557
	/*::[*/0x01BC/*::]*/: 'DOLLARFR',
11558
	/*::[*/0x01BD/*::]*/: 'NOMINAL',
11559
	/*::[*/0x01BE/*::]*/: 'EFFECT',
11560
	/*::[*/0x01BF/*::]*/: 'CUMPRINC',
11561
	/*::[*/0x01C0/*::]*/: 'CUMIPMT',
11562
	/*::[*/0x01C1/*::]*/: 'EDATE',
11563
	/*::[*/0x01C2/*::]*/: 'EOMONTH',
11564
	/*::[*/0x01C3/*::]*/: 'YEARFRAC',
11565
	/*::[*/0x01C4/*::]*/: 'COUPDAYBS',
11566
	/*::[*/0x01C5/*::]*/: 'COUPDAYS',
11567
	/*::[*/0x01C6/*::]*/: 'COUPDAYSNC',
11568
	/*::[*/0x01C7/*::]*/: 'COUPNCD',
11569
	/*::[*/0x01C8/*::]*/: 'COUPNUM',
11570
	/*::[*/0x01C9/*::]*/: 'COUPPCD',
11571
	/*::[*/0x01CA/*::]*/: 'DURATION',
11572
	/*::[*/0x01CB/*::]*/: 'MDURATION',
11573
	/*::[*/0x01CC/*::]*/: 'ODDLPRICE',
11574
	/*::[*/0x01CD/*::]*/: 'ODDLYIELD',
11575
	/*::[*/0x01CE/*::]*/: 'ODDFPRICE',
11576
	/*::[*/0x01CF/*::]*/: 'ODDFYIELD',
11577
	/*::[*/0x01D0/*::]*/: 'RANDBETWEEN',
11578
	/*::[*/0x01D1/*::]*/: 'WEEKNUM',
11579
	/*::[*/0x01D2/*::]*/: 'AMORDEGRC',
11580
	/*::[*/0x01D3/*::]*/: 'AMORLINC',
11581
	/*::[*/0x01D4/*::]*/: 'CONVERT',
11582
	/*::[*/0x02D4/*::]*/: 'SHEETJS',
11583
	/*::[*/0x01D5/*::]*/: 'ACCRINT',
11584
	/*::[*/0x01D6/*::]*/: 'ACCRINTM',
11585
	/*::[*/0x01D7/*::]*/: 'WORKDAY',
11586
	/*::[*/0x01D8/*::]*/: 'NETWORKDAYS',
11587
	/*::[*/0x01D9/*::]*/: 'GCD',
11588
	/*::[*/0x01DA/*::]*/: 'MULTINOMIAL',
11589
	/*::[*/0x01DB/*::]*/: 'LCM',
11590
	/*::[*/0x01DC/*::]*/: 'FVSCHEDULE',
11591
	/*::[*/0x01DD/*::]*/: 'CUBEKPIMEMBER',
11592
	/*::[*/0x01DE/*::]*/: 'CUBESET',
11593
	/*::[*/0x01DF/*::]*/: 'CUBESETCOUNT',
11594
	/*::[*/0x01E0/*::]*/: 'IFERROR',
11595
	/*::[*/0x01E1/*::]*/: 'COUNTIFS',
11596
	/*::[*/0x01E2/*::]*/: 'SUMIFS',
11597
	/*::[*/0x01E3/*::]*/: 'AVERAGEIF',
11598
	/*::[*/0x01E4/*::]*/: 'AVERAGEIFS'
11599
};
11600
var FtabArgc = {
11601
	/*::[*/0x0002/*::]*/: 1, /* ISNA */
11602
	/*::[*/0x0003/*::]*/: 1, /* ISERROR */
11603
	/*::[*/0x000A/*::]*/: 0, /* NA */
11604
	/*::[*/0x000F/*::]*/: 1, /* SIN */
11605
	/*::[*/0x0010/*::]*/: 1, /* COS */
11606
	/*::[*/0x0011/*::]*/: 1, /* TAN */
11607
	/*::[*/0x0012/*::]*/: 1, /* ATAN */
11608
	/*::[*/0x0013/*::]*/: 0, /* PI */
11609
	/*::[*/0x0014/*::]*/: 1, /* SQRT */
11610
	/*::[*/0x0015/*::]*/: 1, /* EXP */
11611
	/*::[*/0x0016/*::]*/: 1, /* LN */
11612
	/*::[*/0x0017/*::]*/: 1, /* LOG10 */
11613
	/*::[*/0x0018/*::]*/: 1, /* ABS */
11614
	/*::[*/0x0019/*::]*/: 1, /* INT */
11615
	/*::[*/0x001A/*::]*/: 1, /* SIGN */
11616
	/*::[*/0x001B/*::]*/: 2, /* ROUND */
11617
	/*::[*/0x001E/*::]*/: 2, /* REPT */
11618
	/*::[*/0x001F/*::]*/: 3, /* MID */
11619
	/*::[*/0x0020/*::]*/: 1, /* LEN */
11620
	/*::[*/0x0021/*::]*/: 1, /* VALUE */
11621
	/*::[*/0x0022/*::]*/: 0, /* TRUE */
11622
	/*::[*/0x0023/*::]*/: 0, /* FALSE */
11623
	/*::[*/0x0026/*::]*/: 1, /* NOT */
11624
	/*::[*/0x0027/*::]*/: 2, /* MOD */
11625
	/*::[*/0x0028/*::]*/: 3, /* DCOUNT */
11626
	/*::[*/0x0029/*::]*/: 3, /* DSUM */
11627
	/*::[*/0x002A/*::]*/: 3, /* DAVERAGE */
11628
	/*::[*/0x002B/*::]*/: 3, /* DMIN */
11629
	/*::[*/0x002C/*::]*/: 3, /* DMAX */
11630
	/*::[*/0x002D/*::]*/: 3, /* DSTDEV */
11631
	/*::[*/0x002F/*::]*/: 3, /* DVAR */
11632
	/*::[*/0x0030/*::]*/: 2, /* TEXT */
11633
	/*::[*/0x0035/*::]*/: 1, /* GOTO */
11634
	/*::[*/0x003D/*::]*/: 3, /* MIRR */
11635
	/*::[*/0x003F/*::]*/: 0, /* RAND */
11636
	/*::[*/0x0041/*::]*/: 3, /* DATE */
11637
	/*::[*/0x0042/*::]*/: 3, /* TIME */
11638
	/*::[*/0x0043/*::]*/: 1, /* DAY */
11639
	/*::[*/0x0044/*::]*/: 1, /* MONTH */
11640
	/*::[*/0x0045/*::]*/: 1, /* YEAR */
11641
	/*::[*/0x0046/*::]*/: 1, /* WEEKDAY */
11642
	/*::[*/0x0047/*::]*/: 1, /* HOUR */
11643
	/*::[*/0x0048/*::]*/: 1, /* MINUTE */
11644
	/*::[*/0x0049/*::]*/: 1, /* SECOND */
11645
	/*::[*/0x004A/*::]*/: 0, /* NOW */
11646
	/*::[*/0x004B/*::]*/: 1, /* AREAS */
11647
	/*::[*/0x004C/*::]*/: 1, /* ROWS */
11648
	/*::[*/0x004D/*::]*/: 1, /* COLUMNS */
11649
	/*::[*/0x004F/*::]*/: 2, /* ABSREF */
11650
	/*::[*/0x0050/*::]*/: 2, /* RELREF */
11651
	/*::[*/0x0053/*::]*/: 1, /* TRANSPOSE */
11652
	/*::[*/0x0055/*::]*/: 0, /* STEP */
11653
	/*::[*/0x0056/*::]*/: 1, /* TYPE */
11654
	/*::[*/0x0059/*::]*/: 0, /* CALLER */
11655
	/*::[*/0x005A/*::]*/: 1, /* DEREF */
11656
	/*::[*/0x005E/*::]*/: 0, /* ACTIVE.CELL */
11657
	/*::[*/0x005F/*::]*/: 0, /* SELECTION */
11658
	/*::[*/0x0061/*::]*/: 2, /* ATAN2 */
11659
	/*::[*/0x0062/*::]*/: 1, /* ASIN */
11660
	/*::[*/0x0063/*::]*/: 1, /* ACOS */
11661
	/*::[*/0x0065/*::]*/: 3, /* HLOOKUP */
11662
	/*::[*/0x0066/*::]*/: 3, /* VLOOKUP */
11663
	/*::[*/0x0069/*::]*/: 1, /* ISREF */
11664
	/*::[*/0x006A/*::]*/: 1, /* GET.FORMULA */
11665
	/*::[*/0x006C/*::]*/: 2, /* SET.VALUE */
11666
	/*::[*/0x006F/*::]*/: 1, /* CHAR */
11667
	/*::[*/0x0070/*::]*/: 1, /* LOWER */
11668
	/*::[*/0x0071/*::]*/: 1, /* UPPER */
11669
	/*::[*/0x0072/*::]*/: 1, /* PROPER */
11670
	/*::[*/0x0075/*::]*/: 2, /* EXACT */
11671
	/*::[*/0x0076/*::]*/: 1, /* TRIM */
11672
	/*::[*/0x0077/*::]*/: 4, /* REPLACE */
11673
	/*::[*/0x0079/*::]*/: 1, /* CODE */
11674
	/*::[*/0x007E/*::]*/: 1, /* ISERR */
11675
	/*::[*/0x007F/*::]*/: 1, /* ISTEXT */
11676
	/*::[*/0x0080/*::]*/: 1, /* ISNUMBER */
11677
	/*::[*/0x0081/*::]*/: 1, /* ISBLANK */
11678
	/*::[*/0x0082/*::]*/: 1, /* T */
11679
	/*::[*/0x0083/*::]*/: 1, /* N */
11680
	/*::[*/0x0085/*::]*/: 1, /* FCLOSE */
11681
	/*::[*/0x0086/*::]*/: 1, /* FSIZE */
11682
	/*::[*/0x0087/*::]*/: 1, /* FREADLN */
11683
	/*::[*/0x0088/*::]*/: 2, /* FREAD */
11684
	/*::[*/0x0089/*::]*/: 2, /* FWRITELN */
11685
	/*::[*/0x008A/*::]*/: 2, /* FWRITE */
11686
	/*::[*/0x008C/*::]*/: 1, /* DATEVALUE */
11687
	/*::[*/0x008D/*::]*/: 1, /* TIMEVALUE */
11688
	/*::[*/0x008E/*::]*/: 3, /* SLN */
11689
	/*::[*/0x008F/*::]*/: 4, /* SYD */
11690
	/*::[*/0x0090/*::]*/: 4, /* DDB */
11691
	/*::[*/0x00A1/*::]*/: 1, /* DIALOG.BOX */
11692
	/*::[*/0x00A2/*::]*/: 1, /* CLEAN */
11693
	/*::[*/0x00A3/*::]*/: 1, /* MDETERM */
11694
	/*::[*/0x00A4/*::]*/: 1, /* MINVERSE */
11695
	/*::[*/0x00A5/*::]*/: 2, /* MMULT */
11696
	/*::[*/0x00AC/*::]*/: 1, /* WHILE */
11697
	/*::[*/0x00AF/*::]*/: 2, /* INITIATE */
11698
	/*::[*/0x00B0/*::]*/: 2, /* REQUEST */
11699
	/*::[*/0x00B1/*::]*/: 3, /* POKE */
11700
	/*::[*/0x00B2/*::]*/: 2, /* EXECUTE */
11701
	/*::[*/0x00B3/*::]*/: 1, /* TERMINATE */
11702
	/*::[*/0x00B8/*::]*/: 1, /* FACT */
11703
	/*::[*/0x00BA/*::]*/: 1, /* GET.WORKSPACE */
11704
	/*::[*/0x00BD/*::]*/: 3, /* DPRODUCT */
11705
	/*::[*/0x00BE/*::]*/: 1, /* ISNONTEXT */
11706
	/*::[*/0x00C3/*::]*/: 3, /* DSTDEVP */
11707
	/*::[*/0x00C4/*::]*/: 3, /* DVARP */
11708
	/*::[*/0x00C5/*::]*/: 1, /* TRUNC */
11709
	/*::[*/0x00C6/*::]*/: 1, /* ISLOGICAL */
11710
	/*::[*/0x00C7/*::]*/: 3, /* DCOUNTA */
11711
	/*::[*/0x00C9/*::]*/: 1, /* UNREGISTER */
11712
	/*::[*/0x00CF/*::]*/: 4, /* REPLACEB */
11713
	/*::[*/0x00D2/*::]*/: 3, /* MIDB */
11714
	/*::[*/0x00D3/*::]*/: 1, /* LENB */
11715
	/*::[*/0x00D4/*::]*/: 2, /* ROUNDUP */
11716
	/*::[*/0x00D5/*::]*/: 2, /* ROUNDDOWN */
11717
	/*::[*/0x00D6/*::]*/: 1, /* ASC */
11718
	/*::[*/0x00D7/*::]*/: 1, /* DBCS */
11719
	/*::[*/0x00E1/*::]*/: 0, /* END.IF */
11720
	/*::[*/0x00E5/*::]*/: 1, /* SINH */
11721
	/*::[*/0x00E6/*::]*/: 1, /* COSH */
11722
	/*::[*/0x00E7/*::]*/: 1, /* TANH */
11723
	/*::[*/0x00E8/*::]*/: 1, /* ASINH */
11724
	/*::[*/0x00E9/*::]*/: 1, /* ACOSH */
11725
	/*::[*/0x00EA/*::]*/: 1, /* ATANH */
11726
	/*::[*/0x00EB/*::]*/: 3, /* DGET */
11727
	/*::[*/0x00F4/*::]*/: 1, /* INFO */
11728
	/*::[*/0x00F7/*::]*/: 4, /* DB */
11729
	/*::[*/0x00FC/*::]*/: 2, /* FREQUENCY */
11730
	/*::[*/0x0101/*::]*/: 1, /* EVALUATE */
11731
	/*::[*/0x0105/*::]*/: 1, /* ERROR.TYPE */
11732
	/*::[*/0x010F/*::]*/: 1, /* GAMMALN */
11733
	/*::[*/0x0111/*::]*/: 4, /* BINOMDIST */
11734
	/*::[*/0x0112/*::]*/: 2, /* CHIDIST */
11735
	/*::[*/0x0113/*::]*/: 2, /* CHIINV */
11736
	/*::[*/0x0114/*::]*/: 2, /* COMBIN */
11737
	/*::[*/0x0115/*::]*/: 3, /* CONFIDENCE */
11738
	/*::[*/0x0116/*::]*/: 3, /* CRITBINOM */
11739
	/*::[*/0x0117/*::]*/: 1, /* EVEN */
11740
	/*::[*/0x0118/*::]*/: 3, /* EXPONDIST */
11741
	/*::[*/0x0119/*::]*/: 3, /* FDIST */
11742
	/*::[*/0x011A/*::]*/: 3, /* FINV */
11743
	/*::[*/0x011B/*::]*/: 1, /* FISHER */
11744
	/*::[*/0x011C/*::]*/: 1, /* FISHERINV */
11745
	/*::[*/0x011D/*::]*/: 2, /* FLOOR */
11746
	/*::[*/0x011E/*::]*/: 4, /* GAMMADIST */
11747
	/*::[*/0x011F/*::]*/: 3, /* GAMMAINV */
11748
	/*::[*/0x0120/*::]*/: 2, /* CEILING */
11749
	/*::[*/0x0121/*::]*/: 4, /* HYPGEOMDIST */
11750
	/*::[*/0x0122/*::]*/: 3, /* LOGNORMDIST */
11751
	/*::[*/0x0123/*::]*/: 3, /* LOGINV */
11752
	/*::[*/0x0124/*::]*/: 3, /* NEGBINOMDIST */
11753
	/*::[*/0x0125/*::]*/: 4, /* NORMDIST */
11754
	/*::[*/0x0126/*::]*/: 1, /* NORMSDIST */
11755
	/*::[*/0x0127/*::]*/: 3, /* NORMINV */
11756
	/*::[*/0x0128/*::]*/: 1, /* NORMSINV */
11757
	/*::[*/0x0129/*::]*/: 3, /* STANDARDIZE */
11758
	/*::[*/0x012A/*::]*/: 1, /* ODD */
11759
	/*::[*/0x012B/*::]*/: 2, /* PERMUT */
11760
	/*::[*/0x012C/*::]*/: 3, /* POISSON */
11761
	/*::[*/0x012D/*::]*/: 3, /* TDIST */
11762
	/*::[*/0x012E/*::]*/: 4, /* WEIBULL */
11763
	/*::[*/0x012F/*::]*/: 2, /* SUMXMY2 */
11764
	/*::[*/0x0130/*::]*/: 2, /* SUMX2MY2 */
11765
	/*::[*/0x0131/*::]*/: 2, /* SUMX2PY2 */
11766
	/*::[*/0x0132/*::]*/: 2, /* CHITEST */
11767
	/*::[*/0x0133/*::]*/: 2, /* CORREL */
11768
	/*::[*/0x0134/*::]*/: 2, /* COVAR */
11769
	/*::[*/0x0135/*::]*/: 3, /* FORECAST */
11770
	/*::[*/0x0136/*::]*/: 2, /* FTEST */
11771
	/*::[*/0x0137/*::]*/: 2, /* INTERCEPT */
11772
	/*::[*/0x0138/*::]*/: 2, /* PEARSON */
11773
	/*::[*/0x0139/*::]*/: 2, /* RSQ */
11774
	/*::[*/0x013A/*::]*/: 2, /* STEYX */
11775
	/*::[*/0x013B/*::]*/: 2, /* SLOPE */
11776
	/*::[*/0x013C/*::]*/: 4, /* TTEST */
11777
	/*::[*/0x0145/*::]*/: 2, /* LARGE */
11778
	/*::[*/0x0146/*::]*/: 2, /* SMALL */
11779
	/*::[*/0x0147/*::]*/: 2, /* QUARTILE */
11780
	/*::[*/0x0148/*::]*/: 2, /* PERCENTILE */
11781
	/*::[*/0x014B/*::]*/: 2, /* TRIMMEAN */
11782
	/*::[*/0x014C/*::]*/: 2, /* TINV */
11783
	/*::[*/0x0151/*::]*/: 2, /* POWER */
11784
	/*::[*/0x0156/*::]*/: 1, /* RADIANS */
11785
	/*::[*/0x0157/*::]*/: 1, /* DEGREES */
11786
	/*::[*/0x015A/*::]*/: 2, /* COUNTIF */
11787
	/*::[*/0x015B/*::]*/: 1, /* COUNTBLANK */
11788
	/*::[*/0x015E/*::]*/: 4, /* ISPMT */
11789
	/*::[*/0x015F/*::]*/: 3, /* DATEDIF */
11790
	/*::[*/0x0160/*::]*/: 1, /* DATESTRING */
11791
	/*::[*/0x0161/*::]*/: 2, /* NUMBERSTRING */
11792
	/*::[*/0x0168/*::]*/: 1, /* PHONETIC */
11793
	/*::[*/0x0170/*::]*/: 1, /* BAHTTEXT */
11794
	/*::[*/0x0171/*::]*/: 1, /* THAIDAYOFWEEK */
11795
	/*::[*/0x0172/*::]*/: 1, /* THAIDIGIT */
11796
	/*::[*/0x0173/*::]*/: 1, /* THAIMONTHOFYEAR */
11797
	/*::[*/0x0174/*::]*/: 1, /* THAINUMSOUND */
11798
	/*::[*/0x0175/*::]*/: 1, /* THAINUMSTRING */
11799
	/*::[*/0x0176/*::]*/: 1, /* THAISTRINGLENGTH */
11800
	/*::[*/0x0177/*::]*/: 1, /* ISTHAIDIGIT */
11801
	/*::[*/0x0178/*::]*/: 1, /* ROUNDBAHTDOWN */
11802
	/*::[*/0x0179/*::]*/: 1, /* ROUNDBAHTUP */
11803
	/*::[*/0x017A/*::]*/: 1, /* THAIYEAR */
11804
	/*::[*/0x017E/*::]*/: 3, /* CUBEMEMBERPROPERTY */
11805
	/*::[*/0x0181/*::]*/: 1, /* HEX2DEC */
11806
	/*::[*/0x0188/*::]*/: 1, /* OCT2DEC */
11807
	/*::[*/0x0189/*::]*/: 1, /* BIN2DEC */
11808
	/*::[*/0x018C/*::]*/: 2, /* IMSUB */
11809
	/*::[*/0x018D/*::]*/: 2, /* IMDIV */
11810
	/*::[*/0x018E/*::]*/: 2, /* IMPOWER */
11811
	/*::[*/0x018F/*::]*/: 1, /* IMABS */
11812
	/*::[*/0x0190/*::]*/: 1, /* IMSQRT */
11813
	/*::[*/0x0191/*::]*/: 1, /* IMLN */
11814
	/*::[*/0x0192/*::]*/: 1, /* IMLOG2 */
11815
	/*::[*/0x0193/*::]*/: 1, /* IMLOG10 */
11816
	/*::[*/0x0194/*::]*/: 1, /* IMSIN */
11817
	/*::[*/0x0195/*::]*/: 1, /* IMCOS */
11818
	/*::[*/0x0196/*::]*/: 1, /* IMEXP */
11819
	/*::[*/0x0197/*::]*/: 1, /* IMARGUMENT */
11820
	/*::[*/0x0198/*::]*/: 1, /* IMCONJUGATE */
11821
	/*::[*/0x0199/*::]*/: 1, /* IMAGINARY */
11822
	/*::[*/0x019A/*::]*/: 1, /* IMREAL */
11823
	/*::[*/0x019E/*::]*/: 4, /* SERIESSUM */
11824
	/*::[*/0x019F/*::]*/: 1, /* FACTDOUBLE */
11825
	/*::[*/0x01A0/*::]*/: 1, /* SQRTPI */
11826
	/*::[*/0x01A1/*::]*/: 2, /* QUOTIENT */
11827
	/*::[*/0x01A4/*::]*/: 1, /* ISEVEN */
11828
	/*::[*/0x01A5/*::]*/: 1, /* ISODD */
11829
	/*::[*/0x01A6/*::]*/: 2, /* MROUND */
11830
	/*::[*/0x01A8/*::]*/: 1, /* ERFC */
11831
	/*::[*/0x01A9/*::]*/: 2, /* BESSELJ */
11832
	/*::[*/0x01AA/*::]*/: 2, /* BESSELK */
11833
	/*::[*/0x01AB/*::]*/: 2, /* BESSELY */
11834
	/*::[*/0x01AC/*::]*/: 2, /* BESSELI */
11835
	/*::[*/0x01AE/*::]*/: 3, /* XNPV */
11836
	/*::[*/0x01B6/*::]*/: 3, /* TBILLEQ */
11837
	/*::[*/0x01B7/*::]*/: 3, /* TBILLPRICE */
11838
	/*::[*/0x01B8/*::]*/: 3, /* TBILLYIELD */
11839
	/*::[*/0x01BB/*::]*/: 2, /* DOLLARDE */
11840
	/*::[*/0x01BC/*::]*/: 2, /* DOLLARFR */
11841
	/*::[*/0x01BD/*::]*/: 2, /* NOMINAL */
11842
	/*::[*/0x01BE/*::]*/: 2, /* EFFECT */
11843
	/*::[*/0x01BF/*::]*/: 6, /* CUMPRINC */
11844
	/*::[*/0x01C0/*::]*/: 6, /* CUMIPMT */
11845
	/*::[*/0x01C1/*::]*/: 2, /* EDATE */
11846
	/*::[*/0x01C2/*::]*/: 2, /* EOMONTH */
11847
	/*::[*/0x01D0/*::]*/: 2, /* RANDBETWEEN */
11848
	/*::[*/0x01D4/*::]*/: 3, /* CONVERT */
11849
	/*::[*/0x01DC/*::]*/: 2, /* FVSCHEDULE */
11850
	/*::[*/0x01DF/*::]*/: 1, /* CUBESETCOUNT */
11851
	/*::[*/0x01E0/*::]*/: 2, /* IFERROR */
11852
	/*::[*/0xFFFF/*::]*/: 0
11853
};
11854
/* [MS-XLSX] 2.2.3 Functions */
11855
/* [MS-XLSB] 2.5.97.10 Ftab */
11856
var XLSXFutureFunctions = {
11857
	"_xlfn.ACOT": "ACOT",
11858
	"_xlfn.ACOTH": "ACOTH",
11859
	"_xlfn.AGGREGATE": "AGGREGATE",
11860
	"_xlfn.ARABIC": "ARABIC",
11861
	"_xlfn.AVERAGEIF": "AVERAGEIF",
11862
	"_xlfn.AVERAGEIFS": "AVERAGEIFS",
11863
	"_xlfn.BASE": "BASE",
11864
	"_xlfn.BETA.DIST": "BETA.DIST",
11865
	"_xlfn.BETA.INV": "BETA.INV",
11866
	"_xlfn.BINOM.DIST": "BINOM.DIST",
11867
	"_xlfn.BINOM.DIST.RANGE": "BINOM.DIST.RANGE",
11868
	"_xlfn.BINOM.INV": "BINOM.INV",
11869
	"_xlfn.BITAND": "BITAND",
11870
	"_xlfn.BITLSHIFT": "BITLSHIFT",
11871
	"_xlfn.BITOR": "BITOR",
11872
	"_xlfn.BITRSHIFT": "BITRSHIFT",
11873
	"_xlfn.BITXOR": "BITXOR",
11874
	"_xlfn.CEILING.MATH": "CEILING.MATH",
11875
	"_xlfn.CEILING.PRECISE": "CEILING.PRECISE",
11876
	"_xlfn.CHISQ.DIST": "CHISQ.DIST",
11877
	"_xlfn.CHISQ.DIST.RT": "CHISQ.DIST.RT",
11878
	"_xlfn.CHISQ.INV": "CHISQ.INV",
11879
	"_xlfn.CHISQ.INV.RT": "CHISQ.INV.RT",
11880
	"_xlfn.CHISQ.TEST": "CHISQ.TEST",
11881
	"_xlfn.COMBINA": "COMBINA",
11882
	"_xlfn.CONCAT": "CONCAT",
11883
	"_xlfn.CONFIDENCE.NORM": "CONFIDENCE.NORM",
11884
	"_xlfn.CONFIDENCE.T": "CONFIDENCE.T",
11885
	"_xlfn.COT": "COT",
11886
	"_xlfn.COTH": "COTH",
11887
	"_xlfn.COUNTIFS": "COUNTIFS",
11888
	"_xlfn.COVARIANCE.P": "COVARIANCE.P",
11889
	"_xlfn.COVARIANCE.S": "COVARIANCE.S",
11890
	"_xlfn.CSC": "CSC",
11891
	"_xlfn.CSCH": "CSCH",
11892
	"_xlfn.DAYS": "DAYS",
11893
	"_xlfn.DECIMAL": "DECIMAL",
11894
	"_xlfn.ECMA.CEILING": "ECMA.CEILING",
11895
	"_xlfn.ERF.PRECISE": "ERF.PRECISE",
11896
	"_xlfn.ERFC.PRECISE": "ERFC.PRECISE",
11897
	"_xlfn.EXPON.DIST": "EXPON.DIST",
11898
	"_xlfn.F.DIST": "F.DIST",
11899
	"_xlfn.F.DIST.RT": "F.DIST.RT",
11900
	"_xlfn.F.INV": "F.INV",
11901
	"_xlfn.F.INV.RT": "F.INV.RT",
11902
	"_xlfn.F.TEST": "F.TEST",
11903
	"_xlfn.FILTERXML": "FILTERXML",
11904
	"_xlfn.FLOOR.MATH": "FLOOR.MATH",
11905
	"_xlfn.FLOOR.PRECISE": "FLOOR.PRECISE",
11906
	"_xlfn.FORECAST.ETS": "FORECAST.ETS",
11907
	"_xlfn.FORECAST.ETS.CONFINT": "FORECAST.ETS.CONFINT",
11908
	"_xlfn.FORECAST.ETS.SEASONALITY": "FORECAST.ETS.SEASONALITY",
11909
	"_xlfn.FORECAST.ETS.STAT": "FORECAST.ETS.STAT",
11910
	"_xlfn.FORECAST.LINEAR": "FORECAST.LINEAR",
11911
	"_xlfn.FORMULATEXT": "FORMULATEXT",
11912
	"_xlfn.GAMMA": "GAMMA",
11913
	"_xlfn.GAMMA.DIST": "GAMMA.DIST",
11914
	"_xlfn.GAMMA.INV": "GAMMA.INV",
11915
	"_xlfn.GAMMALN.PRECISE": "GAMMALN.PRECISE",
11916
	"_xlfn.GAUSS": "GAUSS",
11917
	"_xlfn.HYPGEOM.DIST": "HYPGEOM.DIST",
11918
	"_xlfn.IFERROR": "IFERROR",
11919
	"_xlfn.IFNA": "IFNA",
11920
	"_xlfn.IFS": "IFS",
11921
	"_xlfn.IMCOSH": "IMCOSH",
11922
	"_xlfn.IMCOT": "IMCOT",
11923
	"_xlfn.IMCSC": "IMCSC",
11924
	"_xlfn.IMCSCH": "IMCSCH",
11925
	"_xlfn.IMSEC": "IMSEC",
11926
	"_xlfn.IMSECH": "IMSECH",
11927
	"_xlfn.IMSINH": "IMSINH",
11928
	"_xlfn.IMTAN": "IMTAN",
11929
	"_xlfn.ISFORMULA": "ISFORMULA",
11930
	"_xlfn.ISO.CEILING": "ISO.CEILING",
11931
	"_xlfn.ISOWEEKNUM": "ISOWEEKNUM",
11932
	"_xlfn.LOGNORM.DIST": "LOGNORM.DIST",
11933
	"_xlfn.LOGNORM.INV": "LOGNORM.INV",
11934
	"_xlfn.MAXIFS": "MAXIFS",
11935
	"_xlfn.MINIFS": "MINIFS",
11936
	"_xlfn.MODE.MULT": "MODE.MULT",
11937
	"_xlfn.MODE.SNGL": "MODE.SNGL",
11938
	"_xlfn.MUNIT": "MUNIT",
11939
	"_xlfn.NEGBINOM.DIST": "NEGBINOM.DIST",
11940
	"_xlfn.NETWORKDAYS.INTL": "NETWORKDAYS.INTL",
11941
	"_xlfn.NIGBINOM": "NIGBINOM",
11942
	"_xlfn.NORM.DIST": "NORM.DIST",
11943
	"_xlfn.NORM.INV": "NORM.INV",
11944
	"_xlfn.NORM.S.DIST": "NORM.S.DIST",
11945
	"_xlfn.NORM.S.INV": "NORM.S.INV",
11946
	"_xlfn.NUMBERVALUE": "NUMBERVALUE",
11947
	"_xlfn.PDURATION": "PDURATION",
11948
	"_xlfn.PERCENTILE.EXC": "PERCENTILE.EXC",
11949
	"_xlfn.PERCENTILE.INC": "PERCENTILE.INC",
11950
	"_xlfn.PERCENTRANK.EXC": "PERCENTRANK.EXC",
11951
	"_xlfn.PERCENTRANK.INC": "PERCENTRANK.INC",
11952
	"_xlfn.PERMUTATIONA": "PERMUTATIONA",
11953
	"_xlfn.PHI": "PHI",
11954
	"_xlfn.POISSON.DIST": "POISSON.DIST",
11955
	"_xlfn.QUARTILE.EXC": "QUARTILE.EXC",
11956
	"_xlfn.QUARTILE.INC": "QUARTILE.INC",
11957
	"_xlfn.QUERYSTRING": "QUERYSTRING",
11958
	"_xlfn.RANK.AVG": "RANK.AVG",
11959
	"_xlfn.RANK.EQ": "RANK.EQ",
11960
	"_xlfn.RRI": "RRI",
11961
	"_xlfn.SEC": "SEC",
11962
	"_xlfn.SECH": "SECH",
11963
	"_xlfn.SHEET": "SHEET",
11964
	"_xlfn.SHEETS": "SHEETS",
11965
	"_xlfn.SKEW.P": "SKEW.P",
11966
	"_xlfn.STDEV.P": "STDEV.P",
11967
	"_xlfn.STDEV.S": "STDEV.S",
11968
	"_xlfn.SUMIFS": "SUMIFS",
11969
	"_xlfn.SWITCH": "SWITCH",
11970
	"_xlfn.T.DIST": "T.DIST",
11971
	"_xlfn.T.DIST.2T": "T.DIST.2T",
11972
	"_xlfn.T.DIST.RT": "T.DIST.RT",
11973
	"_xlfn.T.INV": "T.INV",
11974
	"_xlfn.T.INV.2T": "T.INV.2T",
11975
	"_xlfn.T.TEST": "T.TEST",
11976
	"_xlfn.TEXTJOIN": "TEXTJOIN",
11977
	"_xlfn.UNICHAR": "UNICHAR",
11978
	"_xlfn.UNICODE": "UNICODE",
11979
	"_xlfn.VAR.P": "VAR.P",
11980
	"_xlfn.VAR.S": "VAR.S",
11981
	"_xlfn.WEBSERVICE": "WEBSERVICE",
11982
	"_xlfn.WEIBULL.DIST": "WEIBULL.DIST",
11983
	"_xlfn.WORKDAY.INTL": "WORKDAY.INTL",
11984
	"_xlfn.XOR": "XOR",
11985
	"_xlfn.Z.TEST": "Z.TEST"
11986
};
11987
11988
/* Part 3 TODO: actually parse formulae */
11989
function ods_to_csf_formula(f/*:string*/)/*:string*/ {
11990
	if(f.slice(0,3) == "of:") f = f.slice(3);
11991
	/* 5.2 Basic Expressions */
11992
	if(f.charCodeAt(0) == 61) {
11993
		f = f.slice(1);
11994
		if(f.charCodeAt(0) == 61) f = f.slice(1);
11995
	}
11996
	f = f.replace(/COM\.MICROSOFT\./g, "");
11997
	/* Part 3 Section 5.8 References */
11998
	f = f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, function($$, $1) { return $1.replace(/\./g,""); });
11999
	/* TODO: something other than this */
12000
	f = f.replace(/\[.(#[A-Z]*[?!])\]/g, "$1");
12001
	return f.replace(/[;~]/g,",").replace(/\|/g,";");
12002
}
12003
12004
function csf_to_ods_formula(f/*:string*/)/*:string*/ {
12005
	var o = "of:=" + f.replace(crefregex, "$1[.$2$3$4$5]").replace(/\]:\[/g,":");
12006
	/* TODO: something other than this */
12007
	return o.replace(/;/g, "|").replace(/,/g,";");
12008
}
12009
12010
function ods_to_csf_3D(r/*:string*/)/*:[string, string]*/ {
12011
	var a = r.split(":");
12012
	var s = a[0].split(".")[0];
12013
	return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
12014
}
12015
12016
function csf_to_ods_3D(r/*:string*/)/*:string*/ {
12017
	return r.replace(/\./,"!");
12018
}
12019
12020
var strs = {}; // shared strings
12021
var _ssfopts = {}; // spreadsheet formatting options
12022
12023
RELS.WS = [
12024
	"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
12025
	"http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
12026
];
12027
12028
/*global Map */
12029
var browser_has_Map = typeof Map !== 'undefined';
12030
12031
function get_sst_id(sst/*:SST*/, str/*:string*/, rev)/*:number*/ {
12032
	var i = 0, len = sst.length;
12033
	if(rev) {
12034
		if(browser_has_Map ? rev.has(str) : rev.hasOwnProperty(str)) {
12035
			var revarr = browser_has_Map ? rev.get(str) : rev[str];
12036
			for(; i < revarr.length; ++i) {
12037
				if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
12038
			}
12039
		}
12040
	} else for(; i < len; ++i) {
12041
		if(sst[i].t === str) { sst.Count ++; return i; }
12042
	}
12043
	sst[len] = ({t:str}/*:any*/); sst.Count ++; sst.Unique ++;
12044
	if(rev) {
12045
		if(browser_has_Map) {
12046
			if(!rev.has(str)) rev.set(str, []);
12047
			rev.get(str).push(len);
12048
		} else {
12049
			if(!rev.hasOwnProperty(str)) rev[str] = [];
12050
			rev[str].push(len);
12051
		}
12052
	}
12053
	return len;
12054
}
12055
12056
function col_obj_w(C/*:number*/, col) {
12057
	var p = ({min:C+1,max:C+1}/*:any*/);
12058
	/* wch (chars), wpx (pixels) */
12059
	var wch = -1;
12060
	if(col.MDW) MDW = col.MDW;
12061
	if(col.width != null) p.customWidth = 1;
12062
	else if(col.wpx != null) wch = px2char(col.wpx);
12063
	else if(col.wch != null) wch = col.wch;
12064
	if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
12065
	else if(col.width != null) p.width = col.width;
12066
	if(col.hidden) p.hidden = true;
12067
	return p;
12068
}
12069
12070
function default_margins(margins/*:Margins*/, mode/*:?string*/) {
12071
	if(!margins) return;
12072
	var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
12073
	if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
12074
	if(margins.left   == null) margins.left   = defs[0];
12075
	if(margins.right  == null) margins.right  = defs[1];
12076
	if(margins.top    == null) margins.top    = defs[2];
12077
	if(margins.bottom == null) margins.bottom = defs[3];
12078
	if(margins.header == null) margins.header = defs[4];
12079
	if(margins.footer == null) margins.footer = defs[5];
12080
}
12081
12082
function get_cell_style(styles/*:Array<any>*/, cell/*:Cell*/, opts) {
12083
	var z = opts.revssf[cell.z != null ? cell.z : "General"];
12084
	var i = 0x3c, len = styles.length;
12085
	if(z == null && opts.ssf) {
12086
		for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
12087
			SSF.load(cell.z, i);
12088
			// $FlowIgnore
12089
			opts.ssf[i] = cell.z;
12090
			opts.revssf[cell.z] = z = i;
12091
			break;
12092
		}
12093
	}
12094
	for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
12095
	styles[len] = {
12096
		numFmtId:z,
12097
		fontId:0,
12098
		fillId:0,
12099
		borderId:0,
12100
		xfId:0,
12101
		applyNumberFormat:1
12102
	};
12103
	return len;
12104
}
12105
12106
function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles) {
12107
	if(p.t === 'z') return;
12108
	if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
12109
	try {
12110
		if(opts.cellNF) p.z = SSF._table[fmtid];
12111
	} catch(e) { if(opts.WTF) throw e; }
12112
	if(!opts || opts.cellText !== false) try {
12113
		if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
12114
		if(p.t === 'e') p.w = p.w || BErr[p.v];
12115
		else if(fmtid === 0) {
12116
			if(p.t === 'n') {
12117
				if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
12118
				else p.w = SSF._general_num(p.v);
12119
			}
12120
			else if(p.t === 'd') {
12121
				var dd = datenum(p.v);
12122
				if((dd|0) === dd) p.w = SSF._general_int(dd);
12123
				else p.w = SSF._general_num(dd);
12124
			}
12125
			else if(p.v === undefined) return "";
12126
			else p.w = SSF._general(p.v,_ssfopts);
12127
		}
12128
		else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
12129
		else p.w = SSF.format(fmtid,p.v,_ssfopts);
12130
	} catch(e) { if(opts.WTF) throw e; }
12131
	if(!opts.cellStyles) return;
12132
	if(fillid != null) try {
12133
		p.s = styles.Fills[fillid];
12134
		if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
12135
			p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
12136
			if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
12137
		}
12138
		if (p.s.bgColor && p.s.bgColor.theme) {
12139
			p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
12140
			if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
12141
		}
12142
	} catch(e) { if(opts.WTF && styles.Fills) throw e; }
12143
}
12144
12145
function check_ws(ws/*:Worksheet*/, sname/*:string*/, i/*:number*/) {
12146
	if(ws && ws['!ref']) {
12147
		var range = safe_decode_range(ws['!ref']);
12148
		if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
12149
	}
12150
}
12151
function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
12152
	var d = safe_decode_range(s);
12153
	if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
12154
}
12155
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
12156
var sheetdataregex = /<(?:\w+:)?sheetData>([\s\S]*)<\/(?:\w+:)?sheetData>/;
12157
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
12158
var dimregex = /"(\w*:\w*)"/;
12159
var colregex = /<(?:\w:)?col[^>]*[\/]?>/g;
12160
var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
12161
var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
12162
var sheetprregex = /<(?:\w:)?sheetPr(?:[^>a-z][^>]*)?\/>/;
12163
var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
12164
/* 18.3 Worksheets */
12165
function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ {
12166
	if(!data) return data;
12167
	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
12168
12169
	/* 18.3.1.99 worksheet CT_Worksheet */
12170
	var s = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
12171
	var refguess/*:Range*/ = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} }/*:any*/);
12172
12173
	var data1 = "", data2 = "";
12174
	var mtch/*:?any*/ = data.match(sheetdataregex);
12175
	if(mtch) {
12176
		data1 = data.slice(0, mtch.index);
12177
		data2 = data.slice(mtch.index + mtch[0].length);
12178
	} else data1 = data2 = data;
12179
12180
	/* 18.3.1.82 sheetPr CT_SheetPr */
12181
	var sheetPr = data1.match(sheetprregex);
12182
	if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
12183
12184
	/* 18.3.1.35 dimension CT_SheetDimension */
12185
	// $FlowIgnore
12186
	var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
12187
	if(ridx > 0) {
12188
		var ref = data1.slice(ridx,ridx+50).match(dimregex);
12189
		if(ref) parse_ws_xml_dim(s, ref[1]);
12190
	}
12191
12192
	/* 18.3.1.88 sheetViews CT_SheetViews */
12193
	var svs = data1.match(svsregex);
12194
	if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
12195
12196
	/* 18.3.1.17 cols CT_Cols */
12197
	var columns/*:Array<ColInfo>*/ = [];
12198
	if(opts.cellStyles) {
12199
		/* 18.3.1.13 col CT_Col */
12200
		var cols = data1.match(colregex);
12201
		if(cols) parse_ws_xml_cols(columns, cols);
12202
	}
12203
12204
	/* 18.3.1.80 sheetData CT_SheetData ? */
12205
	if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
12206
12207
	/* 18.3.1.2  autoFilter CT_AutoFilter */
12208
	var afilter = data2.match(afregex);
12209
	if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
12210
12211
	/* 18.3.1.55 mergeCells CT_MergeCells */
12212
	var merges/*:Array<Range>*/ = [];
12213
	var _merge = data2.match(mergecregex);
12214
	if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
12215
		merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
12216
12217
	/* 18.3.1.48 hyperlinks CT_Hyperlinks */
12218
	var hlink = data2.match(hlinkregex);
12219
	if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
12220
12221
	/* 18.3.1.62 pageMargins CT_PageMargins */
12222
	var margins = data2.match(marginregex);
12223
	if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
12224
12225
	if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
12226
	if(opts.sheetRows > 0 && s["!ref"]) {
12227
		var tmpref = safe_decode_range(s["!ref"]);
12228
		if(opts.sheetRows <= +tmpref.e.r) {
12229
			tmpref.e.r = opts.sheetRows - 1;
12230
			if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
12231
			if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
12232
			if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
12233
			if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
12234
			s["!fullref"] = s["!ref"];
12235
			s["!ref"] = encode_range(tmpref);
12236
		}
12237
	}
12238
	if(columns.length > 0) s["!cols"] = columns;
12239
	if(merges.length > 0) s["!merges"] = merges;
12240
	return s;
12241
}
12242
12243
function write_ws_xml_merges(merges/*:Array<Range>*/)/*:string*/ {
12244
	if(merges.length === 0) return "";
12245
	var o = '<mergeCells count="' + merges.length + '">';
12246
	for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
12247
	return o + '</mergeCells>';
12248
}
12249
12250
/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
12251
function parse_ws_xml_sheetpr(sheetPr/*:string*/, s, wb/*:WBWBProps*/, idx/*:number*/) {
12252
	var data = parsexmltag(sheetPr);
12253
	if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
12254
	if(data.codeName) wb.Sheets[idx].CodeName = data.codeName;
12255
}
12256
12257
/* 18.3.1.85 sheetProtection CT_SheetProtection */
12258
function write_ws_xml_protection(sp)/*:string*/ {
12259
	// algorithmName, hashValue, saltValue, spinCountpassword
12260
	var o = ({sheet:1}/*:any*/);
12261
	var deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
12262
	var deftrue = [
12263
		"formatColumns", "formatRows", "formatCells",
12264
		"insertColumns", "insertRows", "insertHyperlinks",
12265
		"deleteColumns", "deleteRows",
12266
		"sort", "autoFilter", "pivotTables"
12267
	];
12268
	deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
12269
	deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
12270
	/* TODO: algorithm */
12271
	if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
12272
	return writextag('sheetProtection', null, o);
12273
}
12274
12275
function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
12276
	var dense = Array.isArray(s);
12277
	for(var i = 0; i != data.length; ++i) {
12278
		var val = parsexmltag(utf8read(data[i]), true);
12279
		if(!val.ref) return;
12280
		var rel = ((rels || {})['!id']||[])[val.id];
12281
		if(rel) {
12282
			val.Target = rel.Target;
12283
			if(val.location) val.Target += "#"+val.location;
12284
		} else {
12285
			val.Target = "#" + val.location;
12286
			rel = {Target: val.Target, TargetMode: 'Internal'};
12287
		}
12288
		val.Rel = rel;
12289
		if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
12290
		var rng = safe_decode_range(val.ref);
12291
		for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
12292
			var addr = encode_cell({c:C,r:R});
12293
			if(dense) {
12294
				if(!s[R]) s[R] = [];
12295
				if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
12296
				s[R][C].l = val;
12297
			} else {
12298
				if(!s[addr]) s[addr] = {t:"z",v:undefined};
12299
				s[addr].l = val;
12300
			}
12301
		}
12302
	}
12303
}
12304
12305
function parse_ws_xml_margins(margin) {
12306
	var o = {};
12307
	["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
12308
		if(margin[k]) o[k] = parseFloat(margin[k]);
12309
	});
12310
	return o;
12311
}
12312
function write_ws_xml_margins(margin)/*:string*/ {
12313
	default_margins(margin);
12314
	return writextag('pageMargins', null, margin);
12315
}
12316
12317
function parse_ws_xml_cols(columns, cols) {
12318
	var seencol = false;
12319
	for(var coli = 0; coli != cols.length; ++coli) {
12320
		var coll = parsexmltag(cols[coli], true);
12321
		if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
12322
		var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
12323
		delete coll.min; delete coll.max; coll.width = +coll.width;
12324
		if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
12325
		process_col(coll);
12326
		while(colm <= colM) columns[colm++] = dup(coll);
12327
	}
12328
}
12329
12330
function write_ws_xml_cols(ws, cols)/*:string*/ {
12331
	var o = ["<cols>"], col;
12332
	for(var i = 0; i != cols.length; ++i) {
12333
		if(!(col = cols[i])) continue;
12334
		o[o.length] = (writextag('col', null, col_obj_w(i, col)));
12335
	}
12336
	o[o.length] = "</cols>";
12337
	return o.join("");
12338
}
12339
12340
function parse_ws_xml_autofilter(data/*:string*/) {
12341
	var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
12342
	return o;
12343
}
12344
function write_ws_xml_autofilter(data)/*:string*/ {
12345
	return writextag("autoFilter", null, {ref:data.ref});
12346
}
12347
12348
/* 18.3.1.88 sheetViews CT_SheetViews */
12349
/* 18.3.1.87 sheetView CT_SheetView */
12350
var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/>/;
12351
function parse_ws_xml_sheetviews(data, wb/*:WBWBProps*/) {
12352
	(data.match(sviewregex)||[]).forEach(function(r/*:string*/) {
12353
		var tag = parsexmltag(r);
12354
		if(parsexmlbool(tag.rightToLeft)) {
12355
			if(!wb.Views) wb.Views = [{}];
12356
			if(!wb.Views[0]) wb.Views[0] = {};
12357
			wb.Views[0].RTL = true;
12358
		}
12359
	});
12360
}
12361
function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ {
12362
	var sview = {workbookViewId:"0"};
12363
	// $FlowIgnore
12364
	if( (((wb||{}).Workbook||{}).Views||[])[0] ) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
12365
	return writextag("sheetViews", writextag("sheetView", null, sview), {});
12366
}
12367
12368
function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string*/ {
12369
	if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return "";
12370
	var vv = "";
12371
	var oldt = cell.t, oldv = cell.v;
12372
	switch(cell.t) {
12373
		case 'b': vv = cell.v ? "1" : "0"; break;
12374
		case 'n': vv = ''+cell.v; break;
12375
		case 'e': vv = BErr[cell.v]; break;
12376
		case 'd':
12377
			if(opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
12378
			else {
12379
				cell = dup(cell);
12380
				cell.t = 'n';
12381
				vv = ''+(cell.v = datenum(parseDate(cell.v)));
12382
			}
12383
			if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
12384
			break;
12385
		default: vv = cell.v; break;
12386
	}
12387
	var v = writetag('v', escapexml(vv)), o = ({r:ref}/*:any*/);
12388
	/* TODO: cell style */
12389
	var os = get_cell_style(opts.cellXfs, cell, opts);
12390
	if(os !== 0) o.s = os;
12391
	switch(cell.t) {
12392
		case 'n': break;
12393
		case 'd': o.t = "d"; break;
12394
		case 'b': o.t = "b"; break;
12395
		case 'e': o.t = "e"; break;
12396
		default: if(cell.v == null) { delete cell.t; break; }
12397
			if(opts.bookSST) {
12398
				v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
12399
				o.t = "s"; break;
12400
			}
12401
			o.t = "str"; break;
12402
	}
12403
	if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
12404
	if(cell.f) {
12405
		var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
12406
		v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
12407
	}
12408
	if(cell.l) ws['!links'].push([ref, cell.l]);
12409
	if(cell.c) ws['!comments'].push([ref, cell.c]);
12410
	return writextag('c', v, o);
12411
}
12412
12413
var parse_ws_xml_data = (function() {
12414
	var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
12415
	var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
12416
	var refregex = /ref=["']([^"']*)["']/;
12417
	var match_v = matchtag("v"), match_f = matchtag("f");
12418
12419
return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, themes, styles) {
12420
	var ri = 0, x = "", cells/*:Array<string>*/ = [], cref/*:?Array<string>*/ = [], idx=0, i=0, cc=0, d="", p/*:any*/;
12421
	var tag, tagr = 0, tagc = 0;
12422
	var sstr, ftag;
12423
	var fmtid = 0, fillid = 0;
12424
	var do_format = Array.isArray(styles.CellXf), cf;
12425
	var arrayf/*:Array<[Range, string]>*/ = [];
12426
	var sharedf = [];
12427
	var dense = Array.isArray(s);
12428
	var rows/*:Array<RowInfo>*/ = [], rowobj = {}, rowrite = false;
12429
	for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
12430
		x = marr[mt].trim();
12431
		var xlen = x.length;
12432
		if(xlen === 0) continue;
12433
12434
		/* 18.3.1.73 row CT_Row */
12435
		for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
12436
		tag = parsexmltag(x.slice(0,ri), true);
12437
		tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
12438
		if(opts.sheetRows && opts.sheetRows < tagr) continue;
12439
		if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
12440
		if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
12441
12442
		if(opts && opts.cellStyles) {
12443
			rowobj = {}; rowrite = false;
12444
			if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
12445
			if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
12446
			if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
12447
			if(rowrite) rows[tagr-1] = rowobj;
12448
		}
12449
12450
		/* 18.3.1.4 c CT_Cell */
12451
		cells = x.slice(ri).split(cellregex);
12452
		for(ri = 0; ri != cells.length; ++ri) {
12453
			x = cells[ri].trim();
12454
			if(x.length === 0) continue;
12455
			cref = x.match(rregex); idx = ri; i=0; cc=0;
12456
			x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
12457
			if(cref != null && cref.length === 2) {
12458
				idx = 0; d=cref[1];
12459
				for(i=0; i != d.length; ++i) {
12460
					if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
12461
					idx = 26*idx + cc;
12462
				}
12463
				--idx;
12464
				tagc = idx;
12465
			} else ++tagc;
12466
			for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
12467
			tag = parsexmltag(x.slice(0,i), true);
12468
			if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
12469
			d = x.slice(i);
12470
			p = ({t:""}/*:any*/);
12471
12472
			if((cref=d.match(match_v))!= null && /*::cref != null && */cref[1] !== '') p.v=unescapexml(cref[1]);
12473
			if(opts.cellFormula) {
12474
				if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') {
12475
					/* TODO: match against XLSXFutureFunctions */
12476
					p.f=_xlfn(unescapexml(utf8read(cref[1])));
12477
					if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) {
12478
						p.F = (d.match(refregex)||[])[1];
12479
						if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
12480
					} else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) {
12481
						// TODO: parse formula
12482
						ftag = parsexmltag(cref[0]);
12483
						sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1])))];
12484
					}
12485
				} else if((cref=d.match(/<f[^>]*\/>/))) {
12486
					ftag = parsexmltag(cref[0]);
12487
					if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][0].ref, tag.r);
12488
				}
12489
				/* TODO: factor out contains logic */
12490
				var _tag = decode_cell(tag.r);
12491
				for(i = 0; i < arrayf.length; ++i)
12492
					if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
12493
						if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
12494
							p.F = arrayf[i][1];
12495
			}
12496
12497
			if(tag.t == null && p.v === undefined) {
12498
				if(p.f || p.F) {
12499
					p.v = 0; p.t = "n";
12500
				} else if(!opts.sheetStubs) continue;
12501
				else p.t = "z";
12502
			}
12503
			else p.t = tag.t || "n";
12504
			if(guess.s.c > tagc) guess.s.c = tagc;
12505
			if(guess.e.c < tagc) guess.e.c = tagc;
12506
			/* 18.18.11 t ST_CellType */
12507
			switch(p.t) {
12508
				case 'n':
12509
					if(p.v == "" || p.v == null) {
12510
						if(!opts.sheetStubs) continue;
12511
						p.t = 'z';
12512
					} else p.v = parseFloat(p.v);
12513
					break;
12514
				case 's':
12515
					if(typeof p.v == 'undefined') {
12516
						if(!opts.sheetStubs) continue;
12517
						p.t = 'z';
12518
					} else {
12519
						sstr = strs[parseInt(p.v, 10)];
12520
						p.v = sstr.t;
12521
						p.r = sstr.r;
12522
						if(opts.cellHTML) p.h = sstr.h;
12523
					}
12524
					break;
12525
				case 'str':
12526
					p.t = "s";
12527
					p.v = (p.v!=null) ? utf8read(p.v) : '';
12528
					if(opts.cellHTML) p.h = escapehtml(p.v);
12529
					break;
12530
				case 'inlineStr':
12531
					cref = d.match(isregex);
12532
					p.t = 's';
12533
					if(cref != null && (sstr = parse_si(cref[1]))) p.v = sstr.t; else p.v = "";
12534
					break;
12535
				case 'b': p.v = parsexmlbool(p.v); break;
12536
				case 'd':
12537
					if(opts.cellDates) p.v = parseDate(p.v, 1);
12538
					else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
12539
					break;
12540
				/* error string in .w, number in .v */
12541
				case 'e':
12542
					if(!opts || opts.cellText !== false) p.w = p.v;
12543
					p.v = RBErr[p.v]; break;
12544
			}
12545
			/* formatting */
12546
			fmtid = fillid = 0;
12547
			if(do_format && tag.s !== undefined) {
12548
				cf = styles.CellXf[tag.s];
12549
				if(cf != null) {
12550
					if(cf.numFmtId != null) fmtid = cf.numFmtId;
12551
					if(opts.cellStyles) {
12552
						if(cf.fillId != null) fillid = cf.fillId;
12553
					}
12554
				}
12555
			}
12556
			safe_format(p, fmtid, fillid, opts, themes, styles);
12557
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
12558
			if(dense) {
12559
				var _r = decode_cell(tag.r);
12560
				if(!s[_r.r]) s[_r.r] = [];
12561
				s[_r.r][_r.c] = p;
12562
			} else s[tag.r] = p;
12563
		}
12564
	}
12565
	if(rows.length > 0) s['!rows'] = rows;
12566
}; })();
12567
12568
function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*//*::, rels*/)/*:string*/ {
12569
	var o/*:Array<string>*/ = [], r/*:Array<string>*/ = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols/*:Array<string>*/ = [], R=0, C=0, rows = ws['!rows'];
12570
	var dense = Array.isArray(ws);
12571
	var params = ({r:rr}/*:any*/), row/*:RowInfo*/, height = -1;
12572
	for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
12573
	for(R = range.s.r; R <= range.e.r; ++R) {
12574
		r = [];
12575
		rr = encode_row(R);
12576
		for(C = range.s.c; C <= range.e.c; ++C) {
12577
			ref = cols[C] + rr;
12578
			var _cell = dense ? (ws[R]||[])[C]: ws[ref];
12579
			if(_cell === undefined) continue;
12580
			if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
12581
		}
12582
		if(r.length > 0 || (rows && rows[R])) {
12583
			params = ({r:rr}/*:any*/);
12584
			if(rows && rows[R]) {
12585
				row = rows[R];
12586
				if(row.hidden) params.hidden = 1;
12587
				height = -1;
12588
				if (row.hpx) height = px2pt(row.hpx);
12589
				else if (row.hpt) height = row.hpt;
12590
				if (height > -1) { params.ht = height; params.customHeight = 1; }
12591
				if (row.level) { params.outlineLevel = row.level; }
12592
			}
12593
			o[o.length] = (writextag('row', r.join(""), params));
12594
		}
12595
	}
12596
	if(rows) for(; R < rows.length; ++R) {
12597
		if(rows && rows[R]) {
12598
			params = ({r:R+1}/*:any*/);
12599
			row = rows[R];
12600
			if(row.hidden) params.hidden = 1;
12601
			height = -1;
12602
			if (row.hpx) height = px2pt(row.hpx);
12603
			else if (row.hpt) height = row.hpt;
12604
			if (height > -1) { params.ht = height; params.customHeight = 1; }
12605
			if (row.level) { params.outlineLevel = row.level; }
12606
			o[o.length] = (writextag('row', "", params));
12607
		}
12608
	}
12609
	return o.join("");
12610
}
12611
12612
var WS_XML_ROOT = writextag('worksheet', null, {
12613
	'xmlns': XMLNS.main[0],
12614
	'xmlns:r': XMLNS.r
12615
});
12616
12617
function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
12618
	var o = [XML_HEADER, WS_XML_ROOT];
12619
	var s = wb.SheetNames[idx], sidx = 0, rdata = "";
12620
	var ws = wb.Sheets[s];
12621
	if(ws == null) ws = {};
12622
	var ref = ws['!ref'] || 'A1';
12623
	var range = safe_decode_range(ref);
12624
	if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
12625
		if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
12626
		range.e.c = Math.min(range.e.c, 0x3FFF);
12627
		range.e.r = Math.min(range.e.c, 0xFFFFF);
12628
		ref = encode_range(range);
12629
	}
12630
	if(!rels) rels = {};
12631
	ws['!comments'] = [];
12632
	ws['!drawing'] = [];
12633
12634
	if(opts.bookType !== 'xlsx' && wb.vbaraw) {
12635
		var cname = wb.SheetNames[idx];
12636
		try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
12637
		o[o.length] = (writextag('sheetPr', null, {'codeName': escapexml(cname)}));
12638
	}
12639
12640
	o[o.length] = (writextag('dimension', null, {'ref': ref}));
12641
12642
	o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
12643
12644
	/* TODO: store in WB, process styles */
12645
	if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
12646
		defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
12647
		baseColWidth:opts.sheetFormat.baseColWidth||'10',
12648
		outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
12649
	}));
12650
12651
	if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
12652
12653
	o[sidx = o.length] = '<sheetData/>';
12654
	ws['!links'] = [];
12655
	if(ws['!ref'] != null) {
12656
		rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
12657
		if(rdata.length > 0) o[o.length] = (rdata);
12658
	}
12659
	if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
12660
12661
	/* sheetCalcPr */
12662
12663
	if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
12664
12665
	/* protectedRanges */
12666
	/* scenarios */
12667
12668
	if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter']);
12669
12670
	/* sortState */
12671
	/* dataConsolidate */
12672
	/* customSheetViews */
12673
12674
	if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
12675
12676
	/* phoneticPr */
12677
	/* conditionalFormatting */
12678
	/* dataValidations */
12679
12680
	var relc = -1, rel, rId = -1;
12681
	if(ws['!links'].length > 0) {
12682
		o[o.length] = "<hyperlinks>";
12683
		ws['!links'].forEach(function(l) {
12684
			if(!l[1].Target) return;
12685
			rel = ({"ref":l[0]}/*:any*/);
12686
			if(l[1].Target.charAt(0) != "#") {
12687
				rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
12688
				rel["r:id"] = "rId"+rId;
12689
			}
12690
			if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
12691
			if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
12692
			o[o.length] = writextag("hyperlink",null,rel);
12693
		});
12694
		o[o.length] = "</hyperlinks>";
12695
	}
12696
	delete ws['!links'];
12697
12698
	/* printOptions */
12699
	if (ws['!margins'] != null) o[o.length] =  write_ws_xml_margins(ws['!margins']);
12700
	/* pageSetup */
12701
12702
	//var hfidx = o.length;
12703
	o[o.length] = "";
12704
12705
	/* rowBreaks */
12706
	/* colBreaks */
12707
	/* customProperties */
12708
	/* cellWatches */
12709
12710
	if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
12711
12712
	/* smartTags */
12713
12714
	if(ws['!drawing'].length > 0) {
12715
		rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
12716
		o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
12717
	}
12718
	else delete ws['!drawing'];
12719
12720
	if(ws['!comments'].length > 0) {
12721
		rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
12722
		o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
12723
		ws['!legacy'] = rId;
12724
	}
12725
12726
	/* drawingHF */
12727
	/* picture */
12728
	/* oleObjects */
12729
	/* controls */
12730
	/* webPublishItems */
12731
	/* tableParts */
12732
	/* extList */
12733
12734
	if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
12735
	return o.join("");
12736
}
12737
12738
/* [MS-XLSB] 2.4.726 BrtRowHdr */
12739
function parse_BrtRowHdr(data, length) {
12740
	var z = ({}/*:any*/);
12741
	var tgt = data.l + length;
12742
	z.r = data.read_shift(4);
12743
	data.l += 4; // TODO: ixfe
12744
	var miyRw = data.read_shift(2);
12745
	data.l += 1; // TODO: top/bot padding
12746
	var flags = data.read_shift(1);
12747
	data.l = tgt;
12748
	if(flags & 0x07) z.level = flags & 0x07;
12749
	if(flags & 0x10) z.hidden = true;
12750
	if(flags & 0x20) z.hpt = miyRw / 20;
12751
	return z;
12752
}
12753
function write_BrtRowHdr(R/*:number*/, range, ws) {
12754
	var o = new_buf(17+8*16);
12755
	var row = (ws['!rows']||[])[R]||{};
12756
	o.write_shift(4, R);
12757
12758
	o.write_shift(4, 0); /* TODO: ixfe */
12759
12760
	var miyRw = 0x0140;
12761
	if(row.hpx) miyRw = px2pt(row.hpx) * 20;
12762
	else if(row.hpt) miyRw = row.hpt * 20;
12763
	o.write_shift(2, miyRw);
12764
12765
	o.write_shift(1, 0); /* top/bot padding */
12766
12767
	var flags = 0x0;
12768
	if(row.level) flags |= row.level;
12769
	if(row.hidden) flags |= 0x10;
12770
	if(row.hpx || row.hpt) flags |= 0x20;
12771
	o.write_shift(1, flags);
12772
12773
	o.write_shift(1, 0); /* phonetic guide */
12774
12775
	/* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
12776
	var ncolspan = 0, lcs = o.l;
12777
	o.l += 4;
12778
12779
	var caddr = {r:R, c:0};
12780
	for(var i = 0; i < 16; ++i) {
12781
		if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue;
12782
		var first = -1, last = -1;
12783
		for(var j = (i<<10); j < ((i+1)<<10); ++j) {
12784
			caddr.c = j;
12785
			var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
12786
			if(cell) { if(first < 0) first = j; last = j; }
12787
		}
12788
		if(first < 0) continue;
12789
		++ncolspan;
12790
		o.write_shift(4, first);
12791
		o.write_shift(4, last);
12792
	}
12793
12794
	var l = o.l;
12795
	o.l = lcs;
12796
	o.write_shift(4, ncolspan);
12797
	o.l = l;
12798
12799
	return o.length > o.l ? o.slice(0, o.l) : o;
12800
}
12801
function write_row_header(ba, ws, range, R) {
12802
	var o = write_BrtRowHdr(R, range, ws);
12803
	if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o);
12804
}
12805
12806
/* [MS-XLSB] 2.4.820 BrtWsDim */
12807
var parse_BrtWsDim = parse_UncheckedRfX;
12808
var write_BrtWsDim = write_UncheckedRfX;
12809
12810
/* [MS-XLSB] 2.4.821 BrtWsFmtInfo */
12811
function parse_BrtWsFmtInfo(/*::data, length*/) {
12812
}
12813
//function write_BrtWsFmtInfo(ws, o) { }
12814
12815
/* [MS-XLSB] 2.4.823 BrtWsProp */
12816
function parse_BrtWsProp(data, length) {
12817
	var z = {};
12818
	/* TODO: pull flags */
12819
	data.l += 19;
12820
	z.name = parse_XLSBCodeName(data, length - 19);
12821
	return z;
12822
}
12823
function write_BrtWsProp(str, o) {
12824
	if(o == null) o = new_buf(84+4*str.length);
12825
	for(var i = 0; i < 3; ++i) o.write_shift(1,0);
12826
	write_BrtColor({auto:1}, o);
12827
	o.write_shift(-4,-1);
12828
	o.write_shift(-4,-1);
12829
	write_XLSBCodeName(str, o);
12830
	return o.slice(0, o.l);
12831
}
12832
12833
/* [MS-XLSB] 2.4.306 BrtCellBlank */
12834
function parse_BrtCellBlank(data) {
12835
	var cell = parse_XLSBCell(data);
12836
	return [cell];
12837
}
12838
function write_BrtCellBlank(cell, ncell, o) {
12839
	if(o == null) o = new_buf(8);
12840
	return write_XLSBCell(ncell, o);
12841
}
12842
12843
12844
/* [MS-XLSB] 2.4.307 BrtCellBool */
12845
function parse_BrtCellBool(data) {
12846
	var cell = parse_XLSBCell(data);
12847
	var fBool = data.read_shift(1);
12848
	return [cell, fBool, 'b'];
12849
}
12850
function write_BrtCellBool(cell, ncell, o) {
12851
	if(o == null) o = new_buf(9);
12852
	write_XLSBCell(ncell, o);
12853
	o.write_shift(1, cell.v ? 1 : 0);
12854
	return o;
12855
}
12856
12857
/* [MS-XLSB] 2.4.308 BrtCellError */
12858
function parse_BrtCellError(data) {
12859
	var cell = parse_XLSBCell(data);
12860
	var bError = data.read_shift(1);
12861
	return [cell, bError, 'e'];
12862
}
12863
12864
/* [MS-XLSB] 2.4.311 BrtCellIsst */
12865
function parse_BrtCellIsst(data) {
12866
	var cell = parse_XLSBCell(data);
12867
	var isst = data.read_shift(4);
12868
	return [cell, isst, 's'];
12869
}
12870
function write_BrtCellIsst(cell, ncell, o) {
12871
	if(o == null) o = new_buf(12);
12872
	write_XLSBCell(ncell, o);
12873
	o.write_shift(4, ncell.v);
12874
	return o;
12875
}
12876
12877
/* [MS-XLSB] 2.4.313 BrtCellReal */
12878
function parse_BrtCellReal(data) {
12879
	var cell = parse_XLSBCell(data);
12880
	var value = parse_Xnum(data);
12881
	return [cell, value, 'n'];
12882
}
12883
function write_BrtCellReal(cell, ncell, o) {
12884
	if(o == null) o = new_buf(16);
12885
	write_XLSBCell(ncell, o);
12886
	write_Xnum(cell.v, o);
12887
	return o;
12888
}
12889
12890
/* [MS-XLSB] 2.4.314 BrtCellRk */
12891
function parse_BrtCellRk(data) {
12892
	var cell = parse_XLSBCell(data);
12893
	var value = parse_RkNumber(data);
12894
	return [cell, value, 'n'];
12895
}
12896
function write_BrtCellRk(cell, ncell, o) {
12897
	if(o == null) o = new_buf(12);
12898
	write_XLSBCell(ncell, o);
12899
	write_RkNumber(cell.v, o);
12900
	return o;
12901
}
12902
12903
12904
/* [MS-XLSB] 2.4.317 BrtCellSt */
12905
function parse_BrtCellSt(data) {
12906
	var cell = parse_XLSBCell(data);
12907
	var value = parse_XLWideString(data);
12908
	return [cell, value, 'str'];
12909
}
12910
function write_BrtCellSt(cell, ncell, o) {
12911
	if(o == null) o = new_buf(12 + 4 * cell.v.length);
12912
	write_XLSBCell(ncell, o);
12913
	write_XLWideString(cell.v, o);
12914
	return o.length > o.l ? o.slice(0, o.l) : o;
12915
}
12916
12917
/* [MS-XLSB] 2.4.653 BrtFmlaBool */
12918
function parse_BrtFmlaBool(data, length, opts) {
12919
	var end = data.l + length;
12920
	var cell = parse_XLSBCell(data);
12921
	cell.r = opts['!row'];
12922
	var value = data.read_shift(1);
12923
	var o = [cell, value, 'b'];
12924
	if(opts.cellFormula) {
12925
		data.l += 2;
12926
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12927
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12928
	}
12929
	else data.l = end;
12930
	return o;
12931
}
12932
12933
/* [MS-XLSB] 2.4.654 BrtFmlaError */
12934
function parse_BrtFmlaError(data, length, opts) {
12935
	var end = data.l + length;
12936
	var cell = parse_XLSBCell(data);
12937
	cell.r = opts['!row'];
12938
	var value = data.read_shift(1);
12939
	var o = [cell, value, 'e'];
12940
	if(opts.cellFormula) {
12941
		data.l += 2;
12942
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12943
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12944
	}
12945
	else data.l = end;
12946
	return o;
12947
}
12948
12949
/* [MS-XLSB] 2.4.655 BrtFmlaNum */
12950
function parse_BrtFmlaNum(data, length, opts) {
12951
	var end = data.l + length;
12952
	var cell = parse_XLSBCell(data);
12953
	cell.r = opts['!row'];
12954
	var value = parse_Xnum(data);
12955
	var o = [cell, value, 'n'];
12956
	if(opts.cellFormula) {
12957
		data.l += 2;
12958
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12959
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12960
	}
12961
	else data.l = end;
12962
	return o;
12963
}
12964
12965
/* [MS-XLSB] 2.4.656 BrtFmlaString */
12966
function parse_BrtFmlaString(data, length, opts) {
12967
	var end = data.l + length;
12968
	var cell = parse_XLSBCell(data);
12969
	cell.r = opts['!row'];
12970
	var value = parse_XLWideString(data);
12971
	var o = [cell, value, 'str'];
12972
	if(opts.cellFormula) {
12973
		data.l += 2;
12974
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12975
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12976
	}
12977
	else data.l = end;
12978
	return o;
12979
}
12980
12981
/* [MS-XLSB] 2.4.682 BrtMergeCell */
12982
var parse_BrtMergeCell = parse_UncheckedRfX;
12983
var write_BrtMergeCell = write_UncheckedRfX;
12984
/* [MS-XLSB] 2.4.107 BrtBeginMergeCells */
12985
function write_BrtBeginMergeCells(cnt, o) {
12986
	if(o == null) o = new_buf(4);
12987
	o.write_shift(4, cnt);
12988
	return o;
12989
}
12990
12991
/* [MS-XLSB] 2.4.662 BrtHLink */
12992
function parse_BrtHLink(data, length/*::, opts*/) {
12993
	var end = data.l + length;
12994
	var rfx = parse_UncheckedRfX(data, 16);
12995
	var relId = parse_XLNullableWideString(data);
12996
	var loc = parse_XLWideString(data);
12997
	var tooltip = parse_XLWideString(data);
12998
	var display = parse_XLWideString(data);
12999
	data.l = end;
13000
	var o = ({rfx:rfx, relId:relId, loc:loc, display:display}/*:any*/);
13001
	if(tooltip) o.Tooltip = tooltip;
13002
	return o;
13003
}
13004
function write_BrtHLink(l, rId) {
13005
	var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
13006
	write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
13007
	write_RelID("rId" + rId, o);
13008
	var locidx = l[1].Target.indexOf("#");
13009
	var loc = locidx == -1 ? "" : l[1].Target.slice(locidx+1);
13010
	write_XLWideString(loc || "", o);
13011
	write_XLWideString(l[1].Tooltip || "", o);
13012
	write_XLWideString("", o);
13013
	return o.slice(0, o.l);
13014
}
13015
13016
/* [MS-XLSB] 2.4.6 BrtArrFmla */
13017
function parse_BrtArrFmla(data, length, opts) {
13018
	var end = data.l + length;
13019
	var rfx = parse_RfX(data, 16);
13020
	var fAlwaysCalc = data.read_shift(1);
13021
	var o = [rfx]; o[2] = fAlwaysCalc;
13022
	if(opts.cellFormula) {
13023
		var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts);
13024
		o[1] = formula;
13025
	} else data.l = end;
13026
	return o;
13027
}
13028
13029
/* [MS-XLSB] 2.4.750 BrtShrFmla */
13030
function parse_BrtShrFmla(data, length, opts) {
13031
	var end = data.l + length;
13032
	var rfx = parse_UncheckedRfX(data, 16);
13033
	var o = [rfx];
13034
	if(opts.cellFormula) {
13035
		var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts);
13036
		o[1] = formula;
13037
		data.l = end;
13038
	} else data.l = end;
13039
	return o;
13040
}
13041
13042
/* [MS-XLSB] 2.4.323 BrtColInfo */
13043
/* TODO: once XLS ColInfo is set, combine the functions */
13044
function write_BrtColInfo(C/*:number*/, col, o) {
13045
	if(o == null) o = new_buf(18);
13046
	var p = col_obj_w(C, col);
13047
	o.write_shift(-4, C);
13048
	o.write_shift(-4, C);
13049
	o.write_shift(4, (p.width || 10) * 256);
13050
	o.write_shift(4, 0/*ixfe*/); // style
13051
	var flags = 0;
13052
	if(col.hidden) flags |= 0x01;
13053
	if(typeof p.width == 'number') flags |= 0x02;
13054
	o.write_shift(1, flags); // bit flag
13055
	o.write_shift(1, 0); // bit flag
13056
	return o;
13057
}
13058
13059
/* [MS-XLSB] 2.4.678 BrtMargins */
13060
var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
13061
function parse_BrtMargins(data/*::, length, opts*/)/*:Margins*/ {
13062
	var margins = ({}/*:any*/);
13063
	BrtMarginKeys.forEach(function(k) { margins[k] = parse_Xnum(data, 8); });
13064
	return margins;
13065
}
13066
function write_BrtMargins(margins/*:Margins*/, o) {
13067
	if(o == null) o = new_buf(6*8);
13068
	default_margins(margins);
13069
	BrtMarginKeys.forEach(function(k) { write_Xnum((margins/*:any*/)[k], o); });
13070
	return o;
13071
}
13072
13073
/* [MS-XLSB] 2.4.299 BrtBeginWsView */
13074
function parse_BrtBeginWsView(data/*::, length, opts*/) {
13075
	var f = data.read_shift(2);
13076
	data.l += 28;
13077
	return { RTL: f & 0x20 };
13078
}
13079
function write_BrtBeginWsView(ws, Workbook, o) {
13080
	if(o == null) o = new_buf(30);
13081
	var f = 0x39c;
13082
	if((((Workbook||{}).Views||[])[0]||{}).RTL) f |= 0x20;
13083
	o.write_shift(2, f); // bit flag
13084
	o.write_shift(4, 0);
13085
	o.write_shift(4, 0); // view first row
13086
	o.write_shift(4, 0); // view first col
13087
	o.write_shift(1, 0); // gridline color ICV
13088
	o.write_shift(1, 0);
13089
	o.write_shift(2, 0);
13090
	o.write_shift(2, 100); // zoom scale
13091
	o.write_shift(2, 0);
13092
	o.write_shift(2, 0);
13093
	o.write_shift(2, 0);
13094
	o.write_shift(4, 0); // workbook view id
13095
	return o;
13096
}
13097
13098
/* [MS-XLSB] 2.4.309 BrtCellIgnoreEC */
13099
function write_BrtCellIgnoreEC(ref) {
13100
	var o = new_buf(24);
13101
	o.write_shift(4, 4);
13102
	o.write_shift(4, 1);
13103
	write_UncheckedRfX(ref, o);
13104
	return o;
13105
}
13106
13107
/* [MS-XLSB] 2.4.748 BrtSheetProtection */
13108
function write_BrtSheetProtection(sp, o) {
13109
	if(o == null) o = new_buf(16*4+2);
13110
	o.write_shift(2, sp.password ? crypto_CreatePasswordVerifier_Method1(sp.password) : 0);
13111
	o.write_shift(4, 1); // this record should not be written if no protection
13112
	[
13113
		["objects",             false], // fObjects
13114
		["scenarios",           false], // fScenarios
13115
		["formatCells",          true], // fFormatCells
13116
		["formatColumns",        true], // fFormatColumns
13117
		["formatRows",           true], // fFormatRows
13118
		["insertColumns",        true], // fInsertColumns
13119
		["insertRows",           true], // fInsertRows
13120
		["insertHyperlinks",     true], // fInsertHyperlinks
13121
		["deleteColumns",        true], // fDeleteColumns
13122
		["deleteRows",           true], // fDeleteRows
13123
		["selectLockedCells",   false], // fSelLockedCells
13124
		["sort",                 true], // fSort
13125
		["autoFilter",           true], // fAutoFilter
13126
		["pivotTables",          true], // fPivotTables
13127
		["selectUnlockedCells", false]  // fSelUnlockedCells
13128
	].forEach(function(n) {
13129
		/*:: if(o == null) throw "unreachable"; */
13130
		if(n[1]) o.write_shift(4, sp[n[0]] != null && !sp[n[0]] ? 1 : 0);
13131
		else      o.write_shift(4, sp[n[0]] != null && sp[n[0]] ? 0 : 1);
13132
	});
13133
	return o;
13134
}
13135
13136
/* [MS-XLSB] 2.1.7.61 Worksheet */
13137
function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ {
13138
	if(!data) return data;
13139
	var opts = _opts || {};
13140
	if(!rels) rels = {'!id':{}};
13141
	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
13142
	var s/*:Worksheet*/ = (opts.dense ? [] : {});
13143
13144
	var ref;
13145
	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
13146
13147
	var pass = false, end = false;
13148
	var row, p, cf, R, C, addr, sstr, rr, cell/*:Cell*/;
13149
	var merges/*:Array<Range>*/ = [];
13150
	opts.biff = 12;
13151
	opts['!row'] = 0;
13152
13153
	var ai = 0, af = false;
13154
13155
	var arrayf/*:Array<[Range, string]>*/ = [];
13156
	var sharedf = {};
13157
	var supbooks = opts.supbooks || ([[]]/*:any*/);
13158
	supbooks.sharedf = sharedf;
13159
	supbooks.arrayf = arrayf;
13160
	supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; });
13161
	if(!opts.supbooks) {
13162
		opts.supbooks = supbooks;
13163
		if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i];
13164
	}
13165
13166
	var colinfo/*:Array<ColInfo>*/ = [], rowinfo/*:Array<RowInfo>*/ = [];
13167
	var seencol = false;
13168
13169
	recordhopper(data, function ws_parse(val, R_n, RT) {
13170
		if(end) return;
13171
		switch(RT) {
13172
			case 0x0094: /* 'BrtWsDim' */
13173
				ref = val; break;
13174
			case 0x0000: /* 'BrtRowHdr' */
13175
				row = val;
13176
				if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
13177
				rr = encode_row(R = row.r);
13178
				opts['!row'] = row.r;
13179
				if(val.hidden || val.hpt || val.level != null) {
13180
					if(val.hpt) val.hpx = pt2px(val.hpt);
13181
					rowinfo[val.r] = val;
13182
				}
13183
				break;
13184
13185
			case 0x0002: /* 'BrtCellRk' */
13186
			case 0x0003: /* 'BrtCellError' */
13187
			case 0x0004: /* 'BrtCellBool' */
13188
			case 0x0005: /* 'BrtCellReal' */
13189
			case 0x0006: /* 'BrtCellSt' */
13190
			case 0x0007: /* 'BrtCellIsst' */
13191
			case 0x0008: /* 'BrtFmlaString' */
13192
			case 0x0009: /* 'BrtFmlaNum' */
13193
			case 0x000A: /* 'BrtFmlaBool' */
13194
			case 0x000B: /* 'BrtFmlaError' */
13195
				p = ({t:val[2]}/*:any*/);
13196
				switch(val[2]) {
13197
					case 'n': p.v = val[1]; break;
13198
					case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
13199
					case 'b': p.v = val[1] ? true : false; break;
13200
					case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
13201
					case 'str': p.t = 's'; p.v = val[1]; break;
13202
				}
13203
				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
13204
				C = val[0].c;
13205
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
13206
				else s[encode_col(C) + rr] = p;
13207
				if(opts.cellFormula) {
13208
					af = false;
13209
					for(ai = 0; ai < arrayf.length; ++ai) {
13210
						var aii = arrayf[ai];
13211
						if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
13212
							if(C >= aii[0].s.c && C <= aii[0].e.c) {
13213
								p.F = encode_range(aii[0]); af = true;
13214
							}
13215
					}
13216
					if(!af && val.length > 3) p.f = val[3];
13217
				}
13218
				if(refguess.s.r > row.r) refguess.s.r = row.r;
13219
				if(refguess.s.c > C) refguess.s.c = C;
13220
				if(refguess.e.r < row.r) refguess.e.r = row.r;
13221
				if(refguess.e.c < C) refguess.e.c = C;
13222
				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
13223
					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
13224
				}
13225
				break;
13226
13227
			case 0x0001: /* 'BrtCellBlank' */
13228
				if(!opts.sheetStubs || pass) break;
13229
				p = ({t:'z',v:undefined}/*:any*/);
13230
				C = val[0].c;
13231
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
13232
				else s[encode_col(C) + rr] = p;
13233
				if(refguess.s.r > row.r) refguess.s.r = row.r;
13234
				if(refguess.s.c > C) refguess.s.c = C;
13235
				if(refguess.e.r < row.r) refguess.e.r = row.r;
13236
				if(refguess.e.c < C) refguess.e.c = C;
13237
				break;
13238
13239
			case 0x00B0: /* 'BrtMergeCell' */
13240
				merges.push(val); break;
13241
13242
			case 0x01EE: /* 'BrtHLink' */
13243
				var rel = rels['!id'][val.relId];
13244
				if(rel) {
13245
					val.Target = rel.Target;
13246
					if(val.loc) val.Target += "#"+val.loc;
13247
					val.Rel = rel;
13248
				} else if(val.relId == '') {
13249
					val.Target = "#" + val.loc;
13250
				}
13251
				for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
13252
					if(opts.dense) {
13253
						if(!s[R]) s[R] = [];
13254
						if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
13255
						s[R][C].l = val;
13256
					} else {
13257
						addr = encode_cell({c:C,r:R});
13258
						if(!s[addr]) s[addr] = {t:'z',v:undefined};
13259
						s[addr].l = val;
13260
					}
13261
				}
13262
				break;
13263
13264
			case 0x01AA: /* 'BrtArrFmla' */
13265
				if(!opts.cellFormula) break;
13266
				arrayf.push(val);
13267
				cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr])/*:any*/);
13268
				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
13269
				cell.F = encode_range(val[0]);
13270
				break;
13271
			case 0x01AB: /* 'BrtShrFmla' */
13272
				if(!opts.cellFormula) break;
13273
				sharedf[encode_cell(val[0].s)] = val[1];
13274
				cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
13275
				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
13276
				break;
13277
13278
			/* identical to 'ColInfo' in XLS */
13279
			case 0x003C: /* 'BrtColInfo' */
13280
				if(!opts.cellStyles) break;
13281
				while(val.e >= val.s) {
13282
					colinfo[val.e--] = { width: val.w/256, hidden: !!(val.flags & 0x01) };
13283
					if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
13284
					process_col(colinfo[val.e+1]);
13285
				}
13286
				break;
13287
13288
			case 0x00A1: /* 'BrtBeginAFilter' */
13289
				s['!autofilter'] = { ref:encode_range(val) };
13290
				break;
13291
13292
			case 0x01DC: /* 'BrtMargins' */
13293
				s['!margins'] = val;
13294
				break;
13295
13296
			case 0x0093: /* 'BrtWsProp' */
13297
				if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13298
				if(val.name) wb.Sheets[idx].CodeName = val.name;
13299
				break;
13300
13301
			case 0x0089: /* 'BrtBeginWsView' */
13302
				if(!wb.Views) wb.Views = [{}];
13303
				if(!wb.Views[0]) wb.Views[0] = {};
13304
				if(val.RTL) wb.Views[0].RTL = true;
13305
				break;
13306
13307
			case 0x01E5: /* 'BrtWsFmtInfo' */
13308
				break;
13309
			case 0x00AF: /* 'BrtAFilterDateGroupItem' */
13310
			case 0x0284: /* 'BrtActiveX' */
13311
			case 0x0271: /* 'BrtBigName' */
13312
			case 0x0232: /* 'BrtBkHim' */
13313
			case 0x018C: /* 'BrtBrk' */
13314
			case 0x0458: /* 'BrtCFIcon' */
13315
			case 0x047A: /* 'BrtCFRuleExt' */
13316
			case 0x01D7: /* 'BrtCFVO' */
13317
			case 0x041A: /* 'BrtCFVO14' */
13318
			case 0x0289: /* 'BrtCellIgnoreEC' */
13319
			case 0x0451: /* 'BrtCellIgnoreEC14' */
13320
			case 0x0031: /* 'BrtCellMeta' */
13321
			case 0x024D: /* 'BrtCellSmartTagProperty' */
13322
			case 0x025F: /* 'BrtCellWatch' */
13323
			case 0x0234: /* 'BrtColor' */
13324
			case 0x041F: /* 'BrtColor14' */
13325
			case 0x00A8: /* 'BrtColorFilter' */
13326
			case 0x00AE: /* 'BrtCustomFilter' */
13327
			case 0x049C: /* 'BrtCustomFilter14' */
13328
			case 0x01F3: /* 'BrtDRef' */
13329
			case 0x0040: /* 'BrtDVal' */
13330
			case 0x041D: /* 'BrtDVal14' */
13331
			case 0x0226: /* 'BrtDrawing' */
13332
			case 0x00AB: /* 'BrtDynamicFilter' */
13333
			case 0x00A7: /* 'BrtFilter' */
13334
			case 0x0499: /* 'BrtFilter14' */
13335
			case 0x00A9: /* 'BrtIconFilter' */
13336
			case 0x049D: /* 'BrtIconFilter14' */
13337
			case 0x0227: /* 'BrtLegacyDrawing' */
13338
			case 0x0228: /* 'BrtLegacyDrawingHF' */
13339
			case 0x0295: /* 'BrtListPart' */
13340
			case 0x027F: /* 'BrtOleObject' */
13341
			case 0x01DE: /* 'BrtPageSetup' */
13342
			case 0x0097: /* 'BrtPane' */
13343
			case 0x0219: /* 'BrtPhoneticInfo' */
13344
			case 0x01DD: /* 'BrtPrintOptions' */
13345
			case 0x0218: /* 'BrtRangeProtection' */
13346
			case 0x044F: /* 'BrtRangeProtection14' */
13347
			case 0x02A8: /* 'BrtRangeProtectionIso' */
13348
			case 0x0450: /* 'BrtRangeProtectionIso14' */
13349
			case 0x0400: /* 'BrtRwDescent' */
13350
			case 0x0098: /* 'BrtSel' */
13351
			case 0x0297: /* 'BrtSheetCalcProp' */
13352
			case 0x0217: /* 'BrtSheetProtection' */
13353
			case 0x02A6: /* 'BrtSheetProtectionIso' */
13354
			case 0x01F8: /* 'BrtSlc' */
13355
			case 0x0413: /* 'BrtSparkline' */
13356
			case 0x01AC: /* 'BrtTable' */
13357
			case 0x00AA: /* 'BrtTop10Filter' */
13358
			case 0x0C00: /* 'BrtUid' */
13359
			case 0x0032: /* 'BrtValueMeta' */
13360
			case 0x0816: /* 'BrtWebExtension' */
13361
			case 0x0415: /* 'BrtWsFmtInfoEx14' */
13362
				break;
13363
13364
			case 0x0023: /* 'BrtFRTBegin' */
13365
				pass = true; break;
13366
			case 0x0024: /* 'BrtFRTEnd' */
13367
				pass = false; break;
13368
			case 0x0025: /* 'BrtACBegin' */ break;
13369
			case 0x0026: /* 'BrtACEnd' */ break;
13370
13371
			default:
13372
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
13373
				else if((R_n||"").indexOf("End") > 0){/* empty */}
13374
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
13375
		}
13376
	}, opts);
13377
13378
	delete opts.supbooks;
13379
	delete opts['!row'];
13380
13381
	if(!s["!ref"] && (refguess.s.r < 2000000 || ref && (ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0))) s["!ref"] = encode_range(ref || refguess);
13382
	if(opts.sheetRows && s["!ref"]) {
13383
		var tmpref = safe_decode_range(s["!ref"]);
13384
		if(opts.sheetRows <= +tmpref.e.r) {
13385
			tmpref.e.r = opts.sheetRows - 1;
13386
			if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
13387
			if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
13388
			if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
13389
			if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
13390
			s["!fullref"] = s["!ref"];
13391
			s["!ref"] = encode_range(tmpref);
13392
		}
13393
	}
13394
	if(merges.length > 0) s["!merges"] = merges;
13395
	if(colinfo.length > 0) s["!cols"] = colinfo;
13396
	if(rowinfo.length > 0) s["!rows"] = rowinfo;
13397
	return s;
13398
}
13399
13400
/* TODO: something useful -- this is a stub */
13401
function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts, ws/*:Worksheet*/) {
13402
	if(cell.v === undefined) return "";
13403
	var vv = "";
13404
	switch(cell.t) {
13405
		case 'b': vv = cell.v ? "1" : "0"; break;
13406
		case 'd': // no BrtCellDate :(
13407
			cell = dup(cell);
13408
			cell.z = cell.z || SSF._table[14];
13409
			cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
13410
			break;
13411
		/* falls through */
13412
		case 'n': case 'e': vv = ''+cell.v; break;
13413
		default: vv = cell.v; break;
13414
	}
13415
	var o/*:any*/ = ({r:R, c:C}/*:any*/);
13416
	/* TODO: cell style */
13417
	o.s = get_cell_style(opts.cellXfs, cell, opts);
13418
	if(cell.l) ws['!links'].push([encode_cell(o), cell.l]);
13419
	if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
13420
	switch(cell.t) {
13421
		case 's': case 'str':
13422
			if(opts.bookSST) {
13423
				vv = get_sst_id(opts.Strings, (cell.v/*:any*/), opts.revStrings);
13424
				o.t = "s"; o.v = vv;
13425
				write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
13426
			} else {
13427
				o.t = "str";
13428
				write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
13429
			}
13430
			return;
13431
		case 'n':
13432
			/* TODO: determine threshold for Real vs RK */
13433
			if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
13434
			else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
13435
			return;
13436
		case 'b':
13437
			o.t = "b";
13438
			write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
13439
			return;
13440
		case 'e': /* TODO: error */ o.t = "e"; break;
13441
	}
13442
	write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
13443
}
13444
13445
function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
13446
	var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols/*:Array<string>*/ = [];
13447
	write_record(ba, 'BrtBeginSheetData');
13448
	var dense = Array.isArray(ws);
13449
	var cap = range.e.r;
13450
	if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1);
13451
	for(var R = range.s.r; R <= cap; ++R) {
13452
		rr = encode_row(R);
13453
		/* [ACCELLTABLE] */
13454
		/* BrtRowHdr */
13455
		write_row_header(ba, ws, range, R);
13456
		if(R <= range.e.r) for(var C = range.s.c; C <= range.e.c; ++C) {
13457
			/* *16384CELL */
13458
			if(R === range.s.r) cols[C] = encode_col(C);
13459
			ref = cols[C] + rr;
13460
			var cell = dense ? (ws[R]||[])[C] : ws[ref];
13461
			if(!cell) continue;
13462
			/* write cell */
13463
			write_ws_bin_cell(ba, cell, R, C, opts, ws);
13464
		}
13465
	}
13466
	write_record(ba, 'BrtEndSheetData');
13467
}
13468
13469
function write_MERGECELLS(ba, ws/*:Worksheet*/) {
13470
	if(!ws || !ws['!merges']) return;
13471
	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
13472
	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
13473
	write_record(ba, 'BrtEndMergeCells');
13474
}
13475
13476
function write_COLINFOS(ba, ws/*:Worksheet*//*::, idx:number, opts, wb:Workbook*/) {
13477
	if(!ws || !ws['!cols']) return;
13478
	write_record(ba, 'BrtBeginColInfos');
13479
	ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
13480
	write_record(ba, 'BrtEndColInfos');
13481
}
13482
13483
function write_IGNOREECS(ba, ws/*:Worksheet*/) {
13484
	if(!ws || !ws['!ref']) return;
13485
	write_record(ba, 'BrtBeginCellIgnoreECs');
13486
	write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref'])));
13487
	write_record(ba, 'BrtEndCellIgnoreECs');
13488
}
13489
13490
function write_HLINKS(ba, ws/*:Worksheet*/, rels) {
13491
	/* *BrtHLink */
13492
	ws['!links'].forEach(function(l) {
13493
		if(!l[1].Target) return;
13494
		var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK);
13495
		write_record(ba, "BrtHLink", write_BrtHLink(l, rId));
13496
	});
13497
	delete ws['!links'];
13498
}
13499
function write_LEGACYDRAWING(ba, ws/*:Worksheet*/, idx/*:number*/, rels) {
13500
	/* [BrtLegacyDrawing] */
13501
	if(ws['!comments'].length > 0) {
13502
		var rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
13503
		write_record(ba, "BrtLegacyDrawing", write_RelID("rId" + rId));
13504
		ws['!legacy'] = rId;
13505
	}
13506
}
13507
13508
function write_AUTOFILTER(ba, ws) {
13509
	if(!ws['!autofilter']) return;
13510
	write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ws['!autofilter'].ref)));
13511
	/* *FILTERCOLUMN */
13512
	/* [SORTSTATE] */
13513
	/* BrtEndAFilter */
13514
	write_record(ba, "BrtEndAFilter");
13515
}
13516
13517
function write_WSVIEWS2(ba, ws, Workbook) {
13518
	write_record(ba, "BrtBeginWsViews");
13519
	{ /* 1*WSVIEW2 */
13520
		/* [ACUID] */
13521
		write_record(ba, "BrtBeginWsView", write_BrtBeginWsView(ws, Workbook));
13522
		/* [BrtPane] */
13523
		/* *4BrtSel */
13524
		/* *4SXSELECT */
13525
		/* *FRT */
13526
		write_record(ba, "BrtEndWsView");
13527
	}
13528
	/* *FRT */
13529
	write_record(ba, "BrtEndWsViews");
13530
}
13531
13532
function write_WSFMTINFO(/*::ba, ws*/) {
13533
	/* [ACWSFMTINFO] */
13534
	//write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
13535
}
13536
13537
function write_SHEETPROTECT(ba, ws) {
13538
	if(!ws['!protect']) return;
13539
	/* [BrtSheetProtectionIso] */
13540
	write_record(ba, "BrtSheetProtection", write_BrtSheetProtection(ws['!protect']));
13541
}
13542
13543
function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
13544
	var ba = buf_array();
13545
	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
13546
	var c/*:string*/ = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
13547
	var r = safe_decode_range(ws['!ref'] || "A1");
13548
	if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
13549
		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
13550
		r.e.c = Math.min(r.e.c, 0x3FFF);
13551
		r.e.r = Math.min(r.e.c, 0xFFFFF);
13552
	}
13553
	ws['!links'] = [];
13554
	/* passed back to write_zip and removed there */
13555
	ws['!comments'] = [];
13556
	write_record(ba, "BrtBeginSheet");
13557
	if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
13558
	write_record(ba, "BrtWsDim", write_BrtWsDim(r));
13559
	write_WSVIEWS2(ba, ws, wb.Workbook);
13560
	write_WSFMTINFO(ba, ws);
13561
	write_COLINFOS(ba, ws, idx, opts, wb);
13562
	write_CELLTABLE(ba, ws, idx, opts, wb);
13563
	/* [BrtSheetCalcProp] */
13564
	write_SHEETPROTECT(ba, ws);
13565
	/* *([BrtRangeProtectionIso] BrtRangeProtection) */
13566
	/* [SCENMAN] */
13567
	write_AUTOFILTER(ba, ws);
13568
	/* [SORTSTATE] */
13569
	/* [DCON] */
13570
	/* [USERSHVIEWS] */
13571
	write_MERGECELLS(ba, ws);
13572
	/* [BrtPhoneticInfo] */
13573
	/* *CONDITIONALFORMATTING */
13574
	/* [DVALS] */
13575
	write_HLINKS(ba, ws, rels);
13576
	/* [BrtPrintOptions] */
13577
	if(ws['!margins']) write_record(ba, "BrtMargins", write_BrtMargins(ws['!margins']));
13578
	/* [BrtPageSetup] */
13579
	/* [HEADERFOOTER] */
13580
	/* [RWBRK] */
13581
	/* [COLBRK] */
13582
	/* *BrtBigName */
13583
	/* [CELLWATCHES] */
13584
	if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) write_IGNOREECS(ba, ws);
13585
	/* [SMARTTAGS] */
13586
	/* [BrtDrawing] */
13587
	write_LEGACYDRAWING(ba, ws, idx, rels);
13588
	/* [BrtLegacyDrawingHF] */
13589
	/* [BrtBkHim] */
13590
	/* [OLEOBJECTS] */
13591
	/* [ACTIVEXCONTROLS] */
13592
	/* [WEBPUBITEMS] */
13593
	/* [LISTPARTS] */
13594
	/* FRTWORKSHEET */
13595
	write_record(ba, "BrtEndSheet");
13596
	return ba.end();
13597
}
13598
function parse_numCache(data/*:string*/)/*:[Array<number>, string]*/ {
13599
	var col/*:Array<number>*/ = [];
13600
13601
	/* 21.2.2.150 pt CT_NumVal */
13602
	(data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
13603
		var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
13604
		if(!q) return;
13605
		col[+q[1]] = +q[2];
13606
	});
13607
13608
	/* 21.2.2.71 formatCode CT_Xstring */
13609
	var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
13610
13611
	return [col, nf];
13612
}
13613
13614
/* 21.2 DrawingML - Charts */
13615
function parse_chart(data/*:?string*/, name/*:string*/, opts, rels, wb, csheet) {
13616
	var cs/*:Worksheet*/ = ((csheet || {"!type":"chart"})/*:any*/);
13617
	if(!data) return csheet;
13618
	/* 21.2.2.27 chart CT_Chart */
13619
13620
	var C = 0, R = 0, col = "A";
13621
	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
13622
13623
	/* 21.2.2.120 numCache CT_NumData */
13624
	(data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
13625
		var cache = parse_numCache(nc);
13626
		refguess.s.r = refguess.s.c = 0;
13627
		refguess.e.c = C;
13628
		col = encode_col(C);
13629
		cache[0].forEach(function(n,i) {
13630
			cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
13631
			R = i;
13632
		});
13633
		if(refguess.e.r < R) refguess.e.r = R;
13634
		++C;
13635
	});
13636
	if(C > 0) cs["!ref"] = encode_range(refguess);
13637
	return cs;
13638
}
13639
RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
13640
13641
var CS_XML_ROOT = writextag('chartsheet', null, {
13642
	'xmlns': XMLNS.main[0],
13643
	'xmlns:r': XMLNS.r
13644
});
13645
13646
/* 18.3 Worksheets also covers Chartsheets */
13647
function parse_cs_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*::, themes, styles*/)/*:Worksheet*/ {
13648
	if(!data) return data;
13649
	/* 18.3.1.12 chartsheet CT_ChartSheet */
13650
	if(!rels) rels = {'!id':{}};
13651
	var s = {'!type':"chart", '!chart':null, '!rel':""};
13652
	var m;
13653
13654
	/* 18.3.1.83 sheetPr CT_ChartsheetPr */
13655
	var sheetPr = data.match(sheetprregex);
13656
	if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
13657
13658
	/* 18.3.1.36 drawing CT_Drawing */
13659
	if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
13660
13661
	if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']];
13662
	return s;
13663
}
13664
function write_cs_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
13665
	var o = [XML_HEADER, CS_XML_ROOT];
13666
	o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
13667
	add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
13668
	if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
13669
	return o.join("");
13670
}
13671
13672
/* [MS-XLSB] 2.4.331 BrtCsProp */
13673
function parse_BrtCsProp(data, length/*:number*/) {
13674
	data.l += 10;
13675
	var name = parse_XLWideString(data, length - 10);
13676
	return { name: name };
13677
}
13678
13679
/* [MS-XLSB] 2.1.7.7 Chart Sheet */
13680
function parse_cs_bin(data, opts, idx/*:number*/, rels, wb/*::, themes, styles*/)/*:Worksheet*/ {
13681
	if(!data) return data;
13682
	if(!rels) rels = {'!id':{}};
13683
	var s = {'!type':"chart", '!chart':null, '!rel':""};
13684
	var state/*:Array<string>*/ = [];
13685
	var pass = false;
13686
	recordhopper(data, function cs_parse(val, R_n, RT) {
13687
		switch(RT) {
13688
13689
			case 0x0226: /* 'BrtDrawing' */
13690
				s['!rel'] = val; break;
13691
13692
			case 0x028B: /* 'BrtCsProp' */
13693
				if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13694
				if(val.name) wb.Sheets[idx].CodeName = val.name;
13695
				break;
13696
13697
			case 0x0232: /* 'BrtBkHim' */
13698
			case 0x028C: /* 'BrtCsPageSetup' */
13699
			case 0x029D: /* 'BrtCsProtection' */
13700
			case 0x02A7: /* 'BrtCsProtectionIso' */
13701
			case 0x0227: /* 'BrtLegacyDrawing' */
13702
			case 0x0228: /* 'BrtLegacyDrawingHF' */
13703
			case 0x01DC: /* 'BrtMargins' */
13704
			case 0x0C00: /* 'BrtUid' */
13705
				break;
13706
13707
			case 0x0023: /* 'BrtFRTBegin' */
13708
				pass = true; break;
13709
			case 0x0024: /* 'BrtFRTEnd' */
13710
				pass = false; break;
13711
			case 0x0025: /* 'BrtACBegin' */
13712
				state.push(R_n); break;
13713
			case 0x0026: /* 'BrtACEnd' */
13714
				state.pop(); break;
13715
13716
			default:
13717
				if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
13718
				else if((R_n||"").indexOf("End") > 0) state.pop();
13719
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
13720
		}
13721
	}, opts);
13722
13723
	if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']];
13724
	return s;
13725
}
13726
function write_cs_bin(/*::idx:number, opts, wb:Workbook, rels*/) {
13727
	var ba = buf_array();
13728
	write_record(ba, "BrtBeginSheet");
13729
	/* [BrtCsProp] */
13730
	/* CSVIEWS */
13731
	/* [[BrtCsProtectionIso] BrtCsProtection] */
13732
	/* [USERCSVIEWS] */
13733
	/* [BrtMargins] */
13734
	/* [BrtCsPageSetup] */
13735
	/* [HEADERFOOTER] */
13736
	/* BrtDrawing */
13737
	/* [BrtLegacyDrawing] */
13738
	/* [BrtLegacyDrawingHF] */
13739
	/* [BrtBkHim] */
13740
	/* [WEBPUBITEMS] */
13741
	/* FRTCHARTSHEET */
13742
	write_record(ba, "BrtEndSheet");
13743
	return ba.end();
13744
}
13745
/* 18.2.28 (CT_WorkbookProtection) Defaults */
13746
var WBPropsDef = [
13747
	['allowRefreshQuery',           false, "bool"],
13748
	['autoCompressPictures',        true,  "bool"],
13749
	['backupFile',                  false, "bool"],
13750
	['checkCompatibility',          false, "bool"],
13751
	['CodeName',                    ''],
13752
	['date1904',                    false, "bool"],
13753
	['defaultThemeVersion',         0,      "int"],
13754
	['filterPrivacy',               false, "bool"],
13755
	['hidePivotFieldList',          false, "bool"],
13756
	['promptedSolutions',           false, "bool"],
13757
	['publishItems',                false, "bool"],
13758
	['refreshAllConnections',       false, "bool"],
13759
	['saveExternalLinkValues',      true,  "bool"],
13760
	['showBorderUnselectedTables',  true,  "bool"],
13761
	['showInkAnnotation',           true,  "bool"],
13762
	['showObjects',                 'all'],
13763
	['showPivotChartFilter',        false, "bool"],
13764
	['updateLinks', 'userSet']
13765
];
13766
13767
/* 18.2.30 (CT_BookView) Defaults */
13768
var WBViewDef = [
13769
	['activeTab',                   0,      "int"],
13770
	['autoFilterDateGrouping',      true,  "bool"],
13771
	['firstSheet',                  0,      "int"],
13772
	['minimized',                   false, "bool"],
13773
	['showHorizontalScroll',        true,  "bool"],
13774
	['showSheetTabs',               true,  "bool"],
13775
	['showVerticalScroll',          true,  "bool"],
13776
	['tabRatio',                    600,    "int"],
13777
	['visibility',                  'visible']
13778
	//window{Height,Width}, {x,y}Window
13779
];
13780
13781
/* 18.2.19 (CT_Sheet) Defaults */
13782
var SheetDef = [
13783
	//['state', 'visible']
13784
];
13785
13786
/* 18.2.2  (CT_CalcPr) Defaults */
13787
var CalcPrDef = [
13788
	['calcCompleted', 'true'],
13789
	['calcMode', 'auto'],
13790
	['calcOnSave', 'true'],
13791
	['concurrentCalc', 'true'],
13792
	['fullCalcOnLoad', 'false'],
13793
	['fullPrecision', 'true'],
13794
	['iterate', 'false'],
13795
	['iterateCount', '100'],
13796
	['iterateDelta', '0.001'],
13797
	['refMode', 'A1']
13798
];
13799
13800
/* 18.2.3 (CT_CustomWorkbookView) Defaults */
13801
/*var CustomWBViewDef = [
13802
	['autoUpdate', 'false'],
13803
	['changesSavedWin', 'false'],
13804
	['includeHiddenRowCol', 'true'],
13805
	['includePrintSettings', 'true'],
13806
	['maximized', 'false'],
13807
	['minimized', 'false'],
13808
	['onlySync', 'false'],
13809
	['personalView', 'false'],
13810
	['showComments', 'commIndicator'],
13811
	['showFormulaBar', 'true'],
13812
	['showHorizontalScroll', 'true'],
13813
	['showObjects', 'all'],
13814
	['showSheetTabs', 'true'],
13815
	['showStatusbar', 'true'],
13816
	['showVerticalScroll', 'true'],
13817
	['tabRatio', '600'],
13818
	['xWindow', '0'],
13819
	['yWindow', '0']
13820
];*/
13821
13822
function push_defaults_array(target, defaults) {
13823
	for(var j = 0; j != target.length; ++j) { var w = target[j];
13824
		for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
13825
			if(w[z[0]] == null) w[z[0]] = z[1];
13826
			else switch(z[2]) {
13827
			case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
13828
			case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
13829
			}
13830
		}
13831
	}
13832
}
13833
function push_defaults(target, defaults) {
13834
	for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
13835
		if(target[z[0]] == null) target[z[0]] = z[1];
13836
		else switch(z[2]) {
13837
			case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
13838
			case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
13839
		}
13840
	}
13841
}
13842
13843
function parse_wb_defaults(wb) {
13844
	push_defaults(wb.WBProps, WBPropsDef);
13845
	push_defaults(wb.CalcPr, CalcPrDef);
13846
13847
	push_defaults_array(wb.WBView, WBViewDef);
13848
	push_defaults_array(wb.Sheets, SheetDef);
13849
13850
	_ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
13851
}
13852
13853
function safe1904(wb/*:Workbook*/)/*:string*/ {
13854
	/* TODO: store date1904 somewhere else */
13855
	if(!wb.Workbook) return "false";
13856
	if(!wb.Workbook.WBProps) return "false";
13857
	return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
13858
}
13859
13860
var badchars = "][*?\/\\".split("");
13861
function check_ws_name(n/*:string*/, safe/*:?boolean*/)/*:boolean*/ {
13862
	if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
13863
	var _good = true;
13864
	badchars.forEach(function(c) {
13865
		if(n.indexOf(c) == -1) return;
13866
		if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
13867
		_good = false;
13868
	});
13869
	return _good;
13870
}
13871
function check_wb_names(N, S, codes) {
13872
	N.forEach(function(n,i) {
13873
		check_ws_name(n);
13874
		for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
13875
		if(codes) {
13876
			var cn = (S && S[i] && S[i].CodeName) || n;
13877
			if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
13878
		}
13879
	});
13880
}
13881
function check_wb(wb) {
13882
	if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
13883
	if(!wb.SheetNames.length) throw new Error("Workbook is empty");
13884
	var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
13885
	check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
13886
	for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
13887
	/* TODO: validate workbook */
13888
}
13889
/* 18.2 Workbook */
13890
var wbnsregex = /<\w+:workbook/;
13891
function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
13892
	if(!data) throw new Error("Could not find file");
13893
	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
13894
	var pass = false, xmlns = "xmlns";
13895
	var dname = {}, dnstart = 0;
13896
	data.replace(tagregex, function xml_wb(x, idx) {
13897
		var y/*:any*/ = parsexmltag(x);
13898
		switch(strip_ns(y[0])) {
13899
			case '<?xml': break;
13900
13901
			/* 18.2.27 workbook CT_Workbook 1 */
13902
			case '<workbook':
13903
				if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
13904
				wb.xmlns = y[xmlns];
13905
				break;
13906
			case '</workbook>': break;
13907
13908
			/* 18.2.13 fileVersion CT_FileVersion ? */
13909
			case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
13910
			case '<fileVersion/>': case '</fileVersion>': break;
13911
13912
			/* 18.2.12 fileSharing CT_FileSharing ? */
13913
			case '<fileSharing': case '<fileSharing/>': break;
13914
13915
			/* 18.2.28 workbookPr CT_WorkbookPr ? */
13916
			case '<workbookPr':
13917
			case '<workbookPr/>':
13918
				WBPropsDef.forEach(function(w) {
13919
					if(y[w[0]] == null) return;
13920
					switch(w[2]) {
13921
						case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
13922
						case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
13923
						default: wb.WBProps[w[0]] = y[w[0]];
13924
					}
13925
				});
13926
				if(y.codeName) wb.WBProps.CodeName = y.codeName;
13927
				break;
13928
			case '</workbookPr>': break;
13929
13930
			/* 18.2.29 workbookProtection CT_WorkbookProtection ? */
13931
			case '<workbookProtection': break;
13932
			case '<workbookProtection/>': break;
13933
13934
			/* 18.2.1  bookViews CT_BookViews ? */
13935
			case '<bookViews': case '<bookViews>': case '</bookViews>': break;
13936
			/* 18.2.30   workbookView CT_BookView + */
13937
			case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
13938
			case '</workbookView>': break;
13939
13940
			/* 18.2.20 sheets CT_Sheets 1 */
13941
			case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
13942
			/* 18.2.19   sheet CT_Sheet + */
13943
			case '<sheet':
13944
				switch(y.state) {
13945
					case "hidden": y.Hidden = 1; break;
13946
					case "veryHidden": y.Hidden = 2; break;
13947
					default: y.Hidden = 0;
13948
				}
13949
				delete y.state;
13950
				y.name = unescapexml(utf8read(y.name));
13951
				delete y[0]; wb.Sheets.push(y); break;
13952
			case '</sheet>': break;
13953
13954
			/* 18.2.15 functionGroups CT_FunctionGroups ? */
13955
			case '<functionGroups': case '<functionGroups/>': break;
13956
			/* 18.2.14   functionGroup CT_FunctionGroup + */
13957
			case '<functionGroup': break;
13958
13959
			/* 18.2.9  externalReferences CT_ExternalReferences ? */
13960
			case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
13961
			/* 18.2.8    externalReference CT_ExternalReference + */
13962
			case '<externalReference': break;
13963
13964
			/* 18.2.6  definedNames CT_DefinedNames ? */
13965
			case '<definedNames/>': break;
13966
			case '<definedNames>': case '<definedNames': pass=true; break;
13967
			case '</definedNames>': pass=false; break;
13968
			/* 18.2.5    definedName CT_DefinedName + */
13969
			case '<definedName': {
13970
				dname = {};
13971
				dname.Name = utf8read(y.name);
13972
				if(y.comment) dname.Comment = y.comment;
13973
				if(y.localSheetId) dname.Sheet = +y.localSheetId;
13974
				dnstart = idx + x.length;
13975
			}	break;
13976
			case '</definedName>': {
13977
				dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
13978
				wb.Names.push(dname);
13979
			} break;
13980
			case '<definedName/>': break;
13981
13982
			/* 18.2.2  calcPr CT_CalcPr ? */
13983
			case '<calcPr': delete y[0]; wb.CalcPr = y; break;
13984
			case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
13985
			case '</calcPr>': break;
13986
13987
			/* 18.2.16 oleSize CT_OleSize ? (ref required) */
13988
			case '<oleSize': break;
13989
13990
			/* 18.2.4  customWorkbookViews CT_CustomWorkbookViews ? */
13991
			case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
13992
			/* 18.2.3    customWorkbookView CT_CustomWorkbookView + */
13993
			case '<customWorkbookView': case '</customWorkbookView>': break;
13994
13995
			/* 18.2.18 pivotCaches CT_PivotCaches ? */
13996
			case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
13997
			/* 18.2.17 pivotCache CT_PivotCache ? */
13998
			case '<pivotCache': break;
13999
14000
			/* 18.2.21 smartTagPr CT_SmartTagPr ? */
14001
			case '<smartTagPr': case '<smartTagPr/>': break;
14002
14003
			/* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
14004
			case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
14005
			/* 18.2.22   smartTagType CT_SmartTagType ? */
14006
			case '<smartTagType': break;
14007
14008
			/* 18.2.24 webPublishing CT_WebPublishing ? */
14009
			case '<webPublishing': case '<webPublishing/>': break;
14010
14011
			/* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
14012
			case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
14013
14014
			/* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
14015
			case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
14016
			/* 18.2.25 webPublishObject CT_WebPublishObject ? */
14017
			case '<webPublishObject': break;
14018
14019
			/* 18.2.10 extLst CT_ExtensionList ? */
14020
			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
14021
			/* 18.2.7    ext CT_Extension + */
14022
			case '<ext': pass=true; break; //TODO: check with versions of excel
14023
			case '</ext>': pass=false; break;
14024
14025
			/* Others */
14026
			case '<ArchID': break;
14027
			case '<AlternateContent':
14028
			case '<AlternateContent>': pass=true; break;
14029
			case '</AlternateContent>': pass=false; break;
14030
14031
			/* TODO */
14032
			case '<revisionPtr': break;
14033
14034
			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
14035
		}
14036
		return x;
14037
	});
14038
	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
14039
14040
	parse_wb_defaults(wb);
14041
14042
	return wb;
14043
}
14044
14045
var WB_XML_ROOT = writextag('workbook', null, {
14046
	'xmlns': XMLNS.main[0],
14047
	//'xmlns:mx': XMLNS.mx,
14048
	//'xmlns:s': XMLNS.main[0],
14049
	'xmlns:r': XMLNS.r
14050
});
14051
14052
function write_wb_xml(wb/*:Workbook*//*::, opts:?WriteOpts*/)/*:string*/ {
14053
	var o = [XML_HEADER];
14054
	o[o.length] = WB_XML_ROOT;
14055
14056
	var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
14057
14058
	/* fileVersion */
14059
	/* fileSharing */
14060
14061
	var workbookPr/*:any*/ = ({codeName:"ThisWorkbook"}/*:any*/);
14062
	if(wb.Workbook && wb.Workbook.WBProps) {
14063
		WBPropsDef.forEach(function(x) {
14064
			/*:: if(!wb.Workbook || !wb.Workbook.WBProps) throw "unreachable"; */
14065
			if((wb.Workbook.WBProps[x[0]]/*:any*/) == null) return;
14066
			if((wb.Workbook.WBProps[x[0]]/*:any*/) == x[1]) return;
14067
			workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]/*:any*/);
14068
		});
14069
		/*:: if(!wb.Workbook || !wb.Workbook.WBProps) throw "unreachable"; */
14070
		if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
14071
	}
14072
	o[o.length] = (writextag('workbookPr', null, workbookPr));
14073
14074
	/* workbookProtection */
14075
	/* bookViews */
14076
14077
	o[o.length] = "<sheets>";
14078
	var sheets = wb.Workbook && wb.Workbook.Sheets || [];
14079
	for(var i = 0; i != wb.SheetNames.length; ++i) {
14080
		var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))}/*:any*/);
14081
		sht.sheetId = ""+(i+1);
14082
		sht["r:id"] = "rId"+(i+1);
14083
		if(sheets[i]) switch(sheets[i].Hidden) {
14084
			case 1: sht.state = "hidden"; break;
14085
			case 2: sht.state = "veryHidden"; break;
14086
		}
14087
		o[o.length] = (writextag('sheet',null,sht));
14088
	}
14089
	o[o.length] = "</sheets>";
14090
14091
	/* functionGroups */
14092
	/* externalReferences */
14093
14094
	if(write_names) {
14095
		o[o.length] = "<definedNames>";
14096
		if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
14097
			var d/*:any*/ = {name:n.Name};
14098
			if(n.Comment) d.comment = n.Comment;
14099
			if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
14100
			if(!n.Ref) return;
14101
			o[o.length] = writextag('definedName', String(n.Ref), d);
14102
		});
14103
		o[o.length] = "</definedNames>";
14104
	}
14105
14106
	/* calcPr */
14107
	/* oleSize */
14108
	/* customWorkbookViews */
14109
	/* pivotCaches */
14110
	/* smartTagPr */
14111
	/* smartTagTypes */
14112
	/* webPublishing */
14113
	/* fileRecoveryPr */
14114
	/* webPublishObjects */
14115
	/* extLst */
14116
14117
	if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
14118
	return o.join("");
14119
}
14120
/* [MS-XLSB] 2.4.304 BrtBundleSh */
14121
function parse_BrtBundleSh(data, length/*:number*/) {
14122
	var z = {};
14123
	z.Hidden = data.read_shift(4); //hsState ST_SheetState
14124
	z.iTabID = data.read_shift(4);
14125
	z.strRelID = parse_RelID(data,length-8);
14126
	z.name = parse_XLWideString(data);
14127
	return z;
14128
}
14129
function write_BrtBundleSh(data, o) {
14130
	if(!o) o = new_buf(127);
14131
	o.write_shift(4, data.Hidden);
14132
	o.write_shift(4, data.iTabID);
14133
	write_RelID(data.strRelID, o);
14134
	write_XLWideString(data.name.slice(0,31), o);
14135
	return o.length > o.l ? o.slice(0, o.l) : o;
14136
}
14137
14138
/* [MS-XLSB] 2.4.815 BrtWbProp */
14139
function parse_BrtWbProp(data, length)/*:WBProps*/ {
14140
	var o/*:WBProps*/ = ({}/*:any*/);
14141
	var flags = data.read_shift(4);
14142
	o.defaultThemeVersion = data.read_shift(4);
14143
	var strName = (length > 8) ? parse_XLWideString(data) : "";
14144
	if(strName.length > 0) o.CodeName = strName;
14145
	o.autoCompressPictures = !!(flags & 0x10000);
14146
	o.backupFile = !!(flags & 0x40);
14147
	o.checkCompatibility = !!(flags & 0x1000);
14148
	o.date1904 = !!(flags & 0x01);
14149
	o.filterPrivacy = !!(flags & 0x08);
14150
	o.hidePivotFieldList = !!(flags & 0x400);
14151
	o.promptedSolutions = !!(flags & 0x10);
14152
	o.publishItems = !!(flags & 0x800);
14153
	o.refreshAllConnections = !!(flags & 0x40000);
14154
	o.saveExternalLinkValues = !!(flags & 0x80);
14155
	o.showBorderUnselectedTables = !!(flags & 0x04);
14156
	o.showInkAnnotation = !!(flags & 0x20);
14157
	o.showObjects = ["all", "placeholders", "none"][(flags >> 13) & 0x03];
14158
	o.showPivotChartFilter = !!(flags & 0x8000);
14159
	o.updateLinks = ["userSet", "never", "always"][(flags >> 8) & 0x03];
14160
	return o;
14161
}
14162
function write_BrtWbProp(data/*:?WBProps*/, o) {
14163
	if(!o) o = new_buf(72);
14164
	var flags = 0;
14165
	if(data) {
14166
		/* TODO: mirror parse_BrtWbProp fields */
14167
		if(data.filterPrivacy) flags |= 0x08;
14168
	}
14169
	o.write_shift(4, flags);
14170
	o.write_shift(4, 0);
14171
	write_XLSBCodeName(data && data.CodeName || "ThisWorkbook", o);
14172
	return o.slice(0, o.l);
14173
}
14174
14175
function parse_BrtFRTArchID$(data, length) {
14176
	var o = {};
14177
	data.read_shift(4);
14178
	o.ArchID = data.read_shift(4);
14179
	data.l += length - 8;
14180
	return o;
14181
}
14182
14183
/* [MS-XLSB] 2.4.687 BrtName */
14184
function parse_BrtName(data, length, opts) {
14185
	var end = data.l + length;
14186
	data.l += 4; //var flags = data.read_shift(4);
14187
	data.l += 1; //var chKey = data.read_shift(1);
14188
	var itab = data.read_shift(4);
14189
	var name = parse_XLNameWideString(data);
14190
	var formula = parse_XLSBNameParsedFormula(data, 0, opts);
14191
	var comment = parse_XLNullableWideString(data);
14192
	//if(0 /* fProc */) {
14193
		// unusedstring1: XLNullableWideString
14194
		// description: XLNullableWideString
14195
		// helpTopic: XLNullableWideString
14196
		// unusedstring2: XLNullableWideString
14197
	//}
14198
	data.l = end;
14199
	var out = ({Name:name, Ptg:formula}/*:any*/);
14200
	if(itab < 0xFFFFFFF) out.Sheet = itab;
14201
	if(comment) out.Comment = comment;
14202
	return out;
14203
}
14204
14205
/* [MS-XLSB] 2.1.7.61 Workbook */
14206
function parse_wb_bin(data, opts)/*:WorkbookFile*/ {
14207
	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
14208
	var pass = false;
14209
14210
	if(!opts) opts = {};
14211
	opts.biff = 12;
14212
14213
	var Names = [];
14214
	var supbooks = ([[]]/*:any*/);
14215
	supbooks.SheetNames = [];
14216
	supbooks.XTI = [];
14217
14218
	recordhopper(data, function hopper_wb(val, R_n, RT) {
14219
		switch(RT) {
14220
			case 0x009C: /* 'BrtBundleSh' */
14221
				supbooks.SheetNames.push(val.name);
14222
				wb.Sheets.push(val); break;
14223
14224
			case 0x0099: /* 'BrtWbProp' */
14225
				wb.WBProps = val; break;
14226
14227
			case 0x0027: /* 'BrtName' */
14228
				if(val.Sheet != null) opts.SID = val.Sheet;
14229
				val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts);
14230
				delete opts.SID;
14231
				delete val.Ptg;
14232
				Names.push(val);
14233
				break;
14234
			case 0x040C: /* 'BrtNameExt' */ break;
14235
14236
			case 0x0165: /* 'BrtSupSelf' */
14237
			case 0x0166: /* 'BrtSupSame' */
14238
			case 0x0163: /* 'BrtSupBookSrc' */
14239
			case 0x029B: /* 'BrtSupAddin' */
14240
				if(!supbooks[0].length) supbooks[0] = [RT, val];
14241
				else supbooks.push([RT, val]);
14242
				supbooks[supbooks.length - 1].XTI = [];
14243
				break;
14244
			case 0x016A: /* 'BrtExternSheet' */
14245
				if(supbooks.length === 0) { supbooks[0] = []; supbooks[0].XTI = []; }
14246
				supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val);
14247
				supbooks.XTI = supbooks.XTI.concat(val);
14248
				break;
14249
			case 0x0169: /* 'BrtPlaceholderName' */
14250
				break;
14251
14252
			/* case 'BrtModelTimeGroupingCalcCol' */
14253
			case 0x0C00: /* 'BrtUid' */
14254
			case 0x0C01: /* 'BrtRevisionPtr' */
14255
			case 0x0817: /* 'BrtAbsPath15' */
14256
			case 0x0216: /* 'BrtBookProtection' */
14257
			case 0x02A5: /* 'BrtBookProtectionIso' */
14258
			case 0x009E: /* 'BrtBookView' */
14259
			case 0x009D: /* 'BrtCalcProp' */
14260
			case 0x0262: /* 'BrtCrashRecErr' */
14261
			case 0x0802: /* 'BrtDecoupledPivotCacheID' */
14262
			case 0x009B: /* 'BrtFileRecover' */
14263
			case 0x0224: /* 'BrtFileSharing' */
14264
			case 0x02A4: /* 'BrtFileSharingIso' */
14265
			case 0x0080: /* 'BrtFileVersion' */
14266
			case 0x0299: /* 'BrtFnGroup' */
14267
			case 0x0850: /* 'BrtModelRelationship' */
14268
			case 0x084D: /* 'BrtModelTable' */
14269
			case 0x0225: /* 'BrtOleSize' */
14270
			case 0x0805: /* 'BrtPivotTableRef' */
14271
			case 0x0254: /* 'BrtSmartTagType' */
14272
			case 0x081C: /* 'BrtTableSlicerCacheID' */
14273
			case 0x081B: /* 'BrtTableSlicerCacheIDs' */
14274
			case 0x0822: /* 'BrtTimelineCachePivotCacheID' */
14275
			case 0x018D: /* 'BrtUserBookView' */
14276
			case 0x009A: /* 'BrtWbFactoid' */
14277
			case 0x045D: /* 'BrtWbProp14' */
14278
			case 0x0229: /* 'BrtWebOpt' */
14279
			case 0x082B: /* 'BrtWorkBookPr15' */
14280
				break;
14281
14282
			case 0x0023: /* 'BrtFRTBegin' */
14283
				pass = true; break;
14284
			case 0x0024: /* 'BrtFRTEnd' */
14285
				pass = false; break;
14286
			case 0x0025: /* 'BrtACBegin' */ break;
14287
			case 0x0026: /* 'BrtACEnd' */ break;
14288
14289
			case 0x0010: /* 'BrtFRTArchID$' */ break;
14290
14291
			default:
14292
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
14293
				else if((R_n||"").indexOf("End") > 0){/* empty */}
14294
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14295
		}
14296
	}, opts);
14297
14298
	parse_wb_defaults(wb);
14299
14300
	// $FlowIgnore
14301
	wb.Names = Names;
14302
14303
	(wb/*:any*/).supbooks = supbooks;
14304
	return wb;
14305
}
14306
14307
function write_BUNDLESHS(ba, wb/*::, opts*/) {
14308
	write_record(ba, "BrtBeginBundleShs");
14309
	for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
14310
		var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
14311
		var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
14312
		write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
14313
	}
14314
	write_record(ba, "BrtEndBundleShs");
14315
}
14316
14317
/* [MS-XLSB] 2.4.649 BrtFileVersion */
14318
function write_BrtFileVersion(data, o) {
14319
	if(!o) o = new_buf(127);
14320
	for(var i = 0; i != 4; ++i) o.write_shift(4, 0);
14321
	write_XLWideString("SheetJS", o);
14322
	write_XLWideString(XLSX.version, o);
14323
	write_XLWideString(XLSX.version, o);
14324
	write_XLWideString("7262", o);
14325
	o.length = o.l;
14326
	return o.length > o.l ? o.slice(0, o.l) : o;
14327
}
14328
14329
/* [MS-XLSB] 2.4.301 BrtBookView */
14330
function write_BrtBookView(idx, o) {
14331
	if(!o) o = new_buf(29);
14332
	o.write_shift(-4, 0);
14333
	o.write_shift(-4, 460);
14334
	o.write_shift(4,  28800);
14335
	o.write_shift(4,  17600);
14336
	o.write_shift(4,  500);
14337
	o.write_shift(4,  idx);
14338
	o.write_shift(4,  idx);
14339
	var flags = 0x78;
14340
	o.write_shift(1,  flags);
14341
	return o.length > o.l ? o.slice(0, o.l) : o;
14342
}
14343
14344
function write_BOOKVIEWS(ba, wb/*::, opts*/) {
14345
	/* required if hidden tab appears before visible tab */
14346
	if(!wb.Workbook || !wb.Workbook.Sheets) return;
14347
	var sheets = wb.Workbook.Sheets;
14348
	var i = 0, vistab = -1, hidden = -1;
14349
	for(; i < sheets.length; ++i) {
14350
		if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
14351
		else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
14352
	}
14353
	if(hidden > vistab) return;
14354
	write_record(ba, "BrtBeginBookViews");
14355
	write_record(ba, "BrtBookView", write_BrtBookView(vistab));
14356
	/* 1*(BrtBookView *FRT) */
14357
	write_record(ba, "BrtEndBookViews");
14358
}
14359
14360
/* [MS-XLSB] 2.4.305 BrtCalcProp */
14361
/*function write_BrtCalcProp(data, o) {
14362
	if(!o) o = new_buf(26);
14363
	o.write_shift(4,0); // force recalc
14364
	o.write_shift(4,1);
14365
	o.write_shift(4,0);
14366
	write_Xnum(0, o);
14367
	o.write_shift(-4, 1023);
14368
	o.write_shift(1, 0x33);
14369
	o.write_shift(1, 0x00);
14370
	return o;
14371
}*/
14372
14373
/* [MS-XLSB] 2.4.646 BrtFileRecover */
14374
/*function write_BrtFileRecover(data, o) {
14375
	if(!o) o = new_buf(1);
14376
	o.write_shift(1,0);
14377
	return o;
14378
}*/
14379
14380
/* [MS-XLSB] 2.1.7.61 Workbook */
14381
function write_wb_bin(wb, opts) {
14382
	var ba = buf_array();
14383
	write_record(ba, "BrtBeginBook");
14384
	write_record(ba, "BrtFileVersion", write_BrtFileVersion());
14385
	/* [[BrtFileSharingIso] BrtFileSharing] */
14386
	write_record(ba, "BrtWbProp", write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null));
14387
	/* [ACABSPATH] */
14388
	/* [[BrtBookProtectionIso] BrtBookProtection] */
14389
	write_BOOKVIEWS(ba, wb, opts);
14390
	write_BUNDLESHS(ba, wb, opts);
14391
	/* [FNGROUP] */
14392
	/* [EXTERNALS] */
14393
	/* *BrtName */
14394
	/* write_record(ba, "BrtCalcProp", write_BrtCalcProp()); */
14395
	/* [BrtOleSize] */
14396
	/* *(BrtUserBookView *FRT) */
14397
	/* [PIVOTCACHEIDS] */
14398
	/* [BrtWbFactoid] */
14399
	/* [SMARTTAGTYPES] */
14400
	/* [BrtWebOpt] */
14401
	/* write_record(ba, "BrtFileRecover", write_BrtFileRecover()); */
14402
	/* [WEBPUBITEMS] */
14403
	/* [CRERRS] */
14404
	/* FRTWORKBOOK */
14405
	write_record(ba, "BrtEndBook");
14406
14407
	return ba.end();
14408
}
14409
function parse_wb(data, name/*:string*/, opts)/*:WorkbookFile*/ {
14410
	if(name.slice(-4)===".bin") return parse_wb_bin((data/*:any*/), opts);
14411
	return parse_wb_xml((data/*:any*/), opts);
14412
}
14413
14414
function parse_ws(data, name/*:string*/, idx/*:number*/, opts, rels, wb, themes, styles)/*:Worksheet*/ {
14415
	if(name.slice(-4)===".bin") return parse_ws_bin((data/*:any*/), opts, idx, rels, wb, themes, styles);
14416
	return parse_ws_xml((data/*:any*/), opts, idx, rels, wb, themes, styles);
14417
}
14418
14419
function parse_cs(data, name/*:string*/, idx/*:number*/, opts, rels, wb, themes, styles)/*:Worksheet*/ {
14420
	if(name.slice(-4)===".bin") return parse_cs_bin((data/*:any*/), opts, idx, rels, wb, themes, styles);
14421
	return parse_cs_xml((data/*:any*/), opts, idx, rels, wb, themes, styles);
14422
}
14423
14424
function parse_ms(data, name/*:string*/, idx/*:number*/, opts, rels, wb, themes, styles)/*:Worksheet*/ {
14425
	if(name.slice(-4)===".bin") return parse_ms_bin((data/*:any*/), opts, idx, rels, wb, themes, styles);
14426
	return parse_ms_xml((data/*:any*/), opts, idx, rels, wb, themes, styles);
14427
}
14428
14429
function parse_ds(data, name/*:string*/, idx/*:number*/, opts, rels, wb, themes, styles)/*:Worksheet*/ {
14430
	if(name.slice(-4)===".bin") return parse_ds_bin((data/*:any*/), opts, idx, rels, wb, themes, styles);
14431
	return parse_ds_xml((data/*:any*/), opts, idx, rels, wb, themes, styles);
14432
}
14433
14434
function parse_sty(data, name/*:string*/, themes, opts) {
14435
	if(name.slice(-4)===".bin") return parse_sty_bin((data/*:any*/), themes, opts);
14436
	return parse_sty_xml((data/*:any*/), themes, opts);
14437
}
14438
14439
function parse_theme(data/*:string*/, name/*:string*/, opts) {
14440
	return parse_theme_xml(data, opts);
14441
}
14442
14443
function parse_sst(data, name/*:string*/, opts)/*:SST*/ {
14444
	if(name.slice(-4)===".bin") return parse_sst_bin((data/*:any*/), opts);
14445
	return parse_sst_xml((data/*:any*/), opts);
14446
}
14447
14448
function parse_cmnt(data, name/*:string*/, opts)/*:Array<RawComment>*/ {
14449
	if(name.slice(-4)===".bin") return parse_comments_bin((data/*:any*/), opts);
14450
	return parse_comments_xml((data/*:any*/), opts);
14451
}
14452
14453
function parse_cc(data, name/*:string*/, opts) {
14454
	if(name.slice(-4)===".bin") return parse_cc_bin((data/*:any*/), name, opts);
14455
	return parse_cc_xml((data/*:any*/), name, opts);
14456
}
14457
14458
function parse_xlink(data, name/*:string*/, opts) {
14459
	if(name.slice(-4)===".bin") return parse_xlink_bin((data/*:any*/), name, opts);
14460
	return parse_xlink_xml((data/*:any*/), name, opts);
14461
}
14462
14463
function write_wb(wb, name/*:string*/, opts) {
14464
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
14465
}
14466
14467
function write_ws(data/*:number*/, name/*:string*/, opts, wb/*:Workbook*/, rels) {
14468
	return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
14469
}
14470
14471
// eslint-disable-next-line no-unused-vars
14472
function write_cs(data/*:number*/, name/*:string*/, opts, wb/*:Workbook*/, rels) {
14473
	return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
14474
}
14475
14476
function write_sty(data, name/*:string*/, opts) {
14477
	return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
14478
}
14479
14480
function write_sst(data/*:SST*/, name/*:string*/, opts) {
14481
	return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
14482
}
14483
14484
function write_cmnt(data/*:Array<any>*/, name/*:string*/, opts) {
14485
	return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
14486
}
14487
/*
14488
function write_cc(data, name:string, opts) {
14489
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
14490
}
14491
*/
14492
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
14493
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
14494
var _chr = function(c) { return String.fromCharCode(c); };
14495
function xlml_parsexmltag(tag/*:string*/, skip_root/*:?boolean*/) {
14496
	var words = tag.split(/\s+/);
14497
	var z/*:any*/ = ([]/*:any*/); if(!skip_root) z[0] = words[0];
14498
	if(words.length === 1) return z;
14499
	var m = tag.match(attregexg2), y, j, w, i;
14500
	if(m) for(i = 0; i != m.length; ++i) {
14501
		y = m[i].match(attregex2);
14502
/*:: if(!y || !y[2]) continue; */
14503
		if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
14504
		else {
14505
			if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
14506
			else w = y[1].slice(j+1);
14507
			z[w] = y[2].slice(1,y[2].length-1);
14508
		}
14509
	}
14510
	return z;
14511
}
14512
function xlml_parsexmltagobj(tag/*:string*/) {
14513
	var words = tag.split(/\s+/);
14514
	var z = {};
14515
	if(words.length === 1) return z;
14516
	var m = tag.match(attregexg2), y, j, w, i;
14517
	if(m) for(i = 0; i != m.length; ++i) {
14518
		y = m[i].match(attregex2);
14519
/*:: if(!y || !y[2]) continue; */
14520
		if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
14521
		else {
14522
			if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
14523
			else w = y[1].slice(j+1);
14524
			z[w] = y[2].slice(1,y[2].length-1);
14525
		}
14526
	}
14527
	return z;
14528
}
14529
14530
// ----
14531
14532
function xlml_format(format, value)/*:string*/ {
14533
	var fmt = XLMLFormatMap[format] || unescapexml(format);
14534
	if(fmt === "General") return SSF._general(value);
14535
	return SSF.format(fmt, value);
14536
}
14537
14538
function xlml_set_custprop(Custprops, key, cp, val/*:string*/) {
14539
	var oval/*:any*/ = val;
14540
	switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) {
14541
		case "boolean": oval = parsexmlbool(val); break;
14542
		case "i2": case "int": oval = parseInt(val, 10); break;
14543
		case "r4": case "float": oval = parseFloat(val); break;
14544
		case "date": case "dateTime.tz": oval = parseDate(val); break;
14545
		case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break;
14546
		default: throw new Error("bad custprop:" + cp[0]);
14547
	}
14548
	Custprops[unescapexml(key)] = oval;
14549
}
14550
14551
function safe_format_xlml(cell/*:Cell*/, nf, o) {
14552
	if(cell.t === 'z') return;
14553
	if(!o || o.cellText !== false) try {
14554
		if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
14555
		else if(nf === "General") {
14556
			if(cell.t === 'n') {
14557
				if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v);
14558
				else cell.w = SSF._general_num(cell.v);
14559
			}
14560
			else cell.w = SSF._general(cell.v);
14561
		}
14562
		else cell.w = xlml_format(nf||"General", cell.v);
14563
	} catch(e) { if(o.WTF) throw e; }
14564
	try {
14565
		var z = XLMLFormatMap[nf]||nf||"General";
14566
		if(o.cellNF) cell.z = z;
14567
		if(o.cellDates && cell.t == 'n' && SSF.is_date(z)) {
14568
			var _d = SSF.parse_date_code(cell.v); if(_d) { cell.t = 'd'; cell.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
14569
		}
14570
	} catch(e) { if(o.WTF) throw e; }
14571
}
14572
14573
function process_style_xlml(styles, stag, opts) {
14574
	if(opts.cellStyles) {
14575
		if(stag.Interior) {
14576
			var I = stag.Interior;
14577
			if(I.Pattern) I.patternType = XLMLPatternTypeMap[I.Pattern] || I.Pattern;
14578
		}
14579
	}
14580
	styles[stag.ID] = stag;
14581
}
14582
14583
/* TODO: there must exist some form of OSP-blessed spec */
14584
function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, arrayf, o) {
14585
	var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
14586
	var interiors = [];
14587
	var i = 0;
14588
	if(sid === undefined && row) sid = row.StyleID;
14589
	if(sid === undefined && csty) sid = csty.StyleID;
14590
	while(styles[sid] !== undefined) {
14591
		if(styles[sid].nf) nf = styles[sid].nf;
14592
		if(styles[sid].Interior) interiors.push(styles[sid].Interior);
14593
		if(!styles[sid].Parent) break;
14594
		sid = styles[sid].Parent;
14595
	}
14596
	switch(data.Type) {
14597
		case 'Boolean':
14598
			cell.t = 'b';
14599
			cell.v = parsexmlbool(xml);
14600
			break;
14601
		case 'String':
14602
			cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
14603
			cell.v = xml.indexOf("<") > -1 ? unescapexml(ss) : cell.r;
14604
			break;
14605
		case 'DateTime':
14606
			if(xml.slice(-1) != "Z") xml += "Z";
14607
			cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
14608
			if(cell.v !== cell.v) cell.v = unescapexml(xml);
14609
			else if(cell.v<60) cell.v = cell.v -1;
14610
			if(!nf || nf == "General") nf = "yyyy-mm-dd";
14611
			/* falls through */
14612
		case 'Number':
14613
			if(cell.v === undefined) cell.v=+xml;
14614
			if(!cell.t) cell.t = 'n';
14615
			break;
14616
		case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
14617
		default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
14618
	}
14619
	safe_format_xlml(cell, nf, o);
14620
	if(o.cellFormula !== false) {
14621
		if(cell.Formula) {
14622
			var fstr = unescapexml(cell.Formula);
14623
			/* strictly speaking, the leading = is required but some writers omit */
14624
			if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.slice(1);
14625
			cell.f = rc_to_a1(fstr, base);
14626
			delete cell.Formula;
14627
			if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base);
14628
			else if(cell.ArrayRange) {
14629
				cell.F = rc_to_a1(cell.ArrayRange, base);
14630
				arrayf.push([safe_decode_range(cell.F), cell.F]);
14631
			}
14632
		} else {
14633
			for(i = 0; i < arrayf.length; ++i)
14634
				if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r)
14635
					if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c)
14636
						cell.F = arrayf[i][1];
14637
		}
14638
	}
14639
	if(o.cellStyles) {
14640
		interiors.forEach(function(x) {
14641
			if(!S.patternType && x.patternType) S.patternType = x.patternType;
14642
		});
14643
		cell.s = S;
14644
	}
14645
	if(cell.StyleID !== undefined) cell.ixfe = cell.StyleID;
14646
}
14647
14648
function xlml_clean_comment(comment/*:any*/) {
14649
	comment.t = comment.v || "";
14650
	comment.t = comment.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
14651
	comment.v = comment.w = comment.ixfe = undefined;
14652
}
14653
14654
function xlml_normalize(d)/*:string*/ {
14655
	if(has_buf &&/*::typeof Buffer !== "undefined" && d != null && d instanceof Buffer &&*/ Buffer.isBuffer(d)) return d.toString('utf8');
14656
	if(typeof d === 'string') return d;
14657
	/* duktape */
14658
	if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d)));
14659
	throw new Error("Bad input format: expected Buffer or string");
14660
}
14661
14662
/* TODO: Everything */
14663
/* UOS uses CJK in tags */
14664
var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>:\/]+)[^>]*>/mg;
14665
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
14666
function parse_xlml_xml(d, _opts)/*:Workbook*/ {
14667
	var opts = _opts || {};
14668
	make_ssf(SSF);
14669
	var str = debom(xlml_normalize(d));
14670
	if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') {
14671
		if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
14672
		else str = utf8read(str);
14673
	}
14674
	var opening = str.slice(0, 1024).toLowerCase(), ishtml = false;
14675
	if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; });
14676
	if(ishtml) return HTML_.to_workbook(str, opts);
14677
	var Rn;
14678
	var state = [], tmp;
14679
	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
14680
	var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = (opts.dense ? [] : {}), sheetname = "";
14681
	var table = {}, cell = ({}/*:any*/), row = {};// eslint-disable-line no-unused-vars
14682
	var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
14683
	var c = 0, r = 0;
14684
	var refguess/*:Range*/ = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14685
	var styles = {}, stag = {};
14686
	var ss = "", fidx = 0;
14687
	var merges/*:Array<Range>*/ = [];
14688
	var Props = {}, Custprops = {}, pidx = 0, cp = [];
14689
	var comments/*:Array<Comment>*/ = [], comment/*:Comment*/ = ({}/*:any*/);
14690
	var cstys = [], csty, seencol = false;
14691
	var arrayf/*:Array<[Range, string]>*/ = [];
14692
	var rowinfo/*:Array<RowInfo>*/ = [], rowobj = {}, cc = 0, rr = 0;
14693
	var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false} }/*:any*/), wsprops = {};
14694
	xlmlregex.lastIndex = 0;
14695
	str = str.replace(/<!--([\s\S]*?)-->/mg,"");
14696
	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
14697
		case 'Data':
14698
			if(state[state.length-1][1]) break;
14699
			if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts);
14700
			else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
14701
			break;
14702
		case 'Cell':
14703
			if(Rn[1]==='/'){
14704
				if(comments.length > 0) cell.c = comments;
14705
				if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) {
14706
					if(opts.dense) {
14707
						if(!cursheet[r]) cursheet[r] = [];
14708
						cursheet[r][c] = cell;
14709
					} else cursheet[encode_col(c) + encode_row(r)] = cell;
14710
				}
14711
				if(cell.HRef) {
14712
					cell.l = ({Target:cell.HRef}/*:any*/);
14713
					if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
14714
					delete cell.HRef; delete cell.HRefScreenTip;
14715
				}
14716
				if(cell.MergeAcross || cell.MergeDown) {
14717
					cc = c + (parseInt(cell.MergeAcross,10)|0);
14718
					rr = r + (parseInt(cell.MergeDown,10)|0);
14719
					merges.push({s:{c:c,r:r},e:{c:cc,r:rr}});
14720
				}
14721
				if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
14722
				else if(cell.MergeAcross || cell.MergeDown) {
14723
					/*:: if(!cc) cc = 0; if(!rr) rr = 0; */
14724
					for(var cma = c; cma <= cc; ++cma) {
14725
						for(var cmd = r; cmd <= rr; ++cmd) {
14726
							if(cma > c || cmd > r) {
14727
								if(opts.dense) {
14728
									if(!cursheet[cmd]) cursheet[cmd] = [];
14729
									cursheet[cmd][cma] = {t:'z'};
14730
								} else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
14731
							}
14732
						}
14733
					}
14734
					c = cc + 1;
14735
				}
14736
				else ++c;
14737
			} else {
14738
				cell = xlml_parsexmltagobj(Rn[0]);
14739
				if(cell.Index) c = +cell.Index - 1;
14740
				if(c < refguess.s.c) refguess.s.c = c;
14741
				if(c > refguess.e.c) refguess.e.c = c;
14742
				if(Rn[0].slice(-2) === "/>") ++c;
14743
				comments = [];
14744
			}
14745
			break;
14746
		case 'Row':
14747
			if(Rn[1]==='/' || Rn[0].slice(-2) === "/>") {
14748
				if(r < refguess.s.r) refguess.s.r = r;
14749
				if(r > refguess.e.r) refguess.e.r = r;
14750
				if(Rn[0].slice(-2) === "/>") {
14751
					row = xlml_parsexmltag(Rn[0]);
14752
					if(row.Index) r = +row.Index - 1;
14753
				}
14754
				c = 0; ++r;
14755
			} else {
14756
				row = xlml_parsexmltag(Rn[0]);
14757
				if(row.Index) r = +row.Index - 1;
14758
				rowobj = {};
14759
				if(row.AutoFitHeight == "0" || row.Height) {
14760
					rowobj.hpx = parseInt(row.Height, 10); rowobj.hpt = px2pt(rowobj.hpx);
14761
					rowinfo[r] = rowobj;
14762
				}
14763
				if(row.Hidden == "1") { rowobj.hidden = true; rowinfo[r] = rowobj; }
14764
			}
14765
			break;
14766
		case 'Worksheet': /* TODO: read range from FullRows/FullColumns */
14767
			if(Rn[1]==='/'){
14768
				if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
14769
				sheetnames.push(sheetname);
14770
				if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) {
14771
					cursheet["!ref"] = encode_range(refguess);
14772
					if(opts.sheetRows && opts.sheetRows <= refguess.e.r) {
14773
						cursheet["!fullref"] = cursheet["!ref"];
14774
						refguess.e.r = opts.sheetRows - 1;
14775
						cursheet["!ref"] = encode_range(refguess);
14776
					}
14777
				}
14778
				if(merges.length) cursheet["!merges"] = merges;
14779
				if(cstys.length > 0) cursheet["!cols"] = cstys;
14780
				if(rowinfo.length > 0) cursheet["!rows"] = rowinfo;
14781
				sheets[sheetname] = cursheet;
14782
			} else {
14783
				refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14784
				r = c = 0;
14785
				state.push([Rn[3], false]);
14786
				tmp = xlml_parsexmltag(Rn[0]);
14787
				sheetname = unescapexml(tmp.Name);
14788
				cursheet = (opts.dense ? [] : {});
14789
				merges = [];
14790
				arrayf = [];
14791
				rowinfo = [];
14792
				wsprops = {name:sheetname, Hidden:0};
14793
				Workbook.Sheets.push(wsprops);
14794
			}
14795
			break;
14796
		case 'Table':
14797
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14798
			else if(Rn[0].slice(-2) == "/>") break;
14799
			else {
14800
				table = xlml_parsexmltag(Rn[0]);
14801
				state.push([Rn[3], false]);
14802
				cstys = []; seencol = false;
14803
			}
14804
			break;
14805
14806
		case 'Style':
14807
			if(Rn[1]==='/') process_style_xlml(styles, stag, opts);
14808
			else stag = xlml_parsexmltag(Rn[0]);
14809
			break;
14810
14811
		case 'NumberFormat':
14812
			stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
14813
			if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
14814
			for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
14815
			if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
14816
			break;
14817
14818
		case 'Column':
14819
			if(state[state.length-1][0] !== 'Table') break;
14820
			csty = xlml_parsexmltag(Rn[0]);
14821
			if(csty.Hidden) { csty.hidden = true; delete csty.Hidden; }
14822
			if(csty.Width) csty.wpx = parseInt(csty.Width, 10);
14823
			if(!seencol && csty.wpx > 10) {
14824
				seencol = true; MDW = DEF_MDW; //find_mdw_wpx(csty.wpx);
14825
				for(var _col = 0; _col < cstys.length; ++_col) if(cstys[_col]) process_col(cstys[_col]);
14826
			}
14827
			if(seencol) process_col(csty);
14828
			cstys[(csty.Index-1||cstys.length)] = csty;
14829
			for(var i = 0; i < +csty.Span; ++i) cstys[cstys.length] = dup(csty);
14830
			break;
14831
14832
		case 'NamedRange':
14833
			if(!Workbook.Names) Workbook.Names = [];
14834
			var _NamedRange = parsexmltag(Rn[0]);
14835
			var _DefinedName/*:DefinedName*/ = ({
14836
				Name: _NamedRange.Name,
14837
				Ref: rc_to_a1(_NamedRange.RefersTo.slice(1), {r:0, c:0})
14838
			}/*:any*/);
14839
			if(Workbook.Sheets.length>0) _DefinedName.Sheet=Workbook.Sheets.length-1;
14840
			/*:: if(Workbook.Names) */Workbook.Names.push(_DefinedName);
14841
			break;
14842
14843
		case 'NamedCell': break;
14844
		case 'B': break;
14845
		case 'I': break;
14846
		case 'U': break;
14847
		case 'S': break;
14848
		case 'Sub': break;
14849
		case 'Sup': break;
14850
		case 'Span': break;
14851
		case 'Border': break;
14852
		case 'Alignment': break;
14853
		case 'Borders': break;
14854
		case 'Font':
14855
			if(Rn[0].slice(-2) === "/>") break;
14856
			else if(Rn[1]==="/") ss += str.slice(fidx, Rn.index);
14857
			else fidx = Rn.index + Rn[0].length;
14858
			break;
14859
		case 'Interior':
14860
			if(!opts.cellStyles) break;
14861
			stag.Interior = xlml_parsexmltag(Rn[0]);
14862
			break;
14863
		case 'Protection': break;
14864
14865
		case 'Author':
14866
		case 'Title':
14867
		case 'Description':
14868
		case 'Created':
14869
		case 'Keywords':
14870
		case 'Subject':
14871
		case 'Category':
14872
		case 'Company':
14873
		case 'LastAuthor':
14874
		case 'LastSaved':
14875
		case 'LastPrinted':
14876
		case 'Version':
14877
		case 'Revision':
14878
		case 'TotalTime':
14879
		case 'HyperlinkBase':
14880
		case 'Manager':
14881
		case 'ContentStatus':
14882
		case 'Identifier':
14883
		case 'Language':
14884
		case 'AppName':
14885
			if(Rn[0].slice(-2) === "/>") break;
14886
			else if(Rn[1]==="/") xlml_set_prop(Props, Rn[3], str.slice(pidx, Rn.index));
14887
			else pidx = Rn.index + Rn[0].length;
14888
			break;
14889
		case 'Paragraphs': break;
14890
14891
		case 'Styles':
14892
		case 'Workbook':
14893
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14894
			else state.push([Rn[3], false]);
14895
			break;
14896
14897
		case 'Comment':
14898
			if(Rn[1]==='/'){
14899
				if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
14900
				xlml_clean_comment(comment);
14901
				comments.push(comment);
14902
			} else {
14903
				state.push([Rn[3], false]);
14904
				tmp = xlml_parsexmltag(Rn[0]);
14905
				comment = ({a:tmp.Author}/*:any*/);
14906
			}
14907
			break;
14908
14909
		case 'AutoFilter':
14910
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14911
			else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
14912
				var AutoFilter = xlml_parsexmltag(Rn[0]);
14913
				cursheet['!autofilter'] = { ref:rc_to_a1(AutoFilter.Range).replace(/\$/g,"") };
14914
				state.push([Rn[3], true]);
14915
			}
14916
			break;
14917
14918
		case 'Name': break;
14919
14920
		case 'ComponentOptions':
14921
		case 'DocumentProperties':
14922
		case 'CustomDocumentProperties':
14923
		case 'OfficeDocumentSettings':
14924
		case 'PivotTable':
14925
		case 'PivotCache':
14926
		case 'Names':
14927
		case 'MapInfo':
14928
		case 'PageBreaks':
14929
		case 'QueryTable':
14930
		case 'DataValidation':
14931
		case 'Sorting':
14932
		case 'Schema':
14933
		case 'data':
14934
		case 'ConditionalFormatting':
14935
		case 'SmartTagType':
14936
		case 'SmartTags':
14937
		case 'ExcelWorkbook':
14938
		case 'WorkbookOptions':
14939
		case 'WorksheetOptions':
14940
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14941
			else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
14942
			break;
14943
14944
		default:
14945
			/* FODS file root is <office:document> */
14946
			if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts);
14947
			/* UOS file root is <uof:UOF> */
14948
			if(state.length == 0 && Rn[3] == "UOF") return parse_fods(str, opts);
14949
14950
			var seen = true;
14951
			switch(state[state.length-1][0]) {
14952
				/* OfficeDocumentSettings */
14953
				case 'OfficeDocumentSettings': switch(Rn[3]) {
14954
					case 'AllowPNG': break;
14955
					case 'RemovePersonalInformation': break;
14956
					case 'DownloadComponents': break;
14957
					case 'LocationOfComponents': break;
14958
					case 'Colors': break;
14959
					case 'Color': break;
14960
					case 'Index': break;
14961
					case 'RGB': break;
14962
					case 'PixelsPerInch': break; // TODO: set PPI
14963
					case 'TargetScreenSize': break;
14964
					case 'ReadOnlyRecommended': break;
14965
					default: seen = false;
14966
				} break;
14967
14968
				/* ComponentOptions */
14969
				case 'ComponentOptions': switch(Rn[3]) {
14970
					case 'Toolbar': break;
14971
					case 'HideOfficeLogo': break;
14972
					case 'SpreadsheetAutoFit': break;
14973
					case 'Label': break;
14974
					case 'Caption': break;
14975
					case 'MaxHeight': break;
14976
					case 'MaxWidth': break;
14977
					case 'NextSheetNumber': break;
14978
					default: seen = false;
14979
				} break;
14980
14981
				/* ExcelWorkbook */
14982
				case 'ExcelWorkbook': switch(Rn[3]) {
14983
					case 'Date1904':
14984
						/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */
14985
						Workbook.WBProps.date1904 = true;
14986
						break;
14987
					case 'WindowHeight': break;
14988
					case 'WindowWidth': break;
14989
					case 'WindowTopX': break;
14990
					case 'WindowTopY': break;
14991
					case 'TabRatio': break;
14992
					case 'ProtectStructure': break;
14993
					case 'ProtectWindows': break;
14994
					case 'ActiveSheet': break;
14995
					case 'DisplayInkNotes': break;
14996
					case 'FirstVisibleSheet': break;
14997
					case 'SupBook': break;
14998
					case 'SheetName': break;
14999
					case 'SheetIndex': break;
15000
					case 'SheetIndexFirst': break;
15001
					case 'SheetIndexLast': break;
15002
					case 'Dll': break;
15003
					case 'AcceptLabelsInFormulas': break;
15004
					case 'DoNotSaveLinkValues': break;
15005
					case 'Iteration': break;
15006
					case 'MaxIterations': break;
15007
					case 'MaxChange': break;
15008
					case 'Path': break;
15009
					case 'Xct': break;
15010
					case 'Count': break;
15011
					case 'SelectedSheets': break;
15012
					case 'Calculation': break;
15013
					case 'Uncalced': break;
15014
					case 'StartupPrompt': break;
15015
					case 'Crn': break;
15016
					case 'ExternName': break;
15017
					case 'Formula': break;
15018
					case 'ColFirst': break;
15019
					case 'ColLast': break;
15020
					case 'WantAdvise': break;
15021
					case 'Boolean': break;
15022
					case 'Error': break;
15023
					case 'Text': break;
15024
					case 'OLE': break;
15025
					case 'NoAutoRecover': break;
15026
					case 'PublishObjects': break;
15027
					case 'DoNotCalculateBeforeSave': break;
15028
					case 'Number': break;
15029
					case 'RefModeR1C1': break;
15030
					case 'EmbedSaveSmartTags': break;
15031
					default: seen = false;
15032
				} break;
15033
15034
				/* WorkbookOptions */
15035
				case 'WorkbookOptions': switch(Rn[3]) {
15036
					case 'OWCVersion': break;
15037
					case 'Height': break;
15038
					case 'Width': break;
15039
					default: seen = false;
15040
				} break;
15041
15042
				/* WorksheetOptions */
15043
				case 'WorksheetOptions': switch(Rn[3]) {
15044
					case 'Visible':
15045
						if(Rn[0].slice(-2) === "/>"){/* empty */}
15046
						else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
15047
							case "SheetHidden": wsprops.Hidden = 1; break;
15048
							case "SheetVeryHidden": wsprops.Hidden = 2; break;
15049
						}
15050
						else pidx = Rn.index + Rn[0].length;
15051
						break;
15052
					case 'Header':
15053
						if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
15054
						cursheet['!margins'].header = parsexmltag(Rn[0]).Margin;
15055
						break;
15056
					case 'Footer':
15057
						if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
15058
						cursheet['!margins'].footer = parsexmltag(Rn[0]).Margin;
15059
						break;
15060
					case 'PageMargins':
15061
						var pagemargins = parsexmltag(Rn[0]);
15062
						if(!cursheet['!margins']) default_margins(cursheet['!margins']={},'xlml');
15063
						if(pagemargins.Top) cursheet['!margins'].top = pagemargins.Top;
15064
						if(pagemargins.Left) cursheet['!margins'].left = pagemargins.Left;
15065
						if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right;
15066
						if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom;
15067
						break;
15068
					case 'DisplayRightToLeft':
15069
						if(!Workbook.Views) Workbook.Views = [];
15070
						if(!Workbook.Views[0]) Workbook.Views[0] = {};
15071
						Workbook.Views[0].RTL = true;
15072
						break;
15073
15074
					case 'Unsynced': break;
15075
					case 'Print': break;
15076
					case 'Panes': break;
15077
					case 'Scale': break;
15078
					case 'Pane': break;
15079
					case 'Number': break;
15080
					case 'Layout': break;
15081
					case 'PageSetup': break;
15082
					case 'Selected': break;
15083
					case 'ProtectObjects': break;
15084
					case 'EnableSelection': break;
15085
					case 'ProtectScenarios': break;
15086
					case 'ValidPrinterInfo': break;
15087
					case 'HorizontalResolution': break;
15088
					case 'VerticalResolution': break;
15089
					case 'NumberofCopies': break;
15090
					case 'ActiveRow': break;
15091
					case 'ActiveCol': break;
15092
					case 'ActivePane': break;
15093
					case 'TopRowVisible': break;
15094
					case 'TopRowBottomPane': break;
15095
					case 'LeftColumnVisible': break;
15096
					case 'LeftColumnRightPane': break;
15097
					case 'FitToPage': break;
15098
					case 'RangeSelection': break;
15099
					case 'PaperSizeIndex': break;
15100
					case 'PageLayoutZoom': break;
15101
					case 'PageBreakZoom': break;
15102
					case 'FilterOn': break;
15103
					case 'DoNotDisplayGridlines': break;
15104
					case 'SplitHorizontal': break;
15105
					case 'SplitVertical': break;
15106
					case 'FreezePanes': break;
15107
					case 'FrozenNoSplit': break;
15108
					case 'FitWidth': break;
15109
					case 'FitHeight': break;
15110
					case 'CommentsLayout': break;
15111
					case 'Zoom': break;
15112
					case 'LeftToRight': break;
15113
					case 'Gridlines': break;
15114
					case 'AllowSort': break;
15115
					case 'AllowFilter': break;
15116
					case 'AllowInsertRows': break;
15117
					case 'AllowDeleteRows': break;
15118
					case 'AllowInsertCols': break;
15119
					case 'AllowDeleteCols': break;
15120
					case 'AllowInsertHyperlinks': break;
15121
					case 'AllowFormatCells': break;
15122
					case 'AllowSizeCols': break;
15123
					case 'AllowSizeRows': break;
15124
					case 'NoSummaryRowsBelowDetail': break;
15125
					case 'TabColorIndex': break;
15126
					case 'DoNotDisplayHeadings': break;
15127
					case 'ShowPageLayoutZoom': break;
15128
					case 'NoSummaryColumnsRightDetail': break;
15129
					case 'BlackAndWhite': break;
15130
					case 'DoNotDisplayZeros': break;
15131
					case 'DisplayPageBreak': break;
15132
					case 'RowColHeadings': break;
15133
					case 'DoNotDisplayOutline': break;
15134
					case 'NoOrientation': break;
15135
					case 'AllowUsePivotTables': break;
15136
					case 'ZeroHeight': break;
15137
					case 'ViewableRange': break;
15138
					case 'Selection': break;
15139
					case 'ProtectContents': break;
15140
					default: seen = false;
15141
				} break;
15142
15143
				/* PivotTable */
15144
				case 'PivotTable': case 'PivotCache': switch(Rn[3]) {
15145
					case 'ImmediateItemsOnDrop': break;
15146
					case 'ShowPageMultipleItemLabel': break;
15147
					case 'CompactRowIndent': break;
15148
					case 'Location': break;
15149
					case 'PivotField': break;
15150
					case 'Orientation': break;
15151
					case 'LayoutForm': break;
15152
					case 'LayoutSubtotalLocation': break;
15153
					case 'LayoutCompactRow': break;
15154
					case 'Position': break;
15155
					case 'PivotItem': break;
15156
					case 'DataType': break;
15157
					case 'DataField': break;
15158
					case 'SourceName': break;
15159
					case 'ParentField': break;
15160
					case 'PTLineItems': break;
15161
					case 'PTLineItem': break;
15162
					case 'CountOfSameItems': break;
15163
					case 'Item': break;
15164
					case 'ItemType': break;
15165
					case 'PTSource': break;
15166
					case 'CacheIndex': break;
15167
					case 'ConsolidationReference': break;
15168
					case 'FileName': break;
15169
					case 'Reference': break;
15170
					case 'NoColumnGrand': break;
15171
					case 'NoRowGrand': break;
15172
					case 'BlankLineAfterItems': break;
15173
					case 'Hidden': break;
15174
					case 'Subtotal': break;
15175
					case 'BaseField': break;
15176
					case 'MapChildItems': break;
15177
					case 'Function': break;
15178
					case 'RefreshOnFileOpen': break;
15179
					case 'PrintSetTitles': break;
15180
					case 'MergeLabels': break;
15181
					case 'DefaultVersion': break;
15182
					case 'RefreshName': break;
15183
					case 'RefreshDate': break;
15184
					case 'RefreshDateCopy': break;
15185
					case 'VersionLastRefresh': break;
15186
					case 'VersionLastUpdate': break;
15187
					case 'VersionUpdateableMin': break;
15188
					case 'VersionRefreshableMin': break;
15189
					case 'Calculation': break;
15190
					default: seen = false;
15191
				} break;
15192
15193
				/* PageBreaks */
15194
				case 'PageBreaks': switch(Rn[3]) {
15195
					case 'ColBreaks': break;
15196
					case 'ColBreak': break;
15197
					case 'RowBreaks': break;
15198
					case 'RowBreak': break;
15199
					case 'ColStart': break;
15200
					case 'ColEnd': break;
15201
					case 'RowEnd': break;
15202
					default: seen = false;
15203
				} break;
15204
15205
				/* AutoFilter */
15206
				case 'AutoFilter': switch(Rn[3]) {
15207
					case 'AutoFilterColumn': break;
15208
					case 'AutoFilterCondition': break;
15209
					case 'AutoFilterAnd': break;
15210
					case 'AutoFilterOr': break;
15211
					default: seen = false;
15212
				} break;
15213
15214
				/* QueryTable */
15215
				case 'QueryTable': switch(Rn[3]) {
15216
					case 'Id': break;
15217
					case 'AutoFormatFont': break;
15218
					case 'AutoFormatPattern': break;
15219
					case 'QuerySource': break;
15220
					case 'QueryType': break;
15221
					case 'EnableRedirections': break;
15222
					case 'RefreshedInXl9': break;
15223
					case 'URLString': break;
15224
					case 'HTMLTables': break;
15225
					case 'Connection': break;
15226
					case 'CommandText': break;
15227
					case 'RefreshInfo': break;
15228
					case 'NoTitles': break;
15229
					case 'NextId': break;
15230
					case 'ColumnInfo': break;
15231
					case 'OverwriteCells': break;
15232
					case 'DoNotPromptForFile': break;
15233
					case 'TextWizardSettings': break;
15234
					case 'Source': break;
15235
					case 'Number': break;
15236
					case 'Decimal': break;
15237
					case 'ThousandSeparator': break;
15238
					case 'TrailingMinusNumbers': break;
15239
					case 'FormatSettings': break;
15240
					case 'FieldType': break;
15241
					case 'Delimiters': break;
15242
					case 'Tab': break;
15243
					case 'Comma': break;
15244
					case 'AutoFormatName': break;
15245
					case 'VersionLastEdit': break;
15246
					case 'VersionLastRefresh': break;
15247
					default: seen = false;
15248
				} break;
15249
15250
				case 'Sorting':
15251
				case 'ConditionalFormatting':
15252
				case 'DataValidation':
15253
				switch(Rn[3]) {
15254
					case 'Range': break;
15255
					case 'Type': break;
15256
					case 'Min': break;
15257
					case 'Max': break;
15258
					case 'Sort': break;
15259
					case 'Descending': break;
15260
					case 'Order': break;
15261
					case 'CaseSensitive': break;
15262
					case 'Value': break;
15263
					case 'ErrorStyle': break;
15264
					case 'ErrorMessage': break;
15265
					case 'ErrorTitle': break;
15266
					case 'CellRangeList': break;
15267
					case 'InputMessage': break;
15268
					case 'InputTitle': break;
15269
					case 'ComboHide': break;
15270
					case 'InputHide': break;
15271
					case 'Condition': break;
15272
					case 'Qualifier': break;
15273
					case 'UseBlank': break;
15274
					case 'Value1': break;
15275
					case 'Value2': break;
15276
					case 'Format': break;
15277
					default: seen = false;
15278
				} break;
15279
15280
				/* MapInfo (schema) */
15281
				case 'MapInfo': case 'Schema': case 'data': switch(Rn[3]) {
15282
					case 'Map': break;
15283
					case 'Entry': break;
15284
					case 'Range': break;
15285
					case 'XPath': break;
15286
					case 'Field': break;
15287
					case 'XSDType': break;
15288
					case 'FilterOn': break;
15289
					case 'Aggregate': break;
15290
					case 'ElementType': break;
15291
					case 'AttributeType': break;
15292
				/* These are from xsd (XML Schema Definition) */
15293
					case 'schema':
15294
					case 'element':
15295
					case 'complexType':
15296
					case 'datatype':
15297
					case 'all':
15298
					case 'attribute':
15299
					case 'extends': break;
15300
15301
					case 'row': break;
15302
					default: seen = false;
15303
				} break;
15304
15305
				/* SmartTags (can be anything) */
15306
				case 'SmartTags': break;
15307
15308
				default: seen = false; break;
15309
			}
15310
			if(seen) break;
15311
			/* CustomDocumentProperties */
15312
			if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
15313
			if(state[state.length-1][0]==='CustomDocumentProperties') {
15314
				if(Rn[0].slice(-2) === "/>") break;
15315
				else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn[3], cp, str.slice(pidx, Rn.index));
15316
				else { cp = Rn; pidx = Rn.index + Rn[0].length; }
15317
				break;
15318
			}
15319
			if(opts.WTF) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
15320
	}
15321
	var out = ({}/*:any*/);
15322
	if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
15323
	out.SheetNames = sheetnames;
15324
	out.Workbook = Workbook;
15325
	out.SSF = SSF.get_table();
15326
	out.Props = Props;
15327
	out.Custprops = Custprops;
15328
	return out;
15329
}
15330
15331
function parse_xlml(data/*:RawBytes|string*/, opts)/*:Workbook*/ {
15332
	fix_read_opts(opts=opts||{});
15333
	switch(opts.type||"base64") {
15334
		case "base64": return parse_xlml_xml(Base64.decode(data), opts);
15335
		case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
15336
		case "array": return parse_xlml_xml(a2s(data), opts);
15337
	}
15338
	/*:: throw new Error("unsupported type " + opts.type); */
15339
}
15340
15341
/* TODO */
15342
function write_props_xlml(wb/*:Workbook*/, opts)/*:string*/ {
15343
	var o/*:Array<string>*/ = [];
15344
	/* DocumentProperties */
15345
	if(wb.Props) o.push(xlml_write_docprops(wb.Props, opts));
15346
	/* CustomDocumentProperties */
15347
	if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops, opts));
15348
	return o.join("");
15349
}
15350
/* TODO */
15351
function write_wb_xlml(/*::wb, opts*/)/*:string*/ {
15352
	/* OfficeDocumentSettings */
15353
	/* ExcelWorkbook */
15354
	return "";
15355
}
15356
/* TODO */
15357
function write_sty_xlml(wb, opts)/*:string*/ {
15358
	/* Styles */
15359
	var styles/*:Array<string>*/ = ['<Style ss:ID="Default" ss:Name="Normal"><NumberFormat/></Style>'];
15360
	opts.cellXfs.forEach(function(xf, id) {
15361
		var payload/*:Array<string>*/ = [];
15362
		payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])}));
15363
		styles.push(writextag('Style', payload.join(""), {"ss:ID": "s" + (21+id)}));
15364
	});
15365
	return writextag("Styles", styles.join(""));
15366
}
15367
function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); }
15368
function write_names_xlml(wb/*::, opts*/)/*:string*/ {
15369
	if(!((wb||{}).Workbook||{}).Names) return "";
15370
	/*:: if(!wb || !wb.Workbook || !wb.Workbook.Names) throw new Error("unreachable"); */
15371
	var names/*:Array<any>*/ = wb.Workbook.Names;
15372
	var out/*:Array<string>*/ = [];
15373
	for(var i = 0; i < names.length; ++i) {
15374
		var n = names[i];
15375
		if(n.Sheet != null) continue;
15376
		if(n.Name.match(/^_xlfn\./)) continue;
15377
		out.push(write_name_xlml(n));
15378
	}
15379
	return writextag("Names", out.join(""));
15380
}
15381
function write_ws_xlml_names(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
15382
	if(!ws) return "";
15383
	if(!((wb||{}).Workbook||{}).Names) return "";
15384
	/*:: if(!wb || !wb.Workbook || !wb.Workbook.Names) throw new Error("unreachable"); */
15385
	var names/*:Array<any>*/ = wb.Workbook.Names;
15386
	var out/*:Array<string>*/ = [];
15387
	for(var i = 0; i < names.length; ++i) {
15388
		var n = names[i];
15389
		if(n.Sheet != idx) continue;
15390
		/*switch(n.Name) {
15391
			case "_": continue;
15392
		}*/
15393
		if(n.Name.match(/^_xlfn\./)) continue;
15394
		out.push(write_name_xlml(n));
15395
	}
15396
	return out.join("");
15397
}
15398
/* WorksheetOptions */
15399
function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
15400
	if(!ws) return "";
15401
	var o/*:Array<string>*/ = [];
15402
	/* NOTE: spec technically allows any order, but stick with implied order */
15403
15404
	/* FitToPage */
15405
	/* DoNotDisplayColHeaders */
15406
	/* DoNotDisplayRowHeaders */
15407
	/* ViewableRange */
15408
	/* Selection */
15409
	/* GridlineColor */
15410
	/* Name */
15411
	/* ExcelWorksheetType */
15412
	/* IntlMacro */
15413
	/* Unsynced */
15414
	/* Selected */
15415
	/* CodeName */
15416
15417
	if(ws['!margins']) {
15418
		o.push("<PageSetup>");
15419
		if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
15420
		if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
15421
		o.push(writextag("PageMargins", null, {
15422
			'x:Bottom': ws['!margins'].bottom || "0.75",
15423
			'x:Left': ws['!margins'].left || "0.7",
15424
			'x:Right': ws['!margins'].right || "0.7",
15425
			'x:Top': ws['!margins'].top || "0.75"
15426
		}));
15427
		o.push("</PageSetup>");
15428
	}
15429
15430
	/* PageSetup */
15431
	/* DisplayPageBreak */
15432
	/* TransitionExpressionEvaluation */
15433
	/* TransitionFormulaEntry */
15434
	/* Print */
15435
	/* Zoom */
15436
	/* PageLayoutZoom */
15437
	/* PageBreakZoom */
15438
	/* ShowPageBreakZoom */
15439
	/* DefaultRowHeight */
15440
	/* DefaultColumnWidth */
15441
	/* StandardWidth */
15442
15443
	if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
15444
		/* Visible */
15445
		if(wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
15446
		else {
15447
			/* Selected */
15448
			for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
15449
			if(i == idx) o.push("<Selected/>");
15450
		}
15451
	}
15452
15453
	/* LeftColumnVisible */
15454
15455
	if(((((wb||{}).Workbook||{}).Views||[])[0]||{}).RTL) o.push("<DisplayRightToLeft/>");
15456
15457
	/* GridlineColorIndex */
15458
	/* DisplayFormulas */
15459
	/* DoNotDisplayGridlines */
15460
	/* DoNotDisplayHeadings */
15461
	/* DoNotDisplayOutline */
15462
	/* ApplyAutomaticOutlineStyles */
15463
	/* NoSummaryRowsBelowDetail */
15464
	/* NoSummaryColumnsRightDetail */
15465
	/* DoNotDisplayZeros */
15466
	/* ActiveRow */
15467
	/* ActiveColumn */
15468
	/* FilterOn */
15469
	/* RangeSelection */
15470
	/* TopRowVisible */
15471
	/* TopRowBottomPane */
15472
	/* LeftColumnRightPane */
15473
	/* ActivePane */
15474
	/* SplitHorizontal */
15475
	/* SplitVertical */
15476
	/* FreezePanes */
15477
	/* FrozenNoSplit */
15478
	/* TabColorIndex */
15479
	/* Panes */
15480
15481
	/* NOTE: Password not supported in XLML Format */
15482
	if(ws['!protect']) {
15483
		o.push(writetag("ProtectContents", "True"));
15484
		if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
15485
		if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
15486
		if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
15487
		else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
15488
	[
15489
		[ "formatCells", "AllowFormatCells" ],
15490
		[ "formatColumns", "AllowSizeCols" ],
15491
		[ "formatRows", "AllowSizeRows" ],
15492
		[ "insertColumns", "AllowInsertCols" ],
15493
		[ "insertRows", "AllowInsertRows" ],
15494
		[ "insertHyperlinks", "AllowInsertHyperlinks" ],
15495
		[ "deleteColumns", "AllowDeleteCols" ],
15496
		[ "deleteRows", "AllowDeleteRows" ],
15497
		[ "sort", "AllowSort" ],
15498
		[ "autoFilter", "AllowFilter" ],
15499
		[ "pivotTables", "AllowUsePivotTables" ]
15500
	].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
15501
	}
15502
15503
	if(o.length == 0) return "";
15504
	return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
15505
}
15506
function write_ws_xlml_comment(comments/*:Array<any>*/)/*:string*/ {
15507
	return comments.map(function(c) {
15508
		// TODO: formatted text
15509
		var t = xlml_unfixstr(c.t||"");
15510
		var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
15511
		return writextag("Comment", d, {"ss:Author":c.a});
15512
	}).join("");
15513
}
15514
function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, addr)/*:string*/{
15515
	if(!cell || (cell.v == undefined && cell.f == undefined)) return "";
15516
15517
	var attr = {};
15518
	if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
15519
	if(cell.F && cell.F.slice(0, ref.length) == ref) {
15520
		var end = decode_cell(cell.F.slice(ref.length + 1));
15521
		attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
15522
	}
15523
15524
	if(cell.l && cell.l.Target) {
15525
		attr["ss:HRef"] = escapexml(cell.l.Target);
15526
		if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
15527
	}
15528
15529
	if(ws['!merges']) {
15530
		var marr = ws['!merges'];
15531
		for(var mi = 0; mi != marr.length; ++mi) {
15532
			if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
15533
			if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
15534
			if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
15535
		}
15536
	}
15537
15538
	var t = "", p = "";
15539
	switch(cell.t) {
15540
		case 'z': return "";
15541
		case 'n': t = 'Number'; p = String(cell.v); break;
15542
		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
15543
		case 'e': t = 'Error'; p = BErr[cell.v]; break;
15544
		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break;
15545
		case 's': t = 'String'; p = escapexlml(cell.v||""); break;
15546
	}
15547
	/* TODO: cell style */
15548
	var os = get_cell_style(opts.cellXfs, cell, opts);
15549
	attr["ss:StyleID"] = "s" + (21+os);
15550
	attr["ss:Index"] = addr.c + 1;
15551
	var _v = (cell.v != null ? p : "");
15552
	var m = '<Data ss:Type="' + t + '">' + _v + '</Data>';
15553
15554
	if((cell.c||[]).length > 0) m += write_ws_xlml_comment(cell.c);
15555
15556
	return writextag("Cell", m, attr);
15557
}
15558
function write_ws_xlml_row(R/*:number*/, row)/*:string*/ {
15559
	var o = '<Row ss:Index="' + (R+1) + '"';
15560
	if(row) {
15561
		if(row.hpt && !row.hpx) row.hpx = pt2px(row.hpt);
15562
		if(row.hpx) o += ' ss:AutoFitHeight="0" ss:Height="' + row.hpx + '"';
15563
		if(row.hidden) o += ' ss:Hidden="1"';
15564
	}
15565
	return o + '>';
15566
}
15567
/* TODO */
15568
function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ {
15569
	if(!ws['!ref']) return "";
15570
	var range/*:Range*/ = safe_decode_range(ws['!ref']);
15571
	var marr/*:Array<Range>*/ = ws['!merges'] || [], mi = 0;
15572
	var o/*:Array<string>*/ = [];
15573
	if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
15574
		process_col(n);
15575
		var w = !!n.width;
15576
		var p = col_obj_w(i, n);
15577
		var k/*:any*/ = {"ss:Index":i+1};
15578
		if(w) k['ss:Width'] = width2px(p.width);
15579
		if(n.hidden) k['ss:Hidden']="1";
15580
		o.push(writextag("Column",null,k));
15581
	});
15582
	var dense = Array.isArray(ws);
15583
	for(var R = range.s.r; R <= range.e.r; ++R) {
15584
		var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
15585
		for(var C = range.s.c; C <= range.e.c; ++C) {
15586
			var skip = false;
15587
			for(mi = 0; mi != marr.length; ++mi) {
15588
				if(marr[mi].s.c > C) continue;
15589
				if(marr[mi].s.r > R) continue;
15590
				if(marr[mi].e.c < C) continue;
15591
				if(marr[mi].e.r < R) continue;
15592
				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
15593
				break;
15594
			}
15595
			if(skip) continue;
15596
			var addr = {r:R,c:C};
15597
			var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
15598
			row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
15599
		}
15600
		row.push("</Row>");
15601
		if(row.length > 2) o.push(row.join(""));
15602
	}
15603
	return o.join("");
15604
}
15605
function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
15606
	var o/*:Array<string>*/ = [];
15607
	var s = wb.SheetNames[idx];
15608
	var ws = wb.Sheets[s];
15609
15610
	var t/*:string*/ = ws ? write_ws_xlml_names(ws, opts, idx, wb) : "";
15611
	if(t.length > 0) o.push("<Names>" + t + "</Names>");
15612
15613
	/* Table */
15614
	t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
15615
	if(t.length > 0) o.push("<Table>" + t + "</Table>");
15616
15617
	/* WorksheetOptions */
15618
	o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
15619
15620
	return o.join("");
15621
}
15622
function write_xlml(wb, opts)/*:string*/ {
15623
	if(!opts) opts = {};
15624
	if(!wb.SSF) wb.SSF = SSF.get_table();
15625
	if(wb.SSF) {
15626
		make_ssf(SSF); SSF.load_table(wb.SSF);
15627
		// $FlowIgnore
15628
		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
15629
		opts.ssf = wb.SSF;
15630
		opts.cellXfs = [];
15631
		get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
15632
	}
15633
	var d/*:Array<string>*/ = [];
15634
	d.push(write_props_xlml(wb, opts));
15635
	d.push(write_wb_xlml(wb, opts));
15636
	d.push("");
15637
	d.push("");
15638
	for(var i = 0; i < wb.SheetNames.length; ++i)
15639
		d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
15640
	d[2] = write_sty_xlml(wb, opts);
15641
	d[3] = write_names_xlml(wb, opts);
15642
	return XML_HEADER + writextag("Workbook", d.join(""), {
15643
		'xmlns':      XLMLNS.ss,
15644
		'xmlns:o':    XLMLNS.o,
15645
		'xmlns:x':    XLMLNS.x,
15646
		'xmlns:ss':   XLMLNS.ss,
15647
		'xmlns:dt':   XLMLNS.dt,
15648
		'xmlns:html': XLMLNS.html
15649
	});
15650
}
15651
/* [MS-OLEDS] 2.3.8 CompObjStream */
15652
function parse_compobj(obj/*:CFBEntry*/) {
15653
	var v = {};
15654
	var o = obj.content;
15655
	/*:: if(o == null) return; */
15656
15657
	/* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
15658
	o.l = 28;
15659
15660
	v.AnsiUserType = o.read_shift(0, "lpstr-ansi");
15661
	v.AnsiClipboardFormat = parse_ClipboardFormatOrAnsiString(o);
15662
15663
	if(o.length - o.l <= 4) return v;
15664
15665
	var m/*:number*/ = o.read_shift(4);
15666
	if(m == 0 || m > 40) return v;
15667
	o.l-=4; v.Reserved1 = o.read_shift(0, "lpstr-ansi");
15668
15669
	if(o.length - o.l <= 4) return v;
15670
	m = o.read_shift(4);
15671
	if(m !== 0x71b239f4) return v;
15672
	v.UnicodeClipboardFormat = parse_ClipboardFormatOrUnicodeString(o);
15673
15674
	m = o.read_shift(4);
15675
	if(m == 0 || m > 40) return v;
15676
	o.l-=4; v.Reserved2 = o.read_shift(0, "lpwstr");
15677
}
15678
15679
/*
15680
	Continue logic for:
15681
	- 2.4.58 Continue
15682
	- 2.4.59 ContinueBigName
15683
	- 2.4.60 ContinueFrt
15684
	- 2.4.61 ContinueFrt11
15685
	- 2.4.62 ContinueFrt12
15686
*/
15687
function slurp(R, blob, length/*:number*/, opts) {
15688
	var l = length;
15689
	var bufs = [];
15690
	var d = blob.slice(blob.l,blob.l+l);
15691
	if(opts && opts.enc && opts.enc.insitu) switch(R.n) {
15692
	case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': break;
15693
	default:
15694
		if(d.length === 0) break;
15695
		opts.enc.insitu(d);
15696
	}
15697
	bufs.push(d);
15698
	blob.l += l;
15699
	var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]);
15700
	var start = 0;
15701
	while(next != null && next.n.slice(0,8) === 'Continue') {
15702
		l = __readUInt16LE(blob,blob.l+2);
15703
		start = blob.l + 4;
15704
		if(next.n == 'ContinueFrt') start += 4;
15705
		else if(next.n.slice(0,11) == 'ContinueFrt') start += 12;
15706
		bufs.push(blob.slice(start,blob.l+4+l));
15707
		blob.l += 4+l;
15708
		next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]);
15709
	}
15710
	var b = (bconcat(bufs)/*:any*/);
15711
	prep_blob(b, 0);
15712
	var ll = 0; b.lens = [];
15713
	for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; }
15714
	return R.f(b, b.length, opts);
15715
}
15716
15717
function safe_format_xf(p/*:any*/, opts/*:ParseOpts*/, date1904/*:?boolean*/) {
15718
	if(p.t === 'z') return;
15719
	if(!p.XF) return;
15720
	var fmtid = 0;
15721
	try {
15722
		fmtid = p.z || p.XF.numFmtId || 0;
15723
		if(opts.cellNF) p.z = SSF._table[fmtid];
15724
	} catch(e) { if(opts.WTF) throw e; }
15725
	if(!opts || opts.cellText !== false) try {
15726
		if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
15727
		else if(fmtid === 0 || fmtid == "General") {
15728
			if(p.t === 'n') {
15729
				if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
15730
				else p.w = SSF._general_num(p.v);
15731
			}
15732
			else p.w = SSF._general(p.v);
15733
		}
15734
		else p.w = SSF.format(fmtid,p.v, {date1904:!!date1904});
15735
	} catch(e) { if(opts.WTF) throw e; }
15736
	if(opts.cellDates && fmtid && p.t == 'n' && SSF.is_date(SSF._table[fmtid] || String(fmtid))) {
15737
		var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
15738
	}
15739
}
15740
15741
function make_cell(val, ixfe, t)/*:Cell*/ {
15742
	return ({v:val, ixfe:ixfe, t:t}/*:any*/);
15743
}
15744
15745
// 2.3.2
15746
function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
15747
	var wb = ({opts:{}}/*:any*/);
15748
	var Sheets = {};
15749
	if(DENSE != null && options.dense == null) options.dense = DENSE;
15750
	var out/*:Worksheet*/ = ((options.dense ? [] : {})/*:any*/);
15751
	var Directory = {};
15752
	var range/*:Range*/ = ({}/*:any*/);
15753
	var last_formula = null;
15754
	var sst/*:SST*/ = ([]/*:any*/);
15755
	var cur_sheet = "";
15756
	var Preamble = {};
15757
	var lastcell, last_cell = "", cc, cmnt, rngC, rngR;
15758
	var sharedf = {};
15759
	var arrayf/*:Array<[Range, string]>*/ = [];
15760
	var temp_val/*:Cell*/;
15761
	var country;
15762
	var cell_valid = true;
15763
	var XFs = []; /* XF records */
15764
	var palette = [];
15765
	var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }/*:any*/), wsprops = {};
15766
	var get_rgb = function getrgb(icv) {
15767
		if(icv < 8) return XLSIcv[icv];
15768
		if(icv < 64) return palette[icv-8] || XLSIcv[icv];
15769
		return XLSIcv[icv];
15770
	};
15771
	var process_cell_style = function pcs(cell, line/*:any*/, options) {
15772
		var xfd = line.XF.data;
15773
		if(!xfd || !xfd.patternType || !options || !options.cellStyles) return;
15774
		line.s = ({}/*:any*/);
15775
		line.s.patternType = xfd.patternType;
15776
		var t;
15777
		if((t = rgb2Hex(get_rgb(xfd.icvFore)))) { line.s.fgColor = {rgb:t}; }
15778
		if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
15779
	};
15780
	var addcell = function addcell(cell/*:any*/, line/*:any*/, options/*:any*/) {
15781
		if(file_depth > 1) return;
15782
		if(options.sheetRows && cell.r >= options.sheetRows) cell_valid = false;
15783
		if(!cell_valid) return;
15784
		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options);
15785
		delete line.ixfe; delete line.XF;
15786
		lastcell = cell;
15787
		last_cell = encode_cell(cell);
15788
		if(range.s) {
15789
			if(cell.r < range.s.r) range.s.r = cell.r;
15790
			if(cell.c < range.s.c) range.s.c = cell.c;
15791
		}
15792
		if(range.e) {
15793
			if(cell.r + 1 > range.e.r) range.e.r = cell.r + 1;
15794
			if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1;
15795
		}
15796
		if(options.cellFormula && line.f) {
15797
			for(var afi = 0; afi < arrayf.length; ++afi) {
15798
				if(arrayf[afi][0].s.c > cell.c || arrayf[afi][0].s.r > cell.r) continue;
15799
				if(arrayf[afi][0].e.c < cell.c || arrayf[afi][0].e.r < cell.r) continue;
15800
				line.F = encode_range(arrayf[afi][0]);
15801
				if(arrayf[afi][0].s.c != cell.c || arrayf[afi][0].s.r != cell.r) delete line.f;
15802
				if(line.f) line.f = "" + stringify_formula(arrayf[afi][1], range, cell, supbooks, opts);
15803
				break;
15804
			}
15805
		}
15806
		{
15807
			if(options.dense) {
15808
				if(!out[cell.r]) out[cell.r] = [];
15809
				out[cell.r][cell.c] = line;
15810
			} else out[last_cell] = line;
15811
		}
15812
	};
15813
	var opts = ({
15814
		enc: false, // encrypted
15815
		sbcch: 0, // cch in the preceding SupBook
15816
		snames: [], // sheetnames
15817
		sharedf: sharedf, // shared formulae by address
15818
		arrayf: arrayf, // array formulae array
15819
		rrtabid: [], // RRTabId
15820
		lastuser: "", // Last User from WriteAccess
15821
		biff: 8, // BIFF version
15822
		codepage: 0, // CP from CodePage record
15823
		winlocked: 0, // fLockWn from WinProtect
15824
		cellStyles: !!options && !!options.cellStyles,
15825
		WTF: !!options && !!options.wtf
15826
	}/*:any*/);
15827
	if(options.password) opts.password = options.password;
15828
	var themes;
15829
	var merges/*:Array<Range>*/ = [];
15830
	var objects = [];
15831
	var colinfo/*:Array<ColInfo>*/ = [], rowinfo/*:Array<RowInfo>*/ = [];
15832
	// eslint-disable-next-line no-unused-vars
15833
	var defwidth = 0, defheight = 0; // twips / MDW respectively
15834
	var seencol = false;
15835
	var supbooks = ([]/*:any*/); // 1-indexed, will hold extern names
15836
	supbooks.SheetNames = opts.snames;
15837
	supbooks.sharedf = opts.sharedf;
15838
	supbooks.arrayf = opts.arrayf;
15839
	supbooks.names = [];
15840
	supbooks.XTI = [];
15841
	var last_Rn = '';
15842
	var file_depth = 0; /* TODO: make a real stack */
15843
	var BIFF2Fmt = 0, BIFF2FmtTable/*:Array<string>*/ = [];
15844
	var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
15845
	var last_lbl/*:?DefinedName*/;
15846
15847
	/* explicit override for some broken writers */
15848
	opts.codepage = 1200;
15849
	set_cp(1200);
15850
	var seen_codepage = false;
15851
	while(blob.l < blob.length - 1) {
15852
		var s = blob.l;
15853
		var RecordType = blob.read_shift(2);
15854
		if(RecordType === 0 && last_Rn === 'EOF') break;
15855
		var length = (blob.l === blob.length ? 0 : blob.read_shift(2));
15856
		var R = XLSRecordEnum[RecordType];
15857
		//console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length);
15858
		//if(!R) console.log(blob.slice(blob.l, blob.l + length));
15859
		if(R && R.f) {
15860
			if(options.bookSheets) {
15861
				if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
15862
			}
15863
			last_Rn = R.n;
15864
			if(R.r === 2 || R.r == 12) {
15865
				var rt = blob.read_shift(2); length -= 2;
15866
				if(!opts.enc && rt !== RecordType && (((rt&0xFF)<<8)|(rt>>8)) !== RecordType) throw new Error("rt mismatch: " + rt + "!=" + RecordType);
15867
				if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
15868
			}
15869
			//console.error(R,blob.l,length,blob.length);
15870
			var val;
15871
			if(R.n === 'EOF') val = R.f(blob, length, opts);
15872
			else val = slurp(R, blob, length, opts);
15873
			var Rn = R.n;
15874
			if(file_depth == 0 && Rn != 'BOF') continue;
15875
			/* nested switch statements to workaround V8 128 limit */
15876
			switch(Rn) {
15877
				/* Workbook Options */
15878
				case 'Date1904':
15879
					/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */
15880
					wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break;
15881
				case 'WriteProtect': wb.opts.WriteProtect = true; break;
15882
				case 'FilePass':
15883
					if(!opts.enc) blob.l = 0;
15884
					opts.enc = val;
15885
					if(!options.password) throw new Error("File is password-protected");
15886
					if(val.valid == null) throw new Error("Encryption scheme unsupported");
15887
					if(!val.valid) throw new Error("Password is incorrect");
15888
					break;
15889
				case 'WriteAccess': opts.lastuser = val; break;
15890
				case 'FileSharing': break; //TODO
15891
				case 'CodePage':
15892
					/* overrides based on test cases */
15893
					switch(val) {
15894
						case 0x5212: val =  1200; break;
15895
						case 0x8000: val = 10000; break;
15896
						case 0x8001: val =  1252; break;
15897
					}
15898
					set_cp(opts.codepage = val);
15899
					seen_codepage = true;
15900
					break;
15901
				case 'RRTabId': opts.rrtabid = val; break;
15902
				case 'WinProtect': opts.winlocked = val; break;
15903
				case 'Template': break; // TODO
15904
				case 'BookBool': break; // TODO
15905
				case 'UsesELFs': break;
15906
				case 'MTRSettings': break;
15907
				case 'RefreshAll':
15908
				case 'CalcCount':
15909
				case 'CalcDelta':
15910
				case 'CalcIter':
15911
				case 'CalcMode':
15912
				case 'CalcPrecision':
15913
				case 'CalcSaveRecalc':
15914
					wb.opts[Rn] = val; break;
15915
				case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
15916
				case 'Uncalced': break;
15917
				case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
15918
				case 'WsBool':
15919
					if(val.fDialog) out["!type"] = "dialog";
15920
					break; // TODO
15921
				case 'XF': XFs.push(val); break;
15922
				case 'ExtSST': break; // TODO
15923
				case 'BookExt': break; // TODO
15924
				case 'RichTextStream': break;
15925
				case 'BkHim': break;
15926
15927
				case 'SupBook':
15928
					supbooks.push([val]);
15929
					supbooks[supbooks.length-1].XTI = [];
15930
					break;
15931
				case 'ExternName':
15932
					supbooks[supbooks.length-1].push(val);
15933
					break;
15934
				case 'Index': break; // TODO
15935
				case 'Lbl':
15936
					last_lbl = ({
15937
						Name: val.Name,
15938
						Ref: stringify_formula(val.rgce,range,null,supbooks,opts)
15939
					}/*:DefinedName*/);
15940
					if(val.itab > 0) last_lbl.Sheet = val.itab - 1;
15941
					supbooks.names.push(last_lbl);
15942
					if(!supbooks[0]) { supbooks[0] = []; supbooks[0].XTI = []; }
15943
					supbooks[supbooks.length-1].push(val);
15944
					if(val.Name == "_xlnm._FilterDatabase" && val.itab > 0)
15945
						if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d')
15946
							FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) };
15947
					break;
15948
				case 'ExternCount': opts.ExternCount = val; break;
15949
				case 'ExternSheet':
15950
					if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; }
15951
					supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break;
15952
				case 'NameCmt':
15953
					/* TODO: search for correct name */
15954
					if(opts.biff < 8) break;
15955
					if(last_lbl != null) last_lbl.Comment = val[1];
15956
					break;
15957
15958
				case 'Protect': out["!protect"] = val; break; /* for sheet or book */
15959
				case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
15960
				case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/
15961
15962
				case 'BoundSheet8': {
15963
					Directory[val.pos] = val;
15964
					opts.snames.push(val.name);
15965
				} break;
15966
				case 'EOF': {
15967
					if(--file_depth) break;
15968
					if(range.e) {
15969
						if(range.e.r > 0 && range.e.c > 0) {
15970
							range.e.r--; range.e.c--;
15971
							out["!ref"] = encode_range(range);
15972
							if(options.sheetRows && options.sheetRows <= range.e.r) {
15973
								var tmpri = range.e.r;
15974
								range.e.r = options.sheetRows - 1;
15975
								out["!fullref"] = out["!ref"];
15976
								out["!ref"] = encode_range(range);
15977
								range.e.r = tmpri;
15978
							}
15979
							range.e.r++; range.e.c++;
15980
						}
15981
						if(merges.length > 0) out["!merges"] = merges;
15982
						if(objects.length > 0) out["!objects"] = objects;
15983
						if(colinfo.length > 0) out["!cols"] = colinfo;
15984
						if(rowinfo.length > 0) out["!rows"] = rowinfo;
15985
						Workbook.Sheets.push(wsprops);
15986
					}
15987
					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
15988
					out = ((options.dense ? [] : {})/*:any*/);
15989
				} break;
15990
				case 'BOF': {
15991
					if(opts.biff === 8) opts.biff = {
15992
						/*::[*/0x0009/*::]*/:2,
15993
						/*::[*/0x0209/*::]*/:3,
15994
						/*::[*/0x0409/*::]*/:4
15995
					}[RecordType] || {
15996
						/*::[*/0x0200/*::]*/:2,
15997
						/*::[*/0x0300/*::]*/:3,
15998
						/*::[*/0x0400/*::]*/:4,
15999
						/*::[*/0x0500/*::]*/:5,
16000
						/*::[*/0x0600/*::]*/:8,
16001
						/*::[*/0x0002/*::]*/:2,
16002
						/*::[*/0x0007/*::]*/:2
16003
					}[val.BIFFVer] || 8;
16004
					if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
16005
					if(file_depth++) break;
16006
					cell_valid = true;
16007
					out = ((options.dense ? [] : {})/*:any*/);
16008
16009
					if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
16010
					if(opts.biff < 5) {
16011
						if(cur_sheet === "") cur_sheet = "Sheet1";
16012
						range = {s:{r:0,c:0},e:{r:0,c:0}};
16013
						/* fake BoundSheet8 */
16014
						var fakebs8 = {pos: blob.l - length, name:cur_sheet};
16015
						Directory[fakebs8.pos] = fakebs8;
16016
						opts.snames.push(cur_sheet);
16017
					}
16018
					else cur_sheet = (Directory[s] || {name:""}).name;
16019
					if(val.dt == 0x20) out["!type"] = "chart";
16020
					if(val.dt == 0x40) out["!type"] = "macro";
16021
					merges = [];
16022
					objects = [];
16023
					opts.arrayf = arrayf = [];
16024
					colinfo = []; rowinfo = [];
16025
					defwidth = defheight = 0;
16026
					seencol = false;
16027
					wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
16028
				} break;
16029
16030
				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
16031
					if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
16032
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'}/*:any*/);
16033
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16034
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16035
					addcell({c:val.c, r:val.r}, temp_val, options);
16036
				} break;
16037
				case 'BoolErr': {
16038
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t}/*:any*/);
16039
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16040
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16041
					addcell({c:val.c, r:val.r}, temp_val, options);
16042
				} break;
16043
				case 'RK': {
16044
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'}/*:any*/);
16045
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16046
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16047
					addcell({c:val.c, r:val.r}, temp_val, options);
16048
				} break;
16049
				case 'MulRk': {
16050
					for(var j = val.c; j <= val.C; ++j) {
16051
						var ixfe = val.rkrec[j-val.c][0];
16052
						temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'}/*:any*/);
16053
						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16054
						safe_format_xf(temp_val, options, wb.opts.Date1904);
16055
						addcell({c:j, r:val.r}, temp_val, options);
16056
					}
16057
				} break;
16058
				case 'Formula': {
16059
					if(val.val == 'String') { last_formula = val; break; }
16060
					temp_val = make_cell(val.val, val.cell.ixfe, val.tt);
16061
					temp_val.XF = XFs[temp_val.ixfe];
16062
					if(options.cellFormula) {
16063
						var _f = val.formula;
16064
						if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
16065
							var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
16066
							var _fe = encode_cell({r:_fr, c:_fc});
16067
							if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
16068
							else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
16069
						} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
16070
					}
16071
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16072
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16073
					addcell(val.cell, temp_val, options);
16074
					last_formula = val;
16075
				} break;
16076
				case 'String': {
16077
					if(last_formula) { /* technically always true */
16078
						last_formula.val = val;
16079
						temp_val = make_cell(val, last_formula.cell.ixfe, 's');
16080
						temp_val.XF = XFs[temp_val.ixfe];
16081
						if(options.cellFormula) {
16082
							temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
16083
						}
16084
						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16085
						safe_format_xf(temp_val, options, wb.opts.Date1904);
16086
						addcell(last_formula.cell, temp_val, options);
16087
						last_formula = null;
16088
					} else throw new Error("String record expects Formula");
16089
				} break;
16090
				case 'Array': {
16091
					arrayf.push(val);
16092
					var _arraystart = encode_cell(val[0].s);
16093
					cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
16094
					if(options.cellFormula && cc) {
16095
						if(!last_formula) break; /* technically unreachable */
16096
						if(!_arraystart || !cc) break;
16097
						cc.f = ""+stringify_formula(val[1], range, val[0], supbooks, opts);
16098
						cc.F = encode_range(val[0]);
16099
					}
16100
				} break;
16101
				case 'ShrFmla': {
16102
					if(!cell_valid) break;
16103
					if(!options.cellFormula) break;
16104
					if(last_cell) {
16105
						/* TODO: capture range */
16106
						if(!last_formula) break; /* technically unreachable */
16107
						sharedf[encode_cell(last_formula.cell)]= val[0];
16108
						cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
16109
						(cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
16110
					}
16111
				} break;
16112
				case 'LabelSst':
16113
					temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
16114
					temp_val.XF = XFs[temp_val.ixfe];
16115
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16116
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16117
					addcell({c:val.c, r:val.r}, temp_val, options);
16118
					break;
16119
				case 'Blank': if(options.sheetStubs) {
16120
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'}/*:any*/);
16121
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16122
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16123
					addcell({c:val.c, r:val.r}, temp_val, options);
16124
				} break;
16125
				case 'MulBlank': if(options.sheetStubs) {
16126
					for(var _j = val.c; _j <= val.C; ++_j) {
16127
						var _ixfe = val.ixfe[_j-val.c];
16128
						temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'}/*:any*/);
16129
						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16130
						safe_format_xf(temp_val, options, wb.opts.Date1904);
16131
						addcell({c:_j, r:val.r}, temp_val, options);
16132
					}
16133
				} break;
16134
				case 'RString':
16135
				case 'Label': case 'BIFF2STR':
16136
					temp_val=make_cell(val.val, val.ixfe, 's');
16137
					temp_val.XF = XFs[temp_val.ixfe];
16138
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16139
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16140
					addcell({c:val.c, r:val.r}, temp_val, options);
16141
					break;
16142
16143
				case 'Dimensions': {
16144
					if(file_depth === 1) range = val; /* TODO: stack */
16145
				} break;
16146
				case 'SST': {
16147
					sst = val;
16148
				} break;
16149
				case 'Format': { /* val = [id, fmt] */
16150
					if(opts.biff == 4) {
16151
						BIFF2FmtTable[BIFF2Fmt++] = val[1];
16152
						for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(SSF._table[b4idx] == val[1]) break;
16153
						if(b4idx >= 163) SSF.load(val[1], BIFF2Fmt + 163);
16154
					}
16155
					else SSF.load(val[1], val[0]);
16156
				} break;
16157
				case 'BIFF2FORMAT': {
16158
					BIFF2FmtTable[BIFF2Fmt++] = val;
16159
					for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break;
16160
					if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163);
16161
				} break;
16162
16163
				case 'MergeCells': merges = merges.concat(val); break;
16164
16165
				case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break;
16166
				case 'TxO': opts.lastobj.TxO = val; break;
16167
				case 'ImData': opts.lastobj.ImData = val; break;
16168
16169
				case 'HLink': {
16170
					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
16171
						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
16172
							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
16173
							if(cc) cc.l = val[1];
16174
						}
16175
				} break;
16176
				case 'HLinkTooltip': {
16177
					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
16178
						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
16179
							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
16180
							if(cc && cc.l) cc.l.Tooltip = val[1];
16181
							}
16182
				} break;
16183
16184
				/* Comments */
16185
				case 'Note': {
16186
					if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
16187
					cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
16188
					var noteobj = objects[val[2]];
16189
					if(!cc) break;
16190
					if(!cc.c) cc.c = [];
16191
					cmnt = {a:val[1],t:noteobj.TxO.t};
16192
					cc.c.push(cmnt);
16193
				} break;
16194
16195
				default: switch(R.n) { /* nested */
16196
				case 'ClrtClient': break;
16197
				case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break;
16198
16199
				case 'DefColWidth': defwidth = val; break;
16200
				case 'DefaultRowHeight': defheight = val[1]; break; // TODO: flags
16201
16202
				case 'ColInfo': {
16203
					if(!opts.cellStyles) break;
16204
					while(val.e >= val.s) {
16205
						colinfo[val.e--] = { width: val.w/256 };
16206
						if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
16207
						process_col(colinfo[val.e+1]);
16208
					}
16209
				} break;
16210
				case 'Row': {
16211
					var rowobj = {};
16212
					if(val.level != null) { rowinfo[val.r] = rowobj; rowobj.level = val.level; }
16213
					if(val.hidden) { rowinfo[val.r] = rowobj; rowobj.hidden = true; }
16214
					if(val.hpt) {
16215
						rowinfo[val.r] = rowobj;
16216
						rowobj.hpt = val.hpt; rowobj.hpx = pt2px(val.hpt);
16217
					}
16218
				} break;
16219
16220
				case 'LeftMargin':
16221
				case 'RightMargin':
16222
				case 'TopMargin':
16223
				case 'BottomMargin':
16224
					if(!out['!margins']) default_margins(out['!margins'] = {});
16225
					out['!margins'][Rn.slice(0,-6).toLowerCase()] = val;
16226
					break;
16227
16228
				case 'Setup': // TODO
16229
					if(!out['!margins']) default_margins(out['!margins'] = {});
16230
					out['!margins'].header = val.header;
16231
					out['!margins'].footer = val.footer;
16232
					break;
16233
16234
				case 'Window2': // TODO
16235
					// $FlowIgnore
16236
					if(val.RTL) Workbook.Views[0].RTL = true;
16237
					break;
16238
16239
				case 'Header': break; // TODO
16240
				case 'Footer': break; // TODO
16241
				case 'HCenter': break; // TODO
16242
				case 'VCenter': break; // TODO
16243
				case 'Pls': break; // TODO
16244
				case 'GCW': break;
16245
				case 'LHRecord': break;
16246
				case 'DBCell': break; // TODO
16247
				case 'EntExU2': break; // TODO
16248
				case 'SxView': break; // TODO
16249
				case 'Sxvd': break; // TODO
16250
				case 'SXVI': break; // TODO
16251
				case 'SXVDEx': break; // TODO
16252
				case 'SxIvd': break; // TODO
16253
				case 'SXString': break; // TODO
16254
				case 'Sync': break;
16255
				case 'Addin': break;
16256
				case 'SXDI': break; // TODO
16257
				case 'SXLI': break; // TODO
16258
				case 'SXEx': break; // TODO
16259
				case 'QsiSXTag': break; // TODO
16260
				case 'Selection': break;
16261
				case 'Feat': break;
16262
				case 'FeatHdr': case 'FeatHdr11': break;
16263
				case 'Feature11': case 'Feature12': case 'List12': break;
16264
				case 'Country': country = val; break;
16265
				case 'RecalcId': break;
16266
				case 'DxGCol': break; // TODO: htmlify
16267
				case 'Fbi': case 'Fbi2': case 'GelFrame': break;
16268
				case 'Font': break; // TODO
16269
				case 'XFCRC': break; // TODO
16270
				case 'Style': break; // TODO
16271
				case 'StyleExt': break; // TODO
16272
				case 'Palette': palette = val; break;
16273
				case 'Theme': themes = val; break;
16274
				/* Protection */
16275
				case 'ScenarioProtect': break;
16276
				case 'ObjProtect': break;
16277
16278
				/* Conditional Formatting */
16279
				case 'CondFmt12': break;
16280
16281
				/* Table */
16282
				case 'Table': break; // TODO
16283
				case 'TableStyles': break; // TODO
16284
				case 'TableStyle': break; // TODO
16285
				case 'TableStyleElement': break; // TODO
16286
16287
				/* PivotTable */
16288
				case 'SXStreamID': break; // TODO
16289
				case 'SXVS': break; // TODO
16290
				case 'DConRef': break; // TODO
16291
				case 'SXAddl': break; // TODO
16292
				case 'DConBin': break; // TODO
16293
				case 'DConName': break; // TODO
16294
				case 'SXPI': break; // TODO
16295
				case 'SxFormat': break; // TODO
16296
				case 'SxSelect': break; // TODO
16297
				case 'SxRule': break; // TODO
16298
				case 'SxFilt': break; // TODO
16299
				case 'SxItm': break; // TODO
16300
				case 'SxDXF': break; // TODO
16301
16302
				/* Scenario Manager */
16303
				case 'ScenMan': break;
16304
16305
				/* Data Consolidation */
16306
				case 'DCon': break;
16307
16308
				/* Watched Cell */
16309
				case 'CellWatch': break;
16310
16311
				/* Print Settings */
16312
				case 'PrintRowCol': break;
16313
				case 'PrintGrid': break;
16314
				case 'PrintSize': break;
16315
16316
				case 'XCT': break;
16317
				case 'CRN': break;
16318
16319
				case 'Scl': {
16320
					//console.log("Zoom Level:", val[0]/val[1],val);
16321
				} break;
16322
				case 'SheetExt': {
16323
					/* empty */
16324
				} break;
16325
				case 'SheetExtOptional': {
16326
					/* empty */
16327
				} break;
16328
16329
				/* VBA */
16330
				case 'ObNoMacros': {
16331
					/* empty */
16332
				} break;
16333
				case 'ObProj': {
16334
					/* empty */
16335
				} break;
16336
				case 'CodeName': {
16337
					/*:: if(!Workbook.WBProps) Workbook.WBProps = {}; */
16338
					if(!cur_sheet) Workbook.WBProps.CodeName = val || "ThisWorkbook";
16339
					else wsprops.CodeName = val || wsprops.name;
16340
				} break;
16341
				case 'GUIDTypeLib': {
16342
					/* empty */
16343
				} break;
16344
16345
				case 'WOpt': break; // TODO: WTF?
16346
				case 'PhoneticInfo': break;
16347
16348
				case 'OleObjectSize': break;
16349
16350
				/* Differential Formatting */
16351
				case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break;
16352
16353
				/* Data Validation */
16354
				case 'Dv': case 'DVal': break;
16355
16356
				/* Data Series */
16357
				case 'BRAI': case 'Series': case 'SeriesText': break;
16358
16359
				/* Data Connection */
16360
				case 'DConn': break;
16361
				case 'DbOrParamQry': break;
16362
				case 'DBQueryExt': break;
16363
16364
				case 'OleDbConn': break;
16365
				case 'ExtString': break;
16366
16367
				/* Formatting */
16368
				case 'IFmtRecord': break;
16369
				case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
16370
16371
				/* Explicitly Ignored */
16372
				case 'Excel9File': break;
16373
				case 'Units': break;
16374
				case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break;
16375
				case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break;
16376
				/* View Stuff */
16377
				case 'Window1': case 'HideObj': case 'GridSet': case 'Guts':
16378
				case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd':
16379
				case 'Pane': break;
16380
				default: switch(R.n) { /* nested */
16381
				/* Chart */
16382
				case 'Dat':
16383
				case 'Begin': case 'End':
16384
				case 'StartBlock': case 'EndBlock':
16385
				case 'Frame': case 'Area':
16386
				case 'Axis': case 'AxisLine': case 'Tick': break;
16387
				case 'AxesUsed':
16388
				case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break;
16389
				case 'LineFormat': case 'AreaFormat':
16390
				case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break;
16391
				case 'PlotArea': case 'PlotGrowth': break;
16392
				case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break;
16393
				case 'DataFormat': case 'SerToCrt': case 'FontX': break;
16394
				case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
16395
				case 'ShtProps': break;
16396
				case 'DefaultText': case 'Text': case 'CatLab': break;
16397
				case 'DataLabExtContents': break;
16398
				case 'Legend': case 'LegendException': break;
16399
				case 'Pie': case 'Scatter': break;
16400
				case 'PieFormat': case 'MarkerFormat': break;
16401
				case 'StartObject': case 'EndObject': break;
16402
				case 'AlRuns': case 'ObjectLink': break;
16403
				case 'SIIndex': break;
16404
				case 'AttachedLabel': case 'YMult': break;
16405
16406
				/* Chart Group */
16407
				case 'Line': case 'Bar': break;
16408
				case 'Surf': break;
16409
16410
				/* Axis Group */
16411
				case 'AxisParent': break;
16412
				case 'Pos': break;
16413
				case 'ValueRange': break;
16414
16415
				/* Pivot Chart */
16416
				case 'SXViewEx9': break; // TODO
16417
				case 'SXViewLink': break;
16418
				case 'PivotChartBits': break;
16419
				case 'SBaseRef': break;
16420
				case 'TextPropsStream': break;
16421
16422
				/* Chart Misc */
16423
				case 'LnExt': break;
16424
				case 'MkrExt': break;
16425
				case 'CrtCoopt': break;
16426
16427
				/* Query Table */
16428
				case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break;
16429
				case 'TxtQry': break;
16430
16431
				/* Filter */
16432
				case 'FilterMode': break;
16433
				case 'AutoFilter': case 'AutoFilterInfo': break;
16434
				case 'AutoFilter12': break;
16435
				case 'DropDownObjIds': break;
16436
				case 'Sort': break;
16437
				case 'SortData': break;
16438
16439
				/* Drawing */
16440
				case 'ShapePropsStream': break;
16441
				case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
16442
				/* Pub Stuff */
16443
				case 'WebPub': case 'AutoWebPub': break;
16444
16445
				/* Print Stuff */
16446
				case 'HeaderFooter': case 'HFPicture': case 'PLV':
16447
				case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break;
16448
				/* Behavioral */
16449
				case 'Backup': case 'CompressPictures': case 'Compat12': break;
16450
16451
				/* Should not Happen */
16452
				case 'Continue': case 'ContinueFrt12': break;
16453
16454
				/* Future Records */
16455
				case 'FrtFontList': case 'FrtWrapper': break;
16456
16457
				default: switch(R.n) { /* nested */
16458
				/* BIFF5 records */
16459
				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
16460
16461
				/* BIFF2-4 records */
16462
				case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break;
16463
				case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break;
16464
				case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break;
16465
16466
				/* Miscellaneous */
16467
				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':
16468
				case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData':
16469
				case 'Name': break;
16470
				case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break;
16471
				case 'ListObj': case 'ListField': break;
16472
				case 'RRSort': break;
16473
				case 'BigName': break;
16474
				case 'ToolbarHdr': case 'ToolbarEnd': break;
16475
				case 'DDEObjName': break;
16476
				case 'FRTArchId$': break;
16477
				default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
16478
			}}}}
16479
		} else blob.l += length;
16480
	}
16481
	wb.SheetNames=keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;});
16482
	if(!options.bookSheets) wb.Sheets=Sheets;
16483
	if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; });
16484
	wb.Preamble=Preamble;
16485
	wb.Strings = sst;
16486
	wb.SSF = SSF.get_table();
16487
	if(opts.enc) wb.Encryption = opts.enc;
16488
	if(themes) wb.Themes = themes;
16489
	wb.Metadata = {};
16490
	if(country !== undefined) wb.Metadata.Country = country;
16491
	if(supbooks.names.length > 0) Workbook.Names = supbooks.names;
16492
	wb.Workbook = Workbook;
16493
	return wb;
16494
}
16495
16496
/* TODO: split props*/
16497
var PSCLSID = {
16498
	SI: "e0859ff2f94f6810ab9108002b27b3d9",
16499
	DSI: "02d5cdd59c2e1b10939708002b2cf9ae",
16500
	UDI: "05d5cdd59c2e1b10939708002b2cf9ae"
16501
};
16502
function parse_xls_props(cfb/*:CFBContainer*/, props, o) {
16503
	/* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
16504
	var DSI = CFB.find(cfb, '!DocumentSummaryInformation');
16505
	if(DSI && DSI.size > 0) try {
16506
		var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI);
16507
		for(var d in DocSummary) props[d] = DocSummary[d];
16508
	} catch(e) {if(o.WTF) throw e;/* empty */}
16509
16510
	/* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
16511
	var SI = CFB.find(cfb, '!SummaryInformation');
16512
	if(SI && SI.size > 0) try {
16513
		var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI);
16514
		for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
16515
	} catch(e) {if(o.WTF) throw e;/* empty */}
16516
16517
	if(props.HeadingPairs && props.TitlesOfParts) {
16518
		load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o);
16519
		delete props.HeadingPairs; delete props.TitlesOfParts;
16520
	}
16521
}
16522
function write_xls_props(wb/*:Workbook*/, cfb/*:CFBContainer*/) {
16523
	var DSEntries = [], SEntries = [], CEntries = [];
16524
	var i = 0, Keys;
16525
	if(wb.Props) {
16526
		Keys = keys(wb.Props);
16527
		// $FlowIgnore
16528
		for(i = 0; i < Keys.length; ++i) (DocSummaryRE.hasOwnProperty(Keys[i]) ? DSEntries : SummaryRE.hasOwnProperty(Keys[i]) ? SEntries : CEntries).push([Keys[i], wb.Props[Keys[i]]]);
16529
	}
16530
	if(wb.Custprops) {
16531
		Keys = keys(wb.Custprops);
16532
		// $FlowIgnore
16533
		for(i = 0; i < Keys.length; ++i) if(!(wb.Props||{}).hasOwnProperty(Keys[i])) (DocSummaryRE.hasOwnProperty(Keys[i]) ? DSEntries : SummaryRE.hasOwnProperty(Keys[i]) ? SEntries : CEntries).push([Keys[i], wb.Custprops[Keys[i]]]);
16534
	}
16535
	var CEntries2 = [];
16536
	for(i = 0; i < CEntries.length; ++i) {
16537
		if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue;
16538
		if(CEntries[i][1] == null) continue;
16539
		CEntries2.push(CEntries[i]);
16540
	}
16541
	if(SEntries.length) CFB.utils.cfb_add(cfb, "/\u0005SummaryInformation", write_PropertySetStream(SEntries, PSCLSID.SI, SummaryRE, SummaryPIDSI));
16542
	if(DSEntries.length || CEntries2.length) CFB.utils.cfb_add(cfb, "/\u0005DocumentSummaryInformation", write_PropertySetStream(DSEntries, PSCLSID.DSI, DocSummaryRE, DocSummaryPIDDSI, CEntries2.length ? CEntries2 : null, PSCLSID.UDI));
16543
}
16544
16545
function parse_xlscfb(cfb/*:any*/, options/*:?ParseOpts*/)/*:Workbook*/ {
16546
if(!options) options = {};
16547
fix_read_opts(options);
16548
reset_cp();
16549
if(options.codepage) set_ansi(options.codepage);
16550
var CompObj/*:?CFBEntry*/, WB/*:?any*/;
16551
if(cfb.FullPaths) {
16552
	if(CFB.find(cfb, '/encryption')) throw new Error("File is password-protected");
16553
	CompObj = CFB.find(cfb, '!CompObj');
16554
	WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
16555
} else {
16556
	switch(options.type) {
16557
		case 'base64': cfb = s2a(Base64.decode(cfb)); break;
16558
		case 'binary': cfb = s2a(cfb); break;
16559
		case 'buffer': break;
16560
		case 'array': if(!Array.isArray(cfb)) cfb = Array.prototype.slice.call(cfb); break;
16561
	}
16562
	prep_blob(cfb, 0);
16563
	WB = ({content: cfb}/*:any*/);
16564
}
16565
var /*::CompObjP, */WorkbookP/*:: :Workbook = XLSX.utils.book_new(); */;
16566
16567
var _data/*:?any*/;
16568
if(CompObj) /*::CompObjP = */parse_compobj(CompObj);
16569
if(options.bookProps && !options.bookSheets) WorkbookP = ({}/*:any*/);
16570
else/*:: if(cfb instanceof CFBContainer) */ {
16571
	var T = has_buf ? 'buffer' : 'array';
16572
	if(WB && WB.content) WorkbookP = parse_workbook(WB.content, options);
16573
	/* Quattro Pro 7-8 */
16574
	else if((_data=CFB.find(cfb, 'PerfectOffice_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
16575
	/* Quattro Pro 9 */
16576
	else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
16577
	else throw new Error("Cannot find Workbook stream");
16578
	if(options.bookVBA && cfb.FullPaths && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb);
16579
}
16580
16581
var props = {};
16582
if(cfb.FullPaths) parse_xls_props(/*::((*/cfb/*:: :any):CFBContainer)*/, props, options);
16583
16584
WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
16585
if(options.bookFiles) WorkbookP.cfb = cfb;
16586
/*WorkbookP.CompObjP = CompObjP; // TODO: storage? */
16587
return WorkbookP;
16588
}
16589
16590
16591
function write_xlscfb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:CFBContainer*/ {
16592
	var o = opts || {};
16593
	var cfb = CFB.utils.cfb_new({root:"R"});
16594
	var wbpath = "/Workbook";
16595
	switch(o.bookType || "xls") {
16596
		case "xls": o.bookType = "biff8";
16597
		/* falls through */
16598
		case "xla": if(!o.bookType) o.bookType = "xla";
16599
		/* falls through */
16600
		case "biff8": wbpath = "/Workbook"; o.biff = 8; break;
16601
		case "biff5": wbpath = "/Book"; o.biff = 5; break;
16602
		default: throw new Error("invalid type " + o.bookType + " for XLS CFB");
16603
	}
16604
	CFB.utils.cfb_add(cfb, wbpath, write_biff_buf(wb, o));
16605
	if(o.biff == 8 && (wb.Props || wb.Custprops)) write_xls_props(wb, cfb);
16606
	// TODO: SI, DSI, CO
16607
	if(o.biff == 8 && wb.vbaraw) fill_vba_xls(cfb, CFB.read(wb.vbaraw, {type: typeof wb.vbaraw == "string" ? "binary" : "buffer"}));
16608
	return cfb;
16609
}
16610
/* [MS-XLSB] 2.3 Record Enumeration */
16611
var XLSBRecordEnum = {
16612
	/*::[*/0x0000/*::]*/: { n:"BrtRowHdr", f:parse_BrtRowHdr },
16613
	/*::[*/0x0001/*::]*/: { n:"BrtCellBlank", f:parse_BrtCellBlank },
16614
	/*::[*/0x0002/*::]*/: { n:"BrtCellRk", f:parse_BrtCellRk },
16615
	/*::[*/0x0003/*::]*/: { n:"BrtCellError", f:parse_BrtCellError },
16616
	/*::[*/0x0004/*::]*/: { n:"BrtCellBool", f:parse_BrtCellBool },
16617
	/*::[*/0x0005/*::]*/: { n:"BrtCellReal", f:parse_BrtCellReal },
16618
	/*::[*/0x0006/*::]*/: { n:"BrtCellSt", f:parse_BrtCellSt },
16619
	/*::[*/0x0007/*::]*/: { n:"BrtCellIsst", f:parse_BrtCellIsst },
16620
	/*::[*/0x0008/*::]*/: { n:"BrtFmlaString", f:parse_BrtFmlaString },
16621
	/*::[*/0x0009/*::]*/: { n:"BrtFmlaNum", f:parse_BrtFmlaNum },
16622
	/*::[*/0x000A/*::]*/: { n:"BrtFmlaBool", f:parse_BrtFmlaBool },
16623
	/*::[*/0x000B/*::]*/: { n:"BrtFmlaError", f:parse_BrtFmlaError },
16624
	/*::[*/0x0010/*::]*/: { n:"BrtFRTArchID$", f:parse_BrtFRTArchID$ },
16625
	/*::[*/0x0013/*::]*/: { n:"BrtSSTItem", f:parse_RichStr },
16626
	/*::[*/0x0014/*::]*/: { n:"BrtPCDIMissing" },
16627
	/*::[*/0x0015/*::]*/: { n:"BrtPCDINumber" },
16628
	/*::[*/0x0016/*::]*/: { n:"BrtPCDIBoolean" },
16629
	/*::[*/0x0017/*::]*/: { n:"BrtPCDIError" },
16630
	/*::[*/0x0018/*::]*/: { n:"BrtPCDIString" },
16631
	/*::[*/0x0019/*::]*/: { n:"BrtPCDIDatetime" },
16632
	/*::[*/0x001A/*::]*/: { n:"BrtPCDIIndex" },
16633
	/*::[*/0x001B/*::]*/: { n:"BrtPCDIAMissing" },
16634
	/*::[*/0x001C/*::]*/: { n:"BrtPCDIANumber" },
16635
	/*::[*/0x001D/*::]*/: { n:"BrtPCDIABoolean" },
16636
	/*::[*/0x001E/*::]*/: { n:"BrtPCDIAError" },
16637
	/*::[*/0x001F/*::]*/: { n:"BrtPCDIAString" },
16638
	/*::[*/0x0020/*::]*/: { n:"BrtPCDIADatetime" },
16639
	/*::[*/0x0021/*::]*/: { n:"BrtPCRRecord" },
16640
	/*::[*/0x0022/*::]*/: { n:"BrtPCRRecordDt" },
16641
	/*::[*/0x0023/*::]*/: { n:"BrtFRTBegin" },
16642
	/*::[*/0x0024/*::]*/: { n:"BrtFRTEnd" },
16643
	/*::[*/0x0025/*::]*/: { n:"BrtACBegin" },
16644
	/*::[*/0x0026/*::]*/: { n:"BrtACEnd" },
16645
	/*::[*/0x0027/*::]*/: { n:"BrtName", f:parse_BrtName },
16646
	/*::[*/0x0028/*::]*/: { n:"BrtIndexRowBlock" },
16647
	/*::[*/0x002A/*::]*/: { n:"BrtIndexBlock" },
16648
	/*::[*/0x002B/*::]*/: { n:"BrtFont", f:parse_BrtFont },
16649
	/*::[*/0x002C/*::]*/: { n:"BrtFmt", f:parse_BrtFmt },
16650
	/*::[*/0x002D/*::]*/: { n:"BrtFill", f:parse_BrtFill },
16651
	/*::[*/0x002E/*::]*/: { n:"BrtBorder", f:parse_BrtBorder },
16652
	/*::[*/0x002F/*::]*/: { n:"BrtXF", f:parse_BrtXF },
16653
	/*::[*/0x0030/*::]*/: { n:"BrtStyle" },
16654
	/*::[*/0x0031/*::]*/: { n:"BrtCellMeta" },
16655
	/*::[*/0x0032/*::]*/: { n:"BrtValueMeta" },
16656
	/*::[*/0x0033/*::]*/: { n:"BrtMdb" },
16657
	/*::[*/0x0034/*::]*/: { n:"BrtBeginFmd" },
16658
	/*::[*/0x0035/*::]*/: { n:"BrtEndFmd" },
16659
	/*::[*/0x0036/*::]*/: { n:"BrtBeginMdx" },
16660
	/*::[*/0x0037/*::]*/: { n:"BrtEndMdx" },
16661
	/*::[*/0x0038/*::]*/: { n:"BrtBeginMdxTuple" },
16662
	/*::[*/0x0039/*::]*/: { n:"BrtEndMdxTuple" },
16663
	/*::[*/0x003A/*::]*/: { n:"BrtMdxMbrIstr" },
16664
	/*::[*/0x003B/*::]*/: { n:"BrtStr" },
16665
	/*::[*/0x003C/*::]*/: { n:"BrtColInfo", f:parse_ColInfo },
16666
	/*::[*/0x003E/*::]*/: { n:"BrtCellRString" },
16667
	/*::[*/0x003F/*::]*/: { n:"BrtCalcChainItem$", f:parse_BrtCalcChainItem$ },
16668
	/*::[*/0x0040/*::]*/: { n:"BrtDVal" },
16669
	/*::[*/0x0041/*::]*/: { n:"BrtSxvcellNum" },
16670
	/*::[*/0x0042/*::]*/: { n:"BrtSxvcellStr" },
16671
	/*::[*/0x0043/*::]*/: { n:"BrtSxvcellBool" },
16672
	/*::[*/0x0044/*::]*/: { n:"BrtSxvcellErr" },
16673
	/*::[*/0x0045/*::]*/: { n:"BrtSxvcellDate" },
16674
	/*::[*/0x0046/*::]*/: { n:"BrtSxvcellNil" },
16675
	/*::[*/0x0080/*::]*/: { n:"BrtFileVersion" },
16676
	/*::[*/0x0081/*::]*/: { n:"BrtBeginSheet" },
16677
	/*::[*/0x0082/*::]*/: { n:"BrtEndSheet" },
16678
	/*::[*/0x0083/*::]*/: { n:"BrtBeginBook", f:parsenoop, p:0 },
16679
	/*::[*/0x0084/*::]*/: { n:"BrtEndBook" },
16680
	/*::[*/0x0085/*::]*/: { n:"BrtBeginWsViews" },
16681
	/*::[*/0x0086/*::]*/: { n:"BrtEndWsViews" },
16682
	/*::[*/0x0087/*::]*/: { n:"BrtBeginBookViews" },
16683
	/*::[*/0x0088/*::]*/: { n:"BrtEndBookViews" },
16684
	/*::[*/0x0089/*::]*/: { n:"BrtBeginWsView", f:parse_BrtBeginWsView },
16685
	/*::[*/0x008A/*::]*/: { n:"BrtEndWsView" },
16686
	/*::[*/0x008B/*::]*/: { n:"BrtBeginCsViews" },
16687
	/*::[*/0x008C/*::]*/: { n:"BrtEndCsViews" },
16688
	/*::[*/0x008D/*::]*/: { n:"BrtBeginCsView" },
16689
	/*::[*/0x008E/*::]*/: { n:"BrtEndCsView" },
16690
	/*::[*/0x008F/*::]*/: { n:"BrtBeginBundleShs" },
16691
	/*::[*/0x0090/*::]*/: { n:"BrtEndBundleShs" },
16692
	/*::[*/0x0091/*::]*/: { n:"BrtBeginSheetData" },
16693
	/*::[*/0x0092/*::]*/: { n:"BrtEndSheetData" },
16694
	/*::[*/0x0093/*::]*/: { n:"BrtWsProp", f:parse_BrtWsProp },
16695
	/*::[*/0x0094/*::]*/: { n:"BrtWsDim", f:parse_BrtWsDim, p:16 },
16696
	/*::[*/0x0097/*::]*/: { n:"BrtPane" },
16697
	/*::[*/0x0098/*::]*/: { n:"BrtSel" },
16698
	/*::[*/0x0099/*::]*/: { n:"BrtWbProp", f:parse_BrtWbProp },
16699
	/*::[*/0x009A/*::]*/: { n:"BrtWbFactoid" },
16700
	/*::[*/0x009B/*::]*/: { n:"BrtFileRecover" },
16701
	/*::[*/0x009C/*::]*/: { n:"BrtBundleSh", f:parse_BrtBundleSh },
16702
	/*::[*/0x009D/*::]*/: { n:"BrtCalcProp" },
16703
	/*::[*/0x009E/*::]*/: { n:"BrtBookView" },
16704
	/*::[*/0x009F/*::]*/: { n:"BrtBeginSst", f:parse_BrtBeginSst },
16705
	/*::[*/0x00A0/*::]*/: { n:"BrtEndSst" },
16706
	/*::[*/0x00A1/*::]*/: { n:"BrtBeginAFilter", f:parse_UncheckedRfX },
16707
	/*::[*/0x00A2/*::]*/: { n:"BrtEndAFilter" },
16708
	/*::[*/0x00A3/*::]*/: { n:"BrtBeginFilterColumn" },
16709
	/*::[*/0x00A4/*::]*/: { n:"BrtEndFilterColumn" },
16710
	/*::[*/0x00A5/*::]*/: { n:"BrtBeginFilters" },
16711
	/*::[*/0x00A6/*::]*/: { n:"BrtEndFilters" },
16712
	/*::[*/0x00A7/*::]*/: { n:"BrtFilter" },
16713
	/*::[*/0x00A8/*::]*/: { n:"BrtColorFilter" },
16714
	/*::[*/0x00A9/*::]*/: { n:"BrtIconFilter" },
16715
	/*::[*/0x00AA/*::]*/: { n:"BrtTop10Filter" },
16716
	/*::[*/0x00AB/*::]*/: { n:"BrtDynamicFilter" },
16717
	/*::[*/0x00AC/*::]*/: { n:"BrtBeginCustomFilters" },
16718
	/*::[*/0x00AD/*::]*/: { n:"BrtEndCustomFilters" },
16719
	/*::[*/0x00AE/*::]*/: { n:"BrtCustomFilter" },
16720
	/*::[*/0x00AF/*::]*/: { n:"BrtAFilterDateGroupItem" },
16721
	/*::[*/0x00B0/*::]*/: { n:"BrtMergeCell", f:parse_BrtMergeCell },
16722
	/*::[*/0x00B1/*::]*/: { n:"BrtBeginMergeCells" },
16723
	/*::[*/0x00B2/*::]*/: { n:"BrtEndMergeCells" },
16724
	/*::[*/0x00B3/*::]*/: { n:"BrtBeginPivotCacheDef" },
16725
	/*::[*/0x00B4/*::]*/: { n:"BrtEndPivotCacheDef" },
16726
	/*::[*/0x00B5/*::]*/: { n:"BrtBeginPCDFields" },
16727
	/*::[*/0x00B6/*::]*/: { n:"BrtEndPCDFields" },
16728
	/*::[*/0x00B7/*::]*/: { n:"BrtBeginPCDField" },
16729
	/*::[*/0x00B8/*::]*/: { n:"BrtEndPCDField" },
16730
	/*::[*/0x00B9/*::]*/: { n:"BrtBeginPCDSource" },
16731
	/*::[*/0x00BA/*::]*/: { n:"BrtEndPCDSource" },
16732
	/*::[*/0x00BB/*::]*/: { n:"BrtBeginPCDSRange" },
16733
	/*::[*/0x00BC/*::]*/: { n:"BrtEndPCDSRange" },
16734
	/*::[*/0x00BD/*::]*/: { n:"BrtBeginPCDFAtbl" },
16735
	/*::[*/0x00BE/*::]*/: { n:"BrtEndPCDFAtbl" },
16736
	/*::[*/0x00BF/*::]*/: { n:"BrtBeginPCDIRun" },
16737
	/*::[*/0x00C0/*::]*/: { n:"BrtEndPCDIRun" },
16738
	/*::[*/0x00C1/*::]*/: { n:"BrtBeginPivotCacheRecords" },
16739
	/*::[*/0x00C2/*::]*/: { n:"BrtEndPivotCacheRecords" },
16740
	/*::[*/0x00C3/*::]*/: { n:"BrtBeginPCDHierarchies" },
16741
	/*::[*/0x00C4/*::]*/: { n:"BrtEndPCDHierarchies" },
16742
	/*::[*/0x00C5/*::]*/: { n:"BrtBeginPCDHierarchy" },
16743
	/*::[*/0x00C6/*::]*/: { n:"BrtEndPCDHierarchy" },
16744
	/*::[*/0x00C7/*::]*/: { n:"BrtBeginPCDHFieldsUsage" },
16745
	/*::[*/0x00C8/*::]*/: { n:"BrtEndPCDHFieldsUsage" },
16746
	/*::[*/0x00C9/*::]*/: { n:"BrtBeginExtConnection" },
16747
	/*::[*/0x00CA/*::]*/: { n:"BrtEndExtConnection" },
16748
	/*::[*/0x00CB/*::]*/: { n:"BrtBeginECDbProps" },
16749
	/*::[*/0x00CC/*::]*/: { n:"BrtEndECDbProps" },
16750
	/*::[*/0x00CD/*::]*/: { n:"BrtBeginECOlapProps" },
16751
	/*::[*/0x00CE/*::]*/: { n:"BrtEndECOlapProps" },
16752
	/*::[*/0x00CF/*::]*/: { n:"BrtBeginPCDSConsol" },
16753
	/*::[*/0x00D0/*::]*/: { n:"BrtEndPCDSConsol" },
16754
	/*::[*/0x00D1/*::]*/: { n:"BrtBeginPCDSCPages" },
16755
	/*::[*/0x00D2/*::]*/: { n:"BrtEndPCDSCPages" },
16756
	/*::[*/0x00D3/*::]*/: { n:"BrtBeginPCDSCPage" },
16757
	/*::[*/0x00D4/*::]*/: { n:"BrtEndPCDSCPage" },
16758
	/*::[*/0x00D5/*::]*/: { n:"BrtBeginPCDSCPItem" },
16759
	/*::[*/0x00D6/*::]*/: { n:"BrtEndPCDSCPItem" },
16760
	/*::[*/0x00D7/*::]*/: { n:"BrtBeginPCDSCSets" },
16761
	/*::[*/0x00D8/*::]*/: { n:"BrtEndPCDSCSets" },
16762
	/*::[*/0x00D9/*::]*/: { n:"BrtBeginPCDSCSet" },
16763
	/*::[*/0x00DA/*::]*/: { n:"BrtEndPCDSCSet" },
16764
	/*::[*/0x00DB/*::]*/: { n:"BrtBeginPCDFGroup" },
16765
	/*::[*/0x00DC/*::]*/: { n:"BrtEndPCDFGroup" },
16766
	/*::[*/0x00DD/*::]*/: { n:"BrtBeginPCDFGItems" },
16767
	/*::[*/0x00DE/*::]*/: { n:"BrtEndPCDFGItems" },
16768
	/*::[*/0x00DF/*::]*/: { n:"BrtBeginPCDFGRange" },
16769
	/*::[*/0x00E0/*::]*/: { n:"BrtEndPCDFGRange" },
16770
	/*::[*/0x00E1/*::]*/: { n:"BrtBeginPCDFGDiscrete" },
16771
	/*::[*/0x00E2/*::]*/: { n:"BrtEndPCDFGDiscrete" },
16772
	/*::[*/0x00E3/*::]*/: { n:"BrtBeginPCDSDTupleCache" },
16773
	/*::[*/0x00E4/*::]*/: { n:"BrtEndPCDSDTupleCache" },
16774
	/*::[*/0x00E5/*::]*/: { n:"BrtBeginPCDSDTCEntries" },
16775
	/*::[*/0x00E6/*::]*/: { n:"BrtEndPCDSDTCEntries" },
16776
	/*::[*/0x00E7/*::]*/: { n:"BrtBeginPCDSDTCEMembers" },
16777
	/*::[*/0x00E8/*::]*/: { n:"BrtEndPCDSDTCEMembers" },
16778
	/*::[*/0x00E9/*::]*/: { n:"BrtBeginPCDSDTCEMember" },
16779
	/*::[*/0x00EA/*::]*/: { n:"BrtEndPCDSDTCEMember" },
16780
	/*::[*/0x00EB/*::]*/: { n:"BrtBeginPCDSDTCQueries" },
16781
	/*::[*/0x00EC/*::]*/: { n:"BrtEndPCDSDTCQueries" },
16782
	/*::[*/0x00ED/*::]*/: { n:"BrtBeginPCDSDTCQuery" },
16783
	/*::[*/0x00EE/*::]*/: { n:"BrtEndPCDSDTCQuery" },
16784
	/*::[*/0x00EF/*::]*/: { n:"BrtBeginPCDSDTCSets" },
16785
	/*::[*/0x00F0/*::]*/: { n:"BrtEndPCDSDTCSets" },
16786
	/*::[*/0x00F1/*::]*/: { n:"BrtBeginPCDSDTCSet" },
16787
	/*::[*/0x00F2/*::]*/: { n:"BrtEndPCDSDTCSet" },
16788
	/*::[*/0x00F3/*::]*/: { n:"BrtBeginPCDCalcItems" },
16789
	/*::[*/0x00F4/*::]*/: { n:"BrtEndPCDCalcItems" },
16790
	/*::[*/0x00F5/*::]*/: { n:"BrtBeginPCDCalcItem" },
16791
	/*::[*/0x00F6/*::]*/: { n:"BrtEndPCDCalcItem" },
16792
	/*::[*/0x00F7/*::]*/: { n:"BrtBeginPRule" },
16793
	/*::[*/0x00F8/*::]*/: { n:"BrtEndPRule" },
16794
	/*::[*/0x00F9/*::]*/: { n:"BrtBeginPRFilters" },
16795
	/*::[*/0x00FA/*::]*/: { n:"BrtEndPRFilters" },
16796
	/*::[*/0x00FB/*::]*/: { n:"BrtBeginPRFilter" },
16797
	/*::[*/0x00FC/*::]*/: { n:"BrtEndPRFilter" },
16798
	/*::[*/0x00FD/*::]*/: { n:"BrtBeginPNames" },
16799
	/*::[*/0x00FE/*::]*/: { n:"BrtEndPNames" },
16800
	/*::[*/0x00FF/*::]*/: { n:"BrtBeginPName" },
16801
	/*::[*/0x0100/*::]*/: { n:"BrtEndPName" },
16802
	/*::[*/0x0101/*::]*/: { n:"BrtBeginPNPairs" },
16803
	/*::[*/0x0102/*::]*/: { n:"BrtEndPNPairs" },
16804
	/*::[*/0x0103/*::]*/: { n:"BrtBeginPNPair" },
16805
	/*::[*/0x0104/*::]*/: { n:"BrtEndPNPair" },
16806
	/*::[*/0x0105/*::]*/: { n:"BrtBeginECWebProps" },
16807
	/*::[*/0x0106/*::]*/: { n:"BrtEndECWebProps" },
16808
	/*::[*/0x0107/*::]*/: { n:"BrtBeginEcWpTables" },
16809
	/*::[*/0x0108/*::]*/: { n:"BrtEndECWPTables" },
16810
	/*::[*/0x0109/*::]*/: { n:"BrtBeginECParams" },
16811
	/*::[*/0x010A/*::]*/: { n:"BrtEndECParams" },
16812
	/*::[*/0x010B/*::]*/: { n:"BrtBeginECParam" },
16813
	/*::[*/0x010C/*::]*/: { n:"BrtEndECParam" },
16814
	/*::[*/0x010D/*::]*/: { n:"BrtBeginPCDKPIs" },
16815
	/*::[*/0x010E/*::]*/: { n:"BrtEndPCDKPIs" },
16816
	/*::[*/0x010F/*::]*/: { n:"BrtBeginPCDKPI" },
16817
	/*::[*/0x0110/*::]*/: { n:"BrtEndPCDKPI" },
16818
	/*::[*/0x0111/*::]*/: { n:"BrtBeginDims" },
16819
	/*::[*/0x0112/*::]*/: { n:"BrtEndDims" },
16820
	/*::[*/0x0113/*::]*/: { n:"BrtBeginDim" },
16821
	/*::[*/0x0114/*::]*/: { n:"BrtEndDim" },
16822
	/*::[*/0x0115/*::]*/: { n:"BrtIndexPartEnd" },
16823
	/*::[*/0x0116/*::]*/: { n:"BrtBeginStyleSheet" },
16824
	/*::[*/0x0117/*::]*/: { n:"BrtEndStyleSheet" },
16825
	/*::[*/0x0118/*::]*/: { n:"BrtBeginSXView" },
16826
	/*::[*/0x0119/*::]*/: { n:"BrtEndSXVI" },
16827
	/*::[*/0x011A/*::]*/: { n:"BrtBeginSXVI" },
16828
	/*::[*/0x011B/*::]*/: { n:"BrtBeginSXVIs" },
16829
	/*::[*/0x011C/*::]*/: { n:"BrtEndSXVIs" },
16830
	/*::[*/0x011D/*::]*/: { n:"BrtBeginSXVD" },
16831
	/*::[*/0x011E/*::]*/: { n:"BrtEndSXVD" },
16832
	/*::[*/0x011F/*::]*/: { n:"BrtBeginSXVDs" },
16833
	/*::[*/0x0120/*::]*/: { n:"BrtEndSXVDs" },
16834
	/*::[*/0x0121/*::]*/: { n:"BrtBeginSXPI" },
16835
	/*::[*/0x0122/*::]*/: { n:"BrtEndSXPI" },
16836
	/*::[*/0x0123/*::]*/: { n:"BrtBeginSXPIs" },
16837
	/*::[*/0x0124/*::]*/: { n:"BrtEndSXPIs" },
16838
	/*::[*/0x0125/*::]*/: { n:"BrtBeginSXDI" },
16839
	/*::[*/0x0126/*::]*/: { n:"BrtEndSXDI" },
16840
	/*::[*/0x0127/*::]*/: { n:"BrtBeginSXDIs" },
16841
	/*::[*/0x0128/*::]*/: { n:"BrtEndSXDIs" },
16842
	/*::[*/0x0129/*::]*/: { n:"BrtBeginSXLI" },
16843
	/*::[*/0x012A/*::]*/: { n:"BrtEndSXLI" },
16844
	/*::[*/0x012B/*::]*/: { n:"BrtBeginSXLIRws" },
16845
	/*::[*/0x012C/*::]*/: { n:"BrtEndSXLIRws" },
16846
	/*::[*/0x012D/*::]*/: { n:"BrtBeginSXLICols" },
16847
	/*::[*/0x012E/*::]*/: { n:"BrtEndSXLICols" },
16848
	/*::[*/0x012F/*::]*/: { n:"BrtBeginSXFormat" },
16849
	/*::[*/0x0130/*::]*/: { n:"BrtEndSXFormat" },
16850
	/*::[*/0x0131/*::]*/: { n:"BrtBeginSXFormats" },
16851
	/*::[*/0x0132/*::]*/: { n:"BrtEndSxFormats" },
16852
	/*::[*/0x0133/*::]*/: { n:"BrtBeginSxSelect" },
16853
	/*::[*/0x0134/*::]*/: { n:"BrtEndSxSelect" },
16854
	/*::[*/0x0135/*::]*/: { n:"BrtBeginISXVDRws" },
16855
	/*::[*/0x0136/*::]*/: { n:"BrtEndISXVDRws" },
16856
	/*::[*/0x0137/*::]*/: { n:"BrtBeginISXVDCols" },
16857
	/*::[*/0x0138/*::]*/: { n:"BrtEndISXVDCols" },
16858
	/*::[*/0x0139/*::]*/: { n:"BrtEndSXLocation" },
16859
	/*::[*/0x013A/*::]*/: { n:"BrtBeginSXLocation" },
16860
	/*::[*/0x013B/*::]*/: { n:"BrtEndSXView" },
16861
	/*::[*/0x013C/*::]*/: { n:"BrtBeginSXTHs" },
16862
	/*::[*/0x013D/*::]*/: { n:"BrtEndSXTHs" },
16863
	/*::[*/0x013E/*::]*/: { n:"BrtBeginSXTH" },
16864
	/*::[*/0x013F/*::]*/: { n:"BrtEndSXTH" },
16865
	/*::[*/0x0140/*::]*/: { n:"BrtBeginISXTHRws" },
16866
	/*::[*/0x0141/*::]*/: { n:"BrtEndISXTHRws" },
16867
	/*::[*/0x0142/*::]*/: { n:"BrtBeginISXTHCols" },
16868
	/*::[*/0x0143/*::]*/: { n:"BrtEndISXTHCols" },
16869
	/*::[*/0x0144/*::]*/: { n:"BrtBeginSXTDMPS" },
16870
	/*::[*/0x0145/*::]*/: { n:"BrtEndSXTDMPs" },
16871
	/*::[*/0x0146/*::]*/: { n:"BrtBeginSXTDMP" },
16872
	/*::[*/0x0147/*::]*/: { n:"BrtEndSXTDMP" },
16873
	/*::[*/0x0148/*::]*/: { n:"BrtBeginSXTHItems" },
16874
	/*::[*/0x0149/*::]*/: { n:"BrtEndSXTHItems" },
16875
	/*::[*/0x014A/*::]*/: { n:"BrtBeginSXTHItem" },
16876
	/*::[*/0x014B/*::]*/: { n:"BrtEndSXTHItem" },
16877
	/*::[*/0x014C/*::]*/: { n:"BrtBeginMetadata" },
16878
	/*::[*/0x014D/*::]*/: { n:"BrtEndMetadata" },
16879
	/*::[*/0x014E/*::]*/: { n:"BrtBeginEsmdtinfo" },
16880
	/*::[*/0x014F/*::]*/: { n:"BrtMdtinfo" },
16881
	/*::[*/0x0150/*::]*/: { n:"BrtEndEsmdtinfo" },
16882
	/*::[*/0x0151/*::]*/: { n:"BrtBeginEsmdb" },
16883
	/*::[*/0x0152/*::]*/: { n:"BrtEndEsmdb" },
16884
	/*::[*/0x0153/*::]*/: { n:"BrtBeginEsfmd" },
16885
	/*::[*/0x0154/*::]*/: { n:"BrtEndEsfmd" },
16886
	/*::[*/0x0155/*::]*/: { n:"BrtBeginSingleCells" },
16887
	/*::[*/0x0156/*::]*/: { n:"BrtEndSingleCells" },
16888
	/*::[*/0x0157/*::]*/: { n:"BrtBeginList" },
16889
	/*::[*/0x0158/*::]*/: { n:"BrtEndList" },
16890
	/*::[*/0x0159/*::]*/: { n:"BrtBeginListCols" },
16891
	/*::[*/0x015A/*::]*/: { n:"BrtEndListCols" },
16892
	/*::[*/0x015B/*::]*/: { n:"BrtBeginListCol" },
16893
	/*::[*/0x015C/*::]*/: { n:"BrtEndListCol" },
16894
	/*::[*/0x015D/*::]*/: { n:"BrtBeginListXmlCPr" },
16895
	/*::[*/0x015E/*::]*/: { n:"BrtEndListXmlCPr" },
16896
	/*::[*/0x015F/*::]*/: { n:"BrtListCCFmla" },
16897
	/*::[*/0x0160/*::]*/: { n:"BrtListTrFmla" },
16898
	/*::[*/0x0161/*::]*/: { n:"BrtBeginExternals" },
16899
	/*::[*/0x0162/*::]*/: { n:"BrtEndExternals" },
16900
	/*::[*/0x0163/*::]*/: { n:"BrtSupBookSrc", f:parse_RelID},
16901
	/*::[*/0x0165/*::]*/: { n:"BrtSupSelf" },
16902
	/*::[*/0x0166/*::]*/: { n:"BrtSupSame" },
16903
	/*::[*/0x0167/*::]*/: { n:"BrtSupTabs" },
16904
	/*::[*/0x0168/*::]*/: { n:"BrtBeginSupBook" },
16905
	/*::[*/0x0169/*::]*/: { n:"BrtPlaceholderName" },
16906
	/*::[*/0x016A/*::]*/: { n:"BrtExternSheet", f:parse_ExternSheet },
16907
	/*::[*/0x016B/*::]*/: { n:"BrtExternTableStart" },
16908
	/*::[*/0x016C/*::]*/: { n:"BrtExternTableEnd" },
16909
	/*::[*/0x016E/*::]*/: { n:"BrtExternRowHdr" },
16910
	/*::[*/0x016F/*::]*/: { n:"BrtExternCellBlank" },
16911
	/*::[*/0x0170/*::]*/: { n:"BrtExternCellReal" },
16912
	/*::[*/0x0171/*::]*/: { n:"BrtExternCellBool" },
16913
	/*::[*/0x0172/*::]*/: { n:"BrtExternCellError" },
16914
	/*::[*/0x0173/*::]*/: { n:"BrtExternCellString" },
16915
	/*::[*/0x0174/*::]*/: { n:"BrtBeginEsmdx" },
16916
	/*::[*/0x0175/*::]*/: { n:"BrtEndEsmdx" },
16917
	/*::[*/0x0176/*::]*/: { n:"BrtBeginMdxSet" },
16918
	/*::[*/0x0177/*::]*/: { n:"BrtEndMdxSet" },
16919
	/*::[*/0x0178/*::]*/: { n:"BrtBeginMdxMbrProp" },
16920
	/*::[*/0x0179/*::]*/: { n:"BrtEndMdxMbrProp" },
16921
	/*::[*/0x017A/*::]*/: { n:"BrtBeginMdxKPI" },
16922
	/*::[*/0x017B/*::]*/: { n:"BrtEndMdxKPI" },
16923
	/*::[*/0x017C/*::]*/: { n:"BrtBeginEsstr" },
16924
	/*::[*/0x017D/*::]*/: { n:"BrtEndEsstr" },
16925
	/*::[*/0x017E/*::]*/: { n:"BrtBeginPRFItem" },
16926
	/*::[*/0x017F/*::]*/: { n:"BrtEndPRFItem" },
16927
	/*::[*/0x0180/*::]*/: { n:"BrtBeginPivotCacheIDs" },
16928
	/*::[*/0x0181/*::]*/: { n:"BrtEndPivotCacheIDs" },
16929
	/*::[*/0x0182/*::]*/: { n:"BrtBeginPivotCacheID" },
16930
	/*::[*/0x0183/*::]*/: { n:"BrtEndPivotCacheID" },
16931
	/*::[*/0x0184/*::]*/: { n:"BrtBeginISXVIs" },
16932
	/*::[*/0x0185/*::]*/: { n:"BrtEndISXVIs" },
16933
	/*::[*/0x0186/*::]*/: { n:"BrtBeginColInfos" },
16934
	/*::[*/0x0187/*::]*/: { n:"BrtEndColInfos" },
16935
	/*::[*/0x0188/*::]*/: { n:"BrtBeginRwBrk" },
16936
	/*::[*/0x0189/*::]*/: { n:"BrtEndRwBrk" },
16937
	/*::[*/0x018A/*::]*/: { n:"BrtBeginColBrk" },
16938
	/*::[*/0x018B/*::]*/: { n:"BrtEndColBrk" },
16939
	/*::[*/0x018C/*::]*/: { n:"BrtBrk" },
16940
	/*::[*/0x018D/*::]*/: { n:"BrtUserBookView" },
16941
	/*::[*/0x018E/*::]*/: { n:"BrtInfo" },
16942
	/*::[*/0x018F/*::]*/: { n:"BrtCUsr" },
16943
	/*::[*/0x0190/*::]*/: { n:"BrtUsr" },
16944
	/*::[*/0x0191/*::]*/: { n:"BrtBeginUsers" },
16945
	/*::[*/0x0193/*::]*/: { n:"BrtEOF" },
16946
	/*::[*/0x0194/*::]*/: { n:"BrtUCR" },
16947
	/*::[*/0x0195/*::]*/: { n:"BrtRRInsDel" },
16948
	/*::[*/0x0196/*::]*/: { n:"BrtRREndInsDel" },
16949
	/*::[*/0x0197/*::]*/: { n:"BrtRRMove" },
16950
	/*::[*/0x0198/*::]*/: { n:"BrtRREndMove" },
16951
	/*::[*/0x0199/*::]*/: { n:"BrtRRChgCell" },
16952
	/*::[*/0x019A/*::]*/: { n:"BrtRREndChgCell" },
16953
	/*::[*/0x019B/*::]*/: { n:"BrtRRHeader" },
16954
	/*::[*/0x019C/*::]*/: { n:"BrtRRUserView" },
16955
	/*::[*/0x019D/*::]*/: { n:"BrtRRRenSheet" },
16956
	/*::[*/0x019E/*::]*/: { n:"BrtRRInsertSh" },
16957
	/*::[*/0x019F/*::]*/: { n:"BrtRRDefName" },
16958
	/*::[*/0x01A0/*::]*/: { n:"BrtRRNote" },
16959
	/*::[*/0x01A1/*::]*/: { n:"BrtRRConflict" },
16960
	/*::[*/0x01A2/*::]*/: { n:"BrtRRTQSIF" },
16961
	/*::[*/0x01A3/*::]*/: { n:"BrtRRFormat" },
16962
	/*::[*/0x01A4/*::]*/: { n:"BrtRREndFormat" },
16963
	/*::[*/0x01A5/*::]*/: { n:"BrtRRAutoFmt" },
16964
	/*::[*/0x01A6/*::]*/: { n:"BrtBeginUserShViews" },
16965
	/*::[*/0x01A7/*::]*/: { n:"BrtBeginUserShView" },
16966
	/*::[*/0x01A8/*::]*/: { n:"BrtEndUserShView" },
16967
	/*::[*/0x01A9/*::]*/: { n:"BrtEndUserShViews" },
16968
	/*::[*/0x01AA/*::]*/: { n:"BrtArrFmla", f:parse_BrtArrFmla },
16969
	/*::[*/0x01AB/*::]*/: { n:"BrtShrFmla", f:parse_BrtShrFmla },
16970
	/*::[*/0x01AC/*::]*/: { n:"BrtTable" },
16971
	/*::[*/0x01AD/*::]*/: { n:"BrtBeginExtConnections" },
16972
	/*::[*/0x01AE/*::]*/: { n:"BrtEndExtConnections" },
16973
	/*::[*/0x01AF/*::]*/: { n:"BrtBeginPCDCalcMems" },
16974
	/*::[*/0x01B0/*::]*/: { n:"BrtEndPCDCalcMems" },
16975
	/*::[*/0x01B1/*::]*/: { n:"BrtBeginPCDCalcMem" },
16976
	/*::[*/0x01B2/*::]*/: { n:"BrtEndPCDCalcMem" },
16977
	/*::[*/0x01B3/*::]*/: { n:"BrtBeginPCDHGLevels" },
16978
	/*::[*/0x01B4/*::]*/: { n:"BrtEndPCDHGLevels" },
16979
	/*::[*/0x01B5/*::]*/: { n:"BrtBeginPCDHGLevel" },
16980
	/*::[*/0x01B6/*::]*/: { n:"BrtEndPCDHGLevel" },
16981
	/*::[*/0x01B7/*::]*/: { n:"BrtBeginPCDHGLGroups" },
16982
	/*::[*/0x01B8/*::]*/: { n:"BrtEndPCDHGLGroups" },
16983
	/*::[*/0x01B9/*::]*/: { n:"BrtBeginPCDHGLGroup" },
16984
	/*::[*/0x01BA/*::]*/: { n:"BrtEndPCDHGLGroup" },
16985
	/*::[*/0x01BB/*::]*/: { n:"BrtBeginPCDHGLGMembers" },
16986
	/*::[*/0x01BC/*::]*/: { n:"BrtEndPCDHGLGMembers" },
16987
	/*::[*/0x01BD/*::]*/: { n:"BrtBeginPCDHGLGMember" },
16988
	/*::[*/0x01BE/*::]*/: { n:"BrtEndPCDHGLGMember" },
16989
	/*::[*/0x01BF/*::]*/: { n:"BrtBeginQSI" },
16990
	/*::[*/0x01C0/*::]*/: { n:"BrtEndQSI" },
16991
	/*::[*/0x01C1/*::]*/: { n:"BrtBeginQSIR" },
16992
	/*::[*/0x01C2/*::]*/: { n:"BrtEndQSIR" },
16993
	/*::[*/0x01C3/*::]*/: { n:"BrtBeginDeletedNames" },
16994
	/*::[*/0x01C4/*::]*/: { n:"BrtEndDeletedNames" },
16995
	/*::[*/0x01C5/*::]*/: { n:"BrtBeginDeletedName" },
16996
	/*::[*/0x01C6/*::]*/: { n:"BrtEndDeletedName" },
16997
	/*::[*/0x01C7/*::]*/: { n:"BrtBeginQSIFs" },
16998
	/*::[*/0x01C8/*::]*/: { n:"BrtEndQSIFs" },
16999
	/*::[*/0x01C9/*::]*/: { n:"BrtBeginQSIF" },
17000
	/*::[*/0x01CA/*::]*/: { n:"BrtEndQSIF" },
17001
	/*::[*/0x01CB/*::]*/: { n:"BrtBeginAutoSortScope" },
17002
	/*::[*/0x01CC/*::]*/: { n:"BrtEndAutoSortScope" },
17003
	/*::[*/0x01CD/*::]*/: { n:"BrtBeginConditionalFormatting" },
17004
	/*::[*/0x01CE/*::]*/: { n:"BrtEndConditionalFormatting" },
17005
	/*::[*/0x01CF/*::]*/: { n:"BrtBeginCFRule" },
17006
	/*::[*/0x01D0/*::]*/: { n:"BrtEndCFRule" },
17007
	/*::[*/0x01D1/*::]*/: { n:"BrtBeginIconSet" },
17008
	/*::[*/0x01D2/*::]*/: { n:"BrtEndIconSet" },
17009
	/*::[*/0x01D3/*::]*/: { n:"BrtBeginDatabar" },
17010
	/*::[*/0x01D4/*::]*/: { n:"BrtEndDatabar" },
17011
	/*::[*/0x01D5/*::]*/: { n:"BrtBeginColorScale" },
17012
	/*::[*/0x01D6/*::]*/: { n:"BrtEndColorScale" },
17013
	/*::[*/0x01D7/*::]*/: { n:"BrtCFVO" },
17014
	/*::[*/0x01D8/*::]*/: { n:"BrtExternValueMeta" },
17015
	/*::[*/0x01D9/*::]*/: { n:"BrtBeginColorPalette" },
17016
	/*::[*/0x01DA/*::]*/: { n:"BrtEndColorPalette" },
17017
	/*::[*/0x01DB/*::]*/: { n:"BrtIndexedColor" },
17018
	/*::[*/0x01DC/*::]*/: { n:"BrtMargins", f:parse_BrtMargins },
17019
	/*::[*/0x01DD/*::]*/: { n:"BrtPrintOptions" },
17020
	/*::[*/0x01DE/*::]*/: { n:"BrtPageSetup" },
17021
	/*::[*/0x01DF/*::]*/: { n:"BrtBeginHeaderFooter" },
17022
	/*::[*/0x01E0/*::]*/: { n:"BrtEndHeaderFooter" },
17023
	/*::[*/0x01E1/*::]*/: { n:"BrtBeginSXCrtFormat" },
17024
	/*::[*/0x01E2/*::]*/: { n:"BrtEndSXCrtFormat" },
17025
	/*::[*/0x01E3/*::]*/: { n:"BrtBeginSXCrtFormats" },
17026
	/*::[*/0x01E4/*::]*/: { n:"BrtEndSXCrtFormats" },
17027
	/*::[*/0x01E5/*::]*/: { n:"BrtWsFmtInfo", f:parse_BrtWsFmtInfo },
17028
	/*::[*/0x01E6/*::]*/: { n:"BrtBeginMgs" },
17029
	/*::[*/0x01E7/*::]*/: { n:"BrtEndMGs" },
17030
	/*::[*/0x01E8/*::]*/: { n:"BrtBeginMGMaps" },
17031
	/*::[*/0x01E9/*::]*/: { n:"BrtEndMGMaps" },
17032
	/*::[*/0x01EA/*::]*/: { n:"BrtBeginMG" },
17033
	/*::[*/0x01EB/*::]*/: { n:"BrtEndMG" },
17034
	/*::[*/0x01EC/*::]*/: { n:"BrtBeginMap" },
17035
	/*::[*/0x01ED/*::]*/: { n:"BrtEndMap" },
17036
	/*::[*/0x01EE/*::]*/: { n:"BrtHLink", f:parse_BrtHLink },
17037
	/*::[*/0x01EF/*::]*/: { n:"BrtBeginDCon" },
17038
	/*::[*/0x01F0/*::]*/: { n:"BrtEndDCon" },
17039
	/*::[*/0x01F1/*::]*/: { n:"BrtBeginDRefs" },
17040
	/*::[*/0x01F2/*::]*/: { n:"BrtEndDRefs" },
17041
	/*::[*/0x01F3/*::]*/: { n:"BrtDRef" },
17042
	/*::[*/0x01F4/*::]*/: { n:"BrtBeginScenMan" },
17043
	/*::[*/0x01F5/*::]*/: { n:"BrtEndScenMan" },
17044
	/*::[*/0x01F6/*::]*/: { n:"BrtBeginSct" },
17045
	/*::[*/0x01F7/*::]*/: { n:"BrtEndSct" },
17046
	/*::[*/0x01F8/*::]*/: { n:"BrtSlc" },
17047
	/*::[*/0x01F9/*::]*/: { n:"BrtBeginDXFs" },
17048
	/*::[*/0x01FA/*::]*/: { n:"BrtEndDXFs" },
17049
	/*::[*/0x01FB/*::]*/: { n:"BrtDXF" },
17050
	/*::[*/0x01FC/*::]*/: { n:"BrtBeginTableStyles" },
17051
	/*::[*/0x01FD/*::]*/: { n:"BrtEndTableStyles" },
17052
	/*::[*/0x01FE/*::]*/: { n:"BrtBeginTableStyle" },
17053
	/*::[*/0x01FF/*::]*/: { n:"BrtEndTableStyle" },
17054
	/*::[*/0x0200/*::]*/: { n:"BrtTableStyleElement" },
17055
	/*::[*/0x0201/*::]*/: { n:"BrtTableStyleClient" },
17056
	/*::[*/0x0202/*::]*/: { n:"BrtBeginVolDeps" },
17057
	/*::[*/0x0203/*::]*/: { n:"BrtEndVolDeps" },
17058
	/*::[*/0x0204/*::]*/: { n:"BrtBeginVolType" },
17059
	/*::[*/0x0205/*::]*/: { n:"BrtEndVolType" },
17060
	/*::[*/0x0206/*::]*/: { n:"BrtBeginVolMain" },
17061
	/*::[*/0x0207/*::]*/: { n:"BrtEndVolMain" },
17062
	/*::[*/0x0208/*::]*/: { n:"BrtBeginVolTopic" },
17063
	/*::[*/0x0209/*::]*/: { n:"BrtEndVolTopic" },
17064
	/*::[*/0x020A/*::]*/: { n:"BrtVolSubtopic" },
17065
	/*::[*/0x020B/*::]*/: { n:"BrtVolRef" },
17066
	/*::[*/0x020C/*::]*/: { n:"BrtVolNum" },
17067
	/*::[*/0x020D/*::]*/: { n:"BrtVolErr" },
17068
	/*::[*/0x020E/*::]*/: { n:"BrtVolStr" },
17069
	/*::[*/0x020F/*::]*/: { n:"BrtVolBool" },
17070
	/*::[*/0x0210/*::]*/: { n:"BrtBeginCalcChain$" },
17071
	/*::[*/0x0211/*::]*/: { n:"BrtEndCalcChain$" },
17072
	/*::[*/0x0212/*::]*/: { n:"BrtBeginSortState" },
17073
	/*::[*/0x0213/*::]*/: { n:"BrtEndSortState" },
17074
	/*::[*/0x0214/*::]*/: { n:"BrtBeginSortCond" },
17075
	/*::[*/0x0215/*::]*/: { n:"BrtEndSortCond" },
17076
	/*::[*/0x0216/*::]*/: { n:"BrtBookProtection" },
17077
	/*::[*/0x0217/*::]*/: { n:"BrtSheetProtection" },
17078
	/*::[*/0x0218/*::]*/: { n:"BrtRangeProtection" },
17079
	/*::[*/0x0219/*::]*/: { n:"BrtPhoneticInfo" },
17080
	/*::[*/0x021A/*::]*/: { n:"BrtBeginECTxtWiz" },
17081
	/*::[*/0x021B/*::]*/: { n:"BrtEndECTxtWiz" },
17082
	/*::[*/0x021C/*::]*/: { n:"BrtBeginECTWFldInfoLst" },
17083
	/*::[*/0x021D/*::]*/: { n:"BrtEndECTWFldInfoLst" },
17084
	/*::[*/0x021E/*::]*/: { n:"BrtBeginECTwFldInfo" },
17085
	/*::[*/0x0224/*::]*/: { n:"BrtFileSharing" },
17086
	/*::[*/0x0225/*::]*/: { n:"BrtOleSize" },
17087
	/*::[*/0x0226/*::]*/: { n:"BrtDrawing", f:parse_RelID },
17088
	/*::[*/0x0227/*::]*/: { n:"BrtLegacyDrawing" },
17089
	/*::[*/0x0228/*::]*/: { n:"BrtLegacyDrawingHF" },
17090
	/*::[*/0x0229/*::]*/: { n:"BrtWebOpt" },
17091
	/*::[*/0x022A/*::]*/: { n:"BrtBeginWebPubItems" },
17092
	/*::[*/0x022B/*::]*/: { n:"BrtEndWebPubItems" },
17093
	/*::[*/0x022C/*::]*/: { n:"BrtBeginWebPubItem" },
17094
	/*::[*/0x022D/*::]*/: { n:"BrtEndWebPubItem" },
17095
	/*::[*/0x022E/*::]*/: { n:"BrtBeginSXCondFmt" },
17096
	/*::[*/0x022F/*::]*/: { n:"BrtEndSXCondFmt" },
17097
	/*::[*/0x0230/*::]*/: { n:"BrtBeginSXCondFmts" },
17098
	/*::[*/0x0231/*::]*/: { n:"BrtEndSXCondFmts" },
17099
	/*::[*/0x0232/*::]*/: { n:"BrtBkHim" },
17100
	/*::[*/0x0234/*::]*/: { n:"BrtColor" },
17101
	/*::[*/0x0235/*::]*/: { n:"BrtBeginIndexedColors" },
17102
	/*::[*/0x0236/*::]*/: { n:"BrtEndIndexedColors" },
17103
	/*::[*/0x0239/*::]*/: { n:"BrtBeginMRUColors" },
17104
	/*::[*/0x023A/*::]*/: { n:"BrtEndMRUColors" },
17105
	/*::[*/0x023C/*::]*/: { n:"BrtMRUColor" },
17106
	/*::[*/0x023D/*::]*/: { n:"BrtBeginDVals" },
17107
	/*::[*/0x023E/*::]*/: { n:"BrtEndDVals" },
17108
	/*::[*/0x0241/*::]*/: { n:"BrtSupNameStart" },
17109
	/*::[*/0x0242/*::]*/: { n:"BrtSupNameValueStart" },
17110
	/*::[*/0x0243/*::]*/: { n:"BrtSupNameValueEnd" },
17111
	/*::[*/0x0244/*::]*/: { n:"BrtSupNameNum" },
17112
	/*::[*/0x0245/*::]*/: { n:"BrtSupNameErr" },
17113
	/*::[*/0x0246/*::]*/: { n:"BrtSupNameSt" },
17114
	/*::[*/0x0247/*::]*/: { n:"BrtSupNameNil" },
17115
	/*::[*/0x0248/*::]*/: { n:"BrtSupNameBool" },
17116
	/*::[*/0x0249/*::]*/: { n:"BrtSupNameFmla" },
17117
	/*::[*/0x024A/*::]*/: { n:"BrtSupNameBits" },
17118
	/*::[*/0x024B/*::]*/: { n:"BrtSupNameEnd" },
17119
	/*::[*/0x024C/*::]*/: { n:"BrtEndSupBook" },
17120
	/*::[*/0x024D/*::]*/: { n:"BrtCellSmartTagProperty" },
17121
	/*::[*/0x024E/*::]*/: { n:"BrtBeginCellSmartTag" },
17122
	/*::[*/0x024F/*::]*/: { n:"BrtEndCellSmartTag" },
17123
	/*::[*/0x0250/*::]*/: { n:"BrtBeginCellSmartTags" },
17124
	/*::[*/0x0251/*::]*/: { n:"BrtEndCellSmartTags" },
17125
	/*::[*/0x0252/*::]*/: { n:"BrtBeginSmartTags" },
17126
	/*::[*/0x0253/*::]*/: { n:"BrtEndSmartTags" },
17127
	/*::[*/0x0254/*::]*/: { n:"BrtSmartTagType" },
17128
	/*::[*/0x0255/*::]*/: { n:"BrtBeginSmartTagTypes" },
17129
	/*::[*/0x0256/*::]*/: { n:"BrtEndSmartTagTypes" },
17130
	/*::[*/0x0257/*::]*/: { n:"BrtBeginSXFilters" },
17131
	/*::[*/0x0258/*::]*/: { n:"BrtEndSXFilters" },
17132
	/*::[*/0x0259/*::]*/: { n:"BrtBeginSXFILTER" },
17133
	/*::[*/0x025A/*::]*/: { n:"BrtEndSXFilter" },
17134
	/*::[*/0x025B/*::]*/: { n:"BrtBeginFills" },
17135
	/*::[*/0x025C/*::]*/: { n:"BrtEndFills" },
17136
	/*::[*/0x025D/*::]*/: { n:"BrtBeginCellWatches" },
17137
	/*::[*/0x025E/*::]*/: { n:"BrtEndCellWatches" },
17138
	/*::[*/0x025F/*::]*/: { n:"BrtCellWatch" },
17139
	/*::[*/0x0260/*::]*/: { n:"BrtBeginCRErrs" },
17140
	/*::[*/0x0261/*::]*/: { n:"BrtEndCRErrs" },
17141
	/*::[*/0x0262/*::]*/: { n:"BrtCrashRecErr" },
17142
	/*::[*/0x0263/*::]*/: { n:"BrtBeginFonts" },
17143
	/*::[*/0x0264/*::]*/: { n:"BrtEndFonts" },
17144
	/*::[*/0x0265/*::]*/: { n:"BrtBeginBorders" },
17145
	/*::[*/0x0266/*::]*/: { n:"BrtEndBorders" },
17146
	/*::[*/0x0267/*::]*/: { n:"BrtBeginFmts" },
17147
	/*::[*/0x0268/*::]*/: { n:"BrtEndFmts" },
17148
	/*::[*/0x0269/*::]*/: { n:"BrtBeginCellXFs" },
17149
	/*::[*/0x026A/*::]*/: { n:"BrtEndCellXFs" },
17150
	/*::[*/0x026B/*::]*/: { n:"BrtBeginStyles" },
17151
	/*::[*/0x026C/*::]*/: { n:"BrtEndStyles" },
17152
	/*::[*/0x0271/*::]*/: { n:"BrtBigName" },
17153
	/*::[*/0x0272/*::]*/: { n:"BrtBeginCellStyleXFs" },
17154
	/*::[*/0x0273/*::]*/: { n:"BrtEndCellStyleXFs" },
17155
	/*::[*/0x0274/*::]*/: { n:"BrtBeginComments" },
17156
	/*::[*/0x0275/*::]*/: { n:"BrtEndComments" },
17157
	/*::[*/0x0276/*::]*/: { n:"BrtBeginCommentAuthors" },
17158
	/*::[*/0x0277/*::]*/: { n:"BrtEndCommentAuthors" },
17159
	/*::[*/0x0278/*::]*/: { n:"BrtCommentAuthor", f:parse_BrtCommentAuthor },
17160
	/*::[*/0x0279/*::]*/: { n:"BrtBeginCommentList" },
17161
	/*::[*/0x027A/*::]*/: { n:"BrtEndCommentList" },
17162
	/*::[*/0x027B/*::]*/: { n:"BrtBeginComment", f:parse_BrtBeginComment},
17163
	/*::[*/0x027C/*::]*/: { n:"BrtEndComment" },
17164
	/*::[*/0x027D/*::]*/: { n:"BrtCommentText", f:parse_BrtCommentText },
17165
	/*::[*/0x027E/*::]*/: { n:"BrtBeginOleObjects" },
17166
	/*::[*/0x027F/*::]*/: { n:"BrtOleObject" },
17167
	/*::[*/0x0280/*::]*/: { n:"BrtEndOleObjects" },
17168
	/*::[*/0x0281/*::]*/: { n:"BrtBeginSxrules" },
17169
	/*::[*/0x0282/*::]*/: { n:"BrtEndSxRules" },
17170
	/*::[*/0x0283/*::]*/: { n:"BrtBeginActiveXControls" },
17171
	/*::[*/0x0284/*::]*/: { n:"BrtActiveX" },
17172
	/*::[*/0x0285/*::]*/: { n:"BrtEndActiveXControls" },
17173
	/*::[*/0x0286/*::]*/: { n:"BrtBeginPCDSDTCEMembersSortBy" },
17174
	/*::[*/0x0288/*::]*/: { n:"BrtBeginCellIgnoreECs" },
17175
	/*::[*/0x0289/*::]*/: { n:"BrtCellIgnoreEC" },
17176
	/*::[*/0x028A/*::]*/: { n:"BrtEndCellIgnoreECs" },
17177
	/*::[*/0x028B/*::]*/: { n:"BrtCsProp", f:parse_BrtCsProp },
17178
	/*::[*/0x028C/*::]*/: { n:"BrtCsPageSetup" },
17179
	/*::[*/0x028D/*::]*/: { n:"BrtBeginUserCsViews" },
17180
	/*::[*/0x028E/*::]*/: { n:"BrtEndUserCsViews" },
17181
	/*::[*/0x028F/*::]*/: { n:"BrtBeginUserCsView" },
17182
	/*::[*/0x0290/*::]*/: { n:"BrtEndUserCsView" },
17183
	/*::[*/0x0291/*::]*/: { n:"BrtBeginPcdSFCIEntries" },
17184
	/*::[*/0x0292/*::]*/: { n:"BrtEndPCDSFCIEntries" },
17185
	/*::[*/0x0293/*::]*/: { n:"BrtPCDSFCIEntry" },
17186
	/*::[*/0x0294/*::]*/: { n:"BrtBeginListParts" },
17187
	/*::[*/0x0295/*::]*/: { n:"BrtListPart" },
17188
	/*::[*/0x0296/*::]*/: { n:"BrtEndListParts" },
17189
	/*::[*/0x0297/*::]*/: { n:"BrtSheetCalcProp" },
17190
	/*::[*/0x0298/*::]*/: { n:"BrtBeginFnGroup" },
17191
	/*::[*/0x0299/*::]*/: { n:"BrtFnGroup" },
17192
	/*::[*/0x029A/*::]*/: { n:"BrtEndFnGroup" },
17193
	/*::[*/0x029B/*::]*/: { n:"BrtSupAddin" },
17194
	/*::[*/0x029C/*::]*/: { n:"BrtSXTDMPOrder" },
17195
	/*::[*/0x029D/*::]*/: { n:"BrtCsProtection" },
17196
	/*::[*/0x029F/*::]*/: { n:"BrtBeginWsSortMap" },
17197
	/*::[*/0x02A0/*::]*/: { n:"BrtEndWsSortMap" },
17198
	/*::[*/0x02A1/*::]*/: { n:"BrtBeginRRSort" },
17199
	/*::[*/0x02A2/*::]*/: { n:"BrtEndRRSort" },
17200
	/*::[*/0x02A3/*::]*/: { n:"BrtRRSortItem" },
17201
	/*::[*/0x02A4/*::]*/: { n:"BrtFileSharingIso" },
17202
	/*::[*/0x02A5/*::]*/: { n:"BrtBookProtectionIso" },
17203
	/*::[*/0x02A6/*::]*/: { n:"BrtSheetProtectionIso" },
17204
	/*::[*/0x02A7/*::]*/: { n:"BrtCsProtectionIso" },
17205
	/*::[*/0x02A8/*::]*/: { n:"BrtRangeProtectionIso" },
17206
	/*::[*/0x0400/*::]*/: { n:"BrtRwDescent" },
17207
	/*::[*/0x0401/*::]*/: { n:"BrtKnownFonts" },
17208
	/*::[*/0x0402/*::]*/: { n:"BrtBeginSXTupleSet" },
17209
	/*::[*/0x0403/*::]*/: { n:"BrtEndSXTupleSet" },
17210
	/*::[*/0x0404/*::]*/: { n:"BrtBeginSXTupleSetHeader" },
17211
	/*::[*/0x0405/*::]*/: { n:"BrtEndSXTupleSetHeader" },
17212
	/*::[*/0x0406/*::]*/: { n:"BrtSXTupleSetHeaderItem" },
17213
	/*::[*/0x0407/*::]*/: { n:"BrtBeginSXTupleSetData" },
17214
	/*::[*/0x0408/*::]*/: { n:"BrtEndSXTupleSetData" },
17215
	/*::[*/0x0409/*::]*/: { n:"BrtBeginSXTupleSetRow" },
17216
	/*::[*/0x040A/*::]*/: { n:"BrtEndSXTupleSetRow" },
17217
	/*::[*/0x040B/*::]*/: { n:"BrtSXTupleSetRowItem" },
17218
	/*::[*/0x040C/*::]*/: { n:"BrtNameExt" },
17219
	/*::[*/0x040D/*::]*/: { n:"BrtPCDH14" },
17220
	/*::[*/0x040E/*::]*/: { n:"BrtBeginPCDCalcMem14" },
17221
	/*::[*/0x040F/*::]*/: { n:"BrtEndPCDCalcMem14" },
17222
	/*::[*/0x0410/*::]*/: { n:"BrtSXTH14" },
17223
	/*::[*/0x0411/*::]*/: { n:"BrtBeginSparklineGroup" },
17224
	/*::[*/0x0412/*::]*/: { n:"BrtEndSparklineGroup" },
17225
	/*::[*/0x0413/*::]*/: { n:"BrtSparkline" },
17226
	/*::[*/0x0414/*::]*/: { n:"BrtSXDI14" },
17227
	/*::[*/0x0415/*::]*/: { n:"BrtWsFmtInfoEx14" },
17228
	/*::[*/0x0416/*::]*/: { n:"BrtBeginConditionalFormatting14" },
17229
	/*::[*/0x0417/*::]*/: { n:"BrtEndConditionalFormatting14" },
17230
	/*::[*/0x0418/*::]*/: { n:"BrtBeginCFRule14" },
17231
	/*::[*/0x0419/*::]*/: { n:"BrtEndCFRule14" },
17232
	/*::[*/0x041A/*::]*/: { n:"BrtCFVO14" },
17233
	/*::[*/0x041B/*::]*/: { n:"BrtBeginDatabar14" },
17234
	/*::[*/0x041C/*::]*/: { n:"BrtBeginIconSet14" },
17235
	/*::[*/0x041D/*::]*/: { n:"BrtDVal14" },
17236
	/*::[*/0x041E/*::]*/: { n:"BrtBeginDVals14" },
17237
	/*::[*/0x041F/*::]*/: { n:"BrtColor14" },
17238
	/*::[*/0x0420/*::]*/: { n:"BrtBeginSparklines" },
17239
	/*::[*/0x0421/*::]*/: { n:"BrtEndSparklines" },
17240
	/*::[*/0x0422/*::]*/: { n:"BrtBeginSparklineGroups" },
17241
	/*::[*/0x0423/*::]*/: { n:"BrtEndSparklineGroups" },
17242
	/*::[*/0x0425/*::]*/: { n:"BrtSXVD14" },
17243
	/*::[*/0x0426/*::]*/: { n:"BrtBeginSXView14" },
17244
	/*::[*/0x0427/*::]*/: { n:"BrtEndSXView14" },
17245
	/*::[*/0x0428/*::]*/: { n:"BrtBeginSXView16" },
17246
	/*::[*/0x0429/*::]*/: { n:"BrtEndSXView16" },
17247
	/*::[*/0x042A/*::]*/: { n:"BrtBeginPCD14" },
17248
	/*::[*/0x042B/*::]*/: { n:"BrtEndPCD14" },
17249
	/*::[*/0x042C/*::]*/: { n:"BrtBeginExtConn14" },
17250
	/*::[*/0x042D/*::]*/: { n:"BrtEndExtConn14" },
17251
	/*::[*/0x042E/*::]*/: { n:"BrtBeginSlicerCacheIDs" },
17252
	/*::[*/0x042F/*::]*/: { n:"BrtEndSlicerCacheIDs" },
17253
	/*::[*/0x0430/*::]*/: { n:"BrtBeginSlicerCacheID" },
17254
	/*::[*/0x0431/*::]*/: { n:"BrtEndSlicerCacheID" },
17255
	/*::[*/0x0433/*::]*/: { n:"BrtBeginSlicerCache" },
17256
	/*::[*/0x0434/*::]*/: { n:"BrtEndSlicerCache" },
17257
	/*::[*/0x0435/*::]*/: { n:"BrtBeginSlicerCacheDef" },
17258
	/*::[*/0x0436/*::]*/: { n:"BrtEndSlicerCacheDef" },
17259
	/*::[*/0x0437/*::]*/: { n:"BrtBeginSlicersEx" },
17260
	/*::[*/0x0438/*::]*/: { n:"BrtEndSlicersEx" },
17261
	/*::[*/0x0439/*::]*/: { n:"BrtBeginSlicerEx" },
17262
	/*::[*/0x043A/*::]*/: { n:"BrtEndSlicerEx" },
17263
	/*::[*/0x043B/*::]*/: { n:"BrtBeginSlicer" },
17264
	/*::[*/0x043C/*::]*/: { n:"BrtEndSlicer" },
17265
	/*::[*/0x043D/*::]*/: { n:"BrtSlicerCachePivotTables" },
17266
	/*::[*/0x043E/*::]*/: { n:"BrtBeginSlicerCacheOlapImpl" },
17267
	/*::[*/0x043F/*::]*/: { n:"BrtEndSlicerCacheOlapImpl" },
17268
	/*::[*/0x0440/*::]*/: { n:"BrtBeginSlicerCacheLevelsData" },
17269
	/*::[*/0x0441/*::]*/: { n:"BrtEndSlicerCacheLevelsData" },
17270
	/*::[*/0x0442/*::]*/: { n:"BrtBeginSlicerCacheLevelData" },
17271
	/*::[*/0x0443/*::]*/: { n:"BrtEndSlicerCacheLevelData" },
17272
	/*::[*/0x0444/*::]*/: { n:"BrtBeginSlicerCacheSiRanges" },
17273
	/*::[*/0x0445/*::]*/: { n:"BrtEndSlicerCacheSiRanges" },
17274
	/*::[*/0x0446/*::]*/: { n:"BrtBeginSlicerCacheSiRange" },
17275
	/*::[*/0x0447/*::]*/: { n:"BrtEndSlicerCacheSiRange" },
17276
	/*::[*/0x0448/*::]*/: { n:"BrtSlicerCacheOlapItem" },
17277
	/*::[*/0x0449/*::]*/: { n:"BrtBeginSlicerCacheSelections" },
17278
	/*::[*/0x044A/*::]*/: { n:"BrtSlicerCacheSelection" },
17279
	/*::[*/0x044B/*::]*/: { n:"BrtEndSlicerCacheSelections" },
17280
	/*::[*/0x044C/*::]*/: { n:"BrtBeginSlicerCacheNative" },
17281
	/*::[*/0x044D/*::]*/: { n:"BrtEndSlicerCacheNative" },
17282
	/*::[*/0x044E/*::]*/: { n:"BrtSlicerCacheNativeItem" },
17283
	/*::[*/0x044F/*::]*/: { n:"BrtRangeProtection14" },
17284
	/*::[*/0x0450/*::]*/: { n:"BrtRangeProtectionIso14" },
17285
	/*::[*/0x0451/*::]*/: { n:"BrtCellIgnoreEC14" },
17286
	/*::[*/0x0457/*::]*/: { n:"BrtList14" },
17287
	/*::[*/0x0458/*::]*/: { n:"BrtCFIcon" },
17288
	/*::[*/0x0459/*::]*/: { n:"BrtBeginSlicerCachesPivotCacheIDs" },
17289
	/*::[*/0x045A/*::]*/: { n:"BrtEndSlicerCachesPivotCacheIDs" },
17290
	/*::[*/0x045B/*::]*/: { n:"BrtBeginSlicers" },
17291
	/*::[*/0x045C/*::]*/: { n:"BrtEndSlicers" },
17292
	/*::[*/0x045D/*::]*/: { n:"BrtWbProp14" },
17293
	/*::[*/0x045E/*::]*/: { n:"BrtBeginSXEdit" },
17294
	/*::[*/0x045F/*::]*/: { n:"BrtEndSXEdit" },
17295
	/*::[*/0x0460/*::]*/: { n:"BrtBeginSXEdits" },
17296
	/*::[*/0x0461/*::]*/: { n:"BrtEndSXEdits" },
17297
	/*::[*/0x0462/*::]*/: { n:"BrtBeginSXChange" },
17298
	/*::[*/0x0463/*::]*/: { n:"BrtEndSXChange" },
17299
	/*::[*/0x0464/*::]*/: { n:"BrtBeginSXChanges" },
17300
	/*::[*/0x0465/*::]*/: { n:"BrtEndSXChanges" },
17301
	/*::[*/0x0466/*::]*/: { n:"BrtSXTupleItems" },
17302
	/*::[*/0x0468/*::]*/: { n:"BrtBeginSlicerStyle" },
17303
	/*::[*/0x0469/*::]*/: { n:"BrtEndSlicerStyle" },
17304
	/*::[*/0x046A/*::]*/: { n:"BrtSlicerStyleElement" },
17305
	/*::[*/0x046B/*::]*/: { n:"BrtBeginStyleSheetExt14" },
17306
	/*::[*/0x046C/*::]*/: { n:"BrtEndStyleSheetExt14" },
17307
	/*::[*/0x046D/*::]*/: { n:"BrtBeginSlicerCachesPivotCacheID" },
17308
	/*::[*/0x046E/*::]*/: { n:"BrtEndSlicerCachesPivotCacheID" },
17309
	/*::[*/0x046F/*::]*/: { n:"BrtBeginConditionalFormattings" },
17310
	/*::[*/0x0470/*::]*/: { n:"BrtEndConditionalFormattings" },
17311
	/*::[*/0x0471/*::]*/: { n:"BrtBeginPCDCalcMemExt" },
17312
	/*::[*/0x0472/*::]*/: { n:"BrtEndPCDCalcMemExt" },
17313
	/*::[*/0x0473/*::]*/: { n:"BrtBeginPCDCalcMemsExt" },
17314
	/*::[*/0x0474/*::]*/: { n:"BrtEndPCDCalcMemsExt" },
17315
	/*::[*/0x0475/*::]*/: { n:"BrtPCDField14" },
17316
	/*::[*/0x0476/*::]*/: { n:"BrtBeginSlicerStyles" },
17317
	/*::[*/0x0477/*::]*/: { n:"BrtEndSlicerStyles" },
17318
	/*::[*/0x0478/*::]*/: { n:"BrtBeginSlicerStyleElements" },
17319
	/*::[*/0x0479/*::]*/: { n:"BrtEndSlicerStyleElements" },
17320
	/*::[*/0x047A/*::]*/: { n:"BrtCFRuleExt" },
17321
	/*::[*/0x047B/*::]*/: { n:"BrtBeginSXCondFmt14" },
17322
	/*::[*/0x047C/*::]*/: { n:"BrtEndSXCondFmt14" },
17323
	/*::[*/0x047D/*::]*/: { n:"BrtBeginSXCondFmts14" },
17324
	/*::[*/0x047E/*::]*/: { n:"BrtEndSXCondFmts14" },
17325
	/*::[*/0x0480/*::]*/: { n:"BrtBeginSortCond14" },
17326
	/*::[*/0x0481/*::]*/: { n:"BrtEndSortCond14" },
17327
	/*::[*/0x0482/*::]*/: { n:"BrtEndDVals14" },
17328
	/*::[*/0x0483/*::]*/: { n:"BrtEndIconSet14" },
17329
	/*::[*/0x0484/*::]*/: { n:"BrtEndDatabar14" },
17330
	/*::[*/0x0485/*::]*/: { n:"BrtBeginColorScale14" },
17331
	/*::[*/0x0486/*::]*/: { n:"BrtEndColorScale14" },
17332
	/*::[*/0x0487/*::]*/: { n:"BrtBeginSxrules14" },
17333
	/*::[*/0x0488/*::]*/: { n:"BrtEndSxrules14" },
17334
	/*::[*/0x0489/*::]*/: { n:"BrtBeginPRule14" },
17335
	/*::[*/0x048A/*::]*/: { n:"BrtEndPRule14" },
17336
	/*::[*/0x048B/*::]*/: { n:"BrtBeginPRFilters14" },
17337
	/*::[*/0x048C/*::]*/: { n:"BrtEndPRFilters14" },
17338
	/*::[*/0x048D/*::]*/: { n:"BrtBeginPRFilter14" },
17339
	/*::[*/0x048E/*::]*/: { n:"BrtEndPRFilter14" },
17340
	/*::[*/0x048F/*::]*/: { n:"BrtBeginPRFItem14" },
17341
	/*::[*/0x0490/*::]*/: { n:"BrtEndPRFItem14" },
17342
	/*::[*/0x0491/*::]*/: { n:"BrtBeginCellIgnoreECs14" },
17343
	/*::[*/0x0492/*::]*/: { n:"BrtEndCellIgnoreECs14" },
17344
	/*::[*/0x0493/*::]*/: { n:"BrtDxf14" },
17345
	/*::[*/0x0494/*::]*/: { n:"BrtBeginDxF14s" },
17346
	/*::[*/0x0495/*::]*/: { n:"BrtEndDxf14s" },
17347
	/*::[*/0x0499/*::]*/: { n:"BrtFilter14" },
17348
	/*::[*/0x049A/*::]*/: { n:"BrtBeginCustomFilters14" },
17349
	/*::[*/0x049C/*::]*/: { n:"BrtCustomFilter14" },
17350
	/*::[*/0x049D/*::]*/: { n:"BrtIconFilter14" },
17351
	/*::[*/0x049E/*::]*/: { n:"BrtPivotCacheConnectionName" },
17352
	/*::[*/0x0800/*::]*/: { n:"BrtBeginDecoupledPivotCacheIDs" },
17353
	/*::[*/0x0801/*::]*/: { n:"BrtEndDecoupledPivotCacheIDs" },
17354
	/*::[*/0x0802/*::]*/: { n:"BrtDecoupledPivotCacheID" },
17355
	/*::[*/0x0803/*::]*/: { n:"BrtBeginPivotTableRefs" },
17356
	/*::[*/0x0804/*::]*/: { n:"BrtEndPivotTableRefs" },
17357
	/*::[*/0x0805/*::]*/: { n:"BrtPivotTableRef" },
17358
	/*::[*/0x0806/*::]*/: { n:"BrtSlicerCacheBookPivotTables" },
17359
	/*::[*/0x0807/*::]*/: { n:"BrtBeginSxvcells" },
17360
	/*::[*/0x0808/*::]*/: { n:"BrtEndSxvcells" },
17361
	/*::[*/0x0809/*::]*/: { n:"BrtBeginSxRow" },
17362
	/*::[*/0x080A/*::]*/: { n:"BrtEndSxRow" },
17363
	/*::[*/0x080C/*::]*/: { n:"BrtPcdCalcMem15" },
17364
	/*::[*/0x0813/*::]*/: { n:"BrtQsi15" },
17365
	/*::[*/0x0814/*::]*/: { n:"BrtBeginWebExtensions" },
17366
	/*::[*/0x0815/*::]*/: { n:"BrtEndWebExtensions" },
17367
	/*::[*/0x0816/*::]*/: { n:"BrtWebExtension" },
17368
	/*::[*/0x0817/*::]*/: { n:"BrtAbsPath15" },
17369
	/*::[*/0x0818/*::]*/: { n:"BrtBeginPivotTableUISettings" },
17370
	/*::[*/0x0819/*::]*/: { n:"BrtEndPivotTableUISettings" },
17371
	/*::[*/0x081B/*::]*/: { n:"BrtTableSlicerCacheIDs" },
17372
	/*::[*/0x081C/*::]*/: { n:"BrtTableSlicerCacheID" },
17373
	/*::[*/0x081D/*::]*/: { n:"BrtBeginTableSlicerCache" },
17374
	/*::[*/0x081E/*::]*/: { n:"BrtEndTableSlicerCache" },
17375
	/*::[*/0x081F/*::]*/: { n:"BrtSxFilter15" },
17376
	/*::[*/0x0820/*::]*/: { n:"BrtBeginTimelineCachePivotCacheIDs" },
17377
	/*::[*/0x0821/*::]*/: { n:"BrtEndTimelineCachePivotCacheIDs" },
17378
	/*::[*/0x0822/*::]*/: { n:"BrtTimelineCachePivotCacheID" },
17379
	/*::[*/0x0823/*::]*/: { n:"BrtBeginTimelineCacheIDs" },
17380
	/*::[*/0x0824/*::]*/: { n:"BrtEndTimelineCacheIDs" },
17381
	/*::[*/0x0825/*::]*/: { n:"BrtBeginTimelineCacheID" },
17382
	/*::[*/0x0826/*::]*/: { n:"BrtEndTimelineCacheID" },
17383
	/*::[*/0x0827/*::]*/: { n:"BrtBeginTimelinesEx" },
17384
	/*::[*/0x0828/*::]*/: { n:"BrtEndTimelinesEx" },
17385
	/*::[*/0x0829/*::]*/: { n:"BrtBeginTimelineEx" },
17386
	/*::[*/0x082A/*::]*/: { n:"BrtEndTimelineEx" },
17387
	/*::[*/0x082B/*::]*/: { n:"BrtWorkBookPr15" },
17388
	/*::[*/0x082C/*::]*/: { n:"BrtPCDH15" },
17389
	/*::[*/0x082D/*::]*/: { n:"BrtBeginTimelineStyle" },
17390
	/*::[*/0x082E/*::]*/: { n:"BrtEndTimelineStyle" },
17391
	/*::[*/0x082F/*::]*/: { n:"BrtTimelineStyleElement" },
17392
	/*::[*/0x0830/*::]*/: { n:"BrtBeginTimelineStylesheetExt15" },
17393
	/*::[*/0x0831/*::]*/: { n:"BrtEndTimelineStylesheetExt15" },
17394
	/*::[*/0x0832/*::]*/: { n:"BrtBeginTimelineStyles" },
17395
	/*::[*/0x0833/*::]*/: { n:"BrtEndTimelineStyles" },
17396
	/*::[*/0x0834/*::]*/: { n:"BrtBeginTimelineStyleElements" },
17397
	/*::[*/0x0835/*::]*/: { n:"BrtEndTimelineStyleElements" },
17398
	/*::[*/0x0836/*::]*/: { n:"BrtDxf15" },
17399
	/*::[*/0x0837/*::]*/: { n:"BrtBeginDxfs15" },
17400
	/*::[*/0x0838/*::]*/: { n:"brtEndDxfs15" },
17401
	/*::[*/0x0839/*::]*/: { n:"BrtSlicerCacheHideItemsWithNoData" },
17402
	/*::[*/0x083A/*::]*/: { n:"BrtBeginItemUniqueNames" },
17403
	/*::[*/0x083B/*::]*/: { n:"BrtEndItemUniqueNames" },
17404
	/*::[*/0x083C/*::]*/: { n:"BrtItemUniqueName" },
17405
	/*::[*/0x083D/*::]*/: { n:"BrtBeginExtConn15" },
17406
	/*::[*/0x083E/*::]*/: { n:"BrtEndExtConn15" },
17407
	/*::[*/0x083F/*::]*/: { n:"BrtBeginOledbPr15" },
17408
	/*::[*/0x0840/*::]*/: { n:"BrtEndOledbPr15" },
17409
	/*::[*/0x0841/*::]*/: { n:"BrtBeginDataFeedPr15" },
17410
	/*::[*/0x0842/*::]*/: { n:"BrtEndDataFeedPr15" },
17411
	/*::[*/0x0843/*::]*/: { n:"BrtTextPr15" },
17412
	/*::[*/0x0844/*::]*/: { n:"BrtRangePr15" },
17413
	/*::[*/0x0845/*::]*/: { n:"BrtDbCommand15" },
17414
	/*::[*/0x0846/*::]*/: { n:"BrtBeginDbTables15" },
17415
	/*::[*/0x0847/*::]*/: { n:"BrtEndDbTables15" },
17416
	/*::[*/0x0848/*::]*/: { n:"BrtDbTable15" },
17417
	/*::[*/0x0849/*::]*/: { n:"BrtBeginDataModel" },
17418
	/*::[*/0x084A/*::]*/: { n:"BrtEndDataModel" },
17419
	/*::[*/0x084B/*::]*/: { n:"BrtBeginModelTables" },
17420
	/*::[*/0x084C/*::]*/: { n:"BrtEndModelTables" },
17421
	/*::[*/0x084D/*::]*/: { n:"BrtModelTable" },
17422
	/*::[*/0x084E/*::]*/: { n:"BrtBeginModelRelationships" },
17423
	/*::[*/0x084F/*::]*/: { n:"BrtEndModelRelationships" },
17424
	/*::[*/0x0850/*::]*/: { n:"BrtModelRelationship" },
17425
	/*::[*/0x0851/*::]*/: { n:"BrtBeginECTxtWiz15" },
17426
	/*::[*/0x0852/*::]*/: { n:"BrtEndECTxtWiz15" },
17427
	/*::[*/0x0853/*::]*/: { n:"BrtBeginECTWFldInfoLst15" },
17428
	/*::[*/0x0854/*::]*/: { n:"BrtEndECTWFldInfoLst15" },
17429
	/*::[*/0x0855/*::]*/: { n:"BrtBeginECTWFldInfo15" },
17430
	/*::[*/0x0856/*::]*/: { n:"BrtFieldListActiveItem" },
17431
	/*::[*/0x0857/*::]*/: { n:"BrtPivotCacheIdVersion" },
17432
	/*::[*/0x0858/*::]*/: { n:"BrtSXDI15" },
17433
	/*::[*/0x0859/*::]*/: { n:"BrtBeginModelTimeGroupings" },
17434
	/*::[*/0x085A/*::]*/: { n:"BrtEndModelTimeGroupings" },
17435
	/*::[*/0x085B/*::]*/: { n:"BrtBeginModelTimeGrouping" },
17436
	/*::[*/0x085C/*::]*/: { n:"BrtEndModelTimeGrouping" },
17437
	/*::[*/0x085D/*::]*/: { n:"BrtModelTimeGroupingCalcCol" },
17438
	/*::[*/0x0C00/*::]*/: { n:"BrtUid" },
17439
	/*::[*/0x0C01/*::]*/: { n:"BrtRevisionPtr" },
17440
	/*::[*/0xFFFF/*::]*/: { n:"" }
17441
};
17442
17443
var XLSBRE = evert_key(XLSBRecordEnum, 'n');
17444
17445
/* [MS-XLS] 2.3 Record Enumeration */
17446
var XLSRecordEnum = {
17447
	/*::[*/0x0003/*::]*/: { n:"BIFF2NUM", f:parse_BIFF2NUM },
17448
	/*::[*/0x0004/*::]*/: { n:"BIFF2STR", f:parse_BIFF2STR },
17449
	/*::[*/0x0006/*::]*/: { n:"Formula", f:parse_Formula },
17450
	/*::[*/0x0009/*::]*/: { n:'BOF', f:parse_BOF },
17451
	/*::[*/0x000a/*::]*/: { n:'EOF', f:parsenoop2 },
17452
	/*::[*/0x000c/*::]*/: { n:"CalcCount", f:parseuint16 },
17453
	/*::[*/0x000d/*::]*/: { n:"CalcMode", f:parseuint16 },
17454
	/*::[*/0x000e/*::]*/: { n:"CalcPrecision", f:parsebool },
17455
	/*::[*/0x000f/*::]*/: { n:"CalcRefMode", f:parsebool },
17456
	/*::[*/0x0010/*::]*/: { n:"CalcDelta", f:parse_Xnum },
17457
	/*::[*/0x0011/*::]*/: { n:"CalcIter", f:parsebool },
17458
	/*::[*/0x0012/*::]*/: { n:"Protect", f:parsebool },
17459
	/*::[*/0x0013/*::]*/: { n:"Password", f:parseuint16 },
17460
	/*::[*/0x0014/*::]*/: { n:"Header", f:parse_XLHeaderFooter },
17461
	/*::[*/0x0015/*::]*/: { n:"Footer", f:parse_XLHeaderFooter },
17462
	/*::[*/0x0017/*::]*/: { n:"ExternSheet", f:parse_ExternSheet },
17463
	/*::[*/0x0018/*::]*/: { n:"Lbl", f:parse_Lbl },
17464
	/*::[*/0x0019/*::]*/: { n:"WinProtect", f:parsebool },
17465
	/*::[*/0x001a/*::]*/: { n:"VerticalPageBreaks" },
17466
	/*::[*/0x001b/*::]*/: { n:"HorizontalPageBreaks" },
17467
	/*::[*/0x001c/*::]*/: { n:"Note", f:parse_Note },
17468
	/*::[*/0x001d/*::]*/: { n:"Selection" },
17469
	/*::[*/0x0022/*::]*/: { n:"Date1904", f:parsebool },
17470
	/*::[*/0x0023/*::]*/: { n:"ExternName", f:parse_ExternName },
17471
	/*::[*/0x0026/*::]*/: { n:"LeftMargin", f:parse_Xnum },
17472
	/*::[*/0x0027/*::]*/: { n:"RightMargin", f:parse_Xnum },
17473
	/*::[*/0x0028/*::]*/: { n:"TopMargin", f:parse_Xnum },
17474
	/*::[*/0x0029/*::]*/: { n:"BottomMargin", f:parse_Xnum },
17475
	/*::[*/0x002a/*::]*/: { n:"PrintRowCol", f:parsebool },
17476
	/*::[*/0x002b/*::]*/: { n:"PrintGrid", f:parsebool },
17477
	/*::[*/0x002f/*::]*/: { n:"FilePass", f:parse_FilePass },
17478
	/*::[*/0x0031/*::]*/: { n:"Font", f:parse_Font },
17479
	/*::[*/0x0033/*::]*/: { n:"PrintSize", f:parseuint16 },
17480
	/*::[*/0x003c/*::]*/: { n:"Continue" },
17481
	/*::[*/0x003d/*::]*/: { n:"Window1", f:parse_Window1 },
17482
	/*::[*/0x0040/*::]*/: { n:"Backup", f:parsebool },
17483
	/*::[*/0x0041/*::]*/: { n:"Pane" },
17484
	/*::[*/0x0042/*::]*/: { n:'CodePage', f:parseuint16 },
17485
	/*::[*/0x004d/*::]*/: { n:"Pls" },
17486
	/*::[*/0x0050/*::]*/: { n:"DCon" },
17487
	/*::[*/0x0051/*::]*/: { n:"DConRef" },
17488
	/*::[*/0x0052/*::]*/: { n:"DConName" },
17489
	/*::[*/0x0055/*::]*/: { n:"DefColWidth", f:parseuint16 },
17490
	/*::[*/0x0059/*::]*/: { n:"XCT" },
17491
	/*::[*/0x005a/*::]*/: { n:"CRN" },
17492
	/*::[*/0x005b/*::]*/: { n:"FileSharing" },
17493
	/*::[*/0x005c/*::]*/: { n:'WriteAccess', f:parse_WriteAccess },
17494
	/*::[*/0x005d/*::]*/: { n:"Obj", f:parse_Obj },
17495
	/*::[*/0x005e/*::]*/: { n:"Uncalced" },
17496
	/*::[*/0x005f/*::]*/: { n:"CalcSaveRecalc", f:parsebool },
17497
	/*::[*/0x0060/*::]*/: { n:"Template" },
17498
	/*::[*/0x0061/*::]*/: { n:"Intl" },
17499
	/*::[*/0x0063/*::]*/: { n:"ObjProtect", f:parsebool },
17500
	/*::[*/0x007d/*::]*/: { n:"ColInfo", f:parse_ColInfo },
17501
	/*::[*/0x0080/*::]*/: { n:"Guts", f:parse_Guts },
17502
	/*::[*/0x0081/*::]*/: { n:"WsBool", f:parse_WsBool },
17503
	/*::[*/0x0082/*::]*/: { n:"GridSet", f:parseuint16 },
17504
	/*::[*/0x0083/*::]*/: { n:"HCenter", f:parsebool },
17505
	/*::[*/0x0084/*::]*/: { n:"VCenter", f:parsebool },
17506
	/*::[*/0x0085/*::]*/: { n:'BoundSheet8', f:parse_BoundSheet8 },
17507
	/*::[*/0x0086/*::]*/: { n:"WriteProtect" },
17508
	/*::[*/0x008c/*::]*/: { n:"Country", f:parse_Country },
17509
	/*::[*/0x008d/*::]*/: { n:"HideObj", f:parseuint16 },
17510
	/*::[*/0x0090/*::]*/: { n:"Sort" },
17511
	/*::[*/0x0092/*::]*/: { n:"Palette", f:parse_Palette },
17512
	/*::[*/0x0097/*::]*/: { n:"Sync" },
17513
	/*::[*/0x0098/*::]*/: { n:"LPr" },
17514
	/*::[*/0x0099/*::]*/: { n:"DxGCol" },
17515
	/*::[*/0x009a/*::]*/: { n:"FnGroupName" },
17516
	/*::[*/0x009b/*::]*/: { n:"FilterMode" },
17517
	/*::[*/0x009c/*::]*/: { n:"BuiltInFnGroupCount", f:parseuint16 },
17518
	/*::[*/0x009d/*::]*/: { n:"AutoFilterInfo" },
17519
	/*::[*/0x009e/*::]*/: { n:"AutoFilter" },
17520
	/*::[*/0x00a0/*::]*/: { n:"Scl", f:parse_Scl },
17521
	/*::[*/0x00a1/*::]*/: { n:"Setup", f:parse_Setup },
17522
	/*::[*/0x00ae/*::]*/: { n:"ScenMan" },
17523
	/*::[*/0x00af/*::]*/: { n:"SCENARIO" },
17524
	/*::[*/0x00b0/*::]*/: { n:"SxView" },
17525
	/*::[*/0x00b1/*::]*/: { n:"Sxvd" },
17526
	/*::[*/0x00b2/*::]*/: { n:"SXVI" },
17527
	/*::[*/0x00b4/*::]*/: { n:"SxIvd" },
17528
	/*::[*/0x00b5/*::]*/: { n:"SXLI" },
17529
	/*::[*/0x00b6/*::]*/: { n:"SXPI" },
17530
	/*::[*/0x00b8/*::]*/: { n:"DocRoute" },
17531
	/*::[*/0x00b9/*::]*/: { n:"RecipName" },
17532
	/*::[*/0x00bd/*::]*/: { n:"MulRk", f:parse_MulRk },
17533
	/*::[*/0x00be/*::]*/: { n:"MulBlank", f:parse_MulBlank },
17534
	/*::[*/0x00c1/*::]*/: { n:'Mms', f:parsenoop2 },
17535
	/*::[*/0x00c5/*::]*/: { n:"SXDI" },
17536
	/*::[*/0x00c6/*::]*/: { n:"SXDB" },
17537
	/*::[*/0x00c7/*::]*/: { n:"SXFDB" },
17538
	/*::[*/0x00c8/*::]*/: { n:"SXDBB" },
17539
	/*::[*/0x00c9/*::]*/: { n:"SXNum" },
17540
	/*::[*/0x00ca/*::]*/: { n:"SxBool", f:parsebool },
17541
	/*::[*/0x00cb/*::]*/: { n:"SxErr" },
17542
	/*::[*/0x00cc/*::]*/: { n:"SXInt" },
17543
	/*::[*/0x00cd/*::]*/: { n:"SXString" },
17544
	/*::[*/0x00ce/*::]*/: { n:"SXDtr" },
17545
	/*::[*/0x00cf/*::]*/: { n:"SxNil" },
17546
	/*::[*/0x00d0/*::]*/: { n:"SXTbl" },
17547
	/*::[*/0x00d1/*::]*/: { n:"SXTBRGIITM" },
17548
	/*::[*/0x00d2/*::]*/: { n:"SxTbpg" },
17549
	/*::[*/0x00d3/*::]*/: { n:"ObProj" },
17550
	/*::[*/0x00d5/*::]*/: { n:"SXStreamID" },
17551
	/*::[*/0x00d7/*::]*/: { n:"DBCell" },
17552
	/*::[*/0x00d8/*::]*/: { n:"SXRng" },
17553
	/*::[*/0x00d9/*::]*/: { n:"SxIsxoper" },
17554
	/*::[*/0x00da/*::]*/: { n:"BookBool", f:parseuint16 },
17555
	/*::[*/0x00dc/*::]*/: { n:"DbOrParamQry" },
17556
	/*::[*/0x00dd/*::]*/: { n:"ScenarioProtect", f:parsebool },
17557
	/*::[*/0x00de/*::]*/: { n:"OleObjectSize" },
17558
	/*::[*/0x00e0/*::]*/: { n:"XF", f:parse_XF },
17559
	/*::[*/0x00e1/*::]*/: { n:'InterfaceHdr', f:parse_InterfaceHdr },
17560
	/*::[*/0x00e2/*::]*/: { n:'InterfaceEnd', f:parsenoop2 },
17561
	/*::[*/0x00e3/*::]*/: { n:"SXVS" },
17562
	/*::[*/0x00e5/*::]*/: { n:"MergeCells", f:parse_MergeCells },
17563
	/*::[*/0x00e9/*::]*/: { n:"BkHim" },
17564
	/*::[*/0x00eb/*::]*/: { n:"MsoDrawingGroup" },
17565
	/*::[*/0x00ec/*::]*/: { n:"MsoDrawing" },
17566
	/*::[*/0x00ed/*::]*/: { n:"MsoDrawingSelection" },
17567
	/*::[*/0x00ef/*::]*/: { n:"PhoneticInfo" },
17568
	/*::[*/0x00f0/*::]*/: { n:"SxRule" },
17569
	/*::[*/0x00f1/*::]*/: { n:"SXEx" },
17570
	/*::[*/0x00f2/*::]*/: { n:"SxFilt" },
17571
	/*::[*/0x00f4/*::]*/: { n:"SxDXF" },
17572
	/*::[*/0x00f5/*::]*/: { n:"SxItm" },
17573
	/*::[*/0x00f6/*::]*/: { n:"SxName" },
17574
	/*::[*/0x00f7/*::]*/: { n:"SxSelect" },
17575
	/*::[*/0x00f8/*::]*/: { n:"SXPair" },
17576
	/*::[*/0x00f9/*::]*/: { n:"SxFmla" },
17577
	/*::[*/0x00fb/*::]*/: { n:"SxFormat" },
17578
	/*::[*/0x00fc/*::]*/: { n:"SST", f:parse_SST },
17579
	/*::[*/0x00fd/*::]*/: { n:"LabelSst", f:parse_LabelSst },
17580
	/*::[*/0x00ff/*::]*/: { n:"ExtSST", f:parse_ExtSST },
17581
	/*::[*/0x0100/*::]*/: { n:"SXVDEx" },
17582
	/*::[*/0x0103/*::]*/: { n:"SXFormula" },
17583
	/*::[*/0x0122/*::]*/: { n:"SXDBEx" },
17584
	/*::[*/0x0137/*::]*/: { n:"RRDInsDel" },
17585
	/*::[*/0x0138/*::]*/: { n:"RRDHead" },
17586
	/*::[*/0x013b/*::]*/: { n:"RRDChgCell" },
17587
	/*::[*/0x013d/*::]*/: { n:"RRTabId", f:parseuint16a },
17588
	/*::[*/0x013e/*::]*/: { n:"RRDRenSheet" },
17589
	/*::[*/0x013f/*::]*/: { n:"RRSort" },
17590
	/*::[*/0x0140/*::]*/: { n:"RRDMove" },
17591
	/*::[*/0x014a/*::]*/: { n:"RRFormat" },
17592
	/*::[*/0x014b/*::]*/: { n:"RRAutoFmt" },
17593
	/*::[*/0x014d/*::]*/: { n:"RRInsertSh" },
17594
	/*::[*/0x014e/*::]*/: { n:"RRDMoveBegin" },
17595
	/*::[*/0x014f/*::]*/: { n:"RRDMoveEnd" },
17596
	/*::[*/0x0150/*::]*/: { n:"RRDInsDelBegin" },
17597
	/*::[*/0x0151/*::]*/: { n:"RRDInsDelEnd" },
17598
	/*::[*/0x0152/*::]*/: { n:"RRDConflict" },
17599
	/*::[*/0x0153/*::]*/: { n:"RRDDefName" },
17600
	/*::[*/0x0154/*::]*/: { n:"RRDRstEtxp" },
17601
	/*::[*/0x015f/*::]*/: { n:"LRng" },
17602
	/*::[*/0x0160/*::]*/: { n:"UsesELFs", f:parsebool },
17603
	/*::[*/0x0161/*::]*/: { n:"DSF", f:parsenoop2 },
17604
	/*::[*/0x0191/*::]*/: { n:"CUsr" },
17605
	/*::[*/0x0192/*::]*/: { n:"CbUsr" },
17606
	/*::[*/0x0193/*::]*/: { n:"UsrInfo" },
17607
	/*::[*/0x0194/*::]*/: { n:"UsrExcl" },
17608
	/*::[*/0x0195/*::]*/: { n:"FileLock" },
17609
	/*::[*/0x0196/*::]*/: { n:"RRDInfo" },
17610
	/*::[*/0x0197/*::]*/: { n:"BCUsrs" },
17611
	/*::[*/0x0198/*::]*/: { n:"UsrChk" },
17612
	/*::[*/0x01a9/*::]*/: { n:"UserBView" },
17613
	/*::[*/0x01aa/*::]*/: { n:"UserSViewBegin" },
17614
	/*::[*/0x01ab/*::]*/: { n:"UserSViewEnd" },
17615
	/*::[*/0x01ac/*::]*/: { n:"RRDUserView" },
17616
	/*::[*/0x01ad/*::]*/: { n:"Qsi" },
17617
	/*::[*/0x01ae/*::]*/: { n:"SupBook", f:parse_SupBook },
17618
	/*::[*/0x01af/*::]*/: { n:"Prot4Rev", f:parsebool },
17619
	/*::[*/0x01b0/*::]*/: { n:"CondFmt" },
17620
	/*::[*/0x01b1/*::]*/: { n:"CF" },
17621
	/*::[*/0x01b2/*::]*/: { n:"DVal" },
17622
	/*::[*/0x01b5/*::]*/: { n:"DConBin" },
17623
	/*::[*/0x01b6/*::]*/: { n:"TxO", f:parse_TxO },
17624
	/*::[*/0x01b7/*::]*/: { n:"RefreshAll", f:parsebool },
17625
	/*::[*/0x01b8/*::]*/: { n:"HLink", f:parse_HLink },
17626
	/*::[*/0x01b9/*::]*/: { n:"Lel" },
17627
	/*::[*/0x01ba/*::]*/: { n:"CodeName", f:parse_XLUnicodeString },
17628
	/*::[*/0x01bb/*::]*/: { n:"SXFDBType" },
17629
	/*::[*/0x01bc/*::]*/: { n:"Prot4RevPass", f:parseuint16 },
17630
	/*::[*/0x01bd/*::]*/: { n:"ObNoMacros" },
17631
	/*::[*/0x01be/*::]*/: { n:"Dv" },
17632
	/*::[*/0x01c0/*::]*/: { n:"Excel9File", f:parsenoop2 },
17633
	/*::[*/0x01c1/*::]*/: { n:"RecalcId", f:parse_RecalcId, r:2},
17634
	/*::[*/0x01c2/*::]*/: { n:"EntExU2", f:parsenoop2 },
17635
	/*::[*/0x0200/*::]*/: { n:"Dimensions", f:parse_Dimensions },
17636
	/*::[*/0x0201/*::]*/: { n:"Blank", f:parse_Blank },
17637
	/*::[*/0x0203/*::]*/: { n:"Number", f:parse_Number },
17638
	/*::[*/0x0204/*::]*/: { n:"Label", f:parse_Label },
17639
	/*::[*/0x0205/*::]*/: { n:"BoolErr", f:parse_BoolErr },
17640
	/*::[*/0x0206/*::]*/: { n:"Formula", f:parse_Formula },
17641
	/*::[*/0x0207/*::]*/: { n:"String", f:parse_String },
17642
	/*::[*/0x0208/*::]*/: { n:'Row', f:parse_Row },
17643
	/*::[*/0x020b/*::]*/: { n:"Index" },
17644
	/*::[*/0x0221/*::]*/: { n:"Array", f:parse_Array },
17645
	/*::[*/0x0225/*::]*/: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
17646
	/*::[*/0x0236/*::]*/: { n:"Table" },
17647
	/*::[*/0x023e/*::]*/: { n:"Window2", f:parse_Window2 },
17648
	/*::[*/0x027e/*::]*/: { n:"RK", f:parse_RK },
17649
	/*::[*/0x0293/*::]*/: { n:"Style" },
17650
	/*::[*/0x0406/*::]*/: { n:"Formula", f:parse_Formula },
17651
	/*::[*/0x0418/*::]*/: { n:"BigName" },
17652
	/*::[*/0x041e/*::]*/: { n:"Format", f:parse_Format },
17653
	/*::[*/0x043c/*::]*/: { n:"ContinueBigName" },
17654
	/*::[*/0x04bc/*::]*/: { n:"ShrFmla", f:parse_ShrFmla },
17655
	/*::[*/0x0800/*::]*/: { n:"HLinkTooltip", f:parse_HLinkTooltip },
17656
	/*::[*/0x0801/*::]*/: { n:"WebPub" },
17657
	/*::[*/0x0802/*::]*/: { n:"QsiSXTag" },
17658
	/*::[*/0x0803/*::]*/: { n:"DBQueryExt" },
17659
	/*::[*/0x0804/*::]*/: { n:"ExtString" },
17660
	/*::[*/0x0805/*::]*/: { n:"TxtQry" },
17661
	/*::[*/0x0806/*::]*/: { n:"Qsir" },
17662
	/*::[*/0x0807/*::]*/: { n:"Qsif" },
17663
	/*::[*/0x0808/*::]*/: { n:"RRDTQSIF" },
17664
	/*::[*/0x0809/*::]*/: { n:'BOF', f:parse_BOF },
17665
	/*::[*/0x080a/*::]*/: { n:"OleDbConn" },
17666
	/*::[*/0x080b/*::]*/: { n:"WOpt" },
17667
	/*::[*/0x080c/*::]*/: { n:"SXViewEx" },
17668
	/*::[*/0x080d/*::]*/: { n:"SXTH" },
17669
	/*::[*/0x080e/*::]*/: { n:"SXPIEx" },
17670
	/*::[*/0x080f/*::]*/: { n:"SXVDTEx" },
17671
	/*::[*/0x0810/*::]*/: { n:"SXViewEx9" },
17672
	/*::[*/0x0812/*::]*/: { n:"ContinueFrt" },
17673
	/*::[*/0x0813/*::]*/: { n:"RealTimeData" },
17674
	/*::[*/0x0850/*::]*/: { n:"ChartFrtInfo" },
17675
	/*::[*/0x0851/*::]*/: { n:"FrtWrapper" },
17676
	/*::[*/0x0852/*::]*/: { n:"StartBlock" },
17677
	/*::[*/0x0853/*::]*/: { n:"EndBlock" },
17678
	/*::[*/0x0854/*::]*/: { n:"StartObject" },
17679
	/*::[*/0x0855/*::]*/: { n:"EndObject" },
17680
	/*::[*/0x0856/*::]*/: { n:"CatLab" },
17681
	/*::[*/0x0857/*::]*/: { n:"YMult" },
17682
	/*::[*/0x0858/*::]*/: { n:"SXViewLink" },
17683
	/*::[*/0x0859/*::]*/: { n:"PivotChartBits" },
17684
	/*::[*/0x085a/*::]*/: { n:"FrtFontList" },
17685
	/*::[*/0x0862/*::]*/: { n:"SheetExt" },
17686
	/*::[*/0x0863/*::]*/: { n:"BookExt", r:12},
17687
	/*::[*/0x0864/*::]*/: { n:"SXAddl" },
17688
	/*::[*/0x0865/*::]*/: { n:"CrErr" },
17689
	/*::[*/0x0866/*::]*/: { n:"HFPicture" },
17690
	/*::[*/0x0867/*::]*/: { n:'FeatHdr', f:parsenoop2 },
17691
	/*::[*/0x0868/*::]*/: { n:"Feat" },
17692
	/*::[*/0x086a/*::]*/: { n:"DataLabExt" },
17693
	/*::[*/0x086b/*::]*/: { n:"DataLabExtContents" },
17694
	/*::[*/0x086c/*::]*/: { n:"CellWatch" },
17695
	/*::[*/0x0871/*::]*/: { n:"FeatHdr11" },
17696
	/*::[*/0x0872/*::]*/: { n:"Feature11" },
17697
	/*::[*/0x0874/*::]*/: { n:"DropDownObjIds" },
17698
	/*::[*/0x0875/*::]*/: { n:"ContinueFrt11" },
17699
	/*::[*/0x0876/*::]*/: { n:"DConn" },
17700
	/*::[*/0x0877/*::]*/: { n:"List12" },
17701
	/*::[*/0x0878/*::]*/: { n:"Feature12" },
17702
	/*::[*/0x0879/*::]*/: { n:"CondFmt12" },
17703
	/*::[*/0x087a/*::]*/: { n:"CF12" },
17704
	/*::[*/0x087b/*::]*/: { n:"CFEx" },
17705
	/*::[*/0x087c/*::]*/: { n:"XFCRC", f:parse_XFCRC, r:12 },
17706
	/*::[*/0x087d/*::]*/: { n:"XFExt", f:parse_XFExt, r:12 },
17707
	/*::[*/0x087e/*::]*/: { n:"AutoFilter12" },
17708
	/*::[*/0x087f/*::]*/: { n:"ContinueFrt12" },
17709
	/*::[*/0x0884/*::]*/: { n:"MDTInfo" },
17710
	/*::[*/0x0885/*::]*/: { n:"MDXStr" },
17711
	/*::[*/0x0886/*::]*/: { n:"MDXTuple" },
17712
	/*::[*/0x0887/*::]*/: { n:"MDXSet" },
17713
	/*::[*/0x0888/*::]*/: { n:"MDXProp" },
17714
	/*::[*/0x0889/*::]*/: { n:"MDXKPI" },
17715
	/*::[*/0x088a/*::]*/: { n:"MDB" },
17716
	/*::[*/0x088b/*::]*/: { n:"PLV" },
17717
	/*::[*/0x088c/*::]*/: { n:"Compat12", f:parsebool, r:12 },
17718
	/*::[*/0x088d/*::]*/: { n:"DXF" },
17719
	/*::[*/0x088e/*::]*/: { n:"TableStyles", r:12 },
17720
	/*::[*/0x088f/*::]*/: { n:"TableStyle" },
17721
	/*::[*/0x0890/*::]*/: { n:"TableStyleElement" },
17722
	/*::[*/0x0892/*::]*/: { n:"StyleExt" },
17723
	/*::[*/0x0893/*::]*/: { n:"NamePublish" },
17724
	/*::[*/0x0894/*::]*/: { n:"NameCmt", f:parse_NameCmt, r:12 },
17725
	/*::[*/0x0895/*::]*/: { n:"SortData" },
17726
	/*::[*/0x0896/*::]*/: { n:"Theme", f:parse_Theme, r:12 },
17727
	/*::[*/0x0897/*::]*/: { n:"GUIDTypeLib" },
17728
	/*::[*/0x0898/*::]*/: { n:"FnGrp12" },
17729
	/*::[*/0x0899/*::]*/: { n:"NameFnGrp12" },
17730
	/*::[*/0x089a/*::]*/: { n:"MTRSettings", f:parse_MTRSettings, r:12 },
17731
	/*::[*/0x089b/*::]*/: { n:"CompressPictures", f:parsenoop2 },
17732
	/*::[*/0x089c/*::]*/: { n:"HeaderFooter" },
17733
	/*::[*/0x089d/*::]*/: { n:"CrtLayout12" },
17734
	/*::[*/0x089e/*::]*/: { n:"CrtMlFrt" },
17735
	/*::[*/0x089f/*::]*/: { n:"CrtMlFrtContinue" },
17736
	/*::[*/0x08a3/*::]*/: { n:"ForceFullCalculation", f:parse_ForceFullCalculation },
17737
	/*::[*/0x08a4/*::]*/: { n:"ShapePropsStream" },
17738
	/*::[*/0x08a5/*::]*/: { n:"TextPropsStream" },
17739
	/*::[*/0x08a6/*::]*/: { n:"RichTextStream" },
17740
	/*::[*/0x08a7/*::]*/: { n:"CrtLayout12A" },
17741
	/*::[*/0x1001/*::]*/: { n:"Units" },
17742
	/*::[*/0x1002/*::]*/: { n:"Chart" },
17743
	/*::[*/0x1003/*::]*/: { n:"Series" },
17744
	/*::[*/0x1006/*::]*/: { n:"DataFormat" },
17745
	/*::[*/0x1007/*::]*/: { n:"LineFormat" },
17746
	/*::[*/0x1009/*::]*/: { n:"MarkerFormat" },
17747
	/*::[*/0x100a/*::]*/: { n:"AreaFormat" },
17748
	/*::[*/0x100b/*::]*/: { n:"PieFormat" },
17749
	/*::[*/0x100c/*::]*/: { n:"AttachedLabel" },
17750
	/*::[*/0x100d/*::]*/: { n:"SeriesText" },
17751
	/*::[*/0x1014/*::]*/: { n:"ChartFormat" },
17752
	/*::[*/0x1015/*::]*/: { n:"Legend" },
17753
	/*::[*/0x1016/*::]*/: { n:"SeriesList" },
17754
	/*::[*/0x1017/*::]*/: { n:"Bar" },
17755
	/*::[*/0x1018/*::]*/: { n:"Line" },
17756
	/*::[*/0x1019/*::]*/: { n:"Pie" },
17757
	/*::[*/0x101a/*::]*/: { n:"Area" },
17758
	/*::[*/0x101b/*::]*/: { n:"Scatter" },
17759
	/*::[*/0x101c/*::]*/: { n:"CrtLine" },
17760
	/*::[*/0x101d/*::]*/: { n:"Axis" },
17761
	/*::[*/0x101e/*::]*/: { n:"Tick" },
17762
	/*::[*/0x101f/*::]*/: { n:"ValueRange" },
17763
	/*::[*/0x1020/*::]*/: { n:"CatSerRange" },
17764
	/*::[*/0x1021/*::]*/: { n:"AxisLine" },
17765
	/*::[*/0x1022/*::]*/: { n:"CrtLink" },
17766
	/*::[*/0x1024/*::]*/: { n:"DefaultText" },
17767
	/*::[*/0x1025/*::]*/: { n:"Text" },
17768
	/*::[*/0x1026/*::]*/: { n:"FontX", f:parseuint16 },
17769
	/*::[*/0x1027/*::]*/: { n:"ObjectLink" },
17770
	/*::[*/0x1032/*::]*/: { n:"Frame" },
17771
	/*::[*/0x1033/*::]*/: { n:"Begin" },
17772
	/*::[*/0x1034/*::]*/: { n:"End" },
17773
	/*::[*/0x1035/*::]*/: { n:"PlotArea" },
17774
	/*::[*/0x103a/*::]*/: { n:"Chart3d" },
17775
	/*::[*/0x103c/*::]*/: { n:"PicF" },
17776
	/*::[*/0x103d/*::]*/: { n:"DropBar" },
17777
	/*::[*/0x103e/*::]*/: { n:"Radar" },
17778
	/*::[*/0x103f/*::]*/: { n:"Surf" },
17779
	/*::[*/0x1040/*::]*/: { n:"RadarArea" },
17780
	/*::[*/0x1041/*::]*/: { n:"AxisParent" },
17781
	/*::[*/0x1043/*::]*/: { n:"LegendException" },
17782
	/*::[*/0x1044/*::]*/: { n:"ShtProps", f:parse_ShtProps },
17783
	/*::[*/0x1045/*::]*/: { n:"SerToCrt" },
17784
	/*::[*/0x1046/*::]*/: { n:"AxesUsed" },
17785
	/*::[*/0x1048/*::]*/: { n:"SBaseRef" },
17786
	/*::[*/0x104a/*::]*/: { n:"SerParent" },
17787
	/*::[*/0x104b/*::]*/: { n:"SerAuxTrend" },
17788
	/*::[*/0x104e/*::]*/: { n:"IFmtRecord" },
17789
	/*::[*/0x104f/*::]*/: { n:"Pos" },
17790
	/*::[*/0x1050/*::]*/: { n:"AlRuns" },
17791
	/*::[*/0x1051/*::]*/: { n:"BRAI" },
17792
	/*::[*/0x105b/*::]*/: { n:"SerAuxErrBar" },
17793
	/*::[*/0x105c/*::]*/: { n:"ClrtClient", f:parse_ClrtClient },
17794
	/*::[*/0x105d/*::]*/: { n:"SerFmt" },
17795
	/*::[*/0x105f/*::]*/: { n:"Chart3DBarShape" },
17796
	/*::[*/0x1060/*::]*/: { n:"Fbi" },
17797
	/*::[*/0x1061/*::]*/: { n:"BopPop" },
17798
	/*::[*/0x1062/*::]*/: { n:"AxcExt" },
17799
	/*::[*/0x1063/*::]*/: { n:"Dat" },
17800
	/*::[*/0x1064/*::]*/: { n:"PlotGrowth" },
17801
	/*::[*/0x1065/*::]*/: { n:"SIIndex" },
17802
	/*::[*/0x1066/*::]*/: { n:"GelFrame" },
17803
	/*::[*/0x1067/*::]*/: { n:"BopPopCustom" },
17804
	/*::[*/0x1068/*::]*/: { n:"Fbi2" },
17805
17806
	/*::[*/0x0000/*::]*/: { n:"Dimensions", f:parse_Dimensions },
17807
	/*::[*/0x0002/*::]*/: { n:"BIFF2INT", f:parse_BIFF2INT },
17808
	/*::[*/0x0005/*::]*/: { n:"BoolErr", f:parse_BoolErr },
17809
	/*::[*/0x0007/*::]*/: { n:"String", f:parse_BIFF2STRING },
17810
	/*::[*/0x0008/*::]*/: { n:"BIFF2ROW" },
17811
	/*::[*/0x000b/*::]*/: { n:"Index" },
17812
	/*::[*/0x0016/*::]*/: { n:"ExternCount", f:parseuint16 },
17813
	/*::[*/0x001e/*::]*/: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
17814
	/*::[*/0x001f/*::]*/: { n:"BIFF2FMTCNT" }, /* 16-bit cnt of BIFF2FORMAT records */
17815
	/*::[*/0x0020/*::]*/: { n:"BIFF2COLINFO" },
17816
	/*::[*/0x0021/*::]*/: { n:"Array", f:parse_Array },
17817
	/*::[*/0x0025/*::]*/: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
17818
	/*::[*/0x0032/*::]*/: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
17819
	/*::[*/0x0034/*::]*/: { n:"DDEObjName" },
17820
	/*::[*/0x003e/*::]*/: { n:"BIFF2WINDOW2" },
17821
	/*::[*/0x0043/*::]*/: { n:"BIFF2XF" },
17822
	/*::[*/0x0045/*::]*/: { n:"BIFF2FONTCLR" },
17823
	/*::[*/0x0056/*::]*/: { n:"BIFF4FMTCNT" }, /* 16-bit cnt, similar to BIFF2 */
17824
	/*::[*/0x007e/*::]*/: { n:"RK" }, /* Not necessarily same as 0x027e */
17825
	/*::[*/0x007f/*::]*/: { n:"ImData", f:parse_ImData },
17826
	/*::[*/0x0087/*::]*/: { n:"Addin" },
17827
	/*::[*/0x0088/*::]*/: { n:"Edg" },
17828
	/*::[*/0x0089/*::]*/: { n:"Pub" },
17829
	/*::[*/0x0091/*::]*/: { n:"Sub" },
17830
	/*::[*/0x0094/*::]*/: { n:"LHRecord" },
17831
	/*::[*/0x0095/*::]*/: { n:"LHNGraph" },
17832
	/*::[*/0x0096/*::]*/: { n:"Sound" },
17833
	/*::[*/0x00a9/*::]*/: { n:"CoordList" },
17834
	/*::[*/0x00ab/*::]*/: { n:"GCW" },
17835
	/*::[*/0x00bc/*::]*/: { n:"ShrFmla" }, /* Not necessarily same as 0x04bc */
17836
	/*::[*/0x00bf/*::]*/: { n:"ToolbarHdr" },
17837
	/*::[*/0x00c0/*::]*/: { n:"ToolbarEnd" },
17838
	/*::[*/0x00c2/*::]*/: { n:"AddMenu" },
17839
	/*::[*/0x00c3/*::]*/: { n:"DelMenu" },
17840
	/*::[*/0x00d6/*::]*/: { n:"RString", f:parse_RString },
17841
	/*::[*/0x00df/*::]*/: { n:"UDDesc" },
17842
	/*::[*/0x00ea/*::]*/: { n:"TabIdConf" },
17843
	/*::[*/0x0162/*::]*/: { n:"XL5Modify" },
17844
	/*::[*/0x01a5/*::]*/: { n:"FileSharing2" },
17845
	/*::[*/0x0209/*::]*/: { n:'BOF', f:parse_BOF },
17846
	/*::[*/0x0218/*::]*/: { n:"Lbl", f:parse_Lbl },
17847
	/*::[*/0x0223/*::]*/: { n:"ExternName", f:parse_ExternName },
17848
	/*::[*/0x0231/*::]*/: { n:"Font" },
17849
	/*::[*/0x0243/*::]*/: { n:"BIFF3XF" },
17850
	/*::[*/0x0409/*::]*/: { n:'BOF', f:parse_BOF },
17851
	/*::[*/0x0443/*::]*/: { n:"BIFF4XF" },
17852
	/*::[*/0x086d/*::]*/: { n:"FeatInfo" },
17853
	/*::[*/0x0873/*::]*/: { n:"FeatInfo11" },
17854
	/*::[*/0x0881/*::]*/: { n:"SXAddl12" },
17855
	/*::[*/0x08c0/*::]*/: { n:"AutoWebPub" },
17856
	/*::[*/0x08c1/*::]*/: { n:"ListObj" },
17857
	/*::[*/0x08c2/*::]*/: { n:"ListField" },
17858
	/*::[*/0x08c3/*::]*/: { n:"ListDV" },
17859
	/*::[*/0x08c4/*::]*/: { n:"ListCondFmt" },
17860
	/*::[*/0x08c5/*::]*/: { n:"ListCF" },
17861
	/*::[*/0x08c6/*::]*/: { n:"FMQry" },
17862
	/*::[*/0x08c7/*::]*/: { n:"FMSQry" },
17863
	/*::[*/0x08c8/*::]*/: { n:"PLV" },
17864
	/*::[*/0x08c9/*::]*/: { n:"LnExt" },
17865
	/*::[*/0x08ca/*::]*/: { n:"MkrExt" },
17866
	/*::[*/0x08cb/*::]*/: { n:"CrtCoopt" },
17867
	/*::[*/0x08d6/*::]*/: { n:"FRTArchId$", r:12 },
17868
17869
	/*::[*/0x7262/*::]*/: {}
17870
};
17871
17872
var XLSRE = evert_key(XLSRecordEnum, 'n');
17873
function write_biff_rec(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/)/*:void*/ {
17874
	var t/*:number*/ = +type || +XLSRE[/*::String(*/type/*::)*/];
17875
	if(isNaN(t)) return;
17876
	var len = length || (payload||[]).length || 0;
17877
	var o = ba.next(4);
17878
	o.write_shift(2, t);
17879
	o.write_shift(2, len);
17880
	if(/*:: len != null &&*/len > 0 && is_buf(payload)) ba.push(payload);
17881
}
17882
17883
function write_BIFF2Cell(out, r/*:number*/, c/*:number*/) {
17884
	if(!out) out = new_buf(7);
17885
	out.write_shift(2, r);
17886
	out.write_shift(2, c);
17887
	out.write_shift(2, 0);
17888
	out.write_shift(1, 0);
17889
	return out;
17890
}
17891
17892
function write_BIFF2BERR(r/*:number*/, c/*:number*/, val, t/*:?string*/) {
17893
	var out = new_buf(9);
17894
	write_BIFF2Cell(out, r, c);
17895
	if(t == 'e') { out.write_shift(1, val); out.write_shift(1, 1); }
17896
	else { out.write_shift(1, val?1:0); out.write_shift(1, 0); }
17897
	return out;
17898
}
17899
17900
/* TODO: codepage, large strings */
17901
function write_BIFF2LABEL(r/*:number*/, c/*:number*/, val) {
17902
	var out = new_buf(8 + 2*val.length);
17903
	write_BIFF2Cell(out, r, c);
17904
	out.write_shift(1, val.length);
17905
	out.write_shift(val.length, val, 'sbcs');
17906
	return out.l < out.length ? out.slice(0, out.l) : out;
17907
}
17908
17909
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*//*::, opts*/) {
17910
	if(cell.v != null) switch(cell.t) {
17911
		case 'd': case 'n':
17912
			var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
17913
			if((v == (v|0)) && (v >= 0) && (v < 65536))
17914
				write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
17915
			else
17916
				write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
17917
			return;
17918
		case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
17919
		/* TODO: codepage, sst */
17920
		case 's': case 'str':
17921
			write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v));
17922
			return;
17923
	}
17924
	write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
17925
}
17926
17927
function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
17928
	var dense = Array.isArray(ws);
17929
	var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
17930
	if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
17931
		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
17932
		range.e.c = Math.min(range.e.c, 0xFF);
17933
		range.e.r = Math.min(range.e.c, 0x3FFF);
17934
		ref = encode_range(range);
17935
	}
17936
	for(var R = range.s.r; R <= range.e.r; ++R) {
17937
		rr = encode_row(R);
17938
		for(var C = range.s.c; C <= range.e.c; ++C) {
17939
			if(R === range.s.r) cols[C] = encode_col(C);
17940
			ref = cols[C] + rr;
17941
			var cell = dense ? (ws[R]||[])[C] : ws[ref];
17942
			if(!cell) continue;
17943
			/* write cell */
17944
			write_ws_biff2_cell(ba, cell, R, C, opts);
17945
		}
17946
	}
17947
}
17948
17949
/* Based on test files */
17950
function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
17951
	var o = opts || {};
17952
	if(DENSE != null && o.dense == null) o.dense = DENSE;
17953
	var ba = buf_array();
17954
	var idx = 0;
17955
	for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
17956
	if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
17957
	write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o));
17958
	/* ... */
17959
	write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
17960
	/* ... */
17961
	write_biff_rec(ba, 0x000A);
17962
	return ba.end();
17963
}
17964
17965
function write_FONTS_biff8(ba, data, opts) {
17966
	write_biff_rec(ba, "Font", write_Font({
17967
		sz:12,
17968
		color: {theme:1},
17969
		name: "Arial",
17970
		family: 2,
17971
		scheme: "minor"
17972
	}, opts));
17973
}
17974
17975
17976
function write_FMTS_biff8(ba, NF/*:?SSFTable*/, opts) {
17977
	if(!NF) return;
17978
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
17979
		/*:: if(!NF) return; */
17980
		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts));
17981
	});
17982
}
17983
17984
function write_FEAT(ba, ws) {
17985
	/* [MS-XLS] 2.4.112 */
17986
	var o = new_buf(19);
17987
	o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
17988
	o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
17989
	write_biff_rec(ba, "FeatHdr", o);
17990
	/* [MS-XLS] 2.4.111 */
17991
	o = new_buf(39);
17992
	o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0);
17993
	o.write_shift(2, 3); o.write_shift(1, 0); o.write_shift(4, 0);
17994
	o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0);
17995
	write_Ref8U(safe_decode_range(ws['!ref']||"A1"), o);
17996
	o.write_shift(4, 4);
17997
	write_biff_rec(ba, "Feat", o);
17998
}
17999
18000
function write_CELLXFS_biff8(ba, opts) {
18001
	for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts));
18002
	opts.cellXfs.forEach(function(c) {
18003
		write_biff_rec(ba, "XF", write_XF(c, 0, opts));
18004
	});
18005
}
18006
18007
function write_ws_biff8_hlinks(ba/*:BufArray*/, ws) {
18008
	for(var R=0; R<ws['!links'].length; ++R) {
18009
		var HL = ws['!links'][R];
18010
		write_biff_rec(ba, "HLink", write_HLink(HL));
18011
		if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
18012
	}
18013
	delete ws['!links'];
18014
}
18015
18016
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
18017
	var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
18018
	if(cell.v != null) switch(cell.t) {
18019
		case 'd': case 'n':
18020
			var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
18021
			/* TODO: emit RK as appropriate */
18022
			write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts));
18023
			return;
18024
		case 'b': case 'e': write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t)); return;
18025
		/* TODO: codepage, sst */
18026
		case 's': case 'str':
18027
			write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts));
18028
			return;
18029
	}
18030
	write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
18031
}
18032
18033
/* [MS-XLS] 2.1.7.20.5 */
18034
function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
18035
	var ba = buf_array();
18036
	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
18037
	var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
18038
	var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/);
18039
	var dense = Array.isArray(ws);
18040
	var b8 = opts.biff == 8;
18041
	var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
18042
	var range = safe_decode_range(ws['!ref'] || "A1");
18043
	var MAX_ROWS = b8 ? 65536 : 16384;
18044
	if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
18045
		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
18046
		range.e.c = Math.min(range.e.c, 0xFF);
18047
		range.e.r = Math.min(range.e.c, MAX_ROWS-1);
18048
	}
18049
18050
	write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
18051
	/* ... */
18052
	write_biff_rec(ba, "CalcMode", writeuint16(1));
18053
	write_biff_rec(ba, "CalcCount", writeuint16(100));
18054
	write_biff_rec(ba, "CalcRefMode", writebool(true));
18055
	write_biff_rec(ba, "CalcIter", writebool(false));
18056
	write_biff_rec(ba, "CalcDelta", write_Xnum(0.001));
18057
	write_biff_rec(ba, "CalcSaveRecalc", writebool(true));
18058
	write_biff_rec(ba, "PrintRowCol", writebool(false));
18059
	write_biff_rec(ba, "PrintGrid", writebool(false));
18060
	write_biff_rec(ba, "GridSet", writeuint16(1));
18061
	write_biff_rec(ba, "Guts", write_Guts([0,0]));
18062
	/* ... */
18063
	write_biff_rec(ba, "HCenter", writebool(false));
18064
	write_biff_rec(ba, "VCenter", writebool(false));
18065
	/* ... */
18066
	write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
18067
	/* ... */
18068
18069
	if(b8) ws['!links'] = [];
18070
	for(var R = range.s.r; R <= range.e.r; ++R) {
18071
		rr = encode_row(R);
18072
		for(var C = range.s.c; C <= range.e.c; ++C) {
18073
			if(R === range.s.r) cols[C] = encode_col(C);
18074
			ref = cols[C] + rr;
18075
			var cell = dense ? (ws[R]||[])[C] : ws[ref];
18076
			if(!cell) continue;
18077
			/* write cell */
18078
			write_ws_biff8_cell(ba, cell, R, C, opts);
18079
			if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
18080
		}
18081
	}
18082
	var cname/*:string*/ = _sheet.CodeName || _sheet.name || s;
18083
	/* ... */
18084
	if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0]));
18085
	/* ... */
18086
	if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']));
18087
	/* ... */
18088
	if(b8) write_ws_biff8_hlinks(ba, ws);
18089
	/* ... */
18090
	write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
18091
	/* ... */
18092
	if(b8) write_FEAT(ba, ws);
18093
	/* ... */
18094
	write_biff_rec(ba, "EOF");
18095
	return ba.end();
18096
}
18097
18098
/* [MS-XLS] 2.1.7.20.3 */
18099
function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
18100
	var A = buf_array();
18101
	var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
18102
	var _sheets/*:Array<WBWSProp>*/ = (_WB.Sheets||[]);
18103
	var _wb/*:WBProps*/ = /*::((*/_WB.WBProps||{/*::CodeName:"ThisWorkbook"*/}/*:: ):any)*/;
18104
	var b8 = opts.biff == 8, b5 = opts.biff == 5;
18105
	write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
18106
	if(opts.bookType == "xla") write_biff_rec(A, "Addin");
18107
	write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null);
18108
	write_biff_rec(A, "Mms", writezeroes(2));
18109
	if(b5) write_biff_rec(A, "ToolbarHdr");
18110
	if(b5) write_biff_rec(A, "ToolbarEnd");
18111
	write_biff_rec(A, "InterfaceEnd");
18112
	write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
18113
	write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4));
18114
	if(b8) write_biff_rec(A, "DSF", writeuint16(0));
18115
	if(b8) write_biff_rec(A, "Excel9File");
18116
	write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
18117
	if(b8 && wb.vbaraw) {
18118
		write_biff_rec(A, "ObProj");
18119
		var cname/*:string*/ = _wb.CodeName || "ThisWorkbook";
18120
		write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts));
18121
	}
18122
	write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11));
18123
	write_biff_rec(A, "WinProtect", writebool(false));
18124
	write_biff_rec(A, "Protect", writebool(false));
18125
	write_biff_rec(A, "Password", writeuint16(0));
18126
	if(b8) write_biff_rec(A, "Prot4Rev", writebool(false));
18127
	if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0));
18128
	write_biff_rec(A, "Window1", write_Window1(opts));
18129
	write_biff_rec(A, "Backup", writebool(false));
18130
	write_biff_rec(A, "HideObj", writeuint16(0));
18131
	write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true"));
18132
	write_biff_rec(A, "CalcPrecision", writebool(true));
18133
	if(b8) write_biff_rec(A, "RefreshAll", writebool(false));
18134
	write_biff_rec(A, "BookBool", writeuint16(0));
18135
	/* ... */
18136
	write_FONTS_biff8(A, wb, opts);
18137
	write_FMTS_biff8(A, wb.SSF, opts);
18138
	write_CELLXFS_biff8(A, opts);
18139
	/* ... */
18140
	if(b8) write_biff_rec(A, "UsesELFs", writebool(false));
18141
	var a = A.end();
18142
18143
	var C = buf_array();
18144
	if(b8) write_biff_rec(C, "Country", write_Country());
18145
	/* BIFF8: [SST *Continue] ExtSST */
18146
	write_biff_rec(C, "EOF");
18147
	var c = C.end();
18148
18149
	var B = buf_array();
18150
	var blen = 0, j = 0;
18151
	for(j = 0; j < wb.SheetNames.length; ++j) blen += (b8 ? 12 : 11) + (b8 ? 2 : 1) * wb.SheetNames[j].length;
18152
	var start = a.length + blen + c.length;
18153
	for(j = 0; j < wb.SheetNames.length; ++j) {
18154
		var _sheet/*:WBWSProp*/ = _sheets[j] || ({}/*:any*/);
18155
		write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts));
18156
		start += bufs[j].length;
18157
	}
18158
	/* 1*BoundSheet8 */
18159
	var b = B.end();
18160
	if(blen != b.length) throw new Error("BS8 " + blen + " != " + b.length);
18161
18162
	var out = [];
18163
	if(a.length) out.push(a);
18164
	if(b.length) out.push(b);
18165
	if(c.length) out.push(c);
18166
	return __toBuffer([out]);
18167
}
18168
18169
/* [MS-XLS] 2.1.7.20 Workbook Stream */
18170
function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
18171
	var o = opts || {};
18172
	var bufs = [];
18173
18174
	if(wb && !wb.SSF) {
18175
		wb.SSF = SSF.get_table();
18176
	}
18177
	if(wb && wb.SSF) {
18178
		make_ssf(SSF); SSF.load_table(wb.SSF);
18179
		// $FlowIgnore
18180
		o.revssf = evert_num(wb.SSF); o.revssf[wb.SSF[65535]] = 0;
18181
		o.ssf = wb.SSF;
18182
	}
18183
	o.cellXfs = [];
18184
	o.Strings = /*::((*/[]/*:: :any):SST)*/; o.Strings.Count = 0; o.Strings.Unique = 0;
18185
	get_cell_style(o.cellXfs, {}, {revssf:{"General":0}});
18186
18187
	for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb);
18188
	bufs.unshift(write_biff8_global(wb, bufs, o));
18189
	return __toBuffer([bufs]);
18190
}
18191
18192
function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
18193
	var o = opts || {};
18194
	switch(o.biff || 2) {
18195
		case 8: case 5: return write_biff8_buf(wb, opts);
18196
		case 4: case 3: case 2: return write_biff2_buf(wb, opts);
18197
	}
18198
	throw new Error("invalid type " + o.bookType + " for BIFF");
18199
}
18200
/* note: browser DOM element cannot see mso- style attrs, must parse */
18201
var HTML_ = (function() {
18202
	function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ {
18203
		var opts = _opts || {};
18204
		if(DENSE != null && opts.dense == null) opts.dense = DENSE;
18205
		var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
18206
		var mtch/*:any*/ = str.match(/<table/i);
18207
		if(!mtch) throw new Error("Invalid HTML: could not find <table>");
18208
		var mtch2/*:any*/ = str.match(/<\/table/i);
18209
		var i/*:number*/ = mtch.index, j/*:number*/ = mtch2 && mtch2.index || str.length;
18210
		var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
18211
		var R = -1, C = 0, RS = 0, CS = 0;
18212
		var range/*:Range*/ = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
18213
		var merges/*:Array<Range>*/ = [];
18214
		for(i = 0; i < rows.length; ++i) {
18215
			var row = rows[i].trim();
18216
			var hd = row.slice(0,3).toLowerCase();
18217
			if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
18218
			if(hd != "<td" && hd != "<th") continue;
18219
			var cells = row.split(/<\/t[dh]>/i);
18220
			for(j = 0; j < cells.length; ++j) {
18221
				var cell = cells[j].trim();
18222
				if(!cell.match(/<t[dh]/i)) continue;
18223
				var m = cell, cc = 0;
18224
				/* TODO: parse styles etc */
18225
				while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
18226
				var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
18227
				CS = tag.colspan ? +tag.colspan : 1;
18228
				if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
18229
				var _t/*:string*/ = tag.t || "";
18230
				/* TODO: generate stub cells */
18231
				if(!m.length) { C += CS; continue; }
18232
				m = htmldecode(m);
18233
				if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
18234
				if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
18235
				if(!m.length) continue;
18236
				var o/*:Cell*/ = {t:'s', v:m};
18237
				if(opts.raw || !m.trim().length || _t == 's'){}
18238
				else if(m === 'TRUE') o = {t:'b', v:true};
18239
				else if(m === 'FALSE') o = {t:'b', v:false};
18240
				else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
18241
				else if(!isNaN(fuzzydate(m).getDate())) {
18242
					o = ({t:'d', v:parseDate(m)}/*:any*/);
18243
					if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/);
18244
					o.z = opts.dateNF || SSF._table[14];
18245
				}
18246
				if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
18247
				else ws[encode_cell({r:R, c:C})] = o;
18248
				C += CS;
18249
			}
18250
		}
18251
		ws['!ref'] = encode_range(range);
18252
		return ws;
18253
	}
18254
	function html_to_book(str/*:string*/, opts)/*:Workbook*/ {
18255
		return sheet_to_workbook(html_to_sheet(str, opts), opts);
18256
	}
18257
	function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HTMLOpts*/)/*:string*/ {
18258
		var M/*:Array<Range>*/ = (ws['!merges'] ||[]);
18259
		var oo/*:Array<string>*/ = [];
18260
		for(var C = r.s.c; C <= r.e.c; ++C) {
18261
			var RS = 0, CS = 0;
18262
			for(var j = 0; j < M.length; ++j) {
18263
				if(M[j].s.r > R || M[j].s.c > C) continue;
18264
				if(M[j].e.r < R || M[j].e.c < C) continue;
18265
				if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
18266
				RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
18267
			}
18268
			if(RS < 0) continue;
18269
			var coord = encode_cell({r:R,c:C});
18270
			var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
18271
			var sp = {};
18272
			if(RS > 1) sp.rowspan = RS;
18273
			if(CS > 1) sp.colspan = CS;
18274
			/* TODO: html entities */
18275
			var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
18276
			sp.t = cell && cell.t || 'z';
18277
			if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
18278
			sp.id = "sjs-" + coord;
18279
			oo.push(writextag('td', w, sp));
18280
		}
18281
		var preamble = "<tr>";
18282
		return preamble + oo.join("") + "</tr>";
18283
	}
18284
	function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)/*:string*/ {
18285
		var out/*:Array<string>*/ = [];
18286
		return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
18287
	}
18288
	var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
18289
	var _END = '</body></html>';
18290
	function sheet_to_html(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*//*, wb:?Workbook*/)/*:string*/ {
18291
		var o = opts || {};
18292
		var header = o.header != null ? o.header : _BEGIN;
18293
		var footer = o.footer != null ? o.footer : _END;
18294
		var out/*:Array<string>*/ = [header];
18295
		var r = decode_range(ws['!ref']);
18296
		o.dense = Array.isArray(ws);
18297
		out.push(make_html_preamble(ws, r, o));
18298
		for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
18299
		out.push("</table>" + footer);
18300
		return out.join("");
18301
	}
18302
18303
	return {
18304
		to_workbook: html_to_book,
18305
		to_sheet: html_to_sheet,
18306
		_row: make_html_row,
18307
		BEGIN: _BEGIN,
18308
		END: _END,
18309
		_preamble: make_html_preamble,
18310
		from_sheet: sheet_to_html
18311
	};
18312
})();
18313
18314
function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ {
18315
	var opts = _opts || {};
18316
	if(DENSE != null) opts.dense = DENSE;
18317
	var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
18318
	var rows/*:HTMLCollection<HTMLTableRowElement>*/ = table.getElementsByTagName('tr');
18319
	var sheetRows = opts.sheetRows || 10000000;
18320
	var range/*:Range*/ = {s:{r:0,c:0},e:{r:0,c:0}};
18321
	var merges/*:Array<Range>*/ = [], midx = 0;
18322
	var rowinfo/*:Array<RowInfo>*/ = [];
18323
	var _R = 0, R = 0, _C, C, RS, CS;
18324
	for(; _R < rows.length && R < sheetRows; ++_R) {
18325
		var row/*:HTMLTableRowElement*/ = rows[_R];
18326
		if (is_dom_element_hidden(row)) {
18327
			if (opts.display) continue;
18328
			rowinfo[R] = {hidden: true};
18329
		}
18330
		var elts/*:HTMLCollection<HTMLTableCellElement>*/ = (row.children/*:any*/);
18331
		for(_C = C = 0; _C < elts.length; ++_C) {
18332
			var elt/*:HTMLTableCellElement*/ = elts[_C];
18333
			if (opts.display && is_dom_element_hidden(elt)) continue;
18334
			var v/*:string*/ = htmldecode(elt.innerHTML);
18335
			for(midx = 0; midx < merges.length; ++midx) {
18336
				var m/*:Range*/ = merges[midx];
18337
				if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
18338
			}
18339
			/* TODO: figure out how to extract nonstandard mso- style */
18340
			CS = +elt.getAttribute("colspan") || 1;
18341
			if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
18342
			var o/*:Cell*/ = {t:'s', v:v};
18343
			var _t/*:string*/ = elt.getAttribute("t") || "";
18344
			if(v != null) {
18345
				if(v.length == 0) o.t = _t || 'z';
18346
				else if(opts.raw || v.trim().length == 0 || _t == "s"){}
18347
				else if(v === 'TRUE') o = {t:'b', v:true};
18348
				else if(v === 'FALSE') o = {t:'b', v:false};
18349
				else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
18350
				else if(!isNaN(fuzzydate(v).getDate())) {
18351
					o = ({t:'d', v:parseDate(v)}/*:any*/);
18352
					if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)}/*:any*/);
18353
					o.z = opts.dateNF || SSF._table[14];
18354
				}
18355
			}
18356
			if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
18357
			else ws[encode_cell({c:C, r:R})] = o;
18358
			if(range.e.c < C) range.e.c = C;
18359
			C += CS;
18360
		}
18361
		++R;
18362
	}
18363
	if(merges.length) ws['!merges'] = merges;
18364
	if(rowinfo.length) ws['!rows'] = rowinfo;
18365
	range.e.r = R - 1;
18366
	ws['!ref'] = encode_range(range);
18367
	if(R >= sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don't to improve the performance
18368
	return ws;
18369
}
18370
18371
function table_to_book(table/*:HTMLElement*/, opts/*:?any*/)/*:Workbook*/ {
18372
	return sheet_to_workbook(parse_dom_table(table, opts), opts);
18373
}
18374
18375
function is_dom_element_hidden(element/*:HTMLElement*/)/*:boolean*/ {
18376
	var display/*:string*/ = '';
18377
	var get_computed_style/*:?function*/ = get_get_computed_style_function(element);
18378
	if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
18379
	if(!display) display = element.style.display; // Fallback for cases when getComputedStyle is not available (e.g. an old browser or some Node.js environments) or doesn't work (e.g. if the element is not inserted to a document)
18380
	return display === 'none';
18381
}
18382
18383
/* global getComputedStyle */
18384
function get_get_computed_style_function(element/*:HTMLElement*/)/*:?function*/ {
18385
	// The proper getComputedStyle implementation is the one defined in the element window
18386
	if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
18387
	// If it is not available, try to get one from the global namespace
18388
	if(typeof getComputedStyle === 'function') return getComputedStyle;
18389
	return null;
18390
}
18391
/* OpenDocument */
18392
var parse_content_xml = (function() {
18393
18394
	/* 6.1.2 White Space Characters */
18395
	var parse_text_p = function(text/*:string*//*::, tag*/)/*:string*/ {
18396
		return unescapexml(text
18397
			.replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
18398
			.replace(/<text:s\/>/g," ")
18399
			.replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
18400
			.replace(/<text:tab[^>]*\/>/g,"\t")
18401
			.replace(/<text:line-break\/>/g,"\n")
18402
			.replace(/<[^>]*>/g,"")
18403
		);
18404
	};
18405
18406
	var number_formats = {
18407
		/* ods name: [short ssf fmt, long ssf fmt] */
18408
		day:           ["d",   "dd"],
18409
		month:         ["m",   "mm"],
18410
		year:          ["y",   "yy"],
18411
		hours:         ["h",   "hh"],
18412
		minutes:       ["m",   "mm"],
18413
		seconds:       ["s",   "ss"],
18414
		"am-pm":       ["A/P", "AM/PM"],
18415
		"day-of-week": ["ddd", "dddd"],
18416
		era:           ["e",   "ee"],
18417
		/* there is no native representation of LO "Q" format */
18418
		quarter:       ["\\Qm", "m\\\"th quarter\""]
18419
	};
18420
18421
	return function pcx(d/*:string*/, _opts)/*:Workbook*/ {
18422
		var opts = _opts || {};
18423
		if(DENSE != null && opts.dense == null) opts.dense = DENSE;
18424
		var str = xlml_normalize(d);
18425
		var state/*:Array<any>*/ = [], tmp;
18426
		var tag/*:: = {}*/;
18427
		var NFtag = {name:""}, NF = "", pidx = 0;
18428
		var sheetag/*:: = {name:"", '名称':""}*/;
18429
		var rowtag/*:: = {'行号':""}*/;
18430
		var Sheets = {}, SheetNames/*:Array<string>*/ = [];
18431
		var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
18432
		var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/;
18433
		var ctag = ({value:""}/*:any*/);
18434
		var textp = "", textpidx = 0, textptag/*:: = {}*/;
18435
		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
18436
		var row_ol = 0;
18437
		var number_format_map = {};
18438
		var merges/*:Array<Range>*/ = [], mrange = {}, mR = 0, mC = 0;
18439
		var rowinfo/*:Array<RowInfo>*/ = [], rowpeat = 1, colpeat = 1;
18440
		var arrayf/*:Array<[Range, string]>*/ = [];
18441
		var WB = {Names:[]};
18442
		var atag = ({}/*:any*/);
18443
		var _Ref/*:[string, string]*/ = ["", ""];
18444
		var comments/*:Array<Comment>*/ = [], comment/*:Comment*/ = ({}/*:any*/);
18445
		var creator = "", creatoridx = 0;
18446
		var isstub = false, intable = false;
18447
		var i = 0;
18448
		xlmlregex.lastIndex = 0;
18449
		str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
18450
		while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
18451
18452
			case 'table': case '工作表': // 9.1.2 <table:table>
18453
				if(Rn[1]==='/') {
18454
					if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
18455
					if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
18456
						ws['!fullref'] = ws['!ref'];
18457
						range.e.r = opts.sheetRows - 1;
18458
						ws['!ref'] = encode_range(range);
18459
					}
18460
					if(merges.length) ws['!merges'] = merges;
18461
					if(rowinfo.length) ws["!rows"] = rowinfo;
18462
					sheetag.name = sheetag['名称'] || sheetag.name;
18463
					if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
18464
					SheetNames.push(sheetag.name);
18465
					Sheets[sheetag.name] = ws;
18466
					intable = false;
18467
				}
18468
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
18469
					sheetag = parsexmltag(Rn[0], false);
18470
					R = C = -1;
18471
					range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
18472
					ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = [];
18473
					rowinfo = [];
18474
					intable = true;
18475
				}
18476
				break;
18477
18478
			case 'table-row-group': // 9.1.9 <table:table-row-group>
18479
				if(Rn[1] === "/") --row_ol; else ++row_ol;
18480
				break;
18481
			case 'table-row': case '行': // 9.1.3 <table:table-row>
18482
				if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
18483
				rowtag = parsexmltag(Rn[0], false);
18484
				if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
18485
				rowpeat = +rowtag['number-rows-repeated'] || 1;
18486
				/* TODO: remove magic */
18487
				if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
18488
				C = -1; break;
18489
			case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
18490
				++C;
18491
				if(opts.sheetStubs) {
18492
					if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
18493
					else ws[encode_cell({r:R,c:C})] = {t:'z'};
18494
				}
18495
				break; /* stub */
18496
			case 'table-cell': case '数据':
18497
				if(Rn[0].charAt(Rn[0].length-2) === '/') {
18498
					++C;
18499
					ctag = parsexmltag(Rn[0], false);
18500
					colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
18501
					q = ({t:'z', v:null/*:: , z:null, w:"",c:[]*/}/*:any*/);
18502
					if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
18503
					if((ctag['数据类型'] || ctag['value-type']) == "string") {
18504
						q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
18505
						if(opts.dense) {
18506
							if(!ws[R]) ws[R] = [];
18507
							ws[R][C] = q;
18508
						} else {
18509
							ws[encode_cell({r:R,c:C})] = q;
18510
						}
18511
					}
18512
					C+= colpeat-1;
18513
				} else if(Rn[1]!=='/') {
18514
					++C;
18515
					colpeat = 1;
18516
					var rptR = rowpeat ? R + rowpeat - 1 : R;
18517
					if(C > range.e.c) range.e.c = C;
18518
					if(C < range.s.c) range.s.c = C;
18519
					if(R < range.s.r) range.s.r = R;
18520
					if(rptR > range.e.r) range.e.r = rptR;
18521
					ctag = parsexmltag(Rn[0], false);
18522
					comments = []; comment = ({}/*:any*/);
18523
					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:"",c:[]*/}/*:any*/);
18524
					if(opts.cellFormula) {
18525
						if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
18526
						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
18527
							mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
18528
							mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
18529
							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
18530
							q.F = encode_range(mrange);
18531
							arrayf.push([mrange, q.F]);
18532
						}
18533
						if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
18534
						else for(i = 0; i < arrayf.length; ++i)
18535
							if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
18536
								if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
18537
									q.F = arrayf[i][1];
18538
					}
18539
					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
18540
						mR = parseInt(ctag['number-rows-spanned'],10) || 0;
18541
						mC = parseInt(ctag['number-columns-spanned'],10) || 0;
18542
						mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
18543
						merges.push(mrange);
18544
					}
18545
18546
					/* 19.675.2 table:number-columns-repeated */
18547
					if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
18548
18549
					/* 19.385 office:value-type */
18550
					switch(q.t) {
18551
						case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
18552
						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
18553
						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
18554
						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
18555
						case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
18556
							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
18557
							q.z = 'm/d/yy'; break;
18558
						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
18559
						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
18560
						default:
18561
							if(q.t === 'string' || q.t === 'text' || !q.t) {
18562
								q.t = 's';
18563
								if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']);
18564
							} else throw new Error('Unsupported value type ' + q.t);
18565
					}
18566
				} else {
18567
					isstub = false;
18568
					if(q.t === 's') {
18569
						q.v = textp || '';
18570
						isstub = textpidx == 0;
18571
					}
18572
					if(atag.Target) q.l = atag;
18573
					if(comments.length > 0) { q.c = comments; comments = []; }
18574
					if(textp && opts.cellText !== false) q.w = textp;
18575
					if(!isstub || opts.sheetStubs) {
18576
						if(!(opts.sheetRows && opts.sheetRows <= R)) {
18577
							for(var rpt = 0; rpt < rowpeat; ++rpt) {
18578
								colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
18579
								if(opts.dense) {
18580
									if(!ws[R + rpt]) ws[R + rpt] = [];
18581
									ws[R + rpt][C] = rpt == 0 ? q : dup(q);
18582
									while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
18583
								} else {
18584
									ws[encode_cell({r:R + rpt,c:C})] = q;
18585
									while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
18586
								}
18587
								if(range.e.c <= C) range.e.c = C;
18588
							}
18589
						}
18590
					}
18591
					colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
18592
					C += colpeat-1; colpeat = 0;
18593
					q = {/*:: t:"", v:null, z:null, w:"",c:[]*/};
18594
					textp = "";
18595
				}
18596
				atag = ({}/*:any*/);
18597
				break; // 9.1.4 <table:table-cell>
18598
18599
			/* pure state */
18600
			case 'document': // TODO: <office:document> is the root for FODS
18601
			case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
18602
			case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
18603
			case 'scripts': // 3.12 <office:scripts>
18604
			case 'styles': // TODO <office:styles>
18605
			case 'font-face-decls': // 3.14 <office:font-face-decls>
18606
				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
18607
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
18608
				break;
18609
18610
			case 'annotation': // 14.1 <office:annotation>
18611
				if(Rn[1]==='/'){
18612
					if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
18613
					comment.t = textp;
18614
					comment.a = creator;
18615
					comments.push(comment);
18616
				}
18617
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
18618
				creator = ""; creatoridx = 0;
18619
				textp = ""; textpidx = 0;
18620
				break;
18621
18622
			case 'creator': // 4.3.2.7 <dc:creator>
18623
				if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
18624
				else creatoridx = Rn.index + Rn[0].length;
18625
				break;
18626
18627
			/* ignore state */
18628
			case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
18629
			case 'settings': // TODO: <office:settings>
18630
			case 'config-item-set': // TODO: <office:config-item-set>
18631
			case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
18632
			case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
18633
			case 'config-item-map-named': // TODO: <office:config-item-map-entry>
18634
			case 'shapes': // 9.2.8 <table:shapes>
18635
			case 'frame': // 10.4.2 <draw:frame>
18636
			case 'text-box': // 10.4.3 <draw:text-box>
18637
			case 'image': // 10.4.4 <draw:image>
18638
			case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
18639
			case 'list-style': // 16.30 <text:list-style>
18640
			case 'form': // 13.13 <form:form>
18641
			case 'dde-links': // 9.8 <table:dde-links>
18642
			case 'event-listeners': // TODO
18643
			case 'chart': // TODO
18644
				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
18645
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
18646
				textp = ""; textpidx = 0;
18647
				break;
18648
18649
			case 'scientific-number': // TODO: <number:scientific-number>
18650
				break;
18651
			case 'currency-symbol': // TODO: <number:currency-symbol>
18652
				break;
18653
			case 'currency-style': // TODO: <number:currency-style>
18654
				break;
18655
			case 'number-style': // 16.27.2 <number:number-style>
18656
			case 'percentage-style': // 16.27.9 <number:percentage-style>
18657
			case 'date-style': // 16.27.10 <number:date-style>
18658
			case 'time-style': // 16.27.18 <number:time-style>
18659
				if(Rn[1]==='/'){
18660
					number_format_map[NFtag.name] = NF;
18661
					if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
18662
				} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
18663
					NF = "";
18664
					NFtag = parsexmltag(Rn[0], false);
18665
					state.push([Rn[3], true]);
18666
				} break;
18667
18668
			case 'script': break; // 3.13 <office:script>
18669
			case 'libraries': break; // TODO: <ooo:libraries>
18670
			case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
18671
			case 'master-styles': break; // TODO: <office:master-styles>
18672
18673
			case 'default-style': // TODO: <style:default-style>
18674
			case 'page-layout': break; // TODO: <style:page-layout>
18675
			case 'style': break; // 16.2 <style:style>
18676
			case 'map': break; // 16.3 <style:map>
18677
			case 'font-face': break; // 16.21 <style:font-face>
18678
18679
			case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
18680
			case 'table-properties': break; // 17.15 <style:table-properties>
18681
			case 'table-column-properties': break; // 17.16 <style:table-column-properties>
18682
			case 'table-row-properties': break; // 17.17 <style:table-row-properties>
18683
			case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
18684
18685
			case 'number': // 16.27.3 <number:number>
18686
				switch(state[state.length-1][0]) {
18687
					case 'time-style':
18688
					case 'date-style':
18689
						tag = parsexmltag(Rn[0], false);
18690
						NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
18691
				} break;
18692
18693
			case 'fraction': break; // TODO 16.27.6 <number:fraction>
18694
18695
			case 'day': // 16.27.11 <number:day>
18696
			case 'month': // 16.27.12 <number:month>
18697
			case 'year': // 16.27.13 <number:year>
18698
			case 'era': // 16.27.14 <number:era>
18699
			case 'day-of-week': // 16.27.15 <number:day-of-week>
18700
			case 'week-of-year': // 16.27.16 <number:week-of-year>
18701
			case 'quarter': // 16.27.17 <number:quarter>
18702
			case 'hours': // 16.27.19 <number:hours>
18703
			case 'minutes': // 16.27.20 <number:minutes>
18704
			case 'seconds': // 16.27.21 <number:seconds>
18705
			case 'am-pm': // 16.27.22 <number:am-pm>
18706
				switch(state[state.length-1][0]) {
18707
					case 'time-style':
18708
					case 'date-style':
18709
						tag = parsexmltag(Rn[0], false);
18710
						NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
18711
				} break;
18712
18713
			case 'boolean-style': break; // 16.27.23 <number:boolean-style>
18714
			case 'boolean': break; // 16.27.24 <number:boolean>
18715
			case 'text-style': break; // 16.27.25 <number:text-style>
18716
			case 'text': // 16.27.26 <number:text>
18717
				if(Rn[0].slice(-2) === "/>") break;
18718
				else if(Rn[1]==="/") switch(state[state.length-1][0]) {
18719
					case 'number-style':
18720
					case 'date-style':
18721
					case 'time-style':
18722
						NF += str.slice(pidx, Rn.index);
18723
						break;
18724
				}
18725
				else pidx = Rn.index + Rn[0].length;
18726
				break;
18727
18728
			case 'named-range': // 9.4.12 <table:named-range>
18729
				tag = parsexmltag(Rn[0], false);
18730
				_Ref = ods_to_csf_3D(tag['cell-range-address']);
18731
				var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]}/*:any*/);
18732
				if(intable) nrange.Sheet = SheetNames.length;
18733
				WB.Names.push(nrange);
18734
				break;
18735
18736
			case 'text-content': break; // 16.27.27 <number:text-content>
18737
			case 'text-properties': break; // 16.27.27 <style:text-properties>
18738
			case 'embedded-text': break; // 16.27.4 <number:embedded-text>
18739
18740
			case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
18741
18742
			case 'forms': break; // 12.25.2 13.2
18743
			case 'table-column': break; // 9.1.6 <table:table-column>
18744
			case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
18745
			case 'table-rows': break; // 9.1.12 <table:table-rows>
18746
			/* TODO: outline levels */
18747
			case 'table-column-group': break; // 9.1.10 <table:table-column-group>
18748
			case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
18749
			case 'table-columns': break; // 9.1.12 <table:table-columns>
18750
18751
			case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
18752
18753
			case 'graphic-properties': break; // 17.21 <style:graphic-properties>
18754
			case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
18755
			case 'named-expressions': break; // 9.4.11 <table:named-expressions>
18756
			case 'label-range': break; // 9.4.9 <table:label-range>
18757
			case 'label-ranges': break; // 9.4.10 <table:label-ranges>
18758
			case 'named-expression': break; // 9.4.13 <table:named-expression>
18759
			case 'sort': break; // 9.4.19 <table:sort>
18760
			case 'sort-by': break; // 9.4.20 <table:sort-by>
18761
			case 'sort-groups': break; // 9.4.22 <table:sort-groups>
18762
18763
			case 'tab': break; // 6.1.4 <text:tab>
18764
			case 'line-break': break; // 6.1.5 <text:line-break>
18765
			case 'span': break; // 6.1.7 <text:span>
18766
			case 'p': case '文本串': // 5.1.3 <text:p>
18767
				if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) textp = (textp.length > 0 ? textp + "\n" : "") + parse_text_p(str.slice(textpidx,Rn.index), textptag);
18768
				else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
18769
				break; // <text:p>
18770
			case 's': break; // <text:s>
18771
18772
			case 'database-range': // 9.4.15 <table:database-range>
18773
				if(Rn[1]==='/') break;
18774
				try {
18775
					_Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
18776
					Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
18777
				} catch(e) {/* empty */}
18778
				break;
18779
18780
			case 'date': break; // <*:date>
18781
18782
			case 'object': break; // 10.4.6.2 <draw:object>
18783
			case 'title': case '标题': break; // <*:title> OR <uof:标题>
18784
			case 'desc': break; // <*:desc>
18785
			case 'binary-data': break; // 10.4.5 TODO: b64 blob
18786
18787
			/* 9.2 Advanced Tables */
18788
			case 'table-source': break; // 9.2.6
18789
			case 'scenario': break; // 9.2.6
18790
18791
			case 'iteration': break; // 9.4.3 <table:iteration>
18792
			case 'content-validations': break; // 9.4.4 <table:
18793
			case 'content-validation': break; // 9.4.5 <table:
18794
			case 'help-message': break; // 9.4.6 <table:
18795
			case 'error-message': break; // 9.4.7 <table:
18796
			case 'database-ranges': break; // 9.4.14 <table:database-ranges>
18797
			case 'filter': break; // 9.5.2 <table:filter>
18798
			case 'filter-and': break; // 9.5.3 <table:filter-and>
18799
			case 'filter-or': break; // 9.5.4 <table:filter-or>
18800
			case 'filter-condition': break; // 9.5.5 <table:filter-condition>
18801
18802
			case 'list-level-style-bullet': break; // 16.31 <text:
18803
			case 'list-level-style-number': break; // 16.32 <text:
18804
			case 'list-level-properties': break; // 17.19 <style:
18805
18806
			/* 7.3 Document Fields */
18807
			case 'sender-firstname': // 7.3.6.2
18808
			case 'sender-lastname': // 7.3.6.3
18809
			case 'sender-initials': // 7.3.6.4
18810
			case 'sender-title': // 7.3.6.5
18811
			case 'sender-position': // 7.3.6.6
18812
			case 'sender-email': // 7.3.6.7
18813
			case 'sender-phone-private': // 7.3.6.8
18814
			case 'sender-fax': // 7.3.6.9
18815
			case 'sender-company': // 7.3.6.10
18816
			case 'sender-phone-work': // 7.3.6.11
18817
			case 'sender-street': // 7.3.6.12
18818
			case 'sender-city': // 7.3.6.13
18819
			case 'sender-postal-code': // 7.3.6.14
18820
			case 'sender-country': // 7.3.6.15
18821
			case 'sender-state-or-province': // 7.3.6.16
18822
			case 'author-name': // 7.3.7.1
18823
			case 'author-initials': // 7.3.7.2
18824
			case 'chapter': // 7.3.8
18825
			case 'file-name': // 7.3.9
18826
			case 'template-name': // 7.3.9
18827
			case 'sheet-name': // 7.3.9
18828
				break;
18829
18830
			case 'event-listener':
18831
				break;
18832
			/* TODO: FODS Properties */
18833
			case 'initial-creator':
18834
			case 'creation-date':
18835
			case 'print-date':
18836
			case 'generator':
18837
			case 'document-statistic':
18838
			case 'user-defined':
18839
			case 'editing-duration':
18840
			case 'editing-cycles':
18841
				break;
18842
18843
			/* TODO: FODS Config */
18844
			case 'config-item':
18845
				break;
18846
18847
			/* TODO: style tokens */
18848
			case 'page-number': break; // TODO <text:page-number>
18849
			case 'page-count': break; // TODO <text:page-count>
18850
			case 'time': break; // TODO <text:time>
18851
18852
			/* 9.3 Advanced Table Cells */
18853
			case 'cell-range-source': break; // 9.3.1 <table:
18854
			case 'detective': break; // 9.3.2 <table:
18855
			case 'operation': break; // 9.3.3 <table:
18856
			case 'highlighted-range': break; // 9.3.4 <table:
18857
18858
			/* 9.6 Data Pilot Tables <table: */
18859
			case 'data-pilot-table': // 9.6.3
18860
			case 'source-cell-range': // 9.6.5
18861
			case 'source-service': // 9.6.6
18862
			case 'data-pilot-field': // 9.6.7
18863
			case 'data-pilot-level': // 9.6.8
18864
			case 'data-pilot-subtotals': // 9.6.9
18865
			case 'data-pilot-subtotal': // 9.6.10
18866
			case 'data-pilot-members': // 9.6.11
18867
			case 'data-pilot-member': // 9.6.12
18868
			case 'data-pilot-display-info': // 9.6.13
18869
			case 'data-pilot-sort-info': // 9.6.14
18870
			case 'data-pilot-layout-info': // 9.6.15
18871
			case 'data-pilot-field-reference': // 9.6.16
18872
			case 'data-pilot-groups': // 9.6.17
18873
			case 'data-pilot-group': // 9.6.18
18874
			case 'data-pilot-group-member': // 9.6.19
18875
				break;
18876
18877
			/* 10.3 Drawing Shapes */
18878
			case 'rect': // 10.3.2
18879
				break;
18880
18881
			/* 14.6 DDE Connections */
18882
			case 'dde-connection-decls': // 14.6.2 <text:
18883
			case 'dde-connection-decl': // 14.6.3 <text:
18884
			case 'dde-link': // 14.6.4 <table:
18885
			case 'dde-source': // 14.6.5 <office:
18886
				break;
18887
18888
			case 'properties': break; // 13.7 <form:properties>
18889
			case 'property': break; // 13.8 <form:property>
18890
18891
			case 'a': // 6.1.8 hyperlink
18892
				if(Rn[1]!== '/') {
18893
					atag = parsexmltag(Rn[0], false);
18894
					if(!atag.href) break;
18895
					atag.Target = atag.href; delete atag.href;
18896
					if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
18897
						_Ref = ods_to_csf_3D(atag.Target.slice(1));
18898
						atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
18899
					}
18900
				}
18901
				break;
18902
18903
			/* non-standard */
18904
			case 'table-protection': break;
18905
			case 'data-pilot-grand-total': break; // <table:
18906
			case 'office-document-common-attrs': break; // bare
18907
			default: switch(Rn[2]) {
18908
				case 'dc:':       // TODO: properties
18909
				case 'calcext:':  // ignore undocumented extensions
18910
				case 'loext:':    // ignore undocumented extensions
18911
				case 'ooo:':      // ignore undocumented extensions
18912
				case 'chartooo:': // ignore undocumented extensions
18913
				case 'draw:':     // TODO: drawing
18914
				case 'style:':    // TODO: styles
18915
				case 'chart:':    // TODO: charts
18916
				case 'form:':     // TODO: forms
18917
				case 'uof:':      // TODO: uof
18918
				case '表:':       // TODO: uof
18919
				case '字:':       // TODO: uof
18920
					break;
18921
				default: if(opts.WTF) throw new Error(Rn);
18922
			}
18923
		}
18924
		var out/*:Workbook*/ = ({
18925
			Sheets: Sheets,
18926
			SheetNames: SheetNames,
18927
			Workbook: WB
18928
		}/*:any*/);
18929
		if(opts.bookSheets) delete out.Sheets;
18930
		return out;
18931
	};
18932
})();
18933
18934
function parse_ods(zip/*:ZIPFile*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
18935
	opts = opts || ({}/*:any*/);
18936
	var ods = !!safegetzipfile(zip, 'objectdata');
18937
	if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
18938
	var content = getzipstr(zip, 'content.xml');
18939
	if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
18940
	var wb = parse_content_xml(ods ? content : utf8read(content), opts);
18941
	if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
18942
	return wb;
18943
}
18944
function parse_fods(data/*:string*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
18945
	return parse_content_xml(data, opts);
18946
}
18947
18948
/* OpenDocument */
18949
var write_styles_ods/*:{(wb:any, opts:any):string}*/ = (function() {
18950
	var payload = '<office:document-styles ' + wxt_helper({
18951
		'xmlns:office':   "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
18952
		'xmlns:table':    "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
18953
		'xmlns:style':    "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
18954
		'xmlns:text':     "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
18955
		'xmlns:draw':     "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
18956
		'xmlns:fo':       "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
18957
		'xmlns:xlink':    "http://www.w3.org/1999/xlink",
18958
		'xmlns:dc':       "http://purl.org/dc/elements/1.1/",
18959
		'xmlns:number':   "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
18960
		'xmlns:svg':      "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
18961
		'xmlns:of':       "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
18962
		'office:version': "1.2"
18963
	}) + '></office:document-styles>';
18964
	return function wso(/*::wb, opts*/) {
18965
		return XML_HEADER + payload;
18966
	};
18967
})();
18968
var write_content_ods/*:{(wb:any, opts:any):string}*/ = (function() {
18969
	/* 6.1.2 White Space Characters */
18970
	var write_text_p = function(text/*:string*/)/*:string*/ {
18971
		return escapexml(text)
18972
			.replace(/  +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
18973
			.replace(/\t/g, "<text:tab/>")
18974
			.replace(/\n/g, "<text:line-break/>")
18975
			.replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
18976
	};
18977
18978
	var null_cell_xml = '          <table:table-cell />\n';
18979
	var covered_cell_xml = '          <table:covered-table-cell/>\n';
18980
	var write_ws = function(ws, wb/*:Workbook*/, i/*:number*//*::, opts*/)/*:string*/ {
18981
		/* Section 9 Tables */
18982
		var o/*:Array<string>*/ = [];
18983
		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
18984
		var R=0,C=0, range = decode_range(ws['!ref']);
18985
		var marr/*:Array<Range>*/ = ws['!merges'] || [], mi = 0;
18986
		var dense = Array.isArray(ws);
18987
		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n');
18988
		for(; R <= range.e.r; ++R) {
18989
			o.push('        <table:table-row>\n');
18990
			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
18991
			for(; C <= range.e.c; ++C) {
18992
				var skip = false, ct = {}, textp = "";
18993
				for(mi = 0; mi != marr.length; ++mi) {
18994
					if(marr[mi].s.c > C) continue;
18995
					if(marr[mi].s.r > R) continue;
18996
					if(marr[mi].e.c < C) continue;
18997
					if(marr[mi].e.r < R) continue;
18998
					if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
18999
					ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
19000
					ct['table:number-rows-spanned'] =    (marr[mi].e.r - marr[mi].s.r + 1);
19001
					break;
19002
				}
19003
				if(skip) { o.push(covered_cell_xml); continue; }
19004
				var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
19005
				if(cell && cell.f) {
19006
					ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
19007
					if(cell.F) {
19008
						if(cell.F.slice(0, ref.length) == ref) {
19009
							var _Fref = decode_range(cell.F);
19010
							ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
19011
							ct['table:number-matrix-rows-spanned'] =    (_Fref.e.r - _Fref.s.r + 1);
19012
						}
19013
					}
19014
				}
19015
				if(!cell) { o.push(null_cell_xml); continue; }
19016
				switch(cell.t) {
19017
					case 'b':
19018
						textp = (cell.v ? 'TRUE' : 'FALSE');
19019
						ct['office:value-type'] = "boolean";
19020
						ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
19021
						break;
19022
					case 'n':
19023
						textp = (cell.w||String(cell.v||0));
19024
						ct['office:value-type'] = "float";
19025
						ct['office:value'] = (cell.v||0);
19026
						break;
19027
					case 's': case 'str':
19028
						textp = cell.v;
19029
						ct['office:value-type'] = "string";
19030
						break;
19031
					case 'd':
19032
						textp = (cell.w||(parseDate(cell.v).toISOString()));
19033
						ct['office:value-type'] = "date";
19034
						ct['office:date-value'] = (parseDate(cell.v).toISOString());
19035
						ct['table:style-name'] = "ce1";
19036
						break;
19037
					//case 'e':
19038
					default: o.push(null_cell_xml); continue;
19039
				}
19040
				var text_p = write_text_p(textp);
19041
				if(cell.l && cell.l.Target) {
19042
					var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
19043
					text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
19044
				}
19045
				o.push('          ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
19046
			}
19047
			o.push('        </table:table-row>\n');
19048
		}
19049
		o.push('      </table:table>\n');
19050
		return o.join("");
19051
	};
19052
19053
	var write_automatic_styles_ods = function(o/*:Array<string>*/) {
19054
		o.push(' <office:automatic-styles>\n');
19055
		o.push('  <number:date-style style:name="N37" number:automatic-order="true">\n');
19056
		o.push('   <number:month number:style="long"/>\n');
19057
		o.push('   <number:text>/</number:text>\n');
19058
		o.push('   <number:day number:style="long"/>\n');
19059
		o.push('   <number:text>/</number:text>\n');
19060
		o.push('   <number:year/>\n');
19061
		o.push('  </number:date-style>\n');
19062
		o.push('  <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
19063
		o.push(' </office:automatic-styles>\n');
19064
	};
19065
19066
	return function wcx(wb, opts) {
19067
		var o = [XML_HEADER];
19068
		/* 3.1.3.2 */
19069
		var attr = wxt_helper({
19070
			'xmlns:office':       "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
19071
			'xmlns:table':        "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
19072
			'xmlns:style':        "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
19073
			'xmlns:text':         "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
19074
			'xmlns:draw':         "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
19075
			'xmlns:fo':           "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
19076
			'xmlns:xlink':        "http://www.w3.org/1999/xlink",
19077
			'xmlns:dc':           "http://purl.org/dc/elements/1.1/",
19078
			'xmlns:meta':         "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
19079
			'xmlns:number':       "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
19080
			'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
19081
			'xmlns:svg':          "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
19082
			'xmlns:chart':        "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
19083
			'xmlns:dr3d':         "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
19084
			'xmlns:math':         "http://www.w3.org/1998/Math/MathML",
19085
			'xmlns:form':         "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
19086
			'xmlns:script':       "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
19087
			'xmlns:ooo':          "http://openoffice.org/2004/office",
19088
			'xmlns:ooow':         "http://openoffice.org/2004/writer",
19089
			'xmlns:oooc':         "http://openoffice.org/2004/calc",
19090
			'xmlns:dom':          "http://www.w3.org/2001/xml-events",
19091
			'xmlns:xforms':       "http://www.w3.org/2002/xforms",
19092
			'xmlns:xsd':          "http://www.w3.org/2001/XMLSchema",
19093
			'xmlns:xsi':          "http://www.w3.org/2001/XMLSchema-instance",
19094
			'xmlns:sheet':        "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
19095
			'xmlns:rpt':          "http://openoffice.org/2005/report",
19096
			'xmlns:of':           "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
19097
			'xmlns:xhtml':        "http://www.w3.org/1999/xhtml",
19098
			'xmlns:grddl':        "http://www.w3.org/2003/g/data-view#",
19099
			'xmlns:tableooo':     "http://openoffice.org/2009/table",
19100
			'xmlns:drawooo':      "http://openoffice.org/2010/draw",
19101
			'xmlns:calcext':      "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
19102
			'xmlns:loext':        "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
19103
			'xmlns:field':        "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
19104
			'xmlns:formx':        "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
19105
			'xmlns:css3t':        "http://www.w3.org/TR/css3-text/",
19106
			'office:version':     "1.2"
19107
		});
19108
19109
		var fods = wxt_helper({
19110
			'xmlns:config':    "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
19111
			'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
19112
		});
19113
19114
		if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n');
19115
		else o.push('<office:document-content' + attr  + '>\n');
19116
		write_automatic_styles_ods(o);
19117
		o.push('  <office:body>\n');
19118
		o.push('    <office:spreadsheet>\n');
19119
		for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
19120
		o.push('    </office:spreadsheet>\n');
19121
		o.push('  </office:body>\n');
19122
		if(opts.bookType == "fods") o.push('</office:document>');
19123
		else o.push('</office:document-content>');
19124
		return o.join("");
19125
	};
19126
})();
19127
19128
function write_ods(wb/*:any*/, opts/*:any*/) {
19129
	if(opts.bookType == "fods") return write_content_ods(wb, opts);
19130
19131
	/*:: if(!jszip) throw new Error("JSZip is not available"); */
19132
	var zip = new jszip();
19133
	var f = "";
19134
19135
	var manifest/*:Array<Array<string> >*/ = [];
19136
	var rdf/*:Array<[string, string]>*/ = [];
19137
19138
	/* Part 3 Section 3.3 MIME Media Type */
19139
	f = "mimetype";
19140
	zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
19141
19142
	/* Part 1 Section 2.2 Documents */
19143
	f = "content.xml";
19144
	zip.file(f, write_content_ods(wb, opts));
19145
	manifest.push([f, "text/xml"]);
19146
	rdf.push([f, "ContentFile"]);
19147
19148
	/* TODO: these are hard-coded styles to satiate excel */
19149
	f = "styles.xml";
19150
	zip.file(f, write_styles_ods(wb, opts));
19151
	manifest.push([f, "text/xml"]);
19152
	rdf.push([f, "StylesFile"]);
19153
19154
	/* TODO: this is hard-coded to satiate excel */
19155
	f = "meta.xml";
19156
	zip.file(f, write_meta_ods(/*::wb, opts*/));
19157
	manifest.push([f, "text/xml"]);
19158
	rdf.push([f, "MetadataFile"]);
19159
19160
	/* Part 3 Section 6 Metadata Manifest File */
19161
	f = "manifest.rdf";
19162
	zip.file(f, write_rdf(rdf/*, opts*/));
19163
	manifest.push([f, "application/rdf+xml"]);
19164
19165
	/* Part 3 Section 4 Manifest File */
19166
	f = "META-INF/manifest.xml";
19167
	zip.file(f, write_manifest(manifest/*, opts*/));
19168
19169
	return zip;
19170
}
19171
19172
function write_sheet_index(wb/*:Workbook*/, sheet/*:?string*/)/*:number*/ {
19173
	if(!sheet) return 0;
19174
	var idx = wb.SheetNames.indexOf(sheet);
19175
	if(idx == -1) throw new Error("Sheet not found: " + sheet);
19176
	return idx;
19177
}
19178
19179
function write_obj_str(factory/*:WriteObjStrFactory*/) {
19180
	return function write_str(wb/*:Workbook*/, o/*:WriteOpts*/)/*:string*/ {
19181
		var idx = write_sheet_index(wb, o.sheet);
19182
		return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
19183
	};
19184
}
19185
19186
var write_htm_str = write_obj_str(HTML_);
19187
var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
19188
var write_slk_str = write_obj_str(SYLK);
19189
var write_dif_str = write_obj_str(DIF);
19190
var write_prn_str = write_obj_str(PRN);
19191
var write_rtf_str = write_obj_str(RTF);
19192
var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
19193
var write_dbf_buf = write_obj_str(DBF);
19194
var write_eth_str = write_obj_str(ETH);
19195
19196
function fix_opts_func(defaults/*:Array<Array<any> >*/)/*:{(o:any):void}*/ {
19197
	return function fix_opts(opts) {
19198
		for(var i = 0; i != defaults.length; ++i) {
19199
			var d = defaults[i];
19200
			if(opts[d[0]] === undefined) opts[d[0]] = d[1];
19201
			if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
19202
		}
19203
	};
19204
}
19205
19206
var fix_read_opts = fix_opts_func([
19207
	['cellNF', false], /* emit cell number format string as .z */
19208
	['cellHTML', true], /* emit html string as .h */
19209
	['cellFormula', true], /* emit formulae as .f */
19210
	['cellStyles', false], /* emits style/theme as .s */
19211
	['cellText', true], /* emit formatted text as .w */
19212
	['cellDates', false], /* emit date cells with type `d` */
19213
19214
	['sheetStubs', false], /* emit empty cells */
19215
	['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
19216
19217
	['bookDeps', false], /* parse calculation chains */
19218
	['bookSheets', false], /* only try to get sheet names (no Sheets) */
19219
	['bookProps', false], /* only try to get properties (no Sheets) */
19220
	['bookFiles', false], /* include raw file structure (keys, files, cfb) */
19221
	['bookVBA', false], /* include vba raw data (vbaraw) */
19222
19223
	['password',''], /* password */
19224
	['WTF', false] /* WTF mode (throws errors) */
19225
]);
19226
19227
19228
var fix_write_opts = fix_opts_func([
19229
	['cellDates', false], /* write date cells with type `d` */
19230
19231
	['bookSST', false], /* Generate Shared String Table */
19232
19233
	['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
19234
19235
	['compression', false], /* Use file compression */
19236
19237
	['WTF', false] /* WTF mode (throws errors) */
19238
]);
19239
function get_sheet_type(n/*:string*/)/*:string*/ {
19240
	if(RELS.WS.indexOf(n) > -1) return "sheet";
19241
	if(RELS.CS && n == RELS.CS) return "chart";
19242
	if(RELS.DS && n == RELS.DS) return "dialog";
19243
	if(RELS.MS && n == RELS.MS) return "macro";
19244
	return (n && n.length) ? n : "sheet";
19245
}
19246
function safe_parse_wbrels(wbrels, sheets) {
19247
	if(!wbrels) return 0;
19248
	try {
19249
		wbrels = sheets.map(function pwbr(w) { if(!w.id) w.id = w.strRelID; return [w.name, wbrels['!id'][w.id].Target, get_sheet_type(wbrels['!id'][w.id].Type)]; });
19250
	} catch(e) { return null; }
19251
	return !wbrels || wbrels.length === 0 ? null : wbrels;
19252
}
19253
19254
function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/*:number*/, sheetRels, sheets, stype/*:string*/, opts, wb, themes, styles) {
19255
	try {
19256
		sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
19257
		var data = getzipdata(zip, path);
19258
		var _ws;
19259
		switch(stype) {
19260
			case 'sheet':  _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19261
			case 'chart':  _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
19262
				if(!_ws || !_ws['!chart']) break;
19263
				var dfile = resolve_path(_ws['!chart'].Target, path);
19264
				var drelsp = get_rels_path(dfile);
19265
				var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
19266
				var chartp = resolve_path(draw, dfile);
19267
				var crelsp = get_rels_path(chartp);
19268
				_ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
19269
				break;
19270
			case 'macro':  _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19271
			case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19272
		}
19273
		sheets[sheet] = _ws;
19274
	} catch(e) { if(opts.WTF) throw e; }
19275
}
19276
19277
function strip_front_slash(x/*:string*/)/*:string*/ { return x.charAt(0) == '/' ? x.slice(1) : x; }
19278
19279
function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
19280
	make_ssf(SSF);
19281
	opts = opts || {};
19282
	fix_read_opts(opts);
19283
19284
	/* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
19285
	if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
19286
	/* UOC */
19287
	if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
19288
	/* Numbers */
19289
	if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
19290
19291
	var entries = zipentries(zip);
19292
	var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')/*:?any*/));
19293
	var xlsb = false;
19294
	var sheets, binname;
19295
	if(dir.workbooks.length === 0) {
19296
		binname = "xl/workbook.xml";
19297
		if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
19298
	}
19299
	if(dir.workbooks.length === 0) {
19300
		binname = "xl/workbook.bin";
19301
		if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
19302
		dir.workbooks.push(binname);
19303
		xlsb = true;
19304
	}
19305
	if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
19306
19307
	var themes = ({}/*:any*/);
19308
	var styles = ({}/*:any*/);
19309
	if(!opts.bookSheets && !opts.bookProps) {
19310
		strs = [];
19311
		if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
19312
19313
		if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
19314
19315
		if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
19316
	}
19317
19318
	/*var externbooks = */dir.links.map(function(link) {
19319
		return parse_xlink(getzipdata(zip, strip_front_slash(link)), link, opts);
19320
	});
19321
19322
	var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
19323
19324
	var props = {}, propdata = "";
19325
19326
	if(dir.coreprops.length) {
19327
		propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
19328
		if(propdata) props = parse_core_props(propdata);
19329
		if(dir.extprops.length !== 0) {
19330
			propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
19331
			if(propdata) parse_ext_props(propdata, props, opts);
19332
		}
19333
	}
19334
19335
	var custprops = {};
19336
	if(!opts.bookSheets || opts.bookProps) {
19337
		if (dir.custprops.length !== 0) {
19338
			propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
19339
			if(propdata) custprops = parse_cust_props(propdata, opts);
19340
		}
19341
	}
19342
19343
	var out = ({}/*:any*/);
19344
	if(opts.bookSheets || opts.bookProps) {
19345
		if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
19346
		else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
19347
		if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
19348
		if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
19349
		if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
19350
	}
19351
	sheets = {};
19352
19353
	var deps = {};
19354
	if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
19355
19356
	var i=0;
19357
	var sheetRels = ({}/*:any*/);
19358
	var path, relsPath;
19359
19360
	{
19361
		var wbsheets = wb.Sheets;
19362
		props.Worksheets = wbsheets.length;
19363
		props.SheetNames = [];
19364
		for(var j = 0; j != wbsheets.length; ++j) {
19365
			props.SheetNames[j] = wbsheets[j].name;
19366
		}
19367
	}
19368
19369
	var wbext = xlsb ? "bin" : "xml";
19370
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
19371
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
19372
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
19373
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
19374
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
19375
19376
	/* Numbers iOS hack */
19377
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
19378
	for(i = 0; i != props.Worksheets; ++i) {
19379
		var stype = "sheet";
19380
		if(wbrels && wbrels[i]) {
19381
			path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
19382
			if(!safegetzipfile(zip, path)) path = wbrels[i][1];
19383
			if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
19384
			stype = wbrels[i][2];
19385
		} else {
19386
			path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
19387
			path = path.replace(/sheet0\./,"sheet.");
19388
		}
19389
		relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
19390
		safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
19391
	}
19392
19393
	if(dir.comments) parse_comments(zip, dir.comments, sheets, sheetRels, opts);
19394
19395
	out = ({
19396
		Directory: dir,
19397
		Workbook: wb,
19398
		Props: props,
19399
		Custprops: custprops,
19400
		Deps: deps,
19401
		Sheets: sheets,
19402
		SheetNames: props.SheetNames,
19403
		Strings: strs,
19404
		Styles: styles,
19405
		Themes: themes,
19406
		SSF: SSF.get_table()
19407
	}/*:any*/);
19408
	if(opts.bookFiles) {
19409
		out.keys = entries;
19410
		out.files = zip.files;
19411
	}
19412
	if(opts.bookVBA) {
19413
		if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
19414
		else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
19415
	}
19416
	return out;
19417
}
19418
19419
/* [MS-OFFCRYPTO] 2.1.1 */
19420
function parse_xlsxcfb(cfb, _opts/*:?ParseOpts*/)/*:Workbook*/ {
19421
	var opts = _opts || {};
19422
	var f = 'Workbook', data = CFB.find(cfb, f);
19423
	try {
19424
	f = '/!DataSpaces/Version';
19425
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19426
	/*var version = */parse_DataSpaceVersionInfo(data.content);
19427
19428
	/* 2.3.4.1 */
19429
	f = '/!DataSpaces/DataSpaceMap';
19430
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19431
	var dsm = parse_DataSpaceMap(data.content);
19432
	if(dsm.length !== 1 || dsm[0].comps.length !== 1 || dsm[0].comps[0].t !== 0 || dsm[0].name !== "StrongEncryptionDataSpace" || dsm[0].comps[0].v !== "EncryptedPackage")
19433
		throw new Error("ECMA-376 Encrypted file bad " + f);
19434
19435
	/* 2.3.4.2 */
19436
	f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
19437
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19438
	var seds = parse_DataSpaceDefinition(data.content);
19439
	if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
19440
		throw new Error("ECMA-376 Encrypted file bad " + f);
19441
19442
	/* 2.3.4.3 */
19443
	f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
19444
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19445
	/*var hdr = */parse_Primary(data.content);
19446
	} catch(e) {}
19447
19448
	f = '/EncryptionInfo';
19449
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19450
	var einfo = parse_EncryptionInfo(data.content);
19451
19452
	/* 2.3.4.4 */
19453
	f = '/EncryptedPackage';
19454
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19455
19456
/*global decrypt_agile */
19457
/*:: declare var decrypt_agile:any; */
19458
	if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
19459
/*global decrypt_std76 */
19460
/*:: declare var decrypt_std76:any; */
19461
	if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
19462
	throw new Error("File is password-protected");
19463
}
19464
19465
function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
19466
	_shapeid = 1024;
19467
	if(opts.bookType == "ods") return write_ods(wb, opts);
19468
	if(wb && !wb.SSF) {
19469
		wb.SSF = SSF.get_table();
19470
	}
19471
	if(wb && wb.SSF) {
19472
		make_ssf(SSF); SSF.load_table(wb.SSF);
19473
		// $FlowIgnore
19474
		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
19475
		opts.ssf = wb.SSF;
19476
	}
19477
	opts.rels = {}; opts.wbrels = {};
19478
	opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0;
19479
	if(browser_has_Map) opts.revStrings = new Map();
19480
	else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
19481
	var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
19482
	var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
19483
	var ct = new_ct();
19484
	fix_write_opts(opts = opts || {});
19485
	/*:: if(!jszip) throw new Error("JSZip is not available"); */
19486
	var zip = new jszip();
19487
	var f = "", rId = 0;
19488
19489
	opts.cellXfs = [];
19490
	get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
19491
19492
	if(!wb.Props) wb.Props = {};
19493
19494
	f = "docProps/core.xml";
19495
	zip.file(f, write_core_props(wb.Props, opts));
19496
	ct.coreprops.push(f);
19497
	add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
19498
19499
	/*::if(!wb.Props) throw "unreachable"; */
19500
	f = "docProps/app.xml";
19501
	if(wb.Props && wb.Props.SheetNames){/* empty */}
19502
	else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
19503
	else {
19504
		var _sn = [];
19505
		for(var _i = 0; _i < wb.SheetNames.length; ++_i)
19506
			if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
19507
		wb.Props.SheetNames = _sn;
19508
	}
19509
	wb.Props.Worksheets = wb.Props.SheetNames.length;
19510
	zip.file(f, write_ext_props(wb.Props, opts));
19511
	ct.extprops.push(f);
19512
	add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
19513
19514
	if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
19515
		f = "docProps/custom.xml";
19516
		zip.file(f, write_cust_props(wb.Custprops, opts));
19517
		ct.custprops.push(f);
19518
		add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
19519
	}
19520
19521
	for(rId=1;rId <= wb.SheetNames.length; ++rId) {
19522
		var wsrels = {'!id':{}};
19523
		var ws = wb.Sheets[wb.SheetNames[rId-1]];
19524
		var _type = (ws || {})["!type"] || "sheet";
19525
		switch(_type) {
19526
		case "chart": /*
19527
			f = "xl/chartsheets/sheet" + rId + "." + wbext;
19528
			zip.file(f, write_cs(rId-1, f, opts, wb, wsrels));
19529
			ct.charts.push(f);
19530
			add_rels(wsrels, -1, "chartsheets/sheet" + rId + "." + wbext, RELS.CS);
19531
			break; */
19532
			/* falls through */
19533
		default:
19534
			f = "xl/worksheets/sheet" + rId + "." + wbext;
19535
			zip.file(f, write_ws(rId-1, f, opts, wb, wsrels));
19536
			ct.sheets.push(f);
19537
			add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
19538
		}
19539
19540
		if(ws) {
19541
			var comments = ws['!comments'];
19542
			if(comments && comments.length > 0) {
19543
				var cf = "xl/comments" + rId + "." + wbext;
19544
				zip.file(cf, write_cmnt(comments, cf, opts));
19545
				ct.comments.push(cf);
19546
				add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
19547
			}
19548
			if(ws['!legacy']) {
19549
				zip.file("xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
19550
			}
19551
			delete ws['!comments'];
19552
			delete ws['!legacy'];
19553
		}
19554
19555
		if(wsrels['!id'].rId1) zip.file(get_rels_path(f), write_rels(wsrels));
19556
	}
19557
19558
	if(opts.Strings != null && opts.Strings.length > 0) {
19559
		f = "xl/sharedStrings." + wbext;
19560
		zip.file(f, write_sst(opts.Strings, f, opts));
19561
		ct.strs.push(f);
19562
		add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
19563
	}
19564
19565
	f = "xl/workbook." + wbext;
19566
	zip.file(f, write_wb(wb, f, opts));
19567
	ct.workbooks.push(f);
19568
	add_rels(opts.rels, 1, f, RELS.WB);
19569
19570
	/* TODO: something more intelligent with themes */
19571
19572
	f = "xl/theme/theme1.xml";
19573
	zip.file(f, write_theme(wb.Themes, opts));
19574
	ct.themes.push(f);
19575
	add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
19576
19577
	/* TODO: something more intelligent with styles */
19578
19579
	f = "xl/styles." + wbext;
19580
	zip.file(f, write_sty(wb, f, opts));
19581
	ct.styles.push(f);
19582
	add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
19583
19584
	if(wb.vbaraw && vbafmt) {
19585
		f = "xl/vbaProject.bin";
19586
		zip.file(f, wb.vbaraw);
19587
		ct.vba.push(f);
19588
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
19589
	}
19590
19591
	zip.file("[Content_Types].xml", write_ct(ct, opts));
19592
	zip.file('_rels/.rels', write_rels(opts.rels));
19593
	zip.file('xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
19594
19595
	delete opts.revssf; delete opts.ssf;
19596
	return zip;
19597
}
19598
function firstbyte(f/*:RawData*/,o/*:?TypeOpts*/)/*:Array<number>*/ {
19599
	var x = "";
19600
	switch((o||{}).type || "base64") {
19601
		case 'buffer': return [f[0], f[1], f[2], f[3]];
19602
		case 'base64': x = Base64.decode(f.slice(0,24)); break;
19603
		case 'binary': x = f; break;
19604
		case 'array':  return [f[0], f[1], f[2], f[3]];
19605
		default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
19606
	}
19607
	return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)];
19608
}
19609
19610
function read_cfb(cfb/*:CFBContainer*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
19611
	if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
19612
	return parse_xlscfb(cfb, opts);
19613
}
19614
19615
function read_zip(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
19616
	/*:: if(!jszip) throw new Error("JSZip is not available"); */
19617
	var zip, d = data;
19618
	var o = opts||{};
19619
	if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
19620
	switch(o.type) {
19621
		case "base64": zip = new jszip(d, { base64:true }); break;
19622
		case "binary": case "array": zip = new jszip(d, { base64:false }); break;
19623
		case "buffer": zip = new jszip(d); break;
19624
		default: throw new Error("Unrecognized type " + o.type);
19625
	}
19626
	return parse_zip(zip, o);
19627
}
19628
19629
function read_plaintext(data/*:string*/, o/*:ParseOpts*/)/*:Workbook*/ {
19630
	var i = 0;
19631
	main: while(i < data.length) switch(data.charCodeAt(i)) {
19632
		case 0x0A: case 0x0D: case 0x20: ++i; break;
19633
		case 0x3C: return parse_xlml(data.slice(i),o);
19634
		default: break main;
19635
	}
19636
	return PRN.to_workbook(data, o);
19637
}
19638
19639
function read_plaintext_raw(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
19640
	var str = "", bytes = firstbyte(data, o);
19641
	switch(o.type) {
19642
		case 'base64': str = Base64.decode(data); break;
19643
		case 'binary': str = data; break;
19644
		case 'buffer': str = data.toString('binary'); break;
19645
		case 'array': str = cc2str(data); break;
19646
		default: throw new Error("Unrecognized type " + o.type);
19647
	}
19648
	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
19649
	return read_plaintext(str, o);
19650
}
19651
19652
function read_utf16(data/*:RawData*/, o/*:ParseOpts*/)/*:Workbook*/ {
19653
	var d = data;
19654
	if(o.type == 'base64') d = Base64.decode(d);
19655
	d = cptable.utils.decode(1200, d.slice(2), 'str');
19656
	o.type = "binary";
19657
	return read_plaintext(d, o);
19658
}
19659
19660
function bstrify(data/*:string*/)/*:string*/ {
19661
	return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
19662
}
19663
19664
function read_prn(data, d, o, str) {
19665
	if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
19666
	return PRN.to_workbook(d, o);
19667
}
19668
19669
function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
19670
	reset_cp();
19671
	if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
19672
	var d = data, n = [0,0,0,0], str = false;
19673
	var o = opts||{};
19674
	_ssfopts = {};
19675
	if(o.dateNF) _ssfopts.dateNF = o.dateNF;
19676
	if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
19677
	if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
19678
	if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
19679
	if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
19680
		// $FlowIgnore
19681
		var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
19682
		// $FlowIgnore
19683
		if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
19684
	}
19685
	switch((n = firstbyte(d, o))[0]) {
19686
		case 0xD0: return read_cfb(CFB.read(d, o), o);
19687
		case 0x09: return parse_xlscfb(d, o);
19688
		case 0x3C: return parse_xlml(d, o);
19689
		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
19690
		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
19691
		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
19692
		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
19693
		case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
19694
		case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
19695
		case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
19696
		case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
19697
		case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
19698
	}
19699
	if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
19700
	return read_prn(data, d, o, str);
19701
}
19702
19703
function readFileSync(filename/*:string*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
19704
	var o = opts||{}; o.type = 'file';
19705
	return readSync(filename, o);
19706
}
19707
function write_cfb_ctr(cfb/*:CFBContainer*/, o/*:WriteOpts*/)/*:any*/ {
19708
	switch(o.type) {
19709
		case "base64": case "binary": break;
19710
		case "buffer": case "array": o.type = ""; break;
19711
		case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
19712
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
19713
		default: throw new Error("Unrecognized type " + o.type);
19714
	}
19715
	return CFB.write(cfb, o);
19716
}
19717
19718
/*global encrypt_agile */
19719
/*:: declare var encrypt_agile:any; */
19720
function write_zip_type(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
19721
	var o = opts||{};
19722
	var z = write_zip(wb, o);
19723
	var oopts = {};
19724
	if(o.compression) oopts.compression = 'DEFLATE';
19725
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
19726
	else switch(o.type) {
19727
		case "base64": oopts.type = "base64"; break;
19728
		case "binary": oopts.type = "string"; break;
19729
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
19730
		case "buffer":
19731
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
19732
		default: throw new Error("Unrecognized type " + o.type);
19733
	}
19734
	var out = z.generate(oopts);
19735
	if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o);
19736
	if(o.type === "file") return write_dl(o.file, out);
19737
	return o.type == "string" ? utf8read(out) : out;
19738
}
19739
19740
function write_cfb_type(wb/*:Workbook*/, opts/*:?WriteOpts*/)/*:any*/ {
19741
	var o = opts||{};
19742
	var cfb/*:CFBContainer*/ = write_xlscfb(wb, o);
19743
	return write_cfb_ctr(cfb, o);
19744
}
19745
19746
function write_string_type(out/*:string*/, opts/*:WriteOpts*/, bom/*:?string*/)/*:any*/ {
19747
	if(!bom) bom = "";
19748
	var o = bom + out;
19749
	switch(opts.type) {
19750
		case "base64": return Base64.encode(utf8write(o));
19751
		case "binary": return utf8write(o);
19752
		case "string": return out;
19753
		case "file": return write_dl(opts.file, o, 'utf8');
19754
		case "buffer": {
19755
			// $FlowIgnore
19756
			if(has_buf) return Buffer_from(o, 'utf8');
19757
			else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
19758
		}
19759
	}
19760
	throw new Error("Unrecognized type " + opts.type);
19761
}
19762
19763
function write_stxt_type(out/*:string*/, opts/*:WriteOpts*/)/*:any*/ {
19764
	switch(opts.type) {
19765
		case "base64": return Base64.encode(out);
19766
		case "binary": return out;
19767
		case "string": return out; /* override in sheet_to_txt */
19768
		case "file": return write_dl(opts.file, out, 'binary');
19769
		case "buffer": {
19770
			// $FlowIgnore
19771
			if(has_buf) return Buffer_from(out, 'binary');
19772
			else return out.split("").map(function(c) { return c.charCodeAt(0); });
19773
		}
19774
	}
19775
	throw new Error("Unrecognized type " + opts.type);
19776
}
19777
19778
/* TODO: test consistency */
19779
function write_binary_type(out, opts/*:WriteOpts*/)/*:any*/ {
19780
	switch(opts.type) {
19781
		case "string":
19782
		case "base64":
19783
		case "binary":
19784
			var bstr = "";
19785
			// $FlowIgnore
19786
			for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
19787
			return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
19788
		case "file": return write_dl(opts.file, out);
19789
		case "buffer": return out;
19790
		default: throw new Error("Unrecognized type " + opts.type);
19791
	}
19792
}
19793
19794
function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
19795
	check_wb(wb);
19796
	var o = opts||{};
19797
	if(o.type == "array") { o.type = "binary"; var out/*:string*/ = (writeSync(wb, o)/*:any*/); o.type = "array"; return s2ab(out); }
19798
	switch(o.bookType || 'xlsb') {
19799
		case 'xml':
19800
		case 'xlml': return write_string_type(write_xlml(wb, o), o);
19801
		case 'slk':
19802
		case 'sylk': return write_string_type(write_slk_str(wb, o), o);
19803
		case 'htm':
19804
		case 'html': return write_string_type(write_htm_str(wb, o), o);
19805
		case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
19806
		case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
19807
		case 'dif': return write_string_type(write_dif_str(wb, o), o);
19808
		case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
19809
		case 'prn': return write_string_type(write_prn_str(wb, o), o);
19810
		case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
19811
		case 'eth': return write_string_type(write_eth_str(wb, o), o);
19812
		case 'fods': return write_string_type(write_ods(wb, o), o);
19813
		case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
19814
		case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
19815
		case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
19816
		case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
19817
		case 'biff8':
19818
		case 'xla':
19819
		case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
19820
		case 'xlsx':
19821
		case 'xlsm':
19822
		case 'xlam':
19823
		case 'xlsb':
19824
		case 'ods': return write_zip_type(wb, o);
19825
		default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
19826
	}
19827
}
19828
19829
function resolve_book_type(o/*:WriteFileOpts*/) {
19830
	if(o.bookType) return;
19831
	var _BT = {
19832
		"xls": "biff8",
19833
		"htm": "html",
19834
		"slk": "sylk",
19835
		"socialcalc": "eth",
19836
		"Sh33tJS": "WTF"
19837
	};
19838
	var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
19839
	if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
19840
	o.bookType = _BT[o.bookType] || o.bookType;
19841
}
19842
19843
function writeFileSync(wb/*:Workbook*/, filename/*:string*/, opts/*:?WriteFileOpts*/) {
19844
	var o = opts||{}; o.type = 'file';
19845
	o.file = filename;
19846
	resolve_book_type(o);
19847
	return writeSync(wb, o);
19848
}
19849
19850
function writeFileAsync(filename/*:string*/, wb/*:Workbook*/, opts/*:?WriteFileOpts*/, cb/*:?(e?:ErrnoError)=>void*/) {
19851
	var o = opts||{}; o.type = 'file';
19852
	o.file = filename;
19853
	resolve_book_type(o);
19854
	o.type = 'buffer';
19855
	var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts/*:any*/);
19856
	return _fs.writeFile(filename, writeSync(wb, o), _cb);
19857
}
19858
/*::
19859
type MJRObject = {
19860
	row: any;
19861
	isempty: boolean;
19862
};
19863
*/
19864
function make_json_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, header/*:number*/, hdr/*:Array<any>*/, dense/*:boolean*/, o/*:Sheet2JSONOpts*/)/*:MJRObject*/ {
19865
	var rr = encode_row(R);
19866
	var defval = o.defval, raw = o.raw;
19867
	var isempty = true;
19868
	var row/*:any*/ = (header === 1) ? [] : {};
19869
	if(header !== 1) {
19870
		if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
19871
		else row.__rowNum__ = R;
19872
	}
19873
	if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
19874
		var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
19875
		if(val === undefined || val.t === undefined) {
19876
			if(defval === undefined) continue;
19877
			if(hdr[C] != null) { row[hdr[C]] = defval; }
19878
			continue;
19879
		}
19880
		var v = val.v;
19881
		switch(val.t){
19882
			case 'z': if(v == null) break; continue;
19883
			case 'e': v = void 0; break;
19884
			case 's': case 'd': case 'b': case 'n': break;
19885
			default: throw new Error('unrecognized type ' + val.t);
19886
		}
19887
		if(hdr[C] != null) {
19888
			if(v == null) {
19889
				if(defval !== undefined) row[hdr[C]] = defval;
19890
				else if(raw && v === null) row[hdr[C]] = null;
19891
				else continue;
19892
			} else {
19893
				row[hdr[C]] = raw ? v : format_cell(val,v,o);
19894
			}
19895
			if(v != null) isempty = false;
19896
		}
19897
	}
19898
	return { row: row, isempty: isempty };
19899
}
19900
19901
19902
function sheet_to_json(sheet/*:Worksheet*/, opts/*:?Sheet2JSONOpts*/) {
19903
	if(sheet == null || sheet["!ref"] == null) return [];
19904
	var val = {t:'n',v:0}, header = 0, offset = 1, hdr/*:Array<any>*/ = [], v=0, vv="";
19905
	var r = {s:{r:0,c:0},e:{r:0,c:0}};
19906
	var o = opts || {};
19907
	var range = o.range != null ? o.range : sheet["!ref"];
19908
	if(o.header === 1) header = 1;
19909
	else if(o.header === "A") header = 2;
19910
	else if(Array.isArray(o.header)) header = 3;
19911
	switch(typeof range) {
19912
		case 'string': r = safe_decode_range(range); break;
19913
		case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
19914
		default: r = range;
19915
	}
19916
	if(header > 0) offset = 0;
19917
	var rr = encode_row(r.s.r);
19918
	var cols/*:Array<string>*/ = [];
19919
	var out/*:Array<any>*/ = [];
19920
	var outi = 0, counter = 0;
19921
	var dense = Array.isArray(sheet);
19922
	var R = r.s.r, C = 0, CC = 0;
19923
	if(dense && !sheet[R]) sheet[R] = [];
19924
	for(C = r.s.c; C <= r.e.c; ++C) {
19925
		cols[C] = encode_col(C);
19926
		val = dense ? sheet[R][C] : sheet[cols[C] + rr];
19927
		switch(header) {
19928
			case 1: hdr[C] = C - r.s.c; break;
19929
			case 2: hdr[C] = cols[C]; break;
19930
			case 3: hdr[C] = o.header[C - r.s.c]; break;
19931
			default:
19932
				if(val == null) val = {w: "__EMPTY", t: "s"};
19933
				vv = v = format_cell(val, null, o);
19934
				counter = 0;
19935
				for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
19936
				hdr[C] = vv;
19937
		}
19938
	}
19939
	for (R = r.s.r + offset; R <= r.e.r; ++R) {
19940
		var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
19941
		if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
19942
	}
19943
	out.length = outi;
19944
	return out;
19945
}
19946
19947
var qreg = /"/g;
19948
function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Array<string>*/, fs/*:number*/, rs/*:number*/, FS/*:string*/, o/*:Sheet2CSVOpts*/)/*:?string*/ {
19949
	var isempty = true;
19950
	var row/*:Array<string>*/ = [], txt = "", rr = encode_row(R);
19951
	for(var C = r.s.c; C <= r.e.c; ++C) {
19952
		if (!cols[C]) continue;
19953
		var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
19954
		if(val == null) txt = "";
19955
		else if(val.v != null) {
19956
			isempty = false;
19957
			txt = ''+format_cell(val, null, o);
19958
			for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
19959
			if(txt == "ID") txt = '"ID"';
19960
		} else if(val.f != null && !val.F) {
19961
			isempty = false;
19962
			txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
19963
		} else txt = "";
19964
		/* NOTE: Excel CSV does not support array formulae */
19965
		row.push(txt);
19966
	}
19967
	if(o.blankrows === false && isempty) return null;
19968
	return row.join(FS);
19969
}
19970
19971
function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ {
19972
	var out/*:Array<string>*/ = [];
19973
	var o = opts == null ? {} : opts;
19974
	if(sheet == null || sheet["!ref"] == null) return "";
19975
	var r = safe_decode_range(sheet["!ref"]);
19976
	var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
19977
	var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
19978
	var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
19979
	var row = "", cols/*:Array<string>*/ = [];
19980
	o.dense = Array.isArray(sheet);
19981
	var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
19982
	var rowinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!rows"] || [];
19983
	for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
19984
	for(var R = r.s.r; R <= r.e.r; ++R) {
19985
		if ((rowinfo[R]||{}).hidden) continue;
19986
		row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
19987
		if(row == null) { continue; }
19988
		if(o.strip) row = row.replace(endregex,"");
19989
		out.push(row + RS);
19990
	}
19991
	delete o.dense;
19992
	return out.join("");
19993
}
19994
19995
function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
19996
	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
19997
	var s = sheet_to_csv(sheet, opts);
19998
	if(typeof cptable == 'undefined' || opts.type == 'string') return s;
19999
	var o = cptable.utils.encode(1200, s, 'str');
20000
	return String.fromCharCode(255) + String.fromCharCode(254) + o;
20001
}
20002
20003
function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array<string>*/ {
20004
	var y = "", x, val="";
20005
	if(sheet == null || sheet["!ref"] == null) return [];
20006
	var r = safe_decode_range(sheet['!ref']), rr = "", cols/*:Array<string>*/ = [], C;
20007
	var cmds/*:Array<string>*/ = [];
20008
	var dense = Array.isArray(sheet);
20009
	for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
20010
	for(var R = r.s.r; R <= r.e.r; ++R) {
20011
		rr = encode_row(R);
20012
		for(C = r.s.c; C <= r.e.c; ++C) {
20013
			y = cols[C] + rr;
20014
			x = dense ? (sheet[R]||[])[C] : sheet[y];
20015
			val = "";
20016
			if(x === undefined) continue;
20017
			else if(x.F != null) {
20018
				y = x.F;
20019
				if(!x.f) continue;
20020
				val = x.f;
20021
				if(y.indexOf(":") == -1) y = y + ":" + y;
20022
			}
20023
			if(x.f != null) val = x.f;
20024
			else if(x.t == 'z') continue;
20025
			else if(x.t == 'n' && x.v != null) val = "" + x.v;
20026
			else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
20027
			else if(x.w !== undefined) val = "'" + x.w;
20028
			else if(x.v === undefined) continue;
20029
			else if(x.t == 's') val = "'" + x.v;
20030
			else val = ""+x.v;
20031
			cmds[cmds.length] = y + "=" + val;
20032
		}
20033
	}
20034
	return cmds;
20035
}
20036
20037
function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet*/ {
20038
	var o = opts || {};
20039
	var offset = +!o.skipHeader;
20040
	var ws/*:Worksheet*/ = _ws || ({}/*:any*/);
20041
	var _R = 0, _C = 0;
20042
	if(ws && o.origin != null) {
20043
		if(typeof o.origin == 'number') _R = o.origin;
20044
		else {
20045
			var _origin/*:CellAddress*/ = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
20046
			_R = _origin.r; _C = _origin.c;
20047
		}
20048
	}
20049
	var cell/*:Cell*/;
20050
	var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}}/*:any*/);
20051
	if(ws['!ref']) {
20052
		var _range = safe_decode_range(ws['!ref']);
20053
		range.e.c = Math.max(range.e.c, _range.e.c);
20054
		range.e.r = Math.max(range.e.r, _range.e.r);
20055
		if(_R == -1) { _R = range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
20056
	}
20057
	var hdr/*:Array<string>*/ = o.header || [], C = 0;
20058
20059
	js.forEach(function (JS, R/*:number*/) {
20060
		keys(JS).forEach(function(k) {
20061
			if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
20062
			var v = JS[k];
20063
			var t = 'z';
20064
			var z = "";
20065
			if(v && typeof v === 'object' && !(v instanceof Date)){
20066
				ws[encode_cell({c:_C + C,r:_R + R + offset})] = v;
20067
			} else {
20068
				if(typeof v == 'number') t = 'n';
20069
				else if(typeof v == 'boolean') t = 'b';
20070
				else if(typeof v == 'string') t = 's';
20071
				else if(v instanceof Date) {
20072
					t = 'd';
20073
					if(!o.cellDates) { t = 'n'; v = datenum(v); }
20074
					z = o.dateNF || SSF._table[14];
20075
				}
20076
				ws[encode_cell({c:_C + C,r:_R + R + offset})] = cell = ({t:t, v:v}/*:any*/);
20077
				if(z) cell.z = z;
20078
			}
20079
		});
20080
	});
20081
	range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
20082
	var __R = encode_row(_R);
20083
	if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
20084
	ws['!ref'] = encode_range(range);
20085
	return ws;
20086
}
20087
function json_to_sheet(js/*:Array<any>*/, opts)/*:Worksheet*/ { return sheet_add_json(null, js, opts); }
20088
20089
var utils/*:any*/ = {
20090
	encode_col: encode_col,
20091
	encode_row: encode_row,
20092
	encode_cell: encode_cell,
20093
	encode_range: encode_range,
20094
	decode_col: decode_col,
20095
	decode_row: decode_row,
20096
	split_cell: split_cell,
20097
	decode_cell: decode_cell,
20098
	decode_range: decode_range,
20099
	format_cell: format_cell,
20100
	get_formulae: sheet_to_formulae,
20101
	make_csv: sheet_to_csv,
20102
	make_json: sheet_to_json,
20103
	make_formulae: sheet_to_formulae,
20104
	sheet_add_aoa: sheet_add_aoa,
20105
	sheet_add_json: sheet_add_json,
20106
	aoa_to_sheet: aoa_to_sheet,
20107
	json_to_sheet: json_to_sheet,
20108
	table_to_sheet: parse_dom_table,
20109
	table_to_book: table_to_book,
20110
	sheet_to_csv: sheet_to_csv,
20111
	sheet_to_txt: sheet_to_txt,
20112
	sheet_to_json: sheet_to_json,
20113
	sheet_to_html: HTML_.from_sheet,
20114
	sheet_to_dif: DIF.from_sheet,
20115
	sheet_to_slk: SYLK.from_sheet,
20116
	sheet_to_eth: ETH.from_sheet,
20117
	sheet_to_formulae: sheet_to_formulae,
20118
	sheet_to_row_object_array: sheet_to_json
20119
};
20120
20121
(function(utils) {
20122
utils.consts = utils.consts || {};
20123
function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
20124
20125
function get_default(x/*:any*/, y/*:any*/, z/*:any*/)/*:any*/ { return x[y] != null ? x[y] : (x[y] = z); }
20126
20127
/* get cell, creating a stub if necessary */
20128
function ws_get_cell_stub(ws/*:Worksheet*/, R, C/*:?number*/)/*:Cell*/ {
20129
	/* A1 cell address */
20130
	if(typeof R == "string") return ws[R] || (ws[R] = {t:'z'});
20131
	/* cell address object */
20132
	if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
20133
	/* R and C are 0-based indices */
20134
	return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
20135
}
20136
20137
/* find sheet index for given name / validate index */
20138
function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
20139
	if(typeof sh == "number") {
20140
		if(sh >= 0 && wb.SheetNames.length > sh) return sh;
20141
		throw new Error("Cannot find sheet # " + sh);
20142
	} else if(typeof sh == "string") {
20143
		var idx = wb.SheetNames.indexOf(sh);
20144
		if(idx > -1) return idx;
20145
		throw new Error("Cannot find sheet name |" + sh + "|");
20146
	} else throw new Error("Cannot find sheet |" + sh + "|");
20147
}
20148
20149
/* simple blank workbook object */
20150
utils.book_new = function()/*:Workbook*/ {
20151
	return { SheetNames: [], Sheets: {} };
20152
};
20153
20154
/* add a worksheet to the end of a given workbook */
20155
utils.book_append_sheet = function(wb/*:Workbook*/, ws/*:Worksheet*/, name/*:?string*/) {
20156
	if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
20157
	if(!name) throw new Error("Too many worksheets");
20158
	check_ws_name(name);
20159
	if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
20160
20161
	wb.SheetNames.push(name);
20162
	wb.Sheets[name] = ws;
20163
};
20164
20165
/* set sheet visibility (visible/hidden/very hidden) */
20166
utils.book_set_sheet_visibility = function(wb/*:Workbook*/, sh/*:number|string*/, vis/*:number*/) {
20167
	get_default(wb,"Workbook",{});
20168
	get_default(wb.Workbook,"Sheets",[]);
20169
20170
	var idx = wb_sheet_idx(wb, sh);
20171
	// $FlowIgnore
20172
	get_default(wb.Workbook.Sheets,idx, {});
20173
20174
	switch(vis) {
20175
		case 0: case 1: case 2: break;
20176
		default: throw new Error("Bad sheet visibility setting " + vis);
20177
	}
20178
	// $FlowIgnore
20179
	wb.Workbook.Sheets[idx].Hidden = vis;
20180
};
20181
add_consts([
20182
	["SHEET_VISIBLE", 0],
20183
	["SHEET_HIDDEN", 1],
20184
	["SHEET_VERY_HIDDEN", 2]
20185
]);
20186
20187
/* set number format */
20188
utils.cell_set_number_format = function(cell/*:Cell*/, fmt/*:string|number*/) {
20189
	cell.z = fmt;
20190
	return cell;
20191
};
20192
20193
/* set cell hyperlink */
20194
utils.cell_set_hyperlink = function(cell/*:Cell*/, target/*:string*/, tooltip/*:?string*/) {
20195
	if(!target) {
20196
		delete cell.l;
20197
	} else {
20198
		cell.l = ({ Target: target }/*:Hyperlink*/);
20199
		if(tooltip) cell.l.Tooltip = tooltip;
20200
	}
20201
	return cell;
20202
};
20203
utils.cell_set_internal_link = function(cell/*:Cell*/, range/*:string*/, tooltip/*:?string*/) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
20204
20205
/* add to cell comments */
20206
utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?string*/) {
20207
	if(!cell.c) cell.c = [];
20208
	cell.c.push({t:text, a:author||"SheetJS"});
20209
};
20210
20211
/* set array formula and flush related cells */
20212
utils.sheet_set_array_formula = function(ws/*:Worksheet*/, range, formula/*:string*/) {
20213
	var rng = typeof range != "string" ? range : safe_decode_range(range);
20214
	var rngstr = typeof range == "string" ? range : encode_range(range);
20215
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
20216
		var cell = ws_get_cell_stub(ws, R, C);
20217
		cell.t = 'n';
20218
		cell.F = rngstr;
20219
		delete cell.v;
20220
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
20221
	}
20222
	return ws;
20223
};
20224
20225
return utils;
20226
})(utils);
20227
20228
if(has_buf && typeof require != 'undefined') (function() {
20229
	var Readable = require('stream').Readable;
20230
20231
	var write_csv_stream = function(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
20232
		var stream = Readable();
20233
		var o = opts == null ? {} : opts;
20234
		if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
20235
		var r = safe_decode_range(sheet["!ref"]);
20236
		var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
20237
		var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
20238
		var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
20239
		var row/*:?string*/ = "", cols/*:Array<string>*/ = [];
20240
		o.dense = Array.isArray(sheet);
20241
		var colinfo/*:Array<ColInfo>*/ = o.skipHidden && sheet["!cols"] || [];
20242
		var rowinfo/*:Array<RowInfo>*/ = o.skipHidden && sheet["!rows"] || [];
20243
		for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
20244
		var R = r.s.r;
20245
		var BOM = false;
20246
		stream._read = function() {
20247
			if(!BOM) { BOM = true; return stream.push("\uFEFF"); }
20248
			if(R > r.e.r) return stream.push(null);
20249
			while(R <= r.e.r) {
20250
				++R;
20251
				if ((rowinfo[R-1]||{}).hidden) continue;
20252
				row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o);
20253
				if(row != null) {
20254
					if(o.strip) row = row.replace(endregex,"");
20255
					stream.push(row + RS);
20256
					break;
20257
				}
20258
			}
20259
		};
20260
		return stream;
20261
	};
20262
20263
	var write_html_stream = function(ws/*:Worksheet*/, opts/*:?Sheet2HTMLOpts*/) {
20264
		var stream = Readable();
20265
20266
		var o = opts || {};
20267
		var header = o.header != null ? o.header : HTML_.BEGIN;
20268
		var footer = o.footer != null ? o.footer : HTML_.END;
20269
		stream.push(header);
20270
		var r = decode_range(ws['!ref']);
20271
		o.dense = Array.isArray(ws);
20272
		stream.push(HTML_._preamble(ws, r, o));
20273
		var R = r.s.r;
20274
		var end = false;
20275
		stream._read = function() {
20276
			if(R > r.e.r) {
20277
				if(!end) { end = true; stream.push("</table>" + footer); }
20278
				return stream.push(null);
20279
			}
20280
			while(R <= r.e.r) {
20281
				stream.push(HTML_._row(ws, r, R, o));
20282
				++R;
20283
				break;
20284
			}
20285
		};
20286
		return stream;
20287
	};
20288
20289
	var write_json_stream = function(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
20290
		var stream = Readable({objectMode:true});
20291
20292
		if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
20293
		var val = {t:'n',v:0}, header = 0, offset = 1, hdr/*:Array<any>*/ = [], v=0, vv="";
20294
		var r = {s:{r:0,c:0},e:{r:0,c:0}};
20295
		var o = opts || {};
20296
		var range = o.range != null ? o.range : sheet["!ref"];
20297
		if(o.header === 1) header = 1;
20298
		else if(o.header === "A") header = 2;
20299
		else if(Array.isArray(o.header)) header = 3;
20300
		switch(typeof range) {
20301
			case 'string': r = safe_decode_range(range); break;
20302
			case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
20303
			default: r = range;
20304
		}
20305
		if(header > 0) offset = 0;
20306
		var rr = encode_row(r.s.r);
20307
		var cols/*:Array<string>*/ = [];
20308
		var counter = 0;
20309
		var dense = Array.isArray(sheet);
20310
		var R = r.s.r, C = 0, CC = 0;
20311
		if(dense && !sheet[R]) sheet[R] = [];
20312
		for(C = r.s.c; C <= r.e.c; ++C) {
20313
			cols[C] = encode_col(C);
20314
			val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20315
			switch(header) {
20316
				case 1: hdr[C] = C - r.s.c; break;
20317
				case 2: hdr[C] = cols[C]; break;
20318
				case 3: hdr[C] = o.header[C - r.s.c]; break;
20319
				default:
20320
					if(val == null) val = {w: "__EMPTY", t: "s"};
20321
					vv = v = format_cell(val, null, o);
20322
					counter = 0;
20323
					for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
20324
					hdr[C] = vv;
20325
			}
20326
		}
20327
		R = r.s.r + offset;
20328
		stream._read = function() {
20329
			if(R > r.e.r) return stream.push(null);
20330
			while(R <= r.e.r) {
20331
				++R;
20332
				//if ((rowinfo[R-1]||{}).hidden) continue;
20333
				var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
20334
				if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
20335
					stream.push(row.row);
20336
					break;
20337
				}
20338
			}
20339
		};
20340
		return stream;
20341
	};
20342
20343
	XLSX.stream = {
20344
		to_json: write_json_stream,
20345
		to_html: write_html_stream,
20346
		to_csv: write_csv_stream
20347
	};
20348
})();
20349
20350
XLSX.parse_xlscfb = parse_xlscfb;
20351
XLSX.parse_ods = parse_ods;
20352
XLSX.parse_fods = parse_fods;
20353
XLSX.write_ods = write_ods;
20354
XLSX.parse_zip = parse_zip;
20355
XLSX.read = readSync; //xlsread
20356
XLSX.readFile = readFileSync; //readFile
20357
XLSX.readFileSync = readFileSync;
20358
XLSX.write = writeSync;
20359
XLSX.writeFile = writeFileSync;
20360
XLSX.writeFileSync = writeFileSync;
20361
XLSX.writeFileAsync = writeFileAsync;
20362
XLSX.utils = utils;
20363
XLSX.SSF = SSF;
20364
XLSX.CFB = CFB;
20365
}
20366
/*global define */
20367
/*:: declare var define:any; */
20368
if(typeof exports !== 'undefined') make_xlsx_lib(exports);
20369
else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
20370
else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
20371
else make_xlsx_lib(XLSX);
20372
/*exported XLS, ODS */
20373
var XLS = XLSX, ODS = XLSX;
20374

third-party/js-xlsx/js-xlsx-0.13.5/xlsx.js 1 location

@@ 5-20246 (lines=20242) @@
2
/* vim: set ts=2: */
3
/*exported XLSX */
4
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
5
var XLSX = {};
6
function make_xlsx_lib(XLSX){
7
XLSX.version = '0.13.5';
8
var current_codepage = 1200, current_ansi = 1252;
9
/*global cptable:true, window */
10
if(typeof module !== "undefined" && typeof require !== 'undefined') {
11
	if(typeof cptable === 'undefined') {
12
		if(typeof global !== 'undefined') global.cptable = require('./dist/cpexcel.js');
13
		else if(typeof window !== 'undefined') window.cptable = require('./dist/cpexcel.js');
14
	}
15
}
16
17
var VALID_ANSI = [ 874, 932, 936, 949, 950 ];
18
for(var i = 0; i <= 8; ++i) VALID_ANSI.push(1250 + i);
19
/* ECMA-376 Part I 18.4.1 charset to codepage mapping */
20
var CS2CP = ({
21
0:    1252, /* ANSI */
22
1:   65001, /* DEFAULT */
23
2:   65001, /* SYMBOL */
24
77:  10000, /* MAC */
25
128:   932, /* SHIFTJIS */
26
129:   949, /* HANGUL */
27
130:  1361, /* JOHAB */
28
134:   936, /* GB2312 */
29
136:   950, /* CHINESEBIG5 */
30
161:  1253, /* GREEK */
31
162:  1254, /* TURKISH */
32
163:  1258, /* VIETNAMESE */
33
177:  1255, /* HEBREW */
34
178:  1256, /* ARABIC */
35
186:  1257, /* BALTIC */
36
204:  1251, /* RUSSIAN */
37
222:   874, /* THAI */
38
238:  1250, /* EASTEUROPE */
39
255:  1252, /* OEM */
40
69:   6969  /* MISC */
41
});
42
43
var set_ansi = function(cp) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; };
44
function reset_ansi() { set_ansi(1252); }
45
46
var set_cp = function(cp) { current_codepage = cp; set_ansi(cp); };
47
function reset_cp() { set_cp(1200); reset_ansi(); }
48
49
function char_codes(data) { var o = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
50
51
function utf16leread(data) {
52
	var o = [];
53
	for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8));
54
	return o.join("");
55
}
56
function utf16beread(data) {
57
	var o = [];
58
	for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8));
59
	return o.join("");
60
}
61
62
var debom = function(data) {
63
	var c1 = data.charCodeAt(0), c2 = data.charCodeAt(1);
64
	if(c1 == 0xFF && c2 == 0xFE) return utf16leread(data.slice(2));
65
	if(c1 == 0xFE && c2 == 0xFF) return utf16beread(data.slice(2));
66
	if(c1 == 0xFEFF) return data.slice(1);
67
	return data;
68
};
69
70
var _getchar = function _gc1(x) { return String.fromCharCode(x); };
71
if(typeof cptable !== 'undefined') {
72
	set_cp = function(cp) { current_codepage = cp; };
73
	debom = function(data) {
74
		if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.slice(2))); }
75
		return data;
76
	};
77
	_getchar = function _gc2(x) {
78
		if(current_codepage === 1200) return String.fromCharCode(x);
79
		return cptable.utils.decode(current_codepage, [x&255,x>>8])[0];
80
	};
81
}
82
var DENSE = null;
83
var DIF_XL = true;
84
var Base64 = (function make_b64(){
85
	var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
86
	return {
87
		encode: function(input) {
88
			var o = "";
89
			var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
90
			for(var i = 0; i < input.length; ) {
91
				c1 = input.charCodeAt(i++);
92
				e1 = (c1 >> 2);
93
94
				c2 = input.charCodeAt(i++);
95
				e2 = ((c1 & 3) << 4) | (c2 >> 4);
96
97
				c3 = input.charCodeAt(i++);
98
				e3 = ((c2 & 15) << 2) | (c3 >> 6);
99
				e4 = (c3 & 63);
100
				if (isNaN(c2)) { e3 = e4 = 64; }
101
				else if (isNaN(c3)) { e4 = 64; }
102
				o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
103
			}
104
			return o;
105
		},
106
		decode: function b64_decode(input) {
107
			var o = "";
108
			var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
109
			input = input.replace(/[^\w\+\/\=]/g, "");
110
			for(var i = 0; i < input.length;) {
111
				e1 = map.indexOf(input.charAt(i++));
112
				e2 = map.indexOf(input.charAt(i++));
113
				c1 = (e1 << 2) | (e2 >> 4);
114
				o += String.fromCharCode(c1);
115
116
				e3 = map.indexOf(input.charAt(i++));
117
				c2 = ((e2 & 15) << 4) | (e3 >> 2);
118
				if (e3 !== 64) { o += String.fromCharCode(c2); }
119
120
				e4 = map.indexOf(input.charAt(i++));
121
				c3 = ((e3 & 3) << 6) | e4;
122
				if (e4 !== 64) { o += String.fromCharCode(c3); }
123
			}
124
			return o;
125
		}
126
	};
127
})();
128
var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && process.versions.node);
129
130
var Buffer_from = function(){};
131
132
if(typeof Buffer !== 'undefined') {
133
	var nbfs = !Buffer.from;
134
	if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
135
	Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
136
	// $FlowIgnore
137
	if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
138
}
139
140
function new_raw_buf(len) {
141
	/* jshint -W056 */
142
	return has_buf ? Buffer.alloc(len) : new Array(len);
143
	/* jshint +W056 */
144
}
145
146
var s2a = function s2a(s) {
147
	// $FlowIgnore
148
	if(has_buf) return Buffer_from(s, "binary");
149
	return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
150
};
151
152
function s2ab(s) {
153
	if(typeof ArrayBuffer === 'undefined') return s2a(s);
154
	var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
155
	for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
156
	return buf;
157
}
158
159
function a2s(data) {
160
	if(Array.isArray(data)) return data.map(_chr).join("");
161
	var o = []; for(var i = 0; i < data.length; ++i) o[i] = _chr(data[i]); return o.join("");
162
}
163
164
function a2u(data) {
165
	if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
166
	return new Uint8Array(data);
167
}
168
169
function ab2a(data) {
170
	if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
171
	if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
172
var o = new Array(data.length);
173
	for(var i = 0; i < data.length; ++i) o[i] = data[i];
174
	return o;
175
}
176
177
var bconcat = function(bufs) { return [].concat.apply([], bufs); };
178
179
var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
180
/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
181
/*jshint -W041 */
182
var SSF = ({});
183
var make_ssf = function make_ssf(SSF){
184
SSF.version = '0.10.2';
185
function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
186
function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
187
function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
188
function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
189
function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
190
function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
191
function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
192
var p2_32 = Math.pow(2,32);
193
function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
194
function isgeneral(s, i) { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
195
var days = [
196
	['Sun', 'Sunday'],
197
	['Mon', 'Monday'],
198
	['Tue', 'Tuesday'],
199
	['Wed', 'Wednesday'],
200
	['Thu', 'Thursday'],
201
	['Fri', 'Friday'],
202
	['Sat', 'Saturday']
203
];
204
var months = [
205
	['J', 'Jan', 'January'],
206
	['F', 'Feb', 'February'],
207
	['M', 'Mar', 'March'],
208
	['A', 'Apr', 'April'],
209
	['M', 'May', 'May'],
210
	['J', 'Jun', 'June'],
211
	['J', 'Jul', 'July'],
212
	['A', 'Aug', 'August'],
213
	['S', 'Sep', 'September'],
214
	['O', 'Oct', 'October'],
215
	['N', 'Nov', 'November'],
216
	['D', 'Dec', 'December']
217
];
218
function init_table(t) {
219
	t[0]=  'General';
220
	t[1]=  '0';
221
	t[2]=  '0.00';
222
	t[3]=  '#,##0';
223
	t[4]=  '#,##0.00';
224
	t[9]=  '0%';
225
	t[10]= '0.00%';
226
	t[11]= '0.00E+00';
227
	t[12]= '# ?/?';
228
	t[13]= '# ??/??';
229
	t[14]= 'm/d/yy';
230
	t[15]= 'd-mmm-yy';
231
	t[16]= 'd-mmm';
232
	t[17]= 'mmm-yy';
233
	t[18]= 'h:mm AM/PM';
234
	t[19]= 'h:mm:ss AM/PM';
235
	t[20]= 'h:mm';
236
	t[21]= 'h:mm:ss';
237
	t[22]= 'm/d/yy h:mm';
238
	t[37]= '#,##0 ;(#,##0)';
239
	t[38]= '#,##0 ;[Red](#,##0)';
240
	t[39]= '#,##0.00;(#,##0.00)';
241
	t[40]= '#,##0.00;[Red](#,##0.00)';
242
	t[45]= 'mm:ss';
243
	t[46]= '[h]:mm:ss';
244
	t[47]= 'mmss.0';
245
	t[48]= '##0.0E+0';
246
	t[49]= '@';
247
	t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
248
	t[65535]= 'General';
249
}
250
251
var table_fmt = {};
252
init_table(table_fmt);
253
function frac(x, D, mixed) {
254
	var sgn = x < 0 ? -1 : 1;
255
	var B = x * sgn;
256
	var P_2 = 0, P_1 = 1, P = 0;
257
	var Q_2 = 1, Q_1 = 0, Q = 0;
258
	var A = Math.floor(B);
259
	while(Q_1 < D) {
260
		A = Math.floor(B);
261
		P = A * P_1 + P_2;
262
		Q = A * Q_1 + Q_2;
263
		if((B - A) < 0.00000005) break;
264
		B = 1 / (B - A);
265
		P_2 = P_1; P_1 = P;
266
		Q_2 = Q_1; Q_1 = Q;
267
	}
268
	if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
269
	if(!mixed) return [0, sgn * P, Q];
270
	var q = Math.floor(sgn * P/Q);
271
	return [q, sgn*P - q*Q, Q];
272
}
273
function parse_date_code(v,opts,b2) {
274
	if(v > 2958465 || v < 0) return null;
275
	var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
276
	var dout=[];
277
	var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
278
	if(Math.abs(out.u) < 1e-6) out.u = 0;
279
	if(opts && opts.date1904) date += 1462;
280
	if(out.u > 0.9999) {
281
		out.u = 0;
282
		if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
283
	}
284
	if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
285
	else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
286
	else {
287
		if(date > 60) --date;
288
		/* 1 = Jan 1 1900 in Gregorian */
289
		var d = new Date(1900, 0, 1);
290
		d.setDate(d.getDate() + date - 1);
291
		dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
292
		dow = d.getDay();
293
		if(date < 60) dow = (dow + 6) % 7;
294
		if(b2) dow = fix_hijri(d, dout);
295
	}
296
	out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
297
	out.S = time % 60; time = Math.floor(time / 60);
298
	out.M = time % 60; time = Math.floor(time / 60);
299
	out.H = time;
300
	out.q = dow;
301
	return out;
302
}
303
SSF.parse_date_code = parse_date_code;
304
var basedate = new Date(1899, 11, 31, 0, 0, 0);
305
var dnthresh = basedate.getTime();
306
var base1904 = new Date(1900, 2, 1, 0, 0, 0);
307
function datenum_local(v, date1904) {
308
	var epoch = v.getTime();
309
	if(date1904) epoch -= 1461*24*60*60*1000;
310
	else if(v >= base1904) epoch += 24*60*60*1000;
311
	return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
312
}
313
function general_fmt_int(v) { return v.toString(10); }
314
SSF._general_int = general_fmt_int;
315
var general_fmt_num = (function make_general_fmt_num() {
316
var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
317
function gfn2(v) {
318
	var w = (v<0?12:11);
319
	var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
320
	o = v.toPrecision(10); if(o.length <= w) return o;
321
	return v.toExponential(5);
322
}
323
function gfn3(v) {
324
	var o = v.toFixed(11).replace(gnr1,".$1");
325
	if(o.length > (v<0?12:11)) o = v.toPrecision(6);
326
	return o;
327
}
328
function gfn4(o) {
329
	for(var i = 0; i != o.length; ++i) if((o.charCodeAt(i) | 0x20) === 101) return o.replace(gnr4,".$1").replace(gnr5,"E").replace("e","E").replace(gnr6,"$10$2");
330
	return o;
331
}
332
function gfn5(o) {
333
	return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
334
}
335
return function general_fmt_num(v) {
336
	var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
337
	if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
338
	else if(Math.abs(V) <= 9) o = gfn2(v);
339
	else if(V === 10) o = v.toFixed(10).substr(0,12);
340
	else o = gfn3(v);
341
	return gfn5(gfn4(o));
342
};})();
343
SSF._general_num = general_fmt_num;
344
function general_fmt(v, opts) {
345
	switch(typeof v) {
346
		case 'string': return v;
347
		case 'boolean': return v ? "TRUE" : "FALSE";
348
		case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
349
		case 'undefined': return "";
350
		case 'object':
351
			if(v == null) return "";
352
			if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
353
	}
354
	throw new Error("unsupported value in General format: " + v);
355
}
356
SSF._general = general_fmt;
357
function fix_hijri() { return 0; }
358
/*jshint -W086 */
359
function write_date(type, fmt, val, ss0) {
360
	var o="", ss=0, tt=0, y = val.y, out, outl = 0;
361
	switch(type) {
362
		case 98: /* 'b' buddhist year */
363
			y = val.y + 543;
364
			/* falls through */
365
		case 121: /* 'y' year */
366
		switch(fmt.length) {
367
			case 1: case 2: out = y % 100; outl = 2; break;
368
			default: out = y % 10000; outl = 4; break;
369
		} break;
370
		case 109: /* 'm' month */
371
		switch(fmt.length) {
372
			case 1: case 2: out = val.m; outl = fmt.length; break;
373
			case 3: return months[val.m-1][1];
374
			case 5: return months[val.m-1][0];
375
			default: return months[val.m-1][2];
376
		} break;
377
		case 100: /* 'd' day */
378
		switch(fmt.length) {
379
			case 1: case 2: out = val.d; outl = fmt.length; break;
380
			case 3: return days[val.q][0];
381
			default: return days[val.q][1];
382
		} break;
383
		case 104: /* 'h' 12-hour */
384
		switch(fmt.length) {
385
			case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
386
			default: throw 'bad hour format: ' + fmt;
387
		} break;
388
		case 72: /* 'H' 24-hour */
389
		switch(fmt.length) {
390
			case 1: case 2: out = val.H; outl = fmt.length; break;
391
			default: throw 'bad hour format: ' + fmt;
392
		} break;
393
		case 77: /* 'M' minutes */
394
		switch(fmt.length) {
395
			case 1: case 2: out = val.M; outl = fmt.length; break;
396
			default: throw 'bad minute format: ' + fmt;
397
		} break;
398
		case 115: /* 's' seconds */
399
			if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
400
			if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
401
if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
402
			else tt = ss0 === 1 ? 10 : 1;
403
			ss = Math.round((tt)*(val.S + val.u));
404
			if(ss >= 60*tt) ss = 0;
405
			if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
406
			o = pad0(ss,2 + ss0);
407
			if(fmt === 'ss') return o.substr(0,2);
408
			return "." + o.substr(2,fmt.length-1);
409
		case 90: /* 'Z' absolute time */
410
		switch(fmt) {
411
			case '[h]': case '[hh]': out = val.D*24+val.H; break;
412
			case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
413
			case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
414
			default: throw 'bad abstime format: ' + fmt;
415
		} outl = fmt.length === 3 ? 1 : 2; break;
416
		case 101: /* 'e' era */
417
			out = y; outl = 1;
418
	}
419
	if(outl > 0) return pad0(out, outl); else return "";
420
}
421
/*jshint +W086 */
422
function commaify(s) {
423
	var w = 3;
424
	if(s.length <= w) return s;
425
	var j = (s.length % w), o = s.substr(0,j);
426
	for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
427
	return o;
428
}
429
var write_num = (function make_write_num(){
430
var pct1 = /%/g;
431
function write_num_pct(type, fmt, val){
432
	var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
433
	return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
434
}
435
function write_num_cm(type, fmt, val){
436
	var idx = fmt.length - 1;
437
	while(fmt.charCodeAt(idx-1) === 44) --idx;
438
	return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
439
}
440
function write_num_exp(fmt, val){
441
	var o;
442
	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
443
	if(fmt.match(/^#+0.0E\+0$/)) {
444
		if(val == 0) return "0.0E+0";
445
		else if(val < 0) return "-" + write_num_exp(fmt, -val);
446
		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
447
		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
448
		if(ee < 0) ee += period;
449
		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
450
		if(o.indexOf("e") === -1) {
451
			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
452
			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
453
			else o += "E+" + (fakee - ee);
454
			while(o.substr(0,2) === "0.") {
455
				o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
456
				o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
457
			}
458
			o = o.replace(/\+-/,"-");
459
		}
460
		o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
461
	} else o = val.toExponential(idx);
462
	if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
463
	if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
464
	return o.replace("e","E");
465
}
466
var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
467
function write_num_f1(r, aval, sign) {
468
	var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
469
	var myn = (rr - base*den), myd = den;
470
	return sign + (base === 0 ? "" : ""+base) + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad_(myn,r[1].length) + r[2] + "/" + r[3] + pad0(myd,r[4].length));
471
}
472
function write_num_f2(r, aval, sign) {
473
	return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
474
}
475
var dec1 = /^#*0*\.([0#]+)/;
476
var closeparen = /\).*[0#]/;
477
var phone = /\(###\) ###\\?-####/;
478
function hashq(str) {
479
	var o = "", cc;
480
	for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
481
		case 35: break;
482
		case 63: o+= " "; break;
483
		case 48: o+= "0"; break;
484
		default: o+= String.fromCharCode(cc);
485
	}
486
	return o;
487
}
488
function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
489
function dec(val, d) {
490
	if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
491
		return 0;
492
	}
493
	return Math.round((val-Math.floor(val))*Math.pow(10,d));
494
}
495
function carry(val, d) {
496
	if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
497
		return 1;
498
	}
499
	return 0;
500
}
501
function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
502
function write_num_flt(type, fmt, val) {
503
	if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
504
		var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
505
		if(val >= 0) return write_num_flt('n', ffmt, val);
506
		return '(' + write_num_flt('n', ffmt, -val) + ')';
507
	}
508
	if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
509
	if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
510
	if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
511
	if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
512
	var o;
513
	var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
514
	if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
515
	if(fmt.match(/^[#?]+$/)) {
516
		o = pad0r(val,0); if(o === "0") o = "";
517
		return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
518
	}
519
	if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
520
	if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
521
	if((r = fmt.match(dec1))) {
522
		o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
523
		return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
524
	}
525
	fmt = fmt.replace(/^#+([0.])/, "$1");
526
	if((r = fmt.match(/^(0*)\.(#*)$/))) {
527
		return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
528
	}
529
	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
530
	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
531
		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
532
	}
533
	if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
534
	if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
535
		o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
536
		ri = 0;
537
		return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
538
	}
539
	if(fmt.match(phone)) {
540
		o = write_num_flt(type, "##########", val);
541
		return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
542
	}
543
	var oa = "";
544
	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
545
		ri = Math.min(r[4].length,7);
546
		ff = frac(aval, Math.pow(10,ri)-1, false);
547
		o = "" + sign;
548
		oa = write_num("n", r[1], ff[1]);
549
		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
550
		o += oa + r[2] + "/" + r[3];
551
		oa = rpad_(ff[2],ri);
552
		if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
553
		o += oa;
554
		return o;
555
	}
556
	if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
557
		ri = Math.min(Math.max(r[1].length, r[4].length),7);
558
		ff = frac(aval, Math.pow(10,ri)-1, true);
559
		return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
560
	}
561
	if((r = fmt.match(/^[#0?]+$/))) {
562
		o = pad0r(val, 0);
563
		if(fmt.length <= o.length) return o;
564
		return hashq(fmt.substr(0,fmt.length-o.length)) + o;
565
	}
566
	if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
567
		o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
568
		ri = o.indexOf(".");
569
		var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
570
		return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
571
	}
572
	if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
573
		ri = dec(val, r[1].length);
574
		return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
575
	}
576
	switch(fmt) {
577
		case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
578
		case "###,###":
579
		case "##,###":
580
		case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
581
		case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
582
		case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
583
		default:
584
	}
585
	throw new Error("unsupported format |" + fmt + "|");
586
}
587
function write_num_cm2(type, fmt, val){
588
	var idx = fmt.length - 1;
589
	while(fmt.charCodeAt(idx-1) === 44) --idx;
590
	return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
591
}
592
function write_num_pct2(type, fmt, val){
593
	var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
594
	return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
595
}
596
function write_num_exp2(fmt, val){
597
	var o;
598
	var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
599
	if(fmt.match(/^#+0.0E\+0$/)) {
600
		if(val == 0) return "0.0E+0";
601
		else if(val < 0) return "-" + write_num_exp2(fmt, -val);
602
		var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
603
		var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
604
		if(ee < 0) ee += period;
605
		o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
606
		if(!o.match(/[Ee]/)) {
607
			var fakee = Math.floor(Math.log(val)*Math.LOG10E);
608
			if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
609
			else o += "E+" + (fakee - ee);
610
			o = o.replace(/\+-/,"-");
611
		}
612
		o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
613
	} else o = val.toExponential(idx);
614
	if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
615
	if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
616
	return o.replace("e","E");
617
}
618
function write_num_int(type, fmt, val) {
619
	if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
620
		var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
621
		if(val >= 0) return write_num_int('n', ffmt, val);
622
		return '(' + write_num_int('n', ffmt, -val) + ')';
623
	}
624
	if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
625
	if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
626
	if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
627
	if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
628
	var o;
629
	var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
630
	if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
631
	if(fmt.match(/^[#?]+$/)) {
632
		o = (""+val); if(val === 0) o = "";
633
		return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
634
	}
635
	if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
636
	if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
637
	if((r = fmt.match(dec1))) {
638
o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
639
		o = o.replace(/\.(\d*)$/,function($$, $1) {
640
return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
641
		return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
642
	}
643
	fmt = fmt.replace(/^#+([0.])/, "$1");
644
	if((r = fmt.match(/^(0*)\.(#*)$/))) {
645
		return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
646
	}
647
	if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
648
	if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
649
		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
650
	}
651
	if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
652
	if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
653
		o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
654
		ri = 0;
655
		return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
656
	}
657
	if(fmt.match(phone)) {
658
		o = write_num_int(type, "##########", val);
659
		return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
660
	}
661
	var oa = "";
662
	if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
663
		ri = Math.min(r[4].length,7);
664
		ff = frac(aval, Math.pow(10,ri)-1, false);
665
		o = "" + sign;
666
		oa = write_num("n", r[1], ff[1]);
667
		if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
668
		o += oa + r[2] + "/" + r[3];
669
		oa = rpad_(ff[2],ri);
670
		if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
671
		o += oa;
672
		return o;
673
	}
674
	if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
675
		ri = Math.min(Math.max(r[1].length, r[4].length),7);
676
		ff = frac(aval, Math.pow(10,ri)-1, true);
677
		return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
678
	}
679
	if((r = fmt.match(/^[#0?]+$/))) {
680
		o = "" + val;
681
		if(fmt.length <= o.length) return o;
682
		return hashq(fmt.substr(0,fmt.length-o.length)) + o;
683
	}
684
	if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
685
		o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
686
		ri = o.indexOf(".");
687
		var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
688
		return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
689
	}
690
	if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
691
		return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
692
	}
693
	switch(fmt) {
694
		case "###,###":
695
		case "##,###":
696
		case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
697
		default:
698
			if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
699
	}
700
	throw new Error("unsupported format |" + fmt + "|");
701
}
702
return function write_num(type, fmt, val) {
703
	return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
704
};})();
705
function split_fmt(fmt) {
706
	var out = [];
707
	var in_str = false/*, cc*/;
708
	for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
709
		case 34: /* '"' */
710
			in_str = !in_str; break;
711
		case 95: case 42: case 92: /* '_' '*' '\\' */
712
			++i; break;
713
		case 59: /* ';' */
714
			out[out.length] = fmt.substr(j,i-j);
715
			j = i+1;
716
	}
717
	out[out.length] = fmt.substr(j);
718
	if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
719
	return out;
720
}
721
SSF._split = split_fmt;
722
var abstime = /\[[HhMmSs]*\]/;
723
function fmt_is_date(fmt) {
724
	var i = 0, /*cc = 0,*/ c = "", o = "";
725
	while(i < fmt.length) {
726
		switch((c = fmt.charAt(i))) {
727
			case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
728
			case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
729
			case '\\': i+=2; break;
730
			case '_': i+=2; break;
731
			case '@': ++i; break;
732
			case 'B': case 'b':
733
				if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
734
				/* falls through */
735
			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
736
				/* falls through */
737
			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
738
			case 'A': case 'a':
739
				if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
740
				if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
741
				++i; break;
742
			case '[':
743
				o = c;
744
				while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
745
				if(o.match(abstime)) return true;
746
				break;
747
			case '.':
748
				/* falls through */
749
			case '0': case '#':
750
				while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || (c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1))){/* empty */}
751
				break;
752
			case '?': while(fmt.charAt(++i) === c){/* empty */} break;
753
			case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
754
			case '(': case ')': ++i; break;
755
			case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
756
				while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
757
			case ' ': ++i; break;
758
			default: ++i; break;
759
		}
760
	}
761
	return false;
762
}
763
SSF.is_date = fmt_is_date;
764
function eval_fmt(fmt, v, opts, flen) {
765
	var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
766
	var hr='H';
767
	/* Tokenize */
768
	while(i < fmt.length) {
769
		switch((c = fmt.charAt(i))) {
770
			case 'G': /* General */
771
				if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
772
				out[out.length] = {t:'G', v:'General'}; i+=7; break;
773
			case '"': /* Literal text */
774
				for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
775
				out[out.length] = {t:'t', v:o}; ++i; break;
776
			case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
777
				out[out.length] = {t:t, v:w}; ++i; break;
778
			case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
779
			case '@': /* Text Placeholder */
780
				out[out.length] = {t:'T', v:v}; ++i; break;
781
			case 'B': case 'b':
782
				if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
783
					if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
784
					out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
785
				}
786
				/* falls through */
787
			case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
788
				c = c.toLowerCase();
789
				/* falls through */
790
			case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
791
				if(v < 0) return "";
792
				if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
793
				o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
794
				if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
795
				if(c === 'h') c = hr;
796
				out[out.length] = {t:c, v:o}; lst = c; break;
797
			case 'A': case 'a':
798
				var q={t:c, v:c};
799
				if(dt==null) dt=parse_date_code(v, opts);
800
				if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
801
				else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
802
				else { q.t = "t"; ++i; }
803
				if(dt==null && q.t === 'T') return "";
804
				out[out.length] = q; lst = c; break;
805
			case '[':
806
				o = c;
807
				while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
808
				if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
809
				if(o.match(abstime)) {
810
					if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
811
					out[out.length] = {t:'Z', v:o.toLowerCase()};
812
					lst = o.charAt(1);
813
				} else if(o.indexOf("$") > -1) {
814
					o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
815
					if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
816
				}
817
				break;
818
			/* Numbers */
819
			case '.':
820
				if(dt != null) {
821
					o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
822
					out[out.length] = {t:'s', v:o}; break;
823
				}
824
				/* falls through */
825
			case '0': case '#':
826
				o = c; while((++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) || (c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1)) o += c;
827
				out[out.length] = {t:'n', v:o}; break;
828
			case '?':
829
				o = c; while(fmt.charAt(++i) === c) o+=c;
830
				out[out.length] = {t:c, v:o}; lst = c; break;
831
			case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
832
			case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
833
			case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
834
				o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
835
				out[out.length] = {t:'D', v:o}; break;
836
			case ' ': out[out.length] = {t:c, v:c}; ++i; break;
837
			default:
838
				if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
839
				out[out.length] = {t:'t', v:c}; ++i; break;
840
		}
841
	}
842
	var bt = 0, ss0 = 0, ssm;
843
	for(i=out.length-1, lst='t'; i >= 0; --i) {
844
		switch(out[i].t) {
845
			case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
846
			case 's':
847
				if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
848
				if(bt < 3) bt = 3;
849
			/* falls through */
850
			case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
851
			case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
852
			case 'X': /*if(out[i].v === "B2");*/
853
				break;
854
			case 'Z':
855
				if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
856
				if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
857
				if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
858
		}
859
	}
860
	switch(bt) {
861
		case 0: break;
862
		case 1:
863
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
864
			if(dt.S >=  60) { dt.S = 0; ++dt.M; }
865
			if(dt.M >=  60) { dt.M = 0; ++dt.H; }
866
			break;
867
		case 2:
868
if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
869
			if(dt.S >=  60) { dt.S = 0; ++dt.M; }
870
			break;
871
	}
872
	/* replace fields */
873
	var nstr = "", jj;
874
	for(i=0; i < out.length; ++i) {
875
		switch(out[i].t) {
876
			case 't': case 'T': case ' ': case 'D': break;
877
			case 'X': out[i].v = ""; out[i].t = ";"; break;
878
			case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
879
out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
880
				out[i].t = 't'; break;
881
			case 'n': case '(': case '?':
882
				jj = i+1;
883
				while(out[jj] != null && (
884
					(c=out[jj].t) === "?" || c === "D" ||
885
					((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
886
					(out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
887
					(c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
888
				)) {
889
					out[i].v += out[jj].v;
890
					out[jj] = {v:"", t:";"}; ++jj;
891
				}
892
				nstr += out[i].v;
893
				i = jj-1; break;
894
			case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
895
		}
896
	}
897
	var vv = "", myv, ostr;
898
	if(nstr.length > 0) {
899
		if(nstr.charCodeAt(0) == 40) /* '(' */ {
900
			myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
901
			ostr = write_num('(', nstr, myv);
902
		} else {
903
			myv = (v<0 && flen > 1 ? -v : v);
904
			ostr = write_num('n', nstr, myv);
905
			if(myv < 0 && out[0] && out[0].t == 't') {
906
				ostr = ostr.substr(1);
907
				out[0].v = "-" + out[0].v;
908
			}
909
		}
910
		jj=ostr.length-1;
911
		var decpt = out.length;
912
		for(i=0; i < out.length; ++i) if(out[i] != null && out[i].t != 't' && out[i].v.indexOf(".") > -1) { decpt = i; break; }
913
		var lasti=out.length;
914
		if(decpt === out.length && ostr.indexOf("E") === -1) {
915
			for(i=out.length-1; i>= 0;--i) {
916
				if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
917
				if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
918
				else if(jj < 0) out[i].v = "";
919
				else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
920
				out[i].t = 't';
921
				lasti = i;
922
			}
923
			if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
924
		}
925
		else if(decpt !== out.length && ostr.indexOf("E") === -1) {
926
			jj = ostr.indexOf(".")-1;
927
			for(i=decpt; i>= 0; --i) {
928
				if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
929
				j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
930
				vv = out[i].v.substr(j+1);
931
				for(; j>=0; --j) {
932
					if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
933
				}
934
				out[i].v = vv;
935
				out[i].t = 't';
936
				lasti = i;
937
			}
938
			if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
939
			jj = ostr.indexOf(".")+1;
940
			for(i=decpt; i<out.length; ++i) {
941
				if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
942
				j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
943
				vv = out[i].v.substr(0,j);
944
				for(; j<out[i].v.length; ++j) {
945
					if(jj<ostr.length) vv += ostr.charAt(jj++);
946
				}
947
				out[i].v = vv;
948
				out[i].t = 't';
949
				lasti = i;
950
			}
951
		}
952
	}
953
	for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
954
		myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
955
		out[i].v = write_num(out[i].t, out[i].v, myv);
956
		out[i].t = 't';
957
	}
958
	var retval = "";
959
	for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
960
	return retval;
961
}
962
SSF._eval = eval_fmt;
963
var cfregex = /\[[=<>]/;
964
var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
965
function chkcond(v, rr) {
966
	if(rr == null) return false;
967
	var thresh = parseFloat(rr[2]);
968
	switch(rr[1]) {
969
		case "=":  if(v == thresh) return true; break;
970
		case ">":  if(v >  thresh) return true; break;
971
		case "<":  if(v <  thresh) return true; break;
972
		case "<>": if(v != thresh) return true; break;
973
		case ">=": if(v >= thresh) return true; break;
974
		case "<=": if(v <= thresh) return true; break;
975
	}
976
	return false;
977
}
978
function choose_fmt(f, v) {
979
	var fmt = split_fmt(f);
980
	var l = fmt.length, lat = fmt[l-1].indexOf("@");
981
	if(l<4 && lat>-1) --l;
982
	if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
983
	if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
984
	switch(fmt.length) {
985
		case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
986
		case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
987
		case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
988
		case 4: break;
989
	}
990
	var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
991
	if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
992
	if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
993
		var m1 = fmt[0].match(cfregex2);
994
		var m2 = fmt[1].match(cfregex2);
995
		return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
996
	}
997
	return [l, ff];
998
}
999
function format(fmt,v,o) {
1000
	if(o == null) o = {};
1001
	var sfmt = "";
1002
	switch(typeof fmt) {
1003
		case "string":
1004
			if(fmt == "m/d/yy" && o.dateNF) sfmt = o.dateNF;
1005
			else sfmt = fmt;
1006
			break;
1007
		case "number":
1008
			if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
1009
			else sfmt = (o.table != null ? (o.table) : table_fmt)[fmt];
1010
			break;
1011
	}
1012
	if(isgeneral(sfmt,0)) return general_fmt(v, o);
1013
	if(v instanceof Date) v = datenum_local(v, o.date1904);
1014
	var f = choose_fmt(sfmt, v);
1015
	if(isgeneral(f[1])) return general_fmt(v, o);
1016
	if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
1017
	else if(v === "" || v == null) return "";
1018
	return eval_fmt(f[1], v, o, f[0]);
1019
}
1020
function load_entry(fmt, idx) {
1021
	if(typeof idx != 'number') {
1022
		idx = +idx || -1;
1023
for(var i = 0; i < 0x0188; ++i) {
1024
if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
1025
			if(table_fmt[i] == fmt) { idx = i; break; }
1026
		}
1027
if(idx < 0) idx = 0x187;
1028
	}
1029
table_fmt[idx] = fmt;
1030
	return idx;
1031
}
1032
SSF.load = load_entry;
1033
SSF._table = table_fmt;
1034
SSF.get_table = function get_table() { return table_fmt; };
1035
SSF.load_table = function load_table(tbl) {
1036
	for(var i=0; i!=0x0188; ++i)
1037
		if(tbl[i] !== undefined) load_entry(tbl[i], i);
1038
};
1039
SSF.init_table = init_table;
1040
SSF.format = format;
1041
};
1042
make_ssf(SSF);
1043
/* map from xlml named formats to SSF TODO: localize */
1044
var XLMLFormatMap/*{[string]:string}*/ = ({
1045
	"General Number": "General",
1046
	"General Date": SSF._table[22],
1047
	"Long Date": "dddd, mmmm dd, yyyy",
1048
	"Medium Date": SSF._table[15],
1049
	"Short Date": SSF._table[14],
1050
	"Long Time": SSF._table[19],
1051
	"Medium Time": SSF._table[18],
1052
	"Short Time": SSF._table[20],
1053
	"Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1054
	"Fixed": SSF._table[2],
1055
	"Standard": SSF._table[4],
1056
	"Percent": SSF._table[10],
1057
	"Scientific": SSF._table[11],
1058
	"Yes/No": '"Yes";"Yes";"No";@',
1059
	"True/False": '"True";"True";"False";@',
1060
	"On/Off": '"Yes";"Yes";"No";@'
1061
});
1062
1063
var SSFImplicit/*{[number]:string}*/ = ({
1064
	"5": '"$"#,##0_);\\("$"#,##0\\)',
1065
	"6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1066
	"7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1067
	"8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1068
	"23": 'General', "24": 'General', "25": 'General', "26": 'General',
1069
	"27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
1070
	"32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
1071
	"36": 'm/d/yy',
1072
	"41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
1073
	"42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
1074
	"43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
1075
	"44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
1076
	"50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
1077
	"55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
1078
	"59": '0',
1079
	"60": '0.00',
1080
	"61": '#,##0',
1081
	"62": '#,##0.00',
1082
	"63": '"$"#,##0_);\\("$"#,##0\\)',
1083
	"64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1084
	"65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1085
	"66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1086
	"67": '0%',
1087
	"68": '0.00%',
1088
	"69": '# ?/?',
1089
	"70": '# ??/??',
1090
	"71": 'm/d/yy',
1091
	"72": 'm/d/yy',
1092
	"73": 'd-mmm-yy',
1093
	"74": 'd-mmm',
1094
	"75": 'mmm-yy',
1095
	"76": 'h:mm',
1096
	"77": 'h:mm:ss',
1097
	"78": 'm/d/yy h:mm',
1098
	"79": 'mm:ss',
1099
	"80": '[h]:mm:ss',
1100
	"81": 'mmss.0'
1101
});
1102
1103
/* dateNF parse TODO: move to SSF */
1104
var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
1105
function dateNF_regex(dateNF) {
1106
	var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF;
1107
	fmt = fmt.replace(dateNFregex, "(\\d+)");
1108
	return new RegExp("^" + fmt + "$");
1109
}
1110
function dateNF_fix(str, dateNF, match) {
1111
	var Y = -1, m = -1, d = -1, H = -1, M = -1, S = -1;
1112
	(dateNF.match(dateNFregex)||[]).forEach(function(n, i) {
1113
		var v = parseInt(match[i+1], 10);
1114
		switch(n.toLowerCase().charAt(0)) {
1115
			case 'y': Y = v; break; case 'd': d = v; break;
1116
			case 'h': H = v; break; case 's': S = v; break;
1117
			case 'm': if(H >= 0) M = v; else m = v; break;
1118
		}
1119
	});
1120
	if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
1121
	var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
1122
	if(datestr.length == 7) datestr = "0" + datestr;
1123
	if(datestr.length == 8) datestr = "20" + datestr;
1124
	var timestr = (("00" + (H>=0?H:0)).slice(-2) + ":" + ("00" + (M>=0?M:0)).slice(-2) + ":" + ("00" + (S>=0?S:0)).slice(-2));
1125
	if(H == -1 && M == -1 && S == -1) return datestr;
1126
	if(Y == -1 && m == -1 && d == -1) return timestr;
1127
	return datestr + "T" + timestr;
1128
}
1129
1130
var DO_NOT_EXPORT_CFB = true;
1131
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
1132
/* vim: set ts=2: */
1133
/*jshint eqnull:true */
1134
/*exported CFB */
1135
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
1136
1137
/* [MS-CFB] v20171201 */
1138
var CFB = (function _CFB(){
1139
var exports = {};
1140
exports.version = '1.0.8';
1141
/* [MS-CFB] 2.6.4 */
1142
function namecmp(l, r) {
1143
	var L = l.split("/"), R = r.split("/");
1144
	for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
1145
		if((c = L[i].length - R[i].length)) return c;
1146
		if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
1147
	}
1148
	return L.length - R.length;
1149
}
1150
function dirname(p) {
1151
	if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
1152
	var c = p.lastIndexOf("/");
1153
	return (c === -1) ? p : p.slice(0, c+1);
1154
}
1155
1156
function filename(p) {
1157
	if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
1158
	var c = p.lastIndexOf("/");
1159
	return (c === -1) ? p : p.slice(c+1);
1160
}
1161
var fs;
1162
function get_fs() { return fs || (fs = require('fs')); }
1163
function parse(file, options) {
1164
if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
1165
var mver = 3;
1166
var ssz = 512;
1167
var nmfs = 0; // number of mini FAT sectors
1168
var difat_sec_cnt = 0;
1169
var dir_start = 0;
1170
var minifat_start = 0;
1171
var difat_start = 0;
1172
1173
var fat_addrs = []; // locations of FAT sectors
1174
1175
/* [MS-CFB] 2.2 Compound File Header */
1176
var blob = file.slice(0,512);
1177
prep_blob(blob, 0);
1178
1179
/* major version */
1180
var mv = check_get_mver(blob);
1181
mver = mv[0];
1182
switch(mver) {
1183
	case 3: ssz = 512; break; case 4: ssz = 4096; break;
1184
	default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
1185
}
1186
1187
/* reprocess header */
1188
if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
1189
/* Save header for final object */
1190
var header = file.slice(0,ssz);
1191
1192
check_shifts(blob, mver);
1193
1194
// Number of Directory Sectors
1195
var dir_cnt = blob.read_shift(4, 'i');
1196
if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
1197
1198
// Number of FAT Sectors
1199
blob.l += 4;
1200
1201
// First Directory Sector Location
1202
dir_start = blob.read_shift(4, 'i');
1203
1204
// Transaction Signature
1205
blob.l += 4;
1206
1207
// Mini Stream Cutoff Size
1208
blob.chk('00100000', 'Mini Stream Cutoff Size: ');
1209
1210
// First Mini FAT Sector Location
1211
minifat_start = blob.read_shift(4, 'i');
1212
1213
// Number of Mini FAT Sectors
1214
nmfs = blob.read_shift(4, 'i');
1215
1216
// First DIFAT sector location
1217
difat_start = blob.read_shift(4, 'i');
1218
1219
// Number of DIFAT Sectors
1220
difat_sec_cnt = blob.read_shift(4, 'i');
1221
1222
// Grab FAT Sector Locations
1223
for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
1224
	q = blob.read_shift(4, 'i');
1225
	if(q<0) break;
1226
	fat_addrs[j] = q;
1227
}
1228
1229
/** Break the file up into sectors */
1230
var sectors = sectorify(file, ssz);
1231
1232
sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
1233
1234
/** Chains */
1235
var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);
1236
1237
sector_list[dir_start].name = "!Directory";
1238
if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
1239
sector_list[fat_addrs[0]].name = "!FAT";
1240
sector_list.fat_addrs = fat_addrs;
1241
sector_list.ssz = ssz;
1242
1243
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1244
var files = {}, Paths = [], FileIndex = [], FullPaths = [];
1245
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
1246
1247
build_full_paths(FileIndex, FullPaths, Paths);
1248
Paths.shift();
1249
1250
var o = {
1251
	FileIndex: FileIndex,
1252
	FullPaths: FullPaths
1253
};
1254
1255
// $FlowIgnore
1256
if(options && options.raw) o.raw = {header: header, sectors: sectors};
1257
return o;
1258
} // parse
1259
1260
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
1261
function check_get_mver(blob) {
1262
	// header signature 8
1263
	blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
1264
1265
	// clsid 16
1266
	blob.chk(HEADER_CLSID, 'CLSID: ');
1267
1268
	// minor version 2
1269
	var mver = blob.read_shift(2, 'u');
1270
1271
	return [blob.read_shift(2,'u'), mver];
1272
}
1273
function check_shifts(blob, mver) {
1274
	var shift = 0x09;
1275
1276
	// Byte Order
1277
	//blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff
1278
	blob.l += 2;
1279
1280
	// Sector Shift
1281
	switch((shift = blob.read_shift(2))) {
1282
		case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;
1283
		case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;
1284
		default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);
1285
	}
1286
1287
	// Mini Sector Shift
1288
	blob.chk('0600', 'Mini Sector Shift: ');
1289
1290
	// Reserved
1291
	blob.chk('000000000000', 'Reserved: ');
1292
}
1293
1294
/** Break the file up into sectors */
1295
function sectorify(file, ssz) {
1296
	var nsectors = Math.ceil(file.length/ssz)-1;
1297
	var sectors = [];
1298
	for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
1299
	sectors[nsectors-1] = file.slice(nsectors*ssz);
1300
	return sectors;
1301
}
1302
1303
/* [MS-CFB] 2.6.4 Red-Black Tree */
1304
function build_full_paths(FI, FP, Paths) {
1305
	var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
1306
	var dad = [], q = [];
1307
1308
	for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
1309
1310
	for(; j < q.length; ++j) {
1311
		i = q[j];
1312
		L = FI[i].L; R = FI[i].R; C = FI[i].C;
1313
		if(dad[i] === i) {
1314
			if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
1315
			if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
1316
		}
1317
		if(C !== -1 /*NOSTREAM*/) dad[C] = i;
1318
		if(L !== -1) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
1319
		if(R !== -1) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
1320
	}
1321
	for(i=1; i < pl; ++i) if(dad[i] === i) {
1322
		if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
1323
		else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
1324
	}
1325
1326
	for(i=1; i < pl; ++i) {
1327
		if(FI[i].type === 0 /* unknown */) continue;
1328
		j = dad[i];
1329
		if(j === 0) FP[i] = FP[0] + "/" + FP[i];
1330
		else while(j !== 0 && j !== dad[j]) {
1331
			FP[i] = FP[j] + "/" + FP[i];
1332
			j = dad[j];
1333
		}
1334
		dad[i] = 0;
1335
	}
1336
1337
	FP[0] += "/";
1338
	for(i=1; i < pl; ++i) {
1339
		if(FI[i].type !== 2 /* stream */) FP[i] += "/";
1340
	}
1341
}
1342
1343
function get_mfat_entry(entry, payload, mini) {
1344
	var start = entry.start, size = entry.size;
1345
	//return (payload.slice(start*MSSZ, start*MSSZ + size));
1346
	var o = [];
1347
	var idx = start;
1348
	while(mini && size > 0 && idx >= 0) {
1349
		o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
1350
		size -= MSSZ;
1351
		idx = __readInt32LE(mini, idx * 4);
1352
	}
1353
	if(o.length === 0) return (new_buf(0));
1354
	return (bconcat(o).slice(0, entry.size));
1355
}
1356
1357
/** Chase down the rest of the DIFAT chain to build a comprehensive list
1358
    DIFAT chains by storing the next sector number as the last 32 bits */
1359
function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
1360
	var q = ENDOFCHAIN;
1361
	if(idx === ENDOFCHAIN) {
1362
		if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
1363
	} else if(idx !== -1 /*FREESECT*/) {
1364
		var sector = sectors[idx], m = (ssz>>>2)-1;
1365
		if(!sector) return;
1366
		for(var i = 0; i < m; ++i) {
1367
			if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1368
			fat_addrs.push(q);
1369
		}
1370
		sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
1371
	}
1372
}
1373
1374
/** Follow the linked list of sectors for a given starting point */
1375
function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
1376
	var buf = [], buf_chain = [];
1377
	if(!chkd) chkd = [];
1378
	var modulus = ssz - 1, j = 0, jj = 0;
1379
	for(j=start; j>=0;) {
1380
		chkd[j] = true;
1381
		buf[buf.length] = j;
1382
		buf_chain.push(sectors[j]);
1383
		var addr = fat_addrs[Math.floor(j*4/ssz)];
1384
		jj = ((j*4) & modulus);
1385
		if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1386
		if(!sectors[addr]) break;
1387
		j = __readInt32LE(sectors[addr], jj);
1388
	}
1389
	return {nodes: buf, data:__toBuffer([buf_chain])};
1390
}
1391
1392
/** Chase down the sector linked lists */
1393
function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
1394
	var sl = sectors.length, sector_list = ([]);
1395
	var chkd = [], buf = [], buf_chain = [];
1396
	var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
1397
	for(i=0; i < sl; ++i) {
1398
		buf = ([]);
1399
		k = (i + dir_start); if(k >= sl) k-=sl;
1400
		if(chkd[k]) continue;
1401
		buf_chain = [];
1402
		for(j=k; j>=0;) {
1403
			chkd[j] = true;
1404
			buf[buf.length] = j;
1405
			buf_chain.push(sectors[j]);
1406
			var addr = fat_addrs[Math.floor(j*4/ssz)];
1407
			jj = ((j*4) & modulus);
1408
			if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1409
			if(!sectors[addr]) break;
1410
			j = __readInt32LE(sectors[addr], jj);
1411
		}
1412
		sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
1413
	}
1414
	return sector_list;
1415
}
1416
1417
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1418
function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {
1419
	var minifat_store = 0, pl = (Paths.length?2:0);
1420
	var sector = sector_list[dir_start].data;
1421
	var i = 0, namelen = 0, name;
1422
	for(; i < sector.length; i+= 128) {
1423
		var blob = sector.slice(i, i+128);
1424
		prep_blob(blob, 64);
1425
		namelen = blob.read_shift(2);
1426
		name = __utf16le(blob,0,namelen-pl);
1427
		Paths.push(name);
1428
		var o = ({
1429
			name:  name,
1430
			type:  blob.read_shift(1),
1431
			color: blob.read_shift(1),
1432
			L:     blob.read_shift(4, 'i'),
1433
			R:     blob.read_shift(4, 'i'),
1434
			C:     blob.read_shift(4, 'i'),
1435
			clsid: blob.read_shift(16),
1436
			state: blob.read_shift(4, 'i'),
1437
			start: 0,
1438
			size: 0
1439
		});
1440
		var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1441
		if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1442
		var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1443
		if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1444
		o.start = blob.read_shift(4, 'i');
1445
		o.size = blob.read_shift(4, 'i');
1446
		if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1447
		if(o.type === 5) { /* root */
1448
			minifat_store = o.start;
1449
			if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1450
			/*minifat_size = o.size;*/
1451
		} else if(o.size >= 4096 /* MSCSZ */) {
1452
			o.storage = 'fat';
1453
			if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1454
			sector_list[o.start].name = o.name;
1455
			o.content = (sector_list[o.start].data.slice(0,o.size));
1456
		} else {
1457
			o.storage = 'minifat';
1458
			if(o.size < 0) o.size = 0;
1459
			else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1460
				o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1461
			}
1462
		}
1463
		if(o.content) prep_blob(o.content, 0);
1464
		files[name] = o;
1465
		FileIndex.push(o);
1466
	}
1467
}
1468
1469
function read_date(blob, offset) {
1470
	return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1471
}
1472
1473
function read_file(filename, options) {
1474
	get_fs();
1475
	return parse(fs.readFileSync(filename), options);
1476
}
1477
1478
function read(blob, options) {
1479
	switch(options && options.type || "base64") {
1480
		case "file": return read_file(blob, options);
1481
		case "base64": return parse(s2a(Base64.decode(blob)), options);
1482
		case "binary": return parse(s2a(blob), options);
1483
	}
1484
	return parse(blob, options);
1485
}
1486
1487
function init_cfb(cfb, opts) {
1488
	var o = opts || {}, root = o.root || "Root Entry";
1489
	if(!cfb.FullPaths) cfb.FullPaths = [];
1490
	if(!cfb.FileIndex) cfb.FileIndex = [];
1491
	if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1492
	if(cfb.FullPaths.length === 0) {
1493
		cfb.FullPaths[0] = root + "/";
1494
		cfb.FileIndex[0] = ({ name: root, type: 5 });
1495
	}
1496
	if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1497
	seed_cfb(cfb);
1498
}
1499
function seed_cfb(cfb) {
1500
	var nm = "\u0001Sh33tJ5";
1501
	if(CFB.find(cfb, "/" + nm)) return;
1502
	var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1503
	cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));
1504
	cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1505
	rebuild_cfb(cfb);
1506
}
1507
function rebuild_cfb(cfb, f) {
1508
	init_cfb(cfb);
1509
	var gc = false, s = false;
1510
	for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1511
		var _file = cfb.FileIndex[i];
1512
		switch(_file.type) {
1513
			case 0:
1514
				if(s) gc = true;
1515
				else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1516
				break;
1517
			case 1: case 2: case 5:
1518
				s = true;
1519
				if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1520
				if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1521
				break;
1522
			default: gc = true; break;
1523
		}
1524
	}
1525
	if(!gc && !f) return;
1526
1527
	var now = new Date(1987, 1, 19), j = 0;
1528
	var data = [];
1529
	for(i = 0; i < cfb.FullPaths.length; ++i) {
1530
		if(cfb.FileIndex[i].type === 0) continue;
1531
		data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1532
	}
1533
	for(i = 0; i < data.length; ++i) {
1534
		var dad = dirname(data[i][0]);
1535
		s = false;
1536
		for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1537
		if(!s) data.push([dad, ({
1538
			name: filename(dad).replace("/",""),
1539
			type: 1,
1540
			clsid: HEADER_CLSID,
1541
			ct: now, mt: now,
1542
			content: null
1543
		})]);
1544
	}
1545
1546
	data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1547
	cfb.FullPaths = []; cfb.FileIndex = [];
1548
	for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1549
	for(i = 0; i < data.length; ++i) {
1550
		var elt = cfb.FileIndex[i];
1551
		var nm = cfb.FullPaths[i];
1552
1553
		elt.name =  filename(nm).replace("/","");
1554
		elt.L = elt.R = elt.C = -(elt.color = 1);
1555
		elt.size = elt.content ? elt.content.length : 0;
1556
		elt.start = 0;
1557
		elt.clsid = (elt.clsid || HEADER_CLSID);
1558
		if(i === 0) {
1559
			elt.C = data.length > 1 ? 1 : -1;
1560
			elt.size = 0;
1561
			elt.type = 5;
1562
		} else if(nm.slice(-1) == "/") {
1563
			for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1564
			elt.C = j >= data.length ? -1 : j;
1565
			for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1566
			elt.R = j >= data.length ? -1 : j;
1567
			elt.type = 1;
1568
		} else {
1569
			if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1570
			elt.type = 2;
1571
		}
1572
	}
1573
1574
}
1575
1576
function _write(cfb, options) {
1577
	var _opts = options || {};
1578
	rebuild_cfb(cfb);
1579
	var L = (function(cfb){
1580
		var mini_size = 0, fat_size = 0;
1581
		for(var i = 0; i < cfb.FileIndex.length; ++i) {
1582
			var file = cfb.FileIndex[i];
1583
			if(!file.content) continue;
1584
var flen = file.content.length;
1585
			if(flen > 0){
1586
				if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1587
				else fat_size += (flen + 0x01FF) >> 9;
1588
			}
1589
		}
1590
		var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1591
		var mini_cnt = (mini_size + 7) >> 3;
1592
		var mfat_cnt = (mini_size + 0x7F) >> 7;
1593
		var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1594
		var fat_cnt = (fat_base + 0x7F) >> 7;
1595
		var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1596
		while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1597
		var L =  [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1598
		cfb.FileIndex[0].size = mini_size << 6;
1599
		L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1600
		return L;
1601
	})(cfb);
1602
	var o = new_buf(L[7] << 9);
1603
	var i = 0, T = 0;
1604
	{
1605
		for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1606
		for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1607
		o.write_shift(2, 0x003E);
1608
		o.write_shift(2, 0x0003);
1609
		o.write_shift(2, 0xFFFE);
1610
		o.write_shift(2, 0x0009);
1611
		o.write_shift(2, 0x0006);
1612
		for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1613
		o.write_shift(4, 0);
1614
		o.write_shift(4, L[2]);
1615
		o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1616
		o.write_shift(4, 0);
1617
		o.write_shift(4, 1<<12);
1618
		o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1619
		o.write_shift(4, L[3]);
1620
		o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1621
		o.write_shift(4, L[1]);
1622
		for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1623
	}
1624
	if(L[1]) {
1625
		for(T = 0; T < L[1]; ++T) {
1626
			for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1627
			o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1628
		}
1629
	}
1630
	var chainit = function(w) {
1631
		for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1632
		if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1633
	};
1634
	T = i = 0;
1635
	for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1636
	for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1637
	chainit(L[3]);
1638
	chainit(L[4]);
1639
	var j = 0, flen = 0;
1640
	var file = cfb.FileIndex[0];
1641
	for(; j < cfb.FileIndex.length; ++j) {
1642
		file = cfb.FileIndex[j];
1643
		if(!file.content) continue;
1644
flen = file.content.length;
1645
		if(flen < 0x1000) continue;
1646
		file.start = T;
1647
		chainit((flen + 0x01FF) >> 9);
1648
	}
1649
	chainit((L[6] + 7) >> 3);
1650
	while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1651
	T = i = 0;
1652
	for(j = 0; j < cfb.FileIndex.length; ++j) {
1653
		file = cfb.FileIndex[j];
1654
		if(!file.content) continue;
1655
flen = file.content.length;
1656
		if(!flen || flen >= 0x1000) continue;
1657
		file.start = T;
1658
		chainit((flen + 0x3F) >> 6);
1659
	}
1660
	while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1661
	for(i = 0; i < L[4]<<2; ++i) {
1662
		var nm = cfb.FullPaths[i];
1663
		if(!nm || nm.length === 0) {
1664
			for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1665
			for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1666
			for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1667
			continue;
1668
		}
1669
		file = cfb.FileIndex[i];
1670
		if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1671
		var _nm = (i === 0 && _opts.root) || file.name;
1672
		flen = 2*(_nm.length+1);
1673
		o.write_shift(64, _nm, "utf16le");
1674
		o.write_shift(2, flen);
1675
		o.write_shift(1, file.type);
1676
		o.write_shift(1, file.color);
1677
		o.write_shift(-4, file.L);
1678
		o.write_shift(-4, file.R);
1679
		o.write_shift(-4, file.C);
1680
		if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1681
		else o.write_shift(16, file.clsid, "hex");
1682
		o.write_shift(4, file.state || 0);
1683
		o.write_shift(4, 0); o.write_shift(4, 0);
1684
		o.write_shift(4, 0); o.write_shift(4, 0);
1685
		o.write_shift(4, file.start);
1686
		o.write_shift(4, file.size); o.write_shift(4, 0);
1687
	}
1688
	for(i = 1; i < cfb.FileIndex.length; ++i) {
1689
		file = cfb.FileIndex[i];
1690
if(file.size >= 0x1000) {
1691
			o.l = (file.start+1) << 9;
1692
			for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1693
			for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1694
		}
1695
	}
1696
	for(i = 1; i < cfb.FileIndex.length; ++i) {
1697
		file = cfb.FileIndex[i];
1698
if(file.size > 0 && file.size < 0x1000) {
1699
			for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1700
			for(; j & 0x3F; ++j) o.write_shift(1, 0);
1701
		}
1702
	}
1703
	while(o.l < o.length) o.write_shift(1, 0);
1704
	return o;
1705
}
1706
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1707
function find(cfb, path) {
1708
	var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1709
	var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1710
	var k = false;
1711
	if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1712
	else k = path.indexOf("/") !== -1;
1713
	var UCPath = path.toUpperCase();
1714
	var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1715
	if(w !== -1) return cfb.FileIndex[w];
1716
1717
	var m = !UCPath.match(chr1);
1718
	UCPath = UCPath.replace(chr0,'');
1719
	if(m) UCPath = UCPath.replace(chr1,'!');
1720
	for(w = 0; w < UCFullPaths.length; ++w) {
1721
		if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1722
		if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1723
	}
1724
	return null;
1725
}
1726
/** CFB Constants */
1727
var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1728
//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1729
/* 2.1 Compound File Sector Numbers and Types */
1730
var ENDOFCHAIN = -2;
1731
/* 2.2 Compound File Header */
1732
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1733
var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1734
var HEADER_CLSID = '00000000000000000000000000000000';
1735
var consts = {
1736
	/* 2.1 Compund File Sector Numbers and Types */
1737
	MAXREGSECT: -6,
1738
	DIFSECT: -4,
1739
	FATSECT: -3,
1740
	ENDOFCHAIN: ENDOFCHAIN,
1741
	FREESECT: -1,
1742
	/* 2.2 Compound File Header */
1743
	HEADER_SIGNATURE: HEADER_SIGNATURE,
1744
	HEADER_MINOR_VERSION: '3e00',
1745
	MAXREGSID: -6,
1746
	NOSTREAM: -1,
1747
	HEADER_CLSID: HEADER_CLSID,
1748
	/* 2.6.1 Compound File Directory Entry */
1749
	EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
1750
};
1751
1752
function write_file(cfb, filename, options) {
1753
	get_fs();
1754
	var o = _write(cfb, options);
1755
fs.writeFileSync(filename, o);
1756
}
1757
1758
function a2s(o) {
1759
	var out = new Array(o.length);
1760
	for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
1761
	return out.join("");
1762
}
1763
1764
function write(cfb, options) {
1765
	var o = _write(cfb, options);
1766
	switch(options && options.type) {
1767
		case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
1768
		case "binary": return a2s(o);
1769
		case "base64": return Base64.encode(a2s(o));
1770
	}
1771
	return o;
1772
}
1773
function cfb_new(opts) {
1774
	var o = ({});
1775
	init_cfb(o, opts);
1776
	return o;
1777
}
1778
1779
function cfb_add(cfb, name, content, opts) {
1780
	var unsafe = opts && opts.unsafe;
1781
	if(!unsafe) init_cfb(cfb);
1782
	var file = !unsafe && CFB.find(cfb, name);
1783
	if(!file) {
1784
		var fpath = cfb.FullPaths[0];
1785
		if(name.slice(0, fpath.length) == fpath) fpath = name;
1786
		else {
1787
			if(fpath.slice(-1) != "/") fpath += "/";
1788
			fpath = (fpath + name).replace("//","/");
1789
		}
1790
		file = ({name: filename(name), type: 2});
1791
		cfb.FileIndex.push(file);
1792
		cfb.FullPaths.push(fpath);
1793
		if(!unsafe) CFB.utils.cfb_gc(cfb);
1794
	}
1795
file.content = (content);
1796
	file.size = content ? content.length : 0;
1797
	if(opts) {
1798
		if(opts.CLSID) file.clsid = opts.CLSID;
1799
	}
1800
	return file;
1801
}
1802
1803
function cfb_del(cfb, name) {
1804
	init_cfb(cfb);
1805
	var file = CFB.find(cfb, name);
1806
	if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
1807
		cfb.FileIndex.splice(j, 1);
1808
		cfb.FullPaths.splice(j, 1);
1809
		return true;
1810
	}
1811
	return false;
1812
}
1813
1814
function cfb_mov(cfb, old_name, new_name) {
1815
	init_cfb(cfb);
1816
	var file = CFB.find(cfb, old_name);
1817
	if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
1818
		cfb.FileIndex[j].name = filename(new_name);
1819
		cfb.FullPaths[j] = new_name;
1820
		return true;
1821
	}
1822
	return false;
1823
}
1824
1825
function cfb_gc(cfb) { rebuild_cfb(cfb, true); }
1826
1827
exports.find = find;
1828
exports.read = read;
1829
exports.parse = parse;
1830
exports.write = write;
1831
exports.writeFile = write_file;
1832
exports.utils = {
1833
	cfb_new: cfb_new,
1834
	cfb_add: cfb_add,
1835
	cfb_del: cfb_del,
1836
	cfb_mov: cfb_mov,
1837
	cfb_gc: cfb_gc,
1838
	ReadShift: ReadShift,
1839
	CheckField: CheckField,
1840
	prep_blob: prep_blob,
1841
	bconcat: bconcat,
1842
	consts: consts
1843
};
1844
1845
return exports;
1846
})();
1847
1848
if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
1849
var _fs;
1850
if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
1851
1852
/* normalize data for blob ctor */
1853
function blobify(data) {
1854
	if(typeof data === "string") return s2ab(data);
1855
	if(Array.isArray(data)) return a2u(data);
1856
	return data;
1857
}
1858
/* write or download file */
1859
function write_dl(fname, payload, enc) {
1860
	/*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File, chrome */
1861
	if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
1862
	var data = (enc == "utf8") ? utf8write(payload) : payload;
1863
if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
1864
	if(typeof Blob !== 'undefined') {
1865
		var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
1866
if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
1867
if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
1868
		if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
1869
			var url = URL.createObjectURL(blob);
1870
if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
1871
				if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
1872
				return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
1873
			}
1874
			var a = document.createElement("a");
1875
			if(a.download != null) {
1876
a.download = fname; a.href = url; document.body.appendChild(a); a.click();
1877
document.body.removeChild(a);
1878
				if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
1879
				return url;
1880
			}
1881
		}
1882
	}
1883
	// $FlowIgnore
1884
	if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
1885
		// $FlowIgnore
1886
		var out = File(fname); out.open("w"); out.encoding = "binary";
1887
		if(Array.isArray(payload)) payload = a2s(payload);
1888
		out.write(payload); out.close(); return payload;
1889
	} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
1890
	throw new Error("cannot save file " + fname);
1891
}
1892
1893
/* read binary data from file */
1894
function read_binary(path) {
1895
	if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
1896
	// $FlowIgnore
1897
	if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
1898
		// $FlowIgnore
1899
		var infile = File(path); infile.open("r"); infile.encoding = "binary";
1900
		var data = infile.read(); infile.close();
1901
		return data;
1902
	} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
1903
	throw new Error("Cannot access file " + path);
1904
}
1905
function keys(o) {
1906
	var ks = Object.keys(o), o2 = [];
1907
	for(var i = 0; i < ks.length; ++i) if(o.hasOwnProperty(ks[i])) o2.push(ks[i]);
1908
	return o2;
1909
}
1910
1911
function evert_key(obj, key) {
1912
	var o = ([]), K = keys(obj);
1913
	for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
1914
	return o;
1915
}
1916
1917
function evert(obj) {
1918
	var o = ([]), K = keys(obj);
1919
	for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
1920
	return o;
1921
}
1922
1923
function evert_num(obj) {
1924
	var o = ([]), K = keys(obj);
1925
	for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
1926
	return o;
1927
}
1928
1929
function evert_arr(obj) {
1930
	var o = ([]), K = keys(obj);
1931
	for(var i = 0; i !== K.length; ++i) {
1932
		if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
1933
		o[obj[K[i]]].push(K[i]);
1934
	}
1935
	return o;
1936
}
1937
1938
var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
1939
var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
1940
function datenum(v, date1904) {
1941
	var epoch = v.getTime();
1942
	if(date1904) epoch -= 1462*24*60*60*1000;
1943
	return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
1944
}
1945
function numdate(v) {
1946
	var out = new Date();
1947
	out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
1948
	return out;
1949
}
1950
1951
/* ISO 8601 Duration */
1952
function parse_isodur(s) {
1953
	var sec = 0, mt = 0, time = false;
1954
	var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
1955
	if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
1956
	for(var i = 1; i != m.length; ++i) {
1957
		if(!m[i]) continue;
1958
		mt = 1;
1959
		if(i > 3) time = true;
1960
		switch(m[i].slice(m[i].length-1)) {
1961
			case 'Y':
1962
				throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
1963
			case 'D': mt *= 24;
1964
				/* falls through */
1965
			case 'H': mt *= 60;
1966
				/* falls through */
1967
			case 'M':
1968
				if(!time) throw new Error("Unsupported ISO Duration Field: M");
1969
				else mt *= 60;
1970
				/* falls through */
1971
			case 'S': break;
1972
		}
1973
		sec += mt * parseInt(m[i], 10);
1974
	}
1975
	return sec;
1976
}
1977
1978
var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
1979
if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
1980
var good_pd = good_pd_date.getFullYear() == 2017;
1981
/* parses a date as a local date */
1982
function parseDate(str, fixdate) {
1983
	var d = new Date(str);
1984
	if(good_pd) {
1985
if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
1986
		else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
1987
		return d;
1988
	}
1989
	if(str instanceof Date) return str;
1990
	if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
1991
		var s = d.getFullYear();
1992
		if(str.indexOf("" + s) > -1) return d;
1993
		d.setFullYear(d.getFullYear() + 100); return d;
1994
	}
1995
	var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
1996
	var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
1997
	if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
1998
	return out;
1999
}
2000
2001
function cc2str(arr) {
2002
	var o = "";
2003
	for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2004
	return o;
2005
}
2006
2007
function dup(o) {
2008
	if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2009
	if(typeof o != 'object' || o == null) return o;
2010
	if(o instanceof Date) return new Date(o.getTime());
2011
	var out = {};
2012
	for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
2013
	return out;
2014
}
2015
2016
function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
2017
2018
/* TODO: stress test */
2019
function fuzzynum(s) {
2020
	var v = Number(s);
2021
	if(!isNaN(v)) return v;
2022
	var wt = 1;
2023
	var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2024
	if(!isNaN(v = Number(ss))) return v / wt;
2025
	ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2026
	if(!isNaN(v = Number(ss))) return v / wt;
2027
	return v;
2028
}
2029
function fuzzydate(s) {
2030
	var o = new Date(s), n = new Date(NaN);
2031
	var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2032
	if(isNaN(d)) return n;
2033
	if(y < 0 || y > 8099) return n;
2034
	if((m > 0 || d > 1) && y != 101) return o;
2035
	if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2036
	if(s.match(/[^-0-9:,\/\\]/)) return n;
2037
	return o;
2038
}
2039
2040
var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2041
function split_regex(str, re, def) {
2042
	if(safe_split_regex || typeof re == "string") return str.split(re);
2043
	var p = str.split(re), o = [p[0]];
2044
	for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2045
	return o;
2046
}
2047
function getdatastr(data) {
2048
	if(!data) return null;
2049
	if(data.data) return debom(data.data);
2050
	if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2051
	if(data.asBinary) return debom(data.asBinary());
2052
	if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2053
	return null;
2054
}
2055
2056
function getdatabin(data) {
2057
	if(!data) return null;
2058
	if(data.data) return char_codes(data.data);
2059
	if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2060
	if(data._data && data._data.getContent) {
2061
		var o = data._data.getContent();
2062
		if(typeof o == "string") return char_codes(o);
2063
		return Array.prototype.slice.call(o);
2064
	}
2065
	return null;
2066
}
2067
2068
function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2069
2070
/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2071
/* OASIS does not comment on filename case sensitivity */
2072
function safegetzipfile(zip, file) {
2073
	var k = keys(zip.files);
2074
	var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
2075
	for(var i=0; i<k.length; ++i) {
2076
		var n = k[i].toLowerCase();
2077
		if(f == n || g == n) return zip.files[k[i]];
2078
	}
2079
	return null;
2080
}
2081
2082
function getzipfile(zip, file) {
2083
	var o = safegetzipfile(zip, file);
2084
	if(o == null) throw new Error("Cannot find file " + file + " in zip");
2085
	return o;
2086
}
2087
2088
function getzipdata(zip, file, safe) {
2089
	if(!safe) return getdata(getzipfile(zip, file));
2090
	if(!file) return null;
2091
	try { return getzipdata(zip, file); } catch(e) { return null; }
2092
}
2093
2094
function getzipstr(zip, file, safe) {
2095
	if(!safe) return getdatastr(getzipfile(zip, file));
2096
	if(!file) return null;
2097
	try { return getzipstr(zip, file); } catch(e) { return null; }
2098
}
2099
2100
function zipentries(zip) {
2101
	var k = keys(zip.files), o = [];
2102
	for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i]);
2103
	return o.sort();
2104
}
2105
2106
var jszip;
2107
/*global JSZipSync:true */
2108
if(typeof JSZipSync !== 'undefined') jszip = JSZipSync;
2109
if(typeof exports !== 'undefined') {
2110
	if(typeof module !== 'undefined' && module.exports) {
2111
		if(typeof jszip === 'undefined') jszip = require('./jszip.js');
2112
	}
2113
}
2114
2115
function resolve_path(path, base) {
2116
	var result = base.split('/');
2117
	if(base.slice(-1) != "/") result.pop(); // folder path
2118
	var target = path.split('/');
2119
	while (target.length !== 0) {
2120
		var step = target.shift();
2121
		if (step === '..') result.pop();
2122
		else if (step !== '.') result.push(step);
2123
	}
2124
	return result.join('/');
2125
}
2126
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2127
var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2128
var tagregex=/<[\/\?]?[a-zA-Z0-9:]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s?[\/\?]?>/g;
2129
if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2130
var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2131
function parsexmltag(tag, skip_root) {
2132
	var z = ({});
2133
	var eq = 0, c = 0;
2134
	for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2135
	if(!skip_root) z[0] = tag.slice(0, eq);
2136
	if(eq === tag.length) return z;
2137
	var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2138
	if(m) for(i = 0; i != m.length; ++i) {
2139
		cc = m[i];
2140
		for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2141
		q = cc.slice(0,c).trim();
2142
		while(cc.charCodeAt(c+1) == 32) ++c;
2143
		quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2144
		v = cc.slice(c+1+quot, cc.length-quot);
2145
		for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2146
		if(j===q.length) {
2147
			if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2148
			z[q] = v;
2149
			z[q.toLowerCase()] = v;
2150
		}
2151
		else {
2152
			var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2153
			if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2154
			z[k] = v;
2155
			z[k.toLowerCase()] = v;
2156
		}
2157
	}
2158
	return z;
2159
}
2160
function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
2161
2162
var encodings = {
2163
	'&quot;': '"',
2164
	'&apos;': "'",
2165
	'&gt;': '>',
2166
	'&lt;': '<',
2167
	'&amp;': '&'
2168
};
2169
var rencoding = evert(encodings);
2170
//var rencstr = "&<>'\"".split("");
2171
2172
// TODO: CP remap (need to read file version to determine OS)
2173
var unescapexml = (function() {
2174
	/* 22.4.2.4 bstr (Basic String) */
2175
	var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
2176
	return function unescapexml(text) {
2177
		var s = text + '', i = s.indexOf("<![CDATA[");
2178
		if(i == -1) return s.replace(encregex, function($$, $1) { return encodings[$$]||String.fromCharCode(parseInt($1,$$.indexOf("x")>-1?16:10))||$$; }).replace(coderegex,function(m,c) {return String.fromCharCode(parseInt(c,16));});
2179
		var j = s.indexOf("]]>");
2180
		return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
2181
	};
2182
})();
2183
2184
var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
2185
function escapexml(text){
2186
	var s = text + '';
2187
	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
2188
}
2189
function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
2190
2191
var htmlcharegex = /[\u0000-\u001f]/g;
2192
function escapehtml(text){
2193
	var s = text + '';
2194
	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(/\n/g, "<br/>").replace(htmlcharegex,function(s) { return "&#x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + ";"; });
2195
}
2196
2197
function escapexlml(text){
2198
	var s = text + '';
2199
	return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
2200
}
2201
2202
/* TODO: handle codepages */
2203
var xlml_fixstr = (function() {
2204
	var entregex = /&#(\d+);/g;
2205
	function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
2206
	return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
2207
})();
2208
var xlml_unfixstr = (function() {
2209
	return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
2210
})();
2211
2212
function parsexmlbool(value) {
2213
	switch(value) {
2214
		case 1: case true: case '1': case 'true': case 'TRUE': return true;
2215
		/* case '0': case 'false': case 'FALSE':*/
2216
		default: return false;
2217
	}
2218
}
2219
2220
var utf8read = function utf8reada(orig) {
2221
	var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
2222
	while (i < orig.length) {
2223
		c = orig.charCodeAt(i++);
2224
		if (c < 128) { out += String.fromCharCode(c); continue; }
2225
		d = orig.charCodeAt(i++);
2226
		if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
2227
		e = orig.charCodeAt(i++);
2228
		if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
2229
		f = orig.charCodeAt(i++);
2230
		w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
2231
		out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
2232
		out += String.fromCharCode(0xDC00 + (w&1023));
2233
	}
2234
	return out;
2235
};
2236
2237
var utf8write = function(orig) {
2238
	var out = [], i = 0, c = 0, d = 0;
2239
	while(i < orig.length) {
2240
		c = orig.charCodeAt(i++);
2241
		switch(true) {
2242
			case c < 128: out.push(String.fromCharCode(c)); break;
2243
			case c < 2048:
2244
				out.push(String.fromCharCode(192 + (c >> 6)));
2245
				out.push(String.fromCharCode(128 + (c & 63)));
2246
				break;
2247
			case c >= 55296 && c < 57344:
2248
				c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
2249
				out.push(String.fromCharCode(240 + ((d >>18) & 7)));
2250
				out.push(String.fromCharCode(144 + ((d >>12) & 63)));
2251
				out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
2252
				out.push(String.fromCharCode(128 + (d & 63)));
2253
				break;
2254
			default:
2255
				out.push(String.fromCharCode(224 + (c >> 12)));
2256
				out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
2257
				out.push(String.fromCharCode(128 + (c & 63)));
2258
		}
2259
	}
2260
	return out.join("");
2261
};
2262
2263
if(has_buf) {
2264
	var utf8readb = function utf8readb(data) {
2265
		var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
2266
		for(i = 0; i < data.length; i+=j) {
2267
			j = 1;
2268
			if((c=data.charCodeAt(i)) < 128) w = c;
2269
			else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
2270
			else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
2271
			else { j = 4;
2272
				w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
2273
				w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
2274
			}
2275
			if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
2276
			out[k++] = w%256; out[k++] = w>>>8;
2277
		}
2278
		return out.slice(0,k).toString('ucs2');
2279
	};
2280
	var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
2281
	if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
2282
	// $FlowIgnore
2283
	var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
2284
	if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
2285
2286
	// $FlowIgnore
2287
	utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
2288
}
2289
2290
// matches <foo>...</foo> extracts content
2291
var matchtag = (function() {
2292
	var mtcache = ({});
2293
	return function matchtag(f,g) {
2294
		var t = f+"|"+(g||"");
2295
		if(mtcache[t]) return mtcache[t];
2296
		return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
2297
	};
2298
})();
2299
2300
var htmldecode = (function() {
2301
	var entities = [
2302
		['nbsp', ' '], ['middot', '·'],
2303
		['quot', '"'], ['apos', "'"], ['gt',   '>'], ['lt',   '<'], ['amp',  '&']
2304
	].map(function(x) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; });
2305
	return function htmldecode(str) {
2306
		var o = str.replace(/^[\t\n\r ]+/, "").replace(/[\t\n\r ]+$/,"").replace(/[\t\n\r ]+/g, " ").replace(/<\s*[bB][rR]\s*\/?>/g,"\n").replace(/<[^>]*>/g,"");
2307
		for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
2308
		return o;
2309
	};
2310
})();
2311
2312
var vtregex = (function(){ var vt_cache = {};
2313
	return function vt_regex(bt) {
2314
		if(vt_cache[bt] !== undefined) return vt_cache[bt];
2315
		return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
2316
};})();
2317
var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
2318
function parseVector(data, opts) {
2319
	var h = parsexmltag(data);
2320
2321
	var matches = data.match(vtregex(h.baseType))||[];
2322
	var res = [];
2323
	if(matches.length != h.size) {
2324
		if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
2325
		return res;
2326
	}
2327
	matches.forEach(function(x) {
2328
		var v = x.replace(vtvregex,"").match(vtmregex);
2329
		if(v) res.push({v:utf8read(v[2]), t:v[1]});
2330
	});
2331
	return res;
2332
}
2333
2334
var wtregex = /(^\s|\s$|\n)/;
2335
function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
2336
2337
function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
2338
function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
2339
2340
function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
2341
2342
function write_vt(s) {
2343
	switch(typeof s) {
2344
		case 'string': return writextag('vt:lpwstr', s);
2345
		case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
2346
		case 'boolean': return writextag('vt:bool',s?'true':'false');
2347
	}
2348
	if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
2349
	throw new Error("Unable to serialize " + s);
2350
}
2351
2352
var XMLNS = ({
2353
	'dc': 'http://purl.org/dc/elements/1.1/',
2354
	'dcterms': 'http://purl.org/dc/terms/',
2355
	'dcmitype': 'http://purl.org/dc/dcmitype/',
2356
	'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
2357
	'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
2358
	'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
2359
	'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
2360
	'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
2361
	'xsd': 'http://www.w3.org/2001/XMLSchema'
2362
});
2363
2364
XMLNS.main = [
2365
	'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
2366
	'http://purl.oclc.org/ooxml/spreadsheetml/main',
2367
	'http://schemas.microsoft.com/office/excel/2006/main',
2368
	'http://schemas.microsoft.com/office/excel/2006/2'
2369
];
2370
2371
var XLMLNS = ({
2372
	'o':    'urn:schemas-microsoft-com:office:office',
2373
	'x':    'urn:schemas-microsoft-com:office:excel',
2374
	'ss':   'urn:schemas-microsoft-com:office:spreadsheet',
2375
	'dt':   'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
2376
	'mv':   'http://macVmlSchemaUri',
2377
	'v':    'urn:schemas-microsoft-com:vml',
2378
	'html': 'http://www.w3.org/TR/REC-html40'
2379
});
2380
function read_double_le(b, idx) {
2381
	var s = 1 - 2 * (b[idx + 7] >>> 7);
2382
	var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
2383
	var m = (b[idx+6]&0x0f);
2384
	for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
2385
	if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
2386
	if(e == 0) e = -1022;
2387
	else { e -= 1023; m += Math.pow(2,52); }
2388
	return s * Math.pow(2, e - 52) * m;
2389
}
2390
2391
function write_double_le(b, v, idx) {
2392
	var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
2393
	var av = bs ? (-v) : v;
2394
	if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
2395
	else if(av == 0) e = m = 0;
2396
	else {
2397
		e = Math.floor(Math.log(av) / Math.LN2);
2398
		m = av * Math.pow(2, 52 - e);
2399
		if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
2400
		else { m -= Math.pow(2,52); e+=1023; }
2401
	}
2402
	for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
2403
	b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
2404
	b[idx + 7] = (e >> 4) | bs;
2405
}
2406
2407
var __toBuffer = function(bufs) { var x=[],w=10240; for(var i=0;i<bufs[0].length;++i) if(bufs[0][i]) for(var j=0,L=bufs[0][i].length;j<L;j+=w) x.push.apply(x, bufs[0][i].slice(j,j+w)); return x; };
2408
var ___toBuffer = __toBuffer;
2409
var __utf16le = function(b,s,e) { var ss=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join("").replace(chr0,''); };
2410
var ___utf16le = __utf16le;
2411
var __hexlify = function(b,s,l) { var ss=[]; for(var i=s; i<s+l; ++i) ss.push(("0" + b[i].toString(16)).slice(-2)); return ss.join(""); };
2412
var ___hexlify = __hexlify;
2413
var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
2414
var ___utf8 = __utf8;
2415
var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
2416
var ___lpstr = __lpstr;
2417
var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
2418
var ___cpstr = __cpstr;
2419
var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
2420
var ___lpwstr = __lpwstr;
2421
var __lpp4, ___lpp4;
2422
__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
2423
var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
2424
var ___8lpp4 = __8lpp4;
2425
var __double, ___double;
2426
__double = ___double = function(b, idx) { return read_double_le(b, idx);};
2427
var is_buf = function is_buf_a(a) { return Array.isArray(a); };
2428
2429
if(has_buf) {
2430
	__utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
2431
	__hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
2432
	__lpstr = function lpstr_b(b, i) { if(!Buffer.isBuffer(b)) return ___lpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
2433
	__cpstr = function cpstr_b(b, i) { if(!Buffer.isBuffer(b)) return ___cpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";};
2434
	__lpwstr = function lpwstr_b(b, i) { if(!Buffer.isBuffer(b)) return ___lpwstr(b, i); var len = 2*b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len-1);};
2435
	__lpp4 = function lpp4_b(b, i) { if(!Buffer.isBuffer(b)) return ___lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len);};
2436
	__8lpp4 = function lpp4_8b(b, i) { if(!Buffer.isBuffer(b)) return ___8lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf8',i+4,i+4+len);};
2437
	__utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
2438
	__toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
2439
	bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
2440
	__double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
2441
	is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
2442
}
2443
2444
/* from js-xls */
2445
if(typeof cptable !== 'undefined') {
2446
	__utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
2447
	__utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
2448
	__lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_ansi, b.slice(i+4, i+4+len-1)) : "";};
2449
	__cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";};
2450
	__lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len-1)) : "";};
2451
	__lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
2452
	__8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
2453
}
2454
2455
var __readUInt8 = function(b, idx) { return b[idx]; };
2456
var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
2457
var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
2458
var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
2459
var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
2460
var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
2461
2462
function ReadShift(size, t) {
2463
	var o="", oI, oR, oo=[], w, vv, i, loc;
2464
	switch(t) {
2465
		case 'dbcs':
2466
			loc = this.l;
2467
			if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
2468
			else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
2469
			size *= 2;
2470
			break;
2471
2472
		case 'utf8': o = __utf8(this, this.l, this.l + size); break;
2473
		case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
2474
2475
		case 'wstr':
2476
			if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
2477
			else return ReadShift.call(this, size, 'dbcs');
2478
			size = 2 * size; break;
2479
2480
		/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
2481
		case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
2482
		case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
2483
		/* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
2484
		case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
2485
		/* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
2486
		case 'lpp4': size = 4 +  __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
2487
		/* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
2488
		case '8lpp4': size = 4 +  __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
2489
2490
		case 'cstr': size = 0; o = "";
2491
			while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
2492
			o = oo.join(""); break;
2493
		case '_wstr': size = 0; o = "";
2494
			while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
2495
			size+=2; o = oo.join(""); break;
2496
2497
		/* sbcs and dbcs support continue records in the SST way TODO codepages */
2498
		case 'dbcs-cont': o = ""; loc = this.l;
2499
			for(i = 0; i < size; ++i) {
2500
				if(this.lens && this.lens.indexOf(loc) !== -1) {
2501
					w = __readUInt8(this, loc);
2502
					this.l = loc + 1;
2503
					vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
2504
					return oo.join("") + vv;
2505
				}
2506
				oo.push(_getchar(__readUInt16LE(this, loc)));
2507
				loc+=2;
2508
			} o = oo.join(""); size *= 2; break;
2509
2510
		case 'cpstr':
2511
			if(typeof cptable !== 'undefined') {
2512
				o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
2513
				break;
2514
			}
2515
		/* falls through */
2516
		case 'sbcs-cont': o = ""; loc = this.l;
2517
			for(i = 0; i != size; ++i) {
2518
				if(this.lens && this.lens.indexOf(loc) !== -1) {
2519
					w = __readUInt8(this, loc);
2520
					this.l = loc + 1;
2521
					vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
2522
					return oo.join("") + vv;
2523
				}
2524
				oo.push(_getchar(__readUInt8(this, loc)));
2525
				loc+=1;
2526
			} o = oo.join(""); break;
2527
2528
		default:
2529
	switch(size) {
2530
		case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
2531
		case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
2532
		case 4: case -4:
2533
			if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
2534
			else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
2535
		case 8: case -8:
2536
			if(t === 'f') {
2537
				if(size == 8) oR = __double(this, this.l);
2538
				else oR = __double([this[this.l+7],this[this.l+6],this[this.l+5],this[this.l+4],this[this.l+3],this[this.l+2],this[this.l+1],this[this.l+0]], 0);
2539
				this.l += 8; return oR;
2540
			} else size = 8;
2541
		/* falls through */
2542
		case 16: o = __hexlify(this, this.l, size); break;
2543
	}}
2544
	this.l+=size; return o;
2545
}
2546
2547
var __writeUInt32LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); b[idx+2] = ((val >>> 16) & 0xFF); b[idx+3] = ((val >>> 24) & 0xFF); };
2548
var __writeInt32LE  = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >> 8) & 0xFF); b[idx+2] = ((val >> 16) & 0xFF); b[idx+3] = ((val >> 24) & 0xFF); };
2549
var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
2550
2551
function WriteShift(t, val, f) {
2552
	var size = 0, i = 0;
2553
	if(f === 'dbcs') {
2554
for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
2555
		size = 2 * val.length;
2556
	} else if(f === 'sbcs') {
2557
		/* TODO: codepage */
2558
val = val.replace(/[^\x00-\x7F]/g, "_");
2559
for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
2560
		size = val.length;
2561
	} else if(f === 'hex') {
2562
		for(; i < t; ++i) {
2563
this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
2564
		} return this;
2565
	} else if(f === 'utf16le') {
2566
var end = Math.min(this.l + t, this.length);
2567
			for(i = 0; i < Math.min(val.length, t); ++i) {
2568
				var cc = val.charCodeAt(i);
2569
				this[this.l++] = (cc & 0xff);
2570
				this[this.l++] = (cc >> 8);
2571
			}
2572
			while(this.l < end) this[this.l++] = 0;
2573
			return this;
2574
	} else  switch(t) {
2575
		case  1: size = 1; this[this.l] = val&0xFF; break;
2576
		case  2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
2577
		case  3: size = 3; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; val >>>= 8; this[this.l+2] = val&0xFF; break;
2578
		case  4: size = 4; __writeUInt32LE(this, val, this.l); break;
2579
		case  8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
2580
		/* falls through */
2581
		case 16: break;
2582
		case -4: size = 4; __writeInt32LE(this, val, this.l); break;
2583
	}
2584
	this.l += size; return this;
2585
}
2586
2587
function CheckField(hexstr, fld) {
2588
	var m = __hexlify(this,this.l,hexstr.length>>1);
2589
	if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
2590
	this.l += hexstr.length>>1;
2591
}
2592
2593
function prep_blob(blob, pos) {
2594
	blob.l = pos;
2595
	blob.read_shift = ReadShift;
2596
	blob.chk = CheckField;
2597
	blob.write_shift = WriteShift;
2598
}
2599
2600
function parsenoop(blob, length) { blob.l += length; }
2601
2602
function new_buf(sz) {
2603
	var o = new_raw_buf(sz);
2604
	prep_blob(o, 0);
2605
	return o;
2606
}
2607
2608
/* [MS-XLSB] 2.1.4 Record */
2609
function recordhopper(data, cb, opts) {
2610
	if(!data) return;
2611
	var tmpbyte, cntbyte, length;
2612
	prep_blob(data, data.l || 0);
2613
	var L = data.length, RT = 0, tgt = 0;
2614
	while(data.l < L) {
2615
		RT = data.read_shift(1);
2616
		if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
2617
		var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
2618
		tmpbyte = data.read_shift(1);
2619
		length = tmpbyte & 0x7F;
2620
		for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
2621
		tgt = data.l + length;
2622
		var d = (R.f||parsenoop)(data, length, opts);
2623
		data.l = tgt;
2624
		if(cb(d, R.n, RT)) return;
2625
	}
2626
}
2627
2628
/* control buffer usage for fixed-length buffers */
2629
function buf_array() {
2630
	var bufs = [], blksz = has_buf ? 256 : 2048;
2631
	var newblk = function ba_newblk(sz) {
2632
		var o = (new_buf(sz));
2633
		prep_blob(o, 0);
2634
		return o;
2635
	};
2636
2637
	var curbuf = newblk(blksz);
2638
2639
	var endbuf = function ba_endbuf() {
2640
		if(!curbuf) return;
2641
		if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
2642
		if(curbuf.length > 0) bufs.push(curbuf);
2643
		curbuf = null;
2644
	};
2645
2646
	var next = function ba_next(sz) {
2647
		if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
2648
		endbuf();
2649
		return (curbuf = newblk(Math.max(sz+1, blksz)));
2650
	};
2651
2652
	var end = function ba_end() {
2653
		endbuf();
2654
		return __toBuffer([bufs]);
2655
	};
2656
2657
	var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
2658
2659
	return ({ next:next, push:push, end:end, _bufs:bufs });
2660
}
2661
2662
function write_record(ba, type, payload, length) {
2663
	var t = +XLSBRE[type], l;
2664
	if(isNaN(t)) return; // TODO: throw something here?
2665
	if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
2666
	l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
2667
	if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
2668
	var o = ba.next(l);
2669
	if(t <= 0x7F) o.write_shift(1, t);
2670
	else {
2671
		o.write_shift(1, (t & 0x7F) + 0x80);
2672
		o.write_shift(1, (t >> 7));
2673
	}
2674
	for(var i = 0; i != 4; ++i) {
2675
		if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
2676
		else { o.write_shift(1, length); break; }
2677
	}
2678
	if(length > 0 && is_buf(payload)) ba.push(payload);
2679
}
2680
/* XLS ranges enforced */
2681
function shift_cell_xls(cell, tgt, opts) {
2682
	var out = dup(cell);
2683
	if(tgt.s) {
2684
		if(out.cRel) out.c += tgt.s.c;
2685
		if(out.rRel) out.r += tgt.s.r;
2686
	} else {
2687
		if(out.cRel) out.c += tgt.c;
2688
		if(out.rRel) out.r += tgt.r;
2689
	}
2690
	if(!opts || opts.biff < 12) {
2691
		while(out.c >= 0x100) out.c -= 0x100;
2692
		while(out.r >= 0x10000) out.r -= 0x10000;
2693
	}
2694
	return out;
2695
}
2696
2697
function shift_range_xls(cell, range, opts) {
2698
	var out = dup(cell);
2699
	out.s = shift_cell_xls(out.s, range.s, opts);
2700
	out.e = shift_cell_xls(out.e, range.s, opts);
2701
	return out;
2702
}
2703
2704
function encode_cell_xls(c, biff) {
2705
	if(c.cRel && c.c < 0) { c = dup(c); c.c += (biff > 8) ? 0x4000 : 0x100; }
2706
	if(c.rRel && c.r < 0) { c = dup(c); c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
2707
	var s = encode_cell(c);
2708
	if(c.cRel === 0) s = fix_col(s);
2709
	if(c.rRel === 0) s = fix_row(s);
2710
	return s;
2711
}
2712
2713
function encode_range_xls(r, opts) {
2714
	if(r.s.r == 0 && !r.s.rRel) {
2715
		if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
2716
			return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
2717
		}
2718
	}
2719
	if(r.s.c == 0 && !r.s.cRel) {
2720
		if(r.e.c == (opts.biff >= 12 ? 0xFFFF : 0xFF) && !r.e.cRel) {
2721
			return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
2722
		}
2723
	}
2724
	return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
2725
}
2726
var OFFCRYPTO = {};
2727
2728
var make_offcrypto = function(O, _crypto) {
2729
	var crypto;
2730
	if(typeof _crypto !== 'undefined') crypto = _crypto;
2731
	else if(typeof require !== 'undefined') {
2732
		try { crypto = require('crypto'); }
2733
		catch(e) { crypto = null; }
2734
	}
2735
2736
	O.rc4 = function(key, data) {
2737
		var S = new Array(256);
2738
		var c = 0, i = 0, j = 0, t = 0;
2739
		for(i = 0; i != 256; ++i) S[i] = i;
2740
		for(i = 0; i != 256; ++i) {
2741
			j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
2742
			t = S[i]; S[i] = S[j]; S[j] = t;
2743
		}
2744
		// $FlowIgnore
2745
		i = j = 0; var out = Buffer(data.length);
2746
		for(c = 0; c != data.length; ++c) {
2747
			i = (i + 1)&255;
2748
			j = (j + S[i])%256;
2749
			t = S[i]; S[i] = S[j]; S[j] = t;
2750
			out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
2751
		}
2752
		return out;
2753
	};
2754
2755
	O.md5 = function(hex) {
2756
		if(!crypto) throw new Error("Unsupported crypto");
2757
		return crypto.createHash('md5').update(hex).digest('hex');
2758
	};
2759
};
2760
/*global crypto:true */
2761
make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
2762
2763
function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
2764
function encode_row(row) { return "" + (row + 1); }
2765
function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
2766
function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
2767
2768
function decode_col(colstr) { var c = unfix_col(colstr), d = 0, i = 0; for(; i !== c.length; ++i) d = 26*d + c.charCodeAt(i) - 64; return d - 1; }
2769
function encode_col(col) { var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
2770
function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
2771
function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
2772
2773
function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
2774
function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
2775
function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
2776
function decode_range(range) { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
2777
function encode_range(cs,ce) {
2778
	if(typeof ce === 'undefined' || typeof ce === 'number') {
2779
return encode_range(cs.s, cs.e);
2780
	}
2781
if(typeof cs !== 'string') cs = encode_cell((cs));
2782
	if(typeof ce !== 'string') ce = encode_cell((ce));
2783
return cs == ce ? cs : cs + ":" + ce;
2784
}
2785
2786
function safe_decode_range(range) {
2787
	var o = {s:{c:0,r:0},e:{c:0,r:0}};
2788
	var idx = 0, i = 0, cc = 0;
2789
	var len = range.length;
2790
	for(idx = 0; i < len; ++i) {
2791
		if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
2792
		idx = 26*idx + cc;
2793
	}
2794
	o.s.c = --idx;
2795
2796
	for(idx = 0; i < len; ++i) {
2797
		if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
2798
		idx = 10*idx + cc;
2799
	}
2800
	o.s.r = --idx;
2801
2802
	if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
2803
2804
	for(idx = 0; i != len; ++i) {
2805
		if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
2806
		idx = 26*idx + cc;
2807
	}
2808
	o.e.c = --idx;
2809
2810
	for(idx = 0; i != len; ++i) {
2811
		if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
2812
		idx = 10*idx + cc;
2813
	}
2814
	o.e.r = --idx;
2815
	return o;
2816
}
2817
2818
function safe_format_cell(cell, v) {
2819
	var q = (cell.t == 'd' && v instanceof Date);
2820
	if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
2821
	try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0),  q ? datenum(v) : v)); } catch(e) { return ''+v; }
2822
}
2823
2824
function format_cell(cell, v, o) {
2825
	if(cell == null || cell.t == null || cell.t == 'z') return "";
2826
	if(cell.w !== undefined) return cell.w;
2827
	if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
2828
	if(v == undefined) return safe_format_cell(cell, cell.v);
2829
	return safe_format_cell(cell, v);
2830
}
2831
2832
function sheet_to_workbook(sheet, opts) {
2833
	var n = opts && opts.sheet ? opts.sheet : "Sheet1";
2834
	var sheets = {}; sheets[n] = sheet;
2835
	return { SheetNames: [n], Sheets: sheets };
2836
}
2837
2838
function sheet_add_aoa(_ws, data, opts) {
2839
	var o = opts || {};
2840
	var dense = _ws ? Array.isArray(_ws) : o.dense;
2841
	if(DENSE != null && dense == null) dense = DENSE;
2842
	var ws = _ws || (dense ? ([]) : ({}));
2843
	var _R = 0, _C = 0;
2844
	if(ws && o.origin != null) {
2845
		if(typeof o.origin == 'number') _R = o.origin;
2846
		else {
2847
			var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
2848
			_R = _origin.r; _C = _origin.c;
2849
		}
2850
	}
2851
	var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
2852
	if(ws['!ref']) {
2853
		var _range = safe_decode_range(ws['!ref']);
2854
		range.s.c = _range.s.c;
2855
		range.s.r = _range.s.r;
2856
		range.e.c = Math.max(range.e.c, _range.e.c);
2857
		range.e.r = Math.max(range.e.r, _range.e.r);
2858
		if(_R == -1) range.e.r = _R = _range.e.r + 1;
2859
	}
2860
	for(var R = 0; R != data.length; ++R) {
2861
		if(!data[R]) continue;
2862
		if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
2863
		for(var C = 0; C != data[R].length; ++C) {
2864
			if(typeof data[R][C] === 'undefined') continue;
2865
			var cell = ({v: data[R][C] });
2866
			if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
2867
			var __R = _R + R, __C = _C + C;
2868
			if(range.s.r > __R) range.s.r = __R;
2869
			if(range.s.c > __C) range.s.c = __C;
2870
			if(range.e.r < __R) range.e.r = __R;
2871
			if(range.e.c < __C) range.e.c = __C;
2872
			if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.cellStubs) continue; else cell.t = 'z'; }
2873
			else if(typeof cell.v === 'number') cell.t = 'n';
2874
			else if(typeof cell.v === 'boolean') cell.t = 'b';
2875
			else if(cell.v instanceof Date) {
2876
				cell.z = o.dateNF || SSF._table[14];
2877
				if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
2878
				else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
2879
			}
2880
			else cell.t = 's';
2881
			if(dense) {
2882
				if(!ws[__R]) ws[__R] = [];
2883
				ws[__R][__C] = cell;
2884
			} else {
2885
				var cell_ref = encode_cell(({c:__C,r:__R}));
2886
				ws[cell_ref] = cell;
2887
			}
2888
		}
2889
	}
2890
	if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
2891
	return ws;
2892
}
2893
function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
2894
2895
function write_UInt32LE(x, o) {
2896
	if(!o) o = new_buf(4);
2897
	o.write_shift(4, x);
2898
	return o;
2899
}
2900
2901
/* [MS-XLSB] 2.5.168 */
2902
function parse_XLWideString(data) {
2903
	var cchCharacters = data.read_shift(4);
2904
	return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
2905
}
2906
function write_XLWideString(data, o) {
2907
	var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
2908
	o.write_shift(4, data.length);
2909
	if(data.length > 0) o.write_shift(0, data, 'dbcs');
2910
	return _null ? o.slice(0, o.l) : o;
2911
}
2912
2913
/* [MS-XLSB] 2.5.143 */
2914
function parse_StrRun(data) {
2915
	return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
2916
}
2917
function write_StrRun(run, o) {
2918
	if(!o) o = new_buf(4);
2919
	o.write_shift(2, run.ich || 0);
2920
	o.write_shift(2, run.ifnt || 0);
2921
	return o;
2922
}
2923
2924
/* [MS-XLSB] 2.5.121 */
2925
function parse_RichStr(data, length) {
2926
	var start = data.l;
2927
	var flags = data.read_shift(1);
2928
	var str = parse_XLWideString(data);
2929
	var rgsStrRun = [];
2930
	var z = ({ t: str, h: str });
2931
	if((flags & 1) !== 0) { /* fRichStr */
2932
		/* TODO: formatted string */
2933
		var dwSizeStrRun = data.read_shift(4);
2934
		for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
2935
		z.r = rgsStrRun;
2936
	}
2937
	else z.r = [{ich:0, ifnt:0}];
2938
	//if((flags & 2) !== 0) { /* fExtStr */
2939
	//	/* TODO: phonetic string */
2940
	//}
2941
	data.l = start + length;
2942
	return z;
2943
}
2944
function write_RichStr(str, o) {
2945
	/* TODO: formatted string */
2946
	var _null = false; if(o == null) { _null = true; o = new_buf(15+4*str.t.length); }
2947
	o.write_shift(1,0);
2948
	write_XLWideString(str.t, o);
2949
	return _null ? o.slice(0, o.l) : o;
2950
}
2951
/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
2952
var parse_BrtCommentText = parse_RichStr;
2953
function write_BrtCommentText(str, o) {
2954
	/* TODO: formatted string */
2955
	var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
2956
	o.write_shift(1,1);
2957
	write_XLWideString(str.t, o);
2958
	o.write_shift(4,1);
2959
	write_StrRun({ich:0,ifnt:0}, o);
2960
	return _null ? o.slice(0, o.l) : o;
2961
}
2962
2963
/* [MS-XLSB] 2.5.9 */
2964
function parse_XLSBCell(data) {
2965
	var col = data.read_shift(4);
2966
	var iStyleRef = data.read_shift(2);
2967
	iStyleRef += data.read_shift(1) <<16;
2968
	data.l++; //var fPhShow = data.read_shift(1);
2969
	return { c:col, iStyleRef: iStyleRef };
2970
}
2971
function write_XLSBCell(cell, o) {
2972
	if(o == null) o = new_buf(8);
2973
	o.write_shift(-4, cell.c);
2974
	o.write_shift(3, cell.iStyleRef || cell.s);
2975
	o.write_shift(1, 0); /* fPhShow */
2976
	return o;
2977
}
2978
2979
2980
/* [MS-XLSB] 2.5.21 */
2981
var parse_XLSBCodeName = parse_XLWideString;
2982
var write_XLSBCodeName = write_XLWideString;
2983
2984
/* [MS-XLSB] 2.5.166 */
2985
function parse_XLNullableWideString(data) {
2986
	var cchCharacters = data.read_shift(4);
2987
	return cchCharacters === 0 || cchCharacters === 0xFFFFFFFF ? "" : data.read_shift(cchCharacters, 'dbcs');
2988
}
2989
function write_XLNullableWideString(data, o) {
2990
	var _null = false; if(o == null) { _null = true; o = new_buf(127); }
2991
	o.write_shift(4, data.length > 0 ? data.length : 0xFFFFFFFF);
2992
	if(data.length > 0) o.write_shift(0, data, 'dbcs');
2993
	return _null ? o.slice(0, o.l) : o;
2994
}
2995
2996
/* [MS-XLSB] 2.5.165 */
2997
var parse_XLNameWideString = parse_XLWideString;
2998
//var write_XLNameWideString = write_XLWideString;
2999
3000
/* [MS-XLSB] 2.5.114 */
3001
var parse_RelID = parse_XLNullableWideString;
3002
var write_RelID = write_XLNullableWideString;
3003
3004
3005
/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
3006
function parse_RkNumber(data) {
3007
	var b = data.slice(data.l, data.l+4);
3008
	var fX100 = (b[0] & 1), fInt = (b[0] & 2);
3009
	data.l+=4;
3010
	b[0] &= 0xFC; // b[0] &= ~3;
3011
	var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
3012
	return fX100 ? (RK/100) : RK;
3013
}
3014
function write_RkNumber(data, o) {
3015
	if(o == null) o = new_buf(4);
3016
	var fX100 = 0, fInt = 0, d100 = data * 100;
3017
	if((data == (data | 0)) && (data >= -(1<<29)) && (data < (1 << 29))) { fInt = 1; }
3018
	else if((d100 == (d100 | 0)) && (d100 >= -(1<<29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
3019
	if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
3020
	else throw new Error("unsupported RkNumber " + data); // TODO
3021
}
3022
3023
3024
/* [MS-XLSB] 2.5.117 RfX */
3025
function parse_RfX(data ) {
3026
	var cell = ({s: {}, e: {}});
3027
	cell.s.r = data.read_shift(4);
3028
	cell.e.r = data.read_shift(4);
3029
	cell.s.c = data.read_shift(4);
3030
	cell.e.c = data.read_shift(4);
3031
	return cell;
3032
}
3033
function write_RfX(r, o) {
3034
	if(!o) o = new_buf(16);
3035
	o.write_shift(4, r.s.r);
3036
	o.write_shift(4, r.e.r);
3037
	o.write_shift(4, r.s.c);
3038
	o.write_shift(4, r.e.c);
3039
	return o;
3040
}
3041
3042
/* [MS-XLSB] 2.5.153 UncheckedRfX */
3043
var parse_UncheckedRfX = parse_RfX;
3044
var write_UncheckedRfX = write_RfX;
3045
3046
/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
3047
/* TODO: error checking, NaN and Infinity values are not valid Xnum */
3048
function parse_Xnum(data) { return data.read_shift(8, 'f'); }
3049
function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
3050
3051
/* [MS-XLSB] 2.5.97.2 */
3052
var BErr = {
3053
0x00: "#NULL!",
3054
0x07: "#DIV/0!",
3055
0x0F: "#VALUE!",
3056
0x17: "#REF!",
3057
0x1D: "#NAME?",
3058
0x24: "#NUM!",
3059
0x2A: "#N/A",
3060
0x2B: "#GETTING_DATA",
3061
0xFF: "#WTF?"
3062
};
3063
var RBErr = evert_num(BErr);
3064
3065
/* [MS-XLSB] 2.4.324 BrtColor */
3066
function parse_BrtColor(data) {
3067
	var out = {};
3068
	var d = data.read_shift(1);
3069
3070
	//var fValidRGB = d & 1;
3071
	var xColorType = d >>> 1;
3072
3073
	var index = data.read_shift(1);
3074
	var nTS = data.read_shift(2, 'i');
3075
	var bR = data.read_shift(1);
3076
	var bG = data.read_shift(1);
3077
	var bB = data.read_shift(1);
3078
	data.l++; //var bAlpha = data.read_shift(1);
3079
3080
	switch(xColorType) {
3081
		case 0: out.auto = 1; break;
3082
		case 1:
3083
			out.index = index;
3084
			var icv = XLSIcv[index];
3085
			/* automatic pseudo index 81 */
3086
			if(icv) out.rgb = rgb2Hex(icv);
3087
			break;
3088
		case 2:
3089
			/* if(!fValidRGB) throw new Error("invalid"); */
3090
			out.rgb = rgb2Hex([bR, bG, bB]);
3091
			break;
3092
		case 3: out.theme = index; break;
3093
	}
3094
	if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
3095
3096
	return out;
3097
}
3098
function write_BrtColor(color, o) {
3099
	if(!o) o = new_buf(8);
3100
	if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
3101
	if(color.index) {
3102
		o.write_shift(1, 0x02);
3103
		o.write_shift(1, color.index);
3104
	} else if(color.theme) {
3105
		o.write_shift(1, 0x06);
3106
		o.write_shift(1, color.theme);
3107
	} else {
3108
		o.write_shift(1, 0x05);
3109
		o.write_shift(1, 0);
3110
	}
3111
	var nTS = color.tint || 0;
3112
	if(nTS > 0) nTS *= 32767;
3113
	else if(nTS < 0) nTS *= 32768;
3114
	o.write_shift(2, nTS);
3115
	if(!color.rgb) {
3116
		o.write_shift(2, 0);
3117
		o.write_shift(1, 0);
3118
		o.write_shift(1, 0);
3119
	} else {
3120
		var rgb = (color.rgb || 'FFFFFF');
3121
		o.write_shift(1, parseInt(rgb.slice(0,2),16));
3122
		o.write_shift(1, parseInt(rgb.slice(2,4),16));
3123
		o.write_shift(1, parseInt(rgb.slice(4,6),16));
3124
		o.write_shift(1, 0xFF);
3125
	}
3126
	return o;
3127
}
3128
3129
/* [MS-XLSB] 2.5.52 */
3130
function parse_FontFlags(data) {
3131
	var d = data.read_shift(1);
3132
	data.l++;
3133
	var out = {
3134
		/* fBold: d & 0x01 */
3135
		fItalic: d & 0x02,
3136
		/* fUnderline: d & 0x04 */
3137
		fStrikeout: d & 0x08,
3138
		fOutline: d & 0x10,
3139
		fShadow: d & 0x20,
3140
		fCondense: d & 0x40,
3141
		fExtend: d & 0x80
3142
	};
3143
	return out;
3144
}
3145
function write_FontFlags(font, o) {
3146
	if(!o) o = new_buf(2);
3147
	var grbit =
3148
		(font.italic   ? 0x02 : 0) |
3149
		(font.strike   ? 0x08 : 0) |
3150
		(font.outline  ? 0x10 : 0) |
3151
		(font.shadow   ? 0x20 : 0) |
3152
		(font.condense ? 0x40 : 0) |
3153
		(font.extend   ? 0x80 : 0);
3154
	o.write_shift(1, grbit);
3155
	o.write_shift(1, 0);
3156
	return o;
3157
}
3158
3159
/* [MS-OLEDS] 2.3.1 and 2.3.2 */
3160
function parse_ClipboardFormatOrString(o, w) {
3161
	// $FlowIgnore
3162
	var ClipFmt = {2:"BITMAP",3:"METAFILEPICT",8:"DIB",14:"ENHMETAFILE"};
3163
	var m = o.read_shift(4);
3164
	switch(m) {
3165
		case 0x00000000: return "";
3166
		case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)]||"";
3167
	}
3168
	if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
3169
	o.l -= 4;
3170
	return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr");
3171
}
3172
function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); }
3173
function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); }
3174
3175
/* [MS-OLEPS] 2.2 PropertyType */
3176
//var VT_EMPTY    = 0x0000;
3177
//var VT_NULL     = 0x0001;
3178
var VT_I2       = 0x0002;
3179
var VT_I4       = 0x0003;
3180
//var VT_R4       = 0x0004;
3181
//var VT_R8       = 0x0005;
3182
//var VT_CY       = 0x0006;
3183
//var VT_DATE     = 0x0007;
3184
//var VT_BSTR     = 0x0008;
3185
//var VT_ERROR    = 0x000A;
3186
var VT_BOOL     = 0x000B;
3187
var VT_VARIANT  = 0x000C;
3188
//var VT_DECIMAL  = 0x000E;
3189
//var VT_I1       = 0x0010;
3190
//var VT_UI1      = 0x0011;
3191
//var VT_UI2      = 0x0012;
3192
var VT_UI4      = 0x0013;
3193
//var VT_I8       = 0x0014;
3194
//var VT_UI8      = 0x0015;
3195
//var VT_INT      = 0x0016;
3196
//var VT_UINT     = 0x0017;
3197
var VT_LPSTR    = 0x001E;
3198
//var VT_LPWSTR   = 0x001F;
3199
var VT_FILETIME = 0x0040;
3200
var VT_BLOB     = 0x0041;
3201
//var VT_STREAM   = 0x0042;
3202
//var VT_STORAGE  = 0x0043;
3203
//var VT_STREAMED_Object  = 0x0044;
3204
//var VT_STORED_Object    = 0x0045;
3205
//var VT_BLOB_Object      = 0x0046;
3206
var VT_CF       = 0x0047;
3207
//var VT_CLSID    = 0x0048;
3208
//var VT_VERSIONED_STREAM = 0x0049;
3209
var VT_VECTOR   = 0x1000;
3210
//var VT_ARRAY    = 0x2000;
3211
3212
var VT_STRING   = 0x0050; // 2.3.3.1.11 VtString
3213
var VT_USTR     = 0x0051; // 2.3.3.1.12 VtUnalignedString
3214
var VT_CUSTOM   = [VT_STRING, VT_USTR];
3215
3216
/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
3217
var DocSummaryPIDDSI = {
3218
0x01: { n: 'CodePage', t: VT_I2 },
3219
0x02: { n: 'Category', t: VT_STRING },
3220
0x03: { n: 'PresentationFormat', t: VT_STRING },
3221
0x04: { n: 'ByteCount', t: VT_I4 },
3222
0x05: { n: 'LineCount', t: VT_I4 },
3223
0x06: { n: 'ParagraphCount', t: VT_I4 },
3224
0x07: { n: 'SlideCount', t: VT_I4 },
3225
0x08: { n: 'NoteCount', t: VT_I4 },
3226
0x09: { n: 'HiddenCount', t: VT_I4 },
3227
0x0a: { n: 'MultimediaClipCount', t: VT_I4 },
3228
0x0b: { n: 'ScaleCrop', t: VT_BOOL },
3229
0x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
3230
0x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
3231
0x0e: { n: 'Manager', t: VT_STRING },
3232
0x0f: { n: 'Company', t: VT_STRING },
3233
0x10: { n: 'LinksUpToDate', t: VT_BOOL },
3234
0x11: { n: 'CharacterCount', t: VT_I4 },
3235
0x13: { n: 'SharedDoc', t: VT_BOOL },
3236
0x16: { n: 'HyperlinksChanged', t: VT_BOOL },
3237
0x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
3238
0x18: { n: 'DigSig', t: VT_BLOB },
3239
0x1A: { n: 'ContentType', t: VT_STRING },
3240
0x1B: { n: 'ContentStatus', t: VT_STRING },
3241
0x1C: { n: 'Language', t: VT_STRING },
3242
0x1D: { n: 'Version', t: VT_STRING },
3243
0xFF: {}
3244
};
3245
3246
/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
3247
var SummaryPIDSI = {
3248
0x01: { n: 'CodePage', t: VT_I2 },
3249
0x02: { n: 'Title', t: VT_STRING },
3250
0x03: { n: 'Subject', t: VT_STRING },
3251
0x04: { n: 'Author', t: VT_STRING },
3252
0x05: { n: 'Keywords', t: VT_STRING },
3253
0x06: { n: 'Comments', t: VT_STRING },
3254
0x07: { n: 'Template', t: VT_STRING },
3255
0x08: { n: 'LastAuthor', t: VT_STRING },
3256
0x09: { n: 'RevNumber', t: VT_STRING },
3257
0x0A: { n: 'EditTime', t: VT_FILETIME },
3258
0x0B: { n: 'LastPrinted', t: VT_FILETIME },
3259
0x0C: { n: 'CreatedDate', t: VT_FILETIME },
3260
0x0D: { n: 'ModifiedDate', t: VT_FILETIME },
3261
0x0E: { n: 'PageCount', t: VT_I4 },
3262
0x0F: { n: 'WordCount', t: VT_I4 },
3263
0x10: { n: 'CharCount', t: VT_I4 },
3264
0x11: { n: 'Thumbnail', t: VT_CF },
3265
0x12: { n: 'Application', t: VT_STRING },
3266
0x13: { n: 'DocSecurity', t: VT_I4 },
3267
0xFF: {}
3268
};
3269
3270
/* [MS-OLEPS] 2.18 */
3271
var SpecialProperties = {
3272
0x80000000: { n: 'Locale', t: VT_UI4 },
3273
0x80000003: { n: 'Behavior', t: VT_UI4 },
3274
0x72627262: {}
3275
};
3276
3277
(function() {
3278
	for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
3279
	DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
3280
})();
3281
3282
var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
3283
var SummaryRE = evert_key(SummaryPIDSI, "n");
3284
3285
/* [MS-XLS] 2.4.63 Country/Region codes */
3286
var CountryEnum = {
3287
0x0001: "US", // United States
3288
0x0002: "CA", // Canada
3289
0x0003: "", // Latin America (except Brazil)
3290
0x0007: "RU", // Russia
3291
0x0014: "EG", // Egypt
3292
0x001E: "GR", // Greece
3293
0x001F: "NL", // Netherlands
3294
0x0020: "BE", // Belgium
3295
0x0021: "FR", // France
3296
0x0022: "ES", // Spain
3297
0x0024: "HU", // Hungary
3298
0x0027: "IT", // Italy
3299
0x0029: "CH", // Switzerland
3300
0x002B: "AT", // Austria
3301
0x002C: "GB", // United Kingdom
3302
0x002D: "DK", // Denmark
3303
0x002E: "SE", // Sweden
3304
0x002F: "NO", // Norway
3305
0x0030: "PL", // Poland
3306
0x0031: "DE", // Germany
3307
0x0034: "MX", // Mexico
3308
0x0037: "BR", // Brazil
3309
0x003d: "AU", // Australia
3310
0x0040: "NZ", // New Zealand
3311
0x0042: "TH", // Thailand
3312
0x0051: "JP", // Japan
3313
0x0052: "KR", // Korea
3314
0x0054: "VN", // Viet Nam
3315
0x0056: "CN", // China
3316
0x005A: "TR", // Turkey
3317
0x0069: "JS", // Ramastan
3318
0x00D5: "DZ", // Algeria
3319
0x00D8: "MA", // Morocco
3320
0x00DA: "LY", // Libya
3321
0x015F: "PT", // Portugal
3322
0x0162: "IS", // Iceland
3323
0x0166: "FI", // Finland
3324
0x01A4: "CZ", // Czech Republic
3325
0x0376: "TW", // Taiwan
3326
0x03C1: "LB", // Lebanon
3327
0x03C2: "JO", // Jordan
3328
0x03C3: "SY", // Syria
3329
0x03C4: "IQ", // Iraq
3330
0x03C5: "KW", // Kuwait
3331
0x03C6: "SA", // Saudi Arabia
3332
0x03CB: "AE", // United Arab Emirates
3333
0x03CC: "IL", // Israel
3334
0x03CE: "QA", // Qatar
3335
0x03D5: "IR", // Iran
3336
0xFFFF: "US"  // United States
3337
};
3338
3339
/* [MS-XLS] 2.5.127 */
3340
var XLSFillPattern = [
3341
	null,
3342
	'solid',
3343
	'mediumGray',
3344
	'darkGray',
3345
	'lightGray',
3346
	'darkHorizontal',
3347
	'darkVertical',
3348
	'darkDown',
3349
	'darkUp',
3350
	'darkGrid',
3351
	'darkTrellis',
3352
	'lightHorizontal',
3353
	'lightVertical',
3354
	'lightDown',
3355
	'lightUp',
3356
	'lightGrid',
3357
	'lightTrellis',
3358
	'gray125',
3359
	'gray0625'
3360
];
3361
3362
function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
3363
3364
/* [MS-XLS] 2.5.161 */
3365
/* [MS-XLSB] 2.5.75 Icv */
3366
var XLSIcv = rgbify([
3367
	/* Color Constants */
3368
	0x000000,
3369
	0xFFFFFF,
3370
	0xFF0000,
3371
	0x00FF00,
3372
	0x0000FF,
3373
	0xFFFF00,
3374
	0xFF00FF,
3375
	0x00FFFF,
3376
3377
	/* Overridable Defaults */
3378
	0x000000,
3379
	0xFFFFFF,
3380
	0xFF0000,
3381
	0x00FF00,
3382
	0x0000FF,
3383
	0xFFFF00,
3384
	0xFF00FF,
3385
	0x00FFFF,
3386
3387
	0x800000,
3388
	0x008000,
3389
	0x000080,
3390
	0x808000,
3391
	0x800080,
3392
	0x008080,
3393
	0xC0C0C0,
3394
	0x808080,
3395
	0x9999FF,
3396
	0x993366,
3397
	0xFFFFCC,
3398
	0xCCFFFF,
3399
	0x660066,
3400
	0xFF8080,
3401
	0x0066CC,
3402
	0xCCCCFF,
3403
3404
	0x000080,
3405
	0xFF00FF,
3406
	0xFFFF00,
3407
	0x00FFFF,
3408
	0x800080,
3409
	0x800000,
3410
	0x008080,
3411
	0x0000FF,
3412
	0x00CCFF,
3413
	0xCCFFFF,
3414
	0xCCFFCC,
3415
	0xFFFF99,
3416
	0x99CCFF,
3417
	0xFF99CC,
3418
	0xCC99FF,
3419
	0xFFCC99,
3420
3421
	0x3366FF,
3422
	0x33CCCC,
3423
	0x99CC00,
3424
	0xFFCC00,
3425
	0xFF9900,
3426
	0xFF6600,
3427
	0x666699,
3428
	0x969696,
3429
	0x003366,
3430
	0x339966,
3431
	0x003300,
3432
	0x333300,
3433
	0x993300,
3434
	0x993366,
3435
	0x333399,
3436
	0x333333,
3437
3438
	/* Other entries to appease BIFF8/12 */
3439
	0xFFFFFF, /* 0x40 icvForeground ?? */
3440
	0x000000, /* 0x41 icvBackground ?? */
3441
	0x000000, /* 0x42 icvFrame ?? */
3442
	0x000000, /* 0x43 icv3D ?? */
3443
	0x000000, /* 0x44 icv3DText ?? */
3444
	0x000000, /* 0x45 icv3DHilite ?? */
3445
	0x000000, /* 0x46 icv3DShadow ?? */
3446
	0x000000, /* 0x47 icvHilite ?? */
3447
	0x000000, /* 0x48 icvCtlText ?? */
3448
	0x000000, /* 0x49 icvCtlScrl ?? */
3449
	0x000000, /* 0x4A icvCtlInv ?? */
3450
	0x000000, /* 0x4B icvCtlBody ?? */
3451
	0x000000, /* 0x4C icvCtlFrame ?? */
3452
	0x000000, /* 0x4D icvCtlFore ?? */
3453
	0x000000, /* 0x4E icvCtlBack ?? */
3454
	0x000000, /* 0x4F icvCtlNeutral */
3455
	0x000000, /* 0x50 icvInfoBk ?? */
3456
	0x000000 /* 0x51 icvInfoText ?? */
3457
]);
3458
3459
/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
3460
/* 12.3 Part Summary <SpreadsheetML> */
3461
/* 14.2 Part Summary <DrawingML> */
3462
/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
3463
var ct2type/*{[string]:string}*/ = ({
3464
	/* Workbook */
3465
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
3466
3467
	/* Worksheet */
3468
	"application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
3469
3470
	/* Macrosheet */
3471
	"application/vnd.ms-excel.intlmacrosheet": "TODO",
3472
	"application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
3473
3474
	/* File Properties */
3475
	"application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
3476
	"application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
3477
	"application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
3478
3479
	/* Custom Data Properties */
3480
	"application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
3481
	"application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
3482
3483
	/* PivotTable */
3484
	"application/vnd.ms-excel.pivotTable": "TODO",
3485
	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
3486
3487
	/* Chart Colors */
3488
	"application/vnd.ms-office.chartcolorstyle+xml": "TODO",
3489
3490
	/* Chart Style */
3491
	"application/vnd.ms-office.chartstyle+xml": "TODO",
3492
3493
	/* Calculation Chain */
3494
	"application/vnd.ms-excel.calcChain": "calcchains",
3495
	"application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
3496
3497
	/* Printer Settings */
3498
	"application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
3499
3500
	/* ActiveX */
3501
	"application/vnd.ms-office.activeX": "TODO",
3502
	"application/vnd.ms-office.activeX+xml": "TODO",
3503
3504
	/* Custom Toolbars */
3505
	"application/vnd.ms-excel.attachedToolbars": "TODO",
3506
3507
	/* External Data Connections */
3508
	"application/vnd.ms-excel.connections": "TODO",
3509
	"application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
3510
3511
	/* External Links */
3512
	"application/vnd.ms-excel.externalLink": "links",
3513
	"application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
3514
3515
	/* Metadata */
3516
	"application/vnd.ms-excel.sheetMetadata": "TODO",
3517
	"application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
3518
3519
	/* PivotCache */
3520
	"application/vnd.ms-excel.pivotCacheDefinition": "TODO",
3521
	"application/vnd.ms-excel.pivotCacheRecords": "TODO",
3522
	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
3523
	"application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
3524
3525
	/* Query Table */
3526
	"application/vnd.ms-excel.queryTable": "TODO",
3527
	"application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
3528
3529
	/* Shared Workbook */
3530
	"application/vnd.ms-excel.userNames": "TODO",
3531
	"application/vnd.ms-excel.revisionHeaders": "TODO",
3532
	"application/vnd.ms-excel.revisionLog": "TODO",
3533
	"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
3534
	"application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
3535
	"application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
3536
3537
	/* Single Cell Table */
3538
	"application/vnd.ms-excel.tableSingleCells": "TODO",
3539
	"application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
3540
3541
	/* Slicer */
3542
	"application/vnd.ms-excel.slicer": "TODO",
3543
	"application/vnd.ms-excel.slicerCache": "TODO",
3544
	"application/vnd.ms-excel.slicer+xml": "TODO",
3545
	"application/vnd.ms-excel.slicerCache+xml": "TODO",
3546
3547
	/* Sort Map */
3548
	"application/vnd.ms-excel.wsSortMap": "TODO",
3549
3550
	/* Table */
3551
	"application/vnd.ms-excel.table": "TODO",
3552
	"application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
3553
3554
	/* Themes */
3555
	"application/vnd.openxmlformats-officedocument.theme+xml": "themes",
3556
3557
	/* Theme Override */
3558
	"application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
3559
3560
	/* Timeline */
3561
	"application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
3562
	"application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
3563
3564
	/* VBA */
3565
	"application/vnd.ms-office.vbaProject": "vba",
3566
	"application/vnd.ms-office.vbaProjectSignature": "vba",
3567
3568
	/* Volatile Dependencies */
3569
	"application/vnd.ms-office.volatileDependencies": "TODO",
3570
	"application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
3571
3572
	/* Control Properties */
3573
	"application/vnd.ms-excel.controlproperties+xml": "TODO",
3574
3575
	/* Data Model */
3576
	"application/vnd.openxmlformats-officedocument.model+data": "TODO",
3577
3578
	/* Survey */
3579
	"application/vnd.ms-excel.Survey+xml": "TODO",
3580
3581
	/* Drawing */
3582
	"application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
3583
	"application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
3584
	"application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
3585
	"application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
3586
	"application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
3587
	"application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
3588
	"application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
3589
3590
	/* VML */
3591
	"application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
3592
3593
	"application/vnd.openxmlformats-package.relationships+xml": "rels",
3594
	"application/vnd.openxmlformats-officedocument.oleObject": "TODO",
3595
3596
	/* Image */
3597
	"image/png": "TODO",
3598
3599
	"sheet": "js"
3600
});
3601
3602
var CT_LIST = (function(){
3603
	var o = {
3604
		workbooks: {
3605
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
3606
			xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
3607
			xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
3608
			xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
3609
			xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
3610
		},
3611
		strs: { /* Shared Strings */
3612
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
3613
			xlsb: "application/vnd.ms-excel.sharedStrings"
3614
		},
3615
		comments: { /* Comments */
3616
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
3617
			xlsb: "application/vnd.ms-excel.comments"
3618
		},
3619
		sheets: { /* Worksheet */
3620
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
3621
			xlsb: "application/vnd.ms-excel.worksheet"
3622
		},
3623
		charts: { /* Chartsheet */
3624
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
3625
			xlsb: "application/vnd.ms-excel.chartsheet"
3626
		},
3627
		dialogs: { /* Dialogsheet */
3628
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
3629
			xlsb: "application/vnd.ms-excel.dialogsheet"
3630
		},
3631
		macros: { /* Macrosheet (Excel 4.0 Macros) */
3632
			xlsx: "application/vnd.ms-excel.macrosheet+xml",
3633
			xlsb: "application/vnd.ms-excel.macrosheet"
3634
		},
3635
		styles: { /* Styles */
3636
			xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
3637
			xlsb: "application/vnd.ms-excel.styles"
3638
		}
3639
	};
3640
	keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
3641
	keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
3642
	return o;
3643
})();
3644
3645
var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
3646
3647
XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
3648
3649
function new_ct() {
3650
	return ({
3651
		workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
3652
		rels:[], strs:[], comments:[], links:[],
3653
		coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
3654
		calcchains:[], vba: [], drawings: [],
3655
		TODO:[], xmlns: "" });
3656
}
3657
3658
function parse_ct(data) {
3659
	var ct = new_ct();
3660
	if(!data || !data.match) return ct;
3661
	var ctext = {};
3662
	(data.match(tagregex)||[]).forEach(function(x) {
3663
		var y = parsexmltag(x);
3664
		switch(y[0].replace(nsregex,"<")) {
3665
			case '<?xml': break;
3666
			case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
3667
			case '<Default': ctext[y.Extension] = y.ContentType; break;
3668
			case '<Override':
3669
				if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
3670
				break;
3671
		}
3672
	});
3673
	if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
3674
	ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
3675
	ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
3676
	ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
3677
	ct.defaults = ctext;
3678
	delete ct.calcchains;
3679
	return ct;
3680
}
3681
3682
var CTYPE_XML_ROOT = writextag('Types', null, {
3683
	'xmlns': XMLNS.CT,
3684
	'xmlns:xsd': XMLNS.xsd,
3685
	'xmlns:xsi': XMLNS.xsi
3686
});
3687
3688
var CTYPE_DEFAULTS = [
3689
	['xml', 'application/xml'],
3690
	['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
3691
	['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
3692
	/* from test files */
3693
	['bmp', 'image/bmp'],
3694
	['png', 'image/png'],
3695
	['gif', 'image/gif'],
3696
	['emf', 'image/x-emf'],
3697
	['wmf', 'image/x-wmf'],
3698
	['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
3699
	['tif', 'image/tiff'], ['tiff', 'image/tiff'],
3700
	['pdf', 'application/pdf'],
3701
	['rels', type2ct.rels[0]]
3702
].map(function(x) {
3703
	return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
3704
});
3705
3706
function write_ct(ct, opts) {
3707
	var o = [], v;
3708
	o[o.length] = (XML_HEADER);
3709
	o[o.length] = (CTYPE_XML_ROOT);
3710
	o = o.concat(CTYPE_DEFAULTS);
3711
	var f1 = function(w) {
3712
		if(ct[w] && ct[w].length > 0) {
3713
			v = ct[w][0];
3714
			o[o.length] = (writextag('Override', null, {
3715
				'PartName': (v[0] == '/' ? "":"/") + v,
3716
				'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
3717
			}));
3718
		}
3719
	};
3720
	var f2 = function(w) {
3721
		(ct[w]||[]).forEach(function(v) {
3722
			o[o.length] = (writextag('Override', null, {
3723
				'PartName': (v[0] == '/' ? "":"/") + v,
3724
				'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
3725
			}));
3726
		});
3727
	};
3728
	var f3 = function(t) {
3729
		(ct[t]||[]).forEach(function(v) {
3730
			o[o.length] = (writextag('Override', null, {
3731
				'PartName': (v[0] == '/' ? "":"/") + v,
3732
				'ContentType': type2ct[t][0]
3733
			}));
3734
		});
3735
	};
3736
	f1('workbooks');
3737
	f2('sheets');
3738
	f2('charts');
3739
	f3('themes');
3740
	['strs', 'styles'].forEach(f1);
3741
	['coreprops', 'extprops', 'custprops'].forEach(f3);
3742
	f3('vba');
3743
	f3('comments');
3744
	f3('drawings');
3745
	if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
3746
	return o.join("");
3747
}
3748
/* 9.3 Relationships */
3749
var RELS = ({
3750
	WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
3751
	SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
3752
	HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
3753
	VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
3754
	VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
3755
});
3756
3757
/* 9.3.3 Representing Relationships */
3758
function get_rels_path(file) {
3759
	var n = file.lastIndexOf("/");
3760
	return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
3761
}
3762
3763
function parse_rels(data, currentFilePath) {
3764
	if (!data) return data;
3765
	if (currentFilePath.charAt(0) !== '/') {
3766
		currentFilePath = '/'+currentFilePath;
3767
	}
3768
	var rels = {};
3769
	var hash = {};
3770
3771
	(data.match(tagregex)||[]).forEach(function(x) {
3772
		var y = parsexmltag(x);
3773
		/* 9.3.2.2 OPC_Relationships */
3774
		if (y[0] === '<Relationship') {
3775
			var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
3776
			var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
3777
			rels[canonictarget] = rel;
3778
			hash[y.Id] = rel;
3779
		}
3780
	});
3781
	rels["!id"] = hash;
3782
	return rels;
3783
}
3784
3785
XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
3786
3787
var RELS_ROOT = writextag('Relationships', null, {
3788
	//'xmlns:ns0': XMLNS.RELS,
3789
	'xmlns': XMLNS.RELS
3790
});
3791
3792
/* TODO */
3793
function write_rels(rels) {
3794
	var o = [XML_HEADER, RELS_ROOT];
3795
	keys(rels['!id']).forEach(function(rid) {
3796
		o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
3797
	});
3798
	if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
3799
	return o.join("");
3800
}
3801
3802
function add_rels(rels, rId, f, type, relobj) {
3803
	if(!relobj) relobj = {};
3804
	if(!rels['!id']) rels['!id'] = {};
3805
	if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
3806
	relobj.Id = 'rId' + rId;
3807
	relobj.Type = type;
3808
	relobj.Target = f;
3809
	if(relobj.Type == RELS.HLINK) relobj.TargetMode = "External";
3810
	if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
3811
	rels['!id'][relobj.Id] = relobj;
3812
	rels[('/' + relobj.Target).replace("//","/")] = relobj;
3813
	return rId;
3814
}
3815
/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
3816
/* Part 3 Section 4 Manifest File */
3817
var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
3818
function parse_manifest(d, opts) {
3819
	var str = xlml_normalize(d);
3820
	var Rn;
3821
	var FEtag;
3822
	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
3823
		case 'manifest': break; // 4.2 <manifest:manifest>
3824
		case 'file-entry': // 4.3 <manifest:file-entry>
3825
			FEtag = parsexmltag(Rn[0], false);
3826
			if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
3827
			break;
3828
		case 'encryption-data': // 4.4 <manifest:encryption-data>
3829
		case 'algorithm': // 4.5 <manifest:algorithm>
3830
		case 'start-key-generation': // 4.6 <manifest:start-key-generation>
3831
		case 'key-derivation': // 4.7 <manifest:key-derivation>
3832
			throw new Error("Unsupported ODS Encryption");
3833
		default: if(opts && opts.WTF) throw Rn;
3834
	}
3835
}
3836
3837
function write_manifest(manifest) {
3838
	var o = [XML_HEADER];
3839
	o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
3840
	o.push('  <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
3841
	for(var i = 0; i < manifest.length; ++i) o.push('  <manifest:file-entry manifest:full-path="' + manifest[i][0] + '" manifest:media-type="' + manifest[i][1] + '"/>\n');
3842
	o.push('</manifest:manifest>');
3843
	return o.join("");
3844
}
3845
3846
/* Part 3 Section 6 Metadata Manifest File */
3847
function write_rdf_type(file, res, tag) {
3848
	return [
3849
		'  <rdf:Description rdf:about="' + file + '">\n',
3850
		'    <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
3851
		'  </rdf:Description>\n'
3852
	].join("");
3853
}
3854
function write_rdf_has(base, file) {
3855
	return [
3856
		'  <rdf:Description rdf:about="' + base + '">\n',
3857
		'    <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
3858
		'  </rdf:Description>\n'
3859
	].join("");
3860
}
3861
function write_rdf(rdf) {
3862
	var o = [XML_HEADER];
3863
	o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
3864
	for(var i = 0; i != rdf.length; ++i) {
3865
		o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
3866
		o.push(write_rdf_has("",rdf[i][0]));
3867
	}
3868
	o.push(write_rdf_type("","Document", "pkg"));
3869
	o.push('</rdf:RDF>');
3870
	return o.join("");
3871
}
3872
/* TODO: pull properties */
3873
var write_meta_ods = (function() {
3874
	var payload = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?><office:document-meta xmlns:office="urn:oasis:names:tc:opendocument:xmlns:office:1.0" xmlns:meta="urn:oasis:names:tc:opendocument:xmlns:meta:1.0" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:xlink="http://www.w3.org/1999/xlink" office:version="1.2"><office:meta><meta:generator>Sheet' + 'JS ' + XLSX.version + '</meta:generator></office:meta></office:document-meta>';
3875
	return function wmo() {
3876
		return payload;
3877
	};
3878
})();
3879
3880
/* ECMA-376 Part II 11.1 Core Properties Part */
3881
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
3882
var CORE_PROPS = [
3883
	["cp:category", "Category"],
3884
	["cp:contentStatus", "ContentStatus"],
3885
	["cp:keywords", "Keywords"],
3886
	["cp:lastModifiedBy", "LastAuthor"],
3887
	["cp:lastPrinted", "LastPrinted"],
3888
	["cp:revision", "RevNumber"],
3889
	["cp:version", "Version"],
3890
	["dc:creator", "Author"],
3891
	["dc:description", "Comments"],
3892
	["dc:identifier", "Identifier"],
3893
	["dc:language", "Language"],
3894
	["dc:subject", "Subject"],
3895
	["dc:title", "Title"],
3896
	["dcterms:created", "CreatedDate", 'date'],
3897
	["dcterms:modified", "ModifiedDate", 'date']
3898
];
3899
3900
XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
3901
RELS.CORE_PROPS  = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
3902
3903
var CORE_PROPS_REGEX = (function() {
3904
	var r = new Array(CORE_PROPS.length);
3905
	for(var i = 0; i < CORE_PROPS.length; ++i) {
3906
		var f = CORE_PROPS[i];
3907
		var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
3908
		r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
3909
	}
3910
	return r;
3911
})();
3912
3913
function parse_core_props(data) {
3914
	var p = {};
3915
	data = utf8read(data);
3916
3917
	for(var i = 0; i < CORE_PROPS.length; ++i) {
3918
		var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
3919
		if(cur != null && cur.length > 0) p[f[1]] = cur[1];
3920
		if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
3921
	}
3922
3923
	return p;
3924
}
3925
3926
var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
3927
	//'xmlns': XMLNS.CORE_PROPS,
3928
	'xmlns:cp': XMLNS.CORE_PROPS,
3929
	'xmlns:dc': XMLNS.dc,
3930
	'xmlns:dcterms': XMLNS.dcterms,
3931
	'xmlns:dcmitype': XMLNS.dcmitype,
3932
	'xmlns:xsi': XMLNS.xsi
3933
});
3934
3935
function cp_doit(f, g, h, o, p) {
3936
	if(p[f] != null || g == null || g === "") return;
3937
	p[f] = g;
3938
	o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
3939
}
3940
3941
function write_core_props(cp, _opts) {
3942
	var opts = _opts || {};
3943
	var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
3944
	if(!cp && !opts.Props) return o.join("");
3945
3946
	if(cp) {
3947
		if(cp.CreatedDate != null) cp_doit("dcterms:created", typeof cp.CreatedDate === "string" ? cp.CreatedDate : write_w3cdtf(cp.CreatedDate, opts.WTF), {"xsi:type":"dcterms:W3CDTF"}, o, p);
3948
		if(cp.ModifiedDate != null) cp_doit("dcterms:modified", typeof cp.ModifiedDate === "string" ? cp.ModifiedDate : write_w3cdtf(cp.ModifiedDate, opts.WTF), {"xsi:type":"dcterms:W3CDTF"}, o, p);
3949
	}
3950
3951
	for(var i = 0; i != CORE_PROPS.length; ++i) {
3952
		var f = CORE_PROPS[i];
3953
		var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
3954
		if(v === true) v = "1";
3955
		else if(v === false) v = "0";
3956
		else if(typeof v == "number") v = String(v);
3957
		if(v != null) cp_doit(f[0], v, null, o, p);
3958
	}
3959
	if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
3960
	return o.join("");
3961
}
3962
/* 15.2.12.3 Extended File Properties Part */
3963
/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
3964
var EXT_PROPS = [
3965
	["Application", "Application", "string"],
3966
	["AppVersion", "AppVersion", "string"],
3967
	["Company", "Company", "string"],
3968
	["DocSecurity", "DocSecurity", "string"],
3969
	["Manager", "Manager", "string"],
3970
	["HyperlinksChanged", "HyperlinksChanged", "bool"],
3971
	["SharedDoc", "SharedDoc", "bool"],
3972
	["LinksUpToDate", "LinksUpToDate", "bool"],
3973
	["ScaleCrop", "ScaleCrop", "bool"],
3974
	["HeadingPairs", "HeadingPairs", "raw"],
3975
	["TitlesOfParts", "TitlesOfParts", "raw"]
3976
];
3977
3978
XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
3979
RELS.EXT_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
3980
3981
var PseudoPropsPairs = [
3982
	"Worksheets",  "SheetNames",
3983
	"NamedRanges", "DefinedNames",
3984
	"Chartsheets", "ChartNames"
3985
];
3986
function load_props_pairs(HP, TOP, props, opts) {
3987
	var v = [];
3988
	if(typeof HP == "string") v = parseVector(HP, opts);
3989
	else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
3990
	var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
3991
	var idx = 0, len = 0;
3992
	if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
3993
		len = +(v[i+1].v);
3994
		switch(v[i].v) {
3995
			case "Worksheets":
3996
			case "工作表":
3997
			case "Листы":
3998
			case "أوراق العمل":
3999
			case "ワークシート":
4000
			case "גליונות עבודה":
4001
			case "Arbeitsblätter":
4002
			case "Çalışma Sayfaları":
4003
			case "Feuilles de calcul":
4004
			case "Fogli di lavoro":
4005
			case "Folhas de cálculo":
4006
			case "Planilhas":
4007
			case "Regneark":
4008
			case "Werkbladen":
4009
				props.Worksheets = len;
4010
				props.SheetNames = parts.slice(idx, idx + len);
4011
				break;
4012
4013
			case "Named Ranges":
4014
			case "名前付き一覧":
4015
			case "Benannte Bereiche":
4016
			case "Navngivne områder":
4017
				props.NamedRanges = len;
4018
				props.DefinedNames = parts.slice(idx, idx + len);
4019
				break;
4020
4021
			case "Charts":
4022
			case "Diagramme":
4023
				props.Chartsheets = len;
4024
				props.ChartNames = parts.slice(idx, idx + len);
4025
				break;
4026
		}
4027
		idx += len;
4028
	}
4029
}
4030
4031
function parse_ext_props(data, p, opts) {
4032
	var q = {}; if(!p) p = {};
4033
	data = utf8read(data);
4034
4035
	EXT_PROPS.forEach(function(f) {
4036
		switch(f[2]) {
4037
			case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
4038
			case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
4039
			case "raw":
4040
				var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4041
				if(cur && cur.length > 0) q[f[1]] = cur[1];
4042
				break;
4043
		}
4044
	});
4045
4046
	if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4047
4048
	return p;
4049
}
4050
4051
var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4052
	'xmlns': XMLNS.EXT_PROPS,
4053
	'xmlns:vt': XMLNS.vt
4054
});
4055
4056
function write_ext_props(cp) {
4057
	var o = [], W = writextag;
4058
	if(!cp) cp = {};
4059
	cp.Application = "SheetJS";
4060
	o[o.length] = (XML_HEADER);
4061
	o[o.length] = (EXT_PROPS_XML_ROOT);
4062
4063
	EXT_PROPS.forEach(function(f) {
4064
		if(cp[f[1]] === undefined) return;
4065
		var v;
4066
		switch(f[2]) {
4067
			case 'string': v = String(cp[f[1]]); break;
4068
			case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4069
		}
4070
		if(v !== undefined) o[o.length] = (W(f[0], v));
4071
	});
4072
4073
	/* TODO: HeadingPairs, TitlesOfParts */
4074
	o[o.length] = (W('HeadingPairs', W('vt:vector', W('vt:variant', '<vt:lpstr>Worksheets</vt:lpstr>')+W('vt:variant', W('vt:i4', String(cp.Worksheets))), {size:2, baseType:"variant"})));
4075
	o[o.length] = (W('TitlesOfParts', W('vt:vector', cp.SheetNames.map(function(s) { return "<vt:lpstr>" + escapexml(s) + "</vt:lpstr>"; }).join(""), {size: cp.Worksheets, baseType:"lpstr"})));
4076
	if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4077
	return o.join("");
4078
}
4079
/* 15.2.12.2 Custom File Properties Part */
4080
XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4081
RELS.CUST_PROPS  = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4082
4083
var custregex = /<[^>]+>[^<]*/g;
4084
function parse_cust_props(data, opts) {
4085
	var p = {}, name = "";
4086
	var m = data.match(custregex);
4087
	if(m) for(var i = 0; i != m.length; ++i) {
4088
		var x = m[i], y = parsexmltag(x);
4089
		switch(y[0]) {
4090
			case '<?xml': break;
4091
			case '<Properties': break;
4092
			case '<property': name = y.name; break;
4093
			case '</property>': name = null; break;
4094
			default: if (x.indexOf('<vt:') === 0) {
4095
				var toks = x.split('>');
4096
				var type = toks[0].slice(4), text = toks[1];
4097
				/* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4098
				switch(type) {
4099
					case 'lpstr': case 'bstr': case 'lpwstr':
4100
						p[name] = unescapexml(text);
4101
						break;
4102
					case 'bool':
4103
						p[name] = parsexmlbool(text);
4104
						break;
4105
					case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4106
						p[name] = parseInt(text, 10);
4107
						break;
4108
					case 'r4': case 'r8': case 'decimal':
4109
						p[name] = parseFloat(text);
4110
						break;
4111
					case 'filetime': case 'date':
4112
						p[name] = parseDate(text);
4113
						break;
4114
					case 'cy': case 'error':
4115
						p[name] = unescapexml(text);
4116
						break;
4117
					default:
4118
						if(type.slice(-1) == '/') break;
4119
						if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4120
				}
4121
			} else if(x.slice(0,2) === "</") {/* empty */
4122
			} else if(opts.WTF) throw new Error(x);
4123
		}
4124
	}
4125
	return p;
4126
}
4127
4128
var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4129
	'xmlns': XMLNS.CUST_PROPS,
4130
	'xmlns:vt': XMLNS.vt
4131
});
4132
4133
function write_cust_props(cp) {
4134
	var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4135
	if(!cp) return o.join("");
4136
	var pid = 1;
4137
	keys(cp).forEach(function custprop(k) { ++pid;
4138
		o[o.length] = (writextag('property', write_vt(cp[k]), {
4139
			'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4140
			'pid': pid,
4141
			'name': k
4142
		}));
4143
	});
4144
	if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4145
	return o.join("");
4146
}
4147
/* Common Name -> XLML Name */
4148
var XLMLDocPropsMap = {
4149
	Title: 'Title',
4150
	Subject: 'Subject',
4151
	Author: 'Author',
4152
	Keywords: 'Keywords',
4153
	Comments: 'Description',
4154
	LastAuthor: 'LastAuthor',
4155
	RevNumber: 'Revision',
4156
	Application: 'AppName',
4157
	/* TotalTime: 'TotalTime', */
4158
	LastPrinted: 'LastPrinted',
4159
	CreatedDate: 'Created',
4160
	ModifiedDate: 'LastSaved',
4161
	/* Pages */
4162
	/* Words */
4163
	/* Characters */
4164
	Category: 'Category',
4165
	/* PresentationFormat */
4166
	Manager: 'Manager',
4167
	Company: 'Company',
4168
	/* Guid */
4169
	/* HyperlinkBase */
4170
	/* Bytes */
4171
	/* Lines */
4172
	/* Paragraphs */
4173
	/* CharactersWithSpaces */
4174
	AppVersion: 'Version',
4175
4176
	ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
4177
	Identifier: 'Identifier', /* NOTE: missing from schema */
4178
	Language: 'Language' /* NOTE: missing from schema */
4179
};
4180
var evert_XLMLDPM = evert(XLMLDocPropsMap);
4181
4182
function xlml_set_prop(Props, tag, val) {
4183
	tag = evert_XLMLDPM[tag] || tag;
4184
	Props[tag] = val;
4185
}
4186
4187
function xlml_write_docprops(Props, opts) {
4188
	var o = [];
4189
	keys(XLMLDocPropsMap).map(function(m) {
4190
		for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
4191
		for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
4192
		throw m;
4193
	}).forEach(function(p) {
4194
		if(Props[p[1]] == null) return;
4195
		var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
4196
		switch(p[2]) {
4197
			case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
4198
		}
4199
		if(typeof m == 'number') m = String(m);
4200
		else if(m === true || m === false) { m = m ? "1" : "0"; }
4201
		else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
4202
		o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
4203
	});
4204
	return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
4205
}
4206
function xlml_write_custprops(Props, Custprops) {
4207
	var BLACKLIST = ["Worksheets","SheetNames"];
4208
	var T = 'CustomDocumentProperties';
4209
	var o = [];
4210
	if(Props) keys(Props).forEach(function(k) {
4211
if(!Props.hasOwnProperty(k)) return;
4212
		for(var i = 0; i < CORE_PROPS.length; ++i) if(k == CORE_PROPS[i][1]) return;
4213
		for(i = 0; i < EXT_PROPS.length; ++i) if(k == EXT_PROPS[i][1]) return;
4214
		for(i = 0; i < BLACKLIST.length; ++i) if(k == BLACKLIST[i]) return;
4215
4216
		var m = Props[k];
4217
		var t = "string";
4218
		if(typeof m == 'number') { t = "float"; m = String(m); }
4219
		else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
4220
		else m = String(m);
4221
		o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
4222
	});
4223
	if(Custprops) keys(Custprops).forEach(function(k) {
4224
if(!Custprops.hasOwnProperty(k)) return;
4225
		if(Props && Props.hasOwnProperty(k)) return;
4226
		var m = Custprops[k];
4227
		var t = "string";
4228
		if(typeof m == 'number') { t = "float"; m = String(m); }
4229
		else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
4230
		else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); }
4231
		else m = String(m);
4232
		o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
4233
	});
4234
	return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
4235
}
4236
/* [MS-DTYP] 2.3.3 FILETIME */
4237
/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
4238
/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
4239
function parse_FILETIME(blob) {
4240
	var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
4241
	return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
4242
}
4243
function write_FILETIME(time) {
4244
	var date = (typeof time == "string") ? new Date(Date.parse(time)) : time;
4245
	var t = date.getTime() / 1000 + 11644473600;
4246
	var l = t % Math.pow(2,32), h = (t - l) / Math.pow(2,32);
4247
	l *= 1e7; h *= 1e7;
4248
	var w = (l / Math.pow(2,32)) | 0;
4249
	if(w > 0) { l = l % Math.pow(2,32); h += w; }
4250
	var o = new_buf(8); o.write_shift(4, l); o.write_shift(4, h); return o;
4251
}
4252
4253
/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
4254
function parse_lpstr(blob, type, pad) {
4255
	var start = blob.l;
4256
	var str = blob.read_shift(0, 'lpstr-cp');
4257
	if(pad) while((blob.l - start) & 3) ++blob.l;
4258
	return str;
4259
}
4260
4261
/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
4262
function parse_lpwstr(blob, type, pad) {
4263
	var str = blob.read_shift(0, 'lpwstr');
4264
	if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
4265
	return str;
4266
}
4267
4268
4269
/* [MS-OSHARED] 2.3.3.1.11 VtString */
4270
/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
4271
function parse_VtStringBase(blob, stringType, pad) {
4272
	if(stringType === 0x1F /*VT_LPWSTR*/) return parse_lpwstr(blob);
4273
	return parse_lpstr(blob, stringType, pad);
4274
}
4275
4276
function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
4277
function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); }
4278
4279
/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
4280
function parse_VtVecUnalignedLpstrValue(blob) {
4281
	var length = blob.read_shift(4);
4282
	var ret = [];
4283
	for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,'');
4284
	return ret;
4285
}
4286
4287
/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
4288
function parse_VtVecUnalignedLpstr(blob) {
4289
	return parse_VtVecUnalignedLpstrValue(blob);
4290
}
4291
4292
/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
4293
function parse_VtHeadingPair(blob) {
4294
	var headingString = parse_TypedPropertyValue(blob, VT_USTR);
4295
	var headerParts = parse_TypedPropertyValue(blob, VT_I4);
4296
	return [headingString, headerParts];
4297
}
4298
4299
/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
4300
function parse_VtVecHeadingPairValue(blob) {
4301
	var cElements = blob.read_shift(4);
4302
	var out = [];
4303
	for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
4304
	return out;
4305
}
4306
4307
/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
4308
function parse_VtVecHeadingPair(blob) {
4309
	// NOTE: When invoked, wType & padding were already consumed
4310
	return parse_VtVecHeadingPairValue(blob);
4311
}
4312
4313
/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
4314
function parse_dictionary(blob,CodePage) {
4315
	var cnt = blob.read_shift(4);
4316
	var dict = ({});
4317
	for(var j = 0; j != cnt; ++j) {
4318
		var pid = blob.read_shift(4);
4319
		var len = blob.read_shift(4);
4320
		dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
4321
		if(CodePage === 0x4B0 && (len % 2)) blob.l += 2;
4322
	}
4323
	if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
4324
	return dict;
4325
}
4326
4327
/* [MS-OLEPS] 2.9 BLOB */
4328
function parse_BLOB(blob) {
4329
	var size = blob.read_shift(4);
4330
	var bytes = blob.slice(blob.l,blob.l+size);
4331
	blob.l += size;
4332
	if((size & 3) > 0) blob.l += (4 - (size & 3)) & 3;
4333
	return bytes;
4334
}
4335
4336
/* [MS-OLEPS] 2.11 ClipboardData */
4337
function parse_ClipboardData(blob) {
4338
	// TODO
4339
	var o = {};
4340
	o.Size = blob.read_shift(4);
4341
	//o.Format = blob.read_shift(4);
4342
	blob.l += o.Size + 3 - (o.Size - 1) % 4;
4343
	return o;
4344
}
4345
4346
/* [MS-OLEPS] 2.15 TypedPropertyValue */
4347
function parse_TypedPropertyValue(blob, type, _opts) {
4348
	var t = blob.read_shift(2), ret, opts = _opts||{};
4349
	blob.l += 2;
4350
	if(type !== VT_VARIANT)
4351
	if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
4352
	switch(type === VT_VARIANT ? t : type) {
4353
		case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
4354
		case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
4355
		case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
4356
		case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
4357
		case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
4358
		case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
4359
		case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
4360
		case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
4361
		case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
4362
		case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw).replace(chr0,'');
4363
		case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t/*, 4*/).replace(chr0,'');
4364
		case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
4365
		case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
4366
		default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
4367
	}
4368
}
4369
function write_TypedPropertyValue(type, value) {
4370
	var o = new_buf(4), p = new_buf(4);
4371
	o.write_shift(4, type == 0x50 ? 0x1F : type);
4372
	switch(type) {
4373
		case 0x03 /*VT_I4*/: p.write_shift(-4, value); break;
4374
		case 0x05 /*VT_I4*/: p = new_buf(8); p.write_shift(8, value, 'f'); break;
4375
		case 0x0B /*VT_BOOL*/: p.write_shift(4, value ? 0x01 : 0x00); break;
4376
		case 0x40 /*VT_FILETIME*/:  p = write_FILETIME(value); break;
4377
		case 0x1F /*VT_LPWSTR*/:
4378
		case 0x50 /*VT_STRING*/:
4379
p = new_buf(4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
4380
			p.write_shift(4, value.length + 1);
4381
			p.write_shift(0, value, "dbcs");
4382
			while(p.l != p.length) p.write_shift(1, 0);
4383
			break;
4384
		default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + value);
4385
	}
4386
	return bconcat([o, p]);
4387
}
4388
4389
/* [MS-OLEPS] 2.20 PropertySet */
4390
function parse_PropertySet(blob, PIDSI) {
4391
	var start_addr = blob.l;
4392
	var size = blob.read_shift(4);
4393
	var NumProps = blob.read_shift(4);
4394
	var Props = [], i = 0;
4395
	var CodePage = 0;
4396
	var Dictionary = -1, DictObj = ({});
4397
	for(i = 0; i != NumProps; ++i) {
4398
		var PropID = blob.read_shift(4);
4399
		var Offset = blob.read_shift(4);
4400
		Props[i] = [PropID, Offset + start_addr];
4401
	}
4402
	Props.sort(function(x,y) { return x[1] - y[1]; });
4403
	var PropH = {};
4404
	for(i = 0; i != NumProps; ++i) {
4405
		if(blob.l !== Props[i][1]) {
4406
			var fail = true;
4407
			if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
4408
				case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break;
4409
				case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
4410
				case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
4411
			}
4412
			if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
4413
			if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
4414
		}
4415
		if(PIDSI) {
4416
			var piddsi = PIDSI[Props[i][0]];
4417
			PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
4418
			if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + ("0000" + String(PropH[piddsi.n] & 0xFFFF)).slice(-4);
4419
			if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
4420
				case 0: PropH[piddsi.n] = 1252;
4421
					/* falls through */
4422
				case 874:
4423
				case 932:
4424
				case 936:
4425
				case 949:
4426
				case 950:
4427
				case 1250:
4428
				case 1251:
4429
				case 1253:
4430
				case 1254:
4431
				case 1255:
4432
				case 1256:
4433
				case 1257:
4434
				case 1258:
4435
				case 10000:
4436
				case 1200:
4437
				case 1201:
4438
				case 1252:
4439
				case 65000: case -536:
4440
				case 65001: case -535:
4441
					set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
4442
				default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
4443
			}
4444
		} else {
4445
			if(Props[i][0] === 0x1) {
4446
				CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2));
4447
				set_cp(CodePage);
4448
				if(Dictionary !== -1) {
4449
					var oldpos = blob.l;
4450
					blob.l = Props[Dictionary][1];
4451
					DictObj = parse_dictionary(blob,CodePage);
4452
					blob.l = oldpos;
4453
				}
4454
			} else if(Props[i][0] === 0) {
4455
				if(CodePage === 0) { Dictionary = i; blob.l = Props[i+1][1]; continue; }
4456
				DictObj = parse_dictionary(blob,CodePage);
4457
			} else {
4458
				var name = DictObj[Props[i][0]];
4459
				var val;
4460
				/* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
4461
				switch(blob[blob.l]) {
4462
					case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
4463
					case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
4464
					case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
4465
					case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
4466
					case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
4467
					case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
4468
					case 0x0B /*VT_BOOL*/: blob.l += 4; val = parsebool(blob, 4); break;
4469
					case 0x40 /*VT_FILETIME*/: blob.l += 4; val = parseDate(parse_FILETIME(blob)); break;
4470
					default: throw new Error("unparsed value: " + blob[blob.l]);
4471
				}
4472
				PropH[name] = val;
4473
			}
4474
		}
4475
	}
4476
	blob.l = start_addr + size; /* step ahead to skip padding */
4477
	return PropH;
4478
}
4479
var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs);
4480
function guess_property_type(val) {
4481
	switch(typeof val) {
4482
		case "boolean": return 0x0B;
4483
		case "number": return ((val|0)==val) ? 0x03 : 0x05;
4484
		case "string": return 0x1F;
4485
		case "object": if(val instanceof Date) return 0x40; break;
4486
	}
4487
	return -1;
4488
}
4489
function write_PropertySet(entries, RE, PIDSI) {
4490
	var hdr = new_buf(8), piao = [], prop = [];
4491
	var sz = 8, i = 0;
4492
4493
	var pr = new_buf(8), pio = new_buf(8);
4494
	pr.write_shift(4, 0x0002);
4495
	pr.write_shift(4, 0x04B0);
4496
	pio.write_shift(4, 0x0001);
4497
	prop.push(pr); piao.push(pio);
4498
	sz += 8 + pr.length;
4499
4500
	if(!RE) {
4501
		pio = new_buf(8);
4502
		pio.write_shift(4, 0);
4503
		piao.unshift(pio);
4504
4505
		var bufs = [new_buf(4)];
4506
		bufs[0].write_shift(4, entries.length);
4507
		for(i = 0; i < entries.length; ++i) {
4508
			var value = entries[i][0];
4509
			pr = new_buf(4 + 4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
4510
			pr.write_shift(4, i+2);
4511
			pr.write_shift(4, value.length + 1);
4512
			pr.write_shift(0, value, "dbcs");
4513
			while(pr.l != pr.length) pr.write_shift(1, 0);
4514
			bufs.push(pr);
4515
		}
4516
		pr = bconcat(bufs);
4517
		prop.unshift(pr);
4518
		sz += 8 + pr.length;
4519
	}
4520
4521
	for(i = 0; i < entries.length; ++i) {
4522
		if(RE && !RE[entries[i][0]]) continue;
4523
		if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue;
4524
		if(entries[i][1] == null) continue;
4525
4526
		var val = entries[i][1], idx = 0;
4527
		if(RE) {
4528
			idx = +RE[entries[i][0]];
4529
			var pinfo = (PIDSI)[idx];
4530
			if(pinfo.p == "version" && typeof val == "string") {
4531
var arr = val.split(".");
4532
				val = ((+arr[0])<<16) + ((+arr[1])||0);
4533
			}
4534
			pr = write_TypedPropertyValue(pinfo.t, val);
4535
		} else {
4536
			var T = guess_property_type(val);
4537
			if(T == -1) { T = 0x1F; val = String(val); }
4538
			pr = write_TypedPropertyValue(T, val);
4539
		}
4540
		prop.push(pr);
4541
4542
		pio = new_buf(8);
4543
		pio.write_shift(4, !RE ? 2+i : idx);
4544
		piao.push(pio);
4545
4546
		sz += 8 + pr.length;
4547
	}
4548
4549
	var w = 8 * (prop.length + 1);
4550
	for(i = 0; i < prop.length; ++i) { piao[i].write_shift(4, w); w += prop[i].length; }
4551
	hdr.write_shift(4, sz);
4552
	hdr.write_shift(4, prop.length);
4553
	return bconcat([hdr].concat(piao).concat(prop));
4554
}
4555
4556
/* [MS-OLEPS] 2.21 PropertySetStream */
4557
function parse_PropertySetStream(file, PIDSI, clsid) {
4558
	var blob = file.content;
4559
	if(!blob) return ({});
4560
	prep_blob(blob, 0);
4561
4562
	var NumSets, FMTID0, FMTID1, Offset0, Offset1 = 0;
4563
	blob.chk('feff', 'Byte Order: ');
4564
4565
	/*var vers = */blob.read_shift(2); // TODO: check version
4566
	var SystemIdentifier = blob.read_shift(4);
4567
	var CLSID = blob.read_shift(16);
4568
	if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
4569
	NumSets = blob.read_shift(4);
4570
	if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
4571
	FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
4572
4573
	if(NumSets === 1 && Offset0 !== blob.l) throw new Error("Length mismatch: " + Offset0 + " !== " + blob.l);
4574
	else if(NumSets === 2) { FMTID1 = blob.read_shift(16); Offset1 = blob.read_shift(4); }
4575
	var PSet0 = parse_PropertySet(blob, PIDSI);
4576
4577
	var rval = ({ SystemIdentifier: SystemIdentifier });
4578
	for(var y in PSet0) rval[y] = PSet0[y];
4579
	//rval.blob = blob;
4580
	rval.FMTID = FMTID0;
4581
	//rval.PSet0 = PSet0;
4582
	if(NumSets === 1) return rval;
4583
	if(Offset1 - blob.l == 2) blob.l += 2;
4584
	if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
4585
	var PSet1;
4586
	try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
4587
	for(y in PSet1) rval[y] = PSet1[y];
4588
	rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
4589
	return rval;
4590
}
4591
function write_PropertySetStream(entries, clsid, RE, PIDSI, entries2, clsid2) {
4592
	var hdr = new_buf(entries2 ? 68 : 48);
4593
	var bufs = [hdr];
4594
	hdr.write_shift(2, 0xFFFE);
4595
	hdr.write_shift(2, 0x0000); /* TODO: type 1 props */
4596
	hdr.write_shift(4, 0x32363237);
4597
	hdr.write_shift(16, CFB.utils.consts.HEADER_CLSID, "hex");
4598
	hdr.write_shift(4, (entries2 ? 2 : 1));
4599
	hdr.write_shift(16, clsid, "hex");
4600
	hdr.write_shift(4, (entries2 ? 68 : 48));
4601
	var ps0 = write_PropertySet(entries, RE, PIDSI);
4602
	bufs.push(ps0);
4603
4604
	if(entries2) {
4605
		var ps1 = write_PropertySet(entries2, null, null);
4606
		hdr.write_shift(16, clsid2, "hex");
4607
		hdr.write_shift(4, 68 + ps0.length);
4608
		bufs.push(ps1);
4609
	}
4610
	return bconcat(bufs);
4611
}
4612
4613
function parsenoop2(blob, length) { blob.read_shift(length); return null; }
4614
function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j<n; ++j) o.write_shift(1, 0); return o; }
4615
4616
function parslurp(blob, length, cb) {
4617
	var arr = [], target = blob.l + length;
4618
	while(blob.l < target) arr.push(cb(blob, target - blob.l));
4619
	if(target !== blob.l) throw new Error("Slurp error");
4620
	return arr;
4621
}
4622
4623
function parsebool(blob, length) { return blob.read_shift(length) === 0x1; }
4624
function writebool(v, o) { if(!o) o=new_buf(2); o.write_shift(2, +!!v); return o; }
4625
4626
function parseuint16(blob) { return blob.read_shift(2, 'u'); }
4627
function writeuint16(v, o) { if(!o) o=new_buf(2); o.write_shift(2, v); return o; }
4628
function parseuint16a(blob, length) { return parslurp(blob,length,parseuint16);}
4629
4630
/* --- 2.5 Structures --- */
4631
4632
/* [MS-XLS] 2.5.10 Bes (boolean or error) */
4633
function parse_Bes(blob) {
4634
	var v = blob.read_shift(1), t = blob.read_shift(1);
4635
	return t === 0x01 ? v : v === 0x01;
4636
}
4637
function write_Bes(v, t, o) {
4638
	if(!o) o = new_buf(2);
4639
	o.write_shift(1, +v);
4640
	o.write_shift(1, ((t == 'e') ? 1 : 0));
4641
	return o;
4642
}
4643
4644
/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
4645
function parse_ShortXLUnicodeString(blob, length, opts) {
4646
	var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1);
4647
	var encoding = 'sbcs-cont';
4648
	var cp = current_codepage;
4649
	if(opts && opts.biff >= 8) current_codepage = 1200;
4650
	if(!opts || opts.biff == 8 ) {
4651
		var fHighByte = blob.read_shift(1);
4652
		if(fHighByte) { encoding = 'dbcs-cont'; }
4653
	} else if(opts.biff == 12) {
4654
		encoding = 'wstr';
4655
	}
4656
	if(opts.biff >= 2 && opts.biff <= 5) encoding = 'cpstr';
4657
	var o = cch ? blob.read_shift(cch, encoding) : "";
4658
	current_codepage = cp;
4659
	return o;
4660
}
4661
4662
/* 2.5.293 XLUnicodeRichExtendedString */
4663
function parse_XLUnicodeRichExtendedString(blob) {
4664
	var cp = current_codepage;
4665
	current_codepage = 1200;
4666
	var cch = blob.read_shift(2), flags = blob.read_shift(1);
4667
	var /*fHighByte = flags & 0x1,*/ fExtSt = flags & 0x4, fRichSt = flags & 0x8;
4668
	var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
4669
	var cRun = 0, cbExtRst;
4670
	var z = {};
4671
	if(fRichSt) cRun = blob.read_shift(2);
4672
	if(fExtSt) cbExtRst = blob.read_shift(4);
4673
	var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont';
4674
	var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
4675
	if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
4676
	if(fExtSt) blob.l += cbExtRst; //TODO: parse this
4677
	z.t = msg;
4678
	if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
4679
	current_codepage = cp;
4680
	return z;
4681
}
4682
4683
/* 2.5.296 XLUnicodeStringNoCch */
4684
function parse_XLUnicodeStringNoCch(blob, cch, opts) {
4685
	var retval;
4686
	if(opts) {
4687
		if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'cpstr');
4688
		if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
4689
	}
4690
	var fHighByte = blob.read_shift(1);
4691
	if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
4692
	else { retval = blob.read_shift(cch, 'dbcs-cont'); }
4693
	return retval;
4694
}
4695
4696
/* 2.5.294 XLUnicodeString */
4697
function parse_XLUnicodeString(blob, length, opts) {
4698
	var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
4699
	if(cch === 0) { blob.l++; return ""; }
4700
	return parse_XLUnicodeStringNoCch(blob, cch, opts);
4701
}
4702
/* BIFF5 override */
4703
function parse_XLUnicodeString2(blob, length, opts) {
4704
	if(opts.biff > 5) return parse_XLUnicodeString(blob, length, opts);
4705
	var cch = blob.read_shift(1);
4706
	if(cch === 0) { blob.l++; return ""; }
4707
	return blob.read_shift(cch, (opts.biff <= 4 || !blob.lens ) ? 'cpstr' : 'sbcs-cont');
4708
}
4709
/* TODO: BIFF5 and lower, codepage awareness */
4710
function write_XLUnicodeString(str, opts, o) {
4711
	if(!o) o = new_buf(3 + 2 * str.length);
4712
	o.write_shift(2, str.length);
4713
	o.write_shift(1, 1);
4714
	o.write_shift(31, str, 'utf16le');
4715
	return o;
4716
}
4717
4718
/* [MS-XLS] 2.5.61 ControlInfo */
4719
function parse_ControlInfo(blob) {
4720
	var flags = blob.read_shift(1);
4721
	blob.l++;
4722
	var accel = blob.read_shift(2);
4723
	blob.l += 2;
4724
	return [flags, accel];
4725
}
4726
4727
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
4728
function parse_URLMoniker(blob) {
4729
	var len = blob.read_shift(4), start = blob.l;
4730
	var extra = false;
4731
	if(len > 24) {
4732
		/* look ahead */
4733
		blob.l += len - 24;
4734
		if(blob.read_shift(16) === "795881f43b1d7f48af2c825dc4852763") extra = true;
4735
		blob.l = start;
4736
	}
4737
	var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
4738
	if(extra) blob.l += 24;
4739
	return url;
4740
}
4741
4742
/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
4743
function parse_FileMoniker(blob) {
4744
	blob.l += 2; //var cAnti = blob.read_shift(2);
4745
	var ansiPath = blob.read_shift(0, 'lpstr-ansi');
4746
	blob.l += 2; //var endServer = blob.read_shift(2);
4747
	if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker");
4748
	var sz = blob.read_shift(4);
4749
	if(sz === 0) return ansiPath.replace(/\\/g,"/");
4750
	var bytes = blob.read_shift(4);
4751
	if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker");
4752
	var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,"");
4753
	return unicodePath;
4754
}
4755
4756
/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
4757
function parse_HyperlinkMoniker(blob, length) {
4758
	var clsid = blob.read_shift(16); length -= 16;
4759
	switch(clsid) {
4760
		case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
4761
		case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
4762
		default: throw new Error("Unsupported Moniker " + clsid);
4763
	}
4764
}
4765
4766
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
4767
function parse_HyperlinkString(blob) {
4768
	var len = blob.read_shift(4);
4769
	var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
4770
	return o;
4771
}
4772
4773
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
4774
function parse_Hyperlink(blob, length) {
4775
	var end = blob.l + length;
4776
	var sVer = blob.read_shift(4);
4777
	if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
4778
	var flags = blob.read_shift(2);
4779
	blob.l += 2;
4780
	var displayName, targetFrameName, moniker, oleMoniker, Loc="", guid, fileTime;
4781
	if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
4782
	if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
4783
	if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
4784
	if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
4785
	if(flags & 0x0008) Loc = parse_HyperlinkString(blob, end - blob.l);
4786
	if(flags & 0x0020) guid = blob.read_shift(16);
4787
	if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
4788
	blob.l = end;
4789
	var target = targetFrameName||moniker||oleMoniker||"";
4790
	if(target && Loc) target+="#"+Loc;
4791
	if(!target) target = "#" + Loc;
4792
	var out = ({Target:target});
4793
	if(guid) out.guid = guid;
4794
	if(fileTime) out.time = fileTime;
4795
	if(displayName) out.Tooltip = displayName;
4796
	return out;
4797
}
4798
function write_Hyperlink(hl) {
4799
	var out = new_buf(512), i = 0;
4800
	var Target = hl.Target;
4801
	var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
4802
	switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
4803
	out.write_shift(4,2); out.write_shift(4, F);
4804
	var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
4805
	if(F == 0x1C) {
4806
		Target = Target.slice(1);
4807
		out.write_shift(4, Target.length + 1);
4808
		for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
4809
		out.write_shift(2, 0);
4810
	} else if(F & 0x02) {
4811
		data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
4812
		for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
4813
		out.write_shift(4, 2*(Target.length + 1));
4814
		for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
4815
		out.write_shift(2, 0);
4816
	} else {
4817
		data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
4818
		for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
4819
		var P = 0;
4820
		while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
4821
		out.write_shift(2, P);
4822
		out.write_shift(4, Target.length + 1);
4823
		for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
4824
		out.write_shift(1, 0);
4825
		out.write_shift(2, 0xFFFF);
4826
		out.write_shift(2, 0xDEAD);
4827
		for(i = 0; i < 6; ++i) out.write_shift(4, 0);
4828
	}
4829
	return out.slice(0, out.l);
4830
}
4831
4832
/* 2.5.178 LongRGBA */
4833
function parse_LongRGBA(blob) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
4834
4835
/* 2.5.177 LongRGB */
4836
function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
4837
4838
4839
/* [MS-XLS] 2.5.19 */
4840
function parse_XLSCell(blob) {
4841
	var rw = blob.read_shift(2); // 0-indexed
4842
	var col = blob.read_shift(2);
4843
	var ixfe = blob.read_shift(2);
4844
	return ({r:rw, c:col, ixfe:ixfe});
4845
}
4846
function write_XLSCell(R, C, ixfe, o) {
4847
	if(!o) o = new_buf(6);
4848
	o.write_shift(2, R);
4849
	o.write_shift(2, C);
4850
	o.write_shift(2, ixfe||0);
4851
	return o;
4852
}
4853
4854
/* [MS-XLS] 2.5.134 */
4855
function parse_frtHeader(blob) {
4856
	var rt = blob.read_shift(2);
4857
	var flags = blob.read_shift(2); // TODO: parse these flags
4858
	blob.l += 8;
4859
	return {type: rt, flags: flags};
4860
}
4861
4862
4863
4864
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
4865
4866
/* [MS-XLS] 2.5.344 */
4867
function parse_XTI(blob, length, opts) {
4868
	var w = opts.biff > 8 ? 4 : 2;
4869
	var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
4870
	return [iSupBook, itabFirst, itabLast];
4871
}
4872
4873
/* [MS-XLS] 2.5.218 */
4874
function parse_RkRec(blob) {
4875
	var ixfe = blob.read_shift(2);
4876
	var RK = parse_RkNumber(blob);
4877
	return [ixfe, RK];
4878
}
4879
4880
/* [MS-XLS] 2.5.1 */
4881
function parse_AddinUdf(blob, length, opts) {
4882
	blob.l += 4; length -= 4;
4883
	var l = blob.l + length;
4884
	var udfName = parse_ShortXLUnicodeString(blob, length, opts);
4885
	var cb = blob.read_shift(2);
4886
	l -= blob.l;
4887
	if(cb !== l) throw new Error("Malformed AddinUdf: padding = " + l + " != " + cb);
4888
	blob.l += cb;
4889
	return udfName;
4890
}
4891
4892
/* [MS-XLS] 2.5.209 TODO: Check sizes */
4893
function parse_Ref8U(blob) {
4894
	var rwFirst = blob.read_shift(2);
4895
	var rwLast = blob.read_shift(2);
4896
	var colFirst = blob.read_shift(2);
4897
	var colLast = blob.read_shift(2);
4898
	return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
4899
}
4900
function write_Ref8U(r, o) {
4901
	if(!o) o = new_buf(8);
4902
	o.write_shift(2, r.s.r);
4903
	o.write_shift(2, r.e.r);
4904
	o.write_shift(2, r.s.c);
4905
	o.write_shift(2, r.e.c);
4906
	return o;
4907
}
4908
4909
/* [MS-XLS] 2.5.211 */
4910
function parse_RefU(blob) {
4911
	var rwFirst = blob.read_shift(2);
4912
	var rwLast = blob.read_shift(2);
4913
	var colFirst = blob.read_shift(1);
4914
	var colLast = blob.read_shift(1);
4915
	return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
4916
}
4917
4918
/* [MS-XLS] 2.5.207 */
4919
var parse_Ref = parse_RefU;
4920
4921
/* [MS-XLS] 2.5.143 */
4922
function parse_FtCmo(blob) {
4923
	blob.l += 4;
4924
	var ot = blob.read_shift(2);
4925
	var id = blob.read_shift(2);
4926
	var flags = blob.read_shift(2);
4927
	blob.l+=12;
4928
	return [id, ot, flags];
4929
}
4930
4931
/* [MS-XLS] 2.5.149 */
4932
function parse_FtNts(blob) {
4933
	var out = {};
4934
	blob.l += 4;
4935
	blob.l += 16; // GUID TODO
4936
	out.fSharedNote = blob.read_shift(2);
4937
	blob.l += 4;
4938
	return out;
4939
}
4940
4941
/* [MS-XLS] 2.5.142 */
4942
function parse_FtCf(blob) {
4943
	var out = {};
4944
	blob.l += 4;
4945
	blob.cf = blob.read_shift(2);
4946
	return out;
4947
}
4948
4949
/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
4950
function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
4951
var FtTab = {
4952
0x00: parse_FtSkip,      /* FtEnd */
4953
0x04: parse_FtSkip,      /* FtMacro */
4954
0x05: parse_FtSkip,      /* FtButton */
4955
0x06: parse_FtSkip,      /* FtGmo */
4956
0x07: parse_FtCf,        /* FtCf */
4957
0x08: parse_FtSkip,      /* FtPioGrbit */
4958
0x09: parse_FtSkip,      /* FtPictFmla */
4959
0x0A: parse_FtSkip,      /* FtCbls */
4960
0x0B: parse_FtSkip,      /* FtRbo */
4961
0x0C: parse_FtSkip,      /* FtSbs */
4962
0x0D: parse_FtNts,       /* FtNts */
4963
0x0E: parse_FtSkip,      /* FtSbsFmla */
4964
0x0F: parse_FtSkip,      /* FtGboData */
4965
0x10: parse_FtSkip,      /* FtEdoData */
4966
0x11: parse_FtSkip,      /* FtRboData */
4967
0x12: parse_FtSkip,      /* FtCblsData */
4968
0x13: parse_FtSkip,      /* FtLbsData */
4969
0x14: parse_FtSkip,      /* FtCblsFmla */
4970
0x15: parse_FtCmo
4971
};
4972
function parse_FtArray(blob, length) {
4973
	var tgt = blob.l + length;
4974
	var fts = [];
4975
	while(blob.l < tgt) {
4976
		var ft = blob.read_shift(2);
4977
		blob.l-=2;
4978
		try {
4979
			fts.push(FtTab[ft](blob, tgt - blob.l));
4980
		} catch(e) { blob.l = tgt; return fts; }
4981
	}
4982
	if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
4983
	return fts;
4984
}
4985
4986
/* --- 2.4 Records --- */
4987
4988
/* [MS-XLS] 2.4.21 */
4989
function parse_BOF(blob, length) {
4990
	var o = {BIFFVer:0, dt:0};
4991
	o.BIFFVer = blob.read_shift(2); length -= 2;
4992
	if(length >= 2) { o.dt = blob.read_shift(2); blob.l -= 2; }
4993
	switch(o.BIFFVer) {
4994
		case 0x0600: /* BIFF8 */
4995
		case 0x0500: /* BIFF5 */
4996
		case 0x0400: /* BIFF4 */
4997
		case 0x0300: /* BIFF3 */
4998
		case 0x0200: /* BIFF2 */
4999
		case 0x0002: case 0x0007: /* BIFF2 */
5000
			break;
5001
		default: if(length > 6) throw new Error("Unexpected BIFF Ver " + o.BIFFVer);
5002
	}
5003
5004
	blob.read_shift(length);
5005
	return o;
5006
}
5007
function write_BOF(wb, t, o) {
5008
	var h = 0x0600, w = 16;
5009
	switch(o.bookType) {
5010
		case 'biff8': break;
5011
		case 'biff5': h = 0x0500; w = 8; break;
5012
		case 'biff4': h = 0x0004; w = 6; break;
5013
		case 'biff3': h = 0x0003; w = 6; break;
5014
		case 'biff2': h = 0x0002; w = 4; break;
5015
		case 'xla': break;
5016
		default: throw new Error("unsupported BIFF version");
5017
	}
5018
	var out = new_buf(w);
5019
	out.write_shift(2, h);
5020
	out.write_shift(2, t);
5021
	if(w > 4) out.write_shift(2, 0x7262);
5022
	if(w > 6) out.write_shift(2, 0x07CD);
5023
	if(w > 8) {
5024
		out.write_shift(2, 0xC009);
5025
		out.write_shift(2, 0x0001);
5026
		out.write_shift(2, 0x0706);
5027
		out.write_shift(2, 0x0000);
5028
	}
5029
	return out;
5030
}
5031
5032
5033
/* [MS-XLS] 2.4.146 */
5034
function parse_InterfaceHdr(blob, length) {
5035
	if(length === 0) return 0x04b0;
5036
	if((blob.read_shift(2))!==0x04b0){/* empty */}
5037
	return 0x04b0;
5038
}
5039
5040
5041
/* [MS-XLS] 2.4.349 */
5042
function parse_WriteAccess(blob, length, opts) {
5043
	if(opts.enc) { blob.l += length; return ""; }
5044
	var l = blob.l;
5045
	// TODO: make sure XLUnicodeString doesnt overrun
5046
	var UserName = parse_XLUnicodeString2(blob, 0, opts);
5047
	blob.read_shift(length + l - blob.l);
5048
	return UserName;
5049
}
5050
function write_WriteAccess(s, opts) {
5051
	var b8 = !opts || opts.biff == 8;
5052
	var o = new_buf(b8 ? 112 : 54);
5053
	o.write_shift(opts.biff == 8 ? 2 : 1, 7);
5054
	if(b8) o.write_shift(1, 0);
5055
	o.write_shift(4, 0x33336853);
5056
	o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
5057
	while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
5058
	return o;
5059
}
5060
5061
/* [MS-XLS] 2.4.351 */
5062
function parse_WsBool(blob, length, opts) {
5063
	var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
5064
	return { fDialog: flags & 0x10 };
5065
}
5066
5067
/* [MS-XLS] 2.4.28 */
5068
function parse_BoundSheet8(blob, length, opts) {
5069
	var pos = blob.read_shift(4);
5070
	var hidden = blob.read_shift(1) & 0x03;
5071
	var dt = blob.read_shift(1);
5072
	switch(dt) {
5073
		case 0: dt = 'Worksheet'; break;
5074
		case 1: dt = 'Macrosheet'; break;
5075
		case 2: dt = 'Chartsheet'; break;
5076
		case 6: dt = 'VBAModule'; break;
5077
	}
5078
	var name = parse_ShortXLUnicodeString(blob, 0, opts);
5079
	if(name.length === 0) name = "Sheet1";
5080
	return { pos:pos, hs:hidden, dt:dt, name:name };
5081
}
5082
function write_BoundSheet8(data, opts) {
5083
	var w = (!opts || opts.biff >= 8 ? 2 : 1);
5084
	var o = new_buf(8 + w * data.name.length);
5085
	o.write_shift(4, data.pos);
5086
	o.write_shift(1, data.hs || 0);
5087
	o.write_shift(1, data.dt);
5088
	o.write_shift(1, data.name.length);
5089
	if(opts.biff >= 8) o.write_shift(1, 1);
5090
	o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
5091
	var out = o.slice(0, o.l);
5092
	out.l = o.l; return out;
5093
}
5094
5095
/* [MS-XLS] 2.4.265 TODO */
5096
function parse_SST(blob, length) {
5097
	var end = blob.l + length;
5098
	var cnt = blob.read_shift(4);
5099
	var ucnt = blob.read_shift(4);
5100
	var strs = ([]);
5101
	for(var i = 0; i != ucnt && blob.l < end; ++i) {
5102
		strs.push(parse_XLUnicodeRichExtendedString(blob));
5103
	}
5104
	strs.Count = cnt; strs.Unique = ucnt;
5105
	return strs;
5106
}
5107
5108
/* [MS-XLS] 2.4.107 */
5109
function parse_ExtSST(blob, length) {
5110
	var extsst = {};
5111
	extsst.dsst = blob.read_shift(2);
5112
	blob.l += length-2;
5113
	return extsst;
5114
}
5115
5116
5117
/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
5118
function parse_Row(blob) {
5119
	var z = ({});
5120
	z.r = blob.read_shift(2);
5121
	z.c = blob.read_shift(2);
5122
	z.cnt = blob.read_shift(2) - z.c;
5123
	var miyRw = blob.read_shift(2);
5124
	blob.l += 4; // reserved(2), unused(2)
5125
	var flags = blob.read_shift(1); // various flags
5126
	blob.l += 3; // reserved(8), ixfe(12), flags(4)
5127
	if(flags & 0x07) z.level = flags & 0x07;
5128
	// collapsed: flags & 0x10
5129
	if(flags & 0x20) z.hidden = true;
5130
	if(flags & 0x40) z.hpt = miyRw / 20;
5131
	return z;
5132
}
5133
5134
5135
/* [MS-XLS] 2.4.125 */
5136
function parse_ForceFullCalculation(blob) {
5137
	var header = parse_frtHeader(blob);
5138
	if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
5139
	var fullcalc = blob.read_shift(4);
5140
	return fullcalc !== 0x0;
5141
}
5142
5143
5144
5145
5146
5147
/* [MS-XLS] 2.4.215 rt */
5148
function parse_RecalcId(blob) {
5149
	blob.read_shift(2);
5150
	return blob.read_shift(4);
5151
}
5152
5153
/* [MS-XLS] 2.4.87 */
5154
function parse_DefaultRowHeight(blob, length, opts) {
5155
	var f = 0;
5156
	if(!(opts && opts.biff == 2)) {
5157
		f = blob.read_shift(2);
5158
	}
5159
	var miyRw = blob.read_shift(2);
5160
	if((opts && opts.biff == 2)) {
5161
		f = 1 - (miyRw >> 15); miyRw &= 0x7fff;
5162
	}
5163
	var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
5164
	return [fl, miyRw];
5165
}
5166
5167
/* [MS-XLS] 2.4.345 TODO */
5168
function parse_Window1(blob) {
5169
	var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
5170
	var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
5171
	var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
5172
	return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
5173
		FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
5174
}
5175
function write_Window1() {
5176
	var o = new_buf(18);
5177
	o.write_shift(2, 0);
5178
	o.write_shift(2, 0);
5179
	o.write_shift(2, 0x7260);
5180
	o.write_shift(2, 0x44c0);
5181
	o.write_shift(2, 0x38);
5182
	o.write_shift(2, 0);
5183
	o.write_shift(2, 0);
5184
	o.write_shift(2, 1);
5185
	o.write_shift(2, 0x01f4);
5186
	return o;
5187
}
5188
/* [MS-XLS] 2.4.346 TODO */
5189
function parse_Window2(blob, length, opts) {
5190
	if(opts && opts.biff >= 2 && opts.biff < 8) return {};
5191
	var f = blob.read_shift(2);
5192
	return { RTL: f & 0x40 };
5193
}
5194
function write_Window2(view) {
5195
	var o = new_buf(18), f = 0x6b6;
5196
	if(view && view.RTL) f |= 0x40;
5197
	o.write_shift(2, f);
5198
	o.write_shift(4, 0);
5199
	o.write_shift(4, 64);
5200
	o.write_shift(4, 0);
5201
	o.write_shift(4, 0);
5202
	return o;
5203
}
5204
5205
/* [MS-XLS] 2.4.122 TODO */
5206
function parse_Font(blob, length, opts) {
5207
	var o = {
5208
		dyHeight: blob.read_shift(2),
5209
		fl: blob.read_shift(2)
5210
	};
5211
	switch((opts && opts.biff) || 8) {
5212
		case 2: break;
5213
		case 3: case 4: blob.l += 2; break;
5214
		default: blob.l += 10; break;
5215
	}
5216
	o.name = parse_ShortXLUnicodeString(blob, 0, opts);
5217
	return o;
5218
}
5219
function write_Font(data, opts) {
5220
	var name = data.name || "Arial";
5221
	var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
5222
	var o = new_buf(w);
5223
	o.write_shift(2, (data.sz || 12) * 20);
5224
	o.write_shift(4, 0);
5225
	o.write_shift(2, 400);
5226
	o.write_shift(4, 0);
5227
	o.write_shift(2, 0);
5228
	o.write_shift(1, name.length);
5229
	if(!b5) o.write_shift(1, 1);
5230
	o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
5231
	return o;
5232
}
5233
5234
/* [MS-XLS] 2.4.149 */
5235
function parse_LabelSst(blob) {
5236
	var cell = parse_XLSCell(blob);
5237
	cell.isst = blob.read_shift(4);
5238
	return cell;
5239
}
5240
5241
/* [MS-XLS] 2.4.148 */
5242
function parse_Label(blob, length, opts) {
5243
	var target = blob.l + length;
5244
	var cell = parse_XLSCell(blob, 6);
5245
	if(opts.biff == 2) blob.l++;
5246
	var str = parse_XLUnicodeString(blob, target - blob.l, opts);
5247
	cell.val = str;
5248
	return cell;
5249
}
5250
function write_Label(R, C, v, os, opts) {
5251
	var b8 = !opts || opts.biff == 8;
5252
	var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
5253
	write_XLSCell(R, C, os, o);
5254
	o.write_shift(2, v.length);
5255
	if(b8) o.write_shift(1, 1);
5256
	o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
5257
	return o;
5258
}
5259
5260
5261
/* [MS-XLS] 2.4.126 Number Formats */
5262
function parse_Format(blob, length, opts) {
5263
	var numFmtId = blob.read_shift(2);
5264
	var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
5265
	return [numFmtId, fmtstr];
5266
}
5267
function write_Format(i, f, opts, o) {
5268
	var b5 = (opts && (opts.biff == 5));
5269
	if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
5270
	o.write_shift(2, i);
5271
	o.write_shift((b5 ? 1 : 2), f.length);
5272
	if(!b5) o.write_shift(1, 1);
5273
	o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
5274
	var out = (o.length > o.l) ? o.slice(0, o.l) : o;
5275
	if(out.l == null) out.l = out.length;
5276
	return out;
5277
}
5278
var parse_BIFF2Format = parse_XLUnicodeString2;
5279
5280
/* [MS-XLS] 2.4.90 */
5281
function parse_Dimensions(blob, length, opts) {
5282
	var end = blob.l + length;
5283
	var w = opts.biff == 8 || !opts.biff ? 4 : 2;
5284
	var r = blob.read_shift(w), R = blob.read_shift(w);
5285
	var c = blob.read_shift(2), C = blob.read_shift(2);
5286
	blob.l = end;
5287
	return {s: {r:r, c:c}, e: {r:R, c:C}};
5288
}
5289
function write_Dimensions(range, opts) {
5290
	var w = opts.biff == 8 || !opts.biff ? 4 : 2;
5291
	var o = new_buf(2*w + 6);
5292
	o.write_shift(w, range.s.r);
5293
	o.write_shift(w, range.e.r + 1);
5294
	o.write_shift(2, range.s.c);
5295
	o.write_shift(2, range.e.c + 1);
5296
	o.write_shift(2, 0);
5297
	return o;
5298
}
5299
5300
/* [MS-XLS] 2.4.220 */
5301
function parse_RK(blob) {
5302
	var rw = blob.read_shift(2), col = blob.read_shift(2);
5303
	var rkrec = parse_RkRec(blob);
5304
	return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
5305
}
5306
5307
/* [MS-XLS] 2.4.175 */
5308
function parse_MulRk(blob, length) {
5309
	var target = blob.l + length - 2;
5310
	var rw = blob.read_shift(2), col = blob.read_shift(2);
5311
	var rkrecs = [];
5312
	while(blob.l < target) rkrecs.push(parse_RkRec(blob));
5313
	if(blob.l !== target) throw new Error("MulRK read error");
5314
	var lastcol = blob.read_shift(2);
5315
	if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
5316
	return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
5317
}
5318
/* [MS-XLS] 2.4.174 */
5319
function parse_MulBlank(blob, length) {
5320
	var target = blob.l + length - 2;
5321
	var rw = blob.read_shift(2), col = blob.read_shift(2);
5322
	var ixfes = [];
5323
	while(blob.l < target) ixfes.push(blob.read_shift(2));
5324
	if(blob.l !== target) throw new Error("MulBlank read error");
5325
	var lastcol = blob.read_shift(2);
5326
	if(ixfes.length != lastcol - col + 1) throw new Error("MulBlank length mismatch");
5327
	return {r:rw, c:col, C:lastcol, ixfe:ixfes};
5328
}
5329
5330
/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
5331
function parse_CellStyleXF(blob, length, style, opts) {
5332
	var o = {};
5333
	var a = blob.read_shift(4), b = blob.read_shift(4);
5334
	var c = blob.read_shift(4), d = blob.read_shift(2);
5335
	o.patternType = XLSFillPattern[c >> 26];
5336
5337
	if(!opts.cellStyles) return o;
5338
	o.alc = a & 0x07;
5339
	o.fWrap = (a >> 3) & 0x01;
5340
	o.alcV = (a >> 4) & 0x07;
5341
	o.fJustLast = (a >> 7) & 0x01;
5342
	o.trot = (a >> 8) & 0xFF;
5343
	o.cIndent = (a >> 16) & 0x0F;
5344
	o.fShrinkToFit = (a >> 20) & 0x01;
5345
	o.iReadOrder = (a >> 22) & 0x02;
5346
	o.fAtrNum = (a >> 26) & 0x01;
5347
	o.fAtrFnt = (a >> 27) & 0x01;
5348
	o.fAtrAlc = (a >> 28) & 0x01;
5349
	o.fAtrBdr = (a >> 29) & 0x01;
5350
	o.fAtrPat = (a >> 30) & 0x01;
5351
	o.fAtrProt = (a >> 31) & 0x01;
5352
5353
	o.dgLeft = b & 0x0F;
5354
	o.dgRight = (b >> 4) & 0x0F;
5355
	o.dgTop = (b >> 8) & 0x0F;
5356
	o.dgBottom = (b >> 12) & 0x0F;
5357
	o.icvLeft = (b >> 16) & 0x7F;
5358
	o.icvRight = (b >> 23) & 0x7F;
5359
	o.grbitDiag = (b >> 30) & 0x03;
5360
5361
	o.icvTop = c & 0x7F;
5362
	o.icvBottom = (c >> 7) & 0x7F;
5363
	o.icvDiag = (c >> 14) & 0x7F;
5364
	o.dgDiag = (c >> 21) & 0x0F;
5365
5366
	o.icvFore = d & 0x7F;
5367
	o.icvBack = (d >> 7) & 0x7F;
5368
	o.fsxButton = (d >> 14) & 0x01;
5369
	return o;
5370
}
5371
//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
5372
//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
5373
5374
/* [MS-XLS] 2.4.353 TODO: actually do this right */
5375
function parse_XF(blob, length, opts) {
5376
	var o = {};
5377
	o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
5378
	o.fStyle = (o.flags >> 2) & 0x01;
5379
	length -= 6;
5380
	o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
5381
	return o;
5382
}
5383
function write_XF(data, ixfeP, opts, o) {
5384
	var b5 = (opts && (opts.biff == 5));
5385
	if(!o) o = new_buf(b5 ? 16 : 20);
5386
	o.write_shift(2, 0);
5387
	if(data.style) {
5388
		o.write_shift(2, (data.numFmtId||0));
5389
		o.write_shift(2, 0xFFF4);
5390
	} else {
5391
		o.write_shift(2, (data.numFmtId||0));
5392
		o.write_shift(2, (ixfeP<<4));
5393
	}
5394
	o.write_shift(4, 0);
5395
	o.write_shift(4, 0);
5396
	if(!b5) o.write_shift(4, 0);
5397
	o.write_shift(2, 0);
5398
	return o;
5399
}
5400
5401
/* [MS-XLS] 2.4.134 */
5402
function parse_Guts(blob) {
5403
	blob.l += 4;
5404
	var out = [blob.read_shift(2), blob.read_shift(2)];
5405
	if(out[0] !== 0) out[0]--;
5406
	if(out[1] !== 0) out[1]--;
5407
	if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
5408
	return out;
5409
}
5410
function write_Guts(guts) {
5411
	var o = new_buf(8);
5412
	o.write_shift(4, 0);
5413
	o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
5414
	o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
5415
	return o;
5416
}
5417
5418
/* [MS-XLS] 2.4.24 */
5419
function parse_BoolErr(blob, length, opts) {
5420
	var cell = parse_XLSCell(blob, 6);
5421
	if(opts.biff == 2) ++blob.l;
5422
	var val = parse_Bes(blob, 2);
5423
	cell.val = val;
5424
	cell.t = (val === true || val === false) ? 'b' : 'e';
5425
	return cell;
5426
}
5427
function write_BoolErr(R, C, v, os, opts, t) {
5428
	var o = new_buf(8);
5429
	write_XLSCell(R, C, os, o);
5430
	write_Bes(v, t, o);
5431
	return o;
5432
}
5433
5434
/* [MS-XLS] 2.4.180 Number */
5435
function parse_Number(blob) {
5436
	var cell = parse_XLSCell(blob, 6);
5437
	var xnum = parse_Xnum(blob, 8);
5438
	cell.val = xnum;
5439
	return cell;
5440
}
5441
function write_Number(R, C, v, os) {
5442
	var o = new_buf(14);
5443
	write_XLSCell(R, C, os, o);
5444
	write_Xnum(v, o);
5445
	return o;
5446
}
5447
5448
var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
5449
5450
/* [MS-XLS] 2.4.271 */
5451
function parse_SupBook(blob, length, opts) {
5452
	var end = blob.l + length;
5453
	var ctab = blob.read_shift(2);
5454
	var cch = blob.read_shift(2);
5455
	opts.sbcch = cch;
5456
	if(cch == 0x0401 || cch == 0x3A01) return [cch, ctab];
5457
	if(cch < 0x01 || cch >0xff) throw new Error("Unexpected SupBook type: "+cch);
5458
	var virtPath = parse_XLUnicodeStringNoCch(blob, cch);
5459
	/* TODO: 2.5.277 Virtual Path */
5460
	var rgst = [];
5461
	while(end > blob.l) rgst.push(parse_XLUnicodeString(blob));
5462
	return [cch, ctab, virtPath, rgst];
5463
}
5464
5465
/* [MS-XLS] 2.4.105 TODO */
5466
function parse_ExternName(blob, length, opts) {
5467
	var flags = blob.read_shift(2);
5468
	var body;
5469
	var o = ({
5470
		fBuiltIn: flags & 0x01,
5471
		fWantAdvise: (flags >>> 1) & 0x01,
5472
		fWantPict: (flags >>> 2) & 0x01,
5473
		fOle: (flags >>> 3) & 0x01,
5474
		fOleLink: (flags >>> 4) & 0x01,
5475
		cf: (flags >>> 5) & 0x3FF,
5476
		fIcon: flags >>> 15 & 0x01
5477
	});
5478
	if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts);
5479
	//else throw new Error("unsupported SupBook cch: " + opts.sbcch);
5480
	o.body = body || blob.read_shift(length-2);
5481
	if(typeof body === "string") o.Name = body;
5482
	return o;
5483
}
5484
5485
/* [MS-XLS] 2.4.150 TODO */
5486
var XLSLblBuiltIn = [
5487
	"_xlnm.Consolidate_Area",
5488
	"_xlnm.Auto_Open",
5489
	"_xlnm.Auto_Close",
5490
	"_xlnm.Extract",
5491
	"_xlnm.Database",
5492
	"_xlnm.Criteria",
5493
	"_xlnm.Print_Area",
5494
	"_xlnm.Print_Titles",
5495
	"_xlnm.Recorder",
5496
	"_xlnm.Data_Form",
5497
	"_xlnm.Auto_Activate",
5498
	"_xlnm.Auto_Deactivate",
5499
	"_xlnm.Sheet_Title",
5500
	"_xlnm._FilterDatabase"
5501
];
5502
function parse_Lbl(blob, length, opts) {
5503
	var target = blob.l + length;
5504
	var flags = blob.read_shift(2);
5505
	var chKey = blob.read_shift(1);
5506
	var cch = blob.read_shift(1);
5507
	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
5508
	var itab = 0;
5509
	if(!opts || opts.biff >= 5) {
5510
		if(opts.biff != 5) blob.l += 2;
5511
		itab = blob.read_shift(2);
5512
		if(opts.biff == 5) blob.l += 2;
5513
		blob.l += 4;
5514
	}
5515
	var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
5516
	if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
5517
	var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
5518
	var rgce = target == blob.l || cce === 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
5519
	return {
5520
		chKey: chKey,
5521
		Name: name,
5522
		itab: itab,
5523
		rgce: rgce
5524
	};
5525
}
5526
5527
/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
5528
function parse_ExternSheet(blob, length, opts) {
5529
	if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
5530
	var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
5531
	while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
5532
		// [iSupBook, itabFirst, itabLast];
5533
	if(blob.l != target) throw new Error("Bad ExternSheet: " + blob.l + " != " + target);
5534
	return o;
5535
}
5536
function parse_BIFF5ExternSheet(blob, length, opts) {
5537
	if(blob[blob.l + 1] == 0x03) blob[blob.l]++;
5538
	var o = parse_ShortXLUnicodeString(blob, length, opts);
5539
	return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
5540
}
5541
5542
/* [MS-XLS] 2.4.176 TODO: check older biff */
5543
function parse_NameCmt(blob, length, opts) {
5544
	if(opts.biff < 8) { blob.l += length; return; }
5545
	var cchName = blob.read_shift(2);
5546
	var cchComment = blob.read_shift(2);
5547
	var name = parse_XLUnicodeStringNoCch(blob, cchName, opts);
5548
	var comment = parse_XLUnicodeStringNoCch(blob, cchComment, opts);
5549
	return [name, comment];
5550
}
5551
5552
/* [MS-XLS] 2.4.260 */
5553
function parse_ShrFmla(blob, length, opts) {
5554
	var ref = parse_RefU(blob, 6);
5555
	blob.l++;
5556
	var cUse = blob.read_shift(1);
5557
	length -= 8;
5558
	return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
5559
}
5560
5561
/* [MS-XLS] 2.4.4 TODO */
5562
function parse_Array(blob, length, opts) {
5563
	var ref = parse_Ref(blob, 6);
5564
	/* TODO: fAlwaysCalc */
5565
	switch(opts.biff) {
5566
		case 2: blob.l ++; length -= 7; break;
5567
		case 3: case 4: blob.l += 2; length -= 8; break;
5568
		default: blob.l += 6; length -= 12;
5569
	}
5570
	return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
5571
}
5572
5573
/* [MS-XLS] 2.4.173 */
5574
function parse_MTRSettings(blob) {
5575
	var fMTREnabled = blob.read_shift(4) !== 0x00;
5576
	var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
5577
	var cUserThreadCount = blob.read_shift(4);
5578
	return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
5579
}
5580
5581
/* [MS-XLS] 2.5.186 TODO: BIFF5 */
5582
function parse_NoteSh(blob, length, opts) {
5583
	if(opts.biff < 8) return;
5584
	var row = blob.read_shift(2), col = blob.read_shift(2);
5585
	var flags = blob.read_shift(2), idObj = blob.read_shift(2);
5586
	var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
5587
	if(opts.biff < 8) blob.read_shift(1);
5588
	return [{r:row,c:col}, stAuthor, idObj, flags];
5589
}
5590
5591
/* [MS-XLS] 2.4.179 */
5592
function parse_Note(blob, length, opts) {
5593
	/* TODO: Support revisions */
5594
	return parse_NoteSh(blob, length, opts);
5595
}
5596
5597
/* [MS-XLS] 2.4.168 */
5598
function parse_MergeCells(blob, length) {
5599
	var merges = [];
5600
	var cmcs = blob.read_shift(2);
5601
	while (cmcs--) merges.push(parse_Ref8U(blob,length));
5602
	return merges;
5603
}
5604
function write_MergeCells(merges) {
5605
	var o = new_buf(2 + merges.length * 8);
5606
	o.write_shift(2, merges.length);
5607
	for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o);
5608
	return o;
5609
}
5610
5611
/* [MS-XLS] 2.4.181 TODO: parse all the things! */
5612
function parse_Obj(blob, length, opts) {
5613
	if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
5614
	var cmo = parse_FtCmo(blob, 22); // id, ot, flags
5615
	var fts = parse_FtArray(blob, length-22, cmo[1]);
5616
	return { cmo: cmo, ft:fts };
5617
}
5618
/* from older spec */
5619
var parse_BIFF5OT = [];
5620
parse_BIFF5OT[0x08] = function(blob, length) {
5621
	var tgt = blob.l + length;
5622
	blob.l += 10; // todo
5623
	var cf = blob.read_shift(2);
5624
	blob.l += 4;
5625
	blob.l += 2; //var cbPictFmla = blob.read_shift(2);
5626
	blob.l += 2;
5627
	blob.l += 2; //var grbit = blob.read_shift(2);
5628
	blob.l += 4;
5629
	var cchName = blob.read_shift(1);
5630
	blob.l += cchName; // TODO: stName
5631
	blob.l = tgt; // TODO: fmla
5632
	return { fmt:cf };
5633
};
5634
5635
function parse_BIFF5Obj(blob, length, opts) {
5636
	blob.l += 4; //var cnt = blob.read_shift(4);
5637
	var ot = blob.read_shift(2);
5638
	var id = blob.read_shift(2);
5639
	var grbit = blob.read_shift(2);
5640
	blob.l += 2; //var colL = blob.read_shift(2);
5641
	blob.l += 2; //var dxL = blob.read_shift(2);
5642
	blob.l += 2; //var rwT = blob.read_shift(2);
5643
	blob.l += 2; //var dyT = blob.read_shift(2);
5644
	blob.l += 2; //var colR = blob.read_shift(2);
5645
	blob.l += 2; //var dxR = blob.read_shift(2);
5646
	blob.l += 2; //var rwB = blob.read_shift(2);
5647
	blob.l += 2; //var dyB = blob.read_shift(2);
5648
	blob.l += 2; //var cbMacro = blob.read_shift(2);
5649
	blob.l += 6;
5650
	length -= 36;
5651
	var fts = [];
5652
	fts.push((parse_BIFF5OT[ot]||parsenoop)(blob, length, opts));
5653
	return { cmo: [id, ot, grbit], ft:fts };
5654
}
5655
5656
/* [MS-XLS] 2.4.329 TODO: parse properly */
5657
function parse_TxO(blob, length, opts) {
5658
	var s = blob.l;
5659
	var texts = "";
5660
try {
5661
	blob.l += 4;
5662
	var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
5663
	var controlInfo; // eslint-disable-line no-unused-vars
5664
	if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
5665
	else controlInfo = parse_ControlInfo(blob, 6, opts);
5666
	var cchText = blob.read_shift(2);
5667
	/*var cbRuns = */blob.read_shift(2);
5668
	/*var ifntEmpty = */parseuint16(blob, 2);
5669
	var len = blob.read_shift(2);
5670
	blob.l += len;
5671
	//var fmla = parse_ObjFmla(blob, s + length - blob.l);
5672
5673
	for(var i = 1; i < blob.lens.length-1; ++i) {
5674
		if(blob.l-s != blob.lens[i]) throw new Error("TxO: bad continue record");
5675
		var hdr = blob[blob.l];
5676
		var t = parse_XLUnicodeStringNoCch(blob, blob.lens[i+1]-blob.lens[i]-1);
5677
		texts += t;
5678
		if(texts.length >= (hdr ? cchText : 2*cchText)) break;
5679
	}
5680
	if(texts.length !== cchText && texts.length !== cchText*2) {
5681
		throw new Error("cchText: " + cchText + " != " + texts.length);
5682
	}
5683
5684
	blob.l = s + length;
5685
	/* [MS-XLS] 2.5.272 TxORuns */
5686
//	var rgTxoRuns = [];
5687
//	for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
5688
//	var cchText2 = blob.read_shift(2);
5689
//	if(cchText2 !== cchText) throw new Error("TxOLastRun mismatch: " + cchText2 + " " + cchText);
5690
//	blob.l += 6;
5691
//	if(s + length != blob.l) throw new Error("TxO " + (s + length) + ", at " + blob.l);
5692
	return { t: texts };
5693
} catch(e) { blob.l = s + length; return { t: texts }; }
5694
}
5695
5696
/* [MS-XLS] 2.4.140 */
5697
function parse_HLink(blob, length) {
5698
	var ref = parse_Ref8U(blob, 8);
5699
	blob.l += 16; /* CLSID */
5700
	var hlink = parse_Hyperlink(blob, length-24);
5701
	return [ref, hlink];
5702
}
5703
function write_HLink(hl) {
5704
	var O = new_buf(24);
5705
	var ref = decode_cell(hl[0]);
5706
	O.write_shift(2, ref.r); O.write_shift(2, ref.r);
5707
	O.write_shift(2, ref.c); O.write_shift(2, ref.c);
5708
	var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
5709
	for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
5710
	return bconcat([O, write_Hyperlink(hl[1])]);
5711
}
5712
5713
5714
/* [MS-XLS] 2.4.141 */
5715
function parse_HLinkTooltip(blob, length) {
5716
	blob.read_shift(2);
5717
	var ref = parse_Ref8U(blob, 8);
5718
	var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
5719
	wzTooltip = wzTooltip.replace(chr0,"");
5720
	return [ref, wzTooltip];
5721
}
5722
function write_HLinkTooltip(hl) {
5723
	var TT = hl[1].Tooltip;
5724
	var O = new_buf(10 + 2 * (TT.length + 1));
5725
	O.write_shift(2, 0x0800);
5726
	var ref = decode_cell(hl[0]);
5727
	O.write_shift(2, ref.r); O.write_shift(2, ref.r);
5728
	O.write_shift(2, ref.c); O.write_shift(2, ref.c);
5729
	for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
5730
	O.write_shift(2, 0);
5731
	return O;
5732
}
5733
5734
/* [MS-XLS] 2.4.63 */
5735
function parse_Country(blob) {
5736
	var o = [0,0], d;
5737
	d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
5738
	d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
5739
	return o;
5740
}
5741
function write_Country(o) {
5742
	if(!o) o = new_buf(4);
5743
	o.write_shift(2, 0x01);
5744
	o.write_shift(2, 0x01);
5745
	return o;
5746
}
5747
5748
/* [MS-XLS] 2.4.50 ClrtClient */
5749
function parse_ClrtClient(blob) {
5750
	var ccv = blob.read_shift(2);
5751
	var o = [];
5752
	while(ccv-->0) o.push(parse_LongRGB(blob, 8));
5753
	return o;
5754
}
5755
5756
/* [MS-XLS] 2.4.188 */
5757
function parse_Palette(blob) {
5758
	var ccv = blob.read_shift(2);
5759
	var o = [];
5760
	while(ccv-->0) o.push(parse_LongRGB(blob, 8));
5761
	return o;
5762
}
5763
5764
/* [MS-XLS] 2.4.354 */
5765
function parse_XFCRC(blob) {
5766
	blob.l += 2;
5767
	var o = {cxfs:0, crc:0};
5768
	o.cxfs = blob.read_shift(2);
5769
	o.crc = blob.read_shift(4);
5770
	return o;
5771
}
5772
5773
/* [MS-XLS] 2.4.53 TODO: parse flags */
5774
/* [MS-XLSB] 2.4.323 TODO: parse flags */
5775
function parse_ColInfo(blob, length, opts) {
5776
	if(!opts.cellStyles) return parsenoop(blob, length);
5777
	var w = opts && opts.biff >= 12 ? 4 : 2;
5778
	var colFirst = blob.read_shift(w);
5779
	var colLast = blob.read_shift(w);
5780
	var coldx = blob.read_shift(w);
5781
	var ixfe = blob.read_shift(w);
5782
	var flags = blob.read_shift(2);
5783
	if(w == 2) blob.l += 2;
5784
	return {s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags};
5785
}
5786
5787
/* [MS-XLS] 2.4.257 */
5788
function parse_Setup(blob, length) {
5789
	var o = {};
5790
	if(length < 32) return o;
5791
	blob.l += 16;
5792
	o.header = parse_Xnum(blob, 8);
5793
	o.footer = parse_Xnum(blob, 8);
5794
	blob.l += 2;
5795
	return o;
5796
}
5797
5798
/* [MS-XLS] 2.4.261 */
5799
function parse_ShtProps(blob, length, opts) {
5800
	var def = {area:false};
5801
	if(opts.biff != 5) { blob.l += length; return def; }
5802
	var d = blob.read_shift(1); blob.l += 3;
5803
	if((d & 0x10)) def.area = true;
5804
	return def;
5805
}
5806
5807
/* [MS-XLS] 2.4.241 */
5808
function write_RRTabId(n) {
5809
	var out = new_buf(2 * n);
5810
	for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
5811
	return out;
5812
}
5813
5814
var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
5815
var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
5816
var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
5817
5818
/* --- Specific to versions before BIFF8 --- */
5819
function parse_ImData(blob) {
5820
	var cf = blob.read_shift(2);
5821
	var env = blob.read_shift(2);
5822
	var lcb = blob.read_shift(4);
5823
	var o = {fmt:cf, env:env, len:lcb, data:blob.slice(blob.l,blob.l+lcb)};
5824
	blob.l += lcb;
5825
	return o;
5826
}
5827
5828
/* BIFF2_??? where ??? is the name from [XLS] */
5829
function parse_BIFF2STR(blob, length, opts) {
5830
	var cell = parse_XLSCell(blob, 6);
5831
	++blob.l;
5832
	var str = parse_XLUnicodeString2(blob, length-7, opts);
5833
	cell.t = 'str';
5834
	cell.val = str;
5835
	return cell;
5836
}
5837
5838
function parse_BIFF2NUM(blob) {
5839
	var cell = parse_XLSCell(blob, 6);
5840
	++blob.l;
5841
	var num = parse_Xnum(blob, 8);
5842
	cell.t = 'n';
5843
	cell.val = num;
5844
	return cell;
5845
}
5846
function write_BIFF2NUM(r, c, val) {
5847
	var out = new_buf(15);
5848
	write_BIFF2Cell(out, r, c);
5849
	out.write_shift(8, val, 'f');
5850
	return out;
5851
}
5852
5853
function parse_BIFF2INT(blob) {
5854
	var cell = parse_XLSCell(blob, 6);
5855
	++blob.l;
5856
	var num = blob.read_shift(2);
5857
	cell.t = 'n';
5858
	cell.val = num;
5859
	return cell;
5860
}
5861
function write_BIFF2INT(r, c, val) {
5862
	var out = new_buf(9);
5863
	write_BIFF2Cell(out, r, c);
5864
	out.write_shift(2, val);
5865
	return out;
5866
}
5867
5868
function parse_BIFF2STRING(blob) {
5869
	var cch = blob.read_shift(1);
5870
	if(cch === 0) { blob.l++; return ""; }
5871
	return blob.read_shift(cch, 'sbcs-cont');
5872
}
5873
5874
/* TODO: convert to BIFF8 font struct */
5875
function parse_BIFF2FONTXTRA(blob, length) {
5876
	blob.l += 6; // unknown
5877
	blob.l += 2; // font weight "bls"
5878
	blob.l += 1; // charset
5879
	blob.l += 3; // unknown
5880
	blob.l += 1; // font family
5881
	blob.l += length - 13;
5882
}
5883
5884
/* TODO: parse rich text runs */
5885
function parse_RString(blob, length, opts) {
5886
	var end = blob.l + length;
5887
	var cell = parse_XLSCell(blob, 6);
5888
	var cch = blob.read_shift(2);
5889
	var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
5890
	blob.l = end;
5891
	cell.t = 'str';
5892
	cell.val = str;
5893
	return cell;
5894
}
5895
/* from js-harb (C) 2014-present  SheetJS */
5896
var DBF = (function() {
5897
var dbf_codepage_map = {
5898
	/* Code Pages Supported by Visual FoxPro */
5899
0x01:   437,           0x02:   850,
5900
0x03:  1252,           0x04: 10000,
5901
0x64:   852,           0x65:   866,
5902
0x66:   865,           0x67:   861,
5903
0x68:   895,           0x69:   620,
5904
0x6A:   737,           0x6B:   857,
5905
0x78:   950,           0x79:   949,
5906
0x7A:   936,           0x7B:   932,
5907
0x7C:   874,           0x7D:  1255,
5908
0x7E:  1256,           0x96: 10007,
5909
0x97: 10029,           0x98: 10006,
5910
0xC8:  1250,           0xC9:  1251,
5911
0xCA:  1254,           0xCB:  1253,
5912
5913
	/* shapefile DBF extension */
5914
0x00: 20127,           0x08:   865,
5915
0x09:   437,           0x0A:   850,
5916
0x0B:   437,           0x0D:   437,
5917
0x0E:   850,           0x0F:   437,
5918
0x10:   850,           0x11:   437,
5919
0x12:   850,           0x13:   932,
5920
0x14:   850,           0x15:   437,
5921
0x16:   850,           0x17:   865,
5922
0x18:   437,           0x19:   437,
5923
0x1A:   850,           0x1B:   437,
5924
0x1C:   863,           0x1D:   850,
5925
0x1F:   852,           0x22:   852,
5926
0x23:   852,           0x24:   860,
5927
0x25:   850,           0x26:   866,
5928
0x37:   850,           0x40:   852,
5929
0x4D:   936,           0x4E:   949,
5930
0x4F:   950,           0x50:   874,
5931
0x57:  1252,           0x58:  1252,
5932
0x59:  1252,
5933
5934
0xFF: 16969
5935
};
5936
5937
/* TODO: find an actual specification */
5938
function dbf_to_aoa(buf, opts) {
5939
	var out = [];
5940
	/* TODO: browser based */
5941
	var d = (new_raw_buf(1));
5942
	switch(opts.type) {
5943
		case 'base64': d = s2a(Base64.decode(buf)); break;
5944
		case 'binary': d = s2a(buf); break;
5945
		case 'buffer':
5946
		case 'array': d = buf; break;
5947
	}
5948
	prep_blob(d, 0);
5949
	/* header */
5950
	var ft = d.read_shift(1);
5951
	var memo = false;
5952
	var vfp = false, l7 = false;
5953
	switch(ft) {
5954
		case 0x02: case 0x03: break;
5955
		case 0x30: vfp = true; memo = true; break;
5956
		case 0x31: vfp = true; break;
5957
		case 0x83: memo = true; break;
5958
		case 0x8B: memo = true; break;
5959
		case 0x8C: memo = true; l7 = true; break;
5960
		case 0xF5: memo = true; break;
5961
		default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
5962
	}
5963
	var /*filedate = new Date(),*/ nrow = 0, fpos = 0;
5964
	if(ft == 0x02) nrow = d.read_shift(2);
5965
	/*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3;
5966
	if(ft != 0x02) nrow = d.read_shift(4);
5967
	if(ft != 0x02) fpos = d.read_shift(2);
5968
	var rlen = d.read_shift(2);
5969
5970
	var /*flags = 0,*/ current_cp = 1252;
5971
	if(ft != 0x02) {
5972
	d.l+=16;
5973
	/*flags = */d.read_shift(1);
5974
	//if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
5975
5976
	/* codepage present in FoxPro */
5977
	if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
5978
	d.l+=1;
5979
5980
	d.l+=2;
5981
	}
5982
	if(l7) d.l += 36;
5983
var fields = [], field = ({});
5984
	var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
5985
	while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
5986
		field = ({});
5987
		field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
5988
		d.l += ww;
5989
		field.type = String.fromCharCode(d.read_shift(1));
5990
		if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
5991
		field.len = d.read_shift(1);
5992
		if(ft == 0x02) field.offset = d.read_shift(2);
5993
		field.dec = d.read_shift(1);
5994
		if(field.name.length) fields.push(field);
5995
		if(ft != 0x02) d.l += l7 ? 13 : 14;
5996
		switch(field.type) {
5997
			case 'B': // VFP Double
5998
				if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
5999
				break;
6000
			case 'G': // General
6001
			case 'P': // Picture
6002
				if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6003
				break;
6004
			case 'C': // character
6005
			case 'D': // date
6006
			case 'F': // floating point
6007
			case 'I': // long
6008
			case 'L': // boolean
6009
			case 'M': // memo
6010
			case 'N': // number
6011
			case 'O': // double
6012
			case 'T': // datetime
6013
			case 'Y': // currency
6014
			case '0': // VFP _NullFlags
6015
			case '@': // timestamp
6016
			case '+': // autoincrement
6017
				break;
6018
			default: throw new Error('Unknown Field Type: ' + field.type);
6019
		}
6020
	}
6021
	if(d[d.l] !== 0x0D) d.l = fpos-1;
6022
	else if(ft == 0x02) d.l = 0x209;
6023
	if(ft != 0x02) {
6024
		if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
6025
		d.l = fpos;
6026
	}
6027
	/* data */
6028
	var R = 0, C = 0;
6029
	out[0] = [];
6030
	for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
6031
	while(nrow-- > 0) {
6032
		if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
6033
		++d.l;
6034
		out[++R] = []; C = 0;
6035
		for(C = 0; C != fields.length; ++C) {
6036
			var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
6037
			prep_blob(dd, 0);
6038
			var s = cptable.utils.decode(current_cp, dd);
6039
			switch(fields[C].type) {
6040
				case 'C':
6041
					out[R][C] = cptable.utils.decode(current_cp, dd);
6042
					out[R][C] = out[R][C].trim();
6043
					break;
6044
				case 'D':
6045
					if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
6046
					else out[R][C] = s;
6047
					break;
6048
				case 'F': out[R][C] = parseFloat(s.trim()); break;
6049
				case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
6050
				case 'L': switch(s.toUpperCase()) {
6051
					case 'Y': case 'T': out[R][C] = true; break;
6052
					case 'N': case 'F': out[R][C] = false; break;
6053
					case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
6054
					default: throw new Error("DBF Unrecognized L:|" + s + "|");
6055
					} break;
6056
				case 'M': /* TODO: handle memo files */
6057
					if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
6058
					out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
6059
					break;
6060
				case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
6061
				case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
6062
				case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
6063
				case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
6064
				case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
6065
				case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
6066
					/* falls through */
6067
				case 'G': case 'P': dd.l += fields[C].len; break;
6068
				case '0':
6069
					if(fields[C].name === '_NullFlags') break;
6070
					/* falls through */
6071
				default: throw new Error("DBF Unsupported data type " + fields[C].type);
6072
			}
6073
		}
6074
	}
6075
	if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16));
6076
	if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
6077
	return out;
6078
}
6079
6080
function dbf_to_sheet(buf, opts) {
6081
	var o = opts || {};
6082
	if(!o.dateNF) o.dateNF = "yyyymmdd";
6083
	return aoa_to_sheet(dbf_to_aoa(buf, o), o);
6084
}
6085
6086
function dbf_to_workbook(buf, opts) {
6087
	try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
6088
	catch(e) { if(opts && opts.WTF) throw e; }
6089
	return ({SheetNames:[],Sheets:{}});
6090
}
6091
6092
var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
6093
function sheet_to_dbf(ws, opts) {
6094
	var o = opts || {};
6095
	if(o.type == "string") throw new Error("Cannot write DBF to JS string");
6096
	var ba = buf_array();
6097
	var aoa = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
6098
	var headers = aoa[0], data = aoa.slice(1);
6099
	var i = 0, j = 0, hcnt = 0, rlen = 1;
6100
	for(i = 0; i < headers.length; ++i) {
6101
		if(i == null) continue;
6102
		++hcnt;
6103
		if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
6104
		if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
6105
		if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
6106
			if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
6107
	}
6108
	var range = safe_decode_range(ws['!ref']);
6109
	var coltypes = [];
6110
	for(i = 0; i <= range.e.c - range.s.c; ++i) {
6111
		var col = [];
6112
		for(j=0; j < data.length; ++j) {
6113
			if(data[j][i] != null) col.push(data[j][i]);
6114
		}
6115
		if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
6116
		var guess = '', _guess = '';
6117
		for(j = 0; j < col.length; ++j) {
6118
			switch(typeof col[j]) {
6119
				/* TODO: check if L2 compat is desired */
6120
				case 'number': _guess = 'B'; break;
6121
				case 'string': _guess = 'C'; break;
6122
				case 'boolean': _guess = 'L'; break;
6123
				case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
6124
				default: _guess = 'C';
6125
			}
6126
			guess = guess && guess != _guess ? 'C' : _guess;
6127
			if(guess == 'C') break;
6128
		}
6129
		rlen += _RLEN[guess] || 0;
6130
		coltypes[i] = guess;
6131
	}
6132
6133
	var h = ba.next(32);
6134
	h.write_shift(4, 0x13021130);
6135
	h.write_shift(4, data.length);
6136
	h.write_shift(2, 296 + 32 * hcnt);
6137
	h.write_shift(2, rlen);
6138
	for(i=0; i < 4; ++i) h.write_shift(4, 0);
6139
	h.write_shift(4, 0x00000300); // TODO: CP
6140
6141
	for(i = 0, j = 0; i < headers.length; ++i) {
6142
		if(headers[i] == null) continue;
6143
		var hf = ba.next(32);
6144
		var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
6145
		hf.write_shift(1, _f, "sbcs");
6146
		hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
6147
		hf.write_shift(4, j);
6148
		hf.write_shift(1, _RLEN[coltypes[i]] || 0);
6149
		hf.write_shift(1, 0);
6150
		hf.write_shift(1, 0x02);
6151
		hf.write_shift(4, 0);
6152
		hf.write_shift(1, 0);
6153
		hf.write_shift(4, 0);
6154
		hf.write_shift(4, 0);
6155
		j += _RLEN[coltypes[i]] || 0;
6156
	}
6157
6158
	var hb = ba.next(264);
6159
	hb.write_shift(4, 0x0000000D);
6160
	for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
6161
	for(i=0; i < data.length; ++i) {
6162
		var rout = ba.next(rlen);
6163
		rout.write_shift(1, 0);
6164
		for(j=0; j<headers.length; ++j) {
6165
			if(headers[j] == null) continue;
6166
			switch(coltypes[j]) {
6167
				case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
6168
				case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
6169
				case 'D':
6170
					if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
6171
					else {
6172
						rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
6173
						rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
6174
						rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
6175
					} break;
6176
				case 'C':
6177
					var _s = String(data[i][j]||"");
6178
					rout.write_shift(1, _s, "sbcs");
6179
					for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
6180
			}
6181
		}
6182
		// data
6183
	}
6184
	ba.next(1).write_shift(1, 0x1A);
6185
	return ba.end();
6186
}
6187
	return {
6188
		to_workbook: dbf_to_workbook,
6189
		to_sheet: dbf_to_sheet,
6190
		from_sheet: sheet_to_dbf
6191
	};
6192
})();
6193
6194
var SYLK = (function() {
6195
	/* TODO: find an actual specification */
6196
	function sylk_to_aoa(d, opts) {
6197
		switch(opts.type) {
6198
			case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
6199
			case 'binary': return sylk_to_aoa_str(d, opts);
6200
			case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts);
6201
			case 'array': return sylk_to_aoa_str(cc2str(d), opts);
6202
		}
6203
		throw new Error("Unrecognized type " + opts.type);
6204
	}
6205
	function sylk_to_aoa_str(str, opts) {
6206
		var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
6207
		var formats = [];
6208
		var next_cell_format = null;
6209
		var sht = {}, rowinfo = [], colinfo = [], cw = [];
6210
		var Mval = 0, j;
6211
		for (; ri !== records.length; ++ri) {
6212
			Mval = 0;
6213
			var rstr=records[ri].trim();
6214
			var record=rstr.replace(/;;/g, "\u0001").split(";").map(function(x) { return x.replace(/\u0001/g, ";"); });
6215
			var RT=record[0], val;
6216
			if(rstr.length > 0) switch(RT) {
6217
			case 'ID': break; /* header */
6218
			case 'E': break; /* EOF */
6219
			case 'B': break; /* dimensions */
6220
			case 'O': break; /* options? */
6221
			case 'P':
6222
				if(record[1].charAt(0) == 'P')
6223
					formats.push(rstr.slice(3).replace(/;;/g, ";"));
6224
				break;
6225
			case 'C':
6226
			var C_seen_K = false, C_seen_X = false;
6227
			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
6228
				case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
6229
				case 'Y':
6230
					R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
6231
					for(j = arr.length; j <= R; ++j) arr[j] = [];
6232
					break;
6233
				case 'K':
6234
					val = record[rj].slice(1);
6235
					if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
6236
					else if(val === 'TRUE') val = true;
6237
					else if(val === 'FALSE') val = false;
6238
					else if(!isNaN(fuzzynum(val))) {
6239
						val = fuzzynum(val);
6240
						if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
6241
					} else if(!isNaN(fuzzydate(val).getDate())) {
6242
						val = parseDate(val);
6243
					}
6244
					if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
6245
					C_seen_K = true;
6246
					break;
6247
				case 'E':
6248
					var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
6249
					arr[R][C] = [arr[R][C], formula];
6250
					break;
6251
				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
6252
			}
6253
			if(C_seen_K) { arr[R][C] = val; next_cell_format = null; }
6254
			break;
6255
			case 'F':
6256
			var F_seen = 0;
6257
			for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
6258
				case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
6259
				case 'Y':
6260
					R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
6261
					for(j = arr.length; j <= R; ++j) arr[j] = [];
6262
					break;
6263
				case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
6264
				case 'F': break; /* ??? */
6265
				case 'G': break; /* hide grid */
6266
				case 'P':
6267
					next_cell_format = formats[parseInt(record[rj].slice(1))];
6268
					break;
6269
				case 'S': break; /* cell style */
6270
				case 'D': break; /* column */
6271
				case 'N': break; /* font */
6272
				case 'W':
6273
					cw = record[rj].slice(1).split(" ");
6274
					for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
6275
						Mval = parseInt(cw[2], 10);
6276
						colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
6277
					} break;
6278
				case 'C': /* default column format */
6279
					C = parseInt(record[rj].slice(1))-1;
6280
					if(!colinfo[C]) colinfo[C] = {};
6281
					break;
6282
				case 'R': /* row properties */
6283
					R = parseInt(record[rj].slice(1))-1;
6284
					if(!rowinfo[R]) rowinfo[R] = {};
6285
					if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
6286
					else if(Mval === 0) rowinfo[R].hidden = true;
6287
					break;
6288
				default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
6289
			}
6290
			if(F_seen < 1) next_cell_format = null; break;
6291
			default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
6292
			}
6293
		}
6294
		if(rowinfo.length > 0) sht['!rows'] = rowinfo;
6295
		if(colinfo.length > 0) sht['!cols'] = colinfo;
6296
		if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
6297
		return [arr, sht];
6298
	}
6299
6300
	function sylk_to_sheet(d, opts) {
6301
		var aoasht = sylk_to_aoa(d, opts);
6302
		var aoa = aoasht[0], ws = aoasht[1];
6303
		var o = aoa_to_sheet(aoa, opts);
6304
		keys(ws).forEach(function(k) { o[k] = ws[k]; });
6305
		return o;
6306
	}
6307
6308
	function sylk_to_workbook(d, opts) { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
6309
6310
	function write_ws_cell_sylk(cell, ws, R, C) {
6311
		var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
6312
		switch(cell.t) {
6313
			case 'n':
6314
				o += (cell.v||0);
6315
				if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
6316
			case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
6317
			case 'e': o += cell.w || cell.v; break;
6318
			case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
6319
			case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
6320
		}
6321
		return o;
6322
	}
6323
6324
	function write_ws_cols_sylk(out, cols) {
6325
		cols.forEach(function(col, i) {
6326
			var rec = "F;W" + (i+1) + " " + (i+1) + " ";
6327
			if(col.hidden) rec += "0";
6328
			else {
6329
				if(typeof col.width == 'number') col.wpx = width2px(col.width);
6330
				if(typeof col.wpx == 'number') col.wch = px2char(col.wpx);
6331
				if(typeof col.wch == 'number') rec += Math.round(col.wch);
6332
			}
6333
			if(rec.charAt(rec.length - 1) != " ") out.push(rec);
6334
		});
6335
	}
6336
6337
	function write_ws_rows_sylk(out, rows) {
6338
		rows.forEach(function(row, i) {
6339
			var rec = "F;";
6340
			if(row.hidden) rec += "M0;";
6341
			else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
6342
			else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
6343
			if(rec.length > 2) out.push(rec + "R" + (i+1));
6344
		});
6345
	}
6346
6347
	function sheet_to_sylk(ws, opts) {
6348
		var preamble = ["ID;PWXL;N;E"], o = [];
6349
		var r = safe_decode_range(ws['!ref']), cell;
6350
		var dense = Array.isArray(ws);
6351
		var RS = "\r\n";
6352
6353
		preamble.push("P;PGeneral");
6354
		preamble.push("F;P0;DG0G8;M255");
6355
		if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
6356
		if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
6357
6358
		preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
6359
		for(var R = r.s.r; R <= r.e.r; ++R) {
6360
			for(var C = r.s.c; C <= r.e.c; ++C) {
6361
				var coord = encode_cell({r:R,c:C});
6362
				cell = dense ? (ws[R]||[])[C]: ws[coord];
6363
				if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
6364
				o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
6365
			}
6366
		}
6367
		return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
6368
	}
6369
6370
	return {
6371
		to_workbook: sylk_to_workbook,
6372
		to_sheet: sylk_to_sheet,
6373
		from_sheet: sheet_to_sylk
6374
	};
6375
})();
6376
6377
var DIF = (function() {
6378
	function dif_to_aoa(d, opts) {
6379
		switch(opts.type) {
6380
			case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
6381
			case 'binary': return dif_to_aoa_str(d, opts);
6382
			case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts);
6383
			case 'array': return dif_to_aoa_str(cc2str(d), opts);
6384
		}
6385
		throw new Error("Unrecognized type " + opts.type);
6386
	}
6387
	function dif_to_aoa_str(str, opts) {
6388
		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
6389
		for (; ri !== records.length; ++ri) {
6390
			if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
6391
			if (R < 0) continue;
6392
			var metadata = records[ri].trim().split(",");
6393
			var type = metadata[0], value = metadata[1];
6394
			++ri;
6395
			var data = records[ri].trim();
6396
			switch (+type) {
6397
				case -1:
6398
					if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
6399
					else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
6400
					break;
6401
				case 0:
6402
					if(data === 'TRUE') arr[R][C] = true;
6403
					else if(data === 'FALSE') arr[R][C] = false;
6404
					else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
6405
					else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
6406
					else arr[R][C] = value;
6407
					++C; break;
6408
				case 1:
6409
					data = data.slice(1,data.length-1);
6410
					arr[R][C++] = data !== '' ? data : null;
6411
					break;
6412
			}
6413
			if (data === 'EOD') break;
6414
		}
6415
		if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
6416
		return arr;
6417
	}
6418
6419
	function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
6420
	function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
6421
6422
	var sheet_to_dif = (function() {
6423
		var push_field = function pf(o, topic, v, n, s) {
6424
			o.push(topic);
6425
			o.push(v + "," + n);
6426
			o.push('"' + s.replace(/"/g,'""') + '"');
6427
		};
6428
		var push_value = function po(o, type, v, s) {
6429
			o.push(type + "," + v);
6430
			o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
6431
		};
6432
		return function sheet_to_dif(ws) {
6433
			var o = [];
6434
			var r = safe_decode_range(ws['!ref']), cell;
6435
			var dense = Array.isArray(ws);
6436
			push_field(o, "TABLE", 0, 1, "sheetjs");
6437
			push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
6438
			push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
6439
			push_field(o, "DATA", 0, 0,"");
6440
			for(var R = r.s.r; R <= r.e.r; ++R) {
6441
				push_value(o, -1, 0, "BOT");
6442
				for(var C = r.s.c; C <= r.e.c; ++C) {
6443
					var coord = encode_cell({r:R,c:C});
6444
					cell = dense ? (ws[R]||[])[C] : ws[coord];
6445
					if(!cell) { push_value(o, 1, 0, ""); continue;}
6446
					switch(cell.t) {
6447
						case 'n':
6448
							var val = DIF_XL ? cell.w : cell.v;
6449
							if(!val && cell.v != null) val = cell.v;
6450
							if(val == null) {
6451
								if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
6452
								else push_value(o, 1, 0, "");
6453
							}
6454
							else push_value(o, 0, val, "V");
6455
							break;
6456
						case 'b':
6457
							push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
6458
							break;
6459
						case 's':
6460
							push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
6461
							break;
6462
						case 'd':
6463
							if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
6464
							if(DIF_XL) push_value(o, 0, cell.w, "V");
6465
							else push_value(o, 1, 0, cell.w);
6466
							break;
6467
						default: push_value(o, 1, 0, "");
6468
					}
6469
				}
6470
			}
6471
			push_value(o, -1, 0, "EOD");
6472
			var RS = "\r\n";
6473
			var oo = o.join(RS);
6474
			//while((oo.length & 0x7F) != 0) oo += "\0";
6475
			return oo;
6476
		};
6477
	})();
6478
	return {
6479
		to_workbook: dif_to_workbook,
6480
		to_sheet: dif_to_sheet,
6481
		from_sheet: sheet_to_dif
6482
	};
6483
})();
6484
6485
var ETH = (function() {
6486
	function decode(s) { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
6487
	function encode(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
6488
6489
	function eth_to_aoa(str, opts) {
6490
		var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
6491
		for (; ri !== records.length; ++ri) {
6492
			var record = records[ri].trim().split(":");
6493
			if(record[0] !== 'cell') continue;
6494
			var addr = decode_cell(record[1]);
6495
			if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
6496
			R = addr.r; C = addr.c;
6497
			switch(record[2]) {
6498
				case 't': arr[R][C] = decode(record[3]); break;
6499
				case 'v': arr[R][C] = +record[3]; break;
6500
				case 'vtf': var _f = record[record.length - 1];
6501
					/* falls through */
6502
				case 'vtc':
6503
					switch(record[3]) {
6504
						case 'nl': arr[R][C] = +record[4] ? true : false; break;
6505
						default: arr[R][C] = +record[4]; break;
6506
					}
6507
					if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
6508
			}
6509
		}
6510
		if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
6511
		return arr;
6512
	}
6513
6514
	function eth_to_sheet(d, opts) { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
6515
	function eth_to_workbook(d, opts) { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
6516
6517
	var header = [
6518
		"socialcalc:version:1.5",
6519
		"MIME-Version: 1.0",
6520
		"Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
6521
	].join("\n");
6522
6523
	var sep = [
6524
		"--SocialCalcSpreadsheetControlSave",
6525
		"Content-type: text/plain; charset=UTF-8"
6526
	].join("\n") + "\n";
6527
6528
	/* TODO: the other parts */
6529
	var meta = [
6530
		"# SocialCalc Spreadsheet Control Save",
6531
		"part:sheet"
6532
	].join("\n");
6533
6534
	var end = "--SocialCalcSpreadsheetControlSave--";
6535
6536
	function sheet_to_eth_data(ws) {
6537
		if(!ws || !ws['!ref']) return "";
6538
		var o = [], oo = [], cell, coord = "";
6539
		var r = decode_range(ws['!ref']);
6540
		var dense = Array.isArray(ws);
6541
		for(var R = r.s.r; R <= r.e.r; ++R) {
6542
			for(var C = r.s.c; C <= r.e.c; ++C) {
6543
				coord = encode_cell({r:R,c:C});
6544
				cell = dense ? (ws[R]||[])[C] : ws[coord];
6545
				if(!cell || cell.v == null || cell.t === 'z') continue;
6546
				oo = ["cell", coord, 't'];
6547
				switch(cell.t) {
6548
					case 's': case 'str': oo.push(encode(cell.v)); break;
6549
					case 'n':
6550
						if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
6551
						else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
6552
						break;
6553
					case 'b':
6554
						oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
6555
						oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
6556
						break;
6557
					case 'd':
6558
						var t = datenum(parseDate(cell.v));
6559
						oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
6560
						oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
6561
						break;
6562
					case 'e': continue;
6563
				}
6564
				o.push(oo.join(":"));
6565
			}
6566
		}
6567
		o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
6568
		o.push("valueformat:1:text-wiki");
6569
		//o.push("copiedfrom:" + ws['!ref']); // clipboard only
6570
		return o.join("\n");
6571
	}
6572
6573
	function sheet_to_eth(ws) {
6574
		return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
6575
		// return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
6576
	}
6577
6578
	return {
6579
		to_workbook: eth_to_workbook,
6580
		to_sheet: eth_to_sheet,
6581
		from_sheet: sheet_to_eth
6582
	};
6583
})();
6584
6585
var PRN = (function() {
6586
	function set_text_arr(data, arr, R, C, o) {
6587
		if(o.raw) arr[R][C] = data;
6588
		else if(data === 'TRUE') arr[R][C] = true;
6589
		else if(data === 'FALSE') arr[R][C] = false;
6590
		else if(data === ""){/* empty */}
6591
		else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
6592
		else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
6593
		else arr[R][C] = data;
6594
	}
6595
6596
	function prn_to_aoa_str(f, opts) {
6597
		var o = opts || {};
6598
		var arr = ([]);
6599
		if(!f || f.length === 0) return arr;
6600
		var lines = f.split(/[\r\n]/);
6601
		var L = lines.length - 1;
6602
		while(L >= 0 && lines[L].length === 0) --L;
6603
		var start = 10, idx = 0;
6604
		var R = 0;
6605
		for(; R <= L; ++R) {
6606
			idx = lines[R].indexOf(" ");
6607
			if(idx == -1) idx = lines[R].length; else idx++;
6608
			start = Math.max(start, idx);
6609
		}
6610
		for(R = 0; R <= L; ++R) {
6611
			arr[R] = [];
6612
			/* TODO: confirm that widths are always 10 */
6613
			var C = 0;
6614
			set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
6615
			for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
6616
				set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
6617
		}
6618
		if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
6619
		return arr;
6620
	}
6621
6622
	// List of accepted CSV separators
6623
	var guess_seps = {
6624
0x2C: ',',
6625
0x09: "\t",
6626
0x3B: ';'
6627
	};
6628
6629
	// CSV separator weights to be used in case of equal numbers
6630
	var guess_sep_weights = {
6631
0x2C: 3,
6632
0x09: 2,
6633
0x3B: 1
6634
	};
6635
6636
	function guess_sep(str) {
6637
		var cnt = {}, instr = false, end = 0, cc = 0;
6638
		for(;end < str.length;++end) {
6639
			if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
6640
			else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
6641
		}
6642
6643
		cc = [];
6644
		for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
6645
			cc.push([ cnt[end], end ]);
6646
		}
6647
6648
		if ( !cc.length ) {
6649
			cnt = guess_sep_weights;
6650
			for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
6651
				cc.push([ cnt[end], end ]);
6652
			}
6653
		}
6654
6655
		cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
6656
6657
		return guess_seps[cc.pop()[1]];
6658
	}
6659
6660
	function dsv_to_sheet_str(str, opts) {
6661
		var o = opts || {};
6662
		var sep = "";
6663
		if(DENSE != null && o.dense == null) o.dense = DENSE;
6664
		var ws = o.dense ? ([]) : ({});
6665
		var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
6666
6667
		if(str.slice(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.slice(6); }
6668
		else sep = guess_sep(str.slice(0,1024));
6669
		var R = 0, C = 0, v = 0;
6670
		var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
6671
		str = str.replace(/\r\n/mg, "\n");
6672
		var _re = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
6673
		function finish_cell() {
6674
			var s = str.slice(start, end);
6675
			var cell = ({});
6676
			if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
6677
			if(s.length === 0) cell.t = 'z';
6678
			else if(o.raw) { cell.t = 's'; cell.v = s; }
6679
			else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
6680
			else if(s.charCodeAt(0) == 0x3D) {
6681
				if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
6682
				else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
6683
				else { cell.t = 's'; cell.v = s; } }
6684
			else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
6685
			else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
6686
			else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
6687
			else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
6688
				cell.z = o.dateNF || SSF._table[14];
6689
				var k = 0;
6690
				if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
6691
				if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
6692
				else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
6693
				if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
6694
				if(!o.cellNF) delete cell.z;
6695
			} else {
6696
				cell.t = 's';
6697
				cell.v = s;
6698
			}
6699
			if(cell.t == 'z'){}
6700
			else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
6701
			else ws[encode_cell({c:C,r:R})] = cell;
6702
			start = end+1;
6703
			if(range.e.c < C) range.e.c = C;
6704
			if(range.e.r < R) range.e.r = R;
6705
			if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
6706
		}
6707
		outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
6708
			case 0x22: instr = !instr; break;
6709
			case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
6710
			default: break;
6711
		}
6712
		if(end - start > 0) finish_cell();
6713
6714
		ws['!ref'] = encode_range(range);
6715
		return ws;
6716
	}
6717
6718
	function prn_to_sheet_str(str, opts) {
6719
		if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
6720
		if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
6721
		return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
6722
	}
6723
6724
	function prn_to_sheet(d, opts) {
6725
		var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
6726
		switch(opts.type) {
6727
			case 'base64': str = Base64.decode(d); break;
6728
			case 'binary': str = d; break;
6729
			case 'buffer':
6730
				if(opts.codepage == 65001) str = d.toString('utf8');
6731
				else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
6732
				else str = d.toString('binary');
6733
				break;
6734
			case 'array': str = cc2str(d); break;
6735
			case 'string': str = d; break;
6736
			default: throw new Error("Unrecognized type " + opts.type);
6737
		}
6738
		if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
6739
		else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage)  str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str));
6740
		if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
6741
		return prn_to_sheet_str(str, opts);
6742
	}
6743
6744
	function prn_to_workbook(d, opts) { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
6745
6746
	function sheet_to_prn(ws) {
6747
		var o = [];
6748
		var r = safe_decode_range(ws['!ref']), cell;
6749
		var dense = Array.isArray(ws);
6750
		for(var R = r.s.r; R <= r.e.r; ++R) {
6751
			var oo = [];
6752
			for(var C = r.s.c; C <= r.e.c; ++C) {
6753
				var coord = encode_cell({r:R,c:C});
6754
				cell = dense ? (ws[R]||[])[C] : ws[coord];
6755
				if(!cell || cell.v == null) { oo.push("          "); continue; }
6756
				var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
6757
				while(w.length < 10) w += " ";
6758
				oo.push(w + (C === 0 ? " " : ""));
6759
			}
6760
			o.push(oo.join(""));
6761
		}
6762
		return o.join("\n");
6763
	}
6764
6765
	return {
6766
		to_workbook: prn_to_workbook,
6767
		to_sheet: prn_to_sheet,
6768
		from_sheet: sheet_to_prn
6769
	};
6770
})();
6771
6772
/* Excel defaults to SYLK but warns if data is not valid */
6773
function read_wb_ID(d, opts) {
6774
	var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
6775
	try {
6776
		var out = SYLK.to_workbook(d, o);
6777
		o.WTF = OLD_WTF;
6778
		return out;
6779
	} catch(e) {
6780
		o.WTF = OLD_WTF;
6781
		if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
6782
		return PRN.to_workbook(d, opts);
6783
	}
6784
}
6785
var WK_ = (function() {
6786
	function lotushopper(data, cb, opts) {
6787
		if(!data) return;
6788
		prep_blob(data, data.l || 0);
6789
		var Enum = opts.Enum || WK1Enum;
6790
		while(data.l < data.length) {
6791
			var RT = data.read_shift(2);
6792
			var R = Enum[RT] || Enum[0xFF];
6793
			var length = data.read_shift(2);
6794
			var tgt = data.l + length;
6795
			var d = (R.f||parsenoop)(data, length, opts);
6796
			data.l = tgt;
6797
			if(cb(d, R.n, RT)) return;
6798
		}
6799
	}
6800
6801
	function lotus_to_workbook(d, opts) {
6802
		switch(opts.type) {
6803
			case 'base64': return lotus_to_workbook_buf(s2a(Base64.decode(d)), opts);
6804
			case 'binary': return lotus_to_workbook_buf(s2a(d), opts);
6805
			case 'buffer':
6806
			case 'array': return lotus_to_workbook_buf(d, opts);
6807
		}
6808
		throw "Unsupported type " + opts.type;
6809
	}
6810
6811
	function lotus_to_workbook_buf(d, opts) {
6812
		if(!d) return d;
6813
		var o = opts || {};
6814
		if(DENSE != null && o.dense == null) o.dense = DENSE;
6815
		var s = ((o.dense ? [] : {})), n = "Sheet1", sidx = 0;
6816
		var sheets = {}, snames = [n];
6817
6818
		var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
6819
		var sheetRows = o.sheetRows || 0;
6820
6821
		if(d[2] == 0x02) o.Enum = WK1Enum;
6822
		else if(d[2] == 0x1a) o.Enum = WK3Enum;
6823
		else if(d[2] == 0x0e) { o.Enum = WK3Enum; o.qpro = true; d.l = 0; }
6824
		else throw new Error("Unrecognized LOTUS BOF " + d[2]);
6825
		lotushopper(d, function(val, Rn, RT) {
6826
			if(d[2] == 0x02) switch(RT) {
6827
				case 0x00:
6828
					o.vers = val;
6829
					if(val >= 0x1000) o.qpro = true;
6830
					break;
6831
				case 0x06: refguess = val; break; /* RANGE */
6832
				case 0x0F: /* LABEL */
6833
					if(!o.qpro) val[1].v = val[1].v.slice(1);
6834
					/* falls through */
6835
				case 0x0D: /* INTEGER */
6836
				case 0x0E: /* NUMBER */
6837
				case 0x10: /* FORMULA */
6838
				case 0x33: /* STRING */
6839
					/* TODO: actual translation of the format code */
6840
					if(RT == 0x0E && (val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
6841
						val[1].z = o.dateNF || SSF._table[14];
6842
						if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
6843
					}
6844
					if(o.dense) {
6845
						if(!s[val[0].r]) s[val[0].r] = [];
6846
						s[val[0].r][val[0].c] = val[1];
6847
					} else s[encode_cell(val[0])] = val[1];
6848
					break;
6849
			} else switch(RT) {
6850
				case 0x16: /* LABEL16 */
6851
					val[1].v = val[1].v.slice(1);
6852
					/* falls through */
6853
				case 0x17: /* NUMBER17 */
6854
				case 0x18: /* NUMBER18 */
6855
				case 0x19: /* FORMULA19 */
6856
				case 0x25: /* NUMBER25 */
6857
				case 0x27: /* NUMBER27 */
6858
				case 0x28: /* FORMULA28 */
6859
					if(val[3] > sidx) {
6860
						s["!ref"] = encode_range(refguess);
6861
						sheets[n] = s;
6862
						s = (o.dense ? [] : {});
6863
						refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
6864
						sidx = val[3]; n = "Sheet" + (sidx + 1);
6865
						snames.push(n);
6866
					}
6867
					if(sheetRows > 0 && val[0].r >= sheetRows) break;
6868
					if(o.dense) {
6869
						if(!s[val[0].r]) s[val[0].r] = [];
6870
						s[val[0].r][val[0].c] = val[1];
6871
					} else s[encode_cell(val[0])] = val[1];
6872
					if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
6873
					if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
6874
					break;
6875
				default: break;
6876
			}
6877
		}, o);
6878
6879
		s["!ref"] = encode_range(refguess);
6880
		sheets[n] = s;
6881
		return { SheetNames: snames, Sheets:sheets };
6882
	}
6883
6884
	function parse_RANGE(blob) {
6885
		var o = {s:{c:0,r:0},e:{c:0,r:0}};
6886
		o.s.c = blob.read_shift(2);
6887
		o.s.r = blob.read_shift(2);
6888
		o.e.c = blob.read_shift(2);
6889
		o.e.r = blob.read_shift(2);
6890
		if(o.s.c == 0xFFFF) o.s.c = o.e.c = o.s.r = o.e.r = 0;
6891
		return o;
6892
	}
6893
6894
	function parse_cell(blob, length, opts) {
6895
		var o = [{c:0,r:0}, {t:'n',v:0}, 0];
6896
		if(opts.qpro && opts.vers != 0x5120) {
6897
			o[0].c = blob.read_shift(1);
6898
			blob.l++;
6899
			o[0].r = blob.read_shift(2);
6900
			blob.l+=2;
6901
		} else {
6902
			o[2] = blob.read_shift(1);
6903
			o[0].c = blob.read_shift(2); o[0].r = blob.read_shift(2);
6904
		}
6905
		return o;
6906
	}
6907
6908
	function parse_LABEL(blob, length, opts) {
6909
		var tgt = blob.l + length;
6910
		var o = parse_cell(blob, length, opts);
6911
		o[1].t = 's';
6912
		if(opts.vers == 0x5120) {
6913
			blob.l++;
6914
			var len = blob.read_shift(1);
6915
			o[1].v = blob.read_shift(len, 'utf8');
6916
			return o;
6917
		}
6918
		if(opts.qpro) blob.l++;
6919
		o[1].v = blob.read_shift(tgt - blob.l, 'cstr');
6920
		return o;
6921
	}
6922
6923
	function parse_INTEGER(blob, length, opts) {
6924
		var o = parse_cell(blob, length, opts);
6925
		o[1].v = blob.read_shift(2, 'i');
6926
		return o;
6927
	}
6928
6929
	function parse_NUMBER(blob, length, opts) {
6930
		var o = parse_cell(blob, length, opts);
6931
		o[1].v = blob.read_shift(8, 'f');
6932
		return o;
6933
	}
6934
6935
	function parse_FORMULA(blob, length, opts) {
6936
		var tgt = blob.l + length;
6937
		var o = parse_cell(blob, length, opts);
6938
		/* TODO: formula */
6939
		o[1].v = blob.read_shift(8, 'f');
6940
		if(opts.qpro) blob.l = tgt;
6941
		else {
6942
			var flen = blob.read_shift(2);
6943
			blob.l += flen;
6944
		}
6945
		return o;
6946
	}
6947
6948
	function parse_cell_3(blob) {
6949
		var o = [{c:0,r:0}, {t:'n',v:0}, 0];
6950
		o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
6951
		return o;
6952
	}
6953
6954
	function parse_LABEL_16(blob, length) {
6955
		var o = parse_cell_3(blob, length);
6956
		o[1].t = 's';
6957
		o[1].v = blob.read_shift(length - 4, 'cstr');
6958
		return o;
6959
	}
6960
6961
	function parse_NUMBER_18(blob, length) {
6962
		var o = parse_cell_3(blob, length);
6963
		o[1].v = blob.read_shift(2);
6964
		var v = o[1].v >> 1;
6965
		/* TODO: figure out all of the corner cases */
6966
		if(o[1].v & 0x1) {
6967
			switch(v & 0x07) {
6968
				case 1: v = (v >> 3) * 500; break;
6969
				case 2: v = (v >> 3) / 20; break;
6970
				case 4: v = (v >> 3) / 2000; break;
6971
				case 6: v = (v >> 3) / 16; break;
6972
				case 7: v = (v >> 3) / 64; break;
6973
				default: throw "unknown NUMBER_18 encoding " + (v & 0x07);
6974
			}
6975
		}
6976
		o[1].v = v;
6977
		return o;
6978
	}
6979
6980
	function parse_NUMBER_17(blob, length) {
6981
		var o = parse_cell_3(blob, length);
6982
		var v1 = blob.read_shift(4);
6983
		var v2 = blob.read_shift(4);
6984
		var e = blob.read_shift(2);
6985
		if(e == 0xFFFF) { o[1].v = 0; return o; }
6986
		var s = e & 0x8000; e = (e&0x7FFF) - 16446;
6987
		o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
6988
		return o;
6989
	}
6990
6991
	function parse_FORMULA_19(blob, length) {
6992
		var o = parse_NUMBER_17(blob, 14);
6993
		blob.l += length - 14; /* TODO: formula */
6994
		return o;
6995
	}
6996
6997
	function parse_NUMBER_25(blob, length) {
6998
		var o = parse_cell_3(blob, length);
6999
		var v1 = blob.read_shift(4);
7000
		o[1].v = v1 >> 6;
7001
		return o;
7002
	}
7003
7004
	function parse_NUMBER_27(blob, length) {
7005
		var o = parse_cell_3(blob, length);
7006
		var v1 = blob.read_shift(8,'f');
7007
		o[1].v = v1;
7008
		return o;
7009
	}
7010
7011
	function parse_FORMULA_28(blob, length) {
7012
		var o = parse_NUMBER_27(blob, 14);
7013
		blob.l += length - 10; /* TODO: formula */
7014
		return o;
7015
	}
7016
7017
	var WK1Enum = {
7018
0x0000: { n:"BOF", f:parseuint16 },
7019
0x0001: { n:"EOF" },
7020
0x0002: { n:"CALCMODE" },
7021
0x0003: { n:"CALCORDER" },
7022
0x0004: { n:"SPLIT" },
7023
0x0005: { n:"SYNC" },
7024
0x0006: { n:"RANGE", f:parse_RANGE },
7025
0x0007: { n:"WINDOW1" },
7026
0x0008: { n:"COLW1" },
7027
0x0009: { n:"WINTWO" },
7028
0x000A: { n:"COLW2" },
7029
0x000B: { n:"NAME" },
7030
0x000C: { n:"BLANK" },
7031
0x000D: { n:"INTEGER", f:parse_INTEGER },
7032
0x000E: { n:"NUMBER", f:parse_NUMBER },
7033
0x000F: { n:"LABEL", f:parse_LABEL },
7034
0x0010: { n:"FORMULA", f:parse_FORMULA },
7035
0x0018: { n:"TABLE" },
7036
0x0019: { n:"ORANGE" },
7037
0x001A: { n:"PRANGE" },
7038
0x001B: { n:"SRANGE" },
7039
0x001C: { n:"FRANGE" },
7040
0x001D: { n:"KRANGE1" },
7041
0x0020: { n:"HRANGE" },
7042
0x0023: { n:"KRANGE2" },
7043
0x0024: { n:"PROTEC" },
7044
0x0025: { n:"FOOTER" },
7045
0x0026: { n:"HEADER" },
7046
0x0027: { n:"SETUP" },
7047
0x0028: { n:"MARGINS" },
7048
0x0029: { n:"LABELFMT" },
7049
0x002A: { n:"TITLES" },
7050
0x002B: { n:"SHEETJS" },
7051
0x002D: { n:"GRAPH" },
7052
0x002E: { n:"NGRAPH" },
7053
0x002F: { n:"CALCCOUNT" },
7054
0x0030: { n:"UNFORMATTED" },
7055
0x0031: { n:"CURSORW12" },
7056
0x0032: { n:"WINDOW" },
7057
0x0033: { n:"STRING", f:parse_LABEL },
7058
0x0037: { n:"PASSWORD" },
7059
0x0038: { n:"LOCKED" },
7060
0x003C: { n:"QUERY" },
7061
0x003D: { n:"QUERYNAME" },
7062
0x003E: { n:"PRINT" },
7063
0x003F: { n:"PRINTNAME" },
7064
0x0040: { n:"GRAPH2" },
7065
0x0041: { n:"GRAPHNAME" },
7066
0x0042: { n:"ZOOM" },
7067
0x0043: { n:"SYMSPLIT" },
7068
0x0044: { n:"NSROWS" },
7069
0x0045: { n:"NSCOLS" },
7070
0x0046: { n:"RULER" },
7071
0x0047: { n:"NNAME" },
7072
0x0048: { n:"ACOMM" },
7073
0x0049: { n:"AMACRO" },
7074
0x004A: { n:"PARSE" },
7075
0x00FF: { n:"", f:parsenoop }
7076
	};
7077
7078
	var WK3Enum = {
7079
0x0000: { n:"BOF" },
7080
0x0001: { n:"EOF" },
7081
0x0003: { n:"??" },
7082
0x0004: { n:"??" },
7083
0x0005: { n:"??" },
7084
0x0006: { n:"??" },
7085
0x0007: { n:"??" },
7086
0x0009: { n:"??" },
7087
0x000a: { n:"??" },
7088
0x000b: { n:"??" },
7089
0x000c: { n:"??" },
7090
0x000e: { n:"??" },
7091
0x000f: { n:"??" },
7092
0x0010: { n:"??" },
7093
0x0011: { n:"??" },
7094
0x0012: { n:"??" },
7095
0x0013: { n:"??" },
7096
0x0015: { n:"??" },
7097
0x0016: { n:"LABEL16", f:parse_LABEL_16},
7098
0x0017: { n:"NUMBER17", f:parse_NUMBER_17 },
7099
0x0018: { n:"NUMBER18", f:parse_NUMBER_18 },
7100
0x0019: { n:"FORMULA19", f:parse_FORMULA_19},
7101
0x001a: { n:"??" },
7102
0x001b: { n:"??" },
7103
0x001c: { n:"??" },
7104
0x001d: { n:"??" },
7105
0x001e: { n:"??" },
7106
0x001f: { n:"??" },
7107
0x0021: { n:"??" },
7108
0x0025: { n:"NUMBER25", f:parse_NUMBER_25 },
7109
0x0027: { n:"NUMBER27", f:parse_NUMBER_27 },
7110
0x0028: { n:"FORMULA28", f:parse_FORMULA_28 },
7111
0x00FF: { n:"", f:parsenoop }
7112
	};
7113
	return {
7114
		to_workbook: lotus_to_workbook
7115
	};
7116
})();
7117
/* Parse a list of <r> tags */
7118
var parse_rs = (function parse_rs_factory() {
7119
	var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g;
7120
	/* 18.4.7 rPr CT_RPrElt */
7121
	var parse_rpr = function parse_rpr(rpr, intro, outro) {
7122
		var font = {}, cp = 65001, align = "";
7123
		var pass = false;
7124
		var m = rpr.match(tagregex), i = 0;
7125
		if(m) for(;i!=m.length; ++i) {
7126
			var y = parsexmltag(m[i]);
7127
			switch(y[0].replace(/\w*:/g,"")) {
7128
				/* 18.8.12 condense CT_BooleanProperty */
7129
				/* ** not required . */
7130
				case '<condense': break;
7131
				/* 18.8.17 extend CT_BooleanProperty */
7132
				/* ** not required . */
7133
				case '<extend': break;
7134
				/* 18.8.36 shadow CT_BooleanProperty */
7135
				/* ** not required . */
7136
				case '<shadow':
7137
					if(!y.val) break;
7138
					/* falls through */
7139
				case '<shadow>':
7140
				case '<shadow/>': font.shadow = 1; break;
7141
				case '</shadow>': break;
7142
7143
				/* 18.4.1 charset CT_IntProperty TODO */
7144
				case '<charset':
7145
					if(y.val == '1') break;
7146
					cp = CS2CP[parseInt(y.val, 10)];
7147
					break;
7148
7149
				/* 18.4.2 outline CT_BooleanProperty TODO */
7150
				case '<outline':
7151
					if(!y.val) break;
7152
					/* falls through */
7153
				case '<outline>':
7154
				case '<outline/>': font.outline = 1; break;
7155
				case '</outline>': break;
7156
7157
				/* 18.4.5 rFont CT_FontName */
7158
				case '<rFont': font.name = y.val; break;
7159
7160
				/* 18.4.11 sz CT_FontSize */
7161
				case '<sz': font.sz = y.val; break;
7162
7163
				/* 18.4.10 strike CT_BooleanProperty */
7164
				case '<strike':
7165
					if(!y.val) break;
7166
					/* falls through */
7167
				case '<strike>':
7168
				case '<strike/>': font.strike = 1; break;
7169
				case '</strike>': break;
7170
7171
				/* 18.4.13 u CT_UnderlineProperty */
7172
				case '<u':
7173
					if(!y.val) break;
7174
					switch(y.val) {
7175
						case 'double': font.uval = "double"; break;
7176
						case 'singleAccounting': font.uval = "single-accounting"; break;
7177
						case 'doubleAccounting': font.uval = "double-accounting"; break;
7178
					}
7179
					/* falls through */
7180
				case '<u>':
7181
				case '<u/>': font.u = 1; break;
7182
				case '</u>': break;
7183
7184
				/* 18.8.2 b */
7185
				case '<b':
7186
					if(y.val == '0') break;
7187
					/* falls through */
7188
				case '<b>':
7189
				case '<b/>': font.b = 1; break;
7190
				case '</b>': break;
7191
7192
				/* 18.8.26 i */
7193
				case '<i':
7194
					if(y.val == '0') break;
7195
					/* falls through */
7196
				case '<i>':
7197
				case '<i/>': font.i = 1; break;
7198
				case '</i>': break;
7199
7200
				/* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
7201
				case '<color':
7202
					if(y.rgb) font.color = y.rgb.slice(2,8);
7203
					break;
7204
7205
				/* 18.8.18 family ST_FontFamily */
7206
				case '<family': font.family = y.val; break;
7207
7208
				/* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
7209
				case '<vertAlign': align = y.val; break;
7210
7211
				/* 18.8.35 scheme CT_FontScheme TODO */
7212
				case '<scheme': break;
7213
7214
				/* 18.2.10 extLst CT_ExtensionList ? */
7215
				case '<extLst': case '<extLst>': case '</extLst>': break;
7216
				case '<ext': pass = true; break;
7217
				case '</ext>': pass = false; break;
7218
				default:
7219
					if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
7220
			}
7221
		}
7222
		var style = [];
7223
7224
		if(font.u) style.push("text-decoration: underline;");
7225
		if(font.uval) style.push("text-underline-style:" + font.uval + ";");
7226
		if(font.sz) style.push("font-size:" + font.sz + "pt;");
7227
		if(font.outline) style.push("text-effect: outline;");
7228
		if(font.shadow) style.push("text-shadow: auto;");
7229
		intro.push('<span style="' + style.join("") + '">');
7230
7231
		if(font.b) { intro.push("<b>"); outro.push("</b>"); }
7232
		if(font.i) { intro.push("<i>"); outro.push("</i>"); }
7233
		if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
7234
7235
		if(align == "superscript") align = "sup";
7236
		else if(align == "subscript") align = "sub";
7237
		if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
7238
7239
		outro.push("</span>");
7240
		return cp;
7241
	};
7242
7243
	/* 18.4.4 r CT_RElt */
7244
	function parse_r(r) {
7245
		var terms = [[],"",[]];
7246
		/* 18.4.12 t ST_Xstring */
7247
		var t = r.match(tregex)/*, cp = 65001*/;
7248
		if(!t) return "";
7249
		terms[1] = t[1];
7250
7251
		var rpr = r.match(rpregex);
7252
		if(rpr) /*cp = */parse_rpr(rpr[1], terms[0], terms[2]);
7253
7254
		return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
7255
	}
7256
	return function parse_rs(rs) {
7257
		return rs.replace(rregex,"").split(rend).map(parse_r).join("");
7258
	};
7259
})();
7260
7261
/* 18.4.8 si CT_Rst */
7262
var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
7263
var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
7264
function parse_si(x, opts) {
7265
	var html = opts ? opts.cellHTML : true;
7266
	var z = {};
7267
	if(!x) return null;
7268
	//var y;
7269
	/* 18.4.12 t ST_Xstring (Plaintext String) */
7270
	// TODO: is whitespace actually valid here?
7271
	if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
7272
		z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
7273
		z.r = utf8read(x);
7274
		if(html) z.h = escapehtml(z.t);
7275
	}
7276
	/* 18.4.4 r CT_RElt (Rich Text Run) */
7277
	else if((/*y = */x.match(sirregex))) {
7278
		z.r = utf8read(x);
7279
		z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
7280
		if(html) z.h = parse_rs(z.r);
7281
	}
7282
	/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
7283
	/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
7284
	return z;
7285
}
7286
7287
/* 18.4 Shared String Table */
7288
var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
7289
var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
7290
var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
7291
function parse_sst_xml(data, opts) {
7292
	var s = ([]), ss = "";
7293
	if(!data) return s;
7294
	/* 18.4.9 sst CT_Sst */
7295
	var sst = data.match(sstr0);
7296
	if(sst) {
7297
		ss = sst[2].replace(sstr1,"").split(sstr2);
7298
		for(var i = 0; i != ss.length; ++i) {
7299
			var o = parse_si(ss[i].trim(), opts);
7300
			if(o != null) s[s.length] = o;
7301
		}
7302
		sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
7303
	}
7304
	return s;
7305
}
7306
7307
RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
7308
var straywsregex = /^\s|\s$|[\t\n\r]/;
7309
function write_sst_xml(sst, opts) {
7310
	if(!opts.bookSST) return "";
7311
	var o = [XML_HEADER];
7312
	o[o.length] = (writextag('sst', null, {
7313
		xmlns: XMLNS.main[0],
7314
		count: sst.Count,
7315
		uniqueCount: sst.Unique
7316
	}));
7317
	for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
7318
		var s = sst[i];
7319
		var sitag = "<si>";
7320
		if(s.r) sitag += s.r;
7321
		else {
7322
			sitag += "<t";
7323
			if(!s.t) s.t = "";
7324
			if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
7325
			sitag += ">" + escapexml(s.t) + "</t>";
7326
		}
7327
		sitag += "</si>";
7328
		o[o.length] = (sitag);
7329
	}
7330
	if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
7331
	return o.join("");
7332
}
7333
/* [MS-XLSB] 2.4.221 BrtBeginSst */
7334
function parse_BrtBeginSst(data) {
7335
	return [data.read_shift(4), data.read_shift(4)];
7336
}
7337
7338
/* [MS-XLSB] 2.1.7.45 Shared Strings */
7339
function parse_sst_bin(data, opts) {
7340
	var s = ([]);
7341
	var pass = false;
7342
	recordhopper(data, function hopper_sst(val, R_n, RT) {
7343
		switch(RT) {
7344
			case 0x009F: /* 'BrtBeginSst' */
7345
				s.Count = val[0]; s.Unique = val[1]; break;
7346
			case 0x0013: /* 'BrtSSTItem' */
7347
				s.push(val); break;
7348
			case 0x00A0: /* 'BrtEndSst' */
7349
				return true;
7350
7351
			case 0x0023: /* 'BrtFRTBegin' */
7352
				pass = true; break;
7353
			case 0x0024: /* 'BrtFRTEnd' */
7354
				pass = false; break;
7355
7356
			default:
7357
				if(R_n.indexOf("Begin") > 0){/* empty */}
7358
				else if(R_n.indexOf("End") > 0){/* empty */}
7359
				if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
7360
		}
7361
	});
7362
	return s;
7363
}
7364
7365
function write_BrtBeginSst(sst, o) {
7366
	if(!o) o = new_buf(8);
7367
	o.write_shift(4, sst.Count);
7368
	o.write_shift(4, sst.Unique);
7369
	return o;
7370
}
7371
7372
var write_BrtSSTItem = write_RichStr;
7373
7374
function write_sst_bin(sst) {
7375
	var ba = buf_array();
7376
	write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst));
7377
	for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i]));
7378
	/* FRTSST */
7379
	write_record(ba, "BrtEndSst");
7380
	return ba.end();
7381
}
7382
function _JS2ANSI(str) {
7383
	if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str);
7384
	var o = [], oo = str.split("");
7385
	for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0);
7386
	return o;
7387
}
7388
7389
/* [MS-OFFCRYPTO] 2.1.4 Version */
7390
function parse_CRYPTOVersion(blob, length) {
7391
	var o = {};
7392
	o.Major = blob.read_shift(2);
7393
	o.Minor = blob.read_shift(2);
7394
if(length >= 4) blob.l += length - 4;
7395
	return o;
7396
}
7397
7398
/* [MS-OFFCRYPTO] 2.1.5 DataSpaceVersionInfo */
7399
function parse_DataSpaceVersionInfo(blob) {
7400
	var o = {};
7401
	o.id = blob.read_shift(0, 'lpp4');
7402
	o.R = parse_CRYPTOVersion(blob, 4);
7403
	o.U = parse_CRYPTOVersion(blob, 4);
7404
	o.W = parse_CRYPTOVersion(blob, 4);
7405
	return o;
7406
}
7407
7408
/* [MS-OFFCRYPTO] 2.1.6.1 DataSpaceMapEntry Structure */
7409
function parse_DataSpaceMapEntry(blob) {
7410
	var len = blob.read_shift(4);
7411
	var end = blob.l + len - 4;
7412
	var o = {};
7413
	var cnt = blob.read_shift(4);
7414
	var comps = [];
7415
	/* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
7416
	while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') });
7417
	o.name = blob.read_shift(0, 'lpp4');
7418
	o.comps = comps;
7419
	if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end);
7420
	return o;
7421
}
7422
7423
/* [MS-OFFCRYPTO] 2.1.6 DataSpaceMap */
7424
function parse_DataSpaceMap(blob) {
7425
	var o = [];
7426
	blob.l += 4; // must be 0x8
7427
	var cnt = blob.read_shift(4);
7428
	while(cnt-- > 0) o.push(parse_DataSpaceMapEntry(blob));
7429
	return o;
7430
}
7431
7432
/* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */
7433
function parse_DataSpaceDefinition(blob) {
7434
	var o = [];
7435
	blob.l += 4; // must be 0x8
7436
	var cnt = blob.read_shift(4);
7437
	while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4'));
7438
	return o;
7439
}
7440
7441
/* [MS-OFFCRYPTO] 2.1.8 DataSpaceDefinition */
7442
function parse_TransformInfoHeader(blob) {
7443
	var o = {};
7444
	/*var len = */blob.read_shift(4);
7445
	blob.l += 4; // must be 0x1
7446
	o.id = blob.read_shift(0, 'lpp4');
7447
	o.name = blob.read_shift(0, 'lpp4');
7448
	o.R = parse_CRYPTOVersion(blob, 4);
7449
	o.U = parse_CRYPTOVersion(blob, 4);
7450
	o.W = parse_CRYPTOVersion(blob, 4);
7451
	return o;
7452
}
7453
7454
function parse_Primary(blob) {
7455
	/* [MS-OFFCRYPTO] 2.2.6 IRMDSTransformInfo */
7456
	var hdr = parse_TransformInfoHeader(blob);
7457
	/* [MS-OFFCRYPTO] 2.1.9 EncryptionTransformInfo */
7458
	hdr.ename = blob.read_shift(0, '8lpp4');
7459
	hdr.blksz = blob.read_shift(4);
7460
	hdr.cmode = blob.read_shift(4);
7461
	if(blob.read_shift(4) != 0x04) throw new Error("Bad !Primary record");
7462
	return hdr;
7463
}
7464
7465
/* [MS-OFFCRYPTO] 2.3.2 Encryption Header */
7466
function parse_EncryptionHeader(blob, length) {
7467
	var tgt = blob.l + length;
7468
	var o = {};
7469
	o.Flags = (blob.read_shift(4) & 0x3F);
7470
	blob.l += 4;
7471
	o.AlgID = blob.read_shift(4);
7472
	var valid = false;
7473
	switch(o.AlgID) {
7474
		case 0x660E: case 0x660F: case 0x6610: valid = (o.Flags == 0x24); break;
7475
		case 0x6801: valid = (o.Flags == 0x04); break;
7476
		case 0: valid = (o.Flags == 0x10 || o.Flags == 0x04 || o.Flags == 0x24); break;
7477
		default: throw 'Unrecognized encryption algorithm: ' + o.AlgID;
7478
	}
7479
	if(!valid) throw new Error("Encryption Flags/AlgID mismatch");
7480
	o.AlgIDHash = blob.read_shift(4);
7481
	o.KeySize = blob.read_shift(4);
7482
	o.ProviderType = blob.read_shift(4);
7483
	blob.l += 8;
7484
	o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
7485
	blob.l = tgt;
7486
	return o;
7487
}
7488
7489
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
7490
function parse_EncryptionVerifier(blob, length) {
7491
	var o = {}, tgt = blob.l + length;
7492
	blob.l += 4; // SaltSize must be 0x10
7493
	o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
7494
	o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
7495
	/*var sz = */blob.read_shift(4);
7496
	o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
7497
	return o;
7498
}
7499
7500
/* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */
7501
function parse_EncryptionInfo(blob) {
7502
	var vers = parse_CRYPTOVersion(blob);
7503
	switch(vers.Minor) {
7504
		case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
7505
		case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
7506
		case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
7507
	}
7508
	throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
7509
}
7510
7511
/* [MS-OFFCRYPTO] 2.3.4.5  EncryptionInfo Stream (Standard Encryption) */
7512
function parse_EncInfoStd(blob) {
7513
	var flags = blob.read_shift(4);
7514
	if((flags & 0x3F) != 0x24) throw new Error("EncryptionInfo mismatch");
7515
	var sz = blob.read_shift(4);
7516
	//var tgt = blob.l + sz;
7517
	var hdr = parse_EncryptionHeader(blob, sz);
7518
	var verifier = parse_EncryptionVerifier(blob, blob.length - blob.l);
7519
	return { t:"Std", h:hdr, v:verifier };
7520
}
7521
/* [MS-OFFCRYPTO] 2.3.4.6  EncryptionInfo Stream (Extensible Encryption) */
7522
function parse_EncInfoExt() { throw new Error("File is password-protected: ECMA-376 Extensible"); }
7523
/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
7524
function parse_EncInfoAgl(blob) {
7525
	var KeyData = ["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];
7526
	blob.l+=4;
7527
	var xml = blob.read_shift(blob.length - blob.l, 'utf8');
7528
	var o = {};
7529
	xml.replace(tagregex, function xml_agile(x) {
7530
		var y = parsexmltag(x);
7531
		switch(strip_ns(y[0])) {
7532
			case '<?xml': break;
7533
			case '<encryption': case '</encryption>': break;
7534
			case '<keyData': KeyData.forEach(function(k) { o[k] = y[k]; }); break;
7535
			case '<dataIntegrity': o.encryptedHmacKey = y.encryptedHmacKey; o.encryptedHmacValue = y.encryptedHmacValue; break;
7536
			case '<keyEncryptors>': case '<keyEncryptors': o.encs = []; break;
7537
			case '</keyEncryptors>': break;
7538
7539
			case '<keyEncryptor': o.uri = y.uri; break;
7540
			case '</keyEncryptor>': break;
7541
			case '<encryptedKey': o.encs.push(y); break;
7542
			default: throw y[0];
7543
		}
7544
	});
7545
	return o;
7546
}
7547
7548
/* [MS-OFFCRYPTO] 2.3.5.1 RC4 CryptoAPI Encryption Header */
7549
function parse_RC4CryptoHeader(blob, length) {
7550
	var o = {};
7551
	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4;
7552
	if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor);
7553
	if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major);
7554
	o.Flags = blob.read_shift(4); length -= 4;
7555
	var sz = blob.read_shift(4); length -= 4;
7556
	o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
7557
	o.EncryptionVerifier = parse_EncryptionVerifier(blob, length);
7558
	return o;
7559
}
7560
/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
7561
function parse_RC4Header(blob) {
7562
	var o = {};
7563
	var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4);
7564
	if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
7565
	o.Salt = blob.read_shift(16);
7566
	o.EncryptedVerifier = blob.read_shift(16);
7567
	o.EncryptedVerifierHash = blob.read_shift(16);
7568
	return o;
7569
}
7570
7571
/* [MS-OFFCRYPTO] 2.3.7.1 Binary Document Password Verifier Derivation */
7572
function crypto_CreatePasswordVerifier_Method1(Password) {
7573
	var Verifier = 0x0000, PasswordArray;
7574
	var PasswordDecoded = _JS2ANSI(Password);
7575
	var len = PasswordDecoded.length + 1, i, PasswordByte;
7576
	var Intermediate1, Intermediate2, Intermediate3;
7577
	PasswordArray = new_raw_buf(len);
7578
	PasswordArray[0] = PasswordDecoded.length;
7579
	for(i = 1; i != len; ++i) PasswordArray[i] = PasswordDecoded[i-1];
7580
	for(i = len-1; i >= 0; --i) {
7581
		PasswordByte = PasswordArray[i];
7582
		Intermediate1 = ((Verifier & 0x4000) === 0x0000) ? 0 : 1;
7583
		Intermediate2 = (Verifier << 1) & 0x7FFF;
7584
		Intermediate3 = Intermediate1 | Intermediate2;
7585
		Verifier = Intermediate3 ^ PasswordByte;
7586
	}
7587
	return Verifier ^ 0xCE4B;
7588
}
7589
7590
/* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */
7591
var crypto_CreateXorArray_Method1 = (function() {
7592
	var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00];
7593
	var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3];
7594
	var XorMatrix = [0xAEFC, 0x4DD9, 0x9BB2, 0x2745, 0x4E8A, 0x9D14, 0x2A09, 0x7B61, 0xF6C2, 0xFDA5, 0xEB6B, 0xC6F7, 0x9DCF, 0x2BBF, 0x4563, 0x8AC6, 0x05AD, 0x0B5A, 0x16B4, 0x2D68, 0x5AD0, 0x0375, 0x06EA, 0x0DD4, 0x1BA8, 0x3750, 0x6EA0, 0xDD40, 0xD849, 0xA0B3, 0x5147, 0xA28E, 0x553D, 0xAA7A, 0x44D5, 0x6F45, 0xDE8A, 0xAD35, 0x4A4B, 0x9496, 0x390D, 0x721A, 0xEB23, 0xC667, 0x9CEF, 0x29FF, 0x53FE, 0xA7FC, 0x5FD9, 0x47D3, 0x8FA6, 0x0F6D, 0x1EDA, 0x3DB4, 0x7B68, 0xF6D0, 0xB861, 0x60E3, 0xC1C6, 0x93AD, 0x377B, 0x6EF6, 0xDDEC, 0x45A0, 0x8B40, 0x06A1, 0x0D42, 0x1A84, 0x3508, 0x6A10, 0xAA51, 0x4483, 0x8906, 0x022D, 0x045A, 0x08B4, 0x1168, 0x76B4, 0xED68, 0xCAF1, 0x85C3, 0x1BA7, 0x374E, 0x6E9C, 0x3730, 0x6E60, 0xDCC0, 0xA9A1, 0x4363, 0x86C6, 0x1DAD, 0x3331, 0x6662, 0xCCC4, 0x89A9, 0x0373, 0x06E6, 0x0DCC, 0x1021, 0x2042, 0x4084, 0x8108, 0x1231, 0x2462, 0x48C4];
7595
	var Ror = function(Byte) { return ((Byte/2) | (Byte*128)) & 0xFF; };
7596
	var XorRor = function(byte1, byte2) { return Ror(byte1 ^ byte2); };
7597
	var CreateXorKey_Method1 = function(Password) {
7598
		var XorKey = InitialCode[Password.length - 1];
7599
		var CurrentElement = 0x68;
7600
		for(var i = Password.length-1; i >= 0; --i) {
7601
			var Char = Password[i];
7602
			for(var j = 0; j != 7; ++j) {
7603
				if(Char & 0x40) XorKey ^= XorMatrix[CurrentElement];
7604
				Char *= 2; --CurrentElement;
7605
			}
7606
		}
7607
		return XorKey;
7608
	};
7609
	return function(password) {
7610
		var Password = _JS2ANSI(password);
7611
		var XorKey = CreateXorKey_Method1(Password);
7612
		var Index = Password.length;
7613
		var ObfuscationArray = new_raw_buf(16);
7614
		for(var i = 0; i != 16; ++i) ObfuscationArray[i] = 0x00;
7615
		var Temp, PasswordLastChar, PadIndex;
7616
		if((Index & 1) === 1) {
7617
			Temp = XorKey >> 8;
7618
			ObfuscationArray[Index] = XorRor(PadArray[0], Temp);
7619
			--Index;
7620
			Temp = XorKey & 0xFF;
7621
			PasswordLastChar = Password[Password.length - 1];
7622
			ObfuscationArray[Index] = XorRor(PasswordLastChar, Temp);
7623
		}
7624
		while(Index > 0) {
7625
			--Index;
7626
			Temp = XorKey >> 8;
7627
			ObfuscationArray[Index] = XorRor(Password[Index], Temp);
7628
			--Index;
7629
			Temp = XorKey & 0xFF;
7630
			ObfuscationArray[Index] = XorRor(Password[Index], Temp);
7631
		}
7632
		Index = 15;
7633
		PadIndex = 15 - Password.length;
7634
		while(PadIndex > 0) {
7635
			Temp = XorKey >> 8;
7636
			ObfuscationArray[Index] = XorRor(PadArray[PadIndex], Temp);
7637
			--Index;
7638
			--PadIndex;
7639
			Temp = XorKey & 0xFF;
7640
			ObfuscationArray[Index] = XorRor(Password[Index], Temp);
7641
			--Index;
7642
			--PadIndex;
7643
		}
7644
		return ObfuscationArray;
7645
	};
7646
})();
7647
7648
/* [MS-OFFCRYPTO] 2.3.7.3 Binary Document XOR Data Transformation Method 1 */
7649
var crypto_DecryptData_Method1 = function(password, Data, XorArrayIndex, XorArray, O) {
7650
	/* If XorArray is set, use it; if O is not set, make changes in-place */
7651
	if(!O) O = Data;
7652
	if(!XorArray) XorArray = crypto_CreateXorArray_Method1(password);
7653
	var Index, Value;
7654
	for(Index = 0; Index != Data.length; ++Index) {
7655
		Value = Data[Index];
7656
		Value ^= XorArray[XorArrayIndex];
7657
		Value = ((Value>>5) | (Value<<3)) & 0xFF;
7658
		O[Index] = Value;
7659
		++XorArrayIndex;
7660
	}
7661
	return [O, XorArrayIndex, XorArray];
7662
};
7663
7664
var crypto_MakeXorDecryptor = function(password) {
7665
	var XorArrayIndex = 0, XorArray = crypto_CreateXorArray_Method1(password);
7666
	return function(Data) {
7667
		var O = crypto_DecryptData_Method1("", Data, XorArrayIndex, XorArray);
7668
		XorArrayIndex = O[1];
7669
		return O[0];
7670
	};
7671
};
7672
7673
/* 2.5.343 */
7674
function parse_XORObfuscation(blob, length, opts, out) {
7675
	var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) });
7676
	if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
7677
	out.valid = o.verificationBytes === o.verifier;
7678
	if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
7679
	return o;
7680
}
7681
7682
/* 2.4.117 */
7683
function parse_FilePassHeader(blob, length, oo) {
7684
	var o = oo || {}; o.Info = blob.read_shift(2); blob.l -= 2;
7685
	if(o.Info === 1) o.Data = parse_RC4Header(blob, length);
7686
	else o.Data = parse_RC4CryptoHeader(blob, length);
7687
	return o;
7688
}
7689
function parse_FilePass(blob, length, opts) {
7690
	var o = ({ Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }); /* wEncryptionType */
7691
	if(o.Type) parse_FilePassHeader(blob, length-2, o);
7692
	else parse_XORObfuscation(blob, opts.biff >= 8 ? length : length - 2, opts, o);
7693
	return o;
7694
}
7695
7696
7697
var RTF = (function() {
7698
	function rtf_to_sheet(d, opts) {
7699
		switch(opts.type) {
7700
			case 'base64': return rtf_to_sheet_str(Base64.decode(d), opts);
7701
			case 'binary': return rtf_to_sheet_str(d, opts);
7702
			case 'buffer': return rtf_to_sheet_str(d.toString('binary'), opts);
7703
			case 'array':  return rtf_to_sheet_str(cc2str(d), opts);
7704
		}
7705
		throw new Error("Unrecognized type " + opts.type);
7706
	}
7707
7708
	function rtf_to_sheet_str(str, opts) {
7709
		var o = opts || {};
7710
		var ws = o.dense ? ([]) : ({});
7711
		var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
7712
7713
		// TODO: parse
7714
		if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
7715
7716
		ws['!ref'] = encode_range(range);
7717
		return ws;
7718
	}
7719
7720
	function rtf_to_workbook(d, opts) { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
7721
7722
	/* TODO: this is a stub */
7723
	function sheet_to_rtf(ws) {
7724
		var o = ["{\\rtf1\\ansi"];
7725
		var r = safe_decode_range(ws['!ref']), cell;
7726
		var dense = Array.isArray(ws);
7727
		for(var R = r.s.r; R <= r.e.r; ++R) {
7728
			o.push("\\trowd\\trautofit1");
7729
			for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
7730
			o.push("\\pard\\intbl");
7731
			for(C = r.s.c; C <= r.e.c; ++C) {
7732
				var coord = encode_cell({r:R,c:C});
7733
				cell = dense ? (ws[R]||[])[C]: ws[coord];
7734
				if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
7735
				o.push(" " + (cell.w || (format_cell(cell), cell.w)));
7736
				o.push("\\cell");
7737
			}
7738
			o.push("\\pard\\intbl\\row");
7739
		}
7740
		return o.join("") + "}";
7741
	}
7742
7743
	return {
7744
		to_workbook: rtf_to_workbook,
7745
		to_sheet: rtf_to_sheet,
7746
		from_sheet: sheet_to_rtf
7747
	};
7748
})();
7749
function hex2RGB(h) {
7750
	var o = h.slice(h[0]==="#"?1:0).slice(0,6);
7751
	return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
7752
}
7753
function rgb2Hex(rgb) {
7754
	for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
7755
	return o.toString(16).toUpperCase().slice(1);
7756
}
7757
7758
function rgb2HSL(rgb) {
7759
	var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
7760
	var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
7761
	if(C === 0) return [0, 0, R];
7762
7763
	var H6 = 0, S = 0, L2 = (M + m);
7764
	S = C / (L2 > 1 ? 2 - L2 : L2);
7765
	switch(M){
7766
		case R: H6 = ((G - B) / C + 6)%6; break;
7767
		case G: H6 = ((B - R) / C + 2); break;
7768
		case B: H6 = ((R - G) / C + 4); break;
7769
	}
7770
	return [H6 / 6, S, L2 / 2];
7771
}
7772
7773
function hsl2RGB(hsl){
7774
	var H = hsl[0], S = hsl[1], L = hsl[2];
7775
	var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
7776
	var rgb = [m,m,m], h6 = 6*H;
7777
7778
	var X;
7779
	if(S !== 0) switch(h6|0) {
7780
		case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
7781
		case 1: X = C * (2 - h6);   rgb[0] += X; rgb[1] += C; break;
7782
		case 2: X = C * (h6 - 2);   rgb[1] += C; rgb[2] += X; break;
7783
		case 3: X = C * (4 - h6);   rgb[1] += X; rgb[2] += C; break;
7784
		case 4: X = C * (h6 - 4);   rgb[2] += C; rgb[0] += X; break;
7785
		case 5: X = C * (6 - h6);   rgb[2] += X; rgb[0] += C; break;
7786
	}
7787
	for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
7788
	return rgb;
7789
}
7790
7791
/* 18.8.3 bgColor tint algorithm */
7792
function rgb_tint(hex, tint) {
7793
	if(tint === 0) return hex;
7794
	var hsl = rgb2HSL(hex2RGB(hex));
7795
	if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
7796
	else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
7797
	return rgb2Hex(hsl2RGB(hsl));
7798
}
7799
7800
/* 18.3.1.13 width calculations */
7801
/* [MS-OI29500] 2.1.595 Column Width & Formatting */
7802
var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
7803
function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
7804
function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
7805
function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
7806
//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
7807
//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
7808
function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
7809
/* XLSX/XLSB/XLS specify width in units of MDW */
7810
function find_mdw_colw(collw) {
7811
	var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
7812
	if(delta > 0.005) for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) if(Math.abs(collw - cycle_width(collw)) <= delta) { delta = Math.abs(collw - cycle_width(collw)); _MDW = MDW; }
7813
	MDW = _MDW;
7814
}
7815
/* XLML specifies width in terms of pixels */
7816
/*function find_mdw_wpx(wpx) {
7817
	var delta = Infinity, guess = 0, _MDW = MIN_MDW;
7818
	for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
7819
		guess = char2width_(px2char_(wpx))*256;
7820
		guess = (guess) % 1;
7821
		if(guess > 0.5) guess--;
7822
		if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
7823
	}
7824
	MDW = _MDW;
7825
}*/
7826
7827
function process_col(coll) {
7828
	if(coll.width) {
7829
		coll.wpx = width2px(coll.width);
7830
		coll.wch = px2char(coll.wpx);
7831
		coll.MDW = MDW;
7832
	} else if(coll.wpx) {
7833
		coll.wch = px2char(coll.wpx);
7834
		coll.width = char2width(coll.wch);
7835
		coll.MDW = MDW;
7836
	} else if(typeof coll.wch == 'number') {
7837
		coll.width = char2width(coll.wch);
7838
		coll.wpx = width2px(coll.width);
7839
		coll.MDW = MDW;
7840
	}
7841
	if(coll.customWidth) delete coll.customWidth;
7842
}
7843
7844
var DEF_PPI = 96, PPI = DEF_PPI;
7845
function px2pt(px) { return px * 96 / PPI; }
7846
function pt2px(pt) { return pt * PPI / 96; }
7847
7848
/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
7849
var XLMLPatternTypeMap = {
7850
	"None": "none",
7851
	"Solid": "solid",
7852
	"Gray50": "mediumGray",
7853
	"Gray75": "darkGray",
7854
	"Gray25": "lightGray",
7855
	"HorzStripe": "darkHorizontal",
7856
	"VertStripe": "darkVertical",
7857
	"ReverseDiagStripe": "darkDown",
7858
	"DiagStripe": "darkUp",
7859
	"DiagCross": "darkGrid",
7860
	"ThickDiagCross": "darkTrellis",
7861
	"ThinHorzStripe": "lightHorizontal",
7862
	"ThinVertStripe": "lightVertical",
7863
	"ThinReverseDiagStripe": "lightDown",
7864
	"ThinHorzCross": "lightGrid"
7865
};
7866
7867
/* 18.8.5 borders CT_Borders */
7868
function parse_borders(t, styles, themes, opts) {
7869
	styles.Borders = [];
7870
	var border = {}/*, sub_border = {}*/;
7871
	var pass = false;
7872
	t[0].match(tagregex).forEach(function(x) {
7873
		var y = parsexmltag(x);
7874
		switch(strip_ns(y[0])) {
7875
			case '<borders': case '<borders>': case '</borders>': break;
7876
7877
			/* 18.8.4 border CT_Border */
7878
			case '<border': case '<border>': case '<border/>':
7879
				border = {};
7880
				if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; }
7881
				if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; }
7882
				styles.Borders.push(border);
7883
				break;
7884
			case '</border>': break;
7885
7886
			/* note: not in spec, appears to be CT_BorderPr */
7887
			case '<left/>': break;
7888
			case '<left': case '<left>': break;
7889
			case '</left>': break;
7890
7891
			/* note: not in spec, appears to be CT_BorderPr */
7892
			case '<right/>': break;
7893
			case '<right': case '<right>': break;
7894
			case '</right>': break;
7895
7896
			/* 18.8.43 top CT_BorderPr */
7897
			case '<top/>': break;
7898
			case '<top': case '<top>': break;
7899
			case '</top>': break;
7900
7901
			/* 18.8.6 bottom CT_BorderPr */
7902
			case '<bottom/>': break;
7903
			case '<bottom': case '<bottom>': break;
7904
			case '</bottom>': break;
7905
7906
			/* 18.8.13 diagonal CT_BorderPr */
7907
			case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
7908
			case '</diagonal>': break;
7909
7910
			/* 18.8.25 horizontal CT_BorderPr */
7911
			case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
7912
			case '</horizontal>': break;
7913
7914
			/* 18.8.44 vertical CT_BorderPr */
7915
			case '<vertical': case '<vertical>': case '<vertical/>': break;
7916
			case '</vertical>': break;
7917
7918
			/* 18.8.37 start CT_BorderPr */
7919
			case '<start': case '<start>': case '<start/>': break;
7920
			case '</start>': break;
7921
7922
			/* 18.8.16 end CT_BorderPr */
7923
			case '<end': case '<end>': case '<end/>': break;
7924
			case '</end>': break;
7925
7926
			/* 18.8.? color CT_Color */
7927
			case '<color': case '<color>': break;
7928
			case '<color/>': case '</color>': break;
7929
7930
			/* 18.2.10 extLst CT_ExtensionList ? */
7931
			case '<extLst': case '<extLst>': case '</extLst>': break;
7932
			case '<ext': pass = true; break;
7933
			case '</ext>': pass = false; break;
7934
			default: if(opts && opts.WTF) {
7935
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
7936
			}
7937
		}
7938
	});
7939
}
7940
7941
/* 18.8.21 fills CT_Fills */
7942
function parse_fills(t, styles, themes, opts) {
7943
	styles.Fills = [];
7944
	var fill = {};
7945
	var pass = false;
7946
	t[0].match(tagregex).forEach(function(x) {
7947
		var y = parsexmltag(x);
7948
		switch(strip_ns(y[0])) {
7949
			case '<fills': case '<fills>': case '</fills>': break;
7950
7951
			/* 18.8.20 fill CT_Fill */
7952
			case '<fill>': case '<fill': case '<fill/>':
7953
				fill = {}; styles.Fills.push(fill); break;
7954
			case '</fill>': break;
7955
7956
			/* 18.8.24 gradientFill CT_GradientFill */
7957
			case '<gradientFill>': break;
7958
			case '<gradientFill':
7959
			case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
7960
7961
			/* 18.8.32 patternFill CT_PatternFill */
7962
			case '<patternFill': case '<patternFill>':
7963
				if(y.patternType) fill.patternType = y.patternType;
7964
				break;
7965
			case '<patternFill/>': case '</patternFill>': break;
7966
7967
			/* 18.8.3 bgColor CT_Color */
7968
			case '<bgColor':
7969
				if(!fill.bgColor) fill.bgColor = {};
7970
				if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
7971
				if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
7972
				if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
7973
				/* Excel uses ARGB strings */
7974
				if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
7975
				break;
7976
			case '<bgColor/>': case '</bgColor>': break;
7977
7978
			/* 18.8.19 fgColor CT_Color */
7979
			case '<fgColor':
7980
				if(!fill.fgColor) fill.fgColor = {};
7981
				if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
7982
				if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
7983
				/* Excel uses ARGB strings */
7984
				if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6);
7985
				break;
7986
			case '<fgColor/>': case '</fgColor>': break;
7987
7988
			/* 18.8.38 stop CT_GradientStop */
7989
			case '<stop': case '<stop/>': break;
7990
			case '</stop>': break;
7991
7992
			/* 18.8.? color CT_Color */
7993
			case '<color': case '<color/>': break;
7994
			case '</color>': break;
7995
7996
			/* 18.2.10 extLst CT_ExtensionList ? */
7997
			case '<extLst': case '<extLst>': case '</extLst>': break;
7998
			case '<ext': pass = true; break;
7999
			case '</ext>': pass = false; break;
8000
			default: if(opts && opts.WTF) {
8001
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
8002
			}
8003
		}
8004
	});
8005
}
8006
8007
/* 18.8.23 fonts CT_Fonts */
8008
function parse_fonts(t, styles, themes, opts) {
8009
	styles.Fonts = [];
8010
	var font = {};
8011
	var pass = false;
8012
	t[0].match(tagregex).forEach(function(x) {
8013
		var y = parsexmltag(x);
8014
		switch(strip_ns(y[0])) {
8015
			case '<fonts': case '<fonts>': case '</fonts>': break;
8016
8017
			/* 18.8.22 font CT_Font */
8018
			case '<font': case '<font>': break;
8019
			case '</font>': case '<font/>':
8020
				styles.Fonts.push(font);
8021
				font = {};
8022
				break;
8023
8024
			/* 18.8.29 name CT_FontName */
8025
			case '<name': if(y.val) font.name = y.val; break;
8026
			case '<name/>': case '</name>': break;
8027
8028
			/* 18.8.2  b CT_BooleanProperty */
8029
			case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
8030
			case '<b/>': font.bold = 1; break;
8031
8032
			/* 18.8.26 i CT_BooleanProperty */
8033
			case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
8034
			case '<i/>': font.italic = 1; break;
8035
8036
			/* 18.4.13 u CT_UnderlineProperty */
8037
			case '<u':
8038
				switch(y.val) {
8039
					case "none": font.underline = 0x00; break;
8040
					case "single": font.underline = 0x01; break;
8041
					case "double": font.underline = 0x02; break;
8042
					case "singleAccounting": font.underline = 0x21; break;
8043
					case "doubleAccounting": font.underline = 0x22; break;
8044
				} break;
8045
			case '<u/>': font.underline = 1; break;
8046
8047
			/* 18.4.10 strike CT_BooleanProperty */
8048
			case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
8049
			case '<strike/>': font.strike = 1; break;
8050
8051
			/* 18.4.2  outline CT_BooleanProperty */
8052
			case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
8053
			case '<outline/>': font.outline = 1; break;
8054
8055
			/* 18.8.36 shadow CT_BooleanProperty */
8056
			case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
8057
			case '<shadow/>': font.shadow = 1; break;
8058
8059
			/* 18.8.12 condense CT_BooleanProperty */
8060
			case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
8061
			case '<condense/>': font.condense = 1; break;
8062
8063
			/* 18.8.17 extend CT_BooleanProperty */
8064
			case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
8065
			case '<extend/>': font.extend = 1; break;
8066
8067
			/* 18.4.11 sz CT_FontSize */
8068
			case '<sz': if(y.val) font.sz = +y.val; break;
8069
			case '<sz/>': case '</sz>': break;
8070
8071
			/* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
8072
			case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
8073
			case '<vertAlign/>': case '</vertAlign>': break;
8074
8075
			/* 18.8.18 family CT_FontFamily */
8076
			case '<family': if(y.val) font.family = parseInt(y.val,10); break;
8077
			case '<family/>': case '</family>': break;
8078
8079
			/* 18.8.35 scheme CT_FontScheme */
8080
			case '<scheme': if(y.val) font.scheme = y.val; break;
8081
			case '<scheme/>': case '</scheme>': break;
8082
8083
			/* 18.4.1 charset CT_IntProperty */
8084
			case '<charset':
8085
				if(y.val == '1') break;
8086
				y.codepage = CS2CP[parseInt(y.val, 10)];
8087
				break;
8088
8089
			/* 18.?.? color CT_Color */
8090
			case '<color':
8091
				if(!font.color) font.color = {};
8092
				if(y.auto) font.color.auto = parsexmlbool(y.auto);
8093
8094
				if(y.rgb) font.color.rgb = y.rgb.slice(-6);
8095
				else if(y.indexed) {
8096
					font.color.index = parseInt(y.indexed, 10);
8097
					var icv = XLSIcv[font.color.index];
8098
					if(font.color.index == 81) icv = XLSIcv[1];
8099
					if(!icv) throw new Error(x);
8100
					font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
8101
				} else if(y.theme) {
8102
					font.color.theme = parseInt(y.theme, 10);
8103
					if(y.tint) font.color.tint = parseFloat(y.tint);
8104
					if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
8105
						font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
8106
					}
8107
				}
8108
8109
				break;
8110
			case '<color/>': case '</color>': break;
8111
8112
			/* 18.2.10 extLst CT_ExtensionList ? */
8113
			case '<extLst': case '<extLst>': case '</extLst>': break;
8114
			case '<ext': pass = true; break;
8115
			case '</ext>': pass = false; break;
8116
			default: if(opts && opts.WTF) {
8117
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
8118
			}
8119
		}
8120
	});
8121
}
8122
8123
/* 18.8.31 numFmts CT_NumFmts */
8124
function parse_numFmts(t, styles, opts) {
8125
	styles.NumberFmt = [];
8126
	var k/*Array<number>*/ = (keys(SSF._table));
8127
	for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
8128
	var m = t[0].match(tagregex);
8129
	if(!m) return;
8130
	for(i=0; i < m.length; ++i) {
8131
		var y = parsexmltag(m[i]);
8132
		switch(strip_ns(y[0])) {
8133
			case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
8134
			case '<numFmt': {
8135
				var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
8136
				styles.NumberFmt[j] = f;
8137
				if(j>0) {
8138
					if(j > 0x188) {
8139
						for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
8140
						styles.NumberFmt[j] = f;
8141
					}
8142
					SSF.load(f,j);
8143
				}
8144
			} break;
8145
			case '</numFmt>': break;
8146
			default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
8147
		}
8148
	}
8149
}
8150
8151
function write_numFmts(NF) {
8152
	var o = ["<numFmts>"];
8153
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8154
		for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) o[o.length] = (writextag('numFmt',null,{numFmtId:i,formatCode:escapexml(NF[i])}));
8155
	});
8156
	if(o.length === 1) return "";
8157
	o[o.length] = ("</numFmts>");
8158
	o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
8159
	return o.join("");
8160
}
8161
8162
/* 18.8.10 cellXfs CT_CellXfs */
8163
var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
8164
var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
8165
function parse_cellXfs(t, styles, opts) {
8166
	styles.CellXf = [];
8167
	var xf;
8168
	var pass = false;
8169
	t[0].match(tagregex).forEach(function(x) {
8170
		var y = parsexmltag(x), i = 0;
8171
		switch(strip_ns(y[0])) {
8172
			case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
8173
8174
			/* 18.8.45 xf CT_Xf */
8175
			case '<xf': case '<xf/>':
8176
				xf = y;
8177
				delete xf[0];
8178
				for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
8179
					xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
8180
				for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
8181
					xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
8182
				if(xf.numFmtId > 0x188) {
8183
					for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
8184
				}
8185
				styles.CellXf.push(xf); break;
8186
			case '</xf>': break;
8187
8188
			/* 18.8.1 alignment CT_CellAlignment */
8189
			case '<alignment': case '<alignment/>':
8190
				var alignment = {};
8191
				if(y.vertical) alignment.vertical = y.vertical;
8192
				if(y.horizontal) alignment.horizontal = y.horizontal;
8193
				if(y.textRotation != null) alignment.textRotation = y.textRotation;
8194
				if(y.indent) alignment.indent = y.indent;
8195
				if(y.wrapText) alignment.wrapText = y.wrapText;
8196
				xf.alignment = alignment;
8197
				break;
8198
			case '</alignment>': break;
8199
8200
			/* 18.8.33 protection CT_CellProtection */
8201
			case '<protection': case '</protection>': case '<protection/>': break;
8202
8203
			/* 18.2.10 extLst CT_ExtensionList ? */
8204
			case '<extLst': case '<extLst>': case '</extLst>': break;
8205
			case '<ext': pass = true; break;
8206
			case '</ext>': pass = false; break;
8207
			default: if(opts && opts.WTF) {
8208
				if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
8209
			}
8210
		}
8211
	});
8212
}
8213
8214
function write_cellXfs(cellXfs) {
8215
	var o = [];
8216
	o[o.length] = (writextag('cellXfs',null));
8217
	cellXfs.forEach(function(c) { o[o.length] = (writextag('xf', null, c)); });
8218
	o[o.length] = ("</cellXfs>");
8219
	if(o.length === 2) return "";
8220
	o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
8221
	return o.join("");
8222
}
8223
8224
/* 18.8 Styles CT_Stylesheet*/
8225
var parse_sty_xml= (function make_pstyx() {
8226
var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
8227
var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
8228
var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
8229
var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
8230
var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
8231
8232
return function parse_sty_xml(data, themes, opts) {
8233
	var styles = {};
8234
	if(!data) return styles;
8235
	data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
8236
	/* 18.8.39 styleSheet CT_Stylesheet */
8237
	var t;
8238
8239
	/* 18.8.31 numFmts CT_NumFmts ? */
8240
	if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
8241
8242
	/* 18.8.23 fonts CT_Fonts ? */
8243
	if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
8244
8245
	/* 18.8.21 fills CT_Fills ? */
8246
	if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
8247
8248
	/* 18.8.5  borders CT_Borders ? */
8249
	if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
8250
8251
	/* 18.8.9  cellStyleXfs CT_CellStyleXfs ? */
8252
8253
	/* 18.8.10 cellXfs CT_CellXfs ? */
8254
	if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
8255
8256
	/* 18.8.8  cellStyles CT_CellStyles ? */
8257
	/* 18.8.15 dxfs CT_Dxfs ? */
8258
	/* 18.8.42 tableStyles CT_TableStyles ? */
8259
	/* 18.8.11 colors CT_Colors ? */
8260
	/* 18.2.10 extLst CT_ExtensionList ? */
8261
8262
	return styles;
8263
};
8264
})();
8265
8266
var STYLES_XML_ROOT = writextag('styleSheet', null, {
8267
	'xmlns': XMLNS.main[0],
8268
	'xmlns:vt': XMLNS.vt
8269
});
8270
8271
RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
8272
8273
function write_sty_xml(wb, opts) {
8274
	var o = [XML_HEADER, STYLES_XML_ROOT], w;
8275
	if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
8276
	o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
8277
	o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
8278
	o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
8279
	o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
8280
	if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
8281
	o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
8282
	o[o.length] = ('<dxfs count="0"/>');
8283
	o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
8284
8285
	if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
8286
	return o.join("");
8287
}
8288
/* [MS-XLSB] 2.4.657 BrtFmt */
8289
function parse_BrtFmt(data, length) {
8290
	var numFmtId = data.read_shift(2);
8291
	var stFmtCode = parse_XLWideString(data,length-2);
8292
	return [numFmtId, stFmtCode];
8293
}
8294
function write_BrtFmt(i, f, o) {
8295
	if(!o) o = new_buf(6 + 4 * f.length);
8296
	o.write_shift(2, i);
8297
	write_XLWideString(f, o);
8298
	var out = (o.length > o.l) ? o.slice(0, o.l) : o;
8299
	if(o.l == null) o.l = o.length;
8300
	return out;
8301
}
8302
8303
/* [MS-XLSB] 2.4.659 BrtFont TODO */
8304
function parse_BrtFont(data, length, opts) {
8305
	var out = ({});
8306
8307
	out.sz = data.read_shift(2) / 20;
8308
8309
	var grbit = parse_FontFlags(data, 2, opts);
8310
	if(grbit.fCondense) out.condense = 1;
8311
	if(grbit.fExtend) out.extend = 1;
8312
	if(grbit.fShadow) out.shadow = 1;
8313
	if(grbit.fOutline) out.outline = 1;
8314
	if(grbit.fStrikeout) out.strike = 1;
8315
	if(grbit.fItalic) out.italic = 1;
8316
8317
	var bls = data.read_shift(2);
8318
	if(bls === 0x02BC) out.bold = 1;
8319
8320
	switch(data.read_shift(2)) {
8321
		/* case 0: out.vertAlign = "baseline"; break; */
8322
		case 1: out.vertAlign = "superscript"; break;
8323
		case 2: out.vertAlign = "subscript"; break;
8324
	}
8325
8326
	var underline = data.read_shift(1);
8327
	if(underline != 0) out.underline = underline;
8328
8329
	var family = data.read_shift(1);
8330
	if(family > 0) out.family = family;
8331
8332
	var bCharSet = data.read_shift(1);
8333
	if(bCharSet > 0) out.charset = bCharSet;
8334
8335
	data.l++;
8336
	out.color = parse_BrtColor(data, 8);
8337
8338
	switch(data.read_shift(1)) {
8339
		/* case 0: out.scheme = "none": break; */
8340
		case 1: out.scheme = "major"; break;
8341
		case 2: out.scheme = "minor"; break;
8342
	}
8343
8344
	out.name = parse_XLWideString(data, length - 21);
8345
8346
	return out;
8347
}
8348
function write_BrtFont(font, o) {
8349
	if(!o) o = new_buf(25+4*32);
8350
	o.write_shift(2, font.sz * 20);
8351
	write_FontFlags(font, o);
8352
	o.write_shift(2, font.bold ? 0x02BC : 0x0190);
8353
	var sss = 0;
8354
	if(font.vertAlign == "superscript") sss = 1;
8355
	else if(font.vertAlign == "subscript") sss = 2;
8356
	o.write_shift(2, sss);
8357
	o.write_shift(1, font.underline || 0);
8358
	o.write_shift(1, font.family || 0);
8359
	o.write_shift(1, font.charset || 0);
8360
	o.write_shift(1, 0);
8361
	write_BrtColor(font.color, o);
8362
	var scheme = 0;
8363
	if(font.scheme == "major") scheme = 1;
8364
	if(font.scheme == "minor") scheme = 2;
8365
	o.write_shift(1, scheme);
8366
	write_XLWideString(font.name, o);
8367
	return o.length > o.l ? o.slice(0, o.l) : o;
8368
}
8369
8370
/* [MS-XLSB] 2.4.650 BrtFill */
8371
var XLSBFillPTNames = [
8372
	"none",
8373
	"solid",
8374
	"mediumGray",
8375
	"darkGray",
8376
	"lightGray",
8377
	"darkHorizontal",
8378
	"darkVertical",
8379
	"darkDown",
8380
	"darkUp",
8381
	"darkGrid",
8382
	"darkTrellis",
8383
	"lightHorizontal",
8384
	"lightVertical",
8385
	"lightDown",
8386
	"lightUp",
8387
	"lightGrid",
8388
	"lightTrellis",
8389
	"gray125",
8390
	"gray0625"
8391
];
8392
var rev_XLSBFillPTNames = (evert(XLSBFillPTNames));
8393
/* TODO: gradient fill representation */
8394
var parse_BrtFill = parsenoop;
8395
function write_BrtFill(fill, o) {
8396
	if(!o) o = new_buf(4*3 + 8*7 + 16*1);
8397
	var fls = rev_XLSBFillPTNames[fill.patternType];
8398
	if(fls == null) fls = 0x28;
8399
	o.write_shift(4, fls);
8400
	var j = 0;
8401
	if(fls != 0x28) {
8402
		/* TODO: custom FG Color */
8403
		write_BrtColor({auto:1}, o);
8404
		/* TODO: custom BG Color */
8405
		write_BrtColor({auto:1}, o);
8406
8407
		for(; j < 12; ++j) o.write_shift(4, 0);
8408
	} else {
8409
		for(; j < 4; ++j) o.write_shift(4, 0);
8410
8411
		for(; j < 12; ++j) o.write_shift(4, 0); /* TODO */
8412
		/* iGradientType */
8413
		/* xnumDegree */
8414
		/* xnumFillToLeft */
8415
		/* xnumFillToRight */
8416
		/* xnumFillToTop */
8417
		/* xnumFillToBottom */
8418
		/* cNumStop */
8419
		/* xfillGradientStop */
8420
	}
8421
	return o.length > o.l ? o.slice(0, o.l) : o;
8422
}
8423
8424
/* [MS-XLSB] 2.4.824 BrtXF */
8425
function parse_BrtXF(data, length) {
8426
	var tgt = data.l + length;
8427
	var ixfeParent = data.read_shift(2);
8428
	var ifmt = data.read_shift(2);
8429
	data.l = tgt;
8430
	return {ixfe:ixfeParent, numFmtId:ifmt };
8431
}
8432
function write_BrtXF(data, ixfeP, o) {
8433
	if(!o) o = new_buf(16);
8434
	o.write_shift(2, ixfeP||0);
8435
	o.write_shift(2, data.numFmtId||0);
8436
	o.write_shift(2, 0); /* iFont */
8437
	o.write_shift(2, 0); /* iFill */
8438
	o.write_shift(2, 0); /* ixBorder */
8439
	o.write_shift(1, 0); /* trot */
8440
	o.write_shift(1, 0); /* indent */
8441
	o.write_shift(1, 0); /* flags */
8442
	o.write_shift(1, 0); /* flags */
8443
	o.write_shift(1, 0); /* xfGrbitAtr */
8444
	o.write_shift(1, 0);
8445
	return o;
8446
}
8447
8448
/* [MS-XLSB] 2.5.4 Blxf TODO */
8449
function write_Blxf(data, o) {
8450
	if(!o) o = new_buf(10);
8451
	o.write_shift(1, 0); /* dg */
8452
	o.write_shift(1, 0);
8453
	o.write_shift(4, 0); /* color */
8454
	o.write_shift(4, 0); /* color */
8455
	return o;
8456
}
8457
/* [MS-XLSB] 2.4.302 BrtBorder TODO */
8458
var parse_BrtBorder = parsenoop;
8459
function write_BrtBorder(border, o) {
8460
	if(!o) o = new_buf(51);
8461
	o.write_shift(1, 0); /* diagonal */
8462
	write_Blxf(null, o); /* top */
8463
	write_Blxf(null, o); /* bottom */
8464
	write_Blxf(null, o); /* left */
8465
	write_Blxf(null, o); /* right */
8466
	write_Blxf(null, o); /* diag */
8467
	return o.length > o.l ? o.slice(0, o.l) : o;
8468
}
8469
8470
/* [MS-XLSB] 2.4.763 BrtStyle TODO */
8471
function write_BrtStyle(style, o) {
8472
	if(!o) o = new_buf(12+4*10);
8473
	o.write_shift(4, style.xfId);
8474
	o.write_shift(2, 1);
8475
	o.write_shift(1, +style.builtinId);
8476
	o.write_shift(1, 0); /* iLevel */
8477
	write_XLNullableWideString(style.name || "", o);
8478
	return o.length > o.l ? o.slice(0, o.l) : o;
8479
}
8480
8481
/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
8482
function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
8483
	var o = new_buf(4+256*2*4);
8484
	o.write_shift(4, cnt);
8485
	write_XLNullableWideString(defTableStyle, o);
8486
	write_XLNullableWideString(defPivotStyle, o);
8487
	return o.length > o.l ? o.slice(0, o.l) : o;
8488
}
8489
8490
/* [MS-XLSB] 2.1.7.50 Styles */
8491
function parse_sty_bin(data, themes, opts) {
8492
	var styles = {};
8493
	styles.NumberFmt = ([]);
8494
	for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y];
8495
8496
	styles.CellXf = [];
8497
	styles.Fonts = [];
8498
	var state = [];
8499
	var pass = false;
8500
	recordhopper(data, function hopper_sty(val, R_n, RT) {
8501
		switch(RT) {
8502
			case 0x002C: /* 'BrtFmt' */
8503
				styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]);
8504
				break;
8505
			case 0x002B: /* 'BrtFont' */
8506
				styles.Fonts.push(val);
8507
				if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) {
8508
					val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0);
8509
				}
8510
				break;
8511
			case 0x0401: /* 'BrtKnownFonts' */ break;
8512
			case 0x002D: /* 'BrtFill' */ break;
8513
			case 0x002E: /* 'BrtBorder' */ break;
8514
			case 0x002F: /* 'BrtXF' */
8515
				if(state[state.length - 1] == "BrtBeginCellXFs") {
8516
					styles.CellXf.push(val);
8517
				}
8518
				break;
8519
			case 0x0030: /* 'BrtStyle' */
8520
			case 0x01FB: /* 'BrtDXF' */
8521
			case 0x023C: /* 'BrtMRUColor' */
8522
			case 0x01DB: /* 'BrtIndexedColor': */
8523
				break;
8524
8525
			case 0x0493: /* 'BrtDXF14' */
8526
			case 0x0836: /* 'BrtDXF15' */
8527
			case 0x046A: /* 'BrtSlicerStyleElement' */
8528
			case 0x0200: /* 'BrtTableStyleElement' */
8529
			case 0x082F: /* 'BrtTimelineStyleElement' */
8530
			case 0x0C00: /* 'BrtUid' */
8531
				break;
8532
8533
			case 0x0023: /* 'BrtFRTBegin' */
8534
				pass = true; break;
8535
			case 0x0024: /* 'BrtFRTEnd' */
8536
				pass = false; break;
8537
			case 0x0025: /* 'BrtACBegin' */
8538
				state.push(R_n); break;
8539
			case 0x0026: /* 'BrtACEnd' */
8540
				state.pop(); break;
8541
8542
			default:
8543
				if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
8544
				else if((R_n||"").indexOf("End") > 0) state.pop();
8545
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
8546
		}
8547
	});
8548
	return styles;
8549
}
8550
8551
function write_FMTS_bin(ba, NF) {
8552
	if(!NF) return;
8553
	var cnt = 0;
8554
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8555
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
8556
	});
8557
8558
	if(cnt == 0) return;
8559
	write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
8560
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8561
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
8562
	});
8563
	write_record(ba, "BrtEndFmts");
8564
}
8565
8566
function write_FONTS_bin(ba) {
8567
	var cnt = 1;
8568
8569
	if(cnt == 0) return;
8570
	write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt));
8571
	write_record(ba, "BrtFont", write_BrtFont({
8572
		sz:12,
8573
		color: {theme:1},
8574
		name: "Calibri",
8575
		family: 2,
8576
		scheme: "minor"
8577
	}));
8578
	/* 1*65491BrtFont [ACFONTS] */
8579
	write_record(ba, "BrtEndFonts");
8580
}
8581
8582
function write_FILLS_bin(ba) {
8583
	var cnt = 2;
8584
8585
	if(cnt == 0) return;
8586
	write_record(ba, "BrtBeginFills", write_UInt32LE(cnt));
8587
	write_record(ba, "BrtFill", write_BrtFill({patternType:"none"}));
8588
	write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"}));
8589
	/* 1*65431BrtFill */
8590
	write_record(ba, "BrtEndFills");
8591
}
8592
8593
function write_BORDERS_bin(ba) {
8594
	var cnt = 1;
8595
8596
	if(cnt == 0) return;
8597
	write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt));
8598
	write_record(ba, "BrtBorder", write_BrtBorder({}));
8599
	/* 1*65430BrtBorder */
8600
	write_record(ba, "BrtEndBorders");
8601
}
8602
8603
function write_CELLSTYLEXFS_bin(ba) {
8604
	var cnt = 1;
8605
	write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
8606
	write_record(ba, "BrtXF", write_BrtXF({
8607
		numFmtId:0,
8608
		fontId:0,
8609
		fillId:0,
8610
		borderId:0
8611
	}, 0xFFFF));
8612
	/* 1*65430(BrtXF *FRT) */
8613
	write_record(ba, "BrtEndCellStyleXFs");
8614
}
8615
8616
function write_CELLXFS_bin(ba, data) {
8617
	write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length));
8618
	data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); });
8619
	/* 1*65430(BrtXF *FRT) */
8620
	write_record(ba, "BrtEndCellXFs");
8621
}
8622
8623
function write_STYLES_bin(ba) {
8624
	var cnt = 1;
8625
8626
	write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt));
8627
	write_record(ba, "BrtStyle", write_BrtStyle({
8628
		xfId:0,
8629
		builtinId:0,
8630
		name:"Normal"
8631
	}));
8632
	/* 1*65430(BrtStyle *FRT) */
8633
	write_record(ba, "BrtEndStyles");
8634
}
8635
8636
function write_DXFS_bin(ba) {
8637
	var cnt = 0;
8638
8639
	write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
8640
	/* *2147483647(BrtDXF *FRT) */
8641
	write_record(ba, "BrtEndDXFs");
8642
}
8643
8644
function write_TABLESTYLES_bin(ba) {
8645
	var cnt = 0;
8646
8647
	write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
8648
	/* *TABLESTYLE */
8649
	write_record(ba, "BrtEndTableStyles");
8650
}
8651
8652
function write_COLORPALETTE_bin() {
8653
	return;
8654
	/* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
8655
}
8656
8657
/* [MS-XLSB] 2.1.7.50 Styles */
8658
function write_sty_bin(wb, opts) {
8659
	var ba = buf_array();
8660
	write_record(ba, "BrtBeginStyleSheet");
8661
	write_FMTS_bin(ba, wb.SSF);
8662
	write_FONTS_bin(ba, wb);
8663
	write_FILLS_bin(ba, wb);
8664
	write_BORDERS_bin(ba, wb);
8665
	write_CELLSTYLEXFS_bin(ba, wb);
8666
	write_CELLXFS_bin(ba, opts.cellXfs);
8667
	write_STYLES_bin(ba, wb);
8668
	write_DXFS_bin(ba, wb);
8669
	write_TABLESTYLES_bin(ba, wb);
8670
	write_COLORPALETTE_bin(ba, wb);
8671
	/* FRTSTYLESHEET*/
8672
	write_record(ba, "BrtEndStyleSheet");
8673
	return ba.end();
8674
}
8675
RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
8676
8677
/* 20.1.6.2 clrScheme CT_ColorScheme */
8678
function parse_clrScheme(t, themes, opts) {
8679
	themes.themeElements.clrScheme = [];
8680
	var color = {};
8681
	(t[0].match(tagregex)||[]).forEach(function(x) {
8682
		var y = parsexmltag(x);
8683
		switch(y[0]) {
8684
			/* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
8685
			case '<a:clrScheme': case '</a:clrScheme>': break;
8686
8687
			/* 20.1.2.3.32 srgbClr CT_SRgbColor */
8688
			case '<a:srgbClr':
8689
				color.rgb = y.val; break;
8690
8691
			/* 20.1.2.3.33 sysClr CT_SystemColor */
8692
			case '<a:sysClr':
8693
				color.rgb = y.lastClr; break;
8694
8695
			/* 20.1.4.1.1 accent1 (Accent 1) */
8696
			/* 20.1.4.1.2 accent2 (Accent 2) */
8697
			/* 20.1.4.1.3 accent3 (Accent 3) */
8698
			/* 20.1.4.1.4 accent4 (Accent 4) */
8699
			/* 20.1.4.1.5 accent5 (Accent 5) */
8700
			/* 20.1.4.1.6 accent6 (Accent 6) */
8701
			/* 20.1.4.1.9 dk1 (Dark 1) */
8702
			/* 20.1.4.1.10 dk2 (Dark 2) */
8703
			/* 20.1.4.1.15 folHlink (Followed Hyperlink) */
8704
			/* 20.1.4.1.19 hlink (Hyperlink) */
8705
			/* 20.1.4.1.22 lt1 (Light 1) */
8706
			/* 20.1.4.1.23 lt2 (Light 2) */
8707
			case '<a:dk1>': case '</a:dk1>':
8708
			case '<a:lt1>': case '</a:lt1>':
8709
			case '<a:dk2>': case '</a:dk2>':
8710
			case '<a:lt2>': case '</a:lt2>':
8711
			case '<a:accent1>': case '</a:accent1>':
8712
			case '<a:accent2>': case '</a:accent2>':
8713
			case '<a:accent3>': case '</a:accent3>':
8714
			case '<a:accent4>': case '</a:accent4>':
8715
			case '<a:accent5>': case '</a:accent5>':
8716
			case '<a:accent6>': case '</a:accent6>':
8717
			case '<a:hlink>': case '</a:hlink>':
8718
			case '<a:folHlink>': case '</a:folHlink>':
8719
				if (y[0].charAt(1) === '/') {
8720
					themes.themeElements.clrScheme.push(color);
8721
					color = {};
8722
				} else {
8723
					color.name = y[0].slice(3, y[0].length - 1);
8724
				}
8725
				break;
8726
8727
			default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
8728
		}
8729
	});
8730
}
8731
8732
/* 20.1.4.1.18 fontScheme CT_FontScheme */
8733
function parse_fontScheme() { }
8734
8735
/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
8736
function parse_fmtScheme() { }
8737
8738
var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
8739
var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
8740
var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
8741
8742
/* 20.1.6.10 themeElements CT_BaseStyles */
8743
function parse_themeElements(data, themes, opts) {
8744
	themes.themeElements = {};
8745
8746
	var t;
8747
8748
	[
8749
		/* clrScheme CT_ColorScheme */
8750
		['clrScheme', clrsregex, parse_clrScheme],
8751
		/* fontScheme CT_FontScheme */
8752
		['fontScheme', fntsregex, parse_fontScheme],
8753
		/* fmtScheme CT_StyleMatrix */
8754
		['fmtScheme', fmtsregex, parse_fmtScheme]
8755
	].forEach(function(m) {
8756
		if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
8757
		m[2](t, themes, opts);
8758
	});
8759
}
8760
8761
var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
8762
8763
/* 14.2.7 Theme Part */
8764
function parse_theme_xml(data, opts) {
8765
	/* 20.1.6.9 theme CT_OfficeStyleSheet */
8766
	if(!data || data.length === 0) return parse_theme_xml(write_theme());
8767
8768
	var t;
8769
	var themes = {};
8770
8771
	/* themeElements CT_BaseStyles */
8772
	if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
8773
	parse_themeElements(t[0], themes, opts);
8774
8775
	return themes;
8776
}
8777
8778
function write_theme(Themes, opts) {
8779
	if(opts && opts.themeXLSX) return opts.themeXLSX;
8780
	var o = [XML_HEADER];
8781
	o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
8782
	o[o.length] =  '<a:themeElements>';
8783
8784
	o[o.length] =   '<a:clrScheme name="Office">';
8785
	o[o.length] =    '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
8786
	o[o.length] =    '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
8787
	o[o.length] =    '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
8788
	o[o.length] =    '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
8789
	o[o.length] =    '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
8790
	o[o.length] =    '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
8791
	o[o.length] =    '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
8792
	o[o.length] =    '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
8793
	o[o.length] =    '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
8794
	o[o.length] =    '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
8795
	o[o.length] =    '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
8796
	o[o.length] =    '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
8797
	o[o.length] =   '</a:clrScheme>';
8798
8799
	o[o.length] =   '<a:fontScheme name="Office">';
8800
	o[o.length] =    '<a:majorFont>';
8801
	o[o.length] =     '<a:latin typeface="Cambria"/>';
8802
	o[o.length] =     '<a:ea typeface=""/>';
8803
	o[o.length] =     '<a:cs typeface=""/>';
8804
	o[o.length] =     '<a:font script="Jpan" typeface="MS Pゴシック"/>';
8805
	o[o.length] =     '<a:font script="Hang" typeface="맑은 고딕"/>';
8806
	o[o.length] =     '<a:font script="Hans" typeface="宋体"/>';
8807
	o[o.length] =     '<a:font script="Hant" typeface="新細明體"/>';
8808
	o[o.length] =     '<a:font script="Arab" typeface="Times New Roman"/>';
8809
	o[o.length] =     '<a:font script="Hebr" typeface="Times New Roman"/>';
8810
	o[o.length] =     '<a:font script="Thai" typeface="Tahoma"/>';
8811
	o[o.length] =     '<a:font script="Ethi" typeface="Nyala"/>';
8812
	o[o.length] =     '<a:font script="Beng" typeface="Vrinda"/>';
8813
	o[o.length] =     '<a:font script="Gujr" typeface="Shruti"/>';
8814
	o[o.length] =     '<a:font script="Khmr" typeface="MoolBoran"/>';
8815
	o[o.length] =     '<a:font script="Knda" typeface="Tunga"/>';
8816
	o[o.length] =     '<a:font script="Guru" typeface="Raavi"/>';
8817
	o[o.length] =     '<a:font script="Cans" typeface="Euphemia"/>';
8818
	o[o.length] =     '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
8819
	o[o.length] =     '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
8820
	o[o.length] =     '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
8821
	o[o.length] =     '<a:font script="Thaa" typeface="MV Boli"/>';
8822
	o[o.length] =     '<a:font script="Deva" typeface="Mangal"/>';
8823
	o[o.length] =     '<a:font script="Telu" typeface="Gautami"/>';
8824
	o[o.length] =     '<a:font script="Taml" typeface="Latha"/>';
8825
	o[o.length] =     '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
8826
	o[o.length] =     '<a:font script="Orya" typeface="Kalinga"/>';
8827
	o[o.length] =     '<a:font script="Mlym" typeface="Kartika"/>';
8828
	o[o.length] =     '<a:font script="Laoo" typeface="DokChampa"/>';
8829
	o[o.length] =     '<a:font script="Sinh" typeface="Iskoola Pota"/>';
8830
	o[o.length] =     '<a:font script="Mong" typeface="Mongolian Baiti"/>';
8831
	o[o.length] =     '<a:font script="Viet" typeface="Times New Roman"/>';
8832
	o[o.length] =     '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
8833
	o[o.length] =     '<a:font script="Geor" typeface="Sylfaen"/>';
8834
	o[o.length] =    '</a:majorFont>';
8835
	o[o.length] =    '<a:minorFont>';
8836
	o[o.length] =     '<a:latin typeface="Calibri"/>';
8837
	o[o.length] =     '<a:ea typeface=""/>';
8838
	o[o.length] =     '<a:cs typeface=""/>';
8839
	o[o.length] =     '<a:font script="Jpan" typeface="MS Pゴシック"/>';
8840
	o[o.length] =     '<a:font script="Hang" typeface="맑은 고딕"/>';
8841
	o[o.length] =     '<a:font script="Hans" typeface="宋体"/>';
8842
	o[o.length] =     '<a:font script="Hant" typeface="新細明體"/>';
8843
	o[o.length] =     '<a:font script="Arab" typeface="Arial"/>';
8844
	o[o.length] =     '<a:font script="Hebr" typeface="Arial"/>';
8845
	o[o.length] =     '<a:font script="Thai" typeface="Tahoma"/>';
8846
	o[o.length] =     '<a:font script="Ethi" typeface="Nyala"/>';
8847
	o[o.length] =     '<a:font script="Beng" typeface="Vrinda"/>';
8848
	o[o.length] =     '<a:font script="Gujr" typeface="Shruti"/>';
8849
	o[o.length] =     '<a:font script="Khmr" typeface="DaunPenh"/>';
8850
	o[o.length] =     '<a:font script="Knda" typeface="Tunga"/>';
8851
	o[o.length] =     '<a:font script="Guru" typeface="Raavi"/>';
8852
	o[o.length] =     '<a:font script="Cans" typeface="Euphemia"/>';
8853
	o[o.length] =     '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
8854
	o[o.length] =     '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
8855
	o[o.length] =     '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
8856
	o[o.length] =     '<a:font script="Thaa" typeface="MV Boli"/>';
8857
	o[o.length] =     '<a:font script="Deva" typeface="Mangal"/>';
8858
	o[o.length] =     '<a:font script="Telu" typeface="Gautami"/>';
8859
	o[o.length] =     '<a:font script="Taml" typeface="Latha"/>';
8860
	o[o.length] =     '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
8861
	o[o.length] =     '<a:font script="Orya" typeface="Kalinga"/>';
8862
	o[o.length] =     '<a:font script="Mlym" typeface="Kartika"/>';
8863
	o[o.length] =     '<a:font script="Laoo" typeface="DokChampa"/>';
8864
	o[o.length] =     '<a:font script="Sinh" typeface="Iskoola Pota"/>';
8865
	o[o.length] =     '<a:font script="Mong" typeface="Mongolian Baiti"/>';
8866
	o[o.length] =     '<a:font script="Viet" typeface="Arial"/>';
8867
	o[o.length] =     '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
8868
	o[o.length] =     '<a:font script="Geor" typeface="Sylfaen"/>';
8869
	o[o.length] =    '</a:minorFont>';
8870
	o[o.length] =   '</a:fontScheme>';
8871
8872
	o[o.length] =   '<a:fmtScheme name="Office">';
8873
	o[o.length] =    '<a:fillStyleLst>';
8874
	o[o.length] =     '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
8875
	o[o.length] =     '<a:gradFill rotWithShape="1">';
8876
	o[o.length] =      '<a:gsLst>';
8877
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
8878
	o[o.length] =       '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
8879
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
8880
	o[o.length] =      '</a:gsLst>';
8881
	o[o.length] =      '<a:lin ang="16200000" scaled="1"/>';
8882
	o[o.length] =     '</a:gradFill>';
8883
	o[o.length] =     '<a:gradFill rotWithShape="1">';
8884
	o[o.length] =      '<a:gsLst>';
8885
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="100000"/><a:shade val="100000"/><a:satMod val="130000"/></a:schemeClr></a:gs>';
8886
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="50000"/><a:shade val="100000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
8887
	o[o.length] =      '</a:gsLst>';
8888
	o[o.length] =      '<a:lin ang="16200000" scaled="0"/>';
8889
	o[o.length] =     '</a:gradFill>';
8890
	o[o.length] =    '</a:fillStyleLst>';
8891
	o[o.length] =    '<a:lnStyleLst>';
8892
	o[o.length] =     '<a:ln w="9525" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"><a:shade val="95000"/><a:satMod val="105000"/></a:schemeClr></a:solidFill><a:prstDash val="solid"/></a:ln>';
8893
	o[o.length] =     '<a:ln w="25400" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>';
8894
	o[o.length] =     '<a:ln w="38100" cap="flat" cmpd="sng" algn="ctr"><a:solidFill><a:schemeClr val="phClr"/></a:solidFill><a:prstDash val="solid"/></a:ln>';
8895
	o[o.length] =    '</a:lnStyleLst>';
8896
	o[o.length] =    '<a:effectStyleLst>';
8897
	o[o.length] =     '<a:effectStyle>';
8898
	o[o.length] =      '<a:effectLst>';
8899
	o[o.length] =       '<a:outerShdw blurRad="40000" dist="20000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="38000"/></a:srgbClr></a:outerShdw>';
8900
	o[o.length] =      '</a:effectLst>';
8901
	o[o.length] =     '</a:effectStyle>';
8902
	o[o.length] =     '<a:effectStyle>';
8903
	o[o.length] =      '<a:effectLst>';
8904
	o[o.length] =       '<a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw>';
8905
	o[o.length] =      '</a:effectLst>';
8906
	o[o.length] =     '</a:effectStyle>';
8907
	o[o.length] =     '<a:effectStyle>';
8908
	o[o.length] =      '<a:effectLst>';
8909
	o[o.length] =       '<a:outerShdw blurRad="40000" dist="23000" dir="5400000" rotWithShape="0"><a:srgbClr val="000000"><a:alpha val="35000"/></a:srgbClr></a:outerShdw>';
8910
	o[o.length] =      '</a:effectLst>';
8911
	o[o.length] =      '<a:scene3d><a:camera prst="orthographicFront"><a:rot lat="0" lon="0" rev="0"/></a:camera><a:lightRig rig="threePt" dir="t"><a:rot lat="0" lon="0" rev="1200000"/></a:lightRig></a:scene3d>';
8912
	o[o.length] =      '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
8913
	o[o.length] =     '</a:effectStyle>';
8914
	o[o.length] =    '</a:effectStyleLst>';
8915
	o[o.length] =    '<a:bgFillStyleLst>';
8916
	o[o.length] =     '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
8917
	o[o.length] =     '<a:gradFill rotWithShape="1">';
8918
	o[o.length] =      '<a:gsLst>';
8919
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
8920
	o[o.length] =       '<a:gs pos="40000"><a:schemeClr val="phClr"><a:tint val="45000"/><a:shade val="99000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
8921
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
8922
	o[o.length] =      '</a:gsLst>';
8923
	o[o.length] =      '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
8924
	o[o.length] =     '</a:gradFill>';
8925
	o[o.length] =     '<a:gradFill rotWithShape="1">';
8926
	o[o.length] =      '<a:gsLst>';
8927
	o[o.length] =       '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
8928
	o[o.length] =       '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
8929
	o[o.length] =      '</a:gsLst>';
8930
	o[o.length] =      '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
8931
	o[o.length] =     '</a:gradFill>';
8932
	o[o.length] =    '</a:bgFillStyleLst>';
8933
	o[o.length] =   '</a:fmtScheme>';
8934
	o[o.length] =  '</a:themeElements>';
8935
8936
	o[o.length] =  '<a:objectDefaults>';
8937
	o[o.length] =   '<a:spDef>';
8938
	o[o.length] =    '<a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="1"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="3"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="2"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="lt1"/></a:fontRef></a:style>';
8939
	o[o.length] =   '</a:spDef>';
8940
	o[o.length] =   '<a:lnDef>';
8941
	o[o.length] =    '<a:spPr/><a:bodyPr/><a:lstStyle/><a:style><a:lnRef idx="2"><a:schemeClr val="accent1"/></a:lnRef><a:fillRef idx="0"><a:schemeClr val="accent1"/></a:fillRef><a:effectRef idx="1"><a:schemeClr val="accent1"/></a:effectRef><a:fontRef idx="minor"><a:schemeClr val="tx1"/></a:fontRef></a:style>';
8942
	o[o.length] =   '</a:lnDef>';
8943
	o[o.length] =  '</a:objectDefaults>';
8944
	o[o.length] =  '<a:extraClrSchemeLst/>';
8945
	o[o.length] = '</a:theme>';
8946
	return o.join("");
8947
}
8948
/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
8949
function parse_Theme(blob, length, opts) {
8950
	var end = blob.l + length;
8951
	var dwThemeVersion = blob.read_shift(4);
8952
	if(dwThemeVersion === 124226) return;
8953
	if(!opts.cellStyles || !jszip) { blob.l = end; return; }
8954
	var data = blob.slice(blob.l);
8955
	blob.l = end;
8956
	var zip; try { zip = new jszip(data); } catch(e) { return; }
8957
	var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true);
8958
	if(!themeXML) return;
8959
	return parse_theme_xml(themeXML, opts);
8960
}
8961
8962
/* 2.5.49 */
8963
function parse_ColorTheme(blob) { return blob.read_shift(4); }
8964
8965
/* 2.5.155 */
8966
function parse_FullColorExt(blob) {
8967
	var o = {};
8968
	o.xclrType = blob.read_shift(2);
8969
	o.nTintShade = blob.read_shift(2);
8970
	switch(o.xclrType) {
8971
		case 0: blob.l += 4; break;
8972
		case 1: o.xclrValue = parse_IcvXF(blob, 4); break;
8973
		case 2: o.xclrValue = parse_LongRGBA(blob, 4); break;
8974
		case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
8975
		case 4: blob.l += 4; break;
8976
	}
8977
	blob.l += 8;
8978
	return o;
8979
}
8980
8981
/* 2.5.164 TODO: read 7 bits*/
8982
function parse_IcvXF(blob, length) {
8983
	return parsenoop(blob, length);
8984
}
8985
8986
/* 2.5.280 */
8987
function parse_XFExtGradient(blob, length) {
8988
	return parsenoop(blob, length);
8989
}
8990
8991
/* [MS-XLS] 2.5.108 */
8992
function parse_ExtProp(blob) {
8993
	var extType = blob.read_shift(2);
8994
	var cb = blob.read_shift(2) - 4;
8995
	var o = [extType];
8996
	switch(extType) {
8997
		case 0x04: case 0x05: case 0x07: case 0x08:
8998
		case 0x09: case 0x0A: case 0x0B: case 0x0D:
8999
			o[1] = parse_FullColorExt(blob, cb); break;
9000
		case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
9001
		case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
9002
		default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
9003
	}
9004
	return o;
9005
}
9006
9007
/* 2.4.355 */
9008
function parse_XFExt(blob, length) {
9009
	var end = blob.l + length;
9010
	blob.l += 2;
9011
	var ixfe = blob.read_shift(2);
9012
	blob.l += 2;
9013
	var cexts = blob.read_shift(2);
9014
	var ext = [];
9015
	while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
9016
	return {ixfe:ixfe, ext:ext};
9017
}
9018
9019
/* xf is an XF, see parse_XFExt for xfext */
9020
function update_xfext(xf, xfext) {
9021
	xfext.forEach(function(xfe) {
9022
		switch(xfe[0]) { /* 2.5.108 extPropData */
9023
			case 0x04: break; /* foreground color */
9024
			case 0x05: break; /* background color */
9025
			case 0x06: break; /* gradient fill */
9026
			case 0x07: break; /* top cell border color */
9027
			case 0x08: break; /* bottom cell border color */
9028
			case 0x09: break; /* left cell border color */
9029
			case 0x0a: break; /* right cell border color */
9030
			case 0x0b: break; /* diagonal cell border color */
9031
			case 0x0d: break; /* text color */
9032
			case 0x0e: break; /* font scheme */
9033
			case 0x0f: break; /* indentation level */
9034
		}
9035
	});
9036
}
9037
9038
/* 18.6 Calculation Chain */
9039
function parse_cc_xml(data) {
9040
	var d = [];
9041
	if(!data) return d;
9042
	var i = 1;
9043
	(data.match(tagregex)||[]).forEach(function(x) {
9044
		var y = parsexmltag(x);
9045
		switch(y[0]) {
9046
			case '<?xml': break;
9047
			/* 18.6.2  calcChain CT_CalcChain 1 */
9048
			case '<calcChain': case '<calcChain>': case '</calcChain>': break;
9049
			/* 18.6.1  c CT_CalcCell 1 */
9050
			case '<c': delete y[0]; if(y.i) i = y.i; else y.i = i; d.push(y); break;
9051
		}
9052
	});
9053
	return d;
9054
}
9055
9056
//function write_cc_xml(data, opts) { }
9057
9058
/* [MS-XLSB] 2.6.4.1 */
9059
function parse_BrtCalcChainItem$(data) {
9060
	var out = {};
9061
	out.i = data.read_shift(4);
9062
	var cell = {};
9063
	cell.r = data.read_shift(4);
9064
	cell.c = data.read_shift(4);
9065
	out.r = encode_cell(cell);
9066
	var flags = data.read_shift(1);
9067
	if(flags & 0x2) out.l = '1';
9068
	if(flags & 0x8) out.a = '1';
9069
	return out;
9070
}
9071
9072
/* 18.6 Calculation Chain */
9073
function parse_cc_bin(data, name, opts) {
9074
	var out = [];
9075
	var pass = false;
9076
	recordhopper(data, function hopper_cc(val, R_n, RT) {
9077
		switch(RT) {
9078
			case 0x003F: /* 'BrtCalcChainItem$' */
9079
				out.push(val); break;
9080
9081
			default:
9082
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
9083
				else if((R_n||"").indexOf("End") > 0){/* empty */}
9084
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9085
		}
9086
	});
9087
	return out;
9088
}
9089
9090
//function write_cc_bin(data, opts) { }
9091
/* 18.14 Supplementary Workbook Data */
9092
function parse_xlink_xml() {
9093
	//var opts = _opts || {};
9094
	//if(opts.WTF) throw "XLSX External Link";
9095
}
9096
9097
/* [MS-XLSB] 2.1.7.25 External Link */
9098
function parse_xlink_bin(data, name, _opts) {
9099
	if(!data) return data;
9100
	var opts = _opts || {};
9101
9102
	var pass = false, end = false;
9103
9104
	recordhopper(data, function xlink_parse(val, R_n, RT) {
9105
		if(end) return;
9106
		switch(RT) {
9107
			case 0x0167: /* 'BrtSupTabs' */
9108
			case 0x016B: /* 'BrtExternTableStart' */
9109
			case 0x016C: /* 'BrtExternTableEnd' */
9110
			case 0x016E: /* 'BrtExternRowHdr' */
9111
			case 0x016F: /* 'BrtExternCellBlank' */
9112
			case 0x0170: /* 'BrtExternCellReal' */
9113
			case 0x0171: /* 'BrtExternCellBool' */
9114
			case 0x0172: /* 'BrtExternCellError' */
9115
			case 0x0173: /* 'BrtExternCellString' */
9116
			case 0x01D8: /* 'BrtExternValueMeta' */
9117
			case 0x0241: /* 'BrtSupNameStart' */
9118
			case 0x0242: /* 'BrtSupNameValueStart' */
9119
			case 0x0243: /* 'BrtSupNameValueEnd' */
9120
			case 0x0244: /* 'BrtSupNameNum' */
9121
			case 0x0245: /* 'BrtSupNameErr' */
9122
			case 0x0246: /* 'BrtSupNameSt' */
9123
			case 0x0247: /* 'BrtSupNameNil' */
9124
			case 0x0248: /* 'BrtSupNameBool' */
9125
			case 0x0249: /* 'BrtSupNameFmla' */
9126
			case 0x024A: /* 'BrtSupNameBits' */
9127
			case 0x024B: /* 'BrtSupNameEnd' */
9128
				break;
9129
9130
			case 0x0023: /* 'BrtFRTBegin' */
9131
				pass = true; break;
9132
			case 0x0024: /* 'BrtFRTEnd' */
9133
				pass = false; break;
9134
9135
			default:
9136
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
9137
				else if((R_n||"").indexOf("End") > 0){/* empty */}
9138
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
9139
		}
9140
	}, opts);
9141
}
9142
RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
9143
RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
9144
/* 20.5 DrawingML - SpreadsheetML Drawing */
9145
function parse_drawing(data, rels) {
9146
	if(!data) return "??";
9147
	/*
9148
	  Chartsheet Drawing:
9149
	   - 20.5.2.35 wsDr CT_Drawing
9150
	    - 20.5.2.1  absoluteAnchor CT_AbsoluteAnchor
9151
	     - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
9152
	      - 20.1.2.2.16 graphic CT_GraphicalObject
9153
	       - 20.1.2.2.17 graphicData CT_GraphicalObjectData
9154
          - chart reference
9155
	   the actual type is based on the URI of the graphicData
9156
		TODO: handle embedded charts and other types of graphics
9157
	*/
9158
	var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
9159
9160
	return rels['!id'][id].Target;
9161
}
9162
9163
/* L.5.5.2 SpreadsheetML Comments + VML Schema */
9164
var _shapeid = 1024;
9165
function write_comments_vml(rId, comments) {
9166
	var csize = [21600, 21600];
9167
	/* L.5.2.1.2 Path Attribute */
9168
	var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
9169
	var o = [
9170
		writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
9171
		writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
9172
		writextag("v:shapetype", [
9173
			writextag("v:stroke", null, {joinstyle:"miter"}),
9174
			writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
9175
		].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
9176
	];
9177
	while(_shapeid < rId * 1000) _shapeid += 1000;
9178
9179
	comments.forEach(function(x) { var c = decode_cell(x[0]);
9180
	o = o.concat([
9181
	'<v:shape' + wxt_helper({
9182
		id:'_x0000_s' + (++_shapeid),
9183
		type:"#_x0000_t202",
9184
		style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
9185
		fillcolor:"#ECFAD4",
9186
		strokecolor:"#edeaa1"
9187
	}) + '>',
9188
		writextag('v:fill', writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}), {'color2':"#BEFF82", 'angle':"-180", 'type':"gradient"}),
9189
		writextag("v:shadow", null, {on:"t", 'obscured':"t"}),
9190
		writextag("v:path", null, {'o:connecttype':"none"}),
9191
		'<v:textbox><div style="text-align:left"></div></v:textbox>',
9192
		'<x:ClientData ObjectType="Note">',
9193
			'<x:MoveWithCells/>',
9194
			'<x:SizeWithCells/>',
9195
			/* Part 4 19.4.2.3 Anchor (Anchor) */
9196
			writetag('x:Anchor', [c.c, 0, c.r, 0, c.c+3, 100, c.r+5, 100].join(",")),
9197
			writetag('x:AutoFill', "False"),
9198
			writetag('x:Row', String(c.r)),
9199
			writetag('x:Column', String(c.c)),
9200
			x[1].hidden ? '' : '<x:Visible/>',
9201
		'</x:ClientData>',
9202
	'</v:shape>'
9203
	]); });
9204
	o.push('</xml>');
9205
	return o.join("");
9206
}
9207
9208
RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
9209
9210
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
9211
	for(var i = 0; i != dirComments.length; ++i) {
9212
		var canonicalpath=dirComments[i];
9213
		var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
9214
		if(!comments || !comments.length) continue;
9215
		// find the sheets targeted by these comments
9216
		var sheetNames = keys(sheets);
9217
		for(var j = 0; j != sheetNames.length; ++j) {
9218
			var sheetName = sheetNames[j];
9219
			var rels = sheetRels[sheetName];
9220
			if(rels) {
9221
				var rel = rels[canonicalpath];
9222
				if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
9223
			}
9224
		}
9225
	}
9226
}
9227
9228
function insertCommentsIntoSheet(sheetName, sheet, comments) {
9229
	var dense = Array.isArray(sheet);
9230
	var cell, r;
9231
	comments.forEach(function(comment) {
9232
		if(dense) {
9233
			r = decode_cell(comment.ref);
9234
			if(!sheet[r.r]) sheet[r.r] = [];
9235
			cell = sheet[r.r][r.c];
9236
		} else cell = sheet[comment.ref];
9237
		if (!cell) {
9238
			cell = {};
9239
			if(dense) sheet[r.r][r.c] = cell;
9240
			else sheet[comment.ref] = cell;
9241
			var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
9242
			var thisCell = decode_cell(comment.ref);
9243
			if(range.s.r > thisCell.r) range.s.r = thisCell.r;
9244
			if(range.e.r < thisCell.r) range.e.r = thisCell.r;
9245
			if(range.s.c > thisCell.c) range.s.c = thisCell.c;
9246
			if(range.e.c < thisCell.c) range.e.c = thisCell.c;
9247
			var encoded = encode_range(range);
9248
			if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
9249
		}
9250
9251
		if (!cell.c) cell.c = [];
9252
		var o = ({a: comment.author, t: comment.t, r: comment.r});
9253
		if(comment.h) o.h = comment.h;
9254
		cell.c.push(o);
9255
	});
9256
}
9257
9258
/* 18.7 Comments */
9259
function parse_comments_xml(data, opts) {
9260
	/* 18.7.6 CT_Comments */
9261
	if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
9262
	var authors = [];
9263
	var commentList = [];
9264
	var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
9265
	if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
9266
		if(x === "" || x.trim() === "") return;
9267
		var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
9268
		if(a) authors.push(a[1]);
9269
	});
9270
	var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
9271
	if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
9272
		if(x === "" || x.trim() === "") return;
9273
		var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
9274
		if(!cm) return;
9275
		var y = parsexmltag(cm[0]);
9276
		var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
9277
		var cell = decode_cell(y.ref);
9278
		if(opts.sheetRows && opts.sheetRows <= cell.r) return;
9279
		var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
9280
		var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
9281
		comment.r = rt.r;
9282
		if(rt.r == "<t></t>") rt.t = rt.h = "";
9283
		comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
9284
		if(opts.cellHTML) comment.h = rt.h;
9285
		commentList.push(comment);
9286
	});
9287
	return commentList;
9288
}
9289
9290
var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
9291
function write_comments_xml(data) {
9292
	var o = [XML_HEADER, CMNT_XML_ROOT];
9293
9294
	var iauthor = [];
9295
	o.push("<authors>");
9296
	data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
9297
		if(iauthor.indexOf(a) > -1) return;
9298
		iauthor.push(a);
9299
		o.push("<author>" + a + "</author>");
9300
	}); });
9301
	o.push("</authors>");
9302
	o.push("<commentList>");
9303
	data.forEach(function(d) {
9304
		d[1].forEach(function(c) {
9305
			/* 18.7.3 CT_Comment */
9306
			o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
9307
			o.push(writetag("t", c.t == null ? "" : c.t));
9308
			o.push('</text></comment>');
9309
		});
9310
	});
9311
	o.push("</commentList>");
9312
	if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
9313
	return o.join("");
9314
}
9315
/* [MS-XLSB] 2.4.28 BrtBeginComment */
9316
function parse_BrtBeginComment(data) {
9317
	var out = {};
9318
	out.iauthor = data.read_shift(4);
9319
	var rfx = parse_UncheckedRfX(data, 16);
9320
	out.rfx = rfx.s;
9321
	out.ref = encode_cell(rfx.s);
9322
	data.l += 16; /*var guid = parse_GUID(data); */
9323
	return out;
9324
}
9325
function write_BrtBeginComment(data, o) {
9326
	if(o == null) o = new_buf(36);
9327
	o.write_shift(4, data[1].iauthor);
9328
	write_UncheckedRfX((data[0]), o);
9329
	o.write_shift(4, 0);
9330
	o.write_shift(4, 0);
9331
	o.write_shift(4, 0);
9332
	o.write_shift(4, 0);
9333
	return o;
9334
}
9335
9336
/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
9337
var parse_BrtCommentAuthor = parse_XLWideString;
9338
function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
9339
9340
/* [MS-XLSB] 2.1.7.8 Comments */
9341
function parse_comments_bin(data, opts) {
9342
	var out = [];
9343
	var authors = [];
9344
	var c = {};
9345
	var pass = false;
9346
	recordhopper(data, function hopper_cmnt(val, R_n, RT) {
9347
		switch(RT) {
9348
			case 0x0278: /* 'BrtCommentAuthor' */
9349
				authors.push(val); break;
9350
			case 0x027B: /* 'BrtBeginComment' */
9351
				c = val; break;
9352
			case 0x027D: /* 'BrtCommentText' */
9353
				c.t = val.t; c.h = val.h; c.r = val.r; break;
9354
			case 0x027C: /* 'BrtEndComment' */
9355
				c.author = authors[c.iauthor];
9356
				delete c.iauthor;
9357
				if(opts.sheetRows && opts.sheetRows <= c.rfx.r) break;
9358
				if(!c.t) c.t = "";
9359
				delete c.rfx; out.push(c); break;
9360
9361
			case 0x0C00: /* 'BrtUid' */
9362
				break;
9363
9364
			case 0x0023: /* 'BrtFRTBegin' */
9365
				pass = true; break;
9366
			case 0x0024: /* 'BrtFRTEnd' */
9367
				pass = false; break;
9368
			case 0x0025: /* 'BrtACBegin' */ break;
9369
			case 0x0026: /* 'BrtACEnd' */ break;
9370
9371
9372
			default:
9373
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
9374
				else if((R_n||"").indexOf("End") > 0){/* empty */}
9375
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9376
		}
9377
	});
9378
	return out;
9379
}
9380
9381
function write_comments_bin(data) {
9382
	var ba = buf_array();
9383
	var iauthor = [];
9384
	write_record(ba, "BrtBeginComments");
9385
9386
	write_record(ba, "BrtBeginCommentAuthors");
9387
	data.forEach(function(comment) {
9388
		comment[1].forEach(function(c) {
9389
			if(iauthor.indexOf(c.a) > -1) return;
9390
			iauthor.push(c.a.slice(0,54));
9391
			write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a));
9392
		});
9393
	});
9394
	write_record(ba, "BrtEndCommentAuthors");
9395
9396
	write_record(ba, "BrtBeginCommentList");
9397
	data.forEach(function(comment) {
9398
		comment[1].forEach(function(c) {
9399
			c.iauthor = iauthor.indexOf(c.a);
9400
			var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
9401
			write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c]));
9402
			if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c));
9403
			write_record(ba, "BrtEndComment");
9404
			delete c.iauthor;
9405
		});
9406
	});
9407
	write_record(ba, "BrtEndCommentList");
9408
9409
	write_record(ba, "BrtEndComments");
9410
	return ba.end();
9411
}
9412
var CT_VBA = "application/vnd.ms-office.vbaProject";
9413
function make_vba_xls(cfb) {
9414
	var newcfb = CFB.utils.cfb_new({root:"R"});
9415
	cfb.FullPaths.forEach(function(p, i) {
9416
		if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
9417
		var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
9418
		CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
9419
	});
9420
	return CFB.write(newcfb);
9421
}
9422
9423
function fill_vba_xls(cfb, vba) {
9424
	vba.FullPaths.forEach(function(p, i) {
9425
		if(i == 0) return;
9426
		var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
9427
		if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
9428
	});
9429
}
9430
9431
var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
9432
9433
RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
9434
RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
9435
9436
/* macro and dialog sheet stubs */
9437
function parse_ds_bin() { return {'!type':'dialog'}; }
9438
function parse_ds_xml() { return {'!type':'dialog'}; }
9439
function parse_ms_bin() { return {'!type':'macro'}; }
9440
function parse_ms_xml() { return {'!type':'macro'}; }
9441
/* TODO: it will be useful to parse the function str */
9442
var rc_to_a1 = (function(){
9443
	var rcregex = /(^|[^A-Za-z])R(\[?)(-?\d+|)\]?C(\[?)(-?\d+|)\]?/g;
9444
	var rcbase = ({r:0,c:0});
9445
	function rcfunc($$,$1,$2,$3,$4,$5) {
9446
		var R = $3.length>0?parseInt($3,10)|0:0, C = $5.length>0?parseInt($5,10)|0:0;
9447
		if(C<0 && $4.length === 0) C=0;
9448
		var cRel = false, rRel = false;
9449
		if($4.length > 0 || $5.length == 0) cRel = true; if(cRel) C += rcbase.c; else --C;
9450
		if($2.length > 0 || $3.length == 0) rRel = true; if(rRel) R += rcbase.r; else --R;
9451
		return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
9452
	}
9453
	return function rc_to_a1(fstr, base) {
9454
		rcbase = base;
9455
		return fstr.replace(rcregex, rcfunc);
9456
	};
9457
})();
9458
9459
var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)([1-9]\d{0,5}|10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6])(?![_.\(A-Za-z0-9])/g;
9460
var a1_to_rc =(function(){
9461
	return function a1_to_rc(fstr, base) {
9462
		return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
9463
			var c = decode_col($3) - ($2 ? 0 : base.c);
9464
			var r = decode_row($5) - ($4 ? 0 : base.r);
9465
			var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
9466
			var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
9467
			return $1 + "R" + R + "C" + C;
9468
		});
9469
	};
9470
})();
9471
9472
/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
9473
function shift_formula_str(f, delta) {
9474
	return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
9475
		return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
9476
	});
9477
}
9478
9479
function shift_formula_xlsx(f, range, cell) {
9480
	var r = decode_range(range), s = r.s, c = decode_cell(cell);
9481
	var delta = {r:c.r - s.r, c:c.c - s.c};
9482
	return shift_formula_str(f, delta);
9483
}
9484
9485
/* TODO: parse formula */
9486
function fuzzyfmla(f) {
9487
	if(f.length == 1) return false;
9488
	return true;
9489
}
9490
9491
function _xlfn(f) {
9492
	return f.replace(/_xlfn\./g,"");
9493
}
9494
function parseread1(blob) { blob.l+=1; return; }
9495
9496
/* [MS-XLS] 2.5.51 */
9497
function parse_ColRelU(blob, length) {
9498
	var c = blob.read_shift(length == 1 ? 1 : 2);
9499
	return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
9500
}
9501
9502
/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.89 */
9503
function parse_RgceArea(blob, length, opts) {
9504
	var w = 2;
9505
	if(opts) {
9506
		if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts);
9507
		else if(opts.biff == 12) w = 4;
9508
	}
9509
	var r=blob.read_shift(w), R=blob.read_shift(w);
9510
	var c=parse_ColRelU(blob, 2);
9511
	var C=parse_ColRelU(blob, 2);
9512
	return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
9513
}
9514
/* BIFF 2-5 encodes flags in the row field */
9515
function parse_RgceArea_BIFF2(blob) {
9516
	var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
9517
	var c=blob.read_shift(1);
9518
	var C=blob.read_shift(1);
9519
	return { s:{r:r[0], c:c, cRel:r[1], rRel:r[2]}, e:{r:R[0], c:C, cRel:R[1], rRel:R[2]} };
9520
}
9521
9522
/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.90 */
9523
function parse_RgceAreaRel(blob, length, opts) {
9524
	if(opts.biff < 8) return parse_RgceArea_BIFF2(blob, length, opts);
9525
	var r=blob.read_shift(opts.biff == 12 ? 4 : 2), R=blob.read_shift(opts.biff == 12 ? 4 : 2);
9526
	var c=parse_ColRelU(blob, 2);
9527
	var C=parse_ColRelU(blob, 2);
9528
	return { s:{r:r, c:c[0], cRel:c[1], rRel:c[2]}, e:{r:R, c:C[0], cRel:C[1], rRel:C[2]} };
9529
}
9530
9531
/* [MS-XLS] 2.5.198.109 ; [MS-XLSB] 2.5.97.91 */
9532
function parse_RgceLoc(blob, length, opts) {
9533
	if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts);
9534
	var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2);
9535
	var c = parse_ColRelU(blob, 2);
9536
	return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
9537
}
9538
function parse_RgceLoc_BIFF2(blob) {
9539
	var r = parse_ColRelU(blob, 2);
9540
	var c = blob.read_shift(1);
9541
	return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
9542
}
9543
9544
/* [MS-XLS] 2.5.198.107, 2.5.47 */
9545
function parse_RgceElfLoc(blob) {
9546
	var r = blob.read_shift(2);
9547
	var c = blob.read_shift(2);
9548
	return {r:r, c:c & 0xFF, fQuoted:!!(c & 0x4000), cRel:c>>15, rRel:c>>15 };
9549
}
9550
9551
/* [MS-XLS] 2.5.198.111 ; [MS-XLSB] 2.5.97.92 TODO */
9552
function parse_RgceLocRel(blob, length, opts) {
9553
	var biff = opts && opts.biff ? opts.biff : 8;
9554
	if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts);
9555
	var r = blob.read_shift(biff >= 12 ? 4 : 2);
9556
	var cl = blob.read_shift(2);
9557
	var cRel = (cl & 0x4000) >> 14, rRel = (cl & 0x8000) >> 15;
9558
	cl &= 0x3FFF;
9559
	if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000;
9560
	if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000;
9561
	return {r:r,c:cl,cRel:cRel,rRel:rRel};
9562
}
9563
function parse_RgceLocRel_BIFF2(blob) {
9564
	var rl = blob.read_shift(2);
9565
	var c = blob.read_shift(1);
9566
	var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14;
9567
	rl &= 0x3FFF;
9568
	if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000;
9569
	if(cRel == 1 && c >= 0x80) c = c - 0x100;
9570
	return {r:rl,c:c,cRel:cRel,rRel:rRel};
9571
}
9572
9573
/* [MS-XLS] 2.5.198.27 ; [MS-XLSB] 2.5.97.18 */
9574
function parse_PtgArea(blob, length, opts) {
9575
	var type = (blob[blob.l++] & 0x60) >> 5;
9576
	var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
9577
	return [type, area];
9578
}
9579
9580
/* [MS-XLS] 2.5.198.28 ; [MS-XLSB] 2.5.97.19 */
9581
function parse_PtgArea3d(blob, length, opts) {
9582
	var type = (blob[blob.l++] & 0x60) >> 5;
9583
	var ixti = blob.read_shift(2, 'i');
9584
	var w = 8;
9585
	if(opts) switch(opts.biff) {
9586
		case 5: blob.l += 12; w = 6; break;
9587
		case 12: w = 12; break;
9588
	}
9589
	var area = parse_RgceArea(blob, w, opts);
9590
	return [type, ixti, area];
9591
}
9592
9593
/* [MS-XLS] 2.5.198.29 ; [MS-XLSB] 2.5.97.20 */
9594
function parse_PtgAreaErr(blob, length, opts) {
9595
	var type = (blob[blob.l++] & 0x60) >> 5;
9596
	blob.l += opts && (opts.biff > 8) ? 12 : (opts.biff < 8 ? 6 : 8);
9597
	return [type];
9598
}
9599
/* [MS-XLS] 2.5.198.30 ; [MS-XLSB] 2.5.97.21 */
9600
function parse_PtgAreaErr3d(blob, length, opts) {
9601
	var type = (blob[blob.l++] & 0x60) >> 5;
9602
	var ixti = blob.read_shift(2);
9603
	var w = 8;
9604
	if(opts) switch(opts.biff) {
9605
		case 5: blob.l += 12; w = 6; break;
9606
		case 12: w = 12; break;
9607
	}
9608
	blob.l += w;
9609
	return [type, ixti];
9610
}
9611
9612
/* [MS-XLS] 2.5.198.31 ; [MS-XLSB] 2.5.97.22 */
9613
function parse_PtgAreaN(blob, length, opts) {
9614
	var type = (blob[blob.l++] & 0x60) >> 5;
9615
	var area = parse_RgceAreaRel(blob, length - 1, opts);
9616
	return [type, area];
9617
}
9618
9619
/* [MS-XLS] 2.5.198.32 ; [MS-XLSB] 2.5.97.23 */
9620
function parse_PtgArray(blob, length, opts) {
9621
	var type = (blob[blob.l++] & 0x60) >> 5;
9622
	blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
9623
	return [type];
9624
}
9625
9626
/* [MS-XLS] 2.5.198.33 ; [MS-XLSB] 2.5.97.24 */
9627
function parse_PtgAttrBaxcel(blob) {
9628
	var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
9629
	var bitBaxcel = 1;
9630
	blob.l += 4;
9631
	return [bitSemi, bitBaxcel];
9632
}
9633
9634
/* [MS-XLS] 2.5.198.34 ; [MS-XLSB] 2.5.97.25 */
9635
function parse_PtgAttrChoose(blob, length, opts) {
9636
	blob.l +=2;
9637
	var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9638
	var o = [];
9639
	/* offset is 1 less than the number of elements */
9640
	for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2));
9641
	return o;
9642
}
9643
9644
/* [MS-XLS] 2.5.198.35 ; [MS-XLSB] 2.5.97.26 */
9645
function parse_PtgAttrGoto(blob, length, opts) {
9646
	var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9647
	blob.l += 2;
9648
	return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
9649
}
9650
9651
/* [MS-XLS] 2.5.198.36 ; [MS-XLSB] 2.5.97.27 */
9652
function parse_PtgAttrIf(blob, length, opts) {
9653
	var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9654
	blob.l += 2;
9655
	return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
9656
}
9657
9658
/* [MS-XLSB] 2.5.97.28 */
9659
function parse_PtgAttrIfError(blob) {
9660
	var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9661
	blob.l += 2;
9662
	return [bitIf, blob.read_shift(2)];
9663
}
9664
9665
/* [MS-XLS] 2.5.198.37 ; [MS-XLSB] 2.5.97.29 */
9666
function parse_PtgAttrSemi(blob, length, opts) {
9667
	var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
9668
	blob.l += opts && opts.biff == 2 ? 3 : 4;
9669
	return [bitSemi];
9670
}
9671
9672
/* [MS-XLS] 2.5.198.40 ; [MS-XLSB] 2.5.97.32 */
9673
function parse_PtgAttrSpaceType(blob) {
9674
	var type = blob.read_shift(1), cch = blob.read_shift(1);
9675
	return [type, cch];
9676
}
9677
9678
/* [MS-XLS] 2.5.198.38 ; [MS-XLSB] 2.5.97.30 */
9679
function parse_PtgAttrSpace(blob) {
9680
	blob.read_shift(2);
9681
	return parse_PtgAttrSpaceType(blob, 2);
9682
}
9683
9684
/* [MS-XLS] 2.5.198.39 ; [MS-XLSB] 2.5.97.31 */
9685
function parse_PtgAttrSpaceSemi(blob) {
9686
	blob.read_shift(2);
9687
	return parse_PtgAttrSpaceType(blob, 2);
9688
}
9689
9690
/* [MS-XLS] 2.5.198.84 ; [MS-XLSB] 2.5.97.68 TODO */
9691
function parse_PtgRef(blob, length, opts) {
9692
	//var ptg = blob[blob.l] & 0x1F;
9693
	var type = (blob[blob.l] & 0x60)>>5;
9694
	blob.l += 1;
9695
	var loc = parse_RgceLoc(blob, 0, opts);
9696
	return [type, loc];
9697
}
9698
9699
/* [MS-XLS] 2.5.198.88 ; [MS-XLSB] 2.5.97.72 TODO */
9700
function parse_PtgRefN(blob, length, opts) {
9701
	var type = (blob[blob.l] & 0x60)>>5;
9702
	blob.l += 1;
9703
	var loc = parse_RgceLocRel(blob, 0, opts);
9704
	return [type, loc];
9705
}
9706
9707
/* [MS-XLS] 2.5.198.85 ; [MS-XLSB] 2.5.97.69 TODO */
9708
function parse_PtgRef3d(blob, length, opts) {
9709
	var type = (blob[blob.l] & 0x60)>>5;
9710
	blob.l += 1;
9711
	var ixti = blob.read_shift(2); // XtiIndex
9712
	if(opts && opts.biff == 5) blob.l += 12;
9713
	var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
9714
	return [type, ixti, loc];
9715
}
9716
9717
9718
/* [MS-XLS] 2.5.198.62 ; [MS-XLSB] 2.5.97.45 TODO */
9719
function parse_PtgFunc(blob, length, opts) {
9720
	//var ptg = blob[blob.l] & 0x1F;
9721
	var type = (blob[blob.l] & 0x60)>>5;
9722
	blob.l += 1;
9723
	var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
9724
	return [FtabArgc[iftab], Ftab[iftab], type];
9725
}
9726
/* [MS-XLS] 2.5.198.63 ; [MS-XLSB] 2.5.97.46 TODO */
9727
function parse_PtgFuncVar(blob, length, opts) {
9728
	var type = blob[blob.l++];
9729
	var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [(type == 0x58 ? -1 : 0), blob.read_shift(1)]: parsetab(blob);
9730
	return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
9731
}
9732
9733
function parsetab(blob) {
9734
	return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
9735
}
9736
9737
/* [MS-XLS] 2.5.198.41 ; [MS-XLSB] 2.5.97.33 */
9738
function parse_PtgAttrSum(blob, length, opts) {
9739
	blob.l += opts && opts.biff == 2 ? 3 : 4; return;
9740
}
9741
9742
/* [MS-XLS] 2.5.198.58 ; [MS-XLSB] 2.5.97.40 */
9743
function parse_PtgExp(blob, length, opts) {
9744
	blob.l++;
9745
	if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
9746
	var row = blob.read_shift(2);
9747
	var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9748
	return [row, col];
9749
}
9750
9751
/* [MS-XLS] 2.5.198.57 ; [MS-XLSB] 2.5.97.39 */
9752
function parse_PtgErr(blob) { blob.l++; return BErr[blob.read_shift(1)]; }
9753
9754
/* [MS-XLS] 2.5.198.66 ; [MS-XLSB] 2.5.97.49 */
9755
function parse_PtgInt(blob) { blob.l++; return blob.read_shift(2); }
9756
9757
/* [MS-XLS] 2.5.198.42 ; [MS-XLSB] 2.5.97.34 */
9758
function parse_PtgBool(blob) { blob.l++; return blob.read_shift(1)!==0;}
9759
9760
/* [MS-XLS] 2.5.198.79 ; [MS-XLSB] 2.5.97.63 */
9761
function parse_PtgNum(blob) { blob.l++; return parse_Xnum(blob, 8); }
9762
9763
/* [MS-XLS] 2.5.198.89 ; [MS-XLSB] 2.5.97.74 */
9764
function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
9765
9766
/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
9767
/* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */
9768
function parse_SerAr(blob, biff) {
9769
	var val = [blob.read_shift(1)];
9770
	if(biff == 12) switch(val[0]) {
9771
		case 0x02: val[0] = 0x04; break; /* SerBool */
9772
		case 0x04: val[0] = 0x10; break; /* SerErr */
9773
		case 0x00: val[0] = 0x01; break; /* SerNum */
9774
		case 0x01: val[0] = 0x02; break; /* SerStr */
9775
	}
9776
	switch(val[0]) {
9777
		case 0x04: /* SerBool -- boolean */
9778
			val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
9779
			if(biff != 12) blob.l += 7; break;
9780
		case 0x25: /* appears to be an alias */
9781
		case 0x10: /* SerErr -- error */
9782
			val[1] = BErr[blob[blob.l]];
9783
			blob.l += ((biff == 12) ? 4 : 8); break;
9784
		case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
9785
			blob.l += 8; break;
9786
		case 0x01: /* SerNum -- Xnum */
9787
			val[1] = parse_Xnum(blob, 8); break;
9788
		case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
9789
			val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
9790
		default: throw new Error("Bad SerAr: " + val[0]); /* Unreachable */
9791
	}
9792
	return val;
9793
}
9794
9795
/* [MS-XLS] 2.5.198.61 ; [MS-XLSB] 2.5.97.44 */
9796
function parse_PtgExtraMem(blob, cce, opts) {
9797
	var count = blob.read_shift((opts.biff == 12) ? 4 : 2);
9798
	var out = [];
9799
	for(var i = 0; i != count; ++i) out.push(((opts.biff == 12) ? parse_UncheckedRfX : parse_Ref8U)(blob, 8));
9800
	return out;
9801
}
9802
9803
/* [MS-XLS] 2.5.198.59 ; [MS-XLSB] 2.5.97.41 */
9804
function parse_PtgExtraArray(blob, length, opts) {
9805
	var rows = 0, cols = 0;
9806
	if(opts.biff == 12) {
9807
		rows = blob.read_shift(4); // DRw
9808
		cols = blob.read_shift(4); // DCol
9809
	} else {
9810
		cols = 1 + blob.read_shift(1); //DColByteU
9811
		rows = 1 + blob.read_shift(2); //DRw
9812
	}
9813
	if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; }
9814
	// $FlowIgnore
9815
	for(var i = 0, o = []; i != rows && (o[i] = []); ++i)
9816
		for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff);
9817
	return o;
9818
}
9819
9820
/* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 */
9821
function parse_PtgName(blob, length, opts) {
9822
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9823
	var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
9824
	var nameindex = blob.read_shift(w);
9825
	switch(opts.biff) {
9826
		case 2: blob.l += 5; break;
9827
		case 3: case 4: blob.l += 8; break;
9828
		case 5: blob.l += 12; break;
9829
	}
9830
	return [type, 0, nameindex];
9831
}
9832
9833
/* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 */
9834
function parse_PtgNameX(blob, length, opts) {
9835
	if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts);
9836
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9837
	var ixti = blob.read_shift(2); // XtiIndex
9838
	var nameindex = blob.read_shift(4);
9839
	return [type, ixti, nameindex];
9840
}
9841
function parse_PtgNameX_BIFF5(blob) {
9842
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9843
	var ixti = blob.read_shift(2, 'i'); // XtiIndex
9844
	blob.l += 8;
9845
	var nameindex = blob.read_shift(2);
9846
	blob.l += 12;
9847
	return [type, ixti, nameindex];
9848
}
9849
9850
/* [MS-XLS] 2.5.198.70 ; [MS-XLSB] 2.5.97.54 */
9851
function parse_PtgMemArea(blob, length, opts) {
9852
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9853
	blob.l += (opts && opts.biff == 2 ? 3 : 4);
9854
	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9855
	return [type, cce];
9856
}
9857
9858
/* [MS-XLS] 2.5.198.72 ; [MS-XLSB] 2.5.97.56 */
9859
function parse_PtgMemFunc(blob, length, opts) {
9860
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9861
	var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
9862
	return [type, cce];
9863
}
9864
9865
9866
/* [MS-XLS] 2.5.198.86 ; [MS-XLSB] 2.5.97.69 */
9867
function parse_PtgRefErr(blob, length, opts) {
9868
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9869
	blob.l += 4;
9870
	if(opts.biff < 8) blob.l--;
9871
	if(opts.biff == 12) blob.l += 2;
9872
	return [type];
9873
}
9874
9875
/* [MS-XLS] 2.5.198.87 ; [MS-XLSB] 2.5.97.71 */
9876
function parse_PtgRefErr3d(blob, length, opts) {
9877
	var type = (blob[blob.l++] & 0x60) >> 5;
9878
	var ixti = blob.read_shift(2);
9879
	var w = 4;
9880
	if(opts) switch(opts.biff) {
9881
		case 5: w = 15; break;
9882
		case 12: w = 6; break;
9883
	}
9884
	blob.l += w;
9885
	return [type, ixti];
9886
}
9887
9888
/* [MS-XLS] 2.5.198.71 ; [MS-XLSB] 2.5.97.55 */
9889
var parse_PtgMemErr = parsenoop;
9890
/* [MS-XLS] 2.5.198.73  ; [MS-XLSB] 2.5.97.57 */
9891
var parse_PtgMemNoMem = parsenoop;
9892
/* [MS-XLS] 2.5.198.92 */
9893
var parse_PtgTbl = parsenoop;
9894
9895
function parse_PtgElfLoc(blob, length, opts) {
9896
	blob.l += 2;
9897
	return [parse_RgceElfLoc(blob, 4, opts)];
9898
}
9899
function parse_PtgElfNoop(blob) {
9900
	blob.l += 6;
9901
	return [];
9902
}
9903
/* [MS-XLS] 2.5.198.46 */
9904
var parse_PtgElfCol = parse_PtgElfLoc;
9905
/* [MS-XLS] 2.5.198.47 */
9906
var parse_PtgElfColS = parse_PtgElfNoop;
9907
/* [MS-XLS] 2.5.198.48 */
9908
var parse_PtgElfColSV = parse_PtgElfNoop;
9909
/* [MS-XLS] 2.5.198.49 */
9910
var parse_PtgElfColV = parse_PtgElfLoc;
9911
/* [MS-XLS] 2.5.198.50 */
9912
function parse_PtgElfLel(blob) {
9913
	blob.l += 2;
9914
	return [parseuint16(blob), blob.read_shift(2) & 0x01];
9915
}
9916
/* [MS-XLS] 2.5.198.51 */
9917
var parse_PtgElfRadical = parse_PtgElfLoc;
9918
/* [MS-XLS] 2.5.198.52 */
9919
var parse_PtgElfRadicalLel = parse_PtgElfLel;
9920
/* [MS-XLS] 2.5.198.53 */
9921
var parse_PtgElfRadicalS = parse_PtgElfNoop;
9922
/* [MS-XLS] 2.5.198.54 */
9923
var parse_PtgElfRw = parse_PtgElfLoc;
9924
/* [MS-XLS] 2.5.198.55 */
9925
var parse_PtgElfRwV = parse_PtgElfLoc;
9926
9927
/* [MS-XLSB] 2.5.97.52 TODO */
9928
var PtgListRT = [
9929
	"Data",
9930
	"All",
9931
	"Headers",
9932
	"??",
9933
	"?Data2",
9934
	"??",
9935
	"?DataHeaders",
9936
	"??",
9937
	"Totals",
9938
	"??",
9939
	"??",
9940
	"??",
9941
	"?DataTotals",
9942
	"??",
9943
	"??",
9944
	"??",
9945
	"?Current"
9946
];
9947
function parse_PtgList(blob) {
9948
	blob.l += 2;
9949
	var ixti = blob.read_shift(2);
9950
	var flags = blob.read_shift(2);
9951
	var idx = blob.read_shift(4);
9952
	var c = blob.read_shift(2);
9953
	var C = blob.read_shift(2);
9954
	var rt = PtgListRT[(flags >> 2) & 0x1F];
9955
	return {ixti: ixti, coltype:(flags&0x3), rt:rt, idx:idx, c:c, C:C};
9956
}
9957
/* [MS-XLS] 2.5.198.91 ; [MS-XLSB] 2.5.97.76 */
9958
function parse_PtgSxName(blob) {
9959
	blob.l += 2;
9960
	return [blob.read_shift(4)];
9961
}
9962
9963
/* [XLS] old spec */
9964
function parse_PtgSheet(blob, length, opts) {
9965
	blob.l += 5;
9966
	blob.l += 2;
9967
	blob.l += (opts.biff == 2 ? 1 : 4);
9968
	return ["PTGSHEET"];
9969
}
9970
function parse_PtgEndSheet(blob, length, opts) {
9971
	blob.l += (opts.biff == 2 ? 4 : 5);
9972
	return ["PTGENDSHEET"];
9973
}
9974
function parse_PtgMemAreaN(blob) {
9975
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9976
	var cce = blob.read_shift(2);
9977
	return [type, cce];
9978
}
9979
function parse_PtgMemNoMemN(blob) {
9980
	var type = (blob.read_shift(1) >>> 5) & 0x03;
9981
	var cce = blob.read_shift(2);
9982
	return [type, cce];
9983
}
9984
function parse_PtgAttrNoop(blob) {
9985
	blob.l += 4;
9986
	return [0, 0];
9987
}
9988
9989
/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
9990
var PtgTypes = {
9991
0x01: { n:'PtgExp', f:parse_PtgExp },
9992
0x02: { n:'PtgTbl', f:parse_PtgTbl },
9993
0x03: { n:'PtgAdd', f:parseread1 },
9994
0x04: { n:'PtgSub', f:parseread1 },
9995
0x05: { n:'PtgMul', f:parseread1 },
9996
0x06: { n:'PtgDiv', f:parseread1 },
9997
0x07: { n:'PtgPower', f:parseread1 },
9998
0x08: { n:'PtgConcat', f:parseread1 },
9999
0x09: { n:'PtgLt', f:parseread1 },
10000
0x0A: { n:'PtgLe', f:parseread1 },
10001
0x0B: { n:'PtgEq', f:parseread1 },
10002
0x0C: { n:'PtgGe', f:parseread1 },
10003
0x0D: { n:'PtgGt', f:parseread1 },
10004
0x0E: { n:'PtgNe', f:parseread1 },
10005
0x0F: { n:'PtgIsect', f:parseread1 },
10006
0x10: { n:'PtgUnion', f:parseread1 },
10007
0x11: { n:'PtgRange', f:parseread1 },
10008
0x12: { n:'PtgUplus', f:parseread1 },
10009
0x13: { n:'PtgUminus', f:parseread1 },
10010
0x14: { n:'PtgPercent', f:parseread1 },
10011
0x15: { n:'PtgParen', f:parseread1 },
10012
0x16: { n:'PtgMissArg', f:parseread1 },
10013
0x17: { n:'PtgStr', f:parse_PtgStr },
10014
0x1A: { n:'PtgSheet', f:parse_PtgSheet },
10015
0x1B: { n:'PtgEndSheet', f:parse_PtgEndSheet },
10016
0x1C: { n:'PtgErr', f:parse_PtgErr },
10017
0x1D: { n:'PtgBool', f:parse_PtgBool },
10018
0x1E: { n:'PtgInt', f:parse_PtgInt },
10019
0x1F: { n:'PtgNum', f:parse_PtgNum },
10020
0x20: { n:'PtgArray', f:parse_PtgArray },
10021
0x21: { n:'PtgFunc', f:parse_PtgFunc },
10022
0x22: { n:'PtgFuncVar', f:parse_PtgFuncVar },
10023
0x23: { n:'PtgName', f:parse_PtgName },
10024
0x24: { n:'PtgRef', f:parse_PtgRef },
10025
0x25: { n:'PtgArea', f:parse_PtgArea },
10026
0x26: { n:'PtgMemArea', f:parse_PtgMemArea },
10027
0x27: { n:'PtgMemErr', f:parse_PtgMemErr },
10028
0x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
10029
0x29: { n:'PtgMemFunc', f:parse_PtgMemFunc },
10030
0x2A: { n:'PtgRefErr', f:parse_PtgRefErr },
10031
0x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr },
10032
0x2C: { n:'PtgRefN', f:parse_PtgRefN },
10033
0x2D: { n:'PtgAreaN', f:parse_PtgAreaN },
10034
0x2E: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
10035
0x2F: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
10036
0x39: { n:'PtgNameX', f:parse_PtgNameX },
10037
0x3A: { n:'PtgRef3d', f:parse_PtgRef3d },
10038
0x3B: { n:'PtgArea3d', f:parse_PtgArea3d },
10039
0x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
10040
0x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
10041
0xFF: {}
10042
};
10043
/* These are duplicated in the PtgTypes table */
10044
var PtgDupes = {
10045
0x40: 0x20, 0x60: 0x20,
10046
0x41: 0x21, 0x61: 0x21,
10047
0x42: 0x22, 0x62: 0x22,
10048
0x43: 0x23, 0x63: 0x23,
10049
0x44: 0x24, 0x64: 0x24,
10050
0x45: 0x25, 0x65: 0x25,
10051
0x46: 0x26, 0x66: 0x26,
10052
0x47: 0x27, 0x67: 0x27,
10053
0x48: 0x28, 0x68: 0x28,
10054
0x49: 0x29, 0x69: 0x29,
10055
0x4A: 0x2A, 0x6A: 0x2A,
10056
0x4B: 0x2B, 0x6B: 0x2B,
10057
0x4C: 0x2C, 0x6C: 0x2C,
10058
0x4D: 0x2D, 0x6D: 0x2D,
10059
0x4E: 0x2E, 0x6E: 0x2E,
10060
0x4F: 0x2F, 0x6F: 0x2F,
10061
0x58: 0x22, 0x78: 0x22,
10062
0x59: 0x39, 0x79: 0x39,
10063
0x5A: 0x3A, 0x7A: 0x3A,
10064
0x5B: 0x3B, 0x7B: 0x3B,
10065
0x5C: 0x3C, 0x7C: 0x3C,
10066
0x5D: 0x3D, 0x7D: 0x3D
10067
};
10068
(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
10069
10070
var Ptg18 = {
10071
0x01: { n:'PtgElfLel', f:parse_PtgElfLel },
10072
0x02: { n:'PtgElfRw', f:parse_PtgElfRw },
10073
0x03: { n:'PtgElfCol', f:parse_PtgElfCol },
10074
0x06: { n:'PtgElfRwV', f:parse_PtgElfRwV },
10075
0x07: { n:'PtgElfColV', f:parse_PtgElfColV },
10076
0x0A: { n:'PtgElfRadical', f:parse_PtgElfRadical },
10077
0x0B: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
10078
0x0D: { n:'PtgElfColS', f:parse_PtgElfColS },
10079
0x0F: { n:'PtgElfColSV', f:parse_PtgElfColSV },
10080
0x10: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
10081
0x19: { n:'PtgList', f:parse_PtgList },
10082
0x1D: { n:'PtgSxName', f:parse_PtgSxName },
10083
0xFF: {}
10084
};
10085
var Ptg19 = {
10086
0x00: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
10087
0x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
10088
0x02: { n:'PtgAttrIf', f:parse_PtgAttrIf },
10089
0x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
10090
0x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
10091
0x10: { n:'PtgAttrSum', f:parse_PtgAttrSum },
10092
0x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
10093
0x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
10094
0x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
10095
0x80: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
10096
0xFF: {}
10097
};
10098
Ptg19[0x21] = Ptg19[0x20];
10099
10100
/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
10101
function parse_RgbExtra(blob, length, rgce, opts) {
10102
	if(opts.biff < 8) return parsenoop(blob, length);
10103
	var target = blob.l + length;
10104
	var o = [];
10105
	for(var i = 0; i !== rgce.length; ++i) {
10106
		switch(rgce[i][0]) {
10107
			case 'PtgArray': /* PtgArray -> PtgExtraArray */
10108
				rgce[i][1] = parse_PtgExtraArray(blob, 0, opts);
10109
				o.push(rgce[i][1]);
10110
				break;
10111
			case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
10112
				rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1], opts);
10113
				o.push(rgce[i][2]);
10114
				break;
10115
			case 'PtgExp': /* PtgExp -> PtgExtraCol */
10116
				if(opts && opts.biff == 12) {
10117
					rgce[i][1][1] = blob.read_shift(4);
10118
					o.push(rgce[i][1]);
10119
				} break;
10120
			case 'PtgList': /* TODO: PtgList -> PtgExtraList */
10121
			case 'PtgElfRadicalS': /* TODO: PtgElfRadicalS -> PtgExtraElf */
10122
			case 'PtgElfColS': /* TODO: PtgElfColS -> PtgExtraElf */
10123
			case 'PtgElfColSV': /* TODO: PtgElfColSV -> PtgExtraElf */
10124
				throw "Unsupported " + rgce[i][0];
10125
			default: break;
10126
		}
10127
	}
10128
	length = target - blob.l;
10129
	/* note: this is technically an error but Excel disregards */
10130
	//if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
10131
	if(length !== 0) o.push(parsenoop(blob, length));
10132
	return o;
10133
}
10134
10135
/* [MS-XLS] 2.5.198.104 ; [MS-XLSB] 2.5.97.88 */
10136
function parse_Rgce(blob, length, opts) {
10137
	var target = blob.l + length;
10138
	var R, id, ptgs = [];
10139
	while(target != blob.l) {
10140
		length = target - blob.l;
10141
		id = blob[blob.l];
10142
		R = PtgTypes[id];
10143
		if(id === 0x18 || id === 0x19) R = (id === 0x18 ? Ptg18 : Ptg19)[blob[blob.l + 1]];
10144
		if(!R || !R.f) { /*ptgs.push*/(parsenoop(blob, length)); }
10145
		else { ptgs.push([R.n, R.f(blob, length, opts)]); }
10146
	}
10147
	return ptgs;
10148
}
10149
10150
function stringify_array(f) {
10151
	var o = [];
10152
	for(var i = 0; i < f.length; ++i) {
10153
		var x = f[i], r = [];
10154
		for(var j = 0; j < x.length; ++j) {
10155
			var y = x[j];
10156
			if(y) switch(y[0]) {
10157
				// TODO: handle embedded quotes
10158
				case 0x02:
10159
r.push('"' + y[1].replace(/"/g,'""') + '"'); break;
10160
				default: r.push(y[1]);
10161
			} else r.push("");
10162
		}
10163
		o.push(r.join(","));
10164
	}
10165
	return o.join(";");
10166
}
10167
10168
/* [MS-XLS] 2.2.2 ; [MS-XLSB] 2.2.2 TODO */
10169
var PtgBinOp = {
10170
	PtgAdd: "+",
10171
	PtgConcat: "&",
10172
	PtgDiv: "/",
10173
	PtgEq: "=",
10174
	PtgGe: ">=",
10175
	PtgGt: ">",
10176
	PtgLe: "<=",
10177
	PtgLt: "<",
10178
	PtgMul: "*",
10179
	PtgNe: "<>",
10180
	PtgPower: "^",
10181
	PtgSub: "-"
10182
};
10183
function formula_quote_sheet_name(sname, opts) {
10184
	if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name");
10185
	if(sname.indexOf(" ") > -1) return "'" + sname + "'";
10186
	return sname;
10187
}
10188
function get_ixti_raw(supbooks, ixti, opts) {
10189
	if(!supbooks) return "SH33TJSERR0";
10190
	if(!supbooks.XTI) return "SH33TJSERR6";
10191
	var XTI = supbooks.XTI[ixti];
10192
	if(opts.biff > 8 && !supbooks.XTI[ixti]) return supbooks.SheetNames[ixti];
10193
	if(opts.biff < 8) {
10194
		if(ixti > 10000) ixti-= 65536;
10195
		if(ixti < 0) ixti = -ixti;
10196
		return ixti == 0 ? "" : supbooks.XTI[ixti - 1];
10197
	}
10198
	if(!XTI) return "SH33TJSERR1";
10199
	var o = "";
10200
	if(opts.biff > 8) switch(supbooks[XTI[0]][0]) {
10201
		case 0x0165: /* 'BrtSupSelf' */
10202
			o = XTI[1] == -1 ? "#REF" : supbooks.SheetNames[XTI[1]];
10203
			return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
10204
		case 0x0166: /* 'BrtSupSame' */
10205
			if(opts.SID != null) return supbooks.SheetNames[opts.SID];
10206
			return "SH33TJSSAME" + supbooks[XTI[0]][0];
10207
		case 0x0163: /* 'BrtSupBookSrc' */
10208
			/* falls through */
10209
		default: return "SH33TJSSRC" + supbooks[XTI[0]][0];
10210
	}
10211
	switch(supbooks[XTI[0]][0][0]) {
10212
		case 0x0401:
10213
			o = XTI[1] == -1 ? "#REF" : (supbooks.SheetNames[XTI[1]] || "SH33TJSERR3");
10214
			return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
10215
		case 0x3A01: return "SH33TJSERR8";
10216
		default:
10217
			if(!supbooks[XTI[0]][0][3]) return "SH33TJSERR2";
10218
			o = XTI[1] == -1 ? "#REF" : (supbooks[XTI[0]][0][3][XTI[1]] || "SH33TJSERR4");
10219
			return XTI[1] == XTI[2] ? o : o + ":" + supbooks[XTI[0]][0][3][XTI[2]];
10220
	}
10221
}
10222
function get_ixti(supbooks, ixti, opts) {
10223
	return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts), opts);
10224
}
10225
function stringify_formula(formula/*Array<any>*/, range, cell, supbooks, opts) {
10226
	var biff = (opts && opts.biff) || 8;
10227
	var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
10228
	var stack = [], e1, e2,  c, ixti=0, nameidx=0, r, sname="";
10229
	if(!formula[0] || !formula[0][0]) return "";
10230
	var last_sp = -1, sp = "";
10231
	for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
10232
		var f = formula[0][ff];
10233
		switch(f[0]) {
10234
			case 'PtgUminus': /* [MS-XLS] 2.5.198.93 */
10235
				stack.push("-" + stack.pop()); break;
10236
			case 'PtgUplus': /* [MS-XLS] 2.5.198.95 */
10237
				stack.push("+" + stack.pop()); break;
10238
			case 'PtgPercent': /* [MS-XLS] 2.5.198.81 */
10239
				stack.push(stack.pop() + "%"); break;
10240
10241
			case 'PtgAdd':    /* [MS-XLS] 2.5.198.26 */
10242
			case 'PtgConcat': /* [MS-XLS] 2.5.198.43 */
10243
			case 'PtgDiv':    /* [MS-XLS] 2.5.198.45 */
10244
			case 'PtgEq':     /* [MS-XLS] 2.5.198.56 */
10245
			case 'PtgGe':     /* [MS-XLS] 2.5.198.64 */
10246
			case 'PtgGt':     /* [MS-XLS] 2.5.198.65 */
10247
			case 'PtgLe':     /* [MS-XLS] 2.5.198.68 */
10248
			case 'PtgLt':     /* [MS-XLS] 2.5.198.69 */
10249
			case 'PtgMul':    /* [MS-XLS] 2.5.198.75 */
10250
			case 'PtgNe':     /* [MS-XLS] 2.5.198.78 */
10251
			case 'PtgPower':  /* [MS-XLS] 2.5.198.82 */
10252
			case 'PtgSub':    /* [MS-XLS] 2.5.198.90 */
10253
				e1 = stack.pop(); e2 = stack.pop();
10254
				if(last_sp >= 0) {
10255
					switch(formula[0][last_sp][1][0]) {
10256
						case 0:
10257
							// $FlowIgnore
10258
							sp = fill(" ", formula[0][last_sp][1][1]); break;
10259
						case 1:
10260
							// $FlowIgnore
10261
							sp = fill("\r", formula[0][last_sp][1][1]); break;
10262
						default:
10263
							sp = "";
10264
							// $FlowIgnore
10265
							if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
10266
					}
10267
					e2 = e2 + sp;
10268
					last_sp = -1;
10269
				}
10270
				stack.push(e2+PtgBinOp[f[0]]+e1);
10271
				break;
10272
10273
			case 'PtgIsect': /* [MS-XLS] 2.5.198.67 */
10274
				e1 = stack.pop(); e2 = stack.pop();
10275
				stack.push(e2+" "+e1);
10276
				break;
10277
			case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
10278
				e1 = stack.pop(); e2 = stack.pop();
10279
				stack.push(e2+","+e1);
10280
				break;
10281
			case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
10282
				e1 = stack.pop(); e2 = stack.pop();
10283
				stack.push(e2+":"+e1);
10284
				break;
10285
10286
			case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */
10287
				break;
10288
			case 'PtgAttrGoto': /* [MS-XLS] 2.5.198.35 */
10289
				break;
10290
			case 'PtgAttrIf': /* [MS-XLS] 2.5.198.36 */
10291
				break;
10292
			case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
10293
				break;
10294
10295
10296
			case 'PtgRef': /* [MS-XLS] 2.5.198.84 */
10297
c = shift_cell_xls((f[1][1]), _range, opts);
10298
				stack.push(encode_cell_xls(c, biff));
10299
				break;
10300
			case 'PtgRefN': /* [MS-XLS] 2.5.198.88 */
10301
c = cell ? shift_cell_xls((f[1][1]), cell, opts) : (f[1][1]);
10302
				stack.push(encode_cell_xls(c, biff));
10303
				break;
10304
			case 'PtgRef3d': /* [MS-XLS] 2.5.198.85 */
10305
ixti = f[1][1]; c = shift_cell_xls((f[1][2]), _range, opts);
10306
				sname = get_ixti(supbooks, ixti, opts);
10307
				var w = sname; /* IE9 fails on defined names */ // eslint-disable-line no-unused-vars
10308
				stack.push(sname + "!" + encode_cell_xls(c, biff));
10309
				break;
10310
10311
			case 'PtgFunc': /* [MS-XLS] 2.5.198.62 */
10312
			case 'PtgFuncVar': /* [MS-XLS] 2.5.198.63 */
10313
				/* f[1] = [argc, func, type] */
10314
				var argc = (f[1][0]), func = (f[1][1]);
10315
				if(!argc) argc = 0;
10316
				argc &= 0x7F;
10317
				var args = argc == 0 ? [] : stack.slice(-argc);
10318
				stack.length -= argc;
10319
				if(func === 'User') func = args.shift();
10320
				stack.push(func + "(" + args.join(",") + ")");
10321
				break;
10322
10323
			case 'PtgBool': /* [MS-XLS] 2.5.198.42 */
10324
				stack.push(f[1] ? "TRUE" : "FALSE"); break;
10325
			case 'PtgInt': /* [MS-XLS] 2.5.198.66 */
10326
				stack.push(f[1]); break;
10327
			case 'PtgNum': /* [MS-XLS] 2.5.198.79 TODO: precision? */
10328
				stack.push(String(f[1])); break;
10329
			case 'PtgStr': /* [MS-XLS] 2.5.198.89 */
10330
				// $FlowIgnore
10331
				stack.push('"' + f[1] + '"'); break;
10332
			case 'PtgErr': /* [MS-XLS] 2.5.198.57 */
10333
				stack.push(f[1]); break;
10334
			case 'PtgAreaN': /* [MS-XLS] 2.5.198.31 TODO */
10335
r = shift_range_xls(f[1][1], cell ? {s:cell} : _range, opts);
10336
				stack.push(encode_range_xls((r), opts));
10337
				break;
10338
			case 'PtgArea': /* [MS-XLS] 2.5.198.27 TODO: fixed points */
10339
r = shift_range_xls(f[1][1], _range, opts);
10340
				stack.push(encode_range_xls((r), opts));
10341
				break;
10342
			case 'PtgArea3d': /* [MS-XLS] 2.5.198.28 TODO */
10343
ixti = f[1][1]; r = f[1][2];
10344
				sname = get_ixti(supbooks, ixti, opts);
10345
				stack.push(sname + "!" + encode_range_xls((r), opts));
10346
				break;
10347
			case 'PtgAttrSum': /* [MS-XLS] 2.5.198.41 */
10348
				stack.push("SUM(" + stack.pop() + ")");
10349
				break;
10350
10351
			case 'PtgAttrBaxcel': /* [MS-XLS] 2.5.198.33 */
10352
			case 'PtgAttrSemi': /* [MS-XLS] 2.5.198.37 */
10353
				break;
10354
10355
			case 'PtgName': /* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 TODO: revisions */
10356
				/* f[1] = type, 0, nameindex */
10357
				nameidx = (f[1][2]);
10358
				var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
10359
				var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
10360
				if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
10361
				stack.push(name);
10362
				break;
10363
10364
			case 'PtgNameX': /* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 TODO: revisions */
10365
				/* f[1] = type, ixti, nameindex */
10366
				var bookidx = (f[1][1]); nameidx = (f[1][2]); var externbook;
10367
				/* TODO: Properly handle missing values */
10368
				if(opts.biff <= 5) {
10369
					if(bookidx < 0) bookidx = -bookidx;
10370
					if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
10371
				} else {
10372
					var o = "";
10373
					if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){/* empty */}
10374
					else if(((supbooks[bookidx]||[])[0]||[])[0] == 0x0401){
10375
						if(supbooks[bookidx][nameidx] && supbooks[bookidx][nameidx].itab > 0) {
10376
							o = supbooks.SheetNames[supbooks[bookidx][nameidx].itab-1] + "!";
10377
						}
10378
					}
10379
					else o = supbooks.SheetNames[nameidx-1]+ "!";
10380
					if(supbooks[bookidx] && supbooks[bookidx][nameidx]) o += supbooks[bookidx][nameidx].Name;
10381
					else if(supbooks[0] && supbooks[0][nameidx]) o += supbooks[0][nameidx].Name;
10382
					else o += "SH33TJSERRX";
10383
					stack.push(o);
10384
					break;
10385
				}
10386
				if(!externbook) externbook = {Name: "SH33TJSERRY"};
10387
				stack.push(externbook.Name);
10388
				break;
10389
10390
			case 'PtgParen': /* [MS-XLS] 2.5.198.80 */
10391
				var lp = '(', rp = ')';
10392
				if(last_sp >= 0) {
10393
					sp = "";
10394
					switch(formula[0][last_sp][1][0]) {
10395
						// $FlowIgnore
10396
						case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
10397
						// $FlowIgnore
10398
						case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
10399
						// $FlowIgnore
10400
						case 4: rp = fill(" ", formula[0][last_sp][1][1]) + rp; break;
10401
						// $FlowIgnore
10402
						case 5: rp = fill("\r", formula[0][last_sp][1][1]) + rp; break;
10403
						default:
10404
							// $FlowIgnore
10405
							if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
10406
					}
10407
					last_sp = -1;
10408
				}
10409
				stack.push(lp + stack.pop() + rp); break;
10410
10411
			case 'PtgRefErr': /* [MS-XLS] 2.5.198.86 */
10412
				stack.push('#REF!'); break;
10413
10414
			case 'PtgRefErr3d': /* [MS-XLS] 2.5.198.87 */
10415
				stack.push('#REF!'); break;
10416
10417
			case 'PtgExp': /* [MS-XLS] 2.5.198.58 TODO */
10418
				c = {c:(f[1][1]),r:(f[1][0])};
10419
				var q = ({c: cell.c, r:cell.r});
10420
				if(supbooks.sharedf[encode_cell(c)]) {
10421
					var parsedf = (supbooks.sharedf[encode_cell(c)]);
10422
					stack.push(stringify_formula(parsedf, _range, q, supbooks, opts));
10423
				}
10424
				else {
10425
					var fnd = false;
10426
					for(e1=0;e1!=supbooks.arrayf.length; ++e1) {
10427
						/* TODO: should be something like range_has */
10428
						e2 = supbooks.arrayf[e1];
10429
						if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
10430
						if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
10431
						stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
10432
						fnd = true;
10433
						break;
10434
					}
10435
					if(!fnd) stack.push(f[1]);
10436
				}
10437
				break;
10438
10439
			case 'PtgArray': /* [MS-XLS] 2.5.198.32 TODO */
10440
				stack.push("{" + stringify_array(f[1]) + "}");
10441
				break;
10442
10443
			case 'PtgMemArea': /* [MS-XLS] 2.5.198.70 TODO: confirm this is a non-display */
10444
				//stack.push("(" + f[2].map(encode_range).join(",") + ")");
10445
				break;
10446
10447
			case 'PtgAttrSpace': /* [MS-XLS] 2.5.198.38 */
10448
			case 'PtgAttrSpaceSemi': /* [MS-XLS] 2.5.198.39 */
10449
				last_sp = ff;
10450
				break;
10451
10452
			case 'PtgTbl': /* [MS-XLS] 2.5.198.92 TODO */
10453
				break;
10454
10455
			case 'PtgMemErr': /* [MS-XLS] 2.5.198.71 */
10456
				break;
10457
10458
			case 'PtgMissArg': /* [MS-XLS] 2.5.198.74 */
10459
				stack.push("");
10460
				break;
10461
10462
			case 'PtgAreaErr': /* [MS-XLS] 2.5.198.29 */
10463
				stack.push("#REF!"); break;
10464
10465
			case 'PtgAreaErr3d': /* [MS-XLS] 2.5.198.30 */
10466
				stack.push("#REF!"); break;
10467
10468
			case 'PtgList': /* [MS-XLSB] 2.5.97.52 */
10469
				// $FlowIgnore
10470
				stack.push("Table" + f[1].idx + "[#" + f[1].rt + "]");
10471
				break;
10472
10473
			case 'PtgMemAreaN':
10474
			case 'PtgMemNoMemN':
10475
			case 'PtgAttrNoop':
10476
			case 'PtgSheet':
10477
			case 'PtgEndSheet':
10478
				break;
10479
10480
			case 'PtgMemFunc': /* [MS-XLS] 2.5.198.72 TODO */
10481
				break;
10482
			case 'PtgMemNoMem': /* [MS-XLS] 2.5.198.73 TODO */
10483
				break;
10484
10485
			case 'PtgElfCol': /* [MS-XLS] 2.5.198.46 */
10486
			case 'PtgElfColS': /* [MS-XLS] 2.5.198.47 */
10487
			case 'PtgElfColSV': /* [MS-XLS] 2.5.198.48 */
10488
			case 'PtgElfColV': /* [MS-XLS] 2.5.198.49 */
10489
			case 'PtgElfLel': /* [MS-XLS] 2.5.198.50 */
10490
			case 'PtgElfRadical': /* [MS-XLS] 2.5.198.51 */
10491
			case 'PtgElfRadicalLel': /* [MS-XLS] 2.5.198.52 */
10492
			case 'PtgElfRadicalS': /* [MS-XLS] 2.5.198.53 */
10493
			case 'PtgElfRw': /* [MS-XLS] 2.5.198.54 */
10494
			case 'PtgElfRwV': /* [MS-XLS] 2.5.198.55 */
10495
				throw new Error("Unsupported ELFs");
10496
10497
			case 'PtgSxName': /* [MS-XLS] 2.5.198.91 TODO -- find a test case */
10498
				throw new Error('Unrecognized Formula Token: ' + String(f));
10499
			default: throw new Error('Unrecognized Formula Token: ' + String(f));
10500
		}
10501
		var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto'];
10502
		if(opts.biff != 3) if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) {
10503
			f = formula[0][last_sp];
10504
			var _left = true;
10505
			switch(f[1][0]) {
10506
				/* note: some bad XLSB files omit the PtgParen */
10507
				case 4: _left = false;
10508
				/* falls through */
10509
				case 0:
10510
					// $FlowIgnore
10511
					sp = fill(" ", f[1][1]); break;
10512
				case 5: _left = false;
10513
				/* falls through */
10514
				case 1:
10515
					// $FlowIgnore
10516
					sp = fill("\r", f[1][1]); break;
10517
				default:
10518
					sp = "";
10519
					// $FlowIgnore
10520
					if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + f[1][0]);
10521
			}
10522
			stack.push((_left ? sp : "") + stack.pop() + (_left ? "" : sp));
10523
			last_sp = -1;
10524
		}
10525
	}
10526
	if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
10527
	return stack[0];
10528
}
10529
10530
/* [MS-XLS] 2.5.198.1 TODO */
10531
function parse_ArrayParsedFormula(blob, length, opts) {
10532
	var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
10533
	var rgcb, cce = blob.read_shift(len); // length of rgce
10534
	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
10535
	var rgce = parse_Rgce(blob, cce, opts);
10536
	if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
10537
	blob.l = target;
10538
	return [rgce, rgcb];
10539
}
10540
10541
/* [MS-XLS] 2.5.198.3 TODO */
10542
function parse_XLSCellParsedFormula(blob, length, opts) {
10543
	var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
10544
	var rgcb, cce = blob.read_shift(len); // length of rgce
10545
	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
10546
	var rgce = parse_Rgce(blob, cce, opts);
10547
	if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
10548
	blob.l = target;
10549
	return [rgce, rgcb];
10550
}
10551
10552
/* [MS-XLS] 2.5.198.21 */
10553
function parse_NameParsedFormula(blob, length, opts, cce) {
10554
	var target = blob.l + length;
10555
	var rgce = parse_Rgce(blob, cce, opts);
10556
	var rgcb;
10557
	if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
10558
	return [rgce, rgcb];
10559
}
10560
10561
/* [MS-XLS] 2.5.198.118 TODO */
10562
function parse_SharedParsedFormula(blob, length, opts) {
10563
	var target = blob.l + length;
10564
	var rgcb, cce = blob.read_shift(2); // length of rgce
10565
	var rgce = parse_Rgce(blob, cce, opts);
10566
	if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
10567
	if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
10568
	return [rgce, rgcb];
10569
}
10570
10571
/* [MS-XLS] 2.5.133 TODO: how to emit empty strings? */
10572
function parse_FormulaValue(blob) {
10573
	var b;
10574
	if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
10575
	switch(blob[blob.l]) {
10576
		case 0x00: blob.l += 8; return ["String", 's'];
10577
		case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
10578
		case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
10579
		case 0x03: blob.l += 8; return ["",'s'];
10580
	}
10581
	return [];
10582
}
10583
10584
/* [MS-XLS] 2.4.127 TODO */
10585
function parse_Formula(blob, length, opts) {
10586
	var end = blob.l + length;
10587
	var cell = parse_XLSCell(blob, 6);
10588
	if(opts.biff == 2) ++blob.l;
10589
	var val = parse_FormulaValue(blob,8);
10590
	var flags = blob.read_shift(1);
10591
	if(opts.biff != 2) {
10592
		blob.read_shift(1);
10593
		if(opts.biff >= 5) {
10594
			/*var chn = */blob.read_shift(4);
10595
		}
10596
	}
10597
	var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
10598
	return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
10599
}
10600
10601
/* XLSB Parsed Formula records have the same shape */
10602
function parse_XLSBParsedFormula(data, length, opts) {
10603
	var cce = data.read_shift(4);
10604
	var rgce = parse_Rgce(data, cce, opts);
10605
	var cb = data.read_shift(4);
10606
	var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null;
10607
	return [rgce, rgcb];
10608
}
10609
10610
/* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */
10611
var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula;
10612
/* [MS-XLSB] 2.5.97.4 CellParsedFormula */
10613
var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula;
10614
/* [MS-XLSB] 2.5.97.12 NameParsedFormula */
10615
var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula;
10616
/* [MS-XLSB] 2.5.97.98 SharedParsedFormula */
10617
var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula;
10618
/* [MS-XLS] 2.5.198.4 */
10619
var Cetab = {
10620
0x0000: 'BEEP',
10621
0x0001: 'OPEN',
10622
0x0002: 'OPEN.LINKS',
10623
0x0003: 'CLOSE.ALL',
10624
0x0004: 'SAVE',
10625
0x0005: 'SAVE.AS',
10626
0x0006: 'FILE.DELETE',
10627
0x0007: 'PAGE.SETUP',
10628
0x0008: 'PRINT',
10629
0x0009: 'PRINTER.SETUP',
10630
0x000A: 'QUIT',
10631
0x000B: 'NEW.WINDOW',
10632
0x000C: 'ARRANGE.ALL',
10633
0x000D: 'WINDOW.SIZE',
10634
0x000E: 'WINDOW.MOVE',
10635
0x000F: 'FULL',
10636
0x0010: 'CLOSE',
10637
0x0011: 'RUN',
10638
0x0016: 'SET.PRINT.AREA',
10639
0x0017: 'SET.PRINT.TITLES',
10640
0x0018: 'SET.PAGE.BREAK',
10641
0x0019: 'REMOVE.PAGE.BREAK',
10642
0x001A: 'FONT',
10643
0x001B: 'DISPLAY',
10644
0x001C: 'PROTECT.DOCUMENT',
10645
0x001D: 'PRECISION',
10646
0x001E: 'A1.R1C1',
10647
0x001F: 'CALCULATE.NOW',
10648
0x0020: 'CALCULATION',
10649
0x0022: 'DATA.FIND',
10650
0x0023: 'EXTRACT',
10651
0x0024: 'DATA.DELETE',
10652
0x0025: 'SET.DATABASE',
10653
0x0026: 'SET.CRITERIA',
10654
0x0027: 'SORT',
10655
0x0028: 'DATA.SERIES',
10656
0x0029: 'TABLE',
10657
0x002A: 'FORMAT.NUMBER',
10658
0x002B: 'ALIGNMENT',
10659
0x002C: 'STYLE',
10660
0x002D: 'BORDER',
10661
0x002E: 'CELL.PROTECTION',
10662
0x002F: 'COLUMN.WIDTH',
10663
0x0030: 'UNDO',
10664
0x0031: 'CUT',
10665
0x0032: 'COPY',
10666
0x0033: 'PASTE',
10667
0x0034: 'CLEAR',
10668
0x0035: 'PASTE.SPECIAL',
10669
0x0036: 'EDIT.DELETE',
10670
0x0037: 'INSERT',
10671
0x0038: 'FILL.RIGHT',
10672
0x0039: 'FILL.DOWN',
10673
0x003D: 'DEFINE.NAME',
10674
0x003E: 'CREATE.NAMES',
10675
0x003F: 'FORMULA.GOTO',
10676
0x0040: 'FORMULA.FIND',
10677
0x0041: 'SELECT.LAST.CELL',
10678
0x0042: 'SHOW.ACTIVE.CELL',
10679
0x0043: 'GALLERY.AREA',
10680
0x0044: 'GALLERY.BAR',
10681
0x0045: 'GALLERY.COLUMN',
10682
0x0046: 'GALLERY.LINE',
10683
0x0047: 'GALLERY.PIE',
10684
0x0048: 'GALLERY.SCATTER',
10685
0x0049: 'COMBINATION',
10686
0x004A: 'PREFERRED',
10687
0x004B: 'ADD.OVERLAY',
10688
0x004C: 'GRIDLINES',
10689
0x004D: 'SET.PREFERRED',
10690
0x004E: 'AXES',
10691
0x004F: 'LEGEND',
10692
0x0050: 'ATTACH.TEXT',
10693
0x0051: 'ADD.ARROW',
10694
0x0052: 'SELECT.CHART',
10695
0x0053: 'SELECT.PLOT.AREA',
10696
0x0054: 'PATTERNS',
10697
0x0055: 'MAIN.CHART',
10698
0x0056: 'OVERLAY',
10699
0x0057: 'SCALE',
10700
0x0058: 'FORMAT.LEGEND',
10701
0x0059: 'FORMAT.TEXT',
10702
0x005A: 'EDIT.REPEAT',
10703
0x005B: 'PARSE',
10704
0x005C: 'JUSTIFY',
10705
0x005D: 'HIDE',
10706
0x005E: 'UNHIDE',
10707
0x005F: 'WORKSPACE',
10708
0x0060: 'FORMULA',
10709
0x0061: 'FORMULA.FILL',
10710
0x0062: 'FORMULA.ARRAY',
10711
0x0063: 'DATA.FIND.NEXT',
10712
0x0064: 'DATA.FIND.PREV',
10713
0x0065: 'FORMULA.FIND.NEXT',
10714
0x0066: 'FORMULA.FIND.PREV',
10715
0x0067: 'ACTIVATE',
10716
0x0068: 'ACTIVATE.NEXT',
10717
0x0069: 'ACTIVATE.PREV',
10718
0x006A: 'UNLOCKED.NEXT',
10719
0x006B: 'UNLOCKED.PREV',
10720
0x006C: 'COPY.PICTURE',
10721
0x006D: 'SELECT',
10722
0x006E: 'DELETE.NAME',
10723
0x006F: 'DELETE.FORMAT',
10724
0x0070: 'VLINE',
10725
0x0071: 'HLINE',
10726
0x0072: 'VPAGE',
10727
0x0073: 'HPAGE',
10728
0x0074: 'VSCROLL',
10729
0x0075: 'HSCROLL',
10730
0x0076: 'ALERT',
10731
0x0077: 'NEW',
10732
0x0078: 'CANCEL.COPY',
10733
0x0079: 'SHOW.CLIPBOARD',
10734
0x007A: 'MESSAGE',
10735
0x007C: 'PASTE.LINK',
10736
0x007D: 'APP.ACTIVATE',
10737
0x007E: 'DELETE.ARROW',
10738
0x007F: 'ROW.HEIGHT',
10739
0x0080: 'FORMAT.MOVE',
10740
0x0081: 'FORMAT.SIZE',
10741
0x0082: 'FORMULA.REPLACE',
10742
0x0083: 'SEND.KEYS',
10743
0x0084: 'SELECT.SPECIAL',
10744
0x0085: 'APPLY.NAMES',
10745
0x0086: 'REPLACE.FONT',
10746
0x0087: 'FREEZE.PANES',
10747
0x0088: 'SHOW.INFO',
10748
0x0089: 'SPLIT',
10749
0x008A: 'ON.WINDOW',
10750
0x008B: 'ON.DATA',
10751
0x008C: 'DISABLE.INPUT',
10752
0x008E: 'OUTLINE',
10753
0x008F: 'LIST.NAMES',
10754
0x0090: 'FILE.CLOSE',
10755
0x0091: 'SAVE.WORKBOOK',
10756
0x0092: 'DATA.FORM',
10757
0x0093: 'COPY.CHART',
10758
0x0094: 'ON.TIME',
10759
0x0095: 'WAIT',
10760
0x0096: 'FORMAT.FONT',
10761
0x0097: 'FILL.UP',
10762
0x0098: 'FILL.LEFT',
10763
0x0099: 'DELETE.OVERLAY',
10764
0x009B: 'SHORT.MENUS',
10765
0x009F: 'SET.UPDATE.STATUS',
10766
0x00A1: 'COLOR.PALETTE',
10767
0x00A2: 'DELETE.STYLE',
10768
0x00A3: 'WINDOW.RESTORE',
10769
0x00A4: 'WINDOW.MAXIMIZE',
10770
0x00A6: 'CHANGE.LINK',
10771
0x00A7: 'CALCULATE.DOCUMENT',
10772
0x00A8: 'ON.KEY',
10773
0x00A9: 'APP.RESTORE',
10774
0x00AA: 'APP.MOVE',
10775
0x00AB: 'APP.SIZE',
10776
0x00AC: 'APP.MINIMIZE',
10777
0x00AD: 'APP.MAXIMIZE',
10778
0x00AE: 'BRING.TO.FRONT',
10779
0x00AF: 'SEND.TO.BACK',
10780
0x00B9: 'MAIN.CHART.TYPE',
10781
0x00BA: 'OVERLAY.CHART.TYPE',
10782
0x00BB: 'SELECT.END',
10783
0x00BC: 'OPEN.MAIL',
10784
0x00BD: 'SEND.MAIL',
10785
0x00BE: 'STANDARD.FONT',
10786
0x00BF: 'CONSOLIDATE',
10787
0x00C0: 'SORT.SPECIAL',
10788
0x00C1: 'GALLERY.3D.AREA',
10789
0x00C2: 'GALLERY.3D.COLUMN',
10790
0x00C3: 'GALLERY.3D.LINE',
10791
0x00C4: 'GALLERY.3D.PIE',
10792
0x00C5: 'VIEW.3D',
10793
0x00C6: 'GOAL.SEEK',
10794
0x00C7: 'WORKGROUP',
10795
0x00C8: 'FILL.GROUP',
10796
0x00C9: 'UPDATE.LINK',
10797
0x00CA: 'PROMOTE',
10798
0x00CB: 'DEMOTE',
10799
0x00CC: 'SHOW.DETAIL',
10800
0x00CE: 'UNGROUP',
10801
0x00CF: 'OBJECT.PROPERTIES',
10802
0x00D0: 'SAVE.NEW.OBJECT',
10803
0x00D1: 'SHARE',
10804
0x00D2: 'SHARE.NAME',
10805
0x00D3: 'DUPLICATE',
10806
0x00D4: 'APPLY.STYLE',
10807
0x00D5: 'ASSIGN.TO.OBJECT',
10808
0x00D6: 'OBJECT.PROTECTION',
10809
0x00D7: 'HIDE.OBJECT',
10810
0x00D8: 'SET.EXTRACT',
10811
0x00D9: 'CREATE.PUBLISHER',
10812
0x00DA: 'SUBSCRIBE.TO',
10813
0x00DB: 'ATTRIBUTES',
10814
0x00DC: 'SHOW.TOOLBAR',
10815
0x00DE: 'PRINT.PREVIEW',
10816
0x00DF: 'EDIT.COLOR',
10817
0x00E0: 'SHOW.LEVELS',
10818
0x00E1: 'FORMAT.MAIN',
10819
0x00E2: 'FORMAT.OVERLAY',
10820
0x00E3: 'ON.RECALC',
10821
0x00E4: 'EDIT.SERIES',
10822
0x00E5: 'DEFINE.STYLE',
10823
0x00F0: 'LINE.PRINT',
10824
0x00F3: 'ENTER.DATA',
10825
0x00F9: 'GALLERY.RADAR',
10826
0x00FA: 'MERGE.STYLES',
10827
0x00FB: 'EDITION.OPTIONS',
10828
0x00FC: 'PASTE.PICTURE',
10829
0x00FD: 'PASTE.PICTURE.LINK',
10830
0x00FE: 'SPELLING',
10831
0x0100: 'ZOOM',
10832
0x0103: 'INSERT.OBJECT',
10833
0x0104: 'WINDOW.MINIMIZE',
10834
0x0109: 'SOUND.NOTE',
10835
0x010A: 'SOUND.PLAY',
10836
0x010B: 'FORMAT.SHAPE',
10837
0x010C: 'EXTEND.POLYGON',
10838
0x010D: 'FORMAT.AUTO',
10839
0x0110: 'GALLERY.3D.BAR',
10840
0x0111: 'GALLERY.3D.SURFACE',
10841
0x0112: 'FILL.AUTO',
10842
0x0114: 'CUSTOMIZE.TOOLBAR',
10843
0x0115: 'ADD.TOOL',
10844
0x0116: 'EDIT.OBJECT',
10845
0x0117: 'ON.DOUBLECLICK',
10846
0x0118: 'ON.ENTRY',
10847
0x0119: 'WORKBOOK.ADD',
10848
0x011A: 'WORKBOOK.MOVE',
10849
0x011B: 'WORKBOOK.COPY',
10850
0x011C: 'WORKBOOK.OPTIONS',
10851
0x011D: 'SAVE.WORKSPACE',
10852
0x0120: 'CHART.WIZARD',
10853
0x0121: 'DELETE.TOOL',
10854
0x0122: 'MOVE.TOOL',
10855
0x0123: 'WORKBOOK.SELECT',
10856
0x0124: 'WORKBOOK.ACTIVATE',
10857
0x0125: 'ASSIGN.TO.TOOL',
10858
0x0127: 'COPY.TOOL',
10859
0x0128: 'RESET.TOOL',
10860
0x0129: 'CONSTRAIN.NUMERIC',
10861
0x012A: 'PASTE.TOOL',
10862
0x012E: 'WORKBOOK.NEW',
10863
0x0131: 'SCENARIO.CELLS',
10864
0x0132: 'SCENARIO.DELETE',
10865
0x0133: 'SCENARIO.ADD',
10866
0x0134: 'SCENARIO.EDIT',
10867
0x0135: 'SCENARIO.SHOW',
10868
0x0136: 'SCENARIO.SHOW.NEXT',
10869
0x0137: 'SCENARIO.SUMMARY',
10870
0x0138: 'PIVOT.TABLE.WIZARD',
10871
0x0139: 'PIVOT.FIELD.PROPERTIES',
10872
0x013A: 'PIVOT.FIELD',
10873
0x013B: 'PIVOT.ITEM',
10874
0x013C: 'PIVOT.ADD.FIELDS',
10875
0x013E: 'OPTIONS.CALCULATION',
10876
0x013F: 'OPTIONS.EDIT',
10877
0x0140: 'OPTIONS.VIEW',
10878
0x0141: 'ADDIN.MANAGER',
10879
0x0142: 'MENU.EDITOR',
10880
0x0143: 'ATTACH.TOOLBARS',
10881
0x0144: 'VBAActivate',
10882
0x0145: 'OPTIONS.CHART',
10883
0x0148: 'VBA.INSERT.FILE',
10884
0x014A: 'VBA.PROCEDURE.DEFINITION',
10885
0x0150: 'ROUTING.SLIP',
10886
0x0152: 'ROUTE.DOCUMENT',
10887
0x0153: 'MAIL.LOGON',
10888
0x0156: 'INSERT.PICTURE',
10889
0x0157: 'EDIT.TOOL',
10890
0x0158: 'GALLERY.DOUGHNUT',
10891
0x015E: 'CHART.TREND',
10892
0x0160: 'PIVOT.ITEM.PROPERTIES',
10893
0x0162: 'WORKBOOK.INSERT',
10894
0x0163: 'OPTIONS.TRANSITION',
10895
0x0164: 'OPTIONS.GENERAL',
10896
0x0172: 'FILTER.ADVANCED',
10897
0x0175: 'MAIL.ADD.MAILER',
10898
0x0176: 'MAIL.DELETE.MAILER',
10899
0x0177: 'MAIL.REPLY',
10900
0x0178: 'MAIL.REPLY.ALL',
10901
0x0179: 'MAIL.FORWARD',
10902
0x017A: 'MAIL.NEXT.LETTER',
10903
0x017B: 'DATA.LABEL',
10904
0x017C: 'INSERT.TITLE',
10905
0x017D: 'FONT.PROPERTIES',
10906
0x017E: 'MACRO.OPTIONS',
10907
0x017F: 'WORKBOOK.HIDE',
10908
0x0180: 'WORKBOOK.UNHIDE',
10909
0x0181: 'WORKBOOK.DELETE',
10910
0x0182: 'WORKBOOK.NAME',
10911
0x0184: 'GALLERY.CUSTOM',
10912
0x0186: 'ADD.CHART.AUTOFORMAT',
10913
0x0187: 'DELETE.CHART.AUTOFORMAT',
10914
0x0188: 'CHART.ADD.DATA',
10915
0x0189: 'AUTO.OUTLINE',
10916
0x018A: 'TAB.ORDER',
10917
0x018B: 'SHOW.DIALOG',
10918
0x018C: 'SELECT.ALL',
10919
0x018D: 'UNGROUP.SHEETS',
10920
0x018E: 'SUBTOTAL.CREATE',
10921
0x018F: 'SUBTOTAL.REMOVE',
10922
0x0190: 'RENAME.OBJECT',
10923
0x019C: 'WORKBOOK.SCROLL',
10924
0x019D: 'WORKBOOK.NEXT',
10925
0x019E: 'WORKBOOK.PREV',
10926
0x019F: 'WORKBOOK.TAB.SPLIT',
10927
0x01A0: 'FULL.SCREEN',
10928
0x01A1: 'WORKBOOK.PROTECT',
10929
0x01A4: 'SCROLLBAR.PROPERTIES',
10930
0x01A5: 'PIVOT.SHOW.PAGES',
10931
0x01A6: 'TEXT.TO.COLUMNS',
10932
0x01A7: 'FORMAT.CHARTTYPE',
10933
0x01A8: 'LINK.FORMAT',
10934
0x01A9: 'TRACER.DISPLAY',
10935
0x01AE: 'TRACER.NAVIGATE',
10936
0x01AF: 'TRACER.CLEAR',
10937
0x01B0: 'TRACER.ERROR',
10938
0x01B1: 'PIVOT.FIELD.GROUP',
10939
0x01B2: 'PIVOT.FIELD.UNGROUP',
10940
0x01B3: 'CHECKBOX.PROPERTIES',
10941
0x01B4: 'LABEL.PROPERTIES',
10942
0x01B5: 'LISTBOX.PROPERTIES',
10943
0x01B6: 'EDITBOX.PROPERTIES',
10944
0x01B7: 'PIVOT.REFRESH',
10945
0x01B8: 'LINK.COMBO',
10946
0x01B9: 'OPEN.TEXT',
10947
0x01BA: 'HIDE.DIALOG',
10948
0x01BB: 'SET.DIALOG.FOCUS',
10949
0x01BC: 'ENABLE.OBJECT',
10950
0x01BD: 'PUSHBUTTON.PROPERTIES',
10951
0x01BE: 'SET.DIALOG.DEFAULT',
10952
0x01BF: 'FILTER',
10953
0x01C0: 'FILTER.SHOW.ALL',
10954
0x01C1: 'CLEAR.OUTLINE',
10955
0x01C2: 'FUNCTION.WIZARD',
10956
0x01C3: 'ADD.LIST.ITEM',
10957
0x01C4: 'SET.LIST.ITEM',
10958
0x01C5: 'REMOVE.LIST.ITEM',
10959
0x01C6: 'SELECT.LIST.ITEM',
10960
0x01C7: 'SET.CONTROL.VALUE',
10961
0x01C8: 'SAVE.COPY.AS',
10962
0x01CA: 'OPTIONS.LISTS.ADD',
10963
0x01CB: 'OPTIONS.LISTS.DELETE',
10964
0x01CC: 'SERIES.AXES',
10965
0x01CD: 'SERIES.X',
10966
0x01CE: 'SERIES.Y',
10967
0x01CF: 'ERRORBAR.X',
10968
0x01D0: 'ERRORBAR.Y',
10969
0x01D1: 'FORMAT.CHART',
10970
0x01D2: 'SERIES.ORDER',
10971
0x01D3: 'MAIL.LOGOFF',
10972
0x01D4: 'CLEAR.ROUTING.SLIP',
10973
0x01D5: 'APP.ACTIVATE.MICROSOFT',
10974
0x01D6: 'MAIL.EDIT.MAILER',
10975
0x01D7: 'ON.SHEET',
10976
0x01D8: 'STANDARD.WIDTH',
10977
0x01D9: 'SCENARIO.MERGE',
10978
0x01DA: 'SUMMARY.INFO',
10979
0x01DB: 'FIND.FILE',
10980
0x01DC: 'ACTIVE.CELL.FONT',
10981
0x01DD: 'ENABLE.TIPWIZARD',
10982
0x01DE: 'VBA.MAKE.ADDIN',
10983
0x01E0: 'INSERTDATATABLE',
10984
0x01E1: 'WORKGROUP.OPTIONS',
10985
0x01E2: 'MAIL.SEND.MAILER',
10986
0x01E5: 'AUTOCORRECT',
10987
0x01E9: 'POST.DOCUMENT',
10988
0x01EB: 'PICKLIST',
10989
0x01ED: 'VIEW.SHOW',
10990
0x01EE: 'VIEW.DEFINE',
10991
0x01EF: 'VIEW.DELETE',
10992
0x01FD: 'SHEET.BACKGROUND',
10993
0x01FE: 'INSERT.MAP.OBJECT',
10994
0x01FF: 'OPTIONS.MENONO',
10995
0x0205: 'MSOCHECKS',
10996
0x0206: 'NORMAL',
10997
0x0207: 'LAYOUT',
10998
0x0208: 'RM.PRINT.AREA',
10999
0x0209: 'CLEAR.PRINT.AREA',
11000
0x020A: 'ADD.PRINT.AREA',
11001
0x020B: 'MOVE.BRK',
11002
0x0221: 'HIDECURR.NOTE',
11003
0x0222: 'HIDEALL.NOTES',
11004
0x0223: 'DELETE.NOTE',
11005
0x0224: 'TRAVERSE.NOTES',
11006
0x0225: 'ACTIVATE.NOTES',
11007
0x026C: 'PROTECT.REVISIONS',
11008
0x026D: 'UNPROTECT.REVISIONS',
11009
0x0287: 'OPTIONS.ME',
11010
0x028D: 'WEB.PUBLISH',
11011
0x029B: 'NEWWEBQUERY',
11012
0x02A1: 'PIVOT.TABLE.CHART',
11013
0x02F1: 'OPTIONS.SAVE',
11014
0x02F3: 'OPTIONS.SPELL',
11015
0x0328: 'HIDEALL.INKANNOTS'
11016
};
11017
11018
/* [MS-XLS] 2.5.198.17 */
11019
/* [MS-XLSB] 2.5.97.10 */
11020
var Ftab = {
11021
0x0000: 'COUNT',
11022
0x0001: 'IF',
11023
0x0002: 'ISNA',
11024
0x0003: 'ISERROR',
11025
0x0004: 'SUM',
11026
0x0005: 'AVERAGE',
11027
0x0006: 'MIN',
11028
0x0007: 'MAX',
11029
0x0008: 'ROW',
11030
0x0009: 'COLUMN',
11031
0x000A: 'NA',
11032
0x000B: 'NPV',
11033
0x000C: 'STDEV',
11034
0x000D: 'DOLLAR',
11035
0x000E: 'FIXED',
11036
0x000F: 'SIN',
11037
0x0010: 'COS',
11038
0x0011: 'TAN',
11039
0x0012: 'ATAN',
11040
0x0013: 'PI',
11041
0x0014: 'SQRT',
11042
0x0015: 'EXP',
11043
0x0016: 'LN',
11044
0x0017: 'LOG10',
11045
0x0018: 'ABS',
11046
0x0019: 'INT',
11047
0x001A: 'SIGN',
11048
0x001B: 'ROUND',
11049
0x001C: 'LOOKUP',
11050
0x001D: 'INDEX',
11051
0x001E: 'REPT',
11052
0x001F: 'MID',
11053
0x0020: 'LEN',
11054
0x0021: 'VALUE',
11055
0x0022: 'TRUE',
11056
0x0023: 'FALSE',
11057
0x0024: 'AND',
11058
0x0025: 'OR',
11059
0x0026: 'NOT',
11060
0x0027: 'MOD',
11061
0x0028: 'DCOUNT',
11062
0x0029: 'DSUM',
11063
0x002A: 'DAVERAGE',
11064
0x002B: 'DMIN',
11065
0x002C: 'DMAX',
11066
0x002D: 'DSTDEV',
11067
0x002E: 'VAR',
11068
0x002F: 'DVAR',
11069
0x0030: 'TEXT',
11070
0x0031: 'LINEST',
11071
0x0032: 'TREND',
11072
0x0033: 'LOGEST',
11073
0x0034: 'GROWTH',
11074
0x0035: 'GOTO',
11075
0x0036: 'HALT',
11076
0x0037: 'RETURN',
11077
0x0038: 'PV',
11078
0x0039: 'FV',
11079
0x003A: 'NPER',
11080
0x003B: 'PMT',
11081
0x003C: 'RATE',
11082
0x003D: 'MIRR',
11083
0x003E: 'IRR',
11084
0x003F: 'RAND',
11085
0x0040: 'MATCH',
11086
0x0041: 'DATE',
11087
0x0042: 'TIME',
11088
0x0043: 'DAY',
11089
0x0044: 'MONTH',
11090
0x0045: 'YEAR',
11091
0x0046: 'WEEKDAY',
11092
0x0047: 'HOUR',
11093
0x0048: 'MINUTE',
11094
0x0049: 'SECOND',
11095
0x004A: 'NOW',
11096
0x004B: 'AREAS',
11097
0x004C: 'ROWS',
11098
0x004D: 'COLUMNS',
11099
0x004E: 'OFFSET',
11100
0x004F: 'ABSREF',
11101
0x0050: 'RELREF',
11102
0x0051: 'ARGUMENT',
11103
0x0052: 'SEARCH',
11104
0x0053: 'TRANSPOSE',
11105
0x0054: 'ERROR',
11106
0x0055: 'STEP',
11107
0x0056: 'TYPE',
11108
0x0057: 'ECHO',
11109
0x0058: 'SET.NAME',
11110
0x0059: 'CALLER',
11111
0x005A: 'DEREF',
11112
0x005B: 'WINDOWS',
11113
0x005C: 'SERIES',
11114
0x005D: 'DOCUMENTS',
11115
0x005E: 'ACTIVE.CELL',
11116
0x005F: 'SELECTION',
11117
0x0060: 'RESULT',
11118
0x0061: 'ATAN2',
11119
0x0062: 'ASIN',
11120
0x0063: 'ACOS',
11121
0x0064: 'CHOOSE',
11122
0x0065: 'HLOOKUP',
11123
0x0066: 'VLOOKUP',
11124
0x0067: 'LINKS',
11125
0x0068: 'INPUT',
11126
0x0069: 'ISREF',
11127
0x006A: 'GET.FORMULA',
11128
0x006B: 'GET.NAME',
11129
0x006C: 'SET.VALUE',
11130
0x006D: 'LOG',
11131
0x006E: 'EXEC',
11132
0x006F: 'CHAR',
11133
0x0070: 'LOWER',
11134
0x0071: 'UPPER',
11135
0x0072: 'PROPER',
11136
0x0073: 'LEFT',
11137
0x0074: 'RIGHT',
11138
0x0075: 'EXACT',
11139
0x0076: 'TRIM',
11140
0x0077: 'REPLACE',
11141
0x0078: 'SUBSTITUTE',
11142
0x0079: 'CODE',
11143
0x007A: 'NAMES',
11144
0x007B: 'DIRECTORY',
11145
0x007C: 'FIND',
11146
0x007D: 'CELL',
11147
0x007E: 'ISERR',
11148
0x007F: 'ISTEXT',
11149
0x0080: 'ISNUMBER',
11150
0x0081: 'ISBLANK',
11151
0x0082: 'T',
11152
0x0083: 'N',
11153
0x0084: 'FOPEN',
11154
0x0085: 'FCLOSE',
11155
0x0086: 'FSIZE',
11156
0x0087: 'FREADLN',
11157
0x0088: 'FREAD',
11158
0x0089: 'FWRITELN',
11159
0x008A: 'FWRITE',
11160
0x008B: 'FPOS',
11161
0x008C: 'DATEVALUE',
11162
0x008D: 'TIMEVALUE',
11163
0x008E: 'SLN',
11164
0x008F: 'SYD',
11165
0x0090: 'DDB',
11166
0x0091: 'GET.DEF',
11167
0x0092: 'REFTEXT',
11168
0x0093: 'TEXTREF',
11169
0x0094: 'INDIRECT',
11170
0x0095: 'REGISTER',
11171
0x0096: 'CALL',
11172
0x0097: 'ADD.BAR',
11173
0x0098: 'ADD.MENU',
11174
0x0099: 'ADD.COMMAND',
11175
0x009A: 'ENABLE.COMMAND',
11176
0x009B: 'CHECK.COMMAND',
11177
0x009C: 'RENAME.COMMAND',
11178
0x009D: 'SHOW.BAR',
11179
0x009E: 'DELETE.MENU',
11180
0x009F: 'DELETE.COMMAND',
11181
0x00A0: 'GET.CHART.ITEM',
11182
0x00A1: 'DIALOG.BOX',
11183
0x00A2: 'CLEAN',
11184
0x00A3: 'MDETERM',
11185
0x00A4: 'MINVERSE',
11186
0x00A5: 'MMULT',
11187
0x00A6: 'FILES',
11188
0x00A7: 'IPMT',
11189
0x00A8: 'PPMT',
11190
0x00A9: 'COUNTA',
11191
0x00AA: 'CANCEL.KEY',
11192
0x00AB: 'FOR',
11193
0x00AC: 'WHILE',
11194
0x00AD: 'BREAK',
11195
0x00AE: 'NEXT',
11196
0x00AF: 'INITIATE',
11197
0x00B0: 'REQUEST',
11198
0x00B1: 'POKE',
11199
0x00B2: 'EXECUTE',
11200
0x00B3: 'TERMINATE',
11201
0x00B4: 'RESTART',
11202
0x00B5: 'HELP',
11203
0x00B6: 'GET.BAR',
11204
0x00B7: 'PRODUCT',
11205
0x00B8: 'FACT',
11206
0x00B9: 'GET.CELL',
11207
0x00BA: 'GET.WORKSPACE',
11208
0x00BB: 'GET.WINDOW',
11209
0x00BC: 'GET.DOCUMENT',
11210
0x00BD: 'DPRODUCT',
11211
0x00BE: 'ISNONTEXT',
11212
0x00BF: 'GET.NOTE',
11213
0x00C0: 'NOTE',
11214
0x00C1: 'STDEVP',
11215
0x00C2: 'VARP',
11216
0x00C3: 'DSTDEVP',
11217
0x00C4: 'DVARP',
11218
0x00C5: 'TRUNC',
11219
0x00C6: 'ISLOGICAL',
11220
0x00C7: 'DCOUNTA',
11221
0x00C8: 'DELETE.BAR',
11222
0x00C9: 'UNREGISTER',
11223
0x00CC: 'USDOLLAR',
11224
0x00CD: 'FINDB',
11225
0x00CE: 'SEARCHB',
11226
0x00CF: 'REPLACEB',
11227
0x00D0: 'LEFTB',
11228
0x00D1: 'RIGHTB',
11229
0x00D2: 'MIDB',
11230
0x00D3: 'LENB',
11231
0x00D4: 'ROUNDUP',
11232
0x00D5: 'ROUNDDOWN',
11233
0x00D6: 'ASC',
11234
0x00D7: 'DBCS',
11235
0x00D8: 'RANK',
11236
0x00DB: 'ADDRESS',
11237
0x00DC: 'DAYS360',
11238
0x00DD: 'TODAY',
11239
0x00DE: 'VDB',
11240
0x00DF: 'ELSE',
11241
0x00E0: 'ELSE.IF',
11242
0x00E1: 'END.IF',
11243
0x00E2: 'FOR.CELL',
11244
0x00E3: 'MEDIAN',
11245
0x00E4: 'SUMPRODUCT',
11246
0x00E5: 'SINH',
11247
0x00E6: 'COSH',
11248
0x00E7: 'TANH',
11249
0x00E8: 'ASINH',
11250
0x00E9: 'ACOSH',
11251
0x00EA: 'ATANH',
11252
0x00EB: 'DGET',
11253
0x00EC: 'CREATE.OBJECT',
11254
0x00ED: 'VOLATILE',
11255
0x00EE: 'LAST.ERROR',
11256
0x00EF: 'CUSTOM.UNDO',
11257
0x00F0: 'CUSTOM.REPEAT',
11258
0x00F1: 'FORMULA.CONVERT',
11259
0x00F2: 'GET.LINK.INFO',
11260
0x00F3: 'TEXT.BOX',
11261
0x00F4: 'INFO',
11262
0x00F5: 'GROUP',
11263
0x00F6: 'GET.OBJECT',
11264
0x00F7: 'DB',
11265
0x00F8: 'PAUSE',
11266
0x00FB: 'RESUME',
11267
0x00FC: 'FREQUENCY',
11268
0x00FD: 'ADD.TOOLBAR',
11269
0x00FE: 'DELETE.TOOLBAR',
11270
0x00FF: 'User',
11271
0x0100: 'RESET.TOOLBAR',
11272
0x0101: 'EVALUATE',
11273
0x0102: 'GET.TOOLBAR',
11274
0x0103: 'GET.TOOL',
11275
0x0104: 'SPELLING.CHECK',
11276
0x0105: 'ERROR.TYPE',
11277
0x0106: 'APP.TITLE',
11278
0x0107: 'WINDOW.TITLE',
11279
0x0108: 'SAVE.TOOLBAR',
11280
0x0109: 'ENABLE.TOOL',
11281
0x010A: 'PRESS.TOOL',
11282
0x010B: 'REGISTER.ID',
11283
0x010C: 'GET.WORKBOOK',
11284
0x010D: 'AVEDEV',
11285
0x010E: 'BETADIST',
11286
0x010F: 'GAMMALN',
11287
0x0110: 'BETAINV',
11288
0x0111: 'BINOMDIST',
11289
0x0112: 'CHIDIST',
11290
0x0113: 'CHIINV',
11291
0x0114: 'COMBIN',
11292
0x0115: 'CONFIDENCE',
11293
0x0116: 'CRITBINOM',
11294
0x0117: 'EVEN',
11295
0x0118: 'EXPONDIST',
11296
0x0119: 'FDIST',
11297
0x011A: 'FINV',
11298
0x011B: 'FISHER',
11299
0x011C: 'FISHERINV',
11300
0x011D: 'FLOOR',
11301
0x011E: 'GAMMADIST',
11302
0x011F: 'GAMMAINV',
11303
0x0120: 'CEILING',
11304
0x0121: 'HYPGEOMDIST',
11305
0x0122: 'LOGNORMDIST',
11306
0x0123: 'LOGINV',
11307
0x0124: 'NEGBINOMDIST',
11308
0x0125: 'NORMDIST',
11309
0x0126: 'NORMSDIST',
11310
0x0127: 'NORMINV',
11311
0x0128: 'NORMSINV',
11312
0x0129: 'STANDARDIZE',
11313
0x012A: 'ODD',
11314
0x012B: 'PERMUT',
11315
0x012C: 'POISSON',
11316
0x012D: 'TDIST',
11317
0x012E: 'WEIBULL',
11318
0x012F: 'SUMXMY2',
11319
0x0130: 'SUMX2MY2',
11320
0x0131: 'SUMX2PY2',
11321
0x0132: 'CHITEST',
11322
0x0133: 'CORREL',
11323
0x0134: 'COVAR',
11324
0x0135: 'FORECAST',
11325
0x0136: 'FTEST',
11326
0x0137: 'INTERCEPT',
11327
0x0138: 'PEARSON',
11328
0x0139: 'RSQ',
11329
0x013A: 'STEYX',
11330
0x013B: 'SLOPE',
11331
0x013C: 'TTEST',
11332
0x013D: 'PROB',
11333
0x013E: 'DEVSQ',
11334
0x013F: 'GEOMEAN',
11335
0x0140: 'HARMEAN',
11336
0x0141: 'SUMSQ',
11337
0x0142: 'KURT',
11338
0x0143: 'SKEW',
11339
0x0144: 'ZTEST',
11340
0x0145: 'LARGE',
11341
0x0146: 'SMALL',
11342
0x0147: 'QUARTILE',
11343
0x0148: 'PERCENTILE',
11344
0x0149: 'PERCENTRANK',
11345
0x014A: 'MODE',
11346
0x014B: 'TRIMMEAN',
11347
0x014C: 'TINV',
11348
0x014E: 'MOVIE.COMMAND',
11349
0x014F: 'GET.MOVIE',
11350
0x0150: 'CONCATENATE',
11351
0x0151: 'POWER',
11352
0x0152: 'PIVOT.ADD.DATA',
11353
0x0153: 'GET.PIVOT.TABLE',
11354
0x0154: 'GET.PIVOT.FIELD',
11355
0x0155: 'GET.PIVOT.ITEM',
11356
0x0156: 'RADIANS',
11357
0x0157: 'DEGREES',
11358
0x0158: 'SUBTOTAL',
11359
0x0159: 'SUMIF',
11360
0x015A: 'COUNTIF',
11361
0x015B: 'COUNTBLANK',
11362
0x015C: 'SCENARIO.GET',
11363
0x015D: 'OPTIONS.LISTS.GET',
11364
0x015E: 'ISPMT',
11365
0x015F: 'DATEDIF',
11366
0x0160: 'DATESTRING',
11367
0x0161: 'NUMBERSTRING',
11368
0x0162: 'ROMAN',
11369
0x0163: 'OPEN.DIALOG',
11370
0x0164: 'SAVE.DIALOG',
11371
0x0165: 'VIEW.GET',
11372
0x0166: 'GETPIVOTDATA',
11373
0x0167: 'HYPERLINK',
11374
0x0168: 'PHONETIC',
11375
0x0169: 'AVERAGEA',
11376
0x016A: 'MAXA',
11377
0x016B: 'MINA',
11378
0x016C: 'STDEVPA',
11379
0x016D: 'VARPA',
11380
0x016E: 'STDEVA',
11381
0x016F: 'VARA',
11382
0x0170: 'BAHTTEXT',
11383
0x0171: 'THAIDAYOFWEEK',
11384
0x0172: 'THAIDIGIT',
11385
0x0173: 'THAIMONTHOFYEAR',
11386
0x0174: 'THAINUMSOUND',
11387
0x0175: 'THAINUMSTRING',
11388
0x0176: 'THAISTRINGLENGTH',
11389
0x0177: 'ISTHAIDIGIT',
11390
0x0178: 'ROUNDBAHTDOWN',
11391
0x0179: 'ROUNDBAHTUP',
11392
0x017A: 'THAIYEAR',
11393
0x017B: 'RTD',
11394
11395
0x017C: 'CUBEVALUE',
11396
0x017D: 'CUBEMEMBER',
11397
0x017E: 'CUBEMEMBERPROPERTY',
11398
0x017F: 'CUBERANKEDMEMBER',
11399
0x0180: 'HEX2BIN',
11400
0x0181: 'HEX2DEC',
11401
0x0182: 'HEX2OCT',
11402
0x0183: 'DEC2BIN',
11403
0x0184: 'DEC2HEX',
11404
0x0185: 'DEC2OCT',
11405
0x0186: 'OCT2BIN',
11406
0x0187: 'OCT2HEX',
11407
0x0188: 'OCT2DEC',
11408
0x0189: 'BIN2DEC',
11409
0x018A: 'BIN2OCT',
11410
0x018B: 'BIN2HEX',
11411
0x018C: 'IMSUB',
11412
0x018D: 'IMDIV',
11413
0x018E: 'IMPOWER',
11414
0x018F: 'IMABS',
11415
0x0190: 'IMSQRT',
11416
0x0191: 'IMLN',
11417
0x0192: 'IMLOG2',
11418
0x0193: 'IMLOG10',
11419
0x0194: 'IMSIN',
11420
0x0195: 'IMCOS',
11421
0x0196: 'IMEXP',
11422
0x0197: 'IMARGUMENT',
11423
0x0198: 'IMCONJUGATE',
11424
0x0199: 'IMAGINARY',
11425
0x019A: 'IMREAL',
11426
0x019B: 'COMPLEX',
11427
0x019C: 'IMSUM',
11428
0x019D: 'IMPRODUCT',
11429
0x019E: 'SERIESSUM',
11430
0x019F: 'FACTDOUBLE',
11431
0x01A0: 'SQRTPI',
11432
0x01A1: 'QUOTIENT',
11433
0x01A2: 'DELTA',
11434
0x01A3: 'GESTEP',
11435
0x01A4: 'ISEVEN',
11436
0x01A5: 'ISODD',
11437
0x01A6: 'MROUND',
11438
0x01A7: 'ERF',
11439
0x01A8: 'ERFC',
11440
0x01A9: 'BESSELJ',
11441
0x01AA: 'BESSELK',
11442
0x01AB: 'BESSELY',
11443
0x01AC: 'BESSELI',
11444
0x01AD: 'XIRR',
11445
0x01AE: 'XNPV',
11446
0x01AF: 'PRICEMAT',
11447
0x01B0: 'YIELDMAT',
11448
0x01B1: 'INTRATE',
11449
0x01B2: 'RECEIVED',
11450
0x01B3: 'DISC',
11451
0x01B4: 'PRICEDISC',
11452
0x01B5: 'YIELDDISC',
11453
0x01B6: 'TBILLEQ',
11454
0x01B7: 'TBILLPRICE',
11455
0x01B8: 'TBILLYIELD',
11456
0x01B9: 'PRICE',
11457
0x01BA: 'YIELD',
11458
0x01BB: 'DOLLARDE',
11459
0x01BC: 'DOLLARFR',
11460
0x01BD: 'NOMINAL',
11461
0x01BE: 'EFFECT',
11462
0x01BF: 'CUMPRINC',
11463
0x01C0: 'CUMIPMT',
11464
0x01C1: 'EDATE',
11465
0x01C2: 'EOMONTH',
11466
0x01C3: 'YEARFRAC',
11467
0x01C4: 'COUPDAYBS',
11468
0x01C5: 'COUPDAYS',
11469
0x01C6: 'COUPDAYSNC',
11470
0x01C7: 'COUPNCD',
11471
0x01C8: 'COUPNUM',
11472
0x01C9: 'COUPPCD',
11473
0x01CA: 'DURATION',
11474
0x01CB: 'MDURATION',
11475
0x01CC: 'ODDLPRICE',
11476
0x01CD: 'ODDLYIELD',
11477
0x01CE: 'ODDFPRICE',
11478
0x01CF: 'ODDFYIELD',
11479
0x01D0: 'RANDBETWEEN',
11480
0x01D1: 'WEEKNUM',
11481
0x01D2: 'AMORDEGRC',
11482
0x01D3: 'AMORLINC',
11483
0x01D4: 'CONVERT',
11484
0x02D4: 'SHEETJS',
11485
0x01D5: 'ACCRINT',
11486
0x01D6: 'ACCRINTM',
11487
0x01D7: 'WORKDAY',
11488
0x01D8: 'NETWORKDAYS',
11489
0x01D9: 'GCD',
11490
0x01DA: 'MULTINOMIAL',
11491
0x01DB: 'LCM',
11492
0x01DC: 'FVSCHEDULE',
11493
0x01DD: 'CUBEKPIMEMBER',
11494
0x01DE: 'CUBESET',
11495
0x01DF: 'CUBESETCOUNT',
11496
0x01E0: 'IFERROR',
11497
0x01E1: 'COUNTIFS',
11498
0x01E2: 'SUMIFS',
11499
0x01E3: 'AVERAGEIF',
11500
0x01E4: 'AVERAGEIFS'
11501
};
11502
var FtabArgc = {
11503
0x0002: 1, /* ISNA */
11504
0x0003: 1, /* ISERROR */
11505
0x000A: 0, /* NA */
11506
0x000F: 1, /* SIN */
11507
0x0010: 1, /* COS */
11508
0x0011: 1, /* TAN */
11509
0x0012: 1, /* ATAN */
11510
0x0013: 0, /* PI */
11511
0x0014: 1, /* SQRT */
11512
0x0015: 1, /* EXP */
11513
0x0016: 1, /* LN */
11514
0x0017: 1, /* LOG10 */
11515
0x0018: 1, /* ABS */
11516
0x0019: 1, /* INT */
11517
0x001A: 1, /* SIGN */
11518
0x001B: 2, /* ROUND */
11519
0x001E: 2, /* REPT */
11520
0x001F: 3, /* MID */
11521
0x0020: 1, /* LEN */
11522
0x0021: 1, /* VALUE */
11523
0x0022: 0, /* TRUE */
11524
0x0023: 0, /* FALSE */
11525
0x0026: 1, /* NOT */
11526
0x0027: 2, /* MOD */
11527
0x0028: 3, /* DCOUNT */
11528
0x0029: 3, /* DSUM */
11529
0x002A: 3, /* DAVERAGE */
11530
0x002B: 3, /* DMIN */
11531
0x002C: 3, /* DMAX */
11532
0x002D: 3, /* DSTDEV */
11533
0x002F: 3, /* DVAR */
11534
0x0030: 2, /* TEXT */
11535
0x0035: 1, /* GOTO */
11536
0x003D: 3, /* MIRR */
11537
0x003F: 0, /* RAND */
11538
0x0041: 3, /* DATE */
11539
0x0042: 3, /* TIME */
11540
0x0043: 1, /* DAY */
11541
0x0044: 1, /* MONTH */
11542
0x0045: 1, /* YEAR */
11543
0x0046: 1, /* WEEKDAY */
11544
0x0047: 1, /* HOUR */
11545
0x0048: 1, /* MINUTE */
11546
0x0049: 1, /* SECOND */
11547
0x004A: 0, /* NOW */
11548
0x004B: 1, /* AREAS */
11549
0x004C: 1, /* ROWS */
11550
0x004D: 1, /* COLUMNS */
11551
0x004F: 2, /* ABSREF */
11552
0x0050: 2, /* RELREF */
11553
0x0053: 1, /* TRANSPOSE */
11554
0x0055: 0, /* STEP */
11555
0x0056: 1, /* TYPE */
11556
0x0059: 0, /* CALLER */
11557
0x005A: 1, /* DEREF */
11558
0x005E: 0, /* ACTIVE.CELL */
11559
0x005F: 0, /* SELECTION */
11560
0x0061: 2, /* ATAN2 */
11561
0x0062: 1, /* ASIN */
11562
0x0063: 1, /* ACOS */
11563
0x0065: 3, /* HLOOKUP */
11564
0x0066: 3, /* VLOOKUP */
11565
0x0069: 1, /* ISREF */
11566
0x006A: 1, /* GET.FORMULA */
11567
0x006C: 2, /* SET.VALUE */
11568
0x006F: 1, /* CHAR */
11569
0x0070: 1, /* LOWER */
11570
0x0071: 1, /* UPPER */
11571
0x0072: 1, /* PROPER */
11572
0x0075: 2, /* EXACT */
11573
0x0076: 1, /* TRIM */
11574
0x0077: 4, /* REPLACE */
11575
0x0079: 1, /* CODE */
11576
0x007E: 1, /* ISERR */
11577
0x007F: 1, /* ISTEXT */
11578
0x0080: 1, /* ISNUMBER */
11579
0x0081: 1, /* ISBLANK */
11580
0x0082: 1, /* T */
11581
0x0083: 1, /* N */
11582
0x0085: 1, /* FCLOSE */
11583
0x0086: 1, /* FSIZE */
11584
0x0087: 1, /* FREADLN */
11585
0x0088: 2, /* FREAD */
11586
0x0089: 2, /* FWRITELN */
11587
0x008A: 2, /* FWRITE */
11588
0x008C: 1, /* DATEVALUE */
11589
0x008D: 1, /* TIMEVALUE */
11590
0x008E: 3, /* SLN */
11591
0x008F: 4, /* SYD */
11592
0x0090: 4, /* DDB */
11593
0x00A1: 1, /* DIALOG.BOX */
11594
0x00A2: 1, /* CLEAN */
11595
0x00A3: 1, /* MDETERM */
11596
0x00A4: 1, /* MINVERSE */
11597
0x00A5: 2, /* MMULT */
11598
0x00AC: 1, /* WHILE */
11599
0x00AF: 2, /* INITIATE */
11600
0x00B0: 2, /* REQUEST */
11601
0x00B1: 3, /* POKE */
11602
0x00B2: 2, /* EXECUTE */
11603
0x00B3: 1, /* TERMINATE */
11604
0x00B8: 1, /* FACT */
11605
0x00BA: 1, /* GET.WORKSPACE */
11606
0x00BD: 3, /* DPRODUCT */
11607
0x00BE: 1, /* ISNONTEXT */
11608
0x00C3: 3, /* DSTDEVP */
11609
0x00C4: 3, /* DVARP */
11610
0x00C5: 1, /* TRUNC */
11611
0x00C6: 1, /* ISLOGICAL */
11612
0x00C7: 3, /* DCOUNTA */
11613
0x00C9: 1, /* UNREGISTER */
11614
0x00CF: 4, /* REPLACEB */
11615
0x00D2: 3, /* MIDB */
11616
0x00D3: 1, /* LENB */
11617
0x00D4: 2, /* ROUNDUP */
11618
0x00D5: 2, /* ROUNDDOWN */
11619
0x00D6: 1, /* ASC */
11620
0x00D7: 1, /* DBCS */
11621
0x00E1: 0, /* END.IF */
11622
0x00E5: 1, /* SINH */
11623
0x00E6: 1, /* COSH */
11624
0x00E7: 1, /* TANH */
11625
0x00E8: 1, /* ASINH */
11626
0x00E9: 1, /* ACOSH */
11627
0x00EA: 1, /* ATANH */
11628
0x00EB: 3, /* DGET */
11629
0x00F4: 1, /* INFO */
11630
0x00F7: 4, /* DB */
11631
0x00FC: 2, /* FREQUENCY */
11632
0x0101: 1, /* EVALUATE */
11633
0x0105: 1, /* ERROR.TYPE */
11634
0x010F: 1, /* GAMMALN */
11635
0x0111: 4, /* BINOMDIST */
11636
0x0112: 2, /* CHIDIST */
11637
0x0113: 2, /* CHIINV */
11638
0x0114: 2, /* COMBIN */
11639
0x0115: 3, /* CONFIDENCE */
11640
0x0116: 3, /* CRITBINOM */
11641
0x0117: 1, /* EVEN */
11642
0x0118: 3, /* EXPONDIST */
11643
0x0119: 3, /* FDIST */
11644
0x011A: 3, /* FINV */
11645
0x011B: 1, /* FISHER */
11646
0x011C: 1, /* FISHERINV */
11647
0x011D: 2, /* FLOOR */
11648
0x011E: 4, /* GAMMADIST */
11649
0x011F: 3, /* GAMMAINV */
11650
0x0120: 2, /* CEILING */
11651
0x0121: 4, /* HYPGEOMDIST */
11652
0x0122: 3, /* LOGNORMDIST */
11653
0x0123: 3, /* LOGINV */
11654
0x0124: 3, /* NEGBINOMDIST */
11655
0x0125: 4, /* NORMDIST */
11656
0x0126: 1, /* NORMSDIST */
11657
0x0127: 3, /* NORMINV */
11658
0x0128: 1, /* NORMSINV */
11659
0x0129: 3, /* STANDARDIZE */
11660
0x012A: 1, /* ODD */
11661
0x012B: 2, /* PERMUT */
11662
0x012C: 3, /* POISSON */
11663
0x012D: 3, /* TDIST */
11664
0x012E: 4, /* WEIBULL */
11665
0x012F: 2, /* SUMXMY2 */
11666
0x0130: 2, /* SUMX2MY2 */
11667
0x0131: 2, /* SUMX2PY2 */
11668
0x0132: 2, /* CHITEST */
11669
0x0133: 2, /* CORREL */
11670
0x0134: 2, /* COVAR */
11671
0x0135: 3, /* FORECAST */
11672
0x0136: 2, /* FTEST */
11673
0x0137: 2, /* INTERCEPT */
11674
0x0138: 2, /* PEARSON */
11675
0x0139: 2, /* RSQ */
11676
0x013A: 2, /* STEYX */
11677
0x013B: 2, /* SLOPE */
11678
0x013C: 4, /* TTEST */
11679
0x0145: 2, /* LARGE */
11680
0x0146: 2, /* SMALL */
11681
0x0147: 2, /* QUARTILE */
11682
0x0148: 2, /* PERCENTILE */
11683
0x014B: 2, /* TRIMMEAN */
11684
0x014C: 2, /* TINV */
11685
0x0151: 2, /* POWER */
11686
0x0156: 1, /* RADIANS */
11687
0x0157: 1, /* DEGREES */
11688
0x015A: 2, /* COUNTIF */
11689
0x015B: 1, /* COUNTBLANK */
11690
0x015E: 4, /* ISPMT */
11691
0x015F: 3, /* DATEDIF */
11692
0x0160: 1, /* DATESTRING */
11693
0x0161: 2, /* NUMBERSTRING */
11694
0x0168: 1, /* PHONETIC */
11695
0x0170: 1, /* BAHTTEXT */
11696
0x0171: 1, /* THAIDAYOFWEEK */
11697
0x0172: 1, /* THAIDIGIT */
11698
0x0173: 1, /* THAIMONTHOFYEAR */
11699
0x0174: 1, /* THAINUMSOUND */
11700
0x0175: 1, /* THAINUMSTRING */
11701
0x0176: 1, /* THAISTRINGLENGTH */
11702
0x0177: 1, /* ISTHAIDIGIT */
11703
0x0178: 1, /* ROUNDBAHTDOWN */
11704
0x0179: 1, /* ROUNDBAHTUP */
11705
0x017A: 1, /* THAIYEAR */
11706
0x017E: 3, /* CUBEMEMBERPROPERTY */
11707
0x0181: 1, /* HEX2DEC */
11708
0x0188: 1, /* OCT2DEC */
11709
0x0189: 1, /* BIN2DEC */
11710
0x018C: 2, /* IMSUB */
11711
0x018D: 2, /* IMDIV */
11712
0x018E: 2, /* IMPOWER */
11713
0x018F: 1, /* IMABS */
11714
0x0190: 1, /* IMSQRT */
11715
0x0191: 1, /* IMLN */
11716
0x0192: 1, /* IMLOG2 */
11717
0x0193: 1, /* IMLOG10 */
11718
0x0194: 1, /* IMSIN */
11719
0x0195: 1, /* IMCOS */
11720
0x0196: 1, /* IMEXP */
11721
0x0197: 1, /* IMARGUMENT */
11722
0x0198: 1, /* IMCONJUGATE */
11723
0x0199: 1, /* IMAGINARY */
11724
0x019A: 1, /* IMREAL */
11725
0x019E: 4, /* SERIESSUM */
11726
0x019F: 1, /* FACTDOUBLE */
11727
0x01A0: 1, /* SQRTPI */
11728
0x01A1: 2, /* QUOTIENT */
11729
0x01A4: 1, /* ISEVEN */
11730
0x01A5: 1, /* ISODD */
11731
0x01A6: 2, /* MROUND */
11732
0x01A8: 1, /* ERFC */
11733
0x01A9: 2, /* BESSELJ */
11734
0x01AA: 2, /* BESSELK */
11735
0x01AB: 2, /* BESSELY */
11736
0x01AC: 2, /* BESSELI */
11737
0x01AE: 3, /* XNPV */
11738
0x01B6: 3, /* TBILLEQ */
11739
0x01B7: 3, /* TBILLPRICE */
11740
0x01B8: 3, /* TBILLYIELD */
11741
0x01BB: 2, /* DOLLARDE */
11742
0x01BC: 2, /* DOLLARFR */
11743
0x01BD: 2, /* NOMINAL */
11744
0x01BE: 2, /* EFFECT */
11745
0x01BF: 6, /* CUMPRINC */
11746
0x01C0: 6, /* CUMIPMT */
11747
0x01C1: 2, /* EDATE */
11748
0x01C2: 2, /* EOMONTH */
11749
0x01D0: 2, /* RANDBETWEEN */
11750
0x01D4: 3, /* CONVERT */
11751
0x01DC: 2, /* FVSCHEDULE */
11752
0x01DF: 1, /* CUBESETCOUNT */
11753
0x01E0: 2, /* IFERROR */
11754
0xFFFF: 0
11755
};
11756
/* [MS-XLSX] 2.2.3 Functions */
11757
/* [MS-XLSB] 2.5.97.10 Ftab */
11758
var XLSXFutureFunctions = {
11759
	"_xlfn.ACOT": "ACOT",
11760
	"_xlfn.ACOTH": "ACOTH",
11761
	"_xlfn.AGGREGATE": "AGGREGATE",
11762
	"_xlfn.ARABIC": "ARABIC",
11763
	"_xlfn.AVERAGEIF": "AVERAGEIF",
11764
	"_xlfn.AVERAGEIFS": "AVERAGEIFS",
11765
	"_xlfn.BASE": "BASE",
11766
	"_xlfn.BETA.DIST": "BETA.DIST",
11767
	"_xlfn.BETA.INV": "BETA.INV",
11768
	"_xlfn.BINOM.DIST": "BINOM.DIST",
11769
	"_xlfn.BINOM.DIST.RANGE": "BINOM.DIST.RANGE",
11770
	"_xlfn.BINOM.INV": "BINOM.INV",
11771
	"_xlfn.BITAND": "BITAND",
11772
	"_xlfn.BITLSHIFT": "BITLSHIFT",
11773
	"_xlfn.BITOR": "BITOR",
11774
	"_xlfn.BITRSHIFT": "BITRSHIFT",
11775
	"_xlfn.BITXOR": "BITXOR",
11776
	"_xlfn.CEILING.MATH": "CEILING.MATH",
11777
	"_xlfn.CEILING.PRECISE": "CEILING.PRECISE",
11778
	"_xlfn.CHISQ.DIST": "CHISQ.DIST",
11779
	"_xlfn.CHISQ.DIST.RT": "CHISQ.DIST.RT",
11780
	"_xlfn.CHISQ.INV": "CHISQ.INV",
11781
	"_xlfn.CHISQ.INV.RT": "CHISQ.INV.RT",
11782
	"_xlfn.CHISQ.TEST": "CHISQ.TEST",
11783
	"_xlfn.COMBINA": "COMBINA",
11784
	"_xlfn.CONCAT": "CONCAT",
11785
	"_xlfn.CONFIDENCE.NORM": "CONFIDENCE.NORM",
11786
	"_xlfn.CONFIDENCE.T": "CONFIDENCE.T",
11787
	"_xlfn.COT": "COT",
11788
	"_xlfn.COTH": "COTH",
11789
	"_xlfn.COUNTIFS": "COUNTIFS",
11790
	"_xlfn.COVARIANCE.P": "COVARIANCE.P",
11791
	"_xlfn.COVARIANCE.S": "COVARIANCE.S",
11792
	"_xlfn.CSC": "CSC",
11793
	"_xlfn.CSCH": "CSCH",
11794
	"_xlfn.DAYS": "DAYS",
11795
	"_xlfn.DECIMAL": "DECIMAL",
11796
	"_xlfn.ECMA.CEILING": "ECMA.CEILING",
11797
	"_xlfn.ERF.PRECISE": "ERF.PRECISE",
11798
	"_xlfn.ERFC.PRECISE": "ERFC.PRECISE",
11799
	"_xlfn.EXPON.DIST": "EXPON.DIST",
11800
	"_xlfn.F.DIST": "F.DIST",
11801
	"_xlfn.F.DIST.RT": "F.DIST.RT",
11802
	"_xlfn.F.INV": "F.INV",
11803
	"_xlfn.F.INV.RT": "F.INV.RT",
11804
	"_xlfn.F.TEST": "F.TEST",
11805
	"_xlfn.FILTERXML": "FILTERXML",
11806
	"_xlfn.FLOOR.MATH": "FLOOR.MATH",
11807
	"_xlfn.FLOOR.PRECISE": "FLOOR.PRECISE",
11808
	"_xlfn.FORECAST.ETS": "FORECAST.ETS",
11809
	"_xlfn.FORECAST.ETS.CONFINT": "FORECAST.ETS.CONFINT",
11810
	"_xlfn.FORECAST.ETS.SEASONALITY": "FORECAST.ETS.SEASONALITY",
11811
	"_xlfn.FORECAST.ETS.STAT": "FORECAST.ETS.STAT",
11812
	"_xlfn.FORECAST.LINEAR": "FORECAST.LINEAR",
11813
	"_xlfn.FORMULATEXT": "FORMULATEXT",
11814
	"_xlfn.GAMMA": "GAMMA",
11815
	"_xlfn.GAMMA.DIST": "GAMMA.DIST",
11816
	"_xlfn.GAMMA.INV": "GAMMA.INV",
11817
	"_xlfn.GAMMALN.PRECISE": "GAMMALN.PRECISE",
11818
	"_xlfn.GAUSS": "GAUSS",
11819
	"_xlfn.HYPGEOM.DIST": "HYPGEOM.DIST",
11820
	"_xlfn.IFERROR": "IFERROR",
11821
	"_xlfn.IFNA": "IFNA",
11822
	"_xlfn.IFS": "IFS",
11823
	"_xlfn.IMCOSH": "IMCOSH",
11824
	"_xlfn.IMCOT": "IMCOT",
11825
	"_xlfn.IMCSC": "IMCSC",
11826
	"_xlfn.IMCSCH": "IMCSCH",
11827
	"_xlfn.IMSEC": "IMSEC",
11828
	"_xlfn.IMSECH": "IMSECH",
11829
	"_xlfn.IMSINH": "IMSINH",
11830
	"_xlfn.IMTAN": "IMTAN",
11831
	"_xlfn.ISFORMULA": "ISFORMULA",
11832
	"_xlfn.ISO.CEILING": "ISO.CEILING",
11833
	"_xlfn.ISOWEEKNUM": "ISOWEEKNUM",
11834
	"_xlfn.LOGNORM.DIST": "LOGNORM.DIST",
11835
	"_xlfn.LOGNORM.INV": "LOGNORM.INV",
11836
	"_xlfn.MAXIFS": "MAXIFS",
11837
	"_xlfn.MINIFS": "MINIFS",
11838
	"_xlfn.MODE.MULT": "MODE.MULT",
11839
	"_xlfn.MODE.SNGL": "MODE.SNGL",
11840
	"_xlfn.MUNIT": "MUNIT",
11841
	"_xlfn.NEGBINOM.DIST": "NEGBINOM.DIST",
11842
	"_xlfn.NETWORKDAYS.INTL": "NETWORKDAYS.INTL",
11843
	"_xlfn.NIGBINOM": "NIGBINOM",
11844
	"_xlfn.NORM.DIST": "NORM.DIST",
11845
	"_xlfn.NORM.INV": "NORM.INV",
11846
	"_xlfn.NORM.S.DIST": "NORM.S.DIST",
11847
	"_xlfn.NORM.S.INV": "NORM.S.INV",
11848
	"_xlfn.NUMBERVALUE": "NUMBERVALUE",
11849
	"_xlfn.PDURATION": "PDURATION",
11850
	"_xlfn.PERCENTILE.EXC": "PERCENTILE.EXC",
11851
	"_xlfn.PERCENTILE.INC": "PERCENTILE.INC",
11852
	"_xlfn.PERCENTRANK.EXC": "PERCENTRANK.EXC",
11853
	"_xlfn.PERCENTRANK.INC": "PERCENTRANK.INC",
11854
	"_xlfn.PERMUTATIONA": "PERMUTATIONA",
11855
	"_xlfn.PHI": "PHI",
11856
	"_xlfn.POISSON.DIST": "POISSON.DIST",
11857
	"_xlfn.QUARTILE.EXC": "QUARTILE.EXC",
11858
	"_xlfn.QUARTILE.INC": "QUARTILE.INC",
11859
	"_xlfn.QUERYSTRING": "QUERYSTRING",
11860
	"_xlfn.RANK.AVG": "RANK.AVG",
11861
	"_xlfn.RANK.EQ": "RANK.EQ",
11862
	"_xlfn.RRI": "RRI",
11863
	"_xlfn.SEC": "SEC",
11864
	"_xlfn.SECH": "SECH",
11865
	"_xlfn.SHEET": "SHEET",
11866
	"_xlfn.SHEETS": "SHEETS",
11867
	"_xlfn.SKEW.P": "SKEW.P",
11868
	"_xlfn.STDEV.P": "STDEV.P",
11869
	"_xlfn.STDEV.S": "STDEV.S",
11870
	"_xlfn.SUMIFS": "SUMIFS",
11871
	"_xlfn.SWITCH": "SWITCH",
11872
	"_xlfn.T.DIST": "T.DIST",
11873
	"_xlfn.T.DIST.2T": "T.DIST.2T",
11874
	"_xlfn.T.DIST.RT": "T.DIST.RT",
11875
	"_xlfn.T.INV": "T.INV",
11876
	"_xlfn.T.INV.2T": "T.INV.2T",
11877
	"_xlfn.T.TEST": "T.TEST",
11878
	"_xlfn.TEXTJOIN": "TEXTJOIN",
11879
	"_xlfn.UNICHAR": "UNICHAR",
11880
	"_xlfn.UNICODE": "UNICODE",
11881
	"_xlfn.VAR.P": "VAR.P",
11882
	"_xlfn.VAR.S": "VAR.S",
11883
	"_xlfn.WEBSERVICE": "WEBSERVICE",
11884
	"_xlfn.WEIBULL.DIST": "WEIBULL.DIST",
11885
	"_xlfn.WORKDAY.INTL": "WORKDAY.INTL",
11886
	"_xlfn.XOR": "XOR",
11887
	"_xlfn.Z.TEST": "Z.TEST"
11888
};
11889
11890
/* Part 3 TODO: actually parse formulae */
11891
function ods_to_csf_formula(f) {
11892
	if(f.slice(0,3) == "of:") f = f.slice(3);
11893
	/* 5.2 Basic Expressions */
11894
	if(f.charCodeAt(0) == 61) {
11895
		f = f.slice(1);
11896
		if(f.charCodeAt(0) == 61) f = f.slice(1);
11897
	}
11898
	f = f.replace(/COM\.MICROSOFT\./g, "");
11899
	/* Part 3 Section 5.8 References */
11900
	f = f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, function($$, $1) { return $1.replace(/\./g,""); });
11901
	/* TODO: something other than this */
11902
	f = f.replace(/\[.(#[A-Z]*[?!])\]/g, "$1");
11903
	return f.replace(/[;~]/g,",").replace(/\|/g,";");
11904
}
11905
11906
function csf_to_ods_formula(f) {
11907
	var o = "of:=" + f.replace(crefregex, "$1[.$2$3$4$5]").replace(/\]:\[/g,":");
11908
	/* TODO: something other than this */
11909
	return o.replace(/;/g, "|").replace(/,/g,";");
11910
}
11911
11912
function ods_to_csf_3D(r) {
11913
	var a = r.split(":");
11914
	var s = a[0].split(".")[0];
11915
	return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
11916
}
11917
11918
function csf_to_ods_3D(r) {
11919
	return r.replace(/\./,"!");
11920
}
11921
11922
var strs = {}; // shared strings
11923
var _ssfopts = {}; // spreadsheet formatting options
11924
11925
RELS.WS = [
11926
	"http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
11927
	"http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
11928
];
11929
11930
/*global Map */
11931
var browser_has_Map = typeof Map !== 'undefined';
11932
11933
function get_sst_id(sst, str, rev) {
11934
	var i = 0, len = sst.length;
11935
	if(rev) {
11936
		if(browser_has_Map ? rev.has(str) : rev.hasOwnProperty(str)) {
11937
			var revarr = browser_has_Map ? rev.get(str) : rev[str];
11938
			for(; i < revarr.length; ++i) {
11939
				if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
11940
			}
11941
		}
11942
	} else for(; i < len; ++i) {
11943
		if(sst[i].t === str) { sst.Count ++; return i; }
11944
	}
11945
	sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
11946
	if(rev) {
11947
		if(browser_has_Map) {
11948
			if(!rev.has(str)) rev.set(str, []);
11949
			rev.get(str).push(len);
11950
		} else {
11951
			if(!rev.hasOwnProperty(str)) rev[str] = [];
11952
			rev[str].push(len);
11953
		}
11954
	}
11955
	return len;
11956
}
11957
11958
function col_obj_w(C, col) {
11959
	var p = ({min:C+1,max:C+1});
11960
	/* wch (chars), wpx (pixels) */
11961
	var wch = -1;
11962
	if(col.MDW) MDW = col.MDW;
11963
	if(col.width != null) p.customWidth = 1;
11964
	else if(col.wpx != null) wch = px2char(col.wpx);
11965
	else if(col.wch != null) wch = col.wch;
11966
	if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
11967
	else if(col.width != null) p.width = col.width;
11968
	if(col.hidden) p.hidden = true;
11969
	return p;
11970
}
11971
11972
function default_margins(margins, mode) {
11973
	if(!margins) return;
11974
	var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
11975
	if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
11976
	if(margins.left   == null) margins.left   = defs[0];
11977
	if(margins.right  == null) margins.right  = defs[1];
11978
	if(margins.top    == null) margins.top    = defs[2];
11979
	if(margins.bottom == null) margins.bottom = defs[3];
11980
	if(margins.header == null) margins.header = defs[4];
11981
	if(margins.footer == null) margins.footer = defs[5];
11982
}
11983
11984
function get_cell_style(styles, cell, opts) {
11985
	var z = opts.revssf[cell.z != null ? cell.z : "General"];
11986
	var i = 0x3c, len = styles.length;
11987
	if(z == null && opts.ssf) {
11988
		for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
11989
			SSF.load(cell.z, i);
11990
			// $FlowIgnore
11991
			opts.ssf[i] = cell.z;
11992
			opts.revssf[cell.z] = z = i;
11993
			break;
11994
		}
11995
	}
11996
	for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
11997
	styles[len] = {
11998
		numFmtId:z,
11999
		fontId:0,
12000
		fillId:0,
12001
		borderId:0,
12002
		xfId:0,
12003
		applyNumberFormat:1
12004
	};
12005
	return len;
12006
}
12007
12008
function safe_format(p, fmtid, fillid, opts, themes, styles) {
12009
	if(p.t === 'z') return;
12010
	if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
12011
	try {
12012
		if(opts.cellNF) p.z = SSF._table[fmtid];
12013
	} catch(e) { if(opts.WTF) throw e; }
12014
	if(!opts || opts.cellText !== false) try {
12015
		if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
12016
		if(p.t === 'e') p.w = p.w || BErr[p.v];
12017
		else if(fmtid === 0) {
12018
			if(p.t === 'n') {
12019
				if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
12020
				else p.w = SSF._general_num(p.v);
12021
			}
12022
			else if(p.t === 'd') {
12023
				var dd = datenum(p.v);
12024
				if((dd|0) === dd) p.w = SSF._general_int(dd);
12025
				else p.w = SSF._general_num(dd);
12026
			}
12027
			else if(p.v === undefined) return "";
12028
			else p.w = SSF._general(p.v,_ssfopts);
12029
		}
12030
		else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
12031
		else p.w = SSF.format(fmtid,p.v,_ssfopts);
12032
	} catch(e) { if(opts.WTF) throw e; }
12033
	if(!opts.cellStyles) return;
12034
	if(fillid != null) try {
12035
		p.s = styles.Fills[fillid];
12036
		if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
12037
			p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
12038
			if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
12039
		}
12040
		if (p.s.bgColor && p.s.bgColor.theme) {
12041
			p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
12042
			if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
12043
		}
12044
	} catch(e) { if(opts.WTF && styles.Fills) throw e; }
12045
}
12046
12047
function check_ws(ws, sname, i) {
12048
	if(ws && ws['!ref']) {
12049
		var range = safe_decode_range(ws['!ref']);
12050
		if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
12051
	}
12052
}
12053
function parse_ws_xml_dim(ws, s) {
12054
	var d = safe_decode_range(s);
12055
	if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d);
12056
}
12057
var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
12058
var sheetdataregex = /<(?:\w+:)?sheetData>([\s\S]*)<\/(?:\w+:)?sheetData>/;
12059
var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
12060
var dimregex = /"(\w*:\w*)"/;
12061
var colregex = /<(?:\w:)?col[^>]*[\/]?>/g;
12062
var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
12063
var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
12064
var sheetprregex = /<(?:\w:)?sheetPr(?:[^>a-z][^>]*)?\/>/;
12065
var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
12066
/* 18.3 Worksheets */
12067
function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
12068
	if(!data) return data;
12069
	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
12070
12071
	/* 18.3.1.99 worksheet CT_Worksheet */
12072
	var s = opts.dense ? ([]) : ({});
12073
	var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
12074
12075
	var data1 = "", data2 = "";
12076
	var mtch = data.match(sheetdataregex);
12077
	if(mtch) {
12078
		data1 = data.slice(0, mtch.index);
12079
		data2 = data.slice(mtch.index + mtch[0].length);
12080
	} else data1 = data2 = data;
12081
12082
	/* 18.3.1.82 sheetPr CT_SheetPr */
12083
	var sheetPr = data1.match(sheetprregex);
12084
	if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
12085
12086
	/* 18.3.1.35 dimension CT_SheetDimension */
12087
	// $FlowIgnore
12088
	var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
12089
	if(ridx > 0) {
12090
		var ref = data1.slice(ridx,ridx+50).match(dimregex);
12091
		if(ref) parse_ws_xml_dim(s, ref[1]);
12092
	}
12093
12094
	/* 18.3.1.88 sheetViews CT_SheetViews */
12095
	var svs = data1.match(svsregex);
12096
	if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
12097
12098
	/* 18.3.1.17 cols CT_Cols */
12099
	var columns = [];
12100
	if(opts.cellStyles) {
12101
		/* 18.3.1.13 col CT_Col */
12102
		var cols = data1.match(colregex);
12103
		if(cols) parse_ws_xml_cols(columns, cols);
12104
	}
12105
12106
	/* 18.3.1.80 sheetData CT_SheetData ? */
12107
	if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
12108
12109
	/* 18.3.1.2  autoFilter CT_AutoFilter */
12110
	var afilter = data2.match(afregex);
12111
	if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
12112
12113
	/* 18.3.1.55 mergeCells CT_MergeCells */
12114
	var merges = [];
12115
	var _merge = data2.match(mergecregex);
12116
	if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
12117
		merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
12118
12119
	/* 18.3.1.48 hyperlinks CT_Hyperlinks */
12120
	var hlink = data2.match(hlinkregex);
12121
	if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
12122
12123
	/* 18.3.1.62 pageMargins CT_PageMargins */
12124
	var margins = data2.match(marginregex);
12125
	if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
12126
12127
	if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
12128
	if(opts.sheetRows > 0 && s["!ref"]) {
12129
		var tmpref = safe_decode_range(s["!ref"]);
12130
		if(opts.sheetRows <= +tmpref.e.r) {
12131
			tmpref.e.r = opts.sheetRows - 1;
12132
			if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
12133
			if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
12134
			if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
12135
			if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
12136
			s["!fullref"] = s["!ref"];
12137
			s["!ref"] = encode_range(tmpref);
12138
		}
12139
	}
12140
	if(columns.length > 0) s["!cols"] = columns;
12141
	if(merges.length > 0) s["!merges"] = merges;
12142
	return s;
12143
}
12144
12145
function write_ws_xml_merges(merges) {
12146
	if(merges.length === 0) return "";
12147
	var o = '<mergeCells count="' + merges.length + '">';
12148
	for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
12149
	return o + '</mergeCells>';
12150
}
12151
12152
/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
12153
function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
12154
	var data = parsexmltag(sheetPr);
12155
	if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
12156
	if(data.codeName) wb.Sheets[idx].CodeName = data.codeName;
12157
}
12158
12159
/* 18.3.1.85 sheetProtection CT_SheetProtection */
12160
function write_ws_xml_protection(sp) {
12161
	// algorithmName, hashValue, saltValue, spinCountpassword
12162
	var o = ({sheet:1});
12163
	var deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
12164
	var deftrue = [
12165
		"formatColumns", "formatRows", "formatCells",
12166
		"insertColumns", "insertRows", "insertHyperlinks",
12167
		"deleteColumns", "deleteRows",
12168
		"sort", "autoFilter", "pivotTables"
12169
	];
12170
	deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
12171
	deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
12172
	/* TODO: algorithm */
12173
	if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
12174
	return writextag('sheetProtection', null, o);
12175
}
12176
12177
function parse_ws_xml_hlinks(s, data, rels) {
12178
	var dense = Array.isArray(s);
12179
	for(var i = 0; i != data.length; ++i) {
12180
		var val = parsexmltag(utf8read(data[i]), true);
12181
		if(!val.ref) return;
12182
		var rel = ((rels || {})['!id']||[])[val.id];
12183
		if(rel) {
12184
			val.Target = rel.Target;
12185
			if(val.location) val.Target += "#"+val.location;
12186
		} else {
12187
			val.Target = "#" + val.location;
12188
			rel = {Target: val.Target, TargetMode: 'Internal'};
12189
		}
12190
		val.Rel = rel;
12191
		if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
12192
		var rng = safe_decode_range(val.ref);
12193
		for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
12194
			var addr = encode_cell({c:C,r:R});
12195
			if(dense) {
12196
				if(!s[R]) s[R] = [];
12197
				if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
12198
				s[R][C].l = val;
12199
			} else {
12200
				if(!s[addr]) s[addr] = {t:"z",v:undefined};
12201
				s[addr].l = val;
12202
			}
12203
		}
12204
	}
12205
}
12206
12207
function parse_ws_xml_margins(margin) {
12208
	var o = {};
12209
	["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
12210
		if(margin[k]) o[k] = parseFloat(margin[k]);
12211
	});
12212
	return o;
12213
}
12214
function write_ws_xml_margins(margin) {
12215
	default_margins(margin);
12216
	return writextag('pageMargins', null, margin);
12217
}
12218
12219
function parse_ws_xml_cols(columns, cols) {
12220
	var seencol = false;
12221
	for(var coli = 0; coli != cols.length; ++coli) {
12222
		var coll = parsexmltag(cols[coli], true);
12223
		if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
12224
		var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
12225
		delete coll.min; delete coll.max; coll.width = +coll.width;
12226
		if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
12227
		process_col(coll);
12228
		while(colm <= colM) columns[colm++] = dup(coll);
12229
	}
12230
}
12231
12232
function write_ws_xml_cols(ws, cols) {
12233
	var o = ["<cols>"], col;
12234
	for(var i = 0; i != cols.length; ++i) {
12235
		if(!(col = cols[i])) continue;
12236
		o[o.length] = (writextag('col', null, col_obj_w(i, col)));
12237
	}
12238
	o[o.length] = "</cols>";
12239
	return o.join("");
12240
}
12241
12242
function parse_ws_xml_autofilter(data) {
12243
	var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
12244
	return o;
12245
}
12246
function write_ws_xml_autofilter(data) {
12247
	return writextag("autoFilter", null, {ref:data.ref});
12248
}
12249
12250
/* 18.3.1.88 sheetViews CT_SheetViews */
12251
/* 18.3.1.87 sheetView CT_SheetView */
12252
var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/>/;
12253
function parse_ws_xml_sheetviews(data, wb) {
12254
	(data.match(sviewregex)||[]).forEach(function(r) {
12255
		var tag = parsexmltag(r);
12256
		if(parsexmlbool(tag.rightToLeft)) {
12257
			if(!wb.Views) wb.Views = [{}];
12258
			if(!wb.Views[0]) wb.Views[0] = {};
12259
			wb.Views[0].RTL = true;
12260
		}
12261
	});
12262
}
12263
function write_ws_xml_sheetviews(ws, opts, idx, wb) {
12264
	var sview = {workbookViewId:"0"};
12265
	// $FlowIgnore
12266
	if( (((wb||{}).Workbook||{}).Views||[])[0] ) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
12267
	return writextag("sheetViews", writextag("sheetView", null, sview), {});
12268
}
12269
12270
function write_ws_xml_cell(cell, ref, ws, opts) {
12271
	if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return "";
12272
	var vv = "";
12273
	var oldt = cell.t, oldv = cell.v;
12274
	switch(cell.t) {
12275
		case 'b': vv = cell.v ? "1" : "0"; break;
12276
		case 'n': vv = ''+cell.v; break;
12277
		case 'e': vv = BErr[cell.v]; break;
12278
		case 'd':
12279
			if(opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
12280
			else {
12281
				cell = dup(cell);
12282
				cell.t = 'n';
12283
				vv = ''+(cell.v = datenum(parseDate(cell.v)));
12284
			}
12285
			if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
12286
			break;
12287
		default: vv = cell.v; break;
12288
	}
12289
	var v = writetag('v', escapexml(vv)), o = ({r:ref});
12290
	/* TODO: cell style */
12291
	var os = get_cell_style(opts.cellXfs, cell, opts);
12292
	if(os !== 0) o.s = os;
12293
	switch(cell.t) {
12294
		case 'n': break;
12295
		case 'd': o.t = "d"; break;
12296
		case 'b': o.t = "b"; break;
12297
		case 'e': o.t = "e"; break;
12298
		default: if(cell.v == null) { delete cell.t; break; }
12299
			if(opts.bookSST) {
12300
				v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
12301
				o.t = "s"; break;
12302
			}
12303
			o.t = "str"; break;
12304
	}
12305
	if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
12306
	if(cell.f) {
12307
		var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
12308
		v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
12309
	}
12310
	if(cell.l) ws['!links'].push([ref, cell.l]);
12311
	if(cell.c) ws['!comments'].push([ref, cell.c]);
12312
	return writextag('c', v, o);
12313
}
12314
12315
var parse_ws_xml_data = (function() {
12316
	var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
12317
	var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
12318
	var refregex = /ref=["']([^"']*)["']/;
12319
	var match_v = matchtag("v"), match_f = matchtag("f");
12320
12321
return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
12322
	var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
12323
	var tag, tagr = 0, tagc = 0;
12324
	var sstr, ftag;
12325
	var fmtid = 0, fillid = 0;
12326
	var do_format = Array.isArray(styles.CellXf), cf;
12327
	var arrayf = [];
12328
	var sharedf = [];
12329
	var dense = Array.isArray(s);
12330
	var rows = [], rowobj = {}, rowrite = false;
12331
	for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
12332
		x = marr[mt].trim();
12333
		var xlen = x.length;
12334
		if(xlen === 0) continue;
12335
12336
		/* 18.3.1.73 row CT_Row */
12337
		for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
12338
		tag = parsexmltag(x.slice(0,ri), true);
12339
		tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
12340
		if(opts.sheetRows && opts.sheetRows < tagr) continue;
12341
		if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
12342
		if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
12343
12344
		if(opts && opts.cellStyles) {
12345
			rowobj = {}; rowrite = false;
12346
			if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
12347
			if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
12348
			if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
12349
			if(rowrite) rows[tagr-1] = rowobj;
12350
		}
12351
12352
		/* 18.3.1.4 c CT_Cell */
12353
		cells = x.slice(ri).split(cellregex);
12354
		for(ri = 0; ri != cells.length; ++ri) {
12355
			x = cells[ri].trim();
12356
			if(x.length === 0) continue;
12357
			cref = x.match(rregex); idx = ri; i=0; cc=0;
12358
			x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
12359
			if(cref != null && cref.length === 2) {
12360
				idx = 0; d=cref[1];
12361
				for(i=0; i != d.length; ++i) {
12362
					if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
12363
					idx = 26*idx + cc;
12364
				}
12365
				--idx;
12366
				tagc = idx;
12367
			} else ++tagc;
12368
			for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
12369
			tag = parsexmltag(x.slice(0,i), true);
12370
			if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
12371
			d = x.slice(i);
12372
			p = ({t:""});
12373
12374
			if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
12375
			if(opts.cellFormula) {
12376
				if((cref=d.match(match_f))!= null && cref[1] !== '') {
12377
					/* TODO: match against XLSXFutureFunctions */
12378
					p.f=_xlfn(unescapexml(utf8read(cref[1])));
12379
					if(cref[0].indexOf('t="array"') > -1) {
12380
						p.F = (d.match(refregex)||[])[1];
12381
						if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
12382
					} else if(cref[0].indexOf('t="shared"') > -1) {
12383
						// TODO: parse formula
12384
						ftag = parsexmltag(cref[0]);
12385
						sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1])))];
12386
					}
12387
				} else if((cref=d.match(/<f[^>]*\/>/))) {
12388
					ftag = parsexmltag(cref[0]);
12389
					if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][0].ref, tag.r);
12390
				}
12391
				/* TODO: factor out contains logic */
12392
				var _tag = decode_cell(tag.r);
12393
				for(i = 0; i < arrayf.length; ++i)
12394
					if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
12395
						if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
12396
							p.F = arrayf[i][1];
12397
			}
12398
12399
			if(tag.t == null && p.v === undefined) {
12400
				if(p.f || p.F) {
12401
					p.v = 0; p.t = "n";
12402
				} else if(!opts.sheetStubs) continue;
12403
				else p.t = "z";
12404
			}
12405
			else p.t = tag.t || "n";
12406
			if(guess.s.c > tagc) guess.s.c = tagc;
12407
			if(guess.e.c < tagc) guess.e.c = tagc;
12408
			/* 18.18.11 t ST_CellType */
12409
			switch(p.t) {
12410
				case 'n':
12411
					if(p.v == "" || p.v == null) {
12412
						if(!opts.sheetStubs) continue;
12413
						p.t = 'z';
12414
					} else p.v = parseFloat(p.v);
12415
					break;
12416
				case 's':
12417
					if(typeof p.v == 'undefined') {
12418
						if(!opts.sheetStubs) continue;
12419
						p.t = 'z';
12420
					} else {
12421
						sstr = strs[parseInt(p.v, 10)];
12422
						p.v = sstr.t;
12423
						p.r = sstr.r;
12424
						if(opts.cellHTML) p.h = sstr.h;
12425
					}
12426
					break;
12427
				case 'str':
12428
					p.t = "s";
12429
					p.v = (p.v!=null) ? utf8read(p.v) : '';
12430
					if(opts.cellHTML) p.h = escapehtml(p.v);
12431
					break;
12432
				case 'inlineStr':
12433
					cref = d.match(isregex);
12434
					p.t = 's';
12435
					if(cref != null && (sstr = parse_si(cref[1]))) p.v = sstr.t; else p.v = "";
12436
					break;
12437
				case 'b': p.v = parsexmlbool(p.v); break;
12438
				case 'd':
12439
					if(opts.cellDates) p.v = parseDate(p.v, 1);
12440
					else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
12441
					break;
12442
				/* error string in .w, number in .v */
12443
				case 'e':
12444
					if(!opts || opts.cellText !== false) p.w = p.v;
12445
					p.v = RBErr[p.v]; break;
12446
			}
12447
			/* formatting */
12448
			fmtid = fillid = 0;
12449
			if(do_format && tag.s !== undefined) {
12450
				cf = styles.CellXf[tag.s];
12451
				if(cf != null) {
12452
					if(cf.numFmtId != null) fmtid = cf.numFmtId;
12453
					if(opts.cellStyles) {
12454
						if(cf.fillId != null) fillid = cf.fillId;
12455
					}
12456
				}
12457
			}
12458
			safe_format(p, fmtid, fillid, opts, themes, styles);
12459
			if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
12460
			if(dense) {
12461
				var _r = decode_cell(tag.r);
12462
				if(!s[_r.r]) s[_r.r] = [];
12463
				s[_r.r][_r.c] = p;
12464
			} else s[tag.r] = p;
12465
		}
12466
	}
12467
	if(rows.length > 0) s['!rows'] = rows;
12468
}; })();
12469
12470
function write_ws_xml_data(ws, opts, idx, wb) {
12471
	var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
12472
	var dense = Array.isArray(ws);
12473
	var params = ({r:rr}), row, height = -1;
12474
	for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
12475
	for(R = range.s.r; R <= range.e.r; ++R) {
12476
		r = [];
12477
		rr = encode_row(R);
12478
		for(C = range.s.c; C <= range.e.c; ++C) {
12479
			ref = cols[C] + rr;
12480
			var _cell = dense ? (ws[R]||[])[C]: ws[ref];
12481
			if(_cell === undefined) continue;
12482
			if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
12483
		}
12484
		if(r.length > 0 || (rows && rows[R])) {
12485
			params = ({r:rr});
12486
			if(rows && rows[R]) {
12487
				row = rows[R];
12488
				if(row.hidden) params.hidden = 1;
12489
				height = -1;
12490
				if (row.hpx) height = px2pt(row.hpx);
12491
				else if (row.hpt) height = row.hpt;
12492
				if (height > -1) { params.ht = height; params.customHeight = 1; }
12493
				if (row.level) { params.outlineLevel = row.level; }
12494
			}
12495
			o[o.length] = (writextag('row', r.join(""), params));
12496
		}
12497
	}
12498
	if(rows) for(; R < rows.length; ++R) {
12499
		if(rows && rows[R]) {
12500
			params = ({r:R+1});
12501
			row = rows[R];
12502
			if(row.hidden) params.hidden = 1;
12503
			height = -1;
12504
			if (row.hpx) height = px2pt(row.hpx);
12505
			else if (row.hpt) height = row.hpt;
12506
			if (height > -1) { params.ht = height; params.customHeight = 1; }
12507
			if (row.level) { params.outlineLevel = row.level; }
12508
			o[o.length] = (writextag('row', "", params));
12509
		}
12510
	}
12511
	return o.join("");
12512
}
12513
12514
var WS_XML_ROOT = writextag('worksheet', null, {
12515
	'xmlns': XMLNS.main[0],
12516
	'xmlns:r': XMLNS.r
12517
});
12518
12519
function write_ws_xml(idx, opts, wb, rels) {
12520
	var o = [XML_HEADER, WS_XML_ROOT];
12521
	var s = wb.SheetNames[idx], sidx = 0, rdata = "";
12522
	var ws = wb.Sheets[s];
12523
	if(ws == null) ws = {};
12524
	var ref = ws['!ref'] || 'A1';
12525
	var range = safe_decode_range(ref);
12526
	if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
12527
		if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
12528
		range.e.c = Math.min(range.e.c, 0x3FFF);
12529
		range.e.r = Math.min(range.e.c, 0xFFFFF);
12530
		ref = encode_range(range);
12531
	}
12532
	if(!rels) rels = {};
12533
	ws['!comments'] = [];
12534
	ws['!drawing'] = [];
12535
12536
	if(opts.bookType !== 'xlsx' && wb.vbaraw) {
12537
		var cname = wb.SheetNames[idx];
12538
		try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
12539
		o[o.length] = (writextag('sheetPr', null, {'codeName': escapexml(cname)}));
12540
	}
12541
12542
	o[o.length] = (writextag('dimension', null, {'ref': ref}));
12543
12544
	o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
12545
12546
	/* TODO: store in WB, process styles */
12547
	if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
12548
		defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
12549
		baseColWidth:opts.sheetFormat.baseColWidth||'10',
12550
		outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
12551
	}));
12552
12553
	if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
12554
12555
	o[sidx = o.length] = '<sheetData/>';
12556
	ws['!links'] = [];
12557
	if(ws['!ref'] != null) {
12558
		rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
12559
		if(rdata.length > 0) o[o.length] = (rdata);
12560
	}
12561
	if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
12562
12563
	/* sheetCalcPr */
12564
12565
	if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
12566
12567
	/* protectedRanges */
12568
	/* scenarios */
12569
12570
	if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter']);
12571
12572
	/* sortState */
12573
	/* dataConsolidate */
12574
	/* customSheetViews */
12575
12576
	if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
12577
12578
	/* phoneticPr */
12579
	/* conditionalFormatting */
12580
	/* dataValidations */
12581
12582
	var relc = -1, rel, rId = -1;
12583
	if(ws['!links'].length > 0) {
12584
		o[o.length] = "<hyperlinks>";
12585
		ws['!links'].forEach(function(l) {
12586
			if(!l[1].Target) return;
12587
			rel = ({"ref":l[0]});
12588
			if(l[1].Target.charAt(0) != "#") {
12589
				rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
12590
				rel["r:id"] = "rId"+rId;
12591
			}
12592
			if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
12593
			if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
12594
			o[o.length] = writextag("hyperlink",null,rel);
12595
		});
12596
		o[o.length] = "</hyperlinks>";
12597
	}
12598
	delete ws['!links'];
12599
12600
	/* printOptions */
12601
	if (ws['!margins'] != null) o[o.length] =  write_ws_xml_margins(ws['!margins']);
12602
	/* pageSetup */
12603
12604
	//var hfidx = o.length;
12605
	o[o.length] = "";
12606
12607
	/* rowBreaks */
12608
	/* colBreaks */
12609
	/* customProperties */
12610
	/* cellWatches */
12611
12612
	if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
12613
12614
	/* smartTags */
12615
12616
	if(ws['!drawing'].length > 0) {
12617
		rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
12618
		o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
12619
	}
12620
	else delete ws['!drawing'];
12621
12622
	if(ws['!comments'].length > 0) {
12623
		rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
12624
		o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
12625
		ws['!legacy'] = rId;
12626
	}
12627
12628
	/* drawingHF */
12629
	/* picture */
12630
	/* oleObjects */
12631
	/* controls */
12632
	/* webPublishItems */
12633
	/* tableParts */
12634
	/* extList */
12635
12636
	if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
12637
	return o.join("");
12638
}
12639
12640
/* [MS-XLSB] 2.4.726 BrtRowHdr */
12641
function parse_BrtRowHdr(data, length) {
12642
	var z = ({});
12643
	var tgt = data.l + length;
12644
	z.r = data.read_shift(4);
12645
	data.l += 4; // TODO: ixfe
12646
	var miyRw = data.read_shift(2);
12647
	data.l += 1; // TODO: top/bot padding
12648
	var flags = data.read_shift(1);
12649
	data.l = tgt;
12650
	if(flags & 0x07) z.level = flags & 0x07;
12651
	if(flags & 0x10) z.hidden = true;
12652
	if(flags & 0x20) z.hpt = miyRw / 20;
12653
	return z;
12654
}
12655
function write_BrtRowHdr(R, range, ws) {
12656
	var o = new_buf(17+8*16);
12657
	var row = (ws['!rows']||[])[R]||{};
12658
	o.write_shift(4, R);
12659
12660
	o.write_shift(4, 0); /* TODO: ixfe */
12661
12662
	var miyRw = 0x0140;
12663
	if(row.hpx) miyRw = px2pt(row.hpx) * 20;
12664
	else if(row.hpt) miyRw = row.hpt * 20;
12665
	o.write_shift(2, miyRw);
12666
12667
	o.write_shift(1, 0); /* top/bot padding */
12668
12669
	var flags = 0x0;
12670
	if(row.level) flags |= row.level;
12671
	if(row.hidden) flags |= 0x10;
12672
	if(row.hpx || row.hpt) flags |= 0x20;
12673
	o.write_shift(1, flags);
12674
12675
	o.write_shift(1, 0); /* phonetic guide */
12676
12677
	/* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
12678
	var ncolspan = 0, lcs = o.l;
12679
	o.l += 4;
12680
12681
	var caddr = {r:R, c:0};
12682
	for(var i = 0; i < 16; ++i) {
12683
		if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue;
12684
		var first = -1, last = -1;
12685
		for(var j = (i<<10); j < ((i+1)<<10); ++j) {
12686
			caddr.c = j;
12687
			var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
12688
			if(cell) { if(first < 0) first = j; last = j; }
12689
		}
12690
		if(first < 0) continue;
12691
		++ncolspan;
12692
		o.write_shift(4, first);
12693
		o.write_shift(4, last);
12694
	}
12695
12696
	var l = o.l;
12697
	o.l = lcs;
12698
	o.write_shift(4, ncolspan);
12699
	o.l = l;
12700
12701
	return o.length > o.l ? o.slice(0, o.l) : o;
12702
}
12703
function write_row_header(ba, ws, range, R) {
12704
	var o = write_BrtRowHdr(R, range, ws);
12705
	if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o);
12706
}
12707
12708
/* [MS-XLSB] 2.4.820 BrtWsDim */
12709
var parse_BrtWsDim = parse_UncheckedRfX;
12710
var write_BrtWsDim = write_UncheckedRfX;
12711
12712
/* [MS-XLSB] 2.4.821 BrtWsFmtInfo */
12713
function parse_BrtWsFmtInfo() {
12714
}
12715
//function write_BrtWsFmtInfo(ws, o) { }
12716
12717
/* [MS-XLSB] 2.4.823 BrtWsProp */
12718
function parse_BrtWsProp(data, length) {
12719
	var z = {};
12720
	/* TODO: pull flags */
12721
	data.l += 19;
12722
	z.name = parse_XLSBCodeName(data, length - 19);
12723
	return z;
12724
}
12725
function write_BrtWsProp(str, o) {
12726
	if(o == null) o = new_buf(84+4*str.length);
12727
	for(var i = 0; i < 3; ++i) o.write_shift(1,0);
12728
	write_BrtColor({auto:1}, o);
12729
	o.write_shift(-4,-1);
12730
	o.write_shift(-4,-1);
12731
	write_XLSBCodeName(str, o);
12732
	return o.slice(0, o.l);
12733
}
12734
12735
/* [MS-XLSB] 2.4.306 BrtCellBlank */
12736
function parse_BrtCellBlank(data) {
12737
	var cell = parse_XLSBCell(data);
12738
	return [cell];
12739
}
12740
function write_BrtCellBlank(cell, ncell, o) {
12741
	if(o == null) o = new_buf(8);
12742
	return write_XLSBCell(ncell, o);
12743
}
12744
12745
12746
/* [MS-XLSB] 2.4.307 BrtCellBool */
12747
function parse_BrtCellBool(data) {
12748
	var cell = parse_XLSBCell(data);
12749
	var fBool = data.read_shift(1);
12750
	return [cell, fBool, 'b'];
12751
}
12752
function write_BrtCellBool(cell, ncell, o) {
12753
	if(o == null) o = new_buf(9);
12754
	write_XLSBCell(ncell, o);
12755
	o.write_shift(1, cell.v ? 1 : 0);
12756
	return o;
12757
}
12758
12759
/* [MS-XLSB] 2.4.308 BrtCellError */
12760
function parse_BrtCellError(data) {
12761
	var cell = parse_XLSBCell(data);
12762
	var bError = data.read_shift(1);
12763
	return [cell, bError, 'e'];
12764
}
12765
12766
/* [MS-XLSB] 2.4.311 BrtCellIsst */
12767
function parse_BrtCellIsst(data) {
12768
	var cell = parse_XLSBCell(data);
12769
	var isst = data.read_shift(4);
12770
	return [cell, isst, 's'];
12771
}
12772
function write_BrtCellIsst(cell, ncell, o) {
12773
	if(o == null) o = new_buf(12);
12774
	write_XLSBCell(ncell, o);
12775
	o.write_shift(4, ncell.v);
12776
	return o;
12777
}
12778
12779
/* [MS-XLSB] 2.4.313 BrtCellReal */
12780
function parse_BrtCellReal(data) {
12781
	var cell = parse_XLSBCell(data);
12782
	var value = parse_Xnum(data);
12783
	return [cell, value, 'n'];
12784
}
12785
function write_BrtCellReal(cell, ncell, o) {
12786
	if(o == null) o = new_buf(16);
12787
	write_XLSBCell(ncell, o);
12788
	write_Xnum(cell.v, o);
12789
	return o;
12790
}
12791
12792
/* [MS-XLSB] 2.4.314 BrtCellRk */
12793
function parse_BrtCellRk(data) {
12794
	var cell = parse_XLSBCell(data);
12795
	var value = parse_RkNumber(data);
12796
	return [cell, value, 'n'];
12797
}
12798
function write_BrtCellRk(cell, ncell, o) {
12799
	if(o == null) o = new_buf(12);
12800
	write_XLSBCell(ncell, o);
12801
	write_RkNumber(cell.v, o);
12802
	return o;
12803
}
12804
12805
12806
/* [MS-XLSB] 2.4.317 BrtCellSt */
12807
function parse_BrtCellSt(data) {
12808
	var cell = parse_XLSBCell(data);
12809
	var value = parse_XLWideString(data);
12810
	return [cell, value, 'str'];
12811
}
12812
function write_BrtCellSt(cell, ncell, o) {
12813
	if(o == null) o = new_buf(12 + 4 * cell.v.length);
12814
	write_XLSBCell(ncell, o);
12815
	write_XLWideString(cell.v, o);
12816
	return o.length > o.l ? o.slice(0, o.l) : o;
12817
}
12818
12819
/* [MS-XLSB] 2.4.653 BrtFmlaBool */
12820
function parse_BrtFmlaBool(data, length, opts) {
12821
	var end = data.l + length;
12822
	var cell = parse_XLSBCell(data);
12823
	cell.r = opts['!row'];
12824
	var value = data.read_shift(1);
12825
	var o = [cell, value, 'b'];
12826
	if(opts.cellFormula) {
12827
		data.l += 2;
12828
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12829
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12830
	}
12831
	else data.l = end;
12832
	return o;
12833
}
12834
12835
/* [MS-XLSB] 2.4.654 BrtFmlaError */
12836
function parse_BrtFmlaError(data, length, opts) {
12837
	var end = data.l + length;
12838
	var cell = parse_XLSBCell(data);
12839
	cell.r = opts['!row'];
12840
	var value = data.read_shift(1);
12841
	var o = [cell, value, 'e'];
12842
	if(opts.cellFormula) {
12843
		data.l += 2;
12844
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12845
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12846
	}
12847
	else data.l = end;
12848
	return o;
12849
}
12850
12851
/* [MS-XLSB] 2.4.655 BrtFmlaNum */
12852
function parse_BrtFmlaNum(data, length, opts) {
12853
	var end = data.l + length;
12854
	var cell = parse_XLSBCell(data);
12855
	cell.r = opts['!row'];
12856
	var value = parse_Xnum(data);
12857
	var o = [cell, value, 'n'];
12858
	if(opts.cellFormula) {
12859
		data.l += 2;
12860
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12861
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12862
	}
12863
	else data.l = end;
12864
	return o;
12865
}
12866
12867
/* [MS-XLSB] 2.4.656 BrtFmlaString */
12868
function parse_BrtFmlaString(data, length, opts) {
12869
	var end = data.l + length;
12870
	var cell = parse_XLSBCell(data);
12871
	cell.r = opts['!row'];
12872
	var value = parse_XLWideString(data);
12873
	var o = [cell, value, 'str'];
12874
	if(opts.cellFormula) {
12875
		data.l += 2;
12876
		var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
12877
		o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
12878
	}
12879
	else data.l = end;
12880
	return o;
12881
}
12882
12883
/* [MS-XLSB] 2.4.682 BrtMergeCell */
12884
var parse_BrtMergeCell = parse_UncheckedRfX;
12885
var write_BrtMergeCell = write_UncheckedRfX;
12886
/* [MS-XLSB] 2.4.107 BrtBeginMergeCells */
12887
function write_BrtBeginMergeCells(cnt, o) {
12888
	if(o == null) o = new_buf(4);
12889
	o.write_shift(4, cnt);
12890
	return o;
12891
}
12892
12893
/* [MS-XLSB] 2.4.662 BrtHLink */
12894
function parse_BrtHLink(data, length) {
12895
	var end = data.l + length;
12896
	var rfx = parse_UncheckedRfX(data, 16);
12897
	var relId = parse_XLNullableWideString(data);
12898
	var loc = parse_XLWideString(data);
12899
	var tooltip = parse_XLWideString(data);
12900
	var display = parse_XLWideString(data);
12901
	data.l = end;
12902
	var o = ({rfx:rfx, relId:relId, loc:loc, display:display});
12903
	if(tooltip) o.Tooltip = tooltip;
12904
	return o;
12905
}
12906
function write_BrtHLink(l, rId) {
12907
	var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
12908
	write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
12909
	write_RelID("rId" + rId, o);
12910
	var locidx = l[1].Target.indexOf("#");
12911
	var loc = locidx == -1 ? "" : l[1].Target.slice(locidx+1);
12912
	write_XLWideString(loc || "", o);
12913
	write_XLWideString(l[1].Tooltip || "", o);
12914
	write_XLWideString("", o);
12915
	return o.slice(0, o.l);
12916
}
12917
12918
/* [MS-XLSB] 2.4.6 BrtArrFmla */
12919
function parse_BrtArrFmla(data, length, opts) {
12920
	var end = data.l + length;
12921
	var rfx = parse_RfX(data, 16);
12922
	var fAlwaysCalc = data.read_shift(1);
12923
	var o = [rfx]; o[2] = fAlwaysCalc;
12924
	if(opts.cellFormula) {
12925
		var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts);
12926
		o[1] = formula;
12927
	} else data.l = end;
12928
	return o;
12929
}
12930
12931
/* [MS-XLSB] 2.4.750 BrtShrFmla */
12932
function parse_BrtShrFmla(data, length, opts) {
12933
	var end = data.l + length;
12934
	var rfx = parse_UncheckedRfX(data, 16);
12935
	var o = [rfx];
12936
	if(opts.cellFormula) {
12937
		var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts);
12938
		o[1] = formula;
12939
		data.l = end;
12940
	} else data.l = end;
12941
	return o;
12942
}
12943
12944
/* [MS-XLSB] 2.4.323 BrtColInfo */
12945
/* TODO: once XLS ColInfo is set, combine the functions */
12946
function write_BrtColInfo(C, col, o) {
12947
	if(o == null) o = new_buf(18);
12948
	var p = col_obj_w(C, col);
12949
	o.write_shift(-4, C);
12950
	o.write_shift(-4, C);
12951
	o.write_shift(4, (p.width || 10) * 256);
12952
	o.write_shift(4, 0/*ixfe*/); // style
12953
	var flags = 0;
12954
	if(col.hidden) flags |= 0x01;
12955
	if(typeof p.width == 'number') flags |= 0x02;
12956
	o.write_shift(1, flags); // bit flag
12957
	o.write_shift(1, 0); // bit flag
12958
	return o;
12959
}
12960
12961
/* [MS-XLSB] 2.4.678 BrtMargins */
12962
var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
12963
function parse_BrtMargins(data) {
12964
	var margins = ({});
12965
	BrtMarginKeys.forEach(function(k) { margins[k] = parse_Xnum(data, 8); });
12966
	return margins;
12967
}
12968
function write_BrtMargins(margins, o) {
12969
	if(o == null) o = new_buf(6*8);
12970
	default_margins(margins);
12971
	BrtMarginKeys.forEach(function(k) { write_Xnum((margins)[k], o); });
12972
	return o;
12973
}
12974
12975
/* [MS-XLSB] 2.4.299 BrtBeginWsView */
12976
function parse_BrtBeginWsView(data) {
12977
	var f = data.read_shift(2);
12978
	data.l += 28;
12979
	return { RTL: f & 0x20 };
12980
}
12981
function write_BrtBeginWsView(ws, Workbook, o) {
12982
	if(o == null) o = new_buf(30);
12983
	var f = 0x39c;
12984
	if((((Workbook||{}).Views||[])[0]||{}).RTL) f |= 0x20;
12985
	o.write_shift(2, f); // bit flag
12986
	o.write_shift(4, 0);
12987
	o.write_shift(4, 0); // view first row
12988
	o.write_shift(4, 0); // view first col
12989
	o.write_shift(1, 0); // gridline color ICV
12990
	o.write_shift(1, 0);
12991
	o.write_shift(2, 0);
12992
	o.write_shift(2, 100); // zoom scale
12993
	o.write_shift(2, 0);
12994
	o.write_shift(2, 0);
12995
	o.write_shift(2, 0);
12996
	o.write_shift(4, 0); // workbook view id
12997
	return o;
12998
}
12999
13000
/* [MS-XLSB] 2.4.309 BrtCellIgnoreEC */
13001
function write_BrtCellIgnoreEC(ref) {
13002
	var o = new_buf(24);
13003
	o.write_shift(4, 4);
13004
	o.write_shift(4, 1);
13005
	write_UncheckedRfX(ref, o);
13006
	return o;
13007
}
13008
13009
/* [MS-XLSB] 2.4.748 BrtSheetProtection */
13010
function write_BrtSheetProtection(sp, o) {
13011
	if(o == null) o = new_buf(16*4+2);
13012
	o.write_shift(2, sp.password ? crypto_CreatePasswordVerifier_Method1(sp.password) : 0);
13013
	o.write_shift(4, 1); // this record should not be written if no protection
13014
	[
13015
		["objects",             false], // fObjects
13016
		["scenarios",           false], // fScenarios
13017
		["formatCells",          true], // fFormatCells
13018
		["formatColumns",        true], // fFormatColumns
13019
		["formatRows",           true], // fFormatRows
13020
		["insertColumns",        true], // fInsertColumns
13021
		["insertRows",           true], // fInsertRows
13022
		["insertHyperlinks",     true], // fInsertHyperlinks
13023
		["deleteColumns",        true], // fDeleteColumns
13024
		["deleteRows",           true], // fDeleteRows
13025
		["selectLockedCells",   false], // fSelLockedCells
13026
		["sort",                 true], // fSort
13027
		["autoFilter",           true], // fAutoFilter
13028
		["pivotTables",          true], // fPivotTables
13029
		["selectUnlockedCells", false]  // fSelUnlockedCells
13030
	].forEach(function(n) {
13031
if(n[1]) o.write_shift(4, sp[n[0]] != null && !sp[n[0]] ? 1 : 0);
13032
		else      o.write_shift(4, sp[n[0]] != null && sp[n[0]] ? 0 : 1);
13033
	});
13034
	return o;
13035
}
13036
13037
/* [MS-XLSB] 2.1.7.61 Worksheet */
13038
function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
13039
	if(!data) return data;
13040
	var opts = _opts || {};
13041
	if(!rels) rels = {'!id':{}};
13042
	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
13043
	var s = (opts.dense ? [] : {});
13044
13045
	var ref;
13046
	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
13047
13048
	var pass = false, end = false;
13049
	var row, p, cf, R, C, addr, sstr, rr, cell;
13050
	var merges = [];
13051
	opts.biff = 12;
13052
	opts['!row'] = 0;
13053
13054
	var ai = 0, af = false;
13055
13056
	var arrayf = [];
13057
	var sharedf = {};
13058
	var supbooks = opts.supbooks || ([[]]);
13059
	supbooks.sharedf = sharedf;
13060
	supbooks.arrayf = arrayf;
13061
	supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; });
13062
	if(!opts.supbooks) {
13063
		opts.supbooks = supbooks;
13064
		if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i];
13065
	}
13066
13067
	var colinfo = [], rowinfo = [];
13068
	var seencol = false;
13069
13070
	recordhopper(data, function ws_parse(val, R_n, RT) {
13071
		if(end) return;
13072
		switch(RT) {
13073
			case 0x0094: /* 'BrtWsDim' */
13074
				ref = val; break;
13075
			case 0x0000: /* 'BrtRowHdr' */
13076
				row = val;
13077
				if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
13078
				rr = encode_row(R = row.r);
13079
				opts['!row'] = row.r;
13080
				if(val.hidden || val.hpt || val.level != null) {
13081
					if(val.hpt) val.hpx = pt2px(val.hpt);
13082
					rowinfo[val.r] = val;
13083
				}
13084
				break;
13085
13086
			case 0x0002: /* 'BrtCellRk' */
13087
			case 0x0003: /* 'BrtCellError' */
13088
			case 0x0004: /* 'BrtCellBool' */
13089
			case 0x0005: /* 'BrtCellReal' */
13090
			case 0x0006: /* 'BrtCellSt' */
13091
			case 0x0007: /* 'BrtCellIsst' */
13092
			case 0x0008: /* 'BrtFmlaString' */
13093
			case 0x0009: /* 'BrtFmlaNum' */
13094
			case 0x000A: /* 'BrtFmlaBool' */
13095
			case 0x000B: /* 'BrtFmlaError' */
13096
				p = ({t:val[2]});
13097
				switch(val[2]) {
13098
					case 'n': p.v = val[1]; break;
13099
					case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
13100
					case 'b': p.v = val[1] ? true : false; break;
13101
					case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
13102
					case 'str': p.t = 's'; p.v = val[1]; break;
13103
				}
13104
				if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
13105
				C = val[0].c;
13106
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
13107
				else s[encode_col(C) + rr] = p;
13108
				if(opts.cellFormula) {
13109
					af = false;
13110
					for(ai = 0; ai < arrayf.length; ++ai) {
13111
						var aii = arrayf[ai];
13112
						if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
13113
							if(C >= aii[0].s.c && C <= aii[0].e.c) {
13114
								p.F = encode_range(aii[0]); af = true;
13115
							}
13116
					}
13117
					if(!af && val.length > 3) p.f = val[3];
13118
				}
13119
				if(refguess.s.r > row.r) refguess.s.r = row.r;
13120
				if(refguess.s.c > C) refguess.s.c = C;
13121
				if(refguess.e.r < row.r) refguess.e.r = row.r;
13122
				if(refguess.e.c < C) refguess.e.c = C;
13123
				if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
13124
					var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
13125
				}
13126
				break;
13127
13128
			case 0x0001: /* 'BrtCellBlank' */
13129
				if(!opts.sheetStubs || pass) break;
13130
				p = ({t:'z',v:undefined});
13131
				C = val[0].c;
13132
				if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
13133
				else s[encode_col(C) + rr] = p;
13134
				if(refguess.s.r > row.r) refguess.s.r = row.r;
13135
				if(refguess.s.c > C) refguess.s.c = C;
13136
				if(refguess.e.r < row.r) refguess.e.r = row.r;
13137
				if(refguess.e.c < C) refguess.e.c = C;
13138
				break;
13139
13140
			case 0x00B0: /* 'BrtMergeCell' */
13141
				merges.push(val); break;
13142
13143
			case 0x01EE: /* 'BrtHLink' */
13144
				var rel = rels['!id'][val.relId];
13145
				if(rel) {
13146
					val.Target = rel.Target;
13147
					if(val.loc) val.Target += "#"+val.loc;
13148
					val.Rel = rel;
13149
				} else if(val.relId == '') {
13150
					val.Target = "#" + val.loc;
13151
				}
13152
				for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
13153
					if(opts.dense) {
13154
						if(!s[R]) s[R] = [];
13155
						if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
13156
						s[R][C].l = val;
13157
					} else {
13158
						addr = encode_cell({c:C,r:R});
13159
						if(!s[addr]) s[addr] = {t:'z',v:undefined};
13160
						s[addr].l = val;
13161
					}
13162
				}
13163
				break;
13164
13165
			case 0x01AA: /* 'BrtArrFmla' */
13166
				if(!opts.cellFormula) break;
13167
				arrayf.push(val);
13168
				cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr]));
13169
				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
13170
				cell.F = encode_range(val[0]);
13171
				break;
13172
			case 0x01AB: /* 'BrtShrFmla' */
13173
				if(!opts.cellFormula) break;
13174
				sharedf[encode_cell(val[0].s)] = val[1];
13175
				cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
13176
				cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
13177
				break;
13178
13179
			/* identical to 'ColInfo' in XLS */
13180
			case 0x003C: /* 'BrtColInfo' */
13181
				if(!opts.cellStyles) break;
13182
				while(val.e >= val.s) {
13183
					colinfo[val.e--] = { width: val.w/256, hidden: !!(val.flags & 0x01) };
13184
					if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
13185
					process_col(colinfo[val.e+1]);
13186
				}
13187
				break;
13188
13189
			case 0x00A1: /* 'BrtBeginAFilter' */
13190
				s['!autofilter'] = { ref:encode_range(val) };
13191
				break;
13192
13193
			case 0x01DC: /* 'BrtMargins' */
13194
				s['!margins'] = val;
13195
				break;
13196
13197
			case 0x0093: /* 'BrtWsProp' */
13198
				if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13199
				if(val.name) wb.Sheets[idx].CodeName = val.name;
13200
				break;
13201
13202
			case 0x0089: /* 'BrtBeginWsView' */
13203
				if(!wb.Views) wb.Views = [{}];
13204
				if(!wb.Views[0]) wb.Views[0] = {};
13205
				if(val.RTL) wb.Views[0].RTL = true;
13206
				break;
13207
13208
			case 0x01E5: /* 'BrtWsFmtInfo' */
13209
				break;
13210
			case 0x00AF: /* 'BrtAFilterDateGroupItem' */
13211
			case 0x0284: /* 'BrtActiveX' */
13212
			case 0x0271: /* 'BrtBigName' */
13213
			case 0x0232: /* 'BrtBkHim' */
13214
			case 0x018C: /* 'BrtBrk' */
13215
			case 0x0458: /* 'BrtCFIcon' */
13216
			case 0x047A: /* 'BrtCFRuleExt' */
13217
			case 0x01D7: /* 'BrtCFVO' */
13218
			case 0x041A: /* 'BrtCFVO14' */
13219
			case 0x0289: /* 'BrtCellIgnoreEC' */
13220
			case 0x0451: /* 'BrtCellIgnoreEC14' */
13221
			case 0x0031: /* 'BrtCellMeta' */
13222
			case 0x024D: /* 'BrtCellSmartTagProperty' */
13223
			case 0x025F: /* 'BrtCellWatch' */
13224
			case 0x0234: /* 'BrtColor' */
13225
			case 0x041F: /* 'BrtColor14' */
13226
			case 0x00A8: /* 'BrtColorFilter' */
13227
			case 0x00AE: /* 'BrtCustomFilter' */
13228
			case 0x049C: /* 'BrtCustomFilter14' */
13229
			case 0x01F3: /* 'BrtDRef' */
13230
			case 0x0040: /* 'BrtDVal' */
13231
			case 0x041D: /* 'BrtDVal14' */
13232
			case 0x0226: /* 'BrtDrawing' */
13233
			case 0x00AB: /* 'BrtDynamicFilter' */
13234
			case 0x00A7: /* 'BrtFilter' */
13235
			case 0x0499: /* 'BrtFilter14' */
13236
			case 0x00A9: /* 'BrtIconFilter' */
13237
			case 0x049D: /* 'BrtIconFilter14' */
13238
			case 0x0227: /* 'BrtLegacyDrawing' */
13239
			case 0x0228: /* 'BrtLegacyDrawingHF' */
13240
			case 0x0295: /* 'BrtListPart' */
13241
			case 0x027F: /* 'BrtOleObject' */
13242
			case 0x01DE: /* 'BrtPageSetup' */
13243
			case 0x0097: /* 'BrtPane' */
13244
			case 0x0219: /* 'BrtPhoneticInfo' */
13245
			case 0x01DD: /* 'BrtPrintOptions' */
13246
			case 0x0218: /* 'BrtRangeProtection' */
13247
			case 0x044F: /* 'BrtRangeProtection14' */
13248
			case 0x02A8: /* 'BrtRangeProtectionIso' */
13249
			case 0x0450: /* 'BrtRangeProtectionIso14' */
13250
			case 0x0400: /* 'BrtRwDescent' */
13251
			case 0x0098: /* 'BrtSel' */
13252
			case 0x0297: /* 'BrtSheetCalcProp' */
13253
			case 0x0217: /* 'BrtSheetProtection' */
13254
			case 0x02A6: /* 'BrtSheetProtectionIso' */
13255
			case 0x01F8: /* 'BrtSlc' */
13256
			case 0x0413: /* 'BrtSparkline' */
13257
			case 0x01AC: /* 'BrtTable' */
13258
			case 0x00AA: /* 'BrtTop10Filter' */
13259
			case 0x0C00: /* 'BrtUid' */
13260
			case 0x0032: /* 'BrtValueMeta' */
13261
			case 0x0816: /* 'BrtWebExtension' */
13262
			case 0x0415: /* 'BrtWsFmtInfoEx14' */
13263
				break;
13264
13265
			case 0x0023: /* 'BrtFRTBegin' */
13266
				pass = true; break;
13267
			case 0x0024: /* 'BrtFRTEnd' */
13268
				pass = false; break;
13269
			case 0x0025: /* 'BrtACBegin' */ break;
13270
			case 0x0026: /* 'BrtACEnd' */ break;
13271
13272
			default:
13273
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
13274
				else if((R_n||"").indexOf("End") > 0){/* empty */}
13275
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
13276
		}
13277
	}, opts);
13278
13279
	delete opts.supbooks;
13280
	delete opts['!row'];
13281
13282
	if(!s["!ref"] && (refguess.s.r < 2000000 || ref && (ref.e.r > 0 || ref.e.c > 0 || ref.s.r > 0 || ref.s.c > 0))) s["!ref"] = encode_range(ref || refguess);
13283
	if(opts.sheetRows && s["!ref"]) {
13284
		var tmpref = safe_decode_range(s["!ref"]);
13285
		if(opts.sheetRows <= +tmpref.e.r) {
13286
			tmpref.e.r = opts.sheetRows - 1;
13287
			if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
13288
			if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
13289
			if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
13290
			if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
13291
			s["!fullref"] = s["!ref"];
13292
			s["!ref"] = encode_range(tmpref);
13293
		}
13294
	}
13295
	if(merges.length > 0) s["!merges"] = merges;
13296
	if(colinfo.length > 0) s["!cols"] = colinfo;
13297
	if(rowinfo.length > 0) s["!rows"] = rowinfo;
13298
	return s;
13299
}
13300
13301
/* TODO: something useful -- this is a stub */
13302
function write_ws_bin_cell(ba, cell, R, C, opts, ws) {
13303
	if(cell.v === undefined) return "";
13304
	var vv = "";
13305
	switch(cell.t) {
13306
		case 'b': vv = cell.v ? "1" : "0"; break;
13307
		case 'd': // no BrtCellDate :(
13308
			cell = dup(cell);
13309
			cell.z = cell.z || SSF._table[14];
13310
			cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
13311
			break;
13312
		/* falls through */
13313
		case 'n': case 'e': vv = ''+cell.v; break;
13314
		default: vv = cell.v; break;
13315
	}
13316
	var o = ({r:R, c:C});
13317
	/* TODO: cell style */
13318
	o.s = get_cell_style(opts.cellXfs, cell, opts);
13319
	if(cell.l) ws['!links'].push([encode_cell(o), cell.l]);
13320
	if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
13321
	switch(cell.t) {
13322
		case 's': case 'str':
13323
			if(opts.bookSST) {
13324
				vv = get_sst_id(opts.Strings, (cell.v), opts.revStrings);
13325
				o.t = "s"; o.v = vv;
13326
				write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
13327
			} else {
13328
				o.t = "str";
13329
				write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
13330
			}
13331
			return;
13332
		case 'n':
13333
			/* TODO: determine threshold for Real vs RK */
13334
			if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
13335
			else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
13336
			return;
13337
		case 'b':
13338
			o.t = "b";
13339
			write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
13340
			return;
13341
		case 'e': /* TODO: error */ o.t = "e"; break;
13342
	}
13343
	write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
13344
}
13345
13346
function write_CELLTABLE(ba, ws, idx, opts) {
13347
	var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
13348
	write_record(ba, 'BrtBeginSheetData');
13349
	var dense = Array.isArray(ws);
13350
	var cap = range.e.r;
13351
	if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1);
13352
	for(var R = range.s.r; R <= cap; ++R) {
13353
		rr = encode_row(R);
13354
		/* [ACCELLTABLE] */
13355
		/* BrtRowHdr */
13356
		write_row_header(ba, ws, range, R);
13357
		if(R <= range.e.r) for(var C = range.s.c; C <= range.e.c; ++C) {
13358
			/* *16384CELL */
13359
			if(R === range.s.r) cols[C] = encode_col(C);
13360
			ref = cols[C] + rr;
13361
			var cell = dense ? (ws[R]||[])[C] : ws[ref];
13362
			if(!cell) continue;
13363
			/* write cell */
13364
			write_ws_bin_cell(ba, cell, R, C, opts, ws);
13365
		}
13366
	}
13367
	write_record(ba, 'BrtEndSheetData');
13368
}
13369
13370
function write_MERGECELLS(ba, ws) {
13371
	if(!ws || !ws['!merges']) return;
13372
	write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
13373
	ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
13374
	write_record(ba, 'BrtEndMergeCells');
13375
}
13376
13377
function write_COLINFOS(ba, ws) {
13378
	if(!ws || !ws['!cols']) return;
13379
	write_record(ba, 'BrtBeginColInfos');
13380
	ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
13381
	write_record(ba, 'BrtEndColInfos');
13382
}
13383
13384
function write_IGNOREECS(ba, ws) {
13385
	if(!ws || !ws['!ref']) return;
13386
	write_record(ba, 'BrtBeginCellIgnoreECs');
13387
	write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref'])));
13388
	write_record(ba, 'BrtEndCellIgnoreECs');
13389
}
13390
13391
function write_HLINKS(ba, ws, rels) {
13392
	/* *BrtHLink */
13393
	ws['!links'].forEach(function(l) {
13394
		if(!l[1].Target) return;
13395
		var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK);
13396
		write_record(ba, "BrtHLink", write_BrtHLink(l, rId));
13397
	});
13398
	delete ws['!links'];
13399
}
13400
function write_LEGACYDRAWING(ba, ws, idx, rels) {
13401
	/* [BrtLegacyDrawing] */
13402
	if(ws['!comments'].length > 0) {
13403
		var rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
13404
		write_record(ba, "BrtLegacyDrawing", write_RelID("rId" + rId));
13405
		ws['!legacy'] = rId;
13406
	}
13407
}
13408
13409
function write_AUTOFILTER(ba, ws) {
13410
	if(!ws['!autofilter']) return;
13411
	write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ws['!autofilter'].ref)));
13412
	/* *FILTERCOLUMN */
13413
	/* [SORTSTATE] */
13414
	/* BrtEndAFilter */
13415
	write_record(ba, "BrtEndAFilter");
13416
}
13417
13418
function write_WSVIEWS2(ba, ws, Workbook) {
13419
	write_record(ba, "BrtBeginWsViews");
13420
	{ /* 1*WSVIEW2 */
13421
		/* [ACUID] */
13422
		write_record(ba, "BrtBeginWsView", write_BrtBeginWsView(ws, Workbook));
13423
		/* [BrtPane] */
13424
		/* *4BrtSel */
13425
		/* *4SXSELECT */
13426
		/* *FRT */
13427
		write_record(ba, "BrtEndWsView");
13428
	}
13429
	/* *FRT */
13430
	write_record(ba, "BrtEndWsViews");
13431
}
13432
13433
function write_WSFMTINFO() {
13434
	/* [ACWSFMTINFO] */
13435
	//write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
13436
}
13437
13438
function write_SHEETPROTECT(ba, ws) {
13439
	if(!ws['!protect']) return;
13440
	/* [BrtSheetProtectionIso] */
13441
	write_record(ba, "BrtSheetProtection", write_BrtSheetProtection(ws['!protect']));
13442
}
13443
13444
function write_ws_bin(idx, opts, wb, rels) {
13445
	var ba = buf_array();
13446
	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
13447
	var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
13448
	var r = safe_decode_range(ws['!ref'] || "A1");
13449
	if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
13450
		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
13451
		r.e.c = Math.min(r.e.c, 0x3FFF);
13452
		r.e.r = Math.min(r.e.c, 0xFFFFF);
13453
	}
13454
	ws['!links'] = [];
13455
	/* passed back to write_zip and removed there */
13456
	ws['!comments'] = [];
13457
	write_record(ba, "BrtBeginSheet");
13458
	if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
13459
	write_record(ba, "BrtWsDim", write_BrtWsDim(r));
13460
	write_WSVIEWS2(ba, ws, wb.Workbook);
13461
	write_WSFMTINFO(ba, ws);
13462
	write_COLINFOS(ba, ws, idx, opts, wb);
13463
	write_CELLTABLE(ba, ws, idx, opts, wb);
13464
	/* [BrtSheetCalcProp] */
13465
	write_SHEETPROTECT(ba, ws);
13466
	/* *([BrtRangeProtectionIso] BrtRangeProtection) */
13467
	/* [SCENMAN] */
13468
	write_AUTOFILTER(ba, ws);
13469
	/* [SORTSTATE] */
13470
	/* [DCON] */
13471
	/* [USERSHVIEWS] */
13472
	write_MERGECELLS(ba, ws);
13473
	/* [BrtPhoneticInfo] */
13474
	/* *CONDITIONALFORMATTING */
13475
	/* [DVALS] */
13476
	write_HLINKS(ba, ws, rels);
13477
	/* [BrtPrintOptions] */
13478
	if(ws['!margins']) write_record(ba, "BrtMargins", write_BrtMargins(ws['!margins']));
13479
	/* [BrtPageSetup] */
13480
	/* [HEADERFOOTER] */
13481
	/* [RWBRK] */
13482
	/* [COLBRK] */
13483
	/* *BrtBigName */
13484
	/* [CELLWATCHES] */
13485
	if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) write_IGNOREECS(ba, ws);
13486
	/* [SMARTTAGS] */
13487
	/* [BrtDrawing] */
13488
	write_LEGACYDRAWING(ba, ws, idx, rels);
13489
	/* [BrtLegacyDrawingHF] */
13490
	/* [BrtBkHim] */
13491
	/* [OLEOBJECTS] */
13492
	/* [ACTIVEXCONTROLS] */
13493
	/* [WEBPUBITEMS] */
13494
	/* [LISTPARTS] */
13495
	/* FRTWORKSHEET */
13496
	write_record(ba, "BrtEndSheet");
13497
	return ba.end();
13498
}
13499
function parse_numCache(data) {
13500
	var col = [];
13501
13502
	/* 21.2.2.150 pt CT_NumVal */
13503
	(data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
13504
		var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
13505
		if(!q) return;
13506
		col[+q[1]] = +q[2];
13507
	});
13508
13509
	/* 21.2.2.71 formatCode CT_Xstring */
13510
	var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
13511
13512
	return [col, nf];
13513
}
13514
13515
/* 21.2 DrawingML - Charts */
13516
function parse_chart(data, name, opts, rels, wb, csheet) {
13517
	var cs = ((csheet || {"!type":"chart"}));
13518
	if(!data) return csheet;
13519
	/* 21.2.2.27 chart CT_Chart */
13520
13521
	var C = 0, R = 0, col = "A";
13522
	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
13523
13524
	/* 21.2.2.120 numCache CT_NumData */
13525
	(data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
13526
		var cache = parse_numCache(nc);
13527
		refguess.s.r = refguess.s.c = 0;
13528
		refguess.e.c = C;
13529
		col = encode_col(C);
13530
		cache[0].forEach(function(n,i) {
13531
			cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
13532
			R = i;
13533
		});
13534
		if(refguess.e.r < R) refguess.e.r = R;
13535
		++C;
13536
	});
13537
	if(C > 0) cs["!ref"] = encode_range(refguess);
13538
	return cs;
13539
}
13540
RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
13541
13542
var CS_XML_ROOT = writextag('chartsheet', null, {
13543
	'xmlns': XMLNS.main[0],
13544
	'xmlns:r': XMLNS.r
13545
});
13546
13547
/* 18.3 Worksheets also covers Chartsheets */
13548
function parse_cs_xml(data, opts, idx, rels, wb) {
13549
	if(!data) return data;
13550
	/* 18.3.1.12 chartsheet CT_ChartSheet */
13551
	if(!rels) rels = {'!id':{}};
13552
	var s = {'!type':"chart", '!chart':null, '!rel':""};
13553
	var m;
13554
13555
	/* 18.3.1.83 sheetPr CT_ChartsheetPr */
13556
	var sheetPr = data.match(sheetprregex);
13557
	if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
13558
13559
	/* 18.3.1.36 drawing CT_Drawing */
13560
	if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
13561
13562
	if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']];
13563
	return s;
13564
}
13565
function write_cs_xml(idx, opts, wb, rels) {
13566
	var o = [XML_HEADER, CS_XML_ROOT];
13567
	o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
13568
	add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
13569
	if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
13570
	return o.join("");
13571
}
13572
13573
/* [MS-XLSB] 2.4.331 BrtCsProp */
13574
function parse_BrtCsProp(data, length) {
13575
	data.l += 10;
13576
	var name = parse_XLWideString(data, length - 10);
13577
	return { name: name };
13578
}
13579
13580
/* [MS-XLSB] 2.1.7.7 Chart Sheet */
13581
function parse_cs_bin(data, opts, idx, rels, wb) {
13582
	if(!data) return data;
13583
	if(!rels) rels = {'!id':{}};
13584
	var s = {'!type':"chart", '!chart':null, '!rel':""};
13585
	var state = [];
13586
	var pass = false;
13587
	recordhopper(data, function cs_parse(val, R_n, RT) {
13588
		switch(RT) {
13589
13590
			case 0x0226: /* 'BrtDrawing' */
13591
				s['!rel'] = val; break;
13592
13593
			case 0x028B: /* 'BrtCsProp' */
13594
				if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13595
				if(val.name) wb.Sheets[idx].CodeName = val.name;
13596
				break;
13597
13598
			case 0x0232: /* 'BrtBkHim' */
13599
			case 0x028C: /* 'BrtCsPageSetup' */
13600
			case 0x029D: /* 'BrtCsProtection' */
13601
			case 0x02A7: /* 'BrtCsProtectionIso' */
13602
			case 0x0227: /* 'BrtLegacyDrawing' */
13603
			case 0x0228: /* 'BrtLegacyDrawingHF' */
13604
			case 0x01DC: /* 'BrtMargins' */
13605
			case 0x0C00: /* 'BrtUid' */
13606
				break;
13607
13608
			case 0x0023: /* 'BrtFRTBegin' */
13609
				pass = true; break;
13610
			case 0x0024: /* 'BrtFRTEnd' */
13611
				pass = false; break;
13612
			case 0x0025: /* 'BrtACBegin' */
13613
				state.push(R_n); break;
13614
			case 0x0026: /* 'BrtACEnd' */
13615
				state.pop(); break;
13616
13617
			default:
13618
				if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
13619
				else if((R_n||"").indexOf("End") > 0) state.pop();
13620
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
13621
		}
13622
	}, opts);
13623
13624
	if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']];
13625
	return s;
13626
}
13627
function write_cs_bin() {
13628
	var ba = buf_array();
13629
	write_record(ba, "BrtBeginSheet");
13630
	/* [BrtCsProp] */
13631
	/* CSVIEWS */
13632
	/* [[BrtCsProtectionIso] BrtCsProtection] */
13633
	/* [USERCSVIEWS] */
13634
	/* [BrtMargins] */
13635
	/* [BrtCsPageSetup] */
13636
	/* [HEADERFOOTER] */
13637
	/* BrtDrawing */
13638
	/* [BrtLegacyDrawing] */
13639
	/* [BrtLegacyDrawingHF] */
13640
	/* [BrtBkHim] */
13641
	/* [WEBPUBITEMS] */
13642
	/* FRTCHARTSHEET */
13643
	write_record(ba, "BrtEndSheet");
13644
	return ba.end();
13645
}
13646
/* 18.2.28 (CT_WorkbookProtection) Defaults */
13647
var WBPropsDef = [
13648
	['allowRefreshQuery',           false, "bool"],
13649
	['autoCompressPictures',        true,  "bool"],
13650
	['backupFile',                  false, "bool"],
13651
	['checkCompatibility',          false, "bool"],
13652
	['CodeName',                    ''],
13653
	['date1904',                    false, "bool"],
13654
	['defaultThemeVersion',         0,      "int"],
13655
	['filterPrivacy',               false, "bool"],
13656
	['hidePivotFieldList',          false, "bool"],
13657
	['promptedSolutions',           false, "bool"],
13658
	['publishItems',                false, "bool"],
13659
	['refreshAllConnections',       false, "bool"],
13660
	['saveExternalLinkValues',      true,  "bool"],
13661
	['showBorderUnselectedTables',  true,  "bool"],
13662
	['showInkAnnotation',           true,  "bool"],
13663
	['showObjects',                 'all'],
13664
	['showPivotChartFilter',        false, "bool"],
13665
	['updateLinks', 'userSet']
13666
];
13667
13668
/* 18.2.30 (CT_BookView) Defaults */
13669
var WBViewDef = [
13670
	['activeTab',                   0,      "int"],
13671
	['autoFilterDateGrouping',      true,  "bool"],
13672
	['firstSheet',                  0,      "int"],
13673
	['minimized',                   false, "bool"],
13674
	['showHorizontalScroll',        true,  "bool"],
13675
	['showSheetTabs',               true,  "bool"],
13676
	['showVerticalScroll',          true,  "bool"],
13677
	['tabRatio',                    600,    "int"],
13678
	['visibility',                  'visible']
13679
	//window{Height,Width}, {x,y}Window
13680
];
13681
13682
/* 18.2.19 (CT_Sheet) Defaults */
13683
var SheetDef = [
13684
	//['state', 'visible']
13685
];
13686
13687
/* 18.2.2  (CT_CalcPr) Defaults */
13688
var CalcPrDef = [
13689
	['calcCompleted', 'true'],
13690
	['calcMode', 'auto'],
13691
	['calcOnSave', 'true'],
13692
	['concurrentCalc', 'true'],
13693
	['fullCalcOnLoad', 'false'],
13694
	['fullPrecision', 'true'],
13695
	['iterate', 'false'],
13696
	['iterateCount', '100'],
13697
	['iterateDelta', '0.001'],
13698
	['refMode', 'A1']
13699
];
13700
13701
/* 18.2.3 (CT_CustomWorkbookView) Defaults */
13702
/*var CustomWBViewDef = [
13703
	['autoUpdate', 'false'],
13704
	['changesSavedWin', 'false'],
13705
	['includeHiddenRowCol', 'true'],
13706
	['includePrintSettings', 'true'],
13707
	['maximized', 'false'],
13708
	['minimized', 'false'],
13709
	['onlySync', 'false'],
13710
	['personalView', 'false'],
13711
	['showComments', 'commIndicator'],
13712
	['showFormulaBar', 'true'],
13713
	['showHorizontalScroll', 'true'],
13714
	['showObjects', 'all'],
13715
	['showSheetTabs', 'true'],
13716
	['showStatusbar', 'true'],
13717
	['showVerticalScroll', 'true'],
13718
	['tabRatio', '600'],
13719
	['xWindow', '0'],
13720
	['yWindow', '0']
13721
];*/
13722
13723
function push_defaults_array(target, defaults) {
13724
	for(var j = 0; j != target.length; ++j) { var w = target[j];
13725
		for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
13726
			if(w[z[0]] == null) w[z[0]] = z[1];
13727
			else switch(z[2]) {
13728
			case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
13729
			case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
13730
			}
13731
		}
13732
	}
13733
}
13734
function push_defaults(target, defaults) {
13735
	for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
13736
		if(target[z[0]] == null) target[z[0]] = z[1];
13737
		else switch(z[2]) {
13738
			case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
13739
			case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
13740
		}
13741
	}
13742
}
13743
13744
function parse_wb_defaults(wb) {
13745
	push_defaults(wb.WBProps, WBPropsDef);
13746
	push_defaults(wb.CalcPr, CalcPrDef);
13747
13748
	push_defaults_array(wb.WBView, WBViewDef);
13749
	push_defaults_array(wb.Sheets, SheetDef);
13750
13751
	_ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
13752
}
13753
13754
function safe1904(wb) {
13755
	/* TODO: store date1904 somewhere else */
13756
	if(!wb.Workbook) return "false";
13757
	if(!wb.Workbook.WBProps) return "false";
13758
	return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
13759
}
13760
13761
var badchars = "][*?\/\\".split("");
13762
function check_ws_name(n, safe) {
13763
	if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
13764
	var _good = true;
13765
	badchars.forEach(function(c) {
13766
		if(n.indexOf(c) == -1) return;
13767
		if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
13768
		_good = false;
13769
	});
13770
	return _good;
13771
}
13772
function check_wb_names(N, S, codes) {
13773
	N.forEach(function(n,i) {
13774
		check_ws_name(n);
13775
		for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
13776
		if(codes) {
13777
			var cn = (S && S[i] && S[i].CodeName) || n;
13778
			if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
13779
		}
13780
	});
13781
}
13782
function check_wb(wb) {
13783
	if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
13784
	if(!wb.SheetNames.length) throw new Error("Workbook is empty");
13785
	var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
13786
	check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
13787
	for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
13788
	/* TODO: validate workbook */
13789
}
13790
/* 18.2 Workbook */
13791
var wbnsregex = /<\w+:workbook/;
13792
function parse_wb_xml(data, opts) {
13793
	if(!data) throw new Error("Could not find file");
13794
	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
13795
	var pass = false, xmlns = "xmlns";
13796
	var dname = {}, dnstart = 0;
13797
	data.replace(tagregex, function xml_wb(x, idx) {
13798
		var y = parsexmltag(x);
13799
		switch(strip_ns(y[0])) {
13800
			case '<?xml': break;
13801
13802
			/* 18.2.27 workbook CT_Workbook 1 */
13803
			case '<workbook':
13804
				if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
13805
				wb.xmlns = y[xmlns];
13806
				break;
13807
			case '</workbook>': break;
13808
13809
			/* 18.2.13 fileVersion CT_FileVersion ? */
13810
			case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
13811
			case '<fileVersion/>': case '</fileVersion>': break;
13812
13813
			/* 18.2.12 fileSharing CT_FileSharing ? */
13814
			case '<fileSharing': case '<fileSharing/>': break;
13815
13816
			/* 18.2.28 workbookPr CT_WorkbookPr ? */
13817
			case '<workbookPr':
13818
			case '<workbookPr/>':
13819
				WBPropsDef.forEach(function(w) {
13820
					if(y[w[0]] == null) return;
13821
					switch(w[2]) {
13822
						case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
13823
						case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
13824
						default: wb.WBProps[w[0]] = y[w[0]];
13825
					}
13826
				});
13827
				if(y.codeName) wb.WBProps.CodeName = y.codeName;
13828
				break;
13829
			case '</workbookPr>': break;
13830
13831
			/* 18.2.29 workbookProtection CT_WorkbookProtection ? */
13832
			case '<workbookProtection': break;
13833
			case '<workbookProtection/>': break;
13834
13835
			/* 18.2.1  bookViews CT_BookViews ? */
13836
			case '<bookViews': case '<bookViews>': case '</bookViews>': break;
13837
			/* 18.2.30   workbookView CT_BookView + */
13838
			case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
13839
			case '</workbookView>': break;
13840
13841
			/* 18.2.20 sheets CT_Sheets 1 */
13842
			case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
13843
			/* 18.2.19   sheet CT_Sheet + */
13844
			case '<sheet':
13845
				switch(y.state) {
13846
					case "hidden": y.Hidden = 1; break;
13847
					case "veryHidden": y.Hidden = 2; break;
13848
					default: y.Hidden = 0;
13849
				}
13850
				delete y.state;
13851
				y.name = unescapexml(utf8read(y.name));
13852
				delete y[0]; wb.Sheets.push(y); break;
13853
			case '</sheet>': break;
13854
13855
			/* 18.2.15 functionGroups CT_FunctionGroups ? */
13856
			case '<functionGroups': case '<functionGroups/>': break;
13857
			/* 18.2.14   functionGroup CT_FunctionGroup + */
13858
			case '<functionGroup': break;
13859
13860
			/* 18.2.9  externalReferences CT_ExternalReferences ? */
13861
			case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
13862
			/* 18.2.8    externalReference CT_ExternalReference + */
13863
			case '<externalReference': break;
13864
13865
			/* 18.2.6  definedNames CT_DefinedNames ? */
13866
			case '<definedNames/>': break;
13867
			case '<definedNames>': case '<definedNames': pass=true; break;
13868
			case '</definedNames>': pass=false; break;
13869
			/* 18.2.5    definedName CT_DefinedName + */
13870
			case '<definedName': {
13871
				dname = {};
13872
				dname.Name = utf8read(y.name);
13873
				if(y.comment) dname.Comment = y.comment;
13874
				if(y.localSheetId) dname.Sheet = +y.localSheetId;
13875
				dnstart = idx + x.length;
13876
			}	break;
13877
			case '</definedName>': {
13878
				dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
13879
				wb.Names.push(dname);
13880
			} break;
13881
			case '<definedName/>': break;
13882
13883
			/* 18.2.2  calcPr CT_CalcPr ? */
13884
			case '<calcPr': delete y[0]; wb.CalcPr = y; break;
13885
			case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
13886
			case '</calcPr>': break;
13887
13888
			/* 18.2.16 oleSize CT_OleSize ? (ref required) */
13889
			case '<oleSize': break;
13890
13891
			/* 18.2.4  customWorkbookViews CT_CustomWorkbookViews ? */
13892
			case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
13893
			/* 18.2.3    customWorkbookView CT_CustomWorkbookView + */
13894
			case '<customWorkbookView': case '</customWorkbookView>': break;
13895
13896
			/* 18.2.18 pivotCaches CT_PivotCaches ? */
13897
			case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
13898
			/* 18.2.17 pivotCache CT_PivotCache ? */
13899
			case '<pivotCache': break;
13900
13901
			/* 18.2.21 smartTagPr CT_SmartTagPr ? */
13902
			case '<smartTagPr': case '<smartTagPr/>': break;
13903
13904
			/* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
13905
			case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
13906
			/* 18.2.22   smartTagType CT_SmartTagType ? */
13907
			case '<smartTagType': break;
13908
13909
			/* 18.2.24 webPublishing CT_WebPublishing ? */
13910
			case '<webPublishing': case '<webPublishing/>': break;
13911
13912
			/* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
13913
			case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
13914
13915
			/* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
13916
			case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
13917
			/* 18.2.25 webPublishObject CT_WebPublishObject ? */
13918
			case '<webPublishObject': break;
13919
13920
			/* 18.2.10 extLst CT_ExtensionList ? */
13921
			case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
13922
			/* 18.2.7    ext CT_Extension + */
13923
			case '<ext': pass=true; break; //TODO: check with versions of excel
13924
			case '</ext>': pass=false; break;
13925
13926
			/* Others */
13927
			case '<ArchID': break;
13928
			case '<AlternateContent':
13929
			case '<AlternateContent>': pass=true; break;
13930
			case '</AlternateContent>': pass=false; break;
13931
13932
			/* TODO */
13933
			case '<revisionPtr': break;
13934
13935
			default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
13936
		}
13937
		return x;
13938
	});
13939
	if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
13940
13941
	parse_wb_defaults(wb);
13942
13943
	return wb;
13944
}
13945
13946
var WB_XML_ROOT = writextag('workbook', null, {
13947
	'xmlns': XMLNS.main[0],
13948
	//'xmlns:mx': XMLNS.mx,
13949
	//'xmlns:s': XMLNS.main[0],
13950
	'xmlns:r': XMLNS.r
13951
});
13952
13953
function write_wb_xml(wb) {
13954
	var o = [XML_HEADER];
13955
	o[o.length] = WB_XML_ROOT;
13956
13957
	var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
13958
13959
	/* fileVersion */
13960
	/* fileSharing */
13961
13962
	var workbookPr = ({codeName:"ThisWorkbook"});
13963
	if(wb.Workbook && wb.Workbook.WBProps) {
13964
		WBPropsDef.forEach(function(x) {
13965
if((wb.Workbook.WBProps[x[0]]) == null) return;
13966
			if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
13967
			workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
13968
		});
13969
if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
13970
	}
13971
	o[o.length] = (writextag('workbookPr', null, workbookPr));
13972
13973
	/* workbookProtection */
13974
	/* bookViews */
13975
13976
	o[o.length] = "<sheets>";
13977
	var sheets = wb.Workbook && wb.Workbook.Sheets || [];
13978
	for(var i = 0; i != wb.SheetNames.length; ++i) {
13979
		var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
13980
		sht.sheetId = ""+(i+1);
13981
		sht["r:id"] = "rId"+(i+1);
13982
		if(sheets[i]) switch(sheets[i].Hidden) {
13983
			case 1: sht.state = "hidden"; break;
13984
			case 2: sht.state = "veryHidden"; break;
13985
		}
13986
		o[o.length] = (writextag('sheet',null,sht));
13987
	}
13988
	o[o.length] = "</sheets>";
13989
13990
	/* functionGroups */
13991
	/* externalReferences */
13992
13993
	if(write_names) {
13994
		o[o.length] = "<definedNames>";
13995
		if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
13996
			var d = {name:n.Name};
13997
			if(n.Comment) d.comment = n.Comment;
13998
			if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
13999
			if(!n.Ref) return;
14000
			o[o.length] = writextag('definedName', String(n.Ref), d);
14001
		});
14002
		o[o.length] = "</definedNames>";
14003
	}
14004
14005
	/* calcPr */
14006
	/* oleSize */
14007
	/* customWorkbookViews */
14008
	/* pivotCaches */
14009
	/* smartTagPr */
14010
	/* smartTagTypes */
14011
	/* webPublishing */
14012
	/* fileRecoveryPr */
14013
	/* webPublishObjects */
14014
	/* extLst */
14015
14016
	if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
14017
	return o.join("");
14018
}
14019
/* [MS-XLSB] 2.4.304 BrtBundleSh */
14020
function parse_BrtBundleSh(data, length) {
14021
	var z = {};
14022
	z.Hidden = data.read_shift(4); //hsState ST_SheetState
14023
	z.iTabID = data.read_shift(4);
14024
	z.strRelID = parse_RelID(data,length-8);
14025
	z.name = parse_XLWideString(data);
14026
	return z;
14027
}
14028
function write_BrtBundleSh(data, o) {
14029
	if(!o) o = new_buf(127);
14030
	o.write_shift(4, data.Hidden);
14031
	o.write_shift(4, data.iTabID);
14032
	write_RelID(data.strRelID, o);
14033
	write_XLWideString(data.name.slice(0,31), o);
14034
	return o.length > o.l ? o.slice(0, o.l) : o;
14035
}
14036
14037
/* [MS-XLSB] 2.4.815 BrtWbProp */
14038
function parse_BrtWbProp(data, length) {
14039
	var o = ({});
14040
	var flags = data.read_shift(4);
14041
	o.defaultThemeVersion = data.read_shift(4);
14042
	var strName = (length > 8) ? parse_XLWideString(data) : "";
14043
	if(strName.length > 0) o.CodeName = strName;
14044
	o.autoCompressPictures = !!(flags & 0x10000);
14045
	o.backupFile = !!(flags & 0x40);
14046
	o.checkCompatibility = !!(flags & 0x1000);
14047
	o.date1904 = !!(flags & 0x01);
14048
	o.filterPrivacy = !!(flags & 0x08);
14049
	o.hidePivotFieldList = !!(flags & 0x400);
14050
	o.promptedSolutions = !!(flags & 0x10);
14051
	o.publishItems = !!(flags & 0x800);
14052
	o.refreshAllConnections = !!(flags & 0x40000);
14053
	o.saveExternalLinkValues = !!(flags & 0x80);
14054
	o.showBorderUnselectedTables = !!(flags & 0x04);
14055
	o.showInkAnnotation = !!(flags & 0x20);
14056
	o.showObjects = ["all", "placeholders", "none"][(flags >> 13) & 0x03];
14057
	o.showPivotChartFilter = !!(flags & 0x8000);
14058
	o.updateLinks = ["userSet", "never", "always"][(flags >> 8) & 0x03];
14059
	return o;
14060
}
14061
function write_BrtWbProp(data, o) {
14062
	if(!o) o = new_buf(72);
14063
	var flags = 0;
14064
	if(data) {
14065
		/* TODO: mirror parse_BrtWbProp fields */
14066
		if(data.filterPrivacy) flags |= 0x08;
14067
	}
14068
	o.write_shift(4, flags);
14069
	o.write_shift(4, 0);
14070
	write_XLSBCodeName(data && data.CodeName || "ThisWorkbook", o);
14071
	return o.slice(0, o.l);
14072
}
14073
14074
function parse_BrtFRTArchID$(data, length) {
14075
	var o = {};
14076
	data.read_shift(4);
14077
	o.ArchID = data.read_shift(4);
14078
	data.l += length - 8;
14079
	return o;
14080
}
14081
14082
/* [MS-XLSB] 2.4.687 BrtName */
14083
function parse_BrtName(data, length, opts) {
14084
	var end = data.l + length;
14085
	data.l += 4; //var flags = data.read_shift(4);
14086
	data.l += 1; //var chKey = data.read_shift(1);
14087
	var itab = data.read_shift(4);
14088
	var name = parse_XLNameWideString(data);
14089
	var formula = parse_XLSBNameParsedFormula(data, 0, opts);
14090
	var comment = parse_XLNullableWideString(data);
14091
	//if(0 /* fProc */) {
14092
		// unusedstring1: XLNullableWideString
14093
		// description: XLNullableWideString
14094
		// helpTopic: XLNullableWideString
14095
		// unusedstring2: XLNullableWideString
14096
	//}
14097
	data.l = end;
14098
	var out = ({Name:name, Ptg:formula});
14099
	if(itab < 0xFFFFFFF) out.Sheet = itab;
14100
	if(comment) out.Comment = comment;
14101
	return out;
14102
}
14103
14104
/* [MS-XLSB] 2.1.7.61 Workbook */
14105
function parse_wb_bin(data, opts) {
14106
	var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
14107
	var pass = false;
14108
14109
	if(!opts) opts = {};
14110
	opts.biff = 12;
14111
14112
	var Names = [];
14113
	var supbooks = ([[]]);
14114
	supbooks.SheetNames = [];
14115
	supbooks.XTI = [];
14116
14117
	recordhopper(data, function hopper_wb(val, R_n, RT) {
14118
		switch(RT) {
14119
			case 0x009C: /* 'BrtBundleSh' */
14120
				supbooks.SheetNames.push(val.name);
14121
				wb.Sheets.push(val); break;
14122
14123
			case 0x0099: /* 'BrtWbProp' */
14124
				wb.WBProps = val; break;
14125
14126
			case 0x0027: /* 'BrtName' */
14127
				if(val.Sheet != null) opts.SID = val.Sheet;
14128
				val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts);
14129
				delete opts.SID;
14130
				delete val.Ptg;
14131
				Names.push(val);
14132
				break;
14133
			case 0x040C: /* 'BrtNameExt' */ break;
14134
14135
			case 0x0165: /* 'BrtSupSelf' */
14136
			case 0x0166: /* 'BrtSupSame' */
14137
			case 0x0163: /* 'BrtSupBookSrc' */
14138
			case 0x029B: /* 'BrtSupAddin' */
14139
				if(!supbooks[0].length) supbooks[0] = [RT, val];
14140
				else supbooks.push([RT, val]);
14141
				supbooks[supbooks.length - 1].XTI = [];
14142
				break;
14143
			case 0x016A: /* 'BrtExternSheet' */
14144
				if(supbooks.length === 0) { supbooks[0] = []; supbooks[0].XTI = []; }
14145
				supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val);
14146
				supbooks.XTI = supbooks.XTI.concat(val);
14147
				break;
14148
			case 0x0169: /* 'BrtPlaceholderName' */
14149
				break;
14150
14151
			/* case 'BrtModelTimeGroupingCalcCol' */
14152
			case 0x0C00: /* 'BrtUid' */
14153
			case 0x0C01: /* 'BrtRevisionPtr' */
14154
			case 0x0817: /* 'BrtAbsPath15' */
14155
			case 0x0216: /* 'BrtBookProtection' */
14156
			case 0x02A5: /* 'BrtBookProtectionIso' */
14157
			case 0x009E: /* 'BrtBookView' */
14158
			case 0x009D: /* 'BrtCalcProp' */
14159
			case 0x0262: /* 'BrtCrashRecErr' */
14160
			case 0x0802: /* 'BrtDecoupledPivotCacheID' */
14161
			case 0x009B: /* 'BrtFileRecover' */
14162
			case 0x0224: /* 'BrtFileSharing' */
14163
			case 0x02A4: /* 'BrtFileSharingIso' */
14164
			case 0x0080: /* 'BrtFileVersion' */
14165
			case 0x0299: /* 'BrtFnGroup' */
14166
			case 0x0850: /* 'BrtModelRelationship' */
14167
			case 0x084D: /* 'BrtModelTable' */
14168
			case 0x0225: /* 'BrtOleSize' */
14169
			case 0x0805: /* 'BrtPivotTableRef' */
14170
			case 0x0254: /* 'BrtSmartTagType' */
14171
			case 0x081C: /* 'BrtTableSlicerCacheID' */
14172
			case 0x081B: /* 'BrtTableSlicerCacheIDs' */
14173
			case 0x0822: /* 'BrtTimelineCachePivotCacheID' */
14174
			case 0x018D: /* 'BrtUserBookView' */
14175
			case 0x009A: /* 'BrtWbFactoid' */
14176
			case 0x045D: /* 'BrtWbProp14' */
14177
			case 0x0229: /* 'BrtWebOpt' */
14178
			case 0x082B: /* 'BrtWorkBookPr15' */
14179
				break;
14180
14181
			case 0x0023: /* 'BrtFRTBegin' */
14182
				pass = true; break;
14183
			case 0x0024: /* 'BrtFRTEnd' */
14184
				pass = false; break;
14185
			case 0x0025: /* 'BrtACBegin' */ break;
14186
			case 0x0026: /* 'BrtACEnd' */ break;
14187
14188
			case 0x0010: /* 'BrtFRTArchID$' */ break;
14189
14190
			default:
14191
				if((R_n||"").indexOf("Begin") > 0){/* empty */}
14192
				else if((R_n||"").indexOf("End") > 0){/* empty */}
14193
				else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14194
		}
14195
	}, opts);
14196
14197
	parse_wb_defaults(wb);
14198
14199
	// $FlowIgnore
14200
	wb.Names = Names;
14201
14202
	(wb).supbooks = supbooks;
14203
	return wb;
14204
}
14205
14206
function write_BUNDLESHS(ba, wb) {
14207
	write_record(ba, "BrtBeginBundleShs");
14208
	for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
14209
		var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
14210
		var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
14211
		write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
14212
	}
14213
	write_record(ba, "BrtEndBundleShs");
14214
}
14215
14216
/* [MS-XLSB] 2.4.649 BrtFileVersion */
14217
function write_BrtFileVersion(data, o) {
14218
	if(!o) o = new_buf(127);
14219
	for(var i = 0; i != 4; ++i) o.write_shift(4, 0);
14220
	write_XLWideString("SheetJS", o);
14221
	write_XLWideString(XLSX.version, o);
14222
	write_XLWideString(XLSX.version, o);
14223
	write_XLWideString("7262", o);
14224
	o.length = o.l;
14225
	return o.length > o.l ? o.slice(0, o.l) : o;
14226
}
14227
14228
/* [MS-XLSB] 2.4.301 BrtBookView */
14229
function write_BrtBookView(idx, o) {
14230
	if(!o) o = new_buf(29);
14231
	o.write_shift(-4, 0);
14232
	o.write_shift(-4, 460);
14233
	o.write_shift(4,  28800);
14234
	o.write_shift(4,  17600);
14235
	o.write_shift(4,  500);
14236
	o.write_shift(4,  idx);
14237
	o.write_shift(4,  idx);
14238
	var flags = 0x78;
14239
	o.write_shift(1,  flags);
14240
	return o.length > o.l ? o.slice(0, o.l) : o;
14241
}
14242
14243
function write_BOOKVIEWS(ba, wb) {
14244
	/* required if hidden tab appears before visible tab */
14245
	if(!wb.Workbook || !wb.Workbook.Sheets) return;
14246
	var sheets = wb.Workbook.Sheets;
14247
	var i = 0, vistab = -1, hidden = -1;
14248
	for(; i < sheets.length; ++i) {
14249
		if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
14250
		else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
14251
	}
14252
	if(hidden > vistab) return;
14253
	write_record(ba, "BrtBeginBookViews");
14254
	write_record(ba, "BrtBookView", write_BrtBookView(vistab));
14255
	/* 1*(BrtBookView *FRT) */
14256
	write_record(ba, "BrtEndBookViews");
14257
}
14258
14259
/* [MS-XLSB] 2.4.305 BrtCalcProp */
14260
/*function write_BrtCalcProp(data, o) {
14261
	if(!o) o = new_buf(26);
14262
	o.write_shift(4,0); // force recalc
14263
	o.write_shift(4,1);
14264
	o.write_shift(4,0);
14265
	write_Xnum(0, o);
14266
	o.write_shift(-4, 1023);
14267
	o.write_shift(1, 0x33);
14268
	o.write_shift(1, 0x00);
14269
	return o;
14270
}*/
14271
14272
/* [MS-XLSB] 2.4.646 BrtFileRecover */
14273
/*function write_BrtFileRecover(data, o) {
14274
	if(!o) o = new_buf(1);
14275
	o.write_shift(1,0);
14276
	return o;
14277
}*/
14278
14279
/* [MS-XLSB] 2.1.7.61 Workbook */
14280
function write_wb_bin(wb, opts) {
14281
	var ba = buf_array();
14282
	write_record(ba, "BrtBeginBook");
14283
	write_record(ba, "BrtFileVersion", write_BrtFileVersion());
14284
	/* [[BrtFileSharingIso] BrtFileSharing] */
14285
	write_record(ba, "BrtWbProp", write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null));
14286
	/* [ACABSPATH] */
14287
	/* [[BrtBookProtectionIso] BrtBookProtection] */
14288
	write_BOOKVIEWS(ba, wb, opts);
14289
	write_BUNDLESHS(ba, wb, opts);
14290
	/* [FNGROUP] */
14291
	/* [EXTERNALS] */
14292
	/* *BrtName */
14293
	/* write_record(ba, "BrtCalcProp", write_BrtCalcProp()); */
14294
	/* [BrtOleSize] */
14295
	/* *(BrtUserBookView *FRT) */
14296
	/* [PIVOTCACHEIDS] */
14297
	/* [BrtWbFactoid] */
14298
	/* [SMARTTAGTYPES] */
14299
	/* [BrtWebOpt] */
14300
	/* write_record(ba, "BrtFileRecover", write_BrtFileRecover()); */
14301
	/* [WEBPUBITEMS] */
14302
	/* [CRERRS] */
14303
	/* FRTWORKBOOK */
14304
	write_record(ba, "BrtEndBook");
14305
14306
	return ba.end();
14307
}
14308
function parse_wb(data, name, opts) {
14309
	if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
14310
	return parse_wb_xml((data), opts);
14311
}
14312
14313
function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
14314
	if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
14315
	return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
14316
}
14317
14318
function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
14319
	if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
14320
	return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
14321
}
14322
14323
function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
14324
	if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
14325
	return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
14326
}
14327
14328
function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
14329
	if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
14330
	return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
14331
}
14332
14333
function parse_sty(data, name, themes, opts) {
14334
	if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
14335
	return parse_sty_xml((data), themes, opts);
14336
}
14337
14338
function parse_theme(data, name, opts) {
14339
	return parse_theme_xml(data, opts);
14340
}
14341
14342
function parse_sst(data, name, opts) {
14343
	if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
14344
	return parse_sst_xml((data), opts);
14345
}
14346
14347
function parse_cmnt(data, name, opts) {
14348
	if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
14349
	return parse_comments_xml((data), opts);
14350
}
14351
14352
function parse_cc(data, name, opts) {
14353
	if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
14354
	return parse_cc_xml((data), name, opts);
14355
}
14356
14357
function parse_xlink(data, name, opts) {
14358
	if(name.slice(-4)===".bin") return parse_xlink_bin((data), name, opts);
14359
	return parse_xlink_xml((data), name, opts);
14360
}
14361
14362
function write_wb(wb, name, opts) {
14363
	return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
14364
}
14365
14366
function write_ws(data, name, opts, wb, rels) {
14367
	return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
14368
}
14369
14370
// eslint-disable-next-line no-unused-vars
14371
function write_cs(data, name, opts, wb, rels) {
14372
	return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
14373
}
14374
14375
function write_sty(data, name, opts) {
14376
	return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
14377
}
14378
14379
function write_sst(data, name, opts) {
14380
	return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
14381
}
14382
14383
function write_cmnt(data, name, opts) {
14384
	return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
14385
}
14386
/*
14387
function write_cc(data, name:string, opts) {
14388
	return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
14389
}
14390
*/
14391
var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
14392
var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
14393
var _chr = function(c) { return String.fromCharCode(c); };
14394
function xlml_parsexmltag(tag, skip_root) {
14395
	var words = tag.split(/\s+/);
14396
	var z = ([]); if(!skip_root) z[0] = words[0];
14397
	if(words.length === 1) return z;
14398
	var m = tag.match(attregexg2), y, j, w, i;
14399
	if(m) for(i = 0; i != m.length; ++i) {
14400
		y = m[i].match(attregex2);
14401
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
14402
		else {
14403
			if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
14404
			else w = y[1].slice(j+1);
14405
			z[w] = y[2].slice(1,y[2].length-1);
14406
		}
14407
	}
14408
	return z;
14409
}
14410
function xlml_parsexmltagobj(tag) {
14411
	var words = tag.split(/\s+/);
14412
	var z = {};
14413
	if(words.length === 1) return z;
14414
	var m = tag.match(attregexg2), y, j, w, i;
14415
	if(m) for(i = 0; i != m.length; ++i) {
14416
		y = m[i].match(attregex2);
14417
if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
14418
		else {
14419
			if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
14420
			else w = y[1].slice(j+1);
14421
			z[w] = y[2].slice(1,y[2].length-1);
14422
		}
14423
	}
14424
	return z;
14425
}
14426
14427
// ----
14428
14429
function xlml_format(format, value) {
14430
	var fmt = XLMLFormatMap[format] || unescapexml(format);
14431
	if(fmt === "General") return SSF._general(value);
14432
	return SSF.format(fmt, value);
14433
}
14434
14435
function xlml_set_custprop(Custprops, key, cp, val) {
14436
	var oval = val;
14437
	switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) {
14438
		case "boolean": oval = parsexmlbool(val); break;
14439
		case "i2": case "int": oval = parseInt(val, 10); break;
14440
		case "r4": case "float": oval = parseFloat(val); break;
14441
		case "date": case "dateTime.tz": oval = parseDate(val); break;
14442
		case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break;
14443
		default: throw new Error("bad custprop:" + cp[0]);
14444
	}
14445
	Custprops[unescapexml(key)] = oval;
14446
}
14447
14448
function safe_format_xlml(cell, nf, o) {
14449
	if(cell.t === 'z') return;
14450
	if(!o || o.cellText !== false) try {
14451
		if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
14452
		else if(nf === "General") {
14453
			if(cell.t === 'n') {
14454
				if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v);
14455
				else cell.w = SSF._general_num(cell.v);
14456
			}
14457
			else cell.w = SSF._general(cell.v);
14458
		}
14459
		else cell.w = xlml_format(nf||"General", cell.v);
14460
	} catch(e) { if(o.WTF) throw e; }
14461
	try {
14462
		var z = XLMLFormatMap[nf]||nf||"General";
14463
		if(o.cellNF) cell.z = z;
14464
		if(o.cellDates && cell.t == 'n' && SSF.is_date(z)) {
14465
			var _d = SSF.parse_date_code(cell.v); if(_d) { cell.t = 'd'; cell.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
14466
		}
14467
	} catch(e) { if(o.WTF) throw e; }
14468
}
14469
14470
function process_style_xlml(styles, stag, opts) {
14471
	if(opts.cellStyles) {
14472
		if(stag.Interior) {
14473
			var I = stag.Interior;
14474
			if(I.Pattern) I.patternType = XLMLPatternTypeMap[I.Pattern] || I.Pattern;
14475
		}
14476
	}
14477
	styles[stag.ID] = stag;
14478
}
14479
14480
/* TODO: there must exist some form of OSP-blessed spec */
14481
function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o) {
14482
	var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
14483
	var interiors = [];
14484
	var i = 0;
14485
	if(sid === undefined && row) sid = row.StyleID;
14486
	if(sid === undefined && csty) sid = csty.StyleID;
14487
	while(styles[sid] !== undefined) {
14488
		if(styles[sid].nf) nf = styles[sid].nf;
14489
		if(styles[sid].Interior) interiors.push(styles[sid].Interior);
14490
		if(!styles[sid].Parent) break;
14491
		sid = styles[sid].Parent;
14492
	}
14493
	switch(data.Type) {
14494
		case 'Boolean':
14495
			cell.t = 'b';
14496
			cell.v = parsexmlbool(xml);
14497
			break;
14498
		case 'String':
14499
			cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
14500
			cell.v = xml.indexOf("<") > -1 ? unescapexml(ss) : cell.r;
14501
			break;
14502
		case 'DateTime':
14503
			if(xml.slice(-1) != "Z") xml += "Z";
14504
			cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
14505
			if(cell.v !== cell.v) cell.v = unescapexml(xml);
14506
			else if(cell.v<60) cell.v = cell.v -1;
14507
			if(!nf || nf == "General") nf = "yyyy-mm-dd";
14508
			/* falls through */
14509
		case 'Number':
14510
			if(cell.v === undefined) cell.v=+xml;
14511
			if(!cell.t) cell.t = 'n';
14512
			break;
14513
		case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
14514
		default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
14515
	}
14516
	safe_format_xlml(cell, nf, o);
14517
	if(o.cellFormula !== false) {
14518
		if(cell.Formula) {
14519
			var fstr = unescapexml(cell.Formula);
14520
			/* strictly speaking, the leading = is required but some writers omit */
14521
			if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.slice(1);
14522
			cell.f = rc_to_a1(fstr, base);
14523
			delete cell.Formula;
14524
			if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base);
14525
			else if(cell.ArrayRange) {
14526
				cell.F = rc_to_a1(cell.ArrayRange, base);
14527
				arrayf.push([safe_decode_range(cell.F), cell.F]);
14528
			}
14529
		} else {
14530
			for(i = 0; i < arrayf.length; ++i)
14531
				if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r)
14532
					if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c)
14533
						cell.F = arrayf[i][1];
14534
		}
14535
	}
14536
	if(o.cellStyles) {
14537
		interiors.forEach(function(x) {
14538
			if(!S.patternType && x.patternType) S.patternType = x.patternType;
14539
		});
14540
		cell.s = S;
14541
	}
14542
	if(cell.StyleID !== undefined) cell.ixfe = cell.StyleID;
14543
}
14544
14545
function xlml_clean_comment(comment) {
14546
	comment.t = comment.v || "";
14547
	comment.t = comment.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
14548
	comment.v = comment.w = comment.ixfe = undefined;
14549
}
14550
14551
function xlml_normalize(d) {
14552
	if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
14553
	if(typeof d === 'string') return d;
14554
	/* duktape */
14555
	if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d)));
14556
	throw new Error("Bad input format: expected Buffer or string");
14557
}
14558
14559
/* TODO: Everything */
14560
/* UOS uses CJK in tags */
14561
var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>:\/]+)[^>]*>/mg;
14562
//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
14563
function parse_xlml_xml(d, _opts) {
14564
	var opts = _opts || {};
14565
	make_ssf(SSF);
14566
	var str = debom(xlml_normalize(d));
14567
	if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') {
14568
		if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
14569
		else str = utf8read(str);
14570
	}
14571
	var opening = str.slice(0, 1024).toLowerCase(), ishtml = false;
14572
	if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; });
14573
	if(ishtml) return HTML_.to_workbook(str, opts);
14574
	var Rn;
14575
	var state = [], tmp;
14576
	if(DENSE != null && opts.dense == null) opts.dense = DENSE;
14577
	var sheets = {}, sheetnames = [], cursheet = (opts.dense ? [] : {}), sheetname = "";
14578
	var table = {}, cell = ({}), row = {};// eslint-disable-line no-unused-vars
14579
	var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
14580
	var c = 0, r = 0;
14581
	var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14582
	var styles = {}, stag = {};
14583
	var ss = "", fidx = 0;
14584
	var merges = [];
14585
	var Props = {}, Custprops = {}, pidx = 0, cp = [];
14586
	var comments = [], comment = ({});
14587
	var cstys = [], csty, seencol = false;
14588
	var arrayf = [];
14589
	var rowinfo = [], rowobj = {}, cc = 0, rr = 0;
14590
	var Workbook = ({ Sheets:[], WBProps:{date1904:false} }), wsprops = {};
14591
	xlmlregex.lastIndex = 0;
14592
	str = str.replace(/<!--([\s\S]*?)-->/mg,"");
14593
	while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
14594
		case 'Data':
14595
			if(state[state.length-1][1]) break;
14596
			if(Rn[1]==='/') parse_xlml_data(str.slice(didx, Rn.index), ss, dtag, state[state.length-1][0]=="Comment"?comment:cell, {c:c,r:r}, styles, cstys[c], row, arrayf, opts);
14597
			else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
14598
			break;
14599
		case 'Cell':
14600
			if(Rn[1]==='/'){
14601
				if(comments.length > 0) cell.c = comments;
14602
				if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) {
14603
					if(opts.dense) {
14604
						if(!cursheet[r]) cursheet[r] = [];
14605
						cursheet[r][c] = cell;
14606
					} else cursheet[encode_col(c) + encode_row(r)] = cell;
14607
				}
14608
				if(cell.HRef) {
14609
					cell.l = ({Target:cell.HRef});
14610
					if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
14611
					delete cell.HRef; delete cell.HRefScreenTip;
14612
				}
14613
				if(cell.MergeAcross || cell.MergeDown) {
14614
					cc = c + (parseInt(cell.MergeAcross,10)|0);
14615
					rr = r + (parseInt(cell.MergeDown,10)|0);
14616
					merges.push({s:{c:c,r:r},e:{c:cc,r:rr}});
14617
				}
14618
				if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
14619
				else if(cell.MergeAcross || cell.MergeDown) {
14620
for(var cma = c; cma <= cc; ++cma) {
14621
						for(var cmd = r; cmd <= rr; ++cmd) {
14622
							if(cma > c || cmd > r) {
14623
								if(opts.dense) {
14624
									if(!cursheet[cmd]) cursheet[cmd] = [];
14625
									cursheet[cmd][cma] = {t:'z'};
14626
								} else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
14627
							}
14628
						}
14629
					}
14630
					c = cc + 1;
14631
				}
14632
				else ++c;
14633
			} else {
14634
				cell = xlml_parsexmltagobj(Rn[0]);
14635
				if(cell.Index) c = +cell.Index - 1;
14636
				if(c < refguess.s.c) refguess.s.c = c;
14637
				if(c > refguess.e.c) refguess.e.c = c;
14638
				if(Rn[0].slice(-2) === "/>") ++c;
14639
				comments = [];
14640
			}
14641
			break;
14642
		case 'Row':
14643
			if(Rn[1]==='/' || Rn[0].slice(-2) === "/>") {
14644
				if(r < refguess.s.r) refguess.s.r = r;
14645
				if(r > refguess.e.r) refguess.e.r = r;
14646
				if(Rn[0].slice(-2) === "/>") {
14647
					row = xlml_parsexmltag(Rn[0]);
14648
					if(row.Index) r = +row.Index - 1;
14649
				}
14650
				c = 0; ++r;
14651
			} else {
14652
				row = xlml_parsexmltag(Rn[0]);
14653
				if(row.Index) r = +row.Index - 1;
14654
				rowobj = {};
14655
				if(row.AutoFitHeight == "0" || row.Height) {
14656
					rowobj.hpx = parseInt(row.Height, 10); rowobj.hpt = px2pt(rowobj.hpx);
14657
					rowinfo[r] = rowobj;
14658
				}
14659
				if(row.Hidden == "1") { rowobj.hidden = true; rowinfo[r] = rowobj; }
14660
			}
14661
			break;
14662
		case 'Worksheet': /* TODO: read range from FullRows/FullColumns */
14663
			if(Rn[1]==='/'){
14664
				if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
14665
				sheetnames.push(sheetname);
14666
				if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) {
14667
					cursheet["!ref"] = encode_range(refguess);
14668
					if(opts.sheetRows && opts.sheetRows <= refguess.e.r) {
14669
						cursheet["!fullref"] = cursheet["!ref"];
14670
						refguess.e.r = opts.sheetRows - 1;
14671
						cursheet["!ref"] = encode_range(refguess);
14672
					}
14673
				}
14674
				if(merges.length) cursheet["!merges"] = merges;
14675
				if(cstys.length > 0) cursheet["!cols"] = cstys;
14676
				if(rowinfo.length > 0) cursheet["!rows"] = rowinfo;
14677
				sheets[sheetname] = cursheet;
14678
			} else {
14679
				refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14680
				r = c = 0;
14681
				state.push([Rn[3], false]);
14682
				tmp = xlml_parsexmltag(Rn[0]);
14683
				sheetname = unescapexml(tmp.Name);
14684
				cursheet = (opts.dense ? [] : {});
14685
				merges = [];
14686
				arrayf = [];
14687
				rowinfo = [];
14688
				wsprops = {name:sheetname, Hidden:0};
14689
				Workbook.Sheets.push(wsprops);
14690
			}
14691
			break;
14692
		case 'Table':
14693
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14694
			else if(Rn[0].slice(-2) == "/>") break;
14695
			else {
14696
				table = xlml_parsexmltag(Rn[0]);
14697
				state.push([Rn[3], false]);
14698
				cstys = []; seencol = false;
14699
			}
14700
			break;
14701
14702
		case 'Style':
14703
			if(Rn[1]==='/') process_style_xlml(styles, stag, opts);
14704
			else stag = xlml_parsexmltag(Rn[0]);
14705
			break;
14706
14707
		case 'NumberFormat':
14708
			stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
14709
			if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
14710
			for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
14711
			if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
14712
			break;
14713
14714
		case 'Column':
14715
			if(state[state.length-1][0] !== 'Table') break;
14716
			csty = xlml_parsexmltag(Rn[0]);
14717
			if(csty.Hidden) { csty.hidden = true; delete csty.Hidden; }
14718
			if(csty.Width) csty.wpx = parseInt(csty.Width, 10);
14719
			if(!seencol && csty.wpx > 10) {
14720
				seencol = true; MDW = DEF_MDW; //find_mdw_wpx(csty.wpx);
14721
				for(var _col = 0; _col < cstys.length; ++_col) if(cstys[_col]) process_col(cstys[_col]);
14722
			}
14723
			if(seencol) process_col(csty);
14724
			cstys[(csty.Index-1||cstys.length)] = csty;
14725
			for(var i = 0; i < +csty.Span; ++i) cstys[cstys.length] = dup(csty);
14726
			break;
14727
14728
		case 'NamedRange':
14729
			if(!Workbook.Names) Workbook.Names = [];
14730
			var _NamedRange = parsexmltag(Rn[0]);
14731
			var _DefinedName = ({
14732
				Name: _NamedRange.Name,
14733
				Ref: rc_to_a1(_NamedRange.RefersTo.slice(1), {r:0, c:0})
14734
			});
14735
			if(Workbook.Sheets.length>0) _DefinedName.Sheet=Workbook.Sheets.length-1;
14736
Workbook.Names.push(_DefinedName);
14737
			break;
14738
14739
		case 'NamedCell': break;
14740
		case 'B': break;
14741
		case 'I': break;
14742
		case 'U': break;
14743
		case 'S': break;
14744
		case 'Sub': break;
14745
		case 'Sup': break;
14746
		case 'Span': break;
14747
		case 'Border': break;
14748
		case 'Alignment': break;
14749
		case 'Borders': break;
14750
		case 'Font':
14751
			if(Rn[0].slice(-2) === "/>") break;
14752
			else if(Rn[1]==="/") ss += str.slice(fidx, Rn.index);
14753
			else fidx = Rn.index + Rn[0].length;
14754
			break;
14755
		case 'Interior':
14756
			if(!opts.cellStyles) break;
14757
			stag.Interior = xlml_parsexmltag(Rn[0]);
14758
			break;
14759
		case 'Protection': break;
14760
14761
		case 'Author':
14762
		case 'Title':
14763
		case 'Description':
14764
		case 'Created':
14765
		case 'Keywords':
14766
		case 'Subject':
14767
		case 'Category':
14768
		case 'Company':
14769
		case 'LastAuthor':
14770
		case 'LastSaved':
14771
		case 'LastPrinted':
14772
		case 'Version':
14773
		case 'Revision':
14774
		case 'TotalTime':
14775
		case 'HyperlinkBase':
14776
		case 'Manager':
14777
		case 'ContentStatus':
14778
		case 'Identifier':
14779
		case 'Language':
14780
		case 'AppName':
14781
			if(Rn[0].slice(-2) === "/>") break;
14782
			else if(Rn[1]==="/") xlml_set_prop(Props, Rn[3], str.slice(pidx, Rn.index));
14783
			else pidx = Rn.index + Rn[0].length;
14784
			break;
14785
		case 'Paragraphs': break;
14786
14787
		case 'Styles':
14788
		case 'Workbook':
14789
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14790
			else state.push([Rn[3], false]);
14791
			break;
14792
14793
		case 'Comment':
14794
			if(Rn[1]==='/'){
14795
				if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
14796
				xlml_clean_comment(comment);
14797
				comments.push(comment);
14798
			} else {
14799
				state.push([Rn[3], false]);
14800
				tmp = xlml_parsexmltag(Rn[0]);
14801
				comment = ({a:tmp.Author});
14802
			}
14803
			break;
14804
14805
		case 'AutoFilter':
14806
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14807
			else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
14808
				var AutoFilter = xlml_parsexmltag(Rn[0]);
14809
				cursheet['!autofilter'] = { ref:rc_to_a1(AutoFilter.Range).replace(/\$/g,"") };
14810
				state.push([Rn[3], true]);
14811
			}
14812
			break;
14813
14814
		case 'Name': break;
14815
14816
		case 'ComponentOptions':
14817
		case 'DocumentProperties':
14818
		case 'CustomDocumentProperties':
14819
		case 'OfficeDocumentSettings':
14820
		case 'PivotTable':
14821
		case 'PivotCache':
14822
		case 'Names':
14823
		case 'MapInfo':
14824
		case 'PageBreaks':
14825
		case 'QueryTable':
14826
		case 'DataValidation':
14827
		case 'Sorting':
14828
		case 'Schema':
14829
		case 'data':
14830
		case 'ConditionalFormatting':
14831
		case 'SmartTagType':
14832
		case 'SmartTags':
14833
		case 'ExcelWorkbook':
14834
		case 'WorkbookOptions':
14835
		case 'WorksheetOptions':
14836
			if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
14837
			else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
14838
			break;
14839
14840
		default:
14841
			/* FODS file root is <office:document> */
14842
			if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts);
14843
			/* UOS file root is <uof:UOF> */
14844
			if(state.length == 0 && Rn[3] == "UOF") return parse_fods(str, opts);
14845
14846
			var seen = true;
14847
			switch(state[state.length-1][0]) {
14848
				/* OfficeDocumentSettings */
14849
				case 'OfficeDocumentSettings': switch(Rn[3]) {
14850
					case 'AllowPNG': break;
14851
					case 'RemovePersonalInformation': break;
14852
					case 'DownloadComponents': break;
14853
					case 'LocationOfComponents': break;
14854
					case 'Colors': break;
14855
					case 'Color': break;
14856
					case 'Index': break;
14857
					case 'RGB': break;
14858
					case 'PixelsPerInch': break; // TODO: set PPI
14859
					case 'TargetScreenSize': break;
14860
					case 'ReadOnlyRecommended': break;
14861
					default: seen = false;
14862
				} break;
14863
14864
				/* ComponentOptions */
14865
				case 'ComponentOptions': switch(Rn[3]) {
14866
					case 'Toolbar': break;
14867
					case 'HideOfficeLogo': break;
14868
					case 'SpreadsheetAutoFit': break;
14869
					case 'Label': break;
14870
					case 'Caption': break;
14871
					case 'MaxHeight': break;
14872
					case 'MaxWidth': break;
14873
					case 'NextSheetNumber': break;
14874
					default: seen = false;
14875
				} break;
14876
14877
				/* ExcelWorkbook */
14878
				case 'ExcelWorkbook': switch(Rn[3]) {
14879
					case 'Date1904':
14880
Workbook.WBProps.date1904 = true;
14881
						break;
14882
					case 'WindowHeight': break;
14883
					case 'WindowWidth': break;
14884
					case 'WindowTopX': break;
14885
					case 'WindowTopY': break;
14886
					case 'TabRatio': break;
14887
					case 'ProtectStructure': break;
14888
					case 'ProtectWindows': break;
14889
					case 'ActiveSheet': break;
14890
					case 'DisplayInkNotes': break;
14891
					case 'FirstVisibleSheet': break;
14892
					case 'SupBook': break;
14893
					case 'SheetName': break;
14894
					case 'SheetIndex': break;
14895
					case 'SheetIndexFirst': break;
14896
					case 'SheetIndexLast': break;
14897
					case 'Dll': break;
14898
					case 'AcceptLabelsInFormulas': break;
14899
					case 'DoNotSaveLinkValues': break;
14900
					case 'Iteration': break;
14901
					case 'MaxIterations': break;
14902
					case 'MaxChange': break;
14903
					case 'Path': break;
14904
					case 'Xct': break;
14905
					case 'Count': break;
14906
					case 'SelectedSheets': break;
14907
					case 'Calculation': break;
14908
					case 'Uncalced': break;
14909
					case 'StartupPrompt': break;
14910
					case 'Crn': break;
14911
					case 'ExternName': break;
14912
					case 'Formula': break;
14913
					case 'ColFirst': break;
14914
					case 'ColLast': break;
14915
					case 'WantAdvise': break;
14916
					case 'Boolean': break;
14917
					case 'Error': break;
14918
					case 'Text': break;
14919
					case 'OLE': break;
14920
					case 'NoAutoRecover': break;
14921
					case 'PublishObjects': break;
14922
					case 'DoNotCalculateBeforeSave': break;
14923
					case 'Number': break;
14924
					case 'RefModeR1C1': break;
14925
					case 'EmbedSaveSmartTags': break;
14926
					default: seen = false;
14927
				} break;
14928
14929
				/* WorkbookOptions */
14930
				case 'WorkbookOptions': switch(Rn[3]) {
14931
					case 'OWCVersion': break;
14932
					case 'Height': break;
14933
					case 'Width': break;
14934
					default: seen = false;
14935
				} break;
14936
14937
				/* WorksheetOptions */
14938
				case 'WorksheetOptions': switch(Rn[3]) {
14939
					case 'Visible':
14940
						if(Rn[0].slice(-2) === "/>"){/* empty */}
14941
						else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
14942
							case "SheetHidden": wsprops.Hidden = 1; break;
14943
							case "SheetVeryHidden": wsprops.Hidden = 2; break;
14944
						}
14945
						else pidx = Rn.index + Rn[0].length;
14946
						break;
14947
					case 'Header':
14948
						if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
14949
						cursheet['!margins'].header = parsexmltag(Rn[0]).Margin;
14950
						break;
14951
					case 'Footer':
14952
						if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
14953
						cursheet['!margins'].footer = parsexmltag(Rn[0]).Margin;
14954
						break;
14955
					case 'PageMargins':
14956
						var pagemargins = parsexmltag(Rn[0]);
14957
						if(!cursheet['!margins']) default_margins(cursheet['!margins']={},'xlml');
14958
						if(pagemargins.Top) cursheet['!margins'].top = pagemargins.Top;
14959
						if(pagemargins.Left) cursheet['!margins'].left = pagemargins.Left;
14960
						if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right;
14961
						if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom;
14962
						break;
14963
					case 'DisplayRightToLeft':
14964
						if(!Workbook.Views) Workbook.Views = [];
14965
						if(!Workbook.Views[0]) Workbook.Views[0] = {};
14966
						Workbook.Views[0].RTL = true;
14967
						break;
14968
14969
					case 'Unsynced': break;
14970
					case 'Print': break;
14971
					case 'Panes': break;
14972
					case 'Scale': break;
14973
					case 'Pane': break;
14974
					case 'Number': break;
14975
					case 'Layout': break;
14976
					case 'PageSetup': break;
14977
					case 'Selected': break;
14978
					case 'ProtectObjects': break;
14979
					case 'EnableSelection': break;
14980
					case 'ProtectScenarios': break;
14981
					case 'ValidPrinterInfo': break;
14982
					case 'HorizontalResolution': break;
14983
					case 'VerticalResolution': break;
14984
					case 'NumberofCopies': break;
14985
					case 'ActiveRow': break;
14986
					case 'ActiveCol': break;
14987
					case 'ActivePane': break;
14988
					case 'TopRowVisible': break;
14989
					case 'TopRowBottomPane': break;
14990
					case 'LeftColumnVisible': break;
14991
					case 'LeftColumnRightPane': break;
14992
					case 'FitToPage': break;
14993
					case 'RangeSelection': break;
14994
					case 'PaperSizeIndex': break;
14995
					case 'PageLayoutZoom': break;
14996
					case 'PageBreakZoom': break;
14997
					case 'FilterOn': break;
14998
					case 'DoNotDisplayGridlines': break;
14999
					case 'SplitHorizontal': break;
15000
					case 'SplitVertical': break;
15001
					case 'FreezePanes': break;
15002
					case 'FrozenNoSplit': break;
15003
					case 'FitWidth': break;
15004
					case 'FitHeight': break;
15005
					case 'CommentsLayout': break;
15006
					case 'Zoom': break;
15007
					case 'LeftToRight': break;
15008
					case 'Gridlines': break;
15009
					case 'AllowSort': break;
15010
					case 'AllowFilter': break;
15011
					case 'AllowInsertRows': break;
15012
					case 'AllowDeleteRows': break;
15013
					case 'AllowInsertCols': break;
15014
					case 'AllowDeleteCols': break;
15015
					case 'AllowInsertHyperlinks': break;
15016
					case 'AllowFormatCells': break;
15017
					case 'AllowSizeCols': break;
15018
					case 'AllowSizeRows': break;
15019
					case 'NoSummaryRowsBelowDetail': break;
15020
					case 'TabColorIndex': break;
15021
					case 'DoNotDisplayHeadings': break;
15022
					case 'ShowPageLayoutZoom': break;
15023
					case 'NoSummaryColumnsRightDetail': break;
15024
					case 'BlackAndWhite': break;
15025
					case 'DoNotDisplayZeros': break;
15026
					case 'DisplayPageBreak': break;
15027
					case 'RowColHeadings': break;
15028
					case 'DoNotDisplayOutline': break;
15029
					case 'NoOrientation': break;
15030
					case 'AllowUsePivotTables': break;
15031
					case 'ZeroHeight': break;
15032
					case 'ViewableRange': break;
15033
					case 'Selection': break;
15034
					case 'ProtectContents': break;
15035
					default: seen = false;
15036
				} break;
15037
15038
				/* PivotTable */
15039
				case 'PivotTable': case 'PivotCache': switch(Rn[3]) {
15040
					case 'ImmediateItemsOnDrop': break;
15041
					case 'ShowPageMultipleItemLabel': break;
15042
					case 'CompactRowIndent': break;
15043
					case 'Location': break;
15044
					case 'PivotField': break;
15045
					case 'Orientation': break;
15046
					case 'LayoutForm': break;
15047
					case 'LayoutSubtotalLocation': break;
15048
					case 'LayoutCompactRow': break;
15049
					case 'Position': break;
15050
					case 'PivotItem': break;
15051
					case 'DataType': break;
15052
					case 'DataField': break;
15053
					case 'SourceName': break;
15054
					case 'ParentField': break;
15055
					case 'PTLineItems': break;
15056
					case 'PTLineItem': break;
15057
					case 'CountOfSameItems': break;
15058
					case 'Item': break;
15059
					case 'ItemType': break;
15060
					case 'PTSource': break;
15061
					case 'CacheIndex': break;
15062
					case 'ConsolidationReference': break;
15063
					case 'FileName': break;
15064
					case 'Reference': break;
15065
					case 'NoColumnGrand': break;
15066
					case 'NoRowGrand': break;
15067
					case 'BlankLineAfterItems': break;
15068
					case 'Hidden': break;
15069
					case 'Subtotal': break;
15070
					case 'BaseField': break;
15071
					case 'MapChildItems': break;
15072
					case 'Function': break;
15073
					case 'RefreshOnFileOpen': break;
15074
					case 'PrintSetTitles': break;
15075
					case 'MergeLabels': break;
15076
					case 'DefaultVersion': break;
15077
					case 'RefreshName': break;
15078
					case 'RefreshDate': break;
15079
					case 'RefreshDateCopy': break;
15080
					case 'VersionLastRefresh': break;
15081
					case 'VersionLastUpdate': break;
15082
					case 'VersionUpdateableMin': break;
15083
					case 'VersionRefreshableMin': break;
15084
					case 'Calculation': break;
15085
					default: seen = false;
15086
				} break;
15087
15088
				/* PageBreaks */
15089
				case 'PageBreaks': switch(Rn[3]) {
15090
					case 'ColBreaks': break;
15091
					case 'ColBreak': break;
15092
					case 'RowBreaks': break;
15093
					case 'RowBreak': break;
15094
					case 'ColStart': break;
15095
					case 'ColEnd': break;
15096
					case 'RowEnd': break;
15097
					default: seen = false;
15098
				} break;
15099
15100
				/* AutoFilter */
15101
				case 'AutoFilter': switch(Rn[3]) {
15102
					case 'AutoFilterColumn': break;
15103
					case 'AutoFilterCondition': break;
15104
					case 'AutoFilterAnd': break;
15105
					case 'AutoFilterOr': break;
15106
					default: seen = false;
15107
				} break;
15108
15109
				/* QueryTable */
15110
				case 'QueryTable': switch(Rn[3]) {
15111
					case 'Id': break;
15112
					case 'AutoFormatFont': break;
15113
					case 'AutoFormatPattern': break;
15114
					case 'QuerySource': break;
15115
					case 'QueryType': break;
15116
					case 'EnableRedirections': break;
15117
					case 'RefreshedInXl9': break;
15118
					case 'URLString': break;
15119
					case 'HTMLTables': break;
15120
					case 'Connection': break;
15121
					case 'CommandText': break;
15122
					case 'RefreshInfo': break;
15123
					case 'NoTitles': break;
15124
					case 'NextId': break;
15125
					case 'ColumnInfo': break;
15126
					case 'OverwriteCells': break;
15127
					case 'DoNotPromptForFile': break;
15128
					case 'TextWizardSettings': break;
15129
					case 'Source': break;
15130
					case 'Number': break;
15131
					case 'Decimal': break;
15132
					case 'ThousandSeparator': break;
15133
					case 'TrailingMinusNumbers': break;
15134
					case 'FormatSettings': break;
15135
					case 'FieldType': break;
15136
					case 'Delimiters': break;
15137
					case 'Tab': break;
15138
					case 'Comma': break;
15139
					case 'AutoFormatName': break;
15140
					case 'VersionLastEdit': break;
15141
					case 'VersionLastRefresh': break;
15142
					default: seen = false;
15143
				} break;
15144
15145
				case 'Sorting':
15146
				case 'ConditionalFormatting':
15147
				case 'DataValidation':
15148
				switch(Rn[3]) {
15149
					case 'Range': break;
15150
					case 'Type': break;
15151
					case 'Min': break;
15152
					case 'Max': break;
15153
					case 'Sort': break;
15154
					case 'Descending': break;
15155
					case 'Order': break;
15156
					case 'CaseSensitive': break;
15157
					case 'Value': break;
15158
					case 'ErrorStyle': break;
15159
					case 'ErrorMessage': break;
15160
					case 'ErrorTitle': break;
15161
					case 'CellRangeList': break;
15162
					case 'InputMessage': break;
15163
					case 'InputTitle': break;
15164
					case 'ComboHide': break;
15165
					case 'InputHide': break;
15166
					case 'Condition': break;
15167
					case 'Qualifier': break;
15168
					case 'UseBlank': break;
15169
					case 'Value1': break;
15170
					case 'Value2': break;
15171
					case 'Format': break;
15172
					default: seen = false;
15173
				} break;
15174
15175
				/* MapInfo (schema) */
15176
				case 'MapInfo': case 'Schema': case 'data': switch(Rn[3]) {
15177
					case 'Map': break;
15178
					case 'Entry': break;
15179
					case 'Range': break;
15180
					case 'XPath': break;
15181
					case 'Field': break;
15182
					case 'XSDType': break;
15183
					case 'FilterOn': break;
15184
					case 'Aggregate': break;
15185
					case 'ElementType': break;
15186
					case 'AttributeType': break;
15187
				/* These are from xsd (XML Schema Definition) */
15188
					case 'schema':
15189
					case 'element':
15190
					case 'complexType':
15191
					case 'datatype':
15192
					case 'all':
15193
					case 'attribute':
15194
					case 'extends': break;
15195
15196
					case 'row': break;
15197
					default: seen = false;
15198
				} break;
15199
15200
				/* SmartTags (can be anything) */
15201
				case 'SmartTags': break;
15202
15203
				default: seen = false; break;
15204
			}
15205
			if(seen) break;
15206
			/* CustomDocumentProperties */
15207
			if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
15208
			if(state[state.length-1][0]==='CustomDocumentProperties') {
15209
				if(Rn[0].slice(-2) === "/>") break;
15210
				else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn[3], cp, str.slice(pidx, Rn.index));
15211
				else { cp = Rn; pidx = Rn.index + Rn[0].length; }
15212
				break;
15213
			}
15214
			if(opts.WTF) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
15215
	}
15216
	var out = ({});
15217
	if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
15218
	out.SheetNames = sheetnames;
15219
	out.Workbook = Workbook;
15220
	out.SSF = SSF.get_table();
15221
	out.Props = Props;
15222
	out.Custprops = Custprops;
15223
	return out;
15224
}
15225
15226
function parse_xlml(data, opts) {
15227
	fix_read_opts(opts=opts||{});
15228
	switch(opts.type||"base64") {
15229
		case "base64": return parse_xlml_xml(Base64.decode(data), opts);
15230
		case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
15231
		case "array": return parse_xlml_xml(a2s(data), opts);
15232
	}
15233
}
15234
15235
/* TODO */
15236
function write_props_xlml(wb, opts) {
15237
	var o = [];
15238
	/* DocumentProperties */
15239
	if(wb.Props) o.push(xlml_write_docprops(wb.Props, opts));
15240
	/* CustomDocumentProperties */
15241
	if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops, opts));
15242
	return o.join("");
15243
}
15244
/* TODO */
15245
function write_wb_xlml() {
15246
	/* OfficeDocumentSettings */
15247
	/* ExcelWorkbook */
15248
	return "";
15249
}
15250
/* TODO */
15251
function write_sty_xlml(wb, opts) {
15252
	/* Styles */
15253
	var styles = ['<Style ss:ID="Default" ss:Name="Normal"><NumberFormat/></Style>'];
15254
	opts.cellXfs.forEach(function(xf, id) {
15255
		var payload = [];
15256
		payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])}));
15257
		styles.push(writextag('Style', payload.join(""), {"ss:ID": "s" + (21+id)}));
15258
	});
15259
	return writextag("Styles", styles.join(""));
15260
}
15261
function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); }
15262
function write_names_xlml(wb) {
15263
	if(!((wb||{}).Workbook||{}).Names) return "";
15264
var names = wb.Workbook.Names;
15265
	var out = [];
15266
	for(var i = 0; i < names.length; ++i) {
15267
		var n = names[i];
15268
		if(n.Sheet != null) continue;
15269
		if(n.Name.match(/^_xlfn\./)) continue;
15270
		out.push(write_name_xlml(n));
15271
	}
15272
	return writextag("Names", out.join(""));
15273
}
15274
function write_ws_xlml_names(ws, opts, idx, wb) {
15275
	if(!ws) return "";
15276
	if(!((wb||{}).Workbook||{}).Names) return "";
15277
var names = wb.Workbook.Names;
15278
	var out = [];
15279
	for(var i = 0; i < names.length; ++i) {
15280
		var n = names[i];
15281
		if(n.Sheet != idx) continue;
15282
		/*switch(n.Name) {
15283
			case "_": continue;
15284
		}*/
15285
		if(n.Name.match(/^_xlfn\./)) continue;
15286
		out.push(write_name_xlml(n));
15287
	}
15288
	return out.join("");
15289
}
15290
/* WorksheetOptions */
15291
function write_ws_xlml_wsopts(ws, opts, idx, wb) {
15292
	if(!ws) return "";
15293
	var o = [];
15294
	/* NOTE: spec technically allows any order, but stick with implied order */
15295
15296
	/* FitToPage */
15297
	/* DoNotDisplayColHeaders */
15298
	/* DoNotDisplayRowHeaders */
15299
	/* ViewableRange */
15300
	/* Selection */
15301
	/* GridlineColor */
15302
	/* Name */
15303
	/* ExcelWorksheetType */
15304
	/* IntlMacro */
15305
	/* Unsynced */
15306
	/* Selected */
15307
	/* CodeName */
15308
15309
	if(ws['!margins']) {
15310
		o.push("<PageSetup>");
15311
		if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
15312
		if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
15313
		o.push(writextag("PageMargins", null, {
15314
			'x:Bottom': ws['!margins'].bottom || "0.75",
15315
			'x:Left': ws['!margins'].left || "0.7",
15316
			'x:Right': ws['!margins'].right || "0.7",
15317
			'x:Top': ws['!margins'].top || "0.75"
15318
		}));
15319
		o.push("</PageSetup>");
15320
	}
15321
15322
	/* PageSetup */
15323
	/* DisplayPageBreak */
15324
	/* TransitionExpressionEvaluation */
15325
	/* TransitionFormulaEntry */
15326
	/* Print */
15327
	/* Zoom */
15328
	/* PageLayoutZoom */
15329
	/* PageBreakZoom */
15330
	/* ShowPageBreakZoom */
15331
	/* DefaultRowHeight */
15332
	/* DefaultColumnWidth */
15333
	/* StandardWidth */
15334
15335
	if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
15336
		/* Visible */
15337
		if(wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
15338
		else {
15339
			/* Selected */
15340
			for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
15341
			if(i == idx) o.push("<Selected/>");
15342
		}
15343
	}
15344
15345
	/* LeftColumnVisible */
15346
15347
	if(((((wb||{}).Workbook||{}).Views||[])[0]||{}).RTL) o.push("<DisplayRightToLeft/>");
15348
15349
	/* GridlineColorIndex */
15350
	/* DisplayFormulas */
15351
	/* DoNotDisplayGridlines */
15352
	/* DoNotDisplayHeadings */
15353
	/* DoNotDisplayOutline */
15354
	/* ApplyAutomaticOutlineStyles */
15355
	/* NoSummaryRowsBelowDetail */
15356
	/* NoSummaryColumnsRightDetail */
15357
	/* DoNotDisplayZeros */
15358
	/* ActiveRow */
15359
	/* ActiveColumn */
15360
	/* FilterOn */
15361
	/* RangeSelection */
15362
	/* TopRowVisible */
15363
	/* TopRowBottomPane */
15364
	/* LeftColumnRightPane */
15365
	/* ActivePane */
15366
	/* SplitHorizontal */
15367
	/* SplitVertical */
15368
	/* FreezePanes */
15369
	/* FrozenNoSplit */
15370
	/* TabColorIndex */
15371
	/* Panes */
15372
15373
	/* NOTE: Password not supported in XLML Format */
15374
	if(ws['!protect']) {
15375
		o.push(writetag("ProtectContents", "True"));
15376
		if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
15377
		if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
15378
		if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
15379
		else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
15380
	[
15381
		[ "formatCells", "AllowFormatCells" ],
15382
		[ "formatColumns", "AllowSizeCols" ],
15383
		[ "formatRows", "AllowSizeRows" ],
15384
		[ "insertColumns", "AllowInsertCols" ],
15385
		[ "insertRows", "AllowInsertRows" ],
15386
		[ "insertHyperlinks", "AllowInsertHyperlinks" ],
15387
		[ "deleteColumns", "AllowDeleteCols" ],
15388
		[ "deleteRows", "AllowDeleteRows" ],
15389
		[ "sort", "AllowSort" ],
15390
		[ "autoFilter", "AllowFilter" ],
15391
		[ "pivotTables", "AllowUsePivotTables" ]
15392
	].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
15393
	}
15394
15395
	if(o.length == 0) return "";
15396
	return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
15397
}
15398
function write_ws_xlml_comment(comments) {
15399
	return comments.map(function(c) {
15400
		// TODO: formatted text
15401
		var t = xlml_unfixstr(c.t||"");
15402
		var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
15403
		return writextag("Comment", d, {"ss:Author":c.a});
15404
	}).join("");
15405
}
15406
function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
15407
	if(!cell || (cell.v == undefined && cell.f == undefined)) return "";
15408
15409
	var attr = {};
15410
	if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
15411
	if(cell.F && cell.F.slice(0, ref.length) == ref) {
15412
		var end = decode_cell(cell.F.slice(ref.length + 1));
15413
		attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
15414
	}
15415
15416
	if(cell.l && cell.l.Target) {
15417
		attr["ss:HRef"] = escapexml(cell.l.Target);
15418
		if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
15419
	}
15420
15421
	if(ws['!merges']) {
15422
		var marr = ws['!merges'];
15423
		for(var mi = 0; mi != marr.length; ++mi) {
15424
			if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
15425
			if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
15426
			if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
15427
		}
15428
	}
15429
15430
	var t = "", p = "";
15431
	switch(cell.t) {
15432
		case 'z': return "";
15433
		case 'n': t = 'Number'; p = String(cell.v); break;
15434
		case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
15435
		case 'e': t = 'Error'; p = BErr[cell.v]; break;
15436
		case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break;
15437
		case 's': t = 'String'; p = escapexlml(cell.v||""); break;
15438
	}
15439
	/* TODO: cell style */
15440
	var os = get_cell_style(opts.cellXfs, cell, opts);
15441
	attr["ss:StyleID"] = "s" + (21+os);
15442
	attr["ss:Index"] = addr.c + 1;
15443
	var _v = (cell.v != null ? p : "");
15444
	var m = '<Data ss:Type="' + t + '">' + _v + '</Data>';
15445
15446
	if((cell.c||[]).length > 0) m += write_ws_xlml_comment(cell.c);
15447
15448
	return writextag("Cell", m, attr);
15449
}
15450
function write_ws_xlml_row(R, row) {
15451
	var o = '<Row ss:Index="' + (R+1) + '"';
15452
	if(row) {
15453
		if(row.hpt && !row.hpx) row.hpx = pt2px(row.hpt);
15454
		if(row.hpx) o += ' ss:AutoFitHeight="0" ss:Height="' + row.hpx + '"';
15455
		if(row.hidden) o += ' ss:Hidden="1"';
15456
	}
15457
	return o + '>';
15458
}
15459
/* TODO */
15460
function write_ws_xlml_table(ws, opts, idx, wb) {
15461
	if(!ws['!ref']) return "";
15462
	var range = safe_decode_range(ws['!ref']);
15463
	var marr = ws['!merges'] || [], mi = 0;
15464
	var o = [];
15465
	if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
15466
		process_col(n);
15467
		var w = !!n.width;
15468
		var p = col_obj_w(i, n);
15469
		var k = {"ss:Index":i+1};
15470
		if(w) k['ss:Width'] = width2px(p.width);
15471
		if(n.hidden) k['ss:Hidden']="1";
15472
		o.push(writextag("Column",null,k));
15473
	});
15474
	var dense = Array.isArray(ws);
15475
	for(var R = range.s.r; R <= range.e.r; ++R) {
15476
		var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
15477
		for(var C = range.s.c; C <= range.e.c; ++C) {
15478
			var skip = false;
15479
			for(mi = 0; mi != marr.length; ++mi) {
15480
				if(marr[mi].s.c > C) continue;
15481
				if(marr[mi].s.r > R) continue;
15482
				if(marr[mi].e.c < C) continue;
15483
				if(marr[mi].e.r < R) continue;
15484
				if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
15485
				break;
15486
			}
15487
			if(skip) continue;
15488
			var addr = {r:R,c:C};
15489
			var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
15490
			row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
15491
		}
15492
		row.push("</Row>");
15493
		if(row.length > 2) o.push(row.join(""));
15494
	}
15495
	return o.join("");
15496
}
15497
function write_ws_xlml(idx, opts, wb) {
15498
	var o = [];
15499
	var s = wb.SheetNames[idx];
15500
	var ws = wb.Sheets[s];
15501
15502
	var t = ws ? write_ws_xlml_names(ws, opts, idx, wb) : "";
15503
	if(t.length > 0) o.push("<Names>" + t + "</Names>");
15504
15505
	/* Table */
15506
	t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
15507
	if(t.length > 0) o.push("<Table>" + t + "</Table>");
15508
15509
	/* WorksheetOptions */
15510
	o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
15511
15512
	return o.join("");
15513
}
15514
function write_xlml(wb, opts) {
15515
	if(!opts) opts = {};
15516
	if(!wb.SSF) wb.SSF = SSF.get_table();
15517
	if(wb.SSF) {
15518
		make_ssf(SSF); SSF.load_table(wb.SSF);
15519
		// $FlowIgnore
15520
		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
15521
		opts.ssf = wb.SSF;
15522
		opts.cellXfs = [];
15523
		get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
15524
	}
15525
	var d = [];
15526
	d.push(write_props_xlml(wb, opts));
15527
	d.push(write_wb_xlml(wb, opts));
15528
	d.push("");
15529
	d.push("");
15530
	for(var i = 0; i < wb.SheetNames.length; ++i)
15531
		d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
15532
	d[2] = write_sty_xlml(wb, opts);
15533
	d[3] = write_names_xlml(wb, opts);
15534
	return XML_HEADER + writextag("Workbook", d.join(""), {
15535
		'xmlns':      XLMLNS.ss,
15536
		'xmlns:o':    XLMLNS.o,
15537
		'xmlns:x':    XLMLNS.x,
15538
		'xmlns:ss':   XLMLNS.ss,
15539
		'xmlns:dt':   XLMLNS.dt,
15540
		'xmlns:html': XLMLNS.html
15541
	});
15542
}
15543
/* [MS-OLEDS] 2.3.8 CompObjStream */
15544
function parse_compobj(obj) {
15545
	var v = {};
15546
	var o = obj.content;
15547
/* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
15548
	o.l = 28;
15549
15550
	v.AnsiUserType = o.read_shift(0, "lpstr-ansi");
15551
	v.AnsiClipboardFormat = parse_ClipboardFormatOrAnsiString(o);
15552
15553
	if(o.length - o.l <= 4) return v;
15554
15555
	var m = o.read_shift(4);
15556
	if(m == 0 || m > 40) return v;
15557
	o.l-=4; v.Reserved1 = o.read_shift(0, "lpstr-ansi");
15558
15559
	if(o.length - o.l <= 4) return v;
15560
	m = o.read_shift(4);
15561
	if(m !== 0x71b239f4) return v;
15562
	v.UnicodeClipboardFormat = parse_ClipboardFormatOrUnicodeString(o);
15563
15564
	m = o.read_shift(4);
15565
	if(m == 0 || m > 40) return v;
15566
	o.l-=4; v.Reserved2 = o.read_shift(0, "lpwstr");
15567
}
15568
15569
/*
15570
	Continue logic for:
15571
	- 2.4.58 Continue
15572
	- 2.4.59 ContinueBigName
15573
	- 2.4.60 ContinueFrt
15574
	- 2.4.61 ContinueFrt11
15575
	- 2.4.62 ContinueFrt12
15576
*/
15577
function slurp(R, blob, length, opts) {
15578
	var l = length;
15579
	var bufs = [];
15580
	var d = blob.slice(blob.l,blob.l+l);
15581
	if(opts && opts.enc && opts.enc.insitu) switch(R.n) {
15582
	case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': break;
15583
	default:
15584
		if(d.length === 0) break;
15585
		opts.enc.insitu(d);
15586
	}
15587
	bufs.push(d);
15588
	blob.l += l;
15589
	var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]);
15590
	var start = 0;
15591
	while(next != null && next.n.slice(0,8) === 'Continue') {
15592
		l = __readUInt16LE(blob,blob.l+2);
15593
		start = blob.l + 4;
15594
		if(next.n == 'ContinueFrt') start += 4;
15595
		else if(next.n.slice(0,11) == 'ContinueFrt') start += 12;
15596
		bufs.push(blob.slice(start,blob.l+4+l));
15597
		blob.l += 4+l;
15598
		next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]);
15599
	}
15600
	var b = (bconcat(bufs));
15601
	prep_blob(b, 0);
15602
	var ll = 0; b.lens = [];
15603
	for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; }
15604
	return R.f(b, b.length, opts);
15605
}
15606
15607
function safe_format_xf(p, opts, date1904) {
15608
	if(p.t === 'z') return;
15609
	if(!p.XF) return;
15610
	var fmtid = 0;
15611
	try {
15612
		fmtid = p.z || p.XF.numFmtId || 0;
15613
		if(opts.cellNF) p.z = SSF._table[fmtid];
15614
	} catch(e) { if(opts.WTF) throw e; }
15615
	if(!opts || opts.cellText !== false) try {
15616
		if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
15617
		else if(fmtid === 0 || fmtid == "General") {
15618
			if(p.t === 'n') {
15619
				if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
15620
				else p.w = SSF._general_num(p.v);
15621
			}
15622
			else p.w = SSF._general(p.v);
15623
		}
15624
		else p.w = SSF.format(fmtid,p.v, {date1904:!!date1904});
15625
	} catch(e) { if(opts.WTF) throw e; }
15626
	if(opts.cellDates && fmtid && p.t == 'n' && SSF.is_date(SSF._table[fmtid] || String(fmtid))) {
15627
		var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); }
15628
	}
15629
}
15630
15631
function make_cell(val, ixfe, t) {
15632
	return ({v:val, ixfe:ixfe, t:t});
15633
}
15634
15635
// 2.3.2
15636
function parse_workbook(blob, options) {
15637
	var wb = ({opts:{}});
15638
	var Sheets = {};
15639
	if(DENSE != null && options.dense == null) options.dense = DENSE;
15640
	var out = ((options.dense ? [] : {}));
15641
	var Directory = {};
15642
	var range = ({});
15643
	var last_formula = null;
15644
	var sst = ([]);
15645
	var cur_sheet = "";
15646
	var Preamble = {};
15647
	var lastcell, last_cell = "", cc, cmnt, rngC, rngR;
15648
	var sharedf = {};
15649
	var arrayf = [];
15650
	var temp_val;
15651
	var country;
15652
	var cell_valid = true;
15653
	var XFs = []; /* XF records */
15654
	var palette = [];
15655
	var Workbook = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }), wsprops = {};
15656
	var get_rgb = function getrgb(icv) {
15657
		if(icv < 8) return XLSIcv[icv];
15658
		if(icv < 64) return palette[icv-8] || XLSIcv[icv];
15659
		return XLSIcv[icv];
15660
	};
15661
	var process_cell_style = function pcs(cell, line, options) {
15662
		var xfd = line.XF.data;
15663
		if(!xfd || !xfd.patternType || !options || !options.cellStyles) return;
15664
		line.s = ({});
15665
		line.s.patternType = xfd.patternType;
15666
		var t;
15667
		if((t = rgb2Hex(get_rgb(xfd.icvFore)))) { line.s.fgColor = {rgb:t}; }
15668
		if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
15669
	};
15670
	var addcell = function addcell(cell, line, options) {
15671
		if(file_depth > 1) return;
15672
		if(options.sheetRows && cell.r >= options.sheetRows) cell_valid = false;
15673
		if(!cell_valid) return;
15674
		if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options);
15675
		delete line.ixfe; delete line.XF;
15676
		lastcell = cell;
15677
		last_cell = encode_cell(cell);
15678
		if(range.s) {
15679
			if(cell.r < range.s.r) range.s.r = cell.r;
15680
			if(cell.c < range.s.c) range.s.c = cell.c;
15681
		}
15682
		if(range.e) {
15683
			if(cell.r + 1 > range.e.r) range.e.r = cell.r + 1;
15684
			if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1;
15685
		}
15686
		if(options.cellFormula && line.f) {
15687
			for(var afi = 0; afi < arrayf.length; ++afi) {
15688
				if(arrayf[afi][0].s.c > cell.c || arrayf[afi][0].s.r > cell.r) continue;
15689
				if(arrayf[afi][0].e.c < cell.c || arrayf[afi][0].e.r < cell.r) continue;
15690
				line.F = encode_range(arrayf[afi][0]);
15691
				if(arrayf[afi][0].s.c != cell.c || arrayf[afi][0].s.r != cell.r) delete line.f;
15692
				if(line.f) line.f = "" + stringify_formula(arrayf[afi][1], range, cell, supbooks, opts);
15693
				break;
15694
			}
15695
		}
15696
		{
15697
			if(options.dense) {
15698
				if(!out[cell.r]) out[cell.r] = [];
15699
				out[cell.r][cell.c] = line;
15700
			} else out[last_cell] = line;
15701
		}
15702
	};
15703
	var opts = ({
15704
		enc: false, // encrypted
15705
		sbcch: 0, // cch in the preceding SupBook
15706
		snames: [], // sheetnames
15707
		sharedf: sharedf, // shared formulae by address
15708
		arrayf: arrayf, // array formulae array
15709
		rrtabid: [], // RRTabId
15710
		lastuser: "", // Last User from WriteAccess
15711
		biff: 8, // BIFF version
15712
		codepage: 0, // CP from CodePage record
15713
		winlocked: 0, // fLockWn from WinProtect
15714
		cellStyles: !!options && !!options.cellStyles,
15715
		WTF: !!options && !!options.wtf
15716
	});
15717
	if(options.password) opts.password = options.password;
15718
	var themes;
15719
	var merges = [];
15720
	var objects = [];
15721
	var colinfo = [], rowinfo = [];
15722
	// eslint-disable-next-line no-unused-vars
15723
	var defwidth = 0, defheight = 0; // twips / MDW respectively
15724
	var seencol = false;
15725
	var supbooks = ([]); // 1-indexed, will hold extern names
15726
	supbooks.SheetNames = opts.snames;
15727
	supbooks.sharedf = opts.sharedf;
15728
	supbooks.arrayf = opts.arrayf;
15729
	supbooks.names = [];
15730
	supbooks.XTI = [];
15731
	var last_Rn = '';
15732
	var file_depth = 0; /* TODO: make a real stack */
15733
	var BIFF2Fmt = 0, BIFF2FmtTable = [];
15734
	var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
15735
	var last_lbl;
15736
15737
	/* explicit override for some broken writers */
15738
	opts.codepage = 1200;
15739
	set_cp(1200);
15740
	var seen_codepage = false;
15741
	while(blob.l < blob.length - 1) {
15742
		var s = blob.l;
15743
		var RecordType = blob.read_shift(2);
15744
		if(RecordType === 0 && last_Rn === 'EOF') break;
15745
		var length = (blob.l === blob.length ? 0 : blob.read_shift(2));
15746
		var R = XLSRecordEnum[RecordType];
15747
		//console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length);
15748
		//if(!R) console.log(blob.slice(blob.l, blob.l + length));
15749
		if(R && R.f) {
15750
			if(options.bookSheets) {
15751
				if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
15752
			}
15753
			last_Rn = R.n;
15754
			if(R.r === 2 || R.r == 12) {
15755
				var rt = blob.read_shift(2); length -= 2;
15756
				if(!opts.enc && rt !== RecordType && (((rt&0xFF)<<8)|(rt>>8)) !== RecordType) throw new Error("rt mismatch: " + rt + "!=" + RecordType);
15757
				if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
15758
			}
15759
			//console.error(R,blob.l,length,blob.length);
15760
			var val;
15761
			if(R.n === 'EOF') val = R.f(blob, length, opts);
15762
			else val = slurp(R, blob, length, opts);
15763
			var Rn = R.n;
15764
			if(file_depth == 0 && Rn != 'BOF') continue;
15765
			/* nested switch statements to workaround V8 128 limit */
15766
			switch(Rn) {
15767
				/* Workbook Options */
15768
				case 'Date1904':
15769
wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break;
15770
				case 'WriteProtect': wb.opts.WriteProtect = true; break;
15771
				case 'FilePass':
15772
					if(!opts.enc) blob.l = 0;
15773
					opts.enc = val;
15774
					if(!options.password) throw new Error("File is password-protected");
15775
					if(val.valid == null) throw new Error("Encryption scheme unsupported");
15776
					if(!val.valid) throw new Error("Password is incorrect");
15777
					break;
15778
				case 'WriteAccess': opts.lastuser = val; break;
15779
				case 'FileSharing': break; //TODO
15780
				case 'CodePage':
15781
					/* overrides based on test cases */
15782
					switch(val) {
15783
						case 0x5212: val =  1200; break;
15784
						case 0x8000: val = 10000; break;
15785
						case 0x8001: val =  1252; break;
15786
					}
15787
					set_cp(opts.codepage = val);
15788
					seen_codepage = true;
15789
					break;
15790
				case 'RRTabId': opts.rrtabid = val; break;
15791
				case 'WinProtect': opts.winlocked = val; break;
15792
				case 'Template': break; // TODO
15793
				case 'BookBool': break; // TODO
15794
				case 'UsesELFs': break;
15795
				case 'MTRSettings': break;
15796
				case 'RefreshAll':
15797
				case 'CalcCount':
15798
				case 'CalcDelta':
15799
				case 'CalcIter':
15800
				case 'CalcMode':
15801
				case 'CalcPrecision':
15802
				case 'CalcSaveRecalc':
15803
					wb.opts[Rn] = val; break;
15804
				case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
15805
				case 'Uncalced': break;
15806
				case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
15807
				case 'WsBool':
15808
					if(val.fDialog) out["!type"] = "dialog";
15809
					break; // TODO
15810
				case 'XF': XFs.push(val); break;
15811
				case 'ExtSST': break; // TODO
15812
				case 'BookExt': break; // TODO
15813
				case 'RichTextStream': break;
15814
				case 'BkHim': break;
15815
15816
				case 'SupBook':
15817
					supbooks.push([val]);
15818
					supbooks[supbooks.length-1].XTI = [];
15819
					break;
15820
				case 'ExternName':
15821
					supbooks[supbooks.length-1].push(val);
15822
					break;
15823
				case 'Index': break; // TODO
15824
				case 'Lbl':
15825
					last_lbl = ({
15826
						Name: val.Name,
15827
						Ref: stringify_formula(val.rgce,range,null,supbooks,opts)
15828
					});
15829
					if(val.itab > 0) last_lbl.Sheet = val.itab - 1;
15830
					supbooks.names.push(last_lbl);
15831
					if(!supbooks[0]) { supbooks[0] = []; supbooks[0].XTI = []; }
15832
					supbooks[supbooks.length-1].push(val);
15833
					if(val.Name == "_xlnm._FilterDatabase" && val.itab > 0)
15834
						if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d')
15835
							FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) };
15836
					break;
15837
				case 'ExternCount': opts.ExternCount = val; break;
15838
				case 'ExternSheet':
15839
					if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; }
15840
					supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break;
15841
				case 'NameCmt':
15842
					/* TODO: search for correct name */
15843
					if(opts.biff < 8) break;
15844
					if(last_lbl != null) last_lbl.Comment = val[1];
15845
					break;
15846
15847
				case 'Protect': out["!protect"] = val; break; /* for sheet or book */
15848
				case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
15849
				case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/
15850
15851
				case 'BoundSheet8': {
15852
					Directory[val.pos] = val;
15853
					opts.snames.push(val.name);
15854
				} break;
15855
				case 'EOF': {
15856
					if(--file_depth) break;
15857
					if(range.e) {
15858
						if(range.e.r > 0 && range.e.c > 0) {
15859
							range.e.r--; range.e.c--;
15860
							out["!ref"] = encode_range(range);
15861
							if(options.sheetRows && options.sheetRows <= range.e.r) {
15862
								var tmpri = range.e.r;
15863
								range.e.r = options.sheetRows - 1;
15864
								out["!fullref"] = out["!ref"];
15865
								out["!ref"] = encode_range(range);
15866
								range.e.r = tmpri;
15867
							}
15868
							range.e.r++; range.e.c++;
15869
						}
15870
						if(merges.length > 0) out["!merges"] = merges;
15871
						if(objects.length > 0) out["!objects"] = objects;
15872
						if(colinfo.length > 0) out["!cols"] = colinfo;
15873
						if(rowinfo.length > 0) out["!rows"] = rowinfo;
15874
						Workbook.Sheets.push(wsprops);
15875
					}
15876
					if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
15877
					out = ((options.dense ? [] : {}));
15878
				} break;
15879
				case 'BOF': {
15880
					if(opts.biff === 8) opts.biff = {
15881
0x0009:2,
15882
0x0209:3,
15883
0x0409:4
15884
					}[RecordType] || {
15885
0x0200:2,
15886
0x0300:3,
15887
0x0400:4,
15888
0x0500:5,
15889
0x0600:8,
15890
0x0002:2,
15891
0x0007:2
15892
					}[val.BIFFVer] || 8;
15893
					if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
15894
					if(file_depth++) break;
15895
					cell_valid = true;
15896
					out = ((options.dense ? [] : {}));
15897
15898
					if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
15899
					if(opts.biff < 5) {
15900
						if(cur_sheet === "") cur_sheet = "Sheet1";
15901
						range = {s:{r:0,c:0},e:{r:0,c:0}};
15902
						/* fake BoundSheet8 */
15903
						var fakebs8 = {pos: blob.l - length, name:cur_sheet};
15904
						Directory[fakebs8.pos] = fakebs8;
15905
						opts.snames.push(cur_sheet);
15906
					}
15907
					else cur_sheet = (Directory[s] || {name:""}).name;
15908
					if(val.dt == 0x20) out["!type"] = "chart";
15909
					if(val.dt == 0x40) out["!type"] = "macro";
15910
					merges = [];
15911
					objects = [];
15912
					opts.arrayf = arrayf = [];
15913
					colinfo = []; rowinfo = [];
15914
					defwidth = defheight = 0;
15915
					seencol = false;
15916
					wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
15917
				} break;
15918
15919
				case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
15920
					if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
15921
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'});
15922
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
15923
					safe_format_xf(temp_val, options, wb.opts.Date1904);
15924
					addcell({c:val.c, r:val.r}, temp_val, options);
15925
				} break;
15926
				case 'BoolErr': {
15927
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t});
15928
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
15929
					safe_format_xf(temp_val, options, wb.opts.Date1904);
15930
					addcell({c:val.c, r:val.r}, temp_val, options);
15931
				} break;
15932
				case 'RK': {
15933
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'});
15934
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
15935
					safe_format_xf(temp_val, options, wb.opts.Date1904);
15936
					addcell({c:val.c, r:val.r}, temp_val, options);
15937
				} break;
15938
				case 'MulRk': {
15939
					for(var j = val.c; j <= val.C; ++j) {
15940
						var ixfe = val.rkrec[j-val.c][0];
15941
						temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'});
15942
						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
15943
						safe_format_xf(temp_val, options, wb.opts.Date1904);
15944
						addcell({c:j, r:val.r}, temp_val, options);
15945
					}
15946
				} break;
15947
				case 'Formula': {
15948
					if(val.val == 'String') { last_formula = val; break; }
15949
					temp_val = make_cell(val.val, val.cell.ixfe, val.tt);
15950
					temp_val.XF = XFs[temp_val.ixfe];
15951
					if(options.cellFormula) {
15952
						var _f = val.formula;
15953
						if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
15954
							var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
15955
							var _fe = encode_cell({r:_fr, c:_fc});
15956
							if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
15957
							else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
15958
						} else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
15959
					}
15960
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
15961
					safe_format_xf(temp_val, options, wb.opts.Date1904);
15962
					addcell(val.cell, temp_val, options);
15963
					last_formula = val;
15964
				} break;
15965
				case 'String': {
15966
					if(last_formula) { /* technically always true */
15967
						last_formula.val = val;
15968
						temp_val = make_cell(val, last_formula.cell.ixfe, 's');
15969
						temp_val.XF = XFs[temp_val.ixfe];
15970
						if(options.cellFormula) {
15971
							temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
15972
						}
15973
						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
15974
						safe_format_xf(temp_val, options, wb.opts.Date1904);
15975
						addcell(last_formula.cell, temp_val, options);
15976
						last_formula = null;
15977
					} else throw new Error("String record expects Formula");
15978
				} break;
15979
				case 'Array': {
15980
					arrayf.push(val);
15981
					var _arraystart = encode_cell(val[0].s);
15982
					cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
15983
					if(options.cellFormula && cc) {
15984
						if(!last_formula) break; /* technically unreachable */
15985
						if(!_arraystart || !cc) break;
15986
						cc.f = ""+stringify_formula(val[1], range, val[0], supbooks, opts);
15987
						cc.F = encode_range(val[0]);
15988
					}
15989
				} break;
15990
				case 'ShrFmla': {
15991
					if(!cell_valid) break;
15992
					if(!options.cellFormula) break;
15993
					if(last_cell) {
15994
						/* TODO: capture range */
15995
						if(!last_formula) break; /* technically unreachable */
15996
						sharedf[encode_cell(last_formula.cell)]= val[0];
15997
						cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
15998
						(cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
15999
					}
16000
				} break;
16001
				case 'LabelSst':
16002
					temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
16003
					temp_val.XF = XFs[temp_val.ixfe];
16004
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16005
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16006
					addcell({c:val.c, r:val.r}, temp_val, options);
16007
					break;
16008
				case 'Blank': if(options.sheetStubs) {
16009
					temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'});
16010
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16011
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16012
					addcell({c:val.c, r:val.r}, temp_val, options);
16013
				} break;
16014
				case 'MulBlank': if(options.sheetStubs) {
16015
					for(var _j = val.c; _j <= val.C; ++_j) {
16016
						var _ixfe = val.ixfe[_j-val.c];
16017
						temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'});
16018
						if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16019
						safe_format_xf(temp_val, options, wb.opts.Date1904);
16020
						addcell({c:_j, r:val.r}, temp_val, options);
16021
					}
16022
				} break;
16023
				case 'RString':
16024
				case 'Label': case 'BIFF2STR':
16025
					temp_val=make_cell(val.val, val.ixfe, 's');
16026
					temp_val.XF = XFs[temp_val.ixfe];
16027
					if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16028
					safe_format_xf(temp_val, options, wb.opts.Date1904);
16029
					addcell({c:val.c, r:val.r}, temp_val, options);
16030
					break;
16031
16032
				case 'Dimensions': {
16033
					if(file_depth === 1) range = val; /* TODO: stack */
16034
				} break;
16035
				case 'SST': {
16036
					sst = val;
16037
				} break;
16038
				case 'Format': { /* val = [id, fmt] */
16039
					if(opts.biff == 4) {
16040
						BIFF2FmtTable[BIFF2Fmt++] = val[1];
16041
						for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(SSF._table[b4idx] == val[1]) break;
16042
						if(b4idx >= 163) SSF.load(val[1], BIFF2Fmt + 163);
16043
					}
16044
					else SSF.load(val[1], val[0]);
16045
				} break;
16046
				case 'BIFF2FORMAT': {
16047
					BIFF2FmtTable[BIFF2Fmt++] = val;
16048
					for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break;
16049
					if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163);
16050
				} break;
16051
16052
				case 'MergeCells': merges = merges.concat(val); break;
16053
16054
				case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break;
16055
				case 'TxO': opts.lastobj.TxO = val; break;
16056
				case 'ImData': opts.lastobj.ImData = val; break;
16057
16058
				case 'HLink': {
16059
					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
16060
						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
16061
							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
16062
							if(cc) cc.l = val[1];
16063
						}
16064
				} break;
16065
				case 'HLinkTooltip': {
16066
					for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
16067
						for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
16068
							cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
16069
							if(cc && cc.l) cc.l.Tooltip = val[1];
16070
							}
16071
				} break;
16072
16073
				/* Comments */
16074
				case 'Note': {
16075
					if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
16076
					cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
16077
					var noteobj = objects[val[2]];
16078
					if(!cc) break;
16079
					if(!cc.c) cc.c = [];
16080
					cmnt = {a:val[1],t:noteobj.TxO.t};
16081
					cc.c.push(cmnt);
16082
				} break;
16083
16084
				default: switch(R.n) { /* nested */
16085
				case 'ClrtClient': break;
16086
				case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break;
16087
16088
				case 'DefColWidth': defwidth = val; break;
16089
				case 'DefaultRowHeight': defheight = val[1]; break; // TODO: flags
16090
16091
				case 'ColInfo': {
16092
					if(!opts.cellStyles) break;
16093
					while(val.e >= val.s) {
16094
						colinfo[val.e--] = { width: val.w/256 };
16095
						if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
16096
						process_col(colinfo[val.e+1]);
16097
					}
16098
				} break;
16099
				case 'Row': {
16100
					var rowobj = {};
16101
					if(val.level != null) { rowinfo[val.r] = rowobj; rowobj.level = val.level; }
16102
					if(val.hidden) { rowinfo[val.r] = rowobj; rowobj.hidden = true; }
16103
					if(val.hpt) {
16104
						rowinfo[val.r] = rowobj;
16105
						rowobj.hpt = val.hpt; rowobj.hpx = pt2px(val.hpt);
16106
					}
16107
				} break;
16108
16109
				case 'LeftMargin':
16110
				case 'RightMargin':
16111
				case 'TopMargin':
16112
				case 'BottomMargin':
16113
					if(!out['!margins']) default_margins(out['!margins'] = {});
16114
					out['!margins'][Rn.slice(0,-6).toLowerCase()] = val;
16115
					break;
16116
16117
				case 'Setup': // TODO
16118
					if(!out['!margins']) default_margins(out['!margins'] = {});
16119
					out['!margins'].header = val.header;
16120
					out['!margins'].footer = val.footer;
16121
					break;
16122
16123
				case 'Window2': // TODO
16124
					// $FlowIgnore
16125
					if(val.RTL) Workbook.Views[0].RTL = true;
16126
					break;
16127
16128
				case 'Header': break; // TODO
16129
				case 'Footer': break; // TODO
16130
				case 'HCenter': break; // TODO
16131
				case 'VCenter': break; // TODO
16132
				case 'Pls': break; // TODO
16133
				case 'GCW': break;
16134
				case 'LHRecord': break;
16135
				case 'DBCell': break; // TODO
16136
				case 'EntExU2': break; // TODO
16137
				case 'SxView': break; // TODO
16138
				case 'Sxvd': break; // TODO
16139
				case 'SXVI': break; // TODO
16140
				case 'SXVDEx': break; // TODO
16141
				case 'SxIvd': break; // TODO
16142
				case 'SXString': break; // TODO
16143
				case 'Sync': break;
16144
				case 'Addin': break;
16145
				case 'SXDI': break; // TODO
16146
				case 'SXLI': break; // TODO
16147
				case 'SXEx': break; // TODO
16148
				case 'QsiSXTag': break; // TODO
16149
				case 'Selection': break;
16150
				case 'Feat': break;
16151
				case 'FeatHdr': case 'FeatHdr11': break;
16152
				case 'Feature11': case 'Feature12': case 'List12': break;
16153
				case 'Country': country = val; break;
16154
				case 'RecalcId': break;
16155
				case 'DxGCol': break; // TODO: htmlify
16156
				case 'Fbi': case 'Fbi2': case 'GelFrame': break;
16157
				case 'Font': break; // TODO
16158
				case 'XFCRC': break; // TODO
16159
				case 'Style': break; // TODO
16160
				case 'StyleExt': break; // TODO
16161
				case 'Palette': palette = val; break;
16162
				case 'Theme': themes = val; break;
16163
				/* Protection */
16164
				case 'ScenarioProtect': break;
16165
				case 'ObjProtect': break;
16166
16167
				/* Conditional Formatting */
16168
				case 'CondFmt12': break;
16169
16170
				/* Table */
16171
				case 'Table': break; // TODO
16172
				case 'TableStyles': break; // TODO
16173
				case 'TableStyle': break; // TODO
16174
				case 'TableStyleElement': break; // TODO
16175
16176
				/* PivotTable */
16177
				case 'SXStreamID': break; // TODO
16178
				case 'SXVS': break; // TODO
16179
				case 'DConRef': break; // TODO
16180
				case 'SXAddl': break; // TODO
16181
				case 'DConBin': break; // TODO
16182
				case 'DConName': break; // TODO
16183
				case 'SXPI': break; // TODO
16184
				case 'SxFormat': break; // TODO
16185
				case 'SxSelect': break; // TODO
16186
				case 'SxRule': break; // TODO
16187
				case 'SxFilt': break; // TODO
16188
				case 'SxItm': break; // TODO
16189
				case 'SxDXF': break; // TODO
16190
16191
				/* Scenario Manager */
16192
				case 'ScenMan': break;
16193
16194
				/* Data Consolidation */
16195
				case 'DCon': break;
16196
16197
				/* Watched Cell */
16198
				case 'CellWatch': break;
16199
16200
				/* Print Settings */
16201
				case 'PrintRowCol': break;
16202
				case 'PrintGrid': break;
16203
				case 'PrintSize': break;
16204
16205
				case 'XCT': break;
16206
				case 'CRN': break;
16207
16208
				case 'Scl': {
16209
					//console.log("Zoom Level:", val[0]/val[1],val);
16210
				} break;
16211
				case 'SheetExt': {
16212
					/* empty */
16213
				} break;
16214
				case 'SheetExtOptional': {
16215
					/* empty */
16216
				} break;
16217
16218
				/* VBA */
16219
				case 'ObNoMacros': {
16220
					/* empty */
16221
				} break;
16222
				case 'ObProj': {
16223
					/* empty */
16224
				} break;
16225
				case 'CodeName': {
16226
if(!cur_sheet) Workbook.WBProps.CodeName = val || "ThisWorkbook";
16227
					else wsprops.CodeName = val || wsprops.name;
16228
				} break;
16229
				case 'GUIDTypeLib': {
16230
					/* empty */
16231
				} break;
16232
16233
				case 'WOpt': break; // TODO: WTF?
16234
				case 'PhoneticInfo': break;
16235
16236
				case 'OleObjectSize': break;
16237
16238
				/* Differential Formatting */
16239
				case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break;
16240
16241
				/* Data Validation */
16242
				case 'Dv': case 'DVal': break;
16243
16244
				/* Data Series */
16245
				case 'BRAI': case 'Series': case 'SeriesText': break;
16246
16247
				/* Data Connection */
16248
				case 'DConn': break;
16249
				case 'DbOrParamQry': break;
16250
				case 'DBQueryExt': break;
16251
16252
				case 'OleDbConn': break;
16253
				case 'ExtString': break;
16254
16255
				/* Formatting */
16256
				case 'IFmtRecord': break;
16257
				case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
16258
16259
				/* Explicitly Ignored */
16260
				case 'Excel9File': break;
16261
				case 'Units': break;
16262
				case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break;
16263
				case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break;
16264
				/* View Stuff */
16265
				case 'Window1': case 'HideObj': case 'GridSet': case 'Guts':
16266
				case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd':
16267
				case 'Pane': break;
16268
				default: switch(R.n) { /* nested */
16269
				/* Chart */
16270
				case 'Dat':
16271
				case 'Begin': case 'End':
16272
				case 'StartBlock': case 'EndBlock':
16273
				case 'Frame': case 'Area':
16274
				case 'Axis': case 'AxisLine': case 'Tick': break;
16275
				case 'AxesUsed':
16276
				case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break;
16277
				case 'LineFormat': case 'AreaFormat':
16278
				case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break;
16279
				case 'PlotArea': case 'PlotGrowth': break;
16280
				case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break;
16281
				case 'DataFormat': case 'SerToCrt': case 'FontX': break;
16282
				case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
16283
				case 'ShtProps': break;
16284
				case 'DefaultText': case 'Text': case 'CatLab': break;
16285
				case 'DataLabExtContents': break;
16286
				case 'Legend': case 'LegendException': break;
16287
				case 'Pie': case 'Scatter': break;
16288
				case 'PieFormat': case 'MarkerFormat': break;
16289
				case 'StartObject': case 'EndObject': break;
16290
				case 'AlRuns': case 'ObjectLink': break;
16291
				case 'SIIndex': break;
16292
				case 'AttachedLabel': case 'YMult': break;
16293
16294
				/* Chart Group */
16295
				case 'Line': case 'Bar': break;
16296
				case 'Surf': break;
16297
16298
				/* Axis Group */
16299
				case 'AxisParent': break;
16300
				case 'Pos': break;
16301
				case 'ValueRange': break;
16302
16303
				/* Pivot Chart */
16304
				case 'SXViewEx9': break; // TODO
16305
				case 'SXViewLink': break;
16306
				case 'PivotChartBits': break;
16307
				case 'SBaseRef': break;
16308
				case 'TextPropsStream': break;
16309
16310
				/* Chart Misc */
16311
				case 'LnExt': break;
16312
				case 'MkrExt': break;
16313
				case 'CrtCoopt': break;
16314
16315
				/* Query Table */
16316
				case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break;
16317
				case 'TxtQry': break;
16318
16319
				/* Filter */
16320
				case 'FilterMode': break;
16321
				case 'AutoFilter': case 'AutoFilterInfo': break;
16322
				case 'AutoFilter12': break;
16323
				case 'DropDownObjIds': break;
16324
				case 'Sort': break;
16325
				case 'SortData': break;
16326
16327
				/* Drawing */
16328
				case 'ShapePropsStream': break;
16329
				case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
16330
				/* Pub Stuff */
16331
				case 'WebPub': case 'AutoWebPub': break;
16332
16333
				/* Print Stuff */
16334
				case 'HeaderFooter': case 'HFPicture': case 'PLV':
16335
				case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break;
16336
				/* Behavioral */
16337
				case 'Backup': case 'CompressPictures': case 'Compat12': break;
16338
16339
				/* Should not Happen */
16340
				case 'Continue': case 'ContinueFrt12': break;
16341
16342
				/* Future Records */
16343
				case 'FrtFontList': case 'FrtWrapper': break;
16344
16345
				default: switch(R.n) { /* nested */
16346
				/* BIFF5 records */
16347
				case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
16348
16349
				/* BIFF2-4 records */
16350
				case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break;
16351
				case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break;
16352
				case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break;
16353
16354
				/* Miscellaneous */
16355
				case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':
16356
				case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData':
16357
				case 'Name': break;
16358
				case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break;
16359
				case 'ListObj': case 'ListField': break;
16360
				case 'RRSort': break;
16361
				case 'BigName': break;
16362
				case 'ToolbarHdr': case 'ToolbarEnd': break;
16363
				case 'DDEObjName': break;
16364
				case 'FRTArchId$': break;
16365
				default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
16366
			}}}}
16367
		} else blob.l += length;
16368
	}
16369
	wb.SheetNames=keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;});
16370
	if(!options.bookSheets) wb.Sheets=Sheets;
16371
	if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; });
16372
	wb.Preamble=Preamble;
16373
	wb.Strings = sst;
16374
	wb.SSF = SSF.get_table();
16375
	if(opts.enc) wb.Encryption = opts.enc;
16376
	if(themes) wb.Themes = themes;
16377
	wb.Metadata = {};
16378
	if(country !== undefined) wb.Metadata.Country = country;
16379
	if(supbooks.names.length > 0) Workbook.Names = supbooks.names;
16380
	wb.Workbook = Workbook;
16381
	return wb;
16382
}
16383
16384
/* TODO: split props*/
16385
var PSCLSID = {
16386
	SI: "e0859ff2f94f6810ab9108002b27b3d9",
16387
	DSI: "02d5cdd59c2e1b10939708002b2cf9ae",
16388
	UDI: "05d5cdd59c2e1b10939708002b2cf9ae"
16389
};
16390
function parse_xls_props(cfb, props, o) {
16391
	/* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
16392
	var DSI = CFB.find(cfb, '!DocumentSummaryInformation');
16393
	if(DSI && DSI.size > 0) try {
16394
		var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI);
16395
		for(var d in DocSummary) props[d] = DocSummary[d];
16396
	} catch(e) {if(o.WTF) throw e;/* empty */}
16397
16398
	/* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
16399
	var SI = CFB.find(cfb, '!SummaryInformation');
16400
	if(SI && SI.size > 0) try {
16401
		var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI);
16402
		for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
16403
	} catch(e) {if(o.WTF) throw e;/* empty */}
16404
16405
	if(props.HeadingPairs && props.TitlesOfParts) {
16406
		load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o);
16407
		delete props.HeadingPairs; delete props.TitlesOfParts;
16408
	}
16409
}
16410
function write_xls_props(wb, cfb) {
16411
	var DSEntries = [], SEntries = [], CEntries = [];
16412
	var i = 0, Keys;
16413
	if(wb.Props) {
16414
		Keys = keys(wb.Props);
16415
		// $FlowIgnore
16416
		for(i = 0; i < Keys.length; ++i) (DocSummaryRE.hasOwnProperty(Keys[i]) ? DSEntries : SummaryRE.hasOwnProperty(Keys[i]) ? SEntries : CEntries).push([Keys[i], wb.Props[Keys[i]]]);
16417
	}
16418
	if(wb.Custprops) {
16419
		Keys = keys(wb.Custprops);
16420
		// $FlowIgnore
16421
		for(i = 0; i < Keys.length; ++i) if(!(wb.Props||{}).hasOwnProperty(Keys[i])) (DocSummaryRE.hasOwnProperty(Keys[i]) ? DSEntries : SummaryRE.hasOwnProperty(Keys[i]) ? SEntries : CEntries).push([Keys[i], wb.Custprops[Keys[i]]]);
16422
	}
16423
	var CEntries2 = [];
16424
	for(i = 0; i < CEntries.length; ++i) {
16425
		if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue;
16426
		if(CEntries[i][1] == null) continue;
16427
		CEntries2.push(CEntries[i]);
16428
	}
16429
	if(SEntries.length) CFB.utils.cfb_add(cfb, "/\u0005SummaryInformation", write_PropertySetStream(SEntries, PSCLSID.SI, SummaryRE, SummaryPIDSI));
16430
	if(DSEntries.length || CEntries2.length) CFB.utils.cfb_add(cfb, "/\u0005DocumentSummaryInformation", write_PropertySetStream(DSEntries, PSCLSID.DSI, DocSummaryRE, DocSummaryPIDDSI, CEntries2.length ? CEntries2 : null, PSCLSID.UDI));
16431
}
16432
16433
function parse_xlscfb(cfb, options) {
16434
if(!options) options = {};
16435
fix_read_opts(options);
16436
reset_cp();
16437
if(options.codepage) set_ansi(options.codepage);
16438
var CompObj, WB;
16439
if(cfb.FullPaths) {
16440
	if(CFB.find(cfb, '/encryption')) throw new Error("File is password-protected");
16441
	CompObj = CFB.find(cfb, '!CompObj');
16442
	WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
16443
} else {
16444
	switch(options.type) {
16445
		case 'base64': cfb = s2a(Base64.decode(cfb)); break;
16446
		case 'binary': cfb = s2a(cfb); break;
16447
		case 'buffer': break;
16448
		case 'array': if(!Array.isArray(cfb)) cfb = Array.prototype.slice.call(cfb); break;
16449
	}
16450
	prep_blob(cfb, 0);
16451
	WB = ({content: cfb});
16452
}
16453
var WorkbookP;
16454
16455
var _data;
16456
if(CompObj) parse_compobj(CompObj);
16457
if(options.bookProps && !options.bookSheets) WorkbookP = ({});
16458
else {
16459
	var T = has_buf ? 'buffer' : 'array';
16460
	if(WB && WB.content) WorkbookP = parse_workbook(WB.content, options);
16461
	/* Quattro Pro 7-8 */
16462
	else if((_data=CFB.find(cfb, 'PerfectOffice_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
16463
	/* Quattro Pro 9 */
16464
	else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
16465
	else throw new Error("Cannot find Workbook stream");
16466
	if(options.bookVBA && cfb.FullPaths && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb);
16467
}
16468
16469
var props = {};
16470
if(cfb.FullPaths) parse_xls_props(cfb, props, options);
16471
16472
WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
16473
if(options.bookFiles) WorkbookP.cfb = cfb;
16474
/*WorkbookP.CompObjP = CompObjP; // TODO: storage? */
16475
return WorkbookP;
16476
}
16477
16478
16479
function write_xlscfb(wb, opts) {
16480
	var o = opts || {};
16481
	var cfb = CFB.utils.cfb_new({root:"R"});
16482
	var wbpath = "/Workbook";
16483
	switch(o.bookType || "xls") {
16484
		case "xls": o.bookType = "biff8";
16485
		/* falls through */
16486
		case "xla": if(!o.bookType) o.bookType = "xla";
16487
		/* falls through */
16488
		case "biff8": wbpath = "/Workbook"; o.biff = 8; break;
16489
		case "biff5": wbpath = "/Book"; o.biff = 5; break;
16490
		default: throw new Error("invalid type " + o.bookType + " for XLS CFB");
16491
	}
16492
	CFB.utils.cfb_add(cfb, wbpath, write_biff_buf(wb, o));
16493
	if(o.biff == 8 && (wb.Props || wb.Custprops)) write_xls_props(wb, cfb);
16494
	// TODO: SI, DSI, CO
16495
	if(o.biff == 8 && wb.vbaraw) fill_vba_xls(cfb, CFB.read(wb.vbaraw, {type: typeof wb.vbaraw == "string" ? "binary" : "buffer"}));
16496
	return cfb;
16497
}
16498
/* [MS-XLSB] 2.3 Record Enumeration */
16499
var XLSBRecordEnum = {
16500
0x0000: { n:"BrtRowHdr", f:parse_BrtRowHdr },
16501
0x0001: { n:"BrtCellBlank", f:parse_BrtCellBlank },
16502
0x0002: { n:"BrtCellRk", f:parse_BrtCellRk },
16503
0x0003: { n:"BrtCellError", f:parse_BrtCellError },
16504
0x0004: { n:"BrtCellBool", f:parse_BrtCellBool },
16505
0x0005: { n:"BrtCellReal", f:parse_BrtCellReal },
16506
0x0006: { n:"BrtCellSt", f:parse_BrtCellSt },
16507
0x0007: { n:"BrtCellIsst", f:parse_BrtCellIsst },
16508
0x0008: { n:"BrtFmlaString", f:parse_BrtFmlaString },
16509
0x0009: { n:"BrtFmlaNum", f:parse_BrtFmlaNum },
16510
0x000A: { n:"BrtFmlaBool", f:parse_BrtFmlaBool },
16511
0x000B: { n:"BrtFmlaError", f:parse_BrtFmlaError },
16512
0x0010: { n:"BrtFRTArchID$", f:parse_BrtFRTArchID$ },
16513
0x0013: { n:"BrtSSTItem", f:parse_RichStr },
16514
0x0014: { n:"BrtPCDIMissing" },
16515
0x0015: { n:"BrtPCDINumber" },
16516
0x0016: { n:"BrtPCDIBoolean" },
16517
0x0017: { n:"BrtPCDIError" },
16518
0x0018: { n:"BrtPCDIString" },
16519
0x0019: { n:"BrtPCDIDatetime" },
16520
0x001A: { n:"BrtPCDIIndex" },
16521
0x001B: { n:"BrtPCDIAMissing" },
16522
0x001C: { n:"BrtPCDIANumber" },
16523
0x001D: { n:"BrtPCDIABoolean" },
16524
0x001E: { n:"BrtPCDIAError" },
16525
0x001F: { n:"BrtPCDIAString" },
16526
0x0020: { n:"BrtPCDIADatetime" },
16527
0x0021: { n:"BrtPCRRecord" },
16528
0x0022: { n:"BrtPCRRecordDt" },
16529
0x0023: { n:"BrtFRTBegin" },
16530
0x0024: { n:"BrtFRTEnd" },
16531
0x0025: { n:"BrtACBegin" },
16532
0x0026: { n:"BrtACEnd" },
16533
0x0027: { n:"BrtName", f:parse_BrtName },
16534
0x0028: { n:"BrtIndexRowBlock" },
16535
0x002A: { n:"BrtIndexBlock" },
16536
0x002B: { n:"BrtFont", f:parse_BrtFont },
16537
0x002C: { n:"BrtFmt", f:parse_BrtFmt },
16538
0x002D: { n:"BrtFill", f:parse_BrtFill },
16539
0x002E: { n:"BrtBorder", f:parse_BrtBorder },
16540
0x002F: { n:"BrtXF", f:parse_BrtXF },
16541
0x0030: { n:"BrtStyle" },
16542
0x0031: { n:"BrtCellMeta" },
16543
0x0032: { n:"BrtValueMeta" },
16544
0x0033: { n:"BrtMdb" },
16545
0x0034: { n:"BrtBeginFmd" },
16546
0x0035: { n:"BrtEndFmd" },
16547
0x0036: { n:"BrtBeginMdx" },
16548
0x0037: { n:"BrtEndMdx" },
16549
0x0038: { n:"BrtBeginMdxTuple" },
16550
0x0039: { n:"BrtEndMdxTuple" },
16551
0x003A: { n:"BrtMdxMbrIstr" },
16552
0x003B: { n:"BrtStr" },
16553
0x003C: { n:"BrtColInfo", f:parse_ColInfo },
16554
0x003E: { n:"BrtCellRString" },
16555
0x003F: { n:"BrtCalcChainItem$", f:parse_BrtCalcChainItem$ },
16556
0x0040: { n:"BrtDVal" },
16557
0x0041: { n:"BrtSxvcellNum" },
16558
0x0042: { n:"BrtSxvcellStr" },
16559
0x0043: { n:"BrtSxvcellBool" },
16560
0x0044: { n:"BrtSxvcellErr" },
16561
0x0045: { n:"BrtSxvcellDate" },
16562
0x0046: { n:"BrtSxvcellNil" },
16563
0x0080: { n:"BrtFileVersion" },
16564
0x0081: { n:"BrtBeginSheet" },
16565
0x0082: { n:"BrtEndSheet" },
16566
0x0083: { n:"BrtBeginBook", f:parsenoop, p:0 },
16567
0x0084: { n:"BrtEndBook" },
16568
0x0085: { n:"BrtBeginWsViews" },
16569
0x0086: { n:"BrtEndWsViews" },
16570
0x0087: { n:"BrtBeginBookViews" },
16571
0x0088: { n:"BrtEndBookViews" },
16572
0x0089: { n:"BrtBeginWsView", f:parse_BrtBeginWsView },
16573
0x008A: { n:"BrtEndWsView" },
16574
0x008B: { n:"BrtBeginCsViews" },
16575
0x008C: { n:"BrtEndCsViews" },
16576
0x008D: { n:"BrtBeginCsView" },
16577
0x008E: { n:"BrtEndCsView" },
16578
0x008F: { n:"BrtBeginBundleShs" },
16579
0x0090: { n:"BrtEndBundleShs" },
16580
0x0091: { n:"BrtBeginSheetData" },
16581
0x0092: { n:"BrtEndSheetData" },
16582
0x0093: { n:"BrtWsProp", f:parse_BrtWsProp },
16583
0x0094: { n:"BrtWsDim", f:parse_BrtWsDim, p:16 },
16584
0x0097: { n:"BrtPane" },
16585
0x0098: { n:"BrtSel" },
16586
0x0099: { n:"BrtWbProp", f:parse_BrtWbProp },
16587
0x009A: { n:"BrtWbFactoid" },
16588
0x009B: { n:"BrtFileRecover" },
16589
0x009C: { n:"BrtBundleSh", f:parse_BrtBundleSh },
16590
0x009D: { n:"BrtCalcProp" },
16591
0x009E: { n:"BrtBookView" },
16592
0x009F: { n:"BrtBeginSst", f:parse_BrtBeginSst },
16593
0x00A0: { n:"BrtEndSst" },
16594
0x00A1: { n:"BrtBeginAFilter", f:parse_UncheckedRfX },
16595
0x00A2: { n:"BrtEndAFilter" },
16596
0x00A3: { n:"BrtBeginFilterColumn" },
16597
0x00A4: { n:"BrtEndFilterColumn" },
16598
0x00A5: { n:"BrtBeginFilters" },
16599
0x00A6: { n:"BrtEndFilters" },
16600
0x00A7: { n:"BrtFilter" },
16601
0x00A8: { n:"BrtColorFilter" },
16602
0x00A9: { n:"BrtIconFilter" },
16603
0x00AA: { n:"BrtTop10Filter" },
16604
0x00AB: { n:"BrtDynamicFilter" },
16605
0x00AC: { n:"BrtBeginCustomFilters" },
16606
0x00AD: { n:"BrtEndCustomFilters" },
16607
0x00AE: { n:"BrtCustomFilter" },
16608
0x00AF: { n:"BrtAFilterDateGroupItem" },
16609
0x00B0: { n:"BrtMergeCell", f:parse_BrtMergeCell },
16610
0x00B1: { n:"BrtBeginMergeCells" },
16611
0x00B2: { n:"BrtEndMergeCells" },
16612
0x00B3: { n:"BrtBeginPivotCacheDef" },
16613
0x00B4: { n:"BrtEndPivotCacheDef" },
16614
0x00B5: { n:"BrtBeginPCDFields" },
16615
0x00B6: { n:"BrtEndPCDFields" },
16616
0x00B7: { n:"BrtBeginPCDField" },
16617
0x00B8: { n:"BrtEndPCDField" },
16618
0x00B9: { n:"BrtBeginPCDSource" },
16619
0x00BA: { n:"BrtEndPCDSource" },
16620
0x00BB: { n:"BrtBeginPCDSRange" },
16621
0x00BC: { n:"BrtEndPCDSRange" },
16622
0x00BD: { n:"BrtBeginPCDFAtbl" },
16623
0x00BE: { n:"BrtEndPCDFAtbl" },
16624
0x00BF: { n:"BrtBeginPCDIRun" },
16625
0x00C0: { n:"BrtEndPCDIRun" },
16626
0x00C1: { n:"BrtBeginPivotCacheRecords" },
16627
0x00C2: { n:"BrtEndPivotCacheRecords" },
16628
0x00C3: { n:"BrtBeginPCDHierarchies" },
16629
0x00C4: { n:"BrtEndPCDHierarchies" },
16630
0x00C5: { n:"BrtBeginPCDHierarchy" },
16631
0x00C6: { n:"BrtEndPCDHierarchy" },
16632
0x00C7: { n:"BrtBeginPCDHFieldsUsage" },
16633
0x00C8: { n:"BrtEndPCDHFieldsUsage" },
16634
0x00C9: { n:"BrtBeginExtConnection" },
16635
0x00CA: { n:"BrtEndExtConnection" },
16636
0x00CB: { n:"BrtBeginECDbProps" },
16637
0x00CC: { n:"BrtEndECDbProps" },
16638
0x00CD: { n:"BrtBeginECOlapProps" },
16639
0x00CE: { n:"BrtEndECOlapProps" },
16640
0x00CF: { n:"BrtBeginPCDSConsol" },
16641
0x00D0: { n:"BrtEndPCDSConsol" },
16642
0x00D1: { n:"BrtBeginPCDSCPages" },
16643
0x00D2: { n:"BrtEndPCDSCPages" },
16644
0x00D3: { n:"BrtBeginPCDSCPage" },
16645
0x00D4: { n:"BrtEndPCDSCPage" },
16646
0x00D5: { n:"BrtBeginPCDSCPItem" },
16647
0x00D6: { n:"BrtEndPCDSCPItem" },
16648
0x00D7: { n:"BrtBeginPCDSCSets" },
16649
0x00D8: { n:"BrtEndPCDSCSets" },
16650
0x00D9: { n:"BrtBeginPCDSCSet" },
16651
0x00DA: { n:"BrtEndPCDSCSet" },
16652
0x00DB: { n:"BrtBeginPCDFGroup" },
16653
0x00DC: { n:"BrtEndPCDFGroup" },
16654
0x00DD: { n:"BrtBeginPCDFGItems" },
16655
0x00DE: { n:"BrtEndPCDFGItems" },
16656
0x00DF: { n:"BrtBeginPCDFGRange" },
16657
0x00E0: { n:"BrtEndPCDFGRange" },
16658
0x00E1: { n:"BrtBeginPCDFGDiscrete" },
16659
0x00E2: { n:"BrtEndPCDFGDiscrete" },
16660
0x00E3: { n:"BrtBeginPCDSDTupleCache" },
16661
0x00E4: { n:"BrtEndPCDSDTupleCache" },
16662
0x00E5: { n:"BrtBeginPCDSDTCEntries" },
16663
0x00E6: { n:"BrtEndPCDSDTCEntries" },
16664
0x00E7: { n:"BrtBeginPCDSDTCEMembers" },
16665
0x00E8: { n:"BrtEndPCDSDTCEMembers" },
16666
0x00E9: { n:"BrtBeginPCDSDTCEMember" },
16667
0x00EA: { n:"BrtEndPCDSDTCEMember" },
16668
0x00EB: { n:"BrtBeginPCDSDTCQueries" },
16669
0x00EC: { n:"BrtEndPCDSDTCQueries" },
16670
0x00ED: { n:"BrtBeginPCDSDTCQuery" },
16671
0x00EE: { n:"BrtEndPCDSDTCQuery" },
16672
0x00EF: { n:"BrtBeginPCDSDTCSets" },
16673
0x00F0: { n:"BrtEndPCDSDTCSets" },
16674
0x00F1: { n:"BrtBeginPCDSDTCSet" },
16675
0x00F2: { n:"BrtEndPCDSDTCSet" },
16676
0x00F3: { n:"BrtBeginPCDCalcItems" },
16677
0x00F4: { n:"BrtEndPCDCalcItems" },
16678
0x00F5: { n:"BrtBeginPCDCalcItem" },
16679
0x00F6: { n:"BrtEndPCDCalcItem" },
16680
0x00F7: { n:"BrtBeginPRule" },
16681
0x00F8: { n:"BrtEndPRule" },
16682
0x00F9: { n:"BrtBeginPRFilters" },
16683
0x00FA: { n:"BrtEndPRFilters" },
16684
0x00FB: { n:"BrtBeginPRFilter" },
16685
0x00FC: { n:"BrtEndPRFilter" },
16686
0x00FD: { n:"BrtBeginPNames" },
16687
0x00FE: { n:"BrtEndPNames" },
16688
0x00FF: { n:"BrtBeginPName" },
16689
0x0100: { n:"BrtEndPName" },
16690
0x0101: { n:"BrtBeginPNPairs" },
16691
0x0102: { n:"BrtEndPNPairs" },
16692
0x0103: { n:"BrtBeginPNPair" },
16693
0x0104: { n:"BrtEndPNPair" },
16694
0x0105: { n:"BrtBeginECWebProps" },
16695
0x0106: { n:"BrtEndECWebProps" },
16696
0x0107: { n:"BrtBeginEcWpTables" },
16697
0x0108: { n:"BrtEndECWPTables" },
16698
0x0109: { n:"BrtBeginECParams" },
16699
0x010A: { n:"BrtEndECParams" },
16700
0x010B: { n:"BrtBeginECParam" },
16701
0x010C: { n:"BrtEndECParam" },
16702
0x010D: { n:"BrtBeginPCDKPIs" },
16703
0x010E: { n:"BrtEndPCDKPIs" },
16704
0x010F: { n:"BrtBeginPCDKPI" },
16705
0x0110: { n:"BrtEndPCDKPI" },
16706
0x0111: { n:"BrtBeginDims" },
16707
0x0112: { n:"BrtEndDims" },
16708
0x0113: { n:"BrtBeginDim" },
16709
0x0114: { n:"BrtEndDim" },
16710
0x0115: { n:"BrtIndexPartEnd" },
16711
0x0116: { n:"BrtBeginStyleSheet" },
16712
0x0117: { n:"BrtEndStyleSheet" },
16713
0x0118: { n:"BrtBeginSXView" },
16714
0x0119: { n:"BrtEndSXVI" },
16715
0x011A: { n:"BrtBeginSXVI" },
16716
0x011B: { n:"BrtBeginSXVIs" },
16717
0x011C: { n:"BrtEndSXVIs" },
16718
0x011D: { n:"BrtBeginSXVD" },
16719
0x011E: { n:"BrtEndSXVD" },
16720
0x011F: { n:"BrtBeginSXVDs" },
16721
0x0120: { n:"BrtEndSXVDs" },
16722
0x0121: { n:"BrtBeginSXPI" },
16723
0x0122: { n:"BrtEndSXPI" },
16724
0x0123: { n:"BrtBeginSXPIs" },
16725
0x0124: { n:"BrtEndSXPIs" },
16726
0x0125: { n:"BrtBeginSXDI" },
16727
0x0126: { n:"BrtEndSXDI" },
16728
0x0127: { n:"BrtBeginSXDIs" },
16729
0x0128: { n:"BrtEndSXDIs" },
16730
0x0129: { n:"BrtBeginSXLI" },
16731
0x012A: { n:"BrtEndSXLI" },
16732
0x012B: { n:"BrtBeginSXLIRws" },
16733
0x012C: { n:"BrtEndSXLIRws" },
16734
0x012D: { n:"BrtBeginSXLICols" },
16735
0x012E: { n:"BrtEndSXLICols" },
16736
0x012F: { n:"BrtBeginSXFormat" },
16737
0x0130: { n:"BrtEndSXFormat" },
16738
0x0131: { n:"BrtBeginSXFormats" },
16739
0x0132: { n:"BrtEndSxFormats" },
16740
0x0133: { n:"BrtBeginSxSelect" },
16741
0x0134: { n:"BrtEndSxSelect" },
16742
0x0135: { n:"BrtBeginISXVDRws" },
16743
0x0136: { n:"BrtEndISXVDRws" },
16744
0x0137: { n:"BrtBeginISXVDCols" },
16745
0x0138: { n:"BrtEndISXVDCols" },
16746
0x0139: { n:"BrtEndSXLocation" },
16747
0x013A: { n:"BrtBeginSXLocation" },
16748
0x013B: { n:"BrtEndSXView" },
16749
0x013C: { n:"BrtBeginSXTHs" },
16750
0x013D: { n:"BrtEndSXTHs" },
16751
0x013E: { n:"BrtBeginSXTH" },
16752
0x013F: { n:"BrtEndSXTH" },
16753
0x0140: { n:"BrtBeginISXTHRws" },
16754
0x0141: { n:"BrtEndISXTHRws" },
16755
0x0142: { n:"BrtBeginISXTHCols" },
16756
0x0143: { n:"BrtEndISXTHCols" },
16757
0x0144: { n:"BrtBeginSXTDMPS" },
16758
0x0145: { n:"BrtEndSXTDMPs" },
16759
0x0146: { n:"BrtBeginSXTDMP" },
16760
0x0147: { n:"BrtEndSXTDMP" },
16761
0x0148: { n:"BrtBeginSXTHItems" },
16762
0x0149: { n:"BrtEndSXTHItems" },
16763
0x014A: { n:"BrtBeginSXTHItem" },
16764
0x014B: { n:"BrtEndSXTHItem" },
16765
0x014C: { n:"BrtBeginMetadata" },
16766
0x014D: { n:"BrtEndMetadata" },
16767
0x014E: { n:"BrtBeginEsmdtinfo" },
16768
0x014F: { n:"BrtMdtinfo" },
16769
0x0150: { n:"BrtEndEsmdtinfo" },
16770
0x0151: { n:"BrtBeginEsmdb" },
16771
0x0152: { n:"BrtEndEsmdb" },
16772
0x0153: { n:"BrtBeginEsfmd" },
16773
0x0154: { n:"BrtEndEsfmd" },
16774
0x0155: { n:"BrtBeginSingleCells" },
16775
0x0156: { n:"BrtEndSingleCells" },
16776
0x0157: { n:"BrtBeginList" },
16777
0x0158: { n:"BrtEndList" },
16778
0x0159: { n:"BrtBeginListCols" },
16779
0x015A: { n:"BrtEndListCols" },
16780
0x015B: { n:"BrtBeginListCol" },
16781
0x015C: { n:"BrtEndListCol" },
16782
0x015D: { n:"BrtBeginListXmlCPr" },
16783
0x015E: { n:"BrtEndListXmlCPr" },
16784
0x015F: { n:"BrtListCCFmla" },
16785
0x0160: { n:"BrtListTrFmla" },
16786
0x0161: { n:"BrtBeginExternals" },
16787
0x0162: { n:"BrtEndExternals" },
16788
0x0163: { n:"BrtSupBookSrc", f:parse_RelID},
16789
0x0165: { n:"BrtSupSelf" },
16790
0x0166: { n:"BrtSupSame" },
16791
0x0167: { n:"BrtSupTabs" },
16792
0x0168: { n:"BrtBeginSupBook" },
16793
0x0169: { n:"BrtPlaceholderName" },
16794
0x016A: { n:"BrtExternSheet", f:parse_ExternSheet },
16795
0x016B: { n:"BrtExternTableStart" },
16796
0x016C: { n:"BrtExternTableEnd" },
16797
0x016E: { n:"BrtExternRowHdr" },
16798
0x016F: { n:"BrtExternCellBlank" },
16799
0x0170: { n:"BrtExternCellReal" },
16800
0x0171: { n:"BrtExternCellBool" },
16801
0x0172: { n:"BrtExternCellError" },
16802
0x0173: { n:"BrtExternCellString" },
16803
0x0174: { n:"BrtBeginEsmdx" },
16804
0x0175: { n:"BrtEndEsmdx" },
16805
0x0176: { n:"BrtBeginMdxSet" },
16806
0x0177: { n:"BrtEndMdxSet" },
16807
0x0178: { n:"BrtBeginMdxMbrProp" },
16808
0x0179: { n:"BrtEndMdxMbrProp" },
16809
0x017A: { n:"BrtBeginMdxKPI" },
16810
0x017B: { n:"BrtEndMdxKPI" },
16811
0x017C: { n:"BrtBeginEsstr" },
16812
0x017D: { n:"BrtEndEsstr" },
16813
0x017E: { n:"BrtBeginPRFItem" },
16814
0x017F: { n:"BrtEndPRFItem" },
16815
0x0180: { n:"BrtBeginPivotCacheIDs" },
16816
0x0181: { n:"BrtEndPivotCacheIDs" },
16817
0x0182: { n:"BrtBeginPivotCacheID" },
16818
0x0183: { n:"BrtEndPivotCacheID" },
16819
0x0184: { n:"BrtBeginISXVIs" },
16820
0x0185: { n:"BrtEndISXVIs" },
16821
0x0186: { n:"BrtBeginColInfos" },
16822
0x0187: { n:"BrtEndColInfos" },
16823
0x0188: { n:"BrtBeginRwBrk" },
16824
0x0189: { n:"BrtEndRwBrk" },
16825
0x018A: { n:"BrtBeginColBrk" },
16826
0x018B: { n:"BrtEndColBrk" },
16827
0x018C: { n:"BrtBrk" },
16828
0x018D: { n:"BrtUserBookView" },
16829
0x018E: { n:"BrtInfo" },
16830
0x018F: { n:"BrtCUsr" },
16831
0x0190: { n:"BrtUsr" },
16832
0x0191: { n:"BrtBeginUsers" },
16833
0x0193: { n:"BrtEOF" },
16834
0x0194: { n:"BrtUCR" },
16835
0x0195: { n:"BrtRRInsDel" },
16836
0x0196: { n:"BrtRREndInsDel" },
16837
0x0197: { n:"BrtRRMove" },
16838
0x0198: { n:"BrtRREndMove" },
16839
0x0199: { n:"BrtRRChgCell" },
16840
0x019A: { n:"BrtRREndChgCell" },
16841
0x019B: { n:"BrtRRHeader" },
16842
0x019C: { n:"BrtRRUserView" },
16843
0x019D: { n:"BrtRRRenSheet" },
16844
0x019E: { n:"BrtRRInsertSh" },
16845
0x019F: { n:"BrtRRDefName" },
16846
0x01A0: { n:"BrtRRNote" },
16847
0x01A1: { n:"BrtRRConflict" },
16848
0x01A2: { n:"BrtRRTQSIF" },
16849
0x01A3: { n:"BrtRRFormat" },
16850
0x01A4: { n:"BrtRREndFormat" },
16851
0x01A5: { n:"BrtRRAutoFmt" },
16852
0x01A6: { n:"BrtBeginUserShViews" },
16853
0x01A7: { n:"BrtBeginUserShView" },
16854
0x01A8: { n:"BrtEndUserShView" },
16855
0x01A9: { n:"BrtEndUserShViews" },
16856
0x01AA: { n:"BrtArrFmla", f:parse_BrtArrFmla },
16857
0x01AB: { n:"BrtShrFmla", f:parse_BrtShrFmla },
16858
0x01AC: { n:"BrtTable" },
16859
0x01AD: { n:"BrtBeginExtConnections" },
16860
0x01AE: { n:"BrtEndExtConnections" },
16861
0x01AF: { n:"BrtBeginPCDCalcMems" },
16862
0x01B0: { n:"BrtEndPCDCalcMems" },
16863
0x01B1: { n:"BrtBeginPCDCalcMem" },
16864
0x01B2: { n:"BrtEndPCDCalcMem" },
16865
0x01B3: { n:"BrtBeginPCDHGLevels" },
16866
0x01B4: { n:"BrtEndPCDHGLevels" },
16867
0x01B5: { n:"BrtBeginPCDHGLevel" },
16868
0x01B6: { n:"BrtEndPCDHGLevel" },
16869
0x01B7: { n:"BrtBeginPCDHGLGroups" },
16870
0x01B8: { n:"BrtEndPCDHGLGroups" },
16871
0x01B9: { n:"BrtBeginPCDHGLGroup" },
16872
0x01BA: { n:"BrtEndPCDHGLGroup" },
16873
0x01BB: { n:"BrtBeginPCDHGLGMembers" },
16874
0x01BC: { n:"BrtEndPCDHGLGMembers" },
16875
0x01BD: { n:"BrtBeginPCDHGLGMember" },
16876
0x01BE: { n:"BrtEndPCDHGLGMember" },
16877
0x01BF: { n:"BrtBeginQSI" },
16878
0x01C0: { n:"BrtEndQSI" },
16879
0x01C1: { n:"BrtBeginQSIR" },
16880
0x01C2: { n:"BrtEndQSIR" },
16881
0x01C3: { n:"BrtBeginDeletedNames" },
16882
0x01C4: { n:"BrtEndDeletedNames" },
16883
0x01C5: { n:"BrtBeginDeletedName" },
16884
0x01C6: { n:"BrtEndDeletedName" },
16885
0x01C7: { n:"BrtBeginQSIFs" },
16886
0x01C8: { n:"BrtEndQSIFs" },
16887
0x01C9: { n:"BrtBeginQSIF" },
16888
0x01CA: { n:"BrtEndQSIF" },
16889
0x01CB: { n:"BrtBeginAutoSortScope" },
16890
0x01CC: { n:"BrtEndAutoSortScope" },
16891
0x01CD: { n:"BrtBeginConditionalFormatting" },
16892
0x01CE: { n:"BrtEndConditionalFormatting" },
16893
0x01CF: { n:"BrtBeginCFRule" },
16894
0x01D0: { n:"BrtEndCFRule" },
16895
0x01D1: { n:"BrtBeginIconSet" },
16896
0x01D2: { n:"BrtEndIconSet" },
16897
0x01D3: { n:"BrtBeginDatabar" },
16898
0x01D4: { n:"BrtEndDatabar" },
16899
0x01D5: { n:"BrtBeginColorScale" },
16900
0x01D6: { n:"BrtEndColorScale" },
16901
0x01D7: { n:"BrtCFVO" },
16902
0x01D8: { n:"BrtExternValueMeta" },
16903
0x01D9: { n:"BrtBeginColorPalette" },
16904
0x01DA: { n:"BrtEndColorPalette" },
16905
0x01DB: { n:"BrtIndexedColor" },
16906
0x01DC: { n:"BrtMargins", f:parse_BrtMargins },
16907
0x01DD: { n:"BrtPrintOptions" },
16908
0x01DE: { n:"BrtPageSetup" },
16909
0x01DF: { n:"BrtBeginHeaderFooter" },
16910
0x01E0: { n:"BrtEndHeaderFooter" },
16911
0x01E1: { n:"BrtBeginSXCrtFormat" },
16912
0x01E2: { n:"BrtEndSXCrtFormat" },
16913
0x01E3: { n:"BrtBeginSXCrtFormats" },
16914
0x01E4: { n:"BrtEndSXCrtFormats" },
16915
0x01E5: { n:"BrtWsFmtInfo", f:parse_BrtWsFmtInfo },
16916
0x01E6: { n:"BrtBeginMgs" },
16917
0x01E7: { n:"BrtEndMGs" },
16918
0x01E8: { n:"BrtBeginMGMaps" },
16919
0x01E9: { n:"BrtEndMGMaps" },
16920
0x01EA: { n:"BrtBeginMG" },
16921
0x01EB: { n:"BrtEndMG" },
16922
0x01EC: { n:"BrtBeginMap" },
16923
0x01ED: { n:"BrtEndMap" },
16924
0x01EE: { n:"BrtHLink", f:parse_BrtHLink },
16925
0x01EF: { n:"BrtBeginDCon" },
16926
0x01F0: { n:"BrtEndDCon" },
16927
0x01F1: { n:"BrtBeginDRefs" },
16928
0x01F2: { n:"BrtEndDRefs" },
16929
0x01F3: { n:"BrtDRef" },
16930
0x01F4: { n:"BrtBeginScenMan" },
16931
0x01F5: { n:"BrtEndScenMan" },
16932
0x01F6: { n:"BrtBeginSct" },
16933
0x01F7: { n:"BrtEndSct" },
16934
0x01F8: { n:"BrtSlc" },
16935
0x01F9: { n:"BrtBeginDXFs" },
16936
0x01FA: { n:"BrtEndDXFs" },
16937
0x01FB: { n:"BrtDXF" },
16938
0x01FC: { n:"BrtBeginTableStyles" },
16939
0x01FD: { n:"BrtEndTableStyles" },
16940
0x01FE: { n:"BrtBeginTableStyle" },
16941
0x01FF: { n:"BrtEndTableStyle" },
16942
0x0200: { n:"BrtTableStyleElement" },
16943
0x0201: { n:"BrtTableStyleClient" },
16944
0x0202: { n:"BrtBeginVolDeps" },
16945
0x0203: { n:"BrtEndVolDeps" },
16946
0x0204: { n:"BrtBeginVolType" },
16947
0x0205: { n:"BrtEndVolType" },
16948
0x0206: { n:"BrtBeginVolMain" },
16949
0x0207: { n:"BrtEndVolMain" },
16950
0x0208: { n:"BrtBeginVolTopic" },
16951
0x0209: { n:"BrtEndVolTopic" },
16952
0x020A: { n:"BrtVolSubtopic" },
16953
0x020B: { n:"BrtVolRef" },
16954
0x020C: { n:"BrtVolNum" },
16955
0x020D: { n:"BrtVolErr" },
16956
0x020E: { n:"BrtVolStr" },
16957
0x020F: { n:"BrtVolBool" },
16958
0x0210: { n:"BrtBeginCalcChain$" },
16959
0x0211: { n:"BrtEndCalcChain$" },
16960
0x0212: { n:"BrtBeginSortState" },
16961
0x0213: { n:"BrtEndSortState" },
16962
0x0214: { n:"BrtBeginSortCond" },
16963
0x0215: { n:"BrtEndSortCond" },
16964
0x0216: { n:"BrtBookProtection" },
16965
0x0217: { n:"BrtSheetProtection" },
16966
0x0218: { n:"BrtRangeProtection" },
16967
0x0219: { n:"BrtPhoneticInfo" },
16968
0x021A: { n:"BrtBeginECTxtWiz" },
16969
0x021B: { n:"BrtEndECTxtWiz" },
16970
0x021C: { n:"BrtBeginECTWFldInfoLst" },
16971
0x021D: { n:"BrtEndECTWFldInfoLst" },
16972
0x021E: { n:"BrtBeginECTwFldInfo" },
16973
0x0224: { n:"BrtFileSharing" },
16974
0x0225: { n:"BrtOleSize" },
16975
0x0226: { n:"BrtDrawing", f:parse_RelID },
16976
0x0227: { n:"BrtLegacyDrawing" },
16977
0x0228: { n:"BrtLegacyDrawingHF" },
16978
0x0229: { n:"BrtWebOpt" },
16979
0x022A: { n:"BrtBeginWebPubItems" },
16980
0x022B: { n:"BrtEndWebPubItems" },
16981
0x022C: { n:"BrtBeginWebPubItem" },
16982
0x022D: { n:"BrtEndWebPubItem" },
16983
0x022E: { n:"BrtBeginSXCondFmt" },
16984
0x022F: { n:"BrtEndSXCondFmt" },
16985
0x0230: { n:"BrtBeginSXCondFmts" },
16986
0x0231: { n:"BrtEndSXCondFmts" },
16987
0x0232: { n:"BrtBkHim" },
16988
0x0234: { n:"BrtColor" },
16989
0x0235: { n:"BrtBeginIndexedColors" },
16990
0x0236: { n:"BrtEndIndexedColors" },
16991
0x0239: { n:"BrtBeginMRUColors" },
16992
0x023A: { n:"BrtEndMRUColors" },
16993
0x023C: { n:"BrtMRUColor" },
16994
0x023D: { n:"BrtBeginDVals" },
16995
0x023E: { n:"BrtEndDVals" },
16996
0x0241: { n:"BrtSupNameStart" },
16997
0x0242: { n:"BrtSupNameValueStart" },
16998
0x0243: { n:"BrtSupNameValueEnd" },
16999
0x0244: { n:"BrtSupNameNum" },
17000
0x0245: { n:"BrtSupNameErr" },
17001
0x0246: { n:"BrtSupNameSt" },
17002
0x0247: { n:"BrtSupNameNil" },
17003
0x0248: { n:"BrtSupNameBool" },
17004
0x0249: { n:"BrtSupNameFmla" },
17005
0x024A: { n:"BrtSupNameBits" },
17006
0x024B: { n:"BrtSupNameEnd" },
17007
0x024C: { n:"BrtEndSupBook" },
17008
0x024D: { n:"BrtCellSmartTagProperty" },
17009
0x024E: { n:"BrtBeginCellSmartTag" },
17010
0x024F: { n:"BrtEndCellSmartTag" },
17011
0x0250: { n:"BrtBeginCellSmartTags" },
17012
0x0251: { n:"BrtEndCellSmartTags" },
17013
0x0252: { n:"BrtBeginSmartTags" },
17014
0x0253: { n:"BrtEndSmartTags" },
17015
0x0254: { n:"BrtSmartTagType" },
17016
0x0255: { n:"BrtBeginSmartTagTypes" },
17017
0x0256: { n:"BrtEndSmartTagTypes" },
17018
0x0257: { n:"BrtBeginSXFilters" },
17019
0x0258: { n:"BrtEndSXFilters" },
17020
0x0259: { n:"BrtBeginSXFILTER" },
17021
0x025A: { n:"BrtEndSXFilter" },
17022
0x025B: { n:"BrtBeginFills" },
17023
0x025C: { n:"BrtEndFills" },
17024
0x025D: { n:"BrtBeginCellWatches" },
17025
0x025E: { n:"BrtEndCellWatches" },
17026
0x025F: { n:"BrtCellWatch" },
17027
0x0260: { n:"BrtBeginCRErrs" },
17028
0x0261: { n:"BrtEndCRErrs" },
17029
0x0262: { n:"BrtCrashRecErr" },
17030
0x0263: { n:"BrtBeginFonts" },
17031
0x0264: { n:"BrtEndFonts" },
17032
0x0265: { n:"BrtBeginBorders" },
17033
0x0266: { n:"BrtEndBorders" },
17034
0x0267: { n:"BrtBeginFmts" },
17035
0x0268: { n:"BrtEndFmts" },
17036
0x0269: { n:"BrtBeginCellXFs" },
17037
0x026A: { n:"BrtEndCellXFs" },
17038
0x026B: { n:"BrtBeginStyles" },
17039
0x026C: { n:"BrtEndStyles" },
17040
0x0271: { n:"BrtBigName" },
17041
0x0272: { n:"BrtBeginCellStyleXFs" },
17042
0x0273: { n:"BrtEndCellStyleXFs" },
17043
0x0274: { n:"BrtBeginComments" },
17044
0x0275: { n:"BrtEndComments" },
17045
0x0276: { n:"BrtBeginCommentAuthors" },
17046
0x0277: { n:"BrtEndCommentAuthors" },
17047
0x0278: { n:"BrtCommentAuthor", f:parse_BrtCommentAuthor },
17048
0x0279: { n:"BrtBeginCommentList" },
17049
0x027A: { n:"BrtEndCommentList" },
17050
0x027B: { n:"BrtBeginComment", f:parse_BrtBeginComment},
17051
0x027C: { n:"BrtEndComment" },
17052
0x027D: { n:"BrtCommentText", f:parse_BrtCommentText },
17053
0x027E: { n:"BrtBeginOleObjects" },
17054
0x027F: { n:"BrtOleObject" },
17055
0x0280: { n:"BrtEndOleObjects" },
17056
0x0281: { n:"BrtBeginSxrules" },
17057
0x0282: { n:"BrtEndSxRules" },
17058
0x0283: { n:"BrtBeginActiveXControls" },
17059
0x0284: { n:"BrtActiveX" },
17060
0x0285: { n:"BrtEndActiveXControls" },
17061
0x0286: { n:"BrtBeginPCDSDTCEMembersSortBy" },
17062
0x0288: { n:"BrtBeginCellIgnoreECs" },
17063
0x0289: { n:"BrtCellIgnoreEC" },
17064
0x028A: { n:"BrtEndCellIgnoreECs" },
17065
0x028B: { n:"BrtCsProp", f:parse_BrtCsProp },
17066
0x028C: { n:"BrtCsPageSetup" },
17067
0x028D: { n:"BrtBeginUserCsViews" },
17068
0x028E: { n:"BrtEndUserCsViews" },
17069
0x028F: { n:"BrtBeginUserCsView" },
17070
0x0290: { n:"BrtEndUserCsView" },
17071
0x0291: { n:"BrtBeginPcdSFCIEntries" },
17072
0x0292: { n:"BrtEndPCDSFCIEntries" },
17073
0x0293: { n:"BrtPCDSFCIEntry" },
17074
0x0294: { n:"BrtBeginListParts" },
17075
0x0295: { n:"BrtListPart" },
17076
0x0296: { n:"BrtEndListParts" },
17077
0x0297: { n:"BrtSheetCalcProp" },
17078
0x0298: { n:"BrtBeginFnGroup" },
17079
0x0299: { n:"BrtFnGroup" },
17080
0x029A: { n:"BrtEndFnGroup" },
17081
0x029B: { n:"BrtSupAddin" },
17082
0x029C: { n:"BrtSXTDMPOrder" },
17083
0x029D: { n:"BrtCsProtection" },
17084
0x029F: { n:"BrtBeginWsSortMap" },
17085
0x02A0: { n:"BrtEndWsSortMap" },
17086
0x02A1: { n:"BrtBeginRRSort" },
17087
0x02A2: { n:"BrtEndRRSort" },
17088
0x02A3: { n:"BrtRRSortItem" },
17089
0x02A4: { n:"BrtFileSharingIso" },
17090
0x02A5: { n:"BrtBookProtectionIso" },
17091
0x02A6: { n:"BrtSheetProtectionIso" },
17092
0x02A7: { n:"BrtCsProtectionIso" },
17093
0x02A8: { n:"BrtRangeProtectionIso" },
17094
0x0400: { n:"BrtRwDescent" },
17095
0x0401: { n:"BrtKnownFonts" },
17096
0x0402: { n:"BrtBeginSXTupleSet" },
17097
0x0403: { n:"BrtEndSXTupleSet" },
17098
0x0404: { n:"BrtBeginSXTupleSetHeader" },
17099
0x0405: { n:"BrtEndSXTupleSetHeader" },
17100
0x0406: { n:"BrtSXTupleSetHeaderItem" },
17101
0x0407: { n:"BrtBeginSXTupleSetData" },
17102
0x0408: { n:"BrtEndSXTupleSetData" },
17103
0x0409: { n:"BrtBeginSXTupleSetRow" },
17104
0x040A: { n:"BrtEndSXTupleSetRow" },
17105
0x040B: { n:"BrtSXTupleSetRowItem" },
17106
0x040C: { n:"BrtNameExt" },
17107
0x040D: { n:"BrtPCDH14" },
17108
0x040E: { n:"BrtBeginPCDCalcMem14" },
17109
0x040F: { n:"BrtEndPCDCalcMem14" },
17110
0x0410: { n:"BrtSXTH14" },
17111
0x0411: { n:"BrtBeginSparklineGroup" },
17112
0x0412: { n:"BrtEndSparklineGroup" },
17113
0x0413: { n:"BrtSparkline" },
17114
0x0414: { n:"BrtSXDI14" },
17115
0x0415: { n:"BrtWsFmtInfoEx14" },
17116
0x0416: { n:"BrtBeginConditionalFormatting14" },
17117
0x0417: { n:"BrtEndConditionalFormatting14" },
17118
0x0418: { n:"BrtBeginCFRule14" },
17119
0x0419: { n:"BrtEndCFRule14" },
17120
0x041A: { n:"BrtCFVO14" },
17121
0x041B: { n:"BrtBeginDatabar14" },
17122
0x041C: { n:"BrtBeginIconSet14" },
17123
0x041D: { n:"BrtDVal14" },
17124
0x041E: { n:"BrtBeginDVals14" },
17125
0x041F: { n:"BrtColor14" },
17126
0x0420: { n:"BrtBeginSparklines" },
17127
0x0421: { n:"BrtEndSparklines" },
17128
0x0422: { n:"BrtBeginSparklineGroups" },
17129
0x0423: { n:"BrtEndSparklineGroups" },
17130
0x0425: { n:"BrtSXVD14" },
17131
0x0426: { n:"BrtBeginSXView14" },
17132
0x0427: { n:"BrtEndSXView14" },
17133
0x0428: { n:"BrtBeginSXView16" },
17134
0x0429: { n:"BrtEndSXView16" },
17135
0x042A: { n:"BrtBeginPCD14" },
17136
0x042B: { n:"BrtEndPCD14" },
17137
0x042C: { n:"BrtBeginExtConn14" },
17138
0x042D: { n:"BrtEndExtConn14" },
17139
0x042E: { n:"BrtBeginSlicerCacheIDs" },
17140
0x042F: { n:"BrtEndSlicerCacheIDs" },
17141
0x0430: { n:"BrtBeginSlicerCacheID" },
17142
0x0431: { n:"BrtEndSlicerCacheID" },
17143
0x0433: { n:"BrtBeginSlicerCache" },
17144
0x0434: { n:"BrtEndSlicerCache" },
17145
0x0435: { n:"BrtBeginSlicerCacheDef" },
17146
0x0436: { n:"BrtEndSlicerCacheDef" },
17147
0x0437: { n:"BrtBeginSlicersEx" },
17148
0x0438: { n:"BrtEndSlicersEx" },
17149
0x0439: { n:"BrtBeginSlicerEx" },
17150
0x043A: { n:"BrtEndSlicerEx" },
17151
0x043B: { n:"BrtBeginSlicer" },
17152
0x043C: { n:"BrtEndSlicer" },
17153
0x043D: { n:"BrtSlicerCachePivotTables" },
17154
0x043E: { n:"BrtBeginSlicerCacheOlapImpl" },
17155
0x043F: { n:"BrtEndSlicerCacheOlapImpl" },
17156
0x0440: { n:"BrtBeginSlicerCacheLevelsData" },
17157
0x0441: { n:"BrtEndSlicerCacheLevelsData" },
17158
0x0442: { n:"BrtBeginSlicerCacheLevelData" },
17159
0x0443: { n:"BrtEndSlicerCacheLevelData" },
17160
0x0444: { n:"BrtBeginSlicerCacheSiRanges" },
17161
0x0445: { n:"BrtEndSlicerCacheSiRanges" },
17162
0x0446: { n:"BrtBeginSlicerCacheSiRange" },
17163
0x0447: { n:"BrtEndSlicerCacheSiRange" },
17164
0x0448: { n:"BrtSlicerCacheOlapItem" },
17165
0x0449: { n:"BrtBeginSlicerCacheSelections" },
17166
0x044A: { n:"BrtSlicerCacheSelection" },
17167
0x044B: { n:"BrtEndSlicerCacheSelections" },
17168
0x044C: { n:"BrtBeginSlicerCacheNative" },
17169
0x044D: { n:"BrtEndSlicerCacheNative" },
17170
0x044E: { n:"BrtSlicerCacheNativeItem" },
17171
0x044F: { n:"BrtRangeProtection14" },
17172
0x0450: { n:"BrtRangeProtectionIso14" },
17173
0x0451: { n:"BrtCellIgnoreEC14" },
17174
0x0457: { n:"BrtList14" },
17175
0x0458: { n:"BrtCFIcon" },
17176
0x0459: { n:"BrtBeginSlicerCachesPivotCacheIDs" },
17177
0x045A: { n:"BrtEndSlicerCachesPivotCacheIDs" },
17178
0x045B: { n:"BrtBeginSlicers" },
17179
0x045C: { n:"BrtEndSlicers" },
17180
0x045D: { n:"BrtWbProp14" },
17181
0x045E: { n:"BrtBeginSXEdit" },
17182
0x045F: { n:"BrtEndSXEdit" },
17183
0x0460: { n:"BrtBeginSXEdits" },
17184
0x0461: { n:"BrtEndSXEdits" },
17185
0x0462: { n:"BrtBeginSXChange" },
17186
0x0463: { n:"BrtEndSXChange" },
17187
0x0464: { n:"BrtBeginSXChanges" },
17188
0x0465: { n:"BrtEndSXChanges" },
17189
0x0466: { n:"BrtSXTupleItems" },
17190
0x0468: { n:"BrtBeginSlicerStyle" },
17191
0x0469: { n:"BrtEndSlicerStyle" },
17192
0x046A: { n:"BrtSlicerStyleElement" },
17193
0x046B: { n:"BrtBeginStyleSheetExt14" },
17194
0x046C: { n:"BrtEndStyleSheetExt14" },
17195
0x046D: { n:"BrtBeginSlicerCachesPivotCacheID" },
17196
0x046E: { n:"BrtEndSlicerCachesPivotCacheID" },
17197
0x046F: { n:"BrtBeginConditionalFormattings" },
17198
0x0470: { n:"BrtEndConditionalFormattings" },
17199
0x0471: { n:"BrtBeginPCDCalcMemExt" },
17200
0x0472: { n:"BrtEndPCDCalcMemExt" },
17201
0x0473: { n:"BrtBeginPCDCalcMemsExt" },
17202
0x0474: { n:"BrtEndPCDCalcMemsExt" },
17203
0x0475: { n:"BrtPCDField14" },
17204
0x0476: { n:"BrtBeginSlicerStyles" },
17205
0x0477: { n:"BrtEndSlicerStyles" },
17206
0x0478: { n:"BrtBeginSlicerStyleElements" },
17207
0x0479: { n:"BrtEndSlicerStyleElements" },
17208
0x047A: { n:"BrtCFRuleExt" },
17209
0x047B: { n:"BrtBeginSXCondFmt14" },
17210
0x047C: { n:"BrtEndSXCondFmt14" },
17211
0x047D: { n:"BrtBeginSXCondFmts14" },
17212
0x047E: { n:"BrtEndSXCondFmts14" },
17213
0x0480: { n:"BrtBeginSortCond14" },
17214
0x0481: { n:"BrtEndSortCond14" },
17215
0x0482: { n:"BrtEndDVals14" },
17216
0x0483: { n:"BrtEndIconSet14" },
17217
0x0484: { n:"BrtEndDatabar14" },
17218
0x0485: { n:"BrtBeginColorScale14" },
17219
0x0486: { n:"BrtEndColorScale14" },
17220
0x0487: { n:"BrtBeginSxrules14" },
17221
0x0488: { n:"BrtEndSxrules14" },
17222
0x0489: { n:"BrtBeginPRule14" },
17223
0x048A: { n:"BrtEndPRule14" },
17224
0x048B: { n:"BrtBeginPRFilters14" },
17225
0x048C: { n:"BrtEndPRFilters14" },
17226
0x048D: { n:"BrtBeginPRFilter14" },
17227
0x048E: { n:"BrtEndPRFilter14" },
17228
0x048F: { n:"BrtBeginPRFItem14" },
17229
0x0490: { n:"BrtEndPRFItem14" },
17230
0x0491: { n:"BrtBeginCellIgnoreECs14" },
17231
0x0492: { n:"BrtEndCellIgnoreECs14" },
17232
0x0493: { n:"BrtDxf14" },
17233
0x0494: { n:"BrtBeginDxF14s" },
17234
0x0495: { n:"BrtEndDxf14s" },
17235
0x0499: { n:"BrtFilter14" },
17236
0x049A: { n:"BrtBeginCustomFilters14" },
17237
0x049C: { n:"BrtCustomFilter14" },
17238
0x049D: { n:"BrtIconFilter14" },
17239
0x049E: { n:"BrtPivotCacheConnectionName" },
17240
0x0800: { n:"BrtBeginDecoupledPivotCacheIDs" },
17241
0x0801: { n:"BrtEndDecoupledPivotCacheIDs" },
17242
0x0802: { n:"BrtDecoupledPivotCacheID" },
17243
0x0803: { n:"BrtBeginPivotTableRefs" },
17244
0x0804: { n:"BrtEndPivotTableRefs" },
17245
0x0805: { n:"BrtPivotTableRef" },
17246
0x0806: { n:"BrtSlicerCacheBookPivotTables" },
17247
0x0807: { n:"BrtBeginSxvcells" },
17248
0x0808: { n:"BrtEndSxvcells" },
17249
0x0809: { n:"BrtBeginSxRow" },
17250
0x080A: { n:"BrtEndSxRow" },
17251
0x080C: { n:"BrtPcdCalcMem15" },
17252
0x0813: { n:"BrtQsi15" },
17253
0x0814: { n:"BrtBeginWebExtensions" },
17254
0x0815: { n:"BrtEndWebExtensions" },
17255
0x0816: { n:"BrtWebExtension" },
17256
0x0817: { n:"BrtAbsPath15" },
17257
0x0818: { n:"BrtBeginPivotTableUISettings" },
17258
0x0819: { n:"BrtEndPivotTableUISettings" },
17259
0x081B: { n:"BrtTableSlicerCacheIDs" },
17260
0x081C: { n:"BrtTableSlicerCacheID" },
17261
0x081D: { n:"BrtBeginTableSlicerCache" },
17262
0x081E: { n:"BrtEndTableSlicerCache" },
17263
0x081F: { n:"BrtSxFilter15" },
17264
0x0820: { n:"BrtBeginTimelineCachePivotCacheIDs" },
17265
0x0821: { n:"BrtEndTimelineCachePivotCacheIDs" },
17266
0x0822: { n:"BrtTimelineCachePivotCacheID" },
17267
0x0823: { n:"BrtBeginTimelineCacheIDs" },
17268
0x0824: { n:"BrtEndTimelineCacheIDs" },
17269
0x0825: { n:"BrtBeginTimelineCacheID" },
17270
0x0826: { n:"BrtEndTimelineCacheID" },
17271
0x0827: { n:"BrtBeginTimelinesEx" },
17272
0x0828: { n:"BrtEndTimelinesEx" },
17273
0x0829: { n:"BrtBeginTimelineEx" },
17274
0x082A: { n:"BrtEndTimelineEx" },
17275
0x082B: { n:"BrtWorkBookPr15" },
17276
0x082C: { n:"BrtPCDH15" },
17277
0x082D: { n:"BrtBeginTimelineStyle" },
17278
0x082E: { n:"BrtEndTimelineStyle" },
17279
0x082F: { n:"BrtTimelineStyleElement" },
17280
0x0830: { n:"BrtBeginTimelineStylesheetExt15" },
17281
0x0831: { n:"BrtEndTimelineStylesheetExt15" },
17282
0x0832: { n:"BrtBeginTimelineStyles" },
17283
0x0833: { n:"BrtEndTimelineStyles" },
17284
0x0834: { n:"BrtBeginTimelineStyleElements" },
17285
0x0835: { n:"BrtEndTimelineStyleElements" },
17286
0x0836: { n:"BrtDxf15" },
17287
0x0837: { n:"BrtBeginDxfs15" },
17288
0x0838: { n:"brtEndDxfs15" },
17289
0x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
17290
0x083A: { n:"BrtBeginItemUniqueNames" },
17291
0x083B: { n:"BrtEndItemUniqueNames" },
17292
0x083C: { n:"BrtItemUniqueName" },
17293
0x083D: { n:"BrtBeginExtConn15" },
17294
0x083E: { n:"BrtEndExtConn15" },
17295
0x083F: { n:"BrtBeginOledbPr15" },
17296
0x0840: { n:"BrtEndOledbPr15" },
17297
0x0841: { n:"BrtBeginDataFeedPr15" },
17298
0x0842: { n:"BrtEndDataFeedPr15" },
17299
0x0843: { n:"BrtTextPr15" },
17300
0x0844: { n:"BrtRangePr15" },
17301
0x0845: { n:"BrtDbCommand15" },
17302
0x0846: { n:"BrtBeginDbTables15" },
17303
0x0847: { n:"BrtEndDbTables15" },
17304
0x0848: { n:"BrtDbTable15" },
17305
0x0849: { n:"BrtBeginDataModel" },
17306
0x084A: { n:"BrtEndDataModel" },
17307
0x084B: { n:"BrtBeginModelTables" },
17308
0x084C: { n:"BrtEndModelTables" },
17309
0x084D: { n:"BrtModelTable" },
17310
0x084E: { n:"BrtBeginModelRelationships" },
17311
0x084F: { n:"BrtEndModelRelationships" },
17312
0x0850: { n:"BrtModelRelationship" },
17313
0x0851: { n:"BrtBeginECTxtWiz15" },
17314
0x0852: { n:"BrtEndECTxtWiz15" },
17315
0x0853: { n:"BrtBeginECTWFldInfoLst15" },
17316
0x0854: { n:"BrtEndECTWFldInfoLst15" },
17317
0x0855: { n:"BrtBeginECTWFldInfo15" },
17318
0x0856: { n:"BrtFieldListActiveItem" },
17319
0x0857: { n:"BrtPivotCacheIdVersion" },
17320
0x0858: { n:"BrtSXDI15" },
17321
0x0859: { n:"BrtBeginModelTimeGroupings" },
17322
0x085A: { n:"BrtEndModelTimeGroupings" },
17323
0x085B: { n:"BrtBeginModelTimeGrouping" },
17324
0x085C: { n:"BrtEndModelTimeGrouping" },
17325
0x085D: { n:"BrtModelTimeGroupingCalcCol" },
17326
0x0C00: { n:"BrtUid" },
17327
0x0C01: { n:"BrtRevisionPtr" },
17328
0xFFFF: { n:"" }
17329
};
17330
17331
var XLSBRE = evert_key(XLSBRecordEnum, 'n');
17332
17333
/* [MS-XLS] 2.3 Record Enumeration */
17334
var XLSRecordEnum = {
17335
0x0003: { n:"BIFF2NUM", f:parse_BIFF2NUM },
17336
0x0004: { n:"BIFF2STR", f:parse_BIFF2STR },
17337
0x0006: { n:"Formula", f:parse_Formula },
17338
0x0009: { n:'BOF', f:parse_BOF },
17339
0x000a: { n:'EOF', f:parsenoop2 },
17340
0x000c: { n:"CalcCount", f:parseuint16 },
17341
0x000d: { n:"CalcMode", f:parseuint16 },
17342
0x000e: { n:"CalcPrecision", f:parsebool },
17343
0x000f: { n:"CalcRefMode", f:parsebool },
17344
0x0010: { n:"CalcDelta", f:parse_Xnum },
17345
0x0011: { n:"CalcIter", f:parsebool },
17346
0x0012: { n:"Protect", f:parsebool },
17347
0x0013: { n:"Password", f:parseuint16 },
17348
0x0014: { n:"Header", f:parse_XLHeaderFooter },
17349
0x0015: { n:"Footer", f:parse_XLHeaderFooter },
17350
0x0017: { n:"ExternSheet", f:parse_ExternSheet },
17351
0x0018: { n:"Lbl", f:parse_Lbl },
17352
0x0019: { n:"WinProtect", f:parsebool },
17353
0x001a: { n:"VerticalPageBreaks" },
17354
0x001b: { n:"HorizontalPageBreaks" },
17355
0x001c: { n:"Note", f:parse_Note },
17356
0x001d: { n:"Selection" },
17357
0x0022: { n:"Date1904", f:parsebool },
17358
0x0023: { n:"ExternName", f:parse_ExternName },
17359
0x0026: { n:"LeftMargin", f:parse_Xnum },
17360
0x0027: { n:"RightMargin", f:parse_Xnum },
17361
0x0028: { n:"TopMargin", f:parse_Xnum },
17362
0x0029: { n:"BottomMargin", f:parse_Xnum },
17363
0x002a: { n:"PrintRowCol", f:parsebool },
17364
0x002b: { n:"PrintGrid", f:parsebool },
17365
0x002f: { n:"FilePass", f:parse_FilePass },
17366
0x0031: { n:"Font", f:parse_Font },
17367
0x0033: { n:"PrintSize", f:parseuint16 },
17368
0x003c: { n:"Continue" },
17369
0x003d: { n:"Window1", f:parse_Window1 },
17370
0x0040: { n:"Backup", f:parsebool },
17371
0x0041: { n:"Pane" },
17372
0x0042: { n:'CodePage', f:parseuint16 },
17373
0x004d: { n:"Pls" },
17374
0x0050: { n:"DCon" },
17375
0x0051: { n:"DConRef" },
17376
0x0052: { n:"DConName" },
17377
0x0055: { n:"DefColWidth", f:parseuint16 },
17378
0x0059: { n:"XCT" },
17379
0x005a: { n:"CRN" },
17380
0x005b: { n:"FileSharing" },
17381
0x005c: { n:'WriteAccess', f:parse_WriteAccess },
17382
0x005d: { n:"Obj", f:parse_Obj },
17383
0x005e: { n:"Uncalced" },
17384
0x005f: { n:"CalcSaveRecalc", f:parsebool },
17385
0x0060: { n:"Template" },
17386
0x0061: { n:"Intl" },
17387
0x0063: { n:"ObjProtect", f:parsebool },
17388
0x007d: { n:"ColInfo", f:parse_ColInfo },
17389
0x0080: { n:"Guts", f:parse_Guts },
17390
0x0081: { n:"WsBool", f:parse_WsBool },
17391
0x0082: { n:"GridSet", f:parseuint16 },
17392
0x0083: { n:"HCenter", f:parsebool },
17393
0x0084: { n:"VCenter", f:parsebool },
17394
0x0085: { n:'BoundSheet8', f:parse_BoundSheet8 },
17395
0x0086: { n:"WriteProtect" },
17396
0x008c: { n:"Country", f:parse_Country },
17397
0x008d: { n:"HideObj", f:parseuint16 },
17398
0x0090: { n:"Sort" },
17399
0x0092: { n:"Palette", f:parse_Palette },
17400
0x0097: { n:"Sync" },
17401
0x0098: { n:"LPr" },
17402
0x0099: { n:"DxGCol" },
17403
0x009a: { n:"FnGroupName" },
17404
0x009b: { n:"FilterMode" },
17405
0x009c: { n:"BuiltInFnGroupCount", f:parseuint16 },
17406
0x009d: { n:"AutoFilterInfo" },
17407
0x009e: { n:"AutoFilter" },
17408
0x00a0: { n:"Scl", f:parse_Scl },
17409
0x00a1: { n:"Setup", f:parse_Setup },
17410
0x00ae: { n:"ScenMan" },
17411
0x00af: { n:"SCENARIO" },
17412
0x00b0: { n:"SxView" },
17413
0x00b1: { n:"Sxvd" },
17414
0x00b2: { n:"SXVI" },
17415
0x00b4: { n:"SxIvd" },
17416
0x00b5: { n:"SXLI" },
17417
0x00b6: { n:"SXPI" },
17418
0x00b8: { n:"DocRoute" },
17419
0x00b9: { n:"RecipName" },
17420
0x00bd: { n:"MulRk", f:parse_MulRk },
17421
0x00be: { n:"MulBlank", f:parse_MulBlank },
17422
0x00c1: { n:'Mms', f:parsenoop2 },
17423
0x00c5: { n:"SXDI" },
17424
0x00c6: { n:"SXDB" },
17425
0x00c7: { n:"SXFDB" },
17426
0x00c8: { n:"SXDBB" },
17427
0x00c9: { n:"SXNum" },
17428
0x00ca: { n:"SxBool", f:parsebool },
17429
0x00cb: { n:"SxErr" },
17430
0x00cc: { n:"SXInt" },
17431
0x00cd: { n:"SXString" },
17432
0x00ce: { n:"SXDtr" },
17433
0x00cf: { n:"SxNil" },
17434
0x00d0: { n:"SXTbl" },
17435
0x00d1: { n:"SXTBRGIITM" },
17436
0x00d2: { n:"SxTbpg" },
17437
0x00d3: { n:"ObProj" },
17438
0x00d5: { n:"SXStreamID" },
17439
0x00d7: { n:"DBCell" },
17440
0x00d8: { n:"SXRng" },
17441
0x00d9: { n:"SxIsxoper" },
17442
0x00da: { n:"BookBool", f:parseuint16 },
17443
0x00dc: { n:"DbOrParamQry" },
17444
0x00dd: { n:"ScenarioProtect", f:parsebool },
17445
0x00de: { n:"OleObjectSize" },
17446
0x00e0: { n:"XF", f:parse_XF },
17447
0x00e1: { n:'InterfaceHdr', f:parse_InterfaceHdr },
17448
0x00e2: { n:'InterfaceEnd', f:parsenoop2 },
17449
0x00e3: { n:"SXVS" },
17450
0x00e5: { n:"MergeCells", f:parse_MergeCells },
17451
0x00e9: { n:"BkHim" },
17452
0x00eb: { n:"MsoDrawingGroup" },
17453
0x00ec: { n:"MsoDrawing" },
17454
0x00ed: { n:"MsoDrawingSelection" },
17455
0x00ef: { n:"PhoneticInfo" },
17456
0x00f0: { n:"SxRule" },
17457
0x00f1: { n:"SXEx" },
17458
0x00f2: { n:"SxFilt" },
17459
0x00f4: { n:"SxDXF" },
17460
0x00f5: { n:"SxItm" },
17461
0x00f6: { n:"SxName" },
17462
0x00f7: { n:"SxSelect" },
17463
0x00f8: { n:"SXPair" },
17464
0x00f9: { n:"SxFmla" },
17465
0x00fb: { n:"SxFormat" },
17466
0x00fc: { n:"SST", f:parse_SST },
17467
0x00fd: { n:"LabelSst", f:parse_LabelSst },
17468
0x00ff: { n:"ExtSST", f:parse_ExtSST },
17469
0x0100: { n:"SXVDEx" },
17470
0x0103: { n:"SXFormula" },
17471
0x0122: { n:"SXDBEx" },
17472
0x0137: { n:"RRDInsDel" },
17473
0x0138: { n:"RRDHead" },
17474
0x013b: { n:"RRDChgCell" },
17475
0x013d: { n:"RRTabId", f:parseuint16a },
17476
0x013e: { n:"RRDRenSheet" },
17477
0x013f: { n:"RRSort" },
17478
0x0140: { n:"RRDMove" },
17479
0x014a: { n:"RRFormat" },
17480
0x014b: { n:"RRAutoFmt" },
17481
0x014d: { n:"RRInsertSh" },
17482
0x014e: { n:"RRDMoveBegin" },
17483
0x014f: { n:"RRDMoveEnd" },
17484
0x0150: { n:"RRDInsDelBegin" },
17485
0x0151: { n:"RRDInsDelEnd" },
17486
0x0152: { n:"RRDConflict" },
17487
0x0153: { n:"RRDDefName" },
17488
0x0154: { n:"RRDRstEtxp" },
17489
0x015f: { n:"LRng" },
17490
0x0160: { n:"UsesELFs", f:parsebool },
17491
0x0161: { n:"DSF", f:parsenoop2 },
17492
0x0191: { n:"CUsr" },
17493
0x0192: { n:"CbUsr" },
17494
0x0193: { n:"UsrInfo" },
17495
0x0194: { n:"UsrExcl" },
17496
0x0195: { n:"FileLock" },
17497
0x0196: { n:"RRDInfo" },
17498
0x0197: { n:"BCUsrs" },
17499
0x0198: { n:"UsrChk" },
17500
0x01a9: { n:"UserBView" },
17501
0x01aa: { n:"UserSViewBegin" },
17502
0x01ab: { n:"UserSViewEnd" },
17503
0x01ac: { n:"RRDUserView" },
17504
0x01ad: { n:"Qsi" },
17505
0x01ae: { n:"SupBook", f:parse_SupBook },
17506
0x01af: { n:"Prot4Rev", f:parsebool },
17507
0x01b0: { n:"CondFmt" },
17508
0x01b1: { n:"CF" },
17509
0x01b2: { n:"DVal" },
17510
0x01b5: { n:"DConBin" },
17511
0x01b6: { n:"TxO", f:parse_TxO },
17512
0x01b7: { n:"RefreshAll", f:parsebool },
17513
0x01b8: { n:"HLink", f:parse_HLink },
17514
0x01b9: { n:"Lel" },
17515
0x01ba: { n:"CodeName", f:parse_XLUnicodeString },
17516
0x01bb: { n:"SXFDBType" },
17517
0x01bc: { n:"Prot4RevPass", f:parseuint16 },
17518
0x01bd: { n:"ObNoMacros" },
17519
0x01be: { n:"Dv" },
17520
0x01c0: { n:"Excel9File", f:parsenoop2 },
17521
0x01c1: { n:"RecalcId", f:parse_RecalcId, r:2},
17522
0x01c2: { n:"EntExU2", f:parsenoop2 },
17523
0x0200: { n:"Dimensions", f:parse_Dimensions },
17524
0x0201: { n:"Blank", f:parse_Blank },
17525
0x0203: { n:"Number", f:parse_Number },
17526
0x0204: { n:"Label", f:parse_Label },
17527
0x0205: { n:"BoolErr", f:parse_BoolErr },
17528
0x0206: { n:"Formula", f:parse_Formula },
17529
0x0207: { n:"String", f:parse_String },
17530
0x0208: { n:'Row', f:parse_Row },
17531
0x020b: { n:"Index" },
17532
0x0221: { n:"Array", f:parse_Array },
17533
0x0225: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
17534
0x0236: { n:"Table" },
17535
0x023e: { n:"Window2", f:parse_Window2 },
17536
0x027e: { n:"RK", f:parse_RK },
17537
0x0293: { n:"Style" },
17538
0x0406: { n:"Formula", f:parse_Formula },
17539
0x0418: { n:"BigName" },
17540
0x041e: { n:"Format", f:parse_Format },
17541
0x043c: { n:"ContinueBigName" },
17542
0x04bc: { n:"ShrFmla", f:parse_ShrFmla },
17543
0x0800: { n:"HLinkTooltip", f:parse_HLinkTooltip },
17544
0x0801: { n:"WebPub" },
17545
0x0802: { n:"QsiSXTag" },
17546
0x0803: { n:"DBQueryExt" },
17547
0x0804: { n:"ExtString" },
17548
0x0805: { n:"TxtQry" },
17549
0x0806: { n:"Qsir" },
17550
0x0807: { n:"Qsif" },
17551
0x0808: { n:"RRDTQSIF" },
17552
0x0809: { n:'BOF', f:parse_BOF },
17553
0x080a: { n:"OleDbConn" },
17554
0x080b: { n:"WOpt" },
17555
0x080c: { n:"SXViewEx" },
17556
0x080d: { n:"SXTH" },
17557
0x080e: { n:"SXPIEx" },
17558
0x080f: { n:"SXVDTEx" },
17559
0x0810: { n:"SXViewEx9" },
17560
0x0812: { n:"ContinueFrt" },
17561
0x0813: { n:"RealTimeData" },
17562
0x0850: { n:"ChartFrtInfo" },
17563
0x0851: { n:"FrtWrapper" },
17564
0x0852: { n:"StartBlock" },
17565
0x0853: { n:"EndBlock" },
17566
0x0854: { n:"StartObject" },
17567
0x0855: { n:"EndObject" },
17568
0x0856: { n:"CatLab" },
17569
0x0857: { n:"YMult" },
17570
0x0858: { n:"SXViewLink" },
17571
0x0859: { n:"PivotChartBits" },
17572
0x085a: { n:"FrtFontList" },
17573
0x0862: { n:"SheetExt" },
17574
0x0863: { n:"BookExt", r:12},
17575
0x0864: { n:"SXAddl" },
17576
0x0865: { n:"CrErr" },
17577
0x0866: { n:"HFPicture" },
17578
0x0867: { n:'FeatHdr', f:parsenoop2 },
17579
0x0868: { n:"Feat" },
17580
0x086a: { n:"DataLabExt" },
17581
0x086b: { n:"DataLabExtContents" },
17582
0x086c: { n:"CellWatch" },
17583
0x0871: { n:"FeatHdr11" },
17584
0x0872: { n:"Feature11" },
17585
0x0874: { n:"DropDownObjIds" },
17586
0x0875: { n:"ContinueFrt11" },
17587
0x0876: { n:"DConn" },
17588
0x0877: { n:"List12" },
17589
0x0878: { n:"Feature12" },
17590
0x0879: { n:"CondFmt12" },
17591
0x087a: { n:"CF12" },
17592
0x087b: { n:"CFEx" },
17593
0x087c: { n:"XFCRC", f:parse_XFCRC, r:12 },
17594
0x087d: { n:"XFExt", f:parse_XFExt, r:12 },
17595
0x087e: { n:"AutoFilter12" },
17596
0x087f: { n:"ContinueFrt12" },
17597
0x0884: { n:"MDTInfo" },
17598
0x0885: { n:"MDXStr" },
17599
0x0886: { n:"MDXTuple" },
17600
0x0887: { n:"MDXSet" },
17601
0x0888: { n:"MDXProp" },
17602
0x0889: { n:"MDXKPI" },
17603
0x088a: { n:"MDB" },
17604
0x088b: { n:"PLV" },
17605
0x088c: { n:"Compat12", f:parsebool, r:12 },
17606
0x088d: { n:"DXF" },
17607
0x088e: { n:"TableStyles", r:12 },
17608
0x088f: { n:"TableStyle" },
17609
0x0890: { n:"TableStyleElement" },
17610
0x0892: { n:"StyleExt" },
17611
0x0893: { n:"NamePublish" },
17612
0x0894: { n:"NameCmt", f:parse_NameCmt, r:12 },
17613
0x0895: { n:"SortData" },
17614
0x0896: { n:"Theme", f:parse_Theme, r:12 },
17615
0x0897: { n:"GUIDTypeLib" },
17616
0x0898: { n:"FnGrp12" },
17617
0x0899: { n:"NameFnGrp12" },
17618
0x089a: { n:"MTRSettings", f:parse_MTRSettings, r:12 },
17619
0x089b: { n:"CompressPictures", f:parsenoop2 },
17620
0x089c: { n:"HeaderFooter" },
17621
0x089d: { n:"CrtLayout12" },
17622
0x089e: { n:"CrtMlFrt" },
17623
0x089f: { n:"CrtMlFrtContinue" },
17624
0x08a3: { n:"ForceFullCalculation", f:parse_ForceFullCalculation },
17625
0x08a4: { n:"ShapePropsStream" },
17626
0x08a5: { n:"TextPropsStream" },
17627
0x08a6: { n:"RichTextStream" },
17628
0x08a7: { n:"CrtLayout12A" },
17629
0x1001: { n:"Units" },
17630
0x1002: { n:"Chart" },
17631
0x1003: { n:"Series" },
17632
0x1006: { n:"DataFormat" },
17633
0x1007: { n:"LineFormat" },
17634
0x1009: { n:"MarkerFormat" },
17635
0x100a: { n:"AreaFormat" },
17636
0x100b: { n:"PieFormat" },
17637
0x100c: { n:"AttachedLabel" },
17638
0x100d: { n:"SeriesText" },
17639
0x1014: { n:"ChartFormat" },
17640
0x1015: { n:"Legend" },
17641
0x1016: { n:"SeriesList" },
17642
0x1017: { n:"Bar" },
17643
0x1018: { n:"Line" },
17644
0x1019: { n:"Pie" },
17645
0x101a: { n:"Area" },
17646
0x101b: { n:"Scatter" },
17647
0x101c: { n:"CrtLine" },
17648
0x101d: { n:"Axis" },
17649
0x101e: { n:"Tick" },
17650
0x101f: { n:"ValueRange" },
17651
0x1020: { n:"CatSerRange" },
17652
0x1021: { n:"AxisLine" },
17653
0x1022: { n:"CrtLink" },
17654
0x1024: { n:"DefaultText" },
17655
0x1025: { n:"Text" },
17656
0x1026: { n:"FontX", f:parseuint16 },
17657
0x1027: { n:"ObjectLink" },
17658
0x1032: { n:"Frame" },
17659
0x1033: { n:"Begin" },
17660
0x1034: { n:"End" },
17661
0x1035: { n:"PlotArea" },
17662
0x103a: { n:"Chart3d" },
17663
0x103c: { n:"PicF" },
17664
0x103d: { n:"DropBar" },
17665
0x103e: { n:"Radar" },
17666
0x103f: { n:"Surf" },
17667
0x1040: { n:"RadarArea" },
17668
0x1041: { n:"AxisParent" },
17669
0x1043: { n:"LegendException" },
17670
0x1044: { n:"ShtProps", f:parse_ShtProps },
17671
0x1045: { n:"SerToCrt" },
17672
0x1046: { n:"AxesUsed" },
17673
0x1048: { n:"SBaseRef" },
17674
0x104a: { n:"SerParent" },
17675
0x104b: { n:"SerAuxTrend" },
17676
0x104e: { n:"IFmtRecord" },
17677
0x104f: { n:"Pos" },
17678
0x1050: { n:"AlRuns" },
17679
0x1051: { n:"BRAI" },
17680
0x105b: { n:"SerAuxErrBar" },
17681
0x105c: { n:"ClrtClient", f:parse_ClrtClient },
17682
0x105d: { n:"SerFmt" },
17683
0x105f: { n:"Chart3DBarShape" },
17684
0x1060: { n:"Fbi" },
17685
0x1061: { n:"BopPop" },
17686
0x1062: { n:"AxcExt" },
17687
0x1063: { n:"Dat" },
17688
0x1064: { n:"PlotGrowth" },
17689
0x1065: { n:"SIIndex" },
17690
0x1066: { n:"GelFrame" },
17691
0x1067: { n:"BopPopCustom" },
17692
0x1068: { n:"Fbi2" },
17693
17694
0x0000: { n:"Dimensions", f:parse_Dimensions },
17695
0x0002: { n:"BIFF2INT", f:parse_BIFF2INT },
17696
0x0005: { n:"BoolErr", f:parse_BoolErr },
17697
0x0007: { n:"String", f:parse_BIFF2STRING },
17698
0x0008: { n:"BIFF2ROW" },
17699
0x000b: { n:"Index" },
17700
0x0016: { n:"ExternCount", f:parseuint16 },
17701
0x001e: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
17702
0x001f: { n:"BIFF2FMTCNT" }, /* 16-bit cnt of BIFF2FORMAT records */
17703
0x0020: { n:"BIFF2COLINFO" },
17704
0x0021: { n:"Array", f:parse_Array },
17705
0x0025: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
17706
0x0032: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
17707
0x0034: { n:"DDEObjName" },
17708
0x003e: { n:"BIFF2WINDOW2" },
17709
0x0043: { n:"BIFF2XF" },
17710
0x0045: { n:"BIFF2FONTCLR" },
17711
0x0056: { n:"BIFF4FMTCNT" }, /* 16-bit cnt, similar to BIFF2 */
17712
0x007e: { n:"RK" }, /* Not necessarily same as 0x027e */
17713
0x007f: { n:"ImData", f:parse_ImData },
17714
0x0087: { n:"Addin" },
17715
0x0088: { n:"Edg" },
17716
0x0089: { n:"Pub" },
17717
0x0091: { n:"Sub" },
17718
0x0094: { n:"LHRecord" },
17719
0x0095: { n:"LHNGraph" },
17720
0x0096: { n:"Sound" },
17721
0x00a9: { n:"CoordList" },
17722
0x00ab: { n:"GCW" },
17723
0x00bc: { n:"ShrFmla" }, /* Not necessarily same as 0x04bc */
17724
0x00bf: { n:"ToolbarHdr" },
17725
0x00c0: { n:"ToolbarEnd" },
17726
0x00c2: { n:"AddMenu" },
17727
0x00c3: { n:"DelMenu" },
17728
0x00d6: { n:"RString", f:parse_RString },
17729
0x00df: { n:"UDDesc" },
17730
0x00ea: { n:"TabIdConf" },
17731
0x0162: { n:"XL5Modify" },
17732
0x01a5: { n:"FileSharing2" },
17733
0x0209: { n:'BOF', f:parse_BOF },
17734
0x0218: { n:"Lbl", f:parse_Lbl },
17735
0x0223: { n:"ExternName", f:parse_ExternName },
17736
0x0231: { n:"Font" },
17737
0x0243: { n:"BIFF3XF" },
17738
0x0409: { n:'BOF', f:parse_BOF },
17739
0x0443: { n:"BIFF4XF" },
17740
0x086d: { n:"FeatInfo" },
17741
0x0873: { n:"FeatInfo11" },
17742
0x0881: { n:"SXAddl12" },
17743
0x08c0: { n:"AutoWebPub" },
17744
0x08c1: { n:"ListObj" },
17745
0x08c2: { n:"ListField" },
17746
0x08c3: { n:"ListDV" },
17747
0x08c4: { n:"ListCondFmt" },
17748
0x08c5: { n:"ListCF" },
17749
0x08c6: { n:"FMQry" },
17750
0x08c7: { n:"FMSQry" },
17751
0x08c8: { n:"PLV" },
17752
0x08c9: { n:"LnExt" },
17753
0x08ca: { n:"MkrExt" },
17754
0x08cb: { n:"CrtCoopt" },
17755
0x08d6: { n:"FRTArchId$", r:12 },
17756
17757
0x7262: {}
17758
};
17759
17760
var XLSRE = evert_key(XLSRecordEnum, 'n');
17761
function write_biff_rec(ba, type, payload, length) {
17762
	var t = +type || +XLSRE[type];
17763
	if(isNaN(t)) return;
17764
	var len = length || (payload||[]).length || 0;
17765
	var o = ba.next(4);
17766
	o.write_shift(2, t);
17767
	o.write_shift(2, len);
17768
	if(len > 0 && is_buf(payload)) ba.push(payload);
17769
}
17770
17771
function write_BIFF2Cell(out, r, c) {
17772
	if(!out) out = new_buf(7);
17773
	out.write_shift(2, r);
17774
	out.write_shift(2, c);
17775
	out.write_shift(2, 0);
17776
	out.write_shift(1, 0);
17777
	return out;
17778
}
17779
17780
function write_BIFF2BERR(r, c, val, t) {
17781
	var out = new_buf(9);
17782
	write_BIFF2Cell(out, r, c);
17783
	if(t == 'e') { out.write_shift(1, val); out.write_shift(1, 1); }
17784
	else { out.write_shift(1, val?1:0); out.write_shift(1, 0); }
17785
	return out;
17786
}
17787
17788
/* TODO: codepage, large strings */
17789
function write_BIFF2LABEL(r, c, val) {
17790
	var out = new_buf(8 + 2*val.length);
17791
	write_BIFF2Cell(out, r, c);
17792
	out.write_shift(1, val.length);
17793
	out.write_shift(val.length, val, 'sbcs');
17794
	return out.l < out.length ? out.slice(0, out.l) : out;
17795
}
17796
17797
function write_ws_biff2_cell(ba, cell, R, C) {
17798
	if(cell.v != null) switch(cell.t) {
17799
		case 'd': case 'n':
17800
			var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
17801
			if((v == (v|0)) && (v >= 0) && (v < 65536))
17802
				write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
17803
			else
17804
				write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
17805
			return;
17806
		case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
17807
		/* TODO: codepage, sst */
17808
		case 's': case 'str':
17809
			write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v));
17810
			return;
17811
	}
17812
	write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
17813
}
17814
17815
function write_ws_biff2(ba, ws, idx, opts) {
17816
	var dense = Array.isArray(ws);
17817
	var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
17818
	if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
17819
		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
17820
		range.e.c = Math.min(range.e.c, 0xFF);
17821
		range.e.r = Math.min(range.e.c, 0x3FFF);
17822
		ref = encode_range(range);
17823
	}
17824
	for(var R = range.s.r; R <= range.e.r; ++R) {
17825
		rr = encode_row(R);
17826
		for(var C = range.s.c; C <= range.e.c; ++C) {
17827
			if(R === range.s.r) cols[C] = encode_col(C);
17828
			ref = cols[C] + rr;
17829
			var cell = dense ? (ws[R]||[])[C] : ws[ref];
17830
			if(!cell) continue;
17831
			/* write cell */
17832
			write_ws_biff2_cell(ba, cell, R, C, opts);
17833
		}
17834
	}
17835
}
17836
17837
/* Based on test files */
17838
function write_biff2_buf(wb, opts) {
17839
	var o = opts || {};
17840
	if(DENSE != null && o.dense == null) o.dense = DENSE;
17841
	var ba = buf_array();
17842
	var idx = 0;
17843
	for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
17844
	if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
17845
	write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o));
17846
	/* ... */
17847
	write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
17848
	/* ... */
17849
	write_biff_rec(ba, 0x000A);
17850
	return ba.end();
17851
}
17852
17853
function write_FONTS_biff8(ba, data, opts) {
17854
	write_biff_rec(ba, "Font", write_Font({
17855
		sz:12,
17856
		color: {theme:1},
17857
		name: "Arial",
17858
		family: 2,
17859
		scheme: "minor"
17860
	}, opts));
17861
}
17862
17863
17864
function write_FMTS_biff8(ba, NF, opts) {
17865
	if(!NF) return;
17866
	[[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
17867
for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts));
17868
	});
17869
}
17870
17871
function write_FEAT(ba, ws) {
17872
	/* [MS-XLS] 2.4.112 */
17873
	var o = new_buf(19);
17874
	o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
17875
	o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
17876
	write_biff_rec(ba, "FeatHdr", o);
17877
	/* [MS-XLS] 2.4.111 */
17878
	o = new_buf(39);
17879
	o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0);
17880
	o.write_shift(2, 3); o.write_shift(1, 0); o.write_shift(4, 0);
17881
	o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0);
17882
	write_Ref8U(safe_decode_range(ws['!ref']||"A1"), o);
17883
	o.write_shift(4, 4);
17884
	write_biff_rec(ba, "Feat", o);
17885
}
17886
17887
function write_CELLXFS_biff8(ba, opts) {
17888
	for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts));
17889
	opts.cellXfs.forEach(function(c) {
17890
		write_biff_rec(ba, "XF", write_XF(c, 0, opts));
17891
	});
17892
}
17893
17894
function write_ws_biff8_hlinks(ba, ws) {
17895
	for(var R=0; R<ws['!links'].length; ++R) {
17896
		var HL = ws['!links'][R];
17897
		write_biff_rec(ba, "HLink", write_HLink(HL));
17898
		if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
17899
	}
17900
	delete ws['!links'];
17901
}
17902
17903
function write_ws_biff8_cell(ba, cell, R, C, opts) {
17904
	var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
17905
	if(cell.v != null) switch(cell.t) {
17906
		case 'd': case 'n':
17907
			var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
17908
			/* TODO: emit RK as appropriate */
17909
			write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts));
17910
			return;
17911
		case 'b': case 'e': write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t)); return;
17912
		/* TODO: codepage, sst */
17913
		case 's': case 'str':
17914
			write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts));
17915
			return;
17916
	}
17917
	write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
17918
}
17919
17920
/* [MS-XLS] 2.1.7.20.5 */
17921
function write_ws_biff8(idx, opts, wb) {
17922
	var ba = buf_array();
17923
	var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
17924
	var _WB = ((wb||{}).Workbook||{});
17925
	var _sheet = ((_WB.Sheets||[])[idx]||{});
17926
	var dense = Array.isArray(ws);
17927
	var b8 = opts.biff == 8;
17928
	var ref, rr = "", cols = [];
17929
	var range = safe_decode_range(ws['!ref'] || "A1");
17930
	var MAX_ROWS = b8 ? 65536 : 16384;
17931
	if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
17932
		if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
17933
		range.e.c = Math.min(range.e.c, 0xFF);
17934
		range.e.r = Math.min(range.e.c, MAX_ROWS-1);
17935
	}
17936
17937
	write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
17938
	/* ... */
17939
	write_biff_rec(ba, "CalcMode", writeuint16(1));
17940
	write_biff_rec(ba, "CalcCount", writeuint16(100));
17941
	write_biff_rec(ba, "CalcRefMode", writebool(true));
17942
	write_biff_rec(ba, "CalcIter", writebool(false));
17943
	write_biff_rec(ba, "CalcDelta", write_Xnum(0.001));
17944
	write_biff_rec(ba, "CalcSaveRecalc", writebool(true));
17945
	write_biff_rec(ba, "PrintRowCol", writebool(false));
17946
	write_biff_rec(ba, "PrintGrid", writebool(false));
17947
	write_biff_rec(ba, "GridSet", writeuint16(1));
17948
	write_biff_rec(ba, "Guts", write_Guts([0,0]));
17949
	/* ... */
17950
	write_biff_rec(ba, "HCenter", writebool(false));
17951
	write_biff_rec(ba, "VCenter", writebool(false));
17952
	/* ... */
17953
	write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
17954
	/* ... */
17955
17956
	if(b8) ws['!links'] = [];
17957
	for(var R = range.s.r; R <= range.e.r; ++R) {
17958
		rr = encode_row(R);
17959
		for(var C = range.s.c; C <= range.e.c; ++C) {
17960
			if(R === range.s.r) cols[C] = encode_col(C);
17961
			ref = cols[C] + rr;
17962
			var cell = dense ? (ws[R]||[])[C] : ws[ref];
17963
			if(!cell) continue;
17964
			/* write cell */
17965
			write_ws_biff8_cell(ba, cell, R, C, opts);
17966
			if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
17967
		}
17968
	}
17969
	var cname = _sheet.CodeName || _sheet.name || s;
17970
	/* ... */
17971
	if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0]));
17972
	/* ... */
17973
	if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']));
17974
	/* ... */
17975
	if(b8) write_ws_biff8_hlinks(ba, ws);
17976
	/* ... */
17977
	write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
17978
	/* ... */
17979
	if(b8) write_FEAT(ba, ws);
17980
	/* ... */
17981
	write_biff_rec(ba, "EOF");
17982
	return ba.end();
17983
}
17984
17985
/* [MS-XLS] 2.1.7.20.3 */
17986
function write_biff8_global(wb, bufs, opts) {
17987
	var A = buf_array();
17988
	var _WB = ((wb||{}).Workbook||{});
17989
	var _sheets = (_WB.Sheets||[]);
17990
	var _wb = _WB.WBProps||{};
17991
	var b8 = opts.biff == 8, b5 = opts.biff == 5;
17992
	write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
17993
	if(opts.bookType == "xla") write_biff_rec(A, "Addin");
17994
	write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null);
17995
	write_biff_rec(A, "Mms", writezeroes(2));
17996
	if(b5) write_biff_rec(A, "ToolbarHdr");
17997
	if(b5) write_biff_rec(A, "ToolbarEnd");
17998
	write_biff_rec(A, "InterfaceEnd");
17999
	write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
18000
	write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4));
18001
	if(b8) write_biff_rec(A, "DSF", writeuint16(0));
18002
	if(b8) write_biff_rec(A, "Excel9File");
18003
	write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
18004
	if(b8 && wb.vbaraw) {
18005
		write_biff_rec(A, "ObProj");
18006
		var cname = _wb.CodeName || "ThisWorkbook";
18007
		write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts));
18008
	}
18009
	write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11));
18010
	write_biff_rec(A, "WinProtect", writebool(false));
18011
	write_biff_rec(A, "Protect", writebool(false));
18012
	write_biff_rec(A, "Password", writeuint16(0));
18013
	if(b8) write_biff_rec(A, "Prot4Rev", writebool(false));
18014
	if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0));
18015
	write_biff_rec(A, "Window1", write_Window1(opts));
18016
	write_biff_rec(A, "Backup", writebool(false));
18017
	write_biff_rec(A, "HideObj", writeuint16(0));
18018
	write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true"));
18019
	write_biff_rec(A, "CalcPrecision", writebool(true));
18020
	if(b8) write_biff_rec(A, "RefreshAll", writebool(false));
18021
	write_biff_rec(A, "BookBool", writeuint16(0));
18022
	/* ... */
18023
	write_FONTS_biff8(A, wb, opts);
18024
	write_FMTS_biff8(A, wb.SSF, opts);
18025
	write_CELLXFS_biff8(A, opts);
18026
	/* ... */
18027
	if(b8) write_biff_rec(A, "UsesELFs", writebool(false));
18028
	var a = A.end();
18029
18030
	var C = buf_array();
18031
	if(b8) write_biff_rec(C, "Country", write_Country());
18032
	/* BIFF8: [SST *Continue] ExtSST */
18033
	write_biff_rec(C, "EOF");
18034
	var c = C.end();
18035
18036
	var B = buf_array();
18037
	var blen = 0, j = 0;
18038
	for(j = 0; j < wb.SheetNames.length; ++j) blen += (b8 ? 12 : 11) + (b8 ? 2 : 1) * wb.SheetNames[j].length;
18039
	var start = a.length + blen + c.length;
18040
	for(j = 0; j < wb.SheetNames.length; ++j) {
18041
		var _sheet = _sheets[j] || ({});
18042
		write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts));
18043
		start += bufs[j].length;
18044
	}
18045
	/* 1*BoundSheet8 */
18046
	var b = B.end();
18047
	if(blen != b.length) throw new Error("BS8 " + blen + " != " + b.length);
18048
18049
	var out = [];
18050
	if(a.length) out.push(a);
18051
	if(b.length) out.push(b);
18052
	if(c.length) out.push(c);
18053
	return __toBuffer([out]);
18054
}
18055
18056
/* [MS-XLS] 2.1.7.20 Workbook Stream */
18057
function write_biff8_buf(wb, opts) {
18058
	var o = opts || {};
18059
	var bufs = [];
18060
18061
	if(wb && !wb.SSF) {
18062
		wb.SSF = SSF.get_table();
18063
	}
18064
	if(wb && wb.SSF) {
18065
		make_ssf(SSF); SSF.load_table(wb.SSF);
18066
		// $FlowIgnore
18067
		o.revssf = evert_num(wb.SSF); o.revssf[wb.SSF[65535]] = 0;
18068
		o.ssf = wb.SSF;
18069
	}
18070
	o.cellXfs = [];
18071
	o.Strings = []; o.Strings.Count = 0; o.Strings.Unique = 0;
18072
	get_cell_style(o.cellXfs, {}, {revssf:{"General":0}});
18073
18074
	for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb);
18075
	bufs.unshift(write_biff8_global(wb, bufs, o));
18076
	return __toBuffer([bufs]);
18077
}
18078
18079
function write_biff_buf(wb, opts) {
18080
	var o = opts || {};
18081
	switch(o.biff || 2) {
18082
		case 8: case 5: return write_biff8_buf(wb, opts);
18083
		case 4: case 3: case 2: return write_biff2_buf(wb, opts);
18084
	}
18085
	throw new Error("invalid type " + o.bookType + " for BIFF");
18086
}
18087
/* note: browser DOM element cannot see mso- style attrs, must parse */
18088
var HTML_ = (function() {
18089
	function html_to_sheet(str, _opts) {
18090
		var opts = _opts || {};
18091
		if(DENSE != null && opts.dense == null) opts.dense = DENSE;
18092
		var ws = opts.dense ? ([]) : ({});
18093
		var mtch = str.match(/<table/i);
18094
		if(!mtch) throw new Error("Invalid HTML: could not find <table>");
18095
		var mtch2 = str.match(/<\/table/i);
18096
		var i = mtch.index, j = mtch2 && mtch2.index || str.length;
18097
		var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
18098
		var R = -1, C = 0, RS = 0, CS = 0;
18099
		var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
18100
		var merges = [];
18101
		for(i = 0; i < rows.length; ++i) {
18102
			var row = rows[i].trim();
18103
			var hd = row.slice(0,3).toLowerCase();
18104
			if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
18105
			if(hd != "<td" && hd != "<th") continue;
18106
			var cells = row.split(/<\/t[dh]>/i);
18107
			for(j = 0; j < cells.length; ++j) {
18108
				var cell = cells[j].trim();
18109
				if(!cell.match(/<t[dh]/i)) continue;
18110
				var m = cell, cc = 0;
18111
				/* TODO: parse styles etc */
18112
				while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
18113
				var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
18114
				CS = tag.colspan ? +tag.colspan : 1;
18115
				if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
18116
				var _t = tag.t || "";
18117
				/* TODO: generate stub cells */
18118
				if(!m.length) { C += CS; continue; }
18119
				m = htmldecode(m);
18120
				if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
18121
				if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
18122
				if(!m.length) continue;
18123
				var o = {t:'s', v:m};
18124
				if(opts.raw || !m.trim().length || _t == 's'){}
18125
				else if(m === 'TRUE') o = {t:'b', v:true};
18126
				else if(m === 'FALSE') o = {t:'b', v:false};
18127
				else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
18128
				else if(!isNaN(fuzzydate(m).getDate())) {
18129
					o = ({t:'d', v:parseDate(m)});
18130
					if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
18131
					o.z = opts.dateNF || SSF._table[14];
18132
				}
18133
				if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
18134
				else ws[encode_cell({r:R, c:C})] = o;
18135
				C += CS;
18136
			}
18137
		}
18138
		ws['!ref'] = encode_range(range);
18139
		return ws;
18140
	}
18141
	function html_to_book(str, opts) {
18142
		return sheet_to_workbook(html_to_sheet(str, opts), opts);
18143
	}
18144
	function make_html_row(ws, r, R, o) {
18145
		var M = (ws['!merges'] ||[]);
18146
		var oo = [];
18147
		for(var C = r.s.c; C <= r.e.c; ++C) {
18148
			var RS = 0, CS = 0;
18149
			for(var j = 0; j < M.length; ++j) {
18150
				if(M[j].s.r > R || M[j].s.c > C) continue;
18151
				if(M[j].e.r < R || M[j].e.c < C) continue;
18152
				if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
18153
				RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
18154
			}
18155
			if(RS < 0) continue;
18156
			var coord = encode_cell({r:R,c:C});
18157
			var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
18158
			var sp = {};
18159
			if(RS > 1) sp.rowspan = RS;
18160
			if(CS > 1) sp.colspan = CS;
18161
			/* TODO: html entities */
18162
			var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
18163
			sp.t = cell && cell.t || 'z';
18164
			if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
18165
			sp.id = "sjs-" + coord;
18166
			oo.push(writextag('td', w, sp));
18167
		}
18168
		var preamble = "<tr>";
18169
		return preamble + oo.join("") + "</tr>";
18170
	}
18171
	function make_html_preamble(ws, R, o) {
18172
		var out = [];
18173
		return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
18174
	}
18175
	var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
18176
	var _END = '</body></html>';
18177
	function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
18178
		var o = opts || {};
18179
		var header = o.header != null ? o.header : _BEGIN;
18180
		var footer = o.footer != null ? o.footer : _END;
18181
		var out = [header];
18182
		var r = decode_range(ws['!ref']);
18183
		o.dense = Array.isArray(ws);
18184
		out.push(make_html_preamble(ws, r, o));
18185
		for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
18186
		out.push("</table>" + footer);
18187
		return out.join("");
18188
	}
18189
18190
	return {
18191
		to_workbook: html_to_book,
18192
		to_sheet: html_to_sheet,
18193
		_row: make_html_row,
18194
		BEGIN: _BEGIN,
18195
		END: _END,
18196
		_preamble: make_html_preamble,
18197
		from_sheet: sheet_to_html
18198
	};
18199
})();
18200
18201
function parse_dom_table(table, _opts) {
18202
	var opts = _opts || {};
18203
	if(DENSE != null) opts.dense = DENSE;
18204
	var ws = opts.dense ? ([]) : ({});
18205
	var rows = table.getElementsByTagName('tr');
18206
	var sheetRows = opts.sheetRows || 10000000;
18207
	var range = {s:{r:0,c:0},e:{r:0,c:0}};
18208
	var merges = [], midx = 0;
18209
	var rowinfo = [];
18210
	var _R = 0, R = 0, _C, C, RS, CS;
18211
	for(; _R < rows.length && R < sheetRows; ++_R) {
18212
		var row = rows[_R];
18213
		if (is_dom_element_hidden(row)) {
18214
			if (opts.display) continue;
18215
			rowinfo[R] = {hidden: true};
18216
		}
18217
		var elts = (row.children);
18218
		for(_C = C = 0; _C < elts.length; ++_C) {
18219
			var elt = elts[_C];
18220
			if (opts.display && is_dom_element_hidden(elt)) continue;
18221
			var v = htmldecode(elt.innerHTML);
18222
			for(midx = 0; midx < merges.length; ++midx) {
18223
				var m = merges[midx];
18224
				if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
18225
			}
18226
			/* TODO: figure out how to extract nonstandard mso- style */
18227
			CS = +elt.getAttribute("colspan") || 1;
18228
			if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
18229
			var o = {t:'s', v:v};
18230
			var _t = elt.getAttribute("t") || "";
18231
			if(v != null) {
18232
				if(v.length == 0) o.t = _t || 'z';
18233
				else if(opts.raw || v.trim().length == 0 || _t == "s"){}
18234
				else if(v === 'TRUE') o = {t:'b', v:true};
18235
				else if(v === 'FALSE') o = {t:'b', v:false};
18236
				else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
18237
				else if(!isNaN(fuzzydate(v).getDate())) {
18238
					o = ({t:'d', v:parseDate(v)});
18239
					if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
18240
					o.z = opts.dateNF || SSF._table[14];
18241
				}
18242
			}
18243
			if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
18244
			else ws[encode_cell({c:C, r:R})] = o;
18245
			if(range.e.c < C) range.e.c = C;
18246
			C += CS;
18247
		}
18248
		++R;
18249
	}
18250
	if(merges.length) ws['!merges'] = merges;
18251
	if(rowinfo.length) ws['!rows'] = rowinfo;
18252
	range.e.r = R - 1;
18253
	ws['!ref'] = encode_range(range);
18254
	if(R >= sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1,range)); // We can count the real number of rows to parse but we don't to improve the performance
18255
	return ws;
18256
}
18257
18258
function table_to_book(table, opts) {
18259
	return sheet_to_workbook(parse_dom_table(table, opts), opts);
18260
}
18261
18262
function is_dom_element_hidden(element) {
18263
	var display = '';
18264
	var get_computed_style = get_get_computed_style_function(element);
18265
	if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
18266
	if(!display) display = element.style.display; // Fallback for cases when getComputedStyle is not available (e.g. an old browser or some Node.js environments) or doesn't work (e.g. if the element is not inserted to a document)
18267
	return display === 'none';
18268
}
18269
18270
/* global getComputedStyle */
18271
function get_get_computed_style_function(element) {
18272
	// The proper getComputedStyle implementation is the one defined in the element window
18273
	if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
18274
	// If it is not available, try to get one from the global namespace
18275
	if(typeof getComputedStyle === 'function') return getComputedStyle;
18276
	return null;
18277
}
18278
/* OpenDocument */
18279
var parse_content_xml = (function() {
18280
18281
	/* 6.1.2 White Space Characters */
18282
	var parse_text_p = function(text) {
18283
		return unescapexml(text
18284
			.replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
18285
			.replace(/<text:s\/>/g," ")
18286
			.replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
18287
			.replace(/<text:tab[^>]*\/>/g,"\t")
18288
			.replace(/<text:line-break\/>/g,"\n")
18289
			.replace(/<[^>]*>/g,"")
18290
		);
18291
	};
18292
18293
	var number_formats = {
18294
		/* ods name: [short ssf fmt, long ssf fmt] */
18295
		day:           ["d",   "dd"],
18296
		month:         ["m",   "mm"],
18297
		year:          ["y",   "yy"],
18298
		hours:         ["h",   "hh"],
18299
		minutes:       ["m",   "mm"],
18300
		seconds:       ["s",   "ss"],
18301
		"am-pm":       ["A/P", "AM/PM"],
18302
		"day-of-week": ["ddd", "dddd"],
18303
		era:           ["e",   "ee"],
18304
		/* there is no native representation of LO "Q" format */
18305
		quarter:       ["\\Qm", "m\\\"th quarter\""]
18306
	};
18307
18308
	return function pcx(d, _opts) {
18309
		var opts = _opts || {};
18310
		if(DENSE != null && opts.dense == null) opts.dense = DENSE;
18311
		var str = xlml_normalize(d);
18312
		var state = [], tmp;
18313
		var tag;
18314
		var NFtag = {name:""}, NF = "", pidx = 0;
18315
		var sheetag;
18316
		var rowtag;
18317
		var Sheets = {}, SheetNames = [];
18318
		var ws = opts.dense ? ([]) : ({});
18319
		var Rn, q;
18320
		var ctag = ({value:""});
18321
		var textp = "", textpidx = 0, textptag;
18322
		var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
18323
		var row_ol = 0;
18324
		var number_format_map = {};
18325
		var merges = [], mrange = {}, mR = 0, mC = 0;
18326
		var rowinfo = [], rowpeat = 1, colpeat = 1;
18327
		var arrayf = [];
18328
		var WB = {Names:[]};
18329
		var atag = ({});
18330
		var _Ref = ["", ""];
18331
		var comments = [], comment = ({});
18332
		var creator = "", creatoridx = 0;
18333
		var isstub = false, intable = false;
18334
		var i = 0;
18335
		xlmlregex.lastIndex = 0;
18336
		str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
18337
		while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
18338
18339
			case 'table': case '工作表': // 9.1.2 <table:table>
18340
				if(Rn[1]==='/') {
18341
					if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
18342
					if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
18343
						ws['!fullref'] = ws['!ref'];
18344
						range.e.r = opts.sheetRows - 1;
18345
						ws['!ref'] = encode_range(range);
18346
					}
18347
					if(merges.length) ws['!merges'] = merges;
18348
					if(rowinfo.length) ws["!rows"] = rowinfo;
18349
					sheetag.name = sheetag['名称'] || sheetag.name;
18350
					if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
18351
					SheetNames.push(sheetag.name);
18352
					Sheets[sheetag.name] = ws;
18353
					intable = false;
18354
				}
18355
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
18356
					sheetag = parsexmltag(Rn[0], false);
18357
					R = C = -1;
18358
					range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
18359
					ws = opts.dense ? ([]) : ({}); merges = [];
18360
					rowinfo = [];
18361
					intable = true;
18362
				}
18363
				break;
18364
18365
			case 'table-row-group': // 9.1.9 <table:table-row-group>
18366
				if(Rn[1] === "/") --row_ol; else ++row_ol;
18367
				break;
18368
			case 'table-row': case '行': // 9.1.3 <table:table-row>
18369
				if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
18370
				rowtag = parsexmltag(Rn[0], false);
18371
				if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
18372
				rowpeat = +rowtag['number-rows-repeated'] || 1;
18373
				/* TODO: remove magic */
18374
				if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
18375
				C = -1; break;
18376
			case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
18377
				++C;
18378
				if(opts.sheetStubs) {
18379
					if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
18380
					else ws[encode_cell({r:R,c:C})] = {t:'z'};
18381
				}
18382
				break; /* stub */
18383
			case 'table-cell': case '数据':
18384
				if(Rn[0].charAt(Rn[0].length-2) === '/') {
18385
					++C;
18386
					ctag = parsexmltag(Rn[0], false);
18387
					colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
18388
					q = ({t:'z', v:null});
18389
					if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
18390
					if((ctag['数据类型'] || ctag['value-type']) == "string") {
18391
						q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
18392
						if(opts.dense) {
18393
							if(!ws[R]) ws[R] = [];
18394
							ws[R][C] = q;
18395
						} else {
18396
							ws[encode_cell({r:R,c:C})] = q;
18397
						}
18398
					}
18399
					C+= colpeat-1;
18400
				} else if(Rn[1]!=='/') {
18401
					++C;
18402
					colpeat = 1;
18403
					var rptR = rowpeat ? R + rowpeat - 1 : R;
18404
					if(C > range.e.c) range.e.c = C;
18405
					if(C < range.s.c) range.s.c = C;
18406
					if(R < range.s.r) range.s.r = R;
18407
					if(rptR > range.e.r) range.e.r = rptR;
18408
					ctag = parsexmltag(Rn[0], false);
18409
					comments = []; comment = ({});
18410
					q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
18411
					if(opts.cellFormula) {
18412
						if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
18413
						if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
18414
							mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
18415
							mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
18416
							mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
18417
							q.F = encode_range(mrange);
18418
							arrayf.push([mrange, q.F]);
18419
						}
18420
						if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
18421
						else for(i = 0; i < arrayf.length; ++i)
18422
							if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
18423
								if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
18424
									q.F = arrayf[i][1];
18425
					}
18426
					if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
18427
						mR = parseInt(ctag['number-rows-spanned'],10) || 0;
18428
						mC = parseInt(ctag['number-columns-spanned'],10) || 0;
18429
						mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
18430
						merges.push(mrange);
18431
					}
18432
18433
					/* 19.675.2 table:number-columns-repeated */
18434
					if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
18435
18436
					/* 19.385 office:value-type */
18437
					switch(q.t) {
18438
						case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
18439
						case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
18440
						case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
18441
						case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
18442
						case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
18443
							if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
18444
							q.z = 'm/d/yy'; break;
18445
						case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
18446
						case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
18447
						default:
18448
							if(q.t === 'string' || q.t === 'text' || !q.t) {
18449
								q.t = 's';
18450
								if(ctag['string-value'] != null) textp = unescapexml(ctag['string-value']);
18451
							} else throw new Error('Unsupported value type ' + q.t);
18452
					}
18453
				} else {
18454
					isstub = false;
18455
					if(q.t === 's') {
18456
						q.v = textp || '';
18457
						isstub = textpidx == 0;
18458
					}
18459
					if(atag.Target) q.l = atag;
18460
					if(comments.length > 0) { q.c = comments; comments = []; }
18461
					if(textp && opts.cellText !== false) q.w = textp;
18462
					if(!isstub || opts.sheetStubs) {
18463
						if(!(opts.sheetRows && opts.sheetRows <= R)) {
18464
							for(var rpt = 0; rpt < rowpeat; ++rpt) {
18465
								colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
18466
								if(opts.dense) {
18467
									if(!ws[R + rpt]) ws[R + rpt] = [];
18468
									ws[R + rpt][C] = rpt == 0 ? q : dup(q);
18469
									while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
18470
								} else {
18471
									ws[encode_cell({r:R + rpt,c:C})] = q;
18472
									while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
18473
								}
18474
								if(range.e.c <= C) range.e.c = C;
18475
							}
18476
						}
18477
					}
18478
					colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
18479
					C += colpeat-1; colpeat = 0;
18480
					q = {};
18481
					textp = "";
18482
				}
18483
				atag = ({});
18484
				break; // 9.1.4 <table:table-cell>
18485
18486
			/* pure state */
18487
			case 'document': // TODO: <office:document> is the root for FODS
18488
			case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
18489
			case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
18490
			case 'scripts': // 3.12 <office:scripts>
18491
			case 'styles': // TODO <office:styles>
18492
			case 'font-face-decls': // 3.14 <office:font-face-decls>
18493
				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
18494
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
18495
				break;
18496
18497
			case 'annotation': // 14.1 <office:annotation>
18498
				if(Rn[1]==='/'){
18499
					if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
18500
					comment.t = textp;
18501
					comment.a = creator;
18502
					comments.push(comment);
18503
				}
18504
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
18505
				creator = ""; creatoridx = 0;
18506
				textp = ""; textpidx = 0;
18507
				break;
18508
18509
			case 'creator': // 4.3.2.7 <dc:creator>
18510
				if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
18511
				else creatoridx = Rn.index + Rn[0].length;
18512
				break;
18513
18514
			/* ignore state */
18515
			case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
18516
			case 'settings': // TODO: <office:settings>
18517
			case 'config-item-set': // TODO: <office:config-item-set>
18518
			case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
18519
			case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
18520
			case 'config-item-map-named': // TODO: <office:config-item-map-entry>
18521
			case 'shapes': // 9.2.8 <table:shapes>
18522
			case 'frame': // 10.4.2 <draw:frame>
18523
			case 'text-box': // 10.4.3 <draw:text-box>
18524
			case 'image': // 10.4.4 <draw:image>
18525
			case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
18526
			case 'list-style': // 16.30 <text:list-style>
18527
			case 'form': // 13.13 <form:form>
18528
			case 'dde-links': // 9.8 <table:dde-links>
18529
			case 'event-listeners': // TODO
18530
			case 'chart': // TODO
18531
				if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
18532
				else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
18533
				textp = ""; textpidx = 0;
18534
				break;
18535
18536
			case 'scientific-number': // TODO: <number:scientific-number>
18537
				break;
18538
			case 'currency-symbol': // TODO: <number:currency-symbol>
18539
				break;
18540
			case 'currency-style': // TODO: <number:currency-style>
18541
				break;
18542
			case 'number-style': // 16.27.2 <number:number-style>
18543
			case 'percentage-style': // 16.27.9 <number:percentage-style>
18544
			case 'date-style': // 16.27.10 <number:date-style>
18545
			case 'time-style': // 16.27.18 <number:time-style>
18546
				if(Rn[1]==='/'){
18547
					number_format_map[NFtag.name] = NF;
18548
					if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
18549
				} else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
18550
					NF = "";
18551
					NFtag = parsexmltag(Rn[0], false);
18552
					state.push([Rn[3], true]);
18553
				} break;
18554
18555
			case 'script': break; // 3.13 <office:script>
18556
			case 'libraries': break; // TODO: <ooo:libraries>
18557
			case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
18558
			case 'master-styles': break; // TODO: <office:master-styles>
18559
18560
			case 'default-style': // TODO: <style:default-style>
18561
			case 'page-layout': break; // TODO: <style:page-layout>
18562
			case 'style': break; // 16.2 <style:style>
18563
			case 'map': break; // 16.3 <style:map>
18564
			case 'font-face': break; // 16.21 <style:font-face>
18565
18566
			case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
18567
			case 'table-properties': break; // 17.15 <style:table-properties>
18568
			case 'table-column-properties': break; // 17.16 <style:table-column-properties>
18569
			case 'table-row-properties': break; // 17.17 <style:table-row-properties>
18570
			case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
18571
18572
			case 'number': // 16.27.3 <number:number>
18573
				switch(state[state.length-1][0]) {
18574
					case 'time-style':
18575
					case 'date-style':
18576
						tag = parsexmltag(Rn[0], false);
18577
						NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
18578
				} break;
18579
18580
			case 'fraction': break; // TODO 16.27.6 <number:fraction>
18581
18582
			case 'day': // 16.27.11 <number:day>
18583
			case 'month': // 16.27.12 <number:month>
18584
			case 'year': // 16.27.13 <number:year>
18585
			case 'era': // 16.27.14 <number:era>
18586
			case 'day-of-week': // 16.27.15 <number:day-of-week>
18587
			case 'week-of-year': // 16.27.16 <number:week-of-year>
18588
			case 'quarter': // 16.27.17 <number:quarter>
18589
			case 'hours': // 16.27.19 <number:hours>
18590
			case 'minutes': // 16.27.20 <number:minutes>
18591
			case 'seconds': // 16.27.21 <number:seconds>
18592
			case 'am-pm': // 16.27.22 <number:am-pm>
18593
				switch(state[state.length-1][0]) {
18594
					case 'time-style':
18595
					case 'date-style':
18596
						tag = parsexmltag(Rn[0], false);
18597
						NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
18598
				} break;
18599
18600
			case 'boolean-style': break; // 16.27.23 <number:boolean-style>
18601
			case 'boolean': break; // 16.27.24 <number:boolean>
18602
			case 'text-style': break; // 16.27.25 <number:text-style>
18603
			case 'text': // 16.27.26 <number:text>
18604
				if(Rn[0].slice(-2) === "/>") break;
18605
				else if(Rn[1]==="/") switch(state[state.length-1][0]) {
18606
					case 'number-style':
18607
					case 'date-style':
18608
					case 'time-style':
18609
						NF += str.slice(pidx, Rn.index);
18610
						break;
18611
				}
18612
				else pidx = Rn.index + Rn[0].length;
18613
				break;
18614
18615
			case 'named-range': // 9.4.12 <table:named-range>
18616
				tag = parsexmltag(Rn[0], false);
18617
				_Ref = ods_to_csf_3D(tag['cell-range-address']);
18618
				var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
18619
				if(intable) nrange.Sheet = SheetNames.length;
18620
				WB.Names.push(nrange);
18621
				break;
18622
18623
			case 'text-content': break; // 16.27.27 <number:text-content>
18624
			case 'text-properties': break; // 16.27.27 <style:text-properties>
18625
			case 'embedded-text': break; // 16.27.4 <number:embedded-text>
18626
18627
			case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
18628
18629
			case 'forms': break; // 12.25.2 13.2
18630
			case 'table-column': break; // 9.1.6 <table:table-column>
18631
			case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
18632
			case 'table-rows': break; // 9.1.12 <table:table-rows>
18633
			/* TODO: outline levels */
18634
			case 'table-column-group': break; // 9.1.10 <table:table-column-group>
18635
			case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
18636
			case 'table-columns': break; // 9.1.12 <table:table-columns>
18637
18638
			case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
18639
18640
			case 'graphic-properties': break; // 17.21 <style:graphic-properties>
18641
			case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
18642
			case 'named-expressions': break; // 9.4.11 <table:named-expressions>
18643
			case 'label-range': break; // 9.4.9 <table:label-range>
18644
			case 'label-ranges': break; // 9.4.10 <table:label-ranges>
18645
			case 'named-expression': break; // 9.4.13 <table:named-expression>
18646
			case 'sort': break; // 9.4.19 <table:sort>
18647
			case 'sort-by': break; // 9.4.20 <table:sort-by>
18648
			case 'sort-groups': break; // 9.4.22 <table:sort-groups>
18649
18650
			case 'tab': break; // 6.1.4 <text:tab>
18651
			case 'line-break': break; // 6.1.5 <text:line-break>
18652
			case 'span': break; // 6.1.7 <text:span>
18653
			case 'p': case '文本串': // 5.1.3 <text:p>
18654
				if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) textp = (textp.length > 0 ? textp + "\n" : "") + parse_text_p(str.slice(textpidx,Rn.index), textptag);
18655
				else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
18656
				break; // <text:p>
18657
			case 's': break; // <text:s>
18658
18659
			case 'database-range': // 9.4.15 <table:database-range>
18660
				if(Rn[1]==='/') break;
18661
				try {
18662
					_Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
18663
					Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
18664
				} catch(e) {/* empty */}
18665
				break;
18666
18667
			case 'date': break; // <*:date>
18668
18669
			case 'object': break; // 10.4.6.2 <draw:object>
18670
			case 'title': case '标题': break; // <*:title> OR <uof:标题>
18671
			case 'desc': break; // <*:desc>
18672
			case 'binary-data': break; // 10.4.5 TODO: b64 blob
18673
18674
			/* 9.2 Advanced Tables */
18675
			case 'table-source': break; // 9.2.6
18676
			case 'scenario': break; // 9.2.6
18677
18678
			case 'iteration': break; // 9.4.3 <table:iteration>
18679
			case 'content-validations': break; // 9.4.4 <table:
18680
			case 'content-validation': break; // 9.4.5 <table:
18681
			case 'help-message': break; // 9.4.6 <table:
18682
			case 'error-message': break; // 9.4.7 <table:
18683
			case 'database-ranges': break; // 9.4.14 <table:database-ranges>
18684
			case 'filter': break; // 9.5.2 <table:filter>
18685
			case 'filter-and': break; // 9.5.3 <table:filter-and>
18686
			case 'filter-or': break; // 9.5.4 <table:filter-or>
18687
			case 'filter-condition': break; // 9.5.5 <table:filter-condition>
18688
18689
			case 'list-level-style-bullet': break; // 16.31 <text:
18690
			case 'list-level-style-number': break; // 16.32 <text:
18691
			case 'list-level-properties': break; // 17.19 <style:
18692
18693
			/* 7.3 Document Fields */
18694
			case 'sender-firstname': // 7.3.6.2
18695
			case 'sender-lastname': // 7.3.6.3
18696
			case 'sender-initials': // 7.3.6.4
18697
			case 'sender-title': // 7.3.6.5
18698
			case 'sender-position': // 7.3.6.6
18699
			case 'sender-email': // 7.3.6.7
18700
			case 'sender-phone-private': // 7.3.6.8
18701
			case 'sender-fax': // 7.3.6.9
18702
			case 'sender-company': // 7.3.6.10
18703
			case 'sender-phone-work': // 7.3.6.11
18704
			case 'sender-street': // 7.3.6.12
18705
			case 'sender-city': // 7.3.6.13
18706
			case 'sender-postal-code': // 7.3.6.14
18707
			case 'sender-country': // 7.3.6.15
18708
			case 'sender-state-or-province': // 7.3.6.16
18709
			case 'author-name': // 7.3.7.1
18710
			case 'author-initials': // 7.3.7.2
18711
			case 'chapter': // 7.3.8
18712
			case 'file-name': // 7.3.9
18713
			case 'template-name': // 7.3.9
18714
			case 'sheet-name': // 7.3.9
18715
				break;
18716
18717
			case 'event-listener':
18718
				break;
18719
			/* TODO: FODS Properties */
18720
			case 'initial-creator':
18721
			case 'creation-date':
18722
			case 'print-date':
18723
			case 'generator':
18724
			case 'document-statistic':
18725
			case 'user-defined':
18726
			case 'editing-duration':
18727
			case 'editing-cycles':
18728
				break;
18729
18730
			/* TODO: FODS Config */
18731
			case 'config-item':
18732
				break;
18733
18734
			/* TODO: style tokens */
18735
			case 'page-number': break; // TODO <text:page-number>
18736
			case 'page-count': break; // TODO <text:page-count>
18737
			case 'time': break; // TODO <text:time>
18738
18739
			/* 9.3 Advanced Table Cells */
18740
			case 'cell-range-source': break; // 9.3.1 <table:
18741
			case 'detective': break; // 9.3.2 <table:
18742
			case 'operation': break; // 9.3.3 <table:
18743
			case 'highlighted-range': break; // 9.3.4 <table:
18744
18745
			/* 9.6 Data Pilot Tables <table: */
18746
			case 'data-pilot-table': // 9.6.3
18747
			case 'source-cell-range': // 9.6.5
18748
			case 'source-service': // 9.6.6
18749
			case 'data-pilot-field': // 9.6.7
18750
			case 'data-pilot-level': // 9.6.8
18751
			case 'data-pilot-subtotals': // 9.6.9
18752
			case 'data-pilot-subtotal': // 9.6.10
18753
			case 'data-pilot-members': // 9.6.11
18754
			case 'data-pilot-member': // 9.6.12
18755
			case 'data-pilot-display-info': // 9.6.13
18756
			case 'data-pilot-sort-info': // 9.6.14
18757
			case 'data-pilot-layout-info': // 9.6.15
18758
			case 'data-pilot-field-reference': // 9.6.16
18759
			case 'data-pilot-groups': // 9.6.17
18760
			case 'data-pilot-group': // 9.6.18
18761
			case 'data-pilot-group-member': // 9.6.19
18762
				break;
18763
18764
			/* 10.3 Drawing Shapes */
18765
			case 'rect': // 10.3.2
18766
				break;
18767
18768
			/* 14.6 DDE Connections */
18769
			case 'dde-connection-decls': // 14.6.2 <text:
18770
			case 'dde-connection-decl': // 14.6.3 <text:
18771
			case 'dde-link': // 14.6.4 <table:
18772
			case 'dde-source': // 14.6.5 <office:
18773
				break;
18774
18775
			case 'properties': break; // 13.7 <form:properties>
18776
			case 'property': break; // 13.8 <form:property>
18777
18778
			case 'a': // 6.1.8 hyperlink
18779
				if(Rn[1]!== '/') {
18780
					atag = parsexmltag(Rn[0], false);
18781
					if(!atag.href) break;
18782
					atag.Target = atag.href; delete atag.href;
18783
					if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
18784
						_Ref = ods_to_csf_3D(atag.Target.slice(1));
18785
						atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
18786
					}
18787
				}
18788
				break;
18789
18790
			/* non-standard */
18791
			case 'table-protection': break;
18792
			case 'data-pilot-grand-total': break; // <table:
18793
			case 'office-document-common-attrs': break; // bare
18794
			default: switch(Rn[2]) {
18795
				case 'dc:':       // TODO: properties
18796
				case 'calcext:':  // ignore undocumented extensions
18797
				case 'loext:':    // ignore undocumented extensions
18798
				case 'ooo:':      // ignore undocumented extensions
18799
				case 'chartooo:': // ignore undocumented extensions
18800
				case 'draw:':     // TODO: drawing
18801
				case 'style:':    // TODO: styles
18802
				case 'chart:':    // TODO: charts
18803
				case 'form:':     // TODO: forms
18804
				case 'uof:':      // TODO: uof
18805
				case '表:':       // TODO: uof
18806
				case '字:':       // TODO: uof
18807
					break;
18808
				default: if(opts.WTF) throw new Error(Rn);
18809
			}
18810
		}
18811
		var out = ({
18812
			Sheets: Sheets,
18813
			SheetNames: SheetNames,
18814
			Workbook: WB
18815
		});
18816
		if(opts.bookSheets) delete out.Sheets;
18817
		return out;
18818
	};
18819
})();
18820
18821
function parse_ods(zip, opts) {
18822
	opts = opts || ({});
18823
	var ods = !!safegetzipfile(zip, 'objectdata');
18824
	if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
18825
	var content = getzipstr(zip, 'content.xml');
18826
	if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
18827
	var wb = parse_content_xml(ods ? content : utf8read(content), opts);
18828
	if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
18829
	return wb;
18830
}
18831
function parse_fods(data, opts) {
18832
	return parse_content_xml(data, opts);
18833
}
18834
18835
/* OpenDocument */
18836
var write_styles_ods = (function() {
18837
	var payload = '<office:document-styles ' + wxt_helper({
18838
		'xmlns:office':   "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
18839
		'xmlns:table':    "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
18840
		'xmlns:style':    "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
18841
		'xmlns:text':     "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
18842
		'xmlns:draw':     "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
18843
		'xmlns:fo':       "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
18844
		'xmlns:xlink':    "http://www.w3.org/1999/xlink",
18845
		'xmlns:dc':       "http://purl.org/dc/elements/1.1/",
18846
		'xmlns:number':   "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
18847
		'xmlns:svg':      "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
18848
		'xmlns:of':       "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
18849
		'office:version': "1.2"
18850
	}) + '></office:document-styles>';
18851
	return function wso() {
18852
		return XML_HEADER + payload;
18853
	};
18854
})();
18855
var write_content_ods = (function() {
18856
	/* 6.1.2 White Space Characters */
18857
	var write_text_p = function(text) {
18858
		return escapexml(text)
18859
			.replace(/  +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
18860
			.replace(/\t/g, "<text:tab/>")
18861
			.replace(/\n/g, "<text:line-break/>")
18862
			.replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
18863
	};
18864
18865
	var null_cell_xml = '          <table:table-cell />\n';
18866
	var covered_cell_xml = '          <table:covered-table-cell/>\n';
18867
	var write_ws = function(ws, wb, i) {
18868
		/* Section 9 Tables */
18869
		var o = [];
18870
		o.push('      <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
18871
		var R=0,C=0, range = decode_range(ws['!ref']);
18872
		var marr = ws['!merges'] || [], mi = 0;
18873
		var dense = Array.isArray(ws);
18874
		for(R = 0; R < range.s.r; ++R) o.push('        <table:table-row></table:table-row>\n');
18875
		for(; R <= range.e.r; ++R) {
18876
			o.push('        <table:table-row>\n');
18877
			for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
18878
			for(; C <= range.e.c; ++C) {
18879
				var skip = false, ct = {}, textp = "";
18880
				for(mi = 0; mi != marr.length; ++mi) {
18881
					if(marr[mi].s.c > C) continue;
18882
					if(marr[mi].s.r > R) continue;
18883
					if(marr[mi].e.c < C) continue;
18884
					if(marr[mi].e.r < R) continue;
18885
					if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
18886
					ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
18887
					ct['table:number-rows-spanned'] =    (marr[mi].e.r - marr[mi].s.r + 1);
18888
					break;
18889
				}
18890
				if(skip) { o.push(covered_cell_xml); continue; }
18891
				var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
18892
				if(cell && cell.f) {
18893
					ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
18894
					if(cell.F) {
18895
						if(cell.F.slice(0, ref.length) == ref) {
18896
							var _Fref = decode_range(cell.F);
18897
							ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
18898
							ct['table:number-matrix-rows-spanned'] =    (_Fref.e.r - _Fref.s.r + 1);
18899
						}
18900
					}
18901
				}
18902
				if(!cell) { o.push(null_cell_xml); continue; }
18903
				switch(cell.t) {
18904
					case 'b':
18905
						textp = (cell.v ? 'TRUE' : 'FALSE');
18906
						ct['office:value-type'] = "boolean";
18907
						ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
18908
						break;
18909
					case 'n':
18910
						textp = (cell.w||String(cell.v||0));
18911
						ct['office:value-type'] = "float";
18912
						ct['office:value'] = (cell.v||0);
18913
						break;
18914
					case 's': case 'str':
18915
						textp = cell.v;
18916
						ct['office:value-type'] = "string";
18917
						break;
18918
					case 'd':
18919
						textp = (cell.w||(parseDate(cell.v).toISOString()));
18920
						ct['office:value-type'] = "date";
18921
						ct['office:date-value'] = (parseDate(cell.v).toISOString());
18922
						ct['table:style-name'] = "ce1";
18923
						break;
18924
					//case 'e':
18925
					default: o.push(null_cell_xml); continue;
18926
				}
18927
				var text_p = write_text_p(textp);
18928
				if(cell.l && cell.l.Target) {
18929
					var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
18930
					text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
18931
				}
18932
				o.push('          ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
18933
			}
18934
			o.push('        </table:table-row>\n');
18935
		}
18936
		o.push('      </table:table>\n');
18937
		return o.join("");
18938
	};
18939
18940
	var write_automatic_styles_ods = function(o) {
18941
		o.push(' <office:automatic-styles>\n');
18942
		o.push('  <number:date-style style:name="N37" number:automatic-order="true">\n');
18943
		o.push('   <number:month number:style="long"/>\n');
18944
		o.push('   <number:text>/</number:text>\n');
18945
		o.push('   <number:day number:style="long"/>\n');
18946
		o.push('   <number:text>/</number:text>\n');
18947
		o.push('   <number:year/>\n');
18948
		o.push('  </number:date-style>\n');
18949
		o.push('  <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
18950
		o.push(' </office:automatic-styles>\n');
18951
	};
18952
18953
	return function wcx(wb, opts) {
18954
		var o = [XML_HEADER];
18955
		/* 3.1.3.2 */
18956
		var attr = wxt_helper({
18957
			'xmlns:office':       "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
18958
			'xmlns:table':        "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
18959
			'xmlns:style':        "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
18960
			'xmlns:text':         "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
18961
			'xmlns:draw':         "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
18962
			'xmlns:fo':           "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
18963
			'xmlns:xlink':        "http://www.w3.org/1999/xlink",
18964
			'xmlns:dc':           "http://purl.org/dc/elements/1.1/",
18965
			'xmlns:meta':         "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
18966
			'xmlns:number':       "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
18967
			'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
18968
			'xmlns:svg':          "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
18969
			'xmlns:chart':        "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
18970
			'xmlns:dr3d':         "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
18971
			'xmlns:math':         "http://www.w3.org/1998/Math/MathML",
18972
			'xmlns:form':         "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
18973
			'xmlns:script':       "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
18974
			'xmlns:ooo':          "http://openoffice.org/2004/office",
18975
			'xmlns:ooow':         "http://openoffice.org/2004/writer",
18976
			'xmlns:oooc':         "http://openoffice.org/2004/calc",
18977
			'xmlns:dom':          "http://www.w3.org/2001/xml-events",
18978
			'xmlns:xforms':       "http://www.w3.org/2002/xforms",
18979
			'xmlns:xsd':          "http://www.w3.org/2001/XMLSchema",
18980
			'xmlns:xsi':          "http://www.w3.org/2001/XMLSchema-instance",
18981
			'xmlns:sheet':        "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
18982
			'xmlns:rpt':          "http://openoffice.org/2005/report",
18983
			'xmlns:of':           "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
18984
			'xmlns:xhtml':        "http://www.w3.org/1999/xhtml",
18985
			'xmlns:grddl':        "http://www.w3.org/2003/g/data-view#",
18986
			'xmlns:tableooo':     "http://openoffice.org/2009/table",
18987
			'xmlns:drawooo':      "http://openoffice.org/2010/draw",
18988
			'xmlns:calcext':      "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
18989
			'xmlns:loext':        "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
18990
			'xmlns:field':        "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
18991
			'xmlns:formx':        "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
18992
			'xmlns:css3t':        "http://www.w3.org/TR/css3-text/",
18993
			'office:version':     "1.2"
18994
		});
18995
18996
		var fods = wxt_helper({
18997
			'xmlns:config':    "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
18998
			'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
18999
		});
19000
19001
		if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n');
19002
		else o.push('<office:document-content' + attr  + '>\n');
19003
		write_automatic_styles_ods(o);
19004
		o.push('  <office:body>\n');
19005
		o.push('    <office:spreadsheet>\n');
19006
		for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
19007
		o.push('    </office:spreadsheet>\n');
19008
		o.push('  </office:body>\n');
19009
		if(opts.bookType == "fods") o.push('</office:document>');
19010
		else o.push('</office:document-content>');
19011
		return o.join("");
19012
	};
19013
})();
19014
19015
function write_ods(wb, opts) {
19016
	if(opts.bookType == "fods") return write_content_ods(wb, opts);
19017
19018
var zip = new jszip();
19019
	var f = "";
19020
19021
	var manifest = [];
19022
	var rdf = [];
19023
19024
	/* Part 3 Section 3.3 MIME Media Type */
19025
	f = "mimetype";
19026
	zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
19027
19028
	/* Part 1 Section 2.2 Documents */
19029
	f = "content.xml";
19030
	zip.file(f, write_content_ods(wb, opts));
19031
	manifest.push([f, "text/xml"]);
19032
	rdf.push([f, "ContentFile"]);
19033
19034
	/* TODO: these are hard-coded styles to satiate excel */
19035
	f = "styles.xml";
19036
	zip.file(f, write_styles_ods(wb, opts));
19037
	manifest.push([f, "text/xml"]);
19038
	rdf.push([f, "StylesFile"]);
19039
19040
	/* TODO: this is hard-coded to satiate excel */
19041
	f = "meta.xml";
19042
	zip.file(f, write_meta_ods());
19043
	manifest.push([f, "text/xml"]);
19044
	rdf.push([f, "MetadataFile"]);
19045
19046
	/* Part 3 Section 6 Metadata Manifest File */
19047
	f = "manifest.rdf";
19048
	zip.file(f, write_rdf(rdf/*, opts*/));
19049
	manifest.push([f, "application/rdf+xml"]);
19050
19051
	/* Part 3 Section 4 Manifest File */
19052
	f = "META-INF/manifest.xml";
19053
	zip.file(f, write_manifest(manifest/*, opts*/));
19054
19055
	return zip;
19056
}
19057
19058
function write_sheet_index(wb, sheet) {
19059
	if(!sheet) return 0;
19060
	var idx = wb.SheetNames.indexOf(sheet);
19061
	if(idx == -1) throw new Error("Sheet not found: " + sheet);
19062
	return idx;
19063
}
19064
19065
function write_obj_str(factory) {
19066
	return function write_str(wb, o) {
19067
		var idx = write_sheet_index(wb, o.sheet);
19068
		return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
19069
	};
19070
}
19071
19072
var write_htm_str = write_obj_str(HTML_);
19073
var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
19074
var write_slk_str = write_obj_str(SYLK);
19075
var write_dif_str = write_obj_str(DIF);
19076
var write_prn_str = write_obj_str(PRN);
19077
var write_rtf_str = write_obj_str(RTF);
19078
var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
19079
var write_dbf_buf = write_obj_str(DBF);
19080
var write_eth_str = write_obj_str(ETH);
19081
19082
function fix_opts_func(defaults) {
19083
	return function fix_opts(opts) {
19084
		for(var i = 0; i != defaults.length; ++i) {
19085
			var d = defaults[i];
19086
			if(opts[d[0]] === undefined) opts[d[0]] = d[1];
19087
			if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
19088
		}
19089
	};
19090
}
19091
19092
var fix_read_opts = fix_opts_func([
19093
	['cellNF', false], /* emit cell number format string as .z */
19094
	['cellHTML', true], /* emit html string as .h */
19095
	['cellFormula', true], /* emit formulae as .f */
19096
	['cellStyles', false], /* emits style/theme as .s */
19097
	['cellText', true], /* emit formatted text as .w */
19098
	['cellDates', false], /* emit date cells with type `d` */
19099
19100
	['sheetStubs', false], /* emit empty cells */
19101
	['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
19102
19103
	['bookDeps', false], /* parse calculation chains */
19104
	['bookSheets', false], /* only try to get sheet names (no Sheets) */
19105
	['bookProps', false], /* only try to get properties (no Sheets) */
19106
	['bookFiles', false], /* include raw file structure (keys, files, cfb) */
19107
	['bookVBA', false], /* include vba raw data (vbaraw) */
19108
19109
	['password',''], /* password */
19110
	['WTF', false] /* WTF mode (throws errors) */
19111
]);
19112
19113
19114
var fix_write_opts = fix_opts_func([
19115
	['cellDates', false], /* write date cells with type `d` */
19116
19117
	['bookSST', false], /* Generate Shared String Table */
19118
19119
	['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
19120
19121
	['compression', false], /* Use file compression */
19122
19123
	['WTF', false] /* WTF mode (throws errors) */
19124
]);
19125
function get_sheet_type(n) {
19126
	if(RELS.WS.indexOf(n) > -1) return "sheet";
19127
	if(RELS.CS && n == RELS.CS) return "chart";
19128
	if(RELS.DS && n == RELS.DS) return "dialog";
19129
	if(RELS.MS && n == RELS.MS) return "macro";
19130
	return (n && n.length) ? n : "sheet";
19131
}
19132
function safe_parse_wbrels(wbrels, sheets) {
19133
	if(!wbrels) return 0;
19134
	try {
19135
		wbrels = sheets.map(function pwbr(w) { if(!w.id) w.id = w.strRelID; return [w.name, wbrels['!id'][w.id].Target, get_sheet_type(wbrels['!id'][w.id].Type)]; });
19136
	} catch(e) { return null; }
19137
	return !wbrels || wbrels.length === 0 ? null : wbrels;
19138
}
19139
19140
function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
19141
	try {
19142
		sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
19143
		var data = getzipdata(zip, path);
19144
		var _ws;
19145
		switch(stype) {
19146
			case 'sheet':  _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19147
			case 'chart':  _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
19148
				if(!_ws || !_ws['!chart']) break;
19149
				var dfile = resolve_path(_ws['!chart'].Target, path);
19150
				var drelsp = get_rels_path(dfile);
19151
				var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
19152
				var chartp = resolve_path(draw, dfile);
19153
				var crelsp = get_rels_path(chartp);
19154
				_ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
19155
				break;
19156
			case 'macro':  _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19157
			case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19158
		}
19159
		sheets[sheet] = _ws;
19160
	} catch(e) { if(opts.WTF) throw e; }
19161
}
19162
19163
function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
19164
19165
function parse_zip(zip, opts) {
19166
	make_ssf(SSF);
19167
	opts = opts || {};
19168
	fix_read_opts(opts);
19169
19170
	/* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
19171
	if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
19172
	/* UOC */
19173
	if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
19174
	/* Numbers */
19175
	if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
19176
19177
	var entries = zipentries(zip);
19178
	var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
19179
	var xlsb = false;
19180
	var sheets, binname;
19181
	if(dir.workbooks.length === 0) {
19182
		binname = "xl/workbook.xml";
19183
		if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
19184
	}
19185
	if(dir.workbooks.length === 0) {
19186
		binname = "xl/workbook.bin";
19187
		if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
19188
		dir.workbooks.push(binname);
19189
		xlsb = true;
19190
	}
19191
	if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
19192
19193
	var themes = ({});
19194
	var styles = ({});
19195
	if(!opts.bookSheets && !opts.bookProps) {
19196
		strs = [];
19197
		if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
19198
19199
		if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
19200
19201
		if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
19202
	}
19203
19204
	/*var externbooks = */dir.links.map(function(link) {
19205
		return parse_xlink(getzipdata(zip, strip_front_slash(link)), link, opts);
19206
	});
19207
19208
	var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
19209
19210
	var props = {}, propdata = "";
19211
19212
	if(dir.coreprops.length) {
19213
		propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
19214
		if(propdata) props = parse_core_props(propdata);
19215
		if(dir.extprops.length !== 0) {
19216
			propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
19217
			if(propdata) parse_ext_props(propdata, props, opts);
19218
		}
19219
	}
19220
19221
	var custprops = {};
19222
	if(!opts.bookSheets || opts.bookProps) {
19223
		if (dir.custprops.length !== 0) {
19224
			propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
19225
			if(propdata) custprops = parse_cust_props(propdata, opts);
19226
		}
19227
	}
19228
19229
	var out = ({});
19230
	if(opts.bookSheets || opts.bookProps) {
19231
		if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
19232
		else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
19233
		if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
19234
		if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
19235
		if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
19236
	}
19237
	sheets = {};
19238
19239
	var deps = {};
19240
	if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
19241
19242
	var i=0;
19243
	var sheetRels = ({});
19244
	var path, relsPath;
19245
19246
	{
19247
		var wbsheets = wb.Sheets;
19248
		props.Worksheets = wbsheets.length;
19249
		props.SheetNames = [];
19250
		for(var j = 0; j != wbsheets.length; ++j) {
19251
			props.SheetNames[j] = wbsheets[j].name;
19252
		}
19253
	}
19254
19255
	var wbext = xlsb ? "bin" : "xml";
19256
	var wbrelsi = dir.workbooks[0].lastIndexOf("/");
19257
	var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
19258
	if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
19259
	var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
19260
	if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
19261
19262
	/* Numbers iOS hack */
19263
	var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
19264
	for(i = 0; i != props.Worksheets; ++i) {
19265
		var stype = "sheet";
19266
		if(wbrels && wbrels[i]) {
19267
			path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
19268
			if(!safegetzipfile(zip, path)) path = wbrels[i][1];
19269
			if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
19270
			stype = wbrels[i][2];
19271
		} else {
19272
			path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
19273
			path = path.replace(/sheet0\./,"sheet.");
19274
		}
19275
		relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
19276
		safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
19277
	}
19278
19279
	if(dir.comments) parse_comments(zip, dir.comments, sheets, sheetRels, opts);
19280
19281
	out = ({
19282
		Directory: dir,
19283
		Workbook: wb,
19284
		Props: props,
19285
		Custprops: custprops,
19286
		Deps: deps,
19287
		Sheets: sheets,
19288
		SheetNames: props.SheetNames,
19289
		Strings: strs,
19290
		Styles: styles,
19291
		Themes: themes,
19292
		SSF: SSF.get_table()
19293
	});
19294
	if(opts.bookFiles) {
19295
		out.keys = entries;
19296
		out.files = zip.files;
19297
	}
19298
	if(opts.bookVBA) {
19299
		if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
19300
		else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
19301
	}
19302
	return out;
19303
}
19304
19305
/* [MS-OFFCRYPTO] 2.1.1 */
19306
function parse_xlsxcfb(cfb, _opts) {
19307
	var opts = _opts || {};
19308
	var f = 'Workbook', data = CFB.find(cfb, f);
19309
	try {
19310
	f = '/!DataSpaces/Version';
19311
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19312
	/*var version = */parse_DataSpaceVersionInfo(data.content);
19313
19314
	/* 2.3.4.1 */
19315
	f = '/!DataSpaces/DataSpaceMap';
19316
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19317
	var dsm = parse_DataSpaceMap(data.content);
19318
	if(dsm.length !== 1 || dsm[0].comps.length !== 1 || dsm[0].comps[0].t !== 0 || dsm[0].name !== "StrongEncryptionDataSpace" || dsm[0].comps[0].v !== "EncryptedPackage")
19319
		throw new Error("ECMA-376 Encrypted file bad " + f);
19320
19321
	/* 2.3.4.2 */
19322
	f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
19323
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19324
	var seds = parse_DataSpaceDefinition(data.content);
19325
	if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
19326
		throw new Error("ECMA-376 Encrypted file bad " + f);
19327
19328
	/* 2.3.4.3 */
19329
	f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
19330
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19331
	/*var hdr = */parse_Primary(data.content);
19332
	} catch(e) {}
19333
19334
	f = '/EncryptionInfo';
19335
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19336
	var einfo = parse_EncryptionInfo(data.content);
19337
19338
	/* 2.3.4.4 */
19339
	f = '/EncryptedPackage';
19340
	data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
19341
19342
/*global decrypt_agile */
19343
if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
19344
/*global decrypt_std76 */
19345
if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
19346
	throw new Error("File is password-protected");
19347
}
19348
19349
function write_zip(wb, opts) {
19350
	_shapeid = 1024;
19351
	if(opts.bookType == "ods") return write_ods(wb, opts);
19352
	if(wb && !wb.SSF) {
19353
		wb.SSF = SSF.get_table();
19354
	}
19355
	if(wb && wb.SSF) {
19356
		make_ssf(SSF); SSF.load_table(wb.SSF);
19357
		// $FlowIgnore
19358
		opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
19359
		opts.ssf = wb.SSF;
19360
	}
19361
	opts.rels = {}; opts.wbrels = {};
19362
	opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
19363
	if(browser_has_Map) opts.revStrings = new Map();
19364
	else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
19365
	var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
19366
	var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
19367
	var ct = new_ct();
19368
	fix_write_opts(opts = opts || {});
19369
var zip = new jszip();
19370
	var f = "", rId = 0;
19371
19372
	opts.cellXfs = [];
19373
	get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
19374
19375
	if(!wb.Props) wb.Props = {};
19376
19377
	f = "docProps/core.xml";
19378
	zip.file(f, write_core_props(wb.Props, opts));
19379
	ct.coreprops.push(f);
19380
	add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
19381
19382
f = "docProps/app.xml";
19383
	if(wb.Props && wb.Props.SheetNames){/* empty */}
19384
	else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
19385
	else {
19386
		var _sn = [];
19387
		for(var _i = 0; _i < wb.SheetNames.length; ++_i)
19388
			if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
19389
		wb.Props.SheetNames = _sn;
19390
	}
19391
	wb.Props.Worksheets = wb.Props.SheetNames.length;
19392
	zip.file(f, write_ext_props(wb.Props, opts));
19393
	ct.extprops.push(f);
19394
	add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
19395
19396
	if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
19397
		f = "docProps/custom.xml";
19398
		zip.file(f, write_cust_props(wb.Custprops, opts));
19399
		ct.custprops.push(f);
19400
		add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
19401
	}
19402
19403
	for(rId=1;rId <= wb.SheetNames.length; ++rId) {
19404
		var wsrels = {'!id':{}};
19405
		var ws = wb.Sheets[wb.SheetNames[rId-1]];
19406
		var _type = (ws || {})["!type"] || "sheet";
19407
		switch(_type) {
19408
		case "chart": /*
19409
			f = "xl/chartsheets/sheet" + rId + "." + wbext;
19410
			zip.file(f, write_cs(rId-1, f, opts, wb, wsrels));
19411
			ct.charts.push(f);
19412
			add_rels(wsrels, -1, "chartsheets/sheet" + rId + "." + wbext, RELS.CS);
19413
			break; */
19414
			/* falls through */
19415
		default:
19416
			f = "xl/worksheets/sheet" + rId + "." + wbext;
19417
			zip.file(f, write_ws(rId-1, f, opts, wb, wsrels));
19418
			ct.sheets.push(f);
19419
			add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
19420
		}
19421
19422
		if(ws) {
19423
			var comments = ws['!comments'];
19424
			if(comments && comments.length > 0) {
19425
				var cf = "xl/comments" + rId + "." + wbext;
19426
				zip.file(cf, write_cmnt(comments, cf, opts));
19427
				ct.comments.push(cf);
19428
				add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
19429
			}
19430
			if(ws['!legacy']) {
19431
				zip.file("xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
19432
			}
19433
			delete ws['!comments'];
19434
			delete ws['!legacy'];
19435
		}
19436
19437
		if(wsrels['!id'].rId1) zip.file(get_rels_path(f), write_rels(wsrels));
19438
	}
19439
19440
	if(opts.Strings != null && opts.Strings.length > 0) {
19441
		f = "xl/sharedStrings." + wbext;
19442
		zip.file(f, write_sst(opts.Strings, f, opts));
19443
		ct.strs.push(f);
19444
		add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
19445
	}
19446
19447
	f = "xl/workbook." + wbext;
19448
	zip.file(f, write_wb(wb, f, opts));
19449
	ct.workbooks.push(f);
19450
	add_rels(opts.rels, 1, f, RELS.WB);
19451
19452
	/* TODO: something more intelligent with themes */
19453
19454
	f = "xl/theme/theme1.xml";
19455
	zip.file(f, write_theme(wb.Themes, opts));
19456
	ct.themes.push(f);
19457
	add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
19458
19459
	/* TODO: something more intelligent with styles */
19460
19461
	f = "xl/styles." + wbext;
19462
	zip.file(f, write_sty(wb, f, opts));
19463
	ct.styles.push(f);
19464
	add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
19465
19466
	if(wb.vbaraw && vbafmt) {
19467
		f = "xl/vbaProject.bin";
19468
		zip.file(f, wb.vbaraw);
19469
		ct.vba.push(f);
19470
		add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
19471
	}
19472
19473
	zip.file("[Content_Types].xml", write_ct(ct, opts));
19474
	zip.file('_rels/.rels', write_rels(opts.rels));
19475
	zip.file('xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
19476
19477
	delete opts.revssf; delete opts.ssf;
19478
	return zip;
19479
}
19480
function firstbyte(f,o) {
19481
	var x = "";
19482
	switch((o||{}).type || "base64") {
19483
		case 'buffer': return [f[0], f[1], f[2], f[3]];
19484
		case 'base64': x = Base64.decode(f.slice(0,24)); break;
19485
		case 'binary': x = f; break;
19486
		case 'array':  return [f[0], f[1], f[2], f[3]];
19487
		default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
19488
	}
19489
	return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)];
19490
}
19491
19492
function read_cfb(cfb, opts) {
19493
	if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
19494
	return parse_xlscfb(cfb, opts);
19495
}
19496
19497
function read_zip(data, opts) {
19498
var zip, d = data;
19499
	var o = opts||{};
19500
	if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
19501
	switch(o.type) {
19502
		case "base64": zip = new jszip(d, { base64:true }); break;
19503
		case "binary": case "array": zip = new jszip(d, { base64:false }); break;
19504
		case "buffer": zip = new jszip(d); break;
19505
		default: throw new Error("Unrecognized type " + o.type);
19506
	}
19507
	return parse_zip(zip, o);
19508
}
19509
19510
function read_plaintext(data, o) {
19511
	var i = 0;
19512
	main: while(i < data.length) switch(data.charCodeAt(i)) {
19513
		case 0x0A: case 0x0D: case 0x20: ++i; break;
19514
		case 0x3C: return parse_xlml(data.slice(i),o);
19515
		default: break main;
19516
	}
19517
	return PRN.to_workbook(data, o);
19518
}
19519
19520
function read_plaintext_raw(data, o) {
19521
	var str = "", bytes = firstbyte(data, o);
19522
	switch(o.type) {
19523
		case 'base64': str = Base64.decode(data); break;
19524
		case 'binary': str = data; break;
19525
		case 'buffer': str = data.toString('binary'); break;
19526
		case 'array': str = cc2str(data); break;
19527
		default: throw new Error("Unrecognized type " + o.type);
19528
	}
19529
	if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
19530
	return read_plaintext(str, o);
19531
}
19532
19533
function read_utf16(data, o) {
19534
	var d = data;
19535
	if(o.type == 'base64') d = Base64.decode(d);
19536
	d = cptable.utils.decode(1200, d.slice(2), 'str');
19537
	o.type = "binary";
19538
	return read_plaintext(d, o);
19539
}
19540
19541
function bstrify(data) {
19542
	return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
19543
}
19544
19545
function read_prn(data, d, o, str) {
19546
	if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
19547
	return PRN.to_workbook(d, o);
19548
}
19549
19550
function readSync(data, opts) {
19551
	reset_cp();
19552
	if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
19553
	var d = data, n = [0,0,0,0], str = false;
19554
	var o = opts||{};
19555
	_ssfopts = {};
19556
	if(o.dateNF) _ssfopts.dateNF = o.dateNF;
19557
	if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
19558
	if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
19559
	if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
19560
	if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
19561
		// $FlowIgnore
19562
		var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
19563
		// $FlowIgnore
19564
		if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
19565
	}
19566
	switch((n = firstbyte(d, o))[0]) {
19567
		case 0xD0: return read_cfb(CFB.read(d, o), o);
19568
		case 0x09: return parse_xlscfb(d, o);
19569
		case 0x3C: return parse_xlml(d, o);
19570
		case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
19571
		case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
19572
		case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
19573
		case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
19574
		case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
19575
		case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
19576
		case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
19577
		case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
19578
		case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
19579
	}
19580
	if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
19581
	return read_prn(data, d, o, str);
19582
}
19583
19584
function readFileSync(filename, opts) {
19585
	var o = opts||{}; o.type = 'file';
19586
	return readSync(filename, o);
19587
}
19588
function write_cfb_ctr(cfb, o) {
19589
	switch(o.type) {
19590
		case "base64": case "binary": break;
19591
		case "buffer": case "array": o.type = ""; break;
19592
		case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
19593
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
19594
		default: throw new Error("Unrecognized type " + o.type);
19595
	}
19596
	return CFB.write(cfb, o);
19597
}
19598
19599
/*global encrypt_agile */
19600
function write_zip_type(wb, opts) {
19601
	var o = opts||{};
19602
	var z = write_zip(wb, o);
19603
	var oopts = {};
19604
	if(o.compression) oopts.compression = 'DEFLATE';
19605
	if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
19606
	else switch(o.type) {
19607
		case "base64": oopts.type = "base64"; break;
19608
		case "binary": oopts.type = "string"; break;
19609
		case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
19610
		case "buffer":
19611
		case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
19612
		default: throw new Error("Unrecognized type " + o.type);
19613
	}
19614
	var out = z.generate(oopts);
19615
	if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o);
19616
	if(o.type === "file") return write_dl(o.file, out);
19617
	return o.type == "string" ? utf8read(out) : out;
19618
}
19619
19620
function write_cfb_type(wb, opts) {
19621
	var o = opts||{};
19622
	var cfb = write_xlscfb(wb, o);
19623
	return write_cfb_ctr(cfb, o);
19624
}
19625
19626
function write_string_type(out, opts, bom) {
19627
	if(!bom) bom = "";
19628
	var o = bom + out;
19629
	switch(opts.type) {
19630
		case "base64": return Base64.encode(utf8write(o));
19631
		case "binary": return utf8write(o);
19632
		case "string": return out;
19633
		case "file": return write_dl(opts.file, o, 'utf8');
19634
		case "buffer": {
19635
			// $FlowIgnore
19636
			if(has_buf) return Buffer_from(o, 'utf8');
19637
			else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
19638
		}
19639
	}
19640
	throw new Error("Unrecognized type " + opts.type);
19641
}
19642
19643
function write_stxt_type(out, opts) {
19644
	switch(opts.type) {
19645
		case "base64": return Base64.encode(out);
19646
		case "binary": return out;
19647
		case "string": return out; /* override in sheet_to_txt */
19648
		case "file": return write_dl(opts.file, out, 'binary');
19649
		case "buffer": {
19650
			// $FlowIgnore
19651
			if(has_buf) return Buffer_from(out, 'binary');
19652
			else return out.split("").map(function(c) { return c.charCodeAt(0); });
19653
		}
19654
	}
19655
	throw new Error("Unrecognized type " + opts.type);
19656
}
19657
19658
/* TODO: test consistency */
19659
function write_binary_type(out, opts) {
19660
	switch(opts.type) {
19661
		case "string":
19662
		case "base64":
19663
		case "binary":
19664
			var bstr = "";
19665
			// $FlowIgnore
19666
			for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
19667
			return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
19668
		case "file": return write_dl(opts.file, out);
19669
		case "buffer": return out;
19670
		default: throw new Error("Unrecognized type " + opts.type);
19671
	}
19672
}
19673
19674
function writeSync(wb, opts) {
19675
	check_wb(wb);
19676
	var o = opts||{};
19677
	if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
19678
	switch(o.bookType || 'xlsb') {
19679
		case 'xml':
19680
		case 'xlml': return write_string_type(write_xlml(wb, o), o);
19681
		case 'slk':
19682
		case 'sylk': return write_string_type(write_slk_str(wb, o), o);
19683
		case 'htm':
19684
		case 'html': return write_string_type(write_htm_str(wb, o), o);
19685
		case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
19686
		case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
19687
		case 'dif': return write_string_type(write_dif_str(wb, o), o);
19688
		case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
19689
		case 'prn': return write_string_type(write_prn_str(wb, o), o);
19690
		case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
19691
		case 'eth': return write_string_type(write_eth_str(wb, o), o);
19692
		case 'fods': return write_string_type(write_ods(wb, o), o);
19693
		case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
19694
		case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
19695
		case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
19696
		case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
19697
		case 'biff8':
19698
		case 'xla':
19699
		case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
19700
		case 'xlsx':
19701
		case 'xlsm':
19702
		case 'xlam':
19703
		case 'xlsb':
19704
		case 'ods': return write_zip_type(wb, o);
19705
		default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
19706
	}
19707
}
19708
19709
function resolve_book_type(o) {
19710
	if(o.bookType) return;
19711
	var _BT = {
19712
		"xls": "biff8",
19713
		"htm": "html",
19714
		"slk": "sylk",
19715
		"socialcalc": "eth",
19716
		"Sh33tJS": "WTF"
19717
	};
19718
	var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
19719
	if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
19720
	o.bookType = _BT[o.bookType] || o.bookType;
19721
}
19722
19723
function writeFileSync(wb, filename, opts) {
19724
	var o = opts||{}; o.type = 'file';
19725
	o.file = filename;
19726
	resolve_book_type(o);
19727
	return writeSync(wb, o);
19728
}
19729
19730
function writeFileAsync(filename, wb, opts, cb) {
19731
	var o = opts||{}; o.type = 'file';
19732
	o.file = filename;
19733
	resolve_book_type(o);
19734
	o.type = 'buffer';
19735
	var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
19736
	return _fs.writeFile(filename, writeSync(wb, o), _cb);
19737
}
19738
function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
19739
	var rr = encode_row(R);
19740
	var defval = o.defval, raw = o.raw;
19741
	var isempty = true;
19742
	var row = (header === 1) ? [] : {};
19743
	if(header !== 1) {
19744
		if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
19745
		else row.__rowNum__ = R;
19746
	}
19747
	if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
19748
		var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
19749
		if(val === undefined || val.t === undefined) {
19750
			if(defval === undefined) continue;
19751
			if(hdr[C] != null) { row[hdr[C]] = defval; }
19752
			continue;
19753
		}
19754
		var v = val.v;
19755
		switch(val.t){
19756
			case 'z': if(v == null) break; continue;
19757
			case 'e': v = void 0; break;
19758
			case 's': case 'd': case 'b': case 'n': break;
19759
			default: throw new Error('unrecognized type ' + val.t);
19760
		}
19761
		if(hdr[C] != null) {
19762
			if(v == null) {
19763
				if(defval !== undefined) row[hdr[C]] = defval;
19764
				else if(raw && v === null) row[hdr[C]] = null;
19765
				else continue;
19766
			} else {
19767
				row[hdr[C]] = raw ? v : format_cell(val,v,o);
19768
			}
19769
			if(v != null) isempty = false;
19770
		}
19771
	}
19772
	return { row: row, isempty: isempty };
19773
}
19774
19775
19776
function sheet_to_json(sheet, opts) {
19777
	if(sheet == null || sheet["!ref"] == null) return [];
19778
	var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
19779
	var r = {s:{r:0,c:0},e:{r:0,c:0}};
19780
	var o = opts || {};
19781
	var range = o.range != null ? o.range : sheet["!ref"];
19782
	if(o.header === 1) header = 1;
19783
	else if(o.header === "A") header = 2;
19784
	else if(Array.isArray(o.header)) header = 3;
19785
	switch(typeof range) {
19786
		case 'string': r = safe_decode_range(range); break;
19787
		case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
19788
		default: r = range;
19789
	}
19790
	if(header > 0) offset = 0;
19791
	var rr = encode_row(r.s.r);
19792
	var cols = [];
19793
	var out = [];
19794
	var outi = 0, counter = 0;
19795
	var dense = Array.isArray(sheet);
19796
	var R = r.s.r, C = 0, CC = 0;
19797
	if(dense && !sheet[R]) sheet[R] = [];
19798
	for(C = r.s.c; C <= r.e.c; ++C) {
19799
		cols[C] = encode_col(C);
19800
		val = dense ? sheet[R][C] : sheet[cols[C] + rr];
19801
		switch(header) {
19802
			case 1: hdr[C] = C - r.s.c; break;
19803
			case 2: hdr[C] = cols[C]; break;
19804
			case 3: hdr[C] = o.header[C - r.s.c]; break;
19805
			default:
19806
				if(val == null) val = {w: "__EMPTY", t: "s"};
19807
				vv = v = format_cell(val, null, o);
19808
				counter = 0;
19809
				for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
19810
				hdr[C] = vv;
19811
		}
19812
	}
19813
	for (R = r.s.r + offset; R <= r.e.r; ++R) {
19814
		var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
19815
		if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
19816
	}
19817
	out.length = outi;
19818
	return out;
19819
}
19820
19821
var qreg = /"/g;
19822
function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
19823
	var isempty = true;
19824
	var row = [], txt = "", rr = encode_row(R);
19825
	for(var C = r.s.c; C <= r.e.c; ++C) {
19826
		if (!cols[C]) continue;
19827
		var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
19828
		if(val == null) txt = "";
19829
		else if(val.v != null) {
19830
			isempty = false;
19831
			txt = ''+format_cell(val, null, o);
19832
			for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
19833
			if(txt == "ID") txt = '"ID"';
19834
		} else if(val.f != null && !val.F) {
19835
			isempty = false;
19836
			txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
19837
		} else txt = "";
19838
		/* NOTE: Excel CSV does not support array formulae */
19839
		row.push(txt);
19840
	}
19841
	if(o.blankrows === false && isempty) return null;
19842
	return row.join(FS);
19843
}
19844
19845
function sheet_to_csv(sheet, opts) {
19846
	var out = [];
19847
	var o = opts == null ? {} : opts;
19848
	if(sheet == null || sheet["!ref"] == null) return "";
19849
	var r = safe_decode_range(sheet["!ref"]);
19850
	var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
19851
	var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
19852
	var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
19853
	var row = "", cols = [];
19854
	o.dense = Array.isArray(sheet);
19855
	var colinfo = o.skipHidden && sheet["!cols"] || [];
19856
	var rowinfo = o.skipHidden && sheet["!rows"] || [];
19857
	for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
19858
	for(var R = r.s.r; R <= r.e.r; ++R) {
19859
		if ((rowinfo[R]||{}).hidden) continue;
19860
		row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
19861
		if(row == null) { continue; }
19862
		if(o.strip) row = row.replace(endregex,"");
19863
		out.push(row + RS);
19864
	}
19865
	delete o.dense;
19866
	return out.join("");
19867
}
19868
19869
function sheet_to_txt(sheet, opts) {
19870
	if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
19871
	var s = sheet_to_csv(sheet, opts);
19872
	if(typeof cptable == 'undefined' || opts.type == 'string') return s;
19873
	var o = cptable.utils.encode(1200, s, 'str');
19874
	return String.fromCharCode(255) + String.fromCharCode(254) + o;
19875
}
19876
19877
function sheet_to_formulae(sheet) {
19878
	var y = "", x, val="";
19879
	if(sheet == null || sheet["!ref"] == null) return [];
19880
	var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
19881
	var cmds = [];
19882
	var dense = Array.isArray(sheet);
19883
	for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
19884
	for(var R = r.s.r; R <= r.e.r; ++R) {
19885
		rr = encode_row(R);
19886
		for(C = r.s.c; C <= r.e.c; ++C) {
19887
			y = cols[C] + rr;
19888
			x = dense ? (sheet[R]||[])[C] : sheet[y];
19889
			val = "";
19890
			if(x === undefined) continue;
19891
			else if(x.F != null) {
19892
				y = x.F;
19893
				if(!x.f) continue;
19894
				val = x.f;
19895
				if(y.indexOf(":") == -1) y = y + ":" + y;
19896
			}
19897
			if(x.f != null) val = x.f;
19898
			else if(x.t == 'z') continue;
19899
			else if(x.t == 'n' && x.v != null) val = "" + x.v;
19900
			else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
19901
			else if(x.w !== undefined) val = "'" + x.w;
19902
			else if(x.v === undefined) continue;
19903
			else if(x.t == 's') val = "'" + x.v;
19904
			else val = ""+x.v;
19905
			cmds[cmds.length] = y + "=" + val;
19906
		}
19907
	}
19908
	return cmds;
19909
}
19910
19911
function sheet_add_json(_ws, js, opts) {
19912
	var o = opts || {};
19913
	var offset = +!o.skipHeader;
19914
	var ws = _ws || ({});
19915
	var _R = 0, _C = 0;
19916
	if(ws && o.origin != null) {
19917
		if(typeof o.origin == 'number') _R = o.origin;
19918
		else {
19919
			var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
19920
			_R = _origin.r; _C = _origin.c;
19921
		}
19922
	}
19923
	var cell;
19924
	var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
19925
	if(ws['!ref']) {
19926
		var _range = safe_decode_range(ws['!ref']);
19927
		range.e.c = Math.max(range.e.c, _range.e.c);
19928
		range.e.r = Math.max(range.e.r, _range.e.r);
19929
		if(_R == -1) { _R = range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
19930
	}
19931
	var hdr = o.header || [], C = 0;
19932
19933
	js.forEach(function (JS, R) {
19934
		keys(JS).forEach(function(k) {
19935
			if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
19936
			var v = JS[k];
19937
			var t = 'z';
19938
			var z = "";
19939
			if(v && typeof v === 'object' && !(v instanceof Date)){
19940
				ws[encode_cell({c:_C + C,r:_R + R + offset})] = v;
19941
			} else {
19942
				if(typeof v == 'number') t = 'n';
19943
				else if(typeof v == 'boolean') t = 'b';
19944
				else if(typeof v == 'string') t = 's';
19945
				else if(v instanceof Date) {
19946
					t = 'd';
19947
					if(!o.cellDates) { t = 'n'; v = datenum(v); }
19948
					z = o.dateNF || SSF._table[14];
19949
				}
19950
				ws[encode_cell({c:_C + C,r:_R + R + offset})] = cell = ({t:t, v:v});
19951
				if(z) cell.z = z;
19952
			}
19953
		});
19954
	});
19955
	range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
19956
	var __R = encode_row(_R);
19957
	if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
19958
	ws['!ref'] = encode_range(range);
19959
	return ws;
19960
}
19961
function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
19962
19963
var utils = {
19964
	encode_col: encode_col,
19965
	encode_row: encode_row,
19966
	encode_cell: encode_cell,
19967
	encode_range: encode_range,
19968
	decode_col: decode_col,
19969
	decode_row: decode_row,
19970
	split_cell: split_cell,
19971
	decode_cell: decode_cell,
19972
	decode_range: decode_range,
19973
	format_cell: format_cell,
19974
	get_formulae: sheet_to_formulae,
19975
	make_csv: sheet_to_csv,
19976
	make_json: sheet_to_json,
19977
	make_formulae: sheet_to_formulae,
19978
	sheet_add_aoa: sheet_add_aoa,
19979
	sheet_add_json: sheet_add_json,
19980
	aoa_to_sheet: aoa_to_sheet,
19981
	json_to_sheet: json_to_sheet,
19982
	table_to_sheet: parse_dom_table,
19983
	table_to_book: table_to_book,
19984
	sheet_to_csv: sheet_to_csv,
19985
	sheet_to_txt: sheet_to_txt,
19986
	sheet_to_json: sheet_to_json,
19987
	sheet_to_html: HTML_.from_sheet,
19988
	sheet_to_dif: DIF.from_sheet,
19989
	sheet_to_slk: SYLK.from_sheet,
19990
	sheet_to_eth: ETH.from_sheet,
19991
	sheet_to_formulae: sheet_to_formulae,
19992
	sheet_to_row_object_array: sheet_to_json
19993
};
19994
19995
(function(utils) {
19996
utils.consts = utils.consts || {};
19997
function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
19998
19999
function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
20000
20001
/* get cell, creating a stub if necessary */
20002
function ws_get_cell_stub(ws, R, C) {
20003
	/* A1 cell address */
20004
	if(typeof R == "string") return ws[R] || (ws[R] = {t:'z'});
20005
	/* cell address object */
20006
	if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
20007
	/* R and C are 0-based indices */
20008
	return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
20009
}
20010
20011
/* find sheet index for given name / validate index */
20012
function wb_sheet_idx(wb, sh) {
20013
	if(typeof sh == "number") {
20014
		if(sh >= 0 && wb.SheetNames.length > sh) return sh;
20015
		throw new Error("Cannot find sheet # " + sh);
20016
	} else if(typeof sh == "string") {
20017
		var idx = wb.SheetNames.indexOf(sh);
20018
		if(idx > -1) return idx;
20019
		throw new Error("Cannot find sheet name |" + sh + "|");
20020
	} else throw new Error("Cannot find sheet |" + sh + "|");
20021
}
20022
20023
/* simple blank workbook object */
20024
utils.book_new = function() {
20025
	return { SheetNames: [], Sheets: {} };
20026
};
20027
20028
/* add a worksheet to the end of a given workbook */
20029
utils.book_append_sheet = function(wb, ws, name) {
20030
	if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
20031
	if(!name) throw new Error("Too many worksheets");
20032
	check_ws_name(name);
20033
	if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
20034
20035
	wb.SheetNames.push(name);
20036
	wb.Sheets[name] = ws;
20037
};
20038
20039
/* set sheet visibility (visible/hidden/very hidden) */
20040
utils.book_set_sheet_visibility = function(wb, sh, vis) {
20041
	get_default(wb,"Workbook",{});
20042
	get_default(wb.Workbook,"Sheets",[]);
20043
20044
	var idx = wb_sheet_idx(wb, sh);
20045
	// $FlowIgnore
20046
	get_default(wb.Workbook.Sheets,idx, {});
20047
20048
	switch(vis) {
20049
		case 0: case 1: case 2: break;
20050
		default: throw new Error("Bad sheet visibility setting " + vis);
20051
	}
20052
	// $FlowIgnore
20053
	wb.Workbook.Sheets[idx].Hidden = vis;
20054
};
20055
add_consts([
20056
	["SHEET_VISIBLE", 0],
20057
	["SHEET_HIDDEN", 1],
20058
	["SHEET_VERY_HIDDEN", 2]
20059
]);
20060
20061
/* set number format */
20062
utils.cell_set_number_format = function(cell, fmt) {
20063
	cell.z = fmt;
20064
	return cell;
20065
};
20066
20067
/* set cell hyperlink */
20068
utils.cell_set_hyperlink = function(cell, target, tooltip) {
20069
	if(!target) {
20070
		delete cell.l;
20071
	} else {
20072
		cell.l = ({ Target: target });
20073
		if(tooltip) cell.l.Tooltip = tooltip;
20074
	}
20075
	return cell;
20076
};
20077
utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
20078
20079
/* add to cell comments */
20080
utils.cell_add_comment = function(cell, text, author) {
20081
	if(!cell.c) cell.c = [];
20082
	cell.c.push({t:text, a:author||"SheetJS"});
20083
};
20084
20085
/* set array formula and flush related cells */
20086
utils.sheet_set_array_formula = function(ws, range, formula) {
20087
	var rng = typeof range != "string" ? range : safe_decode_range(range);
20088
	var rngstr = typeof range == "string" ? range : encode_range(range);
20089
	for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
20090
		var cell = ws_get_cell_stub(ws, R, C);
20091
		cell.t = 'n';
20092
		cell.F = rngstr;
20093
		delete cell.v;
20094
		if(R == rng.s.r && C == rng.s.c) cell.f = formula;
20095
	}
20096
	return ws;
20097
};
20098
20099
return utils;
20100
})(utils);
20101
20102
if(has_buf && typeof require != 'undefined') (function() {
20103
	var Readable = require('stream').Readable;
20104
20105
	var write_csv_stream = function(sheet, opts) {
20106
		var stream = Readable();
20107
		var o = opts == null ? {} : opts;
20108
		if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
20109
		var r = safe_decode_range(sheet["!ref"]);
20110
		var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
20111
		var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
20112
		var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
20113
		var row = "", cols = [];
20114
		o.dense = Array.isArray(sheet);
20115
		var colinfo = o.skipHidden && sheet["!cols"] || [];
20116
		var rowinfo = o.skipHidden && sheet["!rows"] || [];
20117
		for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
20118
		var R = r.s.r;
20119
		var BOM = false;
20120
		stream._read = function() {
20121
			if(!BOM) { BOM = true; return stream.push("\uFEFF"); }
20122
			if(R > r.e.r) return stream.push(null);
20123
			while(R <= r.e.r) {
20124
				++R;
20125
				if ((rowinfo[R-1]||{}).hidden) continue;
20126
				row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o);
20127
				if(row != null) {
20128
					if(o.strip) row = row.replace(endregex,"");
20129
					stream.push(row + RS);
20130
					break;
20131
				}
20132
			}
20133
		};
20134
		return stream;
20135
	};
20136
20137
	var write_html_stream = function(ws, opts) {
20138
		var stream = Readable();
20139
20140
		var o = opts || {};
20141
		var header = o.header != null ? o.header : HTML_.BEGIN;
20142
		var footer = o.footer != null ? o.footer : HTML_.END;
20143
		stream.push(header);
20144
		var r = decode_range(ws['!ref']);
20145
		o.dense = Array.isArray(ws);
20146
		stream.push(HTML_._preamble(ws, r, o));
20147
		var R = r.s.r;
20148
		var end = false;
20149
		stream._read = function() {
20150
			if(R > r.e.r) {
20151
				if(!end) { end = true; stream.push("</table>" + footer); }
20152
				return stream.push(null);
20153
			}
20154
			while(R <= r.e.r) {
20155
				stream.push(HTML_._row(ws, r, R, o));
20156
				++R;
20157
				break;
20158
			}
20159
		};
20160
		return stream;
20161
	};
20162
20163
	var write_json_stream = function(sheet, opts) {
20164
		var stream = Readable({objectMode:true});
20165
20166
		if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
20167
		var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
20168
		var r = {s:{r:0,c:0},e:{r:0,c:0}};
20169
		var o = opts || {};
20170
		var range = o.range != null ? o.range : sheet["!ref"];
20171
		if(o.header === 1) header = 1;
20172
		else if(o.header === "A") header = 2;
20173
		else if(Array.isArray(o.header)) header = 3;
20174
		switch(typeof range) {
20175
			case 'string': r = safe_decode_range(range); break;
20176
			case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
20177
			default: r = range;
20178
		}
20179
		if(header > 0) offset = 0;
20180
		var rr = encode_row(r.s.r);
20181
		var cols = [];
20182
		var counter = 0;
20183
		var dense = Array.isArray(sheet);
20184
		var R = r.s.r, C = 0, CC = 0;
20185
		if(dense && !sheet[R]) sheet[R] = [];
20186
		for(C = r.s.c; C <= r.e.c; ++C) {
20187
			cols[C] = encode_col(C);
20188
			val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20189
			switch(header) {
20190
				case 1: hdr[C] = C - r.s.c; break;
20191
				case 2: hdr[C] = cols[C]; break;
20192
				case 3: hdr[C] = o.header[C - r.s.c]; break;
20193
				default:
20194
					if(val == null) val = {w: "__EMPTY", t: "s"};
20195
					vv = v = format_cell(val, null, o);
20196
					counter = 0;
20197
					for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
20198
					hdr[C] = vv;
20199
			}
20200
		}
20201
		R = r.s.r + offset;
20202
		stream._read = function() {
20203
			if(R > r.e.r) return stream.push(null);
20204
			while(R <= r.e.r) {
20205
				++R;
20206
				//if ((rowinfo[R-1]||{}).hidden) continue;
20207
				var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
20208
				if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
20209
					stream.push(row.row);
20210
					break;
20211
				}
20212
			}
20213
		};
20214
		return stream;
20215
	};
20216
20217
	XLSX.stream = {
20218
		to_json: write_json_stream,
20219
		to_html: write_html_stream,
20220
		to_csv: write_csv_stream
20221
	};
20222
})();
20223
20224
XLSX.parse_xlscfb = parse_xlscfb;
20225
XLSX.parse_ods = parse_ods;
20226
XLSX.parse_fods = parse_fods;
20227
XLSX.write_ods = write_ods;
20228
XLSX.parse_zip = parse_zip;
20229
XLSX.read = readSync; //xlsread
20230
XLSX.readFile = readFileSync; //readFile
20231
XLSX.readFileSync = readFileSync;
20232
XLSX.write = writeSync;
20233
XLSX.writeFile = writeFileSync;
20234
XLSX.writeFileSync = writeFileSync;
20235
XLSX.writeFileAsync = writeFileAsync;
20236
XLSX.utils = utils;
20237
XLSX.SSF = SSF;
20238
XLSX.CFB = CFB;
20239
}
20240
/*global define */
20241
if(typeof exports !== 'undefined') make_xlsx_lib(exports);
20242
else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
20243
else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
20244
else make_xlsx_lib(XLSX);
20245
/*exported XLS, ODS */
20246
var XLS = XLSX, ODS = XLSX;
20247