UNPKG

700 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.14.4';
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 = require('./dist/cpexcel.js');
13 else if(typeof window !== 'undefined') window.cptable = require('./dist/cpexcel.js');
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 // $FlowIgnore
160 if(has_buf) return Buffer_from(s, "binary");
161 return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
162};
163
164function s2ab(s) {
165 if(typeof ArrayBuffer === 'undefined') return s2a(s);
166 var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
167 for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
168 return buf;
169}
170
171function a2s(data) {
172 if(Array.isArray(data)) return data.map(_chr).join("");
173 var o = []; for(var i = 0; i < data.length; ++i) o[i] = _chr(data[i]); return o.join("");
174}
175
176function a2u(data) {
177 if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
178 return new Uint8Array(data);
179}
180
181function ab2a(data) {
182 if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
183 if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
184var o = new Array(data.length);
185 for(var i = 0; i < data.length; ++i) o[i] = data[i];
186 return o;
187}
188
189var bconcat = function(bufs) { return [].concat.apply([], bufs); };
190
191var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
192/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
193/*jshint -W041 */
194var SSF = ({});
195var make_ssf = function make_ssf(SSF){
196SSF.version = '0.10.2';
197function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
198function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
199function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
200function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
201function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
202function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
203function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
204var p2_32 = Math.pow(2,32);
205function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
206function 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; }
207var days = [
208 ['Sun', 'Sunday'],
209 ['Mon', 'Monday'],
210 ['Tue', 'Tuesday'],
211 ['Wed', 'Wednesday'],
212 ['Thu', 'Thursday'],
213 ['Fri', 'Friday'],
214 ['Sat', 'Saturday']
215];
216var months = [
217 ['J', 'Jan', 'January'],
218 ['F', 'Feb', 'February'],
219 ['M', 'Mar', 'March'],
220 ['A', 'Apr', 'April'],
221 ['M', 'May', 'May'],
222 ['J', 'Jun', 'June'],
223 ['J', 'Jul', 'July'],
224 ['A', 'Aug', 'August'],
225 ['S', 'Sep', 'September'],
226 ['O', 'Oct', 'October'],
227 ['N', 'Nov', 'November'],
228 ['D', 'Dec', 'December']
229];
230function init_table(t) {
231 t[0]= 'General';
232 t[1]= '0';
233 t[2]= '0.00';
234 t[3]= '#,##0';
235 t[4]= '#,##0.00';
236 t[9]= '0%';
237 t[10]= '0.00%';
238 t[11]= '0.00E+00';
239 t[12]= '# ?/?';
240 t[13]= '# ??/??';
241 t[14]= 'm/d/yy';
242 t[15]= 'd-mmm-yy';
243 t[16]= 'd-mmm';
244 t[17]= 'mmm-yy';
245 t[18]= 'h:mm AM/PM';
246 t[19]= 'h:mm:ss AM/PM';
247 t[20]= 'h:mm';
248 t[21]= 'h:mm:ss';
249 t[22]= 'm/d/yy h:mm';
250 t[37]= '#,##0 ;(#,##0)';
251 t[38]= '#,##0 ;[Red](#,##0)';
252 t[39]= '#,##0.00;(#,##0.00)';
253 t[40]= '#,##0.00;[Red](#,##0.00)';
254 t[45]= 'mm:ss';
255 t[46]= '[h]:mm:ss';
256 t[47]= 'mmss.0';
257 t[48]= '##0.0E+0';
258 t[49]= '@';
259 t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
260 t[65535]= 'General';
261}
262
263var table_fmt = {};
264init_table(table_fmt);
265function frac(x, D, mixed) {
266 var sgn = x < 0 ? -1 : 1;
267 var B = x * sgn;
268 var P_2 = 0, P_1 = 1, P = 0;
269 var Q_2 = 1, Q_1 = 0, Q = 0;
270 var A = Math.floor(B);
271 while(Q_1 < D) {
272 A = Math.floor(B);
273 P = A * P_1 + P_2;
274 Q = A * Q_1 + Q_2;
275 if((B - A) < 0.00000005) break;
276 B = 1 / (B - A);
277 P_2 = P_1; P_1 = P;
278 Q_2 = Q_1; Q_1 = Q;
279 }
280 if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
281 if(!mixed) return [0, sgn * P, Q];
282 var q = Math.floor(sgn * P/Q);
283 return [q, sgn*P - q*Q, Q];
284}
285function parse_date_code(v,opts,b2) {
286 if(v > 2958465 || v < 0) return null;
287 var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
288 var dout=[];
289 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};
290 if(Math.abs(out.u) < 1e-6) out.u = 0;
291 if(opts && opts.date1904) date += 1462;
292 if(out.u > 0.9999) {
293 out.u = 0;
294 if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
295 }
296 if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
297 else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
298 else {
299 if(date > 60) --date;
300 /* 1 = Jan 1 1900 in Gregorian */
301 var d = new Date(1900, 0, 1);
302 d.setDate(d.getDate() + date - 1);
303 dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
304 dow = d.getDay();
305 if(date < 60) dow = (dow + 6) % 7;
306 if(b2) dow = fix_hijri(d, dout);
307 }
308 out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
309 out.S = time % 60; time = Math.floor(time / 60);
310 out.M = time % 60; time = Math.floor(time / 60);
311 out.H = time;
312 out.q = dow;
313 return out;
314}
315SSF.parse_date_code = parse_date_code;
316var basedate = new Date(1899, 11, 31, 0, 0, 0);
317var dnthresh = basedate.getTime();
318var base1904 = new Date(1900, 2, 1, 0, 0, 0);
319function datenum_local(v, date1904) {
320 var epoch = v.getTime();
321 if(date1904) epoch -= 1461*24*60*60*1000;
322 else if(v >= base1904) epoch += 24*60*60*1000;
323 return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
324}
325function general_fmt_int(v) { return v.toString(10); }
326SSF._general_int = general_fmt_int;
327var general_fmt_num = (function make_general_fmt_num() {
328var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
329function gfn2(v) {
330 var w = (v<0?12:11);
331 var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
332 o = v.toPrecision(10); if(o.length <= w) return o;
333 return v.toExponential(5);
334}
335function gfn3(v) {
336 var o = v.toFixed(11).replace(gnr1,".$1");
337 if(o.length > (v<0?12:11)) o = v.toPrecision(6);
338 return o;
339}
340function gfn4(o) {
341 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");
342 return o;
343}
344function gfn5(o) {
345 return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
346}
347return function general_fmt_num(v) {
348 var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
349 if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
350 else if(Math.abs(V) <= 9) o = gfn2(v);
351 else if(V === 10) o = v.toFixed(10).substr(0,12);
352 else o = gfn3(v);
353 return gfn5(gfn4(o));
354};})();
355SSF._general_num = general_fmt_num;
356function general_fmt(v, opts) {
357 switch(typeof v) {
358 case 'string': return v;
359 case 'boolean': return v ? "TRUE" : "FALSE";
360 case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
361 case 'undefined': return "";
362 case 'object':
363 if(v == null) return "";
364 if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
365 }
366 throw new Error("unsupported value in General format: " + v);
367}
368SSF._general = general_fmt;
369function fix_hijri() { return 0; }
370/*jshint -W086 */
371function write_date(type, fmt, val, ss0) {
372 var o="", ss=0, tt=0, y = val.y, out, outl = 0;
373 switch(type) {
374 case 98: /* 'b' buddhist year */
375 y = val.y + 543;
376 /* falls through */
377 case 121: /* 'y' year */
378 switch(fmt.length) {
379 case 1: case 2: out = y % 100; outl = 2; break;
380 default: out = y % 10000; outl = 4; break;
381 } break;
382 case 109: /* 'm' month */
383 switch(fmt.length) {
384 case 1: case 2: out = val.m; outl = fmt.length; break;
385 case 3: return months[val.m-1][1];
386 case 5: return months[val.m-1][0];
387 default: return months[val.m-1][2];
388 } break;
389 case 100: /* 'd' day */
390 switch(fmt.length) {
391 case 1: case 2: out = val.d; outl = fmt.length; break;
392 case 3: return days[val.q][0];
393 default: return days[val.q][1];
394 } break;
395 case 104: /* 'h' 12-hour */
396 switch(fmt.length) {
397 case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
398 default: throw 'bad hour format: ' + fmt;
399 } break;
400 case 72: /* 'H' 24-hour */
401 switch(fmt.length) {
402 case 1: case 2: out = val.H; outl = fmt.length; break;
403 default: throw 'bad hour format: ' + fmt;
404 } break;
405 case 77: /* 'M' minutes */
406 switch(fmt.length) {
407 case 1: case 2: out = val.M; outl = fmt.length; break;
408 default: throw 'bad minute format: ' + fmt;
409 } break;
410 case 115: /* 's' seconds */
411 if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
412 if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
413if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
414 else tt = ss0 === 1 ? 10 : 1;
415 ss = Math.round((tt)*(val.S + val.u));
416 if(ss >= 60*tt) ss = 0;
417 if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
418 o = pad0(ss,2 + ss0);
419 if(fmt === 'ss') return o.substr(0,2);
420 return "." + o.substr(2,fmt.length-1);
421 case 90: /* 'Z' absolute time */
422 switch(fmt) {
423 case '[h]': case '[hh]': out = val.D*24+val.H; break;
424 case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
425 case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
426 default: throw 'bad abstime format: ' + fmt;
427 } outl = fmt.length === 3 ? 1 : 2; break;
428 case 101: /* 'e' era */
429 out = y; outl = 1;
430 }
431 if(outl > 0) return pad0(out, outl); else return "";
432}
433/*jshint +W086 */
434function commaify(s) {
435 var w = 3;
436 if(s.length <= w) return s;
437 var j = (s.length % w), o = s.substr(0,j);
438 for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
439 return o;
440}
441var write_num = (function make_write_num(){
442var pct1 = /%/g;
443function write_num_pct(type, fmt, val){
444 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
445 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
446}
447function write_num_cm(type, fmt, val){
448 var idx = fmt.length - 1;
449 while(fmt.charCodeAt(idx-1) === 44) --idx;
450 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
451}
452function write_num_exp(fmt, val){
453 var o;
454 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
455 if(fmt.match(/^#+0.0E\+0$/)) {
456 if(val == 0) return "0.0E+0";
457 else if(val < 0) return "-" + write_num_exp(fmt, -val);
458 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
459 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
460 if(ee < 0) ee += period;
461 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
462 if(o.indexOf("e") === -1) {
463 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
464 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
465 else o += "E+" + (fakee - ee);
466 while(o.substr(0,2) === "0.") {
467 o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
468 o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
469 }
470 o = o.replace(/\+-/,"-");
471 }
472 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
473 } else o = val.toExponential(idx);
474 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
475 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
476 return o.replace("e","E");
477}
478var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
479function write_num_f1(r, aval, sign) {
480 var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
481 var myn = (rr - base*den), myd = den;
482 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));
483}
484function write_num_f2(r, aval, sign) {
485 return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
486}
487var dec1 = /^#*0*\.([0#]+)/;
488var closeparen = /\).*[0#]/;
489var phone = /\(###\) ###\\?-####/;
490function hashq(str) {
491 var o = "", cc;
492 for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
493 case 35: break;
494 case 63: o+= " "; break;
495 case 48: o+= "0"; break;
496 default: o+= String.fromCharCode(cc);
497 }
498 return o;
499}
500function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
501function dec(val, d) {
502 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
503 return 0;
504 }
505 return Math.round((val-Math.floor(val))*Math.pow(10,d));
506}
507function carry(val, d) {
508 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
509 return 1;
510 }
511 return 0;
512}
513function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
514function write_num_flt(type, fmt, val) {
515 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
516 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
517 if(val >= 0) return write_num_flt('n', ffmt, val);
518 return '(' + write_num_flt('n', ffmt, -val) + ')';
519 }
520 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
521 if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
522 if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
523 if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
524 var o;
525 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
526 if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
527 if(fmt.match(/^[#?]+$/)) {
528 o = pad0r(val,0); if(o === "0") o = "";
529 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
530 }
531 if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
532 if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
533 if((r = fmt.match(dec1))) {
534 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); });
535 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
536 }
537 fmt = fmt.replace(/^#+([0.])/, "$1");
538 if((r = fmt.match(/^(0*)\.(#*)$/))) {
539 return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
540 }
541 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
542 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
543 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);
544 }
545 if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
546 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
547 o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
548 ri = 0;
549 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
550 }
551 if(fmt.match(phone)) {
552 o = write_num_flt(type, "##########", val);
553 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
554 }
555 var oa = "";
556 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
557 ri = Math.min(r[4].length,7);
558 ff = frac(aval, Math.pow(10,ri)-1, false);
559 o = "" + sign;
560 oa = write_num("n", r[1], ff[1]);
561 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
562 o += oa + r[2] + "/" + r[3];
563 oa = rpad_(ff[2],ri);
564 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
565 o += oa;
566 return o;
567 }
568 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
569 ri = Math.min(Math.max(r[1].length, r[4].length),7);
570 ff = frac(aval, Math.pow(10,ri)-1, true);
571 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));
572 }
573 if((r = fmt.match(/^[#0?]+$/))) {
574 o = pad0r(val, 0);
575 if(fmt.length <= o.length) return o;
576 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
577 }
578 if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
579 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
580 ri = o.indexOf(".");
581 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
582 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
583 }
584 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
585 ri = dec(val, r[1].length);
586 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);
587 }
588 switch(fmt) {
589 case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
590 case "###,###":
591 case "##,###":
592 case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
593 case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
594 case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
595 default:
596 }
597 throw new Error("unsupported format |" + fmt + "|");
598}
599function write_num_cm2(type, fmt, val){
600 var idx = fmt.length - 1;
601 while(fmt.charCodeAt(idx-1) === 44) --idx;
602 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
603}
604function write_num_pct2(type, fmt, val){
605 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
606 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
607}
608function write_num_exp2(fmt, val){
609 var o;
610 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
611 if(fmt.match(/^#+0.0E\+0$/)) {
612 if(val == 0) return "0.0E+0";
613 else if(val < 0) return "-" + write_num_exp2(fmt, -val);
614 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
615 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
616 if(ee < 0) ee += period;
617 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
618 if(!o.match(/[Ee]/)) {
619 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
620 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
621 else o += "E+" + (fakee - ee);
622 o = o.replace(/\+-/,"-");
623 }
624 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
625 } else o = val.toExponential(idx);
626 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
627 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
628 return o.replace("e","E");
629}
630function write_num_int(type, fmt, val) {
631 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
632 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
633 if(val >= 0) return write_num_int('n', ffmt, val);
634 return '(' + write_num_int('n', ffmt, -val) + ')';
635 }
636 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
637 if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
638 if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
639 if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
640 var o;
641 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
642 if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
643 if(fmt.match(/^[#?]+$/)) {
644 o = (""+val); if(val === 0) o = "";
645 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
646 }
647 if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
648 if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
649 if((r = fmt.match(dec1))) {
650o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
651 o = o.replace(/\.(\d*)$/,function($$, $1) {
652return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
653 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
654 }
655 fmt = fmt.replace(/^#+([0.])/, "$1");
656 if((r = fmt.match(/^(0*)\.(#*)$/))) {
657 return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
658 }
659 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
660 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
661 return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
662 }
663 if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
664 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
665 o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
666 ri = 0;
667 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
668 }
669 if(fmt.match(phone)) {
670 o = write_num_int(type, "##########", val);
671 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
672 }
673 var oa = "";
674 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
675 ri = Math.min(r[4].length,7);
676 ff = frac(aval, Math.pow(10,ri)-1, false);
677 o = "" + sign;
678 oa = write_num("n", r[1], ff[1]);
679 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
680 o += oa + r[2] + "/" + r[3];
681 oa = rpad_(ff[2],ri);
682 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
683 o += oa;
684 return o;
685 }
686 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
687 ri = Math.min(Math.max(r[1].length, r[4].length),7);
688 ff = frac(aval, Math.pow(10,ri)-1, true);
689 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));
690 }
691 if((r = fmt.match(/^[#0?]+$/))) {
692 o = "" + val;
693 if(fmt.length <= o.length) return o;
694 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
695 }
696 if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
697 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
698 ri = o.indexOf(".");
699 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
700 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
701 }
702 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
703 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);
704 }
705 switch(fmt) {
706 case "###,###":
707 case "##,###":
708 case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
709 default:
710 if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
711 }
712 throw new Error("unsupported format |" + fmt + "|");
713}
714return function write_num(type, fmt, val) {
715 return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
716};})();
717function split_fmt(fmt) {
718 var out = [];
719 var in_str = false/*, cc*/;
720 for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
721 case 34: /* '"' */
722 in_str = !in_str; break;
723 case 95: case 42: case 92: /* '_' '*' '\\' */
724 ++i; break;
725 case 59: /* ';' */
726 out[out.length] = fmt.substr(j,i-j);
727 j = i+1;
728 }
729 out[out.length] = fmt.substr(j);
730 if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
731 return out;
732}
733SSF._split = split_fmt;
734var abstime = /\[[HhMmSs]*\]/;
735function fmt_is_date(fmt) {
736 var i = 0, /*cc = 0,*/ c = "", o = "";
737 while(i < fmt.length) {
738 switch((c = fmt.charAt(i))) {
739 case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
740 case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
741 case '\\': i+=2; break;
742 case '_': i+=2; break;
743 case '@': ++i; break;
744 case 'B': case 'b':
745 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
746 /* falls through */
747 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
748 /* falls through */
749 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
750 case 'A': case 'a':
751 if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
752 if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
753 ++i; break;
754 case '[':
755 o = c;
756 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
757 if(o.match(abstime)) return true;
758 break;
759 case '.':
760 /* falls through */
761 case '0': case '#':
762 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 */}
763 break;
764 case '?': while(fmt.charAt(++i) === c){/* empty */} break;
765 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
766 case '(': case ')': ++i; break;
767 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
768 while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
769 case ' ': ++i; break;
770 default: ++i; break;
771 }
772 }
773 return false;
774}
775SSF.is_date = fmt_is_date;
776function eval_fmt(fmt, v, opts, flen) {
777 var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
778 var hr='H';
779 /* Tokenize */
780 while(i < fmt.length) {
781 switch((c = fmt.charAt(i))) {
782 case 'G': /* General */
783 if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
784 out[out.length] = {t:'G', v:'General'}; i+=7; break;
785 case '"': /* Literal text */
786 for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
787 out[out.length] = {t:'t', v:o}; ++i; break;
788 case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
789 out[out.length] = {t:t, v:w}; ++i; break;
790 case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
791 case '@': /* Text Placeholder */
792 out[out.length] = {t:'T', v:v}; ++i; break;
793 case 'B': case 'b':
794 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
795 if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
796 out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
797 }
798 /* falls through */
799 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
800 c = c.toLowerCase();
801 /* falls through */
802 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
803 if(v < 0) return "";
804 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
805 o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
806 if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
807 if(c === 'h') c = hr;
808 out[out.length] = {t:c, v:o}; lst = c; break;
809 case 'A': case 'a':
810 var q={t:c, v:c};
811 if(dt==null) dt=parse_date_code(v, opts);
812 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;}
813 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'; }
814 else { q.t = "t"; ++i; }
815 if(dt==null && q.t === 'T') return "";
816 out[out.length] = q; lst = c; break;
817 case '[':
818 o = c;
819 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
820 if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
821 if(o.match(abstime)) {
822 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
823 out[out.length] = {t:'Z', v:o.toLowerCase()};
824 lst = o.charAt(1);
825 } else if(o.indexOf("$") > -1) {
826 o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
827 if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
828 }
829 break;
830 /* Numbers */
831 case '.':
832 if(dt != null) {
833 o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
834 out[out.length] = {t:'s', v:o}; break;
835 }
836 /* falls through */
837 case '0': case '#':
838 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;
839 out[out.length] = {t:'n', v:o}; break;
840 case '?':
841 o = c; while(fmt.charAt(++i) === c) o+=c;
842 out[out.length] = {t:c, v:o}; lst = c; break;
843 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
844 case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
845 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
846 o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
847 out[out.length] = {t:'D', v:o}; break;
848 case ' ': out[out.length] = {t:c, v:c}; ++i; break;
849 default:
850 if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
851 out[out.length] = {t:'t', v:c}; ++i; break;
852 }
853 }
854 var bt = 0, ss0 = 0, ssm;
855 for(i=out.length-1, lst='t'; i >= 0; --i) {
856 switch(out[i].t) {
857 case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
858 case 's':
859 if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
860 if(bt < 3) bt = 3;
861 /* falls through */
862 case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
863 case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
864 case 'X': /*if(out[i].v === "B2");*/
865 break;
866 case 'Z':
867 if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
868 if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
869 if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
870 }
871 }
872 switch(bt) {
873 case 0: break;
874 case 1:
875if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
876 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
877 if(dt.M >= 60) { dt.M = 0; ++dt.H; }
878 break;
879 case 2:
880if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
881 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
882 break;
883 }
884 /* replace fields */
885 var nstr = "", jj;
886 for(i=0; i < out.length; ++i) {
887 switch(out[i].t) {
888 case 't': case 'T': case ' ': case 'D': break;
889 case 'X': out[i].v = ""; out[i].t = ";"; break;
890 case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
891out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
892 out[i].t = 't'; break;
893 case 'n': case '(': case '?':
894 jj = i+1;
895 while(out[jj] != null && (
896 (c=out[jj].t) === "?" || c === "D" ||
897 ((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
898 (out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
899 (c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
900 )) {
901 out[i].v += out[jj].v;
902 out[jj] = {v:"", t:";"}; ++jj;
903 }
904 nstr += out[i].v;
905 i = jj-1; break;
906 case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
907 }
908 }
909 var vv = "", myv, ostr;
910 if(nstr.length > 0) {
911 if(nstr.charCodeAt(0) == 40) /* '(' */ {
912 myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
913 ostr = write_num('(', nstr, myv);
914 } else {
915 myv = (v<0 && flen > 1 ? -v : v);
916 ostr = write_num('n', nstr, myv);
917 if(myv < 0 && out[0] && out[0].t == 't') {
918 ostr = ostr.substr(1);
919 out[0].v = "-" + out[0].v;
920 }
921 }
922 jj=ostr.length-1;
923 var decpt = out.length;
924 for(i=0; i < out.length; ++i) if(out[i] != null && out[i].t != 't' && out[i].v.indexOf(".") > -1) { decpt = i; break; }
925 var lasti=out.length;
926 if(decpt === out.length && ostr.indexOf("E") === -1) {
927 for(i=out.length-1; i>= 0;--i) {
928 if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
929 if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
930 else if(jj < 0) out[i].v = "";
931 else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
932 out[i].t = 't';
933 lasti = i;
934 }
935 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
936 }
937 else if(decpt !== out.length && ostr.indexOf("E") === -1) {
938 jj = ostr.indexOf(".")-1;
939 for(i=decpt; i>= 0; --i) {
940 if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
941 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
942 vv = out[i].v.substr(j+1);
943 for(; j>=0; --j) {
944 if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
945 }
946 out[i].v = vv;
947 out[i].t = 't';
948 lasti = i;
949 }
950 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
951 jj = ostr.indexOf(".")+1;
952 for(i=decpt; i<out.length; ++i) {
953 if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
954 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
955 vv = out[i].v.substr(0,j);
956 for(; j<out[i].v.length; ++j) {
957 if(jj<ostr.length) vv += ostr.charAt(jj++);
958 }
959 out[i].v = vv;
960 out[i].t = 't';
961 lasti = i;
962 }
963 }
964 }
965 for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
966 myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
967 out[i].v = write_num(out[i].t, out[i].v, myv);
968 out[i].t = 't';
969 }
970 var retval = "";
971 for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
972 return retval;
973}
974SSF._eval = eval_fmt;
975var cfregex = /\[[=<>]/;
976var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
977function chkcond(v, rr) {
978 if(rr == null) return false;
979 var thresh = parseFloat(rr[2]);
980 switch(rr[1]) {
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 case "<=": if(v <= thresh) return true; break;
987 }
988 return false;
989}
990function choose_fmt(f, v) {
991 var fmt = split_fmt(f);
992 var l = fmt.length, lat = fmt[l-1].indexOf("@");
993 if(l<4 && lat>-1) --l;
994 if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
995 if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
996 switch(fmt.length) {
997 case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
998 case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
999 case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
1000 case 4: break;
1001 }
1002 var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
1003 if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
1004 if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
1005 var m1 = fmt[0].match(cfregex2);
1006 var m2 = fmt[1].match(cfregex2);
1007 return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
1008 }
1009 return [l, ff];
1010}
1011function format(fmt,v,o) {
1012 if(o == null) o = {};
1013 var sfmt = "";
1014 switch(typeof fmt) {
1015 case "string":
1016 if(fmt == "m/d/yy" && o.dateNF) sfmt = o.dateNF;
1017 else sfmt = fmt;
1018 break;
1019 case "number":
1020 if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
1021 else sfmt = (o.table != null ? (o.table) : table_fmt)[fmt];
1022 break;
1023 }
1024 if(isgeneral(sfmt,0)) return general_fmt(v, o);
1025 if(v instanceof Date) v = datenum_local(v, o.date1904);
1026 var f = choose_fmt(sfmt, v);
1027 if(isgeneral(f[1])) return general_fmt(v, o);
1028 if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
1029 else if(v === "" || v == null) return "";
1030 return eval_fmt(f[1], v, o, f[0]);
1031}
1032function load_entry(fmt, idx) {
1033 if(typeof idx != 'number') {
1034 idx = +idx || -1;
1035for(var i = 0; i < 0x0188; ++i) {
1036if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
1037 if(table_fmt[i] == fmt) { idx = i; break; }
1038 }
1039if(idx < 0) idx = 0x187;
1040 }
1041table_fmt[idx] = fmt;
1042 return idx;
1043}
1044SSF.load = load_entry;
1045SSF._table = table_fmt;
1046SSF.get_table = function get_table() { return table_fmt; };
1047SSF.load_table = function load_table(tbl) {
1048 for(var i=0; i!=0x0188; ++i)
1049 if(tbl[i] !== undefined) load_entry(tbl[i], i);
1050};
1051SSF.init_table = init_table;
1052SSF.format = format;
1053};
1054make_ssf(SSF);
1055/* map from xlml named formats to SSF TODO: localize */
1056var XLMLFormatMap/*{[string]:string}*/ = ({
1057 "General Number": "General",
1058 "General Date": SSF._table[22],
1059 "Long Date": "dddd, mmmm dd, yyyy",
1060 "Medium Date": SSF._table[15],
1061 "Short Date": SSF._table[14],
1062 "Long Time": SSF._table[19],
1063 "Medium Time": SSF._table[18],
1064 "Short Time": SSF._table[20],
1065 "Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1066 "Fixed": SSF._table[2],
1067 "Standard": SSF._table[4],
1068 "Percent": SSF._table[10],
1069 "Scientific": SSF._table[11],
1070 "Yes/No": '"Yes";"Yes";"No";@',
1071 "True/False": '"True";"True";"False";@',
1072 "On/Off": '"Yes";"Yes";"No";@'
1073});
1074
1075var SSFImplicit/*{[number]:string}*/ = ({
1076 "5": '"$"#,##0_);\\("$"#,##0\\)',
1077 "6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1078 "7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1079 "8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1080 "23": 'General', "24": 'General', "25": 'General', "26": 'General',
1081 "27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
1082 "32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
1083 "36": 'm/d/yy',
1084 "41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
1085 "42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
1086 "43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
1087 "44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
1088 "50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
1089 "55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
1090 "59": '0',
1091 "60": '0.00',
1092 "61": '#,##0',
1093 "62": '#,##0.00',
1094 "63": '"$"#,##0_);\\("$"#,##0\\)',
1095 "64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1096 "65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1097 "66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1098 "67": '0%',
1099 "68": '0.00%',
1100 "69": '# ?/?',
1101 "70": '# ??/??',
1102 "71": 'm/d/yy',
1103 "72": 'm/d/yy',
1104 "73": 'd-mmm-yy',
1105 "74": 'd-mmm',
1106 "75": 'mmm-yy',
1107 "76": 'h:mm',
1108 "77": 'h:mm:ss',
1109 "78": 'm/d/yy h:mm',
1110 "79": 'mm:ss',
1111 "80": '[h]:mm:ss',
1112 "81": 'mmss.0'
1113});
1114
1115/* dateNF parse TODO: move to SSF */
1116var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
1117function dateNF_regex(dateNF) {
1118 var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF;
1119 fmt = fmt.replace(dateNFregex, "(\\d+)");
1120 return new RegExp("^" + fmt + "$");
1121}
1122function dateNF_fix(str, dateNF, match) {
1123 var Y = -1, m = -1, d = -1, H = -1, M = -1, S = -1;
1124 (dateNF.match(dateNFregex)||[]).forEach(function(n, i) {
1125 var v = parseInt(match[i+1], 10);
1126 switch(n.toLowerCase().charAt(0)) {
1127 case 'y': Y = v; break; case 'd': d = v; break;
1128 case 'h': H = v; break; case 's': S = v; break;
1129 case 'm': if(H >= 0) M = v; else m = v; break;
1130 }
1131 });
1132 if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
1133 var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
1134 if(datestr.length == 7) datestr = "0" + datestr;
1135 if(datestr.length == 8) datestr = "20" + datestr;
1136 var timestr = (("00" + (H>=0?H:0)).slice(-2) + ":" + ("00" + (M>=0?M:0)).slice(-2) + ":" + ("00" + (S>=0?S:0)).slice(-2));
1137 if(H == -1 && M == -1 && S == -1) return datestr;
1138 if(Y == -1 && m == -1 && d == -1) return timestr;
1139 return datestr + "T" + timestr;
1140}
1141
1142var DO_NOT_EXPORT_CFB = true;
1143/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
1144/* vim: set ts=2: */
1145/*jshint eqnull:true */
1146/*exported CFB */
1147/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
1148
1149/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
1150/* vim: set ts=2: */
1151/*exported CRC32 */
1152var CRC32;
1153(function (factory) {
1154 /*jshint ignore:start */
1155 /*eslint-disable */
1156 factory(CRC32 = {});
1157 /*eslint-enable */
1158 /*jshint ignore:end */
1159}(function(CRC32) {
1160CRC32.version = '1.2.0';
1161/* see perf/crc32table.js */
1162/*global Int32Array */
1163function signed_crc_table() {
1164 var c = 0, table = new Array(256);
1165
1166 for(var n =0; n != 256; ++n){
1167 c = n;
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 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1176 table[n] = c;
1177 }
1178
1179 return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
1180}
1181
1182var T = signed_crc_table();
1183function crc32_bstr(bstr, seed) {
1184 var C = seed ^ -1, L = bstr.length - 1;
1185 for(var i = 0; i < L;) {
1186 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1187 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1188 }
1189 if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
1190 return C ^ -1;
1191}
1192
1193function crc32_buf(buf, seed) {
1194 if(buf.length > 10000) return crc32_buf_8(buf, seed);
1195 var C = seed ^ -1, L = buf.length - 3;
1196 for(var i = 0; i < L;) {
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 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1201 }
1202 while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1203 return C ^ -1;
1204}
1205
1206function crc32_buf_8(buf, seed) {
1207 var C = seed ^ -1, L = buf.length - 7;
1208 for(var i = 0; i < L;) {
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 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1217 }
1218 while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1219 return C ^ -1;
1220}
1221
1222function crc32_str(str, seed) {
1223 var C = seed ^ -1;
1224 for(var i = 0, L=str.length, c, d; i < L;) {
1225 c = str.charCodeAt(i++);
1226 if(c < 0x80) {
1227 C = (C>>>8) ^ T[(C ^ c)&0xFF];
1228 } else if(c < 0x800) {
1229 C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
1230 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1231 } else if(c >= 0xD800 && c < 0xE000) {
1232 c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
1233 C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
1234 C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
1235 C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
1236 C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
1237 } else {
1238 C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
1239 C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
1240 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1241 }
1242 }
1243 return C ^ -1;
1244}
1245CRC32.table = T;
1246CRC32.bstr = crc32_bstr;
1247CRC32.buf = crc32_buf;
1248CRC32.str = crc32_str;
1249}));
1250/* [MS-CFB] v20171201 */
1251var CFB = (function _CFB(){
1252var exports = {};
1253exports.version = '1.1.2';
1254/* [MS-CFB] 2.6.4 */
1255function namecmp(l, r) {
1256 var L = l.split("/"), R = r.split("/");
1257 for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
1258 if((c = L[i].length - R[i].length)) return c;
1259 if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
1260 }
1261 return L.length - R.length;
1262}
1263function dirname(p) {
1264 if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
1265 var c = p.lastIndexOf("/");
1266 return (c === -1) ? p : p.slice(0, c+1);
1267}
1268
1269function filename(p) {
1270 if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
1271 var c = p.lastIndexOf("/");
1272 return (c === -1) ? p : p.slice(c+1);
1273}
1274/* -------------------------------------------------------------------------- */
1275/* DOS Date format:
1276 high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
1277 add 1980 to stored year
1278 stored second should be doubled
1279*/
1280
1281/* write JS date to buf as a DOS date */
1282function write_dos_date(buf, date) {
1283 if(typeof date === "string") date = new Date(date);
1284 var hms = date.getHours();
1285 hms = hms << 6 | date.getMinutes();
1286 hms = hms << 5 | (date.getSeconds()>>>1);
1287 buf.write_shift(2, hms);
1288 var ymd = (date.getFullYear() - 1980);
1289 ymd = ymd << 4 | (date.getMonth()+1);
1290 ymd = ymd << 5 | date.getDate();
1291 buf.write_shift(2, ymd);
1292}
1293
1294/* read four bytes from buf and interpret as a DOS date */
1295function parse_dos_date(buf) {
1296 var hms = buf.read_shift(2) & 0xFFFF;
1297 var ymd = buf.read_shift(2) & 0xFFFF;
1298 var val = new Date();
1299 var d = ymd & 0x1F; ymd >>>= 5;
1300 var m = ymd & 0x0F; ymd >>>= 4;
1301 val.setMilliseconds(0);
1302 val.setFullYear(ymd + 1980);
1303 val.setMonth(m-1);
1304 val.setDate(d);
1305 var S = hms & 0x1F; hms >>>= 5;
1306 var M = hms & 0x3F; hms >>>= 6;
1307 val.setHours(hms);
1308 val.setMinutes(M);
1309 val.setSeconds(S<<1);
1310 return val;
1311}
1312function parse_extra_field(blob) {
1313 prep_blob(blob, 0);
1314 var o = {};
1315 var flags = 0;
1316 while(blob.l <= blob.length - 4) {
1317 var type = blob.read_shift(2);
1318 var sz = blob.read_shift(2), tgt = blob.l + sz;
1319 var p = {};
1320 switch(type) {
1321 /* UNIX-style Timestamps */
1322 case 0x5455: {
1323 flags = blob.read_shift(1);
1324 if(flags & 1) p.mtime = blob.read_shift(4);
1325 /* for some reason, CD flag corresponds to LFH */
1326 if(sz > 5) {
1327 if(flags & 2) p.atime = blob.read_shift(4);
1328 if(flags & 4) p.ctime = blob.read_shift(4);
1329 }
1330 if(p.mtime) p.mt = new Date(p.mtime*1000);
1331 }
1332 break;
1333 }
1334 blob.l = tgt;
1335 o[type] = p;
1336 }
1337 return o;
1338}
1339var fs;
1340function get_fs() { return fs || (fs = require('fs')); }
1341function parse(file, options) {
1342if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
1343if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
1344var mver = 3;
1345var ssz = 512;
1346var nmfs = 0; // number of mini FAT sectors
1347var difat_sec_cnt = 0;
1348var dir_start = 0;
1349var minifat_start = 0;
1350var difat_start = 0;
1351
1352var fat_addrs = []; // locations of FAT sectors
1353
1354/* [MS-CFB] 2.2 Compound File Header */
1355var blob = file.slice(0,512);
1356prep_blob(blob, 0);
1357
1358/* major version */
1359var mv = check_get_mver(blob);
1360mver = mv[0];
1361switch(mver) {
1362 case 3: ssz = 512; break; case 4: ssz = 4096; break;
1363 case 0: if(mv[1] == 0) return parse_zip(file, options);
1364 /* falls through */
1365 default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
1366}
1367
1368/* reprocess header */
1369if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
1370/* Save header for final object */
1371var header = file.slice(0,ssz);
1372
1373check_shifts(blob, mver);
1374
1375// Number of Directory Sectors
1376var dir_cnt = blob.read_shift(4, 'i');
1377if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
1378
1379// Number of FAT Sectors
1380blob.l += 4;
1381
1382// First Directory Sector Location
1383dir_start = blob.read_shift(4, 'i');
1384
1385// Transaction Signature
1386blob.l += 4;
1387
1388// Mini Stream Cutoff Size
1389blob.chk('00100000', 'Mini Stream Cutoff Size: ');
1390
1391// First Mini FAT Sector Location
1392minifat_start = blob.read_shift(4, 'i');
1393
1394// Number of Mini FAT Sectors
1395nmfs = blob.read_shift(4, 'i');
1396
1397// First DIFAT sector location
1398difat_start = blob.read_shift(4, 'i');
1399
1400// Number of DIFAT Sectors
1401difat_sec_cnt = blob.read_shift(4, 'i');
1402
1403// Grab FAT Sector Locations
1404for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
1405 q = blob.read_shift(4, 'i');
1406 if(q<0) break;
1407 fat_addrs[j] = q;
1408}
1409
1410/** Break the file up into sectors */
1411var sectors = sectorify(file, ssz);
1412
1413sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
1414
1415/** Chains */
1416var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);
1417
1418sector_list[dir_start].name = "!Directory";
1419if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
1420sector_list[fat_addrs[0]].name = "!FAT";
1421sector_list.fat_addrs = fat_addrs;
1422sector_list.ssz = ssz;
1423
1424/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1425var files = {}, Paths = [], FileIndex = [], FullPaths = [];
1426read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
1427
1428build_full_paths(FileIndex, FullPaths, Paths);
1429Paths.shift();
1430
1431var o = {
1432 FileIndex: FileIndex,
1433 FullPaths: FullPaths
1434};
1435
1436// $FlowIgnore
1437if(options && options.raw) o.raw = {header: header, sectors: sectors};
1438return o;
1439} // parse
1440
1441/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
1442function check_get_mver(blob) {
1443 if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
1444 // header signature 8
1445 blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
1446
1447 // clsid 16
1448 //blob.chk(HEADER_CLSID, 'CLSID: ');
1449 blob.l += 16;
1450
1451 // minor version 2
1452 var mver = blob.read_shift(2, 'u');
1453
1454 return [blob.read_shift(2,'u'), mver];
1455}
1456function check_shifts(blob, mver) {
1457 var shift = 0x09;
1458
1459 // Byte Order
1460 //blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff
1461 blob.l += 2;
1462
1463 // Sector Shift
1464 switch((shift = blob.read_shift(2))) {
1465 case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;
1466 case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;
1467 default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);
1468 }
1469
1470 // Mini Sector Shift
1471 blob.chk('0600', 'Mini Sector Shift: ');
1472
1473 // Reserved
1474 blob.chk('000000000000', 'Reserved: ');
1475}
1476
1477/** Break the file up into sectors */
1478function sectorify(file, ssz) {
1479 var nsectors = Math.ceil(file.length/ssz)-1;
1480 var sectors = [];
1481 for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
1482 sectors[nsectors-1] = file.slice(nsectors*ssz);
1483 return sectors;
1484}
1485
1486/* [MS-CFB] 2.6.4 Red-Black Tree */
1487function build_full_paths(FI, FP, Paths) {
1488 var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
1489 var dad = [], q = [];
1490
1491 for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
1492
1493 for(; j < q.length; ++j) {
1494 i = q[j];
1495 L = FI[i].L; R = FI[i].R; C = FI[i].C;
1496 if(dad[i] === i) {
1497 if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
1498 if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
1499 }
1500 if(C !== -1 /*NOSTREAM*/) dad[C] = i;
1501 if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
1502 if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
1503 }
1504 for(i=1; i < pl; ++i) if(dad[i] === i) {
1505 if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
1506 else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
1507 }
1508
1509 for(i=1; i < pl; ++i) {
1510 if(FI[i].type === 0 /* unknown */) continue;
1511 j = i;
1512 if(j != dad[j]) do {
1513 j = dad[j];
1514 FP[i] = FP[j] + "/" + FP[i];
1515 } while (j !== 0 && -1 !== dad[j] && j != dad[j]);
1516 dad[i] = -1;
1517 }
1518
1519 FP[0] += "/";
1520 for(i=1; i < pl; ++i) {
1521 if(FI[i].type !== 2 /* stream */) FP[i] += "/";
1522 }
1523}
1524
1525function get_mfat_entry(entry, payload, mini) {
1526 var start = entry.start, size = entry.size;
1527 //return (payload.slice(start*MSSZ, start*MSSZ + size));
1528 var o = [];
1529 var idx = start;
1530 while(mini && size > 0 && idx >= 0) {
1531 o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
1532 size -= MSSZ;
1533 idx = __readInt32LE(mini, idx * 4);
1534 }
1535 if(o.length === 0) return (new_buf(0));
1536 return (bconcat(o).slice(0, entry.size));
1537}
1538
1539/** Chase down the rest of the DIFAT chain to build a comprehensive list
1540 DIFAT chains by storing the next sector number as the last 32 bits */
1541function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
1542 var q = ENDOFCHAIN;
1543 if(idx === ENDOFCHAIN) {
1544 if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
1545 } else if(idx !== -1 /*FREESECT*/) {
1546 var sector = sectors[idx], m = (ssz>>>2)-1;
1547 if(!sector) return;
1548 for(var i = 0; i < m; ++i) {
1549 if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1550 fat_addrs.push(q);
1551 }
1552 sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
1553 }
1554}
1555
1556/** Follow the linked list of sectors for a given starting point */
1557function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
1558 var buf = [], buf_chain = [];
1559 if(!chkd) chkd = [];
1560 var modulus = ssz - 1, j = 0, jj = 0;
1561 for(j=start; j>=0;) {
1562 chkd[j] = true;
1563 buf[buf.length] = j;
1564 buf_chain.push(sectors[j]);
1565 var addr = fat_addrs[Math.floor(j*4/ssz)];
1566 jj = ((j*4) & modulus);
1567 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1568 if(!sectors[addr]) break;
1569 j = __readInt32LE(sectors[addr], jj);
1570 }
1571 return {nodes: buf, data:__toBuffer([buf_chain])};
1572}
1573
1574/** Chase down the sector linked lists */
1575function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
1576 var sl = sectors.length, sector_list = ([]);
1577 var chkd = [], buf = [], buf_chain = [];
1578 var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
1579 for(i=0; i < sl; ++i) {
1580 buf = ([]);
1581 k = (i + dir_start); if(k >= sl) k-=sl;
1582 if(chkd[k]) continue;
1583 buf_chain = [];
1584 for(j=k; j>=0;) {
1585 chkd[j] = true;
1586 buf[buf.length] = j;
1587 buf_chain.push(sectors[j]);
1588 var addr = fat_addrs[Math.floor(j*4/ssz)];
1589 jj = ((j*4) & modulus);
1590 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1591 if(!sectors[addr]) break;
1592 j = __readInt32LE(sectors[addr], jj);
1593 }
1594 sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
1595 }
1596 return sector_list;
1597}
1598
1599/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1600function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {
1601 var minifat_store = 0, pl = (Paths.length?2:0);
1602 var sector = sector_list[dir_start].data;
1603 var i = 0, namelen = 0, name;
1604 for(; i < sector.length; i+= 128) {
1605 var blob = sector.slice(i, i+128);
1606 prep_blob(blob, 64);
1607 namelen = blob.read_shift(2);
1608 name = __utf16le(blob,0,namelen-pl);
1609 Paths.push(name);
1610 var o = ({
1611 name: name,
1612 type: blob.read_shift(1),
1613 color: blob.read_shift(1),
1614 L: blob.read_shift(4, 'i'),
1615 R: blob.read_shift(4, 'i'),
1616 C: blob.read_shift(4, 'i'),
1617 clsid: blob.read_shift(16),
1618 state: blob.read_shift(4, 'i'),
1619 start: 0,
1620 size: 0
1621 });
1622 var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1623 if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1624 var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1625 if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1626 o.start = blob.read_shift(4, 'i');
1627 o.size = blob.read_shift(4, 'i');
1628 if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1629 if(o.type === 5) { /* root */
1630 minifat_store = o.start;
1631 if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1632 /*minifat_size = o.size;*/
1633 } else if(o.size >= 4096 /* MSCSZ */) {
1634 o.storage = 'fat';
1635 if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1636 sector_list[o.start].name = o.name;
1637 o.content = (sector_list[o.start].data.slice(0,o.size));
1638 } else {
1639 o.storage = 'minifat';
1640 if(o.size < 0) o.size = 0;
1641 else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1642 o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1643 }
1644 }
1645 if(o.content) prep_blob(o.content, 0);
1646 files[name] = o;
1647 FileIndex.push(o);
1648 }
1649}
1650
1651function read_date(blob, offset) {
1652 return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1653}
1654
1655function read_file(filename, options) {
1656 get_fs();
1657 return parse(fs.readFileSync(filename), options);
1658}
1659
1660function read(blob, options) {
1661 switch(options && options.type || "base64") {
1662 case "file": return read_file(blob, options);
1663 case "base64": return parse(s2a(Base64.decode(blob)), options);
1664 case "binary": return parse(s2a(blob), options);
1665 }
1666 return parse(blob, options);
1667}
1668
1669function init_cfb(cfb, opts) {
1670 var o = opts || {}, root = o.root || "Root Entry";
1671 if(!cfb.FullPaths) cfb.FullPaths = [];
1672 if(!cfb.FileIndex) cfb.FileIndex = [];
1673 if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1674 if(cfb.FullPaths.length === 0) {
1675 cfb.FullPaths[0] = root + "/";
1676 cfb.FileIndex[0] = ({ name: root, type: 5 });
1677 }
1678 if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1679 seed_cfb(cfb);
1680}
1681function seed_cfb(cfb) {
1682 var nm = "\u0001Sh33tJ5";
1683 if(CFB.find(cfb, "/" + nm)) return;
1684 var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1685 cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));
1686 cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1687 rebuild_cfb(cfb);
1688}
1689function rebuild_cfb(cfb, f) {
1690 init_cfb(cfb);
1691 var gc = false, s = false;
1692 for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1693 var _file = cfb.FileIndex[i];
1694 switch(_file.type) {
1695 case 0:
1696 if(s) gc = true;
1697 else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1698 break;
1699 case 1: case 2: case 5:
1700 s = true;
1701 if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1702 if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1703 break;
1704 default: gc = true; break;
1705 }
1706 }
1707 if(!gc && !f) return;
1708
1709 var now = new Date(1987, 1, 19), j = 0;
1710 var data = [];
1711 for(i = 0; i < cfb.FullPaths.length; ++i) {
1712 if(cfb.FileIndex[i].type === 0) continue;
1713 data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1714 }
1715 for(i = 0; i < data.length; ++i) {
1716 var dad = dirname(data[i][0]);
1717 s = false;
1718 for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1719 if(!s) data.push([dad, ({
1720 name: filename(dad).replace("/",""),
1721 type: 1,
1722 clsid: HEADER_CLSID,
1723 ct: now, mt: now,
1724 content: null
1725 })]);
1726 }
1727
1728 data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1729 cfb.FullPaths = []; cfb.FileIndex = [];
1730 for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1731 for(i = 0; i < data.length; ++i) {
1732 var elt = cfb.FileIndex[i];
1733 var nm = cfb.FullPaths[i];
1734
1735 elt.name = filename(nm).replace("/","");
1736 elt.L = elt.R = elt.C = -(elt.color = 1);
1737 elt.size = elt.content ? elt.content.length : 0;
1738 elt.start = 0;
1739 elt.clsid = (elt.clsid || HEADER_CLSID);
1740 if(i === 0) {
1741 elt.C = data.length > 1 ? 1 : -1;
1742 elt.size = 0;
1743 elt.type = 5;
1744 } else if(nm.slice(-1) == "/") {
1745 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1746 elt.C = j >= data.length ? -1 : j;
1747 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1748 elt.R = j >= data.length ? -1 : j;
1749 elt.type = 1;
1750 } else {
1751 if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1752 elt.type = 2;
1753 }
1754 }
1755
1756}
1757
1758function _write(cfb, options) {
1759 var _opts = options || {};
1760 rebuild_cfb(cfb);
1761 if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
1762 var L = (function(cfb){
1763 var mini_size = 0, fat_size = 0;
1764 for(var i = 0; i < cfb.FileIndex.length; ++i) {
1765 var file = cfb.FileIndex[i];
1766 if(!file.content) continue;
1767var flen = file.content.length;
1768 if(flen > 0){
1769 if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1770 else fat_size += (flen + 0x01FF) >> 9;
1771 }
1772 }
1773 var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1774 var mini_cnt = (mini_size + 7) >> 3;
1775 var mfat_cnt = (mini_size + 0x7F) >> 7;
1776 var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1777 var fat_cnt = (fat_base + 0x7F) >> 7;
1778 var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1779 while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1780 var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1781 cfb.FileIndex[0].size = mini_size << 6;
1782 L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1783 return L;
1784 })(cfb);
1785 var o = new_buf(L[7] << 9);
1786 var i = 0, T = 0;
1787 {
1788 for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1789 for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1790 o.write_shift(2, 0x003E);
1791 o.write_shift(2, 0x0003);
1792 o.write_shift(2, 0xFFFE);
1793 o.write_shift(2, 0x0009);
1794 o.write_shift(2, 0x0006);
1795 for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1796 o.write_shift(4, 0);
1797 o.write_shift(4, L[2]);
1798 o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1799 o.write_shift(4, 0);
1800 o.write_shift(4, 1<<12);
1801 o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1802 o.write_shift(4, L[3]);
1803 o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1804 o.write_shift(4, L[1]);
1805 for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1806 }
1807 if(L[1]) {
1808 for(T = 0; T < L[1]; ++T) {
1809 for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1810 o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1811 }
1812 }
1813 var chainit = function(w) {
1814 for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1815 if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1816 };
1817 T = i = 0;
1818 for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1819 for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1820 chainit(L[3]);
1821 chainit(L[4]);
1822 var j = 0, flen = 0;
1823 var file = cfb.FileIndex[0];
1824 for(; j < cfb.FileIndex.length; ++j) {
1825 file = cfb.FileIndex[j];
1826 if(!file.content) continue;
1827flen = file.content.length;
1828 if(flen < 0x1000) continue;
1829 file.start = T;
1830 chainit((flen + 0x01FF) >> 9);
1831 }
1832 chainit((L[6] + 7) >> 3);
1833 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1834 T = i = 0;
1835 for(j = 0; j < cfb.FileIndex.length; ++j) {
1836 file = cfb.FileIndex[j];
1837 if(!file.content) continue;
1838flen = file.content.length;
1839 if(!flen || flen >= 0x1000) continue;
1840 file.start = T;
1841 chainit((flen + 0x3F) >> 6);
1842 }
1843 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1844 for(i = 0; i < L[4]<<2; ++i) {
1845 var nm = cfb.FullPaths[i];
1846 if(!nm || nm.length === 0) {
1847 for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1848 for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1849 for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1850 continue;
1851 }
1852 file = cfb.FileIndex[i];
1853 if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1854 var _nm = (i === 0 && _opts.root) || file.name;
1855 flen = 2*(_nm.length+1);
1856 o.write_shift(64, _nm, "utf16le");
1857 o.write_shift(2, flen);
1858 o.write_shift(1, file.type);
1859 o.write_shift(1, file.color);
1860 o.write_shift(-4, file.L);
1861 o.write_shift(-4, file.R);
1862 o.write_shift(-4, file.C);
1863 if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1864 else o.write_shift(16, file.clsid, "hex");
1865 o.write_shift(4, file.state || 0);
1866 o.write_shift(4, 0); o.write_shift(4, 0);
1867 o.write_shift(4, 0); o.write_shift(4, 0);
1868 o.write_shift(4, file.start);
1869 o.write_shift(4, file.size); o.write_shift(4, 0);
1870 }
1871 for(i = 1; i < cfb.FileIndex.length; ++i) {
1872 file = cfb.FileIndex[i];
1873if(file.size >= 0x1000) {
1874 o.l = (file.start+1) << 9;
1875 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1876 for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1877 }
1878 }
1879 for(i = 1; i < cfb.FileIndex.length; ++i) {
1880 file = cfb.FileIndex[i];
1881if(file.size > 0 && file.size < 0x1000) {
1882 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1883 for(; j & 0x3F; ++j) o.write_shift(1, 0);
1884 }
1885 }
1886 while(o.l < o.length) o.write_shift(1, 0);
1887 return o;
1888}
1889/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1890function find(cfb, path) {
1891 var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1892 var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1893 var k = false;
1894 if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1895 else k = path.indexOf("/") !== -1;
1896 var UCPath = path.toUpperCase();
1897 var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1898 if(w !== -1) return cfb.FileIndex[w];
1899
1900 var m = !UCPath.match(chr1);
1901 UCPath = UCPath.replace(chr0,'');
1902 if(m) UCPath = UCPath.replace(chr1,'!');
1903 for(w = 0; w < UCFullPaths.length; ++w) {
1904 if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1905 if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1906 }
1907 return null;
1908}
1909/** CFB Constants */
1910var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1911//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1912/* 2.1 Compound File Sector Numbers and Types */
1913var ENDOFCHAIN = -2;
1914/* 2.2 Compound File Header */
1915var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1916var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1917var HEADER_CLSID = '00000000000000000000000000000000';
1918var consts = {
1919 /* 2.1 Compund File Sector Numbers and Types */
1920 MAXREGSECT: -6,
1921 DIFSECT: -4,
1922 FATSECT: -3,
1923 ENDOFCHAIN: ENDOFCHAIN,
1924 FREESECT: -1,
1925 /* 2.2 Compound File Header */
1926 HEADER_SIGNATURE: HEADER_SIGNATURE,
1927 HEADER_MINOR_VERSION: '3e00',
1928 MAXREGSID: -6,
1929 NOSTREAM: -1,
1930 HEADER_CLSID: HEADER_CLSID,
1931 /* 2.6.1 Compound File Directory Entry */
1932 EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
1933};
1934
1935function write_file(cfb, filename, options) {
1936 get_fs();
1937 var o = _write(cfb, options);
1938fs.writeFileSync(filename, o);
1939}
1940
1941function a2s(o) {
1942 var out = new Array(o.length);
1943 for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
1944 return out.join("");
1945}
1946
1947function write(cfb, options) {
1948 var o = _write(cfb, options);
1949 switch(options && options.type) {
1950 case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
1951 case "binary": return a2s(o);
1952 case "base64": return Base64.encode(a2s(o));
1953 }
1954 return o;
1955}
1956/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
1957var _zlib;
1958function use_zlib(zlib) { try {
1959 var InflateRaw = zlib.InflateRaw;
1960 var InflRaw = new InflateRaw();
1961 InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
1962 if(InflRaw.bytesRead) _zlib = zlib;
1963 else throw new Error("zlib does not expose bytesRead");
1964} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
1965
1966function _inflateRawSync(payload, usz) {
1967 if(!_zlib) return _inflate(payload, usz);
1968 var InflateRaw = _zlib.InflateRaw;
1969 var InflRaw = new InflateRaw();
1970 var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
1971 payload.l += InflRaw.bytesRead;
1972 return out;
1973}
1974
1975function _deflateRawSync(payload) {
1976 return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
1977}
1978var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
1979
1980/* 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 ]; */
1981var 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 ];
1982
1983/* 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 ]; */
1984var 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 ];
1985
1986function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
1987
1988var use_typed_arrays = typeof Uint8Array !== 'undefined';
1989
1990var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
1991for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
1992
1993function bit_swap_n(n, b) {
1994 var rev = bitswap8[n & 0xFF];
1995 if(b <= 8) return rev >>> (8-b);
1996 rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
1997 if(b <= 16) return rev >>> (16-b);
1998 rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
1999 return rev >>> (24-b);
2000}
2001
2002/* helpers for unaligned bit reads */
2003function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
2004function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
2005function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
2006function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
2007function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
2008
2009/* works up to n = 3 * 8 + 1 = 25 */
2010function read_bits_n(buf, bl, n) {
2011 var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
2012 var v = buf[h] >>> w;
2013 if(n < 8 - w) return v & f;
2014 v |= buf[h+1]<<(8-w);
2015 if(n < 16 - w) return v & f;
2016 v |= buf[h+2]<<(16-w);
2017 if(n < 24 - w) return v & f;
2018 v |= buf[h+3]<<(24-w);
2019 return v & f;
2020}
2021
2022/* until ArrayBuffer#realloc is a thing, fake a realloc */
2023function realloc(b, sz) {
2024 var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
2025 if(L >= sz) return b;
2026 if(has_buf) {
2027 var o = new_unsafe_buf(M);
2028 // $FlowIgnore
2029 if(b.copy) b.copy(o);
2030 else for(; i < b.length; ++i) o[i] = b[i];
2031 return o;
2032 } else if(use_typed_arrays) {
2033 var a = new Uint8Array(M);
2034 if(a.set) a.set(b);
2035 else for(; i < b.length; ++i) a[i] = b[i];
2036 return a;
2037 }
2038 b.length = M;
2039 return b;
2040}
2041
2042/* zero-filled arrays for older browsers */
2043function zero_fill_array(n) {
2044 var o = new Array(n);
2045 for(var i = 0; i < n; ++i) o[i] = 0;
2046 return o;
2047}var _deflate = (function() {
2048var _deflateRaw = (function() {
2049 return function deflateRaw(data, out) {
2050 var boff = 0;
2051 while(boff < data.length) {
2052 var L = Math.min(0xFFFF, data.length - boff);
2053 var h = boff + L == data.length;
2054 /* TODO: this is only type 0 stored */
2055 out.write_shift(1, +h);
2056 out.write_shift(2, L);
2057 out.write_shift(2, (~L) & 0xFFFF);
2058 while(L-- > 0) out[out.l++] = data[boff++];
2059 }
2060 return out.l;
2061 };
2062})();
2063
2064return function(data) {
2065 var buf = new_buf(50+Math.floor(data.length*1.1));
2066 var off = _deflateRaw(data, buf);
2067 return buf.slice(0, off);
2068};
2069})();
2070/* modified inflate function also moves original read head */
2071
2072/* build tree (used for literals and lengths) */
2073function build_tree(clens, cmap, MAX) {
2074 var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
2075
2076 var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2077 for(i = 0; i < 32; ++i) bl_count[i] = 0;
2078
2079 for(i = L; i < MAX; ++i) clens[i] = 0;
2080 L = clens.length;
2081
2082 var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
2083
2084 /* build code tree */
2085 for(i = 0; i < L; ++i) {
2086 bl_count[(w = clens[i])]++;
2087 if(maxlen < w) maxlen = w;
2088 ctree[i] = 0;
2089 }
2090 bl_count[0] = 0;
2091 for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
2092 for(i = 0; i < L; ++i) {
2093 ccode = clens[i];
2094 if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
2095 }
2096
2097 /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
2098 var cleni = 0;
2099 for(i = 0; i < L; ++i) {
2100 cleni = clens[i];
2101 if(cleni != 0) {
2102 ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
2103 for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
2104 cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
2105 }
2106 }
2107 return maxlen;
2108}
2109
2110var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
2111var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2112if(!use_typed_arrays) {
2113 for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
2114 for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
2115}
2116(function() {
2117 var dlens = [];
2118 var i = 0;
2119 for(;i<32; i++) dlens.push(5);
2120 build_tree(dlens, fix_dmap, 32);
2121
2122 var clens = [];
2123 i = 0;
2124 for(; i<=143; i++) clens.push(8);
2125 for(; i<=255; i++) clens.push(9);
2126 for(; i<=279; i++) clens.push(7);
2127 for(; i<=287; i++) clens.push(8);
2128 build_tree(clens, fix_lmap, 288);
2129})();
2130
2131var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2132var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2133var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
2134var dyn_len_1 = 1, dyn_len_2 = 1;
2135
2136/* 5.5.3 Expanding Huffman Codes */
2137function dyn(data, boff) {
2138 /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
2139 var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
2140 var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
2141 var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
2142 var w = 0;
2143
2144 /* grab and store code lengths */
2145 var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
2146 var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2147 var maxlen = 1;
2148 var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2149 var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2150 var L = clens.length; /* 19 */
2151 for(var i = 0; i < _HCLEN; ++i) {
2152 clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
2153 if(maxlen < w) maxlen = w;
2154 bl_count[w]++;
2155 boff += 3;
2156 }
2157
2158 /* build code tree */
2159 var ccode = 0;
2160 bl_count[0] = 0;
2161 for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
2162 for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
2163 /* cmap[7 bits from stream] = (off&7) + (lit<<3) */
2164 var cleni = 0;
2165 for(i = 0; i < L; ++i) {
2166 cleni = clens[i];
2167 if(cleni != 0) {
2168 ccode = bitswap8[ctree[i]]>>(8-cleni);
2169 for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
2170 }
2171 }
2172
2173 /* read literal and dist codes at once */
2174 var hcodes = [];
2175 maxlen = 1;
2176 for(; hcodes.length < _HLIT + _HDIST;) {
2177 ccode = dyn_cmap[read_bits_7(data, boff)];
2178 boff += ccode & 7;
2179 switch((ccode >>>= 3)) {
2180 case 16:
2181 w = 3 + read_bits_2(data, boff); boff += 2;
2182 ccode = hcodes[hcodes.length - 1];
2183 while(w-- > 0) hcodes.push(ccode);
2184 break;
2185 case 17:
2186 w = 3 + read_bits_3(data, boff); boff += 3;
2187 while(w-- > 0) hcodes.push(0);
2188 break;
2189 case 18:
2190 w = 11 + read_bits_7(data, boff); boff += 7;
2191 while(w -- > 0) hcodes.push(0);
2192 break;
2193 default:
2194 hcodes.push(ccode);
2195 if(maxlen < ccode) maxlen = ccode;
2196 break;
2197 }
2198 }
2199
2200 /* build literal / length trees */
2201 var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
2202 for(i = _HLIT; i < 286; ++i) h1[i] = 0;
2203 for(i = _HDIST; i < 30; ++i) h2[i] = 0;
2204 dyn_len_1 = build_tree(h1, dyn_lmap, 286);
2205 dyn_len_2 = build_tree(h2, dyn_dmap, 30);
2206 return boff;
2207}
2208
2209/* return [ data, bytesRead ] */
2210function inflate(data, usz) {
2211 /* shortcircuit for empty buffer [0x03, 0x00] */
2212 if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
2213
2214 /* bit offset */
2215 var boff = 0;
2216
2217 /* header includes final bit and type bits */
2218 var header = 0;
2219
2220 var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
2221 var woff = 0;
2222 var OL = outbuf.length>>>0;
2223 var max_len_1 = 0, max_len_2 = 0;
2224
2225 while((header&1) == 0) {
2226 header = read_bits_3(data, boff); boff += 3;
2227 if((header >>> 1) == 0) {
2228 /* Stored block */
2229 if(boff & 7) boff += 8 - (boff&7);
2230 /* 2 bytes sz, 2 bytes bit inverse */
2231 var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
2232 boff += 32;
2233 /* push sz bytes */
2234 if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
2235 if(typeof data.copy === 'function') {
2236 // $FlowIgnore
2237 data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
2238 woff += sz; boff += 8*sz;
2239 } else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
2240 continue;
2241 } else if((header >>> 1) == 1) {
2242 /* Fixed Huffman */
2243 max_len_1 = 9; max_len_2 = 5;
2244 } else {
2245 /* Dynamic Huffman */
2246 boff = dyn(data, boff);
2247 max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
2248 }
2249 if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
2250 for(;;) { // while(true) is apparently out of vogue in modern JS circles
2251 /* ingest code and move read head */
2252 var bits = read_bits_n(data, boff, max_len_1);
2253 var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
2254 boff += code & 15; code >>>= 4;
2255 /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
2256 if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
2257 else if(code == 256) break;
2258 else {
2259 code -= 257;
2260 var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
2261 var tgt = woff + LEN_LN[code];
2262 /* length extra bits */
2263 if(len_eb > 0) {
2264 tgt += read_bits_n(data, boff, len_eb);
2265 boff += len_eb;
2266 }
2267
2268 /* dist code */
2269 bits = read_bits_n(data, boff, max_len_2);
2270 code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
2271 boff += code & 15; code >>>= 4;
2272 var dst_eb = (code < 4 ? 0 : (code-2)>>1);
2273 var dst = DST_LN[code];
2274 /* dist extra bits */
2275 if(dst_eb > 0) {
2276 dst += read_bits_n(data, boff, dst_eb);
2277 boff += dst_eb;
2278 }
2279
2280 /* in the common case, manual byte copy is faster than TA set / Buffer copy */
2281 if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
2282 while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
2283 }
2284 }
2285 }
2286 return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
2287}
2288
2289function _inflate(payload, usz) {
2290 var data = payload.slice(payload.l||0);
2291 var out = inflate(data, usz);
2292 payload.l += out[1];
2293 return out[0];
2294}
2295
2296function warn_or_throw(wrn, msg) {
2297 if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
2298 else throw new Error(msg);
2299}
2300
2301function parse_zip(file, options) {
2302 var blob = file;
2303 prep_blob(blob, 0);
2304
2305 var FileIndex = [], FullPaths = [];
2306 var o = {
2307 FileIndex: FileIndex,
2308 FullPaths: FullPaths
2309 };
2310 init_cfb(o, { root: options.root });
2311
2312 /* find end of central directory, start just after signature */
2313 var i = blob.length - 4;
2314 while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
2315 blob.l = i + 4;
2316
2317 /* parse end of central directory */
2318 blob.l += 4;
2319 var fcnt = blob.read_shift(2);
2320 blob.l += 6;
2321 var start_cd = blob.read_shift(4);
2322
2323 /* parse central directory */
2324 blob.l = start_cd;
2325
2326 for(i = 0; i < fcnt; ++i) {
2327 /* trust local file header instead of CD entry */
2328 blob.l += 20;
2329 var csz = blob.read_shift(4);
2330 var usz = blob.read_shift(4);
2331 var namelen = blob.read_shift(2);
2332 var efsz = blob.read_shift(2);
2333 var fcsz = blob.read_shift(2);
2334 blob.l += 8;
2335 var offset = blob.read_shift(4);
2336 var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
2337 blob.l += namelen + efsz + fcsz;
2338
2339 var L = blob.l;
2340 blob.l = offset + 4;
2341 parse_local_file(blob, csz, usz, o, EF);
2342 blob.l = L;
2343 }
2344
2345 return o;
2346}
2347
2348
2349/* head starts just after local file header signature */
2350function parse_local_file(blob, csz, usz, o, EF) {
2351 /* [local file header] */
2352 blob.l += 2;
2353 var flags = blob.read_shift(2);
2354 var meth = blob.read_shift(2);
2355 var date = parse_dos_date(blob);
2356
2357 if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
2358 var crc32 = blob.read_shift(4);
2359 var _csz = blob.read_shift(4);
2360 var _usz = blob.read_shift(4);
2361
2362 var namelen = blob.read_shift(2);
2363 var efsz = blob.read_shift(2);
2364
2365 // TODO: flags & (1<<11) // UTF8
2366 var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
2367 if(efsz) {
2368 var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
2369 if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
2370 if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
2371 }
2372 blob.l += efsz;
2373
2374 /* [encryption header] */
2375
2376 /* [file data] */
2377 var data = blob.slice(blob.l, blob.l + _csz);
2378 switch(meth) {
2379 case 8: data = _inflateRawSync(blob, _usz); break;
2380 case 0: break;
2381 default: throw new Error("Unsupported ZIP Compression method " + meth);
2382 }
2383
2384 /* [data descriptor] */
2385 var wrn = false;
2386 if(flags & 8) {
2387 crc32 = blob.read_shift(4);
2388 if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
2389 _csz = blob.read_shift(4);
2390 _usz = blob.read_shift(4);
2391 }
2392
2393 if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
2394 if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
2395 var _crc32 = CRC32.buf(data, 0);
2396 if(crc32 != _crc32) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
2397 cfb_add(o, name, data, {unsafe: true, mt: date});
2398}
2399function write_zip(cfb, options) {
2400 var _opts = options || {};
2401 var out = [], cdirs = [];
2402 var o = new_buf(1);
2403 var method = (_opts.compression ? 8 : 0), flags = 0;
2404 var desc = false;
2405 if(desc) flags |= 8;
2406 var i = 0, j = 0;
2407
2408 var start_cd = 0, fcnt = 0;
2409 var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
2410 var crcs = [];
2411 var sz_cd = 0;
2412
2413 for(i = 1; i < cfb.FullPaths.length; ++i) {
2414 fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
2415 if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
2416 var start = start_cd;
2417
2418 /* TODO: CP437 filename */
2419 var namebuf = new_buf(fp.length);
2420 for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
2421 namebuf = namebuf.slice(0, namebuf.l);
2422 crcs[fcnt] = CRC32.buf(fi.content, 0);
2423
2424 var outbuf = fi.content;
2425 if(method == 8) outbuf = _deflateRawSync(outbuf);
2426
2427 /* local file header */
2428 o = new_buf(30);
2429 o.write_shift(4, 0x04034b50);
2430 o.write_shift(2, 20);
2431 o.write_shift(2, flags);
2432 o.write_shift(2, method);
2433 /* TODO: last mod file time/date */
2434 if(fi.mt) write_dos_date(o, fi.mt);
2435 else o.write_shift(4, 0);
2436 o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
2437 o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
2438 o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
2439 o.write_shift(2, namebuf.length);
2440 o.write_shift(2, 0);
2441
2442 start_cd += o.length;
2443 out.push(o);
2444 start_cd += namebuf.length;
2445 out.push(namebuf);
2446
2447 /* TODO: encryption header ? */
2448 start_cd += outbuf.length;
2449 out.push(outbuf);
2450
2451 /* data descriptor */
2452 if(flags & 8) {
2453 o = new_buf(12);
2454 o.write_shift(-4, crcs[fcnt]);
2455 o.write_shift(4, outbuf.length);
2456 o.write_shift(4, fi.content.length);
2457 start_cd += o.l;
2458 out.push(o);
2459 }
2460
2461 /* central directory */
2462 o = new_buf(46);
2463 o.write_shift(4, 0x02014b50);
2464 o.write_shift(2, 0);
2465 o.write_shift(2, 20);
2466 o.write_shift(2, flags);
2467 o.write_shift(2, method);
2468 o.write_shift(4, 0); /* TODO: last mod file time/date */
2469 o.write_shift(-4, crcs[fcnt]);
2470
2471 o.write_shift(4, outbuf.length);
2472 o.write_shift(4, fi.content.length);
2473 o.write_shift(2, namebuf.length);
2474 o.write_shift(2, 0);
2475 o.write_shift(2, 0);
2476 o.write_shift(2, 0);
2477 o.write_shift(2, 0);
2478 o.write_shift(4, 0);
2479 o.write_shift(4, start);
2480
2481 sz_cd += o.l;
2482 cdirs.push(o);
2483 sz_cd += namebuf.length;
2484 cdirs.push(namebuf);
2485 ++fcnt;
2486 }
2487
2488 /* end of central directory */
2489 o = new_buf(22);
2490 o.write_shift(4, 0x06054b50);
2491 o.write_shift(2, 0);
2492 o.write_shift(2, 0);
2493 o.write_shift(2, fcnt);
2494 o.write_shift(2, fcnt);
2495 o.write_shift(4, sz_cd);
2496 o.write_shift(4, start_cd);
2497 o.write_shift(2, 0);
2498
2499 return bconcat(([bconcat((out)), bconcat(cdirs), o]));
2500}
2501function cfb_new(opts) {
2502 var o = ({});
2503 init_cfb(o, opts);
2504 return o;
2505}
2506
2507function cfb_add(cfb, name, content, opts) {
2508 var unsafe = opts && opts.unsafe;
2509 if(!unsafe) init_cfb(cfb);
2510 var file = !unsafe && CFB.find(cfb, name);
2511 if(!file) {
2512 var fpath = cfb.FullPaths[0];
2513 if(name.slice(0, fpath.length) == fpath) fpath = name;
2514 else {
2515 if(fpath.slice(-1) != "/") fpath += "/";
2516 fpath = (fpath + name).replace("//","/");
2517 }
2518 file = ({name: filename(name), type: 2});
2519 cfb.FileIndex.push(file);
2520 cfb.FullPaths.push(fpath);
2521 if(!unsafe) CFB.utils.cfb_gc(cfb);
2522 }
2523file.content = (content);
2524 file.size = content ? content.length : 0;
2525 if(opts) {
2526 if(opts.CLSID) file.clsid = opts.CLSID;
2527 if(opts.mt) file.mt = opts.mt;
2528 if(opts.ct) file.ct = opts.ct;
2529 }
2530 return file;
2531}
2532
2533function cfb_del(cfb, name) {
2534 init_cfb(cfb);
2535 var file = CFB.find(cfb, name);
2536 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2537 cfb.FileIndex.splice(j, 1);
2538 cfb.FullPaths.splice(j, 1);
2539 return true;
2540 }
2541 return false;
2542}
2543
2544function cfb_mov(cfb, old_name, new_name) {
2545 init_cfb(cfb);
2546 var file = CFB.find(cfb, old_name);
2547 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2548 cfb.FileIndex[j].name = filename(new_name);
2549 cfb.FullPaths[j] = new_name;
2550 return true;
2551 }
2552 return false;
2553}
2554
2555function cfb_gc(cfb) { rebuild_cfb(cfb, true); }
2556
2557exports.find = find;
2558exports.read = read;
2559exports.parse = parse;
2560exports.write = write;
2561exports.writeFile = write_file;
2562exports.utils = {
2563 cfb_new: cfb_new,
2564 cfb_add: cfb_add,
2565 cfb_del: cfb_del,
2566 cfb_mov: cfb_mov,
2567 cfb_gc: cfb_gc,
2568 ReadShift: ReadShift,
2569 CheckField: CheckField,
2570 prep_blob: prep_blob,
2571 bconcat: bconcat,
2572 use_zlib: use_zlib,
2573 _deflateRaw: _deflate,
2574 _inflateRaw: _inflate,
2575 consts: consts
2576};
2577
2578return exports;
2579})();
2580
2581if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
2582var _fs;
2583if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
2584
2585/* normalize data for blob ctor */
2586function blobify(data) {
2587 if(typeof data === "string") return s2ab(data);
2588 if(Array.isArray(data)) return a2u(data);
2589 return data;
2590}
2591/* write or download file */
2592function write_dl(fname, payload, enc) {
2593 /*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File, chrome */
2594 if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
2595 var data = (enc == "utf8") ? utf8write(payload) : payload;
2596if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
2597 if(typeof Blob !== 'undefined') {
2598 var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
2599if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
2600if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
2601 if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
2602 var url = URL.createObjectURL(blob);
2603if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
2604 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2605 return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
2606 }
2607 var a = document.createElement("a");
2608 if(a.download != null) {
2609a.download = fname; a.href = url; document.body.appendChild(a); a.click();
2610document.body.removeChild(a);
2611 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2612 return url;
2613 }
2614 }
2615 }
2616 // $FlowIgnore
2617 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2618 // $FlowIgnore
2619 var out = File(fname); out.open("w"); out.encoding = "binary";
2620 if(Array.isArray(payload)) payload = a2s(payload);
2621 out.write(payload); out.close(); return payload;
2622 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2623 throw new Error("cannot save file " + fname);
2624}
2625
2626/* read binary data from file */
2627function read_binary(path) {
2628 if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
2629 // $FlowIgnore
2630 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2631 // $FlowIgnore
2632 var infile = File(path); infile.open("r"); infile.encoding = "binary";
2633 var data = infile.read(); infile.close();
2634 return data;
2635 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2636 throw new Error("Cannot access file " + path);
2637}
2638function keys(o) {
2639 var ks = Object.keys(o), o2 = [];
2640 for(var i = 0; i < ks.length; ++i) if(o.hasOwnProperty(ks[i])) o2.push(ks[i]);
2641 return o2;
2642}
2643
2644function evert_key(obj, key) {
2645 var o = ([]), K = keys(obj);
2646 for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
2647 return o;
2648}
2649
2650function evert(obj) {
2651 var o = ([]), K = keys(obj);
2652 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
2653 return o;
2654}
2655
2656function evert_num(obj) {
2657 var o = ([]), K = keys(obj);
2658 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
2659 return o;
2660}
2661
2662function evert_arr(obj) {
2663 var o = ([]), K = keys(obj);
2664 for(var i = 0; i !== K.length; ++i) {
2665 if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
2666 o[obj[K[i]]].push(K[i]);
2667 }
2668 return o;
2669}
2670
2671var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
2672var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2673function datenum(v, date1904) {
2674 var epoch = v.getTime();
2675 if(date1904) epoch -= 1462*24*60*60*1000;
2676 return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
2677}
2678function numdate(v) {
2679 var out = new Date();
2680 out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
2681 return out;
2682}
2683
2684/* ISO 8601 Duration */
2685function parse_isodur(s) {
2686 var sec = 0, mt = 0, time = false;
2687 var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
2688 if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
2689 for(var i = 1; i != m.length; ++i) {
2690 if(!m[i]) continue;
2691 mt = 1;
2692 if(i > 3) time = true;
2693 switch(m[i].slice(m[i].length-1)) {
2694 case 'Y':
2695 throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
2696 case 'D': mt *= 24;
2697 /* falls through */
2698 case 'H': mt *= 60;
2699 /* falls through */
2700 case 'M':
2701 if(!time) throw new Error("Unsupported ISO Duration Field: M");
2702 else mt *= 60;
2703 /* falls through */
2704 case 'S': break;
2705 }
2706 sec += mt * parseInt(m[i], 10);
2707 }
2708 return sec;
2709}
2710
2711var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
2712if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
2713var good_pd = good_pd_date.getFullYear() == 2017;
2714/* parses a date as a local date */
2715function parseDate(str, fixdate) {
2716 var d = new Date(str);
2717 if(good_pd) {
2718if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
2719 else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
2720 return d;
2721 }
2722 if(str instanceof Date) return str;
2723 if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
2724 var s = d.getFullYear();
2725 if(str.indexOf("" + s) > -1) return d;
2726 d.setFullYear(d.getFullYear() + 100); return d;
2727 }
2728 var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
2729 var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
2730 if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
2731 return out;
2732}
2733
2734function cc2str(arr) {
2735 var o = "";
2736 for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2737 return o;
2738}
2739
2740function dup(o) {
2741 if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2742 if(typeof o != 'object' || o == null) return o;
2743 if(o instanceof Date) return new Date(o.getTime());
2744 var out = {};
2745 for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
2746 return out;
2747}
2748
2749function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
2750
2751/* TODO: stress test */
2752function fuzzynum(s) {
2753 var v = Number(s);
2754 if(!isNaN(v)) return v;
2755 var wt = 1;
2756 var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2757 if(!isNaN(v = Number(ss))) return v / wt;
2758 ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2759 if(!isNaN(v = Number(ss))) return v / wt;
2760 return v;
2761}
2762function fuzzydate(s) {
2763 var o = new Date(s), n = new Date(NaN);
2764 var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2765 if(isNaN(d)) return n;
2766 if(y < 0 || y > 8099) return n;
2767 if((m > 0 || d > 1) && y != 101) return o;
2768 if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2769 if(s.match(/[^-0-9:,\/\\]/)) return n;
2770 return o;
2771}
2772
2773var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2774function split_regex(str, re, def) {
2775 if(safe_split_regex || typeof re == "string") return str.split(re);
2776 var p = str.split(re), o = [p[0]];
2777 for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2778 return o;
2779}
2780function getdatastr(data) {
2781 if(!data) return null;
2782 if(data.data) return debom(data.data);
2783 if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2784 if(data.asBinary) return debom(data.asBinary());
2785 if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
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 return null;
2799}
2800
2801function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2802
2803/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2804/* OASIS does not comment on filename case sensitivity */
2805function safegetzipfile(zip, file) {
2806 var k = keys(zip.files);
2807 var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
2808 for(var i=0; i<k.length; ++i) {
2809 var n = k[i].toLowerCase();
2810 if(f == n || g == n) return zip.files[k[i]];
2811 }
2812 return null;
2813}
2814
2815function getzipfile(zip, file) {
2816 var o = safegetzipfile(zip, file);
2817 if(o == null) throw new Error("Cannot find file " + file + " in zip");
2818 return o;
2819}
2820
2821function getzipdata(zip, file, safe) {
2822 if(!safe) return getdata(getzipfile(zip, file));
2823 if(!file) return null;
2824 try { return getzipdata(zip, file); } catch(e) { return null; }
2825}
2826
2827function getzipstr(zip, file, safe) {
2828 if(!safe) return getdatastr(getzipfile(zip, file));
2829 if(!file) return null;
2830 try { return getzipstr(zip, file); } catch(e) { return null; }
2831}
2832
2833function zipentries(zip) {
2834 var k = keys(zip.files), o = [];
2835 for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i]);
2836 return o.sort();
2837}
2838
2839var jszip;
2840/*global JSZipSync:true */
2841if(typeof JSZipSync !== 'undefined') jszip = JSZipSync;
2842if(typeof exports !== 'undefined') {
2843 if(typeof module !== 'undefined' && module.exports) {
2844 if(typeof jszip === 'undefined') jszip = require('./jszip.js');
2845 }
2846}
2847
2848function resolve_path(path, base) {
2849 var result = base.split('/');
2850 if(base.slice(-1) != "/") result.pop(); // folder path
2851 var target = path.split('/');
2852 while (target.length !== 0) {
2853 var step = target.shift();
2854 if (step === '..') result.pop();
2855 else if (step !== '.') result.push(step);
2856 }
2857 return result.join('/');
2858}
2859var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2860var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2861var tagregex=/<[\/\?]?[a-zA-Z0-9:]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s?[\/\?]?>/g;
2862if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2863var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2864function parsexmltag(tag, skip_root) {
2865 var z = ({});
2866 var eq = 0, c = 0;
2867 for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2868 if(!skip_root) z[0] = tag.slice(0, eq);
2869 if(eq === tag.length) return z;
2870 var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2871 if(m) for(i = 0; i != m.length; ++i) {
2872 cc = m[i];
2873 for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2874 q = cc.slice(0,c).trim();
2875 while(cc.charCodeAt(c+1) == 32) ++c;
2876 quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2877 v = cc.slice(c+1+quot, cc.length-quot);
2878 for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2879 if(j===q.length) {
2880 if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2881 z[q] = v;
2882 z[q.toLowerCase()] = v;
2883 }
2884 else {
2885 var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2886 if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2887 z[k] = v;
2888 z[k.toLowerCase()] = v;
2889 }
2890 }
2891 return z;
2892}
2893function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
2894
2895var encodings = {
2896 '&quot;': '"',
2897 '&apos;': "'",
2898 '&gt;': '>',
2899 '&lt;': '<',
2900 '&amp;': '&'
2901};
2902var rencoding = evert(encodings);
2903//var rencstr = "&<>'\"".split("");
2904
2905// TODO: CP remap (need to read file version to determine OS)
2906var unescapexml = (function() {
2907 /* 22.4.2.4 bstr (Basic String) */
2908 var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
2909 return function unescapexml(text) {
2910 var s = text + '', i = s.indexOf("<![CDATA[");
2911 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));});
2912 var j = s.indexOf("]]>");
2913 return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
2914 };
2915})();
2916
2917var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
2918function escapexml(text){
2919 var s = text + '';
2920 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
2921}
2922function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
2923
2924var htmlcharegex = /[\u0000-\u001f]/g;
2925function escapehtml(text){
2926 var s = text + '';
2927 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) + ";"; });
2928}
2929
2930function escapexlml(text){
2931 var s = text + '';
2932 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
2933}
2934
2935/* TODO: handle codepages */
2936var xlml_fixstr = (function() {
2937 var entregex = /&#(\d+);/g;
2938 function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
2939 return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
2940})();
2941var xlml_unfixstr = (function() {
2942 return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
2943})();
2944
2945function parsexmlbool(value) {
2946 switch(value) {
2947 case 1: case true: case '1': case 'true': case 'TRUE': return true;
2948 /* case '0': case 'false': case 'FALSE':*/
2949 default: return false;
2950 }
2951}
2952
2953var utf8read = function utf8reada(orig) {
2954 var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
2955 while (i < orig.length) {
2956 c = orig.charCodeAt(i++);
2957 if (c < 128) { out += String.fromCharCode(c); continue; }
2958 d = orig.charCodeAt(i++);
2959 if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
2960 e = orig.charCodeAt(i++);
2961 if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
2962 f = orig.charCodeAt(i++);
2963 w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
2964 out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
2965 out += String.fromCharCode(0xDC00 + (w&1023));
2966 }
2967 return out;
2968};
2969
2970var utf8write = function(orig) {
2971 var out = [], i = 0, c = 0, d = 0;
2972 while(i < orig.length) {
2973 c = orig.charCodeAt(i++);
2974 switch(true) {
2975 case c < 128: out.push(String.fromCharCode(c)); break;
2976 case c < 2048:
2977 out.push(String.fromCharCode(192 + (c >> 6)));
2978 out.push(String.fromCharCode(128 + (c & 63)));
2979 break;
2980 case c >= 55296 && c < 57344:
2981 c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
2982 out.push(String.fromCharCode(240 + ((d >>18) & 7)));
2983 out.push(String.fromCharCode(144 + ((d >>12) & 63)));
2984 out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
2985 out.push(String.fromCharCode(128 + (d & 63)));
2986 break;
2987 default:
2988 out.push(String.fromCharCode(224 + (c >> 12)));
2989 out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
2990 out.push(String.fromCharCode(128 + (c & 63)));
2991 }
2992 }
2993 return out.join("");
2994};
2995
2996if(has_buf) {
2997 var utf8readb = function utf8readb(data) {
2998 var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
2999 for(i = 0; i < data.length; i+=j) {
3000 j = 1;
3001 if((c=data.charCodeAt(i)) < 128) w = c;
3002 else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
3003 else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
3004 else { j = 4;
3005 w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
3006 w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
3007 }
3008 if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
3009 out[k++] = w%256; out[k++] = w>>>8;
3010 }
3011 return out.slice(0,k).toString('ucs2');
3012 };
3013 var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
3014 if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
3015 // $FlowIgnore
3016 var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
3017 if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
3018
3019 // $FlowIgnore
3020 utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
3021}
3022
3023// matches <foo>...</foo> extracts content
3024var matchtag = (function() {
3025 var mtcache = ({});
3026 return function matchtag(f,g) {
3027 var t = f+"|"+(g||"");
3028 if(mtcache[t]) return mtcache[t];
3029 return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
3030 };
3031})();
3032
3033var htmldecode = (function() {
3034 var entities = [
3035 ['nbsp', ' '], ['middot', '·'],
3036 ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
3037 ].map(function(x) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; });
3038 return function htmldecode(str) {
3039 var o = str.replace(/^[\t\n\r ]+/, "").replace(/[\t\n\r ]+$/,"").replace(/[\t\n\r ]+/g, " ").replace(/<\s*[bB][rR]\s*\/?>/g,"\n").replace(/<[^>]*>/g,"");
3040 for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
3041 return o;
3042 };
3043})();
3044
3045var vtregex = (function(){ var vt_cache = {};
3046 return function vt_regex(bt) {
3047 if(vt_cache[bt] !== undefined) return vt_cache[bt];
3048 return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
3049};})();
3050var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
3051function parseVector(data, opts) {
3052 var h = parsexmltag(data);
3053
3054 var matches = data.match(vtregex(h.baseType))||[];
3055 var res = [];
3056 if(matches.length != h.size) {
3057 if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
3058 return res;
3059 }
3060 matches.forEach(function(x) {
3061 var v = x.replace(vtvregex,"").match(vtmregex);
3062 if(v) res.push({v:utf8read(v[2]), t:v[1]});
3063 });
3064 return res;
3065}
3066
3067var wtregex = /(^\s|\s$|\n)/;
3068function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
3069
3070function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
3071function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
3072
3073function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
3074
3075function write_vt(s) {
3076 switch(typeof s) {
3077 case 'string': return writextag('vt:lpwstr', s);
3078 case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
3079 case 'boolean': return writextag('vt:bool',s?'true':'false');
3080 }
3081 if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
3082 throw new Error("Unable to serialize " + s);
3083}
3084
3085var XMLNS = ({
3086 'dc': 'http://purl.org/dc/elements/1.1/',
3087 'dcterms': 'http://purl.org/dc/terms/',
3088 'dcmitype': 'http://purl.org/dc/dcmitype/',
3089 'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
3090 'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
3091 'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
3092 'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
3093 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
3094 'xsd': 'http://www.w3.org/2001/XMLSchema'
3095});
3096
3097XMLNS.main = [
3098 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
3099 'http://purl.oclc.org/ooxml/spreadsheetml/main',
3100 'http://schemas.microsoft.com/office/excel/2006/main',
3101 'http://schemas.microsoft.com/office/excel/2006/2'
3102];
3103
3104var XLMLNS = ({
3105 'o': 'urn:schemas-microsoft-com:office:office',
3106 'x': 'urn:schemas-microsoft-com:office:excel',
3107 'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
3108 'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
3109 'mv': 'http://macVmlSchemaUri',
3110 'v': 'urn:schemas-microsoft-com:vml',
3111 'html': 'http://www.w3.org/TR/REC-html40'
3112});
3113function read_double_le(b, idx) {
3114 var s = 1 - 2 * (b[idx + 7] >>> 7);
3115 var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
3116 var m = (b[idx+6]&0x0f);
3117 for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
3118 if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
3119 if(e == 0) e = -1022;
3120 else { e -= 1023; m += Math.pow(2,52); }
3121 return s * Math.pow(2, e - 52) * m;
3122}
3123
3124function write_double_le(b, v, idx) {
3125 var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
3126 var av = bs ? (-v) : v;
3127 if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
3128 else if(av == 0) e = m = 0;
3129 else {
3130 e = Math.floor(Math.log(av) / Math.LN2);
3131 m = av * Math.pow(2, 52 - e);
3132 if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
3133 else { m -= Math.pow(2,52); e+=1023; }
3134 }
3135 for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
3136 b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
3137 b[idx + 7] = (e >> 4) | bs;
3138}
3139
3140var __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; };
3141var ___toBuffer = __toBuffer;
3142var __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,''); };
3143var ___utf16le = __utf16le;
3144var __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(""); };
3145var ___hexlify = __hexlify;
3146var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
3147var ___utf8 = __utf8;
3148var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3149var ___lpstr = __lpstr;
3150var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3151var ___cpstr = __cpstr;
3152var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3153var ___lpwstr = __lpwstr;
3154var __lpp4, ___lpp4;
3155__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
3156var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
3157var ___8lpp4 = __8lpp4;
3158var __double, ___double;
3159__double = ___double = function(b, idx) { return read_double_le(b, idx);};
3160var is_buf = function is_buf_a(a) { return Array.isArray(a); };
3161
3162if(has_buf) {
3163 __utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
3164 __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
3165 __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) : "";};
3166 __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) : "";};
3167 __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);};
3168 __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);};
3169 __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);};
3170 __utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
3171 __toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
3172 bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
3173 __double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
3174 is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
3175}
3176
3177/* from js-xls */
3178if(typeof cptable !== 'undefined') {
3179 __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
3180 __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
3181 __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)) : "";};
3182 __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)) : "";};
3183 __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)) : "";};
3184 __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
3185 __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
3186}
3187
3188var __readUInt8 = function(b, idx) { return b[idx]; };
3189var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
3190var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
3191var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
3192var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
3193var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
3194
3195function ReadShift(size, t) {
3196 var o="", oI, oR, oo=[], w, vv, i, loc;
3197 switch(t) {
3198 case 'dbcs':
3199 loc = this.l;
3200 if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
3201 else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
3202 size *= 2;
3203 break;
3204
3205 case 'utf8': o = __utf8(this, this.l, this.l + size); break;
3206 case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
3207
3208 case 'wstr':
3209 if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
3210 else return ReadShift.call(this, size, 'dbcs');
3211 size = 2 * size; break;
3212
3213 /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
3214 case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3215 case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3216 /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
3217 case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
3218 /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
3219 case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
3220 /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
3221 case '8lpp4': size = 4 + __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
3222
3223 case 'cstr': size = 0; o = "";
3224 while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
3225 o = oo.join(""); break;
3226 case '_wstr': size = 0; o = "";
3227 while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
3228 size+=2; o = oo.join(""); break;
3229
3230 /* sbcs and dbcs support continue records in the SST way TODO codepages */
3231 case 'dbcs-cont': o = ""; loc = this.l;
3232 for(i = 0; i < size; ++i) {
3233 if(this.lens && this.lens.indexOf(loc) !== -1) {
3234 w = __readUInt8(this, loc);
3235 this.l = loc + 1;
3236 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3237 return oo.join("") + vv;
3238 }
3239 oo.push(_getchar(__readUInt16LE(this, loc)));
3240 loc+=2;
3241 } o = oo.join(""); size *= 2; break;
3242
3243 case 'cpstr':
3244 if(typeof cptable !== 'undefined') {
3245 o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
3246 break;
3247 }
3248 /* falls through */
3249 case 'sbcs-cont': o = ""; loc = this.l;
3250 for(i = 0; i != size; ++i) {
3251 if(this.lens && this.lens.indexOf(loc) !== -1) {
3252 w = __readUInt8(this, loc);
3253 this.l = loc + 1;
3254 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3255 return oo.join("") + vv;
3256 }
3257 oo.push(_getchar(__readUInt8(this, loc)));
3258 loc+=1;
3259 } o = oo.join(""); break;
3260
3261 default:
3262 switch(size) {
3263 case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
3264 case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
3265 case 4: case -4:
3266 if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
3267 else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
3268 case 8: case -8:
3269 if(t === 'f') {
3270 if(size == 8) oR = __double(this, this.l);
3271 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);
3272 this.l += 8; return oR;
3273 } else size = 8;
3274 /* falls through */
3275 case 16: o = __hexlify(this, this.l, size); break;
3276 }}
3277 this.l+=size; return o;
3278}
3279
3280var __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); };
3281var __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); };
3282var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
3283
3284function WriteShift(t, val, f) {
3285 var size = 0, i = 0;
3286 if(f === 'dbcs') {
3287for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
3288 size = 2 * val.length;
3289 } else if(f === 'sbcs') {
3290 /* TODO: codepage */
3291val = val.replace(/[^\x00-\x7F]/g, "_");
3292for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
3293 size = val.length;
3294 } else if(f === 'hex') {
3295 for(; i < t; ++i) {
3296this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
3297 } return this;
3298 } else if(f === 'utf16le') {
3299var end = Math.min(this.l + t, this.length);
3300 for(i = 0; i < Math.min(val.length, t); ++i) {
3301 var cc = val.charCodeAt(i);
3302 this[this.l++] = (cc & 0xff);
3303 this[this.l++] = (cc >> 8);
3304 }
3305 while(this.l < end) this[this.l++] = 0;
3306 return this;
3307 } else switch(t) {
3308 case 1: size = 1; this[this.l] = val&0xFF; break;
3309 case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
3310 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;
3311 case 4: size = 4; __writeUInt32LE(this, val, this.l); break;
3312 case 8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
3313 /* falls through */
3314 case 16: break;
3315 case -4: size = 4; __writeInt32LE(this, val, this.l); break;
3316 }
3317 this.l += size; return this;
3318}
3319
3320function CheckField(hexstr, fld) {
3321 var m = __hexlify(this,this.l,hexstr.length>>1);
3322 if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
3323 this.l += hexstr.length>>1;
3324}
3325
3326function prep_blob(blob, pos) {
3327 blob.l = pos;
3328 blob.read_shift = ReadShift;
3329 blob.chk = CheckField;
3330 blob.write_shift = WriteShift;
3331}
3332
3333function parsenoop(blob, length) { blob.l += length; }
3334
3335function new_buf(sz) {
3336 var o = new_raw_buf(sz);
3337 prep_blob(o, 0);
3338 return o;
3339}
3340
3341/* [MS-XLSB] 2.1.4 Record */
3342function recordhopper(data, cb, opts) {
3343 if(!data) return;
3344 var tmpbyte, cntbyte, length;
3345 prep_blob(data, data.l || 0);
3346 var L = data.length, RT = 0, tgt = 0;
3347 while(data.l < L) {
3348 RT = data.read_shift(1);
3349 if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
3350 var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
3351 tmpbyte = data.read_shift(1);
3352 length = tmpbyte & 0x7F;
3353 for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
3354 tgt = data.l + length;
3355 var d = (R.f||parsenoop)(data, length, opts);
3356 data.l = tgt;
3357 if(cb(d, R.n, RT)) return;
3358 }
3359}
3360
3361/* control buffer usage for fixed-length buffers */
3362function buf_array() {
3363 var bufs = [], blksz = has_buf ? 256 : 2048;
3364 var newblk = function ba_newblk(sz) {
3365 var o = (new_buf(sz));
3366 prep_blob(o, 0);
3367 return o;
3368 };
3369
3370 var curbuf = newblk(blksz);
3371
3372 var endbuf = function ba_endbuf() {
3373 if(!curbuf) return;
3374 if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3375 if(curbuf.length > 0) bufs.push(curbuf);
3376 curbuf = null;
3377 };
3378
3379 var next = function ba_next(sz) {
3380 if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
3381 endbuf();
3382 return (curbuf = newblk(Math.max(sz+1, blksz)));
3383 };
3384
3385 var end = function ba_end() {
3386 endbuf();
3387 return __toBuffer([bufs]);
3388 };
3389
3390 var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
3391
3392 return ({ next:next, push:push, end:end, _bufs:bufs });
3393}
3394
3395function write_record(ba, type, payload, length) {
3396 var t = +XLSBRE[type], l;
3397 if(isNaN(t)) return; // TODO: throw something here?
3398 if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
3399 l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
3400 if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
3401 var o = ba.next(l);
3402 if(t <= 0x7F) o.write_shift(1, t);
3403 else {
3404 o.write_shift(1, (t & 0x7F) + 0x80);
3405 o.write_shift(1, (t >> 7));
3406 }
3407 for(var i = 0; i != 4; ++i) {
3408 if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
3409 else { o.write_shift(1, length); break; }
3410 }
3411 if(length > 0 && is_buf(payload)) ba.push(payload);
3412}
3413/* XLS ranges enforced */
3414function shift_cell_xls(cell, tgt, opts) {
3415 var out = dup(cell);
3416 if(tgt.s) {
3417 if(out.cRel) out.c += tgt.s.c;
3418 if(out.rRel) out.r += tgt.s.r;
3419 } else {
3420 if(out.cRel) out.c += tgt.c;
3421 if(out.rRel) out.r += tgt.r;
3422 }
3423 if(!opts || opts.biff < 12) {
3424 while(out.c >= 0x100) out.c -= 0x100;
3425 while(out.r >= 0x10000) out.r -= 0x10000;
3426 }
3427 return out;
3428}
3429
3430function shift_range_xls(cell, range, opts) {
3431 var out = dup(cell);
3432 out.s = shift_cell_xls(out.s, range.s, opts);
3433 out.e = shift_cell_xls(out.e, range.s, opts);
3434 return out;
3435}
3436
3437function encode_cell_xls(c, biff) {
3438 if(c.cRel && c.c < 0) { c = dup(c); c.c += (biff > 8) ? 0x4000 : 0x100; }
3439 if(c.rRel && c.r < 0) { c = dup(c); c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
3440 var s = encode_cell(c);
3441 if(c.cRel === 0) s = fix_col(s);
3442 if(c.rRel === 0) s = fix_row(s);
3443 return s;
3444}
3445
3446function encode_range_xls(r, opts) {
3447 if(r.s.r == 0 && !r.s.rRel) {
3448 if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
3449 return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
3450 }
3451 }
3452 if(r.s.c == 0 && !r.s.cRel) {
3453 if(r.e.c == (opts.biff >= 12 ? 0xFFFF : 0xFF) && !r.e.cRel) {
3454 return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
3455 }
3456 }
3457 return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
3458}
3459var OFFCRYPTO = {};
3460
3461var make_offcrypto = function(O, _crypto) {
3462 var crypto;
3463 if(typeof _crypto !== 'undefined') crypto = _crypto;
3464 else if(typeof require !== 'undefined') {
3465 try { crypto = require('crypto'); }
3466 catch(e) { crypto = null; }
3467 }
3468
3469 O.rc4 = function(key, data) {
3470 var S = new Array(256);
3471 var c = 0, i = 0, j = 0, t = 0;
3472 for(i = 0; i != 256; ++i) S[i] = i;
3473 for(i = 0; i != 256; ++i) {
3474 j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
3475 t = S[i]; S[i] = S[j]; S[j] = t;
3476 }
3477 // $FlowIgnore
3478 i = j = 0; var out = Buffer(data.length);
3479 for(c = 0; c != data.length; ++c) {
3480 i = (i + 1)&255;
3481 j = (j + S[i])%256;
3482 t = S[i]; S[i] = S[j]; S[j] = t;
3483 out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
3484 }
3485 return out;
3486 };
3487
3488 O.md5 = function(hex) {
3489 if(!crypto) throw new Error("Unsupported crypto");
3490 return crypto.createHash('md5').update(hex).digest('hex');
3491 };
3492};
3493/*global crypto:true */
3494make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
3495
3496function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
3497function encode_row(row) { return "" + (row + 1); }
3498function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
3499function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
3500
3501function 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; }
3502function encode_col(col) { var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
3503function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
3504function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
3505
3506function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
3507function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
3508function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
3509function decode_range(range) { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
3510function encode_range(cs,ce) {
3511 if(typeof ce === 'undefined' || typeof ce === 'number') {
3512return encode_range(cs.s, cs.e);
3513 }
3514if(typeof cs !== 'string') cs = encode_cell((cs));
3515 if(typeof ce !== 'string') ce = encode_cell((ce));
3516return cs == ce ? cs : cs + ":" + ce;
3517}
3518
3519function safe_decode_range(range) {
3520 var o = {s:{c:0,r:0},e:{c:0,r:0}};
3521 var idx = 0, i = 0, cc = 0;
3522 var len = range.length;
3523 for(idx = 0; i < len; ++i) {
3524 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3525 idx = 26*idx + cc;
3526 }
3527 o.s.c = --idx;
3528
3529 for(idx = 0; i < len; ++i) {
3530 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3531 idx = 10*idx + cc;
3532 }
3533 o.s.r = --idx;
3534
3535 if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
3536
3537 for(idx = 0; i != len; ++i) {
3538 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3539 idx = 26*idx + cc;
3540 }
3541 o.e.c = --idx;
3542
3543 for(idx = 0; i != len; ++i) {
3544 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3545 idx = 10*idx + cc;
3546 }
3547 o.e.r = --idx;
3548 return o;
3549}
3550
3551function safe_format_cell(cell, v) {
3552 var q = (cell.t == 'd' && v instanceof Date);
3553 if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
3554 try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
3555}
3556
3557function format_cell(cell, v, o) {
3558 if(cell == null || cell.t == null || cell.t == 'z') return "";
3559 if(cell.w !== undefined) return cell.w;
3560 if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
3561 if(v == undefined) return safe_format_cell(cell, cell.v);
3562 return safe_format_cell(cell, v);
3563}
3564
3565function sheet_to_workbook(sheet, opts) {
3566 var n = opts && opts.sheet ? opts.sheet : "Sheet1";
3567 var sheets = {}; sheets[n] = sheet;
3568 return { SheetNames: [n], Sheets: sheets };
3569}
3570
3571function sheet_add_aoa(_ws, data, opts) {
3572 var o = opts || {};
3573 var dense = _ws ? Array.isArray(_ws) : o.dense;
3574 if(DENSE != null && dense == null) dense = DENSE;
3575 var ws = _ws || (dense ? ([]) : ({}));
3576 var _R = 0, _C = 0;
3577 if(ws && o.origin != null) {
3578 if(typeof o.origin == 'number') _R = o.origin;
3579 else {
3580 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
3581 _R = _origin.r; _C = _origin.c;
3582 }
3583 }
3584 var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
3585 if(ws['!ref']) {
3586 var _range = safe_decode_range(ws['!ref']);
3587 range.s.c = _range.s.c;
3588 range.s.r = _range.s.r;
3589 range.e.c = Math.max(range.e.c, _range.e.c);
3590 range.e.r = Math.max(range.e.r, _range.e.r);
3591 if(_R == -1) range.e.r = _R = _range.e.r + 1;
3592 }
3593 for(var R = 0; R != data.length; ++R) {
3594 if(!data[R]) continue;
3595 if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
3596 for(var C = 0; C != data[R].length; ++C) {
3597 if(typeof data[R][C] === 'undefined') continue;
3598 var cell = ({v: data[R][C] });
3599 var __R = _R + R, __C = _C + C;
3600 if(range.s.r > __R) range.s.r = __R;
3601 if(range.s.c > __C) range.s.c = __C;
3602 if(range.e.r < __R) range.e.r = __R;
3603 if(range.e.c < __C) range.e.c = __C;
3604 if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
3605 else {
3606 if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
3607 if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.sheetStubs) continue; else cell.t = 'z'; }
3608 else if(typeof cell.v === 'number') cell.t = 'n';
3609 else if(typeof cell.v === 'boolean') cell.t = 'b';
3610 else if(cell.v instanceof Date) {
3611 cell.z = o.dateNF || SSF._table[14];
3612 if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
3613 else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
3614 }
3615 else cell.t = 's';
3616 }
3617 if(dense) {
3618 if(!ws[__R]) ws[__R] = [];
3619 ws[__R][__C] = cell;
3620 } else {
3621 var cell_ref = encode_cell(({c:__C,r:__R}));
3622 ws[cell_ref] = cell;
3623 }
3624 }
3625 }
3626 if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
3627 return ws;
3628}
3629function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
3630
3631function write_UInt32LE(x, o) {
3632 if(!o) o = new_buf(4);
3633 o.write_shift(4, x);
3634 return o;
3635}
3636
3637/* [MS-XLSB] 2.5.168 */
3638function parse_XLWideString(data) {
3639 var cchCharacters = data.read_shift(4);
3640 return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
3641}
3642function write_XLWideString(data, o) {
3643 var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
3644 o.write_shift(4, data.length);
3645 if(data.length > 0) o.write_shift(0, data, 'dbcs');
3646 return _null ? o.slice(0, o.l) : o;
3647}
3648
3649/* [MS-XLSB] 2.5.143 */
3650function parse_StrRun(data) {
3651 return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
3652}
3653function write_StrRun(run, o) {
3654 if(!o) o = new_buf(4);
3655 o.write_shift(2, run.ich || 0);
3656 o.write_shift(2, run.ifnt || 0);
3657 return o;
3658}
3659
3660/* [MS-XLSB] 2.5.121 */
3661function parse_RichStr(data, length) {
3662 var start = data.l;
3663 var flags = data.read_shift(1);
3664 var str = parse_XLWideString(data);
3665 var rgsStrRun = [];
3666 var z = ({ t: str, h: str });
3667 if((flags & 1) !== 0) { /* fRichStr */
3668 /* TODO: formatted string */
3669 var dwSizeStrRun = data.read_shift(4);
3670 for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
3671 z.r = rgsStrRun;
3672 }
3673 else z.r = [{ich:0, ifnt:0}];
3674 //if((flags & 2) !== 0) { /* fExtStr */
3675 // /* TODO: phonetic string */
3676 //}
3677 data.l = start + length;
3678 return z;
3679}
3680function write_RichStr(str, o) {
3681 /* TODO: formatted string */
3682 var _null = false; if(o == null) { _null = true; o = new_buf(15+4*str.t.length); }
3683 o.write_shift(1,0);
3684 write_XLWideString(str.t, o);
3685 return _null ? o.slice(0, o.l) : o;
3686}
3687/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
3688var parse_BrtCommentText = parse_RichStr;
3689function write_BrtCommentText(str, o) {
3690 /* TODO: formatted string */
3691 var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
3692 o.write_shift(1,1);
3693 write_XLWideString(str.t, o);
3694 o.write_shift(4,1);
3695 write_StrRun({ich:0,ifnt:0}, o);
3696 return _null ? o.slice(0, o.l) : o;
3697}
3698
3699/* [MS-XLSB] 2.5.9 */
3700function parse_XLSBCell(data) {
3701 var col = data.read_shift(4);
3702 var iStyleRef = data.read_shift(2);
3703 iStyleRef += data.read_shift(1) <<16;
3704 data.l++; //var fPhShow = data.read_shift(1);
3705 return { c:col, iStyleRef: iStyleRef };
3706}
3707function write_XLSBCell(cell, o) {
3708 if(o == null) o = new_buf(8);
3709 o.write_shift(-4, cell.c);
3710 o.write_shift(3, cell.iStyleRef || cell.s);
3711 o.write_shift(1, 0); /* fPhShow */
3712 return o;
3713}
3714
3715
3716/* [MS-XLSB] 2.5.21 */
3717var parse_XLSBCodeName = parse_XLWideString;
3718var write_XLSBCodeName = write_XLWideString;
3719
3720/* [MS-XLSB] 2.5.166 */
3721function parse_XLNullableWideString(data) {
3722 var cchCharacters = data.read_shift(4);
3723 return cchCharacters === 0 || cchCharacters === 0xFFFFFFFF ? "" : data.read_shift(cchCharacters, 'dbcs');
3724}
3725function write_XLNullableWideString(data, o) {
3726 var _null = false; if(o == null) { _null = true; o = new_buf(127); }
3727 o.write_shift(4, data.length > 0 ? data.length : 0xFFFFFFFF);
3728 if(data.length > 0) o.write_shift(0, data, 'dbcs');
3729 return _null ? o.slice(0, o.l) : o;
3730}
3731
3732/* [MS-XLSB] 2.5.165 */
3733var parse_XLNameWideString = parse_XLWideString;
3734//var write_XLNameWideString = write_XLWideString;
3735
3736/* [MS-XLSB] 2.5.114 */
3737var parse_RelID = parse_XLNullableWideString;
3738var write_RelID = write_XLNullableWideString;
3739
3740
3741/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
3742function parse_RkNumber(data) {
3743 var b = data.slice(data.l, data.l+4);
3744 var fX100 = (b[0] & 1), fInt = (b[0] & 2);
3745 data.l+=4;
3746 b[0] &= 0xFC; // b[0] &= ~3;
3747 var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
3748 return fX100 ? (RK/100) : RK;
3749}
3750function write_RkNumber(data, o) {
3751 if(o == null) o = new_buf(4);
3752 var fX100 = 0, fInt = 0, d100 = data * 100;
3753 if((data == (data | 0)) && (data >= -(1<<29)) && (data < (1 << 29))) { fInt = 1; }
3754 else if((d100 == (d100 | 0)) && (d100 >= -(1<<29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
3755 if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
3756 else throw new Error("unsupported RkNumber " + data); // TODO
3757}
3758
3759
3760/* [MS-XLSB] 2.5.117 RfX */
3761function parse_RfX(data ) {
3762 var cell = ({s: {}, e: {}});
3763 cell.s.r = data.read_shift(4);
3764 cell.e.r = data.read_shift(4);
3765 cell.s.c = data.read_shift(4);
3766 cell.e.c = data.read_shift(4);
3767 return cell;
3768}
3769function write_RfX(r, o) {
3770 if(!o) o = new_buf(16);
3771 o.write_shift(4, r.s.r);
3772 o.write_shift(4, r.e.r);
3773 o.write_shift(4, r.s.c);
3774 o.write_shift(4, r.e.c);
3775 return o;
3776}
3777
3778/* [MS-XLSB] 2.5.153 UncheckedRfX */
3779var parse_UncheckedRfX = parse_RfX;
3780var write_UncheckedRfX = write_RfX;
3781
3782/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
3783/* TODO: error checking, NaN and Infinity values are not valid Xnum */
3784function parse_Xnum(data) { return data.read_shift(8, 'f'); }
3785function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
3786
3787/* [MS-XLSB] 2.5.97.2 */
3788var BErr = {
37890x00: "#NULL!",
37900x07: "#DIV/0!",
37910x0F: "#VALUE!",
37920x17: "#REF!",
37930x1D: "#NAME?",
37940x24: "#NUM!",
37950x2A: "#N/A",
37960x2B: "#GETTING_DATA",
37970xFF: "#WTF?"
3798};
3799var RBErr = evert_num(BErr);
3800
3801/* [MS-XLSB] 2.4.324 BrtColor */
3802function parse_BrtColor(data) {
3803 var out = {};
3804 var d = data.read_shift(1);
3805
3806 //var fValidRGB = d & 1;
3807 var xColorType = d >>> 1;
3808
3809 var index = data.read_shift(1);
3810 var nTS = data.read_shift(2, 'i');
3811 var bR = data.read_shift(1);
3812 var bG = data.read_shift(1);
3813 var bB = data.read_shift(1);
3814 data.l++; //var bAlpha = data.read_shift(1);
3815
3816 switch(xColorType) {
3817 case 0: out.auto = 1; break;
3818 case 1:
3819 out.index = index;
3820 var icv = XLSIcv[index];
3821 /* automatic pseudo index 81 */
3822 if(icv) out.rgb = rgb2Hex(icv);
3823 break;
3824 case 2:
3825 /* if(!fValidRGB) throw new Error("invalid"); */
3826 out.rgb = rgb2Hex([bR, bG, bB]);
3827 break;
3828 case 3: out.theme = index; break;
3829 }
3830 if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
3831
3832 return out;
3833}
3834function write_BrtColor(color, o) {
3835 if(!o) o = new_buf(8);
3836 if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
3837 if(color.index) {
3838 o.write_shift(1, 0x02);
3839 o.write_shift(1, color.index);
3840 } else if(color.theme) {
3841 o.write_shift(1, 0x06);
3842 o.write_shift(1, color.theme);
3843 } else {
3844 o.write_shift(1, 0x05);
3845 o.write_shift(1, 0);
3846 }
3847 var nTS = color.tint || 0;
3848 if(nTS > 0) nTS *= 32767;
3849 else if(nTS < 0) nTS *= 32768;
3850 o.write_shift(2, nTS);
3851 if(!color.rgb) {
3852 o.write_shift(2, 0);
3853 o.write_shift(1, 0);
3854 o.write_shift(1, 0);
3855 } else {
3856 var rgb = (color.rgb || 'FFFFFF');
3857 o.write_shift(1, parseInt(rgb.slice(0,2),16));
3858 o.write_shift(1, parseInt(rgb.slice(2,4),16));
3859 o.write_shift(1, parseInt(rgb.slice(4,6),16));
3860 o.write_shift(1, 0xFF);
3861 }
3862 return o;
3863}
3864
3865/* [MS-XLSB] 2.5.52 */
3866function parse_FontFlags(data) {
3867 var d = data.read_shift(1);
3868 data.l++;
3869 var out = {
3870 /* fBold: d & 0x01 */
3871 fItalic: d & 0x02,
3872 /* fUnderline: d & 0x04 */
3873 fStrikeout: d & 0x08,
3874 fOutline: d & 0x10,
3875 fShadow: d & 0x20,
3876 fCondense: d & 0x40,
3877 fExtend: d & 0x80
3878 };
3879 return out;
3880}
3881function write_FontFlags(font, o) {
3882 if(!o) o = new_buf(2);
3883 var grbit =
3884 (font.italic ? 0x02 : 0) |
3885 (font.strike ? 0x08 : 0) |
3886 (font.outline ? 0x10 : 0) |
3887 (font.shadow ? 0x20 : 0) |
3888 (font.condense ? 0x40 : 0) |
3889 (font.extend ? 0x80 : 0);
3890 o.write_shift(1, grbit);
3891 o.write_shift(1, 0);
3892 return o;
3893}
3894
3895/* [MS-OLEDS] 2.3.1 and 2.3.2 */
3896function parse_ClipboardFormatOrString(o, w) {
3897 // $FlowIgnore
3898 var ClipFmt = {2:"BITMAP",3:"METAFILEPICT",8:"DIB",14:"ENHMETAFILE"};
3899 var m = o.read_shift(4);
3900 switch(m) {
3901 case 0x00000000: return "";
3902 case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)]||"";
3903 }
3904 if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
3905 o.l -= 4;
3906 return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr");
3907}
3908function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); }
3909function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); }
3910
3911/* [MS-OLEPS] 2.2 PropertyType */
3912//var VT_EMPTY = 0x0000;
3913//var VT_NULL = 0x0001;
3914var VT_I2 = 0x0002;
3915var VT_I4 = 0x0003;
3916//var VT_R4 = 0x0004;
3917//var VT_R8 = 0x0005;
3918//var VT_CY = 0x0006;
3919//var VT_DATE = 0x0007;
3920//var VT_BSTR = 0x0008;
3921//var VT_ERROR = 0x000A;
3922var VT_BOOL = 0x000B;
3923var VT_VARIANT = 0x000C;
3924//var VT_DECIMAL = 0x000E;
3925//var VT_I1 = 0x0010;
3926//var VT_UI1 = 0x0011;
3927//var VT_UI2 = 0x0012;
3928var VT_UI4 = 0x0013;
3929//var VT_I8 = 0x0014;
3930//var VT_UI8 = 0x0015;
3931//var VT_INT = 0x0016;
3932//var VT_UINT = 0x0017;
3933var VT_LPSTR = 0x001E;
3934//var VT_LPWSTR = 0x001F;
3935var VT_FILETIME = 0x0040;
3936var VT_BLOB = 0x0041;
3937//var VT_STREAM = 0x0042;
3938//var VT_STORAGE = 0x0043;
3939//var VT_STREAMED_Object = 0x0044;
3940//var VT_STORED_Object = 0x0045;
3941//var VT_BLOB_Object = 0x0046;
3942var VT_CF = 0x0047;
3943//var VT_CLSID = 0x0048;
3944//var VT_VERSIONED_STREAM = 0x0049;
3945var VT_VECTOR = 0x1000;
3946//var VT_ARRAY = 0x2000;
3947
3948var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
3949var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
3950var VT_CUSTOM = [VT_STRING, VT_USTR];
3951
3952/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
3953var DocSummaryPIDDSI = {
39540x01: { n: 'CodePage', t: VT_I2 },
39550x02: { n: 'Category', t: VT_STRING },
39560x03: { n: 'PresentationFormat', t: VT_STRING },
39570x04: { n: 'ByteCount', t: VT_I4 },
39580x05: { n: 'LineCount', t: VT_I4 },
39590x06: { n: 'ParagraphCount', t: VT_I4 },
39600x07: { n: 'SlideCount', t: VT_I4 },
39610x08: { n: 'NoteCount', t: VT_I4 },
39620x09: { n: 'HiddenCount', t: VT_I4 },
39630x0a: { n: 'MultimediaClipCount', t: VT_I4 },
39640x0b: { n: 'ScaleCrop', t: VT_BOOL },
39650x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
39660x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
39670x0e: { n: 'Manager', t: VT_STRING },
39680x0f: { n: 'Company', t: VT_STRING },
39690x10: { n: 'LinksUpToDate', t: VT_BOOL },
39700x11: { n: 'CharacterCount', t: VT_I4 },
39710x13: { n: 'SharedDoc', t: VT_BOOL },
39720x16: { n: 'HyperlinksChanged', t: VT_BOOL },
39730x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
39740x18: { n: 'DigSig', t: VT_BLOB },
39750x1A: { n: 'ContentType', t: VT_STRING },
39760x1B: { n: 'ContentStatus', t: VT_STRING },
39770x1C: { n: 'Language', t: VT_STRING },
39780x1D: { n: 'Version', t: VT_STRING },
39790xFF: {}
3980};
3981
3982/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
3983var SummaryPIDSI = {
39840x01: { n: 'CodePage', t: VT_I2 },
39850x02: { n: 'Title', t: VT_STRING },
39860x03: { n: 'Subject', t: VT_STRING },
39870x04: { n: 'Author', t: VT_STRING },
39880x05: { n: 'Keywords', t: VT_STRING },
39890x06: { n: 'Comments', t: VT_STRING },
39900x07: { n: 'Template', t: VT_STRING },
39910x08: { n: 'LastAuthor', t: VT_STRING },
39920x09: { n: 'RevNumber', t: VT_STRING },
39930x0A: { n: 'EditTime', t: VT_FILETIME },
39940x0B: { n: 'LastPrinted', t: VT_FILETIME },
39950x0C: { n: 'CreatedDate', t: VT_FILETIME },
39960x0D: { n: 'ModifiedDate', t: VT_FILETIME },
39970x0E: { n: 'PageCount', t: VT_I4 },
39980x0F: { n: 'WordCount', t: VT_I4 },
39990x10: { n: 'CharCount', t: VT_I4 },
40000x11: { n: 'Thumbnail', t: VT_CF },
40010x12: { n: 'Application', t: VT_STRING },
40020x13: { n: 'DocSecurity', t: VT_I4 },
40030xFF: {}
4004};
4005
4006/* [MS-OLEPS] 2.18 */
4007var SpecialProperties = {
40080x80000000: { n: 'Locale', t: VT_UI4 },
40090x80000003: { n: 'Behavior', t: VT_UI4 },
40100x72627262: {}
4011};
4012
4013(function() {
4014 for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
4015 DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
4016})();
4017
4018var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
4019var SummaryRE = evert_key(SummaryPIDSI, "n");
4020
4021/* [MS-XLS] 2.4.63 Country/Region codes */
4022var CountryEnum = {
40230x0001: "US", // United States
40240x0002: "CA", // Canada
40250x0003: "", // Latin America (except Brazil)
40260x0007: "RU", // Russia
40270x0014: "EG", // Egypt
40280x001E: "GR", // Greece
40290x001F: "NL", // Netherlands
40300x0020: "BE", // Belgium
40310x0021: "FR", // France
40320x0022: "ES", // Spain
40330x0024: "HU", // Hungary
40340x0027: "IT", // Italy
40350x0029: "CH", // Switzerland
40360x002B: "AT", // Austria
40370x002C: "GB", // United Kingdom
40380x002D: "DK", // Denmark
40390x002E: "SE", // Sweden
40400x002F: "NO", // Norway
40410x0030: "PL", // Poland
40420x0031: "DE", // Germany
40430x0034: "MX", // Mexico
40440x0037: "BR", // Brazil
40450x003d: "AU", // Australia
40460x0040: "NZ", // New Zealand
40470x0042: "TH", // Thailand
40480x0051: "JP", // Japan
40490x0052: "KR", // Korea
40500x0054: "VN", // Viet Nam
40510x0056: "CN", // China
40520x005A: "TR", // Turkey
40530x0069: "JS", // Ramastan
40540x00D5: "DZ", // Algeria
40550x00D8: "MA", // Morocco
40560x00DA: "LY", // Libya
40570x015F: "PT", // Portugal
40580x0162: "IS", // Iceland
40590x0166: "FI", // Finland
40600x01A4: "CZ", // Czech Republic
40610x0376: "TW", // Taiwan
40620x03C1: "LB", // Lebanon
40630x03C2: "JO", // Jordan
40640x03C3: "SY", // Syria
40650x03C4: "IQ", // Iraq
40660x03C5: "KW", // Kuwait
40670x03C6: "SA", // Saudi Arabia
40680x03CB: "AE", // United Arab Emirates
40690x03CC: "IL", // Israel
40700x03CE: "QA", // Qatar
40710x03D5: "IR", // Iran
40720xFFFF: "US" // United States
4073};
4074
4075/* [MS-XLS] 2.5.127 */
4076var XLSFillPattern = [
4077 null,
4078 'solid',
4079 'mediumGray',
4080 'darkGray',
4081 'lightGray',
4082 'darkHorizontal',
4083 'darkVertical',
4084 'darkDown',
4085 'darkUp',
4086 'darkGrid',
4087 'darkTrellis',
4088 'lightHorizontal',
4089 'lightVertical',
4090 'lightDown',
4091 'lightUp',
4092 'lightGrid',
4093 'lightTrellis',
4094 'gray125',
4095 'gray0625'
4096];
4097
4098function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
4099
4100/* [MS-XLS] 2.5.161 */
4101/* [MS-XLSB] 2.5.75 Icv */
4102var XLSIcv = rgbify([
4103 /* Color Constants */
4104 0x000000,
4105 0xFFFFFF,
4106 0xFF0000,
4107 0x00FF00,
4108 0x0000FF,
4109 0xFFFF00,
4110 0xFF00FF,
4111 0x00FFFF,
4112
4113 /* Overridable Defaults */
4114 0x000000,
4115 0xFFFFFF,
4116 0xFF0000,
4117 0x00FF00,
4118 0x0000FF,
4119 0xFFFF00,
4120 0xFF00FF,
4121 0x00FFFF,
4122
4123 0x800000,
4124 0x008000,
4125 0x000080,
4126 0x808000,
4127 0x800080,
4128 0x008080,
4129 0xC0C0C0,
4130 0x808080,
4131 0x9999FF,
4132 0x993366,
4133 0xFFFFCC,
4134 0xCCFFFF,
4135 0x660066,
4136 0xFF8080,
4137 0x0066CC,
4138 0xCCCCFF,
4139
4140 0x000080,
4141 0xFF00FF,
4142 0xFFFF00,
4143 0x00FFFF,
4144 0x800080,
4145 0x800000,
4146 0x008080,
4147 0x0000FF,
4148 0x00CCFF,
4149 0xCCFFFF,
4150 0xCCFFCC,
4151 0xFFFF99,
4152 0x99CCFF,
4153 0xFF99CC,
4154 0xCC99FF,
4155 0xFFCC99,
4156
4157 0x3366FF,
4158 0x33CCCC,
4159 0x99CC00,
4160 0xFFCC00,
4161 0xFF9900,
4162 0xFF6600,
4163 0x666699,
4164 0x969696,
4165 0x003366,
4166 0x339966,
4167 0x003300,
4168 0x333300,
4169 0x993300,
4170 0x993366,
4171 0x333399,
4172 0x333333,
4173
4174 /* Other entries to appease BIFF8/12 */
4175 0xFFFFFF, /* 0x40 icvForeground ?? */
4176 0x000000, /* 0x41 icvBackground ?? */
4177 0x000000, /* 0x42 icvFrame ?? */
4178 0x000000, /* 0x43 icv3D ?? */
4179 0x000000, /* 0x44 icv3DText ?? */
4180 0x000000, /* 0x45 icv3DHilite ?? */
4181 0x000000, /* 0x46 icv3DShadow ?? */
4182 0x000000, /* 0x47 icvHilite ?? */
4183 0x000000, /* 0x48 icvCtlText ?? */
4184 0x000000, /* 0x49 icvCtlScrl ?? */
4185 0x000000, /* 0x4A icvCtlInv ?? */
4186 0x000000, /* 0x4B icvCtlBody ?? */
4187 0x000000, /* 0x4C icvCtlFrame ?? */
4188 0x000000, /* 0x4D icvCtlFore ?? */
4189 0x000000, /* 0x4E icvCtlBack ?? */
4190 0x000000, /* 0x4F icvCtlNeutral */
4191 0x000000, /* 0x50 icvInfoBk ?? */
4192 0x000000 /* 0x51 icvInfoText ?? */
4193]);
4194
4195/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
4196/* 12.3 Part Summary <SpreadsheetML> */
4197/* 14.2 Part Summary <DrawingML> */
4198/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
4199var ct2type/*{[string]:string}*/ = ({
4200 /* Workbook */
4201 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
4202
4203 /* Worksheet */
4204 "application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
4205
4206 /* Macrosheet */
4207 "application/vnd.ms-excel.intlmacrosheet": "TODO",
4208 "application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
4209
4210 /* File Properties */
4211 "application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
4212 "application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
4213 "application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
4214
4215 /* Custom Data Properties */
4216 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
4217 "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
4218
4219 /* PivotTable */
4220 "application/vnd.ms-excel.pivotTable": "TODO",
4221 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
4222
4223 /* Chart Colors */
4224 "application/vnd.ms-office.chartcolorstyle+xml": "TODO",
4225
4226 /* Chart Style */
4227 "application/vnd.ms-office.chartstyle+xml": "TODO",
4228
4229 /* Calculation Chain */
4230 "application/vnd.ms-excel.calcChain": "calcchains",
4231 "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
4232
4233 /* Printer Settings */
4234 "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
4235
4236 /* ActiveX */
4237 "application/vnd.ms-office.activeX": "TODO",
4238 "application/vnd.ms-office.activeX+xml": "TODO",
4239
4240 /* Custom Toolbars */
4241 "application/vnd.ms-excel.attachedToolbars": "TODO",
4242
4243 /* External Data Connections */
4244 "application/vnd.ms-excel.connections": "TODO",
4245 "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
4246
4247 /* External Links */
4248 "application/vnd.ms-excel.externalLink": "links",
4249 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
4250
4251 /* Metadata */
4252 "application/vnd.ms-excel.sheetMetadata": "TODO",
4253 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
4254
4255 /* PivotCache */
4256 "application/vnd.ms-excel.pivotCacheDefinition": "TODO",
4257 "application/vnd.ms-excel.pivotCacheRecords": "TODO",
4258 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
4259 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
4260
4261 /* Query Table */
4262 "application/vnd.ms-excel.queryTable": "TODO",
4263 "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
4264
4265 /* Shared Workbook */
4266 "application/vnd.ms-excel.userNames": "TODO",
4267 "application/vnd.ms-excel.revisionHeaders": "TODO",
4268 "application/vnd.ms-excel.revisionLog": "TODO",
4269 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
4270 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
4271 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
4272
4273 /* Single Cell Table */
4274 "application/vnd.ms-excel.tableSingleCells": "TODO",
4275 "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
4276
4277 /* Slicer */
4278 "application/vnd.ms-excel.slicer": "TODO",
4279 "application/vnd.ms-excel.slicerCache": "TODO",
4280 "application/vnd.ms-excel.slicer+xml": "TODO",
4281 "application/vnd.ms-excel.slicerCache+xml": "TODO",
4282
4283 /* Sort Map */
4284 "application/vnd.ms-excel.wsSortMap": "TODO",
4285
4286 /* Table */
4287 "application/vnd.ms-excel.table": "TODO",
4288 "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
4289
4290 /* Themes */
4291 "application/vnd.openxmlformats-officedocument.theme+xml": "themes",
4292
4293 /* Theme Override */
4294 "application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
4295
4296 /* Timeline */
4297 "application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
4298 "application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
4299
4300 /* VBA */
4301 "application/vnd.ms-office.vbaProject": "vba",
4302 "application/vnd.ms-office.vbaProjectSignature": "vba",
4303
4304 /* Volatile Dependencies */
4305 "application/vnd.ms-office.volatileDependencies": "TODO",
4306 "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
4307
4308 /* Control Properties */
4309 "application/vnd.ms-excel.controlproperties+xml": "TODO",
4310
4311 /* Data Model */
4312 "application/vnd.openxmlformats-officedocument.model+data": "TODO",
4313
4314 /* Survey */
4315 "application/vnd.ms-excel.Survey+xml": "TODO",
4316
4317 /* Drawing */
4318 "application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
4319 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
4320 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
4321 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
4322 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
4323 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
4324 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
4325
4326 /* VML */
4327 "application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
4328
4329 "application/vnd.openxmlformats-package.relationships+xml": "rels",
4330 "application/vnd.openxmlformats-officedocument.oleObject": "TODO",
4331
4332 /* Image */
4333 "image/png": "TODO",
4334
4335 "sheet": "js"
4336});
4337
4338var CT_LIST = (function(){
4339 var o = {
4340 workbooks: {
4341 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
4342 xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
4343 xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
4344 xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
4345 xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
4346 },
4347 strs: { /* Shared Strings */
4348 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
4349 xlsb: "application/vnd.ms-excel.sharedStrings"
4350 },
4351 comments: { /* Comments */
4352 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
4353 xlsb: "application/vnd.ms-excel.comments"
4354 },
4355 sheets: { /* Worksheet */
4356 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
4357 xlsb: "application/vnd.ms-excel.worksheet"
4358 },
4359 charts: { /* Chartsheet */
4360 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
4361 xlsb: "application/vnd.ms-excel.chartsheet"
4362 },
4363 dialogs: { /* Dialogsheet */
4364 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
4365 xlsb: "application/vnd.ms-excel.dialogsheet"
4366 },
4367 macros: { /* Macrosheet (Excel 4.0 Macros) */
4368 xlsx: "application/vnd.ms-excel.macrosheet+xml",
4369 xlsb: "application/vnd.ms-excel.macrosheet"
4370 },
4371 styles: { /* Styles */
4372 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
4373 xlsb: "application/vnd.ms-excel.styles"
4374 }
4375 };
4376 keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
4377 keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
4378 return o;
4379})();
4380
4381var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
4382
4383XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
4384
4385function new_ct() {
4386 return ({
4387 workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
4388 rels:[], strs:[], comments:[], links:[],
4389 coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
4390 calcchains:[], vba: [], drawings: [],
4391 TODO:[], xmlns: "" });
4392}
4393
4394function parse_ct(data) {
4395 var ct = new_ct();
4396 if(!data || !data.match) return ct;
4397 var ctext = {};
4398 (data.match(tagregex)||[]).forEach(function(x) {
4399 var y = parsexmltag(x);
4400 switch(y[0].replace(nsregex,"<")) {
4401 case '<?xml': break;
4402 case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
4403 case '<Default': ctext[y.Extension] = y.ContentType; break;
4404 case '<Override':
4405 if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
4406 break;
4407 }
4408 });
4409 if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
4410 ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
4411 ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
4412 ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
4413 ct.defaults = ctext;
4414 delete ct.calcchains;
4415 return ct;
4416}
4417
4418var CTYPE_XML_ROOT = writextag('Types', null, {
4419 'xmlns': XMLNS.CT,
4420 'xmlns:xsd': XMLNS.xsd,
4421 'xmlns:xsi': XMLNS.xsi
4422});
4423
4424var CTYPE_DEFAULTS = [
4425 ['xml', 'application/xml'],
4426 ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
4427 ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
4428 /* from test files */
4429 ['bmp', 'image/bmp'],
4430 ['png', 'image/png'],
4431 ['gif', 'image/gif'],
4432 ['emf', 'image/x-emf'],
4433 ['wmf', 'image/x-wmf'],
4434 ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
4435 ['tif', 'image/tiff'], ['tiff', 'image/tiff'],
4436 ['pdf', 'application/pdf'],
4437 ['rels', type2ct.rels[0]]
4438].map(function(x) {
4439 return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
4440});
4441
4442function write_ct(ct, opts) {
4443 var o = [], v;
4444 o[o.length] = (XML_HEADER);
4445 o[o.length] = (CTYPE_XML_ROOT);
4446 o = o.concat(CTYPE_DEFAULTS);
4447 var f1 = function(w) {
4448 if(ct[w] && ct[w].length > 0) {
4449 v = ct[w][0];
4450 o[o.length] = (writextag('Override', null, {
4451 'PartName': (v[0] == '/' ? "":"/") + v,
4452 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4453 }));
4454 }
4455 };
4456 var f2 = function(w) {
4457 (ct[w]||[]).forEach(function(v) {
4458 o[o.length] = (writextag('Override', null, {
4459 'PartName': (v[0] == '/' ? "":"/") + v,
4460 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4461 }));
4462 });
4463 };
4464 var f3 = function(t) {
4465 (ct[t]||[]).forEach(function(v) {
4466 o[o.length] = (writextag('Override', null, {
4467 'PartName': (v[0] == '/' ? "":"/") + v,
4468 'ContentType': type2ct[t][0]
4469 }));
4470 });
4471 };
4472 f1('workbooks');
4473 f2('sheets');
4474 f2('charts');
4475 f3('themes');
4476 ['strs', 'styles'].forEach(f1);
4477 ['coreprops', 'extprops', 'custprops'].forEach(f3);
4478 f3('vba');
4479 f3('comments');
4480 f3('drawings');
4481 if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
4482 return o.join("");
4483}
4484/* 9.3 Relationships */
4485var RELS = ({
4486 WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4487 SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4488 HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
4489 VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
4490 VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
4491});
4492
4493/* 9.3.3 Representing Relationships */
4494function get_rels_path(file) {
4495 var n = file.lastIndexOf("/");
4496 return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
4497}
4498
4499function parse_rels(data, currentFilePath) {
4500 if (!data) return data;
4501 if (currentFilePath.charAt(0) !== '/') {
4502 currentFilePath = '/'+currentFilePath;
4503 }
4504 var rels = {};
4505 var hash = {};
4506
4507 (data.match(tagregex)||[]).forEach(function(x) {
4508 var y = parsexmltag(x);
4509 /* 9.3.2.2 OPC_Relationships */
4510 if (y[0] === '<Relationship') {
4511 var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
4512 var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
4513 rels[canonictarget] = rel;
4514 hash[y.Id] = rel;
4515 }
4516 });
4517 rels["!id"] = hash;
4518 return rels;
4519}
4520
4521XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
4522
4523var RELS_ROOT = writextag('Relationships', null, {
4524 //'xmlns:ns0': XMLNS.RELS,
4525 'xmlns': XMLNS.RELS
4526});
4527
4528/* TODO */
4529function write_rels(rels) {
4530 var o = [XML_HEADER, RELS_ROOT];
4531 keys(rels['!id']).forEach(function(rid) {
4532 o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
4533 });
4534 if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
4535 return o.join("");
4536}
4537
4538function add_rels(rels, rId, f, type, relobj) {
4539 if(!relobj) relobj = {};
4540 if(!rels['!id']) rels['!id'] = {};
4541 if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
4542 relobj.Id = 'rId' + rId;
4543 relobj.Type = type;
4544 relobj.Target = f;
4545 if(relobj.Type == RELS.HLINK) relobj.TargetMode = "External";
4546 if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
4547 rels['!id'][relobj.Id] = relobj;
4548 rels[('/' + relobj.Target).replace("//","/")] = relobj;
4549 return rId;
4550}
4551/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
4552/* Part 3 Section 4 Manifest File */
4553var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
4554function parse_manifest(d, opts) {
4555 var str = xlml_normalize(d);
4556 var Rn;
4557 var FEtag;
4558 while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
4559 case 'manifest': break; // 4.2 <manifest:manifest>
4560 case 'file-entry': // 4.3 <manifest:file-entry>
4561 FEtag = parsexmltag(Rn[0], false);
4562 if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
4563 break;
4564 case 'encryption-data': // 4.4 <manifest:encryption-data>
4565 case 'algorithm': // 4.5 <manifest:algorithm>
4566 case 'start-key-generation': // 4.6 <manifest:start-key-generation>
4567 case 'key-derivation': // 4.7 <manifest:key-derivation>
4568 throw new Error("Unsupported ODS Encryption");
4569 default: if(opts && opts.WTF) throw Rn;
4570 }
4571}
4572
4573function write_manifest(manifest) {
4574 var o = [XML_HEADER];
4575 o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
4576 o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
4577 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');
4578 o.push('</manifest:manifest>');
4579 return o.join("");
4580}
4581
4582/* Part 3 Section 6 Metadata Manifest File */
4583function write_rdf_type(file, res, tag) {
4584 return [
4585 ' <rdf:Description rdf:about="' + file + '">\n',
4586 ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
4587 ' </rdf:Description>\n'
4588 ].join("");
4589}
4590function write_rdf_has(base, file) {
4591 return [
4592 ' <rdf:Description rdf:about="' + base + '">\n',
4593 ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
4594 ' </rdf:Description>\n'
4595 ].join("");
4596}
4597function write_rdf(rdf) {
4598 var o = [XML_HEADER];
4599 o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
4600 for(var i = 0; i != rdf.length; ++i) {
4601 o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
4602 o.push(write_rdf_has("",rdf[i][0]));
4603 }
4604 o.push(write_rdf_type("","Document", "pkg"));
4605 o.push('</rdf:RDF>');
4606 return o.join("");
4607}
4608/* TODO: pull properties */
4609var write_meta_ods = (function() {
4610 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>';
4611 return function wmo() {
4612 return payload;
4613 };
4614})();
4615
4616/* ECMA-376 Part II 11.1 Core Properties Part */
4617/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4618var CORE_PROPS = [
4619 ["cp:category", "Category"],
4620 ["cp:contentStatus", "ContentStatus"],
4621 ["cp:keywords", "Keywords"],
4622 ["cp:lastModifiedBy", "LastAuthor"],
4623 ["cp:lastPrinted", "LastPrinted"],
4624 ["cp:revision", "RevNumber"],
4625 ["cp:version", "Version"],
4626 ["dc:creator", "Author"],
4627 ["dc:description", "Comments"],
4628 ["dc:identifier", "Identifier"],
4629 ["dc:language", "Language"],
4630 ["dc:subject", "Subject"],
4631 ["dc:title", "Title"],
4632 ["dcterms:created", "CreatedDate", 'date'],
4633 ["dcterms:modified", "ModifiedDate", 'date']
4634];
4635
4636XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
4637RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
4638
4639var CORE_PROPS_REGEX = (function() {
4640 var r = new Array(CORE_PROPS.length);
4641 for(var i = 0; i < CORE_PROPS.length; ++i) {
4642 var f = CORE_PROPS[i];
4643 var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
4644 r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
4645 }
4646 return r;
4647})();
4648
4649function parse_core_props(data) {
4650 var p = {};
4651 data = utf8read(data);
4652
4653 for(var i = 0; i < CORE_PROPS.length; ++i) {
4654 var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4655 if(cur != null && cur.length > 0) p[f[1]] = cur[1];
4656 if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4657 }
4658
4659 return p;
4660}
4661
4662var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4663 //'xmlns': XMLNS.CORE_PROPS,
4664 'xmlns:cp': XMLNS.CORE_PROPS,
4665 'xmlns:dc': XMLNS.dc,
4666 'xmlns:dcterms': XMLNS.dcterms,
4667 'xmlns:dcmitype': XMLNS.dcmitype,
4668 'xmlns:xsi': XMLNS.xsi
4669});
4670
4671function cp_doit(f, g, h, o, p) {
4672 if(p[f] != null || g == null || g === "") return;
4673 p[f] = g;
4674 o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4675}
4676
4677function write_core_props(cp, _opts) {
4678 var opts = _opts || {};
4679 var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4680 if(!cp && !opts.Props) return o.join("");
4681
4682 if(cp) {
4683 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);
4684 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);
4685 }
4686
4687 for(var i = 0; i != CORE_PROPS.length; ++i) {
4688 var f = CORE_PROPS[i];
4689 var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4690 if(v === true) v = "1";
4691 else if(v === false) v = "0";
4692 else if(typeof v == "number") v = String(v);
4693 if(v != null) cp_doit(f[0], v, null, o, p);
4694 }
4695 if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4696 return o.join("");
4697}
4698/* 15.2.12.3 Extended File Properties Part */
4699/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4700var EXT_PROPS = [
4701 ["Application", "Application", "string"],
4702 ["AppVersion", "AppVersion", "string"],
4703 ["Company", "Company", "string"],
4704 ["DocSecurity", "DocSecurity", "string"],
4705 ["Manager", "Manager", "string"],
4706 ["HyperlinksChanged", "HyperlinksChanged", "bool"],
4707 ["SharedDoc", "SharedDoc", "bool"],
4708 ["LinksUpToDate", "LinksUpToDate", "bool"],
4709 ["ScaleCrop", "ScaleCrop", "bool"],
4710 ["HeadingPairs", "HeadingPairs", "raw"],
4711 ["TitlesOfParts", "TitlesOfParts", "raw"]
4712];
4713
4714XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4715RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4716
4717var PseudoPropsPairs = [
4718 "Worksheets", "SheetNames",
4719 "NamedRanges", "DefinedNames",
4720 "Chartsheets", "ChartNames"
4721];
4722function load_props_pairs(HP, TOP, props, opts) {
4723 var v = [];
4724 if(typeof HP == "string") v = parseVector(HP, opts);
4725 else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4726 var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4727 var idx = 0, len = 0;
4728 if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4729 len = +(v[i+1].v);
4730 switch(v[i].v) {
4731 case "Worksheets":
4732 case "工作表":
4733 case "Листы":
4734 case "أوراق العمل":
4735 case "ワークシート":
4736 case "גליונות עבודה":
4737 case "Arbeitsblätter":
4738 case "Çalışma Sayfaları":
4739 case "Feuilles de calcul":
4740 case "Fogli di lavoro":
4741 case "Folhas de cálculo":
4742 case "Planilhas":
4743 case "Regneark":
4744 case "Werkbladen":
4745 props.Worksheets = len;
4746 props.SheetNames = parts.slice(idx, idx + len);
4747 break;
4748
4749 case "Named Ranges":
4750 case "名前付き一覧":
4751 case "Benannte Bereiche":
4752 case "Navngivne områder":
4753 props.NamedRanges = len;
4754 props.DefinedNames = parts.slice(idx, idx + len);
4755 break;
4756
4757 case "Charts":
4758 case "Diagramme":
4759 props.Chartsheets = len;
4760 props.ChartNames = parts.slice(idx, idx + len);
4761 break;
4762 }
4763 idx += len;
4764 }
4765}
4766
4767function parse_ext_props(data, p, opts) {
4768 var q = {}; if(!p) p = {};
4769 data = utf8read(data);
4770
4771 EXT_PROPS.forEach(function(f) {
4772 switch(f[2]) {
4773 case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
4774 case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
4775 case "raw":
4776 var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4777 if(cur && cur.length > 0) q[f[1]] = cur[1];
4778 break;
4779 }
4780 });
4781
4782 if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4783
4784 return p;
4785}
4786
4787var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4788 'xmlns': XMLNS.EXT_PROPS,
4789 'xmlns:vt': XMLNS.vt
4790});
4791
4792function write_ext_props(cp) {
4793 var o = [], W = writextag;
4794 if(!cp) cp = {};
4795 cp.Application = "SheetJS";
4796 o[o.length] = (XML_HEADER);
4797 o[o.length] = (EXT_PROPS_XML_ROOT);
4798
4799 EXT_PROPS.forEach(function(f) {
4800 if(cp[f[1]] === undefined) return;
4801 var v;
4802 switch(f[2]) {
4803 case 'string': v = String(cp[f[1]]); break;
4804 case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4805 }
4806 if(v !== undefined) o[o.length] = (W(f[0], v));
4807 });
4808
4809 /* TODO: HeadingPairs, TitlesOfParts */
4810 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"})));
4811 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"})));
4812 if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4813 return o.join("");
4814}
4815/* 15.2.12.2 Custom File Properties Part */
4816XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4817RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4818
4819var custregex = /<[^>]+>[^<]*/g;
4820function parse_cust_props(data, opts) {
4821 var p = {}, name = "";
4822 var m = data.match(custregex);
4823 if(m) for(var i = 0; i != m.length; ++i) {
4824 var x = m[i], y = parsexmltag(x);
4825 switch(y[0]) {
4826 case '<?xml': break;
4827 case '<Properties': break;
4828 case '<property': name = y.name; break;
4829 case '</property>': name = null; break;
4830 default: if (x.indexOf('<vt:') === 0) {
4831 var toks = x.split('>');
4832 var type = toks[0].slice(4), text = toks[1];
4833 /* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4834 switch(type) {
4835 case 'lpstr': case 'bstr': case 'lpwstr':
4836 p[name] = unescapexml(text);
4837 break;
4838 case 'bool':
4839 p[name] = parsexmlbool(text);
4840 break;
4841 case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4842 p[name] = parseInt(text, 10);
4843 break;
4844 case 'r4': case 'r8': case 'decimal':
4845 p[name] = parseFloat(text);
4846 break;
4847 case 'filetime': case 'date':
4848 p[name] = parseDate(text);
4849 break;
4850 case 'cy': case 'error':
4851 p[name] = unescapexml(text);
4852 break;
4853 default:
4854 if(type.slice(-1) == '/') break;
4855 if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4856 }
4857 } else if(x.slice(0,2) === "</") {/* empty */
4858 } else if(opts.WTF) throw new Error(x);
4859 }
4860 }
4861 return p;
4862}
4863
4864var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4865 'xmlns': XMLNS.CUST_PROPS,
4866 'xmlns:vt': XMLNS.vt
4867});
4868
4869function write_cust_props(cp) {
4870 var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4871 if(!cp) return o.join("");
4872 var pid = 1;
4873 keys(cp).forEach(function custprop(k) { ++pid;
4874 o[o.length] = (writextag('property', write_vt(cp[k]), {
4875 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4876 'pid': pid,
4877 'name': k
4878 }));
4879 });
4880 if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4881 return o.join("");
4882}
4883/* Common Name -> XLML Name */
4884var XLMLDocPropsMap = {
4885 Title: 'Title',
4886 Subject: 'Subject',
4887 Author: 'Author',
4888 Keywords: 'Keywords',
4889 Comments: 'Description',
4890 LastAuthor: 'LastAuthor',
4891 RevNumber: 'Revision',
4892 Application: 'AppName',
4893 /* TotalTime: 'TotalTime', */
4894 LastPrinted: 'LastPrinted',
4895 CreatedDate: 'Created',
4896 ModifiedDate: 'LastSaved',
4897 /* Pages */
4898 /* Words */
4899 /* Characters */
4900 Category: 'Category',
4901 /* PresentationFormat */
4902 Manager: 'Manager',
4903 Company: 'Company',
4904 /* Guid */
4905 /* HyperlinkBase */
4906 /* Bytes */
4907 /* Lines */
4908 /* Paragraphs */
4909 /* CharactersWithSpaces */
4910 AppVersion: 'Version',
4911
4912 ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
4913 Identifier: 'Identifier', /* NOTE: missing from schema */
4914 Language: 'Language' /* NOTE: missing from schema */
4915};
4916var evert_XLMLDPM = evert(XLMLDocPropsMap);
4917
4918function xlml_set_prop(Props, tag, val) {
4919 tag = evert_XLMLDPM[tag] || tag;
4920 Props[tag] = val;
4921}
4922
4923function xlml_write_docprops(Props, opts) {
4924 var o = [];
4925 keys(XLMLDocPropsMap).map(function(m) {
4926 for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
4927 for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
4928 throw m;
4929 }).forEach(function(p) {
4930 if(Props[p[1]] == null) return;
4931 var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
4932 switch(p[2]) {
4933 case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
4934 }
4935 if(typeof m == 'number') m = String(m);
4936 else if(m === true || m === false) { m = m ? "1" : "0"; }
4937 else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
4938 o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
4939 });
4940 return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
4941}
4942function xlml_write_custprops(Props, Custprops) {
4943 var BLACKLIST = ["Worksheets","SheetNames"];
4944 var T = 'CustomDocumentProperties';
4945 var o = [];
4946 if(Props) keys(Props).forEach(function(k) {
4947if(!Props.hasOwnProperty(k)) return;
4948 for(var i = 0; i < CORE_PROPS.length; ++i) if(k == CORE_PROPS[i][1]) return;
4949 for(i = 0; i < EXT_PROPS.length; ++i) if(k == EXT_PROPS[i][1]) return;
4950 for(i = 0; i < BLACKLIST.length; ++i) if(k == BLACKLIST[i]) return;
4951
4952 var m = Props[k];
4953 var t = "string";
4954 if(typeof m == 'number') { t = "float"; m = String(m); }
4955 else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
4956 else m = String(m);
4957 o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
4958 });
4959 if(Custprops) keys(Custprops).forEach(function(k) {
4960if(!Custprops.hasOwnProperty(k)) return;
4961 if(Props && Props.hasOwnProperty(k)) return;
4962 var m = Custprops[k];
4963 var t = "string";
4964 if(typeof m == 'number') { t = "float"; m = String(m); }
4965 else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
4966 else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); }
4967 else m = String(m);
4968 o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
4969 });
4970 return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
4971}
4972/* [MS-DTYP] 2.3.3 FILETIME */
4973/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
4974/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
4975function parse_FILETIME(blob) {
4976 var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
4977 return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
4978}
4979function write_FILETIME(time) {
4980 var date = (typeof time == "string") ? new Date(Date.parse(time)) : time;
4981 var t = date.getTime() / 1000 + 11644473600;
4982 var l = t % Math.pow(2,32), h = (t - l) / Math.pow(2,32);
4983 l *= 1e7; h *= 1e7;
4984 var w = (l / Math.pow(2,32)) | 0;
4985 if(w > 0) { l = l % Math.pow(2,32); h += w; }
4986 var o = new_buf(8); o.write_shift(4, l); o.write_shift(4, h); return o;
4987}
4988
4989/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
4990function parse_lpstr(blob, type, pad) {
4991 var start = blob.l;
4992 var str = blob.read_shift(0, 'lpstr-cp');
4993 if(pad) while((blob.l - start) & 3) ++blob.l;
4994 return str;
4995}
4996
4997/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
4998function parse_lpwstr(blob, type, pad) {
4999 var str = blob.read_shift(0, 'lpwstr');
5000 if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
5001 return str;
5002}
5003
5004
5005/* [MS-OSHARED] 2.3.3.1.11 VtString */
5006/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
5007function parse_VtStringBase(blob, stringType, pad) {
5008 if(stringType === 0x1F /*VT_LPWSTR*/) return parse_lpwstr(blob);
5009 return parse_lpstr(blob, stringType, pad);
5010}
5011
5012function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
5013function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); }
5014
5015/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
5016function parse_VtVecUnalignedLpstrValue(blob) {
5017 var length = blob.read_shift(4);
5018 var ret = [];
5019 for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,'');
5020 return ret;
5021}
5022
5023/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
5024function parse_VtVecUnalignedLpstr(blob) {
5025 return parse_VtVecUnalignedLpstrValue(blob);
5026}
5027
5028/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
5029function parse_VtHeadingPair(blob) {
5030 var headingString = parse_TypedPropertyValue(blob, VT_USTR);
5031 var headerParts = parse_TypedPropertyValue(blob, VT_I4);
5032 return [headingString, headerParts];
5033}
5034
5035/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
5036function parse_VtVecHeadingPairValue(blob) {
5037 var cElements = blob.read_shift(4);
5038 var out = [];
5039 for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
5040 return out;
5041}
5042
5043/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
5044function parse_VtVecHeadingPair(blob) {
5045 // NOTE: When invoked, wType & padding were already consumed
5046 return parse_VtVecHeadingPairValue(blob);
5047}
5048
5049/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
5050function parse_dictionary(blob,CodePage) {
5051 var cnt = blob.read_shift(4);
5052 var dict = ({});
5053 for(var j = 0; j != cnt; ++j) {
5054 var pid = blob.read_shift(4);
5055 var len = blob.read_shift(4);
5056 dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
5057 if(CodePage === 0x4B0 && (len % 2)) blob.l += 2;
5058 }
5059 if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
5060 return dict;
5061}
5062
5063/* [MS-OLEPS] 2.9 BLOB */
5064function parse_BLOB(blob) {
5065 var size = blob.read_shift(4);
5066 var bytes = blob.slice(blob.l,blob.l+size);
5067 blob.l += size;
5068 if((size & 3) > 0) blob.l += (4 - (size & 3)) & 3;
5069 return bytes;
5070}
5071
5072/* [MS-OLEPS] 2.11 ClipboardData */
5073function parse_ClipboardData(blob) {
5074 // TODO
5075 var o = {};
5076 o.Size = blob.read_shift(4);
5077 //o.Format = blob.read_shift(4);
5078 blob.l += o.Size + 3 - (o.Size - 1) % 4;
5079 return o;
5080}
5081
5082/* [MS-OLEPS] 2.15 TypedPropertyValue */
5083function parse_TypedPropertyValue(blob, type, _opts) {
5084 var t = blob.read_shift(2), ret, opts = _opts||{};
5085 blob.l += 2;
5086 if(type !== VT_VARIANT)
5087 if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
5088 switch(type === VT_VARIANT ? t : type) {
5089 case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
5090 case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
5091 case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
5092 case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
5093 case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
5094 case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
5095 case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
5096 case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
5097 case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
5098 case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw).replace(chr0,'');
5099 case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t/*, 4*/).replace(chr0,'');
5100 case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
5101 case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
5102 default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
5103 }
5104}
5105function write_TypedPropertyValue(type, value) {
5106 var o = new_buf(4), p = new_buf(4);
5107 o.write_shift(4, type == 0x50 ? 0x1F : type);
5108 switch(type) {
5109 case 0x03 /*VT_I4*/: p.write_shift(-4, value); break;
5110 case 0x05 /*VT_I4*/: p = new_buf(8); p.write_shift(8, value, 'f'); break;
5111 case 0x0B /*VT_BOOL*/: p.write_shift(4, value ? 0x01 : 0x00); break;
5112 case 0x40 /*VT_FILETIME*/: p = write_FILETIME(value); break;
5113 case 0x1F /*VT_LPWSTR*/:
5114 case 0x50 /*VT_STRING*/:
5115p = new_buf(4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
5116 p.write_shift(4, value.length + 1);
5117 p.write_shift(0, value, "dbcs");
5118 while(p.l != p.length) p.write_shift(1, 0);
5119 break;
5120 default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + value);
5121 }
5122 return bconcat([o, p]);
5123}
5124
5125/* [MS-OLEPS] 2.20 PropertySet */
5126function parse_PropertySet(blob, PIDSI) {
5127 var start_addr = blob.l;
5128 var size = blob.read_shift(4);
5129 var NumProps = blob.read_shift(4);
5130 var Props = [], i = 0;
5131 var CodePage = 0;
5132 var Dictionary = -1, DictObj = ({});
5133 for(i = 0; i != NumProps; ++i) {
5134 var PropID = blob.read_shift(4);
5135 var Offset = blob.read_shift(4);
5136 Props[i] = [PropID, Offset + start_addr];
5137 }
5138 Props.sort(function(x,y) { return x[1] - y[1]; });
5139 var PropH = {};
5140 for(i = 0; i != NumProps; ++i) {
5141 if(blob.l !== Props[i][1]) {
5142 var fail = true;
5143 if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
5144 case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break;
5145 case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
5146 case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
5147 }
5148 if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
5149 if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
5150 }
5151 if(PIDSI) {
5152 var piddsi = PIDSI[Props[i][0]];
5153 PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
5154 if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + ("0000" + String(PropH[piddsi.n] & 0xFFFF)).slice(-4);
5155 if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
5156 case 0: PropH[piddsi.n] = 1252;
5157 /* falls through */
5158 case 874:
5159 case 932:
5160 case 936:
5161 case 949:
5162 case 950:
5163 case 1250:
5164 case 1251:
5165 case 1253:
5166 case 1254:
5167 case 1255:
5168 case 1256:
5169 case 1257:
5170 case 1258:
5171 case 10000:
5172 case 1200:
5173 case 1201:
5174 case 1252:
5175 case 65000: case -536:
5176 case 65001: case -535:
5177 set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
5178 default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
5179 }
5180 } else {
5181 if(Props[i][0] === 0x1) {
5182 CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2));
5183 set_cp(CodePage);
5184 if(Dictionary !== -1) {
5185 var oldpos = blob.l;
5186 blob.l = Props[Dictionary][1];
5187 DictObj = parse_dictionary(blob,CodePage);
5188 blob.l = oldpos;
5189 }
5190 } else if(Props[i][0] === 0) {
5191 if(CodePage === 0) { Dictionary = i; blob.l = Props[i+1][1]; continue; }
5192 DictObj = parse_dictionary(blob,CodePage);
5193 } else {
5194 var name = DictObj[Props[i][0]];
5195 var val;
5196 /* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
5197 switch(blob[blob.l]) {
5198 case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
5199 case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
5200 case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
5201 case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
5202 case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
5203 case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
5204 case 0x0B /*VT_BOOL*/: blob.l += 4; val = parsebool(blob, 4); break;
5205 case 0x40 /*VT_FILETIME*/: blob.l += 4; val = parseDate(parse_FILETIME(blob)); break;
5206 default: throw new Error("unparsed value: " + blob[blob.l]);
5207 }
5208 PropH[name] = val;
5209 }
5210 }
5211 }
5212 blob.l = start_addr + size; /* step ahead to skip padding */
5213 return PropH;
5214}
5215var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs);
5216function guess_property_type(val) {
5217 switch(typeof val) {
5218 case "boolean": return 0x0B;
5219 case "number": return ((val|0)==val) ? 0x03 : 0x05;
5220 case "string": return 0x1F;
5221 case "object": if(val instanceof Date) return 0x40; break;
5222 }
5223 return -1;
5224}
5225function write_PropertySet(entries, RE, PIDSI) {
5226 var hdr = new_buf(8), piao = [], prop = [];
5227 var sz = 8, i = 0;
5228
5229 var pr = new_buf(8), pio = new_buf(8);
5230 pr.write_shift(4, 0x0002);
5231 pr.write_shift(4, 0x04B0);
5232 pio.write_shift(4, 0x0001);
5233 prop.push(pr); piao.push(pio);
5234 sz += 8 + pr.length;
5235
5236 if(!RE) {
5237 pio = new_buf(8);
5238 pio.write_shift(4, 0);
5239 piao.unshift(pio);
5240
5241 var bufs = [new_buf(4)];
5242 bufs[0].write_shift(4, entries.length);
5243 for(i = 0; i < entries.length; ++i) {
5244 var value = entries[i][0];
5245 pr = new_buf(4 + 4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
5246 pr.write_shift(4, i+2);
5247 pr.write_shift(4, value.length + 1);
5248 pr.write_shift(0, value, "dbcs");
5249 while(pr.l != pr.length) pr.write_shift(1, 0);
5250 bufs.push(pr);
5251 }
5252 pr = bconcat(bufs);
5253 prop.unshift(pr);
5254 sz += 8 + pr.length;
5255 }
5256
5257 for(i = 0; i < entries.length; ++i) {
5258 if(RE && !RE[entries[i][0]]) continue;
5259 if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue;
5260 if(entries[i][1] == null) continue;
5261
5262 var val = entries[i][1], idx = 0;
5263 if(RE) {
5264 idx = +RE[entries[i][0]];
5265 var pinfo = (PIDSI)[idx];
5266 if(pinfo.p == "version" && typeof val == "string") {
5267var arr = val.split(".");
5268 val = ((+arr[0])<<16) + ((+arr[1])||0);
5269 }
5270 pr = write_TypedPropertyValue(pinfo.t, val);
5271 } else {
5272 var T = guess_property_type(val);
5273 if(T == -1) { T = 0x1F; val = String(val); }
5274 pr = write_TypedPropertyValue(T, val);
5275 }
5276 prop.push(pr);
5277
5278 pio = new_buf(8);
5279 pio.write_shift(4, !RE ? 2+i : idx);
5280 piao.push(pio);
5281
5282 sz += 8 + pr.length;
5283 }
5284
5285 var w = 8 * (prop.length + 1);
5286 for(i = 0; i < prop.length; ++i) { piao[i].write_shift(4, w); w += prop[i].length; }
5287 hdr.write_shift(4, sz);
5288 hdr.write_shift(4, prop.length);
5289 return bconcat([hdr].concat(piao).concat(prop));
5290}
5291
5292/* [MS-OLEPS] 2.21 PropertySetStream */
5293function parse_PropertySetStream(file, PIDSI, clsid) {
5294 var blob = file.content;
5295 if(!blob) return ({});
5296 prep_blob(blob, 0);
5297
5298 var NumSets, FMTID0, FMTID1, Offset0, Offset1 = 0;
5299 blob.chk('feff', 'Byte Order: ');
5300
5301 /*var vers = */blob.read_shift(2); // TODO: check version
5302 var SystemIdentifier = blob.read_shift(4);
5303 var CLSID = blob.read_shift(16);
5304 if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
5305 NumSets = blob.read_shift(4);
5306 if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
5307 FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
5308
5309 if(NumSets === 1 && Offset0 !== blob.l) throw new Error("Length mismatch: " + Offset0 + " !== " + blob.l);
5310 else if(NumSets === 2) { FMTID1 = blob.read_shift(16); Offset1 = blob.read_shift(4); }
5311 var PSet0 = parse_PropertySet(blob, PIDSI);
5312
5313 var rval = ({ SystemIdentifier: SystemIdentifier });
5314 for(var y in PSet0) rval[y] = PSet0[y];
5315 //rval.blob = blob;
5316 rval.FMTID = FMTID0;
5317 //rval.PSet0 = PSet0;
5318 if(NumSets === 1) return rval;
5319 if(Offset1 - blob.l == 2) blob.l += 2;
5320 if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
5321 var PSet1;
5322 try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
5323 for(y in PSet1) rval[y] = PSet1[y];
5324 rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
5325 return rval;
5326}
5327function write_PropertySetStream(entries, clsid, RE, PIDSI, entries2, clsid2) {
5328 var hdr = new_buf(entries2 ? 68 : 48);
5329 var bufs = [hdr];
5330 hdr.write_shift(2, 0xFFFE);
5331 hdr.write_shift(2, 0x0000); /* TODO: type 1 props */
5332 hdr.write_shift(4, 0x32363237);
5333 hdr.write_shift(16, CFB.utils.consts.HEADER_CLSID, "hex");
5334 hdr.write_shift(4, (entries2 ? 2 : 1));
5335 hdr.write_shift(16, clsid, "hex");
5336 hdr.write_shift(4, (entries2 ? 68 : 48));
5337 var ps0 = write_PropertySet(entries, RE, PIDSI);
5338 bufs.push(ps0);
5339
5340 if(entries2) {
5341 var ps1 = write_PropertySet(entries2, null, null);
5342 hdr.write_shift(16, clsid2, "hex");
5343 hdr.write_shift(4, 68 + ps0.length);
5344 bufs.push(ps1);
5345 }
5346 return bconcat(bufs);
5347}
5348
5349function parsenoop2(blob, length) { blob.read_shift(length); return null; }
5350function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j<n; ++j) o.write_shift(1, 0); return o; }
5351
5352function parslurp(blob, length, cb) {
5353 var arr = [], target = blob.l + length;
5354 while(blob.l < target) arr.push(cb(blob, target - blob.l));
5355 if(target !== blob.l) throw new Error("Slurp error");
5356 return arr;
5357}
5358
5359function parsebool(blob, length) { return blob.read_shift(length) === 0x1; }
5360function writebool(v, o) { if(!o) o=new_buf(2); o.write_shift(2, +!!v); return o; }
5361
5362function parseuint16(blob) { return blob.read_shift(2, 'u'); }
5363function writeuint16(v, o) { if(!o) o=new_buf(2); o.write_shift(2, v); return o; }
5364function parseuint16a(blob, length) { return parslurp(blob,length,parseuint16);}
5365
5366/* --- 2.5 Structures --- */
5367
5368/* [MS-XLS] 2.5.10 Bes (boolean or error) */
5369function parse_Bes(blob) {
5370 var v = blob.read_shift(1), t = blob.read_shift(1);
5371 return t === 0x01 ? v : v === 0x01;
5372}
5373function write_Bes(v, t, o) {
5374 if(!o) o = new_buf(2);
5375 o.write_shift(1, +v);
5376 o.write_shift(1, ((t == 'e') ? 1 : 0));
5377 return o;
5378}
5379
5380/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
5381function parse_ShortXLUnicodeString(blob, length, opts) {
5382 var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1);
5383 var encoding = 'sbcs-cont';
5384 var cp = current_codepage;
5385 if(opts && opts.biff >= 8) current_codepage = 1200;
5386 if(!opts || opts.biff == 8 ) {
5387 var fHighByte = blob.read_shift(1);
5388 if(fHighByte) { encoding = 'dbcs-cont'; }
5389 } else if(opts.biff == 12) {
5390 encoding = 'wstr';
5391 }
5392 if(opts.biff >= 2 && opts.biff <= 5) encoding = 'cpstr';
5393 var o = cch ? blob.read_shift(cch, encoding) : "";
5394 current_codepage = cp;
5395 return o;
5396}
5397
5398/* 2.5.293 XLUnicodeRichExtendedString */
5399function parse_XLUnicodeRichExtendedString(blob) {
5400 var cp = current_codepage;
5401 current_codepage = 1200;
5402 var cch = blob.read_shift(2), flags = blob.read_shift(1);
5403 var /*fHighByte = flags & 0x1,*/ fExtSt = flags & 0x4, fRichSt = flags & 0x8;
5404 var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
5405 var cRun = 0, cbExtRst;
5406 var z = {};
5407 if(fRichSt) cRun = blob.read_shift(2);
5408 if(fExtSt) cbExtRst = blob.read_shift(4);
5409 var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont';
5410 var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
5411 if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
5412 if(fExtSt) blob.l += cbExtRst; //TODO: parse this
5413 z.t = msg;
5414 if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
5415 current_codepage = cp;
5416 return z;
5417}
5418
5419/* 2.5.296 XLUnicodeStringNoCch */
5420function parse_XLUnicodeStringNoCch(blob, cch, opts) {
5421 var retval;
5422 if(opts) {
5423 if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'cpstr');
5424 if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
5425 }
5426 var fHighByte = blob.read_shift(1);
5427 if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
5428 else { retval = blob.read_shift(cch, 'dbcs-cont'); }
5429 return retval;
5430}
5431
5432/* 2.5.294 XLUnicodeString */
5433function parse_XLUnicodeString(blob, length, opts) {
5434 var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
5435 if(cch === 0) { blob.l++; return ""; }
5436 return parse_XLUnicodeStringNoCch(blob, cch, opts);
5437}
5438/* BIFF5 override */
5439function parse_XLUnicodeString2(blob, length, opts) {
5440 if(opts.biff > 5) return parse_XLUnicodeString(blob, length, opts);
5441 var cch = blob.read_shift(1);
5442 if(cch === 0) { blob.l++; return ""; }
5443 return blob.read_shift(cch, (opts.biff <= 4 || !blob.lens ) ? 'cpstr' : 'sbcs-cont');
5444}
5445/* TODO: BIFF5 and lower, codepage awareness */
5446function write_XLUnicodeString(str, opts, o) {
5447 if(!o) o = new_buf(3 + 2 * str.length);
5448 o.write_shift(2, str.length);
5449 o.write_shift(1, 1);
5450 o.write_shift(31, str, 'utf16le');
5451 return o;
5452}
5453
5454/* [MS-XLS] 2.5.61 ControlInfo */
5455function parse_ControlInfo(blob) {
5456 var flags = blob.read_shift(1);
5457 blob.l++;
5458 var accel = blob.read_shift(2);
5459 blob.l += 2;
5460 return [flags, accel];
5461}
5462
5463/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
5464function parse_URLMoniker(blob) {
5465 var len = blob.read_shift(4), start = blob.l;
5466 var extra = false;
5467 if(len > 24) {
5468 /* look ahead */
5469 blob.l += len - 24;
5470 if(blob.read_shift(16) === "795881f43b1d7f48af2c825dc4852763") extra = true;
5471 blob.l = start;
5472 }
5473 var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
5474 if(extra) blob.l += 24;
5475 return url;
5476}
5477
5478/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
5479function parse_FileMoniker(blob) {
5480 blob.l += 2; //var cAnti = blob.read_shift(2);
5481 var ansiPath = blob.read_shift(0, 'lpstr-ansi');
5482 blob.l += 2; //var endServer = blob.read_shift(2);
5483 if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker");
5484 var sz = blob.read_shift(4);
5485 if(sz === 0) return ansiPath.replace(/\\/g,"/");
5486 var bytes = blob.read_shift(4);
5487 if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker");
5488 var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,"");
5489 return unicodePath;
5490}
5491
5492/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
5493function parse_HyperlinkMoniker(blob, length) {
5494 var clsid = blob.read_shift(16); length -= 16;
5495 switch(clsid) {
5496 case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
5497 case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
5498 default: throw new Error("Unsupported Moniker " + clsid);
5499 }
5500}
5501
5502/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
5503function parse_HyperlinkString(blob) {
5504 var len = blob.read_shift(4);
5505 var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
5506 return o;
5507}
5508
5509/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
5510function parse_Hyperlink(blob, length) {
5511 var end = blob.l + length;
5512 var sVer = blob.read_shift(4);
5513 if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
5514 var flags = blob.read_shift(2);
5515 blob.l += 2;
5516 var displayName, targetFrameName, moniker, oleMoniker, Loc="", guid, fileTime;
5517 if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
5518 if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
5519 if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
5520 if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
5521 if(flags & 0x0008) Loc = parse_HyperlinkString(blob, end - blob.l);
5522 if(flags & 0x0020) guid = blob.read_shift(16);
5523 if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
5524 blob.l = end;
5525 var target = targetFrameName||moniker||oleMoniker||"";
5526 if(target && Loc) target+="#"+Loc;
5527 if(!target) target = "#" + Loc;
5528 var out = ({Target:target});
5529 if(guid) out.guid = guid;
5530 if(fileTime) out.time = fileTime;
5531 if(displayName) out.Tooltip = displayName;
5532 return out;
5533}
5534function write_Hyperlink(hl) {
5535 var out = new_buf(512), i = 0;
5536 var Target = hl.Target;
5537 var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
5538 switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
5539 out.write_shift(4,2); out.write_shift(4, F);
5540 var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
5541 if(F == 0x1C) {
5542 Target = Target.slice(1);
5543 out.write_shift(4, Target.length + 1);
5544 for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
5545 out.write_shift(2, 0);
5546 } else if(F & 0x02) {
5547 data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
5548 for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
5549 out.write_shift(4, 2*(Target.length + 1));
5550 for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
5551 out.write_shift(2, 0);
5552 } else {
5553 data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
5554 for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
5555 var P = 0;
5556 while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
5557 out.write_shift(2, P);
5558 out.write_shift(4, Target.length + 1);
5559 for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
5560 out.write_shift(1, 0);
5561 out.write_shift(2, 0xFFFF);
5562 out.write_shift(2, 0xDEAD);
5563 for(i = 0; i < 6; ++i) out.write_shift(4, 0);
5564 }
5565 return out.slice(0, out.l);
5566}
5567
5568/* 2.5.178 LongRGBA */
5569function 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]; }
5570
5571/* 2.5.177 LongRGB */
5572function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
5573
5574
5575/* [MS-XLS] 2.5.19 */
5576function parse_XLSCell(blob) {
5577 var rw = blob.read_shift(2); // 0-indexed
5578 var col = blob.read_shift(2);
5579 var ixfe = blob.read_shift(2);
5580 return ({r:rw, c:col, ixfe:ixfe});
5581}
5582function write_XLSCell(R, C, ixfe, o) {
5583 if(!o) o = new_buf(6);
5584 o.write_shift(2, R);
5585 o.write_shift(2, C);
5586 o.write_shift(2, ixfe||0);
5587 return o;
5588}
5589
5590/* [MS-XLS] 2.5.134 */
5591function parse_frtHeader(blob) {
5592 var rt = blob.read_shift(2);
5593 var flags = blob.read_shift(2); // TODO: parse these flags
5594 blob.l += 8;
5595 return {type: rt, flags: flags};
5596}
5597
5598
5599
5600function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
5601
5602/* [MS-XLS] 2.5.344 */
5603function parse_XTI(blob, length, opts) {
5604 var w = opts.biff > 8 ? 4 : 2;
5605 var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
5606 return [iSupBook, itabFirst, itabLast];
5607}
5608
5609/* [MS-XLS] 2.5.218 */
5610function parse_RkRec(blob) {
5611 var ixfe = blob.read_shift(2);
5612 var RK = parse_RkNumber(blob);
5613 return [ixfe, RK];
5614}
5615
5616/* [MS-XLS] 2.5.1 */
5617function parse_AddinUdf(blob, length, opts) {
5618 blob.l += 4; length -= 4;
5619 var l = blob.l + length;
5620 var udfName = parse_ShortXLUnicodeString(blob, length, opts);
5621 var cb = blob.read_shift(2);
5622 l -= blob.l;
5623 if(cb !== l) throw new Error("Malformed AddinUdf: padding = " + l + " != " + cb);
5624 blob.l += cb;
5625 return udfName;
5626}
5627
5628/* [MS-XLS] 2.5.209 TODO: Check sizes */
5629function parse_Ref8U(blob) {
5630 var rwFirst = blob.read_shift(2);
5631 var rwLast = blob.read_shift(2);
5632 var colFirst = blob.read_shift(2);
5633 var colLast = blob.read_shift(2);
5634 return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5635}
5636function write_Ref8U(r, o) {
5637 if(!o) o = new_buf(8);
5638 o.write_shift(2, r.s.r);
5639 o.write_shift(2, r.e.r);
5640 o.write_shift(2, r.s.c);
5641 o.write_shift(2, r.e.c);
5642 return o;
5643}
5644
5645/* [MS-XLS] 2.5.211 */
5646function parse_RefU(blob) {
5647 var rwFirst = blob.read_shift(2);
5648 var rwLast = blob.read_shift(2);
5649 var colFirst = blob.read_shift(1);
5650 var colLast = blob.read_shift(1);
5651 return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5652}
5653
5654/* [MS-XLS] 2.5.207 */
5655var parse_Ref = parse_RefU;
5656
5657/* [MS-XLS] 2.5.143 */
5658function parse_FtCmo(blob) {
5659 blob.l += 4;
5660 var ot = blob.read_shift(2);
5661 var id = blob.read_shift(2);
5662 var flags = blob.read_shift(2);
5663 blob.l+=12;
5664 return [id, ot, flags];
5665}
5666
5667/* [MS-XLS] 2.5.149 */
5668function parse_FtNts(blob) {
5669 var out = {};
5670 blob.l += 4;
5671 blob.l += 16; // GUID TODO
5672 out.fSharedNote = blob.read_shift(2);
5673 blob.l += 4;
5674 return out;
5675}
5676
5677/* [MS-XLS] 2.5.142 */
5678function parse_FtCf(blob) {
5679 var out = {};
5680 blob.l += 4;
5681 blob.cf = blob.read_shift(2);
5682 return out;
5683}
5684
5685/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
5686function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
5687var FtTab = {
56880x00: parse_FtSkip, /* FtEnd */
56890x04: parse_FtSkip, /* FtMacro */
56900x05: parse_FtSkip, /* FtButton */
56910x06: parse_FtSkip, /* FtGmo */
56920x07: parse_FtCf, /* FtCf */
56930x08: parse_FtSkip, /* FtPioGrbit */
56940x09: parse_FtSkip, /* FtPictFmla */
56950x0A: parse_FtSkip, /* FtCbls */
56960x0B: parse_FtSkip, /* FtRbo */
56970x0C: parse_FtSkip, /* FtSbs */
56980x0D: parse_FtNts, /* FtNts */
56990x0E: parse_FtSkip, /* FtSbsFmla */
57000x0F: parse_FtSkip, /* FtGboData */
57010x10: parse_FtSkip, /* FtEdoData */
57020x11: parse_FtSkip, /* FtRboData */
57030x12: parse_FtSkip, /* FtCblsData */
57040x13: parse_FtSkip, /* FtLbsData */
57050x14: parse_FtSkip, /* FtCblsFmla */
57060x15: parse_FtCmo
5707};
5708function parse_FtArray(blob, length) {
5709 var tgt = blob.l + length;
5710 var fts = [];
5711 while(blob.l < tgt) {
5712 var ft = blob.read_shift(2);
5713 blob.l-=2;
5714 try {
5715 fts.push(FtTab[ft](blob, tgt - blob.l));
5716 } catch(e) { blob.l = tgt; return fts; }
5717 }
5718 if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
5719 return fts;
5720}
5721
5722/* --- 2.4 Records --- */
5723
5724/* [MS-XLS] 2.4.21 */
5725function parse_BOF(blob, length) {
5726 var o = {BIFFVer:0, dt:0};
5727 o.BIFFVer = blob.read_shift(2); length -= 2;
5728 if(length >= 2) { o.dt = blob.read_shift(2); blob.l -= 2; }
5729 switch(o.BIFFVer) {
5730 case 0x0600: /* BIFF8 */
5731 case 0x0500: /* BIFF5 */
5732 case 0x0400: /* BIFF4 */
5733 case 0x0300: /* BIFF3 */
5734 case 0x0200: /* BIFF2 */
5735 case 0x0002: case 0x0007: /* BIFF2 */
5736 break;
5737 default: if(length > 6) throw new Error("Unexpected BIFF Ver " + o.BIFFVer);
5738 }
5739
5740 blob.read_shift(length);
5741 return o;
5742}
5743function write_BOF(wb, t, o) {
5744 var h = 0x0600, w = 16;
5745 switch(o.bookType) {
5746 case 'biff8': break;
5747 case 'biff5': h = 0x0500; w = 8; break;
5748 case 'biff4': h = 0x0004; w = 6; break;
5749 case 'biff3': h = 0x0003; w = 6; break;
5750 case 'biff2': h = 0x0002; w = 4; break;
5751 case 'xla': break;
5752 default: throw new Error("unsupported BIFF version");
5753 }
5754 var out = new_buf(w);
5755 out.write_shift(2, h);
5756 out.write_shift(2, t);
5757 if(w > 4) out.write_shift(2, 0x7262);
5758 if(w > 6) out.write_shift(2, 0x07CD);
5759 if(w > 8) {
5760 out.write_shift(2, 0xC009);
5761 out.write_shift(2, 0x0001);
5762 out.write_shift(2, 0x0706);
5763 out.write_shift(2, 0x0000);
5764 }
5765 return out;
5766}
5767
5768
5769/* [MS-XLS] 2.4.146 */
5770function parse_InterfaceHdr(blob, length) {
5771 if(length === 0) return 0x04b0;
5772 if((blob.read_shift(2))!==0x04b0){/* empty */}
5773 return 0x04b0;
5774}
5775
5776
5777/* [MS-XLS] 2.4.349 */
5778function parse_WriteAccess(blob, length, opts) {
5779 if(opts.enc) { blob.l += length; return ""; }
5780 var l = blob.l;
5781 // TODO: make sure XLUnicodeString doesnt overrun
5782 var UserName = parse_XLUnicodeString2(blob, 0, opts);
5783 blob.read_shift(length + l - blob.l);
5784 return UserName;
5785}
5786function write_WriteAccess(s, opts) {
5787 var b8 = !opts || opts.biff == 8;
5788 var o = new_buf(b8 ? 112 : 54);
5789 o.write_shift(opts.biff == 8 ? 2 : 1, 7);
5790 if(b8) o.write_shift(1, 0);
5791 o.write_shift(4, 0x33336853);
5792 o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
5793 while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
5794 return o;
5795}
5796
5797/* [MS-XLS] 2.4.351 */
5798function parse_WsBool(blob, length, opts) {
5799 var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
5800 return { fDialog: flags & 0x10 };
5801}
5802
5803/* [MS-XLS] 2.4.28 */
5804function parse_BoundSheet8(blob, length, opts) {
5805 var pos = blob.read_shift(4);
5806 var hidden = blob.read_shift(1) & 0x03;
5807 var dt = blob.read_shift(1);
5808 switch(dt) {
5809 case 0: dt = 'Worksheet'; break;
5810 case 1: dt = 'Macrosheet'; break;
5811 case 2: dt = 'Chartsheet'; break;
5812 case 6: dt = 'VBAModule'; break;
5813 }
5814 var name = parse_ShortXLUnicodeString(blob, 0, opts);
5815 if(name.length === 0) name = "Sheet1";
5816 return { pos:pos, hs:hidden, dt:dt, name:name };
5817}
5818function write_BoundSheet8(data, opts) {
5819 var w = (!opts || opts.biff >= 8 ? 2 : 1);
5820 var o = new_buf(8 + w * data.name.length);
5821 o.write_shift(4, data.pos);
5822 o.write_shift(1, data.hs || 0);
5823 o.write_shift(1, data.dt);
5824 o.write_shift(1, data.name.length);
5825 if(opts.biff >= 8) o.write_shift(1, 1);
5826 o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
5827 var out = o.slice(0, o.l);
5828 out.l = o.l; return out;
5829}
5830
5831/* [MS-XLS] 2.4.265 TODO */
5832function parse_SST(blob, length) {
5833 var end = blob.l + length;
5834 var cnt = blob.read_shift(4);
5835 var ucnt = blob.read_shift(4);
5836 var strs = ([]);
5837 for(var i = 0; i != ucnt && blob.l < end; ++i) {
5838 strs.push(parse_XLUnicodeRichExtendedString(blob));
5839 }
5840 strs.Count = cnt; strs.Unique = ucnt;
5841 return strs;
5842}
5843
5844/* [MS-XLS] 2.4.107 */
5845function parse_ExtSST(blob, length) {
5846 var extsst = {};
5847 extsst.dsst = blob.read_shift(2);
5848 blob.l += length-2;
5849 return extsst;
5850}
5851
5852
5853/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
5854function parse_Row(blob) {
5855 var z = ({});
5856 z.r = blob.read_shift(2);
5857 z.c = blob.read_shift(2);
5858 z.cnt = blob.read_shift(2) - z.c;
5859 var miyRw = blob.read_shift(2);
5860 blob.l += 4; // reserved(2), unused(2)
5861 var flags = blob.read_shift(1); // various flags
5862 blob.l += 3; // reserved(8), ixfe(12), flags(4)
5863 if(flags & 0x07) z.level = flags & 0x07;
5864 // collapsed: flags & 0x10
5865 if(flags & 0x20) z.hidden = true;
5866 if(flags & 0x40) z.hpt = miyRw / 20;
5867 return z;
5868}
5869
5870
5871/* [MS-XLS] 2.4.125 */
5872function parse_ForceFullCalculation(blob) {
5873 var header = parse_frtHeader(blob);
5874 if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
5875 var fullcalc = blob.read_shift(4);
5876 return fullcalc !== 0x0;
5877}
5878
5879
5880
5881
5882
5883/* [MS-XLS] 2.4.215 rt */
5884function parse_RecalcId(blob) {
5885 blob.read_shift(2);
5886 return blob.read_shift(4);
5887}
5888
5889/* [MS-XLS] 2.4.87 */
5890function parse_DefaultRowHeight(blob, length, opts) {
5891 var f = 0;
5892 if(!(opts && opts.biff == 2)) {
5893 f = blob.read_shift(2);
5894 }
5895 var miyRw = blob.read_shift(2);
5896 if((opts && opts.biff == 2)) {
5897 f = 1 - (miyRw >> 15); miyRw &= 0x7fff;
5898 }
5899 var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
5900 return [fl, miyRw];
5901}
5902
5903/* [MS-XLS] 2.4.345 TODO */
5904function parse_Window1(blob) {
5905 var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
5906 var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
5907 var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
5908 return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
5909 FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
5910}
5911function write_Window1() {
5912 var o = new_buf(18);
5913 o.write_shift(2, 0);
5914 o.write_shift(2, 0);
5915 o.write_shift(2, 0x7260);
5916 o.write_shift(2, 0x44c0);
5917 o.write_shift(2, 0x38);
5918 o.write_shift(2, 0);
5919 o.write_shift(2, 0);
5920 o.write_shift(2, 1);
5921 o.write_shift(2, 0x01f4);
5922 return o;
5923}
5924/* [MS-XLS] 2.4.346 TODO */
5925function parse_Window2(blob, length, opts) {
5926 if(opts && opts.biff >= 2 && opts.biff < 8) return {};
5927 var f = blob.read_shift(2);
5928 return { RTL: f & 0x40 };
5929}
5930function write_Window2(view) {
5931 var o = new_buf(18), f = 0x6b6;
5932 if(view && view.RTL) f |= 0x40;
5933 o.write_shift(2, f);
5934 o.write_shift(4, 0);
5935 o.write_shift(4, 64);
5936 o.write_shift(4, 0);
5937 o.write_shift(4, 0);
5938 return o;
5939}
5940
5941/* [MS-XLS] 2.4.122 TODO */
5942function parse_Font(blob, length, opts) {
5943 var o = {
5944 dyHeight: blob.read_shift(2),
5945 fl: blob.read_shift(2)
5946 };
5947 switch((opts && opts.biff) || 8) {
5948 case 2: break;
5949 case 3: case 4: blob.l += 2; break;
5950 default: blob.l += 10; break;
5951 }
5952 o.name = parse_ShortXLUnicodeString(blob, 0, opts);
5953 return o;
5954}
5955function write_Font(data, opts) {
5956 var name = data.name || "Arial";
5957 var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
5958 var o = new_buf(w);
5959 o.write_shift(2, (data.sz || 12) * 20);
5960 o.write_shift(4, 0);
5961 o.write_shift(2, 400);
5962 o.write_shift(4, 0);
5963 o.write_shift(2, 0);
5964 o.write_shift(1, name.length);
5965 if(!b5) o.write_shift(1, 1);
5966 o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
5967 return o;
5968}
5969
5970/* [MS-XLS] 2.4.149 */
5971function parse_LabelSst(blob) {
5972 var cell = parse_XLSCell(blob);
5973 cell.isst = blob.read_shift(4);
5974 return cell;
5975}
5976
5977/* [MS-XLS] 2.4.148 */
5978function parse_Label(blob, length, opts) {
5979 var target = blob.l + length;
5980 var cell = parse_XLSCell(blob, 6);
5981 if(opts.biff == 2) blob.l++;
5982 var str = parse_XLUnicodeString(blob, target - blob.l, opts);
5983 cell.val = str;
5984 return cell;
5985}
5986function write_Label(R, C, v, os, opts) {
5987 var b8 = !opts || opts.biff == 8;
5988 var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
5989 write_XLSCell(R, C, os, o);
5990 o.write_shift(2, v.length);
5991 if(b8) o.write_shift(1, 1);
5992 o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
5993 return o;
5994}
5995
5996
5997/* [MS-XLS] 2.4.126 Number Formats */
5998function parse_Format(blob, length, opts) {
5999 var numFmtId = blob.read_shift(2);
6000 var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
6001 return [numFmtId, fmtstr];
6002}
6003function write_Format(i, f, opts, o) {
6004 var b5 = (opts && (opts.biff == 5));
6005 if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
6006 o.write_shift(2, i);
6007 o.write_shift((b5 ? 1 : 2), f.length);
6008 if(!b5) o.write_shift(1, 1);
6009 o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
6010 var out = (o.length > o.l) ? o.slice(0, o.l) : o;
6011 if(out.l == null) out.l = out.length;
6012 return out;
6013}
6014var parse_BIFF2Format = parse_XLUnicodeString2;
6015
6016/* [MS-XLS] 2.4.90 */
6017function parse_Dimensions(blob, length, opts) {
6018 var end = blob.l + length;
6019 var w = opts.biff == 8 || !opts.biff ? 4 : 2;
6020 var r = blob.read_shift(w), R = blob.read_shift(w);
6021 var c = blob.read_shift(2), C = blob.read_shift(2);
6022 blob.l = end;
6023 return {s: {r:r, c:c}, e: {r:R, c:C}};
6024}
6025function write_Dimensions(range, opts) {
6026 var w = opts.biff == 8 || !opts.biff ? 4 : 2;
6027 var o = new_buf(2*w + 6);
6028 o.write_shift(w, range.s.r);
6029 o.write_shift(w, range.e.r + 1);
6030 o.write_shift(2, range.s.c);
6031 o.write_shift(2, range.e.c + 1);
6032 o.write_shift(2, 0);
6033 return o;
6034}
6035
6036/* [MS-XLS] 2.4.220 */
6037function parse_RK(blob) {
6038 var rw = blob.read_shift(2), col = blob.read_shift(2);
6039 var rkrec = parse_RkRec(blob);
6040 return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
6041}
6042
6043/* [MS-XLS] 2.4.175 */
6044function parse_MulRk(blob, length) {
6045 var target = blob.l + length - 2;
6046 var rw = blob.read_shift(2), col = blob.read_shift(2);
6047 var rkrecs = [];
6048 while(blob.l < target) rkrecs.push(parse_RkRec(blob));
6049 if(blob.l !== target) throw new Error("MulRK read error");
6050 var lastcol = blob.read_shift(2);
6051 if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
6052 return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
6053}
6054/* [MS-XLS] 2.4.174 */
6055function parse_MulBlank(blob, length) {
6056 var target = blob.l + length - 2;
6057 var rw = blob.read_shift(2), col = blob.read_shift(2);
6058 var ixfes = [];
6059 while(blob.l < target) ixfes.push(blob.read_shift(2));
6060 if(blob.l !== target) throw new Error("MulBlank read error");
6061 var lastcol = blob.read_shift(2);
6062 if(ixfes.length != lastcol - col + 1) throw new Error("MulBlank length mismatch");
6063 return {r:rw, c:col, C:lastcol, ixfe:ixfes};
6064}
6065
6066/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
6067function parse_CellStyleXF(blob, length, style, opts) {
6068 var o = {};
6069 var a = blob.read_shift(4), b = blob.read_shift(4);
6070 var c = blob.read_shift(4), d = blob.read_shift(2);
6071 o.patternType = XLSFillPattern[c >> 26];
6072
6073 if(!opts.cellStyles) return o;
6074 o.alc = a & 0x07;
6075 o.fWrap = (a >> 3) & 0x01;
6076 o.alcV = (a >> 4) & 0x07;
6077 o.fJustLast = (a >> 7) & 0x01;
6078 o.trot = (a >> 8) & 0xFF;
6079 o.cIndent = (a >> 16) & 0x0F;
6080 o.fShrinkToFit = (a >> 20) & 0x01;
6081 o.iReadOrder = (a >> 22) & 0x02;
6082 o.fAtrNum = (a >> 26) & 0x01;
6083 o.fAtrFnt = (a >> 27) & 0x01;
6084 o.fAtrAlc = (a >> 28) & 0x01;
6085 o.fAtrBdr = (a >> 29) & 0x01;
6086 o.fAtrPat = (a >> 30) & 0x01;
6087 o.fAtrProt = (a >> 31) & 0x01;
6088
6089 o.dgLeft = b & 0x0F;
6090 o.dgRight = (b >> 4) & 0x0F;
6091 o.dgTop = (b >> 8) & 0x0F;
6092 o.dgBottom = (b >> 12) & 0x0F;
6093 o.icvLeft = (b >> 16) & 0x7F;
6094 o.icvRight = (b >> 23) & 0x7F;
6095 o.grbitDiag = (b >> 30) & 0x03;
6096
6097 o.icvTop = c & 0x7F;
6098 o.icvBottom = (c >> 7) & 0x7F;
6099 o.icvDiag = (c >> 14) & 0x7F;
6100 o.dgDiag = (c >> 21) & 0x0F;
6101
6102 o.icvFore = d & 0x7F;
6103 o.icvBack = (d >> 7) & 0x7F;
6104 o.fsxButton = (d >> 14) & 0x01;
6105 return o;
6106}
6107//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
6108//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
6109
6110/* [MS-XLS] 2.4.353 TODO: actually do this right */
6111function parse_XF(blob, length, opts) {
6112 var o = {};
6113 o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
6114 o.fStyle = (o.flags >> 2) & 0x01;
6115 length -= 6;
6116 o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
6117 return o;
6118}
6119function write_XF(data, ixfeP, opts, o) {
6120 var b5 = (opts && (opts.biff == 5));
6121 if(!o) o = new_buf(b5 ? 16 : 20);
6122 o.write_shift(2, 0);
6123 if(data.style) {
6124 o.write_shift(2, (data.numFmtId||0));
6125 o.write_shift(2, 0xFFF4);
6126 } else {
6127 o.write_shift(2, (data.numFmtId||0));
6128 o.write_shift(2, (ixfeP<<4));
6129 }
6130 o.write_shift(4, 0);
6131 o.write_shift(4, 0);
6132 if(!b5) o.write_shift(4, 0);
6133 o.write_shift(2, 0);
6134 return o;
6135}
6136
6137/* [MS-XLS] 2.4.134 */
6138function parse_Guts(blob) {
6139 blob.l += 4;
6140 var out = [blob.read_shift(2), blob.read_shift(2)];
6141 if(out[0] !== 0) out[0]--;
6142 if(out[1] !== 0) out[1]--;
6143 if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
6144 return out;
6145}
6146function write_Guts(guts) {
6147 var o = new_buf(8);
6148 o.write_shift(4, 0);
6149 o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
6150 o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
6151 return o;
6152}
6153
6154/* [MS-XLS] 2.4.24 */
6155function parse_BoolErr(blob, length, opts) {
6156 var cell = parse_XLSCell(blob, 6);
6157 if(opts.biff == 2) ++blob.l;
6158 var val = parse_Bes(blob, 2);
6159 cell.val = val;
6160 cell.t = (val === true || val === false) ? 'b' : 'e';
6161 return cell;
6162}
6163function write_BoolErr(R, C, v, os, opts, t) {
6164 var o = new_buf(8);
6165 write_XLSCell(R, C, os, o);
6166 write_Bes(v, t, o);
6167 return o;
6168}
6169
6170/* [MS-XLS] 2.4.180 Number */
6171function parse_Number(blob) {
6172 var cell = parse_XLSCell(blob, 6);
6173 var xnum = parse_Xnum(blob, 8);
6174 cell.val = xnum;
6175 return cell;
6176}
6177function write_Number(R, C, v, os) {
6178 var o = new_buf(14);
6179 write_XLSCell(R, C, os, o);
6180 write_Xnum(v, o);
6181 return o;
6182}
6183
6184var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
6185
6186/* [MS-XLS] 2.4.271 */
6187function parse_SupBook(blob, length, opts) {
6188 var end = blob.l + length;
6189 var ctab = blob.read_shift(2);
6190 var cch = blob.read_shift(2);
6191 opts.sbcch = cch;
6192 if(cch == 0x0401 || cch == 0x3A01) return [cch, ctab];
6193 if(cch < 0x01 || cch >0xff) throw new Error("Unexpected SupBook type: "+cch);
6194 var virtPath = parse_XLUnicodeStringNoCch(blob, cch);
6195 /* TODO: 2.5.277 Virtual Path */
6196 var rgst = [];
6197 while(end > blob.l) rgst.push(parse_XLUnicodeString(blob));
6198 return [cch, ctab, virtPath, rgst];
6199}
6200
6201/* [MS-XLS] 2.4.105 TODO */
6202function parse_ExternName(blob, length, opts) {
6203 var flags = blob.read_shift(2);
6204 var body;
6205 var o = ({
6206 fBuiltIn: flags & 0x01,
6207 fWantAdvise: (flags >>> 1) & 0x01,
6208 fWantPict: (flags >>> 2) & 0x01,
6209 fOle: (flags >>> 3) & 0x01,
6210 fOleLink: (flags >>> 4) & 0x01,
6211 cf: (flags >>> 5) & 0x3FF,
6212 fIcon: flags >>> 15 & 0x01
6213 });
6214 if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts);
6215 //else throw new Error("unsupported SupBook cch: " + opts.sbcch);
6216 o.body = body || blob.read_shift(length-2);
6217 if(typeof body === "string") o.Name = body;
6218 return o;
6219}
6220
6221/* [MS-XLS] 2.4.150 TODO */
6222var XLSLblBuiltIn = [
6223 "_xlnm.Consolidate_Area",
6224 "_xlnm.Auto_Open",
6225 "_xlnm.Auto_Close",
6226 "_xlnm.Extract",
6227 "_xlnm.Database",
6228 "_xlnm.Criteria",
6229 "_xlnm.Print_Area",
6230 "_xlnm.Print_Titles",
6231 "_xlnm.Recorder",
6232 "_xlnm.Data_Form",
6233 "_xlnm.Auto_Activate",
6234 "_xlnm.Auto_Deactivate",
6235 "_xlnm.Sheet_Title",
6236 "_xlnm._FilterDatabase"
6237];
6238function parse_Lbl(blob, length, opts) {
6239 var target = blob.l + length;
6240 var flags = blob.read_shift(2);
6241 var chKey = blob.read_shift(1);
6242 var cch = blob.read_shift(1);
6243 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
6244 var itab = 0;
6245 if(!opts || opts.biff >= 5) {
6246 if(opts.biff != 5) blob.l += 2;
6247 itab = blob.read_shift(2);
6248 if(opts.biff == 5) blob.l += 2;
6249 blob.l += 4;
6250 }
6251 var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
6252 if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
6253 var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
6254 var rgce = target == blob.l || cce === 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
6255 return {
6256 chKey: chKey,
6257 Name: name,
6258 itab: itab,
6259 rgce: rgce
6260 };
6261}
6262
6263/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
6264function parse_ExternSheet(blob, length, opts) {
6265 if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
6266 var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
6267 while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
6268 // [iSupBook, itabFirst, itabLast];
6269 if(blob.l != target) throw new Error("Bad ExternSheet: " + blob.l + " != " + target);
6270 return o;
6271}
6272function parse_BIFF5ExternSheet(blob, length, opts) {
6273 if(blob[blob.l + 1] == 0x03) blob[blob.l]++;
6274 var o = parse_ShortXLUnicodeString(blob, length, opts);
6275 return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
6276}
6277
6278/* [MS-XLS] 2.4.176 TODO: check older biff */
6279function parse_NameCmt(blob, length, opts) {
6280 if(opts.biff < 8) { blob.l += length; return; }
6281 var cchName = blob.read_shift(2);
6282 var cchComment = blob.read_shift(2);
6283 var name = parse_XLUnicodeStringNoCch(blob, cchName, opts);
6284 var comment = parse_XLUnicodeStringNoCch(blob, cchComment, opts);
6285 return [name, comment];
6286}
6287
6288/* [MS-XLS] 2.4.260 */
6289function parse_ShrFmla(blob, length, opts) {
6290 var ref = parse_RefU(blob, 6);
6291 blob.l++;
6292 var cUse = blob.read_shift(1);
6293 length -= 8;
6294 return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
6295}
6296
6297/* [MS-XLS] 2.4.4 TODO */
6298function parse_Array(blob, length, opts) {
6299 var ref = parse_Ref(blob, 6);
6300 /* TODO: fAlwaysCalc */
6301 switch(opts.biff) {
6302 case 2: blob.l ++; length -= 7; break;
6303 case 3: case 4: blob.l += 2; length -= 8; break;
6304 default: blob.l += 6; length -= 12;
6305 }
6306 return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
6307}
6308
6309/* [MS-XLS] 2.4.173 */
6310function parse_MTRSettings(blob) {
6311 var fMTREnabled = blob.read_shift(4) !== 0x00;
6312 var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
6313 var cUserThreadCount = blob.read_shift(4);
6314 return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
6315}
6316
6317/* [MS-XLS] 2.5.186 TODO: BIFF5 */
6318function parse_NoteSh(blob, length, opts) {
6319 if(opts.biff < 8) return;
6320 var row = blob.read_shift(2), col = blob.read_shift(2);
6321 var flags = blob.read_shift(2), idObj = blob.read_shift(2);
6322 var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
6323 if(opts.biff < 8) blob.read_shift(1);
6324 return [{r:row,c:col}, stAuthor, idObj, flags];
6325}
6326
6327/* [MS-XLS] 2.4.179 */
6328function parse_Note(blob, length, opts) {
6329 /* TODO: Support revisions */
6330 return parse_NoteSh(blob, length, opts);
6331}
6332
6333/* [MS-XLS] 2.4.168 */
6334function parse_MergeCells(blob, length) {
6335 var merges = [];
6336 var cmcs = blob.read_shift(2);
6337 while (cmcs--) merges.push(parse_Ref8U(blob,length));
6338 return merges;
6339}
6340function write_MergeCells(merges) {
6341 var o = new_buf(2 + merges.length * 8);
6342 o.write_shift(2, merges.length);
6343 for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o);
6344 return o;
6345}
6346
6347/* [MS-XLS] 2.4.181 TODO: parse all the things! */
6348function parse_Obj(blob, length, opts) {
6349 if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
6350 var cmo = parse_FtCmo(blob, 22); // id, ot, flags
6351 var fts = parse_FtArray(blob, length-22, cmo[1]);
6352 return { cmo: cmo, ft:fts };
6353}
6354/* from older spec */
6355var parse_BIFF5OT = [];
6356parse_BIFF5OT[0x08] = function(blob, length) {
6357 var tgt = blob.l + length;
6358 blob.l += 10; // todo
6359 var cf = blob.read_shift(2);
6360 blob.l += 4;
6361 blob.l += 2; //var cbPictFmla = blob.read_shift(2);
6362 blob.l += 2;
6363 blob.l += 2; //var grbit = blob.read_shift(2);
6364 blob.l += 4;
6365 var cchName = blob.read_shift(1);
6366 blob.l += cchName; // TODO: stName
6367 blob.l = tgt; // TODO: fmla
6368 return { fmt:cf };
6369};
6370
6371function parse_BIFF5Obj(blob, length, opts) {
6372 blob.l += 4; //var cnt = blob.read_shift(4);
6373 var ot = blob.read_shift(2);
6374 var id = blob.read_shift(2);
6375 var grbit = blob.read_shift(2);
6376 blob.l += 2; //var colL = blob.read_shift(2);
6377 blob.l += 2; //var dxL = blob.read_shift(2);
6378 blob.l += 2; //var rwT = blob.read_shift(2);
6379 blob.l += 2; //var dyT = blob.read_shift(2);
6380 blob.l += 2; //var colR = blob.read_shift(2);
6381 blob.l += 2; //var dxR = blob.read_shift(2);
6382 blob.l += 2; //var rwB = blob.read_shift(2);
6383 blob.l += 2; //var dyB = blob.read_shift(2);
6384 blob.l += 2; //var cbMacro = blob.read_shift(2);
6385 blob.l += 6;
6386 length -= 36;
6387 var fts = [];
6388 fts.push((parse_BIFF5OT[ot]||parsenoop)(blob, length, opts));
6389 return { cmo: [id, ot, grbit], ft:fts };
6390}
6391
6392/* [MS-XLS] 2.4.329 TODO: parse properly */
6393function parse_TxO(blob, length, opts) {
6394 var s = blob.l;
6395 var texts = "";
6396try {
6397 blob.l += 4;
6398 var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
6399 var controlInfo; // eslint-disable-line no-unused-vars
6400 if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
6401 else controlInfo = parse_ControlInfo(blob, 6, opts);
6402 var cchText = blob.read_shift(2);
6403 /*var cbRuns = */blob.read_shift(2);
6404 /*var ifntEmpty = */parseuint16(blob, 2);
6405 var len = blob.read_shift(2);
6406 blob.l += len;
6407 //var fmla = parse_ObjFmla(blob, s + length - blob.l);
6408
6409 for(var i = 1; i < blob.lens.length-1; ++i) {
6410 if(blob.l-s != blob.lens[i]) throw new Error("TxO: bad continue record");
6411 var hdr = blob[blob.l];
6412 var t = parse_XLUnicodeStringNoCch(blob, blob.lens[i+1]-blob.lens[i]-1);
6413 texts += t;
6414 if(texts.length >= (hdr ? cchText : 2*cchText)) break;
6415 }
6416 if(texts.length !== cchText && texts.length !== cchText*2) {
6417 throw new Error("cchText: " + cchText + " != " + texts.length);
6418 }
6419
6420 blob.l = s + length;
6421 /* [MS-XLS] 2.5.272 TxORuns */
6422// var rgTxoRuns = [];
6423// for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
6424// var cchText2 = blob.read_shift(2);
6425// if(cchText2 !== cchText) throw new Error("TxOLastRun mismatch: " + cchText2 + " " + cchText);
6426// blob.l += 6;
6427// if(s + length != blob.l) throw new Error("TxO " + (s + length) + ", at " + blob.l);
6428 return { t: texts };
6429} catch(e) { blob.l = s + length; return { t: texts }; }
6430}
6431
6432/* [MS-XLS] 2.4.140 */
6433function parse_HLink(blob, length) {
6434 var ref = parse_Ref8U(blob, 8);
6435 blob.l += 16; /* CLSID */
6436 var hlink = parse_Hyperlink(blob, length-24);
6437 return [ref, hlink];
6438}
6439function write_HLink(hl) {
6440 var O = new_buf(24);
6441 var ref = decode_cell(hl[0]);
6442 O.write_shift(2, ref.r); O.write_shift(2, ref.r);
6443 O.write_shift(2, ref.c); O.write_shift(2, ref.c);
6444 var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
6445 for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
6446 return bconcat([O, write_Hyperlink(hl[1])]);
6447}
6448
6449
6450/* [MS-XLS] 2.4.141 */
6451function parse_HLinkTooltip(blob, length) {
6452 blob.read_shift(2);
6453 var ref = parse_Ref8U(blob, 8);
6454 var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
6455 wzTooltip = wzTooltip.replace(chr0,"");
6456 return [ref, wzTooltip];
6457}
6458function write_HLinkTooltip(hl) {
6459 var TT = hl[1].Tooltip;
6460 var O = new_buf(10 + 2 * (TT.length + 1));
6461 O.write_shift(2, 0x0800);
6462 var ref = decode_cell(hl[0]);
6463 O.write_shift(2, ref.r); O.write_shift(2, ref.r);
6464 O.write_shift(2, ref.c); O.write_shift(2, ref.c);
6465 for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
6466 O.write_shift(2, 0);
6467 return O;
6468}
6469
6470/* [MS-XLS] 2.4.63 */
6471function parse_Country(blob) {
6472 var o = [0,0], d;
6473 d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
6474 d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
6475 return o;
6476}
6477function write_Country(o) {
6478 if(!o) o = new_buf(4);
6479 o.write_shift(2, 0x01);
6480 o.write_shift(2, 0x01);
6481 return o;
6482}
6483
6484/* [MS-XLS] 2.4.50 ClrtClient */
6485function parse_ClrtClient(blob) {
6486 var ccv = blob.read_shift(2);
6487 var o = [];
6488 while(ccv-->0) o.push(parse_LongRGB(blob, 8));
6489 return o;
6490}
6491
6492/* [MS-XLS] 2.4.188 */
6493function parse_Palette(blob) {
6494 var ccv = blob.read_shift(2);
6495 var o = [];
6496 while(ccv-->0) o.push(parse_LongRGB(blob, 8));
6497 return o;
6498}
6499
6500/* [MS-XLS] 2.4.354 */
6501function parse_XFCRC(blob) {
6502 blob.l += 2;
6503 var o = {cxfs:0, crc:0};
6504 o.cxfs = blob.read_shift(2);
6505 o.crc = blob.read_shift(4);
6506 return o;
6507}
6508
6509/* [MS-XLS] 2.4.53 TODO: parse flags */
6510/* [MS-XLSB] 2.4.323 TODO: parse flags */
6511function parse_ColInfo(blob, length, opts) {
6512 if(!opts.cellStyles) return parsenoop(blob, length);
6513 var w = opts && opts.biff >= 12 ? 4 : 2;
6514 var colFirst = blob.read_shift(w);
6515 var colLast = blob.read_shift(w);
6516 var coldx = blob.read_shift(w);
6517 var ixfe = blob.read_shift(w);
6518 var flags = blob.read_shift(2);
6519 if(w == 2) blob.l += 2;
6520 return {s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags};
6521}
6522
6523/* [MS-XLS] 2.4.257 */
6524function parse_Setup(blob, length) {
6525 var o = {};
6526 if(length < 32) return o;
6527 blob.l += 16;
6528 o.header = parse_Xnum(blob, 8);
6529 o.footer = parse_Xnum(blob, 8);
6530 blob.l += 2;
6531 return o;
6532}
6533
6534/* [MS-XLS] 2.4.261 */
6535function parse_ShtProps(blob, length, opts) {
6536 var def = {area:false};
6537 if(opts.biff != 5) { blob.l += length; return def; }
6538 var d = blob.read_shift(1); blob.l += 3;
6539 if((d & 0x10)) def.area = true;
6540 return def;
6541}
6542
6543/* [MS-XLS] 2.4.241 */
6544function write_RRTabId(n) {
6545 var out = new_buf(2 * n);
6546 for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
6547 return out;
6548}
6549
6550var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
6551var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
6552var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
6553
6554/* --- Specific to versions before BIFF8 --- */
6555function parse_ImData(blob) {
6556 var cf = blob.read_shift(2);
6557 var env = blob.read_shift(2);
6558 var lcb = blob.read_shift(4);
6559 var o = {fmt:cf, env:env, len:lcb, data:blob.slice(blob.l,blob.l+lcb)};
6560 blob.l += lcb;
6561 return o;
6562}
6563
6564/* BIFF2_??? where ??? is the name from [XLS] */
6565function parse_BIFF2STR(blob, length, opts) {
6566 var cell = parse_XLSCell(blob, 6);
6567 ++blob.l;
6568 var str = parse_XLUnicodeString2(blob, length-7, opts);
6569 cell.t = 'str';
6570 cell.val = str;
6571 return cell;
6572}
6573
6574function parse_BIFF2NUM(blob) {
6575 var cell = parse_XLSCell(blob, 6);
6576 ++blob.l;
6577 var num = parse_Xnum(blob, 8);
6578 cell.t = 'n';
6579 cell.val = num;
6580 return cell;
6581}
6582function write_BIFF2NUM(r, c, val) {
6583 var out = new_buf(15);
6584 write_BIFF2Cell(out, r, c);
6585 out.write_shift(8, val, 'f');
6586 return out;
6587}
6588
6589function parse_BIFF2INT(blob) {
6590 var cell = parse_XLSCell(blob, 6);
6591 ++blob.l;
6592 var num = blob.read_shift(2);
6593 cell.t = 'n';
6594 cell.val = num;
6595 return cell;
6596}
6597function write_BIFF2INT(r, c, val) {
6598 var out = new_buf(9);
6599 write_BIFF2Cell(out, r, c);
6600 out.write_shift(2, val);
6601 return out;
6602}
6603
6604function parse_BIFF2STRING(blob) {
6605 var cch = blob.read_shift(1);
6606 if(cch === 0) { blob.l++; return ""; }
6607 return blob.read_shift(cch, 'sbcs-cont');
6608}
6609
6610/* TODO: convert to BIFF8 font struct */
6611function parse_BIFF2FONTXTRA(blob, length) {
6612 blob.l += 6; // unknown
6613 blob.l += 2; // font weight "bls"
6614 blob.l += 1; // charset
6615 blob.l += 3; // unknown
6616 blob.l += 1; // font family
6617 blob.l += length - 13;
6618}
6619
6620/* TODO: parse rich text runs */
6621function parse_RString(blob, length, opts) {
6622 var end = blob.l + length;
6623 var cell = parse_XLSCell(blob, 6);
6624 var cch = blob.read_shift(2);
6625 var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
6626 blob.l = end;
6627 cell.t = 'str';
6628 cell.val = str;
6629 return cell;
6630}
6631/* from js-harb (C) 2014-present SheetJS */
6632var DBF = (function() {
6633var dbf_codepage_map = {
6634 /* Code Pages Supported by Visual FoxPro */
66350x01: 437, 0x02: 850,
66360x03: 1252, 0x04: 10000,
66370x64: 852, 0x65: 866,
66380x66: 865, 0x67: 861,
66390x68: 895, 0x69: 620,
66400x6A: 737, 0x6B: 857,
66410x78: 950, 0x79: 949,
66420x7A: 936, 0x7B: 932,
66430x7C: 874, 0x7D: 1255,
66440x7E: 1256, 0x96: 10007,
66450x97: 10029, 0x98: 10006,
66460xC8: 1250, 0xC9: 1251,
66470xCA: 1254, 0xCB: 1253,
6648
6649 /* shapefile DBF extension */
66500x00: 20127, 0x08: 865,
66510x09: 437, 0x0A: 850,
66520x0B: 437, 0x0D: 437,
66530x0E: 850, 0x0F: 437,
66540x10: 850, 0x11: 437,
66550x12: 850, 0x13: 932,
66560x14: 850, 0x15: 437,
66570x16: 850, 0x17: 865,
66580x18: 437, 0x19: 437,
66590x1A: 850, 0x1B: 437,
66600x1C: 863, 0x1D: 850,
66610x1F: 852, 0x22: 852,
66620x23: 852, 0x24: 860,
66630x25: 850, 0x26: 866,
66640x37: 850, 0x40: 852,
66650x4D: 936, 0x4E: 949,
66660x4F: 950, 0x50: 874,
66670x57: 1252, 0x58: 1252,
66680x59: 1252,
6669
66700xFF: 16969
6671};
6672var dbf_reverse_map = evert({
66730x01: 437, 0x02: 850,
66740x03: 1252, 0x04: 10000,
66750x64: 852, 0x65: 866,
66760x66: 865, 0x67: 861,
66770x68: 895, 0x69: 620,
66780x6A: 737, 0x6B: 857,
66790x78: 950, 0x79: 949,
66800x7A: 936, 0x7B: 932,
66810x7C: 874, 0x7D: 1255,
66820x7E: 1256, 0x96: 10007,
66830x97: 10029, 0x98: 10006,
66840xC8: 1250, 0xC9: 1251,
66850xCA: 1254, 0xCB: 1253,
66860x00: 20127
6687});
6688/* TODO: find an actual specification */
6689function dbf_to_aoa(buf, opts) {
6690 var out = [];
6691 /* TODO: browser based */
6692 var d = (new_raw_buf(1));
6693 switch(opts.type) {
6694 case 'base64': d = s2a(Base64.decode(buf)); break;
6695 case 'binary': d = s2a(buf); break;
6696 case 'buffer':
6697 case 'array': d = buf; break;
6698 }
6699 prep_blob(d, 0);
6700 /* header */
6701 var ft = d.read_shift(1);
6702 var memo = false;
6703 var vfp = false, l7 = false;
6704 switch(ft) {
6705 case 0x02: case 0x03: break;
6706 case 0x30: vfp = true; memo = true; break;
6707 case 0x31: vfp = true; break;
6708 case 0x83: memo = true; break;
6709 case 0x8B: memo = true; break;
6710 case 0x8C: memo = true; l7 = true; break;
6711 case 0xF5: memo = true; break;
6712 default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
6713 }
6714 var /*filedate = new Date(),*/ nrow = 0, fpos = 0;
6715 if(ft == 0x02) nrow = d.read_shift(2);
6716 /*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3;
6717 if(ft != 0x02) nrow = d.read_shift(4);
6718 if(ft != 0x02) fpos = d.read_shift(2);
6719 var rlen = d.read_shift(2);
6720
6721 var /*flags = 0,*/ current_cp = 1252;
6722 if(ft != 0x02) {
6723 d.l+=16;
6724 /*flags = */d.read_shift(1);
6725 //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
6726
6727 /* codepage present in FoxPro */
6728 if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
6729 d.l+=1;
6730
6731 d.l+=2;
6732 }
6733 if(l7) d.l += 36;
6734var fields = [], field = ({});
6735 var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
6736 while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
6737 field = ({});
6738 field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
6739 d.l += ww;
6740 field.type = String.fromCharCode(d.read_shift(1));
6741 if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
6742 field.len = d.read_shift(1);
6743 if(ft == 0x02) field.offset = d.read_shift(2);
6744 field.dec = d.read_shift(1);
6745 if(field.name.length) fields.push(field);
6746 if(ft != 0x02) d.l += l7 ? 13 : 14;
6747 switch(field.type) {
6748 case 'B': // VFP Double
6749 if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6750 break;
6751 case 'G': // General
6752 case 'P': // Picture
6753 if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6754 break;
6755 case 'C': // character
6756 case 'D': // date
6757 case 'F': // floating point
6758 case 'I': // long
6759 case 'L': // boolean
6760 case 'M': // memo
6761 case 'N': // number
6762 case 'O': // double
6763 case 'T': // datetime
6764 case 'Y': // currency
6765 case '0': // VFP _NullFlags
6766 case '@': // timestamp
6767 case '+': // autoincrement
6768 break;
6769 default: throw new Error('Unknown Field Type: ' + field.type);
6770 }
6771 }
6772 if(d[d.l] !== 0x0D) d.l = fpos-1;
6773 else if(ft == 0x02) d.l = 0x209;
6774 if(ft != 0x02) {
6775 if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
6776 d.l = fpos;
6777 }
6778 /* data */
6779 var R = 0, C = 0;
6780 out[0] = [];
6781 for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
6782 while(nrow-- > 0) {
6783 if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
6784 ++d.l;
6785 out[++R] = []; C = 0;
6786 for(C = 0; C != fields.length; ++C) {
6787 var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
6788 prep_blob(dd, 0);
6789 var s = cptable.utils.decode(current_cp, dd);
6790 switch(fields[C].type) {
6791 case 'C':
6792 out[R][C] = cptable.utils.decode(current_cp, dd);
6793 out[R][C] = out[R][C].trim();
6794 break;
6795 case 'D':
6796 if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
6797 else out[R][C] = s;
6798 break;
6799 case 'F': out[R][C] = parseFloat(s.trim()); break;
6800 case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
6801 case 'L': switch(s.toUpperCase()) {
6802 case 'Y': case 'T': out[R][C] = true; break;
6803 case 'N': case 'F': out[R][C] = false; break;
6804 case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
6805 default: throw new Error("DBF Unrecognized L:|" + s + "|");
6806 } break;
6807 case 'M': /* TODO: handle memo files */
6808 if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
6809 out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
6810 break;
6811 case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
6812 case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
6813 case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
6814 case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
6815 case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
6816 case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
6817 /* falls through */
6818 case 'G': case 'P': dd.l += fields[C].len; break;
6819 case '0':
6820 if(fields[C].name === '_NullFlags') break;
6821 /* falls through */
6822 default: throw new Error("DBF Unsupported data type " + fields[C].type);
6823 }
6824 }
6825 }
6826 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));
6827 if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
6828 return out;
6829}
6830
6831function dbf_to_sheet(buf, opts) {
6832 var o = opts || {};
6833 if(!o.dateNF) o.dateNF = "yyyymmdd";
6834 return aoa_to_sheet(dbf_to_aoa(buf, o), o);
6835}
6836
6837function dbf_to_workbook(buf, opts) {
6838 try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
6839 catch(e) { if(opts && opts.WTF) throw e; }
6840 return ({SheetNames:[],Sheets:{}});
6841}
6842
6843var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
6844function sheet_to_dbf(ws, opts) {
6845 var o = opts || {};
6846 if(+o.codepage >= 0) set_cp(+o.codepage);
6847 if(o.type == "string") throw new Error("Cannot write DBF to JS string");
6848 var ba = buf_array();
6849 var aoa = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
6850 var headers = aoa[0], data = aoa.slice(1);
6851 var i = 0, j = 0, hcnt = 0, rlen = 1;
6852 for(i = 0; i < headers.length; ++i) {
6853 if(i == null) continue;
6854 ++hcnt;
6855 if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
6856 if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
6857 if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
6858 if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
6859 }
6860 var range = safe_decode_range(ws['!ref']);
6861 var coltypes = [];
6862 for(i = 0; i <= range.e.c - range.s.c; ++i) {
6863 var col = [];
6864 for(j=0; j < data.length; ++j) {
6865 if(data[j][i] != null) col.push(data[j][i]);
6866 }
6867 if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
6868 var guess = '', _guess = '';
6869 for(j = 0; j < col.length; ++j) {
6870 switch(typeof col[j]) {
6871 /* TODO: check if L2 compat is desired */
6872 case 'number': _guess = 'B'; break;
6873 case 'string': _guess = 'C'; break;
6874 case 'boolean': _guess = 'L'; break;
6875 case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
6876 default: _guess = 'C';
6877 }
6878 guess = guess && guess != _guess ? 'C' : _guess;
6879 if(guess == 'C') break;
6880 }
6881 rlen += _RLEN[guess] || 0;
6882 coltypes[i] = guess;
6883 }
6884
6885 var h = ba.next(32);
6886 h.write_shift(4, 0x13021130);
6887 h.write_shift(4, data.length);
6888 h.write_shift(2, 296 + 32 * hcnt);
6889 h.write_shift(2, rlen);
6890 for(i=0; i < 4; ++i) h.write_shift(4, 0);
6891 h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[current_ansi] || 0x03)<<8));
6892
6893 for(i = 0, j = 0; i < headers.length; ++i) {
6894 if(headers[i] == null) continue;
6895 var hf = ba.next(32);
6896 var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
6897 hf.write_shift(1, _f, "sbcs");
6898 hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
6899 hf.write_shift(4, j);
6900 hf.write_shift(1, _RLEN[coltypes[i]] || 0);
6901 hf.write_shift(1, 0);
6902 hf.write_shift(1, 0x02);
6903 hf.write_shift(4, 0);
6904 hf.write_shift(1, 0);
6905 hf.write_shift(4, 0);
6906 hf.write_shift(4, 0);
6907 j += _RLEN[coltypes[i]] || 0;
6908 }
6909
6910 var hb = ba.next(264);
6911 hb.write_shift(4, 0x0000000D);
6912 for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
6913 for(i=0; i < data.length; ++i) {
6914 var rout = ba.next(rlen);
6915 rout.write_shift(1, 0);
6916 for(j=0; j<headers.length; ++j) {
6917 if(headers[j] == null) continue;
6918 switch(coltypes[j]) {
6919 case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
6920 case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
6921 case 'D':
6922 if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
6923 else {
6924 rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
6925 rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
6926 rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
6927 } break;
6928 case 'C':
6929 var _s = String(data[i][j]||"");
6930 rout.write_shift(1, _s, "sbcs");
6931 for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
6932 }
6933 }
6934 // data
6935 }
6936 ba.next(1).write_shift(1, 0x1A);
6937 return ba.end();
6938}
6939 return {
6940 to_workbook: dbf_to_workbook,
6941 to_sheet: dbf_to_sheet,
6942 from_sheet: sheet_to_dbf
6943 };
6944})();
6945
6946var SYLK = (function() {
6947 /* TODO: stress test sequences */
6948 var sylk_escapes = {
6949 AA:'À', BA:'Á', CA:'Â', DA:195, HA:'Ä', JA:197,
6950 AE:'È', BE:'É', CE:'Ê', HE:'Ë',
6951 AI:'Ì', BI:'Í', CI:'Î', HI:'Ï',
6952 AO:'Ò', BO:'Ó', CO:'Ô', DO:213, HO:'Ö',
6953 AU:'Ù', BU:'Ú', CU:'Û', HU:'Ü',
6954 Aa:'à', Ba:'á', Ca:'â', Da:227, Ha:'ä', Ja:229,
6955 Ae:'è', Be:'é', Ce:'ê', He:'ë',
6956 Ai:'ì', Bi:'í', Ci:'î', Hi:'ï',
6957 Ao:'ò', Bo:'ó', Co:'ô', Do:245, Ho:'ö',
6958 Au:'ù', Bu:'ú', Cu:'û', Hu:'ü',
6959 KC:'Ç', Kc:'ç', q:'æ', z:'œ', a:'Æ', j:'Œ',
6960 DN:209, Dn:241, Hy:255,
6961 S:169, c:170, R:174, 0:176, 1:177, 2:178, 3:179, B:180, 5:181,
6962 6:182, 7:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
6963 "!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
6964 "+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
6965 };
6966 var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
6967 sylk_escapes["|"] = 254;
6968 /* TODO: find an actual specification */
6969 function sylk_to_aoa(d, opts) {
6970 switch(opts.type) {
6971 case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
6972 case 'binary': return sylk_to_aoa_str(d, opts);
6973 case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts);
6974 case 'array': return sylk_to_aoa_str(cc2str(d), opts);
6975 }
6976 throw new Error("Unrecognized type " + opts.type);
6977 }
6978 function sylk_to_aoa_str(str, opts) {
6979 var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
6980 var formats = [];
6981 var next_cell_format = null;
6982 var sht = {}, rowinfo = [], colinfo = [], cw = [];
6983 var Mval = 0, j;
6984 if(+opts.codepage >= 0) set_cp(+opts.codepage);
6985 for (; ri !== records.length; ++ri) {
6986 Mval = 0;
6987 var rstr=records[ri].trim().replace(/\x1B([\x20-\x2F])([\x30-\x3F])/g, function($$, $1, $2) {
6988 var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30);
6989 return newcc == 59 ? $$ : _getansi(newcc);
6990 }).replace(sylk_char_regex, function(_, $1){
6991 var o = sylk_escapes[$1];
6992 return typeof o == "number" ? _getansi(o) : o;
6993 });
6994 var record=rstr.replace(/;;/g, "\u0000").split(";").map(function(x) { return x.replace(/\u0000/g, ";"); });
6995 var RT=record[0], val;
6996 if(rstr.length > 0) switch(RT) {
6997 case 'ID': break; /* header */
6998 case 'E': break; /* EOF */
6999 case 'B': break; /* dimensions */
7000 case 'O': break; /* options? */
7001 case 'P':
7002 if(record[1].charAt(0) == 'P')
7003 formats.push(rstr.slice(3).replace(/;;/g, ";"));
7004 break;
7005 case 'C':
7006 var C_seen_K = false, C_seen_X = false;
7007 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
7008 case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
7009 case 'Y':
7010 R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
7011 for(j = arr.length; j <= R; ++j) arr[j] = [];
7012 break;
7013 case 'K':
7014 val = record[rj].slice(1);
7015 if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
7016 else if(val === 'TRUE') val = true;
7017 else if(val === 'FALSE') val = false;
7018 else if(!isNaN(fuzzynum(val))) {
7019 val = fuzzynum(val);
7020 if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
7021 } else if(!isNaN(fuzzydate(val).getDate())) {
7022 val = parseDate(val);
7023 }
7024 if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
7025 C_seen_K = true;
7026 break;
7027 case 'E':
7028 var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
7029 arr[R][C] = [arr[R][C], formula];
7030 break;
7031 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7032 }
7033 if(C_seen_K) { arr[R][C] = val; next_cell_format = null; }
7034 break;
7035 case 'F':
7036 var F_seen = 0;
7037 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
7038 case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
7039 case 'Y':
7040 R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
7041 for(j = arr.length; j <= R; ++j) arr[j] = [];
7042 break;
7043 case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
7044 case 'F': break; /* ??? */
7045 case 'G': break; /* hide grid */
7046 case 'P':
7047 next_cell_format = formats[parseInt(record[rj].slice(1))];
7048 break;
7049 case 'S': break; /* cell style */
7050 case 'D': break; /* column */
7051 case 'N': break; /* font */
7052 case 'W':
7053 cw = record[rj].slice(1).split(" ");
7054 for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
7055 Mval = parseInt(cw[2], 10);
7056 colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
7057 } break;
7058 case 'C': /* default column format */
7059 C = parseInt(record[rj].slice(1))-1;
7060 if(!colinfo[C]) colinfo[C] = {};
7061 break;
7062 case 'R': /* row properties */
7063 R = parseInt(record[rj].slice(1))-1;
7064 if(!rowinfo[R]) rowinfo[R] = {};
7065 if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
7066 else if(Mval === 0) rowinfo[R].hidden = true;
7067 break;
7068 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7069 }
7070 if(F_seen < 1) next_cell_format = null; break;
7071 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7072 }
7073 }
7074 if(rowinfo.length > 0) sht['!rows'] = rowinfo;
7075 if(colinfo.length > 0) sht['!cols'] = colinfo;
7076 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7077 return [arr, sht];
7078 }
7079
7080 function sylk_to_sheet(d, opts) {
7081 var aoasht = sylk_to_aoa(d, opts);
7082 var aoa = aoasht[0], ws = aoasht[1];
7083 var o = aoa_to_sheet(aoa, opts);
7084 keys(ws).forEach(function(k) { o[k] = ws[k]; });
7085 return o;
7086 }
7087
7088 function sylk_to_workbook(d, opts) { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
7089
7090 function write_ws_cell_sylk(cell, ws, R, C) {
7091 var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
7092 switch(cell.t) {
7093 case 'n':
7094 o += (cell.v||0);
7095 if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
7096 case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
7097 case 'e': o += cell.w || cell.v; break;
7098 case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
7099 case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
7100 }
7101 return o;
7102 }
7103
7104 function write_ws_cols_sylk(out, cols) {
7105 cols.forEach(function(col, i) {
7106 var rec = "F;W" + (i+1) + " " + (i+1) + " ";
7107 if(col.hidden) rec += "0";
7108 else {
7109 if(typeof col.width == 'number') col.wpx = width2px(col.width);
7110 if(typeof col.wpx == 'number') col.wch = px2char(col.wpx);
7111 if(typeof col.wch == 'number') rec += Math.round(col.wch);
7112 }
7113 if(rec.charAt(rec.length - 1) != " ") out.push(rec);
7114 });
7115 }
7116
7117 function write_ws_rows_sylk(out, rows) {
7118 rows.forEach(function(row, i) {
7119 var rec = "F;";
7120 if(row.hidden) rec += "M0;";
7121 else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
7122 else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
7123 if(rec.length > 2) out.push(rec + "R" + (i+1));
7124 });
7125 }
7126
7127 function sheet_to_sylk(ws, opts) {
7128 var preamble = ["ID;PWXL;N;E"], o = [];
7129 var r = safe_decode_range(ws['!ref']), cell;
7130 var dense = Array.isArray(ws);
7131 var RS = "\r\n";
7132
7133 preamble.push("P;PGeneral");
7134 preamble.push("F;P0;DG0G8;M255");
7135 if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
7136 if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
7137
7138 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(" "));
7139 for(var R = r.s.r; R <= r.e.r; ++R) {
7140 for(var C = r.s.c; C <= r.e.c; ++C) {
7141 var coord = encode_cell({r:R,c:C});
7142 cell = dense ? (ws[R]||[])[C]: ws[coord];
7143 if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
7144 o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
7145 }
7146 }
7147 return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
7148 }
7149
7150 return {
7151 to_workbook: sylk_to_workbook,
7152 to_sheet: sylk_to_sheet,
7153 from_sheet: sheet_to_sylk
7154 };
7155})();
7156
7157var DIF = (function() {
7158 function dif_to_aoa(d, opts) {
7159 switch(opts.type) {
7160 case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
7161 case 'binary': return dif_to_aoa_str(d, opts);
7162 case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts);
7163 case 'array': return dif_to_aoa_str(cc2str(d), opts);
7164 }
7165 throw new Error("Unrecognized type " + opts.type);
7166 }
7167 function dif_to_aoa_str(str, opts) {
7168 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
7169 for (; ri !== records.length; ++ri) {
7170 if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
7171 if (R < 0) continue;
7172 var metadata = records[ri].trim().split(",");
7173 var type = metadata[0], value = metadata[1];
7174 ++ri;
7175 var data = records[ri].trim();
7176 switch (+type) {
7177 case -1:
7178 if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
7179 else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
7180 break;
7181 case 0:
7182 if(data === 'TRUE') arr[R][C] = true;
7183 else if(data === 'FALSE') arr[R][C] = false;
7184 else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
7185 else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
7186 else arr[R][C] = value;
7187 ++C; break;
7188 case 1:
7189 data = data.slice(1,data.length-1);
7190 arr[R][C++] = data !== '' ? data : null;
7191 break;
7192 }
7193 if (data === 'EOD') break;
7194 }
7195 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7196 return arr;
7197 }
7198
7199 function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
7200 function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
7201
7202 var sheet_to_dif = (function() {
7203 var push_field = function pf(o, topic, v, n, s) {
7204 o.push(topic);
7205 o.push(v + "," + n);
7206 o.push('"' + s.replace(/"/g,'""') + '"');
7207 };
7208 var push_value = function po(o, type, v, s) {
7209 o.push(type + "," + v);
7210 o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
7211 };
7212 return function sheet_to_dif(ws) {
7213 var o = [];
7214 var r = safe_decode_range(ws['!ref']), cell;
7215 var dense = Array.isArray(ws);
7216 push_field(o, "TABLE", 0, 1, "sheetjs");
7217 push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
7218 push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
7219 push_field(o, "DATA", 0, 0,"");
7220 for(var R = r.s.r; R <= r.e.r; ++R) {
7221 push_value(o, -1, 0, "BOT");
7222 for(var C = r.s.c; C <= r.e.c; ++C) {
7223 var coord = encode_cell({r:R,c:C});
7224 cell = dense ? (ws[R]||[])[C] : ws[coord];
7225 if(!cell) { push_value(o, 1, 0, ""); continue;}
7226 switch(cell.t) {
7227 case 'n':
7228 var val = DIF_XL ? cell.w : cell.v;
7229 if(!val && cell.v != null) val = cell.v;
7230 if(val == null) {
7231 if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
7232 else push_value(o, 1, 0, "");
7233 }
7234 else push_value(o, 0, val, "V");
7235 break;
7236 case 'b':
7237 push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
7238 break;
7239 case 's':
7240 push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
7241 break;
7242 case 'd':
7243 if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
7244 if(DIF_XL) push_value(o, 0, cell.w, "V");
7245 else push_value(o, 1, 0, cell.w);
7246 break;
7247 default: push_value(o, 1, 0, "");
7248 }
7249 }
7250 }
7251 push_value(o, -1, 0, "EOD");
7252 var RS = "\r\n";
7253 var oo = o.join(RS);
7254 //while((oo.length & 0x7F) != 0) oo += "\0";
7255 return oo;
7256 };
7257 })();
7258 return {
7259 to_workbook: dif_to_workbook,
7260 to_sheet: dif_to_sheet,
7261 from_sheet: sheet_to_dif
7262 };
7263})();
7264
7265var ETH = (function() {
7266 function decode(s) { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
7267 function encode(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
7268
7269 function eth_to_aoa(str, opts) {
7270 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
7271 for (; ri !== records.length; ++ri) {
7272 var record = records[ri].trim().split(":");
7273 if(record[0] !== 'cell') continue;
7274 var addr = decode_cell(record[1]);
7275 if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
7276 R = addr.r; C = addr.c;
7277 switch(record[2]) {
7278 case 't': arr[R][C] = decode(record[3]); break;
7279 case 'v': arr[R][C] = +record[3]; break;
7280 case 'vtf': var _f = record[record.length - 1];
7281 /* falls through */
7282 case 'vtc':
7283 switch(record[3]) {
7284 case 'nl': arr[R][C] = +record[4] ? true : false; break;
7285 default: arr[R][C] = +record[4]; break;
7286 }
7287 if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
7288 }
7289 }
7290 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7291 return arr;
7292 }
7293
7294 function eth_to_sheet(d, opts) { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
7295 function eth_to_workbook(d, opts) { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
7296
7297 var header = [
7298 "socialcalc:version:1.5",
7299 "MIME-Version: 1.0",
7300 "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
7301 ].join("\n");
7302
7303 var sep = [
7304 "--SocialCalcSpreadsheetControlSave",
7305 "Content-type: text/plain; charset=UTF-8"
7306 ].join("\n") + "\n";
7307
7308 /* TODO: the other parts */
7309 var meta = [
7310 "# SocialCalc Spreadsheet Control Save",
7311 "part:sheet"
7312 ].join("\n");
7313
7314 var end = "--SocialCalcSpreadsheetControlSave--";
7315
7316 function sheet_to_eth_data(ws) {
7317 if(!ws || !ws['!ref']) return "";
7318 var o = [], oo = [], cell, coord = "";
7319 var r = decode_range(ws['!ref']);
7320 var dense = Array.isArray(ws);
7321 for(var R = r.s.r; R <= r.e.r; ++R) {
7322 for(var C = r.s.c; C <= r.e.c; ++C) {
7323 coord = encode_cell({r:R,c:C});
7324 cell = dense ? (ws[R]||[])[C] : ws[coord];
7325 if(!cell || cell.v == null || cell.t === 'z') continue;
7326 oo = ["cell", coord, 't'];
7327 switch(cell.t) {
7328 case 's': case 'str': oo.push(encode(cell.v)); break;
7329 case 'n':
7330 if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
7331 else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
7332 break;
7333 case 'b':
7334 oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
7335 oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
7336 break;
7337 case 'd':
7338 var t = datenum(parseDate(cell.v));
7339 oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
7340 oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
7341 break;
7342 case 'e': continue;
7343 }
7344 o.push(oo.join(":"));
7345 }
7346 }
7347 o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
7348 o.push("valueformat:1:text-wiki");
7349 //o.push("copiedfrom:" + ws['!ref']); // clipboard only
7350 return o.join("\n");
7351 }
7352
7353 function sheet_to_eth(ws) {
7354 return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
7355 // return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
7356 }
7357
7358 return {
7359 to_workbook: eth_to_workbook,
7360 to_sheet: eth_to_sheet,
7361 from_sheet: sheet_to_eth
7362 };
7363})();
7364
7365var PRN = (function() {
7366 function set_text_arr(data, arr, R, C, o) {
7367 if(o.raw) arr[R][C] = data;
7368 else if(data === 'TRUE') arr[R][C] = true;
7369 else if(data === 'FALSE') arr[R][C] = false;
7370 else if(data === ""){/* empty */}
7371 else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
7372 else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
7373 else arr[R][C] = data;
7374 }
7375
7376 function prn_to_aoa_str(f, opts) {
7377 var o = opts || {};
7378 var arr = ([]);
7379 if(!f || f.length === 0) return arr;
7380 var lines = f.split(/[\r\n]/);
7381 var L = lines.length - 1;
7382 while(L >= 0 && lines[L].length === 0) --L;
7383 var start = 10, idx = 0;
7384 var R = 0;
7385 for(; R <= L; ++R) {
7386 idx = lines[R].indexOf(" ");
7387 if(idx == -1) idx = lines[R].length; else idx++;
7388 start = Math.max(start, idx);
7389 }
7390 for(R = 0; R <= L; ++R) {
7391 arr[R] = [];
7392 /* TODO: confirm that widths are always 10 */
7393 var C = 0;
7394 set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
7395 for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
7396 set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
7397 }
7398 if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
7399 return arr;
7400 }
7401
7402 // List of accepted CSV separators
7403 var guess_seps = {
74040x2C: ',',
74050x09: "\t",
74060x3B: ';'
7407 };
7408
7409 // CSV separator weights to be used in case of equal numbers
7410 var guess_sep_weights = {
74110x2C: 3,
74120x09: 2,
74130x3B: 1
7414 };
7415
7416 function guess_sep(str) {
7417 var cnt = {}, instr = false, end = 0, cc = 0;
7418 for(;end < str.length;++end) {
7419 if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
7420 else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
7421 }
7422
7423 cc = [];
7424 for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
7425 cc.push([ cnt[end], end ]);
7426 }
7427
7428 if ( !cc.length ) {
7429 cnt = guess_sep_weights;
7430 for(end in cnt) if ( cnt.hasOwnProperty(end) ) {
7431 cc.push([ cnt[end], end ]);
7432 }
7433 }
7434
7435 cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
7436
7437 return guess_seps[cc.pop()[1]];
7438 }
7439
7440 function dsv_to_sheet_str(str, opts) {
7441 var o = opts || {};
7442 var sep = "";
7443 if(DENSE != null && o.dense == null) o.dense = DENSE;
7444 var ws = o.dense ? ([]) : ({});
7445 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
7446
7447 if(str.slice(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.slice(6); }
7448 else sep = guess_sep(str.slice(0,1024));
7449 var R = 0, C = 0, v = 0;
7450 var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
7451 str = str.replace(/\r\n/mg, "\n");
7452 var _re = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
7453 function finish_cell() {
7454 var s = str.slice(start, end);
7455 var cell = ({});
7456 if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
7457 if(s.length === 0) cell.t = 'z';
7458 else if(o.raw) { cell.t = 's'; cell.v = s; }
7459 else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
7460 else if(s.charCodeAt(0) == 0x3D) {
7461 if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
7462 else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
7463 else { cell.t = 's'; cell.v = s; } }
7464 else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
7465 else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
7466 else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
7467 else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
7468 cell.z = o.dateNF || SSF._table[14];
7469 var k = 0;
7470 if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
7471 if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
7472 else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
7473 if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
7474 if(!o.cellNF) delete cell.z;
7475 } else {
7476 cell.t = 's';
7477 cell.v = s;
7478 }
7479 if(cell.t == 'z'){}
7480 else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
7481 else ws[encode_cell({c:C,r:R})] = cell;
7482 start = end+1;
7483 if(range.e.c < C) range.e.c = C;
7484 if(range.e.r < R) range.e.r = R;
7485 if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
7486 }
7487 outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
7488 case 0x22: instr = !instr; break;
7489 case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
7490 default: break;
7491 }
7492 if(end - start > 0) finish_cell();
7493
7494 ws['!ref'] = encode_range(range);
7495 return ws;
7496 }
7497
7498 function prn_to_sheet_str(str, opts) {
7499 if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
7500 if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
7501 return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
7502 }
7503
7504 function prn_to_sheet(d, opts) {
7505 var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
7506 switch(opts.type) {
7507 case 'base64': str = Base64.decode(d); break;
7508 case 'binary': str = d; break;
7509 case 'buffer':
7510 if(opts.codepage == 65001) str = d.toString('utf8');
7511 else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
7512 else str = d.toString('binary');
7513 break;
7514 case 'array': str = cc2str(d); break;
7515 case 'string': str = d; break;
7516 default: throw new Error("Unrecognized type " + opts.type);
7517 }
7518 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
7519 else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage) str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str));
7520 if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
7521 return prn_to_sheet_str(str, opts);
7522 }
7523
7524 function prn_to_workbook(d, opts) { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
7525
7526 function sheet_to_prn(ws) {
7527 var o = [];
7528 var r = safe_decode_range(ws['!ref']), cell;
7529 var dense = Array.isArray(ws);
7530 for(var R = r.s.r; R <= r.e.r; ++R) {
7531 var oo = [];
7532 for(var C = r.s.c; C <= r.e.c; ++C) {
7533 var coord = encode_cell({r:R,c:C});
7534 cell = dense ? (ws[R]||[])[C] : ws[coord];
7535 if(!cell || cell.v == null) { oo.push(" "); continue; }
7536 var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
7537 while(w.length < 10) w += " ";
7538 oo.push(w + (C === 0 ? " " : ""));
7539 }
7540 o.push(oo.join(""));
7541 }
7542 return o.join("\n");
7543 }
7544
7545 return {
7546 to_workbook: prn_to_workbook,
7547 to_sheet: prn_to_sheet,
7548 from_sheet: sheet_to_prn
7549 };
7550})();
7551
7552/* Excel defaults to SYLK but warns if data is not valid */
7553function read_wb_ID(d, opts) {
7554 var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
7555 try {
7556 var out = SYLK.to_workbook(d, o);
7557 o.WTF = OLD_WTF;
7558 return out;
7559 } catch(e) {
7560 o.WTF = OLD_WTF;
7561 if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
7562 return PRN.to_workbook(d, opts);
7563 }
7564}
7565
7566var WK_ = (function() {
7567 function lotushopper(data, cb, opts) {
7568 if(!data) return;
7569 prep_blob(data, data.l || 0);
7570 var Enum = opts.Enum || WK1Enum;
7571 while(data.l < data.length) {
7572 var RT = data.read_shift(2);
7573 var R = Enum[RT] || Enum[0xFF];
7574 var length = data.read_shift(2);
7575 var tgt = data.l + length;
7576 var d = (R.f||parsenoop)(data, length, opts);
7577 data.l = tgt;
7578 if(cb(d, R.n, RT)) return;
7579 }
7580 }
7581
7582 function lotus_to_workbook(d, opts) {
7583 switch(opts.type) {
7584 case 'base64': return lotus_to_workbook_buf(s2a(Base64.decode(d)), opts);
7585 case 'binary': return lotus_to_workbook_buf(s2a(d), opts);
7586 case 'buffer':
7587 case 'array': return lotus_to_workbook_buf(d, opts);
7588 }
7589 throw "Unsupported type " + opts.type;
7590 }
7591
7592 function lotus_to_workbook_buf(d, opts) {
7593 if(!d) return d;
7594 var o = opts || {};
7595 if(DENSE != null && o.dense == null) o.dense = DENSE;
7596 var s = ((o.dense ? [] : {})), n = "Sheet1", sidx = 0;
7597 var sheets = {}, snames = [n];
7598
7599 var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
7600 var sheetRows = o.sheetRows || 0;
7601
7602 if(d[2] == 0x02) o.Enum = WK1Enum;
7603 else if(d[2] == 0x1a) o.Enum = WK3Enum;
7604 else if(d[2] == 0x0e) { o.Enum = WK3Enum; o.qpro = true; d.l = 0; }
7605 else throw new Error("Unrecognized LOTUS BOF " + d[2]);
7606 lotushopper(d, function(val, Rn, RT) {
7607 if(d[2] == 0x02) switch(RT) {
7608 case 0x00:
7609 o.vers = val;
7610 if(val >= 0x1000) o.qpro = true;
7611 break;
7612 case 0x06: refguess = val; break; /* RANGE */
7613 case 0x0F: /* LABEL */
7614 if(!o.qpro) val[1].v = val[1].v.slice(1);
7615 /* falls through */
7616 case 0x0D: /* INTEGER */
7617 case 0x0E: /* NUMBER */
7618 case 0x10: /* FORMULA */
7619 case 0x33: /* STRING */
7620 /* TODO: actual translation of the format code */
7621 if(RT == 0x0E && (val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
7622 val[1].z = o.dateNF || SSF._table[14];
7623 if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
7624 }
7625 if(o.dense) {
7626 if(!s[val[0].r]) s[val[0].r] = [];
7627 s[val[0].r][val[0].c] = val[1];
7628 } else s[encode_cell(val[0])] = val[1];
7629 break;
7630 } else switch(RT) {
7631 case 0x16: /* LABEL16 */
7632 val[1].v = val[1].v.slice(1);
7633 /* falls through */
7634 case 0x17: /* NUMBER17 */
7635 case 0x18: /* NUMBER18 */
7636 case 0x19: /* FORMULA19 */
7637 case 0x25: /* NUMBER25 */
7638 case 0x27: /* NUMBER27 */
7639 case 0x28: /* FORMULA28 */
7640 if(val[3] > sidx) {
7641 s["!ref"] = encode_range(refguess);
7642 sheets[n] = s;
7643 s = (o.dense ? [] : {});
7644 refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
7645 sidx = val[3]; n = "Sheet" + (sidx + 1);
7646 snames.push(n);
7647 }
7648 if(sheetRows > 0 && val[0].r >= sheetRows) break;
7649 if(o.dense) {
7650 if(!s[val[0].r]) s[val[0].r] = [];
7651 s[val[0].r][val[0].c] = val[1];
7652 } else s[encode_cell(val[0])] = val[1];
7653 if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
7654 if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
7655 break;
7656 default: break;
7657 }
7658 }, o);
7659
7660 s["!ref"] = encode_range(refguess);
7661 sheets[n] = s;
7662 return { SheetNames: snames, Sheets:sheets };
7663 }
7664
7665 function parse_RANGE(blob) {
7666 var o = {s:{c:0,r:0},e:{c:0,r:0}};
7667 o.s.c = blob.read_shift(2);
7668 o.s.r = blob.read_shift(2);
7669 o.e.c = blob.read_shift(2);
7670 o.e.r = blob.read_shift(2);
7671 if(o.s.c == 0xFFFF) o.s.c = o.e.c = o.s.r = o.e.r = 0;
7672 return o;
7673 }
7674
7675 function parse_cell(blob, length, opts) {
7676 var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7677 if(opts.qpro && opts.vers != 0x5120) {
7678 o[0].c = blob.read_shift(1);
7679 blob.l++;
7680 o[0].r = blob.read_shift(2);
7681 blob.l+=2;
7682 } else {
7683 o[2] = blob.read_shift(1);
7684 o[0].c = blob.read_shift(2); o[0].r = blob.read_shift(2);
7685 }
7686 return o;
7687 }
7688
7689 function parse_LABEL(blob, length, opts) {
7690 var tgt = blob.l + length;
7691 var o = parse_cell(blob, length, opts);
7692 o[1].t = 's';
7693 if(opts.vers == 0x5120) {
7694 blob.l++;
7695 var len = blob.read_shift(1);
7696 o[1].v = blob.read_shift(len, 'utf8');
7697 return o;
7698 }
7699 if(opts.qpro) blob.l++;
7700 o[1].v = blob.read_shift(tgt - blob.l, 'cstr');
7701 return o;
7702 }
7703
7704 function parse_INTEGER(blob, length, opts) {
7705 var o = parse_cell(blob, length, opts);
7706 o[1].v = blob.read_shift(2, 'i');
7707 return o;
7708 }
7709
7710 function parse_NUMBER(blob, length, opts) {
7711 var o = parse_cell(blob, length, opts);
7712 o[1].v = blob.read_shift(8, 'f');
7713 return o;
7714 }
7715
7716 function parse_FORMULA(blob, length, opts) {
7717 var tgt = blob.l + length;
7718 var o = parse_cell(blob, length, opts);
7719 /* TODO: formula */
7720 o[1].v = blob.read_shift(8, 'f');
7721 if(opts.qpro) blob.l = tgt;
7722 else {
7723 var flen = blob.read_shift(2);
7724 blob.l += flen;
7725 }
7726 return o;
7727 }
7728
7729 function parse_cell_3(blob) {
7730 var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7731 o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
7732 return o;
7733 }
7734
7735 function parse_LABEL_16(blob, length) {
7736 var o = parse_cell_3(blob, length);
7737 o[1].t = 's';
7738 o[1].v = blob.read_shift(length - 4, 'cstr');
7739 return o;
7740 }
7741
7742 function parse_NUMBER_18(blob, length) {
7743 var o = parse_cell_3(blob, length);
7744 o[1].v = blob.read_shift(2);
7745 var v = o[1].v >> 1;
7746 /* TODO: figure out all of the corner cases */
7747 if(o[1].v & 0x1) {
7748 switch(v & 0x07) {
7749 case 1: v = (v >> 3) * 500; break;
7750 case 2: v = (v >> 3) / 20; break;
7751 case 4: v = (v >> 3) / 2000; break;
7752 case 6: v = (v >> 3) / 16; break;
7753 case 7: v = (v >> 3) / 64; break;
7754 default: throw "unknown NUMBER_18 encoding " + (v & 0x07);
7755 }
7756 }
7757 o[1].v = v;
7758 return o;
7759 }
7760
7761 function parse_NUMBER_17(blob, length) {
7762 var o = parse_cell_3(blob, length);
7763 var v1 = blob.read_shift(4);
7764 var v2 = blob.read_shift(4);
7765 var e = blob.read_shift(2);
7766 if(e == 0xFFFF) { o[1].v = 0; return o; }
7767 var s = e & 0x8000; e = (e&0x7FFF) - 16446;
7768 o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
7769 return o;
7770 }
7771
7772 function parse_FORMULA_19(blob, length) {
7773 var o = parse_NUMBER_17(blob, 14);
7774 blob.l += length - 14; /* TODO: formula */
7775 return o;
7776 }
7777
7778 function parse_NUMBER_25(blob, length) {
7779 var o = parse_cell_3(blob, length);
7780 var v1 = blob.read_shift(4);
7781 o[1].v = v1 >> 6;
7782 return o;
7783 }
7784
7785 function parse_NUMBER_27(blob, length) {
7786 var o = parse_cell_3(blob, length);
7787 var v1 = blob.read_shift(8,'f');
7788 o[1].v = v1;
7789 return o;
7790 }
7791
7792 function parse_FORMULA_28(blob, length) {
7793 var o = parse_NUMBER_27(blob, 14);
7794 blob.l += length - 10; /* TODO: formula */
7795 return o;
7796 }
7797
7798 var WK1Enum = {
77990x0000: { n:"BOF", f:parseuint16 },
78000x0001: { n:"EOF" },
78010x0002: { n:"CALCMODE" },
78020x0003: { n:"CALCORDER" },
78030x0004: { n:"SPLIT" },
78040x0005: { n:"SYNC" },
78050x0006: { n:"RANGE", f:parse_RANGE },
78060x0007: { n:"WINDOW1" },
78070x0008: { n:"COLW1" },
78080x0009: { n:"WINTWO" },
78090x000A: { n:"COLW2" },
78100x000B: { n:"NAME" },
78110x000C: { n:"BLANK" },
78120x000D: { n:"INTEGER", f:parse_INTEGER },
78130x000E: { n:"NUMBER", f:parse_NUMBER },
78140x000F: { n:"LABEL", f:parse_LABEL },
78150x0010: { n:"FORMULA", f:parse_FORMULA },
78160x0018: { n:"TABLE" },
78170x0019: { n:"ORANGE" },
78180x001A: { n:"PRANGE" },
78190x001B: { n:"SRANGE" },
78200x001C: { n:"FRANGE" },
78210x001D: { n:"KRANGE1" },
78220x0020: { n:"HRANGE" },
78230x0023: { n:"KRANGE2" },
78240x0024: { n:"PROTEC" },
78250x0025: { n:"FOOTER" },
78260x0026: { n:"HEADER" },
78270x0027: { n:"SETUP" },
78280x0028: { n:"MARGINS" },
78290x0029: { n:"LABELFMT" },
78300x002A: { n:"TITLES" },
78310x002B: { n:"SHEETJS" },
78320x002D: { n:"GRAPH" },
78330x002E: { n:"NGRAPH" },
78340x002F: { n:"CALCCOUNT" },
78350x0030: { n:"UNFORMATTED" },
78360x0031: { n:"CURSORW12" },
78370x0032: { n:"WINDOW" },
78380x0033: { n:"STRING", f:parse_LABEL },
78390x0037: { n:"PASSWORD" },
78400x0038: { n:"LOCKED" },
78410x003C: { n:"QUERY" },
78420x003D: { n:"QUERYNAME" },
78430x003E: { n:"PRINT" },
78440x003F: { n:"PRINTNAME" },
78450x0040: { n:"GRAPH2" },
78460x0041: { n:"GRAPHNAME" },
78470x0042: { n:"ZOOM" },
78480x0043: { n:"SYMSPLIT" },
78490x0044: { n:"NSROWS" },
78500x0045: { n:"NSCOLS" },
78510x0046: { n:"RULER" },
78520x0047: { n:"NNAME" },
78530x0048: { n:"ACOMM" },
78540x0049: { n:"AMACRO" },
78550x004A: { n:"PARSE" },
78560x00FF: { n:"", f:parsenoop }
7857 };
7858
7859 var WK3Enum = {
78600x0000: { n:"BOF" },
78610x0001: { n:"EOF" },
78620x0003: { n:"??" },
78630x0004: { n:"??" },
78640x0005: { n:"??" },
78650x0006: { n:"??" },
78660x0007: { n:"??" },
78670x0009: { n:"??" },
78680x000a: { n:"??" },
78690x000b: { n:"??" },
78700x000c: { n:"??" },
78710x000e: { n:"??" },
78720x000f: { n:"??" },
78730x0010: { n:"??" },
78740x0011: { n:"??" },
78750x0012: { n:"??" },
78760x0013: { n:"??" },
78770x0015: { n:"??" },
78780x0016: { n:"LABEL16", f:parse_LABEL_16},
78790x0017: { n:"NUMBER17", f:parse_NUMBER_17 },
78800x0018: { n:"NUMBER18", f:parse_NUMBER_18 },
78810x0019: { n:"FORMULA19", f:parse_FORMULA_19},
78820x001a: { n:"??" },
78830x001b: { n:"??" },
78840x001c: { n:"??" },
78850x001d: { n:"??" },
78860x001e: { n:"??" },
78870x001f: { n:"??" },
78880x0021: { n:"??" },
78890x0025: { n:"NUMBER25", f:parse_NUMBER_25 },
78900x0027: { n:"NUMBER27", f:parse_NUMBER_27 },
78910x0028: { n:"FORMULA28", f:parse_FORMULA_28 },
78920x00FF: { n:"", f:parsenoop }
7893 };
7894 return {
7895 to_workbook: lotus_to_workbook
7896 };
7897})();
7898/* Parse a list of <r> tags */
7899var parse_rs = (function parse_rs_factory() {
7900 var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g;
7901 /* 18.4.7 rPr CT_RPrElt */
7902 var parse_rpr = function parse_rpr(rpr, intro, outro) {
7903 var font = {}, cp = 65001, align = "";
7904 var pass = false;
7905 var m = rpr.match(tagregex), i = 0;
7906 if(m) for(;i!=m.length; ++i) {
7907 var y = parsexmltag(m[i]);
7908 switch(y[0].replace(/\w*:/g,"")) {
7909 /* 18.8.12 condense CT_BooleanProperty */
7910 /* ** not required . */
7911 case '<condense': break;
7912 /* 18.8.17 extend CT_BooleanProperty */
7913 /* ** not required . */
7914 case '<extend': break;
7915 /* 18.8.36 shadow CT_BooleanProperty */
7916 /* ** not required . */
7917 case '<shadow':
7918 if(!y.val) break;
7919 /* falls through */
7920 case '<shadow>':
7921 case '<shadow/>': font.shadow = 1; break;
7922 case '</shadow>': break;
7923
7924 /* 18.4.1 charset CT_IntProperty TODO */
7925 case '<charset':
7926 if(y.val == '1') break;
7927 cp = CS2CP[parseInt(y.val, 10)];
7928 break;
7929
7930 /* 18.4.2 outline CT_BooleanProperty TODO */
7931 case '<outline':
7932 if(!y.val) break;
7933 /* falls through */
7934 case '<outline>':
7935 case '<outline/>': font.outline = 1; break;
7936 case '</outline>': break;
7937
7938 /* 18.4.5 rFont CT_FontName */
7939 case '<rFont': font.name = y.val; break;
7940
7941 /* 18.4.11 sz CT_FontSize */
7942 case '<sz': font.sz = y.val; break;
7943
7944 /* 18.4.10 strike CT_BooleanProperty */
7945 case '<strike':
7946 if(!y.val) break;
7947 /* falls through */
7948 case '<strike>':
7949 case '<strike/>': font.strike = 1; break;
7950 case '</strike>': break;
7951
7952 /* 18.4.13 u CT_UnderlineProperty */
7953 case '<u':
7954 if(!y.val) break;
7955 switch(y.val) {
7956 case 'double': font.uval = "double"; break;
7957 case 'singleAccounting': font.uval = "single-accounting"; break;
7958 case 'doubleAccounting': font.uval = "double-accounting"; break;
7959 }
7960 /* falls through */
7961 case '<u>':
7962 case '<u/>': font.u = 1; break;
7963 case '</u>': break;
7964
7965 /* 18.8.2 b */
7966 case '<b':
7967 if(y.val == '0') break;
7968 /* falls through */
7969 case '<b>':
7970 case '<b/>': font.b = 1; break;
7971 case '</b>': break;
7972
7973 /* 18.8.26 i */
7974 case '<i':
7975 if(y.val == '0') break;
7976 /* falls through */
7977 case '<i>':
7978 case '<i/>': font.i = 1; break;
7979 case '</i>': break;
7980
7981 /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
7982 case '<color':
7983 if(y.rgb) font.color = y.rgb.slice(2,8);
7984 break;
7985
7986 /* 18.8.18 family ST_FontFamily */
7987 case '<family': font.family = y.val; break;
7988
7989 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
7990 case '<vertAlign': align = y.val; break;
7991
7992 /* 18.8.35 scheme CT_FontScheme TODO */
7993 case '<scheme': break;
7994
7995 /* 18.2.10 extLst CT_ExtensionList ? */
7996 case '<extLst': case '<extLst>': case '</extLst>': break;
7997 case '<ext': pass = true; break;
7998 case '</ext>': pass = false; break;
7999 default:
8000 if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
8001 }
8002 }
8003 var style = [];
8004
8005 if(font.u) style.push("text-decoration: underline;");
8006 if(font.uval) style.push("text-underline-style:" + font.uval + ";");
8007 if(font.sz) style.push("font-size:" + font.sz + "pt;");
8008 if(font.outline) style.push("text-effect: outline;");
8009 if(font.shadow) style.push("text-shadow: auto;");
8010 intro.push('<span style="' + style.join("") + '">');
8011
8012 if(font.b) { intro.push("<b>"); outro.push("</b>"); }
8013 if(font.i) { intro.push("<i>"); outro.push("</i>"); }
8014 if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
8015
8016 if(align == "superscript") align = "sup";
8017 else if(align == "subscript") align = "sub";
8018 if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
8019
8020 outro.push("</span>");
8021 return cp;
8022 };
8023
8024 /* 18.4.4 r CT_RElt */
8025 function parse_r(r) {
8026 var terms = [[],"",[]];
8027 /* 18.4.12 t ST_Xstring */
8028 var t = r.match(tregex)/*, cp = 65001*/;
8029 if(!t) return "";
8030 terms[1] = t[1];
8031
8032 var rpr = r.match(rpregex);
8033 if(rpr) /*cp = */parse_rpr(rpr[1], terms[0], terms[2]);
8034
8035 return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
8036 }
8037 return function parse_rs(rs) {
8038 return rs.replace(rregex,"").split(rend).map(parse_r).join("");
8039 };
8040})();
8041
8042/* 18.4.8 si CT_Rst */
8043var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
8044var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
8045function parse_si(x, opts) {
8046 var html = opts ? opts.cellHTML : true;
8047 var z = {};
8048 if(!x) return null;
8049 //var y;
8050 /* 18.4.12 t ST_Xstring (Plaintext String) */
8051 // TODO: is whitespace actually valid here?
8052 if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
8053 z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
8054 z.r = utf8read(x);
8055 if(html) z.h = escapehtml(z.t);
8056 }
8057 /* 18.4.4 r CT_RElt (Rich Text Run) */
8058 else if((/*y = */x.match(sirregex))) {
8059 z.r = utf8read(x);
8060 z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
8061 if(html) z.h = parse_rs(z.r);
8062 }
8063 /* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
8064 /* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
8065 return z;
8066}
8067
8068/* 18.4 Shared String Table */
8069var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
8070var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
8071var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
8072function parse_sst_xml(data, opts) {
8073 var s = ([]), ss = "";
8074 if(!data) return s;
8075 /* 18.4.9 sst CT_Sst */
8076 var sst = data.match(sstr0);
8077 if(sst) {
8078 ss = sst[2].replace(sstr1,"").split(sstr2);
8079 for(var i = 0; i != ss.length; ++i) {
8080 var o = parse_si(ss[i].trim(), opts);
8081 if(o != null) s[s.length] = o;
8082 }
8083 sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
8084 }
8085 return s;
8086}
8087
8088RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
8089var straywsregex = /^\s|\s$|[\t\n\r]/;
8090function write_sst_xml(sst, opts) {
8091 if(!opts.bookSST) return "";
8092 var o = [XML_HEADER];
8093 o[o.length] = (writextag('sst', null, {
8094 xmlns: XMLNS.main[0],
8095 count: sst.Count,
8096 uniqueCount: sst.Unique
8097 }));
8098 for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
8099 var s = sst[i];
8100 var sitag = "<si>";
8101 if(s.r) sitag += s.r;
8102 else {
8103 sitag += "<t";
8104 if(!s.t) s.t = "";
8105 if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
8106 sitag += ">" + escapexml(s.t) + "</t>";
8107 }
8108 sitag += "</si>";
8109 o[o.length] = (sitag);
8110 }
8111 if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
8112 return o.join("");
8113}
8114/* [MS-XLSB] 2.4.221 BrtBeginSst */
8115function parse_BrtBeginSst(data) {
8116 return [data.read_shift(4), data.read_shift(4)];
8117}
8118
8119/* [MS-XLSB] 2.1.7.45 Shared Strings */
8120function parse_sst_bin(data, opts) {
8121 var s = ([]);
8122 var pass = false;
8123 recordhopper(data, function hopper_sst(val, R_n, RT) {
8124 switch(RT) {
8125 case 0x009F: /* 'BrtBeginSst' */
8126 s.Count = val[0]; s.Unique = val[1]; break;
8127 case 0x0013: /* 'BrtSSTItem' */
8128 s.push(val); break;
8129 case 0x00A0: /* 'BrtEndSst' */
8130 return true;
8131
8132 case 0x0023: /* 'BrtFRTBegin' */
8133 pass = true; break;
8134 case 0x0024: /* 'BrtFRTEnd' */
8135 pass = false; break;
8136
8137 default:
8138 if(R_n.indexOf("Begin") > 0){/* empty */}
8139 else if(R_n.indexOf("End") > 0){/* empty */}
8140 if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
8141 }
8142 });
8143 return s;
8144}
8145
8146function write_BrtBeginSst(sst, o) {
8147 if(!o) o = new_buf(8);
8148 o.write_shift(4, sst.Count);
8149 o.write_shift(4, sst.Unique);
8150 return o;
8151}
8152
8153var write_BrtSSTItem = write_RichStr;
8154
8155function write_sst_bin(sst) {
8156 var ba = buf_array();
8157 write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst));
8158 for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i]));
8159 /* FRTSST */
8160 write_record(ba, "BrtEndSst");
8161 return ba.end();
8162}
8163function _JS2ANSI(str) {
8164 if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str);
8165 var o = [], oo = str.split("");
8166 for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0);
8167 return o;
8168}
8169
8170/* [MS-OFFCRYPTO] 2.1.4 Version */
8171function parse_CRYPTOVersion(blob, length) {
8172 var o = {};
8173 o.Major = blob.read_shift(2);
8174 o.Minor = blob.read_shift(2);
8175if(length >= 4) blob.l += length - 4;
8176 return o;
8177}
8178
8179/* [MS-OFFCRYPTO] 2.1.5 DataSpaceVersionInfo */
8180function parse_DataSpaceVersionInfo(blob) {
8181 var o = {};
8182 o.id = blob.read_shift(0, 'lpp4');
8183 o.R = parse_CRYPTOVersion(blob, 4);
8184 o.U = parse_CRYPTOVersion(blob, 4);
8185 o.W = parse_CRYPTOVersion(blob, 4);
8186 return o;
8187}
8188
8189/* [MS-OFFCRYPTO] 2.1.6.1 DataSpaceMapEntry Structure */
8190function parse_DataSpaceMapEntry(blob) {
8191 var len = blob.read_shift(4);
8192 var end = blob.l + len - 4;
8193 var o = {};
8194 var cnt = blob.read_shift(4);
8195 var comps = [];
8196 /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
8197 while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') });
8198 o.name = blob.read_shift(0, 'lpp4');
8199 o.comps = comps;
8200 if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end);
8201 return o;
8202}
8203
8204/* [MS-OFFCRYPTO] 2.1.6 DataSpaceMap */
8205function parse_DataSpaceMap(blob) {
8206 var o = [];
8207 blob.l += 4; // must be 0x8
8208 var cnt = blob.read_shift(4);
8209 while(cnt-- > 0) o.push(parse_DataSpaceMapEntry(blob));
8210 return o;
8211}
8212
8213/* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */
8214function parse_DataSpaceDefinition(blob) {
8215 var o = [];
8216 blob.l += 4; // must be 0x8
8217 var cnt = blob.read_shift(4);
8218 while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4'));
8219 return o;
8220}
8221
8222/* [MS-OFFCRYPTO] 2.1.8 DataSpaceDefinition */
8223function parse_TransformInfoHeader(blob) {
8224 var o = {};
8225 /*var len = */blob.read_shift(4);
8226 blob.l += 4; // must be 0x1
8227 o.id = blob.read_shift(0, 'lpp4');
8228 o.name = blob.read_shift(0, 'lpp4');
8229 o.R = parse_CRYPTOVersion(blob, 4);
8230 o.U = parse_CRYPTOVersion(blob, 4);
8231 o.W = parse_CRYPTOVersion(blob, 4);
8232 return o;
8233}
8234
8235function parse_Primary(blob) {
8236 /* [MS-OFFCRYPTO] 2.2.6 IRMDSTransformInfo */
8237 var hdr = parse_TransformInfoHeader(blob);
8238 /* [MS-OFFCRYPTO] 2.1.9 EncryptionTransformInfo */
8239 hdr.ename = blob.read_shift(0, '8lpp4');
8240 hdr.blksz = blob.read_shift(4);
8241 hdr.cmode = blob.read_shift(4);
8242 if(blob.read_shift(4) != 0x04) throw new Error("Bad !Primary record");
8243 return hdr;
8244}
8245
8246/* [MS-OFFCRYPTO] 2.3.2 Encryption Header */
8247function parse_EncryptionHeader(blob, length) {
8248 var tgt = blob.l + length;
8249 var o = {};
8250 o.Flags = (blob.read_shift(4) & 0x3F);
8251 blob.l += 4;
8252 o.AlgID = blob.read_shift(4);
8253 var valid = false;
8254 switch(o.AlgID) {
8255 case 0x660E: case 0x660F: case 0x6610: valid = (o.Flags == 0x24); break;
8256 case 0x6801: valid = (o.Flags == 0x04); break;
8257 case 0: valid = (o.Flags == 0x10 || o.Flags == 0x04 || o.Flags == 0x24); break;
8258 default: throw 'Unrecognized encryption algorithm: ' + o.AlgID;
8259 }
8260 if(!valid) throw new Error("Encryption Flags/AlgID mismatch");
8261 o.AlgIDHash = blob.read_shift(4);
8262 o.KeySize = blob.read_shift(4);
8263 o.ProviderType = blob.read_shift(4);
8264 blob.l += 8;
8265 o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
8266 blob.l = tgt;
8267 return o;
8268}
8269
8270/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
8271function parse_EncryptionVerifier(blob, length) {
8272 var o = {}, tgt = blob.l + length;
8273 blob.l += 4; // SaltSize must be 0x10
8274 o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
8275 o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
8276 /*var sz = */blob.read_shift(4);
8277 o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
8278 return o;
8279}
8280
8281/* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */
8282function parse_EncryptionInfo(blob) {
8283 var vers = parse_CRYPTOVersion(blob);
8284 switch(vers.Minor) {
8285 case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
8286 case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
8287 case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
8288 }
8289 throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
8290}
8291
8292/* [MS-OFFCRYPTO] 2.3.4.5 EncryptionInfo Stream (Standard Encryption) */
8293function parse_EncInfoStd(blob) {
8294 var flags = blob.read_shift(4);
8295 if((flags & 0x3F) != 0x24) throw new Error("EncryptionInfo mismatch");
8296 var sz = blob.read_shift(4);
8297 //var tgt = blob.l + sz;
8298 var hdr = parse_EncryptionHeader(blob, sz);
8299 var verifier = parse_EncryptionVerifier(blob, blob.length - blob.l);
8300 return { t:"Std", h:hdr, v:verifier };
8301}
8302/* [MS-OFFCRYPTO] 2.3.4.6 EncryptionInfo Stream (Extensible Encryption) */
8303function parse_EncInfoExt() { throw new Error("File is password-protected: ECMA-376 Extensible"); }
8304/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
8305function parse_EncInfoAgl(blob) {
8306 var KeyData = ["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];
8307 blob.l+=4;
8308 var xml = blob.read_shift(blob.length - blob.l, 'utf8');
8309 var o = {};
8310 xml.replace(tagregex, function xml_agile(x) {
8311 var y = parsexmltag(x);
8312 switch(strip_ns(y[0])) {
8313 case '<?xml': break;
8314 case '<encryption': case '</encryption>': break;
8315 case '<keyData': KeyData.forEach(function(k) { o[k] = y[k]; }); break;
8316 case '<dataIntegrity': o.encryptedHmacKey = y.encryptedHmacKey; o.encryptedHmacValue = y.encryptedHmacValue; break;
8317 case '<keyEncryptors>': case '<keyEncryptors': o.encs = []; break;
8318 case '</keyEncryptors>': break;
8319
8320 case '<keyEncryptor': o.uri = y.uri; break;
8321 case '</keyEncryptor>': break;
8322 case '<encryptedKey': o.encs.push(y); break;
8323 default: throw y[0];
8324 }
8325 });
8326 return o;
8327}
8328
8329/* [MS-OFFCRYPTO] 2.3.5.1 RC4 CryptoAPI Encryption Header */
8330function parse_RC4CryptoHeader(blob, length) {
8331 var o = {};
8332 var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4;
8333 if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor);
8334 if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major);
8335 o.Flags = blob.read_shift(4); length -= 4;
8336 var sz = blob.read_shift(4); length -= 4;
8337 o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
8338 o.EncryptionVerifier = parse_EncryptionVerifier(blob, length);
8339 return o;
8340}
8341/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
8342function parse_RC4Header(blob) {
8343 var o = {};
8344 var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4);
8345 if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
8346 o.Salt = blob.read_shift(16);
8347 o.EncryptedVerifier = blob.read_shift(16);
8348 o.EncryptedVerifierHash = blob.read_shift(16);
8349 return o;
8350}
8351
8352/* [MS-OFFCRYPTO] 2.3.7.1 Binary Document Password Verifier Derivation */
8353function crypto_CreatePasswordVerifier_Method1(Password) {
8354 var Verifier = 0x0000, PasswordArray;
8355 var PasswordDecoded = _JS2ANSI(Password);
8356 var len = PasswordDecoded.length + 1, i, PasswordByte;
8357 var Intermediate1, Intermediate2, Intermediate3;
8358 PasswordArray = new_raw_buf(len);
8359 PasswordArray[0] = PasswordDecoded.length;
8360 for(i = 1; i != len; ++i) PasswordArray[i] = PasswordDecoded[i-1];
8361 for(i = len-1; i >= 0; --i) {
8362 PasswordByte = PasswordArray[i];
8363 Intermediate1 = ((Verifier & 0x4000) === 0x0000) ? 0 : 1;
8364 Intermediate2 = (Verifier << 1) & 0x7FFF;
8365 Intermediate3 = Intermediate1 | Intermediate2;
8366 Verifier = Intermediate3 ^ PasswordByte;
8367 }
8368 return Verifier ^ 0xCE4B;
8369}
8370
8371/* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */
8372var crypto_CreateXorArray_Method1 = (function() {
8373 var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00];
8374 var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3];
8375 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];
8376 var Ror = function(Byte) { return ((Byte/2) | (Byte*128)) & 0xFF; };
8377 var XorRor = function(byte1, byte2) { return Ror(byte1 ^ byte2); };
8378 var CreateXorKey_Method1 = function(Password) {
8379 var XorKey = InitialCode[Password.length - 1];
8380 var CurrentElement = 0x68;
8381 for(var i = Password.length-1; i >= 0; --i) {
8382 var Char = Password[i];
8383 for(var j = 0; j != 7; ++j) {
8384 if(Char & 0x40) XorKey ^= XorMatrix[CurrentElement];
8385 Char *= 2; --CurrentElement;
8386 }
8387 }
8388 return XorKey;
8389 };
8390 return function(password) {
8391 var Password = _JS2ANSI(password);
8392 var XorKey = CreateXorKey_Method1(Password);
8393 var Index = Password.length;
8394 var ObfuscationArray = new_raw_buf(16);
8395 for(var i = 0; i != 16; ++i) ObfuscationArray[i] = 0x00;
8396 var Temp, PasswordLastChar, PadIndex;
8397 if((Index & 1) === 1) {
8398 Temp = XorKey >> 8;
8399 ObfuscationArray[Index] = XorRor(PadArray[0], Temp);
8400 --Index;
8401 Temp = XorKey & 0xFF;
8402 PasswordLastChar = Password[Password.length - 1];
8403 ObfuscationArray[Index] = XorRor(PasswordLastChar, Temp);
8404 }
8405 while(Index > 0) {
8406 --Index;
8407 Temp = XorKey >> 8;
8408 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8409 --Index;
8410 Temp = XorKey & 0xFF;
8411 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8412 }
8413 Index = 15;
8414 PadIndex = 15 - Password.length;
8415 while(PadIndex > 0) {
8416 Temp = XorKey >> 8;
8417 ObfuscationArray[Index] = XorRor(PadArray[PadIndex], Temp);
8418 --Index;
8419 --PadIndex;
8420 Temp = XorKey & 0xFF;
8421 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8422 --Index;
8423 --PadIndex;
8424 }
8425 return ObfuscationArray;
8426 };
8427})();
8428
8429/* [MS-OFFCRYPTO] 2.3.7.3 Binary Document XOR Data Transformation Method 1 */
8430var crypto_DecryptData_Method1 = function(password, Data, XorArrayIndex, XorArray, O) {
8431 /* If XorArray is set, use it; if O is not set, make changes in-place */
8432 if(!O) O = Data;
8433 if(!XorArray) XorArray = crypto_CreateXorArray_Method1(password);
8434 var Index, Value;
8435 for(Index = 0; Index != Data.length; ++Index) {
8436 Value = Data[Index];
8437 Value ^= XorArray[XorArrayIndex];
8438 Value = ((Value>>5) | (Value<<3)) & 0xFF;
8439 O[Index] = Value;
8440 ++XorArrayIndex;
8441 }
8442 return [O, XorArrayIndex, XorArray];
8443};
8444
8445var crypto_MakeXorDecryptor = function(password) {
8446 var XorArrayIndex = 0, XorArray = crypto_CreateXorArray_Method1(password);
8447 return function(Data) {
8448 var O = crypto_DecryptData_Method1("", Data, XorArrayIndex, XorArray);
8449 XorArrayIndex = O[1];
8450 return O[0];
8451 };
8452};
8453
8454/* 2.5.343 */
8455function parse_XORObfuscation(blob, length, opts, out) {
8456 var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) });
8457 if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
8458 out.valid = o.verificationBytes === o.verifier;
8459 if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
8460 return o;
8461}
8462
8463/* 2.4.117 */
8464function parse_FilePassHeader(blob, length, oo) {
8465 var o = oo || {}; o.Info = blob.read_shift(2); blob.l -= 2;
8466 if(o.Info === 1) o.Data = parse_RC4Header(blob, length);
8467 else o.Data = parse_RC4CryptoHeader(blob, length);
8468 return o;
8469}
8470function parse_FilePass(blob, length, opts) {
8471 var o = ({ Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }); /* wEncryptionType */
8472 if(o.Type) parse_FilePassHeader(blob, length-2, o);
8473 else parse_XORObfuscation(blob, opts.biff >= 8 ? length : length - 2, opts, o);
8474 return o;
8475}
8476
8477
8478var RTF = (function() {
8479 function rtf_to_sheet(d, opts) {
8480 switch(opts.type) {
8481 case 'base64': return rtf_to_sheet_str(Base64.decode(d), opts);
8482 case 'binary': return rtf_to_sheet_str(d, opts);
8483 case 'buffer': return rtf_to_sheet_str(d.toString('binary'), opts);
8484 case 'array': return rtf_to_sheet_str(cc2str(d), opts);
8485 }
8486 throw new Error("Unrecognized type " + opts.type);
8487 }
8488
8489 function rtf_to_sheet_str(str, opts) {
8490 var o = opts || {};
8491 var ws = o.dense ? ([]) : ({});
8492 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
8493
8494 // TODO: parse
8495 if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
8496
8497 ws['!ref'] = encode_range(range);
8498 return ws;
8499 }
8500
8501 function rtf_to_workbook(d, opts) { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
8502
8503 /* TODO: this is a stub */
8504 function sheet_to_rtf(ws) {
8505 var o = ["{\\rtf1\\ansi"];
8506 var r = safe_decode_range(ws['!ref']), cell;
8507 var dense = Array.isArray(ws);
8508 for(var R = r.s.r; R <= r.e.r; ++R) {
8509 o.push("\\trowd\\trautofit1");
8510 for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
8511 o.push("\\pard\\intbl");
8512 for(C = r.s.c; C <= r.e.c; ++C) {
8513 var coord = encode_cell({r:R,c:C});
8514 cell = dense ? (ws[R]||[])[C]: ws[coord];
8515 if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
8516 o.push(" " + (cell.w || (format_cell(cell), cell.w)));
8517 o.push("\\cell");
8518 }
8519 o.push("\\pard\\intbl\\row");
8520 }
8521 return o.join("") + "}";
8522 }
8523
8524 return {
8525 to_workbook: rtf_to_workbook,
8526 to_sheet: rtf_to_sheet,
8527 from_sheet: sheet_to_rtf
8528 };
8529})();
8530function hex2RGB(h) {
8531 var o = h.slice(h[0]==="#"?1:0).slice(0,6);
8532 return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
8533}
8534function rgb2Hex(rgb) {
8535 for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
8536 return o.toString(16).toUpperCase().slice(1);
8537}
8538
8539function rgb2HSL(rgb) {
8540 var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
8541 var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
8542 if(C === 0) return [0, 0, R];
8543
8544 var H6 = 0, S = 0, L2 = (M + m);
8545 S = C / (L2 > 1 ? 2 - L2 : L2);
8546 switch(M){
8547 case R: H6 = ((G - B) / C + 6)%6; break;
8548 case G: H6 = ((B - R) / C + 2); break;
8549 case B: H6 = ((R - G) / C + 4); break;
8550 }
8551 return [H6 / 6, S, L2 / 2];
8552}
8553
8554function hsl2RGB(hsl){
8555 var H = hsl[0], S = hsl[1], L = hsl[2];
8556 var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
8557 var rgb = [m,m,m], h6 = 6*H;
8558
8559 var X;
8560 if(S !== 0) switch(h6|0) {
8561 case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
8562 case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
8563 case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
8564 case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
8565 case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
8566 case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
8567 }
8568 for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
8569 return rgb;
8570}
8571
8572/* 18.8.3 bgColor tint algorithm */
8573function rgb_tint(hex, tint) {
8574 if(tint === 0) return hex;
8575 var hsl = rgb2HSL(hex2RGB(hex));
8576 if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
8577 else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
8578 return rgb2Hex(hsl2RGB(hsl));
8579}
8580
8581/* 18.3.1.13 width calculations */
8582/* [MS-OI29500] 2.1.595 Column Width & Formatting */
8583var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
8584function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
8585function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
8586function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
8587//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
8588//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
8589function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
8590/* XLSX/XLSB/XLS specify width in units of MDW */
8591function find_mdw_colw(collw) {
8592 var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
8593 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; }
8594 MDW = _MDW;
8595}
8596/* XLML specifies width in terms of pixels */
8597/*function find_mdw_wpx(wpx) {
8598 var delta = Infinity, guess = 0, _MDW = MIN_MDW;
8599 for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
8600 guess = char2width_(px2char_(wpx))*256;
8601 guess = (guess) % 1;
8602 if(guess > 0.5) guess--;
8603 if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
8604 }
8605 MDW = _MDW;
8606}*/
8607
8608function process_col(coll) {
8609 if(coll.width) {
8610 coll.wpx = width2px(coll.width);
8611 coll.wch = px2char(coll.wpx);
8612 coll.MDW = MDW;
8613 } else if(coll.wpx) {
8614 coll.wch = px2char(coll.wpx);
8615 coll.width = char2width(coll.wch);
8616 coll.MDW = MDW;
8617 } else if(typeof coll.wch == 'number') {
8618 coll.width = char2width(coll.wch);
8619 coll.wpx = width2px(coll.width);
8620 coll.MDW = MDW;
8621 }
8622 if(coll.customWidth) delete coll.customWidth;
8623}
8624
8625var DEF_PPI = 96, PPI = DEF_PPI;
8626function px2pt(px) { return px * 96 / PPI; }
8627function pt2px(pt) { return pt * PPI / 96; }
8628
8629/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
8630var XLMLPatternTypeMap = {
8631 "None": "none",
8632 "Solid": "solid",
8633 "Gray50": "mediumGray",
8634 "Gray75": "darkGray",
8635 "Gray25": "lightGray",
8636 "HorzStripe": "darkHorizontal",
8637 "VertStripe": "darkVertical",
8638 "ReverseDiagStripe": "darkDown",
8639 "DiagStripe": "darkUp",
8640 "DiagCross": "darkGrid",
8641 "ThickDiagCross": "darkTrellis",
8642 "ThinHorzStripe": "lightHorizontal",
8643 "ThinVertStripe": "lightVertical",
8644 "ThinReverseDiagStripe": "lightDown",
8645 "ThinHorzCross": "lightGrid"
8646};
8647
8648/* 18.8.5 borders CT_Borders */
8649function parse_borders(t, styles, themes, opts) {
8650 styles.Borders = [];
8651 var border = {}/*, sub_border = {}*/;
8652 var pass = false;
8653 t[0].match(tagregex).forEach(function(x) {
8654 var y = parsexmltag(x);
8655 switch(strip_ns(y[0])) {
8656 case '<borders': case '<borders>': case '</borders>': break;
8657
8658 /* 18.8.4 border CT_Border */
8659 case '<border': case '<border>': case '<border/>':
8660 border = {};
8661 if (y.diagonalUp) { border.diagonalUp = y.diagonalUp; }
8662 if (y.diagonalDown) { border.diagonalDown = y.diagonalDown; }
8663 styles.Borders.push(border);
8664 break;
8665 case '</border>': break;
8666
8667 /* note: not in spec, appears to be CT_BorderPr */
8668 case '<left/>': break;
8669 case '<left': case '<left>': break;
8670 case '</left>': break;
8671
8672 /* note: not in spec, appears to be CT_BorderPr */
8673 case '<right/>': break;
8674 case '<right': case '<right>': break;
8675 case '</right>': break;
8676
8677 /* 18.8.43 top CT_BorderPr */
8678 case '<top/>': break;
8679 case '<top': case '<top>': break;
8680 case '</top>': break;
8681
8682 /* 18.8.6 bottom CT_BorderPr */
8683 case '<bottom/>': break;
8684 case '<bottom': case '<bottom>': break;
8685 case '</bottom>': break;
8686
8687 /* 18.8.13 diagonal CT_BorderPr */
8688 case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
8689 case '</diagonal>': break;
8690
8691 /* 18.8.25 horizontal CT_BorderPr */
8692 case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
8693 case '</horizontal>': break;
8694
8695 /* 18.8.44 vertical CT_BorderPr */
8696 case '<vertical': case '<vertical>': case '<vertical/>': break;
8697 case '</vertical>': break;
8698
8699 /* 18.8.37 start CT_BorderPr */
8700 case '<start': case '<start>': case '<start/>': break;
8701 case '</start>': break;
8702
8703 /* 18.8.16 end CT_BorderPr */
8704 case '<end': case '<end>': case '<end/>': break;
8705 case '</end>': break;
8706
8707 /* 18.8.? color CT_Color */
8708 case '<color': case '<color>': break;
8709 case '<color/>': case '</color>': break;
8710
8711 /* 18.2.10 extLst CT_ExtensionList ? */
8712 case '<extLst': case '<extLst>': case '</extLst>': break;
8713 case '<ext': pass = true; break;
8714 case '</ext>': pass = false; break;
8715 default: if(opts && opts.WTF) {
8716 if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
8717 }
8718 }
8719 });
8720}
8721
8722/* 18.8.21 fills CT_Fills */
8723function parse_fills(t, styles, themes, opts) {
8724 styles.Fills = [];
8725 var fill = {};
8726 var pass = false;
8727 t[0].match(tagregex).forEach(function(x) {
8728 var y = parsexmltag(x);
8729 switch(strip_ns(y[0])) {
8730 case '<fills': case '<fills>': case '</fills>': break;
8731
8732 /* 18.8.20 fill CT_Fill */
8733 case '<fill>': case '<fill': case '<fill/>':
8734 fill = {}; styles.Fills.push(fill); break;
8735 case '</fill>': break;
8736
8737 /* 18.8.24 gradientFill CT_GradientFill */
8738 case '<gradientFill>': break;
8739 case '<gradientFill':
8740 case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
8741
8742 /* 18.8.32 patternFill CT_PatternFill */
8743 case '<patternFill': case '<patternFill>':
8744 if(y.patternType) fill.patternType = y.patternType;
8745 break;
8746 case '<patternFill/>': case '</patternFill>': break;
8747
8748 /* 18.8.3 bgColor CT_Color */
8749 case '<bgColor':
8750 if(!fill.bgColor) fill.bgColor = {};
8751 if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
8752 if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
8753 if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
8754 /* Excel uses ARGB strings */
8755 if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
8756 break;
8757 case '<bgColor/>': case '</bgColor>': break;
8758
8759 /* 18.8.19 fgColor CT_Color */
8760 case '<fgColor':
8761 if(!fill.fgColor) fill.fgColor = {};
8762 if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
8763 if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
8764 /* Excel uses ARGB strings */
8765 if(y.rgb) fill.fgColor.rgb = y.rgb.slice(-6);
8766 break;
8767 case '<fgColor/>': case '</fgColor>': break;
8768
8769 /* 18.8.38 stop CT_GradientStop */
8770 case '<stop': case '<stop/>': break;
8771 case '</stop>': break;
8772
8773 /* 18.8.? color CT_Color */
8774 case '<color': case '<color/>': break;
8775 case '</color>': break;
8776
8777 /* 18.2.10 extLst CT_ExtensionList ? */
8778 case '<extLst': case '<extLst>': case '</extLst>': break;
8779 case '<ext': pass = true; break;
8780 case '</ext>': pass = false; break;
8781 default: if(opts && opts.WTF) {
8782 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
8783 }
8784 }
8785 });
8786}
8787
8788/* 18.8.23 fonts CT_Fonts */
8789function parse_fonts(t, styles, themes, opts) {
8790 styles.Fonts = [];
8791 var font = {};
8792 var pass = false;
8793 t[0].match(tagregex).forEach(function(x) {
8794 var y = parsexmltag(x);
8795 switch(strip_ns(y[0])) {
8796 case '<fonts': case '<fonts>': case '</fonts>': break;
8797
8798 /* 18.8.22 font CT_Font */
8799 case '<font': case '<font>': break;
8800 case '</font>': case '<font/>':
8801 styles.Fonts.push(font);
8802 font = {};
8803 break;
8804
8805 /* 18.8.29 name CT_FontName */
8806 case '<name': if(y.val) font.name = y.val; break;
8807 case '<name/>': case '</name>': break;
8808
8809 /* 18.8.2 b CT_BooleanProperty */
8810 case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
8811 case '<b/>': font.bold = 1; break;
8812
8813 /* 18.8.26 i CT_BooleanProperty */
8814 case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
8815 case '<i/>': font.italic = 1; break;
8816
8817 /* 18.4.13 u CT_UnderlineProperty */
8818 case '<u':
8819 switch(y.val) {
8820 case "none": font.underline = 0x00; break;
8821 case "single": font.underline = 0x01; break;
8822 case "double": font.underline = 0x02; break;
8823 case "singleAccounting": font.underline = 0x21; break;
8824 case "doubleAccounting": font.underline = 0x22; break;
8825 } break;
8826 case '<u/>': font.underline = 1; break;
8827
8828 /* 18.4.10 strike CT_BooleanProperty */
8829 case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
8830 case '<strike/>': font.strike = 1; break;
8831
8832 /* 18.4.2 outline CT_BooleanProperty */
8833 case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
8834 case '<outline/>': font.outline = 1; break;
8835
8836 /* 18.8.36 shadow CT_BooleanProperty */
8837 case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
8838 case '<shadow/>': font.shadow = 1; break;
8839
8840 /* 18.8.12 condense CT_BooleanProperty */
8841 case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
8842 case '<condense/>': font.condense = 1; break;
8843
8844 /* 18.8.17 extend CT_BooleanProperty */
8845 case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
8846 case '<extend/>': font.extend = 1; break;
8847
8848 /* 18.4.11 sz CT_FontSize */
8849 case '<sz': if(y.val) font.sz = +y.val; break;
8850 case '<sz/>': case '</sz>': break;
8851
8852 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
8853 case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
8854 case '<vertAlign/>': case '</vertAlign>': break;
8855
8856 /* 18.8.18 family CT_FontFamily */
8857 case '<family': if(y.val) font.family = parseInt(y.val,10); break;
8858 case '<family/>': case '</family>': break;
8859
8860 /* 18.8.35 scheme CT_FontScheme */
8861 case '<scheme': if(y.val) font.scheme = y.val; break;
8862 case '<scheme/>': case '</scheme>': break;
8863
8864 /* 18.4.1 charset CT_IntProperty */
8865 case '<charset':
8866 if(y.val == '1') break;
8867 y.codepage = CS2CP[parseInt(y.val, 10)];
8868 break;
8869
8870 /* 18.?.? color CT_Color */
8871 case '<color':
8872 if(!font.color) font.color = {};
8873 if(y.auto) font.color.auto = parsexmlbool(y.auto);
8874
8875 if(y.rgb) font.color.rgb = y.rgb.slice(-6);
8876 else if(y.indexed) {
8877 font.color.index = parseInt(y.indexed, 10);
8878 var icv = XLSIcv[font.color.index];
8879 if(font.color.index == 81) icv = XLSIcv[1];
8880 if(!icv) throw new Error(x);
8881 font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
8882 } else if(y.theme) {
8883 font.color.theme = parseInt(y.theme, 10);
8884 if(y.tint) font.color.tint = parseFloat(y.tint);
8885 if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
8886 font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
8887 }
8888 }
8889
8890 break;
8891 case '<color/>': case '</color>': break;
8892
8893 /* 18.2.10 extLst CT_ExtensionList ? */
8894 case '<extLst': case '<extLst>': case '</extLst>': break;
8895 case '<ext': pass = true; break;
8896 case '</ext>': pass = false; break;
8897 default: if(opts && opts.WTF) {
8898 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
8899 }
8900 }
8901 });
8902}
8903
8904/* 18.8.31 numFmts CT_NumFmts */
8905function parse_numFmts(t, styles, opts) {
8906 styles.NumberFmt = [];
8907 var k/*Array<number>*/ = (keys(SSF._table));
8908 for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
8909 var m = t[0].match(tagregex);
8910 if(!m) return;
8911 for(i=0; i < m.length; ++i) {
8912 var y = parsexmltag(m[i]);
8913 switch(strip_ns(y[0])) {
8914 case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
8915 case '<numFmt': {
8916 var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
8917 styles.NumberFmt[j] = f;
8918 if(j>0) {
8919 if(j > 0x188) {
8920 for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
8921 styles.NumberFmt[j] = f;
8922 }
8923 SSF.load(f,j);
8924 }
8925 } break;
8926 case '</numFmt>': break;
8927 default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
8928 }
8929 }
8930}
8931
8932function write_numFmts(NF) {
8933 var o = ["<numFmts>"];
8934 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
8935 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])}));
8936 });
8937 if(o.length === 1) return "";
8938 o[o.length] = ("</numFmts>");
8939 o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
8940 return o.join("");
8941}
8942
8943/* 18.8.10 cellXfs CT_CellXfs */
8944var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
8945var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
8946function parse_cellXfs(t, styles, opts) {
8947 styles.CellXf = [];
8948 var xf;
8949 var pass = false;
8950 t[0].match(tagregex).forEach(function(x) {
8951 var y = parsexmltag(x), i = 0;
8952 switch(strip_ns(y[0])) {
8953 case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
8954
8955 /* 18.8.45 xf CT_Xf */
8956 case '<xf': case '<xf/>':
8957 xf = y;
8958 delete xf[0];
8959 for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
8960 xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
8961 for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
8962 xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
8963 if(xf.numFmtId > 0x188) {
8964 for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
8965 }
8966 styles.CellXf.push(xf); break;
8967 case '</xf>': break;
8968
8969 /* 18.8.1 alignment CT_CellAlignment */
8970 case '<alignment': case '<alignment/>':
8971 var alignment = {};
8972 if(y.vertical) alignment.vertical = y.vertical;
8973 if(y.horizontal) alignment.horizontal = y.horizontal;
8974 if(y.textRotation != null) alignment.textRotation = y.textRotation;
8975 if(y.indent) alignment.indent = y.indent;
8976 if(y.wrapText) alignment.wrapText = y.wrapText;
8977 xf.alignment = alignment;
8978 break;
8979 case '</alignment>': break;
8980
8981 /* 18.8.33 protection CT_CellProtection */
8982 case '<protection': case '</protection>': case '<protection/>': break;
8983
8984 /* 18.2.10 extLst CT_ExtensionList ? */
8985 case '<extLst': case '<extLst>': case '</extLst>': break;
8986 case '<ext': pass = true; break;
8987 case '</ext>': pass = false; break;
8988 default: if(opts && opts.WTF) {
8989 if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
8990 }
8991 }
8992 });
8993}
8994
8995function write_cellXfs(cellXfs) {
8996 var o = [];
8997 o[o.length] = (writextag('cellXfs',null));
8998 cellXfs.forEach(function(c) { o[o.length] = (writextag('xf', null, c)); });
8999 o[o.length] = ("</cellXfs>");
9000 if(o.length === 2) return "";
9001 o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
9002 return o.join("");
9003}
9004
9005/* 18.8 Styles CT_Stylesheet*/
9006var parse_sty_xml= (function make_pstyx() {
9007var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
9008var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
9009var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
9010var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
9011var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
9012
9013return function parse_sty_xml(data, themes, opts) {
9014 var styles = {};
9015 if(!data) return styles;
9016 data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
9017 /* 18.8.39 styleSheet CT_Stylesheet */
9018 var t;
9019
9020 /* 18.8.31 numFmts CT_NumFmts ? */
9021 if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
9022
9023 /* 18.8.23 fonts CT_Fonts ? */
9024 if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
9025
9026 /* 18.8.21 fills CT_Fills ? */
9027 if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
9028
9029 /* 18.8.5 borders CT_Borders ? */
9030 if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
9031
9032 /* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
9033
9034 /* 18.8.10 cellXfs CT_CellXfs ? */
9035 if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
9036
9037 /* 18.8.8 cellStyles CT_CellStyles ? */
9038 /* 18.8.15 dxfs CT_Dxfs ? */
9039 /* 18.8.42 tableStyles CT_TableStyles ? */
9040 /* 18.8.11 colors CT_Colors ? */
9041 /* 18.2.10 extLst CT_ExtensionList ? */
9042
9043 return styles;
9044};
9045})();
9046
9047var STYLES_XML_ROOT = writextag('styleSheet', null, {
9048 'xmlns': XMLNS.main[0],
9049 'xmlns:vt': XMLNS.vt
9050});
9051
9052RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
9053
9054function write_sty_xml(wb, opts) {
9055 var o = [XML_HEADER, STYLES_XML_ROOT], w;
9056 if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
9057 o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
9058 o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
9059 o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
9060 o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
9061 if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
9062 o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
9063 o[o.length] = ('<dxfs count="0"/>');
9064 o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
9065
9066 if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
9067 return o.join("");
9068}
9069/* [MS-XLSB] 2.4.657 BrtFmt */
9070function parse_BrtFmt(data, length) {
9071 var numFmtId = data.read_shift(2);
9072 var stFmtCode = parse_XLWideString(data,length-2);
9073 return [numFmtId, stFmtCode];
9074}
9075function write_BrtFmt(i, f, o) {
9076 if(!o) o = new_buf(6 + 4 * f.length);
9077 o.write_shift(2, i);
9078 write_XLWideString(f, o);
9079 var out = (o.length > o.l) ? o.slice(0, o.l) : o;
9080 if(o.l == null) o.l = o.length;
9081 return out;
9082}
9083
9084/* [MS-XLSB] 2.4.659 BrtFont TODO */
9085function parse_BrtFont(data, length, opts) {
9086 var out = ({});
9087
9088 out.sz = data.read_shift(2) / 20;
9089
9090 var grbit = parse_FontFlags(data, 2, opts);
9091 if(grbit.fCondense) out.condense = 1;
9092 if(grbit.fExtend) out.extend = 1;
9093 if(grbit.fShadow) out.shadow = 1;
9094 if(grbit.fOutline) out.outline = 1;
9095 if(grbit.fStrikeout) out.strike = 1;
9096 if(grbit.fItalic) out.italic = 1;
9097
9098 var bls = data.read_shift(2);
9099 if(bls === 0x02BC) out.bold = 1;
9100
9101 switch(data.read_shift(2)) {
9102 /* case 0: out.vertAlign = "baseline"; break; */
9103 case 1: out.vertAlign = "superscript"; break;
9104 case 2: out.vertAlign = "subscript"; break;
9105 }
9106
9107 var underline = data.read_shift(1);
9108 if(underline != 0) out.underline = underline;
9109
9110 var family = data.read_shift(1);
9111 if(family > 0) out.family = family;
9112
9113 var bCharSet = data.read_shift(1);
9114 if(bCharSet > 0) out.charset = bCharSet;
9115
9116 data.l++;
9117 out.color = parse_BrtColor(data, 8);
9118
9119 switch(data.read_shift(1)) {
9120 /* case 0: out.scheme = "none": break; */
9121 case 1: out.scheme = "major"; break;
9122 case 2: out.scheme = "minor"; break;
9123 }
9124
9125 out.name = parse_XLWideString(data, length - 21);
9126
9127 return out;
9128}
9129function write_BrtFont(font, o) {
9130 if(!o) o = new_buf(25+4*32);
9131 o.write_shift(2, font.sz * 20);
9132 write_FontFlags(font, o);
9133 o.write_shift(2, font.bold ? 0x02BC : 0x0190);
9134 var sss = 0;
9135 if(font.vertAlign == "superscript") sss = 1;
9136 else if(font.vertAlign == "subscript") sss = 2;
9137 o.write_shift(2, sss);
9138 o.write_shift(1, font.underline || 0);
9139 o.write_shift(1, font.family || 0);
9140 o.write_shift(1, font.charset || 0);
9141 o.write_shift(1, 0);
9142 write_BrtColor(font.color, o);
9143 var scheme = 0;
9144 if(font.scheme == "major") scheme = 1;
9145 if(font.scheme == "minor") scheme = 2;
9146 o.write_shift(1, scheme);
9147 write_XLWideString(font.name, o);
9148 return o.length > o.l ? o.slice(0, o.l) : o;
9149}
9150
9151/* [MS-XLSB] 2.4.650 BrtFill */
9152var XLSBFillPTNames = [
9153 "none",
9154 "solid",
9155 "mediumGray",
9156 "darkGray",
9157 "lightGray",
9158 "darkHorizontal",
9159 "darkVertical",
9160 "darkDown",
9161 "darkUp",
9162 "darkGrid",
9163 "darkTrellis",
9164 "lightHorizontal",
9165 "lightVertical",
9166 "lightDown",
9167 "lightUp",
9168 "lightGrid",
9169 "lightTrellis",
9170 "gray125",
9171 "gray0625"
9172];
9173var rev_XLSBFillPTNames = (evert(XLSBFillPTNames));
9174/* TODO: gradient fill representation */
9175var parse_BrtFill = parsenoop;
9176function write_BrtFill(fill, o) {
9177 if(!o) o = new_buf(4*3 + 8*7 + 16*1);
9178 var fls = rev_XLSBFillPTNames[fill.patternType];
9179 if(fls == null) fls = 0x28;
9180 o.write_shift(4, fls);
9181 var j = 0;
9182 if(fls != 0x28) {
9183 /* TODO: custom FG Color */
9184 write_BrtColor({auto:1}, o);
9185 /* TODO: custom BG Color */
9186 write_BrtColor({auto:1}, o);
9187
9188 for(; j < 12; ++j) o.write_shift(4, 0);
9189 } else {
9190 for(; j < 4; ++j) o.write_shift(4, 0);
9191
9192 for(; j < 12; ++j) o.write_shift(4, 0); /* TODO */
9193 /* iGradientType */
9194 /* xnumDegree */
9195 /* xnumFillToLeft */
9196 /* xnumFillToRight */
9197 /* xnumFillToTop */
9198 /* xnumFillToBottom */
9199 /* cNumStop */
9200 /* xfillGradientStop */
9201 }
9202 return o.length > o.l ? o.slice(0, o.l) : o;
9203}
9204
9205/* [MS-XLSB] 2.4.824 BrtXF */
9206function parse_BrtXF(data, length) {
9207 var tgt = data.l + length;
9208 var ixfeParent = data.read_shift(2);
9209 var ifmt = data.read_shift(2);
9210 data.l = tgt;
9211 return {ixfe:ixfeParent, numFmtId:ifmt };
9212}
9213function write_BrtXF(data, ixfeP, o) {
9214 if(!o) o = new_buf(16);
9215 o.write_shift(2, ixfeP||0);
9216 o.write_shift(2, data.numFmtId||0);
9217 o.write_shift(2, 0); /* iFont */
9218 o.write_shift(2, 0); /* iFill */
9219 o.write_shift(2, 0); /* ixBorder */
9220 o.write_shift(1, 0); /* trot */
9221 o.write_shift(1, 0); /* indent */
9222 o.write_shift(1, 0); /* flags */
9223 o.write_shift(1, 0); /* flags */
9224 o.write_shift(1, 0); /* xfGrbitAtr */
9225 o.write_shift(1, 0);
9226 return o;
9227}
9228
9229/* [MS-XLSB] 2.5.4 Blxf TODO */
9230function write_Blxf(data, o) {
9231 if(!o) o = new_buf(10);
9232 o.write_shift(1, 0); /* dg */
9233 o.write_shift(1, 0);
9234 o.write_shift(4, 0); /* color */
9235 o.write_shift(4, 0); /* color */
9236 return o;
9237}
9238/* [MS-XLSB] 2.4.302 BrtBorder TODO */
9239var parse_BrtBorder = parsenoop;
9240function write_BrtBorder(border, o) {
9241 if(!o) o = new_buf(51);
9242 o.write_shift(1, 0); /* diagonal */
9243 write_Blxf(null, o); /* top */
9244 write_Blxf(null, o); /* bottom */
9245 write_Blxf(null, o); /* left */
9246 write_Blxf(null, o); /* right */
9247 write_Blxf(null, o); /* diag */
9248 return o.length > o.l ? o.slice(0, o.l) : o;
9249}
9250
9251/* [MS-XLSB] 2.4.763 BrtStyle TODO */
9252function write_BrtStyle(style, o) {
9253 if(!o) o = new_buf(12+4*10);
9254 o.write_shift(4, style.xfId);
9255 o.write_shift(2, 1);
9256 o.write_shift(1, +style.builtinId);
9257 o.write_shift(1, 0); /* iLevel */
9258 write_XLNullableWideString(style.name || "", o);
9259 return o.length > o.l ? o.slice(0, o.l) : o;
9260}
9261
9262/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
9263function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
9264 var o = new_buf(4+256*2*4);
9265 o.write_shift(4, cnt);
9266 write_XLNullableWideString(defTableStyle, o);
9267 write_XLNullableWideString(defPivotStyle, o);
9268 return o.length > o.l ? o.slice(0, o.l) : o;
9269}
9270
9271/* [MS-XLSB] 2.1.7.50 Styles */
9272function parse_sty_bin(data, themes, opts) {
9273 var styles = {};
9274 styles.NumberFmt = ([]);
9275 for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y];
9276
9277 styles.CellXf = [];
9278 styles.Fonts = [];
9279 var state = [];
9280 var pass = false;
9281 recordhopper(data, function hopper_sty(val, R_n, RT) {
9282 switch(RT) {
9283 case 0x002C: /* 'BrtFmt' */
9284 styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]);
9285 break;
9286 case 0x002B: /* 'BrtFont' */
9287 styles.Fonts.push(val);
9288 if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) {
9289 val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0);
9290 }
9291 break;
9292 case 0x0401: /* 'BrtKnownFonts' */ break;
9293 case 0x002D: /* 'BrtFill' */ break;
9294 case 0x002E: /* 'BrtBorder' */ break;
9295 case 0x002F: /* 'BrtXF' */
9296 if(state[state.length - 1] == "BrtBeginCellXFs") {
9297 styles.CellXf.push(val);
9298 }
9299 break;
9300 case 0x0030: /* 'BrtStyle' */
9301 case 0x01FB: /* 'BrtDXF' */
9302 case 0x023C: /* 'BrtMRUColor' */
9303 case 0x01DB: /* 'BrtIndexedColor': */
9304 break;
9305
9306 case 0x0493: /* 'BrtDXF14' */
9307 case 0x0836: /* 'BrtDXF15' */
9308 case 0x046A: /* 'BrtSlicerStyleElement' */
9309 case 0x0200: /* 'BrtTableStyleElement' */
9310 case 0x082F: /* 'BrtTimelineStyleElement' */
9311 case 0x0C00: /* 'BrtUid' */
9312 break;
9313
9314 case 0x0023: /* 'BrtFRTBegin' */
9315 pass = true; break;
9316 case 0x0024: /* 'BrtFRTEnd' */
9317 pass = false; break;
9318 case 0x0025: /* 'BrtACBegin' */
9319 state.push(R_n); break;
9320 case 0x0026: /* 'BrtACEnd' */
9321 state.pop(); break;
9322
9323 default:
9324 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
9325 else if((R_n||"").indexOf("End") > 0) state.pop();
9326 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9327 }
9328 });
9329 return styles;
9330}
9331
9332function write_FMTS_bin(ba, NF) {
9333 if(!NF) return;
9334 var cnt = 0;
9335 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9336for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
9337 });
9338
9339 if(cnt == 0) return;
9340 write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
9341 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9342for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
9343 });
9344 write_record(ba, "BrtEndFmts");
9345}
9346
9347function write_FONTS_bin(ba) {
9348 var cnt = 1;
9349
9350 if(cnt == 0) return;
9351 write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt));
9352 write_record(ba, "BrtFont", write_BrtFont({
9353 sz:12,
9354 color: {theme:1},
9355 name: "Calibri",
9356 family: 2,
9357 scheme: "minor"
9358 }));
9359 /* 1*65491BrtFont [ACFONTS] */
9360 write_record(ba, "BrtEndFonts");
9361}
9362
9363function write_FILLS_bin(ba) {
9364 var cnt = 2;
9365
9366 if(cnt == 0) return;
9367 write_record(ba, "BrtBeginFills", write_UInt32LE(cnt));
9368 write_record(ba, "BrtFill", write_BrtFill({patternType:"none"}));
9369 write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"}));
9370 /* 1*65431BrtFill */
9371 write_record(ba, "BrtEndFills");
9372}
9373
9374function write_BORDERS_bin(ba) {
9375 var cnt = 1;
9376
9377 if(cnt == 0) return;
9378 write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt));
9379 write_record(ba, "BrtBorder", write_BrtBorder({}));
9380 /* 1*65430BrtBorder */
9381 write_record(ba, "BrtEndBorders");
9382}
9383
9384function write_CELLSTYLEXFS_bin(ba) {
9385 var cnt = 1;
9386 write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
9387 write_record(ba, "BrtXF", write_BrtXF({
9388 numFmtId:0,
9389 fontId:0,
9390 fillId:0,
9391 borderId:0
9392 }, 0xFFFF));
9393 /* 1*65430(BrtXF *FRT) */
9394 write_record(ba, "BrtEndCellStyleXFs");
9395}
9396
9397function write_CELLXFS_bin(ba, data) {
9398 write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length));
9399 data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); });
9400 /* 1*65430(BrtXF *FRT) */
9401 write_record(ba, "BrtEndCellXFs");
9402}
9403
9404function write_STYLES_bin(ba) {
9405 var cnt = 1;
9406
9407 write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt));
9408 write_record(ba, "BrtStyle", write_BrtStyle({
9409 xfId:0,
9410 builtinId:0,
9411 name:"Normal"
9412 }));
9413 /* 1*65430(BrtStyle *FRT) */
9414 write_record(ba, "BrtEndStyles");
9415}
9416
9417function write_DXFS_bin(ba) {
9418 var cnt = 0;
9419
9420 write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
9421 /* *2147483647(BrtDXF *FRT) */
9422 write_record(ba, "BrtEndDXFs");
9423}
9424
9425function write_TABLESTYLES_bin(ba) {
9426 var cnt = 0;
9427
9428 write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
9429 /* *TABLESTYLE */
9430 write_record(ba, "BrtEndTableStyles");
9431}
9432
9433function write_COLORPALETTE_bin() {
9434 return;
9435 /* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
9436}
9437
9438/* [MS-XLSB] 2.1.7.50 Styles */
9439function write_sty_bin(wb, opts) {
9440 var ba = buf_array();
9441 write_record(ba, "BrtBeginStyleSheet");
9442 write_FMTS_bin(ba, wb.SSF);
9443 write_FONTS_bin(ba, wb);
9444 write_FILLS_bin(ba, wb);
9445 write_BORDERS_bin(ba, wb);
9446 write_CELLSTYLEXFS_bin(ba, wb);
9447 write_CELLXFS_bin(ba, opts.cellXfs);
9448 write_STYLES_bin(ba, wb);
9449 write_DXFS_bin(ba, wb);
9450 write_TABLESTYLES_bin(ba, wb);
9451 write_COLORPALETTE_bin(ba, wb);
9452 /* FRTSTYLESHEET*/
9453 write_record(ba, "BrtEndStyleSheet");
9454 return ba.end();
9455}
9456RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
9457
9458/* 20.1.6.2 clrScheme CT_ColorScheme */
9459function parse_clrScheme(t, themes, opts) {
9460 themes.themeElements.clrScheme = [];
9461 var color = {};
9462 (t[0].match(tagregex)||[]).forEach(function(x) {
9463 var y = parsexmltag(x);
9464 switch(y[0]) {
9465 /* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
9466 case '<a:clrScheme': case '</a:clrScheme>': break;
9467
9468 /* 20.1.2.3.32 srgbClr CT_SRgbColor */
9469 case '<a:srgbClr':
9470 color.rgb = y.val; break;
9471
9472 /* 20.1.2.3.33 sysClr CT_SystemColor */
9473 case '<a:sysClr':
9474 color.rgb = y.lastClr; break;
9475
9476 /* 20.1.4.1.1 accent1 (Accent 1) */
9477 /* 20.1.4.1.2 accent2 (Accent 2) */
9478 /* 20.1.4.1.3 accent3 (Accent 3) */
9479 /* 20.1.4.1.4 accent4 (Accent 4) */
9480 /* 20.1.4.1.5 accent5 (Accent 5) */
9481 /* 20.1.4.1.6 accent6 (Accent 6) */
9482 /* 20.1.4.1.9 dk1 (Dark 1) */
9483 /* 20.1.4.1.10 dk2 (Dark 2) */
9484 /* 20.1.4.1.15 folHlink (Followed Hyperlink) */
9485 /* 20.1.4.1.19 hlink (Hyperlink) */
9486 /* 20.1.4.1.22 lt1 (Light 1) */
9487 /* 20.1.4.1.23 lt2 (Light 2) */
9488 case '<a:dk1>': case '</a:dk1>':
9489 case '<a:lt1>': case '</a:lt1>':
9490 case '<a:dk2>': case '</a:dk2>':
9491 case '<a:lt2>': case '</a:lt2>':
9492 case '<a:accent1>': case '</a:accent1>':
9493 case '<a:accent2>': case '</a:accent2>':
9494 case '<a:accent3>': case '</a:accent3>':
9495 case '<a:accent4>': case '</a:accent4>':
9496 case '<a:accent5>': case '</a:accent5>':
9497 case '<a:accent6>': case '</a:accent6>':
9498 case '<a:hlink>': case '</a:hlink>':
9499 case '<a:folHlink>': case '</a:folHlink>':
9500 if (y[0].charAt(1) === '/') {
9501 themes.themeElements.clrScheme.push(color);
9502 color = {};
9503 } else {
9504 color.name = y[0].slice(3, y[0].length - 1);
9505 }
9506 break;
9507
9508 default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
9509 }
9510 });
9511}
9512
9513/* 20.1.4.1.18 fontScheme CT_FontScheme */
9514function parse_fontScheme() { }
9515
9516/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
9517function parse_fmtScheme() { }
9518
9519var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
9520var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
9521var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
9522
9523/* 20.1.6.10 themeElements CT_BaseStyles */
9524function parse_themeElements(data, themes, opts) {
9525 themes.themeElements = {};
9526
9527 var t;
9528
9529 [
9530 /* clrScheme CT_ColorScheme */
9531 ['clrScheme', clrsregex, parse_clrScheme],
9532 /* fontScheme CT_FontScheme */
9533 ['fontScheme', fntsregex, parse_fontScheme],
9534 /* fmtScheme CT_StyleMatrix */
9535 ['fmtScheme', fmtsregex, parse_fmtScheme]
9536 ].forEach(function(m) {
9537 if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
9538 m[2](t, themes, opts);
9539 });
9540}
9541
9542var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
9543
9544/* 14.2.7 Theme Part */
9545function parse_theme_xml(data, opts) {
9546 /* 20.1.6.9 theme CT_OfficeStyleSheet */
9547 if(!data || data.length === 0) return parse_theme_xml(write_theme());
9548
9549 var t;
9550 var themes = {};
9551
9552 /* themeElements CT_BaseStyles */
9553 if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
9554 parse_themeElements(t[0], themes, opts);
9555
9556 return themes;
9557}
9558
9559function write_theme(Themes, opts) {
9560 if(opts && opts.themeXLSX) return opts.themeXLSX;
9561 var o = [XML_HEADER];
9562 o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
9563 o[o.length] = '<a:themeElements>';
9564
9565 o[o.length] = '<a:clrScheme name="Office">';
9566 o[o.length] = '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
9567 o[o.length] = '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
9568 o[o.length] = '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
9569 o[o.length] = '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
9570 o[o.length] = '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
9571 o[o.length] = '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
9572 o[o.length] = '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
9573 o[o.length] = '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
9574 o[o.length] = '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
9575 o[o.length] = '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
9576 o[o.length] = '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
9577 o[o.length] = '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
9578 o[o.length] = '</a:clrScheme>';
9579
9580 o[o.length] = '<a:fontScheme name="Office">';
9581 o[o.length] = '<a:majorFont>';
9582 o[o.length] = '<a:latin typeface="Cambria"/>';
9583 o[o.length] = '<a:ea typeface=""/>';
9584 o[o.length] = '<a:cs typeface=""/>';
9585 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
9586 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
9587 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
9588 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
9589 o[o.length] = '<a:font script="Arab" typeface="Times New Roman"/>';
9590 o[o.length] = '<a:font script="Hebr" typeface="Times New Roman"/>';
9591 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
9592 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
9593 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
9594 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
9595 o[o.length] = '<a:font script="Khmr" typeface="MoolBoran"/>';
9596 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
9597 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
9598 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
9599 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
9600 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
9601 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
9602 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
9603 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
9604 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
9605 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
9606 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
9607 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
9608 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
9609 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
9610 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
9611 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
9612 o[o.length] = '<a:font script="Viet" typeface="Times New Roman"/>';
9613 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
9614 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
9615 o[o.length] = '</a:majorFont>';
9616 o[o.length] = '<a:minorFont>';
9617 o[o.length] = '<a:latin typeface="Calibri"/>';
9618 o[o.length] = '<a:ea typeface=""/>';
9619 o[o.length] = '<a:cs typeface=""/>';
9620 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
9621 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
9622 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
9623 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
9624 o[o.length] = '<a:font script="Arab" typeface="Arial"/>';
9625 o[o.length] = '<a:font script="Hebr" typeface="Arial"/>';
9626 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
9627 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
9628 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
9629 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
9630 o[o.length] = '<a:font script="Khmr" typeface="DaunPenh"/>';
9631 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
9632 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
9633 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
9634 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
9635 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
9636 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
9637 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
9638 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
9639 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
9640 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
9641 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
9642 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
9643 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
9644 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
9645 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
9646 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
9647 o[o.length] = '<a:font script="Viet" typeface="Arial"/>';
9648 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
9649 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
9650 o[o.length] = '</a:minorFont>';
9651 o[o.length] = '</a:fontScheme>';
9652
9653 o[o.length] = '<a:fmtScheme name="Office">';
9654 o[o.length] = '<a:fillStyleLst>';
9655 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9656 o[o.length] = '<a:gradFill rotWithShape="1">';
9657 o[o.length] = '<a:gsLst>';
9658 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9659 o[o.length] = '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9660 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9661 o[o.length] = '</a:gsLst>';
9662 o[o.length] = '<a:lin ang="16200000" scaled="1"/>';
9663 o[o.length] = '</a:gradFill>';
9664 o[o.length] = '<a:gradFill rotWithShape="1">';
9665 o[o.length] = '<a:gsLst>';
9666 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>';
9667 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>';
9668 o[o.length] = '</a:gsLst>';
9669 o[o.length] = '<a:lin ang="16200000" scaled="0"/>';
9670 o[o.length] = '</a:gradFill>';
9671 o[o.length] = '</a:fillStyleLst>';
9672 o[o.length] = '<a:lnStyleLst>';
9673 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>';
9674 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>';
9675 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>';
9676 o[o.length] = '</a:lnStyleLst>';
9677 o[o.length] = '<a:effectStyleLst>';
9678 o[o.length] = '<a:effectStyle>';
9679 o[o.length] = '<a:effectLst>';
9680 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>';
9681 o[o.length] = '</a:effectLst>';
9682 o[o.length] = '</a:effectStyle>';
9683 o[o.length] = '<a:effectStyle>';
9684 o[o.length] = '<a:effectLst>';
9685 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>';
9686 o[o.length] = '</a:effectLst>';
9687 o[o.length] = '</a:effectStyle>';
9688 o[o.length] = '<a:effectStyle>';
9689 o[o.length] = '<a:effectLst>';
9690 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>';
9691 o[o.length] = '</a:effectLst>';
9692 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>';
9693 o[o.length] = '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
9694 o[o.length] = '</a:effectStyle>';
9695 o[o.length] = '</a:effectStyleLst>';
9696 o[o.length] = '<a:bgFillStyleLst>';
9697 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9698 o[o.length] = '<a:gradFill rotWithShape="1">';
9699 o[o.length] = '<a:gsLst>';
9700 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9701 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>';
9702 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
9703 o[o.length] = '</a:gsLst>';
9704 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
9705 o[o.length] = '</a:gradFill>';
9706 o[o.length] = '<a:gradFill rotWithShape="1">';
9707 o[o.length] = '<a:gsLst>';
9708 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9709 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
9710 o[o.length] = '</a:gsLst>';
9711 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
9712 o[o.length] = '</a:gradFill>';
9713 o[o.length] = '</a:bgFillStyleLst>';
9714 o[o.length] = '</a:fmtScheme>';
9715 o[o.length] = '</a:themeElements>';
9716
9717 o[o.length] = '<a:objectDefaults>';
9718 o[o.length] = '<a:spDef>';
9719 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>';
9720 o[o.length] = '</a:spDef>';
9721 o[o.length] = '<a:lnDef>';
9722 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>';
9723 o[o.length] = '</a:lnDef>';
9724 o[o.length] = '</a:objectDefaults>';
9725 o[o.length] = '<a:extraClrSchemeLst/>';
9726 o[o.length] = '</a:theme>';
9727 return o.join("");
9728}
9729/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
9730function parse_Theme(blob, length, opts) {
9731 var end = blob.l + length;
9732 var dwThemeVersion = blob.read_shift(4);
9733 if(dwThemeVersion === 124226) return;
9734 if(!opts.cellStyles || !jszip) { blob.l = end; return; }
9735 var data = blob.slice(blob.l);
9736 blob.l = end;
9737 var zip; try { zip = new jszip(data); } catch(e) { return; }
9738 var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true);
9739 if(!themeXML) return;
9740 return parse_theme_xml(themeXML, opts);
9741}
9742
9743/* 2.5.49 */
9744function parse_ColorTheme(blob) { return blob.read_shift(4); }
9745
9746/* 2.5.155 */
9747function parse_FullColorExt(blob) {
9748 var o = {};
9749 o.xclrType = blob.read_shift(2);
9750 o.nTintShade = blob.read_shift(2);
9751 switch(o.xclrType) {
9752 case 0: blob.l += 4; break;
9753 case 1: o.xclrValue = parse_IcvXF(blob, 4); break;
9754 case 2: o.xclrValue = parse_LongRGBA(blob, 4); break;
9755 case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
9756 case 4: blob.l += 4; break;
9757 }
9758 blob.l += 8;
9759 return o;
9760}
9761
9762/* 2.5.164 TODO: read 7 bits*/
9763function parse_IcvXF(blob, length) {
9764 return parsenoop(blob, length);
9765}
9766
9767/* 2.5.280 */
9768function parse_XFExtGradient(blob, length) {
9769 return parsenoop(blob, length);
9770}
9771
9772/* [MS-XLS] 2.5.108 */
9773function parse_ExtProp(blob) {
9774 var extType = blob.read_shift(2);
9775 var cb = blob.read_shift(2) - 4;
9776 var o = [extType];
9777 switch(extType) {
9778 case 0x04: case 0x05: case 0x07: case 0x08:
9779 case 0x09: case 0x0A: case 0x0B: case 0x0D:
9780 o[1] = parse_FullColorExt(blob, cb); break;
9781 case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
9782 case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
9783 default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
9784 }
9785 return o;
9786}
9787
9788/* 2.4.355 */
9789function parse_XFExt(blob, length) {
9790 var end = blob.l + length;
9791 blob.l += 2;
9792 var ixfe = blob.read_shift(2);
9793 blob.l += 2;
9794 var cexts = blob.read_shift(2);
9795 var ext = [];
9796 while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
9797 return {ixfe:ixfe, ext:ext};
9798}
9799
9800/* xf is an XF, see parse_XFExt for xfext */
9801function update_xfext(xf, xfext) {
9802 xfext.forEach(function(xfe) {
9803 switch(xfe[0]) { /* 2.5.108 extPropData */
9804 case 0x04: break; /* foreground color */
9805 case 0x05: break; /* background color */
9806 case 0x06: break; /* gradient fill */
9807 case 0x07: break; /* top cell border color */
9808 case 0x08: break; /* bottom cell border color */
9809 case 0x09: break; /* left cell border color */
9810 case 0x0a: break; /* right cell border color */
9811 case 0x0b: break; /* diagonal cell border color */
9812 case 0x0d: break; /* text color */
9813 case 0x0e: break; /* font scheme */
9814 case 0x0f: break; /* indentation level */
9815 }
9816 });
9817}
9818
9819/* 18.6 Calculation Chain */
9820function parse_cc_xml(data) {
9821 var d = [];
9822 if(!data) return d;
9823 var i = 1;
9824 (data.match(tagregex)||[]).forEach(function(x) {
9825 var y = parsexmltag(x);
9826 switch(y[0]) {
9827 case '<?xml': break;
9828 /* 18.6.2 calcChain CT_CalcChain 1 */
9829 case '<calcChain': case '<calcChain>': case '</calcChain>': break;
9830 /* 18.6.1 c CT_CalcCell 1 */
9831 case '<c': delete y[0]; if(y.i) i = y.i; else y.i = i; d.push(y); break;
9832 }
9833 });
9834 return d;
9835}
9836
9837//function write_cc_xml(data, opts) { }
9838
9839/* [MS-XLSB] 2.6.4.1 */
9840function parse_BrtCalcChainItem$(data) {
9841 var out = {};
9842 out.i = data.read_shift(4);
9843 var cell = {};
9844 cell.r = data.read_shift(4);
9845 cell.c = data.read_shift(4);
9846 out.r = encode_cell(cell);
9847 var flags = data.read_shift(1);
9848 if(flags & 0x2) out.l = '1';
9849 if(flags & 0x8) out.a = '1';
9850 return out;
9851}
9852
9853/* 18.6 Calculation Chain */
9854function parse_cc_bin(data, name, opts) {
9855 var out = [];
9856 var pass = false;
9857 recordhopper(data, function hopper_cc(val, R_n, RT) {
9858 switch(RT) {
9859 case 0x003F: /* 'BrtCalcChainItem$' */
9860 out.push(val); break;
9861
9862 default:
9863 if((R_n||"").indexOf("Begin") > 0){/* empty */}
9864 else if((R_n||"").indexOf("End") > 0){/* empty */}
9865 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
9866 }
9867 });
9868 return out;
9869}
9870
9871//function write_cc_bin(data, opts) { }
9872/* 18.14 Supplementary Workbook Data */
9873function parse_xlink_xml() {
9874 //var opts = _opts || {};
9875 //if(opts.WTF) throw "XLSX External Link";
9876}
9877
9878/* [MS-XLSB] 2.1.7.25 External Link */
9879function parse_xlink_bin(data, name, _opts) {
9880 if(!data) return data;
9881 var opts = _opts || {};
9882
9883 var pass = false, end = false;
9884
9885 recordhopper(data, function xlink_parse(val, R_n, RT) {
9886 if(end) return;
9887 switch(RT) {
9888 case 0x0167: /* 'BrtSupTabs' */
9889 case 0x016B: /* 'BrtExternTableStart' */
9890 case 0x016C: /* 'BrtExternTableEnd' */
9891 case 0x016E: /* 'BrtExternRowHdr' */
9892 case 0x016F: /* 'BrtExternCellBlank' */
9893 case 0x0170: /* 'BrtExternCellReal' */
9894 case 0x0171: /* 'BrtExternCellBool' */
9895 case 0x0172: /* 'BrtExternCellError' */
9896 case 0x0173: /* 'BrtExternCellString' */
9897 case 0x01D8: /* 'BrtExternValueMeta' */
9898 case 0x0241: /* 'BrtSupNameStart' */
9899 case 0x0242: /* 'BrtSupNameValueStart' */
9900 case 0x0243: /* 'BrtSupNameValueEnd' */
9901 case 0x0244: /* 'BrtSupNameNum' */
9902 case 0x0245: /* 'BrtSupNameErr' */
9903 case 0x0246: /* 'BrtSupNameSt' */
9904 case 0x0247: /* 'BrtSupNameNil' */
9905 case 0x0248: /* 'BrtSupNameBool' */
9906 case 0x0249: /* 'BrtSupNameFmla' */
9907 case 0x024A: /* 'BrtSupNameBits' */
9908 case 0x024B: /* 'BrtSupNameEnd' */
9909 break;
9910
9911 case 0x0023: /* 'BrtFRTBegin' */
9912 pass = true; break;
9913 case 0x0024: /* 'BrtFRTEnd' */
9914 pass = false; break;
9915
9916 default:
9917 if((R_n||"").indexOf("Begin") > 0){/* empty */}
9918 else if((R_n||"").indexOf("End") > 0){/* empty */}
9919 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
9920 }
9921 }, opts);
9922}
9923RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
9924RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
9925/* 20.5 DrawingML - SpreadsheetML Drawing */
9926function parse_drawing(data, rels) {
9927 if(!data) return "??";
9928 /*
9929 Chartsheet Drawing:
9930 - 20.5.2.35 wsDr CT_Drawing
9931 - 20.5.2.1 absoluteAnchor CT_AbsoluteAnchor
9932 - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
9933 - 20.1.2.2.16 graphic CT_GraphicalObject
9934 - 20.1.2.2.17 graphicData CT_GraphicalObjectData
9935 - chart reference
9936 the actual type is based on the URI of the graphicData
9937 TODO: handle embedded charts and other types of graphics
9938 */
9939 var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
9940
9941 return rels['!id'][id].Target;
9942}
9943
9944/* L.5.5.2 SpreadsheetML Comments + VML Schema */
9945var _shapeid = 1024;
9946function write_comments_vml(rId, comments) {
9947 var csize = [21600, 21600];
9948 /* L.5.2.1.2 Path Attribute */
9949 var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
9950 var o = [
9951 writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
9952 writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
9953 writextag("v:shapetype", [
9954 writextag("v:stroke", null, {joinstyle:"miter"}),
9955 writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
9956 ].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
9957 ];
9958 while(_shapeid < rId * 1000) _shapeid += 1000;
9959
9960 comments.forEach(function(x) { var c = decode_cell(x[0]);
9961 o = o.concat([
9962 '<v:shape' + wxt_helper({
9963 id:'_x0000_s' + (++_shapeid),
9964 type:"#_x0000_t202",
9965 style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
9966 fillcolor:"#ECFAD4",
9967 strokecolor:"#edeaa1"
9968 }) + '>',
9969 writextag('v:fill', writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}), {'color2':"#BEFF82", 'angle':"-180", 'type':"gradient"}),
9970 writextag("v:shadow", null, {on:"t", 'obscured':"t"}),
9971 writextag("v:path", null, {'o:connecttype':"none"}),
9972 '<v:textbox><div style="text-align:left"></div></v:textbox>',
9973 '<x:ClientData ObjectType="Note">',
9974 '<x:MoveWithCells/>',
9975 '<x:SizeWithCells/>',
9976 /* Part 4 19.4.2.3 Anchor (Anchor) */
9977 writetag('x:Anchor', [c.c, 0, c.r, 0, c.c+3, 100, c.r+5, 100].join(",")),
9978 writetag('x:AutoFill', "False"),
9979 writetag('x:Row', String(c.r)),
9980 writetag('x:Column', String(c.c)),
9981 x[1].hidden ? '' : '<x:Visible/>',
9982 '</x:ClientData>',
9983 '</v:shape>'
9984 ]); });
9985 o.push('</xml>');
9986 return o.join("");
9987}
9988
9989RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
9990
9991function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
9992 for(var i = 0; i != dirComments.length; ++i) {
9993 var canonicalpath=dirComments[i];
9994 var comments=parse_cmnt(getzipdata(zip, canonicalpath.replace(/^\//,''), true), canonicalpath, opts);
9995 if(!comments || !comments.length) continue;
9996 // find the sheets targeted by these comments
9997 var sheetNames = keys(sheets);
9998 for(var j = 0; j != sheetNames.length; ++j) {
9999 var sheetName = sheetNames[j];
10000 var rels = sheetRels[sheetName];
10001 if(rels) {
10002 var rel = rels[canonicalpath];
10003 if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
10004 }
10005 }
10006 }
10007}
10008
10009function insertCommentsIntoSheet(sheetName, sheet, comments) {
10010 var dense = Array.isArray(sheet);
10011 var cell;
10012 comments.forEach(function(comment) {
10013 var r = decode_cell(comment.ref);
10014 if(dense) {
10015 if(!sheet[r.r]) sheet[r.r] = [];
10016 cell = sheet[r.r][r.c];
10017 } else cell = sheet[comment.ref];
10018 if (!cell) {
10019 cell = {};
10020 if(dense) sheet[r.r][r.c] = cell;
10021 else sheet[comment.ref] = cell;
10022 var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
10023 if(range.s.r > r.r) range.s.r = r.r;
10024 if(range.e.r < r.r) range.e.r = r.r;
10025 if(range.s.c > r.c) range.s.c = r.c;
10026 if(range.e.c < r.c) range.e.c = r.c;
10027 var encoded = encode_range(range);
10028 if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
10029 }
10030
10031 if (!cell.c) cell.c = [];
10032 var o = ({a: comment.author, t: comment.t, r: comment.r});
10033 if(comment.h) o.h = comment.h;
10034 cell.c.push(o);
10035 });
10036}
10037
10038/* 18.7 Comments */
10039function parse_comments_xml(data, opts) {
10040 /* 18.7.6 CT_Comments */
10041 if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
10042 var authors = [];
10043 var commentList = [];
10044 var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
10045 if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
10046 if(x === "" || x.trim() === "") return;
10047 var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
10048 if(a) authors.push(a[1]);
10049 });
10050 var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
10051 if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
10052 if(x === "" || x.trim() === "") return;
10053 var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
10054 if(!cm) return;
10055 var y = parsexmltag(cm[0]);
10056 var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
10057 var cell = decode_cell(y.ref);
10058 if(opts.sheetRows && opts.sheetRows <= cell.r) return;
10059 var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
10060 var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
10061 comment.r = rt.r;
10062 if(rt.r == "<t></t>") rt.t = rt.h = "";
10063 comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
10064 if(opts.cellHTML) comment.h = rt.h;
10065 commentList.push(comment);
10066 });
10067 return commentList;
10068}
10069
10070var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
10071function write_comments_xml(data) {
10072 var o = [XML_HEADER, CMNT_XML_ROOT];
10073
10074 var iauthor = [];
10075 o.push("<authors>");
10076 data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
10077 if(iauthor.indexOf(a) > -1) return;
10078 iauthor.push(a);
10079 o.push("<author>" + a + "</author>");
10080 }); });
10081 o.push("</authors>");
10082 o.push("<commentList>");
10083 data.forEach(function(d) {
10084 d[1].forEach(function(c) {
10085 /* 18.7.3 CT_Comment */
10086 o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
10087 o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
10088 o.push('</text></comment>');
10089 });
10090 });
10091 o.push("</commentList>");
10092 if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
10093 return o.join("");
10094}
10095/* [MS-XLSB] 2.4.28 BrtBeginComment */
10096function parse_BrtBeginComment(data) {
10097 var out = {};
10098 out.iauthor = data.read_shift(4);
10099 var rfx = parse_UncheckedRfX(data, 16);
10100 out.rfx = rfx.s;
10101 out.ref = encode_cell(rfx.s);
10102 data.l += 16; /*var guid = parse_GUID(data); */
10103 return out;
10104}
10105function write_BrtBeginComment(data, o) {
10106 if(o == null) o = new_buf(36);
10107 o.write_shift(4, data[1].iauthor);
10108 write_UncheckedRfX((data[0]), o);
10109 o.write_shift(4, 0);
10110 o.write_shift(4, 0);
10111 o.write_shift(4, 0);
10112 o.write_shift(4, 0);
10113 return o;
10114}
10115
10116/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
10117var parse_BrtCommentAuthor = parse_XLWideString;
10118function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
10119
10120/* [MS-XLSB] 2.1.7.8 Comments */
10121function parse_comments_bin(data, opts) {
10122 var out = [];
10123 var authors = [];
10124 var c = {};
10125 var pass = false;
10126 recordhopper(data, function hopper_cmnt(val, R_n, RT) {
10127 switch(RT) {
10128 case 0x0278: /* 'BrtCommentAuthor' */
10129 authors.push(val); break;
10130 case 0x027B: /* 'BrtBeginComment' */
10131 c = val; break;
10132 case 0x027D: /* 'BrtCommentText' */
10133 c.t = val.t; c.h = val.h; c.r = val.r; break;
10134 case 0x027C: /* 'BrtEndComment' */
10135 c.author = authors[c.iauthor];
10136 delete c.iauthor;
10137 if(opts.sheetRows && opts.sheetRows <= c.rfx.r) break;
10138 if(!c.t) c.t = "";
10139 delete c.rfx; out.push(c); break;
10140
10141 case 0x0C00: /* 'BrtUid' */
10142 break;
10143
10144 case 0x0023: /* 'BrtFRTBegin' */
10145 pass = true; break;
10146 case 0x0024: /* 'BrtFRTEnd' */
10147 pass = false; break;
10148 case 0x0025: /* 'BrtACBegin' */ break;
10149 case 0x0026: /* 'BrtACEnd' */ break;
10150
10151
10152 default:
10153 if((R_n||"").indexOf("Begin") > 0){/* empty */}
10154 else if((R_n||"").indexOf("End") > 0){/* empty */}
10155 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
10156 }
10157 });
10158 return out;
10159}
10160
10161function write_comments_bin(data) {
10162 var ba = buf_array();
10163 var iauthor = [];
10164 write_record(ba, "BrtBeginComments");
10165
10166 write_record(ba, "BrtBeginCommentAuthors");
10167 data.forEach(function(comment) {
10168 comment[1].forEach(function(c) {
10169 if(iauthor.indexOf(c.a) > -1) return;
10170 iauthor.push(c.a.slice(0,54));
10171 write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a));
10172 });
10173 });
10174 write_record(ba, "BrtEndCommentAuthors");
10175
10176 write_record(ba, "BrtBeginCommentList");
10177 data.forEach(function(comment) {
10178 comment[1].forEach(function(c) {
10179 c.iauthor = iauthor.indexOf(c.a);
10180 var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
10181 write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c]));
10182 if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c));
10183 write_record(ba, "BrtEndComment");
10184 delete c.iauthor;
10185 });
10186 });
10187 write_record(ba, "BrtEndCommentList");
10188
10189 write_record(ba, "BrtEndComments");
10190 return ba.end();
10191}
10192var CT_VBA = "application/vnd.ms-office.vbaProject";
10193function make_vba_xls(cfb) {
10194 var newcfb = CFB.utils.cfb_new({root:"R"});
10195 cfb.FullPaths.forEach(function(p, i) {
10196 if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
10197 var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
10198 CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
10199 });
10200 return CFB.write(newcfb);
10201}
10202
10203function fill_vba_xls(cfb, vba) {
10204 vba.FullPaths.forEach(function(p, i) {
10205 if(i == 0) return;
10206 var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
10207 if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
10208 });
10209}
10210
10211var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
10212
10213RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
10214RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
10215
10216/* macro and dialog sheet stubs */
10217function parse_ds_bin() { return {'!type':'dialog'}; }
10218function parse_ds_xml() { return {'!type':'dialog'}; }
10219function parse_ms_bin() { return {'!type':'macro'}; }
10220function parse_ms_xml() { return {'!type':'macro'}; }
10221/* TODO: it will be useful to parse the function str */
10222var rc_to_a1 = (function(){
10223 var rcregex = /(^|[^A-Za-z])R(\[?)(-?\d+|)\]?C(\[?)(-?\d+|)\]?/g;
10224 var rcbase = ({r:0,c:0});
10225 function rcfunc($$,$1,$2,$3,$4,$5) {
10226 var R = $3.length>0?parseInt($3,10)|0:0, C = $5.length>0?parseInt($5,10)|0:0;
10227 if(C<0 && $4.length === 0) C=0;
10228 var cRel = false, rRel = false;
10229 if($4.length > 0 || $5.length == 0) cRel = true; if(cRel) C += rcbase.c; else --C;
10230 if($2.length > 0 || $3.length == 0) rRel = true; if(rRel) R += rcbase.r; else --R;
10231 return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
10232 }
10233 return function rc_to_a1(fstr, base) {
10234 rcbase = base;
10235 return fstr.replace(rcregex, rcfunc);
10236 };
10237})();
10238
10239var 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;
10240var a1_to_rc =(function(){
10241 return function a1_to_rc(fstr, base) {
10242 return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
10243 var c = decode_col($3) - ($2 ? 0 : base.c);
10244 var r = decode_row($5) - ($4 ? 0 : base.r);
10245 var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
10246 var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
10247 return $1 + "R" + R + "C" + C;
10248 });
10249 };
10250})();
10251
10252/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
10253function shift_formula_str(f, delta) {
10254 return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
10255 return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
10256 });
10257}
10258
10259function shift_formula_xlsx(f, range, cell) {
10260 var r = decode_range(range), s = r.s, c = decode_cell(cell);
10261 var delta = {r:c.r - s.r, c:c.c - s.c};
10262 return shift_formula_str(f, delta);
10263}
10264
10265/* TODO: parse formula */
10266function fuzzyfmla(f) {
10267 if(f.length == 1) return false;
10268 return true;
10269}
10270
10271function _xlfn(f) {
10272 return f.replace(/_xlfn\./g,"");
10273}
10274function parseread1(blob) { blob.l+=1; return; }
10275
10276/* [MS-XLS] 2.5.51 */
10277function parse_ColRelU(blob, length) {
10278 var c = blob.read_shift(length == 1 ? 1 : 2);
10279 return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
10280}
10281
10282/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.89 */
10283function parse_RgceArea(blob, length, opts) {
10284 var w = 2;
10285 if(opts) {
10286 if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts);
10287 else if(opts.biff == 12) w = 4;
10288 }
10289 var r=blob.read_shift(w), R=blob.read_shift(w);
10290 var c=parse_ColRelU(blob, 2);
10291 var C=parse_ColRelU(blob, 2);
10292 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]} };
10293}
10294/* BIFF 2-5 encodes flags in the row field */
10295function parse_RgceArea_BIFF2(blob) {
10296 var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
10297 var c=blob.read_shift(1);
10298 var C=blob.read_shift(1);
10299 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]} };
10300}
10301
10302/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.90 */
10303function parse_RgceAreaRel(blob, length, opts) {
10304 if(opts.biff < 8) return parse_RgceArea_BIFF2(blob, length, opts);
10305 var r=blob.read_shift(opts.biff == 12 ? 4 : 2), R=blob.read_shift(opts.biff == 12 ? 4 : 2);
10306 var c=parse_ColRelU(blob, 2);
10307 var C=parse_ColRelU(blob, 2);
10308 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]} };
10309}
10310
10311/* [MS-XLS] 2.5.198.109 ; [MS-XLSB] 2.5.97.91 */
10312function parse_RgceLoc(blob, length, opts) {
10313 if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts);
10314 var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2);
10315 var c = parse_ColRelU(blob, 2);
10316 return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
10317}
10318function parse_RgceLoc_BIFF2(blob) {
10319 var r = parse_ColRelU(blob, 2);
10320 var c = blob.read_shift(1);
10321 return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
10322}
10323
10324/* [MS-XLS] 2.5.198.107, 2.5.47 */
10325function parse_RgceElfLoc(blob) {
10326 var r = blob.read_shift(2);
10327 var c = blob.read_shift(2);
10328 return {r:r, c:c & 0xFF, fQuoted:!!(c & 0x4000), cRel:c>>15, rRel:c>>15 };
10329}
10330
10331/* [MS-XLS] 2.5.198.111 ; [MS-XLSB] 2.5.97.92 TODO */
10332function parse_RgceLocRel(blob, length, opts) {
10333 var biff = opts && opts.biff ? opts.biff : 8;
10334 if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts);
10335 var r = blob.read_shift(biff >= 12 ? 4 : 2);
10336 var cl = blob.read_shift(2);
10337 var cRel = (cl & 0x4000) >> 14, rRel = (cl & 0x8000) >> 15;
10338 cl &= 0x3FFF;
10339 if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000;
10340 if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000;
10341 return {r:r,c:cl,cRel:cRel,rRel:rRel};
10342}
10343function parse_RgceLocRel_BIFF2(blob) {
10344 var rl = blob.read_shift(2);
10345 var c = blob.read_shift(1);
10346 var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14;
10347 rl &= 0x3FFF;
10348 if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000;
10349 if(cRel == 1 && c >= 0x80) c = c - 0x100;
10350 return {r:rl,c:c,cRel:cRel,rRel:rRel};
10351}
10352
10353/* [MS-XLS] 2.5.198.27 ; [MS-XLSB] 2.5.97.18 */
10354function parse_PtgArea(blob, length, opts) {
10355 var type = (blob[blob.l++] & 0x60) >> 5;
10356 var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
10357 return [type, area];
10358}
10359
10360/* [MS-XLS] 2.5.198.28 ; [MS-XLSB] 2.5.97.19 */
10361function parse_PtgArea3d(blob, length, opts) {
10362 var type = (blob[blob.l++] & 0x60) >> 5;
10363 var ixti = blob.read_shift(2, 'i');
10364 var w = 8;
10365 if(opts) switch(opts.biff) {
10366 case 5: blob.l += 12; w = 6; break;
10367 case 12: w = 12; break;
10368 }
10369 var area = parse_RgceArea(blob, w, opts);
10370 return [type, ixti, area];
10371}
10372
10373/* [MS-XLS] 2.5.198.29 ; [MS-XLSB] 2.5.97.20 */
10374function parse_PtgAreaErr(blob, length, opts) {
10375 var type = (blob[blob.l++] & 0x60) >> 5;
10376 blob.l += opts && (opts.biff > 8) ? 12 : (opts.biff < 8 ? 6 : 8);
10377 return [type];
10378}
10379/* [MS-XLS] 2.5.198.30 ; [MS-XLSB] 2.5.97.21 */
10380function parse_PtgAreaErr3d(blob, length, opts) {
10381 var type = (blob[blob.l++] & 0x60) >> 5;
10382 var ixti = blob.read_shift(2);
10383 var w = 8;
10384 if(opts) switch(opts.biff) {
10385 case 5: blob.l += 12; w = 6; break;
10386 case 12: w = 12; break;
10387 }
10388 blob.l += w;
10389 return [type, ixti];
10390}
10391
10392/* [MS-XLS] 2.5.198.31 ; [MS-XLSB] 2.5.97.22 */
10393function parse_PtgAreaN(blob, length, opts) {
10394 var type = (blob[blob.l++] & 0x60) >> 5;
10395 var area = parse_RgceAreaRel(blob, length - 1, opts);
10396 return [type, area];
10397}
10398
10399/* [MS-XLS] 2.5.198.32 ; [MS-XLSB] 2.5.97.23 */
10400function parse_PtgArray(blob, length, opts) {
10401 var type = (blob[blob.l++] & 0x60) >> 5;
10402 blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
10403 return [type];
10404}
10405
10406/* [MS-XLS] 2.5.198.33 ; [MS-XLSB] 2.5.97.24 */
10407function parse_PtgAttrBaxcel(blob) {
10408 var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
10409 var bitBaxcel = 1;
10410 blob.l += 4;
10411 return [bitSemi, bitBaxcel];
10412}
10413
10414/* [MS-XLS] 2.5.198.34 ; [MS-XLSB] 2.5.97.25 */
10415function parse_PtgAttrChoose(blob, length, opts) {
10416 blob.l +=2;
10417 var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10418 var o = [];
10419 /* offset is 1 less than the number of elements */
10420 for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2));
10421 return o;
10422}
10423
10424/* [MS-XLS] 2.5.198.35 ; [MS-XLSB] 2.5.97.26 */
10425function parse_PtgAttrGoto(blob, length, opts) {
10426 var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10427 blob.l += 2;
10428 return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
10429}
10430
10431/* [MS-XLS] 2.5.198.36 ; [MS-XLSB] 2.5.97.27 */
10432function parse_PtgAttrIf(blob, length, opts) {
10433 var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10434 blob.l += 2;
10435 return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
10436}
10437
10438/* [MS-XLSB] 2.5.97.28 */
10439function parse_PtgAttrIfError(blob) {
10440 var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10441 blob.l += 2;
10442 return [bitIf, blob.read_shift(2)];
10443}
10444
10445/* [MS-XLS] 2.5.198.37 ; [MS-XLSB] 2.5.97.29 */
10446function parse_PtgAttrSemi(blob, length, opts) {
10447 var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10448 blob.l += opts && opts.biff == 2 ? 3 : 4;
10449 return [bitSemi];
10450}
10451
10452/* [MS-XLS] 2.5.198.40 ; [MS-XLSB] 2.5.97.32 */
10453function parse_PtgAttrSpaceType(blob) {
10454 var type = blob.read_shift(1), cch = blob.read_shift(1);
10455 return [type, cch];
10456}
10457
10458/* [MS-XLS] 2.5.198.38 ; [MS-XLSB] 2.5.97.30 */
10459function parse_PtgAttrSpace(blob) {
10460 blob.read_shift(2);
10461 return parse_PtgAttrSpaceType(blob, 2);
10462}
10463
10464/* [MS-XLS] 2.5.198.39 ; [MS-XLSB] 2.5.97.31 */
10465function parse_PtgAttrSpaceSemi(blob) {
10466 blob.read_shift(2);
10467 return parse_PtgAttrSpaceType(blob, 2);
10468}
10469
10470/* [MS-XLS] 2.5.198.84 ; [MS-XLSB] 2.5.97.68 TODO */
10471function parse_PtgRef(blob, length, opts) {
10472 //var ptg = blob[blob.l] & 0x1F;
10473 var type = (blob[blob.l] & 0x60)>>5;
10474 blob.l += 1;
10475 var loc = parse_RgceLoc(blob, 0, opts);
10476 return [type, loc];
10477}
10478
10479/* [MS-XLS] 2.5.198.88 ; [MS-XLSB] 2.5.97.72 TODO */
10480function parse_PtgRefN(blob, length, opts) {
10481 var type = (blob[blob.l] & 0x60)>>5;
10482 blob.l += 1;
10483 var loc = parse_RgceLocRel(blob, 0, opts);
10484 return [type, loc];
10485}
10486
10487/* [MS-XLS] 2.5.198.85 ; [MS-XLSB] 2.5.97.69 TODO */
10488function parse_PtgRef3d(blob, length, opts) {
10489 var type = (blob[blob.l] & 0x60)>>5;
10490 blob.l += 1;
10491 var ixti = blob.read_shift(2); // XtiIndex
10492 if(opts && opts.biff == 5) blob.l += 12;
10493 var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
10494 return [type, ixti, loc];
10495}
10496
10497
10498/* [MS-XLS] 2.5.198.62 ; [MS-XLSB] 2.5.97.45 TODO */
10499function parse_PtgFunc(blob, length, opts) {
10500 //var ptg = blob[blob.l] & 0x1F;
10501 var type = (blob[blob.l] & 0x60)>>5;
10502 blob.l += 1;
10503 var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
10504 return [FtabArgc[iftab], Ftab[iftab], type];
10505}
10506/* [MS-XLS] 2.5.198.63 ; [MS-XLSB] 2.5.97.46 TODO */
10507function parse_PtgFuncVar(blob, length, opts) {
10508 var type = blob[blob.l++];
10509 var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [(type == 0x58 ? -1 : 0), blob.read_shift(1)]: parsetab(blob);
10510 return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
10511}
10512
10513function parsetab(blob) {
10514 return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
10515}
10516
10517/* [MS-XLS] 2.5.198.41 ; [MS-XLSB] 2.5.97.33 */
10518function parse_PtgAttrSum(blob, length, opts) {
10519 blob.l += opts && opts.biff == 2 ? 3 : 4; return;
10520}
10521
10522/* [MS-XLS] 2.5.198.58 ; [MS-XLSB] 2.5.97.40 */
10523function parse_PtgExp(blob, length, opts) {
10524 blob.l++;
10525 if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
10526 var row = blob.read_shift(2);
10527 var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10528 return [row, col];
10529}
10530
10531/* [MS-XLS] 2.5.198.57 ; [MS-XLSB] 2.5.97.39 */
10532function parse_PtgErr(blob) { blob.l++; return BErr[blob.read_shift(1)]; }
10533
10534/* [MS-XLS] 2.5.198.66 ; [MS-XLSB] 2.5.97.49 */
10535function parse_PtgInt(blob) { blob.l++; return blob.read_shift(2); }
10536
10537/* [MS-XLS] 2.5.198.42 ; [MS-XLSB] 2.5.97.34 */
10538function parse_PtgBool(blob) { blob.l++; return blob.read_shift(1)!==0;}
10539
10540/* [MS-XLS] 2.5.198.79 ; [MS-XLSB] 2.5.97.63 */
10541function parse_PtgNum(blob) { blob.l++; return parse_Xnum(blob, 8); }
10542
10543/* [MS-XLS] 2.5.198.89 ; [MS-XLSB] 2.5.97.74 */
10544function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
10545
10546/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
10547/* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */
10548function parse_SerAr(blob, biff) {
10549 var val = [blob.read_shift(1)];
10550 if(biff == 12) switch(val[0]) {
10551 case 0x02: val[0] = 0x04; break; /* SerBool */
10552 case 0x04: val[0] = 0x10; break; /* SerErr */
10553 case 0x00: val[0] = 0x01; break; /* SerNum */
10554 case 0x01: val[0] = 0x02; break; /* SerStr */
10555 }
10556 switch(val[0]) {
10557 case 0x04: /* SerBool -- boolean */
10558 val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
10559 if(biff != 12) blob.l += 7; break;
10560 case 0x25: /* appears to be an alias */
10561 case 0x10: /* SerErr -- error */
10562 val[1] = BErr[blob[blob.l]];
10563 blob.l += ((biff == 12) ? 4 : 8); break;
10564 case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
10565 blob.l += 8; break;
10566 case 0x01: /* SerNum -- Xnum */
10567 val[1] = parse_Xnum(blob, 8); break;
10568 case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
10569 val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
10570 default: throw new Error("Bad SerAr: " + val[0]); /* Unreachable */
10571 }
10572 return val;
10573}
10574
10575/* [MS-XLS] 2.5.198.61 ; [MS-XLSB] 2.5.97.44 */
10576function parse_PtgExtraMem(blob, cce, opts) {
10577 var count = blob.read_shift((opts.biff == 12) ? 4 : 2);
10578 var out = [];
10579 for(var i = 0; i != count; ++i) out.push(((opts.biff == 12) ? parse_UncheckedRfX : parse_Ref8U)(blob, 8));
10580 return out;
10581}
10582
10583/* [MS-XLS] 2.5.198.59 ; [MS-XLSB] 2.5.97.41 */
10584function parse_PtgExtraArray(blob, length, opts) {
10585 var rows = 0, cols = 0;
10586 if(opts.biff == 12) {
10587 rows = blob.read_shift(4); // DRw
10588 cols = blob.read_shift(4); // DCol
10589 } else {
10590 cols = 1 + blob.read_shift(1); //DColByteU
10591 rows = 1 + blob.read_shift(2); //DRw
10592 }
10593 if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; }
10594 // $FlowIgnore
10595 for(var i = 0, o = []; i != rows && (o[i] = []); ++i)
10596 for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff);
10597 return o;
10598}
10599
10600/* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 */
10601function parse_PtgName(blob, length, opts) {
10602 var type = (blob.read_shift(1) >>> 5) & 0x03;
10603 var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
10604 var nameindex = blob.read_shift(w);
10605 switch(opts.biff) {
10606 case 2: blob.l += 5; break;
10607 case 3: case 4: blob.l += 8; break;
10608 case 5: blob.l += 12; break;
10609 }
10610 return [type, 0, nameindex];
10611}
10612
10613/* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 */
10614function parse_PtgNameX(blob, length, opts) {
10615 if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts);
10616 var type = (blob.read_shift(1) >>> 5) & 0x03;
10617 var ixti = blob.read_shift(2); // XtiIndex
10618 var nameindex = blob.read_shift(4);
10619 return [type, ixti, nameindex];
10620}
10621function parse_PtgNameX_BIFF5(blob) {
10622 var type = (blob.read_shift(1) >>> 5) & 0x03;
10623 var ixti = blob.read_shift(2, 'i'); // XtiIndex
10624 blob.l += 8;
10625 var nameindex = blob.read_shift(2);
10626 blob.l += 12;
10627 return [type, ixti, nameindex];
10628}
10629
10630/* [MS-XLS] 2.5.198.70 ; [MS-XLSB] 2.5.97.54 */
10631function parse_PtgMemArea(blob, length, opts) {
10632 var type = (blob.read_shift(1) >>> 5) & 0x03;
10633 blob.l += (opts && opts.biff == 2 ? 3 : 4);
10634 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10635 return [type, cce];
10636}
10637
10638/* [MS-XLS] 2.5.198.72 ; [MS-XLSB] 2.5.97.56 */
10639function parse_PtgMemFunc(blob, length, opts) {
10640 var type = (blob.read_shift(1) >>> 5) & 0x03;
10641 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10642 return [type, cce];
10643}
10644
10645
10646/* [MS-XLS] 2.5.198.86 ; [MS-XLSB] 2.5.97.69 */
10647function parse_PtgRefErr(blob, length, opts) {
10648 var type = (blob.read_shift(1) >>> 5) & 0x03;
10649 blob.l += 4;
10650 if(opts.biff < 8) blob.l--;
10651 if(opts.biff == 12) blob.l += 2;
10652 return [type];
10653}
10654
10655/* [MS-XLS] 2.5.198.87 ; [MS-XLSB] 2.5.97.71 */
10656function parse_PtgRefErr3d(blob, length, opts) {
10657 var type = (blob[blob.l++] & 0x60) >> 5;
10658 var ixti = blob.read_shift(2);
10659 var w = 4;
10660 if(opts) switch(opts.biff) {
10661 case 5: w = 15; break;
10662 case 12: w = 6; break;
10663 }
10664 blob.l += w;
10665 return [type, ixti];
10666}
10667
10668/* [MS-XLS] 2.5.198.71 ; [MS-XLSB] 2.5.97.55 */
10669var parse_PtgMemErr = parsenoop;
10670/* [MS-XLS] 2.5.198.73 ; [MS-XLSB] 2.5.97.57 */
10671var parse_PtgMemNoMem = parsenoop;
10672/* [MS-XLS] 2.5.198.92 */
10673var parse_PtgTbl = parsenoop;
10674
10675function parse_PtgElfLoc(blob, length, opts) {
10676 blob.l += 2;
10677 return [parse_RgceElfLoc(blob, 4, opts)];
10678}
10679function parse_PtgElfNoop(blob) {
10680 blob.l += 6;
10681 return [];
10682}
10683/* [MS-XLS] 2.5.198.46 */
10684var parse_PtgElfCol = parse_PtgElfLoc;
10685/* [MS-XLS] 2.5.198.47 */
10686var parse_PtgElfColS = parse_PtgElfNoop;
10687/* [MS-XLS] 2.5.198.48 */
10688var parse_PtgElfColSV = parse_PtgElfNoop;
10689/* [MS-XLS] 2.5.198.49 */
10690var parse_PtgElfColV = parse_PtgElfLoc;
10691/* [MS-XLS] 2.5.198.50 */
10692function parse_PtgElfLel(blob) {
10693 blob.l += 2;
10694 return [parseuint16(blob), blob.read_shift(2) & 0x01];
10695}
10696/* [MS-XLS] 2.5.198.51 */
10697var parse_PtgElfRadical = parse_PtgElfLoc;
10698/* [MS-XLS] 2.5.198.52 */
10699var parse_PtgElfRadicalLel = parse_PtgElfLel;
10700/* [MS-XLS] 2.5.198.53 */
10701var parse_PtgElfRadicalS = parse_PtgElfNoop;
10702/* [MS-XLS] 2.5.198.54 */
10703var parse_PtgElfRw = parse_PtgElfLoc;
10704/* [MS-XLS] 2.5.198.55 */
10705var parse_PtgElfRwV = parse_PtgElfLoc;
10706
10707/* [MS-XLSB] 2.5.97.52 TODO */
10708var PtgListRT = [
10709 "Data",
10710 "All",
10711 "Headers",
10712 "??",
10713 "?Data2",
10714 "??",
10715 "?DataHeaders",
10716 "??",
10717 "Totals",
10718 "??",
10719 "??",
10720 "??",
10721 "?DataTotals",
10722 "??",
10723 "??",
10724 "??",
10725 "?Current"
10726];
10727function parse_PtgList(blob) {
10728 blob.l += 2;
10729 var ixti = blob.read_shift(2);
10730 var flags = blob.read_shift(2);
10731 var idx = blob.read_shift(4);
10732 var c = blob.read_shift(2);
10733 var C = blob.read_shift(2);
10734 var rt = PtgListRT[(flags >> 2) & 0x1F];
10735 return {ixti: ixti, coltype:(flags&0x3), rt:rt, idx:idx, c:c, C:C};
10736}
10737/* [MS-XLS] 2.5.198.91 ; [MS-XLSB] 2.5.97.76 */
10738function parse_PtgSxName(blob) {
10739 blob.l += 2;
10740 return [blob.read_shift(4)];
10741}
10742
10743/* [XLS] old spec */
10744function parse_PtgSheet(blob, length, opts) {
10745 blob.l += 5;
10746 blob.l += 2;
10747 blob.l += (opts.biff == 2 ? 1 : 4);
10748 return ["PTGSHEET"];
10749}
10750function parse_PtgEndSheet(blob, length, opts) {
10751 blob.l += (opts.biff == 2 ? 4 : 5);
10752 return ["PTGENDSHEET"];
10753}
10754function parse_PtgMemAreaN(blob) {
10755 var type = (blob.read_shift(1) >>> 5) & 0x03;
10756 var cce = blob.read_shift(2);
10757 return [type, cce];
10758}
10759function parse_PtgMemNoMemN(blob) {
10760 var type = (blob.read_shift(1) >>> 5) & 0x03;
10761 var cce = blob.read_shift(2);
10762 return [type, cce];
10763}
10764function parse_PtgAttrNoop(blob) {
10765 blob.l += 4;
10766 return [0, 0];
10767}
10768
10769/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
10770var PtgTypes = {
107710x01: { n:'PtgExp', f:parse_PtgExp },
107720x02: { n:'PtgTbl', f:parse_PtgTbl },
107730x03: { n:'PtgAdd', f:parseread1 },
107740x04: { n:'PtgSub', f:parseread1 },
107750x05: { n:'PtgMul', f:parseread1 },
107760x06: { n:'PtgDiv', f:parseread1 },
107770x07: { n:'PtgPower', f:parseread1 },
107780x08: { n:'PtgConcat', f:parseread1 },
107790x09: { n:'PtgLt', f:parseread1 },
107800x0A: { n:'PtgLe', f:parseread1 },
107810x0B: { n:'PtgEq', f:parseread1 },
107820x0C: { n:'PtgGe', f:parseread1 },
107830x0D: { n:'PtgGt', f:parseread1 },
107840x0E: { n:'PtgNe', f:parseread1 },
107850x0F: { n:'PtgIsect', f:parseread1 },
107860x10: { n:'PtgUnion', f:parseread1 },
107870x11: { n:'PtgRange', f:parseread1 },
107880x12: { n:'PtgUplus', f:parseread1 },
107890x13: { n:'PtgUminus', f:parseread1 },
107900x14: { n:'PtgPercent', f:parseread1 },
107910x15: { n:'PtgParen', f:parseread1 },
107920x16: { n:'PtgMissArg', f:parseread1 },
107930x17: { n:'PtgStr', f:parse_PtgStr },
107940x1A: { n:'PtgSheet', f:parse_PtgSheet },
107950x1B: { n:'PtgEndSheet', f:parse_PtgEndSheet },
107960x1C: { n:'PtgErr', f:parse_PtgErr },
107970x1D: { n:'PtgBool', f:parse_PtgBool },
107980x1E: { n:'PtgInt', f:parse_PtgInt },
107990x1F: { n:'PtgNum', f:parse_PtgNum },
108000x20: { n:'PtgArray', f:parse_PtgArray },
108010x21: { n:'PtgFunc', f:parse_PtgFunc },
108020x22: { n:'PtgFuncVar', f:parse_PtgFuncVar },
108030x23: { n:'PtgName', f:parse_PtgName },
108040x24: { n:'PtgRef', f:parse_PtgRef },
108050x25: { n:'PtgArea', f:parse_PtgArea },
108060x26: { n:'PtgMemArea', f:parse_PtgMemArea },
108070x27: { n:'PtgMemErr', f:parse_PtgMemErr },
108080x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
108090x29: { n:'PtgMemFunc', f:parse_PtgMemFunc },
108100x2A: { n:'PtgRefErr', f:parse_PtgRefErr },
108110x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr },
108120x2C: { n:'PtgRefN', f:parse_PtgRefN },
108130x2D: { n:'PtgAreaN', f:parse_PtgAreaN },
108140x2E: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
108150x2F: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
108160x39: { n:'PtgNameX', f:parse_PtgNameX },
108170x3A: { n:'PtgRef3d', f:parse_PtgRef3d },
108180x3B: { n:'PtgArea3d', f:parse_PtgArea3d },
108190x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
108200x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
108210xFF: {}
10822};
10823/* These are duplicated in the PtgTypes table */
10824var PtgDupes = {
108250x40: 0x20, 0x60: 0x20,
108260x41: 0x21, 0x61: 0x21,
108270x42: 0x22, 0x62: 0x22,
108280x43: 0x23, 0x63: 0x23,
108290x44: 0x24, 0x64: 0x24,
108300x45: 0x25, 0x65: 0x25,
108310x46: 0x26, 0x66: 0x26,
108320x47: 0x27, 0x67: 0x27,
108330x48: 0x28, 0x68: 0x28,
108340x49: 0x29, 0x69: 0x29,
108350x4A: 0x2A, 0x6A: 0x2A,
108360x4B: 0x2B, 0x6B: 0x2B,
108370x4C: 0x2C, 0x6C: 0x2C,
108380x4D: 0x2D, 0x6D: 0x2D,
108390x4E: 0x2E, 0x6E: 0x2E,
108400x4F: 0x2F, 0x6F: 0x2F,
108410x58: 0x22, 0x78: 0x22,
108420x59: 0x39, 0x79: 0x39,
108430x5A: 0x3A, 0x7A: 0x3A,
108440x5B: 0x3B, 0x7B: 0x3B,
108450x5C: 0x3C, 0x7C: 0x3C,
108460x5D: 0x3D, 0x7D: 0x3D
10847};
10848(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
10849
10850var Ptg18 = {
108510x01: { n:'PtgElfLel', f:parse_PtgElfLel },
108520x02: { n:'PtgElfRw', f:parse_PtgElfRw },
108530x03: { n:'PtgElfCol', f:parse_PtgElfCol },
108540x06: { n:'PtgElfRwV', f:parse_PtgElfRwV },
108550x07: { n:'PtgElfColV', f:parse_PtgElfColV },
108560x0A: { n:'PtgElfRadical', f:parse_PtgElfRadical },
108570x0B: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
108580x0D: { n:'PtgElfColS', f:parse_PtgElfColS },
108590x0F: { n:'PtgElfColSV', f:parse_PtgElfColSV },
108600x10: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
108610x19: { n:'PtgList', f:parse_PtgList },
108620x1D: { n:'PtgSxName', f:parse_PtgSxName },
108630xFF: {}
10864};
10865var Ptg19 = {
108660x00: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
108670x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
108680x02: { n:'PtgAttrIf', f:parse_PtgAttrIf },
108690x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
108700x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
108710x10: { n:'PtgAttrSum', f:parse_PtgAttrSum },
108720x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
108730x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
108740x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
108750x80: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
108760xFF: {}
10877};
10878Ptg19[0x21] = Ptg19[0x20];
10879
10880/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
10881function parse_RgbExtra(blob, length, rgce, opts) {
10882 if(opts.biff < 8) return parsenoop(blob, length);
10883 var target = blob.l + length;
10884 var o = [];
10885 for(var i = 0; i !== rgce.length; ++i) {
10886 switch(rgce[i][0]) {
10887 case 'PtgArray': /* PtgArray -> PtgExtraArray */
10888 rgce[i][1] = parse_PtgExtraArray(blob, 0, opts);
10889 o.push(rgce[i][1]);
10890 break;
10891 case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
10892 rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1], opts);
10893 o.push(rgce[i][2]);
10894 break;
10895 case 'PtgExp': /* PtgExp -> PtgExtraCol */
10896 if(opts && opts.biff == 12) {
10897 rgce[i][1][1] = blob.read_shift(4);
10898 o.push(rgce[i][1]);
10899 } break;
10900 case 'PtgList': /* TODO: PtgList -> PtgExtraList */
10901 case 'PtgElfRadicalS': /* TODO: PtgElfRadicalS -> PtgExtraElf */
10902 case 'PtgElfColS': /* TODO: PtgElfColS -> PtgExtraElf */
10903 case 'PtgElfColSV': /* TODO: PtgElfColSV -> PtgExtraElf */
10904 throw "Unsupported " + rgce[i][0];
10905 default: break;
10906 }
10907 }
10908 length = target - blob.l;
10909 /* note: this is technically an error but Excel disregards */
10910 //if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
10911 if(length !== 0) o.push(parsenoop(blob, length));
10912 return o;
10913}
10914
10915/* [MS-XLS] 2.5.198.104 ; [MS-XLSB] 2.5.97.88 */
10916function parse_Rgce(blob, length, opts) {
10917 var target = blob.l + length;
10918 var R, id, ptgs = [];
10919 while(target != blob.l) {
10920 length = target - blob.l;
10921 id = blob[blob.l];
10922 R = PtgTypes[id];
10923 if(id === 0x18 || id === 0x19) R = (id === 0x18 ? Ptg18 : Ptg19)[blob[blob.l + 1]];
10924 if(!R || !R.f) { /*ptgs.push*/(parsenoop(blob, length)); }
10925 else { ptgs.push([R.n, R.f(blob, length, opts)]); }
10926 }
10927 return ptgs;
10928}
10929
10930function stringify_array(f) {
10931 var o = [];
10932 for(var i = 0; i < f.length; ++i) {
10933 var x = f[i], r = [];
10934 for(var j = 0; j < x.length; ++j) {
10935 var y = x[j];
10936 if(y) switch(y[0]) {
10937 // TODO: handle embedded quotes
10938 case 0x02:
10939r.push('"' + y[1].replace(/"/g,'""') + '"'); break;
10940 default: r.push(y[1]);
10941 } else r.push("");
10942 }
10943 o.push(r.join(","));
10944 }
10945 return o.join(";");
10946}
10947
10948/* [MS-XLS] 2.2.2 ; [MS-XLSB] 2.2.2 TODO */
10949var PtgBinOp = {
10950 PtgAdd: "+",
10951 PtgConcat: "&",
10952 PtgDiv: "/",
10953 PtgEq: "=",
10954 PtgGe: ">=",
10955 PtgGt: ">",
10956 PtgLe: "<=",
10957 PtgLt: "<",
10958 PtgMul: "*",
10959 PtgNe: "<>",
10960 PtgPower: "^",
10961 PtgSub: "-"
10962};
10963function formula_quote_sheet_name(sname, opts) {
10964 if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name");
10965 if(sname.indexOf(" ") > -1) return "'" + sname + "'";
10966 return sname;
10967}
10968function get_ixti_raw(supbooks, ixti, opts) {
10969 if(!supbooks) return "SH33TJSERR0";
10970 if(opts.biff > 8 && (!supbooks.XTI || !supbooks.XTI[ixti])) return supbooks.SheetNames[ixti];
10971 if(!supbooks.XTI) return "SH33TJSERR6";
10972 var XTI = supbooks.XTI[ixti];
10973 if(opts.biff < 8) {
10974 if(ixti > 10000) ixti-= 65536;
10975 if(ixti < 0) ixti = -ixti;
10976 return ixti == 0 ? "" : supbooks.XTI[ixti - 1];
10977 }
10978 if(!XTI) return "SH33TJSERR1";
10979 var o = "";
10980 if(opts.biff > 8) switch(supbooks[XTI[0]][0]) {
10981 case 0x0165: /* 'BrtSupSelf' */
10982 o = XTI[1] == -1 ? "#REF" : supbooks.SheetNames[XTI[1]];
10983 return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
10984 case 0x0166: /* 'BrtSupSame' */
10985 if(opts.SID != null) return supbooks.SheetNames[opts.SID];
10986 return "SH33TJSSAME" + supbooks[XTI[0]][0];
10987 case 0x0163: /* 'BrtSupBookSrc' */
10988 /* falls through */
10989 default: return "SH33TJSSRC" + supbooks[XTI[0]][0];
10990 }
10991 switch(supbooks[XTI[0]][0][0]) {
10992 case 0x0401:
10993 o = XTI[1] == -1 ? "#REF" : (supbooks.SheetNames[XTI[1]] || "SH33TJSERR3");
10994 return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
10995 case 0x3A01: return "SH33TJSERR8";
10996 default:
10997 if(!supbooks[XTI[0]][0][3]) return "SH33TJSERR2";
10998 o = XTI[1] == -1 ? "#REF" : (supbooks[XTI[0]][0][3][XTI[1]] || "SH33TJSERR4");
10999 return XTI[1] == XTI[2] ? o : o + ":" + supbooks[XTI[0]][0][3][XTI[2]];
11000 }
11001}
11002function get_ixti(supbooks, ixti, opts) {
11003 return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts), opts);
11004}
11005function stringify_formula(formula/*Array<any>*/, range, cell, supbooks, opts) {
11006 var biff = (opts && opts.biff) || 8;
11007 var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
11008 var stack = [], e1, e2, c, ixti=0, nameidx=0, r, sname="";
11009 if(!formula[0] || !formula[0][0]) return "";
11010 var last_sp = -1, sp = "";
11011 for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
11012 var f = formula[0][ff];
11013 switch(f[0]) {
11014 case 'PtgUminus': /* [MS-XLS] 2.5.198.93 */
11015 stack.push("-" + stack.pop()); break;
11016 case 'PtgUplus': /* [MS-XLS] 2.5.198.95 */
11017 stack.push("+" + stack.pop()); break;
11018 case 'PtgPercent': /* [MS-XLS] 2.5.198.81 */
11019 stack.push(stack.pop() + "%"); break;
11020
11021 case 'PtgAdd': /* [MS-XLS] 2.5.198.26 */
11022 case 'PtgConcat': /* [MS-XLS] 2.5.198.43 */
11023 case 'PtgDiv': /* [MS-XLS] 2.5.198.45 */
11024 case 'PtgEq': /* [MS-XLS] 2.5.198.56 */
11025 case 'PtgGe': /* [MS-XLS] 2.5.198.64 */
11026 case 'PtgGt': /* [MS-XLS] 2.5.198.65 */
11027 case 'PtgLe': /* [MS-XLS] 2.5.198.68 */
11028 case 'PtgLt': /* [MS-XLS] 2.5.198.69 */
11029 case 'PtgMul': /* [MS-XLS] 2.5.198.75 */
11030 case 'PtgNe': /* [MS-XLS] 2.5.198.78 */
11031 case 'PtgPower': /* [MS-XLS] 2.5.198.82 */
11032 case 'PtgSub': /* [MS-XLS] 2.5.198.90 */
11033 e1 = stack.pop(); e2 = stack.pop();
11034 if(last_sp >= 0) {
11035 switch(formula[0][last_sp][1][0]) {
11036 case 0:
11037 // $FlowIgnore
11038 sp = fill(" ", formula[0][last_sp][1][1]); break;
11039 case 1:
11040 // $FlowIgnore
11041 sp = fill("\r", formula[0][last_sp][1][1]); break;
11042 default:
11043 sp = "";
11044 // $FlowIgnore
11045 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
11046 }
11047 e2 = e2 + sp;
11048 last_sp = -1;
11049 }
11050 stack.push(e2+PtgBinOp[f[0]]+e1);
11051 break;
11052
11053 case 'PtgIsect': /* [MS-XLS] 2.5.198.67 */
11054 e1 = stack.pop(); e2 = stack.pop();
11055 stack.push(e2+" "+e1);
11056 break;
11057 case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
11058 e1 = stack.pop(); e2 = stack.pop();
11059 stack.push(e2+","+e1);
11060 break;
11061 case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
11062 e1 = stack.pop(); e2 = stack.pop();
11063 stack.push(e2+":"+e1);
11064 break;
11065
11066 case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */
11067 break;
11068 case 'PtgAttrGoto': /* [MS-XLS] 2.5.198.35 */
11069 break;
11070 case 'PtgAttrIf': /* [MS-XLS] 2.5.198.36 */
11071 break;
11072 case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
11073 break;
11074
11075
11076 case 'PtgRef': /* [MS-XLS] 2.5.198.84 */
11077c = shift_cell_xls((f[1][1]), _range, opts);
11078 stack.push(encode_cell_xls(c, biff));
11079 break;
11080 case 'PtgRefN': /* [MS-XLS] 2.5.198.88 */
11081c = cell ? shift_cell_xls((f[1][1]), cell, opts) : (f[1][1]);
11082 stack.push(encode_cell_xls(c, biff));
11083 break;
11084 case 'PtgRef3d': /* [MS-XLS] 2.5.198.85 */
11085ixti = f[1][1]; c = shift_cell_xls((f[1][2]), _range, opts);
11086 sname = get_ixti(supbooks, ixti, opts);
11087 var w = sname; /* IE9 fails on defined names */ // eslint-disable-line no-unused-vars
11088 stack.push(sname + "!" + encode_cell_xls(c, biff));
11089 break;
11090
11091 case 'PtgFunc': /* [MS-XLS] 2.5.198.62 */
11092 case 'PtgFuncVar': /* [MS-XLS] 2.5.198.63 */
11093 /* f[1] = [argc, func, type] */
11094 var argc = (f[1][0]), func = (f[1][1]);
11095 if(!argc) argc = 0;
11096 argc &= 0x7F;
11097 var args = argc == 0 ? [] : stack.slice(-argc);
11098 stack.length -= argc;
11099 if(func === 'User') func = args.shift();
11100 stack.push(func + "(" + args.join(",") + ")");
11101 break;
11102
11103 case 'PtgBool': /* [MS-XLS] 2.5.198.42 */
11104 stack.push(f[1] ? "TRUE" : "FALSE"); break;
11105 case 'PtgInt': /* [MS-XLS] 2.5.198.66 */
11106 stack.push(f[1]); break;
11107 case 'PtgNum': /* [MS-XLS] 2.5.198.79 TODO: precision? */
11108 stack.push(String(f[1])); break;
11109 case 'PtgStr': /* [MS-XLS] 2.5.198.89 */
11110 // $FlowIgnore
11111 stack.push('"' + f[1] + '"'); break;
11112 case 'PtgErr': /* [MS-XLS] 2.5.198.57 */
11113 stack.push(f[1]); break;
11114 case 'PtgAreaN': /* [MS-XLS] 2.5.198.31 TODO */
11115r = shift_range_xls(f[1][1], cell ? {s:cell} : _range, opts);
11116 stack.push(encode_range_xls((r), opts));
11117 break;
11118 case 'PtgArea': /* [MS-XLS] 2.5.198.27 TODO: fixed points */
11119r = shift_range_xls(f[1][1], _range, opts);
11120 stack.push(encode_range_xls((r), opts));
11121 break;
11122 case 'PtgArea3d': /* [MS-XLS] 2.5.198.28 TODO */
11123ixti = f[1][1]; r = f[1][2];
11124 sname = get_ixti(supbooks, ixti, opts);
11125 stack.push(sname + "!" + encode_range_xls((r), opts));
11126 break;
11127 case 'PtgAttrSum': /* [MS-XLS] 2.5.198.41 */
11128 stack.push("SUM(" + stack.pop() + ")");
11129 break;
11130
11131 case 'PtgAttrBaxcel': /* [MS-XLS] 2.5.198.33 */
11132 case 'PtgAttrSemi': /* [MS-XLS] 2.5.198.37 */
11133 break;
11134
11135 case 'PtgName': /* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 TODO: revisions */
11136 /* f[1] = type, 0, nameindex */
11137 nameidx = (f[1][2]);
11138 var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
11139 var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
11140 if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
11141 stack.push(name);
11142 break;
11143
11144 case 'PtgNameX': /* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 TODO: revisions */
11145 /* f[1] = type, ixti, nameindex */
11146 var bookidx = (f[1][1]); nameidx = (f[1][2]); var externbook;
11147 /* TODO: Properly handle missing values */
11148 if(opts.biff <= 5) {
11149 if(bookidx < 0) bookidx = -bookidx;
11150 if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
11151 } else {
11152 var o = "";
11153 if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){/* empty */}
11154 else if(((supbooks[bookidx]||[])[0]||[])[0] == 0x0401){
11155 if(supbooks[bookidx][nameidx] && supbooks[bookidx][nameidx].itab > 0) {
11156 o = supbooks.SheetNames[supbooks[bookidx][nameidx].itab-1] + "!";
11157 }
11158 }
11159 else o = supbooks.SheetNames[nameidx-1]+ "!";
11160 if(supbooks[bookidx] && supbooks[bookidx][nameidx]) o += supbooks[bookidx][nameidx].Name;
11161 else if(supbooks[0] && supbooks[0][nameidx]) o += supbooks[0][nameidx].Name;
11162 else o += "SH33TJSERRX";
11163 stack.push(o);
11164 break;
11165 }
11166 if(!externbook) externbook = {Name: "SH33TJSERRY"};
11167 stack.push(externbook.Name);
11168 break;
11169
11170 case 'PtgParen': /* [MS-XLS] 2.5.198.80 */
11171 var lp = '(', rp = ')';
11172 if(last_sp >= 0) {
11173 sp = "";
11174 switch(formula[0][last_sp][1][0]) {
11175 // $FlowIgnore
11176 case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
11177 // $FlowIgnore
11178 case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
11179 // $FlowIgnore
11180 case 4: rp = fill(" ", formula[0][last_sp][1][1]) + rp; break;
11181 // $FlowIgnore
11182 case 5: rp = fill("\r", formula[0][last_sp][1][1]) + rp; break;
11183 default:
11184 // $FlowIgnore
11185 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
11186 }
11187 last_sp = -1;
11188 }
11189 stack.push(lp + stack.pop() + rp); break;
11190
11191 case 'PtgRefErr': /* [MS-XLS] 2.5.198.86 */
11192 stack.push('#REF!'); break;
11193
11194 case 'PtgRefErr3d': /* [MS-XLS] 2.5.198.87 */
11195 stack.push('#REF!'); break;
11196
11197 case 'PtgExp': /* [MS-XLS] 2.5.198.58 TODO */
11198 c = {c:(f[1][1]),r:(f[1][0])};
11199 var q = ({c: cell.c, r:cell.r});
11200 if(supbooks.sharedf[encode_cell(c)]) {
11201 var parsedf = (supbooks.sharedf[encode_cell(c)]);
11202 stack.push(stringify_formula(parsedf, _range, q, supbooks, opts));
11203 }
11204 else {
11205 var fnd = false;
11206 for(e1=0;e1!=supbooks.arrayf.length; ++e1) {
11207 /* TODO: should be something like range_has */
11208 e2 = supbooks.arrayf[e1];
11209 if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
11210 if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
11211 stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
11212 fnd = true;
11213 break;
11214 }
11215 if(!fnd) stack.push(f[1]);
11216 }
11217 break;
11218
11219 case 'PtgArray': /* [MS-XLS] 2.5.198.32 TODO */
11220 stack.push("{" + stringify_array(f[1]) + "}");
11221 break;
11222
11223 case 'PtgMemArea': /* [MS-XLS] 2.5.198.70 TODO: confirm this is a non-display */
11224 //stack.push("(" + f[2].map(encode_range).join(",") + ")");
11225 break;
11226
11227 case 'PtgAttrSpace': /* [MS-XLS] 2.5.198.38 */
11228 case 'PtgAttrSpaceSemi': /* [MS-XLS] 2.5.198.39 */
11229 last_sp = ff;
11230 break;
11231
11232 case 'PtgTbl': /* [MS-XLS] 2.5.198.92 TODO */
11233 break;
11234
11235 case 'PtgMemErr': /* [MS-XLS] 2.5.198.71 */
11236 break;
11237
11238 case 'PtgMissArg': /* [MS-XLS] 2.5.198.74 */
11239 stack.push("");
11240 break;
11241
11242 case 'PtgAreaErr': /* [MS-XLS] 2.5.198.29 */
11243 stack.push("#REF!"); break;
11244
11245 case 'PtgAreaErr3d': /* [MS-XLS] 2.5.198.30 */
11246 stack.push("#REF!"); break;
11247
11248 case 'PtgList': /* [MS-XLSB] 2.5.97.52 */
11249 // $FlowIgnore
11250 stack.push("Table" + f[1].idx + "[#" + f[1].rt + "]");
11251 break;
11252
11253 case 'PtgMemAreaN':
11254 case 'PtgMemNoMemN':
11255 case 'PtgAttrNoop':
11256 case 'PtgSheet':
11257 case 'PtgEndSheet':
11258 break;
11259
11260 case 'PtgMemFunc': /* [MS-XLS] 2.5.198.72 TODO */
11261 break;
11262 case 'PtgMemNoMem': /* [MS-XLS] 2.5.198.73 TODO */
11263 break;
11264
11265 case 'PtgElfCol': /* [MS-XLS] 2.5.198.46 */
11266 case 'PtgElfColS': /* [MS-XLS] 2.5.198.47 */
11267 case 'PtgElfColSV': /* [MS-XLS] 2.5.198.48 */
11268 case 'PtgElfColV': /* [MS-XLS] 2.5.198.49 */
11269 case 'PtgElfLel': /* [MS-XLS] 2.5.198.50 */
11270 case 'PtgElfRadical': /* [MS-XLS] 2.5.198.51 */
11271 case 'PtgElfRadicalLel': /* [MS-XLS] 2.5.198.52 */
11272 case 'PtgElfRadicalS': /* [MS-XLS] 2.5.198.53 */
11273 case 'PtgElfRw': /* [MS-XLS] 2.5.198.54 */
11274 case 'PtgElfRwV': /* [MS-XLS] 2.5.198.55 */
11275 throw new Error("Unsupported ELFs");
11276
11277 case 'PtgSxName': /* [MS-XLS] 2.5.198.91 TODO -- find a test case */
11278 throw new Error('Unrecognized Formula Token: ' + String(f));
11279 default: throw new Error('Unrecognized Formula Token: ' + String(f));
11280 }
11281 var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto'];
11282 if(opts.biff != 3) if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) {
11283 f = formula[0][last_sp];
11284 var _left = true;
11285 switch(f[1][0]) {
11286 /* note: some bad XLSB files omit the PtgParen */
11287 case 4: _left = false;
11288 /* falls through */
11289 case 0:
11290 // $FlowIgnore
11291 sp = fill(" ", f[1][1]); break;
11292 case 5: _left = false;
11293 /* falls through */
11294 case 1:
11295 // $FlowIgnore
11296 sp = fill("\r", f[1][1]); break;
11297 default:
11298 sp = "";
11299 // $FlowIgnore
11300 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + f[1][0]);
11301 }
11302 stack.push((_left ? sp : "") + stack.pop() + (_left ? "" : sp));
11303 last_sp = -1;
11304 }
11305 }
11306 if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
11307 return stack[0];
11308}
11309
11310/* [MS-XLS] 2.5.198.1 TODO */
11311function parse_ArrayParsedFormula(blob, length, opts) {
11312 var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
11313 var rgcb, cce = blob.read_shift(len); // length of rgce
11314 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11315 var rgce = parse_Rgce(blob, cce, opts);
11316 if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
11317 blob.l = target;
11318 return [rgce, rgcb];
11319}
11320
11321/* [MS-XLS] 2.5.198.3 TODO */
11322function parse_XLSCellParsedFormula(blob, length, opts) {
11323 var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
11324 var rgcb, cce = blob.read_shift(len); // length of rgce
11325 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11326 var rgce = parse_Rgce(blob, cce, opts);
11327 if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
11328 blob.l = target;
11329 return [rgce, rgcb];
11330}
11331
11332/* [MS-XLS] 2.5.198.21 */
11333function parse_NameParsedFormula(blob, length, opts, cce) {
11334 var target = blob.l + length;
11335 var rgce = parse_Rgce(blob, cce, opts);
11336 var rgcb;
11337 if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
11338 return [rgce, rgcb];
11339}
11340
11341/* [MS-XLS] 2.5.198.118 TODO */
11342function parse_SharedParsedFormula(blob, length, opts) {
11343 var target = blob.l + length;
11344 var rgcb, cce = blob.read_shift(2); // length of rgce
11345 var rgce = parse_Rgce(blob, cce, opts);
11346 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11347 if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
11348 return [rgce, rgcb];
11349}
11350
11351/* [MS-XLS] 2.5.133 TODO: how to emit empty strings? */
11352function parse_FormulaValue(blob) {
11353 var b;
11354 if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
11355 switch(blob[blob.l]) {
11356 case 0x00: blob.l += 8; return ["String", 's'];
11357 case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
11358 case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
11359 case 0x03: blob.l += 8; return ["",'s'];
11360 }
11361 return [];
11362}
11363
11364/* [MS-XLS] 2.4.127 TODO */
11365function parse_Formula(blob, length, opts) {
11366 var end = blob.l + length;
11367 var cell = parse_XLSCell(blob, 6);
11368 if(opts.biff == 2) ++blob.l;
11369 var val = parse_FormulaValue(blob,8);
11370 var flags = blob.read_shift(1);
11371 if(opts.biff != 2) {
11372 blob.read_shift(1);
11373 if(opts.biff >= 5) {
11374 /*var chn = */blob.read_shift(4);
11375 }
11376 }
11377 var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
11378 return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
11379}
11380
11381/* XLSB Parsed Formula records have the same shape */
11382function parse_XLSBParsedFormula(data, length, opts) {
11383 var cce = data.read_shift(4);
11384 var rgce = parse_Rgce(data, cce, opts);
11385 var cb = data.read_shift(4);
11386 var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null;
11387 return [rgce, rgcb];
11388}
11389
11390/* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */
11391var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula;
11392/* [MS-XLSB] 2.5.97.4 CellParsedFormula */
11393var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula;
11394/* [MS-XLSB] 2.5.97.12 NameParsedFormula */
11395var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula;
11396/* [MS-XLSB] 2.5.97.98 SharedParsedFormula */
11397var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula;
11398/* [MS-XLS] 2.5.198.4 */
11399var Cetab = {
114000x0000: 'BEEP',
114010x0001: 'OPEN',
114020x0002: 'OPEN.LINKS',
114030x0003: 'CLOSE.ALL',
114040x0004: 'SAVE',
114050x0005: 'SAVE.AS',
114060x0006: 'FILE.DELETE',
114070x0007: 'PAGE.SETUP',
114080x0008: 'PRINT',
114090x0009: 'PRINTER.SETUP',
114100x000A: 'QUIT',
114110x000B: 'NEW.WINDOW',
114120x000C: 'ARRANGE.ALL',
114130x000D: 'WINDOW.SIZE',
114140x000E: 'WINDOW.MOVE',
114150x000F: 'FULL',
114160x0010: 'CLOSE',
114170x0011: 'RUN',
114180x0016: 'SET.PRINT.AREA',
114190x0017: 'SET.PRINT.TITLES',
114200x0018: 'SET.PAGE.BREAK',
114210x0019: 'REMOVE.PAGE.BREAK',
114220x001A: 'FONT',
114230x001B: 'DISPLAY',
114240x001C: 'PROTECT.DOCUMENT',
114250x001D: 'PRECISION',
114260x001E: 'A1.R1C1',
114270x001F: 'CALCULATE.NOW',
114280x0020: 'CALCULATION',
114290x0022: 'DATA.FIND',
114300x0023: 'EXTRACT',
114310x0024: 'DATA.DELETE',
114320x0025: 'SET.DATABASE',
114330x0026: 'SET.CRITERIA',
114340x0027: 'SORT',
114350x0028: 'DATA.SERIES',
114360x0029: 'TABLE',
114370x002A: 'FORMAT.NUMBER',
114380x002B: 'ALIGNMENT',
114390x002C: 'STYLE',
114400x002D: 'BORDER',
114410x002E: 'CELL.PROTECTION',
114420x002F: 'COLUMN.WIDTH',
114430x0030: 'UNDO',
114440x0031: 'CUT',
114450x0032: 'COPY',
114460x0033: 'PASTE',
114470x0034: 'CLEAR',
114480x0035: 'PASTE.SPECIAL',
114490x0036: 'EDIT.DELETE',
114500x0037: 'INSERT',
114510x0038: 'FILL.RIGHT',
114520x0039: 'FILL.DOWN',
114530x003D: 'DEFINE.NAME',
114540x003E: 'CREATE.NAMES',
114550x003F: 'FORMULA.GOTO',
114560x0040: 'FORMULA.FIND',
114570x0041: 'SELECT.LAST.CELL',
114580x0042: 'SHOW.ACTIVE.CELL',
114590x0043: 'GALLERY.AREA',
114600x0044: 'GALLERY.BAR',
114610x0045: 'GALLERY.COLUMN',
114620x0046: 'GALLERY.LINE',
114630x0047: 'GALLERY.PIE',
114640x0048: 'GALLERY.SCATTER',
114650x0049: 'COMBINATION',
114660x004A: 'PREFERRED',
114670x004B: 'ADD.OVERLAY',
114680x004C: 'GRIDLINES',
114690x004D: 'SET.PREFERRED',
114700x004E: 'AXES',
114710x004F: 'LEGEND',
114720x0050: 'ATTACH.TEXT',
114730x0051: 'ADD.ARROW',
114740x0052: 'SELECT.CHART',
114750x0053: 'SELECT.PLOT.AREA',
114760x0054: 'PATTERNS',
114770x0055: 'MAIN.CHART',
114780x0056: 'OVERLAY',
114790x0057: 'SCALE',
114800x0058: 'FORMAT.LEGEND',
114810x0059: 'FORMAT.TEXT',
114820x005A: 'EDIT.REPEAT',
114830x005B: 'PARSE',
114840x005C: 'JUSTIFY',
114850x005D: 'HIDE',
114860x005E: 'UNHIDE',
114870x005F: 'WORKSPACE',
114880x0060: 'FORMULA',
114890x0061: 'FORMULA.FILL',
114900x0062: 'FORMULA.ARRAY',
114910x0063: 'DATA.FIND.NEXT',
114920x0064: 'DATA.FIND.PREV',
114930x0065: 'FORMULA.FIND.NEXT',
114940x0066: 'FORMULA.FIND.PREV',
114950x0067: 'ACTIVATE',
114960x0068: 'ACTIVATE.NEXT',
114970x0069: 'ACTIVATE.PREV',
114980x006A: 'UNLOCKED.NEXT',
114990x006B: 'UNLOCKED.PREV',
115000x006C: 'COPY.PICTURE',
115010x006D: 'SELECT',
115020x006E: 'DELETE.NAME',
115030x006F: 'DELETE.FORMAT',
115040x0070: 'VLINE',
115050x0071: 'HLINE',
115060x0072: 'VPAGE',
115070x0073: 'HPAGE',
115080x0074: 'VSCROLL',
115090x0075: 'HSCROLL',
115100x0076: 'ALERT',
115110x0077: 'NEW',
115120x0078: 'CANCEL.COPY',
115130x0079: 'SHOW.CLIPBOARD',
115140x007A: 'MESSAGE',
115150x007C: 'PASTE.LINK',
115160x007D: 'APP.ACTIVATE',
115170x007E: 'DELETE.ARROW',
115180x007F: 'ROW.HEIGHT',
115190x0080: 'FORMAT.MOVE',
115200x0081: 'FORMAT.SIZE',
115210x0082: 'FORMULA.REPLACE',
115220x0083: 'SEND.KEYS',
115230x0084: 'SELECT.SPECIAL',
115240x0085: 'APPLY.NAMES',
115250x0086: 'REPLACE.FONT',
115260x0087: 'FREEZE.PANES',
115270x0088: 'SHOW.INFO',
115280x0089: 'SPLIT',
115290x008A: 'ON.WINDOW',
115300x008B: 'ON.DATA',
115310x008C: 'DISABLE.INPUT',
115320x008E: 'OUTLINE',
115330x008F: 'LIST.NAMES',
115340x0090: 'FILE.CLOSE',
115350x0091: 'SAVE.WORKBOOK',
115360x0092: 'DATA.FORM',
115370x0093: 'COPY.CHART',
115380x0094: 'ON.TIME',
115390x0095: 'WAIT',
115400x0096: 'FORMAT.FONT',
115410x0097: 'FILL.UP',
115420x0098: 'FILL.LEFT',
115430x0099: 'DELETE.OVERLAY',
115440x009B: 'SHORT.MENUS',
115450x009F: 'SET.UPDATE.STATUS',
115460x00A1: 'COLOR.PALETTE',
115470x00A2: 'DELETE.STYLE',
115480x00A3: 'WINDOW.RESTORE',
115490x00A4: 'WINDOW.MAXIMIZE',
115500x00A6: 'CHANGE.LINK',
115510x00A7: 'CALCULATE.DOCUMENT',
115520x00A8: 'ON.KEY',
115530x00A9: 'APP.RESTORE',
115540x00AA: 'APP.MOVE',
115550x00AB: 'APP.SIZE',
115560x00AC: 'APP.MINIMIZE',
115570x00AD: 'APP.MAXIMIZE',
115580x00AE: 'BRING.TO.FRONT',
115590x00AF: 'SEND.TO.BACK',
115600x00B9: 'MAIN.CHART.TYPE',
115610x00BA: 'OVERLAY.CHART.TYPE',
115620x00BB: 'SELECT.END',
115630x00BC: 'OPEN.MAIL',
115640x00BD: 'SEND.MAIL',
115650x00BE: 'STANDARD.FONT',
115660x00BF: 'CONSOLIDATE',
115670x00C0: 'SORT.SPECIAL',
115680x00C1: 'GALLERY.3D.AREA',
115690x00C2: 'GALLERY.3D.COLUMN',
115700x00C3: 'GALLERY.3D.LINE',
115710x00C4: 'GALLERY.3D.PIE',
115720x00C5: 'VIEW.3D',
115730x00C6: 'GOAL.SEEK',
115740x00C7: 'WORKGROUP',
115750x00C8: 'FILL.GROUP',
115760x00C9: 'UPDATE.LINK',
115770x00CA: 'PROMOTE',
115780x00CB: 'DEMOTE',
115790x00CC: 'SHOW.DETAIL',
115800x00CE: 'UNGROUP',
115810x00CF: 'OBJECT.PROPERTIES',
115820x00D0: 'SAVE.NEW.OBJECT',
115830x00D1: 'SHARE',
115840x00D2: 'SHARE.NAME',
115850x00D3: 'DUPLICATE',
115860x00D4: 'APPLY.STYLE',
115870x00D5: 'ASSIGN.TO.OBJECT',
115880x00D6: 'OBJECT.PROTECTION',
115890x00D7: 'HIDE.OBJECT',
115900x00D8: 'SET.EXTRACT',
115910x00D9: 'CREATE.PUBLISHER',
115920x00DA: 'SUBSCRIBE.TO',
115930x00DB: 'ATTRIBUTES',
115940x00DC: 'SHOW.TOOLBAR',
115950x00DE: 'PRINT.PREVIEW',
115960x00DF: 'EDIT.COLOR',
115970x00E0: 'SHOW.LEVELS',
115980x00E1: 'FORMAT.MAIN',
115990x00E2: 'FORMAT.OVERLAY',
116000x00E3: 'ON.RECALC',
116010x00E4: 'EDIT.SERIES',
116020x00E5: 'DEFINE.STYLE',
116030x00F0: 'LINE.PRINT',
116040x00F3: 'ENTER.DATA',
116050x00F9: 'GALLERY.RADAR',
116060x00FA: 'MERGE.STYLES',
116070x00FB: 'EDITION.OPTIONS',
116080x00FC: 'PASTE.PICTURE',
116090x00FD: 'PASTE.PICTURE.LINK',
116100x00FE: 'SPELLING',
116110x0100: 'ZOOM',
116120x0103: 'INSERT.OBJECT',
116130x0104: 'WINDOW.MINIMIZE',
116140x0109: 'SOUND.NOTE',
116150x010A: 'SOUND.PLAY',
116160x010B: 'FORMAT.SHAPE',
116170x010C: 'EXTEND.POLYGON',
116180x010D: 'FORMAT.AUTO',
116190x0110: 'GALLERY.3D.BAR',
116200x0111: 'GALLERY.3D.SURFACE',
116210x0112: 'FILL.AUTO',
116220x0114: 'CUSTOMIZE.TOOLBAR',
116230x0115: 'ADD.TOOL',
116240x0116: 'EDIT.OBJECT',
116250x0117: 'ON.DOUBLECLICK',
116260x0118: 'ON.ENTRY',
116270x0119: 'WORKBOOK.ADD',
116280x011A: 'WORKBOOK.MOVE',
116290x011B: 'WORKBOOK.COPY',
116300x011C: 'WORKBOOK.OPTIONS',
116310x011D: 'SAVE.WORKSPACE',
116320x0120: 'CHART.WIZARD',
116330x0121: 'DELETE.TOOL',
116340x0122: 'MOVE.TOOL',
116350x0123: 'WORKBOOK.SELECT',
116360x0124: 'WORKBOOK.ACTIVATE',
116370x0125: 'ASSIGN.TO.TOOL',
116380x0127: 'COPY.TOOL',
116390x0128: 'RESET.TOOL',
116400x0129: 'CONSTRAIN.NUMERIC',
116410x012A: 'PASTE.TOOL',
116420x012E: 'WORKBOOK.NEW',
116430x0131: 'SCENARIO.CELLS',
116440x0132: 'SCENARIO.DELETE',
116450x0133: 'SCENARIO.ADD',
116460x0134: 'SCENARIO.EDIT',
116470x0135: 'SCENARIO.SHOW',
116480x0136: 'SCENARIO.SHOW.NEXT',
116490x0137: 'SCENARIO.SUMMARY',
116500x0138: 'PIVOT.TABLE.WIZARD',
116510x0139: 'PIVOT.FIELD.PROPERTIES',
116520x013A: 'PIVOT.FIELD',
116530x013B: 'PIVOT.ITEM',
116540x013C: 'PIVOT.ADD.FIELDS',
116550x013E: 'OPTIONS.CALCULATION',
116560x013F: 'OPTIONS.EDIT',
116570x0140: 'OPTIONS.VIEW',
116580x0141: 'ADDIN.MANAGER',
116590x0142: 'MENU.EDITOR',
116600x0143: 'ATTACH.TOOLBARS',
116610x0144: 'VBAActivate',
116620x0145: 'OPTIONS.CHART',
116630x0148: 'VBA.INSERT.FILE',
116640x014A: 'VBA.PROCEDURE.DEFINITION',
116650x0150: 'ROUTING.SLIP',
116660x0152: 'ROUTE.DOCUMENT',
116670x0153: 'MAIL.LOGON',
116680x0156: 'INSERT.PICTURE',
116690x0157: 'EDIT.TOOL',
116700x0158: 'GALLERY.DOUGHNUT',
116710x015E: 'CHART.TREND',
116720x0160: 'PIVOT.ITEM.PROPERTIES',
116730x0162: 'WORKBOOK.INSERT',
116740x0163: 'OPTIONS.TRANSITION',
116750x0164: 'OPTIONS.GENERAL',
116760x0172: 'FILTER.ADVANCED',
116770x0175: 'MAIL.ADD.MAILER',
116780x0176: 'MAIL.DELETE.MAILER',
116790x0177: 'MAIL.REPLY',
116800x0178: 'MAIL.REPLY.ALL',
116810x0179: 'MAIL.FORWARD',
116820x017A: 'MAIL.NEXT.LETTER',
116830x017B: 'DATA.LABEL',
116840x017C: 'INSERT.TITLE',
116850x017D: 'FONT.PROPERTIES',
116860x017E: 'MACRO.OPTIONS',
116870x017F: 'WORKBOOK.HIDE',
116880x0180: 'WORKBOOK.UNHIDE',
116890x0181: 'WORKBOOK.DELETE',
116900x0182: 'WORKBOOK.NAME',
116910x0184: 'GALLERY.CUSTOM',
116920x0186: 'ADD.CHART.AUTOFORMAT',
116930x0187: 'DELETE.CHART.AUTOFORMAT',
116940x0188: 'CHART.ADD.DATA',
116950x0189: 'AUTO.OUTLINE',
116960x018A: 'TAB.ORDER',
116970x018B: 'SHOW.DIALOG',
116980x018C: 'SELECT.ALL',
116990x018D: 'UNGROUP.SHEETS',
117000x018E: 'SUBTOTAL.CREATE',
117010x018F: 'SUBTOTAL.REMOVE',
117020x0190: 'RENAME.OBJECT',
117030x019C: 'WORKBOOK.SCROLL',
117040x019D: 'WORKBOOK.NEXT',
117050x019E: 'WORKBOOK.PREV',
117060x019F: 'WORKBOOK.TAB.SPLIT',
117070x01A0: 'FULL.SCREEN',
117080x01A1: 'WORKBOOK.PROTECT',
117090x01A4: 'SCROLLBAR.PROPERTIES',
117100x01A5: 'PIVOT.SHOW.PAGES',
117110x01A6: 'TEXT.TO.COLUMNS',
117120x01A7: 'FORMAT.CHARTTYPE',
117130x01A8: 'LINK.FORMAT',
117140x01A9: 'TRACER.DISPLAY',
117150x01AE: 'TRACER.NAVIGATE',
117160x01AF: 'TRACER.CLEAR',
117170x01B0: 'TRACER.ERROR',
117180x01B1: 'PIVOT.FIELD.GROUP',
117190x01B2: 'PIVOT.FIELD.UNGROUP',
117200x01B3: 'CHECKBOX.PROPERTIES',
117210x01B4: 'LABEL.PROPERTIES',
117220x01B5: 'LISTBOX.PROPERTIES',
117230x01B6: 'EDITBOX.PROPERTIES',
117240x01B7: 'PIVOT.REFRESH',
117250x01B8: 'LINK.COMBO',
117260x01B9: 'OPEN.TEXT',
117270x01BA: 'HIDE.DIALOG',
117280x01BB: 'SET.DIALOG.FOCUS',
117290x01BC: 'ENABLE.OBJECT',
117300x01BD: 'PUSHBUTTON.PROPERTIES',
117310x01BE: 'SET.DIALOG.DEFAULT',
117320x01BF: 'FILTER',
117330x01C0: 'FILTER.SHOW.ALL',
117340x01C1: 'CLEAR.OUTLINE',
117350x01C2: 'FUNCTION.WIZARD',
117360x01C3: 'ADD.LIST.ITEM',
117370x01C4: 'SET.LIST.ITEM',
117380x01C5: 'REMOVE.LIST.ITEM',
117390x01C6: 'SELECT.LIST.ITEM',
117400x01C7: 'SET.CONTROL.VALUE',
117410x01C8: 'SAVE.COPY.AS',
117420x01CA: 'OPTIONS.LISTS.ADD',
117430x01CB: 'OPTIONS.LISTS.DELETE',
117440x01CC: 'SERIES.AXES',
117450x01CD: 'SERIES.X',
117460x01CE: 'SERIES.Y',
117470x01CF: 'ERRORBAR.X',
117480x01D0: 'ERRORBAR.Y',
117490x01D1: 'FORMAT.CHART',
117500x01D2: 'SERIES.ORDER',
117510x01D3: 'MAIL.LOGOFF',
117520x01D4: 'CLEAR.ROUTING.SLIP',
117530x01D5: 'APP.ACTIVATE.MICROSOFT',
117540x01D6: 'MAIL.EDIT.MAILER',
117550x01D7: 'ON.SHEET',
117560x01D8: 'STANDARD.WIDTH',
117570x01D9: 'SCENARIO.MERGE',
117580x01DA: 'SUMMARY.INFO',
117590x01DB: 'FIND.FILE',
117600x01DC: 'ACTIVE.CELL.FONT',
117610x01DD: 'ENABLE.TIPWIZARD',
117620x01DE: 'VBA.MAKE.ADDIN',
117630x01E0: 'INSERTDATATABLE',
117640x01E1: 'WORKGROUP.OPTIONS',
117650x01E2: 'MAIL.SEND.MAILER',
117660x01E5: 'AUTOCORRECT',
117670x01E9: 'POST.DOCUMENT',
117680x01EB: 'PICKLIST',
117690x01ED: 'VIEW.SHOW',
117700x01EE: 'VIEW.DEFINE',
117710x01EF: 'VIEW.DELETE',
117720x01FD: 'SHEET.BACKGROUND',
117730x01FE: 'INSERT.MAP.OBJECT',
117740x01FF: 'OPTIONS.MENONO',
117750x0205: 'MSOCHECKS',
117760x0206: 'NORMAL',
117770x0207: 'LAYOUT',
117780x0208: 'RM.PRINT.AREA',
117790x0209: 'CLEAR.PRINT.AREA',
117800x020A: 'ADD.PRINT.AREA',
117810x020B: 'MOVE.BRK',
117820x0221: 'HIDECURR.NOTE',
117830x0222: 'HIDEALL.NOTES',
117840x0223: 'DELETE.NOTE',
117850x0224: 'TRAVERSE.NOTES',
117860x0225: 'ACTIVATE.NOTES',
117870x026C: 'PROTECT.REVISIONS',
117880x026D: 'UNPROTECT.REVISIONS',
117890x0287: 'OPTIONS.ME',
117900x028D: 'WEB.PUBLISH',
117910x029B: 'NEWWEBQUERY',
117920x02A1: 'PIVOT.TABLE.CHART',
117930x02F1: 'OPTIONS.SAVE',
117940x02F3: 'OPTIONS.SPELL',
117950x0328: 'HIDEALL.INKANNOTS'
11796};
11797
11798/* [MS-XLS] 2.5.198.17 */
11799/* [MS-XLSB] 2.5.97.10 */
11800var Ftab = {
118010x0000: 'COUNT',
118020x0001: 'IF',
118030x0002: 'ISNA',
118040x0003: 'ISERROR',
118050x0004: 'SUM',
118060x0005: 'AVERAGE',
118070x0006: 'MIN',
118080x0007: 'MAX',
118090x0008: 'ROW',
118100x0009: 'COLUMN',
118110x000A: 'NA',
118120x000B: 'NPV',
118130x000C: 'STDEV',
118140x000D: 'DOLLAR',
118150x000E: 'FIXED',
118160x000F: 'SIN',
118170x0010: 'COS',
118180x0011: 'TAN',
118190x0012: 'ATAN',
118200x0013: 'PI',
118210x0014: 'SQRT',
118220x0015: 'EXP',
118230x0016: 'LN',
118240x0017: 'LOG10',
118250x0018: 'ABS',
118260x0019: 'INT',
118270x001A: 'SIGN',
118280x001B: 'ROUND',
118290x001C: 'LOOKUP',
118300x001D: 'INDEX',
118310x001E: 'REPT',
118320x001F: 'MID',
118330x0020: 'LEN',
118340x0021: 'VALUE',
118350x0022: 'TRUE',
118360x0023: 'FALSE',
118370x0024: 'AND',
118380x0025: 'OR',
118390x0026: 'NOT',
118400x0027: 'MOD',
118410x0028: 'DCOUNT',
118420x0029: 'DSUM',
118430x002A: 'DAVERAGE',
118440x002B: 'DMIN',
118450x002C: 'DMAX',
118460x002D: 'DSTDEV',
118470x002E: 'VAR',
118480x002F: 'DVAR',
118490x0030: 'TEXT',
118500x0031: 'LINEST',
118510x0032: 'TREND',
118520x0033: 'LOGEST',
118530x0034: 'GROWTH',
118540x0035: 'GOTO',
118550x0036: 'HALT',
118560x0037: 'RETURN',
118570x0038: 'PV',
118580x0039: 'FV',
118590x003A: 'NPER',
118600x003B: 'PMT',
118610x003C: 'RATE',
118620x003D: 'MIRR',
118630x003E: 'IRR',
118640x003F: 'RAND',
118650x0040: 'MATCH',
118660x0041: 'DATE',
118670x0042: 'TIME',
118680x0043: 'DAY',
118690x0044: 'MONTH',
118700x0045: 'YEAR',
118710x0046: 'WEEKDAY',
118720x0047: 'HOUR',
118730x0048: 'MINUTE',
118740x0049: 'SECOND',
118750x004A: 'NOW',
118760x004B: 'AREAS',
118770x004C: 'ROWS',
118780x004D: 'COLUMNS',
118790x004E: 'OFFSET',
118800x004F: 'ABSREF',
118810x0050: 'RELREF',
118820x0051: 'ARGUMENT',
118830x0052: 'SEARCH',
118840x0053: 'TRANSPOSE',
118850x0054: 'ERROR',
118860x0055: 'STEP',
118870x0056: 'TYPE',
118880x0057: 'ECHO',
118890x0058: 'SET.NAME',
118900x0059: 'CALLER',
118910x005A: 'DEREF',
118920x005B: 'WINDOWS',
118930x005C: 'SERIES',
118940x005D: 'DOCUMENTS',
118950x005E: 'ACTIVE.CELL',
118960x005F: 'SELECTION',
118970x0060: 'RESULT',
118980x0061: 'ATAN2',
118990x0062: 'ASIN',
119000x0063: 'ACOS',
119010x0064: 'CHOOSE',
119020x0065: 'HLOOKUP',
119030x0066: 'VLOOKUP',
119040x0067: 'LINKS',
119050x0068: 'INPUT',
119060x0069: 'ISREF',
119070x006A: 'GET.FORMULA',
119080x006B: 'GET.NAME',
119090x006C: 'SET.VALUE',
119100x006D: 'LOG',
119110x006E: 'EXEC',
119120x006F: 'CHAR',
119130x0070: 'LOWER',
119140x0071: 'UPPER',
119150x0072: 'PROPER',
119160x0073: 'LEFT',
119170x0074: 'RIGHT',
119180x0075: 'EXACT',
119190x0076: 'TRIM',
119200x0077: 'REPLACE',
119210x0078: 'SUBSTITUTE',
119220x0079: 'CODE',
119230x007A: 'NAMES',
119240x007B: 'DIRECTORY',
119250x007C: 'FIND',
119260x007D: 'CELL',
119270x007E: 'ISERR',
119280x007F: 'ISTEXT',
119290x0080: 'ISNUMBER',
119300x0081: 'ISBLANK',
119310x0082: 'T',
119320x0083: 'N',
119330x0084: 'FOPEN',
119340x0085: 'FCLOSE',
119350x0086: 'FSIZE',
119360x0087: 'FREADLN',
119370x0088: 'FREAD',
119380x0089: 'FWRITELN',
119390x008A: 'FWRITE',
119400x008B: 'FPOS',
119410x008C: 'DATEVALUE',
119420x008D: 'TIMEVALUE',
119430x008E: 'SLN',
119440x008F: 'SYD',
119450x0090: 'DDB',
119460x0091: 'GET.DEF',
119470x0092: 'REFTEXT',
119480x0093: 'TEXTREF',
119490x0094: 'INDIRECT',
119500x0095: 'REGISTER',
119510x0096: 'CALL',
119520x0097: 'ADD.BAR',
119530x0098: 'ADD.MENU',
119540x0099: 'ADD.COMMAND',
119550x009A: 'ENABLE.COMMAND',
119560x009B: 'CHECK.COMMAND',
119570x009C: 'RENAME.COMMAND',
119580x009D: 'SHOW.BAR',
119590x009E: 'DELETE.MENU',
119600x009F: 'DELETE.COMMAND',
119610x00A0: 'GET.CHART.ITEM',
119620x00A1: 'DIALOG.BOX',
119630x00A2: 'CLEAN',
119640x00A3: 'MDETERM',
119650x00A4: 'MINVERSE',
119660x00A5: 'MMULT',
119670x00A6: 'FILES',
119680x00A7: 'IPMT',
119690x00A8: 'PPMT',
119700x00A9: 'COUNTA',
119710x00AA: 'CANCEL.KEY',
119720x00AB: 'FOR',
119730x00AC: 'WHILE',
119740x00AD: 'BREAK',
119750x00AE: 'NEXT',
119760x00AF: 'INITIATE',
119770x00B0: 'REQUEST',
119780x00B1: 'POKE',
119790x00B2: 'EXECUTE',
119800x00B3: 'TERMINATE',
119810x00B4: 'RESTART',
119820x00B5: 'HELP',
119830x00B6: 'GET.BAR',
119840x00B7: 'PRODUCT',
119850x00B8: 'FACT',
119860x00B9: 'GET.CELL',
119870x00BA: 'GET.WORKSPACE',
119880x00BB: 'GET.WINDOW',
119890x00BC: 'GET.DOCUMENT',
119900x00BD: 'DPRODUCT',
119910x00BE: 'ISNONTEXT',
119920x00BF: 'GET.NOTE',
119930x00C0: 'NOTE',
119940x00C1: 'STDEVP',
119950x00C2: 'VARP',
119960x00C3: 'DSTDEVP',
119970x00C4: 'DVARP',
119980x00C5: 'TRUNC',
119990x00C6: 'ISLOGICAL',
120000x00C7: 'DCOUNTA',
120010x00C8: 'DELETE.BAR',
120020x00C9: 'UNREGISTER',
120030x00CC: 'USDOLLAR',
120040x00CD: 'FINDB',
120050x00CE: 'SEARCHB',
120060x00CF: 'REPLACEB',
120070x00D0: 'LEFTB',
120080x00D1: 'RIGHTB',
120090x00D2: 'MIDB',
120100x00D3: 'LENB',
120110x00D4: 'ROUNDUP',
120120x00D5: 'ROUNDDOWN',
120130x00D6: 'ASC',
120140x00D7: 'DBCS',
120150x00D8: 'RANK',
120160x00DB: 'ADDRESS',
120170x00DC: 'DAYS360',
120180x00DD: 'TODAY',
120190x00DE: 'VDB',
120200x00DF: 'ELSE',
120210x00E0: 'ELSE.IF',
120220x00E1: 'END.IF',
120230x00E2: 'FOR.CELL',
120240x00E3: 'MEDIAN',
120250x00E4: 'SUMPRODUCT',
120260x00E5: 'SINH',
120270x00E6: 'COSH',
120280x00E7: 'TANH',
120290x00E8: 'ASINH',
120300x00E9: 'ACOSH',
120310x00EA: 'ATANH',
120320x00EB: 'DGET',
120330x00EC: 'CREATE.OBJECT',
120340x00ED: 'VOLATILE',
120350x00EE: 'LAST.ERROR',
120360x00EF: 'CUSTOM.UNDO',
120370x00F0: 'CUSTOM.REPEAT',
120380x00F1: 'FORMULA.CONVERT',
120390x00F2: 'GET.LINK.INFO',
120400x00F3: 'TEXT.BOX',
120410x00F4: 'INFO',
120420x00F5: 'GROUP',
120430x00F6: 'GET.OBJECT',
120440x00F7: 'DB',
120450x00F8: 'PAUSE',
120460x00FB: 'RESUME',
120470x00FC: 'FREQUENCY',
120480x00FD: 'ADD.TOOLBAR',
120490x00FE: 'DELETE.TOOLBAR',
120500x00FF: 'User',
120510x0100: 'RESET.TOOLBAR',
120520x0101: 'EVALUATE',
120530x0102: 'GET.TOOLBAR',
120540x0103: 'GET.TOOL',
120550x0104: 'SPELLING.CHECK',
120560x0105: 'ERROR.TYPE',
120570x0106: 'APP.TITLE',
120580x0107: 'WINDOW.TITLE',
120590x0108: 'SAVE.TOOLBAR',
120600x0109: 'ENABLE.TOOL',
120610x010A: 'PRESS.TOOL',
120620x010B: 'REGISTER.ID',
120630x010C: 'GET.WORKBOOK',
120640x010D: 'AVEDEV',
120650x010E: 'BETADIST',
120660x010F: 'GAMMALN',
120670x0110: 'BETAINV',
120680x0111: 'BINOMDIST',
120690x0112: 'CHIDIST',
120700x0113: 'CHIINV',
120710x0114: 'COMBIN',
120720x0115: 'CONFIDENCE',
120730x0116: 'CRITBINOM',
120740x0117: 'EVEN',
120750x0118: 'EXPONDIST',
120760x0119: 'FDIST',
120770x011A: 'FINV',
120780x011B: 'FISHER',
120790x011C: 'FISHERINV',
120800x011D: 'FLOOR',
120810x011E: 'GAMMADIST',
120820x011F: 'GAMMAINV',
120830x0120: 'CEILING',
120840x0121: 'HYPGEOMDIST',
120850x0122: 'LOGNORMDIST',
120860x0123: 'LOGINV',
120870x0124: 'NEGBINOMDIST',
120880x0125: 'NORMDIST',
120890x0126: 'NORMSDIST',
120900x0127: 'NORMINV',
120910x0128: 'NORMSINV',
120920x0129: 'STANDARDIZE',
120930x012A: 'ODD',
120940x012B: 'PERMUT',
120950x012C: 'POISSON',
120960x012D: 'TDIST',
120970x012E: 'WEIBULL',
120980x012F: 'SUMXMY2',
120990x0130: 'SUMX2MY2',
121000x0131: 'SUMX2PY2',
121010x0132: 'CHITEST',
121020x0133: 'CORREL',
121030x0134: 'COVAR',
121040x0135: 'FORECAST',
121050x0136: 'FTEST',
121060x0137: 'INTERCEPT',
121070x0138: 'PEARSON',
121080x0139: 'RSQ',
121090x013A: 'STEYX',
121100x013B: 'SLOPE',
121110x013C: 'TTEST',
121120x013D: 'PROB',
121130x013E: 'DEVSQ',
121140x013F: 'GEOMEAN',
121150x0140: 'HARMEAN',
121160x0141: 'SUMSQ',
121170x0142: 'KURT',
121180x0143: 'SKEW',
121190x0144: 'ZTEST',
121200x0145: 'LARGE',
121210x0146: 'SMALL',
121220x0147: 'QUARTILE',
121230x0148: 'PERCENTILE',
121240x0149: 'PERCENTRANK',
121250x014A: 'MODE',
121260x014B: 'TRIMMEAN',
121270x014C: 'TINV',
121280x014E: 'MOVIE.COMMAND',
121290x014F: 'GET.MOVIE',
121300x0150: 'CONCATENATE',
121310x0151: 'POWER',
121320x0152: 'PIVOT.ADD.DATA',
121330x0153: 'GET.PIVOT.TABLE',
121340x0154: 'GET.PIVOT.FIELD',
121350x0155: 'GET.PIVOT.ITEM',
121360x0156: 'RADIANS',
121370x0157: 'DEGREES',
121380x0158: 'SUBTOTAL',
121390x0159: 'SUMIF',
121400x015A: 'COUNTIF',
121410x015B: 'COUNTBLANK',
121420x015C: 'SCENARIO.GET',
121430x015D: 'OPTIONS.LISTS.GET',
121440x015E: 'ISPMT',
121450x015F: 'DATEDIF',
121460x0160: 'DATESTRING',
121470x0161: 'NUMBERSTRING',
121480x0162: 'ROMAN',
121490x0163: 'OPEN.DIALOG',
121500x0164: 'SAVE.DIALOG',
121510x0165: 'VIEW.GET',
121520x0166: 'GETPIVOTDATA',
121530x0167: 'HYPERLINK',
121540x0168: 'PHONETIC',
121550x0169: 'AVERAGEA',
121560x016A: 'MAXA',
121570x016B: 'MINA',
121580x016C: 'STDEVPA',
121590x016D: 'VARPA',
121600x016E: 'STDEVA',
121610x016F: 'VARA',
121620x0170: 'BAHTTEXT',
121630x0171: 'THAIDAYOFWEEK',
121640x0172: 'THAIDIGIT',
121650x0173: 'THAIMONTHOFYEAR',
121660x0174: 'THAINUMSOUND',
121670x0175: 'THAINUMSTRING',
121680x0176: 'THAISTRINGLENGTH',
121690x0177: 'ISTHAIDIGIT',
121700x0178: 'ROUNDBAHTDOWN',
121710x0179: 'ROUNDBAHTUP',
121720x017A: 'THAIYEAR',
121730x017B: 'RTD',
12174
121750x017C: 'CUBEVALUE',
121760x017D: 'CUBEMEMBER',
121770x017E: 'CUBEMEMBERPROPERTY',
121780x017F: 'CUBERANKEDMEMBER',
121790x0180: 'HEX2BIN',
121800x0181: 'HEX2DEC',
121810x0182: 'HEX2OCT',
121820x0183: 'DEC2BIN',
121830x0184: 'DEC2HEX',
121840x0185: 'DEC2OCT',
121850x0186: 'OCT2BIN',
121860x0187: 'OCT2HEX',
121870x0188: 'OCT2DEC',
121880x0189: 'BIN2DEC',
121890x018A: 'BIN2OCT',
121900x018B: 'BIN2HEX',
121910x018C: 'IMSUB',
121920x018D: 'IMDIV',
121930x018E: 'IMPOWER',
121940x018F: 'IMABS',
121950x0190: 'IMSQRT',
121960x0191: 'IMLN',
121970x0192: 'IMLOG2',
121980x0193: 'IMLOG10',
121990x0194: 'IMSIN',
122000x0195: 'IMCOS',
122010x0196: 'IMEXP',
122020x0197: 'IMARGUMENT',
122030x0198: 'IMCONJUGATE',
122040x0199: 'IMAGINARY',
122050x019A: 'IMREAL',
122060x019B: 'COMPLEX',
122070x019C: 'IMSUM',
122080x019D: 'IMPRODUCT',
122090x019E: 'SERIESSUM',
122100x019F: 'FACTDOUBLE',
122110x01A0: 'SQRTPI',
122120x01A1: 'QUOTIENT',
122130x01A2: 'DELTA',
122140x01A3: 'GESTEP',
122150x01A4: 'ISEVEN',
122160x01A5: 'ISODD',
122170x01A6: 'MROUND',
122180x01A7: 'ERF',
122190x01A8: 'ERFC',
122200x01A9: 'BESSELJ',
122210x01AA: 'BESSELK',
122220x01AB: 'BESSELY',
122230x01AC: 'BESSELI',
122240x01AD: 'XIRR',
122250x01AE: 'XNPV',
122260x01AF: 'PRICEMAT',
122270x01B0: 'YIELDMAT',
122280x01B1: 'INTRATE',
122290x01B2: 'RECEIVED',
122300x01B3: 'DISC',
122310x01B4: 'PRICEDISC',
122320x01B5: 'YIELDDISC',
122330x01B6: 'TBILLEQ',
122340x01B7: 'TBILLPRICE',
122350x01B8: 'TBILLYIELD',
122360x01B9: 'PRICE',
122370x01BA: 'YIELD',
122380x01BB: 'DOLLARDE',
122390x01BC: 'DOLLARFR',
122400x01BD: 'NOMINAL',
122410x01BE: 'EFFECT',
122420x01BF: 'CUMPRINC',
122430x01C0: 'CUMIPMT',
122440x01C1: 'EDATE',
122450x01C2: 'EOMONTH',
122460x01C3: 'YEARFRAC',
122470x01C4: 'COUPDAYBS',
122480x01C5: 'COUPDAYS',
122490x01C6: 'COUPDAYSNC',
122500x01C7: 'COUPNCD',
122510x01C8: 'COUPNUM',
122520x01C9: 'COUPPCD',
122530x01CA: 'DURATION',
122540x01CB: 'MDURATION',
122550x01CC: 'ODDLPRICE',
122560x01CD: 'ODDLYIELD',
122570x01CE: 'ODDFPRICE',
122580x01CF: 'ODDFYIELD',
122590x01D0: 'RANDBETWEEN',
122600x01D1: 'WEEKNUM',
122610x01D2: 'AMORDEGRC',
122620x01D3: 'AMORLINC',
122630x01D4: 'CONVERT',
122640x02D4: 'SHEETJS',
122650x01D5: 'ACCRINT',
122660x01D6: 'ACCRINTM',
122670x01D7: 'WORKDAY',
122680x01D8: 'NETWORKDAYS',
122690x01D9: 'GCD',
122700x01DA: 'MULTINOMIAL',
122710x01DB: 'LCM',
122720x01DC: 'FVSCHEDULE',
122730x01DD: 'CUBEKPIMEMBER',
122740x01DE: 'CUBESET',
122750x01DF: 'CUBESETCOUNT',
122760x01E0: 'IFERROR',
122770x01E1: 'COUNTIFS',
122780x01E2: 'SUMIFS',
122790x01E3: 'AVERAGEIF',
122800x01E4: 'AVERAGEIFS'
12281};
12282var FtabArgc = {
122830x0002: 1, /* ISNA */
122840x0003: 1, /* ISERROR */
122850x000A: 0, /* NA */
122860x000F: 1, /* SIN */
122870x0010: 1, /* COS */
122880x0011: 1, /* TAN */
122890x0012: 1, /* ATAN */
122900x0013: 0, /* PI */
122910x0014: 1, /* SQRT */
122920x0015: 1, /* EXP */
122930x0016: 1, /* LN */
122940x0017: 1, /* LOG10 */
122950x0018: 1, /* ABS */
122960x0019: 1, /* INT */
122970x001A: 1, /* SIGN */
122980x001B: 2, /* ROUND */
122990x001E: 2, /* REPT */
123000x001F: 3, /* MID */
123010x0020: 1, /* LEN */
123020x0021: 1, /* VALUE */
123030x0022: 0, /* TRUE */
123040x0023: 0, /* FALSE */
123050x0026: 1, /* NOT */
123060x0027: 2, /* MOD */
123070x0028: 3, /* DCOUNT */
123080x0029: 3, /* DSUM */
123090x002A: 3, /* DAVERAGE */
123100x002B: 3, /* DMIN */
123110x002C: 3, /* DMAX */
123120x002D: 3, /* DSTDEV */
123130x002F: 3, /* DVAR */
123140x0030: 2, /* TEXT */
123150x0035: 1, /* GOTO */
123160x003D: 3, /* MIRR */
123170x003F: 0, /* RAND */
123180x0041: 3, /* DATE */
123190x0042: 3, /* TIME */
123200x0043: 1, /* DAY */
123210x0044: 1, /* MONTH */
123220x0045: 1, /* YEAR */
123230x0046: 1, /* WEEKDAY */
123240x0047: 1, /* HOUR */
123250x0048: 1, /* MINUTE */
123260x0049: 1, /* SECOND */
123270x004A: 0, /* NOW */
123280x004B: 1, /* AREAS */
123290x004C: 1, /* ROWS */
123300x004D: 1, /* COLUMNS */
123310x004F: 2, /* ABSREF */
123320x0050: 2, /* RELREF */
123330x0053: 1, /* TRANSPOSE */
123340x0055: 0, /* STEP */
123350x0056: 1, /* TYPE */
123360x0059: 0, /* CALLER */
123370x005A: 1, /* DEREF */
123380x005E: 0, /* ACTIVE.CELL */
123390x005F: 0, /* SELECTION */
123400x0061: 2, /* ATAN2 */
123410x0062: 1, /* ASIN */
123420x0063: 1, /* ACOS */
123430x0065: 3, /* HLOOKUP */
123440x0066: 3, /* VLOOKUP */
123450x0069: 1, /* ISREF */
123460x006A: 1, /* GET.FORMULA */
123470x006C: 2, /* SET.VALUE */
123480x006F: 1, /* CHAR */
123490x0070: 1, /* LOWER */
123500x0071: 1, /* UPPER */
123510x0072: 1, /* PROPER */
123520x0075: 2, /* EXACT */
123530x0076: 1, /* TRIM */
123540x0077: 4, /* REPLACE */
123550x0079: 1, /* CODE */
123560x007E: 1, /* ISERR */
123570x007F: 1, /* ISTEXT */
123580x0080: 1, /* ISNUMBER */
123590x0081: 1, /* ISBLANK */
123600x0082: 1, /* T */
123610x0083: 1, /* N */
123620x0085: 1, /* FCLOSE */
123630x0086: 1, /* FSIZE */
123640x0087: 1, /* FREADLN */
123650x0088: 2, /* FREAD */
123660x0089: 2, /* FWRITELN */
123670x008A: 2, /* FWRITE */
123680x008C: 1, /* DATEVALUE */
123690x008D: 1, /* TIMEVALUE */
123700x008E: 3, /* SLN */
123710x008F: 4, /* SYD */
123720x0090: 4, /* DDB */
123730x00A1: 1, /* DIALOG.BOX */
123740x00A2: 1, /* CLEAN */
123750x00A3: 1, /* MDETERM */
123760x00A4: 1, /* MINVERSE */
123770x00A5: 2, /* MMULT */
123780x00AC: 1, /* WHILE */
123790x00AF: 2, /* INITIATE */
123800x00B0: 2, /* REQUEST */
123810x00B1: 3, /* POKE */
123820x00B2: 2, /* EXECUTE */
123830x00B3: 1, /* TERMINATE */
123840x00B8: 1, /* FACT */
123850x00BA: 1, /* GET.WORKSPACE */
123860x00BD: 3, /* DPRODUCT */
123870x00BE: 1, /* ISNONTEXT */
123880x00C3: 3, /* DSTDEVP */
123890x00C4: 3, /* DVARP */
123900x00C5: 1, /* TRUNC */
123910x00C6: 1, /* ISLOGICAL */
123920x00C7: 3, /* DCOUNTA */
123930x00C9: 1, /* UNREGISTER */
123940x00CF: 4, /* REPLACEB */
123950x00D2: 3, /* MIDB */
123960x00D3: 1, /* LENB */
123970x00D4: 2, /* ROUNDUP */
123980x00D5: 2, /* ROUNDDOWN */
123990x00D6: 1, /* ASC */
124000x00D7: 1, /* DBCS */
124010x00E1: 0, /* END.IF */
124020x00E5: 1, /* SINH */
124030x00E6: 1, /* COSH */
124040x00E7: 1, /* TANH */
124050x00E8: 1, /* ASINH */
124060x00E9: 1, /* ACOSH */
124070x00EA: 1, /* ATANH */
124080x00EB: 3, /* DGET */
124090x00F4: 1, /* INFO */
124100x00F7: 4, /* DB */
124110x00FC: 2, /* FREQUENCY */
124120x0101: 1, /* EVALUATE */
124130x0105: 1, /* ERROR.TYPE */
124140x010F: 1, /* GAMMALN */
124150x0111: 4, /* BINOMDIST */
124160x0112: 2, /* CHIDIST */
124170x0113: 2, /* CHIINV */
124180x0114: 2, /* COMBIN */
124190x0115: 3, /* CONFIDENCE */
124200x0116: 3, /* CRITBINOM */
124210x0117: 1, /* EVEN */
124220x0118: 3, /* EXPONDIST */
124230x0119: 3, /* FDIST */
124240x011A: 3, /* FINV */
124250x011B: 1, /* FISHER */
124260x011C: 1, /* FISHERINV */
124270x011D: 2, /* FLOOR */
124280x011E: 4, /* GAMMADIST */
124290x011F: 3, /* GAMMAINV */
124300x0120: 2, /* CEILING */
124310x0121: 4, /* HYPGEOMDIST */
124320x0122: 3, /* LOGNORMDIST */
124330x0123: 3, /* LOGINV */
124340x0124: 3, /* NEGBINOMDIST */
124350x0125: 4, /* NORMDIST */
124360x0126: 1, /* NORMSDIST */
124370x0127: 3, /* NORMINV */
124380x0128: 1, /* NORMSINV */
124390x0129: 3, /* STANDARDIZE */
124400x012A: 1, /* ODD */
124410x012B: 2, /* PERMUT */
124420x012C: 3, /* POISSON */
124430x012D: 3, /* TDIST */
124440x012E: 4, /* WEIBULL */
124450x012F: 2, /* SUMXMY2 */
124460x0130: 2, /* SUMX2MY2 */
124470x0131: 2, /* SUMX2PY2 */
124480x0132: 2, /* CHITEST */
124490x0133: 2, /* CORREL */
124500x0134: 2, /* COVAR */
124510x0135: 3, /* FORECAST */
124520x0136: 2, /* FTEST */
124530x0137: 2, /* INTERCEPT */
124540x0138: 2, /* PEARSON */
124550x0139: 2, /* RSQ */
124560x013A: 2, /* STEYX */
124570x013B: 2, /* SLOPE */
124580x013C: 4, /* TTEST */
124590x0145: 2, /* LARGE */
124600x0146: 2, /* SMALL */
124610x0147: 2, /* QUARTILE */
124620x0148: 2, /* PERCENTILE */
124630x014B: 2, /* TRIMMEAN */
124640x014C: 2, /* TINV */
124650x0151: 2, /* POWER */
124660x0156: 1, /* RADIANS */
124670x0157: 1, /* DEGREES */
124680x015A: 2, /* COUNTIF */
124690x015B: 1, /* COUNTBLANK */
124700x015E: 4, /* ISPMT */
124710x015F: 3, /* DATEDIF */
124720x0160: 1, /* DATESTRING */
124730x0161: 2, /* NUMBERSTRING */
124740x0168: 1, /* PHONETIC */
124750x0170: 1, /* BAHTTEXT */
124760x0171: 1, /* THAIDAYOFWEEK */
124770x0172: 1, /* THAIDIGIT */
124780x0173: 1, /* THAIMONTHOFYEAR */
124790x0174: 1, /* THAINUMSOUND */
124800x0175: 1, /* THAINUMSTRING */
124810x0176: 1, /* THAISTRINGLENGTH */
124820x0177: 1, /* ISTHAIDIGIT */
124830x0178: 1, /* ROUNDBAHTDOWN */
124840x0179: 1, /* ROUNDBAHTUP */
124850x017A: 1, /* THAIYEAR */
124860x017E: 3, /* CUBEMEMBERPROPERTY */
124870x0181: 1, /* HEX2DEC */
124880x0188: 1, /* OCT2DEC */
124890x0189: 1, /* BIN2DEC */
124900x018C: 2, /* IMSUB */
124910x018D: 2, /* IMDIV */
124920x018E: 2, /* IMPOWER */
124930x018F: 1, /* IMABS */
124940x0190: 1, /* IMSQRT */
124950x0191: 1, /* IMLN */
124960x0192: 1, /* IMLOG2 */
124970x0193: 1, /* IMLOG10 */
124980x0194: 1, /* IMSIN */
124990x0195: 1, /* IMCOS */
125000x0196: 1, /* IMEXP */
125010x0197: 1, /* IMARGUMENT */
125020x0198: 1, /* IMCONJUGATE */
125030x0199: 1, /* IMAGINARY */
125040x019A: 1, /* IMREAL */
125050x019E: 4, /* SERIESSUM */
125060x019F: 1, /* FACTDOUBLE */
125070x01A0: 1, /* SQRTPI */
125080x01A1: 2, /* QUOTIENT */
125090x01A4: 1, /* ISEVEN */
125100x01A5: 1, /* ISODD */
125110x01A6: 2, /* MROUND */
125120x01A8: 1, /* ERFC */
125130x01A9: 2, /* BESSELJ */
125140x01AA: 2, /* BESSELK */
125150x01AB: 2, /* BESSELY */
125160x01AC: 2, /* BESSELI */
125170x01AE: 3, /* XNPV */
125180x01B6: 3, /* TBILLEQ */
125190x01B7: 3, /* TBILLPRICE */
125200x01B8: 3, /* TBILLYIELD */
125210x01BB: 2, /* DOLLARDE */
125220x01BC: 2, /* DOLLARFR */
125230x01BD: 2, /* NOMINAL */
125240x01BE: 2, /* EFFECT */
125250x01BF: 6, /* CUMPRINC */
125260x01C0: 6, /* CUMIPMT */
125270x01C1: 2, /* EDATE */
125280x01C2: 2, /* EOMONTH */
125290x01D0: 2, /* RANDBETWEEN */
125300x01D4: 3, /* CONVERT */
125310x01DC: 2, /* FVSCHEDULE */
125320x01DF: 1, /* CUBESETCOUNT */
125330x01E0: 2, /* IFERROR */
125340xFFFF: 0
12535};
12536/* [MS-XLSX] 2.2.3 Functions */
12537/* [MS-XLSB] 2.5.97.10 Ftab */
12538var XLSXFutureFunctions = {
12539 "_xlfn.ACOT": "ACOT",
12540 "_xlfn.ACOTH": "ACOTH",
12541 "_xlfn.AGGREGATE": "AGGREGATE",
12542 "_xlfn.ARABIC": "ARABIC",
12543 "_xlfn.AVERAGEIF": "AVERAGEIF",
12544 "_xlfn.AVERAGEIFS": "AVERAGEIFS",
12545 "_xlfn.BASE": "BASE",
12546 "_xlfn.BETA.DIST": "BETA.DIST",
12547 "_xlfn.BETA.INV": "BETA.INV",
12548 "_xlfn.BINOM.DIST": "BINOM.DIST",
12549 "_xlfn.BINOM.DIST.RANGE": "BINOM.DIST.RANGE",
12550 "_xlfn.BINOM.INV": "BINOM.INV",
12551 "_xlfn.BITAND": "BITAND",
12552 "_xlfn.BITLSHIFT": "BITLSHIFT",
12553 "_xlfn.BITOR": "BITOR",
12554 "_xlfn.BITRSHIFT": "BITRSHIFT",
12555 "_xlfn.BITXOR": "BITXOR",
12556 "_xlfn.CEILING.MATH": "CEILING.MATH",
12557 "_xlfn.CEILING.PRECISE": "CEILING.PRECISE",
12558 "_xlfn.CHISQ.DIST": "CHISQ.DIST",
12559 "_xlfn.CHISQ.DIST.RT": "CHISQ.DIST.RT",
12560 "_xlfn.CHISQ.INV": "CHISQ.INV",
12561 "_xlfn.CHISQ.INV.RT": "CHISQ.INV.RT",
12562 "_xlfn.CHISQ.TEST": "CHISQ.TEST",
12563 "_xlfn.COMBINA": "COMBINA",
12564 "_xlfn.CONCAT": "CONCAT",
12565 "_xlfn.CONFIDENCE.NORM": "CONFIDENCE.NORM",
12566 "_xlfn.CONFIDENCE.T": "CONFIDENCE.T",
12567 "_xlfn.COT": "COT",
12568 "_xlfn.COTH": "COTH",
12569 "_xlfn.COUNTIFS": "COUNTIFS",
12570 "_xlfn.COVARIANCE.P": "COVARIANCE.P",
12571 "_xlfn.COVARIANCE.S": "COVARIANCE.S",
12572 "_xlfn.CSC": "CSC",
12573 "_xlfn.CSCH": "CSCH",
12574 "_xlfn.DAYS": "DAYS",
12575 "_xlfn.DECIMAL": "DECIMAL",
12576 "_xlfn.ECMA.CEILING": "ECMA.CEILING",
12577 "_xlfn.ERF.PRECISE": "ERF.PRECISE",
12578 "_xlfn.ERFC.PRECISE": "ERFC.PRECISE",
12579 "_xlfn.EXPON.DIST": "EXPON.DIST",
12580 "_xlfn.F.DIST": "F.DIST",
12581 "_xlfn.F.DIST.RT": "F.DIST.RT",
12582 "_xlfn.F.INV": "F.INV",
12583 "_xlfn.F.INV.RT": "F.INV.RT",
12584 "_xlfn.F.TEST": "F.TEST",
12585 "_xlfn.FILTERXML": "FILTERXML",
12586 "_xlfn.FLOOR.MATH": "FLOOR.MATH",
12587 "_xlfn.FLOOR.PRECISE": "FLOOR.PRECISE",
12588 "_xlfn.FORECAST.ETS": "FORECAST.ETS",
12589 "_xlfn.FORECAST.ETS.CONFINT": "FORECAST.ETS.CONFINT",
12590 "_xlfn.FORECAST.ETS.SEASONALITY": "FORECAST.ETS.SEASONALITY",
12591 "_xlfn.FORECAST.ETS.STAT": "FORECAST.ETS.STAT",
12592 "_xlfn.FORECAST.LINEAR": "FORECAST.LINEAR",
12593 "_xlfn.FORMULATEXT": "FORMULATEXT",
12594 "_xlfn.GAMMA": "GAMMA",
12595 "_xlfn.GAMMA.DIST": "GAMMA.DIST",
12596 "_xlfn.GAMMA.INV": "GAMMA.INV",
12597 "_xlfn.GAMMALN.PRECISE": "GAMMALN.PRECISE",
12598 "_xlfn.GAUSS": "GAUSS",
12599 "_xlfn.HYPGEOM.DIST": "HYPGEOM.DIST",
12600 "_xlfn.IFERROR": "IFERROR",
12601 "_xlfn.IFNA": "IFNA",
12602 "_xlfn.IFS": "IFS",
12603 "_xlfn.IMCOSH": "IMCOSH",
12604 "_xlfn.IMCOT": "IMCOT",
12605 "_xlfn.IMCSC": "IMCSC",
12606 "_xlfn.IMCSCH": "IMCSCH",
12607 "_xlfn.IMSEC": "IMSEC",
12608 "_xlfn.IMSECH": "IMSECH",
12609 "_xlfn.IMSINH": "IMSINH",
12610 "_xlfn.IMTAN": "IMTAN",
12611 "_xlfn.ISFORMULA": "ISFORMULA",
12612 "_xlfn.ISO.CEILING": "ISO.CEILING",
12613 "_xlfn.ISOWEEKNUM": "ISOWEEKNUM",
12614 "_xlfn.LOGNORM.DIST": "LOGNORM.DIST",
12615 "_xlfn.LOGNORM.INV": "LOGNORM.INV",
12616 "_xlfn.MAXIFS": "MAXIFS",
12617 "_xlfn.MINIFS": "MINIFS",
12618 "_xlfn.MODE.MULT": "MODE.MULT",
12619 "_xlfn.MODE.SNGL": "MODE.SNGL",
12620 "_xlfn.MUNIT": "MUNIT",
12621 "_xlfn.NEGBINOM.DIST": "NEGBINOM.DIST",
12622 "_xlfn.NETWORKDAYS.INTL": "NETWORKDAYS.INTL",
12623 "_xlfn.NIGBINOM": "NIGBINOM",
12624 "_xlfn.NORM.DIST": "NORM.DIST",
12625 "_xlfn.NORM.INV": "NORM.INV",
12626 "_xlfn.NORM.S.DIST": "NORM.S.DIST",
12627 "_xlfn.NORM.S.INV": "NORM.S.INV",
12628 "_xlfn.NUMBERVALUE": "NUMBERVALUE",
12629 "_xlfn.PDURATION": "PDURATION",
12630 "_xlfn.PERCENTILE.EXC": "PERCENTILE.EXC",
12631 "_xlfn.PERCENTILE.INC": "PERCENTILE.INC",
12632 "_xlfn.PERCENTRANK.EXC": "PERCENTRANK.EXC",
12633 "_xlfn.PERCENTRANK.INC": "PERCENTRANK.INC",
12634 "_xlfn.PERMUTATIONA": "PERMUTATIONA",
12635 "_xlfn.PHI": "PHI",
12636 "_xlfn.POISSON.DIST": "POISSON.DIST",
12637 "_xlfn.QUARTILE.EXC": "QUARTILE.EXC",
12638 "_xlfn.QUARTILE.INC": "QUARTILE.INC",
12639 "_xlfn.QUERYSTRING": "QUERYSTRING",
12640 "_xlfn.RANK.AVG": "RANK.AVG",
12641 "_xlfn.RANK.EQ": "RANK.EQ",
12642 "_xlfn.RRI": "RRI",
12643 "_xlfn.SEC": "SEC",
12644 "_xlfn.SECH": "SECH",
12645 "_xlfn.SHEET": "SHEET",
12646 "_xlfn.SHEETS": "SHEETS",
12647 "_xlfn.SKEW.P": "SKEW.P",
12648 "_xlfn.STDEV.P": "STDEV.P",
12649 "_xlfn.STDEV.S": "STDEV.S",
12650 "_xlfn.SUMIFS": "SUMIFS",
12651 "_xlfn.SWITCH": "SWITCH",
12652 "_xlfn.T.DIST": "T.DIST",
12653 "_xlfn.T.DIST.2T": "T.DIST.2T",
12654 "_xlfn.T.DIST.RT": "T.DIST.RT",
12655 "_xlfn.T.INV": "T.INV",
12656 "_xlfn.T.INV.2T": "T.INV.2T",
12657 "_xlfn.T.TEST": "T.TEST",
12658 "_xlfn.TEXTJOIN": "TEXTJOIN",
12659 "_xlfn.UNICHAR": "UNICHAR",
12660 "_xlfn.UNICODE": "UNICODE",
12661 "_xlfn.VAR.P": "VAR.P",
12662 "_xlfn.VAR.S": "VAR.S",
12663 "_xlfn.WEBSERVICE": "WEBSERVICE",
12664 "_xlfn.WEIBULL.DIST": "WEIBULL.DIST",
12665 "_xlfn.WORKDAY.INTL": "WORKDAY.INTL",
12666 "_xlfn.XOR": "XOR",
12667 "_xlfn.Z.TEST": "Z.TEST"
12668};
12669
12670/* Part 3 TODO: actually parse formulae */
12671function ods_to_csf_formula(f) {
12672 if(f.slice(0,3) == "of:") f = f.slice(3);
12673 /* 5.2 Basic Expressions */
12674 if(f.charCodeAt(0) == 61) {
12675 f = f.slice(1);
12676 if(f.charCodeAt(0) == 61) f = f.slice(1);
12677 }
12678 f = f.replace(/COM\.MICROSOFT\./g, "");
12679 /* Part 3 Section 5.8 References */
12680 f = f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, function($$, $1) { return $1.replace(/\./g,""); });
12681 /* TODO: something other than this */
12682 f = f.replace(/\[.(#[A-Z]*[?!])\]/g, "$1");
12683 return f.replace(/[;~]/g,",").replace(/\|/g,";");
12684}
12685
12686function csf_to_ods_formula(f) {
12687 var o = "of:=" + f.replace(crefregex, "$1[.$2$3$4$5]").replace(/\]:\[/g,":");
12688 /* TODO: something other than this */
12689 return o.replace(/;/g, "|").replace(/,/g,";");
12690}
12691
12692function ods_to_csf_3D(r) {
12693 var a = r.split(":");
12694 var s = a[0].split(".")[0];
12695 return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
12696}
12697
12698function csf_to_ods_3D(r) {
12699 return r.replace(/\./,"!");
12700}
12701
12702var strs = {}; // shared strings
12703var _ssfopts = {}; // spreadsheet formatting options
12704
12705RELS.WS = [
12706 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
12707 "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
12708];
12709
12710/*global Map */
12711var browser_has_Map = typeof Map !== 'undefined';
12712
12713function get_sst_id(sst, str, rev) {
12714 var i = 0, len = sst.length;
12715 if(rev) {
12716 if(browser_has_Map ? rev.has(str) : rev.hasOwnProperty(str)) {
12717 var revarr = browser_has_Map ? rev.get(str) : rev[str];
12718 for(; i < revarr.length; ++i) {
12719 if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
12720 }
12721 }
12722 } else for(; i < len; ++i) {
12723 if(sst[i].t === str) { sst.Count ++; return i; }
12724 }
12725 sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
12726 if(rev) {
12727 if(browser_has_Map) {
12728 if(!rev.has(str)) rev.set(str, []);
12729 rev.get(str).push(len);
12730 } else {
12731 if(!rev.hasOwnProperty(str)) rev[str] = [];
12732 rev[str].push(len);
12733 }
12734 }
12735 return len;
12736}
12737
12738function col_obj_w(C, col) {
12739 var p = ({min:C+1,max:C+1});
12740 /* wch (chars), wpx (pixels) */
12741 var wch = -1;
12742 if(col.MDW) MDW = col.MDW;
12743 if(col.width != null) p.customWidth = 1;
12744 else if(col.wpx != null) wch = px2char(col.wpx);
12745 else if(col.wch != null) wch = col.wch;
12746 if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
12747 else if(col.width != null) p.width = col.width;
12748 if(col.hidden) p.hidden = true;
12749 return p;
12750}
12751
12752function default_margins(margins, mode) {
12753 if(!margins) return;
12754 var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
12755 if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
12756 if(margins.left == null) margins.left = defs[0];
12757 if(margins.right == null) margins.right = defs[1];
12758 if(margins.top == null) margins.top = defs[2];
12759 if(margins.bottom == null) margins.bottom = defs[3];
12760 if(margins.header == null) margins.header = defs[4];
12761 if(margins.footer == null) margins.footer = defs[5];
12762}
12763
12764function get_cell_style(styles, cell, opts) {
12765 var z = opts.revssf[cell.z != null ? cell.z : "General"];
12766 var i = 0x3c, len = styles.length;
12767 if(z == null && opts.ssf) {
12768 for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
12769 SSF.load(cell.z, i);
12770 // $FlowIgnore
12771 opts.ssf[i] = cell.z;
12772 opts.revssf[cell.z] = z = i;
12773 break;
12774 }
12775 }
12776 for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
12777 styles[len] = {
12778 numFmtId:z,
12779 fontId:0,
12780 fillId:0,
12781 borderId:0,
12782 xfId:0,
12783 applyNumberFormat:1
12784 };
12785 return len;
12786}
12787
12788function safe_format(p, fmtid, fillid, opts, themes, styles) {
12789 if(p.t === 'z') return;
12790 if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
12791 try {
12792 if(opts.cellNF) p.z = SSF._table[fmtid];
12793 } catch(e) { if(opts.WTF) throw e; }
12794 if(!opts || opts.cellText !== false) try {
12795 if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
12796 if(p.t === 'e') p.w = p.w || BErr[p.v];
12797 else if(fmtid === 0) {
12798 if(p.t === 'n') {
12799 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
12800 else p.w = SSF._general_num(p.v);
12801 }
12802 else if(p.t === 'd') {
12803 var dd = datenum(p.v);
12804 if((dd|0) === dd) p.w = SSF._general_int(dd);
12805 else p.w = SSF._general_num(dd);
12806 }
12807 else if(p.v === undefined) return "";
12808 else p.w = SSF._general(p.v,_ssfopts);
12809 }
12810 else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
12811 else p.w = SSF.format(fmtid,p.v,_ssfopts);
12812 } catch(e) { if(opts.WTF) throw e; }
12813 if(!opts.cellStyles) return;
12814 if(fillid != null) try {
12815 p.s = styles.Fills[fillid];
12816 if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
12817 p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
12818 if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
12819 }
12820 if (p.s.bgColor && p.s.bgColor.theme) {
12821 p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
12822 if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
12823 }
12824 } catch(e) { if(opts.WTF && styles.Fills) throw e; }
12825}
12826
12827function check_ws(ws, sname, i) {
12828 if(ws && ws['!ref']) {
12829 var range = safe_decode_range(ws['!ref']);
12830 if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
12831 }
12832}
12833function parse_ws_xml_dim(ws, s) {
12834 var d = safe_decode_range(s);
12835 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);
12836}
12837var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
12838var sheetdataregex = /<(?:\w+:)?sheetData>([\s\S]*)<\/(?:\w+:)?sheetData>/;
12839var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
12840var dimregex = /"(\w*:\w*)"/;
12841var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
12842var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
12843var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
12844var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
12845var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
12846/* 18.3 Worksheets */
12847function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
12848 if(!data) return data;
12849 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
12850
12851 /* 18.3.1.99 worksheet CT_Worksheet */
12852 var s = opts.dense ? ([]) : ({});
12853 var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
12854
12855 var data1 = "", data2 = "";
12856 var mtch = data.match(sheetdataregex);
12857 if(mtch) {
12858 data1 = data.slice(0, mtch.index);
12859 data2 = data.slice(mtch.index + mtch[0].length);
12860 } else data1 = data2 = data;
12861
12862 /* 18.3.1.82 sheetPr CT_SheetPr */
12863 var sheetPr = data1.match(sheetprregex);
12864 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
12865
12866 /* 18.3.1.35 dimension CT_SheetDimension */
12867 // $FlowIgnore
12868 var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
12869 if(ridx > 0) {
12870 var ref = data1.slice(ridx,ridx+50).match(dimregex);
12871 if(ref) parse_ws_xml_dim(s, ref[1]);
12872 }
12873
12874 /* 18.3.1.88 sheetViews CT_SheetViews */
12875 var svs = data1.match(svsregex);
12876 if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
12877
12878 /* 18.3.1.17 cols CT_Cols */
12879 var columns = [];
12880 if(opts.cellStyles) {
12881 /* 18.3.1.13 col CT_Col */
12882 var cols = data1.match(colregex);
12883 if(cols) parse_ws_xml_cols(columns, cols);
12884 }
12885
12886 /* 18.3.1.80 sheetData CT_SheetData ? */
12887 if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
12888
12889 /* 18.3.1.2 autoFilter CT_AutoFilter */
12890 var afilter = data2.match(afregex);
12891 if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
12892
12893 /* 18.3.1.55 mergeCells CT_MergeCells */
12894 var merges = [];
12895 var _merge = data2.match(mergecregex);
12896 if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
12897 merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
12898
12899 /* 18.3.1.48 hyperlinks CT_Hyperlinks */
12900 var hlink = data2.match(hlinkregex);
12901 if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
12902
12903 /* 18.3.1.62 pageMargins CT_PageMargins */
12904 var margins = data2.match(marginregex);
12905 if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
12906
12907 if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
12908 if(opts.sheetRows > 0 && s["!ref"]) {
12909 var tmpref = safe_decode_range(s["!ref"]);
12910 if(opts.sheetRows <= +tmpref.e.r) {
12911 tmpref.e.r = opts.sheetRows - 1;
12912 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
12913 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
12914 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
12915 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
12916 s["!fullref"] = s["!ref"];
12917 s["!ref"] = encode_range(tmpref);
12918 }
12919 }
12920 if(columns.length > 0) s["!cols"] = columns;
12921 if(merges.length > 0) s["!merges"] = merges;
12922 return s;
12923}
12924
12925function write_ws_xml_merges(merges) {
12926 if(merges.length === 0) return "";
12927 var o = '<mergeCells count="' + merges.length + '">';
12928 for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
12929 return o + '</mergeCells>';
12930}
12931
12932/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
12933function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
12934 var data = parsexmltag(sheetPr);
12935 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
12936 if(data.codeName) wb.Sheets[idx].CodeName = data.codeName;
12937}
12938
12939/* 18.3.1.85 sheetProtection CT_SheetProtection */
12940function write_ws_xml_protection(sp) {
12941 // algorithmName, hashValue, saltValue, spinCountpassword
12942 var o = ({sheet:1});
12943 var deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
12944 var deftrue = [
12945 "formatColumns", "formatRows", "formatCells",
12946 "insertColumns", "insertRows", "insertHyperlinks",
12947 "deleteColumns", "deleteRows",
12948 "sort", "autoFilter", "pivotTables"
12949 ];
12950 deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
12951 deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
12952 /* TODO: algorithm */
12953 if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
12954 return writextag('sheetProtection', null, o);
12955}
12956
12957function parse_ws_xml_hlinks(s, data, rels) {
12958 var dense = Array.isArray(s);
12959 for(var i = 0; i != data.length; ++i) {
12960 var val = parsexmltag(utf8read(data[i]), true);
12961 if(!val.ref) return;
12962 var rel = ((rels || {})['!id']||[])[val.id];
12963 if(rel) {
12964 val.Target = rel.Target;
12965 if(val.location) val.Target += "#"+val.location;
12966 } else {
12967 val.Target = "#" + val.location;
12968 rel = {Target: val.Target, TargetMode: 'Internal'};
12969 }
12970 val.Rel = rel;
12971 if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
12972 var rng = safe_decode_range(val.ref);
12973 for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
12974 var addr = encode_cell({c:C,r:R});
12975 if(dense) {
12976 if(!s[R]) s[R] = [];
12977 if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
12978 s[R][C].l = val;
12979 } else {
12980 if(!s[addr]) s[addr] = {t:"z",v:undefined};
12981 s[addr].l = val;
12982 }
12983 }
12984 }
12985}
12986
12987function parse_ws_xml_margins(margin) {
12988 var o = {};
12989 ["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
12990 if(margin[k]) o[k] = parseFloat(margin[k]);
12991 });
12992 return o;
12993}
12994function write_ws_xml_margins(margin) {
12995 default_margins(margin);
12996 return writextag('pageMargins', null, margin);
12997}
12998
12999function parse_ws_xml_cols(columns, cols) {
13000 var seencol = false;
13001 for(var coli = 0; coli != cols.length; ++coli) {
13002 var coll = parsexmltag(cols[coli], true);
13003 if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
13004 var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
13005 delete coll.min; delete coll.max; coll.width = +coll.width;
13006 if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
13007 process_col(coll);
13008 while(colm <= colM) columns[colm++] = dup(coll);
13009 }
13010}
13011
13012function write_ws_xml_cols(ws, cols) {
13013 var o = ["<cols>"], col;
13014 for(var i = 0; i != cols.length; ++i) {
13015 if(!(col = cols[i])) continue;
13016 o[o.length] = (writextag('col', null, col_obj_w(i, col)));
13017 }
13018 o[o.length] = "</cols>";
13019 return o.join("");
13020}
13021
13022function parse_ws_xml_autofilter(data) {
13023 var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
13024 return o;
13025}
13026function write_ws_xml_autofilter(data, ws, wb, idx) {
13027 var ref = typeof data.ref == "string" ? data.ref : encode_range(data.ref);
13028 if(!wb.Workbook) wb.Workbook = {};
13029 if(!wb.Workbook.Names) wb.Workbook.Names = [];
13030 var names = wb.Workbook.Names;
13031 var range = decode_range(ref);
13032 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
13033 for(var i = 0; i < names.length; ++i) {
13034 var name = names[i];
13035 if(name.Name != '_xlnm._FilterDatabase') continue;
13036 if(name.Sheet != idx) continue;
13037 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
13038 }
13039 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
13040 return writextag("autoFilter", null, {ref:ref});
13041}
13042
13043/* 18.3.1.88 sheetViews CT_SheetViews */
13044/* 18.3.1.87 sheetView CT_SheetView */
13045var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/>/;
13046function parse_ws_xml_sheetviews(data, wb) {
13047 (data.match(sviewregex)||[]).forEach(function(r) {
13048 var tag = parsexmltag(r);
13049 if(parsexmlbool(tag.rightToLeft)) {
13050 if(!wb.Views) wb.Views = [{}];
13051 if(!wb.Views[0]) wb.Views[0] = {};
13052 wb.Views[0].RTL = true;
13053 }
13054 });
13055}
13056function write_ws_xml_sheetviews(ws, opts, idx, wb) {
13057 var sview = {workbookViewId:"0"};
13058 // $FlowIgnore
13059 if( (((wb||{}).Workbook||{}).Views||[])[0] ) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
13060 return writextag("sheetViews", writextag("sheetView", null, sview), {});
13061}
13062
13063function write_ws_xml_cell(cell, ref, ws, opts) {
13064 if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return "";
13065 var vv = "";
13066 var oldt = cell.t, oldv = cell.v;
13067 switch(cell.t) {
13068 case 'b': vv = cell.v ? "1" : "0"; break;
13069 case 'n': vv = ''+cell.v; break;
13070 case 'e': vv = BErr[cell.v]; break;
13071 case 'd':
13072 if(opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
13073 else {
13074 cell = dup(cell);
13075 cell.t = 'n';
13076 vv = ''+(cell.v = datenum(parseDate(cell.v)));
13077 }
13078 if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
13079 break;
13080 default: vv = cell.v; break;
13081 }
13082 var v = writetag('v', escapexml(vv)), o = ({r:ref});
13083 /* TODO: cell style */
13084 var os = get_cell_style(opts.cellXfs, cell, opts);
13085 if(os !== 0) o.s = os;
13086 switch(cell.t) {
13087 case 'n': break;
13088 case 'd': o.t = "d"; break;
13089 case 'b': o.t = "b"; break;
13090 case 'e': o.t = "e"; break;
13091 default: if(cell.v == null) { delete cell.t; break; }
13092 if(opts.bookSST) {
13093 v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
13094 o.t = "s"; break;
13095 }
13096 o.t = "str"; break;
13097 }
13098 if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
13099 if(cell.f) {
13100 var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
13101 v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
13102 }
13103 if(cell.l) ws['!links'].push([ref, cell.l]);
13104 if(cell.c) ws['!comments'].push([ref, cell.c]);
13105 return writextag('c', v, o);
13106}
13107
13108var parse_ws_xml_data = (function() {
13109 var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
13110 var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
13111 var refregex = /ref=["']([^"']*)["']/;
13112 var match_v = matchtag("v"), match_f = matchtag("f");
13113
13114return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
13115 var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
13116 var tag, tagr = 0, tagc = 0;
13117 var sstr, ftag;
13118 var fmtid = 0, fillid = 0;
13119 var do_format = Array.isArray(styles.CellXf), cf;
13120 var arrayf = [];
13121 var sharedf = [];
13122 var dense = Array.isArray(s);
13123 var rows = [], rowobj = {}, rowrite = false;
13124 for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
13125 x = marr[mt].trim();
13126 var xlen = x.length;
13127 if(xlen === 0) continue;
13128
13129 /* 18.3.1.73 row CT_Row */
13130 for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
13131 tag = parsexmltag(x.slice(0,ri), true);
13132 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
13133 if(opts.sheetRows && opts.sheetRows < tagr) continue;
13134 if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
13135 if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
13136
13137 if(opts && opts.cellStyles) {
13138 rowobj = {}; rowrite = false;
13139 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
13140 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
13141 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
13142 if(rowrite) rows[tagr-1] = rowobj;
13143 }
13144
13145 /* 18.3.1.4 c CT_Cell */
13146 cells = x.slice(ri).split(cellregex);
13147 for(ri = 0; ri != cells.length; ++ri) {
13148 x = cells[ri].trim();
13149 if(x.length === 0) continue;
13150 cref = x.match(rregex); idx = ri; i=0; cc=0;
13151 x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
13152 if(cref != null && cref.length === 2) {
13153 idx = 0; d=cref[1];
13154 for(i=0; i != d.length; ++i) {
13155 if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
13156 idx = 26*idx + cc;
13157 }
13158 --idx;
13159 tagc = idx;
13160 } else ++tagc;
13161 for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
13162 tag = parsexmltag(x.slice(0,i), true);
13163 if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
13164 d = x.slice(i);
13165 p = ({t:""});
13166
13167 if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
13168 if(opts.cellFormula) {
13169 if((cref=d.match(match_f))!= null && cref[1] !== '') {
13170 /* TODO: match against XLSXFutureFunctions */
13171 p.f=_xlfn(unescapexml(utf8read(cref[1])));
13172 if(cref[0].indexOf('t="array"') > -1) {
13173 p.F = (d.match(refregex)||[])[1];
13174 if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
13175 } else if(cref[0].indexOf('t="shared"') > -1) {
13176 // TODO: parse formula
13177 ftag = parsexmltag(cref[0]);
13178 sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1]))), tag.r];
13179 }
13180 } else if((cref=d.match(/<f[^>]*\/>/))) {
13181 ftag = parsexmltag(cref[0]);
13182 if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
13183 }
13184 /* TODO: factor out contains logic */
13185 var _tag = decode_cell(tag.r);
13186 for(i = 0; i < arrayf.length; ++i)
13187 if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
13188 if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
13189 p.F = arrayf[i][1];
13190 }
13191
13192 if(tag.t == null && p.v === undefined) {
13193 if(p.f || p.F) {
13194 p.v = 0; p.t = "n";
13195 } else if(!opts.sheetStubs) continue;
13196 else p.t = "z";
13197 }
13198 else p.t = tag.t || "n";
13199 if(guess.s.c > tagc) guess.s.c = tagc;
13200 if(guess.e.c < tagc) guess.e.c = tagc;
13201 /* 18.18.11 t ST_CellType */
13202 switch(p.t) {
13203 case 'n':
13204 if(p.v == "" || p.v == null) {
13205 if(!opts.sheetStubs) continue;
13206 p.t = 'z';
13207 } else p.v = parseFloat(p.v);
13208 break;
13209 case 's':
13210 if(typeof p.v == 'undefined') {
13211 if(!opts.sheetStubs) continue;
13212 p.t = 'z';
13213 } else {
13214 sstr = strs[parseInt(p.v, 10)];
13215 p.v = sstr.t;
13216 p.r = sstr.r;
13217 if(opts.cellHTML) p.h = sstr.h;
13218 }
13219 break;
13220 case 'str':
13221 p.t = "s";
13222 p.v = (p.v!=null) ? utf8read(p.v) : '';
13223 if(opts.cellHTML) p.h = escapehtml(p.v);
13224 break;
13225 case 'inlineStr':
13226 cref = d.match(isregex);
13227 p.t = 's';
13228 if(cref != null && (sstr = parse_si(cref[1]))) p.v = sstr.t; else p.v = "";
13229 break;
13230 case 'b': p.v = parsexmlbool(p.v); break;
13231 case 'd':
13232 if(opts.cellDates) p.v = parseDate(p.v, 1);
13233 else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
13234 break;
13235 /* error string in .w, number in .v */
13236 case 'e':
13237 if(!opts || opts.cellText !== false) p.w = p.v;
13238 p.v = RBErr[p.v]; break;
13239 }
13240 /* formatting */
13241 fmtid = fillid = 0;
13242 if(do_format && tag.s !== undefined) {
13243 cf = styles.CellXf[tag.s];
13244 if(cf != null) {
13245 if(cf.numFmtId != null) fmtid = cf.numFmtId;
13246 if(opts.cellStyles) {
13247 if(cf.fillId != null) fillid = cf.fillId;
13248 }
13249 }
13250 }
13251 safe_format(p, fmtid, fillid, opts, themes, styles);
13252 if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
13253 if(dense) {
13254 var _r = decode_cell(tag.r);
13255 if(!s[_r.r]) s[_r.r] = [];
13256 s[_r.r][_r.c] = p;
13257 } else s[tag.r] = p;
13258 }
13259 }
13260 if(rows.length > 0) s['!rows'] = rows;
13261}; })();
13262
13263function write_ws_xml_data(ws, opts, idx, wb) {
13264 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
13265 var dense = Array.isArray(ws);
13266 var params = ({r:rr}), row, height = -1;
13267 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
13268 for(R = range.s.r; R <= range.e.r; ++R) {
13269 r = [];
13270 rr = encode_row(R);
13271 for(C = range.s.c; C <= range.e.c; ++C) {
13272 ref = cols[C] + rr;
13273 var _cell = dense ? (ws[R]||[])[C]: ws[ref];
13274 if(_cell === undefined) continue;
13275 if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
13276 }
13277 if(r.length > 0 || (rows && rows[R])) {
13278 params = ({r:rr});
13279 if(rows && rows[R]) {
13280 row = rows[R];
13281 if(row.hidden) params.hidden = 1;
13282 height = -1;
13283 if(row.hpx) height = px2pt(row.hpx);
13284 else if(row.hpt) height = row.hpt;
13285 if(height > -1) { params.ht = height; params.customHeight = 1; }
13286 if(row.level) { params.outlineLevel = row.level; }
13287 }
13288 o[o.length] = (writextag('row', r.join(""), params));
13289 }
13290 }
13291 if(rows) for(; R < rows.length; ++R) {
13292 if(rows && rows[R]) {
13293 params = ({r:R+1});
13294 row = rows[R];
13295 if(row.hidden) params.hidden = 1;
13296 height = -1;
13297 if (row.hpx) height = px2pt(row.hpx);
13298 else if (row.hpt) height = row.hpt;
13299 if (height > -1) { params.ht = height; params.customHeight = 1; }
13300 if (row.level) { params.outlineLevel = row.level; }
13301 o[o.length] = (writextag('row', "", params));
13302 }
13303 }
13304 return o.join("");
13305}
13306
13307var WS_XML_ROOT = writextag('worksheet', null, {
13308 'xmlns': XMLNS.main[0],
13309 'xmlns:r': XMLNS.r
13310});
13311
13312function write_ws_xml(idx, opts, wb, rels) {
13313 var o = [XML_HEADER, WS_XML_ROOT];
13314 var s = wb.SheetNames[idx], sidx = 0, rdata = "";
13315 var ws = wb.Sheets[s];
13316 if(ws == null) ws = {};
13317 var ref = ws['!ref'] || 'A1';
13318 var range = safe_decode_range(ref);
13319 if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
13320 if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
13321 range.e.c = Math.min(range.e.c, 0x3FFF);
13322 range.e.r = Math.min(range.e.c, 0xFFFFF);
13323 ref = encode_range(range);
13324 }
13325 if(!rels) rels = {};
13326 ws['!comments'] = [];
13327 ws['!drawing'] = [];
13328
13329 if(opts.bookType !== 'xlsx' && wb.vbaraw) {
13330 var cname = wb.SheetNames[idx];
13331 try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
13332 o[o.length] = (writextag('sheetPr', null, {'codeName': escapexml(cname)}));
13333 }
13334
13335 o[o.length] = (writextag('dimension', null, {'ref': ref}));
13336
13337 o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
13338
13339 /* TODO: store in WB, process styles */
13340 if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
13341 defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
13342 baseColWidth:opts.sheetFormat.baseColWidth||'10',
13343 outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
13344 }));
13345
13346 if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
13347
13348 o[sidx = o.length] = '<sheetData/>';
13349 ws['!links'] = [];
13350 if(ws['!ref'] != null) {
13351 rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
13352 if(rdata.length > 0) o[o.length] = (rdata);
13353 }
13354 if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
13355
13356 /* sheetCalcPr */
13357
13358 if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
13359
13360 /* protectedRanges */
13361 /* scenarios */
13362
13363 if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter'], ws, wb, idx);
13364
13365 /* sortState */
13366 /* dataConsolidate */
13367 /* customSheetViews */
13368
13369 if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
13370
13371 /* phoneticPr */
13372 /* conditionalFormatting */
13373 /* dataValidations */
13374
13375 var relc = -1, rel, rId = -1;
13376 if(ws['!links'].length > 0) {
13377 o[o.length] = "<hyperlinks>";
13378 ws['!links'].forEach(function(l) {
13379 if(!l[1].Target) return;
13380 rel = ({"ref":l[0]});
13381 if(l[1].Target.charAt(0) != "#") {
13382 rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
13383 rel["r:id"] = "rId"+rId;
13384 }
13385 if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
13386 if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
13387 o[o.length] = writextag("hyperlink",null,rel);
13388 });
13389 o[o.length] = "</hyperlinks>";
13390 }
13391 delete ws['!links'];
13392
13393 /* printOptions */
13394 if (ws['!margins'] != null) o[o.length] = write_ws_xml_margins(ws['!margins']);
13395 /* pageSetup */
13396
13397 //var hfidx = o.length;
13398 o[o.length] = "";
13399
13400 /* rowBreaks */
13401 /* colBreaks */
13402 /* customProperties */
13403 /* cellWatches */
13404
13405 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
13406
13407 /* smartTags */
13408
13409 if(ws['!drawing'].length > 0) {
13410 rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
13411 o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
13412 }
13413 else delete ws['!drawing'];
13414
13415 if(ws['!comments'].length > 0) {
13416 rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
13417 o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
13418 ws['!legacy'] = rId;
13419 }
13420
13421 /* drawingHF */
13422 /* picture */
13423 /* oleObjects */
13424 /* controls */
13425 /* webPublishItems */
13426 /* tableParts */
13427 /* extList */
13428
13429 if(o.length>2) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
13430 return o.join("");
13431}
13432
13433/* [MS-XLSB] 2.4.726 BrtRowHdr */
13434function parse_BrtRowHdr(data, length) {
13435 var z = ({});
13436 var tgt = data.l + length;
13437 z.r = data.read_shift(4);
13438 data.l += 4; // TODO: ixfe
13439 var miyRw = data.read_shift(2);
13440 data.l += 1; // TODO: top/bot padding
13441 var flags = data.read_shift(1);
13442 data.l = tgt;
13443 if(flags & 0x07) z.level = flags & 0x07;
13444 if(flags & 0x10) z.hidden = true;
13445 if(flags & 0x20) z.hpt = miyRw / 20;
13446 return z;
13447}
13448function write_BrtRowHdr(R, range, ws) {
13449 var o = new_buf(17+8*16);
13450 var row = (ws['!rows']||[])[R]||{};
13451 o.write_shift(4, R);
13452
13453 o.write_shift(4, 0); /* TODO: ixfe */
13454
13455 var miyRw = 0x0140;
13456 if(row.hpx) miyRw = px2pt(row.hpx) * 20;
13457 else if(row.hpt) miyRw = row.hpt * 20;
13458 o.write_shift(2, miyRw);
13459
13460 o.write_shift(1, 0); /* top/bot padding */
13461
13462 var flags = 0x0;
13463 if(row.level) flags |= row.level;
13464 if(row.hidden) flags |= 0x10;
13465 if(row.hpx || row.hpt) flags |= 0x20;
13466 o.write_shift(1, flags);
13467
13468 o.write_shift(1, 0); /* phonetic guide */
13469
13470 /* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
13471 var ncolspan = 0, lcs = o.l;
13472 o.l += 4;
13473
13474 var caddr = {r:R, c:0};
13475 for(var i = 0; i < 16; ++i) {
13476 if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue;
13477 var first = -1, last = -1;
13478 for(var j = (i<<10); j < ((i+1)<<10); ++j) {
13479 caddr.c = j;
13480 var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
13481 if(cell) { if(first < 0) first = j; last = j; }
13482 }
13483 if(first < 0) continue;
13484 ++ncolspan;
13485 o.write_shift(4, first);
13486 o.write_shift(4, last);
13487 }
13488
13489 var l = o.l;
13490 o.l = lcs;
13491 o.write_shift(4, ncolspan);
13492 o.l = l;
13493
13494 return o.length > o.l ? o.slice(0, o.l) : o;
13495}
13496function write_row_header(ba, ws, range, R) {
13497 var o = write_BrtRowHdr(R, range, ws);
13498 if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o);
13499}
13500
13501/* [MS-XLSB] 2.4.820 BrtWsDim */
13502var parse_BrtWsDim = parse_UncheckedRfX;
13503var write_BrtWsDim = write_UncheckedRfX;
13504
13505/* [MS-XLSB] 2.4.821 BrtWsFmtInfo */
13506function parse_BrtWsFmtInfo() {
13507}
13508//function write_BrtWsFmtInfo(ws, o) { }
13509
13510/* [MS-XLSB] 2.4.823 BrtWsProp */
13511function parse_BrtWsProp(data, length) {
13512 var z = {};
13513 /* TODO: pull flags */
13514 data.l += 19;
13515 z.name = parse_XLSBCodeName(data, length - 19);
13516 return z;
13517}
13518function write_BrtWsProp(str, o) {
13519 if(o == null) o = new_buf(84+4*str.length);
13520 for(var i = 0; i < 3; ++i) o.write_shift(1,0);
13521 write_BrtColor({auto:1}, o);
13522 o.write_shift(-4,-1);
13523 o.write_shift(-4,-1);
13524 write_XLSBCodeName(str, o);
13525 return o.slice(0, o.l);
13526}
13527
13528/* [MS-XLSB] 2.4.306 BrtCellBlank */
13529function parse_BrtCellBlank(data) {
13530 var cell = parse_XLSBCell(data);
13531 return [cell];
13532}
13533function write_BrtCellBlank(cell, ncell, o) {
13534 if(o == null) o = new_buf(8);
13535 return write_XLSBCell(ncell, o);
13536}
13537
13538
13539/* [MS-XLSB] 2.4.307 BrtCellBool */
13540function parse_BrtCellBool(data) {
13541 var cell = parse_XLSBCell(data);
13542 var fBool = data.read_shift(1);
13543 return [cell, fBool, 'b'];
13544}
13545function write_BrtCellBool(cell, ncell, o) {
13546 if(o == null) o = new_buf(9);
13547 write_XLSBCell(ncell, o);
13548 o.write_shift(1, cell.v ? 1 : 0);
13549 return o;
13550}
13551
13552/* [MS-XLSB] 2.4.308 BrtCellError */
13553function parse_BrtCellError(data) {
13554 var cell = parse_XLSBCell(data);
13555 var bError = data.read_shift(1);
13556 return [cell, bError, 'e'];
13557}
13558
13559/* [MS-XLSB] 2.4.311 BrtCellIsst */
13560function parse_BrtCellIsst(data) {
13561 var cell = parse_XLSBCell(data);
13562 var isst = data.read_shift(4);
13563 return [cell, isst, 's'];
13564}
13565function write_BrtCellIsst(cell, ncell, o) {
13566 if(o == null) o = new_buf(12);
13567 write_XLSBCell(ncell, o);
13568 o.write_shift(4, ncell.v);
13569 return o;
13570}
13571
13572/* [MS-XLSB] 2.4.313 BrtCellReal */
13573function parse_BrtCellReal(data) {
13574 var cell = parse_XLSBCell(data);
13575 var value = parse_Xnum(data);
13576 return [cell, value, 'n'];
13577}
13578function write_BrtCellReal(cell, ncell, o) {
13579 if(o == null) o = new_buf(16);
13580 write_XLSBCell(ncell, o);
13581 write_Xnum(cell.v, o);
13582 return o;
13583}
13584
13585/* [MS-XLSB] 2.4.314 BrtCellRk */
13586function parse_BrtCellRk(data) {
13587 var cell = parse_XLSBCell(data);
13588 var value = parse_RkNumber(data);
13589 return [cell, value, 'n'];
13590}
13591function write_BrtCellRk(cell, ncell, o) {
13592 if(o == null) o = new_buf(12);
13593 write_XLSBCell(ncell, o);
13594 write_RkNumber(cell.v, o);
13595 return o;
13596}
13597
13598
13599/* [MS-XLSB] 2.4.317 BrtCellSt */
13600function parse_BrtCellSt(data) {
13601 var cell = parse_XLSBCell(data);
13602 var value = parse_XLWideString(data);
13603 return [cell, value, 'str'];
13604}
13605function write_BrtCellSt(cell, ncell, o) {
13606 if(o == null) o = new_buf(12 + 4 * cell.v.length);
13607 write_XLSBCell(ncell, o);
13608 write_XLWideString(cell.v, o);
13609 return o.length > o.l ? o.slice(0, o.l) : o;
13610}
13611
13612/* [MS-XLSB] 2.4.653 BrtFmlaBool */
13613function parse_BrtFmlaBool(data, length, opts) {
13614 var end = data.l + length;
13615 var cell = parse_XLSBCell(data);
13616 cell.r = opts['!row'];
13617 var value = data.read_shift(1);
13618 var o = [cell, value, 'b'];
13619 if(opts.cellFormula) {
13620 data.l += 2;
13621 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13622 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13623 }
13624 else data.l = end;
13625 return o;
13626}
13627
13628/* [MS-XLSB] 2.4.654 BrtFmlaError */
13629function parse_BrtFmlaError(data, length, opts) {
13630 var end = data.l + length;
13631 var cell = parse_XLSBCell(data);
13632 cell.r = opts['!row'];
13633 var value = data.read_shift(1);
13634 var o = [cell, value, 'e'];
13635 if(opts.cellFormula) {
13636 data.l += 2;
13637 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13638 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13639 }
13640 else data.l = end;
13641 return o;
13642}
13643
13644/* [MS-XLSB] 2.4.655 BrtFmlaNum */
13645function parse_BrtFmlaNum(data, length, opts) {
13646 var end = data.l + length;
13647 var cell = parse_XLSBCell(data);
13648 cell.r = opts['!row'];
13649 var value = parse_Xnum(data);
13650 var o = [cell, value, 'n'];
13651 if(opts.cellFormula) {
13652 data.l += 2;
13653 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13654 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13655 }
13656 else data.l = end;
13657 return o;
13658}
13659
13660/* [MS-XLSB] 2.4.656 BrtFmlaString */
13661function parse_BrtFmlaString(data, length, opts) {
13662 var end = data.l + length;
13663 var cell = parse_XLSBCell(data);
13664 cell.r = opts['!row'];
13665 var value = parse_XLWideString(data);
13666 var o = [cell, value, 'str'];
13667 if(opts.cellFormula) {
13668 data.l += 2;
13669 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13670 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13671 }
13672 else data.l = end;
13673 return o;
13674}
13675
13676/* [MS-XLSB] 2.4.682 BrtMergeCell */
13677var parse_BrtMergeCell = parse_UncheckedRfX;
13678var write_BrtMergeCell = write_UncheckedRfX;
13679/* [MS-XLSB] 2.4.107 BrtBeginMergeCells */
13680function write_BrtBeginMergeCells(cnt, o) {
13681 if(o == null) o = new_buf(4);
13682 o.write_shift(4, cnt);
13683 return o;
13684}
13685
13686/* [MS-XLSB] 2.4.662 BrtHLink */
13687function parse_BrtHLink(data, length) {
13688 var end = data.l + length;
13689 var rfx = parse_UncheckedRfX(data, 16);
13690 var relId = parse_XLNullableWideString(data);
13691 var loc = parse_XLWideString(data);
13692 var tooltip = parse_XLWideString(data);
13693 var display = parse_XLWideString(data);
13694 data.l = end;
13695 var o = ({rfx:rfx, relId:relId, loc:loc, display:display});
13696 if(tooltip) o.Tooltip = tooltip;
13697 return o;
13698}
13699function write_BrtHLink(l, rId) {
13700 var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
13701 write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
13702 write_RelID("rId" + rId, o);
13703 var locidx = l[1].Target.indexOf("#");
13704 var loc = locidx == -1 ? "" : l[1].Target.slice(locidx+1);
13705 write_XLWideString(loc || "", o);
13706 write_XLWideString(l[1].Tooltip || "", o);
13707 write_XLWideString("", o);
13708 return o.slice(0, o.l);
13709}
13710
13711/* [MS-XLSB] 2.4.6 BrtArrFmla */
13712function parse_BrtArrFmla(data, length, opts) {
13713 var end = data.l + length;
13714 var rfx = parse_RfX(data, 16);
13715 var fAlwaysCalc = data.read_shift(1);
13716 var o = [rfx]; o[2] = fAlwaysCalc;
13717 if(opts.cellFormula) {
13718 var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts);
13719 o[1] = formula;
13720 } else data.l = end;
13721 return o;
13722}
13723
13724/* [MS-XLSB] 2.4.750 BrtShrFmla */
13725function parse_BrtShrFmla(data, length, opts) {
13726 var end = data.l + length;
13727 var rfx = parse_UncheckedRfX(data, 16);
13728 var o = [rfx];
13729 if(opts.cellFormula) {
13730 var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts);
13731 o[1] = formula;
13732 data.l = end;
13733 } else data.l = end;
13734 return o;
13735}
13736
13737/* [MS-XLSB] 2.4.323 BrtColInfo */
13738/* TODO: once XLS ColInfo is set, combine the functions */
13739function write_BrtColInfo(C, col, o) {
13740 if(o == null) o = new_buf(18);
13741 var p = col_obj_w(C, col);
13742 o.write_shift(-4, C);
13743 o.write_shift(-4, C);
13744 o.write_shift(4, (p.width || 10) * 256);
13745 o.write_shift(4, 0/*ixfe*/); // style
13746 var flags = 0;
13747 if(col.hidden) flags |= 0x01;
13748 if(typeof p.width == 'number') flags |= 0x02;
13749 o.write_shift(1, flags); // bit flag
13750 o.write_shift(1, 0); // bit flag
13751 return o;
13752}
13753
13754/* [MS-XLSB] 2.4.678 BrtMargins */
13755var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
13756function parse_BrtMargins(data) {
13757 var margins = ({});
13758 BrtMarginKeys.forEach(function(k) { margins[k] = parse_Xnum(data, 8); });
13759 return margins;
13760}
13761function write_BrtMargins(margins, o) {
13762 if(o == null) o = new_buf(6*8);
13763 default_margins(margins);
13764 BrtMarginKeys.forEach(function(k) { write_Xnum((margins)[k], o); });
13765 return o;
13766}
13767
13768/* [MS-XLSB] 2.4.299 BrtBeginWsView */
13769function parse_BrtBeginWsView(data) {
13770 var f = data.read_shift(2);
13771 data.l += 28;
13772 return { RTL: f & 0x20 };
13773}
13774function write_BrtBeginWsView(ws, Workbook, o) {
13775 if(o == null) o = new_buf(30);
13776 var f = 0x39c;
13777 if((((Workbook||{}).Views||[])[0]||{}).RTL) f |= 0x20;
13778 o.write_shift(2, f); // bit flag
13779 o.write_shift(4, 0);
13780 o.write_shift(4, 0); // view first row
13781 o.write_shift(4, 0); // view first col
13782 o.write_shift(1, 0); // gridline color ICV
13783 o.write_shift(1, 0);
13784 o.write_shift(2, 0);
13785 o.write_shift(2, 100); // zoom scale
13786 o.write_shift(2, 0);
13787 o.write_shift(2, 0);
13788 o.write_shift(2, 0);
13789 o.write_shift(4, 0); // workbook view id
13790 return o;
13791}
13792
13793/* [MS-XLSB] 2.4.309 BrtCellIgnoreEC */
13794function write_BrtCellIgnoreEC(ref) {
13795 var o = new_buf(24);
13796 o.write_shift(4, 4);
13797 o.write_shift(4, 1);
13798 write_UncheckedRfX(ref, o);
13799 return o;
13800}
13801
13802/* [MS-XLSB] 2.4.748 BrtSheetProtection */
13803function write_BrtSheetProtection(sp, o) {
13804 if(o == null) o = new_buf(16*4+2);
13805 o.write_shift(2, sp.password ? crypto_CreatePasswordVerifier_Method1(sp.password) : 0);
13806 o.write_shift(4, 1); // this record should not be written if no protection
13807 [
13808 ["objects", false], // fObjects
13809 ["scenarios", false], // fScenarios
13810 ["formatCells", true], // fFormatCells
13811 ["formatColumns", true], // fFormatColumns
13812 ["formatRows", true], // fFormatRows
13813 ["insertColumns", true], // fInsertColumns
13814 ["insertRows", true], // fInsertRows
13815 ["insertHyperlinks", true], // fInsertHyperlinks
13816 ["deleteColumns", true], // fDeleteColumns
13817 ["deleteRows", true], // fDeleteRows
13818 ["selectLockedCells", false], // fSelLockedCells
13819 ["sort", true], // fSort
13820 ["autoFilter", true], // fAutoFilter
13821 ["pivotTables", true], // fPivotTables
13822 ["selectUnlockedCells", false] // fSelUnlockedCells
13823 ].forEach(function(n) {
13824if(n[1]) o.write_shift(4, sp[n[0]] != null && !sp[n[0]] ? 1 : 0);
13825 else o.write_shift(4, sp[n[0]] != null && sp[n[0]] ? 0 : 1);
13826 });
13827 return o;
13828}
13829
13830/* [MS-XLSB] 2.1.7.61 Worksheet */
13831function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
13832 if(!data) return data;
13833 var opts = _opts || {};
13834 if(!rels) rels = {'!id':{}};
13835 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
13836 var s = (opts.dense ? [] : {});
13837
13838 var ref;
13839 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
13840
13841 var pass = false, end = false;
13842 var row, p, cf, R, C, addr, sstr, rr, cell;
13843 var merges = [];
13844 opts.biff = 12;
13845 opts['!row'] = 0;
13846
13847 var ai = 0, af = false;
13848
13849 var arrayf = [];
13850 var sharedf = {};
13851 var supbooks = opts.supbooks || wb.supbooks || ([[]]);
13852 supbooks.sharedf = sharedf;
13853 supbooks.arrayf = arrayf;
13854 supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; });
13855 if(!opts.supbooks) {
13856 opts.supbooks = supbooks;
13857 if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i];
13858 }
13859
13860 var colinfo = [], rowinfo = [];
13861 var seencol = false;
13862
13863 recordhopper(data, function ws_parse(val, R_n, RT) {
13864 if(end) return;
13865 switch(RT) {
13866 case 0x0094: /* 'BrtWsDim' */
13867 ref = val; break;
13868 case 0x0000: /* 'BrtRowHdr' */
13869 row = val;
13870 if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
13871 rr = encode_row(R = row.r);
13872 opts['!row'] = row.r;
13873 if(val.hidden || val.hpt || val.level != null) {
13874 if(val.hpt) val.hpx = pt2px(val.hpt);
13875 rowinfo[val.r] = val;
13876 }
13877 break;
13878
13879 case 0x0002: /* 'BrtCellRk' */
13880 case 0x0003: /* 'BrtCellError' */
13881 case 0x0004: /* 'BrtCellBool' */
13882 case 0x0005: /* 'BrtCellReal' */
13883 case 0x0006: /* 'BrtCellSt' */
13884 case 0x0007: /* 'BrtCellIsst' */
13885 case 0x0008: /* 'BrtFmlaString' */
13886 case 0x0009: /* 'BrtFmlaNum' */
13887 case 0x000A: /* 'BrtFmlaBool' */
13888 case 0x000B: /* 'BrtFmlaError' */
13889 p = ({t:val[2]});
13890 switch(val[2]) {
13891 case 'n': p.v = val[1]; break;
13892 case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
13893 case 'b': p.v = val[1] ? true : false; break;
13894 case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
13895 case 'str': p.t = 's'; p.v = val[1]; break;
13896 }
13897 if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
13898 C = val[0].c;
13899 if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
13900 else s[encode_col(C) + rr] = p;
13901 if(opts.cellFormula) {
13902 af = false;
13903 for(ai = 0; ai < arrayf.length; ++ai) {
13904 var aii = arrayf[ai];
13905 if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
13906 if(C >= aii[0].s.c && C <= aii[0].e.c) {
13907 p.F = encode_range(aii[0]); af = true;
13908 }
13909 }
13910 if(!af && val.length > 3) p.f = val[3];
13911 }
13912 if(refguess.s.r > row.r) refguess.s.r = row.r;
13913 if(refguess.s.c > C) refguess.s.c = C;
13914 if(refguess.e.r < row.r) refguess.e.r = row.r;
13915 if(refguess.e.c < C) refguess.e.c = C;
13916 if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
13917 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); }
13918 }
13919 break;
13920
13921 case 0x0001: /* 'BrtCellBlank' */
13922 if(!opts.sheetStubs || pass) break;
13923 p = ({t:'z',v:undefined});
13924 C = val[0].c;
13925 if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
13926 else s[encode_col(C) + rr] = p;
13927 if(refguess.s.r > row.r) refguess.s.r = row.r;
13928 if(refguess.s.c > C) refguess.s.c = C;
13929 if(refguess.e.r < row.r) refguess.e.r = row.r;
13930 if(refguess.e.c < C) refguess.e.c = C;
13931 break;
13932
13933 case 0x00B0: /* 'BrtMergeCell' */
13934 merges.push(val); break;
13935
13936 case 0x01EE: /* 'BrtHLink' */
13937 var rel = rels['!id'][val.relId];
13938 if(rel) {
13939 val.Target = rel.Target;
13940 if(val.loc) val.Target += "#"+val.loc;
13941 val.Rel = rel;
13942 } else if(val.relId == '') {
13943 val.Target = "#" + val.loc;
13944 }
13945 for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
13946 if(opts.dense) {
13947 if(!s[R]) s[R] = [];
13948 if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
13949 s[R][C].l = val;
13950 } else {
13951 addr = encode_cell({c:C,r:R});
13952 if(!s[addr]) s[addr] = {t:'z',v:undefined};
13953 s[addr].l = val;
13954 }
13955 }
13956 break;
13957
13958 case 0x01AA: /* 'BrtArrFmla' */
13959 if(!opts.cellFormula) break;
13960 arrayf.push(val);
13961 cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr]));
13962 cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
13963 cell.F = encode_range(val[0]);
13964 break;
13965 case 0x01AB: /* 'BrtShrFmla' */
13966 if(!opts.cellFormula) break;
13967 sharedf[encode_cell(val[0].s)] = val[1];
13968 cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
13969 cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
13970 break;
13971
13972 /* identical to 'ColInfo' in XLS */
13973 case 0x003C: /* 'BrtColInfo' */
13974 if(!opts.cellStyles) break;
13975 while(val.e >= val.s) {
13976 colinfo[val.e--] = { width: val.w/256, hidden: !!(val.flags & 0x01) };
13977 if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
13978 process_col(colinfo[val.e+1]);
13979 }
13980 break;
13981
13982 case 0x00A1: /* 'BrtBeginAFilter' */
13983 s['!autofilter'] = { ref:encode_range(val) };
13984 break;
13985
13986 case 0x01DC: /* 'BrtMargins' */
13987 s['!margins'] = val;
13988 break;
13989
13990 case 0x0093: /* 'BrtWsProp' */
13991 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13992 if(val.name) wb.Sheets[idx].CodeName = val.name;
13993 break;
13994
13995 case 0x0089: /* 'BrtBeginWsView' */
13996 if(!wb.Views) wb.Views = [{}];
13997 if(!wb.Views[0]) wb.Views[0] = {};
13998 if(val.RTL) wb.Views[0].RTL = true;
13999 break;
14000
14001 case 0x01E5: /* 'BrtWsFmtInfo' */
14002 break;
14003 case 0x00AF: /* 'BrtAFilterDateGroupItem' */
14004 case 0x0284: /* 'BrtActiveX' */
14005 case 0x0271: /* 'BrtBigName' */
14006 case 0x0232: /* 'BrtBkHim' */
14007 case 0x018C: /* 'BrtBrk' */
14008 case 0x0458: /* 'BrtCFIcon' */
14009 case 0x047A: /* 'BrtCFRuleExt' */
14010 case 0x01D7: /* 'BrtCFVO' */
14011 case 0x041A: /* 'BrtCFVO14' */
14012 case 0x0289: /* 'BrtCellIgnoreEC' */
14013 case 0x0451: /* 'BrtCellIgnoreEC14' */
14014 case 0x0031: /* 'BrtCellMeta' */
14015 case 0x024D: /* 'BrtCellSmartTagProperty' */
14016 case 0x025F: /* 'BrtCellWatch' */
14017 case 0x0234: /* 'BrtColor' */
14018 case 0x041F: /* 'BrtColor14' */
14019 case 0x00A8: /* 'BrtColorFilter' */
14020 case 0x00AE: /* 'BrtCustomFilter' */
14021 case 0x049C: /* 'BrtCustomFilter14' */
14022 case 0x01F3: /* 'BrtDRef' */
14023 case 0x0040: /* 'BrtDVal' */
14024 case 0x041D: /* 'BrtDVal14' */
14025 case 0x0226: /* 'BrtDrawing' */
14026 case 0x00AB: /* 'BrtDynamicFilter' */
14027 case 0x00A7: /* 'BrtFilter' */
14028 case 0x0499: /* 'BrtFilter14' */
14029 case 0x00A9: /* 'BrtIconFilter' */
14030 case 0x049D: /* 'BrtIconFilter14' */
14031 case 0x0227: /* 'BrtLegacyDrawing' */
14032 case 0x0228: /* 'BrtLegacyDrawingHF' */
14033 case 0x0295: /* 'BrtListPart' */
14034 case 0x027F: /* 'BrtOleObject' */
14035 case 0x01DE: /* 'BrtPageSetup' */
14036 case 0x0097: /* 'BrtPane' */
14037 case 0x0219: /* 'BrtPhoneticInfo' */
14038 case 0x01DD: /* 'BrtPrintOptions' */
14039 case 0x0218: /* 'BrtRangeProtection' */
14040 case 0x044F: /* 'BrtRangeProtection14' */
14041 case 0x02A8: /* 'BrtRangeProtectionIso' */
14042 case 0x0450: /* 'BrtRangeProtectionIso14' */
14043 case 0x0400: /* 'BrtRwDescent' */
14044 case 0x0098: /* 'BrtSel' */
14045 case 0x0297: /* 'BrtSheetCalcProp' */
14046 case 0x0217: /* 'BrtSheetProtection' */
14047 case 0x02A6: /* 'BrtSheetProtectionIso' */
14048 case 0x01F8: /* 'BrtSlc' */
14049 case 0x0413: /* 'BrtSparkline' */
14050 case 0x01AC: /* 'BrtTable' */
14051 case 0x00AA: /* 'BrtTop10Filter' */
14052 case 0x0C00: /* 'BrtUid' */
14053 case 0x0032: /* 'BrtValueMeta' */
14054 case 0x0816: /* 'BrtWebExtension' */
14055 case 0x0415: /* 'BrtWsFmtInfoEx14' */
14056 break;
14057
14058 case 0x0023: /* 'BrtFRTBegin' */
14059 pass = true; break;
14060 case 0x0024: /* 'BrtFRTEnd' */
14061 pass = false; break;
14062 case 0x0025: /* 'BrtACBegin' */ break;
14063 case 0x0026: /* 'BrtACEnd' */ break;
14064
14065 default:
14066 if((R_n||"").indexOf("Begin") > 0){/* empty */}
14067 else if((R_n||"").indexOf("End") > 0){/* empty */}
14068 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14069 }
14070 }, opts);
14071
14072 delete opts.supbooks;
14073 delete opts['!row'];
14074
14075 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);
14076 if(opts.sheetRows && s["!ref"]) {
14077 var tmpref = safe_decode_range(s["!ref"]);
14078 if(opts.sheetRows <= +tmpref.e.r) {
14079 tmpref.e.r = opts.sheetRows - 1;
14080 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
14081 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
14082 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
14083 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
14084 s["!fullref"] = s["!ref"];
14085 s["!ref"] = encode_range(tmpref);
14086 }
14087 }
14088 if(merges.length > 0) s["!merges"] = merges;
14089 if(colinfo.length > 0) s["!cols"] = colinfo;
14090 if(rowinfo.length > 0) s["!rows"] = rowinfo;
14091 return s;
14092}
14093
14094/* TODO: something useful -- this is a stub */
14095function write_ws_bin_cell(ba, cell, R, C, opts, ws) {
14096 if(cell.v === undefined) return "";
14097 var vv = "";
14098 switch(cell.t) {
14099 case 'b': vv = cell.v ? "1" : "0"; break;
14100 case 'd': // no BrtCellDate :(
14101 cell = dup(cell);
14102 cell.z = cell.z || SSF._table[14];
14103 cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
14104 break;
14105 /* falls through */
14106 case 'n': case 'e': vv = ''+cell.v; break;
14107 default: vv = cell.v; break;
14108 }
14109 var o = ({r:R, c:C});
14110 /* TODO: cell style */
14111 o.s = get_cell_style(opts.cellXfs, cell, opts);
14112 if(cell.l) ws['!links'].push([encode_cell(o), cell.l]);
14113 if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
14114 switch(cell.t) {
14115 case 's': case 'str':
14116 if(opts.bookSST) {
14117 vv = get_sst_id(opts.Strings, (cell.v), opts.revStrings);
14118 o.t = "s"; o.v = vv;
14119 write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
14120 } else {
14121 o.t = "str";
14122 write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
14123 }
14124 return;
14125 case 'n':
14126 /* TODO: determine threshold for Real vs RK */
14127 if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
14128 else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
14129 return;
14130 case 'b':
14131 o.t = "b";
14132 write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
14133 return;
14134 case 'e': /* TODO: error */ o.t = "e"; break;
14135 }
14136 write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
14137}
14138
14139function write_CELLTABLE(ba, ws, idx, opts) {
14140 var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
14141 write_record(ba, 'BrtBeginSheetData');
14142 var dense = Array.isArray(ws);
14143 var cap = range.e.r;
14144 if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1);
14145 for(var R = range.s.r; R <= cap; ++R) {
14146 rr = encode_row(R);
14147 /* [ACCELLTABLE] */
14148 /* BrtRowHdr */
14149 write_row_header(ba, ws, range, R);
14150 if(R <= range.e.r) for(var C = range.s.c; C <= range.e.c; ++C) {
14151 /* *16384CELL */
14152 if(R === range.s.r) cols[C] = encode_col(C);
14153 ref = cols[C] + rr;
14154 var cell = dense ? (ws[R]||[])[C] : ws[ref];
14155 if(!cell) continue;
14156 /* write cell */
14157 write_ws_bin_cell(ba, cell, R, C, opts, ws);
14158 }
14159 }
14160 write_record(ba, 'BrtEndSheetData');
14161}
14162
14163function write_MERGECELLS(ba, ws) {
14164 if(!ws || !ws['!merges']) return;
14165 write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
14166 ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
14167 write_record(ba, 'BrtEndMergeCells');
14168}
14169
14170function write_COLINFOS(ba, ws) {
14171 if(!ws || !ws['!cols']) return;
14172 write_record(ba, 'BrtBeginColInfos');
14173 ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
14174 write_record(ba, 'BrtEndColInfos');
14175}
14176
14177function write_IGNOREECS(ba, ws) {
14178 if(!ws || !ws['!ref']) return;
14179 write_record(ba, 'BrtBeginCellIgnoreECs');
14180 write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref'])));
14181 write_record(ba, 'BrtEndCellIgnoreECs');
14182}
14183
14184function write_HLINKS(ba, ws, rels) {
14185 /* *BrtHLink */
14186 ws['!links'].forEach(function(l) {
14187 if(!l[1].Target) return;
14188 var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK);
14189 write_record(ba, "BrtHLink", write_BrtHLink(l, rId));
14190 });
14191 delete ws['!links'];
14192}
14193function write_LEGACYDRAWING(ba, ws, idx, rels) {
14194 /* [BrtLegacyDrawing] */
14195 if(ws['!comments'].length > 0) {
14196 var rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
14197 write_record(ba, "BrtLegacyDrawing", write_RelID("rId" + rId));
14198 ws['!legacy'] = rId;
14199 }
14200}
14201
14202function write_AUTOFILTER(ba, ws) {
14203 if(!ws['!autofilter']) return;
14204 write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ws['!autofilter'].ref)));
14205 /* *FILTERCOLUMN */
14206 /* [SORTSTATE] */
14207 /* BrtEndAFilter */
14208 write_record(ba, "BrtEndAFilter");
14209}
14210
14211function write_WSVIEWS2(ba, ws, Workbook) {
14212 write_record(ba, "BrtBeginWsViews");
14213 { /* 1*WSVIEW2 */
14214 /* [ACUID] */
14215 write_record(ba, "BrtBeginWsView", write_BrtBeginWsView(ws, Workbook));
14216 /* [BrtPane] */
14217 /* *4BrtSel */
14218 /* *4SXSELECT */
14219 /* *FRT */
14220 write_record(ba, "BrtEndWsView");
14221 }
14222 /* *FRT */
14223 write_record(ba, "BrtEndWsViews");
14224}
14225
14226function write_WSFMTINFO() {
14227 /* [ACWSFMTINFO] */
14228 //write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
14229}
14230
14231function write_SHEETPROTECT(ba, ws) {
14232 if(!ws['!protect']) return;
14233 /* [BrtSheetProtectionIso] */
14234 write_record(ba, "BrtSheetProtection", write_BrtSheetProtection(ws['!protect']));
14235}
14236
14237function write_ws_bin(idx, opts, wb, rels) {
14238 var ba = buf_array();
14239 var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
14240 var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
14241 var r = safe_decode_range(ws['!ref'] || "A1");
14242 if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
14243 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
14244 r.e.c = Math.min(r.e.c, 0x3FFF);
14245 r.e.r = Math.min(r.e.c, 0xFFFFF);
14246 }
14247 ws['!links'] = [];
14248 /* passed back to write_zip and removed there */
14249 ws['!comments'] = [];
14250 write_record(ba, "BrtBeginSheet");
14251 if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
14252 write_record(ba, "BrtWsDim", write_BrtWsDim(r));
14253 write_WSVIEWS2(ba, ws, wb.Workbook);
14254 write_WSFMTINFO(ba, ws);
14255 write_COLINFOS(ba, ws, idx, opts, wb);
14256 write_CELLTABLE(ba, ws, idx, opts, wb);
14257 /* [BrtSheetCalcProp] */
14258 write_SHEETPROTECT(ba, ws);
14259 /* *([BrtRangeProtectionIso] BrtRangeProtection) */
14260 /* [SCENMAN] */
14261 write_AUTOFILTER(ba, ws);
14262 /* [SORTSTATE] */
14263 /* [DCON] */
14264 /* [USERSHVIEWS] */
14265 write_MERGECELLS(ba, ws);
14266 /* [BrtPhoneticInfo] */
14267 /* *CONDITIONALFORMATTING */
14268 /* [DVALS] */
14269 write_HLINKS(ba, ws, rels);
14270 /* [BrtPrintOptions] */
14271 if(ws['!margins']) write_record(ba, "BrtMargins", write_BrtMargins(ws['!margins']));
14272 /* [BrtPageSetup] */
14273 /* [HEADERFOOTER] */
14274 /* [RWBRK] */
14275 /* [COLBRK] */
14276 /* *BrtBigName */
14277 /* [CELLWATCHES] */
14278 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) write_IGNOREECS(ba, ws);
14279 /* [SMARTTAGS] */
14280 /* [BrtDrawing] */
14281 write_LEGACYDRAWING(ba, ws, idx, rels);
14282 /* [BrtLegacyDrawingHF] */
14283 /* [BrtBkHim] */
14284 /* [OLEOBJECTS] */
14285 /* [ACTIVEXCONTROLS] */
14286 /* [WEBPUBITEMS] */
14287 /* [LISTPARTS] */
14288 /* FRTWORKSHEET */
14289 write_record(ba, "BrtEndSheet");
14290 return ba.end();
14291}
14292function parse_numCache(data) {
14293 var col = [];
14294
14295 /* 21.2.2.150 pt CT_NumVal */
14296 (data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
14297 var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
14298 if(!q) return;
14299 col[+q[1]] = +q[2];
14300 });
14301
14302 /* 21.2.2.71 formatCode CT_Xstring */
14303 var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
14304
14305 return [col, nf];
14306}
14307
14308/* 21.2 DrawingML - Charts */
14309function parse_chart(data, name, opts, rels, wb, csheet) {
14310 var cs = ((csheet || {"!type":"chart"}));
14311 if(!data) return csheet;
14312 /* 21.2.2.27 chart CT_Chart */
14313
14314 var C = 0, R = 0, col = "A";
14315 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14316
14317 /* 21.2.2.120 numCache CT_NumData */
14318 (data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
14319 var cache = parse_numCache(nc);
14320 refguess.s.r = refguess.s.c = 0;
14321 refguess.e.c = C;
14322 col = encode_col(C);
14323 cache[0].forEach(function(n,i) {
14324 cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
14325 R = i;
14326 });
14327 if(refguess.e.r < R) refguess.e.r = R;
14328 ++C;
14329 });
14330 if(C > 0) cs["!ref"] = encode_range(refguess);
14331 return cs;
14332}
14333RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
14334
14335var CS_XML_ROOT = writextag('chartsheet', null, {
14336 'xmlns': XMLNS.main[0],
14337 'xmlns:r': XMLNS.r
14338});
14339
14340/* 18.3 Worksheets also covers Chartsheets */
14341function parse_cs_xml(data, opts, idx, rels, wb) {
14342 if(!data) return data;
14343 /* 18.3.1.12 chartsheet CT_ChartSheet */
14344 if(!rels) rels = {'!id':{}};
14345 var s = {'!type':"chart", '!chart':null, '!rel':""};
14346 var m;
14347
14348 /* 18.3.1.83 sheetPr CT_ChartsheetPr */
14349 var sheetPr = data.match(sheetprregex);
14350 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
14351
14352 /* 18.3.1.36 drawing CT_Drawing */
14353 if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
14354
14355 if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']];
14356 return s;
14357}
14358function write_cs_xml(idx, opts, wb, rels) {
14359 var o = [XML_HEADER, CS_XML_ROOT];
14360 o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
14361 add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
14362 if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
14363 return o.join("");
14364}
14365
14366/* [MS-XLSB] 2.4.331 BrtCsProp */
14367function parse_BrtCsProp(data, length) {
14368 data.l += 10;
14369 var name = parse_XLWideString(data, length - 10);
14370 return { name: name };
14371}
14372
14373/* [MS-XLSB] 2.1.7.7 Chart Sheet */
14374function parse_cs_bin(data, opts, idx, rels, wb) {
14375 if(!data) return data;
14376 if(!rels) rels = {'!id':{}};
14377 var s = {'!type':"chart", '!chart':null, '!rel':""};
14378 var state = [];
14379 var pass = false;
14380 recordhopper(data, function cs_parse(val, R_n, RT) {
14381 switch(RT) {
14382
14383 case 0x0226: /* 'BrtDrawing' */
14384 s['!rel'] = val; break;
14385
14386 case 0x028B: /* 'BrtCsProp' */
14387 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
14388 if(val.name) wb.Sheets[idx].CodeName = val.name;
14389 break;
14390
14391 case 0x0232: /* 'BrtBkHim' */
14392 case 0x028C: /* 'BrtCsPageSetup' */
14393 case 0x029D: /* 'BrtCsProtection' */
14394 case 0x02A7: /* 'BrtCsProtectionIso' */
14395 case 0x0227: /* 'BrtLegacyDrawing' */
14396 case 0x0228: /* 'BrtLegacyDrawingHF' */
14397 case 0x01DC: /* 'BrtMargins' */
14398 case 0x0C00: /* 'BrtUid' */
14399 break;
14400
14401 case 0x0023: /* 'BrtFRTBegin' */
14402 pass = true; break;
14403 case 0x0024: /* 'BrtFRTEnd' */
14404 pass = false; break;
14405 case 0x0025: /* 'BrtACBegin' */
14406 state.push(R_n); break;
14407 case 0x0026: /* 'BrtACEnd' */
14408 state.pop(); break;
14409
14410 default:
14411 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
14412 else if((R_n||"").indexOf("End") > 0) state.pop();
14413 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14414 }
14415 }, opts);
14416
14417 if(rels['!id'][s['!rel']]) s['!chart'] = rels['!id'][s['!rel']];
14418 return s;
14419}
14420function write_cs_bin() {
14421 var ba = buf_array();
14422 write_record(ba, "BrtBeginSheet");
14423 /* [BrtCsProp] */
14424 /* CSVIEWS */
14425 /* [[BrtCsProtectionIso] BrtCsProtection] */
14426 /* [USERCSVIEWS] */
14427 /* [BrtMargins] */
14428 /* [BrtCsPageSetup] */
14429 /* [HEADERFOOTER] */
14430 /* BrtDrawing */
14431 /* [BrtLegacyDrawing] */
14432 /* [BrtLegacyDrawingHF] */
14433 /* [BrtBkHim] */
14434 /* [WEBPUBITEMS] */
14435 /* FRTCHARTSHEET */
14436 write_record(ba, "BrtEndSheet");
14437 return ba.end();
14438}
14439/* 18.2.28 (CT_WorkbookProtection) Defaults */
14440var WBPropsDef = [
14441 ['allowRefreshQuery', false, "bool"],
14442 ['autoCompressPictures', true, "bool"],
14443 ['backupFile', false, "bool"],
14444 ['checkCompatibility', false, "bool"],
14445 ['CodeName', ''],
14446 ['date1904', false, "bool"],
14447 ['defaultThemeVersion', 0, "int"],
14448 ['filterPrivacy', false, "bool"],
14449 ['hidePivotFieldList', false, "bool"],
14450 ['promptedSolutions', false, "bool"],
14451 ['publishItems', false, "bool"],
14452 ['refreshAllConnections', false, "bool"],
14453 ['saveExternalLinkValues', true, "bool"],
14454 ['showBorderUnselectedTables', true, "bool"],
14455 ['showInkAnnotation', true, "bool"],
14456 ['showObjects', 'all'],
14457 ['showPivotChartFilter', false, "bool"],
14458 ['updateLinks', 'userSet']
14459];
14460
14461/* 18.2.30 (CT_BookView) Defaults */
14462var WBViewDef = [
14463 ['activeTab', 0, "int"],
14464 ['autoFilterDateGrouping', true, "bool"],
14465 ['firstSheet', 0, "int"],
14466 ['minimized', false, "bool"],
14467 ['showHorizontalScroll', true, "bool"],
14468 ['showSheetTabs', true, "bool"],
14469 ['showVerticalScroll', true, "bool"],
14470 ['tabRatio', 600, "int"],
14471 ['visibility', 'visible']
14472 //window{Height,Width}, {x,y}Window
14473];
14474
14475/* 18.2.19 (CT_Sheet) Defaults */
14476var SheetDef = [
14477 //['state', 'visible']
14478];
14479
14480/* 18.2.2 (CT_CalcPr) Defaults */
14481var CalcPrDef = [
14482 ['calcCompleted', 'true'],
14483 ['calcMode', 'auto'],
14484 ['calcOnSave', 'true'],
14485 ['concurrentCalc', 'true'],
14486 ['fullCalcOnLoad', 'false'],
14487 ['fullPrecision', 'true'],
14488 ['iterate', 'false'],
14489 ['iterateCount', '100'],
14490 ['iterateDelta', '0.001'],
14491 ['refMode', 'A1']
14492];
14493
14494/* 18.2.3 (CT_CustomWorkbookView) Defaults */
14495/*var CustomWBViewDef = [
14496 ['autoUpdate', 'false'],
14497 ['changesSavedWin', 'false'],
14498 ['includeHiddenRowCol', 'true'],
14499 ['includePrintSettings', 'true'],
14500 ['maximized', 'false'],
14501 ['minimized', 'false'],
14502 ['onlySync', 'false'],
14503 ['personalView', 'false'],
14504 ['showComments', 'commIndicator'],
14505 ['showFormulaBar', 'true'],
14506 ['showHorizontalScroll', 'true'],
14507 ['showObjects', 'all'],
14508 ['showSheetTabs', 'true'],
14509 ['showStatusbar', 'true'],
14510 ['showVerticalScroll', 'true'],
14511 ['tabRatio', '600'],
14512 ['xWindow', '0'],
14513 ['yWindow', '0']
14514];*/
14515
14516function push_defaults_array(target, defaults) {
14517 for(var j = 0; j != target.length; ++j) { var w = target[j];
14518 for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
14519 if(w[z[0]] == null) w[z[0]] = z[1];
14520 else switch(z[2]) {
14521 case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
14522 case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
14523 }
14524 }
14525 }
14526}
14527function push_defaults(target, defaults) {
14528 for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
14529 if(target[z[0]] == null) target[z[0]] = z[1];
14530 else switch(z[2]) {
14531 case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
14532 case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
14533 }
14534 }
14535}
14536
14537function parse_wb_defaults(wb) {
14538 push_defaults(wb.WBProps, WBPropsDef);
14539 push_defaults(wb.CalcPr, CalcPrDef);
14540
14541 push_defaults_array(wb.WBView, WBViewDef);
14542 push_defaults_array(wb.Sheets, SheetDef);
14543
14544 _ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
14545}
14546
14547function safe1904(wb) {
14548 /* TODO: store date1904 somewhere else */
14549 if(!wb.Workbook) return "false";
14550 if(!wb.Workbook.WBProps) return "false";
14551 return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
14552}
14553
14554var badchars = "][*?\/\\".split("");
14555function check_ws_name(n, safe) {
14556 if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
14557 var _good = true;
14558 badchars.forEach(function(c) {
14559 if(n.indexOf(c) == -1) return;
14560 if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
14561 _good = false;
14562 });
14563 return _good;
14564}
14565function check_wb_names(N, S, codes) {
14566 N.forEach(function(n,i) {
14567 check_ws_name(n);
14568 for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
14569 if(codes) {
14570 var cn = (S && S[i] && S[i].CodeName) || n;
14571 if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
14572 }
14573 });
14574}
14575function check_wb(wb) {
14576 if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
14577 if(!wb.SheetNames.length) throw new Error("Workbook is empty");
14578 var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
14579 check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
14580 for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
14581 /* TODO: validate workbook */
14582}
14583/* 18.2 Workbook */
14584var wbnsregex = /<\w+:workbook/;
14585function parse_wb_xml(data, opts) {
14586 if(!data) throw new Error("Could not find file");
14587 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
14588 var pass = false, xmlns = "xmlns";
14589 var dname = {}, dnstart = 0;
14590 data.replace(tagregex, function xml_wb(x, idx) {
14591 var y = parsexmltag(x);
14592 switch(strip_ns(y[0])) {
14593 case '<?xml': break;
14594
14595 /* 18.2.27 workbook CT_Workbook 1 */
14596 case '<workbook':
14597 if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
14598 wb.xmlns = y[xmlns];
14599 break;
14600 case '</workbook>': break;
14601
14602 /* 18.2.13 fileVersion CT_FileVersion ? */
14603 case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
14604 case '<fileVersion/>': case '</fileVersion>': break;
14605
14606 /* 18.2.12 fileSharing CT_FileSharing ? */
14607 case '<fileSharing': case '<fileSharing/>': break;
14608
14609 /* 18.2.28 workbookPr CT_WorkbookPr ? */
14610 case '<workbookPr':
14611 case '<workbookPr/>':
14612 WBPropsDef.forEach(function(w) {
14613 if(y[w[0]] == null) return;
14614 switch(w[2]) {
14615 case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
14616 case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
14617 default: wb.WBProps[w[0]] = y[w[0]];
14618 }
14619 });
14620 if(y.codeName) wb.WBProps.CodeName = y.codeName;
14621 break;
14622 case '</workbookPr>': break;
14623
14624 /* 18.2.29 workbookProtection CT_WorkbookProtection ? */
14625 case '<workbookProtection': break;
14626 case '<workbookProtection/>': break;
14627
14628 /* 18.2.1 bookViews CT_BookViews ? */
14629 case '<bookViews': case '<bookViews>': case '</bookViews>': break;
14630 /* 18.2.30 workbookView CT_BookView + */
14631 case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
14632 case '</workbookView>': break;
14633
14634 /* 18.2.20 sheets CT_Sheets 1 */
14635 case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
14636 /* 18.2.19 sheet CT_Sheet + */
14637 case '<sheet':
14638 switch(y.state) {
14639 case "hidden": y.Hidden = 1; break;
14640 case "veryHidden": y.Hidden = 2; break;
14641 default: y.Hidden = 0;
14642 }
14643 delete y.state;
14644 y.name = unescapexml(utf8read(y.name));
14645 delete y[0]; wb.Sheets.push(y); break;
14646 case '</sheet>': break;
14647
14648 /* 18.2.15 functionGroups CT_FunctionGroups ? */
14649 case '<functionGroups': case '<functionGroups/>': break;
14650 /* 18.2.14 functionGroup CT_FunctionGroup + */
14651 case '<functionGroup': break;
14652
14653 /* 18.2.9 externalReferences CT_ExternalReferences ? */
14654 case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
14655 /* 18.2.8 externalReference CT_ExternalReference + */
14656 case '<externalReference': break;
14657
14658 /* 18.2.6 definedNames CT_DefinedNames ? */
14659 case '<definedNames/>': break;
14660 case '<definedNames>': case '<definedNames': pass=true; break;
14661 case '</definedNames>': pass=false; break;
14662 /* 18.2.5 definedName CT_DefinedName + */
14663 case '<definedName': {
14664 dname = {};
14665 dname.Name = utf8read(y.name);
14666 if(y.comment) dname.Comment = y.comment;
14667 if(y.localSheetId) dname.Sheet = +y.localSheetId;
14668 if(parsexmlbool(y.hidden||"0")) dname.Hidden = true;
14669 dnstart = idx + x.length;
14670 } break;
14671 case '</definedName>': {
14672 dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
14673 wb.Names.push(dname);
14674 } break;
14675 case '<definedName/>': break;
14676
14677 /* 18.2.2 calcPr CT_CalcPr ? */
14678 case '<calcPr': delete y[0]; wb.CalcPr = y; break;
14679 case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
14680 case '</calcPr>': break;
14681
14682 /* 18.2.16 oleSize CT_OleSize ? (ref required) */
14683 case '<oleSize': break;
14684
14685 /* 18.2.4 customWorkbookViews CT_CustomWorkbookViews ? */
14686 case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
14687 /* 18.2.3 customWorkbookView CT_CustomWorkbookView + */
14688 case '<customWorkbookView': case '</customWorkbookView>': break;
14689
14690 /* 18.2.18 pivotCaches CT_PivotCaches ? */
14691 case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
14692 /* 18.2.17 pivotCache CT_PivotCache ? */
14693 case '<pivotCache': break;
14694
14695 /* 18.2.21 smartTagPr CT_SmartTagPr ? */
14696 case '<smartTagPr': case '<smartTagPr/>': break;
14697
14698 /* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
14699 case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
14700 /* 18.2.22 smartTagType CT_SmartTagType ? */
14701 case '<smartTagType': break;
14702
14703 /* 18.2.24 webPublishing CT_WebPublishing ? */
14704 case '<webPublishing': case '<webPublishing/>': break;
14705
14706 /* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
14707 case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
14708
14709 /* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
14710 case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
14711 /* 18.2.25 webPublishObject CT_WebPublishObject ? */
14712 case '<webPublishObject': break;
14713
14714 /* 18.2.10 extLst CT_ExtensionList ? */
14715 case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
14716 /* 18.2.7 ext CT_Extension + */
14717 case '<ext': pass=true; break; //TODO: check with versions of excel
14718 case '</ext>': pass=false; break;
14719
14720 /* Others */
14721 case '<ArchID': break;
14722 case '<AlternateContent':
14723 case '<AlternateContent>': pass=true; break;
14724 case '</AlternateContent>': pass=false; break;
14725
14726 /* TODO */
14727 case '<revisionPtr': break;
14728
14729 default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
14730 }
14731 return x;
14732 });
14733 if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
14734
14735 parse_wb_defaults(wb);
14736
14737 return wb;
14738}
14739
14740var WB_XML_ROOT = writextag('workbook', null, {
14741 'xmlns': XMLNS.main[0],
14742 //'xmlns:mx': XMLNS.mx,
14743 //'xmlns:s': XMLNS.main[0],
14744 'xmlns:r': XMLNS.r
14745});
14746
14747function write_wb_xml(wb) {
14748 var o = [XML_HEADER];
14749 o[o.length] = WB_XML_ROOT;
14750
14751 var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
14752
14753 /* fileVersion */
14754 /* fileSharing */
14755
14756 var workbookPr = ({codeName:"ThisWorkbook"});
14757 if(wb.Workbook && wb.Workbook.WBProps) {
14758 WBPropsDef.forEach(function(x) {
14759if((wb.Workbook.WBProps[x[0]]) == null) return;
14760 if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
14761 workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
14762 });
14763if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
14764 }
14765 o[o.length] = (writextag('workbookPr', null, workbookPr));
14766
14767 /* workbookProtection */
14768
14769 var sheets = wb.Workbook && wb.Workbook.Sheets || [];
14770 var i = 0;
14771
14772 /* bookViews */
14773
14774 o[o.length] = "<sheets>";
14775 for(i = 0; i != wb.SheetNames.length; ++i) {
14776 var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
14777 sht.sheetId = ""+(i+1);
14778 sht["r:id"] = "rId"+(i+1);
14779 if(sheets[i]) switch(sheets[i].Hidden) {
14780 case 1: sht.state = "hidden"; break;
14781 case 2: sht.state = "veryHidden"; break;
14782 }
14783 o[o.length] = (writextag('sheet',null,sht));
14784 }
14785 o[o.length] = "</sheets>";
14786
14787 /* functionGroups */
14788 /* externalReferences */
14789
14790 if(write_names) {
14791 o[o.length] = "<definedNames>";
14792 if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
14793 var d = {name:n.Name};
14794 if(n.Comment) d.comment = n.Comment;
14795 if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
14796 if(n.Hidden) d.hidden = "1";
14797 if(!n.Ref) return;
14798 o[o.length] = writextag('definedName', String(n.Ref).replace(/</g, "&lt;").replace(/>/g, "&gt;"), d);
14799 });
14800 o[o.length] = "</definedNames>";
14801 }
14802
14803 /* calcPr */
14804 /* oleSize */
14805 /* customWorkbookViews */
14806 /* pivotCaches */
14807 /* smartTagPr */
14808 /* smartTagTypes */
14809 /* webPublishing */
14810 /* fileRecoveryPr */
14811 /* webPublishObjects */
14812 /* extLst */
14813
14814 if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
14815 return o.join("");
14816}
14817/* [MS-XLSB] 2.4.304 BrtBundleSh */
14818function parse_BrtBundleSh(data, length) {
14819 var z = {};
14820 z.Hidden = data.read_shift(4); //hsState ST_SheetState
14821 z.iTabID = data.read_shift(4);
14822 z.strRelID = parse_RelID(data,length-8);
14823 z.name = parse_XLWideString(data);
14824 return z;
14825}
14826function write_BrtBundleSh(data, o) {
14827 if(!o) o = new_buf(127);
14828 o.write_shift(4, data.Hidden);
14829 o.write_shift(4, data.iTabID);
14830 write_RelID(data.strRelID, o);
14831 write_XLWideString(data.name.slice(0,31), o);
14832 return o.length > o.l ? o.slice(0, o.l) : o;
14833}
14834
14835/* [MS-XLSB] 2.4.815 BrtWbProp */
14836function parse_BrtWbProp(data, length) {
14837 var o = ({});
14838 var flags = data.read_shift(4);
14839 o.defaultThemeVersion = data.read_shift(4);
14840 var strName = (length > 8) ? parse_XLWideString(data) : "";
14841 if(strName.length > 0) o.CodeName = strName;
14842 o.autoCompressPictures = !!(flags & 0x10000);
14843 o.backupFile = !!(flags & 0x40);
14844 o.checkCompatibility = !!(flags & 0x1000);
14845 o.date1904 = !!(flags & 0x01);
14846 o.filterPrivacy = !!(flags & 0x08);
14847 o.hidePivotFieldList = !!(flags & 0x400);
14848 o.promptedSolutions = !!(flags & 0x10);
14849 o.publishItems = !!(flags & 0x800);
14850 o.refreshAllConnections = !!(flags & 0x40000);
14851 o.saveExternalLinkValues = !!(flags & 0x80);
14852 o.showBorderUnselectedTables = !!(flags & 0x04);
14853 o.showInkAnnotation = !!(flags & 0x20);
14854 o.showObjects = ["all", "placeholders", "none"][(flags >> 13) & 0x03];
14855 o.showPivotChartFilter = !!(flags & 0x8000);
14856 o.updateLinks = ["userSet", "never", "always"][(flags >> 8) & 0x03];
14857 return o;
14858}
14859function write_BrtWbProp(data, o) {
14860 if(!o) o = new_buf(72);
14861 var flags = 0;
14862 if(data) {
14863 /* TODO: mirror parse_BrtWbProp fields */
14864 if(data.filterPrivacy) flags |= 0x08;
14865 }
14866 o.write_shift(4, flags);
14867 o.write_shift(4, 0);
14868 write_XLSBCodeName(data && data.CodeName || "ThisWorkbook", o);
14869 return o.slice(0, o.l);
14870}
14871
14872function parse_BrtFRTArchID$(data, length) {
14873 var o = {};
14874 data.read_shift(4);
14875 o.ArchID = data.read_shift(4);
14876 data.l += length - 8;
14877 return o;
14878}
14879
14880/* [MS-XLSB] 2.4.687 BrtName */
14881function parse_BrtName(data, length, opts) {
14882 var end = data.l + length;
14883 data.l += 4; //var flags = data.read_shift(4);
14884 data.l += 1; //var chKey = data.read_shift(1);
14885 var itab = data.read_shift(4);
14886 var name = parse_XLNameWideString(data);
14887 var formula = parse_XLSBNameParsedFormula(data, 0, opts);
14888 var comment = parse_XLNullableWideString(data);
14889 //if(0 /* fProc */) {
14890 // unusedstring1: XLNullableWideString
14891 // description: XLNullableWideString
14892 // helpTopic: XLNullableWideString
14893 // unusedstring2: XLNullableWideString
14894 //}
14895 data.l = end;
14896 var out = ({Name:name, Ptg:formula});
14897 if(itab < 0xFFFFFFF) out.Sheet = itab;
14898 if(comment) out.Comment = comment;
14899 return out;
14900}
14901
14902/* [MS-XLSB] 2.1.7.61 Workbook */
14903function parse_wb_bin(data, opts) {
14904 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
14905 var state = [];
14906 var pass = false;
14907
14908 if(!opts) opts = {};
14909 opts.biff = 12;
14910
14911 var Names = [];
14912 var supbooks = ([[]]);
14913 supbooks.SheetNames = [];
14914 supbooks.XTI = [];
14915
14916 recordhopper(data, function hopper_wb(val, R_n, RT) {
14917 switch(RT) {
14918 case 0x009C: /* 'BrtBundleSh' */
14919 supbooks.SheetNames.push(val.name);
14920 wb.Sheets.push(val); break;
14921
14922 case 0x0099: /* 'BrtWbProp' */
14923 wb.WBProps = val; break;
14924
14925 case 0x0027: /* 'BrtName' */
14926 if(val.Sheet != null) opts.SID = val.Sheet;
14927 val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts);
14928 delete opts.SID;
14929 delete val.Ptg;
14930 Names.push(val);
14931 break;
14932 case 0x040C: /* 'BrtNameExt' */ break;
14933
14934 case 0x0165: /* 'BrtSupSelf' */
14935 case 0x0166: /* 'BrtSupSame' */
14936 case 0x0163: /* 'BrtSupBookSrc' */
14937 case 0x029B: /* 'BrtSupAddin' */
14938 if(!supbooks[0].length) supbooks[0] = [RT, val];
14939 else supbooks.push([RT, val]);
14940 supbooks[supbooks.length - 1].XTI = [];
14941 break;
14942 case 0x016A: /* 'BrtExternSheet' */
14943 if(supbooks.length === 0) { supbooks[0] = []; supbooks[0].XTI = []; }
14944 supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val);
14945 supbooks.XTI = supbooks.XTI.concat(val);
14946 break;
14947 case 0x0169: /* 'BrtPlaceholderName' */
14948 break;
14949
14950 /* case 'BrtModelTimeGroupingCalcCol' */
14951 case 0x0C00: /* 'BrtUid' */
14952 case 0x0C01: /* 'BrtRevisionPtr' */
14953 case 0x0817: /* 'BrtAbsPath15' */
14954 case 0x0216: /* 'BrtBookProtection' */
14955 case 0x02A5: /* 'BrtBookProtectionIso' */
14956 case 0x009E: /* 'BrtBookView' */
14957 case 0x009D: /* 'BrtCalcProp' */
14958 case 0x0262: /* 'BrtCrashRecErr' */
14959 case 0x0802: /* 'BrtDecoupledPivotCacheID' */
14960 case 0x009B: /* 'BrtFileRecover' */
14961 case 0x0224: /* 'BrtFileSharing' */
14962 case 0x02A4: /* 'BrtFileSharingIso' */
14963 case 0x0080: /* 'BrtFileVersion' */
14964 case 0x0299: /* 'BrtFnGroup' */
14965 case 0x0850: /* 'BrtModelRelationship' */
14966 case 0x084D: /* 'BrtModelTable' */
14967 case 0x0225: /* 'BrtOleSize' */
14968 case 0x0805: /* 'BrtPivotTableRef' */
14969 case 0x0254: /* 'BrtSmartTagType' */
14970 case 0x081C: /* 'BrtTableSlicerCacheID' */
14971 case 0x081B: /* 'BrtTableSlicerCacheIDs' */
14972 case 0x0822: /* 'BrtTimelineCachePivotCacheID' */
14973 case 0x018D: /* 'BrtUserBookView' */
14974 case 0x009A: /* 'BrtWbFactoid' */
14975 case 0x045D: /* 'BrtWbProp14' */
14976 case 0x0229: /* 'BrtWebOpt' */
14977 case 0x082B: /* 'BrtWorkBookPr15' */
14978 break;
14979
14980 case 0x0023: /* 'BrtFRTBegin' */
14981 state.push(R_n); pass = true; break;
14982 case 0x0024: /* 'BrtFRTEnd' */
14983 state.pop(); pass = false; break;
14984 case 0x0025: /* 'BrtACBegin' */
14985 state.push(R_n); pass = true; break;
14986 case 0x0026: /* 'BrtACEnd' */
14987 state.pop(); pass = false; break;
14988
14989 case 0x0010: /* 'BrtFRTArchID$' */ break;
14990
14991 default:
14992 if((R_n||"").indexOf("Begin") > 0){/* empty */}
14993 else if((R_n||"").indexOf("End") > 0){/* empty */}
14994 else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin" && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
14995 }
14996 }, opts);
14997
14998 parse_wb_defaults(wb);
14999
15000 // $FlowIgnore
15001 wb.Names = Names;
15002
15003 (wb).supbooks = supbooks;
15004 return wb;
15005}
15006
15007function write_BUNDLESHS(ba, wb) {
15008 write_record(ba, "BrtBeginBundleShs");
15009 for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
15010 var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
15011 var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
15012 write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
15013 }
15014 write_record(ba, "BrtEndBundleShs");
15015}
15016
15017/* [MS-XLSB] 2.4.649 BrtFileVersion */
15018function write_BrtFileVersion(data, o) {
15019 if(!o) o = new_buf(127);
15020 for(var i = 0; i != 4; ++i) o.write_shift(4, 0);
15021 write_XLWideString("SheetJS", o);
15022 write_XLWideString(XLSX.version, o);
15023 write_XLWideString(XLSX.version, o);
15024 write_XLWideString("7262", o);
15025 o.length = o.l;
15026 return o.length > o.l ? o.slice(0, o.l) : o;
15027}
15028
15029/* [MS-XLSB] 2.4.301 BrtBookView */
15030function write_BrtBookView(idx, o) {
15031 if(!o) o = new_buf(29);
15032 o.write_shift(-4, 0);
15033 o.write_shift(-4, 460);
15034 o.write_shift(4, 28800);
15035 o.write_shift(4, 17600);
15036 o.write_shift(4, 500);
15037 o.write_shift(4, idx);
15038 o.write_shift(4, idx);
15039 var flags = 0x78;
15040 o.write_shift(1, flags);
15041 return o.length > o.l ? o.slice(0, o.l) : o;
15042}
15043
15044function write_BOOKVIEWS(ba, wb) {
15045 /* required if hidden tab appears before visible tab */
15046 if(!wb.Workbook || !wb.Workbook.Sheets) return;
15047 var sheets = wb.Workbook.Sheets;
15048 var i = 0, vistab = -1, hidden = -1;
15049 for(; i < sheets.length; ++i) {
15050 if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
15051 else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
15052 }
15053 if(hidden > vistab) return;
15054 write_record(ba, "BrtBeginBookViews");
15055 write_record(ba, "BrtBookView", write_BrtBookView(vistab));
15056 /* 1*(BrtBookView *FRT) */
15057 write_record(ba, "BrtEndBookViews");
15058}
15059
15060/* [MS-XLSB] 2.4.305 BrtCalcProp */
15061/*function write_BrtCalcProp(data, o) {
15062 if(!o) o = new_buf(26);
15063 o.write_shift(4,0); // force recalc
15064 o.write_shift(4,1);
15065 o.write_shift(4,0);
15066 write_Xnum(0, o);
15067 o.write_shift(-4, 1023);
15068 o.write_shift(1, 0x33);
15069 o.write_shift(1, 0x00);
15070 return o;
15071}*/
15072
15073/* [MS-XLSB] 2.4.646 BrtFileRecover */
15074/*function write_BrtFileRecover(data, o) {
15075 if(!o) o = new_buf(1);
15076 o.write_shift(1,0);
15077 return o;
15078}*/
15079
15080/* [MS-XLSB] 2.1.7.61 Workbook */
15081function write_wb_bin(wb, opts) {
15082 var ba = buf_array();
15083 write_record(ba, "BrtBeginBook");
15084 write_record(ba, "BrtFileVersion", write_BrtFileVersion());
15085 /* [[BrtFileSharingIso] BrtFileSharing] */
15086 write_record(ba, "BrtWbProp", write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null));
15087 /* [ACABSPATH] */
15088 /* [[BrtBookProtectionIso] BrtBookProtection] */
15089 write_BOOKVIEWS(ba, wb, opts);
15090 write_BUNDLESHS(ba, wb, opts);
15091 /* [FNGROUP] */
15092 /* [EXTERNALS] */
15093 /* *BrtName */
15094 /* write_record(ba, "BrtCalcProp", write_BrtCalcProp()); */
15095 /* [BrtOleSize] */
15096 /* *(BrtUserBookView *FRT) */
15097 /* [PIVOTCACHEIDS] */
15098 /* [BrtWbFactoid] */
15099 /* [SMARTTAGTYPES] */
15100 /* [BrtWebOpt] */
15101 /* write_record(ba, "BrtFileRecover", write_BrtFileRecover()); */
15102 /* [WEBPUBITEMS] */
15103 /* [CRERRS] */
15104 /* FRTWORKBOOK */
15105 write_record(ba, "BrtEndBook");
15106
15107 return ba.end();
15108}
15109function parse_wb(data, name, opts) {
15110 if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
15111 return parse_wb_xml((data), opts);
15112}
15113
15114function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
15115 if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
15116 return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
15117}
15118
15119function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
15120 if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
15121 return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
15122}
15123
15124function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
15125 if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
15126 return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
15127}
15128
15129function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
15130 if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
15131 return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
15132}
15133
15134function parse_sty(data, name, themes, opts) {
15135 if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
15136 return parse_sty_xml((data), themes, opts);
15137}
15138
15139function parse_theme(data, name, opts) {
15140 return parse_theme_xml(data, opts);
15141}
15142
15143function parse_sst(data, name, opts) {
15144 if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
15145 return parse_sst_xml((data), opts);
15146}
15147
15148function parse_cmnt(data, name, opts) {
15149 if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
15150 return parse_comments_xml((data), opts);
15151}
15152
15153function parse_cc(data, name, opts) {
15154 if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
15155 return parse_cc_xml((data), name, opts);
15156}
15157
15158function parse_xlink(data, name, opts) {
15159 if(name.slice(-4)===".bin") return parse_xlink_bin((data), name, opts);
15160 return parse_xlink_xml((data), name, opts);
15161}
15162
15163function write_wb(wb, name, opts) {
15164 return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
15165}
15166
15167function write_ws(data, name, opts, wb, rels) {
15168 return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
15169}
15170
15171// eslint-disable-next-line no-unused-vars
15172function write_cs(data, name, opts, wb, rels) {
15173 return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
15174}
15175
15176function write_sty(data, name, opts) {
15177 return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
15178}
15179
15180function write_sst(data, name, opts) {
15181 return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
15182}
15183
15184function write_cmnt(data, name, opts) {
15185 return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
15186}
15187/*
15188function write_cc(data, name:string, opts) {
15189 return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
15190}
15191*/
15192var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
15193var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
15194var _chr = function(c) { return String.fromCharCode(c); };
15195function xlml_parsexmltag(tag, skip_root) {
15196 var words = tag.split(/\s+/);
15197 var z = ([]); if(!skip_root) z[0] = words[0];
15198 if(words.length === 1) return z;
15199 var m = tag.match(attregexg2), y, j, w, i;
15200 if(m) for(i = 0; i != m.length; ++i) {
15201 y = m[i].match(attregex2);
15202if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
15203 else {
15204 if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
15205 else w = y[1].slice(j+1);
15206 z[w] = y[2].slice(1,y[2].length-1);
15207 }
15208 }
15209 return z;
15210}
15211function xlml_parsexmltagobj(tag) {
15212 var words = tag.split(/\s+/);
15213 var z = {};
15214 if(words.length === 1) return z;
15215 var m = tag.match(attregexg2), y, j, w, i;
15216 if(m) for(i = 0; i != m.length; ++i) {
15217 y = m[i].match(attregex2);
15218if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
15219 else {
15220 if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
15221 else w = y[1].slice(j+1);
15222 z[w] = y[2].slice(1,y[2].length-1);
15223 }
15224 }
15225 return z;
15226}
15227
15228// ----
15229
15230function xlml_format(format, value) {
15231 var fmt = XLMLFormatMap[format] || unescapexml(format);
15232 if(fmt === "General") return SSF._general(value);
15233 return SSF.format(fmt, value);
15234}
15235
15236function xlml_set_custprop(Custprops, key, cp, val) {
15237 var oval = val;
15238 switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) {
15239 case "boolean": oval = parsexmlbool(val); break;
15240 case "i2": case "int": oval = parseInt(val, 10); break;
15241 case "r4": case "float": oval = parseFloat(val); break;
15242 case "date": case "dateTime.tz": oval = parseDate(val); break;
15243 case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break;
15244 default: throw new Error("bad custprop:" + cp[0]);
15245 }
15246 Custprops[unescapexml(key)] = oval;
15247}
15248
15249function safe_format_xlml(cell, nf, o) {
15250 if(cell.t === 'z') return;
15251 if(!o || o.cellText !== false) try {
15252 if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
15253 else if(nf === "General") {
15254 if(cell.t === 'n') {
15255 if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v);
15256 else cell.w = SSF._general_num(cell.v);
15257 }
15258 else cell.w = SSF._general(cell.v);
15259 }
15260 else cell.w = xlml_format(nf||"General", cell.v);
15261 } catch(e) { if(o.WTF) throw e; }
15262 try {
15263 var z = XLMLFormatMap[nf]||nf||"General";
15264 if(o.cellNF) cell.z = z;
15265 if(o.cellDates && cell.t == 'n' && SSF.is_date(z)) {
15266 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); }
15267 }
15268 } catch(e) { if(o.WTF) throw e; }
15269}
15270
15271function process_style_xlml(styles, stag, opts) {
15272 if(opts.cellStyles) {
15273 if(stag.Interior) {
15274 var I = stag.Interior;
15275 if(I.Pattern) I.patternType = XLMLPatternTypeMap[I.Pattern] || I.Pattern;
15276 }
15277 }
15278 styles[stag.ID] = stag;
15279}
15280
15281/* TODO: there must exist some form of OSP-blessed spec */
15282function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o) {
15283 var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
15284 var interiors = [];
15285 var i = 0;
15286 if(sid === undefined && row) sid = row.StyleID;
15287 if(sid === undefined && csty) sid = csty.StyleID;
15288 while(styles[sid] !== undefined) {
15289 if(styles[sid].nf) nf = styles[sid].nf;
15290 if(styles[sid].Interior) interiors.push(styles[sid].Interior);
15291 if(!styles[sid].Parent) break;
15292 sid = styles[sid].Parent;
15293 }
15294 switch(data.Type) {
15295 case 'Boolean':
15296 cell.t = 'b';
15297 cell.v = parsexmlbool(xml);
15298 break;
15299 case 'String':
15300 cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
15301 cell.v = xml.indexOf("<") > -1 ? unescapexml(ss) : cell.r;
15302 break;
15303 case 'DateTime':
15304 if(xml.slice(-1) != "Z") xml += "Z";
15305 cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
15306 if(cell.v !== cell.v) cell.v = unescapexml(xml);
15307 else if(cell.v<60) cell.v = cell.v -1;
15308 if(!nf || nf == "General") nf = "yyyy-mm-dd";
15309 /* falls through */
15310 case 'Number':
15311 if(cell.v === undefined) cell.v=+xml;
15312 if(!cell.t) cell.t = 'n';
15313 break;
15314 case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
15315 default: cell.t = 's'; cell.v = xlml_fixstr(ss||xml); break;
15316 }
15317 safe_format_xlml(cell, nf, o);
15318 if(o.cellFormula !== false) {
15319 if(cell.Formula) {
15320 var fstr = unescapexml(cell.Formula);
15321 /* strictly speaking, the leading = is required but some writers omit */
15322 if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.slice(1);
15323 cell.f = rc_to_a1(fstr, base);
15324 delete cell.Formula;
15325 if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base);
15326 else if(cell.ArrayRange) {
15327 cell.F = rc_to_a1(cell.ArrayRange, base);
15328 arrayf.push([safe_decode_range(cell.F), cell.F]);
15329 }
15330 } else {
15331 for(i = 0; i < arrayf.length; ++i)
15332 if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r)
15333 if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c)
15334 cell.F = arrayf[i][1];
15335 }
15336 }
15337 if(o.cellStyles) {
15338 interiors.forEach(function(x) {
15339 if(!S.patternType && x.patternType) S.patternType = x.patternType;
15340 });
15341 cell.s = S;
15342 }
15343 if(cell.StyleID !== undefined) cell.ixfe = cell.StyleID;
15344}
15345
15346function xlml_clean_comment(comment) {
15347 comment.t = comment.v || "";
15348 comment.t = comment.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
15349 comment.v = comment.w = comment.ixfe = undefined;
15350}
15351
15352function xlml_normalize(d) {
15353 if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
15354 if(typeof d === 'string') return d;
15355 /* duktape */
15356 if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d)));
15357 throw new Error("Bad input format: expected Buffer or string");
15358}
15359
15360/* TODO: Everything */
15361/* UOS uses CJK in tags */
15362var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>:\/]+)[^>]*>/mg;
15363//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
15364function parse_xlml_xml(d, _opts) {
15365 var opts = _opts || {};
15366 make_ssf(SSF);
15367 var str = debom(xlml_normalize(d));
15368 if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') {
15369 if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
15370 else str = utf8read(str);
15371 }
15372 var opening = str.slice(0, 1024).toLowerCase(), ishtml = false;
15373 if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; });
15374 if(ishtml) return HTML_.to_workbook(str, opts);
15375 var Rn;
15376 var state = [], tmp;
15377 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
15378 var sheets = {}, sheetnames = [], cursheet = (opts.dense ? [] : {}), sheetname = "";
15379 var table = {}, cell = ({}), row = {};// eslint-disable-line no-unused-vars
15380 var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
15381 var c = 0, r = 0;
15382 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
15383 var styles = {}, stag = {};
15384 var ss = "", fidx = 0;
15385 var merges = [];
15386 var Props = {}, Custprops = {}, pidx = 0, cp = [];
15387 var comments = [], comment = ({});
15388 var cstys = [], csty, seencol = false;
15389 var arrayf = [];
15390 var rowinfo = [], rowobj = {}, cc = 0, rr = 0;
15391 var Workbook = ({ Sheets:[], WBProps:{date1904:false} }), wsprops = {};
15392 xlmlregex.lastIndex = 0;
15393 str = str.replace(/<!--([\s\S]*?)-->/mg,"");
15394 while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
15395 case 'Data':
15396 if(state[state.length-1][1]) break;
15397 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);
15398 else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
15399 break;
15400 case 'Cell':
15401 if(Rn[1]==='/'){
15402 if(comments.length > 0) cell.c = comments;
15403 if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) {
15404 if(opts.dense) {
15405 if(!cursheet[r]) cursheet[r] = [];
15406 cursheet[r][c] = cell;
15407 } else cursheet[encode_col(c) + encode_row(r)] = cell;
15408 }
15409 if(cell.HRef) {
15410 cell.l = ({Target:cell.HRef});
15411 if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
15412 delete cell.HRef; delete cell.HRefScreenTip;
15413 }
15414 if(cell.MergeAcross || cell.MergeDown) {
15415 cc = c + (parseInt(cell.MergeAcross,10)|0);
15416 rr = r + (parseInt(cell.MergeDown,10)|0);
15417 merges.push({s:{c:c,r:r},e:{c:cc,r:rr}});
15418 }
15419 if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
15420 else if(cell.MergeAcross || cell.MergeDown) {
15421for(var cma = c; cma <= cc; ++cma) {
15422 for(var cmd = r; cmd <= rr; ++cmd) {
15423 if(cma > c || cmd > r) {
15424 if(opts.dense) {
15425 if(!cursheet[cmd]) cursheet[cmd] = [];
15426 cursheet[cmd][cma] = {t:'z'};
15427 } else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
15428 }
15429 }
15430 }
15431 c = cc + 1;
15432 }
15433 else ++c;
15434 } else {
15435 cell = xlml_parsexmltagobj(Rn[0]);
15436 if(cell.Index) c = +cell.Index - 1;
15437 if(c < refguess.s.c) refguess.s.c = c;
15438 if(c > refguess.e.c) refguess.e.c = c;
15439 if(Rn[0].slice(-2) === "/>") ++c;
15440 comments = [];
15441 }
15442 break;
15443 case 'Row':
15444 if(Rn[1]==='/' || Rn[0].slice(-2) === "/>") {
15445 if(r < refguess.s.r) refguess.s.r = r;
15446 if(r > refguess.e.r) refguess.e.r = r;
15447 if(Rn[0].slice(-2) === "/>") {
15448 row = xlml_parsexmltag(Rn[0]);
15449 if(row.Index) r = +row.Index - 1;
15450 }
15451 c = 0; ++r;
15452 } else {
15453 row = xlml_parsexmltag(Rn[0]);
15454 if(row.Index) r = +row.Index - 1;
15455 rowobj = {};
15456 if(row.AutoFitHeight == "0" || row.Height) {
15457 rowobj.hpx = parseInt(row.Height, 10); rowobj.hpt = px2pt(rowobj.hpx);
15458 rowinfo[r] = rowobj;
15459 }
15460 if(row.Hidden == "1") { rowobj.hidden = true; rowinfo[r] = rowobj; }
15461 }
15462 break;
15463 case 'Worksheet': /* TODO: read range from FullRows/FullColumns */
15464 if(Rn[1]==='/'){
15465 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15466 sheetnames.push(sheetname);
15467 if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) {
15468 cursheet["!ref"] = encode_range(refguess);
15469 if(opts.sheetRows && opts.sheetRows <= refguess.e.r) {
15470 cursheet["!fullref"] = cursheet["!ref"];
15471 refguess.e.r = opts.sheetRows - 1;
15472 cursheet["!ref"] = encode_range(refguess);
15473 }
15474 }
15475 if(merges.length) cursheet["!merges"] = merges;
15476 if(cstys.length > 0) cursheet["!cols"] = cstys;
15477 if(rowinfo.length > 0) cursheet["!rows"] = rowinfo;
15478 sheets[sheetname] = cursheet;
15479 } else {
15480 refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
15481 r = c = 0;
15482 state.push([Rn[3], false]);
15483 tmp = xlml_parsexmltag(Rn[0]);
15484 sheetname = unescapexml(tmp.Name);
15485 cursheet = (opts.dense ? [] : {});
15486 merges = [];
15487 arrayf = [];
15488 rowinfo = [];
15489 wsprops = {name:sheetname, Hidden:0};
15490 Workbook.Sheets.push(wsprops);
15491 }
15492 break;
15493 case 'Table':
15494 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15495 else if(Rn[0].slice(-2) == "/>") break;
15496 else {
15497 table = xlml_parsexmltag(Rn[0]);
15498 state.push([Rn[3], false]);
15499 cstys = []; seencol = false;
15500 }
15501 break;
15502
15503 case 'Style':
15504 if(Rn[1]==='/') process_style_xlml(styles, stag, opts);
15505 else stag = xlml_parsexmltag(Rn[0]);
15506 break;
15507
15508 case 'NumberFormat':
15509 stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
15510 if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
15511 for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
15512 if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
15513 break;
15514
15515 case 'Column':
15516 if(state[state.length-1][0] !== 'Table') break;
15517 csty = xlml_parsexmltag(Rn[0]);
15518 if(csty.Hidden) { csty.hidden = true; delete csty.Hidden; }
15519 if(csty.Width) csty.wpx = parseInt(csty.Width, 10);
15520 if(!seencol && csty.wpx > 10) {
15521 seencol = true; MDW = DEF_MDW; //find_mdw_wpx(csty.wpx);
15522 for(var _col = 0; _col < cstys.length; ++_col) if(cstys[_col]) process_col(cstys[_col]);
15523 }
15524 if(seencol) process_col(csty);
15525 cstys[(csty.Index-1||cstys.length)] = csty;
15526 for(var i = 0; i < +csty.Span; ++i) cstys[cstys.length] = dup(csty);
15527 break;
15528
15529 case 'NamedRange':
15530 if(!Workbook.Names) Workbook.Names = [];
15531 var _NamedRange = parsexmltag(Rn[0]);
15532 var _DefinedName = ({
15533 Name: _NamedRange.Name,
15534 Ref: rc_to_a1(_NamedRange.RefersTo.slice(1), {r:0, c:0})
15535 });
15536 if(Workbook.Sheets.length>0) _DefinedName.Sheet=Workbook.Sheets.length-1;
15537Workbook.Names.push(_DefinedName);
15538 break;
15539
15540 case 'NamedCell': break;
15541 case 'B': break;
15542 case 'I': break;
15543 case 'U': break;
15544 case 'S': break;
15545 case 'Sub': break;
15546 case 'Sup': break;
15547 case 'Span': break;
15548 case 'Border': break;
15549 case 'Alignment': break;
15550 case 'Borders': break;
15551 case 'Font':
15552 if(Rn[0].slice(-2) === "/>") break;
15553 else if(Rn[1]==="/") ss += str.slice(fidx, Rn.index);
15554 else fidx = Rn.index + Rn[0].length;
15555 break;
15556 case 'Interior':
15557 if(!opts.cellStyles) break;
15558 stag.Interior = xlml_parsexmltag(Rn[0]);
15559 break;
15560 case 'Protection': break;
15561
15562 case 'Author':
15563 case 'Title':
15564 case 'Description':
15565 case 'Created':
15566 case 'Keywords':
15567 case 'Subject':
15568 case 'Category':
15569 case 'Company':
15570 case 'LastAuthor':
15571 case 'LastSaved':
15572 case 'LastPrinted':
15573 case 'Version':
15574 case 'Revision':
15575 case 'TotalTime':
15576 case 'HyperlinkBase':
15577 case 'Manager':
15578 case 'ContentStatus':
15579 case 'Identifier':
15580 case 'Language':
15581 case 'AppName':
15582 if(Rn[0].slice(-2) === "/>") break;
15583 else if(Rn[1]==="/") xlml_set_prop(Props, Rn[3], str.slice(pidx, Rn.index));
15584 else pidx = Rn.index + Rn[0].length;
15585 break;
15586 case 'Paragraphs': break;
15587
15588 case 'Styles':
15589 case 'Workbook':
15590 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15591 else state.push([Rn[3], false]);
15592 break;
15593
15594 case 'Comment':
15595 if(Rn[1]==='/'){
15596 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15597 xlml_clean_comment(comment);
15598 comments.push(comment);
15599 } else {
15600 state.push([Rn[3], false]);
15601 tmp = xlml_parsexmltag(Rn[0]);
15602 comment = ({a:tmp.Author});
15603 }
15604 break;
15605
15606 case 'AutoFilter':
15607 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15608 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
15609 var AutoFilter = xlml_parsexmltag(Rn[0]);
15610 cursheet['!autofilter'] = { ref:rc_to_a1(AutoFilter.Range).replace(/\$/g,"") };
15611 state.push([Rn[3], true]);
15612 }
15613 break;
15614
15615 case 'Name': break;
15616
15617 case 'ComponentOptions':
15618 case 'DocumentProperties':
15619 case 'CustomDocumentProperties':
15620 case 'OfficeDocumentSettings':
15621 case 'PivotTable':
15622 case 'PivotCache':
15623 case 'Names':
15624 case 'MapInfo':
15625 case 'PageBreaks':
15626 case 'QueryTable':
15627 case 'DataValidation':
15628 case 'Sorting':
15629 case 'Schema':
15630 case 'data':
15631 case 'ConditionalFormatting':
15632 case 'SmartTagType':
15633 case 'SmartTags':
15634 case 'ExcelWorkbook':
15635 case 'WorkbookOptions':
15636 case 'WorksheetOptions':
15637 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15638 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
15639 break;
15640
15641 default:
15642 /* FODS file root is <office:document> */
15643 if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts);
15644 /* UOS file root is <uof:UOF> */
15645 if(state.length == 0 && Rn[3] == "UOF") return parse_fods(str, opts);
15646
15647 var seen = true;
15648 switch(state[state.length-1][0]) {
15649 /* OfficeDocumentSettings */
15650 case 'OfficeDocumentSettings': switch(Rn[3]) {
15651 case 'AllowPNG': break;
15652 case 'RemovePersonalInformation': break;
15653 case 'DownloadComponents': break;
15654 case 'LocationOfComponents': break;
15655 case 'Colors': break;
15656 case 'Color': break;
15657 case 'Index': break;
15658 case 'RGB': break;
15659 case 'PixelsPerInch': break; // TODO: set PPI
15660 case 'TargetScreenSize': break;
15661 case 'ReadOnlyRecommended': break;
15662 default: seen = false;
15663 } break;
15664
15665 /* ComponentOptions */
15666 case 'ComponentOptions': switch(Rn[3]) {
15667 case 'Toolbar': break;
15668 case 'HideOfficeLogo': break;
15669 case 'SpreadsheetAutoFit': break;
15670 case 'Label': break;
15671 case 'Caption': break;
15672 case 'MaxHeight': break;
15673 case 'MaxWidth': break;
15674 case 'NextSheetNumber': break;
15675 default: seen = false;
15676 } break;
15677
15678 /* ExcelWorkbook */
15679 case 'ExcelWorkbook': switch(Rn[3]) {
15680 case 'Date1904':
15681Workbook.WBProps.date1904 = true;
15682 break;
15683 case 'WindowHeight': break;
15684 case 'WindowWidth': break;
15685 case 'WindowTopX': break;
15686 case 'WindowTopY': break;
15687 case 'TabRatio': break;
15688 case 'ProtectStructure': break;
15689 case 'ProtectWindows': break;
15690 case 'ActiveSheet': break;
15691 case 'DisplayInkNotes': break;
15692 case 'FirstVisibleSheet': break;
15693 case 'SupBook': break;
15694 case 'SheetName': break;
15695 case 'SheetIndex': break;
15696 case 'SheetIndexFirst': break;
15697 case 'SheetIndexLast': break;
15698 case 'Dll': break;
15699 case 'AcceptLabelsInFormulas': break;
15700 case 'DoNotSaveLinkValues': break;
15701 case 'Iteration': break;
15702 case 'MaxIterations': break;
15703 case 'MaxChange': break;
15704 case 'Path': break;
15705 case 'Xct': break;
15706 case 'Count': break;
15707 case 'SelectedSheets': break;
15708 case 'Calculation': break;
15709 case 'Uncalced': break;
15710 case 'StartupPrompt': break;
15711 case 'Crn': break;
15712 case 'ExternName': break;
15713 case 'Formula': break;
15714 case 'ColFirst': break;
15715 case 'ColLast': break;
15716 case 'WantAdvise': break;
15717 case 'Boolean': break;
15718 case 'Error': break;
15719 case 'Text': break;
15720 case 'OLE': break;
15721 case 'NoAutoRecover': break;
15722 case 'PublishObjects': break;
15723 case 'DoNotCalculateBeforeSave': break;
15724 case 'Number': break;
15725 case 'RefModeR1C1': break;
15726 case 'EmbedSaveSmartTags': break;
15727 default: seen = false;
15728 } break;
15729
15730 /* WorkbookOptions */
15731 case 'WorkbookOptions': switch(Rn[3]) {
15732 case 'OWCVersion': break;
15733 case 'Height': break;
15734 case 'Width': break;
15735 default: seen = false;
15736 } break;
15737
15738 /* WorksheetOptions */
15739 case 'WorksheetOptions': switch(Rn[3]) {
15740 case 'Visible':
15741 if(Rn[0].slice(-2) === "/>"){/* empty */}
15742 else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
15743 case "SheetHidden": wsprops.Hidden = 1; break;
15744 case "SheetVeryHidden": wsprops.Hidden = 2; break;
15745 }
15746 else pidx = Rn.index + Rn[0].length;
15747 break;
15748 case 'Header':
15749 if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
15750 cursheet['!margins'].header = parsexmltag(Rn[0]).Margin;
15751 break;
15752 case 'Footer':
15753 if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
15754 cursheet['!margins'].footer = parsexmltag(Rn[0]).Margin;
15755 break;
15756 case 'PageMargins':
15757 var pagemargins = parsexmltag(Rn[0]);
15758 if(!cursheet['!margins']) default_margins(cursheet['!margins']={},'xlml');
15759 if(pagemargins.Top) cursheet['!margins'].top = pagemargins.Top;
15760 if(pagemargins.Left) cursheet['!margins'].left = pagemargins.Left;
15761 if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right;
15762 if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom;
15763 break;
15764 case 'DisplayRightToLeft':
15765 if(!Workbook.Views) Workbook.Views = [];
15766 if(!Workbook.Views[0]) Workbook.Views[0] = {};
15767 Workbook.Views[0].RTL = true;
15768 break;
15769
15770 case 'Unsynced': break;
15771 case 'Print': break;
15772 case 'Panes': break;
15773 case 'Scale': break;
15774 case 'Pane': break;
15775 case 'Number': break;
15776 case 'Layout': break;
15777 case 'PageSetup': break;
15778 case 'Selected': break;
15779 case 'ProtectObjects': break;
15780 case 'EnableSelection': break;
15781 case 'ProtectScenarios': break;
15782 case 'ValidPrinterInfo': break;
15783 case 'HorizontalResolution': break;
15784 case 'VerticalResolution': break;
15785 case 'NumberofCopies': break;
15786 case 'ActiveRow': break;
15787 case 'ActiveCol': break;
15788 case 'ActivePane': break;
15789 case 'TopRowVisible': break;
15790 case 'TopRowBottomPane': break;
15791 case 'LeftColumnVisible': break;
15792 case 'LeftColumnRightPane': break;
15793 case 'FitToPage': break;
15794 case 'RangeSelection': break;
15795 case 'PaperSizeIndex': break;
15796 case 'PageLayoutZoom': break;
15797 case 'PageBreakZoom': break;
15798 case 'FilterOn': break;
15799 case 'DoNotDisplayGridlines': break;
15800 case 'SplitHorizontal': break;
15801 case 'SplitVertical': break;
15802 case 'FreezePanes': break;
15803 case 'FrozenNoSplit': break;
15804 case 'FitWidth': break;
15805 case 'FitHeight': break;
15806 case 'CommentsLayout': break;
15807 case 'Zoom': break;
15808 case 'LeftToRight': break;
15809 case 'Gridlines': break;
15810 case 'AllowSort': break;
15811 case 'AllowFilter': break;
15812 case 'AllowInsertRows': break;
15813 case 'AllowDeleteRows': break;
15814 case 'AllowInsertCols': break;
15815 case 'AllowDeleteCols': break;
15816 case 'AllowInsertHyperlinks': break;
15817 case 'AllowFormatCells': break;
15818 case 'AllowSizeCols': break;
15819 case 'AllowSizeRows': break;
15820 case 'NoSummaryRowsBelowDetail': break;
15821 case 'TabColorIndex': break;
15822 case 'DoNotDisplayHeadings': break;
15823 case 'ShowPageLayoutZoom': break;
15824 case 'NoSummaryColumnsRightDetail': break;
15825 case 'BlackAndWhite': break;
15826 case 'DoNotDisplayZeros': break;
15827 case 'DisplayPageBreak': break;
15828 case 'RowColHeadings': break;
15829 case 'DoNotDisplayOutline': break;
15830 case 'NoOrientation': break;
15831 case 'AllowUsePivotTables': break;
15832 case 'ZeroHeight': break;
15833 case 'ViewableRange': break;
15834 case 'Selection': break;
15835 case 'ProtectContents': break;
15836 default: seen = false;
15837 } break;
15838
15839 /* PivotTable */
15840 case 'PivotTable': case 'PivotCache': switch(Rn[3]) {
15841 case 'ImmediateItemsOnDrop': break;
15842 case 'ShowPageMultipleItemLabel': break;
15843 case 'CompactRowIndent': break;
15844 case 'Location': break;
15845 case 'PivotField': break;
15846 case 'Orientation': break;
15847 case 'LayoutForm': break;
15848 case 'LayoutSubtotalLocation': break;
15849 case 'LayoutCompactRow': break;
15850 case 'Position': break;
15851 case 'PivotItem': break;
15852 case 'DataType': break;
15853 case 'DataField': break;
15854 case 'SourceName': break;
15855 case 'ParentField': break;
15856 case 'PTLineItems': break;
15857 case 'PTLineItem': break;
15858 case 'CountOfSameItems': break;
15859 case 'Item': break;
15860 case 'ItemType': break;
15861 case 'PTSource': break;
15862 case 'CacheIndex': break;
15863 case 'ConsolidationReference': break;
15864 case 'FileName': break;
15865 case 'Reference': break;
15866 case 'NoColumnGrand': break;
15867 case 'NoRowGrand': break;
15868 case 'BlankLineAfterItems': break;
15869 case 'Hidden': break;
15870 case 'Subtotal': break;
15871 case 'BaseField': break;
15872 case 'MapChildItems': break;
15873 case 'Function': break;
15874 case 'RefreshOnFileOpen': break;
15875 case 'PrintSetTitles': break;
15876 case 'MergeLabels': break;
15877 case 'DefaultVersion': break;
15878 case 'RefreshName': break;
15879 case 'RefreshDate': break;
15880 case 'RefreshDateCopy': break;
15881 case 'VersionLastRefresh': break;
15882 case 'VersionLastUpdate': break;
15883 case 'VersionUpdateableMin': break;
15884 case 'VersionRefreshableMin': break;
15885 case 'Calculation': break;
15886 default: seen = false;
15887 } break;
15888
15889 /* PageBreaks */
15890 case 'PageBreaks': switch(Rn[3]) {
15891 case 'ColBreaks': break;
15892 case 'ColBreak': break;
15893 case 'RowBreaks': break;
15894 case 'RowBreak': break;
15895 case 'ColStart': break;
15896 case 'ColEnd': break;
15897 case 'RowEnd': break;
15898 default: seen = false;
15899 } break;
15900
15901 /* AutoFilter */
15902 case 'AutoFilter': switch(Rn[3]) {
15903 case 'AutoFilterColumn': break;
15904 case 'AutoFilterCondition': break;
15905 case 'AutoFilterAnd': break;
15906 case 'AutoFilterOr': break;
15907 default: seen = false;
15908 } break;
15909
15910 /* QueryTable */
15911 case 'QueryTable': switch(Rn[3]) {
15912 case 'Id': break;
15913 case 'AutoFormatFont': break;
15914 case 'AutoFormatPattern': break;
15915 case 'QuerySource': break;
15916 case 'QueryType': break;
15917 case 'EnableRedirections': break;
15918 case 'RefreshedInXl9': break;
15919 case 'URLString': break;
15920 case 'HTMLTables': break;
15921 case 'Connection': break;
15922 case 'CommandText': break;
15923 case 'RefreshInfo': break;
15924 case 'NoTitles': break;
15925 case 'NextId': break;
15926 case 'ColumnInfo': break;
15927 case 'OverwriteCells': break;
15928 case 'DoNotPromptForFile': break;
15929 case 'TextWizardSettings': break;
15930 case 'Source': break;
15931 case 'Number': break;
15932 case 'Decimal': break;
15933 case 'ThousandSeparator': break;
15934 case 'TrailingMinusNumbers': break;
15935 case 'FormatSettings': break;
15936 case 'FieldType': break;
15937 case 'Delimiters': break;
15938 case 'Tab': break;
15939 case 'Comma': break;
15940 case 'AutoFormatName': break;
15941 case 'VersionLastEdit': break;
15942 case 'VersionLastRefresh': break;
15943 default: seen = false;
15944 } break;
15945
15946 case 'Sorting':
15947 case 'ConditionalFormatting':
15948 case 'DataValidation':
15949 switch(Rn[3]) {
15950 case 'Range': break;
15951 case 'Type': break;
15952 case 'Min': break;
15953 case 'Max': break;
15954 case 'Sort': break;
15955 case 'Descending': break;
15956 case 'Order': break;
15957 case 'CaseSensitive': break;
15958 case 'Value': break;
15959 case 'ErrorStyle': break;
15960 case 'ErrorMessage': break;
15961 case 'ErrorTitle': break;
15962 case 'CellRangeList': break;
15963 case 'InputMessage': break;
15964 case 'InputTitle': break;
15965 case 'ComboHide': break;
15966 case 'InputHide': break;
15967 case 'Condition': break;
15968 case 'Qualifier': break;
15969 case 'UseBlank': break;
15970 case 'Value1': break;
15971 case 'Value2': break;
15972 case 'Format': break;
15973 default: seen = false;
15974 } break;
15975
15976 /* MapInfo (schema) */
15977 case 'MapInfo': case 'Schema': case 'data': switch(Rn[3]) {
15978 case 'Map': break;
15979 case 'Entry': break;
15980 case 'Range': break;
15981 case 'XPath': break;
15982 case 'Field': break;
15983 case 'XSDType': break;
15984 case 'FilterOn': break;
15985 case 'Aggregate': break;
15986 case 'ElementType': break;
15987 case 'AttributeType': break;
15988 /* These are from xsd (XML Schema Definition) */
15989 case 'schema':
15990 case 'element':
15991 case 'complexType':
15992 case 'datatype':
15993 case 'all':
15994 case 'attribute':
15995 case 'extends': break;
15996
15997 case 'row': break;
15998 default: seen = false;
15999 } break;
16000
16001 /* SmartTags (can be anything) */
16002 case 'SmartTags': break;
16003
16004 default: seen = false; break;
16005 }
16006 if(seen) break;
16007 /* CustomDocumentProperties */
16008 if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
16009 if(state[state.length-1][0]==='CustomDocumentProperties') {
16010 if(Rn[0].slice(-2) === "/>") break;
16011 else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn[3], cp, str.slice(pidx, Rn.index));
16012 else { cp = Rn; pidx = Rn.index + Rn[0].length; }
16013 break;
16014 }
16015 if(opts.WTF) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
16016 }
16017 var out = ({});
16018 if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
16019 out.SheetNames = sheetnames;
16020 out.Workbook = Workbook;
16021 out.SSF = SSF.get_table();
16022 out.Props = Props;
16023 out.Custprops = Custprops;
16024 return out;
16025}
16026
16027function parse_xlml(data, opts) {
16028 fix_read_opts(opts=opts||{});
16029 switch(opts.type||"base64") {
16030 case "base64": return parse_xlml_xml(Base64.decode(data), opts);
16031 case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
16032 case "array": return parse_xlml_xml(a2s(data), opts);
16033 }
16034}
16035
16036/* TODO */
16037function write_props_xlml(wb, opts) {
16038 var o = [];
16039 /* DocumentProperties */
16040 if(wb.Props) o.push(xlml_write_docprops(wb.Props, opts));
16041 /* CustomDocumentProperties */
16042 if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops, opts));
16043 return o.join("");
16044}
16045/* TODO */
16046function write_wb_xlml() {
16047 /* OfficeDocumentSettings */
16048 /* ExcelWorkbook */
16049 return "";
16050}
16051/* TODO */
16052function write_sty_xlml(wb, opts) {
16053 /* Styles */
16054 var styles = ['<Style ss:ID="Default" ss:Name="Normal"><NumberFormat/></Style>'];
16055 opts.cellXfs.forEach(function(xf, id) {
16056 var payload = [];
16057 payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])}));
16058 styles.push(writextag('Style', payload.join(""), {"ss:ID": "s" + (21+id)}));
16059 });
16060 return writextag("Styles", styles.join(""));
16061}
16062function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); }
16063function write_names_xlml(wb) {
16064 if(!((wb||{}).Workbook||{}).Names) return "";
16065var names = wb.Workbook.Names;
16066 var out = [];
16067 for(var i = 0; i < names.length; ++i) {
16068 var n = names[i];
16069 if(n.Sheet != null) continue;
16070 if(n.Name.match(/^_xlfn\./)) continue;
16071 out.push(write_name_xlml(n));
16072 }
16073 return writextag("Names", out.join(""));
16074}
16075function write_ws_xlml_names(ws, opts, idx, wb) {
16076 if(!ws) return "";
16077 if(!((wb||{}).Workbook||{}).Names) return "";
16078var names = wb.Workbook.Names;
16079 var out = [];
16080 for(var i = 0; i < names.length; ++i) {
16081 var n = names[i];
16082 if(n.Sheet != idx) continue;
16083 /*switch(n.Name) {
16084 case "_": continue;
16085 }*/
16086 if(n.Name.match(/^_xlfn\./)) continue;
16087 out.push(write_name_xlml(n));
16088 }
16089 return out.join("");
16090}
16091/* WorksheetOptions */
16092function write_ws_xlml_wsopts(ws, opts, idx, wb) {
16093 if(!ws) return "";
16094 var o = [];
16095 /* NOTE: spec technically allows any order, but stick with implied order */
16096
16097 /* FitToPage */
16098 /* DoNotDisplayColHeaders */
16099 /* DoNotDisplayRowHeaders */
16100 /* ViewableRange */
16101 /* Selection */
16102 /* GridlineColor */
16103 /* Name */
16104 /* ExcelWorksheetType */
16105 /* IntlMacro */
16106 /* Unsynced */
16107 /* Selected */
16108 /* CodeName */
16109
16110 if(ws['!margins']) {
16111 o.push("<PageSetup>");
16112 if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
16113 if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
16114 o.push(writextag("PageMargins", null, {
16115 'x:Bottom': ws['!margins'].bottom || "0.75",
16116 'x:Left': ws['!margins'].left || "0.7",
16117 'x:Right': ws['!margins'].right || "0.7",
16118 'x:Top': ws['!margins'].top || "0.75"
16119 }));
16120 o.push("</PageSetup>");
16121 }
16122
16123 /* PageSetup */
16124 /* DisplayPageBreak */
16125 /* TransitionExpressionEvaluation */
16126 /* TransitionFormulaEntry */
16127 /* Print */
16128 /* Zoom */
16129 /* PageLayoutZoom */
16130 /* PageBreakZoom */
16131 /* ShowPageBreakZoom */
16132 /* DefaultRowHeight */
16133 /* DefaultColumnWidth */
16134 /* StandardWidth */
16135
16136 if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
16137 /* Visible */
16138 if(wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
16139 else {
16140 /* Selected */
16141 for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
16142 if(i == idx) o.push("<Selected/>");
16143 }
16144 }
16145
16146 /* LeftColumnVisible */
16147
16148 if(((((wb||{}).Workbook||{}).Views||[])[0]||{}).RTL) o.push("<DisplayRightToLeft/>");
16149
16150 /* GridlineColorIndex */
16151 /* DisplayFormulas */
16152 /* DoNotDisplayGridlines */
16153 /* DoNotDisplayHeadings */
16154 /* DoNotDisplayOutline */
16155 /* ApplyAutomaticOutlineStyles */
16156 /* NoSummaryRowsBelowDetail */
16157 /* NoSummaryColumnsRightDetail */
16158 /* DoNotDisplayZeros */
16159 /* ActiveRow */
16160 /* ActiveColumn */
16161 /* FilterOn */
16162 /* RangeSelection */
16163 /* TopRowVisible */
16164 /* TopRowBottomPane */
16165 /* LeftColumnRightPane */
16166 /* ActivePane */
16167 /* SplitHorizontal */
16168 /* SplitVertical */
16169 /* FreezePanes */
16170 /* FrozenNoSplit */
16171 /* TabColorIndex */
16172 /* Panes */
16173
16174 /* NOTE: Password not supported in XLML Format */
16175 if(ws['!protect']) {
16176 o.push(writetag("ProtectContents", "True"));
16177 if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
16178 if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
16179 if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
16180 else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
16181 [
16182 [ "formatCells", "AllowFormatCells" ],
16183 [ "formatColumns", "AllowSizeCols" ],
16184 [ "formatRows", "AllowSizeRows" ],
16185 [ "insertColumns", "AllowInsertCols" ],
16186 [ "insertRows", "AllowInsertRows" ],
16187 [ "insertHyperlinks", "AllowInsertHyperlinks" ],
16188 [ "deleteColumns", "AllowDeleteCols" ],
16189 [ "deleteRows", "AllowDeleteRows" ],
16190 [ "sort", "AllowSort" ],
16191 [ "autoFilter", "AllowFilter" ],
16192 [ "pivotTables", "AllowUsePivotTables" ]
16193 ].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
16194 }
16195
16196 if(o.length == 0) return "";
16197 return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
16198}
16199function write_ws_xlml_comment(comments) {
16200 return comments.map(function(c) {
16201 // TODO: formatted text
16202 var t = xlml_unfixstr(c.t||"");
16203 var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
16204 return writextag("Comment", d, {"ss:Author":c.a});
16205 }).join("");
16206}
16207function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
16208 if(!cell || (cell.v == undefined && cell.f == undefined)) return "";
16209
16210 var attr = {};
16211 if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
16212 if(cell.F && cell.F.slice(0, ref.length) == ref) {
16213 var end = decode_cell(cell.F.slice(ref.length + 1));
16214 attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
16215 }
16216
16217 if(cell.l && cell.l.Target) {
16218 attr["ss:HRef"] = escapexml(cell.l.Target);
16219 if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
16220 }
16221
16222 if(ws['!merges']) {
16223 var marr = ws['!merges'];
16224 for(var mi = 0; mi != marr.length; ++mi) {
16225 if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
16226 if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
16227 if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
16228 }
16229 }
16230
16231 var t = "", p = "";
16232 switch(cell.t) {
16233 case 'z': return "";
16234 case 'n': t = 'Number'; p = String(cell.v); break;
16235 case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
16236 case 'e': t = 'Error'; p = BErr[cell.v]; break;
16237 case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break;
16238 case 's': t = 'String'; p = escapexlml(cell.v||""); break;
16239 }
16240 /* TODO: cell style */
16241 var os = get_cell_style(opts.cellXfs, cell, opts);
16242 attr["ss:StyleID"] = "s" + (21+os);
16243 attr["ss:Index"] = addr.c + 1;
16244 var _v = (cell.v != null ? p : "");
16245 var m = '<Data ss:Type="' + t + '">' + _v + '</Data>';
16246
16247 if((cell.c||[]).length > 0) m += write_ws_xlml_comment(cell.c);
16248
16249 return writextag("Cell", m, attr);
16250}
16251function write_ws_xlml_row(R, row) {
16252 var o = '<Row ss:Index="' + (R+1) + '"';
16253 if(row) {
16254 if(row.hpt && !row.hpx) row.hpx = pt2px(row.hpt);
16255 if(row.hpx) o += ' ss:AutoFitHeight="0" ss:Height="' + row.hpx + '"';
16256 if(row.hidden) o += ' ss:Hidden="1"';
16257 }
16258 return o + '>';
16259}
16260/* TODO */
16261function write_ws_xlml_table(ws, opts, idx, wb) {
16262 if(!ws['!ref']) return "";
16263 var range = safe_decode_range(ws['!ref']);
16264 var marr = ws['!merges'] || [], mi = 0;
16265 var o = [];
16266 if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
16267 process_col(n);
16268 var w = !!n.width;
16269 var p = col_obj_w(i, n);
16270 var k = {"ss:Index":i+1};
16271 if(w) k['ss:Width'] = width2px(p.width);
16272 if(n.hidden) k['ss:Hidden']="1";
16273 o.push(writextag("Column",null,k));
16274 });
16275 var dense = Array.isArray(ws);
16276 for(var R = range.s.r; R <= range.e.r; ++R) {
16277 var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
16278 for(var C = range.s.c; C <= range.e.c; ++C) {
16279 var skip = false;
16280 for(mi = 0; mi != marr.length; ++mi) {
16281 if(marr[mi].s.c > C) continue;
16282 if(marr[mi].s.r > R) continue;
16283 if(marr[mi].e.c < C) continue;
16284 if(marr[mi].e.r < R) continue;
16285 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
16286 break;
16287 }
16288 if(skip) continue;
16289 var addr = {r:R,c:C};
16290 var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
16291 row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
16292 }
16293 row.push("</Row>");
16294 if(row.length > 2) o.push(row.join(""));
16295 }
16296 return o.join("");
16297}
16298function write_ws_xlml(idx, opts, wb) {
16299 var o = [];
16300 var s = wb.SheetNames[idx];
16301 var ws = wb.Sheets[s];
16302
16303 var t = ws ? write_ws_xlml_names(ws, opts, idx, wb) : "";
16304 if(t.length > 0) o.push("<Names>" + t + "</Names>");
16305
16306 /* Table */
16307 t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
16308 if(t.length > 0) o.push("<Table>" + t + "</Table>");
16309
16310 /* WorksheetOptions */
16311 o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
16312
16313 return o.join("");
16314}
16315function write_xlml(wb, opts) {
16316 if(!opts) opts = {};
16317 if(!wb.SSF) wb.SSF = SSF.get_table();
16318 if(wb.SSF) {
16319 make_ssf(SSF); SSF.load_table(wb.SSF);
16320 // $FlowIgnore
16321 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
16322 opts.ssf = wb.SSF;
16323 opts.cellXfs = [];
16324 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
16325 }
16326 var d = [];
16327 d.push(write_props_xlml(wb, opts));
16328 d.push(write_wb_xlml(wb, opts));
16329 d.push("");
16330 d.push("");
16331 for(var i = 0; i < wb.SheetNames.length; ++i)
16332 d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
16333 d[2] = write_sty_xlml(wb, opts);
16334 d[3] = write_names_xlml(wb, opts);
16335 return XML_HEADER + writextag("Workbook", d.join(""), {
16336 'xmlns': XLMLNS.ss,
16337 'xmlns:o': XLMLNS.o,
16338 'xmlns:x': XLMLNS.x,
16339 'xmlns:ss': XLMLNS.ss,
16340 'xmlns:dt': XLMLNS.dt,
16341 'xmlns:html': XLMLNS.html
16342 });
16343}
16344/* [MS-OLEDS] 2.3.8 CompObjStream */
16345function parse_compobj(obj) {
16346 var v = {};
16347 var o = obj.content;
16348/* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
16349 o.l = 28;
16350
16351 v.AnsiUserType = o.read_shift(0, "lpstr-ansi");
16352 v.AnsiClipboardFormat = parse_ClipboardFormatOrAnsiString(o);
16353
16354 if(o.length - o.l <= 4) return v;
16355
16356 var m = o.read_shift(4);
16357 if(m == 0 || m > 40) return v;
16358 o.l-=4; v.Reserved1 = o.read_shift(0, "lpstr-ansi");
16359
16360 if(o.length - o.l <= 4) return v;
16361 m = o.read_shift(4);
16362 if(m !== 0x71b239f4) return v;
16363 v.UnicodeClipboardFormat = parse_ClipboardFormatOrUnicodeString(o);
16364
16365 m = o.read_shift(4);
16366 if(m == 0 || m > 40) return v;
16367 o.l-=4; v.Reserved2 = o.read_shift(0, "lpwstr");
16368}
16369
16370/*
16371 Continue logic for:
16372 - 2.4.58 Continue
16373 - 2.4.59 ContinueBigName
16374 - 2.4.60 ContinueFrt
16375 - 2.4.61 ContinueFrt11
16376 - 2.4.62 ContinueFrt12
16377*/
16378function slurp(R, blob, length, opts) {
16379 var l = length;
16380 var bufs = [];
16381 var d = blob.slice(blob.l,blob.l+l);
16382 if(opts && opts.enc && opts.enc.insitu) switch(R.n) {
16383 case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': break;
16384 default:
16385 if(d.length === 0) break;
16386 opts.enc.insitu(d);
16387 }
16388 bufs.push(d);
16389 blob.l += l;
16390 var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]);
16391 var start = 0;
16392 while(next != null && next.n.slice(0,8) === 'Continue') {
16393 l = __readUInt16LE(blob,blob.l+2);
16394 start = blob.l + 4;
16395 if(next.n == 'ContinueFrt') start += 4;
16396 else if(next.n.slice(0,11) == 'ContinueFrt') start += 12;
16397 bufs.push(blob.slice(start,blob.l+4+l));
16398 blob.l += 4+l;
16399 next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]);
16400 }
16401 var b = (bconcat(bufs));
16402 prep_blob(b, 0);
16403 var ll = 0; b.lens = [];
16404 for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; }
16405 return R.f(b, b.length, opts);
16406}
16407
16408function safe_format_xf(p, opts, date1904) {
16409 if(p.t === 'z') return;
16410 if(!p.XF) return;
16411 var fmtid = 0;
16412 try {
16413 fmtid = p.z || p.XF.numFmtId || 0;
16414 if(opts.cellNF) p.z = SSF._table[fmtid];
16415 } catch(e) { if(opts.WTF) throw e; }
16416 if(!opts || opts.cellText !== false) try {
16417 if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
16418 else if(fmtid === 0 || fmtid == "General") {
16419 if(p.t === 'n') {
16420 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
16421 else p.w = SSF._general_num(p.v);
16422 }
16423 else p.w = SSF._general(p.v);
16424 }
16425 else p.w = SSF.format(fmtid,p.v, {date1904:!!date1904});
16426 } catch(e) { if(opts.WTF) throw e; }
16427 if(opts.cellDates && fmtid && p.t == 'n' && SSF.is_date(SSF._table[fmtid] || String(fmtid))) {
16428 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); }
16429 }
16430}
16431
16432function make_cell(val, ixfe, t) {
16433 return ({v:val, ixfe:ixfe, t:t});
16434}
16435
16436// 2.3.2
16437function parse_workbook(blob, options) {
16438 var wb = ({opts:{}});
16439 var Sheets = {};
16440 if(DENSE != null && options.dense == null) options.dense = DENSE;
16441 var out = ((options.dense ? [] : {}));
16442 var Directory = {};
16443 var range = ({});
16444 var last_formula = null;
16445 var sst = ([]);
16446 var cur_sheet = "";
16447 var Preamble = {};
16448 var lastcell, last_cell = "", cc, cmnt, rngC, rngR;
16449 var sharedf = {};
16450 var arrayf = [];
16451 var temp_val;
16452 var country;
16453 var cell_valid = true;
16454 var XFs = []; /* XF records */
16455 var palette = [];
16456 var Workbook = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }), wsprops = {};
16457 var get_rgb = function getrgb(icv) {
16458 if(icv < 8) return XLSIcv[icv];
16459 if(icv < 64) return palette[icv-8] || XLSIcv[icv];
16460 return XLSIcv[icv];
16461 };
16462 var process_cell_style = function pcs(cell, line, options) {
16463 var xfd = line.XF.data;
16464 if(!xfd || !xfd.patternType || !options || !options.cellStyles) return;
16465 line.s = ({});
16466 line.s.patternType = xfd.patternType;
16467 var t;
16468 if((t = rgb2Hex(get_rgb(xfd.icvFore)))) { line.s.fgColor = {rgb:t}; }
16469 if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
16470 };
16471 var addcell = function addcell(cell, line, options) {
16472 if(file_depth > 1) return;
16473 if(options.sheetRows && cell.r >= options.sheetRows) cell_valid = false;
16474 if(!cell_valid) return;
16475 if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options);
16476 delete line.ixfe; delete line.XF;
16477 lastcell = cell;
16478 last_cell = encode_cell(cell);
16479 if(!range || !range.s || !range.e) range = {s:{r:0,c:0},e:{r:0,c:0}};
16480 if(cell.r < range.s.r) range.s.r = cell.r;
16481 if(cell.c < range.s.c) range.s.c = cell.c;
16482 if(cell.r + 1 > range.e.r) range.e.r = cell.r + 1;
16483 if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1;
16484 if(options.cellFormula && line.f) {
16485 for(var afi = 0; afi < arrayf.length; ++afi) {
16486 if(arrayf[afi][0].s.c > cell.c || arrayf[afi][0].s.r > cell.r) continue;
16487 if(arrayf[afi][0].e.c < cell.c || arrayf[afi][0].e.r < cell.r) continue;
16488 line.F = encode_range(arrayf[afi][0]);
16489 if(arrayf[afi][0].s.c != cell.c || arrayf[afi][0].s.r != cell.r) delete line.f;
16490 if(line.f) line.f = "" + stringify_formula(arrayf[afi][1], range, cell, supbooks, opts);
16491 break;
16492 }
16493 }
16494 {
16495 if(options.dense) {
16496 if(!out[cell.r]) out[cell.r] = [];
16497 out[cell.r][cell.c] = line;
16498 } else out[last_cell] = line;
16499 }
16500 };
16501 var opts = ({
16502 enc: false, // encrypted
16503 sbcch: 0, // cch in the preceding SupBook
16504 snames: [], // sheetnames
16505 sharedf: sharedf, // shared formulae by address
16506 arrayf: arrayf, // array formulae array
16507 rrtabid: [], // RRTabId
16508 lastuser: "", // Last User from WriteAccess
16509 biff: 8, // BIFF version
16510 codepage: 0, // CP from CodePage record
16511 winlocked: 0, // fLockWn from WinProtect
16512 cellStyles: !!options && !!options.cellStyles,
16513 WTF: !!options && !!options.wtf
16514 });
16515 if(options.password) opts.password = options.password;
16516 var themes;
16517 var merges = [];
16518 var objects = [];
16519 var colinfo = [], rowinfo = [];
16520 // eslint-disable-next-line no-unused-vars
16521 var defwidth = 0, defheight = 0; // twips / MDW respectively
16522 var seencol = false;
16523 var supbooks = ([]); // 1-indexed, will hold extern names
16524 supbooks.SheetNames = opts.snames;
16525 supbooks.sharedf = opts.sharedf;
16526 supbooks.arrayf = opts.arrayf;
16527 supbooks.names = [];
16528 supbooks.XTI = [];
16529 var last_Rn = '';
16530 var file_depth = 0; /* TODO: make a real stack */
16531 var BIFF2Fmt = 0, BIFF2FmtTable = [];
16532 var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
16533 var last_lbl;
16534
16535 /* explicit override for some broken writers */
16536 opts.codepage = 1200;
16537 set_cp(1200);
16538 var seen_codepage = false;
16539 while(blob.l < blob.length - 1) {
16540 var s = blob.l;
16541 var RecordType = blob.read_shift(2);
16542 if(RecordType === 0 && last_Rn === 'EOF') break;
16543 var length = (blob.l === blob.length ? 0 : blob.read_shift(2));
16544 var R = XLSRecordEnum[RecordType];
16545 //console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length);
16546 //if(!R) console.log(blob.slice(blob.l, blob.l + length));
16547 if(R && R.f) {
16548 if(options.bookSheets) {
16549 if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
16550 }
16551 last_Rn = R.n;
16552 if(R.r === 2 || R.r == 12) {
16553 var rt = blob.read_shift(2); length -= 2;
16554 if(!opts.enc && rt !== RecordType && (((rt&0xFF)<<8)|(rt>>8)) !== RecordType) throw new Error("rt mismatch: " + rt + "!=" + RecordType);
16555 if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
16556 }
16557 //console.error(R,blob.l,length,blob.length);
16558 var val;
16559 if(R.n === 'EOF') val = R.f(blob, length, opts);
16560 else val = slurp(R, blob, length, opts);
16561 var Rn = R.n;
16562 if(file_depth == 0 && Rn != 'BOF') continue;
16563 /* nested switch statements to workaround V8 128 limit */
16564 switch(Rn) {
16565 /* Workbook Options */
16566 case 'Date1904':
16567wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break;
16568 case 'WriteProtect': wb.opts.WriteProtect = true; break;
16569 case 'FilePass':
16570 if(!opts.enc) blob.l = 0;
16571 opts.enc = val;
16572 if(!options.password) throw new Error("File is password-protected");
16573 if(val.valid == null) throw new Error("Encryption scheme unsupported");
16574 if(!val.valid) throw new Error("Password is incorrect");
16575 break;
16576 case 'WriteAccess': opts.lastuser = val; break;
16577 case 'FileSharing': break; //TODO
16578 case 'CodePage':
16579 /* overrides based on test cases */
16580 switch(val) {
16581 case 0x5212: val = 1200; break;
16582 case 0x8000: val = 10000; break;
16583 case 0x8001: val = 1252; break;
16584 }
16585 set_cp(opts.codepage = val);
16586 seen_codepage = true;
16587 break;
16588 case 'RRTabId': opts.rrtabid = val; break;
16589 case 'WinProtect': opts.winlocked = val; break;
16590 case 'Template': break; // TODO
16591 case 'BookBool': break; // TODO
16592 case 'UsesELFs': break;
16593 case 'MTRSettings': break;
16594 case 'RefreshAll':
16595 case 'CalcCount':
16596 case 'CalcDelta':
16597 case 'CalcIter':
16598 case 'CalcMode':
16599 case 'CalcPrecision':
16600 case 'CalcSaveRecalc':
16601 wb.opts[Rn] = val; break;
16602 case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
16603 case 'Uncalced': break;
16604 case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
16605 case 'WsBool':
16606 if(val.fDialog) out["!type"] = "dialog";
16607 break; // TODO
16608 case 'XF':
16609 XFs.push(val); break;
16610 case 'ExtSST': break; // TODO
16611 case 'BookExt': break; // TODO
16612 case 'RichTextStream': break;
16613 case 'BkHim': break;
16614
16615 case 'SupBook':
16616 supbooks.push([val]);
16617 supbooks[supbooks.length-1].XTI = [];
16618 break;
16619 case 'ExternName':
16620 supbooks[supbooks.length-1].push(val);
16621 break;
16622 case 'Index': break; // TODO
16623 case 'Lbl':
16624 last_lbl = ({
16625 Name: val.Name,
16626 Ref: stringify_formula(val.rgce,range,null,supbooks,opts)
16627 });
16628 if(val.itab > 0) last_lbl.Sheet = val.itab - 1;
16629 supbooks.names.push(last_lbl);
16630 if(!supbooks[0]) { supbooks[0] = []; supbooks[0].XTI = []; }
16631 supbooks[supbooks.length-1].push(val);
16632 if(val.Name == "_xlnm._FilterDatabase" && val.itab > 0)
16633 if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d')
16634 FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) };
16635 break;
16636 case 'ExternCount': opts.ExternCount = val; break;
16637 case 'ExternSheet':
16638 if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; }
16639 supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break;
16640 case 'NameCmt':
16641 /* TODO: search for correct name */
16642 if(opts.biff < 8) break;
16643 if(last_lbl != null) last_lbl.Comment = val[1];
16644 break;
16645
16646 case 'Protect': out["!protect"] = val; break; /* for sheet or book */
16647 case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
16648 case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/
16649
16650 case 'BoundSheet8': {
16651 Directory[val.pos] = val;
16652 opts.snames.push(val.name);
16653 } break;
16654 case 'EOF': {
16655 if(--file_depth) break;
16656 if(range.e) {
16657 if(range.e.r > 0 && range.e.c > 0) {
16658 range.e.r--; range.e.c--;
16659 out["!ref"] = encode_range(range);
16660 if(options.sheetRows && options.sheetRows <= range.e.r) {
16661 var tmpri = range.e.r;
16662 range.e.r = options.sheetRows - 1;
16663 out["!fullref"] = out["!ref"];
16664 out["!ref"] = encode_range(range);
16665 range.e.r = tmpri;
16666 }
16667 range.e.r++; range.e.c++;
16668 }
16669 if(merges.length > 0) out["!merges"] = merges;
16670 if(objects.length > 0) out["!objects"] = objects;
16671 if(colinfo.length > 0) out["!cols"] = colinfo;
16672 if(rowinfo.length > 0) out["!rows"] = rowinfo;
16673 Workbook.Sheets.push(wsprops);
16674 }
16675 if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
16676 out = ((options.dense ? [] : {}));
16677 } break;
16678 case 'BOF': {
16679 if(opts.biff === 8) opts.biff = {
166800x0009:2,
166810x0209:3,
166820x0409:4
16683 }[RecordType] || {
166840x0200:2,
166850x0300:3,
166860x0400:4,
166870x0500:5,
166880x0600:8,
166890x0002:2,
166900x0007:2
16691 }[val.BIFFVer] || 8;
16692 if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
16693 if(file_depth++) break;
16694 cell_valid = true;
16695 out = ((options.dense ? [] : {}));
16696
16697 if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
16698 if(opts.biff < 5) {
16699 if(cur_sheet === "") cur_sheet = "Sheet1";
16700 range = {s:{r:0,c:0},e:{r:0,c:0}};
16701 /* fake BoundSheet8 */
16702 var fakebs8 = {pos: blob.l - length, name:cur_sheet};
16703 Directory[fakebs8.pos] = fakebs8;
16704 opts.snames.push(cur_sheet);
16705 }
16706 else cur_sheet = (Directory[s] || {name:""}).name;
16707 if(val.dt == 0x20) out["!type"] = "chart";
16708 if(val.dt == 0x40) out["!type"] = "macro";
16709 merges = [];
16710 objects = [];
16711 opts.arrayf = arrayf = [];
16712 colinfo = []; rowinfo = [];
16713 defwidth = defheight = 0;
16714 seencol = false;
16715 wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
16716 } break;
16717
16718 case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
16719 if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
16720 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'});
16721 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16722 safe_format_xf(temp_val, options, wb.opts.Date1904);
16723 addcell({c:val.c, r:val.r}, temp_val, options);
16724 } break;
16725 case 'BoolErr': {
16726 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t});
16727 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16728 safe_format_xf(temp_val, options, wb.opts.Date1904);
16729 addcell({c:val.c, r:val.r}, temp_val, options);
16730 } break;
16731 case 'RK': {
16732 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'});
16733 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16734 safe_format_xf(temp_val, options, wb.opts.Date1904);
16735 addcell({c:val.c, r:val.r}, temp_val, options);
16736 } break;
16737 case 'MulRk': {
16738 for(var j = val.c; j <= val.C; ++j) {
16739 var ixfe = val.rkrec[j-val.c][0];
16740 temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'});
16741 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16742 safe_format_xf(temp_val, options, wb.opts.Date1904);
16743 addcell({c:j, r:val.r}, temp_val, options);
16744 }
16745 } break;
16746 case 'Formula': {
16747 if(val.val == 'String') { last_formula = val; break; }
16748 temp_val = make_cell(val.val, val.cell.ixfe, val.tt);
16749 temp_val.XF = XFs[temp_val.ixfe];
16750 if(options.cellFormula) {
16751 var _f = val.formula;
16752 if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
16753 var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
16754 var _fe = encode_cell({r:_fr, c:_fc});
16755 if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
16756 else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
16757 } else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
16758 }
16759 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16760 safe_format_xf(temp_val, options, wb.opts.Date1904);
16761 addcell(val.cell, temp_val, options);
16762 last_formula = val;
16763 } break;
16764 case 'String': {
16765 if(last_formula) { /* technically always true */
16766 last_formula.val = val;
16767 temp_val = make_cell(val, last_formula.cell.ixfe, 's');
16768 temp_val.XF = XFs[temp_val.ixfe];
16769 if(options.cellFormula) {
16770 temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
16771 }
16772 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16773 safe_format_xf(temp_val, options, wb.opts.Date1904);
16774 addcell(last_formula.cell, temp_val, options);
16775 last_formula = null;
16776 } else throw new Error("String record expects Formula");
16777 } break;
16778 case 'Array': {
16779 arrayf.push(val);
16780 var _arraystart = encode_cell(val[0].s);
16781 cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
16782 if(options.cellFormula && cc) {
16783 if(!last_formula) break; /* technically unreachable */
16784 if(!_arraystart || !cc) break;
16785 cc.f = ""+stringify_formula(val[1], range, val[0], supbooks, opts);
16786 cc.F = encode_range(val[0]);
16787 }
16788 } break;
16789 case 'ShrFmla': {
16790 if(!cell_valid) break;
16791 if(!options.cellFormula) break;
16792 if(last_cell) {
16793 /* TODO: capture range */
16794 if(!last_formula) break; /* technically unreachable */
16795 sharedf[encode_cell(last_formula.cell)]= val[0];
16796 cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
16797 (cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
16798 }
16799 } break;
16800 case 'LabelSst':
16801 temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
16802 temp_val.XF = XFs[temp_val.ixfe];
16803 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16804 safe_format_xf(temp_val, options, wb.opts.Date1904);
16805 addcell({c:val.c, r:val.r}, temp_val, options);
16806 break;
16807 case 'Blank': if(options.sheetStubs) {
16808 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'});
16809 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16810 safe_format_xf(temp_val, options, wb.opts.Date1904);
16811 addcell({c:val.c, r:val.r}, temp_val, options);
16812 } break;
16813 case 'MulBlank': if(options.sheetStubs) {
16814 for(var _j = val.c; _j <= val.C; ++_j) {
16815 var _ixfe = val.ixfe[_j-val.c];
16816 temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'});
16817 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16818 safe_format_xf(temp_val, options, wb.opts.Date1904);
16819 addcell({c:_j, r:val.r}, temp_val, options);
16820 }
16821 } break;
16822 case 'RString':
16823 case 'Label': case 'BIFF2STR':
16824 temp_val=make_cell(val.val, val.ixfe, 's');
16825 temp_val.XF = XFs[temp_val.ixfe];
16826 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
16827 safe_format_xf(temp_val, options, wb.opts.Date1904);
16828 addcell({c:val.c, r:val.r}, temp_val, options);
16829 break;
16830
16831 case 'Dimensions': {
16832 if(file_depth === 1) range = val; /* TODO: stack */
16833 } break;
16834 case 'SST': {
16835 sst = val;
16836 } break;
16837 case 'Format': { /* val = [id, fmt] */
16838 if(opts.biff == 4) {
16839 BIFF2FmtTable[BIFF2Fmt++] = val[1];
16840 for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(SSF._table[b4idx] == val[1]) break;
16841 if(b4idx >= 163) SSF.load(val[1], BIFF2Fmt + 163);
16842 }
16843 else SSF.load(val[1], val[0]);
16844 } break;
16845 case 'BIFF2FORMAT': {
16846 BIFF2FmtTable[BIFF2Fmt++] = val;
16847 for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break;
16848 if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163);
16849 } break;
16850
16851 case 'MergeCells': merges = merges.concat(val); break;
16852
16853 case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break;
16854 case 'TxO': opts.lastobj.TxO = val; break;
16855 case 'ImData': opts.lastobj.ImData = val; break;
16856
16857 case 'HLink': {
16858 for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
16859 for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
16860 cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
16861 if(cc) cc.l = val[1];
16862 }
16863 } break;
16864 case 'HLinkTooltip': {
16865 for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
16866 for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
16867 cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
16868 if(cc && cc.l) cc.l.Tooltip = val[1];
16869 }
16870 } break;
16871
16872 /* Comments */
16873 case 'Note': {
16874 if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
16875 cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
16876 var noteobj = objects[val[2]];
16877 if(!cc) break;
16878 if(!cc.c) cc.c = [];
16879 cmnt = {a:val[1],t:noteobj.TxO.t};
16880 cc.c.push(cmnt);
16881 } break;
16882
16883 default: switch(R.n) { /* nested */
16884 case 'ClrtClient': break;
16885 case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break;
16886
16887 case 'DefColWidth': defwidth = val; break;
16888 case 'DefaultRowHeight': defheight = val[1]; break; // TODO: flags
16889
16890 case 'ColInfo': {
16891 if(!opts.cellStyles) break;
16892 while(val.e >= val.s) {
16893 colinfo[val.e--] = { width: val.w/256 };
16894 if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
16895 process_col(colinfo[val.e+1]);
16896 }
16897 } break;
16898 case 'Row': {
16899 var rowobj = {};
16900 if(val.level != null) { rowinfo[val.r] = rowobj; rowobj.level = val.level; }
16901 if(val.hidden) { rowinfo[val.r] = rowobj; rowobj.hidden = true; }
16902 if(val.hpt) {
16903 rowinfo[val.r] = rowobj;
16904 rowobj.hpt = val.hpt; rowobj.hpx = pt2px(val.hpt);
16905 }
16906 } break;
16907
16908 case 'LeftMargin':
16909 case 'RightMargin':
16910 case 'TopMargin':
16911 case 'BottomMargin':
16912 if(!out['!margins']) default_margins(out['!margins'] = {});
16913 out['!margins'][Rn.slice(0,-6).toLowerCase()] = val;
16914 break;
16915
16916 case 'Setup': // TODO
16917 if(!out['!margins']) default_margins(out['!margins'] = {});
16918 out['!margins'].header = val.header;
16919 out['!margins'].footer = val.footer;
16920 break;
16921
16922 case 'Window2': // TODO
16923 // $FlowIgnore
16924 if(val.RTL) Workbook.Views[0].RTL = true;
16925 break;
16926
16927 case 'Header': break; // TODO
16928 case 'Footer': break; // TODO
16929 case 'HCenter': break; // TODO
16930 case 'VCenter': break; // TODO
16931 case 'Pls': break; // TODO
16932 case 'GCW': break;
16933 case 'LHRecord': break;
16934 case 'DBCell': break; // TODO
16935 case 'EntExU2': break; // TODO
16936 case 'SxView': break; // TODO
16937 case 'Sxvd': break; // TODO
16938 case 'SXVI': break; // TODO
16939 case 'SXVDEx': break; // TODO
16940 case 'SxIvd': break; // TODO
16941 case 'SXString': break; // TODO
16942 case 'Sync': break;
16943 case 'Addin': break;
16944 case 'SXDI': break; // TODO
16945 case 'SXLI': break; // TODO
16946 case 'SXEx': break; // TODO
16947 case 'QsiSXTag': break; // TODO
16948 case 'Selection': break;
16949 case 'Feat': break;
16950 case 'FeatHdr': case 'FeatHdr11': break;
16951 case 'Feature11': case 'Feature12': case 'List12': break;
16952 case 'Country': country = val; break;
16953 case 'RecalcId': break;
16954 case 'DxGCol': break; // TODO: htmlify
16955 case 'Fbi': case 'Fbi2': case 'GelFrame': break;
16956 case 'Font': break; // TODO
16957 case 'XFCRC': break; // TODO
16958 case 'Style': break; // TODO
16959 case 'StyleExt': break; // TODO
16960 case 'Palette': palette = val; break;
16961 case 'Theme': themes = val; break;
16962 /* Protection */
16963 case 'ScenarioProtect': break;
16964 case 'ObjProtect': break;
16965
16966 /* Conditional Formatting */
16967 case 'CondFmt12': break;
16968
16969 /* Table */
16970 case 'Table': break; // TODO
16971 case 'TableStyles': break; // TODO
16972 case 'TableStyle': break; // TODO
16973 case 'TableStyleElement': break; // TODO
16974
16975 /* PivotTable */
16976 case 'SXStreamID': break; // TODO
16977 case 'SXVS': break; // TODO
16978 case 'DConRef': break; // TODO
16979 case 'SXAddl': break; // TODO
16980 case 'DConBin': break; // TODO
16981 case 'DConName': break; // TODO
16982 case 'SXPI': break; // TODO
16983 case 'SxFormat': break; // TODO
16984 case 'SxSelect': break; // TODO
16985 case 'SxRule': break; // TODO
16986 case 'SxFilt': break; // TODO
16987 case 'SxItm': break; // TODO
16988 case 'SxDXF': break; // TODO
16989
16990 /* Scenario Manager */
16991 case 'ScenMan': break;
16992
16993 /* Data Consolidation */
16994 case 'DCon': break;
16995
16996 /* Watched Cell */
16997 case 'CellWatch': break;
16998
16999 /* Print Settings */
17000 case 'PrintRowCol': break;
17001 case 'PrintGrid': break;
17002 case 'PrintSize': break;
17003
17004 case 'XCT': break;
17005 case 'CRN': break;
17006
17007 case 'Scl': {
17008 //console.log("Zoom Level:", val[0]/val[1],val);
17009 } break;
17010 case 'SheetExt': {
17011 /* empty */
17012 } break;
17013 case 'SheetExtOptional': {
17014 /* empty */
17015 } break;
17016
17017 /* VBA */
17018 case 'ObNoMacros': {
17019 /* empty */
17020 } break;
17021 case 'ObProj': {
17022 /* empty */
17023 } break;
17024 case 'CodeName': {
17025if(!cur_sheet) Workbook.WBProps.CodeName = val || "ThisWorkbook";
17026 else wsprops.CodeName = val || wsprops.name;
17027 } break;
17028 case 'GUIDTypeLib': {
17029 /* empty */
17030 } break;
17031
17032 case 'WOpt': break; // TODO: WTF?
17033 case 'PhoneticInfo': break;
17034
17035 case 'OleObjectSize': break;
17036
17037 /* Differential Formatting */
17038 case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break;
17039
17040 /* Data Validation */
17041 case 'Dv': case 'DVal': break;
17042
17043 /* Data Series */
17044 case 'BRAI': case 'Series': case 'SeriesText': break;
17045
17046 /* Data Connection */
17047 case 'DConn': break;
17048 case 'DbOrParamQry': break;
17049 case 'DBQueryExt': break;
17050
17051 case 'OleDbConn': break;
17052 case 'ExtString': break;
17053
17054 /* Formatting */
17055 case 'IFmtRecord': break;
17056 case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
17057
17058 /* Explicitly Ignored */
17059 case 'Excel9File': break;
17060 case 'Units': break;
17061 case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break;
17062 case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break;
17063 /* View Stuff */
17064 case 'Window1': case 'HideObj': case 'GridSet': case 'Guts':
17065 case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd':
17066 case 'Pane': break;
17067 default: switch(R.n) { /* nested */
17068 /* Chart */
17069 case 'Dat':
17070 case 'Begin': case 'End':
17071 case 'StartBlock': case 'EndBlock':
17072 case 'Frame': case 'Area':
17073 case 'Axis': case 'AxisLine': case 'Tick': break;
17074 case 'AxesUsed':
17075 case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break;
17076 case 'LineFormat': case 'AreaFormat':
17077 case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break;
17078 case 'PlotArea': case 'PlotGrowth': break;
17079 case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break;
17080 case 'DataFormat': case 'SerToCrt': case 'FontX': break;
17081 case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
17082 case 'ShtProps': break;
17083 case 'DefaultText': case 'Text': case 'CatLab': break;
17084 case 'DataLabExtContents': break;
17085 case 'Legend': case 'LegendException': break;
17086 case 'Pie': case 'Scatter': break;
17087 case 'PieFormat': case 'MarkerFormat': break;
17088 case 'StartObject': case 'EndObject': break;
17089 case 'AlRuns': case 'ObjectLink': break;
17090 case 'SIIndex': break;
17091 case 'AttachedLabel': case 'YMult': break;
17092
17093 /* Chart Group */
17094 case 'Line': case 'Bar': break;
17095 case 'Surf': break;
17096
17097 /* Axis Group */
17098 case 'AxisParent': break;
17099 case 'Pos': break;
17100 case 'ValueRange': break;
17101
17102 /* Pivot Chart */
17103 case 'SXViewEx9': break; // TODO
17104 case 'SXViewLink': break;
17105 case 'PivotChartBits': break;
17106 case 'SBaseRef': break;
17107 case 'TextPropsStream': break;
17108
17109 /* Chart Misc */
17110 case 'LnExt': break;
17111 case 'MkrExt': break;
17112 case 'CrtCoopt': break;
17113
17114 /* Query Table */
17115 case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break;
17116 case 'TxtQry': break;
17117
17118 /* Filter */
17119 case 'FilterMode': break;
17120 case 'AutoFilter': case 'AutoFilterInfo': break;
17121 case 'AutoFilter12': break;
17122 case 'DropDownObjIds': break;
17123 case 'Sort': break;
17124 case 'SortData': break;
17125
17126 /* Drawing */
17127 case 'ShapePropsStream': break;
17128 case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
17129 /* Pub Stuff */
17130 case 'WebPub': case 'AutoWebPub': break;
17131
17132 /* Print Stuff */
17133 case 'HeaderFooter': case 'HFPicture': case 'PLV':
17134 case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break;
17135 /* Behavioral */
17136 case 'Backup': case 'CompressPictures': case 'Compat12': break;
17137
17138 /* Should not Happen */
17139 case 'Continue': case 'ContinueFrt12': break;
17140
17141 /* Future Records */
17142 case 'FrtFontList': case 'FrtWrapper': break;
17143
17144 default: switch(R.n) { /* nested */
17145 /* BIFF5 records */
17146 case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
17147
17148 /* BIFF2-4 records */
17149 case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break;
17150 case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break;
17151 case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break;
17152
17153 /* Miscellaneous */
17154 case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':
17155 case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData':
17156 case 'Name': break;
17157 case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break;
17158 case 'ListObj': case 'ListField': break;
17159 case 'RRSort': break;
17160 case 'BigName': break;
17161 case 'ToolbarHdr': case 'ToolbarEnd': break;
17162 case 'DDEObjName': break;
17163 case 'FRTArchId$': break;
17164 default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
17165 }}}}
17166 } else blob.l += length;
17167 }
17168 wb.SheetNames=keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;});
17169 if(!options.bookSheets) wb.Sheets=Sheets;
17170 if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; });
17171 wb.Preamble=Preamble;
17172 wb.Strings = sst;
17173 wb.SSF = SSF.get_table();
17174 if(opts.enc) wb.Encryption = opts.enc;
17175 if(themes) wb.Themes = themes;
17176 wb.Metadata = {};
17177 if(country !== undefined) wb.Metadata.Country = country;
17178 if(supbooks.names.length > 0) Workbook.Names = supbooks.names;
17179 wb.Workbook = Workbook;
17180 return wb;
17181}
17182
17183/* TODO: split props*/
17184var PSCLSID = {
17185 SI: "e0859ff2f94f6810ab9108002b27b3d9",
17186 DSI: "02d5cdd59c2e1b10939708002b2cf9ae",
17187 UDI: "05d5cdd59c2e1b10939708002b2cf9ae"
17188};
17189function parse_xls_props(cfb, props, o) {
17190 /* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
17191 var DSI = CFB.find(cfb, '!DocumentSummaryInformation');
17192 if(DSI && DSI.size > 0) try {
17193 var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI);
17194 for(var d in DocSummary) props[d] = DocSummary[d];
17195 } catch(e) {if(o.WTF) throw e;/* empty */}
17196
17197 /* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
17198 var SI = CFB.find(cfb, '!SummaryInformation');
17199 if(SI && SI.size > 0) try {
17200 var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI);
17201 for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
17202 } catch(e) {if(o.WTF) throw e;/* empty */}
17203
17204 if(props.HeadingPairs && props.TitlesOfParts) {
17205 load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o);
17206 delete props.HeadingPairs; delete props.TitlesOfParts;
17207 }
17208}
17209function write_xls_props(wb, cfb) {
17210 var DSEntries = [], SEntries = [], CEntries = [];
17211 var i = 0, Keys;
17212 if(wb.Props) {
17213 Keys = keys(wb.Props);
17214 // $FlowIgnore
17215 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]]]);
17216 }
17217 if(wb.Custprops) {
17218 Keys = keys(wb.Custprops);
17219 // $FlowIgnore
17220 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]]]);
17221 }
17222 var CEntries2 = [];
17223 for(i = 0; i < CEntries.length; ++i) {
17224 if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue;
17225 if(CEntries[i][1] == null) continue;
17226 CEntries2.push(CEntries[i]);
17227 }
17228 if(SEntries.length) CFB.utils.cfb_add(cfb, "/\u0005SummaryInformation", write_PropertySetStream(SEntries, PSCLSID.SI, SummaryRE, SummaryPIDSI));
17229 if(DSEntries.length || CEntries2.length) CFB.utils.cfb_add(cfb, "/\u0005DocumentSummaryInformation", write_PropertySetStream(DSEntries, PSCLSID.DSI, DocSummaryRE, DocSummaryPIDDSI, CEntries2.length ? CEntries2 : null, PSCLSID.UDI));
17230}
17231
17232function parse_xlscfb(cfb, options) {
17233if(!options) options = {};
17234fix_read_opts(options);
17235reset_cp();
17236if(options.codepage) set_ansi(options.codepage);
17237var CompObj, WB;
17238if(cfb.FullPaths) {
17239 if(CFB.find(cfb, '/encryption')) throw new Error("File is password-protected");
17240 CompObj = CFB.find(cfb, '!CompObj');
17241 WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
17242} else {
17243 switch(options.type) {
17244 case 'base64': cfb = s2a(Base64.decode(cfb)); break;
17245 case 'binary': cfb = s2a(cfb); break;
17246 case 'buffer': break;
17247 case 'array': if(!Array.isArray(cfb)) cfb = Array.prototype.slice.call(cfb); break;
17248 }
17249 prep_blob(cfb, 0);
17250 WB = ({content: cfb});
17251}
17252var WorkbookP;
17253
17254var _data;
17255if(CompObj) parse_compobj(CompObj);
17256if(options.bookProps && !options.bookSheets) WorkbookP = ({});
17257else {
17258 var T = has_buf ? 'buffer' : 'array';
17259 if(WB && WB.content) WorkbookP = parse_workbook(WB.content, options);
17260 /* Quattro Pro 7-8 */
17261 else if((_data=CFB.find(cfb, 'PerfectOffice_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
17262 /* Quattro Pro 9 */
17263 else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
17264 else throw new Error("Cannot find Workbook stream");
17265 if(options.bookVBA && cfb.FullPaths && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb);
17266}
17267
17268var props = {};
17269if(cfb.FullPaths) parse_xls_props(cfb, props, options);
17270
17271WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
17272if(options.bookFiles) WorkbookP.cfb = cfb;
17273/*WorkbookP.CompObjP = CompObjP; // TODO: storage? */
17274return WorkbookP;
17275}
17276
17277
17278function write_xlscfb(wb, opts) {
17279 var o = opts || {};
17280 var cfb = CFB.utils.cfb_new({root:"R"});
17281 var wbpath = "/Workbook";
17282 switch(o.bookType || "xls") {
17283 case "xls": o.bookType = "biff8";
17284 /* falls through */
17285 case "xla": if(!o.bookType) o.bookType = "xla";
17286 /* falls through */
17287 case "biff8": wbpath = "/Workbook"; o.biff = 8; break;
17288 case "biff5": wbpath = "/Book"; o.biff = 5; break;
17289 default: throw new Error("invalid type " + o.bookType + " for XLS CFB");
17290 }
17291 CFB.utils.cfb_add(cfb, wbpath, write_biff_buf(wb, o));
17292 if(o.biff == 8 && (wb.Props || wb.Custprops)) write_xls_props(wb, cfb);
17293 // TODO: SI, DSI, CO
17294 if(o.biff == 8 && wb.vbaraw) fill_vba_xls(cfb, CFB.read(wb.vbaraw, {type: typeof wb.vbaraw == "string" ? "binary" : "buffer"}));
17295 return cfb;
17296}
17297/* [MS-XLSB] 2.3 Record Enumeration */
17298var XLSBRecordEnum = {
172990x0000: { n:"BrtRowHdr", f:parse_BrtRowHdr },
173000x0001: { n:"BrtCellBlank", f:parse_BrtCellBlank },
173010x0002: { n:"BrtCellRk", f:parse_BrtCellRk },
173020x0003: { n:"BrtCellError", f:parse_BrtCellError },
173030x0004: { n:"BrtCellBool", f:parse_BrtCellBool },
173040x0005: { n:"BrtCellReal", f:parse_BrtCellReal },
173050x0006: { n:"BrtCellSt", f:parse_BrtCellSt },
173060x0007: { n:"BrtCellIsst", f:parse_BrtCellIsst },
173070x0008: { n:"BrtFmlaString", f:parse_BrtFmlaString },
173080x0009: { n:"BrtFmlaNum", f:parse_BrtFmlaNum },
173090x000A: { n:"BrtFmlaBool", f:parse_BrtFmlaBool },
173100x000B: { n:"BrtFmlaError", f:parse_BrtFmlaError },
173110x0010: { n:"BrtFRTArchID$", f:parse_BrtFRTArchID$ },
173120x0013: { n:"BrtSSTItem", f:parse_RichStr },
173130x0014: { n:"BrtPCDIMissing" },
173140x0015: { n:"BrtPCDINumber" },
173150x0016: { n:"BrtPCDIBoolean" },
173160x0017: { n:"BrtPCDIError" },
173170x0018: { n:"BrtPCDIString" },
173180x0019: { n:"BrtPCDIDatetime" },
173190x001A: { n:"BrtPCDIIndex" },
173200x001B: { n:"BrtPCDIAMissing" },
173210x001C: { n:"BrtPCDIANumber" },
173220x001D: { n:"BrtPCDIABoolean" },
173230x001E: { n:"BrtPCDIAError" },
173240x001F: { n:"BrtPCDIAString" },
173250x0020: { n:"BrtPCDIADatetime" },
173260x0021: { n:"BrtPCRRecord" },
173270x0022: { n:"BrtPCRRecordDt" },
173280x0023: { n:"BrtFRTBegin" },
173290x0024: { n:"BrtFRTEnd" },
173300x0025: { n:"BrtACBegin" },
173310x0026: { n:"BrtACEnd" },
173320x0027: { n:"BrtName", f:parse_BrtName },
173330x0028: { n:"BrtIndexRowBlock" },
173340x002A: { n:"BrtIndexBlock" },
173350x002B: { n:"BrtFont", f:parse_BrtFont },
173360x002C: { n:"BrtFmt", f:parse_BrtFmt },
173370x002D: { n:"BrtFill", f:parse_BrtFill },
173380x002E: { n:"BrtBorder", f:parse_BrtBorder },
173390x002F: { n:"BrtXF", f:parse_BrtXF },
173400x0030: { n:"BrtStyle" },
173410x0031: { n:"BrtCellMeta" },
173420x0032: { n:"BrtValueMeta" },
173430x0033: { n:"BrtMdb" },
173440x0034: { n:"BrtBeginFmd" },
173450x0035: { n:"BrtEndFmd" },
173460x0036: { n:"BrtBeginMdx" },
173470x0037: { n:"BrtEndMdx" },
173480x0038: { n:"BrtBeginMdxTuple" },
173490x0039: { n:"BrtEndMdxTuple" },
173500x003A: { n:"BrtMdxMbrIstr" },
173510x003B: { n:"BrtStr" },
173520x003C: { n:"BrtColInfo", f:parse_ColInfo },
173530x003E: { n:"BrtCellRString" },
173540x003F: { n:"BrtCalcChainItem$", f:parse_BrtCalcChainItem$ },
173550x0040: { n:"BrtDVal" },
173560x0041: { n:"BrtSxvcellNum" },
173570x0042: { n:"BrtSxvcellStr" },
173580x0043: { n:"BrtSxvcellBool" },
173590x0044: { n:"BrtSxvcellErr" },
173600x0045: { n:"BrtSxvcellDate" },
173610x0046: { n:"BrtSxvcellNil" },
173620x0080: { n:"BrtFileVersion" },
173630x0081: { n:"BrtBeginSheet" },
173640x0082: { n:"BrtEndSheet" },
173650x0083: { n:"BrtBeginBook", f:parsenoop, p:0 },
173660x0084: { n:"BrtEndBook" },
173670x0085: { n:"BrtBeginWsViews" },
173680x0086: { n:"BrtEndWsViews" },
173690x0087: { n:"BrtBeginBookViews" },
173700x0088: { n:"BrtEndBookViews" },
173710x0089: { n:"BrtBeginWsView", f:parse_BrtBeginWsView },
173720x008A: { n:"BrtEndWsView" },
173730x008B: { n:"BrtBeginCsViews" },
173740x008C: { n:"BrtEndCsViews" },
173750x008D: { n:"BrtBeginCsView" },
173760x008E: { n:"BrtEndCsView" },
173770x008F: { n:"BrtBeginBundleShs" },
173780x0090: { n:"BrtEndBundleShs" },
173790x0091: { n:"BrtBeginSheetData" },
173800x0092: { n:"BrtEndSheetData" },
173810x0093: { n:"BrtWsProp", f:parse_BrtWsProp },
173820x0094: { n:"BrtWsDim", f:parse_BrtWsDim, p:16 },
173830x0097: { n:"BrtPane" },
173840x0098: { n:"BrtSel" },
173850x0099: { n:"BrtWbProp", f:parse_BrtWbProp },
173860x009A: { n:"BrtWbFactoid" },
173870x009B: { n:"BrtFileRecover" },
173880x009C: { n:"BrtBundleSh", f:parse_BrtBundleSh },
173890x009D: { n:"BrtCalcProp" },
173900x009E: { n:"BrtBookView" },
173910x009F: { n:"BrtBeginSst", f:parse_BrtBeginSst },
173920x00A0: { n:"BrtEndSst" },
173930x00A1: { n:"BrtBeginAFilter", f:parse_UncheckedRfX },
173940x00A2: { n:"BrtEndAFilter" },
173950x00A3: { n:"BrtBeginFilterColumn" },
173960x00A4: { n:"BrtEndFilterColumn" },
173970x00A5: { n:"BrtBeginFilters" },
173980x00A6: { n:"BrtEndFilters" },
173990x00A7: { n:"BrtFilter" },
174000x00A8: { n:"BrtColorFilter" },
174010x00A9: { n:"BrtIconFilter" },
174020x00AA: { n:"BrtTop10Filter" },
174030x00AB: { n:"BrtDynamicFilter" },
174040x00AC: { n:"BrtBeginCustomFilters" },
174050x00AD: { n:"BrtEndCustomFilters" },
174060x00AE: { n:"BrtCustomFilter" },
174070x00AF: { n:"BrtAFilterDateGroupItem" },
174080x00B0: { n:"BrtMergeCell", f:parse_BrtMergeCell },
174090x00B1: { n:"BrtBeginMergeCells" },
174100x00B2: { n:"BrtEndMergeCells" },
174110x00B3: { n:"BrtBeginPivotCacheDef" },
174120x00B4: { n:"BrtEndPivotCacheDef" },
174130x00B5: { n:"BrtBeginPCDFields" },
174140x00B6: { n:"BrtEndPCDFields" },
174150x00B7: { n:"BrtBeginPCDField" },
174160x00B8: { n:"BrtEndPCDField" },
174170x00B9: { n:"BrtBeginPCDSource" },
174180x00BA: { n:"BrtEndPCDSource" },
174190x00BB: { n:"BrtBeginPCDSRange" },
174200x00BC: { n:"BrtEndPCDSRange" },
174210x00BD: { n:"BrtBeginPCDFAtbl" },
174220x00BE: { n:"BrtEndPCDFAtbl" },
174230x00BF: { n:"BrtBeginPCDIRun" },
174240x00C0: { n:"BrtEndPCDIRun" },
174250x00C1: { n:"BrtBeginPivotCacheRecords" },
174260x00C2: { n:"BrtEndPivotCacheRecords" },
174270x00C3: { n:"BrtBeginPCDHierarchies" },
174280x00C4: { n:"BrtEndPCDHierarchies" },
174290x00C5: { n:"BrtBeginPCDHierarchy" },
174300x00C6: { n:"BrtEndPCDHierarchy" },
174310x00C7: { n:"BrtBeginPCDHFieldsUsage" },
174320x00C8: { n:"BrtEndPCDHFieldsUsage" },
174330x00C9: { n:"BrtBeginExtConnection" },
174340x00CA: { n:"BrtEndExtConnection" },
174350x00CB: { n:"BrtBeginECDbProps" },
174360x00CC: { n:"BrtEndECDbProps" },
174370x00CD: { n:"BrtBeginECOlapProps" },
174380x00CE: { n:"BrtEndECOlapProps" },
174390x00CF: { n:"BrtBeginPCDSConsol" },
174400x00D0: { n:"BrtEndPCDSConsol" },
174410x00D1: { n:"BrtBeginPCDSCPages" },
174420x00D2: { n:"BrtEndPCDSCPages" },
174430x00D3: { n:"BrtBeginPCDSCPage" },
174440x00D4: { n:"BrtEndPCDSCPage" },
174450x00D5: { n:"BrtBeginPCDSCPItem" },
174460x00D6: { n:"BrtEndPCDSCPItem" },
174470x00D7: { n:"BrtBeginPCDSCSets" },
174480x00D8: { n:"BrtEndPCDSCSets" },
174490x00D9: { n:"BrtBeginPCDSCSet" },
174500x00DA: { n:"BrtEndPCDSCSet" },
174510x00DB: { n:"BrtBeginPCDFGroup" },
174520x00DC: { n:"BrtEndPCDFGroup" },
174530x00DD: { n:"BrtBeginPCDFGItems" },
174540x00DE: { n:"BrtEndPCDFGItems" },
174550x00DF: { n:"BrtBeginPCDFGRange" },
174560x00E0: { n:"BrtEndPCDFGRange" },
174570x00E1: { n:"BrtBeginPCDFGDiscrete" },
174580x00E2: { n:"BrtEndPCDFGDiscrete" },
174590x00E3: { n:"BrtBeginPCDSDTupleCache" },
174600x00E4: { n:"BrtEndPCDSDTupleCache" },
174610x00E5: { n:"BrtBeginPCDSDTCEntries" },
174620x00E6: { n:"BrtEndPCDSDTCEntries" },
174630x00E7: { n:"BrtBeginPCDSDTCEMembers" },
174640x00E8: { n:"BrtEndPCDSDTCEMembers" },
174650x00E9: { n:"BrtBeginPCDSDTCEMember" },
174660x00EA: { n:"BrtEndPCDSDTCEMember" },
174670x00EB: { n:"BrtBeginPCDSDTCQueries" },
174680x00EC: { n:"BrtEndPCDSDTCQueries" },
174690x00ED: { n:"BrtBeginPCDSDTCQuery" },
174700x00EE: { n:"BrtEndPCDSDTCQuery" },
174710x00EF: { n:"BrtBeginPCDSDTCSets" },
174720x00F0: { n:"BrtEndPCDSDTCSets" },
174730x00F1: { n:"BrtBeginPCDSDTCSet" },
174740x00F2: { n:"BrtEndPCDSDTCSet" },
174750x00F3: { n:"BrtBeginPCDCalcItems" },
174760x00F4: { n:"BrtEndPCDCalcItems" },
174770x00F5: { n:"BrtBeginPCDCalcItem" },
174780x00F6: { n:"BrtEndPCDCalcItem" },
174790x00F7: { n:"BrtBeginPRule" },
174800x00F8: { n:"BrtEndPRule" },
174810x00F9: { n:"BrtBeginPRFilters" },
174820x00FA: { n:"BrtEndPRFilters" },
174830x00FB: { n:"BrtBeginPRFilter" },
174840x00FC: { n:"BrtEndPRFilter" },
174850x00FD: { n:"BrtBeginPNames" },
174860x00FE: { n:"BrtEndPNames" },
174870x00FF: { n:"BrtBeginPName" },
174880x0100: { n:"BrtEndPName" },
174890x0101: { n:"BrtBeginPNPairs" },
174900x0102: { n:"BrtEndPNPairs" },
174910x0103: { n:"BrtBeginPNPair" },
174920x0104: { n:"BrtEndPNPair" },
174930x0105: { n:"BrtBeginECWebProps" },
174940x0106: { n:"BrtEndECWebProps" },
174950x0107: { n:"BrtBeginEcWpTables" },
174960x0108: { n:"BrtEndECWPTables" },
174970x0109: { n:"BrtBeginECParams" },
174980x010A: { n:"BrtEndECParams" },
174990x010B: { n:"BrtBeginECParam" },
175000x010C: { n:"BrtEndECParam" },
175010x010D: { n:"BrtBeginPCDKPIs" },
175020x010E: { n:"BrtEndPCDKPIs" },
175030x010F: { n:"BrtBeginPCDKPI" },
175040x0110: { n:"BrtEndPCDKPI" },
175050x0111: { n:"BrtBeginDims" },
175060x0112: { n:"BrtEndDims" },
175070x0113: { n:"BrtBeginDim" },
175080x0114: { n:"BrtEndDim" },
175090x0115: { n:"BrtIndexPartEnd" },
175100x0116: { n:"BrtBeginStyleSheet" },
175110x0117: { n:"BrtEndStyleSheet" },
175120x0118: { n:"BrtBeginSXView" },
175130x0119: { n:"BrtEndSXVI" },
175140x011A: { n:"BrtBeginSXVI" },
175150x011B: { n:"BrtBeginSXVIs" },
175160x011C: { n:"BrtEndSXVIs" },
175170x011D: { n:"BrtBeginSXVD" },
175180x011E: { n:"BrtEndSXVD" },
175190x011F: { n:"BrtBeginSXVDs" },
175200x0120: { n:"BrtEndSXVDs" },
175210x0121: { n:"BrtBeginSXPI" },
175220x0122: { n:"BrtEndSXPI" },
175230x0123: { n:"BrtBeginSXPIs" },
175240x0124: { n:"BrtEndSXPIs" },
175250x0125: { n:"BrtBeginSXDI" },
175260x0126: { n:"BrtEndSXDI" },
175270x0127: { n:"BrtBeginSXDIs" },
175280x0128: { n:"BrtEndSXDIs" },
175290x0129: { n:"BrtBeginSXLI" },
175300x012A: { n:"BrtEndSXLI" },
175310x012B: { n:"BrtBeginSXLIRws" },
175320x012C: { n:"BrtEndSXLIRws" },
175330x012D: { n:"BrtBeginSXLICols" },
175340x012E: { n:"BrtEndSXLICols" },
175350x012F: { n:"BrtBeginSXFormat" },
175360x0130: { n:"BrtEndSXFormat" },
175370x0131: { n:"BrtBeginSXFormats" },
175380x0132: { n:"BrtEndSxFormats" },
175390x0133: { n:"BrtBeginSxSelect" },
175400x0134: { n:"BrtEndSxSelect" },
175410x0135: { n:"BrtBeginISXVDRws" },
175420x0136: { n:"BrtEndISXVDRws" },
175430x0137: { n:"BrtBeginISXVDCols" },
175440x0138: { n:"BrtEndISXVDCols" },
175450x0139: { n:"BrtEndSXLocation" },
175460x013A: { n:"BrtBeginSXLocation" },
175470x013B: { n:"BrtEndSXView" },
175480x013C: { n:"BrtBeginSXTHs" },
175490x013D: { n:"BrtEndSXTHs" },
175500x013E: { n:"BrtBeginSXTH" },
175510x013F: { n:"BrtEndSXTH" },
175520x0140: { n:"BrtBeginISXTHRws" },
175530x0141: { n:"BrtEndISXTHRws" },
175540x0142: { n:"BrtBeginISXTHCols" },
175550x0143: { n:"BrtEndISXTHCols" },
175560x0144: { n:"BrtBeginSXTDMPS" },
175570x0145: { n:"BrtEndSXTDMPs" },
175580x0146: { n:"BrtBeginSXTDMP" },
175590x0147: { n:"BrtEndSXTDMP" },
175600x0148: { n:"BrtBeginSXTHItems" },
175610x0149: { n:"BrtEndSXTHItems" },
175620x014A: { n:"BrtBeginSXTHItem" },
175630x014B: { n:"BrtEndSXTHItem" },
175640x014C: { n:"BrtBeginMetadata" },
175650x014D: { n:"BrtEndMetadata" },
175660x014E: { n:"BrtBeginEsmdtinfo" },
175670x014F: { n:"BrtMdtinfo" },
175680x0150: { n:"BrtEndEsmdtinfo" },
175690x0151: { n:"BrtBeginEsmdb" },
175700x0152: { n:"BrtEndEsmdb" },
175710x0153: { n:"BrtBeginEsfmd" },
175720x0154: { n:"BrtEndEsfmd" },
175730x0155: { n:"BrtBeginSingleCells" },
175740x0156: { n:"BrtEndSingleCells" },
175750x0157: { n:"BrtBeginList" },
175760x0158: { n:"BrtEndList" },
175770x0159: { n:"BrtBeginListCols" },
175780x015A: { n:"BrtEndListCols" },
175790x015B: { n:"BrtBeginListCol" },
175800x015C: { n:"BrtEndListCol" },
175810x015D: { n:"BrtBeginListXmlCPr" },
175820x015E: { n:"BrtEndListXmlCPr" },
175830x015F: { n:"BrtListCCFmla" },
175840x0160: { n:"BrtListTrFmla" },
175850x0161: { n:"BrtBeginExternals" },
175860x0162: { n:"BrtEndExternals" },
175870x0163: { n:"BrtSupBookSrc", f:parse_RelID},
175880x0165: { n:"BrtSupSelf" },
175890x0166: { n:"BrtSupSame" },
175900x0167: { n:"BrtSupTabs" },
175910x0168: { n:"BrtBeginSupBook" },
175920x0169: { n:"BrtPlaceholderName" },
175930x016A: { n:"BrtExternSheet", f:parse_ExternSheet },
175940x016B: { n:"BrtExternTableStart" },
175950x016C: { n:"BrtExternTableEnd" },
175960x016E: { n:"BrtExternRowHdr" },
175970x016F: { n:"BrtExternCellBlank" },
175980x0170: { n:"BrtExternCellReal" },
175990x0171: { n:"BrtExternCellBool" },
176000x0172: { n:"BrtExternCellError" },
176010x0173: { n:"BrtExternCellString" },
176020x0174: { n:"BrtBeginEsmdx" },
176030x0175: { n:"BrtEndEsmdx" },
176040x0176: { n:"BrtBeginMdxSet" },
176050x0177: { n:"BrtEndMdxSet" },
176060x0178: { n:"BrtBeginMdxMbrProp" },
176070x0179: { n:"BrtEndMdxMbrProp" },
176080x017A: { n:"BrtBeginMdxKPI" },
176090x017B: { n:"BrtEndMdxKPI" },
176100x017C: { n:"BrtBeginEsstr" },
176110x017D: { n:"BrtEndEsstr" },
176120x017E: { n:"BrtBeginPRFItem" },
176130x017F: { n:"BrtEndPRFItem" },
176140x0180: { n:"BrtBeginPivotCacheIDs" },
176150x0181: { n:"BrtEndPivotCacheIDs" },
176160x0182: { n:"BrtBeginPivotCacheID" },
176170x0183: { n:"BrtEndPivotCacheID" },
176180x0184: { n:"BrtBeginISXVIs" },
176190x0185: { n:"BrtEndISXVIs" },
176200x0186: { n:"BrtBeginColInfos" },
176210x0187: { n:"BrtEndColInfos" },
176220x0188: { n:"BrtBeginRwBrk" },
176230x0189: { n:"BrtEndRwBrk" },
176240x018A: { n:"BrtBeginColBrk" },
176250x018B: { n:"BrtEndColBrk" },
176260x018C: { n:"BrtBrk" },
176270x018D: { n:"BrtUserBookView" },
176280x018E: { n:"BrtInfo" },
176290x018F: { n:"BrtCUsr" },
176300x0190: { n:"BrtUsr" },
176310x0191: { n:"BrtBeginUsers" },
176320x0193: { n:"BrtEOF" },
176330x0194: { n:"BrtUCR" },
176340x0195: { n:"BrtRRInsDel" },
176350x0196: { n:"BrtRREndInsDel" },
176360x0197: { n:"BrtRRMove" },
176370x0198: { n:"BrtRREndMove" },
176380x0199: { n:"BrtRRChgCell" },
176390x019A: { n:"BrtRREndChgCell" },
176400x019B: { n:"BrtRRHeader" },
176410x019C: { n:"BrtRRUserView" },
176420x019D: { n:"BrtRRRenSheet" },
176430x019E: { n:"BrtRRInsertSh" },
176440x019F: { n:"BrtRRDefName" },
176450x01A0: { n:"BrtRRNote" },
176460x01A1: { n:"BrtRRConflict" },
176470x01A2: { n:"BrtRRTQSIF" },
176480x01A3: { n:"BrtRRFormat" },
176490x01A4: { n:"BrtRREndFormat" },
176500x01A5: { n:"BrtRRAutoFmt" },
176510x01A6: { n:"BrtBeginUserShViews" },
176520x01A7: { n:"BrtBeginUserShView" },
176530x01A8: { n:"BrtEndUserShView" },
176540x01A9: { n:"BrtEndUserShViews" },
176550x01AA: { n:"BrtArrFmla", f:parse_BrtArrFmla },
176560x01AB: { n:"BrtShrFmla", f:parse_BrtShrFmla },
176570x01AC: { n:"BrtTable" },
176580x01AD: { n:"BrtBeginExtConnections" },
176590x01AE: { n:"BrtEndExtConnections" },
176600x01AF: { n:"BrtBeginPCDCalcMems" },
176610x01B0: { n:"BrtEndPCDCalcMems" },
176620x01B1: { n:"BrtBeginPCDCalcMem" },
176630x01B2: { n:"BrtEndPCDCalcMem" },
176640x01B3: { n:"BrtBeginPCDHGLevels" },
176650x01B4: { n:"BrtEndPCDHGLevels" },
176660x01B5: { n:"BrtBeginPCDHGLevel" },
176670x01B6: { n:"BrtEndPCDHGLevel" },
176680x01B7: { n:"BrtBeginPCDHGLGroups" },
176690x01B8: { n:"BrtEndPCDHGLGroups" },
176700x01B9: { n:"BrtBeginPCDHGLGroup" },
176710x01BA: { n:"BrtEndPCDHGLGroup" },
176720x01BB: { n:"BrtBeginPCDHGLGMembers" },
176730x01BC: { n:"BrtEndPCDHGLGMembers" },
176740x01BD: { n:"BrtBeginPCDHGLGMember" },
176750x01BE: { n:"BrtEndPCDHGLGMember" },
176760x01BF: { n:"BrtBeginQSI" },
176770x01C0: { n:"BrtEndQSI" },
176780x01C1: { n:"BrtBeginQSIR" },
176790x01C2: { n:"BrtEndQSIR" },
176800x01C3: { n:"BrtBeginDeletedNames" },
176810x01C4: { n:"BrtEndDeletedNames" },
176820x01C5: { n:"BrtBeginDeletedName" },
176830x01C6: { n:"BrtEndDeletedName" },
176840x01C7: { n:"BrtBeginQSIFs" },
176850x01C8: { n:"BrtEndQSIFs" },
176860x01C9: { n:"BrtBeginQSIF" },
176870x01CA: { n:"BrtEndQSIF" },
176880x01CB: { n:"BrtBeginAutoSortScope" },
176890x01CC: { n:"BrtEndAutoSortScope" },
176900x01CD: { n:"BrtBeginConditionalFormatting" },
176910x01CE: { n:"BrtEndConditionalFormatting" },
176920x01CF: { n:"BrtBeginCFRule" },
176930x01D0: { n:"BrtEndCFRule" },
176940x01D1: { n:"BrtBeginIconSet" },
176950x01D2: { n:"BrtEndIconSet" },
176960x01D3: { n:"BrtBeginDatabar" },
176970x01D4: { n:"BrtEndDatabar" },
176980x01D5: { n:"BrtBeginColorScale" },
176990x01D6: { n:"BrtEndColorScale" },
177000x01D7: { n:"BrtCFVO" },
177010x01D8: { n:"BrtExternValueMeta" },
177020x01D9: { n:"BrtBeginColorPalette" },
177030x01DA: { n:"BrtEndColorPalette" },
177040x01DB: { n:"BrtIndexedColor" },
177050x01DC: { n:"BrtMargins", f:parse_BrtMargins },
177060x01DD: { n:"BrtPrintOptions" },
177070x01DE: { n:"BrtPageSetup" },
177080x01DF: { n:"BrtBeginHeaderFooter" },
177090x01E0: { n:"BrtEndHeaderFooter" },
177100x01E1: { n:"BrtBeginSXCrtFormat" },
177110x01E2: { n:"BrtEndSXCrtFormat" },
177120x01E3: { n:"BrtBeginSXCrtFormats" },
177130x01E4: { n:"BrtEndSXCrtFormats" },
177140x01E5: { n:"BrtWsFmtInfo", f:parse_BrtWsFmtInfo },
177150x01E6: { n:"BrtBeginMgs" },
177160x01E7: { n:"BrtEndMGs" },
177170x01E8: { n:"BrtBeginMGMaps" },
177180x01E9: { n:"BrtEndMGMaps" },
177190x01EA: { n:"BrtBeginMG" },
177200x01EB: { n:"BrtEndMG" },
177210x01EC: { n:"BrtBeginMap" },
177220x01ED: { n:"BrtEndMap" },
177230x01EE: { n:"BrtHLink", f:parse_BrtHLink },
177240x01EF: { n:"BrtBeginDCon" },
177250x01F0: { n:"BrtEndDCon" },
177260x01F1: { n:"BrtBeginDRefs" },
177270x01F2: { n:"BrtEndDRefs" },
177280x01F3: { n:"BrtDRef" },
177290x01F4: { n:"BrtBeginScenMan" },
177300x01F5: { n:"BrtEndScenMan" },
177310x01F6: { n:"BrtBeginSct" },
177320x01F7: { n:"BrtEndSct" },
177330x01F8: { n:"BrtSlc" },
177340x01F9: { n:"BrtBeginDXFs" },
177350x01FA: { n:"BrtEndDXFs" },
177360x01FB: { n:"BrtDXF" },
177370x01FC: { n:"BrtBeginTableStyles" },
177380x01FD: { n:"BrtEndTableStyles" },
177390x01FE: { n:"BrtBeginTableStyle" },
177400x01FF: { n:"BrtEndTableStyle" },
177410x0200: { n:"BrtTableStyleElement" },
177420x0201: { n:"BrtTableStyleClient" },
177430x0202: { n:"BrtBeginVolDeps" },
177440x0203: { n:"BrtEndVolDeps" },
177450x0204: { n:"BrtBeginVolType" },
177460x0205: { n:"BrtEndVolType" },
177470x0206: { n:"BrtBeginVolMain" },
177480x0207: { n:"BrtEndVolMain" },
177490x0208: { n:"BrtBeginVolTopic" },
177500x0209: { n:"BrtEndVolTopic" },
177510x020A: { n:"BrtVolSubtopic" },
177520x020B: { n:"BrtVolRef" },
177530x020C: { n:"BrtVolNum" },
177540x020D: { n:"BrtVolErr" },
177550x020E: { n:"BrtVolStr" },
177560x020F: { n:"BrtVolBool" },
177570x0210: { n:"BrtBeginCalcChain$" },
177580x0211: { n:"BrtEndCalcChain$" },
177590x0212: { n:"BrtBeginSortState" },
177600x0213: { n:"BrtEndSortState" },
177610x0214: { n:"BrtBeginSortCond" },
177620x0215: { n:"BrtEndSortCond" },
177630x0216: { n:"BrtBookProtection" },
177640x0217: { n:"BrtSheetProtection" },
177650x0218: { n:"BrtRangeProtection" },
177660x0219: { n:"BrtPhoneticInfo" },
177670x021A: { n:"BrtBeginECTxtWiz" },
177680x021B: { n:"BrtEndECTxtWiz" },
177690x021C: { n:"BrtBeginECTWFldInfoLst" },
177700x021D: { n:"BrtEndECTWFldInfoLst" },
177710x021E: { n:"BrtBeginECTwFldInfo" },
177720x0224: { n:"BrtFileSharing" },
177730x0225: { n:"BrtOleSize" },
177740x0226: { n:"BrtDrawing", f:parse_RelID },
177750x0227: { n:"BrtLegacyDrawing" },
177760x0228: { n:"BrtLegacyDrawingHF" },
177770x0229: { n:"BrtWebOpt" },
177780x022A: { n:"BrtBeginWebPubItems" },
177790x022B: { n:"BrtEndWebPubItems" },
177800x022C: { n:"BrtBeginWebPubItem" },
177810x022D: { n:"BrtEndWebPubItem" },
177820x022E: { n:"BrtBeginSXCondFmt" },
177830x022F: { n:"BrtEndSXCondFmt" },
177840x0230: { n:"BrtBeginSXCondFmts" },
177850x0231: { n:"BrtEndSXCondFmts" },
177860x0232: { n:"BrtBkHim" },
177870x0234: { n:"BrtColor" },
177880x0235: { n:"BrtBeginIndexedColors" },
177890x0236: { n:"BrtEndIndexedColors" },
177900x0239: { n:"BrtBeginMRUColors" },
177910x023A: { n:"BrtEndMRUColors" },
177920x023C: { n:"BrtMRUColor" },
177930x023D: { n:"BrtBeginDVals" },
177940x023E: { n:"BrtEndDVals" },
177950x0241: { n:"BrtSupNameStart" },
177960x0242: { n:"BrtSupNameValueStart" },
177970x0243: { n:"BrtSupNameValueEnd" },
177980x0244: { n:"BrtSupNameNum" },
177990x0245: { n:"BrtSupNameErr" },
178000x0246: { n:"BrtSupNameSt" },
178010x0247: { n:"BrtSupNameNil" },
178020x0248: { n:"BrtSupNameBool" },
178030x0249: { n:"BrtSupNameFmla" },
178040x024A: { n:"BrtSupNameBits" },
178050x024B: { n:"BrtSupNameEnd" },
178060x024C: { n:"BrtEndSupBook" },
178070x024D: { n:"BrtCellSmartTagProperty" },
178080x024E: { n:"BrtBeginCellSmartTag" },
178090x024F: { n:"BrtEndCellSmartTag" },
178100x0250: { n:"BrtBeginCellSmartTags" },
178110x0251: { n:"BrtEndCellSmartTags" },
178120x0252: { n:"BrtBeginSmartTags" },
178130x0253: { n:"BrtEndSmartTags" },
178140x0254: { n:"BrtSmartTagType" },
178150x0255: { n:"BrtBeginSmartTagTypes" },
178160x0256: { n:"BrtEndSmartTagTypes" },
178170x0257: { n:"BrtBeginSXFilters" },
178180x0258: { n:"BrtEndSXFilters" },
178190x0259: { n:"BrtBeginSXFILTER" },
178200x025A: { n:"BrtEndSXFilter" },
178210x025B: { n:"BrtBeginFills" },
178220x025C: { n:"BrtEndFills" },
178230x025D: { n:"BrtBeginCellWatches" },
178240x025E: { n:"BrtEndCellWatches" },
178250x025F: { n:"BrtCellWatch" },
178260x0260: { n:"BrtBeginCRErrs" },
178270x0261: { n:"BrtEndCRErrs" },
178280x0262: { n:"BrtCrashRecErr" },
178290x0263: { n:"BrtBeginFonts" },
178300x0264: { n:"BrtEndFonts" },
178310x0265: { n:"BrtBeginBorders" },
178320x0266: { n:"BrtEndBorders" },
178330x0267: { n:"BrtBeginFmts" },
178340x0268: { n:"BrtEndFmts" },
178350x0269: { n:"BrtBeginCellXFs" },
178360x026A: { n:"BrtEndCellXFs" },
178370x026B: { n:"BrtBeginStyles" },
178380x026C: { n:"BrtEndStyles" },
178390x0271: { n:"BrtBigName" },
178400x0272: { n:"BrtBeginCellStyleXFs" },
178410x0273: { n:"BrtEndCellStyleXFs" },
178420x0274: { n:"BrtBeginComments" },
178430x0275: { n:"BrtEndComments" },
178440x0276: { n:"BrtBeginCommentAuthors" },
178450x0277: { n:"BrtEndCommentAuthors" },
178460x0278: { n:"BrtCommentAuthor", f:parse_BrtCommentAuthor },
178470x0279: { n:"BrtBeginCommentList" },
178480x027A: { n:"BrtEndCommentList" },
178490x027B: { n:"BrtBeginComment", f:parse_BrtBeginComment},
178500x027C: { n:"BrtEndComment" },
178510x027D: { n:"BrtCommentText", f:parse_BrtCommentText },
178520x027E: { n:"BrtBeginOleObjects" },
178530x027F: { n:"BrtOleObject" },
178540x0280: { n:"BrtEndOleObjects" },
178550x0281: { n:"BrtBeginSxrules" },
178560x0282: { n:"BrtEndSxRules" },
178570x0283: { n:"BrtBeginActiveXControls" },
178580x0284: { n:"BrtActiveX" },
178590x0285: { n:"BrtEndActiveXControls" },
178600x0286: { n:"BrtBeginPCDSDTCEMembersSortBy" },
178610x0288: { n:"BrtBeginCellIgnoreECs" },
178620x0289: { n:"BrtCellIgnoreEC" },
178630x028A: { n:"BrtEndCellIgnoreECs" },
178640x028B: { n:"BrtCsProp", f:parse_BrtCsProp },
178650x028C: { n:"BrtCsPageSetup" },
178660x028D: { n:"BrtBeginUserCsViews" },
178670x028E: { n:"BrtEndUserCsViews" },
178680x028F: { n:"BrtBeginUserCsView" },
178690x0290: { n:"BrtEndUserCsView" },
178700x0291: { n:"BrtBeginPcdSFCIEntries" },
178710x0292: { n:"BrtEndPCDSFCIEntries" },
178720x0293: { n:"BrtPCDSFCIEntry" },
178730x0294: { n:"BrtBeginListParts" },
178740x0295: { n:"BrtListPart" },
178750x0296: { n:"BrtEndListParts" },
178760x0297: { n:"BrtSheetCalcProp" },
178770x0298: { n:"BrtBeginFnGroup" },
178780x0299: { n:"BrtFnGroup" },
178790x029A: { n:"BrtEndFnGroup" },
178800x029B: { n:"BrtSupAddin" },
178810x029C: { n:"BrtSXTDMPOrder" },
178820x029D: { n:"BrtCsProtection" },
178830x029F: { n:"BrtBeginWsSortMap" },
178840x02A0: { n:"BrtEndWsSortMap" },
178850x02A1: { n:"BrtBeginRRSort" },
178860x02A2: { n:"BrtEndRRSort" },
178870x02A3: { n:"BrtRRSortItem" },
178880x02A4: { n:"BrtFileSharingIso" },
178890x02A5: { n:"BrtBookProtectionIso" },
178900x02A6: { n:"BrtSheetProtectionIso" },
178910x02A7: { n:"BrtCsProtectionIso" },
178920x02A8: { n:"BrtRangeProtectionIso" },
178930x0400: { n:"BrtRwDescent" },
178940x0401: { n:"BrtKnownFonts" },
178950x0402: { n:"BrtBeginSXTupleSet" },
178960x0403: { n:"BrtEndSXTupleSet" },
178970x0404: { n:"BrtBeginSXTupleSetHeader" },
178980x0405: { n:"BrtEndSXTupleSetHeader" },
178990x0406: { n:"BrtSXTupleSetHeaderItem" },
179000x0407: { n:"BrtBeginSXTupleSetData" },
179010x0408: { n:"BrtEndSXTupleSetData" },
179020x0409: { n:"BrtBeginSXTupleSetRow" },
179030x040A: { n:"BrtEndSXTupleSetRow" },
179040x040B: { n:"BrtSXTupleSetRowItem" },
179050x040C: { n:"BrtNameExt" },
179060x040D: { n:"BrtPCDH14" },
179070x040E: { n:"BrtBeginPCDCalcMem14" },
179080x040F: { n:"BrtEndPCDCalcMem14" },
179090x0410: { n:"BrtSXTH14" },
179100x0411: { n:"BrtBeginSparklineGroup" },
179110x0412: { n:"BrtEndSparklineGroup" },
179120x0413: { n:"BrtSparkline" },
179130x0414: { n:"BrtSXDI14" },
179140x0415: { n:"BrtWsFmtInfoEx14" },
179150x0416: { n:"BrtBeginConditionalFormatting14" },
179160x0417: { n:"BrtEndConditionalFormatting14" },
179170x0418: { n:"BrtBeginCFRule14" },
179180x0419: { n:"BrtEndCFRule14" },
179190x041A: { n:"BrtCFVO14" },
179200x041B: { n:"BrtBeginDatabar14" },
179210x041C: { n:"BrtBeginIconSet14" },
179220x041D: { n:"BrtDVal14" },
179230x041E: { n:"BrtBeginDVals14" },
179240x041F: { n:"BrtColor14" },
179250x0420: { n:"BrtBeginSparklines" },
179260x0421: { n:"BrtEndSparklines" },
179270x0422: { n:"BrtBeginSparklineGroups" },
179280x0423: { n:"BrtEndSparklineGroups" },
179290x0425: { n:"BrtSXVD14" },
179300x0426: { n:"BrtBeginSXView14" },
179310x0427: { n:"BrtEndSXView14" },
179320x0428: { n:"BrtBeginSXView16" },
179330x0429: { n:"BrtEndSXView16" },
179340x042A: { n:"BrtBeginPCD14" },
179350x042B: { n:"BrtEndPCD14" },
179360x042C: { n:"BrtBeginExtConn14" },
179370x042D: { n:"BrtEndExtConn14" },
179380x042E: { n:"BrtBeginSlicerCacheIDs" },
179390x042F: { n:"BrtEndSlicerCacheIDs" },
179400x0430: { n:"BrtBeginSlicerCacheID" },
179410x0431: { n:"BrtEndSlicerCacheID" },
179420x0433: { n:"BrtBeginSlicerCache" },
179430x0434: { n:"BrtEndSlicerCache" },
179440x0435: { n:"BrtBeginSlicerCacheDef" },
179450x0436: { n:"BrtEndSlicerCacheDef" },
179460x0437: { n:"BrtBeginSlicersEx" },
179470x0438: { n:"BrtEndSlicersEx" },
179480x0439: { n:"BrtBeginSlicerEx" },
179490x043A: { n:"BrtEndSlicerEx" },
179500x043B: { n:"BrtBeginSlicer" },
179510x043C: { n:"BrtEndSlicer" },
179520x043D: { n:"BrtSlicerCachePivotTables" },
179530x043E: { n:"BrtBeginSlicerCacheOlapImpl" },
179540x043F: { n:"BrtEndSlicerCacheOlapImpl" },
179550x0440: { n:"BrtBeginSlicerCacheLevelsData" },
179560x0441: { n:"BrtEndSlicerCacheLevelsData" },
179570x0442: { n:"BrtBeginSlicerCacheLevelData" },
179580x0443: { n:"BrtEndSlicerCacheLevelData" },
179590x0444: { n:"BrtBeginSlicerCacheSiRanges" },
179600x0445: { n:"BrtEndSlicerCacheSiRanges" },
179610x0446: { n:"BrtBeginSlicerCacheSiRange" },
179620x0447: { n:"BrtEndSlicerCacheSiRange" },
179630x0448: { n:"BrtSlicerCacheOlapItem" },
179640x0449: { n:"BrtBeginSlicerCacheSelections" },
179650x044A: { n:"BrtSlicerCacheSelection" },
179660x044B: { n:"BrtEndSlicerCacheSelections" },
179670x044C: { n:"BrtBeginSlicerCacheNative" },
179680x044D: { n:"BrtEndSlicerCacheNative" },
179690x044E: { n:"BrtSlicerCacheNativeItem" },
179700x044F: { n:"BrtRangeProtection14" },
179710x0450: { n:"BrtRangeProtectionIso14" },
179720x0451: { n:"BrtCellIgnoreEC14" },
179730x0457: { n:"BrtList14" },
179740x0458: { n:"BrtCFIcon" },
179750x0459: { n:"BrtBeginSlicerCachesPivotCacheIDs" },
179760x045A: { n:"BrtEndSlicerCachesPivotCacheIDs" },
179770x045B: { n:"BrtBeginSlicers" },
179780x045C: { n:"BrtEndSlicers" },
179790x045D: { n:"BrtWbProp14" },
179800x045E: { n:"BrtBeginSXEdit" },
179810x045F: { n:"BrtEndSXEdit" },
179820x0460: { n:"BrtBeginSXEdits" },
179830x0461: { n:"BrtEndSXEdits" },
179840x0462: { n:"BrtBeginSXChange" },
179850x0463: { n:"BrtEndSXChange" },
179860x0464: { n:"BrtBeginSXChanges" },
179870x0465: { n:"BrtEndSXChanges" },
179880x0466: { n:"BrtSXTupleItems" },
179890x0468: { n:"BrtBeginSlicerStyle" },
179900x0469: { n:"BrtEndSlicerStyle" },
179910x046A: { n:"BrtSlicerStyleElement" },
179920x046B: { n:"BrtBeginStyleSheetExt14" },
179930x046C: { n:"BrtEndStyleSheetExt14" },
179940x046D: { n:"BrtBeginSlicerCachesPivotCacheID" },
179950x046E: { n:"BrtEndSlicerCachesPivotCacheID" },
179960x046F: { n:"BrtBeginConditionalFormattings" },
179970x0470: { n:"BrtEndConditionalFormattings" },
179980x0471: { n:"BrtBeginPCDCalcMemExt" },
179990x0472: { n:"BrtEndPCDCalcMemExt" },
180000x0473: { n:"BrtBeginPCDCalcMemsExt" },
180010x0474: { n:"BrtEndPCDCalcMemsExt" },
180020x0475: { n:"BrtPCDField14" },
180030x0476: { n:"BrtBeginSlicerStyles" },
180040x0477: { n:"BrtEndSlicerStyles" },
180050x0478: { n:"BrtBeginSlicerStyleElements" },
180060x0479: { n:"BrtEndSlicerStyleElements" },
180070x047A: { n:"BrtCFRuleExt" },
180080x047B: { n:"BrtBeginSXCondFmt14" },
180090x047C: { n:"BrtEndSXCondFmt14" },
180100x047D: { n:"BrtBeginSXCondFmts14" },
180110x047E: { n:"BrtEndSXCondFmts14" },
180120x0480: { n:"BrtBeginSortCond14" },
180130x0481: { n:"BrtEndSortCond14" },
180140x0482: { n:"BrtEndDVals14" },
180150x0483: { n:"BrtEndIconSet14" },
180160x0484: { n:"BrtEndDatabar14" },
180170x0485: { n:"BrtBeginColorScale14" },
180180x0486: { n:"BrtEndColorScale14" },
180190x0487: { n:"BrtBeginSxrules14" },
180200x0488: { n:"BrtEndSxrules14" },
180210x0489: { n:"BrtBeginPRule14" },
180220x048A: { n:"BrtEndPRule14" },
180230x048B: { n:"BrtBeginPRFilters14" },
180240x048C: { n:"BrtEndPRFilters14" },
180250x048D: { n:"BrtBeginPRFilter14" },
180260x048E: { n:"BrtEndPRFilter14" },
180270x048F: { n:"BrtBeginPRFItem14" },
180280x0490: { n:"BrtEndPRFItem14" },
180290x0491: { n:"BrtBeginCellIgnoreECs14" },
180300x0492: { n:"BrtEndCellIgnoreECs14" },
180310x0493: { n:"BrtDxf14" },
180320x0494: { n:"BrtBeginDxF14s" },
180330x0495: { n:"BrtEndDxf14s" },
180340x0499: { n:"BrtFilter14" },
180350x049A: { n:"BrtBeginCustomFilters14" },
180360x049C: { n:"BrtCustomFilter14" },
180370x049D: { n:"BrtIconFilter14" },
180380x049E: { n:"BrtPivotCacheConnectionName" },
180390x0800: { n:"BrtBeginDecoupledPivotCacheIDs" },
180400x0801: { n:"BrtEndDecoupledPivotCacheIDs" },
180410x0802: { n:"BrtDecoupledPivotCacheID" },
180420x0803: { n:"BrtBeginPivotTableRefs" },
180430x0804: { n:"BrtEndPivotTableRefs" },
180440x0805: { n:"BrtPivotTableRef" },
180450x0806: { n:"BrtSlicerCacheBookPivotTables" },
180460x0807: { n:"BrtBeginSxvcells" },
180470x0808: { n:"BrtEndSxvcells" },
180480x0809: { n:"BrtBeginSxRow" },
180490x080A: { n:"BrtEndSxRow" },
180500x080C: { n:"BrtPcdCalcMem15" },
180510x0813: { n:"BrtQsi15" },
180520x0814: { n:"BrtBeginWebExtensions" },
180530x0815: { n:"BrtEndWebExtensions" },
180540x0816: { n:"BrtWebExtension" },
180550x0817: { n:"BrtAbsPath15" },
180560x0818: { n:"BrtBeginPivotTableUISettings" },
180570x0819: { n:"BrtEndPivotTableUISettings" },
180580x081B: { n:"BrtTableSlicerCacheIDs" },
180590x081C: { n:"BrtTableSlicerCacheID" },
180600x081D: { n:"BrtBeginTableSlicerCache" },
180610x081E: { n:"BrtEndTableSlicerCache" },
180620x081F: { n:"BrtSxFilter15" },
180630x0820: { n:"BrtBeginTimelineCachePivotCacheIDs" },
180640x0821: { n:"BrtEndTimelineCachePivotCacheIDs" },
180650x0822: { n:"BrtTimelineCachePivotCacheID" },
180660x0823: { n:"BrtBeginTimelineCacheIDs" },
180670x0824: { n:"BrtEndTimelineCacheIDs" },
180680x0825: { n:"BrtBeginTimelineCacheID" },
180690x0826: { n:"BrtEndTimelineCacheID" },
180700x0827: { n:"BrtBeginTimelinesEx" },
180710x0828: { n:"BrtEndTimelinesEx" },
180720x0829: { n:"BrtBeginTimelineEx" },
180730x082A: { n:"BrtEndTimelineEx" },
180740x082B: { n:"BrtWorkBookPr15" },
180750x082C: { n:"BrtPCDH15" },
180760x082D: { n:"BrtBeginTimelineStyle" },
180770x082E: { n:"BrtEndTimelineStyle" },
180780x082F: { n:"BrtTimelineStyleElement" },
180790x0830: { n:"BrtBeginTimelineStylesheetExt15" },
180800x0831: { n:"BrtEndTimelineStylesheetExt15" },
180810x0832: { n:"BrtBeginTimelineStyles" },
180820x0833: { n:"BrtEndTimelineStyles" },
180830x0834: { n:"BrtBeginTimelineStyleElements" },
180840x0835: { n:"BrtEndTimelineStyleElements" },
180850x0836: { n:"BrtDxf15" },
180860x0837: { n:"BrtBeginDxfs15" },
180870x0838: { n:"brtEndDxfs15" },
180880x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
180890x083A: { n:"BrtBeginItemUniqueNames" },
180900x083B: { n:"BrtEndItemUniqueNames" },
180910x083C: { n:"BrtItemUniqueName" },
180920x083D: { n:"BrtBeginExtConn15" },
180930x083E: { n:"BrtEndExtConn15" },
180940x083F: { n:"BrtBeginOledbPr15" },
180950x0840: { n:"BrtEndOledbPr15" },
180960x0841: { n:"BrtBeginDataFeedPr15" },
180970x0842: { n:"BrtEndDataFeedPr15" },
180980x0843: { n:"BrtTextPr15" },
180990x0844: { n:"BrtRangePr15" },
181000x0845: { n:"BrtDbCommand15" },
181010x0846: { n:"BrtBeginDbTables15" },
181020x0847: { n:"BrtEndDbTables15" },
181030x0848: { n:"BrtDbTable15" },
181040x0849: { n:"BrtBeginDataModel" },
181050x084A: { n:"BrtEndDataModel" },
181060x084B: { n:"BrtBeginModelTables" },
181070x084C: { n:"BrtEndModelTables" },
181080x084D: { n:"BrtModelTable" },
181090x084E: { n:"BrtBeginModelRelationships" },
181100x084F: { n:"BrtEndModelRelationships" },
181110x0850: { n:"BrtModelRelationship" },
181120x0851: { n:"BrtBeginECTxtWiz15" },
181130x0852: { n:"BrtEndECTxtWiz15" },
181140x0853: { n:"BrtBeginECTWFldInfoLst15" },
181150x0854: { n:"BrtEndECTWFldInfoLst15" },
181160x0855: { n:"BrtBeginECTWFldInfo15" },
181170x0856: { n:"BrtFieldListActiveItem" },
181180x0857: { n:"BrtPivotCacheIdVersion" },
181190x0858: { n:"BrtSXDI15" },
181200x0859: { n:"BrtBeginModelTimeGroupings" },
181210x085A: { n:"BrtEndModelTimeGroupings" },
181220x085B: { n:"BrtBeginModelTimeGrouping" },
181230x085C: { n:"BrtEndModelTimeGrouping" },
181240x085D: { n:"BrtModelTimeGroupingCalcCol" },
181250x0C00: { n:"BrtUid" },
181260x0C01: { n:"BrtRevisionPtr" },
181270x13e7: { n:"BrtBeginCalcFeatures" },
181280x13e8: { n:"BrtEndCalcFeatures" },
181290x13e9: { n:"BrtCalcFeature" },
181300xFFFF: { n:"" }
18131};
18132
18133var XLSBRE = evert_key(XLSBRecordEnum, 'n');
18134
18135/* [MS-XLS] 2.3 Record Enumeration */
18136var XLSRecordEnum = {
181370x0003: { n:"BIFF2NUM", f:parse_BIFF2NUM },
181380x0004: { n:"BIFF2STR", f:parse_BIFF2STR },
181390x0006: { n:"Formula", f:parse_Formula },
181400x0009: { n:'BOF', f:parse_BOF },
181410x000a: { n:'EOF', f:parsenoop2 },
181420x000c: { n:"CalcCount", f:parseuint16 },
181430x000d: { n:"CalcMode", f:parseuint16 },
181440x000e: { n:"CalcPrecision", f:parsebool },
181450x000f: { n:"CalcRefMode", f:parsebool },
181460x0010: { n:"CalcDelta", f:parse_Xnum },
181470x0011: { n:"CalcIter", f:parsebool },
181480x0012: { n:"Protect", f:parsebool },
181490x0013: { n:"Password", f:parseuint16 },
181500x0014: { n:"Header", f:parse_XLHeaderFooter },
181510x0015: { n:"Footer", f:parse_XLHeaderFooter },
181520x0017: { n:"ExternSheet", f:parse_ExternSheet },
181530x0018: { n:"Lbl", f:parse_Lbl },
181540x0019: { n:"WinProtect", f:parsebool },
181550x001a: { n:"VerticalPageBreaks" },
181560x001b: { n:"HorizontalPageBreaks" },
181570x001c: { n:"Note", f:parse_Note },
181580x001d: { n:"Selection" },
181590x0022: { n:"Date1904", f:parsebool },
181600x0023: { n:"ExternName", f:parse_ExternName },
181610x0026: { n:"LeftMargin", f:parse_Xnum },
181620x0027: { n:"RightMargin", f:parse_Xnum },
181630x0028: { n:"TopMargin", f:parse_Xnum },
181640x0029: { n:"BottomMargin", f:parse_Xnum },
181650x002a: { n:"PrintRowCol", f:parsebool },
181660x002b: { n:"PrintGrid", f:parsebool },
181670x002f: { n:"FilePass", f:parse_FilePass },
181680x0031: { n:"Font", f:parse_Font },
181690x0033: { n:"PrintSize", f:parseuint16 },
181700x003c: { n:"Continue" },
181710x003d: { n:"Window1", f:parse_Window1 },
181720x0040: { n:"Backup", f:parsebool },
181730x0041: { n:"Pane" },
181740x0042: { n:'CodePage', f:parseuint16 },
181750x004d: { n:"Pls" },
181760x0050: { n:"DCon" },
181770x0051: { n:"DConRef" },
181780x0052: { n:"DConName" },
181790x0055: { n:"DefColWidth", f:parseuint16 },
181800x0059: { n:"XCT" },
181810x005a: { n:"CRN" },
181820x005b: { n:"FileSharing" },
181830x005c: { n:'WriteAccess', f:parse_WriteAccess },
181840x005d: { n:"Obj", f:parse_Obj },
181850x005e: { n:"Uncalced" },
181860x005f: { n:"CalcSaveRecalc", f:parsebool },
181870x0060: { n:"Template" },
181880x0061: { n:"Intl" },
181890x0063: { n:"ObjProtect", f:parsebool },
181900x007d: { n:"ColInfo", f:parse_ColInfo },
181910x0080: { n:"Guts", f:parse_Guts },
181920x0081: { n:"WsBool", f:parse_WsBool },
181930x0082: { n:"GridSet", f:parseuint16 },
181940x0083: { n:"HCenter", f:parsebool },
181950x0084: { n:"VCenter", f:parsebool },
181960x0085: { n:'BoundSheet8', f:parse_BoundSheet8 },
181970x0086: { n:"WriteProtect" },
181980x008c: { n:"Country", f:parse_Country },
181990x008d: { n:"HideObj", f:parseuint16 },
182000x0090: { n:"Sort" },
182010x0092: { n:"Palette", f:parse_Palette },
182020x0097: { n:"Sync" },
182030x0098: { n:"LPr" },
182040x0099: { n:"DxGCol" },
182050x009a: { n:"FnGroupName" },
182060x009b: { n:"FilterMode" },
182070x009c: { n:"BuiltInFnGroupCount", f:parseuint16 },
182080x009d: { n:"AutoFilterInfo" },
182090x009e: { n:"AutoFilter" },
182100x00a0: { n:"Scl", f:parse_Scl },
182110x00a1: { n:"Setup", f:parse_Setup },
182120x00ae: { n:"ScenMan" },
182130x00af: { n:"SCENARIO" },
182140x00b0: { n:"SxView" },
182150x00b1: { n:"Sxvd" },
182160x00b2: { n:"SXVI" },
182170x00b4: { n:"SxIvd" },
182180x00b5: { n:"SXLI" },
182190x00b6: { n:"SXPI" },
182200x00b8: { n:"DocRoute" },
182210x00b9: { n:"RecipName" },
182220x00bd: { n:"MulRk", f:parse_MulRk },
182230x00be: { n:"MulBlank", f:parse_MulBlank },
182240x00c1: { n:'Mms', f:parsenoop2 },
182250x00c5: { n:"SXDI" },
182260x00c6: { n:"SXDB" },
182270x00c7: { n:"SXFDB" },
182280x00c8: { n:"SXDBB" },
182290x00c9: { n:"SXNum" },
182300x00ca: { n:"SxBool", f:parsebool },
182310x00cb: { n:"SxErr" },
182320x00cc: { n:"SXInt" },
182330x00cd: { n:"SXString" },
182340x00ce: { n:"SXDtr" },
182350x00cf: { n:"SxNil" },
182360x00d0: { n:"SXTbl" },
182370x00d1: { n:"SXTBRGIITM" },
182380x00d2: { n:"SxTbpg" },
182390x00d3: { n:"ObProj" },
182400x00d5: { n:"SXStreamID" },
182410x00d7: { n:"DBCell" },
182420x00d8: { n:"SXRng" },
182430x00d9: { n:"SxIsxoper" },
182440x00da: { n:"BookBool", f:parseuint16 },
182450x00dc: { n:"DbOrParamQry" },
182460x00dd: { n:"ScenarioProtect", f:parsebool },
182470x00de: { n:"OleObjectSize" },
182480x00e0: { n:"XF", f:parse_XF },
182490x00e1: { n:'InterfaceHdr', f:parse_InterfaceHdr },
182500x00e2: { n:'InterfaceEnd', f:parsenoop2 },
182510x00e3: { n:"SXVS" },
182520x00e5: { n:"MergeCells", f:parse_MergeCells },
182530x00e9: { n:"BkHim" },
182540x00eb: { n:"MsoDrawingGroup" },
182550x00ec: { n:"MsoDrawing" },
182560x00ed: { n:"MsoDrawingSelection" },
182570x00ef: { n:"PhoneticInfo" },
182580x00f0: { n:"SxRule" },
182590x00f1: { n:"SXEx" },
182600x00f2: { n:"SxFilt" },
182610x00f4: { n:"SxDXF" },
182620x00f5: { n:"SxItm" },
182630x00f6: { n:"SxName" },
182640x00f7: { n:"SxSelect" },
182650x00f8: { n:"SXPair" },
182660x00f9: { n:"SxFmla" },
182670x00fb: { n:"SxFormat" },
182680x00fc: { n:"SST", f:parse_SST },
182690x00fd: { n:"LabelSst", f:parse_LabelSst },
182700x00ff: { n:"ExtSST", f:parse_ExtSST },
182710x0100: { n:"SXVDEx" },
182720x0103: { n:"SXFormula" },
182730x0122: { n:"SXDBEx" },
182740x0137: { n:"RRDInsDel" },
182750x0138: { n:"RRDHead" },
182760x013b: { n:"RRDChgCell" },
182770x013d: { n:"RRTabId", f:parseuint16a },
182780x013e: { n:"RRDRenSheet" },
182790x013f: { n:"RRSort" },
182800x0140: { n:"RRDMove" },
182810x014a: { n:"RRFormat" },
182820x014b: { n:"RRAutoFmt" },
182830x014d: { n:"RRInsertSh" },
182840x014e: { n:"RRDMoveBegin" },
182850x014f: { n:"RRDMoveEnd" },
182860x0150: { n:"RRDInsDelBegin" },
182870x0151: { n:"RRDInsDelEnd" },
182880x0152: { n:"RRDConflict" },
182890x0153: { n:"RRDDefName" },
182900x0154: { n:"RRDRstEtxp" },
182910x015f: { n:"LRng" },
182920x0160: { n:"UsesELFs", f:parsebool },
182930x0161: { n:"DSF", f:parsenoop2 },
182940x0191: { n:"CUsr" },
182950x0192: { n:"CbUsr" },
182960x0193: { n:"UsrInfo" },
182970x0194: { n:"UsrExcl" },
182980x0195: { n:"FileLock" },
182990x0196: { n:"RRDInfo" },
183000x0197: { n:"BCUsrs" },
183010x0198: { n:"UsrChk" },
183020x01a9: { n:"UserBView" },
183030x01aa: { n:"UserSViewBegin" },
183040x01ab: { n:"UserSViewEnd" },
183050x01ac: { n:"RRDUserView" },
183060x01ad: { n:"Qsi" },
183070x01ae: { n:"SupBook", f:parse_SupBook },
183080x01af: { n:"Prot4Rev", f:parsebool },
183090x01b0: { n:"CondFmt" },
183100x01b1: { n:"CF" },
183110x01b2: { n:"DVal" },
183120x01b5: { n:"DConBin" },
183130x01b6: { n:"TxO", f:parse_TxO },
183140x01b7: { n:"RefreshAll", f:parsebool },
183150x01b8: { n:"HLink", f:parse_HLink },
183160x01b9: { n:"Lel" },
183170x01ba: { n:"CodeName", f:parse_XLUnicodeString },
183180x01bb: { n:"SXFDBType" },
183190x01bc: { n:"Prot4RevPass", f:parseuint16 },
183200x01bd: { n:"ObNoMacros" },
183210x01be: { n:"Dv" },
183220x01c0: { n:"Excel9File", f:parsenoop2 },
183230x01c1: { n:"RecalcId", f:parse_RecalcId, r:2},
183240x01c2: { n:"EntExU2", f:parsenoop2 },
183250x0200: { n:"Dimensions", f:parse_Dimensions },
183260x0201: { n:"Blank", f:parse_Blank },
183270x0203: { n:"Number", f:parse_Number },
183280x0204: { n:"Label", f:parse_Label },
183290x0205: { n:"BoolErr", f:parse_BoolErr },
183300x0206: { n:"Formula", f:parse_Formula },
183310x0207: { n:"String", f:parse_String },
183320x0208: { n:'Row', f:parse_Row },
183330x020b: { n:"Index" },
183340x0221: { n:"Array", f:parse_Array },
183350x0225: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
183360x0236: { n:"Table" },
183370x023e: { n:"Window2", f:parse_Window2 },
183380x027e: { n:"RK", f:parse_RK },
183390x0293: { n:"Style" },
183400x0406: { n:"Formula", f:parse_Formula },
183410x0418: { n:"BigName" },
183420x041e: { n:"Format", f:parse_Format },
183430x043c: { n:"ContinueBigName" },
183440x04bc: { n:"ShrFmla", f:parse_ShrFmla },
183450x0800: { n:"HLinkTooltip", f:parse_HLinkTooltip },
183460x0801: { n:"WebPub" },
183470x0802: { n:"QsiSXTag" },
183480x0803: { n:"DBQueryExt" },
183490x0804: { n:"ExtString" },
183500x0805: { n:"TxtQry" },
183510x0806: { n:"Qsir" },
183520x0807: { n:"Qsif" },
183530x0808: { n:"RRDTQSIF" },
183540x0809: { n:'BOF', f:parse_BOF },
183550x080a: { n:"OleDbConn" },
183560x080b: { n:"WOpt" },
183570x080c: { n:"SXViewEx" },
183580x080d: { n:"SXTH" },
183590x080e: { n:"SXPIEx" },
183600x080f: { n:"SXVDTEx" },
183610x0810: { n:"SXViewEx9" },
183620x0812: { n:"ContinueFrt" },
183630x0813: { n:"RealTimeData" },
183640x0850: { n:"ChartFrtInfo" },
183650x0851: { n:"FrtWrapper" },
183660x0852: { n:"StartBlock" },
183670x0853: { n:"EndBlock" },
183680x0854: { n:"StartObject" },
183690x0855: { n:"EndObject" },
183700x0856: { n:"CatLab" },
183710x0857: { n:"YMult" },
183720x0858: { n:"SXViewLink" },
183730x0859: { n:"PivotChartBits" },
183740x085a: { n:"FrtFontList" },
183750x0862: { n:"SheetExt" },
183760x0863: { n:"BookExt", r:12},
183770x0864: { n:"SXAddl" },
183780x0865: { n:"CrErr" },
183790x0866: { n:"HFPicture" },
183800x0867: { n:'FeatHdr', f:parsenoop2 },
183810x0868: { n:"Feat" },
183820x086a: { n:"DataLabExt" },
183830x086b: { n:"DataLabExtContents" },
183840x086c: { n:"CellWatch" },
183850x0871: { n:"FeatHdr11" },
183860x0872: { n:"Feature11" },
183870x0874: { n:"DropDownObjIds" },
183880x0875: { n:"ContinueFrt11" },
183890x0876: { n:"DConn" },
183900x0877: { n:"List12" },
183910x0878: { n:"Feature12" },
183920x0879: { n:"CondFmt12" },
183930x087a: { n:"CF12" },
183940x087b: { n:"CFEx" },
183950x087c: { n:"XFCRC", f:parse_XFCRC, r:12 },
183960x087d: { n:"XFExt", f:parse_XFExt, r:12 },
183970x087e: { n:"AutoFilter12" },
183980x087f: { n:"ContinueFrt12" },
183990x0884: { n:"MDTInfo" },
184000x0885: { n:"MDXStr" },
184010x0886: { n:"MDXTuple" },
184020x0887: { n:"MDXSet" },
184030x0888: { n:"MDXProp" },
184040x0889: { n:"MDXKPI" },
184050x088a: { n:"MDB" },
184060x088b: { n:"PLV" },
184070x088c: { n:"Compat12", f:parsebool, r:12 },
184080x088d: { n:"DXF" },
184090x088e: { n:"TableStyles", r:12 },
184100x088f: { n:"TableStyle" },
184110x0890: { n:"TableStyleElement" },
184120x0892: { n:"StyleExt" },
184130x0893: { n:"NamePublish" },
184140x0894: { n:"NameCmt", f:parse_NameCmt, r:12 },
184150x0895: { n:"SortData" },
184160x0896: { n:"Theme", f:parse_Theme, r:12 },
184170x0897: { n:"GUIDTypeLib" },
184180x0898: { n:"FnGrp12" },
184190x0899: { n:"NameFnGrp12" },
184200x089a: { n:"MTRSettings", f:parse_MTRSettings, r:12 },
184210x089b: { n:"CompressPictures", f:parsenoop2 },
184220x089c: { n:"HeaderFooter" },
184230x089d: { n:"CrtLayout12" },
184240x089e: { n:"CrtMlFrt" },
184250x089f: { n:"CrtMlFrtContinue" },
184260x08a3: { n:"ForceFullCalculation", f:parse_ForceFullCalculation },
184270x08a4: { n:"ShapePropsStream" },
184280x08a5: { n:"TextPropsStream" },
184290x08a6: { n:"RichTextStream" },
184300x08a7: { n:"CrtLayout12A" },
184310x1001: { n:"Units" },
184320x1002: { n:"Chart" },
184330x1003: { n:"Series" },
184340x1006: { n:"DataFormat" },
184350x1007: { n:"LineFormat" },
184360x1009: { n:"MarkerFormat" },
184370x100a: { n:"AreaFormat" },
184380x100b: { n:"PieFormat" },
184390x100c: { n:"AttachedLabel" },
184400x100d: { n:"SeriesText" },
184410x1014: { n:"ChartFormat" },
184420x1015: { n:"Legend" },
184430x1016: { n:"SeriesList" },
184440x1017: { n:"Bar" },
184450x1018: { n:"Line" },
184460x1019: { n:"Pie" },
184470x101a: { n:"Area" },
184480x101b: { n:"Scatter" },
184490x101c: { n:"CrtLine" },
184500x101d: { n:"Axis" },
184510x101e: { n:"Tick" },
184520x101f: { n:"ValueRange" },
184530x1020: { n:"CatSerRange" },
184540x1021: { n:"AxisLine" },
184550x1022: { n:"CrtLink" },
184560x1024: { n:"DefaultText" },
184570x1025: { n:"Text" },
184580x1026: { n:"FontX", f:parseuint16 },
184590x1027: { n:"ObjectLink" },
184600x1032: { n:"Frame" },
184610x1033: { n:"Begin" },
184620x1034: { n:"End" },
184630x1035: { n:"PlotArea" },
184640x103a: { n:"Chart3d" },
184650x103c: { n:"PicF" },
184660x103d: { n:"DropBar" },
184670x103e: { n:"Radar" },
184680x103f: { n:"Surf" },
184690x1040: { n:"RadarArea" },
184700x1041: { n:"AxisParent" },
184710x1043: { n:"LegendException" },
184720x1044: { n:"ShtProps", f:parse_ShtProps },
184730x1045: { n:"SerToCrt" },
184740x1046: { n:"AxesUsed" },
184750x1048: { n:"SBaseRef" },
184760x104a: { n:"SerParent" },
184770x104b: { n:"SerAuxTrend" },
184780x104e: { n:"IFmtRecord" },
184790x104f: { n:"Pos" },
184800x1050: { n:"AlRuns" },
184810x1051: { n:"BRAI" },
184820x105b: { n:"SerAuxErrBar" },
184830x105c: { n:"ClrtClient", f:parse_ClrtClient },
184840x105d: { n:"SerFmt" },
184850x105f: { n:"Chart3DBarShape" },
184860x1060: { n:"Fbi" },
184870x1061: { n:"BopPop" },
184880x1062: { n:"AxcExt" },
184890x1063: { n:"Dat" },
184900x1064: { n:"PlotGrowth" },
184910x1065: { n:"SIIndex" },
184920x1066: { n:"GelFrame" },
184930x1067: { n:"BopPopCustom" },
184940x1068: { n:"Fbi2" },
18495
184960x0000: { n:"Dimensions", f:parse_Dimensions },
184970x0002: { n:"BIFF2INT", f:parse_BIFF2INT },
184980x0005: { n:"BoolErr", f:parse_BoolErr },
184990x0007: { n:"String", f:parse_BIFF2STRING },
185000x0008: { n:"BIFF2ROW" },
185010x000b: { n:"Index" },
185020x0016: { n:"ExternCount", f:parseuint16 },
185030x001e: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
185040x001f: { n:"BIFF2FMTCNT" }, /* 16-bit cnt of BIFF2FORMAT records */
185050x0020: { n:"BIFF2COLINFO" },
185060x0021: { n:"Array", f:parse_Array },
185070x0025: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
185080x0032: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
185090x0034: { n:"DDEObjName" },
185100x003e: { n:"BIFF2WINDOW2" },
185110x0043: { n:"BIFF2XF" },
185120x0045: { n:"BIFF2FONTCLR" },
185130x0056: { n:"BIFF4FMTCNT" }, /* 16-bit cnt, similar to BIFF2 */
185140x007e: { n:"RK" }, /* Not necessarily same as 0x027e */
185150x007f: { n:"ImData", f:parse_ImData },
185160x0087: { n:"Addin" },
185170x0088: { n:"Edg" },
185180x0089: { n:"Pub" },
185190x0091: { n:"Sub" },
185200x0094: { n:"LHRecord" },
185210x0095: { n:"LHNGraph" },
185220x0096: { n:"Sound" },
185230x00a9: { n:"CoordList" },
185240x00ab: { n:"GCW" },
185250x00bc: { n:"ShrFmla" }, /* Not necessarily same as 0x04bc */
185260x00bf: { n:"ToolbarHdr" },
185270x00c0: { n:"ToolbarEnd" },
185280x00c2: { n:"AddMenu" },
185290x00c3: { n:"DelMenu" },
185300x00d6: { n:"RString", f:parse_RString },
185310x00df: { n:"UDDesc" },
185320x00ea: { n:"TabIdConf" },
185330x0162: { n:"XL5Modify" },
185340x01a5: { n:"FileSharing2" },
185350x0209: { n:'BOF', f:parse_BOF },
185360x0218: { n:"Lbl", f:parse_Lbl },
185370x0223: { n:"ExternName", f:parse_ExternName },
185380x0231: { n:"Font" },
185390x0243: { n:"BIFF3XF" },
185400x0409: { n:'BOF', f:parse_BOF },
185410x0443: { n:"BIFF4XF" },
185420x086d: { n:"FeatInfo" },
185430x0873: { n:"FeatInfo11" },
185440x0881: { n:"SXAddl12" },
185450x08c0: { n:"AutoWebPub" },
185460x08c1: { n:"ListObj" },
185470x08c2: { n:"ListField" },
185480x08c3: { n:"ListDV" },
185490x08c4: { n:"ListCondFmt" },
185500x08c5: { n:"ListCF" },
185510x08c6: { n:"FMQry" },
185520x08c7: { n:"FMSQry" },
185530x08c8: { n:"PLV" },
185540x08c9: { n:"LnExt" },
185550x08ca: { n:"MkrExt" },
185560x08cb: { n:"CrtCoopt" },
185570x08d6: { n:"FRTArchId$", r:12 },
18558
185590x7262: {}
18560};
18561
18562var XLSRE = evert_key(XLSRecordEnum, 'n');
18563function write_biff_rec(ba, type, payload, length) {
18564 var t = +type || +XLSRE[type];
18565 if(isNaN(t)) return;
18566 var len = length || (payload||[]).length || 0;
18567 var o = ba.next(4);
18568 o.write_shift(2, t);
18569 o.write_shift(2, len);
18570 if(len > 0 && is_buf(payload)) ba.push(payload);
18571}
18572
18573function write_BIFF2Cell(out, r, c) {
18574 if(!out) out = new_buf(7);
18575 out.write_shift(2, r);
18576 out.write_shift(2, c);
18577 out.write_shift(2, 0);
18578 out.write_shift(1, 0);
18579 return out;
18580}
18581
18582function write_BIFF2BERR(r, c, val, t) {
18583 var out = new_buf(9);
18584 write_BIFF2Cell(out, r, c);
18585 if(t == 'e') { out.write_shift(1, val); out.write_shift(1, 1); }
18586 else { out.write_shift(1, val?1:0); out.write_shift(1, 0); }
18587 return out;
18588}
18589
18590/* TODO: codepage, large strings */
18591function write_BIFF2LABEL(r, c, val) {
18592 var out = new_buf(8 + 2*val.length);
18593 write_BIFF2Cell(out, r, c);
18594 out.write_shift(1, val.length);
18595 out.write_shift(val.length, val, 'sbcs');
18596 return out.l < out.length ? out.slice(0, out.l) : out;
18597}
18598
18599function write_ws_biff2_cell(ba, cell, R, C) {
18600 if(cell.v != null) switch(cell.t) {
18601 case 'd': case 'n':
18602 var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
18603 if((v == (v|0)) && (v >= 0) && (v < 65536))
18604 write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
18605 else
18606 write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
18607 return;
18608 case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
18609 /* TODO: codepage, sst */
18610 case 's': case 'str':
18611 write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v));
18612 return;
18613 }
18614 write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
18615}
18616
18617function write_ws_biff2(ba, ws, idx, opts) {
18618 var dense = Array.isArray(ws);
18619 var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
18620 if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
18621 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
18622 range.e.c = Math.min(range.e.c, 0xFF);
18623 range.e.r = Math.min(range.e.c, 0x3FFF);
18624 ref = encode_range(range);
18625 }
18626 for(var R = range.s.r; R <= range.e.r; ++R) {
18627 rr = encode_row(R);
18628 for(var C = range.s.c; C <= range.e.c; ++C) {
18629 if(R === range.s.r) cols[C] = encode_col(C);
18630 ref = cols[C] + rr;
18631 var cell = dense ? (ws[R]||[])[C] : ws[ref];
18632 if(!cell) continue;
18633 /* write cell */
18634 write_ws_biff2_cell(ba, cell, R, C, opts);
18635 }
18636 }
18637}
18638
18639/* Based on test files */
18640function write_biff2_buf(wb, opts) {
18641 var o = opts || {};
18642 if(DENSE != null && o.dense == null) o.dense = DENSE;
18643 var ba = buf_array();
18644 var idx = 0;
18645 for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
18646 if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
18647 write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o));
18648 /* ... */
18649 write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
18650 /* ... */
18651 write_biff_rec(ba, 0x000A);
18652 return ba.end();
18653}
18654
18655function write_FONTS_biff8(ba, data, opts) {
18656 write_biff_rec(ba, "Font", write_Font({
18657 sz:12,
18658 color: {theme:1},
18659 name: "Arial",
18660 family: 2,
18661 scheme: "minor"
18662 }, opts));
18663}
18664
18665
18666function write_FMTS_biff8(ba, NF, opts) {
18667 if(!NF) return;
18668 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
18669for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts));
18670 });
18671}
18672
18673function write_FEAT(ba, ws) {
18674 /* [MS-XLS] 2.4.112 */
18675 var o = new_buf(19);
18676 o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
18677 o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
18678 write_biff_rec(ba, "FeatHdr", o);
18679 /* [MS-XLS] 2.4.111 */
18680 o = new_buf(39);
18681 o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0);
18682 o.write_shift(2, 3); o.write_shift(1, 0); o.write_shift(4, 0);
18683 o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0);
18684 write_Ref8U(safe_decode_range(ws['!ref']||"A1"), o);
18685 o.write_shift(4, 4);
18686 write_biff_rec(ba, "Feat", o);
18687}
18688
18689function write_CELLXFS_biff8(ba, opts) {
18690 for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts));
18691 opts.cellXfs.forEach(function(c) {
18692 write_biff_rec(ba, "XF", write_XF(c, 0, opts));
18693 });
18694}
18695
18696function write_ws_biff8_hlinks(ba, ws) {
18697 for(var R=0; R<ws['!links'].length; ++R) {
18698 var HL = ws['!links'][R];
18699 write_biff_rec(ba, "HLink", write_HLink(HL));
18700 if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
18701 }
18702 delete ws['!links'];
18703}
18704
18705function write_ws_biff8_cell(ba, cell, R, C, opts) {
18706 var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
18707 if(cell.v != null) switch(cell.t) {
18708 case 'd': case 'n':
18709 var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
18710 /* TODO: emit RK as appropriate */
18711 write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts));
18712 return;
18713 case 'b': case 'e': write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t)); return;
18714 /* TODO: codepage, sst */
18715 case 's': case 'str':
18716 write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts));
18717 return;
18718 }
18719 write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
18720}
18721
18722/* [MS-XLS] 2.1.7.20.5 */
18723function write_ws_biff8(idx, opts, wb) {
18724 var ba = buf_array();
18725 var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
18726 var _WB = ((wb||{}).Workbook||{});
18727 var _sheet = ((_WB.Sheets||[])[idx]||{});
18728 var dense = Array.isArray(ws);
18729 var b8 = opts.biff == 8;
18730 var ref, rr = "", cols = [];
18731 var range = safe_decode_range(ws['!ref'] || "A1");
18732 var MAX_ROWS = b8 ? 65536 : 16384;
18733 if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
18734 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
18735 range.e.c = Math.min(range.e.c, 0xFF);
18736 range.e.r = Math.min(range.e.c, MAX_ROWS-1);
18737 }
18738
18739 write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
18740 /* ... */
18741 write_biff_rec(ba, "CalcMode", writeuint16(1));
18742 write_biff_rec(ba, "CalcCount", writeuint16(100));
18743 write_biff_rec(ba, "CalcRefMode", writebool(true));
18744 write_biff_rec(ba, "CalcIter", writebool(false));
18745 write_biff_rec(ba, "CalcDelta", write_Xnum(0.001));
18746 write_biff_rec(ba, "CalcSaveRecalc", writebool(true));
18747 write_biff_rec(ba, "PrintRowCol", writebool(false));
18748 write_biff_rec(ba, "PrintGrid", writebool(false));
18749 write_biff_rec(ba, "GridSet", writeuint16(1));
18750 write_biff_rec(ba, "Guts", write_Guts([0,0]));
18751 /* ... */
18752 write_biff_rec(ba, "HCenter", writebool(false));
18753 write_biff_rec(ba, "VCenter", writebool(false));
18754 /* ... */
18755 write_biff_rec(ba, 0x200, write_Dimensions(range, opts));
18756 /* ... */
18757
18758 if(b8) ws['!links'] = [];
18759 for(var R = range.s.r; R <= range.e.r; ++R) {
18760 rr = encode_row(R);
18761 for(var C = range.s.c; C <= range.e.c; ++C) {
18762 if(R === range.s.r) cols[C] = encode_col(C);
18763 ref = cols[C] + rr;
18764 var cell = dense ? (ws[R]||[])[C] : ws[ref];
18765 if(!cell) continue;
18766 /* write cell */
18767 write_ws_biff8_cell(ba, cell, R, C, opts);
18768 if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
18769 }
18770 }
18771 var cname = _sheet.CodeName || _sheet.name || s;
18772 /* ... */
18773 if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0]));
18774 /* ... */
18775 if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']));
18776 /* ... */
18777 if(b8) write_ws_biff8_hlinks(ba, ws);
18778 /* ... */
18779 write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
18780 /* ... */
18781 if(b8) write_FEAT(ba, ws);
18782 /* ... */
18783 write_biff_rec(ba, "EOF");
18784 return ba.end();
18785}
18786
18787/* [MS-XLS] 2.1.7.20.3 */
18788function write_biff8_global(wb, bufs, opts) {
18789 var A = buf_array();
18790 var _WB = ((wb||{}).Workbook||{});
18791 var _sheets = (_WB.Sheets||[]);
18792 var _wb = _WB.WBProps||{};
18793 var b8 = opts.biff == 8, b5 = opts.biff == 5;
18794 write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
18795 if(opts.bookType == "xla") write_biff_rec(A, "Addin");
18796 write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null);
18797 write_biff_rec(A, "Mms", writezeroes(2));
18798 if(b5) write_biff_rec(A, "ToolbarHdr");
18799 if(b5) write_biff_rec(A, "ToolbarEnd");
18800 write_biff_rec(A, "InterfaceEnd");
18801 write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
18802 write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4));
18803 if(b8) write_biff_rec(A, "DSF", writeuint16(0));
18804 if(b8) write_biff_rec(A, "Excel9File");
18805 write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
18806 if(b8 && wb.vbaraw) {
18807 write_biff_rec(A, "ObProj");
18808 var cname = _wb.CodeName || "ThisWorkbook";
18809 write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts));
18810 }
18811 write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11));
18812 write_biff_rec(A, "WinProtect", writebool(false));
18813 write_biff_rec(A, "Protect", writebool(false));
18814 write_biff_rec(A, "Password", writeuint16(0));
18815 if(b8) write_biff_rec(A, "Prot4Rev", writebool(false));
18816 if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0));
18817 write_biff_rec(A, "Window1", write_Window1(opts));
18818 write_biff_rec(A, "Backup", writebool(false));
18819 write_biff_rec(A, "HideObj", writeuint16(0));
18820 write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true"));
18821 write_biff_rec(A, "CalcPrecision", writebool(true));
18822 if(b8) write_biff_rec(A, "RefreshAll", writebool(false));
18823 write_biff_rec(A, "BookBool", writeuint16(0));
18824 /* ... */
18825 write_FONTS_biff8(A, wb, opts);
18826 write_FMTS_biff8(A, wb.SSF, opts);
18827 write_CELLXFS_biff8(A, opts);
18828 /* ... */
18829 if(b8) write_biff_rec(A, "UsesELFs", writebool(false));
18830 var a = A.end();
18831
18832 var C = buf_array();
18833 if(b8) write_biff_rec(C, "Country", write_Country());
18834 /* BIFF8: [SST *Continue] ExtSST */
18835 write_biff_rec(C, "EOF");
18836 var c = C.end();
18837
18838 var B = buf_array();
18839 var blen = 0, j = 0;
18840 for(j = 0; j < wb.SheetNames.length; ++j) blen += (b8 ? 12 : 11) + (b8 ? 2 : 1) * wb.SheetNames[j].length;
18841 var start = a.length + blen + c.length;
18842 for(j = 0; j < wb.SheetNames.length; ++j) {
18843 var _sheet = _sheets[j] || ({});
18844 write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts));
18845 start += bufs[j].length;
18846 }
18847 /* 1*BoundSheet8 */
18848 var b = B.end();
18849 if(blen != b.length) throw new Error("BS8 " + blen + " != " + b.length);
18850
18851 var out = [];
18852 if(a.length) out.push(a);
18853 if(b.length) out.push(b);
18854 if(c.length) out.push(c);
18855 return __toBuffer([out]);
18856}
18857
18858/* [MS-XLS] 2.1.7.20 Workbook Stream */
18859function write_biff8_buf(wb, opts) {
18860 var o = opts || {};
18861 var bufs = [];
18862
18863 if(wb && !wb.SSF) {
18864 wb.SSF = SSF.get_table();
18865 }
18866 if(wb && wb.SSF) {
18867 make_ssf(SSF); SSF.load_table(wb.SSF);
18868 // $FlowIgnore
18869 o.revssf = evert_num(wb.SSF); o.revssf[wb.SSF[65535]] = 0;
18870 o.ssf = wb.SSF;
18871 }
18872 o.cellXfs = [];
18873 o.Strings = []; o.Strings.Count = 0; o.Strings.Unique = 0;
18874 get_cell_style(o.cellXfs, {}, {revssf:{"General":0}});
18875
18876 for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb);
18877 bufs.unshift(write_biff8_global(wb, bufs, o));
18878 return __toBuffer([bufs]);
18879}
18880
18881function write_biff_buf(wb, opts) {
18882 var o = opts || {};
18883 switch(o.biff || 2) {
18884 case 8: case 5: return write_biff8_buf(wb, opts);
18885 case 4: case 3: case 2: return write_biff2_buf(wb, opts);
18886 }
18887 throw new Error("invalid type " + o.bookType + " for BIFF");
18888}
18889/* note: browser DOM element cannot see mso- style attrs, must parse */
18890var HTML_ = (function() {
18891 function html_to_sheet(str, _opts) {
18892 var opts = _opts || {};
18893 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
18894 var ws = opts.dense ? ([]) : ({});
18895 var mtch = str.match(/<table/i);
18896 if(!mtch) throw new Error("Invalid HTML: could not find <table>");
18897 var mtch2 = str.match(/<\/table/i);
18898 var i = mtch.index, j = mtch2 && mtch2.index || str.length;
18899 var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
18900 var R = -1, C = 0, RS = 0, CS = 0;
18901 var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
18902 var merges = [];
18903 for(i = 0; i < rows.length; ++i) {
18904 var row = rows[i].trim();
18905 var hd = row.slice(0,3).toLowerCase();
18906 if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
18907 if(hd != "<td" && hd != "<th") continue;
18908 var cells = row.split(/<\/t[dh]>/i);
18909 for(j = 0; j < cells.length; ++j) {
18910 var cell = cells[j].trim();
18911 if(!cell.match(/<t[dh]/i)) continue;
18912 var m = cell, cc = 0;
18913 /* TODO: parse styles etc */
18914 while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
18915 var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
18916 CS = tag.colspan ? +tag.colspan : 1;
18917 if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
18918 var _t = tag.t || "";
18919 /* TODO: generate stub cells */
18920 if(!m.length) { C += CS; continue; }
18921 m = htmldecode(m);
18922 if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
18923 if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
18924 if(!m.length) continue;
18925 var o = {t:'s', v:m};
18926 if(opts.raw || !m.trim().length || _t == 's'){}
18927 else if(m === 'TRUE') o = {t:'b', v:true};
18928 else if(m === 'FALSE') o = {t:'b', v:false};
18929 else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
18930 else if(!isNaN(fuzzydate(m).getDate())) {
18931 o = ({t:'d', v:parseDate(m)});
18932 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
18933 o.z = opts.dateNF || SSF._table[14];
18934 }
18935 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
18936 else ws[encode_cell({r:R, c:C})] = o;
18937 C += CS;
18938 }
18939 }
18940 ws['!ref'] = encode_range(range);
18941 return ws;
18942 }
18943 function html_to_book(str, opts) {
18944 return sheet_to_workbook(html_to_sheet(str, opts), opts);
18945 }
18946 function make_html_row(ws, r, R, o) {
18947 var M = (ws['!merges'] ||[]);
18948 var oo = [];
18949 for(var C = r.s.c; C <= r.e.c; ++C) {
18950 var RS = 0, CS = 0;
18951 for(var j = 0; j < M.length; ++j) {
18952 if(M[j].s.r > R || M[j].s.c > C) continue;
18953 if(M[j].e.r < R || M[j].e.c < C) continue;
18954 if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
18955 RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
18956 }
18957 if(RS < 0) continue;
18958 var coord = encode_cell({r:R,c:C});
18959 var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
18960 var sp = {};
18961 if(RS > 1) sp.rowspan = RS;
18962 if(CS > 1) sp.colspan = CS;
18963 /* TODO: html entities */
18964 var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
18965 sp.t = cell && cell.t || 'z';
18966 if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
18967 sp.id = "sjs-" + coord;
18968 oo.push(writextag('td', w, sp));
18969 }
18970 var preamble = "<tr>";
18971 return preamble + oo.join("") + "</tr>";
18972 }
18973 function make_html_preamble(ws, R, o) {
18974 var out = [];
18975 return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
18976 }
18977 var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
18978 var _END = '</body></html>';
18979 function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
18980 var o = opts || {};
18981 var header = o.header != null ? o.header : _BEGIN;
18982 var footer = o.footer != null ? o.footer : _END;
18983 var out = [header];
18984 var r = decode_range(ws['!ref']);
18985 o.dense = Array.isArray(ws);
18986 out.push(make_html_preamble(ws, r, o));
18987 for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
18988 out.push("</table>" + footer);
18989 return out.join("");
18990 }
18991
18992 return {
18993 to_workbook: html_to_book,
18994 to_sheet: html_to_sheet,
18995 _row: make_html_row,
18996 BEGIN: _BEGIN,
18997 END: _END,
18998 _preamble: make_html_preamble,
18999 from_sheet: sheet_to_html
19000 };
19001})();
19002
19003function parse_dom_table(table, _opts) {
19004 var opts = _opts || {};
19005 if(DENSE != null) opts.dense = DENSE;
19006 var ws = opts.dense ? ([]) : ({});
19007 var rows = table.getElementsByTagName('tr');
19008 var sheetRows = opts.sheetRows || 10000000;
19009 var range = {s:{r:0,c:0},e:{r:0,c:0}};
19010 var merges = [], midx = 0;
19011 var rowinfo = [];
19012 var _R = 0, R = 0, _C, C, RS, CS;
19013 for(; _R < rows.length && R < sheetRows; ++_R) {
19014 var row = rows[_R];
19015 if (is_dom_element_hidden(row)) {
19016 if (opts.display) continue;
19017 rowinfo[R] = {hidden: true};
19018 }
19019 var elts = (row.children);
19020 for(_C = C = 0; _C < elts.length; ++_C) {
19021 var elt = elts[_C];
19022 if (opts.display && is_dom_element_hidden(elt)) continue;
19023 var v = htmldecode(elt.innerHTML);
19024 for(midx = 0; midx < merges.length; ++midx) {
19025 var m = merges[midx];
19026 if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
19027 }
19028 /* TODO: figure out how to extract nonstandard mso- style */
19029 CS = +elt.getAttribute("colspan") || 1;
19030 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}});
19031 var o = {t:'s', v:v};
19032 var _t = elt.getAttribute("t") || "";
19033 if(v != null) {
19034 if(v.length == 0) o.t = _t || 'z';
19035 else if(opts.raw || v.trim().length == 0 || _t == "s"){}
19036 else if(v === 'TRUE') o = {t:'b', v:true};
19037 else if(v === 'FALSE') o = {t:'b', v:false};
19038 else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
19039 else if(!isNaN(fuzzydate(v).getDate())) {
19040 o = ({t:'d', v:parseDate(v)});
19041 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
19042 o.z = opts.dateNF || SSF._table[14];
19043 }
19044 }
19045 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
19046 else ws[encode_cell({c:C, r:R})] = o;
19047 if(range.e.c < C) range.e.c = C;
19048 C += CS;
19049 }
19050 ++R;
19051 }
19052 if(merges.length) ws['!merges'] = merges;
19053 if(rowinfo.length) ws['!rows'] = rowinfo;
19054 range.e.r = R - 1;
19055 ws['!ref'] = encode_range(range);
19056 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
19057 return ws;
19058}
19059
19060function table_to_book(table, opts) {
19061 return sheet_to_workbook(parse_dom_table(table, opts), opts);
19062}
19063
19064function is_dom_element_hidden(element) {
19065 var display = '';
19066 var get_computed_style = get_get_computed_style_function(element);
19067 if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
19068 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)
19069 return display === 'none';
19070}
19071
19072/* global getComputedStyle */
19073function get_get_computed_style_function(element) {
19074 // The proper getComputedStyle implementation is the one defined in the element window
19075 if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
19076 // If it is not available, try to get one from the global namespace
19077 if(typeof getComputedStyle === 'function') return getComputedStyle;
19078 return null;
19079}
19080/* OpenDocument */
19081var parse_content_xml = (function() {
19082
19083 var parse_text_p = function(text) {
19084 /* 6.1.2 White Space Characters */
19085 var fixed = text
19086 .replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
19087 .replace(/<text:s\/>/g," ")
19088 .replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
19089 .replace(/<text:tab[^>]*\/>/g,"\t")
19090 .replace(/<text:line-break\/>/g,"\n");
19091 var v = unescapexml(fixed.replace(/<[^>]*>/g,""));
19092
19093 return [v];
19094 };
19095
19096 var number_formats = {
19097 /* ods name: [short ssf fmt, long ssf fmt] */
19098 day: ["d", "dd"],
19099 month: ["m", "mm"],
19100 year: ["y", "yy"],
19101 hours: ["h", "hh"],
19102 minutes: ["m", "mm"],
19103 seconds: ["s", "ss"],
19104 "am-pm": ["A/P", "AM/PM"],
19105 "day-of-week": ["ddd", "dddd"],
19106 era: ["e", "ee"],
19107 /* there is no native representation of LO "Q" format */
19108 quarter: ["\\Qm", "m\\\"th quarter\""]
19109 };
19110
19111 return function pcx(d, _opts) {
19112 var opts = _opts || {};
19113 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
19114 var str = xlml_normalize(d);
19115 var state = [], tmp;
19116 var tag;
19117 var NFtag = {name:""}, NF = "", pidx = 0;
19118 var sheetag;
19119 var rowtag;
19120 var Sheets = {}, SheetNames = [];
19121 var ws = opts.dense ? ([]) : ({});
19122 var Rn, q;
19123 var ctag = ({value:""});
19124 var textp = "", textpidx = 0, textptag;
19125 var textR = [];
19126 var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
19127 var row_ol = 0;
19128 var number_format_map = {};
19129 var merges = [], mrange = {}, mR = 0, mC = 0;
19130 var rowinfo = [], rowpeat = 1, colpeat = 1;
19131 var arrayf = [];
19132 var WB = {Names:[]};
19133 var atag = ({});
19134 var _Ref = ["", ""];
19135 var comments = [], comment = ({});
19136 var creator = "", creatoridx = 0;
19137 var isstub = false, intable = false;
19138 var i = 0;
19139 xlmlregex.lastIndex = 0;
19140 str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
19141 while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
19142
19143 case 'table': case '工作表': // 9.1.2 <table:table>
19144 if(Rn[1]==='/') {
19145 if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
19146 if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
19147 ws['!fullref'] = ws['!ref'];
19148 range.e.r = opts.sheetRows - 1;
19149 ws['!ref'] = encode_range(range);
19150 }
19151 if(merges.length) ws['!merges'] = merges;
19152 if(rowinfo.length) ws["!rows"] = rowinfo;
19153 sheetag.name = sheetag['名称'] || sheetag.name;
19154 if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
19155 SheetNames.push(sheetag.name);
19156 Sheets[sheetag.name] = ws;
19157 intable = false;
19158 }
19159 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
19160 sheetag = parsexmltag(Rn[0], false);
19161 R = C = -1;
19162 range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
19163 ws = opts.dense ? ([]) : ({}); merges = [];
19164 rowinfo = [];
19165 intable = true;
19166 }
19167 break;
19168
19169 case 'table-row-group': // 9.1.9 <table:table-row-group>
19170 if(Rn[1] === "/") --row_ol; else ++row_ol;
19171 break;
19172 case 'table-row': case '行': // 9.1.3 <table:table-row>
19173 if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
19174 rowtag = parsexmltag(Rn[0], false);
19175 if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
19176 rowpeat = +rowtag['number-rows-repeated'] || 1;
19177 /* TODO: remove magic */
19178 if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
19179 C = -1; break;
19180 case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
19181 if(Rn[1] !== '/') ++C;
19182 if(opts.sheetStubs) {
19183 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
19184 else ws[encode_cell({r:R,c:C})] = {t:'z'};
19185 }
19186 textp = ""; textR = [];
19187 break; /* stub */
19188 case 'table-cell': case '数据':
19189 if(Rn[0].charAt(Rn[0].length-2) === '/') {
19190 ++C;
19191 ctag = parsexmltag(Rn[0], false);
19192 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19193 q = ({t:'z', v:null});
19194 if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
19195 if((ctag['数据类型'] || ctag['value-type']) == "string") {
19196 q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
19197 if(opts.dense) {
19198 if(!ws[R]) ws[R] = [];
19199 ws[R][C] = q;
19200 } else {
19201 ws[encode_cell({r:R,c:C})] = q;
19202 }
19203 }
19204 C+= colpeat-1;
19205 } else if(Rn[1]!=='/') {
19206 ++C;
19207 colpeat = 1;
19208 var rptR = rowpeat ? R + rowpeat - 1 : R;
19209 if(C > range.e.c) range.e.c = C;
19210 if(C < range.s.c) range.s.c = C;
19211 if(R < range.s.r) range.s.r = R;
19212 if(rptR > range.e.r) range.e.r = rptR;
19213 ctag = parsexmltag(Rn[0], false);
19214 comments = []; comment = ({});
19215 q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
19216 if(opts.cellFormula) {
19217 if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
19218 if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
19219 mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
19220 mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
19221 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
19222 q.F = encode_range(mrange);
19223 arrayf.push([mrange, q.F]);
19224 }
19225 if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
19226 else for(i = 0; i < arrayf.length; ++i)
19227 if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
19228 if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
19229 q.F = arrayf[i][1];
19230 }
19231 if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
19232 mR = parseInt(ctag['number-rows-spanned'],10) || 0;
19233 mC = parseInt(ctag['number-columns-spanned'],10) || 0;
19234 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
19235 merges.push(mrange);
19236 }
19237
19238 /* 19.675.2 table:number-columns-repeated */
19239 if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
19240
19241 /* 19.385 office:value-type */
19242 switch(q.t) {
19243 case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
19244 case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19245 case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19246 case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19247 case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
19248 if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
19249 q.z = 'm/d/yy'; break;
19250 case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
19251 case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
19252 default:
19253 if(q.t === 'string' || q.t === 'text' || !q.t) {
19254 q.t = 's';
19255 if(ctag['string-value'] != null) { textp = unescapexml(ctag['string-value']); textR = []; }
19256 } else throw new Error('Unsupported value type ' + q.t);
19257 }
19258 } else {
19259 isstub = false;
19260 if(q.t === 's') {
19261 q.v = textp || '';
19262 if(textR.length) q.R = textR;
19263 isstub = textpidx == 0;
19264 }
19265 if(atag.Target) q.l = atag;
19266 if(comments.length > 0) { q.c = comments; comments = []; }
19267 if(textp && opts.cellText !== false) q.w = textp;
19268 if(!isstub || opts.sheetStubs) {
19269 if(!(opts.sheetRows && opts.sheetRows <= R)) {
19270 for(var rpt = 0; rpt < rowpeat; ++rpt) {
19271 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19272 if(opts.dense) {
19273 if(!ws[R + rpt]) ws[R + rpt] = [];
19274 ws[R + rpt][C] = rpt == 0 ? q : dup(q);
19275 while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
19276 } else {
19277 ws[encode_cell({r:R + rpt,c:C})] = q;
19278 while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
19279 }
19280 if(range.e.c <= C) range.e.c = C;
19281 }
19282 }
19283 }
19284 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19285 C += colpeat-1; colpeat = 0;
19286 q = {};
19287 textp = ""; textR = [];
19288 }
19289 atag = ({});
19290 break; // 9.1.4 <table:table-cell>
19291
19292 /* pure state */
19293 case 'document': // TODO: <office:document> is the root for FODS
19294 case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
19295 case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
19296 case 'scripts': // 3.12 <office:scripts>
19297 case 'styles': // TODO <office:styles>
19298 case 'font-face-decls': // 3.14 <office:font-face-decls>
19299 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
19300 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
19301 break;
19302
19303 case 'annotation': // 14.1 <office:annotation>
19304 if(Rn[1]==='/'){
19305 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
19306 comment.t = textp;
19307 if(textR.length) comment.R = textR;
19308 comment.a = creator;
19309 comments.push(comment);
19310 }
19311 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
19312 creator = ""; creatoridx = 0;
19313 textp = ""; textpidx = 0; textR = [];
19314 break;
19315
19316 case 'creator': // 4.3.2.7 <dc:creator>
19317 if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
19318 else creatoridx = Rn.index + Rn[0].length;
19319 break;
19320
19321 /* ignore state */
19322 case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
19323 case 'settings': // TODO: <office:settings>
19324 case 'config-item-set': // TODO: <office:config-item-set>
19325 case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
19326 case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
19327 case 'config-item-map-named': // TODO: <office:config-item-map-entry>
19328 case 'shapes': // 9.2.8 <table:shapes>
19329 case 'frame': // 10.4.2 <draw:frame>
19330 case 'text-box': // 10.4.3 <draw:text-box>
19331 case 'image': // 10.4.4 <draw:image>
19332 case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
19333 case 'list-style': // 16.30 <text:list-style>
19334 case 'form': // 13.13 <form:form>
19335 case 'dde-links': // 9.8 <table:dde-links>
19336 case 'event-listeners': // TODO
19337 case 'chart': // TODO
19338 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
19339 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
19340 textp = ""; textpidx = 0; textR = [];
19341 break;
19342
19343 case 'scientific-number': // TODO: <number:scientific-number>
19344 break;
19345 case 'currency-symbol': // TODO: <number:currency-symbol>
19346 break;
19347 case 'currency-style': // TODO: <number:currency-style>
19348 break;
19349 case 'number-style': // 16.27.2 <number:number-style>
19350 case 'percentage-style': // 16.27.9 <number:percentage-style>
19351 case 'date-style': // 16.27.10 <number:date-style>
19352 case 'time-style': // 16.27.18 <number:time-style>
19353 if(Rn[1]==='/'){
19354 number_format_map[NFtag.name] = NF;
19355 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
19356 } else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
19357 NF = "";
19358 NFtag = parsexmltag(Rn[0], false);
19359 state.push([Rn[3], true]);
19360 } break;
19361
19362 case 'script': break; // 3.13 <office:script>
19363 case 'libraries': break; // TODO: <ooo:libraries>
19364 case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
19365 case 'master-styles': break; // TODO: <office:master-styles>
19366
19367 case 'default-style': // TODO: <style:default-style>
19368 case 'page-layout': break; // TODO: <style:page-layout>
19369 case 'style': // 16.2 <style:style>
19370 break;
19371 case 'map': break; // 16.3 <style:map>
19372 case 'font-face': break; // 16.21 <style:font-face>
19373
19374 case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
19375 case 'table-properties': break; // 17.15 <style:table-properties>
19376 case 'table-column-properties': break; // 17.16 <style:table-column-properties>
19377 case 'table-row-properties': break; // 17.17 <style:table-row-properties>
19378 case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
19379
19380 case 'number': // 16.27.3 <number:number>
19381 switch(state[state.length-1][0]) {
19382 case 'time-style':
19383 case 'date-style':
19384 tag = parsexmltag(Rn[0], false);
19385 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
19386 } break;
19387
19388 case 'fraction': break; // TODO 16.27.6 <number:fraction>
19389
19390 case 'day': // 16.27.11 <number:day>
19391 case 'month': // 16.27.12 <number:month>
19392 case 'year': // 16.27.13 <number:year>
19393 case 'era': // 16.27.14 <number:era>
19394 case 'day-of-week': // 16.27.15 <number:day-of-week>
19395 case 'week-of-year': // 16.27.16 <number:week-of-year>
19396 case 'quarter': // 16.27.17 <number:quarter>
19397 case 'hours': // 16.27.19 <number:hours>
19398 case 'minutes': // 16.27.20 <number:minutes>
19399 case 'seconds': // 16.27.21 <number:seconds>
19400 case 'am-pm': // 16.27.22 <number:am-pm>
19401 switch(state[state.length-1][0]) {
19402 case 'time-style':
19403 case 'date-style':
19404 tag = parsexmltag(Rn[0], false);
19405 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
19406 } break;
19407
19408 case 'boolean-style': break; // 16.27.23 <number:boolean-style>
19409 case 'boolean': break; // 16.27.24 <number:boolean>
19410 case 'text-style': break; // 16.27.25 <number:text-style>
19411 case 'text': // 16.27.26 <number:text>
19412 if(Rn[0].slice(-2) === "/>") break;
19413 else if(Rn[1]==="/") switch(state[state.length-1][0]) {
19414 case 'number-style':
19415 case 'date-style':
19416 case 'time-style':
19417 NF += str.slice(pidx, Rn.index);
19418 break;
19419 }
19420 else pidx = Rn.index + Rn[0].length;
19421 break;
19422
19423 case 'named-range': // 9.4.12 <table:named-range>
19424 tag = parsexmltag(Rn[0], false);
19425 _Ref = ods_to_csf_3D(tag['cell-range-address']);
19426 var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
19427 if(intable) nrange.Sheet = SheetNames.length;
19428 WB.Names.push(nrange);
19429 break;
19430
19431 case 'text-content': break; // 16.27.27 <number:text-content>
19432 case 'text-properties': break; // 16.27.27 <style:text-properties>
19433 case 'embedded-text': break; // 16.27.4 <number:embedded-text>
19434
19435 case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
19436
19437 case 'forms': break; // 12.25.2 13.2
19438 case 'table-column': break; // 9.1.6 <table:table-column>
19439 case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
19440 case 'table-rows': break; // 9.1.12 <table:table-rows>
19441 /* TODO: outline levels */
19442 case 'table-column-group': break; // 9.1.10 <table:table-column-group>
19443 case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
19444 case 'table-columns': break; // 9.1.12 <table:table-columns>
19445
19446 case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
19447
19448 case 'graphic-properties': break; // 17.21 <style:graphic-properties>
19449 case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
19450 case 'named-expressions': break; // 9.4.11 <table:named-expressions>
19451 case 'label-range': break; // 9.4.9 <table:label-range>
19452 case 'label-ranges': break; // 9.4.10 <table:label-ranges>
19453 case 'named-expression': break; // 9.4.13 <table:named-expression>
19454 case 'sort': break; // 9.4.19 <table:sort>
19455 case 'sort-by': break; // 9.4.20 <table:sort-by>
19456 case 'sort-groups': break; // 9.4.22 <table:sort-groups>
19457
19458 case 'tab': break; // 6.1.4 <text:tab>
19459 case 'line-break': break; // 6.1.5 <text:line-break>
19460 case 'span': break; // 6.1.7 <text:span>
19461 case 'p': case '文本串': // 5.1.3 <text:p>
19462 if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) {
19463 var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
19464 textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0];
19465 } else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
19466 break; // <text:p>
19467 case 's': break; // <text:s>
19468
19469 case 'database-range': // 9.4.15 <table:database-range>
19470 if(Rn[1]==='/') break;
19471 try {
19472 _Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
19473 Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
19474 } catch(e) {/* empty */}
19475 break;
19476
19477 case 'date': break; // <*:date>
19478
19479 case 'object': break; // 10.4.6.2 <draw:object>
19480 case 'title': case '标题': break; // <*:title> OR <uof:标题>
19481 case 'desc': break; // <*:desc>
19482 case 'binary-data': break; // 10.4.5 TODO: b64 blob
19483
19484 /* 9.2 Advanced Tables */
19485 case 'table-source': break; // 9.2.6
19486 case 'scenario': break; // 9.2.6
19487
19488 case 'iteration': break; // 9.4.3 <table:iteration>
19489 case 'content-validations': break; // 9.4.4 <table:
19490 case 'content-validation': break; // 9.4.5 <table:
19491 case 'help-message': break; // 9.4.6 <table:
19492 case 'error-message': break; // 9.4.7 <table:
19493 case 'database-ranges': break; // 9.4.14 <table:database-ranges>
19494 case 'filter': break; // 9.5.2 <table:filter>
19495 case 'filter-and': break; // 9.5.3 <table:filter-and>
19496 case 'filter-or': break; // 9.5.4 <table:filter-or>
19497 case 'filter-condition': break; // 9.5.5 <table:filter-condition>
19498
19499 case 'list-level-style-bullet': break; // 16.31 <text:
19500 case 'list-level-style-number': break; // 16.32 <text:
19501 case 'list-level-properties': break; // 17.19 <style:
19502
19503 /* 7.3 Document Fields */
19504 case 'sender-firstname': // 7.3.6.2
19505 case 'sender-lastname': // 7.3.6.3
19506 case 'sender-initials': // 7.3.6.4
19507 case 'sender-title': // 7.3.6.5
19508 case 'sender-position': // 7.3.6.6
19509 case 'sender-email': // 7.3.6.7
19510 case 'sender-phone-private': // 7.3.6.8
19511 case 'sender-fax': // 7.3.6.9
19512 case 'sender-company': // 7.3.6.10
19513 case 'sender-phone-work': // 7.3.6.11
19514 case 'sender-street': // 7.3.6.12
19515 case 'sender-city': // 7.3.6.13
19516 case 'sender-postal-code': // 7.3.6.14
19517 case 'sender-country': // 7.3.6.15
19518 case 'sender-state-or-province': // 7.3.6.16
19519 case 'author-name': // 7.3.7.1
19520 case 'author-initials': // 7.3.7.2
19521 case 'chapter': // 7.3.8
19522 case 'file-name': // 7.3.9
19523 case 'template-name': // 7.3.9
19524 case 'sheet-name': // 7.3.9
19525 break;
19526
19527 case 'event-listener':
19528 break;
19529 /* TODO: FODS Properties */
19530 case 'initial-creator':
19531 case 'creation-date':
19532 case 'print-date':
19533 case 'generator':
19534 case 'document-statistic':
19535 case 'user-defined':
19536 case 'editing-duration':
19537 case 'editing-cycles':
19538 break;
19539
19540 /* TODO: FODS Config */
19541 case 'config-item':
19542 break;
19543
19544 /* TODO: style tokens */
19545 case 'page-number': break; // TODO <text:page-number>
19546 case 'page-count': break; // TODO <text:page-count>
19547 case 'time': break; // TODO <text:time>
19548
19549 /* 9.3 Advanced Table Cells */
19550 case 'cell-range-source': break; // 9.3.1 <table:
19551 case 'detective': break; // 9.3.2 <table:
19552 case 'operation': break; // 9.3.3 <table:
19553 case 'highlighted-range': break; // 9.3.4 <table:
19554
19555 /* 9.6 Data Pilot Tables <table: */
19556 case 'data-pilot-table': // 9.6.3
19557 case 'source-cell-range': // 9.6.5
19558 case 'source-service': // 9.6.6
19559 case 'data-pilot-field': // 9.6.7
19560 case 'data-pilot-level': // 9.6.8
19561 case 'data-pilot-subtotals': // 9.6.9
19562 case 'data-pilot-subtotal': // 9.6.10
19563 case 'data-pilot-members': // 9.6.11
19564 case 'data-pilot-member': // 9.6.12
19565 case 'data-pilot-display-info': // 9.6.13
19566 case 'data-pilot-sort-info': // 9.6.14
19567 case 'data-pilot-layout-info': // 9.6.15
19568 case 'data-pilot-field-reference': // 9.6.16
19569 case 'data-pilot-groups': // 9.6.17
19570 case 'data-pilot-group': // 9.6.18
19571 case 'data-pilot-group-member': // 9.6.19
19572 break;
19573
19574 /* 10.3 Drawing Shapes */
19575 case 'rect': // 10.3.2
19576 break;
19577
19578 /* 14.6 DDE Connections */
19579 case 'dde-connection-decls': // 14.6.2 <text:
19580 case 'dde-connection-decl': // 14.6.3 <text:
19581 case 'dde-link': // 14.6.4 <table:
19582 case 'dde-source': // 14.6.5 <office:
19583 break;
19584
19585 case 'properties': break; // 13.7 <form:properties>
19586 case 'property': break; // 13.8 <form:property>
19587
19588 case 'a': // 6.1.8 hyperlink
19589 if(Rn[1]!== '/') {
19590 atag = parsexmltag(Rn[0], false);
19591 if(!atag.href) break;
19592 atag.Target = atag.href; delete atag.href;
19593 if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
19594 _Ref = ods_to_csf_3D(atag.Target.slice(1));
19595 atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
19596 }
19597 }
19598 break;
19599
19600 /* non-standard */
19601 case 'table-protection': break;
19602 case 'data-pilot-grand-total': break; // <table:
19603 case 'office-document-common-attrs': break; // bare
19604 default: switch(Rn[2]) {
19605 case 'dc:': // TODO: properties
19606 case 'calcext:': // ignore undocumented extensions
19607 case 'loext:': // ignore undocumented extensions
19608 case 'ooo:': // ignore undocumented extensions
19609 case 'chartooo:': // ignore undocumented extensions
19610 case 'draw:': // TODO: drawing
19611 case 'style:': // TODO: styles
19612 case 'chart:': // TODO: charts
19613 case 'form:': // TODO: forms
19614 case 'uof:': // TODO: uof
19615 case '表:': // TODO: uof
19616 case '字:': // TODO: uof
19617 break;
19618 default: if(opts.WTF) throw new Error(Rn);
19619 }
19620 }
19621 var out = ({
19622 Sheets: Sheets,
19623 SheetNames: SheetNames,
19624 Workbook: WB
19625 });
19626 if(opts.bookSheets) delete out.Sheets;
19627 return out;
19628 };
19629})();
19630
19631function parse_ods(zip, opts) {
19632 opts = opts || ({});
19633 var ods = !!safegetzipfile(zip, 'objectdata');
19634 if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
19635 var content = getzipstr(zip, 'content.xml');
19636 if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
19637 var wb = parse_content_xml(ods ? content : utf8read(content), opts);
19638 if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
19639 return wb;
19640}
19641function parse_fods(data, opts) {
19642 return parse_content_xml(data, opts);
19643}
19644
19645/* OpenDocument */
19646var write_styles_ods = (function() {
19647 var payload = '<office:document-styles ' + wxt_helper({
19648 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
19649 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
19650 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
19651 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
19652 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
19653 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
19654 'xmlns:xlink': "http://www.w3.org/1999/xlink",
19655 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
19656 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
19657 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
19658 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
19659 'office:version': "1.2"
19660 }) + '></office:document-styles>';
19661 return function wso() {
19662 return XML_HEADER + payload;
19663 };
19664})();
19665var write_content_ods = (function() {
19666 /* 6.1.2 White Space Characters */
19667 var write_text_p = function(text) {
19668 return escapexml(text)
19669 .replace(/ +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
19670 .replace(/\t/g, "<text:tab/>")
19671 .replace(/\n/g, "<text:line-break/>")
19672 .replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
19673 };
19674
19675 var null_cell_xml = ' <table:table-cell />\n';
19676 var covered_cell_xml = ' <table:covered-table-cell/>\n';
19677 var write_ws = function(ws, wb, i) {
19678 /* Section 9 Tables */
19679 var o = [];
19680 o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
19681 var R=0,C=0, range = decode_range(ws['!ref']);
19682 var marr = ws['!merges'] || [], mi = 0;
19683 var dense = Array.isArray(ws);
19684 for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
19685 for(; R <= range.e.r; ++R) {
19686 o.push(' <table:table-row>\n');
19687 for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
19688 for(; C <= range.e.c; ++C) {
19689 var skip = false, ct = {}, textp = "";
19690 for(mi = 0; mi != marr.length; ++mi) {
19691 if(marr[mi].s.c > C) continue;
19692 if(marr[mi].s.r > R) continue;
19693 if(marr[mi].e.c < C) continue;
19694 if(marr[mi].e.r < R) continue;
19695 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
19696 ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
19697 ct['table:number-rows-spanned'] = (marr[mi].e.r - marr[mi].s.r + 1);
19698 break;
19699 }
19700 if(skip) { o.push(covered_cell_xml); continue; }
19701 var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
19702 if(cell && cell.f) {
19703 ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
19704 if(cell.F) {
19705 if(cell.F.slice(0, ref.length) == ref) {
19706 var _Fref = decode_range(cell.F);
19707 ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
19708 ct['table:number-matrix-rows-spanned'] = (_Fref.e.r - _Fref.s.r + 1);
19709 }
19710 }
19711 }
19712 if(!cell) { o.push(null_cell_xml); continue; }
19713 switch(cell.t) {
19714 case 'b':
19715 textp = (cell.v ? 'TRUE' : 'FALSE');
19716 ct['office:value-type'] = "boolean";
19717 ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
19718 break;
19719 case 'n':
19720 textp = (cell.w||String(cell.v||0));
19721 ct['office:value-type'] = "float";
19722 ct['office:value'] = (cell.v||0);
19723 break;
19724 case 's': case 'str':
19725 textp = cell.v;
19726 ct['office:value-type'] = "string";
19727 break;
19728 case 'd':
19729 textp = (cell.w||(parseDate(cell.v).toISOString()));
19730 ct['office:value-type'] = "date";
19731 ct['office:date-value'] = (parseDate(cell.v).toISOString());
19732 ct['table:style-name'] = "ce1";
19733 break;
19734 //case 'e':
19735 default: o.push(null_cell_xml); continue;
19736 }
19737 var text_p = write_text_p(textp);
19738 if(cell.l && cell.l.Target) {
19739 var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
19740 text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
19741 }
19742 o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
19743 }
19744 o.push(' </table:table-row>\n');
19745 }
19746 o.push(' </table:table>\n');
19747 return o.join("");
19748 };
19749
19750 var write_automatic_styles_ods = function(o) {
19751 o.push(' <office:automatic-styles>\n');
19752 o.push(' <number:date-style style:name="N37" number:automatic-order="true">\n');
19753 o.push(' <number:month number:style="long"/>\n');
19754 o.push(' <number:text>/</number:text>\n');
19755 o.push(' <number:day number:style="long"/>\n');
19756 o.push(' <number:text>/</number:text>\n');
19757 o.push(' <number:year/>\n');
19758 o.push(' </number:date-style>\n');
19759 o.push(' <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
19760 o.push(' </office:automatic-styles>\n');
19761 };
19762
19763 return function wcx(wb, opts) {
19764 var o = [XML_HEADER];
19765 /* 3.1.3.2 */
19766 var attr = wxt_helper({
19767 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
19768 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
19769 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
19770 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
19771 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
19772 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
19773 'xmlns:xlink': "http://www.w3.org/1999/xlink",
19774 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
19775 'xmlns:meta': "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
19776 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
19777 'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
19778 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
19779 'xmlns:chart': "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
19780 'xmlns:dr3d': "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
19781 'xmlns:math': "http://www.w3.org/1998/Math/MathML",
19782 'xmlns:form': "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
19783 'xmlns:script': "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
19784 'xmlns:ooo': "http://openoffice.org/2004/office",
19785 'xmlns:ooow': "http://openoffice.org/2004/writer",
19786 'xmlns:oooc': "http://openoffice.org/2004/calc",
19787 'xmlns:dom': "http://www.w3.org/2001/xml-events",
19788 'xmlns:xforms': "http://www.w3.org/2002/xforms",
19789 'xmlns:xsd': "http://www.w3.org/2001/XMLSchema",
19790 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
19791 'xmlns:sheet': "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
19792 'xmlns:rpt': "http://openoffice.org/2005/report",
19793 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
19794 'xmlns:xhtml': "http://www.w3.org/1999/xhtml",
19795 'xmlns:grddl': "http://www.w3.org/2003/g/data-view#",
19796 'xmlns:tableooo': "http://openoffice.org/2009/table",
19797 'xmlns:drawooo': "http://openoffice.org/2010/draw",
19798 'xmlns:calcext': "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
19799 'xmlns:loext': "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
19800 'xmlns:field': "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
19801 'xmlns:formx': "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
19802 'xmlns:css3t': "http://www.w3.org/TR/css3-text/",
19803 'office:version': "1.2"
19804 });
19805
19806 var fods = wxt_helper({
19807 'xmlns:config': "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
19808 'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
19809 });
19810
19811 if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n');
19812 else o.push('<office:document-content' + attr + '>\n');
19813 write_automatic_styles_ods(o);
19814 o.push(' <office:body>\n');
19815 o.push(' <office:spreadsheet>\n');
19816 for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
19817 o.push(' </office:spreadsheet>\n');
19818 o.push(' </office:body>\n');
19819 if(opts.bookType == "fods") o.push('</office:document>');
19820 else o.push('</office:document-content>');
19821 return o.join("");
19822 };
19823})();
19824
19825function write_ods(wb, opts) {
19826 if(opts.bookType == "fods") return write_content_ods(wb, opts);
19827
19828var zip = new jszip();
19829 var f = "";
19830
19831 var manifest = [];
19832 var rdf = [];
19833
19834 /* Part 3 Section 3.3 MIME Media Type */
19835 f = "mimetype";
19836 zip.file(f, "application/vnd.oasis.opendocument.spreadsheet");
19837
19838 /* Part 1 Section 2.2 Documents */
19839 f = "content.xml";
19840 zip.file(f, write_content_ods(wb, opts));
19841 manifest.push([f, "text/xml"]);
19842 rdf.push([f, "ContentFile"]);
19843
19844 /* TODO: these are hard-coded styles to satiate excel */
19845 f = "styles.xml";
19846 zip.file(f, write_styles_ods(wb, opts));
19847 manifest.push([f, "text/xml"]);
19848 rdf.push([f, "StylesFile"]);
19849
19850 /* TODO: this is hard-coded to satiate excel */
19851 f = "meta.xml";
19852 zip.file(f, write_meta_ods());
19853 manifest.push([f, "text/xml"]);
19854 rdf.push([f, "MetadataFile"]);
19855
19856 /* Part 3 Section 6 Metadata Manifest File */
19857 f = "manifest.rdf";
19858 zip.file(f, write_rdf(rdf/*, opts*/));
19859 manifest.push([f, "application/rdf+xml"]);
19860
19861 /* Part 3 Section 4 Manifest File */
19862 f = "META-INF/manifest.xml";
19863 zip.file(f, write_manifest(manifest/*, opts*/));
19864
19865 return zip;
19866}
19867
19868function write_sheet_index(wb, sheet) {
19869 if(!sheet) return 0;
19870 var idx = wb.SheetNames.indexOf(sheet);
19871 if(idx == -1) throw new Error("Sheet not found: " + sheet);
19872 return idx;
19873}
19874
19875function write_obj_str(factory) {
19876 return function write_str(wb, o) {
19877 var idx = write_sheet_index(wb, o.sheet);
19878 return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
19879 };
19880}
19881
19882var write_htm_str = write_obj_str(HTML_);
19883var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
19884var write_slk_str = write_obj_str(SYLK);
19885var write_dif_str = write_obj_str(DIF);
19886var write_prn_str = write_obj_str(PRN);
19887var write_rtf_str = write_obj_str(RTF);
19888var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
19889var write_dbf_buf = write_obj_str(DBF);
19890var write_eth_str = write_obj_str(ETH);
19891
19892function fix_opts_func(defaults) {
19893 return function fix_opts(opts) {
19894 for(var i = 0; i != defaults.length; ++i) {
19895 var d = defaults[i];
19896 if(opts[d[0]] === undefined) opts[d[0]] = d[1];
19897 if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
19898 }
19899 };
19900}
19901
19902var fix_read_opts = fix_opts_func([
19903 ['cellNF', false], /* emit cell number format string as .z */
19904 ['cellHTML', true], /* emit html string as .h */
19905 ['cellFormula', true], /* emit formulae as .f */
19906 ['cellStyles', false], /* emits style/theme as .s */
19907 ['cellText', true], /* emit formatted text as .w */
19908 ['cellDates', false], /* emit date cells with type `d` */
19909
19910 ['sheetStubs', false], /* emit empty cells */
19911 ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
19912
19913 ['bookDeps', false], /* parse calculation chains */
19914 ['bookSheets', false], /* only try to get sheet names (no Sheets) */
19915 ['bookProps', false], /* only try to get properties (no Sheets) */
19916 ['bookFiles', false], /* include raw file structure (keys, files, cfb) */
19917 ['bookVBA', false], /* include vba raw data (vbaraw) */
19918
19919 ['password',''], /* password */
19920 ['WTF', false] /* WTF mode (throws errors) */
19921]);
19922
19923
19924var fix_write_opts = fix_opts_func([
19925 ['cellDates', false], /* write date cells with type `d` */
19926
19927 ['bookSST', false], /* Generate Shared String Table */
19928
19929 ['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
19930
19931 ['compression', false], /* Use file compression */
19932
19933 ['WTF', false] /* WTF mode (throws errors) */
19934]);
19935function get_sheet_type(n) {
19936 if(RELS.WS.indexOf(n) > -1) return "sheet";
19937 if(RELS.CS && n == RELS.CS) return "chart";
19938 if(RELS.DS && n == RELS.DS) return "dialog";
19939 if(RELS.MS && n == RELS.MS) return "macro";
19940 return (n && n.length) ? n : "sheet";
19941}
19942function safe_parse_wbrels(wbrels, sheets) {
19943 if(!wbrels) return 0;
19944 try {
19945 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)]; });
19946 } catch(e) { return null; }
19947 return !wbrels || wbrels.length === 0 ? null : wbrels;
19948}
19949
19950function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
19951 try {
19952 sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
19953 var data = getzipdata(zip, path);
19954 var _ws;
19955 switch(stype) {
19956 case 'sheet': _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19957 case 'chart': _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
19958 if(!_ws || !_ws['!chart']) break;
19959 var dfile = resolve_path(_ws['!chart'].Target, path);
19960 var drelsp = get_rels_path(dfile);
19961 var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
19962 var chartp = resolve_path(draw, dfile);
19963 var crelsp = get_rels_path(chartp);
19964 _ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
19965 break;
19966 case 'macro': _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19967 case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
19968 }
19969 sheets[sheet] = _ws;
19970 } catch(e) { if(opts.WTF) throw e; }
19971}
19972
19973function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
19974
19975function parse_zip(zip, opts) {
19976 make_ssf(SSF);
19977 opts = opts || {};
19978 fix_read_opts(opts);
19979
19980 /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
19981 if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
19982 /* UOC */
19983 if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
19984 /* Numbers */
19985 if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
19986
19987 var entries = zipentries(zip);
19988 var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
19989 var xlsb = false;
19990 var sheets, binname;
19991 if(dir.workbooks.length === 0) {
19992 binname = "xl/workbook.xml";
19993 if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
19994 }
19995 if(dir.workbooks.length === 0) {
19996 binname = "xl/workbook.bin";
19997 if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
19998 dir.workbooks.push(binname);
19999 xlsb = true;
20000 }
20001 if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
20002
20003 var themes = ({});
20004 var styles = ({});
20005 if(!opts.bookSheets && !opts.bookProps) {
20006 strs = [];
20007 if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
20008
20009 if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
20010
20011 if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
20012 }
20013
20014 /*var externbooks = */dir.links.map(function(link) {
20015 return parse_xlink(getzipdata(zip, strip_front_slash(link)), link, opts);
20016 });
20017
20018 var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
20019
20020 var props = {}, propdata = "";
20021
20022 if(dir.coreprops.length) {
20023 propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
20024 if(propdata) props = parse_core_props(propdata);
20025 if(dir.extprops.length !== 0) {
20026 propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
20027 if(propdata) parse_ext_props(propdata, props, opts);
20028 }
20029 }
20030
20031 var custprops = {};
20032 if(!opts.bookSheets || opts.bookProps) {
20033 if (dir.custprops.length !== 0) {
20034 propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
20035 if(propdata) custprops = parse_cust_props(propdata, opts);
20036 }
20037 }
20038
20039 var out = ({});
20040 if(opts.bookSheets || opts.bookProps) {
20041 if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
20042 else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
20043 if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
20044 if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
20045 if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
20046 }
20047 sheets = {};
20048
20049 var deps = {};
20050 if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
20051
20052 var i=0;
20053 var sheetRels = ({});
20054 var path, relsPath;
20055
20056 {
20057 var wbsheets = wb.Sheets;
20058 props.Worksheets = wbsheets.length;
20059 props.SheetNames = [];
20060 for(var j = 0; j != wbsheets.length; ++j) {
20061 props.SheetNames[j] = wbsheets[j].name;
20062 }
20063 }
20064
20065 var wbext = xlsb ? "bin" : "xml";
20066 var wbrelsi = dir.workbooks[0].lastIndexOf("/");
20067 var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
20068 if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
20069 var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
20070 if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
20071
20072 /* Numbers iOS hack */
20073 var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
20074 for(i = 0; i != props.Worksheets; ++i) {
20075 var stype = "sheet";
20076 if(wbrels && wbrels[i]) {
20077 path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
20078 if(!safegetzipfile(zip, path)) path = wbrels[i][1];
20079 if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
20080 stype = wbrels[i][2];
20081 } else {
20082 path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
20083 path = path.replace(/sheet0\./,"sheet.");
20084 }
20085 relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
20086 safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
20087 }
20088
20089 if(dir.comments) parse_comments(zip, dir.comments, sheets, sheetRels, opts);
20090
20091 out = ({
20092 Directory: dir,
20093 Workbook: wb,
20094 Props: props,
20095 Custprops: custprops,
20096 Deps: deps,
20097 Sheets: sheets,
20098 SheetNames: props.SheetNames,
20099 Strings: strs,
20100 Styles: styles,
20101 Themes: themes,
20102 SSF: SSF.get_table()
20103 });
20104 if(opts.bookFiles) {
20105 out.keys = entries;
20106 out.files = zip.files;
20107 }
20108 if(opts.bookVBA) {
20109 if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
20110 else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
20111 }
20112 return out;
20113}
20114
20115/* [MS-OFFCRYPTO] 2.1.1 */
20116function parse_xlsxcfb(cfb, _opts) {
20117 var opts = _opts || {};
20118 var f = 'Workbook', data = CFB.find(cfb, f);
20119 try {
20120 f = '/!DataSpaces/Version';
20121 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20122 /*var version = */parse_DataSpaceVersionInfo(data.content);
20123
20124 /* 2.3.4.1 */
20125 f = '/!DataSpaces/DataSpaceMap';
20126 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20127 var dsm = parse_DataSpaceMap(data.content);
20128 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")
20129 throw new Error("ECMA-376 Encrypted file bad " + f);
20130
20131 /* 2.3.4.2 */
20132 f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
20133 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20134 var seds = parse_DataSpaceDefinition(data.content);
20135 if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
20136 throw new Error("ECMA-376 Encrypted file bad " + f);
20137
20138 /* 2.3.4.3 */
20139 f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
20140 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20141 /*var hdr = */parse_Primary(data.content);
20142 } catch(e) {}
20143
20144 f = '/EncryptionInfo';
20145 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20146 var einfo = parse_EncryptionInfo(data.content);
20147
20148 /* 2.3.4.4 */
20149 f = '/EncryptedPackage';
20150 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20151
20152/*global decrypt_agile */
20153if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
20154/*global decrypt_std76 */
20155if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
20156 throw new Error("File is password-protected");
20157}
20158
20159function write_zip(wb, opts) {
20160 _shapeid = 1024;
20161 if(opts.bookType == "ods") return write_ods(wb, opts);
20162 if(wb && !wb.SSF) {
20163 wb.SSF = SSF.get_table();
20164 }
20165 if(wb && wb.SSF) {
20166 make_ssf(SSF); SSF.load_table(wb.SSF);
20167 // $FlowIgnore
20168 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
20169 opts.ssf = wb.SSF;
20170 }
20171 opts.rels = {}; opts.wbrels = {};
20172 opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
20173 if(browser_has_Map) opts.revStrings = new Map();
20174 else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
20175 var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
20176 var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
20177 var ct = new_ct();
20178 fix_write_opts(opts = opts || {});
20179var zip = new jszip();
20180 var f = "", rId = 0;
20181
20182 opts.cellXfs = [];
20183 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
20184
20185 if(!wb.Props) wb.Props = {};
20186
20187 f = "docProps/core.xml";
20188 zip.file(f, write_core_props(wb.Props, opts));
20189 ct.coreprops.push(f);
20190 add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
20191
20192f = "docProps/app.xml";
20193 if(wb.Props && wb.Props.SheetNames){/* empty */}
20194 else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
20195 else {
20196 var _sn = [];
20197 for(var _i = 0; _i < wb.SheetNames.length; ++_i)
20198 if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
20199 wb.Props.SheetNames = _sn;
20200 }
20201 wb.Props.Worksheets = wb.Props.SheetNames.length;
20202 zip.file(f, write_ext_props(wb.Props, opts));
20203 ct.extprops.push(f);
20204 add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
20205
20206 if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
20207 f = "docProps/custom.xml";
20208 zip.file(f, write_cust_props(wb.Custprops, opts));
20209 ct.custprops.push(f);
20210 add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
20211 }
20212
20213 for(rId=1;rId <= wb.SheetNames.length; ++rId) {
20214 var wsrels = {'!id':{}};
20215 var ws = wb.Sheets[wb.SheetNames[rId-1]];
20216 var _type = (ws || {})["!type"] || "sheet";
20217 switch(_type) {
20218 case "chart": /*
20219 f = "xl/chartsheets/sheet" + rId + "." + wbext;
20220 zip.file(f, write_cs(rId-1, f, opts, wb, wsrels));
20221 ct.charts.push(f);
20222 add_rels(wsrels, -1, "chartsheets/sheet" + rId + "." + wbext, RELS.CS);
20223 break; */
20224 /* falls through */
20225 default:
20226 f = "xl/worksheets/sheet" + rId + "." + wbext;
20227 zip.file(f, write_ws(rId-1, f, opts, wb, wsrels));
20228 ct.sheets.push(f);
20229 add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
20230 }
20231
20232 if(ws) {
20233 var comments = ws['!comments'];
20234 var need_vml = false;
20235 if(comments && comments.length > 0) {
20236 var cf = "xl/comments" + rId + "." + wbext;
20237 zip.file(cf, write_cmnt(comments, cf, opts));
20238 ct.comments.push(cf);
20239 add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
20240 need_vml = true;
20241 }
20242 if(ws['!legacy']) {
20243 if(need_vml) zip.file("xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
20244 }
20245 delete ws['!comments'];
20246 delete ws['!legacy'];
20247 }
20248
20249 if(wsrels['!id'].rId1) zip.file(get_rels_path(f), write_rels(wsrels));
20250 }
20251
20252 if(opts.Strings != null && opts.Strings.length > 0) {
20253 f = "xl/sharedStrings." + wbext;
20254 zip.file(f, write_sst(opts.Strings, f, opts));
20255 ct.strs.push(f);
20256 add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
20257 }
20258
20259 f = "xl/workbook." + wbext;
20260 zip.file(f, write_wb(wb, f, opts));
20261 ct.workbooks.push(f);
20262 add_rels(opts.rels, 1, f, RELS.WB);
20263
20264 /* TODO: something more intelligent with themes */
20265
20266 f = "xl/theme/theme1.xml";
20267 zip.file(f, write_theme(wb.Themes, opts));
20268 ct.themes.push(f);
20269 add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
20270
20271 /* TODO: something more intelligent with styles */
20272
20273 f = "xl/styles." + wbext;
20274 zip.file(f, write_sty(wb, f, opts));
20275 ct.styles.push(f);
20276 add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
20277
20278 if(wb.vbaraw && vbafmt) {
20279 f = "xl/vbaProject.bin";
20280 zip.file(f, wb.vbaraw);
20281 ct.vba.push(f);
20282 add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
20283 }
20284
20285 zip.file("[Content_Types].xml", write_ct(ct, opts));
20286 zip.file('_rels/.rels', write_rels(opts.rels));
20287 zip.file('xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
20288
20289 delete opts.revssf; delete opts.ssf;
20290 return zip;
20291}
20292function firstbyte(f,o) {
20293 var x = "";
20294 switch((o||{}).type || "base64") {
20295 case 'buffer': return [f[0], f[1], f[2], f[3]];
20296 case 'base64': x = Base64.decode(f.slice(0,24)); break;
20297 case 'binary': x = f; break;
20298 case 'array': return [f[0], f[1], f[2], f[3]];
20299 default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
20300 }
20301 return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)];
20302}
20303
20304function read_cfb(cfb, opts) {
20305 if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
20306 return parse_xlscfb(cfb, opts);
20307}
20308
20309function read_zip(data, opts) {
20310var zip, d = data;
20311 var o = opts||{};
20312 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
20313 switch(o.type) {
20314 case "base64": zip = new jszip(d, { base64:true }); break;
20315 case "binary": case "array": zip = new jszip(d, { base64:false }); break;
20316 case "buffer": zip = new jszip(d); break;
20317 default: throw new Error("Unrecognized type " + o.type);
20318 }
20319 return parse_zip(zip, o);
20320}
20321
20322function read_plaintext(data, o) {
20323 var i = 0;
20324 main: while(i < data.length) switch(data.charCodeAt(i)) {
20325 case 0x0A: case 0x0D: case 0x20: ++i; break;
20326 case 0x3C: return parse_xlml(data.slice(i),o);
20327 default: break main;
20328 }
20329 return PRN.to_workbook(data, o);
20330}
20331
20332function read_plaintext_raw(data, o) {
20333 var str = "", bytes = firstbyte(data, o);
20334 switch(o.type) {
20335 case 'base64': str = Base64.decode(data); break;
20336 case 'binary': str = data; break;
20337 case 'buffer': str = data.toString('binary'); break;
20338 case 'array': str = cc2str(data); break;
20339 default: throw new Error("Unrecognized type " + o.type);
20340 }
20341 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
20342 return read_plaintext(str, o);
20343}
20344
20345function read_utf16(data, o) {
20346 var d = data;
20347 if(o.type == 'base64') d = Base64.decode(d);
20348 d = cptable.utils.decode(1200, d.slice(2), 'str');
20349 o.type = "binary";
20350 return read_plaintext(d, o);
20351}
20352
20353function bstrify(data) {
20354 return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
20355}
20356
20357function read_prn(data, d, o, str) {
20358 if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
20359 return PRN.to_workbook(d, o);
20360}
20361
20362function readSync(data, opts) {
20363 reset_cp();
20364 if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
20365 var d = data, n = [0,0,0,0], str = false;
20366 var o = opts||{};
20367 _ssfopts = {};
20368 if(o.dateNF) _ssfopts.dateNF = o.dateNF;
20369 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
20370 if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
20371 if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
20372 if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
20373 // $FlowIgnore
20374 var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
20375 // $FlowIgnore
20376 if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
20377 }
20378 switch((n = firstbyte(d, o))[0]) {
20379 case 0xD0: return read_cfb(CFB.read(d, o), o);
20380 case 0x09: return parse_xlscfb(d, o);
20381 case 0x3C: return parse_xlml(d, o);
20382 case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
20383 case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
20384 case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
20385 case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
20386 case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
20387 case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
20388 case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
20389 case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
20390 case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
20391 }
20392 if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
20393 return read_prn(data, d, o, str);
20394}
20395
20396function readFileSync(filename, opts) {
20397 var o = opts||{}; o.type = 'file';
20398 return readSync(filename, o);
20399}
20400function write_cfb_ctr(cfb, o) {
20401 switch(o.type) {
20402 case "base64": case "binary": break;
20403 case "buffer": case "array": o.type = ""; break;
20404 case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
20405 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
20406 default: throw new Error("Unrecognized type " + o.type);
20407 }
20408 return CFB.write(cfb, o);
20409}
20410
20411/*global encrypt_agile */
20412function write_zip_type(wb, opts) {
20413 var o = opts||{};
20414 var z = write_zip(wb, o);
20415 var oopts = {};
20416 if(o.compression) oopts.compression = 'DEFLATE';
20417 if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
20418 else switch(o.type) {
20419 case "base64": oopts.type = "base64"; break;
20420 case "binary": oopts.type = "string"; break;
20421 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
20422 case "buffer":
20423 case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
20424 default: throw new Error("Unrecognized type " + o.type);
20425 }
20426 var out = z.generate(oopts);
20427 if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o);
20428 if(o.type === "file") return write_dl(o.file, out);
20429 return o.type == "string" ? utf8read(out) : out;
20430}
20431
20432function write_cfb_type(wb, opts) {
20433 var o = opts||{};
20434 var cfb = write_xlscfb(wb, o);
20435 return write_cfb_ctr(cfb, o);
20436}
20437
20438function write_string_type(out, opts, bom) {
20439 if(!bom) bom = "";
20440 var o = bom + out;
20441 switch(opts.type) {
20442 case "base64": return Base64.encode(utf8write(o));
20443 case "binary": return utf8write(o);
20444 case "string": return out;
20445 case "file": return write_dl(opts.file, o, 'utf8');
20446 case "buffer": {
20447 // $FlowIgnore
20448 if(has_buf) return Buffer_from(o, 'utf8');
20449 else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
20450 }
20451 }
20452 throw new Error("Unrecognized type " + opts.type);
20453}
20454
20455function write_stxt_type(out, opts) {
20456 switch(opts.type) {
20457 case "base64": return Base64.encode(out);
20458 case "binary": return out;
20459 case "string": return out; /* override in sheet_to_txt */
20460 case "file": return write_dl(opts.file, out, 'binary');
20461 case "buffer": {
20462 // $FlowIgnore
20463 if(has_buf) return Buffer_from(out, 'binary');
20464 else return out.split("").map(function(c) { return c.charCodeAt(0); });
20465 }
20466 }
20467 throw new Error("Unrecognized type " + opts.type);
20468}
20469
20470/* TODO: test consistency */
20471function write_binary_type(out, opts) {
20472 switch(opts.type) {
20473 case "string":
20474 case "base64":
20475 case "binary":
20476 var bstr = "";
20477 // $FlowIgnore
20478 for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
20479 return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
20480 case "file": return write_dl(opts.file, out);
20481 case "buffer": return out;
20482 default: throw new Error("Unrecognized type " + opts.type);
20483 }
20484}
20485
20486function writeSync(wb, opts) {
20487 check_wb(wb);
20488 var o = opts||{};
20489 if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
20490 switch(o.bookType || 'xlsb') {
20491 case 'xml':
20492 case 'xlml': return write_string_type(write_xlml(wb, o), o);
20493 case 'slk':
20494 case 'sylk': return write_string_type(write_slk_str(wb, o), o);
20495 case 'htm':
20496 case 'html': return write_string_type(write_htm_str(wb, o), o);
20497 case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
20498 case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
20499 case 'dif': return write_string_type(write_dif_str(wb, o), o);
20500 case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
20501 case 'prn': return write_string_type(write_prn_str(wb, o), o);
20502 case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
20503 case 'eth': return write_string_type(write_eth_str(wb, o), o);
20504 case 'fods': return write_string_type(write_ods(wb, o), o);
20505 case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
20506 case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
20507 case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
20508 case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
20509 case 'biff8':
20510 case 'xla':
20511 case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
20512 case 'xlsx':
20513 case 'xlsm':
20514 case 'xlam':
20515 case 'xlsb':
20516 case 'ods': return write_zip_type(wb, o);
20517 default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
20518 }
20519}
20520
20521function resolve_book_type(o) {
20522 if(o.bookType) return;
20523 var _BT = {
20524 "xls": "biff8",
20525 "htm": "html",
20526 "slk": "sylk",
20527 "socialcalc": "eth",
20528 "Sh33tJS": "WTF"
20529 };
20530 var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
20531 if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
20532 o.bookType = _BT[o.bookType] || o.bookType;
20533}
20534
20535function writeFileSync(wb, filename, opts) {
20536 var o = opts||{}; o.type = 'file';
20537 o.file = filename;
20538 resolve_book_type(o);
20539 return writeSync(wb, o);
20540}
20541
20542function writeFileAsync(filename, wb, opts, cb) {
20543 var o = opts||{}; o.type = 'file';
20544 o.file = filename;
20545 resolve_book_type(o);
20546 o.type = 'buffer';
20547 var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
20548 return _fs.writeFile(filename, writeSync(wb, o), _cb);
20549}
20550function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
20551 var rr = encode_row(R);
20552 var defval = o.defval, raw = o.raw || !o.hasOwnProperty("raw");
20553 var isempty = true;
20554 var row = (header === 1) ? [] : {};
20555 if(header !== 1) {
20556 if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
20557 else row.__rowNum__ = R;
20558 }
20559 if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
20560 var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20561 if(val === undefined || val.t === undefined) {
20562 if(defval === undefined) continue;
20563 if(hdr[C] != null) { row[hdr[C]] = defval; }
20564 continue;
20565 }
20566 var v = val.v;
20567 switch(val.t){
20568 case 'z': if(v == null) break; continue;
20569 case 'e': v = void 0; break;
20570 case 's': case 'd': case 'b': case 'n': break;
20571 default: throw new Error('unrecognized type ' + val.t);
20572 }
20573 if(hdr[C] != null) {
20574 if(v == null) {
20575 if(defval !== undefined) row[hdr[C]] = defval;
20576 else if(raw && v === null) row[hdr[C]] = null;
20577 else continue;
20578 } else {
20579 row[hdr[C]] = raw ? v : format_cell(val,v,o);
20580 }
20581 if(v != null) isempty = false;
20582 }
20583 }
20584 return { row: row, isempty: isempty };
20585}
20586
20587
20588function sheet_to_json(sheet, opts) {
20589 if(sheet == null || sheet["!ref"] == null) return [];
20590 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
20591 var r = {s:{r:0,c:0},e:{r:0,c:0}};
20592 var o = opts || {};
20593 var range = o.range != null ? o.range : sheet["!ref"];
20594 if(o.header === 1) header = 1;
20595 else if(o.header === "A") header = 2;
20596 else if(Array.isArray(o.header)) header = 3;
20597 switch(typeof range) {
20598 case 'string': r = safe_decode_range(range); break;
20599 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
20600 default: r = range;
20601 }
20602 if(header > 0) offset = 0;
20603 var rr = encode_row(r.s.r);
20604 var cols = [];
20605 var out = [];
20606 var outi = 0, counter = 0;
20607 var dense = Array.isArray(sheet);
20608 var R = r.s.r, C = 0, CC = 0;
20609 if(dense && !sheet[R]) sheet[R] = [];
20610 for(C = r.s.c; C <= r.e.c; ++C) {
20611 cols[C] = encode_col(C);
20612 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20613 switch(header) {
20614 case 1: hdr[C] = C - r.s.c; break;
20615 case 2: hdr[C] = cols[C]; break;
20616 case 3: hdr[C] = o.header[C - r.s.c]; break;
20617 default:
20618 if(val == null) val = {w: "__EMPTY", t: "s"};
20619 vv = v = format_cell(val, null, o);
20620 counter = 0;
20621 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
20622 hdr[C] = vv;
20623 }
20624 }
20625 for (R = r.s.r + offset; R <= r.e.r; ++R) {
20626 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
20627 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
20628 }
20629 out.length = outi;
20630 return out;
20631}
20632
20633var qreg = /"/g;
20634function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
20635 var isempty = true;
20636 var row = [], txt = "", rr = encode_row(R);
20637 for(var C = r.s.c; C <= r.e.c; ++C) {
20638 if (!cols[C]) continue;
20639 var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
20640 if(val == null) txt = "";
20641 else if(val.v != null) {
20642 isempty = false;
20643 txt = ''+format_cell(val, null, o);
20644 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; }
20645 if(txt == "ID") txt = '"ID"';
20646 } else if(val.f != null && !val.F) {
20647 isempty = false;
20648 txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
20649 } else txt = "";
20650 /* NOTE: Excel CSV does not support array formulae */
20651 row.push(txt);
20652 }
20653 if(o.blankrows === false && isempty) return null;
20654 return row.join(FS);
20655}
20656
20657function sheet_to_csv(sheet, opts) {
20658 var out = [];
20659 var o = opts == null ? {} : opts;
20660 if(sheet == null || sheet["!ref"] == null) return "";
20661 var r = safe_decode_range(sheet["!ref"]);
20662 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
20663 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
20664 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
20665 var row = "", cols = [];
20666 o.dense = Array.isArray(sheet);
20667 var colinfo = o.skipHidden && sheet["!cols"] || [];
20668 var rowinfo = o.skipHidden && sheet["!rows"] || [];
20669 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
20670 for(var R = r.s.r; R <= r.e.r; ++R) {
20671 if ((rowinfo[R]||{}).hidden) continue;
20672 row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
20673 if(row == null) { continue; }
20674 if(o.strip) row = row.replace(endregex,"");
20675 out.push(row + RS);
20676 }
20677 delete o.dense;
20678 return out.join("");
20679}
20680
20681function sheet_to_txt(sheet, opts) {
20682 if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
20683 var s = sheet_to_csv(sheet, opts);
20684 if(typeof cptable == 'undefined' || opts.type == 'string') return s;
20685 var o = cptable.utils.encode(1200, s, 'str');
20686 return String.fromCharCode(255) + String.fromCharCode(254) + o;
20687}
20688
20689function sheet_to_formulae(sheet) {
20690 var y = "", x, val="";
20691 if(sheet == null || sheet["!ref"] == null) return [];
20692 var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
20693 var cmds = [];
20694 var dense = Array.isArray(sheet);
20695 for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
20696 for(var R = r.s.r; R <= r.e.r; ++R) {
20697 rr = encode_row(R);
20698 for(C = r.s.c; C <= r.e.c; ++C) {
20699 y = cols[C] + rr;
20700 x = dense ? (sheet[R]||[])[C] : sheet[y];
20701 val = "";
20702 if(x === undefined) continue;
20703 else if(x.F != null) {
20704 y = x.F;
20705 if(!x.f) continue;
20706 val = x.f;
20707 if(y.indexOf(":") == -1) y = y + ":" + y;
20708 }
20709 if(x.f != null) val = x.f;
20710 else if(x.t == 'z') continue;
20711 else if(x.t == 'n' && x.v != null) val = "" + x.v;
20712 else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
20713 else if(x.w !== undefined) val = "'" + x.w;
20714 else if(x.v === undefined) continue;
20715 else if(x.t == 's') val = "'" + x.v;
20716 else val = ""+x.v;
20717 cmds[cmds.length] = y + "=" + val;
20718 }
20719 }
20720 return cmds;
20721}
20722
20723function sheet_add_json(_ws, js, opts) {
20724 var o = opts || {};
20725 var offset = +!o.skipHeader;
20726 var ws = _ws || ({});
20727 var _R = 0, _C = 0;
20728 if(ws && o.origin != null) {
20729 if(typeof o.origin == 'number') _R = o.origin;
20730 else {
20731 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
20732 _R = _origin.r; _C = _origin.c;
20733 }
20734 }
20735 var cell;
20736 var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
20737 if(ws['!ref']) {
20738 var _range = safe_decode_range(ws['!ref']);
20739 range.e.c = Math.max(range.e.c, _range.e.c);
20740 range.e.r = Math.max(range.e.r, _range.e.r);
20741 if(_R == -1) { _R = range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
20742 }
20743 var hdr = o.header || [], C = 0;
20744
20745 js.forEach(function (JS, R) {
20746 keys(JS).forEach(function(k) {
20747 if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
20748 var v = JS[k];
20749 var t = 'z';
20750 var z = "";
20751 if(v && typeof v === 'object' && !(v instanceof Date)){
20752 ws[encode_cell({c:_C + C,r:_R + R + offset})] = v;
20753 } else {
20754 if(typeof v == 'number') t = 'n';
20755 else if(typeof v == 'boolean') t = 'b';
20756 else if(typeof v == 'string') t = 's';
20757 else if(v instanceof Date) {
20758 t = 'd';
20759 if(!o.cellDates) { t = 'n'; v = datenum(v); }
20760 z = o.dateNF || SSF._table[14];
20761 }
20762 ws[encode_cell({c:_C + C,r:_R + R + offset})] = cell = ({t:t, v:v});
20763 if(z) cell.z = z;
20764 }
20765 });
20766 });
20767 range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
20768 var __R = encode_row(_R);
20769 if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
20770 ws['!ref'] = encode_range(range);
20771 return ws;
20772}
20773function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
20774
20775var utils = {
20776 encode_col: encode_col,
20777 encode_row: encode_row,
20778 encode_cell: encode_cell,
20779 encode_range: encode_range,
20780 decode_col: decode_col,
20781 decode_row: decode_row,
20782 split_cell: split_cell,
20783 decode_cell: decode_cell,
20784 decode_range: decode_range,
20785 format_cell: format_cell,
20786 get_formulae: sheet_to_formulae,
20787 make_csv: sheet_to_csv,
20788 make_json: sheet_to_json,
20789 make_formulae: sheet_to_formulae,
20790 sheet_add_aoa: sheet_add_aoa,
20791 sheet_add_json: sheet_add_json,
20792 aoa_to_sheet: aoa_to_sheet,
20793 json_to_sheet: json_to_sheet,
20794 table_to_sheet: parse_dom_table,
20795 table_to_book: table_to_book,
20796 sheet_to_csv: sheet_to_csv,
20797 sheet_to_txt: sheet_to_txt,
20798 sheet_to_json: sheet_to_json,
20799 sheet_to_html: HTML_.from_sheet,
20800 sheet_to_dif: DIF.from_sheet,
20801 sheet_to_slk: SYLK.from_sheet,
20802 sheet_to_eth: ETH.from_sheet,
20803 sheet_to_formulae: sheet_to_formulae,
20804 sheet_to_row_object_array: sheet_to_json
20805};
20806
20807(function(utils) {
20808utils.consts = utils.consts || {};
20809function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
20810
20811function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
20812
20813/* get cell, creating a stub if necessary */
20814function ws_get_cell_stub(ws, R, C) {
20815 /* A1 cell address */
20816 if(typeof R == "string") return ws[R] || (ws[R] = {t:'z'});
20817 /* cell address object */
20818 if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
20819 /* R and C are 0-based indices */
20820 return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
20821}
20822
20823/* find sheet index for given name / validate index */
20824function wb_sheet_idx(wb, sh) {
20825 if(typeof sh == "number") {
20826 if(sh >= 0 && wb.SheetNames.length > sh) return sh;
20827 throw new Error("Cannot find sheet # " + sh);
20828 } else if(typeof sh == "string") {
20829 var idx = wb.SheetNames.indexOf(sh);
20830 if(idx > -1) return idx;
20831 throw new Error("Cannot find sheet name |" + sh + "|");
20832 } else throw new Error("Cannot find sheet |" + sh + "|");
20833}
20834
20835/* simple blank workbook object */
20836utils.book_new = function() {
20837 return { SheetNames: [], Sheets: {} };
20838};
20839
20840/* add a worksheet to the end of a given workbook */
20841utils.book_append_sheet = function(wb, ws, name) {
20842 if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
20843 if(!name) throw new Error("Too many worksheets");
20844 check_ws_name(name);
20845 if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
20846
20847 wb.SheetNames.push(name);
20848 wb.Sheets[name] = ws;
20849};
20850
20851/* set sheet visibility (visible/hidden/very hidden) */
20852utils.book_set_sheet_visibility = function(wb, sh, vis) {
20853 get_default(wb,"Workbook",{});
20854 get_default(wb.Workbook,"Sheets",[]);
20855
20856 var idx = wb_sheet_idx(wb, sh);
20857 // $FlowIgnore
20858 get_default(wb.Workbook.Sheets,idx, {});
20859
20860 switch(vis) {
20861 case 0: case 1: case 2: break;
20862 default: throw new Error("Bad sheet visibility setting " + vis);
20863 }
20864 // $FlowIgnore
20865 wb.Workbook.Sheets[idx].Hidden = vis;
20866};
20867add_consts([
20868 ["SHEET_VISIBLE", 0],
20869 ["SHEET_HIDDEN", 1],
20870 ["SHEET_VERY_HIDDEN", 2]
20871]);
20872
20873/* set number format */
20874utils.cell_set_number_format = function(cell, fmt) {
20875 cell.z = fmt;
20876 return cell;
20877};
20878
20879/* set cell hyperlink */
20880utils.cell_set_hyperlink = function(cell, target, tooltip) {
20881 if(!target) {
20882 delete cell.l;
20883 } else {
20884 cell.l = ({ Target: target });
20885 if(tooltip) cell.l.Tooltip = tooltip;
20886 }
20887 return cell;
20888};
20889utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
20890
20891/* add to cell comments */
20892utils.cell_add_comment = function(cell, text, author) {
20893 if(!cell.c) cell.c = [];
20894 cell.c.push({t:text, a:author||"SheetJS"});
20895};
20896
20897/* set array formula and flush related cells */
20898utils.sheet_set_array_formula = function(ws, range, formula) {
20899 var rng = typeof range != "string" ? range : safe_decode_range(range);
20900 var rngstr = typeof range == "string" ? range : encode_range(range);
20901 for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
20902 var cell = ws_get_cell_stub(ws, R, C);
20903 cell.t = 'n';
20904 cell.F = rngstr;
20905 delete cell.v;
20906 if(R == rng.s.r && C == rng.s.c) cell.f = formula;
20907 }
20908 return ws;
20909};
20910
20911return utils;
20912})(utils);
20913
20914if(has_buf && typeof require != 'undefined') (function() {
20915 var Readable = require('stream').Readable;
20916
20917 var write_csv_stream = function(sheet, opts) {
20918 var stream = Readable();
20919 var o = opts == null ? {} : opts;
20920 if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
20921 var r = safe_decode_range(sheet["!ref"]);
20922 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
20923 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
20924 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
20925 var row = "", cols = [];
20926 o.dense = Array.isArray(sheet);
20927 var colinfo = o.skipHidden && sheet["!cols"] || [];
20928 var rowinfo = o.skipHidden && sheet["!rows"] || [];
20929 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
20930 var R = r.s.r;
20931 var BOM = false;
20932 stream._read = function() {
20933 if(!BOM) { BOM = true; return stream.push("\uFEFF"); }
20934 while(R <= r.e.r) {
20935 ++R;
20936 if ((rowinfo[R-1]||{}).hidden) continue;
20937 row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o);
20938 if(row != null) {
20939 if(o.strip) row = row.replace(endregex,"");
20940 stream.push(row + RS);
20941 break;
20942 }
20943 }
20944 if(R > r.e.r) return stream.push(null);
20945 };
20946 return stream;
20947 };
20948
20949 var write_html_stream = function(ws, opts) {
20950 var stream = Readable();
20951
20952 var o = opts || {};
20953 var header = o.header != null ? o.header : HTML_.BEGIN;
20954 var footer = o.footer != null ? o.footer : HTML_.END;
20955 stream.push(header);
20956 var r = decode_range(ws['!ref']);
20957 o.dense = Array.isArray(ws);
20958 stream.push(HTML_._preamble(ws, r, o));
20959 var R = r.s.r;
20960 var end = false;
20961 stream._read = function() {
20962 if(R > r.e.r) {
20963 if(!end) { end = true; stream.push("</table>" + footer); }
20964 return stream.push(null);
20965 }
20966 while(R <= r.e.r) {
20967 stream.push(HTML_._row(ws, r, R, o));
20968 ++R;
20969 break;
20970 }
20971 };
20972 return stream;
20973 };
20974
20975 var write_json_stream = function(sheet, opts) {
20976 var stream = Readable({objectMode:true});
20977
20978 if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
20979 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
20980 var r = {s:{r:0,c:0},e:{r:0,c:0}};
20981 var o = opts || {};
20982 var range = o.range != null ? o.range : sheet["!ref"];
20983 if(o.header === 1) header = 1;
20984 else if(o.header === "A") header = 2;
20985 else if(Array.isArray(o.header)) header = 3;
20986 switch(typeof range) {
20987 case 'string': r = safe_decode_range(range); break;
20988 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
20989 default: r = range;
20990 }
20991 if(header > 0) offset = 0;
20992 var rr = encode_row(r.s.r);
20993 var cols = [];
20994 var counter = 0;
20995 var dense = Array.isArray(sheet);
20996 var R = r.s.r, C = 0, CC = 0;
20997 if(dense && !sheet[R]) sheet[R] = [];
20998 for(C = r.s.c; C <= r.e.c; ++C) {
20999 cols[C] = encode_col(C);
21000 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
21001 switch(header) {
21002 case 1: hdr[C] = C - r.s.c; break;
21003 case 2: hdr[C] = cols[C]; break;
21004 case 3: hdr[C] = o.header[C - r.s.c]; break;
21005 default:
21006 if(val == null) val = {w: "__EMPTY", t: "s"};
21007 vv = v = format_cell(val, null, o);
21008 counter = 0;
21009 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
21010 hdr[C] = vv;
21011 }
21012 }
21013 R = r.s.r + offset;
21014 stream._read = function() {
21015 if(R > r.e.r) return stream.push(null);
21016 while(R <= r.e.r) {
21017 //if ((rowinfo[R-1]||{}).hidden) continue;
21018 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
21019 ++R;
21020 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
21021 stream.push(row.row);
21022 break;
21023 }
21024 }
21025 };
21026 return stream;
21027 };
21028
21029 XLSX.stream = {
21030 to_json: write_json_stream,
21031 to_html: write_html_stream,
21032 to_csv: write_csv_stream
21033 };
21034})();
21035
21036XLSX.parse_xlscfb = parse_xlscfb;
21037XLSX.parse_ods = parse_ods;
21038XLSX.parse_fods = parse_fods;
21039XLSX.write_ods = write_ods;
21040XLSX.parse_zip = parse_zip;
21041XLSX.read = readSync; //xlsread
21042XLSX.readFile = readFileSync; //readFile
21043XLSX.readFileSync = readFileSync;
21044XLSX.write = writeSync;
21045XLSX.writeFile = writeFileSync;
21046XLSX.writeFileSync = writeFileSync;
21047XLSX.writeFileAsync = writeFileAsync;
21048XLSX.utils = utils;
21049XLSX.SSF = SSF;
21050XLSX.CFB = CFB;
21051}
21052/*global define */
21053if(typeof exports !== 'undefined') make_xlsx_lib(exports);
21054else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
21055else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
21056else make_xlsx_lib(XLSX);
21057/*exported XLS, ODS */
21058var XLS = XLSX, ODS = XLSX;