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.

third-party/js-xlsx/js-xlsx-0.13.5/xlsx.js   F
last analyzed

Complexity

Total Complexity 4713
Complexity/F 4.23

Size

Lines of Code 20242
Function Count 1114

Duplication

Duplicated Lines 20242
Ratio 100 %

Importance

Changes 0
Metric Value
eloc 15760
dl 20242
loc 20242
rs 0.8
c 0
b 0
f 0
wmc 4713
mnd 3599
bc 3599
fnc 1114
bpm 3.2307
cpm 4.2307
noi 268

1 Function

Rating   Name   Duplication   Size   Complexity  
F xlsx.js ➔ make_xlsx_lib 20234 20234 4708

How to fix   Duplicated Code    Complexity   

Duplicated Code

Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.

Common duplication problems, and corresponding solutions are:

Complexity

 Tip:   Before tackling complexity, make sure that you eliminate any duplication first. This often can reduce the size of classes significantly.

Complex classes like third-party/js-xlsx/js-xlsx-0.13.5/xlsx.js often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
2
/* vim: set ts=2: */
3
/*exported XLSX */
4
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
5 View Code Duplication
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);
0 ignored issues
show
Coding Style Best Practice introduced by
Using the Array constructor is generally discouraged. Consider using an array literal instead.
Loading history...
143
	/* jshint +W056 */
144
}
145
146
var s2a = function s2a(s) {
147
	// $FlowIgnore
148
	if(has_buf) return Buffer_from(s, "binary");
0 ignored issues
show
Bug introduced by
The call to Buffer_from seems to have too many arguments starting with s.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to fix_hijri seems to have too many arguments starting with d.
Loading history...
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;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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 "";
0 ignored issues
show
Bug introduced by
The variable out seems to not be initialized for all possible execution paths. Are you sure pad0 handles undefined variables?
Loading history...
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
751
				break;
752
			case '?': while(fmt.charAt(++i) === c){/* empty */} break;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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;
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable j here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable j here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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];
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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];
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable j here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The variable i is changed as part of the for loop for example by ++i on line 1631. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
1632
		if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
1633
	};
1634
	T = i = 0;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable T here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
1651
	T = i = 0;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
1964
				/* falls through */
1965
			case 'H': mt *= 60;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
1966
				/* falls through */
1967
			case 'M':
1968
				if(!time) throw new Error("Unsupported ISO Duration Field: M");
1969
				else mt *= 60;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable c here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
2143
		quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable eq here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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'); };
0 ignored issues
show
Bug introduced by
The call to Buffer_from seems to have too many arguments starting with data.
Loading history...
2284
	if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
2285
2286
	// $FlowIgnore
2287
	utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
0 ignored issues
show
Bug introduced by
The call to Buffer_from seems to have too many arguments starting with data.
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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
			}
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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;
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
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;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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; }
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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; }
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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) { }
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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 */
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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];
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
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 */}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_URLMoniker seems to have too many arguments starting with length.
Loading history...
4761
		case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
0 ignored issues
show
Bug introduced by
The call to parse_FileMoniker seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_HyperlinkString seems to have too many arguments starting with end - blob.l.
Loading history...
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
4782
	if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
4786
	if(flags & 0x0020) guid = blob.read_shift(16);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
4787
	if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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) {
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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; }
0 ignored issues
show
Bug introduced by
The call to parse_LongRGBA seems to have too many arguments starting with length.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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);
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
5128
	// collapsed: flags & 0x10
5129
	if(flags & 0x20) z.hidden = true;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
5130
	if(flags & 0x40) z.hpt = miyRw / 20;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
5421
	if(opts.biff == 2) ++blob.l;
5422
	var val = parse_Bes(blob, 2);
0 ignored issues
show
Bug introduced by
The call to parse_Bes seems to have too many arguments starting with 2.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
5437
	var xnum = parse_Xnum(blob, 8);
