UNPKG

711 kBJavaScriptView Raw
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 */
5var XLSX = {};
6function make_xlsx_lib(XLSX){
7XLSX.version = '0.15.2';
8var current_codepage = 1200, current_ansi = 1252;
9/*global cptable:true, window */
10if(typeof module !== "undefined" && typeof require !== 'undefined') {
11 if(typeof cptable === 'undefined') {
12 if(typeof global !== 'undefined') global.cptable = undefined;
13 else if(typeof window !== 'undefined') window.cptable = undefined;
14 }
15}
16
17var VALID_ANSI = [ 874, 932, 936, 949, 950 ];
18for(var i = 0; i <= 8; ++i) VALID_ANSI.push(1250 + i);
19/* ECMA-376 Part I 18.4.1 charset to codepage mapping */
20var CS2CP = ({
210: 1252, /* ANSI */
221: 65001, /* DEFAULT */
232: 65001, /* SYMBOL */
2477: 10000, /* MAC */
25128: 932, /* SHIFTJIS */
26129: 949, /* HANGUL */
27130: 1361, /* JOHAB */
28134: 936, /* GB2312 */
29136: 950, /* CHINESEBIG5 */
30161: 1253, /* GREEK */
31162: 1254, /* TURKISH */
32163: 1258, /* VIETNAMESE */
33177: 1255, /* HEBREW */
34178: 1256, /* ARABIC */
35186: 1257, /* BALTIC */
36204: 1251, /* RUSSIAN */
37222: 874, /* THAI */
38238: 1250, /* EASTEUROPE */
39255: 1252, /* OEM */
4069: 6969 /* MISC */
41});
42
43var set_ansi = function(cp) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; };
44function reset_ansi() { set_ansi(1252); }
45
46var set_cp = function(cp) { current_codepage = cp; set_ansi(cp); };
47function reset_cp() { set_cp(1200); reset_ansi(); }
48
49function char_codes(data) { var o = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
50
51function 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}
56function 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
62var 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
70var _getchar = function _gc1(x) { return String.fromCharCode(x); };
71var _getansi = function _ga1(x) { return String.fromCharCode(x); };
72if(typeof cptable !== 'undefined') {
73 set_cp = function(cp) { current_codepage = cp; set_ansi(cp); };
74 debom = function(data) {
75 if(data.charCodeAt(0) === 0xFF && data.charCodeAt(1) === 0xFE) { return cptable.utils.decode(1200, char_codes(data.slice(2))); }
76 return data;
77 };
78 _getchar = function _gc2(x) {
79 if(current_codepage === 1200) return String.fromCharCode(x);
80 return cptable.utils.decode(current_codepage, [x&255,x>>8])[0];
81 };
82 _getansi = function _ga2(x) {
83 return cptable.utils.decode(current_ansi, [x])[0];
84 };
85}
86var DENSE = null;
87var DIF_XL = true;
88var Base64 = (function make_b64(){
89 var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
90 return {
91 encode: function(input) {
92 var o = "";
93 var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
94 for(var i = 0; i < input.length; ) {
95 c1 = input.charCodeAt(i++);
96 e1 = (c1 >> 2);
97
98 c2 = input.charCodeAt(i++);
99 e2 = ((c1 & 3) << 4) | (c2 >> 4);
100
101 c3 = input.charCodeAt(i++);
102 e3 = ((c2 & 15) << 2) | (c3 >> 6);
103 e4 = (c3 & 63);
104 if (isNaN(c2)) { e3 = e4 = 64; }
105 else if (isNaN(c3)) { e4 = 64; }
106 o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
107 }
108 return o;
109 },
110 decode: function b64_decode(input) {
111 var o = "";
112 var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
113 input = input.replace(/[^\w\+\/\=]/g, "");
114 for(var i = 0; i < input.length;) {
115 e1 = map.indexOf(input.charAt(i++));
116 e2 = map.indexOf(input.charAt(i++));
117 c1 = (e1 << 2) | (e2 >> 4);
118 o += String.fromCharCode(c1);
119
120 e3 = map.indexOf(input.charAt(i++));
121 c2 = ((e2 & 15) << 4) | (e3 >> 2);
122 if (e3 !== 64) { o += String.fromCharCode(c2); }
123
124 e4 = map.indexOf(input.charAt(i++));
125 c3 = ((e3 & 3) << 6) | e4;
126 if (e4 !== 64) { o += String.fromCharCode(c3); }
127 }
128 return o;
129 }
130 };
131})();
132var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node);
133
134var Buffer_from = function(){};
135
136if(typeof Buffer !== 'undefined') {
137 var nbfs = !Buffer.from;
138 if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
139 Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
140 // $FlowIgnore
141 if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
142 // $FlowIgnore
143 if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
144}
145
146function new_raw_buf(len) {
147 /* jshint -W056 */
148 return has_buf ? Buffer.alloc(len) : new Array(len);
149 /* jshint +W056 */
150}
151
152function new_unsafe_buf(len) {
153 /* jshint -W056 */
154 return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
155 /* jshint +W056 */
156}
157
158var s2a = function s2a(s) {
159 if(has_buf) return Buffer_from(s, "binary");
160 return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
161};
162
163function s2ab(s) {
164 if(typeof ArrayBuffer === 'undefined') return s2a(s);
165 var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
166 for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
167 return buf;
168}
169
170function a2s(data) {
171 if(Array.isArray(data)) return data.map(function(c) { return String.fromCharCode(c); }).join("");
172 var o = []; for(var i = 0; i < data.length; ++i) o[i] = String.fromCharCode(data[i]); return o.join("");
173}
174
175function a2u(data) {
176 if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
177 return new Uint8Array(data);
178}
179
180function ab2a(data) {
181 if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
182 if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
183var o = new Array(data.length);
184 for(var i = 0; i < data.length; ++i) o[i] = data[i];
185 return o;
186}
187
188var bconcat = function(bufs) { return [].concat.apply([], bufs); };
189
190var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
191/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
192/*jshint -W041 */
193var SSF = ({});
194var make_ssf = function make_ssf(SSF){
195SSF.version = '0.10.2';
196function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
197function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
198function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
199function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
200function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
201function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
202function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
203var p2_32 = Math.pow(2,32);
204function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
205function 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; }
206var days = [
207 ['Sun', 'Sunday'],
208 ['Mon', 'Monday'],
209 ['Tue', 'Tuesday'],
210 ['Wed', 'Wednesday'],
211 ['Thu', 'Thursday'],
212 ['Fri', 'Friday'],
213 ['Sat', 'Saturday']
214];
215var months = [
216 ['J', 'Jan', 'January'],
217 ['F', 'Feb', 'February'],
218 ['M', 'Mar', 'March'],
219 ['A', 'Apr', 'April'],
220 ['M', 'May', 'May'],
221 ['J', 'Jun', 'June'],
222 ['J', 'Jul', 'July'],
223 ['A', 'Aug', 'August'],
224 ['S', 'Sep', 'September'],
225 ['O', 'Oct', 'October'],
226 ['N', 'Nov', 'November'],
227 ['D', 'Dec', 'December']
228];
229function init_table(t) {
230 t[0]= 'General';
231 t[1]= '0';
232 t[2]= '0.00';
233 t[3]= '#,##0';
234 t[4]= '#,##0.00';
235 t[9]= '0%';
236 t[10]= '0.00%';
237 t[11]= '0.00E+00';
238 t[12]= '# ?/?';
239 t[13]= '# ??/??';
240 t[14]= 'm/d/yy';
241 t[15]= 'd-mmm-yy';
242 t[16]= 'd-mmm';
243 t[17]= 'mmm-yy';
244 t[18]= 'h:mm AM/PM';
245 t[19]= 'h:mm:ss AM/PM';
246 t[20]= 'h:mm';
247 t[21]= 'h:mm:ss';
248 t[22]= 'm/d/yy h:mm';
249 t[37]= '#,##0 ;(#,##0)';
250 t[38]= '#,##0 ;[Red](#,##0)';
251 t[39]= '#,##0.00;(#,##0.00)';
252 t[40]= '#,##0.00;[Red](#,##0.00)';
253 t[45]= 'mm:ss';
254 t[46]= '[h]:mm:ss';
255 t[47]= 'mmss.0';
256 t[48]= '##0.0E+0';
257 t[49]= '@';
258 t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
259 t[65535]= 'General';
260}
261
262var table_fmt = {};
263init_table(table_fmt);
264function frac(x, D, mixed) {
265 var sgn = x < 0 ? -1 : 1;
266 var B = x * sgn;
267 var P_2 = 0, P_1 = 1, P = 0;
268 var Q_2 = 1, Q_1 = 0, Q = 0;
269 var A = Math.floor(B);
270 while(Q_1 < D) {
271 A = Math.floor(B);
272 P = A * P_1 + P_2;
273 Q = A * Q_1 + Q_2;
274 if((B - A) < 0.00000005) break;
275 B = 1 / (B - A);
276 P_2 = P_1; P_1 = P;
277 Q_2 = Q_1; Q_1 = Q;
278 }
279 if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
280 if(!mixed) return [0, sgn * P, Q];
281 var q = Math.floor(sgn * P/Q);
282 return [q, sgn*P - q*Q, Q];
283}
284function parse_date_code(v,opts,b2) {
285 if(v > 2958465 || v < 0) return null;
286 var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
287 var dout=[];
288 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};
289 if(Math.abs(out.u) < 1e-6) out.u = 0;
290 if(opts && opts.date1904) date += 1462;
291 if(out.u > 0.9999) {
292 out.u = 0;
293 if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
294 }
295 if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
296 else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
297 else {
298 if(date > 60) --date;
299 /* 1 = Jan 1 1900 in Gregorian */
300 var d = new Date(1900, 0, 1);
301 d.setDate(d.getDate() + date - 1);
302 dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
303 dow = d.getDay();
304 if(date < 60) dow = (dow + 6) % 7;
305 if(b2) dow = fix_hijri(d, dout);
306 }
307 out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
308 out.S = time % 60; time = Math.floor(time / 60);
309 out.M = time % 60; time = Math.floor(time / 60);
310 out.H = time;
311 out.q = dow;
312 return out;
313}
314SSF.parse_date_code = parse_date_code;
315var basedate = new Date(1899, 11, 31, 0, 0, 0);
316var dnthresh = basedate.getTime();
317var base1904 = new Date(1900, 2, 1, 0, 0, 0);
318function datenum_local(v, date1904) {
319 var epoch = v.getTime();
320 if(date1904) epoch -= 1461*24*60*60*1000;
321 else if(v >= base1904) epoch += 24*60*60*1000;
322 return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
323}
324function general_fmt_int(v) { return v.toString(10); }
325SSF._general_int = general_fmt_int;
326var general_fmt_num = (function make_general_fmt_num() {
327var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
328function gfn2(v) {
329 var w = (v<0?12:11);
330 var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
331 o = v.toPrecision(10); if(o.length <= w) return o;
332 return v.toExponential(5);
333}
334function gfn3(v) {
335 var o = v.toFixed(11).replace(gnr1,".$1");
336 if(o.length > (v<0?12:11)) o = v.toPrecision(6);
337 return o;
338}
339function gfn4(o) {
340 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");
341 return o;
342}
343function gfn5(o) {
344 return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
345}
346return function general_fmt_num(v) {
347 var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
348 if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
349 else if(Math.abs(V) <= 9) o = gfn2(v);
350 else if(V === 10) o = v.toFixed(10).substr(0,12);
351 else o = gfn3(v);
352 return gfn5(gfn4(o));
353};})();
354SSF._general_num = general_fmt_num;
355function general_fmt(v, opts) {
356 switch(typeof v) {
357 case 'string': return v;
358 case 'boolean': return v ? "TRUE" : "FALSE";
359 case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
360 case 'undefined': return "";
361 case 'object':
362 if(v == null) return "";
363 if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
364 }
365 throw new Error("unsupported value in General format: " + v);
366}
367SSF._general = general_fmt;
368function fix_hijri() { return 0; }
369/*jshint -W086 */
370function write_date(type, fmt, val, ss0) {
371 var o="", ss=0, tt=0, y = val.y, out, outl = 0;
372 switch(type) {
373 case 98: /* 'b' buddhist year */
374 y = val.y + 543;
375 /* falls through */
376 case 121: /* 'y' year */
377 switch(fmt.length) {
378 case 1: case 2: out = y % 100; outl = 2; break;
379 default: out = y % 10000; outl = 4; break;
380 } break;
381 case 109: /* 'm' month */
382 switch(fmt.length) {
383 case 1: case 2: out = val.m; outl = fmt.length; break;
384 case 3: return months[val.m-1][1];
385 case 5: return months[val.m-1][0];
386 default: return months[val.m-1][2];
387 } break;
388 case 100: /* 'd' day */
389 switch(fmt.length) {
390 case 1: case 2: out = val.d; outl = fmt.length; break;
391 case 3: return days[val.q][0];
392 default: return days[val.q][1];
393 } break;
394 case 104: /* 'h' 12-hour */
395 switch(fmt.length) {
396 case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
397 default: throw 'bad hour format: ' + fmt;
398 } break;
399 case 72: /* 'H' 24-hour */
400 switch(fmt.length) {
401 case 1: case 2: out = val.H; outl = fmt.length; break;
402 default: throw 'bad hour format: ' + fmt;
403 } break;
404 case 77: /* 'M' minutes */
405 switch(fmt.length) {
406 case 1: case 2: out = val.M; outl = fmt.length; break;
407 default: throw 'bad minute format: ' + fmt;
408 } break;
409 case 115: /* 's' seconds */
410 if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
411 if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
412if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
413 else tt = ss0 === 1 ? 10 : 1;
414 ss = Math.round((tt)*(val.S + val.u));
415 if(ss >= 60*tt) ss = 0;
416 if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
417 o = pad0(ss,2 + ss0);
418 if(fmt === 'ss') return o.substr(0,2);
419 return "." + o.substr(2,fmt.length-1);
420 case 90: /* 'Z' absolute time */
421 switch(fmt) {
422 case '[h]': case '[hh]': out = val.D*24+val.H; break;
423 case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
424 case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
425 default: throw 'bad abstime format: ' + fmt;
426 } outl = fmt.length === 3 ? 1 : 2; break;
427 case 101: /* 'e' era */
428 out = y; outl = 1;
429 }
430 if(outl > 0) return pad0(out, outl); else return "";
431}
432/*jshint +W086 */
433function commaify(s) {
434 var w = 3;
435 if(s.length <= w) return s;
436 var j = (s.length % w), o = s.substr(0,j);
437 for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
438 return o;
439}
440var write_num = (function make_write_num(){
441var pct1 = /%/g;
442function write_num_pct(type, fmt, val){
443 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
444 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
445}
446function write_num_cm(type, fmt, val){
447 var idx = fmt.length - 1;
448 while(fmt.charCodeAt(idx-1) === 44) --idx;
449 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
450}
451function write_num_exp(fmt, val){
452 var o;
453 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
454 if(fmt.match(/^#+0.0E\+0$/)) {
455 if(val == 0) return "0.0E+0";
456 else if(val < 0) return "-" + write_num_exp(fmt, -val);
457 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
458 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
459 if(ee < 0) ee += period;
460 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
461 if(o.indexOf("e") === -1) {
462 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
463 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
464 else o += "E+" + (fakee - ee);
465 while(o.substr(0,2) === "0.") {
466 o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
467 o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
468 }
469 o = o.replace(/\+-/,"-");
470 }
471 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
472 } else o = val.toExponential(idx);
473 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
474 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
475 return o.replace("e","E");
476}
477var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
478function write_num_f1(r, aval, sign) {
479 var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
480 var myn = (rr - base*den), myd = den;
481 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));
482}
483function write_num_f2(r, aval, sign) {
484 return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
485}
486var dec1 = /^#*0*\.([0#]+)/;
487var closeparen = /\).*[0#]/;
488var phone = /\(###\) ###\\?-####/;
489function hashq(str) {
490 var o = "", cc;
491 for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
492 case 35: break;
493 case 63: o+= " "; break;
494 case 48: o+= "0"; break;
495 default: o+= String.fromCharCode(cc);
496 }
497 return o;
498}
499function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
500function dec(val, d) {
501 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
502 return 0;
503 }
504 return Math.round((val-Math.floor(val))*Math.pow(10,d));
505}
506function carry(val, d) {
507 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
508 return 1;
509 }
510 return 0;
511}
512function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
513function write_num_flt(type, fmt, val) {
514 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
515 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
516 if(val >= 0) return write_num_flt('n', ffmt, val);
517 return '(' + write_num_flt('n', ffmt, -val) + ')';
518 }
519 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
520 if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
521 if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
522 if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
523 var o;
524 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
525 if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
526 if(fmt.match(/^[#?]+$/)) {
527 o = pad0r(val,0); if(o === "0") o = "";
528 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
529 }
530 if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
531 if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
532 if((r = fmt.match(dec1))) {
533 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); });
534 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
535 }
536 fmt = fmt.replace(/^#+([0.])/, "$1");
537 if((r = fmt.match(/^(0*)\.(#*)$/))) {
538 return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
539 }
540 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
541 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
542 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);
543 }
544 if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
545 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
546 o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
547 ri = 0;
548 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
549 }
550 if(fmt.match(phone)) {
551 o = write_num_flt(type, "##########", val);
552 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
553 }
554 var oa = "";
555 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
556 ri = Math.min(r[4].length,7);
557 ff = frac(aval, Math.pow(10,ri)-1, false);
558 o = "" + sign;
559 oa = write_num("n", r[1], ff[1]);
560 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
561 o += oa + r[2] + "/" + r[3];
562 oa = rpad_(ff[2],ri);
563 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
564 o += oa;
565 return o;
566 }
567 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
568 ri = Math.min(Math.max(r[1].length, r[4].length),7);
569 ff = frac(aval, Math.pow(10,ri)-1, true);
570 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));
571 }
572 if((r = fmt.match(/^[#0?]+$/))) {
573 o = pad0r(val, 0);
574 if(fmt.length <= o.length) return o;
575 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
576 }
577 if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
578 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
579 ri = o.indexOf(".");
580 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
581 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
582 }
583 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
584 ri = dec(val, r[1].length);
585 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);
586 }
587 switch(fmt) {
588 case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
589 case "###,###":
590 case "##,###":
591 case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
592 case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
593 case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
594 default:
595 }
596 throw new Error("unsupported format |" + fmt + "|");
597}
598function write_num_cm2(type, fmt, val){
599 var idx = fmt.length - 1;
600 while(fmt.charCodeAt(idx-1) === 44) --idx;
601 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
602}
603function write_num_pct2(type, fmt, val){
604 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
605 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
606}
607function write_num_exp2(fmt, val){
608 var o;
609 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
610 if(fmt.match(/^#+0.0E\+0$/)) {
611 if(val == 0) return "0.0E+0";
612 else if(val < 0) return "-" + write_num_exp2(fmt, -val);
613 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
614 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
615 if(ee < 0) ee += period;
616 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
617 if(!o.match(/[Ee]/)) {
618 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
619 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
620 else o += "E+" + (fakee - ee);
621 o = o.replace(/\+-/,"-");
622 }
623 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
624 } else o = val.toExponential(idx);
625 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
626 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
627 return o.replace("e","E");
628}
629function write_num_int(type, fmt, val) {
630 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
631 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
632 if(val >= 0) return write_num_int('n', ffmt, val);
633 return '(' + write_num_int('n', ffmt, -val) + ')';
634 }
635 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
636 if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
637 if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
638 if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
639 var o;
640 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
641 if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
642 if(fmt.match(/^[#?]+$/)) {
643 o = (""+val); if(val === 0) o = "";
644 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
645 }
646 if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
647 if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
648 if((r = fmt.match(dec1))) {
649o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
650 o = o.replace(/\.(\d*)$/,function($$, $1) {
651return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
652 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
653 }
654 fmt = fmt.replace(/^#+([0.])/, "$1");
655 if((r = fmt.match(/^(0*)\.(#*)$/))) {
656 return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
657 }
658 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
659 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
660 return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
661 }
662 if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
663 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
664 o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
665 ri = 0;
666 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
667 }
668 if(fmt.match(phone)) {
669 o = write_num_int(type, "##########", val);
670 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
671 }
672 var oa = "";
673 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
674 ri = Math.min(r[4].length,7);
675 ff = frac(aval, Math.pow(10,ri)-1, false);
676 o = "" + sign;
677 oa = write_num("n", r[1], ff[1]);
678 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
679 o += oa + r[2] + "/" + r[3];
680 oa = rpad_(ff[2],ri);
681 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
682 o += oa;
683 return o;
684 }
685 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
686 ri = Math.min(Math.max(r[1].length, r[4].length),7);
687 ff = frac(aval, Math.pow(10,ri)-1, true);
688 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));
689 }
690 if((r = fmt.match(/^[#0?]+$/))) {
691 o = "" + val;
692 if(fmt.length <= o.length) return o;
693 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
694 }
695 if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
696 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
697 ri = o.indexOf(".");
698 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
699 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
700 }
701 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
702 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);
703 }
704 switch(fmt) {
705 case "###,###":
706 case "##,###":
707 case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
708 default:
709 if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
710 }
711 throw new Error("unsupported format |" + fmt + "|");
712}
713return function write_num(type, fmt, val) {
714 return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
715};})();
716function split_fmt(fmt) {
717 var out = [];
718 var in_str = false/*, cc*/;
719 for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
720 case 34: /* '"' */
721 in_str = !in_str; break;
722 case 95: case 42: case 92: /* '_' '*' '\\' */
723 ++i; break;
724 case 59: /* ';' */
725 out[out.length] = fmt.substr(j,i-j);
726 j = i+1;
727 }
728 out[out.length] = fmt.substr(j);
729 if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
730 return out;
731}
732SSF._split = split_fmt;
733var abstime = /\[[HhMmSs]*\]/;
734function fmt_is_date(fmt) {
735 var i = 0, /*cc = 0,*/ c = "", o = "";
736 while(i < fmt.length) {
737 switch((c = fmt.charAt(i))) {
738 case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
739 case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
740 case '\\': i+=2; break;
741 case '_': i+=2; break;
742 case '@': ++i; break;
743 case 'B': case 'b':
744 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
745 /* falls through */
746 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
747 /* falls through */
748 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
749 case 'A': case 'a':
750 if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
751 if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
752 ++i; break;
753 case '[':
754 o = c;
755 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
756 if(o.match(abstime)) return true;
757 break;
758 case '.':
759 /* falls through */
760 case '0': case '#':
761 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 */}
762 break;
763 case '?': while(fmt.charAt(++i) === c){/* empty */} break;
764 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
765 case '(': case ')': ++i; break;
766 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
767 while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
768 case ' ': ++i; break;
769 default: ++i; break;
770 }
771 }
772 return false;
773}
774SSF.is_date = fmt_is_date;
775function eval_fmt(fmt, v, opts, flen) {
776 var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
777 var hr='H';
778 /* Tokenize */
779 while(i < fmt.length) {
780 switch((c = fmt.charAt(i))) {
781 case 'G': /* General */
782 if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
783 out[out.length] = {t:'G', v:'General'}; i+=7; break;
784 case '"': /* Literal text */
785 for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
786 out[out.length] = {t:'t', v:o}; ++i; break;
787 case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
788 out[out.length] = {t:t, v:w}; ++i; break;
789 case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
790 case '@': /* Text Placeholder */
791 out[out.length] = {t:'T', v:v}; ++i; break;
792 case 'B': case 'b':
793 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
794 if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
795 out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
796 }
797 /* falls through */
798 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
799 c = c.toLowerCase();
800 /* falls through */
801 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
802 if(v < 0) return "";
803 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
804 o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
805 if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
806 if(c === 'h') c = hr;
807 out[out.length] = {t:c, v:o}; lst = c; break;
808 case 'A': case 'a':
809 var q={t:c, v:c};
810 if(dt==null) dt=parse_date_code(v, opts);
811 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;}
812 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'; }
813 else { q.t = "t"; ++i; }
814 if(dt==null && q.t === 'T') return "";
815 out[out.length] = q; lst = c; break;
816 case '[':
817 o = c;
818 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
819 if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
820 if(o.match(abstime)) {
821 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
822 out[out.length] = {t:'Z', v:o.toLowerCase()};
823 lst = o.charAt(1);
824 } else if(o.indexOf("$") > -1) {
825 o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
826 if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
827 }
828 break;
829 /* Numbers */
830 case '.':
831 if(dt != null) {
832 o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
833 out[out.length] = {t:'s', v:o}; break;
834 }
835 /* falls through */
836 case '0': case '#':
837 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;
838 out[out.length] = {t:'n', v:o}; break;
839 case '?':
840 o = c; while(fmt.charAt(++i) === c) o+=c;
841 out[out.length] = {t:c, v:o}; lst = c; break;
842 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
843 case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
844 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
845 o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
846 out[out.length] = {t:'D', v:o}; break;
847 case ' ': out[out.length] = {t:c, v:c}; ++i; break;
848 default:
849 if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
850 out[out.length] = {t:'t', v:c}; ++i; break;
851 }
852 }
853 var bt = 0, ss0 = 0, ssm;
854 for(i=out.length-1, lst='t'; i >= 0; --i) {
855 switch(out[i].t) {
856 case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
857 case 's':
858 if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
859 if(bt < 3) bt = 3;
860 /* falls through */
861 case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
862 case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
863 case 'X': /*if(out[i].v === "B2");*/
864 break;
865 case 'Z':
866 if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
867 if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
868 if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
869 }
870 }
871 switch(bt) {
872 case 0: break;
873 case 1:
874if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
875 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
876 if(dt.M >= 60) { dt.M = 0; ++dt.H; }
877 break;
878 case 2:
879if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
880 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
881 break;
882 }
883 /* replace fields */
884 var nstr = "", jj;
885 for(i=0; i < out.length; ++i) {
886 switch(out[i].t) {
887 case 't': case 'T': case ' ': case 'D': break;
888 case 'X': out[i].v = ""; out[i].t = ";"; break;
889 case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
890out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
891 out[i].t = 't'; break;
892 case 'n': case '(': case '?':
893 jj = i+1;
894 while(out[jj] != null && (
895 (c=out[jj].t) === "?" || c === "D" ||
896 ((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
897 (out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
898 (c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
899 )) {
900 out[i].v += out[jj].v;
901 out[jj] = {v:"", t:";"}; ++jj;
902 }
903 nstr += out[i].v;
904 i = jj-1; break;
905 case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
906 }
907 }
908 var vv = "", myv, ostr;
909 if(nstr.length > 0) {
910 if(nstr.charCodeAt(0) == 40) /* '(' */ {
911 myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
912 ostr = write_num('(', nstr, myv);
913 } else {
914 myv = (v<0 && flen > 1 ? -v : v);
915 ostr = write_num('n', nstr, myv);
916 if(myv < 0 && out[0] && out[0].t == 't') {
917 ostr = ostr.substr(1);
918 out[0].v = "-" + out[0].v;
919 }
920 }
921 jj=ostr.length-1;
922 var decpt = out.length;
923 for(i=0; i < out.length; ++i) if(out[i] != null && out[i].t != 't' && out[i].v.indexOf(".") > -1) { decpt = i; break; }
924 var lasti=out.length;
925 if(decpt === out.length && ostr.indexOf("E") === -1) {
926 for(i=out.length-1; i>= 0;--i) {
927 if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
928 if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
929 else if(jj < 0) out[i].v = "";
930 else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
931 out[i].t = 't';
932 lasti = i;
933 }
934 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
935 }
936 else if(decpt !== out.length && ostr.indexOf("E") === -1) {
937 jj = ostr.indexOf(".")-1;
938 for(i=decpt; i>= 0; --i) {
939 if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
940 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
941 vv = out[i].v.substr(j+1);
942 for(; j>=0; --j) {
943 if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
944 }
945 out[i].v = vv;
946 out[i].t = 't';
947 lasti = i;
948 }
949 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
950 jj = ostr.indexOf(".")+1;
951 for(i=decpt; i<out.length; ++i) {
952 if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
953 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
954 vv = out[i].v.substr(0,j);
955 for(; j<out[i].v.length; ++j) {
956 if(jj<ostr.length) vv += ostr.charAt(jj++);
957 }
958 out[i].v = vv;
959 out[i].t = 't';
960 lasti = i;
961 }
962 }
963 }
964 for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
965 myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
966 out[i].v = write_num(out[i].t, out[i].v, myv);
967 out[i].t = 't';
968 }
969 var retval = "";
970 for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
971 return retval;
972}
973SSF._eval = eval_fmt;
974var cfregex = /\[[=<>]/;
975var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
976function chkcond(v, rr) {
977 if(rr == null) return false;
978 var thresh = parseFloat(rr[2]);
979 switch(rr[1]) {
980 case "=": if(v == thresh) return true; break;
981 case ">": if(v > thresh) return true; break;
982 case "<": if(v < thresh) return true; break;
983 case "<>": if(v != thresh) return true; break;
984 case ">=": if(v >= thresh) return true; break;
985 case "<=": if(v <= thresh) return true; break;
986 }
987 return false;
988}
989function choose_fmt(f, v) {
990 var fmt = split_fmt(f);
991 var l = fmt.length, lat = fmt[l-1].indexOf("@");
992 if(l<4 && lat>-1) --l;
993 if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
994 if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
995 switch(fmt.length) {
996 case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
997 case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
998 case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
999 case 4: break;
1000 }
1001 var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
1002 if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
1003 if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
1004 var m1 = fmt[0].match(cfregex2);
1005 var m2 = fmt[1].match(cfregex2);
1006 return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
1007 }
1008 return [l, ff];
1009}
1010function format(fmt,v,o) {
1011 if(o == null) o = {};
1012 var sfmt = "";
1013 switch(typeof fmt) {
1014 case "string":
1015 if(fmt == "m/d/yy" && o.dateNF) sfmt = o.dateNF;
1016 else sfmt = fmt;
1017 break;
1018 case "number":
1019 if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
1020 else sfmt = (o.table != null ? (o.table) : table_fmt)[fmt];
1021 break;
1022 }
1023 if(isgeneral(sfmt,0)) return general_fmt(v, o);
1024 if(v instanceof Date) v = datenum_local(v, o.date1904);
1025 var f = choose_fmt(sfmt, v);
1026 if(isgeneral(f[1])) return general_fmt(v, o);
1027 if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
1028 else if(v === "" || v == null) return "";
1029 return eval_fmt(f[1], v, o, f[0]);
1030}
1031function load_entry(fmt, idx) {
1032 if(typeof idx != 'number') {
1033 idx = +idx || -1;
1034for(var i = 0; i < 0x0188; ++i) {
1035if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
1036 if(table_fmt[i] == fmt) { idx = i; break; }
1037 }
1038if(idx < 0) idx = 0x187;
1039 }
1040table_fmt[idx] = fmt;
1041 return idx;
1042}
1043SSF.load = load_entry;
1044SSF._table = table_fmt;
1045SSF.get_table = function get_table() { return table_fmt; };
1046SSF.load_table = function load_table(tbl) {
1047 for(var i=0; i!=0x0188; ++i)
1048 if(tbl[i] !== undefined) load_entry(tbl[i], i);
1049};
1050SSF.init_table = init_table;
1051SSF.format = format;
1052};
1053make_ssf(SSF);
1054/* map from xlml named formats to SSF TODO: localize */
1055var XLMLFormatMap/*{[string]:string}*/ = ({
1056 "General Number": "General",
1057 "General Date": SSF._table[22],
1058 "Long Date": "dddd, mmmm dd, yyyy",
1059 "Medium Date": SSF._table[15],
1060 "Short Date": SSF._table[14],
1061 "Long Time": SSF._table[19],
1062 "Medium Time": SSF._table[18],
1063 "Short Time": SSF._table[20],
1064 "Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1065 "Fixed": SSF._table[2],
1066 "Standard": SSF._table[4],
1067 "Percent": SSF._table[10],
1068 "Scientific": SSF._table[11],
1069 "Yes/No": '"Yes";"Yes";"No";@',
1070 "True/False": '"True";"True";"False";@',
1071 "On/Off": '"Yes";"Yes";"No";@'
1072});
1073
1074var SSFImplicit/*{[number]:string}*/ = ({
1075 "5": '"$"#,##0_);\\("$"#,##0\\)',
1076 "6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1077 "7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1078 "8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1079 "23": 'General', "24": 'General', "25": 'General', "26": 'General',
1080 "27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
1081 "32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
1082 "36": 'm/d/yy',
1083 "41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
1084 "42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
1085 "43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
1086 "44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
1087 "50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
1088 "55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
1089 "59": '0',
1090 "60": '0.00',
1091 "61": '#,##0',
1092 "62": '#,##0.00',
1093 "63": '"$"#,##0_);\\("$"#,##0\\)',
1094 "64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1095 "65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1096 "66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1097 "67": '0%',
1098 "68": '0.00%',
1099 "69": '# ?/?',
1100 "70": '# ??/??',
1101 "71": 'm/d/yy',
1102 "72": 'm/d/yy',
1103 "73": 'd-mmm-yy',
1104 "74": 'd-mmm',
1105 "75": 'mmm-yy',
1106 "76": 'h:mm',
1107 "77": 'h:mm:ss',
1108 "78": 'm/d/yy h:mm',
1109 "79": 'mm:ss',
1110 "80": '[h]:mm:ss',
1111 "81": 'mmss.0'
1112});
1113
1114/* dateNF parse TODO: move to SSF */
1115var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
1116function dateNF_regex(dateNF) {
1117 var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF;
1118 fmt = fmt.replace(dateNFregex, "(\\d+)");
1119 return new RegExp("^" + fmt + "$");
1120}
1121function dateNF_fix(str, dateNF, match) {
1122 var Y = -1, m = -1, d = -1, H = -1, M = -1, S = -1;
1123 (dateNF.match(dateNFregex)||[]).forEach(function(n, i) {
1124 var v = parseInt(match[i+1], 10);
1125 switch(n.toLowerCase().charAt(0)) {
1126 case 'y': Y = v; break; case 'd': d = v; break;
1127 case 'h': H = v; break; case 's': S = v; break;
1128 case 'm': if(H >= 0) M = v; else m = v; break;
1129 }
1130 });
1131 if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
1132 var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
1133 if(datestr.length == 7) datestr = "0" + datestr;
1134 if(datestr.length == 8) datestr = "20" + datestr;
1135 var timestr = (("00" + (H>=0?H:0)).slice(-2) + ":" + ("00" + (M>=0?M:0)).slice(-2) + ":" + ("00" + (S>=0?S:0)).slice(-2));
1136 if(H == -1 && M == -1 && S == -1) return datestr;
1137 if(Y == -1 && m == -1 && d == -1) return timestr;
1138 return datestr + "T" + timestr;
1139}
1140
1141var DO_NOT_EXPORT_CFB = true;
1142/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
1143/* vim: set ts=2: */
1144/*jshint eqnull:true */
1145/*exported CFB */
1146/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
1147
1148/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
1149/* vim: set ts=2: */
1150/*exported CRC32 */
1151var CRC32;
1152(function (factory) {
1153 /*jshint ignore:start */
1154 /*eslint-disable */
1155 factory(CRC32 = {});
1156 /*eslint-enable */
1157 /*jshint ignore:end */
1158}(function(CRC32) {
1159CRC32.version = '1.2.0';
1160/* see perf/crc32table.js */
1161/*global Int32Array */
1162function signed_crc_table() {
1163 var c = 0, table = new Array(256);
1164
1165 for(var n =0; n != 256; ++n){
1166 c = n;
1167 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1168 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1169 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1170 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1171 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1172 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1173 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1174 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1175 table[n] = c;
1176 }
1177
1178 return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
1179}
1180
1181var T = signed_crc_table();
1182function crc32_bstr(bstr, seed) {
1183 var C = seed ^ -1, L = bstr.length - 1;
1184 for(var i = 0; i < L;) {
1185 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1186 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1187 }
1188 if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
1189 return C ^ -1;
1190}
1191
1192function crc32_buf(buf, seed) {
1193 if(buf.length > 10000) return crc32_buf_8(buf, seed);
1194 var C = seed ^ -1, L = buf.length - 3;
1195 for(var i = 0; i < L;) {
1196 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1197 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1198 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1199 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1200 }
1201 while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1202 return C ^ -1;
1203}
1204
1205function crc32_buf_8(buf, seed) {
1206 var C = seed ^ -1, L = buf.length - 7;
1207 for(var i = 0; i < L;) {
1208 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1209 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1210 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1211 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1212 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1213 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1214 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1215 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1216 }
1217 while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1218 return C ^ -1;
1219}
1220
1221function crc32_str(str, seed) {
1222 var C = seed ^ -1;
1223 for(var i = 0, L=str.length, c, d; i < L;) {
1224 c = str.charCodeAt(i++);
1225 if(c < 0x80) {
1226 C = (C>>>8) ^ T[(C ^ c)&0xFF];
1227 } else if(c < 0x800) {
1228 C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
1229 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1230 } else if(c >= 0xD800 && c < 0xE000) {
1231 c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
1232 C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
1233 C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
1234 C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
1235 C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
1236 } else {
1237 C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
1238 C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
1239 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1240 }
1241 }
1242 return C ^ -1;
1243}
1244CRC32.table = T;
1245CRC32.bstr = crc32_bstr;
1246CRC32.buf = crc32_buf;
1247CRC32.str = crc32_str;
1248}));
1249/* [MS-CFB] v20171201 */
1250var CFB = (function _CFB(){
1251var exports = {};
1252exports.version = '1.1.3';
1253/* [MS-CFB] 2.6.4 */
1254function namecmp(l, r) {
1255 var L = l.split("/"), R = r.split("/");
1256 for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
1257 if((c = L[i].length - R[i].length)) return c;
1258 if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
1259 }
1260 return L.length - R.length;
1261}
1262function dirname(p) {
1263 if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
1264 var c = p.lastIndexOf("/");
1265 return (c === -1) ? p : p.slice(0, c+1);
1266}
1267
1268function filename(p) {
1269 if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
1270 var c = p.lastIndexOf("/");
1271 return (c === -1) ? p : p.slice(c+1);
1272}
1273/* -------------------------------------------------------------------------- */
1274/* DOS Date format:
1275 high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
1276 add 1980 to stored year
1277 stored second should be doubled
1278*/
1279
1280/* write JS date to buf as a DOS date */
1281function write_dos_date(buf, date) {
1282 if(typeof date === "string") date = new Date(date);
1283 var hms = date.getHours();
1284 hms = hms << 6 | date.getMinutes();
1285 hms = hms << 5 | (date.getSeconds()>>>1);
1286 buf.write_shift(2, hms);
1287 var ymd = (date.getFullYear() - 1980);
1288 ymd = ymd << 4 | (date.getMonth()+1);
1289 ymd = ymd << 5 | date.getDate();
1290 buf.write_shift(2, ymd);
1291}
1292
1293/* read four bytes from buf and interpret as a DOS date */
1294function parse_dos_date(buf) {
1295 var hms = buf.read_shift(2) & 0xFFFF;
1296 var ymd = buf.read_shift(2) & 0xFFFF;
1297 var val = new Date();
1298 var d = ymd & 0x1F; ymd >>>= 5;
1299 var m = ymd & 0x0F; ymd >>>= 4;
1300 val.setMilliseconds(0);
1301 val.setFullYear(ymd + 1980);
1302 val.setMonth(m-1);
1303 val.setDate(d);
1304 var S = hms & 0x1F; hms >>>= 5;
1305 var M = hms & 0x3F; hms >>>= 6;
1306 val.setHours(hms);
1307 val.setMinutes(M);
1308 val.setSeconds(S<<1);
1309 return val;
1310}
1311function parse_extra_field(blob) {
1312 prep_blob(blob, 0);
1313 var o = {};
1314 var flags = 0;
1315 while(blob.l <= blob.length - 4) {
1316 var type = blob.read_shift(2);
1317 var sz = blob.read_shift(2), tgt = blob.l + sz;
1318 var p = {};
1319 switch(type) {
1320 /* UNIX-style Timestamps */
1321 case 0x5455: {
1322 flags = blob.read_shift(1);
1323 if(flags & 1) p.mtime = blob.read_shift(4);
1324 /* for some reason, CD flag corresponds to LFH */
1325 if(sz > 5) {
1326 if(flags & 2) p.atime = blob.read_shift(4);
1327 if(flags & 4) p.ctime = blob.read_shift(4);
1328 }
1329 if(p.mtime) p.mt = new Date(p.mtime*1000);
1330 }
1331 break;
1332 }
1333 blob.l = tgt;
1334 o[type] = p;
1335 }
1336 return o;
1337}
1338var fs;
1339function get_fs() { return fs || (fs = require('fs')); }
1340function parse(file, options) {
1341if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
1342if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
1343var mver = 3;
1344var ssz = 512;
1345var nmfs = 0; // number of mini FAT sectors
1346var difat_sec_cnt = 0;
1347var dir_start = 0;
1348var minifat_start = 0;
1349var difat_start = 0;
1350
1351var fat_addrs = []; // locations of FAT sectors
1352
1353/* [MS-CFB] 2.2 Compound File Header */
1354var blob = file.slice(0,512);
1355prep_blob(blob, 0);
1356
1357/* major version */
1358var mv = check_get_mver(blob);
1359mver = mv[0];
1360switch(mver) {
1361 case 3: ssz = 512; break; case 4: ssz = 4096; break;
1362 case 0: if(mv[1] == 0) return parse_zip(file, options);
1363 /* falls through */
1364 default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
1365}
1366
1367/* reprocess header */
1368if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
1369/* Save header for final object */
1370var header = file.slice(0,ssz);
1371
1372check_shifts(blob, mver);
1373
1374// Number of Directory Sectors
1375var dir_cnt = blob.read_shift(4, 'i');
1376if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
1377
1378// Number of FAT Sectors
1379blob.l += 4;
1380
1381// First Directory Sector Location
1382dir_start = blob.read_shift(4, 'i');
1383
1384// Transaction Signature
1385blob.l += 4;
1386
1387// Mini Stream Cutoff Size
1388blob.chk('00100000', 'Mini Stream Cutoff Size: ');
1389
1390// First Mini FAT Sector Location
1391minifat_start = blob.read_shift(4, 'i');
1392
1393// Number of Mini FAT Sectors
1394nmfs = blob.read_shift(4, 'i');
1395
1396// First DIFAT sector location
1397difat_start = blob.read_shift(4, 'i');
1398
1399// Number of DIFAT Sectors
1400difat_sec_cnt = blob.read_shift(4, 'i');
1401
1402// Grab FAT Sector Locations
1403for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
1404 q = blob.read_shift(4, 'i');
1405 if(q<0) break;
1406 fat_addrs[j] = q;
1407}
1408
1409/** Break the file up into sectors */
1410var sectors = sectorify(file, ssz);
1411
1412sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
1413
1414/** Chains */
1415var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);
1416
1417sector_list[dir_start].name = "!Directory";
1418if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
1419sector_list[fat_addrs[0]].name = "!FAT";
1420sector_list.fat_addrs = fat_addrs;
1421sector_list.ssz = ssz;
1422
1423/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1424var files = {}, Paths = [], FileIndex = [], FullPaths = [];
1425read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
1426
1427build_full_paths(FileIndex, FullPaths, Paths);
1428Paths.shift();
1429
1430var o = {
1431 FileIndex: FileIndex,
1432 FullPaths: FullPaths
1433};
1434
1435// $FlowIgnore
1436if(options && options.raw) o.raw = {header: header, sectors: sectors};
1437return o;
1438} // parse
1439
1440/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
1441function check_get_mver(blob) {
1442 if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
1443 // header signature 8
1444 blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
1445
1446 // clsid 16
1447 //blob.chk(HEADER_CLSID, 'CLSID: ');
1448 blob.l += 16;
1449
1450 // minor version 2
1451 var mver = blob.read_shift(2, 'u');
1452
1453 return [blob.read_shift(2,'u'), mver];
1454}
1455function check_shifts(blob, mver) {
1456 var shift = 0x09;
1457
1458 // Byte Order
1459 //blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff
1460 blob.l += 2;
1461
1462 // Sector Shift
1463 switch((shift = blob.read_shift(2))) {
1464 case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;
1465 case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;
1466 default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);
1467 }
1468
1469 // Mini Sector Shift
1470 blob.chk('0600', 'Mini Sector Shift: ');
1471
1472 // Reserved
1473 blob.chk('000000000000', 'Reserved: ');
1474}
1475
1476/** Break the file up into sectors */
1477function sectorify(file, ssz) {
1478 var nsectors = Math.ceil(file.length/ssz)-1;
1479 var sectors = [];
1480 for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
1481 sectors[nsectors-1] = file.slice(nsectors*ssz);
1482 return sectors;
1483}
1484
1485/* [MS-CFB] 2.6.4 Red-Black Tree */
1486function build_full_paths(FI, FP, Paths) {
1487 var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
1488 var dad = [], q = [];
1489
1490 for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
1491
1492 for(; j < q.length; ++j) {
1493 i = q[j];
1494 L = FI[i].L; R = FI[i].R; C = FI[i].C;
1495 if(dad[i] === i) {
1496 if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
1497 if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
1498 }
1499 if(C !== -1 /*NOSTREAM*/) dad[C] = i;
1500 if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
1501 if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
1502 }
1503 for(i=1; i < pl; ++i) if(dad[i] === i) {
1504 if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
1505 else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
1506 }
1507
1508 for(i=1; i < pl; ++i) {
1509 if(FI[i].type === 0 /* unknown */) continue;
1510 j = i;
1511 if(j != dad[j]) do {
1512 j = dad[j];
1513 FP[i] = FP[j] + "/" + FP[i];
1514 } while (j !== 0 && -1 !== dad[j] && j != dad[j]);
1515 dad[i] = -1;
1516 }
1517
1518 FP[0] += "/";
1519 for(i=1; i < pl; ++i) {
1520 if(FI[i].type !== 2 /* stream */) FP[i] += "/";
1521 }
1522}
1523
1524function get_mfat_entry(entry, payload, mini) {
1525 var start = entry.start, size = entry.size;
1526 //return (payload.slice(start*MSSZ, start*MSSZ + size));
1527 var o = [];
1528 var idx = start;
1529 while(mini && size > 0 && idx >= 0) {
1530 o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
1531 size -= MSSZ;
1532 idx = __readInt32LE(mini, idx * 4);
1533 }
1534 if(o.length === 0) return (new_buf(0));
1535 return (bconcat(o).slice(0, entry.size));
1536}
1537
1538/** Chase down the rest of the DIFAT chain to build a comprehensive list
1539 DIFAT chains by storing the next sector number as the last 32 bits */
1540function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
1541 var q = ENDOFCHAIN;
1542 if(idx === ENDOFCHAIN) {
1543 if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
1544 } else if(idx !== -1 /*FREESECT*/) {
1545 var sector = sectors[idx], m = (ssz>>>2)-1;
1546 if(!sector) return;
1547 for(var i = 0; i < m; ++i) {
1548 if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1549 fat_addrs.push(q);
1550 }
1551 sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
1552 }
1553}
1554
1555/** Follow the linked list of sectors for a given starting point */
1556function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
1557 var buf = [], buf_chain = [];
1558 if(!chkd) chkd = [];
1559 var modulus = ssz - 1, j = 0, jj = 0;
1560 for(j=start; j>=0;) {
1561 chkd[j] = true;
1562 buf[buf.length] = j;
1563 buf_chain.push(sectors[j]);
1564 var addr = fat_addrs[Math.floor(j*4/ssz)];
1565 jj = ((j*4) & modulus);
1566 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1567 if(!sectors[addr]) break;
1568 j = __readInt32LE(sectors[addr], jj);
1569 }
1570 return {nodes: buf, data:__toBuffer([buf_chain])};
1571}
1572
1573/** Chase down the sector linked lists */
1574function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
1575 var sl = sectors.length, sector_list = ([]);
1576 var chkd = [], buf = [], buf_chain = [];
1577 var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
1578 for(i=0; i < sl; ++i) {
1579 buf = ([]);
1580 k = (i + dir_start); if(k >= sl) k-=sl;
1581 if(chkd[k]) continue;
1582 buf_chain = [];
1583 for(j=k; j>=0;) {
1584 chkd[j] = true;
1585 buf[buf.length] = j;
1586 buf_chain.push(sectors[j]);
1587 var addr = fat_addrs[Math.floor(j*4/ssz)];
1588 jj = ((j*4) & modulus);
1589 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1590 if(!sectors[addr]) break;
1591 j = __readInt32LE(sectors[addr], jj);
1592 }
1593 sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
1594 }
1595 return sector_list;
1596}
1597
1598/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1599function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {
1600 var minifat_store = 0, pl = (Paths.length?2:0);
1601 var sector = sector_list[dir_start].data;
1602 var i = 0, namelen = 0, name;
1603 for(; i < sector.length; i+= 128) {
1604 var blob = sector.slice(i, i+128);
1605 prep_blob(blob, 64);
1606 namelen = blob.read_shift(2);
1607 name = __utf16le(blob,0,namelen-pl);
1608 Paths.push(name);
1609 var o = ({
1610 name: name,
1611 type: blob.read_shift(1),
1612 color: blob.read_shift(1),
1613 L: blob.read_shift(4, 'i'),
1614 R: blob.read_shift(4, 'i'),
1615 C: blob.read_shift(4, 'i'),
1616 clsid: blob.read_shift(16),
1617 state: blob.read_shift(4, 'i'),
1618 start: 0,
1619 size: 0
1620 });
1621 var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1622 if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1623 var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1624 if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1625 o.start = blob.read_shift(4, 'i');
1626 o.size = blob.read_shift(4, 'i');
1627 if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1628 if(o.type === 5) { /* root */
1629 minifat_store = o.start;
1630 if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1631 /*minifat_size = o.size;*/
1632 } else if(o.size >= 4096 /* MSCSZ */) {
1633 o.storage = 'fat';
1634 if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1635 sector_list[o.start].name = o.name;
1636 o.content = (sector_list[o.start].data.slice(0,o.size));
1637 } else {
1638 o.storage = 'minifat';
1639 if(o.size < 0) o.size = 0;
1640 else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1641 o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1642 }
1643 }
1644 if(o.content) prep_blob(o.content, 0);
1645 files[name] = o;
1646 FileIndex.push(o);
1647 }
1648}
1649
1650function read_date(blob, offset) {
1651 return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1652}
1653
1654function read_file(filename, options) {
1655 get_fs();
1656 return parse(fs.readFileSync(filename), options);
1657}
1658
1659function read(blob, options) {
1660 switch(options && options.type || "base64") {
1661 case "file": return read_file(blob, options);
1662 case "base64": return parse(s2a(Base64.decode(blob)), options);
1663 case "binary": return parse(s2a(blob), options);
1664 }
1665 return parse(blob, options);
1666}
1667
1668function init_cfb(cfb, opts) {
1669 var o = opts || {}, root = o.root || "Root Entry";
1670 if(!cfb.FullPaths) cfb.FullPaths = [];
1671 if(!cfb.FileIndex) cfb.FileIndex = [];
1672 if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1673 if(cfb.FullPaths.length === 0) {
1674 cfb.FullPaths[0] = root + "/";
1675 cfb.FileIndex[0] = ({ name: root, type: 5 });
1676 }
1677 if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1678 seed_cfb(cfb);
1679}
1680function seed_cfb(cfb) {
1681 var nm = "\u0001Sh33tJ5";
1682 if(CFB.find(cfb, "/" + nm)) return;
1683 var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1684 cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));
1685 cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1686 rebuild_cfb(cfb);
1687}
1688function rebuild_cfb(cfb, f) {
1689 init_cfb(cfb);
1690 var gc = false, s = false;
1691 for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1692 var _file = cfb.FileIndex[i];
1693 switch(_file.type) {
1694 case 0:
1695 if(s) gc = true;
1696 else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1697 break;
1698 case 1: case 2: case 5:
1699 s = true;
1700 if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1701 if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1702 break;
1703 default: gc = true; break;
1704 }
1705 }
1706 if(!gc && !f) return;
1707
1708 var now = new Date(1987, 1, 19), j = 0;
1709 var data = [];
1710 for(i = 0; i < cfb.FullPaths.length; ++i) {
1711 if(cfb.FileIndex[i].type === 0) continue;
1712 data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1713 }
1714 for(i = 0; i < data.length; ++i) {
1715 var dad = dirname(data[i][0]);
1716 s = false;
1717 for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1718 if(!s) data.push([dad, ({
1719 name: filename(dad).replace("/",""),
1720 type: 1,
1721 clsid: HEADER_CLSID,
1722 ct: now, mt: now,
1723 content: null
1724 })]);
1725 }
1726
1727 data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1728 cfb.FullPaths = []; cfb.FileIndex = [];
1729 for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1730 for(i = 0; i < data.length; ++i) {
1731 var elt = cfb.FileIndex[i];
1732 var nm = cfb.FullPaths[i];
1733
1734 elt.name = filename(nm).replace("/","");
1735 elt.L = elt.R = elt.C = -(elt.color = 1);
1736 elt.size = elt.content ? elt.content.length : 0;
1737 elt.start = 0;
1738 elt.clsid = (elt.clsid || HEADER_CLSID);
1739 if(i === 0) {
1740 elt.C = data.length > 1 ? 1 : -1;
1741 elt.size = 0;
1742 elt.type = 5;
1743 } else if(nm.slice(-1) == "/") {
1744 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1745 elt.C = j >= data.length ? -1 : j;
1746 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1747 elt.R = j >= data.length ? -1 : j;
1748 elt.type = 1;
1749 } else {
1750 if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1751 elt.type = 2;
1752 }
1753 }
1754
1755}
1756
1757function _write(cfb, options) {
1758 var _opts = options || {};
1759 rebuild_cfb(cfb);
1760 if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
1761 var L = (function(cfb){
1762 var mini_size = 0, fat_size = 0;
1763 for(var i = 0; i < cfb.FileIndex.length; ++i) {
1764 var file = cfb.FileIndex[i];
1765 if(!file.content) continue;
1766var flen = file.content.length;
1767 if(flen > 0){
1768 if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1769 else fat_size += (flen + 0x01FF) >> 9;
1770 }
1771 }
1772 var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1773 var mini_cnt = (mini_size + 7) >> 3;
1774 var mfat_cnt = (mini_size + 0x7F) >> 7;
1775 var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1776 var fat_cnt = (fat_base + 0x7F) >> 7;
1777 var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1778 while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1779 var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1780 cfb.FileIndex[0].size = mini_size << 6;
1781 L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1782 return L;
1783 })(cfb);
1784 var o = new_buf(L[7] << 9);
1785 var i = 0, T = 0;
1786 {
1787 for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1788 for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1789 o.write_shift(2, 0x003E);
1790 o.write_shift(2, 0x0003);
1791 o.write_shift(2, 0xFFFE);
1792 o.write_shift(2, 0x0009);
1793 o.write_shift(2, 0x0006);
1794 for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1795 o.write_shift(4, 0);
1796 o.write_shift(4, L[2]);
1797 o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1798 o.write_shift(4, 0);
1799 o.write_shift(4, 1<<12);
1800 o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1801 o.write_shift(4, L[3]);
1802 o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1803 o.write_shift(4, L[1]);
1804 for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1805 }
1806 if(L[1]) {
1807 for(T = 0; T < L[1]; ++T) {
1808 for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1809 o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1810 }
1811 }
1812 var chainit = function(w) {
1813 for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1814 if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1815 };
1816 T = i = 0;
1817 for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1818 for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1819 chainit(L[3]);
1820 chainit(L[4]);
1821 var j = 0, flen = 0;
1822 var file = cfb.FileIndex[0];
1823 for(; j < cfb.FileIndex.length; ++j) {
1824 file = cfb.FileIndex[j];
1825 if(!file.content) continue;
1826flen = file.content.length;
1827 if(flen < 0x1000) continue;
1828 file.start = T;
1829 chainit((flen + 0x01FF) >> 9);
1830 }
1831 chainit((L[6] + 7) >> 3);
1832 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1833 T = i = 0;
1834 for(j = 0; j < cfb.FileIndex.length; ++j) {
1835 file = cfb.FileIndex[j];
1836 if(!file.content) continue;
1837flen = file.content.length;
1838 if(!flen || flen >= 0x1000) continue;
1839 file.start = T;
1840 chainit((flen + 0x3F) >> 6);
1841 }
1842 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1843 for(i = 0; i < L[4]<<2; ++i) {
1844 var nm = cfb.FullPaths[i];
1845 if(!nm || nm.length === 0) {
1846 for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1847 for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1848 for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1849 continue;
1850 }
1851 file = cfb.FileIndex[i];
1852 if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1853 var _nm = (i === 0 && _opts.root) || file.name;
1854 flen = 2*(_nm.length+1);
1855 o.write_shift(64, _nm, "utf16le");
1856 o.write_shift(2, flen);
1857 o.write_shift(1, file.type);
1858 o.write_shift(1, file.color);
1859 o.write_shift(-4, file.L);
1860 o.write_shift(-4, file.R);
1861 o.write_shift(-4, file.C);
1862 if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1863 else o.write_shift(16, file.clsid, "hex");
1864 o.write_shift(4, file.state || 0);
1865 o.write_shift(4, 0); o.write_shift(4, 0);
1866 o.write_shift(4, 0); o.write_shift(4, 0);
1867 o.write_shift(4, file.start);
1868 o.write_shift(4, file.size); o.write_shift(4, 0);
1869 }
1870 for(i = 1; i < cfb.FileIndex.length; ++i) {
1871 file = cfb.FileIndex[i];
1872if(file.size >= 0x1000) {
1873 o.l = (file.start+1) << 9;
1874 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1875 for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1876 }
1877 }
1878 for(i = 1; i < cfb.FileIndex.length; ++i) {
1879 file = cfb.FileIndex[i];
1880if(file.size > 0 && file.size < 0x1000) {
1881 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1882 for(; j & 0x3F; ++j) o.write_shift(1, 0);
1883 }
1884 }
1885 while(o.l < o.length) o.write_shift(1, 0);
1886 return o;
1887}
1888/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1889function find(cfb, path) {
1890 var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1891 var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1892 var k = false;
1893 if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1894 else k = path.indexOf("/") !== -1;
1895 var UCPath = path.toUpperCase();
1896 var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1897 if(w !== -1) return cfb.FileIndex[w];
1898
1899 var m = !UCPath.match(chr1);
1900 UCPath = UCPath.replace(chr0,'');
1901 if(m) UCPath = UCPath.replace(chr1,'!');
1902 for(w = 0; w < UCFullPaths.length; ++w) {
1903 if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1904 if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1905 }
1906 return null;
1907}
1908/** CFB Constants */
1909var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1910//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1911/* 2.1 Compound File Sector Numbers and Types */
1912var ENDOFCHAIN = -2;
1913/* 2.2 Compound File Header */
1914var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1915var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1916var HEADER_CLSID = '00000000000000000000000000000000';
1917var consts = {
1918 /* 2.1 Compund File Sector Numbers and Types */
1919 MAXREGSECT: -6,
1920 DIFSECT: -4,
1921 FATSECT: -3,
1922 ENDOFCHAIN: ENDOFCHAIN,
1923 FREESECT: -1,
1924 /* 2.2 Compound File Header */
1925 HEADER_SIGNATURE: HEADER_SIGNATURE,
1926 HEADER_MINOR_VERSION: '3e00',
1927 MAXREGSID: -6,
1928 NOSTREAM: -1,
1929 HEADER_CLSID: HEADER_CLSID,
1930 /* 2.6.1 Compound File Directory Entry */
1931 EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
1932};
1933
1934function write_file(cfb, filename, options) {
1935 get_fs();
1936 var o = _write(cfb, options);
1937fs.writeFileSync(filename, o);
1938}
1939
1940function a2s(o) {
1941 var out = new Array(o.length);
1942 for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
1943 return out.join("");
1944}
1945
1946function write(cfb, options) {
1947 var o = _write(cfb, options);
1948 switch(options && options.type) {
1949 case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
1950 case "binary": return a2s(o);
1951 case "base64": return Base64.encode(a2s(o));
1952 }
1953 return o;
1954}
1955/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
1956var _zlib;
1957function use_zlib(zlib) { try {
1958 var InflateRaw = zlib.InflateRaw;
1959 var InflRaw = new InflateRaw();
1960 InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
1961 if(InflRaw.bytesRead) _zlib = zlib;
1962 else throw new Error("zlib does not expose bytesRead");
1963} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
1964
1965function _inflateRawSync(payload, usz) {
1966 if(!_zlib) return _inflate(payload, usz);
1967 var InflateRaw = _zlib.InflateRaw;
1968 var InflRaw = new InflateRaw();
1969 var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
1970 payload.l += InflRaw.bytesRead;
1971 return out;
1972}
1973
1974function _deflateRawSync(payload) {
1975 return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
1976}
1977var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
1978
1979/* LEN_ID = [ 257, 258, 259, 260, 261, 262, 263, 264, 265, 266, 267, 268, 269, 270, 271, 272, 273, 274, 275, 276, 277, 278, 279, 280, 281, 282, 283, 284, 285 ]; */
1980var LEN_LN = [ 3, 4, 5, 6, 7, 8, 9, 10, 11, 13 , 15, 17, 19, 23, 27, 31, 35, 43, 51, 59, 67, 83, 99, 115, 131, 163, 195, 227, 258 ];
1981
1982/* DST_ID = [ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29 ]; */
1983var DST_LN = [ 1, 2, 3, 4, 5, 7, 9, 13, 17, 25, 33, 49, 65, 97, 129, 193, 257, 385, 513, 769, 1025, 1537, 2049, 3073, 4097, 6145, 8193, 12289, 16385, 24577 ];
1984
1985function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
1986
1987var use_typed_arrays = typeof Uint8Array !== 'undefined';
1988
1989var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
1990for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
1991
1992function bit_swap_n(n, b) {
1993 var rev = bitswap8[n & 0xFF];
1994 if(b <= 8) return rev >>> (8-b);
1995 rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
1996 if(b <= 16) return rev >>> (16-b);
1997 rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
1998 return rev >>> (24-b);
1999}
2000
2001/* helpers for unaligned bit reads */
2002function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
2003function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
2004function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
2005function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
2006function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
2007
2008/* works up to n = 3 * 8 + 1 = 25 */
2009function read_bits_n(buf, bl, n) {
2010 var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
2011 var v = buf[h] >>> w;
2012 if(n < 8 - w) return v & f;
2013 v |= buf[h+1]<<(8-w);
2014 if(n < 16 - w) return v & f;
2015 v |= buf[h+2]<<(16-w);
2016 if(n < 24 - w) return v & f;
2017 v |= buf[h+3]<<(24-w);
2018 return v & f;
2019}
2020
2021/* until ArrayBuffer#realloc is a thing, fake a realloc */
2022function realloc(b, sz) {
2023 var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
2024 if(L >= sz) return b;
2025 if(has_buf) {
2026 var o = new_unsafe_buf(M);
2027 // $FlowIgnore
2028 if(b.copy) b.copy(o);
2029 else for(; i < b.length; ++i) o[i] = b[i];
2030 return o;
2031 } else if(use_typed_arrays) {
2032 var a = new Uint8Array(M);
2033 if(a.set) a.set(b);
2034 else for(; i < b.length; ++i) a[i] = b[i];
2035 return a;
2036 }
2037 b.length = M;
2038 return b;
2039}
2040
2041/* zero-filled arrays for older browsers */
2042function zero_fill_array(n) {
2043 var o = new Array(n);
2044 for(var i = 0; i < n; ++i) o[i] = 0;
2045 return o;
2046}var _deflate = (function() {
2047var _deflateRaw = (function() {
2048 return function deflateRaw(data, out) {
2049 var boff = 0;
2050 while(boff < data.length) {
2051 var L = Math.min(0xFFFF, data.length - boff);
2052 var h = boff + L == data.length;
2053 /* TODO: this is only type 0 stored */
2054 out.write_shift(1, +h);
2055 out.write_shift(2, L);
2056 out.write_shift(2, (~L) & 0xFFFF);
2057 while(L-- > 0) out[out.l++] = data[boff++];
2058 }
2059 return out.l;
2060 };
2061})();
2062
2063return function(data) {
2064 var buf = new_buf(50+Math.floor(data.length*1.1));
2065 var off = _deflateRaw(data, buf);
2066 return buf.slice(0, off);
2067};
2068})();
2069/* modified inflate function also moves original read head */
2070
2071/* build tree (used for literals and lengths) */
2072function build_tree(clens, cmap, MAX) {
2073 var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
2074
2075 var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2076 for(i = 0; i < 32; ++i) bl_count[i] = 0;
2077
2078 for(i = L; i < MAX; ++i) clens[i] = 0;
2079 L = clens.length;
2080
2081 var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
2082
2083 /* build code tree */
2084 for(i = 0; i < L; ++i) {
2085 bl_count[(w = clens[i])]++;
2086 if(maxlen < w) maxlen = w;
2087 ctree[i] = 0;
2088 }
2089 bl_count[0] = 0;
2090 for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
2091 for(i = 0; i < L; ++i) {
2092 ccode = clens[i];
2093 if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
2094 }
2095
2096 /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
2097 var cleni = 0;
2098 for(i = 0; i < L; ++i) {
2099 cleni = clens[i];
2100 if(cleni != 0) {
2101 ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
2102 for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
2103 cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
2104 }
2105 }
2106 return maxlen;
2107}
2108
2109var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
2110var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2111if(!use_typed_arrays) {
2112 for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
2113 for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
2114}
2115(function() {
2116 var dlens = [];
2117 var i = 0;
2118 for(;i<32; i++) dlens.push(5);
2119 build_tree(dlens, fix_dmap, 32);
2120
2121 var clens = [];
2122 i = 0;
2123 for(; i<=143; i++) clens.push(8);
2124 for(; i<=255; i++) clens.push(9);
2125 for(; i<=279; i++) clens.push(7);
2126 for(; i<=287; i++) clens.push(8);
2127 build_tree(clens, fix_lmap, 288);
2128})();
2129
2130var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2131var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2132var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
2133var dyn_len_1 = 1, dyn_len_2 = 1;
2134
2135/* 5.5.3 Expanding Huffman Codes */
2136function dyn(data, boff) {
2137 /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
2138 var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
2139 var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
2140 var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
2141 var w = 0;
2142
2143 /* grab and store code lengths */
2144 var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
2145 var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2146 var maxlen = 1;
2147 var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2148 var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2149 var L = clens.length; /* 19 */
2150 for(var i = 0; i < _HCLEN; ++i) {
2151 clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
2152 if(maxlen < w) maxlen = w;
2153 bl_count[w]++;
2154 boff += 3;
2155 }
2156
2157 /* build code tree */
2158 var ccode = 0;
2159 bl_count[0] = 0;
2160 for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
2161 for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
2162 /* cmap[7 bits from stream] = (off&7) + (lit<<3) */
2163 var cleni = 0;
2164 for(i = 0; i < L; ++i) {
2165 cleni = clens[i];
2166 if(cleni != 0) {
2167 ccode = bitswap8[ctree[i]]>>(8-cleni);
2168 for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
2169 }
2170 }
2171
2172 /* read literal and dist codes at once */
2173 var hcodes = [];
2174 maxlen = 1;
2175 for(; hcodes.length < _HLIT + _HDIST;) {
2176 ccode = dyn_cmap[read_bits_7(data, boff)];
2177 boff += ccode & 7;
2178 switch((ccode >>>= 3)) {
2179 case 16:
2180 w = 3 + read_bits_2(data, boff); boff += 2;
2181 ccode = hcodes[hcodes.length - 1];
2182 while(w-- > 0) hcodes.push(ccode);
2183 break;
2184 case 17:
2185 w = 3 + read_bits_3(data, boff); boff += 3;
2186 while(w-- > 0) hcodes.push(0);
2187 break;
2188 case 18:
2189 w = 11 + read_bits_7(data, boff); boff += 7;
2190 while(w -- > 0) hcodes.push(0);
2191 break;
2192 default:
2193 hcodes.push(ccode);
2194 if(maxlen < ccode) maxlen = ccode;
2195 break;
2196 }
2197 }
2198
2199 /* build literal / length trees */
2200 var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
2201 for(i = _HLIT; i < 286; ++i) h1[i] = 0;
2202 for(i = _HDIST; i < 30; ++i) h2[i] = 0;
2203 dyn_len_1 = build_tree(h1, dyn_lmap, 286);
2204 dyn_len_2 = build_tree(h2, dyn_dmap, 30);
2205 return boff;
2206}
2207
2208/* return [ data, bytesRead ] */
2209function inflate(data, usz) {
2210 /* shortcircuit for empty buffer [0x03, 0x00] */
2211 if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
2212
2213 /* bit offset */
2214 var boff = 0;
2215
2216 /* header includes final bit and type bits */
2217 var header = 0;
2218
2219 var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
2220 var woff = 0;
2221 var OL = outbuf.length>>>0;
2222 var max_len_1 = 0, max_len_2 = 0;
2223
2224 while((header&1) == 0) {
2225 header = read_bits_3(data, boff); boff += 3;
2226 if((header >>> 1) == 0) {
2227 /* Stored block */
2228 if(boff & 7) boff += 8 - (boff&7);
2229 /* 2 bytes sz, 2 bytes bit inverse */
2230 var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
2231 boff += 32;
2232 /* push sz bytes */
2233 if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
2234 if(typeof data.copy === 'function') {
2235 // $FlowIgnore
2236 data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
2237 woff += sz; boff += 8*sz;
2238 } else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
2239 continue;
2240 } else if((header >>> 1) == 1) {
2241 /* Fixed Huffman */
2242 max_len_1 = 9; max_len_2 = 5;
2243 } else {
2244 /* Dynamic Huffman */
2245 boff = dyn(data, boff);
2246 max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
2247 }
2248 if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
2249 for(;;) { // while(true) is apparently out of vogue in modern JS circles
2250 /* ingest code and move read head */
2251 var bits = read_bits_n(data, boff, max_len_1);
2252 var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
2253 boff += code & 15; code >>>= 4;
2254 /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
2255 if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
2256 else if(code == 256) break;
2257 else {
2258 code -= 257;
2259 var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
2260 var tgt = woff + LEN_LN[code];
2261 /* length extra bits */
2262 if(len_eb > 0) {
2263 tgt += read_bits_n(data, boff, len_eb);
2264 boff += len_eb;
2265 }
2266
2267 /* dist code */
2268 bits = read_bits_n(data, boff, max_len_2);
2269 code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
2270 boff += code & 15; code >>>= 4;
2271 var dst_eb = (code < 4 ? 0 : (code-2)>>1);
2272 var dst = DST_LN[code];
2273 /* dist extra bits */
2274 if(dst_eb > 0) {
2275 dst += read_bits_n(data, boff, dst_eb);
2276 boff += dst_eb;
2277 }
2278
2279 /* in the common case, manual byte copy is faster than TA set / Buffer copy */
2280 if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
2281 while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
2282 }
2283 }
2284 }
2285 return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
2286}
2287
2288function _inflate(payload, usz) {
2289 var data = payload.slice(payload.l||0);
2290 var out = inflate(data, usz);
2291 payload.l += out[1];
2292 return out[0];
2293}
2294
2295function warn_or_throw(wrn, msg) {
2296 if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
2297 else throw new Error(msg);
2298}
2299
2300function parse_zip(file, options) {
2301 var blob = file;
2302 prep_blob(blob, 0);
2303
2304 var FileIndex = [], FullPaths = [];
2305 var o = {
2306 FileIndex: FileIndex,
2307 FullPaths: FullPaths
2308 };
2309 init_cfb(o, { root: options.root });
2310
2311 /* find end of central directory, start just after signature */
2312 var i = blob.length - 4;
2313 while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
2314 blob.l = i + 4;
2315
2316 /* parse end of central directory */
2317 blob.l += 4;
2318 var fcnt = blob.read_shift(2);
2319 blob.l += 6;
2320 var start_cd = blob.read_shift(4);
2321
2322 /* parse central directory */
2323 blob.l = start_cd;
2324
2325 for(i = 0; i < fcnt; ++i) {
2326 /* trust local file header instead of CD entry */
2327 blob.l += 20;
2328 var csz = blob.read_shift(4);
2329 var usz = blob.read_shift(4);
2330 var namelen = blob.read_shift(2);
2331 var efsz = blob.read_shift(2);
2332 var fcsz = blob.read_shift(2);
2333 blob.l += 8;
2334 var offset = blob.read_shift(4);
2335 var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
2336 blob.l += namelen + efsz + fcsz;
2337
2338 var L = blob.l;
2339 blob.l = offset + 4;
2340 parse_local_file(blob, csz, usz, o, EF);
2341 blob.l = L;
2342 }
2343
2344 return o;
2345}
2346
2347
2348/* head starts just after local file header signature */
2349function parse_local_file(blob, csz, usz, o, EF) {
2350 /* [local file header] */
2351 blob.l += 2;
2352 var flags = blob.read_shift(2);
2353 var meth = blob.read_shift(2);
2354 var date = parse_dos_date(blob);
2355
2356 if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
2357 var crc32 = blob.read_shift(4);
2358 var _csz = blob.read_shift(4);
2359 var _usz = blob.read_shift(4);
2360
2361 var namelen = blob.read_shift(2);
2362 var efsz = blob.read_shift(2);
2363
2364 // TODO: flags & (1<<11) // UTF8
2365 var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
2366 if(efsz) {
2367 var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
2368 if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
2369 if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
2370 }
2371 blob.l += efsz;
2372
2373 /* [encryption header] */
2374
2375 /* [file data] */
2376 var data = blob.slice(blob.l, blob.l + _csz);
2377 switch(meth) {
2378 case 8: data = _inflateRawSync(blob, _usz); break;
2379 case 0: break;
2380 default: throw new Error("Unsupported ZIP Compression method " + meth);
2381 }
2382
2383 /* [data descriptor] */
2384 var wrn = false;
2385 if(flags & 8) {
2386 crc32 = blob.read_shift(4);
2387 if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
2388 _csz = blob.read_shift(4);
2389 _usz = blob.read_shift(4);
2390 }
2391
2392 if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
2393 if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
2394 var _crc32 = CRC32.buf(data, 0);
2395 if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
2396 cfb_add(o, name, data, {unsafe: true, mt: date});
2397}
2398function write_zip(cfb, options) {
2399 var _opts = options || {};
2400 var out = [], cdirs = [];
2401 var o = new_buf(1);
2402 var method = (_opts.compression ? 8 : 0), flags = 0;
2403 var desc = false;
2404 if(desc) flags |= 8;
2405 var i = 0, j = 0;
2406
2407 var start_cd = 0, fcnt = 0;
2408 var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
2409 var crcs = [];
2410 var sz_cd = 0;
2411
2412 for(i = 1; i < cfb.FullPaths.length; ++i) {
2413 fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
2414 if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
2415 var start = start_cd;
2416
2417 /* TODO: CP437 filename */
2418 var namebuf = new_buf(fp.length);
2419 for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
2420 namebuf = namebuf.slice(0, namebuf.l);
2421 crcs[fcnt] = CRC32.buf(fi.content, 0);
2422
2423 var outbuf = fi.content;
2424 if(method == 8) outbuf = _deflateRawSync(outbuf);
2425
2426 /* local file header */
2427 o = new_buf(30);
2428 o.write_shift(4, 0x04034b50);
2429 o.write_shift(2, 20);
2430 o.write_shift(2, flags);
2431 o.write_shift(2, method);
2432 /* TODO: last mod file time/date */
2433 if(fi.mt) write_dos_date(o, fi.mt);
2434 else o.write_shift(4, 0);
2435 o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
2436 o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
2437 o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
2438 o.write_shift(2, namebuf.length);
2439 o.write_shift(2, 0);
2440
2441 start_cd += o.length;
2442 out.push(o);
2443 start_cd += namebuf.length;
2444 out.push(namebuf);
2445
2446 /* TODO: encryption header ? */
2447 start_cd += outbuf.length;
2448 out.push(outbuf);
2449
2450 /* data descriptor */
2451 if(flags & 8) {
2452 o = new_buf(12);
2453 o.write_shift(-4, crcs[fcnt]);
2454 o.write_shift(4, outbuf.length);
2455 o.write_shift(4, fi.content.length);
2456 start_cd += o.l;
2457 out.push(o);
2458 }
2459
2460 /* central directory */
2461 o = new_buf(46);
2462 o.write_shift(4, 0x02014b50);
2463 o.write_shift(2, 0);
2464 o.write_shift(2, 20);
2465 o.write_shift(2, flags);
2466 o.write_shift(2, method);
2467 o.write_shift(4, 0); /* TODO: last mod file time/date */
2468 o.write_shift(-4, crcs[fcnt]);
2469
2470 o.write_shift(4, outbuf.length);
2471 o.write_shift(4, fi.content.length);
2472 o.write_shift(2, namebuf.length);
2473 o.write_shift(2, 0);
2474 o.write_shift(2, 0);
2475 o.write_shift(2, 0);
2476 o.write_shift(2, 0);
2477 o.write_shift(4, 0);
2478 o.write_shift(4, start);
2479
2480 sz_cd += o.l;
2481 cdirs.push(o);
2482 sz_cd += namebuf.length;
2483 cdirs.push(namebuf);
2484 ++fcnt;
2485 }
2486
2487 /* end of central directory */
2488 o = new_buf(22);
2489 o.write_shift(4, 0x06054b50);
2490 o.write_shift(2, 0);
2491 o.write_shift(2, 0);
2492 o.write_shift(2, fcnt);
2493 o.write_shift(2, fcnt);
2494 o.write_shift(4, sz_cd);
2495 o.write_shift(4, start_cd);
2496 o.write_shift(2, 0);
2497
2498 return bconcat(([bconcat((out)), bconcat(cdirs), o]));
2499}
2500function cfb_new(opts) {
2501 var o = ({});
2502 init_cfb(o, opts);
2503 return o;
2504}
2505
2506function cfb_add(cfb, name, content, opts) {
2507 var unsafe = opts && opts.unsafe;
2508 if(!unsafe) init_cfb(cfb);
2509 var file = !unsafe && CFB.find(cfb, name);
2510 if(!file) {
2511 var fpath = cfb.FullPaths[0];
2512 if(name.slice(0, fpath.length) == fpath) fpath = name;
2513 else {
2514 if(fpath.slice(-1) != "/") fpath += "/";
2515 fpath = (fpath + name).replace("//","/");
2516 }
2517 file = ({name: filename(name), type: 2});
2518 cfb.FileIndex.push(file);
2519 cfb.FullPaths.push(fpath);
2520 if(!unsafe) CFB.utils.cfb_gc(cfb);
2521 }
2522file.content = (content);
2523 file.size = content ? content.length : 0;
2524 if(opts) {
2525 if(opts.CLSID) file.clsid = opts.CLSID;
2526 if(opts.mt) file.mt = opts.mt;
2527 if(opts.ct) file.ct = opts.ct;
2528 }
2529 return file;
2530}
2531
2532function cfb_del(cfb, name) {
2533 init_cfb(cfb);
2534 var file = CFB.find(cfb, name);
2535 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2536 cfb.FileIndex.splice(j, 1);
2537 cfb.FullPaths.splice(j, 1);
2538 return true;
2539 }
2540 return false;
2541}
2542
2543function cfb_mov(cfb, old_name, new_name) {
2544 init_cfb(cfb);
2545 var file = CFB.find(cfb, old_name);
2546 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2547 cfb.FileIndex[j].name = filename(new_name);
2548 cfb.FullPaths[j] = new_name;
2549 return true;
2550 }
2551 return false;
2552}
2553
2554function cfb_gc(cfb) { rebuild_cfb(cfb, true); }
2555
2556exports.find = find;
2557exports.read = read;
2558exports.parse = parse;
2559exports.write = write;
2560exports.writeFile = write_file;
2561exports.utils = {
2562 cfb_new: cfb_new,
2563 cfb_add: cfb_add,
2564 cfb_del: cfb_del,
2565 cfb_mov: cfb_mov,
2566 cfb_gc: cfb_gc,
2567 ReadShift: ReadShift,
2568 CheckField: CheckField,
2569 prep_blob: prep_blob,
2570 bconcat: bconcat,
2571 use_zlib: use_zlib,
2572 _deflateRaw: _deflate,
2573 _inflateRaw: _inflate,
2574 consts: consts
2575};
2576
2577return exports;
2578})();
2579
2580if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
2581var _fs;
2582if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
2583
2584/* normalize data for blob ctor */
2585function blobify(data) {
2586 if(typeof data === "string") return s2ab(data);
2587 if(Array.isArray(data)) return a2u(data);
2588 return data;
2589}
2590/* write or download file */
2591function write_dl(fname, payload, enc) {
2592 /*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File, chrome */
2593 if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
2594 var data = (enc == "utf8") ? utf8write(payload) : payload;
2595if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
2596 if(typeof Blob !== 'undefined') {
2597 var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
2598if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
2599if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
2600 if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
2601 var url = URL.createObjectURL(blob);
2602if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
2603 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2604 return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
2605 }
2606 var a = document.createElement("a");
2607 if(a.download != null) {
2608a.download = fname; a.href = url; document.body.appendChild(a); a.click();
2609document.body.removeChild(a);
2610 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2611 return url;
2612 }
2613 }
2614 }
2615 // $FlowIgnore
2616 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2617 // $FlowIgnore
2618 var out = File(fname); out.open("w"); out.encoding = "binary";
2619 if(Array.isArray(payload)) payload = a2s(payload);
2620 out.write(payload); out.close(); return payload;
2621 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2622 throw new Error("cannot save file " + fname);
2623}
2624
2625/* read binary data from file */
2626function read_binary(path) {
2627 if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
2628 // $FlowIgnore
2629 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2630 // $FlowIgnore
2631 var infile = File(path); infile.open("r"); infile.encoding = "binary";
2632 var data = infile.read(); infile.close();
2633 return data;
2634 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2635 throw new Error("Cannot access file " + path);
2636}
2637function keys(o) {
2638 var ks = Object.keys(o), o2 = [];
2639 for(var i = 0; i < ks.length; ++i) if(o.hasOwnProperty(ks[i])) o2.push(ks[i]);
2640 return o2;
2641}
2642
2643function evert_key(obj, key) {
2644 var o = ([]), K = keys(obj);
2645 for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
2646 return o;
2647}
2648
2649function evert(obj) {
2650 var o = ([]), K = keys(obj);
2651 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
2652 return o;
2653}
2654
2655function evert_num(obj) {
2656 var o = ([]), K = keys(obj);
2657 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
2658 return o;
2659}
2660
2661function evert_arr(obj) {
2662 var o = ([]), K = keys(obj);
2663 for(var i = 0; i !== K.length; ++i) {
2664 if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
2665 o[obj[K[i]]].push(K[i]);
2666 }
2667 return o;
2668}
2669
2670var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
2671var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2672function datenum(v, date1904) {
2673 var epoch = v.getTime();
2674 if(date1904) epoch -= 1462*24*60*60*1000;
2675 return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
2676}
2677function numdate(v) {
2678 var out = new Date();
2679 out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
2680 return out;
2681}
2682
2683/* ISO 8601 Duration */
2684function parse_isodur(s) {
2685 var sec = 0, mt = 0, time = false;
2686 var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
2687 if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
2688 for(var i = 1; i != m.length; ++i) {
2689 if(!m[i]) continue;
2690 mt = 1;
2691 if(i > 3) time = true;
2692 switch(m[i].slice(m[i].length-1)) {
2693 case 'Y':
2694 throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
2695 case 'D': mt *= 24;
2696 /* falls through */
2697 case 'H': mt *= 60;
2698 /* falls through */
2699 case 'M':
2700 if(!time) throw new Error("Unsupported ISO Duration Field: M");
2701 else mt *= 60;
2702 /* falls through */
2703 case 'S': break;
2704 }
2705 sec += mt * parseInt(m[i], 10);
2706 }
2707 return sec;
2708}
2709
2710var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
2711if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
2712var good_pd = good_pd_date.getFullYear() == 2017;
2713/* parses a date as a local date */
2714function parseDate(str, fixdate) {
2715 var d = new Date(str);
2716 if(good_pd) {
2717if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
2718 else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
2719 return d;
2720 }
2721 if(str instanceof Date) return str;
2722 if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
2723 var s = d.getFullYear();
2724 if(str.indexOf("" + s) > -1) return d;
2725 d.setFullYear(d.getFullYear() + 100); return d;
2726 }
2727 var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
2728 var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
2729 if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
2730 return out;
2731}
2732
2733function cc2str(arr) {
2734 var o = "";
2735 for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2736 return o;
2737}
2738
2739function dup(o) {
2740 if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2741 if(typeof o != 'object' || o == null) return o;
2742 if(o instanceof Date) return new Date(o.getTime());
2743 var out = {};
2744 for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
2745 return out;
2746}
2747
2748function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
2749
2750/* TODO: stress test */
2751function fuzzynum(s) {
2752 var v = Number(s);
2753 if(!isNaN(v)) return v;
2754 var wt = 1;
2755 var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2756 if(!isNaN(v = Number(ss))) return v / wt;
2757 ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2758 if(!isNaN(v = Number(ss))) return v / wt;
2759 return v;
2760}
2761function fuzzydate(s) {
2762 var o = new Date(s), n = new Date(NaN);
2763 var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2764 if(isNaN(d)) return n;
2765 if(y < 0 || y > 8099) return n;
2766 if((m > 0 || d > 1) && y != 101) return o;
2767 if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2768 if(s.match(/[^-0-9:,\/\\]/)) return n;
2769 return o;
2770}
2771
2772var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2773function split_regex(str, re, def) {
2774 if(safe_split_regex || typeof re == "string") return str.split(re);
2775 var p = str.split(re), o = [p[0]];
2776 for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2777 return o;
2778}
2779function getdatastr(data) {
2780 if(!data) return null;
2781 if(data.data) return debom(data.data);
2782 if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2783 if(data.asBinary) return debom(data.asBinary());
2784 if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2785 if(data.content && data.type) return debom(cc2str(data.content));
2786 return null;
2787}
2788
2789function getdatabin(data) {
2790 if(!data) return null;
2791 if(data.data) return char_codes(data.data);
2792 if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2793 if(data._data && data._data.getContent) {
2794 var o = data._data.getContent();
2795 if(typeof o == "string") return char_codes(o);
2796 return Array.prototype.slice.call(o);
2797 }
2798 if(data.content && data.type) return data.content;
2799 return null;
2800}
2801
2802function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2803
2804/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2805/* OASIS does not comment on filename case sensitivity */
2806function safegetzipfile(zip, file) {
2807 var k = zip.FullPaths || keys(zip.files);
2808 var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
2809 for(var i=0; i<k.length; ++i) {
2810 var n = k[i].toLowerCase();
2811 if(f == n || g == n) return zip.files[k[i]];
2812 }
2813 return null;
2814}
2815
2816function getzipfile(zip, file) {
2817 var o = safegetzipfile(zip, file);
2818 if(o == null) throw new Error("Cannot find file " + file + " in zip");
2819 return o;
2820}
2821
2822function getzipdata(zip, file, safe) {
2823 if(!safe) return getdata(getzipfile(zip, file));
2824 if(!file) return null;
2825 try { return getzipdata(zip, file); } catch(e) { return null; }
2826}
2827
2828function getzipstr(zip, file, safe) {
2829 if(!safe) return getdatastr(getzipfile(zip, file));
2830 if(!file) return null;
2831 try { return getzipstr(zip, file); } catch(e) { return null; }
2832}
2833
2834function zipentries(zip) {
2835 var k = zip.FullPaths || keys(zip.files), o = [];
2836 for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i]);
2837 return o.sort();
2838}
2839
2840function zip_add_file(zip, path, content) {
2841 if(zip.FullPaths) CFB.utils.cfb_add(zip, path, content);
2842 else zip.file(path, content);
2843}
2844
2845var jszip;
2846/*global JSZipSync:true */
2847if(typeof JSZipSync !== 'undefined') jszip = JSZipSync;
2848if(typeof exports !== 'undefined') {
2849 if(typeof module !== 'undefined' && module.exports) {
2850 if(typeof jszip === 'undefined') jszip = undefined;
2851 }
2852}
2853
2854function zip_new() {
2855 if(!jszip) return CFB.utils.cfb_new();
2856 return new jszip();
2857}
2858
2859function zip_read(d, o) {
2860 var zip;
2861 if(jszip) switch(o.type) {
2862 case "base64": zip = new jszip(d, { base64:true }); break;
2863 case "binary": case "array": zip = new jszip(d, { base64:false }); break;
2864 case "buffer": zip = new jszip(d); break;
2865 default: throw new Error("Unrecognized type " + o.type);
2866 }
2867 else switch(o.type) {
2868 case "base64": zip = CFB.read(d, { type: "base64" }); break;
2869 case "binary": zip = CFB.read(d, { type: "binary" }); break;
2870 case "buffer": case "array": zip = CFB.read(d, { type: "buffer" }); break;
2871 default: throw new Error("Unrecognized type " + o.type);
2872 }
2873 return zip;
2874}
2875
2876function resolve_path(path, base) {
2877 if(path.charAt(0) == "/") return path.slice(1);
2878 var result = base.split('/');
2879 if(base.slice(-1) != "/") result.pop(); // folder path
2880 var target = path.split('/');
2881 while (target.length !== 0) {
2882 var step = target.shift();
2883 if (step === '..') result.pop();
2884 else if (step !== '.') result.push(step);
2885 }
2886 return result.join('/');
2887}
2888var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2889var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2890var tagregex=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s?[\/\?]?>/g;
2891
2892if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2893var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2894function parsexmltag(tag, skip_root, skip_LC) {
2895 var z = ({});
2896 var eq = 0, c = 0;
2897 for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2898 if(!skip_root) z[0] = tag.slice(0, eq);
2899 if(eq === tag.length) return z;
2900 var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2901 if(m) for(i = 0; i != m.length; ++i) {
2902 cc = m[i];
2903 for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2904 q = cc.slice(0,c).trim();
2905 while(cc.charCodeAt(c+1) == 32) ++c;
2906 quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2907 v = cc.slice(c+1+quot, cc.length-quot);
2908 for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2909 if(j===q.length) {
2910 if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2911 z[q] = v;
2912 if(!skip_LC) z[q.toLowerCase()] = v;
2913 }
2914 else {
2915 var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2916 if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2917 z[k] = v;
2918 if(!skip_LC) z[k.toLowerCase()] = v;
2919 }
2920 }
2921 return z;
2922}
2923function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
2924
2925var encodings = {
2926 '&quot;': '"',
2927 '&apos;': "'",
2928 '&gt;': '>',
2929 '&lt;': '<',
2930 '&amp;': '&'
2931};
2932var rencoding = evert(encodings);
2933//var rencstr = "&<>'\"".split("");
2934
2935// TODO: CP remap (need to read file version to determine OS)
2936var unescapexml = (function() {
2937 /* 22.4.2.4 bstr (Basic String) */
2938 var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
2939 return function unescapexml(text) {
2940 var s = text + '', i = s.indexOf("<![CDATA[");
2941 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));});
2942 var j = s.indexOf("]]>");
2943 return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
2944 };
2945})();
2946
2947var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
2948function escapexml(text){
2949 var s = text + '';
2950 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
2951}
2952function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
2953
2954var htmlcharegex = /[\u0000-\u001f]/g;
2955function escapehtml(text){
2956 var s = text + '';
2957 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) + ";"; });
2958}
2959
2960function escapexlml(text){
2961 var s = text + '';
2962 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
2963}
2964
2965/* TODO: handle codepages */
2966var xlml_fixstr = (function() {
2967 var entregex = /&#(\d+);/g;
2968 function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
2969 return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
2970})();
2971var xlml_unfixstr = (function() {
2972 return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
2973})();
2974
2975function parsexmlbool(value) {
2976 switch(value) {
2977 case 1: case true: case '1': case 'true': case 'TRUE': return true;
2978 /* case '0': case 'false': case 'FALSE':*/
2979 default: return false;
2980 }
2981}
2982
2983var utf8read = function utf8reada(orig) {
2984 var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
2985 while (i < orig.length) {
2986 c = orig.charCodeAt(i++);
2987 if (c < 128) { out += String.fromCharCode(c); continue; }
2988 d = orig.charCodeAt(i++);
2989 if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
2990 e = orig.charCodeAt(i++);
2991 if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
2992 f = orig.charCodeAt(i++);
2993 w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
2994 out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
2995 out += String.fromCharCode(0xDC00 + (w&1023));
2996 }
2997 return out;
2998};
2999
3000var utf8write = function(orig) {
3001 var out = [], i = 0, c = 0, d = 0;
3002 while(i < orig.length) {
3003 c = orig.charCodeAt(i++);
3004 switch(true) {
3005 case c < 128: out.push(String.fromCharCode(c)); break;
3006 case c < 2048:
3007 out.push(String.fromCharCode(192 + (c >> 6)));
3008 out.push(String.fromCharCode(128 + (c & 63)));
3009 break;
3010 case c >= 55296 && c < 57344:
3011 c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
3012 out.push(String.fromCharCode(240 + ((d >>18) & 7)));
3013 out.push(String.fromCharCode(144 + ((d >>12) & 63)));
3014 out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
3015 out.push(String.fromCharCode(128 + (d & 63)));
3016 break;
3017 default:
3018 out.push(String.fromCharCode(224 + (c >> 12)));
3019 out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
3020 out.push(String.fromCharCode(128 + (c & 63)));
3021 }
3022 }
3023 return out.join("");
3024};
3025
3026if(has_buf) {
3027 var utf8readb = function utf8readb(data) {
3028 var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
3029 for(i = 0; i < data.length; i+=j) {
3030 j = 1;
3031 if((c=data.charCodeAt(i)) < 128) w = c;
3032 else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
3033 else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
3034 else { j = 4;
3035 w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
3036 w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
3037 }
3038 if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
3039 out[k++] = w%256; out[k++] = w>>>8;
3040 }
3041 return out.slice(0,k).toString('ucs2');
3042 };
3043 var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
3044 if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
3045 var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
3046 if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
3047
3048 utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
3049}
3050
3051// matches <foo>...</foo> extracts content
3052var matchtag = (function() {
3053 var mtcache = ({});
3054 return function matchtag(f,g) {
3055 var t = f+"|"+(g||"");
3056 if(mtcache[t]) return mtcache[t];
3057 return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
3058 };
3059})();
3060
3061var htmldecode = (function() {
3062 var entities = [
3063 ['nbsp', ' '], ['middot', '·'],
3064 ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
3065 ].map(function(x) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; });
3066 return function htmldecode(str) {
3067 var o = str
3068 // Remove new lines and spaces from start of content
3069 .replace(/^[\t\n\r ]+/, "")
3070 // Remove new lines and spaces from end of content
3071 .replace(/[\t\n\r ]+$/,"")
3072 // Added line which removes any white space characters after and before html tags
3073 .replace(/>\s+/g,">").replace(/\s+</g,"<")
3074 // Replace remaining new lines and spaces with space
3075 .replace(/[\t\n\r ]+/g, " ")
3076 // Replace <br> tags with new lines
3077 .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
3078 // Strip HTML elements
3079 .replace(/<[^>]*>/g,"");
3080 for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
3081 return o;
3082 };
3083})();
3084
3085var vtregex = (function(){ var vt_cache = {};
3086 return function vt_regex(bt) {
3087 if(vt_cache[bt] !== undefined) return vt_cache[bt];
3088 return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
3089};})();
3090var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
3091function parseVector(data, opts) {
3092 var h = parsexmltag(data);
3093
3094 var matches = data.match(vtregex(h.baseType))||[];
3095 var res = [];
3096 if(matches.length != h.size) {
3097 if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
3098 return res;
3099 }
3100 matches.forEach(function(x) {
3101 var v = x.replace(vtvregex,"").match(vtmregex);
3102 if(v) res.push({v:utf8read(v[2]), t:v[1]});
3103 });
3104 return res;
3105}
3106
3107var wtregex = /(^\s|\s$|\n)/;
3108function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
3109
3110function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
3111function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
3112
3113function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
3114
3115function write_vt(s) {
3116 switch(typeof s) {
3117 case 'string': return writextag('vt:lpwstr', s);
3118 case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
3119 case 'boolean': return writextag('vt:bool',s?'true':'false');
3120 }
3121 if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
3122 throw new Error("Unable to serialize " + s);
3123}
3124
3125var XMLNS = ({
3126 'dc': 'http://purl.org/dc/elements/1.1/',
3127 'dcterms': 'http://purl.org/dc/terms/',
3128 'dcmitype': 'http://purl.org/dc/dcmitype/',
3129 'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
3130 'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
3131 'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
3132 'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
3133 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
3134 'xsd': 'http://www.w3.org/2001/XMLSchema'
3135});
3136
3137XMLNS.main = [
3138 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
3139 'http://purl.oclc.org/ooxml/spreadsheetml/main',
3140 'http://schemas.microsoft.com/office/excel/2006/main',
3141 'http://schemas.microsoft.com/office/excel/2006/2'
3142];
3143
3144var XLMLNS = ({
3145 'o': 'urn:schemas-microsoft-com:office:office',
3146 'x': 'urn:schemas-microsoft-com:office:excel',
3147 'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
3148 'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
3149 'mv': 'http://macVmlSchemaUri',
3150 'v': 'urn:schemas-microsoft-com:vml',
3151 'html': 'http://www.w3.org/TR/REC-html40'
3152});
3153function read_double_le(b, idx) {
3154 var s = 1 - 2 * (b[idx + 7] >>> 7);
3155 var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
3156 var m = (b[idx+6]&0x0f);
3157 for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
3158 if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
3159 if(e == 0) e = -1022;
3160 else { e -= 1023; m += Math.pow(2,52); }
3161 return s * Math.pow(2, e - 52) * m;
3162}
3163
3164function write_double_le(b, v, idx) {
3165 var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
3166 var av = bs ? (-v) : v;
3167 if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
3168 else if(av == 0) e = m = 0;
3169 else {
3170 e = Math.floor(Math.log(av) / Math.LN2);
3171 m = av * Math.pow(2, 52 - e);
3172 if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
3173 else { m -= Math.pow(2,52); e+=1023; }
3174 }
3175 for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
3176 b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
3177 b[idx + 7] = (e >> 4) | bs;
3178}
3179
3180var __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; };
3181var ___toBuffer = __toBuffer;
3182var __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,''); };
3183var ___utf16le = __utf16le;
3184var __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(""); };
3185var ___hexlify = __hexlify;
3186var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
3187var ___utf8 = __utf8;
3188var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3189var ___lpstr = __lpstr;
3190var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3191var ___cpstr = __cpstr;
3192var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3193var ___lpwstr = __lpwstr;
3194var __lpp4, ___lpp4;
3195__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
3196var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
3197var ___8lpp4 = __8lpp4;
3198var __double, ___double;
3199__double = ___double = function(b, idx) { return read_double_le(b, idx);};
3200var is_buf = function is_buf_a(a) { return Array.isArray(a); };
3201
3202if(has_buf) {
3203 __utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
3204 __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
3205 __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) : "";};
3206 __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) : "";};
3207 __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);};
3208 __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);};
3209 __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);};
3210 __utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
3211 __toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
3212 bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
3213 __double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
3214 is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
3215}
3216
3217/* from js-xls */
3218if(typeof cptable !== 'undefined') {
3219 __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
3220 __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
3221 __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)) : "";};
3222 __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)) : "";};
3223 __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)) : "";};
3224 __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
3225 __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
3226}
3227
3228var __readUInt8 = function(b, idx) { return b[idx]; };
3229var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
3230var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
3231var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
3232var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
3233var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
3234
3235function ReadShift(size, t) {
3236 var o="", oI, oR, oo=[], w, vv, i, loc;
3237 switch(t) {
3238 case 'dbcs':
3239 loc = this.l;
3240 if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
3241 else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
3242 size *= 2;
3243 break;
3244
3245 case 'utf8': o = __utf8(this, this.l, this.l + size); break;
3246 case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
3247
3248 case 'wstr':
3249 if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
3250 else return ReadShift.call(this, size, 'dbcs');
3251 size = 2 * size; break;
3252
3253 /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
3254 case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3255 case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3256 /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
3257 case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
3258 /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
3259 case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
3260 /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
3261 case '8lpp4': size = 4 + __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
3262
3263 case 'cstr': size = 0; o = "";
3264 while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
3265 o = oo.join(""); break;
3266 case '_wstr': size = 0; o = "";
3267 while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
3268 size+=2; o = oo.join(""); break;
3269
3270 /* sbcs and dbcs support continue records in the SST way TODO codepages */
3271 case 'dbcs-cont': o = ""; loc = this.l;
3272 for(i = 0; i < size; ++i) {
3273 if(this.lens && this.lens.indexOf(loc) !== -1) {
3274 w = __readUInt8(this, loc);
3275 this.l = loc + 1;
3276 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3277 return oo.join("") + vv;
3278 }
3279 oo.push(_getchar(__readUInt16LE(this, loc)));
3280 loc+=2;
3281 } o = oo.join(""); size *= 2; break;
3282
3283 case 'cpstr':
3284 if(typeof cptable !== 'undefined') {
3285 o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
3286 break;
3287 }
3288 /* falls through */
3289 case 'sbcs-cont': o = ""; loc = this.l;
3290 for(i = 0; i != size; ++i) {
3291 if(this.lens && this.lens.indexOf(loc) !== -1) {
3292 w = __readUInt8(this, loc);
3293 this.l = loc + 1;
3294 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3295 return oo.join("") + vv;
3296 }
3297 oo.push(_getchar(__readUInt8(this, loc)));
3298 loc+=1;
3299 } o = oo.join(""); break;
3300
3301 default:
3302 switch(size) {
3303 case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
3304 case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
3305 case 4: case -4:
3306 if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
3307 else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
3308 case 8: case -8:
3309 if(t === 'f') {
3310 if(size == 8) oR = __double(this, this.l);
3311 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);
3312 this.l += 8; return oR;
3313 } else size = 8;
3314 /* falls through */
3315 case 16: o = __hexlify(this, this.l, size); break;
3316 }}
3317 this.l+=size; return o;
3318}
3319
3320var __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); };
3321var __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); };
3322var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
3323
3324function WriteShift(t, val, f) {
3325 var size = 0, i = 0;
3326 if(f === 'dbcs') {
3327for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
3328 size = 2 * val.length;
3329 } else if(f === 'sbcs') {
3330 if(typeof cptable !== 'undefined' && current_ansi == 874) {
3331 /* TODO: use tables directly, don't encode */
3332for(i = 0; i != val.length; ++i) {
3333 var cppayload = cptable.utils.encode(current_ansi, val.charAt(i));
3334 this[this.l + i] = cppayload[0];
3335 }
3336 } else {
3337val = val.replace(/[^\x00-\x7F]/g, "_");
3338for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
3339 }
3340 size = val.length;
3341 } else if(f === 'hex') {
3342 for(; i < t; ++i) {
3343this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
3344 } return this;
3345 } else if(f === 'utf16le') {
3346var end = Math.min(this.l + t, this.length);
3347 for(i = 0; i < Math.min(val.length, t); ++i) {
3348 var cc = val.charCodeAt(i);
3349 this[this.l++] = (cc & 0xff);
3350 this[this.l++] = (cc >> 8);
3351 }
3352 while(this.l < end) this[this.l++] = 0;
3353 return this;
3354 } else switch(t) {
3355 case 1: size = 1; this[this.l] = val&0xFF; break;
3356 case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
3357 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;
3358 case 4: size = 4; __writeUInt32LE(this, val, this.l); break;
3359 case 8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
3360 /* falls through */
3361 case 16: break;
3362 case -4: size = 4; __writeInt32LE(this, val, this.l); break;
3363 }
3364 this.l += size; return this;
3365}
3366
3367function CheckField(hexstr, fld) {
3368 var m = __hexlify(this,this.l,hexstr.length>>1);
3369 if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
3370 this.l += hexstr.length>>1;
3371}
3372
3373function prep_blob(blob, pos) {
3374 blob.l = pos;
3375 blob.read_shift = ReadShift;
3376 blob.chk = CheckField;
3377 blob.write_shift = WriteShift;
3378}
3379
3380function parsenoop(blob, length) { blob.l += length; }
3381
3382function new_buf(sz) {
3383 var o = new_raw_buf(sz);
3384 prep_blob(o, 0);
3385 return o;
3386}
3387
3388/* [MS-XLSB] 2.1.4 Record */
3389function recordhopper(data, cb, opts) {
3390 if(!data) return;
3391 var tmpbyte, cntbyte, length;
3392 prep_blob(data, data.l || 0);
3393 var L = data.length, RT = 0, tgt = 0;
3394 while(data.l < L) {
3395 RT = data.read_shift(1);
3396 if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
3397 var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
3398 tmpbyte = data.read_shift(1);
3399 length = tmpbyte & 0x7F;
3400 for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
3401 tgt = data.l + length;
3402 var d = (R.f||parsenoop)(data, length, opts);
3403 data.l = tgt;
3404 if(cb(d, R.n, RT)) return;
3405 }
3406}
3407
3408/* control buffer usage for fixed-length buffers */
3409function buf_array() {
3410 var bufs = [], blksz = has_buf ? 256 : 2048;
3411 var newblk = function ba_newblk(sz) {
3412 var o = (new_buf(sz));
3413 prep_blob(o, 0);
3414 return o;
3415 };
3416
3417 var curbuf = newblk(blksz);
3418
3419 var endbuf = function ba_endbuf() {
3420 if(!curbuf) return;
3421 if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3422 if(curbuf.length > 0) bufs.push(curbuf);
3423 curbuf = null;
3424 };
3425
3426 var next = function ba_next(sz) {
3427 if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
3428 endbuf();
3429 return (curbuf = newblk(Math.max(sz+1, blksz)));
3430 };
3431
3432 var end = function ba_end() {
3433 endbuf();
3434 return __toBuffer([bufs]);
3435 };
3436
3437 var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
3438
3439 return ({ next:next, push:push, end:end, _bufs:bufs });
3440}
3441
3442function write_record(ba, type, payload, length) {
3443 var t = +XLSBRE[type], l;
3444 if(isNaN(t)) return; // TODO: throw something here?
3445 if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
3446 l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
3447 if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
3448 var o = ba.next(l);
3449 if(t <= 0x7F) o.write_shift(1, t);
3450 else {
3451 o.write_shift(1, (t & 0x7F) + 0x80);
3452 o.write_shift(1, (t >> 7));
3453 }
3454 for(var i = 0; i != 4; ++i) {
3455 if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
3456 else { o.write_shift(1, length); break; }
3457 }
3458 if(length > 0 && is_buf(payload)) ba.push(payload);
3459}
3460/* XLS ranges enforced */
3461function shift_cell_xls(cell, tgt, opts) {
3462 var out = dup(cell);
3463 if(tgt.s) {
3464 if(out.cRel) out.c += tgt.s.c;
3465 if(out.rRel) out.r += tgt.s.r;
3466 } else {
3467 if(out.cRel) out.c += tgt.c;
3468 if(out.rRel) out.r += tgt.r;
3469 }
3470 if(!opts || opts.biff < 12) {
3471 while(out.c >= 0x100) out.c -= 0x100;
3472 while(out.r >= 0x10000) out.r -= 0x10000;
3473 }
3474 return out;
3475}
3476
3477function shift_range_xls(cell, range, opts) {
3478 var out = dup(cell);
3479 out.s = shift_cell_xls(out.s, range.s, opts);
3480 out.e = shift_cell_xls(out.e, range.s, opts);
3481 return out;
3482}
3483
3484function encode_cell_xls(c, biff) {
3485 if(c.cRel && c.c < 0) { c = dup(c); while(c.c < 0) c.c += (biff > 8) ? 0x4000 : 0x100; }
3486 if(c.rRel && c.r < 0) { c = dup(c); while(c.r < 0) c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
3487 var s = encode_cell(c);
3488 if(!c.cRel && c.cRel != null) s = fix_col(s);
3489 if(!c.rRel && c.rRel != null) s = fix_row(s);
3490 return s;
3491}
3492
3493function encode_range_xls(r, opts) {
3494 if(r.s.r == 0 && !r.s.rRel) {
3495 if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
3496 return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
3497 }
3498 }
3499 if(r.s.c == 0 && !r.s.cRel) {
3500 if(r.e.c == (opts.biff >= 12 ? 0xFFFF : 0xFF) && !r.e.cRel) {
3501 return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
3502 }
3503 }
3504 return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
3505}
3506var OFFCRYPTO = {};
3507
3508var make_offcrypto = function(O, _crypto) {
3509 var crypto;
3510 if(typeof _crypto !== 'undefined') crypto = _crypto;
3511 else if(typeof require !== 'undefined') {
3512 try { crypto = undefined; }
3513 catch(e) { crypto = null; }
3514 }
3515
3516 O.rc4 = function(key, data) {
3517 var S = new Array(256);
3518 var c = 0, i = 0, j = 0, t = 0;
3519 for(i = 0; i != 256; ++i) S[i] = i;
3520 for(i = 0; i != 256; ++i) {
3521 j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
3522 t = S[i]; S[i] = S[j]; S[j] = t;
3523 }
3524 // $FlowIgnore
3525 i = j = 0; var out = Buffer(data.length);
3526 for(c = 0; c != data.length; ++c) {
3527 i = (i + 1)&255;
3528 j = (j + S[i])%256;
3529 t = S[i]; S[i] = S[j]; S[j] = t;
3530 out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
3531 }
3532 return out;
3533 };
3534
3535 O.md5 = function(hex) {
3536 if(!crypto) throw new Error("Unsupported crypto");
3537 return crypto.createHash('md5').update(hex).digest('hex');
3538 };
3539};
3540/*global crypto:true */
3541make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
3542
3543function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
3544function encode_row(row) { return "" + (row + 1); }
3545function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
3546function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
3547
3548function 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; }
3549function encode_col(col) { if(col < 0) throw new Error("invalid column " + col); var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
3550function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
3551function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
3552
3553function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
3554function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
3555function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
3556function decode_range(range) { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
3557function encode_range(cs,ce) {
3558 if(typeof ce === 'undefined' || typeof ce === 'number') {
3559return encode_range(cs.s, cs.e);
3560 }
3561if(typeof cs !== 'string') cs = encode_cell((cs));
3562 if(typeof ce !== 'string') ce = encode_cell((ce));
3563return cs == ce ? cs : cs + ":" + ce;
3564}
3565
3566function safe_decode_range(range) {
3567 var o = {s:{c:0,r:0},e:{c:0,r:0}};
3568 var idx = 0, i = 0, cc = 0;
3569 var len = range.length;
3570 for(idx = 0; i < len; ++i) {
3571 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3572 idx = 26*idx + cc;
3573 }
3574 o.s.c = --idx;
3575
3576 for(idx = 0; i < len; ++i) {
3577 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3578 idx = 10*idx + cc;
3579 }
3580 o.s.r = --idx;
3581
3582 if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
3583
3584 for(idx = 0; i != len; ++i) {
3585 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3586 idx = 26*idx + cc;
3587 }
3588 o.e.c = --idx;
3589
3590 for(idx = 0; i != len; ++i) {
3591 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3592 idx = 10*idx + cc;
3593 }
3594 o.e.r = --idx;
3595 return o;
3596}
3597
3598function safe_format_cell(cell, v) {
3599 var q = (cell.t == 'd' && v instanceof Date);
3600 if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
3601 try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
3602}
3603
3604function format_cell(cell, v, o) {
3605 if(cell == null || cell.t == null || cell.t == 'z') return "";
3606 if(cell.w !== undefined) return cell.w;
3607 if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
3608 if(v == undefined) return safe_format_cell(cell, cell.v);
3609 return safe_format_cell(cell, v);
3610}
3611
3612function sheet_to_workbook(sheet, opts) {
3613 var n = opts && opts.sheet ? opts.sheet : "Sheet1";
3614 var sheets = {}; sheets[n] = sheet;
3615 return { SheetNames: [n], Sheets: sheets };
3616}
3617
3618function sheet_add_aoa(_ws, data, opts) {
3619 var o = opts || {};
3620 var dense = _ws ? Array.isArray(_ws) : o.dense;
3621 if(DENSE != null && dense == null) dense = DENSE;
3622 var ws = _ws || (dense ? ([]) : ({}));
3623 var _R = 0, _C = 0;
3624 if(ws && o.origin != null) {
3625 if(typeof o.origin == 'number') _R = o.origin;
3626 else {
3627 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
3628 _R = _origin.r; _C = _origin.c;
3629 }
3630 }
3631 var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
3632 if(ws['!ref']) {
3633 var _range = safe_decode_range(ws['!ref']);
3634 range.s.c = _range.s.c;
3635 range.s.r = _range.s.r;
3636 range.e.c = Math.max(range.e.c, _range.e.c);
3637 range.e.r = Math.max(range.e.r, _range.e.r);
3638 if(_R == -1) range.e.r = _R = _range.e.r + 1;
3639 }
3640 for(var R = 0; R != data.length; ++R) {
3641 if(!data[R]) continue;
3642 if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
3643 for(var C = 0; C != data[R].length; ++C) {
3644 if(typeof data[R][C] === 'undefined') continue;
3645 var cell = ({v: data[R][C] });
3646 var __R = _R + R, __C = _C + C;
3647 if(range.s.r > __R) range.s.r = __R;
3648 if(range.s.c > __C) range.s.c = __C;
3649 if(range.e.r < __R) range.e.r = __R;
3650 if(range.e.c < __C) range.e.c = __C;
3651 if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
3652 else {
3653 if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
3654 if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.sheetStubs) continue; else cell.t = 'z'; }
3655 else if(typeof cell.v === 'number') cell.t = 'n';
3656 else if(typeof cell.v === 'boolean') cell.t = 'b';
3657 else if(cell.v instanceof Date) {
3658 cell.z = o.dateNF || SSF._table[14];
3659 if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
3660 else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
3661 }
3662 else cell.t = 's';
3663 }
3664 if(dense) {
3665 if(!ws[__R]) ws[__R] = [];
3666 ws[__R][__C] = cell;
3667 } else {
3668 var cell_ref = encode_cell(({c:__C,r:__R}));
3669 ws[cell_ref] = cell;
3670 }
3671 }
3672 }
3673 if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
3674 return ws;
3675}
3676function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
3677
3678function write_UInt32LE(x, o) {
3679 if(!o) o = new_buf(4);
3680 o.write_shift(4, x);
3681 return o;
3682}
3683
3684/* [MS-XLSB] 2.5.168 */
3685function parse_XLWideString(data) {
3686 var cchCharacters = data.read_shift(4);
3687 return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
3688}
3689function write_XLWideString(data, o) {
3690 var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
3691 o.write_shift(4, data.length);
3692 if(data.length > 0) o.write_shift(0, data, 'dbcs');
3693 return _null ? o.slice(0, o.l) : o;
3694}
3695
3696/* [MS-XLSB] 2.5.143 */
3697function parse_StrRun(data) {
3698 return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
3699}
3700function write_StrRun(run, o) {
3701 if(!o) o = new_buf(4);
3702 o.write_shift(2, run.ich || 0);
3703 o.write_shift(2, run.ifnt || 0);
3704 return o;
3705}
3706
3707/* [MS-XLSB] 2.5.121 */
3708function parse_RichStr(data, length) {
3709 var start = data.l;
3710 var flags = data.read_shift(1);
3711 var str = parse_XLWideString(data);
3712 var rgsStrRun = [];
3713 var z = ({ t: str, h: str });
3714 if((flags & 1) !== 0) { /* fRichStr */
3715 /* TODO: formatted string */
3716 var dwSizeStrRun = data.read_shift(4);
3717 for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
3718 z.r = rgsStrRun;
3719 }
3720 else z.r = [{ich:0, ifnt:0}];
3721 //if((flags & 2) !== 0) { /* fExtStr */
3722 // /* TODO: phonetic string */
3723 //}
3724 data.l = start + length;
3725 return z;
3726}
3727function write_RichStr(str, o) {
3728 /* TODO: formatted string */
3729 var _null = false; if(o == null) { _null = true; o = new_buf(15+4*str.t.length); }
3730 o.write_shift(1,0);
3731 write_XLWideString(str.t, o);
3732 return _null ? o.slice(0, o.l) : o;
3733}
3734/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
3735var parse_BrtCommentText = parse_RichStr;
3736function write_BrtCommentText(str, o) {
3737 /* TODO: formatted string */
3738 var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
3739 o.write_shift(1,1);
3740 write_XLWideString(str.t, o);
3741 o.write_shift(4,1);
3742 write_StrRun({ich:0,ifnt:0}, o);
3743 return _null ? o.slice(0, o.l) : o;
3744}
3745
3746/* [MS-XLSB] 2.5.9 */
3747function parse_XLSBCell(data) {
3748 var col = data.read_shift(4);
3749 var iStyleRef = data.read_shift(2);
3750 iStyleRef += data.read_shift(1) <<16;
3751 data.l++; //var fPhShow = data.read_shift(1);
3752 return { c:col, iStyleRef: iStyleRef };
3753}
3754function write_XLSBCell(cell, o) {
3755 if(o == null) o = new_buf(8);
3756 o.write_shift(-4, cell.c);
3757 o.write_shift(3, cell.iStyleRef || cell.s);
3758 o.write_shift(1, 0); /* fPhShow */
3759 return o;
3760}
3761
3762
3763/* [MS-XLSB] 2.5.21 */
3764var parse_XLSBCodeName = parse_XLWideString;
3765var write_XLSBCodeName = write_XLWideString;
3766
3767/* [MS-XLSB] 2.5.166 */
3768function parse_XLNullableWideString(data) {
3769 var cchCharacters = data.read_shift(4);
3770 return cchCharacters === 0 || cchCharacters === 0xFFFFFFFF ? "" : data.read_shift(cchCharacters, 'dbcs');
3771}
3772function write_XLNullableWideString(data, o) {
3773 var _null = false; if(o == null) { _null = true; o = new_buf(127); }
3774 o.write_shift(4, data.length > 0 ? data.length : 0xFFFFFFFF);
3775 if(data.length > 0) o.write_shift(0, data, 'dbcs');
3776 return _null ? o.slice(0, o.l) : o;
3777}
3778
3779/* [MS-XLSB] 2.5.165 */
3780var parse_XLNameWideString = parse_XLWideString;
3781//var write_XLNameWideString = write_XLWideString;
3782
3783/* [MS-XLSB] 2.5.114 */
3784var parse_RelID = parse_XLNullableWideString;
3785var write_RelID = write_XLNullableWideString;
3786
3787
3788/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
3789function parse_RkNumber(data) {
3790 var b = data.slice(data.l, data.l+4);
3791 var fX100 = (b[0] & 1), fInt = (b[0] & 2);
3792 data.l+=4;
3793 b[0] &= 0xFC; // b[0] &= ~3;
3794 var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
3795 return fX100 ? (RK/100) : RK;
3796}
3797function write_RkNumber(data, o) {
3798 if(o == null) o = new_buf(4);
3799 var fX100 = 0, fInt = 0, d100 = data * 100;
3800 if((data == (data | 0)) && (data >= -(1<<29)) && (data < (1 << 29))) { fInt = 1; }
3801 else if((d100 == (d100 | 0)) && (d100 >= -(1<<29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
3802 if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
3803 else throw new Error("unsupported RkNumber " + data); // TODO
3804}
3805
3806
3807/* [MS-XLSB] 2.5.117 RfX */
3808function parse_RfX(data ) {
3809 var cell = ({s: {}, e: {}});
3810 cell.s.r = data.read_shift(4);
3811 cell.e.r = data.read_shift(4);
3812 cell.s.c = data.read_shift(4);
3813 cell.e.c = data.read_shift(4);
3814 return cell;
3815}
3816function write_RfX(r, o) {
3817 if(!o) o = new_buf(16);
3818 o.write_shift(4, r.s.r);
3819 o.write_shift(4, r.e.r);
3820 o.write_shift(4, r.s.c);
3821 o.write_shift(4, r.e.c);
3822 return o;
3823}
3824
3825/* [MS-XLSB] 2.5.153 UncheckedRfX */
3826var parse_UncheckedRfX = parse_RfX;
3827var write_UncheckedRfX = write_RfX;
3828
3829
3830/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
3831/* TODO: error checking, NaN and Infinity values are not valid Xnum */
3832function parse_Xnum(data) { return data.read_shift(8, 'f'); }
3833function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
3834
3835/* [MS-XLSB] 2.5.97.2 */
3836var BErr = {
38370x00: "#NULL!",
38380x07: "#DIV/0!",
38390x0F: "#VALUE!",
38400x17: "#REF!",
38410x1D: "#NAME?",
38420x24: "#NUM!",
38430x2A: "#N/A",
38440x2B: "#GETTING_DATA",
38450xFF: "#WTF?"
3846};
3847var RBErr = evert_num(BErr);
3848
3849/* [MS-XLSB] 2.4.324 BrtColor */
3850function parse_BrtColor(data) {
3851 var out = {};
3852 var d = data.read_shift(1);
3853
3854 //var fValidRGB = d & 1;
3855 var xColorType = d >>> 1;
3856
3857 var index = data.read_shift(1);
3858 var nTS = data.read_shift(2, 'i');
3859 var bR = data.read_shift(1);
3860 var bG = data.read_shift(1);
3861 var bB = data.read_shift(1);
3862 data.l++; //var bAlpha = data.read_shift(1);
3863
3864 switch(xColorType) {
3865 case 0: out.auto = 1; break;
3866 case 1:
3867 out.index = index;
3868 var icv = XLSIcv[index];
3869 /* automatic pseudo index 81 */
3870 if(icv) out.rgb = rgb2Hex(icv);
3871 break;
3872 case 2:
3873 /* if(!fValidRGB) throw new Error("invalid"); */
3874 out.rgb = rgb2Hex([bR, bG, bB]);
3875 break;
3876 case 3: out.theme = index; break;
3877 }
3878 if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
3879
3880 return out;
3881}
3882function write_BrtColor(color, o) {
3883 if(!o) o = new_buf(8);
3884 if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
3885 if(color.index != null) {
3886 o.write_shift(1, 0x02);
3887 o.write_shift(1, color.index);
3888 } else if(color.theme != null) {
3889 o.write_shift(1, 0x06);
3890 o.write_shift(1, color.theme);
3891 } else {
3892 o.write_shift(1, 0x05);
3893 o.write_shift(1, 0);
3894 }
3895 var nTS = color.tint || 0;
3896 if(nTS > 0) nTS *= 32767;
3897 else if(nTS < 0) nTS *= 32768;
3898 o.write_shift(2, nTS);
3899 if(!color.rgb || color.theme != null) {
3900 o.write_shift(2, 0);
3901 o.write_shift(1, 0);
3902 o.write_shift(1, 0);
3903 } else {
3904 var rgb = (color.rgb || 'FFFFFF');
3905 if(typeof rgb == 'number') rgb = ("000000" + rgb.toString(16)).slice(-6);
3906 o.write_shift(1, parseInt(rgb.slice(0,2),16));
3907 o.write_shift(1, parseInt(rgb.slice(2,4),16));
3908 o.write_shift(1, parseInt(rgb.slice(4,6),16));
3909 o.write_shift(1, 0xFF);
3910 }
3911 return o;
3912}
3913
3914/* [MS-XLSB] 2.5.52 */
3915function parse_FontFlags(data) {
3916 var d = data.read_shift(1);
3917 data.l++;
3918 var out = {
3919 fBold: d & 0x01,
3920 fItalic: d & 0x02,
3921 fUnderline: d & 0x04,
3922 fStrikeout: d & 0x08,
3923 fOutline: d & 0x10,
3924 fShadow: d & 0x20,
3925 fCondense: d & 0x40,
3926 fExtend: d & 0x80
3927 };
3928 return out;
3929}
3930function write_FontFlags(font, o) {
3931 if(!o) o = new_buf(2);
3932 var grbit =
3933 (font.italic ? 0x02 : 0) |
3934 (font.strike ? 0x08 : 0) |
3935 (font.outline ? 0x10 : 0) |
3936 (font.shadow ? 0x20 : 0) |
3937 (font.condense ? 0x40 : 0) |
3938 (font.extend ? 0x80 : 0);
3939 o.write_shift(1, grbit);
3940 o.write_shift(1, 0);
3941 return o;
3942}
3943
3944/* [MS-OLEDS] 2.3.1 and 2.3.2 */
3945function parse_ClipboardFormatOrString(o, w) {
3946 // $FlowIgnore
3947 var ClipFmt = {2:"BITMAP",3:"METAFILEPICT",8:"DIB",14:"ENHMETAFILE"};
3948 var m = o.read_shift(4);
3949 switch(m) {
3950 case 0x00000000: return "";
3951 case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)]||"";
3952 }
3953 if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
3954 o.l -= 4;
3955 return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr");
3956}
3957function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); }
3958function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); }
3959
3960/* [MS-OLEPS] 2.2 PropertyType */
3961//var VT_EMPTY = 0x0000;
3962//var VT_NULL = 0x0001;
3963var VT_I2 = 0x0002;
3964var VT_I4 = 0x0003;
3965//var VT_R4 = 0x0004;
3966//var VT_R8 = 0x0005;
3967//var VT_CY = 0x0006;
3968//var VT_DATE = 0x0007;
3969//var VT_BSTR = 0x0008;
3970//var VT_ERROR = 0x000A;
3971var VT_BOOL = 0x000B;
3972var VT_VARIANT = 0x000C;
3973//var VT_DECIMAL = 0x000E;
3974//var VT_I1 = 0x0010;
3975//var VT_UI1 = 0x0011;
3976//var VT_UI2 = 0x0012;
3977var VT_UI4 = 0x0013;
3978//var VT_I8 = 0x0014;
3979//var VT_UI8 = 0x0015;
3980//var VT_INT = 0x0016;
3981//var VT_UINT = 0x0017;
3982var VT_LPSTR = 0x001E;
3983//var VT_LPWSTR = 0x001F;
3984var VT_FILETIME = 0x0040;
3985var VT_BLOB = 0x0041;
3986//var VT_STREAM = 0x0042;
3987//var VT_STORAGE = 0x0043;
3988//var VT_STREAMED_Object = 0x0044;
3989//var VT_STORED_Object = 0x0045;
3990//var VT_BLOB_Object = 0x0046;
3991var VT_CF = 0x0047;
3992//var VT_CLSID = 0x0048;
3993//var VT_VERSIONED_STREAM = 0x0049;
3994var VT_VECTOR = 0x1000;
3995//var VT_ARRAY = 0x2000;
3996
3997var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
3998var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
3999var VT_CUSTOM = [VT_STRING, VT_USTR];
4000
4001/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
4002var DocSummaryPIDDSI = {
40030x01: { n: 'CodePage', t: VT_I2 },
40040x02: { n: 'Category', t: VT_STRING },
40050x03: { n: 'PresentationFormat', t: VT_STRING },
40060x04: { n: 'ByteCount', t: VT_I4 },
40070x05: { n: 'LineCount', t: VT_I4 },
40080x06: { n: 'ParagraphCount', t: VT_I4 },
40090x07: { n: 'SlideCount', t: VT_I4 },
40100x08: { n: 'NoteCount', t: VT_I4 },
40110x09: { n: 'HiddenCount', t: VT_I4 },
40120x0a: { n: 'MultimediaClipCount', t: VT_I4 },
40130x0b: { n: 'ScaleCrop', t: VT_BOOL },
40140x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
40150x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
40160x0e: { n: 'Manager', t: VT_STRING },
40170x0f: { n: 'Company', t: VT_STRING },
40180x10: { n: 'LinksUpToDate', t: VT_BOOL },
40190x11: { n: 'CharacterCount', t: VT_I4 },
40200x13: { n: 'SharedDoc', t: VT_BOOL },
40210x16: { n: 'HyperlinksChanged', t: VT_BOOL },
40220x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
40230x18: { n: 'DigSig', t: VT_BLOB },
40240x1A: { n: 'ContentType', t: VT_STRING },
40250x1B: { n: 'ContentStatus', t: VT_STRING },
40260x1C: { n: 'Language', t: VT_STRING },
40270x1D: { n: 'Version', t: VT_STRING },
40280xFF: {}
4029};
4030
4031/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
4032var SummaryPIDSI = {
40330x01: { n: 'CodePage', t: VT_I2 },
40340x02: { n: 'Title', t: VT_STRING },
40350x03: { n: 'Subject', t: VT_STRING },
40360x04: { n: 'Author', t: VT_STRING },
40370x05: { n: 'Keywords', t: VT_STRING },
40380x06: { n: 'Comments', t: VT_STRING },
40390x07: { n: 'Template', t: VT_STRING },
40400x08: { n: 'LastAuthor', t: VT_STRING },
40410x09: { n: 'RevNumber', t: VT_STRING },
40420x0A: { n: 'EditTime', t: VT_FILETIME },
40430x0B: { n: 'LastPrinted', t: VT_FILETIME },
40440x0C: { n: 'CreatedDate', t: VT_FILETIME },
40450x0D: { n: 'ModifiedDate', t: VT_FILETIME },
40460x0E: { n: 'PageCount', t: VT_I4 },
40470x0F: { n: 'WordCount', t: VT_I4 },
40480x10: { n: 'CharCount', t: VT_I4 },
40490x11: { n: 'Thumbnail', t: VT_CF },
40500x12: { n: 'Application', t: VT_STRING },
40510x13: { n: 'DocSecurity', t: VT_I4 },
40520xFF: {}
4053};
4054
4055/* [MS-OLEPS] 2.18 */
4056var SpecialProperties = {
40570x80000000: { n: 'Locale', t: VT_UI4 },
40580x80000003: { n: 'Behavior', t: VT_UI4 },
40590x72627262: {}
4060};
4061
4062(function() {
4063 for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
4064 DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
4065})();
4066
4067var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
4068var SummaryRE = evert_key(SummaryPIDSI, "n");
4069
4070/* [MS-XLS] 2.4.63 Country/Region codes */
4071var CountryEnum = {
40720x0001: "US", // United States
40730x0002: "CA", // Canada
40740x0003: "", // Latin America (except Brazil)
40750x0007: "RU", // Russia
40760x0014: "EG", // Egypt
40770x001E: "GR", // Greece
40780x001F: "NL", // Netherlands
40790x0020: "BE", // Belgium
40800x0021: "FR", // France
40810x0022: "ES", // Spain
40820x0024: "HU", // Hungary
40830x0027: "IT", // Italy
40840x0029: "CH", // Switzerland
40850x002B: "AT", // Austria
40860x002C: "GB", // United Kingdom
40870x002D: "DK", // Denmark
40880x002E: "SE", // Sweden
40890x002F: "NO", // Norway
40900x0030: "PL", // Poland
40910x0031: "DE", // Germany
40920x0034: "MX", // Mexico
40930x0037: "BR", // Brazil
40940x003d: "AU", // Australia
40950x0040: "NZ", // New Zealand
40960x0042: "TH", // Thailand
40970x0051: "JP", // Japan
40980x0052: "KR", // Korea
40990x0054: "VN", // Viet Nam
41000x0056: "CN", // China
41010x005A: "TR", // Turkey
41020x0069: "JS", // Ramastan
41030x00D5: "DZ", // Algeria
41040x00D8: "MA", // Morocco
41050x00DA: "LY", // Libya
41060x015F: "PT", // Portugal
41070x0162: "IS", // Iceland
41080x0166: "FI", // Finland
41090x01A4: "CZ", // Czech Republic
41100x0376: "TW", // Taiwan
41110x03C1: "LB", // Lebanon
41120x03C2: "JO", // Jordan
41130x03C3: "SY", // Syria
41140x03C4: "IQ", // Iraq
41150x03C5: "KW", // Kuwait
41160x03C6: "SA", // Saudi Arabia
41170x03CB: "AE", // United Arab Emirates
41180x03CC: "IL", // Israel
41190x03CE: "QA", // Qatar
41200x03D5: "IR", // Iran
41210xFFFF: "US" // United States
4122};
4123
4124/* [MS-XLS] 2.5.127 */
4125var XLSFillPattern = [
4126 null,
4127 'solid',
4128 'mediumGray',
4129 'darkGray',
4130 'lightGray',
4131 'darkHorizontal',
4132 'darkVertical',
4133 'darkDown',
4134 'darkUp',
4135 'darkGrid',
4136 'darkTrellis',
4137 'lightHorizontal',
4138 'lightVertical',
4139 'lightDown',
4140 'lightUp',
4141 'lightGrid',
4142 'lightTrellis',
4143 'gray125',
4144 'gray0625'
4145];
4146
4147function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
4148
4149/* [MS-XLS] 2.5.161 */
4150/* [MS-XLSB] 2.5.75 Icv */
4151var _XLSIcv = rgbify([
4152 /* Color Constants */
4153 0x000000,
4154 0xFFFFFF,
4155 0xFF0000,
4156 0x00FF00,
4157 0x0000FF,
4158 0xFFFF00,
4159 0xFF00FF,
4160 0x00FFFF,
4161
4162 /* Overridable Defaults */
4163 0x000000,
4164 0xFFFFFF,
4165 0xFF0000,
4166 0x00FF00,
4167 0x0000FF,
4168 0xFFFF00,
4169 0xFF00FF,
4170 0x00FFFF,
4171
4172 0x800000,
4173 0x008000,
4174 0x000080,
4175 0x808000,
4176 0x800080,
4177 0x008080,
4178 0xC0C0C0,
4179 0x808080,
4180 0x9999FF,
4181 0x993366,
4182 0xFFFFCC,
4183 0xCCFFFF,
4184 0x660066,
4185 0xFF8080,
4186 0x0066CC,
4187 0xCCCCFF,
4188
4189 0x000080,
4190 0xFF00FF,
4191 0xFFFF00,
4192 0x00FFFF,
4193 0x800080,
4194 0x800000,
4195 0x008080,
4196 0x0000FF,
4197 0x00CCFF,
4198 0xCCFFFF,
4199 0xCCFFCC,
4200 0xFFFF99,
4201 0x99CCFF,
4202 0xFF99CC,
4203 0xCC99FF,
4204 0xFFCC99,
4205
4206 0x3366FF,
4207 0x33CCCC,
4208 0x99CC00,
4209 0xFFCC00,
4210 0xFF9900,
4211 0xFF6600,
4212 0x666699,
4213 0x969696,
4214 0x003366,
4215 0x339966,
4216 0x003300,
4217 0x333300,
4218 0x993300,
4219 0x993366,
4220 0x333399,
4221 0x333333,
4222
4223 /* Other entries to appease BIFF8/12 */
4224 0xFFFFFF, /* 0x40 icvForeground ?? */
4225 0x000000, /* 0x41 icvBackground ?? */
4226 0x000000, /* 0x42 icvFrame ?? */
4227 0x000000, /* 0x43 icv3D ?? */
4228 0x000000, /* 0x44 icv3DText ?? */
4229 0x000000, /* 0x45 icv3DHilite ?? */
4230 0x000000, /* 0x46 icv3DShadow ?? */
4231 0x000000, /* 0x47 icvHilite ?? */
4232 0x000000, /* 0x48 icvCtlText ?? */
4233 0x000000, /* 0x49 icvCtlScrl ?? */
4234 0x000000, /* 0x4A icvCtlInv ?? */
4235 0x000000, /* 0x4B icvCtlBody ?? */
4236 0x000000, /* 0x4C icvCtlFrame ?? */
4237 0x000000, /* 0x4D icvCtlFore ?? */
4238 0x000000, /* 0x4E icvCtlBack ?? */
4239 0x000000, /* 0x4F icvCtlNeutral */
4240 0x000000, /* 0x50 icvInfoBk ?? */
4241 0x000000 /* 0x51 icvInfoText ?? */
4242]);
4243var XLSIcv = dup(_XLSIcv);
4244/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
4245/* 12.3 Part Summary <SpreadsheetML> */
4246/* 14.2 Part Summary <DrawingML> */
4247/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
4248var ct2type/*{[string]:string}*/ = ({
4249 /* Workbook */
4250 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
4251
4252 /* Worksheet */
4253 "application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
4254
4255 /* Macrosheet */
4256 "application/vnd.ms-excel.intlmacrosheet": "TODO",
4257 "application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
4258
4259 /* File Properties */
4260 "application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
4261 "application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
4262 "application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
4263
4264 /* Custom Data Properties */
4265 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
4266 "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
4267
4268 /* PivotTable */
4269 "application/vnd.ms-excel.pivotTable": "TODO",
4270 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
4271
4272 /* Chart Objects */
4273 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
4274
4275 /* Chart Colors */
4276 "application/vnd.ms-office.chartcolorstyle+xml": "TODO",
4277
4278 /* Chart Style */
4279 "application/vnd.ms-office.chartstyle+xml": "TODO",
4280
4281 /* Chart Advanced */
4282 "application/vnd.ms-office.chartex+xml": "TODO",
4283
4284 /* Calculation Chain */
4285 "application/vnd.ms-excel.calcChain": "calcchains",
4286 "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
4287
4288 /* Printer Settings */
4289 "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
4290
4291 /* ActiveX */
4292 "application/vnd.ms-office.activeX": "TODO",
4293 "application/vnd.ms-office.activeX+xml": "TODO",
4294
4295 /* Custom Toolbars */
4296 "application/vnd.ms-excel.attachedToolbars": "TODO",
4297
4298 /* External Data Connections */
4299 "application/vnd.ms-excel.connections": "TODO",
4300 "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
4301
4302 /* External Links */
4303 "application/vnd.ms-excel.externalLink": "links",
4304 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
4305
4306 /* Metadata */
4307 "application/vnd.ms-excel.sheetMetadata": "TODO",
4308 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
4309
4310 /* PivotCache */
4311 "application/vnd.ms-excel.pivotCacheDefinition": "TODO",
4312 "application/vnd.ms-excel.pivotCacheRecords": "TODO",
4313 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
4314 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
4315
4316 /* Query Table */
4317 "application/vnd.ms-excel.queryTable": "TODO",
4318 "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
4319
4320 /* Shared Workbook */
4321 "application/vnd.ms-excel.userNames": "TODO",
4322 "application/vnd.ms-excel.revisionHeaders": "TODO",
4323 "application/vnd.ms-excel.revisionLog": "TODO",
4324 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
4325 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
4326 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
4327
4328 /* Single Cell Table */
4329 "application/vnd.ms-excel.tableSingleCells": "TODO",
4330 "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
4331
4332 /* Slicer */
4333 "application/vnd.ms-excel.slicer": "TODO",
4334 "application/vnd.ms-excel.slicerCache": "TODO",
4335 "application/vnd.ms-excel.slicer+xml": "TODO",
4336 "application/vnd.ms-excel.slicerCache+xml": "TODO",
4337
4338 /* Sort Map */
4339 "application/vnd.ms-excel.wsSortMap": "TODO",
4340
4341 /* Table */
4342 "application/vnd.ms-excel.table": "TODO",
4343 "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
4344
4345 /* Themes */
4346 "application/vnd.openxmlformats-officedocument.theme+xml": "themes",
4347
4348 /* Theme Override */
4349 "application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
4350
4351 /* Timeline */
4352 "application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
4353 "application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
4354
4355 /* VBA */
4356 "application/vnd.ms-office.vbaProject": "vba",
4357 "application/vnd.ms-office.vbaProjectSignature": "vba",
4358
4359 /* Volatile Dependencies */
4360 "application/vnd.ms-office.volatileDependencies": "TODO",
4361 "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
4362
4363 /* Control Properties */
4364 "application/vnd.ms-excel.controlproperties+xml": "TODO",
4365
4366 /* Data Model */
4367 "application/vnd.openxmlformats-officedocument.model+data": "TODO",
4368
4369 /* Survey */
4370 "application/vnd.ms-excel.Survey+xml": "TODO",
4371
4372 /* Drawing */
4373 "application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
4374 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
4375 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
4376 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
4377 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
4378 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
4379
4380 /* VML */
4381 "application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
4382
4383 "application/vnd.openxmlformats-package.relationships+xml": "rels",
4384 "application/vnd.openxmlformats-officedocument.oleObject": "TODO",
4385
4386 /* Image */
4387 "image/png": "TODO",
4388
4389 "sheet": "js"
4390});
4391
4392var CT_LIST = (function(){
4393 var o = {
4394 workbooks: {
4395 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
4396 xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
4397 xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
4398 xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
4399 xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
4400 },
4401 strs: { /* Shared Strings */
4402 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
4403 xlsb: "application/vnd.ms-excel.sharedStrings"
4404 },
4405 comments: { /* Comments */
4406 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
4407 xlsb: "application/vnd.ms-excel.comments"
4408 },
4409 sheets: { /* Worksheet */
4410 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
4411 xlsb: "application/vnd.ms-excel.worksheet"
4412 },
4413 charts: { /* Chartsheet */
4414 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
4415 xlsb: "application/vnd.ms-excel.chartsheet"
4416 },
4417 dialogs: { /* Dialogsheet */
4418 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
4419 xlsb: "application/vnd.ms-excel.dialogsheet"
4420 },
4421 macros: { /* Macrosheet (Excel 4.0 Macros) */
4422 xlsx: "application/vnd.ms-excel.macrosheet+xml",
4423 xlsb: "application/vnd.ms-excel.macrosheet"
4424 },
4425 styles: { /* Styles */
4426 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
4427 xlsb: "application/vnd.ms-excel.styles"
4428 }
4429 };
4430 keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
4431 keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
4432 return o;
4433})();
4434
4435var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
4436
4437XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
4438
4439function new_ct() {
4440 return ({
4441 workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
4442 rels:[], strs:[], comments:[], links:[],
4443 coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
4444 calcchains:[], vba: [], drawings: [],
4445 TODO:[], xmlns: "" });
4446}
4447
4448function parse_ct(data) {
4449 var ct = new_ct();
4450 if(!data || !data.match) return ct;
4451 var ctext = {};
4452 (data.match(tagregex)||[]).forEach(function(x) {
4453 var y = parsexmltag(x);
4454 switch(y[0].replace(nsregex,"<")) {
4455 case '<?xml': break;
4456 case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
4457 case '<Default': ctext[y.Extension] = y.ContentType; break;
4458 case '<Override':
4459 if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
4460 break;
4461 }
4462 });
4463 if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
4464 ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
4465 ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
4466 ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
4467 ct.defaults = ctext;
4468 delete ct.calcchains;
4469 return ct;
4470}
4471
4472var CTYPE_XML_ROOT = writextag('Types', null, {
4473 'xmlns': XMLNS.CT,
4474 'xmlns:xsd': XMLNS.xsd,
4475 'xmlns:xsi': XMLNS.xsi
4476});
4477
4478var CTYPE_DEFAULTS = [
4479 ['xml', 'application/xml'],
4480 ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
4481 ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
4482 ['data', 'application/vnd.openxmlformats-officedocument.model+data'],
4483 /* from test files */
4484 ['bmp', 'image/bmp'],
4485 ['png', 'image/png'],
4486 ['gif', 'image/gif'],
4487 ['emf', 'image/x-emf'],
4488 ['wmf', 'image/x-wmf'],
4489 ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
4490 ['tif', 'image/tiff'], ['tiff', 'image/tiff'],
4491 ['pdf', 'application/pdf'],
4492 ['rels', type2ct.rels[0]]
4493].map(function(x) {
4494 return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
4495});
4496
4497function write_ct(ct, opts) {
4498 var o = [], v;
4499 o[o.length] = (XML_HEADER);
4500 o[o.length] = (CTYPE_XML_ROOT);
4501 o = o.concat(CTYPE_DEFAULTS);
4502
4503 /* only write first instance */
4504 var f1 = function(w) {
4505 if(ct[w] && ct[w].length > 0) {
4506 v = ct[w][0];
4507 o[o.length] = (writextag('Override', null, {
4508 'PartName': (v[0] == '/' ? "":"/") + v,
4509 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4510 }));
4511 }
4512 };
4513
4514 /* book type-specific */
4515 var f2 = function(w) {
4516 (ct[w]||[]).forEach(function(v) {
4517 o[o.length] = (writextag('Override', null, {
4518 'PartName': (v[0] == '/' ? "":"/") + v,
4519 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4520 }));
4521 });
4522 };
4523
4524 /* standard type */
4525 var f3 = function(t) {
4526 (ct[t]||[]).forEach(function(v) {
4527 o[o.length] = (writextag('Override', null, {
4528 'PartName': (v[0] == '/' ? "":"/") + v,
4529 'ContentType': type2ct[t][0]
4530 }));
4531 });
4532 };
4533
4534 f1('workbooks');
4535 f2('sheets');
4536 f2('charts');
4537 f3('themes');
4538 ['strs', 'styles'].forEach(f1);
4539 ['coreprops', 'extprops', 'custprops'].forEach(f3);
4540 f3('vba');
4541 f3('comments');
4542 f3('drawings');
4543 if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
4544 return o.join("");
4545}
4546/* 9.3 Relationships */
4547var RELS = ({
4548 WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4549 SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4550 HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
4551 VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
4552 XPATH: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",
4553 XMISS: "http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",
4554 XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
4555 VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
4556});
4557
4558/* 9.3.3 Representing Relationships */
4559function get_rels_path(file) {
4560 var n = file.lastIndexOf("/");
4561 return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
4562}
4563
4564function parse_rels(data, currentFilePath) {
4565 var rels = {"!id":{}};
4566 if (!data) return rels;
4567 if (currentFilePath.charAt(0) !== '/') {
4568 currentFilePath = '/'+currentFilePath;
4569 }
4570 var hash = {};
4571
4572 (data.match(tagregex)||[]).forEach(function(x) {
4573 var y = parsexmltag(x);
4574 /* 9.3.2.2 OPC_Relationships */
4575 if (y[0] === '<Relationship') {
4576 var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
4577 var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
4578 rels[canonictarget] = rel;
4579 hash[y.Id] = rel;
4580 }
4581 });
4582 rels["!id"] = hash;
4583 return rels;
4584}
4585
4586XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
4587
4588var RELS_ROOT = writextag('Relationships', null, {
4589 //'xmlns:ns0': XMLNS.RELS,
4590 'xmlns': XMLNS.RELS
4591});
4592
4593/* TODO */
4594function write_rels(rels) {
4595 var o = [XML_HEADER, RELS_ROOT];
4596 keys(rels['!id']).forEach(function(rid) {
4597 o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
4598 });
4599 if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
4600 return o.join("");
4601}
4602
4603var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
4604function add_rels(rels, rId, f, type, relobj, targetmode) {
4605 if(!relobj) relobj = {};
4606 if(!rels['!id']) rels['!id'] = {};
4607 if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
4608 relobj.Id = 'rId' + rId;
4609 relobj.Type = type;
4610 relobj.Target = f;
4611 if(targetmode) relobj.TargetMode = targetmode;
4612 else if(RELS_EXTERN.indexOf(relobj.Type) > -1) relobj.TargetMode = "External";
4613 if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
4614 rels['!id'][relobj.Id] = relobj;
4615 rels[('/' + relobj.Target).replace("//","/")] = relobj;
4616 return rId;
4617}
4618/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
4619/* Part 3 Section 4 Manifest File */
4620var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
4621function parse_manifest(d, opts) {
4622 var str = xlml_normalize(d);
4623 var Rn;
4624 var FEtag;
4625 while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
4626 case 'manifest': break; // 4.2 <manifest:manifest>
4627 case 'file-entry': // 4.3 <manifest:file-entry>
4628 FEtag = parsexmltag(Rn[0], false);
4629 if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
4630 break;
4631 case 'encryption-data': // 4.4 <manifest:encryption-data>
4632 case 'algorithm': // 4.5 <manifest:algorithm>
4633 case 'start-key-generation': // 4.6 <manifest:start-key-generation>
4634 case 'key-derivation': // 4.7 <manifest:key-derivation>
4635 throw new Error("Unsupported ODS Encryption");
4636 default: if(opts && opts.WTF) throw Rn;
4637 }
4638}
4639
4640function write_manifest(manifest) {
4641 var o = [XML_HEADER];
4642 o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
4643 o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
4644 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');
4645 o.push('</manifest:manifest>');
4646 return o.join("");
4647}
4648
4649/* Part 3 Section 6 Metadata Manifest File */
4650function write_rdf_type(file, res, tag) {
4651 return [
4652 ' <rdf:Description rdf:about="' + file + '">\n',
4653 ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
4654 ' </rdf:Description>\n'
4655 ].join("");
4656}
4657function write_rdf_has(base, file) {
4658 return [
4659 ' <rdf:Description rdf:about="' + base + '">\n',
4660 ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
4661 ' </rdf:Description>\n'
4662 ].join("");
4663}
4664function write_rdf(rdf) {
4665 var o = [XML_HEADER];
4666 o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
4667 for(var i = 0; i != rdf.length; ++i) {
4668 o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
4669 o.push(write_rdf_has("",rdf[i][0]));
4670 }
4671 o.push(write_rdf_type("","Document", "pkg"));
4672 o.push('</rdf:RDF>');
4673 return o.join("");
4674}
4675/* TODO: pull properties */
4676var write_meta_ods = (function() {
4677 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>';
4678 return function wmo() {
4679 return payload;
4680 };
4681})();
4682
4683/* ECMA-376 Part II 11.1 Core Properties Part */
4684/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4685var CORE_PROPS = [
4686 ["cp:category", "Category"],
4687 ["cp:contentStatus", "ContentStatus"],
4688 ["cp:keywords", "Keywords"],
4689 ["cp:lastModifiedBy", "LastAuthor"],
4690 ["cp:lastPrinted", "LastPrinted"],
4691 ["cp:revision", "RevNumber"],
4692 ["cp:version", "Version"],
4693 ["dc:creator", "Author"],
4694 ["dc:description", "Comments"],
4695 ["dc:identifier", "Identifier"],
4696 ["dc:language", "Language"],
4697 ["dc:subject", "Subject"],
4698 ["dc:title", "Title"],
4699 ["dcterms:created", "CreatedDate", 'date'],
4700 ["dcterms:modified", "ModifiedDate", 'date']
4701];
4702
4703XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
4704RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
4705
4706var CORE_PROPS_REGEX = (function() {
4707 var r = new Array(CORE_PROPS.length);
4708 for(var i = 0; i < CORE_PROPS.length; ++i) {
4709 var f = CORE_PROPS[i];
4710 var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
4711 r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
4712 }
4713 return r;
4714})();
4715
4716function parse_core_props(data) {
4717 var p = {};
4718 data = utf8read(data);
4719
4720 for(var i = 0; i < CORE_PROPS.length; ++i) {
4721 var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4722 if(cur != null && cur.length > 0) p[f[1]] = cur[1];
4723 if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4724 }
4725
4726 return p;
4727}
4728
4729var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4730 //'xmlns': XMLNS.CORE_PROPS,
4731 'xmlns:cp': XMLNS.CORE_PROPS,
4732 'xmlns:dc': XMLNS.dc,
4733 'xmlns:dcterms': XMLNS.dcterms,
4734 'xmlns:dcmitype': XMLNS.dcmitype,
4735 'xmlns:xsi': XMLNS.xsi
4736});
4737
4738function cp_doit(f, g, h, o, p) {
4739 if(p[f] != null || g == null || g === "") return;
4740 p[f] = g;
4741 o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4742}
4743
4744function write_core_props(cp, _opts) {
4745 var opts = _opts || {};
4746 var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4747 if(!cp && !opts.Props) return o.join("");
4748
4749 if(cp) {
4750 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);
4751 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);
4752 }
4753
4754 for(var i = 0; i != CORE_PROPS.length; ++i) {
4755 var f = CORE_PROPS[i];
4756 var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4757 if(v === true) v = "1";
4758 else if(v === false) v = "0";
4759 else if(typeof v == "number") v = String(v);
4760 if(v != null) cp_doit(f[0], v, null, o, p);
4761 }
4762 if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4763 return o.join("");
4764}
4765/* 15.2.12.3 Extended File Properties Part */
4766/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4767var EXT_PROPS = [
4768 ["Application", "Application", "string"],
4769 ["AppVersion", "AppVersion", "string"],
4770 ["Company", "Company", "string"],
4771 ["DocSecurity", "DocSecurity", "string"],
4772 ["Manager", "Manager", "string"],
4773 ["HyperlinksChanged", "HyperlinksChanged", "bool"],
4774 ["SharedDoc", "SharedDoc", "bool"],
4775 ["LinksUpToDate", "LinksUpToDate", "bool"],
4776 ["ScaleCrop", "ScaleCrop", "bool"],
4777 ["HeadingPairs", "HeadingPairs", "raw"],
4778 ["TitlesOfParts", "TitlesOfParts", "raw"]
4779];
4780
4781XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4782RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4783
4784var PseudoPropsPairs = [
4785 "Worksheets", "SheetNames",
4786 "NamedRanges", "DefinedNames",
4787 "Chartsheets", "ChartNames"
4788];
4789function load_props_pairs(HP, TOP, props, opts) {
4790 var v = [];
4791 if(typeof HP == "string") v = parseVector(HP, opts);
4792 else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4793 var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4794 var idx = 0, len = 0;
4795 if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4796 len = +(v[i+1].v);
4797 switch(v[i].v) {
4798 case "Worksheets":
4799 case "工作表":
4800 case "Листы":
4801 case "أوراق العمل":
4802 case "ワークシート":
4803 case "גליונות עבודה":
4804 case "Arbeitsblätter":
4805 case "Çalışma Sayfaları":
4806 case "Feuilles de calcul":
4807 case "Fogli di lavoro":
4808 case "Folhas de cálculo":
4809 case "Planilhas":
4810 case "Regneark":
4811 case "Hojas de cálculo":
4812 case "Werkbladen":
4813 props.Worksheets = len;
4814 props.SheetNames = parts.slice(idx, idx + len);
4815 break;
4816
4817 case "Named Ranges":
4818 case "Rangos con nombre":
4819 case "名前付き一覧":
4820 case "Benannte Bereiche":
4821 case "Navngivne områder":
4822 props.NamedRanges = len;
4823 props.DefinedNames = parts.slice(idx, idx + len);
4824 break;
4825
4826 case "Charts":
4827 case "Diagramme":
4828 props.Chartsheets = len;
4829 props.ChartNames = parts.slice(idx, idx + len);
4830 break;
4831 }
4832 idx += len;
4833 }
4834}
4835
4836function parse_ext_props(data, p, opts) {
4837 var q = {}; if(!p) p = {};
4838 data = utf8read(data);
4839
4840 EXT_PROPS.forEach(function(f) {
4841 switch(f[2]) {
4842 case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
4843 case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
4844 case "raw":
4845 var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4846 if(cur && cur.length > 0) q[f[1]] = cur[1];
4847 break;
4848 }
4849 });
4850
4851 if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4852
4853 return p;
4854}
4855
4856var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4857 'xmlns': XMLNS.EXT_PROPS,
4858 'xmlns:vt': XMLNS.vt
4859});
4860
4861function write_ext_props(cp) {
4862 var o = [], W = writextag;
4863 if(!cp) cp = {};
4864 cp.Application = "SheetJS";
4865 o[o.length] = (XML_HEADER);
4866 o[o.length] = (EXT_PROPS_XML_ROOT);
4867
4868 EXT_PROPS.forEach(function(f) {
4869 if(cp[f[1]] === undefined) return;
4870 var v;
4871 switch(f[2]) {
4872 case 'string': v = String(cp[f[1]]); break;
4873 case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4874 }
4875 if(v !== undefined) o[o.length] = (W(f[0], v));
4876 });
4877
4878 /* TODO: HeadingPairs, TitlesOfParts */
4879 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"})));
4880 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"})));
4881 if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4882 return o.join("");
4883}
4884/* 15.2.12.2 Custom File Properties Part */
4885XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4886RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4887
4888var custregex = /<[^>]+>[^<]*/g;
4889function parse_cust_props(data, opts) {
4890 var p = {}, name = "";
4891 var m = data.match(custregex);
4892 if(m) for(var i = 0; i != m.length; ++i) {
4893 var x = m[i], y = parsexmltag(x);
4894 switch(y[0]) {
4895 case '<?xml': break;
4896 case '<Properties': break;
4897 case '<property': name = y.name; break;
4898 case '</property>': name = null; break;
4899 default: if (x.indexOf('<vt:') === 0) {
4900 var toks = x.split('>');
4901 var type = toks[0].slice(4), text = toks[1];
4902 /* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4903 switch(type) {
4904 case 'lpstr': case 'bstr': case 'lpwstr':
4905 p[name] = unescapexml(text);
4906 break;
4907 case 'bool':
4908 p[name] = parsexmlbool(text);
4909 break;
4910 case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4911 p[name] = parseInt(text, 10);
4912 break;
4913 case 'r4': case 'r8': case 'decimal':
4914 p[name] = parseFloat(text);
4915 break;
4916 case 'filetime': case 'date':
4917 p[name] = parseDate(text);
4918 break;
4919 case 'cy': case 'error':
4920 p[name] = unescapexml(text);
4921 break;
4922 default:
4923 if(type.slice(-1) == '/') break;
4924 if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4925 }
4926 } else if(x.slice(0,2) === "</") {/* empty */
4927 } else if(opts.WTF) throw new Error(x);
4928 }
4929 }
4930 return p;
4931}
4932
4933var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4934 'xmlns': XMLNS.CUST_PROPS,
4935 'xmlns:vt': XMLNS.vt
4936});
4937
4938function write_cust_props(cp) {
4939 var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4940 if(!cp) return o.join("");
4941 var pid = 1;
4942 keys(cp).forEach(function custprop(k) { ++pid;
4943 o[o.length] = (writextag('property', write_vt(cp[k]), {
4944 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4945 'pid': pid,
4946 'name': k
4947 }));
4948 });
4949 if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4950 return o.join("");
4951}
4952/* Common Name -> XLML Name */
4953var XLMLDocPropsMap = {
4954 Title: 'Title',
4955 Subject: 'Subject',
4956 Author: 'Author',
4957 Keywords: 'Keywords',
4958 Comments: 'Description',
4959 LastAuthor: 'LastAuthor',
4960 RevNumber: 'Revision',
4961 Application: 'AppName',
4962 /* TotalTime: 'TotalTime', */
4963 LastPrinted: 'LastPrinted',
4964 CreatedDate: 'Created',
4965 ModifiedDate: 'LastSaved',
4966 /* Pages */
4967 /* Words */
4968 /* Characters */
4969 Category: 'Category',
4970 /* PresentationFormat */
4971 Manager: 'Manager',
4972 Company: 'Company',
4973 /* Guid */
4974 /* HyperlinkBase */
4975 /* Bytes */
4976 /* Lines */
4977 /* Paragraphs */
4978 /* CharactersWithSpaces */
4979 AppVersion: 'Version',
4980
4981 ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
4982 Identifier: 'Identifier', /* NOTE: missing from schema */
4983 Language: 'Language' /* NOTE: missing from schema */
4984};
4985var evert_XLMLDPM = evert(XLMLDocPropsMap);
4986
4987function xlml_set_prop(Props, tag, val) {
4988 tag = evert_XLMLDPM[tag] || tag;
4989 Props[tag] = val;
4990}
4991
4992function xlml_write_docprops(Props, opts) {
4993 var o = [];
4994 keys(XLMLDocPropsMap).map(function(m) {
4995 for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
4996 for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
4997 throw m;
4998 }).forEach(function(p) {
4999 if(Props[p[1]] == null) return;
5000 var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
5001 switch(p[2]) {
5002 case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
5003 }
5004 if(typeof m == 'number') m = String(m);
5005 else if(m === true || m === false) { m = m ? "1" : "0"; }
5006 else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
5007 o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
5008 });
5009 return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
5010}
5011function xlml_write_custprops(Props, Custprops) {
5012 var BLACKLIST = ["Worksheets","SheetNames"];
5013 var T = 'CustomDocumentProperties';
5014 var o = [];
5015 if(Props) keys(Props).forEach(function(k) {
5016if(!Props.hasOwnProperty(k)) return;
5017 for(var i = 0; i < CORE_PROPS.length; ++i) if(k == CORE_PROPS[i][1]) return;
5018 for(i = 0; i < EXT_PROPS.length; ++i) if(k == EXT_PROPS[i][1]) return;
5019 for(i = 0; i < BLACKLIST.length; ++i) if(k == BLACKLIST[i]) return;
5020
5021 var m = Props[k];
5022 var t = "string";
5023 if(typeof m == 'number') { t = "float"; m = String(m); }
5024 else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
5025 else m = String(m);
5026 o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
5027 });
5028 if(Custprops) keys(Custprops).forEach(function(k) {
5029if(!Custprops.hasOwnProperty(k)) return;
5030 if(Props && Props.hasOwnProperty(k)) return;
5031 var m = Custprops[k];
5032 var t = "string";
5033 if(typeof m == 'number') { t = "float"; m = String(m); }
5034 else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
5035 else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); }
5036 else m = String(m);
5037 o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
5038 });
5039 return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
5040}
5041/* [MS-DTYP] 2.3.3 FILETIME */
5042/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
5043/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
5044function parse_FILETIME(blob) {
5045 var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
5046 return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
5047}
5048function write_FILETIME(time) {
5049 var date = (typeof time == "string") ? new Date(Date.parse(time)) : time;
5050 var t = date.getTime() / 1000 + 11644473600;
5051 var l = t % Math.pow(2,32), h = (t - l) / Math.pow(2,32);
5052 l *= 1e7; h *= 1e7;
5053 var w = (l / Math.pow(2,32)) | 0;
5054 if(w > 0) { l = l % Math.pow(2,32); h += w; }
5055 var o = new_buf(8); o.write_shift(4, l); o.write_shift(4, h); return o;
5056}
5057
5058/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
5059function parse_lpstr(blob, type, pad) {
5060 var start = blob.l;
5061 var str = blob.read_shift(0, 'lpstr-cp');
5062 if(pad) while((blob.l - start) & 3) ++blob.l;
5063 return str;
5064}
5065
5066/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
5067function parse_lpwstr(blob, type, pad) {
5068 var str = blob.read_shift(0, 'lpwstr');
5069 if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
5070 return str;
5071}
5072
5073
5074/* [MS-OSHARED] 2.3.3.1.11 VtString */
5075/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
5076function parse_VtStringBase(blob, stringType, pad) {
5077 if(stringType === 0x1F /*VT_LPWSTR*/) return parse_lpwstr(blob);
5078 return parse_lpstr(blob, stringType, pad);
5079}
5080
5081function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
5082function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); }
5083
5084/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
5085function parse_VtVecUnalignedLpstrValue(blob) {
5086 var length = blob.read_shift(4);
5087 var ret = [];
5088 for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,'');
5089 return ret;
5090}
5091
5092/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
5093function parse_VtVecUnalignedLpstr(blob) {
5094 return parse_VtVecUnalignedLpstrValue(blob);
5095}
5096
5097/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
5098function parse_VtHeadingPair(blob) {
5099 var headingString = parse_TypedPropertyValue(blob, VT_USTR);
5100 var headerParts = parse_TypedPropertyValue(blob, VT_I4);
5101 return [headingString, headerParts];
5102}
5103
5104/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
5105function parse_VtVecHeadingPairValue(blob) {
5106 var cElements = blob.read_shift(4);
5107 var out = [];
5108 for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
5109 return out;
5110}
5111
5112/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
5113function parse_VtVecHeadingPair(blob) {
5114 // NOTE: When invoked, wType & padding were already consumed
5115 return parse_VtVecHeadingPairValue(blob);
5116}
5117
5118/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
5119function parse_dictionary(blob,CodePage) {
5120 var cnt = blob.read_shift(4);
5121 var dict = ({});
5122 for(var j = 0; j != cnt; ++j) {
5123 var pid = blob.read_shift(4);
5124 var len = blob.read_shift(4);
5125 dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
5126 if(CodePage === 0x4B0 && (len % 2)) blob.l += 2;
5127 }
5128 if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
5129 return dict;
5130}
5131
5132/* [MS-OLEPS] 2.9 BLOB */
5133function parse_BLOB(blob) {
5134 var size = blob.read_shift(4);
5135 var bytes = blob.slice(blob.l,blob.l+size);
5136 blob.l += size;
5137 if((size & 3) > 0) blob.l += (4 - (size & 3)) & 3;
5138 return bytes;
5139}
5140
5141/* [MS-OLEPS] 2.11 ClipboardData */
5142function parse_ClipboardData(blob) {
5143 // TODO
5144 var o = {};
5145 o.Size = blob.read_shift(4);
5146 //o.Format = blob.read_shift(4);
5147 blob.l += o.Size + 3 - (o.Size - 1) % 4;
5148 return o;
5149}
5150
5151/* [MS-OLEPS] 2.15 TypedPropertyValue */
5152function parse_TypedPropertyValue(blob, type, _opts) {
5153 var t = blob.read_shift(2), ret, opts = _opts||{};
5154 blob.l += 2;
5155 if(type !== VT_VARIANT)
5156 if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
5157 switch(type === VT_VARIANT ? t : type) {
5158 case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
5159 case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
5160 case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
5161 case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
5162 case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
5163 case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
5164 case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
5165 case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
5166 case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
5167 case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw).replace(chr0,'');
5168 case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t/*, 4*/).replace(chr0,'');
5169 case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
5170 case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
5171 default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
5172 }
5173}
5174function write_TypedPropertyValue(type, value) {
5175 var o = new_buf(4), p = new_buf(4);
5176 o.write_shift(4, type == 0x50 ? 0x1F : type);
5177 switch(type) {
5178 case 0x03 /*VT_I4*/: p.write_shift(-4, value); break;
5179 case 0x05 /*VT_I4*/: p = new_buf(8); p.write_shift(8, value, 'f'); break;
5180 case 0x0B /*VT_BOOL*/: p.write_shift(4, value ? 0x01 : 0x00); break;
5181 case 0x40 /*VT_FILETIME*/: p = write_FILETIME(value); break;
5182 case 0x1F /*VT_LPWSTR*/:
5183 case 0x50 /*VT_STRING*/:
5184p = new_buf(4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
5185 p.write_shift(4, value.length + 1);
5186 p.write_shift(0, value, "dbcs");
5187 while(p.l != p.length) p.write_shift(1, 0);
5188 break;
5189 default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + value);
5190 }
5191 return bconcat([o, p]);
5192}
5193
5194/* [MS-OLEPS] 2.20 PropertySet */
5195function parse_PropertySet(blob, PIDSI) {
5196 var start_addr = blob.l;
5197 var size = blob.read_shift(4);
5198 var NumProps = blob.read_shift(4);
5199 var Props = [], i = 0;
5200 var CodePage = 0;
5201 var Dictionary = -1, DictObj = ({});
5202 for(i = 0; i != NumProps; ++i) {
5203 var PropID = blob.read_shift(4);
5204 var Offset = blob.read_shift(4);
5205 Props[i] = [PropID, Offset + start_addr];
5206 }
5207 Props.sort(function(x,y) { return x[1] - y[1]; });
5208 var PropH = {};
5209 for(i = 0; i != NumProps; ++i) {
5210 if(blob.l !== Props[i][1]) {
5211 var fail = true;
5212 if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
5213 case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break;
5214 case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
5215 case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
5216 }
5217 if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
5218 if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
5219 }
5220 if(PIDSI) {
5221 var piddsi = PIDSI[Props[i][0]];
5222 PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
5223 if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + ("0000" + String(PropH[piddsi.n] & 0xFFFF)).slice(-4);
5224 if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
5225 case 0: PropH[piddsi.n] = 1252;
5226 /* falls through */
5227 case 874:
5228 case 932:
5229 case 936:
5230 case 949:
5231 case 950:
5232 case 1250:
5233 case 1251:
5234 case 1253:
5235 case 1254:
5236 case 1255:
5237 case 1256:
5238 case 1257:
5239 case 1258:
5240 case 10000:
5241 case 1200:
5242 case 1201:
5243 case 1252:
5244 case 65000: case -536:
5245 case 65001: case -535:
5246 set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
5247 default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
5248 }
5249 } else {
5250 if(Props[i][0] === 0x1) {
5251 CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2));
5252 set_cp(CodePage);
5253 if(Dictionary !== -1) {
5254 var oldpos = blob.l;
5255 blob.l = Props[Dictionary][1];
5256 DictObj = parse_dictionary(blob,CodePage);
5257 blob.l = oldpos;
5258 }
5259 } else if(Props[i][0] === 0) {
5260 if(CodePage === 0) { Dictionary = i; blob.l = Props[i+1][1]; continue; }
5261 DictObj = parse_dictionary(blob,CodePage);
5262 } else {
5263 var name = DictObj[Props[i][0]];
5264 var val;
5265 /* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
5266 switch(blob[blob.l]) {
5267 case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
5268 case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
5269 case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
5270 case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
5271 case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
5272 case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
5273 case 0x0B /*VT_BOOL*/: blob.l += 4; val = parsebool(blob, 4); break;
5274 case 0x40 /*VT_FILETIME*/: blob.l += 4; val = parseDate(parse_FILETIME(blob)); break;
5275 default: throw new Error("unparsed value: " + blob[blob.l]);
5276 }
5277 PropH[name] = val;
5278 }
5279 }
5280 }
5281 blob.l = start_addr + size; /* step ahead to skip padding */
5282 return PropH;
5283}
5284var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs);
5285function guess_property_type(val) {
5286 switch(typeof val) {
5287 case "boolean": return 0x0B;
5288 case "number": return ((val|0)==val) ? 0x03 : 0x05;
5289 case "string": return 0x1F;
5290 case "object": if(val instanceof Date) return 0x40; break;
5291 }
5292 return -1;
5293}
5294function write_PropertySet(entries, RE, PIDSI) {
5295 var hdr = new_buf(8), piao = [], prop = [];
5296 var sz = 8, i = 0;
5297
5298 var pr = new_buf(8), pio = new_buf(8);
5299 pr.write_shift(4, 0x0002);
5300 pr.write_shift(4, 0x04B0);
5301 pio.write_shift(4, 0x0001);
5302 prop.push(pr); piao.push(pio);
5303 sz += 8 + pr.length;
5304
5305 if(!RE) {
5306 pio = new_buf(8);
5307 pio.write_shift(4, 0);
5308 piao.unshift(pio);
5309
5310 var bufs = [new_buf(4)];
5311 bufs[0].write_shift(4, entries.length);
5312 for(i = 0; i < entries.length; ++i) {
5313 var value = entries[i][0];
5314 pr = new_buf(4 + 4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
5315 pr.write_shift(4, i+2);
5316 pr.write_shift(4, value.length + 1);
5317 pr.write_shift(0, value, "dbcs");
5318 while(pr.l != pr.length) pr.write_shift(1, 0);
5319 bufs.push(pr);
5320 }
5321 pr = bconcat(bufs);
5322 prop.unshift(pr);
5323 sz += 8 + pr.length;
5324 }
5325
5326 for(i = 0; i < entries.length; ++i) {
5327 if(RE && !RE[entries[i][0]]) continue;
5328 if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue;
5329 if(entries[i][1] == null) continue;
5330
5331 var val = entries[i][1], idx = 0;
5332 if(RE) {
5333 idx = +RE[entries[i][0]];
5334 var pinfo = (PIDSI)[idx];
5335 if(pinfo.p == "version" && typeof val == "string") {
5336var arr = val.split(".");
5337 val = ((+arr[0])<<16) + ((+arr[1])||0);
5338 }
5339 pr = write_TypedPropertyValue(pinfo.t, val);
5340 } else {
5341 var T = guess_property_type(val);
5342 if(T == -1) { T = 0x1F; val = String(val); }
5343 pr = write_TypedPropertyValue(T, val);
5344 }
5345 prop.push(pr);
5346
5347 pio = new_buf(8);
5348 pio.write_shift(4, !RE ? 2+i : idx);
5349 piao.push(pio);
5350
5351 sz += 8 + pr.length;
5352 }
5353
5354 var w = 8 * (prop.length + 1);
5355 for(i = 0; i < prop.length; ++i) { piao[i].write_shift(4, w); w += prop[i].length; }
5356 hdr.write_shift(4, sz);
5357 hdr.write_shift(4, prop.length);
5358 return bconcat([hdr].concat(piao).concat(prop));
5359}
5360
5361/* [MS-OLEPS] 2.21 PropertySetStream */
5362function parse_PropertySetStream(file, PIDSI, clsid) {
5363 var blob = file.content;
5364 if(!blob) return ({});
5365 prep_blob(blob, 0);
5366
5367 var NumSets, FMTID0, FMTID1, Offset0, Offset1 = 0;
5368 blob.chk('feff', 'Byte Order: ');
5369
5370 /*var vers = */blob.read_shift(2); // TODO: check version
5371 var SystemIdentifier = blob.read_shift(4);
5372 var CLSID = blob.read_shift(16);
5373 if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
5374 NumSets = blob.read_shift(4);
5375 if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
5376 FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
5377
5378 if(NumSets === 1 && Offset0 !== blob.l) throw new Error("Length mismatch: " + Offset0 + " !== " + blob.l);
5379 else if(NumSets === 2) { FMTID1 = blob.read_shift(16); Offset1 = blob.read_shift(4); }
5380 var PSet0 = parse_PropertySet(blob, PIDSI);
5381
5382 var rval = ({ SystemIdentifier: SystemIdentifier });
5383 for(var y in PSet0) rval[y] = PSet0[y];
5384 //rval.blob = blob;
5385 rval.FMTID = FMTID0;
5386 //rval.PSet0 = PSet0;
5387 if(NumSets === 1) return rval;
5388 if(Offset1 - blob.l == 2) blob.l += 2;
5389 if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
5390 var PSet1;
5391 try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
5392 for(y in PSet1) rval[y] = PSet1[y];
5393 rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
5394 return rval;
5395}
5396function write_PropertySetStream(entries, clsid, RE, PIDSI, entries2, clsid2) {
5397 var hdr = new_buf(entries2 ? 68 : 48);
5398 var bufs = [hdr];
5399 hdr.write_shift(2, 0xFFFE);
5400 hdr.write_shift(2, 0x0000); /* TODO: type 1 props */
5401 hdr.write_shift(4, 0x32363237);
5402 hdr.write_shift(16, CFB.utils.consts.HEADER_CLSID, "hex");
5403 hdr.write_shift(4, (entries2 ? 2 : 1));
5404 hdr.write_shift(16, clsid, "hex");
5405 hdr.write_shift(4, (entries2 ? 68 : 48));
5406 var ps0 = write_PropertySet(entries, RE, PIDSI);
5407 bufs.push(ps0);
5408
5409 if(entries2) {
5410 var ps1 = write_PropertySet(entries2, null, null);
5411 hdr.write_shift(16, clsid2, "hex");
5412 hdr.write_shift(4, 68 + ps0.length);
5413 bufs.push(ps1);
5414 }
5415 return bconcat(bufs);
5416}
5417
5418function parsenoop2(blob, length) { blob.read_shift(length); return null; }
5419function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j<n; ++j) o.write_shift(1, 0); return o; }
5420
5421function parslurp(blob, length, cb) {
5422 var arr = [], target = blob.l + length;
5423 while(blob.l < target) arr.push(cb(blob, target - blob.l));
5424 if(target !== blob.l) throw new Error("Slurp error");
5425 return arr;
5426}
5427
5428function parsebool(blob, length) { return blob.read_shift(length) === 0x1; }
5429function writebool(v, o) { if(!o) o=new_buf(2); o.write_shift(2, +!!v); return o; }
5430
5431function parseuint16(blob) { return blob.read_shift(2, 'u'); }
5432function writeuint16(v, o) { if(!o) o=new_buf(2); o.write_shift(2, v); return o; }
5433function parseuint16a(blob, length) { return parslurp(blob,length,parseuint16);}
5434
5435/* --- 2.5 Structures --- */
5436
5437/* [MS-XLS] 2.5.10 Bes (boolean or error) */
5438function parse_Bes(blob) {
5439 var v = blob.read_shift(1), t = blob.read_shift(1);
5440 return t === 0x01 ? v : v === 0x01;
5441}
5442function write_Bes(v, t, o) {
5443 if(!o) o = new_buf(2);
5444 o.write_shift(1, +v);
5445 o.write_shift(1, ((t == 'e') ? 1 : 0));
5446 return o;
5447}
5448
5449/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
5450function parse_ShortXLUnicodeString(blob, length, opts) {
5451 var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1);
5452 var encoding = 'sbcs-cont';
5453 var cp = current_codepage;
5454 if(opts && opts.biff >= 8) current_codepage = 1200;
5455 if(!opts || opts.biff == 8 ) {
5456 var fHighByte = blob.read_shift(1);
5457 if(fHighByte) { encoding = 'dbcs-cont'; }
5458 } else if(opts.biff == 12) {
5459 encoding = 'wstr';
5460 }
5461 if(opts.biff >= 2 && opts.biff <= 5) encoding = 'cpstr';
5462 var o = cch ? blob.read_shift(cch, encoding) : "";
5463 current_codepage = cp;
5464 return o;
5465}
5466
5467/* 2.5.293 XLUnicodeRichExtendedString */
5468function parse_XLUnicodeRichExtendedString(blob) {
5469 var cp = current_codepage;
5470 current_codepage = 1200;
5471 var cch = blob.read_shift(2), flags = blob.read_shift(1);
5472 var /*fHighByte = flags & 0x1,*/ fExtSt = flags & 0x4, fRichSt = flags & 0x8;
5473 var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
5474 var cRun = 0, cbExtRst;
5475 var z = {};
5476 if(fRichSt) cRun = blob.read_shift(2);
5477 if(fExtSt) cbExtRst = blob.read_shift(4);
5478 var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont';
5479 var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
5480 if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
5481 if(fExtSt) blob.l += cbExtRst; //TODO: parse this
5482 z.t = msg;
5483 if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
5484 current_codepage = cp;
5485 return z;
5486}
5487
5488/* 2.5.296 XLUnicodeStringNoCch */
5489function parse_XLUnicodeStringNoCch(blob, cch, opts) {
5490 var retval;
5491 if(opts) {
5492 if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'cpstr');
5493 if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
5494 }
5495 var fHighByte = blob.read_shift(1);
5496 if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
5497 else { retval = blob.read_shift(cch, 'dbcs-cont'); }
5498 return retval;
5499}
5500
5501/* 2.5.294 XLUnicodeString */
5502function parse_XLUnicodeString(blob, length, opts) {
5503 var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
5504 if(cch === 0) { blob.l++; return ""; }
5505 return parse_XLUnicodeStringNoCch(blob, cch, opts);
5506}
5507/* BIFF5 override */
5508function parse_XLUnicodeString2(blob, length, opts) {
5509 if(opts.biff > 5) return parse_XLUnicodeString(blob, length, opts);
5510 var cch = blob.read_shift(1);
5511 if(cch === 0) { blob.l++; return ""; }
5512 return blob.read_shift(cch, (opts.biff <= 4 || !blob.lens ) ? 'cpstr' : 'sbcs-cont');
5513}
5514/* TODO: BIFF5 and lower, codepage awareness */
5515function write_XLUnicodeString(str, opts, o) {
5516 if(!o) o = new_buf(3 + 2 * str.length);
5517 o.write_shift(2, str.length);
5518 o.write_shift(1, 1);
5519 o.write_shift(31, str, 'utf16le');
5520 return o;
5521}
5522
5523/* [MS-XLS] 2.5.61 ControlInfo */
5524function parse_ControlInfo(blob) {
5525 var flags = blob.read_shift(1);
5526 blob.l++;
5527 var accel = blob.read_shift(2);
5528 blob.l += 2;
5529 return [flags, accel];
5530}
5531
5532/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
5533function parse_URLMoniker(blob) {
5534 var len = blob.read_shift(4), start = blob.l;
5535 var extra = false;
5536 if(len > 24) {
5537 /* look ahead */
5538 blob.l += len - 24;
5539 if(blob.read_shift(16) === "795881f43b1d7f48af2c825dc4852763") extra = true;
5540 blob.l = start;
5541 }
5542 var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
5543 if(extra) blob.l += 24;
5544 return url;
5545}
5546
5547/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
5548function parse_FileMoniker(blob) {
5549 blob.l += 2; //var cAnti = blob.read_shift(2);
5550 var ansiPath = blob.read_shift(0, 'lpstr-ansi');
5551 blob.l += 2; //var endServer = blob.read_shift(2);
5552 if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker");
5553 var sz = blob.read_shift(4);
5554 if(sz === 0) return ansiPath.replace(/\\/g,"/");
5555 var bytes = blob.read_shift(4);
5556 if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker");
5557 var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,"");
5558 return unicodePath;
5559}
5560
5561/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
5562function parse_HyperlinkMoniker(blob, length) {
5563 var clsid = blob.read_shift(16); length -= 16;
5564 switch(clsid) {
5565 case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
5566 case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
5567 default: throw new Error("Unsupported Moniker " + clsid);
5568 }
5569}
5570
5571/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
5572function parse_HyperlinkString(blob) {
5573 var len = blob.read_shift(4);
5574 var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
5575 return o;
5576}
5577
5578/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
5579function parse_Hyperlink(blob, length) {
5580 var end = blob.l + length;
5581 var sVer = blob.read_shift(4);
5582 if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
5583 var flags = blob.read_shift(2);
5584 blob.l += 2;
5585 var displayName, targetFrameName, moniker, oleMoniker, Loc="", guid, fileTime;
5586 if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
5587 if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
5588 if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
5589 if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
5590 if(flags & 0x0008) Loc = parse_HyperlinkString(blob, end - blob.l);
5591 if(flags & 0x0020) guid = blob.read_shift(16);
5592 if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
5593 blob.l = end;
5594 var target = targetFrameName||moniker||oleMoniker||"";
5595 if(target && Loc) target+="#"+Loc;
5596 if(!target) target = "#" + Loc;
5597 var out = ({Target:target});
5598 if(guid) out.guid = guid;
5599 if(fileTime) out.time = fileTime;
5600 if(displayName) out.Tooltip = displayName;
5601 return out;
5602}
5603function write_Hyperlink(hl) {
5604 var out = new_buf(512), i = 0;
5605 var Target = hl.Target;
5606 var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
5607 switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
5608 out.write_shift(4,2); out.write_shift(4, F);
5609 var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
5610 if(F == 0x1C) {
5611 Target = Target.slice(1);
5612 out.write_shift(4, Target.length + 1);
5613 for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
5614 out.write_shift(2, 0);
5615 } else if(F & 0x02) {
5616 data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
5617 for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
5618 out.write_shift(4, 2*(Target.length + 1));
5619 for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
5620 out.write_shift(2, 0);
5621 } else {
5622 data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
5623 for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
5624 var P = 0;
5625 while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
5626 out.write_shift(2, P);
5627 out.write_shift(4, Target.length + 1);
5628 for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
5629 out.write_shift(1, 0);
5630 out.write_shift(2, 0xFFFF);
5631 out.write_shift(2, 0xDEAD);
5632 for(i = 0; i < 6; ++i) out.write_shift(4, 0);
5633 }
5634 return out.slice(0, out.l);
5635}
5636
5637/* 2.5.178 LongRGBA */
5638function 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]; }
5639
5640/* 2.5.177 LongRGB */
5641function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
5642
5643
5644/* [MS-XLS] 2.5.19 */
5645function parse_XLSCell(blob) {
5646 var rw = blob.read_shift(2); // 0-indexed
5647 var col = blob.read_shift(2);
5648 var ixfe = blob.read_shift(2);
5649 return ({r:rw, c:col, ixfe:ixfe});
5650}
5651function write_XLSCell(R, C, ixfe, o) {
5652 if(!o) o = new_buf(6);
5653 o.write_shift(2, R);
5654 o.write_shift(2, C);
5655 o.write_shift(2, ixfe||0);
5656 return o;
5657}
5658
5659/* [MS-XLS] 2.5.134 */
5660function parse_frtHeader(blob) {
5661 var rt = blob.read_shift(2);
5662 var flags = blob.read_shift(2); // TODO: parse these flags
5663 blob.l += 8;
5664 return {type: rt, flags: flags};
5665}
5666
5667
5668
5669function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
5670
5671/* [MS-XLS] 2.5.344 */
5672function parse_XTI(blob, length, opts) {
5673 var w = opts.biff > 8 ? 4 : 2;
5674 var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
5675 return [iSupBook, itabFirst, itabLast];
5676}
5677
5678/* [MS-XLS] 2.5.218 */
5679function parse_RkRec(blob) {
5680 var ixfe = blob.read_shift(2);
5681 var RK = parse_RkNumber(blob);
5682 return [ixfe, RK];
5683}
5684
5685/* [MS-XLS] 2.5.1 */
5686function parse_AddinUdf(blob, length, opts) {
5687 blob.l += 4; length -= 4;
5688 var l = blob.l + length;
5689 var udfName = parse_ShortXLUnicodeString(blob, length, opts);
5690 var cb = blob.read_shift(2);
5691 l -= blob.l;
5692 if(cb !== l) throw new Error("Malformed AddinUdf: padding = " + l + " != " + cb);
5693 blob.l += cb;
5694 return udfName;
5695}
5696
5697/* [MS-XLS] 2.5.209 TODO: Check sizes */
5698function parse_Ref8U(blob) {
5699 var rwFirst = blob.read_shift(2);
5700 var rwLast = blob.read_shift(2);
5701 var colFirst = blob.read_shift(2);
5702 var colLast = blob.read_shift(2);
5703 return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5704}
5705function write_Ref8U(r, o) {
5706 if(!o) o = new_buf(8);
5707 o.write_shift(2, r.s.r);
5708 o.write_shift(2, r.e.r);
5709 o.write_shift(2, r.s.c);
5710 o.write_shift(2, r.e.c);
5711 return o;
5712}
5713
5714/* [MS-XLS] 2.5.211 */
5715function parse_RefU(blob) {
5716 var rwFirst = blob.read_shift(2);
5717 var rwLast = blob.read_shift(2);
5718 var colFirst = blob.read_shift(1);
5719 var colLast = blob.read_shift(1);
5720 return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5721}
5722
5723/* [MS-XLS] 2.5.207 */
5724var parse_Ref = parse_RefU;
5725
5726/* [MS-XLS] 2.5.143 */
5727function parse_FtCmo(blob) {
5728 blob.l += 4;
5729 var ot = blob.read_shift(2);
5730 var id = blob.read_shift(2);
5731 var flags = blob.read_shift(2);
5732 blob.l+=12;
5733 return [id, ot, flags];
5734}
5735
5736/* [MS-XLS] 2.5.149 */
5737function parse_FtNts(blob) {
5738 var out = {};
5739 blob.l += 4;
5740 blob.l += 16; // GUID TODO
5741 out.fSharedNote = blob.read_shift(2);
5742 blob.l += 4;
5743 return out;
5744}
5745
5746/* [MS-XLS] 2.5.142 */
5747function parse_FtCf(blob) {
5748 var out = {};
5749 blob.l += 4;
5750 blob.cf = blob.read_shift(2);
5751 return out;
5752}
5753
5754/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
5755function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
5756var FtTab = {
57570x00: parse_FtSkip, /* FtEnd */
57580x04: parse_FtSkip, /* FtMacro */
57590x05: parse_FtSkip, /* FtButton */
57600x06: parse_FtSkip, /* FtGmo */
57610x07: parse_FtCf, /* FtCf */
57620x08: parse_FtSkip, /* FtPioGrbit */
57630x09: parse_FtSkip, /* FtPictFmla */
57640x0A: parse_FtSkip, /* FtCbls */
57650x0B: parse_FtSkip, /* FtRbo */
57660x0C: parse_FtSkip, /* FtSbs */
57670x0D: parse_FtNts, /* FtNts */
57680x0E: parse_FtSkip, /* FtSbsFmla */
57690x0F: parse_FtSkip, /* FtGboData */
57700x10: parse_FtSkip, /* FtEdoData */
57710x11: parse_FtSkip, /* FtRboData */
57720x12: parse_FtSkip, /* FtCblsData */
57730x13: parse_FtSkip, /* FtLbsData */
57740x14: parse_FtSkip, /* FtCblsFmla */
57750x15: parse_FtCmo
5776};
5777function parse_FtArray(blob, length) {
5778 var tgt = blob.l + length;
5779 var fts = [];
5780 while(blob.l < tgt) {
5781 var ft = blob.read_shift(2);
5782 blob.l-=2;
5783 try {
5784 fts.push(FtTab[ft](blob, tgt - blob.l));
5785 } catch(e) { blob.l = tgt; return fts; }
5786 }
5787 if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
5788 return fts;
5789}
5790
5791/* --- 2.4 Records --- */
5792
5793/* [MS-XLS] 2.4.21 */
5794function parse_BOF(blob, length) {
5795 var o = {BIFFVer:0, dt:0};
5796 o.BIFFVer = blob.read_shift(2); length -= 2;
5797 if(length >= 2) { o.dt = blob.read_shift(2); blob.l -= 2; }
5798 switch(o.BIFFVer) {
5799 case 0x0600: /* BIFF8 */
5800 case 0x0500: /* BIFF5 */
5801 case 0x0400: /* BIFF4 */
5802 case 0x0300: /* BIFF3 */
5803 case 0x0200: /* BIFF2 */
5804 case 0x0002: case 0x0007: /* BIFF2 */
5805 break;
5806 default: if(length > 6) throw new Error("Unexpected BIFF Ver " + o.BIFFVer);
5807 }
5808
5809 blob.read_shift(length);
5810 return o;
5811}
5812function write_BOF(wb, t, o) {
5813 var h = 0x0600, w = 16;
5814 switch(o.bookType) {
5815 case 'biff8': break;
5816 case 'biff5': h = 0x0500; w = 8; break;
5817 case 'biff4': h = 0x0004; w = 6; break;
5818 case 'biff3': h = 0x0003; w = 6; break;
5819 case 'biff2': h = 0x0002; w = 4; break;
5820 case 'xla': break;
5821 default: throw new Error("unsupported BIFF version");
5822 }
5823 var out = new_buf(w);
5824 out.write_shift(2, h);
5825 out.write_shift(2, t);
5826 if(w > 4) out.write_shift(2, 0x7262);
5827 if(w > 6) out.write_shift(2, 0x07CD);
5828 if(w > 8) {
5829 out.write_shift(2, 0xC009);
5830 out.write_shift(2, 0x0001);
5831 out.write_shift(2, 0x0706);
5832 out.write_shift(2, 0x0000);
5833 }
5834 return out;
5835}
5836
5837
5838/* [MS-XLS] 2.4.146 */
5839function parse_InterfaceHdr(blob, length) {
5840 if(length === 0) return 0x04b0;
5841 if((blob.read_shift(2))!==0x04b0){/* empty */}
5842 return 0x04b0;
5843}
5844
5845
5846/* [MS-XLS] 2.4.349 */
5847function parse_WriteAccess(blob, length, opts) {
5848 if(opts.enc) { blob.l += length; return ""; }
5849 var l = blob.l;
5850 // TODO: make sure XLUnicodeString doesnt overrun
5851 var UserName = parse_XLUnicodeString2(blob, 0, opts);
5852 blob.read_shift(length + l - blob.l);
5853 return UserName;
5854}
5855function write_WriteAccess(s, opts) {
5856 var b8 = !opts || opts.biff == 8;
5857 var o = new_buf(b8 ? 112 : 54);
5858 o.write_shift(opts.biff == 8 ? 2 : 1, 7);
5859 if(b8) o.write_shift(1, 0);
5860 o.write_shift(4, 0x33336853);
5861 o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
5862 while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
5863 return o;
5864}
5865
5866/* [MS-XLS] 2.4.351 */
5867function parse_WsBool(blob, length, opts) {
5868 var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
5869 return { fDialog: flags & 0x10 };
5870}
5871
5872/* [MS-XLS] 2.4.28 */
5873function parse_BoundSheet8(blob, length, opts) {
5874 var pos = blob.read_shift(4);
5875 var hidden = blob.read_shift(1) & 0x03;
5876 var dt = blob.read_shift(1);
5877 switch(dt) {
5878 case 0: dt = 'Worksheet'; break;
5879 case 1: dt = 'Macrosheet'; break;
5880 case 2: dt = 'Chartsheet'; break;
5881 case 6: dt = 'VBAModule'; break;
5882 }
5883 var name = parse_ShortXLUnicodeString(blob, 0, opts);
5884 if(name.length === 0) name = "Sheet1";
5885 return { pos:pos, hs:hidden, dt:dt, name:name };
5886}
5887function write_BoundSheet8(data, opts) {
5888 var w = (!opts || opts.biff >= 8 ? 2 : 1);
5889 var o = new_buf(8 + w * data.name.length);
5890 o.write_shift(4, data.pos);
5891 o.write_shift(1, data.hs || 0);
5892 o.write_shift(1, data.dt);
5893 o.write_shift(1, data.name.length);
5894 if(opts.biff >= 8) o.write_shift(1, 1);
5895 o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
5896 var out = o.slice(0, o.l);
5897 out.l = o.l; return out;
5898}
5899
5900/* [MS-XLS] 2.4.265 TODO */
5901function parse_SST(blob, length) {
5902 var end = blob.l + length;
5903 var cnt = blob.read_shift(4);
5904 var ucnt = blob.read_shift(4);
5905 var strs = ([]);
5906 for(var i = 0; i != ucnt && blob.l < end; ++i) {
5907 strs.push(parse_XLUnicodeRichExtendedString(blob));
5908 }
5909 strs.Count = cnt; strs.Unique = ucnt;
5910 return strs;
5911}
5912
5913/* [MS-XLS] 2.4.107 */
5914function parse_ExtSST(blob, length) {
5915 var extsst = {};
5916 extsst.dsst = blob.read_shift(2);
5917 blob.l += length-2;
5918 return extsst;
5919}
5920
5921
5922/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
5923function parse_Row(blob) {
5924 var z = ({});
5925 z.r = blob.read_shift(2);
5926 z.c = blob.read_shift(2);
5927 z.cnt = blob.read_shift(2) - z.c;
5928 var miyRw = blob.read_shift(2);
5929 blob.l += 4; // reserved(2), unused(2)
5930 var flags = blob.read_shift(1); // various flags
5931 blob.l += 3; // reserved(8), ixfe(12), flags(4)
5932 if(flags & 0x07) z.level = flags & 0x07;
5933 // collapsed: flags & 0x10
5934 if(flags & 0x20) z.hidden = true;
5935 if(flags & 0x40) z.hpt = miyRw / 20;
5936 return z;
5937}
5938
5939
5940/* [MS-XLS] 2.4.125 */
5941function parse_ForceFullCalculation(blob) {
5942 var header = parse_frtHeader(blob);
5943 if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
5944 var fullcalc = blob.read_shift(4);
5945 return fullcalc !== 0x0;
5946}
5947
5948
5949
5950
5951
5952/* [MS-XLS] 2.4.215 rt */
5953function parse_RecalcId(blob) {
5954 blob.read_shift(2);
5955 return blob.read_shift(4);
5956}
5957
5958/* [MS-XLS] 2.4.87 */
5959function parse_DefaultRowHeight(blob, length, opts) {
5960 var f = 0;
5961 if(!(opts && opts.biff == 2)) {
5962 f = blob.read_shift(2);
5963 }
5964 var miyRw = blob.read_shift(2);
5965 if((opts && opts.biff == 2)) {
5966 f = 1 - (miyRw >> 15); miyRw &= 0x7fff;
5967 }
5968 var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
5969 return [fl, miyRw];
5970}
5971
5972/* [MS-XLS] 2.4.345 TODO */
5973function parse_Window1(blob) {
5974 var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
5975 var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
5976 var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
5977 return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
5978 FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
5979}
5980function write_Window1() {
5981 var o = new_buf(18);
5982 o.write_shift(2, 0);
5983 o.write_shift(2, 0);
5984 o.write_shift(2, 0x7260);
5985 o.write_shift(2, 0x44c0);
5986 o.write_shift(2, 0x38);
5987 o.write_shift(2, 0);
5988 o.write_shift(2, 0);
5989 o.write_shift(2, 1);
5990 o.write_shift(2, 0x01f4);
5991 return o;
5992}
5993/* [MS-XLS] 2.4.346 TODO */
5994function parse_Window2(blob, length, opts) {
5995 if(opts && opts.biff >= 2 && opts.biff < 8) return {};
5996 var f = blob.read_shift(2);
5997 return { RTL: f & 0x40 };
5998}
5999function write_Window2(view) {
6000 var o = new_buf(18), f = 0x6b6;
6001 if(view && view.RTL) f |= 0x40;
6002 o.write_shift(2, f);
6003 o.write_shift(4, 0);
6004 o.write_shift(4, 64);
6005 o.write_shift(4, 0);
6006 o.write_shift(4, 0);
6007 return o;
6008}
6009
6010/* [MS-XLS] 2.4.189 TODO */
6011function parse_Pane(/*blob, length, opts*/) {
6012}
6013
6014/* [MS-XLS] 2.4.122 TODO */
6015function parse_Font(blob, length, opts) {
6016 var o = {
6017 dyHeight: blob.read_shift(2),
6018 fl: blob.read_shift(2)
6019 };
6020 switch((opts && opts.biff) || 8) {
6021 case 2: break;
6022 case 3: case 4: blob.l += 2; break;
6023 default: blob.l += 10; break;
6024 }
6025 o.name = parse_ShortXLUnicodeString(blob, 0, opts);
6026 return o;
6027}
6028function write_Font(data, opts) {
6029 var name = data.name || "Arial";
6030 var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
6031 var o = new_buf(w);
6032 o.write_shift(2, (data.sz || 12) * 20);
6033 o.write_shift(4, 0);
6034 o.write_shift(2, 400);
6035 o.write_shift(4, 0);
6036 o.write_shift(2, 0);
6037 o.write_shift(1, name.length);
6038 if(!b5) o.write_shift(1, 1);
6039 o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
6040 return o;
6041}
6042
6043/* [MS-XLS] 2.4.149 */
6044function parse_LabelSst(blob) {
6045 var cell = parse_XLSCell(blob);
6046 cell.isst = blob.read_shift(4);
6047 return cell;
6048}
6049
6050/* [MS-XLS] 2.4.148 */
6051function parse_Label(blob, length, opts) {
6052 var target = blob.l + length;
6053 var cell = parse_XLSCell(blob, 6);
6054 if(opts.biff == 2) blob.l++;
6055 var str = parse_XLUnicodeString(blob, target - blob.l, opts);
6056 cell.val = str;
6057 return cell;
6058}
6059function write_Label(R, C, v, os, opts) {
6060 var b8 = !opts || opts.biff == 8;
6061 var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
6062 write_XLSCell(R, C, os, o);
6063 o.write_shift(2, v.length);
6064 if(b8) o.write_shift(1, 1);
6065 o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
6066 return o;
6067}
6068
6069
6070/* [MS-XLS] 2.4.126 Number Formats */
6071function parse_Format(blob, length, opts) {
6072 var numFmtId = blob.read_shift(2);
6073 var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
6074 return [numFmtId, fmtstr];
6075}
6076function write_Format(i, f, opts, o) {
6077 var b5 = (opts && (opts.biff == 5));
6078 if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
6079 o.write_shift(2, i);
6080 o.write_shift((b5 ? 1 : 2), f.length);
6081 if(!b5) o.write_shift(1, 1);
6082 o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
6083 var out = (o.length > o.l) ? o.slice(0, o.l) : o;
6084 if(out.l == null) out.l = out.length;
6085 return out;
6086}
6087var parse_BIFF2Format = parse_XLUnicodeString2;
6088
6089/* [MS-XLS] 2.4.90 */
6090function parse_Dimensions(blob, length, opts) {
6091 var end = blob.l + length;
6092 var w = opts.biff == 8 || !opts.biff ? 4 : 2;
6093 var r = blob.read_shift(w), R = blob.read_shift(w);
6094 var c = blob.read_shift(2), C = blob.read_shift(2);
6095 blob.l = end;
6096 return {s: {r:r, c:c}, e: {r:R, c:C}};
6097}
6098function write_Dimensions(range, opts) {
6099 var w = opts.biff == 8 || !opts.biff ? 4 : 2;
6100 var o = new_buf(2*w + 6);
6101 o.write_shift(w, range.s.r);
6102 o.write_shift(w, range.e.r + 1);
6103 o.write_shift(2, range.s.c);
6104 o.write_shift(2, range.e.c + 1);
6105 o.write_shift(2, 0);
6106 return o;
6107}
6108
6109/* [MS-XLS] 2.4.220 */
6110function parse_RK(blob) {
6111 var rw = blob.read_shift(2), col = blob.read_shift(2);
6112 var rkrec = parse_RkRec(blob);
6113 return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
6114}
6115
6116/* [MS-XLS] 2.4.175 */
6117function parse_MulRk(blob, length) {
6118 var target = blob.l + length - 2;
6119 var rw = blob.read_shift(2), col = blob.read_shift(2);
6120 var rkrecs = [];
6121 while(blob.l < target) rkrecs.push(parse_RkRec(blob));
6122 if(blob.l !== target) throw new Error("MulRK read error");
6123 var lastcol = blob.read_shift(2);
6124 if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
6125 return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
6126}
6127/* [MS-XLS] 2.4.174 */
6128function parse_MulBlank(blob, length) {
6129 var target = blob.l + length - 2;
6130 var rw = blob.read_shift(2), col = blob.read_shift(2);
6131 var ixfes = [];
6132 while(blob.l < target) ixfes.push(blob.read_shift(2));
6133 if(blob.l !== target) throw new Error("MulBlank read error");
6134 var lastcol = blob.read_shift(2);
6135 if(ixfes.length != lastcol - col + 1) throw new Error("MulBlank length mismatch");
6136 return {r:rw, c:col, C:lastcol, ixfe:ixfes};
6137}
6138
6139/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
6140function parse_CellStyleXF(blob, length, style, opts) {
6141 var o = {};
6142 var a = blob.read_shift(4), b = blob.read_shift(4);
6143 var c = blob.read_shift(4), d = blob.read_shift(2);
6144 o.patternType = XLSFillPattern[c >> 26];
6145
6146 if(!opts.cellStyles) return o;
6147 o.alc = a & 0x07;
6148 o.fWrap = (a >> 3) & 0x01;
6149 o.alcV = (a >> 4) & 0x07;
6150 o.fJustLast = (a >> 7) & 0x01;
6151 o.trot = (a >> 8) & 0xFF;
6152 o.cIndent = (a >> 16) & 0x0F;
6153 o.fShrinkToFit = (a >> 20) & 0x01;
6154 o.iReadOrder = (a >> 22) & 0x02;
6155 o.fAtrNum = (a >> 26) & 0x01;
6156 o.fAtrFnt = (a >> 27) & 0x01;
6157 o.fAtrAlc = (a >> 28) & 0x01;
6158 o.fAtrBdr = (a >> 29) & 0x01;
6159 o.fAtrPat = (a >> 30) & 0x01;
6160 o.fAtrProt = (a >> 31) & 0x01;
6161
6162 o.dgLeft = b & 0x0F;
6163 o.dgRight = (b >> 4) & 0x0F;
6164 o.dgTop = (b >> 8) & 0x0F;
6165 o.dgBottom = (b >> 12) & 0x0F;
6166 o.icvLeft = (b >> 16) & 0x7F;
6167 o.icvRight = (b >> 23) & 0x7F;
6168 o.grbitDiag = (b >> 30) & 0x03;
6169
6170 o.icvTop = c & 0x7F;
6171 o.icvBottom = (c >> 7) & 0x7F;
6172 o.icvDiag = (c >> 14) & 0x7F;
6173 o.dgDiag = (c >> 21) & 0x0F;
6174
6175 o.icvFore = d & 0x7F;
6176 o.icvBack = (d >> 7) & 0x7F;
6177 o.fsxButton = (d >> 14) & 0x01;
6178 return o;
6179}
6180//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
6181//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
6182
6183/* [MS-XLS] 2.4.353 TODO: actually do this right */
6184function parse_XF(blob, length, opts) {
6185 var o = {};
6186 o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
6187 o.fStyle = (o.flags >> 2) & 0x01;
6188 length -= 6;
6189 o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
6190 return o;
6191}
6192function write_XF(data, ixfeP, opts, o) {
6193 var b5 = (opts && (opts.biff == 5));
6194 if(!o) o = new_buf(b5 ? 16 : 20);
6195 o.write_shift(2, 0);
6196 if(data.style) {
6197 o.write_shift(2, (data.numFmtId||0));
6198 o.write_shift(2, 0xFFF4);
6199 } else {
6200 o.write_shift(2, (data.numFmtId||0));
6201 o.write_shift(2, (ixfeP<<4));
6202 }
6203 o.write_shift(4, 0);
6204 o.write_shift(4, 0);
6205 if(!b5) o.write_shift(4, 0);
6206 o.write_shift(2, 0);
6207 return o;
6208}
6209
6210/* [MS-XLS] 2.4.134 */
6211function parse_Guts(blob) {
6212 blob.l += 4;
6213 var out = [blob.read_shift(2), blob.read_shift(2)];
6214 if(out[0] !== 0) out[0]--;
6215 if(out[1] !== 0) out[1]--;
6216 if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
6217 return out;
6218}
6219function write_Guts(guts) {
6220 var o = new_buf(8);
6221 o.write_shift(4, 0);
6222 o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
6223 o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
6224 return o;
6225}
6226
6227/* [MS-XLS] 2.4.24 */
6228function parse_BoolErr(blob, length, opts) {
6229 var cell = parse_XLSCell(blob, 6);
6230 if(opts.biff == 2) ++blob.l;
6231 var val = parse_Bes(blob, 2);
6232 cell.val = val;
6233 cell.t = (val === true || val === false) ? 'b' : 'e';
6234 return cell;
6235}
6236function write_BoolErr(R, C, v, os, opts, t) {
6237 var o = new_buf(8);
6238 write_XLSCell(R, C, os, o);
6239 write_Bes(v, t, o);
6240 return o;
6241}
6242
6243/* [MS-XLS] 2.4.180 Number */
6244function parse_Number(blob) {
6245 var cell = parse_XLSCell(blob, 6);
6246 var xnum = parse_Xnum(blob, 8);
6247 cell.val = xnum;
6248 return cell;
6249}
6250function write_Number(R, C, v, os) {
6251 var o = new_buf(14);
6252 write_XLSCell(R, C, os, o);
6253 write_Xnum(v, o);
6254 return o;
6255}
6256
6257var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
6258
6259/* [MS-XLS] 2.4.271 */
6260function parse_SupBook(blob, length, opts) {
6261 var end = blob.l + length;
6262 var ctab = blob.read_shift(2);
6263 var cch = blob.read_shift(2);
6264 opts.sbcch = cch;
6265 if(cch == 0x0401 || cch == 0x3A01) return [cch, ctab];
6266 if(cch < 0x01 || cch >0xff) throw new Error("Unexpected SupBook type: "+cch);
6267 var virtPath = parse_XLUnicodeStringNoCch(blob, cch);
6268 /* TODO: 2.5.277 Virtual Path */
6269 var rgst = [];
6270 while(end > blob.l) rgst.push(parse_XLUnicodeString(blob));
6271 return [cch, ctab, virtPath, rgst];
6272}
6273
6274/* [MS-XLS] 2.4.105 TODO */
6275function parse_ExternName(blob, length, opts) {
6276 var flags = blob.read_shift(2);
6277 var body;
6278 var o = ({
6279 fBuiltIn: flags & 0x01,
6280 fWantAdvise: (flags >>> 1) & 0x01,
6281 fWantPict: (flags >>> 2) & 0x01,
6282 fOle: (flags >>> 3) & 0x01,
6283 fOleLink: (flags >>> 4) & 0x01,
6284 cf: (flags >>> 5) & 0x3FF,
6285 fIcon: flags >>> 15 & 0x01
6286 });
6287 if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts);
6288 //else throw new Error("unsupported SupBook cch: " + opts.sbcch);
6289 o.body = body || blob.read_shift(length-2);
6290 if(typeof body === "string") o.Name = body;
6291 return o;
6292}
6293
6294/* [MS-XLS] 2.4.150 TODO */
6295var XLSLblBuiltIn = [
6296 "_xlnm.Consolidate_Area",
6297 "_xlnm.Auto_Open",
6298 "_xlnm.Auto_Close",
6299 "_xlnm.Extract",
6300 "_xlnm.Database",
6301 "_xlnm.Criteria",
6302 "_xlnm.Print_Area",
6303 "_xlnm.Print_Titles",
6304 "_xlnm.Recorder",
6305 "_xlnm.Data_Form",
6306 "_xlnm.Auto_Activate",
6307 "_xlnm.Auto_Deactivate",
6308 "_xlnm.Sheet_Title",
6309 "_xlnm._FilterDatabase"
6310];
6311function parse_Lbl(blob, length, opts) {
6312 var target = blob.l + length;
6313 var flags = blob.read_shift(2);
6314 var chKey = blob.read_shift(1);
6315 var cch = blob.read_shift(1);
6316 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
6317 var itab = 0;
6318 if(!opts || opts.biff >= 5) {
6319 if(opts.biff != 5) blob.l += 2;
6320 itab = blob.read_shift(2);
6321 if(opts.biff == 5) blob.l += 2;
6322 blob.l += 4;
6323 }
6324 var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
6325 if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
6326 var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
6327 var rgce = target == blob.l || cce === 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
6328 return {
6329 chKey: chKey,
6330 Name: name,
6331 itab: itab,
6332 rgce: rgce
6333 };
6334}
6335
6336/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
6337function parse_ExternSheet(blob, length, opts) {
6338 if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
6339 var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
6340 while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
6341 // [iSupBook, itabFirst, itabLast];
6342 if(blob.l != target) throw new Error("Bad ExternSheet: " + blob.l + " != " + target);
6343 return o;
6344}
6345function parse_BIFF5ExternSheet(blob, length, opts) {
6346 if(blob[blob.l + 1] == 0x03) blob[blob.l]++;
6347 var o = parse_ShortXLUnicodeString(blob, length, opts);
6348 return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
6349}
6350
6351/* [MS-XLS] 2.4.176 TODO: check older biff */
6352function parse_NameCmt(blob, length, opts) {
6353 if(opts.biff < 8) { blob.l += length; return; }
6354 var cchName = blob.read_shift(2);
6355 var cchComment = blob.read_shift(2);
6356 var name = parse_XLUnicodeStringNoCch(blob, cchName, opts);
6357 var comment = parse_XLUnicodeStringNoCch(blob, cchComment, opts);
6358 return [name, comment];
6359}
6360
6361/* [MS-XLS] 2.4.260 */
6362function parse_ShrFmla(blob, length, opts) {
6363 var ref = parse_RefU(blob, 6);
6364 blob.l++;
6365 var cUse = blob.read_shift(1);
6366 length -= 8;
6367 return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
6368}
6369
6370/* [MS-XLS] 2.4.4 TODO */
6371function parse_Array(blob, length, opts) {
6372 var ref = parse_Ref(blob, 6);
6373 /* TODO: fAlwaysCalc */
6374 switch(opts.biff) {
6375 case 2: blob.l ++; length -= 7; break;
6376 case 3: case 4: blob.l += 2; length -= 8; break;
6377 default: blob.l += 6; length -= 12;
6378 }
6379 return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
6380}
6381
6382/* [MS-XLS] 2.4.173 */
6383function parse_MTRSettings(blob) {
6384 var fMTREnabled = blob.read_shift(4) !== 0x00;
6385 var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
6386 var cUserThreadCount = blob.read_shift(4);
6387 return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
6388}
6389
6390/* [MS-XLS] 2.5.186 TODO: BIFF5 */
6391function parse_NoteSh(blob, length, opts) {
6392 if(opts.biff < 8) return;
6393 var row = blob.read_shift(2), col = blob.read_shift(2);
6394 var flags = blob.read_shift(2), idObj = blob.read_shift(2);
6395 var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
6396 if(opts.biff < 8) blob.read_shift(1);
6397 return [{r:row,c:col}, stAuthor, idObj, flags];
6398}
6399
6400/* [MS-XLS] 2.4.179 */
6401function parse_Note(blob, length, opts) {
6402 /* TODO: Support revisions */
6403 return parse_NoteSh(blob, length, opts);
6404}
6405
6406/* [MS-XLS] 2.4.168 */
6407function parse_MergeCells(blob, length) {
6408 var merges = [];
6409 var cmcs = blob.read_shift(2);
6410 while (cmcs--) merges.push(parse_Ref8U(blob,length));
6411 return merges;
6412}
6413function write_MergeCells(merges) {
6414 var o = new_buf(2 + merges.length * 8);
6415 o.write_shift(2, merges.length);
6416 for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o);
6417 return o;
6418}
6419
6420/* [MS-XLS] 2.4.181 TODO: parse all the things! */
6421function parse_Obj(blob, length, opts) {
6422 if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
6423 var cmo = parse_FtCmo(blob, 22); // id, ot, flags
6424 var fts = parse_FtArray(blob, length-22, cmo[1]);
6425 return { cmo: cmo, ft:fts };
6426}
6427/* from older spec */
6428var parse_BIFF5OT = [];
6429parse_BIFF5OT[0x08] = function(blob, length) {
6430 var tgt = blob.l + length;
6431 blob.l += 10; // todo
6432 var cf = blob.read_shift(2);
6433 blob.l += 4;
6434 blob.l += 2; //var cbPictFmla = blob.read_shift(2);
6435 blob.l += 2;
6436 blob.l += 2; //var grbit = blob.read_shift(2);
6437 blob.l += 4;
6438 var cchName = blob.read_shift(1);
6439 blob.l += cchName; // TODO: stName
6440 blob.l = tgt; // TODO: fmla
6441 return { fmt:cf };
6442};
6443
6444function parse_BIFF5Obj(blob, length, opts) {
6445 blob.l += 4; //var cnt = blob.read_shift(4);
6446 var ot = blob.read_shift(2);
6447 var id = blob.read_shift(2);
6448 var grbit = blob.read_shift(2);
6449 blob.l += 2; //var colL = blob.read_shift(2);
6450 blob.l += 2; //var dxL = blob.read_shift(2);
6451 blob.l += 2; //var rwT = blob.read_shift(2);
6452 blob.l += 2; //var dyT = blob.read_shift(2);
6453 blob.l += 2; //var colR = blob.read_shift(2);
6454 blob.l += 2; //var dxR = blob.read_shift(2);
6455 blob.l += 2; //var rwB = blob.read_shift(2);
6456 blob.l += 2; //var dyB = blob.read_shift(2);
6457 blob.l += 2; //var cbMacro = blob.read_shift(2);
6458 blob.l += 6;
6459 length -= 36;
6460 var fts = [];
6461 fts.push((parse_BIFF5OT[ot]||parsenoop)(blob, length, opts));
6462 return { cmo: [id, ot, grbit], ft:fts };
6463}
6464
6465/* [MS-XLS] 2.4.329 TODO: parse properly */
6466function parse_TxO(blob, length, opts) {
6467 var s = blob.l;
6468 var texts = "";
6469try {
6470 blob.l += 4;
6471 var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
6472 var controlInfo; // eslint-disable-line no-unused-vars
6473 if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
6474 else controlInfo = parse_ControlInfo(blob, 6, opts);
6475 var cchText = blob.read_shift(2);
6476 /*var cbRuns = */blob.read_shift(2);
6477 /*var ifntEmpty = */parseuint16(blob, 2);
6478 var len = blob.read_shift(2);
6479 blob.l += len;
6480 //var fmla = parse_ObjFmla(blob, s + length - blob.l);
6481
6482 for(var i = 1; i < blob.lens.length-1; ++i) {
6483 if(blob.l-s != blob.lens[i]) throw new Error("TxO: bad continue record");
6484 var hdr = blob[blob.l];
6485 var t = parse_XLUnicodeStringNoCch(blob, blob.lens[i+1]-blob.lens[i]-1);
6486 texts += t;
6487 if(texts.length >= (hdr ? cchText : 2*cchText)) break;
6488 }
6489 if(texts.length !== cchText && texts.length !== cchText*2) {
6490 throw new Error("cchText: " + cchText + " != " + texts.length);
6491 }
6492
6493 blob.l = s + length;
6494 /* [MS-XLS] 2.5.272 TxORuns */
6495// var rgTxoRuns = [];
6496// for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
6497// var cchText2 = blob.read_shift(2);
6498// if(cchText2 !== cchText) throw new Error("TxOLastRun mismatch: " + cchText2 + " " + cchText);
6499// blob.l += 6;
6500// if(s + length != blob.l) throw new Error("TxO " + (s + length) + ", at " + blob.l);
6501 return { t: texts };
6502} catch(e) { blob.l = s + length; return { t: texts }; }
6503}
6504
6505/* [MS-XLS] 2.4.140 */
6506function parse_HLink(blob, length) {
6507 var ref = parse_Ref8U(blob, 8);
6508 blob.l += 16; /* CLSID */
6509 var hlink = parse_Hyperlink(blob, length-24);
6510 return [ref, hlink];
6511}
6512function write_HLink(hl) {
6513 var O = new_buf(24);
6514 var ref = decode_cell(hl[0]);
6515 O.write_shift(2, ref.r); O.write_shift(2, ref.r);
6516 O.write_shift(2, ref.c); O.write_shift(2, ref.c);
6517 var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
6518 for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
6519 return bconcat([O, write_Hyperlink(hl[1])]);
6520}
6521
6522
6523/* [MS-XLS] 2.4.141 */
6524function parse_HLinkTooltip(blob, length) {
6525 blob.read_shift(2);
6526 var ref = parse_Ref8U(blob, 8);
6527 var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
6528 wzTooltip = wzTooltip.replace(chr0,"");
6529 return [ref, wzTooltip];
6530}
6531function write_HLinkTooltip(hl) {
6532 var TT = hl[1].Tooltip;
6533 var O = new_buf(10 + 2 * (TT.length + 1));
6534 O.write_shift(2, 0x0800);
6535 var ref = decode_cell(hl[0]);
6536 O.write_shift(2, ref.r); O.write_shift(2, ref.r);
6537 O.write_shift(2, ref.c); O.write_shift(2, ref.c);
6538 for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
6539 O.write_shift(2, 0);
6540 return O;
6541}
6542
6543/* [MS-XLS] 2.4.63 */
6544function parse_Country(blob) {
6545 var o = [0,0], d;
6546 d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
6547 d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
6548 return o;
6549}
6550function write_Country(o) {
6551 if(!o) o = new_buf(4);
6552 o.write_shift(2, 0x01);
6553 o.write_shift(2, 0x01);
6554 return o;
6555}
6556
6557/* [MS-XLS] 2.4.50 ClrtClient */
6558function parse_ClrtClient(blob) {
6559 var ccv = blob.read_shift(2);
6560 var o = [];
6561 while(ccv-->0) o.push(parse_LongRGB(blob, 8));
6562 return o;
6563}
6564
6565/* [MS-XLS] 2.4.188 */
6566function parse_Palette(blob) {
6567 var ccv = blob.read_shift(2);
6568 var o = [];
6569 while(ccv-->0) o.push(parse_LongRGB(blob, 8));
6570 return o;
6571}
6572
6573/* [MS-XLS] 2.4.354 */
6574function parse_XFCRC(blob) {
6575 blob.l += 2;
6576 var o = {cxfs:0, crc:0};
6577 o.cxfs = blob.read_shift(2);
6578 o.crc = blob.read_shift(4);
6579 return o;
6580}
6581
6582/* [MS-XLS] 2.4.53 TODO: parse flags */
6583/* [MS-XLSB] 2.4.323 TODO: parse flags */
6584function parse_ColInfo(blob, length, opts) {
6585 if(!opts.cellStyles) return parsenoop(blob, length);
6586 var w = opts && opts.biff >= 12 ? 4 : 2;
6587 var colFirst = blob.read_shift(w);
6588 var colLast = blob.read_shift(w);
6589 var coldx = blob.read_shift(w);
6590 var ixfe = blob.read_shift(w);
6591 var flags = blob.read_shift(2);
6592 if(w == 2) blob.l += 2;
6593 var o = ({s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags});
6594 if(opts.biff >= 5 || !opts.biff) o.level = (flags >> 8) & 0x7;
6595 return o;
6596}
6597
6598/* [MS-XLS] 2.4.257 */
6599function parse_Setup(blob, length) {
6600 var o = {};
6601 if(length < 32) return o;
6602 blob.l += 16;
6603 o.header = parse_Xnum(blob, 8);
6604 o.footer = parse_Xnum(blob, 8);
6605 blob.l += 2;
6606 return o;
6607}
6608
6609/* [MS-XLS] 2.4.261 */
6610function parse_ShtProps(blob, length, opts) {
6611 var def = {area:false};
6612 if(opts.biff != 5) { blob.l += length; return def; }
6613 var d = blob.read_shift(1); blob.l += 3;
6614 if((d & 0x10)) def.area = true;
6615 return def;
6616}
6617
6618/* [MS-XLS] 2.4.241 */
6619function write_RRTabId(n) {
6620 var out = new_buf(2 * n);
6621 for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
6622 return out;
6623}
6624
6625var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
6626var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
6627var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
6628
6629/* --- Specific to versions before BIFF8 --- */
6630function parse_ImData(blob) {
6631 var cf = blob.read_shift(2);
6632 var env = blob.read_shift(2);
6633 var lcb = blob.read_shift(4);
6634 var o = {fmt:cf, env:env, len:lcb, data:blob.slice(blob.l,blob.l+lcb)};
6635 blob.l += lcb;
6636 return o;
6637}
6638
6639/* BIFF2_??? where ??? is the name from [XLS] */
6640function parse_BIFF2STR(blob, length, opts) {
6641 var cell = parse_XLSCell(blob, 6);
6642 ++blob.l;
6643 var str = parse_XLUnicodeString2(blob, length-7, opts);
6644 cell.t = 'str';
6645 cell.val = str;
6646 return cell;
6647}
6648
6649function parse_BIFF2NUM(blob) {
6650 var cell = parse_XLSCell(blob, 6);
6651 ++blob.l;
6652 var num = parse_Xnum(blob, 8);
6653 cell.t = 'n';
6654 cell.val = num;
6655 return cell;
6656}
6657function write_BIFF2NUM(r, c, val) {
6658 var out = new_buf(15);
6659 write_BIFF2Cell(out, r, c);
6660 out.write_shift(8, val, 'f');
6661 return out;
6662}
6663
6664function parse_BIFF2INT(blob) {
6665 var cell = parse_XLSCell(blob, 6);
6666 ++blob.l;
6667 var num = blob.read_shift(2);
6668 cell.t = 'n';
6669 cell.val = num;
6670 return cell;
6671}
6672function write_BIFF2INT(r, c, val) {
6673 var out = new_buf(9);
6674 write_BIFF2Cell(out, r, c);
6675 out.write_shift(2, val);
6676 return out;
6677}
6678
6679function parse_BIFF2STRING(blob) {
6680 var cch = blob.read_shift(1);
6681 if(cch === 0) { blob.l++; return ""; }
6682 return blob.read_shift(cch, 'sbcs-cont');
6683}
6684
6685/* TODO: convert to BIFF8 font struct */
6686function parse_BIFF2FONTXTRA(blob, length) {
6687 blob.l += 6; // unknown
6688 blob.l += 2; // font weight "bls"
6689 blob.l += 1; // charset
6690 blob.l += 3; // unknown
6691 blob.l += 1; // font family
6692 blob.l += length - 13;
6693}
6694
6695/* TODO: parse rich text runs */
6696function parse_RString(blob, length, opts) {
6697 var end = blob.l + length;
6698 var cell = parse_XLSCell(blob, 6);
6699 var cch = blob.read_shift(2);
6700 var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
6701 blob.l = end;
6702 cell.t = 'str';
6703 cell.val = str;
6704 return cell;
6705}
6706/* from js-harb (C) 2014-present SheetJS */
6707var DBF = (function() {
6708var dbf_codepage_map = {
6709 /* Code Pages Supported by Visual FoxPro */
67100x01: 437, 0x02: 850,
67110x03: 1252, 0x04: 10000,
67120x64: 852, 0x65: 866,
67130x66: 865, 0x67: 861,
67140x68: 895, 0x69: 620,
67150x6A: 737, 0x6B: 857,
67160x78: 950, 0x79: 949,
67170x7A: 936, 0x7B: 932,
67180x7C: 874, 0x7D: 1255,
67190x7E: 1256, 0x96: 10007,
67200x97: 10029, 0x98: 10006,
67210xC8: 1250, 0xC9: 1251,
67220xCA: 1254, 0xCB: 1253,
6723
6724 /* shapefile DBF extension */
67250x00: 20127, 0x08: 865,
67260x09: 437, 0x0A: 850,
67270x0B: 437, 0x0D: 437,
67280x0E: 850, 0x0F: 437,
67290x10: 850, 0x11: 437,
67300x12: 850, 0x13: 932,
67310x14: 850, 0x15: 437,
67320x16: 850, 0x17: 865,
67330x18: 437, 0x19: 437,
67340x1A: 850, 0x1B: 437,
67350x1C: 863, 0x1D: 850,
67360x1F: 852, 0x22: 852,
67370x23: 852, 0x24: 860,
67380x25: 850, 0x26: 866,
67390x37: 850, 0x40: 852,
67400x4D: 936, 0x4E: 949,
67410x4F: 950, 0x50: 874,
67420x57: 1252, 0x58: 1252,
67430x59: 1252,
6744
67450xFF: 16969
6746};
6747var dbf_reverse_map = evert({
67480x01: 437, 0x02: 850,
67490x03: 1252, 0x04: 10000,
67500x64: 852, 0x65: 866,
67510x66: 865, 0x67: 861,
67520x68: 895, 0x69: 620,
67530x6A: 737, 0x6B: 857,
67540x78: 950, 0x79: 949,
67550x7A: 936, 0x7B: 932,
67560x7C: 874, 0x7D: 1255,
67570x7E: 1256, 0x96: 10007,
67580x97: 10029, 0x98: 10006,
67590xC8: 1250, 0xC9: 1251,
67600xCA: 1254, 0xCB: 1253,
67610x00: 20127
6762});
6763/* TODO: find an actual specification */
6764function dbf_to_aoa(buf, opts) {
6765 var out = [];
6766 /* TODO: browser based */
6767 var d = (new_raw_buf(1));
6768 switch(opts.type) {
6769 case 'base64': d = s2a(Base64.decode(buf)); break;
6770 case 'binary': d = s2a(buf); break;
6771 case 'buffer':
6772 case 'array': d = buf; break;
6773 }
6774 prep_blob(d, 0);
6775 /* header */
6776 var ft = d.read_shift(1);
6777 var memo = false;
6778 var vfp = false, l7 = false;
6779 switch(ft) {
6780 case 0x02: case 0x03: break;
6781 case 0x30: vfp = true; memo = true; break;
6782 case 0x31: vfp = true; break;
6783 case 0x83: memo = true; break;
6784 case 0x8B: memo = true; break;
6785 case 0x8C: memo = true; l7 = true; break;
6786 case 0xF5: memo = true; break;
6787 default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
6788 }
6789 var /*filedate = new Date(),*/ nrow = 0, fpos = 0;
6790 if(ft == 0x02) nrow = d.read_shift(2);
6791 /*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3;
6792 if(ft != 0x02) nrow = d.read_shift(4);
6793 if(ft != 0x02) fpos = d.read_shift(2);
6794 var rlen = d.read_shift(2);
6795
6796 var /*flags = 0,*/ current_cp = 1252;
6797 if(ft != 0x02) {
6798 d.l+=16;
6799 /*flags = */d.read_shift(1);
6800 //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
6801
6802 /* codepage present in FoxPro */
6803 if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
6804 d.l+=1;
6805
6806 d.l+=2;
6807 }
6808 if(l7) d.l += 36;
6809var fields = [], field = ({});
6810 var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
6811 while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
6812 field = ({});
6813 field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
6814 d.l += ww;
6815 field.type = String.fromCharCode(d.read_shift(1));
6816 if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
6817 field.len = d.read_shift(1);
6818 if(ft == 0x02) field.offset = d.read_shift(2);
6819 field.dec = d.read_shift(1);
6820 if(field.name.length) fields.push(field);
6821 if(ft != 0x02) d.l += l7 ? 13 : 14;
6822 switch(field.type) {
6823 case 'B': // VFP Double
6824 if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6825 break;
6826 case 'G': // General
6827 case 'P': // Picture
6828 if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6829 break;
6830 case 'C': // character
6831 case 'D': // date
6832 case 'F': // floating point
6833 case 'I': // long
6834 case 'L': // boolean
6835 case 'M': // memo
6836 case 'N': // number
6837 case 'O': // double
6838 case 'T': // datetime
6839 case 'Y': // currency
6840 case '0': // VFP _NullFlags
6841 case '@': // timestamp
6842 case '+': // autoincrement
6843 break;
6844 default: throw new Error('Unknown Field Type: ' + field.type);
6845 }
6846 }
6847 if(d[d.l] !== 0x0D) d.l = fpos-1;
6848 else if(ft == 0x02) d.l = 0x209;
6849 if(ft != 0x02) {
6850 if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
6851 d.l = fpos;
6852 }
6853 /* data */
6854 var R = 0, C = 0;
6855 out[0] = [];
6856 for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
6857 while(nrow-- > 0) {
6858 if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
6859 ++d.l;
6860 out[++R] = []; C = 0;
6861 for(C = 0; C != fields.length; ++C) {
6862 var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
6863 prep_blob(dd, 0);
6864 var s = cptable.utils.decode(current_cp, dd);
6865 switch(fields[C].type) {
6866 case 'C':
6867 out[R][C] = cptable.utils.decode(current_cp, dd);
6868 out[R][C] = out[R][C].trim();
6869 break;
6870 case 'D':
6871 if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
6872 else out[R][C] = s;
6873 break;
6874 case 'F': out[R][C] = parseFloat(s.trim()); break;
6875 case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
6876 case 'L': switch(s.toUpperCase()) {
6877 case 'Y': case 'T': out[R][C] = true; break;
6878 case 'N': case 'F': out[R][C] = false; break;
6879 case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
6880 default: throw new Error("DBF Unrecognized L:|" + s + "|");
6881 } break;
6882 case 'M': /* TODO: handle memo files */
6883 if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
6884 out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
6885 break;
6886 case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
6887 case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
6888 case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
6889 case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
6890 case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
6891 case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
6892 /* falls through */
6893 case 'G': case 'P': dd.l += fields[C].len; break;
6894 case '0':
6895 if(fields[C].name === '_NullFlags') break;
6896 /* falls through */
6897 default: throw new Error("DBF Unsupported data type " + fields[C].type);
6898 }
6899 }
6900 }
6901 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));
6902 if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
6903 return out;
6904}
6905
6906function dbf_to_sheet(buf, opts) {
6907 var o = opts || {};
6908 if(!o.dateNF) o.dateNF = "yyyymmdd";
6909 return aoa_to_sheet(dbf_to_aoa(buf, o), o);
6910}
6911
6912function dbf_to_workbook(buf, opts) {
6913 try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
6914 catch(e) { if(opts && opts.WTF) throw e; }
6915 return ({SheetNames:[],Sheets:{}});
6916}
6917
6918var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
6919function sheet_to_dbf(ws, opts) {
6920 var o = opts || {};
6921 if(+o.codepage >= 0) set_cp(+o.codepage);
6922 if(o.type == "string") throw new Error("Cannot write DBF to JS string");
6923 var ba = buf_array();
6924 var aoa = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
6925 var headers = aoa[0], data = aoa.slice(1);
6926 var i = 0, j = 0, hcnt = 0, rlen = 1;
6927 for(i = 0; i < headers.length; ++i) {
6928 if(i == null) continue;
6929 ++hcnt;
6930 if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
6931 if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
6932 if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
6933 if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
6934 }
6935 var range = safe_decode_range(ws['!ref']);
6936 var coltypes = [];
6937 for(i = 0; i <= range.e.c - range.s.c; ++i) {
6938 var col = [];
6939 for(j=0; j < data.length; ++j) {
6940 if(data[j][i] != null) col.push(data[j][i]);
6941 }
6942 if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
6943 var guess = '', _guess = '';
6944 for(j = 0; j < col.length; ++j) {
6945 switch(typeof col[j]) {
6946 /* TODO: check if L2 compat is desired */
6947 case 'number': _guess = 'B'; break;
6948 case 'string': _guess = 'C'; break;
6949 case 'boolean': _guess = 'L'; break;
6950 case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
6951 default: _guess = 'C';
6952 }
6953 guess = guess && guess != _guess ? 'C' : _guess;
6954 if(guess == 'C') break;
6955 }
6956 rlen += _RLEN[guess] || 0;
6957 coltypes[i] = guess;
6958 }
6959
6960 var h = ba.next(32);
6961 h.write_shift(4, 0x13021130);
6962 h.write_shift(4, data.length);
6963 h.write_shift(2, 296 + 32 * hcnt);
6964 h.write_shift(2, rlen);
6965 for(i=0; i < 4; ++i) h.write_shift(4, 0);
6966 h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[current_ansi] || 0x03)<<8));
6967
6968 for(i = 0, j = 0; i < headers.length; ++i) {
6969 if(headers[i] == null) continue;
6970 var hf = ba.next(32);
6971 var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
6972 hf.write_shift(1, _f, "sbcs");
6973 hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
6974 hf.write_shift(4, j);
6975 hf.write_shift(1, _RLEN[coltypes[i]] || 0);
6976 hf.write_shift(1, 0);
6977 hf.write_shift(1, 0x02);
6978 hf.write_shift(4, 0);
6979 hf.write_shift(1, 0);
6980 hf.write_shift(4, 0);
6981 hf.write_shift(4, 0);
6982 j += _RLEN[coltypes[i]] || 0;
6983 }
6984
6985 var hb = ba.next(264);
6986 hb.write_shift(4, 0x0000000D);
6987 for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
6988 for(i=0; i < data.length; ++i) {
6989 var rout = ba.next(rlen);
6990 rout.write_shift(1, 0);
6991 for(j=0; j<headers.length; ++j) {
6992 if(headers[j] == null) continue;
6993 switch(coltypes[j]) {
6994 case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
6995 case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
6996 case 'D':
6997 if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
6998 else {
6999 rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
7000 rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
7001 rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
7002 } break;
7003 case 'C':
7004 var _s = String(data[i][j]||"");
7005 rout.write_shift(1, _s, "sbcs");
7006 for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
7007 }
7008 }
7009 // data
7010 }
7011 ba.next(1).write_shift(1, 0x1A);
7012 return ba.end();
7013}
7014 return {
7015 to_workbook: dbf_to_workbook,
7016 to_sheet: dbf_to_sheet,
7017 from_sheet: sheet_to_dbf
7018 };
7019})();
7020
7021var SYLK = (function() {
7022 /* TODO: stress test sequences */
7023 var sylk_escapes = ({
7024 AA:'À', BA:'Á', CA:'Â', DA:195, HA:'Ä', JA:197,
7025 AE:'È', BE:'É', CE:'Ê', HE:'Ë',
7026 AI:'Ì', BI:'Í', CI:'Î', HI:'Ï',
7027 AO:'Ò', BO:'Ó', CO:'Ô', DO:213, HO:'Ö',
7028 AU:'Ù', BU:'Ú', CU:'Û', HU:'Ü',
7029 Aa:'à', Ba:'á', Ca:'â', Da:227, Ha:'ä', Ja:229,
7030 Ae:'è', Be:'é', Ce:'ê', He:'ë',
7031 Ai:'ì', Bi:'í', Ci:'î', Hi:'ï',
7032 Ao:'ò', Bo:'ó', Co:'ô', Do:245, Ho:'ö',
7033 Au:'ù', Bu:'ú', Cu:'û', Hu:'ü',
7034 KC:'Ç', Kc:'ç', q:'æ', z:'œ', a:'Æ', j:'Œ',
7035 DN:209, Dn:241, Hy:255,
7036 S:169, c:170, R:174, B:180,
70370:176, 1:177, 2:178,
70383:179, 5:181, 6:182,
70397:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
7040 "!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
7041 "+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
7042 });
7043 var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
7044 var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
7045 var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
7046 sylk_escapes["|"] = 254;
7047 /* TODO: find an actual specification */
7048 function sylk_to_aoa(d, opts) {
7049 switch(opts.type) {
7050 case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
7051 case 'binary': return sylk_to_aoa_str(d, opts);
7052 case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts);
7053 case 'array': return sylk_to_aoa_str(cc2str(d), opts);
7054 }
7055 throw new Error("Unrecognized type " + opts.type);
7056 }
7057 function sylk_to_aoa_str(str, opts) {
7058 var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
7059 var formats = [];
7060 var next_cell_format = null;
7061 var sht = {}, rowinfo = [], colinfo = [], cw = [];
7062 var Mval = 0, j;
7063 if(+opts.codepage >= 0) set_cp(+opts.codepage);
7064 for (; ri !== records.length; ++ri) {
7065 Mval = 0;
7066 var rstr=records[ri].trim().replace(/\x1B([\x20-\x2F])([\x30-\x3F])/g, decode_sylk_char).replace(sylk_char_regex, sylk_char_fn);
7067 var record=rstr.replace(/;;/g, "\u0000").split(";").map(function(x) { return x.replace(/\u0000/g, ";"); });
7068 var RT=record[0], val;
7069 if(rstr.length > 0) switch(RT) {
7070 case 'ID': break; /* header */
7071 case 'E': break; /* EOF */
7072 case 'B': break; /* dimensions */
7073 case 'O': break; /* options? */
7074 case 'P':
7075 if(record[1].charAt(0) == 'P')
7076 formats.push(rstr.slice(3).replace(/;;/g, ";"));
7077 break;
7078 case 'C':
7079 var C_seen_K = false, C_seen_X = false;
7080 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
7081 case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
7082 case 'Y':
7083 R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
7084 for(j = arr.length; j <= R; ++j) arr[j] = [];
7085 break;
7086 case 'K':
7087 val = record[rj].slice(1);
7088 if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
7089 else if(val === 'TRUE') val = true;
7090 else if(val === 'FALSE') val = false;
7091 else if(!isNaN(fuzzynum(val))) {
7092 val = fuzzynum(val);
7093 if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
7094 } else if(!isNaN(fuzzydate(val).getDate())) {
7095 val = parseDate(val);
7096 }
7097 if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
7098 C_seen_K = true;
7099 break;
7100 case 'E':
7101 var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
7102 arr[R][C] = [arr[R][C], formula];
7103 break;
7104 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7105 }
7106 if(C_seen_K) { arr[R][C] = val; next_cell_format = null; }
7107 break;
7108 case 'F':
7109 var F_seen = 0;
7110 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
7111 case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
7112 case 'Y':
7113 R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
7114 for(j = arr.length; j <= R; ++j) arr[j] = [];
7115 break;
7116 case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
7117 case 'F': break; /* ??? */
7118 case 'G': break; /* hide grid */
7119 case 'P':
7120 next_cell_format = formats[parseInt(record[rj].slice(1))];
7121 break;
7122 case 'S': break; /* cell style */
7123 case 'D': break; /* column */
7124 case 'N': break; /* font */
7125 case 'W':
7126 cw = record[rj].slice(1).split(" ");
7127 for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
7128 Mval = parseInt(cw[2], 10);
7129 colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
7130 } break;
7131 case 'C': /* default column format */
7132 C = parseInt(record[rj].slice(1))-1;
7133 if(!colinfo[C]) colinfo[C] = {};
7134 break;
7135 case 'R': /* row properties */
7136 R = parseInt(record[rj].slice(1))-1;
7137 if(!rowinfo[R]) rowinfo[R] = {};
7138 if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
7139 else if(Mval === 0) rowinfo[R].hidden = true;
7140 break;
7141 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7142 }
7143 if(F_seen < 1) next_cell_format = null; break;
7144 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7145 }
7146 }
7147 if(rowinfo.length > 0) sht['!rows'] = rowinfo;
7148 if(colinfo.length > 0) sht['!cols'] = colinfo;
7149 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7150 return [arr, sht];
7151 }
7152
7153 function sylk_to_sheet(d, opts) {
7154 var aoasht = sylk_to_aoa(d, opts);
7155 var aoa = aoasht[0], ws = aoasht[1];
7156 var o = aoa_to_sheet(aoa, opts);
7157 keys(ws).forEach(function(k) { o[k] = ws[k]; });
7158 return o;
7159 }
7160
7161 function sylk_to_workbook(d, opts) { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
7162
7163 function write_ws_cell_sylk(cell, ws, R, C) {
7164 var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
7165 switch(cell.t) {
7166 case 'n':
7167 o += (cell.v||0);
7168 if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
7169 case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
7170 case 'e': o += cell.w || cell.v; break;
7171 case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
7172 case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
7173 }
7174 return o;
7175 }
7176
7177 function write_ws_cols_sylk(out, cols) {
7178 cols.forEach(function(col, i) {
7179 var rec = "F;W" + (i+1) + " " + (i+1) + " ";
7180 if(col.hidden) rec += "0";
7181 else {
7182 if(typeof col.width == 'number') col.wpx = width2px(col.width);
7183 if(typeof col.wpx == 'number') col.wch = px2char(col.wpx);
7184 if(typeof col.wch == 'number') rec += Math.round(col.wch);
7185 }
7186 if(rec.charAt(rec.length - 1) != " ") out.push(rec);
7187 });
7188 }
7189
7190 function write_ws_rows_sylk(out, rows) {
7191 rows.forEach(function(row, i) {
7192 var rec = "F;";
7193 if(row.hidden) rec += "M0;";
7194 else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
7195 else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
7196 if(rec.length > 2) out.push(rec + "R" + (i+1));
7197 });
7198 }
7199
7200 function sheet_to_sylk(ws, opts) {
7201 var preamble = ["ID;PWXL;N;E"], o = [];
7202 var r = safe_decode_range(ws['!ref']), cell;
7203 var dense = Array.isArray(ws);
7204 var RS = "\r\n";
7205
7206 preamble.push("P;PGeneral");
7207 preamble.push("F;P0;DG0G8;M255");
7208 if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
7209 if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
7210
7211 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(" "));
7212 for(var R = r.s.r; R <= r.e.r; ++R) {
7213 for(var C = r.s.c; C <= r.e.c; ++C) {
7214 var coord = encode_cell({r:R,c:C});
7215 cell = dense ? (ws[R]||[])[C]: ws[coord];
7216 if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
7217 o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
7218 }
7219 }
7220 return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
7221 }
7222
7223 return {
7224 to_workbook: sylk_to_workbook,
7225 to_sheet: sylk_to_sheet,
7226 from_sheet: sheet_to_sylk
7227 };
7228})();
7229
7230var DIF = (function() {
7231 function dif_to_aoa(d, opts) {
7232 switch(opts.type) {
7233 case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
7234 case 'binary': return dif_to_aoa_str(d, opts);
7235 case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts);
7236 case 'array': return dif_to_aoa_str(cc2str(d), opts);
7237 }
7238 throw new Error("Unrecognized type " + opts.type);
7239 }
7240 function dif_to_aoa_str(str, opts) {
7241 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
7242 for (; ri !== records.length; ++ri) {
7243 if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
7244 if (R < 0) continue;
7245 var metadata = records[ri].trim().split(",");
7246 var type = metadata[0], value = metadata[1];
7247 ++ri;
7248 var data = records[ri].trim();
7249 switch (+type) {
7250 case -1:
7251 if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
7252 else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
7253 break;
7254 case 0:
7255 if(data === 'TRUE') arr[R][C] = true;
7256 else if(data === 'FALSE') arr[R][C] = false;
7257 else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
7258 else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
7259 else arr[R][C] = value;
7260 ++C; break;
7261 case 1:
7262 data = data.slice(1,data.length-1);
7263 arr[R][C++] = data !== '' ? data : null;
7264 break;
7265 }
7266 if (data === 'EOD') break;
7267 }
7268 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7269 return arr;
7270 }
7271
7272 function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
7273 function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
7274
7275 var sheet_to_dif = (function() {
7276 var push_field = function pf(o, topic, v, n, s) {
7277 o.push(topic);
7278 o.push(v + "," + n);
7279 o.push('"' + s.replace(/"/g,'""') + '"');
7280 };
7281 var push_value = function po(o, type, v, s) {
7282 o.push(type + "," + v);
7283 o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
7284 };
7285 return function sheet_to_dif(ws) {
7286 var o = [];
7287 var r = safe_decode_range(ws['!ref']), cell;
7288 var dense = Array.isArray(ws);
7289 push_field(o, "TABLE", 0, 1, "sheetjs");
7290 push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
7291 push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
7292 push_field(o, "DATA", 0, 0,"");
7293 for(var R = r.s.r; R <= r.e.r; ++R) {
7294 push_value(o, -1, 0, "BOT");
7295 for(var C = r.s.c; C <= r.e.c; ++C) {
7296 var coord = encode_cell({r:R,c:C});
7297 cell = dense ? (ws[R]||[])[C] : ws[coord];
7298 if(!cell) { push_value(o, 1, 0, ""); continue;}
7299 switch(cell.t) {
7300 case 'n':
7301 var val = DIF_XL ? cell.w : cell.v;
7302 if(!val && cell.v != null) val = cell.v;
7303 if(val == null) {
7304 if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
7305 else push_value(o, 1, 0, "");
7306 }
7307 else push_value(o, 0, val, "V");
7308 break;
7309 case 'b':
7310 push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
7311 break;
7312 case 's':
7313 push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
7314 break;
7315 case 'd':
7316 if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
7317 if(DIF_XL) push_value(o, 0, cell.w, "V");
7318 else push_value(o, 1, 0, cell.w);
7319 break;
7320 default: push_value(o, 1, 0, "");
7321 }
7322 }
7323 }
7324 push_value(o, -1, 0, "EOD");
7325 var RS = "\r\n";
7326 var oo = o.join(RS);
7327 //while((oo.length & 0x7F) != 0) oo += "\0";
7328 return oo;
7329 };
7330 })();
7331 return {
7332 to_workbook: dif_to_workbook,
7333 to_sheet: dif_to_sheet,
7334 from_sheet: sheet_to_dif
7335 };
7336})();
7337
7338var ETH = (function() {
7339 function decode(s) { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
7340 function encode(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
7341
7342 function eth_to_aoa(str, opts) {
7343 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
7344 for (; ri !== records.length; ++ri) {
7345 var record = records[ri].trim().split(":");
7346 if(record[0] !== 'cell') continue;
7347 var addr = decode_cell(record[1]);
7348 if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
7349 R = addr.r; C = addr.c;
7350 switch(record[2]) {
7351 case 't': arr[R][C] = decode(record[3]); break;
7352 case 'v': arr[R][C] = +record[3]; break;
7353 case 'vtf': var _f = record[record.length - 1];
7354 /* falls through */
7355 case 'vtc':
7356 switch(record[3]) {
7357 case 'nl': arr[R][C] = +record[4] ? true : false; break;
7358 default: arr[R][C] = +record[4]; break;
7359 }
7360 if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
7361 }
7362 }
7363 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7364 return arr;
7365 }
7366
7367 function eth_to_sheet(d, opts) { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
7368 function eth_to_workbook(d, opts) { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
7369
7370 var header = [
7371 "socialcalc:version:1.5",
7372 "MIME-Version: 1.0",
7373 "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
7374 ].join("\n");
7375
7376 var sep = [
7377 "--SocialCalcSpreadsheetControlSave",
7378 "Content-type: text/plain; charset=UTF-8"
7379 ].join("\n") + "\n";
7380
7381 /* TODO: the other parts */
7382 var meta = [
7383 "# SocialCalc Spreadsheet Control Save",
7384 "part:sheet"
7385 ].join("\n");
7386
7387 var end = "--SocialCalcSpreadsheetControlSave--";
7388
7389 function sheet_to_eth_data(ws) {
7390 if(!ws || !ws['!ref']) return "";
7391 var o = [], oo = [], cell, coord = "";
7392 var r = decode_range(ws['!ref']);
7393 var dense = Array.isArray(ws);
7394 for(var R = r.s.r; R <= r.e.r; ++R) {
7395 for(var C = r.s.c; C <= r.e.c; ++C) {
7396 coord = encode_cell({r:R,c:C});
7397 cell = dense ? (ws[R]||[])[C] : ws[coord];
7398 if(!cell || cell.v == null || cell.t === 'z') continue;
7399 oo = ["cell", coord, 't'];
7400 switch(cell.t) {
7401 case 's': case 'str': oo.push(encode(cell.v)); break;
7402 case 'n':
7403 if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
7404 else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
7405 break;
7406 case 'b':
7407 oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
7408 oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
7409 break;
7410 case 'd':
7411 var t = datenum(parseDate(cell.v));
7412 oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
7413 oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
7414 break;
7415 case 'e': continue;
7416 }
7417 o.push(oo.join(":"));
7418 }
7419 }
7420 o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
7421 o.push("valueformat:1:text-wiki");
7422 //o.push("copiedfrom:" + ws['!ref']); // clipboard only
7423 return o.join("\n");
7424 }
7425
7426 function sheet_to_eth(ws) {
7427 return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
7428 // return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
7429 }
7430
7431 return {
7432 to_workbook: eth_to_workbook,
7433 to_sheet: eth_to_sheet,
7434 from_sheet: sheet_to_eth
7435 };
7436})();
7437
7438var PRN = (function() {
7439 function set_text_arr(data, arr, R, C, o) {
7440 if(o.raw) arr[R][C] = data;
7441 else if(data === 'TRUE') arr[R][C] = true;
7442 else if(data === 'FALSE') arr[R][C] = false;
7443 else if(data === ""){/* empty */}
7444 else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
7445 else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
7446 else arr[R][C] = data;
7447 }
7448
7449 function prn_to_aoa_str(f, opts) {
7450 var o = opts || {};
7451 var arr = ([]);
7452 if(!f || f.length === 0) return arr;
7453 var lines = f.split(/[\r\n]/);
7454 var L = lines.length - 1;
7455 while(L >= 0 && lines[L].length === 0) --L;
7456 var start = 10, idx = 0;
7457 var R = 0;
7458 for(; R <= L; ++R) {
7459 idx = lines[R].indexOf(" ");
7460 if(idx == -1) idx = lines[R].length; else idx++;
7461 start = Math.max(start, idx);
7462 }
7463 for(R = 0; R <= L; ++R) {
7464 arr[R] = [];
7465 /* TODO: confirm that widths are always 10 */
7466 var C = 0;
7467 set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
7468 for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
7469 set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
7470 }
7471 if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
7472 return arr;
7473 }
7474
7475 // List of accepted CSV separators
7476 var guess_seps = {
74770x2C: ',',
74780x09: "\t",
74790x3B: ';'
7480 };
7481
7482 // CSV separator weights to be used in case of equal numbers
7483 var guess_sep_weights = {
74840x2C: 3,
74850x09: 2,
74860x3B: 1
7487 };
7488
7489 function guess_sep(str) {
7490 var cnt = {}, instr = false, end = 0, cc = 0;
7491 for(;end < str.length;++end) {
7492 if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
7493 else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
7494 }
7495
7496 cc = [];
7497 for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
7498 cc.push([ cnt[end], end ]);
7499 }
7500
7501 if ( !cc.length ) {
7502 cnt = guess_sep_weights;
7503 for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
7504 cc.push([ cnt[end], end ]);
7505 }
7506 }
7507
7508 cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
7509
7510 return guess_seps[cc.pop()[1]];
7511 }
7512
7513 function dsv_to_sheet_str(str, opts) {
7514 var o = opts || {};
7515 var sep = "";
7516 if(DENSE != null && o.dense == null) o.dense = DENSE;
7517 var ws = o.dense ? ([]) : ({});
7518 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
7519
7520 if(str.slice(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.slice(6); }
7521 else sep = guess_sep(str.slice(0,1024));
7522 var R = 0, C = 0, v = 0;
7523 var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
7524 str = str.replace(/\r\n/mg, "\n");
7525 var _re = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
7526 function finish_cell() {
7527 var s = str.slice(start, end);
7528 var cell = ({});
7529 if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
7530 if(s.length === 0) cell.t = 'z';
7531 else if(o.raw) { cell.t = 's'; cell.v = s; }
7532 else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
7533 else if(s.charCodeAt(0) == 0x3D) {
7534 if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
7535 else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
7536 else { cell.t = 's'; cell.v = s; } }
7537 else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
7538 else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
7539 else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
7540 else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
7541 cell.z = o.dateNF || SSF._table[14];
7542 var k = 0;
7543 if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
7544 if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
7545 else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
7546 if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
7547 if(!o.cellNF) delete cell.z;
7548 } else {
7549 cell.t = 's';
7550 cell.v = s;
7551 }
7552 if(cell.t == 'z'){}
7553 else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
7554 else ws[encode_cell({c:C,r:R})] = cell;
7555 start = end+1;
7556 if(range.e.c < C) range.e.c = C;
7557 if(range.e.r < R) range.e.r = R;
7558 if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
7559 }
7560 outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
7561 case 0x22: instr = !instr; break;
7562 case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
7563 default: break;
7564 }
7565 if(end - start > 0) finish_cell();
7566
7567 ws['!ref'] = encode_range(range);
7568 return ws;
7569 }
7570
7571 function prn_to_sheet_str(str, opts) {
7572 if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
7573 if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
7574 return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
7575 }
7576
7577 function prn_to_sheet(d, opts) {
7578 var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
7579 switch(opts.type) {
7580 case 'base64': str = Base64.decode(d); break;
7581 case 'binary': str = d; break;
7582 case 'buffer':
7583 if(opts.codepage == 65001) str = d.toString('utf8');
7584 else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
7585 else str = d.toString('binary');
7586 break;
7587 case 'array': str = cc2str(d); break;
7588 case 'string': str = d; break;
7589 default: throw new Error("Unrecognized type " + opts.type);
7590 }
7591 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
7592 else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage) str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str));
7593 if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
7594 return prn_to_sheet_str(str, opts);
7595 }
7596
7597 function prn_to_workbook(d, opts) { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
7598
7599 function sheet_to_prn(ws) {
7600 var o = [];
7601 var r = safe_decode_range(ws['!ref']), cell;
7602 var dense = Array.isArray(ws);
7603 for(var R = r.s.r; R <= r.e.r; ++R) {
7604 var oo = [];
7605 for(var C = r.s.c; C <= r.e.c; ++C) {
7606 var coord = encode_cell({r:R,c:C});
7607 cell = dense ? (ws[R]||[])[C] : ws[coord];
7608 if(!cell || cell.v == null) { oo.push(" "); continue; }
7609 var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
7610 while(w.length < 10) w += " ";
7611 oo.push(w + (C === 0 ? " " : ""));
7612 }
7613 o.push(oo.join(""));
7614 }
7615 return o.join("\n");
7616 }
7617
7618 return {
7619 to_workbook: prn_to_workbook,
7620 to_sheet: prn_to_sheet,
7621 from_sheet: sheet_to_prn
7622 };
7623})();
7624
7625/* Excel defaults to SYLK but warns if data is not valid */
7626function read_wb_ID(d, opts) {
7627 var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
7628 try {
7629 var out = SYLK.to_workbook(d, o);
7630 o.WTF = OLD_WTF;
7631 return out;
7632 } catch(e) {
7633 o.WTF = OLD_WTF;
7634 if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
7635 return PRN.to_workbook(d, opts);
7636 }
7637}
7638
7639var WK_ = (function() {
7640 function lotushopper(data, cb, opts) {
7641 if(!data) return;
7642 prep_blob(data, data.l || 0);
7643 var Enum = opts.Enum || WK1Enum;
7644 while(data.l < data.length) {
7645 var RT = data.read_shift(2);
7646 var R = Enum[RT] || Enum[0xFF];
7647 var length = data.read_shift(2);
7648 var tgt = data.l + length;
7649 var d = (R.f||parsenoop)(data, length, opts);
7650 data.l = tgt;
7651 if(cb(d, R.n, RT)) return;
7652 }
7653 }
7654
7655 function lotus_to_workbook(d, opts) {
7656 switch(opts.type) {
7657 case 'base64': return lotus_to_workbook_buf(s2a(Base64.decode(d)), opts);
7658 case 'binary': return lotus_to_workbook_buf(s2a(d), opts);
7659 case 'buffer':
7660 case 'array': return lotus_to_workbook_buf(d, opts);
7661 }
7662 throw "Unsupported type " + opts.type;
7663 }
7664
7665 function lotus_to_workbook_buf(d, opts) {
7666 if(!d) return d;
7667 var o = opts || {};
7668 if(DENSE != null && o.dense == null) o.dense = DENSE;
7669 var s = ((o.dense ? [] : {})), n = "Sheet1", sidx = 0;
7670 var sheets = {}, snames = [n];
7671
7672 var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
7673 var sheetRows = o.sheetRows || 0;
7674
7675 if(d[2] == 0x02) o.Enum = WK1Enum;
7676 else if(d[2] == 0x1a) o.Enum = WK3Enum;
7677 else if(d[2] == 0x0e) { o.Enum = WK3Enum; o.qpro = true; d.l = 0; }
7678 else throw new Error("Unrecognized LOTUS BOF " + d[2]);
7679 lotushopper(d, function(val, Rn, RT) {
7680 if(d[2] == 0x02) switch(RT) {
7681 case 0x00:
7682 o.vers = val;
7683 if(val >= 0x1000) o.qpro = true;
7684 break;
7685 case 0x06: refguess = val; break; /* RANGE */
7686 case 0x0F: /* LABEL */
7687 if(!o.qpro) val[1].v = val[1].v.slice(1);
7688 /* falls through */
7689 case 0x0D: /* INTEGER */
7690 case 0x0E: /* NUMBER */
7691 case 0x10: /* FORMULA */
7692 case 0x33: /* STRING */
7693 /* TODO: actual translation of the format code */
7694 if(RT == 0x0E && (val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
7695 val[1].z = o.dateNF || SSF._table[14];
7696 if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
7697 }
7698 if(o.dense) {
7699 if(!s[val[0].r]) s[val[0].r] = [];
7700 s[val[0].r][val[0].c] = val[1];
7701 } else s[encode_cell(val[0])] = val[1];
7702 break;
7703 } else switch(RT) {
7704 case 0x16: /* LABEL16 */
7705 val[1].v = val[1].v.slice(1);
7706 /* falls through */
7707 case 0x17: /* NUMBER17 */
7708 case 0x18: /* NUMBER18 */
7709 case 0x19: /* FORMULA19 */
7710 case 0x25: /* NUMBER25 */
7711 case 0x27: /* NUMBER27 */
7712 case 0x28: /* FORMULA28 */
7713 if(val[3] > sidx) {
7714 s["!ref"] = encode_range(refguess);
7715 sheets[n] = s;
7716 s = (o.dense ? [] : {});
7717 refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
7718 sidx = val[3]; n = "Sheet" + (sidx + 1);
7719 snames.push(n);
7720 }
7721 if(sheetRows > 0 && val[0].r >= sheetRows) break;
7722 if(o.dense) {
7723 if(!s[val[0].r]) s[val[0].r] = [];
7724 s[val[0].r][val[0].c] = val[1];
7725 } else s[encode_cell(val[0])] = val[1];
7726 if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
7727 if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
7728 break;
7729 default: break;
7730 }
7731 }, o);
7732
7733 s["!ref"] = encode_range(refguess);
7734 sheets[n] = s;
7735 return { SheetNames: snames, Sheets:sheets };
7736 }
7737
7738 function parse_RANGE(blob) {
7739 var o = {s:{c:0,r:0},e:{c:0,r:0}};
7740 o.s.c = blob.read_shift(2);
7741 o.s.r = blob.read_shift(2);
7742 o.e.c = blob.read_shift(2);
7743 o.e.r = blob.read_shift(2);
7744 if(o.s.c == 0xFFFF) o.s.c = o.e.c = o.s.r = o.e.r = 0;
7745 return o;
7746 }
7747
7748 function parse_cell(blob, length, opts) {
7749 var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7750 if(opts.qpro && opts.vers != 0x5120) {
7751 o[0].c = blob.read_shift(1);
7752 blob.l++;
7753 o[0].r = blob.read_shift(2);
7754 blob.l+=2;
7755 } else {
7756 o[2] = blob.read_shift(1);
7757 o[0].c = blob.read_shift(2); o[0].r = blob.read_shift(2);
7758 }
7759 return o;
7760 }
7761
7762 function parse_LABEL(blob, length, opts) {
7763 var tgt = blob.l + length;
7764 var o = parse_cell(blob, length, opts);
7765 o[1].t = 's';
7766 if(opts.vers == 0x5120) {
7767 blob.l++;
7768 var len = blob.read_shift(1);
7769 o[1].v = blob.read_shift(len, 'utf8');
7770 return o;
7771 }
7772 if(opts.qpro) blob.l++;
7773 o[1].v = blob.read_shift(tgt - blob.l, 'cstr');
7774 return o;
7775 }
7776
7777 function parse_INTEGER(blob, length, opts) {
7778 var o = parse_cell(blob, length, opts);
7779 o[1].v = blob.read_shift(2, 'i');
7780 return o;
7781 }
7782
7783 function parse_NUMBER(blob, length, opts) {
7784 var o = parse_cell(blob, length, opts);
7785 o[1].v = blob.read_shift(8, 'f');
7786 return o;
7787 }
7788
7789 function parse_FORMULA(blob, length, opts) {
7790 var tgt = blob.l + length;
7791 var o = parse_cell(blob, length, opts);
7792 /* TODO: formula */
7793 o[1].v = blob.read_shift(8, 'f');
7794 if(opts.qpro) blob.l = tgt;
7795 else {
7796 var flen = blob.read_shift(2);
7797 blob.l += flen;
7798 }
7799 return o;
7800 }
7801
7802 function parse_cell_3(blob) {
7803 var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7804 o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
7805 return o;
7806 }
7807
7808 function parse_LABEL_16(blob, length) {
7809 var o = parse_cell_3(blob, length);
7810 o[1].t = 's';
7811 o[1].v = blob.read_shift(length - 4, 'cstr');
7812 return o;
7813 }
7814
7815 function parse_NUMBER_18(blob, length) {
7816 var o = parse_cell_3(blob, length);
7817 o[1].v = blob.read_shift(2);
7818 var v = o[1].v >> 1;
7819 /* TODO: figure out all of the corner cases */
7820 if(o[1].v & 0x1) {
7821 switch(v & 0x07) {
7822 case 1: v = (v >> 3) * 500; break;
7823 case 2: v = (v >> 3) / 20; break;
7824 case 4: v = (v >> 3) / 2000; break;
7825 case 6: v = (v >> 3) / 16; break;
7826 case 7: v = (v >> 3) / 64; break;
7827 default: throw "unknown NUMBER_18 encoding " + (v & 0x07);
7828 }
7829 }
7830 o[1].v = v;
7831 return o;
7832 }
7833
7834 function parse_NUMBER_17(blob, length) {
7835 var o = parse_cell_3(blob, length);
7836 var v1 = blob.read_shift(4);
7837 var v2 = blob.read_shift(4);
7838 var e = blob.read_shift(2);
7839 if(e == 0xFFFF) { o[1].v = 0; return o; }
7840 var s = e & 0x8000; e = (e&0x7FFF) - 16446;
7841 o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
7842 return o;
7843 }
7844
7845 function parse_FORMULA_19(blob, length) {
7846 var o = parse_NUMBER_17(blob, 14);
7847 blob.l += length - 14; /* TODO: formula */
7848 return o;
7849 }
7850
7851 function parse_NUMBER_25(blob, length) {
7852 var o = parse_cell_3(blob, length);
7853 var v1 = blob.read_shift(4);
7854 o[1].v = v1 >> 6;
7855 return o;
7856 }
7857
7858 function parse_NUMBER_27(blob, length) {
7859 var o = parse_cell_3(blob, length);
7860 var v1 = blob.read_shift(8,'f');
7861 o[1].v = v1;
7862 return o;
7863 }
7864
7865 function parse_FORMULA_28(blob, length) {
7866 var o = parse_NUMBER_27(blob, 14);
7867 blob.l += length - 10; /* TODO: formula */
7868 return o;
7869 }
7870
7871 var WK1Enum = {
78720x0000: { n:"BOF", f:parseuint16 },
78730x0001: { n:"EOF" },
78740x0002: { n:"CALCMODE" },
78750x0003: { n:"CALCORDER" },
78760x0004: { n:"SPLIT" },
78770x0005: { n:"SYNC" },
78780x0006: { n:"RANGE", f:parse_RANGE },
78790x0007: { n:"WINDOW1" },
78800x0008: { n:"COLW1" },
78810x0009: { n:"WINTWO" },
78820x000A: { n:"COLW2" },
78830x000B: { n:"NAME" },
78840x000C: { n:"BLANK" },
78850x000D: { n:"INTEGER", f:parse_INTEGER },
78860x000E: { n:"NUMBER", f:parse_NUMBER },
78870x000F: { n:"LABEL", f:parse_LABEL },
78880x0010: { n:"FORMULA", f:parse_FORMULA },
78890x0018: { n:"TABLE" },
78900x0019: { n:"ORANGE" },
78910x001A: { n:"PRANGE" },
78920x001B: { n:"SRANGE" },
78930x001C: { n:"FRANGE" },
78940x001D: { n:"KRANGE1" },
78950x0020: { n:"HRANGE" },
78960x0023: { n:"KRANGE2" },
78970x0024: { n:"PROTEC" },
78980x0025: { n:"FOOTER" },
78990x0026: { n:"HEADER" },
79000x0027: { n:"SETUP" },
79010x0028: { n:"MARGINS" },
79020x0029: { n:"LABELFMT" },
79030x002A: { n:"TITLES" },
79040x002B: { n:"SHEETJS" },
79050x002D: { n:"GRAPH" },
79060x002E: { n:"NGRAPH" },
79070x002F: { n:"CALCCOUNT" },
79080x0030: { n:"UNFORMATTED" },
79090x0031: { n:"CURSORW12" },
79100x0032: { n:"WINDOW" },
79110x0033: { n:"STRING", f:parse_LABEL },
79120x0037: { n:"PASSWORD" },
79130x0038: { n:"LOCKED" },
79140x003C: { n:"QUERY" },
79150x003D: { n:"QUERYNAME" },
79160x003E: { n:"PRINT" },
79170x003F: { n:"PRINTNAME" },
79180x0040: { n:"GRAPH2" },
79190x0041: { n:"GRAPHNAME" },
79200x0042: { n:"ZOOM" },
79210x0043: { n:"SYMSPLIT" },
79220x0044: { n:"NSROWS" },
79230x0045: { n:"NSCOLS" },
79240x0046: { n:"RULER" },
79250x0047: { n:"NNAME" },
79260x0048: { n:"ACOMM" },
79270x0049: { n:"AMACRO" },
79280x004A: { n:"PARSE" },
79290x00FF: { n:"", f:parsenoop }
7930 };
7931
7932 var WK3Enum = {
79330x0000: { n:"BOF" },
79340x0001: { n:"EOF" },
79350x0003: { n:"??" },
79360x0004: { n:"??" },
79370x0005: { n:"??" },
79380x0006: { n:"??" },
79390x0007: { n:"??" },
79400x0009: { n:"??" },
79410x000a: { n:"??" },
79420x000b: { n:"??" },
79430x000c: { n:"??" },
79440x000e: { n:"??" },
79450x000f: { n:"??" },
79460x0010: { n:"??" },
79470x0011: { n:"??" },
79480x0012: { n:"??" },
79490x0013: { n:"??" },
79500x0015: { n:"??" },
79510x0016: { n:"LABEL16", f:parse_LABEL_16},
79520x0017: { n:"NUMBER17", f:parse_NUMBER_17 },
79530x0018: { n:"NUMBER18", f:parse_NUMBER_18 },
79540x0019: { n:"FORMULA19", f:parse_FORMULA_19},
79550x001a: { n:"??" },
79560x001b: { n:"??" },
79570x001c: { n:"??" },
79580x001d: { n:"??" },
79590x001e: { n:"??" },
79600x001f: { n:"??" },
79610x0021: { n:"??" },
79620x0025: { n:"NUMBER25", f:parse_NUMBER_25 },
79630x0027: { n:"NUMBER27", f:parse_NUMBER_27 },
79640x0028: { n:"FORMULA28", f:parse_FORMULA_28 },
79650x00FF: { n:"", f:parsenoop }
7966 };
7967 return {
7968 to_workbook: lotus_to_workbook
7969 };
7970})();
7971/* 18.4.7 rPr CT_RPrElt */
7972function parse_rpr(rpr) {
7973 var font = {}, m = rpr.match(tagregex), i = 0;
7974 var pass = false;
7975 if(m) for(;i!=m.length; ++i) {
7976 var y = parsexmltag(m[i]);
7977 switch(y[0].replace(/\w*:/g,"")) {
7978 /* 18.8.12 condense CT_BooleanProperty */
7979 /* ** not required . */
7980 case '<condense': break;
7981 /* 18.8.17 extend CT_BooleanProperty */
7982 /* ** not required . */
7983 case '<extend': break;
7984 /* 18.8.36 shadow CT_BooleanProperty */
7985 /* ** not required . */
7986 case '<shadow':
7987 if(!y.val) break;
7988 /* falls through */
7989 case '<shadow>':
7990 case '<shadow/>': font.shadow = 1; break;
7991 case '</shadow>': break;
7992
7993 /* 18.4.1 charset CT_IntProperty TODO */
7994 case '<charset':
7995 if(y.val == '1') break;
7996 font.cp = CS2CP[parseInt(y.val, 10)];
7997 break;
7998
7999 /* 18.4.2 outline CT_BooleanProperty TODO */
8000 case '<outline':
8001 if(!y.val) break;
8002 /* falls through */
8003 case '<outline>':
8004 case '<outline/>': font.outline = 1; break;
8005 case '</outline>': break;
8006
8007 /* 18.4.5 rFont CT_FontName */
8008 case '<rFont': font.name = y.val; break;
8009
8010 /* 18.4.11 sz CT_FontSize */
8011 case '<sz': font.sz = y.val; break;
8012
8013 /* 18.4.10 strike CT_BooleanProperty */
8014 case '<strike':
8015 if(!y.val) break;
8016 /* falls through */
8017 case '<strike>':
8018 case '<strike/>': font.strike = 1; break;
8019 case '</strike>': break;
8020
8021 /* 18.4.13 u CT_UnderlineProperty */
8022 case '<u':
8023 if(!y.val) break;
8024 switch(y.val) {
8025 case 'double': font.uval = "double"; break;
8026 case 'singleAccounting': font.uval = "single-accounting"; break;
8027 case 'doubleAccounting': font.uval = "double-accounting"; break;
8028 }
8029 /* falls through */
8030 case '<u>':
8031 case '<u/>': font.u = 1; break;
8032 case '</u>': break;
8033
8034 /* 18.8.2 b */
8035 case '<b':
8036 if(y.val == '0') break;
8037 /* falls through */
8038 case '<b>':
8039 case '<b/>': font.b = 1; break;
8040 case '</b>': break;
8041
8042 /* 18.8.26 i */
8043 case '<i':
8044 if(y.val == '0') break;
8045 /* falls through */
8046 case '<i>':
8047 case '<i/>': font.i = 1; break;
8048 case '</i>': break;
8049
8050 /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
8051 case '<color':
8052 if(y.rgb) font.color = y.rgb.slice(2,8);
8053 break;
8054
8055 /* 18.8.18 family ST_FontFamily */
8056 case '<family': font.family = y.val; break;
8057
8058 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
8059 case '<vertAlign': font.valign = y.val; break;
8060
8061 /* 18.8.35 scheme CT_FontScheme TODO */
8062 case '<scheme': break;
8063
8064 /* 18.2.10 extLst CT_ExtensionList ? */
8065 case '<extLst': case '<extLst>': case '</extLst>': break;
8066 case '<ext': pass = true; break;
8067 case '</ext>': pass = false; break;
8068 default:
8069 if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
8070 }
8071 }
8072 return font;
8073}
8074
8075var parse_rs = (function() {
8076 var tregex = matchtag("t"), rpregex = matchtag("rPr");
8077 /* 18.4.4 r CT_RElt */
8078 function parse_r(r) {
8079 /* 18.4.12 t ST_Xstring */
8080 var t = r.match(tregex)/*, cp = 65001*/;
8081 if(!t) return {t:"s", v:""};
8082
8083 var o = ({t:'s', v:unescapexml(t[1])});
8084 var rpr = r.match(rpregex);
8085 if(rpr) o.s = parse_rpr(rpr[1]);
8086 return o;
8087 }
8088 var rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/;
8089 return function parse_rs(rs) {
8090 return rs.replace(rregex,"").split(rend).map(parse_r).filter(function(r) { return r.v; });
8091 };
8092})();
8093
8094
8095/* Parse a list of <r> tags */
8096var rs_to_html = (function parse_rs_factory() {
8097 var nlregex = /(\r\n|\n)/g;
8098 function parse_rpr2(font, intro, outro) {
8099 var style = [];
8100
8101 if(font.u) style.push("text-decoration: underline;");
8102 if(font.uval) style.push("text-underline-style:" + font.uval + ";");
8103 if(font.sz) style.push("font-size:" + font.sz + "pt;");
8104 if(font.outline) style.push("text-effect: outline;");
8105 if(font.shadow) style.push("text-shadow: auto;");
8106 intro.push('<span style="' + style.join("") + '">');
8107
8108 if(font.b) { intro.push("<b>"); outro.push("</b>"); }
8109 if(font.i) { intro.push("<i>"); outro.push("</i>"); }
8110 if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
8111
8112 var align = font.valign || "";
8113 if(align == "superscript" || align == "super") align = "sup";
8114 else if(align == "subscript") align = "sub";
8115 if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
8116
8117 outro.push("</span>");
8118 return font;
8119 }
8120
8121 /* 18.4.4 r CT_RElt */
8122 function r_to_html(r) {
8123 var terms = [[],r.v,[]];
8124 if(!r.v) return "";
8125
8126 if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
8127
8128 return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
8129 }
8130
8131 return function parse_rs(rs) {
8132 return rs.map(r_to_html).join("");
8133 };
8134})();
8135
8136/* 18.4.8 si CT_Rst */
8137var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
8138var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
8139function parse_si(x, opts) {
8140 var html = opts ? opts.cellHTML : true;
8141 var z = {};
8142 if(!x) return null;
8143 //var y;
8144 /* 18.4.12 t ST_Xstring (Plaintext String) */
8145 // TODO: is whitespace actually valid here?
8146 if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
8147 z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
8148 z.r = utf8read(x);
8149 if(html) z.h = escapehtml(z.t);
8150 }
8151 /* 18.4.4 r CT_RElt (Rich Text Run) */
8152 else if((/*y = */x.match(sirregex))) {
8153 z.r = utf8read(x);
8154 z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
8155 if(html) z.h = rs_to_html(parse_rs(z.r));
8156 }
8157 /* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
8158 /* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
8159 return z;
8160}
8161
8162/* 18.4 Shared String Table */
8163var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
8164var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
8165var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
8166function parse_sst_xml(data, opts) {
8167 var s = ([]), ss = "";
8168 if(!data) return s;
8169 /* 18.4.9 sst CT_Sst */
8170 var sst = data.match(sstr0);
8171 if(sst) {
8172 ss = sst[2].replace(sstr1,"").split(sstr2);
8173 for(var i = 0; i != ss.length; ++i) {
8174 var o = parse_si(ss[i].trim(), opts);
8175 if(o != null) s[s.length] = o;
8176 }
8177 sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
8178 }
8179 return s;
8180}
8181
8182RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
8183var straywsregex = /^\s|\s$|[\t\n\r]/;
8184function write_sst_xml(sst, opts) {
8185 if(!opts.bookSST) return "";
8186 var o = [XML_HEADER];
8187 o[o.length] = (writextag('sst', null, {
8188 xmlns: XMLNS.main[0],
8189 count: sst.Count,
8190 uniqueCount: sst.Unique
8191 }));
8192 for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
8193 var s = sst[i];
8194 var sitag = "<si>";
8195 if(s.r) sitag += s.r;
8196 else {
8197 sitag += "<t";
8198 if(!s.t) s.t = "";
8199 if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
8200 sitag += ">" + escapexml(s.t) + "</t>";
8201 }
8202 sitag += "</si>";
8203 o[o.length] = (sitag);
8204 }
8205 if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
8206 return o.join("");
8207}
8208/* [MS-XLSB] 2.4.221 BrtBeginSst */
8209function parse_BrtBeginSst(data) {
8210 return [data.read_shift(4), data.read_shift(4)];
8211}
8212
8213/* [MS-XLSB] 2.1.7.45 Shared Strings */
8214function parse_sst_bin(data, opts) {
8215 var s = ([]);
8216 var pass = false;
8217 recordhopper(data, function hopper_sst(val, R_n, RT) {
8218 switch(RT) {
8219 case 0x009F: /* 'BrtBeginSst' */
8220 s.Count = val[0]; s.Unique = val[1]; break;
8221 case 0x0013: /* 'BrtSSTItem' */
8222 s.push(val); break;
8223 case 0x00A0: /* 'BrtEndSst' */
8224 return true;
8225
8226 case 0x0023: /* 'BrtFRTBegin' */
8227 pass = true; break;
8228 case 0x0024: /* 'BrtFRTEnd' */
8229 pass = false; break;
8230
8231 default:
8232 if(R_n.indexOf("Begin") > 0){/* empty */}
8233 else if(R_n.indexOf("End") > 0){/* empty */}
8234 if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
8235 }
8236 });
8237 return s;
8238}
8239
8240function write_BrtBeginSst(sst, o) {
8241 if(!o) o = new_buf(8);
8242 o.write_shift(4, sst.Count);
8243 o.write_shift(4, sst.Unique);
8244 return o;
8245}
8246
8247var write_BrtSSTItem = write_RichStr;
8248
8249function write_sst_bin(sst) {
8250 var ba = buf_array();
8251 write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst));
8252 for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i]));
8253 /* FRTSST */
8254 write_record(ba, "BrtEndSst");
8255 return ba.end();
8256}
8257function _JS2ANSI(str) {
8258 if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str);
8259 var o = [], oo = str.split("");
8260 for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0);
8261 return o;
8262}
8263
8264/* [MS-OFFCRYPTO] 2.1.4 Version */
8265function parse_CRYPTOVersion(blob, length) {
8266 var o = {};
8267 o.Major = blob.read_shift(2);
8268 o.Minor = blob.read_shift(2);
8269if(length >= 4) blob.l += length - 4;
8270 return o;
8271}
8272
8273/* [MS-OFFCRYPTO] 2.1.5 DataSpaceVersionInfo */
8274function parse_DataSpaceVersionInfo(blob) {
8275 var o = {};
8276 o.id = blob.read_shift(0, 'lpp4');
8277 o.R = parse_CRYPTOVersion(blob, 4);
8278 o.U = parse_CRYPTOVersion(blob, 4);
8279 o.W = parse_CRYPTOVersion(blob, 4);
8280 return o;
8281}
8282
8283/* [MS-OFFCRYPTO] 2.1.6.1 DataSpaceMapEntry Structure */
8284function parse_DataSpaceMapEntry(blob) {
8285 var len = blob.read_shift(4);
8286 var end = blob.l + len - 4;
8287 var o = {};
8288 var cnt = blob.read_shift(4);
8289 var comps = [];
8290 /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
8291 while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') });
8292 o.name = blob.read_shift(0, 'lpp4');
8293 o.comps = comps;
8294 if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end);
8295 return o;
8296}
8297
8298/* [MS-OFFCRYPTO] 2.1.6 DataSpaceMap */
8299function parse_DataSpaceMap(blob) {
8300 var o = [];
8301 blob.l += 4; // must be 0x8
8302 var cnt = blob.read_shift(4);
8303 while(cnt-- > 0) o.push(parse_DataSpaceMapEntry(blob));
8304 return o;
8305}
8306
8307/* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */
8308function parse_DataSpaceDefinition(blob) {
8309 var o = [];
8310 blob.l += 4; // must be 0x8
8311 var cnt = blob.read_shift(4);
8312 while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4'));
8313 return o;
8314}
8315
8316/* [MS-OFFCRYPTO] 2.1.8 DataSpaceDefinition */
8317function parse_TransformInfoHeader(blob) {
8318 var o = {};
8319 /*var len = */blob.read_shift(4);
8320 blob.l += 4; // must be 0x1
8321 o.id = blob.read_shift(0, 'lpp4');
8322 o.name = blob.read_shift(0, 'lpp4');
8323 o.R = parse_CRYPTOVersion(blob, 4);
8324 o.U = parse_CRYPTOVersion(blob, 4);
8325 o.W = parse_CRYPTOVersion(blob, 4);
8326 return o;
8327}
8328
8329function parse_Primary(blob) {
8330 /* [MS-OFFCRYPTO] 2.2.6 IRMDSTransformInfo */
8331 var hdr = parse_TransformInfoHeader(blob);
8332 /* [MS-OFFCRYPTO] 2.1.9 EncryptionTransformInfo */
8333 hdr.ename = blob.read_shift(0, '8lpp4');
8334 hdr.blksz = blob.read_shift(4);
8335 hdr.cmode = blob.read_shift(4);
8336 if(blob.read_shift(4) != 0x04) throw new Error("Bad !Primary record");
8337 return hdr;
8338}
8339
8340/* [MS-OFFCRYPTO] 2.3.2 Encryption Header */
8341function parse_EncryptionHeader(blob, length) {
8342 var tgt = blob.l + length;
8343 var o = {};
8344 o.Flags = (blob.read_shift(4) & 0x3F);
8345 blob.l += 4;
8346 o.AlgID = blob.read_shift(4);
8347 var valid = false;
8348 switch(o.AlgID) {
8349 case 0x660E: case 0x660F: case 0x6610: valid = (o.Flags == 0x24); break;
8350 case 0x6801: valid = (o.Flags == 0x04); break;
8351 case 0: valid = (o.Flags == 0x10 || o.Flags == 0x04 || o.Flags == 0x24); break;
8352 default: throw 'Unrecognized encryption algorithm: ' + o.AlgID;
8353 }
8354 if(!valid) throw new Error("Encryption Flags/AlgID mismatch");
8355 o.AlgIDHash = blob.read_shift(4);
8356 o.KeySize = blob.read_shift(4);
8357 o.ProviderType = blob.read_shift(4);
8358 blob.l += 8;
8359 o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
8360 blob.l = tgt;
8361 return o;
8362}
8363
8364/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
8365function parse_EncryptionVerifier(blob, length) {
8366 var o = {}, tgt = blob.l + length;
8367 blob.l += 4; // SaltSize must be 0x10
8368 o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
8369 o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
8370 /*var sz = */blob.read_shift(4);
8371 o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
8372 return o;
8373}
8374
8375/* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */
8376function parse_EncryptionInfo(blob) {
8377 var vers = parse_CRYPTOVersion(blob);
8378 switch(vers.Minor) {
8379 case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
8380 case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
8381 case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
8382 }
8383 throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
8384}
8385
8386/* [MS-OFFCRYPTO] 2.3.4.5 EncryptionInfo Stream (Standard Encryption) */
8387function parse_EncInfoStd(blob) {
8388 var flags = blob.read_shift(4);
8389 if((flags & 0x3F) != 0x24) throw new Error("EncryptionInfo mismatch");
8390 var sz = blob.read_shift(4);
8391 //var tgt = blob.l + sz;
8392 var hdr = parse_EncryptionHeader(blob, sz);
8393 var verifier = parse_EncryptionVerifier(blob, blob.length - blob.l);
8394 return { t:"Std", h:hdr, v:verifier };
8395}
8396/* [MS-OFFCRYPTO] 2.3.4.6 EncryptionInfo Stream (Extensible Encryption) */
8397function parse_EncInfoExt() { throw new Error("File is password-protected: ECMA-376 Extensible"); }
8398/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
8399function parse_EncInfoAgl(blob) {
8400 var KeyData = ["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];
8401 blob.l+=4;
8402 var xml = blob.read_shift(blob.length - blob.l, 'utf8');
8403 var o = {};
8404 xml.replace(tagregex, function xml_agile(x) {
8405 var y = parsexmltag(x);
8406 switch(strip_ns(y[0])) {
8407 case '<?xml': break;
8408 case '<encryption': case '</encryption>': break;
8409 case '<keyData': KeyData.forEach(function(k) { o[k] = y[k]; }); break;
8410 case '<dataIntegrity': o.encryptedHmacKey = y.encryptedHmacKey; o.encryptedHmacValue = y.encryptedHmacValue; break;
8411 case '<keyEncryptors>': case '<keyEncryptors': o.encs = []; break;
8412 case '</keyEncryptors>': break;
8413
8414 case '<keyEncryptor': o.uri = y.uri; break;
8415 case '</keyEncryptor>': break;
8416 case '<encryptedKey': o.encs.push(y); break;
8417 default: throw y[0];
8418 }
8419 });
8420 return o;
8421}
8422
8423/* [MS-OFFCRYPTO] 2.3.5.1 RC4 CryptoAPI Encryption Header */
8424function parse_RC4CryptoHeader(blob, length) {
8425 var o = {};
8426 var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4;
8427 if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor);
8428 if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major);
8429 o.Flags = blob.read_shift(4); length -= 4;
8430 var sz = blob.read_shift(4); length -= 4;
8431 o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
8432 o.EncryptionVerifier = parse_EncryptionVerifier(blob, length);
8433 return o;
8434}
8435/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
8436function parse_RC4Header(blob) {
8437 var o = {};
8438 var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4);
8439 if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
8440 o.Salt = blob.read_shift(16);
8441 o.EncryptedVerifier = blob.read_shift(16);
8442 o.EncryptedVerifierHash = blob.read_shift(16);
8443 return o;
8444}
8445
8446/* [MS-OFFCRYPTO] 2.3.7.1 Binary Document Password Verifier Derivation */
8447function crypto_CreatePasswordVerifier_Method1(Password) {
8448 var Verifier = 0x0000, PasswordArray;
8449 var PasswordDecoded = _JS2ANSI(Password);
8450 var len = PasswordDecoded.length + 1, i, PasswordByte;
8451 var Intermediate1, Intermediate2, Intermediate3;
8452 PasswordArray = new_raw_buf(len);
8453 PasswordArray[0] = PasswordDecoded.length;
8454 for(i = 1; i != len; ++i) PasswordArray[i] = PasswordDecoded[i-1];
8455 for(i = len-1; i >= 0; --i) {
8456 PasswordByte = PasswordArray[i];
8457 Intermediate1 = ((Verifier & 0x4000) === 0x0000) ? 0 : 1;
8458 Intermediate2 = (Verifier << 1) & 0x7FFF;
8459 Intermediate3 = Intermediate1 | Intermediate2;
8460 Verifier = Intermediate3 ^ PasswordByte;
8461 }
8462 return Verifier ^ 0xCE4B;
8463}
8464
8465/* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */
8466var crypto_CreateXorArray_Method1 = (function() {
8467 var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00];
8468 var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3];
8469 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];
8470 var Ror = function(Byte) { return ((Byte/2) | (Byte*128)) & 0xFF; };
8471 var XorRor = function(byte1, byte2) { return Ror(byte1 ^ byte2); };
8472 var CreateXorKey_Method1 = function(Password) {
8473 var XorKey = InitialCode[Password.length - 1];
8474 var CurrentElement = 0x68;
8475 for(var i = Password.length-1; i >= 0; --i) {
8476 var Char = Password[i];
8477 for(var j = 0; j != 7; ++j) {
8478 if(Char & 0x40) XorKey ^= XorMatrix[CurrentElement];
8479 Char *= 2; --CurrentElement;
8480 }
8481 }
8482 return XorKey;
8483 };
8484 return function(password) {
8485 var Password = _JS2ANSI(password);
8486 var XorKey = CreateXorKey_Method1(Password);
8487 var Index = Password.length;
8488 var ObfuscationArray = new_raw_buf(16);
8489 for(var i = 0; i != 16; ++i) ObfuscationArray[i] = 0x00;
8490 var Temp, PasswordLastChar, PadIndex;
8491 if((Index & 1) === 1) {
8492 Temp = XorKey >> 8;
8493 ObfuscationArray[Index] = XorRor(PadArray[0], Temp);
8494 --Index;
8495 Temp = XorKey & 0xFF;
8496 PasswordLastChar = Password[Password.length - 1];
8497 ObfuscationArray[Index] = XorRor(PasswordLastChar, Temp);
8498 }
8499 while(Index > 0) {
8500 --Index;
8501 Temp = XorKey >> 8;
8502 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8503 --Index;
8504 Temp = XorKey & 0xFF;
8505 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8506 }
8507 Index = 15;
8508 PadIndex = 15 - Password.length;
8509 while(PadIndex > 0) {
8510 Temp = XorKey >> 8;
8511 ObfuscationArray[Index] = XorRor(PadArray[PadIndex], Temp);
8512 --Index;
8513 --PadIndex;
8514 Temp = XorKey & 0xFF;
8515 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8516 --Index;
8517 --PadIndex;
8518 }
8519 return ObfuscationArray;
8520 };
8521})();
8522
8523/* [MS-OFFCRYPTO] 2.3.7.3 Binary Document XOR Data Transformation Method 1 */
8524var crypto_DecryptData_Method1 = function(password, Data, XorArrayIndex, XorArray, O) {
8525 /* If XorArray is set, use it; if O is not set, make changes in-place */
8526 if(!O) O = Data;
8527 if(!XorArray) XorArray = crypto_CreateXorArray_Method1(password);
8528 var Index, Value;
8529 for(Index = 0; Index != Data.length; ++Index) {
8530 Value = Data[Index];
8531 Value ^= XorArray[XorArrayIndex];
8532 Value = ((Value>>5) | (Value<<3)) & 0xFF;
8533 O[Index] = Value;
8534 ++XorArrayIndex;
8535 }
8536 return [O, XorArrayIndex, XorArray];
8537};
8538
8539var crypto_MakeXorDecryptor = function(password) {
8540 var XorArrayIndex = 0, XorArray = crypto_CreateXorArray_Method1(password);
8541 return function(Data) {
8542 var O = crypto_DecryptData_Method1("", Data, XorArrayIndex, XorArray);
8543 XorArrayIndex = O[1];
8544 return O[0];
8545 };
8546};
8547
8548/* 2.5.343 */
8549function parse_XORObfuscation(blob, length, opts, out) {
8550 var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) });
8551 if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
8552 out.valid = o.verificationBytes === o.verifier;
8553 if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
8554 return o;
8555}
8556
8557/* 2.4.117 */
8558function parse_FilePassHeader(blob, length, oo) {
8559 var o = oo || {}; o.Info = blob.read_shift(2); blob.l -= 2;
8560 if(o.Info === 1) o.Data = parse_RC4Header(blob, length);
8561 else o.Data = parse_RC4CryptoHeader(blob, length);
8562 return o;
8563}
8564function parse_FilePass(blob, length, opts) {
8565 var o = ({ Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }); /* wEncryptionType */
8566 if(o.Type) parse_FilePassHeader(blob, length-2, o);
8567 else parse_XORObfuscation(blob, opts.biff >= 8 ? length : length - 2, opts, o);
8568 return o;
8569}
8570
8571
8572var RTF = (function() {
8573 function rtf_to_sheet(d, opts) {
8574 switch(opts.type) {
8575 case 'base64': return rtf_to_sheet_str(Base64.decode(d), opts);
8576 case 'binary': return rtf_to_sheet_str(d, opts);
8577 case 'buffer': return rtf_to_sheet_str(d.toString('binary'), opts);
8578 case 'array': return rtf_to_sheet_str(cc2str(d), opts);
8579 }
8580 throw new Error("Unrecognized type " + opts.type);
8581 }
8582
8583 function rtf_to_sheet_str(str, opts) {
8584 var o = opts || {};
8585 var ws = o.dense ? ([]) : ({});
8586 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
8587
8588 // TODO: parse
8589 if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
8590
8591 ws['!ref'] = encode_range(range);
8592 return ws;
8593 }
8594
8595 function rtf_to_workbook(d, opts) { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
8596
8597 /* TODO: this is a stub */
8598 function sheet_to_rtf(ws) {
8599 var o = ["{\\rtf1\\ansi"];
8600 var r = safe_decode_range(ws['!ref']), cell;
8601 var dense = Array.isArray(ws);
8602 for(var R = r.s.r; R <= r.e.r; ++R) {
8603 o.push("\\trowd\\trautofit1");
8604 for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
8605 o.push("\\pard\\intbl");
8606 for(C = r.s.c; C <= r.e.c; ++C) {
8607 var coord = encode_cell({r:R,c:C});
8608 cell = dense ? (ws[R]||[])[C]: ws[coord];
8609 if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
8610 o.push(" " + (cell.w || (format_cell(cell), cell.w)));
8611 o.push("\\cell");
8612 }
8613 o.push("\\pard\\intbl\\row");
8614 }
8615 return o.join("") + "}";
8616 }
8617
8618 return {
8619 to_workbook: rtf_to_workbook,
8620 to_sheet: rtf_to_sheet,
8621 from_sheet: sheet_to_rtf
8622 };
8623})();
8624function hex2RGB(h) {
8625 var o = h.slice(h[0]==="#"?1:0).slice(0,6);
8626 return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
8627}
8628function rgb2Hex(rgb) {
8629 for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
8630 return o.toString(16).toUpperCase().slice(1);
8631}
8632
8633function rgb2HSL(rgb) {
8634 var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
8635 var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
8636 if(C === 0) return [0, 0, R];
8637
8638 var H6 = 0, S = 0, L2 = (M + m);
8639 S = C / (L2 > 1 ? 2 - L2 : L2);
8640 switch(M){
8641 case R: H6 = ((G - B) / C + 6)%6; break;
8642 case G: H6 = ((B - R) / C + 2); break;
8643 case B: H6 = ((R - G) / C + 4); break;
8644 }
8645 return [H6 / 6, S, L2 / 2];
8646}
8647
8648function hsl2RGB(hsl){
8649 var H = hsl[0], S = hsl[1], L = hsl[2];
8650 var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
8651 var rgb = [m,m,m], h6 = 6*H;
8652
8653 var X;
8654 if(S !== 0) switch(h6|0) {
8655 case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
8656 case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
8657 case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
8658 case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
8659 case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
8660 case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
8661 }
8662 for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
8663 return rgb;
8664}
8665
8666/* 18.8.3 bgColor tint algorithm */
8667function rgb_tint(hex, tint) {
8668 if(tint === 0) return hex;
8669 var hsl = rgb2HSL(hex2RGB(hex));
8670 if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
8671 else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
8672 return rgb2Hex(hsl2RGB(hsl));
8673}
8674
8675/* 18.3.1.13 width calculations */
8676/* [MS-OI29500] 2.1.595 Column Width & Formatting */
8677var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
8678function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
8679function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
8680function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
8681//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
8682//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
8683function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
8684/* XLSX/XLSB/XLS specify width in units of MDW */
8685function find_mdw_colw(collw) {
8686 var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
8687 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; }
8688 MDW = _MDW;
8689}
8690/* XLML specifies width in terms of pixels */
8691/*function find_mdw_wpx(wpx) {
8692 var delta = Infinity, guess = 0, _MDW = MIN_MDW;
8693 for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
8694 guess = char2width_(px2char_(wpx))*256;
8695 guess = (guess) % 1;
8696 if(guess > 0.5) guess--;
8697 if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
8698 }
8699 MDW = _MDW;
8700}*/
8701
8702function process_col(coll) {
8703 if(coll.width) {
8704 coll.wpx = width2px(coll.width);
8705 coll.wch = px2char(coll.wpx);
8706 coll.MDW = MDW;
8707 } else if(coll.wpx) {
8708 coll.wch = px2char(coll.wpx);
8709 coll.width = char2width(coll.wch);
8710 coll.MDW = MDW;
8711 } else if(typeof coll.wch == 'number') {
8712 coll.width = char2width(coll.wch);
8713 coll.wpx = width2px(coll.width);
8714 coll.MDW = MDW;
8715 }
8716 if(coll.customWidth) delete coll.customWidth;
8717}
8718
8719var DEF_PPI = 96, PPI = DEF_PPI;
8720function px2pt(px) { return px * 96 / PPI; }
8721function pt2px(pt) { return pt * PPI / 96; }
8722
8723/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
8724var XLMLPatternTypeMap = {
8725 "None": "none",
8726 "Solid": "solid",
8727 "Gray50": "mediumGray",
8728 "Gray75": "darkGray",
8729 "Gray25": "lightGray",
8730 "HorzStripe": "darkHorizontal",
8731 "VertStripe": "darkVertical",
8732 "ReverseDiagStripe": "darkDown",
8733 "DiagStripe": "darkUp",
8734 "DiagCross": "darkGrid",
8735 "ThickDiagCross": "darkTrellis",
8736 "ThinHorzStripe": "lightHorizontal",
8737 "ThinVertStripe": "lightVertical",
8738 "ThinReverseDiagStripe": "lightDown",
8739 "ThinHorzCross": "lightGrid"
8740};
8741
8742/* 18.8.5 borders CT_Borders */
8743function parse_borders(t, styles, themes, opts) {
8744 styles.Borders = [];
8745 var border = {};
8746 var pass = false;
8747 (t[0].match(tagregex)||[]).forEach(function(x) {
8748 var y = parsexmltag(x);
8749 switch(strip_ns(y[0])) {
8750 case '<borders': case '<borders>': case '</borders>': break;
8751
8752 /* 18.8.4 border CT_Border */
8753 case '<border': case '<border>': case '<border/>':
8754 border = {};
8755 if(y.diagonalUp) border.diagonalUp = parsexmlbool(y.diagonalUp);
8756 if(y.diagonalDown) border.diagonalDown = parsexmlbool(y.diagonalDown);
8757 styles.Borders.push(border);
8758 break;
8759 case '</border>': break;
8760
8761 /* note: not in spec, appears to be CT_BorderPr */
8762 case '<left/>': break;
8763 case '<left': case '<left>': break;
8764 case '</left>': break;
8765
8766 /* note: not in spec, appears to be CT_BorderPr */
8767 case '<right/>': break;
8768 case '<right': case '<right>': break;
8769 case '</right>': break;
8770
8771 /* 18.8.43 top CT_BorderPr */
8772 case '<top/>': break;
8773 case '<top': case '<top>': break;
8774 case '</top>': break;
8775
8776 /* 18.8.6 bottom CT_BorderPr */
8777 case '<bottom/>': break;
8778 case '<bottom': case '<bottom>': break;
8779 case '</bottom>': break;
8780
8781 /* 18.8.13 diagonal CT_BorderPr */
8782 case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
8783 case '</diagonal>': break;
8784
8785 /* 18.8.25 horizontal CT_BorderPr */
8786 case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
8787 case '</horizontal>': break;
8788
8789 /* 18.8.44 vertical CT_BorderPr */
8790 case '<vertical': case '<vertical>': case '<vertical/>': break;
8791 case '</vertical>': break;
8792
8793 /* 18.8.37 start CT_BorderPr */
8794 case '<start': case '<start>': case '<start/>': break;
8795 case '</start>': break;
8796
8797 /* 18.8.16 end CT_BorderPr */
8798 case '<end': case '<end>': case '<end/>': break;
8799 case '</end>': break;
8800
8801 /* 18.8.? color CT_Color */
8802 case '<color': case '<color>':
8803 break;
8804 case '<color/>': case '</color>': break;
8805
8806 /* 18.2.10 extLst CT_ExtensionList ? */
8807 case '<extLst': case '<extLst>': case '</extLst>': break;
8808 case '<ext': pass = true; break;
8809 case '</ext>': pass = false; break;
8810 default: if(opts && opts.WTF) {
8811 if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
8812 }
8813 }
8814 });
8815}
8816
8817/* 18.8.21 fills CT_Fills */
8818function parse_fills(t, styles, themes, opts) {
8819 styles.Fills = [];
8820 var fill = {};
8821 var pass = false;
8822 (t[0].match(tagregex)||[]).forEach(function(x) {
8823 var y = parsexmltag(x);
8824 switch(strip_ns(y[0])) {
8825 case '<fills': case '<fills>': case '</fills>': break;
8826
8827 /* 18.8.20 fill CT_Fill */
8828 case '<fill>': case '<fill': case '<fill/>':
8829 fill = {}; styles.Fills.push(fill); break;
8830 case '</fill>': break;
8831
8832 /* 18.8.24 gradientFill CT_GradientFill */
8833 case '<gradientFill>': break;
8834 case '<gradientFill':
8835 case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
8836
8837 /* 18.8.32 patternFill CT_PatternFill */
8838 case '<patternFill': case '<patternFill>':
8839 if(y.patternType) fill.patternType = y.patternType;
8840 break;
8841 case '<patternFill/>': case '</patternFill>': break;
8842
8843 /* 18.8.3 bgColor CT_Color */
8844 case '<bgColor':
8845 if(!fill.bgColor) fill.bgColor = {};
8846 if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
8847 if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
8848 if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
8849 /* Excel uses ARGB strings */
8850 if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
8851 break;
8852 case '<bgColor/>': case '</bgColor>': break;
8853
8854 /* 18.8.19 fgColor CT_Color */
8855 case '<fgColor':
8856 if(!fill.fgColor) fill.fgColor = {};
8857 if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
8858 if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
8859 /* Excel uses ARGB strings */
8860 if(y.rgb != null) fill.fgColor.rgb = y.rgb.slice(-6);
8861 break;
8862 case '<fgColor/>': case '</fgColor>': break;
8863
8864 /* 18.8.38 stop CT_GradientStop */
8865 case '<stop': case '<stop/>': break;
8866 case '</stop>': break;
8867
8868 /* 18.8.? color CT_Color */
8869 case '<color': case '<color/>': break;
8870 case '</color>': break;
8871
8872 /* 18.2.10 extLst CT_ExtensionList ? */
8873 case '<extLst': case '<extLst>': case '</extLst>': break;
8874 case '<ext': pass = true; break;
8875 case '</ext>': pass = false; break;
8876 default: if(opts && opts.WTF) {
8877 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
8878 }
8879 }
8880 });
8881}
8882
8883/* 18.8.23 fonts CT_Fonts */
8884function parse_fonts(t, styles, themes, opts) {
8885 styles.Fonts = [];
8886 var font = {};
8887 var pass = false;
8888 (t[0].match(tagregex)||[]).forEach(function(x) {
8889 var y = parsexmltag(x);
8890 switch(strip_ns(y[0])) {
8891 case '<fonts': case '<fonts>': case '</fonts>': break;
8892
8893 /* 18.8.22 font CT_Font */
8894 case '<font': case '<font>': break;
8895 case '</font>': case '<font/>':
8896 styles.Fonts.push(font);
8897 font = {};
8898 break;
8899
8900 /* 18.8.29 name CT_FontName */
8901 case '<name': if(y.val) font.name = y.val; break;
8902 case '<name/>': case '</name>': break;
8903
8904 /* 18.8.2 b CT_BooleanProperty */
8905 case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
8906 case '<b/>': font.bold = 1; break;
8907
8908 /* 18.8.26 i CT_BooleanProperty */
8909 case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
8910 case '<i/>': font.italic = 1; break;
8911
8912 /* 18.4.13 u CT_UnderlineProperty */
8913 case '<u':
8914 switch(y.val) {
8915 case "none": font.underline = 0x00; break;
8916 case "single": font.underline = 0x01; break;
8917 case "double": font.underline = 0x02; break;
8918 case "singleAccounting": font.underline = 0x21; break;
8919 case "doubleAccounting": font.underline = 0x22; break;
8920 } break;
8921 case '<u/>': font.underline = 1; break;
8922
8923 /* 18.4.10 strike CT_BooleanProperty */
8924 case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
8925 case '<strike/>': font.strike = 1; break;
8926
8927 /* 18.4.2 outline CT_BooleanProperty */
8928 case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
8929 case '<outline/>': font.outline = 1; break;
8930
8931 /* 18.8.36 shadow CT_BooleanProperty */
8932 case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
8933 case '<shadow/>': font.shadow = 1; break;
8934
8935 /* 18.8.12 condense CT_BooleanProperty */
8936 case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
8937 case '<condense/>': font.condense = 1; break;
8938
8939 /* 18.8.17 extend CT_BooleanProperty */
8940 case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
8941 case '<extend/>': font.extend = 1; break;
8942
8943 /* 18.4.11 sz CT_FontSize */
8944 case '<sz': if(y.val) font.sz = +y.val; break;
8945 case '<sz/>': case '</sz>': break;
8946
8947 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
8948 case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
8949 case '<vertAlign/>': case '</vertAlign>': break;
8950
8951 /* 18.8.18 family CT_FontFamily */
8952 case '<family': if(y.val) font.family = parseInt(y.val,10); break;
8953 case '<family/>': case '</family>': break;
8954
8955 /* 18.8.35 scheme CT_FontScheme */
8956 case '<scheme': if(y.val) font.scheme = y.val; break;
8957 case '<scheme/>': case '</scheme>': break;
8958
8959 /* 18.4.1 charset CT_IntProperty */
8960 case '<charset':
8961 if(y.val == '1') break;
8962 y.codepage = CS2CP[parseInt(y.val, 10)];
8963 break;
8964
8965 /* 18.?.? color CT_Color */
8966 case '<color':
8967 if(!font.color) font.color = {};
8968 if(y.auto) font.color.auto = parsexmlbool(y.auto);
8969
8970 if(y.rgb) font.color.rgb = y.rgb.slice(-6);
8971 else if(y.indexed) {
8972 font.color.index = parseInt(y.indexed, 10);
8973 var icv = XLSIcv[font.color.index];
8974 if(font.color.index == 81) icv = XLSIcv[1];
8975 if(!icv) throw new Error(x);
8976 font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
8977 } else if(y.theme) {
8978 font.color.theme = parseInt(y.theme, 10);
8979 if(y.tint) font.color.tint = parseFloat(y.tint);
8980 if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
8981 font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
8982 }
8983 }
8984
8985 break;
8986 case '<color/>': case '</color>': break;
8987
8988 /* note: sometimes mc:AlternateContent appears bare */
8989 case '<AlternateContent': pass = true; break;
8990 case '</AlternateContent>': pass = false; break;
8991
8992 /* 18.2.10 extLst CT_ExtensionList ? */
8993 case '<extLst': case '<extLst>': case '</extLst>': break;
8994 case '<ext': pass = true; break;
8995 case '</ext>': pass = false; break;
8996 default: if(opts && opts.WTF) {
8997 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
8998 }
8999 }
9000 });
9001}
9002
9003/* 18.8.31 numFmts CT_NumFmts */
9004function parse_numFmts(t, styles, opts) {
9005 styles.NumberFmt = [];
9006 var k/*Array<number>*/ = (keys(SSF._table));
9007 for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
9008 var m = t[0].match(tagregex);
9009 if(!m) return;
9010 for(i=0; i < m.length; ++i) {
9011 var y = parsexmltag(m[i]);
9012 switch(strip_ns(y[0])) {
9013 case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
9014 case '<numFmt': {
9015 var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
9016 styles.NumberFmt[j] = f;
9017 if(j>0) {
9018 if(j > 0x188) {
9019 for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
9020 styles.NumberFmt[j] = f;
9021 }
9022 SSF.load(f,j);
9023 }
9024 } break;
9025 case '</numFmt>': break;
9026 default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
9027 }
9028 }
9029}
9030
9031function write_numFmts(NF) {
9032 var o = ["<numFmts>"];
9033 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9034 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])}));
9035 });
9036 if(o.length === 1) return "";
9037 o[o.length] = ("</numFmts>");
9038 o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
9039 return o.join("");
9040}
9041
9042/* 18.8.10 cellXfs CT_CellXfs */
9043var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
9044var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
9045function parse_cellXfs(t, styles, opts) {
9046 styles.CellXf = [];
9047 var xf;
9048 var pass = false;
9049 (t[0].match(tagregex)||[]).forEach(function(x) {
9050 var y = parsexmltag(x), i = 0;
9051 switch(strip_ns(y[0])) {
9052 case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
9053
9054 /* 18.8.45 xf CT_Xf */
9055 case '<xf': case '<xf/>':
9056 xf = y;
9057 delete xf[0];
9058 for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
9059 xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
9060 for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
9061 xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
9062 if(xf.numFmtId > 0x188) {
9063 for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
9064 }
9065 styles.CellXf.push(xf); break;
9066 case '</xf>': break;
9067
9068 /* 18.8.1 alignment CT_CellAlignment */
9069 case '<alignment': case '<alignment/>':
9070 var alignment = {};
9071 if(y.vertical) alignment.vertical = y.vertical;
9072 if(y.horizontal) alignment.horizontal = y.horizontal;
9073 if(y.textRotation != null) alignment.textRotation = y.textRotation;
9074 if(y.indent) alignment.indent = y.indent;
9075 if(y.wrapText) alignment.wrapText = parsexmlbool(y.wrapText);
9076 xf.alignment = alignment;
9077 break;
9078 case '</alignment>': break;
9079
9080 /* 18.8.33 protection CT_CellProtection */
9081 case '<protection':
9082 break;
9083 case '</protection>': case '<protection/>': break;
9084
9085 /* note: sometimes mc:AlternateContent appears bare */
9086 case '<AlternateContent': pass = true; break;
9087 case '</AlternateContent>': pass = false; break;
9088
9089 /* 18.2.10 extLst CT_ExtensionList ? */
9090 case '<extLst': case '<extLst>': case '</extLst>': break;
9091 case '<ext': pass = true; break;
9092 case '</ext>': pass = false; break;
9093 default: if(opts && opts.WTF) {
9094 if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
9095 }
9096 }
9097 });
9098}
9099
9100function write_cellXfs(cellXfs) {
9101 var o = [];
9102 o[o.length] = (writextag('cellXfs',null));
9103 cellXfs.forEach(function(c) {
9104 o[o.length] = (writextag('xf', null, c));
9105 });
9106 o[o.length] = ("</cellXfs>");
9107 if(o.length === 2) return "";
9108 o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
9109 return o.join("");
9110}
9111
9112/* 18.8 Styles CT_Stylesheet*/
9113var parse_sty_xml= (function make_pstyx() {
9114var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
9115var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
9116var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
9117var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
9118var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
9119
9120return function parse_sty_xml(data, themes, opts) {
9121 var styles = {};
9122 if(!data) return styles;
9123 data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
9124 /* 18.8.39 styleSheet CT_Stylesheet */
9125 var t;
9126
9127 /* 18.8.31 numFmts CT_NumFmts ? */
9128 if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
9129
9130 /* 18.8.23 fonts CT_Fonts ? */
9131 if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
9132
9133 /* 18.8.21 fills CT_Fills ? */
9134 if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
9135
9136 /* 18.8.5 borders CT_Borders ? */
9137 if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
9138
9139 /* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
9140
9141 /* 18.8.10 cellXfs CT_CellXfs ? */
9142 if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
9143
9144 /* 18.8.8 cellStyles CT_CellStyles ? */
9145 /* 18.8.15 dxfs CT_Dxfs ? */
9146 /* 18.8.42 tableStyles CT_TableStyles ? */
9147 /* 18.8.11 colors CT_Colors ? */
9148 /* 18.2.10 extLst CT_ExtensionList ? */
9149
9150 return styles;
9151};
9152})();
9153
9154var STYLES_XML_ROOT = writextag('styleSheet', null, {
9155 'xmlns': XMLNS.main[0],
9156 'xmlns:vt': XMLNS.vt
9157});
9158
9159RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
9160
9161function write_sty_xml(wb, opts) {
9162 var o = [XML_HEADER, STYLES_XML_ROOT], w;
9163 if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
9164 o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
9165 o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
9166 o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
9167 o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
9168 if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
9169 o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
9170 o[o.length] = ('<dxfs count="0"/>');
9171 o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
9172
9173 if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
9174 return o.join("");
9175}
9176/* [MS-XLSB] 2.4.657 BrtFmt */
9177function parse_BrtFmt(data, length) {
9178 var numFmtId = data.read_shift(2);
9179 var stFmtCode = parse_XLWideString(data,length-2);
9180 return [numFmtId, stFmtCode];
9181}
9182function write_BrtFmt(i, f, o) {
9183 if(!o) o = new_buf(6 + 4 * f.length);
9184 o.write_shift(2, i);
9185 write_XLWideString(f, o);
9186 var out = (o.length > o.l) ? o.slice(0, o.l) : o;
9187 if(o.l == null) o.l = o.length;
9188 return out;
9189}
9190
9191/* [MS-XLSB] 2.4.659 BrtFont TODO */
9192function parse_BrtFont(data, length, opts) {
9193 var out = ({});
9194
9195 out.sz = data.read_shift(2) / 20;
9196
9197 var grbit = parse_FontFlags(data, 2, opts);
9198 if(grbit.fItalic) out.italic = 1;
9199 if(grbit.fCondense) out.condense = 1;
9200 if(grbit.fExtend) out.extend = 1;
9201 if(grbit.fShadow) out.shadow = 1;
9202 if(grbit.fOutline) out.outline = 1;
9203 if(grbit.fStrikeout) out.strike = 1;
9204
9205 var bls = data.read_shift(2);
9206 if(bls === 0x02BC) out.bold = 1;
9207
9208 switch(data.read_shift(2)) {
9209 /* case 0: out.vertAlign = "baseline"; break; */
9210 case 1: out.vertAlign = "superscript"; break;
9211 case 2: out.vertAlign = "subscript"; break;
9212 }
9213
9214 var underline = data.read_shift(1);
9215 if(underline != 0) out.underline = underline;
9216
9217 var family = data.read_shift(1);
9218 if(family > 0) out.family = family;
9219
9220 var bCharSet = data.read_shift(1);
9221 if(bCharSet > 0) out.charset = bCharSet;
9222
9223 data.l++;
9224 out.color = parse_BrtColor(data, 8);
9225
9226 switch(data.read_shift(1)) {
9227 /* case 0: out.scheme = "none": break; */
9228 case 1: out.scheme = "major"; break;
9229 case 2: out.scheme = "minor"; break;
9230 }
9231
9232 out.name = parse_XLWideString(data, length - 21);
9233
9234 return out;
9235}
9236function write_BrtFont(font, o) {
9237 if(!o) o = new_buf(25+4*32);
9238 o.write_shift(2, font.sz * 20);
9239 write_FontFlags(font, o);
9240 o.write_shift(2, font.bold ? 0x02BC : 0x0190);
9241 var sss = 0;
9242 if(font.vertAlign == "superscript") sss = 1;
9243 else if(font.vertAlign == "subscript") sss = 2;
9244 o.write_shift(2, sss);
9245 o.write_shift(1, font.underline || 0);
9246 o.write_shift(1, font.family || 0);
9247 o.write_shift(1, font.charset || 0);
9248 o.write_shift(1, 0);
9249 write_BrtColor(font.color, o);
9250 var scheme = 0;
9251 if(font.scheme == "major") scheme = 1;
9252 if(font.scheme == "minor") scheme = 2;
9253 o.write_shift(1, scheme);
9254 write_XLWideString(font.name, o);
9255 return o.length > o.l ? o.slice(0, o.l) : o;
9256}
9257
9258/* [MS-XLSB] 2.4.650 BrtFill */
9259var XLSBFillPTNames = [
9260 "none",
9261 "solid",
9262 "mediumGray",
9263 "darkGray",
9264 "lightGray",
9265 "darkHorizontal",
9266 "darkVertical",
9267 "darkDown",
9268 "darkUp",
9269 "darkGrid",
9270 "darkTrellis",
9271 "lightHorizontal",
9272 "lightVertical",
9273 "lightDown",
9274 "lightUp",
9275 "lightGrid",
9276 "lightTrellis",
9277 "gray125",
9278 "gray0625"
9279];
9280var rev_XLSBFillPTNames = (evert(XLSBFillPTNames));
9281/* TODO: gradient fill representation */
9282var parse_BrtFill = parsenoop;
9283function write_BrtFill(fill, o) {
9284 if(!o) o = new_buf(4*3 + 8*7 + 16*1);
9285 var fls = rev_XLSBFillPTNames[fill.patternType];
9286 if(fls == null) fls = 0x28;
9287 o.write_shift(4, fls);
9288 var j = 0;
9289 if(fls != 0x28) {
9290 /* TODO: custom FG Color */
9291 write_BrtColor({auto:1}, o);
9292 /* TODO: custom BG Color */
9293 write_BrtColor({auto:1}, o);
9294
9295 for(; j < 12; ++j) o.write_shift(4, 0);
9296 } else {
9297 for(; j < 4; ++j) o.write_shift(4, 0);
9298
9299 for(; j < 12; ++j) o.write_shift(4, 0); /* TODO */
9300 /* iGradientType */
9301 /* xnumDegree */
9302 /* xnumFillToLeft */
9303 /* xnumFillToRight */
9304 /* xnumFillToTop */
9305 /* xnumFillToBottom */
9306 /* cNumStop */
9307 /* xfillGradientStop */
9308 }
9309 return o.length > o.l ? o.slice(0, o.l) : o;
9310}
9311
9312/* [MS-XLSB] 2.4.824 BrtXF */
9313function parse_BrtXF(data, length) {
9314 var tgt = data.l + length;
9315 var ixfeParent = data.read_shift(2);
9316 var ifmt = data.read_shift(2);
9317 data.l = tgt;
9318 return {ixfe:ixfeParent, numFmtId:ifmt };
9319}
9320function write_BrtXF(data, ixfeP, o) {
9321 if(!o) o = new_buf(16);
9322 o.write_shift(2, ixfeP||0);
9323 o.write_shift(2, data.numFmtId||0);
9324 o.write_shift(2, 0); /* iFont */
9325 o.write_shift(2, 0); /* iFill */
9326 o.write_shift(2, 0); /* ixBorder */
9327 o.write_shift(1, 0); /* trot */
9328 o.write_shift(1, 0); /* indent */
9329 var flow = 0;
9330 o.write_shift(1, flow); /* flags */
9331 o.write_shift(1, 0); /* flags */
9332 o.write_shift(1, 0); /* xfGrbitAtr */
9333 o.write_shift(1, 0);
9334 return o;
9335}
9336
9337/* [MS-XLSB] 2.5.4 Blxf TODO */
9338function write_Blxf(data, o) {
9339 if(!o) o = new_buf(10);
9340 o.write_shift(1, 0); /* dg */
9341 o.write_shift(1, 0);
9342 o.write_shift(4, 0); /* color */
9343 o.write_shift(4, 0); /* color */
9344 return o;
9345}
9346/* [MS-XLSB] 2.4.302 BrtBorder TODO */
9347var parse_BrtBorder = parsenoop;
9348function write_BrtBorder(border, o) {
9349 if(!o) o = new_buf(51);
9350 o.write_shift(1, 0); /* diagonal */
9351 write_Blxf(null, o); /* top */
9352 write_Blxf(null, o); /* bottom */
9353 write_Blxf(null, o); /* left */
9354 write_Blxf(null, o); /* right */
9355 write_Blxf(null, o); /* diag */
9356 return o.length > o.l ? o.slice(0, o.l) : o;
9357}
9358
9359/* [MS-XLSB] 2.4.763 BrtStyle TODO */
9360function write_BrtStyle(style, o) {
9361 if(!o) o = new_buf(12+4*10);
9362 o.write_shift(4, style.xfId);
9363 o.write_shift(2, 1);
9364 o.write_shift(1, +style.builtinId);
9365 o.write_shift(1, 0); /* iLevel */
9366 write_XLNullableWideString(style.name || "", o);
9367 return o.length > o.l ? o.slice(0, o.l) : o;
9368}
9369
9370/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
9371function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
9372 var o = new_buf(4+256*2*4);
9373 o.write_shift(4, cnt);
9374 write_XLNullableWideString(defTableStyle, o);
9375 write_XLNullableWideString(defPivotStyle, o);
9376 return o.length > o.l ? o.slice(0, o.l) : o;
9377}
9378
9379/* [MS-XLSB] 2.1.7.50 Styles */
9380function parse_sty_bin(data, themes, opts) {
9381 var styles = {};
9382 styles.NumberFmt = ([]);
9383 for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y];
9384
9385 styles.CellXf = [];
9386 styles.Fonts = [];
9387 var state = [];
9388 var pass = false;
9389 recordhopper(data, function hopper_sty(val, R_n, RT) {
9390 switch(RT) {
9391 case 0x002C: /* 'BrtFmt' */
9392 styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]);
9393 break;
9394 case 0x002B: /* 'BrtFont' */
9395 styles.Fonts.push(val);
9396 if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) {
9397 val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0);
9398 }
9399 break;
9400 case 0x0401: /* 'BrtKnownFonts' */ break;
9401 case 0x002D: /* 'BrtFill' */
9402 break;
9403 case 0x002E: /* 'BrtBorder' */
9404 break;
9405 case 0x002F: /* 'BrtXF' */
9406 if(state[state.length - 1] == "BrtBeginCellXFs") {
9407 styles.CellXf.push(val);
9408 }
9409 break;
9410 case 0x0030: /* 'BrtStyle' */
9411 case 0x01FB: /* 'BrtDXF' */
9412 case 0x023C: /* 'BrtMRUColor' */
9413 case 0x01DB: /* 'BrtIndexedColor': */
9414 break;
9415
9416 case 0x0493: /* 'BrtDXF14' */
9417 case 0x0836: /* 'BrtDXF15' */
9418 case 0x046A: /* 'BrtSlicerStyleElement' */
9419 case 0x0200: /* 'BrtTableStyleElement' */
9420 case 0x082F: /* 'BrtTimelineStyleElement' */
9421 case 0x0C00: /* 'BrtUid' */
9422 break;
9423
9424 case 0x0023: /* 'BrtFRTBegin' */
9425 pass = true; break;
9426 case 0x0024: /* 'BrtFRTEnd' */
9427 pass = false; break;
9428 case 0x0025: /* 'BrtACBegin' */
9429 state.push(R_n); pass = true; break;
9430 case 0x0026: /* 'BrtACEnd' */
9431 state.pop(); pass = false; break;
9432
9433 default:
9434 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
9435 else if((R_n||"").indexOf("End") > 0) state.pop();
9436 else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
9437 }
9438 });
9439 return styles;
9440}
9441
9442function write_FMTS_bin(ba, NF) {
9443 if(!NF) return;
9444 var cnt = 0;
9445 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9446for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
9447 });
9448
9449 if(cnt == 0) return;
9450 write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
9451 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9452for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
9453 });
9454 write_record(ba, "BrtEndFmts");
9455}
9456
9457function write_FONTS_bin(ba) {
9458 var cnt = 1;
9459
9460 if(cnt == 0) return;
9461 write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt));
9462 write_record(ba, "BrtFont", write_BrtFont({
9463 sz:12,
9464 color: {theme:1},
9465 name: "Calibri",
9466 family: 2,
9467 scheme: "minor"
9468 }));
9469 /* 1*65491BrtFont [ACFONTS] */
9470 write_record(ba, "BrtEndFonts");
9471}
9472
9473function write_FILLS_bin(ba) {
9474 var cnt = 2;
9475
9476 if(cnt == 0) return;
9477 write_record(ba, "BrtBeginFills", write_UInt32LE(cnt));
9478 write_record(ba, "BrtFill", write_BrtFill({patternType:"none"}));
9479 write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"}));
9480 /* 1*65431BrtFill */
9481 write_record(ba, "BrtEndFills");
9482}
9483
9484function write_BORDERS_bin(ba) {
9485 var cnt = 1;
9486
9487 if(cnt == 0) return;
9488 write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt));
9489 write_record(ba, "BrtBorder", write_BrtBorder({}));
9490 /* 1*65430BrtBorder */
9491 write_record(ba, "BrtEndBorders");
9492}
9493
9494function write_CELLSTYLEXFS_bin(ba) {
9495 var cnt = 1;
9496 write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
9497 write_record(ba, "BrtXF", write_BrtXF({
9498 numFmtId: 0,
9499 fontId: 0,
9500 fillId: 0,
9501 borderId: 0
9502 }, 0xFFFF));
9503 /* 1*65430(BrtXF *FRT) */
9504 write_record(ba, "BrtEndCellStyleXFs");
9505}
9506
9507function write_CELLXFS_bin(ba, data) {
9508 write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length));
9509 data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); });
9510 /* 1*65430(BrtXF *FRT) */
9511 write_record(ba, "BrtEndCellXFs");
9512}
9513
9514function write_STYLES_bin(ba) {
9515 var cnt = 1;
9516
9517 write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt));
9518 write_record(ba, "BrtStyle", write_BrtStyle({
9519 xfId:0,
9520 builtinId:0,
9521 name:"Normal"
9522 }));
9523 /* 1*65430(BrtStyle *FRT) */
9524 write_record(ba, "BrtEndStyles");
9525}
9526
9527function write_DXFS_bin(ba) {
9528 var cnt = 0;
9529
9530 write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
9531 /* *2147483647(BrtDXF *FRT) */
9532 write_record(ba, "BrtEndDXFs");
9533}
9534
9535function write_TABLESTYLES_bin(ba) {
9536 var cnt = 0;
9537
9538 write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
9539 /* *TABLESTYLE */
9540 write_record(ba, "BrtEndTableStyles");
9541}
9542
9543function write_COLORPALETTE_bin() {
9544 return;
9545 /* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
9546}
9547
9548/* [MS-XLSB] 2.1.7.50 Styles */
9549function write_sty_bin(wb, opts) {
9550 var ba = buf_array();
9551 write_record(ba, "BrtBeginStyleSheet");
9552 write_FMTS_bin(ba, wb.SSF);
9553 write_FONTS_bin(ba, wb);
9554 write_FILLS_bin(ba, wb);
9555 write_BORDERS_bin(ba, wb);
9556 write_CELLSTYLEXFS_bin(ba, wb);
9557 write_CELLXFS_bin(ba, opts.cellXfs);
9558 write_STYLES_bin(ba, wb);
9559 write_DXFS_bin(ba, wb);
9560 write_TABLESTYLES_bin(ba, wb);
9561 write_COLORPALETTE_bin(ba, wb);
9562 /* FRTSTYLESHEET*/
9563 write_record(ba, "BrtEndStyleSheet");
9564 return ba.end();
9565}
9566RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
9567
9568/* 20.1.6.2 clrScheme CT_ColorScheme */
9569function parse_clrScheme(t, themes, opts) {
9570 themes.themeElements.clrScheme = [];
9571 var color = {};
9572 (t[0].match(tagregex)||[]).forEach(function(x) {
9573 var y = parsexmltag(x);
9574 switch(y[0]) {
9575 /* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
9576 case '<a:clrScheme': case '</a:clrScheme>': break;
9577
9578 /* 20.1.2.3.32 srgbClr CT_SRgbColor */
9579 case '<a:srgbClr':
9580 color.rgb = y.val; break;
9581
9582 /* 20.1.2.3.33 sysClr CT_SystemColor */
9583 case '<a:sysClr':
9584 color.rgb = y.lastClr; break;
9585
9586 /* 20.1.4.1.1 accent1 (Accent 1) */
9587 /* 20.1.4.1.2 accent2 (Accent 2) */
9588 /* 20.1.4.1.3 accent3 (Accent 3) */
9589 /* 20.1.4.1.4 accent4 (Accent 4) */
9590 /* 20.1.4.1.5 accent5 (Accent 5) */
9591 /* 20.1.4.1.6 accent6 (Accent 6) */
9592 /* 20.1.4.1.9 dk1 (Dark 1) */
9593 /* 20.1.4.1.10 dk2 (Dark 2) */
9594 /* 20.1.4.1.15 folHlink (Followed Hyperlink) */
9595 /* 20.1.4.1.19 hlink (Hyperlink) */
9596 /* 20.1.4.1.22 lt1 (Light 1) */
9597 /* 20.1.4.1.23 lt2 (Light 2) */
9598 case '<a:dk1>': case '</a:dk1>':
9599 case '<a:lt1>': case '</a:lt1>':
9600 case '<a:dk2>': case '</a:dk2>':
9601 case '<a:lt2>': case '</a:lt2>':
9602 case '<a:accent1>': case '</a:accent1>':
9603 case '<a:accent2>': case '</a:accent2>':
9604 case '<a:accent3>': case '</a:accent3>':
9605 case '<a:accent4>': case '</a:accent4>':
9606 case '<a:accent5>': case '</a:accent5>':
9607 case '<a:accent6>': case '</a:accent6>':
9608 case '<a:hlink>': case '</a:hlink>':
9609 case '<a:folHlink>': case '</a:folHlink>':
9610 if (y[0].charAt(1) === '/') {
9611 themes.themeElements.clrScheme.push(color);
9612 color = {};
9613 } else {
9614 color.name = y[0].slice(3, y[0].length - 1);
9615 }
9616 break;
9617
9618 default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
9619 }
9620 });
9621}
9622
9623/* 20.1.4.1.18 fontScheme CT_FontScheme */
9624function parse_fontScheme() { }
9625
9626/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
9627function parse_fmtScheme() { }
9628
9629var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
9630var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
9631var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
9632
9633/* 20.1.6.10 themeElements CT_BaseStyles */
9634function parse_themeElements(data, themes, opts) {
9635 themes.themeElements = {};
9636
9637 var t;
9638
9639 [
9640 /* clrScheme CT_ColorScheme */
9641 ['clrScheme', clrsregex, parse_clrScheme],
9642 /* fontScheme CT_FontScheme */
9643 ['fontScheme', fntsregex, parse_fontScheme],
9644 /* fmtScheme CT_StyleMatrix */
9645 ['fmtScheme', fmtsregex, parse_fmtScheme]
9646 ].forEach(function(m) {
9647 if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
9648 m[2](t, themes, opts);
9649 });
9650}
9651
9652var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
9653
9654/* 14.2.7 Theme Part */
9655function parse_theme_xml(data, opts) {
9656 /* 20.1.6.9 theme CT_OfficeStyleSheet */
9657 if(!data || data.length === 0) return parse_theme_xml(write_theme());
9658
9659 var t;
9660 var themes = {};
9661
9662 /* themeElements CT_BaseStyles */
9663 if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
9664 parse_themeElements(t[0], themes, opts);
9665 themes.raw = data;
9666 return themes;
9667}
9668
9669function write_theme(Themes, opts) {
9670 if(opts && opts.themeXLSX) return opts.themeXLSX;
9671 if(Themes && typeof Themes.raw == "string") return Themes.raw;
9672 var o = [XML_HEADER];
9673 o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
9674 o[o.length] = '<a:themeElements>';
9675
9676 o[o.length] = '<a:clrScheme name="Office">';
9677 o[o.length] = '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
9678 o[o.length] = '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
9679 o[o.length] = '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
9680 o[o.length] = '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
9681 o[o.length] = '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
9682 o[o.length] = '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
9683 o[o.length] = '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
9684 o[o.length] = '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
9685 o[o.length] = '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
9686 o[o.length] = '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
9687 o[o.length] = '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
9688 o[o.length] = '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
9689 o[o.length] = '</a:clrScheme>';
9690
9691 o[o.length] = '<a:fontScheme name="Office">';
9692 o[o.length] = '<a:majorFont>';
9693 o[o.length] = '<a:latin typeface="Cambria"/>';
9694 o[o.length] = '<a:ea typeface=""/>';
9695 o[o.length] = '<a:cs typeface=""/>';
9696 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
9697 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
9698 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
9699 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
9700 o[o.length] = '<a:font script="Arab" typeface="Times New Roman"/>';
9701 o[o.length] = '<a:font script="Hebr" typeface="Times New Roman"/>';
9702 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
9703 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
9704 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
9705 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
9706 o[o.length] = '<a:font script="Khmr" typeface="MoolBoran"/>';
9707 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
9708 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
9709 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
9710 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
9711 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
9712 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
9713 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
9714 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
9715 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
9716 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
9717 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
9718 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
9719 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
9720 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
9721 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
9722 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
9723 o[o.length] = '<a:font script="Viet" typeface="Times New Roman"/>';
9724 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
9725 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
9726 o[o.length] = '</a:majorFont>';
9727 o[o.length] = '<a:minorFont>';
9728 o[o.length] = '<a:latin typeface="Calibri"/>';
9729 o[o.length] = '<a:ea typeface=""/>';
9730 o[o.length] = '<a:cs typeface=""/>';
9731 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
9732 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
9733 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
9734 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
9735 o[o.length] = '<a:font script="Arab" typeface="Arial"/>';
9736 o[o.length] = '<a:font script="Hebr" typeface="Arial"/>';
9737 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
9738 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
9739 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
9740 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
9741 o[o.length] = '<a:font script="Khmr" typeface="DaunPenh"/>';
9742 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
9743 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
9744 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
9745 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
9746 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
9747 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
9748 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
9749 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
9750 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
9751 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
9752 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
9753 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
9754 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
9755 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
9756 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
9757 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
9758 o[o.length] = '<a:font script="Viet" typeface="Arial"/>';
9759 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
9760 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
9761 o[o.length] = '</a:minorFont>';
9762 o[o.length] = '</a:fontScheme>';
9763
9764 o[o.length] = '<a:fmtScheme name="Office">';
9765 o[o.length] = '<a:fillStyleLst>';
9766 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9767 o[o.length] = '<a:gradFill rotWithShape="1">';
9768 o[o.length] = '<a:gsLst>';
9769 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9770 o[o.length] = '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9771 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9772 o[o.length] = '</a:gsLst>';
9773 o[o.length] = '<a:lin ang="16200000" scaled="1"/>';
9774 o[o.length] = '</a:gradFill>';
9775 o[o.length] = '<a:gradFill rotWithShape="1">';
9776 o[o.length] = '<a:gsLst>';
9777 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>';
9778 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>';
9779 o[o.length] = '</a:gsLst>';
9780 o[o.length] = '<a:lin ang="16200000" scaled="0"/>';
9781 o[o.length] = '</a:gradFill>';
9782 o[o.length] = '</a:fillStyleLst>';
9783 o[o.length] = '<a:lnStyleLst>';
9784 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>';
9785 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>';
9786 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>';
9787 o[o.length] = '</a:lnStyleLst>';
9788 o[o.length] = '<a:effectStyleLst>';
9789 o[o.length] = '<a:effectStyle>';
9790 o[o.length] = '<a:effectLst>';
9791 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>';
9792 o[o.length] = '</a:effectLst>';
9793 o[o.length] = '</a:effectStyle>';
9794 o[o.length] = '<a:effectStyle>';
9795 o[o.length] = '<a:effectLst>';
9796 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>';
9797 o[o.length] = '</a:effectLst>';
9798 o[o.length] = '</a:effectStyle>';
9799 o[o.length] = '<a:effectStyle>';
9800 o[o.length] = '<a:effectLst>';
9801 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>';
9802 o[o.length] = '</a:effectLst>';
9803 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>';
9804 o[o.length] = '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
9805 o[o.length] = '</a:effectStyle>';
9806 o[o.length] = '</a:effectStyleLst>';
9807 o[o.length] = '<a:bgFillStyleLst>';
9808 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9809 o[o.length] = '<a:gradFill rotWithShape="1">';
9810 o[o.length] = '<a:gsLst>';
9811 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9812 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>';
9813 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
9814 o[o.length] = '</a:gsLst>';
9815 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
9816 o[o.length] = '</a:gradFill>';
9817 o[o.length] = '<a:gradFill rotWithShape="1">';
9818 o[o.length] = '<a:gsLst>';
9819 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9820 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
9821 o[o.length] = '</a:gsLst>';
9822 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
9823 o[o.length] = '</a:gradFill>';
9824 o[o.length] = '</a:bgFillStyleLst>';
9825 o[o.length] = '</a:fmtScheme>';
9826 o[o.length] = '</a:themeElements>';
9827
9828 o[o.length] = '<a:objectDefaults>';
9829 o[o.length] = '<a:spDef>';
9830 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>';
9831 o[o.length] = '</a:spDef>';
9832 o[o.length] = '<a:lnDef>';
9833 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>';
9834 o[o.length] = '</a:lnDef>';
9835 o[o.length] = '</a:objectDefaults>';
9836 o[o.length] = '<a:extraClrSchemeLst/>';
9837 o[o.length] = '</a:theme>';
9838 return o.join("");
9839}
9840/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
9841function parse_Theme(blob, length, opts) {
9842 var end = blob.l + length;
9843 var dwThemeVersion = blob.read_shift(4);
9844 if(dwThemeVersion === 124226) return;
9845 if(!opts.cellStyles || !jszip) { blob.l = end; return; }
9846 var data = blob.slice(blob.l);
9847 blob.l = end;
9848 var zip; try { zip = new jszip(data); } catch(e) { return; }
9849 var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true);
9850 if(!themeXML) return;
9851 return parse_theme_xml(themeXML, opts);
9852}
9853
9854/* 2.5.49 */
9855function parse_ColorTheme(blob) { return blob.read_shift(4); }
9856
9857/* 2.5.155 */
9858function parse_FullColorExt(blob) {
9859 var o = {};
9860 o.xclrType = blob.read_shift(2);
9861 o.nTintShade = blob.read_shift(2);
9862 switch(o.xclrType) {
9863 case 0: blob.l += 4; break;
9864 case 1: o.xclrValue = parse_IcvXF(blob, 4); break;
9865 case 2: o.xclrValue = parse_LongRGBA(blob, 4); break;
9866 case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
9867 case 4: blob.l += 4; break;
9868 }
9869 blob.l += 8;
9870 return o;
9871}
9872
9873/* 2.5.164 TODO: read 7 bits*/
9874function parse_IcvXF(blob, length) {
9875 return parsenoop(blob, length);
9876}
9877
9878/* 2.5.280 */
9879function parse_XFExtGradient(blob, length) {
9880 return parsenoop(blob, length);
9881}
9882
9883/* [MS-XLS] 2.5.108 */
9884function parse_ExtProp(blob) {
9885 var extType = blob.read_shift(2);
9886 var cb = blob.read_shift(2) - 4;
9887 var o = [extType];
9888 switch(extType) {
9889 case 0x04: case 0x05: case 0x07: case 0x08:
9890 case 0x09: case 0x0A: case 0x0B: case 0x0D:
9891 o[1] = parse_FullColorExt(blob, cb); break;
9892 case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
9893 case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
9894 default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
9895 }
9896 return o;
9897}
9898
9899/* 2.4.355 */
9900function parse_XFExt(blob, length) {
9901 var end = blob.l + length;
9902 blob.l += 2;
9903 var ixfe = blob.read_shift(2);
9904 blob.l += 2;
9905 var cexts = blob.read_shift(2);
9906 var ext = [];
9907 while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
9908 return {ixfe:ixfe, ext:ext};
9909}
9910
9911/* xf is an XF, see parse_XFExt for xfext */
9912function update_xfext(xf, xfext) {
9913 xfext.forEach(function(xfe) {
9914 switch(xfe[0]) { /* 2.5.108 extPropData */
9915 case 0x04: break; /* foreground color */
9916 case 0x05: break; /* background color */
9917 case 0x06: break; /* gradient fill */
9918 case 0x07: break; /* top cell border color */
9919 case 0x08: break; /* bottom cell border color */
9920 case 0x09: break; /* left cell border color */
9921 case 0x0a: break; /* right cell border color */
9922 case 0x0b: break; /* diagonal cell border color */
9923 case 0x0d: /* text color */
9924 break;
9925 case 0x0e: break; /* font scheme */
9926 case 0x0f: break; /* indentation level */
9927 }
9928 });
9929}
9930
9931/* 18.6 Calculation Chain */
9932function parse_cc_xml(data) {
9933 var d = [];
9934 if(!data) return d;
9935 var i = 1;
9936 (data.match(tagregex)||[]).forEach(function(x) {
9937 var y = parsexmltag(x);
9938 switch(y[0]) {
9939 case '<?xml': break;
9940 /* 18.6.2 calcChain CT_CalcChain 1 */
9941 case '<calcChain': case '<calcChain>': case '</calcChain>': break;
9942 /* 18.6.1 c CT_CalcCell 1 */
9943 case '<c': delete y[0]; if(y.i) i = y.i; else y.i = i; d.push(y); break;
9944 }
9945 });
9946 return d;
9947}
9948
9949//function write_cc_xml(data, opts) { }
9950
9951/* [MS-XLSB] 2.6.4.1 */
9952function parse_BrtCalcChainItem$(data) {
9953 var out = {};
9954 out.i = data.read_shift(4);
9955 var cell = {};
9956 cell.r = data.read_shift(4);
9957 cell.c = data.read_shift(4);
9958 out.r = encode_cell(cell);
9959 var flags = data.read_shift(1);
9960 if(flags & 0x2) out.l = '1';
9961 if(flags & 0x8) out.a = '1';
9962 return out;
9963}
9964
9965/* 18.6 Calculation Chain */
9966function parse_cc_bin(data, name, opts) {
9967 var out = [];
9968 var pass = false;
9969 recordhopper(data, function hopper_cc(val, R_n, RT) {
9970 switch(RT) {
9971 case 0x003F: /* 'BrtCalcChainItem$' */
9972 out.push(val); break;
9973
9974 default:
9975 if((R_n||"").indexOf("Begin") > 0){/* empty */}
9976 else if((R_n||"").indexOf("End") > 0){/* empty */}
9977 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9978 }
9979 });
9980 return out;
9981}
9982
9983//function write_cc_bin(data, opts) { }
9984/* 18.14 Supplementary Workbook Data */
9985function parse_xlink_xml() {
9986 //var opts = _opts || {};
9987 //if(opts.WTF) throw "XLSX External Link";
9988}
9989
9990/* [MS-XLSB] 2.1.7.25 External Link */
9991function parse_xlink_bin(data, rel, name, _opts) {
9992 if(!data) return data;
9993 var opts = _opts || {};
9994
9995 var pass = false, end = false;
9996
9997 recordhopper(data, function xlink_parse(val, R_n, RT) {
9998 if(end) return;
9999 switch(RT) {
10000 case 0x0167: /* 'BrtSupTabs' */
10001 case 0x016B: /* 'BrtExternTableStart' */
10002 case 0x016C: /* 'BrtExternTableEnd' */
10003 case 0x016E: /* 'BrtExternRowHdr' */
10004 case 0x016F: /* 'BrtExternCellBlank' */
10005 case 0x0170: /* 'BrtExternCellReal' */
10006 case 0x0171: /* 'BrtExternCellBool' */
10007 case 0x0172: /* 'BrtExternCellError' */
10008 case 0x0173: /* 'BrtExternCellString' */
10009 case 0x01D8: /* 'BrtExternValueMeta' */
10010 case 0x0241: /* 'BrtSupNameStart' */
10011 case 0x0242: /* 'BrtSupNameValueStart' */
10012 case 0x0243: /* 'BrtSupNameValueEnd' */
10013 case 0x0244: /* 'BrtSupNameNum' */
10014 case 0x0245: /* 'BrtSupNameErr' */
10015 case 0x0246: /* 'BrtSupNameSt' */
10016 case 0x0247: /* 'BrtSupNameNil' */
10017 case 0x0248: /* 'BrtSupNameBool' */
10018 case 0x0249: /* 'BrtSupNameFmla' */
10019 case 0x024A: /* 'BrtSupNameBits' */
10020 case 0x024B: /* 'BrtSupNameEnd' */
10021 break;
10022
10023 case 0x0023: /* 'BrtFRTBegin' */
10024 pass = true; break;
10025 case 0x0024: /* 'BrtFRTEnd' */
10026 pass = false; break;
10027
10028 default:
10029 if((R_n||"").indexOf("Begin") > 0){/* empty */}
10030 else if((R_n||"").indexOf("End") > 0){/* empty */}
10031 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
10032 }
10033 }, opts);
10034}
10035/* 20.5 DrawingML - SpreadsheetML Drawing */
10036RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
10037RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
10038
10039/* 20.5.2.35 wsDr CT_Drawing */
10040function parse_drawing(data, rels) {
10041 if(!data) return "??";
10042 /*
10043 Chartsheet Drawing:
10044 - 20.5.2.35 wsDr CT_Drawing
10045 - 20.5.2.1 absoluteAnchor CT_AbsoluteAnchor
10046 - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
10047 - 20.1.2.2.16 graphic CT_GraphicalObject
10048 - 20.1.2.2.17 graphicData CT_GraphicalObjectData
10049 - chart reference
10050 the actual type is based on the URI of the graphicData
10051 TODO: handle embedded charts and other types of graphics
10052 */
10053 var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
10054
10055 return rels['!id'][id].Target;
10056}
10057
10058/* L.5.5.2 SpreadsheetML Comments + VML Schema */
10059var _shapeid = 1024;
10060function write_comments_vml(rId, comments) {
10061 var csize = [21600, 21600];
10062 /* L.5.2.1.2 Path Attribute */
10063 var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
10064 var o = [
10065 writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
10066 writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
10067 writextag("v:shapetype", [
10068 writextag("v:stroke", null, {joinstyle:"miter"}),
10069 writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
10070 ].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
10071 ];
10072 while(_shapeid < rId * 1000) _shapeid += 1000;
10073
10074 comments.forEach(function(x) {
10075 var c = decode_cell(x[0]);
10076 var fillopts = {'color2':"#BEFF82", 'type':"gradient"};
10077 if(fillopts.type == "gradient") fillopts.angle = "-180";
10078 var fillparm = fillopts.type == "gradient" ? writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}) : null;
10079 var fillxml = writextag('v:fill', fillparm, fillopts);
10080
10081 var shadata = ({on:"t", 'obscured':"t"});
10082 ++_shapeid;
10083
10084 o = o.concat([
10085 '<v:shape' + wxt_helper({
10086 id:'_x0000_s' + _shapeid,
10087 type:"#_x0000_t202",
10088 style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
10089 fillcolor:"#ECFAD4",
10090 strokecolor:"#edeaa1"
10091 }) + '>',
10092 fillxml,
10093 writextag("v:shadow", null, shadata),
10094 writextag("v:path", null, {'o:connecttype':"none"}),
10095 '<v:textbox><div style="text-align:left"></div></v:textbox>',
10096 '<x:ClientData ObjectType="Note">',
10097 '<x:MoveWithCells/>',
10098 '<x:SizeWithCells/>',
10099 /* Part 4 19.4.2.3 Anchor (Anchor) */
10100 writetag('x:Anchor', [c.c+1, 0, c.r+1, 0, c.c+3, 20, c.r+5, 20].join(",")),
10101 writetag('x:AutoFill', "False"),
10102 writetag('x:Row', String(c.r)),
10103 writetag('x:Column', String(c.c)),
10104 x[1].hidden ? '' : '<x:Visible/>',
10105 '</x:ClientData>',
10106 '</v:shape>'
10107 ]); });
10108 o.push('</xml>');
10109 return o.join("");
10110}
10111RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
10112
10113function sheet_insert_comments(sheet, comments) {
10114 var dense = Array.isArray(sheet);
10115 var cell;
10116 comments.forEach(function(comment) {
10117 var r = decode_cell(comment.ref);
10118 if(dense) {
10119 if(!sheet[r.r]) sheet[r.r] = [];
10120 cell = sheet[r.r][r.c];
10121 } else cell = sheet[comment.ref];
10122 if (!cell) {
10123 cell = ({t:"z"});
10124 if(dense) sheet[r.r][r.c] = cell;
10125 else sheet[comment.ref] = cell;
10126 var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
10127 if(range.s.r > r.r) range.s.r = r.r;
10128 if(range.e.r < r.r) range.e.r = r.r;
10129 if(range.s.c > r.c) range.s.c = r.c;
10130 if(range.e.c < r.c) range.e.c = r.c;
10131 var encoded = encode_range(range);
10132 if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
10133 }
10134
10135 if (!cell.c) cell.c = [];
10136 var o = ({a: comment.author, t: comment.t, r: comment.r});
10137 if(comment.h) o.h = comment.h;
10138 cell.c.push(o);
10139 });
10140}
10141
10142/* 18.7 Comments */
10143function parse_comments_xml(data, opts) {
10144 /* 18.7.6 CT_Comments */
10145 if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
10146 var authors = [];
10147 var commentList = [];
10148 var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
10149 if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
10150 if(x === "" || x.trim() === "") return;
10151 var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
10152 if(a) authors.push(a[1]);
10153 });
10154 var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
10155 if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
10156 if(x === "" || x.trim() === "") return;
10157 var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
10158 if(!cm) return;
10159 var y = parsexmltag(cm[0]);
10160 var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
10161 var cell = decode_cell(y.ref);
10162 if(opts.sheetRows && opts.sheetRows <= cell.r) return;
10163 var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
10164 var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
10165 comment.r = rt.r;
10166 if(rt.r == "<t></t>") rt.t = rt.h = "";
10167 comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
10168 if(opts.cellHTML) comment.h = rt.h;
10169 commentList.push(comment);
10170 });
10171 return commentList;
10172}
10173
10174var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
10175function write_comments_xml(data) {
10176 var o = [XML_HEADER, CMNT_XML_ROOT];
10177
10178 var iauthor = [];
10179 o.push("<authors>");
10180 data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
10181 if(iauthor.indexOf(a) > -1) return;
10182 iauthor.push(a);
10183 o.push("<author>" + a + "</author>");
10184 }); });
10185 o.push("</authors>");
10186 o.push("<commentList>");
10187 data.forEach(function(d) {
10188 d[1].forEach(function(c) {
10189 /* 18.7.3 CT_Comment */
10190 o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
10191 o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
10192 o.push('</text></comment>');
10193 });
10194 });
10195 o.push("</commentList>");
10196 if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
10197 return o.join("");
10198}
10199/* [MS-XLSB] 2.4.28 BrtBeginComment */
10200function parse_BrtBeginComment(data) {
10201 var out = {};
10202 out.iauthor = data.read_shift(4);
10203 var rfx = parse_UncheckedRfX(data, 16);
10204 out.rfx = rfx.s;
10205 out.ref = encode_cell(rfx.s);
10206 data.l += 16; /*var guid = parse_GUID(data); */
10207 return out;
10208}
10209function write_BrtBeginComment(data, o) {
10210 if(o == null) o = new_buf(36);
10211 o.write_shift(4, data[1].iauthor);
10212 write_UncheckedRfX((data[0]), o);
10213 o.write_shift(4, 0);
10214 o.write_shift(4, 0);
10215 o.write_shift(4, 0);
10216 o.write_shift(4, 0);
10217 return o;
10218}
10219
10220/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
10221var parse_BrtCommentAuthor = parse_XLWideString;
10222function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
10223
10224/* [MS-XLSB] 2.1.7.8 Comments */
10225function parse_comments_bin(data, opts) {
10226 var out = [];
10227 var authors = [];
10228 var c = {};
10229 var pass = false;
10230 recordhopper(data, function hopper_cmnt(val, R_n, RT) {
10231 switch(RT) {
10232 case 0x0278: /* 'BrtCommentAuthor' */
10233 authors.push(val); break;
10234 case 0x027B: /* 'BrtBeginComment' */
10235 c = val; break;
10236 case 0x027D: /* 'BrtCommentText' */
10237 c.t = val.t; c.h = val.h; c.r = val.r; break;
10238 case 0x027C: /* 'BrtEndComment' */
10239 c.author = authors[c.iauthor];
10240 delete (c).iauthor;
10241 if(opts.sheetRows && c.rfx && opts.sheetRows <= c.rfx.r) break;
10242 if(!c.t) c.t = "";
10243 delete c.rfx; out.push(c); break;
10244
10245 case 0x0C00: /* 'BrtUid' */
10246 break;
10247
10248 case 0x0023: /* 'BrtFRTBegin' */
10249 pass = true; break;
10250 case 0x0024: /* 'BrtFRTEnd' */
10251 pass = false; break;
10252 case 0x0025: /* 'BrtACBegin' */ break;
10253 case 0x0026: /* 'BrtACEnd' */ break;
10254
10255
10256 default:
10257 if((R_n||"").indexOf("Begin") > 0){/* empty */}
10258 else if((R_n||"").indexOf("End") > 0){/* empty */}
10259 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
10260 }
10261 });
10262 return out;
10263}
10264
10265function write_comments_bin(data) {
10266 var ba = buf_array();
10267 var iauthor = [];
10268 write_record(ba, "BrtBeginComments");
10269
10270 write_record(ba, "BrtBeginCommentAuthors");
10271 data.forEach(function(comment) {
10272 comment[1].forEach(function(c) {
10273 if(iauthor.indexOf(c.a) > -1) return;
10274 iauthor.push(c.a.slice(0,54));
10275 write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a));
10276 });
10277 });
10278 write_record(ba, "BrtEndCommentAuthors");
10279
10280 write_record(ba, "BrtBeginCommentList");
10281 data.forEach(function(comment) {
10282 comment[1].forEach(function(c) {
10283 c.iauthor = iauthor.indexOf(c.a);
10284 var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
10285 write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c]));
10286 if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c));
10287 write_record(ba, "BrtEndComment");
10288 delete c.iauthor;
10289 });
10290 });
10291 write_record(ba, "BrtEndCommentList");
10292
10293 write_record(ba, "BrtEndComments");
10294 return ba.end();
10295}
10296var CT_VBA = "application/vnd.ms-office.vbaProject";
10297function make_vba_xls(cfb) {
10298 var newcfb = CFB.utils.cfb_new({root:"R"});
10299 cfb.FullPaths.forEach(function(p, i) {
10300 if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
10301 var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
10302 CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
10303 });
10304 return CFB.write(newcfb);
10305}
10306
10307function fill_vba_xls(cfb, vba) {
10308 vba.FullPaths.forEach(function(p, i) {
10309 if(i == 0) return;
10310 var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
10311 if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
10312 });
10313}
10314
10315var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
10316
10317RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
10318RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
10319
10320/* macro and dialog sheet stubs */
10321function parse_ds_bin() { return {'!type':'dialog'}; }
10322function parse_ds_xml() { return {'!type':'dialog'}; }
10323function parse_ms_bin() { return {'!type':'macro'}; }
10324function parse_ms_xml() { return {'!type':'macro'}; }
10325/* TODO: it will be useful to parse the function str */
10326var rc_to_a1 = (function(){
10327 var rcregex = /(^|[^A-Za-z_])R(\[?-?\d+\]|[1-9]\d*|)C(\[?-?\d+\]|[1-9]\d*|)(?![A-Za-z0-9_])/g;
10328 var rcbase = ({r:0,c:0});
10329 function rcfunc($$,$1,$2,$3) {
10330 var cRel = false, rRel = false;
10331
10332 if($2.length == 0) rRel = true;
10333 else if($2.charAt(0) == "[") { rRel = true; $2 = $2.slice(1, -1); }
10334
10335 if($3.length == 0) cRel = true;
10336 else if($3.charAt(0) == "[") { cRel = true; $3 = $3.slice(1, -1); }
10337
10338 var R = $2.length>0?parseInt($2,10)|0:0, C = $3.length>0?parseInt($3,10)|0:0;
10339
10340 if(cRel) C += rcbase.c; else --C;
10341 if(rRel) R += rcbase.r; else --R;
10342 return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
10343 }
10344 return function rc_to_a1(fstr, base) {
10345 rcbase = base;
10346 return fstr.replace(rcregex, rcfunc);
10347 };
10348})();
10349
10350var 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;
10351var a1_to_rc =(function(){
10352 return function a1_to_rc(fstr, base) {
10353 return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
10354 var c = decode_col($3) - ($2 ? 0 : base.c);
10355 var r = decode_row($5) - ($4 ? 0 : base.r);
10356 var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
10357 var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
10358 return $1 + "R" + R + "C" + C;
10359 });
10360 };
10361})();
10362
10363/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
10364function shift_formula_str(f, delta) {
10365 return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
10366 return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
10367 });
10368}
10369
10370function shift_formula_xlsx(f, range, cell) {
10371 var r = decode_range(range), s = r.s, c = decode_cell(cell);
10372 var delta = {r:c.r - s.r, c:c.c - s.c};
10373 return shift_formula_str(f, delta);
10374}
10375
10376/* TODO: parse formula */
10377function fuzzyfmla(f) {
10378 if(f.length == 1) return false;
10379 return true;
10380}
10381
10382function _xlfn(f) {
10383 return f.replace(/_xlfn\./g,"");
10384}
10385function parseread1(blob) { blob.l+=1; return; }
10386
10387/* [MS-XLS] 2.5.51 */
10388function parse_ColRelU(blob, length) {
10389 var c = blob.read_shift(length == 1 ? 1 : 2);
10390 return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
10391}
10392
10393/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.89 */
10394function parse_RgceArea(blob, length, opts) {
10395 var w = 2;
10396 if(opts) {
10397 if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts);
10398 else if(opts.biff == 12) w = 4;
10399 }
10400 var r=blob.read_shift(w), R=blob.read_shift(w);
10401 var c=parse_ColRelU(blob, 2);
10402 var C=parse_ColRelU(blob, 2);
10403 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]} };
10404}
10405/* BIFF 2-5 encodes flags in the row field */
10406function parse_RgceArea_BIFF2(blob) {
10407 var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
10408 var c=blob.read_shift(1);
10409 var C=blob.read_shift(1);
10410 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]} };
10411}
10412
10413/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.90 */
10414function parse_RgceAreaRel(blob, length, opts) {
10415 if(opts.biff < 8) return parse_RgceArea_BIFF2(blob, length, opts);
10416 var r=blob.read_shift(opts.biff == 12 ? 4 : 2), R=blob.read_shift(opts.biff == 12 ? 4 : 2);
10417 var c=parse_ColRelU(blob, 2);
10418 var C=parse_ColRelU(blob, 2);
10419 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]} };
10420}
10421
10422/* [MS-XLS] 2.5.198.109 ; [MS-XLSB] 2.5.97.91 */
10423function parse_RgceLoc(blob, length, opts) {
10424 if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts);
10425 var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2);
10426 var c = parse_ColRelU(blob, 2);
10427 return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
10428}
10429function parse_RgceLoc_BIFF2(blob) {
10430 var r = parse_ColRelU(blob, 2);
10431 var c = blob.read_shift(1);
10432 return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
10433}
10434
10435/* [MS-XLS] 2.5.198.107, 2.5.47 */
10436function parse_RgceElfLoc(blob) {
10437 var r = blob.read_shift(2);
10438 var c = blob.read_shift(2);
10439 return {r:r, c:c & 0xFF, fQuoted:!!(c & 0x4000), cRel:c>>15, rRel:c>>15 };
10440}
10441
10442/* [MS-XLS] 2.5.198.111 ; [MS-XLSB] 2.5.97.92 TODO */
10443function parse_RgceLocRel(blob, length, opts) {
10444 var biff = opts && opts.biff ? opts.biff : 8;
10445 if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts);
10446 var r = blob.read_shift(biff >= 12 ? 4 : 2);
10447 var cl = blob.read_shift(2);
10448 var cRel = (cl & 0x4000) >> 14, rRel = (cl & 0x8000) >> 15;
10449 cl &= 0x3FFF;
10450 if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000;
10451 if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000;
10452 return {r:r,c:cl,cRel:cRel,rRel:rRel};
10453}
10454function parse_RgceLocRel_BIFF2(blob) {
10455 var rl = blob.read_shift(2);
10456 var c = blob.read_shift(1);
10457 var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14;
10458 rl &= 0x3FFF;
10459 if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000;
10460 if(cRel == 1 && c >= 0x80) c = c - 0x100;
10461 return {r:rl,c:c,cRel:cRel,rRel:rRel};
10462}
10463
10464/* [MS-XLS] 2.5.198.27 ; [MS-XLSB] 2.5.97.18 */
10465function parse_PtgArea(blob, length, opts) {
10466 var type = (blob[blob.l++] & 0x60) >> 5;
10467 var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
10468 return [type, area];
10469}
10470
10471/* [MS-XLS] 2.5.198.28 ; [MS-XLSB] 2.5.97.19 */
10472function parse_PtgArea3d(blob, length, opts) {
10473 var type = (blob[blob.l++] & 0x60) >> 5;
10474 var ixti = blob.read_shift(2, 'i');
10475 var w = 8;
10476 if(opts) switch(opts.biff) {
10477 case 5: blob.l += 12; w = 6; break;
10478 case 12: w = 12; break;
10479 }
10480 var area = parse_RgceArea(blob, w, opts);
10481 return [type, ixti, area];
10482}
10483
10484/* [MS-XLS] 2.5.198.29 ; [MS-XLSB] 2.5.97.20 */
10485function parse_PtgAreaErr(blob, length, opts) {
10486 var type = (blob[blob.l++] & 0x60) >> 5;
10487 blob.l += opts && (opts.biff > 8) ? 12 : (opts.biff < 8 ? 6 : 8);
10488 return [type];
10489}
10490/* [MS-XLS] 2.5.198.30 ; [MS-XLSB] 2.5.97.21 */
10491function parse_PtgAreaErr3d(blob, length, opts) {
10492 var type = (blob[blob.l++] & 0x60) >> 5;
10493 var ixti = blob.read_shift(2);
10494 var w = 8;
10495 if(opts) switch(opts.biff) {
10496 case 5: blob.l += 12; w = 6; break;
10497 case 12: w = 12; break;
10498 }
10499 blob.l += w;
10500 return [type, ixti];
10501}
10502
10503/* [MS-XLS] 2.5.198.31 ; [MS-XLSB] 2.5.97.22 */
10504function parse_PtgAreaN(blob, length, opts) {
10505 var type = (blob[blob.l++] & 0x60) >> 5;
10506 var area = parse_RgceAreaRel(blob, length - 1, opts);
10507 return [type, area];
10508}
10509
10510/* [MS-XLS] 2.5.198.32 ; [MS-XLSB] 2.5.97.23 */
10511function parse_PtgArray(blob, length, opts) {
10512 var type = (blob[blob.l++] & 0x60) >> 5;
10513 blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
10514 return [type];
10515}
10516
10517/* [MS-XLS] 2.5.198.33 ; [MS-XLSB] 2.5.97.24 */
10518function parse_PtgAttrBaxcel(blob) {
10519 var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
10520 var bitBaxcel = 1;
10521 blob.l += 4;
10522 return [bitSemi, bitBaxcel];
10523}
10524
10525/* [MS-XLS] 2.5.198.34 ; [MS-XLSB] 2.5.97.25 */
10526function parse_PtgAttrChoose(blob, length, opts) {
10527 blob.l +=2;
10528 var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10529 var o = [];
10530 /* offset is 1 less than the number of elements */
10531 for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2));
10532 return o;
10533}
10534
10535/* [MS-XLS] 2.5.198.35 ; [MS-XLSB] 2.5.97.26 */
10536function parse_PtgAttrGoto(blob, length, opts) {
10537 var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10538 blob.l += 2;
10539 return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
10540}
10541
10542/* [MS-XLS] 2.5.198.36 ; [MS-XLSB] 2.5.97.27 */
10543function parse_PtgAttrIf(blob, length, opts) {
10544 var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10545 blob.l += 2;
10546 return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
10547}
10548
10549/* [MS-XLSB] 2.5.97.28 */
10550function parse_PtgAttrIfError(blob) {
10551 var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10552 blob.l += 2;
10553 return [bitIf, blob.read_shift(2)];
10554}
10555
10556/* [MS-XLS] 2.5.198.37 ; [MS-XLSB] 2.5.97.29 */
10557function parse_PtgAttrSemi(blob, length, opts) {
10558 var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10559 blob.l += opts && opts.biff == 2 ? 3 : 4;
10560 return [bitSemi];
10561}
10562
10563/* [MS-XLS] 2.5.198.40 ; [MS-XLSB] 2.5.97.32 */
10564function parse_PtgAttrSpaceType(blob) {
10565 var type = blob.read_shift(1), cch = blob.read_shift(1);
10566 return [type, cch];
10567}
10568
10569/* [MS-XLS] 2.5.198.38 ; [MS-XLSB] 2.5.97.30 */
10570function parse_PtgAttrSpace(blob) {
10571 blob.read_shift(2);
10572 return parse_PtgAttrSpaceType(blob, 2);
10573}
10574
10575/* [MS-XLS] 2.5.198.39 ; [MS-XLSB] 2.5.97.31 */
10576function parse_PtgAttrSpaceSemi(blob) {
10577 blob.read_shift(2);
10578 return parse_PtgAttrSpaceType(blob, 2);
10579}
10580
10581/* [MS-XLS] 2.5.198.84 ; [MS-XLSB] 2.5.97.68 TODO */
10582function parse_PtgRef(blob, length, opts) {
10583 //var ptg = blob[blob.l] & 0x1F;
10584 var type = (blob[blob.l] & 0x60)>>5;
10585 blob.l += 1;
10586 var loc = parse_RgceLoc(blob, 0, opts);
10587 return [type, loc];
10588}
10589
10590/* [MS-XLS] 2.5.198.88 ; [MS-XLSB] 2.5.97.72 TODO */
10591function parse_PtgRefN(blob, length, opts) {
10592 var type = (blob[blob.l] & 0x60)>>5;
10593 blob.l += 1;
10594 var loc = parse_RgceLocRel(blob, 0, opts);
10595 return [type, loc];
10596}
10597
10598/* [MS-XLS] 2.5.198.85 ; [MS-XLSB] 2.5.97.69 TODO */
10599function parse_PtgRef3d(blob, length, opts) {
10600 var type = (blob[blob.l] & 0x60)>>5;
10601 blob.l += 1;
10602 var ixti = blob.read_shift(2); // XtiIndex
10603 if(opts && opts.biff == 5) blob.l += 12;
10604 var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
10605 return [type, ixti, loc];
10606}
10607
10608
10609/* [MS-XLS] 2.5.198.62 ; [MS-XLSB] 2.5.97.45 TODO */
10610function parse_PtgFunc(blob, length, opts) {
10611 //var ptg = blob[blob.l] & 0x1F;
10612 var type = (blob[blob.l] & 0x60)>>5;
10613 blob.l += 1;
10614 var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
10615 return [FtabArgc[iftab], Ftab[iftab], type];
10616}
10617/* [MS-XLS] 2.5.198.63 ; [MS-XLSB] 2.5.97.46 TODO */
10618function parse_PtgFuncVar(blob, length, opts) {
10619 var type = blob[blob.l++];
10620 var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [(type == 0x58 ? -1 : 0), blob.read_shift(1)]: parsetab(blob);
10621 return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
10622}
10623
10624function parsetab(blob) {
10625 return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
10626}
10627
10628/* [MS-XLS] 2.5.198.41 ; [MS-XLSB] 2.5.97.33 */
10629function parse_PtgAttrSum(blob, length, opts) {
10630 blob.l += opts && opts.biff == 2 ? 3 : 4; return;
10631}
10632
10633/* [MS-XLS] 2.5.198.58 ; [MS-XLSB] 2.5.97.40 */
10634function parse_PtgExp(blob, length, opts) {
10635 blob.l++;
10636 if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
10637 var row = blob.read_shift(2);
10638 var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10639 return [row, col];
10640}
10641
10642/* [MS-XLS] 2.5.198.57 ; [MS-XLSB] 2.5.97.39 */
10643function parse_PtgErr(blob) { blob.l++; return BErr[blob.read_shift(1)]; }
10644
10645/* [MS-XLS] 2.5.198.66 ; [MS-XLSB] 2.5.97.49 */
10646function parse_PtgInt(blob) { blob.l++; return blob.read_shift(2); }
10647
10648/* [MS-XLS] 2.5.198.42 ; [MS-XLSB] 2.5.97.34 */
10649function parse_PtgBool(blob) { blob.l++; return blob.read_shift(1)!==0;}
10650
10651/* [MS-XLS] 2.5.198.79 ; [MS-XLSB] 2.5.97.63 */
10652function parse_PtgNum(blob) { blob.l++; return parse_Xnum(blob, 8); }
10653
10654/* [MS-XLS] 2.5.198.89 ; [MS-XLSB] 2.5.97.74 */
10655function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
10656
10657/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
10658/* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */
10659function parse_SerAr(blob, biff) {
10660 var val = [blob.read_shift(1)];
10661 if(biff == 12) switch(val[0]) {
10662 case 0x02: val[0] = 0x04; break; /* SerBool */
10663 case 0x04: val[0] = 0x10; break; /* SerErr */
10664 case 0x00: val[0] = 0x01; break; /* SerNum */
10665 case 0x01: val[0] = 0x02; break; /* SerStr */
10666 }
10667 switch(val[0]) {
10668 case 0x04: /* SerBool -- boolean */
10669 val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
10670 if(biff != 12) blob.l += 7; break;
10671 case 0x25: /* appears to be an alias */
10672 case 0x10: /* SerErr -- error */
10673 val[1] = BErr[blob[blob.l]];
10674 blob.l += ((biff == 12) ? 4 : 8); break;
10675 case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
10676 blob.l += 8; break;
10677 case 0x01: /* SerNum -- Xnum */
10678 val[1] = parse_Xnum(blob, 8); break;
10679 case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
10680 val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
10681 default: throw new Error("Bad SerAr: " + val[0]); /* Unreachable */
10682 }
10683 return val;
10684}
10685
10686/* [MS-XLS] 2.5.198.61 ; [MS-XLSB] 2.5.97.44 */
10687function parse_PtgExtraMem(blob, cce, opts) {
10688 var count = blob.read_shift((opts.biff == 12) ? 4 : 2);
10689 var out = [];
10690 for(var i = 0; i != count; ++i) out.push(((opts.biff == 12) ? parse_UncheckedRfX : parse_Ref8U)(blob, 8));
10691 return out;
10692}
10693
10694/* [MS-XLS] 2.5.198.59 ; [MS-XLSB] 2.5.97.41 */
10695function parse_PtgExtraArray(blob, length, opts) {
10696 var rows = 0, cols = 0;
10697 if(opts.biff == 12) {
10698 rows = blob.read_shift(4); // DRw
10699 cols = blob.read_shift(4); // DCol
10700 } else {
10701 cols = 1 + blob.read_shift(1); //DColByteU
10702 rows = 1 + blob.read_shift(2); //DRw
10703 }
10704 if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; }
10705 // $FlowIgnore
10706 for(var i = 0, o = []; i != rows && (o[i] = []); ++i)
10707 for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff);
10708 return o;
10709}
10710
10711/* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 */
10712function parse_PtgName(blob, length, opts) {
10713 var type = (blob.read_shift(1) >>> 5) & 0x03;
10714 var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
10715 var nameindex = blob.read_shift(w);
10716 switch(opts.biff) {
10717 case 2: blob.l += 5; break;
10718 case 3: case 4: blob.l += 8; break;
10719 case 5: blob.l += 12; break;
10720 }
10721 return [type, 0, nameindex];
10722}
10723
10724/* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 */
10725function parse_PtgNameX(blob, length, opts) {
10726 if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts);
10727 var type = (blob.read_shift(1) >>> 5) & 0x03;
10728 var ixti = blob.read_shift(2); // XtiIndex
10729 var nameindex = blob.read_shift(4);
10730 return [type, ixti, nameindex];
10731}
10732function parse_PtgNameX_BIFF5(blob) {
10733 var type = (blob.read_shift(1) >>> 5) & 0x03;
10734 var ixti = blob.read_shift(2, 'i'); // XtiIndex
10735 blob.l += 8;
10736 var nameindex = blob.read_shift(2);
10737 blob.l += 12;
10738 return [type, ixti, nameindex];
10739}
10740
10741/* [MS-XLS] 2.5.198.70 ; [MS-XLSB] 2.5.97.54 */
10742function parse_PtgMemArea(blob, length, opts) {
10743 var type = (blob.read_shift(1) >>> 5) & 0x03;
10744 blob.l += (opts && opts.biff == 2 ? 3 : 4);
10745 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10746 return [type, cce];
10747}
10748
10749/* [MS-XLS] 2.5.198.72 ; [MS-XLSB] 2.5.97.56 */
10750function parse_PtgMemFunc(blob, length, opts) {
10751 var type = (blob.read_shift(1) >>> 5) & 0x03;
10752 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10753 return [type, cce];
10754}
10755
10756
10757/* [MS-XLS] 2.5.198.86 ; [MS-XLSB] 2.5.97.69 */
10758function parse_PtgRefErr(blob, length, opts) {
10759 var type = (blob.read_shift(1) >>> 5) & 0x03;
10760 blob.l += 4;
10761 if(opts.biff < 8) blob.l--;
10762 if(opts.biff == 12) blob.l += 2;
10763 return [type];
10764}
10765
10766/* [MS-XLS] 2.5.198.87 ; [MS-XLSB] 2.5.97.71 */
10767function parse_PtgRefErr3d(blob, length, opts) {
10768 var type = (blob[blob.l++] & 0x60) >> 5;
10769 var ixti = blob.read_shift(2);
10770 var w = 4;
10771 if(opts) switch(opts.biff) {
10772 case 5: w = 15; break;
10773 case 12: w = 6; break;
10774 }
10775 blob.l += w;
10776 return [type, ixti];
10777}
10778
10779/* [MS-XLS] 2.5.198.71 ; [MS-XLSB] 2.5.97.55 */
10780var parse_PtgMemErr = parsenoop;
10781/* [MS-XLS] 2.5.198.73 ; [MS-XLSB] 2.5.97.57 */
10782var parse_PtgMemNoMem = parsenoop;
10783/* [MS-XLS] 2.5.198.92 */
10784var parse_PtgTbl = parsenoop;
10785
10786function parse_PtgElfLoc(blob, length, opts) {
10787 blob.l += 2;
10788 return [parse_RgceElfLoc(blob, 4, opts)];
10789}
10790function parse_PtgElfNoop(blob) {
10791 blob.l += 6;
10792 return [];
10793}
10794/* [MS-XLS] 2.5.198.46 */
10795var parse_PtgElfCol = parse_PtgElfLoc;
10796/* [MS-XLS] 2.5.198.47 */
10797var parse_PtgElfColS = parse_PtgElfNoop;
10798/* [MS-XLS] 2.5.198.48 */
10799var parse_PtgElfColSV = parse_PtgElfNoop;
10800/* [MS-XLS] 2.5.198.49 */
10801var parse_PtgElfColV = parse_PtgElfLoc;
10802/* [MS-XLS] 2.5.198.50 */
10803function parse_PtgElfLel(blob) {
10804 blob.l += 2;
10805 return [parseuint16(blob), blob.read_shift(2) & 0x01];
10806}
10807/* [MS-XLS] 2.5.198.51 */
10808var parse_PtgElfRadical = parse_PtgElfLoc;
10809/* [MS-XLS] 2.5.198.52 */
10810var parse_PtgElfRadicalLel = parse_PtgElfLel;
10811/* [MS-XLS] 2.5.198.53 */
10812var parse_PtgElfRadicalS = parse_PtgElfNoop;
10813/* [MS-XLS] 2.5.198.54 */
10814var parse_PtgElfRw = parse_PtgElfLoc;
10815/* [MS-XLS] 2.5.198.55 */
10816var parse_PtgElfRwV = parse_PtgElfLoc;
10817
10818/* [MS-XLSB] 2.5.97.52 TODO */
10819var PtgListRT = [
10820 "Data",
10821 "All",
10822 "Headers",
10823 "??",
10824 "?Data2",
10825 "??",
10826 "?DataHeaders",
10827 "??",
10828 "Totals",
10829 "??",
10830 "??",
10831 "??",
10832 "?DataTotals",
10833 "??",
10834 "??",
10835 "??",
10836 "?Current"
10837];
10838function parse_PtgList(blob) {
10839 blob.l += 2;
10840 var ixti = blob.read_shift(2);
10841 var flags = blob.read_shift(2);
10842 var idx = blob.read_shift(4);
10843 var c = blob.read_shift(2);
10844 var C = blob.read_shift(2);
10845 var rt = PtgListRT[(flags >> 2) & 0x1F];
10846 return {ixti: ixti, coltype:(flags&0x3), rt:rt, idx:idx, c:c, C:C};
10847}
10848/* [MS-XLS] 2.5.198.91 ; [MS-XLSB] 2.5.97.76 */
10849function parse_PtgSxName(blob) {
10850 blob.l += 2;
10851 return [blob.read_shift(4)];
10852}
10853
10854/* [XLS] old spec */
10855function parse_PtgSheet(blob, length, opts) {
10856 blob.l += 5;
10857 blob.l += 2;
10858 blob.l += (opts.biff == 2 ? 1 : 4);
10859 return ["PTGSHEET"];
10860}
10861function parse_PtgEndSheet(blob, length, opts) {
10862 blob.l += (opts.biff == 2 ? 4 : 5);
10863 return ["PTGENDSHEET"];
10864}
10865function parse_PtgMemAreaN(blob) {
10866 var type = (blob.read_shift(1) >>> 5) & 0x03;
10867 var cce = blob.read_shift(2);
10868 return [type, cce];
10869}
10870function parse_PtgMemNoMemN(blob) {
10871 var type = (blob.read_shift(1) >>> 5) & 0x03;
10872 var cce = blob.read_shift(2);
10873 return [type, cce];
10874}
10875function parse_PtgAttrNoop(blob) {
10876 blob.l += 4;
10877 return [0, 0];
10878}
10879
10880/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
10881var PtgTypes = {
108820x01: { n:'PtgExp', f:parse_PtgExp },
108830x02: { n:'PtgTbl', f:parse_PtgTbl },
108840x03: { n:'PtgAdd', f:parseread1 },
108850x04: { n:'PtgSub', f:parseread1 },
108860x05: { n:'PtgMul', f:parseread1 },
108870x06: { n:'PtgDiv', f:parseread1 },
108880x07: { n:'PtgPower', f:parseread1 },
108890x08: { n:'PtgConcat', f:parseread1 },
108900x09: { n:'PtgLt', f:parseread1 },
108910x0A: { n:'PtgLe', f:parseread1 },
108920x0B: { n:'PtgEq', f:parseread1 },
108930x0C: { n:'PtgGe', f:parseread1 },
108940x0D: { n:'PtgGt', f:parseread1 },
108950x0E: { n:'PtgNe', f:parseread1 },
108960x0F: { n:'PtgIsect', f:parseread1 },
108970x10: { n:'PtgUnion', f:parseread1 },
108980x11: { n:'PtgRange', f:parseread1 },
108990x12: { n:'PtgUplus', f:parseread1 },
109000x13: { n:'PtgUminus', f:parseread1 },
109010x14: { n:'PtgPercent', f:parseread1 },
109020x15: { n:'PtgParen', f:parseread1 },
109030x16: { n:'PtgMissArg', f:parseread1 },
109040x17: { n:'PtgStr', f:parse_PtgStr },
109050x1A: { n:'PtgSheet', f:parse_PtgSheet },
109060x1B: { n:'PtgEndSheet', f:parse_PtgEndSheet },
109070x1C: { n:'PtgErr', f:parse_PtgErr },
109080x1D: { n:'PtgBool', f:parse_PtgBool },
109090x1E: { n:'PtgInt', f:parse_PtgInt },
109100x1F: { n:'PtgNum', f:parse_PtgNum },
109110x20: { n:'PtgArray', f:parse_PtgArray },
109120x21: { n:'PtgFunc', f:parse_PtgFunc },
109130x22: { n:'PtgFuncVar', f:parse_PtgFuncVar },
109140x23: { n:'PtgName', f:parse_PtgName },
109150x24: { n:'PtgRef', f:parse_PtgRef },
109160x25: { n:'PtgArea', f:parse_PtgArea },
109170x26: { n:'PtgMemArea', f:parse_PtgMemArea },
109180x27: { n:'PtgMemErr', f:parse_PtgMemErr },
109190x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
109200x29: { n:'PtgMemFunc', f:parse_PtgMemFunc },
109210x2A: { n:'PtgRefErr', f:parse_PtgRefErr },
109220x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr },
109230x2C: { n:'PtgRefN', f:parse_PtgRefN },
109240x2D: { n:'PtgAreaN', f:parse_PtgAreaN },
109250x2E: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
109260x2F: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
109270x39: { n:'PtgNameX', f:parse_PtgNameX },
109280x3A: { n:'PtgRef3d', f:parse_PtgRef3d },
109290x3B: { n:'PtgArea3d', f:parse_PtgArea3d },
109300x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
109310x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
109320xFF: {}
10933};
10934/* These are duplicated in the PtgTypes table */
10935var PtgDupes = {
109360x40: 0x20, 0x60: 0x20,
109370x41: 0x21, 0x61: 0x21,
109380x42: 0x22, 0x62: 0x22,
109390x43: 0x23, 0x63: 0x23,
109400x44: 0x24, 0x64: 0x24,
109410x45: 0x25, 0x65: 0x25,
109420x46: 0x26, 0x66: 0x26,
109430x47: 0x27, 0x67: 0x27,
109440x48: 0x28, 0x68: 0x28,
109450x49: 0x29, 0x69: 0x29,
109460x4A: 0x2A, 0x6A: 0x2A,
109470x4B: 0x2B, 0x6B: 0x2B,
109480x4C: 0x2C, 0x6C: 0x2C,
109490x4D: 0x2D, 0x6D: 0x2D,
109500x4E: 0x2E, 0x6E: 0x2E,
109510x4F: 0x2F, 0x6F: 0x2F,
109520x58: 0x22, 0x78: 0x22,
109530x59: 0x39, 0x79: 0x39,
109540x5A: 0x3A, 0x7A: 0x3A,
109550x5B: 0x3B, 0x7B: 0x3B,
109560x5C: 0x3C, 0x7C: 0x3C,
109570x5D: 0x3D, 0x7D: 0x3D
10958};
10959(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
10960
10961var Ptg18 = {
109620x01: { n:'PtgElfLel', f:parse_PtgElfLel },
109630x02: { n:'PtgElfRw', f:parse_PtgElfRw },
109640x03: { n:'PtgElfCol', f:parse_PtgElfCol },
109650x06: { n:'PtgElfRwV', f:parse_PtgElfRwV },
109660x07: { n:'PtgElfColV', f:parse_PtgElfColV },
109670x0A: { n:'PtgElfRadical', f:parse_PtgElfRadical },
109680x0B: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
109690x0D: { n:'PtgElfColS', f:parse_PtgElfColS },
109700x0F: { n:'PtgElfColSV', f:parse_PtgElfColSV },
109710x10: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
109720x19: { n:'PtgList', f:parse_PtgList },
109730x1D: { n:'PtgSxName', f:parse_PtgSxName },
109740xFF: {}
10975};
10976var Ptg19 = {
109770x00: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
109780x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
109790x02: { n:'PtgAttrIf', f:parse_PtgAttrIf },
109800x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
109810x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
109820x10: { n:'PtgAttrSum', f:parse_PtgAttrSum },
109830x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
109840x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
109850x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
109860x80: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
109870xFF: {}
10988};
10989Ptg19[0x21] = Ptg19[0x20];
10990
10991/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
10992function parse_RgbExtra(blob, length, rgce, opts) {
10993 if(opts.biff < 8) return parsenoop(blob, length);
10994 var target = blob.l + length;
10995 var o = [];
10996 for(var i = 0; i !== rgce.length; ++i) {
10997 switch(rgce[i][0]) {
10998 case 'PtgArray': /* PtgArray -> PtgExtraArray */
10999 rgce[i][1] = parse_PtgExtraArray(blob, 0, opts);
11000 o.push(rgce[i][1]);
11001 break;
11002 case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
11003 rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1], opts);
11004 o.push(rgce[i][2]);
11005 break;
11006 case 'PtgExp': /* PtgExp -> PtgExtraCol */
11007 if(opts && opts.biff == 12) {
11008 rgce[i][1][1] = blob.read_shift(4);
11009 o.push(rgce[i][1]);
11010 } break;
11011 case 'PtgList': /* TODO: PtgList -> PtgExtraList */
11012 case 'PtgElfRadicalS': /* TODO: PtgElfRadicalS -> PtgExtraElf */
11013 case 'PtgElfColS': /* TODO: PtgElfColS -> PtgExtraElf */
11014 case 'PtgElfColSV': /* TODO: PtgElfColSV -> PtgExtraElf */
11015 throw "Unsupported " + rgce[i][0];
11016 default: break;
11017 }
11018 }
11019 length = target - blob.l;
11020 /* note: this is technically an error but Excel disregards */
11021 //if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
11022 if(length !== 0) o.push(parsenoop(blob, length));
11023 return o;
11024}
11025
11026/* [MS-XLS] 2.5.198.104 ; [MS-XLSB] 2.5.97.88 */
11027function parse_Rgce(blob, length, opts) {
11028 var target = blob.l + length;
11029 var R, id, ptgs = [];
11030 while(target != blob.l) {
11031 length = target - blob.l;
11032 id = blob[blob.l];
11033 R = PtgTypes[id];
11034 if(id === 0x18 || id === 0x19) R = (id === 0x18 ? Ptg18 : Ptg19)[blob[blob.l + 1]];
11035 if(!R || !R.f) { /*ptgs.push*/(parsenoop(blob, length)); }
11036 else { ptgs.push([R.n, R.f(blob, length, opts)]); }
11037 }
11038 return ptgs;
11039}
11040
11041function stringify_array(f) {
11042 var o = [];
11043 for(var i = 0; i < f.length; ++i) {
11044 var x = f[i], r = [];
11045 for(var j = 0; j < x.length; ++j) {
11046 var y = x[j];
11047 if(y) switch(y[0]) {
11048 // TODO: handle embedded quotes
11049 case 0x02:
11050r.push('"' + y[1].replace(/"/g,'""') + '"'); break;
11051 default: r.push(y[1]);
11052 } else r.push("");
11053 }
11054 o.push(r.join(","));
11055 }
11056 return o.join(";");
11057}
11058
11059/* [MS-XLS] 2.2.2 ; [MS-XLSB] 2.2.2 TODO */
11060var PtgBinOp = {
11061 PtgAdd: "+",
11062 PtgConcat: "&",
11063 PtgDiv: "/",
11064 PtgEq: "=",
11065 PtgGe: ">=",
11066 PtgGt: ">",
11067 PtgLe: "<=",
11068 PtgLt: "<",
11069 PtgMul: "*",
11070 PtgNe: "<>",
11071 PtgPower: "^",
11072 PtgSub: "-"
11073};
11074function formula_quote_sheet_name(sname, opts) {
11075 if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name");
11076 if(sname.indexOf(" ") > -1) return "'" + sname + "'";
11077 return sname;
11078}
11079function get_ixti_raw(supbooks, ixti, opts) {
11080 if(!supbooks) return "SH33TJSERR0";
11081 if(opts.biff > 8 && (!supbooks.XTI || !supbooks.XTI[ixti])) return supbooks.SheetNames[ixti];
11082 if(!supbooks.XTI) return "SH33TJSERR6";
11083 var XTI = supbooks.XTI[ixti];
11084 if(opts.biff < 8) {
11085 if(ixti > 10000) ixti-= 65536;
11086 if(ixti < 0) ixti = -ixti;
11087 return ixti == 0 ? "" : supbooks.XTI[ixti - 1];
11088 }
11089 if(!XTI) return "SH33TJSERR1";
11090 var o = "";
11091 if(opts.biff > 8) switch(supbooks[XTI[0]][0]) {
11092 case 0x0165: /* 'BrtSupSelf' */
11093 o = XTI[1] == -1 ? "#REF" : supbooks.SheetNames[XTI[1]];
11094 return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
11095 case 0x0166: /* 'BrtSupSame' */
11096 if(opts.SID != null) return supbooks.SheetNames[opts.SID];
11097 return "SH33TJSSAME" + supbooks[XTI[0]][0];
11098 case 0x0163: /* 'BrtSupBookSrc' */
11099 /* falls through */
11100 default: return "SH33TJSSRC" + supbooks[XTI[0]][0];
11101 }
11102 switch(supbooks[XTI[0]][0][0]) {
11103 case 0x0401:
11104 o = XTI[1] == -1 ? "#REF" : (supbooks.SheetNames[XTI[1]] || "SH33TJSERR3");
11105 return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
11106 case 0x3A01: return supbooks[XTI[0]].slice(1).map(function(name) { return name.Name; }).join(";;"); //return "SH33TJSERR8";
11107 default:
11108 if(!supbooks[XTI[0]][0][3]) return "SH33TJSERR2";
11109 o = XTI[1] == -1 ? "#REF" : (supbooks[XTI[0]][0][3][XTI[1]] || "SH33TJSERR4");
11110 return XTI[1] == XTI[2] ? o : o + ":" + supbooks[XTI[0]][0][3][XTI[2]];
11111 }
11112}
11113function get_ixti(supbooks, ixti, opts) {
11114 return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts), opts);
11115}
11116function stringify_formula(formula/*Array<any>*/, range, cell, supbooks, opts) {
11117 var biff = (opts && opts.biff) || 8;
11118 var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
11119 var stack = [], e1, e2, c, ixti=0, nameidx=0, r, sname="";
11120 if(!formula[0] || !formula[0][0]) return "";
11121 var last_sp = -1, sp = "";
11122 for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
11123 var f = formula[0][ff];
11124 switch(f[0]) {
11125 case 'PtgUminus': /* [MS-XLS] 2.5.198.93 */
11126 stack.push("-" + stack.pop()); break;
11127 case 'PtgUplus': /* [MS-XLS] 2.5.198.95 */
11128 stack.push("+" + stack.pop()); break;
11129 case 'PtgPercent': /* [MS-XLS] 2.5.198.81 */
11130 stack.push(stack.pop() + "%"); break;
11131
11132 case 'PtgAdd': /* [MS-XLS] 2.5.198.26 */
11133 case 'PtgConcat': /* [MS-XLS] 2.5.198.43 */
11134 case 'PtgDiv': /* [MS-XLS] 2.5.198.45 */
11135 case 'PtgEq': /* [MS-XLS] 2.5.198.56 */
11136 case 'PtgGe': /* [MS-XLS] 2.5.198.64 */
11137 case 'PtgGt': /* [MS-XLS] 2.5.198.65 */
11138 case 'PtgLe': /* [MS-XLS] 2.5.198.68 */
11139 case 'PtgLt': /* [MS-XLS] 2.5.198.69 */
11140 case 'PtgMul': /* [MS-XLS] 2.5.198.75 */
11141 case 'PtgNe': /* [MS-XLS] 2.5.198.78 */
11142 case 'PtgPower': /* [MS-XLS] 2.5.198.82 */
11143 case 'PtgSub': /* [MS-XLS] 2.5.198.90 */
11144 e1 = stack.pop(); e2 = stack.pop();
11145 if(last_sp >= 0) {
11146 switch(formula[0][last_sp][1][0]) {
11147 case 0:
11148 // $FlowIgnore
11149 sp = fill(" ", formula[0][last_sp][1][1]); break;
11150 case 1:
11151 // $FlowIgnore
11152 sp = fill("\r", formula[0][last_sp][1][1]); break;
11153 default:
11154 sp = "";
11155 // $FlowIgnore
11156 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
11157 }
11158 e2 = e2 + sp;
11159 last_sp = -1;
11160 }
11161 stack.push(e2+PtgBinOp[f[0]]+e1);
11162 break;
11163
11164 case 'PtgIsect': /* [MS-XLS] 2.5.198.67 */
11165 e1 = stack.pop(); e2 = stack.pop();
11166 stack.push(e2+" "+e1);
11167 break;
11168 case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
11169 e1 = stack.pop(); e2 = stack.pop();
11170 stack.push(e2+","+e1);
11171 break;
11172 case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
11173 e1 = stack.pop(); e2 = stack.pop();
11174 stack.push(e2+":"+e1);
11175 break;
11176
11177 case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */
11178 break;
11179 case 'PtgAttrGoto': /* [MS-XLS] 2.5.198.35 */
11180 break;
11181 case 'PtgAttrIf': /* [MS-XLS] 2.5.198.36 */
11182 break;
11183 case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
11184 break;
11185
11186
11187 case 'PtgRef': /* [MS-XLS] 2.5.198.84 */
11188c = shift_cell_xls((f[1][1]), _range, opts);
11189 stack.push(encode_cell_xls(c, biff));
11190 break;
11191 case 'PtgRefN': /* [MS-XLS] 2.5.198.88 */
11192c = cell ? shift_cell_xls((f[1][1]), cell, opts) : (f[1][1]);
11193 stack.push(encode_cell_xls(c, biff));
11194 break;
11195 case 'PtgRef3d': /* [MS-XLS] 2.5.198.85 */
11196ixti = f[1][1]; c = shift_cell_xls((f[1][2]), _range, opts);
11197 sname = get_ixti(supbooks, ixti, opts);
11198 var w = sname; /* IE9 fails on defined names */ // eslint-disable-line no-unused-vars
11199 stack.push(sname + "!" + encode_cell_xls(c, biff));
11200 break;
11201
11202 case 'PtgFunc': /* [MS-XLS] 2.5.198.62 */
11203 case 'PtgFuncVar': /* [MS-XLS] 2.5.198.63 */
11204 /* f[1] = [argc, func, type] */
11205 var argc = (f[1][0]), func = (f[1][1]);
11206 if(!argc) argc = 0;
11207 argc &= 0x7F;
11208 var args = argc == 0 ? [] : stack.slice(-argc);
11209 stack.length -= argc;
11210 if(func === 'User') func = args.shift();
11211 stack.push(func + "(" + args.join(",") + ")");
11212 break;
11213
11214 case 'PtgBool': /* [MS-XLS] 2.5.198.42 */
11215 stack.push(f[1] ? "TRUE" : "FALSE"); break;
11216 case 'PtgInt': /* [MS-XLS] 2.5.198.66 */
11217 stack.push(f[1]); break;
11218 case 'PtgNum': /* [MS-XLS] 2.5.198.79 TODO: precision? */
11219 stack.push(String(f[1])); break;
11220 case 'PtgStr': /* [MS-XLS] 2.5.198.89 */
11221 // $FlowIgnore
11222 stack.push('"' + f[1].replace(/"/g, '""') + '"'); break;
11223 case 'PtgErr': /* [MS-XLS] 2.5.198.57 */
11224 stack.push(f[1]); break;
11225 case 'PtgAreaN': /* [MS-XLS] 2.5.198.31 TODO */
11226r = shift_range_xls(f[1][1], cell ? {s:cell} : _range, opts);
11227 stack.push(encode_range_xls((r), opts));
11228 break;
11229 case 'PtgArea': /* [MS-XLS] 2.5.198.27 TODO: fixed points */
11230r = shift_range_xls(f[1][1], _range, opts);
11231 stack.push(encode_range_xls((r), opts));
11232 break;
11233 case 'PtgArea3d': /* [MS-XLS] 2.5.198.28 TODO */
11234ixti = f[1][1]; r = f[1][2];
11235 sname = get_ixti(supbooks, ixti, opts);
11236 stack.push(sname + "!" + encode_range_xls((r), opts));
11237 break;
11238 case 'PtgAttrSum': /* [MS-XLS] 2.5.198.41 */
11239 stack.push("SUM(" + stack.pop() + ")");
11240 break;
11241
11242 case 'PtgAttrBaxcel': /* [MS-XLS] 2.5.198.33 */
11243 case 'PtgAttrSemi': /* [MS-XLS] 2.5.198.37 */
11244 break;
11245
11246 case 'PtgName': /* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 TODO: revisions */
11247 /* f[1] = type, 0, nameindex */
11248 nameidx = (f[1][2]);
11249 var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
11250 var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
11251 if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
11252 stack.push(name);
11253 break;
11254
11255 case 'PtgNameX': /* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 TODO: revisions */
11256 /* f[1] = type, ixti, nameindex */
11257 var bookidx = (f[1][1]); nameidx = (f[1][2]); var externbook;
11258 /* TODO: Properly handle missing values -- this should be using get_ixti_raw primarily */
11259 if(opts.biff <= 5) {
11260 if(bookidx < 0) bookidx = -bookidx;
11261 if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
11262 } else {
11263 var o = "";
11264 if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){/* empty */}
11265 else if(((supbooks[bookidx]||[])[0]||[])[0] == 0x0401){
11266 if(supbooks[bookidx][nameidx] && supbooks[bookidx][nameidx].itab > 0) {
11267 o = supbooks.SheetNames[supbooks[bookidx][nameidx].itab-1] + "!";
11268 }
11269 }
11270 else o = supbooks.SheetNames[nameidx-1]+ "!";
11271 if(supbooks[bookidx] && supbooks[bookidx][nameidx]) o += supbooks[bookidx][nameidx].Name;
11272 else if(supbooks[0] && supbooks[0][nameidx]) o += supbooks[0][nameidx].Name;
11273 else {
11274 var ixtidata = get_ixti_raw(supbooks, bookidx, opts).split(";;");
11275 if(ixtidata[nameidx - 1]) o = ixtidata[nameidx - 1]; // TODO: confirm this is correct
11276 else o += "SH33TJSERRX";
11277 }
11278 stack.push(o);
11279 break;
11280 }
11281 if(!externbook) externbook = {Name: "SH33TJSERRY"};
11282 stack.push(externbook.Name);
11283 break;
11284
11285 case 'PtgParen': /* [MS-XLS] 2.5.198.80 */
11286 var lp = '(', rp = ')';
11287 if(last_sp >= 0) {
11288 sp = "";
11289 switch(formula[0][last_sp][1][0]) {
11290 // $FlowIgnore
11291 case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
11292 // $FlowIgnore
11293 case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
11294 // $FlowIgnore
11295 case 4: rp = fill(" ", formula[0][last_sp][1][1]) + rp; break;
11296 // $FlowIgnore
11297 case 5: rp = fill("\r", formula[0][last_sp][1][1]) + rp; break;
11298 default:
11299 // $FlowIgnore
11300 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
11301 }
11302 last_sp = -1;
11303 }
11304 stack.push(lp + stack.pop() + rp); break;
11305
11306 case 'PtgRefErr': /* [MS-XLS] 2.5.198.86 */
11307 stack.push('#REF!'); break;
11308
11309 case 'PtgRefErr3d': /* [MS-XLS] 2.5.198.87 */
11310 stack.push('#REF!'); break;
11311
11312 case 'PtgExp': /* [MS-XLS] 2.5.198.58 TODO */
11313 c = {c:(f[1][1]),r:(f[1][0])};
11314 var q = ({c: cell.c, r:cell.r});
11315 if(supbooks.sharedf[encode_cell(c)]) {
11316 var parsedf = (supbooks.sharedf[encode_cell(c)]);
11317 stack.push(stringify_formula(parsedf, _range, q, supbooks, opts));
11318 }
11319 else {
11320 var fnd = false;
11321 for(e1=0;e1!=supbooks.arrayf.length; ++e1) {
11322 /* TODO: should be something like range_has */
11323 e2 = supbooks.arrayf[e1];
11324 if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
11325 if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
11326 stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
11327 fnd = true;
11328 break;
11329 }
11330 if(!fnd) stack.push(f[1]);
11331 }
11332 break;
11333
11334 case 'PtgArray': /* [MS-XLS] 2.5.198.32 TODO */
11335 stack.push("{" + stringify_array(f[1]) + "}");
11336 break;
11337
11338 case 'PtgMemArea': /* [MS-XLS] 2.5.198.70 TODO: confirm this is a non-display */
11339 //stack.push("(" + f[2].map(encode_range).join(",") + ")");
11340 break;
11341
11342 case 'PtgAttrSpace': /* [MS-XLS] 2.5.198.38 */
11343 case 'PtgAttrSpaceSemi': /* [MS-XLS] 2.5.198.39 */
11344 last_sp = ff;
11345 break;
11346
11347 case 'PtgTbl': /* [MS-XLS] 2.5.198.92 TODO */
11348 break;
11349
11350 case 'PtgMemErr': /* [MS-XLS] 2.5.198.71 */
11351 break;
11352
11353 case 'PtgMissArg': /* [MS-XLS] 2.5.198.74 */
11354 stack.push("");
11355 break;
11356
11357 case 'PtgAreaErr': /* [MS-XLS] 2.5.198.29 */
11358 stack.push("#REF!"); break;
11359
11360 case 'PtgAreaErr3d': /* [MS-XLS] 2.5.198.30 */
11361 stack.push("#REF!"); break;
11362
11363 case 'PtgList': /* [MS-XLSB] 2.5.97.52 */
11364 // $FlowIgnore
11365 stack.push("Table" + f[1].idx + "[#" + f[1].rt + "]");
11366 break;
11367
11368 case 'PtgMemAreaN':
11369 case 'PtgMemNoMemN':
11370 case 'PtgAttrNoop':
11371 case 'PtgSheet':
11372 case 'PtgEndSheet':
11373 break;
11374
11375 case 'PtgMemFunc': /* [MS-XLS] 2.5.198.72 TODO */
11376 break;
11377 case 'PtgMemNoMem': /* [MS-XLS] 2.5.198.73 TODO */
11378 break;
11379
11380 case 'PtgElfCol': /* [MS-XLS] 2.5.198.46 */
11381 case 'PtgElfColS': /* [MS-XLS] 2.5.198.47 */
11382 case 'PtgElfColSV': /* [MS-XLS] 2.5.198.48 */
11383 case 'PtgElfColV': /* [MS-XLS] 2.5.198.49 */
11384 case 'PtgElfLel': /* [MS-XLS] 2.5.198.50 */
11385 case 'PtgElfRadical': /* [MS-XLS] 2.5.198.51 */
11386 case 'PtgElfRadicalLel': /* [MS-XLS] 2.5.198.52 */
11387 case 'PtgElfRadicalS': /* [MS-XLS] 2.5.198.53 */
11388 case 'PtgElfRw': /* [MS-XLS] 2.5.198.54 */
11389 case 'PtgElfRwV': /* [MS-XLS] 2.5.198.55 */
11390 throw new Error("Unsupported ELFs");
11391
11392 case 'PtgSxName': /* [MS-XLS] 2.5.198.91 TODO -- find a test case */
11393 throw new Error('Unrecognized Formula Token: ' + String(f));
11394 default: throw new Error('Unrecognized Formula Token: ' + String(f));
11395 }
11396 var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto'];
11397 if(opts.biff != 3) if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) {
11398 f = formula[0][last_sp];
11399 var _left = true;
11400 switch(f[1][0]) {
11401 /* note: some bad XLSB files omit the PtgParen */
11402 case 4: _left = false;
11403 /* falls through */
11404 case 0:
11405 // $FlowIgnore
11406 sp = fill(" ", f[1][1]); break;
11407 case 5: _left = false;
11408 /* falls through */
11409 case 1:
11410 // $FlowIgnore
11411 sp = fill("\r", f[1][1]); break;
11412 default:
11413 sp = "";
11414 // $FlowIgnore
11415 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + f[1][0]);
11416 }
11417 stack.push((_left ? sp : "") + stack.pop() + (_left ? "" : sp));
11418 last_sp = -1;
11419 }
11420 }
11421 if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
11422 return stack[0];
11423}
11424
11425/* [MS-XLS] 2.5.198.1 TODO */
11426function parse_ArrayParsedFormula(blob, length, opts) {
11427 var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
11428 var rgcb, cce = blob.read_shift(len); // length of rgce
11429 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11430 var rgce = parse_Rgce(blob, cce, opts);
11431 if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
11432 blob.l = target;
11433 return [rgce, rgcb];
11434}
11435
11436/* [MS-XLS] 2.5.198.3 TODO */
11437function parse_XLSCellParsedFormula(blob, length, opts) {
11438 var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
11439 var rgcb, cce = blob.read_shift(len); // length of rgce
11440 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11441 var rgce = parse_Rgce(blob, cce, opts);
11442 if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
11443 blob.l = target;
11444 return [rgce, rgcb];
11445}
11446
11447/* [MS-XLS] 2.5.198.21 */
11448function parse_NameParsedFormula(blob, length, opts, cce) {
11449 var target = blob.l + length;
11450 var rgce = parse_Rgce(blob, cce, opts);
11451 var rgcb;
11452 if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
11453 return [rgce, rgcb];
11454}
11455
11456/* [MS-XLS] 2.5.198.118 TODO */
11457function parse_SharedParsedFormula(blob, length, opts) {
11458 var target = blob.l + length;
11459 var rgcb, cce = blob.read_shift(2); // length of rgce
11460 var rgce = parse_Rgce(blob, cce, opts);
11461 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11462 if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
11463 return [rgce, rgcb];
11464}
11465
11466/* [MS-XLS] 2.5.133 TODO: how to emit empty strings? */
11467function parse_FormulaValue(blob) {
11468 var b;
11469 if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
11470 switch(blob[blob.l]) {
11471 case 0x00: blob.l += 8; return ["String", 's'];
11472 case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
11473 case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
11474 case 0x03: blob.l += 8; return ["",'s'];
11475 }
11476 return [];
11477}
11478function write_FormulaValue(value) {
11479 if(value == null) {
11480 // Blank String Value
11481 var o = new_buf(8);
11482 o.write_shift(1, 0x03);
11483 o.write_shift(1, 0);
11484 o.write_shift(2, 0);
11485 o.write_shift(2, 0);
11486 o.write_shift(2, 0xFFFF);
11487 return o;
11488 } else if(typeof value == "number") return write_Xnum(value);
11489 return write_Xnum(0);
11490}
11491
11492/* [MS-XLS] 2.4.127 TODO */
11493function parse_Formula(blob, length, opts) {
11494 var end = blob.l + length;
11495 var cell = parse_XLSCell(blob, 6);
11496 if(opts.biff == 2) ++blob.l;
11497 var val = parse_FormulaValue(blob,8);
11498 var flags = blob.read_shift(1);
11499 if(opts.biff != 2) {
11500 blob.read_shift(1);
11501 if(opts.biff >= 5) {
11502 /*var chn = */blob.read_shift(4);
11503 }
11504 }
11505 var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
11506 return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
11507}
11508function write_Formula(cell, R, C, opts, os) {
11509 // Cell
11510 var o1 = write_XLSCell(R, C, os);
11511
11512 // FormulaValue
11513 var o2 = write_FormulaValue(cell.v);
11514
11515 // flags + cache
11516 var o3 = new_buf(6);
11517 var flags = 0x01 | 0x20;
11518 o3.write_shift(2, flags);
11519 o3.write_shift(4, 0);
11520
11521 // CellParsedFormula
11522 var bf = new_buf(cell.bf.length);
11523 for(var i = 0; i < cell.bf.length; ++i) bf[i] = cell.bf[i];
11524
11525 var out = bconcat([o1, o2, o3, bf]);
11526 return out;
11527}
11528
11529
11530/* XLSB Parsed Formula records have the same shape */
11531function parse_XLSBParsedFormula(data, length, opts) {
11532 var cce = data.read_shift(4);
11533 var rgce = parse_Rgce(data, cce, opts);
11534 var cb = data.read_shift(4);
11535 var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null;
11536 return [rgce, rgcb];
11537}
11538
11539/* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */
11540var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula;
11541/* [MS-XLSB] 2.5.97.4 CellParsedFormula */
11542var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula;
11543/* [MS-XLSB] 2.5.97.8 DVParsedFormula */
11544//var parse_XLSBDVParsedFormula = parse_XLSBParsedFormula;
11545/* [MS-XLSB] 2.5.97.9 FRTParsedFormula */
11546//var parse_XLSBFRTParsedFormula = parse_XLSBParsedFormula2;
11547/* [MS-XLSB] 2.5.97.12 NameParsedFormula */
11548var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula;
11549/* [MS-XLSB] 2.5.97.98 SharedParsedFormula */
11550var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula;
11551/* [MS-XLS] 2.5.198.4 */
11552var Cetab = {
115530x0000: 'BEEP',
115540x0001: 'OPEN',
115550x0002: 'OPEN.LINKS',
115560x0003: 'CLOSE.ALL',
115570x0004: 'SAVE',
115580x0005: 'SAVE.AS',
115590x0006: 'FILE.DELETE',
115600x0007: 'PAGE.SETUP',
115610x0008: 'PRINT',
115620x0009: 'PRINTER.SETUP',
115630x000A: 'QUIT',
115640x000B: 'NEW.WINDOW',
115650x000C: 'ARRANGE.ALL',
115660x000D: 'WINDOW.SIZE',
115670x000E: 'WINDOW.MOVE',
115680x000F: 'FULL',
115690x0010: 'CLOSE',
115700x0011: 'RUN',
115710x0016: 'SET.PRINT.AREA',
115720x0017: 'SET.PRINT.TITLES',
115730x0018: 'SET.PAGE.BREAK',
115740x0019: 'REMOVE.PAGE.BREAK',
115750x001A: 'FONT',
115760x001B: 'DISPLAY',
115770x001C: 'PROTECT.DOCUMENT',
115780x001D: 'PRECISION',
115790x001E: 'A1.R1C1',
115800x001F: 'CALCULATE.NOW',
115810x0020: 'CALCULATION',
115820x0022: 'DATA.FIND',
115830x0023: 'EXTRACT',
115840x0024: 'DATA.DELETE',
115850x0025: 'SET.DATABASE',
115860x0026: 'SET.CRITERIA',
115870x0027: 'SORT',
115880x0028: 'DATA.SERIES',
115890x0029: 'TABLE',
115900x002A: 'FORMAT.NUMBER',
115910x002B: 'ALIGNMENT',
115920x002C: 'STYLE',
115930x002D: 'BORDER',
115940x002E: 'CELL.PROTECTION',
115950x002F: 'COLUMN.WIDTH',
115960x0030: 'UNDO',
115970x0031: 'CUT',
115980x0032: 'COPY',
115990x0033: 'PASTE',
116000x0034: 'CLEAR',
116010x0035: 'PASTE.SPECIAL',
116020x0036: 'EDIT.DELETE',
116030x0037: 'INSERT',
116040x0038: 'FILL.RIGHT',
116050x0039: 'FILL.DOWN',
116060x003D: 'DEFINE.NAME',
116070x003E: 'CREATE.NAMES',
116080x003F: 'FORMULA.GOTO',
116090x0040: 'FORMULA.FIND',
116100x0041: 'SELECT.LAST.CELL',
116110x0042: 'SHOW.ACTIVE.CELL',
116120x0043: 'GALLERY.AREA',
116130x0044: 'GALLERY.BAR',
116140x0045: 'GALLERY.COLUMN',
116150x0046: 'GALLERY.LINE',
116160x0047: 'GALLERY.PIE',
116170x0048: 'GALLERY.SCATTER',
116180x0049: 'COMBINATION',
116190x004A: 'PREFERRED',
116200x004B: 'ADD.OVERLAY',
116210x004C: 'GRIDLINES',
116220x004D: 'SET.PREFERRED',
116230x004E: 'AXES',
116240x004F: 'LEGEND',
116250x0050: 'ATTACH.TEXT',
116260x0051: 'ADD.ARROW',
116270x0052: 'SELECT.CHART',
116280x0053: 'SELECT.PLOT.AREA',
116290x0054: 'PATTERNS',
116300x0055: 'MAIN.CHART',
116310x0056: 'OVERLAY',
116320x0057: 'SCALE',
116330x0058: 'FORMAT.LEGEND',
116340x0059: 'FORMAT.TEXT',
116350x005A: 'EDIT.REPEAT',
116360x005B: 'PARSE',
116370x005C: 'JUSTIFY',
116380x005D: 'HIDE',
116390x005E: 'UNHIDE',
116400x005F: 'WORKSPACE',
116410x0060: 'FORMULA',
116420x0061: 'FORMULA.FILL',
116430x0062: 'FORMULA.ARRAY',
116440x0063: 'DATA.FIND.NEXT',
116450x0064: 'DATA.FIND.PREV',
116460x0065: 'FORMULA.FIND.NEXT',
116470x0066: 'FORMULA.FIND.PREV',
116480x0067: 'ACTIVATE',
116490x0068: 'ACTIVATE.NEXT',
116500x0069: 'ACTIVATE.PREV',
116510x006A: 'UNLOCKED.NEXT',
116520x006B: 'UNLOCKED.PREV',
116530x006C: 'COPY.PICTURE',
116540x006D: 'SELECT',
116550x006E: 'DELETE.NAME',
116560x006F: 'DELETE.FORMAT',
116570x0070: 'VLINE',
116580x0071: 'HLINE',
116590x0072: 'VPAGE',
116600x0073: 'HPAGE',
116610x0074: 'VSCROLL',
116620x0075: 'HSCROLL',
116630x0076: 'ALERT',
116640x0077: 'NEW',
116650x0078: 'CANCEL.COPY',
116660x0079: 'SHOW.CLIPBOARD',
116670x007A: 'MESSAGE',
116680x007C: 'PASTE.LINK',
116690x007D: 'APP.ACTIVATE',
116700x007E: 'DELETE.ARROW',
116710x007F: 'ROW.HEIGHT',
116720x0080: 'FORMAT.MOVE',
116730x0081: 'FORMAT.SIZE',
116740x0082: 'FORMULA.REPLACE',
116750x0083: 'SEND.KEYS',
116760x0084: 'SELECT.SPECIAL',
116770x0085: 'APPLY.NAMES',
116780x0086: 'REPLACE.FONT',
116790x0087: 'FREEZE.PANES',
116800x0088: 'SHOW.INFO',
116810x0089: 'SPLIT',
116820x008A: 'ON.WINDOW',
116830x008B: 'ON.DATA',
116840x008C: 'DISABLE.INPUT',
116850x008E: 'OUTLINE',
116860x008F: 'LIST.NAMES',
116870x0090: 'FILE.CLOSE',
116880x0091: 'SAVE.WORKBOOK',
116890x0092: 'DATA.FORM',
116900x0093: 'COPY.CHART',
116910x0094: 'ON.TIME',
116920x0095: 'WAIT',
116930x0096: 'FORMAT.FONT',
116940x0097: 'FILL.UP',
116950x0098: 'FILL.LEFT',
116960x0099: 'DELETE.OVERLAY',
116970x009B: 'SHORT.MENUS',
116980x009F: 'SET.UPDATE.STATUS',
116990x00A1: 'COLOR.PALETTE',
117000x00A2: 'DELETE.STYLE',
117010x00A3: 'WINDOW.RESTORE',
117020x00A4: 'WINDOW.MAXIMIZE',
117030x00A6: 'CHANGE.LINK',
117040x00A7: 'CALCULATE.DOCUMENT',
117050x00A8: 'ON.KEY',
117060x00A9: 'APP.RESTORE',
117070x00AA: 'APP.MOVE',
117080x00AB: 'APP.SIZE',
117090x00AC: 'APP.MINIMIZE',
117100x00AD: 'APP.MAXIMIZE',
117110x00AE: 'BRING.TO.FRONT',
117120x00AF: 'SEND.TO.BACK',
117130x00B9: 'MAIN.CHART.TYPE',
117140x00BA: 'OVERLAY.CHART.TYPE',
117150x00BB: 'SELECT.END',
117160x00BC: 'OPEN.MAIL',
117170x00BD: 'SEND.MAIL',
117180x00BE: 'STANDARD.FONT',
117190x00BF: 'CONSOLIDATE',
117200x00C0: 'SORT.SPECIAL',
117210x00C1: 'GALLERY.3D.AREA',
117220x00C2: 'GALLERY.3D.COLUMN',
117230x00C3: 'GALLERY.3D.LINE',
117240x00C4: 'GALLERY.3D.PIE',
117250x00C5: 'VIEW.3D',
117260x00C6: 'GOAL.SEEK',
117270x00C7: 'WORKGROUP',
117280x00C8: 'FILL.GROUP',
117290x00C9: 'UPDATE.LINK',
117300x00CA: 'PROMOTE',
117310x00CB: 'DEMOTE',
117320x00CC: 'SHOW.DETAIL',
117330x00CE: 'UNGROUP',
117340x00CF: 'OBJECT.PROPERTIES',
117350x00D0: 'SAVE.NEW.OBJECT',
117360x00D1: 'SHARE',
117370x00D2: 'SHARE.NAME',
117380x00D3: 'DUPLICATE',
117390x00D4: 'APPLY.STYLE',
117400x00D5: 'ASSIGN.TO.OBJECT',
117410x00D6: 'OBJECT.PROTECTION',
117420x00D7: 'HIDE.OBJECT',
117430x00D8: 'SET.EXTRACT',
117440x00D9: 'CREATE.PUBLISHER',
117450x00DA: 'SUBSCRIBE.TO',
117460x00DB: 'ATTRIBUTES',
117470x00DC: 'SHOW.TOOLBAR',
117480x00DE: 'PRINT.PREVIEW',
117490x00DF: 'EDIT.COLOR',
117500x00E0: 'SHOW.LEVELS',
117510x00E1: 'FORMAT.MAIN',
117520x00E2: 'FORMAT.OVERLAY',
117530x00E3: 'ON.RECALC',
117540x00E4: 'EDIT.SERIES',
117550x00E5: 'DEFINE.STYLE',
117560x00F0: 'LINE.PRINT',
117570x00F3: 'ENTER.DATA',
117580x00F9: 'GALLERY.RADAR',
117590x00FA: 'MERGE.STYLES',
117600x00FB: 'EDITION.OPTIONS',
117610x00FC: 'PASTE.PICTURE',
117620x00FD: 'PASTE.PICTURE.LINK',
117630x00FE: 'SPELLING',
117640x0100: 'ZOOM',
117650x0103: 'INSERT.OBJECT',
117660x0104: 'WINDOW.MINIMIZE',
117670x0109: 'SOUND.NOTE',
117680x010A: 'SOUND.PLAY',
117690x010B: 'FORMAT.SHAPE',
117700x010C: 'EXTEND.POLYGON',
117710x010D: 'FORMAT.AUTO',
117720x0110: 'GALLERY.3D.BAR',
117730x0111: 'GALLERY.3D.SURFACE',
117740x0112: 'FILL.AUTO',
117750x0114: 'CUSTOMIZE.TOOLBAR',
117760x0115: 'ADD.TOOL',
117770x0116: 'EDIT.OBJECT',
117780x0117: 'ON.DOUBLECLICK',
117790x0118: 'ON.ENTRY',
117800x0119: 'WORKBOOK.ADD',
117810x011A: 'WORKBOOK.MOVE',
117820x011B: 'WORKBOOK.COPY',
117830x011C: 'WORKBOOK.OPTIONS',
117840x011D: 'SAVE.WORKSPACE',
117850x0120: 'CHART.WIZARD',
117860x0121: 'DELETE.TOOL',
117870x0122: 'MOVE.TOOL',
117880x0123: 'WORKBOOK.SELECT',
117890x0124: 'WORKBOOK.ACTIVATE',
117900x0125: 'ASSIGN.TO.TOOL',
117910x0127: 'COPY.TOOL',
117920x0128: 'RESET.TOOL',
117930x0129: 'CONSTRAIN.NUMERIC',
117940x012A: 'PASTE.TOOL',
117950x012E: 'WORKBOOK.NEW',
117960x0131: 'SCENARIO.CELLS',
117970x0132: 'SCENARIO.DELETE',
117980x0133: 'SCENARIO.ADD',
117990x0134: 'SCENARIO.EDIT',
118000x0135: 'SCENARIO.SHOW',
118010x0136: 'SCENARIO.SHOW.NEXT',
118020x0137: 'SCENARIO.SUMMARY',
118030x0138: 'PIVOT.TABLE.WIZARD',
118040x0139: 'PIVOT.FIELD.PROPERTIES',
118050x013A: 'PIVOT.FIELD',
118060x013B: 'PIVOT.ITEM',
118070x013C: 'PIVOT.ADD.FIELDS',
118080x013E: 'OPTIONS.CALCULATION',
118090x013F: 'OPTIONS.EDIT',
118100x0140: 'OPTIONS.VIEW',
118110x0141: 'ADDIN.MANAGER',
118120x0142: 'MENU.EDITOR',
118130x0143: 'ATTACH.TOOLBARS',
118140x0144: 'VBAActivate',
118150x0145: 'OPTIONS.CHART',
118160x0148: 'VBA.INSERT.FILE',
118170x014A: 'VBA.PROCEDURE.DEFINITION',
118180x0150: 'ROUTING.SLIP',
118190x0152: 'ROUTE.DOCUMENT',
118200x0153: 'MAIL.LOGON',
118210x0156: 'INSERT.PICTURE',
118220x0157: 'EDIT.TOOL',
118230x0158: 'GALLERY.DOUGHNUT',
118240x015E: 'CHART.TREND',
118250x0160: 'PIVOT.ITEM.PROPERTIES',
118260x0162: 'WORKBOOK.INSERT',
118270x0163: 'OPTIONS.TRANSITION',
118280x0164: 'OPTIONS.GENERAL',
118290x0172: 'FILTER.ADVANCED',
118300x0175: 'MAIL.ADD.MAILER',
118310x0176: 'MAIL.DELETE.MAILER',
118320x0177: 'MAIL.REPLY',
118330x0178: 'MAIL.REPLY.ALL',
118340x0179: 'MAIL.FORWARD',
118350x017A: 'MAIL.NEXT.LETTER',
118360x017B: 'DATA.LABEL',
118370x017C: 'INSERT.TITLE',
118380x017D: 'FONT.PROPERTIES',
118390x017E: 'MACRO.OPTIONS',
118400x017F: 'WORKBOOK.HIDE',
118410x0180: 'WORKBOOK.UNHIDE',
118420x0181: 'WORKBOOK.DELETE',
118430x0182: 'WORKBOOK.NAME',
118440x0184: 'GALLERY.CUSTOM',
118450x0186: 'ADD.CHART.AUTOFORMAT',
118460x0187: 'DELETE.CHART.AUTOFORMAT',
118470x0188: 'CHART.ADD.DATA',
118480x0189: 'AUTO.OUTLINE',
118490x018A: 'TAB.ORDER',
118500x018B: 'SHOW.DIALOG',
118510x018C: 'SELECT.ALL',
118520x018D: 'UNGROUP.SHEETS',
118530x018E: 'SUBTOTAL.CREATE',
118540x018F: 'SUBTOTAL.REMOVE',
118550x0190: 'RENAME.OBJECT',
118560x019C: 'WORKBOOK.SCROLL',
118570x019D: 'WORKBOOK.NEXT',
118580x019E: 'WORKBOOK.PREV',
118590x019F: 'WORKBOOK.TAB.SPLIT',
118600x01A0: 'FULL.SCREEN',
118610x01A1: 'WORKBOOK.PROTECT',
118620x01A4: 'SCROLLBAR.PROPERTIES',
118630x01A5: 'PIVOT.SHOW.PAGES',
118640x01A6: 'TEXT.TO.COLUMNS',
118650x01A7: 'FORMAT.CHARTTYPE',
118660x01A8: 'LINK.FORMAT',
118670x01A9: 'TRACER.DISPLAY',
118680x01AE: 'TRACER.NAVIGATE',
118690x01AF: 'TRACER.CLEAR',
118700x01B0: 'TRACER.ERROR',
118710x01B1: 'PIVOT.FIELD.GROUP',
118720x01B2: 'PIVOT.FIELD.UNGROUP',
118730x01B3: 'CHECKBOX.PROPERTIES',
118740x01B4: 'LABEL.PROPERTIES',
118750x01B5: 'LISTBOX.PROPERTIES',
118760x01B6: 'EDITBOX.PROPERTIES',
118770x01B7: 'PIVOT.REFRESH',
118780x01B8: 'LINK.COMBO',
118790x01B9: 'OPEN.TEXT',
118800x01BA: 'HIDE.DIALOG',
118810x01BB: 'SET.DIALOG.FOCUS',
118820x01BC: 'ENABLE.OBJECT',
118830x01BD: 'PUSHBUTTON.PROPERTIES',
118840x01BE: 'SET.DIALOG.DEFAULT',
118850x01BF: 'FILTER',
118860x01C0: 'FILTER.SHOW.ALL',
118870x01C1: 'CLEAR.OUTLINE',
118880x01C2: 'FUNCTION.WIZARD',
118890x01C3: 'ADD.LIST.ITEM',
118900x01C4: 'SET.LIST.ITEM',
118910x01C5: 'REMOVE.LIST.ITEM',
118920x01C6: 'SELECT.LIST.ITEM',
118930x01C7: 'SET.CONTROL.VALUE',
118940x01C8: 'SAVE.COPY.AS',
118950x01CA: 'OPTIONS.LISTS.ADD',
118960x01CB: 'OPTIONS.LISTS.DELETE',
118970x01CC: 'SERIES.AXES',
118980x01CD: 'SERIES.X',
118990x01CE: 'SERIES.Y',
119000x01CF: 'ERRORBAR.X',
119010x01D0: 'ERRORBAR.Y',
119020x01D1: 'FORMAT.CHART',
119030x01D2: 'SERIES.ORDER',
119040x01D3: 'MAIL.LOGOFF',
119050x01D4: 'CLEAR.ROUTING.SLIP',
119060x01D5: 'APP.ACTIVATE.MICROSOFT',
119070x01D6: 'MAIL.EDIT.MAILER',
119080x01D7: 'ON.SHEET',
119090x01D8: 'STANDARD.WIDTH',
119100x01D9: 'SCENARIO.MERGE',
119110x01DA: 'SUMMARY.INFO',
119120x01DB: 'FIND.FILE',
119130x01DC: 'ACTIVE.CELL.FONT',
119140x01DD: 'ENABLE.TIPWIZARD',
119150x01DE: 'VBA.MAKE.ADDIN',
119160x01E0: 'INSERTDATATABLE',
119170x01E1: 'WORKGROUP.OPTIONS',
119180x01E2: 'MAIL.SEND.MAILER',
119190x01E5: 'AUTOCORRECT',
119200x01E9: 'POST.DOCUMENT',
119210x01EB: 'PICKLIST',
119220x01ED: 'VIEW.SHOW',
119230x01EE: 'VIEW.DEFINE',
119240x01EF: 'VIEW.DELETE',
119250x01FD: 'SHEET.BACKGROUND',
119260x01FE: 'INSERT.MAP.OBJECT',
119270x01FF: 'OPTIONS.MENONO',
119280x0205: 'MSOCHECKS',
119290x0206: 'NORMAL',
119300x0207: 'LAYOUT',
119310x0208: 'RM.PRINT.AREA',
119320x0209: 'CLEAR.PRINT.AREA',
119330x020A: 'ADD.PRINT.AREA',
119340x020B: 'MOVE.BRK',
119350x0221: 'HIDECURR.NOTE',
119360x0222: 'HIDEALL.NOTES',
119370x0223: 'DELETE.NOTE',
119380x0224: 'TRAVERSE.NOTES',
119390x0225: 'ACTIVATE.NOTES',
119400x026C: 'PROTECT.REVISIONS',
119410x026D: 'UNPROTECT.REVISIONS',
119420x0287: 'OPTIONS.ME',
119430x028D: 'WEB.PUBLISH',
119440x029B: 'NEWWEBQUERY',
119450x02A1: 'PIVOT.TABLE.CHART',
119460x02F1: 'OPTIONS.SAVE',
119470x02F3: 'OPTIONS.SPELL',
119480x0328: 'HIDEALL.INKANNOTS'
11949};
11950
11951/* [MS-XLS] 2.5.198.17 */
11952/* [MS-XLSB] 2.5.97.10 */
11953var Ftab = {
119540x0000: 'COUNT',
119550x0001: 'IF',
119560x0002: 'ISNA',
119570x0003: 'ISERROR',
119580x0004: 'SUM',
119590x0005: 'AVERAGE',
119600x0006: 'MIN',
119610x0007: 'MAX',
119620x0008: 'ROW',
119630x0009: 'COLUMN',
119640x000A: 'NA',
119650x000B: 'NPV',
119660x000C: 'STDEV',
119670x000D: 'DOLLAR',
119680x000E: 'FIXED',
119690x000F: 'SIN',
119700x0010: 'COS',
119710x0011: 'TAN',
119720x0012: 'ATAN',
119730x0013: 'PI',
119740x0014: 'SQRT',
119750x0015: 'EXP',
119760x0016: 'LN',
119770x0017: 'LOG10',
119780x0018: 'ABS',
119790x0019: 'INT',
119800x001A: 'SIGN',
119810x001B: 'ROUND',
119820x001C: 'LOOKUP',
119830x001D: 'INDEX',
119840x001E: 'REPT',
119850x001F: 'MID',
119860x0020: 'LEN',
119870x0021: 'VALUE',
119880x0022: 'TRUE',
119890x0023: 'FALSE',
119900x0024: 'AND',
119910x0025: 'OR',
119920x0026: 'NOT',
119930x0027: 'MOD',
119940x0028: 'DCOUNT',
119950x0029: 'DSUM',
119960x002A: 'DAVERAGE',
119970x002B: 'DMIN',
119980x002C: 'DMAX',
119990x002D: 'DSTDEV',
120000x002E: 'VAR',
120010x002F: 'DVAR',
120020x0030: 'TEXT',
120030x0031: 'LINEST',
120040x0032: 'TREND',
120050x0033: 'LOGEST',
120060x0034: 'GROWTH',
120070x0035: 'GOTO',
120080x0036: 'HALT',
120090x0037: 'RETURN',
120100x0038: 'PV',
120110x0039: 'FV',
120120x003A: 'NPER',
120130x003B: 'PMT',
120140x003C: 'RATE',
120150x003D: 'MIRR',
120160x003E: 'IRR',
120170x003F: 'RAND',
120180x0040: 'MATCH',
120190x0041: 'DATE',
120200x0042: 'TIME',
120210x0043: 'DAY',
120220x0044: 'MONTH',
120230x0045: 'YEAR',
120240x0046: 'WEEKDAY',
120250x0047: 'HOUR',
120260x0048: 'MINUTE',
120270x0049: 'SECOND',
120280x004A: 'NOW',
120290x004B: 'AREAS',
120300x004C: 'ROWS',
120310x004D: 'COLUMNS',
120320x004E: 'OFFSET',
120330x004F: 'ABSREF',
120340x0050: 'RELREF',
120350x0051: 'ARGUMENT',
120360x0052: 'SEARCH',
120370x0053: 'TRANSPOSE',
120380x0054: 'ERROR',
120390x0055: 'STEP',
120400x0056: 'TYPE',
120410x0057: 'ECHO',
120420x0058: 'SET.NAME',
120430x0059: 'CALLER',
120440x005A: 'DEREF',
120450x005B: 'WINDOWS',
120460x005C: 'SERIES',
120470x005D: 'DOCUMENTS',
120480x005E: 'ACTIVE.CELL',
120490x005F: 'SELECTION',
120500x0060: 'RESULT',
120510x0061: 'ATAN2',
120520x0062: 'ASIN',
120530x0063: 'ACOS',
120540x0064: 'CHOOSE',
120550x0065: 'HLOOKUP',
120560x0066: 'VLOOKUP',
120570x0067: 'LINKS',
120580x0068: 'INPUT',
120590x0069: 'ISREF',
120600x006A: 'GET.FORMULA',
120610x006B: 'GET.NAME',
120620x006C: 'SET.VALUE',
120630x006D: 'LOG',
120640x006E: 'EXEC',
120650x006F: 'CHAR',
120660x0070: 'LOWER',
120670x0071: 'UPPER',
120680x0072: 'PROPER',
120690x0073: 'LEFT',
120700x0074: 'RIGHT',
120710x0075: 'EXACT',
120720x0076: 'TRIM',
120730x0077: 'REPLACE',
120740x0078: 'SUBSTITUTE',
120750x0079: 'CODE',
120760x007A: 'NAMES',
120770x007B: 'DIRECTORY',
120780x007C: 'FIND',
120790x007D: 'CELL',
120800x007E: 'ISERR',
120810x007F: 'ISTEXT',
120820x0080: 'ISNUMBER',
120830x0081: 'ISBLANK',
120840x0082: 'T',
120850x0083: 'N',
120860x0084: 'FOPEN',
120870x0085: 'FCLOSE',
120880x0086: 'FSIZE',
120890x0087: 'FREADLN',
120900x0088: 'FREAD',
120910x0089: 'FWRITELN',
120920x008A: 'FWRITE',
120930x008B: 'FPOS',
120940x008C: 'DATEVALUE',
120950x008D: 'TIMEVALUE',
120960x008E: 'SLN',
120970x008F: 'SYD',
120980x0090: 'DDB',
120990x0091: 'GET.DEF',
121000x0092: 'REFTEXT',
121010x0093: 'TEXTREF',
121020x0094: 'INDIRECT',
121030x0095: 'REGISTER',
121040x0096: 'CALL',
121050x0097: 'ADD.BAR',
121060x0098: 'ADD.MENU',
121070x0099: 'ADD.COMMAND',
121080x009A: 'ENABLE.COMMAND',
121090x009B: 'CHECK.COMMAND',
121100x009C: 'RENAME.COMMAND',
121110x009D: 'SHOW.BAR',
121120x009E: 'DELETE.MENU',
121130x009F: 'DELETE.COMMAND',
121140x00A0: 'GET.CHART.ITEM',
121150x00A1: 'DIALOG.BOX',
121160x00A2: 'CLEAN',
121170x00A3: 'MDETERM',
121180x00A4: 'MINVERSE',
121190x00A5: 'MMULT',
121200x00A6: 'FILES',
121210x00A7: 'IPMT',
121220x00A8: 'PPMT',
121230x00A9: 'COUNTA',
121240x00AA: 'CANCEL.KEY',
121250x00AB: 'FOR',
121260x00AC: 'WHILE',
121270x00AD: 'BREAK',
121280x00AE: 'NEXT',
121290x00AF: 'INITIATE',
121300x00B0: 'REQUEST',
121310x00B1: 'POKE',
121320x00B2: 'EXECUTE',
121330x00B3: 'TERMINATE',
121340x00B4: 'RESTART',
121350x00B5: 'HELP',
121360x00B6: 'GET.BAR',
121370x00B7: 'PRODUCT',
121380x00B8: 'FACT',
121390x00B9: 'GET.CELL',
121400x00BA: 'GET.WORKSPACE',
121410x00BB: 'GET.WINDOW',
121420x00BC: 'GET.DOCUMENT',
121430x00BD: 'DPRODUCT',
121440x00BE: 'ISNONTEXT',
121450x00BF: 'GET.NOTE',
121460x00C0: 'NOTE',
121470x00C1: 'STDEVP',
121480x00C2: 'VARP',
121490x00C3: 'DSTDEVP',
121500x00C4: 'DVARP',
121510x00C5: 'TRUNC',
121520x00C6: 'ISLOGICAL',
121530x00C7: 'DCOUNTA',
121540x00C8: 'DELETE.BAR',
121550x00C9: 'UNREGISTER',
121560x00CC: 'USDOLLAR',
121570x00CD: 'FINDB',
121580x00CE: 'SEARCHB',
121590x00CF: 'REPLACEB',
121600x00D0: 'LEFTB',
121610x00D1: 'RIGHTB',
121620x00D2: 'MIDB',
121630x00D3: 'LENB',
121640x00D4: 'ROUNDUP',
121650x00D5: 'ROUNDDOWN',
121660x00D6: 'ASC',
121670x00D7: 'DBCS',
121680x00D8: 'RANK',
121690x00DB: 'ADDRESS',
121700x00DC: 'DAYS360',
121710x00DD: 'TODAY',
121720x00DE: 'VDB',
121730x00DF: 'ELSE',
121740x00E0: 'ELSE.IF',
121750x00E1: 'END.IF',
121760x00E2: 'FOR.CELL',
121770x00E3: 'MEDIAN',
121780x00E4: 'SUMPRODUCT',
121790x00E5: 'SINH',
121800x00E6: 'COSH',
121810x00E7: 'TANH',
121820x00E8: 'ASINH',
121830x00E9: 'ACOSH',
121840x00EA: 'ATANH',
121850x00EB: 'DGET',
121860x00EC: 'CREATE.OBJECT',
121870x00ED: 'VOLATILE',
121880x00EE: 'LAST.ERROR',
121890x00EF: 'CUSTOM.UNDO',
121900x00F0: 'CUSTOM.REPEAT',
121910x00F1: 'FORMULA.CONVERT',
121920x00F2: 'GET.LINK.INFO',
121930x00F3: 'TEXT.BOX',
121940x00F4: 'INFO',
121950x00F5: 'GROUP',
121960x00F6: 'GET.OBJECT',
121970x00F7: 'DB',
121980x00F8: 'PAUSE',
121990x00FB: 'RESUME',
122000x00FC: 'FREQUENCY',
122010x00FD: 'ADD.TOOLBAR',
122020x00FE: 'DELETE.TOOLBAR',
122030x00FF: 'User',
122040x0100: 'RESET.TOOLBAR',
122050x0101: 'EVALUATE',
122060x0102: 'GET.TOOLBAR',
122070x0103: 'GET.TOOL',
122080x0104: 'SPELLING.CHECK',
122090x0105: 'ERROR.TYPE',
122100x0106: 'APP.TITLE',
122110x0107: 'WINDOW.TITLE',
122120x0108: 'SAVE.TOOLBAR',
122130x0109: 'ENABLE.TOOL',
122140x010A: 'PRESS.TOOL',
122150x010B: 'REGISTER.ID',
122160x010C: 'GET.WORKBOOK',
122170x010D: 'AVEDEV',
122180x010E: 'BETADIST',
122190x010F: 'GAMMALN',
122200x0110: 'BETAINV',
122210x0111: 'BINOMDIST',
122220x0112: 'CHIDIST',
122230x0113: 'CHIINV',
122240x0114: 'COMBIN',
122250x0115: 'CONFIDENCE',
122260x0116: 'CRITBINOM',
122270x0117: 'EVEN',
122280x0118: 'EXPONDIST',
122290x0119: 'FDIST',
122300x011A: 'FINV',
122310x011B: 'FISHER',
122320x011C: 'FISHERINV',
122330x011D: 'FLOOR',
122340x011E: 'GAMMADIST',
122350x011F: 'GAMMAINV',
122360x0120: 'CEILING',
122370x0121: 'HYPGEOMDIST',
122380x0122: 'LOGNORMDIST',
122390x0123: 'LOGINV',
122400x0124: 'NEGBINOMDIST',
122410x0125: 'NORMDIST',
122420x0126: 'NORMSDIST',
122430x0127: 'NORMINV',
122440x0128: 'NORMSINV',
122450x0129: 'STANDARDIZE',
122460x012A: 'ODD',
122470x012B: 'PERMUT',
122480x012C: 'POISSON',
122490x012D: 'TDIST',
122500x012E: 'WEIBULL',
122510x012F: 'SUMXMY2',
122520x0130: 'SUMX2MY2',
122530x0131: 'SUMX2PY2',
122540x0132: 'CHITEST',
122550x0133: 'CORREL',
122560x0134: 'COVAR',
122570x0135: 'FORECAST',
122580x0136: 'FTEST',
122590x0137: 'INTERCEPT',
122600x0138: 'PEARSON',
122610x0139: 'RSQ',
122620x013A: 'STEYX',
122630x013B: 'SLOPE',
122640x013C: 'TTEST',
122650x013D: 'PROB',
122660x013E: 'DEVSQ',
122670x013F: 'GEOMEAN',
122680x0140: 'HARMEAN',
122690x0141: 'SUMSQ',
122700x0142: 'KURT',
122710x0143: 'SKEW',
122720x0144: 'ZTEST',
122730x0145: 'LARGE',
122740x0146: 'SMALL',
122750x0147: 'QUARTILE',
122760x0148: 'PERCENTILE',
122770x0149: 'PERCENTRANK',
122780x014A: 'MODE',
122790x014B: 'TRIMMEAN',
122800x014C: 'TINV',
122810x014E: 'MOVIE.COMMAND',
122820x014F: 'GET.MOVIE',
122830x0150: 'CONCATENATE',
122840x0151: 'POWER',
122850x0152: 'PIVOT.ADD.DATA',
122860x0153: 'GET.PIVOT.TABLE',
122870x0154: 'GET.PIVOT.FIELD',
122880x0155: 'GET.PIVOT.ITEM',
122890x0156: 'RADIANS',
122900x0157: 'DEGREES',
122910x0158: 'SUBTOTAL',
122920x0159: 'SUMIF',
122930x015A: 'COUNTIF',
122940x015B: 'COUNTBLANK',
122950x015C: 'SCENARIO.GET',
122960x015D: 'OPTIONS.LISTS.GET',
122970x015E: 'ISPMT',
122980x015F: 'DATEDIF',
122990x0160: 'DATESTRING',
123000x0161: 'NUMBERSTRING',
123010x0162: 'ROMAN',
123020x0163: 'OPEN.DIALOG',
123030x0164: 'SAVE.DIALOG',
123040x0165: 'VIEW.GET',
123050x0166: 'GETPIVOTDATA',
123060x0167: 'HYPERLINK',
123070x0168: 'PHONETIC',
123080x0169: 'AVERAGEA',
123090x016A: 'MAXA',
123100x016B: 'MINA',
123110x016C: 'STDEVPA',
123120x016D: 'VARPA',
123130x016E: 'STDEVA',
123140x016F: 'VARA',
123150x0170: 'BAHTTEXT',
123160x0171: 'THAIDAYOFWEEK',
123170x0172: 'THAIDIGIT',
123180x0173: 'THAIMONTHOFYEAR',
123190x0174: 'THAINUMSOUND',
123200x0175: 'THAINUMSTRING',
123210x0176: 'THAISTRINGLENGTH',
123220x0177: 'ISTHAIDIGIT',
123230x0178: 'ROUNDBAHTDOWN',
123240x0179: 'ROUNDBAHTUP',
123250x017A: 'THAIYEAR',
123260x017B: 'RTD',
12327
123280x017C: 'CUBEVALUE',
123290x017D: 'CUBEMEMBER',
123300x017E: 'CUBEMEMBERPROPERTY',
123310x017F: 'CUBERANKEDMEMBER',
123320x0180: 'HEX2BIN',
123330x0181: 'HEX2DEC',
123340x0182: 'HEX2OCT',
123350x0183: 'DEC2BIN',
123360x0184: 'DEC2HEX',
123370x0185: 'DEC2OCT',
123380x0186: 'OCT2BIN',
123390x0187: 'OCT2HEX',
123400x0188: 'OCT2DEC',
123410x0189: 'BIN2DEC',
123420x018A: 'BIN2OCT',
123430x018B: 'BIN2HEX',
123440x018C: 'IMSUB',
123450x018D: 'IMDIV',
123460x018E: 'IMPOWER',
123470x018F: 'IMABS',
123480x0190: 'IMSQRT',
123490x0191: 'IMLN',
123500x0192: 'IMLOG2',
123510x0193: 'IMLOG10',
123520x0194: 'IMSIN',
123530x0195: 'IMCOS',
123540x0196: 'IMEXP',
123550x0197: 'IMARGUMENT',
123560x0198: 'IMCONJUGATE',
123570x0199: 'IMAGINARY',
123580x019A: 'IMREAL',
123590x019B: 'COMPLEX',
123600x019C: 'IMSUM',
123610x019D: 'IMPRODUCT',
123620x019E: 'SERIESSUM',
123630x019F: 'FACTDOUBLE',
123640x01A0: 'SQRTPI',
123650x01A1: 'QUOTIENT',
123660x01A2: 'DELTA',
123670x01A3: 'GESTEP',
123680x01A4: 'ISEVEN',
123690x01A5: 'ISODD',
123700x01A6: 'MROUND',
123710x01A7: 'ERF',
123720x01A8: 'ERFC',
123730x01A9: 'BESSELJ',
123740x01AA: 'BESSELK',
123750x01AB: 'BESSELY',
123760x01AC: 'BESSELI',
123770x01AD: 'XIRR',
123780x01AE: 'XNPV',
123790x01AF: 'PRICEMAT',
123800x01B0: 'YIELDMAT',
123810x01B1: 'INTRATE',
123820x01B2: 'RECEIVED',
123830x01B3: 'DISC',
123840x01B4: 'PRICEDISC',
123850x01B5: 'YIELDDISC',
123860x01B6: 'TBILLEQ',
123870x01B7: 'TBILLPRICE',
123880x01B8: 'TBILLYIELD',
123890x01B9: 'PRICE',
123900x01BA: 'YIELD',
123910x01BB: 'DOLLARDE',
123920x01BC: 'DOLLARFR',
123930x01BD: 'NOMINAL',
123940x01BE: 'EFFECT',
123950x01BF: 'CUMPRINC',
123960x01C0: 'CUMIPMT',
123970x01C1: 'EDATE',
123980x01C2: 'EOMONTH',
123990x01C3: 'YEARFRAC',
124000x01C4: 'COUPDAYBS',
124010x01C5: 'COUPDAYS',
124020x01C6: 'COUPDAYSNC',
124030x01C7: 'COUPNCD',
124040x01C8: 'COUPNUM',
124050x01C9: 'COUPPCD',
124060x01CA: 'DURATION',
124070x01CB: 'MDURATION',
124080x01CC: 'ODDLPRICE',
124090x01CD: 'ODDLYIELD',
124100x01CE: 'ODDFPRICE',
124110x01CF: 'ODDFYIELD',
124120x01D0: 'RANDBETWEEN',
124130x01D1: 'WEEKNUM',
124140x01D2: 'AMORDEGRC',
124150x01D3: 'AMORLINC',
124160x01D4: 'CONVERT',
124170x02D4: 'SHEETJS',
124180x01D5: 'ACCRINT',
124190x01D6: 'ACCRINTM',
124200x01D7: 'WORKDAY',
124210x01D8: 'NETWORKDAYS',
124220x01D9: 'GCD',
124230x01DA: 'MULTINOMIAL',
124240x01DB: 'LCM',
124250x01DC: 'FVSCHEDULE',
124260x01DD: 'CUBEKPIMEMBER',
124270x01DE: 'CUBESET',
124280x01DF: 'CUBESETCOUNT',
124290x01E0: 'IFERROR',
124300x01E1: 'COUNTIFS',
124310x01E2: 'SUMIFS',
124320x01E3: 'AVERAGEIF',
124330x01E4: 'AVERAGEIFS'
12434};
12435var FtabArgc = {
124360x0002: 1, /* ISNA */
124370x0003: 1, /* ISERROR */
124380x000A: 0, /* NA */
124390x000F: 1, /* SIN */
124400x0010: 1, /* COS */
124410x0011: 1, /* TAN */
124420x0012: 1, /* ATAN */
124430x0013: 0, /* PI */
124440x0014: 1, /* SQRT */
124450x0015: 1, /* EXP */
124460x0016: 1, /* LN */
124470x0017: 1, /* LOG10 */
124480x0018: 1, /* ABS */
124490x0019: 1, /* INT */
124500x001A: 1, /* SIGN */
124510x001B: 2, /* ROUND */
124520x001E: 2, /* REPT */
124530x001F: 3, /* MID */
124540x0020: 1, /* LEN */
124550x0021: 1, /* VALUE */
124560x0022: 0, /* TRUE */
124570x0023: 0, /* FALSE */
124580x0026: 1, /* NOT */
124590x0027: 2, /* MOD */
124600x0028: 3, /* DCOUNT */
124610x0029: 3, /* DSUM */
124620x002A: 3, /* DAVERAGE */
124630x002B: 3, /* DMIN */
124640x002C: 3, /* DMAX */
124650x002D: 3, /* DSTDEV */
124660x002F: 3, /* DVAR */
124670x0030: 2, /* TEXT */
124680x0035: 1, /* GOTO */
124690x003D: 3, /* MIRR */
124700x003F: 0, /* RAND */
124710x0041: 3, /* DATE */
124720x0042: 3, /* TIME */
124730x0043: 1, /* DAY */
124740x0044: 1, /* MONTH */
124750x0045: 1, /* YEAR */
124760x0046: 1, /* WEEKDAY */
124770x0047: 1, /* HOUR */
124780x0048: 1, /* MINUTE */
124790x0049: 1, /* SECOND */
124800x004A: 0, /* NOW */
124810x004B: 1, /* AREAS */
124820x004C: 1, /* ROWS */
124830x004D: 1, /* COLUMNS */
124840x004F: 2, /* ABSREF */
124850x0050: 2, /* RELREF */
124860x0053: 1, /* TRANSPOSE */
124870x0055: 0, /* STEP */
124880x0056: 1, /* TYPE */
124890x0059: 0, /* CALLER */
124900x005A: 1, /* DEREF */
124910x005E: 0, /* ACTIVE.CELL */
124920x005F: 0, /* SELECTION */
124930x0061: 2, /* ATAN2 */
124940x0062: 1, /* ASIN */
124950x0063: 1, /* ACOS */
124960x0065: 3, /* HLOOKUP */
124970x0066: 3, /* VLOOKUP */
124980x0069: 1, /* ISREF */
124990x006A: 1, /* GET.FORMULA */
125000x006C: 2, /* SET.VALUE */
125010x006F: 1, /* CHAR */
125020x0070: 1, /* LOWER */
125030x0071: 1, /* UPPER */
125040x0072: 1, /* PROPER */
125050x0075: 2, /* EXACT */
125060x0076: 1, /* TRIM */
125070x0077: 4, /* REPLACE */
125080x0079: 1, /* CODE */
125090x007E: 1, /* ISERR */
125100x007F: 1, /* ISTEXT */
125110x0080: 1, /* ISNUMBER */
125120x0081: 1, /* ISBLANK */
125130x0082: 1, /* T */
125140x0083: 1, /* N */
125150x0085: 1, /* FCLOSE */
125160x0086: 1, /* FSIZE */
125170x0087: 1, /* FREADLN */
125180x0088: 2, /* FREAD */
125190x0089: 2, /* FWRITELN */
125200x008A: 2, /* FWRITE */
125210x008C: 1, /* DATEVALUE */
125220x008D: 1, /* TIMEVALUE */
125230x008E: 3, /* SLN */
125240x008F: 4, /* SYD */
125250x0090: 4, /* DDB */
125260x00A1: 1, /* DIALOG.BOX */
125270x00A2: 1, /* CLEAN */
125280x00A3: 1, /* MDETERM */
125290x00A4: 1, /* MINVERSE */
125300x00A5: 2, /* MMULT */
125310x00AC: 1, /* WHILE */
125320x00AF: 2, /* INITIATE */
125330x00B0: 2, /* REQUEST */
125340x00B1: 3, /* POKE */
125350x00B2: 2, /* EXECUTE */
125360x00B3: 1, /* TERMINATE */
125370x00B8: 1, /* FACT */
125380x00BA: 1, /* GET.WORKSPACE */
125390x00BD: 3, /* DPRODUCT */
125400x00BE: 1, /* ISNONTEXT */
125410x00C3: 3, /* DSTDEVP */
125420x00C4: 3, /* DVARP */
125430x00C5: 1, /* TRUNC */
125440x00C6: 1, /* ISLOGICAL */
125450x00C7: 3, /* DCOUNTA */
125460x00C9: 1, /* UNREGISTER */
125470x00CF: 4, /* REPLACEB */
125480x00D2: 3, /* MIDB */
125490x00D3: 1, /* LENB */
125500x00D4: 2, /* ROUNDUP */
125510x00D5: 2, /* ROUNDDOWN */
125520x00D6: 1, /* ASC */
125530x00D7: 1, /* DBCS */
125540x00E1: 0, /* END.IF */
125550x00E5: 1, /* SINH */
125560x00E6: 1, /* COSH */
125570x00E7: 1, /* TANH */
125580x00E8: 1, /* ASINH */
125590x00E9: 1, /* ACOSH */
125600x00EA: 1, /* ATANH */
125610x00EB: 3, /* DGET */
125620x00F4: 1, /* INFO */
125630x00F7: 4, /* DB */
125640x00FC: 2, /* FREQUENCY */
125650x0101: 1, /* EVALUATE */
125660x0105: 1, /* ERROR.TYPE */
125670x010F: 1, /* GAMMALN */
125680x0111: 4, /* BINOMDIST */
125690x0112: 2, /* CHIDIST */
125700x0113: 2, /* CHIINV */
125710x0114: 2, /* COMBIN */
125720x0115: 3, /* CONFIDENCE */
125730x0116: 3, /* CRITBINOM */
125740x0117: 1, /* EVEN */
125750x0118: 3, /* EXPONDIST */
125760x0119: 3, /* FDIST */
125770x011A: 3, /* FINV */
125780x011B: 1, /* FISHER */
125790x011C: 1, /* FISHERINV */
125800x011D: 2, /* FLOOR */
125810x011E: 4, /* GAMMADIST */
125820x011F: 3, /* GAMMAINV */
125830x0120: 2, /* CEILING */
125840x0121: 4, /* HYPGEOMDIST */
125850x0122: 3, /* LOGNORMDIST */
125860x0123: 3, /* LOGINV */
125870x0124: 3, /* NEGBINOMDIST */
125880x0125: 4, /* NORMDIST */
125890x0126: 1, /* NORMSDIST */
125900x0127: 3, /* NORMINV */
125910x0128: 1, /* NORMSINV */
125920x0129: 3, /* STANDARDIZE */
125930x012A: 1, /* ODD */
125940x012B: 2, /* PERMUT */
125950x012C: 3, /* POISSON */
125960x012D: 3, /* TDIST */
125970x012E: 4, /* WEIBULL */
125980x012F: 2, /* SUMXMY2 */
125990x0130: 2, /* SUMX2MY2 */
126000x0131: 2, /* SUMX2PY2 */
126010x0132: 2, /* CHITEST */
126020x0133: 2, /* CORREL */
126030x0134: 2, /* COVAR */
126040x0135: 3, /* FORECAST */
126050x0136: 2, /* FTEST */
126060x0137: 2, /* INTERCEPT */
126070x0138: 2, /* PEARSON */
126080x0139: 2, /* RSQ */
126090x013A: 2, /* STEYX */
126100x013B: 2, /* SLOPE */
126110x013C: 4, /* TTEST */
126120x0145: 2, /* LARGE */
126130x0146: 2, /* SMALL */
126140x0147: 2, /* QUARTILE */
126150x0148: 2, /* PERCENTILE */
126160x014B: 2, /* TRIMMEAN */
126170x014C: 2, /* TINV */
126180x0151: 2, /* POWER */
126190x0156: 1, /* RADIANS */
126200x0157: 1, /* DEGREES */
126210x015A: 2, /* COUNTIF */
126220x015B: 1, /* COUNTBLANK */
126230x015E: 4, /* ISPMT */
126240x015F: 3, /* DATEDIF */
126250x0160: 1, /* DATESTRING */
126260x0161: 2, /* NUMBERSTRING */
126270x0168: 1, /* PHONETIC */
126280x0170: 1, /* BAHTTEXT */
126290x0171: 1, /* THAIDAYOFWEEK */
126300x0172: 1, /* THAIDIGIT */
126310x0173: 1, /* THAIMONTHOFYEAR */
126320x0174: 1, /* THAINUMSOUND */
126330x0175: 1, /* THAINUMSTRING */
126340x0176: 1, /* THAISTRINGLENGTH */
126350x0177: 1, /* ISTHAIDIGIT */
126360x0178: 1, /* ROUNDBAHTDOWN */
126370x0179: 1, /* ROUNDBAHTUP */
126380x017A: 1, /* THAIYEAR */
126390x017E: 3, /* CUBEMEMBERPROPERTY */
126400x0181: 1, /* HEX2DEC */
126410x0188: 1, /* OCT2DEC */
126420x0189: 1, /* BIN2DEC */
126430x018C: 2, /* IMSUB */
126440x018D: 2, /* IMDIV */
126450x018E: 2, /* IMPOWER */
126460x018F: 1, /* IMABS */
126470x0190: 1, /* IMSQRT */
126480x0191: 1, /* IMLN */
126490x0192: 1, /* IMLOG2 */
126500x0193: 1, /* IMLOG10 */
126510x0194: 1, /* IMSIN */
126520x0195: 1, /* IMCOS */
126530x0196: 1, /* IMEXP */
126540x0197: 1, /* IMARGUMENT */
126550x0198: 1, /* IMCONJUGATE */
126560x0199: 1, /* IMAGINARY */
126570x019A: 1, /* IMREAL */
126580x019E: 4, /* SERIESSUM */
126590x019F: 1, /* FACTDOUBLE */
126600x01A0: 1, /* SQRTPI */
126610x01A1: 2, /* QUOTIENT */
126620x01A4: 1, /* ISEVEN */
126630x01A5: 1, /* ISODD */
126640x01A6: 2, /* MROUND */
126650x01A8: 1, /* ERFC */
126660x01A9: 2, /* BESSELJ */
126670x01AA: 2, /* BESSELK */
126680x01AB: 2, /* BESSELY */
126690x01AC: 2, /* BESSELI */
126700x01AE: 3, /* XNPV */
126710x01B6: 3, /* TBILLEQ */
126720x01B7: 3, /* TBILLPRICE */
126730x01B8: 3, /* TBILLYIELD */
126740x01BB: 2, /* DOLLARDE */
126750x01BC: 2, /* DOLLARFR */
126760x01BD: 2, /* NOMINAL */
126770x01BE: 2, /* EFFECT */
126780x01BF: 6, /* CUMPRINC */
126790x01C0: 6, /* CUMIPMT */
126800x01C1: 2, /* EDATE */
126810x01C2: 2, /* EOMONTH */
126820x01D0: 2, /* RANDBETWEEN */
126830x01D4: 3, /* CONVERT */
126840x01DC: 2, /* FVSCHEDULE */
126850x01DF: 1, /* CUBESETCOUNT */
126860x01E0: 2, /* IFERROR */
126870xFFFF: 0
12688};
12689/* [MS-XLSX] 2.2.3 Functions */
12690/* [MS-XLSB] 2.5.97.10 Ftab */
12691var XLSXFutureFunctions = {
12692 "_xlfn.ACOT": "ACOT",
12693 "_xlfn.ACOTH": "ACOTH",
12694 "_xlfn.AGGREGATE": "AGGREGATE",
12695 "_xlfn.ARABIC": "ARABIC",
12696 "_xlfn.AVERAGEIF": "AVERAGEIF",
12697 "_xlfn.AVERAGEIFS": "AVERAGEIFS",
12698 "_xlfn.BASE": "BASE",
12699 "_xlfn.BETA.DIST": "BETA.DIST",
12700 "_xlfn.BETA.INV": "BETA.INV",
12701 "_xlfn.BINOM.DIST": "BINOM.DIST",
12702 "_xlfn.BINOM.DIST.RANGE": "BINOM.DIST.RANGE",
12703 "_xlfn.BINOM.INV": "BINOM.INV",
12704 "_xlfn.BITAND": "BITAND",
12705 "_xlfn.BITLSHIFT": "BITLSHIFT",
12706 "_xlfn.BITOR": "BITOR",
12707 "_xlfn.BITRSHIFT": "BITRSHIFT",
12708 "_xlfn.BITXOR": "BITXOR",
12709 "_xlfn.CEILING.MATH": "CEILING.MATH",
12710 "_xlfn.CEILING.PRECISE": "CEILING.PRECISE",
12711 "_xlfn.CHISQ.DIST": "CHISQ.DIST",
12712 "_xlfn.CHISQ.DIST.RT": "CHISQ.DIST.RT",
12713 "_xlfn.CHISQ.INV": "CHISQ.INV",
12714 "_xlfn.CHISQ.INV.RT": "CHISQ.INV.RT",
12715 "_xlfn.CHISQ.TEST": "CHISQ.TEST",
12716 "_xlfn.COMBINA": "COMBINA",
12717 "_xlfn.CONCAT": "CONCAT",
12718 "_xlfn.CONFIDENCE.NORM": "CONFIDENCE.NORM",
12719 "_xlfn.CONFIDENCE.T": "CONFIDENCE.T",
12720 "_xlfn.COT": "COT",
12721 "_xlfn.COTH": "COTH",
12722 "_xlfn.COUNTIFS": "COUNTIFS",
12723 "_xlfn.COVARIANCE.P": "COVARIANCE.P",
12724 "_xlfn.COVARIANCE.S": "COVARIANCE.S",
12725 "_xlfn.CSC": "CSC",
12726 "_xlfn.CSCH": "CSCH",
12727 "_xlfn.DAYS": "DAYS",
12728 "_xlfn.DECIMAL": "DECIMAL",
12729 "_xlfn.ECMA.CEILING": "ECMA.CEILING",
12730 "_xlfn.ERF.PRECISE": "ERF.PRECISE",
12731 "_xlfn.ERFC.PRECISE": "ERFC.PRECISE",
12732 "_xlfn.EXPON.DIST": "EXPON.DIST",
12733 "_xlfn.F.DIST": "F.DIST",
12734 "_xlfn.F.DIST.RT": "F.DIST.RT",
12735 "_xlfn.F.INV": "F.INV",
12736 "_xlfn.F.INV.RT": "F.INV.RT",
12737 "_xlfn.F.TEST": "F.TEST",
12738 "_xlfn.FILTERXML": "FILTERXML",
12739 "_xlfn.FLOOR.MATH": "FLOOR.MATH",
12740 "_xlfn.FLOOR.PRECISE": "FLOOR.PRECISE",
12741 "_xlfn.FORECAST.ETS": "FORECAST.ETS",
12742 "_xlfn.FORECAST.ETS.CONFINT": "FORECAST.ETS.CONFINT",
12743 "_xlfn.FORECAST.ETS.SEASONALITY": "FORECAST.ETS.SEASONALITY",
12744 "_xlfn.FORECAST.ETS.STAT": "FORECAST.ETS.STAT",
12745 "_xlfn.FORECAST.LINEAR": "FORECAST.LINEAR",
12746 "_xlfn.FORMULATEXT": "FORMULATEXT",
12747 "_xlfn.GAMMA": "GAMMA",
12748 "_xlfn.GAMMA.DIST": "GAMMA.DIST",
12749 "_xlfn.GAMMA.INV": "GAMMA.INV",
12750 "_xlfn.GAMMALN.PRECISE": "GAMMALN.PRECISE",
12751 "_xlfn.GAUSS": "GAUSS",
12752 "_xlfn.HYPGEOM.DIST": "HYPGEOM.DIST",
12753 "_xlfn.IFERROR": "IFERROR",
12754 "_xlfn.IFNA": "IFNA",
12755 "_xlfn.IFS": "IFS",
12756 "_xlfn.IMCOSH": "IMCOSH",
12757 "_xlfn.IMCOT": "IMCOT",
12758 "_xlfn.IMCSC": "IMCSC",
12759 "_xlfn.IMCSCH": "IMCSCH",
12760 "_xlfn.IMSEC": "IMSEC",
12761 "_xlfn.IMSECH": "IMSECH",
12762 "_xlfn.IMSINH": "IMSINH",
12763 "_xlfn.IMTAN": "IMTAN",
12764 "_xlfn.ISFORMULA": "ISFORMULA",
12765 "_xlfn.ISO.CEILING": "ISO.CEILING",
12766 "_xlfn.ISOWEEKNUM": "ISOWEEKNUM",
12767 "_xlfn.LOGNORM.DIST": "LOGNORM.DIST",
12768 "_xlfn.LOGNORM.INV": "LOGNORM.INV",
12769 "_xlfn.MAXIFS": "MAXIFS",
12770 "_xlfn.MINIFS": "MINIFS",
12771 "_xlfn.MODE.MULT": "MODE.MULT",
12772 "_xlfn.MODE.SNGL": "MODE.SNGL",
12773 "_xlfn.MUNIT": "MUNIT",
12774 "_xlfn.NEGBINOM.DIST": "NEGBINOM.DIST",
12775 "_xlfn.NETWORKDAYS.INTL": "NETWORKDAYS.INTL",
12776 "_xlfn.NIGBINOM": "NIGBINOM",
12777 "_xlfn.NORM.DIST": "NORM.DIST",
12778 "_xlfn.NORM.INV": "NORM.INV",
12779 "_xlfn.NORM.S.DIST": "NORM.S.DIST",
12780 "_xlfn.NORM.S.INV": "NORM.S.INV",
12781 "_xlfn.NUMBERVALUE": "NUMBERVALUE",
12782 "_xlfn.PDURATION": "PDURATION",
12783 "_xlfn.PERCENTILE.EXC": "PERCENTILE.EXC",
12784 "_xlfn.PERCENTILE.INC": "PERCENTILE.INC",
12785 "_xlfn.PERCENTRANK.EXC": "PERCENTRANK.EXC",
12786 "_xlfn.PERCENTRANK.INC": "PERCENTRANK.INC",
12787 "_xlfn.PERMUTATIONA": "PERMUTATIONA",
12788 "_xlfn.PHI": "PHI",
12789 "_xlfn.POISSON.DIST": "POISSON.DIST",
12790 "_xlfn.QUARTILE.EXC": "QUARTILE.EXC",
12791 "_xlfn.QUARTILE.INC": "QUARTILE.INC",
12792 "_xlfn.QUERYSTRING": "QUERYSTRING",
12793 "_xlfn.RANK.AVG": "RANK.AVG",
12794 "_xlfn.RANK.EQ": "RANK.EQ",
12795 "_xlfn.RRI": "RRI",
12796 "_xlfn.SEC": "SEC",
12797 "_xlfn.SECH": "SECH",
12798 "_xlfn.SHEET": "SHEET",
12799 "_xlfn.SHEETS": "SHEETS",
12800 "_xlfn.SKEW.P": "SKEW.P",
12801 "_xlfn.STDEV.P": "STDEV.P",
12802 "_xlfn.STDEV.S": "STDEV.S",
12803 "_xlfn.SUMIFS": "SUMIFS",
12804 "_xlfn.SWITCH": "SWITCH",
12805 "_xlfn.T.DIST": "T.DIST",
12806 "_xlfn.T.DIST.2T": "T.DIST.2T",
12807 "_xlfn.T.DIST.RT": "T.DIST.RT",
12808 "_xlfn.T.INV": "T.INV",
12809 "_xlfn.T.INV.2T": "T.INV.2T",
12810 "_xlfn.T.TEST": "T.TEST",
12811 "_xlfn.TEXTJOIN": "TEXTJOIN",
12812 "_xlfn.UNICHAR": "UNICHAR",
12813 "_xlfn.UNICODE": "UNICODE",
12814 "_xlfn.VAR.P": "VAR.P",
12815 "_xlfn.VAR.S": "VAR.S",
12816 "_xlfn.WEBSERVICE": "WEBSERVICE",
12817 "_xlfn.WEIBULL.DIST": "WEIBULL.DIST",
12818 "_xlfn.WORKDAY.INTL": "WORKDAY.INTL",
12819 "_xlfn.XOR": "XOR",
12820 "_xlfn.Z.TEST": "Z.TEST"
12821};
12822
12823/* Part 3 TODO: actually parse formulae */
12824function ods_to_csf_formula(f) {
12825 if(f.slice(0,3) == "of:") f = f.slice(3);
12826 /* 5.2 Basic Expressions */
12827 if(f.charCodeAt(0) == 61) {
12828 f = f.slice(1);
12829 if(f.charCodeAt(0) == 61) f = f.slice(1);
12830 }
12831 f = f.replace(/COM\.MICROSOFT\./g, "");
12832 /* Part 3 Section 5.8 References */
12833 f = f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, function($$, $1) { return $1.replace(/\./g,""); });
12834 /* TODO: something other than this */
12835 f = f.replace(/\[.(#[A-Z]*[?!])\]/g, "$1");
12836 return f.replace(/[;~]/g,",").replace(/\|/g,";");
12837}
12838
12839function csf_to_ods_formula(f) {
12840 var o = "of:=" + f.replace(crefregex, "$1[.$2$3$4$5]").replace(/\]:\[/g,":");
12841 /* TODO: something other than this */
12842 return o.replace(/;/g, "|").replace(/,/g,";");
12843}
12844
12845function ods_to_csf_3D(r) {
12846 var a = r.split(":");
12847 var s = a[0].split(".")[0];
12848 return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
12849}
12850
12851function csf_to_ods_3D(r) {
12852 return r.replace(/\./,"!");
12853}
12854
12855var strs = {}; // shared strings
12856var _ssfopts = {}; // spreadsheet formatting options
12857
12858RELS.WS = [
12859 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
12860 "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
12861];
12862
12863/*global Map */
12864var browser_has_Map = typeof Map !== 'undefined';
12865
12866function get_sst_id(sst, str, rev) {
12867 var i = 0, len = sst.length;
12868 if(rev) {
12869 if(browser_has_Map ? rev.has(str) : rev.hasOwnProperty(str)) {
12870 var revarr = browser_has_Map ? rev.get(str) : rev[str];
12871 for(; i < revarr.length; ++i) {
12872 if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
12873 }
12874 }
12875 } else for(; i < len; ++i) {
12876 if(sst[i].t === str) { sst.Count ++; return i; }
12877 }
12878 sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
12879 if(rev) {
12880 if(browser_has_Map) {
12881 if(!rev.has(str)) rev.set(str, []);
12882 rev.get(str).push(len);
12883 } else {
12884 if(!rev.hasOwnProperty(str)) rev[str] = [];
12885 rev[str].push(len);
12886 }
12887 }
12888 return len;
12889}
12890
12891function col_obj_w(C, col) {
12892 var p = ({min:C+1,max:C+1});
12893 /* wch (chars), wpx (pixels) */
12894 var wch = -1;
12895 if(col.MDW) MDW = col.MDW;
12896 if(col.width != null) p.customWidth = 1;
12897 else if(col.wpx != null) wch = px2char(col.wpx);
12898 else if(col.wch != null) wch = col.wch;
12899 if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
12900 else if(col.width != null) p.width = col.width;
12901 if(col.hidden) p.hidden = true;
12902 return p;
12903}
12904
12905function default_margins(margins, mode) {
12906 if(!margins) return;
12907 var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
12908 if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
12909 if(margins.left == null) margins.left = defs[0];
12910 if(margins.right == null) margins.right = defs[1];
12911 if(margins.top == null) margins.top = defs[2];
12912 if(margins.bottom == null) margins.bottom = defs[3];
12913 if(margins.header == null) margins.header = defs[4];
12914 if(margins.footer == null) margins.footer = defs[5];
12915}
12916
12917function get_cell_style(styles, cell, opts) {
12918 var z = opts.revssf[cell.z != null ? cell.z : "General"];
12919 var i = 0x3c, len = styles.length;
12920 if(z == null && opts.ssf) {
12921 for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
12922 SSF.load(cell.z, i);
12923 // $FlowIgnore
12924 opts.ssf[i] = cell.z;
12925 opts.revssf[cell.z] = z = i;
12926 break;
12927 }
12928 }
12929 for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
12930 styles[len] = {
12931 numFmtId:z,
12932 fontId:0,
12933 fillId:0,
12934 borderId:0,
12935 xfId:0,
12936 applyNumberFormat:1
12937 };
12938 return len;
12939}
12940
12941function safe_format(p, fmtid, fillid, opts, themes, styles) {
12942 if(p.t === 'z') return;
12943 if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
12944 try {
12945 if(opts.cellNF) p.z = SSF._table[fmtid];
12946 } catch(e) { if(opts.WTF) throw e; }
12947 if(!opts || opts.cellText !== false) try {
12948 if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
12949 if(p.t === 'e') p.w = p.w || BErr[p.v];
12950 else if(fmtid === 0) {
12951 if(p.t === 'n') {
12952 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
12953 else p.w = SSF._general_num(p.v);
12954 }
12955 else if(p.t === 'd') {
12956 var dd = datenum(p.v);
12957 if((dd|0) === dd) p.w = SSF._general_int(dd);
12958 else p.w = SSF._general_num(dd);
12959 }
12960 else if(p.v === undefined) return "";
12961 else p.w = SSF._general(p.v,_ssfopts);
12962 }
12963 else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
12964 else p.w = SSF.format(fmtid,p.v,_ssfopts);
12965 } catch(e) { if(opts.WTF) throw e; }
12966 if(!opts.cellStyles) return;
12967 if(fillid != null) try {
12968 p.s = styles.Fills[fillid];
12969 if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
12970 p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
12971 if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
12972 }
12973 if (p.s.bgColor && p.s.bgColor.theme) {
12974 p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
12975 if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
12976 }
12977 } catch(e) { if(opts.WTF && styles.Fills) throw e; }
12978}
12979
12980function check_ws(ws, sname, i) {
12981 if(ws && ws['!ref']) {
12982 var range = safe_decode_range(ws['!ref']);
12983 if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
12984 }
12985}
12986function parse_ws_xml_dim(ws, s) {
12987 var d = safe_decode_range(s);
12988 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);
12989}
12990var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
12991var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
12992var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
12993var dimregex = /"(\w*:\w*)"/;
12994var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
12995var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
12996var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
12997var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
12998var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
12999
13000/* 18.3 Worksheets */
13001function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
13002 if(!data) return data;
13003 if(!rels) rels = {'!id':{}};
13004 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
13005
13006 /* 18.3.1.99 worksheet CT_Worksheet */
13007 var s = opts.dense ? ([]) : ({});
13008 var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
13009
13010 var data1 = "", data2 = "";
13011 var mtch = data.match(sheetdataregex);
13012 if(mtch) {
13013 data1 = data.slice(0, mtch.index);
13014 data2 = data.slice(mtch.index + mtch[0].length);
13015 } else data1 = data2 = data;
13016
13017 /* 18.3.1.82 sheetPr CT_SheetPr */
13018 var sheetPr = data1.match(sheetprregex);
13019 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
13020
13021 /* 18.3.1.35 dimension CT_SheetDimension */
13022 var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
13023 if(ridx > 0) {
13024 var ref = data1.slice(ridx,ridx+50).match(dimregex);
13025 if(ref) parse_ws_xml_dim(s, ref[1]);
13026 }
13027
13028 /* 18.3.1.88 sheetViews CT_SheetViews */
13029 var svs = data1.match(svsregex);
13030 if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
13031
13032 /* 18.3.1.17 cols CT_Cols */
13033 var columns = [];
13034 if(opts.cellStyles) {
13035 /* 18.3.1.13 col CT_Col */
13036 var cols = data1.match(colregex);
13037 if(cols) parse_ws_xml_cols(columns, cols);
13038 }
13039
13040 /* 18.3.1.80 sheetData CT_SheetData ? */
13041 if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
13042
13043 /* 18.3.1.2 autoFilter CT_AutoFilter */
13044 var afilter = data2.match(afregex);
13045 if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
13046
13047 /* 18.3.1.55 mergeCells CT_MergeCells */
13048 var merges = [];
13049 var _merge = data2.match(mergecregex);
13050 if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
13051 merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
13052
13053 /* 18.3.1.48 hyperlinks CT_Hyperlinks */
13054 var hlink = data2.match(hlinkregex);
13055 if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
13056
13057 /* 18.3.1.62 pageMargins CT_PageMargins */
13058 var margins = data2.match(marginregex);
13059 if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
13060
13061 if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
13062 if(opts.sheetRows > 0 && s["!ref"]) {
13063 var tmpref = safe_decode_range(s["!ref"]);
13064 if(opts.sheetRows <= +tmpref.e.r) {
13065 tmpref.e.r = opts.sheetRows - 1;
13066 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
13067 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
13068 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
13069 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
13070 s["!fullref"] = s["!ref"];
13071 s["!ref"] = encode_range(tmpref);
13072 }
13073 }
13074 if(columns.length > 0) s["!cols"] = columns;
13075 if(merges.length > 0) s["!merges"] = merges;
13076 return s;
13077}
13078
13079function write_ws_xml_merges(merges) {
13080 if(merges.length === 0) return "";
13081 var o = '<mergeCells count="' + merges.length + '">';
13082 for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
13083 return o + '</mergeCells>';
13084}
13085
13086/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
13087function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
13088 var data = parsexmltag(sheetPr);
13089 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13090 if(data.codeName) wb.Sheets[idx].CodeName = data.codeName;
13091}
13092function write_ws_xml_sheetpr(ws, wb, idx, opts, o) {
13093 var needed = false;
13094 var props = {}, payload = null;
13095 if(opts.bookType !== 'xlsx' && wb.vbaraw) {
13096 var cname = wb.SheetNames[idx];
13097 try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
13098 needed = true;
13099 props.codeName = escapexml(cname);
13100 }
13101
13102 if(!needed && !payload) return;
13103 o[o.length] = (writextag('sheetPr', payload, props));
13104}
13105
13106/* 18.3.1.85 sheetProtection CT_SheetProtection */
13107var sheetprot_deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
13108var sheetprot_deftrue = [
13109 "formatColumns", "formatRows", "formatCells",
13110 "insertColumns", "insertRows", "insertHyperlinks",
13111 "deleteColumns", "deleteRows",
13112 "sort", "autoFilter", "pivotTables"
13113];
13114function write_ws_xml_protection(sp) {
13115 // algorithmName, hashValue, saltValue, spinCountpassword
13116 var o = ({sheet:1});
13117 sheetprot_deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
13118 sheetprot_deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
13119 /* TODO: algorithm */
13120 if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
13121 return writextag('sheetProtection', null, o);
13122}
13123
13124function parse_ws_xml_hlinks(s, data, rels) {
13125 var dense = Array.isArray(s);
13126 for(var i = 0; i != data.length; ++i) {
13127 var val = parsexmltag(utf8read(data[i]), true);
13128 if(!val.ref) return;
13129 var rel = ((rels || {})['!id']||[])[val.id];
13130 if(rel) {
13131 val.Target = rel.Target;
13132 if(val.location) val.Target += "#"+val.location;
13133 } else {
13134 val.Target = "#" + val.location;
13135 rel = {Target: val.Target, TargetMode: 'Internal'};
13136 }
13137 val.Rel = rel;
13138 if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
13139 var rng = safe_decode_range(val.ref);
13140 for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
13141 var addr = encode_cell({c:C,r:R});
13142 if(dense) {
13143 if(!s[R]) s[R] = [];
13144 if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
13145 s[R][C].l = val;
13146 } else {
13147 if(!s[addr]) s[addr] = {t:"z",v:undefined};
13148 s[addr].l = val;
13149 }
13150 }
13151 }
13152}
13153
13154function parse_ws_xml_margins(margin) {
13155 var o = {};
13156 ["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
13157 if(margin[k]) o[k] = parseFloat(margin[k]);
13158 });
13159 return o;
13160}
13161function write_ws_xml_margins(margin) {
13162 default_margins(margin);
13163 return writextag('pageMargins', null, margin);
13164}
13165
13166function parse_ws_xml_cols(columns, cols) {
13167 var seencol = false;
13168 for(var coli = 0; coli != cols.length; ++coli) {
13169 var coll = parsexmltag(cols[coli], true);
13170 if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
13171 var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
13172 delete coll.min; delete coll.max; coll.width = +coll.width;
13173 if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
13174 process_col(coll);
13175 while(colm <= colM) columns[colm++] = dup(coll);
13176 }
13177}
13178function write_ws_xml_cols(ws, cols) {
13179 var o = ["<cols>"], col;
13180 for(var i = 0; i != cols.length; ++i) {
13181 if(!(col = cols[i])) continue;
13182 o[o.length] = (writextag('col', null, col_obj_w(i, col)));
13183 }
13184 o[o.length] = "</cols>";
13185 return o.join("");
13186}
13187
13188function parse_ws_xml_autofilter(data) {
13189 var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
13190 return o;
13191}
13192function write_ws_xml_autofilter(data, ws, wb, idx) {
13193 var ref = typeof data.ref == "string" ? data.ref : encode_range(data.ref);
13194 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
13195 if(!wb.Workbook.Names) wb.Workbook.Names = [];
13196 var names = wb.Workbook.Names;
13197 var range = decode_range(ref);
13198 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
13199 for(var i = 0; i < names.length; ++i) {
13200 var name = names[i];
13201 if(name.Name != '_xlnm._FilterDatabase') continue;
13202 if(name.Sheet != idx) continue;
13203 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
13204 }
13205 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
13206 return writextag("autoFilter", null, {ref:ref});
13207}
13208
13209/* 18.3.1.88 sheetViews CT_SheetViews */
13210/* 18.3.1.87 sheetView CT_SheetView */
13211var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/;
13212function parse_ws_xml_sheetviews(data, wb) {
13213 if(!wb.Views) wb.Views = [{}];
13214 (data.match(sviewregex)||[]).forEach(function(r, i) {
13215 var tag = parsexmltag(r);
13216 // $FlowIgnore
13217 if(!wb.Views[i]) wb.Views[i] = {};
13218 // $FlowIgnore
13219 if(parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true;
13220 });
13221}
13222function write_ws_xml_sheetviews(ws, opts, idx, wb) {
13223 var sview = ({workbookViewId:"0"});
13224 // $FlowIgnore
13225 if((((wb||{}).Workbook||{}).Views||[])[0]) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
13226 return writextag("sheetViews", writextag("sheetView", null, sview), {});
13227}
13228
13229function write_ws_xml_cell(cell, ref, ws, opts) {
13230 if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return "";
13231 var vv = "";
13232 var oldt = cell.t, oldv = cell.v;
13233 if(cell.t !== "z") switch(cell.t) {
13234 case 'b': vv = cell.v ? "1" : "0"; break;
13235 case 'n': vv = ''+cell.v; break;
13236 case 'e': vv = BErr[cell.v]; break;
13237 case 'd':
13238 if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
13239 else {
13240 cell = dup(cell);
13241 cell.t = 'n';
13242 vv = ''+(cell.v = datenum(parseDate(cell.v)));
13243 }
13244 if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
13245 break;
13246 default: vv = cell.v; break;
13247 }
13248 var v = writetag('v', escapexml(vv)), o = ({r:ref});
13249 /* TODO: cell style */
13250 var os = get_cell_style(opts.cellXfs, cell, opts);
13251 if(os !== 0) o.s = os;
13252 switch(cell.t) {
13253 case 'n': break;
13254 case 'd': o.t = "d"; break;
13255 case 'b': o.t = "b"; break;
13256 case 'e': o.t = "e"; break;
13257 case 'z': break;
13258 default: if(cell.v == null) { delete cell.t; break; }
13259 if(opts && opts.bookSST) {
13260 v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
13261 o.t = "s"; break;
13262 }
13263 o.t = "str"; break;
13264 }
13265 if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
13266 if(cell.f) {
13267 var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
13268 v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
13269 }
13270 if(cell.l) ws['!links'].push([ref, cell.l]);
13271 if(cell.c) ws['!comments'].push([ref, cell.c]);
13272 return writextag('c', v, o);
13273}
13274
13275var parse_ws_xml_data = (function() {
13276 var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
13277 var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
13278 var refregex = /ref=["']([^"']*)["']/;
13279 var match_v = matchtag("v"), match_f = matchtag("f");
13280
13281return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
13282 var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
13283 var tag, tagr = 0, tagc = 0;
13284 var sstr, ftag;
13285 var fmtid = 0, fillid = 0;
13286 var do_format = Array.isArray(styles.CellXf), cf;
13287 var arrayf = [];
13288 var sharedf = [];
13289 var dense = Array.isArray(s);
13290 var rows = [], rowobj = {}, rowrite = false;
13291 for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
13292 x = marr[mt].trim();
13293 var xlen = x.length;
13294 if(xlen === 0) continue;
13295
13296 /* 18.3.1.73 row CT_Row */
13297 for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
13298 tag = parsexmltag(x.slice(0,ri), true);
13299 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
13300 if(opts.sheetRows && opts.sheetRows < tagr) continue;
13301 if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
13302 if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
13303
13304 if(opts && opts.cellStyles) {
13305 rowobj = {}; rowrite = false;
13306 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
13307 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
13308 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
13309 if(rowrite) rows[tagr-1] = rowobj;
13310 }
13311
13312 /* 18.3.1.4 c CT_Cell */
13313 cells = x.slice(ri).split(cellregex);
13314 for(var rslice = 0; rslice != cells.length; ++rslice) if(cells[rslice].trim().charAt(0) != "<") break;
13315 cells = cells.slice(rslice);
13316 for(ri = 0; ri != cells.length; ++ri) {
13317 x = cells[ri].trim();
13318 if(x.length === 0) continue;
13319 cref = x.match(rregex); idx = ri; i=0; cc=0;
13320 x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
13321 if(cref != null && cref.length === 2) {
13322 idx = 0; d=cref[1];
13323 for(i=0; i != d.length; ++i) {
13324 if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
13325 idx = 26*idx + cc;
13326 }
13327 --idx;
13328 tagc = idx;
13329 } else ++tagc;
13330 for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
13331 tag = parsexmltag(x.slice(0,i), true);
13332 if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
13333 d = x.slice(i);
13334 p = ({t:""});
13335
13336 if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
13337 if(opts.cellFormula) {
13338 if((cref=d.match(match_f))!= null && cref[1] !== '') {
13339 /* TODO: match against XLSXFutureFunctions */
13340 p.f=_xlfn(unescapexml(utf8read(cref[1])));
13341 if(cref[0].indexOf('t="array"') > -1) {
13342 p.F = (d.match(refregex)||[])[1];
13343 if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
13344 } else if(cref[0].indexOf('t="shared"') > -1) {
13345 // TODO: parse formula
13346 ftag = parsexmltag(cref[0]);
13347 sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1]))), tag.r];
13348 }
13349 } else if((cref=d.match(/<f[^>]*\/>/))) {
13350 ftag = parsexmltag(cref[0]);
13351 if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
13352 }
13353 /* TODO: factor out contains logic */
13354 var _tag = decode_cell(tag.r);
13355 for(i = 0; i < arrayf.length; ++i)
13356 if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
13357 if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
13358 p.F = arrayf[i][1];
13359 }
13360
13361 if(tag.t == null && p.v === undefined) {
13362 if(p.f || p.F) {
13363 p.v = 0; p.t = "n";
13364 } else if(!opts.sheetStubs) continue;
13365 else p.t = "z";
13366 }
13367 else p.t = tag.t || "n";
13368 if(guess.s.c > tagc) guess.s.c = tagc;
13369 if(guess.e.c < tagc) guess.e.c = tagc;
13370 /* 18.18.11 t ST_CellType */
13371 switch(p.t) {
13372 case 'n':
13373 if(p.v == "" || p.v == null) {
13374 if(!opts.sheetStubs) continue;
13375 p.t = 'z';
13376 } else p.v = parseFloat(p.v);
13377 break;
13378 case 's':
13379 if(typeof p.v == 'undefined') {
13380 if(!opts.sheetStubs) continue;
13381 p.t = 'z';
13382 } else {
13383 sstr = strs[parseInt(p.v, 10)];
13384 p.v = sstr.t;
13385 p.r = sstr.r;
13386 if(opts.cellHTML) p.h = sstr.h;
13387 }
13388 break;
13389 case 'str':
13390 p.t = "s";
13391 p.v = (p.v!=null) ? utf8read(p.v) : '';
13392 if(opts.cellHTML) p.h = escapehtml(p.v);
13393 break;
13394 case 'inlineStr':
13395 cref = d.match(isregex);
13396 p.t = 's';
13397 if(cref != null && (sstr = parse_si(cref[1]))) {
13398 p.v = sstr.t;
13399 if(opts.cellHTML) p.h = sstr.h;
13400 } else p.v = "";
13401 break;
13402 case 'b': p.v = parsexmlbool(p.v); break;
13403 case 'd':
13404 if(opts.cellDates) p.v = parseDate(p.v, 1);
13405 else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
13406 break;
13407 /* error string in .w, number in .v */
13408 case 'e':
13409 if(!opts || opts.cellText !== false) p.w = p.v;
13410 p.v = RBErr[p.v]; break;
13411 }
13412 /* formatting */
13413 fmtid = fillid = 0;
13414 cf = null;
13415 if(do_format && tag.s !== undefined) {
13416 cf = styles.CellXf[tag.s];
13417 if(cf != null) {
13418 if(cf.numFmtId != null) fmtid = cf.numFmtId;
13419 if(opts.cellStyles) {
13420 if(cf.fillId != null) fillid = cf.fillId;
13421 }
13422 }
13423 }
13424 safe_format(p, fmtid, fillid, opts, themes, styles);
13425 if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
13426 if(dense) {
13427 var _r = decode_cell(tag.r);
13428 if(!s[_r.r]) s[_r.r] = [];
13429 s[_r.r][_r.c] = p;
13430 } else s[tag.r] = p;
13431 }
13432 }
13433 if(rows.length > 0) s['!rows'] = rows;
13434}; })();
13435
13436function write_ws_xml_data(ws, opts, idx, wb) {
13437 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
13438 var dense = Array.isArray(ws);
13439 var params = ({r:rr}), row, height = -1;
13440 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
13441 for(R = range.s.r; R <= range.e.r; ++R) {
13442 r = [];
13443 rr = encode_row(R);
13444 for(C = range.s.c; C <= range.e.c; ++C) {
13445 ref = cols[C] + rr;
13446 var _cell = dense ? (ws[R]||[])[C]: ws[ref];
13447 if(_cell === undefined) continue;
13448 if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
13449 }
13450 if(r.length > 0 || (rows && rows[R])) {
13451 params = ({r:rr});
13452 if(rows && rows[R]) {
13453 row = rows[R];
13454 if(row.hidden) params.hidden = 1;
13455 height = -1;
13456 if(row.hpx) height = px2pt(row.hpx);
13457 else if(row.hpt) height = row.hpt;
13458 if(height > -1) { params.ht = height; params.customHeight = 1; }
13459 if(row.level) { params.outlineLevel = row.level; }
13460 }
13461 o[o.length] = (writextag('row', r.join(""), params));
13462 }
13463 }
13464 if(rows) for(; R < rows.length; ++R) {
13465 if(rows && rows[R]) {
13466 params = ({r:R+1});
13467 row = rows[R];
13468 if(row.hidden) params.hidden = 1;
13469 height = -1;
13470 if (row.hpx) height = px2pt(row.hpx);
13471 else if (row.hpt) height = row.hpt;
13472 if (height > -1) { params.ht = height; params.customHeight = 1; }
13473 if (row.level) { params.outlineLevel = row.level; }
13474 o[o.length] = (writextag('row', "", params));
13475 }
13476 }
13477 return o.join("");
13478}
13479
13480var WS_XML_ROOT = writextag('worksheet', null, {
13481 'xmlns': XMLNS.main[0],
13482 'xmlns:r': XMLNS.r
13483});
13484
13485function write_ws_xml(idx, opts, wb, rels) {
13486 var o = [XML_HEADER, WS_XML_ROOT];
13487 var s = wb.SheetNames[idx], sidx = 0, rdata = "";
13488 var ws = wb.Sheets[s];
13489 if(ws == null) ws = {};
13490 var ref = ws['!ref'] || 'A1';
13491 var range = safe_decode_range(ref);
13492 if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
13493 if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
13494 range.e.c = Math.min(range.e.c, 0x3FFF);
13495 range.e.r = Math.min(range.e.c, 0xFFFFF);
13496 ref = encode_range(range);
13497 }
13498 if(!rels) rels = {};
13499 ws['!comments'] = [];
13500 var _drawing = [];
13501
13502 write_ws_xml_sheetpr(ws, wb, idx, opts, o);
13503
13504 o[o.length] = (writextag('dimension', null, {'ref': ref}));
13505
13506 o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
13507
13508 /* TODO: store in WB, process styles */
13509 if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
13510 defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
13511 baseColWidth:opts.sheetFormat.baseColWidth||'10',
13512 outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
13513 }));
13514
13515 if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
13516
13517 o[sidx = o.length] = '<sheetData/>';
13518 ws['!links'] = [];
13519 if(ws['!ref'] != null) {
13520 rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
13521 if(rdata.length > 0) o[o.length] = (rdata);
13522 }
13523 if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
13524
13525 /* sheetCalcPr */
13526
13527 if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
13528
13529 /* protectedRanges */
13530 /* scenarios */
13531
13532 if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter'], ws, wb, idx);
13533
13534 /* sortState */
13535 /* dataConsolidate */
13536 /* customSheetViews */
13537
13538 if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
13539
13540 /* phoneticPr */
13541 /* conditionalFormatting */
13542 /* dataValidations */
13543
13544 var relc = -1, rel, rId = -1;
13545 if(ws['!links'].length > 0) {
13546 o[o.length] = "<hyperlinks>";
13547ws['!links'].forEach(function(l) {
13548 if(!l[1].Target) return;
13549 rel = ({"ref":l[0]});
13550 if(l[1].Target.charAt(0) != "#") {
13551 rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
13552 rel["r:id"] = "rId"+rId;
13553 }
13554 if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
13555 if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
13556 o[o.length] = writextag("hyperlink",null,rel);
13557 });
13558 o[o.length] = "</hyperlinks>";
13559 }
13560 delete ws['!links'];
13561
13562 /* printOptions */
13563
13564 if(ws['!margins'] != null) o[o.length] = write_ws_xml_margins(ws['!margins']);
13565
13566 /* pageSetup */
13567 /* headerFooter */
13568 /* rowBreaks */
13569 /* colBreaks */
13570 /* customProperties */
13571 /* cellWatches */
13572
13573 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
13574
13575 /* smartTags */
13576
13577 if(_drawing.length > 0) {
13578 rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
13579 o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
13580 ws['!drawing'] = _drawing;
13581 }
13582
13583 if(ws['!comments'].length > 0) {
13584 rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
13585 o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
13586 ws['!legacy'] = rId;
13587 }
13588
13589 /* legacyDrawingHF */
13590 /* picture */
13591 /* oleObjects */
13592 /* controls */
13593 /* webPublishItems */
13594 /* tableParts */
13595 /* extLst */
13596
13597 if(o.length>1) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
13598 return o.join("");
13599}
13600
13601/* [MS-XLSB] 2.4.726 BrtRowHdr */
13602function parse_BrtRowHdr(data, length) {
13603 var z = ({});
13604 var tgt = data.l + length;
13605 z.r = data.read_shift(4);
13606 data.l += 4; // TODO: ixfe
13607 var miyRw = data.read_shift(2);
13608 data.l += 1; // TODO: top/bot padding
13609 var flags = data.read_shift(1);
13610 data.l = tgt;
13611 if(flags & 0x07) z.level = flags & 0x07;
13612 if(flags & 0x10) z.hidden = true;
13613 if(flags & 0x20) z.hpt = miyRw / 20;
13614 return z;
13615}
13616function write_BrtRowHdr(R, range, ws) {
13617 var o = new_buf(17+8*16);
13618 var row = (ws['!rows']||[])[R]||{};
13619 o.write_shift(4, R);
13620
13621 o.write_shift(4, 0); /* TODO: ixfe */
13622
13623 var miyRw = 0x0140;
13624 if(row.hpx) miyRw = px2pt(row.hpx) * 20;
13625 else if(row.hpt) miyRw = row.hpt * 20;
13626 o.write_shift(2, miyRw);
13627
13628 o.write_shift(1, 0); /* top/bot padding */
13629
13630 var flags = 0x0;
13631 if(row.level) flags |= row.level;
13632 if(row.hidden) flags |= 0x10;
13633 if(row.hpx || row.hpt) flags |= 0x20;
13634 o.write_shift(1, flags);
13635
13636 o.write_shift(1, 0); /* phonetic guide */
13637
13638 /* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
13639 var ncolspan = 0, lcs = o.l;
13640 o.l += 4;
13641
13642 var caddr = {r:R, c:0};
13643 for(var i = 0; i < 16; ++i) {
13644 if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue;
13645 var first = -1, last = -1;
13646 for(var j = (i<<10); j < ((i+1)<<10); ++j) {
13647 caddr.c = j;
13648 var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
13649 if(cell) { if(first < 0) first = j; last = j; }
13650 }
13651 if(first < 0) continue;
13652 ++ncolspan;
13653 o.write_shift(4, first);
13654 o.write_shift(4, last);
13655 }
13656
13657 var l = o.l;
13658 o.l = lcs;
13659 o.write_shift(4, ncolspan);
13660 o.l = l;
13661
13662 return o.length > o.l ? o.slice(0, o.l) : o;
13663}
13664function write_row_header(ba, ws, range, R) {
13665 var o = write_BrtRowHdr(R, range, ws);
13666 if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o);
13667}
13668
13669/* [MS-XLSB] 2.4.820 BrtWsDim */
13670var parse_BrtWsDim = parse_UncheckedRfX;
13671var write_BrtWsDim = write_UncheckedRfX;
13672
13673/* [MS-XLSB] 2.4.821 BrtWsFmtInfo */
13674function parse_BrtWsFmtInfo() {
13675}
13676//function write_BrtWsFmtInfo(ws, o) { }
13677
13678/* [MS-XLSB] 2.4.823 BrtWsProp */
13679function parse_BrtWsProp(data, length) {
13680 var z = {};
13681 /* TODO: pull flags */
13682 data.l += 19;
13683 z.name = parse_XLSBCodeName(data, length - 19);
13684 return z;
13685}
13686function write_BrtWsProp(str, o) {
13687 if(o == null) o = new_buf(84+4*str.length);
13688 for(var i = 0; i < 3; ++i) o.write_shift(1,0);
13689 write_BrtColor({auto:1}, o);
13690 o.write_shift(-4,-1);
13691 o.write_shift(-4,-1);
13692 write_XLSBCodeName(str, o);
13693 return o.slice(0, o.l);
13694}
13695
13696/* [MS-XLSB] 2.4.306 BrtCellBlank */
13697function parse_BrtCellBlank(data) {
13698 var cell = parse_XLSBCell(data);
13699 return [cell];
13700}
13701function write_BrtCellBlank(cell, ncell, o) {
13702 if(o == null) o = new_buf(8);
13703 return write_XLSBCell(ncell, o);
13704}
13705
13706
13707/* [MS-XLSB] 2.4.307 BrtCellBool */
13708function parse_BrtCellBool(data) {
13709 var cell = parse_XLSBCell(data);
13710 var fBool = data.read_shift(1);
13711 return [cell, fBool, 'b'];
13712}
13713function write_BrtCellBool(cell, ncell, o) {
13714 if(o == null) o = new_buf(9);
13715 write_XLSBCell(ncell, o);
13716 o.write_shift(1, cell.v ? 1 : 0);
13717 return o;
13718}
13719
13720/* [MS-XLSB] 2.4.308 BrtCellError */
13721function parse_BrtCellError(data) {
13722 var cell = parse_XLSBCell(data);
13723 var bError = data.read_shift(1);
13724 return [cell, bError, 'e'];
13725}
13726
13727/* [MS-XLSB] 2.4.311 BrtCellIsst */
13728function parse_BrtCellIsst(data) {
13729 var cell = parse_XLSBCell(data);
13730 var isst = data.read_shift(4);
13731 return [cell, isst, 's'];
13732}
13733function write_BrtCellIsst(cell, ncell, o) {
13734 if(o == null) o = new_buf(12);
13735 write_XLSBCell(ncell, o);
13736 o.write_shift(4, ncell.v);
13737 return o;
13738}
13739
13740/* [MS-XLSB] 2.4.313 BrtCellReal */
13741function parse_BrtCellReal(data) {
13742 var cell = parse_XLSBCell(data);
13743 var value = parse_Xnum(data);
13744 return [cell, value, 'n'];
13745}
13746function write_BrtCellReal(cell, ncell, o) {
13747 if(o == null) o = new_buf(16);
13748 write_XLSBCell(ncell, o);
13749 write_Xnum(cell.v, o);
13750 return o;
13751}
13752
13753/* [MS-XLSB] 2.4.314 BrtCellRk */
13754function parse_BrtCellRk(data) {
13755 var cell = parse_XLSBCell(data);
13756 var value = parse_RkNumber(data);
13757 return [cell, value, 'n'];
13758}
13759function write_BrtCellRk(cell, ncell, o) {
13760 if(o == null) o = new_buf(12);
13761 write_XLSBCell(ncell, o);
13762 write_RkNumber(cell.v, o);
13763 return o;
13764}
13765
13766
13767/* [MS-XLSB] 2.4.317 BrtCellSt */
13768function parse_BrtCellSt(data) {
13769 var cell = parse_XLSBCell(data);
13770 var value = parse_XLWideString(data);
13771 return [cell, value, 'str'];
13772}
13773function write_BrtCellSt(cell, ncell, o) {
13774 if(o == null) o = new_buf(12 + 4 * cell.v.length);
13775 write_XLSBCell(ncell, o);
13776 write_XLWideString(cell.v, o);
13777 return o.length > o.l ? o.slice(0, o.l) : o;
13778}
13779
13780/* [MS-XLSB] 2.4.653 BrtFmlaBool */
13781function parse_BrtFmlaBool(data, length, opts) {
13782 var end = data.l + length;
13783 var cell = parse_XLSBCell(data);
13784 cell.r = opts['!row'];
13785 var value = data.read_shift(1);
13786 var o = [cell, value, 'b'];
13787 if(opts.cellFormula) {
13788 data.l += 2;
13789 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13790 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13791 }
13792 else data.l = end;
13793 return o;
13794}
13795
13796/* [MS-XLSB] 2.4.654 BrtFmlaError */
13797function parse_BrtFmlaError(data, length, opts) {
13798 var end = data.l + length;
13799 var cell = parse_XLSBCell(data);
13800 cell.r = opts['!row'];
13801 var value = data.read_shift(1);
13802 var o = [cell, value, 'e'];
13803 if(opts.cellFormula) {
13804 data.l += 2;
13805 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13806 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13807 }
13808 else data.l = end;
13809 return o;
13810}
13811
13812/* [MS-XLSB] 2.4.655 BrtFmlaNum */
13813function parse_BrtFmlaNum(data, length, opts) {
13814 var end = data.l + length;
13815 var cell = parse_XLSBCell(data);
13816 cell.r = opts['!row'];
13817 var value = parse_Xnum(data);
13818 var o = [cell, value, 'n'];
13819 if(opts.cellFormula) {
13820 data.l += 2;
13821 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13822 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13823 }
13824 else data.l = end;
13825 return o;
13826}
13827
13828/* [MS-XLSB] 2.4.656 BrtFmlaString */
13829function parse_BrtFmlaString(data, length, opts) {
13830 var end = data.l + length;
13831 var cell = parse_XLSBCell(data);
13832 cell.r = opts['!row'];
13833 var value = parse_XLWideString(data);
13834 var o = [cell, value, 'str'];
13835 if(opts.cellFormula) {
13836 data.l += 2;
13837 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13838 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13839 }
13840 else data.l = end;
13841 return o;
13842}
13843
13844/* [MS-XLSB] 2.4.682 BrtMergeCell */
13845var parse_BrtMergeCell = parse_UncheckedRfX;
13846var write_BrtMergeCell = write_UncheckedRfX;
13847/* [MS-XLSB] 2.4.107 BrtBeginMergeCells */
13848function write_BrtBeginMergeCells(cnt, o) {
13849 if(o == null) o = new_buf(4);
13850 o.write_shift(4, cnt);
13851 return o;
13852}
13853
13854/* [MS-XLSB] 2.4.662 BrtHLink */
13855function parse_BrtHLink(data, length) {
13856 var end = data.l + length;
13857 var rfx = parse_UncheckedRfX(data, 16);
13858 var relId = parse_XLNullableWideString(data);
13859 var loc = parse_XLWideString(data);
13860 var tooltip = parse_XLWideString(data);
13861 var display = parse_XLWideString(data);
13862 data.l = end;
13863 var o = ({rfx:rfx, relId:relId, loc:loc, display:display});
13864 if(tooltip) o.Tooltip = tooltip;
13865 return o;
13866}
13867function write_BrtHLink(l, rId) {
13868 var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
13869 write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
13870 write_RelID("rId" + rId, o);
13871 var locidx = l[1].Target.indexOf("#");
13872 var loc = locidx == -1 ? "" : l[1].Target.slice(locidx+1);
13873 write_XLWideString(loc || "", o);
13874 write_XLWideString(l[1].Tooltip || "", o);
13875 write_XLWideString("", o);
13876 return o.slice(0, o.l);
13877}
13878
13879/* [MS-XLSB] 2.4.692 BrtPane */
13880function parse_BrtPane(/*data, length, opts*/) {
13881}
13882
13883/* [MS-XLSB] 2.4.6 BrtArrFmla */
13884function parse_BrtArrFmla(data, length, opts) {
13885 var end = data.l + length;
13886 var rfx = parse_RfX(data, 16);
13887 var fAlwaysCalc = data.read_shift(1);
13888 var o = [rfx]; o[2] = fAlwaysCalc;
13889 if(opts.cellFormula) {
13890 var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts);
13891 o[1] = formula;
13892 } else data.l = end;
13893 return o;
13894}
13895
13896/* [MS-XLSB] 2.4.750 BrtShrFmla */
13897function parse_BrtShrFmla(data, length, opts) {
13898 var end = data.l + length;
13899 var rfx = parse_UncheckedRfX(data, 16);
13900 var o = [rfx];
13901 if(opts.cellFormula) {
13902 var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts);
13903 o[1] = formula;
13904 data.l = end;
13905 } else data.l = end;
13906 return o;
13907}
13908
13909/* [MS-XLSB] 2.4.323 BrtColInfo */
13910/* TODO: once XLS ColInfo is set, combine the functions */
13911function write_BrtColInfo(C, col, o) {
13912 if(o == null) o = new_buf(18);
13913 var p = col_obj_w(C, col);
13914 o.write_shift(-4, C);
13915 o.write_shift(-4, C);
13916 o.write_shift(4, (p.width || 10) * 256);
13917 o.write_shift(4, 0/*ixfe*/); // style
13918 var flags = 0;
13919 if(col.hidden) flags |= 0x01;
13920 if(typeof p.width == 'number') flags |= 0x02;
13921 if(col.level) flags |= (col.level << 8);
13922 o.write_shift(2, flags); // bit flag
13923 return o;
13924}
13925
13926/* [MS-XLSB] 2.4.678 BrtMargins */
13927var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
13928function parse_BrtMargins(data) {
13929 var margins = ({});
13930 BrtMarginKeys.forEach(function(k) { margins[k] = parse_Xnum(data, 8); });
13931 return margins;
13932}
13933function write_BrtMargins(margins, o) {
13934 if(o == null) o = new_buf(6*8);
13935 default_margins(margins);
13936 BrtMarginKeys.forEach(function(k) { write_Xnum((margins)[k], o); });
13937 return o;
13938}
13939
13940/* [MS-XLSB] 2.4.299 BrtBeginWsView */
13941function parse_BrtBeginWsView(data) {
13942 var f = data.read_shift(2);
13943 data.l += 28;
13944 return { RTL: f & 0x20 };
13945}
13946function write_BrtBeginWsView(ws, Workbook, o) {
13947 if(o == null) o = new_buf(30);
13948 var f = 0x39c;
13949 if((((Workbook||{}).Views||[])[0]||{}).RTL) f |= 0x20;
13950 o.write_shift(2, f); // bit flag
13951 o.write_shift(4, 0);
13952 o.write_shift(4, 0); // view first row
13953 o.write_shift(4, 0); // view first col
13954 o.write_shift(1, 0); // gridline color ICV
13955 o.write_shift(1, 0);
13956 o.write_shift(2, 0);
13957 o.write_shift(2, 100); // zoom scale
13958 o.write_shift(2, 0);
13959 o.write_shift(2, 0);
13960 o.write_shift(2, 0);
13961 o.write_shift(4, 0); // workbook view id
13962 return o;
13963}
13964
13965/* [MS-XLSB] 2.4.309 BrtCellIgnoreEC */
13966function write_BrtCellIgnoreEC(ref) {
13967 var o = new_buf(24);
13968 o.write_shift(4, 4);
13969 o.write_shift(4, 1);
13970 write_UncheckedRfX(ref, o);
13971 return o;
13972}
13973
13974/* [MS-XLSB] 2.4.748 BrtSheetProtection */
13975function write_BrtSheetProtection(sp, o) {
13976 if(o == null) o = new_buf(16*4+2);
13977 o.write_shift(2, sp.password ? crypto_CreatePasswordVerifier_Method1(sp.password) : 0);
13978 o.write_shift(4, 1); // this record should not be written if no protection
13979 [
13980 ["objects", false], // fObjects
13981 ["scenarios", false], // fScenarios
13982 ["formatCells", true], // fFormatCells
13983 ["formatColumns", true], // fFormatColumns
13984 ["formatRows", true], // fFormatRows
13985 ["insertColumns", true], // fInsertColumns
13986 ["insertRows", true], // fInsertRows
13987 ["insertHyperlinks", true], // fInsertHyperlinks
13988 ["deleteColumns", true], // fDeleteColumns
13989 ["deleteRows", true], // fDeleteRows
13990 ["selectLockedCells", false], // fSelLockedCells
13991 ["sort", true], // fSort
13992 ["autoFilter", true], // fAutoFilter
13993 ["pivotTables", true], // fPivotTables
13994 ["selectUnlockedCells", false] // fSelUnlockedCells
13995 ].forEach(function(n) {
13996if(n[1]) o.write_shift(4, sp[n[0]] != null && !sp[n[0]] ? 1 : 0);
13997 else o.write_shift(4, sp[n[0]] != null && sp[n[0]] ? 0 : 1);
13998 });
13999 return o;
14000}
14001
14002function parse_BrtDVal(/*data, length, opts*/) {
14003}
14004function parse_BrtDVal14(/*data, length, opts*/) {
14005}
14006/* [MS-XLSB] 2.1.7.61 Worksheet */
14007function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
14008 if(!data) return data;
14009 var opts = _opts || {};
14010 if(!rels) rels = {'!id':{}};
14011 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
14012 var s = (opts.dense ? [] : {});
14013
14014 var ref;
14015 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14016
14017 var state = [];
14018 var pass = false, end = false;
14019 var row, p, cf, R, C, addr, sstr, rr, cell;
14020 var merges = [];
14021 opts.biff = 12;
14022 opts['!row'] = 0;
14023
14024 var ai = 0, af = false;
14025
14026 var arrayf = [];
14027 var sharedf = {};
14028 var supbooks = opts.supbooks || wb.supbooks || ([[]]);
14029 supbooks.sharedf = sharedf;
14030 supbooks.arrayf = arrayf;
14031 supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; });
14032 if(!opts.supbooks) {
14033 opts.supbooks = supbooks;
14034 if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i];
14035 }
14036
14037 var colinfo = [], rowinfo = [];
14038 var seencol = false;
14039
14040 recordhopper(data, function ws_parse(val, R_n, RT) {
14041 if(end) return;
14042 switch(RT) {
14043 case 0x0094: /* 'BrtWsDim' */
14044 ref = val; break;
14045 case 0x0000: /* 'BrtRowHdr' */
14046 row = val;
14047 if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
14048 rr = encode_row(R = row.r);
14049 opts['!row'] = row.r;
14050 if(val.hidden || val.hpt || val.level != null) {
14051 if(val.hpt) val.hpx = pt2px(val.hpt);
14052 rowinfo[val.r] = val;
14053 }
14054 break;
14055
14056 case 0x0002: /* 'BrtCellRk' */
14057 case 0x0003: /* 'BrtCellError' */
14058 case 0x0004: /* 'BrtCellBool' */
14059 case 0x0005: /* 'BrtCellReal' */
14060 case 0x0006: /* 'BrtCellSt' */
14061 case 0x0007: /* 'BrtCellIsst' */
14062 case 0x0008: /* 'BrtFmlaString' */
14063 case 0x0009: /* 'BrtFmlaNum' */
14064 case 0x000A: /* 'BrtFmlaBool' */
14065 case 0x000B: /* 'BrtFmlaError' */
14066 p = ({t:val[2]});
14067 switch(val[2]) {
14068 case 'n': p.v = val[1]; break;
14069 case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
14070 case 'b': p.v = val[1] ? true : false; break;
14071 case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
14072 case 'str': p.t = 's'; p.v = val[1]; break;
14073 }
14074 if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
14075 C = val[0].c;
14076 if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
14077 else s[encode_col(C) + rr] = p;
14078 if(opts.cellFormula) {
14079 af = false;
14080 for(ai = 0; ai < arrayf.length; ++ai) {
14081 var aii = arrayf[ai];
14082 if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
14083 if(C >= aii[0].s.c && C <= aii[0].e.c) {
14084 p.F = encode_range(aii[0]); af = true;
14085 }
14086 }
14087 if(!af && val.length > 3) p.f = val[3];
14088 }
14089 if(refguess.s.r > row.r) refguess.s.r = row.r;
14090 if(refguess.s.c > C) refguess.s.c = C;
14091 if(refguess.e.r < row.r) refguess.e.r = row.r;
14092 if(refguess.e.c < C) refguess.e.c = C;
14093 if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
14094 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); }
14095 }
14096 break;
14097
14098 case 0x0001: /* 'BrtCellBlank' */
14099 if(!opts.sheetStubs || pass) break;
14100 p = ({t:'z',v:undefined});
14101 C = val[0].c;
14102 if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
14103 else s[encode_col(C) + rr] = p;
14104 if(refguess.s.r > row.r) refguess.s.r = row.r;
14105 if(refguess.s.c > C) refguess.s.c = C;
14106 if(refguess.e.r < row.r) refguess.e.r = row.r;
14107 if(refguess.e.c < C) refguess.e.c = C;
14108 break;
14109
14110 case 0x00B0: /* 'BrtMergeCell' */
14111 merges.push(val); break;
14112
14113 case 0x01EE: /* 'BrtHLink' */
14114 var rel = rels['!id'][val.relId];
14115 if(rel) {
14116 val.Target = rel.Target;
14117 if(val.loc) val.Target += "#"+val.loc;
14118 val.Rel = rel;
14119 } else if(val.relId == '') {
14120 val.Target = "#" + val.loc;
14121 }
14122 for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
14123 if(opts.dense) {
14124 if(!s[R]) s[R] = [];
14125 if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
14126 s[R][C].l = val;
14127 } else {
14128 addr = encode_cell({c:C,r:R});
14129 if(!s[addr]) s[addr] = {t:'z',v:undefined};
14130 s[addr].l = val;
14131 }
14132 }
14133 break;
14134
14135 case 0x01AA: /* 'BrtArrFmla' */
14136 if(!opts.cellFormula) break;
14137 arrayf.push(val);
14138 cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr]));
14139 cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
14140 cell.F = encode_range(val[0]);
14141 break;
14142 case 0x01AB: /* 'BrtShrFmla' */
14143 if(!opts.cellFormula) break;
14144 sharedf[encode_cell(val[0].s)] = val[1];
14145 cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
14146 cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
14147 break;
14148
14149 /* identical to 'ColInfo' in XLS */
14150 case 0x003C: /* 'BrtColInfo' */
14151 if(!opts.cellStyles) break;
14152 while(val.e >= val.s) {
14153 colinfo[val.e--] = { width: val.w/256, hidden: !!(val.flags & 0x01), level: val.level };
14154 if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
14155 process_col(colinfo[val.e+1]);
14156 }
14157 break;
14158
14159 case 0x00A1: /* 'BrtBeginAFilter' */
14160 s['!autofilter'] = { ref:encode_range(val) };
14161 break;
14162
14163 case 0x01DC: /* 'BrtMargins' */
14164 s['!margins'] = val;
14165 break;
14166
14167 case 0x0093: /* 'BrtWsProp' */
14168 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
14169 if(val.name) wb.Sheets[idx].CodeName = val.name;
14170 break;
14171
14172 case 0x0089: /* 'BrtBeginWsView' */
14173 if(!wb.Views) wb.Views = [{}];
14174 if(!wb.Views[0]) wb.Views[0] = {};
14175 if(val.RTL) wb.Views[0].RTL = true;
14176 break;
14177
14178 case 0x01E5: /* 'BrtWsFmtInfo' */
14179 break;
14180
14181 case 0x0040: /* 'BrtDVal' */
14182 case 0x041D: /* 'BrtDVal14' */
14183 break;
14184
14185 case 0x0097: /* 'BrtPane' */
14186 break;
14187 case 0x00AF: /* 'BrtAFilterDateGroupItem' */
14188 case 0x0284: /* 'BrtActiveX' */
14189 case 0x0271: /* 'BrtBigName' */
14190 case 0x0232: /* 'BrtBkHim' */
14191 case 0x018C: /* 'BrtBrk' */
14192 case 0x0458: /* 'BrtCFIcon' */
14193 case 0x047A: /* 'BrtCFRuleExt' */
14194 case 0x01D7: /* 'BrtCFVO' */
14195 case 0x041A: /* 'BrtCFVO14' */
14196 case 0x0289: /* 'BrtCellIgnoreEC' */
14197 case 0x0451: /* 'BrtCellIgnoreEC14' */
14198 case 0x0031: /* 'BrtCellMeta' */
14199 case 0x024D: /* 'BrtCellSmartTagProperty' */
14200 case 0x025F: /* 'BrtCellWatch' */
14201 case 0x0234: /* 'BrtColor' */
14202 case 0x041F: /* 'BrtColor14' */
14203 case 0x00A8: /* 'BrtColorFilter' */
14204 case 0x00AE: /* 'BrtCustomFilter' */
14205 case 0x049C: /* 'BrtCustomFilter14' */
14206 case 0x01F3: /* 'BrtDRef' */
14207 case 0x0226: /* 'BrtDrawing' */
14208 case 0x00AB: /* 'BrtDynamicFilter' */
14209 case 0x00A7: /* 'BrtFilter' */
14210 case 0x0499: /* 'BrtFilter14' */
14211 case 0x00A9: /* 'BrtIconFilter' */
14212 case 0x049D: /* 'BrtIconFilter14' */
14213 case 0x0227: /* 'BrtLegacyDrawing' */
14214 case 0x0228: /* 'BrtLegacyDrawingHF' */
14215 case 0x0295: /* 'BrtListPart' */
14216 case 0x027F: /* 'BrtOleObject' */
14217 case 0x01DE: /* 'BrtPageSetup' */
14218 case 0x0219: /* 'BrtPhoneticInfo' */
14219 case 0x01DD: /* 'BrtPrintOptions' */
14220 case 0x0218: /* 'BrtRangeProtection' */
14221 case 0x044F: /* 'BrtRangeProtection14' */
14222 case 0x02A8: /* 'BrtRangeProtectionIso' */
14223 case 0x0450: /* 'BrtRangeProtectionIso14' */
14224 case 0x0400: /* 'BrtRwDescent' */
14225 case 0x0098: /* 'BrtSel' */
14226 case 0x0297: /* 'BrtSheetCalcProp' */
14227 case 0x0217: /* 'BrtSheetProtection' */
14228 case 0x02A6: /* 'BrtSheetProtectionIso' */
14229 case 0x01F8: /* 'BrtSlc' */
14230 case 0x0413: /* 'BrtSparkline' */
14231 case 0x01AC: /* 'BrtTable' */
14232 case 0x00AA: /* 'BrtTop10Filter' */
14233 case 0x0C00: /* 'BrtUid' */
14234 case 0x0032: /* 'BrtValueMeta' */
14235 case 0x0816: /* 'BrtWebExtension' */
14236 case 0x0415: /* 'BrtWsFmtInfoEx14' */
14237 break;
14238
14239 case 0x0023: /* 'BrtFRTBegin' */
14240 pass = true; break;
14241 case 0x0024: /* 'BrtFRTEnd' */
14242 pass = false; break;
14243 case 0x0025: /* 'BrtACBegin' */
14244 state.push(R_n); pass = true; break;
14245 case 0x0026: /* 'BrtACEnd' */
14246 state.pop(); pass = false; break;
14247
14248 default:
14249 if((R_n||"").indexOf("Begin") > 0){/* empty */}
14250 else if((R_n||"").indexOf("End") > 0){/* empty */}
14251 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14252 }
14253 }, opts);
14254
14255 delete opts.supbooks;
14256 delete opts['!row'];
14257
14258 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);
14259 if(opts.sheetRows && s["!ref"]) {
14260 var tmpref = safe_decode_range(s["!ref"]);
14261 if(opts.sheetRows <= +tmpref.e.r) {
14262 tmpref.e.r = opts.sheetRows - 1;
14263 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
14264 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
14265 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
14266 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
14267 s["!fullref"] = s["!ref"];
14268 s["!ref"] = encode_range(tmpref);
14269 }
14270 }
14271 if(merges.length > 0) s["!merges"] = merges;
14272 if(colinfo.length > 0) s["!cols"] = colinfo;
14273 if(rowinfo.length > 0) s["!rows"] = rowinfo;
14274 return s;
14275}
14276
14277/* TODO: something useful -- this is a stub */
14278function write_ws_bin_cell(ba, cell, R, C, opts, ws) {
14279 if(cell.v === undefined) return;
14280 var vv = "";
14281 switch(cell.t) {
14282 case 'b': vv = cell.v ? "1" : "0"; break;
14283 case 'd': // no BrtCellDate :(
14284 cell = dup(cell);
14285 cell.z = cell.z || SSF._table[14];
14286 cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
14287 break;
14288 /* falls through */
14289 case 'n': case 'e': vv = ''+cell.v; break;
14290 default: vv = cell.v; break;
14291 }
14292 var o = ({r:R, c:C});
14293 /* TODO: cell style */
14294 o.s = get_cell_style(opts.cellXfs, cell, opts);
14295 if(cell.l) ws['!links'].push([encode_cell(o), cell.l]);
14296 if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
14297 switch(cell.t) {
14298 case 's': case 'str':
14299 if(opts.bookSST) {
14300 vv = get_sst_id(opts.Strings, (cell.v), opts.revStrings);
14301 o.t = "s"; o.v = vv;
14302 write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
14303 } else {
14304 o.t = "str";
14305 write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
14306 }
14307 return;
14308 case 'n':
14309 /* TODO: determine threshold for Real vs RK */
14310 if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
14311 else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
14312 return;
14313 case 'b':
14314 o.t = "b";
14315 write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
14316 return;
14317 case 'e': /* TODO: error */ o.t = "e"; break;
14318 }
14319 write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
14320}
14321
14322function write_CELLTABLE(ba, ws, idx, opts) {
14323 var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
14324 write_record(ba, 'BrtBeginSheetData');
14325 var dense = Array.isArray(ws);
14326 var cap = range.e.r;
14327 if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1);
14328 for(var R = range.s.r; R <= cap; ++R) {
14329 rr = encode_row(R);
14330 /* [ACCELLTABLE] */
14331 /* BrtRowHdr */
14332 write_row_header(ba, ws, range, R);
14333 if(R <= range.e.r) for(var C = range.s.c; C <= range.e.c; ++C) {
14334 /* *16384CELL */
14335 if(R === range.s.r) cols[C] = encode_col(C);
14336 ref = cols[C] + rr;
14337 var cell = dense ? (ws[R]||[])[C] : ws[ref];
14338 if(!cell) continue;
14339 /* write cell */
14340 write_ws_bin_cell(ba, cell, R, C, opts, ws);
14341 }
14342 }
14343 write_record(ba, 'BrtEndSheetData');
14344}
14345
14346function write_MERGECELLS(ba, ws) {
14347 if(!ws || !ws['!merges']) return;
14348 write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
14349 ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
14350 write_record(ba, 'BrtEndMergeCells');
14351}
14352
14353function write_COLINFOS(ba, ws) {
14354 if(!ws || !ws['!cols']) return;
14355 write_record(ba, 'BrtBeginColInfos');
14356 ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
14357 write_record(ba, 'BrtEndColInfos');
14358}
14359
14360function write_IGNOREECS(ba, ws) {
14361 if(!ws || !ws['!ref']) return;
14362 write_record(ba, 'BrtBeginCellIgnoreECs');
14363 write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref'])));
14364 write_record(ba, 'BrtEndCellIgnoreECs');
14365}
14366
14367function write_HLINKS(ba, ws, rels) {
14368 /* *BrtHLink */
14369 ws['!links'].forEach(function(l) {
14370 if(!l[1].Target) return;
14371 var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK);
14372 write_record(ba, "BrtHLink", write_BrtHLink(l, rId));
14373 });
14374 delete ws['!links'];
14375}
14376function write_LEGACYDRAWING(ba, ws, idx, rels) {
14377 /* [BrtLegacyDrawing] */
14378 if(ws['!comments'].length > 0) {
14379 var rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
14380 write_record(ba, "BrtLegacyDrawing", write_RelID("rId" + rId));
14381 ws['!legacy'] = rId;
14382 }
14383}
14384
14385function write_AUTOFILTER(ba, ws, wb, idx) {
14386 if(!ws['!autofilter']) return;
14387 var data = ws['!autofilter'];
14388 var ref = typeof data.ref === "string" ? data.ref : encode_range(data.ref);
14389
14390 /* Update FilterDatabase defined name for the worksheet */
14391 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
14392 if(!wb.Workbook.Names) wb.Workbook.Names = [];
14393 var names = wb.Workbook.Names;
14394 var range = decode_range(ref);
14395 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
14396 for(var i = 0; i < names.length; ++i) {
14397 var name = names[i];
14398 if(name.Name != '_xlnm._FilterDatabase') continue;
14399 if(name.Sheet != idx) continue;
14400 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
14401 }
14402 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
14403
14404 write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ref)));
14405 /* *FILTERCOLUMN */
14406 /* [SORTSTATE] */
14407 /* BrtEndAFilter */
14408 write_record(ba, "BrtEndAFilter");
14409}
14410
14411function write_WSVIEWS2(ba, ws, Workbook) {
14412 write_record(ba, "BrtBeginWsViews");
14413 { /* 1*WSVIEW2 */
14414 /* [ACUID] */
14415 write_record(ba, "BrtBeginWsView", write_BrtBeginWsView(ws, Workbook));
14416 /* [BrtPane] */
14417 /* *4BrtSel */
14418 /* *4SXSELECT */
14419 /* *FRT */
14420 write_record(ba, "BrtEndWsView");
14421 }
14422 /* *FRT */
14423 write_record(ba, "BrtEndWsViews");
14424}
14425
14426function write_WSFMTINFO() {
14427 /* [ACWSFMTINFO] */
14428 //write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
14429}
14430
14431function write_SHEETPROTECT(ba, ws) {
14432 if(!ws['!protect']) return;
14433 /* [BrtSheetProtectionIso] */
14434 write_record(ba, "BrtSheetProtection", write_BrtSheetProtection(ws['!protect']));
14435}
14436
14437function write_ws_bin(idx, opts, wb, rels) {
14438 var ba = buf_array();
14439 var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
14440 var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
14441 var r = safe_decode_range(ws['!ref'] || "A1");
14442 if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
14443 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
14444 r.e.c = Math.min(r.e.c, 0x3FFF);
14445 r.e.r = Math.min(r.e.c, 0xFFFFF);
14446 }
14447 ws['!links'] = [];
14448 /* passed back to write_zip and removed there */
14449 ws['!comments'] = [];
14450 write_record(ba, "BrtBeginSheet");
14451 if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
14452 write_record(ba, "BrtWsDim", write_BrtWsDim(r));
14453 write_WSVIEWS2(ba, ws, wb.Workbook);
14454 write_WSFMTINFO(ba, ws);
14455 write_COLINFOS(ba, ws, idx, opts, wb);
14456 write_CELLTABLE(ba, ws, idx, opts, wb);
14457 /* [BrtSheetCalcProp] */
14458 write_SHEETPROTECT(ba, ws);
14459 /* *([BrtRangeProtectionIso] BrtRangeProtection) */
14460 /* [SCENMAN] */
14461 write_AUTOFILTER(ba, ws, wb, idx);
14462 /* [SORTSTATE] */
14463 /* [DCON] */
14464 /* [USERSHVIEWS] */
14465 write_MERGECELLS(ba, ws);
14466 /* [BrtPhoneticInfo] */
14467 /* *CONDITIONALFORMATTING */
14468 /* [DVALS] */
14469 write_HLINKS(ba, ws, rels);
14470 /* [BrtPrintOptions] */
14471 if(ws['!margins']) write_record(ba, "BrtMargins", write_BrtMargins(ws['!margins']));
14472 /* [BrtPageSetup] */
14473 /* [HEADERFOOTER] */
14474 /* [RWBRK] */
14475 /* [COLBRK] */
14476 /* *BrtBigName */
14477 /* [CELLWATCHES] */
14478 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) write_IGNOREECS(ba, ws);
14479 /* [SMARTTAGS] */
14480 /* [BrtDrawing] */
14481 write_LEGACYDRAWING(ba, ws, idx, rels);
14482 /* [BrtLegacyDrawingHF] */
14483 /* [BrtBkHim] */
14484 /* [OLEOBJECTS] */
14485 /* [ACTIVEXCONTROLS] */
14486 /* [WEBPUBITEMS] */
14487 /* [LISTPARTS] */
14488 /* FRTWORKSHEET */
14489 write_record(ba, "BrtEndSheet");
14490 return ba.end();
14491}
14492RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
14493RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
14494
14495function parse_Cache(data) {
14496 var col = [];
14497 var num = data.match(/^<c:numCache>/);
14498 var f;
14499
14500 /* 21.2.2.150 pt CT_NumVal */
14501 (data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
14502 var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
14503 if(!q) return;
14504 col[+q[1]] = num ? +q[2] : q[2];
14505 });
14506
14507 /* 21.2.2.71 formatCode CT_Xstring */
14508 var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
14509
14510 (data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); });
14511
14512 return [col, nf, f];
14513}
14514
14515/* 21.2 DrawingML - Charts */
14516function parse_chart(data, name, opts, rels, wb, csheet) {
14517 var cs = ((csheet || {"!type":"chart"}));
14518 if(!data) return csheet;
14519 /* 21.2.2.27 chart CT_Chart */
14520
14521 var C = 0, R = 0, col = "A";
14522 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14523
14524 /* 21.2.2.120 numCache CT_NumData */
14525 (data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
14526 var cache = parse_Cache(nc);
14527 refguess.s.r = refguess.s.c = 0;
14528 refguess.e.c = C;
14529 col = encode_col(C);
14530 cache[0].forEach(function(n,i) {
14531 cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
14532 R = i;
14533 });
14534 if(refguess.e.r < R) refguess.e.r = R;
14535 ++C;
14536 });
14537 if(C > 0) cs["!ref"] = encode_range(refguess);
14538 return cs;
14539}
14540RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
14541
14542var CS_XML_ROOT = writextag('chartsheet', null, {
14543 'xmlns': XMLNS.main[0],
14544 'xmlns:r': XMLNS.r
14545});
14546
14547/* 18.3 Worksheets also covers Chartsheets */
14548function parse_cs_xml(data, opts, idx, rels, wb) {
14549 if(!data) return data;
14550 /* 18.3.1.12 chartsheet CT_ChartSheet */
14551 if(!rels) rels = {'!id':{}};
14552 var s = ({'!type':"chart", '!drawel':null, '!rel':""});
14553 var m;
14554
14555 /* 18.3.1.83 sheetPr CT_ChartsheetPr */
14556 var sheetPr = data.match(sheetprregex);
14557 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
14558
14559 /* 18.3.1.36 drawing CT_Drawing */
14560 if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
14561
14562 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
14563 return s;
14564}
14565function write_cs_xml(idx, opts, wb, rels) {
14566 var o = [XML_HEADER, CS_XML_ROOT];
14567 o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
14568 add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
14569 if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
14570 return o.join("");
14571}
14572
14573/* [MS-XLSB] 2.4.331 BrtCsProp */
14574function parse_BrtCsProp(data, length) {
14575 data.l += 10;
14576 var name = parse_XLWideString(data, length - 10);
14577 return { name: name };
14578}
14579
14580/* [MS-XLSB] 2.1.7.7 Chart Sheet */
14581function parse_cs_bin(data, opts, idx, rels, wb) {
14582 if(!data) return data;
14583 if(!rels) rels = {'!id':{}};
14584 var s = {'!type':"chart", '!drawel':null, '!rel':""};
14585 var state = [];
14586 var pass = false;
14587 recordhopper(data, function cs_parse(val, R_n, RT) {
14588 switch(RT) {
14589
14590 case 0x0226: /* 'BrtDrawing' */
14591 s['!rel'] = val; break;
14592
14593 case 0x028B: /* 'BrtCsProp' */
14594 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
14595 if(val.name) wb.Sheets[idx].CodeName = val.name;
14596 break;
14597
14598 case 0x0232: /* 'BrtBkHim' */
14599 case 0x028C: /* 'BrtCsPageSetup' */
14600 case 0x029D: /* 'BrtCsProtection' */
14601 case 0x02A7: /* 'BrtCsProtectionIso' */
14602 case 0x0227: /* 'BrtLegacyDrawing' */
14603 case 0x0228: /* 'BrtLegacyDrawingHF' */
14604 case 0x01DC: /* 'BrtMargins' */
14605 case 0x0C00: /* 'BrtUid' */
14606 break;
14607
14608 case 0x0023: /* 'BrtFRTBegin' */
14609 pass = true; break;
14610 case 0x0024: /* 'BrtFRTEnd' */
14611 pass = false; break;
14612 case 0x0025: /* 'BrtACBegin' */
14613 state.push(R_n); break;
14614 case 0x0026: /* 'BrtACEnd' */
14615 state.pop(); break;
14616
14617 default:
14618 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
14619 else if((R_n||"").indexOf("End") > 0) state.pop();
14620 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14621 }
14622 }, opts);
14623
14624 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
14625 return s;
14626}
14627function write_cs_bin() {
14628 var ba = buf_array();
14629 write_record(ba, "BrtBeginSheet");
14630 /* [BrtCsProp] */
14631 /* CSVIEWS */
14632 /* [[BrtCsProtectionIso] BrtCsProtection] */
14633 /* [USERCSVIEWS] */
14634 /* [BrtMargins] */
14635 /* [BrtCsPageSetup] */
14636 /* [HEADERFOOTER] */
14637 /* BrtDrawing */
14638 /* [BrtLegacyDrawing] */
14639 /* [BrtLegacyDrawingHF] */
14640 /* [BrtBkHim] */
14641 /* [WEBPUBITEMS] */
14642 /* FRTCHARTSHEET */
14643 write_record(ba, "BrtEndSheet");
14644 return ba.end();
14645}
14646/* 18.2.28 (CT_WorkbookProtection) Defaults */
14647var WBPropsDef = [
14648 ['allowRefreshQuery', false, "bool"],
14649 ['autoCompressPictures', true, "bool"],
14650 ['backupFile', false, "bool"],
14651 ['checkCompatibility', false, "bool"],
14652 ['CodeName', ''],
14653 ['date1904', false, "bool"],
14654 ['defaultThemeVersion', 0, "int"],
14655 ['filterPrivacy', false, "bool"],
14656 ['hidePivotFieldList', false, "bool"],
14657 ['promptedSolutions', false, "bool"],
14658 ['publishItems', false, "bool"],
14659 ['refreshAllConnections', false, "bool"],
14660 ['saveExternalLinkValues', true, "bool"],
14661 ['showBorderUnselectedTables', true, "bool"],
14662 ['showInkAnnotation', true, "bool"],
14663 ['showObjects', 'all'],
14664 ['showPivotChartFilter', false, "bool"],
14665 ['updateLinks', 'userSet']
14666];
14667
14668/* 18.2.30 (CT_BookView) Defaults */
14669var WBViewDef = [
14670 ['activeTab', 0, "int"],
14671 ['autoFilterDateGrouping', true, "bool"],
14672 ['firstSheet', 0, "int"],
14673 ['minimized', false, "bool"],
14674 ['showHorizontalScroll', true, "bool"],
14675 ['showSheetTabs', true, "bool"],
14676 ['showVerticalScroll', true, "bool"],
14677 ['tabRatio', 600, "int"],
14678 ['visibility', 'visible']
14679 //window{Height,Width}, {x,y}Window
14680];
14681
14682/* 18.2.19 (CT_Sheet) Defaults */
14683var SheetDef = [
14684 //['state', 'visible']
14685];
14686
14687/* 18.2.2 (CT_CalcPr) Defaults */
14688var CalcPrDef = [
14689 ['calcCompleted', 'true'],
14690 ['calcMode', 'auto'],
14691 ['calcOnSave', 'true'],
14692 ['concurrentCalc', 'true'],
14693 ['fullCalcOnLoad', 'false'],
14694 ['fullPrecision', 'true'],
14695 ['iterate', 'false'],
14696 ['iterateCount', '100'],
14697 ['iterateDelta', '0.001'],
14698 ['refMode', 'A1']
14699];
14700
14701/* 18.2.3 (CT_CustomWorkbookView) Defaults */
14702/*var CustomWBViewDef = [
14703 ['autoUpdate', 'false'],
14704 ['changesSavedWin', 'false'],
14705 ['includeHiddenRowCol', 'true'],
14706 ['includePrintSettings', 'true'],
14707 ['maximized', 'false'],
14708 ['minimized', 'false'],
14709 ['onlySync', 'false'],
14710 ['personalView', 'false'],
14711 ['showComments', 'commIndicator'],
14712 ['showFormulaBar', 'true'],
14713 ['showHorizontalScroll', 'true'],
14714 ['showObjects', 'all'],
14715 ['showSheetTabs', 'true'],
14716 ['showStatusbar', 'true'],
14717 ['showVerticalScroll', 'true'],
14718 ['tabRatio', '600'],
14719 ['xWindow', '0'],
14720 ['yWindow', '0']
14721];*/
14722
14723function push_defaults_array(target, defaults) {
14724 for(var j = 0; j != target.length; ++j) { var w = target[j];
14725 for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
14726 if(w[z[0]] == null) w[z[0]] = z[1];
14727 else switch(z[2]) {
14728 case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
14729 case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
14730 }
14731 }
14732 }
14733}
14734function push_defaults(target, defaults) {
14735 for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
14736 if(target[z[0]] == null) target[z[0]] = z[1];
14737 else switch(z[2]) {
14738 case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
14739 case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
14740 }
14741 }
14742}
14743
14744function parse_wb_defaults(wb) {
14745 push_defaults(wb.WBProps, WBPropsDef);
14746 push_defaults(wb.CalcPr, CalcPrDef);
14747
14748 push_defaults_array(wb.WBView, WBViewDef);
14749 push_defaults_array(wb.Sheets, SheetDef);
14750
14751 _ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
14752}
14753
14754function safe1904(wb) {
14755 /* TODO: store date1904 somewhere else */
14756 if(!wb.Workbook) return "false";
14757 if(!wb.Workbook.WBProps) return "false";
14758 return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
14759}
14760
14761var badchars = "][*?\/\\".split("");
14762function check_ws_name(n, safe) {
14763 if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
14764 var _good = true;
14765 badchars.forEach(function(c) {
14766 if(n.indexOf(c) == -1) return;
14767 if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
14768 _good = false;
14769 });
14770 return _good;
14771}
14772function check_wb_names(N, S, codes) {
14773 N.forEach(function(n,i) {
14774 check_ws_name(n);
14775 for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
14776 if(codes) {
14777 var cn = (S && S[i] && S[i].CodeName) || n;
14778 if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
14779 }
14780 });
14781}
14782function check_wb(wb) {
14783 if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
14784 if(!wb.SheetNames.length) throw new Error("Workbook is empty");
14785 var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
14786 check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
14787 for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
14788 /* TODO: validate workbook */
14789}
14790/* 18.2 Workbook */
14791var wbnsregex = /<\w+:workbook/;
14792function parse_wb_xml(data, opts) {
14793 if(!data) throw new Error("Could not find file");
14794 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
14795 var pass = false, xmlns = "xmlns";
14796 var dname = {}, dnstart = 0;
14797 data.replace(tagregex, function xml_wb(x, idx) {
14798 var y = parsexmltag(x);
14799 switch(strip_ns(y[0])) {
14800 case '<?xml': break;
14801
14802 /* 18.2.27 workbook CT_Workbook 1 */
14803 case '<workbook':
14804 if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
14805 wb.xmlns = y[xmlns];
14806 break;
14807 case '</workbook>': break;
14808
14809 /* 18.2.13 fileVersion CT_FileVersion ? */
14810 case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
14811 case '<fileVersion/>': case '</fileVersion>': break;
14812
14813 /* 18.2.12 fileSharing CT_FileSharing ? */
14814 case '<fileSharing':
14815 break;
14816 case '<fileSharing/>': break;
14817
14818 /* 18.2.28 workbookPr CT_WorkbookPr ? */
14819 case '<workbookPr':
14820 case '<workbookPr/>':
14821 WBPropsDef.forEach(function(w) {
14822 if(y[w[0]] == null) return;
14823 switch(w[2]) {
14824 case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
14825 case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
14826 default: wb.WBProps[w[0]] = y[w[0]];
14827 }
14828 });
14829 if(y.codeName) wb.WBProps.CodeName = y.codeName;
14830 break;
14831 case '</workbookPr>': break;
14832
14833 /* 18.2.29 workbookProtection CT_WorkbookProtection ? */
14834 case '<workbookProtection':
14835 break;
14836 case '<workbookProtection/>': break;
14837
14838 /* 18.2.1 bookViews CT_BookViews ? */
14839 case '<bookViews': case '<bookViews>': case '</bookViews>': break;
14840 /* 18.2.30 workbookView CT_BookView + */
14841 case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
14842 case '</workbookView>': break;
14843
14844 /* 18.2.20 sheets CT_Sheets 1 */
14845 case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
14846 /* 18.2.19 sheet CT_Sheet + */
14847 case '<sheet':
14848 switch(y.state) {
14849 case "hidden": y.Hidden = 1; break;
14850 case "veryHidden": y.Hidden = 2; break;
14851 default: y.Hidden = 0;
14852 }
14853 delete y.state;
14854 y.name = unescapexml(utf8read(y.name));
14855 delete y[0]; wb.Sheets.push(y); break;
14856 case '</sheet>': break;
14857
14858 /* 18.2.15 functionGroups CT_FunctionGroups ? */
14859 case '<functionGroups': case '<functionGroups/>': break;
14860 /* 18.2.14 functionGroup CT_FunctionGroup + */
14861 case '<functionGroup': break;
14862
14863 /* 18.2.9 externalReferences CT_ExternalReferences ? */
14864 case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
14865 /* 18.2.8 externalReference CT_ExternalReference + */
14866 case '<externalReference': break;
14867
14868 /* 18.2.6 definedNames CT_DefinedNames ? */
14869 case '<definedNames/>': break;
14870 case '<definedNames>': case '<definedNames': pass=true; break;
14871 case '</definedNames>': pass=false; break;
14872 /* 18.2.5 definedName CT_DefinedName + */
14873 case '<definedName': {
14874 dname = {};
14875 dname.Name = utf8read(y.name);
14876 if(y.comment) dname.Comment = y.comment;
14877 if(y.localSheetId) dname.Sheet = +y.localSheetId;
14878 if(parsexmlbool(y.hidden||"0")) dname.Hidden = true;
14879 dnstart = idx + x.length;
14880 } break;
14881 case '</definedName>': {
14882 dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
14883 wb.Names.push(dname);
14884 } break;
14885 case '<definedName/>': break;
14886
14887 /* 18.2.2 calcPr CT_CalcPr ? */
14888 case '<calcPr': delete y[0]; wb.CalcPr = y; break;
14889 case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
14890 case '</calcPr>': break;
14891
14892 /* 18.2.16 oleSize CT_OleSize ? (ref required) */
14893 case '<oleSize': break;
14894
14895 /* 18.2.4 customWorkbookViews CT_CustomWorkbookViews ? */
14896 case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
14897 /* 18.2.3 customWorkbookView CT_CustomWorkbookView + */
14898 case '<customWorkbookView': case '</customWorkbookView>': break;
14899
14900 /* 18.2.18 pivotCaches CT_PivotCaches ? */
14901 case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
14902 /* 18.2.17 pivotCache CT_PivotCache ? */
14903 case '<pivotCache': break;
14904
14905 /* 18.2.21 smartTagPr CT_SmartTagPr ? */
14906 case '<smartTagPr': case '<smartTagPr/>': break;
14907
14908 /* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
14909 case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
14910 /* 18.2.22 smartTagType CT_SmartTagType ? */
14911 case '<smartTagType': break;
14912
14913 /* 18.2.24 webPublishing CT_WebPublishing ? */
14914 case '<webPublishing': case '<webPublishing/>': break;
14915
14916 /* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
14917 case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
14918
14919 /* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
14920 case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
14921 /* 18.2.25 webPublishObject CT_WebPublishObject ? */
14922 case '<webPublishObject': break;
14923
14924 /* 18.2.10 extLst CT_ExtensionList ? */
14925 case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
14926 /* 18.2.7 ext CT_Extension + */
14927 case '<ext': pass=true; break; //TODO: check with versions of excel
14928 case '</ext>': pass=false; break;
14929
14930 /* Others */
14931 case '<ArchID': break;
14932 case '<AlternateContent':
14933 case '<AlternateContent>': pass=true; break;
14934 case '</AlternateContent>': pass=false; break;
14935
14936 /* TODO */
14937 case '<revisionPtr': break;
14938
14939 default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
14940 }
14941 return x;
14942 });
14943 if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
14944
14945 parse_wb_defaults(wb);
14946
14947 return wb;
14948}
14949
14950var WB_XML_ROOT = writextag('workbook', null, {
14951 'xmlns': XMLNS.main[0],
14952 //'xmlns:mx': XMLNS.mx,
14953 //'xmlns:s': XMLNS.main[0],
14954 'xmlns:r': XMLNS.r
14955});
14956
14957function write_wb_xml(wb) {
14958 var o = [XML_HEADER];
14959 o[o.length] = WB_XML_ROOT;
14960
14961 var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
14962
14963 /* fileVersion */
14964 /* fileSharing */
14965
14966 var workbookPr = ({codeName:"ThisWorkbook"});
14967 if(wb.Workbook && wb.Workbook.WBProps) {
14968 WBPropsDef.forEach(function(x) {
14969if((wb.Workbook.WBProps[x[0]]) == null) return;
14970 if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
14971 workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
14972 });
14973if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
14974 }
14975 o[o.length] = (writextag('workbookPr', null, workbookPr));
14976
14977 /* workbookProtection */
14978
14979 var sheets = wb.Workbook && wb.Workbook.Sheets || [];
14980 var i = 0;
14981
14982 /* bookViews */
14983
14984 o[o.length] = "<sheets>";
14985 for(i = 0; i != wb.SheetNames.length; ++i) {
14986 var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
14987 sht.sheetId = ""+(i+1);
14988 sht["r:id"] = "rId"+(i+1);
14989 if(sheets[i]) switch(sheets[i].Hidden) {
14990 case 1: sht.state = "hidden"; break;
14991 case 2: sht.state = "veryHidden"; break;
14992 }
14993 o[o.length] = (writextag('sheet',null,sht));
14994 }
14995 o[o.length] = "</sheets>";
14996
14997 /* functionGroups */
14998 /* externalReferences */
14999
15000 if(write_names) {
15001 o[o.length] = "<definedNames>";
15002 if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
15003 var d = {name:n.Name};
15004 if(n.Comment) d.comment = n.Comment;
15005 if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
15006 if(n.Hidden) d.hidden = "1";
15007 if(!n.Ref) return;
15008 o[o.length] = writextag('definedName', String(n.Ref).replace(/</g, "&lt;").replace(/>/g, "&gt;"), d);
15009 });
15010 o[o.length] = "</definedNames>";
15011 }
15012
15013 /* calcPr */
15014 /* oleSize */
15015 /* customWorkbookViews */
15016 /* pivotCaches */
15017 /* smartTagPr */
15018 /* smartTagTypes */
15019 /* webPublishing */
15020 /* fileRecoveryPr */
15021 /* webPublishObjects */
15022 /* extLst */
15023
15024 if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
15025 return o.join("");
15026}
15027/* [MS-XLSB] 2.4.304 BrtBundleSh */
15028function parse_BrtBundleSh(data, length) {
15029 var z = {};
15030 z.Hidden = data.read_shift(4); //hsState ST_SheetState
15031 z.iTabID = data.read_shift(4);
15032 z.strRelID = parse_RelID(data,length-8);
15033 z.name = parse_XLWideString(data);
15034 return z;
15035}
15036function write_BrtBundleSh(data, o) {
15037 if(!o) o = new_buf(127);
15038 o.write_shift(4, data.Hidden);
15039 o.write_shift(4, data.iTabID);
15040 write_RelID(data.strRelID, o);
15041 write_XLWideString(data.name.slice(0,31), o);
15042 return o.length > o.l ? o.slice(0, o.l) : o;
15043}
15044
15045/* [MS-XLSB] 2.4.815 BrtWbProp */
15046function parse_BrtWbProp(data, length) {
15047 var o = ({});
15048 var flags = data.read_shift(4);
15049 o.defaultThemeVersion = data.read_shift(4);
15050 var strName = (length > 8) ? parse_XLWideString(data) : "";
15051 if(strName.length > 0) o.CodeName = strName;
15052 o.autoCompressPictures = !!(flags & 0x10000);
15053 o.backupFile = !!(flags & 0x40);
15054 o.checkCompatibility = !!(flags & 0x1000);
15055 o.date1904 = !!(flags & 0x01);
15056 o.filterPrivacy = !!(flags & 0x08);
15057 o.hidePivotFieldList = !!(flags & 0x400);
15058 o.promptedSolutions = !!(flags & 0x10);
15059 o.publishItems = !!(flags & 0x800);
15060 o.refreshAllConnections = !!(flags & 0x40000);
15061 o.saveExternalLinkValues = !!(flags & 0x80);
15062 o.showBorderUnselectedTables = !!(flags & 0x04);
15063 o.showInkAnnotation = !!(flags & 0x20);
15064 o.showObjects = ["all", "placeholders", "none"][(flags >> 13) & 0x03];
15065 o.showPivotChartFilter = !!(flags & 0x8000);
15066 o.updateLinks = ["userSet", "never", "always"][(flags >> 8) & 0x03];
15067 return o;
15068}
15069function write_BrtWbProp(data, o) {
15070 if(!o) o = new_buf(72);
15071 var flags = 0;
15072 if(data) {
15073 /* TODO: mirror parse_BrtWbProp fields */
15074 if(data.filterPrivacy) flags |= 0x08;
15075 }
15076 o.write_shift(4, flags);
15077 o.write_shift(4, 0);
15078 write_XLSBCodeName(data && data.CodeName || "ThisWorkbook", o);
15079 return o.slice(0, o.l);
15080}
15081
15082function parse_BrtFRTArchID$(data, length) {
15083 var o = {};
15084 data.read_shift(4);
15085 o.ArchID = data.read_shift(4);
15086 data.l += length - 8;
15087 return o;
15088}
15089
15090/* [MS-XLSB] 2.4.687 BrtName */
15091function parse_BrtName(data, length, opts) {
15092 var end = data.l + length;
15093 data.l += 4; //var flags = data.read_shift(4);
15094 data.l += 1; //var chKey = data.read_shift(1);
15095 var itab = data.read_shift(4);
15096 var name = parse_XLNameWideString(data);
15097 var formula = parse_XLSBNameParsedFormula(data, 0, opts);
15098 var comment = parse_XLNullableWideString(data);
15099 //if(0 /* fProc */) {
15100 // unusedstring1: XLNullableWideString
15101 // description: XLNullableWideString
15102 // helpTopic: XLNullableWideString
15103 // unusedstring2: XLNullableWideString
15104 //}
15105 data.l = end;
15106 var out = ({Name:name, Ptg:formula});
15107 if(itab < 0xFFFFFFF) out.Sheet = itab;
15108 if(comment) out.Comment = comment;
15109 return out;
15110}
15111
15112/* [MS-XLSB] 2.1.7.61 Workbook */
15113function parse_wb_bin(data, opts) {
15114 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
15115 var state = [];
15116 var pass = false;
15117
15118 if(!opts) opts = {};
15119 opts.biff = 12;
15120
15121 var Names = [];
15122 var supbooks = ([[]]);
15123 supbooks.SheetNames = [];
15124 supbooks.XTI = [];
15125
15126 recordhopper(data, function hopper_wb(val, R_n, RT) {
15127 switch(RT) {
15128 case 0x009C: /* 'BrtBundleSh' */
15129 supbooks.SheetNames.push(val.name);
15130 wb.Sheets.push(val); break;
15131
15132 case 0x0099: /* 'BrtWbProp' */
15133 wb.WBProps = val; break;
15134
15135 case 0x0027: /* 'BrtName' */
15136 if(val.Sheet != null) opts.SID = val.Sheet;
15137 val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts);
15138 delete opts.SID;
15139 delete val.Ptg;
15140 Names.push(val);
15141 break;
15142 case 0x040C: /* 'BrtNameExt' */ break;
15143
15144 case 0x0165: /* 'BrtSupSelf' */
15145 case 0x0166: /* 'BrtSupSame' */
15146 case 0x0163: /* 'BrtSupBookSrc' */
15147 case 0x029B: /* 'BrtSupAddin' */
15148 if(!supbooks[0].length) supbooks[0] = [RT, val];
15149 else supbooks.push([RT, val]);
15150 supbooks[supbooks.length - 1].XTI = [];
15151 break;
15152 case 0x016A: /* 'BrtExternSheet' */
15153 if(supbooks.length === 0) { supbooks[0] = []; supbooks[0].XTI = []; }
15154 supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val);
15155 supbooks.XTI = supbooks.XTI.concat(val);
15156 break;
15157 case 0x0169: /* 'BrtPlaceholderName' */
15158 break;
15159
15160 /* case 'BrtModelTimeGroupingCalcCol' */
15161 case 0x0C00: /* 'BrtUid' */
15162 case 0x0C01: /* 'BrtRevisionPtr' */
15163 case 0x0817: /* 'BrtAbsPath15' */
15164 case 0x0216: /* 'BrtBookProtection' */
15165 case 0x02A5: /* 'BrtBookProtectionIso' */
15166 case 0x009E: /* 'BrtBookView' */
15167 case 0x009D: /* 'BrtCalcProp' */
15168 case 0x0262: /* 'BrtCrashRecErr' */
15169 case 0x0802: /* 'BrtDecoupledPivotCacheID' */
15170 case 0x009B: /* 'BrtFileRecover' */
15171 case 0x0224: /* 'BrtFileSharing' */
15172 case 0x02A4: /* 'BrtFileSharingIso' */
15173 case 0x0080: /* 'BrtFileVersion' */
15174 case 0x0299: /* 'BrtFnGroup' */
15175 case 0x0850: /* 'BrtModelRelationship' */
15176 case 0x084D: /* 'BrtModelTable' */
15177 case 0x0225: /* 'BrtOleSize' */
15178 case 0x0805: /* 'BrtPivotTableRef' */
15179 case 0x0254: /* 'BrtSmartTagType' */
15180 case 0x081C: /* 'BrtTableSlicerCacheID' */
15181 case 0x081B: /* 'BrtTableSlicerCacheIDs' */
15182 case 0x0822: /* 'BrtTimelineCachePivotCacheID' */
15183 case 0x018D: /* 'BrtUserBookView' */
15184 case 0x009A: /* 'BrtWbFactoid' */
15185 case 0x045D: /* 'BrtWbProp14' */
15186 case 0x0229: /* 'BrtWebOpt' */
15187 case 0x082B: /* 'BrtWorkBookPr15' */
15188 break;
15189
15190 case 0x0023: /* 'BrtFRTBegin' */
15191 state.push(R_n); pass = true; break;
15192 case 0x0024: /* 'BrtFRTEnd' */
15193 state.pop(); pass = false; break;
15194 case 0x0025: /* 'BrtACBegin' */
15195 state.push(R_n); pass = true; break;
15196 case 0x0026: /* 'BrtACEnd' */
15197 state.pop(); pass = false; break;
15198
15199 case 0x0010: /* 'BrtFRTArchID$' */ break;
15200
15201 default:
15202 if((R_n||"").indexOf("Begin") > 0){/* empty */}
15203 else if((R_n||"").indexOf("End") > 0){/* empty */}
15204 else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin" && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
15205 }
15206 }, opts);
15207
15208 parse_wb_defaults(wb);
15209
15210 // $FlowIgnore
15211 wb.Names = Names;
15212
15213 (wb).supbooks = supbooks;
15214 return wb;
15215}
15216
15217function write_BUNDLESHS(ba, wb) {
15218 write_record(ba, "BrtBeginBundleShs");
15219 for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
15220 var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
15221 var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
15222 write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
15223 }
15224 write_record(ba, "BrtEndBundleShs");
15225}
15226
15227/* [MS-XLSB] 2.4.649 BrtFileVersion */
15228function write_BrtFileVersion(data, o) {
15229 if(!o) o = new_buf(127);
15230 for(var i = 0; i != 4; ++i) o.write_shift(4, 0);
15231 write_XLWideString("SheetJS", o);
15232 write_XLWideString(XLSX.version, o);
15233 write_XLWideString(XLSX.version, o);
15234 write_XLWideString("7262", o);
15235 o.length = o.l;
15236 return o.length > o.l ? o.slice(0, o.l) : o;
15237}
15238
15239/* [MS-XLSB] 2.4.301 BrtBookView */
15240function write_BrtBookView(idx, o) {
15241 if(!o) o = new_buf(29);
15242 o.write_shift(-4, 0);
15243 o.write_shift(-4, 460);
15244 o.write_shift(4, 28800);
15245 o.write_shift(4, 17600);
15246 o.write_shift(4, 500);
15247 o.write_shift(4, idx);
15248 o.write_shift(4, idx);
15249 var flags = 0x78;
15250 o.write_shift(1, flags);
15251 return o.length > o.l ? o.slice(0, o.l) : o;
15252}
15253
15254function write_BOOKVIEWS(ba, wb) {
15255 /* required if hidden tab appears before visible tab */
15256 if(!wb.Workbook || !wb.Workbook.Sheets) return;
15257 var sheets = wb.Workbook.Sheets;
15258 var i = 0, vistab = -1, hidden = -1;
15259 for(; i < sheets.length; ++i) {
15260 if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
15261 else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
15262 }
15263 if(hidden > vistab) return;
15264 write_record(ba, "BrtBeginBookViews");
15265 write_record(ba, "BrtBookView", write_BrtBookView(vistab));
15266 /* 1*(BrtBookView *FRT) */
15267 write_record(ba, "BrtEndBookViews");
15268}
15269
15270/* [MS-XLSB] 2.4.305 BrtCalcProp */
15271/*function write_BrtCalcProp(data, o) {
15272 if(!o) o = new_buf(26);
15273 o.write_shift(4,0); // force recalc
15274 o.write_shift(4,1);
15275 o.write_shift(4,0);
15276 write_Xnum(0, o);
15277 o.write_shift(-4, 1023);
15278 o.write_shift(1, 0x33);
15279 o.write_shift(1, 0x00);
15280 return o;
15281}*/
15282
15283/* [MS-XLSB] 2.4.646 BrtFileRecover */
15284/*function write_BrtFileRecover(data, o) {
15285 if(!o) o = new_buf(1);
15286 o.write_shift(1,0);
15287 return o;
15288}*/
15289
15290/* [MS-XLSB] 2.1.7.61 Workbook */
15291function write_wb_bin(wb, opts) {
15292 var ba = buf_array();
15293 write_record(ba, "BrtBeginBook");
15294 write_record(ba, "BrtFileVersion", write_BrtFileVersion());
15295 /* [[BrtFileSharingIso] BrtFileSharing] */
15296 write_record(ba, "BrtWbProp", write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null));
15297 /* [ACABSPATH] */
15298 /* [[BrtBookProtectionIso] BrtBookProtection] */
15299 write_BOOKVIEWS(ba, wb, opts);
15300 write_BUNDLESHS(ba, wb, opts);
15301 /* [FNGROUP] */
15302 /* [EXTERNALS] */
15303 /* *BrtName */
15304 /* write_record(ba, "BrtCalcProp", write_BrtCalcProp()); */
15305 /* [BrtOleSize] */
15306 /* *(BrtUserBookView *FRT) */
15307 /* [PIVOTCACHEIDS] */
15308 /* [BrtWbFactoid] */
15309 /* [SMARTTAGTYPES] */
15310 /* [BrtWebOpt] */
15311 /* write_record(ba, "BrtFileRecover", write_BrtFileRecover()); */
15312 /* [WEBPUBITEMS] */
15313 /* [CRERRS] */
15314 /* FRTWORKBOOK */
15315 write_record(ba, "BrtEndBook");
15316
15317 return ba.end();
15318}
15319function parse_wb(data, name, opts) {
15320 if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
15321 return parse_wb_xml((data), opts);
15322}
15323
15324function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
15325 if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
15326 return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
15327}
15328
15329function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
15330 if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
15331 return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
15332}
15333
15334function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
15335 if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
15336 return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
15337}
15338
15339function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
15340 if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
15341 return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
15342}
15343
15344function parse_sty(data, name, themes, opts) {
15345 if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
15346 return parse_sty_xml((data), themes, opts);
15347}
15348
15349function parse_theme(data, name, opts) {
15350 return parse_theme_xml(data, opts);
15351}
15352
15353function parse_sst(data, name, opts) {
15354 if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
15355 return parse_sst_xml((data), opts);
15356}
15357
15358function parse_cmnt(data, name, opts) {
15359 if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
15360 return parse_comments_xml((data), opts);
15361}
15362
15363function parse_cc(data, name, opts) {
15364 if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
15365 return parse_cc_xml((data), name, opts);
15366}
15367
15368function parse_xlink(data, rel, name, opts) {
15369 if(name.slice(-4)===".bin") return parse_xlink_bin((data), rel, name, opts);
15370 return parse_xlink_xml((data), rel, name, opts);
15371}
15372
15373function write_wb(wb, name, opts) {
15374 return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
15375}
15376
15377function write_ws(data, name, opts, wb, rels) {
15378 return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
15379}
15380
15381// eslint-disable-next-line no-unused-vars
15382function write_cs(data, name, opts, wb, rels) {
15383 return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
15384}
15385
15386function write_sty(data, name, opts) {
15387 return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
15388}
15389
15390function write_sst(data, name, opts) {
15391 return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
15392}
15393
15394function write_cmnt(data, name, opts) {
15395 return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
15396}
15397/*
15398function write_cc(data, name:string, opts) {
15399 return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
15400}
15401*/
15402var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
15403var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
15404function xlml_parsexmltag(tag, skip_root) {
15405 var words = tag.split(/\s+/);
15406 var z = ([]); if(!skip_root) z[0] = words[0];
15407 if(words.length === 1) return z;
15408 var m = tag.match(attregexg2), y, j, w, i;
15409 if(m) for(i = 0; i != m.length; ++i) {
15410 y = m[i].match(attregex2);
15411if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
15412 else {
15413 if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
15414 else w = y[1].slice(j+1);
15415 z[w] = y[2].slice(1,y[2].length-1);
15416 }
15417 }
15418 return z;
15419}
15420function xlml_parsexmltagobj(tag) {
15421 var words = tag.split(/\s+/);
15422 var z = {};
15423 if(words.length === 1) return z;
15424 var m = tag.match(attregexg2), y, j, w, i;
15425 if(m) for(i = 0; i != m.length; ++i) {
15426 y = m[i].match(attregex2);
15427if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
15428 else {
15429 if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
15430 else w = y[1].slice(j+1);
15431 z[w] = y[2].slice(1,y[2].length-1);
15432 }
15433 }
15434 return z;
15435}
15436
15437// ----
15438
15439function xlml_format(format, value) {
15440 var fmt = XLMLFormatMap[format] || unescapexml(format);
15441 if(fmt === "General") return SSF._general(value);
15442 return SSF.format(fmt, value);
15443}
15444
15445function xlml_set_custprop(Custprops, key, cp, val) {
15446 var oval = val;
15447 switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) {
15448 case "boolean": oval = parsexmlbool(val); break;
15449 case "i2": case "int": oval = parseInt(val, 10); break;
15450 case "r4": case "float": oval = parseFloat(val); break;
15451 case "date": case "dateTime.tz": oval = parseDate(val); break;
15452 case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break;
15453 default: throw new Error("bad custprop:" + cp[0]);
15454 }
15455 Custprops[unescapexml(key)] = oval;
15456}
15457
15458function safe_format_xlml(cell, nf, o) {
15459 if(cell.t === 'z') return;
15460 if(!o || o.cellText !== false) try {
15461 if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
15462 else if(nf === "General") {
15463 if(cell.t === 'n') {
15464 if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v);
15465 else cell.w = SSF._general_num(cell.v);
15466 }
15467 else cell.w = SSF._general(cell.v);
15468 }
15469 else cell.w = xlml_format(nf||"General", cell.v);
15470 } catch(e) { if(o.WTF) throw e; }
15471 try {
15472 var z = XLMLFormatMap[nf]||nf||"General";
15473 if(o.cellNF) cell.z = z;
15474 if(o.cellDates && cell.t == 'n' && SSF.is_date(z)) {
15475 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); }
15476 }
15477 } catch(e) { if(o.WTF) throw e; }
15478}
15479
15480function process_style_xlml(styles, stag, opts) {
15481 if(opts.cellStyles) {
15482 if(stag.Interior) {
15483 var I = stag.Interior;
15484 if(I.Pattern) I.patternType = XLMLPatternTypeMap[I.Pattern] || I.Pattern;
15485 }
15486 }
15487 styles[stag.ID] = stag;
15488}
15489
15490/* TODO: there must exist some form of OSP-blessed spec */
15491function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o) {
15492 var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
15493 var interiors = [];
15494 var i = 0;
15495 if(sid === undefined && row) sid = row.StyleID;
15496 if(sid === undefined && csty) sid = csty.StyleID;
15497 while(styles[sid] !== undefined) {
15498 if(styles[sid].nf) nf = styles[sid].nf;
15499 if(styles[sid].Interior) interiors.push(styles[sid].Interior);
15500 if(!styles[sid].Parent) break;
15501 sid = styles[sid].Parent;
15502 }
15503 switch(data.Type) {
15504 case 'Boolean':
15505 cell.t = 'b';
15506 cell.v = parsexmlbool(xml);
15507 break;
15508 case 'String':
15509 cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
15510 cell.v = xml.indexOf("<") > -1 ? unescapexml(ss||xml) : cell.r;
15511 break;
15512 case 'DateTime':
15513 if(xml.slice(-1) != "Z") xml += "Z";
15514 cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
15515 if(cell.v !== cell.v) cell.v = unescapexml(xml);
15516 else if(cell.v<60) cell.v = cell.v -1;
15517 if(!nf || nf == "General") nf = "yyyy-mm-dd";
15518 /* falls through */
15519 case 'Number':
15520 if(cell.v === undefined) cell.v=+xml;
15521 if(!cell.t) cell.t = 'n';
15522 break;
15523 case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
15524 default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
15525 }
15526 safe_format_xlml(cell, nf, o);
15527 if(o.cellFormula !== false) {
15528 if(cell.Formula) {
15529 var fstr = unescapexml(cell.Formula);
15530 /* strictly speaking, the leading = is required but some writers omit */
15531 if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.slice(1);
15532 cell.f = rc_to_a1(fstr, base);
15533 delete cell.Formula;
15534 if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base);
15535 else if(cell.ArrayRange) {
15536 cell.F = rc_to_a1(cell.ArrayRange, base);
15537 arrayf.push([safe_decode_range(cell.F), cell.F]);
15538 }
15539 } else {
15540 for(i = 0; i < arrayf.length; ++i)
15541 if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r)
15542 if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c)
15543 cell.F = arrayf[i][1];
15544 }
15545 }
15546 if(o.cellStyles) {
15547 interiors.forEach(function(x) {
15548 if(!S.patternType && x.patternType) S.patternType = x.patternType;
15549 });
15550 cell.s = S;
15551 }
15552 if(cell.StyleID !== undefined) cell.ixfe = cell.StyleID;
15553}
15554
15555function xlml_clean_comment(comment) {
15556 comment.t = comment.v || "";
15557 comment.t = comment.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
15558 comment.v = comment.w = comment.ixfe = undefined;
15559}
15560
15561function xlml_normalize(d) {
15562 if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
15563 if(typeof d === 'string') return d;
15564 /* duktape */
15565 if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d)));
15566 throw new Error("Bad input format: expected Buffer or string");
15567}
15568
15569/* TODO: Everything */
15570/* UOS uses CJK in tags */
15571var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>:\/]+)[^>]*>/mg;
15572//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
15573function parse_xlml_xml(d, _opts) {
15574 var opts = _opts || {};
15575 make_ssf(SSF);
15576 var str = debom(xlml_normalize(d));
15577 if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') {
15578 if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
15579 else str = utf8read(str);
15580 }
15581 var opening = str.slice(0, 1024).toLowerCase(), ishtml = false;
15582 if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; });
15583 if(ishtml) return HTML_.to_workbook(str, opts);
15584 var Rn;
15585 var state = [], tmp;
15586 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
15587 var sheets = {}, sheetnames = [], cursheet = (opts.dense ? [] : {}), sheetname = "";
15588 var table = {}, cell = ({}), row = {};// eslint-disable-line no-unused-vars
15589 var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
15590 var c = 0, r = 0;
15591 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
15592 var styles = {}, stag = {};
15593 var ss = "", fidx = 0;
15594 var merges = [];
15595 var Props = {}, Custprops = {}, pidx = 0, cp = [];
15596 var comments = [], comment = ({});
15597 var cstys = [], csty, seencol = false;
15598 var arrayf = [];
15599 var rowinfo = [], rowobj = {}, cc = 0, rr = 0;
15600 var Workbook = ({ Sheets:[], WBProps:{date1904:false} }), wsprops = {};
15601 xlmlregex.lastIndex = 0;
15602 str = str.replace(/<!--([\s\S]*?)-->/mg,"");
15603 while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
15604 case 'Data':
15605 if(state[state.length-1][1]) break;
15606 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);
15607 else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
15608 break;
15609 case 'Cell':
15610 if(Rn[1]==='/'){
15611 if(comments.length > 0) cell.c = comments;
15612 if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) {
15613 if(opts.dense) {
15614 if(!cursheet[r]) cursheet[r] = [];
15615 cursheet[r][c] = cell;
15616 } else cursheet[encode_col(c) + encode_row(r)] = cell;
15617 }
15618 if(cell.HRef) {
15619 cell.l = ({Target:cell.HRef});
15620 if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
15621 delete cell.HRef; delete cell.HRefScreenTip;
15622 }
15623 if(cell.MergeAcross || cell.MergeDown) {
15624 cc = c + (parseInt(cell.MergeAcross,10)|0);
15625 rr = r + (parseInt(cell.MergeDown,10)|0);
15626 merges.push({s:{c:c,r:r},e:{c:cc,r:rr}});
15627 }
15628 if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
15629 else if(cell.MergeAcross || cell.MergeDown) {
15630for(var cma = c; cma <= cc; ++cma) {
15631 for(var cmd = r; cmd <= rr; ++cmd) {
15632 if(cma > c || cmd > r) {
15633 if(opts.dense) {
15634 if(!cursheet[cmd]) cursheet[cmd] = [];
15635 cursheet[cmd][cma] = {t:'z'};
15636 } else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
15637 }
15638 }
15639 }
15640 c = cc + 1;
15641 }
15642 else ++c;
15643 } else {
15644 cell = xlml_parsexmltagobj(Rn[0]);
15645 if(cell.Index) c = +cell.Index - 1;
15646 if(c < refguess.s.c) refguess.s.c = c;
15647 if(c > refguess.e.c) refguess.e.c = c;
15648 if(Rn[0].slice(-2) === "/>") ++c;
15649 comments = [];
15650 }
15651 break;
15652 case 'Row':
15653 if(Rn[1]==='/' || Rn[0].slice(-2) === "/>") {
15654 if(r < refguess.s.r) refguess.s.r = r;
15655 if(r > refguess.e.r) refguess.e.r = r;
15656 if(Rn[0].slice(-2) === "/>") {
15657 row = xlml_parsexmltag(Rn[0]);
15658 if(row.Index) r = +row.Index - 1;
15659 }
15660 c = 0; ++r;
15661 } else {
15662 row = xlml_parsexmltag(Rn[0]);
15663 if(row.Index) r = +row.Index - 1;
15664 rowobj = {};
15665 if(row.AutoFitHeight == "0" || row.Height) {
15666 rowobj.hpx = parseInt(row.Height, 10); rowobj.hpt = px2pt(rowobj.hpx);
15667 rowinfo[r] = rowobj;
15668 }
15669 if(row.Hidden == "1") { rowobj.hidden = true; rowinfo[r] = rowobj; }
15670 }
15671 break;
15672 case 'Worksheet': /* TODO: read range from FullRows/FullColumns */
15673 if(Rn[1]==='/'){
15674 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15675 sheetnames.push(sheetname);
15676 if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) {
15677 cursheet["!ref"] = encode_range(refguess);
15678 if(opts.sheetRows && opts.sheetRows <= refguess.e.r) {
15679 cursheet["!fullref"] = cursheet["!ref"];
15680 refguess.e.r = opts.sheetRows - 1;
15681 cursheet["!ref"] = encode_range(refguess);
15682 }
15683 }
15684 if(merges.length) cursheet["!merges"] = merges;
15685 if(cstys.length > 0) cursheet["!cols"] = cstys;
15686 if(rowinfo.length > 0) cursheet["!rows"] = rowinfo;
15687 sheets[sheetname] = cursheet;
15688 } else {
15689 refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
15690 r = c = 0;
15691 state.push([Rn[3], false]);
15692 tmp = xlml_parsexmltag(Rn[0]);
15693 sheetname = unescapexml(tmp.Name);
15694 cursheet = (opts.dense ? [] : {});
15695 merges = [];
15696 arrayf = [];
15697 rowinfo = [];
15698 wsprops = {name:sheetname, Hidden:0};
15699 Workbook.Sheets.push(wsprops);
15700 }
15701 break;
15702 case 'Table':
15703 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15704 else if(Rn[0].slice(-2) == "/>") break;
15705 else {
15706 table = xlml_parsexmltag(Rn[0]);
15707 state.push([Rn[3], false]);
15708 cstys = []; seencol = false;
15709 }
15710 break;
15711
15712 case 'Style':
15713 if(Rn[1]==='/') process_style_xlml(styles, stag, opts);
15714 else stag = xlml_parsexmltag(Rn[0]);
15715 break;
15716
15717 case 'NumberFormat':
15718 stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
15719 if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
15720 for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
15721 if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
15722 break;
15723
15724 case 'Column':
15725 if(state[state.length-1][0] !== 'Table') break;
15726 csty = xlml_parsexmltag(Rn[0]);
15727 if(csty.Hidden) { csty.hidden = true; delete csty.Hidden; }
15728 if(csty.Width) csty.wpx = parseInt(csty.Width, 10);
15729 if(!seencol && csty.wpx > 10) {
15730 seencol = true; MDW = DEF_MDW; //find_mdw_wpx(csty.wpx);
15731 for(var _col = 0; _col < cstys.length; ++_col) if(cstys[_col]) process_col(cstys[_col]);
15732 }
15733 if(seencol) process_col(csty);
15734 cstys[(csty.Index-1||cstys.length)] = csty;
15735 for(var i = 0; i < +csty.Span; ++i) cstys[cstys.length] = dup(csty);
15736 break;
15737
15738 case 'NamedRange':
15739 if(!Workbook.Names) Workbook.Names = [];
15740 var _NamedRange = parsexmltag(Rn[0]);
15741 var _DefinedName = ({
15742 Name: _NamedRange.Name,
15743 Ref: rc_to_a1(_NamedRange.RefersTo.slice(1), {r:0, c:0})
15744 });
15745 if(Workbook.Sheets.length>0) _DefinedName.Sheet=Workbook.Sheets.length-1;
15746Workbook.Names.push(_DefinedName);
15747 break;
15748
15749 case 'NamedCell': break;
15750 case 'B': break;
15751 case 'I': break;
15752 case 'U': break;
15753 case 'S': break;
15754 case 'Sub': break;
15755 case 'Sup': break;
15756 case 'Span': break;
15757 case 'Alignment':
15758 break;
15759 case 'Borders': break;
15760 case 'Border': break;
15761 case 'Font':
15762 if(Rn[0].slice(-2) === "/>") break;
15763 else if(Rn[1]==="/") ss += str.slice(fidx, Rn.index);
15764 else fidx = Rn.index + Rn[0].length;
15765 break;
15766 case 'Interior':
15767 if(!opts.cellStyles) break;
15768 stag.Interior = xlml_parsexmltag(Rn[0]);
15769 break;
15770 case 'Protection': break;
15771
15772 case 'Author':
15773 case 'Title':
15774 case 'Description':
15775 case 'Created':
15776 case 'Keywords':
15777 case 'Subject':
15778 case 'Category':
15779 case 'Company':
15780 case 'LastAuthor':
15781 case 'LastSaved':
15782 case 'LastPrinted':
15783 case 'Version':
15784 case 'Revision':
15785 case 'TotalTime':
15786 case 'HyperlinkBase':
15787 case 'Manager':
15788 case 'ContentStatus':
15789 case 'Identifier':
15790 case 'Language':
15791 case 'AppName':
15792 if(Rn[0].slice(-2) === "/>") break;
15793 else if(Rn[1]==="/") xlml_set_prop(Props, Rn[3], str.slice(pidx, Rn.index));
15794 else pidx = Rn.index + Rn[0].length;
15795 break;
15796 case 'Paragraphs': break;
15797
15798 case 'Styles':
15799 case 'Workbook':
15800 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15801 else state.push([Rn[3], false]);
15802 break;
15803
15804 case 'Comment':
15805 if(Rn[1]==='/'){
15806 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15807 xlml_clean_comment(comment);
15808 comments.push(comment);
15809 } else {
15810 state.push([Rn[3], false]);
15811 tmp = xlml_parsexmltag(Rn[0]);
15812 comment = ({a:tmp.Author});
15813 }
15814 break;
15815
15816 case 'AutoFilter':
15817 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15818 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
15819 var AutoFilter = xlml_parsexmltag(Rn[0]);
15820 cursheet['!autofilter'] = { ref:rc_to_a1(AutoFilter.Range).replace(/\$/g,"") };
15821 state.push([Rn[3], true]);
15822 }
15823 break;
15824
15825 case 'Name': break;
15826
15827 case 'DataValidation':
15828 if(Rn[1]==='/'){
15829 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15830 } else {
15831 if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
15832 }
15833 break;
15834
15835 case 'ComponentOptions':
15836 case 'DocumentProperties':
15837 case 'CustomDocumentProperties':
15838 case 'OfficeDocumentSettings':
15839 case 'PivotTable':
15840 case 'PivotCache':
15841 case 'Names':
15842 case 'MapInfo':
15843 case 'PageBreaks':
15844 case 'QueryTable':
15845 case 'Sorting':
15846 case 'Schema':
15847 case 'data':
15848 case 'ConditionalFormatting':
15849 case 'SmartTagType':
15850 case 'SmartTags':
15851 case 'ExcelWorkbook':
15852 case 'WorkbookOptions':
15853 case 'WorksheetOptions':
15854 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15855 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
15856 break;
15857
15858 default:
15859 /* FODS file root is <office:document> */
15860 if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts);
15861 /* UOS file root is <uof:UOF> */
15862 if(state.length == 0 && Rn[3] == "UOF") return parse_fods(str, opts);
15863
15864 var seen = true;
15865 switch(state[state.length-1][0]) {
15866 /* OfficeDocumentSettings */
15867 case 'OfficeDocumentSettings': switch(Rn[3]) {
15868 case 'AllowPNG': break;
15869 case 'RemovePersonalInformation': break;
15870 case 'DownloadComponents': break;
15871 case 'LocationOfComponents': break;
15872 case 'Colors': break;
15873 case 'Color': break;
15874 case 'Index': break;
15875 case 'RGB': break;
15876 case 'PixelsPerInch': break; // TODO: set PPI
15877 case 'TargetScreenSize': break;
15878 case 'ReadOnlyRecommended': break;
15879 default: seen = false;
15880 } break;
15881
15882 /* ComponentOptions */
15883 case 'ComponentOptions': switch(Rn[3]) {
15884 case 'Toolbar': break;
15885 case 'HideOfficeLogo': break;
15886 case 'SpreadsheetAutoFit': break;
15887 case 'Label': break;
15888 case 'Caption': break;
15889 case 'MaxHeight': break;
15890 case 'MaxWidth': break;
15891 case 'NextSheetNumber': break;
15892 default: seen = false;
15893 } break;
15894
15895 /* ExcelWorkbook */
15896 case 'ExcelWorkbook': switch(Rn[3]) {
15897 case 'Date1904':
15898Workbook.WBProps.date1904 = true;
15899 break;
15900 case 'WindowHeight': break;
15901 case 'WindowWidth': break;
15902 case 'WindowTopX': break;
15903 case 'WindowTopY': break;
15904 case 'TabRatio': break;
15905 case 'ProtectStructure': break;
15906 case 'ProtectWindow': break;
15907 case 'ProtectWindows': break;
15908 case 'ActiveSheet': break;
15909 case 'DisplayInkNotes': break;
15910 case 'FirstVisibleSheet': break;
15911 case 'SupBook': break;
15912 case 'SheetName': break;
15913 case 'SheetIndex': break;
15914 case 'SheetIndexFirst': break;
15915 case 'SheetIndexLast': break;
15916 case 'Dll': break;
15917 case 'AcceptLabelsInFormulas': break;
15918 case 'DoNotSaveLinkValues': break;
15919 case 'Iteration': break;
15920 case 'MaxIterations': break;
15921 case 'MaxChange': break;
15922 case 'Path': break;
15923 case 'Xct': break;
15924 case 'Count': break;
15925 case 'SelectedSheets': break;
15926 case 'Calculation': break;
15927 case 'Uncalced': break;
15928 case 'StartupPrompt': break;
15929 case 'Crn': break;
15930 case 'ExternName': break;
15931 case 'Formula': break;
15932 case 'ColFirst': break;
15933 case 'ColLast': break;
15934 case 'WantAdvise': break;
15935 case 'Boolean': break;
15936 case 'Error': break;
15937 case 'Text': break;
15938 case 'OLE': break;
15939 case 'NoAutoRecover': break;
15940 case 'PublishObjects': break;
15941 case 'DoNotCalculateBeforeSave': break;
15942 case 'Number': break;
15943 case 'RefModeR1C1': break;
15944 case 'EmbedSaveSmartTags': break;
15945 default: seen = false;
15946 } break;
15947
15948 /* WorkbookOptions */
15949 case 'WorkbookOptions': switch(Rn[3]) {
15950 case 'OWCVersion': break;
15951 case 'Height': break;
15952 case 'Width': break;
15953 default: seen = false;
15954 } break;
15955
15956 /* WorksheetOptions */
15957 case 'WorksheetOptions': switch(Rn[3]) {
15958 case 'Visible':
15959 if(Rn[0].slice(-2) === "/>"){/* empty */}
15960 else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
15961 case "SheetHidden": wsprops.Hidden = 1; break;
15962 case "SheetVeryHidden": wsprops.Hidden = 2; break;
15963 }
15964 else pidx = Rn.index + Rn[0].length;
15965 break;
15966 case 'Header':
15967 if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
15968 cursheet['!margins'].header = parsexmltag(Rn[0]).Margin;
15969 break;
15970 case 'Footer':
15971 if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
15972 cursheet['!margins'].footer = parsexmltag(Rn[0]).Margin;
15973 break;
15974 case 'PageMargins':
15975 var pagemargins = parsexmltag(Rn[0]);
15976 if(!cursheet['!margins']) default_margins(cursheet['!margins']={},'xlml');
15977 if(pagemargins.Top) cursheet['!margins'].top = pagemargins.Top;
15978 if(pagemargins.Left) cursheet['!margins'].left = pagemargins.Left;
15979 if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right;
15980 if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom;
15981 break;
15982 case 'DisplayRightToLeft':
15983 if(!Workbook.Views) Workbook.Views = [];
15984 if(!Workbook.Views[0]) Workbook.Views[0] = {};
15985 Workbook.Views[0].RTL = true;
15986 break;
15987
15988 case 'FreezePanes': break;
15989 case 'FrozenNoSplit': break;
15990
15991 case 'SplitHorizontal':
15992 case 'SplitVertical':
15993 break;
15994
15995 case 'DoNotDisplayGridlines':
15996 break;
15997
15998 case 'TopRowBottomPane': break;
15999 case 'LeftColumnRightPane': break;
16000
16001 case 'Unsynced': break;
16002 case 'Print': break;
16003 case 'Panes': break;
16004 case 'Scale': break;
16005 case 'Pane': break;
16006 case 'Number': break;
16007 case 'Layout': break;
16008 case 'PageSetup': break;
16009 case 'Selected': break;
16010 case 'ProtectObjects': break;
16011 case 'EnableSelection': break;
16012 case 'ProtectScenarios': break;
16013 case 'ValidPrinterInfo': break;
16014 case 'HorizontalResolution': break;
16015 case 'VerticalResolution': break;
16016 case 'NumberofCopies': break;
16017 case 'ActiveRow': break;
16018 case 'ActiveCol': break;
16019 case 'ActivePane': break;
16020 case 'TopRowVisible': break;
16021 case 'LeftColumnVisible': break;
16022 case 'FitToPage': break;
16023 case 'RangeSelection': break;
16024 case 'PaperSizeIndex': break;
16025 case 'PageLayoutZoom': break;
16026 case 'PageBreakZoom': break;
16027 case 'FilterOn': break;
16028 case 'FitWidth': break;
16029 case 'FitHeight': break;
16030 case 'CommentsLayout': break;
16031 case 'Zoom': break;
16032 case 'LeftToRight': break;
16033 case 'Gridlines': break;
16034 case 'AllowSort': break;
16035 case 'AllowFilter': break;
16036 case 'AllowInsertRows': break;
16037 case 'AllowDeleteRows': break;
16038 case 'AllowInsertCols': break;
16039 case 'AllowDeleteCols': break;
16040 case 'AllowInsertHyperlinks': break;
16041 case 'AllowFormatCells': break;
16042 case 'AllowSizeCols': break;
16043 case 'AllowSizeRows': break;
16044 case 'NoSummaryRowsBelowDetail': break;
16045 case 'TabColorIndex': break;
16046 case 'DoNotDisplayHeadings': break;
16047 case 'ShowPageLayoutZoom': break;
16048 case 'NoSummaryColumnsRightDetail': break;
16049 case 'BlackAndWhite': break;
16050 case 'DoNotDisplayZeros': break;
16051 case 'DisplayPageBreak': break;
16052 case 'RowColHeadings': break;
16053 case 'DoNotDisplayOutline': break;
16054 case 'NoOrientation': break;
16055 case 'AllowUsePivotTables': break;
16056 case 'ZeroHeight': break;
16057 case 'ViewableRange': break;
16058 case 'Selection': break;
16059 case 'ProtectContents': break;
16060 default: seen = false;
16061 } break;
16062
16063 /* PivotTable */
16064 case 'PivotTable': case 'PivotCache': switch(Rn[3]) {
16065 case 'ImmediateItemsOnDrop': break;
16066 case 'ShowPageMultipleItemLabel': break;
16067 case 'CompactRowIndent': break;
16068 case 'Location': break;
16069 case 'PivotField': break;
16070 case 'Orientation': break;
16071 case 'LayoutForm': break;
16072 case 'LayoutSubtotalLocation': break;
16073 case 'LayoutCompactRow': break;
16074 case 'Position': break;
16075 case 'PivotItem': break;
16076 case 'DataType': break;
16077 case 'DataField': break;
16078 case 'SourceName': break;
16079 case 'ParentField': break;
16080 case 'PTLineItems': break;
16081 case 'PTLineItem': break;
16082 case 'CountOfSameItems': break;
16083 case 'Item': break;
16084 case 'ItemType': break;
16085 case 'PTSource': break;
16086 case 'CacheIndex': break;
16087 case 'ConsolidationReference': break;
16088 case 'FileName': break;
16089 case 'Reference': break;
16090 case 'NoColumnGrand': break;
16091 case 'NoRowGrand': break;
16092 case 'BlankLineAfterItems': break;
16093 case 'Hidden': break;
16094 case 'Subtotal': break;
16095 case 'BaseField': break;
16096 case 'MapChildItems': break;
16097 case 'Function': break;
16098 case 'RefreshOnFileOpen': break;
16099 case 'PrintSetTitles': break;
16100 case 'MergeLabels': break;
16101 case 'DefaultVersion': break;
16102 case 'RefreshName': break;
16103 case 'RefreshDate': break;
16104 case 'RefreshDateCopy': break;
16105 case 'VersionLastRefresh': break;
16106 case 'VersionLastUpdate': break;
16107 case 'VersionUpdateableMin': break;
16108 case 'VersionRefreshableMin': break;
16109 case 'Calculation': break;
16110 default: seen = false;
16111 } break;
16112
16113 /* PageBreaks */
16114 case 'PageBreaks': switch(Rn[3]) {
16115 case 'ColBreaks': break;
16116 case 'ColBreak': break;
16117 case 'RowBreaks': break;
16118 case 'RowBreak': break;
16119 case 'ColStart': break;
16120 case 'ColEnd': break;
16121 case 'RowEnd': break;
16122 default: seen = false;
16123 } break;
16124
16125 /* AutoFilter */
16126 case 'AutoFilter': switch(Rn[3]) {
16127 case 'AutoFilterColumn': break;
16128 case 'AutoFilterCondition': break;
16129 case 'AutoFilterAnd': break;
16130 case 'AutoFilterOr': break;
16131 default: seen = false;
16132 } break;
16133
16134 /* QueryTable */
16135 case 'QueryTable': switch(Rn[3]) {
16136 case 'Id': break;
16137 case 'AutoFormatFont': break;
16138 case 'AutoFormatPattern': break;
16139 case 'QuerySource': break;
16140 case 'QueryType': break;
16141 case 'EnableRedirections': break;
16142 case 'RefreshedInXl9': break;
16143 case 'URLString': break;
16144 case 'HTMLTables': break;
16145 case 'Connection': break;
16146 case 'CommandText': break;
16147 case 'RefreshInfo': break;
16148 case 'NoTitles': break;
16149 case 'NextId': break;
16150 case 'ColumnInfo': break;
16151 case 'OverwriteCells': break;
16152 case 'DoNotPromptForFile': break;
16153 case 'TextWizardSettings': break;
16154 case 'Source': break;
16155 case 'Number': break;
16156 case 'Decimal': break;
16157 case 'ThousandSeparator': break;
16158 case 'TrailingMinusNumbers': break;
16159 case 'FormatSettings': break;
16160 case 'FieldType': break;
16161 case 'Delimiters': break;
16162 case 'Tab': break;
16163 case 'Comma': break;
16164 case 'AutoFormatName': break;
16165 case 'VersionLastEdit': break;
16166 case 'VersionLastRefresh': break;
16167 default: seen = false;
16168 } break;
16169
16170 case 'DataValidation':
16171 switch(Rn[3]) {
16172 case 'Range': break;
16173
16174 case 'Type': break;
16175 case 'Min': break;
16176 case 'Max': break;
16177 case 'Sort': break;
16178 case 'Descending': break;
16179 case 'Order': break;
16180 case 'CaseSensitive': break;
16181 case 'Value': break;
16182 case 'ErrorStyle': break;
16183 case 'ErrorMessage': break;
16184 case 'ErrorTitle': break;
16185 case 'InputMessage': break;
16186 case 'InputTitle': break;
16187 case 'ComboHide': break;
16188 case 'InputHide': break;
16189 case 'Condition': break;
16190 case 'Qualifier': break;
16191 case 'UseBlank': break;
16192 case 'Value1': break;
16193 case 'Value2': break;
16194 case 'Format': break;
16195
16196 case 'CellRangeList': break;
16197 default: seen = false;
16198 } break;
16199
16200 case 'Sorting':
16201 case 'ConditionalFormatting':
16202 switch(Rn[3]) {
16203 case 'Range': break;
16204 case 'Type': break;
16205 case 'Min': break;
16206 case 'Max': break;
16207 case 'Sort': break;
16208 case 'Descending': break;
16209 case 'Order': break;
16210 case 'CaseSensitive': break;
16211 case 'Value': break;
16212 case 'ErrorStyle': break;
16213 case 'ErrorMessage': break;
16214 case 'ErrorTitle': break;
16215 case 'CellRangeList': break;
16216 case 'InputMessage': break;
16217 case 'InputTitle': break;
16218 case 'ComboHide': break;
16219 case 'InputHide': break;
16220 case 'Condition': break;
16221 case 'Qualifier': break;
16222 case 'UseBlank': break;
16223 case 'Value1': break;
16224 case 'Value2': break;
16225 case 'Format': break;
16226 default: seen = false;
16227 } break;
16228
16229 /* MapInfo (schema) */
16230 case 'MapInfo': case 'Schema': case 'data': switch(Rn[3]) {
16231 case 'Map': break;
16232 case 'Entry': break;
16233 case 'Range': break;
16234 case 'XPath': break;
16235 case 'Field': break;
16236 case 'XSDType': break;
16237 case 'FilterOn': break;
16238 case 'Aggregate': break;
16239 case 'ElementType': break;
16240 case 'AttributeType': break;
16241 /* These are from xsd (XML Schema Definition) */
16242 case 'schema':
16243 case 'element':
16244 case 'complexType':
16245 case 'datatype':
16246 case 'all':
16247 case 'attribute':
16248 case 'extends': break;
16249
16250 case 'row': break;
16251 default: seen = false;
16252 } break;
16253
16254 /* SmartTags (can be anything) */
16255 case 'SmartTags': break;
16256
16257 default: seen = false; break;
16258 }
16259 if(seen) break;
16260 /* CustomDocumentProperties */
16261 if(Rn[3].match(/!\[CDATA/)) break;
16262 if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
16263 if(state[state.length-1][0]==='CustomDocumentProperties') {
16264 if(Rn[0].slice(-2) === "/>") break;
16265 else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn[3], cp, str.slice(pidx, Rn.index));
16266 else { cp = Rn; pidx = Rn.index + Rn[0].length; }
16267 break;
16268 }
16269 if(opts.WTF) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
16270 }
16271 var out = ({});
16272 if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
16273 out.SheetNames = sheetnames;
16274 out.Workbook = Workbook;
16275 out.SSF = SSF.get_table();
16276 out.Props = Props;
16277 out.Custprops = Custprops;
16278 return out;
16279}
16280
16281function parse_xlml(data, opts) {
16282 fix_read_opts(opts=opts||{});
16283 switch(opts.type||"base64") {
16284 case "base64": return parse_xlml_xml(Base64.decode(data), opts);
16285 case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
16286 case "array": return parse_xlml_xml(a2s(data), opts);
16287 }
16288}
16289
16290/* TODO */
16291function write_props_xlml(wb, opts) {
16292 var o = [];
16293 /* DocumentProperties */
16294 if(wb.Props) o.push(xlml_write_docprops(wb.Props, opts));
16295 /* CustomDocumentProperties */
16296 if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops, opts));
16297 return o.join("");
16298}
16299/* TODO */
16300function write_wb_xlml() {
16301 /* OfficeDocumentSettings */
16302 /* ExcelWorkbook */
16303 return "";
16304}
16305/* TODO */
16306function write_sty_xlml(wb, opts) {
16307 /* Styles */
16308 var styles = ['<Style ss:ID="Default" ss:Name="Normal"><NumberFormat/></Style>'];
16309 opts.cellXfs.forEach(function(xf, id) {
16310 var payload = [];
16311 payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])}));
16312 styles.push(writextag('Style', payload.join(""), {"ss:ID": "s" + (21+id)}));
16313 });
16314 return writextag("Styles", styles.join(""));
16315}
16316function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); }
16317function write_names_xlml(wb) {
16318 if(!((wb||{}).Workbook||{}).Names) return "";
16319var names = wb.Workbook.Names;
16320 var out = [];
16321 for(var i = 0; i < names.length; ++i) {
16322 var n = names[i];
16323 if(n.Sheet != null) continue;
16324 if(n.Name.match(/^_xlfn\./)) continue;
16325 out.push(write_name_xlml(n));
16326 }
16327 return writextag("Names", out.join(""));
16328}
16329function write_ws_xlml_names(ws, opts, idx, wb) {
16330 if(!ws) return "";
16331 if(!((wb||{}).Workbook||{}).Names) return "";
16332var names = wb.Workbook.Names;
16333 var out = [];
16334 for(var i = 0; i < names.length; ++i) {
16335 var n = names[i];
16336 if(n.Sheet != idx) continue;
16337 /*switch(n.Name) {
16338 case "_": continue;
16339 }*/
16340 if(n.Name.match(/^_xlfn\./)) continue;
16341 out.push(write_name_xlml(n));
16342 }
16343 return out.join("");
16344}
16345/* WorksheetOptions */
16346function write_ws_xlml_wsopts(ws, opts, idx, wb) {
16347 if(!ws) return "";
16348 var o = [];
16349 /* NOTE: spec technically allows any order, but stick with implied order */
16350
16351 /* FitToPage */
16352 /* DoNotDisplayColHeaders */
16353 /* DoNotDisplayRowHeaders */
16354 /* ViewableRange */
16355 /* Selection */
16356 /* GridlineColor */
16357 /* Name */
16358 /* ExcelWorksheetType */
16359 /* IntlMacro */
16360 /* Unsynced */
16361 /* Selected */
16362 /* CodeName */
16363
16364 if(ws['!margins']) {
16365 o.push("<PageSetup>");
16366 if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
16367 if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
16368 o.push(writextag("PageMargins", null, {
16369 'x:Bottom': ws['!margins'].bottom || "0.75",
16370 'x:Left': ws['!margins'].left || "0.7",
16371 'x:Right': ws['!margins'].right || "0.7",
16372 'x:Top': ws['!margins'].top || "0.75"
16373 }));
16374 o.push("</PageSetup>");
16375 }
16376
16377 /* PageSetup */
16378 /* DisplayPageBreak */
16379 /* TransitionExpressionEvaluation */
16380 /* TransitionFormulaEntry */
16381 /* Print */
16382 /* Zoom */
16383 /* PageLayoutZoom */
16384 /* PageBreakZoom */
16385 /* ShowPageBreakZoom */
16386 /* DefaultRowHeight */
16387 /* DefaultColumnWidth */
16388 /* StandardWidth */
16389
16390 if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
16391 /* Visible */
16392 if(wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
16393 else {
16394 /* Selected */
16395 for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
16396 if(i == idx) o.push("<Selected/>");
16397 }
16398 }
16399
16400 /* LeftColumnVisible */
16401
16402 if(((((wb||{}).Workbook||{}).Views||[])[0]||{}).RTL) o.push("<DisplayRightToLeft/>");
16403
16404 /* GridlineColorIndex */
16405 /* DisplayFormulas */
16406 /* DoNotDisplayGridlines */
16407 /* DoNotDisplayHeadings */
16408 /* DoNotDisplayOutline */
16409 /* ApplyAutomaticOutlineStyles */
16410 /* NoSummaryRowsBelowDetail */
16411 /* NoSummaryColumnsRightDetail */
16412 /* DoNotDisplayZeros */
16413 /* ActiveRow */
16414 /* ActiveColumn */
16415 /* FilterOn */
16416 /* RangeSelection */
16417 /* TopRowVisible */
16418 /* TopRowBottomPane */
16419 /* LeftColumnRightPane */
16420 /* ActivePane */
16421 /* SplitHorizontal */
16422 /* SplitVertical */
16423 /* FreezePanes */
16424 /* FrozenNoSplit */
16425 /* TabColorIndex */
16426 /* Panes */
16427
16428 /* NOTE: Password not supported in XLML Format */
16429 if(ws['!protect']) {
16430 o.push(writetag("ProtectContents", "True"));
16431 if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
16432 if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
16433 if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
16434 else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
16435 [
16436 [ "formatCells", "AllowFormatCells" ],
16437 [ "formatColumns", "AllowSizeCols" ],
16438 [ "formatRows", "AllowSizeRows" ],
16439 [ "insertColumns", "AllowInsertCols" ],
16440 [ "insertRows", "AllowInsertRows" ],
16441 [ "insertHyperlinks", "AllowInsertHyperlinks" ],
16442 [ "deleteColumns", "AllowDeleteCols" ],
16443 [ "deleteRows", "AllowDeleteRows" ],
16444 [ "sort", "AllowSort" ],
16445 [ "autoFilter", "AllowFilter" ],
16446 [ "pivotTables", "AllowUsePivotTables" ]
16447 ].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
16448 }
16449
16450 if(o.length == 0) return "";
16451 return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
16452}
16453function write_ws_xlml_comment(comments) {
16454 return comments.map(function(c) {
16455 // TODO: formatted text
16456 var t = xlml_unfixstr(c.t||"");
16457 var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
16458 return writextag("Comment", d, {"ss:Author":c.a});
16459 }).join("");
16460}
16461function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
16462 if(!cell || (cell.v == undefined && cell.f == undefined)) return "";
16463
16464 var attr = {};
16465 if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
16466 if(cell.F && cell.F.slice(0, ref.length) == ref) {
16467 var end = decode_cell(cell.F.slice(ref.length + 1));
16468 attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
16469 }
16470
16471 if(cell.l && cell.l.Target) {
16472 attr["ss:HRef"] = escapexml(cell.l.Target);
16473 if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
16474 }
16475
16476 if(ws['!merges']) {
16477 var marr = ws['!merges'];
16478 for(var mi = 0; mi != marr.length; ++mi) {
16479 if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
16480 if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
16481 if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
16482 }
16483 }
16484
16485 var t = "", p = "";
16486 switch(cell.t) {
16487 case 'z': if(!opts.sheetStubs) return ""; break;
16488 case 'n': t = 'Number'; p = String(cell.v); break;
16489 case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
16490 case 'e': t = 'Error'; p = BErr[cell.v]; break;
16491 case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break;
16492 case 's': t = 'String'; p = escapexlml(cell.v||""); break;
16493 }
16494 /* TODO: cell style */
16495 var os = get_cell_style(opts.cellXfs, cell, opts);
16496 attr["ss:StyleID"] = "s" + (21+os);
16497 attr["ss:Index"] = addr.c + 1;
16498 var _v = (cell.v != null ? p : "");
16499 var m = cell.t == 'z' ? "" : ('<Data ss:Type="' + t + '">' + _v + '</Data>');
16500
16501 if((cell.c||[]).length > 0) m += write_ws_xlml_comment(cell.c);
16502
16503 return writextag("Cell", m, attr);
16504}
16505function write_ws_xlml_row(R, row) {
16506 var o = '<Row ss:Index="' + (R+1) + '"';
16507 if(row) {
16508 if(row.hpt && !row.hpx) row.hpx = pt2px(row.hpt);
16509 if(row.hpx) o += ' ss:AutoFitHeight="0" ss:Height="' + row.hpx + '"';
16510 if(row.hidden) o += ' ss:Hidden="1"';
16511 }
16512 return o + '>';
16513}
16514/* TODO */
16515function write_ws_xlml_table(ws, opts, idx, wb) {
16516 if(!ws['!ref']) return "";
16517 var range = safe_decode_range(ws['!ref']);
16518 var marr = ws['!merges'] || [], mi = 0;
16519 var o = [];
16520 if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
16521 process_col(n);
16522 var w = !!n.width;
16523 var p = col_obj_w(i, n);
16524 var k = {"ss:Index":i+1};
16525 if(w) k['ss:Width'] = width2px(p.width);
16526 if(n.hidden) k['ss:Hidden']="1";
16527 o.push(writextag("Column",null,k));
16528 });
16529 var dense = Array.isArray(ws);
16530 for(var R = range.s.r; R <= range.e.r; ++R) {
16531 var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
16532 for(var C = range.s.c; C <= range.e.c; ++C) {
16533 var skip = false;
16534 for(mi = 0; mi != marr.length; ++mi) {
16535 if(marr[mi].s.c > C) continue;
16536 if(marr[mi].s.r > R) continue;
16537 if(marr[mi].e.c < C) continue;
16538 if(marr[mi].e.r < R) continue;
16539 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
16540 break;
16541 }
16542 if(skip) continue;
16543 var addr = {r:R,c:C};
16544 var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
16545 row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
16546 }
16547 row.push("</Row>");
16548 if(row.length > 2) o.push(row.join(""));
16549 }
16550 return o.join("");
16551}
16552function write_ws_xlml(idx, opts, wb) {
16553 var o = [];
16554 var s = wb.SheetNames[idx];
16555 var ws = wb.Sheets[s];
16556
16557 var t = ws ? write_ws_xlml_names(ws, opts, idx, wb) : "";
16558 if(t.length > 0) o.push("<Names>" + t + "</Names>");
16559
16560 /* Table */
16561 t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
16562 if(t.length > 0) o.push("<Table>" + t + "</Table>");
16563
16564 /* WorksheetOptions */
16565 o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
16566
16567 return o.join("");
16568}
16569function write_xlml(wb, opts) {
16570 if(!opts) opts = {};
16571 if(!wb.SSF) wb.SSF = SSF.get_table();
16572 if(wb.SSF) {
16573 make_ssf(SSF); SSF.load_table(wb.SSF);
16574 // $FlowIgnore
16575 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
16576 opts.ssf = wb.SSF;
16577 opts.cellXfs = [];
16578 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
16579 }
16580 var d = [];
16581 d.push(write_props_xlml(wb, opts));
16582 d.push(write_wb_xlml(wb, opts));
16583 d.push("");
16584 d.push("");
16585 for(var i = 0; i < wb.SheetNames.length; ++i)
16586 d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
16587 d[2] = write_sty_xlml(wb, opts);
16588 d[3] = write_names_xlml(wb, opts);
16589 return XML_HEADER + writextag("Workbook", d.join(""), {
16590 'xmlns': XLMLNS.ss,
16591 'xmlns:o': XLMLNS.o,
16592 'xmlns:x': XLMLNS.x,
16593 'xmlns:ss': XLMLNS.ss,
16594 'xmlns:dt': XLMLNS.dt,
16595 'xmlns:html': XLMLNS.html
16596 });
16597}
16598/* [MS-OLEDS] 2.3.8 CompObjStream */
16599function parse_compobj(obj) {
16600 var v = {};
16601 var o = obj.content;
16602/* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
16603 o.l = 28;
16604
16605 v.AnsiUserType = o.read_shift(0, "lpstr-ansi");
16606 v.AnsiClipboardFormat = parse_ClipboardFormatOrAnsiString(o);
16607
16608 if(o.length - o.l <= 4) return v;
16609
16610 var m = o.read_shift(4);
16611 if(m == 0 || m > 40) return v;
16612 o.l-=4; v.Reserved1 = o.read_shift(0, "lpstr-ansi");
16613
16614 if(o.length - o.l <= 4) return v;
16615 m = o.read_shift(4);
16616 if(m !== 0x71b239f4) return v;
16617 v.UnicodeClipboardFormat = parse_ClipboardFormatOrUnicodeString(o);
16618
16619 m = o.read_shift(4);
16620 if(m == 0 || m > 40) return v;
16621 o.l-=4; v.Reserved2 = o.read_shift(0, "lpwstr");
16622}
16623
16624/*
16625 Continue logic for:
16626 - 2.4.58 Continue
16627 - 2.4.59 ContinueBigName
16628 - 2.4.60 ContinueFrt
16629 - 2.4.61 ContinueFrt11
16630 - 2.4.62 ContinueFrt12
16631*/
16632function slurp(R, blob, length, opts) {
16633 var l = length;
16634 var bufs = [];
16635 var d = blob.slice(blob.l,blob.l+l);
16636 if(opts && opts.enc && opts.enc.insitu) switch(R.n) {
16637 case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': break;
16638 default:
16639 if(d.length === 0) break;
16640 opts.enc.insitu(d);
16641 }
16642 bufs.push(d);
16643 blob.l += l;
16644 var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]);
16645 var start = 0;
16646 while(next != null && next.n.slice(0,8) === 'Continue') {
16647 l = __readUInt16LE(blob,blob.l+2);
16648 start = blob.l + 4;
16649 if(next.n == 'ContinueFrt') start += 4;
16650 else if(next.n.slice(0,11) == 'ContinueFrt') start += 12;
16651 bufs.push(blob.slice(start,blob.l+4+l));
16652 blob.l += 4+l;
16653 next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]);
16654 }
16655 var b = (bconcat(bufs));
16656 prep_blob(b, 0);
16657 var ll = 0; b.lens = [];
16658 for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; }
16659 return R.f(b, b.length, opts);
16660}
16661
16662function safe_format_xf(p, opts, date1904) {
16663 if(p.t === 'z') return;
16664 if(!p.XF) return;
16665 var fmtid = 0;
16666 try {
16667 fmtid = p.z || p.XF.numFmtId || 0;
16668 if(opts.cellNF) p.z = SSF._table[fmtid];
16669 } catch(e) { if(opts.WTF) throw e; }
16670 if(!opts || opts.cellText !== false) try {
16671 if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
16672 else if(fmtid === 0 || fmtid == "General") {
16673 if(p.t === 'n') {
16674 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
16675 else p.w = SSF._general_num(p.v);
16676 }
16677 else p.w = SSF._general(p.v);
16678 }
16679 else p.w = SSF.format(fmtid,p.v, {date1904:!!date1904});
16680 } catch(e) { if(opts.WTF) throw e; }
16681 if(opts.cellDates && fmtid && p.t == 'n' && SSF.is_date(SSF._table[fmtid] || String(fmtid))) {
16682 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); }
16683 }
16684}
16685
16686function make_cell(val, ixfe, t) {
16687 return ({v:val, ixfe:ixfe, t:t});
16688}
16689
16690// 2.3.2
16691function parse_workbook(blob, options) {
16692 var wb = ({opts:{}});
16693 var Sheets = {};
16694 if(DENSE != null && options.dense == null) options.dense = DENSE;
16695 var out = ((options.dense ? [] : {}));
16696 var Directory = {};
16697 var range = ({});
16698 var last_formula = null;
16699 var sst = ([]);
16700 var cur_sheet = "";
16701 var Preamble = {};
16702 var lastcell, last_cell = "", cc, cmnt, rngC, rngR;
16703 var sharedf = {};
16704 var arrayf = [];
16705 var temp_val;
16706 var country;
16707 var cell_valid = true;
16708 var XFs = []; /* XF records */
16709 var palette = [];
16710 var Workbook = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }), wsprops = {};
16711 var get_rgb = function getrgb(icv) {
16712 if(icv < 8) return XLSIcv[icv];
16713 if(icv < 64) return palette[icv-8] || XLSIcv[icv];
16714 return XLSIcv[icv];
16715 };
16716 var process_cell_style = function pcs(cell, line, options) {
16717 var xfd = line.XF.data;
16718 if(!xfd || !xfd.patternType || !options || !options.cellStyles) return;
16719 line.s = ({});
16720 line.s.patternType = xfd.patternType;
16721 var t;
16722 if((t = rgb2Hex(get_rgb(xfd.icvFore)))) { line.s.fgColor = {rgb:t}; }
16723 if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
16724 };
16725 var addcell = function addcell(cell, line, options) {
16726 if(file_depth > 1) return;
16727 if(options.sheetRows && cell.r >= options.sheetRows) cell_valid = false;
16728 if(!cell_valid) return;
16729 if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options);
16730 delete line.ixfe; delete line.XF;
16731 lastcell = cell;
16732 last_cell = encode_cell(cell);
16733 if(!range || !range.s || !range.e) range = {s:{r:0,c:0},e:{r:0,c:0}};
16734 if(cell.r < range.s.r) range.s.r = cell.r;
16735 if(cell.c < range.s.c) range.s.c = cell.c;
16736 if(cell.r + 1 > range.e.r) range.e.r = cell.r + 1;
16737 if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1;
16738 if(options.cellFormula && line.f) {
16739 for(var afi = 0; afi < arrayf.length; ++afi) {
16740 if(arrayf[afi][0].s.c > cell.c || arrayf[afi][0].s.r > cell.r) continue;
16741 if(arrayf[afi][0].e.c < cell.c || arrayf[afi][0].e.r < cell.r) continue;
16742 line.F = encode_range(arrayf[afi][0]);
16743 if(arrayf[afi][0].s.c != cell.c || arrayf[afi][0].s.r != cell.r) delete line.f;
16744 if(line.f) line.f = "" + stringify_formula(arrayf[afi][1], range, cell, supbooks, opts);
16745 break;
16746 }
16747 }
16748 {
16749 if(options.dense) {
16750 if(!out[cell.r]) out[cell.r] = [];
16751 out[cell.r][cell.c] = line;
16752 } else out[last_cell] = line;
16753 }
16754 };
16755 var opts = ({
16756 enc: false, // encrypted
16757 sbcch: 0, // cch in the preceding SupBook
16758 snames: [], // sheetnames
16759 sharedf: sharedf, // shared formulae by address
16760 arrayf: arrayf, // array formulae array
16761 rrtabid: [], // RRTabId
16762 lastuser: "", // Last User from WriteAccess
16763 biff: 8, // BIFF version
16764 codepage: 0, // CP from CodePage record
16765 winlocked: 0, // fLockWn from WinProtect
16766 cellStyles: !!options && !!options.cellStyles,
16767 WTF: !!options && !!options.wtf
16768 });
16769 if(options.password) opts.password = options.password;
16770 var themes;
16771 var merges = [];
16772 var objects = [];
16773 var colinfo = [], rowinfo = [];
16774 // eslint-disable-next-line no-unused-vars
16775 var defwidth = 0, defheight = 0; // twips / MDW respectively
16776 var seencol = false;
16777 var supbooks = ([]); // 1-indexed, will hold extern names
16778 supbooks.SheetNames = opts.snames;
16779 supbooks.sharedf = opts.sharedf;
16780 supbooks.arrayf = opts.arrayf;
16781 supbooks.names = [];
16782 supbooks.XTI = [];
16783 var last_Rn = '';
16784 var file_depth = 0; /* TODO: make a real stack */
16785 var BIFF2Fmt = 0, BIFF2FmtTable = [];
16786 var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
16787 var last_lbl;
16788
16789 /* explicit override for some broken writers */
16790 opts.codepage = 1200;
16791 set_cp(1200);
16792 var seen_codepage = false;
16793 while(blob.l < blob.length - 1) {
16794 var s = blob.l;
16795 var RecordType = blob.read_shift(2);
16796 if(RecordType === 0 && last_Rn === 'EOF') break;
16797 var length = (blob.l === blob.length ? 0 : blob.read_shift(2));
16798 var R = XLSRecordEnum[RecordType];
16799 //console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length);
16800 //if(!R) console.log(blob.slice(blob.l, blob.l + length));
16801 if(R && R.f) {
16802 if(options.bookSheets) {
16803 if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
16804 }
16805 last_Rn = R.n;
16806 if(R.r === 2 || R.r == 12) {
16807 var rt = blob.read_shift(2); length -= 2;
16808 if(!opts.enc && rt !== RecordType && (((rt&0xFF)<<8)|(rt>>8)) !== RecordType) throw new Error("rt mismatch: " + rt + "!=" + RecordType);
16809 if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
16810 }
16811 //console.error(R,blob.l,length,blob.length);
16812 var val = ({});
16813 if(R.n === 'EOF') val = R.f(blob, length, opts);
16814 else val = slurp(R, blob, length, opts);
16815 var Rn = R.n;
16816if(file_depth == 0 && Rn != 'BOF') continue;
16817 /* nested switch statements to workaround V8 128 limit */
16818 switch(Rn) {
16819 /* Workbook Options */
16820 case 'Date1904':
16821wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break;
16822 case 'WriteProtect': wb.opts.WriteProtect = true; break;
16823 case 'FilePass':
16824 if(!opts.enc) blob.l = 0;
16825 opts.enc = val;
16826 if(!options.password) throw new Error("File is password-protected");
16827 if(val.valid == null) throw new Error("Encryption scheme unsupported");
16828 if(!val.valid) throw new Error("Password is incorrect");
16829 break;
16830 case 'WriteAccess': opts.lastuser = val; break;
16831 case 'FileSharing': break; //TODO
16832 case 'CodePage':
16833 var cpval = Number(val);
16834 /* overrides based on test cases */
16835 switch(cpval) {
16836 case 0x5212: cpval = 1200; break;
16837 case 0x8000: cpval = 10000; break;
16838 case 0x8001: cpval = 1252; break;
16839 }
16840 set_cp(opts.codepage = cpval);
16841 seen_codepage = true;
16842 break;
16843 case 'RRTabId': opts.rrtabid = val; break;
16844 case 'WinProtect': opts.winlocked = val; break;
16845 case 'Template': break; // TODO
16846 case 'BookBool': break; // TODO
16847 case 'UsesELFs': break;
16848 case 'MTRSettings': break;
16849 case 'RefreshAll':
16850 case 'CalcCount':
16851 case 'CalcDelta':
16852 case 'CalcIter':
16853 case 'CalcMode':
16854 case 'CalcPrecision':
16855 case 'CalcSaveRecalc':
16856 wb.opts[Rn] = val; break;
16857 case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
16858 case 'Uncalced': break;
16859 case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
16860 case 'WsBool':
16861 if(val.fDialog) out["!type"] = "dialog";
16862 break; // TODO
16863 case 'XF':
16864 XFs.push(val); break;
16865 case 'ExtSST': break; // TODO
16866 case 'BookExt': break; // TODO
16867 case 'RichTextStream': break;
16868 case 'BkHim': break;
16869
16870 case 'SupBook':
16871 supbooks.push([val]);
16872 supbooks[supbooks.length-1].XTI = [];
16873 break;
16874 case 'ExternName':
16875 supbooks[supbooks.length-1].push(val);
16876 break;
16877 case 'Index': break; // TODO
16878 case 'Lbl':
16879 last_lbl = ({
16880 Name: val.Name,
16881 Ref: stringify_formula(val.rgce,range,null,supbooks,opts)
16882 });
16883 if(val.itab > 0) last_lbl.Sheet = val.itab - 1;
16884 supbooks.names.push(last_lbl);
16885 if(!supbooks[0]) { supbooks[0] = []; supbooks[0].XTI = []; }
16886 supbooks[supbooks.length-1].push(val);
16887 if(val.Name == "_xlnm._FilterDatabase" && val.itab > 0)
16888 if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d')
16889 FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) };
16890 break;
16891 case 'ExternCount': opts.ExternCount = val; break;
16892 case 'ExternSheet':
16893 if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; }
16894 supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break;
16895 case 'NameCmt':
16896 /* TODO: search for correct name */
16897 if(opts.biff < 8) break;
16898 if(last_lbl != null) last_lbl.Comment = val[1];
16899 break;
16900
16901 case 'Protect': out["!protect"] = val; break; /* for sheet or book */
16902 case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
16903 case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/
16904
16905 case 'BoundSheet8': {
16906 Directory[val.pos] = val;
16907 opts.snames.push(val.name);
16908 } break;
16909 case 'EOF': {
16910 if(--file_depth) break;
16911 if(range.e) {
16912 if(range.e.r > 0 && range.e.c > 0) {
16913 range.e.r--; range.e.c--;
16914 out["!ref"] = encode_range(range);
16915 if(options.sheetRows && options.sheetRows <= range.e.r) {
16916 var tmpri = range.e.r;
16917 range.e.r = options.sheetRows - 1;
16918 out["!fullref"] = out["!ref"];
16919 out["!ref"] = encode_range(range);
16920 range.e.r = tmpri;
16921 }
16922 range.e.r++; range.e.c++;
16923 }
16924 if(merges.length > 0) out["!merges"] = merges;
16925 if(objects.length > 0) out["!objects"] = objects;
16926 if(colinfo.length > 0) out["!cols"] = colinfo;
16927 if(rowinfo.length > 0) out["!rows"] = rowinfo;
16928 Workbook.Sheets.push(wsprops);
16929 }
16930 if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
16931 out = ((options.dense ? [] : {}));
16932 } break;
16933 case 'BOF': {
16934 if(opts.biff === 8) opts.biff = {
169350x0009:2,
169360x0209:3,
169370x0409:4
16938 }[RecordType] || {
169390x0200:2,
169400x0300:3,
169410x0400:4,
169420x0500:5,
169430x0600:8,
169440x0002:2,
169450x0007:2
16946 }[val.BIFFVer] || 8;
16947 if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
16948 if(file_depth++) break;
16949 cell_valid = true;
16950 out = ((options.dense ? [] : {}));
16951
16952 if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
16953 if(opts.biff < 5) {
16954 if(cur_sheet === "") cur_sheet = "Sheet1";
16955 range = {s:{r:0,c:0},e:{r:0,c:0}};
16956 /* fake BoundSheet8 */
16957 var fakebs8 = {pos: blob.l - length, name:cur_sheet};
16958 Directory[fakebs8.pos] = fakebs8;
16959 opts.snames.push(cur_sheet);
16960 }
16961 else cur_sheet = (Directory[s] || {name:""}).name;
16962 if(val.dt == 0x20) out["!type"] = "chart";
16963 if(val.dt == 0x40) out["!type"] = "macro";
16964 merges = [];
16965 objects = [];
16966 opts.arrayf = arrayf = [];
16967 colinfo = []; rowinfo = [];
16968 defwidth = defheight = 0;
16969 seencol = false;
16970 wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
16971 } break;
16972
16973 case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
16974 if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
16975 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'});
16976 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16977 safe_format_xf(temp_val, options, wb.opts.Date1904);
16978 addcell({c:val.c, r:val.r}, temp_val, options);
16979 } break;
16980 case 'BoolErr': {
16981 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t});
16982 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16983 safe_format_xf(temp_val, options, wb.opts.Date1904);
16984 addcell({c:val.c, r:val.r}, temp_val, options);
16985 } break;
16986 case 'RK': {
16987 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'});
16988 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16989 safe_format_xf(temp_val, options, wb.opts.Date1904);
16990 addcell({c:val.c, r:val.r}, temp_val, options);
16991 } break;
16992 case 'MulRk': {
16993 for(var j = val.c; j <= val.C; ++j) {
16994 var ixfe = val.rkrec[j-val.c][0];
16995 temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'});
16996 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16997 safe_format_xf(temp_val, options, wb.opts.Date1904);
16998 addcell({c:j, r:val.r}, temp_val, options);
16999 }
17000 } break;
17001 case 'Formula': {
17002 if(val.val == 'String') { last_formula = val; break; }
17003 temp_val = make_cell(val.val, val.cell.ixfe, val.tt);
17004 temp_val.XF = XFs[temp_val.ixfe];
17005 if(options.cellFormula) {
17006 var _f = val.formula;
17007 if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
17008 var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
17009 var _fe = encode_cell({r:_fr, c:_fc});
17010 if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
17011 else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
17012 } else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
17013 }
17014 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17015 safe_format_xf(temp_val, options, wb.opts.Date1904);
17016 addcell(val.cell, temp_val, options);
17017 last_formula = val;
17018 } break;
17019 case 'String': {
17020 if(last_formula) { /* technically always true */
17021 last_formula.val = val;
17022 temp_val = make_cell(val, last_formula.cell.ixfe, 's');
17023 temp_val.XF = XFs[temp_val.ixfe];
17024 if(options.cellFormula) {
17025 temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
17026 }
17027 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17028 safe_format_xf(temp_val, options, wb.opts.Date1904);
17029 addcell(last_formula.cell, temp_val, options);
17030 last_formula = null;
17031 } else throw new Error("String record expects Formula");
17032 } break;
17033 case 'Array': {
17034 arrayf.push(val);
17035 var _arraystart = encode_cell(val[0].s);
17036 cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
17037 if(options.cellFormula && cc) {
17038 if(!last_formula) break; /* technically unreachable */
17039 if(!_arraystart || !cc) break;
17040 cc.f = ""+stringify_formula(val[1], range, val[0], supbooks, opts);
17041 cc.F = encode_range(val[0]);
17042 }
17043 } break;
17044 case 'ShrFmla': {
17045 if(!cell_valid) break;
17046 if(!options.cellFormula) break;
17047 if(last_cell) {
17048 /* TODO: capture range */
17049 if(!last_formula) break; /* technically unreachable */
17050 sharedf[encode_cell(last_formula.cell)]= val[0];
17051 cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
17052 (cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
17053 }
17054 } break;
17055 case 'LabelSst':
17056 temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
17057 if(sst[val.isst].h) temp_val.h = sst[val.isst].h;
17058 temp_val.XF = XFs[temp_val.ixfe];
17059 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17060 safe_format_xf(temp_val, options, wb.opts.Date1904);
17061 addcell({c:val.c, r:val.r}, temp_val, options);
17062 break;
17063 case 'Blank': if(options.sheetStubs) {
17064 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'});
17065 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17066 safe_format_xf(temp_val, options, wb.opts.Date1904);
17067 addcell({c:val.c, r:val.r}, temp_val, options);
17068 } break;
17069 case 'MulBlank': if(options.sheetStubs) {
17070 for(var _j = val.c; _j <= val.C; ++_j) {
17071 var _ixfe = val.ixfe[_j-val.c];
17072 temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'});
17073 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17074 safe_format_xf(temp_val, options, wb.opts.Date1904);
17075 addcell({c:_j, r:val.r}, temp_val, options);
17076 }
17077 } break;
17078 case 'RString':
17079 case 'Label': case 'BIFF2STR':
17080 temp_val=make_cell(val.val, val.ixfe, 's');
17081 temp_val.XF = XFs[temp_val.ixfe];
17082 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17083 safe_format_xf(temp_val, options, wb.opts.Date1904);
17084 addcell({c:val.c, r:val.r}, temp_val, options);
17085 break;
17086
17087 case 'Dimensions': {
17088 if(file_depth === 1) range = val; /* TODO: stack */
17089 } break;
17090 case 'SST': {
17091 sst = val;
17092 } break;
17093 case 'Format': { /* val = [id, fmt] */
17094 if(opts.biff == 4) {
17095 BIFF2FmtTable[BIFF2Fmt++] = val[1];
17096 for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(SSF._table[b4idx] == val[1]) break;
17097 if(b4idx >= 163) SSF.load(val[1], BIFF2Fmt + 163);
17098 }
17099 else SSF.load(val[1], val[0]);
17100 } break;
17101 case 'BIFF2FORMAT': {
17102 BIFF2FmtTable[BIFF2Fmt++] = val;
17103 for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break;
17104 if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163);
17105 } break;
17106
17107 case 'MergeCells': merges = merges.concat(val); break;
17108
17109 case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break;
17110 case 'TxO': opts.lastobj.TxO = val; break;
17111 case 'ImData': opts.lastobj.ImData = val; break;
17112
17113 case 'HLink': {
17114 for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
17115 for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
17116 cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
17117 if(cc) cc.l = val[1];
17118 }
17119 } break;
17120 case 'HLinkTooltip': {
17121 for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
17122 for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
17123 cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
17124 if(cc && cc.l) cc.l.Tooltip = val[1];
17125 }
17126 } break;
17127
17128 /* Comments */
17129 case 'Note': {
17130 if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
17131 cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
17132 var noteobj = objects[val[2]];
17133 if(!cc) {
17134 if(options.dense) {
17135 if(!out[val[0].r]) out[val[0].r] = [];
17136 cc = out[val[0].r][val[0].c] = ({t:"z"});
17137 } else {
17138 cc = out[encode_cell(val[0])] = ({t:"z"});
17139 }
17140 range.e.r = Math.max(range.e.r, val[0].r);
17141 range.s.r = Math.min(range.s.r, val[0].r);
17142 range.e.c = Math.max(range.e.c, val[0].c);
17143 range.s.c = Math.min(range.s.c, val[0].c);
17144 }
17145 if(!cc.c) cc.c = [];
17146 cmnt = {a:val[1],t:noteobj.TxO.t};
17147 cc.c.push(cmnt);
17148 } break;
17149
17150 default: switch(R.n) { /* nested */
17151 case 'ClrtClient': break;
17152 case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break;
17153
17154 case 'DefColWidth': defwidth = val; break;
17155 case 'DefaultRowHeight': defheight = val[1]; break; // TODO: flags
17156
17157 case 'ColInfo': {
17158 if(!opts.cellStyles) break;
17159 while(val.e >= val.s) {
17160 colinfo[val.e--] = { width: val.w/256 };
17161 if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
17162 process_col(colinfo[val.e+1]);
17163 }
17164 } break;
17165 case 'Row': {
17166 var rowobj = {};
17167 if(val.level != null) { rowinfo[val.r] = rowobj; rowobj.level = val.level; }
17168 if(val.hidden) { rowinfo[val.r] = rowobj; rowobj.hidden = true; }
17169 if(val.hpt) {
17170 rowinfo[val.r] = rowobj;
17171 rowobj.hpt = val.hpt; rowobj.hpx = pt2px(val.hpt);
17172 }
17173 } break;
17174
17175 case 'LeftMargin':
17176 case 'RightMargin':
17177 case 'TopMargin':
17178 case 'BottomMargin':
17179 if(!out['!margins']) default_margins(out['!margins'] = {});
17180 out['!margins'][Rn.slice(0,-6).toLowerCase()] = val;
17181 break;
17182
17183 case 'Setup': // TODO
17184 if(!out['!margins']) default_margins(out['!margins'] = {});
17185 out['!margins'].header = val.header;
17186 out['!margins'].footer = val.footer;
17187 break;
17188
17189 case 'Window2': // TODO
17190 // $FlowIgnore
17191 if(val.RTL) Workbook.Views[0].RTL = true;
17192 break;
17193
17194 case 'Header': break; // TODO
17195 case 'Footer': break; // TODO
17196 case 'HCenter': break; // TODO
17197 case 'VCenter': break; // TODO
17198 case 'Pls': break; // TODO
17199 case 'GCW': break;
17200 case 'LHRecord': break;
17201 case 'DBCell': break; // TODO
17202 case 'EntExU2': break; // TODO
17203 case 'SxView': break; // TODO
17204 case 'Sxvd': break; // TODO
17205 case 'SXVI': break; // TODO
17206 case 'SXVDEx': break; // TODO
17207 case 'SxIvd': break; // TODO
17208 case 'SXString': break; // TODO
17209 case 'Sync': break;
17210 case 'Addin': break;
17211 case 'SXDI': break; // TODO
17212 case 'SXLI': break; // TODO
17213 case 'SXEx': break; // TODO
17214 case 'QsiSXTag': break; // TODO
17215 case 'Selection': break;
17216 case 'Feat': break;
17217 case 'FeatHdr': case 'FeatHdr11': break;
17218 case 'Feature11': case 'Feature12': case 'List12': break;
17219 case 'Country': country = val; break;
17220 case 'RecalcId': break;
17221 case 'DxGCol': break; // TODO: htmlify
17222 case 'Fbi': case 'Fbi2': case 'GelFrame': break;
17223 case 'Font': break; // TODO
17224 case 'XFCRC': break; // TODO
17225 case 'Style': break; // TODO
17226 case 'StyleExt': break; // TODO
17227 case 'Palette': palette = val; break;
17228 case 'Theme': themes = val; break;
17229 /* Protection */
17230 case 'ScenarioProtect': break;
17231 case 'ObjProtect': break;
17232
17233 /* Conditional Formatting */
17234 case 'CondFmt12': break;
17235
17236 /* Table */
17237 case 'Table': break; // TODO
17238 case 'TableStyles': break; // TODO
17239 case 'TableStyle': break; // TODO
17240 case 'TableStyleElement': break; // TODO
17241
17242 /* PivotTable */
17243 case 'SXStreamID': break; // TODO
17244 case 'SXVS': break; // TODO
17245 case 'DConRef': break; // TODO
17246 case 'SXAddl': break; // TODO
17247 case 'DConBin': break; // TODO
17248 case 'DConName': break; // TODO
17249 case 'SXPI': break; // TODO
17250 case 'SxFormat': break; // TODO
17251 case 'SxSelect': break; // TODO
17252 case 'SxRule': break; // TODO
17253 case 'SxFilt': break; // TODO
17254 case 'SxItm': break; // TODO
17255 case 'SxDXF': break; // TODO
17256
17257 /* Scenario Manager */
17258 case 'ScenMan': break;
17259
17260 /* Data Consolidation */
17261 case 'DCon': break;
17262
17263 /* Watched Cell */
17264 case 'CellWatch': break;
17265
17266 /* Print Settings */
17267 case 'PrintRowCol': break;
17268 case 'PrintGrid': break;
17269 case 'PrintSize': break;
17270
17271 case 'XCT': break;
17272 case 'CRN': break;
17273
17274 case 'Scl': {
17275 //console.log("Zoom Level:", val[0]/val[1],val);
17276 } break;
17277 case 'SheetExt': {
17278 /* empty */
17279 } break;
17280 case 'SheetExtOptional': {
17281 /* empty */
17282 } break;
17283
17284 /* VBA */
17285 case 'ObNoMacros': {
17286 /* empty */
17287 } break;
17288 case 'ObProj': {
17289 /* empty */
17290 } break;
17291 case 'CodeName': {
17292if(!cur_sheet) Workbook.WBProps.CodeName = val || "ThisWorkbook";
17293 else wsprops.CodeName = val || wsprops.name;
17294 } break;
17295 case 'GUIDTypeLib': {
17296 /* empty */
17297 } break;
17298
17299 case 'WOpt': break; // TODO: WTF?
17300 case 'PhoneticInfo': break;
17301
17302 case 'OleObjectSize': break;
17303
17304 /* Differential Formatting */
17305 case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break;
17306
17307 /* Data Validation */
17308 case 'Dv': case 'DVal': break;
17309
17310 /* Data Series */
17311 case 'BRAI': case 'Series': case 'SeriesText': break;
17312
17313 /* Data Connection */
17314 case 'DConn': break;
17315 case 'DbOrParamQry': break;
17316 case 'DBQueryExt': break;
17317
17318 case 'OleDbConn': break;
17319 case 'ExtString': break;
17320
17321 /* Formatting */
17322 case 'IFmtRecord': break;
17323 case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
17324
17325 /* Explicitly Ignored */
17326 case 'Excel9File': break;
17327 case 'Units': break;
17328 case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break;
17329 case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break;
17330 /* View Stuff */
17331 case 'Window1': case 'HideObj': case 'GridSet': case 'Guts':
17332 case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd': break;
17333 case 'Pane': break;
17334 default: switch(R.n) { /* nested */
17335 /* Chart */
17336 case 'Dat':
17337 case 'Begin': case 'End':
17338 case 'StartBlock': case 'EndBlock':
17339 case 'Frame': case 'Area':
17340 case 'Axis': case 'AxisLine': case 'Tick': break;
17341 case 'AxesUsed':
17342 case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break;
17343 case 'LineFormat': case 'AreaFormat':
17344 case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break;
17345 case 'PlotArea': case 'PlotGrowth': break;
17346 case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break;
17347 case 'DataFormat': case 'SerToCrt': case 'FontX': break;
17348 case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
17349 case 'ShtProps': break;
17350 case 'DefaultText': case 'Text': case 'CatLab': break;
17351 case 'DataLabExtContents': break;
17352 case 'Legend': case 'LegendException': break;
17353 case 'Pie': case 'Scatter': break;
17354 case 'PieFormat': case 'MarkerFormat': break;
17355 case 'StartObject': case 'EndObject': break;
17356 case 'AlRuns': case 'ObjectLink': break;
17357 case 'SIIndex': break;
17358 case 'AttachedLabel': case 'YMult': break;
17359
17360 /* Chart Group */
17361 case 'Line': case 'Bar': break;
17362 case 'Surf': break;
17363
17364 /* Axis Group */
17365 case 'AxisParent': break;
17366 case 'Pos': break;
17367 case 'ValueRange': break;
17368
17369 /* Pivot Chart */
17370 case 'SXViewEx9': break; // TODO
17371 case 'SXViewLink': break;
17372 case 'PivotChartBits': break;
17373 case 'SBaseRef': break;
17374 case 'TextPropsStream': break;
17375
17376 /* Chart Misc */
17377 case 'LnExt': break;
17378 case 'MkrExt': break;
17379 case 'CrtCoopt': break;
17380
17381 /* Query Table */
17382 case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break;
17383 case 'TxtQry': break;
17384
17385 /* Filter */
17386 case 'FilterMode': break;
17387 case 'AutoFilter': case 'AutoFilterInfo': break;
17388 case 'AutoFilter12': break;
17389 case 'DropDownObjIds': break;
17390 case 'Sort': break;
17391 case 'SortData': break;
17392
17393 /* Drawing */
17394 case 'ShapePropsStream': break;
17395 case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
17396 /* Pub Stuff */
17397 case 'WebPub': case 'AutoWebPub': break;
17398
17399 /* Print Stuff */
17400 case 'HeaderFooter': case 'HFPicture': case 'PLV':
17401 case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break;
17402 /* Behavioral */
17403 case 'Backup': case 'CompressPictures': case 'Compat12': break;
17404
17405 /* Should not Happen */
17406 case 'Continue': case 'ContinueFrt12': break;
17407
17408 /* Future Records */
17409 case 'FrtFontList': case 'FrtWrapper': break;
17410
17411 default: switch(R.n) { /* nested */
17412 /* BIFF5 records */
17413 case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
17414
17415 /* BIFF2-4 records */
17416 case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break;
17417 case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break;
17418 case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break;
17419
17420 /* Miscellaneous */
17421 case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':
17422 case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData':
17423 case 'Name': break;
17424 case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break;
17425 case 'ListObj': case 'ListField': break;
17426 case 'RRSort': break;
17427 case 'BigName': break;
17428 case 'ToolbarHdr': case 'ToolbarEnd': break;
17429 case 'DDEObjName': break;
17430 case 'FRTArchId$': break;
17431 default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
17432 }}}}
17433 } else blob.l += length;
17434 }
17435 wb.SheetNames=keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;});
17436 if(!options.bookSheets) wb.Sheets=Sheets;
17437 if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; });
17438 wb.Preamble=Preamble;
17439 wb.Strings = sst;
17440 wb.SSF = SSF.get_table();
17441 if(opts.enc) wb.Encryption = opts.enc;
17442 if(themes) wb.Themes = themes;
17443 wb.Metadata = {};
17444 if(country !== undefined) wb.Metadata.Country = country;
17445 if(supbooks.names.length > 0) Workbook.Names = supbooks.names;
17446 wb.Workbook = Workbook;
17447 return wb;
17448}
17449
17450/* TODO: split props*/
17451var PSCLSID = {
17452 SI: "e0859ff2f94f6810ab9108002b27b3d9",
17453 DSI: "02d5cdd59c2e1b10939708002b2cf9ae",
17454 UDI: "05d5cdd59c2e1b10939708002b2cf9ae"
17455};
17456function parse_xls_props(cfb, props, o) {
17457 /* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
17458 var DSI = CFB.find(cfb, '!DocumentSummaryInformation');
17459 if(DSI && DSI.size > 0) try {
17460 var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI);
17461 for(var d in DocSummary) props[d] = DocSummary[d];
17462 } catch(e) {if(o.WTF) throw e;/* empty */}
17463
17464 /* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
17465 var SI = CFB.find(cfb, '!SummaryInformation');
17466 if(SI && SI.size > 0) try {
17467 var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI);
17468 for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
17469 } catch(e) {if(o.WTF) throw e;/* empty */}
17470
17471 if(props.HeadingPairs && props.TitlesOfParts) {
17472 load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o);
17473 delete props.HeadingPairs; delete props.TitlesOfParts;
17474 }
17475}
17476function write_xls_props(wb, cfb) {
17477 var DSEntries = [], SEntries = [], CEntries = [];
17478 var i = 0, Keys;
17479 if(wb.Props) {
17480 Keys = keys(wb.Props);
17481 // $FlowIgnore
17482 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]]]);
17483 }
17484 if(wb.Custprops) {
17485 Keys = keys(wb.Custprops);
17486 // $FlowIgnore
17487 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]]]);
17488 }
17489 var CEntries2 = [];
17490 for(i = 0; i < CEntries.length; ++i) {
17491 if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue;
17492 if(CEntries[i][1] == null) continue;
17493 CEntries2.push(CEntries[i]);
17494 }
17495 if(SEntries.length) CFB.utils.cfb_add(cfb, "/\u0005SummaryInformation", write_PropertySetStream(SEntries, PSCLSID.SI, SummaryRE, SummaryPIDSI));
17496 if(DSEntries.length || CEntries2.length) CFB.utils.cfb_add(cfb, "/\u0005DocumentSummaryInformation", write_PropertySetStream(DSEntries, PSCLSID.DSI, DocSummaryRE, DocSummaryPIDDSI, CEntries2.length ? CEntries2 : null, PSCLSID.UDI));
17497}
17498
17499function parse_xlscfb(cfb, options) {
17500if(!options) options = {};
17501fix_read_opts(options);
17502reset_cp();
17503if(options.codepage) set_ansi(options.codepage);
17504var CompObj, WB;
17505if(cfb.FullPaths) {
17506 if(CFB.find(cfb, '/encryption')) throw new Error("File is password-protected");
17507 CompObj = CFB.find(cfb, '!CompObj');
17508 WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
17509} else {
17510 switch(options.type) {
17511 case 'base64': cfb = s2a(Base64.decode(cfb)); break;
17512 case 'binary': cfb = s2a(cfb); break;
17513 case 'buffer': break;
17514 case 'array': if(!Array.isArray(cfb)) cfb = Array.prototype.slice.call(cfb); break;
17515 }
17516 prep_blob(cfb, 0);
17517 WB = ({content: cfb});
17518}
17519var WorkbookP;
17520
17521var _data;
17522if(CompObj) parse_compobj(CompObj);
17523if(options.bookProps && !options.bookSheets) WorkbookP = ({});
17524else {
17525 var T = has_buf ? 'buffer' : 'array';
17526 if(WB && WB.content) WorkbookP = parse_workbook(WB.content, options);
17527 /* Quattro Pro 7-8 */
17528 else if((_data=CFB.find(cfb, 'PerfectOffice_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
17529 /* Quattro Pro 9 */
17530 else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
17531 else throw new Error("Cannot find Workbook stream");
17532 if(options.bookVBA && cfb.FullPaths && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb);
17533}
17534
17535var props = {};
17536if(cfb.FullPaths) parse_xls_props(cfb, props, options);
17537
17538WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
17539if(options.bookFiles) WorkbookP.cfb = cfb;
17540/*WorkbookP.CompObjP = CompObjP; // TODO: storage? */
17541return WorkbookP;
17542}
17543
17544
17545function write_xlscfb(wb, opts) {
17546 var o = opts || {};
17547 var cfb = CFB.utils.cfb_new({root:"R"});
17548 var wbpath = "/Workbook";
17549 switch(o.bookType || "xls") {
17550 case "xls": o.bookType = "biff8";
17551 /* falls through */
17552 case "xla": if(!o.bookType) o.bookType = "xla";
17553 /* falls through */
17554 case "biff8": wbpath = "/Workbook"; o.biff = 8; break;
17555 case "biff5": wbpath = "/Book"; o.biff = 5; break;
17556 default: throw new Error("invalid type " + o.bookType + " for XLS CFB");
17557 }
17558 CFB.utils.cfb_add(cfb, wbpath, write_biff_buf(wb, o));
17559 if(o.biff == 8 && (wb.Props || wb.Custprops)) write_xls_props(wb, cfb);
17560 // TODO: SI, DSI, CO
17561 if(o.biff == 8 && wb.vbaraw) fill_vba_xls(cfb, CFB.read(wb.vbaraw, {type: typeof wb.vbaraw == "string" ? "binary" : "buffer"}));
17562 return cfb;
17563}
17564/* [MS-XLSB] 2.3 Record Enumeration */
17565var XLSBRecordEnum = {
175660x0000: { n:"BrtRowHdr", f:parse_BrtRowHdr },
175670x0001: { n:"BrtCellBlank", f:parse_BrtCellBlank },
175680x0002: { n:"BrtCellRk", f:parse_BrtCellRk },
175690x0003: { n:"BrtCellError", f:parse_BrtCellError },
175700x0004: { n:"BrtCellBool", f:parse_BrtCellBool },
175710x0005: { n:"BrtCellReal", f:parse_BrtCellReal },
175720x0006: { n:"BrtCellSt", f:parse_BrtCellSt },
175730x0007: { n:"BrtCellIsst", f:parse_BrtCellIsst },
175740x0008: { n:"BrtFmlaString", f:parse_BrtFmlaString },
175750x0009: { n:"BrtFmlaNum", f:parse_BrtFmlaNum },
175760x000A: { n:"BrtFmlaBool", f:parse_BrtFmlaBool },
175770x000B: { n:"BrtFmlaError", f:parse_BrtFmlaError },
175780x0010: { n:"BrtFRTArchID$", f:parse_BrtFRTArchID$ },
175790x0013: { n:"BrtSSTItem", f:parse_RichStr },
175800x0014: { n:"BrtPCDIMissing" },
175810x0015: { n:"BrtPCDINumber" },
175820x0016: { n:"BrtPCDIBoolean" },
175830x0017: { n:"BrtPCDIError" },
175840x0018: { n:"BrtPCDIString" },
175850x0019: { n:"BrtPCDIDatetime" },
175860x001A: { n:"BrtPCDIIndex" },
175870x001B: { n:"BrtPCDIAMissing" },
175880x001C: { n:"BrtPCDIANumber" },
175890x001D: { n:"BrtPCDIABoolean" },
175900x001E: { n:"BrtPCDIAError" },
175910x001F: { n:"BrtPCDIAString" },
175920x0020: { n:"BrtPCDIADatetime" },
175930x0021: { n:"BrtPCRRecord" },
175940x0022: { n:"BrtPCRRecordDt" },
175950x0023: { n:"BrtFRTBegin" },
175960x0024: { n:"BrtFRTEnd" },
175970x0025: { n:"BrtACBegin" },
175980x0026: { n:"BrtACEnd" },
175990x0027: { n:"BrtName", f:parse_BrtName },
176000x0028: { n:"BrtIndexRowBlock" },
176010x002A: { n:"BrtIndexBlock" },
176020x002B: { n:"BrtFont", f:parse_BrtFont },
176030x002C: { n:"BrtFmt", f:parse_BrtFmt },
176040x002D: { n:"BrtFill", f:parse_BrtFill },
176050x002E: { n:"BrtBorder", f:parse_BrtBorder },
176060x002F: { n:"BrtXF", f:parse_BrtXF },
176070x0030: { n:"BrtStyle" },
176080x0031: { n:"BrtCellMeta" },
176090x0032: { n:"BrtValueMeta" },
176100x0033: { n:"BrtMdb" },
176110x0034: { n:"BrtBeginFmd" },
176120x0035: { n:"BrtEndFmd" },
176130x0036: { n:"BrtBeginMdx" },
176140x0037: { n:"BrtEndMdx" },
176150x0038: { n:"BrtBeginMdxTuple" },
176160x0039: { n:"BrtEndMdxTuple" },
176170x003A: { n:"BrtMdxMbrIstr" },
176180x003B: { n:"BrtStr" },
176190x003C: { n:"BrtColInfo", f:parse_ColInfo },
176200x003E: { n:"BrtCellRString" },
176210x003F: { n:"BrtCalcChainItem$", f:parse_BrtCalcChainItem$ },
176220x0040: { n:"BrtDVal", f:parse_BrtDVal },
176230x0041: { n:"BrtSxvcellNum" },
176240x0042: { n:"BrtSxvcellStr" },
176250x0043: { n:"BrtSxvcellBool" },
176260x0044: { n:"BrtSxvcellErr" },
176270x0045: { n:"BrtSxvcellDate" },
176280x0046: { n:"BrtSxvcellNil" },
176290x0080: { n:"BrtFileVersion" },
176300x0081: { n:"BrtBeginSheet" },
176310x0082: { n:"BrtEndSheet" },
176320x0083: { n:"BrtBeginBook", f:parsenoop, p:0 },
176330x0084: { n:"BrtEndBook" },
176340x0085: { n:"BrtBeginWsViews" },
176350x0086: { n:"BrtEndWsViews" },
176360x0087: { n:"BrtBeginBookViews" },
176370x0088: { n:"BrtEndBookViews" },
176380x0089: { n:"BrtBeginWsView", f:parse_BrtBeginWsView },
176390x008A: { n:"BrtEndWsView" },
176400x008B: { n:"BrtBeginCsViews" },
176410x008C: { n:"BrtEndCsViews" },
176420x008D: { n:"BrtBeginCsView" },
176430x008E: { n:"BrtEndCsView" },
176440x008F: { n:"BrtBeginBundleShs" },
176450x0090: { n:"BrtEndBundleShs" },
176460x0091: { n:"BrtBeginSheetData" },
176470x0092: { n:"BrtEndSheetData" },
176480x0093: { n:"BrtWsProp", f:parse_BrtWsProp },
176490x0094: { n:"BrtWsDim", f:parse_BrtWsDim, p:16 },
176500x0097: { n:"BrtPane", f:parse_BrtPane },
176510x0098: { n:"BrtSel" },
176520x0099: { n:"BrtWbProp", f:parse_BrtWbProp },
176530x009A: { n:"BrtWbFactoid" },
176540x009B: { n:"BrtFileRecover" },
176550x009C: { n:"BrtBundleSh", f:parse_BrtBundleSh },
176560x009D: { n:"BrtCalcProp" },
176570x009E: { n:"BrtBookView" },
176580x009F: { n:"BrtBeginSst", f:parse_BrtBeginSst },
176590x00A0: { n:"BrtEndSst" },
176600x00A1: { n:"BrtBeginAFilter", f:parse_UncheckedRfX },
176610x00A2: { n:"BrtEndAFilter" },
176620x00A3: { n:"BrtBeginFilterColumn" },
176630x00A4: { n:"BrtEndFilterColumn" },
176640x00A5: { n:"BrtBeginFilters" },
176650x00A6: { n:"BrtEndFilters" },
176660x00A7: { n:"BrtFilter" },
176670x00A8: { n:"BrtColorFilter" },
176680x00A9: { n:"BrtIconFilter" },
176690x00AA: { n:"BrtTop10Filter" },
176700x00AB: { n:"BrtDynamicFilter" },
176710x00AC: { n:"BrtBeginCustomFilters" },
176720x00AD: { n:"BrtEndCustomFilters" },
176730x00AE: { n:"BrtCustomFilter" },
176740x00AF: { n:"BrtAFilterDateGroupItem" },
176750x00B0: { n:"BrtMergeCell", f:parse_BrtMergeCell },
176760x00B1: { n:"BrtBeginMergeCells" },
176770x00B2: { n:"BrtEndMergeCells" },
176780x00B3: { n:"BrtBeginPivotCacheDef" },
176790x00B4: { n:"BrtEndPivotCacheDef" },
176800x00B5: { n:"BrtBeginPCDFields" },
176810x00B6: { n:"BrtEndPCDFields" },
176820x00B7: { n:"BrtBeginPCDField" },
176830x00B8: { n:"BrtEndPCDField" },
176840x00B9: { n:"BrtBeginPCDSource" },
176850x00BA: { n:"BrtEndPCDSource" },
176860x00BB: { n:"BrtBeginPCDSRange" },
176870x00BC: { n:"BrtEndPCDSRange" },
176880x00BD: { n:"BrtBeginPCDFAtbl" },
176890x00BE: { n:"BrtEndPCDFAtbl" },
176900x00BF: { n:"BrtBeginPCDIRun" },
176910x00C0: { n:"BrtEndPCDIRun" },
176920x00C1: { n:"BrtBeginPivotCacheRecords" },
176930x00C2: { n:"BrtEndPivotCacheRecords" },
176940x00C3: { n:"BrtBeginPCDHierarchies" },
176950x00C4: { n:"BrtEndPCDHierarchies" },
176960x00C5: { n:"BrtBeginPCDHierarchy" },
176970x00C6: { n:"BrtEndPCDHierarchy" },
176980x00C7: { n:"BrtBeginPCDHFieldsUsage" },
176990x00C8: { n:"BrtEndPCDHFieldsUsage" },
177000x00C9: { n:"BrtBeginExtConnection" },
177010x00CA: { n:"BrtEndExtConnection" },
177020x00CB: { n:"BrtBeginECDbProps" },
177030x00CC: { n:"BrtEndECDbProps" },
177040x00CD: { n:"BrtBeginECOlapProps" },
177050x00CE: { n:"BrtEndECOlapProps" },
177060x00CF: { n:"BrtBeginPCDSConsol" },
177070x00D0: { n:"BrtEndPCDSConsol" },
177080x00D1: { n:"BrtBeginPCDSCPages" },
177090x00D2: { n:"BrtEndPCDSCPages" },
177100x00D3: { n:"BrtBeginPCDSCPage" },
177110x00D4: { n:"BrtEndPCDSCPage" },
177120x00D5: { n:"BrtBeginPCDSCPItem" },
177130x00D6: { n:"BrtEndPCDSCPItem" },
177140x00D7: { n:"BrtBeginPCDSCSets" },
177150x00D8: { n:"BrtEndPCDSCSets" },
177160x00D9: { n:"BrtBeginPCDSCSet" },
177170x00DA: { n:"BrtEndPCDSCSet" },
177180x00DB: { n:"BrtBeginPCDFGroup" },
177190x00DC: { n:"BrtEndPCDFGroup" },
177200x00DD: { n:"BrtBeginPCDFGItems" },
177210x00DE: { n:"BrtEndPCDFGItems" },
177220x00DF: { n:"BrtBeginPCDFGRange" },
177230x00E0: { n:"BrtEndPCDFGRange" },
177240x00E1: { n:"BrtBeginPCDFGDiscrete" },
177250x00E2: { n:"BrtEndPCDFGDiscrete" },
177260x00E3: { n:"BrtBeginPCDSDTupleCache" },
177270x00E4: { n:"BrtEndPCDSDTupleCache" },
177280x00E5: { n:"BrtBeginPCDSDTCEntries" },
177290x00E6: { n:"BrtEndPCDSDTCEntries" },
177300x00E7: { n:"BrtBeginPCDSDTCEMembers" },
177310x00E8: { n:"BrtEndPCDSDTCEMembers" },
177320x00E9: { n:"BrtBeginPCDSDTCEMember" },
177330x00EA: { n:"BrtEndPCDSDTCEMember" },
177340x00EB: { n:"BrtBeginPCDSDTCQueries" },
177350x00EC: { n:"BrtEndPCDSDTCQueries" },
177360x00ED: { n:"BrtBeginPCDSDTCQuery" },
177370x00EE: { n:"BrtEndPCDSDTCQuery" },
177380x00EF: { n:"BrtBeginPCDSDTCSets" },
177390x00F0: { n:"BrtEndPCDSDTCSets" },
177400x00F1: { n:"BrtBeginPCDSDTCSet" },
177410x00F2: { n:"BrtEndPCDSDTCSet" },
177420x00F3: { n:"BrtBeginPCDCalcItems" },
177430x00F4: { n:"BrtEndPCDCalcItems" },
177440x00F5: { n:"BrtBeginPCDCalcItem" },
177450x00F6: { n:"BrtEndPCDCalcItem" },
177460x00F7: { n:"BrtBeginPRule" },
177470x00F8: { n:"BrtEndPRule" },
177480x00F9: { n:"BrtBeginPRFilters" },
177490x00FA: { n:"BrtEndPRFilters" },
177500x00FB: { n:"BrtBeginPRFilter" },
177510x00FC: { n:"BrtEndPRFilter" },
177520x00FD: { n:"BrtBeginPNames" },
177530x00FE: { n:"BrtEndPNames" },
177540x00FF: { n:"BrtBeginPName" },
177550x0100: { n:"BrtEndPName" },
177560x0101: { n:"BrtBeginPNPairs" },
177570x0102: { n:"BrtEndPNPairs" },
177580x0103: { n:"BrtBeginPNPair" },
177590x0104: { n:"BrtEndPNPair" },
177600x0105: { n:"BrtBeginECWebProps" },
177610x0106: { n:"BrtEndECWebProps" },
177620x0107: { n:"BrtBeginEcWpTables" },
177630x0108: { n:"BrtEndECWPTables" },
177640x0109: { n:"BrtBeginECParams" },
177650x010A: { n:"BrtEndECParams" },
177660x010B: { n:"BrtBeginECParam" },
177670x010C: { n:"BrtEndECParam" },
177680x010D: { n:"BrtBeginPCDKPIs" },
177690x010E: { n:"BrtEndPCDKPIs" },
177700x010F: { n:"BrtBeginPCDKPI" },
177710x0110: { n:"BrtEndPCDKPI" },
177720x0111: { n:"BrtBeginDims" },
177730x0112: { n:"BrtEndDims" },
177740x0113: { n:"BrtBeginDim" },
177750x0114: { n:"BrtEndDim" },
177760x0115: { n:"BrtIndexPartEnd" },
177770x0116: { n:"BrtBeginStyleSheet" },
177780x0117: { n:"BrtEndStyleSheet" },
177790x0118: { n:"BrtBeginSXView" },
177800x0119: { n:"BrtEndSXVI" },
177810x011A: { n:"BrtBeginSXVI" },
177820x011B: { n:"BrtBeginSXVIs" },
177830x011C: { n:"BrtEndSXVIs" },
177840x011D: { n:"BrtBeginSXVD" },
177850x011E: { n:"BrtEndSXVD" },
177860x011F: { n:"BrtBeginSXVDs" },
177870x0120: { n:"BrtEndSXVDs" },
177880x0121: { n:"BrtBeginSXPI" },
177890x0122: { n:"BrtEndSXPI" },
177900x0123: { n:"BrtBeginSXPIs" },
177910x0124: { n:"BrtEndSXPIs" },
177920x0125: { n:"BrtBeginSXDI" },
177930x0126: { n:"BrtEndSXDI" },
177940x0127: { n:"BrtBeginSXDIs" },
177950x0128: { n:"BrtEndSXDIs" },
177960x0129: { n:"BrtBeginSXLI" },
177970x012A: { n:"BrtEndSXLI" },
177980x012B: { n:"BrtBeginSXLIRws" },
177990x012C: { n:"BrtEndSXLIRws" },
178000x012D: { n:"BrtBeginSXLICols" },
178010x012E: { n:"BrtEndSXLICols" },
178020x012F: { n:"BrtBeginSXFormat" },
178030x0130: { n:"BrtEndSXFormat" },
178040x0131: { n:"BrtBeginSXFormats" },
178050x0132: { n:"BrtEndSxFormats" },
178060x0133: { n:"BrtBeginSxSelect" },
178070x0134: { n:"BrtEndSxSelect" },
178080x0135: { n:"BrtBeginISXVDRws" },
178090x0136: { n:"BrtEndISXVDRws" },
178100x0137: { n:"BrtBeginISXVDCols" },
178110x0138: { n:"BrtEndISXVDCols" },
178120x0139: { n:"BrtEndSXLocation" },
178130x013A: { n:"BrtBeginSXLocation" },
178140x013B: { n:"BrtEndSXView" },
178150x013C: { n:"BrtBeginSXTHs" },
178160x013D: { n:"BrtEndSXTHs" },
178170x013E: { n:"BrtBeginSXTH" },
178180x013F: { n:"BrtEndSXTH" },
178190x0140: { n:"BrtBeginISXTHRws" },
178200x0141: { n:"BrtEndISXTHRws" },
178210x0142: { n:"BrtBeginISXTHCols" },
178220x0143: { n:"BrtEndISXTHCols" },
178230x0144: { n:"BrtBeginSXTDMPS" },
178240x0145: { n:"BrtEndSXTDMPs" },
178250x0146: { n:"BrtBeginSXTDMP" },
178260x0147: { n:"BrtEndSXTDMP" },
178270x0148: { n:"BrtBeginSXTHItems" },
178280x0149: { n:"BrtEndSXTHItems" },
178290x014A: { n:"BrtBeginSXTHItem" },
178300x014B: { n:"BrtEndSXTHItem" },
178310x014C: { n:"BrtBeginMetadata" },
178320x014D: { n:"BrtEndMetadata" },
178330x014E: { n:"BrtBeginEsmdtinfo" },
178340x014F: { n:"BrtMdtinfo" },
178350x0150: { n:"BrtEndEsmdtinfo" },
178360x0151: { n:"BrtBeginEsmdb" },
178370x0152: { n:"BrtEndEsmdb" },
178380x0153: { n:"BrtBeginEsfmd" },
178390x0154: { n:"BrtEndEsfmd" },
178400x0155: { n:"BrtBeginSingleCells" },
178410x0156: { n:"BrtEndSingleCells" },
178420x0157: { n:"BrtBeginList" },
178430x0158: { n:"BrtEndList" },
178440x0159: { n:"BrtBeginListCols" },
178450x015A: { n:"BrtEndListCols" },
178460x015B: { n:"BrtBeginListCol" },
178470x015C: { n:"BrtEndListCol" },
178480x015D: { n:"BrtBeginListXmlCPr" },
178490x015E: { n:"BrtEndListXmlCPr" },
178500x015F: { n:"BrtListCCFmla" },
178510x0160: { n:"BrtListTrFmla" },
178520x0161: { n:"BrtBeginExternals" },
178530x0162: { n:"BrtEndExternals" },
178540x0163: { n:"BrtSupBookSrc", f:parse_RelID},
178550x0165: { n:"BrtSupSelf" },
178560x0166: { n:"BrtSupSame" },
178570x0167: { n:"BrtSupTabs" },
178580x0168: { n:"BrtBeginSupBook" },
178590x0169: { n:"BrtPlaceholderName" },
178600x016A: { n:"BrtExternSheet", f:parse_ExternSheet },
178610x016B: { n:"BrtExternTableStart" },
178620x016C: { n:"BrtExternTableEnd" },
178630x016E: { n:"BrtExternRowHdr" },
178640x016F: { n:"BrtExternCellBlank" },
178650x0170: { n:"BrtExternCellReal" },
178660x0171: { n:"BrtExternCellBool" },
178670x0172: { n:"BrtExternCellError" },
178680x0173: { n:"BrtExternCellString" },
178690x0174: { n:"BrtBeginEsmdx" },
178700x0175: { n:"BrtEndEsmdx" },
178710x0176: { n:"BrtBeginMdxSet" },
178720x0177: { n:"BrtEndMdxSet" },
178730x0178: { n:"BrtBeginMdxMbrProp" },
178740x0179: { n:"BrtEndMdxMbrProp" },
178750x017A: { n:"BrtBeginMdxKPI" },
178760x017B: { n:"BrtEndMdxKPI" },
178770x017C: { n:"BrtBeginEsstr" },
178780x017D: { n:"BrtEndEsstr" },
178790x017E: { n:"BrtBeginPRFItem" },
178800x017F: { n:"BrtEndPRFItem" },
178810x0180: { n:"BrtBeginPivotCacheIDs" },
178820x0181: { n:"BrtEndPivotCacheIDs" },
178830x0182: { n:"BrtBeginPivotCacheID" },
178840x0183: { n:"BrtEndPivotCacheID" },
178850x0184: { n:"BrtBeginISXVIs" },
178860x0185: { n:"BrtEndISXVIs" },
178870x0186: { n:"BrtBeginColInfos" },
178880x0187: { n:"BrtEndColInfos" },
178890x0188: { n:"BrtBeginRwBrk" },
178900x0189: { n:"BrtEndRwBrk" },
178910x018A: { n:"BrtBeginColBrk" },
178920x018B: { n:"BrtEndColBrk" },
178930x018C: { n:"BrtBrk" },
178940x018D: { n:"BrtUserBookView" },
178950x018E: { n:"BrtInfo" },
178960x018F: { n:"BrtCUsr" },
178970x0190: { n:"BrtUsr" },
178980x0191: { n:"BrtBeginUsers" },
178990x0193: { n:"BrtEOF" },
179000x0194: { n:"BrtUCR" },
179010x0195: { n:"BrtRRInsDel" },
179020x0196: { n:"BrtRREndInsDel" },
179030x0197: { n:"BrtRRMove" },
179040x0198: { n:"BrtRREndMove" },
179050x0199: { n:"BrtRRChgCell" },
179060x019A: { n:"BrtRREndChgCell" },
179070x019B: { n:"BrtRRHeader" },
179080x019C: { n:"BrtRRUserView" },
179090x019D: { n:"BrtRRRenSheet" },
179100x019E: { n:"BrtRRInsertSh" },
179110x019F: { n:"BrtRRDefName" },
179120x01A0: { n:"BrtRRNote" },
179130x01A1: { n:"BrtRRConflict" },
179140x01A2: { n:"BrtRRTQSIF" },
179150x01A3: { n:"BrtRRFormat" },
179160x01A4: { n:"BrtRREndFormat" },
179170x01A5: { n:"BrtRRAutoFmt" },
179180x01A6: { n:"BrtBeginUserShViews" },
179190x01A7: { n:"BrtBeginUserShView" },
179200x01A8: { n:"BrtEndUserShView" },
179210x01A9: { n:"BrtEndUserShViews" },
179220x01AA: { n:"BrtArrFmla", f:parse_BrtArrFmla },
179230x01AB: { n:"BrtShrFmla", f:parse_BrtShrFmla },
179240x01AC: { n:"BrtTable" },
179250x01AD: { n:"BrtBeginExtConnections" },
179260x01AE: { n:"BrtEndExtConnections" },
179270x01AF: { n:"BrtBeginPCDCalcMems" },
179280x01B0: { n:"BrtEndPCDCalcMems" },
179290x01B1: { n:"BrtBeginPCDCalcMem" },
179300x01B2: { n:"BrtEndPCDCalcMem" },
179310x01B3: { n:"BrtBeginPCDHGLevels" },
179320x01B4: { n:"BrtEndPCDHGLevels" },
179330x01B5: { n:"BrtBeginPCDHGLevel" },
179340x01B6: { n:"BrtEndPCDHGLevel" },
179350x01B7: { n:"BrtBeginPCDHGLGroups" },
179360x01B8: { n:"BrtEndPCDHGLGroups" },
179370x01B9: { n:"BrtBeginPCDHGLGroup" },
179380x01BA: { n:"BrtEndPCDHGLGroup" },
179390x01BB: { n:"BrtBeginPCDHGLGMembers" },
179400x01BC: { n:"BrtEndPCDHGLGMembers" },
179410x01BD: { n:"BrtBeginPCDHGLGMember" },
179420x01BE: { n:"BrtEndPCDHGLGMember" },
179430x01BF: { n:"BrtBeginQSI" },
179440x01C0: { n:"BrtEndQSI" },
179450x01C1: { n:"BrtBeginQSIR" },
179460x01C2: { n:"BrtEndQSIR" },
179470x01C3: { n:"BrtBeginDeletedNames" },
179480x01C4: { n:"BrtEndDeletedNames" },
179490x01C5: { n:"BrtBeginDeletedName" },
179500x01C6: { n:"BrtEndDeletedName" },
179510x01C7: { n:"BrtBeginQSIFs" },
179520x01C8: { n:"BrtEndQSIFs" },
179530x01C9: { n:"BrtBeginQSIF" },
179540x01CA: { n:"BrtEndQSIF" },
179550x01CB: { n:"BrtBeginAutoSortScope" },
179560x01CC: { n:"BrtEndAutoSortScope" },
179570x01CD: { n:"BrtBeginConditionalFormatting" },
179580x01CE: { n:"BrtEndConditionalFormatting" },
179590x01CF: { n:"BrtBeginCFRule" },
179600x01D0: { n:"BrtEndCFRule" },
179610x01D1: { n:"BrtBeginIconSet" },
179620x01D2: { n:"BrtEndIconSet" },
179630x01D3: { n:"BrtBeginDatabar" },
179640x01D4: { n:"BrtEndDatabar" },
179650x01D5: { n:"BrtBeginColorScale" },
179660x01D6: { n:"BrtEndColorScale" },
179670x01D7: { n:"BrtCFVO" },
179680x01D8: { n:"BrtExternValueMeta" },
179690x01D9: { n:"BrtBeginColorPalette" },
179700x01DA: { n:"BrtEndColorPalette" },
179710x01DB: { n:"BrtIndexedColor" },
179720x01DC: { n:"BrtMargins", f:parse_BrtMargins },
179730x01DD: { n:"BrtPrintOptions" },
179740x01DE: { n:"BrtPageSetup" },
179750x01DF: { n:"BrtBeginHeaderFooter" },
179760x01E0: { n:"BrtEndHeaderFooter" },
179770x01E1: { n:"BrtBeginSXCrtFormat" },
179780x01E2: { n:"BrtEndSXCrtFormat" },
179790x01E3: { n:"BrtBeginSXCrtFormats" },
179800x01E4: { n:"BrtEndSXCrtFormats" },
179810x01E5: { n:"BrtWsFmtInfo", f:parse_BrtWsFmtInfo },
179820x01E6: { n:"BrtBeginMgs" },
179830x01E7: { n:"BrtEndMGs" },
179840x01E8: { n:"BrtBeginMGMaps" },
179850x01E9: { n:"BrtEndMGMaps" },
179860x01EA: { n:"BrtBeginMG" },
179870x01EB: { n:"BrtEndMG" },
179880x01EC: { n:"BrtBeginMap" },
179890x01ED: { n:"BrtEndMap" },
179900x01EE: { n:"BrtHLink", f:parse_BrtHLink },
179910x01EF: { n:"BrtBeginDCon" },
179920x01F0: { n:"BrtEndDCon" },
179930x01F1: { n:"BrtBeginDRefs" },
179940x01F2: { n:"BrtEndDRefs" },
179950x01F3: { n:"BrtDRef" },
179960x01F4: { n:"BrtBeginScenMan" },
179970x01F5: { n:"BrtEndScenMan" },
179980x01F6: { n:"BrtBeginSct" },
179990x01F7: { n:"BrtEndSct" },
180000x01F8: { n:"BrtSlc" },
180010x01F9: { n:"BrtBeginDXFs" },
180020x01FA: { n:"BrtEndDXFs" },
180030x01FB: { n:"BrtDXF" },
180040x01FC: { n:"BrtBeginTableStyles" },
180050x01FD: { n:"BrtEndTableStyles" },
180060x01FE: { n:"BrtBeginTableStyle" },
180070x01FF: { n:"BrtEndTableStyle" },
180080x0200: { n:"BrtTableStyleElement" },
180090x0201: { n:"BrtTableStyleClient" },
180100x0202: { n:"BrtBeginVolDeps" },
180110x0203: { n:"BrtEndVolDeps" },
180120x0204: { n:"BrtBeginVolType" },
180130x0205: { n:"BrtEndVolType" },
180140x0206: { n:"BrtBeginVolMain" },
180150x0207: { n:"BrtEndVolMain" },
180160x0208: { n:"BrtBeginVolTopic" },
180170x0209: { n:"BrtEndVolTopic" },
180180x020A: { n:"BrtVolSubtopic" },
180190x020B: { n:"BrtVolRef" },
180200x020C: { n:"BrtVolNum" },
180210x020D: { n:"BrtVolErr" },
180220x020E: { n:"BrtVolStr" },
180230x020F: { n:"BrtVolBool" },
180240x0210: { n:"BrtBeginCalcChain$" },
180250x0211: { n:"BrtEndCalcChain$" },
180260x0212: { n:"BrtBeginSortState" },
180270x0213: { n:"BrtEndSortState" },
180280x0214: { n:"BrtBeginSortCond" },
180290x0215: { n:"BrtEndSortCond" },
180300x0216: { n:"BrtBookProtection" },
180310x0217: { n:"BrtSheetProtection" },
180320x0218: { n:"BrtRangeProtection" },
180330x0219: { n:"BrtPhoneticInfo" },
180340x021A: { n:"BrtBeginECTxtWiz" },
180350x021B: { n:"BrtEndECTxtWiz" },
180360x021C: { n:"BrtBeginECTWFldInfoLst" },
180370x021D: { n:"BrtEndECTWFldInfoLst" },
180380x021E: { n:"BrtBeginECTwFldInfo" },
180390x0224: { n:"BrtFileSharing" },
180400x0225: { n:"BrtOleSize" },
180410x0226: { n:"BrtDrawing", f:parse_RelID },
180420x0227: { n:"BrtLegacyDrawing" },
180430x0228: { n:"BrtLegacyDrawingHF" },
180440x0229: { n:"BrtWebOpt" },
180450x022A: { n:"BrtBeginWebPubItems" },
180460x022B: { n:"BrtEndWebPubItems" },
180470x022C: { n:"BrtBeginWebPubItem" },
180480x022D: { n:"BrtEndWebPubItem" },
180490x022E: { n:"BrtBeginSXCondFmt" },
180500x022F: { n:"BrtEndSXCondFmt" },
180510x0230: { n:"BrtBeginSXCondFmts" },
180520x0231: { n:"BrtEndSXCondFmts" },
180530x0232: { n:"BrtBkHim" },
180540x0234: { n:"BrtColor" },
180550x0235: { n:"BrtBeginIndexedColors" },
180560x0236: { n:"BrtEndIndexedColors" },
180570x0239: { n:"BrtBeginMRUColors" },
180580x023A: { n:"BrtEndMRUColors" },
180590x023C: { n:"BrtMRUColor" },
180600x023D: { n:"BrtBeginDVals" },
180610x023E: { n:"BrtEndDVals" },
180620x0241: { n:"BrtSupNameStart" },
180630x0242: { n:"BrtSupNameValueStart" },
180640x0243: { n:"BrtSupNameValueEnd" },
180650x0244: { n:"BrtSupNameNum" },
180660x0245: { n:"BrtSupNameErr" },
180670x0246: { n:"BrtSupNameSt" },
180680x0247: { n:"BrtSupNameNil" },
180690x0248: { n:"BrtSupNameBool" },
180700x0249: { n:"BrtSupNameFmla" },
180710x024A: { n:"BrtSupNameBits" },
180720x024B: { n:"BrtSupNameEnd" },
180730x024C: { n:"BrtEndSupBook" },
180740x024D: { n:"BrtCellSmartTagProperty" },
180750x024E: { n:"BrtBeginCellSmartTag" },
180760x024F: { n:"BrtEndCellSmartTag" },
180770x0250: { n:"BrtBeginCellSmartTags" },
180780x0251: { n:"BrtEndCellSmartTags" },
180790x0252: { n:"BrtBeginSmartTags" },
180800x0253: { n:"BrtEndSmartTags" },
180810x0254: { n:"BrtSmartTagType" },
180820x0255: { n:"BrtBeginSmartTagTypes" },
180830x0256: { n:"BrtEndSmartTagTypes" },
180840x0257: { n:"BrtBeginSXFilters" },
180850x0258: { n:"BrtEndSXFilters" },
180860x0259: { n:"BrtBeginSXFILTER" },
180870x025A: { n:"BrtEndSXFilter" },
180880x025B: { n:"BrtBeginFills" },
180890x025C: { n:"BrtEndFills" },
180900x025D: { n:"BrtBeginCellWatches" },
180910x025E: { n:"BrtEndCellWatches" },
180920x025F: { n:"BrtCellWatch" },
180930x0260: { n:"BrtBeginCRErrs" },
180940x0261: { n:"BrtEndCRErrs" },
180950x0262: { n:"BrtCrashRecErr" },
180960x0263: { n:"BrtBeginFonts" },
180970x0264: { n:"BrtEndFonts" },
180980x0265: { n:"BrtBeginBorders" },
180990x0266: { n:"BrtEndBorders" },
181000x0267: { n:"BrtBeginFmts" },
181010x0268: { n:"BrtEndFmts" },
181020x0269: { n:"BrtBeginCellXFs" },
181030x026A: { n:"BrtEndCellXFs" },
181040x026B: { n:"BrtBeginStyles" },
181050x026C: { n:"BrtEndStyles" },
181060x0271: { n:"BrtBigName" },
181070x0272: { n:"BrtBeginCellStyleXFs" },
181080x0273: { n:"BrtEndCellStyleXFs" },
181090x0274: { n:"BrtBeginComments" },
181100x0275: { n:"BrtEndComments" },
181110x0276: { n:"BrtBeginCommentAuthors" },
181120x0277: { n:"BrtEndCommentAuthors" },
181130x0278: { n:"BrtCommentAuthor", f:parse_BrtCommentAuthor },
181140x0279: { n:"BrtBeginCommentList" },
181150x027A: { n:"BrtEndCommentList" },
181160x027B: { n:"BrtBeginComment", f:parse_BrtBeginComment},
181170x027C: { n:"BrtEndComment" },
181180x027D: { n:"BrtCommentText", f:parse_BrtCommentText },
181190x027E: { n:"BrtBeginOleObjects" },
181200x027F: { n:"BrtOleObject" },
181210x0280: { n:"BrtEndOleObjects" },
181220x0281: { n:"BrtBeginSxrules" },
181230x0282: { n:"BrtEndSxRules" },
181240x0283: { n:"BrtBeginActiveXControls" },
181250x0284: { n:"BrtActiveX" },
181260x0285: { n:"BrtEndActiveXControls" },
181270x0286: { n:"BrtBeginPCDSDTCEMembersSortBy" },
181280x0288: { n:"BrtBeginCellIgnoreECs" },
181290x0289: { n:"BrtCellIgnoreEC" },
181300x028A: { n:"BrtEndCellIgnoreECs" },
181310x028B: { n:"BrtCsProp", f:parse_BrtCsProp },
181320x028C: { n:"BrtCsPageSetup" },
181330x028D: { n:"BrtBeginUserCsViews" },
181340x028E: { n:"BrtEndUserCsViews" },
181350x028F: { n:"BrtBeginUserCsView" },
181360x0290: { n:"BrtEndUserCsView" },
181370x0291: { n:"BrtBeginPcdSFCIEntries" },
181380x0292: { n:"BrtEndPCDSFCIEntries" },
181390x0293: { n:"BrtPCDSFCIEntry" },
181400x0294: { n:"BrtBeginListParts" },
181410x0295: { n:"BrtListPart" },
181420x0296: { n:"BrtEndListParts" },
181430x0297: { n:"BrtSheetCalcProp" },
181440x0298: { n:"BrtBeginFnGroup" },
181450x0299: { n:"BrtFnGroup" },
181460x029A: { n:"BrtEndFnGroup" },
181470x029B: { n:"BrtSupAddin" },
181480x029C: { n:"BrtSXTDMPOrder" },
181490x029D: { n:"BrtCsProtection" },
181500x029F: { n:"BrtBeginWsSortMap" },
181510x02A0: { n:"BrtEndWsSortMap" },
181520x02A1: { n:"BrtBeginRRSort" },
181530x02A2: { n:"BrtEndRRSort" },
181540x02A3: { n:"BrtRRSortItem" },
181550x02A4: { n:"BrtFileSharingIso" },
181560x02A5: { n:"BrtBookProtectionIso" },
181570x02A6: { n:"BrtSheetProtectionIso" },
181580x02A7: { n:"BrtCsProtectionIso" },
181590x02A8: { n:"BrtRangeProtectionIso" },
181600x02A9: { n:"BrtDValList" },
181610x0400: { n:"BrtRwDescent" },
181620x0401: { n:"BrtKnownFonts" },
181630x0402: { n:"BrtBeginSXTupleSet" },
181640x0403: { n:"BrtEndSXTupleSet" },
181650x0404: { n:"BrtBeginSXTupleSetHeader" },
181660x0405: { n:"BrtEndSXTupleSetHeader" },
181670x0406: { n:"BrtSXTupleSetHeaderItem" },
181680x0407: { n:"BrtBeginSXTupleSetData" },
181690x0408: { n:"BrtEndSXTupleSetData" },
181700x0409: { n:"BrtBeginSXTupleSetRow" },
181710x040A: { n:"BrtEndSXTupleSetRow" },
181720x040B: { n:"BrtSXTupleSetRowItem" },
181730x040C: { n:"BrtNameExt" },
181740x040D: { n:"BrtPCDH14" },
181750x040E: { n:"BrtBeginPCDCalcMem14" },
181760x040F: { n:"BrtEndPCDCalcMem14" },
181770x0410: { n:"BrtSXTH14" },
181780x0411: { n:"BrtBeginSparklineGroup" },
181790x0412: { n:"BrtEndSparklineGroup" },
181800x0413: { n:"BrtSparkline" },
181810x0414: { n:"BrtSXDI14" },
181820x0415: { n:"BrtWsFmtInfoEx14" },
181830x0416: { n:"BrtBeginConditionalFormatting14" },
181840x0417: { n:"BrtEndConditionalFormatting14" },
181850x0418: { n:"BrtBeginCFRule14" },
181860x0419: { n:"BrtEndCFRule14" },
181870x041A: { n:"BrtCFVO14" },
181880x041B: { n:"BrtBeginDatabar14" },
181890x041C: { n:"BrtBeginIconSet14" },
181900x041D: { n:"BrtDVal14", f: parse_BrtDVal14 },
181910x041E: { n:"BrtBeginDVals14" },
181920x041F: { n:"BrtColor14" },
181930x0420: { n:"BrtBeginSparklines" },
181940x0421: { n:"BrtEndSparklines" },
181950x0422: { n:"BrtBeginSparklineGroups" },
181960x0423: { n:"BrtEndSparklineGroups" },
181970x0425: { n:"BrtSXVD14" },
181980x0426: { n:"BrtBeginSXView14" },
181990x0427: { n:"BrtEndSXView14" },
182000x0428: { n:"BrtBeginSXView16" },
182010x0429: { n:"BrtEndSXView16" },
182020x042A: { n:"BrtBeginPCD14" },
182030x042B: { n:"BrtEndPCD14" },
182040x042C: { n:"BrtBeginExtConn14" },
182050x042D: { n:"BrtEndExtConn14" },
182060x042E: { n:"BrtBeginSlicerCacheIDs" },
182070x042F: { n:"BrtEndSlicerCacheIDs" },
182080x0430: { n:"BrtBeginSlicerCacheID" },
182090x0431: { n:"BrtEndSlicerCacheID" },
182100x0433: { n:"BrtBeginSlicerCache" },
182110x0434: { n:"BrtEndSlicerCache" },
182120x0435: { n:"BrtBeginSlicerCacheDef" },
182130x0436: { n:"BrtEndSlicerCacheDef" },
182140x0437: { n:"BrtBeginSlicersEx" },
182150x0438: { n:"BrtEndSlicersEx" },
182160x0439: { n:"BrtBeginSlicerEx" },
182170x043A: { n:"BrtEndSlicerEx" },
182180x043B: { n:"BrtBeginSlicer" },
182190x043C: { n:"BrtEndSlicer" },
182200x043D: { n:"BrtSlicerCachePivotTables" },
182210x043E: { n:"BrtBeginSlicerCacheOlapImpl" },
182220x043F: { n:"BrtEndSlicerCacheOlapImpl" },
182230x0440: { n:"BrtBeginSlicerCacheLevelsData" },
182240x0441: { n:"BrtEndSlicerCacheLevelsData" },
182250x0442: { n:"BrtBeginSlicerCacheLevelData" },
182260x0443: { n:"BrtEndSlicerCacheLevelData" },
182270x0444: { n:"BrtBeginSlicerCacheSiRanges" },
182280x0445: { n:"BrtEndSlicerCacheSiRanges" },
182290x0446: { n:"BrtBeginSlicerCacheSiRange" },
182300x0447: { n:"BrtEndSlicerCacheSiRange" },
182310x0448: { n:"BrtSlicerCacheOlapItem" },
182320x0449: { n:"BrtBeginSlicerCacheSelections" },
182330x044A: { n:"BrtSlicerCacheSelection" },
182340x044B: { n:"BrtEndSlicerCacheSelections" },
182350x044C: { n:"BrtBeginSlicerCacheNative" },
182360x044D: { n:"BrtEndSlicerCacheNative" },
182370x044E: { n:"BrtSlicerCacheNativeItem" },
182380x044F: { n:"BrtRangeProtection14" },
182390x0450: { n:"BrtRangeProtectionIso14" },
182400x0451: { n:"BrtCellIgnoreEC14" },
182410x0457: { n:"BrtList14" },
182420x0458: { n:"BrtCFIcon" },
182430x0459: { n:"BrtBeginSlicerCachesPivotCacheIDs" },
182440x045A: { n:"BrtEndSlicerCachesPivotCacheIDs" },
182450x045B: { n:"BrtBeginSlicers" },
182460x045C: { n:"BrtEndSlicers" },
182470x045D: { n:"BrtWbProp14" },
182480x045E: { n:"BrtBeginSXEdit" },
182490x045F: { n:"BrtEndSXEdit" },
182500x0460: { n:"BrtBeginSXEdits" },
182510x0461: { n:"BrtEndSXEdits" },
182520x0462: { n:"BrtBeginSXChange" },
182530x0463: { n:"BrtEndSXChange" },
182540x0464: { n:"BrtBeginSXChanges" },
182550x0465: { n:"BrtEndSXChanges" },
182560x0466: { n:"BrtSXTupleItems" },
182570x0468: { n:"BrtBeginSlicerStyle" },
182580x0469: { n:"BrtEndSlicerStyle" },
182590x046A: { n:"BrtSlicerStyleElement" },
182600x046B: { n:"BrtBeginStyleSheetExt14" },
182610x046C: { n:"BrtEndStyleSheetExt14" },
182620x046D: { n:"BrtBeginSlicerCachesPivotCacheID" },
182630x046E: { n:"BrtEndSlicerCachesPivotCacheID" },
182640x046F: { n:"BrtBeginConditionalFormattings" },
182650x0470: { n:"BrtEndConditionalFormattings" },
182660x0471: { n:"BrtBeginPCDCalcMemExt" },
182670x0472: { n:"BrtEndPCDCalcMemExt" },
182680x0473: { n:"BrtBeginPCDCalcMemsExt" },
182690x0474: { n:"BrtEndPCDCalcMemsExt" },
182700x0475: { n:"BrtPCDField14" },
182710x0476: { n:"BrtBeginSlicerStyles" },
182720x0477: { n:"BrtEndSlicerStyles" },
182730x0478: { n:"BrtBeginSlicerStyleElements" },
182740x0479: { n:"BrtEndSlicerStyleElements" },
182750x047A: { n:"BrtCFRuleExt" },
182760x047B: { n:"BrtBeginSXCondFmt14" },
182770x047C: { n:"BrtEndSXCondFmt14" },
182780x047D: { n:"BrtBeginSXCondFmts14" },
182790x047E: { n:"BrtEndSXCondFmts14" },
182800x0480: { n:"BrtBeginSortCond14" },
182810x0481: { n:"BrtEndSortCond14" },
182820x0482: { n:"BrtEndDVals14" },
182830x0483: { n:"BrtEndIconSet14" },
182840x0484: { n:"BrtEndDatabar14" },
182850x0485: { n:"BrtBeginColorScale14" },
182860x0486: { n:"BrtEndColorScale14" },
182870x0487: { n:"BrtBeginSxrules14" },
182880x0488: { n:"BrtEndSxrules14" },
182890x0489: { n:"BrtBeginPRule14" },
182900x048A: { n:"BrtEndPRule14" },
182910x048B: { n:"BrtBeginPRFilters14" },
182920x048C: { n:"BrtEndPRFilters14" },
182930x048D: { n:"BrtBeginPRFilter14" },
182940x048E: { n:"BrtEndPRFilter14" },
182950x048F: { n:"BrtBeginPRFItem14" },
182960x0490: { n:"BrtEndPRFItem14" },
182970x0491: { n:"BrtBeginCellIgnoreECs14" },
182980x0492: { n:"BrtEndCellIgnoreECs14" },
182990x0493: { n:"BrtDxf14" },
183000x0494: { n:"BrtBeginDxF14s" },
183010x0495: { n:"BrtEndDxf14s" },
183020x0499: { n:"BrtFilter14" },
183030x049A: { n:"BrtBeginCustomFilters14" },
183040x049C: { n:"BrtCustomFilter14" },
183050x049D: { n:"BrtIconFilter14" },
183060x049E: { n:"BrtPivotCacheConnectionName" },
183070x0800: { n:"BrtBeginDecoupledPivotCacheIDs" },
183080x0801: { n:"BrtEndDecoupledPivotCacheIDs" },
183090x0802: { n:"BrtDecoupledPivotCacheID" },
183100x0803: { n:"BrtBeginPivotTableRefs" },
183110x0804: { n:"BrtEndPivotTableRefs" },
183120x0805: { n:"BrtPivotTableRef" },
183130x0806: { n:"BrtSlicerCacheBookPivotTables" },
183140x0807: { n:"BrtBeginSxvcells" },
183150x0808: { n:"BrtEndSxvcells" },
183160x0809: { n:"BrtBeginSxRow" },
183170x080A: { n:"BrtEndSxRow" },
183180x080C: { n:"BrtPcdCalcMem15" },
183190x0813: { n:"BrtQsi15" },
183200x0814: { n:"BrtBeginWebExtensions" },
183210x0815: { n:"BrtEndWebExtensions" },
183220x0816: { n:"BrtWebExtension" },
183230x0817: { n:"BrtAbsPath15" },
183240x0818: { n:"BrtBeginPivotTableUISettings" },
183250x0819: { n:"BrtEndPivotTableUISettings" },
183260x081B: { n:"BrtTableSlicerCacheIDs" },
183270x081C: { n:"BrtTableSlicerCacheID" },
183280x081D: { n:"BrtBeginTableSlicerCache" },
183290x081E: { n:"BrtEndTableSlicerCache" },
183300x081F: { n:"BrtSxFilter15" },
183310x0820: { n:"BrtBeginTimelineCachePivotCacheIDs" },
183320x0821: { n:"BrtEndTimelineCachePivotCacheIDs" },
183330x0822: { n:"BrtTimelineCachePivotCacheID" },
183340x0823: { n:"BrtBeginTimelineCacheIDs" },
183350x0824: { n:"BrtEndTimelineCacheIDs" },
183360x0825: { n:"BrtBeginTimelineCacheID" },
183370x0826: { n:"BrtEndTimelineCacheID" },
183380x0827: { n:"BrtBeginTimelinesEx" },
183390x0828: { n:"BrtEndTimelinesEx" },
183400x0829: { n:"BrtBeginTimelineEx" },
183410x082A: { n:"BrtEndTimelineEx" },
183420x082B: { n:"BrtWorkBookPr15" },
183430x082C: { n:"BrtPCDH15" },
183440x082D: { n:"BrtBeginTimelineStyle" },
183450x082E: { n:"BrtEndTimelineStyle" },
183460x082F: { n:"BrtTimelineStyleElement" },
183470x0830: { n:"BrtBeginTimelineStylesheetExt15" },
183480x0831: { n:"BrtEndTimelineStylesheetExt15" },
183490x0832: { n:"BrtBeginTimelineStyles" },
183500x0833: { n:"BrtEndTimelineStyles" },
183510x0834: { n:"BrtBeginTimelineStyleElements" },
183520x0835: { n:"BrtEndTimelineStyleElements" },
183530x0836: { n:"BrtDxf15" },
183540x0837: { n:"BrtBeginDxfs15" },
183550x0838: { n:"brtEndDxfs15" },
183560x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
183570x083A: { n:"BrtBeginItemUniqueNames" },
183580x083B: { n:"BrtEndItemUniqueNames" },
183590x083C: { n:"BrtItemUniqueName" },
183600x083D: { n:"BrtBeginExtConn15" },
183610x083E: { n:"BrtEndExtConn15" },
183620x083F: { n:"BrtBeginOledbPr15" },
183630x0840: { n:"BrtEndOledbPr15" },
183640x0841: { n:"BrtBeginDataFeedPr15" },
183650x0842: { n:"BrtEndDataFeedPr15" },
183660x0843: { n:"BrtTextPr15" },
183670x0844: { n:"BrtRangePr15" },
183680x0845: { n:"BrtDbCommand15" },
183690x0846: { n:"BrtBeginDbTables15" },
183700x0847: { n:"BrtEndDbTables15" },
183710x0848: { n:"BrtDbTable15" },
183720x0849: { n:"BrtBeginDataModel" },
183730x084A: { n:"BrtEndDataModel" },
183740x084B: { n:"BrtBeginModelTables" },
183750x084C: { n:"BrtEndModelTables" },
183760x084D: { n:"BrtModelTable" },
183770x084E: { n:"BrtBeginModelRelationships" },
183780x084F: { n:"BrtEndModelRelationships" },
183790x0850: { n:"BrtModelRelationship" },
183800x0851: { n:"BrtBeginECTxtWiz15" },
183810x0852: { n:"BrtEndECTxtWiz15" },
183820x0853: { n:"BrtBeginECTWFldInfoLst15" },
183830x0854: { n:"BrtEndECTWFldInfoLst15" },
183840x0855: { n:"BrtBeginECTWFldInfo15" },
183850x0856: { n:"BrtFieldListActiveItem" },
183860x0857: { n:"BrtPivotCacheIdVersion" },
183870x0858: { n:"BrtSXDI15" },
183880x0859: { n:"BrtBeginModelTimeGroupings" },
183890x085A: { n:"BrtEndModelTimeGroupings" },
183900x085B: { n:"BrtBeginModelTimeGrouping" },
183910x085C: { n:"BrtEndModelTimeGrouping" },
183920x085D: { n:"BrtModelTimeGroupingCalcCol" },
183930x0C00: { n:"BrtUid" },
183940x0C01: { n:"BrtRevisionPtr" },
183950x13e7: { n:"BrtBeginCalcFeatures" },
183960x13e8: { n:"BrtEndCalcFeatures" },
183970x13e9: { n:"BrtCalcFeature" },
183980xFFFF: { n:"" }
18399};
18400
18401var XLSBRE = evert_key(XLSBRecordEnum, 'n');
18402
18403/* [MS-XLS] 2.3 Record Enumeration */
18404var XLSRecordEnum = {
184050x0003: { n:"BIFF2NUM", f:parse_BIFF2NUM },
184060x0004: { n:"BIFF2STR", f:parse_BIFF2STR },
184070x0006: { n:"Formula", f:parse_Formula },
184080x0009: { n:'BOF', f:parse_BOF },
184090x000a: { n:'EOF', f:parsenoop2 },
184100x000c: { n:"CalcCount", f:parseuint16 },
184110x000d: { n:"CalcMode", f:parseuint16 },
184120x000e: { n:"CalcPrecision", f:parsebool },
184130x000f: { n:"CalcRefMode", f:parsebool },
184140x0010: { n:"CalcDelta", f:parse_Xnum },
184150x0011: { n:"CalcIter", f:parsebool },
184160x0012: { n:"Protect", f:parsebool },
184170x0013: { n:"Password", f:parseuint16 },
184180x0014: { n:"Header", f:parse_XLHeaderFooter },
184190x0015: { n:"Footer", f:parse_XLHeaderFooter },
184200x0017: { n:"ExternSheet", f:parse_ExternSheet },
184210x0018: { n:"Lbl", f:parse_Lbl },
184220x0019: { n:"WinProtect", f:parsebool },
184230x001a: { n:"VerticalPageBreaks" },
184240x001b: { n:"HorizontalPageBreaks" },
184250x001c: { n:"Note", f:parse_Note },
184260x001d: { n:"Selection" },
184270x0022: { n:"Date1904", f:parsebool },
184280x0023: { n:"ExternName", f:parse_ExternName },
184290x0026: { n:"LeftMargin", f:parse_Xnum },
184300x0027: { n:"RightMargin", f:parse_Xnum },
184310x0028: { n:"TopMargin", f:parse_Xnum },
184320x0029: { n:"BottomMargin", f:parse_Xnum },
184330x002a: { n:"PrintRowCol", f:parsebool },
184340x002b: { n:"PrintGrid", f:parsebool },
184350x002f: { n:"FilePass", f:parse_FilePass },
184360x0031: { n:"Font", f:parse_Font },
184370x0033: { n:"PrintSize", f:parseuint16 },
184380x003c: { n:"Continue" },
184390x003d: { n:"Window1", f:parse_Window1 },
184400x0040: { n:"Backup", f:parsebool },
184410x0041: { n:"Pane", f:parse_Pane },
184420x0042: { n:'CodePage', f:parseuint16 },
184430x004d: { n:"Pls" },
184440x0050: { n:"DCon" },
184450x0051: { n:"DConRef" },
184460x0052: { n:"DConName" },
184470x0055: { n:"DefColWidth", f:parseuint16 },
184480x0059: { n:"XCT" },
184490x005a: { n:"CRN" },
184500x005b: { n:"FileSharing" },
184510x005c: { n:'WriteAccess', f:parse_WriteAccess },
184520x005d: { n:"Obj", f:parse_Obj },
184530x005e: { n:"Uncalced" },
184540x005f: { n:"CalcSaveRecalc", f:parsebool },
184550x0060: { n:"Template" },
184560x0061: { n:"Intl" },
184570x0063: { n:"ObjProtect", f:parsebool },
184580x007d: { n:"ColInfo", f:parse_ColInfo },
184590x0080: { n:"Guts", f:parse_Guts },
184600x0081: { n:"WsBool", f:parse_WsBool },
184610x0082: { n:"GridSet", f:parseuint16 },
184620x0083: { n:"HCenter", f:parsebool },
184630x0084: { n:"VCenter", f:parsebool },
184640x0085: { n:'BoundSheet8', f:parse_BoundSheet8 },
184650x0086: { n:"WriteProtect" },
184660x008c: { n:"Country", f:parse_Country },
184670x008d: { n:"HideObj", f:parseuint16 },
184680x0090: { n:"Sort" },
184690x0092: { n:"Palette", f:parse_Palette },
184700x0097: { n:"Sync" },
184710x0098: { n:"LPr" },
184720x0099: { n:"DxGCol" },
184730x009a: { n:"FnGroupName" },
184740x009b: { n:"FilterMode" },
184750x009c: { n:"BuiltInFnGroupCount", f:parseuint16 },
184760x009d: { n:"AutoFilterInfo" },
184770x009e: { n:"AutoFilter" },
184780x00a0: { n:"Scl", f:parse_Scl },
184790x00a1: { n:"Setup", f:parse_Setup },
184800x00ae: { n:"ScenMan" },
184810x00af: { n:"SCENARIO" },
184820x00b0: { n:"SxView" },
184830x00b1: { n:"Sxvd" },
184840x00b2: { n:"SXVI" },
184850x00b4: { n:"SxIvd" },
184860x00b5: { n:"SXLI" },
184870x00b6: { n:"SXPI" },
184880x00b8: { n:"DocRoute" },
184890x00b9: { n:"RecipName" },
184900x00bd: { n:"MulRk", f:parse_MulRk },
184910x00be: { n:"MulBlank", f:parse_MulBlank },
184920x00c1: { n:'Mms', f:parsenoop2 },
184930x00c5: { n:"SXDI" },
184940x00c6: { n:"SXDB" },
184950x00c7: { n:"SXFDB" },
184960x00c8: { n:"SXDBB" },
184970x00c9: { n:"SXNum" },
184980x00ca: { n:"SxBool", f:parsebool },
184990x00cb: { n:"SxErr" },
185000x00cc: { n:"SXInt" },
185010x00cd: { n:"SXString" },
185020x00ce: { n:"SXDtr" },
185030x00cf: { n:"SxNil" },
185040x00d0: { n:"SXTbl" },
185050x00d1: { n:"SXTBRGIITM" },
185060x00d2: { n:"SxTbpg" },
185070x00d3: { n:"ObProj" },
185080x00d5: { n:"SXStreamID" },
185090x00d7: { n:"DBCell" },
185100x00d8: { n:"SXRng" },
185110x00d9: { n:"SxIsxoper" },
185120x00da: { n:"BookBool", f:parseuint16 },
185130x00dc: { n:"DbOrParamQry" },
185140x00dd: { n:"ScenarioProtect", f:parsebool },
185150x00de: { n:"OleObjectSize" },
185160x00e0: { n:"XF", f:parse_XF },
185170x00e1: { n:'InterfaceHdr', f:parse_InterfaceHdr },
185180x00e2: { n:'InterfaceEnd', f:parsenoop2 },
185190x00e3: { n:"SXVS" },
185200x00e5: { n:"MergeCells", f:parse_MergeCells },
185210x00e9: { n:"BkHim" },
185220x00eb: { n:"MsoDrawingGroup" },
185230x00ec: { n:"MsoDrawing" },
185240x00ed: { n:"MsoDrawingSelection" },
185250x00ef: { n:"PhoneticInfo" },
185260x00f0: { n:"SxRule" },
185270x00f1: { n:"SXEx" },
185280x00f2: { n:"SxFilt" },
185290x00f4: { n:"SxDXF" },
185300x00f5: { n:"SxItm" },
185310x00f6: { n:"SxName" },
185320x00f7: { n:"SxSelect" },
185330x00f8: { n:"SXPair" },
185340x00f9: { n:"SxFmla" },
185350x00fb: { n:"SxFormat" },
185360x00fc: { n:"SST", f:parse_SST },
185370x00fd: { n:"LabelSst", f:parse_LabelSst },
185380x00ff: { n:"ExtSST", f:parse_ExtSST },
185390x0100: { n:"SXVDEx" },
185400x0103: { n:"SXFormula" },
185410x0122: { n:"SXDBEx" },
185420x0137: { n:"RRDInsDel" },
185430x0138: { n:"RRDHead" },
185440x013b: { n:"RRDChgCell" },
185450x013d: { n:"RRTabId", f:parseuint16a },
185460x013e: { n:"RRDRenSheet" },
185470x013f: { n:"RRSort" },
185480x0140: { n:"RRDMove" },
185490x014a: { n:"RRFormat" },
185500x014b: { n:"RRAutoFmt" },
185510x014d: { n:"RRInsertSh" },
185520x014e: { n:"RRDMoveBegin" },
185530x014f: { n:"RRDMoveEnd" },
185540x0150: { n:"RRDInsDelBegin" },
185550x0151: { n:"RRDInsDelEnd" },
185560x0152: { n:"RRDConflict" },
185570x0153: { n:"RRDDefName" },
185580x0154: { n:"RRDRstEtxp" },
185590x015f: { n:"LRng" },
185600x0160: { n:"UsesELFs", f:parsebool },
185610x0161: { n:"DSF", f:parsenoop2 },
185620x0191: { n:"CUsr" },
185630x0192: { n:"CbUsr" },
185640x0193: { n:"UsrInfo" },
185650x0194: { n:"UsrExcl" },
185660x0195: { n:"FileLock" },
185670x0196: { n:"RRDInfo" },
185680x0197: { n:"BCUsrs" },
185690x0198: { n:"UsrChk" },
185700x01a9: { n:"UserBView" },
185710x01aa: { n:"UserSViewBegin" },
185720x01ab: { n:"UserSViewEnd" },
185730x01ac: { n:"RRDUserView" },
185740x01ad: { n:"Qsi" },
185750x01ae: { n:"SupBook", f:parse_SupBook },
185760x01af: { n:"Prot4Rev", f:parsebool },
185770x01b0: { n:"CondFmt" },
185780x01b1: { n:"CF" },
185790x01b2: { n:"DVal" },
185800x01b5: { n:"DConBin" },
185810x01b6: { n:"TxO", f:parse_TxO },
185820x01b7: { n:"RefreshAll", f:parsebool },
185830x01b8: { n:"HLink", f:parse_HLink },
185840x01b9: { n:"Lel" },
185850x01ba: { n:"CodeName", f:parse_XLUnicodeString },
185860x01bb: { n:"SXFDBType" },
185870x01bc: { n:"Prot4RevPass", f:parseuint16 },
185880x01bd: { n:"ObNoMacros" },
185890x01be: { n:"Dv" },
185900x01c0: { n:"Excel9File", f:parsenoop2 },
185910x01c1: { n:"RecalcId", f:parse_RecalcId, r:2},
185920x01c2: { n:"EntExU2", f:parsenoop2 },
185930x0200: { n:"Dimensions", f:parse_Dimensions },
185940x0201: { n:"Blank", f:parse_Blank },
185950x0203: { n:"Number", f:parse_Number },
185960x0204: { n:"Label", f:parse_Label },
185970x0205: { n:"BoolErr", f:parse_BoolErr },
185980x0206: { n:"Formula", f:parse_Formula },
185990x0207: { n:"String", f:parse_String },
186000x0208: { n:'Row', f:parse_Row },
186010x020b: { n:"Index" },
186020x0221: { n:"Array", f:parse_Array },
186030x0225: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
186040x0236: { n:"Table" },
186050x023e: { n:"Window2", f:parse_Window2 },
186060x027e: { n:"RK", f:parse_RK },
186070x0293: { n:"Style" },
186080x0406: { n:"Formula", f:parse_Formula },
186090x0418: { n:"BigName" },
186100x041e: { n:"Format", f:parse_Format },
186110x043c: { n:"ContinueBigName" },
186120x04bc: { n:"ShrFmla", f:parse_ShrFmla },
186130x0800: { n:"HLinkTooltip", f:parse_HLinkTooltip },
186140x0801: { n:"WebPub" },
186150x0802: { n:"QsiSXTag" },
186160x0803: { n:"DBQueryExt" },
186170x0804: { n:"ExtString" },
186180x0805: { n:"TxtQry" },
186190x0806: { n:"Qsir" },
186200x0807: { n:"Qsif" },
186210x0808: { n:"RRDTQSIF" },
186220x0809: { n:'BOF', f:parse_BOF },
186230x080a: { n:"OleDbConn" },
186240x080b: { n:"WOpt" },
186250x080c: { n:"SXViewEx" },
186260x080d: { n:"SXTH" },
186270x080e: { n:"SXPIEx" },
186280x080f: { n:"SXVDTEx" },
186290x0810: { n:"SXViewEx9" },
186300x0812: { n:"ContinueFrt" },
186310x0813: { n:"RealTimeData" },
186320x0850: { n:"ChartFrtInfo" },
186330x0851: { n:"FrtWrapper" },
186340x0852: { n:"StartBlock" },
186350x0853: { n:"EndBlock" },
186360x0854: { n:"StartObject" },
186370x0855: { n:"EndObject" },
186380x0856: { n:"CatLab" },
186390x0857: { n:"YMult" },
186400x0858: { n:"SXViewLink" },
186410x0859: { n:"PivotChartBits" },
186420x085a: { n:"FrtFontList" },
186430x0862: { n:"SheetExt" },
186440x0863: { n:"BookExt", r:12},
186450x0864: { n:"SXAddl" },
186460x0865: { n:"CrErr" },
186470x0866: { n:"HFPicture" },
186480x0867: { n:'FeatHdr', f:parsenoop2 },
186490x0868: { n:"Feat" },
186500x086a: { n:"DataLabExt" },
186510x086b: { n:"DataLabExtContents" },
186520x086c: { n:"CellWatch" },
186530x0871: { n:"FeatHdr11" },
186540x0872: { n:"Feature11" },
186550x0874: { n:"DropDownObjIds" },
186560x0875: { n:"ContinueFrt11" },
186570x0876: { n:"DConn" },
186580x0877: { n:"List12" },
186590x0878: { n:"Feature12" },
186600x0879: { n:"CondFmt12" },
186610x087a: { n:"CF12" },
186620x087b: { n:"CFEx" },
186630x087c: { n:"XFCRC", f:parse_XFCRC, r:12 },
186640x087d: { n:"XFExt", f:parse_XFExt, r:12 },
186650x087e: { n:"AutoFilter12" },
186660x087f: { n:"ContinueFrt12" },
186670x0884: { n:"MDTInfo" },
186680x0885: { n:"MDXStr" },
186690x0886: { n:"MDXTuple" },
186700x0887: { n:"MDXSet" },
186710x0888: { n:"MDXProp" },
186720x0889: { n:"MDXKPI" },
186730x088a: { n:"MDB" },
186740x088b: { n:"PLV" },
186750x088c: { n:"Compat12", f:parsebool, r:12 },
186760x088d: { n:"DXF" },
186770x088e: { n:"TableStyles", r:12 },
186780x088f: { n:"TableStyle" },
186790x0890: { n:"TableStyleElement" },
186800x0892: { n:"StyleExt" },
186810x0893: { n:"NamePublish" },
186820x0894: { n:"NameCmt", f:parse_NameCmt, r:12 },
186830x0895: { n:"SortData" },
186840x0896: { n:"Theme", f:parse_Theme, r:12 },
186850x0897: { n:"GUIDTypeLib" },
186860x0898: { n:"FnGrp12" },
186870x0899: { n:"NameFnGrp12" },
186880x089a: { n:"MTRSettings", f:parse_MTRSettings, r:12 },
186890x089b: { n:"CompressPictures", f:parsenoop2 },
186900x089c: { n:"HeaderFooter" },
186910x089d: { n:"CrtLayout12" },
186920x089e: { n:"CrtMlFrt" },
186930x089f: { n:"CrtMlFrtContinue" },
186940x08a3: { n:"ForceFullCalculation", f:parse_ForceFullCalculation },
186950x08a4: { n:"ShapePropsStream" },
186960x08a5: { n:"TextPropsStream" },
186970x08a6: { n:"RichTextStream" },
186980x08a7: { n:"CrtLayout12A" },
186990x1001: { n:"Units" },
187000x1002: { n:"Chart" },
187010x1003: { n:"Series" },
187020x1006: { n:"DataFormat" },
187030x1007: { n:"LineFormat" },
187040x1009: { n:"MarkerFormat" },
187050x100a: { n:"AreaFormat" },
187060x100b: { n:"PieFormat" },
187070x100c: { n:"AttachedLabel" },
187080x100d: { n:"SeriesText" },
187090x1014: { n:"ChartFormat" },
187100x1015: { n:"Legend" },
187110x1016: { n:"SeriesList" },
187120x1017: { n:"Bar" },
187130x1018: { n:"Line" },
187140x1019: { n:"Pie" },
187150x101a: { n:"Area" },
187160x101b: { n:"Scatter" },
187170x101c: { n:"CrtLine" },
187180x101d: { n:"Axis" },
187190x101e: { n:"Tick" },
187200x101f: { n:"ValueRange" },
187210x1020: { n:"CatSerRange" },
187220x1021: { n:"AxisLine" },
187230x1022: { n:"CrtLink" },
187240x1024: { n:"DefaultText" },
187250x1025: { n:"Text" },
187260x1026: { n:"FontX", f:parseuint16 },
187270x1027: { n:"ObjectLink" },
187280x1032: { n:"Frame" },
187290x1033: { n:"Begin" },
187300x1034: { n:"End" },
187310x1035: { n:"PlotArea" },
187320x103a: { n:"Chart3d" },
187330x103c: { n:"PicF" },
187340x103d: { n:"DropBar" },
187350x103e: { n:"Radar" },
187360x103f: { n:"Surf" },
187370x1040: { n:"RadarArea" },
187380x1041: { n:"AxisParent" },
187390x1043: { n:"LegendException" },
187400x1044: { n:"ShtProps", f:parse_ShtProps },
187410x1045: { n:"SerToCrt" },
187420x1046: { n:"AxesUsed" },
187430x1048: { n:"SBaseRef" },
187440x104a: { n:"SerParent" },
187450x104b: { n:"SerAuxTrend" },
187460x104e: { n:"IFmtRecord" },
187470x104f: { n:"Pos" },
187480x1050: { n:"AlRuns" },
187490x1051: { n:"BRAI" },
187500x105b: { n:"SerAuxErrBar" },
187510x105c: { n:"ClrtClient", f:parse_ClrtClient },
187520x105d: { n:"SerFmt" },
187530x105f: { n:"Chart3DBarShape" },
187540x1060: { n:"Fbi" },
187550x1061: { n:"BopPop" },
187560x1062: { n:"AxcExt" },
187570x1063: { n:"Dat" },
187580x1064: { n:"PlotGrowth" },
187590x1065: { n:"SIIndex" },
187600x1066: { n:"GelFrame" },
187610x1067: { n:"BopPopCustom" },
187620x1068: { n:"Fbi2" },
18763
187640x0000: { n:"Dimensions", f:parse_Dimensions },
187650x0002: { n:"BIFF2INT", f:parse_BIFF2INT },
187660x0005: { n:"BoolErr", f:parse_BoolErr },
187670x0007: { n:"String", f:parse_BIFF2STRING },
187680x0008: { n:"BIFF2ROW" },
187690x000b: { n:"Index" },
187700x0016: { n:"ExternCount", f:parseuint16 },
187710x001e: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
187720x001f: { n:"BIFF2FMTCNT" }, /* 16-bit cnt of BIFF2FORMAT records */
187730x0020: { n:"BIFF2COLINFO" },
187740x0021: { n:"Array", f:parse_Array },
187750x0025: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
187760x0032: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
187770x0034: { n:"DDEObjName" },
187780x003e: { n:"BIFF2WINDOW2" },
187790x0043: { n:"BIFF2XF" },
187800x0045: { n:"BIFF2FONTCLR" },
187810x0056: { n:"BIFF4FMTCNT" }, /* 16-bit cnt, similar to BIFF2 */
187820x007e: { n:"RK" }, /* Not necessarily same as 0x027e */
187830x007f: { n:"ImData", f:parse_ImData },
187840x0087: { n:"Addin" },
187850x0088: { n:"Edg" },
187860x0089: { n:"Pub" },
187870x0091: { n:"Sub" },
187880x0094: { n:"LHRecord" },
187890x0095: { n:"LHNGraph" },
187900x0096: { n:"Sound" },
187910x00a9: { n:"CoordList" },
187920x00ab: { n:"GCW" },
187930x00bc: { n:"ShrFmla" }, /* Not necessarily same as 0x04bc */
187940x00bf: { n:"ToolbarHdr" },
187950x00c0: { n:"ToolbarEnd" },
187960x00c2: { n:"AddMenu" },
187970x00c3: { n:"DelMenu" },
187980x00d6: { n:"RString", f:parse_RString },
187990x00df: { n:"UDDesc" },
188000x00ea: { n:"TabIdConf" },
188010x0162: { n:"XL5Modify" },
188020x01a5: { n:"FileSharing2" },
188030x0209: { n:'BOF', f:parse_BOF },
188040x0218: { n:"Lbl", f:parse_Lbl },
188050x0223: { n:"ExternName", f:parse_ExternName },
188060x0231: { n:"Font" },
188070x0243: { n:"BIFF3XF" },
188080x0409: { n:'BOF', f:parse_BOF },
188090x0443: { n:"BIFF4XF" },
188100x086d: { n:"FeatInfo" },
188110x0873: { n:"FeatInfo11" },
188120x0881: { n:"SXAddl12" },
188130x08c0: { n:"AutoWebPub" },
188140x08c1: { n:"ListObj" },
188150x08c2: { n:"ListField" },
188160x08c3: { n:"ListDV" },
188170x08c4: { n:"ListCondFmt" },
188180x08c5: { n:"ListCF" },
188190x08c6: { n:"FMQry" },
188200x08c7: { n:"FMSQry" },
188210x08c8: { n:"PLV" },
188220x08c9: { n:"LnExt" },
188230x08ca: { n:"MkrExt" },
188240x08cb: { n:"CrtCoopt" },
188250x08d6: { n:"FRTArchId$", r:12 },
18826
188270x7262: {}
18828};
18829
18830var XLSRE = evert_key(XLSRecordEnum, 'n');
18831function write_biff_rec(ba, type, payload, length) {
18832 var t = +type || +XLSRE[type];
18833 if(isNaN(t)) return;
18834 var len = length || (payload||[]).length || 0;
18835 var o = ba.next(4);
18836 o.write_shift(2, t);
18837 o.write_shift(2, len);
18838 if(len > 0 && is_buf(payload)) ba.push(payload);
18839}
18840
18841function write_BIFF2Cell(out, r, c) {
18842 if(!out) out = new_buf(7);
18843 out.write_shift(2, r);
18844 out.write_shift(2, c);
18845 out.write_shift(2, 0);
18846 out.write_shift(1, 0);
18847 return out;
18848}
18849
18850function write_BIFF2BERR(r, c, val, t) {
18851 var out = new_buf(9);
18852 write_BIFF2Cell(out, r, c);
18853 if(t == 'e') { out.write_shift(1, val); out.write_shift(1, 1); }
18854 else { out.write_shift(1, val?1:0); out.write_shift(1, 0); }
18855 return out;
18856}
18857
18858/* TODO: codepage, large strings */
18859function write_BIFF2LABEL(r, c, val) {
18860 var out = new_buf(8 + 2*val.length);
18861 write_BIFF2Cell(out, r, c);
18862 out.write_shift(1, val.length);
18863 out.write_shift(val.length, val, 'sbcs');
18864 return out.l < out.length ? out.slice(0, out.l) : out;
18865}
18866
18867function write_ws_biff2_cell(ba, cell, R, C) {
18868 if(cell.v != null) switch(cell.t) {
18869 case 'd': case 'n':
18870 var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
18871 if((v == (v|0)) && (v >= 0) && (v < 65536))
18872 write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
18873 else
18874 write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
18875 return;
18876 case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
18877 /* TODO: codepage, sst */
18878 case 's': case 'str':
18879 write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v));
18880 return;
18881 }
18882 write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
18883}
18884
18885function write_ws_biff2(ba, ws, idx, opts) {
18886 var dense = Array.isArray(ws);
18887 var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
18888 if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
18889 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
18890 range.e.c = Math.min(range.e.c, 0xFF);
18891 range.e.r = Math.min(range.e.c, 0x3FFF);
18892 ref = encode_range(range);
18893 }
18894 for(var R = range.s.r; R <= range.e.r; ++R) {
18895 rr = encode_row(R);
18896 for(var C = range.s.c; C <= range.e.c; ++C) {
18897 if(R === range.s.r) cols[C] = encode_col(C);
18898 ref = cols[C] + rr;
18899 var cell = dense ? (ws[R]||[])[C] : ws[ref];
18900 if(!cell) continue;
18901 /* write cell */
18902 write_ws_biff2_cell(ba, cell, R, C, opts);
18903 }
18904 }
18905}
18906
18907/* Based on test files */
18908function write_biff2_buf(wb, opts) {
18909 var o = opts || {};
18910 if(DENSE != null && o.dense == null) o.dense = DENSE;
18911 var ba = buf_array();
18912 var idx = 0;
18913 for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
18914 if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
18915 write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o));
18916 /* ... */
18917 write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
18918 /* ... */
18919 write_biff_rec(ba, 0x000A);
18920 return ba.end();
18921}
18922
18923function write_FONTS_biff8(ba, data, opts) {
18924 write_biff_rec(ba, "Font", write_Font({
18925 sz:12,
18926 color: {theme:1},
18927 name: "Arial",
18928 family: 2,
18929 scheme: "minor"
18930 }, opts));
18931}
18932
18933
18934function write_FMTS_biff8(ba, NF, opts) {
18935 if(!NF) return;
18936 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
18937for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts));
18938 });
18939}
18940
18941function write_FEAT(ba, ws) {
18942 /* [MS-XLS] 2.4.112 */
18943 var o = new_buf(19);
18944 o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
18945 o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
18946 write_biff_rec(ba, "FeatHdr", o);
18947 /* [MS-XLS] 2.4.111 */
18948 o = new_buf(39);
18949 o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0);
18950 o.write_shift(2, 3); o.write_shift(1, 0); o.write_shift(4, 0);
18951 o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0);
18952 write_Ref8U(safe_decode_range(ws['!ref']||"A1"), o);
18953 o.write_shift(4, 4);
18954 write_biff_rec(ba, "Feat", o);
18955}
18956
18957function write_CELLXFS_biff8(ba, opts) {
18958 for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts));
18959 opts.cellXfs.forEach(function(c) {
18960 write_biff_rec(ba, "XF", write_XF(c, 0, opts));
18961 });
18962}
18963
18964function write_ws_biff8_hlinks(ba, ws) {
18965 for(var R=0; R<ws['!links'].length; ++R) {
18966 var HL = ws['!links'][R];
18967 write_biff_rec(ba, "HLink", write_HLink(HL));
18968 if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
18969 }
18970 delete ws['!links'];
18971}
18972
18973function write_ws_biff8_cell(ba, cell, R, C, opts) {
18974 var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
18975 if(cell.v == null && !cell.bf) {
18976 write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
18977 return;
18978 }
18979 if(cell.bf) write_biff_rec(ba, "Formula", write_Formula(cell, R, C, opts, os));
18980 else switch(cell.t) {
18981 case 'd': case 'n':
18982 var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
18983 /* TODO: emit RK as appropriate */
18984 write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts));
18985 break;
18986 case 'b': case 'e':
18987 write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t));
18988 break;
18989 /* TODO: codepage, sst */
18990 case 's': case 'str':
18991 write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts));
18992 break;
18993 default:
18994 write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
18995 }
18996}
18997
18998/* [MS-XLS] 2.1.7.20.5 */
18999function write_ws_biff8(idx, opts, wb) {
19000 var ba = buf_array();
19001 var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
19002 var _WB = ((wb||{}).Workbook||{});
19003 var _sheet = ((_WB.Sheets||[])[idx]||{});
19004 var dense = Array.isArray(ws);
19005 var b8 = opts.biff == 8;
19006 var ref, rr = "", cols = [];
19007 var range = safe_decode_range(ws['!ref'] || "A1");
19008 var MAX_ROWS = b8 ? 65536 : 16384;
19009 if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
19010 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
19011 range.e.c = Math.min(range.e.c, 0xFF);
19012 range.e.r = Math.min(range.e.c, MAX_ROWS-1);
19013 }
19014
19015 write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
19016 /* [Uncalced] Index */
19017 write_biff_rec(ba, "CalcMode", writeuint16(1));
19018 write_biff_rec(ba, "CalcCount", writeuint16(100));
19019 write_biff_rec(ba, "CalcRefMode", writebool(true));
19020 write_biff_rec(ba, "CalcIter", writebool(false));
19021 write_biff_rec(ba, "CalcDelta", write_Xnum(0.001));
19022 write_biff_rec(ba, "CalcSaveRecalc", writebool(true));
19023 write_biff_rec(ba, "PrintRowCol", writebool(false));
19024 write_biff_rec(ba, "PrintGrid", writebool(false));
19025 write_biff_rec(ba, "GridSet", writeuint16(1));
19026 write_biff_rec(ba, "Guts", write_Guts([0,0]));
19027 /* DefaultRowHeight WsBool [Sync] [LPr] [HorizontalPageBreaks] [VerticalPageBreaks] */
19028 /* Header (string) */
19029 /* Footer (string) */
19030 write_biff_rec(ba, "HCenter", writebool(false));
19031 write_biff_rec(ba, "VCenter", writebool(false));
19032 /* ... */
19033 write_biff_rec(ba, 0x200, write_Dimensions(range, opts));
19034 /* ... */
19035
19036 if(b8) ws['!links'] = [];
19037 for(var R = range.s.r; R <= range.e.r; ++R) {
19038 rr = encode_row(R);
19039 for(var C = range.s.c; C <= range.e.c; ++C) {
19040 if(R === range.s.r) cols[C] = encode_col(C);
19041 ref = cols[C] + rr;
19042 var cell = dense ? (ws[R]||[])[C] : ws[ref];
19043 if(!cell) continue;
19044 /* write cell */
19045 write_ws_biff8_cell(ba, cell, R, C, opts);
19046 if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
19047 }
19048 }
19049 var cname = _sheet.CodeName || _sheet.name || s;
19050 /* ... */
19051 if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0]));
19052 /* ... */
19053 if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']));
19054 /* [LRng] *QUERYTABLE [PHONETICINFO] CONDFMTS */
19055 if(b8) write_ws_biff8_hlinks(ba, ws);
19056 /* [DVAL] */
19057 write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
19058 /* *WebPub *CellWatch [SheetExt] */
19059 if(b8) write_FEAT(ba, ws);
19060 /* *FEAT11 *RECORD12 */
19061 write_biff_rec(ba, "EOF");
19062 return ba.end();
19063}
19064
19065/* [MS-XLS] 2.1.7.20.3 */
19066function write_biff8_global(wb, bufs, opts) {
19067 var A = buf_array();
19068 var _WB = ((wb||{}).Workbook||{});
19069 var _sheets = (_WB.Sheets||[]);
19070 var _wb = _WB.WBProps||{};
19071 var b8 = opts.biff == 8, b5 = opts.biff == 5;
19072 write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
19073 if(opts.bookType == "xla") write_biff_rec(A, "Addin");
19074 write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null);
19075 write_biff_rec(A, "Mms", writezeroes(2));
19076 if(b5) write_biff_rec(A, "ToolbarHdr");
19077 if(b5) write_biff_rec(A, "ToolbarEnd");
19078 write_biff_rec(A, "InterfaceEnd");
19079 write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
19080 /* [FileSharing] */
19081 write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4));
19082 /* *2047 Lel */
19083 if(b8) write_biff_rec(A, "DSF", writeuint16(0));
19084 if(b8) write_biff_rec(A, "Excel9File");
19085 write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
19086 if(b8 && wb.vbaraw) write_biff_rec(A, "ObProj");
19087 /* [ObNoMacros] */
19088 if(b8 && wb.vbaraw) {
19089 var cname = _wb.CodeName || "ThisWorkbook";
19090 write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts));
19091 }
19092 write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11));
19093 /* *FnGroupName *FnGrp12 */
19094 /* *Lbl */
19095 /* [OleObjectSize] */
19096 write_biff_rec(A, "WinProtect", writebool(false));
19097 write_biff_rec(A, "Protect", writebool(false));
19098 write_biff_rec(A, "Password", writeuint16(0));
19099 if(b8) write_biff_rec(A, "Prot4Rev", writebool(false));
19100 if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0));
19101 write_biff_rec(A, "Window1", write_Window1(opts));
19102 write_biff_rec(A, "Backup", writebool(false));
19103 write_biff_rec(A, "HideObj", writeuint16(0));
19104 write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true"));
19105 write_biff_rec(A, "CalcPrecision", writebool(true));
19106 if(b8) write_biff_rec(A, "RefreshAll", writebool(false));
19107 write_biff_rec(A, "BookBool", writeuint16(0));
19108 /* ... */
19109 write_FONTS_biff8(A, wb, opts);
19110 write_FMTS_biff8(A, wb.SSF, opts);
19111 write_CELLXFS_biff8(A, opts);
19112 /* ... */
19113 if(b8) write_biff_rec(A, "UsesELFs", writebool(false));
19114 var a = A.end();
19115
19116 var C = buf_array();
19117 /* METADATA [MTRSettings] [ForceFullCalculation] */
19118 if(b8) write_biff_rec(C, "Country", write_Country());
19119 /* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture *MSODRAWINGGROUP */
19120 /* BIFF8: [SST *Continue] ExtSST */
19121 /* *WebPub [WOpt] [CrErr] [BookExt] *FeatHdr *DConn [THEME] [CompressPictures] [Compat12] [GUIDTypeLib] */
19122 write_biff_rec(C, "EOF");
19123 var c = C.end();
19124
19125 var B = buf_array();
19126 var blen = 0, j = 0;
19127 for(j = 0; j < wb.SheetNames.length; ++j) blen += (b8 ? 12 : 11) + (b8 ? 2 : 1) * wb.SheetNames[j].length;
19128 var start = a.length + blen + c.length;
19129 for(j = 0; j < wb.SheetNames.length; ++j) {
19130 var _sheet = _sheets[j] || ({});
19131 write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts));
19132 start += bufs[j].length;
19133 }
19134 /* 1*BoundSheet8 */
19135 var b = B.end();
19136 if(blen != b.length) throw new Error("BS8 " + blen + " != " + b.length);
19137
19138 var out = [];
19139 if(a.length) out.push(a);
19140 if(b.length) out.push(b);
19141 if(c.length) out.push(c);
19142 return __toBuffer([out]);
19143}
19144
19145/* [MS-XLS] 2.1.7.20 Workbook Stream */
19146function write_biff8_buf(wb, opts) {
19147 var o = opts || {};
19148 var bufs = [];
19149
19150 if(wb && !wb.SSF) {
19151 wb.SSF = SSF.get_table();
19152 }
19153 if(wb && wb.SSF) {
19154 make_ssf(SSF); SSF.load_table(wb.SSF);
19155 // $FlowIgnore
19156 o.revssf = evert_num(wb.SSF); o.revssf[wb.SSF[65535]] = 0;
19157 o.ssf = wb.SSF;
19158 }
19159
19160 o.Strings = []; o.Strings.Count = 0; o.Strings.Unique = 0;
19161 fix_write_opts(o);
19162
19163 o.cellXfs = [];
19164 get_cell_style(o.cellXfs, {}, {revssf:{"General":0}});
19165
19166 if(!wb.Props) wb.Props = {};
19167
19168 for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb);
19169 bufs.unshift(write_biff8_global(wb, bufs, o));
19170 return __toBuffer([bufs]);
19171}
19172
19173function write_biff_buf(wb, opts) {
19174 var o = opts || {};
19175 switch(o.biff || 2) {
19176 case 8: case 5: return write_biff8_buf(wb, opts);
19177 case 4: case 3: case 2: return write_biff2_buf(wb, opts);
19178 }
19179 throw new Error("invalid type " + o.bookType + " for BIFF");
19180}
19181/* note: browser DOM element cannot see mso- style attrs, must parse */
19182var HTML_ = (function() {
19183 function html_to_sheet(str, _opts) {
19184 var opts = _opts || {};
19185 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
19186 var ws = opts.dense ? ([]) : ({});
19187 str = str.replace(/<!--.*?-->/g, "");
19188 var mtch = str.match(/<table/i);
19189 if(!mtch) throw new Error("Invalid HTML: could not find <table>");
19190 var mtch2 = str.match(/<\/table/i);
19191 var i = mtch.index, j = mtch2 && mtch2.index || str.length;
19192 var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
19193 var R = -1, C = 0, RS = 0, CS = 0;
19194 var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
19195 var merges = [];
19196 for(i = 0; i < rows.length; ++i) {
19197 var row = rows[i].trim();
19198 var hd = row.slice(0,3).toLowerCase();
19199 if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
19200 if(hd != "<td" && hd != "<th") continue;
19201 var cells = row.split(/<\/t[dh]>/i);
19202 for(j = 0; j < cells.length; ++j) {
19203 var cell = cells[j].trim();
19204 if(!cell.match(/<t[dh]/i)) continue;
19205 var m = cell, cc = 0;
19206 /* TODO: parse styles etc */
19207 while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
19208 for(var midx = 0; midx < merges.length; ++midx) {
19209 var _merge = merges[midx];
19210 if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; }
19211 }
19212 var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
19213 CS = tag.colspan ? +tag.colspan : 1;
19214 if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
19215 var _t = tag.t || "";
19216 /* TODO: generate stub cells */
19217 if(!m.length) { C += CS; continue; }
19218 m = htmldecode(m);
19219 if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
19220 if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
19221 if(!m.length) continue;
19222 var o = {t:'s', v:m};
19223 if(opts.raw || !m.trim().length || _t == 's'){}
19224 else if(m === 'TRUE') o = {t:'b', v:true};
19225 else if(m === 'FALSE') o = {t:'b', v:false};
19226 else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
19227 else if(!isNaN(fuzzydate(m).getDate())) {
19228 o = ({t:'d', v:parseDate(m)});
19229 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
19230 o.z = opts.dateNF || SSF._table[14];
19231 }
19232 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
19233 else ws[encode_cell({r:R, c:C})] = o;
19234 C += CS;
19235 }
19236 }
19237 ws['!ref'] = encode_range(range);
19238 if(merges.length) ws["!merges"] = merges;
19239 return ws;
19240 }
19241 function html_to_book(str, opts) {
19242 return sheet_to_workbook(html_to_sheet(str, opts), opts);
19243 }
19244 function make_html_row(ws, r, R, o) {
19245 var M = (ws['!merges'] ||[]);
19246 var oo = [];
19247 for(var C = r.s.c; C <= r.e.c; ++C) {
19248 var RS = 0, CS = 0;
19249 for(var j = 0; j < M.length; ++j) {
19250 if(M[j].s.r > R || M[j].s.c > C) continue;
19251 if(M[j].e.r < R || M[j].e.c < C) continue;
19252 if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
19253 RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
19254 }
19255 if(RS < 0) continue;
19256 var coord = encode_cell({r:R,c:C});
19257 var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
19258 /* TODO: html entities */
19259 var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
19260 var sp = ({});
19261 if(RS > 1) sp.rowspan = RS;
19262 if(CS > 1) sp.colspan = CS;
19263 sp.t = cell && cell.t || 'z';
19264 if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
19265 sp.id = (o.id || "sjs") + "-" + coord;
19266 oo.push(writextag('td', w, sp));
19267 }
19268 var preamble = "<tr>";
19269 return preamble + oo.join("") + "</tr>";
19270 }
19271 function make_html_preamble(ws, R, o) {
19272 var out = [];
19273 return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
19274 }
19275 var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
19276 var _END = '</body></html>';
19277 function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
19278 var o = opts || {};
19279 var header = o.header != null ? o.header : _BEGIN;
19280 var footer = o.footer != null ? o.footer : _END;
19281 var out = [header];
19282 var r = decode_range(ws['!ref']);
19283 o.dense = Array.isArray(ws);
19284 out.push(make_html_preamble(ws, r, o));
19285 for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
19286 out.push("</table>" + footer);
19287 return out.join("");
19288 }
19289
19290 return {
19291 to_workbook: html_to_book,
19292 to_sheet: html_to_sheet,
19293 _row: make_html_row,
19294 BEGIN: _BEGIN,
19295 END: _END,
19296 _preamble: make_html_preamble,
19297 from_sheet: sheet_to_html
19298 };
19299})();
19300
19301function parse_dom_table(table, _opts) {
19302 var opts = _opts || {};
19303 if(DENSE != null) opts.dense = DENSE;
19304 var ws = opts.dense ? ([]) : ({});
19305 var rows = table.getElementsByTagName('tr');
19306 var sheetRows = opts.sheetRows || 10000000;
19307 var range = {s:{r:0,c:0},e:{r:0,c:0}};
19308 var merges = [], midx = 0;
19309 var rowinfo = [];
19310 var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
19311 for(; _R < rows.length && R < sheetRows; ++_R) {
19312 var row = rows[_R];
19313 if (is_dom_element_hidden(row)) {
19314 if (opts.display) continue;
19315 rowinfo[R] = {hidden: true};
19316 }
19317 var elts = (row.children);
19318 for(_C = C = 0; _C < elts.length; ++_C) {
19319 var elt = elts[_C];
19320 if (opts.display && is_dom_element_hidden(elt)) continue;
19321 var v = htmldecode(elt.innerHTML);
19322 for(midx = 0; midx < merges.length; ++midx) {
19323 var m = merges[midx];
19324 if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
19325 }
19326 /* TODO: figure out how to extract nonstandard mso- style */
19327 CS = +elt.getAttribute("colspan") || 1;
19328 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}});
19329 var o = {t:'s', v:v};
19330 var _t = elt.getAttribute("t") || "";
19331 if(v != null) {
19332 if(v.length == 0) o.t = _t || 'z';
19333 else if(opts.raw || v.trim().length == 0 || _t == "s"){}
19334 else if(v === 'TRUE') o = {t:'b', v:true};
19335 else if(v === 'FALSE') o = {t:'b', v:false};
19336 else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
19337 else if(!isNaN(fuzzydate(v).getDate())) {
19338 o = ({t:'d', v:parseDate(v)});
19339 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
19340 o.z = opts.dateNF || SSF._table[14];
19341 }
19342 }
19343 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
19344 else ws[encode_cell({c:C, r:R})] = o;
19345 if(range.e.c < C) range.e.c = C;
19346 C += CS;
19347 }
19348 ++R;
19349 }
19350 if(merges.length) ws['!merges'] = merges;
19351 if(rowinfo.length) ws['!rows'] = rowinfo;
19352 range.e.r = R - 1;
19353 ws['!ref'] = encode_range(range);
19354 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
19355 return ws;
19356}
19357
19358function table_to_book(table, opts) {
19359 return sheet_to_workbook(parse_dom_table(table, opts), opts);
19360}
19361
19362function is_dom_element_hidden(element) {
19363 var display = '';
19364 var get_computed_style = get_get_computed_style_function(element);
19365 if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
19366 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)
19367 return display === 'none';
19368}
19369
19370/* global getComputedStyle */
19371function get_get_computed_style_function(element) {
19372 // The proper getComputedStyle implementation is the one defined in the element window
19373 if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
19374 // If it is not available, try to get one from the global namespace
19375 if(typeof getComputedStyle === 'function') return getComputedStyle;
19376 return null;
19377}
19378/* OpenDocument */
19379var parse_content_xml = (function() {
19380
19381 var parse_text_p = function(text) {
19382 /* 6.1.2 White Space Characters */
19383 var fixed = text
19384 .replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
19385 .replace(/<text:s\/>/g," ")
19386 .replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
19387 .replace(/<text:tab[^>]*\/>/g,"\t")
19388 .replace(/<text:line-break\/>/g,"\n");
19389 var v = unescapexml(fixed.replace(/<[^>]*>/g,""));
19390
19391 return [v];
19392 };
19393
19394 var number_formats = {
19395 /* ods name: [short ssf fmt, long ssf fmt] */
19396 day: ["d", "dd"],
19397 month: ["m", "mm"],
19398 year: ["y", "yy"],
19399 hours: ["h", "hh"],
19400 minutes: ["m", "mm"],
19401 seconds: ["s", "ss"],
19402 "am-pm": ["A/P", "AM/PM"],
19403 "day-of-week": ["ddd", "dddd"],
19404 era: ["e", "ee"],
19405 /* there is no native representation of LO "Q" format */
19406 quarter: ["\\Qm", "m\\\"th quarter\""]
19407 };
19408
19409 return function pcx(d, _opts) {
19410 var opts = _opts || {};
19411 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
19412 var str = xlml_normalize(d);
19413 var state = [], tmp;
19414 var tag;
19415 var NFtag = {name:""}, NF = "", pidx = 0;
19416 var sheetag;
19417 var rowtag;
19418 var Sheets = {}, SheetNames = [];
19419 var ws = opts.dense ? ([]) : ({});
19420 var Rn, q;
19421 var ctag = ({value:""});
19422 var textp = "", textpidx = 0, textptag;
19423 var textR = [];
19424 var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
19425 var row_ol = 0;
19426 var number_format_map = {};
19427 var merges = [], mrange = {}, mR = 0, mC = 0;
19428 var rowinfo = [], rowpeat = 1, colpeat = 1;
19429 var arrayf = [];
19430 var WB = {Names:[]};
19431 var atag = ({});
19432 var _Ref = ["", ""];
19433 var comments = [], comment = ({});
19434 var creator = "", creatoridx = 0;
19435 var isstub = false, intable = false;
19436 var i = 0;
19437 xlmlregex.lastIndex = 0;
19438 str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
19439 while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
19440
19441 case 'table': case '工作表': // 9.1.2 <table:table>
19442 if(Rn[1]==='/') {
19443 if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
19444 if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
19445 ws['!fullref'] = ws['!ref'];
19446 range.e.r = opts.sheetRows - 1;
19447 ws['!ref'] = encode_range(range);
19448 }
19449 if(merges.length) ws['!merges'] = merges;
19450 if(rowinfo.length) ws["!rows"] = rowinfo;
19451 sheetag.name = sheetag['名称'] || sheetag.name;
19452 if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
19453 SheetNames.push(sheetag.name);
19454 Sheets[sheetag.name] = ws;
19455 intable = false;
19456 }
19457 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
19458 sheetag = parsexmltag(Rn[0], false);
19459 R = C = -1;
19460 range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
19461 ws = opts.dense ? ([]) : ({}); merges = [];
19462 rowinfo = [];
19463 intable = true;
19464 }
19465 break;
19466
19467 case 'table-row-group': // 9.1.9 <table:table-row-group>
19468 if(Rn[1] === "/") --row_ol; else ++row_ol;
19469 break;
19470 case 'table-row': case '行': // 9.1.3 <table:table-row>
19471 if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
19472 rowtag = parsexmltag(Rn[0], false);
19473 if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
19474 rowpeat = +rowtag['number-rows-repeated'] || 1;
19475 /* TODO: remove magic */
19476 if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
19477 C = -1; break;
19478 case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
19479 if(Rn[1] !== '/') ++C;
19480 if(opts.sheetStubs) {
19481 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
19482 else ws[encode_cell({r:R,c:C})] = {t:'z'};
19483 }
19484 textp = ""; textR = [];
19485 break; /* stub */
19486 case 'table-cell': case '数据':
19487 if(Rn[0].charAt(Rn[0].length-2) === '/') {
19488 ++C;
19489 ctag = parsexmltag(Rn[0], false);
19490 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19491 q = ({t:'z', v:null});
19492 if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
19493 if((ctag['数据类型'] || ctag['value-type']) == "string") {
19494 q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
19495 if(opts.dense) {
19496 if(!ws[R]) ws[R] = [];
19497 ws[R][C] = q;
19498 } else {
19499 ws[encode_cell({r:R,c:C})] = q;
19500 }
19501 }
19502 C+= colpeat-1;
19503 } else if(Rn[1]!=='/') {
19504 ++C;
19505 colpeat = 1;
19506 var rptR = rowpeat ? R + rowpeat - 1 : R;
19507 if(C > range.e.c) range.e.c = C;
19508 if(C < range.s.c) range.s.c = C;
19509 if(R < range.s.r) range.s.r = R;
19510 if(rptR > range.e.r) range.e.r = rptR;
19511 ctag = parsexmltag(Rn[0], false);
19512 comments = []; comment = ({});
19513 q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
19514 if(opts.cellFormula) {
19515 if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
19516 if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
19517 mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
19518 mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
19519 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
19520 q.F = encode_range(mrange);
19521 arrayf.push([mrange, q.F]);
19522 }
19523 if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
19524 else for(i = 0; i < arrayf.length; ++i)
19525 if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
19526 if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
19527 q.F = arrayf[i][1];
19528 }
19529 if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
19530 mR = parseInt(ctag['number-rows-spanned'],10) || 0;
19531 mC = parseInt(ctag['number-columns-spanned'],10) || 0;
19532 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
19533 merges.push(mrange);
19534 }
19535
19536 /* 19.675.2 table:number-columns-repeated */
19537 if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
19538
19539 /* 19.385 office:value-type */
19540 switch(q.t) {
19541 case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
19542 case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19543 case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19544 case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19545 case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
19546 if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
19547 q.z = 'm/d/yy'; break;
19548 case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
19549 case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
19550 default:
19551 if(q.t === 'string' || q.t === 'text' || !q.t) {
19552 q.t = 's';
19553 if(ctag['string-value'] != null) { textp = unescapexml(ctag['string-value']); textR = []; }
19554 } else throw new Error('Unsupported value type ' + q.t);
19555 }
19556 } else {
19557 isstub = false;
19558 if(q.t === 's') {
19559 q.v = textp || '';
19560 if(textR.length) q.R = textR;
19561 isstub = textpidx == 0;
19562 }
19563 if(atag.Target) q.l = atag;
19564 if(comments.length > 0) { q.c = comments; comments = []; }
19565 if(textp && opts.cellText !== false) q.w = textp;
19566 if(!isstub || opts.sheetStubs) {
19567 if(!(opts.sheetRows && opts.sheetRows <= R)) {
19568 for(var rpt = 0; rpt < rowpeat; ++rpt) {
19569 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19570 if(opts.dense) {
19571 if(!ws[R + rpt]) ws[R + rpt] = [];
19572 ws[R + rpt][C] = rpt == 0 ? q : dup(q);
19573 while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
19574 } else {
19575 ws[encode_cell({r:R + rpt,c:C})] = q;
19576 while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
19577 }
19578 if(range.e.c <= C) range.e.c = C;
19579 }
19580 }
19581 }
19582 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19583 C += colpeat-1; colpeat = 0;
19584 q = {};
19585 textp = ""; textR = [];
19586 }
19587 atag = ({});
19588 break; // 9.1.4 <table:table-cell>
19589
19590 /* pure state */
19591 case 'document': // TODO: <office:document> is the root for FODS
19592 case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
19593 case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
19594 case 'scripts': // 3.12 <office:scripts>
19595 case 'styles': // TODO <office:styles>
19596 case 'font-face-decls': // 3.14 <office:font-face-decls>
19597 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
19598 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
19599 break;
19600
19601 case 'annotation': // 14.1 <office:annotation>
19602 if(Rn[1]==='/'){
19603 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
19604 comment.t = textp;
19605 if(textR.length) comment.R = textR;
19606 comment.a = creator;
19607 comments.push(comment);
19608 }
19609 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
19610 creator = ""; creatoridx = 0;
19611 textp = ""; textpidx = 0; textR = [];
19612 break;
19613
19614 case 'creator': // 4.3.2.7 <dc:creator>
19615 if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
19616 else creatoridx = Rn.index + Rn[0].length;
19617 break;
19618
19619 /* ignore state */
19620 case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
19621 case 'settings': // TODO: <office:settings>
19622 case 'config-item-set': // TODO: <office:config-item-set>
19623 case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
19624 case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
19625 case 'config-item-map-named': // TODO: <office:config-item-map-entry>
19626 case 'shapes': // 9.2.8 <table:shapes>
19627 case 'frame': // 10.4.2 <draw:frame>
19628 case 'text-box': // 10.4.3 <draw:text-box>
19629 case 'image': // 10.4.4 <draw:image>
19630 case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
19631 case 'list-style': // 16.30 <text:list-style>
19632 case 'form': // 13.13 <form:form>
19633 case 'dde-links': // 9.8 <table:dde-links>
19634 case 'event-listeners': // TODO
19635 case 'chart': // TODO
19636 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
19637 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
19638 textp = ""; textpidx = 0; textR = [];
19639 break;
19640
19641 case 'scientific-number': // TODO: <number:scientific-number>
19642 break;
19643 case 'currency-symbol': // TODO: <number:currency-symbol>
19644 break;
19645 case 'currency-style': // TODO: <number:currency-style>
19646 break;
19647 case 'number-style': // 16.27.2 <number:number-style>
19648 case 'percentage-style': // 16.27.9 <number:percentage-style>
19649 case 'date-style': // 16.27.10 <number:date-style>
19650 case 'time-style': // 16.27.18 <number:time-style>
19651 if(Rn[1]==='/'){
19652 number_format_map[NFtag.name] = NF;
19653 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
19654 } else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
19655 NF = "";
19656 NFtag = parsexmltag(Rn[0], false);
19657 state.push([Rn[3], true]);
19658 } break;
19659
19660 case 'script': break; // 3.13 <office:script>
19661 case 'libraries': break; // TODO: <ooo:libraries>
19662 case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
19663 case 'master-styles': break; // TODO: <office:master-styles>
19664
19665 case 'default-style': // TODO: <style:default-style>
19666 case 'page-layout': break; // TODO: <style:page-layout>
19667 case 'style': // 16.2 <style:style>
19668 break;
19669 case 'map': break; // 16.3 <style:map>
19670 case 'font-face': break; // 16.21 <style:font-face>
19671
19672 case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
19673 case 'table-properties': break; // 17.15 <style:table-properties>
19674 case 'table-column-properties': break; // 17.16 <style:table-column-properties>
19675 case 'table-row-properties': break; // 17.17 <style:table-row-properties>
19676 case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
19677
19678 case 'number': // 16.27.3 <number:number>
19679 switch(state[state.length-1][0]) {
19680 case 'time-style':
19681 case 'date-style':
19682 tag = parsexmltag(Rn[0], false);
19683 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
19684 } break;
19685
19686 case 'fraction': break; // TODO 16.27.6 <number:fraction>
19687
19688 case 'day': // 16.27.11 <number:day>
19689 case 'month': // 16.27.12 <number:month>
19690 case 'year': // 16.27.13 <number:year>
19691 case 'era': // 16.27.14 <number:era>
19692 case 'day-of-week': // 16.27.15 <number:day-of-week>
19693 case 'week-of-year': // 16.27.16 <number:week-of-year>
19694 case 'quarter': // 16.27.17 <number:quarter>
19695 case 'hours': // 16.27.19 <number:hours>
19696 case 'minutes': // 16.27.20 <number:minutes>
19697 case 'seconds': // 16.27.21 <number:seconds>
19698 case 'am-pm': // 16.27.22 <number:am-pm>
19699 switch(state[state.length-1][0]) {
19700 case 'time-style':
19701 case 'date-style':
19702 tag = parsexmltag(Rn[0], false);
19703 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
19704 } break;
19705
19706 case 'boolean-style': break; // 16.27.23 <number:boolean-style>
19707 case 'boolean': break; // 16.27.24 <number:boolean>
19708 case 'text-style': break; // 16.27.25 <number:text-style>
19709 case 'text': // 16.27.26 <number:text>
19710 if(Rn[0].slice(-2) === "/>") break;
19711 else if(Rn[1]==="/") switch(state[state.length-1][0]) {
19712 case 'number-style':
19713 case 'date-style':
19714 case 'time-style':
19715 NF += str.slice(pidx, Rn.index);
19716 break;
19717 }
19718 else pidx = Rn.index + Rn[0].length;
19719 break;
19720
19721 case 'named-range': // 9.4.12 <table:named-range>
19722 tag = parsexmltag(Rn[0], false);
19723 _Ref = ods_to_csf_3D(tag['cell-range-address']);
19724 var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
19725 if(intable) nrange.Sheet = SheetNames.length;
19726 WB.Names.push(nrange);
19727 break;
19728
19729 case 'text-content': break; // 16.27.27 <number:text-content>
19730 case 'text-properties': break; // 16.27.27 <style:text-properties>
19731 case 'embedded-text': break; // 16.27.4 <number:embedded-text>
19732
19733 case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
19734
19735 case 'forms': break; // 12.25.2 13.2
19736 case 'table-column': break; // 9.1.6 <table:table-column>
19737 case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
19738 case 'table-rows': break; // 9.1.12 <table:table-rows>
19739 /* TODO: outline levels */
19740 case 'table-column-group': break; // 9.1.10 <table:table-column-group>
19741 case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
19742 case 'table-columns': break; // 9.1.12 <table:table-columns>
19743
19744 case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
19745
19746 case 'graphic-properties': break; // 17.21 <style:graphic-properties>
19747 case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
19748 case 'named-expressions': break; // 9.4.11 <table:named-expressions>
19749 case 'label-range': break; // 9.4.9 <table:label-range>
19750 case 'label-ranges': break; // 9.4.10 <table:label-ranges>
19751 case 'named-expression': break; // 9.4.13 <table:named-expression>
19752 case 'sort': break; // 9.4.19 <table:sort>
19753 case 'sort-by': break; // 9.4.20 <table:sort-by>
19754 case 'sort-groups': break; // 9.4.22 <table:sort-groups>
19755
19756 case 'tab': break; // 6.1.4 <text:tab>
19757 case 'line-break': break; // 6.1.5 <text:line-break>
19758 case 'span': break; // 6.1.7 <text:span>
19759 case 'p': case '文本串': // 5.1.3 <text:p>
19760 if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) {
19761 var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
19762 textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0];
19763 } else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
19764 break; // <text:p>
19765 case 's': break; // <text:s>
19766
19767 case 'database-range': // 9.4.15 <table:database-range>
19768 if(Rn[1]==='/') break;
19769 try {
19770 _Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
19771 Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
19772 } catch(e) {/* empty */}
19773 break;
19774
19775 case 'date': break; // <*:date>
19776
19777 case 'object': break; // 10.4.6.2 <draw:object>
19778 case 'title': case '标题': break; // <*:title> OR <uof:标题>
19779 case 'desc': break; // <*:desc>
19780 case 'binary-data': break; // 10.4.5 TODO: b64 blob
19781
19782 /* 9.2 Advanced Tables */
19783 case 'table-source': break; // 9.2.6
19784 case 'scenario': break; // 9.2.6
19785
19786 case 'iteration': break; // 9.4.3 <table:iteration>
19787 case 'content-validations': break; // 9.4.4 <table:
19788 case 'content-validation': break; // 9.4.5 <table:
19789 case 'help-message': break; // 9.4.6 <table:
19790 case 'error-message': break; // 9.4.7 <table:
19791 case 'database-ranges': break; // 9.4.14 <table:database-ranges>
19792 case 'filter': break; // 9.5.2 <table:filter>
19793 case 'filter-and': break; // 9.5.3 <table:filter-and>
19794 case 'filter-or': break; // 9.5.4 <table:filter-or>
19795 case 'filter-condition': break; // 9.5.5 <table:filter-condition>
19796
19797 case 'list-level-style-bullet': break; // 16.31 <text:
19798 case 'list-level-style-number': break; // 16.32 <text:
19799 case 'list-level-properties': break; // 17.19 <style:
19800
19801 /* 7.3 Document Fields */
19802 case 'sender-firstname': // 7.3.6.2
19803 case 'sender-lastname': // 7.3.6.3
19804 case 'sender-initials': // 7.3.6.4
19805 case 'sender-title': // 7.3.6.5
19806 case 'sender-position': // 7.3.6.6
19807 case 'sender-email': // 7.3.6.7
19808 case 'sender-phone-private': // 7.3.6.8
19809 case 'sender-fax': // 7.3.6.9
19810 case 'sender-company': // 7.3.6.10
19811 case 'sender-phone-work': // 7.3.6.11
19812 case 'sender-street': // 7.3.6.12
19813 case 'sender-city': // 7.3.6.13
19814 case 'sender-postal-code': // 7.3.6.14
19815 case 'sender-country': // 7.3.6.15
19816 case 'sender-state-or-province': // 7.3.6.16
19817 case 'author-name': // 7.3.7.1
19818 case 'author-initials': // 7.3.7.2
19819 case 'chapter': // 7.3.8
19820 case 'file-name': // 7.3.9
19821 case 'template-name': // 7.3.9
19822 case 'sheet-name': // 7.3.9
19823 break;
19824
19825 case 'event-listener':
19826 break;
19827 /* TODO: FODS Properties */
19828 case 'initial-creator':
19829 case 'creation-date':
19830 case 'print-date':
19831 case 'generator':
19832 case 'document-statistic':
19833 case 'user-defined':
19834 case 'editing-duration':
19835 case 'editing-cycles':
19836 break;
19837
19838 /* TODO: FODS Config */
19839 case 'config-item':
19840 break;
19841
19842 /* TODO: style tokens */
19843 case 'page-number': break; // TODO <text:page-number>
19844 case 'page-count': break; // TODO <text:page-count>
19845 case 'time': break; // TODO <text:time>
19846
19847 /* 9.3 Advanced Table Cells */
19848 case 'cell-range-source': break; // 9.3.1 <table:
19849 case 'detective': break; // 9.3.2 <table:
19850 case 'operation': break; // 9.3.3 <table:
19851 case 'highlighted-range': break; // 9.3.4 <table:
19852
19853 /* 9.6 Data Pilot Tables <table: */
19854 case 'data-pilot-table': // 9.6.3
19855 case 'source-cell-range': // 9.6.5
19856 case 'source-service': // 9.6.6
19857 case 'data-pilot-field': // 9.6.7
19858 case 'data-pilot-level': // 9.6.8
19859 case 'data-pilot-subtotals': // 9.6.9
19860 case 'data-pilot-subtotal': // 9.6.10
19861 case 'data-pilot-members': // 9.6.11
19862 case 'data-pilot-member': // 9.6.12
19863 case 'data-pilot-display-info': // 9.6.13
19864 case 'data-pilot-sort-info': // 9.6.14
19865 case 'data-pilot-layout-info': // 9.6.15
19866 case 'data-pilot-field-reference': // 9.6.16
19867 case 'data-pilot-groups': // 9.6.17
19868 case 'data-pilot-group': // 9.6.18
19869 case 'data-pilot-group-member': // 9.6.19
19870 break;
19871
19872 /* 10.3 Drawing Shapes */
19873 case 'rect': // 10.3.2
19874 break;
19875
19876 /* 14.6 DDE Connections */
19877 case 'dde-connection-decls': // 14.6.2 <text:
19878 case 'dde-connection-decl': // 14.6.3 <text:
19879 case 'dde-link': // 14.6.4 <table:
19880 case 'dde-source': // 14.6.5 <office:
19881 break;
19882
19883 case 'properties': break; // 13.7 <form:properties>
19884 case 'property': break; // 13.8 <form:property>
19885
19886 case 'a': // 6.1.8 hyperlink
19887 if(Rn[1]!== '/') {
19888 atag = parsexmltag(Rn[0], false);
19889 if(!atag.href) break;
19890 atag.Target = atag.href; delete atag.href;
19891 if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
19892 _Ref = ods_to_csf_3D(atag.Target.slice(1));
19893 atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
19894 }
19895 }
19896 break;
19897
19898 /* non-standard */
19899 case 'table-protection': break;
19900 case 'data-pilot-grand-total': break; // <table:
19901 case 'office-document-common-attrs': break; // bare
19902 default: switch(Rn[2]) {
19903 case 'dc:': // TODO: properties
19904 case 'calcext:': // ignore undocumented extensions
19905 case 'loext:': // ignore undocumented extensions
19906 case 'ooo:': // ignore undocumented extensions
19907 case 'chartooo:': // ignore undocumented extensions
19908 case 'draw:': // TODO: drawing
19909 case 'style:': // TODO: styles
19910 case 'chart:': // TODO: charts
19911 case 'form:': // TODO: forms
19912 case 'uof:': // TODO: uof
19913 case '表:': // TODO: uof
19914 case '字:': // TODO: uof
19915 break;
19916 default: if(opts.WTF) throw new Error(Rn);
19917 }
19918 }
19919 var out = ({
19920 Sheets: Sheets,
19921 SheetNames: SheetNames,
19922 Workbook: WB
19923 });
19924 if(opts.bookSheets) delete out.Sheets;
19925 return out;
19926 };
19927})();
19928
19929function parse_ods(zip, opts) {
19930 opts = opts || ({});
19931 var ods = !!safegetzipfile(zip, 'objectdata');
19932 if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
19933 var content = getzipstr(zip, 'content.xml');
19934 if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
19935 var wb = parse_content_xml(ods ? content : utf8read(content), opts);
19936 if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
19937 return wb;
19938}
19939function parse_fods(data, opts) {
19940 return parse_content_xml(data, opts);
19941}
19942
19943/* OpenDocument */
19944var write_styles_ods = (function() {
19945 var payload = '<office:document-styles ' + wxt_helper({
19946 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
19947 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
19948 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
19949 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
19950 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
19951 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
19952 'xmlns:xlink': "http://www.w3.org/1999/xlink",
19953 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
19954 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
19955 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
19956 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
19957 'office:version': "1.2"
19958 }) + '></office:document-styles>';
19959 return function wso() {
19960 return XML_HEADER + payload;
19961 };
19962})();
19963var write_content_ods = (function() {
19964 /* 6.1.2 White Space Characters */
19965 var write_text_p = function(text) {
19966 return escapexml(text)
19967 .replace(/ +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
19968 .replace(/\t/g, "<text:tab/>")
19969 .replace(/\n/g, "<text:line-break/>")
19970 .replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
19971 };
19972
19973 var null_cell_xml = ' <table:table-cell />\n';
19974 var covered_cell_xml = ' <table:covered-table-cell/>\n';
19975 var write_ws = function(ws, wb, i) {
19976 /* Section 9 Tables */
19977 var o = [];
19978 o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
19979 var R=0,C=0, range = decode_range(ws['!ref']);
19980 var marr = ws['!merges'] || [], mi = 0;
19981 var dense = Array.isArray(ws);
19982 for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
19983 for(; R <= range.e.r; ++R) {
19984 o.push(' <table:table-row>\n');
19985 for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
19986 for(; C <= range.e.c; ++C) {
19987 var skip = false, ct = {}, textp = "";
19988 for(mi = 0; mi != marr.length; ++mi) {
19989 if(marr[mi].s.c > C) continue;
19990 if(marr[mi].s.r > R) continue;
19991 if(marr[mi].e.c < C) continue;
19992 if(marr[mi].e.r < R) continue;
19993 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
19994 ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
19995 ct['table:number-rows-spanned'] = (marr[mi].e.r - marr[mi].s.r + 1);
19996 break;
19997 }
19998 if(skip) { o.push(covered_cell_xml); continue; }
19999 var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
20000 if(cell && cell.f) {
20001 ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
20002 if(cell.F) {
20003 if(cell.F.slice(0, ref.length) == ref) {
20004 var _Fref = decode_range(cell.F);
20005 ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
20006 ct['table:number-matrix-rows-spanned'] = (_Fref.e.r - _Fref.s.r + 1);
20007 }
20008 }
20009 }
20010 if(!cell) { o.push(null_cell_xml); continue; }
20011 switch(cell.t) {
20012 case 'b':
20013 textp = (cell.v ? 'TRUE' : 'FALSE');
20014 ct['office:value-type'] = "boolean";
20015 ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
20016 break;
20017 case 'n':
20018 textp = (cell.w||String(cell.v||0));
20019 ct['office:value-type'] = "float";
20020 ct['office:value'] = (cell.v||0);
20021 break;
20022 case 's': case 'str':
20023 textp = cell.v;
20024 ct['office:value-type'] = "string";
20025 break;
20026 case 'd':
20027 textp = (cell.w||(parseDate(cell.v).toISOString()));
20028 ct['office:value-type'] = "date";
20029 ct['office:date-value'] = (parseDate(cell.v).toISOString());
20030 ct['table:style-name'] = "ce1";
20031 break;
20032 //case 'e':
20033 default: o.push(null_cell_xml); continue;
20034 }
20035 var text_p = write_text_p(textp);
20036 if(cell.l && cell.l.Target) {
20037 var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
20038 text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
20039 }
20040 o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
20041 }
20042 o.push(' </table:table-row>\n');
20043 }
20044 o.push(' </table:table>\n');
20045 return o.join("");
20046 };
20047
20048 var write_automatic_styles_ods = function(o) {
20049 o.push(' <office:automatic-styles>\n');
20050 o.push(' <number:date-style style:name="N37" number:automatic-order="true">\n');
20051 o.push(' <number:month number:style="long"/>\n');
20052 o.push(' <number:text>/</number:text>\n');
20053 o.push(' <number:day number:style="long"/>\n');
20054 o.push(' <number:text>/</number:text>\n');
20055 o.push(' <number:year/>\n');
20056 o.push(' </number:date-style>\n');
20057 o.push(' <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
20058 o.push(' </office:automatic-styles>\n');
20059 };
20060
20061 return function wcx(wb, opts) {
20062 var o = [XML_HEADER];
20063 /* 3.1.3.2 */
20064 var attr = wxt_helper({
20065 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
20066 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
20067 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
20068 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
20069 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
20070 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
20071 'xmlns:xlink': "http://www.w3.org/1999/xlink",
20072 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
20073 'xmlns:meta': "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
20074 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
20075 'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
20076 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
20077 'xmlns:chart': "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
20078 'xmlns:dr3d': "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
20079 'xmlns:math': "http://www.w3.org/1998/Math/MathML",
20080 'xmlns:form': "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
20081 'xmlns:script': "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
20082 'xmlns:ooo': "http://openoffice.org/2004/office",
20083 'xmlns:ooow': "http://openoffice.org/2004/writer",
20084 'xmlns:oooc': "http://openoffice.org/2004/calc",
20085 'xmlns:dom': "http://www.w3.org/2001/xml-events",
20086 'xmlns:xforms': "http://www.w3.org/2002/xforms",
20087 'xmlns:xsd': "http://www.w3.org/2001/XMLSchema",
20088 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
20089 'xmlns:sheet': "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
20090 'xmlns:rpt': "http://openoffice.org/2005/report",
20091 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
20092 'xmlns:xhtml': "http://www.w3.org/1999/xhtml",
20093 'xmlns:grddl': "http://www.w3.org/2003/g/data-view#",
20094 'xmlns:tableooo': "http://openoffice.org/2009/table",
20095 'xmlns:drawooo': "http://openoffice.org/2010/draw",
20096 'xmlns:calcext': "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
20097 'xmlns:loext': "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
20098 'xmlns:field': "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
20099 'xmlns:formx': "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
20100 'xmlns:css3t': "http://www.w3.org/TR/css3-text/",
20101 'office:version': "1.2"
20102 });
20103
20104 var fods = wxt_helper({
20105 'xmlns:config': "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
20106 'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
20107 });
20108
20109 if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n');
20110 else o.push('<office:document-content' + attr + '>\n');
20111 write_automatic_styles_ods(o);
20112 o.push(' <office:body>\n');
20113 o.push(' <office:spreadsheet>\n');
20114 for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
20115 o.push(' </office:spreadsheet>\n');
20116 o.push(' </office:body>\n');
20117 if(opts.bookType == "fods") o.push('</office:document>');
20118 else o.push('</office:document-content>');
20119 return o.join("");
20120 };
20121})();
20122
20123function write_ods(wb, opts) {
20124 if(opts.bookType == "fods") return write_content_ods(wb, opts);
20125
20126var zip = zip_new();
20127 var f = "";
20128
20129 var manifest = [];
20130 var rdf = [];
20131
20132 /* Part 3 Section 3.3 MIME Media Type */
20133 f = "mimetype";
20134 zip_add_file(zip, f, "application/vnd.oasis.opendocument.spreadsheet");
20135
20136 /* Part 1 Section 2.2 Documents */
20137 f = "content.xml";
20138 zip_add_file(zip, f, write_content_ods(wb, opts));
20139 manifest.push([f, "text/xml"]);
20140 rdf.push([f, "ContentFile"]);
20141
20142 /* TODO: these are hard-coded styles to satiate excel */
20143 f = "styles.xml";
20144 zip_add_file(zip, f, write_styles_ods(wb, opts));
20145 manifest.push([f, "text/xml"]);
20146 rdf.push([f, "StylesFile"]);
20147
20148 /* TODO: this is hard-coded to satiate excel */
20149 f = "meta.xml";
20150 zip_add_file(zip, f, write_meta_ods());
20151 manifest.push([f, "text/xml"]);
20152 rdf.push([f, "MetadataFile"]);
20153
20154 /* Part 3 Section 6 Metadata Manifest File */
20155 f = "manifest.rdf";
20156 zip_add_file(zip, f, write_rdf(rdf/*, opts*/));
20157 manifest.push([f, "application/rdf+xml"]);
20158
20159 /* Part 3 Section 4 Manifest File */
20160 f = "META-INF/manifest.xml";
20161 zip_add_file(zip, f, write_manifest(manifest/*, opts*/));
20162
20163 return zip;
20164}
20165
20166function write_sheet_index(wb, sheet) {
20167 if(!sheet) return 0;
20168 var idx = wb.SheetNames.indexOf(sheet);
20169 if(idx == -1) throw new Error("Sheet not found: " + sheet);
20170 return idx;
20171}
20172
20173function write_obj_str(factory) {
20174 return function write_str(wb, o) {
20175 var idx = write_sheet_index(wb, o.sheet);
20176 return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
20177 };
20178}
20179
20180var write_htm_str = write_obj_str(HTML_);
20181var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
20182var write_slk_str = write_obj_str(typeof SYLK !== "undefined" ? SYLK : {});
20183var write_dif_str = write_obj_str(typeof DIF !== "undefined" ? DIF : {});
20184var write_prn_str = write_obj_str(typeof PRN !== "undefined" ? PRN : {});
20185var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {});
20186var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
20187var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {});
20188var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {});
20189
20190function fix_opts_func(defaults) {
20191 return function fix_opts(opts) {
20192 for(var i = 0; i != defaults.length; ++i) {
20193 var d = defaults[i];
20194 if(opts[d[0]] === undefined) opts[d[0]] = d[1];
20195 if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
20196 }
20197 };
20198}
20199
20200var fix_read_opts = fix_opts_func([
20201 ['cellNF', false], /* emit cell number format string as .z */
20202 ['cellHTML', true], /* emit html string as .h */
20203 ['cellFormula', true], /* emit formulae as .f */
20204 ['cellStyles', false], /* emits style/theme as .s */
20205 ['cellText', true], /* emit formatted text as .w */
20206 ['cellDates', false], /* emit date cells with type `d` */
20207
20208 ['sheetStubs', false], /* emit empty cells */
20209 ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
20210
20211 ['bookDeps', false], /* parse calculation chains */
20212 ['bookSheets', false], /* only try to get sheet names (no Sheets) */
20213 ['bookProps', false], /* only try to get properties (no Sheets) */
20214 ['bookFiles', false], /* include raw file structure (keys, files, cfb) */
20215 ['bookVBA', false], /* include vba raw data (vbaraw) */
20216
20217 ['password',''], /* password */
20218 ['WTF', false] /* WTF mode (throws errors) */
20219]);
20220
20221
20222var fix_write_opts = fix_opts_func([
20223 ['cellDates', false], /* write date cells with type `d` */
20224
20225 ['bookSST', false], /* Generate Shared String Table */
20226
20227 ['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
20228
20229 ['compression', false], /* Use file compression */
20230
20231 ['WTF', false] /* WTF mode (throws errors) */
20232]);
20233function get_sheet_type(n) {
20234 if(RELS.WS.indexOf(n) > -1) return "sheet";
20235 if(RELS.CS && n == RELS.CS) return "chart";
20236 if(RELS.DS && n == RELS.DS) return "dialog";
20237 if(RELS.MS && n == RELS.MS) return "macro";
20238 return (n && n.length) ? n : "sheet";
20239}
20240function safe_parse_wbrels(wbrels, sheets) {
20241 if(!wbrels) return 0;
20242 try {
20243 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)]; });
20244 } catch(e) { return null; }
20245 return !wbrels || wbrels.length === 0 ? null : wbrels;
20246}
20247
20248function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
20249 try {
20250 sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
20251 var data = getzipdata(zip, path);
20252 var _ws;
20253 switch(stype) {
20254 case 'sheet': _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
20255 case 'chart': _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
20256 if(!_ws || !_ws['!drawel']) break;
20257 var dfile = resolve_path(_ws['!drawel'].Target, path);
20258 var drelsp = get_rels_path(dfile);
20259 var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
20260 var chartp = resolve_path(draw, dfile);
20261 var crelsp = get_rels_path(chartp);
20262 _ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
20263 break;
20264 case 'macro': _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
20265 case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
20266 default: throw new Error("Unrecognized sheet type " + stype);
20267 }
20268 sheets[sheet] = _ws;
20269
20270 /* scan rels for comments */
20271 var comments = [];
20272 if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) {
20273 if(sheetRels[sheet][n].Type == RELS.CMNT) {
20274 var dfile = resolve_path(sheetRels[sheet][n].Target, path);
20275 comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
20276 if(!comments || !comments.length) return;
20277 sheet_insert_comments(_ws, comments);
20278 }
20279 });
20280 } catch(e) { if(opts.WTF) throw e; }
20281}
20282
20283function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
20284
20285function parse_zip(zip, opts) {
20286 make_ssf(SSF);
20287 opts = opts || {};
20288 fix_read_opts(opts);
20289
20290 /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
20291 if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
20292 /* UOC */
20293 if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
20294 /* Numbers */
20295 if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
20296
20297 var entries = zipentries(zip);
20298 var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
20299 var xlsb = false;
20300 var sheets, binname;
20301 if(dir.workbooks.length === 0) {
20302 binname = "xl/workbook.xml";
20303 if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
20304 }
20305 if(dir.workbooks.length === 0) {
20306 binname = "xl/workbook.bin";
20307 if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
20308 dir.workbooks.push(binname);
20309 xlsb = true;
20310 }
20311 if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
20312
20313 var themes = ({});
20314 var styles = ({});
20315 if(!opts.bookSheets && !opts.bookProps) {
20316 strs = [];
20317 if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
20318
20319 if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
20320
20321 if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
20322 }
20323
20324 /*var externbooks = */dir.links.map(function(link) {
20325 try {
20326 var rels = parse_rels(getzipstr(zip, get_rels_path(strip_front_slash(link))), link);
20327 return parse_xlink(getzipdata(zip, strip_front_slash(link)), rels, link, opts);
20328 } catch(e) {}
20329 });
20330
20331 var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
20332
20333 var props = {}, propdata = "";
20334
20335 if(dir.coreprops.length) {
20336 propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
20337 if(propdata) props = parse_core_props(propdata);
20338 if(dir.extprops.length !== 0) {
20339 propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
20340 if(propdata) parse_ext_props(propdata, props, opts);
20341 }
20342 }
20343
20344 var custprops = {};
20345 if(!opts.bookSheets || opts.bookProps) {
20346 if (dir.custprops.length !== 0) {
20347 propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
20348 if(propdata) custprops = parse_cust_props(propdata, opts);
20349 }
20350 }
20351
20352 var out = ({});
20353 if(opts.bookSheets || opts.bookProps) {
20354 if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
20355 else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
20356 if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
20357 if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
20358 if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
20359 }
20360 sheets = {};
20361
20362 var deps = {};
20363 if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
20364
20365 var i=0;
20366 var sheetRels = ({});
20367 var path, relsPath;
20368
20369 {
20370 var wbsheets = wb.Sheets;
20371 props.Worksheets = wbsheets.length;
20372 props.SheetNames = [];
20373 for(var j = 0; j != wbsheets.length; ++j) {
20374 props.SheetNames[j] = wbsheets[j].name;
20375 }
20376 }
20377
20378 var wbext = xlsb ? "bin" : "xml";
20379 var wbrelsi = dir.workbooks[0].lastIndexOf("/");
20380 var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
20381 if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
20382 var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
20383 if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
20384
20385 /* Numbers iOS hack */
20386 var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
20387 for(i = 0; i != props.Worksheets; ++i) {
20388 var stype = "sheet";
20389 if(wbrels && wbrels[i]) {
20390 path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
20391 if(!safegetzipfile(zip, path)) path = wbrels[i][1];
20392 if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
20393 stype = wbrels[i][2];
20394 } else {
20395 path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
20396 path = path.replace(/sheet0\./,"sheet.");
20397 }
20398 relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
20399 safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
20400 }
20401
20402 out = ({
20403 Directory: dir,
20404 Workbook: wb,
20405 Props: props,
20406 Custprops: custprops,
20407 Deps: deps,
20408 Sheets: sheets,
20409 SheetNames: props.SheetNames,
20410 Strings: strs,
20411 Styles: styles,
20412 Themes: themes,
20413 SSF: SSF.get_table()
20414 });
20415 if(opts.bookFiles) {
20416 out.keys = entries;
20417 out.files = zip.files;
20418 }
20419 if(opts.bookVBA) {
20420 if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
20421 else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
20422 }
20423 return out;
20424}
20425
20426/* [MS-OFFCRYPTO] 2.1.1 */
20427function parse_xlsxcfb(cfb, _opts) {
20428 var opts = _opts || {};
20429 var f = 'Workbook', data = CFB.find(cfb, f);
20430 try {
20431 f = '/!DataSpaces/Version';
20432 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20433 /*var version = */parse_DataSpaceVersionInfo(data.content);
20434
20435 /* 2.3.4.1 */
20436 f = '/!DataSpaces/DataSpaceMap';
20437 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20438 var dsm = parse_DataSpaceMap(data.content);
20439 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")
20440 throw new Error("ECMA-376 Encrypted file bad " + f);
20441
20442 /* 2.3.4.2 */
20443 f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
20444 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20445 var seds = parse_DataSpaceDefinition(data.content);
20446 if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
20447 throw new Error("ECMA-376 Encrypted file bad " + f);
20448
20449 /* 2.3.4.3 */
20450 f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
20451 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20452 /*var hdr = */parse_Primary(data.content);
20453 } catch(e) {}
20454
20455 f = '/EncryptionInfo';
20456 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20457 var einfo = parse_EncryptionInfo(data.content);
20458
20459 /* 2.3.4.4 */
20460 f = '/EncryptedPackage';
20461 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20462
20463/*global decrypt_agile */
20464if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
20465/*global decrypt_std76 */
20466if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
20467 throw new Error("File is password-protected");
20468}
20469
20470function write_zip(wb, opts) {
20471 _shapeid = 1024;
20472 if(opts.bookType == "ods") return write_ods(wb, opts);
20473 if(wb && !wb.SSF) {
20474 wb.SSF = SSF.get_table();
20475 }
20476 if(wb && wb.SSF) {
20477 make_ssf(SSF); SSF.load_table(wb.SSF);
20478 // $FlowIgnore
20479 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
20480 opts.ssf = wb.SSF;
20481 }
20482 opts.rels = {}; opts.wbrels = {};
20483 opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
20484 if(browser_has_Map) opts.revStrings = new Map();
20485 else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
20486 var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
20487 var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
20488 var ct = new_ct();
20489 fix_write_opts(opts = opts || {});
20490var zip = zip_new();
20491 var f = "", rId = 0;
20492
20493 opts.cellXfs = [];
20494 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
20495
20496 if(!wb.Props) wb.Props = {};
20497
20498 f = "docProps/core.xml";
20499 zip_add_file(zip, f, write_core_props(wb.Props, opts));
20500 ct.coreprops.push(f);
20501 add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
20502
20503f = "docProps/app.xml";
20504 if(wb.Props && wb.Props.SheetNames){/* empty */}
20505 else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
20506 else {
20507 var _sn = [];
20508 for(var _i = 0; _i < wb.SheetNames.length; ++_i)
20509 if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
20510 wb.Props.SheetNames = _sn;
20511 }
20512 wb.Props.Worksheets = wb.Props.SheetNames.length;
20513 zip_add_file(zip, f, write_ext_props(wb.Props, opts));
20514 ct.extprops.push(f);
20515 add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
20516
20517 if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
20518 f = "docProps/custom.xml";
20519 zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
20520 ct.custprops.push(f);
20521 add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
20522 }
20523
20524 for(rId=1;rId <= wb.SheetNames.length; ++rId) {
20525 var wsrels = {'!id':{}};
20526 var ws = wb.Sheets[wb.SheetNames[rId-1]];
20527 var _type = (ws || {})["!type"] || "sheet";
20528 switch(_type) {
20529 case "chart":
20530 /* falls through */
20531 default:
20532 f = "xl/worksheets/sheet" + rId + "." + wbext;
20533 zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels));
20534 ct.sheets.push(f);
20535 add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
20536 }
20537
20538 if(ws) {
20539 var comments = ws['!comments'];
20540 var need_vml = false;
20541 if(comments && comments.length > 0) {
20542 var cf = "xl/comments" + rId + "." + wbext;
20543 zip_add_file(zip, cf, write_cmnt(comments, cf, opts));
20544 ct.comments.push(cf);
20545 add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
20546 need_vml = true;
20547 }
20548 if(ws['!legacy']) {
20549 if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
20550 }
20551 delete ws['!comments'];
20552 delete ws['!legacy'];
20553 }
20554
20555 if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
20556 }
20557
20558 if(opts.Strings != null && opts.Strings.length > 0) {
20559 f = "xl/sharedStrings." + wbext;
20560 zip_add_file(zip, f, write_sst(opts.Strings, f, opts));
20561 ct.strs.push(f);
20562 add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
20563 }
20564
20565 f = "xl/workbook." + wbext;
20566 zip_add_file(zip, f, write_wb(wb, f, opts));
20567 ct.workbooks.push(f);
20568 add_rels(opts.rels, 1, f, RELS.WB);
20569
20570 /* TODO: something more intelligent with themes */
20571
20572 f = "xl/theme/theme1.xml";
20573 zip_add_file(zip, f, write_theme(wb.Themes, opts));
20574 ct.themes.push(f);
20575 add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
20576
20577 /* TODO: something more intelligent with styles */
20578
20579 f = "xl/styles." + wbext;
20580 zip_add_file(zip, f, write_sty(wb, f, opts));
20581 ct.styles.push(f);
20582 add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
20583
20584 if(wb.vbaraw && vbafmt) {
20585 f = "xl/vbaProject.bin";
20586 zip_add_file(zip, f, wb.vbaraw);
20587 ct.vba.push(f);
20588 add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
20589 }
20590
20591 zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
20592 zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
20593 zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
20594
20595 delete opts.revssf; delete opts.ssf;
20596 return zip;
20597}
20598function firstbyte(f,o) {
20599 var x = "";
20600 switch((o||{}).type || "base64") {
20601 case 'buffer': return [f[0], f[1], f[2], f[3]];
20602 case 'base64': x = Base64.decode(f.slice(0,24)); break;
20603 case 'binary': x = f; break;
20604 case 'array': return [f[0], f[1], f[2], f[3]];
20605 default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
20606 }
20607 return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)];
20608}
20609
20610function read_cfb(cfb, opts) {
20611 if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
20612 return parse_xlscfb(cfb, opts);
20613}
20614
20615function read_zip(data, opts) {
20616var zip, d = data;
20617 var o = opts||{};
20618 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
20619 zip = zip_read(d, o);
20620 return parse_zip(zip, o);
20621}
20622
20623function read_plaintext(data, o) {
20624 var i = 0;
20625 main: while(i < data.length) switch(data.charCodeAt(i)) {
20626 case 0x0A: case 0x0D: case 0x20: ++i; break;
20627 case 0x3C: return parse_xlml(data.slice(i),o);
20628 default: break main;
20629 }
20630 return PRN.to_workbook(data, o);
20631}
20632
20633function read_plaintext_raw(data, o) {
20634 var str = "", bytes = firstbyte(data, o);
20635 switch(o.type) {
20636 case 'base64': str = Base64.decode(data); break;
20637 case 'binary': str = data; break;
20638 case 'buffer': str = data.toString('binary'); break;
20639 case 'array': str = cc2str(data); break;
20640 default: throw new Error("Unrecognized type " + o.type);
20641 }
20642 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
20643 return read_plaintext(str, o);
20644}
20645
20646function read_utf16(data, o) {
20647 var d = data;
20648 if(o.type == 'base64') d = Base64.decode(d);
20649 d = cptable.utils.decode(1200, d.slice(2), 'str');
20650 o.type = "binary";
20651 return read_plaintext(d, o);
20652}
20653
20654function bstrify(data) {
20655 return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
20656}
20657
20658function read_prn(data, d, o, str) {
20659 if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
20660 return PRN.to_workbook(d, o);
20661}
20662
20663function readSync(data, opts) {
20664 reset_cp();
20665 if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
20666 var d = data, n = [0,0,0,0], str = false;
20667 var o = opts||{};
20668 if(o.cellStyles) { o.cellNF = true; }
20669 _ssfopts = {};
20670 if(o.dateNF) _ssfopts.dateNF = o.dateNF;
20671 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
20672 if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
20673 if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
20674 if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
20675 // $FlowIgnore
20676 var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
20677 // $FlowIgnore
20678 if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
20679 }
20680 switch((n = firstbyte(d, o))[0]) {
20681 case 0xD0: return read_cfb(CFB.read(d, o), o);
20682 case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break;
20683 case 0x3C: return parse_xlml(d, o);
20684 case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
20685 case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
20686 case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
20687 case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
20688 case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
20689 case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
20690 case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
20691 case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
20692 case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
20693 }
20694 if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
20695 return read_prn(data, d, o, str);
20696}
20697
20698function readFileSync(filename, opts) {
20699 var o = opts||{}; o.type = 'file';
20700 return readSync(filename, o);
20701}
20702function write_cfb_ctr(cfb, o) {
20703 switch(o.type) {
20704 case "base64": case "binary": break;
20705 case "buffer": case "array": o.type = ""; break;
20706 case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
20707 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
20708 default: throw new Error("Unrecognized type " + o.type);
20709 }
20710 return CFB.write(cfb, o);
20711}
20712
20713/*global encrypt_agile */
20714function write_zip_type(wb, opts) {
20715 var o = opts||{};
20716 var z = write_zip(wb, o);
20717 var oopts = {};
20718 if(o.compression) oopts.compression = 'DEFLATE';
20719 if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
20720 else switch(o.type) {
20721 case "base64": oopts.type = "base64"; break;
20722 case "binary": oopts.type = "string"; break;
20723 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
20724 case "buffer":
20725 case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
20726 default: throw new Error("Unrecognized type " + o.type);
20727 }
20728 var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type}) : z.generate(oopts);
20729 if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o);
20730 if(o.type === "file") return write_dl(o.file, out);
20731 return o.type == "string" ? utf8read(out) : out;
20732}
20733
20734function write_cfb_type(wb, opts) {
20735 var o = opts||{};
20736 var cfb = write_xlscfb(wb, o);
20737 return write_cfb_ctr(cfb, o);
20738}
20739
20740function write_string_type(out, opts, bom) {
20741 if(!bom) bom = "";
20742 var o = bom + out;
20743 switch(opts.type) {
20744 case "base64": return Base64.encode(utf8write(o));
20745 case "binary": return utf8write(o);
20746 case "string": return out;
20747 case "file": return write_dl(opts.file, o, 'utf8');
20748 case "buffer": {
20749 if(has_buf) return Buffer_from(o, 'utf8');
20750 else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
20751 }
20752 }
20753 throw new Error("Unrecognized type " + opts.type);
20754}
20755
20756function write_stxt_type(out, opts) {
20757 switch(opts.type) {
20758 case "base64": return Base64.encode(out);
20759 case "binary": return out;
20760 case "string": return out; /* override in sheet_to_txt */
20761 case "file": return write_dl(opts.file, out, 'binary');
20762 case "buffer": {
20763 if(has_buf) return Buffer_from(out, 'binary');
20764 else return out.split("").map(function(c) { return c.charCodeAt(0); });
20765 }
20766 }
20767 throw new Error("Unrecognized type " + opts.type);
20768}
20769
20770/* TODO: test consistency */
20771function write_binary_type(out, opts) {
20772 switch(opts.type) {
20773 case "string":
20774 case "base64":
20775 case "binary":
20776 var bstr = "";
20777 // $FlowIgnore
20778 for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
20779 return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
20780 case "file": return write_dl(opts.file, out);
20781 case "buffer": return out;
20782 default: throw new Error("Unrecognized type " + opts.type);
20783 }
20784}
20785
20786function writeSync(wb, opts) {
20787 reset_cp();
20788 check_wb(wb);
20789 var o = opts||{};
20790 if(o.cellStyles) { o.cellNF = true; }
20791 if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
20792 switch(o.bookType || 'xlsb') {
20793 case 'xml':
20794 case 'xlml': return write_string_type(write_xlml(wb, o), o);
20795 case 'slk':
20796 case 'sylk': return write_string_type(write_slk_str(wb, o), o);
20797 case 'htm':
20798 case 'html': return write_string_type(write_htm_str(wb, o), o);
20799 case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
20800 case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
20801 case 'dif': return write_string_type(write_dif_str(wb, o), o);
20802 case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
20803 case 'prn': return write_string_type(write_prn_str(wb, o), o);
20804 case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
20805 case 'eth': return write_string_type(write_eth_str(wb, o), o);
20806 case 'fods': return write_string_type(write_ods(wb, o), o);
20807 case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
20808 case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
20809 case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
20810 case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
20811 case 'biff8':
20812 case 'xla':
20813 case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
20814 case 'xlsx':
20815 case 'xlsm':
20816 case 'xlam':
20817 case 'xlsb':
20818 case 'ods': return write_zip_type(wb, o);
20819 default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
20820 }
20821}
20822
20823function resolve_book_type(o) {
20824 if(o.bookType) return;
20825 var _BT = {
20826 "xls": "biff8",
20827 "htm": "html",
20828 "slk": "sylk",
20829 "socialcalc": "eth",
20830 "Sh33tJS": "WTF"
20831 };
20832 var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
20833 if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
20834 o.bookType = _BT[o.bookType] || o.bookType;
20835}
20836
20837function writeFileSync(wb, filename, opts) {
20838 var o = opts||{}; o.type = 'file';
20839 o.file = filename;
20840 resolve_book_type(o);
20841 return writeSync(wb, o);
20842}
20843
20844function writeFileAsync(filename, wb, opts, cb) {
20845 var o = opts||{}; o.type = 'file';
20846 o.file = filename;
20847 resolve_book_type(o);
20848 o.type = 'buffer';
20849 var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
20850 return _fs.writeFile(filename, writeSync(wb, o), _cb);
20851}
20852function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
20853 var rr = encode_row(R);
20854 var defval = o.defval, raw = o.raw || !o.hasOwnProperty("raw");
20855 var isempty = true;
20856 var row = (header === 1) ? [] : {};
20857 if(header !== 1) {
20858 if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
20859 else row.__rowNum__ = R;
20860 }
20861 if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
20862 var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20863 if(val === undefined || val.t === undefined) {
20864 if(defval === undefined) continue;
20865 if(hdr[C] != null) { row[hdr[C]] = defval; }
20866 continue;
20867 }
20868 var v = val.v;
20869 switch(val.t){
20870 case 'z': if(v == null) break; continue;
20871 case 'e': v = void 0; break;
20872 case 's': case 'd': case 'b': case 'n': break;
20873 default: throw new Error('unrecognized type ' + val.t);
20874 }
20875 if(hdr[C] != null) {
20876 if(v == null) {
20877 if(defval !== undefined) row[hdr[C]] = defval;
20878 else if(raw && v === null) row[hdr[C]] = null;
20879 else continue;
20880 } else {
20881 row[hdr[C]] = raw ? v : format_cell(val,v,o);
20882 }
20883 if(v != null) isempty = false;
20884 }
20885 }
20886 return { row: row, isempty: isempty };
20887}
20888
20889
20890function sheet_to_json(sheet, opts) {
20891 if(sheet == null || sheet["!ref"] == null) return [];
20892 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
20893 var r = {s:{r:0,c:0},e:{r:0,c:0}};
20894 var o = opts || {};
20895 var range = o.range != null ? o.range : sheet["!ref"];
20896 if(o.header === 1) header = 1;
20897 else if(o.header === "A") header = 2;
20898 else if(Array.isArray(o.header)) header = 3;
20899 else if(o.header == null) header = 0;
20900 switch(typeof range) {
20901 case 'string': r = safe_decode_range(range); break;
20902 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
20903 default: r = range;
20904 }
20905 if(header > 0) offset = 0;
20906 var rr = encode_row(r.s.r);
20907 var cols = [];
20908 var out = [];
20909 var outi = 0, counter = 0;
20910 var dense = Array.isArray(sheet);
20911 var R = r.s.r, C = 0, CC = 0;
20912 if(dense && !sheet[R]) sheet[R] = [];
20913 for(C = r.s.c; C <= r.e.c; ++C) {
20914 cols[C] = encode_col(C);
20915 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20916 switch(header) {
20917 case 1: hdr[C] = C - r.s.c; break;
20918 case 2: hdr[C] = cols[C]; break;
20919 case 3: hdr[C] = o.header[C - r.s.c]; break;
20920 default:
20921 if(val == null) val = {w: "__EMPTY", t: "s"};
20922 vv = v = format_cell(val, null, o);
20923 counter = 0;
20924 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
20925 hdr[C] = vv;
20926 }
20927 }
20928 for (R = r.s.r + offset; R <= r.e.r; ++R) {
20929 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
20930 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
20931 }
20932 out.length = outi;
20933 return out;
20934}
20935
20936var qreg = /"/g;
20937function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
20938 var isempty = true;
20939 var row = [], txt = "", rr = encode_row(R);
20940 for(var C = r.s.c; C <= r.e.c; ++C) {
20941 if (!cols[C]) continue;
20942 var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
20943 if(val == null) txt = "";
20944 else if(val.v != null) {
20945 isempty = false;
20946 txt = ''+format_cell(val, null, o);
20947 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; }
20948 if(txt == "ID") txt = '"ID"';
20949 } else if(val.f != null && !val.F) {
20950 isempty = false;
20951 txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
20952 } else txt = "";
20953 /* NOTE: Excel CSV does not support array formulae */
20954 row.push(txt);
20955 }
20956 if(o.blankrows === false && isempty) return null;
20957 return row.join(FS);
20958}
20959
20960function sheet_to_csv(sheet, opts) {
20961 var out = [];
20962 var o = opts == null ? {} : opts;
20963 if(sheet == null || sheet["!ref"] == null) return "";
20964 var r = safe_decode_range(sheet["!ref"]);
20965 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
20966 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
20967 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
20968 var row = "", cols = [];
20969 o.dense = Array.isArray(sheet);
20970 var colinfo = o.skipHidden && sheet["!cols"] || [];
20971 var rowinfo = o.skipHidden && sheet["!rows"] || [];
20972 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
20973 for(var R = r.s.r; R <= r.e.r; ++R) {
20974 if ((rowinfo[R]||{}).hidden) continue;
20975 row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
20976 if(row == null) { continue; }
20977 if(o.strip) row = row.replace(endregex,"");
20978 out.push(row + RS);
20979 }
20980 delete o.dense;
20981 return out.join("");
20982}
20983
20984function sheet_to_txt(sheet, opts) {
20985 if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
20986 var s = sheet_to_csv(sheet, opts);
20987 if(typeof cptable == 'undefined' || opts.type == 'string') return s;
20988 var o = cptable.utils.encode(1200, s, 'str');
20989 return String.fromCharCode(255) + String.fromCharCode(254) + o;
20990}
20991
20992function sheet_to_formulae(sheet) {
20993 var y = "", x, val="";
20994 if(sheet == null || sheet["!ref"] == null) return [];
20995 var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
20996 var cmds = [];
20997 var dense = Array.isArray(sheet);
20998 for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
20999 for(var R = r.s.r; R <= r.e.r; ++R) {
21000 rr = encode_row(R);
21001 for(C = r.s.c; C <= r.e.c; ++C) {
21002 y = cols[C] + rr;
21003 x = dense ? (sheet[R]||[])[C] : sheet[y];
21004 val = "";
21005 if(x === undefined) continue;
21006 else if(x.F != null) {
21007 y = x.F;
21008 if(!x.f) continue;
21009 val = x.f;
21010 if(y.indexOf(":") == -1) y = y + ":" + y;
21011 }
21012 if(x.f != null) val = x.f;
21013 else if(x.t == 'z') continue;
21014 else if(x.t == 'n' && x.v != null) val = "" + x.v;
21015 else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
21016 else if(x.w !== undefined) val = "'" + x.w;
21017 else if(x.v === undefined) continue;
21018 else if(x.t == 's') val = "'" + x.v;
21019 else val = ""+x.v;
21020 cmds[cmds.length] = y + "=" + val;
21021 }
21022 }
21023 return cmds;
21024}
21025
21026function sheet_add_json(_ws, js, opts) {
21027 var o = opts || {};
21028 var offset = +!o.skipHeader;
21029 var ws = _ws || ({});
21030 var _R = 0, _C = 0;
21031 if(ws && o.origin != null) {
21032 if(typeof o.origin == 'number') _R = o.origin;
21033 else {
21034 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
21035 _R = _origin.r; _C = _origin.c;
21036 }
21037 }
21038 var cell;
21039 var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
21040 if(ws['!ref']) {
21041 var _range = safe_decode_range(ws['!ref']);
21042 range.e.c = Math.max(range.e.c, _range.e.c);
21043 range.e.r = Math.max(range.e.r, _range.e.r);
21044 if(_R == -1) { _R = range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
21045 }
21046 var hdr = o.header || [], C = 0;
21047
21048 js.forEach(function (JS, R) {
21049 keys(JS).forEach(function(k) {
21050 if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
21051 var v = JS[k];
21052 var t = 'z';
21053 var z = "";
21054 var ref = encode_cell({c:_C + C,r:_R + R + offset});
21055 cell = utils.sheet_get_cell(ws, ref);
21056 if(v && typeof v === 'object' && !(v instanceof Date)){
21057 ws[ref] = v;
21058 } else {
21059 if(typeof v == 'number') t = 'n';
21060 else if(typeof v == 'boolean') t = 'b';
21061 else if(typeof v == 'string') t = 's';
21062 else if(v instanceof Date) {
21063 t = 'd';
21064 if(!o.cellDates) { t = 'n'; v = datenum(v); }
21065 z = (o.dateNF || SSF._table[14]);
21066 }
21067 if(!cell) ws[ref] = cell = ({t:t, v:v});
21068 else {
21069 cell.t = t; cell.v = v;
21070 delete cell.w; delete cell.R;
21071 if(z) cell.z = z;
21072 }
21073 if(z) cell.z = z;
21074 }
21075 });
21076 });
21077 range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
21078 var __R = encode_row(_R);
21079 if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
21080 ws['!ref'] = encode_range(range);
21081 return ws;
21082}
21083function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
21084
21085var utils = {
21086 encode_col: encode_col,
21087 encode_row: encode_row,
21088 encode_cell: encode_cell,
21089 encode_range: encode_range,
21090 decode_col: decode_col,
21091 decode_row: decode_row,
21092 split_cell: split_cell,
21093 decode_cell: decode_cell,
21094 decode_range: decode_range,
21095 format_cell: format_cell,
21096 get_formulae: sheet_to_formulae,
21097 make_csv: sheet_to_csv,
21098 make_json: sheet_to_json,
21099 make_formulae: sheet_to_formulae,
21100 sheet_add_aoa: sheet_add_aoa,
21101 sheet_add_json: sheet_add_json,
21102 aoa_to_sheet: aoa_to_sheet,
21103 json_to_sheet: json_to_sheet,
21104 table_to_sheet: parse_dom_table,
21105 table_to_book: table_to_book,
21106 sheet_to_csv: sheet_to_csv,
21107 sheet_to_txt: sheet_to_txt,
21108 sheet_to_json: sheet_to_json,
21109 sheet_to_html: HTML_.from_sheet,
21110 sheet_to_formulae: sheet_to_formulae,
21111 sheet_to_row_object_array: sheet_to_json
21112};
21113
21114(function(utils) {
21115utils.consts = utils.consts || {};
21116function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
21117
21118function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
21119
21120/* get cell, creating a stub if necessary */
21121function ws_get_cell_stub(ws, R, C) {
21122 /* A1 cell address */
21123 if(typeof R == "string") {
21124 /* dense */
21125 if(Array.isArray(ws)) {
21126 var RC = decode_cell(R);
21127 if(!ws[RC.r]) ws[RC.r] = [];
21128 return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
21129 }
21130 return ws[R] || (ws[R] = {t:'z'});
21131 }
21132 /* cell address object */
21133 if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
21134 /* R and C are 0-based indices */
21135 return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
21136}
21137utils.sheet_get_cell = ws_get_cell_stub;
21138
21139/* find sheet index for given name / validate index */
21140function wb_sheet_idx(wb, sh) {
21141 if(typeof sh == "number") {
21142 if(sh >= 0 && wb.SheetNames.length > sh) return sh;
21143 throw new Error("Cannot find sheet # " + sh);
21144 } else if(typeof sh == "string") {
21145 var idx = wb.SheetNames.indexOf(sh);
21146 if(idx > -1) return idx;
21147 throw new Error("Cannot find sheet name |" + sh + "|");
21148 } else throw new Error("Cannot find sheet |" + sh + "|");
21149}
21150
21151/* simple blank workbook object */
21152utils.book_new = function() {
21153 return { SheetNames: [], Sheets: {} };
21154};
21155
21156/* add a worksheet to the end of a given workbook */
21157utils.book_append_sheet = function(wb, ws, name) {
21158 if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
21159 if(!name) throw new Error("Too many worksheets");
21160 check_ws_name(name);
21161 if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
21162
21163 wb.SheetNames.push(name);
21164 wb.Sheets[name] = ws;
21165};
21166
21167/* set sheet visibility (visible/hidden/very hidden) */
21168utils.book_set_sheet_visibility = function(wb, sh, vis) {
21169 get_default(wb,"Workbook",{});
21170 get_default(wb.Workbook,"Sheets",[]);
21171
21172 var idx = wb_sheet_idx(wb, sh);
21173 // $FlowIgnore
21174 get_default(wb.Workbook.Sheets,idx, {});
21175
21176 switch(vis) {
21177 case 0: case 1: case 2: break;
21178 default: throw new Error("Bad sheet visibility setting " + vis);
21179 }
21180 // $FlowIgnore
21181 wb.Workbook.Sheets[idx].Hidden = vis;
21182};
21183add_consts([
21184 ["SHEET_VISIBLE", 0],
21185 ["SHEET_HIDDEN", 1],
21186 ["SHEET_VERY_HIDDEN", 2]
21187]);
21188
21189/* set number format */
21190utils.cell_set_number_format = function(cell, fmt) {
21191 cell.z = fmt;
21192 return cell;
21193};
21194
21195/* set cell hyperlink */
21196utils.cell_set_hyperlink = function(cell, target, tooltip) {
21197 if(!target) {
21198 delete cell.l;
21199 } else {
21200 cell.l = ({ Target: target });
21201 if(tooltip) cell.l.Tooltip = tooltip;
21202 }
21203 return cell;
21204};
21205utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
21206
21207/* add to cell comments */
21208utils.cell_add_comment = function(cell, text, author) {
21209 if(!cell.c) cell.c = [];
21210 cell.c.push({t:text, a:author||"SheetJS"});
21211};
21212
21213/* set array formula and flush related cells */
21214utils.sheet_set_array_formula = function(ws, range, formula) {
21215 var rng = typeof range != "string" ? range : safe_decode_range(range);
21216 var rngstr = typeof range == "string" ? range : encode_range(range);
21217 for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
21218 var cell = ws_get_cell_stub(ws, R, C);
21219 cell.t = 'n';
21220 cell.F = rngstr;
21221 delete cell.v;
21222 if(R == rng.s.r && C == rng.s.c) cell.f = formula;
21223 }
21224 return ws;
21225};
21226
21227return utils;
21228})(utils);
21229
21230if(has_buf && typeof require != 'undefined') (function() {
21231 var Readable = {}.Readable;
21232
21233 var write_csv_stream = function(sheet, opts) {
21234 var stream = Readable();
21235 var o = opts == null ? {} : opts;
21236 if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
21237 var r = safe_decode_range(sheet["!ref"]);
21238 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
21239 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
21240 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
21241 var row = "", cols = [];
21242 o.dense = Array.isArray(sheet);
21243 var colinfo = o.skipHidden && sheet["!cols"] || [];
21244 var rowinfo = o.skipHidden && sheet["!rows"] || [];
21245 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
21246 var R = r.s.r;
21247 var BOM = false;
21248 stream._read = function() {
21249 if(!BOM) { BOM = true; return stream.push("\uFEFF"); }
21250 while(R <= r.e.r) {
21251 ++R;
21252 if ((rowinfo[R-1]||{}).hidden) continue;
21253 row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o);
21254 if(row != null) {
21255 if(o.strip) row = row.replace(endregex,"");
21256 stream.push(row + RS);
21257 break;
21258 }
21259 }
21260 if(R > r.e.r) return stream.push(null);
21261 };
21262 return stream;
21263 };
21264
21265 var write_html_stream = function(ws, opts) {
21266 var stream = Readable();
21267
21268 var o = opts || {};
21269 var header = o.header != null ? o.header : HTML_.BEGIN;
21270 var footer = o.footer != null ? o.footer : HTML_.END;
21271 stream.push(header);
21272 var r = decode_range(ws['!ref']);
21273 o.dense = Array.isArray(ws);
21274 stream.push(HTML_._preamble(ws, r, o));
21275 var R = r.s.r;
21276 var end = false;
21277 stream._read = function() {
21278 if(R > r.e.r) {
21279 if(!end) { end = true; stream.push("</table>" + footer); }
21280 return stream.push(null);
21281 }
21282 while(R <= r.e.r) {
21283 stream.push(HTML_._row(ws, r, R, o));
21284 ++R;
21285 break;
21286 }
21287 };
21288 return stream;
21289 };
21290
21291 var write_json_stream = function(sheet, opts) {
21292 var stream = Readable({objectMode:true});
21293
21294 if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
21295 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
21296 var r = {s:{r:0,c:0},e:{r:0,c:0}};
21297 var o = opts || {};
21298 var range = o.range != null ? o.range : sheet["!ref"];
21299 if(o.header === 1) header = 1;
21300 else if(o.header === "A") header = 2;
21301 else if(Array.isArray(o.header)) header = 3;
21302 switch(typeof range) {
21303 case 'string': r = safe_decode_range(range); break;
21304 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
21305 default: r = range;
21306 }
21307 if(header > 0) offset = 0;
21308 var rr = encode_row(r.s.r);
21309 var cols = [];
21310 var counter = 0;
21311 var dense = Array.isArray(sheet);
21312 var R = r.s.r, C = 0, CC = 0;
21313 if(dense && !sheet[R]) sheet[R] = [];
21314 for(C = r.s.c; C <= r.e.c; ++C) {
21315 cols[C] = encode_col(C);
21316 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
21317 switch(header) {
21318 case 1: hdr[C] = C - r.s.c; break;
21319 case 2: hdr[C] = cols[C]; break;
21320 case 3: hdr[C] = o.header[C - r.s.c]; break;
21321 default:
21322 if(val == null) val = {w: "__EMPTY", t: "s"};
21323 vv = v = format_cell(val, null, o);
21324 counter = 0;
21325 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
21326 hdr[C] = vv;
21327 }
21328 }
21329 R = r.s.r + offset;
21330 stream._read = function() {
21331 if(R > r.e.r) return stream.push(null);
21332 while(R <= r.e.r) {
21333 //if ((rowinfo[R-1]||{}).hidden) continue;
21334 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
21335 ++R;
21336 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
21337 stream.push(row.row);
21338 break;
21339 }
21340 }
21341 };
21342 return stream;
21343 };
21344
21345 XLSX.stream = {
21346 to_json: write_json_stream,
21347 to_html: write_html_stream,
21348 to_csv: write_csv_stream
21349 };
21350})();
21351
21352if(typeof parse_xlscfb !== "undefined") XLSX.parse_xlscfb = parse_xlscfb;
21353XLSX.parse_zip = parse_zip;
21354XLSX.read = readSync; //xlsread
21355XLSX.readFile = readFileSync; //readFile
21356XLSX.readFileSync = readFileSync;
21357XLSX.write = writeSync;
21358XLSX.writeFile = writeFileSync;
21359XLSX.writeFileSync = writeFileSync;
21360XLSX.writeFileAsync = writeFileAsync;
21361XLSX.utils = utils;
21362XLSX.SSF = SSF;
21363if(typeof CFB !== "undefined") XLSX.CFB = CFB;
21364}
21365/*global define */
21366if(typeof exports !== 'undefined') make_xlsx_lib(exports);
21367else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
21368else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
21369else make_xlsx_lib(XLSX);
21370/*exported XLS, ODS */
21371var XLS = XLSX, ODS = XLSX;