0 ignored issues
show
Bug introduced by
The call to parse_Xnum seems to have too many arguments starting with 8.
Loading history...
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)];
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RefU seems to have too many arguments starting with 6.
Loading history...
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)];
0 ignored issues
show
Bug introduced by
The call to parse_ArrayParsedFormula seems to have too many arguments starting with ref.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to parse_Ref8U seems to have too many arguments starting with length.
Loading history...
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
0 ignored issues
show
Bug introduced by
The call to parse_FtCmo seems to have too many arguments starting with 22.
Loading history...
5615
	var fts = parse_FtArray(blob, length-22, cmo[1]);
0 ignored issues
show
Bug introduced by
The call to parse_FtArray seems to have too many arguments starting with cmo.1.
Loading history...
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);
0 ignored issues
show
Unused Code introduced by
The variable controlInfo seems to be never used. Consider removing it.
Loading history...
Bug introduced by
The call to parse_ControlInfo seems to have too many arguments starting with 6.
Loading history...
5666
	var cchText = blob.read_shift(2);
5667
	/*var cbRuns = */blob.read_shift(2);
5668
	/*var ifntEmpty = */parseuint16(blob, 2);
0 ignored issues
show
Bug introduced by
The call to parseuint16 seems to have too many arguments starting with 2.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_Ref8U seems to have too many arguments starting with 8.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_Ref8U seems to have too many arguments starting with 8.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_Xnum seems to have too many arguments starting with 8.
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
5840
	++blob.l;
5841
	var num = parse_Xnum(blob, 8);
0 ignored issues
show
Bug introduced by
The call to parse_Xnum seems to have too many arguments starting with 8.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
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);
0 ignored issues
show
Debugging Code introduced by
console.log looks like debug code. Are you sure you do not want to remove it?
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable C here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_ws_cell_sylk seems to have too many arguments starting with opts.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable ri here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable R here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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];
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable C here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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) ) {
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable end here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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) ) {
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable end here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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'){}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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);
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cell_3 seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cell_3 seems to have too many arguments starting with length.
Loading history...
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) {
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cell_3 seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cell_3 seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cell_3 seems to have too many arguments starting with length.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
7358
				else if(R_n.indexOf("End") > 0){/* empty */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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)];
0 ignored issues
show
Bug introduced by
The call to parse_EncInfoStd seems to have too many arguments starting with vers.
Loading history...
7505
		case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
0 ignored issues
show
Bug introduced by
The call to parse_EncInfoExt seems to have too many arguments starting with blob.
Loading history...
7506
		case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
0 ignored issues
show
Bug introduced by
The call to parse_EncInfoAgl seems to have too many arguments starting with vers.
Loading history...
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];
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RC4Header seems to have too many arguments starting with length.
Loading history...
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)));
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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; }
0 ignored issues
show
Bug introduced by
The variable MDW is changed as part of the for loop for example by ++MDW on line 7812. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
7813
	MDW = _MDW;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable MDW here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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);
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable j here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLWideString seems to have too many arguments starting with length - 2.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_FontFlags seems to have too many arguments starting with 2.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_BrtColor seems to have too many arguments starting with 8.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLWideString seems to have too many arguments starting with length - 21.
Loading history...
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];
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
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;
0 ignored issues
show
Bug introduced by
The variable cnt is changed as part of the for loop for example by ++cnt on line 8555. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_FONTS_bin seems to have too many arguments starting with wb.
Loading history...
8663
	write_FILLS_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_FILLS_bin seems to have too many arguments starting with wb.
Loading history...
8664
	write_BORDERS_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_BORDERS_bin seems to have too many arguments starting with wb.
Loading history...
8665
	write_CELLSTYLEXFS_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_CELLSTYLEXFS_bin seems to have too many arguments starting with wb.
Loading history...
8666
	write_CELLXFS_bin(ba, opts.cellXfs);
8667
	write_STYLES_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_STYLES_bin seems to have too many arguments starting with wb.
Loading history...
8668
	write_DXFS_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_DXFS_bin seems to have too many arguments starting with wb.
Loading history...
8669
	write_TABLESTYLES_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_TABLESTYLES_bin seems to have too many arguments starting with wb.
Loading history...
8670
	write_COLORPALETTE_bin(ba, wb);
0 ignored issues
show
Bug introduced by
The call to write_COLORPALETTE_bin seems to have too many arguments starting with ba.
Loading history...
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; }
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like jszip should be capitalized.
Loading history...
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;
0 ignored issues
show
Bug introduced by
The call to parse_LongRGBA seems to have too many arguments starting with 4.
Loading history...
8974
		case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
0 ignored issues
show
Bug introduced by
The call to parse_ColorTheme seems to have too many arguments starting with 4.
Loading history...
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;
0 ignored issues
show
Bug introduced by
The call to parse_FullColorExt seems to have too many arguments starting with cb.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to parse_ExtProp seems to have too many arguments starting with end - blob.l.
Loading history...
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';
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
9068
	if(flags & 0x8) out.a = '1';
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
9083
				else if((R_n||"").indexOf("End") > 0){/* empty */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
9137
				else if((R_n||"").indexOf("End") > 0){/* empty */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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;
0 ignored issues
show
Bug introduced by
The variable _shapeid is changed as part of the while loop for example by 1000 on line 9177. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
9374
				else if((R_n||"").indexOf("End") > 0){/* empty */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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; }
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RgceArea_BIFF2 seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RgceArea_BIFF2 seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RgceLoc_BIFF2 seems to have too many arguments starting with length.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RgceLocRel_BIFF2 seems to have too many arguments starting with length.
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_PtgAttrSpaceType seems to have too many arguments starting with 2.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_PtgAttrSpaceType seems to have too many arguments starting with 2.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
This return has no effect and can be removed.
Loading history...
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); }
0 ignored issues
show
Bug introduced by
The call to parse_Xnum seems to have too many arguments starting with 8.
Loading history...
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;
0 ignored issues
show
Bug introduced by
The call to parse_Xnum seems to have too many arguments starting with 8.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_PtgNameX_BIFF5 seems to have too many arguments starting with length.
Loading history...
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)];
0 ignored issues
show
Bug introduced by
The call to parse_RgceElfLoc seems to have too many arguments starting with 4.
Loading history...
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]];})();
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
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();
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable e1 here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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();
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable e1 here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
10275
				stack.push(e2+" "+e1);
10276
				break;
10277
			case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
10278
				e1 = stack.pop(); e2 = stack.pop();
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable e1 here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
10279
				stack.push(e2+","+e1);
10280
				break;
10281
			case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
10282
				e1 = stack.pop(); e2 = stack.pop();
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable e1 here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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
0 ignored issues
show
Unused Code introduced by
The variable w seems to be never used. Consider removing it.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
10508
				/* falls through */
10509
				case 0:
10510
					// $FlowIgnore
10511
					sp = fill(" ", f[1][1]); break;
10512
				case 5: _left = false;
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLSCell seems to have too many arguments starting with 6.
Loading history...
10588
	if(opts.biff == 2) ++blob.l;
10589
	var val = parse_FormulaValue(blob,8);
0 ignored issues
show
Bug introduced by
The call to parse_FormulaValue seems to have too many arguments starting with 8.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable ri here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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;
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable i here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_ws_xml_cell seems to have too many arguments starting with idx.
Loading history...
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) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_ws_xml_data seems to have too many arguments starting with rels.
Loading history...
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}));
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
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;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
12651
	if(flags & 0x10) z.hidden = true;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
12652
	if(flags & 0x20) z.hpt = miyRw / 20;
0 ignored issues
show
introduced by
You have used a bitwise operator & in a condition. Did you maybe want to use the logical operator &&
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_RfX seems to have too many arguments starting with 16.
Loading history...
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); });
0 ignored issues
show
Bug introduced by
The call to parse_Xnum seems to have too many arguments starting with 8.
Loading history...
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) {
0 ignored issues
show
Bug introduced by
The variable ai is changed as part of the for loop for example by ++ai on line 13110. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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) {
0 ignored issues
show
Bug introduced by
The variable C is changed as part of the for loop for example by ++C on line 13152. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
Bug introduced by
The variable R is changed as part of the for loop for example by ++R on line 13152. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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};
0 ignored issues
show
Bug introduced by
The variable addr is changed as part of the for loop for example by encode_cell({IdentifierN...ntifierNode(R,false))}) on line 13158. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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); }
0 ignored issues
show
Bug introduced by
The variable seencol is changed as part of the while loop for example by true on line 13184. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
13274
				else if((R_n||"").indexOf("End") > 0){/* empty */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_WSFMTINFO seems to have too many arguments starting with ba.
Loading history...
13462
	write_COLINFOS(ba, ws, idx, opts, wb);
0 ignored issues
show
Bug introduced by
The call to write_COLINFOS seems to have too many arguments starting with idx.
Loading history...
13463
	write_CELLTABLE(ba, ws, idx, opts, wb);
0 ignored issues
show
Bug introduced by
The call to write_CELLTABLE seems to have too many arguments starting with wb.
Loading history...
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);
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_XLWideString seems to have too many arguments starting with length - 10.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
14192
				else if((R_n||"").indexOf("End") > 0){/* empty */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_BOOKVIEWS seems to have too many arguments starting with opts.
Loading history...
14289
	write_BUNDLESHS(ba, wb, opts);
0 ignored issues
show
Bug introduced by
The call to write_BUNDLESHS seems to have too many arguments starting with opts.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cs_bin seems to have too many arguments starting with themes.
Loading history...
14320
	return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
0 ignored issues
show
Bug introduced by
The call to parse_cs_xml seems to have too many arguments starting with themes.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_ms_bin seems to have too many arguments starting with data.
Loading history...
14325
	return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
0 ignored issues
show
Bug introduced by
The call to parse_ms_xml seems to have too many arguments starting with data.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_ds_bin seems to have too many arguments starting with data.
Loading history...
14330
	return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
0 ignored issues
show
Bug introduced by
The call to parse_ds_xml seems to have too many arguments starting with data.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_cc_xml seems to have too many arguments starting with name.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to parse_xlink_xml seems to have too many arguments starting with data.
Loading history...
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) {
0 ignored issues
show
introduced by
The function write_cs does not seem to be used and can be removed.
Loading history...
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";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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
0 ignored issues
show
Unused Code introduced by
The variable table seems to be never used. Consider removing it.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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
	}
0 ignored issues
show
Comprehensibility introduced by
There is no default case in this switch, so nothing gets returned when all cases fail. You might want to consider adding a default or return undefined explicitly.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to xlml_write_custprops seems to have too many arguments starting with opts.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_wb_xlml seems to have too many arguments starting with wb.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_names_xlml seems to have too many arguments starting with opts.
Loading history...
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;
0 ignored issues
show
Unused Code introduced by
The variable defheight seems to be never used. Consider removing it.
Loading history...
Unused Code introduced by
The variable defwidth seems to be never used. Consider removing it.
Loading history...
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': {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
16209
					//console.log("Zoom Level:", val[0]/val[1],val);
16210
				} break;
16211
				case 'SheetExt': {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
16212
					/* empty */
16213
				} break;
16214
				case 'SheetExtOptional': {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
16215
					/* empty */
16216
				} break;
16217
16218
				/* VBA */
16219
				case 'ObNoMacros': {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
16220
					/* empty */
16221
				} break;
16222
				case 'ObProj': {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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': {
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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];
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
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];
0 ignored issues
show
Complexity introduced by
A for in loop automatically includes the property of any prototype object, consider checking the key using hasOwnProperty.

When iterating over the keys of an object, this includes not only the keys of the object, but also keys contained in the prototype of that object. It is generally a best practice to check for these keys specifically:

var someObject;
for (var key in someObject) {
    if ( ! someObject.hasOwnProperty(key)) {
        continue; // Skip keys from the prototype.
    }

    doSomethingWith(key);
}
Loading history...
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));
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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));
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
16485
		/* falls through */
16486
		case "xla": if(!o.bookType) o.bookType = "xla";
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_ws_biff2_cell seems to have too many arguments starting with opts.
Loading history...
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);
0 ignored issues
show
Bug introduced by
The call to write_ws_biff2 seems to have too many arguments starting with wb.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_Number seems to have too many arguments starting with opts.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_Window1 seems to have too many arguments starting with opts.
Loading history...
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'){}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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) || "")) || "";
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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; }
0 ignored issues
show
Complexity Coding Style introduced by
You seem to be assigning a new value to the loop variable midx here. Please check if this was indeed your intention. Even if it was, consider using another kind of loop instead.
Loading history...
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"){}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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
0 ignored issues
show
Comprehensibility introduced by
Usage of the sequence operator is discouraged, since it may lead to obfuscated code.

The sequence or comma operator allows the inclusion of multiple expressions where only is permitted. The result of the sequence is the value of the last expression.

This operator is most often used in for statements.

Used in another places it can make code hard to read, especially when people do not realize it even exists as a seperate operator.

This check looks for usage of the sequence operator in locations where it is not necessary and could be replaced by a series of expressions or statements.

var a,b,c;

a = 1, b = 1,  c= 3;

could just as well be written as:

var a,b,c;

a = 1;
b = 1;
c = 3;

To learn more about the sequence operator, please refer to the MDN.

Loading history...
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);
0 ignored issues
show
Bug introduced by
The variable textptag seems to not be initialized for all possible execution paths. Are you sure parse_text_p handles undefined variables?
Loading history...
Bug introduced by
The call to parse_text_p seems to have too many arguments starting with textptag.
Loading history...
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 */}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_ws seems to have too many arguments starting with opts.
Loading history...
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();
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like jszip should be capitalized.
Loading history...
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) {}
0 ignored issues
show
Coding Style Comprehensibility Best Practice introduced by
Empty catch clauses should be used with caution; consider adding a comment why this is needed.
Loading history...
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();
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like jszip should be capitalized.
Loading history...
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 */}
0 ignored issues
show
Comprehensibility Documentation Best Practice introduced by
This code block is empty. Consider removing it or adding a comment to explain.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_ext_props seems to have too many arguments starting with opts.
Loading history...
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));
0 ignored issues
show
Bug introduced by
The call to write_cust_props seems to have too many arguments starting with opts.
Loading history...
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;
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like jszip should be capitalized.
Loading history...
19503
		case "binary": case "array": zip = new jszip(d, { base64:false }); break;
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like jszip should be capitalized.
Loading history...
19504
		case "buffer": zip = new jszip(d); break;
0 ignored issues
show
Coding Style Best Practice introduced by
By convention, constructors like jszip should be capitalized.
Loading history...
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');
0 ignored issues
show
Bug introduced by
The call to Buffer_from seems to have too many arguments starting with o.
Loading history...
19637
			else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
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');
0 ignored issues
show
Bug introduced by
The call to Buffer_from seems to have too many arguments starting with out.
Loading history...
19652
			else return out.split("").map(function(c) { return c.charCodeAt(0); });
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
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 */
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
19694
		case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
0 ignored issues
show
introduced by
This node falls through to the next case due to this statement. Please add a comment either directly below this line or between the cases to explain.
Loading history...
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;
0 ignored issues
show
Coding Style introduced by
Consider using undefined instead of void(0). It is equivalent and more straightforward to read.
Loading history...
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) {
0 ignored issues
show
Bug introduced by
The variable R is changed as part of the while loop for example by ++R on line 20124. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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) {
0 ignored issues
show
Bug introduced by
The variable row is changed as part of the while loop for example by make_csv_row(sheet, r, R - 1, cols, fs, rs, FS, o) on line 20126. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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) {
0 ignored issues
show
Bug introduced by
The variable R is changed as part of the while loop for example by ++R on line 20205. Only the value of the last iteration will be visible in this function if it is called after the loop.
Loading history...
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