UNPKG

714 kBJavaScriptView Raw
1/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
2/* vim: set ts=2: */
3/*exported XLSX */
4/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
5var XLSX = {};
6function make_xlsx_lib(XLSX){
7XLSX.version = '0.15.6';
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 if(has_buf) return Buffer_from(s, "binary");
160 return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
161};
162
163function s2ab(s) {
164 if(typeof ArrayBuffer === 'undefined') return s2a(s);
165 var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
166 for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
167 return buf;
168}
169
170function a2s(data) {
171 if(Array.isArray(data)) return data.map(function(c) { return String.fromCharCode(c); }).join("");
172 var o = []; for(var i = 0; i < data.length; ++i) o[i] = String.fromCharCode(data[i]); return o.join("");
173}
174
175function a2u(data) {
176 if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
177 return new Uint8Array(data);
178}
179
180function ab2a(data) {
181 if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
182 if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
183var o = new Array(data.length);
184 for(var i = 0; i < data.length; ++i) o[i] = data[i];
185 return o;
186}
187
188var bconcat = function(bufs) { return [].concat.apply([], bufs); };
189
190var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
191/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
192/*jshint -W041 */
193var SSF = ({});
194var make_ssf = function make_ssf(SSF){
195SSF.version = '0.10.3';
196function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
197function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
198function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
199function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
200function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
201function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
202function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
203var p2_32 = Math.pow(2,32);
204function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
205function isgeneral(s, i) { i = i || 0; return s.length >= 7 + i && (s.charCodeAt(i)|32) === 103 && (s.charCodeAt(i+1)|32) === 101 && (s.charCodeAt(i+2)|32) === 110 && (s.charCodeAt(i+3)|32) === 101 && (s.charCodeAt(i+4)|32) === 114 && (s.charCodeAt(i+5)|32) === 97 && (s.charCodeAt(i+6)|32) === 108; }
206var days = [
207 ['Sun', 'Sunday'],
208 ['Mon', 'Monday'],
209 ['Tue', 'Tuesday'],
210 ['Wed', 'Wednesday'],
211 ['Thu', 'Thursday'],
212 ['Fri', 'Friday'],
213 ['Sat', 'Saturday']
214];
215var months = [
216 ['J', 'Jan', 'January'],
217 ['F', 'Feb', 'February'],
218 ['M', 'Mar', 'March'],
219 ['A', 'Apr', 'April'],
220 ['M', 'May', 'May'],
221 ['J', 'Jun', 'June'],
222 ['J', 'Jul', 'July'],
223 ['A', 'Aug', 'August'],
224 ['S', 'Sep', 'September'],
225 ['O', 'Oct', 'October'],
226 ['N', 'Nov', 'November'],
227 ['D', 'Dec', 'December']
228];
229function init_table(t) {
230 t[0]= 'General';
231 t[1]= '0';
232 t[2]= '0.00';
233 t[3]= '#,##0';
234 t[4]= '#,##0.00';
235 t[9]= '0%';
236 t[10]= '0.00%';
237 t[11]= '0.00E+00';
238 t[12]= '# ?/?';
239 t[13]= '# ??/??';
240 t[14]= 'm/d/yy';
241 t[15]= 'd-mmm-yy';
242 t[16]= 'd-mmm';
243 t[17]= 'mmm-yy';
244 t[18]= 'h:mm AM/PM';
245 t[19]= 'h:mm:ss AM/PM';
246 t[20]= 'h:mm';
247 t[21]= 'h:mm:ss';
248 t[22]= 'm/d/yy h:mm';
249 t[37]= '#,##0 ;(#,##0)';
250 t[38]= '#,##0 ;[Red](#,##0)';
251 t[39]= '#,##0.00;(#,##0.00)';
252 t[40]= '#,##0.00;[Red](#,##0.00)';
253 t[45]= 'mm:ss';
254 t[46]= '[h]:mm:ss';
255 t[47]= 'mmss.0';
256 t[48]= '##0.0E+0';
257 t[49]= '@';
258 t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
259 t[65535]= 'General';
260}
261
262var table_fmt = {};
263init_table(table_fmt);
264function frac(x, D, mixed) {
265 var sgn = x < 0 ? -1 : 1;
266 var B = x * sgn;
267 var P_2 = 0, P_1 = 1, P = 0;
268 var Q_2 = 1, Q_1 = 0, Q = 0;
269 var A = Math.floor(B);
270 while(Q_1 < D) {
271 A = Math.floor(B);
272 P = A * P_1 + P_2;
273 Q = A * Q_1 + Q_2;
274 if((B - A) < 0.00000005) break;
275 B = 1 / (B - A);
276 P_2 = P_1; P_1 = P;
277 Q_2 = Q_1; Q_1 = Q;
278 }
279 if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
280 if(!mixed) return [0, sgn * P, Q];
281 var q = Math.floor(sgn * P/Q);
282 return [q, sgn*P - q*Q, Q];
283}
284function parse_date_code(v,opts,b2) {
285 if(v > 2958465 || v < 0) return null;
286 var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
287 var dout=[];
288 var out={D:date, T:time, u:86400*(v-date)-time,y:0,m:0,d:0,H:0,M:0,S:0,q:0};
289 if(Math.abs(out.u) < 1e-6) out.u = 0;
290 if(opts && opts.date1904) date += 1462;
291 if(out.u > 0.9999) {
292 out.u = 0;
293 if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
294 }
295 if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
296 else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
297 else {
298 if(date > 60) --date;
299 /* 1 = Jan 1 1900 in Gregorian */
300 var d = new Date(1900, 0, 1);
301 d.setDate(d.getDate() + date - 1);
302 dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
303 dow = d.getDay();
304 if(date < 60) dow = (dow + 6) % 7;
305 if(b2) dow = fix_hijri(d, dout);
306 }
307 out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
308 out.S = time % 60; time = Math.floor(time / 60);
309 out.M = time % 60; time = Math.floor(time / 60);
310 out.H = time;
311 out.q = dow;
312 return out;
313}
314SSF.parse_date_code = parse_date_code;
315var basedate = new Date(1899, 11, 31, 0, 0, 0);
316var dnthresh = basedate.getTime();
317var base1904 = new Date(1900, 2, 1, 0, 0, 0);
318function datenum_local(v, date1904) {
319 var epoch = v.getTime();
320 if(date1904) epoch -= 1461*24*60*60*1000;
321 else if(v >= base1904) epoch += 24*60*60*1000;
322 return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
323}
324function general_fmt_int(v) { return v.toString(10); }
325SSF._general_int = general_fmt_int;
326var general_fmt_num = (function make_general_fmt_num() {
327var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
328function gfn2(v) {
329 var w = (v<0?12:11);
330 var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
331 o = v.toPrecision(10); if(o.length <= w) return o;
332 return v.toExponential(5);
333}
334function gfn3(v) {
335 var o = v.toFixed(11).replace(gnr1,".$1");
336 if(o.length > (v<0?12:11)) o = v.toPrecision(6);
337 return o;
338}
339function gfn4(o) {
340 for(var i = 0; i != o.length; ++i) if((o.charCodeAt(i) | 0x20) === 101) return o.replace(gnr4,".$1").replace(gnr5,"E").replace("e","E").replace(gnr6,"$10$2");
341 return o;
342}
343function gfn5(o) {
344 return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
345}
346return function general_fmt_num(v) {
347 var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
348 if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
349 else if(Math.abs(V) <= 9) o = gfn2(v);
350 else if(V === 10) o = v.toFixed(10).substr(0,12);
351 else o = gfn3(v);
352 return gfn5(gfn4(o));
353};})();
354SSF._general_num = general_fmt_num;
355function general_fmt(v, opts) {
356 switch(typeof v) {
357 case 'string': return v;
358 case 'boolean': return v ? "TRUE" : "FALSE";
359 case 'number': return (v|0) === v ? v.toString(10) : general_fmt_num(v);
360 case 'undefined': return "";
361 case 'object':
362 if(v == null) return "";
363 if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
364 }
365 throw new Error("unsupported value in General format: " + v);
366}
367SSF._general = general_fmt;
368function fix_hijri() { return 0; }
369/*jshint -W086 */
370function write_date(type, fmt, val, ss0) {
371 var o="", ss=0, tt=0, y = val.y, out, outl = 0;
372 switch(type) {
373 case 98: /* 'b' buddhist year */
374 y = val.y + 543;
375 /* falls through */
376 case 121: /* 'y' year */
377 switch(fmt.length) {
378 case 1: case 2: out = y % 100; outl = 2; break;
379 default: out = y % 10000; outl = 4; break;
380 } break;
381 case 109: /* 'm' month */
382 switch(fmt.length) {
383 case 1: case 2: out = val.m; outl = fmt.length; break;
384 case 3: return months[val.m-1][1];
385 case 5: return months[val.m-1][0];
386 default: return months[val.m-1][2];
387 } break;
388 case 100: /* 'd' day */
389 switch(fmt.length) {
390 case 1: case 2: out = val.d; outl = fmt.length; break;
391 case 3: return days[val.q][0];
392 default: return days[val.q][1];
393 } break;
394 case 104: /* 'h' 12-hour */
395 switch(fmt.length) {
396 case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
397 default: throw 'bad hour format: ' + fmt;
398 } break;
399 case 72: /* 'H' 24-hour */
400 switch(fmt.length) {
401 case 1: case 2: out = val.H; outl = fmt.length; break;
402 default: throw 'bad hour format: ' + fmt;
403 } break;
404 case 77: /* 'M' minutes */
405 switch(fmt.length) {
406 case 1: case 2: out = val.M; outl = fmt.length; break;
407 default: throw 'bad minute format: ' + fmt;
408 } break;
409 case 115: /* 's' seconds */
410 if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
411 if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
412if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
413 else tt = ss0 === 1 ? 10 : 1;
414 ss = Math.round((tt)*(val.S + val.u));
415 if(ss >= 60*tt) ss = 0;
416 if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
417 o = pad0(ss,2 + ss0);
418 if(fmt === 'ss') return o.substr(0,2);
419 return "." + o.substr(2,fmt.length-1);
420 case 90: /* 'Z' absolute time */
421 switch(fmt) {
422 case '[h]': case '[hh]': out = val.D*24+val.H; break;
423 case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
424 case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
425 default: throw 'bad abstime format: ' + fmt;
426 } outl = fmt.length === 3 ? 1 : 2; break;
427 case 101: /* 'e' era */
428 out = y; outl = 1;
429 }
430 if(outl > 0) return pad0(out, outl); else return "";
431}
432/*jshint +W086 */
433function commaify(s) {
434 var w = 3;
435 if(s.length <= w) return s;
436 var j = (s.length % w), o = s.substr(0,j);
437 for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
438 return o;
439}
440var write_num = (function make_write_num(){
441var pct1 = /%/g;
442function write_num_pct(type, fmt, val){
443 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
444 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
445}
446function write_num_cm(type, fmt, val){
447 var idx = fmt.length - 1;
448 while(fmt.charCodeAt(idx-1) === 44) --idx;
449 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
450}
451function write_num_exp(fmt, val){
452 var o;
453 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
454 if(fmt.match(/^#+0.0E\+0$/)) {
455 if(val == 0) return "0.0E+0";
456 else if(val < 0) return "-" + write_num_exp(fmt, -val);
457 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
458 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
459 if(ee < 0) ee += period;
460 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
461 if(o.indexOf("e") === -1) {
462 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
463 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
464 else o += "E+" + (fakee - ee);
465 while(o.substr(0,2) === "0.") {
466 o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
467 o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
468 }
469 o = o.replace(/\+-/,"-");
470 }
471 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
472 } else o = val.toExponential(idx);
473 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
474 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
475 return o.replace("e","E");
476}
477var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
478function write_num_f1(r, aval, sign) {
479 var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
480 var myn = (rr - base*den), myd = den;
481 return sign + (base === 0 ? "" : ""+base) + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad_(myn,r[1].length) + r[2] + "/" + r[3] + pad0(myd,r[4].length));
482}
483function write_num_f2(r, aval, sign) {
484 return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
485}
486var dec1 = /^#*0*\.([0#]+)/;
487var closeparen = /\).*[0#]/;
488var phone = /\(###\) ###\\?-####/;
489function hashq(str) {
490 var o = "", cc;
491 for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
492 case 35: break;
493 case 63: o+= " "; break;
494 case 48: o+= "0"; break;
495 default: o+= String.fromCharCode(cc);
496 }
497 return o;
498}
499function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
500function dec(val, d) {
501 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
502 return 0;
503 }
504 return Math.round((val-Math.floor(val))*Math.pow(10,d));
505}
506function carry(val, d) {
507 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
508 return 1;
509 }
510 return 0;
511}
512function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
513function write_num_flt(type, fmt, val) {
514 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
515 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
516 if(val >= 0) return write_num_flt('n', ffmt, val);
517 return '(' + write_num_flt('n', ffmt, -val) + ')';
518 }
519 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
520 if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
521 if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
522 if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
523 var o;
524 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
525 if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
526 if(fmt.match(/^[#?]+$/)) {
527 o = pad0r(val,0); if(o === "0") o = "";
528 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
529 }
530 if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
531 if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
532 if((r = fmt.match(dec1))) {
533 o = rnd(val, r[1].length).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1])).replace(/\.(\d*)$/,function($$, $1) { return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
534 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
535 }
536 fmt = fmt.replace(/^#+([0.])/, "$1");
537 if((r = fmt.match(/^(0*)\.(#*)$/))) {
538 return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
539 }
540 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
541 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
542 return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(""+(Math.floor(val) + carry(val, r[1].length))) + "." + pad0(dec(val, r[1].length),r[1].length);
543 }
544 if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
545 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
546 o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
547 ri = 0;
548 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
549 }
550 if(fmt.match(phone)) {
551 o = write_num_flt(type, "##########", val);
552 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
553 }
554 var oa = "";
555 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
556 ri = Math.min(r[4].length,7);
557 ff = frac(aval, Math.pow(10,ri)-1, false);
558 o = "" + sign;
559 oa = write_num("n", r[1], ff[1]);
560 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
561 o += oa + r[2] + "/" + r[3];
562 oa = rpad_(ff[2],ri);
563 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
564 o += oa;
565 return o;
566 }
567 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
568 ri = Math.min(Math.max(r[1].length, r[4].length),7);
569 ff = frac(aval, Math.pow(10,ri)-1, true);
570 return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
571 }
572 if((r = fmt.match(/^[#0?]+$/))) {
573 o = pad0r(val, 0);
574 if(fmt.length <= o.length) return o;
575 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
576 }
577 if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
578 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
579 ri = o.indexOf(".");
580 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
581 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
582 }
583 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
584 ri = dec(val, r[1].length);
585 return val < 0 ? "-" + write_num_flt(type, fmt, -val) : commaify(flr(val)).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(ri,r[1].length);
586 }
587 switch(fmt) {
588 case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
589 case "###,###":
590 case "##,###":
591 case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
592 case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
593 case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
594 default:
595 }
596 throw new Error("unsupported format |" + fmt + "|");
597}
598function write_num_cm2(type, fmt, val){
599 var idx = fmt.length - 1;
600 while(fmt.charCodeAt(idx-1) === 44) --idx;
601 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
602}
603function write_num_pct2(type, fmt, val){
604 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
605 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
606}
607function write_num_exp2(fmt, val){
608 var o;
609 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
610 if(fmt.match(/^#+0.0E\+0$/)) {
611 if(val == 0) return "0.0E+0";
612 else if(val < 0) return "-" + write_num_exp2(fmt, -val);
613 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
614 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
615 if(ee < 0) ee += period;
616 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
617 if(!o.match(/[Ee]/)) {
618 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
619 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
620 else o += "E+" + (fakee - ee);
621 o = o.replace(/\+-/,"-");
622 }
623 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
624 } else o = val.toExponential(idx);
625 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
626 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
627 return o.replace("e","E");
628}
629function write_num_int(type, fmt, val) {
630 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
631 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
632 if(val >= 0) return write_num_int('n', ffmt, val);
633 return '(' + write_num_int('n', ffmt, -val) + ')';
634 }
635 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
636 if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
637 if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
638 if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
639 var o;
640 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
641 if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
642 if(fmt.match(/^[#?]+$/)) {
643 o = (""+val); if(val === 0) o = "";
644 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
645 }
646 if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
647 if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
648 if((r = fmt.match(dec1))) {
649o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
650 o = o.replace(/\.(\d*)$/,function($$, $1) {
651return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
652 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
653 }
654 fmt = fmt.replace(/^#+([0.])/, "$1");
655 if((r = fmt.match(/^(0*)\.(#*)$/))) {
656 return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
657 }
658 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
659 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
660 return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
661 }
662 if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
663 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
664 o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
665 ri = 0;
666 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
667 }
668 if(fmt.match(phone)) {
669 o = write_num_int(type, "##########", val);
670 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
671 }
672 var oa = "";
673 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
674 ri = Math.min(r[4].length,7);
675 ff = frac(aval, Math.pow(10,ri)-1, false);
676 o = "" + sign;
677 oa = write_num("n", r[1], ff[1]);
678 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
679 o += oa + r[2] + "/" + r[3];
680 oa = rpad_(ff[2],ri);
681 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
682 o += oa;
683 return o;
684 }
685 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
686 ri = Math.min(Math.max(r[1].length, r[4].length),7);
687 ff = frac(aval, Math.pow(10,ri)-1, true);
688 return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad_(ff[1],ri) + r[2] + "/" + r[3] + rpad_(ff[2],ri): fill(" ", 2*ri+1 + r[2].length + r[3].length));
689 }
690 if((r = fmt.match(/^[#0?]+$/))) {
691 o = "" + val;
692 if(fmt.length <= o.length) return o;
693 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
694 }
695 if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
696 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
697 ri = o.indexOf(".");
698 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
699 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
700 }
701 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
702 return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify(""+val).replace(/^\d,\d{3}$/,"0$&").replace(/^\d*$/,function($$) { return "00," + ($$.length < 3 ? pad0(0,3-$$.length) : "") + $$; }) + "." + pad0(0,r[1].length);
703 }
704 switch(fmt) {
705 case "###,###":
706 case "##,###":
707 case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
708 default:
709 if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
710 }
711 throw new Error("unsupported format |" + fmt + "|");
712}
713return function write_num(type, fmt, val) {
714 return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
715};})();
716function split_fmt(fmt) {
717 var out = [];
718 var in_str = false/*, cc*/;
719 for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
720 case 34: /* '"' */
721 in_str = !in_str; break;
722 case 95: case 42: case 92: /* '_' '*' '\\' */
723 ++i; break;
724 case 59: /* ';' */
725 out[out.length] = fmt.substr(j,i-j);
726 j = i+1;
727 }
728 out[out.length] = fmt.substr(j);
729 if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
730 return out;
731}
732SSF._split = split_fmt;
733var abstime = /\[[HhMmSs]*\]/;
734function fmt_is_date(fmt) {
735 var i = 0, /*cc = 0,*/ c = "", o = "";
736 while(i < fmt.length) {
737 switch((c = fmt.charAt(i))) {
738 case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
739 case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;){/*empty*/} ++i; break;
740 case '\\': i+=2; break;
741 case '_': i+=2; break;
742 case '@': ++i; break;
743 case 'B': case 'b':
744 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
745 /* falls through */
746 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
747 /* falls through */
748 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
749 case 'A': case 'a':
750 if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
751 if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
752 ++i; break;
753 case '[':
754 o = c;
755 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
756 if(o.match(abstime)) return true;
757 break;
758 case '.':
759 /* falls through */
760 case '0': case '#':
761 while(i < fmt.length && ("0#?.,E+-%".indexOf(c=fmt.charAt(++i)) > -1 || (c=='\\' && fmt.charAt(i+1) == "-" && "0#".indexOf(fmt.charAt(i+2))>-1))){/* empty */}
762 break;
763 case '?': while(fmt.charAt(++i) === c){/* empty */} break;
764 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
765 case '(': case ')': ++i; break;
766 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
767 while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
768 case ' ': ++i; break;
769 default: ++i; break;
770 }
771 }
772 return false;
773}
774SSF.is_date = fmt_is_date;
775function eval_fmt(fmt, v, opts, flen) {
776 var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
777 var hr='H';
778 /* Tokenize */
779 while(i < fmt.length) {
780 switch((c = fmt.charAt(i))) {
781 case 'G': /* General */
782 if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
783 out[out.length] = {t:'G', v:'General'}; i+=7; break;
784 case '"': /* Literal text */
785 for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
786 out[out.length] = {t:'t', v:o}; ++i; break;
787 case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
788 out[out.length] = {t:t, v:w}; ++i; break;
789 case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
790 case '@': /* Text Placeholder */
791 out[out.length] = {t:'T', v:v}; ++i; break;
792 case 'B': case 'b':
793 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
794 if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
795 out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
796 }
797 /* falls through */
798 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
799 c = c.toLowerCase();
800 /* falls through */
801 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
802 if(v < 0) return "";
803 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
804 o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
805 if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
806 if(c === 'h') c = hr;
807 out[out.length] = {t:c, v:o}; lst = c; break;
808 case 'A': case 'a':
809 var q={t:c, v:c};
810 if(dt==null) dt=parse_date_code(v, opts);
811 if(fmt.substr(i, 3).toUpperCase() === "A/P") { if(dt!=null) q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
812 else if(fmt.substr(i,5).toUpperCase() === "AM/PM") { if(dt!=null) q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
813 else { q.t = "t"; ++i; }
814 if(dt==null && q.t === 'T') return "";
815 out[out.length] = q; lst = c; break;
816 case '[':
817 o = c;
818 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
819 if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
820 if(o.match(abstime)) {
821 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
822 out[out.length] = {t:'Z', v:o.toLowerCase()};
823 lst = o.charAt(1);
824 } else if(o.indexOf("$") > -1) {
825 o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
826 if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
827 }
828 break;
829 /* Numbers */
830 case '.':
831 if(dt != null) {
832 o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
833 out[out.length] = {t:'s', v:o}; break;
834 }
835 /* falls through */
836 case '0': case '#':
837 o = c; while((++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) || (c=='\\' && fmt.charAt(i+1) == "-" && i < fmt.length - 2 && "0#".indexOf(fmt.charAt(i+2))>-1)) o += c;
838 out[out.length] = {t:'n', v:o}; break;
839 case '?':
840 o = c; while(fmt.charAt(++i) === c) o+=c;
841 out[out.length] = {t:c, v:o}; lst = c; break;
842 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
843 case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
844 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
845 o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
846 out[out.length] = {t:'D', v:o}; break;
847 case ' ': out[out.length] = {t:c, v:c}; ++i; break;
848 case "$": out[out.length] = {t:'t', v:'$'}; ++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 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.4';
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 var seen = [];
1585 for(j=k; j>=0;) {
1586 seen[j] = true;
1587 chkd[j] = true;
1588 buf[buf.length] = j;
1589 buf_chain.push(sectors[j]);
1590 var addr = fat_addrs[Math.floor(j*4/ssz)];
1591 jj = ((j*4) & modulus);
1592 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1593 if(!sectors[addr]) break;
1594 j = __readInt32LE(sectors[addr], jj);
1595 if(seen[j]) break;
1596 }
1597 sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
1598 }
1599 return sector_list;
1600}
1601
1602/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1603function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {
1604 var minifat_store = 0, pl = (Paths.length?2:0);
1605 var sector = sector_list[dir_start].data;
1606 var i = 0, namelen = 0, name;
1607 for(; i < sector.length; i+= 128) {
1608 var blob = sector.slice(i, i+128);
1609 prep_blob(blob, 64);
1610 namelen = blob.read_shift(2);
1611 name = __utf16le(blob,0,namelen-pl);
1612 Paths.push(name);
1613 var o = ({
1614 name: name,
1615 type: blob.read_shift(1),
1616 color: blob.read_shift(1),
1617 L: blob.read_shift(4, 'i'),
1618 R: blob.read_shift(4, 'i'),
1619 C: blob.read_shift(4, 'i'),
1620 clsid: blob.read_shift(16),
1621 state: blob.read_shift(4, 'i'),
1622 start: 0,
1623 size: 0
1624 });
1625 var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1626 if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1627 var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1628 if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1629 o.start = blob.read_shift(4, 'i');
1630 o.size = blob.read_shift(4, 'i');
1631 if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1632 if(o.type === 5) { /* root */
1633 minifat_store = o.start;
1634 if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1635 /*minifat_size = o.size;*/
1636 } else if(o.size >= 4096 /* MSCSZ */) {
1637 o.storage = 'fat';
1638 if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1639 sector_list[o.start].name = o.name;
1640 o.content = (sector_list[o.start].data.slice(0,o.size));
1641 } else {
1642 o.storage = 'minifat';
1643 if(o.size < 0) o.size = 0;
1644 else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1645 o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1646 }
1647 }
1648 if(o.content) prep_blob(o.content, 0);
1649 files[name] = o;
1650 FileIndex.push(o);
1651 }
1652}
1653
1654function read_date(blob, offset) {
1655 return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1656}
1657
1658function read_file(filename, options) {
1659 get_fs();
1660 return parse(fs.readFileSync(filename), options);
1661}
1662
1663function read(blob, options) {
1664 switch(options && options.type || "base64") {
1665 case "file": return read_file(blob, options);
1666 case "base64": return parse(s2a(Base64.decode(blob)), options);
1667 case "binary": return parse(s2a(blob), options);
1668 }
1669 return parse(blob, options);
1670}
1671
1672function init_cfb(cfb, opts) {
1673 var o = opts || {}, root = o.root || "Root Entry";
1674 if(!cfb.FullPaths) cfb.FullPaths = [];
1675 if(!cfb.FileIndex) cfb.FileIndex = [];
1676 if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1677 if(cfb.FullPaths.length === 0) {
1678 cfb.FullPaths[0] = root + "/";
1679 cfb.FileIndex[0] = ({ name: root, type: 5 });
1680 }
1681 if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1682 seed_cfb(cfb);
1683}
1684function seed_cfb(cfb) {
1685 var nm = "\u0001Sh33tJ5";
1686 if(CFB.find(cfb, "/" + nm)) return;
1687 var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1688 cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));
1689 cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1690 rebuild_cfb(cfb);
1691}
1692function rebuild_cfb(cfb, f) {
1693 init_cfb(cfb);
1694 var gc = false, s = false;
1695 for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1696 var _file = cfb.FileIndex[i];
1697 switch(_file.type) {
1698 case 0:
1699 if(s) gc = true;
1700 else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1701 break;
1702 case 1: case 2: case 5:
1703 s = true;
1704 if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1705 if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1706 break;
1707 default: gc = true; break;
1708 }
1709 }
1710 if(!gc && !f) return;
1711
1712 var now = new Date(1987, 1, 19), j = 0;
1713 var data = [];
1714 for(i = 0; i < cfb.FullPaths.length; ++i) {
1715 if(cfb.FileIndex[i].type === 0) continue;
1716 data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1717 }
1718 for(i = 0; i < data.length; ++i) {
1719 var dad = dirname(data[i][0]);
1720 s = false;
1721 for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1722 if(!s) data.push([dad, ({
1723 name: filename(dad).replace("/",""),
1724 type: 1,
1725 clsid: HEADER_CLSID,
1726 ct: now, mt: now,
1727 content: null
1728 })]);
1729 }
1730
1731 data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1732 cfb.FullPaths = []; cfb.FileIndex = [];
1733 for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1734 for(i = 0; i < data.length; ++i) {
1735 var elt = cfb.FileIndex[i];
1736 var nm = cfb.FullPaths[i];
1737
1738 elt.name = filename(nm).replace("/","");
1739 elt.L = elt.R = elt.C = -(elt.color = 1);
1740 elt.size = elt.content ? elt.content.length : 0;
1741 elt.start = 0;
1742 elt.clsid = (elt.clsid || HEADER_CLSID);
1743 if(i === 0) {
1744 elt.C = data.length > 1 ? 1 : -1;
1745 elt.size = 0;
1746 elt.type = 5;
1747 } else if(nm.slice(-1) == "/") {
1748 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1749 elt.C = j >= data.length ? -1 : j;
1750 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1751 elt.R = j >= data.length ? -1 : j;
1752 elt.type = 1;
1753 } else {
1754 if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1755 elt.type = 2;
1756 }
1757 }
1758
1759}
1760
1761function _write(cfb, options) {
1762 var _opts = options || {};
1763 rebuild_cfb(cfb);
1764 if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
1765 var L = (function(cfb){
1766 var mini_size = 0, fat_size = 0;
1767 for(var i = 0; i < cfb.FileIndex.length; ++i) {
1768 var file = cfb.FileIndex[i];
1769 if(!file.content) continue;
1770var flen = file.content.length;
1771 if(flen > 0){
1772 if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1773 else fat_size += (flen + 0x01FF) >> 9;
1774 }
1775 }
1776 var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1777 var mini_cnt = (mini_size + 7) >> 3;
1778 var mfat_cnt = (mini_size + 0x7F) >> 7;
1779 var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1780 var fat_cnt = (fat_base + 0x7F) >> 7;
1781 var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1782 while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1783 var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1784 cfb.FileIndex[0].size = mini_size << 6;
1785 L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1786 return L;
1787 })(cfb);
1788 var o = new_buf(L[7] << 9);
1789 var i = 0, T = 0;
1790 {
1791 for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1792 for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1793 o.write_shift(2, 0x003E);
1794 o.write_shift(2, 0x0003);
1795 o.write_shift(2, 0xFFFE);
1796 o.write_shift(2, 0x0009);
1797 o.write_shift(2, 0x0006);
1798 for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1799 o.write_shift(4, 0);
1800 o.write_shift(4, L[2]);
1801 o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1802 o.write_shift(4, 0);
1803 o.write_shift(4, 1<<12);
1804 o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1805 o.write_shift(4, L[3]);
1806 o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1807 o.write_shift(4, L[1]);
1808 for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1809 }
1810 if(L[1]) {
1811 for(T = 0; T < L[1]; ++T) {
1812 for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1813 o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1814 }
1815 }
1816 var chainit = function(w) {
1817 for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1818 if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1819 };
1820 T = i = 0;
1821 for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1822 for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1823 chainit(L[3]);
1824 chainit(L[4]);
1825 var j = 0, flen = 0;
1826 var file = cfb.FileIndex[0];
1827 for(; j < cfb.FileIndex.length; ++j) {
1828 file = cfb.FileIndex[j];
1829 if(!file.content) continue;
1830flen = file.content.length;
1831 if(flen < 0x1000) continue;
1832 file.start = T;
1833 chainit((flen + 0x01FF) >> 9);
1834 }
1835 chainit((L[6] + 7) >> 3);
1836 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1837 T = i = 0;
1838 for(j = 0; j < cfb.FileIndex.length; ++j) {
1839 file = cfb.FileIndex[j];
1840 if(!file.content) continue;
1841flen = file.content.length;
1842 if(!flen || flen >= 0x1000) continue;
1843 file.start = T;
1844 chainit((flen + 0x3F) >> 6);
1845 }
1846 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1847 for(i = 0; i < L[4]<<2; ++i) {
1848 var nm = cfb.FullPaths[i];
1849 if(!nm || nm.length === 0) {
1850 for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1851 for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1852 for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1853 continue;
1854 }
1855 file = cfb.FileIndex[i];
1856 if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1857 var _nm = (i === 0 && _opts.root) || file.name;
1858 flen = 2*(_nm.length+1);
1859 o.write_shift(64, _nm, "utf16le");
1860 o.write_shift(2, flen);
1861 o.write_shift(1, file.type);
1862 o.write_shift(1, file.color);
1863 o.write_shift(-4, file.L);
1864 o.write_shift(-4, file.R);
1865 o.write_shift(-4, file.C);
1866 if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1867 else o.write_shift(16, file.clsid, "hex");
1868 o.write_shift(4, file.state || 0);
1869 o.write_shift(4, 0); o.write_shift(4, 0);
1870 o.write_shift(4, 0); o.write_shift(4, 0);
1871 o.write_shift(4, file.start);
1872 o.write_shift(4, file.size); o.write_shift(4, 0);
1873 }
1874 for(i = 1; i < cfb.FileIndex.length; ++i) {
1875 file = cfb.FileIndex[i];
1876if(file.size >= 0x1000) {
1877 o.l = (file.start+1) << 9;
1878 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1879 for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1880 }
1881 }
1882 for(i = 1; i < cfb.FileIndex.length; ++i) {
1883 file = cfb.FileIndex[i];
1884if(file.size > 0 && file.size < 0x1000) {
1885 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1886 for(; j & 0x3F; ++j) o.write_shift(1, 0);
1887 }
1888 }
1889 while(o.l < o.length) o.write_shift(1, 0);
1890 return o;
1891}
1892/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1893function find(cfb, path) {
1894 var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1895 var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1896 var k = false;
1897 if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1898 else k = path.indexOf("/") !== -1;
1899 var UCPath = path.toUpperCase();
1900 var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1901 if(w !== -1) return cfb.FileIndex[w];
1902
1903 var m = !UCPath.match(chr1);
1904 UCPath = UCPath.replace(chr0,'');
1905 if(m) UCPath = UCPath.replace(chr1,'!');
1906 for(w = 0; w < UCFullPaths.length; ++w) {
1907 if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1908 if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1909 }
1910 return null;
1911}
1912/** CFB Constants */
1913var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1914//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1915/* 2.1 Compound File Sector Numbers and Types */
1916var ENDOFCHAIN = -2;
1917/* 2.2 Compound File Header */
1918var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1919var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1920var HEADER_CLSID = '00000000000000000000000000000000';
1921var consts = {
1922 /* 2.1 Compund File Sector Numbers and Types */
1923 MAXREGSECT: -6,
1924 DIFSECT: -4,
1925 FATSECT: -3,
1926 ENDOFCHAIN: ENDOFCHAIN,
1927 FREESECT: -1,
1928 /* 2.2 Compound File Header */
1929 HEADER_SIGNATURE: HEADER_SIGNATURE,
1930 HEADER_MINOR_VERSION: '3e00',
1931 MAXREGSID: -6,
1932 NOSTREAM: -1,
1933 HEADER_CLSID: HEADER_CLSID,
1934 /* 2.6.1 Compound File Directory Entry */
1935 EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
1936};
1937
1938function write_file(cfb, filename, options) {
1939 get_fs();
1940 var o = _write(cfb, options);
1941fs.writeFileSync(filename, o);
1942}
1943
1944function a2s(o) {
1945 var out = new Array(o.length);
1946 for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
1947 return out.join("");
1948}
1949
1950function write(cfb, options) {
1951 var o = _write(cfb, options);
1952 switch(options && options.type) {
1953 case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
1954 case "binary": return a2s(o);
1955 case "base64": return Base64.encode(a2s(o));
1956 }
1957 return o;
1958}
1959/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
1960var _zlib;
1961function use_zlib(zlib) { try {
1962 var InflateRaw = zlib.InflateRaw;
1963 var InflRaw = new InflateRaw();
1964 InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
1965 if(InflRaw.bytesRead) _zlib = zlib;
1966 else throw new Error("zlib does not expose bytesRead");
1967} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
1968
1969function _inflateRawSync(payload, usz) {
1970 if(!_zlib) return _inflate(payload, usz);
1971 var InflateRaw = _zlib.InflateRaw;
1972 var InflRaw = new InflateRaw();
1973 var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
1974 payload.l += InflRaw.bytesRead;
1975 return out;
1976}
1977
1978function _deflateRawSync(payload) {
1979 return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
1980}
1981var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
1982
1983/* 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 ]; */
1984var 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 ];
1985
1986/* 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 ]; */
1987var 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 ];
1988
1989function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
1990
1991var use_typed_arrays = typeof Uint8Array !== 'undefined';
1992
1993var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
1994for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
1995
1996function bit_swap_n(n, b) {
1997 var rev = bitswap8[n & 0xFF];
1998 if(b <= 8) return rev >>> (8-b);
1999 rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
2000 if(b <= 16) return rev >>> (16-b);
2001 rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
2002 return rev >>> (24-b);
2003}
2004
2005/* helpers for unaligned bit reads */
2006function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
2007function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
2008function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
2009function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
2010function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
2011
2012/* works up to n = 3 * 8 + 1 = 25 */
2013function read_bits_n(buf, bl, n) {
2014 var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
2015 var v = buf[h] >>> w;
2016 if(n < 8 - w) return v & f;
2017 v |= buf[h+1]<<(8-w);
2018 if(n < 16 - w) return v & f;
2019 v |= buf[h+2]<<(16-w);
2020 if(n < 24 - w) return v & f;
2021 v |= buf[h+3]<<(24-w);
2022 return v & f;
2023}
2024
2025/* until ArrayBuffer#realloc is a thing, fake a realloc */
2026function realloc(b, sz) {
2027 var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
2028 if(L >= sz) return b;
2029 if(has_buf) {
2030 var o = new_unsafe_buf(M);
2031 // $FlowIgnore
2032 if(b.copy) b.copy(o);
2033 else for(; i < b.length; ++i) o[i] = b[i];
2034 return o;
2035 } else if(use_typed_arrays) {
2036 var a = new Uint8Array(M);
2037 if(a.set) a.set(b);
2038 else for(; i < b.length; ++i) a[i] = b[i];
2039 return a;
2040 }
2041 b.length = M;
2042 return b;
2043}
2044
2045/* zero-filled arrays for older browsers */
2046function zero_fill_array(n) {
2047 var o = new Array(n);
2048 for(var i = 0; i < n; ++i) o[i] = 0;
2049 return o;
2050}var _deflate = (function() {
2051var _deflateRaw = (function() {
2052 return function deflateRaw(data, out) {
2053 var boff = 0;
2054 while(boff < data.length) {
2055 var L = Math.min(0xFFFF, data.length - boff);
2056 var h = boff + L == data.length;
2057 /* TODO: this is only type 0 stored */
2058 out.write_shift(1, +h);
2059 out.write_shift(2, L);
2060 out.write_shift(2, (~L) & 0xFFFF);
2061 while(L-- > 0) out[out.l++] = data[boff++];
2062 }
2063 return out.l;
2064 };
2065})();
2066
2067return function(data) {
2068 var buf = new_buf(50+Math.floor(data.length*1.1));
2069 var off = _deflateRaw(data, buf);
2070 return buf.slice(0, off);
2071};
2072})();
2073/* modified inflate function also moves original read head */
2074
2075/* build tree (used for literals and lengths) */
2076function build_tree(clens, cmap, MAX) {
2077 var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
2078
2079 var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2080 for(i = 0; i < 32; ++i) bl_count[i] = 0;
2081
2082 for(i = L; i < MAX; ++i) clens[i] = 0;
2083 L = clens.length;
2084
2085 var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
2086
2087 /* build code tree */
2088 for(i = 0; i < L; ++i) {
2089 bl_count[(w = clens[i])]++;
2090 if(maxlen < w) maxlen = w;
2091 ctree[i] = 0;
2092 }
2093 bl_count[0] = 0;
2094 for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
2095 for(i = 0; i < L; ++i) {
2096 ccode = clens[i];
2097 if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
2098 }
2099
2100 /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
2101 var cleni = 0;
2102 for(i = 0; i < L; ++i) {
2103 cleni = clens[i];
2104 if(cleni != 0) {
2105 ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
2106 for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
2107 cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
2108 }
2109 }
2110 return maxlen;
2111}
2112
2113var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
2114var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2115if(!use_typed_arrays) {
2116 for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
2117 for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
2118}
2119(function() {
2120 var dlens = [];
2121 var i = 0;
2122 for(;i<32; i++) dlens.push(5);
2123 build_tree(dlens, fix_dmap, 32);
2124
2125 var clens = [];
2126 i = 0;
2127 for(; i<=143; i++) clens.push(8);
2128 for(; i<=255; i++) clens.push(9);
2129 for(; i<=279; i++) clens.push(7);
2130 for(; i<=287; i++) clens.push(8);
2131 build_tree(clens, fix_lmap, 288);
2132})();
2133
2134var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2135var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2136var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
2137var dyn_len_1 = 1, dyn_len_2 = 1;
2138
2139/* 5.5.3 Expanding Huffman Codes */
2140function dyn(data, boff) {
2141 /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
2142 var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
2143 var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
2144 var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
2145 var w = 0;
2146
2147 /* grab and store code lengths */
2148 var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
2149 var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2150 var maxlen = 1;
2151 var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2152 var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2153 var L = clens.length; /* 19 */
2154 for(var i = 0; i < _HCLEN; ++i) {
2155 clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
2156 if(maxlen < w) maxlen = w;
2157 bl_count[w]++;
2158 boff += 3;
2159 }
2160
2161 /* build code tree */
2162 var ccode = 0;
2163 bl_count[0] = 0;
2164 for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
2165 for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
2166 /* cmap[7 bits from stream] = (off&7) + (lit<<3) */
2167 var cleni = 0;
2168 for(i = 0; i < L; ++i) {
2169 cleni = clens[i];
2170 if(cleni != 0) {
2171 ccode = bitswap8[ctree[i]]>>(8-cleni);
2172 for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
2173 }
2174 }
2175
2176 /* read literal and dist codes at once */
2177 var hcodes = [];
2178 maxlen = 1;
2179 for(; hcodes.length < _HLIT + _HDIST;) {
2180 ccode = dyn_cmap[read_bits_7(data, boff)];
2181 boff += ccode & 7;
2182 switch((ccode >>>= 3)) {
2183 case 16:
2184 w = 3 + read_bits_2(data, boff); boff += 2;
2185 ccode = hcodes[hcodes.length - 1];
2186 while(w-- > 0) hcodes.push(ccode);
2187 break;
2188 case 17:
2189 w = 3 + read_bits_3(data, boff); boff += 3;
2190 while(w-- > 0) hcodes.push(0);
2191 break;
2192 case 18:
2193 w = 11 + read_bits_7(data, boff); boff += 7;
2194 while(w -- > 0) hcodes.push(0);
2195 break;
2196 default:
2197 hcodes.push(ccode);
2198 if(maxlen < ccode) maxlen = ccode;
2199 break;
2200 }
2201 }
2202
2203 /* build literal / length trees */
2204 var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
2205 for(i = _HLIT; i < 286; ++i) h1[i] = 0;
2206 for(i = _HDIST; i < 30; ++i) h2[i] = 0;
2207 dyn_len_1 = build_tree(h1, dyn_lmap, 286);
2208 dyn_len_2 = build_tree(h2, dyn_dmap, 30);
2209 return boff;
2210}
2211
2212/* return [ data, bytesRead ] */
2213function inflate(data, usz) {
2214 /* shortcircuit for empty buffer [0x03, 0x00] */
2215 if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
2216
2217 /* bit offset */
2218 var boff = 0;
2219
2220 /* header includes final bit and type bits */
2221 var header = 0;
2222
2223 var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
2224 var woff = 0;
2225 var OL = outbuf.length>>>0;
2226 var max_len_1 = 0, max_len_2 = 0;
2227
2228 while((header&1) == 0) {
2229 header = read_bits_3(data, boff); boff += 3;
2230 if((header >>> 1) == 0) {
2231 /* Stored block */
2232 if(boff & 7) boff += 8 - (boff&7);
2233 /* 2 bytes sz, 2 bytes bit inverse */
2234 var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
2235 boff += 32;
2236 /* push sz bytes */
2237 if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
2238 if(typeof data.copy === 'function') {
2239 // $FlowIgnore
2240 data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
2241 woff += sz; boff += 8*sz;
2242 } else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
2243 continue;
2244 } else if((header >>> 1) == 1) {
2245 /* Fixed Huffman */
2246 max_len_1 = 9; max_len_2 = 5;
2247 } else {
2248 /* Dynamic Huffman */
2249 boff = dyn(data, boff);
2250 max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
2251 }
2252 if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
2253 for(;;) { // while(true) is apparently out of vogue in modern JS circles
2254 /* ingest code and move read head */
2255 var bits = read_bits_n(data, boff, max_len_1);
2256 var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
2257 boff += code & 15; code >>>= 4;
2258 /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
2259 if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
2260 else if(code == 256) break;
2261 else {
2262 code -= 257;
2263 var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
2264 var tgt = woff + LEN_LN[code];
2265 /* length extra bits */
2266 if(len_eb > 0) {
2267 tgt += read_bits_n(data, boff, len_eb);
2268 boff += len_eb;
2269 }
2270
2271 /* dist code */
2272 bits = read_bits_n(data, boff, max_len_2);
2273 code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
2274 boff += code & 15; code >>>= 4;
2275 var dst_eb = (code < 4 ? 0 : (code-2)>>1);
2276 var dst = DST_LN[code];
2277 /* dist extra bits */
2278 if(dst_eb > 0) {
2279 dst += read_bits_n(data, boff, dst_eb);
2280 boff += dst_eb;
2281 }
2282
2283 /* in the common case, manual byte copy is faster than TA set / Buffer copy */
2284 if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
2285 while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
2286 }
2287 }
2288 }
2289 return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
2290}
2291
2292function _inflate(payload, usz) {
2293 var data = payload.slice(payload.l||0);
2294 var out = inflate(data, usz);
2295 payload.l += out[1];
2296 return out[0];
2297}
2298
2299function warn_or_throw(wrn, msg) {
2300 if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
2301 else throw new Error(msg);
2302}
2303
2304function parse_zip(file, options) {
2305 var blob = file;
2306 prep_blob(blob, 0);
2307
2308 var FileIndex = [], FullPaths = [];
2309 var o = {
2310 FileIndex: FileIndex,
2311 FullPaths: FullPaths
2312 };
2313 init_cfb(o, { root: options.root });
2314
2315 /* find end of central directory, start just after signature */
2316 var i = blob.length - 4;
2317 while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
2318 blob.l = i + 4;
2319
2320 /* parse end of central directory */
2321 blob.l += 4;
2322 var fcnt = blob.read_shift(2);
2323 blob.l += 6;
2324 var start_cd = blob.read_shift(4);
2325
2326 /* parse central directory */
2327 blob.l = start_cd;
2328
2329 for(i = 0; i < fcnt; ++i) {
2330 /* trust local file header instead of CD entry */
2331 blob.l += 20;
2332 var csz = blob.read_shift(4);
2333 var usz = blob.read_shift(4);
2334 var namelen = blob.read_shift(2);
2335 var efsz = blob.read_shift(2);
2336 var fcsz = blob.read_shift(2);
2337 blob.l += 8;
2338 var offset = blob.read_shift(4);
2339 var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
2340 blob.l += namelen + efsz + fcsz;
2341
2342 var L = blob.l;
2343 blob.l = offset + 4;
2344 parse_local_file(blob, csz, usz, o, EF);
2345 blob.l = L;
2346 }
2347
2348 return o;
2349}
2350
2351
2352/* head starts just after local file header signature */
2353function parse_local_file(blob, csz, usz, o, EF) {
2354 /* [local file header] */
2355 blob.l += 2;
2356 var flags = blob.read_shift(2);
2357 var meth = blob.read_shift(2);
2358 var date = parse_dos_date(blob);
2359
2360 if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
2361 var crc32 = blob.read_shift(4);
2362 var _csz = blob.read_shift(4);
2363 var _usz = blob.read_shift(4);
2364
2365 var namelen = blob.read_shift(2);
2366 var efsz = blob.read_shift(2);
2367
2368 // TODO: flags & (1<<11) // UTF8
2369 var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
2370 if(efsz) {
2371 var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
2372 if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
2373 if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
2374 }
2375 blob.l += efsz;
2376
2377 /* [encryption header] */
2378
2379 /* [file data] */
2380 var data = blob.slice(blob.l, blob.l + _csz);
2381 switch(meth) {
2382 case 8: data = _inflateRawSync(blob, _usz); break;
2383 case 0: break;
2384 default: throw new Error("Unsupported ZIP Compression method " + meth);
2385 }
2386
2387 /* [data descriptor] */
2388 var wrn = false;
2389 if(flags & 8) {
2390 crc32 = blob.read_shift(4);
2391 if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
2392 _csz = blob.read_shift(4);
2393 _usz = blob.read_shift(4);
2394 }
2395
2396 if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
2397 if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
2398 var _crc32 = CRC32.buf(data, 0);
2399 if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
2400 cfb_add(o, name, data, {unsafe: true, mt: date});
2401}
2402function write_zip(cfb, options) {
2403 var _opts = options || {};
2404 var out = [], cdirs = [];
2405 var o = new_buf(1);
2406 var method = (_opts.compression ? 8 : 0), flags = 0;
2407 var desc = false;
2408 if(desc) flags |= 8;
2409 var i = 0, j = 0;
2410
2411 var start_cd = 0, fcnt = 0;
2412 var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
2413 var crcs = [];
2414 var sz_cd = 0;
2415
2416 for(i = 1; i < cfb.FullPaths.length; ++i) {
2417 fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
2418 if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
2419 var start = start_cd;
2420
2421 /* TODO: CP437 filename */
2422 var namebuf = new_buf(fp.length);
2423 for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
2424 namebuf = namebuf.slice(0, namebuf.l);
2425 crcs[fcnt] = CRC32.buf(fi.content, 0);
2426
2427 var outbuf = fi.content;
2428 if(method == 8) outbuf = _deflateRawSync(outbuf);
2429
2430 /* local file header */
2431 o = new_buf(30);
2432 o.write_shift(4, 0x04034b50);
2433 o.write_shift(2, 20);
2434 o.write_shift(2, flags);
2435 o.write_shift(2, method);
2436 /* TODO: last mod file time/date */
2437 if(fi.mt) write_dos_date(o, fi.mt);
2438 else o.write_shift(4, 0);
2439 o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
2440 o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
2441 o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
2442 o.write_shift(2, namebuf.length);
2443 o.write_shift(2, 0);
2444
2445 start_cd += o.length;
2446 out.push(o);
2447 start_cd += namebuf.length;
2448 out.push(namebuf);
2449
2450 /* TODO: encryption header ? */
2451 start_cd += outbuf.length;
2452 out.push(outbuf);
2453
2454 /* data descriptor */
2455 if(flags & 8) {
2456 o = new_buf(12);
2457 o.write_shift(-4, crcs[fcnt]);
2458 o.write_shift(4, outbuf.length);
2459 o.write_shift(4, fi.content.length);
2460 start_cd += o.l;
2461 out.push(o);
2462 }
2463
2464 /* central directory */
2465 o = new_buf(46);
2466 o.write_shift(4, 0x02014b50);
2467 o.write_shift(2, 0);
2468 o.write_shift(2, 20);
2469 o.write_shift(2, flags);
2470 o.write_shift(2, method);
2471 o.write_shift(4, 0); /* TODO: last mod file time/date */
2472 o.write_shift(-4, crcs[fcnt]);
2473
2474 o.write_shift(4, outbuf.length);
2475 o.write_shift(4, fi.content.length);
2476 o.write_shift(2, namebuf.length);
2477 o.write_shift(2, 0);
2478 o.write_shift(2, 0);
2479 o.write_shift(2, 0);
2480 o.write_shift(2, 0);
2481 o.write_shift(4, 0);
2482 o.write_shift(4, start);
2483
2484 sz_cd += o.l;
2485 cdirs.push(o);
2486 sz_cd += namebuf.length;
2487 cdirs.push(namebuf);
2488 ++fcnt;
2489 }
2490
2491 /* end of central directory */
2492 o = new_buf(22);
2493 o.write_shift(4, 0x06054b50);
2494 o.write_shift(2, 0);
2495 o.write_shift(2, 0);
2496 o.write_shift(2, fcnt);
2497 o.write_shift(2, fcnt);
2498 o.write_shift(4, sz_cd);
2499 o.write_shift(4, start_cd);
2500 o.write_shift(2, 0);
2501
2502 return bconcat(([bconcat((out)), bconcat(cdirs), o]));
2503}
2504function cfb_new(opts) {
2505 var o = ({});
2506 init_cfb(o, opts);
2507 return o;
2508}
2509
2510function cfb_add(cfb, name, content, opts) {
2511 var unsafe = opts && opts.unsafe;
2512 if(!unsafe) init_cfb(cfb);
2513 var file = !unsafe && CFB.find(cfb, name);
2514 if(!file) {
2515 var fpath = cfb.FullPaths[0];
2516 if(name.slice(0, fpath.length) == fpath) fpath = name;
2517 else {
2518 if(fpath.slice(-1) != "/") fpath += "/";
2519 fpath = (fpath + name).replace("//","/");
2520 }
2521 file = ({name: filename(name), type: 2});
2522 cfb.FileIndex.push(file);
2523 cfb.FullPaths.push(fpath);
2524 if(!unsafe) CFB.utils.cfb_gc(cfb);
2525 }
2526file.content = (content);
2527 file.size = content ? content.length : 0;
2528 if(opts) {
2529 if(opts.CLSID) file.clsid = opts.CLSID;
2530 if(opts.mt) file.mt = opts.mt;
2531 if(opts.ct) file.ct = opts.ct;
2532 }
2533 return file;
2534}
2535
2536function cfb_del(cfb, name) {
2537 init_cfb(cfb);
2538 var file = CFB.find(cfb, name);
2539 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2540 cfb.FileIndex.splice(j, 1);
2541 cfb.FullPaths.splice(j, 1);
2542 return true;
2543 }
2544 return false;
2545}
2546
2547function cfb_mov(cfb, old_name, new_name) {
2548 init_cfb(cfb);
2549 var file = CFB.find(cfb, old_name);
2550 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2551 cfb.FileIndex[j].name = filename(new_name);
2552 cfb.FullPaths[j] = new_name;
2553 return true;
2554 }
2555 return false;
2556}
2557
2558function cfb_gc(cfb) { rebuild_cfb(cfb, true); }
2559
2560exports.find = find;
2561exports.read = read;
2562exports.parse = parse;
2563exports.write = write;
2564exports.writeFile = write_file;
2565exports.utils = {
2566 cfb_new: cfb_new,
2567 cfb_add: cfb_add,
2568 cfb_del: cfb_del,
2569 cfb_mov: cfb_mov,
2570 cfb_gc: cfb_gc,
2571 ReadShift: ReadShift,
2572 CheckField: CheckField,
2573 prep_blob: prep_blob,
2574 bconcat: bconcat,
2575 use_zlib: use_zlib,
2576 _deflateRaw: _deflate,
2577 _inflateRaw: _inflate,
2578 consts: consts
2579};
2580
2581return exports;
2582})();
2583
2584if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
2585var _fs;
2586if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
2587
2588/* normalize data for blob ctor */
2589function blobify(data) {
2590 if(typeof data === "string") return s2ab(data);
2591 if(Array.isArray(data)) return a2u(data);
2592 return data;
2593}
2594/* write or download file */
2595function write_dl(fname, payload, enc) {
2596 /*global IE_SaveFile, Blob, navigator, saveAs, document, File, chrome */
2597 if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
2598 var data = (enc == "utf8") ? utf8write(payload) : payload;
2599if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
2600 if(typeof Blob !== 'undefined') {
2601 var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
2602if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
2603if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
2604 if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
2605 var url = URL.createObjectURL(blob);
2606if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
2607 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2608 return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
2609 }
2610 var a = document.createElement("a");
2611 if(a.download != null) {
2612a.download = fname; a.href = url; document.body.appendChild(a); a.click();
2613document.body.removeChild(a);
2614 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2615 return url;
2616 }
2617 }
2618 }
2619 // $FlowIgnore
2620 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2621 // $FlowIgnore
2622 var out = File(fname); out.open("w"); out.encoding = "binary";
2623 if(Array.isArray(payload)) payload = a2s(payload);
2624 out.write(payload); out.close(); return payload;
2625 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2626 throw new Error("cannot save file " + fname);
2627}
2628
2629/* read binary data from file */
2630function read_binary(path) {
2631 if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
2632 // $FlowIgnore
2633 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2634 // $FlowIgnore
2635 var infile = File(path); infile.open("r"); infile.encoding = "binary";
2636 var data = infile.read(); infile.close();
2637 return data;
2638 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2639 throw new Error("Cannot access file " + path);
2640}
2641function keys(o) {
2642 var ks = Object.keys(o), o2 = [];
2643 for(var i = 0; i < ks.length; ++i) if(Object.prototype.hasOwnProperty.call(o, ks[i])) o2.push(ks[i]);
2644 return o2;
2645}
2646
2647function evert_key(obj, key) {
2648 var o = ([]), K = keys(obj);
2649 for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
2650 return o;
2651}
2652
2653function evert(obj) {
2654 var o = ([]), K = keys(obj);
2655 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
2656 return o;
2657}
2658
2659function evert_num(obj) {
2660 var o = ([]), K = keys(obj);
2661 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
2662 return o;
2663}
2664
2665function evert_arr(obj) {
2666 var o = ([]), K = keys(obj);
2667 for(var i = 0; i !== K.length; ++i) {
2668 if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
2669 o[obj[K[i]]].push(K[i]);
2670 }
2671 return o;
2672}
2673
2674var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
2675var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2676function datenum(v, date1904) {
2677 var epoch = v.getTime();
2678 if(date1904) epoch -= 1462*24*60*60*1000;
2679 return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
2680}
2681function numdate(v) {
2682 var out = new Date();
2683 out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
2684 return out;
2685}
2686
2687/* ISO 8601 Duration */
2688function parse_isodur(s) {
2689 var sec = 0, mt = 0, time = false;
2690 var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
2691 if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
2692 for(var i = 1; i != m.length; ++i) {
2693 if(!m[i]) continue;
2694 mt = 1;
2695 if(i > 3) time = true;
2696 switch(m[i].slice(m[i].length-1)) {
2697 case 'Y':
2698 throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
2699 case 'D': mt *= 24;
2700 /* falls through */
2701 case 'H': mt *= 60;
2702 /* falls through */
2703 case 'M':
2704 if(!time) throw new Error("Unsupported ISO Duration Field: M");
2705 else mt *= 60;
2706 /* falls through */
2707 case 'S': break;
2708 }
2709 sec += mt * parseInt(m[i], 10);
2710 }
2711 return sec;
2712}
2713
2714var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
2715if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
2716var good_pd = good_pd_date.getFullYear() == 2017;
2717/* parses a date as a local date */
2718function parseDate(str, fixdate) {
2719 var d = new Date(str);
2720 if(good_pd) {
2721if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
2722 else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
2723 return d;
2724 }
2725 if(str instanceof Date) return str;
2726 if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
2727 var s = d.getFullYear();
2728 if(str.indexOf("" + s) > -1) return d;
2729 d.setFullYear(d.getFullYear() + 100); return d;
2730 }
2731 var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
2732 var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
2733 if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
2734 return out;
2735}
2736
2737function cc2str(arr) {
2738 var o = "";
2739 for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2740 return o;
2741}
2742
2743function dup(o) {
2744 if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2745 if(typeof o != 'object' || o == null) return o;
2746 if(o instanceof Date) return new Date(o.getTime());
2747 var out = {};
2748 for(var k in o) if(Object.prototype.hasOwnProperty.call(o, k)) out[k] = dup(o[k]);
2749 return out;
2750}
2751
2752function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
2753
2754/* TODO: stress test */
2755function fuzzynum(s) {
2756 var v = Number(s);
2757 if(!isNaN(v)) return v;
2758 var wt = 1;
2759 var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2760 if(!isNaN(v = Number(ss))) return v / wt;
2761 ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2762 if(!isNaN(v = Number(ss))) return v / wt;
2763 return v;
2764}
2765function fuzzydate(s) {
2766 var o = new Date(s), n = new Date(NaN);
2767 var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2768 if(isNaN(d)) return n;
2769 if(y < 0 || y > 8099) return n;
2770 if((m > 0 || d > 1) && y != 101) return o;
2771 if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2772 if(s.match(/[^-0-9:,\/\\]/)) return n;
2773 return o;
2774}
2775
2776var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2777function split_regex(str, re, def) {
2778 if(safe_split_regex || typeof re == "string") return str.split(re);
2779 var p = str.split(re), o = [p[0]];
2780 for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2781 return o;
2782}
2783function getdatastr(data) {
2784 if(!data) return null;
2785 if(data.data) return debom(data.data);
2786 if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2787 if(data.asBinary) return debom(data.asBinary());
2788 if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2789 if(data.content && data.type) return debom(cc2str(data.content));
2790 return null;
2791}
2792
2793function getdatabin(data) {
2794 if(!data) return null;
2795 if(data.data) return char_codes(data.data);
2796 if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2797 if(data._data && data._data.getContent) {
2798 var o = data._data.getContent();
2799 if(typeof o == "string") return char_codes(o);
2800 return Array.prototype.slice.call(o);
2801 }
2802 if(data.content && data.type) return data.content;
2803 return null;
2804}
2805
2806function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2807
2808/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2809/* OASIS does not comment on filename case sensitivity */
2810function safegetzipfile(zip, file) {
2811 var k = zip.FullPaths || keys(zip.files);
2812 var f = file.toLowerCase(), g = f.replace(/\//g,'\\');
2813 for(var i=0; i<k.length; ++i) {
2814 var n = k[i].toLowerCase();
2815 if(f == n || g == n) return zip.files[k[i]];
2816 }
2817 return null;
2818}
2819
2820function getzipfile(zip, file) {
2821 var o = safegetzipfile(zip, file);
2822 if(o == null) throw new Error("Cannot find file " + file + " in zip");
2823 return o;
2824}
2825
2826function getzipdata(zip, file, safe) {
2827 if(!safe) return getdata(getzipfile(zip, file));
2828 if(!file) return null;
2829 try { return getzipdata(zip, file); } catch(e) { return null; }
2830}
2831
2832function getzipstr(zip, file, safe) {
2833 if(!safe) return getdatastr(getzipfile(zip, file));
2834 if(!file) return null;
2835 try { return getzipstr(zip, file); } catch(e) { return null; }
2836}
2837
2838function zipentries(zip) {
2839 var k = zip.FullPaths || keys(zip.files), o = [];
2840 for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i]);
2841 return o.sort();
2842}
2843
2844function zip_add_file(zip, path, content) {
2845 if(zip.FullPaths) CFB.utils.cfb_add(zip, path, content);
2846 else zip.file(path, content);
2847}
2848
2849var jszip;
2850/*global JSZipSync:true */
2851if(typeof JSZipSync !== 'undefined') jszip = JSZipSync;
2852if(typeof exports !== 'undefined') {
2853 if(typeof module !== 'undefined' && module.exports) {
2854 if(typeof jszip === 'undefined') jszip = require('./jszip.js');
2855 }
2856}
2857
2858function zip_new() {
2859 if(!jszip) return CFB.utils.cfb_new();
2860 return new jszip();
2861}
2862
2863function zip_read(d, o) {
2864 var zip;
2865 if(jszip) switch(o.type) {
2866 case "base64": zip = new jszip(d, { base64:true }); break;
2867 case "binary": case "array": zip = new jszip(d, { base64:false }); break;
2868 case "buffer": zip = new jszip(d); break;
2869 default: throw new Error("Unrecognized type " + o.type);
2870 }
2871 else switch(o.type) {
2872 case "base64": zip = CFB.read(d, { type: "base64" }); break;
2873 case "binary": zip = CFB.read(d, { type: "binary" }); break;
2874 case "buffer": case "array": zip = CFB.read(d, { type: "buffer" }); break;
2875 default: throw new Error("Unrecognized type " + o.type);
2876 }
2877 return zip;
2878}
2879
2880function resolve_path(path, base) {
2881 if(path.charAt(0) == "/") return path.slice(1);
2882 var result = base.split('/');
2883 if(base.slice(-1) != "/") result.pop(); // folder path
2884 var target = path.split('/');
2885 while (target.length !== 0) {
2886 var step = target.shift();
2887 if (step === '..') result.pop();
2888 else if (step !== '.') result.push(step);
2889 }
2890 return result.join('/');
2891}
2892var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2893var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2894var tagregex=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s?[\/\?]?>/g;
2895
2896if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2897var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2898function parsexmltag(tag, skip_root, skip_LC) {
2899 var z = ({});
2900 var eq = 0, c = 0;
2901 for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2902 if(!skip_root) z[0] = tag.slice(0, eq);
2903 if(eq === tag.length) return z;
2904 var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2905 if(m) for(i = 0; i != m.length; ++i) {
2906 cc = m[i];
2907 for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2908 q = cc.slice(0,c).trim();
2909 while(cc.charCodeAt(c+1) == 32) ++c;
2910 quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2911 v = cc.slice(c+1+quot, cc.length-quot);
2912 for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2913 if(j===q.length) {
2914 if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2915 z[q] = v;
2916 if(!skip_LC) z[q.toLowerCase()] = v;
2917 }
2918 else {
2919 var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2920 if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2921 z[k] = v;
2922 if(!skip_LC) z[k.toLowerCase()] = v;
2923 }
2924 }
2925 return z;
2926}
2927function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
2928
2929var encodings = {
2930 '&quot;': '"',
2931 '&apos;': "'",
2932 '&gt;': '>',
2933 '&lt;': '<',
2934 '&amp;': '&'
2935};
2936var rencoding = evert(encodings);
2937//var rencstr = "&<>'\"".split("");
2938
2939// TODO: CP remap (need to read file version to determine OS)
2940var unescapexml = (function() {
2941 /* 22.4.2.4 bstr (Basic String) */
2942 var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/ig;
2943 return function unescapexml(text) {
2944 var s = text + '', i = s.indexOf("<![CDATA[");
2945 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));});
2946 var j = s.indexOf("]]>");
2947 return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
2948 };
2949})();
2950
2951var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
2952function escapexml(text){
2953 var s = text + '';
2954 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
2955}
2956function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
2957
2958var htmlcharegex = /[\u0000-\u001f]/g;
2959function escapehtml(text){
2960 var s = text + '';
2961 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) + ";"; });
2962}
2963
2964function escapexlml(text){
2965 var s = text + '';
2966 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
2967}
2968
2969/* TODO: handle codepages */
2970var xlml_fixstr = (function() {
2971 var entregex = /&#(\d+);/g;
2972 function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
2973 return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
2974})();
2975var xlml_unfixstr = (function() {
2976 return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
2977})();
2978
2979function parsexmlbool(value) {
2980 switch(value) {
2981 case 1: case true: case '1': case 'true': case 'TRUE': return true;
2982 /* case '0': case 'false': case 'FALSE':*/
2983 default: return false;
2984 }
2985}
2986
2987var utf8read = function utf8reada(orig) {
2988 var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
2989 while (i < orig.length) {
2990 c = orig.charCodeAt(i++);
2991 if (c < 128) { out += String.fromCharCode(c); continue; }
2992 d = orig.charCodeAt(i++);
2993 if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
2994 e = orig.charCodeAt(i++);
2995 if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
2996 f = orig.charCodeAt(i++);
2997 w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
2998 out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
2999 out += String.fromCharCode(0xDC00 + (w&1023));
3000 }
3001 return out;
3002};
3003
3004var utf8write = function(orig) {
3005 var out = [], i = 0, c = 0, d = 0;
3006 while(i < orig.length) {
3007 c = orig.charCodeAt(i++);
3008 switch(true) {
3009 case c < 128: out.push(String.fromCharCode(c)); break;
3010 case c < 2048:
3011 out.push(String.fromCharCode(192 + (c >> 6)));
3012 out.push(String.fromCharCode(128 + (c & 63)));
3013 break;
3014 case c >= 55296 && c < 57344:
3015 c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
3016 out.push(String.fromCharCode(240 + ((d >>18) & 7)));
3017 out.push(String.fromCharCode(144 + ((d >>12) & 63)));
3018 out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
3019 out.push(String.fromCharCode(128 + (d & 63)));
3020 break;
3021 default:
3022 out.push(String.fromCharCode(224 + (c >> 12)));
3023 out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
3024 out.push(String.fromCharCode(128 + (c & 63)));
3025 }
3026 }
3027 return out.join("");
3028};
3029
3030if(has_buf) {
3031 var utf8readb = function utf8readb(data) {
3032 var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
3033 for(i = 0; i < data.length; i+=j) {
3034 j = 1;
3035 if((c=data.charCodeAt(i)) < 128) w = c;
3036 else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
3037 else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
3038 else { j = 4;
3039 w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
3040 w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
3041 }
3042 if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
3043 out[k++] = w%256; out[k++] = w>>>8;
3044 }
3045 return out.slice(0,k).toString('ucs2');
3046 };
3047 var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
3048 if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
3049 var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
3050 if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
3051
3052 utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
3053}
3054
3055// matches <foo>...</foo> extracts content
3056var matchtag = (function() {
3057 var mtcache = ({});
3058 return function matchtag(f,g) {
3059 var t = f+"|"+(g||"");
3060 if(mtcache[t]) return mtcache[t];
3061 return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
3062 };
3063})();
3064
3065var htmldecode = (function() {
3066 var entities = [
3067 ['nbsp', ' '], ['middot', '·'],
3068 ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
3069 ].map(function(x) { return [new RegExp('&' + x[0] + ';', "ig"), x[1]]; });
3070 return function htmldecode(str) {
3071 var o = str
3072 // Remove new lines and spaces from start of content
3073 .replace(/^[\t\n\r ]+/, "")
3074 // Remove new lines and spaces from end of content
3075 .replace(/[\t\n\r ]+$/,"")
3076 // Added line which removes any white space characters after and before html tags
3077 .replace(/>\s+/g,">").replace(/\s+</g,"<")
3078 // Replace remaining new lines and spaces with space
3079 .replace(/[\t\n\r ]+/g, " ")
3080 // Replace <br> tags with new lines
3081 .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
3082 // Strip HTML elements
3083 .replace(/<[^>]*>/g,"");
3084 for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
3085 return o;
3086 };
3087})();
3088
3089var vtregex = (function(){ var vt_cache = {};
3090 return function vt_regex(bt) {
3091 if(vt_cache[bt] !== undefined) return vt_cache[bt];
3092 return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
3093};})();
3094var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
3095function parseVector(data, opts) {
3096 var h = parsexmltag(data);
3097
3098 var matches = data.match(vtregex(h.baseType))||[];
3099 var res = [];
3100 if(matches.length != h.size) {
3101 if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
3102 return res;
3103 }
3104 matches.forEach(function(x) {
3105 var v = x.replace(vtvregex,"").match(vtmregex);
3106 if(v) res.push({v:utf8read(v[2]), t:v[1]});
3107 });
3108 return res;
3109}
3110
3111var wtregex = /(^\s|\s$|\n)/;
3112function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
3113
3114function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
3115function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
3116
3117function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
3118
3119function write_vt(s) {
3120 switch(typeof s) {
3121 case 'string': return writextag('vt:lpwstr', escapexml(s));
3122 case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', escapexml(String(s)));
3123 case 'boolean': return writextag('vt:bool',s?'true':'false');
3124 }
3125 if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
3126 throw new Error("Unable to serialize " + s);
3127}
3128
3129var XMLNS = ({
3130 'dc': 'http://purl.org/dc/elements/1.1/',
3131 'dcterms': 'http://purl.org/dc/terms/',
3132 'dcmitype': 'http://purl.org/dc/dcmitype/',
3133 'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
3134 'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
3135 'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
3136 'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
3137 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
3138 'xsd': 'http://www.w3.org/2001/XMLSchema'
3139});
3140
3141XMLNS.main = [
3142 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
3143 'http://purl.oclc.org/ooxml/spreadsheetml/main',
3144 'http://schemas.microsoft.com/office/excel/2006/main',
3145 'http://schemas.microsoft.com/office/excel/2006/2'
3146];
3147
3148var XLMLNS = ({
3149 'o': 'urn:schemas-microsoft-com:office:office',
3150 'x': 'urn:schemas-microsoft-com:office:excel',
3151 'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
3152 'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
3153 'mv': 'http://macVmlSchemaUri',
3154 'v': 'urn:schemas-microsoft-com:vml',
3155 'html': 'http://www.w3.org/TR/REC-html40'
3156});
3157function read_double_le(b, idx) {
3158 var s = 1 - 2 * (b[idx + 7] >>> 7);
3159 var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
3160 var m = (b[idx+6]&0x0f);
3161 for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
3162 if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
3163 if(e == 0) e = -1022;
3164 else { e -= 1023; m += Math.pow(2,52); }
3165 return s * Math.pow(2, e - 52) * m;
3166}
3167
3168function write_double_le(b, v, idx) {
3169 var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
3170 var av = bs ? (-v) : v;
3171 if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
3172 else if(av == 0) e = m = 0;
3173 else {
3174 e = Math.floor(Math.log(av) / Math.LN2);
3175 m = av * Math.pow(2, 52 - e);
3176 if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
3177 else { m -= Math.pow(2,52); e+=1023; }
3178 }
3179 for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
3180 b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
3181 b[idx + 7] = (e >> 4) | bs;
3182}
3183
3184var __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; };
3185var ___toBuffer = __toBuffer;
3186var __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,''); };
3187var ___utf16le = __utf16le;
3188var __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(""); };
3189var ___hexlify = __hexlify;
3190var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
3191var ___utf8 = __utf8;
3192var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3193var ___lpstr = __lpstr;
3194var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3195var ___cpstr = __cpstr;
3196var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3197var ___lpwstr = __lpwstr;
3198var __lpp4, ___lpp4;
3199__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
3200var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
3201var ___8lpp4 = __8lpp4;
3202var __double, ___double;
3203__double = ___double = function(b, idx) { return read_double_le(b, idx);};
3204var is_buf = function is_buf_a(a) { return Array.isArray(a); };
3205
3206if(has_buf) {
3207 __utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
3208 __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
3209 __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) : "";};
3210 __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) : "";};
3211 __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);};
3212 __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);};
3213 __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);};
3214 __utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
3215 __toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
3216 bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
3217 __double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
3218 is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
3219}
3220
3221/* from js-xls */
3222if(typeof cptable !== 'undefined') {
3223 __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
3224 __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
3225 __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)) : "";};
3226 __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)) : "";};
3227 __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)) : "";};
3228 __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
3229 __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
3230}
3231
3232var __readUInt8 = function(b, idx) { return b[idx]; };
3233var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
3234var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
3235var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
3236var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
3237var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
3238
3239function ReadShift(size, t) {
3240 var o="", oI, oR, oo=[], w, vv, i, loc;
3241 switch(t) {
3242 case 'dbcs':
3243 loc = this.l;
3244 if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
3245 else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
3246 size *= 2;
3247 break;
3248
3249 case 'utf8': o = __utf8(this, this.l, this.l + size); break;
3250 case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
3251
3252 case 'wstr':
3253 if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
3254 else return ReadShift.call(this, size, 'dbcs');
3255 size = 2 * size; break;
3256
3257 /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
3258 case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3259 case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3260 /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
3261 case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
3262 /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
3263 case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
3264 /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
3265 case '8lpp4': size = 4 + __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
3266
3267 case 'cstr': size = 0; o = "";
3268 while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
3269 o = oo.join(""); break;
3270 case '_wstr': size = 0; o = "";
3271 while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
3272 size+=2; o = oo.join(""); break;
3273
3274 /* sbcs and dbcs support continue records in the SST way TODO codepages */
3275 case 'dbcs-cont': o = ""; loc = this.l;
3276 for(i = 0; i < size; ++i) {
3277 if(this.lens && this.lens.indexOf(loc) !== -1) {
3278 w = __readUInt8(this, loc);
3279 this.l = loc + 1;
3280 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3281 return oo.join("") + vv;
3282 }
3283 oo.push(_getchar(__readUInt16LE(this, loc)));
3284 loc+=2;
3285 } o = oo.join(""); size *= 2; break;
3286
3287 case 'cpstr':
3288 if(typeof cptable !== 'undefined') {
3289 o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
3290 break;
3291 }
3292 /* falls through */
3293 case 'sbcs-cont': o = ""; loc = this.l;
3294 for(i = 0; i != size; ++i) {
3295 if(this.lens && this.lens.indexOf(loc) !== -1) {
3296 w = __readUInt8(this, loc);
3297 this.l = loc + 1;
3298 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3299 return oo.join("") + vv;
3300 }
3301 oo.push(_getchar(__readUInt8(this, loc)));
3302 loc+=1;
3303 } o = oo.join(""); break;
3304
3305 default:
3306 switch(size) {
3307 case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
3308 case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
3309 case 4: case -4:
3310 if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
3311 else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
3312 case 8: case -8:
3313 if(t === 'f') {
3314 if(size == 8) oR = __double(this, this.l);
3315 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);
3316 this.l += 8; return oR;
3317 } else size = 8;
3318 /* falls through */
3319 case 16: o = __hexlify(this, this.l, size); break;
3320 }}
3321 this.l+=size; return o;
3322}
3323
3324var __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); };
3325var __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); };
3326var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
3327
3328function WriteShift(t, val, f) {
3329 var size = 0, i = 0;
3330 if(f === 'dbcs') {
3331for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
3332 size = 2 * val.length;
3333 } else if(f === 'sbcs') {
3334 if(typeof cptable !== 'undefined' && current_ansi == 874) {
3335 /* TODO: use tables directly, don't encode */
3336for(i = 0; i != val.length; ++i) {
3337 var cppayload = cptable.utils.encode(current_ansi, val.charAt(i));
3338 this[this.l + i] = cppayload[0];
3339 }
3340 } else {
3341val = val.replace(/[^\x00-\x7F]/g, "_");
3342for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
3343 }
3344 size = val.length;
3345 } else if(f === 'hex') {
3346 for(; i < t; ++i) {
3347this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
3348 } return this;
3349 } else if(f === 'utf16le') {
3350var end = Math.min(this.l + t, this.length);
3351 for(i = 0; i < Math.min(val.length, t); ++i) {
3352 var cc = val.charCodeAt(i);
3353 this[this.l++] = (cc & 0xff);
3354 this[this.l++] = (cc >> 8);
3355 }
3356 while(this.l < end) this[this.l++] = 0;
3357 return this;
3358 } else switch(t) {
3359 case 1: size = 1; this[this.l] = val&0xFF; break;
3360 case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
3361 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;
3362 case 4: size = 4; __writeUInt32LE(this, val, this.l); break;
3363 case 8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
3364 /* falls through */
3365 case 16: break;
3366 case -4: size = 4; __writeInt32LE(this, val, this.l); break;
3367 }
3368 this.l += size; return this;
3369}
3370
3371function CheckField(hexstr, fld) {
3372 var m = __hexlify(this,this.l,hexstr.length>>1);
3373 if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
3374 this.l += hexstr.length>>1;
3375}
3376
3377function prep_blob(blob, pos) {
3378 blob.l = pos;
3379 blob.read_shift = ReadShift;
3380 blob.chk = CheckField;
3381 blob.write_shift = WriteShift;
3382}
3383
3384function parsenoop(blob, length) { blob.l += length; }
3385
3386function new_buf(sz) {
3387 var o = new_raw_buf(sz);
3388 prep_blob(o, 0);
3389 return o;
3390}
3391
3392/* [MS-XLSB] 2.1.4 Record */
3393function recordhopper(data, cb, opts) {
3394 if(!data) return;
3395 var tmpbyte, cntbyte, length;
3396 prep_blob(data, data.l || 0);
3397 var L = data.length, RT = 0, tgt = 0;
3398 while(data.l < L) {
3399 RT = data.read_shift(1);
3400 if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
3401 var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
3402 tmpbyte = data.read_shift(1);
3403 length = tmpbyte & 0x7F;
3404 for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
3405 tgt = data.l + length;
3406 var d = (R.f||parsenoop)(data, length, opts);
3407 data.l = tgt;
3408 if(cb(d, R.n, RT)) return;
3409 }
3410}
3411
3412/* control buffer usage for fixed-length buffers */
3413function buf_array() {
3414 var bufs = [], blksz = has_buf ? 256 : 2048;
3415 var newblk = function ba_newblk(sz) {
3416 var o = (new_buf(sz));
3417 prep_blob(o, 0);
3418 return o;
3419 };
3420
3421 var curbuf = newblk(blksz);
3422
3423 var endbuf = function ba_endbuf() {
3424 if(!curbuf) return;
3425 if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3426 if(curbuf.length > 0) bufs.push(curbuf);
3427 curbuf = null;
3428 };
3429
3430 var next = function ba_next(sz) {
3431 if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
3432 endbuf();
3433 return (curbuf = newblk(Math.max(sz+1, blksz)));
3434 };
3435
3436 var end = function ba_end() {
3437 endbuf();
3438 return __toBuffer([bufs]);
3439 };
3440
3441 var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
3442
3443 return ({ next:next, push:push, end:end, _bufs:bufs });
3444}
3445
3446function write_record(ba, type, payload, length) {
3447 var t = +XLSBRE[type], l;
3448 if(isNaN(t)) return; // TODO: throw something here?
3449 if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
3450 l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
3451 if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
3452 var o = ba.next(l);
3453 if(t <= 0x7F) o.write_shift(1, t);
3454 else {
3455 o.write_shift(1, (t & 0x7F) + 0x80);
3456 o.write_shift(1, (t >> 7));
3457 }
3458 for(var i = 0; i != 4; ++i) {
3459 if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
3460 else { o.write_shift(1, length); break; }
3461 }
3462 if(length > 0 && is_buf(payload)) ba.push(payload);
3463}
3464/* XLS ranges enforced */
3465function shift_cell_xls(cell, tgt, opts) {
3466 var out = dup(cell);
3467 if(tgt.s) {
3468 if(out.cRel) out.c += tgt.s.c;
3469 if(out.rRel) out.r += tgt.s.r;
3470 } else {
3471 if(out.cRel) out.c += tgt.c;
3472 if(out.rRel) out.r += tgt.r;
3473 }
3474 if(!opts || opts.biff < 12) {
3475 while(out.c >= 0x100) out.c -= 0x100;
3476 while(out.r >= 0x10000) out.r -= 0x10000;
3477 }
3478 return out;
3479}
3480
3481function shift_range_xls(cell, range, opts) {
3482 var out = dup(cell);
3483 out.s = shift_cell_xls(out.s, range.s, opts);
3484 out.e = shift_cell_xls(out.e, range.s, opts);
3485 return out;
3486}
3487
3488function encode_cell_xls(c, biff) {
3489 if(c.cRel && c.c < 0) { c = dup(c); while(c.c < 0) c.c += (biff > 8) ? 0x4000 : 0x100; }
3490 if(c.rRel && c.r < 0) { c = dup(c); while(c.r < 0) c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
3491 var s = encode_cell(c);
3492 if(!c.cRel && c.cRel != null) s = fix_col(s);
3493 if(!c.rRel && c.rRel != null) s = fix_row(s);
3494 return s;
3495}
3496
3497function encode_range_xls(r, opts) {
3498 if(r.s.r == 0 && !r.s.rRel) {
3499 if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
3500 return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
3501 }
3502 }
3503 if(r.s.c == 0 && !r.s.cRel) {
3504 if(r.e.c == (opts.biff >= 12 ? 0x3FFF : 0xFF) && !r.e.cRel) {
3505 return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
3506 }
3507 }
3508 return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
3509}
3510var OFFCRYPTO = {};
3511
3512var make_offcrypto = function(O, _crypto) {
3513 var crypto;
3514 if(typeof _crypto !== 'undefined') crypto = _crypto;
3515 else if(typeof require !== 'undefined') {
3516 try { crypto = require('crypto'); }
3517 catch(e) { crypto = null; }
3518 }
3519
3520 O.rc4 = function(key, data) {
3521 var S = new Array(256);
3522 var c = 0, i = 0, j = 0, t = 0;
3523 for(i = 0; i != 256; ++i) S[i] = i;
3524 for(i = 0; i != 256; ++i) {
3525 j = (j + S[i] + (key[i%key.length]).charCodeAt(0))&255;
3526 t = S[i]; S[i] = S[j]; S[j] = t;
3527 }
3528 // $FlowIgnore
3529 i = j = 0; var out = Buffer(data.length);
3530 for(c = 0; c != data.length; ++c) {
3531 i = (i + 1)&255;
3532 j = (j + S[i])%256;
3533 t = S[i]; S[i] = S[j]; S[j] = t;
3534 out[c] = (data[c] ^ S[(S[i]+S[j])&255]);
3535 }
3536 return out;
3537 };
3538
3539 O.md5 = function(hex) {
3540 if(!crypto) throw new Error("Unsupported crypto");
3541 return crypto.createHash('md5').update(hex).digest('hex');
3542 };
3543};
3544/*global crypto:true */
3545make_offcrypto(OFFCRYPTO, typeof crypto !== "undefined" ? crypto : undefined);
3546
3547function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
3548function encode_row(row) { return "" + (row + 1); }
3549function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
3550function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
3551
3552function 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; }
3553function encode_col(col) { if(col < 0) throw new Error("invalid column " + col); var s=""; for(++col; col; col=Math.floor((col-1)/26)) s = String.fromCharCode(((col-1)%26) + 65) + s; return s; }
3554function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
3555function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
3556
3557function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
3558function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
3559function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
3560function decode_range(range) { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
3561function encode_range(cs,ce) {
3562 if(typeof ce === 'undefined' || typeof ce === 'number') {
3563return encode_range(cs.s, cs.e);
3564 }
3565if(typeof cs !== 'string') cs = encode_cell((cs));
3566 if(typeof ce !== 'string') ce = encode_cell((ce));
3567return cs == ce ? cs : cs + ":" + ce;
3568}
3569
3570function safe_decode_range(range) {
3571 var o = {s:{c:0,r:0},e:{c:0,r:0}};
3572 var idx = 0, i = 0, cc = 0;
3573 var len = range.length;
3574 for(idx = 0; i < len; ++i) {
3575 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3576 idx = 26*idx + cc;
3577 }
3578 o.s.c = --idx;
3579
3580 for(idx = 0; i < len; ++i) {
3581 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3582 idx = 10*idx + cc;
3583 }
3584 o.s.r = --idx;
3585
3586 if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
3587
3588 for(idx = 0; i != len; ++i) {
3589 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3590 idx = 26*idx + cc;
3591 }
3592 o.e.c = --idx;
3593
3594 for(idx = 0; i != len; ++i) {
3595 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3596 idx = 10*idx + cc;
3597 }
3598 o.e.r = --idx;
3599 return o;
3600}
3601
3602function safe_format_cell(cell, v) {
3603 var q = (cell.t == 'd' && v instanceof Date);
3604 if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
3605 try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
3606}
3607
3608function format_cell(cell, v, o) {
3609 if(cell == null || cell.t == null || cell.t == 'z') return "";
3610 if(cell.w !== undefined) return cell.w;
3611 if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
3612 if(v == undefined) return safe_format_cell(cell, cell.v);
3613 return safe_format_cell(cell, v);
3614}
3615
3616function sheet_to_workbook(sheet, opts) {
3617 var n = opts && opts.sheet ? opts.sheet : "Sheet1";
3618 var sheets = {}; sheets[n] = sheet;
3619 return { SheetNames: [n], Sheets: sheets };
3620}
3621
3622function sheet_add_aoa(_ws, data, opts) {
3623 var o = opts || {};
3624 var dense = _ws ? Array.isArray(_ws) : o.dense;
3625 if(DENSE != null && dense == null) dense = DENSE;
3626 var ws = _ws || (dense ? ([]) : ({}));
3627 var _R = 0, _C = 0;
3628 if(ws && o.origin != null) {
3629 if(typeof o.origin == 'number') _R = o.origin;
3630 else {
3631 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
3632 _R = _origin.r; _C = _origin.c;
3633 }
3634 }
3635 var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
3636 if(ws['!ref']) {
3637 var _range = safe_decode_range(ws['!ref']);
3638 range.s.c = _range.s.c;
3639 range.s.r = _range.s.r;
3640 range.e.c = Math.max(range.e.c, _range.e.c);
3641 range.e.r = Math.max(range.e.r, _range.e.r);
3642 if(_R == -1) range.e.r = _R = _range.e.r + 1;
3643 }
3644 for(var R = 0; R != data.length; ++R) {
3645 if(!data[R]) continue;
3646 if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
3647 for(var C = 0; C != data[R].length; ++C) {
3648 if(typeof data[R][C] === 'undefined') continue;
3649 var cell = ({v: data[R][C] });
3650 var __R = _R + R, __C = _C + C;
3651 if(range.s.r > __R) range.s.r = __R;
3652 if(range.s.c > __C) range.s.c = __C;
3653 if(range.e.r < __R) range.e.r = __R;
3654 if(range.e.c < __C) range.e.c = __C;
3655 if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
3656 else {
3657 if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
3658 if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.sheetStubs) continue; else cell.t = 'z'; }
3659 else if(typeof cell.v === 'number') cell.t = 'n';
3660 else if(typeof cell.v === 'boolean') cell.t = 'b';
3661 else if(cell.v instanceof Date) {
3662 cell.z = o.dateNF || SSF._table[14];
3663 if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
3664 else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
3665 }
3666 else cell.t = 's';
3667 }
3668 if(dense) {
3669 if(!ws[__R]) ws[__R] = [];
3670 if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z;
3671 ws[__R][__C] = cell;
3672 } else {
3673 var cell_ref = encode_cell(({c:__C,r:__R}));
3674 if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z;
3675 ws[cell_ref] = cell;
3676 }
3677 }
3678 }
3679 if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
3680 return ws;
3681}
3682function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
3683
3684function write_UInt32LE(x, o) {
3685 if(!o) o = new_buf(4);
3686 o.write_shift(4, x);
3687 return o;
3688}
3689
3690/* [MS-XLSB] 2.5.168 */
3691function parse_XLWideString(data) {
3692 var cchCharacters = data.read_shift(4);
3693 return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, 'dbcs');
3694}
3695function write_XLWideString(data, o) {
3696 var _null = false; if(o == null) { _null = true; o = new_buf(4+2*data.length); }
3697 o.write_shift(4, data.length);
3698 if(data.length > 0) o.write_shift(0, data, 'dbcs');
3699 return _null ? o.slice(0, o.l) : o;
3700}
3701
3702/* [MS-XLSB] 2.5.91 */
3703//function parse_LPWideString(data) {
3704// var cchCharacters = data.read_shift(2);
3705// return cchCharacters === 0 ? "" : data.read_shift(cchCharacters, "utf16le");
3706//}
3707
3708/* [MS-XLSB] 2.5.143 */
3709function parse_StrRun(data) {
3710 return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
3711}
3712function write_StrRun(run, o) {
3713 if(!o) o = new_buf(4);
3714 o.write_shift(2, run.ich || 0);
3715 o.write_shift(2, run.ifnt || 0);
3716 return o;
3717}
3718
3719/* [MS-XLSB] 2.5.121 */
3720function parse_RichStr(data, length) {
3721 var start = data.l;
3722 var flags = data.read_shift(1);
3723 var str = parse_XLWideString(data);
3724 var rgsStrRun = [];
3725 var z = ({ t: str, h: str });
3726 if((flags & 1) !== 0) { /* fRichStr */
3727 /* TODO: formatted string */
3728 var dwSizeStrRun = data.read_shift(4);
3729 for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
3730 z.r = rgsStrRun;
3731 }
3732 else z.r = [{ich:0, ifnt:0}];
3733 //if((flags & 2) !== 0) { /* fExtStr */
3734 // /* TODO: phonetic string */
3735 //}
3736 data.l = start + length;
3737 return z;
3738}
3739function write_RichStr(str, o) {
3740 /* TODO: formatted string */
3741 var _null = false; if(o == null) { _null = true; o = new_buf(15+4*str.t.length); }
3742 o.write_shift(1,0);
3743 write_XLWideString(str.t, o);
3744 return _null ? o.slice(0, o.l) : o;
3745}
3746/* [MS-XLSB] 2.4.328 BrtCommentText (RichStr w/1 run) */
3747var parse_BrtCommentText = parse_RichStr;
3748function write_BrtCommentText(str, o) {
3749 /* TODO: formatted string */
3750 var _null = false; if(o == null) { _null = true; o = new_buf(23+4*str.t.length); }
3751 o.write_shift(1,1);
3752 write_XLWideString(str.t, o);
3753 o.write_shift(4,1);
3754 write_StrRun({ich:0,ifnt:0}, o);
3755 return _null ? o.slice(0, o.l) : o;
3756}
3757
3758/* [MS-XLSB] 2.5.9 */
3759function parse_XLSBCell(data) {
3760 var col = data.read_shift(4);
3761 var iStyleRef = data.read_shift(2);
3762 iStyleRef += data.read_shift(1) <<16;
3763 data.l++; //var fPhShow = data.read_shift(1);
3764 return { c:col, iStyleRef: iStyleRef };
3765}
3766function write_XLSBCell(cell, o) {
3767 if(o == null) o = new_buf(8);
3768 o.write_shift(-4, cell.c);
3769 o.write_shift(3, cell.iStyleRef || cell.s);
3770 o.write_shift(1, 0); /* fPhShow */
3771 return o;
3772}
3773
3774
3775/* [MS-XLSB] 2.5.21 */
3776var parse_XLSBCodeName = parse_XLWideString;
3777var write_XLSBCodeName = write_XLWideString;
3778
3779/* [MS-XLSB] 2.5.166 */
3780function parse_XLNullableWideString(data) {
3781 var cchCharacters = data.read_shift(4);
3782 return cchCharacters === 0 || cchCharacters === 0xFFFFFFFF ? "" : data.read_shift(cchCharacters, 'dbcs');
3783}
3784function write_XLNullableWideString(data, o) {
3785 var _null = false; if(o == null) { _null = true; o = new_buf(127); }
3786 o.write_shift(4, data.length > 0 ? data.length : 0xFFFFFFFF);
3787 if(data.length > 0) o.write_shift(0, data, 'dbcs');
3788 return _null ? o.slice(0, o.l) : o;
3789}
3790
3791/* [MS-XLSB] 2.5.165 */
3792var parse_XLNameWideString = parse_XLWideString;
3793//var write_XLNameWideString = write_XLWideString;
3794
3795/* [MS-XLSB] 2.5.114 */
3796var parse_RelID = parse_XLNullableWideString;
3797var write_RelID = write_XLNullableWideString;
3798
3799
3800/* [MS-XLS] 2.5.217 ; [MS-XLSB] 2.5.122 */
3801function parse_RkNumber(data) {
3802 var b = data.slice(data.l, data.l+4);
3803 var fX100 = (b[0] & 1), fInt = (b[0] & 2);
3804 data.l+=4;
3805 b[0] &= 0xFC; // b[0] &= ~3;
3806 var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
3807 return fX100 ? (RK/100) : RK;
3808}
3809function write_RkNumber(data, o) {
3810 if(o == null) o = new_buf(4);
3811 var fX100 = 0, fInt = 0, d100 = data * 100;
3812 if((data == (data | 0)) && (data >= -(1<<29)) && (data < (1 << 29))) { fInt = 1; }
3813 else if((d100 == (d100 | 0)) && (d100 >= -(1<<29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
3814 if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
3815 else throw new Error("unsupported RkNumber " + data); // TODO
3816}
3817
3818
3819/* [MS-XLSB] 2.5.117 RfX */
3820function parse_RfX(data ) {
3821 var cell = ({s: {}, e: {}});
3822 cell.s.r = data.read_shift(4);
3823 cell.e.r = data.read_shift(4);
3824 cell.s.c = data.read_shift(4);
3825 cell.e.c = data.read_shift(4);
3826 return cell;
3827}
3828function write_RfX(r, o) {
3829 if(!o) o = new_buf(16);
3830 o.write_shift(4, r.s.r);
3831 o.write_shift(4, r.e.r);
3832 o.write_shift(4, r.s.c);
3833 o.write_shift(4, r.e.c);
3834 return o;
3835}
3836
3837/* [MS-XLSB] 2.5.153 UncheckedRfX */
3838var parse_UncheckedRfX = parse_RfX;
3839var write_UncheckedRfX = write_RfX;
3840
3841/* [MS-XLSB] 2.5.155 UncheckedSqRfX */
3842//function parse_UncheckedSqRfX(data) {
3843// var cnt = data.read_shift(4);
3844// var out = [];
3845// for(var i = 0; i < cnt; ++i) {
3846// var rng = parse_UncheckedRfX(data);
3847// out.push(encode_range(rng));
3848// }
3849// return out.join(",");
3850//}
3851//function write_UncheckedSqRfX(sqrfx) {
3852// var parts = sqrfx.split(/\s*,\s*/);
3853// var o = new_buf(4); o.write_shift(4, parts.length);
3854// var out = [o];
3855// parts.forEach(function(rng) {
3856// out.push(write_UncheckedRfX(safe_decode_range(rng)));
3857// });
3858// return bconcat(out);
3859//}
3860
3861/* [MS-XLS] 2.5.342 ; [MS-XLSB] 2.5.171 */
3862/* TODO: error checking, NaN and Infinity values are not valid Xnum */
3863function parse_Xnum(data) { return data.read_shift(8, 'f'); }
3864function write_Xnum(data, o) { return (o || new_buf(8)).write_shift(8, data, 'f'); }
3865
3866/* [MS-XLSB] 2.5.97.2 */
3867var BErr = {
38680x00: "#NULL!",
38690x07: "#DIV/0!",
38700x0F: "#VALUE!",
38710x17: "#REF!",
38720x1D: "#NAME?",
38730x24: "#NUM!",
38740x2A: "#N/A",
38750x2B: "#GETTING_DATA",
38760xFF: "#WTF?"
3877};
3878var RBErr = evert_num(BErr);
3879
3880/* [MS-XLSB] 2.4.324 BrtColor */
3881function parse_BrtColor(data) {
3882 var out = {};
3883 var d = data.read_shift(1);
3884
3885 //var fValidRGB = d & 1;
3886 var xColorType = d >>> 1;
3887
3888 var index = data.read_shift(1);
3889 var nTS = data.read_shift(2, 'i');
3890 var bR = data.read_shift(1);
3891 var bG = data.read_shift(1);
3892 var bB = data.read_shift(1);
3893 data.l++; //var bAlpha = data.read_shift(1);
3894
3895 switch(xColorType) {
3896 case 0: out.auto = 1; break;
3897 case 1:
3898 out.index = index;
3899 var icv = XLSIcv[index];
3900 /* automatic pseudo index 81 */
3901 if(icv) out.rgb = rgb2Hex(icv);
3902 break;
3903 case 2:
3904 /* if(!fValidRGB) throw new Error("invalid"); */
3905 out.rgb = rgb2Hex([bR, bG, bB]);
3906 break;
3907 case 3: out.theme = index; break;
3908 }
3909 if(nTS != 0) out.tint = nTS > 0 ? nTS / 32767 : nTS / 32768;
3910
3911 return out;
3912}
3913function write_BrtColor(color, o) {
3914 if(!o) o = new_buf(8);
3915 if(!color||color.auto) { o.write_shift(4, 0); o.write_shift(4, 0); return o; }
3916 if(color.index != null) {
3917 o.write_shift(1, 0x02);
3918 o.write_shift(1, color.index);
3919 } else if(color.theme != null) {
3920 o.write_shift(1, 0x06);
3921 o.write_shift(1, color.theme);
3922 } else {
3923 o.write_shift(1, 0x05);
3924 o.write_shift(1, 0);
3925 }
3926 var nTS = color.tint || 0;
3927 if(nTS > 0) nTS *= 32767;
3928 else if(nTS < 0) nTS *= 32768;
3929 o.write_shift(2, nTS);
3930 if(!color.rgb || color.theme != null) {
3931 o.write_shift(2, 0);
3932 o.write_shift(1, 0);
3933 o.write_shift(1, 0);
3934 } else {
3935 var rgb = (color.rgb || 'FFFFFF');
3936 if(typeof rgb == 'number') rgb = ("000000" + rgb.toString(16)).slice(-6);
3937 o.write_shift(1, parseInt(rgb.slice(0,2),16));
3938 o.write_shift(1, parseInt(rgb.slice(2,4),16));
3939 o.write_shift(1, parseInt(rgb.slice(4,6),16));
3940 o.write_shift(1, 0xFF);
3941 }
3942 return o;
3943}
3944
3945/* [MS-XLSB] 2.5.52 */
3946function parse_FontFlags(data) {
3947 var d = data.read_shift(1);
3948 data.l++;
3949 var out = {
3950 fBold: d & 0x01,
3951 fItalic: d & 0x02,
3952 fUnderline: d & 0x04,
3953 fStrikeout: d & 0x08,
3954 fOutline: d & 0x10,
3955 fShadow: d & 0x20,
3956 fCondense: d & 0x40,
3957 fExtend: d & 0x80
3958 };
3959 return out;
3960}
3961function write_FontFlags(font, o) {
3962 if(!o) o = new_buf(2);
3963 var grbit =
3964 (font.italic ? 0x02 : 0) |
3965 (font.strike ? 0x08 : 0) |
3966 (font.outline ? 0x10 : 0) |
3967 (font.shadow ? 0x20 : 0) |
3968 (font.condense ? 0x40 : 0) |
3969 (font.extend ? 0x80 : 0);
3970 o.write_shift(1, grbit);
3971 o.write_shift(1, 0);
3972 return o;
3973}
3974
3975/* [MS-OLEDS] 2.3.1 and 2.3.2 */
3976function parse_ClipboardFormatOrString(o, w) {
3977 // $FlowIgnore
3978 var ClipFmt = {2:"BITMAP",3:"METAFILEPICT",8:"DIB",14:"ENHMETAFILE"};
3979 var m = o.read_shift(4);
3980 switch(m) {
3981 case 0x00000000: return "";
3982 case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)]||"";
3983 }
3984 if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16));
3985 o.l -= 4;
3986 return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr");
3987}
3988function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); }
3989function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); }
3990
3991/* [MS-OLEPS] 2.2 PropertyType */
3992//var VT_EMPTY = 0x0000;
3993//var VT_NULL = 0x0001;
3994var VT_I2 = 0x0002;
3995var VT_I4 = 0x0003;
3996//var VT_R4 = 0x0004;
3997//var VT_R8 = 0x0005;
3998//var VT_CY = 0x0006;
3999//var VT_DATE = 0x0007;
4000//var VT_BSTR = 0x0008;
4001//var VT_ERROR = 0x000A;
4002var VT_BOOL = 0x000B;
4003var VT_VARIANT = 0x000C;
4004//var VT_DECIMAL = 0x000E;
4005//var VT_I1 = 0x0010;
4006//var VT_UI1 = 0x0011;
4007//var VT_UI2 = 0x0012;
4008var VT_UI4 = 0x0013;
4009//var VT_I8 = 0x0014;
4010//var VT_UI8 = 0x0015;
4011//var VT_INT = 0x0016;
4012//var VT_UINT = 0x0017;
4013var VT_LPSTR = 0x001E;
4014//var VT_LPWSTR = 0x001F;
4015var VT_FILETIME = 0x0040;
4016var VT_BLOB = 0x0041;
4017//var VT_STREAM = 0x0042;
4018//var VT_STORAGE = 0x0043;
4019//var VT_STREAMED_Object = 0x0044;
4020//var VT_STORED_Object = 0x0045;
4021//var VT_BLOB_Object = 0x0046;
4022var VT_CF = 0x0047;
4023//var VT_CLSID = 0x0048;
4024//var VT_VERSIONED_STREAM = 0x0049;
4025var VT_VECTOR = 0x1000;
4026//var VT_ARRAY = 0x2000;
4027
4028var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
4029var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
4030var VT_CUSTOM = [VT_STRING, VT_USTR];
4031
4032/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
4033var DocSummaryPIDDSI = {
40340x01: { n: 'CodePage', t: VT_I2 },
40350x02: { n: 'Category', t: VT_STRING },
40360x03: { n: 'PresentationFormat', t: VT_STRING },
40370x04: { n: 'ByteCount', t: VT_I4 },
40380x05: { n: 'LineCount', t: VT_I4 },
40390x06: { n: 'ParagraphCount', t: VT_I4 },
40400x07: { n: 'SlideCount', t: VT_I4 },
40410x08: { n: 'NoteCount', t: VT_I4 },
40420x09: { n: 'HiddenCount', t: VT_I4 },
40430x0a: { n: 'MultimediaClipCount', t: VT_I4 },
40440x0b: { n: 'ScaleCrop', t: VT_BOOL },
40450x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
40460x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
40470x0e: { n: 'Manager', t: VT_STRING },
40480x0f: { n: 'Company', t: VT_STRING },
40490x10: { n: 'LinksUpToDate', t: VT_BOOL },
40500x11: { n: 'CharacterCount', t: VT_I4 },
40510x13: { n: 'SharedDoc', t: VT_BOOL },
40520x16: { n: 'HyperlinksChanged', t: VT_BOOL },
40530x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
40540x18: { n: 'DigSig', t: VT_BLOB },
40550x1A: { n: 'ContentType', t: VT_STRING },
40560x1B: { n: 'ContentStatus', t: VT_STRING },
40570x1C: { n: 'Language', t: VT_STRING },
40580x1D: { n: 'Version', t: VT_STRING },
40590xFF: {}
4060};
4061
4062/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
4063var SummaryPIDSI = {
40640x01: { n: 'CodePage', t: VT_I2 },
40650x02: { n: 'Title', t: VT_STRING },
40660x03: { n: 'Subject', t: VT_STRING },
40670x04: { n: 'Author', t: VT_STRING },
40680x05: { n: 'Keywords', t: VT_STRING },
40690x06: { n: 'Comments', t: VT_STRING },
40700x07: { n: 'Template', t: VT_STRING },
40710x08: { n: 'LastAuthor', t: VT_STRING },
40720x09: { n: 'RevNumber', t: VT_STRING },
40730x0A: { n: 'EditTime', t: VT_FILETIME },
40740x0B: { n: 'LastPrinted', t: VT_FILETIME },
40750x0C: { n: 'CreatedDate', t: VT_FILETIME },
40760x0D: { n: 'ModifiedDate', t: VT_FILETIME },
40770x0E: { n: 'PageCount', t: VT_I4 },
40780x0F: { n: 'WordCount', t: VT_I4 },
40790x10: { n: 'CharCount', t: VT_I4 },
40800x11: { n: 'Thumbnail', t: VT_CF },
40810x12: { n: 'Application', t: VT_STRING },
40820x13: { n: 'DocSecurity', t: VT_I4 },
40830xFF: {}
4084};
4085
4086/* [MS-OLEPS] 2.18 */
4087var SpecialProperties = {
40880x80000000: { n: 'Locale', t: VT_UI4 },
40890x80000003: { n: 'Behavior', t: VT_UI4 },
40900x72627262: {}
4091};
4092
4093(function() {
4094 for(var y in SpecialProperties) if(Object.prototype.hasOwnProperty.call(SpecialProperties, y))
4095 DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
4096})();
4097
4098var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
4099var SummaryRE = evert_key(SummaryPIDSI, "n");
4100
4101/* [MS-XLS] 2.4.63 Country/Region codes */
4102var CountryEnum = {
41030x0001: "US", // United States
41040x0002: "CA", // Canada
41050x0003: "", // Latin America (except Brazil)
41060x0007: "RU", // Russia
41070x0014: "EG", // Egypt
41080x001E: "GR", // Greece
41090x001F: "NL", // Netherlands
41100x0020: "BE", // Belgium
41110x0021: "FR", // France
41120x0022: "ES", // Spain
41130x0024: "HU", // Hungary
41140x0027: "IT", // Italy
41150x0029: "CH", // Switzerland
41160x002B: "AT", // Austria
41170x002C: "GB", // United Kingdom
41180x002D: "DK", // Denmark
41190x002E: "SE", // Sweden
41200x002F: "NO", // Norway
41210x0030: "PL", // Poland
41220x0031: "DE", // Germany
41230x0034: "MX", // Mexico
41240x0037: "BR", // Brazil
41250x003d: "AU", // Australia
41260x0040: "NZ", // New Zealand
41270x0042: "TH", // Thailand
41280x0051: "JP", // Japan
41290x0052: "KR", // Korea
41300x0054: "VN", // Viet Nam
41310x0056: "CN", // China
41320x005A: "TR", // Turkey
41330x0069: "JS", // Ramastan
41340x00D5: "DZ", // Algeria
41350x00D8: "MA", // Morocco
41360x00DA: "LY", // Libya
41370x015F: "PT", // Portugal
41380x0162: "IS", // Iceland
41390x0166: "FI", // Finland
41400x01A4: "CZ", // Czech Republic
41410x0376: "TW", // Taiwan
41420x03C1: "LB", // Lebanon
41430x03C2: "JO", // Jordan
41440x03C3: "SY", // Syria
41450x03C4: "IQ", // Iraq
41460x03C5: "KW", // Kuwait
41470x03C6: "SA", // Saudi Arabia
41480x03CB: "AE", // United Arab Emirates
41490x03CC: "IL", // Israel
41500x03CE: "QA", // Qatar
41510x03D5: "IR", // Iran
41520xFFFF: "US" // United States
4153};
4154
4155/* [MS-XLS] 2.5.127 */
4156var XLSFillPattern = [
4157 null,
4158 'solid',
4159 'mediumGray',
4160 'darkGray',
4161 'lightGray',
4162 'darkHorizontal',
4163 'darkVertical',
4164 'darkDown',
4165 'darkUp',
4166 'darkGrid',
4167 'darkTrellis',
4168 'lightHorizontal',
4169 'lightVertical',
4170 'lightDown',
4171 'lightUp',
4172 'lightGrid',
4173 'lightTrellis',
4174 'gray125',
4175 'gray0625'
4176];
4177
4178function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
4179
4180/* [MS-XLS] 2.5.161 */
4181/* [MS-XLSB] 2.5.75 Icv */
4182var _XLSIcv = rgbify([
4183 /* Color Constants */
4184 0x000000,
4185 0xFFFFFF,
4186 0xFF0000,
4187 0x00FF00,
4188 0x0000FF,
4189 0xFFFF00,
4190 0xFF00FF,
4191 0x00FFFF,
4192
4193 /* Overridable Defaults */
4194 0x000000,
4195 0xFFFFFF,
4196 0xFF0000,
4197 0x00FF00,
4198 0x0000FF,
4199 0xFFFF00,
4200 0xFF00FF,
4201 0x00FFFF,
4202
4203 0x800000,
4204 0x008000,
4205 0x000080,
4206 0x808000,
4207 0x800080,
4208 0x008080,
4209 0xC0C0C0,
4210 0x808080,
4211 0x9999FF,
4212 0x993366,
4213 0xFFFFCC,
4214 0xCCFFFF,
4215 0x660066,
4216 0xFF8080,
4217 0x0066CC,
4218 0xCCCCFF,
4219
4220 0x000080,
4221 0xFF00FF,
4222 0xFFFF00,
4223 0x00FFFF,
4224 0x800080,
4225 0x800000,
4226 0x008080,
4227 0x0000FF,
4228 0x00CCFF,
4229 0xCCFFFF,
4230 0xCCFFCC,
4231 0xFFFF99,
4232 0x99CCFF,
4233 0xFF99CC,
4234 0xCC99FF,
4235 0xFFCC99,
4236
4237 0x3366FF,
4238 0x33CCCC,
4239 0x99CC00,
4240 0xFFCC00,
4241 0xFF9900,
4242 0xFF6600,
4243 0x666699,
4244 0x969696,
4245 0x003366,
4246 0x339966,
4247 0x003300,
4248 0x333300,
4249 0x993300,
4250 0x993366,
4251 0x333399,
4252 0x333333,
4253
4254 /* Other entries to appease BIFF8/12 */
4255 0xFFFFFF, /* 0x40 icvForeground ?? */
4256 0x000000, /* 0x41 icvBackground ?? */
4257 0x000000, /* 0x42 icvFrame ?? */
4258 0x000000, /* 0x43 icv3D ?? */
4259 0x000000, /* 0x44 icv3DText ?? */
4260 0x000000, /* 0x45 icv3DHilite ?? */
4261 0x000000, /* 0x46 icv3DShadow ?? */
4262 0x000000, /* 0x47 icvHilite ?? */
4263 0x000000, /* 0x48 icvCtlText ?? */
4264 0x000000, /* 0x49 icvCtlScrl ?? */
4265 0x000000, /* 0x4A icvCtlInv ?? */
4266 0x000000, /* 0x4B icvCtlBody ?? */
4267 0x000000, /* 0x4C icvCtlFrame ?? */
4268 0x000000, /* 0x4D icvCtlFore ?? */
4269 0x000000, /* 0x4E icvCtlBack ?? */
4270 0x000000, /* 0x4F icvCtlNeutral */
4271 0x000000, /* 0x50 icvInfoBk ?? */
4272 0x000000 /* 0x51 icvInfoText ?? */
4273]);
4274var XLSIcv = dup(_XLSIcv);
4275/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
4276/* 12.3 Part Summary <SpreadsheetML> */
4277/* 14.2 Part Summary <DrawingML> */
4278/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
4279var ct2type/*{[string]:string}*/ = ({
4280 /* Workbook */
4281 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
4282
4283 /* Worksheet */
4284 "application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
4285
4286 /* Macrosheet */
4287 "application/vnd.ms-excel.intlmacrosheet": "TODO",
4288 "application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
4289
4290 /* File Properties */
4291 "application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
4292 "application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
4293 "application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
4294
4295 /* Custom Data Properties */
4296 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
4297 "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
4298
4299 /* PivotTable */
4300 "application/vnd.ms-excel.pivotTable": "TODO",
4301 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
4302
4303 /* Chart Objects */
4304 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
4305
4306 /* Chart Colors */
4307 "application/vnd.ms-office.chartcolorstyle+xml": "TODO",
4308
4309 /* Chart Style */
4310 "application/vnd.ms-office.chartstyle+xml": "TODO",
4311
4312 /* Chart Advanced */
4313 "application/vnd.ms-office.chartex+xml": "TODO",
4314
4315 /* Calculation Chain */
4316 "application/vnd.ms-excel.calcChain": "calcchains",
4317 "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
4318
4319 /* Printer Settings */
4320 "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
4321
4322 /* ActiveX */
4323 "application/vnd.ms-office.activeX": "TODO",
4324 "application/vnd.ms-office.activeX+xml": "TODO",
4325
4326 /* Custom Toolbars */
4327 "application/vnd.ms-excel.attachedToolbars": "TODO",
4328
4329 /* External Data Connections */
4330 "application/vnd.ms-excel.connections": "TODO",
4331 "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
4332
4333 /* External Links */
4334 "application/vnd.ms-excel.externalLink": "links",
4335 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
4336
4337 /* Metadata */
4338 "application/vnd.ms-excel.sheetMetadata": "TODO",
4339 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
4340
4341 /* PivotCache */
4342 "application/vnd.ms-excel.pivotCacheDefinition": "TODO",
4343 "application/vnd.ms-excel.pivotCacheRecords": "TODO",
4344 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
4345 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
4346
4347 /* Query Table */
4348 "application/vnd.ms-excel.queryTable": "TODO",
4349 "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
4350
4351 /* Shared Workbook */
4352 "application/vnd.ms-excel.userNames": "TODO",
4353 "application/vnd.ms-excel.revisionHeaders": "TODO",
4354 "application/vnd.ms-excel.revisionLog": "TODO",
4355 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
4356 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
4357 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
4358
4359 /* Single Cell Table */
4360 "application/vnd.ms-excel.tableSingleCells": "TODO",
4361 "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
4362
4363 /* Slicer */
4364 "application/vnd.ms-excel.slicer": "TODO",
4365 "application/vnd.ms-excel.slicerCache": "TODO",
4366 "application/vnd.ms-excel.slicer+xml": "TODO",
4367 "application/vnd.ms-excel.slicerCache+xml": "TODO",
4368
4369 /* Sort Map */
4370 "application/vnd.ms-excel.wsSortMap": "TODO",
4371
4372 /* Table */
4373 "application/vnd.ms-excel.table": "TODO",
4374 "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
4375
4376 /* Themes */
4377 "application/vnd.openxmlformats-officedocument.theme+xml": "themes",
4378
4379 /* Theme Override */
4380 "application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
4381
4382 /* Timeline */
4383 "application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
4384 "application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
4385
4386 /* VBA */
4387 "application/vnd.ms-office.vbaProject": "vba",
4388 "application/vnd.ms-office.vbaProjectSignature": "vba",
4389
4390 /* Volatile Dependencies */
4391 "application/vnd.ms-office.volatileDependencies": "TODO",
4392 "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
4393
4394 /* Control Properties */
4395 "application/vnd.ms-excel.controlproperties+xml": "TODO",
4396
4397 /* Data Model */
4398 "application/vnd.openxmlformats-officedocument.model+data": "TODO",
4399
4400 /* Survey */
4401 "application/vnd.ms-excel.Survey+xml": "TODO",
4402
4403 /* Drawing */
4404 "application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
4405 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
4406 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
4407 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
4408 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
4409 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
4410
4411 /* VML */
4412 "application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
4413
4414 "application/vnd.openxmlformats-package.relationships+xml": "rels",
4415 "application/vnd.openxmlformats-officedocument.oleObject": "TODO",
4416
4417 /* Image */
4418 "image/png": "TODO",
4419
4420 "sheet": "js"
4421});
4422
4423var CT_LIST = (function(){
4424 var o = {
4425 workbooks: {
4426 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
4427 xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
4428 xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
4429 xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
4430 xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
4431 },
4432 strs: { /* Shared Strings */
4433 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
4434 xlsb: "application/vnd.ms-excel.sharedStrings"
4435 },
4436 comments: { /* Comments */
4437 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
4438 xlsb: "application/vnd.ms-excel.comments"
4439 },
4440 sheets: { /* Worksheet */
4441 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
4442 xlsb: "application/vnd.ms-excel.worksheet"
4443 },
4444 charts: { /* Chartsheet */
4445 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
4446 xlsb: "application/vnd.ms-excel.chartsheet"
4447 },
4448 dialogs: { /* Dialogsheet */
4449 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
4450 xlsb: "application/vnd.ms-excel.dialogsheet"
4451 },
4452 macros: { /* Macrosheet (Excel 4.0 Macros) */
4453 xlsx: "application/vnd.ms-excel.macrosheet+xml",
4454 xlsb: "application/vnd.ms-excel.macrosheet"
4455 },
4456 styles: { /* Styles */
4457 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
4458 xlsb: "application/vnd.ms-excel.styles"
4459 }
4460 };
4461 keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
4462 keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
4463 return o;
4464})();
4465
4466var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
4467
4468XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
4469
4470function new_ct() {
4471 return ({
4472 workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
4473 rels:[], strs:[], comments:[], links:[],
4474 coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
4475 calcchains:[], vba: [], drawings: [],
4476 TODO:[], xmlns: "" });
4477}
4478
4479function parse_ct(data) {
4480 var ct = new_ct();
4481 if(!data || !data.match) return ct;
4482 var ctext = {};
4483 (data.match(tagregex)||[]).forEach(function(x) {
4484 var y = parsexmltag(x);
4485 switch(y[0].replace(nsregex,"<")) {
4486 case '<?xml': break;
4487 case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
4488 case '<Default': ctext[y.Extension] = y.ContentType; break;
4489 case '<Override':
4490 if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
4491 break;
4492 }
4493 });
4494 if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
4495 ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
4496 ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
4497 ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
4498 ct.defaults = ctext;
4499 delete ct.calcchains;
4500 return ct;
4501}
4502
4503var CTYPE_XML_ROOT = writextag('Types', null, {
4504 'xmlns': XMLNS.CT,
4505 'xmlns:xsd': XMLNS.xsd,
4506 'xmlns:xsi': XMLNS.xsi
4507});
4508
4509var CTYPE_DEFAULTS = [
4510 ['xml', 'application/xml'],
4511 ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
4512 ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
4513 ['data', 'application/vnd.openxmlformats-officedocument.model+data'],
4514 /* from test files */
4515 ['bmp', 'image/bmp'],
4516 ['png', 'image/png'],
4517 ['gif', 'image/gif'],
4518 ['emf', 'image/x-emf'],
4519 ['wmf', 'image/x-wmf'],
4520 ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
4521 ['tif', 'image/tiff'], ['tiff', 'image/tiff'],
4522 ['pdf', 'application/pdf'],
4523 ['rels', type2ct.rels[0]]
4524].map(function(x) {
4525 return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
4526});
4527
4528function write_ct(ct, opts) {
4529 var o = [], v;
4530 o[o.length] = (XML_HEADER);
4531 o[o.length] = (CTYPE_XML_ROOT);
4532 o = o.concat(CTYPE_DEFAULTS);
4533
4534 /* only write first instance */
4535 var f1 = function(w) {
4536 if(ct[w] && ct[w].length > 0) {
4537 v = ct[w][0];
4538 o[o.length] = (writextag('Override', null, {
4539 'PartName': (v[0] == '/' ? "":"/") + v,
4540 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4541 }));
4542 }
4543 };
4544
4545 /* book type-specific */
4546 var f2 = function(w) {
4547 (ct[w]||[]).forEach(function(v) {
4548 o[o.length] = (writextag('Override', null, {
4549 'PartName': (v[0] == '/' ? "":"/") + v,
4550 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4551 }));
4552 });
4553 };
4554
4555 /* standard type */
4556 var f3 = function(t) {
4557 (ct[t]||[]).forEach(function(v) {
4558 o[o.length] = (writextag('Override', null, {
4559 'PartName': (v[0] == '/' ? "":"/") + v,
4560 'ContentType': type2ct[t][0]
4561 }));
4562 });
4563 };
4564
4565 f1('workbooks');
4566 f2('sheets');
4567 f2('charts');
4568 f3('themes');
4569 ['strs', 'styles'].forEach(f1);
4570 ['coreprops', 'extprops', 'custprops'].forEach(f3);
4571 f3('vba');
4572 f3('comments');
4573 f3('drawings');
4574 if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
4575 return o.join("");
4576}
4577/* 9.3 Relationships */
4578var RELS = ({
4579 WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4580 SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4581 HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
4582 VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
4583 XPATH: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",
4584 XMISS: "http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",
4585 XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
4586 VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
4587});
4588
4589/* 9.3.3 Representing Relationships */
4590function get_rels_path(file) {
4591 var n = file.lastIndexOf("/");
4592 return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
4593}
4594
4595function parse_rels(data, currentFilePath) {
4596 var rels = {"!id":{}};
4597 if (!data) return rels;
4598 if (currentFilePath.charAt(0) !== '/') {
4599 currentFilePath = '/'+currentFilePath;
4600 }
4601 var hash = {};
4602
4603 (data.match(tagregex)||[]).forEach(function(x) {
4604 var y = parsexmltag(x);
4605 /* 9.3.2.2 OPC_Relationships */
4606 if (y[0] === '<Relationship') {
4607 var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
4608 var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
4609 rels[canonictarget] = rel;
4610 hash[y.Id] = rel;
4611 }
4612 });
4613 rels["!id"] = hash;
4614 return rels;
4615}
4616
4617XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
4618
4619var RELS_ROOT = writextag('Relationships', null, {
4620 //'xmlns:ns0': XMLNS.RELS,
4621 'xmlns': XMLNS.RELS
4622});
4623
4624/* TODO */
4625function write_rels(rels) {
4626 var o = [XML_HEADER, RELS_ROOT];
4627 keys(rels['!id']).forEach(function(rid) {
4628 o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
4629 });
4630 if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
4631 return o.join("");
4632}
4633
4634var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
4635function add_rels(rels, rId, f, type, relobj, targetmode) {
4636 if(!relobj) relobj = {};
4637 if(!rels['!id']) rels['!id'] = {};
4638 if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
4639 relobj.Id = 'rId' + rId;
4640 relobj.Type = type;
4641 relobj.Target = f;
4642 if(targetmode) relobj.TargetMode = targetmode;
4643 else if(RELS_EXTERN.indexOf(relobj.Type) > -1) relobj.TargetMode = "External";
4644 if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
4645 rels['!id'][relobj.Id] = relobj;
4646 rels[('/' + relobj.Target).replace("//","/")] = relobj;
4647 return rId;
4648}
4649/* Open Document Format for Office Applications (OpenDocument) Version 1.2 */
4650/* Part 3 Section 4 Manifest File */
4651var CT_ODS = "application/vnd.oasis.opendocument.spreadsheet";
4652function parse_manifest(d, opts) {
4653 var str = xlml_normalize(d);
4654 var Rn;
4655 var FEtag;
4656 while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
4657 case 'manifest': break; // 4.2 <manifest:manifest>
4658 case 'file-entry': // 4.3 <manifest:file-entry>
4659 FEtag = parsexmltag(Rn[0], false);
4660 if(FEtag.path == '/' && FEtag.type !== CT_ODS) throw new Error("This OpenDocument is not a spreadsheet");
4661 break;
4662 case 'encryption-data': // 4.4 <manifest:encryption-data>
4663 case 'algorithm': // 4.5 <manifest:algorithm>
4664 case 'start-key-generation': // 4.6 <manifest:start-key-generation>
4665 case 'key-derivation': // 4.7 <manifest:key-derivation>
4666 throw new Error("Unsupported ODS Encryption");
4667 default: if(opts && opts.WTF) throw Rn;
4668 }
4669}
4670
4671function write_manifest(manifest) {
4672 var o = [XML_HEADER];
4673 o.push('<manifest:manifest xmlns:manifest="urn:oasis:names:tc:opendocument:xmlns:manifest:1.0" manifest:version="1.2">\n');
4674 o.push(' <manifest:file-entry manifest:full-path="/" manifest:version="1.2" manifest:media-type="application/vnd.oasis.opendocument.spreadsheet"/>\n');
4675 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');
4676 o.push('</manifest:manifest>');
4677 return o.join("");
4678}
4679
4680/* Part 3 Section 6 Metadata Manifest File */
4681function write_rdf_type(file, res, tag) {
4682 return [
4683 ' <rdf:Description rdf:about="' + file + '">\n',
4684 ' <rdf:type rdf:resource="http://docs.oasis-open.org/ns/office/1.2/meta/' + (tag || "odf") + '#' + res + '"/>\n',
4685 ' </rdf:Description>\n'
4686 ].join("");
4687}
4688function write_rdf_has(base, file) {
4689 return [
4690 ' <rdf:Description rdf:about="' + base + '">\n',
4691 ' <ns0:hasPart xmlns:ns0="http://docs.oasis-open.org/ns/office/1.2/meta/pkg#" rdf:resource="' + file + '"/>\n',
4692 ' </rdf:Description>\n'
4693 ].join("");
4694}
4695function write_rdf(rdf) {
4696 var o = [XML_HEADER];
4697 o.push('<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#">\n');
4698 for(var i = 0; i != rdf.length; ++i) {
4699 o.push(write_rdf_type(rdf[i][0], rdf[i][1]));
4700 o.push(write_rdf_has("",rdf[i][0]));
4701 }
4702 o.push(write_rdf_type("","Document", "pkg"));
4703 o.push('</rdf:RDF>');
4704 return o.join("");
4705}
4706/* TODO: pull properties */
4707var write_meta_ods = (function() {
4708 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>';
4709 return function wmo() {
4710 return payload;
4711 };
4712})();
4713
4714/* ECMA-376 Part II 11.1 Core Properties Part */
4715/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4716var CORE_PROPS = [
4717 ["cp:category", "Category"],
4718 ["cp:contentStatus", "ContentStatus"],
4719 ["cp:keywords", "Keywords"],
4720 ["cp:lastModifiedBy", "LastAuthor"],
4721 ["cp:lastPrinted", "LastPrinted"],
4722 ["cp:revision", "RevNumber"],
4723 ["cp:version", "Version"],
4724 ["dc:creator", "Author"],
4725 ["dc:description", "Comments"],
4726 ["dc:identifier", "Identifier"],
4727 ["dc:language", "Language"],
4728 ["dc:subject", "Subject"],
4729 ["dc:title", "Title"],
4730 ["dcterms:created", "CreatedDate", 'date'],
4731 ["dcterms:modified", "ModifiedDate", 'date']
4732];
4733
4734XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
4735RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
4736
4737var CORE_PROPS_REGEX = (function() {
4738 var r = new Array(CORE_PROPS.length);
4739 for(var i = 0; i < CORE_PROPS.length; ++i) {
4740 var f = CORE_PROPS[i];
4741 var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
4742 r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
4743 }
4744 return r;
4745})();
4746
4747function parse_core_props(data) {
4748 var p = {};
4749 data = utf8read(data);
4750
4751 for(var i = 0; i < CORE_PROPS.length; ++i) {
4752 var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4753 if(cur != null && cur.length > 0) p[f[1]] = unescapexml(cur[1]);
4754 if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4755 }
4756
4757 return p;
4758}
4759
4760var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4761 //'xmlns': XMLNS.CORE_PROPS,
4762 'xmlns:cp': XMLNS.CORE_PROPS,
4763 'xmlns:dc': XMLNS.dc,
4764 'xmlns:dcterms': XMLNS.dcterms,
4765 'xmlns:dcmitype': XMLNS.dcmitype,
4766 'xmlns:xsi': XMLNS.xsi
4767});
4768
4769function cp_doit(f, g, h, o, p) {
4770 if(p[f] != null || g == null || g === "") return;
4771 p[f] = g;
4772 g = escapexml(g);
4773 o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4774}
4775
4776function write_core_props(cp, _opts) {
4777 var opts = _opts || {};
4778 var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4779 if(!cp && !opts.Props) return o.join("");
4780
4781 if(cp) {
4782 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);
4783 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);
4784 }
4785
4786 for(var i = 0; i != CORE_PROPS.length; ++i) {
4787 var f = CORE_PROPS[i];
4788 var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4789 if(v === true) v = "1";
4790 else if(v === false) v = "0";
4791 else if(typeof v == "number") v = String(v);
4792 if(v != null) cp_doit(f[0], v, null, o, p);
4793 }
4794 if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4795 return o.join("");
4796}
4797/* 15.2.12.3 Extended File Properties Part */
4798/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4799var EXT_PROPS = [
4800 ["Application", "Application", "string"],
4801 ["AppVersion", "AppVersion", "string"],
4802 ["Company", "Company", "string"],
4803 ["DocSecurity", "DocSecurity", "string"],
4804 ["Manager", "Manager", "string"],
4805 ["HyperlinksChanged", "HyperlinksChanged", "bool"],
4806 ["SharedDoc", "SharedDoc", "bool"],
4807 ["LinksUpToDate", "LinksUpToDate", "bool"],
4808 ["ScaleCrop", "ScaleCrop", "bool"],
4809 ["HeadingPairs", "HeadingPairs", "raw"],
4810 ["TitlesOfParts", "TitlesOfParts", "raw"]
4811];
4812
4813XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4814RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4815
4816var PseudoPropsPairs = [
4817 "Worksheets", "SheetNames",
4818 "NamedRanges", "DefinedNames",
4819 "Chartsheets", "ChartNames"
4820];
4821function load_props_pairs(HP, TOP, props, opts) {
4822 var v = [];
4823 if(typeof HP == "string") v = parseVector(HP, opts);
4824 else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4825 var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4826 var idx = 0, len = 0;
4827 if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4828 len = +(v[i+1].v);
4829 switch(v[i].v) {
4830 case "Worksheets":
4831 case "工作表":
4832 case "Листы":
4833 case "أوراق العمل":
4834 case "ワークシート":
4835 case "גליונות עבודה":
4836 case "Arbeitsblätter":
4837 case "Çalışma Sayfaları":
4838 case "Feuilles de calcul":
4839 case "Fogli di lavoro":
4840 case "Folhas de cálculo":
4841 case "Planilhas":
4842 case "Regneark":
4843 case "Hojas de cálculo":
4844 case "Werkbladen":
4845 props.Worksheets = len;
4846 props.SheetNames = parts.slice(idx, idx + len);
4847 break;
4848
4849 case "Named Ranges":
4850 case "Rangos con nombre":
4851 case "名前付き一覧":
4852 case "Benannte Bereiche":
4853 case "Navngivne områder":
4854 props.NamedRanges = len;
4855 props.DefinedNames = parts.slice(idx, idx + len);
4856 break;
4857
4858 case "Charts":
4859 case "Diagramme":
4860 props.Chartsheets = len;
4861 props.ChartNames = parts.slice(idx, idx + len);
4862 break;
4863 }
4864 idx += len;
4865 }
4866}
4867
4868function parse_ext_props(data, p, opts) {
4869 var q = {}; if(!p) p = {};
4870 data = utf8read(data);
4871
4872 EXT_PROPS.forEach(function(f) {
4873 var xml = (data.match(matchtag(f[0]))||[])[1];
4874 switch(f[2]) {
4875 case "string": p[f[1]] = unescapexml(xml||""); break;
4876 case "bool": p[f[1]] = xml === "true"; break;
4877 case "raw":
4878 var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4879 if(cur && cur.length > 0) q[f[1]] = cur[1];
4880 break;
4881 }
4882 });
4883
4884 if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4885
4886 return p;
4887}
4888
4889var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4890 'xmlns': XMLNS.EXT_PROPS,
4891 'xmlns:vt': XMLNS.vt
4892});
4893
4894function write_ext_props(cp) {
4895 var o = [], W = writextag;
4896 if(!cp) cp = {};
4897 cp.Application = "SheetJS";
4898 o[o.length] = (XML_HEADER);
4899 o[o.length] = (EXT_PROPS_XML_ROOT);
4900
4901 EXT_PROPS.forEach(function(f) {
4902 if(cp[f[1]] === undefined) return;
4903 var v;
4904 switch(f[2]) {
4905 case 'string': v = escapexml(String(cp[f[1]])); break;
4906 case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4907 }
4908 if(v !== undefined) o[o.length] = (W(f[0], v));
4909 });
4910
4911 /* TODO: HeadingPairs, TitlesOfParts */
4912 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"})));
4913 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"})));
4914 if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4915 return o.join("");
4916}
4917/* 15.2.12.2 Custom File Properties Part */
4918XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4919RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4920
4921var custregex = /<[^>]+>[^<]*/g;
4922function parse_cust_props(data, opts) {
4923 var p = {}, name = "";
4924 var m = data.match(custregex);
4925 if(m) for(var i = 0; i != m.length; ++i) {
4926 var x = m[i], y = parsexmltag(x);
4927 switch(y[0]) {
4928 case '<?xml': break;
4929 case '<Properties': break;
4930 case '<property': name = unescapexml(y.name); break;
4931 case '</property>': name = null; break;
4932 default: if (x.indexOf('<vt:') === 0) {
4933 var toks = x.split('>');
4934 var type = toks[0].slice(4), text = toks[1];
4935 /* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4936 switch(type) {
4937 case 'lpstr': case 'bstr': case 'lpwstr':
4938 p[name] = unescapexml(text);
4939 break;
4940 case 'bool':
4941 p[name] = parsexmlbool(text);
4942 break;
4943 case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4944 p[name] = parseInt(text, 10);
4945 break;
4946 case 'r4': case 'r8': case 'decimal':
4947 p[name] = parseFloat(text);
4948 break;
4949 case 'filetime': case 'date':
4950 p[name] = parseDate(text);
4951 break;
4952 case 'cy': case 'error':
4953 p[name] = unescapexml(text);
4954 break;
4955 default:
4956 if(type.slice(-1) == '/') break;
4957 if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4958 }
4959 } else if(x.slice(0,2) === "</") {/* empty */
4960 } else if(opts.WTF) throw new Error(x);
4961 }
4962 }
4963 return p;
4964}
4965
4966var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4967 'xmlns': XMLNS.CUST_PROPS,
4968 'xmlns:vt': XMLNS.vt
4969});
4970
4971function write_cust_props(cp) {
4972 var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4973 if(!cp) return o.join("");
4974 var pid = 1;
4975 keys(cp).forEach(function custprop(k) { ++pid;
4976 o[o.length] = (writextag('property', write_vt(cp[k]), {
4977 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4978 'pid': pid,
4979 'name': escapexml(k)
4980 }));
4981 });
4982 if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4983 return o.join("");
4984}
4985/* Common Name -> XLML Name */
4986var XLMLDocPropsMap = {
4987 Title: 'Title',
4988 Subject: 'Subject',
4989 Author: 'Author',
4990 Keywords: 'Keywords',
4991 Comments: 'Description',
4992 LastAuthor: 'LastAuthor',
4993 RevNumber: 'Revision',
4994 Application: 'AppName',
4995 /* TotalTime: 'TotalTime', */
4996 LastPrinted: 'LastPrinted',
4997 CreatedDate: 'Created',
4998 ModifiedDate: 'LastSaved',
4999 /* Pages */
5000 /* Words */
5001 /* Characters */
5002 Category: 'Category',
5003 /* PresentationFormat */
5004 Manager: 'Manager',
5005 Company: 'Company',
5006 /* Guid */
5007 /* HyperlinkBase */
5008 /* Bytes */
5009 /* Lines */
5010 /* Paragraphs */
5011 /* CharactersWithSpaces */
5012 AppVersion: 'Version',
5013
5014 ContentStatus: 'ContentStatus', /* NOTE: missing from schema */
5015 Identifier: 'Identifier', /* NOTE: missing from schema */
5016 Language: 'Language' /* NOTE: missing from schema */
5017};
5018var evert_XLMLDPM = evert(XLMLDocPropsMap);
5019
5020function xlml_set_prop(Props, tag, val) {
5021 tag = evert_XLMLDPM[tag] || tag;
5022 Props[tag] = val;
5023}
5024
5025function xlml_write_docprops(Props, opts) {
5026 var o = [];
5027 keys(XLMLDocPropsMap).map(function(m) {
5028 for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i];
5029 for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i];
5030 throw m;
5031 }).forEach(function(p) {
5032 if(Props[p[1]] == null) return;
5033 var m = opts && opts.Props && opts.Props[p[1]] != null ? opts.Props[p[1]] : Props[p[1]];
5034 switch(p[2]) {
5035 case 'date': m = new Date(m).toISOString().replace(/\.\d*Z/,"Z"); break;
5036 }
5037 if(typeof m == 'number') m = String(m);
5038 else if(m === true || m === false) { m = m ? "1" : "0"; }
5039 else if(m instanceof Date) m = new Date(m).toISOString().replace(/\.\d*Z/,"");
5040 o.push(writetag(XLMLDocPropsMap[p[1]] || p[1], m));
5041 });
5042 return writextag('DocumentProperties', o.join(""), {xmlns:XLMLNS.o });
5043}
5044function xlml_write_custprops(Props, Custprops) {
5045 var BLACKLIST = ["Worksheets","SheetNames"];
5046 var T = 'CustomDocumentProperties';
5047 var o = [];
5048 if(Props) keys(Props).forEach(function(k) {
5049if(!Object.prototype.hasOwnProperty.call(Props, k)) return;
5050 for(var i = 0; i < CORE_PROPS.length; ++i) if(k == CORE_PROPS[i][1]) return;
5051 for(i = 0; i < EXT_PROPS.length; ++i) if(k == EXT_PROPS[i][1]) return;
5052 for(i = 0; i < BLACKLIST.length; ++i) if(k == BLACKLIST[i]) return;
5053
5054 var m = Props[k];
5055 var t = "string";
5056 if(typeof m == 'number') { t = "float"; m = String(m); }
5057 else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
5058 else m = String(m);
5059 o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
5060 });
5061 if(Custprops) keys(Custprops).forEach(function(k) {
5062if(!Object.prototype.hasOwnProperty.call(Custprops, k)) return;
5063 if(Props && Object.prototype.hasOwnProperty.call(Props, k)) return;
5064 var m = Custprops[k];
5065 var t = "string";
5066 if(typeof m == 'number') { t = "float"; m = String(m); }
5067 else if(m === true || m === false) { t = "boolean"; m = m ? "1" : "0"; }
5068 else if(m instanceof Date) { t = "dateTime.tz"; m = m.toISOString(); }
5069 else m = String(m);
5070 o.push(writextag(escapexmltag(k), m, {"dt:dt":t}));
5071 });
5072 return '<' + T + ' xmlns="' + XLMLNS.o + '">' + o.join("") + '</' + T + '>';
5073}
5074/* [MS-DTYP] 2.3.3 FILETIME */
5075/* [MS-OLEDS] 2.1.3 FILETIME (Packet Version) */
5076/* [MS-OLEPS] 2.8 FILETIME (Packet Version) */
5077function parse_FILETIME(blob) {
5078 var dwLowDateTime = blob.read_shift(4), dwHighDateTime = blob.read_shift(4);
5079 return new Date(((dwHighDateTime/1e7*Math.pow(2,32) + dwLowDateTime/1e7) - 11644473600)*1000).toISOString().replace(/\.000/,"");
5080}
5081function write_FILETIME(time) {
5082 var date = (typeof time == "string") ? new Date(Date.parse(time)) : time;
5083 var t = date.getTime() / 1000 + 11644473600;
5084 var l = t % Math.pow(2,32), h = (t - l) / Math.pow(2,32);
5085 l *= 1e7; h *= 1e7;
5086 var w = (l / Math.pow(2,32)) | 0;
5087 if(w > 0) { l = l % Math.pow(2,32); h += w; }
5088 var o = new_buf(8); o.write_shift(4, l); o.write_shift(4, h); return o;
5089}
5090
5091/* [MS-OSHARED] 2.3.3.1.4 Lpstr */
5092function parse_lpstr(blob, type, pad) {
5093 var start = blob.l;
5094 var str = blob.read_shift(0, 'lpstr-cp');
5095 if(pad) while((blob.l - start) & 3) ++blob.l;
5096 return str;
5097}
5098
5099/* [MS-OSHARED] 2.3.3.1.6 Lpwstr */
5100function parse_lpwstr(blob, type, pad) {
5101 var str = blob.read_shift(0, 'lpwstr');
5102 if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3;
5103 return str;
5104}
5105
5106
5107/* [MS-OSHARED] 2.3.3.1.11 VtString */
5108/* [MS-OSHARED] 2.3.3.1.12 VtUnalignedString */
5109function parse_VtStringBase(blob, stringType, pad) {
5110 if(stringType === 0x1F /*VT_LPWSTR*/) return parse_lpwstr(blob);
5111 return parse_lpstr(blob, stringType, pad);
5112}
5113
5114function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? 0: 4); }
5115function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); }
5116
5117/* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
5118function parse_VtVecUnalignedLpstrValue(blob) {
5119 var length = blob.read_shift(4);
5120 var ret = [];
5121 for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,'');
5122 return ret;
5123}
5124
5125/* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */
5126function parse_VtVecUnalignedLpstr(blob) {
5127 return parse_VtVecUnalignedLpstrValue(blob);
5128}
5129
5130/* [MS-OSHARED] 2.3.3.1.13 VtHeadingPair */
5131function parse_VtHeadingPair(blob) {
5132 var headingString = parse_TypedPropertyValue(blob, VT_USTR);
5133 var headerParts = parse_TypedPropertyValue(blob, VT_I4);
5134 return [headingString, headerParts];
5135}
5136
5137/* [MS-OSHARED] 2.3.3.1.14 VtVecHeadingPairValue */
5138function parse_VtVecHeadingPairValue(blob) {
5139 var cElements = blob.read_shift(4);
5140 var out = [];
5141 for(var i = 0; i != cElements / 2; ++i) out.push(parse_VtHeadingPair(blob));
5142 return out;
5143}
5144
5145/* [MS-OSHARED] 2.3.3.1.15 VtVecHeadingPair */
5146function parse_VtVecHeadingPair(blob) {
5147 // NOTE: When invoked, wType & padding were already consumed
5148 return parse_VtVecHeadingPairValue(blob);
5149}
5150
5151/* [MS-OLEPS] 2.18.1 Dictionary (uses 2.17, 2.16) */
5152function parse_dictionary(blob,CodePage) {
5153 var cnt = blob.read_shift(4);
5154 var dict = ({});
5155 for(var j = 0; j != cnt; ++j) {
5156 var pid = blob.read_shift(4);
5157 var len = blob.read_shift(4);
5158 dict[pid] = blob.read_shift(len, (CodePage === 0x4B0 ?'utf16le':'utf8')).replace(chr0,'').replace(chr1,'!');
5159 if(CodePage === 0x4B0 && (len % 2)) blob.l += 2;
5160 }
5161 if(blob.l & 3) blob.l = (blob.l>>2+1)<<2;
5162 return dict;
5163}
5164
5165/* [MS-OLEPS] 2.9 BLOB */
5166function parse_BLOB(blob) {
5167 var size = blob.read_shift(4);
5168 var bytes = blob.slice(blob.l,blob.l+size);
5169 blob.l += size;
5170 if((size & 3) > 0) blob.l += (4 - (size & 3)) & 3;
5171 return bytes;
5172}
5173
5174/* [MS-OLEPS] 2.11 ClipboardData */
5175function parse_ClipboardData(blob) {
5176 // TODO
5177 var o = {};
5178 o.Size = blob.read_shift(4);
5179 //o.Format = blob.read_shift(4);
5180 blob.l += o.Size + 3 - (o.Size - 1) % 4;
5181 return o;
5182}
5183
5184/* [MS-OLEPS] 2.15 TypedPropertyValue */
5185function parse_TypedPropertyValue(blob, type, _opts) {
5186 var t = blob.read_shift(2), ret, opts = _opts||{};
5187 blob.l += 2;
5188 if(type !== VT_VARIANT)
5189 if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
5190 switch(type === VT_VARIANT ? t : type) {
5191 case 0x02 /*VT_I2*/: ret = blob.read_shift(2, 'i'); if(!opts.raw) blob.l += 2; return ret;
5192 case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
5193 case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
5194 case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
5195 case 0x1E /*VT_LPSTR*/: return parse_lpstr(blob, t, 4).replace(chr0,'');
5196 case 0x1F /*VT_LPWSTR*/: return parse_lpwstr(blob);
5197 case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
5198 case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
5199 case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
5200 case 0x50 /*VT_STRING*/: return parse_VtString(blob, t, !opts.raw).replace(chr0,'');
5201 case 0x51 /*VT_USTR*/: return parse_VtUnalignedString(blob, t/*, 4*/).replace(chr0,'');
5202 case 0x100C /*VT_VECTOR|VT_VARIANT*/: return parse_VtVecHeadingPair(blob);
5203 case 0x101E /*VT_LPSTR*/: return parse_VtVecUnalignedLpstr(blob);
5204 default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + t);
5205 }
5206}
5207function write_TypedPropertyValue(type, value) {
5208 var o = new_buf(4), p = new_buf(4);
5209 o.write_shift(4, type == 0x50 ? 0x1F : type);
5210 switch(type) {
5211 case 0x03 /*VT_I4*/: p.write_shift(-4, value); break;
5212 case 0x05 /*VT_I4*/: p = new_buf(8); p.write_shift(8, value, 'f'); break;
5213 case 0x0B /*VT_BOOL*/: p.write_shift(4, value ? 0x01 : 0x00); break;
5214 case 0x40 /*VT_FILETIME*/: p = write_FILETIME(value); break;
5215 case 0x1F /*VT_LPWSTR*/:
5216 case 0x50 /*VT_STRING*/:
5217p = new_buf(4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
5218 p.write_shift(4, value.length + 1);
5219 p.write_shift(0, value, "dbcs");
5220 while(p.l != p.length) p.write_shift(1, 0);
5221 break;
5222 default: throw new Error("TypedPropertyValue unrecognized type " + type + " " + value);
5223 }
5224 return bconcat([o, p]);
5225}
5226
5227/* [MS-OLEPS] 2.20 PropertySet */
5228function parse_PropertySet(blob, PIDSI) {
5229 var start_addr = blob.l;
5230 var size = blob.read_shift(4);
5231 var NumProps = blob.read_shift(4);
5232 var Props = [], i = 0;
5233 var CodePage = 0;
5234 var Dictionary = -1, DictObj = ({});
5235 for(i = 0; i != NumProps; ++i) {
5236 var PropID = blob.read_shift(4);
5237 var Offset = blob.read_shift(4);
5238 Props[i] = [PropID, Offset + start_addr];
5239 }
5240 Props.sort(function(x,y) { return x[1] - y[1]; });
5241 var PropH = {};
5242 for(i = 0; i != NumProps; ++i) {
5243 if(blob.l !== Props[i][1]) {
5244 var fail = true;
5245 if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
5246 case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break;
5247 case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
5248 case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
5249 }
5250 if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
5251 if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
5252 }
5253 if(PIDSI) {
5254 var piddsi = PIDSI[Props[i][0]];
5255 PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
5256 if(piddsi.p === 'version') PropH[piddsi.n] = String(PropH[piddsi.n] >> 16) + "." + ("0000" + String(PropH[piddsi.n] & 0xFFFF)).slice(-4);
5257 if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
5258 case 0: PropH[piddsi.n] = 1252;
5259 /* falls through */
5260 case 874:
5261 case 932:
5262 case 936:
5263 case 949:
5264 case 950:
5265 case 1250:
5266 case 1251:
5267 case 1253:
5268 case 1254:
5269 case 1255:
5270 case 1256:
5271 case 1257:
5272 case 1258:
5273 case 10000:
5274 case 1200:
5275 case 1201:
5276 case 1252:
5277 case 65000: case -536:
5278 case 65001: case -535:
5279 set_cp(CodePage = (PropH[piddsi.n]>>>0) & 0xFFFF); break;
5280 default: throw new Error("Unsupported CodePage: " + PropH[piddsi.n]);
5281 }
5282 } else {
5283 if(Props[i][0] === 0x1) {
5284 CodePage = PropH.CodePage = (parse_TypedPropertyValue(blob, VT_I2));
5285 set_cp(CodePage);
5286 if(Dictionary !== -1) {
5287 var oldpos = blob.l;
5288 blob.l = Props[Dictionary][1];
5289 DictObj = parse_dictionary(blob,CodePage);
5290 blob.l = oldpos;
5291 }
5292 } else if(Props[i][0] === 0) {
5293 if(CodePage === 0) { Dictionary = i; blob.l = Props[i+1][1]; continue; }
5294 DictObj = parse_dictionary(blob,CodePage);
5295 } else {
5296 var name = DictObj[Props[i][0]];
5297 var val;
5298 /* [MS-OSHARED] 2.3.3.2.3.1.2 + PROPVARIANT */
5299 switch(blob[blob.l]) {
5300 case 0x41 /*VT_BLOB*/: blob.l += 4; val = parse_BLOB(blob); break;
5301 case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
5302 case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/\u0000+$/,""); break;
5303 case 0x03 /*VT_I4*/: blob.l += 4; val = blob.read_shift(4, 'i'); break;
5304 case 0x13 /*VT_UI4*/: blob.l += 4; val = blob.read_shift(4); break;
5305 case 0x05 /*VT_R8*/: blob.l += 4; val = blob.read_shift(8, 'f'); break;
5306 case 0x0B /*VT_BOOL*/: blob.l += 4; val = parsebool(blob, 4); break;
5307 case 0x40 /*VT_FILETIME*/: blob.l += 4; val = parseDate(parse_FILETIME(blob)); break;
5308 default: throw new Error("unparsed value: " + blob[blob.l]);
5309 }
5310 PropH[name] = val;
5311 }
5312 }
5313 }
5314 blob.l = start_addr + size; /* step ahead to skip padding */
5315 return PropH;
5316}
5317var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs);
5318function guess_property_type(val) {
5319 switch(typeof val) {
5320 case "boolean": return 0x0B;
5321 case "number": return ((val|0)==val) ? 0x03 : 0x05;
5322 case "string": return 0x1F;
5323 case "object": if(val instanceof Date) return 0x40; break;
5324 }
5325 return -1;
5326}
5327function write_PropertySet(entries, RE, PIDSI) {
5328 var hdr = new_buf(8), piao = [], prop = [];
5329 var sz = 8, i = 0;
5330
5331 var pr = new_buf(8), pio = new_buf(8);
5332 pr.write_shift(4, 0x0002);
5333 pr.write_shift(4, 0x04B0);
5334 pio.write_shift(4, 0x0001);
5335 prop.push(pr); piao.push(pio);
5336 sz += 8 + pr.length;
5337
5338 if(!RE) {
5339 pio = new_buf(8);
5340 pio.write_shift(4, 0);
5341 piao.unshift(pio);
5342
5343 var bufs = [new_buf(4)];
5344 bufs[0].write_shift(4, entries.length);
5345 for(i = 0; i < entries.length; ++i) {
5346 var value = entries[i][0];
5347 pr = new_buf(4 + 4 + 2 * (value.length + 1) + (value.length % 2 ? 0 : 2));
5348 pr.write_shift(4, i+2);
5349 pr.write_shift(4, value.length + 1);
5350 pr.write_shift(0, value, "dbcs");
5351 while(pr.l != pr.length) pr.write_shift(1, 0);
5352 bufs.push(pr);
5353 }
5354 pr = bconcat(bufs);
5355 prop.unshift(pr);
5356 sz += 8 + pr.length;
5357 }
5358
5359 for(i = 0; i < entries.length; ++i) {
5360 if(RE && !RE[entries[i][0]]) continue;
5361 if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue;
5362 if(entries[i][1] == null) continue;
5363
5364 var val = entries[i][1], idx = 0;
5365 if(RE) {
5366 idx = +RE[entries[i][0]];
5367 var pinfo = (PIDSI)[idx];
5368 if(pinfo.p == "version" && typeof val == "string") {
5369var arr = val.split(".");
5370 val = ((+arr[0])<<16) + ((+arr[1])||0);
5371 }
5372 pr = write_TypedPropertyValue(pinfo.t, val);
5373 } else {
5374 var T = guess_property_type(val);
5375 if(T == -1) { T = 0x1F; val = String(val); }
5376 pr = write_TypedPropertyValue(T, val);
5377 }
5378 prop.push(pr);
5379
5380 pio = new_buf(8);
5381 pio.write_shift(4, !RE ? 2+i : idx);
5382 piao.push(pio);
5383
5384 sz += 8 + pr.length;
5385 }
5386
5387 var w = 8 * (prop.length + 1);
5388 for(i = 0; i < prop.length; ++i) { piao[i].write_shift(4, w); w += prop[i].length; }
5389 hdr.write_shift(4, sz);
5390 hdr.write_shift(4, prop.length);
5391 return bconcat([hdr].concat(piao).concat(prop));
5392}
5393
5394/* [MS-OLEPS] 2.21 PropertySetStream */
5395function parse_PropertySetStream(file, PIDSI, clsid) {
5396 var blob = file.content;
5397 if(!blob) return ({});
5398 prep_blob(blob, 0);
5399
5400 var NumSets, FMTID0, FMTID1, Offset0, Offset1 = 0;
5401 blob.chk('feff', 'Byte Order: ');
5402
5403 /*var vers = */blob.read_shift(2); // TODO: check version
5404 var SystemIdentifier = blob.read_shift(4);
5405 var CLSID = blob.read_shift(16);
5406 if(CLSID !== CFB.utils.consts.HEADER_CLSID && CLSID !== clsid) throw new Error("Bad PropertySet CLSID " + CLSID);
5407 NumSets = blob.read_shift(4);
5408 if(NumSets !== 1 && NumSets !== 2) throw new Error("Unrecognized #Sets: " + NumSets);
5409 FMTID0 = blob.read_shift(16); Offset0 = blob.read_shift(4);
5410
5411 if(NumSets === 1 && Offset0 !== blob.l) throw new Error("Length mismatch: " + Offset0 + " !== " + blob.l);
5412 else if(NumSets === 2) { FMTID1 = blob.read_shift(16); Offset1 = blob.read_shift(4); }
5413 var PSet0 = parse_PropertySet(blob, PIDSI);
5414
5415 var rval = ({ SystemIdentifier: SystemIdentifier });
5416 for(var y in PSet0) rval[y] = PSet0[y];
5417 //rval.blob = blob;
5418 rval.FMTID = FMTID0;
5419 //rval.PSet0 = PSet0;
5420 if(NumSets === 1) return rval;
5421 if(Offset1 - blob.l == 2) blob.l += 2;
5422 if(blob.l !== Offset1) throw new Error("Length mismatch 2: " + blob.l + " !== " + Offset1);
5423 var PSet1;
5424 try { PSet1 = parse_PropertySet(blob, null); } catch(e) {/* empty */}
5425 for(y in PSet1) rval[y] = PSet1[y];
5426 rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
5427 return rval;
5428}
5429function write_PropertySetStream(entries, clsid, RE, PIDSI, entries2, clsid2) {
5430 var hdr = new_buf(entries2 ? 68 : 48);
5431 var bufs = [hdr];
5432 hdr.write_shift(2, 0xFFFE);
5433 hdr.write_shift(2, 0x0000); /* TODO: type 1 props */
5434 hdr.write_shift(4, 0x32363237);
5435 hdr.write_shift(16, CFB.utils.consts.HEADER_CLSID, "hex");
5436 hdr.write_shift(4, (entries2 ? 2 : 1));
5437 hdr.write_shift(16, clsid, "hex");
5438 hdr.write_shift(4, (entries2 ? 68 : 48));
5439 var ps0 = write_PropertySet(entries, RE, PIDSI);
5440 bufs.push(ps0);
5441
5442 if(entries2) {
5443 var ps1 = write_PropertySet(entries2, null, null);
5444 hdr.write_shift(16, clsid2, "hex");
5445 hdr.write_shift(4, 68 + ps0.length);
5446 bufs.push(ps1);
5447 }
5448 return bconcat(bufs);
5449}
5450
5451function parsenoop2(blob, length) { blob.read_shift(length); return null; }
5452function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j<n; ++j) o.write_shift(1, 0); return o; }
5453
5454function parslurp(blob, length, cb) {
5455 var arr = [], target = blob.l + length;
5456 while(blob.l < target) arr.push(cb(blob, target - blob.l));
5457 if(target !== blob.l) throw new Error("Slurp error");
5458 return arr;
5459}
5460
5461function parsebool(blob, length) { return blob.read_shift(length) === 0x1; }
5462function writebool(v, o) { if(!o) o=new_buf(2); o.write_shift(2, +!!v); return o; }
5463
5464function parseuint16(blob) { return blob.read_shift(2, 'u'); }
5465function writeuint16(v, o) { if(!o) o=new_buf(2); o.write_shift(2, v); return o; }
5466function parseuint16a(blob, length) { return parslurp(blob,length,parseuint16);}
5467
5468/* --- 2.5 Structures --- */
5469
5470/* [MS-XLS] 2.5.10 Bes (boolean or error) */
5471function parse_Bes(blob) {
5472 var v = blob.read_shift(1), t = blob.read_shift(1);
5473 return t === 0x01 ? v : v === 0x01;
5474}
5475function write_Bes(v, t, o) {
5476 if(!o) o = new_buf(2);
5477 o.write_shift(1, +v);
5478 o.write_shift(1, ((t == 'e') ? 1 : 0));
5479 return o;
5480}
5481
5482/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
5483function parse_ShortXLUnicodeString(blob, length, opts) {
5484 var cch = blob.read_shift(opts && opts.biff >= 12 ? 2 : 1);
5485 var encoding = 'sbcs-cont';
5486 var cp = current_codepage;
5487 if(opts && opts.biff >= 8) current_codepage = 1200;
5488 if(!opts || opts.biff == 8 ) {
5489 var fHighByte = blob.read_shift(1);
5490 if(fHighByte) { encoding = 'dbcs-cont'; }
5491 } else if(opts.biff == 12) {
5492 encoding = 'wstr';
5493 }
5494 if(opts.biff >= 2 && opts.biff <= 5) encoding = 'cpstr';
5495 var o = cch ? blob.read_shift(cch, encoding) : "";
5496 current_codepage = cp;
5497 return o;
5498}
5499
5500/* 2.5.293 XLUnicodeRichExtendedString */
5501function parse_XLUnicodeRichExtendedString(blob) {
5502 var cp = current_codepage;
5503 current_codepage = 1200;
5504 var cch = blob.read_shift(2), flags = blob.read_shift(1);
5505 var /*fHighByte = flags & 0x1,*/ fExtSt = flags & 0x4, fRichSt = flags & 0x8;
5506 var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
5507 var cRun = 0, cbExtRst;
5508 var z = {};
5509 if(fRichSt) cRun = blob.read_shift(2);
5510 if(fExtSt) cbExtRst = blob.read_shift(4);
5511 var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont';
5512 var msg = cch === 0 ? "" : blob.read_shift(cch, encoding);
5513 if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
5514 if(fExtSt) blob.l += cbExtRst; //TODO: parse this
5515 z.t = msg;
5516 if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
5517 current_codepage = cp;
5518 return z;
5519}
5520
5521/* 2.5.296 XLUnicodeStringNoCch */
5522function parse_XLUnicodeStringNoCch(blob, cch, opts) {
5523 var retval;
5524 if(opts) {
5525 if(opts.biff >= 2 && opts.biff <= 5) return blob.read_shift(cch, 'cpstr');
5526 if(opts.biff >= 12) return blob.read_shift(cch, 'dbcs-cont');
5527 }
5528 var fHighByte = blob.read_shift(1);
5529 if(fHighByte===0) { retval = blob.read_shift(cch, 'sbcs-cont'); }
5530 else { retval = blob.read_shift(cch, 'dbcs-cont'); }
5531 return retval;
5532}
5533
5534/* 2.5.294 XLUnicodeString */
5535function parse_XLUnicodeString(blob, length, opts) {
5536 var cch = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
5537 if(cch === 0) { blob.l++; return ""; }
5538 return parse_XLUnicodeStringNoCch(blob, cch, opts);
5539}
5540/* BIFF5 override */
5541function parse_XLUnicodeString2(blob, length, opts) {
5542 if(opts.biff > 5) return parse_XLUnicodeString(blob, length, opts);
5543 var cch = blob.read_shift(1);
5544 if(cch === 0) { blob.l++; return ""; }
5545 return blob.read_shift(cch, (opts.biff <= 4 || !blob.lens ) ? 'cpstr' : 'sbcs-cont');
5546}
5547/* TODO: BIFF5 and lower, codepage awareness */
5548function write_XLUnicodeString(str, opts, o) {
5549 if(!o) o = new_buf(3 + 2 * str.length);
5550 o.write_shift(2, str.length);
5551 o.write_shift(1, 1);
5552 o.write_shift(31, str, 'utf16le');
5553 return o;
5554}
5555
5556/* [MS-XLS] 2.5.61 ControlInfo */
5557function parse_ControlInfo(blob) {
5558 var flags = blob.read_shift(1);
5559 blob.l++;
5560 var accel = blob.read_shift(2);
5561 blob.l += 2;
5562 return [flags, accel];
5563}
5564
5565/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
5566function parse_URLMoniker(blob) {
5567 var len = blob.read_shift(4), start = blob.l;
5568 var extra = false;
5569 if(len > 24) {
5570 /* look ahead */
5571 blob.l += len - 24;
5572 if(blob.read_shift(16) === "795881f43b1d7f48af2c825dc4852763") extra = true;
5573 blob.l = start;
5574 }
5575 var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
5576 if(extra) blob.l += 24;
5577 return url;
5578}
5579
5580/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
5581function parse_FileMoniker(blob) {
5582 blob.l += 2; //var cAnti = blob.read_shift(2);
5583 var ansiPath = blob.read_shift(0, 'lpstr-ansi');
5584 blob.l += 2; //var endServer = blob.read_shift(2);
5585 if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker");
5586 var sz = blob.read_shift(4);
5587 if(sz === 0) return ansiPath.replace(/\\/g,"/");
5588 var bytes = blob.read_shift(4);
5589 if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker");
5590 var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,"");
5591 return unicodePath;
5592}
5593
5594/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
5595function parse_HyperlinkMoniker(blob, length) {
5596 var clsid = blob.read_shift(16); length -= 16;
5597 switch(clsid) {
5598 case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
5599 case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
5600 default: throw new Error("Unsupported Moniker " + clsid);
5601 }
5602}
5603
5604/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
5605function parse_HyperlinkString(blob) {
5606 var len = blob.read_shift(4);
5607 var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
5608 return o;
5609}
5610
5611/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
5612function parse_Hyperlink(blob, length) {
5613 var end = blob.l + length;
5614 var sVer = blob.read_shift(4);
5615 if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
5616 var flags = blob.read_shift(2);
5617 blob.l += 2;
5618 var displayName, targetFrameName, moniker, oleMoniker, Loc="", guid, fileTime;
5619 if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
5620 if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
5621 if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
5622 if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
5623 if(flags & 0x0008) Loc = parse_HyperlinkString(blob, end - blob.l);
5624 if(flags & 0x0020) guid = blob.read_shift(16);
5625 if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
5626 blob.l = end;
5627 var target = targetFrameName||moniker||oleMoniker||"";
5628 if(target && Loc) target+="#"+Loc;
5629 if(!target) target = "#" + Loc;
5630 var out = ({Target:target});
5631 if(guid) out.guid = guid;
5632 if(fileTime) out.time = fileTime;
5633 if(displayName) out.Tooltip = displayName;
5634 return out;
5635}
5636function write_Hyperlink(hl) {
5637 var out = new_buf(512), i = 0;
5638 var Target = hl.Target;
5639 var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
5640 switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
5641 out.write_shift(4,2); out.write_shift(4, F);
5642 var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
5643 if(F == 0x1C) {
5644 Target = Target.slice(1);
5645 out.write_shift(4, Target.length + 1);
5646 for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
5647 out.write_shift(2, 0);
5648 } else if(F & 0x02) {
5649 data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
5650 for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
5651 out.write_shift(4, 2*(Target.length + 1));
5652 for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
5653 out.write_shift(2, 0);
5654 } else {
5655 data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
5656 for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
5657 var P = 0;
5658 while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
5659 out.write_shift(2, P);
5660 out.write_shift(4, Target.length + 1);
5661 for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
5662 out.write_shift(1, 0);
5663 out.write_shift(2, 0xFFFF);
5664 out.write_shift(2, 0xDEAD);
5665 for(i = 0; i < 6; ++i) out.write_shift(4, 0);
5666 }
5667 return out.slice(0, out.l);
5668}
5669
5670/* 2.5.178 LongRGBA */
5671function 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]; }
5672
5673/* 2.5.177 LongRGB */
5674function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
5675
5676
5677/* [MS-XLS] 2.5.19 */
5678function parse_XLSCell(blob) {
5679 var rw = blob.read_shift(2); // 0-indexed
5680 var col = blob.read_shift(2);
5681 var ixfe = blob.read_shift(2);
5682 return ({r:rw, c:col, ixfe:ixfe});
5683}
5684function write_XLSCell(R, C, ixfe, o) {
5685 if(!o) o = new_buf(6);
5686 o.write_shift(2, R);
5687 o.write_shift(2, C);
5688 o.write_shift(2, ixfe||0);
5689 return o;
5690}
5691
5692/* [MS-XLS] 2.5.134 */
5693function parse_frtHeader(blob) {
5694 var rt = blob.read_shift(2);
5695 var flags = blob.read_shift(2); // TODO: parse these flags
5696 blob.l += 8;
5697 return {type: rt, flags: flags};
5698}
5699
5700
5701
5702function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
5703
5704/* [MS-XLS] 2.5.344 */
5705function parse_XTI(blob, length, opts) {
5706 var w = opts.biff > 8 ? 4 : 2;
5707 var iSupBook = blob.read_shift(w), itabFirst = blob.read_shift(w,'i'), itabLast = blob.read_shift(w,'i');
5708 return [iSupBook, itabFirst, itabLast];
5709}
5710
5711/* [MS-XLS] 2.5.218 */
5712function parse_RkRec(blob) {
5713 var ixfe = blob.read_shift(2);
5714 var RK = parse_RkNumber(blob);
5715 return [ixfe, RK];
5716}
5717
5718/* [MS-XLS] 2.5.1 */
5719function parse_AddinUdf(blob, length, opts) {
5720 blob.l += 4; length -= 4;
5721 var l = blob.l + length;
5722 var udfName = parse_ShortXLUnicodeString(blob, length, opts);
5723 var cb = blob.read_shift(2);
5724 l -= blob.l;
5725 if(cb !== l) throw new Error("Malformed AddinUdf: padding = " + l + " != " + cb);
5726 blob.l += cb;
5727 return udfName;
5728}
5729
5730/* [MS-XLS] 2.5.209 TODO: Check sizes */
5731function parse_Ref8U(blob) {
5732 var rwFirst = blob.read_shift(2);
5733 var rwLast = blob.read_shift(2);
5734 var colFirst = blob.read_shift(2);
5735 var colLast = blob.read_shift(2);
5736 return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5737}
5738function write_Ref8U(r, o) {
5739 if(!o) o = new_buf(8);
5740 o.write_shift(2, r.s.r);
5741 o.write_shift(2, r.e.r);
5742 o.write_shift(2, r.s.c);
5743 o.write_shift(2, r.e.c);
5744 return o;
5745}
5746
5747/* [MS-XLS] 2.5.211 */
5748function parse_RefU(blob) {
5749 var rwFirst = blob.read_shift(2);
5750 var rwLast = blob.read_shift(2);
5751 var colFirst = blob.read_shift(1);
5752 var colLast = blob.read_shift(1);
5753 return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}};
5754}
5755
5756/* [MS-XLS] 2.5.207 */
5757var parse_Ref = parse_RefU;
5758
5759/* [MS-XLS] 2.5.143 */
5760function parse_FtCmo(blob) {
5761 blob.l += 4;
5762 var ot = blob.read_shift(2);
5763 var id = blob.read_shift(2);
5764 var flags = blob.read_shift(2);
5765 blob.l+=12;
5766 return [id, ot, flags];
5767}
5768
5769/* [MS-XLS] 2.5.149 */
5770function parse_FtNts(blob) {
5771 var out = {};
5772 blob.l += 4;
5773 blob.l += 16; // GUID TODO
5774 out.fSharedNote = blob.read_shift(2);
5775 blob.l += 4;
5776 return out;
5777}
5778
5779/* [MS-XLS] 2.5.142 */
5780function parse_FtCf(blob) {
5781 var out = {};
5782 blob.l += 4;
5783 blob.cf = blob.read_shift(2);
5784 return out;
5785}
5786
5787/* [MS-XLS] 2.5.140 - 2.5.154 and friends */
5788function parse_FtSkip(blob) { blob.l += 2; blob.l += blob.read_shift(2); }
5789var FtTab = {
57900x00: parse_FtSkip, /* FtEnd */
57910x04: parse_FtSkip, /* FtMacro */
57920x05: parse_FtSkip, /* FtButton */
57930x06: parse_FtSkip, /* FtGmo */
57940x07: parse_FtCf, /* FtCf */
57950x08: parse_FtSkip, /* FtPioGrbit */
57960x09: parse_FtSkip, /* FtPictFmla */
57970x0A: parse_FtSkip, /* FtCbls */
57980x0B: parse_FtSkip, /* FtRbo */
57990x0C: parse_FtSkip, /* FtSbs */
58000x0D: parse_FtNts, /* FtNts */
58010x0E: parse_FtSkip, /* FtSbsFmla */
58020x0F: parse_FtSkip, /* FtGboData */
58030x10: parse_FtSkip, /* FtEdoData */
58040x11: parse_FtSkip, /* FtRboData */
58050x12: parse_FtSkip, /* FtCblsData */
58060x13: parse_FtSkip, /* FtLbsData */
58070x14: parse_FtSkip, /* FtCblsFmla */
58080x15: parse_FtCmo
5809};
5810function parse_FtArray(blob, length) {
5811 var tgt = blob.l + length;
5812 var fts = [];
5813 while(blob.l < tgt) {
5814 var ft = blob.read_shift(2);
5815 blob.l-=2;
5816 try {
5817 fts.push(FtTab[ft](blob, tgt - blob.l));
5818 } catch(e) { blob.l = tgt; return fts; }
5819 }
5820 if(blob.l != tgt) blob.l = tgt; //throw new Error("bad Object Ft-sequence");
5821 return fts;
5822}
5823
5824/* --- 2.4 Records --- */
5825
5826/* [MS-XLS] 2.4.21 */
5827function parse_BOF(blob, length) {
5828 var o = {BIFFVer:0, dt:0};
5829 o.BIFFVer = blob.read_shift(2); length -= 2;
5830 if(length >= 2) { o.dt = blob.read_shift(2); blob.l -= 2; }
5831 switch(o.BIFFVer) {
5832 case 0x0600: /* BIFF8 */
5833 case 0x0500: /* BIFF5 */
5834 case 0x0400: /* BIFF4 */
5835 case 0x0300: /* BIFF3 */
5836 case 0x0200: /* BIFF2 */
5837 case 0x0002: case 0x0007: /* BIFF2 */
5838 break;
5839 default: if(length > 6) throw new Error("Unexpected BIFF Ver " + o.BIFFVer);
5840 }
5841
5842 blob.read_shift(length);
5843 return o;
5844}
5845function write_BOF(wb, t, o) {
5846 var h = 0x0600, w = 16;
5847 switch(o.bookType) {
5848 case 'biff8': break;
5849 case 'biff5': h = 0x0500; w = 8; break;
5850 case 'biff4': h = 0x0004; w = 6; break;
5851 case 'biff3': h = 0x0003; w = 6; break;
5852 case 'biff2': h = 0x0002; w = 4; break;
5853 case 'xla': break;
5854 default: throw new Error("unsupported BIFF version");
5855 }
5856 var out = new_buf(w);
5857 out.write_shift(2, h);
5858 out.write_shift(2, t);
5859 if(w > 4) out.write_shift(2, 0x7262);
5860 if(w > 6) out.write_shift(2, 0x07CD);
5861 if(w > 8) {
5862 out.write_shift(2, 0xC009);
5863 out.write_shift(2, 0x0001);
5864 out.write_shift(2, 0x0706);
5865 out.write_shift(2, 0x0000);
5866 }
5867 return out;
5868}
5869
5870
5871/* [MS-XLS] 2.4.146 */
5872function parse_InterfaceHdr(blob, length) {
5873 if(length === 0) return 0x04b0;
5874 if((blob.read_shift(2))!==0x04b0){/* empty */}
5875 return 0x04b0;
5876}
5877
5878
5879/* [MS-XLS] 2.4.349 */
5880function parse_WriteAccess(blob, length, opts) {
5881 if(opts.enc) { blob.l += length; return ""; }
5882 var l = blob.l;
5883 // TODO: make sure XLUnicodeString doesnt overrun
5884 var UserName = parse_XLUnicodeString2(blob, 0, opts);
5885 blob.read_shift(length + l - blob.l);
5886 return UserName;
5887}
5888function write_WriteAccess(s, opts) {
5889 var b8 = !opts || opts.biff == 8;
5890 var o = new_buf(b8 ? 112 : 54);
5891 o.write_shift(opts.biff == 8 ? 2 : 1, 7);
5892 if(b8) o.write_shift(1, 0);
5893 o.write_shift(4, 0x33336853);
5894 o.write_shift(4, (0x00534A74 | (b8 ? 0 : 0x20000000)));
5895 while(o.l < o.length) o.write_shift(1, (b8 ? 0 : 32));
5896 return o;
5897}
5898
5899/* [MS-XLS] 2.4.351 */
5900function parse_WsBool(blob, length, opts) {
5901 var flags = opts && opts.biff == 8 || length == 2 ? blob.read_shift(2) : (blob.l += length, 0);
5902 return { fDialog: flags & 0x10 };
5903}
5904
5905/* [MS-XLS] 2.4.28 */
5906function parse_BoundSheet8(blob, length, opts) {
5907 var pos = blob.read_shift(4);
5908 var hidden = blob.read_shift(1) & 0x03;
5909 var dt = blob.read_shift(1);
5910 switch(dt) {
5911 case 0: dt = 'Worksheet'; break;
5912 case 1: dt = 'Macrosheet'; break;
5913 case 2: dt = 'Chartsheet'; break;
5914 case 6: dt = 'VBAModule'; break;
5915 }
5916 var name = parse_ShortXLUnicodeString(blob, 0, opts);
5917 if(name.length === 0) name = "Sheet1";
5918 return { pos:pos, hs:hidden, dt:dt, name:name };
5919}
5920function write_BoundSheet8(data, opts) {
5921 var w = (!opts || opts.biff >= 8 ? 2 : 1);
5922 var o = new_buf(8 + w * data.name.length);
5923 o.write_shift(4, data.pos);
5924 o.write_shift(1, data.hs || 0);
5925 o.write_shift(1, data.dt);
5926 o.write_shift(1, data.name.length);
5927 if(opts.biff >= 8) o.write_shift(1, 1);
5928 o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
5929 var out = o.slice(0, o.l);
5930 out.l = o.l; return out;
5931}
5932
5933/* [MS-XLS] 2.4.265 TODO */
5934function parse_SST(blob, length) {
5935 var end = blob.l + length;
5936 var cnt = blob.read_shift(4);
5937 var ucnt = blob.read_shift(4);
5938 var strs = ([]);
5939 for(var i = 0; i != ucnt && blob.l < end; ++i) {
5940 strs.push(parse_XLUnicodeRichExtendedString(blob));
5941 }
5942 strs.Count = cnt; strs.Unique = ucnt;
5943 return strs;
5944}
5945
5946/* [MS-XLS] 2.4.107 */
5947function parse_ExtSST(blob, length) {
5948 var extsst = {};
5949 extsst.dsst = blob.read_shift(2);
5950 blob.l += length-2;
5951 return extsst;
5952}
5953
5954
5955/* [MS-XLS] 2.4.221 TODO: check BIFF2-4 */
5956function parse_Row(blob) {
5957 var z = ({});
5958 z.r = blob.read_shift(2);
5959 z.c = blob.read_shift(2);
5960 z.cnt = blob.read_shift(2) - z.c;
5961 var miyRw = blob.read_shift(2);
5962 blob.l += 4; // reserved(2), unused(2)
5963 var flags = blob.read_shift(1); // various flags
5964 blob.l += 3; // reserved(8), ixfe(12), flags(4)
5965 if(flags & 0x07) z.level = flags & 0x07;
5966 // collapsed: flags & 0x10
5967 if(flags & 0x20) z.hidden = true;
5968 if(flags & 0x40) z.hpt = miyRw / 20;
5969 return z;
5970}
5971
5972
5973/* [MS-XLS] 2.4.125 */
5974function parse_ForceFullCalculation(blob) {
5975 var header = parse_frtHeader(blob);
5976 if(header.type != 0x08A3) throw new Error("Invalid Future Record " + header.type);
5977 var fullcalc = blob.read_shift(4);
5978 return fullcalc !== 0x0;
5979}
5980
5981
5982
5983
5984
5985/* [MS-XLS] 2.4.215 rt */
5986function parse_RecalcId(blob) {
5987 blob.read_shift(2);
5988 return blob.read_shift(4);
5989}
5990
5991/* [MS-XLS] 2.4.87 */
5992function parse_DefaultRowHeight(blob, length, opts) {
5993 var f = 0;
5994 if(!(opts && opts.biff == 2)) {
5995 f = blob.read_shift(2);
5996 }
5997 var miyRw = blob.read_shift(2);
5998 if((opts && opts.biff == 2)) {
5999 f = 1 - (miyRw >> 15); miyRw &= 0x7fff;
6000 }
6001 var fl = {Unsynced:f&1,DyZero:(f&2)>>1,ExAsc:(f&4)>>2,ExDsc:(f&8)>>3};
6002 return [fl, miyRw];
6003}
6004
6005/* [MS-XLS] 2.4.345 TODO */
6006function parse_Window1(blob) {
6007 var xWn = blob.read_shift(2), yWn = blob.read_shift(2), dxWn = blob.read_shift(2), dyWn = blob.read_shift(2);
6008 var flags = blob.read_shift(2), iTabCur = blob.read_shift(2), iTabFirst = blob.read_shift(2);
6009 var ctabSel = blob.read_shift(2), wTabRatio = blob.read_shift(2);
6010 return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
6011 FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
6012}
6013function write_Window1() {
6014 var o = new_buf(18);
6015 o.write_shift(2, 0);
6016 o.write_shift(2, 0);
6017 o.write_shift(2, 0x7260);
6018 o.write_shift(2, 0x44c0);
6019 o.write_shift(2, 0x38);
6020 o.write_shift(2, 0);
6021 o.write_shift(2, 0);
6022 o.write_shift(2, 1);
6023 o.write_shift(2, 0x01f4);
6024 return o;
6025}
6026/* [MS-XLS] 2.4.346 TODO */
6027function parse_Window2(blob, length, opts) {
6028 if(opts && opts.biff >= 2 && opts.biff < 5) return {};
6029 var f = blob.read_shift(2);
6030 return { RTL: f & 0x40 };
6031}
6032function write_Window2(view) {
6033 var o = new_buf(18), f = 0x6b6;
6034 if(view && view.RTL) f |= 0x40;
6035 o.write_shift(2, f);
6036 o.write_shift(4, 0);
6037 o.write_shift(4, 64);
6038 o.write_shift(4, 0);
6039 o.write_shift(4, 0);
6040 return o;
6041}
6042
6043/* [MS-XLS] 2.4.189 TODO */
6044function parse_Pane(/*blob, length, opts*/) {
6045}
6046
6047/* [MS-XLS] 2.4.122 TODO */
6048function parse_Font(blob, length, opts) {
6049 var o = {
6050 dyHeight: blob.read_shift(2),
6051 fl: blob.read_shift(2)
6052 };
6053 switch((opts && opts.biff) || 8) {
6054 case 2: break;
6055 case 3: case 4: blob.l += 2; break;
6056 default: blob.l += 10; break;
6057 }
6058 o.name = parse_ShortXLUnicodeString(blob, 0, opts);
6059 return o;
6060}
6061function write_Font(data, opts) {
6062 var name = data.name || "Arial";
6063 var b5 = (opts && (opts.biff == 5)), w = (b5 ? (15 + name.length) : (16 + 2 * name.length));
6064 var o = new_buf(w);
6065 o.write_shift(2, (data.sz || 12) * 20);
6066 o.write_shift(4, 0);
6067 o.write_shift(2, 400);
6068 o.write_shift(4, 0);
6069 o.write_shift(2, 0);
6070 o.write_shift(1, name.length);
6071 if(!b5) o.write_shift(1, 1);
6072 o.write_shift((b5 ? 1 : 2) * name.length, name, (b5 ? "sbcs" : "utf16le"));
6073 return o;
6074}
6075
6076/* [MS-XLS] 2.4.149 */
6077function parse_LabelSst(blob) {
6078 var cell = parse_XLSCell(blob);
6079 cell.isst = blob.read_shift(4);
6080 return cell;
6081}
6082
6083/* [MS-XLS] 2.4.148 */
6084function parse_Label(blob, length, opts) {
6085 var target = blob.l + length;
6086 var cell = parse_XLSCell(blob, 6);
6087 if(opts.biff == 2) blob.l++;
6088 var str = parse_XLUnicodeString(blob, target - blob.l, opts);
6089 cell.val = str;
6090 return cell;
6091}
6092function write_Label(R, C, v, os, opts) {
6093 var b8 = !opts || opts.biff == 8;
6094 var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
6095 write_XLSCell(R, C, os, o);
6096 o.write_shift(2, v.length);
6097 if(b8) o.write_shift(1, 1);
6098 o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
6099 return o;
6100}
6101
6102
6103/* [MS-XLS] 2.4.126 Number Formats */
6104function parse_Format(blob, length, opts) {
6105 var numFmtId = blob.read_shift(2);
6106 var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
6107 return [numFmtId, fmtstr];
6108}
6109function write_Format(i, f, opts, o) {
6110 var b5 = (opts && (opts.biff == 5));
6111 if(!o) o = new_buf(b5 ? (3 + f.length) : (5 + 2 * f.length));
6112 o.write_shift(2, i);
6113 o.write_shift((b5 ? 1 : 2), f.length);
6114 if(!b5) o.write_shift(1, 1);
6115 o.write_shift((b5 ? 1 : 2) * f.length, f, (b5 ? 'sbcs' : 'utf16le'));
6116 var out = (o.length > o.l) ? o.slice(0, o.l) : o;
6117 if(out.l == null) out.l = out.length;
6118 return out;
6119}
6120var parse_BIFF2Format = parse_XLUnicodeString2;
6121
6122/* [MS-XLS] 2.4.90 */
6123function parse_Dimensions(blob, length, opts) {
6124 var end = blob.l + length;
6125 var w = opts.biff == 8 || !opts.biff ? 4 : 2;
6126 var r = blob.read_shift(w), R = blob.read_shift(w);
6127 var c = blob.read_shift(2), C = blob.read_shift(2);
6128 blob.l = end;
6129 return {s: {r:r, c:c}, e: {r:R, c:C}};
6130}
6131function write_Dimensions(range, opts) {
6132 var w = opts.biff == 8 || !opts.biff ? 4 : 2;
6133 var o = new_buf(2*w + 6);
6134 o.write_shift(w, range.s.r);
6135 o.write_shift(w, range.e.r + 1);
6136 o.write_shift(2, range.s.c);
6137 o.write_shift(2, range.e.c + 1);
6138 o.write_shift(2, 0);
6139 return o;
6140}
6141
6142/* [MS-XLS] 2.4.220 */
6143function parse_RK(blob) {
6144 var rw = blob.read_shift(2), col = blob.read_shift(2);
6145 var rkrec = parse_RkRec(blob);
6146 return {r:rw, c:col, ixfe:rkrec[0], rknum:rkrec[1]};
6147}
6148
6149/* [MS-XLS] 2.4.175 */
6150function parse_MulRk(blob, length) {
6151 var target = blob.l + length - 2;
6152 var rw = blob.read_shift(2), col = blob.read_shift(2);
6153 var rkrecs = [];
6154 while(blob.l < target) rkrecs.push(parse_RkRec(blob));
6155 if(blob.l !== target) throw new Error("MulRK read error");
6156 var lastcol = blob.read_shift(2);
6157 if(rkrecs.length != lastcol - col + 1) throw new Error("MulRK length mismatch");
6158 return {r:rw, c:col, C:lastcol, rkrec:rkrecs};
6159}
6160/* [MS-XLS] 2.4.174 */
6161function parse_MulBlank(blob, length) {
6162 var target = blob.l + length - 2;
6163 var rw = blob.read_shift(2), col = blob.read_shift(2);
6164 var ixfes = [];
6165 while(blob.l < target) ixfes.push(blob.read_shift(2));
6166 if(blob.l !== target) throw new Error("MulBlank read error");
6167 var lastcol = blob.read_shift(2);
6168 if(ixfes.length != lastcol - col + 1) throw new Error("MulBlank length mismatch");
6169 return {r:rw, c:col, C:lastcol, ixfe:ixfes};
6170}
6171
6172/* [MS-XLS] 2.5.20 2.5.249 TODO: interpret values here */
6173function parse_CellStyleXF(blob, length, style, opts) {
6174 var o = {};
6175 var a = blob.read_shift(4), b = blob.read_shift(4);
6176 var c = blob.read_shift(4), d = blob.read_shift(2);
6177 o.patternType = XLSFillPattern[c >> 26];
6178
6179 if(!opts.cellStyles) return o;
6180 o.alc = a & 0x07;
6181 o.fWrap = (a >> 3) & 0x01;
6182 o.alcV = (a >> 4) & 0x07;
6183 o.fJustLast = (a >> 7) & 0x01;
6184 o.trot = (a >> 8) & 0xFF;
6185 o.cIndent = (a >> 16) & 0x0F;
6186 o.fShrinkToFit = (a >> 20) & 0x01;
6187 o.iReadOrder = (a >> 22) & 0x02;
6188 o.fAtrNum = (a >> 26) & 0x01;
6189 o.fAtrFnt = (a >> 27) & 0x01;
6190 o.fAtrAlc = (a >> 28) & 0x01;
6191 o.fAtrBdr = (a >> 29) & 0x01;
6192 o.fAtrPat = (a >> 30) & 0x01;
6193 o.fAtrProt = (a >> 31) & 0x01;
6194
6195 o.dgLeft = b & 0x0F;
6196 o.dgRight = (b >> 4) & 0x0F;
6197 o.dgTop = (b >> 8) & 0x0F;
6198 o.dgBottom = (b >> 12) & 0x0F;
6199 o.icvLeft = (b >> 16) & 0x7F;
6200 o.icvRight = (b >> 23) & 0x7F;
6201 o.grbitDiag = (b >> 30) & 0x03;
6202
6203 o.icvTop = c & 0x7F;
6204 o.icvBottom = (c >> 7) & 0x7F;
6205 o.icvDiag = (c >> 14) & 0x7F;
6206 o.dgDiag = (c >> 21) & 0x0F;
6207
6208 o.icvFore = d & 0x7F;
6209 o.icvBack = (d >> 7) & 0x7F;
6210 o.fsxButton = (d >> 14) & 0x01;
6211 return o;
6212}
6213//function parse_CellXF(blob, length, opts) {return parse_CellStyleXF(blob,length,0, opts);}
6214//function parse_StyleXF(blob, length, opts) {return parse_CellStyleXF(blob,length,1, opts);}
6215
6216/* [MS-XLS] 2.4.353 TODO: actually do this right */
6217function parse_XF(blob, length, opts) {
6218 var o = {};
6219 o.ifnt = blob.read_shift(2); o.numFmtId = blob.read_shift(2); o.flags = blob.read_shift(2);
6220 o.fStyle = (o.flags >> 2) & 0x01;
6221 length -= 6;
6222 o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
6223 return o;
6224}
6225function write_XF(data, ixfeP, opts, o) {
6226 var b5 = (opts && (opts.biff == 5));
6227 if(!o) o = new_buf(b5 ? 16 : 20);
6228 o.write_shift(2, 0);
6229 if(data.style) {
6230 o.write_shift(2, (data.numFmtId||0));
6231 o.write_shift(2, 0xFFF4);
6232 } else {
6233 o.write_shift(2, (data.numFmtId||0));
6234 o.write_shift(2, (ixfeP<<4));
6235 }
6236 o.write_shift(4, 0);
6237 o.write_shift(4, 0);
6238 if(!b5) o.write_shift(4, 0);
6239 o.write_shift(2, 0);
6240 return o;
6241}
6242
6243/* [MS-XLS] 2.4.134 */
6244function parse_Guts(blob) {
6245 blob.l += 4;
6246 var out = [blob.read_shift(2), blob.read_shift(2)];
6247 if(out[0] !== 0) out[0]--;
6248 if(out[1] !== 0) out[1]--;
6249 if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
6250 return out;
6251}
6252function write_Guts(guts) {
6253 var o = new_buf(8);
6254 o.write_shift(4, 0);
6255 o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
6256 o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
6257 return o;
6258}
6259
6260/* [MS-XLS] 2.4.24 */
6261function parse_BoolErr(blob, length, opts) {
6262 var cell = parse_XLSCell(blob, 6);
6263 if(opts.biff == 2) ++blob.l;
6264 var val = parse_Bes(blob, 2);
6265 cell.val = val;
6266 cell.t = (val === true || val === false) ? 'b' : 'e';
6267 return cell;
6268}
6269function write_BoolErr(R, C, v, os, opts, t) {
6270 var o = new_buf(8);
6271 write_XLSCell(R, C, os, o);
6272 write_Bes(v, t, o);
6273 return o;
6274}
6275
6276/* [MS-XLS] 2.4.180 Number */
6277function parse_Number(blob) {
6278 var cell = parse_XLSCell(blob, 6);
6279 var xnum = parse_Xnum(blob, 8);
6280 cell.val = xnum;
6281 return cell;
6282}
6283function write_Number(R, C, v, os) {
6284 var o = new_buf(14);
6285 write_XLSCell(R, C, os, o);
6286 write_Xnum(v, o);
6287 return o;
6288}
6289
6290var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
6291
6292/* [MS-XLS] 2.4.271 */
6293function parse_SupBook(blob, length, opts) {
6294 var end = blob.l + length;
6295 var ctab = blob.read_shift(2);
6296 var cch = blob.read_shift(2);
6297 opts.sbcch = cch;
6298 if(cch == 0x0401 || cch == 0x3A01) return [cch, ctab];
6299 if(cch < 0x01 || cch >0xff) throw new Error("Unexpected SupBook type: "+cch);
6300 var virtPath = parse_XLUnicodeStringNoCch(blob, cch);
6301 /* TODO: 2.5.277 Virtual Path */
6302 var rgst = [];
6303 while(end > blob.l) rgst.push(parse_XLUnicodeString(blob));
6304 return [cch, ctab, virtPath, rgst];
6305}
6306
6307/* [MS-XLS] 2.4.105 TODO */
6308function parse_ExternName(blob, length, opts) {
6309 var flags = blob.read_shift(2);
6310 var body;
6311 var o = ({
6312 fBuiltIn: flags & 0x01,
6313 fWantAdvise: (flags >>> 1) & 0x01,
6314 fWantPict: (flags >>> 2) & 0x01,
6315 fOle: (flags >>> 3) & 0x01,
6316 fOleLink: (flags >>> 4) & 0x01,
6317 cf: (flags >>> 5) & 0x3FF,
6318 fIcon: flags >>> 15 & 0x01
6319 });
6320 if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2, opts);
6321 //else throw new Error("unsupported SupBook cch: " + opts.sbcch);
6322 o.body = body || blob.read_shift(length-2);
6323 if(typeof body === "string") o.Name = body;
6324 return o;
6325}
6326
6327/* [MS-XLS] 2.4.150 TODO */
6328var XLSLblBuiltIn = [
6329 "_xlnm.Consolidate_Area",
6330 "_xlnm.Auto_Open",
6331 "_xlnm.Auto_Close",
6332 "_xlnm.Extract",
6333 "_xlnm.Database",
6334 "_xlnm.Criteria",
6335 "_xlnm.Print_Area",
6336 "_xlnm.Print_Titles",
6337 "_xlnm.Recorder",
6338 "_xlnm.Data_Form",
6339 "_xlnm.Auto_Activate",
6340 "_xlnm.Auto_Deactivate",
6341 "_xlnm.Sheet_Title",
6342 "_xlnm._FilterDatabase"
6343];
6344function parse_Lbl(blob, length, opts) {
6345 var target = blob.l + length;
6346 var flags = blob.read_shift(2);
6347 var chKey = blob.read_shift(1);
6348 var cch = blob.read_shift(1);
6349 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
6350 var itab = 0;
6351 if(!opts || opts.biff >= 5) {
6352 if(opts.biff != 5) blob.l += 2;
6353 itab = blob.read_shift(2);
6354 if(opts.biff == 5) blob.l += 2;
6355 blob.l += 4;
6356 }
6357 var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
6358 if(flags & 0x20) name = XLSLblBuiltIn[name.charCodeAt(0)];
6359 var npflen = target - blob.l; if(opts && opts.biff == 2) --npflen;
6360 var rgce = target == blob.l || cce === 0 ? [] : parse_NameParsedFormula(blob, npflen, opts, cce);
6361 return {
6362 chKey: chKey,
6363 Name: name,
6364 itab: itab,
6365 rgce: rgce
6366 };
6367}
6368
6369/* [MS-XLS] 2.4.106 TODO: verify filename encoding */
6370function parse_ExternSheet(blob, length, opts) {
6371 if(opts.biff < 8) return parse_BIFF5ExternSheet(blob, length, opts);
6372 var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2);
6373 while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts));
6374 // [iSupBook, itabFirst, itabLast];
6375 if(blob.l != target) throw new Error("Bad ExternSheet: " + blob.l + " != " + target);
6376 return o;
6377}
6378function parse_BIFF5ExternSheet(blob, length, opts) {
6379 if(blob[blob.l + 1] == 0x03) blob[blob.l]++;
6380 var o = parse_ShortXLUnicodeString(blob, length, opts);
6381 return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
6382}
6383
6384/* [MS-XLS] 2.4.176 TODO: check older biff */
6385function parse_NameCmt(blob, length, opts) {
6386 if(opts.biff < 8) { blob.l += length; return; }
6387 var cchName = blob.read_shift(2);
6388 var cchComment = blob.read_shift(2);
6389 var name = parse_XLUnicodeStringNoCch(blob, cchName, opts);
6390 var comment = parse_XLUnicodeStringNoCch(blob, cchComment, opts);
6391 return [name, comment];
6392}
6393
6394/* [MS-XLS] 2.4.260 */
6395function parse_ShrFmla(blob, length, opts) {
6396 var ref = parse_RefU(blob, 6);
6397 blob.l++;
6398 var cUse = blob.read_shift(1);
6399 length -= 8;
6400 return [parse_SharedParsedFormula(blob, length, opts), cUse, ref];
6401}
6402
6403/* [MS-XLS] 2.4.4 TODO */
6404function parse_Array(blob, length, opts) {
6405 var ref = parse_Ref(blob, 6);
6406 /* TODO: fAlwaysCalc */
6407 switch(opts.biff) {
6408 case 2: blob.l ++; length -= 7; break;
6409 case 3: case 4: blob.l += 2; length -= 8; break;
6410 default: blob.l += 6; length -= 12;
6411 }
6412 return [ref, parse_ArrayParsedFormula(blob, length, opts, ref)];
6413}
6414
6415/* [MS-XLS] 2.4.173 */
6416function parse_MTRSettings(blob) {
6417 var fMTREnabled = blob.read_shift(4) !== 0x00;
6418 var fUserSetThreadCount = blob.read_shift(4) !== 0x00;
6419 var cUserThreadCount = blob.read_shift(4);
6420 return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
6421}
6422
6423/* [MS-XLS] 2.5.186 TODO: BIFF5 */
6424function parse_NoteSh(blob, length, opts) {
6425 if(opts.biff < 8) return;
6426 var row = blob.read_shift(2), col = blob.read_shift(2);
6427 var flags = blob.read_shift(2), idObj = blob.read_shift(2);
6428 var stAuthor = parse_XLUnicodeString2(blob, 0, opts);
6429 if(opts.biff < 8) blob.read_shift(1);
6430 return [{r:row,c:col}, stAuthor, idObj, flags];
6431}
6432
6433/* [MS-XLS] 2.4.179 */
6434function parse_Note(blob, length, opts) {
6435 /* TODO: Support revisions */
6436 return parse_NoteSh(blob, length, opts);
6437}
6438
6439/* [MS-XLS] 2.4.168 */
6440function parse_MergeCells(blob, length) {
6441 var merges = [];
6442 var cmcs = blob.read_shift(2);
6443 while (cmcs--) merges.push(parse_Ref8U(blob,length));
6444 return merges;
6445}
6446function write_MergeCells(merges) {
6447 var o = new_buf(2 + merges.length * 8);
6448 o.write_shift(2, merges.length);
6449 for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o);
6450 return o;
6451}
6452
6453/* [MS-XLS] 2.4.181 TODO: parse all the things! */
6454function parse_Obj(blob, length, opts) {
6455 if(opts && opts.biff < 8) return parse_BIFF5Obj(blob, length, opts);
6456 var cmo = parse_FtCmo(blob, 22); // id, ot, flags
6457 var fts = parse_FtArray(blob, length-22, cmo[1]);
6458 return { cmo: cmo, ft:fts };
6459}
6460/* from older spec */
6461var parse_BIFF5OT = [];
6462parse_BIFF5OT[0x08] = function(blob, length) {
6463 var tgt = blob.l + length;
6464 blob.l += 10; // todo
6465 var cf = blob.read_shift(2);
6466 blob.l += 4;
6467 blob.l += 2; //var cbPictFmla = blob.read_shift(2);
6468 blob.l += 2;
6469 blob.l += 2; //var grbit = blob.read_shift(2);
6470 blob.l += 4;
6471 var cchName = blob.read_shift(1);
6472 blob.l += cchName; // TODO: stName
6473 blob.l = tgt; // TODO: fmla
6474 return { fmt:cf };
6475};
6476
6477function parse_BIFF5Obj(blob, length, opts) {
6478 blob.l += 4; //var cnt = blob.read_shift(4);
6479 var ot = blob.read_shift(2);
6480 var id = blob.read_shift(2);
6481 var grbit = blob.read_shift(2);
6482 blob.l += 2; //var colL = blob.read_shift(2);
6483 blob.l += 2; //var dxL = blob.read_shift(2);
6484 blob.l += 2; //var rwT = blob.read_shift(2);
6485 blob.l += 2; //var dyT = blob.read_shift(2);
6486 blob.l += 2; //var colR = blob.read_shift(2);
6487 blob.l += 2; //var dxR = blob.read_shift(2);
6488 blob.l += 2; //var rwB = blob.read_shift(2);
6489 blob.l += 2; //var dyB = blob.read_shift(2);
6490 blob.l += 2; //var cbMacro = blob.read_shift(2);
6491 blob.l += 6;
6492 length -= 36;
6493 var fts = [];
6494 fts.push((parse_BIFF5OT[ot]||parsenoop)(blob, length, opts));
6495 return { cmo: [id, ot, grbit], ft:fts };
6496}
6497
6498/* [MS-XLS] 2.4.329 TODO: parse properly */
6499function parse_TxO(blob, length, opts) {
6500 var s = blob.l;
6501 var texts = "";
6502try {
6503 blob.l += 4;
6504 var ot = (opts.lastobj||{cmo:[0,0]}).cmo[1];
6505 var controlInfo; // eslint-disable-line no-unused-vars
6506 if([0,5,7,11,12,14].indexOf(ot) == -1) blob.l += 6;
6507 else controlInfo = parse_ControlInfo(blob, 6, opts);
6508 var cchText = blob.read_shift(2);
6509 /*var cbRuns = */blob.read_shift(2);
6510 /*var ifntEmpty = */parseuint16(blob, 2);
6511 var len = blob.read_shift(2);
6512 blob.l += len;
6513 //var fmla = parse_ObjFmla(blob, s + length - blob.l);
6514
6515 for(var i = 1; i < blob.lens.length-1; ++i) {
6516 if(blob.l-s != blob.lens[i]) throw new Error("TxO: bad continue record");
6517 var hdr = blob[blob.l];
6518 var t = parse_XLUnicodeStringNoCch(blob, blob.lens[i+1]-blob.lens[i]-1);
6519 texts += t;
6520 if(texts.length >= (hdr ? cchText : 2*cchText)) break;
6521 }
6522 if(texts.length !== cchText && texts.length !== cchText*2) {
6523 throw new Error("cchText: " + cchText + " != " + texts.length);
6524 }
6525
6526 blob.l = s + length;
6527 /* [MS-XLS] 2.5.272 TxORuns */
6528// var rgTxoRuns = [];
6529// for(var j = 0; j != cbRuns/8-1; ++j) blob.l += 8;
6530// var cchText2 = blob.read_shift(2);
6531// if(cchText2 !== cchText) throw new Error("TxOLastRun mismatch: " + cchText2 + " " + cchText);
6532// blob.l += 6;
6533// if(s + length != blob.l) throw new Error("TxO " + (s + length) + ", at " + blob.l);
6534 return { t: texts };
6535} catch(e) { blob.l = s + length; return { t: texts }; }
6536}
6537
6538/* [MS-XLS] 2.4.140 */
6539function parse_HLink(blob, length) {
6540 var ref = parse_Ref8U(blob, 8);
6541 blob.l += 16; /* CLSID */
6542 var hlink = parse_Hyperlink(blob, length-24);
6543 return [ref, hlink];
6544}
6545function write_HLink(hl) {
6546 var O = new_buf(24);
6547 var ref = decode_cell(hl[0]);
6548 O.write_shift(2, ref.r); O.write_shift(2, ref.r);
6549 O.write_shift(2, ref.c); O.write_shift(2, ref.c);
6550 var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
6551 for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
6552 return bconcat([O, write_Hyperlink(hl[1])]);
6553}
6554
6555
6556/* [MS-XLS] 2.4.141 */
6557function parse_HLinkTooltip(blob, length) {
6558 blob.read_shift(2);
6559 var ref = parse_Ref8U(blob, 8);
6560 var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
6561 wzTooltip = wzTooltip.replace(chr0,"");
6562 return [ref, wzTooltip];
6563}
6564function write_HLinkTooltip(hl) {
6565 var TT = hl[1].Tooltip;
6566 var O = new_buf(10 + 2 * (TT.length + 1));
6567 O.write_shift(2, 0x0800);
6568 var ref = decode_cell(hl[0]);
6569 O.write_shift(2, ref.r); O.write_shift(2, ref.r);
6570 O.write_shift(2, ref.c); O.write_shift(2, ref.c);
6571 for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
6572 O.write_shift(2, 0);
6573 return O;
6574}
6575
6576/* [MS-XLS] 2.4.63 */
6577function parse_Country(blob) {
6578 var o = [0,0], d;
6579 d = blob.read_shift(2); o[0] = CountryEnum[d] || d;
6580 d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
6581 return o;
6582}
6583function write_Country(o) {
6584 if(!o) o = new_buf(4);
6585 o.write_shift(2, 0x01);
6586 o.write_shift(2, 0x01);
6587 return o;
6588}
6589
6590/* [MS-XLS] 2.4.50 ClrtClient */
6591function parse_ClrtClient(blob) {
6592 var ccv = blob.read_shift(2);
6593 var o = [];
6594 while(ccv-->0) o.push(parse_LongRGB(blob, 8));
6595 return o;
6596}
6597
6598/* [MS-XLS] 2.4.188 */
6599function parse_Palette(blob) {
6600 var ccv = blob.read_shift(2);
6601 var o = [];
6602 while(ccv-->0) o.push(parse_LongRGB(blob, 8));
6603 return o;
6604}
6605
6606/* [MS-XLS] 2.4.354 */
6607function parse_XFCRC(blob) {
6608 blob.l += 2;
6609 var o = {cxfs:0, crc:0};
6610 o.cxfs = blob.read_shift(2);
6611 o.crc = blob.read_shift(4);
6612 return o;
6613}
6614
6615/* [MS-XLS] 2.4.53 TODO: parse flags */
6616/* [MS-XLSB] 2.4.323 TODO: parse flags */
6617function parse_ColInfo(blob, length, opts) {
6618 if(!opts.cellStyles) return parsenoop(blob, length);
6619 var w = opts && opts.biff >= 12 ? 4 : 2;
6620 var colFirst = blob.read_shift(w);
6621 var colLast = blob.read_shift(w);
6622 var coldx = blob.read_shift(w);
6623 var ixfe = blob.read_shift(w);
6624 var flags = blob.read_shift(2);
6625 if(w == 2) blob.l += 2;
6626 var o = ({s:colFirst, e:colLast, w:coldx, ixfe:ixfe, flags:flags});
6627 if(opts.biff >= 5 || !opts.biff) o.level = (flags >> 8) & 0x7;
6628 return o;
6629}
6630
6631/* [MS-XLS] 2.4.257 */
6632function parse_Setup(blob, length) {
6633 var o = {};
6634 if(length < 32) return o;
6635 blob.l += 16;
6636 o.header = parse_Xnum(blob, 8);
6637 o.footer = parse_Xnum(blob, 8);
6638 blob.l += 2;
6639 return o;
6640}
6641
6642/* [MS-XLS] 2.4.261 */
6643function parse_ShtProps(blob, length, opts) {
6644 var def = {area:false};
6645 if(opts.biff != 5) { blob.l += length; return def; }
6646 var d = blob.read_shift(1); blob.l += 3;
6647 if((d & 0x10)) def.area = true;
6648 return def;
6649}
6650
6651/* [MS-XLS] 2.4.241 */
6652function write_RRTabId(n) {
6653 var out = new_buf(2 * n);
6654 for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
6655 return out;
6656}
6657
6658var parse_Blank = parse_XLSCell; /* [MS-XLS] 2.4.20 Just the cell */
6659var parse_Scl = parseuint16a; /* [MS-XLS] 2.4.247 num, den */
6660var parse_String = parse_XLUnicodeString; /* [MS-XLS] 2.4.268 */
6661
6662/* --- Specific to versions before BIFF8 --- */
6663function parse_ImData(blob) {
6664 var cf = blob.read_shift(2);
6665 var env = blob.read_shift(2);
6666 var lcb = blob.read_shift(4);
6667 var o = {fmt:cf, env:env, len:lcb, data:blob.slice(blob.l,blob.l+lcb)};
6668 blob.l += lcb;
6669 return o;
6670}
6671
6672/* BIFF2_??? where ??? is the name from [XLS] */
6673function parse_BIFF2STR(blob, length, opts) {
6674 var cell = parse_XLSCell(blob, 6);
6675 ++blob.l;
6676 var str = parse_XLUnicodeString2(blob, length-7, opts);
6677 cell.t = 'str';
6678 cell.val = str;
6679 return cell;
6680}
6681
6682function parse_BIFF2NUM(blob) {
6683 var cell = parse_XLSCell(blob, 6);
6684 ++blob.l;
6685 var num = parse_Xnum(blob, 8);
6686 cell.t = 'n';
6687 cell.val = num;
6688 return cell;
6689}
6690function write_BIFF2NUM(r, c, val) {
6691 var out = new_buf(15);
6692 write_BIFF2Cell(out, r, c);
6693 out.write_shift(8, val, 'f');
6694 return out;
6695}
6696
6697function parse_BIFF2INT(blob) {
6698 var cell = parse_XLSCell(blob, 6);
6699 ++blob.l;
6700 var num = blob.read_shift(2);
6701 cell.t = 'n';
6702 cell.val = num;
6703 return cell;
6704}
6705function write_BIFF2INT(r, c, val) {
6706 var out = new_buf(9);
6707 write_BIFF2Cell(out, r, c);
6708 out.write_shift(2, val);
6709 return out;
6710}
6711
6712function parse_BIFF2STRING(blob) {
6713 var cch = blob.read_shift(1);
6714 if(cch === 0) { blob.l++; return ""; }
6715 return blob.read_shift(cch, 'sbcs-cont');
6716}
6717
6718/* TODO: convert to BIFF8 font struct */
6719function parse_BIFF2FONTXTRA(blob, length) {
6720 blob.l += 6; // unknown
6721 blob.l += 2; // font weight "bls"
6722 blob.l += 1; // charset
6723 blob.l += 3; // unknown
6724 blob.l += 1; // font family
6725 blob.l += length - 13;
6726}
6727
6728/* TODO: parse rich text runs */
6729function parse_RString(blob, length, opts) {
6730 var end = blob.l + length;
6731 var cell = parse_XLSCell(blob, 6);
6732 var cch = blob.read_shift(2);
6733 var str = parse_XLUnicodeStringNoCch(blob, cch, opts);
6734 blob.l = end;
6735 cell.t = 'str';
6736 cell.val = str;
6737 return cell;
6738}
6739/* from js-harb (C) 2014-present SheetJS */
6740var DBF = (function() {
6741var dbf_codepage_map = {
6742 /* Code Pages Supported by Visual FoxPro */
67430x01: 437, 0x02: 850,
67440x03: 1252, 0x04: 10000,
67450x64: 852, 0x65: 866,
67460x66: 865, 0x67: 861,
67470x68: 895, 0x69: 620,
67480x6A: 737, 0x6B: 857,
67490x78: 950, 0x79: 949,
67500x7A: 936, 0x7B: 932,
67510x7C: 874, 0x7D: 1255,
67520x7E: 1256, 0x96: 10007,
67530x97: 10029, 0x98: 10006,
67540xC8: 1250, 0xC9: 1251,
67550xCA: 1254, 0xCB: 1253,
6756
6757 /* shapefile DBF extension */
67580x00: 20127, 0x08: 865,
67590x09: 437, 0x0A: 850,
67600x0B: 437, 0x0D: 437,
67610x0E: 850, 0x0F: 437,
67620x10: 850, 0x11: 437,
67630x12: 850, 0x13: 932,
67640x14: 850, 0x15: 437,
67650x16: 850, 0x17: 865,
67660x18: 437, 0x19: 437,
67670x1A: 850, 0x1B: 437,
67680x1C: 863, 0x1D: 850,
67690x1F: 852, 0x22: 852,
67700x23: 852, 0x24: 860,
67710x25: 850, 0x26: 866,
67720x37: 850, 0x40: 852,
67730x4D: 936, 0x4E: 949,
67740x4F: 950, 0x50: 874,
67750x57: 1252, 0x58: 1252,
67760x59: 1252,
6777
67780xFF: 16969
6779};
6780var dbf_reverse_map = evert({
67810x01: 437, 0x02: 850,
67820x03: 1252, 0x04: 10000,
67830x64: 852, 0x65: 866,
67840x66: 865, 0x67: 861,
67850x68: 895, 0x69: 620,
67860x6A: 737, 0x6B: 857,
67870x78: 950, 0x79: 949,
67880x7A: 936, 0x7B: 932,
67890x7C: 874, 0x7D: 1255,
67900x7E: 1256, 0x96: 10007,
67910x97: 10029, 0x98: 10006,
67920xC8: 1250, 0xC9: 1251,
67930xCA: 1254, 0xCB: 1253,
67940x00: 20127
6795});
6796/* TODO: find an actual specification */
6797function dbf_to_aoa(buf, opts) {
6798 var out = [];
6799 /* TODO: browser based */
6800 var d = (new_raw_buf(1));
6801 switch(opts.type) {
6802 case 'base64': d = s2a(Base64.decode(buf)); break;
6803 case 'binary': d = s2a(buf); break;
6804 case 'buffer':
6805 case 'array': d = buf; break;
6806 }
6807 prep_blob(d, 0);
6808 /* header */
6809 var ft = d.read_shift(1);
6810 var memo = false;
6811 var vfp = false, l7 = false;
6812 switch(ft) {
6813 case 0x02: case 0x03: break;
6814 case 0x30: vfp = true; memo = true; break;
6815 case 0x31: vfp = true; break;
6816 case 0x83: memo = true; break;
6817 case 0x8B: memo = true; break;
6818 case 0x8C: memo = true; l7 = true; break;
6819 case 0xF5: memo = true; break;
6820 default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
6821 }
6822 var /*filedate = new Date(),*/ nrow = 0, fpos = 0;
6823 if(ft == 0x02) nrow = d.read_shift(2);
6824 /*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3;
6825 if(ft != 0x02) nrow = d.read_shift(4);
6826 if(ft != 0x02) fpos = d.read_shift(2);
6827 var rlen = d.read_shift(2);
6828
6829 var /*flags = 0,*/ current_cp = 1252;
6830 if(ft != 0x02) {
6831 d.l+=16;
6832 /*flags = */d.read_shift(1);
6833 //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
6834
6835 /* codepage present in FoxPro */
6836 if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
6837 d.l+=1;
6838
6839 d.l+=2;
6840 }
6841 if(l7) d.l += 36;
6842var fields = [], field = ({});
6843 var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
6844 while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
6845 field = ({});
6846 field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
6847 d.l += ww;
6848 field.type = String.fromCharCode(d.read_shift(1));
6849 if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
6850 field.len = d.read_shift(1);
6851 if(ft == 0x02) field.offset = d.read_shift(2);
6852 field.dec = d.read_shift(1);
6853 if(field.name.length) fields.push(field);
6854 if(ft != 0x02) d.l += l7 ? 13 : 14;
6855 switch(field.type) {
6856 case 'B': // VFP Double
6857 if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6858 break;
6859 case 'G': // General
6860 case 'P': // Picture
6861 if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
6862 break;
6863 case 'C': // character
6864 case 'D': // date
6865 case 'F': // floating point
6866 case 'I': // long
6867 case 'L': // boolean
6868 case 'M': // memo
6869 case 'N': // number
6870 case 'O': // double
6871 case 'T': // datetime
6872 case 'Y': // currency
6873 case '0': // VFP _NullFlags
6874 case '@': // timestamp
6875 case '+': // autoincrement
6876 break;
6877 default: throw new Error('Unknown Field Type: ' + field.type);
6878 }
6879 }
6880 if(d[d.l] !== 0x0D) d.l = fpos-1;
6881 else if(ft == 0x02) d.l = 0x209;
6882 if(ft != 0x02) {
6883 if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
6884 d.l = fpos;
6885 }
6886 /* data */
6887 var R = 0, C = 0;
6888 out[0] = [];
6889 for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
6890 while(nrow-- > 0) {
6891 if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
6892 ++d.l;
6893 out[++R] = []; C = 0;
6894 for(C = 0; C != fields.length; ++C) {
6895 var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
6896 prep_blob(dd, 0);
6897 var s = cptable.utils.decode(current_cp, dd);
6898 switch(fields[C].type) {
6899 case 'C':
6900 out[R][C] = cptable.utils.decode(current_cp, dd);
6901 out[R][C] = out[R][C].trim();
6902 break;
6903 case 'D':
6904 if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
6905 else out[R][C] = s;
6906 break;
6907 case 'F': out[R][C] = parseFloat(s.trim()); break;
6908 case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
6909 case 'L': switch(s.toUpperCase()) {
6910 case 'Y': case 'T': out[R][C] = true; break;
6911 case 'N': case 'F': out[R][C] = false; break;
6912 case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
6913 default: throw new Error("DBF Unrecognized L:|" + s + "|");
6914 } break;
6915 case 'M': /* TODO: handle memo files */
6916 if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
6917 out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
6918 break;
6919 case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
6920 case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
6921 case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
6922 case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
6923 case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
6924 case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
6925 /* falls through */
6926 case 'G': case 'P': dd.l += fields[C].len; break;
6927 case '0':
6928 if(fields[C].name === '_NullFlags') break;
6929 /* falls through */
6930 default: throw new Error("DBF Unsupported data type " + fields[C].type);
6931 }
6932 }
6933 }
6934 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));
6935 if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
6936 return out;
6937}
6938
6939function dbf_to_sheet(buf, opts) {
6940 var o = opts || {};
6941 if(!o.dateNF) o.dateNF = "yyyymmdd";
6942 return aoa_to_sheet(dbf_to_aoa(buf, o), o);
6943}
6944
6945function dbf_to_workbook(buf, opts) {
6946 try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
6947 catch(e) { if(opts && opts.WTF) throw e; }
6948 return ({SheetNames:[],Sheets:{}});
6949}
6950
6951var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
6952function sheet_to_dbf(ws, opts) {
6953 var o = opts || {};
6954 if(+o.codepage >= 0) set_cp(+o.codepage);
6955 if(o.type == "string") throw new Error("Cannot write DBF to JS string");
6956 var ba = buf_array();
6957 var aoa = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
6958 var headers = aoa[0], data = aoa.slice(1);
6959 var i = 0, j = 0, hcnt = 0, rlen = 1;
6960 for(i = 0; i < headers.length; ++i) {
6961 if(i == null) continue;
6962 ++hcnt;
6963 if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
6964 if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
6965 if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
6966 if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
6967 }
6968 var range = safe_decode_range(ws['!ref']);
6969 var coltypes = [];
6970 for(i = 0; i <= range.e.c - range.s.c; ++i) {
6971 var col = [];
6972 for(j=0; j < data.length; ++j) {
6973 if(data[j][i] != null) col.push(data[j][i]);
6974 }
6975 if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
6976 var guess = '', _guess = '';
6977 for(j = 0; j < col.length; ++j) {
6978 switch(typeof col[j]) {
6979 /* TODO: check if L2 compat is desired */
6980 case 'number': _guess = 'B'; break;
6981 case 'string': _guess = 'C'; break;
6982 case 'boolean': _guess = 'L'; break;
6983 case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
6984 default: _guess = 'C';
6985 }
6986 guess = guess && guess != _guess ? 'C' : _guess;
6987 if(guess == 'C') break;
6988 }
6989 rlen += _RLEN[guess] || 0;
6990 coltypes[i] = guess;
6991 }
6992
6993 var h = ba.next(32);
6994 h.write_shift(4, 0x13021130);
6995 h.write_shift(4, data.length);
6996 h.write_shift(2, 296 + 32 * hcnt);
6997 h.write_shift(2, rlen);
6998 for(i=0; i < 4; ++i) h.write_shift(4, 0);
6999 h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[current_ansi] || 0x03)<<8));
7000
7001 for(i = 0, j = 0; i < headers.length; ++i) {
7002 if(headers[i] == null) continue;
7003 var hf = ba.next(32);
7004 var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
7005 hf.write_shift(1, _f, "sbcs");
7006 hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
7007 hf.write_shift(4, j);
7008 hf.write_shift(1, _RLEN[coltypes[i]] || 0);
7009 hf.write_shift(1, 0);
7010 hf.write_shift(1, 0x02);
7011 hf.write_shift(4, 0);
7012 hf.write_shift(1, 0);
7013 hf.write_shift(4, 0);
7014 hf.write_shift(4, 0);
7015 j += _RLEN[coltypes[i]] || 0;
7016 }
7017
7018 var hb = ba.next(264);
7019 hb.write_shift(4, 0x0000000D);
7020 for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
7021 for(i=0; i < data.length; ++i) {
7022 var rout = ba.next(rlen);
7023 rout.write_shift(1, 0);
7024 for(j=0; j<headers.length; ++j) {
7025 if(headers[j] == null) continue;
7026 switch(coltypes[j]) {
7027 case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
7028 case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
7029 case 'D':
7030 if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
7031 else {
7032 rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
7033 rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
7034 rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
7035 } break;
7036 case 'C':
7037 var _s = String(data[i][j]||"");
7038 rout.write_shift(1, _s, "sbcs");
7039 for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
7040 }
7041 }
7042 // data
7043 }
7044 ba.next(1).write_shift(1, 0x1A);
7045 return ba.end();
7046}
7047 return {
7048 to_workbook: dbf_to_workbook,
7049 to_sheet: dbf_to_sheet,
7050 from_sheet: sheet_to_dbf
7051 };
7052})();
7053
7054var SYLK = (function() {
7055 /* TODO: stress test sequences */
7056 var sylk_escapes = ({
7057 AA:'À', BA:'Á', CA:'Â', DA:195, HA:'Ä', JA:197,
7058 AE:'È', BE:'É', CE:'Ê', HE:'Ë',
7059 AI:'Ì', BI:'Í', CI:'Î', HI:'Ï',
7060 AO:'Ò', BO:'Ó', CO:'Ô', DO:213, HO:'Ö',
7061 AU:'Ù', BU:'Ú', CU:'Û', HU:'Ü',
7062 Aa:'à', Ba:'á', Ca:'â', Da:227, Ha:'ä', Ja:229,
7063 Ae:'è', Be:'é', Ce:'ê', He:'ë',
7064 Ai:'ì', Bi:'í', Ci:'î', Hi:'ï',
7065 Ao:'ò', Bo:'ó', Co:'ô', Do:245, Ho:'ö',
7066 Au:'ù', Bu:'ú', Cu:'û', Hu:'ü',
7067 KC:'Ç', Kc:'ç', q:'æ', z:'œ', a:'Æ', j:'Œ',
7068 DN:209, Dn:241, Hy:255,
7069 S:169, c:170, R:174, B:180,
70700:176, 1:177, 2:178,
70713:179, 5:181, 6:182,
70727:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
7073 "!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
7074 "+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
7075 });
7076 var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
7077 var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
7078 var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
7079 sylk_escapes["|"] = 254;
7080 /* TODO: find an actual specification */
7081 function sylk_to_aoa(d, opts) {
7082 switch(opts.type) {
7083 case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
7084 case 'binary': return sylk_to_aoa_str(d, opts);
7085 case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts);
7086 case 'array': return sylk_to_aoa_str(cc2str(d), opts);
7087 }
7088 throw new Error("Unrecognized type " + opts.type);
7089 }
7090 function sylk_to_aoa_str(str, opts) {
7091 var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
7092 var formats = [];
7093 var next_cell_format = null;
7094 var sht = {}, rowinfo = [], colinfo = [], cw = [];
7095 var Mval = 0, j;
7096 if(+opts.codepage >= 0) set_cp(+opts.codepage);
7097 for (; ri !== records.length; ++ri) {
7098 Mval = 0;
7099 var rstr=records[ri].trim().replace(/\x1B([\x20-\x2F])([\x30-\x3F])/g, decode_sylk_char).replace(sylk_char_regex, sylk_char_fn);
7100 var record=rstr.replace(/;;/g, "\u0000").split(";").map(function(x) { return x.replace(/\u0000/g, ";"); });
7101 var RT=record[0], val;
7102 if(rstr.length > 0) switch(RT) {
7103 case 'ID': break; /* header */
7104 case 'E': break; /* EOF */
7105 case 'B': break; /* dimensions */
7106 case 'O': break; /* options? */
7107 case 'P':
7108 if(record[1].charAt(0) == 'P')
7109 formats.push(rstr.slice(3).replace(/;;/g, ";"));
7110 break;
7111 case 'C':
7112 var C_seen_K = false, C_seen_X = false;
7113 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
7114 case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
7115 case 'Y':
7116 R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
7117 for(j = arr.length; j <= R; ++j) arr[j] = [];
7118 break;
7119 case 'K':
7120 val = record[rj].slice(1);
7121 if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
7122 else if(val === 'TRUE') val = true;
7123 else if(val === 'FALSE') val = false;
7124 else if(!isNaN(fuzzynum(val))) {
7125 val = fuzzynum(val);
7126 if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
7127 } else if(!isNaN(fuzzydate(val).getDate())) {
7128 val = parseDate(val);
7129 }
7130 if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
7131 C_seen_K = true;
7132 break;
7133 case 'E':
7134 var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
7135 arr[R][C] = [arr[R][C], formula];
7136 break;
7137 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7138 }
7139 if(C_seen_K) { arr[R][C] = val; next_cell_format = null; }
7140 break;
7141 case 'F':
7142 var F_seen = 0;
7143 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
7144 case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
7145 case 'Y':
7146 R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
7147 for(j = arr.length; j <= R; ++j) arr[j] = [];
7148 break;
7149 case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
7150 case 'F': break; /* ??? */
7151 case 'G': break; /* hide grid */
7152 case 'P':
7153 next_cell_format = formats[parseInt(record[rj].slice(1))];
7154 break;
7155 case 'S': break; /* cell style */
7156 case 'D': break; /* column */
7157 case 'N': break; /* font */
7158 case 'W':
7159 cw = record[rj].slice(1).split(" ");
7160 for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
7161 Mval = parseInt(cw[2], 10);
7162 colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
7163 } break;
7164 case 'C': /* default column format */
7165 C = parseInt(record[rj].slice(1))-1;
7166 if(!colinfo[C]) colinfo[C] = {};
7167 break;
7168 case 'R': /* row properties */
7169 R = parseInt(record[rj].slice(1))-1;
7170 if(!rowinfo[R]) rowinfo[R] = {};
7171 if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
7172 else if(Mval === 0) rowinfo[R].hidden = true;
7173 break;
7174 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7175 }
7176 if(F_seen < 1) next_cell_format = null; break;
7177 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
7178 }
7179 }
7180 if(rowinfo.length > 0) sht['!rows'] = rowinfo;
7181 if(colinfo.length > 0) sht['!cols'] = colinfo;
7182 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7183 return [arr, sht];
7184 }
7185
7186 function sylk_to_sheet(d, opts) {
7187 var aoasht = sylk_to_aoa(d, opts);
7188 var aoa = aoasht[0], ws = aoasht[1];
7189 var o = aoa_to_sheet(aoa, opts);
7190 keys(ws).forEach(function(k) { o[k] = ws[k]; });
7191 return o;
7192 }
7193
7194 function sylk_to_workbook(d, opts) { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
7195
7196 function write_ws_cell_sylk(cell, ws, R, C) {
7197 var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
7198 switch(cell.t) {
7199 case 'n':
7200 o += (cell.v||0);
7201 if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
7202 case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
7203 case 'e': o += cell.w || cell.v; break;
7204 case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
7205 case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
7206 }
7207 return o;
7208 }
7209
7210 function write_ws_cols_sylk(out, cols) {
7211 cols.forEach(function(col, i) {
7212 var rec = "F;W" + (i+1) + " " + (i+1) + " ";
7213 if(col.hidden) rec += "0";
7214 else {
7215 if(typeof col.width == 'number') col.wpx = width2px(col.width);
7216 if(typeof col.wpx == 'number') col.wch = px2char(col.wpx);
7217 if(typeof col.wch == 'number') rec += Math.round(col.wch);
7218 }
7219 if(rec.charAt(rec.length - 1) != " ") out.push(rec);
7220 });
7221 }
7222
7223 function write_ws_rows_sylk(out, rows) {
7224 rows.forEach(function(row, i) {
7225 var rec = "F;";
7226 if(row.hidden) rec += "M0;";
7227 else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
7228 else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
7229 if(rec.length > 2) out.push(rec + "R" + (i+1));
7230 });
7231 }
7232
7233 function sheet_to_sylk(ws, opts) {
7234 var preamble = ["ID;PWXL;N;E"], o = [];
7235 var r = safe_decode_range(ws['!ref']), cell;
7236 var dense = Array.isArray(ws);
7237 var RS = "\r\n";
7238
7239 preamble.push("P;PGeneral");
7240 preamble.push("F;P0;DG0G8;M255");
7241 if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
7242 if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
7243
7244 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(" "));
7245 for(var R = r.s.r; R <= r.e.r; ++R) {
7246 for(var C = r.s.c; C <= r.e.c; ++C) {
7247 var coord = encode_cell({r:R,c:C});
7248 cell = dense ? (ws[R]||[])[C]: ws[coord];
7249 if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
7250 o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
7251 }
7252 }
7253 return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
7254 }
7255
7256 return {
7257 to_workbook: sylk_to_workbook,
7258 to_sheet: sylk_to_sheet,
7259 from_sheet: sheet_to_sylk
7260 };
7261})();
7262
7263var DIF = (function() {
7264 function dif_to_aoa(d, opts) {
7265 switch(opts.type) {
7266 case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
7267 case 'binary': return dif_to_aoa_str(d, opts);
7268 case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts);
7269 case 'array': return dif_to_aoa_str(cc2str(d), opts);
7270 }
7271 throw new Error("Unrecognized type " + opts.type);
7272 }
7273 function dif_to_aoa_str(str, opts) {
7274 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
7275 for (; ri !== records.length; ++ri) {
7276 if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
7277 if (R < 0) continue;
7278 var metadata = records[ri].trim().split(",");
7279 var type = metadata[0], value = metadata[1];
7280 ++ri;
7281 var data = records[ri].trim();
7282 switch (+type) {
7283 case -1:
7284 if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
7285 else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
7286 break;
7287 case 0:
7288 if(data === 'TRUE') arr[R][C] = true;
7289 else if(data === 'FALSE') arr[R][C] = false;
7290 else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
7291 else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
7292 else arr[R][C] = value;
7293 ++C; break;
7294 case 1:
7295 data = data.slice(1,data.length-1);
7296 arr[R][C++] = data !== '' ? data : null;
7297 break;
7298 }
7299 if (data === 'EOD') break;
7300 }
7301 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7302 return arr;
7303 }
7304
7305 function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
7306 function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
7307
7308 var sheet_to_dif = (function() {
7309 var push_field = function pf(o, topic, v, n, s) {
7310 o.push(topic);
7311 o.push(v + "," + n);
7312 o.push('"' + s.replace(/"/g,'""') + '"');
7313 };
7314 var push_value = function po(o, type, v, s) {
7315 o.push(type + "," + v);
7316 o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
7317 };
7318 return function sheet_to_dif(ws) {
7319 var o = [];
7320 var r = safe_decode_range(ws['!ref']), cell;
7321 var dense = Array.isArray(ws);
7322 push_field(o, "TABLE", 0, 1, "sheetjs");
7323 push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
7324 push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
7325 push_field(o, "DATA", 0, 0,"");
7326 for(var R = r.s.r; R <= r.e.r; ++R) {
7327 push_value(o, -1, 0, "BOT");
7328 for(var C = r.s.c; C <= r.e.c; ++C) {
7329 var coord = encode_cell({r:R,c:C});
7330 cell = dense ? (ws[R]||[])[C] : ws[coord];
7331 if(!cell) { push_value(o, 1, 0, ""); continue;}
7332 switch(cell.t) {
7333 case 'n':
7334 var val = DIF_XL ? cell.w : cell.v;
7335 if(!val && cell.v != null) val = cell.v;
7336 if(val == null) {
7337 if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
7338 else push_value(o, 1, 0, "");
7339 }
7340 else push_value(o, 0, val, "V");
7341 break;
7342 case 'b':
7343 push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
7344 break;
7345 case 's':
7346 push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
7347 break;
7348 case 'd':
7349 if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
7350 if(DIF_XL) push_value(o, 0, cell.w, "V");
7351 else push_value(o, 1, 0, cell.w);
7352 break;
7353 default: push_value(o, 1, 0, "");
7354 }
7355 }
7356 }
7357 push_value(o, -1, 0, "EOD");
7358 var RS = "\r\n";
7359 var oo = o.join(RS);
7360 //while((oo.length & 0x7F) != 0) oo += "\0";
7361 return oo;
7362 };
7363 })();
7364 return {
7365 to_workbook: dif_to_workbook,
7366 to_sheet: dif_to_sheet,
7367 from_sheet: sheet_to_dif
7368 };
7369})();
7370
7371var ETH = (function() {
7372 function decode(s) { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
7373 function encode(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
7374
7375 function eth_to_aoa(str, opts) {
7376 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
7377 for (; ri !== records.length; ++ri) {
7378 var record = records[ri].trim().split(":");
7379 if(record[0] !== 'cell') continue;
7380 var addr = decode_cell(record[1]);
7381 if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
7382 R = addr.r; C = addr.c;
7383 switch(record[2]) {
7384 case 't': arr[R][C] = decode(record[3]); break;
7385 case 'v': arr[R][C] = +record[3]; break;
7386 case 'vtf': var _f = record[record.length - 1];
7387 /* falls through */
7388 case 'vtc':
7389 switch(record[3]) {
7390 case 'nl': arr[R][C] = +record[4] ? true : false; break;
7391 default: arr[R][C] = +record[4]; break;
7392 }
7393 if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
7394 }
7395 }
7396 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
7397 return arr;
7398 }
7399
7400 function eth_to_sheet(d, opts) { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
7401 function eth_to_workbook(d, opts) { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
7402
7403 var header = [
7404 "socialcalc:version:1.5",
7405 "MIME-Version: 1.0",
7406 "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
7407 ].join("\n");
7408
7409 var sep = [
7410 "--SocialCalcSpreadsheetControlSave",
7411 "Content-type: text/plain; charset=UTF-8"
7412 ].join("\n") + "\n";
7413
7414 /* TODO: the other parts */
7415 var meta = [
7416 "# SocialCalc Spreadsheet Control Save",
7417 "part:sheet"
7418 ].join("\n");
7419
7420 var end = "--SocialCalcSpreadsheetControlSave--";
7421
7422 function sheet_to_eth_data(ws) {
7423 if(!ws || !ws['!ref']) return "";
7424 var o = [], oo = [], cell, coord = "";
7425 var r = decode_range(ws['!ref']);
7426 var dense = Array.isArray(ws);
7427 for(var R = r.s.r; R <= r.e.r; ++R) {
7428 for(var C = r.s.c; C <= r.e.c; ++C) {
7429 coord = encode_cell({r:R,c:C});
7430 cell = dense ? (ws[R]||[])[C] : ws[coord];
7431 if(!cell || cell.v == null || cell.t === 'z') continue;
7432 oo = ["cell", coord, 't'];
7433 switch(cell.t) {
7434 case 's': case 'str': oo.push(encode(cell.v)); break;
7435 case 'n':
7436 if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
7437 else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
7438 break;
7439 case 'b':
7440 oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
7441 oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
7442 break;
7443 case 'd':
7444 var t = datenum(parseDate(cell.v));
7445 oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
7446 oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
7447 break;
7448 case 'e': continue;
7449 }
7450 o.push(oo.join(":"));
7451 }
7452 }
7453 o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
7454 o.push("valueformat:1:text-wiki");
7455 //o.push("copiedfrom:" + ws['!ref']); // clipboard only
7456 return o.join("\n");
7457 }
7458
7459 function sheet_to_eth(ws) {
7460 return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
7461 // return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
7462 }
7463
7464 return {
7465 to_workbook: eth_to_workbook,
7466 to_sheet: eth_to_sheet,
7467 from_sheet: sheet_to_eth
7468 };
7469})();
7470
7471var PRN = (function() {
7472 function set_text_arr(data, arr, R, C, o) {
7473 if(o.raw) arr[R][C] = data;
7474 else if(data === 'TRUE') arr[R][C] = true;
7475 else if(data === 'FALSE') arr[R][C] = false;
7476 else if(data === ""){/* empty */}
7477 else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
7478 else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
7479 else arr[R][C] = data;
7480 }
7481
7482 function prn_to_aoa_str(f, opts) {
7483 var o = opts || {};
7484 var arr = ([]);
7485 if(!f || f.length === 0) return arr;
7486 var lines = f.split(/[\r\n]/);
7487 var L = lines.length - 1;
7488 while(L >= 0 && lines[L].length === 0) --L;
7489 var start = 10, idx = 0;
7490 var R = 0;
7491 for(; R <= L; ++R) {
7492 idx = lines[R].indexOf(" ");
7493 if(idx == -1) idx = lines[R].length; else idx++;
7494 start = Math.max(start, idx);
7495 }
7496 for(R = 0; R <= L; ++R) {
7497 arr[R] = [];
7498 /* TODO: confirm that widths are always 10 */
7499 var C = 0;
7500 set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
7501 for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
7502 set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
7503 }
7504 if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
7505 return arr;
7506 }
7507
7508 // List of accepted CSV separators
7509 var guess_seps = {
75100x2C: ',',
75110x09: "\t",
75120x3B: ';'
7513 };
7514
7515 // CSV separator weights to be used in case of equal numbers
7516 var guess_sep_weights = {
75170x2C: 3,
75180x09: 2,
75190x3B: 1
7520 };
7521
7522 function guess_sep(str) {
7523 var cnt = {}, instr = false, end = 0, cc = 0;
7524 for(;end < str.length;++end) {
7525 if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
7526 else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
7527 }
7528
7529 cc = [];
7530 for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
7531 cc.push([ cnt[end], end ]);
7532 }
7533
7534 if ( !cc.length ) {
7535 cnt = guess_sep_weights;
7536 for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
7537 cc.push([ cnt[end], end ]);
7538 }
7539 }
7540
7541 cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
7542
7543 return guess_seps[cc.pop()[1]];
7544 }
7545
7546 function dsv_to_sheet_str(str, opts) {
7547 var o = opts || {};
7548 var sep = "";
7549 if(DENSE != null && o.dense == null) o.dense = DENSE;
7550 var ws = o.dense ? ([]) : ({});
7551 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
7552
7553 if(str.slice(0,4) == "sep=" && str.charCodeAt(5) == 10) { sep = str.charAt(4); str = str.slice(6); }
7554 else sep = guess_sep(str.slice(0,1024));
7555 var R = 0, C = 0, v = 0;
7556 var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
7557 str = str.replace(/\r\n/mg, "\n");
7558 var _re = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
7559 function finish_cell() {
7560 var s = str.slice(start, end);
7561 var cell = ({});
7562 if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
7563 if(s.length === 0) cell.t = 'z';
7564 else if(o.raw) { cell.t = 's'; cell.v = s; }
7565 else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
7566 else if(s.charCodeAt(0) == 0x3D) {
7567 if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
7568 else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
7569 else { cell.t = 's'; cell.v = s; } }
7570 else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
7571 else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
7572 else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
7573 else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
7574 cell.z = o.dateNF || SSF._table[14];
7575 var k = 0;
7576 if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
7577 if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
7578 else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
7579 if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
7580 if(!o.cellNF) delete cell.z;
7581 } else {
7582 cell.t = 's';
7583 cell.v = s;
7584 }
7585 if(cell.t == 'z'){}
7586 else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
7587 else ws[encode_cell({c:C,r:R})] = cell;
7588 start = end+1;
7589 if(range.e.c < C) range.e.c = C;
7590 if(range.e.r < R) range.e.r = R;
7591 if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
7592 }
7593 outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
7594 case 0x22: instr = !instr; break;
7595 case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
7596 default: break;
7597 }
7598 if(end - start > 0) finish_cell();
7599
7600 ws['!ref'] = encode_range(range);
7601 return ws;
7602 }
7603
7604 function prn_to_sheet_str(str, opts) {
7605 if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
7606 if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
7607 return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
7608 }
7609
7610 function prn_to_sheet(d, opts) {
7611 var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
7612 switch(opts.type) {
7613 case 'base64': str = Base64.decode(d); break;
7614 case 'binary': str = d; break;
7615 case 'buffer':
7616 if(opts.codepage == 65001) str = d.toString('utf8');
7617 else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
7618 else str = d.toString('binary');
7619 break;
7620 case 'array': str = cc2str(d); break;
7621 case 'string': str = d; break;
7622 default: throw new Error("Unrecognized type " + opts.type);
7623 }
7624 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
7625 else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage) str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str));
7626 if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
7627 return prn_to_sheet_str(str, opts);
7628 }
7629
7630 function prn_to_workbook(d, opts) { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
7631
7632 function sheet_to_prn(ws) {
7633 var o = [];
7634 var r = safe_decode_range(ws['!ref']), cell;
7635 var dense = Array.isArray(ws);
7636 for(var R = r.s.r; R <= r.e.r; ++R) {
7637 var oo = [];
7638 for(var C = r.s.c; C <= r.e.c; ++C) {
7639 var coord = encode_cell({r:R,c:C});
7640 cell = dense ? (ws[R]||[])[C] : ws[coord];
7641 if(!cell || cell.v == null) { oo.push(" "); continue; }
7642 var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
7643 while(w.length < 10) w += " ";
7644 oo.push(w + (C === 0 ? " " : ""));
7645 }
7646 o.push(oo.join(""));
7647 }
7648 return o.join("\n");
7649 }
7650
7651 return {
7652 to_workbook: prn_to_workbook,
7653 to_sheet: prn_to_sheet,
7654 from_sheet: sheet_to_prn
7655 };
7656})();
7657
7658/* Excel defaults to SYLK but warns if data is not valid */
7659function read_wb_ID(d, opts) {
7660 var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
7661 try {
7662 var out = SYLK.to_workbook(d, o);
7663 o.WTF = OLD_WTF;
7664 return out;
7665 } catch(e) {
7666 o.WTF = OLD_WTF;
7667 if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
7668 return PRN.to_workbook(d, opts);
7669 }
7670}
7671
7672var WK_ = (function() {
7673 function lotushopper(data, cb, opts) {
7674 if(!data) return;
7675 prep_blob(data, data.l || 0);
7676 var Enum = opts.Enum || WK1Enum;
7677 while(data.l < data.length) {
7678 var RT = data.read_shift(2);
7679 var R = Enum[RT] || Enum[0xFF];
7680 var length = data.read_shift(2);
7681 var tgt = data.l + length;
7682 var d = (R.f||parsenoop)(data, length, opts);
7683 data.l = tgt;
7684 if(cb(d, R.n, RT)) return;
7685 }
7686 }
7687
7688 function lotus_to_workbook(d, opts) {
7689 switch(opts.type) {
7690 case 'base64': return lotus_to_workbook_buf(s2a(Base64.decode(d)), opts);
7691 case 'binary': return lotus_to_workbook_buf(s2a(d), opts);
7692 case 'buffer':
7693 case 'array': return lotus_to_workbook_buf(d, opts);
7694 }
7695 throw "Unsupported type " + opts.type;
7696 }
7697
7698 function lotus_to_workbook_buf(d, opts) {
7699 if(!d) return d;
7700 var o = opts || {};
7701 if(DENSE != null && o.dense == null) o.dense = DENSE;
7702 var s = ((o.dense ? [] : {})), n = "Sheet1", sidx = 0;
7703 var sheets = {}, snames = [n];
7704
7705 var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
7706 var sheetRows = o.sheetRows || 0;
7707
7708 if(d[2] == 0x02) o.Enum = WK1Enum;
7709 else if(d[2] == 0x1a) o.Enum = WK3Enum;
7710 else if(d[2] == 0x0e) { o.Enum = WK3Enum; o.qpro = true; d.l = 0; }
7711 else throw new Error("Unrecognized LOTUS BOF " + d[2]);
7712 lotushopper(d, function(val, Rn, RT) {
7713 if(d[2] == 0x02) switch(RT) {
7714 case 0x00:
7715 o.vers = val;
7716 if(val >= 0x1000) o.qpro = true;
7717 break;
7718 case 0x06: refguess = val; break; /* RANGE */
7719 case 0x0F: /* LABEL */
7720 if(!o.qpro) val[1].v = val[1].v.slice(1);
7721 /* falls through */
7722 case 0x0D: /* INTEGER */
7723 case 0x0E: /* NUMBER */
7724 case 0x10: /* FORMULA */
7725 case 0x33: /* STRING */
7726 /* TODO: actual translation of the format code */
7727 if(RT == 0x0E && (val[2] & 0x70) == 0x70 && (val[2] & 0x0F) > 1 && (val[2] & 0x0F) < 15) {
7728 val[1].z = o.dateNF || SSF._table[14];
7729 if(o.cellDates) { val[1].t = 'd'; val[1].v = numdate(val[1].v); }
7730 }
7731 if(o.dense) {
7732 if(!s[val[0].r]) s[val[0].r] = [];
7733 s[val[0].r][val[0].c] = val[1];
7734 } else s[encode_cell(val[0])] = val[1];
7735 break;
7736 } else switch(RT) {
7737 case 0x16: /* LABEL16 */
7738 val[1].v = val[1].v.slice(1);
7739 /* falls through */
7740 case 0x17: /* NUMBER17 */
7741 case 0x18: /* NUMBER18 */
7742 case 0x19: /* FORMULA19 */
7743 case 0x25: /* NUMBER25 */
7744 case 0x27: /* NUMBER27 */
7745 case 0x28: /* FORMULA28 */
7746 if(val[3] > sidx) {
7747 s["!ref"] = encode_range(refguess);
7748 sheets[n] = s;
7749 s = (o.dense ? [] : {});
7750 refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
7751 sidx = val[3]; n = "Sheet" + (sidx + 1);
7752 snames.push(n);
7753 }
7754 if(sheetRows > 0 && val[0].r >= sheetRows) break;
7755 if(o.dense) {
7756 if(!s[val[0].r]) s[val[0].r] = [];
7757 s[val[0].r][val[0].c] = val[1];
7758 } else s[encode_cell(val[0])] = val[1];
7759 if(refguess.e.c < val[0].c) refguess.e.c = val[0].c;
7760 if(refguess.e.r < val[0].r) refguess.e.r = val[0].r;
7761 break;
7762 default: break;
7763 }
7764 }, o);
7765
7766 s["!ref"] = encode_range(refguess);
7767 sheets[n] = s;
7768 return { SheetNames: snames, Sheets:sheets };
7769 }
7770
7771 function parse_RANGE(blob) {
7772 var o = {s:{c:0,r:0},e:{c:0,r:0}};
7773 o.s.c = blob.read_shift(2);
7774 o.s.r = blob.read_shift(2);
7775 o.e.c = blob.read_shift(2);
7776 o.e.r = blob.read_shift(2);
7777 if(o.s.c == 0xFFFF) o.s.c = o.e.c = o.s.r = o.e.r = 0;
7778 return o;
7779 }
7780
7781 function parse_cell(blob, length, opts) {
7782 var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7783 if(opts.qpro && opts.vers != 0x5120) {
7784 o[0].c = blob.read_shift(1);
7785 blob.l++;
7786 o[0].r = blob.read_shift(2);
7787 blob.l+=2;
7788 } else {
7789 o[2] = blob.read_shift(1);
7790 o[0].c = blob.read_shift(2); o[0].r = blob.read_shift(2);
7791 }
7792 return o;
7793 }
7794
7795 function parse_LABEL(blob, length, opts) {
7796 var tgt = blob.l + length;
7797 var o = parse_cell(blob, length, opts);
7798 o[1].t = 's';
7799 if(opts.vers == 0x5120) {
7800 blob.l++;
7801 var len = blob.read_shift(1);
7802 o[1].v = blob.read_shift(len, 'utf8');
7803 return o;
7804 }
7805 if(opts.qpro) blob.l++;
7806 o[1].v = blob.read_shift(tgt - blob.l, 'cstr');
7807 return o;
7808 }
7809
7810 function parse_INTEGER(blob, length, opts) {
7811 var o = parse_cell(blob, length, opts);
7812 o[1].v = blob.read_shift(2, 'i');
7813 return o;
7814 }
7815
7816 function parse_NUMBER(blob, length, opts) {
7817 var o = parse_cell(blob, length, opts);
7818 o[1].v = blob.read_shift(8, 'f');
7819 return o;
7820 }
7821
7822 function parse_FORMULA(blob, length, opts) {
7823 var tgt = blob.l + length;
7824 var o = parse_cell(blob, length, opts);
7825 /* TODO: formula */
7826 o[1].v = blob.read_shift(8, 'f');
7827 if(opts.qpro) blob.l = tgt;
7828 else {
7829 var flen = blob.read_shift(2);
7830 blob.l += flen;
7831 }
7832 return o;
7833 }
7834
7835 function parse_cell_3(blob) {
7836 var o = [{c:0,r:0}, {t:'n',v:0}, 0];
7837 o[0].r = blob.read_shift(2); o[3] = blob[blob.l++]; o[0].c = blob[blob.l++];
7838 return o;
7839 }
7840
7841 function parse_LABEL_16(blob, length) {
7842 var o = parse_cell_3(blob, length);
7843 o[1].t = 's';
7844 o[1].v = blob.read_shift(length - 4, 'cstr');
7845 return o;
7846 }
7847
7848 function parse_NUMBER_18(blob, length) {
7849 var o = parse_cell_3(blob, length);
7850 o[1].v = blob.read_shift(2);
7851 var v = o[1].v >> 1;
7852 /* TODO: figure out all of the corner cases */
7853 if(o[1].v & 0x1) {
7854 switch(v & 0x07) {
7855 case 1: v = (v >> 3) * 500; break;
7856 case 2: v = (v >> 3) / 20; break;
7857 case 4: v = (v >> 3) / 2000; break;
7858 case 6: v = (v >> 3) / 16; break;
7859 case 7: v = (v >> 3) / 64; break;
7860 default: throw "unknown NUMBER_18 encoding " + (v & 0x07);
7861 }
7862 }
7863 o[1].v = v;
7864 return o;
7865 }
7866
7867 function parse_NUMBER_17(blob, length) {
7868 var o = parse_cell_3(blob, length);
7869 var v1 = blob.read_shift(4);
7870 var v2 = blob.read_shift(4);
7871 var e = blob.read_shift(2);
7872 if(e == 0xFFFF) { o[1].v = 0; return o; }
7873 var s = e & 0x8000; e = (e&0x7FFF) - 16446;
7874 o[1].v = (s*2 - 1) * ((e > 0 ? (v2 << e) : (v2 >>> -e)) + (e > -32 ? (v1 << (e + 32)) : (v1 >>> -(e + 32))));
7875 return o;
7876 }
7877
7878 function parse_FORMULA_19(blob, length) {
7879 var o = parse_NUMBER_17(blob, 14);
7880 blob.l += length - 14; /* TODO: formula */
7881 return o;
7882 }
7883
7884 function parse_NUMBER_25(blob, length) {
7885 var o = parse_cell_3(blob, length);
7886 var v1 = blob.read_shift(4);
7887 o[1].v = v1 >> 6;
7888 return o;
7889 }
7890
7891 function parse_NUMBER_27(blob, length) {
7892 var o = parse_cell_3(blob, length);
7893 var v1 = blob.read_shift(8,'f');
7894 o[1].v = v1;
7895 return o;
7896 }
7897
7898 function parse_FORMULA_28(blob, length) {
7899 var o = parse_NUMBER_27(blob, 14);
7900 blob.l += length - 10; /* TODO: formula */
7901 return o;
7902 }
7903
7904 var WK1Enum = {
79050x0000: { n:"BOF", f:parseuint16 },
79060x0001: { n:"EOF" },
79070x0002: { n:"CALCMODE" },
79080x0003: { n:"CALCORDER" },
79090x0004: { n:"SPLIT" },
79100x0005: { n:"SYNC" },
79110x0006: { n:"RANGE", f:parse_RANGE },
79120x0007: { n:"WINDOW1" },
79130x0008: { n:"COLW1" },
79140x0009: { n:"WINTWO" },
79150x000A: { n:"COLW2" },
79160x000B: { n:"NAME" },
79170x000C: { n:"BLANK" },
79180x000D: { n:"INTEGER", f:parse_INTEGER },
79190x000E: { n:"NUMBER", f:parse_NUMBER },
79200x000F: { n:"LABEL", f:parse_LABEL },
79210x0010: { n:"FORMULA", f:parse_FORMULA },
79220x0018: { n:"TABLE" },
79230x0019: { n:"ORANGE" },
79240x001A: { n:"PRANGE" },
79250x001B: { n:"SRANGE" },
79260x001C: { n:"FRANGE" },
79270x001D: { n:"KRANGE1" },
79280x0020: { n:"HRANGE" },
79290x0023: { n:"KRANGE2" },
79300x0024: { n:"PROTEC" },
79310x0025: { n:"FOOTER" },
79320x0026: { n:"HEADER" },
79330x0027: { n:"SETUP" },
79340x0028: { n:"MARGINS" },
79350x0029: { n:"LABELFMT" },
79360x002A: { n:"TITLES" },
79370x002B: { n:"SHEETJS" },
79380x002D: { n:"GRAPH" },
79390x002E: { n:"NGRAPH" },
79400x002F: { n:"CALCCOUNT" },
79410x0030: { n:"UNFORMATTED" },
79420x0031: { n:"CURSORW12" },
79430x0032: { n:"WINDOW" },
79440x0033: { n:"STRING", f:parse_LABEL },
79450x0037: { n:"PASSWORD" },
79460x0038: { n:"LOCKED" },
79470x003C: { n:"QUERY" },
79480x003D: { n:"QUERYNAME" },
79490x003E: { n:"PRINT" },
79500x003F: { n:"PRINTNAME" },
79510x0040: { n:"GRAPH2" },
79520x0041: { n:"GRAPHNAME" },
79530x0042: { n:"ZOOM" },
79540x0043: { n:"SYMSPLIT" },
79550x0044: { n:"NSROWS" },
79560x0045: { n:"NSCOLS" },
79570x0046: { n:"RULER" },
79580x0047: { n:"NNAME" },
79590x0048: { n:"ACOMM" },
79600x0049: { n:"AMACRO" },
79610x004A: { n:"PARSE" },
79620x00FF: { n:"", f:parsenoop }
7963 };
7964
7965 var WK3Enum = {
79660x0000: { n:"BOF" },
79670x0001: { n:"EOF" },
79680x0003: { n:"??" },
79690x0004: { n:"??" },
79700x0005: { n:"??" },
79710x0006: { n:"??" },
79720x0007: { n:"??" },
79730x0009: { n:"??" },
79740x000a: { n:"??" },
79750x000b: { n:"??" },
79760x000c: { n:"??" },
79770x000e: { n:"??" },
79780x000f: { n:"??" },
79790x0010: { n:"??" },
79800x0011: { n:"??" },
79810x0012: { n:"??" },
79820x0013: { n:"??" },
79830x0015: { n:"??" },
79840x0016: { n:"LABEL16", f:parse_LABEL_16},
79850x0017: { n:"NUMBER17", f:parse_NUMBER_17 },
79860x0018: { n:"NUMBER18", f:parse_NUMBER_18 },
79870x0019: { n:"FORMULA19", f:parse_FORMULA_19},
79880x001a: { n:"??" },
79890x001b: { n:"??" },
79900x001c: { n:"??" },
79910x001d: { n:"??" },
79920x001e: { n:"??" },
79930x001f: { n:"??" },
79940x0021: { n:"??" },
79950x0025: { n:"NUMBER25", f:parse_NUMBER_25 },
79960x0027: { n:"NUMBER27", f:parse_NUMBER_27 },
79970x0028: { n:"FORMULA28", f:parse_FORMULA_28 },
79980x00FF: { n:"", f:parsenoop }
7999 };
8000 return {
8001 to_workbook: lotus_to_workbook
8002 };
8003})();
8004/* 18.4.7 rPr CT_RPrElt */
8005function parse_rpr(rpr) {
8006 var font = {}, m = rpr.match(tagregex), i = 0;
8007 var pass = false;
8008 if(m) for(;i!=m.length; ++i) {
8009 var y = parsexmltag(m[i]);
8010 switch(y[0].replace(/\w*:/g,"")) {
8011 /* 18.8.12 condense CT_BooleanProperty */
8012 /* ** not required . */
8013 case '<condense': break;
8014 /* 18.8.17 extend CT_BooleanProperty */
8015 /* ** not required . */
8016 case '<extend': break;
8017 /* 18.8.36 shadow CT_BooleanProperty */
8018 /* ** not required . */
8019 case '<shadow':
8020 if(!y.val) break;
8021 /* falls through */
8022 case '<shadow>':
8023 case '<shadow/>': font.shadow = 1; break;
8024 case '</shadow>': break;
8025
8026 /* 18.4.1 charset CT_IntProperty TODO */
8027 case '<charset':
8028 if(y.val == '1') break;
8029 font.cp = CS2CP[parseInt(y.val, 10)];
8030 break;
8031
8032 /* 18.4.2 outline CT_BooleanProperty TODO */
8033 case '<outline':
8034 if(!y.val) break;
8035 /* falls through */
8036 case '<outline>':
8037 case '<outline/>': font.outline = 1; break;
8038 case '</outline>': break;
8039
8040 /* 18.4.5 rFont CT_FontName */
8041 case '<rFont': font.name = y.val; break;
8042
8043 /* 18.4.11 sz CT_FontSize */
8044 case '<sz': font.sz = y.val; break;
8045
8046 /* 18.4.10 strike CT_BooleanProperty */
8047 case '<strike':
8048 if(!y.val) break;
8049 /* falls through */
8050 case '<strike>':
8051 case '<strike/>': font.strike = 1; break;
8052 case '</strike>': break;
8053
8054 /* 18.4.13 u CT_UnderlineProperty */
8055 case '<u':
8056 if(!y.val) break;
8057 switch(y.val) {
8058 case 'double': font.uval = "double"; break;
8059 case 'singleAccounting': font.uval = "single-accounting"; break;
8060 case 'doubleAccounting': font.uval = "double-accounting"; break;
8061 }
8062 /* falls through */
8063 case '<u>':
8064 case '<u/>': font.u = 1; break;
8065 case '</u>': break;
8066
8067 /* 18.8.2 b */
8068 case '<b':
8069 if(y.val == '0') break;
8070 /* falls through */
8071 case '<b>':
8072 case '<b/>': font.b = 1; break;
8073 case '</b>': break;
8074
8075 /* 18.8.26 i */
8076 case '<i':
8077 if(y.val == '0') break;
8078 /* falls through */
8079 case '<i>':
8080 case '<i/>': font.i = 1; break;
8081 case '</i>': break;
8082
8083 /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
8084 case '<color':
8085 if(y.rgb) font.color = y.rgb.slice(2,8);
8086 break;
8087
8088 /* 18.8.18 family ST_FontFamily */
8089 case '<family': font.family = y.val; break;
8090
8091 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
8092 case '<vertAlign': font.valign = y.val; break;
8093
8094 /* 18.8.35 scheme CT_FontScheme TODO */
8095 case '<scheme': break;
8096
8097 /* 18.2.10 extLst CT_ExtensionList ? */
8098 case '<extLst': case '<extLst>': case '</extLst>': break;
8099 case '<ext': pass = true; break;
8100 case '</ext>': pass = false; break;
8101 default:
8102 if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
8103 }
8104 }
8105 return font;
8106}
8107
8108var parse_rs = (function() {
8109 var tregex = matchtag("t"), rpregex = matchtag("rPr");
8110 /* 18.4.4 r CT_RElt */
8111 function parse_r(r) {
8112 /* 18.4.12 t ST_Xstring */
8113 var t = r.match(tregex)/*, cp = 65001*/;
8114 if(!t) return {t:"s", v:""};
8115
8116 var o = ({t:'s', v:unescapexml(t[1])});
8117 var rpr = r.match(rpregex);
8118 if(rpr) o.s = parse_rpr(rpr[1]);
8119 return o;
8120 }
8121 var rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/;
8122 return function parse_rs(rs) {
8123 return rs.replace(rregex,"").split(rend).map(parse_r).filter(function(r) { return r.v; });
8124 };
8125})();
8126
8127
8128/* Parse a list of <r> tags */
8129var rs_to_html = (function parse_rs_factory() {
8130 var nlregex = /(\r\n|\n)/g;
8131 function parse_rpr2(font, intro, outro) {
8132 var style = [];
8133
8134 if(font.u) style.push("text-decoration: underline;");
8135 if(font.uval) style.push("text-underline-style:" + font.uval + ";");
8136 if(font.sz) style.push("font-size:" + font.sz + "pt;");
8137 if(font.outline) style.push("text-effect: outline;");
8138 if(font.shadow) style.push("text-shadow: auto;");
8139 intro.push('<span style="' + style.join("") + '">');
8140
8141 if(font.b) { intro.push("<b>"); outro.push("</b>"); }
8142 if(font.i) { intro.push("<i>"); outro.push("</i>"); }
8143 if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
8144
8145 var align = font.valign || "";
8146 if(align == "superscript" || align == "super") align = "sup";
8147 else if(align == "subscript") align = "sub";
8148 if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
8149
8150 outro.push("</span>");
8151 return font;
8152 }
8153
8154 /* 18.4.4 r CT_RElt */
8155 function r_to_html(r) {
8156 var terms = [[],r.v,[]];
8157 if(!r.v) return "";
8158
8159 if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
8160
8161 return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
8162 }
8163
8164 return function parse_rs(rs) {
8165 return rs.map(r_to_html).join("");
8166 };
8167})();
8168
8169/* 18.4.8 si CT_Rst */
8170var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
8171var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
8172function parse_si(x, opts) {
8173 var html = opts ? opts.cellHTML : true;
8174 var z = {};
8175 if(!x) return null;
8176 //var y;
8177 /* 18.4.12 t ST_Xstring (Plaintext String) */
8178 // TODO: is whitespace actually valid here?
8179 if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
8180 z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
8181 z.r = utf8read(x);
8182 if(html) z.h = escapehtml(z.t);
8183 }
8184 /* 18.4.4 r CT_RElt (Rich Text Run) */
8185 else if((/*y = */x.match(sirregex))) {
8186 z.r = utf8read(x);
8187 z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
8188 if(html) z.h = rs_to_html(parse_rs(z.r));
8189 }
8190 /* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
8191 /* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
8192 return z;
8193}
8194
8195/* 18.4 Shared String Table */
8196var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
8197var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
8198var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
8199function parse_sst_xml(data, opts) {
8200 var s = ([]), ss = "";
8201 if(!data) return s;
8202 /* 18.4.9 sst CT_Sst */
8203 var sst = data.match(sstr0);
8204 if(sst) {
8205 ss = sst[2].replace(sstr1,"").split(sstr2);
8206 for(var i = 0; i != ss.length; ++i) {
8207 var o = parse_si(ss[i].trim(), opts);
8208 if(o != null) s[s.length] = o;
8209 }
8210 sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
8211 }
8212 return s;
8213}
8214
8215RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
8216var straywsregex = /^\s|\s$|[\t\n\r]/;
8217function write_sst_xml(sst, opts) {
8218 if(!opts.bookSST) return "";
8219 var o = [XML_HEADER];
8220 o[o.length] = (writextag('sst', null, {
8221 xmlns: XMLNS.main[0],
8222 count: sst.Count,
8223 uniqueCount: sst.Unique
8224 }));
8225 for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
8226 var s = sst[i];
8227 var sitag = "<si>";
8228 if(s.r) sitag += s.r;
8229 else {
8230 sitag += "<t";
8231 if(!s.t) s.t = "";
8232 if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
8233 sitag += ">" + escapexml(s.t) + "</t>";
8234 }
8235 sitag += "</si>";
8236 o[o.length] = (sitag);
8237 }
8238 if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
8239 return o.join("");
8240}
8241/* [MS-XLSB] 2.4.221 BrtBeginSst */
8242function parse_BrtBeginSst(data) {
8243 return [data.read_shift(4), data.read_shift(4)];
8244}
8245
8246/* [MS-XLSB] 2.1.7.45 Shared Strings */
8247function parse_sst_bin(data, opts) {
8248 var s = ([]);
8249 var pass = false;
8250 recordhopper(data, function hopper_sst(val, R_n, RT) {
8251 switch(RT) {
8252 case 0x009F: /* 'BrtBeginSst' */
8253 s.Count = val[0]; s.Unique = val[1]; break;
8254 case 0x0013: /* 'BrtSSTItem' */
8255 s.push(val); break;
8256 case 0x00A0: /* 'BrtEndSst' */
8257 return true;
8258
8259 case 0x0023: /* 'BrtFRTBegin' */
8260 pass = true; break;
8261 case 0x0024: /* 'BrtFRTEnd' */
8262 pass = false; break;
8263
8264 default:
8265 if(R_n.indexOf("Begin") > 0){/* empty */}
8266 else if(R_n.indexOf("End") > 0){/* empty */}
8267 if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
8268 }
8269 });
8270 return s;
8271}
8272
8273function write_BrtBeginSst(sst, o) {
8274 if(!o) o = new_buf(8);
8275 o.write_shift(4, sst.Count);
8276 o.write_shift(4, sst.Unique);
8277 return o;
8278}
8279
8280var write_BrtSSTItem = write_RichStr;
8281
8282function write_sst_bin(sst) {
8283 var ba = buf_array();
8284 write_record(ba, "BrtBeginSst", write_BrtBeginSst(sst));
8285 for(var i = 0; i < sst.length; ++i) write_record(ba, "BrtSSTItem", write_BrtSSTItem(sst[i]));
8286 /* FRTSST */
8287 write_record(ba, "BrtEndSst");
8288 return ba.end();
8289}
8290function _JS2ANSI(str) {
8291 if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str);
8292 var o = [], oo = str.split("");
8293 for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0);
8294 return o;
8295}
8296
8297/* [MS-OFFCRYPTO] 2.1.4 Version */
8298function parse_CRYPTOVersion(blob, length) {
8299 var o = {};
8300 o.Major = blob.read_shift(2);
8301 o.Minor = blob.read_shift(2);
8302if(length >= 4) blob.l += length - 4;
8303 return o;
8304}
8305
8306/* [MS-OFFCRYPTO] 2.1.5 DataSpaceVersionInfo */
8307function parse_DataSpaceVersionInfo(blob) {
8308 var o = {};
8309 o.id = blob.read_shift(0, 'lpp4');
8310 o.R = parse_CRYPTOVersion(blob, 4);
8311 o.U = parse_CRYPTOVersion(blob, 4);
8312 o.W = parse_CRYPTOVersion(blob, 4);
8313 return o;
8314}
8315
8316/* [MS-OFFCRYPTO] 2.1.6.1 DataSpaceMapEntry Structure */
8317function parse_DataSpaceMapEntry(blob) {
8318 var len = blob.read_shift(4);
8319 var end = blob.l + len - 4;
8320 var o = {};
8321 var cnt = blob.read_shift(4);
8322 var comps = [];
8323 /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */
8324 while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') });
8325 o.name = blob.read_shift(0, 'lpp4');
8326 o.comps = comps;
8327 if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end);
8328 return o;
8329}
8330
8331/* [MS-OFFCRYPTO] 2.1.6 DataSpaceMap */
8332function parse_DataSpaceMap(blob) {
8333 var o = [];
8334 blob.l += 4; // must be 0x8
8335 var cnt = blob.read_shift(4);
8336 while(cnt-- > 0) o.push(parse_DataSpaceMapEntry(blob));
8337 return o;
8338}
8339
8340/* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */
8341function parse_DataSpaceDefinition(blob) {
8342 var o = [];
8343 blob.l += 4; // must be 0x8
8344 var cnt = blob.read_shift(4);
8345 while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4'));
8346 return o;
8347}
8348
8349/* [MS-OFFCRYPTO] 2.1.8 DataSpaceDefinition */
8350function parse_TransformInfoHeader(blob) {
8351 var o = {};
8352 /*var len = */blob.read_shift(4);
8353 blob.l += 4; // must be 0x1
8354 o.id = blob.read_shift(0, 'lpp4');
8355 o.name = blob.read_shift(0, 'lpp4');
8356 o.R = parse_CRYPTOVersion(blob, 4);
8357 o.U = parse_CRYPTOVersion(blob, 4);
8358 o.W = parse_CRYPTOVersion(blob, 4);
8359 return o;
8360}
8361
8362function parse_Primary(blob) {
8363 /* [MS-OFFCRYPTO] 2.2.6 IRMDSTransformInfo */
8364 var hdr = parse_TransformInfoHeader(blob);
8365 /* [MS-OFFCRYPTO] 2.1.9 EncryptionTransformInfo */
8366 hdr.ename = blob.read_shift(0, '8lpp4');
8367 hdr.blksz = blob.read_shift(4);
8368 hdr.cmode = blob.read_shift(4);
8369 if(blob.read_shift(4) != 0x04) throw new Error("Bad !Primary record");
8370 return hdr;
8371}
8372
8373/* [MS-OFFCRYPTO] 2.3.2 Encryption Header */
8374function parse_EncryptionHeader(blob, length) {
8375 var tgt = blob.l + length;
8376 var o = {};
8377 o.Flags = (blob.read_shift(4) & 0x3F);
8378 blob.l += 4;
8379 o.AlgID = blob.read_shift(4);
8380 var valid = false;
8381 switch(o.AlgID) {
8382 case 0x660E: case 0x660F: case 0x6610: valid = (o.Flags == 0x24); break;
8383 case 0x6801: valid = (o.Flags == 0x04); break;
8384 case 0: valid = (o.Flags == 0x10 || o.Flags == 0x04 || o.Flags == 0x24); break;
8385 default: throw 'Unrecognized encryption algorithm: ' + o.AlgID;
8386 }
8387 if(!valid) throw new Error("Encryption Flags/AlgID mismatch");
8388 o.AlgIDHash = blob.read_shift(4);
8389 o.KeySize = blob.read_shift(4);
8390 o.ProviderType = blob.read_shift(4);
8391 blob.l += 8;
8392 o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
8393 blob.l = tgt;
8394 return o;
8395}
8396
8397/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
8398function parse_EncryptionVerifier(blob, length) {
8399 var o = {}, tgt = blob.l + length;
8400 blob.l += 4; // SaltSize must be 0x10
8401 o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
8402 o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
8403 /*var sz = */blob.read_shift(4);
8404 o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
8405 return o;
8406}
8407
8408/* [MS-OFFCRYPTO] 2.3.4.* EncryptionInfo Stream */
8409function parse_EncryptionInfo(blob) {
8410 var vers = parse_CRYPTOVersion(blob);
8411 switch(vers.Minor) {
8412 case 0x02: return [vers.Minor, parse_EncInfoStd(blob, vers)];
8413 case 0x03: return [vers.Minor, parse_EncInfoExt(blob, vers)];
8414 case 0x04: return [vers.Minor, parse_EncInfoAgl(blob, vers)];
8415 }
8416 throw new Error("ECMA-376 Encrypted file unrecognized Version: " + vers.Minor);
8417}
8418
8419/* [MS-OFFCRYPTO] 2.3.4.5 EncryptionInfo Stream (Standard Encryption) */
8420function parse_EncInfoStd(blob) {
8421 var flags = blob.read_shift(4);
8422 if((flags & 0x3F) != 0x24) throw new Error("EncryptionInfo mismatch");
8423 var sz = blob.read_shift(4);
8424 //var tgt = blob.l + sz;
8425 var hdr = parse_EncryptionHeader(blob, sz);
8426 var verifier = parse_EncryptionVerifier(blob, blob.length - blob.l);
8427 return { t:"Std", h:hdr, v:verifier };
8428}
8429/* [MS-OFFCRYPTO] 2.3.4.6 EncryptionInfo Stream (Extensible Encryption) */
8430function parse_EncInfoExt() { throw new Error("File is password-protected: ECMA-376 Extensible"); }
8431/* [MS-OFFCRYPTO] 2.3.4.10 EncryptionInfo Stream (Agile Encryption) */
8432function parse_EncInfoAgl(blob) {
8433 var KeyData = ["saltSize","blockSize","keyBits","hashSize","cipherAlgorithm","cipherChaining","hashAlgorithm","saltValue"];
8434 blob.l+=4;
8435 var xml = blob.read_shift(blob.length - blob.l, 'utf8');
8436 var o = {};
8437 xml.replace(tagregex, function xml_agile(x) {
8438 var y = parsexmltag(x);
8439 switch(strip_ns(y[0])) {
8440 case '<?xml': break;
8441 case '<encryption': case '</encryption>': break;
8442 case '<keyData': KeyData.forEach(function(k) { o[k] = y[k]; }); break;
8443 case '<dataIntegrity': o.encryptedHmacKey = y.encryptedHmacKey; o.encryptedHmacValue = y.encryptedHmacValue; break;
8444 case '<keyEncryptors>': case '<keyEncryptors': o.encs = []; break;
8445 case '</keyEncryptors>': break;
8446
8447 case '<keyEncryptor': o.uri = y.uri; break;
8448 case '</keyEncryptor>': break;
8449 case '<encryptedKey': o.encs.push(y); break;
8450 default: throw y[0];
8451 }
8452 });
8453 return o;
8454}
8455
8456/* [MS-OFFCRYPTO] 2.3.5.1 RC4 CryptoAPI Encryption Header */
8457function parse_RC4CryptoHeader(blob, length) {
8458 var o = {};
8459 var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4); length -= 4;
8460 if(vers.Minor != 2) throw new Error('unrecognized minor version code: ' + vers.Minor);
8461 if(vers.Major > 4 || vers.Major < 2) throw new Error('unrecognized major version code: ' + vers.Major);
8462 o.Flags = blob.read_shift(4); length -= 4;
8463 var sz = blob.read_shift(4); length -= 4;
8464 o.EncryptionHeader = parse_EncryptionHeader(blob, sz); length -= sz;
8465 o.EncryptionVerifier = parse_EncryptionVerifier(blob, length);
8466 return o;
8467}
8468/* [MS-OFFCRYPTO] 2.3.6.1 RC4 Encryption Header */
8469function parse_RC4Header(blob) {
8470 var o = {};
8471 var vers = o.EncryptionVersionInfo = parse_CRYPTOVersion(blob, 4);
8472 if(vers.Major != 1 || vers.Minor != 1) throw 'unrecognized version code ' + vers.Major + ' : ' + vers.Minor;
8473 o.Salt = blob.read_shift(16);
8474 o.EncryptedVerifier = blob.read_shift(16);
8475 o.EncryptedVerifierHash = blob.read_shift(16);
8476 return o;
8477}
8478
8479/* [MS-OFFCRYPTO] 2.3.7.1 Binary Document Password Verifier Derivation */
8480function crypto_CreatePasswordVerifier_Method1(Password) {
8481 var Verifier = 0x0000, PasswordArray;
8482 var PasswordDecoded = _JS2ANSI(Password);
8483 var len = PasswordDecoded.length + 1, i, PasswordByte;
8484 var Intermediate1, Intermediate2, Intermediate3;
8485 PasswordArray = new_raw_buf(len);
8486 PasswordArray[0] = PasswordDecoded.length;
8487 for(i = 1; i != len; ++i) PasswordArray[i] = PasswordDecoded[i-1];
8488 for(i = len-1; i >= 0; --i) {
8489 PasswordByte = PasswordArray[i];
8490 Intermediate1 = ((Verifier & 0x4000) === 0x0000) ? 0 : 1;
8491 Intermediate2 = (Verifier << 1) & 0x7FFF;
8492 Intermediate3 = Intermediate1 | Intermediate2;
8493 Verifier = Intermediate3 ^ PasswordByte;
8494 }
8495 return Verifier ^ 0xCE4B;
8496}
8497
8498/* [MS-OFFCRYPTO] 2.3.7.2 Binary Document XOR Array Initialization */
8499var crypto_CreateXorArray_Method1 = (function() {
8500 var PadArray = [0xBB, 0xFF, 0xFF, 0xBA, 0xFF, 0xFF, 0xB9, 0x80, 0x00, 0xBE, 0x0F, 0x00, 0xBF, 0x0F, 0x00];
8501 var InitialCode = [0xE1F0, 0x1D0F, 0xCC9C, 0x84C0, 0x110C, 0x0E10, 0xF1CE, 0x313E, 0x1872, 0xE139, 0xD40F, 0x84F9, 0x280C, 0xA96A, 0x4EC3];
8502 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];
8503 var Ror = function(Byte) { return ((Byte/2) | (Byte*128)) & 0xFF; };
8504 var XorRor = function(byte1, byte2) { return Ror(byte1 ^ byte2); };
8505 var CreateXorKey_Method1 = function(Password) {
8506 var XorKey = InitialCode[Password.length - 1];
8507 var CurrentElement = 0x68;
8508 for(var i = Password.length-1; i >= 0; --i) {
8509 var Char = Password[i];
8510 for(var j = 0; j != 7; ++j) {
8511 if(Char & 0x40) XorKey ^= XorMatrix[CurrentElement];
8512 Char *= 2; --CurrentElement;
8513 }
8514 }
8515 return XorKey;
8516 };
8517 return function(password) {
8518 var Password = _JS2ANSI(password);
8519 var XorKey = CreateXorKey_Method1(Password);
8520 var Index = Password.length;
8521 var ObfuscationArray = new_raw_buf(16);
8522 for(var i = 0; i != 16; ++i) ObfuscationArray[i] = 0x00;
8523 var Temp, PasswordLastChar, PadIndex;
8524 if((Index & 1) === 1) {
8525 Temp = XorKey >> 8;
8526 ObfuscationArray[Index] = XorRor(PadArray[0], Temp);
8527 --Index;
8528 Temp = XorKey & 0xFF;
8529 PasswordLastChar = Password[Password.length - 1];
8530 ObfuscationArray[Index] = XorRor(PasswordLastChar, Temp);
8531 }
8532 while(Index > 0) {
8533 --Index;
8534 Temp = XorKey >> 8;
8535 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8536 --Index;
8537 Temp = XorKey & 0xFF;
8538 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8539 }
8540 Index = 15;
8541 PadIndex = 15 - Password.length;
8542 while(PadIndex > 0) {
8543 Temp = XorKey >> 8;
8544 ObfuscationArray[Index] = XorRor(PadArray[PadIndex], Temp);
8545 --Index;
8546 --PadIndex;
8547 Temp = XorKey & 0xFF;
8548 ObfuscationArray[Index] = XorRor(Password[Index], Temp);
8549 --Index;
8550 --PadIndex;
8551 }
8552 return ObfuscationArray;
8553 };
8554})();
8555
8556/* [MS-OFFCRYPTO] 2.3.7.3 Binary Document XOR Data Transformation Method 1 */
8557var crypto_DecryptData_Method1 = function(password, Data, XorArrayIndex, XorArray, O) {
8558 /* If XorArray is set, use it; if O is not set, make changes in-place */
8559 if(!O) O = Data;
8560 if(!XorArray) XorArray = crypto_CreateXorArray_Method1(password);
8561 var Index, Value;
8562 for(Index = 0; Index != Data.length; ++Index) {
8563 Value = Data[Index];
8564 Value ^= XorArray[XorArrayIndex];
8565 Value = ((Value>>5) | (Value<<3)) & 0xFF;
8566 O[Index] = Value;
8567 ++XorArrayIndex;
8568 }
8569 return [O, XorArrayIndex, XorArray];
8570};
8571
8572var crypto_MakeXorDecryptor = function(password) {
8573 var XorArrayIndex = 0, XorArray = crypto_CreateXorArray_Method1(password);
8574 return function(Data) {
8575 var O = crypto_DecryptData_Method1("", Data, XorArrayIndex, XorArray);
8576 XorArrayIndex = O[1];
8577 return O[0];
8578 };
8579};
8580
8581/* 2.5.343 */
8582function parse_XORObfuscation(blob, length, opts, out) {
8583 var o = ({ key: parseuint16(blob), verificationBytes: parseuint16(blob) });
8584 if(opts.password) o.verifier = crypto_CreatePasswordVerifier_Method1(opts.password);
8585 out.valid = o.verificationBytes === o.verifier;
8586 if(out.valid) out.insitu = crypto_MakeXorDecryptor(opts.password);
8587 return o;
8588}
8589
8590/* 2.4.117 */
8591function parse_FilePassHeader(blob, length, oo) {
8592 var o = oo || {}; o.Info = blob.read_shift(2); blob.l -= 2;
8593 if(o.Info === 1) o.Data = parse_RC4Header(blob, length);
8594 else o.Data = parse_RC4CryptoHeader(blob, length);
8595 return o;
8596}
8597function parse_FilePass(blob, length, opts) {
8598 var o = ({ Type: opts.biff >= 8 ? blob.read_shift(2) : 0 }); /* wEncryptionType */
8599 if(o.Type) parse_FilePassHeader(blob, length-2, o);
8600 else parse_XORObfuscation(blob, opts.biff >= 8 ? length : length - 2, opts, o);
8601 return o;
8602}
8603
8604
8605var RTF = (function() {
8606 function rtf_to_sheet(d, opts) {
8607 switch(opts.type) {
8608 case 'base64': return rtf_to_sheet_str(Base64.decode(d), opts);
8609 case 'binary': return rtf_to_sheet_str(d, opts);
8610 case 'buffer': return rtf_to_sheet_str(d.toString('binary'), opts);
8611 case 'array': return rtf_to_sheet_str(cc2str(d), opts);
8612 }
8613 throw new Error("Unrecognized type " + opts.type);
8614 }
8615
8616 function rtf_to_sheet_str(str, opts) {
8617 var o = opts || {};
8618 var ws = o.dense ? ([]) : ({});
8619 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
8620
8621 // TODO: parse
8622 if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
8623
8624 ws['!ref'] = encode_range(range);
8625 return ws;
8626 }
8627
8628 function rtf_to_workbook(d, opts) { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
8629
8630 /* TODO: this is a stub */
8631 function sheet_to_rtf(ws) {
8632 var o = ["{\\rtf1\\ansi"];
8633 var r = safe_decode_range(ws['!ref']), cell;
8634 var dense = Array.isArray(ws);
8635 for(var R = r.s.r; R <= r.e.r; ++R) {
8636 o.push("\\trowd\\trautofit1");
8637 for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
8638 o.push("\\pard\\intbl");
8639 for(C = r.s.c; C <= r.e.c; ++C) {
8640 var coord = encode_cell({r:R,c:C});
8641 cell = dense ? (ws[R]||[])[C]: ws[coord];
8642 if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
8643 o.push(" " + (cell.w || (format_cell(cell), cell.w)));
8644 o.push("\\cell");
8645 }
8646 o.push("\\pard\\intbl\\row");
8647 }
8648 return o.join("") + "}";
8649 }
8650
8651 return {
8652 to_workbook: rtf_to_workbook,
8653 to_sheet: rtf_to_sheet,
8654 from_sheet: sheet_to_rtf
8655 };
8656})();
8657function hex2RGB(h) {
8658 var o = h.slice(h[0]==="#"?1:0).slice(0,6);
8659 return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
8660}
8661function rgb2Hex(rgb) {
8662 for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
8663 return o.toString(16).toUpperCase().slice(1);
8664}
8665
8666function rgb2HSL(rgb) {
8667 var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
8668 var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
8669 if(C === 0) return [0, 0, R];
8670
8671 var H6 = 0, S = 0, L2 = (M + m);
8672 S = C / (L2 > 1 ? 2 - L2 : L2);
8673 switch(M){
8674 case R: H6 = ((G - B) / C + 6)%6; break;
8675 case G: H6 = ((B - R) / C + 2); break;
8676 case B: H6 = ((R - G) / C + 4); break;
8677 }
8678 return [H6 / 6, S, L2 / 2];
8679}
8680
8681function hsl2RGB(hsl){
8682 var H = hsl[0], S = hsl[1], L = hsl[2];
8683 var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
8684 var rgb = [m,m,m], h6 = 6*H;
8685
8686 var X;
8687 if(S !== 0) switch(h6|0) {
8688 case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
8689 case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
8690 case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
8691 case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
8692 case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
8693 case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
8694 }
8695 for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
8696 return rgb;
8697}
8698
8699/* 18.8.3 bgColor tint algorithm */
8700function rgb_tint(hex, tint) {
8701 if(tint === 0) return hex;
8702 var hsl = rgb2HSL(hex2RGB(hex));
8703 if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
8704 else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
8705 return rgb2Hex(hsl2RGB(hsl));
8706}
8707
8708/* 18.3.1.13 width calculations */
8709/* [MS-OI29500] 2.1.595 Column Width & Formatting */
8710var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
8711function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
8712function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
8713function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
8714//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
8715//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
8716function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
8717/* XLSX/XLSB/XLS specify width in units of MDW */
8718function find_mdw_colw(collw) {
8719 var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
8720 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; }
8721 MDW = _MDW;
8722}
8723/* XLML specifies width in terms of pixels */
8724/*function find_mdw_wpx(wpx) {
8725 var delta = Infinity, guess = 0, _MDW = MIN_MDW;
8726 for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
8727 guess = char2width_(px2char_(wpx))*256;
8728 guess = (guess) % 1;
8729 if(guess > 0.5) guess--;
8730 if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
8731 }
8732 MDW = _MDW;
8733}*/
8734
8735function process_col(coll) {
8736 if(coll.width) {
8737 coll.wpx = width2px(coll.width);
8738 coll.wch = px2char(coll.wpx);
8739 coll.MDW = MDW;
8740 } else if(coll.wpx) {
8741 coll.wch = px2char(coll.wpx);
8742 coll.width = char2width(coll.wch);
8743 coll.MDW = MDW;
8744 } else if(typeof coll.wch == 'number') {
8745 coll.width = char2width(coll.wch);
8746 coll.wpx = width2px(coll.width);
8747 coll.MDW = MDW;
8748 }
8749 if(coll.customWidth) delete coll.customWidth;
8750}
8751
8752var DEF_PPI = 96, PPI = DEF_PPI;
8753function px2pt(px) { return px * 96 / PPI; }
8754function pt2px(pt) { return pt * PPI / 96; }
8755
8756/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
8757var XLMLPatternTypeMap = {
8758 "None": "none",
8759 "Solid": "solid",
8760 "Gray50": "mediumGray",
8761 "Gray75": "darkGray",
8762 "Gray25": "lightGray",
8763 "HorzStripe": "darkHorizontal",
8764 "VertStripe": "darkVertical",
8765 "ReverseDiagStripe": "darkDown",
8766 "DiagStripe": "darkUp",
8767 "DiagCross": "darkGrid",
8768 "ThickDiagCross": "darkTrellis",
8769 "ThinHorzStripe": "lightHorizontal",
8770 "ThinVertStripe": "lightVertical",
8771 "ThinReverseDiagStripe": "lightDown",
8772 "ThinHorzCross": "lightGrid"
8773};
8774
8775/* 18.8.5 borders CT_Borders */
8776function parse_borders(t, styles, themes, opts) {
8777 styles.Borders = [];
8778 var border = {};
8779 var pass = false;
8780 (t[0].match(tagregex)||[]).forEach(function(x) {
8781 var y = parsexmltag(x);
8782 switch(strip_ns(y[0])) {
8783 case '<borders': case '<borders>': case '</borders>': break;
8784
8785 /* 18.8.4 border CT_Border */
8786 case '<border': case '<border>': case '<border/>':
8787 border = {};
8788 if(y.diagonalUp) border.diagonalUp = parsexmlbool(y.diagonalUp);
8789 if(y.diagonalDown) border.diagonalDown = parsexmlbool(y.diagonalDown);
8790 styles.Borders.push(border);
8791 break;
8792 case '</border>': break;
8793
8794 /* note: not in spec, appears to be CT_BorderPr */
8795 case '<left/>': break;
8796 case '<left': case '<left>': break;
8797 case '</left>': break;
8798
8799 /* note: not in spec, appears to be CT_BorderPr */
8800 case '<right/>': break;
8801 case '<right': case '<right>': break;
8802 case '</right>': break;
8803
8804 /* 18.8.43 top CT_BorderPr */
8805 case '<top/>': break;
8806 case '<top': case '<top>': break;
8807 case '</top>': break;
8808
8809 /* 18.8.6 bottom CT_BorderPr */
8810 case '<bottom/>': break;
8811 case '<bottom': case '<bottom>': break;
8812 case '</bottom>': break;
8813
8814 /* 18.8.13 diagonal CT_BorderPr */
8815 case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
8816 case '</diagonal>': break;
8817
8818 /* 18.8.25 horizontal CT_BorderPr */
8819 case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
8820 case '</horizontal>': break;
8821
8822 /* 18.8.44 vertical CT_BorderPr */
8823 case '<vertical': case '<vertical>': case '<vertical/>': break;
8824 case '</vertical>': break;
8825
8826 /* 18.8.37 start CT_BorderPr */
8827 case '<start': case '<start>': case '<start/>': break;
8828 case '</start>': break;
8829
8830 /* 18.8.16 end CT_BorderPr */
8831 case '<end': case '<end>': case '<end/>': break;
8832 case '</end>': break;
8833
8834 /* 18.8.? color CT_Color */
8835 case '<color': case '<color>':
8836 break;
8837 case '<color/>': case '</color>': break;
8838
8839 /* 18.2.10 extLst CT_ExtensionList ? */
8840 case '<extLst': case '<extLst>': case '</extLst>': break;
8841 case '<ext': pass = true; break;
8842 case '</ext>': pass = false; break;
8843 default: if(opts && opts.WTF) {
8844 if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
8845 }
8846 }
8847 });
8848}
8849
8850/* 18.8.21 fills CT_Fills */
8851function parse_fills(t, styles, themes, opts) {
8852 styles.Fills = [];
8853 var fill = {};
8854 var pass = false;
8855 (t[0].match(tagregex)||[]).forEach(function(x) {
8856 var y = parsexmltag(x);
8857 switch(strip_ns(y[0])) {
8858 case '<fills': case '<fills>': case '</fills>': break;
8859
8860 /* 18.8.20 fill CT_Fill */
8861 case '<fill>': case '<fill': case '<fill/>':
8862 fill = {}; styles.Fills.push(fill); break;
8863 case '</fill>': break;
8864
8865 /* 18.8.24 gradientFill CT_GradientFill */
8866 case '<gradientFill>': break;
8867 case '<gradientFill':
8868 case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
8869
8870 /* 18.8.32 patternFill CT_PatternFill */
8871 case '<patternFill': case '<patternFill>':
8872 if(y.patternType) fill.patternType = y.patternType;
8873 break;
8874 case '<patternFill/>': case '</patternFill>': break;
8875
8876 /* 18.8.3 bgColor CT_Color */
8877 case '<bgColor':
8878 if(!fill.bgColor) fill.bgColor = {};
8879 if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
8880 if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
8881 if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
8882 /* Excel uses ARGB strings */
8883 if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
8884 break;
8885 case '<bgColor/>': case '</bgColor>': break;
8886
8887 /* 18.8.19 fgColor CT_Color */
8888 case '<fgColor':
8889 if(!fill.fgColor) fill.fgColor = {};
8890 if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
8891 if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
8892 /* Excel uses ARGB strings */
8893 if(y.rgb != null) fill.fgColor.rgb = y.rgb.slice(-6);
8894 break;
8895 case '<fgColor/>': case '</fgColor>': break;
8896
8897 /* 18.8.38 stop CT_GradientStop */
8898 case '<stop': case '<stop/>': break;
8899 case '</stop>': break;
8900
8901 /* 18.8.? color CT_Color */
8902 case '<color': case '<color/>': break;
8903 case '</color>': break;
8904
8905 /* 18.2.10 extLst CT_ExtensionList ? */
8906 case '<extLst': case '<extLst>': case '</extLst>': break;
8907 case '<ext': pass = true; break;
8908 case '</ext>': pass = false; break;
8909 default: if(opts && opts.WTF) {
8910 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
8911 }
8912 }
8913 });
8914}
8915
8916/* 18.8.23 fonts CT_Fonts */
8917function parse_fonts(t, styles, themes, opts) {
8918 styles.Fonts = [];
8919 var font = {};
8920 var pass = false;
8921 (t[0].match(tagregex)||[]).forEach(function(x) {
8922 var y = parsexmltag(x);
8923 switch(strip_ns(y[0])) {
8924 case '<fonts': case '<fonts>': case '</fonts>': break;
8925
8926 /* 18.8.22 font CT_Font */
8927 case '<font': case '<font>': break;
8928 case '</font>': case '<font/>':
8929 styles.Fonts.push(font);
8930 font = {};
8931 break;
8932
8933 /* 18.8.29 name CT_FontName */
8934 case '<name': if(y.val) font.name = utf8read(y.val); break;
8935 case '<name/>': case '</name>': break;
8936
8937 /* 18.8.2 b CT_BooleanProperty */
8938 case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
8939 case '<b/>': font.bold = 1; break;
8940
8941 /* 18.8.26 i CT_BooleanProperty */
8942 case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
8943 case '<i/>': font.italic = 1; break;
8944
8945 /* 18.4.13 u CT_UnderlineProperty */
8946 case '<u':
8947 switch(y.val) {
8948 case "none": font.underline = 0x00; break;
8949 case "single": font.underline = 0x01; break;
8950 case "double": font.underline = 0x02; break;
8951 case "singleAccounting": font.underline = 0x21; break;
8952 case "doubleAccounting": font.underline = 0x22; break;
8953 } break;
8954 case '<u/>': font.underline = 1; break;
8955
8956 /* 18.4.10 strike CT_BooleanProperty */
8957 case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
8958 case '<strike/>': font.strike = 1; break;
8959
8960 /* 18.4.2 outline CT_BooleanProperty */
8961 case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
8962 case '<outline/>': font.outline = 1; break;
8963
8964 /* 18.8.36 shadow CT_BooleanProperty */
8965 case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
8966 case '<shadow/>': font.shadow = 1; break;
8967
8968 /* 18.8.12 condense CT_BooleanProperty */
8969 case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
8970 case '<condense/>': font.condense = 1; break;
8971
8972 /* 18.8.17 extend CT_BooleanProperty */
8973 case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
8974 case '<extend/>': font.extend = 1; break;
8975
8976 /* 18.4.11 sz CT_FontSize */
8977 case '<sz': if(y.val) font.sz = +y.val; break;
8978 case '<sz/>': case '</sz>': break;
8979
8980 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
8981 case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
8982 case '<vertAlign/>': case '</vertAlign>': break;
8983
8984 /* 18.8.18 family CT_FontFamily */
8985 case '<family': if(y.val) font.family = parseInt(y.val,10); break;
8986 case '<family/>': case '</family>': break;
8987
8988 /* 18.8.35 scheme CT_FontScheme */
8989 case '<scheme': if(y.val) font.scheme = y.val; break;
8990 case '<scheme/>': case '</scheme>': break;
8991
8992 /* 18.4.1 charset CT_IntProperty */
8993 case '<charset':
8994 if(y.val == '1') break;
8995 y.codepage = CS2CP[parseInt(y.val, 10)];
8996 break;
8997
8998 /* 18.?.? color CT_Color */
8999 case '<color':
9000 if(!font.color) font.color = {};
9001 if(y.auto) font.color.auto = parsexmlbool(y.auto);
9002
9003 if(y.rgb) font.color.rgb = y.rgb.slice(-6);
9004 else if(y.indexed) {
9005 font.color.index = parseInt(y.indexed, 10);
9006 var icv = XLSIcv[font.color.index];
9007 if(font.color.index == 81) icv = XLSIcv[1];
9008 if(!icv) throw new Error(x);
9009 font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
9010 } else if(y.theme) {
9011 font.color.theme = parseInt(y.theme, 10);
9012 if(y.tint) font.color.tint = parseFloat(y.tint);
9013 if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
9014 font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
9015 }
9016 }
9017
9018 break;
9019 case '<color/>': case '</color>': break;
9020
9021 /* note: sometimes mc:AlternateContent appears bare */
9022 case '<AlternateContent': pass = true; break;
9023 case '</AlternateContent>': pass = false; break;
9024
9025 /* 18.2.10 extLst CT_ExtensionList ? */
9026 case '<extLst': case '<extLst>': case '</extLst>': break;
9027 case '<ext': pass = true; break;
9028 case '</ext>': pass = false; break;
9029 default: if(opts && opts.WTF) {
9030 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
9031 }
9032 }
9033 });
9034}
9035
9036/* 18.8.31 numFmts CT_NumFmts */
9037function parse_numFmts(t, styles, opts) {
9038 styles.NumberFmt = [];
9039 var k/*Array<number>*/ = (keys(SSF._table));
9040 for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
9041 var m = t[0].match(tagregex);
9042 if(!m) return;
9043 for(i=0; i < m.length; ++i) {
9044 var y = parsexmltag(m[i]);
9045 switch(strip_ns(y[0])) {
9046 case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
9047 case '<numFmt': {
9048 var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
9049 styles.NumberFmt[j] = f;
9050 if(j>0) {
9051 if(j > 0x188) {
9052 for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
9053 styles.NumberFmt[j] = f;
9054 }
9055 SSF.load(f,j);
9056 }
9057 } break;
9058 case '</numFmt>': break;
9059 default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
9060 }
9061 }
9062}
9063
9064function write_numFmts(NF) {
9065 var o = ["<numFmts>"];
9066 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9067 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])}));
9068 });
9069 if(o.length === 1) return "";
9070 o[o.length] = ("</numFmts>");
9071 o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
9072 return o.join("");
9073}
9074
9075/* 18.8.10 cellXfs CT_CellXfs */
9076var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
9077var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
9078function parse_cellXfs(t, styles, opts) {
9079 styles.CellXf = [];
9080 var xf;
9081 var pass = false;
9082 (t[0].match(tagregex)||[]).forEach(function(x) {
9083 var y = parsexmltag(x), i = 0;
9084 switch(strip_ns(y[0])) {
9085 case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
9086
9087 /* 18.8.45 xf CT_Xf */
9088 case '<xf': case '<xf/>':
9089 xf = y;
9090 delete xf[0];
9091 for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
9092 xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
9093 for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
9094 xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
9095 if(xf.numFmtId > 0x188) {
9096 for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
9097 }
9098 styles.CellXf.push(xf); break;
9099 case '</xf>': break;
9100
9101 /* 18.8.1 alignment CT_CellAlignment */
9102 case '<alignment': case '<alignment/>':
9103 var alignment = {};
9104 if(y.vertical) alignment.vertical = y.vertical;
9105 if(y.horizontal) alignment.horizontal = y.horizontal;
9106 if(y.textRotation != null) alignment.textRotation = y.textRotation;
9107 if(y.indent) alignment.indent = y.indent;
9108 if(y.wrapText) alignment.wrapText = parsexmlbool(y.wrapText);
9109 xf.alignment = alignment;
9110 break;
9111 case '</alignment>': break;
9112
9113 /* 18.8.33 protection CT_CellProtection */
9114 case '<protection':
9115 break;
9116 case '</protection>': case '<protection/>': break;
9117
9118 /* note: sometimes mc:AlternateContent appears bare */
9119 case '<AlternateContent': pass = true; break;
9120 case '</AlternateContent>': pass = false; break;
9121
9122 /* 18.2.10 extLst CT_ExtensionList ? */
9123 case '<extLst': case '<extLst>': case '</extLst>': break;
9124 case '<ext': pass = true; break;
9125 case '</ext>': pass = false; break;
9126 default: if(opts && opts.WTF) {
9127 if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
9128 }
9129 }
9130 });
9131}
9132
9133function write_cellXfs(cellXfs) {
9134 var o = [];
9135 o[o.length] = (writextag('cellXfs',null));
9136 cellXfs.forEach(function(c) {
9137 o[o.length] = (writextag('xf', null, c));
9138 });
9139 o[o.length] = ("</cellXfs>");
9140 if(o.length === 2) return "";
9141 o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
9142 return o.join("");
9143}
9144
9145/* 18.8 Styles CT_Stylesheet*/
9146var parse_sty_xml= (function make_pstyx() {
9147var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
9148var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
9149var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
9150var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
9151var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
9152
9153return function parse_sty_xml(data, themes, opts) {
9154 var styles = {};
9155 if(!data) return styles;
9156 data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
9157 /* 18.8.39 styleSheet CT_Stylesheet */
9158 var t;
9159
9160 /* 18.8.31 numFmts CT_NumFmts ? */
9161 if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
9162
9163 /* 18.8.23 fonts CT_Fonts ? */
9164 if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
9165
9166 /* 18.8.21 fills CT_Fills ? */
9167 if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
9168
9169 /* 18.8.5 borders CT_Borders ? */
9170 if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
9171
9172 /* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
9173 /* 18.8.8 cellStyles CT_CellStyles ? */
9174
9175 /* 18.8.10 cellXfs CT_CellXfs ? */
9176 if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
9177
9178 /* 18.8.15 dxfs CT_Dxfs ? */
9179 /* 18.8.42 tableStyles CT_TableStyles ? */
9180 /* 18.8.11 colors CT_Colors ? */
9181 /* 18.2.10 extLst CT_ExtensionList ? */
9182
9183 return styles;
9184};
9185})();
9186
9187var STYLES_XML_ROOT = writextag('styleSheet', null, {
9188 'xmlns': XMLNS.main[0],
9189 'xmlns:vt': XMLNS.vt
9190});
9191
9192RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
9193
9194function write_sty_xml(wb, opts) {
9195 var o = [XML_HEADER, STYLES_XML_ROOT], w;
9196 if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
9197 o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
9198 o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
9199 o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
9200 o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
9201 if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
9202 o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
9203 o[o.length] = ('<dxfs count="0"/>');
9204 o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
9205
9206 if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
9207 return o.join("");
9208}
9209/* [MS-XLSB] 2.4.657 BrtFmt */
9210function parse_BrtFmt(data, length) {
9211 var numFmtId = data.read_shift(2);
9212 var stFmtCode = parse_XLWideString(data,length-2);
9213 return [numFmtId, stFmtCode];
9214}
9215function write_BrtFmt(i, f, o) {
9216 if(!o) o = new_buf(6 + 4 * f.length);
9217 o.write_shift(2, i);
9218 write_XLWideString(f, o);
9219 var out = (o.length > o.l) ? o.slice(0, o.l) : o;
9220 if(o.l == null) o.l = o.length;
9221 return out;
9222}
9223
9224/* [MS-XLSB] 2.4.659 BrtFont TODO */
9225function parse_BrtFont(data, length, opts) {
9226 var out = ({});
9227
9228 out.sz = data.read_shift(2) / 20;
9229
9230 var grbit = parse_FontFlags(data, 2, opts);
9231 if(grbit.fItalic) out.italic = 1;
9232 if(grbit.fCondense) out.condense = 1;
9233 if(grbit.fExtend) out.extend = 1;
9234 if(grbit.fShadow) out.shadow = 1;
9235 if(grbit.fOutline) out.outline = 1;
9236 if(grbit.fStrikeout) out.strike = 1;
9237
9238 var bls = data.read_shift(2);
9239 if(bls === 0x02BC) out.bold = 1;
9240
9241 switch(data.read_shift(2)) {
9242 /* case 0: out.vertAlign = "baseline"; break; */
9243 case 1: out.vertAlign = "superscript"; break;
9244 case 2: out.vertAlign = "subscript"; break;
9245 }
9246
9247 var underline = data.read_shift(1);
9248 if(underline != 0) out.underline = underline;
9249
9250 var family = data.read_shift(1);
9251 if(family > 0) out.family = family;
9252
9253 var bCharSet = data.read_shift(1);
9254 if(bCharSet > 0) out.charset = bCharSet;
9255
9256 data.l++;
9257 out.color = parse_BrtColor(data, 8);
9258
9259 switch(data.read_shift(1)) {
9260 /* case 0: out.scheme = "none": break; */
9261 case 1: out.scheme = "major"; break;
9262 case 2: out.scheme = "minor"; break;
9263 }
9264
9265 out.name = parse_XLWideString(data, length - 21);
9266
9267 return out;
9268}
9269function write_BrtFont(font, o) {
9270 if(!o) o = new_buf(25+4*32);
9271 o.write_shift(2, font.sz * 20);
9272 write_FontFlags(font, o);
9273 o.write_shift(2, font.bold ? 0x02BC : 0x0190);
9274 var sss = 0;
9275 if(font.vertAlign == "superscript") sss = 1;
9276 else if(font.vertAlign == "subscript") sss = 2;
9277 o.write_shift(2, sss);
9278 o.write_shift(1, font.underline || 0);
9279 o.write_shift(1, font.family || 0);
9280 o.write_shift(1, font.charset || 0);
9281 o.write_shift(1, 0);
9282 write_BrtColor(font.color, o);
9283 var scheme = 0;
9284 if(font.scheme == "major") scheme = 1;
9285 if(font.scheme == "minor") scheme = 2;
9286 o.write_shift(1, scheme);
9287 write_XLWideString(font.name, o);
9288 return o.length > o.l ? o.slice(0, o.l) : o;
9289}
9290
9291/* [MS-XLSB] 2.4.650 BrtFill */
9292var XLSBFillPTNames = [
9293 "none",
9294 "solid",
9295 "mediumGray",
9296 "darkGray",
9297 "lightGray",
9298 "darkHorizontal",
9299 "darkVertical",
9300 "darkDown",
9301 "darkUp",
9302 "darkGrid",
9303 "darkTrellis",
9304 "lightHorizontal",
9305 "lightVertical",
9306 "lightDown",
9307 "lightUp",
9308 "lightGrid",
9309 "lightTrellis",
9310 "gray125",
9311 "gray0625"
9312];
9313var rev_XLSBFillPTNames = (evert(XLSBFillPTNames));
9314/* TODO: gradient fill representation */
9315var parse_BrtFill = parsenoop;
9316function write_BrtFill(fill, o) {
9317 if(!o) o = new_buf(4*3 + 8*7 + 16*1);
9318 var fls = rev_XLSBFillPTNames[fill.patternType];
9319 if(fls == null) fls = 0x28;
9320 o.write_shift(4, fls);
9321 var j = 0;
9322 if(fls != 0x28) {
9323 /* TODO: custom FG Color */
9324 write_BrtColor({auto:1}, o);
9325 /* TODO: custom BG Color */
9326 write_BrtColor({auto:1}, o);
9327
9328 for(; j < 12; ++j) o.write_shift(4, 0);
9329 } else {
9330 for(; j < 4; ++j) o.write_shift(4, 0);
9331
9332 for(; j < 12; ++j) o.write_shift(4, 0); /* TODO */
9333 /* iGradientType */
9334 /* xnumDegree */
9335 /* xnumFillToLeft */
9336 /* xnumFillToRight */
9337 /* xnumFillToTop */
9338 /* xnumFillToBottom */
9339 /* cNumStop */
9340 /* xfillGradientStop */
9341 }
9342 return o.length > o.l ? o.slice(0, o.l) : o;
9343}
9344
9345/* [MS-XLSB] 2.4.824 BrtXF */
9346function parse_BrtXF(data, length) {
9347 var tgt = data.l + length;
9348 var ixfeParent = data.read_shift(2);
9349 var ifmt = data.read_shift(2);
9350 data.l = tgt;
9351 return {ixfe:ixfeParent, numFmtId:ifmt };
9352}
9353function write_BrtXF(data, ixfeP, o) {
9354 if(!o) o = new_buf(16);
9355 o.write_shift(2, ixfeP||0);
9356 o.write_shift(2, data.numFmtId||0);
9357 o.write_shift(2, 0); /* iFont */
9358 o.write_shift(2, 0); /* iFill */
9359 o.write_shift(2, 0); /* ixBorder */
9360 o.write_shift(1, 0); /* trot */
9361 o.write_shift(1, 0); /* indent */
9362 var flow = 0;
9363 o.write_shift(1, flow); /* flags */
9364 o.write_shift(1, 0); /* flags */
9365 o.write_shift(1, 0); /* xfGrbitAtr */
9366 o.write_shift(1, 0);
9367 return o;
9368}
9369
9370/* [MS-XLSB] 2.5.4 Blxf TODO */
9371function write_Blxf(data, o) {
9372 if(!o) o = new_buf(10);
9373 o.write_shift(1, 0); /* dg */
9374 o.write_shift(1, 0);
9375 o.write_shift(4, 0); /* color */
9376 o.write_shift(4, 0); /* color */
9377 return o;
9378}
9379/* [MS-XLSB] 2.4.302 BrtBorder TODO */
9380var parse_BrtBorder = parsenoop;
9381function write_BrtBorder(border, o) {
9382 if(!o) o = new_buf(51);
9383 o.write_shift(1, 0); /* diagonal */
9384 write_Blxf(null, o); /* top */
9385 write_Blxf(null, o); /* bottom */
9386 write_Blxf(null, o); /* left */
9387 write_Blxf(null, o); /* right */
9388 write_Blxf(null, o); /* diag */
9389 return o.length > o.l ? o.slice(0, o.l) : o;
9390}
9391
9392/* [MS-XLSB] 2.4.763 BrtStyle TODO */
9393function write_BrtStyle(style, o) {
9394 if(!o) o = new_buf(12+4*10);
9395 o.write_shift(4, style.xfId);
9396 o.write_shift(2, 1);
9397 o.write_shift(1, +style.builtinId);
9398 o.write_shift(1, 0); /* iLevel */
9399 write_XLNullableWideString(style.name || "", o);
9400 return o.length > o.l ? o.slice(0, o.l) : o;
9401}
9402
9403/* [MS-XLSB] 2.4.272 BrtBeginTableStyles */
9404function write_BrtBeginTableStyles(cnt, defTableStyle, defPivotStyle) {
9405 var o = new_buf(4+256*2*4);
9406 o.write_shift(4, cnt);
9407 write_XLNullableWideString(defTableStyle, o);
9408 write_XLNullableWideString(defPivotStyle, o);
9409 return o.length > o.l ? o.slice(0, o.l) : o;
9410}
9411
9412/* [MS-XLSB] 2.1.7.50 Styles */
9413function parse_sty_bin(data, themes, opts) {
9414 var styles = {};
9415 styles.NumberFmt = ([]);
9416 for(var y in SSF._table) styles.NumberFmt[y] = SSF._table[y];
9417
9418 styles.CellXf = [];
9419 styles.Fonts = [];
9420 var state = [];
9421 var pass = false;
9422 recordhopper(data, function hopper_sty(val, R_n, RT) {
9423 switch(RT) {
9424 case 0x002C: /* 'BrtFmt' */
9425 styles.NumberFmt[val[0]] = val[1]; SSF.load(val[1], val[0]);
9426 break;
9427 case 0x002B: /* 'BrtFont' */
9428 styles.Fonts.push(val);
9429 if(val.color.theme != null && themes && themes.themeElements && themes.themeElements.clrScheme) {
9430 val.color.rgb = rgb_tint(themes.themeElements.clrScheme[val.color.theme].rgb, val.color.tint || 0);
9431 }
9432 break;
9433 case 0x0401: /* 'BrtKnownFonts' */ break;
9434 case 0x002D: /* 'BrtFill' */
9435 break;
9436 case 0x002E: /* 'BrtBorder' */
9437 break;
9438 case 0x002F: /* 'BrtXF' */
9439 if(state[state.length - 1] == "BrtBeginCellXFs") {
9440 styles.CellXf.push(val);
9441 }
9442 break;
9443 case 0x0030: /* 'BrtStyle' */
9444 case 0x01FB: /* 'BrtDXF' */
9445 case 0x023C: /* 'BrtMRUColor' */
9446 case 0x01DB: /* 'BrtIndexedColor': */
9447 break;
9448
9449 case 0x0493: /* 'BrtDXF14' */
9450 case 0x0836: /* 'BrtDXF15' */
9451 case 0x046A: /* 'BrtSlicerStyleElement' */
9452 case 0x0200: /* 'BrtTableStyleElement' */
9453 case 0x082F: /* 'BrtTimelineStyleElement' */
9454 case 0x0C00: /* 'BrtUid' */
9455 break;
9456
9457 case 0x0023: /* 'BrtFRTBegin' */
9458 pass = true; break;
9459 case 0x0024: /* 'BrtFRTEnd' */
9460 pass = false; break;
9461 case 0x0025: /* 'BrtACBegin' */
9462 state.push(R_n); pass = true; break;
9463 case 0x0026: /* 'BrtACEnd' */
9464 state.pop(); pass = false; break;
9465
9466 default:
9467 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
9468 else if((R_n||"").indexOf("End") > 0) state.pop();
9469 else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
9470 }
9471 });
9472 return styles;
9473}
9474
9475function write_FMTS_bin(ba, NF) {
9476 if(!NF) return;
9477 var cnt = 0;
9478 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9479for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) ++cnt;
9480 });
9481
9482 if(cnt == 0) return;
9483 write_record(ba, "BrtBeginFmts", write_UInt32LE(cnt));
9484 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
9485for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_record(ba, "BrtFmt", write_BrtFmt(i, NF[i]));
9486 });
9487 write_record(ba, "BrtEndFmts");
9488}
9489
9490function write_FONTS_bin(ba) {
9491 var cnt = 1;
9492
9493 if(cnt == 0) return;
9494 write_record(ba, "BrtBeginFonts", write_UInt32LE(cnt));
9495 write_record(ba, "BrtFont", write_BrtFont({
9496 sz:12,
9497 color: {theme:1},
9498 name: "Calibri",
9499 family: 2,
9500 scheme: "minor"
9501 }));
9502 /* 1*65491BrtFont [ACFONTS] */
9503 write_record(ba, "BrtEndFonts");
9504}
9505
9506function write_FILLS_bin(ba) {
9507 var cnt = 2;
9508
9509 if(cnt == 0) return;
9510 write_record(ba, "BrtBeginFills", write_UInt32LE(cnt));
9511 write_record(ba, "BrtFill", write_BrtFill({patternType:"none"}));
9512 write_record(ba, "BrtFill", write_BrtFill({patternType:"gray125"}));
9513 /* 1*65431BrtFill */
9514 write_record(ba, "BrtEndFills");
9515}
9516
9517function write_BORDERS_bin(ba) {
9518 var cnt = 1;
9519
9520 if(cnt == 0) return;
9521 write_record(ba, "BrtBeginBorders", write_UInt32LE(cnt));
9522 write_record(ba, "BrtBorder", write_BrtBorder({}));
9523 /* 1*65430BrtBorder */
9524 write_record(ba, "BrtEndBorders");
9525}
9526
9527function write_CELLSTYLEXFS_bin(ba) {
9528 var cnt = 1;
9529 write_record(ba, "BrtBeginCellStyleXFs", write_UInt32LE(cnt));
9530 write_record(ba, "BrtXF", write_BrtXF({
9531 numFmtId: 0,
9532 fontId: 0,
9533 fillId: 0,
9534 borderId: 0
9535 }, 0xFFFF));
9536 /* 1*65430(BrtXF *FRT) */
9537 write_record(ba, "BrtEndCellStyleXFs");
9538}
9539
9540function write_CELLXFS_bin(ba, data) {
9541 write_record(ba, "BrtBeginCellXFs", write_UInt32LE(data.length));
9542 data.forEach(function(c) { write_record(ba, "BrtXF", write_BrtXF(c,0)); });
9543 /* 1*65430(BrtXF *FRT) */
9544 write_record(ba, "BrtEndCellXFs");
9545}
9546
9547function write_STYLES_bin(ba) {
9548 var cnt = 1;
9549
9550 write_record(ba, "BrtBeginStyles", write_UInt32LE(cnt));
9551 write_record(ba, "BrtStyle", write_BrtStyle({
9552 xfId:0,
9553 builtinId:0,
9554 name:"Normal"
9555 }));
9556 /* 1*65430(BrtStyle *FRT) */
9557 write_record(ba, "BrtEndStyles");
9558}
9559
9560function write_DXFS_bin(ba) {
9561 var cnt = 0;
9562
9563 write_record(ba, "BrtBeginDXFs", write_UInt32LE(cnt));
9564 /* *2147483647(BrtDXF *FRT) */
9565 write_record(ba, "BrtEndDXFs");
9566}
9567
9568function write_TABLESTYLES_bin(ba) {
9569 var cnt = 0;
9570
9571 write_record(ba, "BrtBeginTableStyles", write_BrtBeginTableStyles(cnt, "TableStyleMedium9", "PivotStyleMedium4"));
9572 /* *TABLESTYLE */
9573 write_record(ba, "BrtEndTableStyles");
9574}
9575
9576function write_COLORPALETTE_bin() {
9577 return;
9578 /* BrtBeginColorPalette [INDEXEDCOLORS] [MRUCOLORS] BrtEndColorPalette */
9579}
9580
9581/* [MS-XLSB] 2.1.7.50 Styles */
9582function write_sty_bin(wb, opts) {
9583 var ba = buf_array();
9584 write_record(ba, "BrtBeginStyleSheet");
9585 write_FMTS_bin(ba, wb.SSF);
9586 write_FONTS_bin(ba, wb);
9587 write_FILLS_bin(ba, wb);
9588 write_BORDERS_bin(ba, wb);
9589 write_CELLSTYLEXFS_bin(ba, wb);
9590 write_CELLXFS_bin(ba, opts.cellXfs);
9591 write_STYLES_bin(ba, wb);
9592 write_DXFS_bin(ba, wb);
9593 write_TABLESTYLES_bin(ba, wb);
9594 write_COLORPALETTE_bin(ba, wb);
9595 /* FRTSTYLESHEET*/
9596 write_record(ba, "BrtEndStyleSheet");
9597 return ba.end();
9598}
9599RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
9600
9601/* Even though theme layout is dk1 lt1 dk2 lt2, true order is lt1 dk1 lt2 dk2 */
9602var XLSXThemeClrScheme = [
9603 '</a:lt1>', '</a:dk1>', '</a:lt2>', '</a:dk2>',
9604 '</a:accent1>', '</a:accent2>', '</a:accent3>',
9605 '</a:accent4>', '</a:accent5>', '</a:accent6>',
9606 '</a:hlink>', '</a:folHlink>'
9607];
9608/* 20.1.6.2 clrScheme CT_ColorScheme */
9609function parse_clrScheme(t, themes, opts) {
9610 themes.themeElements.clrScheme = [];
9611 var color = {};
9612 (t[0].match(tagregex)||[]).forEach(function(x) {
9613 var y = parsexmltag(x);
9614 switch(y[0]) {
9615 /* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
9616 case '<a:clrScheme': case '</a:clrScheme>': break;
9617
9618 /* 20.1.2.3.32 srgbClr CT_SRgbColor */
9619 case '<a:srgbClr':
9620 color.rgb = y.val; break;
9621
9622 /* 20.1.2.3.33 sysClr CT_SystemColor */
9623 case '<a:sysClr':
9624 color.rgb = y.lastClr; break;
9625
9626 /* 20.1.4.1.1 accent1 (Accent 1) */
9627 /* 20.1.4.1.2 accent2 (Accent 2) */
9628 /* 20.1.4.1.3 accent3 (Accent 3) */
9629 /* 20.1.4.1.4 accent4 (Accent 4) */
9630 /* 20.1.4.1.5 accent5 (Accent 5) */
9631 /* 20.1.4.1.6 accent6 (Accent 6) */
9632 /* 20.1.4.1.9 dk1 (Dark 1) */
9633 /* 20.1.4.1.10 dk2 (Dark 2) */
9634 /* 20.1.4.1.15 folHlink (Followed Hyperlink) */
9635 /* 20.1.4.1.19 hlink (Hyperlink) */
9636 /* 20.1.4.1.22 lt1 (Light 1) */
9637 /* 20.1.4.1.23 lt2 (Light 2) */
9638 case '<a:dk1>': case '</a:dk1>':
9639 case '<a:lt1>': case '</a:lt1>':
9640 case '<a:dk2>': case '</a:dk2>':
9641 case '<a:lt2>': case '</a:lt2>':
9642 case '<a:accent1>': case '</a:accent1>':
9643 case '<a:accent2>': case '</a:accent2>':
9644 case '<a:accent3>': case '</a:accent3>':
9645 case '<a:accent4>': case '</a:accent4>':
9646 case '<a:accent5>': case '</a:accent5>':
9647 case '<a:accent6>': case '</a:accent6>':
9648 case '<a:hlink>': case '</a:hlink>':
9649 case '<a:folHlink>': case '</a:folHlink>':
9650 if (y[0].charAt(1) === '/') {
9651 themes.themeElements.clrScheme[XLSXThemeClrScheme.indexOf(y[0])] = color;
9652 color = {};
9653 } else {
9654 color.name = y[0].slice(3, y[0].length - 1);
9655 }
9656 break;
9657
9658 default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
9659 }
9660 });
9661}
9662
9663/* 20.1.4.1.18 fontScheme CT_FontScheme */
9664function parse_fontScheme() { }
9665
9666/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
9667function parse_fmtScheme() { }
9668
9669var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
9670var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
9671var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
9672
9673/* 20.1.6.10 themeElements CT_BaseStyles */
9674function parse_themeElements(data, themes, opts) {
9675 themes.themeElements = {};
9676
9677 var t;
9678
9679 [
9680 /* clrScheme CT_ColorScheme */
9681 ['clrScheme', clrsregex, parse_clrScheme],
9682 /* fontScheme CT_FontScheme */
9683 ['fontScheme', fntsregex, parse_fontScheme],
9684 /* fmtScheme CT_StyleMatrix */
9685 ['fmtScheme', fmtsregex, parse_fmtScheme]
9686 ].forEach(function(m) {
9687 if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
9688 m[2](t, themes, opts);
9689 });
9690}
9691
9692var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
9693
9694/* 14.2.7 Theme Part */
9695function parse_theme_xml(data, opts) {
9696 /* 20.1.6.9 theme CT_OfficeStyleSheet */
9697 if(!data || data.length === 0) return parse_theme_xml(write_theme());
9698
9699 var t;
9700 var themes = {};
9701
9702 /* themeElements CT_BaseStyles */
9703 if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
9704 parse_themeElements(t[0], themes, opts);
9705 themes.raw = data;
9706 return themes;
9707}
9708
9709function write_theme(Themes, opts) {
9710 if(opts && opts.themeXLSX) return opts.themeXLSX;
9711 if(Themes && typeof Themes.raw == "string") return Themes.raw;
9712 var o = [XML_HEADER];
9713 o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
9714 o[o.length] = '<a:themeElements>';
9715
9716 o[o.length] = '<a:clrScheme name="Office">';
9717 o[o.length] = '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
9718 o[o.length] = '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
9719 o[o.length] = '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
9720 o[o.length] = '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
9721 o[o.length] = '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
9722 o[o.length] = '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
9723 o[o.length] = '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
9724 o[o.length] = '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
9725 o[o.length] = '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
9726 o[o.length] = '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
9727 o[o.length] = '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
9728 o[o.length] = '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
9729 o[o.length] = '</a:clrScheme>';
9730
9731 o[o.length] = '<a:fontScheme name="Office">';
9732 o[o.length] = '<a:majorFont>';
9733 o[o.length] = '<a:latin typeface="Cambria"/>';
9734 o[o.length] = '<a:ea typeface=""/>';
9735 o[o.length] = '<a:cs typeface=""/>';
9736 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
9737 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
9738 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
9739 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
9740 o[o.length] = '<a:font script="Arab" typeface="Times New Roman"/>';
9741 o[o.length] = '<a:font script="Hebr" typeface="Times New Roman"/>';
9742 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
9743 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
9744 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
9745 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
9746 o[o.length] = '<a:font script="Khmr" typeface="MoolBoran"/>';
9747 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
9748 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
9749 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
9750 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
9751 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
9752 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
9753 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
9754 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
9755 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
9756 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
9757 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
9758 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
9759 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
9760 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
9761 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
9762 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
9763 o[o.length] = '<a:font script="Viet" typeface="Times New Roman"/>';
9764 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
9765 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
9766 o[o.length] = '</a:majorFont>';
9767 o[o.length] = '<a:minorFont>';
9768 o[o.length] = '<a:latin typeface="Calibri"/>';
9769 o[o.length] = '<a:ea typeface=""/>';
9770 o[o.length] = '<a:cs typeface=""/>';
9771 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
9772 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
9773 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
9774 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
9775 o[o.length] = '<a:font script="Arab" typeface="Arial"/>';
9776 o[o.length] = '<a:font script="Hebr" typeface="Arial"/>';
9777 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
9778 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
9779 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
9780 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
9781 o[o.length] = '<a:font script="Khmr" typeface="DaunPenh"/>';
9782 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
9783 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
9784 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
9785 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
9786 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
9787 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
9788 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
9789 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
9790 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
9791 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
9792 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
9793 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
9794 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
9795 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
9796 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
9797 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
9798 o[o.length] = '<a:font script="Viet" typeface="Arial"/>';
9799 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
9800 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
9801 o[o.length] = '</a:minorFont>';
9802 o[o.length] = '</a:fontScheme>';
9803
9804 o[o.length] = '<a:fmtScheme name="Office">';
9805 o[o.length] = '<a:fillStyleLst>';
9806 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9807 o[o.length] = '<a:gradFill rotWithShape="1">';
9808 o[o.length] = '<a:gsLst>';
9809 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9810 o[o.length] = '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9811 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9812 o[o.length] = '</a:gsLst>';
9813 o[o.length] = '<a:lin ang="16200000" scaled="1"/>';
9814 o[o.length] = '</a:gradFill>';
9815 o[o.length] = '<a:gradFill rotWithShape="1">';
9816 o[o.length] = '<a:gsLst>';
9817 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>';
9818 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>';
9819 o[o.length] = '</a:gsLst>';
9820 o[o.length] = '<a:lin ang="16200000" scaled="0"/>';
9821 o[o.length] = '</a:gradFill>';
9822 o[o.length] = '</a:fillStyleLst>';
9823 o[o.length] = '<a:lnStyleLst>';
9824 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>';
9825 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>';
9826 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>';
9827 o[o.length] = '</a:lnStyleLst>';
9828 o[o.length] = '<a:effectStyleLst>';
9829 o[o.length] = '<a:effectStyle>';
9830 o[o.length] = '<a:effectLst>';
9831 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>';
9832 o[o.length] = '</a:effectLst>';
9833 o[o.length] = '</a:effectStyle>';
9834 o[o.length] = '<a:effectStyle>';
9835 o[o.length] = '<a:effectLst>';
9836 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>';
9837 o[o.length] = '</a:effectLst>';
9838 o[o.length] = '</a:effectStyle>';
9839 o[o.length] = '<a:effectStyle>';
9840 o[o.length] = '<a:effectLst>';
9841 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>';
9842 o[o.length] = '</a:effectLst>';
9843 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>';
9844 o[o.length] = '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
9845 o[o.length] = '</a:effectStyle>';
9846 o[o.length] = '</a:effectStyleLst>';
9847 o[o.length] = '<a:bgFillStyleLst>';
9848 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
9849 o[o.length] = '<a:gradFill rotWithShape="1">';
9850 o[o.length] = '<a:gsLst>';
9851 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
9852 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>';
9853 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
9854 o[o.length] = '</a:gsLst>';
9855 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
9856 o[o.length] = '</a:gradFill>';
9857 o[o.length] = '<a:gradFill rotWithShape="1">';
9858 o[o.length] = '<a:gsLst>';
9859 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
9860 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
9861 o[o.length] = '</a:gsLst>';
9862 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
9863 o[o.length] = '</a:gradFill>';
9864 o[o.length] = '</a:bgFillStyleLst>';
9865 o[o.length] = '</a:fmtScheme>';
9866 o[o.length] = '</a:themeElements>';
9867
9868 o[o.length] = '<a:objectDefaults>';
9869 o[o.length] = '<a:spDef>';
9870 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>';
9871 o[o.length] = '</a:spDef>';
9872 o[o.length] = '<a:lnDef>';
9873 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>';
9874 o[o.length] = '</a:lnDef>';
9875 o[o.length] = '</a:objectDefaults>';
9876 o[o.length] = '<a:extraClrSchemeLst/>';
9877 o[o.length] = '</a:theme>';
9878 return o.join("");
9879}
9880/* [MS-XLS] 2.4.326 TODO: payload is a zip file */
9881function parse_Theme(blob, length, opts) {
9882 var end = blob.l + length;
9883 var dwThemeVersion = blob.read_shift(4);
9884 if(dwThemeVersion === 124226) return;
9885 if(!opts.cellStyles || !jszip) { blob.l = end; return; }
9886 var data = blob.slice(blob.l);
9887 blob.l = end;
9888 var zip; try { zip = new jszip(data); } catch(e) { return; }
9889 var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true);
9890 if(!themeXML) return;
9891 return parse_theme_xml(themeXML, opts);
9892}
9893
9894/* 2.5.49 */
9895function parse_ColorTheme(blob) { return blob.read_shift(4); }
9896
9897/* 2.5.155 */
9898function parse_FullColorExt(blob) {
9899 var o = {};
9900 o.xclrType = blob.read_shift(2);
9901 o.nTintShade = blob.read_shift(2);
9902 switch(o.xclrType) {
9903 case 0: blob.l += 4; break;
9904 case 1: o.xclrValue = parse_IcvXF(blob, 4); break;
9905 case 2: o.xclrValue = parse_LongRGBA(blob, 4); break;
9906 case 3: o.xclrValue = parse_ColorTheme(blob, 4); break;
9907 case 4: blob.l += 4; break;
9908 }
9909 blob.l += 8;
9910 return o;
9911}
9912
9913/* 2.5.164 TODO: read 7 bits*/
9914function parse_IcvXF(blob, length) {
9915 return parsenoop(blob, length);
9916}
9917
9918/* 2.5.280 */
9919function parse_XFExtGradient(blob, length) {
9920 return parsenoop(blob, length);
9921}
9922
9923/* [MS-XLS] 2.5.108 */
9924function parse_ExtProp(blob) {
9925 var extType = blob.read_shift(2);
9926 var cb = blob.read_shift(2) - 4;
9927 var o = [extType];
9928 switch(extType) {
9929 case 0x04: case 0x05: case 0x07: case 0x08:
9930 case 0x09: case 0x0A: case 0x0B: case 0x0D:
9931 o[1] = parse_FullColorExt(blob, cb); break;
9932 case 0x06: o[1] = parse_XFExtGradient(blob, cb); break;
9933 case 0x0E: case 0x0F: o[1] = blob.read_shift(cb === 1 ? 1 : 2); break;
9934 default: throw new Error("Unrecognized ExtProp type: " + extType + " " + cb);
9935 }
9936 return o;
9937}
9938
9939/* 2.4.355 */
9940function parse_XFExt(blob, length) {
9941 var end = blob.l + length;
9942 blob.l += 2;
9943 var ixfe = blob.read_shift(2);
9944 blob.l += 2;
9945 var cexts = blob.read_shift(2);
9946 var ext = [];
9947 while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l));
9948 return {ixfe:ixfe, ext:ext};
9949}
9950
9951/* xf is an XF, see parse_XFExt for xfext */
9952function update_xfext(xf, xfext) {
9953 xfext.forEach(function(xfe) {
9954 switch(xfe[0]) { /* 2.5.108 extPropData */
9955 case 0x04: break; /* foreground color */
9956 case 0x05: break; /* background color */
9957 case 0x06: break; /* gradient fill */
9958 case 0x07: break; /* top cell border color */
9959 case 0x08: break; /* bottom cell border color */
9960 case 0x09: break; /* left cell border color */
9961 case 0x0a: break; /* right cell border color */
9962 case 0x0b: break; /* diagonal cell border color */
9963 case 0x0d: /* text color */
9964 break;
9965 case 0x0e: break; /* font scheme */
9966 case 0x0f: break; /* indentation level */
9967 }
9968 });
9969}
9970
9971/* 18.6 Calculation Chain */
9972function parse_cc_xml(data) {
9973 var d = [];
9974 if(!data) return d;
9975 var i = 1;
9976 (data.match(tagregex)||[]).forEach(function(x) {
9977 var y = parsexmltag(x);
9978 switch(y[0]) {
9979 case '<?xml': break;
9980 /* 18.6.2 calcChain CT_CalcChain 1 */
9981 case '<calcChain': case '<calcChain>': case '</calcChain>': break;
9982 /* 18.6.1 c CT_CalcCell 1 */
9983 case '<c': delete y[0]; if(y.i) i = y.i; else y.i = i; d.push(y); break;
9984 }
9985 });
9986 return d;
9987}
9988
9989//function write_cc_xml(data, opts) { }
9990
9991/* [MS-XLSB] 2.6.4.1 */
9992function parse_BrtCalcChainItem$(data) {
9993 var out = {};
9994 out.i = data.read_shift(4);
9995 var cell = {};
9996 cell.r = data.read_shift(4);
9997 cell.c = data.read_shift(4);
9998 out.r = encode_cell(cell);
9999 var flags = data.read_shift(1);
10000 if(flags & 0x2) out.l = '1';
10001 if(flags & 0x8) out.a = '1';
10002 return out;
10003}
10004
10005/* 18.6 Calculation Chain */
10006function parse_cc_bin(data, name, opts) {
10007 var out = [];
10008 var pass = false;
10009 recordhopper(data, function hopper_cc(val, R_n, RT) {
10010 switch(RT) {
10011 case 0x003F: /* 'BrtCalcChainItem$' */
10012 out.push(val); break;
10013
10014 default:
10015 if((R_n||"").indexOf("Begin") > 0){/* empty */}
10016 else if((R_n||"").indexOf("End") > 0){/* empty */}
10017 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
10018 }
10019 });
10020 return out;
10021}
10022
10023//function write_cc_bin(data, opts) { }
10024/* 18.14 Supplementary Workbook Data */
10025function parse_xlink_xml() {
10026 //var opts = _opts || {};
10027 //if(opts.WTF) throw "XLSX External Link";
10028}
10029
10030/* [MS-XLSB] 2.1.7.25 External Link */
10031function parse_xlink_bin(data, rel, name, _opts) {
10032 if(!data) return data;
10033 var opts = _opts || {};
10034
10035 var pass = false, end = false;
10036
10037 recordhopper(data, function xlink_parse(val, R_n, RT) {
10038 if(end) return;
10039 switch(RT) {
10040 case 0x0167: /* 'BrtSupTabs' */
10041 case 0x016B: /* 'BrtExternTableStart' */
10042 case 0x016C: /* 'BrtExternTableEnd' */
10043 case 0x016E: /* 'BrtExternRowHdr' */
10044 case 0x016F: /* 'BrtExternCellBlank' */
10045 case 0x0170: /* 'BrtExternCellReal' */
10046 case 0x0171: /* 'BrtExternCellBool' */
10047 case 0x0172: /* 'BrtExternCellError' */
10048 case 0x0173: /* 'BrtExternCellString' */
10049 case 0x01D8: /* 'BrtExternValueMeta' */
10050 case 0x0241: /* 'BrtSupNameStart' */
10051 case 0x0242: /* 'BrtSupNameValueStart' */
10052 case 0x0243: /* 'BrtSupNameValueEnd' */
10053 case 0x0244: /* 'BrtSupNameNum' */
10054 case 0x0245: /* 'BrtSupNameErr' */
10055 case 0x0246: /* 'BrtSupNameSt' */
10056 case 0x0247: /* 'BrtSupNameNil' */
10057 case 0x0248: /* 'BrtSupNameBool' */
10058 case 0x0249: /* 'BrtSupNameFmla' */
10059 case 0x024A: /* 'BrtSupNameBits' */
10060 case 0x024B: /* 'BrtSupNameEnd' */
10061 break;
10062
10063 case 0x0023: /* 'BrtFRTBegin' */
10064 pass = true; break;
10065 case 0x0024: /* 'BrtFRTEnd' */
10066 pass = false; break;
10067
10068 default:
10069 if((R_n||"").indexOf("Begin") > 0){/* empty */}
10070 else if((R_n||"").indexOf("End") > 0){/* empty */}
10071 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
10072 }
10073 }, opts);
10074}
10075/* 20.5 DrawingML - SpreadsheetML Drawing */
10076RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
10077RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
10078
10079/* 20.5.2.35 wsDr CT_Drawing */
10080function parse_drawing(data, rels) {
10081 if(!data) return "??";
10082 /*
10083 Chartsheet Drawing:
10084 - 20.5.2.35 wsDr CT_Drawing
10085 - 20.5.2.1 absoluteAnchor CT_AbsoluteAnchor
10086 - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
10087 - 20.1.2.2.16 graphic CT_GraphicalObject
10088 - 20.1.2.2.17 graphicData CT_GraphicalObjectData
10089 - chart reference
10090 the actual type is based on the URI of the graphicData
10091 TODO: handle embedded charts and other types of graphics
10092 */
10093 var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
10094
10095 return rels['!id'][id].Target;
10096}
10097
10098/* L.5.5.2 SpreadsheetML Comments + VML Schema */
10099var _shapeid = 1024;
10100function write_comments_vml(rId, comments) {
10101 var csize = [21600, 21600];
10102 /* L.5.2.1.2 Path Attribute */
10103 var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
10104 var o = [
10105 writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
10106 writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
10107 writextag("v:shapetype", [
10108 writextag("v:stroke", null, {joinstyle:"miter"}),
10109 writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
10110 ].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
10111 ];
10112 while(_shapeid < rId * 1000) _shapeid += 1000;
10113
10114 comments.forEach(function(x) {
10115 var c = decode_cell(x[0]);
10116 var fillopts = {'color2':"#BEFF82", 'type':"gradient"};
10117 if(fillopts.type == "gradient") fillopts.angle = "-180";
10118 var fillparm = fillopts.type == "gradient" ? writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}) : null;
10119 var fillxml = writextag('v:fill', fillparm, fillopts);
10120
10121 var shadata = ({on:"t", 'obscured':"t"});
10122 ++_shapeid;
10123
10124 o = o.concat([
10125 '<v:shape' + wxt_helper({
10126 id:'_x0000_s' + _shapeid,
10127 type:"#_x0000_t202",
10128 style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
10129 fillcolor:"#ECFAD4",
10130 strokecolor:"#edeaa1"
10131 }) + '>',
10132 fillxml,
10133 writextag("v:shadow", null, shadata),
10134 writextag("v:path", null, {'o:connecttype':"none"}),
10135 '<v:textbox><div style="text-align:left"></div></v:textbox>',
10136 '<x:ClientData ObjectType="Note">',
10137 '<x:MoveWithCells/>',
10138 '<x:SizeWithCells/>',
10139 /* Part 4 19.4.2.3 Anchor (Anchor) */
10140 writetag('x:Anchor', [c.c+1, 0, c.r+1, 0, c.c+3, 20, c.r+5, 20].join(",")),
10141 writetag('x:AutoFill', "False"),
10142 writetag('x:Row', String(c.r)),
10143 writetag('x:Column', String(c.c)),
10144 x[1].hidden ? '' : '<x:Visible/>',
10145 '</x:ClientData>',
10146 '</v:shape>'
10147 ]); });
10148 o.push('</xml>');
10149 return o.join("");
10150}
10151RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
10152
10153function sheet_insert_comments(sheet, comments) {
10154 var dense = Array.isArray(sheet);
10155 var cell;
10156 comments.forEach(function(comment) {
10157 var r = decode_cell(comment.ref);
10158 if(dense) {
10159 if(!sheet[r.r]) sheet[r.r] = [];
10160 cell = sheet[r.r][r.c];
10161 } else cell = sheet[comment.ref];
10162 if (!cell) {
10163 cell = ({t:"z"});
10164 if(dense) sheet[r.r][r.c] = cell;
10165 else sheet[comment.ref] = cell;
10166 var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
10167 if(range.s.r > r.r) range.s.r = r.r;
10168 if(range.e.r < r.r) range.e.r = r.r;
10169 if(range.s.c > r.c) range.s.c = r.c;
10170 if(range.e.c < r.c) range.e.c = r.c;
10171 var encoded = encode_range(range);
10172 if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
10173 }
10174
10175 if (!cell.c) cell.c = [];
10176 var o = ({a: comment.author, t: comment.t, r: comment.r});
10177 if(comment.h) o.h = comment.h;
10178 cell.c.push(o);
10179 });
10180}
10181
10182/* 18.7 Comments */
10183function parse_comments_xml(data, opts) {
10184 /* 18.7.6 CT_Comments */
10185 if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
10186 var authors = [];
10187 var commentList = [];
10188 var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
10189 if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
10190 if(x === "" || x.trim() === "") return;
10191 var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
10192 if(a) authors.push(a[1]);
10193 });
10194 var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
10195 if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
10196 if(x === "" || x.trim() === "") return;
10197 var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
10198 if(!cm) return;
10199 var y = parsexmltag(cm[0]);
10200 var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
10201 var cell = decode_cell(y.ref);
10202 if(opts.sheetRows && opts.sheetRows <= cell.r) return;
10203 var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
10204 var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
10205 comment.r = rt.r;
10206 if(rt.r == "<t></t>") rt.t = rt.h = "";
10207 comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
10208 if(opts.cellHTML) comment.h = rt.h;
10209 commentList.push(comment);
10210 });
10211 return commentList;
10212}
10213
10214var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
10215function write_comments_xml(data) {
10216 var o = [XML_HEADER, CMNT_XML_ROOT];
10217
10218 var iauthor = [];
10219 o.push("<authors>");
10220 data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
10221 if(iauthor.indexOf(a) > -1) return;
10222 iauthor.push(a);
10223 o.push("<author>" + a + "</author>");
10224 }); });
10225 o.push("</authors>");
10226 o.push("<commentList>");
10227 data.forEach(function(d) {
10228 d[1].forEach(function(c) {
10229 /* 18.7.3 CT_Comment */
10230 o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
10231 o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
10232 o.push('</text></comment>');
10233 });
10234 });
10235 o.push("</commentList>");
10236 if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
10237 return o.join("");
10238}
10239/* [MS-XLSB] 2.4.28 BrtBeginComment */
10240function parse_BrtBeginComment(data) {
10241 var out = {};
10242 out.iauthor = data.read_shift(4);
10243 var rfx = parse_UncheckedRfX(data, 16);
10244 out.rfx = rfx.s;
10245 out.ref = encode_cell(rfx.s);
10246 data.l += 16; /*var guid = parse_GUID(data); */
10247 return out;
10248}
10249function write_BrtBeginComment(data, o) {
10250 if(o == null) o = new_buf(36);
10251 o.write_shift(4, data[1].iauthor);
10252 write_UncheckedRfX((data[0]), o);
10253 o.write_shift(4, 0);
10254 o.write_shift(4, 0);
10255 o.write_shift(4, 0);
10256 o.write_shift(4, 0);
10257 return o;
10258}
10259
10260/* [MS-XLSB] 2.4.327 BrtCommentAuthor */
10261var parse_BrtCommentAuthor = parse_XLWideString;
10262function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
10263
10264/* [MS-XLSB] 2.1.7.8 Comments */
10265function parse_comments_bin(data, opts) {
10266 var out = [];
10267 var authors = [];
10268 var c = {};
10269 var pass = false;
10270 recordhopper(data, function hopper_cmnt(val, R_n, RT) {
10271 switch(RT) {
10272 case 0x0278: /* 'BrtCommentAuthor' */
10273 authors.push(val); break;
10274 case 0x027B: /* 'BrtBeginComment' */
10275 c = val; break;
10276 case 0x027D: /* 'BrtCommentText' */
10277 c.t = val.t; c.h = val.h; c.r = val.r; break;
10278 case 0x027C: /* 'BrtEndComment' */
10279 c.author = authors[c.iauthor];
10280 delete (c).iauthor;
10281 if(opts.sheetRows && c.rfx && opts.sheetRows <= c.rfx.r) break;
10282 if(!c.t) c.t = "";
10283 delete c.rfx; out.push(c); break;
10284
10285 case 0x0C00: /* 'BrtUid' */
10286 break;
10287
10288 case 0x0023: /* 'BrtFRTBegin' */
10289 pass = true; break;
10290 case 0x0024: /* 'BrtFRTEnd' */
10291 pass = false; break;
10292 case 0x0025: /* 'BrtACBegin' */ break;
10293 case 0x0026: /* 'BrtACEnd' */ break;
10294
10295
10296 default:
10297 if((R_n||"").indexOf("Begin") > 0){/* empty */}
10298 else if((R_n||"").indexOf("End") > 0){/* empty */}
10299 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
10300 }
10301 });
10302 return out;
10303}
10304
10305function write_comments_bin(data) {
10306 var ba = buf_array();
10307 var iauthor = [];
10308 write_record(ba, "BrtBeginComments");
10309
10310 write_record(ba, "BrtBeginCommentAuthors");
10311 data.forEach(function(comment) {
10312 comment[1].forEach(function(c) {
10313 if(iauthor.indexOf(c.a) > -1) return;
10314 iauthor.push(c.a.slice(0,54));
10315 write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a));
10316 });
10317 });
10318 write_record(ba, "BrtEndCommentAuthors");
10319
10320 write_record(ba, "BrtBeginCommentList");
10321 data.forEach(function(comment) {
10322 comment[1].forEach(function(c) {
10323 c.iauthor = iauthor.indexOf(c.a);
10324 var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])};
10325 write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c]));
10326 if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c));
10327 write_record(ba, "BrtEndComment");
10328 delete c.iauthor;
10329 });
10330 });
10331 write_record(ba, "BrtEndCommentList");
10332
10333 write_record(ba, "BrtEndComments");
10334 return ba.end();
10335}
10336var CT_VBA = "application/vnd.ms-office.vbaProject";
10337function make_vba_xls(cfb) {
10338 var newcfb = CFB.utils.cfb_new({root:"R"});
10339 cfb.FullPaths.forEach(function(p, i) {
10340 if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
10341 var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
10342 CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
10343 });
10344 return CFB.write(newcfb);
10345}
10346
10347function fill_vba_xls(cfb, vba) {
10348 vba.FullPaths.forEach(function(p, i) {
10349 if(i == 0) return;
10350 var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
10351 if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
10352 });
10353}
10354
10355var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
10356
10357RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
10358RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
10359
10360/* macro and dialog sheet stubs */
10361function parse_ds_bin() { return {'!type':'dialog'}; }
10362function parse_ds_xml() { return {'!type':'dialog'}; }
10363function parse_ms_bin() { return {'!type':'macro'}; }
10364function parse_ms_xml() { return {'!type':'macro'}; }
10365/* TODO: it will be useful to parse the function str */
10366var rc_to_a1 = (function(){
10367 var rcregex = /(^|[^A-Za-z_])R(\[?-?\d+\]|[1-9]\d*|)C(\[?-?\d+\]|[1-9]\d*|)(?![A-Za-z0-9_])/g;
10368 var rcbase = ({r:0,c:0});
10369 function rcfunc($$,$1,$2,$3) {
10370 var cRel = false, rRel = false;
10371
10372 if($2.length == 0) rRel = true;
10373 else if($2.charAt(0) == "[") { rRel = true; $2 = $2.slice(1, -1); }
10374
10375 if($3.length == 0) cRel = true;
10376 else if($3.charAt(0) == "[") { cRel = true; $3 = $3.slice(1, -1); }
10377
10378 var R = $2.length>0?parseInt($2,10)|0:0, C = $3.length>0?parseInt($3,10)|0:0;
10379
10380 if(cRel) C += rcbase.c; else --C;
10381 if(rRel) R += rcbase.r; else --R;
10382 return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
10383 }
10384 return function rc_to_a1(fstr, base) {
10385 rcbase = base;
10386 return fstr.replace(rcregex, rcfunc);
10387 };
10388})();
10389
10390var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
10391var a1_to_rc =(function(){
10392 return function a1_to_rc(fstr, base) {
10393 return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
10394 var c = decode_col($3) - ($2 ? 0 : base.c);
10395 var r = decode_row($5) - ($4 ? 0 : base.r);
10396 var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
10397 var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
10398 return $1 + "R" + R + "C" + C;
10399 });
10400 };
10401})();
10402
10403/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
10404function shift_formula_str(f, delta) {
10405 return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
10406 return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
10407 });
10408}
10409
10410function shift_formula_xlsx(f, range, cell) {
10411 var r = decode_range(range), s = r.s, c = decode_cell(cell);
10412 var delta = {r:c.r - s.r, c:c.c - s.c};
10413 return shift_formula_str(f, delta);
10414}
10415
10416/* TODO: parse formula */
10417function fuzzyfmla(f) {
10418 if(f.length == 1) return false;
10419 return true;
10420}
10421
10422function _xlfn(f) {
10423 return f.replace(/_xlfn\./g,"");
10424}
10425function parseread1(blob) { blob.l+=1; return; }
10426
10427/* [MS-XLS] 2.5.51 */
10428function parse_ColRelU(blob, length) {
10429 var c = blob.read_shift(length == 1 ? 1 : 2);
10430 return [c & 0x3FFF, (c >> 14) & 1, (c >> 15) & 1];
10431}
10432
10433/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.89 */
10434function parse_RgceArea(blob, length, opts) {
10435 var w = 2;
10436 if(opts) {
10437 if(opts.biff >= 2 && opts.biff <= 5) return parse_RgceArea_BIFF2(blob, length, opts);
10438 else if(opts.biff == 12) w = 4;
10439 }
10440 var r=blob.read_shift(w), R=blob.read_shift(w);
10441 var c=parse_ColRelU(blob, 2);
10442 var C=parse_ColRelU(blob, 2);
10443 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]} };
10444}
10445/* BIFF 2-5 encodes flags in the row field */
10446function parse_RgceArea_BIFF2(blob) {
10447 var r=parse_ColRelU(blob, 2), R=parse_ColRelU(blob, 2);
10448 var c=blob.read_shift(1);
10449 var C=blob.read_shift(1);
10450 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]} };
10451}
10452
10453/* [MS-XLS] 2.5.198.105 ; [MS-XLSB] 2.5.97.90 */
10454function parse_RgceAreaRel(blob, length, opts) {
10455 if(opts.biff < 8) return parse_RgceArea_BIFF2(blob, length, opts);
10456 var r=blob.read_shift(opts.biff == 12 ? 4 : 2), R=blob.read_shift(opts.biff == 12 ? 4 : 2);
10457 var c=parse_ColRelU(blob, 2);
10458 var C=parse_ColRelU(blob, 2);
10459 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]} };
10460}
10461
10462/* [MS-XLS] 2.5.198.109 ; [MS-XLSB] 2.5.97.91 */
10463function parse_RgceLoc(blob, length, opts) {
10464 if(opts && opts.biff >= 2 && opts.biff <= 5) return parse_RgceLoc_BIFF2(blob, length, opts);
10465 var r = blob.read_shift(opts && opts.biff == 12 ? 4 : 2);
10466 var c = parse_ColRelU(blob, 2);
10467 return {r:r, c:c[0], cRel:c[1], rRel:c[2]};
10468}
10469function parse_RgceLoc_BIFF2(blob) {
10470 var r = parse_ColRelU(blob, 2);
10471 var c = blob.read_shift(1);
10472 return {r:r[0], c:c, cRel:r[1], rRel:r[2]};
10473}
10474
10475/* [MS-XLS] 2.5.198.107, 2.5.47 */
10476function parse_RgceElfLoc(blob) {
10477 var r = blob.read_shift(2);
10478 var c = blob.read_shift(2);
10479 return {r:r, c:c & 0xFF, fQuoted:!!(c & 0x4000), cRel:c>>15, rRel:c>>15 };
10480}
10481
10482/* [MS-XLS] 2.5.198.111 ; [MS-XLSB] 2.5.97.92 TODO */
10483function parse_RgceLocRel(blob, length, opts) {
10484 var biff = opts && opts.biff ? opts.biff : 8;
10485 if(biff >= 2 && biff <= 5) return parse_RgceLocRel_BIFF2(blob, length, opts);
10486 var r = blob.read_shift(biff >= 12 ? 4 : 2);
10487 var cl = blob.read_shift(2);
10488 var cRel = (cl & 0x4000) >> 14, rRel = (cl & 0x8000) >> 15;
10489 cl &= 0x3FFF;
10490 if(rRel == 1) while(r > 0x7FFFF) r -= 0x100000;
10491 if(cRel == 1) while(cl > 0x1FFF) cl = cl - 0x4000;
10492 return {r:r,c:cl,cRel:cRel,rRel:rRel};
10493}
10494function parse_RgceLocRel_BIFF2(blob) {
10495 var rl = blob.read_shift(2);
10496 var c = blob.read_shift(1);
10497 var rRel = (rl & 0x8000) >> 15, cRel = (rl & 0x4000) >> 14;
10498 rl &= 0x3FFF;
10499 if(rRel == 1 && rl >= 0x2000) rl = rl - 0x4000;
10500 if(cRel == 1 && c >= 0x80) c = c - 0x100;
10501 return {r:rl,c:c,cRel:cRel,rRel:rRel};
10502}
10503
10504/* [MS-XLS] 2.5.198.27 ; [MS-XLSB] 2.5.97.18 */
10505function parse_PtgArea(blob, length, opts) {
10506 var type = (blob[blob.l++] & 0x60) >> 5;
10507 var area = parse_RgceArea(blob, opts.biff >= 2 && opts.biff <= 5 ? 6 : 8, opts);
10508 return [type, area];
10509}
10510
10511/* [MS-XLS] 2.5.198.28 ; [MS-XLSB] 2.5.97.19 */
10512function parse_PtgArea3d(blob, length, opts) {
10513 var type = (blob[blob.l++] & 0x60) >> 5;
10514 var ixti = blob.read_shift(2, 'i');
10515 var w = 8;
10516 if(opts) switch(opts.biff) {
10517 case 5: blob.l += 12; w = 6; break;
10518 case 12: w = 12; break;
10519 }
10520 var area = parse_RgceArea(blob, w, opts);
10521 return [type, ixti, area];
10522}
10523
10524/* [MS-XLS] 2.5.198.29 ; [MS-XLSB] 2.5.97.20 */
10525function parse_PtgAreaErr(blob, length, opts) {
10526 var type = (blob[blob.l++] & 0x60) >> 5;
10527 blob.l += opts && (opts.biff > 8) ? 12 : (opts.biff < 8 ? 6 : 8);
10528 return [type];
10529}
10530/* [MS-XLS] 2.5.198.30 ; [MS-XLSB] 2.5.97.21 */
10531function parse_PtgAreaErr3d(blob, length, opts) {
10532 var type = (blob[blob.l++] & 0x60) >> 5;
10533 var ixti = blob.read_shift(2);
10534 var w = 8;
10535 if(opts) switch(opts.biff) {
10536 case 5: blob.l += 12; w = 6; break;
10537 case 12: w = 12; break;
10538 }
10539 blob.l += w;
10540 return [type, ixti];
10541}
10542
10543/* [MS-XLS] 2.5.198.31 ; [MS-XLSB] 2.5.97.22 */
10544function parse_PtgAreaN(blob, length, opts) {
10545 var type = (blob[blob.l++] & 0x60) >> 5;
10546 var area = parse_RgceAreaRel(blob, length - 1, opts);
10547 return [type, area];
10548}
10549
10550/* [MS-XLS] 2.5.198.32 ; [MS-XLSB] 2.5.97.23 */
10551function parse_PtgArray(blob, length, opts) {
10552 var type = (blob[blob.l++] & 0x60) >> 5;
10553 blob.l += opts.biff == 2 ? 6 : opts.biff == 12 ? 14 : 7;
10554 return [type];
10555}
10556
10557/* [MS-XLS] 2.5.198.33 ; [MS-XLSB] 2.5.97.24 */
10558function parse_PtgAttrBaxcel(blob) {
10559 var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
10560 var bitBaxcel = 1;
10561 blob.l += 4;
10562 return [bitSemi, bitBaxcel];
10563}
10564
10565/* [MS-XLS] 2.5.198.34 ; [MS-XLSB] 2.5.97.25 */
10566function parse_PtgAttrChoose(blob, length, opts) {
10567 blob.l +=2;
10568 var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10569 var o = [];
10570 /* offset is 1 less than the number of elements */
10571 for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2));
10572 return o;
10573}
10574
10575/* [MS-XLS] 2.5.198.35 ; [MS-XLSB] 2.5.97.26 */
10576function parse_PtgAttrGoto(blob, length, opts) {
10577 var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10578 blob.l += 2;
10579 return [bitGoto, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
10580}
10581
10582/* [MS-XLS] 2.5.198.36 ; [MS-XLSB] 2.5.97.27 */
10583function parse_PtgAttrIf(blob, length, opts) {
10584 var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10585 blob.l += 2;
10586 return [bitIf, blob.read_shift(opts && opts.biff == 2 ? 1 : 2)];
10587}
10588
10589/* [MS-XLSB] 2.5.97.28 */
10590function parse_PtgAttrIfError(blob) {
10591 var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10592 blob.l += 2;
10593 return [bitIf, blob.read_shift(2)];
10594}
10595
10596/* [MS-XLS] 2.5.198.37 ; [MS-XLSB] 2.5.97.29 */
10597function parse_PtgAttrSemi(blob, length, opts) {
10598 var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
10599 blob.l += opts && opts.biff == 2 ? 3 : 4;
10600 return [bitSemi];
10601}
10602
10603/* [MS-XLS] 2.5.198.40 ; [MS-XLSB] 2.5.97.32 */
10604function parse_PtgAttrSpaceType(blob) {
10605 var type = blob.read_shift(1), cch = blob.read_shift(1);
10606 return [type, cch];
10607}
10608
10609/* [MS-XLS] 2.5.198.38 ; [MS-XLSB] 2.5.97.30 */
10610function parse_PtgAttrSpace(blob) {
10611 blob.read_shift(2);
10612 return parse_PtgAttrSpaceType(blob, 2);
10613}
10614
10615/* [MS-XLS] 2.5.198.39 ; [MS-XLSB] 2.5.97.31 */
10616function parse_PtgAttrSpaceSemi(blob) {
10617 blob.read_shift(2);
10618 return parse_PtgAttrSpaceType(blob, 2);
10619}
10620
10621/* [MS-XLS] 2.5.198.84 ; [MS-XLSB] 2.5.97.68 TODO */
10622function parse_PtgRef(blob, length, opts) {
10623 //var ptg = blob[blob.l] & 0x1F;
10624 var type = (blob[blob.l] & 0x60)>>5;
10625 blob.l += 1;
10626 var loc = parse_RgceLoc(blob, 0, opts);
10627 return [type, loc];
10628}
10629
10630/* [MS-XLS] 2.5.198.88 ; [MS-XLSB] 2.5.97.72 TODO */
10631function parse_PtgRefN(blob, length, opts) {
10632 var type = (blob[blob.l] & 0x60)>>5;
10633 blob.l += 1;
10634 var loc = parse_RgceLocRel(blob, 0, opts);
10635 return [type, loc];
10636}
10637
10638/* [MS-XLS] 2.5.198.85 ; [MS-XLSB] 2.5.97.69 TODO */
10639function parse_PtgRef3d(blob, length, opts) {
10640 var type = (blob[blob.l] & 0x60)>>5;
10641 blob.l += 1;
10642 var ixti = blob.read_shift(2); // XtiIndex
10643 if(opts && opts.biff == 5) blob.l += 12;
10644 var loc = parse_RgceLoc(blob, 0, opts); // TODO: or RgceLocRel
10645 return [type, ixti, loc];
10646}
10647
10648
10649/* [MS-XLS] 2.5.198.62 ; [MS-XLSB] 2.5.97.45 TODO */
10650function parse_PtgFunc(blob, length, opts) {
10651 //var ptg = blob[blob.l] & 0x1F;
10652 var type = (blob[blob.l] & 0x60)>>5;
10653 blob.l += 1;
10654 var iftab = blob.read_shift(opts && opts.biff <= 3 ? 1 : 2);
10655 return [FtabArgc[iftab], Ftab[iftab], type];
10656}
10657/* [MS-XLS] 2.5.198.63 ; [MS-XLSB] 2.5.97.46 TODO */
10658function parse_PtgFuncVar(blob, length, opts) {
10659 var type = blob[blob.l++];
10660 var cparams = blob.read_shift(1), tab = opts && opts.biff <= 3 ? [(type == 0x58 ? -1 : 0), blob.read_shift(1)]: parsetab(blob);
10661 return [cparams, (tab[0] === 0 ? Ftab : Cetab)[tab[1]]];
10662}
10663
10664function parsetab(blob) {
10665 return [blob[blob.l+1]>>7, blob.read_shift(2) & 0x7FFF];
10666}
10667
10668/* [MS-XLS] 2.5.198.41 ; [MS-XLSB] 2.5.97.33 */
10669function parse_PtgAttrSum(blob, length, opts) {
10670 blob.l += opts && opts.biff == 2 ? 3 : 4; return;
10671}
10672
10673/* [MS-XLS] 2.5.198.58 ; [MS-XLSB] 2.5.97.40 */
10674function parse_PtgExp(blob, length, opts) {
10675 blob.l++;
10676 if(opts && opts.biff == 12) return [blob.read_shift(4, 'i'), 0];
10677 var row = blob.read_shift(2);
10678 var col = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10679 return [row, col];
10680}
10681
10682/* [MS-XLS] 2.5.198.57 ; [MS-XLSB] 2.5.97.39 */
10683function parse_PtgErr(blob) { blob.l++; return BErr[blob.read_shift(1)]; }
10684
10685/* [MS-XLS] 2.5.198.66 ; [MS-XLSB] 2.5.97.49 */
10686function parse_PtgInt(blob) { blob.l++; return blob.read_shift(2); }
10687
10688/* [MS-XLS] 2.5.198.42 ; [MS-XLSB] 2.5.97.34 */
10689function parse_PtgBool(blob) { blob.l++; return blob.read_shift(1)!==0;}
10690
10691/* [MS-XLS] 2.5.198.79 ; [MS-XLSB] 2.5.97.63 */
10692function parse_PtgNum(blob) { blob.l++; return parse_Xnum(blob, 8); }
10693
10694/* [MS-XLS] 2.5.198.89 ; [MS-XLSB] 2.5.97.74 */
10695function parse_PtgStr(blob, length, opts) { blob.l++; return parse_ShortXLUnicodeString(blob, length-1, opts); }
10696
10697/* [MS-XLS] 2.5.192.112 + 2.5.192.11{3,4,5,6,7} */
10698/* [MS-XLSB] 2.5.97.93 + 2.5.97.9{4,5,6,7} */
10699function parse_SerAr(blob, biff) {
10700 var val = [blob.read_shift(1)];
10701 if(biff == 12) switch(val[0]) {
10702 case 0x02: val[0] = 0x04; break; /* SerBool */
10703 case 0x04: val[0] = 0x10; break; /* SerErr */
10704 case 0x00: val[0] = 0x01; break; /* SerNum */
10705 case 0x01: val[0] = 0x02; break; /* SerStr */
10706 }
10707 switch(val[0]) {
10708 case 0x04: /* SerBool -- boolean */
10709 val[1] = parsebool(blob, 1) ? 'TRUE' : 'FALSE';
10710 if(biff != 12) blob.l += 7; break;
10711 case 0x25: /* appears to be an alias */
10712 case 0x10: /* SerErr -- error */
10713 val[1] = BErr[blob[blob.l]];
10714 blob.l += ((biff == 12) ? 4 : 8); break;
10715 case 0x00: /* SerNil -- honestly, I'm not sure how to reproduce this */
10716 blob.l += 8; break;
10717 case 0x01: /* SerNum -- Xnum */
10718 val[1] = parse_Xnum(blob, 8); break;
10719 case 0x02: /* SerStr -- XLUnicodeString (<256 chars) */
10720 val[1] = parse_XLUnicodeString2(blob, 0, {biff:biff > 0 && biff < 8 ? 2 : biff}); break;
10721 default: throw new Error("Bad SerAr: " + val[0]); /* Unreachable */
10722 }
10723 return val;
10724}
10725
10726/* [MS-XLS] 2.5.198.61 ; [MS-XLSB] 2.5.97.44 */
10727function parse_PtgExtraMem(blob, cce, opts) {
10728 var count = blob.read_shift((opts.biff == 12) ? 4 : 2);
10729 var out = [];
10730 for(var i = 0; i != count; ++i) out.push(((opts.biff == 12) ? parse_UncheckedRfX : parse_Ref8U)(blob, 8));
10731 return out;
10732}
10733
10734/* [MS-XLS] 2.5.198.59 ; [MS-XLSB] 2.5.97.41 */
10735function parse_PtgExtraArray(blob, length, opts) {
10736 var rows = 0, cols = 0;
10737 if(opts.biff == 12) {
10738 rows = blob.read_shift(4); // DRw
10739 cols = blob.read_shift(4); // DCol
10740 } else {
10741 cols = 1 + blob.read_shift(1); //DColByteU
10742 rows = 1 + blob.read_shift(2); //DRw
10743 }
10744 if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; }
10745 // $FlowIgnore
10746 for(var i = 0, o = []; i != rows && (o[i] = []); ++i)
10747 for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff);
10748 return o;
10749}
10750
10751/* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 */
10752function parse_PtgName(blob, length, opts) {
10753 var type = (blob.read_shift(1) >>> 5) & 0x03;
10754 var w = (!opts || (opts.biff >= 8)) ? 4 : 2;
10755 var nameindex = blob.read_shift(w);
10756 switch(opts.biff) {
10757 case 2: blob.l += 5; break;
10758 case 3: case 4: blob.l += 8; break;
10759 case 5: blob.l += 12; break;
10760 }
10761 return [type, 0, nameindex];
10762}
10763
10764/* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 */
10765function parse_PtgNameX(blob, length, opts) {
10766 if(opts.biff == 5) return parse_PtgNameX_BIFF5(blob, length, opts);
10767 var type = (blob.read_shift(1) >>> 5) & 0x03;
10768 var ixti = blob.read_shift(2); // XtiIndex
10769 var nameindex = blob.read_shift(4);
10770 return [type, ixti, nameindex];
10771}
10772function parse_PtgNameX_BIFF5(blob) {
10773 var type = (blob.read_shift(1) >>> 5) & 0x03;
10774 var ixti = blob.read_shift(2, 'i'); // XtiIndex
10775 blob.l += 8;
10776 var nameindex = blob.read_shift(2);
10777 blob.l += 12;
10778 return [type, ixti, nameindex];
10779}
10780
10781/* [MS-XLS] 2.5.198.70 ; [MS-XLSB] 2.5.97.54 */
10782function parse_PtgMemArea(blob, length, opts) {
10783 var type = (blob.read_shift(1) >>> 5) & 0x03;
10784 blob.l += (opts && opts.biff == 2 ? 3 : 4);
10785 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10786 return [type, cce];
10787}
10788
10789/* [MS-XLS] 2.5.198.72 ; [MS-XLSB] 2.5.97.56 */
10790function parse_PtgMemFunc(blob, length, opts) {
10791 var type = (blob.read_shift(1) >>> 5) & 0x03;
10792 var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
10793 return [type, cce];
10794}
10795
10796
10797/* [MS-XLS] 2.5.198.86 ; [MS-XLSB] 2.5.97.69 */
10798function parse_PtgRefErr(blob, length, opts) {
10799 var type = (blob.read_shift(1) >>> 5) & 0x03;
10800 blob.l += 4;
10801 if(opts.biff < 8) blob.l--;
10802 if(opts.biff == 12) blob.l += 2;
10803 return [type];
10804}
10805
10806/* [MS-XLS] 2.5.198.87 ; [MS-XLSB] 2.5.97.71 */
10807function parse_PtgRefErr3d(blob, length, opts) {
10808 var type = (blob[blob.l++] & 0x60) >> 5;
10809 var ixti = blob.read_shift(2);
10810 var w = 4;
10811 if(opts) switch(opts.biff) {
10812 case 5: w = 15; break;
10813 case 12: w = 6; break;
10814 }
10815 blob.l += w;
10816 return [type, ixti];
10817}
10818
10819/* [MS-XLS] 2.5.198.71 ; [MS-XLSB] 2.5.97.55 */
10820var parse_PtgMemErr = parsenoop;
10821/* [MS-XLS] 2.5.198.73 ; [MS-XLSB] 2.5.97.57 */
10822var parse_PtgMemNoMem = parsenoop;
10823/* [MS-XLS] 2.5.198.92 */
10824var parse_PtgTbl = parsenoop;
10825
10826function parse_PtgElfLoc(blob, length, opts) {
10827 blob.l += 2;
10828 return [parse_RgceElfLoc(blob, 4, opts)];
10829}
10830function parse_PtgElfNoop(blob) {
10831 blob.l += 6;
10832 return [];
10833}
10834/* [MS-XLS] 2.5.198.46 */
10835var parse_PtgElfCol = parse_PtgElfLoc;
10836/* [MS-XLS] 2.5.198.47 */
10837var parse_PtgElfColS = parse_PtgElfNoop;
10838/* [MS-XLS] 2.5.198.48 */
10839var parse_PtgElfColSV = parse_PtgElfNoop;
10840/* [MS-XLS] 2.5.198.49 */
10841var parse_PtgElfColV = parse_PtgElfLoc;
10842/* [MS-XLS] 2.5.198.50 */
10843function parse_PtgElfLel(blob) {
10844 blob.l += 2;
10845 return [parseuint16(blob), blob.read_shift(2) & 0x01];
10846}
10847/* [MS-XLS] 2.5.198.51 */
10848var parse_PtgElfRadical = parse_PtgElfLoc;
10849/* [MS-XLS] 2.5.198.52 */
10850var parse_PtgElfRadicalLel = parse_PtgElfLel;
10851/* [MS-XLS] 2.5.198.53 */
10852var parse_PtgElfRadicalS = parse_PtgElfNoop;
10853/* [MS-XLS] 2.5.198.54 */
10854var parse_PtgElfRw = parse_PtgElfLoc;
10855/* [MS-XLS] 2.5.198.55 */
10856var parse_PtgElfRwV = parse_PtgElfLoc;
10857
10858/* [MS-XLSB] 2.5.97.52 TODO */
10859var PtgListRT = [
10860 "Data",
10861 "All",
10862 "Headers",
10863 "??",
10864 "?Data2",
10865 "??",
10866 "?DataHeaders",
10867 "??",
10868 "Totals",
10869 "??",
10870 "??",
10871 "??",
10872 "?DataTotals",
10873 "??",
10874 "??",
10875 "??",
10876 "?Current"
10877];
10878function parse_PtgList(blob) {
10879 blob.l += 2;
10880 var ixti = blob.read_shift(2);
10881 var flags = blob.read_shift(2);
10882 var idx = blob.read_shift(4);
10883 var c = blob.read_shift(2);
10884 var C = blob.read_shift(2);
10885 var rt = PtgListRT[(flags >> 2) & 0x1F];
10886 return {ixti: ixti, coltype:(flags&0x3), rt:rt, idx:idx, c:c, C:C};
10887}
10888/* [MS-XLS] 2.5.198.91 ; [MS-XLSB] 2.5.97.76 */
10889function parse_PtgSxName(blob) {
10890 blob.l += 2;
10891 return [blob.read_shift(4)];
10892}
10893
10894/* [XLS] old spec */
10895function parse_PtgSheet(blob, length, opts) {
10896 blob.l += 5;
10897 blob.l += 2;
10898 blob.l += (opts.biff == 2 ? 1 : 4);
10899 return ["PTGSHEET"];
10900}
10901function parse_PtgEndSheet(blob, length, opts) {
10902 blob.l += (opts.biff == 2 ? 4 : 5);
10903 return ["PTGENDSHEET"];
10904}
10905function parse_PtgMemAreaN(blob) {
10906 var type = (blob.read_shift(1) >>> 5) & 0x03;
10907 var cce = blob.read_shift(2);
10908 return [type, cce];
10909}
10910function parse_PtgMemNoMemN(blob) {
10911 var type = (blob.read_shift(1) >>> 5) & 0x03;
10912 var cce = blob.read_shift(2);
10913 return [type, cce];
10914}
10915function parse_PtgAttrNoop(blob) {
10916 blob.l += 4;
10917 return [0, 0];
10918}
10919
10920/* [MS-XLS] 2.5.198.25 ; [MS-XLSB] 2.5.97.16 */
10921var PtgTypes = {
109220x01: { n:'PtgExp', f:parse_PtgExp },
109230x02: { n:'PtgTbl', f:parse_PtgTbl },
109240x03: { n:'PtgAdd', f:parseread1 },
109250x04: { n:'PtgSub', f:parseread1 },
109260x05: { n:'PtgMul', f:parseread1 },
109270x06: { n:'PtgDiv', f:parseread1 },
109280x07: { n:'PtgPower', f:parseread1 },
109290x08: { n:'PtgConcat', f:parseread1 },
109300x09: { n:'PtgLt', f:parseread1 },
109310x0A: { n:'PtgLe', f:parseread1 },
109320x0B: { n:'PtgEq', f:parseread1 },
109330x0C: { n:'PtgGe', f:parseread1 },
109340x0D: { n:'PtgGt', f:parseread1 },
109350x0E: { n:'PtgNe', f:parseread1 },
109360x0F: { n:'PtgIsect', f:parseread1 },
109370x10: { n:'PtgUnion', f:parseread1 },
109380x11: { n:'PtgRange', f:parseread1 },
109390x12: { n:'PtgUplus', f:parseread1 },
109400x13: { n:'PtgUminus', f:parseread1 },
109410x14: { n:'PtgPercent', f:parseread1 },
109420x15: { n:'PtgParen', f:parseread1 },
109430x16: { n:'PtgMissArg', f:parseread1 },
109440x17: { n:'PtgStr', f:parse_PtgStr },
109450x1A: { n:'PtgSheet', f:parse_PtgSheet },
109460x1B: { n:'PtgEndSheet', f:parse_PtgEndSheet },
109470x1C: { n:'PtgErr', f:parse_PtgErr },
109480x1D: { n:'PtgBool', f:parse_PtgBool },
109490x1E: { n:'PtgInt', f:parse_PtgInt },
109500x1F: { n:'PtgNum', f:parse_PtgNum },
109510x20: { n:'PtgArray', f:parse_PtgArray },
109520x21: { n:'PtgFunc', f:parse_PtgFunc },
109530x22: { n:'PtgFuncVar', f:parse_PtgFuncVar },
109540x23: { n:'PtgName', f:parse_PtgName },
109550x24: { n:'PtgRef', f:parse_PtgRef },
109560x25: { n:'PtgArea', f:parse_PtgArea },
109570x26: { n:'PtgMemArea', f:parse_PtgMemArea },
109580x27: { n:'PtgMemErr', f:parse_PtgMemErr },
109590x28: { n:'PtgMemNoMem', f:parse_PtgMemNoMem },
109600x29: { n:'PtgMemFunc', f:parse_PtgMemFunc },
109610x2A: { n:'PtgRefErr', f:parse_PtgRefErr },
109620x2B: { n:'PtgAreaErr', f:parse_PtgAreaErr },
109630x2C: { n:'PtgRefN', f:parse_PtgRefN },
109640x2D: { n:'PtgAreaN', f:parse_PtgAreaN },
109650x2E: { n:'PtgMemAreaN', f:parse_PtgMemAreaN },
109660x2F: { n:'PtgMemNoMemN', f:parse_PtgMemNoMemN },
109670x39: { n:'PtgNameX', f:parse_PtgNameX },
109680x3A: { n:'PtgRef3d', f:parse_PtgRef3d },
109690x3B: { n:'PtgArea3d', f:parse_PtgArea3d },
109700x3C: { n:'PtgRefErr3d', f:parse_PtgRefErr3d },
109710x3D: { n:'PtgAreaErr3d', f:parse_PtgAreaErr3d },
109720xFF: {}
10973};
10974/* These are duplicated in the PtgTypes table */
10975var PtgDupes = {
109760x40: 0x20, 0x60: 0x20,
109770x41: 0x21, 0x61: 0x21,
109780x42: 0x22, 0x62: 0x22,
109790x43: 0x23, 0x63: 0x23,
109800x44: 0x24, 0x64: 0x24,
109810x45: 0x25, 0x65: 0x25,
109820x46: 0x26, 0x66: 0x26,
109830x47: 0x27, 0x67: 0x27,
109840x48: 0x28, 0x68: 0x28,
109850x49: 0x29, 0x69: 0x29,
109860x4A: 0x2A, 0x6A: 0x2A,
109870x4B: 0x2B, 0x6B: 0x2B,
109880x4C: 0x2C, 0x6C: 0x2C,
109890x4D: 0x2D, 0x6D: 0x2D,
109900x4E: 0x2E, 0x6E: 0x2E,
109910x4F: 0x2F, 0x6F: 0x2F,
109920x58: 0x22, 0x78: 0x22,
109930x59: 0x39, 0x79: 0x39,
109940x5A: 0x3A, 0x7A: 0x3A,
109950x5B: 0x3B, 0x7B: 0x3B,
109960x5C: 0x3C, 0x7C: 0x3C,
109970x5D: 0x3D, 0x7D: 0x3D
10998};
10999(function(){for(var y in PtgDupes) PtgTypes[y] = PtgTypes[PtgDupes[y]];})();
11000
11001var Ptg18 = {
110020x01: { n:'PtgElfLel', f:parse_PtgElfLel },
110030x02: { n:'PtgElfRw', f:parse_PtgElfRw },
110040x03: { n:'PtgElfCol', f:parse_PtgElfCol },
110050x06: { n:'PtgElfRwV', f:parse_PtgElfRwV },
110060x07: { n:'PtgElfColV', f:parse_PtgElfColV },
110070x0A: { n:'PtgElfRadical', f:parse_PtgElfRadical },
110080x0B: { n:'PtgElfRadicalS', f:parse_PtgElfRadicalS },
110090x0D: { n:'PtgElfColS', f:parse_PtgElfColS },
110100x0F: { n:'PtgElfColSV', f:parse_PtgElfColSV },
110110x10: { n:'PtgElfRadicalLel', f:parse_PtgElfRadicalLel },
110120x19: { n:'PtgList', f:parse_PtgList },
110130x1D: { n:'PtgSxName', f:parse_PtgSxName },
110140xFF: {}
11015};
11016var Ptg19 = {
110170x00: { n:'PtgAttrNoop', f:parse_PtgAttrNoop },
110180x01: { n:'PtgAttrSemi', f:parse_PtgAttrSemi },
110190x02: { n:'PtgAttrIf', f:parse_PtgAttrIf },
110200x04: { n:'PtgAttrChoose', f:parse_PtgAttrChoose },
110210x08: { n:'PtgAttrGoto', f:parse_PtgAttrGoto },
110220x10: { n:'PtgAttrSum', f:parse_PtgAttrSum },
110230x20: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel },
110240x40: { n:'PtgAttrSpace', f:parse_PtgAttrSpace },
110250x41: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi },
110260x80: { n:'PtgAttrIfError', f:parse_PtgAttrIfError },
110270xFF: {}
11028};
11029Ptg19[0x21] = Ptg19[0x20];
11030
11031/* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */
11032function parse_RgbExtra(blob, length, rgce, opts) {
11033 if(opts.biff < 8) return parsenoop(blob, length);
11034 var target = blob.l + length;
11035 var o = [];
11036 for(var i = 0; i !== rgce.length; ++i) {
11037 switch(rgce[i][0]) {
11038 case 'PtgArray': /* PtgArray -> PtgExtraArray */
11039 rgce[i][1] = parse_PtgExtraArray(blob, 0, opts);
11040 o.push(rgce[i][1]);
11041 break;
11042 case 'PtgMemArea': /* PtgMemArea -> PtgExtraMem */
11043 rgce[i][2] = parse_PtgExtraMem(blob, rgce[i][1], opts);
11044 o.push(rgce[i][2]);
11045 break;
11046 case 'PtgExp': /* PtgExp -> PtgExtraCol */
11047 if(opts && opts.biff == 12) {
11048 rgce[i][1][1] = blob.read_shift(4);
11049 o.push(rgce[i][1]);
11050 } break;
11051 case 'PtgList': /* TODO: PtgList -> PtgExtraList */
11052 case 'PtgElfRadicalS': /* TODO: PtgElfRadicalS -> PtgExtraElf */
11053 case 'PtgElfColS': /* TODO: PtgElfColS -> PtgExtraElf */
11054 case 'PtgElfColSV': /* TODO: PtgElfColSV -> PtgExtraElf */
11055 throw "Unsupported " + rgce[i][0];
11056 default: break;
11057 }
11058 }
11059 length = target - blob.l;
11060 /* note: this is technically an error but Excel disregards */
11061 //if(target !== blob.l && blob.l !== target - length) throw new Error(target + " != " + blob.l);
11062 if(length !== 0) o.push(parsenoop(blob, length));
11063 return o;
11064}
11065
11066/* [MS-XLS] 2.5.198.104 ; [MS-XLSB] 2.5.97.88 */
11067function parse_Rgce(blob, length, opts) {
11068 var target = blob.l + length;
11069 var R, id, ptgs = [];
11070 while(target != blob.l) {
11071 length = target - blob.l;
11072 id = blob[blob.l];
11073 R = PtgTypes[id];
11074 if(id === 0x18 || id === 0x19) R = (id === 0x18 ? Ptg18 : Ptg19)[blob[blob.l + 1]];
11075 if(!R || !R.f) { /*ptgs.push*/(parsenoop(blob, length)); }
11076 else { ptgs.push([R.n, R.f(blob, length, opts)]); }
11077 }
11078 return ptgs;
11079}
11080
11081function stringify_array(f) {
11082 var o = [];
11083 for(var i = 0; i < f.length; ++i) {
11084 var x = f[i], r = [];
11085 for(var j = 0; j < x.length; ++j) {
11086 var y = x[j];
11087 if(y) switch(y[0]) {
11088 // TODO: handle embedded quotes
11089 case 0x02:
11090r.push('"' + y[1].replace(/"/g,'""') + '"'); break;
11091 default: r.push(y[1]);
11092 } else r.push("");
11093 }
11094 o.push(r.join(","));
11095 }
11096 return o.join(";");
11097}
11098
11099/* [MS-XLS] 2.2.2 ; [MS-XLSB] 2.2.2 TODO */
11100var PtgBinOp = {
11101 PtgAdd: "+",
11102 PtgConcat: "&",
11103 PtgDiv: "/",
11104 PtgEq: "=",
11105 PtgGe: ">=",
11106 PtgGt: ">",
11107 PtgLe: "<=",
11108 PtgLt: "<",
11109 PtgMul: "*",
11110 PtgNe: "<>",
11111 PtgPower: "^",
11112 PtgSub: "-"
11113};
11114function formula_quote_sheet_name(sname, opts) {
11115 if(!sname && !(opts && opts.biff <= 5 && opts.biff >= 2)) throw new Error("empty sheet name");
11116 if(sname.indexOf(" ") > -1) return "'" + sname + "'";
11117 return sname;
11118}
11119function get_ixti_raw(supbooks, ixti, opts) {
11120 if(!supbooks) return "SH33TJSERR0";
11121 if(opts.biff > 8 && (!supbooks.XTI || !supbooks.XTI[ixti])) return supbooks.SheetNames[ixti];
11122 if(!supbooks.XTI) return "SH33TJSERR6";
11123 var XTI = supbooks.XTI[ixti];
11124 if(opts.biff < 8) {
11125 if(ixti > 10000) ixti-= 65536;
11126 if(ixti < 0) ixti = -ixti;
11127 return ixti == 0 ? "" : supbooks.XTI[ixti - 1];
11128 }
11129 if(!XTI) return "SH33TJSERR1";
11130 var o = "";
11131 if(opts.biff > 8) switch(supbooks[XTI[0]][0]) {
11132 case 0x0165: /* 'BrtSupSelf' */
11133 o = XTI[1] == -1 ? "#REF" : supbooks.SheetNames[XTI[1]];
11134 return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
11135 case 0x0166: /* 'BrtSupSame' */
11136 if(opts.SID != null) return supbooks.SheetNames[opts.SID];
11137 return "SH33TJSSAME" + supbooks[XTI[0]][0];
11138 case 0x0163: /* 'BrtSupBookSrc' */
11139 /* falls through */
11140 default: return "SH33TJSSRC" + supbooks[XTI[0]][0];
11141 }
11142 switch(supbooks[XTI[0]][0][0]) {
11143 case 0x0401:
11144 o = XTI[1] == -1 ? "#REF" : (supbooks.SheetNames[XTI[1]] || "SH33TJSERR3");
11145 return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]];
11146 case 0x3A01: return supbooks[XTI[0]].slice(1).map(function(name) { return name.Name; }).join(";;"); //return "SH33TJSERR8";
11147 default:
11148 if(!supbooks[XTI[0]][0][3]) return "SH33TJSERR2";
11149 o = XTI[1] == -1 ? "#REF" : (supbooks[XTI[0]][0][3][XTI[1]] || "SH33TJSERR4");
11150 return XTI[1] == XTI[2] ? o : o + ":" + supbooks[XTI[0]][0][3][XTI[2]];
11151 }
11152}
11153function get_ixti(supbooks, ixti, opts) {
11154 return formula_quote_sheet_name(get_ixti_raw(supbooks, ixti, opts), opts);
11155}
11156function stringify_formula(formula/*Array<any>*/, range, cell, supbooks, opts) {
11157 var biff = (opts && opts.biff) || 8;
11158 var _range = /*range != null ? range :*/ {s:{c:0, r:0},e:{c:0, r:0}};
11159 var stack = [], e1, e2, c, ixti=0, nameidx=0, r, sname="";
11160 if(!formula[0] || !formula[0][0]) return "";
11161 var last_sp = -1, sp = "";
11162 for(var ff = 0, fflen = formula[0].length; ff < fflen; ++ff) {
11163 var f = formula[0][ff];
11164 switch(f[0]) {
11165 case 'PtgUminus': /* [MS-XLS] 2.5.198.93 */
11166 stack.push("-" + stack.pop()); break;
11167 case 'PtgUplus': /* [MS-XLS] 2.5.198.95 */
11168 stack.push("+" + stack.pop()); break;
11169 case 'PtgPercent': /* [MS-XLS] 2.5.198.81 */
11170 stack.push(stack.pop() + "%"); break;
11171
11172 case 'PtgAdd': /* [MS-XLS] 2.5.198.26 */
11173 case 'PtgConcat': /* [MS-XLS] 2.5.198.43 */
11174 case 'PtgDiv': /* [MS-XLS] 2.5.198.45 */
11175 case 'PtgEq': /* [MS-XLS] 2.5.198.56 */
11176 case 'PtgGe': /* [MS-XLS] 2.5.198.64 */
11177 case 'PtgGt': /* [MS-XLS] 2.5.198.65 */
11178 case 'PtgLe': /* [MS-XLS] 2.5.198.68 */
11179 case 'PtgLt': /* [MS-XLS] 2.5.198.69 */
11180 case 'PtgMul': /* [MS-XLS] 2.5.198.75 */
11181 case 'PtgNe': /* [MS-XLS] 2.5.198.78 */
11182 case 'PtgPower': /* [MS-XLS] 2.5.198.82 */
11183 case 'PtgSub': /* [MS-XLS] 2.5.198.90 */
11184 e1 = stack.pop(); e2 = stack.pop();
11185 if(last_sp >= 0) {
11186 switch(formula[0][last_sp][1][0]) {
11187 case 0:
11188 // $FlowIgnore
11189 sp = fill(" ", formula[0][last_sp][1][1]); break;
11190 case 1:
11191 // $FlowIgnore
11192 sp = fill("\r", formula[0][last_sp][1][1]); break;
11193 default:
11194 sp = "";
11195 // $FlowIgnore
11196 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
11197 }
11198 e2 = e2 + sp;
11199 last_sp = -1;
11200 }
11201 stack.push(e2+PtgBinOp[f[0]]+e1);
11202 break;
11203
11204 case 'PtgIsect': /* [MS-XLS] 2.5.198.67 */
11205 e1 = stack.pop(); e2 = stack.pop();
11206 stack.push(e2+" "+e1);
11207 break;
11208 case 'PtgUnion': /* [MS-XLS] 2.5.198.94 */
11209 e1 = stack.pop(); e2 = stack.pop();
11210 stack.push(e2+","+e1);
11211 break;
11212 case 'PtgRange': /* [MS-XLS] 2.5.198.83 */
11213 e1 = stack.pop(); e2 = stack.pop();
11214 stack.push(e2+":"+e1);
11215 break;
11216
11217 case 'PtgAttrChoose': /* [MS-XLS] 2.5.198.34 */
11218 break;
11219 case 'PtgAttrGoto': /* [MS-XLS] 2.5.198.35 */
11220 break;
11221 case 'PtgAttrIf': /* [MS-XLS] 2.5.198.36 */
11222 break;
11223 case 'PtgAttrIfError': /* [MS-XLSB] 2.5.97.28 */
11224 break;
11225
11226
11227 case 'PtgRef': /* [MS-XLS] 2.5.198.84 */
11228c = shift_cell_xls((f[1][1]), _range, opts);
11229 stack.push(encode_cell_xls(c, biff));
11230 break;
11231 case 'PtgRefN': /* [MS-XLS] 2.5.198.88 */
11232c = cell ? shift_cell_xls((f[1][1]), cell, opts) : (f[1][1]);
11233 stack.push(encode_cell_xls(c, biff));
11234 break;
11235 case 'PtgRef3d': /* [MS-XLS] 2.5.198.85 */
11236ixti = f[1][1]; c = shift_cell_xls((f[1][2]), _range, opts);
11237 sname = get_ixti(supbooks, ixti, opts);
11238 var w = sname; /* IE9 fails on defined names */ // eslint-disable-line no-unused-vars
11239 stack.push(sname + "!" + encode_cell_xls(c, biff));
11240 break;
11241
11242 case 'PtgFunc': /* [MS-XLS] 2.5.198.62 */
11243 case 'PtgFuncVar': /* [MS-XLS] 2.5.198.63 */
11244 /* f[1] = [argc, func, type] */
11245 var argc = (f[1][0]), func = (f[1][1]);
11246 if(!argc) argc = 0;
11247 argc &= 0x7F;
11248 var args = argc == 0 ? [] : stack.slice(-argc);
11249 stack.length -= argc;
11250 if(func === 'User') func = args.shift();
11251 stack.push(func + "(" + args.join(",") + ")");
11252 break;
11253
11254 case 'PtgBool': /* [MS-XLS] 2.5.198.42 */
11255 stack.push(f[1] ? "TRUE" : "FALSE"); break;
11256 case 'PtgInt': /* [MS-XLS] 2.5.198.66 */
11257 stack.push(f[1]); break;
11258 case 'PtgNum': /* [MS-XLS] 2.5.198.79 TODO: precision? */
11259 stack.push(String(f[1])); break;
11260 case 'PtgStr': /* [MS-XLS] 2.5.198.89 */
11261 // $FlowIgnore
11262 stack.push('"' + f[1].replace(/"/g, '""') + '"'); break;
11263 case 'PtgErr': /* [MS-XLS] 2.5.198.57 */
11264 stack.push(f[1]); break;
11265 case 'PtgAreaN': /* [MS-XLS] 2.5.198.31 TODO */
11266r = shift_range_xls(f[1][1], cell ? {s:cell} : _range, opts);
11267 stack.push(encode_range_xls((r), opts));
11268 break;
11269 case 'PtgArea': /* [MS-XLS] 2.5.198.27 TODO: fixed points */
11270r = shift_range_xls(f[1][1], _range, opts);
11271 stack.push(encode_range_xls((r), opts));
11272 break;
11273 case 'PtgArea3d': /* [MS-XLS] 2.5.198.28 TODO */
11274ixti = f[1][1]; r = f[1][2];
11275 sname = get_ixti(supbooks, ixti, opts);
11276 stack.push(sname + "!" + encode_range_xls((r), opts));
11277 break;
11278 case 'PtgAttrSum': /* [MS-XLS] 2.5.198.41 */
11279 stack.push("SUM(" + stack.pop() + ")");
11280 break;
11281
11282 case 'PtgAttrBaxcel': /* [MS-XLS] 2.5.198.33 */
11283 case 'PtgAttrSemi': /* [MS-XLS] 2.5.198.37 */
11284 break;
11285
11286 case 'PtgName': /* [MS-XLS] 2.5.198.76 ; [MS-XLSB] 2.5.97.60 TODO: revisions */
11287 /* f[1] = type, 0, nameindex */
11288 nameidx = (f[1][2]);
11289 var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx];
11290 var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx);
11291 if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name];
11292 stack.push(name);
11293 break;
11294
11295 case 'PtgNameX': /* [MS-XLS] 2.5.198.77 ; [MS-XLSB] 2.5.97.61 TODO: revisions */
11296 /* f[1] = type, ixti, nameindex */
11297 var bookidx = (f[1][1]); nameidx = (f[1][2]); var externbook;
11298 /* TODO: Properly handle missing values -- this should be using get_ixti_raw primarily */
11299 if(opts.biff <= 5) {
11300 if(bookidx < 0) bookidx = -bookidx;
11301 if(supbooks[bookidx]) externbook = supbooks[bookidx][nameidx];
11302 } else {
11303 var o = "";
11304 if(((supbooks[bookidx]||[])[0]||[])[0] == 0x3A01){/* empty */}
11305 else if(((supbooks[bookidx]||[])[0]||[])[0] == 0x0401){
11306 if(supbooks[bookidx][nameidx] && supbooks[bookidx][nameidx].itab > 0) {
11307 o = supbooks.SheetNames[supbooks[bookidx][nameidx].itab-1] + "!";
11308 }
11309 }
11310 else o = supbooks.SheetNames[nameidx-1]+ "!";
11311 if(supbooks[bookidx] && supbooks[bookidx][nameidx]) o += supbooks[bookidx][nameidx].Name;
11312 else if(supbooks[0] && supbooks[0][nameidx]) o += supbooks[0][nameidx].Name;
11313 else {
11314 var ixtidata = get_ixti_raw(supbooks, bookidx, opts).split(";;");
11315 if(ixtidata[nameidx - 1]) o = ixtidata[nameidx - 1]; // TODO: confirm this is correct
11316 else o += "SH33TJSERRX";
11317 }
11318 stack.push(o);
11319 break;
11320 }
11321 if(!externbook) externbook = {Name: "SH33TJSERRY"};
11322 stack.push(externbook.Name);
11323 break;
11324
11325 case 'PtgParen': /* [MS-XLS] 2.5.198.80 */
11326 var lp = '(', rp = ')';
11327 if(last_sp >= 0) {
11328 sp = "";
11329 switch(formula[0][last_sp][1][0]) {
11330 // $FlowIgnore
11331 case 2: lp = fill(" ", formula[0][last_sp][1][1]) + lp; break;
11332 // $FlowIgnore
11333 case 3: lp = fill("\r", formula[0][last_sp][1][1]) + lp; break;
11334 // $FlowIgnore
11335 case 4: rp = fill(" ", formula[0][last_sp][1][1]) + rp; break;
11336 // $FlowIgnore
11337 case 5: rp = fill("\r", formula[0][last_sp][1][1]) + rp; break;
11338 default:
11339 // $FlowIgnore
11340 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + formula[0][last_sp][1][0]);
11341 }
11342 last_sp = -1;
11343 }
11344 stack.push(lp + stack.pop() + rp); break;
11345
11346 case 'PtgRefErr': /* [MS-XLS] 2.5.198.86 */
11347 stack.push('#REF!'); break;
11348
11349 case 'PtgRefErr3d': /* [MS-XLS] 2.5.198.87 */
11350 stack.push('#REF!'); break;
11351
11352 case 'PtgExp': /* [MS-XLS] 2.5.198.58 TODO */
11353 c = {c:(f[1][1]),r:(f[1][0])};
11354 var q = ({c: cell.c, r:cell.r});
11355 if(supbooks.sharedf[encode_cell(c)]) {
11356 var parsedf = (supbooks.sharedf[encode_cell(c)]);
11357 stack.push(stringify_formula(parsedf, _range, q, supbooks, opts));
11358 }
11359 else {
11360 var fnd = false;
11361 for(e1=0;e1!=supbooks.arrayf.length; ++e1) {
11362 /* TODO: should be something like range_has */
11363 e2 = supbooks.arrayf[e1];
11364 if(c.c < e2[0].s.c || c.c > e2[0].e.c) continue;
11365 if(c.r < e2[0].s.r || c.r > e2[0].e.r) continue;
11366 stack.push(stringify_formula(e2[1], _range, q, supbooks, opts));
11367 fnd = true;
11368 break;
11369 }
11370 if(!fnd) stack.push(f[1]);
11371 }
11372 break;
11373
11374 case 'PtgArray': /* [MS-XLS] 2.5.198.32 TODO */
11375 stack.push("{" + stringify_array(f[1]) + "}");
11376 break;
11377
11378 case 'PtgMemArea': /* [MS-XLS] 2.5.198.70 TODO: confirm this is a non-display */
11379 //stack.push("(" + f[2].map(encode_range).join(",") + ")");
11380 break;
11381
11382 case 'PtgAttrSpace': /* [MS-XLS] 2.5.198.38 */
11383 case 'PtgAttrSpaceSemi': /* [MS-XLS] 2.5.198.39 */
11384 last_sp = ff;
11385 break;
11386
11387 case 'PtgTbl': /* [MS-XLS] 2.5.198.92 TODO */
11388 break;
11389
11390 case 'PtgMemErr': /* [MS-XLS] 2.5.198.71 */
11391 break;
11392
11393 case 'PtgMissArg': /* [MS-XLS] 2.5.198.74 */
11394 stack.push("");
11395 break;
11396
11397 case 'PtgAreaErr': /* [MS-XLS] 2.5.198.29 */
11398 stack.push("#REF!"); break;
11399
11400 case 'PtgAreaErr3d': /* [MS-XLS] 2.5.198.30 */
11401 stack.push("#REF!"); break;
11402
11403 case 'PtgList': /* [MS-XLSB] 2.5.97.52 */
11404 // $FlowIgnore
11405 stack.push("Table" + f[1].idx + "[#" + f[1].rt + "]");
11406 break;
11407
11408 case 'PtgMemAreaN':
11409 case 'PtgMemNoMemN':
11410 case 'PtgAttrNoop':
11411 case 'PtgSheet':
11412 case 'PtgEndSheet':
11413 break;
11414
11415 case 'PtgMemFunc': /* [MS-XLS] 2.5.198.72 TODO */
11416 break;
11417 case 'PtgMemNoMem': /* [MS-XLS] 2.5.198.73 TODO */
11418 break;
11419
11420 case 'PtgElfCol': /* [MS-XLS] 2.5.198.46 */
11421 case 'PtgElfColS': /* [MS-XLS] 2.5.198.47 */
11422 case 'PtgElfColSV': /* [MS-XLS] 2.5.198.48 */
11423 case 'PtgElfColV': /* [MS-XLS] 2.5.198.49 */
11424 case 'PtgElfLel': /* [MS-XLS] 2.5.198.50 */
11425 case 'PtgElfRadical': /* [MS-XLS] 2.5.198.51 */
11426 case 'PtgElfRadicalLel': /* [MS-XLS] 2.5.198.52 */
11427 case 'PtgElfRadicalS': /* [MS-XLS] 2.5.198.53 */
11428 case 'PtgElfRw': /* [MS-XLS] 2.5.198.54 */
11429 case 'PtgElfRwV': /* [MS-XLS] 2.5.198.55 */
11430 throw new Error("Unsupported ELFs");
11431
11432 case 'PtgSxName': /* [MS-XLS] 2.5.198.91 TODO -- find a test case */
11433 throw new Error('Unrecognized Formula Token: ' + String(f));
11434 default: throw new Error('Unrecognized Formula Token: ' + String(f));
11435 }
11436 var PtgNonDisp = ['PtgAttrSpace', 'PtgAttrSpaceSemi', 'PtgAttrGoto'];
11437 if(opts.biff != 3) if(last_sp >= 0 && PtgNonDisp.indexOf(formula[0][ff][0]) == -1) {
11438 f = formula[0][last_sp];
11439 var _left = true;
11440 switch(f[1][0]) {
11441 /* note: some bad XLSB files omit the PtgParen */
11442 case 4: _left = false;
11443 /* falls through */
11444 case 0:
11445 // $FlowIgnore
11446 sp = fill(" ", f[1][1]); break;
11447 case 5: _left = false;
11448 /* falls through */
11449 case 1:
11450 // $FlowIgnore
11451 sp = fill("\r", f[1][1]); break;
11452 default:
11453 sp = "";
11454 // $FlowIgnore
11455 if(opts.WTF) throw new Error("Unexpected PtgAttrSpaceType " + f[1][0]);
11456 }
11457 stack.push((_left ? sp : "") + stack.pop() + (_left ? "" : sp));
11458 last_sp = -1;
11459 }
11460 }
11461 if(stack.length > 1 && opts.WTF) throw new Error("bad formula stack");
11462 return stack[0];
11463}
11464
11465/* [MS-XLS] 2.5.198.1 TODO */
11466function parse_ArrayParsedFormula(blob, length, opts) {
11467 var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
11468 var rgcb, cce = blob.read_shift(len); // length of rgce
11469 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11470 var rgce = parse_Rgce(blob, cce, opts);
11471 if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
11472 blob.l = target;
11473 return [rgce, rgcb];
11474}
11475
11476/* [MS-XLS] 2.5.198.3 TODO */
11477function parse_XLSCellParsedFormula(blob, length, opts) {
11478 var target = blob.l + length, len = opts.biff == 2 ? 1 : 2;
11479 var rgcb, cce = blob.read_shift(len); // length of rgce
11480 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11481 var rgce = parse_Rgce(blob, cce, opts);
11482 if(length !== cce + len) rgcb = parse_RgbExtra(blob, length - cce - len, rgce, opts);
11483 blob.l = target;
11484 return [rgce, rgcb];
11485}
11486
11487/* [MS-XLS] 2.5.198.21 */
11488function parse_NameParsedFormula(blob, length, opts, cce) {
11489 var target = blob.l + length;
11490 var rgce = parse_Rgce(blob, cce, opts);
11491 var rgcb;
11492 if(target !== blob.l) rgcb = parse_RgbExtra(blob, target - blob.l, rgce, opts);
11493 return [rgce, rgcb];
11494}
11495
11496/* [MS-XLS] 2.5.198.118 TODO */
11497function parse_SharedParsedFormula(blob, length, opts) {
11498 var target = blob.l + length;
11499 var rgcb, cce = blob.read_shift(2); // length of rgce
11500 var rgce = parse_Rgce(blob, cce, opts);
11501 if(cce == 0xFFFF) return [[],parsenoop(blob, length-2)];
11502 if(length !== cce + 2) rgcb = parse_RgbExtra(blob, target - cce - 2, rgce, opts);
11503 return [rgce, rgcb];
11504}
11505
11506/* [MS-XLS] 2.5.133 TODO: how to emit empty strings? */
11507function parse_FormulaValue(blob) {
11508 var b;
11509 if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return [parse_Xnum(blob),'n'];
11510 switch(blob[blob.l]) {
11511 case 0x00: blob.l += 8; return ["String", 's'];
11512 case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return [b,'b'];
11513 case 0x02: b = blob[blob.l+2]; blob.l += 8; return [b,'e'];
11514 case 0x03: blob.l += 8; return ["",'s'];
11515 }
11516 return [];
11517}
11518function write_FormulaValue(value) {
11519 if(value == null) {
11520 // Blank String Value
11521 var o = new_buf(8);
11522 o.write_shift(1, 0x03);
11523 o.write_shift(1, 0);
11524 o.write_shift(2, 0);
11525 o.write_shift(2, 0);
11526 o.write_shift(2, 0xFFFF);
11527 return o;
11528 } else if(typeof value == "number") return write_Xnum(value);
11529 return write_Xnum(0);
11530}
11531
11532/* [MS-XLS] 2.4.127 TODO */
11533function parse_Formula(blob, length, opts) {
11534 var end = blob.l + length;
11535 var cell = parse_XLSCell(blob, 6);
11536 if(opts.biff == 2) ++blob.l;
11537 var val = parse_FormulaValue(blob,8);
11538 var flags = blob.read_shift(1);
11539 if(opts.biff != 2) {
11540 blob.read_shift(1);
11541 if(opts.biff >= 5) {
11542 /*var chn = */blob.read_shift(4);
11543 }
11544 }
11545 var cbf = parse_XLSCellParsedFormula(blob, end - blob.l, opts);
11546 return {cell:cell, val:val[0], formula:cbf, shared: (flags >> 3) & 1, tt:val[1]};
11547}
11548function write_Formula(cell, R, C, opts, os) {
11549 // Cell
11550 var o1 = write_XLSCell(R, C, os);
11551
11552 // FormulaValue
11553 var o2 = write_FormulaValue(cell.v);
11554
11555 // flags + cache
11556 var o3 = new_buf(6);
11557 var flags = 0x01 | 0x20;
11558 o3.write_shift(2, flags);
11559 o3.write_shift(4, 0);
11560
11561 // CellParsedFormula
11562 var bf = new_buf(cell.bf.length);
11563 for(var i = 0; i < cell.bf.length; ++i) bf[i] = cell.bf[i];
11564
11565 var out = bconcat([o1, o2, o3, bf]);
11566 return out;
11567}
11568
11569
11570/* XLSB Parsed Formula records have the same shape */
11571function parse_XLSBParsedFormula(data, length, opts) {
11572 var cce = data.read_shift(4);
11573 var rgce = parse_Rgce(data, cce, opts);
11574 var cb = data.read_shift(4);
11575 var rgcb = cb > 0 ? parse_RgbExtra(data, cb, rgce, opts) : null;
11576 return [rgce, rgcb];
11577}
11578
11579/* [MS-XLSB] 2.5.97.1 ArrayParsedFormula */
11580var parse_XLSBArrayParsedFormula = parse_XLSBParsedFormula;
11581/* [MS-XLSB] 2.5.97.4 CellParsedFormula */
11582var parse_XLSBCellParsedFormula = parse_XLSBParsedFormula;
11583/* [MS-XLSB] 2.5.97.8 DVParsedFormula */
11584//var parse_XLSBDVParsedFormula = parse_XLSBParsedFormula;
11585/* [MS-XLSB] 2.5.97.9 FRTParsedFormula */
11586//var parse_XLSBFRTParsedFormula = parse_XLSBParsedFormula2;
11587/* [MS-XLSB] 2.5.97.12 NameParsedFormula */
11588var parse_XLSBNameParsedFormula = parse_XLSBParsedFormula;
11589/* [MS-XLSB] 2.5.97.98 SharedParsedFormula */
11590var parse_XLSBSharedParsedFormula = parse_XLSBParsedFormula;
11591/* [MS-XLS] 2.5.198.4 */
11592var Cetab = {
115930x0000: 'BEEP',
115940x0001: 'OPEN',
115950x0002: 'OPEN.LINKS',
115960x0003: 'CLOSE.ALL',
115970x0004: 'SAVE',
115980x0005: 'SAVE.AS',
115990x0006: 'FILE.DELETE',
116000x0007: 'PAGE.SETUP',
116010x0008: 'PRINT',
116020x0009: 'PRINTER.SETUP',
116030x000A: 'QUIT',
116040x000B: 'NEW.WINDOW',
116050x000C: 'ARRANGE.ALL',
116060x000D: 'WINDOW.SIZE',
116070x000E: 'WINDOW.MOVE',
116080x000F: 'FULL',
116090x0010: 'CLOSE',
116100x0011: 'RUN',
116110x0016: 'SET.PRINT.AREA',
116120x0017: 'SET.PRINT.TITLES',
116130x0018: 'SET.PAGE.BREAK',
116140x0019: 'REMOVE.PAGE.BREAK',
116150x001A: 'FONT',
116160x001B: 'DISPLAY',
116170x001C: 'PROTECT.DOCUMENT',
116180x001D: 'PRECISION',
116190x001E: 'A1.R1C1',
116200x001F: 'CALCULATE.NOW',
116210x0020: 'CALCULATION',
116220x0022: 'DATA.FIND',
116230x0023: 'EXTRACT',
116240x0024: 'DATA.DELETE',
116250x0025: 'SET.DATABASE',
116260x0026: 'SET.CRITERIA',
116270x0027: 'SORT',
116280x0028: 'DATA.SERIES',
116290x0029: 'TABLE',
116300x002A: 'FORMAT.NUMBER',
116310x002B: 'ALIGNMENT',
116320x002C: 'STYLE',
116330x002D: 'BORDER',
116340x002E: 'CELL.PROTECTION',
116350x002F: 'COLUMN.WIDTH',
116360x0030: 'UNDO',
116370x0031: 'CUT',
116380x0032: 'COPY',
116390x0033: 'PASTE',
116400x0034: 'CLEAR',
116410x0035: 'PASTE.SPECIAL',
116420x0036: 'EDIT.DELETE',
116430x0037: 'INSERT',
116440x0038: 'FILL.RIGHT',
116450x0039: 'FILL.DOWN',
116460x003D: 'DEFINE.NAME',
116470x003E: 'CREATE.NAMES',
116480x003F: 'FORMULA.GOTO',
116490x0040: 'FORMULA.FIND',
116500x0041: 'SELECT.LAST.CELL',
116510x0042: 'SHOW.ACTIVE.CELL',
116520x0043: 'GALLERY.AREA',
116530x0044: 'GALLERY.BAR',
116540x0045: 'GALLERY.COLUMN',
116550x0046: 'GALLERY.LINE',
116560x0047: 'GALLERY.PIE',
116570x0048: 'GALLERY.SCATTER',
116580x0049: 'COMBINATION',
116590x004A: 'PREFERRED',
116600x004B: 'ADD.OVERLAY',
116610x004C: 'GRIDLINES',
116620x004D: 'SET.PREFERRED',
116630x004E: 'AXES',
116640x004F: 'LEGEND',
116650x0050: 'ATTACH.TEXT',
116660x0051: 'ADD.ARROW',
116670x0052: 'SELECT.CHART',
116680x0053: 'SELECT.PLOT.AREA',
116690x0054: 'PATTERNS',
116700x0055: 'MAIN.CHART',
116710x0056: 'OVERLAY',
116720x0057: 'SCALE',
116730x0058: 'FORMAT.LEGEND',
116740x0059: 'FORMAT.TEXT',
116750x005A: 'EDIT.REPEAT',
116760x005B: 'PARSE',
116770x005C: 'JUSTIFY',
116780x005D: 'HIDE',
116790x005E: 'UNHIDE',
116800x005F: 'WORKSPACE',
116810x0060: 'FORMULA',
116820x0061: 'FORMULA.FILL',
116830x0062: 'FORMULA.ARRAY',
116840x0063: 'DATA.FIND.NEXT',
116850x0064: 'DATA.FIND.PREV',
116860x0065: 'FORMULA.FIND.NEXT',
116870x0066: 'FORMULA.FIND.PREV',
116880x0067: 'ACTIVATE',
116890x0068: 'ACTIVATE.NEXT',
116900x0069: 'ACTIVATE.PREV',
116910x006A: 'UNLOCKED.NEXT',
116920x006B: 'UNLOCKED.PREV',
116930x006C: 'COPY.PICTURE',
116940x006D: 'SELECT',
116950x006E: 'DELETE.NAME',
116960x006F: 'DELETE.FORMAT',
116970x0070: 'VLINE',
116980x0071: 'HLINE',
116990x0072: 'VPAGE',
117000x0073: 'HPAGE',
117010x0074: 'VSCROLL',
117020x0075: 'HSCROLL',
117030x0076: 'ALERT',
117040x0077: 'NEW',
117050x0078: 'CANCEL.COPY',
117060x0079: 'SHOW.CLIPBOARD',
117070x007A: 'MESSAGE',
117080x007C: 'PASTE.LINK',
117090x007D: 'APP.ACTIVATE',
117100x007E: 'DELETE.ARROW',
117110x007F: 'ROW.HEIGHT',
117120x0080: 'FORMAT.MOVE',
117130x0081: 'FORMAT.SIZE',
117140x0082: 'FORMULA.REPLACE',
117150x0083: 'SEND.KEYS',
117160x0084: 'SELECT.SPECIAL',
117170x0085: 'APPLY.NAMES',
117180x0086: 'REPLACE.FONT',
117190x0087: 'FREEZE.PANES',
117200x0088: 'SHOW.INFO',
117210x0089: 'SPLIT',
117220x008A: 'ON.WINDOW',
117230x008B: 'ON.DATA',
117240x008C: 'DISABLE.INPUT',
117250x008E: 'OUTLINE',
117260x008F: 'LIST.NAMES',
117270x0090: 'FILE.CLOSE',
117280x0091: 'SAVE.WORKBOOK',
117290x0092: 'DATA.FORM',
117300x0093: 'COPY.CHART',
117310x0094: 'ON.TIME',
117320x0095: 'WAIT',
117330x0096: 'FORMAT.FONT',
117340x0097: 'FILL.UP',
117350x0098: 'FILL.LEFT',
117360x0099: 'DELETE.OVERLAY',
117370x009B: 'SHORT.MENUS',
117380x009F: 'SET.UPDATE.STATUS',
117390x00A1: 'COLOR.PALETTE',
117400x00A2: 'DELETE.STYLE',
117410x00A3: 'WINDOW.RESTORE',
117420x00A4: 'WINDOW.MAXIMIZE',
117430x00A6: 'CHANGE.LINK',
117440x00A7: 'CALCULATE.DOCUMENT',
117450x00A8: 'ON.KEY',
117460x00A9: 'APP.RESTORE',
117470x00AA: 'APP.MOVE',
117480x00AB: 'APP.SIZE',
117490x00AC: 'APP.MINIMIZE',
117500x00AD: 'APP.MAXIMIZE',
117510x00AE: 'BRING.TO.FRONT',
117520x00AF: 'SEND.TO.BACK',
117530x00B9: 'MAIN.CHART.TYPE',
117540x00BA: 'OVERLAY.CHART.TYPE',
117550x00BB: 'SELECT.END',
117560x00BC: 'OPEN.MAIL',
117570x00BD: 'SEND.MAIL',
117580x00BE: 'STANDARD.FONT',
117590x00BF: 'CONSOLIDATE',
117600x00C0: 'SORT.SPECIAL',
117610x00C1: 'GALLERY.3D.AREA',
117620x00C2: 'GALLERY.3D.COLUMN',
117630x00C3: 'GALLERY.3D.LINE',
117640x00C4: 'GALLERY.3D.PIE',
117650x00C5: 'VIEW.3D',
117660x00C6: 'GOAL.SEEK',
117670x00C7: 'WORKGROUP',
117680x00C8: 'FILL.GROUP',
117690x00C9: 'UPDATE.LINK',
117700x00CA: 'PROMOTE',
117710x00CB: 'DEMOTE',
117720x00CC: 'SHOW.DETAIL',
117730x00CE: 'UNGROUP',
117740x00CF: 'OBJECT.PROPERTIES',
117750x00D0: 'SAVE.NEW.OBJECT',
117760x00D1: 'SHARE',
117770x00D2: 'SHARE.NAME',
117780x00D3: 'DUPLICATE',
117790x00D4: 'APPLY.STYLE',
117800x00D5: 'ASSIGN.TO.OBJECT',
117810x00D6: 'OBJECT.PROTECTION',
117820x00D7: 'HIDE.OBJECT',
117830x00D8: 'SET.EXTRACT',
117840x00D9: 'CREATE.PUBLISHER',
117850x00DA: 'SUBSCRIBE.TO',
117860x00DB: 'ATTRIBUTES',
117870x00DC: 'SHOW.TOOLBAR',
117880x00DE: 'PRINT.PREVIEW',
117890x00DF: 'EDIT.COLOR',
117900x00E0: 'SHOW.LEVELS',
117910x00E1: 'FORMAT.MAIN',
117920x00E2: 'FORMAT.OVERLAY',
117930x00E3: 'ON.RECALC',
117940x00E4: 'EDIT.SERIES',
117950x00E5: 'DEFINE.STYLE',
117960x00F0: 'LINE.PRINT',
117970x00F3: 'ENTER.DATA',
117980x00F9: 'GALLERY.RADAR',
117990x00FA: 'MERGE.STYLES',
118000x00FB: 'EDITION.OPTIONS',
118010x00FC: 'PASTE.PICTURE',
118020x00FD: 'PASTE.PICTURE.LINK',
118030x00FE: 'SPELLING',
118040x0100: 'ZOOM',
118050x0103: 'INSERT.OBJECT',
118060x0104: 'WINDOW.MINIMIZE',
118070x0109: 'SOUND.NOTE',
118080x010A: 'SOUND.PLAY',
118090x010B: 'FORMAT.SHAPE',
118100x010C: 'EXTEND.POLYGON',
118110x010D: 'FORMAT.AUTO',
118120x0110: 'GALLERY.3D.BAR',
118130x0111: 'GALLERY.3D.SURFACE',
118140x0112: 'FILL.AUTO',
118150x0114: 'CUSTOMIZE.TOOLBAR',
118160x0115: 'ADD.TOOL',
118170x0116: 'EDIT.OBJECT',
118180x0117: 'ON.DOUBLECLICK',
118190x0118: 'ON.ENTRY',
118200x0119: 'WORKBOOK.ADD',
118210x011A: 'WORKBOOK.MOVE',
118220x011B: 'WORKBOOK.COPY',
118230x011C: 'WORKBOOK.OPTIONS',
118240x011D: 'SAVE.WORKSPACE',
118250x0120: 'CHART.WIZARD',
118260x0121: 'DELETE.TOOL',
118270x0122: 'MOVE.TOOL',
118280x0123: 'WORKBOOK.SELECT',
118290x0124: 'WORKBOOK.ACTIVATE',
118300x0125: 'ASSIGN.TO.TOOL',
118310x0127: 'COPY.TOOL',
118320x0128: 'RESET.TOOL',
118330x0129: 'CONSTRAIN.NUMERIC',
118340x012A: 'PASTE.TOOL',
118350x012E: 'WORKBOOK.NEW',
118360x0131: 'SCENARIO.CELLS',
118370x0132: 'SCENARIO.DELETE',
118380x0133: 'SCENARIO.ADD',
118390x0134: 'SCENARIO.EDIT',
118400x0135: 'SCENARIO.SHOW',
118410x0136: 'SCENARIO.SHOW.NEXT',
118420x0137: 'SCENARIO.SUMMARY',
118430x0138: 'PIVOT.TABLE.WIZARD',
118440x0139: 'PIVOT.FIELD.PROPERTIES',
118450x013A: 'PIVOT.FIELD',
118460x013B: 'PIVOT.ITEM',
118470x013C: 'PIVOT.ADD.FIELDS',
118480x013E: 'OPTIONS.CALCULATION',
118490x013F: 'OPTIONS.EDIT',
118500x0140: 'OPTIONS.VIEW',
118510x0141: 'ADDIN.MANAGER',
118520x0142: 'MENU.EDITOR',
118530x0143: 'ATTACH.TOOLBARS',
118540x0144: 'VBAActivate',
118550x0145: 'OPTIONS.CHART',
118560x0148: 'VBA.INSERT.FILE',
118570x014A: 'VBA.PROCEDURE.DEFINITION',
118580x0150: 'ROUTING.SLIP',
118590x0152: 'ROUTE.DOCUMENT',
118600x0153: 'MAIL.LOGON',
118610x0156: 'INSERT.PICTURE',
118620x0157: 'EDIT.TOOL',
118630x0158: 'GALLERY.DOUGHNUT',
118640x015E: 'CHART.TREND',
118650x0160: 'PIVOT.ITEM.PROPERTIES',
118660x0162: 'WORKBOOK.INSERT',
118670x0163: 'OPTIONS.TRANSITION',
118680x0164: 'OPTIONS.GENERAL',
118690x0172: 'FILTER.ADVANCED',
118700x0175: 'MAIL.ADD.MAILER',
118710x0176: 'MAIL.DELETE.MAILER',
118720x0177: 'MAIL.REPLY',
118730x0178: 'MAIL.REPLY.ALL',
118740x0179: 'MAIL.FORWARD',
118750x017A: 'MAIL.NEXT.LETTER',
118760x017B: 'DATA.LABEL',
118770x017C: 'INSERT.TITLE',
118780x017D: 'FONT.PROPERTIES',
118790x017E: 'MACRO.OPTIONS',
118800x017F: 'WORKBOOK.HIDE',
118810x0180: 'WORKBOOK.UNHIDE',
118820x0181: 'WORKBOOK.DELETE',
118830x0182: 'WORKBOOK.NAME',
118840x0184: 'GALLERY.CUSTOM',
118850x0186: 'ADD.CHART.AUTOFORMAT',
118860x0187: 'DELETE.CHART.AUTOFORMAT',
118870x0188: 'CHART.ADD.DATA',
118880x0189: 'AUTO.OUTLINE',
118890x018A: 'TAB.ORDER',
118900x018B: 'SHOW.DIALOG',
118910x018C: 'SELECT.ALL',
118920x018D: 'UNGROUP.SHEETS',
118930x018E: 'SUBTOTAL.CREATE',
118940x018F: 'SUBTOTAL.REMOVE',
118950x0190: 'RENAME.OBJECT',
118960x019C: 'WORKBOOK.SCROLL',
118970x019D: 'WORKBOOK.NEXT',
118980x019E: 'WORKBOOK.PREV',
118990x019F: 'WORKBOOK.TAB.SPLIT',
119000x01A0: 'FULL.SCREEN',
119010x01A1: 'WORKBOOK.PROTECT',
119020x01A4: 'SCROLLBAR.PROPERTIES',
119030x01A5: 'PIVOT.SHOW.PAGES',
119040x01A6: 'TEXT.TO.COLUMNS',
119050x01A7: 'FORMAT.CHARTTYPE',
119060x01A8: 'LINK.FORMAT',
119070x01A9: 'TRACER.DISPLAY',
119080x01AE: 'TRACER.NAVIGATE',
119090x01AF: 'TRACER.CLEAR',
119100x01B0: 'TRACER.ERROR',
119110x01B1: 'PIVOT.FIELD.GROUP',
119120x01B2: 'PIVOT.FIELD.UNGROUP',
119130x01B3: 'CHECKBOX.PROPERTIES',
119140x01B4: 'LABEL.PROPERTIES',
119150x01B5: 'LISTBOX.PROPERTIES',
119160x01B6: 'EDITBOX.PROPERTIES',
119170x01B7: 'PIVOT.REFRESH',
119180x01B8: 'LINK.COMBO',
119190x01B9: 'OPEN.TEXT',
119200x01BA: 'HIDE.DIALOG',
119210x01BB: 'SET.DIALOG.FOCUS',
119220x01BC: 'ENABLE.OBJECT',
119230x01BD: 'PUSHBUTTON.PROPERTIES',
119240x01BE: 'SET.DIALOG.DEFAULT',
119250x01BF: 'FILTER',
119260x01C0: 'FILTER.SHOW.ALL',
119270x01C1: 'CLEAR.OUTLINE',
119280x01C2: 'FUNCTION.WIZARD',
119290x01C3: 'ADD.LIST.ITEM',
119300x01C4: 'SET.LIST.ITEM',
119310x01C5: 'REMOVE.LIST.ITEM',
119320x01C6: 'SELECT.LIST.ITEM',
119330x01C7: 'SET.CONTROL.VALUE',
119340x01C8: 'SAVE.COPY.AS',
119350x01CA: 'OPTIONS.LISTS.ADD',
119360x01CB: 'OPTIONS.LISTS.DELETE',
119370x01CC: 'SERIES.AXES',
119380x01CD: 'SERIES.X',
119390x01CE: 'SERIES.Y',
119400x01CF: 'ERRORBAR.X',
119410x01D0: 'ERRORBAR.Y',
119420x01D1: 'FORMAT.CHART',
119430x01D2: 'SERIES.ORDER',
119440x01D3: 'MAIL.LOGOFF',
119450x01D4: 'CLEAR.ROUTING.SLIP',
119460x01D5: 'APP.ACTIVATE.MICROSOFT',
119470x01D6: 'MAIL.EDIT.MAILER',
119480x01D7: 'ON.SHEET',
119490x01D8: 'STANDARD.WIDTH',
119500x01D9: 'SCENARIO.MERGE',
119510x01DA: 'SUMMARY.INFO',
119520x01DB: 'FIND.FILE',
119530x01DC: 'ACTIVE.CELL.FONT',
119540x01DD: 'ENABLE.TIPWIZARD',
119550x01DE: 'VBA.MAKE.ADDIN',
119560x01E0: 'INSERTDATATABLE',
119570x01E1: 'WORKGROUP.OPTIONS',
119580x01E2: 'MAIL.SEND.MAILER',
119590x01E5: 'AUTOCORRECT',
119600x01E9: 'POST.DOCUMENT',
119610x01EB: 'PICKLIST',
119620x01ED: 'VIEW.SHOW',
119630x01EE: 'VIEW.DEFINE',
119640x01EF: 'VIEW.DELETE',
119650x01FD: 'SHEET.BACKGROUND',
119660x01FE: 'INSERT.MAP.OBJECT',
119670x01FF: 'OPTIONS.MENONO',
119680x0205: 'MSOCHECKS',
119690x0206: 'NORMAL',
119700x0207: 'LAYOUT',
119710x0208: 'RM.PRINT.AREA',
119720x0209: 'CLEAR.PRINT.AREA',
119730x020A: 'ADD.PRINT.AREA',
119740x020B: 'MOVE.BRK',
119750x0221: 'HIDECURR.NOTE',
119760x0222: 'HIDEALL.NOTES',
119770x0223: 'DELETE.NOTE',
119780x0224: 'TRAVERSE.NOTES',
119790x0225: 'ACTIVATE.NOTES',
119800x026C: 'PROTECT.REVISIONS',
119810x026D: 'UNPROTECT.REVISIONS',
119820x0287: 'OPTIONS.ME',
119830x028D: 'WEB.PUBLISH',
119840x029B: 'NEWWEBQUERY',
119850x02A1: 'PIVOT.TABLE.CHART',
119860x02F1: 'OPTIONS.SAVE',
119870x02F3: 'OPTIONS.SPELL',
119880x0328: 'HIDEALL.INKANNOTS'
11989};
11990
11991/* [MS-XLS] 2.5.198.17 */
11992/* [MS-XLSB] 2.5.97.10 */
11993var Ftab = {
119940x0000: 'COUNT',
119950x0001: 'IF',
119960x0002: 'ISNA',
119970x0003: 'ISERROR',
119980x0004: 'SUM',
119990x0005: 'AVERAGE',
120000x0006: 'MIN',
120010x0007: 'MAX',
120020x0008: 'ROW',
120030x0009: 'COLUMN',
120040x000A: 'NA',
120050x000B: 'NPV',
120060x000C: 'STDEV',
120070x000D: 'DOLLAR',
120080x000E: 'FIXED',
120090x000F: 'SIN',
120100x0010: 'COS',
120110x0011: 'TAN',
120120x0012: 'ATAN',
120130x0013: 'PI',
120140x0014: 'SQRT',
120150x0015: 'EXP',
120160x0016: 'LN',
120170x0017: 'LOG10',
120180x0018: 'ABS',
120190x0019: 'INT',
120200x001A: 'SIGN',
120210x001B: 'ROUND',
120220x001C: 'LOOKUP',
120230x001D: 'INDEX',
120240x001E: 'REPT',
120250x001F: 'MID',
120260x0020: 'LEN',
120270x0021: 'VALUE',
120280x0022: 'TRUE',
120290x0023: 'FALSE',
120300x0024: 'AND',
120310x0025: 'OR',
120320x0026: 'NOT',
120330x0027: 'MOD',
120340x0028: 'DCOUNT',
120350x0029: 'DSUM',
120360x002A: 'DAVERAGE',
120370x002B: 'DMIN',
120380x002C: 'DMAX',
120390x002D: 'DSTDEV',
120400x002E: 'VAR',
120410x002F: 'DVAR',
120420x0030: 'TEXT',
120430x0031: 'LINEST',
120440x0032: 'TREND',
120450x0033: 'LOGEST',
120460x0034: 'GROWTH',
120470x0035: 'GOTO',
120480x0036: 'HALT',
120490x0037: 'RETURN',
120500x0038: 'PV',
120510x0039: 'FV',
120520x003A: 'NPER',
120530x003B: 'PMT',
120540x003C: 'RATE',
120550x003D: 'MIRR',
120560x003E: 'IRR',
120570x003F: 'RAND',
120580x0040: 'MATCH',
120590x0041: 'DATE',
120600x0042: 'TIME',
120610x0043: 'DAY',
120620x0044: 'MONTH',
120630x0045: 'YEAR',
120640x0046: 'WEEKDAY',
120650x0047: 'HOUR',
120660x0048: 'MINUTE',
120670x0049: 'SECOND',
120680x004A: 'NOW',
120690x004B: 'AREAS',
120700x004C: 'ROWS',
120710x004D: 'COLUMNS',
120720x004E: 'OFFSET',
120730x004F: 'ABSREF',
120740x0050: 'RELREF',
120750x0051: 'ARGUMENT',
120760x0052: 'SEARCH',
120770x0053: 'TRANSPOSE',
120780x0054: 'ERROR',
120790x0055: 'STEP',
120800x0056: 'TYPE',
120810x0057: 'ECHO',
120820x0058: 'SET.NAME',
120830x0059: 'CALLER',
120840x005A: 'DEREF',
120850x005B: 'WINDOWS',
120860x005C: 'SERIES',
120870x005D: 'DOCUMENTS',
120880x005E: 'ACTIVE.CELL',
120890x005F: 'SELECTION',
120900x0060: 'RESULT',
120910x0061: 'ATAN2',
120920x0062: 'ASIN',
120930x0063: 'ACOS',
120940x0064: 'CHOOSE',
120950x0065: 'HLOOKUP',
120960x0066: 'VLOOKUP',
120970x0067: 'LINKS',
120980x0068: 'INPUT',
120990x0069: 'ISREF',
121000x006A: 'GET.FORMULA',
121010x006B: 'GET.NAME',
121020x006C: 'SET.VALUE',
121030x006D: 'LOG',
121040x006E: 'EXEC',
121050x006F: 'CHAR',
121060x0070: 'LOWER',
121070x0071: 'UPPER',
121080x0072: 'PROPER',
121090x0073: 'LEFT',
121100x0074: 'RIGHT',
121110x0075: 'EXACT',
121120x0076: 'TRIM',
121130x0077: 'REPLACE',
121140x0078: 'SUBSTITUTE',
121150x0079: 'CODE',
121160x007A: 'NAMES',
121170x007B: 'DIRECTORY',
121180x007C: 'FIND',
121190x007D: 'CELL',
121200x007E: 'ISERR',
121210x007F: 'ISTEXT',
121220x0080: 'ISNUMBER',
121230x0081: 'ISBLANK',
121240x0082: 'T',
121250x0083: 'N',
121260x0084: 'FOPEN',
121270x0085: 'FCLOSE',
121280x0086: 'FSIZE',
121290x0087: 'FREADLN',
121300x0088: 'FREAD',
121310x0089: 'FWRITELN',
121320x008A: 'FWRITE',
121330x008B: 'FPOS',
121340x008C: 'DATEVALUE',
121350x008D: 'TIMEVALUE',
121360x008E: 'SLN',
121370x008F: 'SYD',
121380x0090: 'DDB',
121390x0091: 'GET.DEF',
121400x0092: 'REFTEXT',
121410x0093: 'TEXTREF',
121420x0094: 'INDIRECT',
121430x0095: 'REGISTER',
121440x0096: 'CALL',
121450x0097: 'ADD.BAR',
121460x0098: 'ADD.MENU',
121470x0099: 'ADD.COMMAND',
121480x009A: 'ENABLE.COMMAND',
121490x009B: 'CHECK.COMMAND',
121500x009C: 'RENAME.COMMAND',
121510x009D: 'SHOW.BAR',
121520x009E: 'DELETE.MENU',
121530x009F: 'DELETE.COMMAND',
121540x00A0: 'GET.CHART.ITEM',
121550x00A1: 'DIALOG.BOX',
121560x00A2: 'CLEAN',
121570x00A3: 'MDETERM',
121580x00A4: 'MINVERSE',
121590x00A5: 'MMULT',
121600x00A6: 'FILES',
121610x00A7: 'IPMT',
121620x00A8: 'PPMT',
121630x00A9: 'COUNTA',
121640x00AA: 'CANCEL.KEY',
121650x00AB: 'FOR',
121660x00AC: 'WHILE',
121670x00AD: 'BREAK',
121680x00AE: 'NEXT',
121690x00AF: 'INITIATE',
121700x00B0: 'REQUEST',
121710x00B1: 'POKE',
121720x00B2: 'EXECUTE',
121730x00B3: 'TERMINATE',
121740x00B4: 'RESTART',
121750x00B5: 'HELP',
121760x00B6: 'GET.BAR',
121770x00B7: 'PRODUCT',
121780x00B8: 'FACT',
121790x00B9: 'GET.CELL',
121800x00BA: 'GET.WORKSPACE',
121810x00BB: 'GET.WINDOW',
121820x00BC: 'GET.DOCUMENT',
121830x00BD: 'DPRODUCT',
121840x00BE: 'ISNONTEXT',
121850x00BF: 'GET.NOTE',
121860x00C0: 'NOTE',
121870x00C1: 'STDEVP',
121880x00C2: 'VARP',
121890x00C3: 'DSTDEVP',
121900x00C4: 'DVARP',
121910x00C5: 'TRUNC',
121920x00C6: 'ISLOGICAL',
121930x00C7: 'DCOUNTA',
121940x00C8: 'DELETE.BAR',
121950x00C9: 'UNREGISTER',
121960x00CC: 'USDOLLAR',
121970x00CD: 'FINDB',
121980x00CE: 'SEARCHB',
121990x00CF: 'REPLACEB',
122000x00D0: 'LEFTB',
122010x00D1: 'RIGHTB',
122020x00D2: 'MIDB',
122030x00D3: 'LENB',
122040x00D4: 'ROUNDUP',
122050x00D5: 'ROUNDDOWN',
122060x00D6: 'ASC',
122070x00D7: 'DBCS',
122080x00D8: 'RANK',
122090x00DB: 'ADDRESS',
122100x00DC: 'DAYS360',
122110x00DD: 'TODAY',
122120x00DE: 'VDB',
122130x00DF: 'ELSE',
122140x00E0: 'ELSE.IF',
122150x00E1: 'END.IF',
122160x00E2: 'FOR.CELL',
122170x00E3: 'MEDIAN',
122180x00E4: 'SUMPRODUCT',
122190x00E5: 'SINH',
122200x00E6: 'COSH',
122210x00E7: 'TANH',
122220x00E8: 'ASINH',
122230x00E9: 'ACOSH',
122240x00EA: 'ATANH',
122250x00EB: 'DGET',
122260x00EC: 'CREATE.OBJECT',
122270x00ED: 'VOLATILE',
122280x00EE: 'LAST.ERROR',
122290x00EF: 'CUSTOM.UNDO',
122300x00F0: 'CUSTOM.REPEAT',
122310x00F1: 'FORMULA.CONVERT',
122320x00F2: 'GET.LINK.INFO',
122330x00F3: 'TEXT.BOX',
122340x00F4: 'INFO',
122350x00F5: 'GROUP',
122360x00F6: 'GET.OBJECT',
122370x00F7: 'DB',
122380x00F8: 'PAUSE',
122390x00FB: 'RESUME',
122400x00FC: 'FREQUENCY',
122410x00FD: 'ADD.TOOLBAR',
122420x00FE: 'DELETE.TOOLBAR',
122430x00FF: 'User',
122440x0100: 'RESET.TOOLBAR',
122450x0101: 'EVALUATE',
122460x0102: 'GET.TOOLBAR',
122470x0103: 'GET.TOOL',
122480x0104: 'SPELLING.CHECK',
122490x0105: 'ERROR.TYPE',
122500x0106: 'APP.TITLE',
122510x0107: 'WINDOW.TITLE',
122520x0108: 'SAVE.TOOLBAR',
122530x0109: 'ENABLE.TOOL',
122540x010A: 'PRESS.TOOL',
122550x010B: 'REGISTER.ID',
122560x010C: 'GET.WORKBOOK',
122570x010D: 'AVEDEV',
122580x010E: 'BETADIST',
122590x010F: 'GAMMALN',
122600x0110: 'BETAINV',
122610x0111: 'BINOMDIST',
122620x0112: 'CHIDIST',
122630x0113: 'CHIINV',
122640x0114: 'COMBIN',
122650x0115: 'CONFIDENCE',
122660x0116: 'CRITBINOM',
122670x0117: 'EVEN',
122680x0118: 'EXPONDIST',
122690x0119: 'FDIST',
122700x011A: 'FINV',
122710x011B: 'FISHER',
122720x011C: 'FISHERINV',
122730x011D: 'FLOOR',
122740x011E: 'GAMMADIST',
122750x011F: 'GAMMAINV',
122760x0120: 'CEILING',
122770x0121: 'HYPGEOMDIST',
122780x0122: 'LOGNORMDIST',
122790x0123: 'LOGINV',
122800x0124: 'NEGBINOMDIST',
122810x0125: 'NORMDIST',
122820x0126: 'NORMSDIST',
122830x0127: 'NORMINV',
122840x0128: 'NORMSINV',
122850x0129: 'STANDARDIZE',
122860x012A: 'ODD',
122870x012B: 'PERMUT',
122880x012C: 'POISSON',
122890x012D: 'TDIST',
122900x012E: 'WEIBULL',
122910x012F: 'SUMXMY2',
122920x0130: 'SUMX2MY2',
122930x0131: 'SUMX2PY2',
122940x0132: 'CHITEST',
122950x0133: 'CORREL',
122960x0134: 'COVAR',
122970x0135: 'FORECAST',
122980x0136: 'FTEST',
122990x0137: 'INTERCEPT',
123000x0138: 'PEARSON',
123010x0139: 'RSQ',
123020x013A: 'STEYX',
123030x013B: 'SLOPE',
123040x013C: 'TTEST',
123050x013D: 'PROB',
123060x013E: 'DEVSQ',
123070x013F: 'GEOMEAN',
123080x0140: 'HARMEAN',
123090x0141: 'SUMSQ',
123100x0142: 'KURT',
123110x0143: 'SKEW',
123120x0144: 'ZTEST',
123130x0145: 'LARGE',
123140x0146: 'SMALL',
123150x0147: 'QUARTILE',
123160x0148: 'PERCENTILE',
123170x0149: 'PERCENTRANK',
123180x014A: 'MODE',
123190x014B: 'TRIMMEAN',
123200x014C: 'TINV',
123210x014E: 'MOVIE.COMMAND',
123220x014F: 'GET.MOVIE',
123230x0150: 'CONCATENATE',
123240x0151: 'POWER',
123250x0152: 'PIVOT.ADD.DATA',
123260x0153: 'GET.PIVOT.TABLE',
123270x0154: 'GET.PIVOT.FIELD',
123280x0155: 'GET.PIVOT.ITEM',
123290x0156: 'RADIANS',
123300x0157: 'DEGREES',
123310x0158: 'SUBTOTAL',
123320x0159: 'SUMIF',
123330x015A: 'COUNTIF',
123340x015B: 'COUNTBLANK',
123350x015C: 'SCENARIO.GET',
123360x015D: 'OPTIONS.LISTS.GET',
123370x015E: 'ISPMT',
123380x015F: 'DATEDIF',
123390x0160: 'DATESTRING',
123400x0161: 'NUMBERSTRING',
123410x0162: 'ROMAN',
123420x0163: 'OPEN.DIALOG',
123430x0164: 'SAVE.DIALOG',
123440x0165: 'VIEW.GET',
123450x0166: 'GETPIVOTDATA',
123460x0167: 'HYPERLINK',
123470x0168: 'PHONETIC',
123480x0169: 'AVERAGEA',
123490x016A: 'MAXA',
123500x016B: 'MINA',
123510x016C: 'STDEVPA',
123520x016D: 'VARPA',
123530x016E: 'STDEVA',
123540x016F: 'VARA',
123550x0170: 'BAHTTEXT',
123560x0171: 'THAIDAYOFWEEK',
123570x0172: 'THAIDIGIT',
123580x0173: 'THAIMONTHOFYEAR',
123590x0174: 'THAINUMSOUND',
123600x0175: 'THAINUMSTRING',
123610x0176: 'THAISTRINGLENGTH',
123620x0177: 'ISTHAIDIGIT',
123630x0178: 'ROUNDBAHTDOWN',
123640x0179: 'ROUNDBAHTUP',
123650x017A: 'THAIYEAR',
123660x017B: 'RTD',
12367
123680x017C: 'CUBEVALUE',
123690x017D: 'CUBEMEMBER',
123700x017E: 'CUBEMEMBERPROPERTY',
123710x017F: 'CUBERANKEDMEMBER',
123720x0180: 'HEX2BIN',
123730x0181: 'HEX2DEC',
123740x0182: 'HEX2OCT',
123750x0183: 'DEC2BIN',
123760x0184: 'DEC2HEX',
123770x0185: 'DEC2OCT',
123780x0186: 'OCT2BIN',
123790x0187: 'OCT2HEX',
123800x0188: 'OCT2DEC',
123810x0189: 'BIN2DEC',
123820x018A: 'BIN2OCT',
123830x018B: 'BIN2HEX',
123840x018C: 'IMSUB',
123850x018D: 'IMDIV',
123860x018E: 'IMPOWER',
123870x018F: 'IMABS',
123880x0190: 'IMSQRT',
123890x0191: 'IMLN',
123900x0192: 'IMLOG2',
123910x0193: 'IMLOG10',
123920x0194: 'IMSIN',
123930x0195: 'IMCOS',
123940x0196: 'IMEXP',
123950x0197: 'IMARGUMENT',
123960x0198: 'IMCONJUGATE',
123970x0199: 'IMAGINARY',
123980x019A: 'IMREAL',
123990x019B: 'COMPLEX',
124000x019C: 'IMSUM',
124010x019D: 'IMPRODUCT',
124020x019E: 'SERIESSUM',
124030x019F: 'FACTDOUBLE',
124040x01A0: 'SQRTPI',
124050x01A1: 'QUOTIENT',
124060x01A2: 'DELTA',
124070x01A3: 'GESTEP',
124080x01A4: 'ISEVEN',
124090x01A5: 'ISODD',
124100x01A6: 'MROUND',
124110x01A7: 'ERF',
124120x01A8: 'ERFC',
124130x01A9: 'BESSELJ',
124140x01AA: 'BESSELK',
124150x01AB: 'BESSELY',
124160x01AC: 'BESSELI',
124170x01AD: 'XIRR',
124180x01AE: 'XNPV',
124190x01AF: 'PRICEMAT',
124200x01B0: 'YIELDMAT',
124210x01B1: 'INTRATE',
124220x01B2: 'RECEIVED',
124230x01B3: 'DISC',
124240x01B4: 'PRICEDISC',
124250x01B5: 'YIELDDISC',
124260x01B6: 'TBILLEQ',
124270x01B7: 'TBILLPRICE',
124280x01B8: 'TBILLYIELD',
124290x01B9: 'PRICE',
124300x01BA: 'YIELD',
124310x01BB: 'DOLLARDE',
124320x01BC: 'DOLLARFR',
124330x01BD: 'NOMINAL',
124340x01BE: 'EFFECT',
124350x01BF: 'CUMPRINC',
124360x01C0: 'CUMIPMT',
124370x01C1: 'EDATE',
124380x01C2: 'EOMONTH',
124390x01C3: 'YEARFRAC',
124400x01C4: 'COUPDAYBS',
124410x01C5: 'COUPDAYS',
124420x01C6: 'COUPDAYSNC',
124430x01C7: 'COUPNCD',
124440x01C8: 'COUPNUM',
124450x01C9: 'COUPPCD',
124460x01CA: 'DURATION',
124470x01CB: 'MDURATION',
124480x01CC: 'ODDLPRICE',
124490x01CD: 'ODDLYIELD',
124500x01CE: 'ODDFPRICE',
124510x01CF: 'ODDFYIELD',
124520x01D0: 'RANDBETWEEN',
124530x01D1: 'WEEKNUM',
124540x01D2: 'AMORDEGRC',
124550x01D3: 'AMORLINC',
124560x01D4: 'CONVERT',
124570x02D4: 'SHEETJS',
124580x01D5: 'ACCRINT',
124590x01D6: 'ACCRINTM',
124600x01D7: 'WORKDAY',
124610x01D8: 'NETWORKDAYS',
124620x01D9: 'GCD',
124630x01DA: 'MULTINOMIAL',
124640x01DB: 'LCM',
124650x01DC: 'FVSCHEDULE',
124660x01DD: 'CUBEKPIMEMBER',
124670x01DE: 'CUBESET',
124680x01DF: 'CUBESETCOUNT',
124690x01E0: 'IFERROR',
124700x01E1: 'COUNTIFS',
124710x01E2: 'SUMIFS',
124720x01E3: 'AVERAGEIF',
124730x01E4: 'AVERAGEIFS'
12474};
12475var FtabArgc = {
124760x0002: 1, /* ISNA */
124770x0003: 1, /* ISERROR */
124780x000A: 0, /* NA */
124790x000F: 1, /* SIN */
124800x0010: 1, /* COS */
124810x0011: 1, /* TAN */
124820x0012: 1, /* ATAN */
124830x0013: 0, /* PI */
124840x0014: 1, /* SQRT */
124850x0015: 1, /* EXP */
124860x0016: 1, /* LN */
124870x0017: 1, /* LOG10 */
124880x0018: 1, /* ABS */
124890x0019: 1, /* INT */
124900x001A: 1, /* SIGN */
124910x001B: 2, /* ROUND */
124920x001E: 2, /* REPT */
124930x001F: 3, /* MID */
124940x0020: 1, /* LEN */
124950x0021: 1, /* VALUE */
124960x0022: 0, /* TRUE */
124970x0023: 0, /* FALSE */
124980x0026: 1, /* NOT */
124990x0027: 2, /* MOD */
125000x0028: 3, /* DCOUNT */
125010x0029: 3, /* DSUM */
125020x002A: 3, /* DAVERAGE */
125030x002B: 3, /* DMIN */
125040x002C: 3, /* DMAX */
125050x002D: 3, /* DSTDEV */
125060x002F: 3, /* DVAR */
125070x0030: 2, /* TEXT */
125080x0035: 1, /* GOTO */
125090x003D: 3, /* MIRR */
125100x003F: 0, /* RAND */
125110x0041: 3, /* DATE */
125120x0042: 3, /* TIME */
125130x0043: 1, /* DAY */
125140x0044: 1, /* MONTH */
125150x0045: 1, /* YEAR */
125160x0046: 1, /* WEEKDAY */
125170x0047: 1, /* HOUR */
125180x0048: 1, /* MINUTE */
125190x0049: 1, /* SECOND */
125200x004A: 0, /* NOW */
125210x004B: 1, /* AREAS */
125220x004C: 1, /* ROWS */
125230x004D: 1, /* COLUMNS */
125240x004F: 2, /* ABSREF */
125250x0050: 2, /* RELREF */
125260x0053: 1, /* TRANSPOSE */
125270x0055: 0, /* STEP */
125280x0056: 1, /* TYPE */
125290x0059: 0, /* CALLER */
125300x005A: 1, /* DEREF */
125310x005E: 0, /* ACTIVE.CELL */
125320x005F: 0, /* SELECTION */
125330x0061: 2, /* ATAN2 */
125340x0062: 1, /* ASIN */
125350x0063: 1, /* ACOS */
125360x0065: 3, /* HLOOKUP */
125370x0066: 3, /* VLOOKUP */
125380x0069: 1, /* ISREF */
125390x006A: 1, /* GET.FORMULA */
125400x006C: 2, /* SET.VALUE */
125410x006F: 1, /* CHAR */
125420x0070: 1, /* LOWER */
125430x0071: 1, /* UPPER */
125440x0072: 1, /* PROPER */
125450x0075: 2, /* EXACT */
125460x0076: 1, /* TRIM */
125470x0077: 4, /* REPLACE */
125480x0079: 1, /* CODE */
125490x007E: 1, /* ISERR */
125500x007F: 1, /* ISTEXT */
125510x0080: 1, /* ISNUMBER */
125520x0081: 1, /* ISBLANK */
125530x0082: 1, /* T */
125540x0083: 1, /* N */
125550x0085: 1, /* FCLOSE */
125560x0086: 1, /* FSIZE */
125570x0087: 1, /* FREADLN */
125580x0088: 2, /* FREAD */
125590x0089: 2, /* FWRITELN */
125600x008A: 2, /* FWRITE */
125610x008C: 1, /* DATEVALUE */
125620x008D: 1, /* TIMEVALUE */
125630x008E: 3, /* SLN */
125640x008F: 4, /* SYD */
125650x0090: 4, /* DDB */
125660x00A1: 1, /* DIALOG.BOX */
125670x00A2: 1, /* CLEAN */
125680x00A3: 1, /* MDETERM */
125690x00A4: 1, /* MINVERSE */
125700x00A5: 2, /* MMULT */
125710x00AC: 1, /* WHILE */
125720x00AF: 2, /* INITIATE */
125730x00B0: 2, /* REQUEST */
125740x00B1: 3, /* POKE */
125750x00B2: 2, /* EXECUTE */
125760x00B3: 1, /* TERMINATE */
125770x00B8: 1, /* FACT */
125780x00BA: 1, /* GET.WORKSPACE */
125790x00BD: 3, /* DPRODUCT */
125800x00BE: 1, /* ISNONTEXT */
125810x00C3: 3, /* DSTDEVP */
125820x00C4: 3, /* DVARP */
125830x00C5: 1, /* TRUNC */
125840x00C6: 1, /* ISLOGICAL */
125850x00C7: 3, /* DCOUNTA */
125860x00C9: 1, /* UNREGISTER */
125870x00CF: 4, /* REPLACEB */
125880x00D2: 3, /* MIDB */
125890x00D3: 1, /* LENB */
125900x00D4: 2, /* ROUNDUP */
125910x00D5: 2, /* ROUNDDOWN */
125920x00D6: 1, /* ASC */
125930x00D7: 1, /* DBCS */
125940x00E1: 0, /* END.IF */
125950x00E5: 1, /* SINH */
125960x00E6: 1, /* COSH */
125970x00E7: 1, /* TANH */
125980x00E8: 1, /* ASINH */
125990x00E9: 1, /* ACOSH */
126000x00EA: 1, /* ATANH */
126010x00EB: 3, /* DGET */
126020x00F4: 1, /* INFO */
126030x00F7: 4, /* DB */
126040x00FC: 2, /* FREQUENCY */
126050x0101: 1, /* EVALUATE */
126060x0105: 1, /* ERROR.TYPE */
126070x010F: 1, /* GAMMALN */
126080x0111: 4, /* BINOMDIST */
126090x0112: 2, /* CHIDIST */
126100x0113: 2, /* CHIINV */
126110x0114: 2, /* COMBIN */
126120x0115: 3, /* CONFIDENCE */
126130x0116: 3, /* CRITBINOM */
126140x0117: 1, /* EVEN */
126150x0118: 3, /* EXPONDIST */
126160x0119: 3, /* FDIST */
126170x011A: 3, /* FINV */
126180x011B: 1, /* FISHER */
126190x011C: 1, /* FISHERINV */
126200x011D: 2, /* FLOOR */
126210x011E: 4, /* GAMMADIST */
126220x011F: 3, /* GAMMAINV */
126230x0120: 2, /* CEILING */
126240x0121: 4, /* HYPGEOMDIST */
126250x0122: 3, /* LOGNORMDIST */
126260x0123: 3, /* LOGINV */
126270x0124: 3, /* NEGBINOMDIST */
126280x0125: 4, /* NORMDIST */
126290x0126: 1, /* NORMSDIST */
126300x0127: 3, /* NORMINV */
126310x0128: 1, /* NORMSINV */
126320x0129: 3, /* STANDARDIZE */
126330x012A: 1, /* ODD */
126340x012B: 2, /* PERMUT */
126350x012C: 3, /* POISSON */
126360x012D: 3, /* TDIST */
126370x012E: 4, /* WEIBULL */
126380x012F: 2, /* SUMXMY2 */
126390x0130: 2, /* SUMX2MY2 */
126400x0131: 2, /* SUMX2PY2 */
126410x0132: 2, /* CHITEST */
126420x0133: 2, /* CORREL */
126430x0134: 2, /* COVAR */
126440x0135: 3, /* FORECAST */
126450x0136: 2, /* FTEST */
126460x0137: 2, /* INTERCEPT */
126470x0138: 2, /* PEARSON */
126480x0139: 2, /* RSQ */
126490x013A: 2, /* STEYX */
126500x013B: 2, /* SLOPE */
126510x013C: 4, /* TTEST */
126520x0145: 2, /* LARGE */
126530x0146: 2, /* SMALL */
126540x0147: 2, /* QUARTILE */
126550x0148: 2, /* PERCENTILE */
126560x014B: 2, /* TRIMMEAN */
126570x014C: 2, /* TINV */
126580x0151: 2, /* POWER */
126590x0156: 1, /* RADIANS */
126600x0157: 1, /* DEGREES */
126610x015A: 2, /* COUNTIF */
126620x015B: 1, /* COUNTBLANK */
126630x015E: 4, /* ISPMT */
126640x015F: 3, /* DATEDIF */
126650x0160: 1, /* DATESTRING */
126660x0161: 2, /* NUMBERSTRING */
126670x0168: 1, /* PHONETIC */
126680x0170: 1, /* BAHTTEXT */
126690x0171: 1, /* THAIDAYOFWEEK */
126700x0172: 1, /* THAIDIGIT */
126710x0173: 1, /* THAIMONTHOFYEAR */
126720x0174: 1, /* THAINUMSOUND */
126730x0175: 1, /* THAINUMSTRING */
126740x0176: 1, /* THAISTRINGLENGTH */
126750x0177: 1, /* ISTHAIDIGIT */
126760x0178: 1, /* ROUNDBAHTDOWN */
126770x0179: 1, /* ROUNDBAHTUP */
126780x017A: 1, /* THAIYEAR */
126790x017E: 3, /* CUBEMEMBERPROPERTY */
126800x0181: 1, /* HEX2DEC */
126810x0188: 1, /* OCT2DEC */
126820x0189: 1, /* BIN2DEC */
126830x018C: 2, /* IMSUB */
126840x018D: 2, /* IMDIV */
126850x018E: 2, /* IMPOWER */
126860x018F: 1, /* IMABS */
126870x0190: 1, /* IMSQRT */
126880x0191: 1, /* IMLN */
126890x0192: 1, /* IMLOG2 */
126900x0193: 1, /* IMLOG10 */
126910x0194: 1, /* IMSIN */
126920x0195: 1, /* IMCOS */
126930x0196: 1, /* IMEXP */
126940x0197: 1, /* IMARGUMENT */
126950x0198: 1, /* IMCONJUGATE */
126960x0199: 1, /* IMAGINARY */
126970x019A: 1, /* IMREAL */
126980x019E: 4, /* SERIESSUM */
126990x019F: 1, /* FACTDOUBLE */
127000x01A0: 1, /* SQRTPI */
127010x01A1: 2, /* QUOTIENT */
127020x01A4: 1, /* ISEVEN */
127030x01A5: 1, /* ISODD */
127040x01A6: 2, /* MROUND */
127050x01A8: 1, /* ERFC */
127060x01A9: 2, /* BESSELJ */
127070x01AA: 2, /* BESSELK */
127080x01AB: 2, /* BESSELY */
127090x01AC: 2, /* BESSELI */
127100x01AE: 3, /* XNPV */
127110x01B6: 3, /* TBILLEQ */
127120x01B7: 3, /* TBILLPRICE */
127130x01B8: 3, /* TBILLYIELD */
127140x01BB: 2, /* DOLLARDE */
127150x01BC: 2, /* DOLLARFR */
127160x01BD: 2, /* NOMINAL */
127170x01BE: 2, /* EFFECT */
127180x01BF: 6, /* CUMPRINC */
127190x01C0: 6, /* CUMIPMT */
127200x01C1: 2, /* EDATE */
127210x01C2: 2, /* EOMONTH */
127220x01D0: 2, /* RANDBETWEEN */
127230x01D4: 3, /* CONVERT */
127240x01DC: 2, /* FVSCHEDULE */
127250x01DF: 1, /* CUBESETCOUNT */
127260x01E0: 2, /* IFERROR */
127270xFFFF: 0
12728};
12729/* [MS-XLSX] 2.2.3 Functions */
12730/* [MS-XLSB] 2.5.97.10 Ftab */
12731var XLSXFutureFunctions = {
12732 "_xlfn.ACOT": "ACOT",
12733 "_xlfn.ACOTH": "ACOTH",
12734 "_xlfn.AGGREGATE": "AGGREGATE",
12735 "_xlfn.ARABIC": "ARABIC",
12736 "_xlfn.AVERAGEIF": "AVERAGEIF",
12737 "_xlfn.AVERAGEIFS": "AVERAGEIFS",
12738 "_xlfn.BASE": "BASE",
12739 "_xlfn.BETA.DIST": "BETA.DIST",
12740 "_xlfn.BETA.INV": "BETA.INV",
12741 "_xlfn.BINOM.DIST": "BINOM.DIST",
12742 "_xlfn.BINOM.DIST.RANGE": "BINOM.DIST.RANGE",
12743 "_xlfn.BINOM.INV": "BINOM.INV",
12744 "_xlfn.BITAND": "BITAND",
12745 "_xlfn.BITLSHIFT": "BITLSHIFT",
12746 "_xlfn.BITOR": "BITOR",
12747 "_xlfn.BITRSHIFT": "BITRSHIFT",
12748 "_xlfn.BITXOR": "BITXOR",
12749 "_xlfn.CEILING.MATH": "CEILING.MATH",
12750 "_xlfn.CEILING.PRECISE": "CEILING.PRECISE",
12751 "_xlfn.CHISQ.DIST": "CHISQ.DIST",
12752 "_xlfn.CHISQ.DIST.RT": "CHISQ.DIST.RT",
12753 "_xlfn.CHISQ.INV": "CHISQ.INV",
12754 "_xlfn.CHISQ.INV.RT": "CHISQ.INV.RT",
12755 "_xlfn.CHISQ.TEST": "CHISQ.TEST",
12756 "_xlfn.COMBINA": "COMBINA",
12757 "_xlfn.CONCAT": "CONCAT",
12758 "_xlfn.CONFIDENCE.NORM": "CONFIDENCE.NORM",
12759 "_xlfn.CONFIDENCE.T": "CONFIDENCE.T",
12760 "_xlfn.COT": "COT",
12761 "_xlfn.COTH": "COTH",
12762 "_xlfn.COUNTIFS": "COUNTIFS",
12763 "_xlfn.COVARIANCE.P": "COVARIANCE.P",
12764 "_xlfn.COVARIANCE.S": "COVARIANCE.S",
12765 "_xlfn.CSC": "CSC",
12766 "_xlfn.CSCH": "CSCH",
12767 "_xlfn.DAYS": "DAYS",
12768 "_xlfn.DECIMAL": "DECIMAL",
12769 "_xlfn.ECMA.CEILING": "ECMA.CEILING",
12770 "_xlfn.ERF.PRECISE": "ERF.PRECISE",
12771 "_xlfn.ERFC.PRECISE": "ERFC.PRECISE",
12772 "_xlfn.EXPON.DIST": "EXPON.DIST",
12773 "_xlfn.F.DIST": "F.DIST",
12774 "_xlfn.F.DIST.RT": "F.DIST.RT",
12775 "_xlfn.F.INV": "F.INV",
12776 "_xlfn.F.INV.RT": "F.INV.RT",
12777 "_xlfn.F.TEST": "F.TEST",
12778 "_xlfn.FILTERXML": "FILTERXML",
12779 "_xlfn.FLOOR.MATH": "FLOOR.MATH",
12780 "_xlfn.FLOOR.PRECISE": "FLOOR.PRECISE",
12781 "_xlfn.FORECAST.ETS": "FORECAST.ETS",
12782 "_xlfn.FORECAST.ETS.CONFINT": "FORECAST.ETS.CONFINT",
12783 "_xlfn.FORECAST.ETS.SEASONALITY": "FORECAST.ETS.SEASONALITY",
12784 "_xlfn.FORECAST.ETS.STAT": "FORECAST.ETS.STAT",
12785 "_xlfn.FORECAST.LINEAR": "FORECAST.LINEAR",
12786 "_xlfn.FORMULATEXT": "FORMULATEXT",
12787 "_xlfn.GAMMA": "GAMMA",
12788 "_xlfn.GAMMA.DIST": "GAMMA.DIST",
12789 "_xlfn.GAMMA.INV": "GAMMA.INV",
12790 "_xlfn.GAMMALN.PRECISE": "GAMMALN.PRECISE",
12791 "_xlfn.GAUSS": "GAUSS",
12792 "_xlfn.HYPGEOM.DIST": "HYPGEOM.DIST",
12793 "_xlfn.IFERROR": "IFERROR",
12794 "_xlfn.IFNA": "IFNA",
12795 "_xlfn.IFS": "IFS",
12796 "_xlfn.IMCOSH": "IMCOSH",
12797 "_xlfn.IMCOT": "IMCOT",
12798 "_xlfn.IMCSC": "IMCSC",
12799 "_xlfn.IMCSCH": "IMCSCH",
12800 "_xlfn.IMSEC": "IMSEC",
12801 "_xlfn.IMSECH": "IMSECH",
12802 "_xlfn.IMSINH": "IMSINH",
12803 "_xlfn.IMTAN": "IMTAN",
12804 "_xlfn.ISFORMULA": "ISFORMULA",
12805 "_xlfn.ISO.CEILING": "ISO.CEILING",
12806 "_xlfn.ISOWEEKNUM": "ISOWEEKNUM",
12807 "_xlfn.LOGNORM.DIST": "LOGNORM.DIST",
12808 "_xlfn.LOGNORM.INV": "LOGNORM.INV",
12809 "_xlfn.MAXIFS": "MAXIFS",
12810 "_xlfn.MINIFS": "MINIFS",
12811 "_xlfn.MODE.MULT": "MODE.MULT",
12812 "_xlfn.MODE.SNGL": "MODE.SNGL",
12813 "_xlfn.MUNIT": "MUNIT",
12814 "_xlfn.NEGBINOM.DIST": "NEGBINOM.DIST",
12815 "_xlfn.NETWORKDAYS.INTL": "NETWORKDAYS.INTL",
12816 "_xlfn.NIGBINOM": "NIGBINOM",
12817 "_xlfn.NORM.DIST": "NORM.DIST",
12818 "_xlfn.NORM.INV": "NORM.INV",
12819 "_xlfn.NORM.S.DIST": "NORM.S.DIST",
12820 "_xlfn.NORM.S.INV": "NORM.S.INV",
12821 "_xlfn.NUMBERVALUE": "NUMBERVALUE",
12822 "_xlfn.PDURATION": "PDURATION",
12823 "_xlfn.PERCENTILE.EXC": "PERCENTILE.EXC",
12824 "_xlfn.PERCENTILE.INC": "PERCENTILE.INC",
12825 "_xlfn.PERCENTRANK.EXC": "PERCENTRANK.EXC",
12826 "_xlfn.PERCENTRANK.INC": "PERCENTRANK.INC",
12827 "_xlfn.PERMUTATIONA": "PERMUTATIONA",
12828 "_xlfn.PHI": "PHI",
12829 "_xlfn.POISSON.DIST": "POISSON.DIST",
12830 "_xlfn.QUARTILE.EXC": "QUARTILE.EXC",
12831 "_xlfn.QUARTILE.INC": "QUARTILE.INC",
12832 "_xlfn.QUERYSTRING": "QUERYSTRING",
12833 "_xlfn.RANK.AVG": "RANK.AVG",
12834 "_xlfn.RANK.EQ": "RANK.EQ",
12835 "_xlfn.RRI": "RRI",
12836 "_xlfn.SEC": "SEC",
12837 "_xlfn.SECH": "SECH",
12838 "_xlfn.SHEET": "SHEET",
12839 "_xlfn.SHEETS": "SHEETS",
12840 "_xlfn.SKEW.P": "SKEW.P",
12841 "_xlfn.STDEV.P": "STDEV.P",
12842 "_xlfn.STDEV.S": "STDEV.S",
12843 "_xlfn.SUMIFS": "SUMIFS",
12844 "_xlfn.SWITCH": "SWITCH",
12845 "_xlfn.T.DIST": "T.DIST",
12846 "_xlfn.T.DIST.2T": "T.DIST.2T",
12847 "_xlfn.T.DIST.RT": "T.DIST.RT",
12848 "_xlfn.T.INV": "T.INV",
12849 "_xlfn.T.INV.2T": "T.INV.2T",
12850 "_xlfn.T.TEST": "T.TEST",
12851 "_xlfn.TEXTJOIN": "TEXTJOIN",
12852 "_xlfn.UNICHAR": "UNICHAR",
12853 "_xlfn.UNICODE": "UNICODE",
12854 "_xlfn.VAR.P": "VAR.P",
12855 "_xlfn.VAR.S": "VAR.S",
12856 "_xlfn.WEBSERVICE": "WEBSERVICE",
12857 "_xlfn.WEIBULL.DIST": "WEIBULL.DIST",
12858 "_xlfn.WORKDAY.INTL": "WORKDAY.INTL",
12859 "_xlfn.XOR": "XOR",
12860 "_xlfn.Z.TEST": "Z.TEST"
12861};
12862
12863/* Part 3 TODO: actually parse formulae */
12864function ods_to_csf_formula(f) {
12865 if(f.slice(0,3) == "of:") f = f.slice(3);
12866 /* 5.2 Basic Expressions */
12867 if(f.charCodeAt(0) == 61) {
12868 f = f.slice(1);
12869 if(f.charCodeAt(0) == 61) f = f.slice(1);
12870 }
12871 f = f.replace(/COM\.MICROSOFT\./g, "");
12872 /* Part 3 Section 5.8 References */
12873 f = f.replace(/\[((?:\.[A-Z]+[0-9]+)(?::\.[A-Z]+[0-9]+)?)\]/g, function($$, $1) { return $1.replace(/\./g,""); });
12874 /* TODO: something other than this */
12875 f = f.replace(/\[.(#[A-Z]*[?!])\]/g, "$1");
12876 return f.replace(/[;~]/g,",").replace(/\|/g,";");
12877}
12878
12879function csf_to_ods_formula(f) {
12880 var o = "of:=" + f.replace(crefregex, "$1[.$2$3$4$5]").replace(/\]:\[/g,":");
12881 /* TODO: something other than this */
12882 return o.replace(/;/g, "|").replace(/,/g,";");
12883}
12884
12885function ods_to_csf_3D(r) {
12886 var a = r.split(":");
12887 var s = a[0].split(".")[0];
12888 return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
12889}
12890
12891function csf_to_ods_3D(r) {
12892 return r.replace(/\./,"!");
12893}
12894
12895var strs = {}; // shared strings
12896var _ssfopts = {}; // spreadsheet formatting options
12897
12898RELS.WS = [
12899 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
12900 "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
12901];
12902
12903/*global Map */
12904var browser_has_Map = typeof Map !== 'undefined';
12905
12906function get_sst_id(sst, str, rev) {
12907 var i = 0, len = sst.length;
12908 if(rev) {
12909 if(browser_has_Map ? rev.has(str) : Object.prototype.hasOwnProperty.call(rev, str)) {
12910 var revarr = browser_has_Map ? rev.get(str) : rev[str];
12911 for(; i < revarr.length; ++i) {
12912 if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
12913 }
12914 }
12915 } else for(; i < len; ++i) {
12916 if(sst[i].t === str) { sst.Count ++; return i; }
12917 }
12918 sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
12919 if(rev) {
12920 if(browser_has_Map) {
12921 if(!rev.has(str)) rev.set(str, []);
12922 rev.get(str).push(len);
12923 } else {
12924 if(!Object.prototype.hasOwnProperty.call(rev, str)) rev[str] = [];
12925 rev[str].push(len);
12926 }
12927 }
12928 return len;
12929}
12930
12931function col_obj_w(C, col) {
12932 var p = ({min:C+1,max:C+1});
12933 /* wch (chars), wpx (pixels) */
12934 var wch = -1;
12935 if(col.MDW) MDW = col.MDW;
12936 if(col.width != null) p.customWidth = 1;
12937 else if(col.wpx != null) wch = px2char(col.wpx);
12938 else if(col.wch != null) wch = col.wch;
12939 if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
12940 else if(col.width != null) p.width = col.width;
12941 if(col.hidden) p.hidden = true;
12942 return p;
12943}
12944
12945function default_margins(margins, mode) {
12946 if(!margins) return;
12947 var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
12948 if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
12949 if(margins.left == null) margins.left = defs[0];
12950 if(margins.right == null) margins.right = defs[1];
12951 if(margins.top == null) margins.top = defs[2];
12952 if(margins.bottom == null) margins.bottom = defs[3];
12953 if(margins.header == null) margins.header = defs[4];
12954 if(margins.footer == null) margins.footer = defs[5];
12955}
12956
12957function get_cell_style(styles, cell, opts) {
12958 var z = opts.revssf[cell.z != null ? cell.z : "General"];
12959 var i = 0x3c, len = styles.length;
12960 if(z == null && opts.ssf) {
12961 for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
12962 SSF.load(cell.z, i);
12963 // $FlowIgnore
12964 opts.ssf[i] = cell.z;
12965 opts.revssf[cell.z] = z = i;
12966 break;
12967 }
12968 }
12969 for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
12970 styles[len] = {
12971 numFmtId:z,
12972 fontId:0,
12973 fillId:0,
12974 borderId:0,
12975 xfId:0,
12976 applyNumberFormat:1
12977 };
12978 return len;
12979}
12980
12981function safe_format(p, fmtid, fillid, opts, themes, styles) {
12982 try {
12983 if(opts.cellNF) p.z = SSF._table[fmtid];
12984 } catch(e) { if(opts.WTF) throw e; }
12985 if(p.t === 'z') return;
12986 if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
12987 if(!opts || opts.cellText !== false) try {
12988 if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
12989 if(p.t === 'e') p.w = p.w || BErr[p.v];
12990 else if(fmtid === 0) {
12991 if(p.t === 'n') {
12992 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
12993 else p.w = SSF._general_num(p.v);
12994 }
12995 else if(p.t === 'd') {
12996 var dd = datenum(p.v);
12997 if((dd|0) === dd) p.w = SSF._general_int(dd);
12998 else p.w = SSF._general_num(dd);
12999 }
13000 else if(p.v === undefined) return "";
13001 else p.w = SSF._general(p.v,_ssfopts);
13002 }
13003 else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
13004 else p.w = SSF.format(fmtid,p.v,_ssfopts);
13005 } catch(e) { if(opts.WTF) throw e; }
13006 if(!opts.cellStyles) return;
13007 if(fillid != null) try {
13008 p.s = styles.Fills[fillid];
13009 if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
13010 p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
13011 if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
13012 }
13013 if (p.s.bgColor && p.s.bgColor.theme) {
13014 p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
13015 if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
13016 }
13017 } catch(e) { if(opts.WTF && styles.Fills) throw e; }
13018}
13019
13020function check_ws(ws, sname, i) {
13021 if(ws && ws['!ref']) {
13022 var range = safe_decode_range(ws['!ref']);
13023 if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
13024 }
13025}
13026function parse_ws_xml_dim(ws, s) {
13027 var d = safe_decode_range(s);
13028 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);
13029}
13030var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
13031var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
13032var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
13033var dimregex = /"(\w*:\w*)"/;
13034var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
13035var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
13036var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
13037var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
13038var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
13039
13040/* 18.3 Worksheets */
13041function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
13042 if(!data) return data;
13043 if(!rels) rels = {'!id':{}};
13044 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
13045
13046 /* 18.3.1.99 worksheet CT_Worksheet */
13047 var s = opts.dense ? ([]) : ({});
13048 var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
13049
13050 var data1 = "", data2 = "";
13051 var mtch = data.match(sheetdataregex);
13052 if(mtch) {
13053 data1 = data.slice(0, mtch.index);
13054 data2 = data.slice(mtch.index + mtch[0].length);
13055 } else data1 = data2 = data;
13056
13057 /* 18.3.1.82 sheetPr CT_SheetPr */
13058 var sheetPr = data1.match(sheetprregex);
13059 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
13060
13061 /* 18.3.1.35 dimension CT_SheetDimension */
13062 var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
13063 if(ridx > 0) {
13064 var ref = data1.slice(ridx,ridx+50).match(dimregex);
13065 if(ref) parse_ws_xml_dim(s, ref[1]);
13066 }
13067
13068 /* 18.3.1.88 sheetViews CT_SheetViews */
13069 var svs = data1.match(svsregex);
13070 if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
13071
13072 /* 18.3.1.17 cols CT_Cols */
13073 var columns = [];
13074 if(opts.cellStyles) {
13075 /* 18.3.1.13 col CT_Col */
13076 var cols = data1.match(colregex);
13077 if(cols) parse_ws_xml_cols(columns, cols);
13078 }
13079
13080 /* 18.3.1.80 sheetData CT_SheetData ? */
13081 if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
13082
13083 /* 18.3.1.2 autoFilter CT_AutoFilter */
13084 var afilter = data2.match(afregex);
13085 if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
13086
13087 /* 18.3.1.55 mergeCells CT_MergeCells */
13088 var merges = [];
13089 var _merge = data2.match(mergecregex);
13090 if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
13091 merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
13092
13093 /* 18.3.1.48 hyperlinks CT_Hyperlinks */
13094 var hlink = data2.match(hlinkregex);
13095 if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
13096
13097 /* 18.3.1.62 pageMargins CT_PageMargins */
13098 var margins = data2.match(marginregex);
13099 if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
13100
13101 if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
13102 if(opts.sheetRows > 0 && s["!ref"]) {
13103 var tmpref = safe_decode_range(s["!ref"]);
13104 if(opts.sheetRows <= +tmpref.e.r) {
13105 tmpref.e.r = opts.sheetRows - 1;
13106 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
13107 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
13108 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
13109 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
13110 s["!fullref"] = s["!ref"];
13111 s["!ref"] = encode_range(tmpref);
13112 }
13113 }
13114 if(columns.length > 0) s["!cols"] = columns;
13115 if(merges.length > 0) s["!merges"] = merges;
13116 return s;
13117}
13118
13119function write_ws_xml_merges(merges) {
13120 if(merges.length === 0) return "";
13121 var o = '<mergeCells count="' + merges.length + '">';
13122 for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
13123 return o + '</mergeCells>';
13124}
13125
13126/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
13127function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
13128 var data = parsexmltag(sheetPr);
13129 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
13130 if(data.codeName) wb.Sheets[idx].CodeName = data.codeName;
13131}
13132function write_ws_xml_sheetpr(ws, wb, idx, opts, o) {
13133 var needed = false;
13134 var props = {}, payload = null;
13135 if(opts.bookType !== 'xlsx' && wb.vbaraw) {
13136 var cname = wb.SheetNames[idx];
13137 try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
13138 needed = true;
13139 props.codeName = escapexml(cname);
13140 }
13141
13142 if(!needed && !payload) return;
13143 o[o.length] = (writextag('sheetPr', payload, props));
13144}
13145
13146/* 18.3.1.85 sheetProtection CT_SheetProtection */
13147var sheetprot_deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
13148var sheetprot_deftrue = [
13149 "formatColumns", "formatRows", "formatCells",
13150 "insertColumns", "insertRows", "insertHyperlinks",
13151 "deleteColumns", "deleteRows",
13152 "sort", "autoFilter", "pivotTables"
13153];
13154function write_ws_xml_protection(sp) {
13155 // algorithmName, hashValue, saltValue, spinCountpassword
13156 var o = ({sheet:1});
13157 sheetprot_deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
13158 sheetprot_deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
13159 /* TODO: algorithm */
13160 if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
13161 return writextag('sheetProtection', null, o);
13162}
13163
13164function parse_ws_xml_hlinks(s, data, rels) {
13165 var dense = Array.isArray(s);
13166 for(var i = 0; i != data.length; ++i) {
13167 var val = parsexmltag(utf8read(data[i]), true);
13168 if(!val.ref) return;
13169 var rel = ((rels || {})['!id']||[])[val.id];
13170 if(rel) {
13171 val.Target = rel.Target;
13172 if(val.location) val.Target += "#"+val.location;
13173 } else {
13174 val.Target = "#" + val.location;
13175 rel = {Target: val.Target, TargetMode: 'Internal'};
13176 }
13177 val.Rel = rel;
13178 if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
13179 var rng = safe_decode_range(val.ref);
13180 for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
13181 var addr = encode_cell({c:C,r:R});
13182 if(dense) {
13183 if(!s[R]) s[R] = [];
13184 if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
13185 s[R][C].l = val;
13186 } else {
13187 if(!s[addr]) s[addr] = {t:"z",v:undefined};
13188 s[addr].l = val;
13189 }
13190 }
13191 }
13192}
13193
13194function parse_ws_xml_margins(margin) {
13195 var o = {};
13196 ["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
13197 if(margin[k]) o[k] = parseFloat(margin[k]);
13198 });
13199 return o;
13200}
13201function write_ws_xml_margins(margin) {
13202 default_margins(margin);
13203 return writextag('pageMargins', null, margin);
13204}
13205
13206function parse_ws_xml_cols(columns, cols) {
13207 var seencol = false;
13208 for(var coli = 0; coli != cols.length; ++coli) {
13209 var coll = parsexmltag(cols[coli], true);
13210 if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
13211 var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
13212 delete coll.min; delete coll.max; coll.width = +coll.width;
13213 if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
13214 process_col(coll);
13215 while(colm <= colM) columns[colm++] = dup(coll);
13216 }
13217}
13218function write_ws_xml_cols(ws, cols) {
13219 var o = ["<cols>"], col;
13220 for(var i = 0; i != cols.length; ++i) {
13221 if(!(col = cols[i])) continue;
13222 o[o.length] = (writextag('col', null, col_obj_w(i, col)));
13223 }
13224 o[o.length] = "</cols>";
13225 return o.join("");
13226}
13227
13228function parse_ws_xml_autofilter(data) {
13229 var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
13230 return o;
13231}
13232function write_ws_xml_autofilter(data, ws, wb, idx) {
13233 var ref = typeof data.ref == "string" ? data.ref : encode_range(data.ref);
13234 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
13235 if(!wb.Workbook.Names) wb.Workbook.Names = [];
13236 var names = wb.Workbook.Names;
13237 var range = decode_range(ref);
13238 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
13239 for(var i = 0; i < names.length; ++i) {
13240 var name = names[i];
13241 if(name.Name != '_xlnm._FilterDatabase') continue;
13242 if(name.Sheet != idx) continue;
13243 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
13244 }
13245 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
13246 return writextag("autoFilter", null, {ref:ref});
13247}
13248
13249/* 18.3.1.88 sheetViews CT_SheetViews */
13250/* 18.3.1.87 sheetView CT_SheetView */
13251var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/;
13252function parse_ws_xml_sheetviews(data, wb) {
13253 if(!wb.Views) wb.Views = [{}];
13254 (data.match(sviewregex)||[]).forEach(function(r, i) {
13255 var tag = parsexmltag(r);
13256 // $FlowIgnore
13257 if(!wb.Views[i]) wb.Views[i] = {};
13258 // $FlowIgnore
13259 if(parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true;
13260 });
13261}
13262function write_ws_xml_sheetviews(ws, opts, idx, wb) {
13263 var sview = ({workbookViewId:"0"});
13264 // $FlowIgnore
13265 if((((wb||{}).Workbook||{}).Views||[])[0]) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
13266 return writextag("sheetViews", writextag("sheetView", null, sview), {});
13267}
13268
13269function write_ws_xml_cell(cell, ref, ws, opts) {
13270 if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return "";
13271 var vv = "";
13272 var oldt = cell.t, oldv = cell.v;
13273 if(cell.t !== "z") switch(cell.t) {
13274 case 'b': vv = cell.v ? "1" : "0"; break;
13275 case 'n': vv = ''+cell.v; break;
13276 case 'e': vv = BErr[cell.v]; break;
13277 case 'd':
13278 if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
13279 else {
13280 cell = dup(cell);
13281 cell.t = 'n';
13282 vv = ''+(cell.v = datenum(parseDate(cell.v)));
13283 }
13284 if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
13285 break;
13286 default: vv = cell.v; break;
13287 }
13288 var v = writetag('v', escapexml(vv)), o = ({r:ref});
13289 /* TODO: cell style */
13290 var os = get_cell_style(opts.cellXfs, cell, opts);
13291 if(os !== 0) o.s = os;
13292 switch(cell.t) {
13293 case 'n': break;
13294 case 'd': o.t = "d"; break;
13295 case 'b': o.t = "b"; break;
13296 case 'e': o.t = "e"; break;
13297 case 'z': break;
13298 default: if(cell.v == null) { delete cell.t; break; }
13299 if(opts && opts.bookSST) {
13300 v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
13301 o.t = "s"; break;
13302 }
13303 o.t = "str"; break;
13304 }
13305 if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
13306 if(cell.f) {
13307 var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
13308 v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
13309 }
13310 if(cell.l) ws['!links'].push([ref, cell.l]);
13311 if(cell.c) ws['!comments'].push([ref, cell.c]);
13312 return writextag('c', v, o);
13313}
13314
13315var parse_ws_xml_data = (function() {
13316 var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
13317 var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
13318 var refregex = /ref=["']([^"']*)["']/;
13319 var match_v = matchtag("v"), match_f = matchtag("f");
13320
13321return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
13322 var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
13323 var tag, tagr = 0, tagc = 0;
13324 var sstr, ftag;
13325 var fmtid = 0, fillid = 0;
13326 var do_format = Array.isArray(styles.CellXf), cf;
13327 var arrayf = [];
13328 var sharedf = [];
13329 var dense = Array.isArray(s);
13330 var rows = [], rowobj = {}, rowrite = false;
13331 for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
13332 x = marr[mt].trim();
13333 var xlen = x.length;
13334 if(xlen === 0) continue;
13335
13336 /* 18.3.1.73 row CT_Row */
13337 for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
13338 tag = parsexmltag(x.slice(0,ri), true);
13339 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
13340 if(opts.sheetRows && opts.sheetRows < tagr) continue;
13341 if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
13342 if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
13343
13344 if(opts && opts.cellStyles) {
13345 rowobj = {}; rowrite = false;
13346 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
13347 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
13348 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
13349 if(rowrite) rows[tagr-1] = rowobj;
13350 }
13351
13352 /* 18.3.1.4 c CT_Cell */
13353 cells = x.slice(ri).split(cellregex);
13354 for(var rslice = 0; rslice != cells.length; ++rslice) if(cells[rslice].trim().charAt(0) != "<") break;
13355 cells = cells.slice(rslice);
13356 for(ri = 0; ri != cells.length; ++ri) {
13357 x = cells[ri].trim();
13358 if(x.length === 0) continue;
13359 cref = x.match(rregex); idx = ri; i=0; cc=0;
13360 x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
13361 if(cref != null && cref.length === 2) {
13362 idx = 0; d=cref[1];
13363 for(i=0; i != d.length; ++i) {
13364 if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
13365 idx = 26*idx + cc;
13366 }
13367 --idx;
13368 tagc = idx;
13369 } else ++tagc;
13370 for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
13371 tag = parsexmltag(x.slice(0,i), true);
13372 if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
13373 d = x.slice(i);
13374 p = ({t:""});
13375
13376 if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
13377 if(opts.cellFormula) {
13378 if((cref=d.match(match_f))!= null && cref[1] !== '') {
13379 /* TODO: match against XLSXFutureFunctions */
13380 p.f=_xlfn(unescapexml(utf8read(cref[1])));
13381 if(cref[0].indexOf('t="array"') > -1) {
13382 p.F = (d.match(refregex)||[])[1];
13383 if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
13384 } else if(cref[0].indexOf('t="shared"') > -1) {
13385 // TODO: parse formula
13386 ftag = parsexmltag(cref[0]);
13387 sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1]))), tag.r];
13388 }
13389 } else if((cref=d.match(/<f[^>]*\/>/))) {
13390 ftag = parsexmltag(cref[0]);
13391 if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
13392 }
13393 /* TODO: factor out contains logic */
13394 var _tag = decode_cell(tag.r);
13395 for(i = 0; i < arrayf.length; ++i)
13396 if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
13397 if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
13398 p.F = arrayf[i][1];
13399 }
13400
13401 if(tag.t == null && p.v === undefined) {
13402 if(p.f || p.F) {
13403 p.v = 0; p.t = "n";
13404 } else if(!opts.sheetStubs) continue;
13405 else p.t = "z";
13406 }
13407 else p.t = tag.t || "n";
13408 if(guess.s.c > tagc) guess.s.c = tagc;
13409 if(guess.e.c < tagc) guess.e.c = tagc;
13410 /* 18.18.11 t ST_CellType */
13411 switch(p.t) {
13412 case 'n':
13413 if(p.v == "" || p.v == null) {
13414 if(!opts.sheetStubs) continue;
13415 p.t = 'z';
13416 } else p.v = parseFloat(p.v);
13417 break;
13418 case 's':
13419 if(typeof p.v == 'undefined') {
13420 if(!opts.sheetStubs) continue;
13421 p.t = 'z';
13422 } else {
13423 sstr = strs[parseInt(p.v, 10)];
13424 p.v = sstr.t;
13425 p.r = sstr.r;
13426 if(opts.cellHTML) p.h = sstr.h;
13427 }
13428 break;
13429 case 'str':
13430 p.t = "s";
13431 p.v = (p.v!=null) ? utf8read(p.v) : '';
13432 if(opts.cellHTML) p.h = escapehtml(p.v);
13433 break;
13434 case 'inlineStr':
13435 cref = d.match(isregex);
13436 p.t = 's';
13437 if(cref != null && (sstr = parse_si(cref[1]))) {
13438 p.v = sstr.t;
13439 if(opts.cellHTML) p.h = sstr.h;
13440 } else p.v = "";
13441 break;
13442 case 'b': p.v = parsexmlbool(p.v); break;
13443 case 'd':
13444 if(opts.cellDates) p.v = parseDate(p.v, 1);
13445 else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
13446 break;
13447 /* error string in .w, number in .v */
13448 case 'e':
13449 if(!opts || opts.cellText !== false) p.w = p.v;
13450 p.v = RBErr[p.v]; break;
13451 }
13452 /* formatting */
13453 fmtid = fillid = 0;
13454 cf = null;
13455 if(do_format && tag.s !== undefined) {
13456 cf = styles.CellXf[tag.s];
13457 if(cf != null) {
13458 if(cf.numFmtId != null) fmtid = cf.numFmtId;
13459 if(opts.cellStyles) {
13460 if(cf.fillId != null) fillid = cf.fillId;
13461 }
13462 }
13463 }
13464 safe_format(p, fmtid, fillid, opts, themes, styles);
13465 if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
13466 if(dense) {
13467 var _r = decode_cell(tag.r);
13468 if(!s[_r.r]) s[_r.r] = [];
13469 s[_r.r][_r.c] = p;
13470 } else s[tag.r] = p;
13471 }
13472 }
13473 if(rows.length > 0) s['!rows'] = rows;
13474}; })();
13475
13476function write_ws_xml_data(ws, opts, idx, wb) {
13477 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
13478 var dense = Array.isArray(ws);
13479 var params = ({r:rr}), row, height = -1;
13480 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
13481 for(R = range.s.r; R <= range.e.r; ++R) {
13482 r = [];
13483 rr = encode_row(R);
13484 for(C = range.s.c; C <= range.e.c; ++C) {
13485 ref = cols[C] + rr;
13486 var _cell = dense ? (ws[R]||[])[C]: ws[ref];
13487 if(_cell === undefined) continue;
13488 if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
13489 }
13490 if(r.length > 0 || (rows && rows[R])) {
13491 params = ({r:rr});
13492 if(rows && rows[R]) {
13493 row = rows[R];
13494 if(row.hidden) params.hidden = 1;
13495 height = -1;
13496 if(row.hpx) height = px2pt(row.hpx);
13497 else if(row.hpt) height = row.hpt;
13498 if(height > -1) { params.ht = height; params.customHeight = 1; }
13499 if(row.level) { params.outlineLevel = row.level; }
13500 }
13501 o[o.length] = (writextag('row', r.join(""), params));
13502 }
13503 }
13504 if(rows) for(; R < rows.length; ++R) {
13505 if(rows && rows[R]) {
13506 params = ({r:R+1});
13507 row = rows[R];
13508 if(row.hidden) params.hidden = 1;
13509 height = -1;
13510 if (row.hpx) height = px2pt(row.hpx);
13511 else if (row.hpt) height = row.hpt;
13512 if (height > -1) { params.ht = height; params.customHeight = 1; }
13513 if (row.level) { params.outlineLevel = row.level; }
13514 o[o.length] = (writextag('row', "", params));
13515 }
13516 }
13517 return o.join("");
13518}
13519
13520var WS_XML_ROOT = writextag('worksheet', null, {
13521 'xmlns': XMLNS.main[0],
13522 'xmlns:r': XMLNS.r
13523});
13524
13525function write_ws_xml(idx, opts, wb, rels) {
13526 var o = [XML_HEADER, WS_XML_ROOT];
13527 var s = wb.SheetNames[idx], sidx = 0, rdata = "";
13528 var ws = wb.Sheets[s];
13529 if(ws == null) ws = {};
13530 var ref = ws['!ref'] || 'A1';
13531 var range = safe_decode_range(ref);
13532 if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
13533 if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
13534 range.e.c = Math.min(range.e.c, 0x3FFF);
13535 range.e.r = Math.min(range.e.c, 0xFFFFF);
13536 ref = encode_range(range);
13537 }
13538 if(!rels) rels = {};
13539 ws['!comments'] = [];
13540 var _drawing = [];
13541
13542 write_ws_xml_sheetpr(ws, wb, idx, opts, o);
13543
13544 o[o.length] = (writextag('dimension', null, {'ref': ref}));
13545
13546 o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
13547
13548 /* TODO: store in WB, process styles */
13549 if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
13550 defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
13551 baseColWidth:opts.sheetFormat.baseColWidth||'10',
13552 outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
13553 }));
13554
13555 if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
13556
13557 o[sidx = o.length] = '<sheetData/>';
13558 ws['!links'] = [];
13559 if(ws['!ref'] != null) {
13560 rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
13561 if(rdata.length > 0) o[o.length] = (rdata);
13562 }
13563 if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
13564
13565 /* sheetCalcPr */
13566
13567 if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
13568
13569 /* protectedRanges */
13570 /* scenarios */
13571
13572 if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter'], ws, wb, idx);
13573
13574 /* sortState */
13575 /* dataConsolidate */
13576 /* customSheetViews */
13577
13578 if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
13579
13580 /* phoneticPr */
13581 /* conditionalFormatting */
13582 /* dataValidations */
13583
13584 var relc = -1, rel, rId = -1;
13585 if(ws['!links'].length > 0) {
13586 o[o.length] = "<hyperlinks>";
13587ws['!links'].forEach(function(l) {
13588 if(!l[1].Target) return;
13589 rel = ({"ref":l[0]});
13590 if(l[1].Target.charAt(0) != "#") {
13591 rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
13592 rel["r:id"] = "rId"+rId;
13593 }
13594 if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
13595 if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
13596 o[o.length] = writextag("hyperlink",null,rel);
13597 });
13598 o[o.length] = "</hyperlinks>";
13599 }
13600 delete ws['!links'];
13601
13602 /* printOptions */
13603
13604 if(ws['!margins'] != null) o[o.length] = write_ws_xml_margins(ws['!margins']);
13605
13606 /* pageSetup */
13607 /* headerFooter */
13608 /* rowBreaks */
13609 /* colBreaks */
13610 /* customProperties */
13611 /* cellWatches */
13612
13613 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
13614
13615 /* smartTags */
13616
13617 if(_drawing.length > 0) {
13618 rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
13619 o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
13620 ws['!drawing'] = _drawing;
13621 }
13622
13623 if(ws['!comments'].length > 0) {
13624 rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
13625 o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
13626 ws['!legacy'] = rId;
13627 }
13628
13629 /* legacyDrawingHF */
13630 /* picture */
13631 /* oleObjects */
13632 /* controls */
13633 /* webPublishItems */
13634 /* tableParts */
13635 /* extLst */
13636
13637 if(o.length>1) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
13638 return o.join("");
13639}
13640
13641/* [MS-XLSB] 2.4.726 BrtRowHdr */
13642function parse_BrtRowHdr(data, length) {
13643 var z = ({});
13644 var tgt = data.l + length;
13645 z.r = data.read_shift(4);
13646 data.l += 4; // TODO: ixfe
13647 var miyRw = data.read_shift(2);
13648 data.l += 1; // TODO: top/bot padding
13649 var flags = data.read_shift(1);
13650 data.l = tgt;
13651 if(flags & 0x07) z.level = flags & 0x07;
13652 if(flags & 0x10) z.hidden = true;
13653 if(flags & 0x20) z.hpt = miyRw / 20;
13654 return z;
13655}
13656function write_BrtRowHdr(R, range, ws) {
13657 var o = new_buf(17+8*16);
13658 var row = (ws['!rows']||[])[R]||{};
13659 o.write_shift(4, R);
13660
13661 o.write_shift(4, 0); /* TODO: ixfe */
13662
13663 var miyRw = 0x0140;
13664 if(row.hpx) miyRw = px2pt(row.hpx) * 20;
13665 else if(row.hpt) miyRw = row.hpt * 20;
13666 o.write_shift(2, miyRw);
13667
13668 o.write_shift(1, 0); /* top/bot padding */
13669
13670 var flags = 0x0;
13671 if(row.level) flags |= row.level;
13672 if(row.hidden) flags |= 0x10;
13673 if(row.hpx || row.hpt) flags |= 0x20;
13674 o.write_shift(1, flags);
13675
13676 o.write_shift(1, 0); /* phonetic guide */
13677
13678 /* [MS-XLSB] 2.5.8 BrtColSpan explains the mechanism */
13679 var ncolspan = 0, lcs = o.l;
13680 o.l += 4;
13681
13682 var caddr = {r:R, c:0};
13683 for(var i = 0; i < 16; ++i) {
13684 if((range.s.c > ((i+1) << 10)) || (range.e.c < (i << 10))) continue;
13685 var first = -1, last = -1;
13686 for(var j = (i<<10); j < ((i+1)<<10); ++j) {
13687 caddr.c = j;
13688 var cell = Array.isArray(ws) ? (ws[caddr.r]||[])[caddr.c] : ws[encode_cell(caddr)];
13689 if(cell) { if(first < 0) first = j; last = j; }
13690 }
13691 if(first < 0) continue;
13692 ++ncolspan;
13693 o.write_shift(4, first);
13694 o.write_shift(4, last);
13695 }
13696
13697 var l = o.l;
13698 o.l = lcs;
13699 o.write_shift(4, ncolspan);
13700 o.l = l;
13701
13702 return o.length > o.l ? o.slice(0, o.l) : o;
13703}
13704function write_row_header(ba, ws, range, R) {
13705 var o = write_BrtRowHdr(R, range, ws);
13706 if((o.length > 17) || (ws['!rows']||[])[R]) write_record(ba, 'BrtRowHdr', o);
13707}
13708
13709/* [MS-XLSB] 2.4.820 BrtWsDim */
13710var parse_BrtWsDim = parse_UncheckedRfX;
13711var write_BrtWsDim = write_UncheckedRfX;
13712
13713/* [MS-XLSB] 2.4.821 BrtWsFmtInfo */
13714function parse_BrtWsFmtInfo() {
13715}
13716//function write_BrtWsFmtInfo(ws, o) { }
13717
13718/* [MS-XLSB] 2.4.823 BrtWsProp */
13719function parse_BrtWsProp(data, length) {
13720 var z = {};
13721 /* TODO: pull flags */
13722 data.l += 19;
13723 z.name = parse_XLSBCodeName(data, length - 19);
13724 return z;
13725}
13726function write_BrtWsProp(str, o) {
13727 if(o == null) o = new_buf(84+4*str.length);
13728 for(var i = 0; i < 3; ++i) o.write_shift(1,0);
13729 write_BrtColor({auto:1}, o);
13730 o.write_shift(-4,-1);
13731 o.write_shift(-4,-1);
13732 write_XLSBCodeName(str, o);
13733 return o.slice(0, o.l);
13734}
13735
13736/* [MS-XLSB] 2.4.306 BrtCellBlank */
13737function parse_BrtCellBlank(data) {
13738 var cell = parse_XLSBCell(data);
13739 return [cell];
13740}
13741function write_BrtCellBlank(cell, ncell, o) {
13742 if(o == null) o = new_buf(8);
13743 return write_XLSBCell(ncell, o);
13744}
13745
13746
13747/* [MS-XLSB] 2.4.307 BrtCellBool */
13748function parse_BrtCellBool(data) {
13749 var cell = parse_XLSBCell(data);
13750 var fBool = data.read_shift(1);
13751 return [cell, fBool, 'b'];
13752}
13753function write_BrtCellBool(cell, ncell, o) {
13754 if(o == null) o = new_buf(9);
13755 write_XLSBCell(ncell, o);
13756 o.write_shift(1, cell.v ? 1 : 0);
13757 return o;
13758}
13759
13760/* [MS-XLSB] 2.4.308 BrtCellError */
13761function parse_BrtCellError(data) {
13762 var cell = parse_XLSBCell(data);
13763 var bError = data.read_shift(1);
13764 return [cell, bError, 'e'];
13765}
13766
13767/* [MS-XLSB] 2.4.311 BrtCellIsst */
13768function parse_BrtCellIsst(data) {
13769 var cell = parse_XLSBCell(data);
13770 var isst = data.read_shift(4);
13771 return [cell, isst, 's'];
13772}
13773function write_BrtCellIsst(cell, ncell, o) {
13774 if(o == null) o = new_buf(12);
13775 write_XLSBCell(ncell, o);
13776 o.write_shift(4, ncell.v);
13777 return o;
13778}
13779
13780/* [MS-XLSB] 2.4.313 BrtCellReal */
13781function parse_BrtCellReal(data) {
13782 var cell = parse_XLSBCell(data);
13783 var value = parse_Xnum(data);
13784 return [cell, value, 'n'];
13785}
13786function write_BrtCellReal(cell, ncell, o) {
13787 if(o == null) o = new_buf(16);
13788 write_XLSBCell(ncell, o);
13789 write_Xnum(cell.v, o);
13790 return o;
13791}
13792
13793/* [MS-XLSB] 2.4.314 BrtCellRk */
13794function parse_BrtCellRk(data) {
13795 var cell = parse_XLSBCell(data);
13796 var value = parse_RkNumber(data);
13797 return [cell, value, 'n'];
13798}
13799function write_BrtCellRk(cell, ncell, o) {
13800 if(o == null) o = new_buf(12);
13801 write_XLSBCell(ncell, o);
13802 write_RkNumber(cell.v, o);
13803 return o;
13804}
13805
13806
13807/* [MS-XLSB] 2.4.317 BrtCellSt */
13808function parse_BrtCellSt(data) {
13809 var cell = parse_XLSBCell(data);
13810 var value = parse_XLWideString(data);
13811 return [cell, value, 'str'];
13812}
13813function write_BrtCellSt(cell, ncell, o) {
13814 if(o == null) o = new_buf(12 + 4 * cell.v.length);
13815 write_XLSBCell(ncell, o);
13816 write_XLWideString(cell.v, o);
13817 return o.length > o.l ? o.slice(0, o.l) : o;
13818}
13819
13820/* [MS-XLSB] 2.4.653 BrtFmlaBool */
13821function parse_BrtFmlaBool(data, length, opts) {
13822 var end = data.l + length;
13823 var cell = parse_XLSBCell(data);
13824 cell.r = opts['!row'];
13825 var value = data.read_shift(1);
13826 var o = [cell, value, 'b'];
13827 if(opts.cellFormula) {
13828 data.l += 2;
13829 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13830 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13831 }
13832 else data.l = end;
13833 return o;
13834}
13835
13836/* [MS-XLSB] 2.4.654 BrtFmlaError */
13837function parse_BrtFmlaError(data, length, opts) {
13838 var end = data.l + length;
13839 var cell = parse_XLSBCell(data);
13840 cell.r = opts['!row'];
13841 var value = data.read_shift(1);
13842 var o = [cell, value, 'e'];
13843 if(opts.cellFormula) {
13844 data.l += 2;
13845 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13846 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13847 }
13848 else data.l = end;
13849 return o;
13850}
13851
13852/* [MS-XLSB] 2.4.655 BrtFmlaNum */
13853function parse_BrtFmlaNum(data, length, opts) {
13854 var end = data.l + length;
13855 var cell = parse_XLSBCell(data);
13856 cell.r = opts['!row'];
13857 var value = parse_Xnum(data);
13858 var o = [cell, value, 'n'];
13859 if(opts.cellFormula) {
13860 data.l += 2;
13861 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13862 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13863 }
13864 else data.l = end;
13865 return o;
13866}
13867
13868/* [MS-XLSB] 2.4.656 BrtFmlaString */
13869function parse_BrtFmlaString(data, length, opts) {
13870 var end = data.l + length;
13871 var cell = parse_XLSBCell(data);
13872 cell.r = opts['!row'];
13873 var value = parse_XLWideString(data);
13874 var o = [cell, value, 'str'];
13875 if(opts.cellFormula) {
13876 data.l += 2;
13877 var formula = parse_XLSBCellParsedFormula(data, end - data.l, opts);
13878 o[3] = stringify_formula(formula, null/*range*/, cell, opts.supbooks, opts);/* TODO */
13879 }
13880 else data.l = end;
13881 return o;
13882}
13883
13884/* [MS-XLSB] 2.4.682 BrtMergeCell */
13885var parse_BrtMergeCell = parse_UncheckedRfX;
13886var write_BrtMergeCell = write_UncheckedRfX;
13887/* [MS-XLSB] 2.4.107 BrtBeginMergeCells */
13888function write_BrtBeginMergeCells(cnt, o) {
13889 if(o == null) o = new_buf(4);
13890 o.write_shift(4, cnt);
13891 return o;
13892}
13893
13894/* [MS-XLSB] 2.4.662 BrtHLink */
13895function parse_BrtHLink(data, length) {
13896 var end = data.l + length;
13897 var rfx = parse_UncheckedRfX(data, 16);
13898 var relId = parse_XLNullableWideString(data);
13899 var loc = parse_XLWideString(data);
13900 var tooltip = parse_XLWideString(data);
13901 var display = parse_XLWideString(data);
13902 data.l = end;
13903 var o = ({rfx:rfx, relId:relId, loc:loc, display:display});
13904 if(tooltip) o.Tooltip = tooltip;
13905 return o;
13906}
13907function write_BrtHLink(l, rId) {
13908 var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
13909 write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
13910 write_RelID("rId" + rId, o);
13911 var locidx = l[1].Target.indexOf("#");
13912 var loc = locidx == -1 ? "" : l[1].Target.slice(locidx+1);
13913 write_XLWideString(loc || "", o);
13914 write_XLWideString(l[1].Tooltip || "", o);
13915 write_XLWideString("", o);
13916 return o.slice(0, o.l);
13917}
13918
13919/* [MS-XLSB] 2.4.692 BrtPane */
13920function parse_BrtPane(/*data, length, opts*/) {
13921}
13922
13923/* [MS-XLSB] 2.4.6 BrtArrFmla */
13924function parse_BrtArrFmla(data, length, opts) {
13925 var end = data.l + length;
13926 var rfx = parse_RfX(data, 16);
13927 var fAlwaysCalc = data.read_shift(1);
13928 var o = [rfx]; o[2] = fAlwaysCalc;
13929 if(opts.cellFormula) {
13930 var formula = parse_XLSBArrayParsedFormula(data, end - data.l, opts);
13931 o[1] = formula;
13932 } else data.l = end;
13933 return o;
13934}
13935
13936/* [MS-XLSB] 2.4.750 BrtShrFmla */
13937function parse_BrtShrFmla(data, length, opts) {
13938 var end = data.l + length;
13939 var rfx = parse_UncheckedRfX(data, 16);
13940 var o = [rfx];
13941 if(opts.cellFormula) {
13942 var formula = parse_XLSBSharedParsedFormula(data, end - data.l, opts);
13943 o[1] = formula;
13944 data.l = end;
13945 } else data.l = end;
13946 return o;
13947}
13948
13949/* [MS-XLSB] 2.4.323 BrtColInfo */
13950/* TODO: once XLS ColInfo is set, combine the functions */
13951function write_BrtColInfo(C, col, o) {
13952 if(o == null) o = new_buf(18);
13953 var p = col_obj_w(C, col);
13954 o.write_shift(-4, C);
13955 o.write_shift(-4, C);
13956 o.write_shift(4, (p.width || 10) * 256);
13957 o.write_shift(4, 0/*ixfe*/); // style
13958 var flags = 0;
13959 if(col.hidden) flags |= 0x01;
13960 if(typeof p.width == 'number') flags |= 0x02;
13961 if(col.level) flags |= (col.level << 8);
13962 o.write_shift(2, flags); // bit flag
13963 return o;
13964}
13965
13966/* [MS-XLSB] 2.4.678 BrtMargins */
13967var BrtMarginKeys = ["left","right","top","bottom","header","footer"];
13968function parse_BrtMargins(data) {
13969 var margins = ({});
13970 BrtMarginKeys.forEach(function(k) { margins[k] = parse_Xnum(data, 8); });
13971 return margins;
13972}
13973function write_BrtMargins(margins, o) {
13974 if(o == null) o = new_buf(6*8);
13975 default_margins(margins);
13976 BrtMarginKeys.forEach(function(k) { write_Xnum((margins)[k], o); });
13977 return o;
13978}
13979
13980/* [MS-XLSB] 2.4.299 BrtBeginWsView */
13981function parse_BrtBeginWsView(data) {
13982 var f = data.read_shift(2);
13983 data.l += 28;
13984 return { RTL: f & 0x20 };
13985}
13986function write_BrtBeginWsView(ws, Workbook, o) {
13987 if(o == null) o = new_buf(30);
13988 var f = 0x39c;
13989 if((((Workbook||{}).Views||[])[0]||{}).RTL) f |= 0x20;
13990 o.write_shift(2, f); // bit flag
13991 o.write_shift(4, 0);
13992 o.write_shift(4, 0); // view first row
13993 o.write_shift(4, 0); // view first col
13994 o.write_shift(1, 0); // gridline color ICV
13995 o.write_shift(1, 0);
13996 o.write_shift(2, 0);
13997 o.write_shift(2, 100); // zoom scale
13998 o.write_shift(2, 0);
13999 o.write_shift(2, 0);
14000 o.write_shift(2, 0);
14001 o.write_shift(4, 0); // workbook view id
14002 return o;
14003}
14004
14005/* [MS-XLSB] 2.4.309 BrtCellIgnoreEC */
14006function write_BrtCellIgnoreEC(ref) {
14007 var o = new_buf(24);
14008 o.write_shift(4, 4);
14009 o.write_shift(4, 1);
14010 write_UncheckedRfX(ref, o);
14011 return o;
14012}
14013
14014/* [MS-XLSB] 2.4.748 BrtSheetProtection */
14015function write_BrtSheetProtection(sp, o) {
14016 if(o == null) o = new_buf(16*4+2);
14017 o.write_shift(2, sp.password ? crypto_CreatePasswordVerifier_Method1(sp.password) : 0);
14018 o.write_shift(4, 1); // this record should not be written if no protection
14019 [
14020 ["objects", false], // fObjects
14021 ["scenarios", false], // fScenarios
14022 ["formatCells", true], // fFormatCells
14023 ["formatColumns", true], // fFormatColumns
14024 ["formatRows", true], // fFormatRows
14025 ["insertColumns", true], // fInsertColumns
14026 ["insertRows", true], // fInsertRows
14027 ["insertHyperlinks", true], // fInsertHyperlinks
14028 ["deleteColumns", true], // fDeleteColumns
14029 ["deleteRows", true], // fDeleteRows
14030 ["selectLockedCells", false], // fSelLockedCells
14031 ["sort", true], // fSort
14032 ["autoFilter", true], // fAutoFilter
14033 ["pivotTables", true], // fPivotTables
14034 ["selectUnlockedCells", false] // fSelUnlockedCells
14035 ].forEach(function(n) {
14036if(n[1]) o.write_shift(4, sp[n[0]] != null && !sp[n[0]] ? 1 : 0);
14037 else o.write_shift(4, sp[n[0]] != null && sp[n[0]] ? 0 : 1);
14038 });
14039 return o;
14040}
14041
14042function parse_BrtDVal(/*data, length, opts*/) {
14043}
14044function parse_BrtDVal14(/*data, length, opts*/) {
14045}
14046/* [MS-XLSB] 2.1.7.61 Worksheet */
14047function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
14048 if(!data) return data;
14049 var opts = _opts || {};
14050 if(!rels) rels = {'!id':{}};
14051 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
14052 var s = (opts.dense ? [] : {});
14053
14054 var ref;
14055 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14056
14057 var state = [];
14058 var pass = false, end = false;
14059 var row, p, cf, R, C, addr, sstr, rr, cell;
14060 var merges = [];
14061 opts.biff = 12;
14062 opts['!row'] = 0;
14063
14064 var ai = 0, af = false;
14065
14066 var arrayf = [];
14067 var sharedf = {};
14068 var supbooks = opts.supbooks || wb.supbooks || ([[]]);
14069 supbooks.sharedf = sharedf;
14070 supbooks.arrayf = arrayf;
14071 supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; });
14072 if(!opts.supbooks) {
14073 opts.supbooks = supbooks;
14074 if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i];
14075 }
14076
14077 var colinfo = [], rowinfo = [];
14078 var seencol = false;
14079
14080 recordhopper(data, function ws_parse(val, R_n, RT) {
14081 if(end) return;
14082 switch(RT) {
14083 case 0x0094: /* 'BrtWsDim' */
14084 ref = val; break;
14085 case 0x0000: /* 'BrtRowHdr' */
14086 row = val;
14087 if(opts.sheetRows && opts.sheetRows <= row.r) end=true;
14088 rr = encode_row(R = row.r);
14089 opts['!row'] = row.r;
14090 if(val.hidden || val.hpt || val.level != null) {
14091 if(val.hpt) val.hpx = pt2px(val.hpt);
14092 rowinfo[val.r] = val;
14093 }
14094 break;
14095
14096 case 0x0002: /* 'BrtCellRk' */
14097 case 0x0003: /* 'BrtCellError' */
14098 case 0x0004: /* 'BrtCellBool' */
14099 case 0x0005: /* 'BrtCellReal' */
14100 case 0x0006: /* 'BrtCellSt' */
14101 case 0x0007: /* 'BrtCellIsst' */
14102 case 0x0008: /* 'BrtFmlaString' */
14103 case 0x0009: /* 'BrtFmlaNum' */
14104 case 0x000A: /* 'BrtFmlaBool' */
14105 case 0x000B: /* 'BrtFmlaError' */
14106 p = ({t:val[2]});
14107 switch(val[2]) {
14108 case 'n': p.v = val[1]; break;
14109 case 's': sstr = strs[val[1]]; p.v = sstr.t; p.r = sstr.r; break;
14110 case 'b': p.v = val[1] ? true : false; break;
14111 case 'e': p.v = val[1]; if(opts.cellText !== false) p.w = BErr[p.v]; break;
14112 case 'str': p.t = 's'; p.v = val[1]; break;
14113 }
14114 if((cf = styles.CellXf[val[0].iStyleRef])) safe_format(p,cf.numFmtId,null,opts, themes, styles);
14115 C = val[0].c;
14116 if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
14117 else s[encode_col(C) + rr] = p;
14118 if(opts.cellFormula) {
14119 af = false;
14120 for(ai = 0; ai < arrayf.length; ++ai) {
14121 var aii = arrayf[ai];
14122 if(row.r >= aii[0].s.r && row.r <= aii[0].e.r)
14123 if(C >= aii[0].s.c && C <= aii[0].e.c) {
14124 p.F = encode_range(aii[0]); af = true;
14125 }
14126 }
14127 if(!af && val.length > 3) p.f = val[3];
14128 }
14129 if(refguess.s.r > row.r) refguess.s.r = row.r;
14130 if(refguess.s.c > C) refguess.s.c = C;
14131 if(refguess.e.r < row.r) refguess.e.r = row.r;
14132 if(refguess.e.c < C) refguess.e.c = C;
14133 if(opts.cellDates && cf && p.t == 'n' && SSF.is_date(SSF._table[cf.numFmtId])) {
14134 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); }
14135 }
14136 break;
14137
14138 case 0x0001: /* 'BrtCellBlank' */
14139 if(!opts.sheetStubs || pass) break;
14140 p = ({t:'z',v:undefined});
14141 C = val[0].c;
14142 if(opts.dense) { if(!s[R]) s[R] = []; s[R][C] = p; }
14143 else s[encode_col(C) + rr] = p;
14144 if(refguess.s.r > row.r) refguess.s.r = row.r;
14145 if(refguess.s.c > C) refguess.s.c = C;
14146 if(refguess.e.r < row.r) refguess.e.r = row.r;
14147 if(refguess.e.c < C) refguess.e.c = C;
14148 break;
14149
14150 case 0x00B0: /* 'BrtMergeCell' */
14151 merges.push(val); break;
14152
14153 case 0x01EE: /* 'BrtHLink' */
14154 var rel = rels['!id'][val.relId];
14155 if(rel) {
14156 val.Target = rel.Target;
14157 if(val.loc) val.Target += "#"+val.loc;
14158 val.Rel = rel;
14159 } else if(val.relId == '') {
14160 val.Target = "#" + val.loc;
14161 }
14162 for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
14163 if(opts.dense) {
14164 if(!s[R]) s[R] = [];
14165 if(!s[R][C]) s[R][C] = {t:'z',v:undefined};
14166 s[R][C].l = val;
14167 } else {
14168 addr = encode_cell({c:C,r:R});
14169 if(!s[addr]) s[addr] = {t:'z',v:undefined};
14170 s[addr].l = val;
14171 }
14172 }
14173 break;
14174
14175 case 0x01AA: /* 'BrtArrFmla' */
14176 if(!opts.cellFormula) break;
14177 arrayf.push(val);
14178 cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr]));
14179 cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
14180 cell.F = encode_range(val[0]);
14181 break;
14182 case 0x01AB: /* 'BrtShrFmla' */
14183 if(!opts.cellFormula) break;
14184 sharedf[encode_cell(val[0].s)] = val[1];
14185 cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]);
14186 cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts);
14187 break;
14188
14189 /* identical to 'ColInfo' in XLS */
14190 case 0x003C: /* 'BrtColInfo' */
14191 if(!opts.cellStyles) break;
14192 while(val.e >= val.s) {
14193 colinfo[val.e--] = { width: val.w/256, hidden: !!(val.flags & 0x01), level: val.level };
14194 if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
14195 process_col(colinfo[val.e+1]);
14196 }
14197 break;
14198
14199 case 0x00A1: /* 'BrtBeginAFilter' */
14200 s['!autofilter'] = { ref:encode_range(val) };
14201 break;
14202
14203 case 0x01DC: /* 'BrtMargins' */
14204 s['!margins'] = val;
14205 break;
14206
14207 case 0x0093: /* 'BrtWsProp' */
14208 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
14209 if(val.name) wb.Sheets[idx].CodeName = val.name;
14210 break;
14211
14212 case 0x0089: /* 'BrtBeginWsView' */
14213 if(!wb.Views) wb.Views = [{}];
14214 if(!wb.Views[0]) wb.Views[0] = {};
14215 if(val.RTL) wb.Views[0].RTL = true;
14216 break;
14217
14218 case 0x01E5: /* 'BrtWsFmtInfo' */
14219 break;
14220
14221 case 0x0040: /* 'BrtDVal' */
14222 case 0x041D: /* 'BrtDVal14' */
14223 break;
14224
14225 case 0x0097: /* 'BrtPane' */
14226 break;
14227 case 0x00AF: /* 'BrtAFilterDateGroupItem' */
14228 case 0x0284: /* 'BrtActiveX' */
14229 case 0x0271: /* 'BrtBigName' */
14230 case 0x0232: /* 'BrtBkHim' */
14231 case 0x018C: /* 'BrtBrk' */
14232 case 0x0458: /* 'BrtCFIcon' */
14233 case 0x047A: /* 'BrtCFRuleExt' */
14234 case 0x01D7: /* 'BrtCFVO' */
14235 case 0x041A: /* 'BrtCFVO14' */
14236 case 0x0289: /* 'BrtCellIgnoreEC' */
14237 case 0x0451: /* 'BrtCellIgnoreEC14' */
14238 case 0x0031: /* 'BrtCellMeta' */
14239 case 0x024D: /* 'BrtCellSmartTagProperty' */
14240 case 0x025F: /* 'BrtCellWatch' */
14241 case 0x0234: /* 'BrtColor' */
14242 case 0x041F: /* 'BrtColor14' */
14243 case 0x00A8: /* 'BrtColorFilter' */
14244 case 0x00AE: /* 'BrtCustomFilter' */
14245 case 0x049C: /* 'BrtCustomFilter14' */
14246 case 0x01F3: /* 'BrtDRef' */
14247 case 0x0226: /* 'BrtDrawing' */
14248 case 0x00AB: /* 'BrtDynamicFilter' */
14249 case 0x00A7: /* 'BrtFilter' */
14250 case 0x0499: /* 'BrtFilter14' */
14251 case 0x00A9: /* 'BrtIconFilter' */
14252 case 0x049D: /* 'BrtIconFilter14' */
14253 case 0x0227: /* 'BrtLegacyDrawing' */
14254 case 0x0228: /* 'BrtLegacyDrawingHF' */
14255 case 0x0295: /* 'BrtListPart' */
14256 case 0x027F: /* 'BrtOleObject' */
14257 case 0x01DE: /* 'BrtPageSetup' */
14258 case 0x0219: /* 'BrtPhoneticInfo' */
14259 case 0x01DD: /* 'BrtPrintOptions' */
14260 case 0x0218: /* 'BrtRangeProtection' */
14261 case 0x044F: /* 'BrtRangeProtection14' */
14262 case 0x02A8: /* 'BrtRangeProtectionIso' */
14263 case 0x0450: /* 'BrtRangeProtectionIso14' */
14264 case 0x0400: /* 'BrtRwDescent' */
14265 case 0x0098: /* 'BrtSel' */
14266 case 0x0297: /* 'BrtSheetCalcProp' */
14267 case 0x0217: /* 'BrtSheetProtection' */
14268 case 0x02A6: /* 'BrtSheetProtectionIso' */
14269 case 0x01F8: /* 'BrtSlc' */
14270 case 0x0413: /* 'BrtSparkline' */
14271 case 0x01AC: /* 'BrtTable' */
14272 case 0x00AA: /* 'BrtTop10Filter' */
14273 case 0x0C00: /* 'BrtUid' */
14274 case 0x0032: /* 'BrtValueMeta' */
14275 case 0x0816: /* 'BrtWebExtension' */
14276 case 0x0415: /* 'BrtWsFmtInfoEx14' */
14277 break;
14278
14279 case 0x0023: /* 'BrtFRTBegin' */
14280 pass = true; break;
14281 case 0x0024: /* 'BrtFRTEnd' */
14282 pass = false; break;
14283 case 0x0025: /* 'BrtACBegin' */
14284 state.push(R_n); pass = true; break;
14285 case 0x0026: /* 'BrtACEnd' */
14286 state.pop(); pass = false; break;
14287
14288 default:
14289 if((R_n||"").indexOf("Begin") > 0){/* empty */}
14290 else if((R_n||"").indexOf("End") > 0){/* empty */}
14291 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14292 }
14293 }, opts);
14294
14295 delete opts.supbooks;
14296 delete opts['!row'];
14297
14298 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);
14299 if(opts.sheetRows && s["!ref"]) {
14300 var tmpref = safe_decode_range(s["!ref"]);
14301 if(opts.sheetRows <= +tmpref.e.r) {
14302 tmpref.e.r = opts.sheetRows - 1;
14303 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
14304 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
14305 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
14306 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
14307 s["!fullref"] = s["!ref"];
14308 s["!ref"] = encode_range(tmpref);
14309 }
14310 }
14311 if(merges.length > 0) s["!merges"] = merges;
14312 if(colinfo.length > 0) s["!cols"] = colinfo;
14313 if(rowinfo.length > 0) s["!rows"] = rowinfo;
14314 return s;
14315}
14316
14317/* TODO: something useful -- this is a stub */
14318function write_ws_bin_cell(ba, cell, R, C, opts, ws) {
14319 if(cell.v === undefined) return;
14320 var vv = "";
14321 switch(cell.t) {
14322 case 'b': vv = cell.v ? "1" : "0"; break;
14323 case 'd': // no BrtCellDate :(
14324 cell = dup(cell);
14325 cell.z = cell.z || SSF._table[14];
14326 cell.v = datenum(parseDate(cell.v)); cell.t = 'n';
14327 break;
14328 /* falls through */
14329 case 'n': case 'e': vv = ''+cell.v; break;
14330 default: vv = cell.v; break;
14331 }
14332 var o = ({r:R, c:C});
14333 /* TODO: cell style */
14334 o.s = get_cell_style(opts.cellXfs, cell, opts);
14335 if(cell.l) ws['!links'].push([encode_cell(o), cell.l]);
14336 if(cell.c) ws['!comments'].push([encode_cell(o), cell.c]);
14337 switch(cell.t) {
14338 case 's': case 'str':
14339 if(opts.bookSST) {
14340 vv = get_sst_id(opts.Strings, (cell.v), opts.revStrings);
14341 o.t = "s"; o.v = vv;
14342 write_record(ba, "BrtCellIsst", write_BrtCellIsst(cell, o));
14343 } else {
14344 o.t = "str";
14345 write_record(ba, "BrtCellSt", write_BrtCellSt(cell, o));
14346 }
14347 return;
14348 case 'n':
14349 /* TODO: determine threshold for Real vs RK */
14350 if(cell.v == (cell.v | 0) && cell.v > -1000 && cell.v < 1000) write_record(ba, "BrtCellRk", write_BrtCellRk(cell, o));
14351 else write_record(ba, "BrtCellReal", write_BrtCellReal(cell, o));
14352 return;
14353 case 'b':
14354 o.t = "b";
14355 write_record(ba, "BrtCellBool", write_BrtCellBool(cell, o));
14356 return;
14357 case 'e': /* TODO: error */ o.t = "e"; break;
14358 }
14359 write_record(ba, "BrtCellBlank", write_BrtCellBlank(cell, o));
14360}
14361
14362function write_CELLTABLE(ba, ws, idx, opts) {
14363 var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
14364 write_record(ba, 'BrtBeginSheetData');
14365 var dense = Array.isArray(ws);
14366 var cap = range.e.r;
14367 if(ws['!rows']) cap = Math.max(range.e.r, ws['!rows'].length - 1);
14368 for(var R = range.s.r; R <= cap; ++R) {
14369 rr = encode_row(R);
14370 /* [ACCELLTABLE] */
14371 /* BrtRowHdr */
14372 write_row_header(ba, ws, range, R);
14373 if(R <= range.e.r) for(var C = range.s.c; C <= range.e.c; ++C) {
14374 /* *16384CELL */
14375 if(R === range.s.r) cols[C] = encode_col(C);
14376 ref = cols[C] + rr;
14377 var cell = dense ? (ws[R]||[])[C] : ws[ref];
14378 if(!cell) continue;
14379 /* write cell */
14380 write_ws_bin_cell(ba, cell, R, C, opts, ws);
14381 }
14382 }
14383 write_record(ba, 'BrtEndSheetData');
14384}
14385
14386function write_MERGECELLS(ba, ws) {
14387 if(!ws || !ws['!merges']) return;
14388 write_record(ba, 'BrtBeginMergeCells', write_BrtBeginMergeCells(ws['!merges'].length));
14389 ws['!merges'].forEach(function(m) { write_record(ba, 'BrtMergeCell', write_BrtMergeCell(m)); });
14390 write_record(ba, 'BrtEndMergeCells');
14391}
14392
14393function write_COLINFOS(ba, ws) {
14394 if(!ws || !ws['!cols']) return;
14395 write_record(ba, 'BrtBeginColInfos');
14396 ws['!cols'].forEach(function(m, i) { if(m) write_record(ba, 'BrtColInfo', write_BrtColInfo(i, m)); });
14397 write_record(ba, 'BrtEndColInfos');
14398}
14399
14400function write_IGNOREECS(ba, ws) {
14401 if(!ws || !ws['!ref']) return;
14402 write_record(ba, 'BrtBeginCellIgnoreECs');
14403 write_record(ba, 'BrtCellIgnoreEC', write_BrtCellIgnoreEC(safe_decode_range(ws['!ref'])));
14404 write_record(ba, 'BrtEndCellIgnoreECs');
14405}
14406
14407function write_HLINKS(ba, ws, rels) {
14408 /* *BrtHLink */
14409 ws['!links'].forEach(function(l) {
14410 if(!l[1].Target) return;
14411 var rId = add_rels(rels, -1, l[1].Target.replace(/#.*$/, ""), RELS.HLINK);
14412 write_record(ba, "BrtHLink", write_BrtHLink(l, rId));
14413 });
14414 delete ws['!links'];
14415}
14416function write_LEGACYDRAWING(ba, ws, idx, rels) {
14417 /* [BrtLegacyDrawing] */
14418 if(ws['!comments'].length > 0) {
14419 var rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
14420 write_record(ba, "BrtLegacyDrawing", write_RelID("rId" + rId));
14421 ws['!legacy'] = rId;
14422 }
14423}
14424
14425function write_AUTOFILTER(ba, ws, wb, idx) {
14426 if(!ws['!autofilter']) return;
14427 var data = ws['!autofilter'];
14428 var ref = typeof data.ref === "string" ? data.ref : encode_range(data.ref);
14429
14430 /* Update FilterDatabase defined name for the worksheet */
14431 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
14432 if(!wb.Workbook.Names) wb.Workbook.Names = [];
14433 var names = wb.Workbook.Names;
14434 var range = decode_range(ref);
14435 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
14436 for(var i = 0; i < names.length; ++i) {
14437 var name = names[i];
14438 if(name.Name != '_xlnm._FilterDatabase') continue;
14439 if(name.Sheet != idx) continue;
14440 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
14441 }
14442 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
14443
14444 write_record(ba, "BrtBeginAFilter", write_UncheckedRfX(safe_decode_range(ref)));
14445 /* *FILTERCOLUMN */
14446 /* [SORTSTATE] */
14447 /* BrtEndAFilter */
14448 write_record(ba, "BrtEndAFilter");
14449}
14450
14451function write_WSVIEWS2(ba, ws, Workbook) {
14452 write_record(ba, "BrtBeginWsViews");
14453 { /* 1*WSVIEW2 */
14454 /* [ACUID] */
14455 write_record(ba, "BrtBeginWsView", write_BrtBeginWsView(ws, Workbook));
14456 /* [BrtPane] */
14457 /* *4BrtSel */
14458 /* *4SXSELECT */
14459 /* *FRT */
14460 write_record(ba, "BrtEndWsView");
14461 }
14462 /* *FRT */
14463 write_record(ba, "BrtEndWsViews");
14464}
14465
14466function write_WSFMTINFO() {
14467 /* [ACWSFMTINFO] */
14468 //write_record(ba, "BrtWsFmtInfo", write_BrtWsFmtInfo(ws));
14469}
14470
14471function write_SHEETPROTECT(ba, ws) {
14472 if(!ws['!protect']) return;
14473 /* [BrtSheetProtectionIso] */
14474 write_record(ba, "BrtSheetProtection", write_BrtSheetProtection(ws['!protect']));
14475}
14476
14477function write_ws_bin(idx, opts, wb, rels) {
14478 var ba = buf_array();
14479 var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
14480 var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
14481 var r = safe_decode_range(ws['!ref'] || "A1");
14482 if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
14483 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
14484 r.e.c = Math.min(r.e.c, 0x3FFF);
14485 r.e.r = Math.min(r.e.c, 0xFFFFF);
14486 }
14487 ws['!links'] = [];
14488 /* passed back to write_zip and removed there */
14489 ws['!comments'] = [];
14490 write_record(ba, "BrtBeginSheet");
14491 if(wb.vbaraw) write_record(ba, "BrtWsProp", write_BrtWsProp(c));
14492 write_record(ba, "BrtWsDim", write_BrtWsDim(r));
14493 write_WSVIEWS2(ba, ws, wb.Workbook);
14494 write_WSFMTINFO(ba, ws);
14495 write_COLINFOS(ba, ws, idx, opts, wb);
14496 write_CELLTABLE(ba, ws, idx, opts, wb);
14497 /* [BrtSheetCalcProp] */
14498 write_SHEETPROTECT(ba, ws);
14499 /* *([BrtRangeProtectionIso] BrtRangeProtection) */
14500 /* [SCENMAN] */
14501 write_AUTOFILTER(ba, ws, wb, idx);
14502 /* [SORTSTATE] */
14503 /* [DCON] */
14504 /* [USERSHVIEWS] */
14505 write_MERGECELLS(ba, ws);
14506 /* [BrtPhoneticInfo] */
14507 /* *CONDITIONALFORMATTING */
14508 /* [DVALS] */
14509 write_HLINKS(ba, ws, rels);
14510 /* [BrtPrintOptions] */
14511 if(ws['!margins']) write_record(ba, "BrtMargins", write_BrtMargins(ws['!margins']));
14512 /* [BrtPageSetup] */
14513 /* [HEADERFOOTER] */
14514 /* [RWBRK] */
14515 /* [COLBRK] */
14516 /* *BrtBigName */
14517 /* [CELLWATCHES] */
14518 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) write_IGNOREECS(ba, ws);
14519 /* [SMARTTAGS] */
14520 /* [BrtDrawing] */
14521 write_LEGACYDRAWING(ba, ws, idx, rels);
14522 /* [BrtLegacyDrawingHF] */
14523 /* [BrtBkHim] */
14524 /* [OLEOBJECTS] */
14525 /* [ACTIVEXCONTROLS] */
14526 /* [WEBPUBITEMS] */
14527 /* [LISTPARTS] */
14528 /* FRTWORKSHEET */
14529 write_record(ba, "BrtEndSheet");
14530 return ba.end();
14531}
14532RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
14533RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
14534
14535function parse_Cache(data) {
14536 var col = [];
14537 var num = data.match(/^<c:numCache>/);
14538 var f;
14539
14540 /* 21.2.2.150 pt CT_NumVal */
14541 (data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
14542 var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
14543 if(!q) return;
14544 col[+q[1]] = num ? +q[2] : q[2];
14545 });
14546
14547 /* 21.2.2.71 formatCode CT_Xstring */
14548 var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
14549
14550 (data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); });
14551
14552 return [col, nf, f];
14553}
14554
14555/* 21.2 DrawingML - Charts */
14556function parse_chart(data, name, opts, rels, wb, csheet) {
14557 var cs = ((csheet || {"!type":"chart"}));
14558 if(!data) return csheet;
14559 /* 21.2.2.27 chart CT_Chart */
14560
14561 var C = 0, R = 0, col = "A";
14562 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
14563
14564 /* 21.2.2.120 numCache CT_NumData */
14565 (data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
14566 var cache = parse_Cache(nc);
14567 refguess.s.r = refguess.s.c = 0;
14568 refguess.e.c = C;
14569 col = encode_col(C);
14570 cache[0].forEach(function(n,i) {
14571 cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
14572 R = i;
14573 });
14574 if(refguess.e.r < R) refguess.e.r = R;
14575 ++C;
14576 });
14577 if(C > 0) cs["!ref"] = encode_range(refguess);
14578 return cs;
14579}
14580RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
14581
14582var CS_XML_ROOT = writextag('chartsheet', null, {
14583 'xmlns': XMLNS.main[0],
14584 'xmlns:r': XMLNS.r
14585});
14586
14587/* 18.3 Worksheets also covers Chartsheets */
14588function parse_cs_xml(data, opts, idx, rels, wb) {
14589 if(!data) return data;
14590 /* 18.3.1.12 chartsheet CT_ChartSheet */
14591 if(!rels) rels = {'!id':{}};
14592 var s = ({'!type':"chart", '!drawel':null, '!rel':""});
14593 var m;
14594
14595 /* 18.3.1.83 sheetPr CT_ChartsheetPr */
14596 var sheetPr = data.match(sheetprregex);
14597 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
14598
14599 /* 18.3.1.36 drawing CT_Drawing */
14600 if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
14601
14602 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
14603 return s;
14604}
14605function write_cs_xml(idx, opts, wb, rels) {
14606 var o = [XML_HEADER, CS_XML_ROOT];
14607 o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
14608 add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
14609 if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
14610 return o.join("");
14611}
14612
14613/* [MS-XLSB] 2.4.331 BrtCsProp */
14614function parse_BrtCsProp(data, length) {
14615 data.l += 10;
14616 var name = parse_XLWideString(data, length - 10);
14617 return { name: name };
14618}
14619
14620/* [MS-XLSB] 2.1.7.7 Chart Sheet */
14621function parse_cs_bin(data, opts, idx, rels, wb) {
14622 if(!data) return data;
14623 if(!rels) rels = {'!id':{}};
14624 var s = {'!type':"chart", '!drawel':null, '!rel':""};
14625 var state = [];
14626 var pass = false;
14627 recordhopper(data, function cs_parse(val, R_n, RT) {
14628 switch(RT) {
14629
14630 case 0x0226: /* 'BrtDrawing' */
14631 s['!rel'] = val; break;
14632
14633 case 0x028B: /* 'BrtCsProp' */
14634 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
14635 if(val.name) wb.Sheets[idx].CodeName = val.name;
14636 break;
14637
14638 case 0x0232: /* 'BrtBkHim' */
14639 case 0x028C: /* 'BrtCsPageSetup' */
14640 case 0x029D: /* 'BrtCsProtection' */
14641 case 0x02A7: /* 'BrtCsProtectionIso' */
14642 case 0x0227: /* 'BrtLegacyDrawing' */
14643 case 0x0228: /* 'BrtLegacyDrawingHF' */
14644 case 0x01DC: /* 'BrtMargins' */
14645 case 0x0C00: /* 'BrtUid' */
14646 break;
14647
14648 case 0x0023: /* 'BrtFRTBegin' */
14649 pass = true; break;
14650 case 0x0024: /* 'BrtFRTEnd' */
14651 pass = false; break;
14652 case 0x0025: /* 'BrtACBegin' */
14653 state.push(R_n); break;
14654 case 0x0026: /* 'BrtACEnd' */
14655 state.pop(); break;
14656
14657 default:
14658 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
14659 else if((R_n||"").indexOf("End") > 0) state.pop();
14660 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
14661 }
14662 }, opts);
14663
14664 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
14665 return s;
14666}
14667function write_cs_bin() {
14668 var ba = buf_array();
14669 write_record(ba, "BrtBeginSheet");
14670 /* [BrtCsProp] */
14671 /* CSVIEWS */
14672 /* [[BrtCsProtectionIso] BrtCsProtection] */
14673 /* [USERCSVIEWS] */
14674 /* [BrtMargins] */
14675 /* [BrtCsPageSetup] */
14676 /* [HEADERFOOTER] */
14677 /* BrtDrawing */
14678 /* [BrtLegacyDrawing] */
14679 /* [BrtLegacyDrawingHF] */
14680 /* [BrtBkHim] */
14681 /* [WEBPUBITEMS] */
14682 /* FRTCHARTSHEET */
14683 write_record(ba, "BrtEndSheet");
14684 return ba.end();
14685}
14686/* 18.2.28 (CT_WorkbookProtection) Defaults */
14687var WBPropsDef = [
14688 ['allowRefreshQuery', false, "bool"],
14689 ['autoCompressPictures', true, "bool"],
14690 ['backupFile', false, "bool"],
14691 ['checkCompatibility', false, "bool"],
14692 ['CodeName', ''],
14693 ['date1904', false, "bool"],
14694 ['defaultThemeVersion', 0, "int"],
14695 ['filterPrivacy', false, "bool"],
14696 ['hidePivotFieldList', false, "bool"],
14697 ['promptedSolutions', false, "bool"],
14698 ['publishItems', false, "bool"],
14699 ['refreshAllConnections', false, "bool"],
14700 ['saveExternalLinkValues', true, "bool"],
14701 ['showBorderUnselectedTables', true, "bool"],
14702 ['showInkAnnotation', true, "bool"],
14703 ['showObjects', 'all'],
14704 ['showPivotChartFilter', false, "bool"],
14705 ['updateLinks', 'userSet']
14706];
14707
14708/* 18.2.30 (CT_BookView) Defaults */
14709var WBViewDef = [
14710 ['activeTab', 0, "int"],
14711 ['autoFilterDateGrouping', true, "bool"],
14712 ['firstSheet', 0, "int"],
14713 ['minimized', false, "bool"],
14714 ['showHorizontalScroll', true, "bool"],
14715 ['showSheetTabs', true, "bool"],
14716 ['showVerticalScroll', true, "bool"],
14717 ['tabRatio', 600, "int"],
14718 ['visibility', 'visible']
14719 //window{Height,Width}, {x,y}Window
14720];
14721
14722/* 18.2.19 (CT_Sheet) Defaults */
14723var SheetDef = [
14724 //['state', 'visible']
14725];
14726
14727/* 18.2.2 (CT_CalcPr) Defaults */
14728var CalcPrDef = [
14729 ['calcCompleted', 'true'],
14730 ['calcMode', 'auto'],
14731 ['calcOnSave', 'true'],
14732 ['concurrentCalc', 'true'],
14733 ['fullCalcOnLoad', 'false'],
14734 ['fullPrecision', 'true'],
14735 ['iterate', 'false'],
14736 ['iterateCount', '100'],
14737 ['iterateDelta', '0.001'],
14738 ['refMode', 'A1']
14739];
14740
14741/* 18.2.3 (CT_CustomWorkbookView) Defaults */
14742/*var CustomWBViewDef = [
14743 ['autoUpdate', 'false'],
14744 ['changesSavedWin', 'false'],
14745 ['includeHiddenRowCol', 'true'],
14746 ['includePrintSettings', 'true'],
14747 ['maximized', 'false'],
14748 ['minimized', 'false'],
14749 ['onlySync', 'false'],
14750 ['personalView', 'false'],
14751 ['showComments', 'commIndicator'],
14752 ['showFormulaBar', 'true'],
14753 ['showHorizontalScroll', 'true'],
14754 ['showObjects', 'all'],
14755 ['showSheetTabs', 'true'],
14756 ['showStatusbar', 'true'],
14757 ['showVerticalScroll', 'true'],
14758 ['tabRatio', '600'],
14759 ['xWindow', '0'],
14760 ['yWindow', '0']
14761];*/
14762
14763function push_defaults_array(target, defaults) {
14764 for(var j = 0; j != target.length; ++j) { var w = target[j];
14765 for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
14766 if(w[z[0]] == null) w[z[0]] = z[1];
14767 else switch(z[2]) {
14768 case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
14769 case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
14770 }
14771 }
14772 }
14773}
14774function push_defaults(target, defaults) {
14775 for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
14776 if(target[z[0]] == null) target[z[0]] = z[1];
14777 else switch(z[2]) {
14778 case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
14779 case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
14780 }
14781 }
14782}
14783
14784function parse_wb_defaults(wb) {
14785 push_defaults(wb.WBProps, WBPropsDef);
14786 push_defaults(wb.CalcPr, CalcPrDef);
14787
14788 push_defaults_array(wb.WBView, WBViewDef);
14789 push_defaults_array(wb.Sheets, SheetDef);
14790
14791 _ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
14792}
14793
14794function safe1904(wb) {
14795 /* TODO: store date1904 somewhere else */
14796 if(!wb.Workbook) return "false";
14797 if(!wb.Workbook.WBProps) return "false";
14798 return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
14799}
14800
14801var badchars = "][*?\/\\".split("");
14802function check_ws_name(n, safe) {
14803 if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
14804 var _good = true;
14805 badchars.forEach(function(c) {
14806 if(n.indexOf(c) == -1) return;
14807 if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
14808 _good = false;
14809 });
14810 return _good;
14811}
14812function check_wb_names(N, S, codes) {
14813 N.forEach(function(n,i) {
14814 check_ws_name(n);
14815 for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
14816 if(codes) {
14817 var cn = (S && S[i] && S[i].CodeName) || n;
14818 if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
14819 }
14820 });
14821}
14822function check_wb(wb) {
14823 if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
14824 if(!wb.SheetNames.length) throw new Error("Workbook is empty");
14825 var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
14826 check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
14827 for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
14828 /* TODO: validate workbook */
14829}
14830/* 18.2 Workbook */
14831var wbnsregex = /<\w+:workbook/;
14832function parse_wb_xml(data, opts) {
14833 if(!data) throw new Error("Could not find file");
14834 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
14835 var pass = false, xmlns = "xmlns";
14836 var dname = {}, dnstart = 0;
14837 data.replace(tagregex, function xml_wb(x, idx) {
14838 var y = parsexmltag(x);
14839 switch(strip_ns(y[0])) {
14840 case '<?xml': break;
14841
14842 /* 18.2.27 workbook CT_Workbook 1 */
14843 case '<workbook':
14844 if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
14845 wb.xmlns = y[xmlns];
14846 break;
14847 case '</workbook>': break;
14848
14849 /* 18.2.13 fileVersion CT_FileVersion ? */
14850 case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
14851 case '<fileVersion/>': case '</fileVersion>': break;
14852
14853 /* 18.2.12 fileSharing CT_FileSharing ? */
14854 case '<fileSharing':
14855 break;
14856 case '<fileSharing/>': break;
14857
14858 /* 18.2.28 workbookPr CT_WorkbookPr ? */
14859 case '<workbookPr':
14860 case '<workbookPr/>':
14861 WBPropsDef.forEach(function(w) {
14862 if(y[w[0]] == null) return;
14863 switch(w[2]) {
14864 case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
14865 case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
14866 default: wb.WBProps[w[0]] = y[w[0]];
14867 }
14868 });
14869 if(y.codeName) wb.WBProps.CodeName = y.codeName;
14870 break;
14871 case '</workbookPr>': break;
14872
14873 /* 18.2.29 workbookProtection CT_WorkbookProtection ? */
14874 case '<workbookProtection':
14875 break;
14876 case '<workbookProtection/>': break;
14877
14878 /* 18.2.1 bookViews CT_BookViews ? */
14879 case '<bookViews': case '<bookViews>': case '</bookViews>': break;
14880 /* 18.2.30 workbookView CT_BookView + */
14881 case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
14882 case '</workbookView>': break;
14883
14884 /* 18.2.20 sheets CT_Sheets 1 */
14885 case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
14886 /* 18.2.19 sheet CT_Sheet + */
14887 case '<sheet':
14888 switch(y.state) {
14889 case "hidden": y.Hidden = 1; break;
14890 case "veryHidden": y.Hidden = 2; break;
14891 default: y.Hidden = 0;
14892 }
14893 delete y.state;
14894 y.name = unescapexml(utf8read(y.name));
14895 delete y[0]; wb.Sheets.push(y); break;
14896 case '</sheet>': break;
14897
14898 /* 18.2.15 functionGroups CT_FunctionGroups ? */
14899 case '<functionGroups': case '<functionGroups/>': break;
14900 /* 18.2.14 functionGroup CT_FunctionGroup + */
14901 case '<functionGroup': break;
14902
14903 /* 18.2.9 externalReferences CT_ExternalReferences ? */
14904 case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
14905 /* 18.2.8 externalReference CT_ExternalReference + */
14906 case '<externalReference': break;
14907
14908 /* 18.2.6 definedNames CT_DefinedNames ? */
14909 case '<definedNames/>': break;
14910 case '<definedNames>': case '<definedNames': pass=true; break;
14911 case '</definedNames>': pass=false; break;
14912 /* 18.2.5 definedName CT_DefinedName + */
14913 case '<definedName': {
14914 dname = {};
14915 dname.Name = utf8read(y.name);
14916 if(y.comment) dname.Comment = y.comment;
14917 if(y.localSheetId) dname.Sheet = +y.localSheetId;
14918 if(parsexmlbool(y.hidden||"0")) dname.Hidden = true;
14919 dnstart = idx + x.length;
14920 } break;
14921 case '</definedName>': {
14922 dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
14923 wb.Names.push(dname);
14924 } break;
14925 case '<definedName/>': break;
14926
14927 /* 18.2.2 calcPr CT_CalcPr ? */
14928 case '<calcPr': delete y[0]; wb.CalcPr = y; break;
14929 case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
14930 case '</calcPr>': break;
14931
14932 /* 18.2.16 oleSize CT_OleSize ? (ref required) */
14933 case '<oleSize': break;
14934
14935 /* 18.2.4 customWorkbookViews CT_CustomWorkbookViews ? */
14936 case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
14937 /* 18.2.3 customWorkbookView CT_CustomWorkbookView + */
14938 case '<customWorkbookView': case '</customWorkbookView>': break;
14939
14940 /* 18.2.18 pivotCaches CT_PivotCaches ? */
14941 case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
14942 /* 18.2.17 pivotCache CT_PivotCache ? */
14943 case '<pivotCache': break;
14944
14945 /* 18.2.21 smartTagPr CT_SmartTagPr ? */
14946 case '<smartTagPr': case '<smartTagPr/>': break;
14947
14948 /* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
14949 case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
14950 /* 18.2.22 smartTagType CT_SmartTagType ? */
14951 case '<smartTagType': break;
14952
14953 /* 18.2.24 webPublishing CT_WebPublishing ? */
14954 case '<webPublishing': case '<webPublishing/>': break;
14955
14956 /* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
14957 case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
14958
14959 /* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
14960 case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
14961 /* 18.2.25 webPublishObject CT_WebPublishObject ? */
14962 case '<webPublishObject': break;
14963
14964 /* 18.2.10 extLst CT_ExtensionList ? */
14965 case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
14966 /* 18.2.7 ext CT_Extension + */
14967 case '<ext': pass=true; break; //TODO: check with versions of excel
14968 case '</ext>': pass=false; break;
14969
14970 /* Others */
14971 case '<ArchID': break;
14972 case '<AlternateContent':
14973 case '<AlternateContent>': pass=true; break;
14974 case '</AlternateContent>': pass=false; break;
14975
14976 /* TODO */
14977 case '<revisionPtr': break;
14978
14979 default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
14980 }
14981 return x;
14982 });
14983 if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
14984
14985 parse_wb_defaults(wb);
14986
14987 return wb;
14988}
14989
14990var WB_XML_ROOT = writextag('workbook', null, {
14991 'xmlns': XMLNS.main[0],
14992 //'xmlns:mx': XMLNS.mx,
14993 //'xmlns:s': XMLNS.main[0],
14994 'xmlns:r': XMLNS.r
14995});
14996
14997function write_wb_xml(wb) {
14998 var o = [XML_HEADER];
14999 o[o.length] = WB_XML_ROOT;
15000
15001 var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
15002
15003 /* fileVersion */
15004 /* fileSharing */
15005
15006 var workbookPr = ({codeName:"ThisWorkbook"});
15007 if(wb.Workbook && wb.Workbook.WBProps) {
15008 WBPropsDef.forEach(function(x) {
15009if((wb.Workbook.WBProps[x[0]]) == null) return;
15010 if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
15011 workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
15012 });
15013if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
15014 }
15015 o[o.length] = (writextag('workbookPr', null, workbookPr));
15016
15017 /* workbookProtection */
15018
15019 var sheets = wb.Workbook && wb.Workbook.Sheets || [];
15020 var i = 0;
15021
15022 /* bookViews */
15023
15024 o[o.length] = "<sheets>";
15025 for(i = 0; i != wb.SheetNames.length; ++i) {
15026 var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
15027 sht.sheetId = ""+(i+1);
15028 sht["r:id"] = "rId"+(i+1);
15029 if(sheets[i]) switch(sheets[i].Hidden) {
15030 case 1: sht.state = "hidden"; break;
15031 case 2: sht.state = "veryHidden"; break;
15032 }
15033 o[o.length] = (writextag('sheet',null,sht));
15034 }
15035 o[o.length] = "</sheets>";
15036
15037 /* functionGroups */
15038 /* externalReferences */
15039
15040 if(write_names) {
15041 o[o.length] = "<definedNames>";
15042 if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
15043 var d = {name:n.Name};
15044 if(n.Comment) d.comment = n.Comment;
15045 if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
15046 if(n.Hidden) d.hidden = "1";
15047 if(!n.Ref) return;
15048 o[o.length] = writextag('definedName', escapexml(n.Ref), d);
15049 });
15050 o[o.length] = "</definedNames>";
15051 }
15052
15053 /* calcPr */
15054 /* oleSize */
15055 /* customWorkbookViews */
15056 /* pivotCaches */
15057 /* smartTagPr */
15058 /* smartTagTypes */
15059 /* webPublishing */
15060 /* fileRecoveryPr */
15061 /* webPublishObjects */
15062 /* extLst */
15063
15064 if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
15065 return o.join("");
15066}
15067/* [MS-XLSB] 2.4.304 BrtBundleSh */
15068function parse_BrtBundleSh(data, length) {
15069 var z = {};
15070 z.Hidden = data.read_shift(4); //hsState ST_SheetState
15071 z.iTabID = data.read_shift(4);
15072 z.strRelID = parse_RelID(data,length-8);
15073 z.name = parse_XLWideString(data);
15074 return z;
15075}
15076function write_BrtBundleSh(data, o) {
15077 if(!o) o = new_buf(127);
15078 o.write_shift(4, data.Hidden);
15079 o.write_shift(4, data.iTabID);
15080 write_RelID(data.strRelID, o);
15081 write_XLWideString(data.name.slice(0,31), o);
15082 return o.length > o.l ? o.slice(0, o.l) : o;
15083}
15084
15085/* [MS-XLSB] 2.4.815 BrtWbProp */
15086function parse_BrtWbProp(data, length) {
15087 var o = ({});
15088 var flags = data.read_shift(4);
15089 o.defaultThemeVersion = data.read_shift(4);
15090 var strName = (length > 8) ? parse_XLWideString(data) : "";
15091 if(strName.length > 0) o.CodeName = strName;
15092 o.autoCompressPictures = !!(flags & 0x10000);
15093 o.backupFile = !!(flags & 0x40);
15094 o.checkCompatibility = !!(flags & 0x1000);
15095 o.date1904 = !!(flags & 0x01);
15096 o.filterPrivacy = !!(flags & 0x08);
15097 o.hidePivotFieldList = !!(flags & 0x400);
15098 o.promptedSolutions = !!(flags & 0x10);
15099 o.publishItems = !!(flags & 0x800);
15100 o.refreshAllConnections = !!(flags & 0x40000);
15101 o.saveExternalLinkValues = !!(flags & 0x80);
15102 o.showBorderUnselectedTables = !!(flags & 0x04);
15103 o.showInkAnnotation = !!(flags & 0x20);
15104 o.showObjects = ["all", "placeholders", "none"][(flags >> 13) & 0x03];
15105 o.showPivotChartFilter = !!(flags & 0x8000);
15106 o.updateLinks = ["userSet", "never", "always"][(flags >> 8) & 0x03];
15107 return o;
15108}
15109function write_BrtWbProp(data, o) {
15110 if(!o) o = new_buf(72);
15111 var flags = 0;
15112 if(data) {
15113 /* TODO: mirror parse_BrtWbProp fields */
15114 if(data.filterPrivacy) flags |= 0x08;
15115 }
15116 o.write_shift(4, flags);
15117 o.write_shift(4, 0);
15118 write_XLSBCodeName(data && data.CodeName || "ThisWorkbook", o);
15119 return o.slice(0, o.l);
15120}
15121
15122function parse_BrtFRTArchID$(data, length) {
15123 var o = {};
15124 data.read_shift(4);
15125 o.ArchID = data.read_shift(4);
15126 data.l += length - 8;
15127 return o;
15128}
15129
15130/* [MS-XLSB] 2.4.687 BrtName */
15131function parse_BrtName(data, length, opts) {
15132 var end = data.l + length;
15133 data.l += 4; //var flags = data.read_shift(4);
15134 data.l += 1; //var chKey = data.read_shift(1);
15135 var itab = data.read_shift(4);
15136 var name = parse_XLNameWideString(data);
15137 var formula = parse_XLSBNameParsedFormula(data, 0, opts);
15138 var comment = parse_XLNullableWideString(data);
15139 //if(0 /* fProc */) {
15140 // unusedstring1: XLNullableWideString
15141 // description: XLNullableWideString
15142 // helpTopic: XLNullableWideString
15143 // unusedstring2: XLNullableWideString
15144 //}
15145 data.l = end;
15146 var out = ({Name:name, Ptg:formula});
15147 if(itab < 0xFFFFFFF) out.Sheet = itab;
15148 if(comment) out.Comment = comment;
15149 return out;
15150}
15151
15152/* [MS-XLSB] 2.1.7.61 Workbook */
15153function parse_wb_bin(data, opts) {
15154 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, xmlns: "" };
15155 var state = [];
15156 var pass = false;
15157
15158 if(!opts) opts = {};
15159 opts.biff = 12;
15160
15161 var Names = [];
15162 var supbooks = ([[]]);
15163 supbooks.SheetNames = [];
15164 supbooks.XTI = [];
15165
15166 recordhopper(data, function hopper_wb(val, R_n, RT) {
15167 switch(RT) {
15168 case 0x009C: /* 'BrtBundleSh' */
15169 supbooks.SheetNames.push(val.name);
15170 wb.Sheets.push(val); break;
15171
15172 case 0x0099: /* 'BrtWbProp' */
15173 wb.WBProps = val; break;
15174
15175 case 0x0027: /* 'BrtName' */
15176 if(val.Sheet != null) opts.SID = val.Sheet;
15177 val.Ref = stringify_formula(val.Ptg, null, null, supbooks, opts);
15178 delete opts.SID;
15179 delete val.Ptg;
15180 Names.push(val);
15181 break;
15182 case 0x040C: /* 'BrtNameExt' */ break;
15183
15184 case 0x0165: /* 'BrtSupSelf' */
15185 case 0x0166: /* 'BrtSupSame' */
15186 case 0x0163: /* 'BrtSupBookSrc' */
15187 case 0x029B: /* 'BrtSupAddin' */
15188 if(!supbooks[0].length) supbooks[0] = [RT, val];
15189 else supbooks.push([RT, val]);
15190 supbooks[supbooks.length - 1].XTI = [];
15191 break;
15192 case 0x016A: /* 'BrtExternSheet' */
15193 if(supbooks.length === 0) { supbooks[0] = []; supbooks[0].XTI = []; }
15194 supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val);
15195 supbooks.XTI = supbooks.XTI.concat(val);
15196 break;
15197 case 0x0169: /* 'BrtPlaceholderName' */
15198 break;
15199
15200 /* case 'BrtModelTimeGroupingCalcCol' */
15201 case 0x0C00: /* 'BrtUid' */
15202 case 0x0C01: /* 'BrtRevisionPtr' */
15203 case 0x0817: /* 'BrtAbsPath15' */
15204 case 0x0216: /* 'BrtBookProtection' */
15205 case 0x02A5: /* 'BrtBookProtectionIso' */
15206 case 0x009E: /* 'BrtBookView' */
15207 case 0x009D: /* 'BrtCalcProp' */
15208 case 0x0262: /* 'BrtCrashRecErr' */
15209 case 0x0802: /* 'BrtDecoupledPivotCacheID' */
15210 case 0x009B: /* 'BrtFileRecover' */
15211 case 0x0224: /* 'BrtFileSharing' */
15212 case 0x02A4: /* 'BrtFileSharingIso' */
15213 case 0x0080: /* 'BrtFileVersion' */
15214 case 0x0299: /* 'BrtFnGroup' */
15215 case 0x0850: /* 'BrtModelRelationship' */
15216 case 0x084D: /* 'BrtModelTable' */
15217 case 0x0225: /* 'BrtOleSize' */
15218 case 0x0805: /* 'BrtPivotTableRef' */
15219 case 0x0254: /* 'BrtSmartTagType' */
15220 case 0x081C: /* 'BrtTableSlicerCacheID' */
15221 case 0x081B: /* 'BrtTableSlicerCacheIDs' */
15222 case 0x0822: /* 'BrtTimelineCachePivotCacheID' */
15223 case 0x018D: /* 'BrtUserBookView' */
15224 case 0x009A: /* 'BrtWbFactoid' */
15225 case 0x045D: /* 'BrtWbProp14' */
15226 case 0x0229: /* 'BrtWebOpt' */
15227 case 0x082B: /* 'BrtWorkBookPr15' */
15228 break;
15229
15230 case 0x0023: /* 'BrtFRTBegin' */
15231 state.push(R_n); pass = true; break;
15232 case 0x0024: /* 'BrtFRTEnd' */
15233 state.pop(); pass = false; break;
15234 case 0x0025: /* 'BrtACBegin' */
15235 state.push(R_n); pass = true; break;
15236 case 0x0026: /* 'BrtACEnd' */
15237 state.pop(); pass = false; break;
15238
15239 case 0x0010: /* 'BrtFRTArchID$' */ break;
15240
15241 default:
15242 if((R_n||"").indexOf("Begin") > 0){/* empty */}
15243 else if((R_n||"").indexOf("End") > 0){/* empty */}
15244 else if(!pass || (opts.WTF && state[state.length-1] != "BrtACBegin" && state[state.length-1] != "BrtFRTBegin")) throw new Error("Unexpected record " + RT + " " + R_n);
15245 }
15246 }, opts);
15247
15248 parse_wb_defaults(wb);
15249
15250 // $FlowIgnore
15251 wb.Names = Names;
15252
15253 (wb).supbooks = supbooks;
15254 return wb;
15255}
15256
15257function write_BUNDLESHS(ba, wb) {
15258 write_record(ba, "BrtBeginBundleShs");
15259 for(var idx = 0; idx != wb.SheetNames.length; ++idx) {
15260 var viz = wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx] && wb.Workbook.Sheets[idx].Hidden || 0;
15261 var d = { Hidden: viz, iTabID: idx+1, strRelID: 'rId' + (idx+1), name: wb.SheetNames[idx] };
15262 write_record(ba, "BrtBundleSh", write_BrtBundleSh(d));
15263 }
15264 write_record(ba, "BrtEndBundleShs");
15265}
15266
15267/* [MS-XLSB] 2.4.649 BrtFileVersion */
15268function write_BrtFileVersion(data, o) {
15269 if(!o) o = new_buf(127);
15270 for(var i = 0; i != 4; ++i) o.write_shift(4, 0);
15271 write_XLWideString("SheetJS", o);
15272 write_XLWideString(XLSX.version, o);
15273 write_XLWideString(XLSX.version, o);
15274 write_XLWideString("7262", o);
15275 o.length = o.l;
15276 return o.length > o.l ? o.slice(0, o.l) : o;
15277}
15278
15279/* [MS-XLSB] 2.4.301 BrtBookView */
15280function write_BrtBookView(idx, o) {
15281 if(!o) o = new_buf(29);
15282 o.write_shift(-4, 0);
15283 o.write_shift(-4, 460);
15284 o.write_shift(4, 28800);
15285 o.write_shift(4, 17600);
15286 o.write_shift(4, 500);
15287 o.write_shift(4, idx);
15288 o.write_shift(4, idx);
15289 var flags = 0x78;
15290 o.write_shift(1, flags);
15291 return o.length > o.l ? o.slice(0, o.l) : o;
15292}
15293
15294function write_BOOKVIEWS(ba, wb) {
15295 /* required if hidden tab appears before visible tab */
15296 if(!wb.Workbook || !wb.Workbook.Sheets) return;
15297 var sheets = wb.Workbook.Sheets;
15298 var i = 0, vistab = -1, hidden = -1;
15299 for(; i < sheets.length; ++i) {
15300 if(!sheets[i] || !sheets[i].Hidden && vistab == -1) vistab = i;
15301 else if(sheets[i].Hidden == 1 && hidden == -1) hidden = i;
15302 }
15303 if(hidden > vistab) return;
15304 write_record(ba, "BrtBeginBookViews");
15305 write_record(ba, "BrtBookView", write_BrtBookView(vistab));
15306 /* 1*(BrtBookView *FRT) */
15307 write_record(ba, "BrtEndBookViews");
15308}
15309
15310/* [MS-XLSB] 2.4.305 BrtCalcProp */
15311/*function write_BrtCalcProp(data, o) {
15312 if(!o) o = new_buf(26);
15313 o.write_shift(4,0); // force recalc
15314 o.write_shift(4,1);
15315 o.write_shift(4,0);
15316 write_Xnum(0, o);
15317 o.write_shift(-4, 1023);
15318 o.write_shift(1, 0x33);
15319 o.write_shift(1, 0x00);
15320 return o;
15321}*/
15322
15323/* [MS-XLSB] 2.4.646 BrtFileRecover */
15324/*function write_BrtFileRecover(data, o) {
15325 if(!o) o = new_buf(1);
15326 o.write_shift(1,0);
15327 return o;
15328}*/
15329
15330/* [MS-XLSB] 2.1.7.61 Workbook */
15331function write_wb_bin(wb, opts) {
15332 var ba = buf_array();
15333 write_record(ba, "BrtBeginBook");
15334 write_record(ba, "BrtFileVersion", write_BrtFileVersion());
15335 /* [[BrtFileSharingIso] BrtFileSharing] */
15336 write_record(ba, "BrtWbProp", write_BrtWbProp(wb.Workbook && wb.Workbook.WBProps || null));
15337 /* [ACABSPATH] */
15338 /* [[BrtBookProtectionIso] BrtBookProtection] */
15339 write_BOOKVIEWS(ba, wb, opts);
15340 write_BUNDLESHS(ba, wb, opts);
15341 /* [FNGROUP] */
15342 /* [EXTERNALS] */
15343 /* *BrtName */
15344 /* write_record(ba, "BrtCalcProp", write_BrtCalcProp()); */
15345 /* [BrtOleSize] */
15346 /* *(BrtUserBookView *FRT) */
15347 /* [PIVOTCACHEIDS] */
15348 /* [BrtWbFactoid] */
15349 /* [SMARTTAGTYPES] */
15350 /* [BrtWebOpt] */
15351 /* write_record(ba, "BrtFileRecover", write_BrtFileRecover()); */
15352 /* [WEBPUBITEMS] */
15353 /* [CRERRS] */
15354 /* FRTWORKBOOK */
15355 write_record(ba, "BrtEndBook");
15356
15357 return ba.end();
15358}
15359function parse_wb(data, name, opts) {
15360 if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
15361 return parse_wb_xml((data), opts);
15362}
15363
15364function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
15365 if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
15366 return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
15367}
15368
15369function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
15370 if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
15371 return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
15372}
15373
15374function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
15375 if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
15376 return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
15377}
15378
15379function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
15380 if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
15381 return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
15382}
15383
15384function parse_sty(data, name, themes, opts) {
15385 if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
15386 return parse_sty_xml((data), themes, opts);
15387}
15388
15389function parse_theme(data, name, opts) {
15390 return parse_theme_xml(data, opts);
15391}
15392
15393function parse_sst(data, name, opts) {
15394 if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
15395 return parse_sst_xml((data), opts);
15396}
15397
15398function parse_cmnt(data, name, opts) {
15399 if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
15400 return parse_comments_xml((data), opts);
15401}
15402
15403function parse_cc(data, name, opts) {
15404 if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
15405 return parse_cc_xml((data), name, opts);
15406}
15407
15408function parse_xlink(data, rel, name, opts) {
15409 if(name.slice(-4)===".bin") return parse_xlink_bin((data), rel, name, opts);
15410 return parse_xlink_xml((data), rel, name, opts);
15411}
15412
15413function write_wb(wb, name, opts) {
15414 return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
15415}
15416
15417function write_ws(data, name, opts, wb, rels) {
15418 return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
15419}
15420
15421// eslint-disable-next-line no-unused-vars
15422function write_cs(data, name, opts, wb, rels) {
15423 return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
15424}
15425
15426function write_sty(data, name, opts) {
15427 return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
15428}
15429
15430function write_sst(data, name, opts) {
15431 return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
15432}
15433
15434function write_cmnt(data, name, opts) {
15435 return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
15436}
15437/*
15438function write_cc(data, name:string, opts) {
15439 return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
15440}
15441*/
15442var attregexg2=/([\w:]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:'))/g;
15443var attregex2=/([\w:]+)=((?:")(?:[^"]*)(?:")|(?:')(?:[^']*)(?:'))/;
15444function xlml_parsexmltag(tag, skip_root) {
15445 var words = tag.split(/\s+/);
15446 var z = ([]); if(!skip_root) z[0] = words[0];
15447 if(words.length === 1) return z;
15448 var m = tag.match(attregexg2), y, j, w, i;
15449 if(m) for(i = 0; i != m.length; ++i) {
15450 y = m[i].match(attregex2);
15451if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
15452 else {
15453 if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
15454 else w = y[1].slice(j+1);
15455 z[w] = y[2].slice(1,y[2].length-1);
15456 }
15457 }
15458 return z;
15459}
15460function xlml_parsexmltagobj(tag) {
15461 var words = tag.split(/\s+/);
15462 var z = {};
15463 if(words.length === 1) return z;
15464 var m = tag.match(attregexg2), y, j, w, i;
15465 if(m) for(i = 0; i != m.length; ++i) {
15466 y = m[i].match(attregex2);
15467if((j=y[1].indexOf(":")) === -1) z[y[1]] = y[2].slice(1,y[2].length-1);
15468 else {
15469 if(y[1].slice(0,6) === "xmlns:") w = "xmlns"+y[1].slice(6);
15470 else w = y[1].slice(j+1);
15471 z[w] = y[2].slice(1,y[2].length-1);
15472 }
15473 }
15474 return z;
15475}
15476
15477// ----
15478
15479function xlml_format(format, value) {
15480 var fmt = XLMLFormatMap[format] || unescapexml(format);
15481 if(fmt === "General") return SSF._general(value);
15482 return SSF.format(fmt, value);
15483}
15484
15485function xlml_set_custprop(Custprops, key, cp, val) {
15486 var oval = val;
15487 switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) {
15488 case "boolean": oval = parsexmlbool(val); break;
15489 case "i2": case "int": oval = parseInt(val, 10); break;
15490 case "r4": case "float": oval = parseFloat(val); break;
15491 case "date": case "dateTime.tz": oval = parseDate(val); break;
15492 case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break;
15493 default: throw new Error("bad custprop:" + cp[0]);
15494 }
15495 Custprops[unescapexml(key)] = oval;
15496}
15497
15498function safe_format_xlml(cell, nf, o) {
15499 if(cell.t === 'z') return;
15500 if(!o || o.cellText !== false) try {
15501 if(cell.t === 'e') { cell.w = cell.w || BErr[cell.v]; }
15502 else if(nf === "General") {
15503 if(cell.t === 'n') {
15504 if((cell.v|0) === cell.v) cell.w = SSF._general_int(cell.v);
15505 else cell.w = SSF._general_num(cell.v);
15506 }
15507 else cell.w = SSF._general(cell.v);
15508 }
15509 else cell.w = xlml_format(nf||"General", cell.v);
15510 } catch(e) { if(o.WTF) throw e; }
15511 try {
15512 var z = XLMLFormatMap[nf]||nf||"General";
15513 if(o.cellNF) cell.z = z;
15514 if(o.cellDates && cell.t == 'n' && SSF.is_date(z)) {
15515 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); }
15516 }
15517 } catch(e) { if(o.WTF) throw e; }
15518}
15519
15520function process_style_xlml(styles, stag, opts) {
15521 if(opts.cellStyles) {
15522 if(stag.Interior) {
15523 var I = stag.Interior;
15524 if(I.Pattern) I.patternType = XLMLPatternTypeMap[I.Pattern] || I.Pattern;
15525 }
15526 }
15527 styles[stag.ID] = stag;
15528}
15529
15530/* TODO: there must exist some form of OSP-blessed spec */
15531function parse_xlml_data(xml, ss, data, cell, base, styles, csty, row, arrayf, o) {
15532 var nf = "General", sid = cell.StyleID, S = {}; o = o || {};
15533 var interiors = [];
15534 var i = 0;
15535 if(sid === undefined && row) sid = row.StyleID;
15536 if(sid === undefined && csty) sid = csty.StyleID;
15537 while(styles[sid] !== undefined) {
15538 if(styles[sid].nf) nf = styles[sid].nf;
15539 if(styles[sid].Interior) interiors.push(styles[sid].Interior);
15540 if(!styles[sid].Parent) break;
15541 sid = styles[sid].Parent;
15542 }
15543 switch(data.Type) {
15544 case 'Boolean':
15545 cell.t = 'b';
15546 cell.v = parsexmlbool(xml);
15547 break;
15548 case 'String':
15549 cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
15550 cell.v = xml.indexOf("<") > -1 ? unescapexml(ss||xml) : cell.r;
15551 break;
15552 case 'DateTime':
15553 if(xml.slice(-1) != "Z") xml += "Z";
15554 cell.v = (parseDate(xml) - new Date(Date.UTC(1899, 11, 30))) / (24 * 60 * 60 * 1000);
15555 if(cell.v !== cell.v) cell.v = unescapexml(xml);
15556 else if(cell.v<60) cell.v = cell.v -1;
15557 if(!nf || nf == "General") nf = "yyyy-mm-dd";
15558 /* falls through */
15559 case 'Number':
15560 if(cell.v === undefined) cell.v=+xml;
15561 if(!cell.t) cell.t = 'n';
15562 break;
15563 case 'Error': cell.t = 'e'; cell.v = RBErr[xml]; if(o.cellText !== false) cell.w = xml; break;
15564 default:
15565 if(xml == "" && ss == "") { cell.t = 'z'; }
15566 else { cell.t = 's'; cell.v = xlml_fixstr(ss||xml); }
15567 break;
15568 }
15569 safe_format_xlml(cell, nf, o);
15570 if(o.cellFormula !== false) {
15571 if(cell.Formula) {
15572 var fstr = unescapexml(cell.Formula);
15573 /* strictly speaking, the leading = is required but some writers omit */
15574 if(fstr.charCodeAt(0) == 61 /* = */) fstr = fstr.slice(1);
15575 cell.f = rc_to_a1(fstr, base);
15576 delete cell.Formula;
15577 if(cell.ArrayRange == "RC") cell.F = rc_to_a1("RC:RC", base);
15578 else if(cell.ArrayRange) {
15579 cell.F = rc_to_a1(cell.ArrayRange, base);
15580 arrayf.push([safe_decode_range(cell.F), cell.F]);
15581 }
15582 } else {
15583 for(i = 0; i < arrayf.length; ++i)
15584 if(base.r >= arrayf[i][0].s.r && base.r <= arrayf[i][0].e.r)
15585 if(base.c >= arrayf[i][0].s.c && base.c <= arrayf[i][0].e.c)
15586 cell.F = arrayf[i][1];
15587 }
15588 }
15589 if(o.cellStyles) {
15590 interiors.forEach(function(x) {
15591 if(!S.patternType && x.patternType) S.patternType = x.patternType;
15592 });
15593 cell.s = S;
15594 }
15595 if(cell.StyleID !== undefined) cell.ixfe = cell.StyleID;
15596}
15597
15598function xlml_clean_comment(comment) {
15599 comment.t = comment.v || "";
15600 comment.t = comment.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
15601 comment.v = comment.w = comment.ixfe = undefined;
15602}
15603
15604function xlml_normalize(d) {
15605 if(has_buf && Buffer.isBuffer(d)) return d.toString('utf8');
15606 if(typeof d === 'string') return d;
15607 /* duktape */
15608 if(typeof Uint8Array !== 'undefined' && d instanceof Uint8Array) return utf8read(a2s(ab2a(d)));
15609 throw new Error("Bad input format: expected Buffer or string");
15610}
15611
15612/* TODO: Everything */
15613/* UOS uses CJK in tags */
15614var xlmlregex = /<(\/?)([^\s?>!\/:]*:|)([^\s?>:\/]+)[^>]*>/mg;
15615//var xlmlregex = /<(\/?)([a-z0-9]*:|)(\w+)[^>]*>/mg;
15616function parse_xlml_xml(d, _opts) {
15617 var opts = _opts || {};
15618 make_ssf(SSF);
15619 var str = debom(xlml_normalize(d));
15620 if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') {
15621 if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str));
15622 else str = utf8read(str);
15623 }
15624 var opening = str.slice(0, 1024).toLowerCase(), ishtml = false;
15625 if(opening.indexOf("<?xml") == -1) ["html", "table", "head", "meta", "script", "style", "div"].forEach(function(tag) { if(opening.indexOf("<" + tag) >= 0) ishtml = true; });
15626 if(ishtml) return HTML_.to_workbook(str, opts);
15627 var Rn;
15628 var state = [], tmp;
15629 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
15630 var sheets = {}, sheetnames = [], cursheet = (opts.dense ? [] : {}), sheetname = "";
15631 var table = {}, cell = ({}), row = {};// eslint-disable-line no-unused-vars
15632 var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
15633 var c = 0, r = 0;
15634 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
15635 var styles = {}, stag = {};
15636 var ss = "", fidx = 0;
15637 var merges = [];
15638 var Props = {}, Custprops = {}, pidx = 0, cp = [];
15639 var comments = [], comment = ({});
15640 var cstys = [], csty, seencol = false;
15641 var arrayf = [];
15642 var rowinfo = [], rowobj = {}, cc = 0, rr = 0;
15643 var Workbook = ({ Sheets:[], WBProps:{date1904:false} }), wsprops = {};
15644 xlmlregex.lastIndex = 0;
15645 str = str.replace(/<!--([\s\S]*?)-->/mg,"");
15646 while((Rn = xlmlregex.exec(str))) switch(Rn[3]) {
15647 case 'Data':
15648 if(state[state.length-1][1]) break;
15649 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);
15650 else { ss = ""; dtag = xlml_parsexmltag(Rn[0]); didx = Rn.index + Rn[0].length; }
15651 break;
15652 case 'Cell':
15653 if(Rn[1]==='/'){
15654 if(comments.length > 0) cell.c = comments;
15655 if((!opts.sheetRows || opts.sheetRows > r) && cell.v !== undefined) {
15656 if(opts.dense) {
15657 if(!cursheet[r]) cursheet[r] = [];
15658 cursheet[r][c] = cell;
15659 } else cursheet[encode_col(c) + encode_row(r)] = cell;
15660 }
15661 if(cell.HRef) {
15662 cell.l = ({Target:cell.HRef});
15663 if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
15664 delete cell.HRef; delete cell.HRefScreenTip;
15665 }
15666 if(cell.MergeAcross || cell.MergeDown) {
15667 cc = c + (parseInt(cell.MergeAcross,10)|0);
15668 rr = r + (parseInt(cell.MergeDown,10)|0);
15669 merges.push({s:{c:c,r:r},e:{c:cc,r:rr}});
15670 }
15671 if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; }
15672 else if(cell.MergeAcross || cell.MergeDown) {
15673for(var cma = c; cma <= cc; ++cma) {
15674 for(var cmd = r; cmd <= rr; ++cmd) {
15675 if(cma > c || cmd > r) {
15676 if(opts.dense) {
15677 if(!cursheet[cmd]) cursheet[cmd] = [];
15678 cursheet[cmd][cma] = {t:'z'};
15679 } else cursheet[encode_col(cma) + encode_row(cmd)] = {t:'z'};
15680 }
15681 }
15682 }
15683 c = cc + 1;
15684 }
15685 else ++c;
15686 } else {
15687 cell = xlml_parsexmltagobj(Rn[0]);
15688 if(cell.Index) c = +cell.Index - 1;
15689 if(c < refguess.s.c) refguess.s.c = c;
15690 if(c > refguess.e.c) refguess.e.c = c;
15691 if(Rn[0].slice(-2) === "/>") ++c;
15692 comments = [];
15693 }
15694 break;
15695 case 'Row':
15696 if(Rn[1]==='/' || Rn[0].slice(-2) === "/>") {
15697 if(r < refguess.s.r) refguess.s.r = r;
15698 if(r > refguess.e.r) refguess.e.r = r;
15699 if(Rn[0].slice(-2) === "/>") {
15700 row = xlml_parsexmltag(Rn[0]);
15701 if(row.Index) r = +row.Index - 1;
15702 }
15703 c = 0; ++r;
15704 } else {
15705 row = xlml_parsexmltag(Rn[0]);
15706 if(row.Index) r = +row.Index - 1;
15707 rowobj = {};
15708 if(row.AutoFitHeight == "0" || row.Height) {
15709 rowobj.hpx = parseInt(row.Height, 10); rowobj.hpt = px2pt(rowobj.hpx);
15710 rowinfo[r] = rowobj;
15711 }
15712 if(row.Hidden == "1") { rowobj.hidden = true; rowinfo[r] = rowobj; }
15713 }
15714 break;
15715 case 'Worksheet': /* TODO: read range from FullRows/FullColumns */
15716 if(Rn[1]==='/'){
15717 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15718 sheetnames.push(sheetname);
15719 if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) {
15720 cursheet["!ref"] = encode_range(refguess);
15721 if(opts.sheetRows && opts.sheetRows <= refguess.e.r) {
15722 cursheet["!fullref"] = cursheet["!ref"];
15723 refguess.e.r = opts.sheetRows - 1;
15724 cursheet["!ref"] = encode_range(refguess);
15725 }
15726 }
15727 if(merges.length) cursheet["!merges"] = merges;
15728 if(cstys.length > 0) cursheet["!cols"] = cstys;
15729 if(rowinfo.length > 0) cursheet["!rows"] = rowinfo;
15730 sheets[sheetname] = cursheet;
15731 } else {
15732 refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
15733 r = c = 0;
15734 state.push([Rn[3], false]);
15735 tmp = xlml_parsexmltag(Rn[0]);
15736 sheetname = unescapexml(tmp.Name);
15737 cursheet = (opts.dense ? [] : {});
15738 merges = [];
15739 arrayf = [];
15740 rowinfo = [];
15741 wsprops = {name:sheetname, Hidden:0};
15742 Workbook.Sheets.push(wsprops);
15743 }
15744 break;
15745 case 'Table':
15746 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15747 else if(Rn[0].slice(-2) == "/>") break;
15748 else {
15749 table = xlml_parsexmltag(Rn[0]);
15750 state.push([Rn[3], false]);
15751 cstys = []; seencol = false;
15752 }
15753 break;
15754
15755 case 'Style':
15756 if(Rn[1]==='/') process_style_xlml(styles, stag, opts);
15757 else stag = xlml_parsexmltag(Rn[0]);
15758 break;
15759
15760 case 'NumberFormat':
15761 stag.nf = unescapexml(xlml_parsexmltag(Rn[0]).Format || "General");
15762 if(XLMLFormatMap[stag.nf]) stag.nf = XLMLFormatMap[stag.nf];
15763 for(var ssfidx = 0; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == stag.nf) break;
15764 if(ssfidx == 0x188) for(ssfidx = 0x39; ssfidx != 0x188; ++ssfidx) if(SSF._table[ssfidx] == null) { SSF.load(stag.nf, ssfidx); break; }
15765 break;
15766
15767 case 'Column':
15768 if(state[state.length-1][0] !== 'Table') break;
15769 csty = xlml_parsexmltag(Rn[0]);
15770 if(csty.Hidden) { csty.hidden = true; delete csty.Hidden; }
15771 if(csty.Width) csty.wpx = parseInt(csty.Width, 10);
15772 if(!seencol && csty.wpx > 10) {
15773 seencol = true; MDW = DEF_MDW; //find_mdw_wpx(csty.wpx);
15774 for(var _col = 0; _col < cstys.length; ++_col) if(cstys[_col]) process_col(cstys[_col]);
15775 }
15776 if(seencol) process_col(csty);
15777 cstys[(csty.Index-1||cstys.length)] = csty;
15778 for(var i = 0; i < +csty.Span; ++i) cstys[cstys.length] = dup(csty);
15779 break;
15780
15781 case 'NamedRange':
15782 if(!Workbook.Names) Workbook.Names = [];
15783 var _NamedRange = parsexmltag(Rn[0]);
15784 var _DefinedName = ({
15785 Name: _NamedRange.Name,
15786 Ref: rc_to_a1(_NamedRange.RefersTo.slice(1), {r:0, c:0})
15787 });
15788 if(Workbook.Sheets.length>0) _DefinedName.Sheet=Workbook.Sheets.length-1;
15789Workbook.Names.push(_DefinedName);
15790 break;
15791
15792 case 'NamedCell': break;
15793 case 'B': break;
15794 case 'I': break;
15795 case 'U': break;
15796 case 'S': break;
15797 case 'Sub': break;
15798 case 'Sup': break;
15799 case 'Span': break;
15800 case 'Alignment':
15801 break;
15802 case 'Borders': break;
15803 case 'Border': break;
15804 case 'Font':
15805 if(Rn[0].slice(-2) === "/>") break;
15806 else if(Rn[1]==="/") ss += str.slice(fidx, Rn.index);
15807 else fidx = Rn.index + Rn[0].length;
15808 break;
15809 case 'Interior':
15810 if(!opts.cellStyles) break;
15811 stag.Interior = xlml_parsexmltag(Rn[0]);
15812 break;
15813 case 'Protection': break;
15814
15815 case 'Author':
15816 case 'Title':
15817 case 'Description':
15818 case 'Created':
15819 case 'Keywords':
15820 case 'Subject':
15821 case 'Category':
15822 case 'Company':
15823 case 'LastAuthor':
15824 case 'LastSaved':
15825 case 'LastPrinted':
15826 case 'Version':
15827 case 'Revision':
15828 case 'TotalTime':
15829 case 'HyperlinkBase':
15830 case 'Manager':
15831 case 'ContentStatus':
15832 case 'Identifier':
15833 case 'Language':
15834 case 'AppName':
15835 if(Rn[0].slice(-2) === "/>") break;
15836 else if(Rn[1]==="/") xlml_set_prop(Props, Rn[3], str.slice(pidx, Rn.index));
15837 else pidx = Rn.index + Rn[0].length;
15838 break;
15839 case 'Paragraphs': break;
15840
15841 case 'Styles':
15842 case 'Workbook':
15843 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15844 else state.push([Rn[3], false]);
15845 break;
15846
15847 case 'Comment':
15848 if(Rn[1]==='/'){
15849 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15850 xlml_clean_comment(comment);
15851 comments.push(comment);
15852 } else {
15853 state.push([Rn[3], false]);
15854 tmp = xlml_parsexmltag(Rn[0]);
15855 comment = ({a:tmp.Author});
15856 }
15857 break;
15858
15859 case 'AutoFilter':
15860 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15861 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
15862 var AutoFilter = xlml_parsexmltag(Rn[0]);
15863 cursheet['!autofilter'] = { ref:rc_to_a1(AutoFilter.Range).replace(/\$/g,"") };
15864 state.push([Rn[3], true]);
15865 }
15866 break;
15867
15868 case 'Name': break;
15869
15870 case 'DataValidation':
15871 if(Rn[1]==='/'){
15872 if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));
15873 } else {
15874 if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
15875 }
15876 break;
15877
15878 case 'ComponentOptions':
15879 case 'DocumentProperties':
15880 case 'CustomDocumentProperties':
15881 case 'OfficeDocumentSettings':
15882 case 'PivotTable':
15883 case 'PivotCache':
15884 case 'Names':
15885 case 'MapInfo':
15886 case 'PageBreaks':
15887 case 'QueryTable':
15888 case 'Sorting':
15889 case 'Schema':
15890 case 'data':
15891 case 'ConditionalFormatting':
15892 case 'SmartTagType':
15893 case 'SmartTags':
15894 case 'ExcelWorkbook':
15895 case 'WorkbookOptions':
15896 case 'WorksheetOptions':
15897 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|"));}
15898 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
15899 break;
15900
15901 default:
15902 /* FODS file root is <office:document> */
15903 if(state.length == 0 && Rn[3] == "document") return parse_fods(str, opts);
15904 /* UOS file root is <uof:UOF> */
15905 if(state.length == 0 && Rn[3] == "UOF") return parse_fods(str, opts);
15906
15907 var seen = true;
15908 switch(state[state.length-1][0]) {
15909 /* OfficeDocumentSettings */
15910 case 'OfficeDocumentSettings': switch(Rn[3]) {
15911 case 'AllowPNG': break;
15912 case 'RemovePersonalInformation': break;
15913 case 'DownloadComponents': break;
15914 case 'LocationOfComponents': break;
15915 case 'Colors': break;
15916 case 'Color': break;
15917 case 'Index': break;
15918 case 'RGB': break;
15919 case 'PixelsPerInch': break; // TODO: set PPI
15920 case 'TargetScreenSize': break;
15921 case 'ReadOnlyRecommended': break;
15922 default: seen = false;
15923 } break;
15924
15925 /* ComponentOptions */
15926 case 'ComponentOptions': switch(Rn[3]) {
15927 case 'Toolbar': break;
15928 case 'HideOfficeLogo': break;
15929 case 'SpreadsheetAutoFit': break;
15930 case 'Label': break;
15931 case 'Caption': break;
15932 case 'MaxHeight': break;
15933 case 'MaxWidth': break;
15934 case 'NextSheetNumber': break;
15935 default: seen = false;
15936 } break;
15937
15938 /* ExcelWorkbook */
15939 case 'ExcelWorkbook': switch(Rn[3]) {
15940 case 'Date1904':
15941Workbook.WBProps.date1904 = true;
15942 break;
15943 case 'WindowHeight': break;
15944 case 'WindowWidth': break;
15945 case 'WindowTopX': break;
15946 case 'WindowTopY': break;
15947 case 'TabRatio': break;
15948 case 'ProtectStructure': break;
15949 case 'ProtectWindow': break;
15950 case 'ProtectWindows': break;
15951 case 'ActiveSheet': break;
15952 case 'DisplayInkNotes': break;
15953 case 'FirstVisibleSheet': break;
15954 case 'SupBook': break;
15955 case 'SheetName': break;
15956 case 'SheetIndex': break;
15957 case 'SheetIndexFirst': break;
15958 case 'SheetIndexLast': break;
15959 case 'Dll': break;
15960 case 'AcceptLabelsInFormulas': break;
15961 case 'DoNotSaveLinkValues': break;
15962 case 'Iteration': break;
15963 case 'MaxIterations': break;
15964 case 'MaxChange': break;
15965 case 'Path': break;
15966 case 'Xct': break;
15967 case 'Count': break;
15968 case 'SelectedSheets': break;
15969 case 'Calculation': break;
15970 case 'Uncalced': break;
15971 case 'StartupPrompt': break;
15972 case 'Crn': break;
15973 case 'ExternName': break;
15974 case 'Formula': break;
15975 case 'ColFirst': break;
15976 case 'ColLast': break;
15977 case 'WantAdvise': break;
15978 case 'Boolean': break;
15979 case 'Error': break;
15980 case 'Text': break;
15981 case 'OLE': break;
15982 case 'NoAutoRecover': break;
15983 case 'PublishObjects': break;
15984 case 'DoNotCalculateBeforeSave': break;
15985 case 'Number': break;
15986 case 'RefModeR1C1': break;
15987 case 'EmbedSaveSmartTags': break;
15988 default: seen = false;
15989 } break;
15990
15991 /* WorkbookOptions */
15992 case 'WorkbookOptions': switch(Rn[3]) {
15993 case 'OWCVersion': break;
15994 case 'Height': break;
15995 case 'Width': break;
15996 default: seen = false;
15997 } break;
15998
15999 /* WorksheetOptions */
16000 case 'WorksheetOptions': switch(Rn[3]) {
16001 case 'Visible':
16002 if(Rn[0].slice(-2) === "/>"){/* empty */}
16003 else if(Rn[1]==="/") switch(str.slice(pidx, Rn.index)) {
16004 case "SheetHidden": wsprops.Hidden = 1; break;
16005 case "SheetVeryHidden": wsprops.Hidden = 2; break;
16006 }
16007 else pidx = Rn.index + Rn[0].length;
16008 break;
16009 case 'Header':
16010 if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
16011 cursheet['!margins'].header = parsexmltag(Rn[0]).Margin;
16012 break;
16013 case 'Footer':
16014 if(!cursheet['!margins']) default_margins(cursheet['!margins']={}, 'xlml');
16015 cursheet['!margins'].footer = parsexmltag(Rn[0]).Margin;
16016 break;
16017 case 'PageMargins':
16018 var pagemargins = parsexmltag(Rn[0]);
16019 if(!cursheet['!margins']) default_margins(cursheet['!margins']={},'xlml');
16020 if(pagemargins.Top) cursheet['!margins'].top = pagemargins.Top;
16021 if(pagemargins.Left) cursheet['!margins'].left = pagemargins.Left;
16022 if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right;
16023 if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom;
16024 break;
16025 case 'DisplayRightToLeft':
16026 if(!Workbook.Views) Workbook.Views = [];
16027 if(!Workbook.Views[0]) Workbook.Views[0] = {};
16028 Workbook.Views[0].RTL = true;
16029 break;
16030
16031 case 'FreezePanes': break;
16032 case 'FrozenNoSplit': break;
16033
16034 case 'SplitHorizontal':
16035 case 'SplitVertical':
16036 break;
16037
16038 case 'DoNotDisplayGridlines':
16039 break;
16040
16041 case 'TopRowBottomPane': break;
16042 case 'LeftColumnRightPane': break;
16043
16044 case 'Unsynced': break;
16045 case 'Print': break;
16046 case 'Panes': break;
16047 case 'Scale': break;
16048 case 'Pane': break;
16049 case 'Number': break;
16050 case 'Layout': break;
16051 case 'PageSetup': break;
16052 case 'Selected': break;
16053 case 'ProtectObjects': break;
16054 case 'EnableSelection': break;
16055 case 'ProtectScenarios': break;
16056 case 'ValidPrinterInfo': break;
16057 case 'HorizontalResolution': break;
16058 case 'VerticalResolution': break;
16059 case 'NumberofCopies': break;
16060 case 'ActiveRow': break;
16061 case 'ActiveCol': break;
16062 case 'ActivePane': break;
16063 case 'TopRowVisible': break;
16064 case 'LeftColumnVisible': break;
16065 case 'FitToPage': break;
16066 case 'RangeSelection': break;
16067 case 'PaperSizeIndex': break;
16068 case 'PageLayoutZoom': break;
16069 case 'PageBreakZoom': break;
16070 case 'FilterOn': break;
16071 case 'FitWidth': break;
16072 case 'FitHeight': break;
16073 case 'CommentsLayout': break;
16074 case 'Zoom': break;
16075 case 'LeftToRight': break;
16076 case 'Gridlines': break;
16077 case 'AllowSort': break;
16078 case 'AllowFilter': break;
16079 case 'AllowInsertRows': break;
16080 case 'AllowDeleteRows': break;
16081 case 'AllowInsertCols': break;
16082 case 'AllowDeleteCols': break;
16083 case 'AllowInsertHyperlinks': break;
16084 case 'AllowFormatCells': break;
16085 case 'AllowSizeCols': break;
16086 case 'AllowSizeRows': break;
16087 case 'NoSummaryRowsBelowDetail': break;
16088 case 'TabColorIndex': break;
16089 case 'DoNotDisplayHeadings': break;
16090 case 'ShowPageLayoutZoom': break;
16091 case 'NoSummaryColumnsRightDetail': break;
16092 case 'BlackAndWhite': break;
16093 case 'DoNotDisplayZeros': break;
16094 case 'DisplayPageBreak': break;
16095 case 'RowColHeadings': break;
16096 case 'DoNotDisplayOutline': break;
16097 case 'NoOrientation': break;
16098 case 'AllowUsePivotTables': break;
16099 case 'ZeroHeight': break;
16100 case 'ViewableRange': break;
16101 case 'Selection': break;
16102 case 'ProtectContents': break;
16103 default: seen = false;
16104 } break;
16105
16106 /* PivotTable */
16107 case 'PivotTable': case 'PivotCache': switch(Rn[3]) {
16108 case 'ImmediateItemsOnDrop': break;
16109 case 'ShowPageMultipleItemLabel': break;
16110 case 'CompactRowIndent': break;
16111 case 'Location': break;
16112 case 'PivotField': break;
16113 case 'Orientation': break;
16114 case 'LayoutForm': break;
16115 case 'LayoutSubtotalLocation': break;
16116 case 'LayoutCompactRow': break;
16117 case 'Position': break;
16118 case 'PivotItem': break;
16119 case 'DataType': break;
16120 case 'DataField': break;
16121 case 'SourceName': break;
16122 case 'ParentField': break;
16123 case 'PTLineItems': break;
16124 case 'PTLineItem': break;
16125 case 'CountOfSameItems': break;
16126 case 'Item': break;
16127 case 'ItemType': break;
16128 case 'PTSource': break;
16129 case 'CacheIndex': break;
16130 case 'ConsolidationReference': break;
16131 case 'FileName': break;
16132 case 'Reference': break;
16133 case 'NoColumnGrand': break;
16134 case 'NoRowGrand': break;
16135 case 'BlankLineAfterItems': break;
16136 case 'Hidden': break;
16137 case 'Subtotal': break;
16138 case 'BaseField': break;
16139 case 'MapChildItems': break;
16140 case 'Function': break;
16141 case 'RefreshOnFileOpen': break;
16142 case 'PrintSetTitles': break;
16143 case 'MergeLabels': break;
16144 case 'DefaultVersion': break;
16145 case 'RefreshName': break;
16146 case 'RefreshDate': break;
16147 case 'RefreshDateCopy': break;
16148 case 'VersionLastRefresh': break;
16149 case 'VersionLastUpdate': break;
16150 case 'VersionUpdateableMin': break;
16151 case 'VersionRefreshableMin': break;
16152 case 'Calculation': break;
16153 default: seen = false;
16154 } break;
16155
16156 /* PageBreaks */
16157 case 'PageBreaks': switch(Rn[3]) {
16158 case 'ColBreaks': break;
16159 case 'ColBreak': break;
16160 case 'RowBreaks': break;
16161 case 'RowBreak': break;
16162 case 'ColStart': break;
16163 case 'ColEnd': break;
16164 case 'RowEnd': break;
16165 default: seen = false;
16166 } break;
16167
16168 /* AutoFilter */
16169 case 'AutoFilter': switch(Rn[3]) {
16170 case 'AutoFilterColumn': break;
16171 case 'AutoFilterCondition': break;
16172 case 'AutoFilterAnd': break;
16173 case 'AutoFilterOr': break;
16174 default: seen = false;
16175 } break;
16176
16177 /* QueryTable */
16178 case 'QueryTable': switch(Rn[3]) {
16179 case 'Id': break;
16180 case 'AutoFormatFont': break;
16181 case 'AutoFormatPattern': break;
16182 case 'QuerySource': break;
16183 case 'QueryType': break;
16184 case 'EnableRedirections': break;
16185 case 'RefreshedInXl9': break;
16186 case 'URLString': break;
16187 case 'HTMLTables': break;
16188 case 'Connection': break;
16189 case 'CommandText': break;
16190 case 'RefreshInfo': break;
16191 case 'NoTitles': break;
16192 case 'NextId': break;
16193 case 'ColumnInfo': break;
16194 case 'OverwriteCells': break;
16195 case 'DoNotPromptForFile': break;
16196 case 'TextWizardSettings': break;
16197 case 'Source': break;
16198 case 'Number': break;
16199 case 'Decimal': break;
16200 case 'ThousandSeparator': break;
16201 case 'TrailingMinusNumbers': break;
16202 case 'FormatSettings': break;
16203 case 'FieldType': break;
16204 case 'Delimiters': break;
16205 case 'Tab': break;
16206 case 'Comma': break;
16207 case 'AutoFormatName': break;
16208 case 'VersionLastEdit': break;
16209 case 'VersionLastRefresh': break;
16210 default: seen = false;
16211 } break;
16212
16213 case 'DataValidation':
16214 switch(Rn[3]) {
16215 case 'Range': break;
16216
16217 case 'Type': break;
16218 case 'Min': break;
16219 case 'Max': break;
16220 case 'Sort': break;
16221 case 'Descending': break;
16222 case 'Order': break;
16223 case 'CaseSensitive': break;
16224 case 'Value': break;
16225 case 'ErrorStyle': break;
16226 case 'ErrorMessage': break;
16227 case 'ErrorTitle': break;
16228 case 'InputMessage': break;
16229 case 'InputTitle': break;
16230 case 'ComboHide': break;
16231 case 'InputHide': break;
16232 case 'Condition': break;
16233 case 'Qualifier': break;
16234 case 'UseBlank': break;
16235 case 'Value1': break;
16236 case 'Value2': break;
16237 case 'Format': break;
16238
16239 case 'CellRangeList': break;
16240 default: seen = false;
16241 } break;
16242
16243 case 'Sorting':
16244 case 'ConditionalFormatting':
16245 switch(Rn[3]) {
16246 case 'Range': break;
16247 case 'Type': break;
16248 case 'Min': break;
16249 case 'Max': break;
16250 case 'Sort': break;
16251 case 'Descending': break;
16252 case 'Order': break;
16253 case 'CaseSensitive': break;
16254 case 'Value': break;
16255 case 'ErrorStyle': break;
16256 case 'ErrorMessage': break;
16257 case 'ErrorTitle': break;
16258 case 'CellRangeList': break;
16259 case 'InputMessage': break;
16260 case 'InputTitle': break;
16261 case 'ComboHide': break;
16262 case 'InputHide': break;
16263 case 'Condition': break;
16264 case 'Qualifier': break;
16265 case 'UseBlank': break;
16266 case 'Value1': break;
16267 case 'Value2': break;
16268 case 'Format': break;
16269 default: seen = false;
16270 } break;
16271
16272 /* MapInfo (schema) */
16273 case 'MapInfo': case 'Schema': case 'data': switch(Rn[3]) {
16274 case 'Map': break;
16275 case 'Entry': break;
16276 case 'Range': break;
16277 case 'XPath': break;
16278 case 'Field': break;
16279 case 'XSDType': break;
16280 case 'FilterOn': break;
16281 case 'Aggregate': break;
16282 case 'ElementType': break;
16283 case 'AttributeType': break;
16284 /* These are from xsd (XML Schema Definition) */
16285 case 'schema':
16286 case 'element':
16287 case 'complexType':
16288 case 'datatype':
16289 case 'all':
16290 case 'attribute':
16291 case 'extends': break;
16292
16293 case 'row': break;
16294 default: seen = false;
16295 } break;
16296
16297 /* SmartTags (can be anything) */
16298 case 'SmartTags': break;
16299
16300 default: seen = false; break;
16301 }
16302 if(seen) break;
16303 /* CustomDocumentProperties */
16304 if(Rn[3].match(/!\[CDATA/)) break;
16305 if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
16306 if(state[state.length-1][0]==='CustomDocumentProperties') {
16307 if(Rn[0].slice(-2) === "/>") break;
16308 else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn[3], cp, str.slice(pidx, Rn.index));
16309 else { cp = Rn; pidx = Rn.index + Rn[0].length; }
16310 break;
16311 }
16312 if(opts.WTF) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|");
16313 }
16314 var out = ({});
16315 if(!opts.bookSheets && !opts.bookProps) out.Sheets = sheets;
16316 out.SheetNames = sheetnames;
16317 out.Workbook = Workbook;
16318 out.SSF = SSF.get_table();
16319 out.Props = Props;
16320 out.Custprops = Custprops;
16321 return out;
16322}
16323
16324function parse_xlml(data, opts) {
16325 fix_read_opts(opts=opts||{});
16326 switch(opts.type||"base64") {
16327 case "base64": return parse_xlml_xml(Base64.decode(data), opts);
16328 case "binary": case "buffer": case "file": return parse_xlml_xml(data, opts);
16329 case "array": return parse_xlml_xml(a2s(data), opts);
16330 }
16331}
16332
16333/* TODO */
16334function write_props_xlml(wb, opts) {
16335 var o = [];
16336 /* DocumentProperties */
16337 if(wb.Props) o.push(xlml_write_docprops(wb.Props, opts));
16338 /* CustomDocumentProperties */
16339 if(wb.Custprops) o.push(xlml_write_custprops(wb.Props, wb.Custprops, opts));
16340 return o.join("");
16341}
16342/* TODO */
16343function write_wb_xlml() {
16344 /* OfficeDocumentSettings */
16345 /* ExcelWorkbook */
16346 return "";
16347}
16348/* TODO */
16349function write_sty_xlml(wb, opts) {
16350 /* Styles */
16351 var styles = ['<Style ss:ID="Default" ss:Name="Normal"><NumberFormat/></Style>'];
16352 opts.cellXfs.forEach(function(xf, id) {
16353 var payload = [];
16354 payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])}));
16355
16356 var o = {"ss:ID": "s" + (21+id)};
16357 styles.push(writextag('Style', payload.join(""), o));
16358 });
16359 return writextag("Styles", styles.join(""));
16360}
16361function write_name_xlml(n) { return writextag("NamedRange", null, {"ss:Name": n.Name, "ss:RefersTo":"=" + a1_to_rc(n.Ref, {r:0,c:0})}); }
16362function write_names_xlml(wb) {
16363 if(!((wb||{}).Workbook||{}).Names) return "";
16364var names = wb.Workbook.Names;
16365 var out = [];
16366 for(var i = 0; i < names.length; ++i) {
16367 var n = names[i];
16368 if(n.Sheet != null) continue;
16369 if(n.Name.match(/^_xlfn\./)) continue;
16370 out.push(write_name_xlml(n));
16371 }
16372 return writextag("Names", out.join(""));
16373}
16374function write_ws_xlml_names(ws, opts, idx, wb) {
16375 if(!ws) return "";
16376 if(!((wb||{}).Workbook||{}).Names) return "";
16377var names = wb.Workbook.Names;
16378 var out = [];
16379 for(var i = 0; i < names.length; ++i) {
16380 var n = names[i];
16381 if(n.Sheet != idx) continue;
16382 /*switch(n.Name) {
16383 case "_": continue;
16384 }*/
16385 if(n.Name.match(/^_xlfn\./)) continue;
16386 out.push(write_name_xlml(n));
16387 }
16388 return out.join("");
16389}
16390/* WorksheetOptions */
16391function write_ws_xlml_wsopts(ws, opts, idx, wb) {
16392 if(!ws) return "";
16393 var o = [];
16394 /* NOTE: spec technically allows any order, but stick with implied order */
16395
16396 /* FitToPage */
16397 /* DoNotDisplayColHeaders */
16398 /* DoNotDisplayRowHeaders */
16399 /* ViewableRange */
16400 /* Selection */
16401 /* GridlineColor */
16402 /* Name */
16403 /* ExcelWorksheetType */
16404 /* IntlMacro */
16405 /* Unsynced */
16406 /* Selected */
16407 /* CodeName */
16408
16409 if(ws['!margins']) {
16410 o.push("<PageSetup>");
16411 if(ws['!margins'].header) o.push(writextag("Header", null, {'x:Margin':ws['!margins'].header}));
16412 if(ws['!margins'].footer) o.push(writextag("Footer", null, {'x:Margin':ws['!margins'].footer}));
16413 o.push(writextag("PageMargins", null, {
16414 'x:Bottom': ws['!margins'].bottom || "0.75",
16415 'x:Left': ws['!margins'].left || "0.7",
16416 'x:Right': ws['!margins'].right || "0.7",
16417 'x:Top': ws['!margins'].top || "0.75"
16418 }));
16419 o.push("</PageSetup>");
16420 }
16421
16422 /* PageSetup */
16423 /* DisplayPageBreak */
16424 /* TransitionExpressionEvaluation */
16425 /* TransitionFormulaEntry */
16426 /* Print */
16427 /* Zoom */
16428 /* PageLayoutZoom */
16429 /* PageBreakZoom */
16430 /* ShowPageBreakZoom */
16431 /* DefaultRowHeight */
16432 /* DefaultColumnWidth */
16433 /* StandardWidth */
16434
16435 if(wb && wb.Workbook && wb.Workbook.Sheets && wb.Workbook.Sheets[idx]) {
16436 /* Visible */
16437 if(wb.Workbook.Sheets[idx].Hidden) o.push(writextag("Visible", (wb.Workbook.Sheets[idx].Hidden == 1 ? "SheetHidden" : "SheetVeryHidden"), {}));
16438 else {
16439 /* Selected */
16440 for(var i = 0; i < idx; ++i) if(wb.Workbook.Sheets[i] && !wb.Workbook.Sheets[i].Hidden) break;
16441 if(i == idx) o.push("<Selected/>");
16442 }
16443 }
16444
16445 /* LeftColumnVisible */
16446
16447 if(((((wb||{}).Workbook||{}).Views||[])[0]||{}).RTL) o.push("<DisplayRightToLeft/>");
16448
16449 /* GridlineColorIndex */
16450 /* DisplayFormulas */
16451 /* DoNotDisplayGridlines */
16452 /* DoNotDisplayHeadings */
16453 /* DoNotDisplayOutline */
16454 /* ApplyAutomaticOutlineStyles */
16455 /* NoSummaryRowsBelowDetail */
16456 /* NoSummaryColumnsRightDetail */
16457 /* DoNotDisplayZeros */
16458 /* ActiveRow */
16459 /* ActiveColumn */
16460 /* FilterOn */
16461 /* RangeSelection */
16462 /* TopRowVisible */
16463 /* TopRowBottomPane */
16464 /* LeftColumnRightPane */
16465 /* ActivePane */
16466 /* SplitHorizontal */
16467 /* SplitVertical */
16468 /* FreezePanes */
16469 /* FrozenNoSplit */
16470 /* TabColorIndex */
16471 /* Panes */
16472
16473 /* NOTE: Password not supported in XLML Format */
16474 if(ws['!protect']) {
16475 o.push(writetag("ProtectContents", "True"));
16476 if(ws['!protect'].objects) o.push(writetag("ProtectObjects", "True"));
16477 if(ws['!protect'].scenarios) o.push(writetag("ProtectScenarios", "True"));
16478 if(ws['!protect'].selectLockedCells != null && !ws['!protect'].selectLockedCells) o.push(writetag("EnableSelection", "NoSelection"));
16479 else if(ws['!protect'].selectUnlockedCells != null && !ws['!protect'].selectUnlockedCells) o.push(writetag("EnableSelection", "UnlockedCells"));
16480 [
16481 [ "formatCells", "AllowFormatCells" ],
16482 [ "formatColumns", "AllowSizeCols" ],
16483 [ "formatRows", "AllowSizeRows" ],
16484 [ "insertColumns", "AllowInsertCols" ],
16485 [ "insertRows", "AllowInsertRows" ],
16486 [ "insertHyperlinks", "AllowInsertHyperlinks" ],
16487 [ "deleteColumns", "AllowDeleteCols" ],
16488 [ "deleteRows", "AllowDeleteRows" ],
16489 [ "sort", "AllowSort" ],
16490 [ "autoFilter", "AllowFilter" ],
16491 [ "pivotTables", "AllowUsePivotTables" ]
16492 ].forEach(function(x) { if(ws['!protect'][x[0]]) o.push("<"+x[1]+"/>"); });
16493 }
16494
16495 if(o.length == 0) return "";
16496 return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
16497}
16498function write_ws_xlml_comment(comments) {
16499 return comments.map(function(c) {
16500 // TODO: formatted text
16501 var t = xlml_unfixstr(c.t||"");
16502 var d =writextag("ss:Data", t, {"xmlns":"http://www.w3.org/TR/REC-html40"});
16503 return writextag("Comment", d, {"ss:Author":c.a});
16504 }).join("");
16505}
16506function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr){
16507 if(!cell || (cell.v == undefined && cell.f == undefined)) return "";
16508
16509 var attr = {};
16510 if(cell.f) attr["ss:Formula"] = "=" + escapexml(a1_to_rc(cell.f, addr));
16511 if(cell.F && cell.F.slice(0, ref.length) == ref) {
16512 var end = decode_cell(cell.F.slice(ref.length + 1));
16513 attr["ss:ArrayRange"] = "RC:R" + (end.r == addr.r ? "" : "[" + (end.r - addr.r) + "]") + "C" + (end.c == addr.c ? "" : "[" + (end.c - addr.c) + "]");
16514 }
16515
16516 if(cell.l && cell.l.Target) {
16517 attr["ss:HRef"] = escapexml(cell.l.Target);
16518 if(cell.l.Tooltip) attr["x:HRefScreenTip"] = escapexml(cell.l.Tooltip);
16519 }
16520
16521 if(ws['!merges']) {
16522 var marr = ws['!merges'];
16523 for(var mi = 0; mi != marr.length; ++mi) {
16524 if(marr[mi].s.c != addr.c || marr[mi].s.r != addr.r) continue;
16525 if(marr[mi].e.c > marr[mi].s.c) attr['ss:MergeAcross'] = marr[mi].e.c - marr[mi].s.c;
16526 if(marr[mi].e.r > marr[mi].s.r) attr['ss:MergeDown'] = marr[mi].e.r - marr[mi].s.r;
16527 }
16528 }
16529
16530 var t = "", p = "";
16531 switch(cell.t) {
16532 case 'z': if(!opts.sheetStubs) return ""; break;
16533 case 'n': t = 'Number'; p = String(cell.v); break;
16534 case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break;
16535 case 'e': t = 'Error'; p = BErr[cell.v]; break;
16536 case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break;
16537 case 's': t = 'String'; p = escapexlml(cell.v||""); break;
16538 }
16539 /* TODO: cell style */
16540 var os = get_cell_style(opts.cellXfs, cell, opts);
16541 attr["ss:StyleID"] = "s" + (21+os);
16542 attr["ss:Index"] = addr.c + 1;
16543 var _v = (cell.v != null ? p : "");
16544 var m = cell.t == 'z' ? "" : ('<Data ss:Type="' + t + '">' + _v + '</Data>');
16545
16546 if((cell.c||[]).length > 0) m += write_ws_xlml_comment(cell.c);
16547
16548 return writextag("Cell", m, attr);
16549}
16550function write_ws_xlml_row(R, row) {
16551 var o = '<Row ss:Index="' + (R+1) + '"';
16552 if(row) {
16553 if(row.hpt && !row.hpx) row.hpx = pt2px(row.hpt);
16554 if(row.hpx) o += ' ss:AutoFitHeight="0" ss:Height="' + row.hpx + '"';
16555 if(row.hidden) o += ' ss:Hidden="1"';
16556 }
16557 return o + '>';
16558}
16559/* TODO */
16560function write_ws_xlml_table(ws, opts, idx, wb) {
16561 if(!ws['!ref']) return "";
16562 var range = safe_decode_range(ws['!ref']);
16563 var marr = ws['!merges'] || [], mi = 0;
16564 var o = [];
16565 if(ws['!cols']) ws['!cols'].forEach(function(n, i) {
16566 process_col(n);
16567 var w = !!n.width;
16568 var p = col_obj_w(i, n);
16569 var k = {"ss:Index":i+1};
16570 if(w) k['ss:Width'] = width2px(p.width);
16571 if(n.hidden) k['ss:Hidden']="1";
16572 o.push(writextag("Column",null,k));
16573 });
16574 var dense = Array.isArray(ws);
16575 for(var R = range.s.r; R <= range.e.r; ++R) {
16576 var row = [write_ws_xlml_row(R, (ws['!rows']||[])[R])];
16577 for(var C = range.s.c; C <= range.e.c; ++C) {
16578 var skip = false;
16579 for(mi = 0; mi != marr.length; ++mi) {
16580 if(marr[mi].s.c > C) continue;
16581 if(marr[mi].s.r > R) continue;
16582 if(marr[mi].e.c < C) continue;
16583 if(marr[mi].e.r < R) continue;
16584 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
16585 break;
16586 }
16587 if(skip) continue;
16588 var addr = {r:R,c:C};
16589 var ref = encode_cell(addr), cell = dense ? (ws[R]||[])[C] : ws[ref];
16590 row.push(write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr));
16591 }
16592 row.push("</Row>");
16593 if(row.length > 2) o.push(row.join(""));
16594 }
16595 return o.join("");
16596}
16597function write_ws_xlml(idx, opts, wb) {
16598 var o = [];
16599 var s = wb.SheetNames[idx];
16600 var ws = wb.Sheets[s];
16601
16602 var t = ws ? write_ws_xlml_names(ws, opts, idx, wb) : "";
16603 if(t.length > 0) o.push("<Names>" + t + "</Names>");
16604
16605 /* Table */
16606 t = ws ? write_ws_xlml_table(ws, opts, idx, wb) : "";
16607 if(t.length > 0) o.push("<Table>" + t + "</Table>");
16608
16609 /* WorksheetOptions */
16610 o.push(write_ws_xlml_wsopts(ws, opts, idx, wb));
16611
16612 return o.join("");
16613}
16614function write_xlml(wb, opts) {
16615 if(!opts) opts = {};
16616 if(!wb.SSF) wb.SSF = SSF.get_table();
16617 if(wb.SSF) {
16618 make_ssf(SSF); SSF.load_table(wb.SSF);
16619 // $FlowIgnore
16620 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
16621 opts.ssf = wb.SSF;
16622 opts.cellXfs = [];
16623 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
16624 }
16625 var d = [];
16626 d.push(write_props_xlml(wb, opts));
16627 d.push(write_wb_xlml(wb, opts));
16628 d.push("");
16629 d.push("");
16630 for(var i = 0; i < wb.SheetNames.length; ++i)
16631 d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])}));
16632 d[2] = write_sty_xlml(wb, opts);
16633 d[3] = write_names_xlml(wb, opts);
16634 return XML_HEADER + writextag("Workbook", d.join(""), {
16635 'xmlns': XLMLNS.ss,
16636 'xmlns:o': XLMLNS.o,
16637 'xmlns:x': XLMLNS.x,
16638 'xmlns:ss': XLMLNS.ss,
16639 'xmlns:dt': XLMLNS.dt,
16640 'xmlns:html': XLMLNS.html
16641 });
16642}
16643/* [MS-OLEDS] 2.3.8 CompObjStream */
16644function parse_compobj(obj) {
16645 var v = {};
16646 var o = obj.content;
16647/* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
16648 o.l = 28;
16649
16650 v.AnsiUserType = o.read_shift(0, "lpstr-ansi");
16651 v.AnsiClipboardFormat = parse_ClipboardFormatOrAnsiString(o);
16652
16653 if(o.length - o.l <= 4) return v;
16654
16655 var m = o.read_shift(4);
16656 if(m == 0 || m > 40) return v;
16657 o.l-=4; v.Reserved1 = o.read_shift(0, "lpstr-ansi");
16658
16659 if(o.length - o.l <= 4) return v;
16660 m = o.read_shift(4);
16661 if(m !== 0x71b239f4) return v;
16662 v.UnicodeClipboardFormat = parse_ClipboardFormatOrUnicodeString(o);
16663
16664 m = o.read_shift(4);
16665 if(m == 0 || m > 40) return v;
16666 o.l-=4; v.Reserved2 = o.read_shift(0, "lpwstr");
16667}
16668
16669/*
16670 Continue logic for:
16671 - 2.4.58 Continue
16672 - 2.4.59 ContinueBigName
16673 - 2.4.60 ContinueFrt
16674 - 2.4.61 ContinueFrt11
16675 - 2.4.62 ContinueFrt12
16676*/
16677function slurp(R, blob, length, opts) {
16678 var l = length;
16679 var bufs = [];
16680 var d = blob.slice(blob.l,blob.l+l);
16681 if(opts && opts.enc && opts.enc.insitu) switch(R.n) {
16682 case 'BOF': case 'FilePass': case 'FileLock': case 'InterfaceHdr': case 'RRDInfo': case 'RRDHead': case 'UsrExcl': break;
16683 default:
16684 if(d.length === 0) break;
16685 opts.enc.insitu(d);
16686 }
16687 bufs.push(d);
16688 blob.l += l;
16689 var next = (XLSRecordEnum[__readUInt16LE(blob,blob.l)]);
16690 var start = 0;
16691 while(next != null && next.n.slice(0,8) === 'Continue') {
16692 l = __readUInt16LE(blob,blob.l+2);
16693 start = blob.l + 4;
16694 if(next.n == 'ContinueFrt') start += 4;
16695 else if(next.n.slice(0,11) == 'ContinueFrt') start += 12;
16696 bufs.push(blob.slice(start,blob.l+4+l));
16697 blob.l += 4+l;
16698 next = (XLSRecordEnum[__readUInt16LE(blob, blob.l)]);
16699 }
16700 var b = (bconcat(bufs));
16701 prep_blob(b, 0);
16702 var ll = 0; b.lens = [];
16703 for(var j = 0; j < bufs.length; ++j) { b.lens.push(ll); ll += bufs[j].length; }
16704 return R.f(b, b.length, opts);
16705}
16706
16707function safe_format_xf(p, opts, date1904) {
16708 if(p.t === 'z') return;
16709 if(!p.XF) return;
16710 var fmtid = 0;
16711 try {
16712 fmtid = p.z || p.XF.numFmtId || 0;
16713 if(opts.cellNF) p.z = SSF._table[fmtid];
16714 } catch(e) { if(opts.WTF) throw e; }
16715 if(!opts || opts.cellText !== false) try {
16716 if(p.t === 'e') { p.w = p.w || BErr[p.v]; }
16717 else if(fmtid === 0 || fmtid == "General") {
16718 if(p.t === 'n') {
16719 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
16720 else p.w = SSF._general_num(p.v);
16721 }
16722 else p.w = SSF._general(p.v);
16723 }
16724 else p.w = SSF.format(fmtid,p.v, {date1904:!!date1904});
16725 } catch(e) { if(opts.WTF) throw e; }
16726 if(opts.cellDates && fmtid && p.t == 'n' && SSF.is_date(SSF._table[fmtid] || String(fmtid))) {
16727 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); }
16728 }
16729}
16730
16731function make_cell(val, ixfe, t) {
16732 return ({v:val, ixfe:ixfe, t:t});
16733}
16734
16735// 2.3.2
16736function parse_workbook(blob, options) {
16737 var wb = ({opts:{}});
16738 var Sheets = {};
16739 if(DENSE != null && options.dense == null) options.dense = DENSE;
16740 var out = ((options.dense ? [] : {}));
16741 var Directory = {};
16742 var range = ({});
16743 var last_formula = null;
16744 var sst = ([]);
16745 var cur_sheet = "";
16746 var Preamble = {};
16747 var lastcell, last_cell = "", cc, cmnt, rngC, rngR;
16748 var sharedf = {};
16749 var arrayf = [];
16750 var temp_val;
16751 var country;
16752 var cell_valid = true;
16753 var XFs = []; /* XF records */
16754 var palette = [];
16755 var Workbook = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }), wsprops = {};
16756 var get_rgb = function getrgb(icv) {
16757 if(icv < 8) return XLSIcv[icv];
16758 if(icv < 64) return palette[icv-8] || XLSIcv[icv];
16759 return XLSIcv[icv];
16760 };
16761 var process_cell_style = function pcs(cell, line, options) {
16762 var xfd = line.XF.data;
16763 if(!xfd || !xfd.patternType || !options || !options.cellStyles) return;
16764 line.s = ({});
16765 line.s.patternType = xfd.patternType;
16766 var t;
16767 if((t = rgb2Hex(get_rgb(xfd.icvFore)))) { line.s.fgColor = {rgb:t}; }
16768 if((t = rgb2Hex(get_rgb(xfd.icvBack)))) { line.s.bgColor = {rgb:t}; }
16769 };
16770 var addcell = function addcell(cell, line, options) {
16771 if(file_depth > 1) return;
16772 if(options.sheetRows && cell.r >= options.sheetRows) cell_valid = false;
16773 if(!cell_valid) return;
16774 if(options.cellStyles && line.XF && line.XF.data) process_cell_style(cell, line, options);
16775 delete line.ixfe; delete line.XF;
16776 lastcell = cell;
16777 last_cell = encode_cell(cell);
16778 if(!range || !range.s || !range.e) range = {s:{r:0,c:0},e:{r:0,c:0}};
16779 if(cell.r < range.s.r) range.s.r = cell.r;
16780 if(cell.c < range.s.c) range.s.c = cell.c;
16781 if(cell.r + 1 > range.e.r) range.e.r = cell.r + 1;
16782 if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1;
16783 if(options.cellFormula && line.f) {
16784 for(var afi = 0; afi < arrayf.length; ++afi) {
16785 if(arrayf[afi][0].s.c > cell.c || arrayf[afi][0].s.r > cell.r) continue;
16786 if(arrayf[afi][0].e.c < cell.c || arrayf[afi][0].e.r < cell.r) continue;
16787 line.F = encode_range(arrayf[afi][0]);
16788 if(arrayf[afi][0].s.c != cell.c || arrayf[afi][0].s.r != cell.r) delete line.f;
16789 if(line.f) line.f = "" + stringify_formula(arrayf[afi][1], range, cell, supbooks, opts);
16790 break;
16791 }
16792 }
16793 {
16794 if(options.dense) {
16795 if(!out[cell.r]) out[cell.r] = [];
16796 out[cell.r][cell.c] = line;
16797 } else out[last_cell] = line;
16798 }
16799 };
16800 var opts = ({
16801 enc: false, // encrypted
16802 sbcch: 0, // cch in the preceding SupBook
16803 snames: [], // sheetnames
16804 sharedf: sharedf, // shared formulae by address
16805 arrayf: arrayf, // array formulae array
16806 rrtabid: [], // RRTabId
16807 lastuser: "", // Last User from WriteAccess
16808 biff: 8, // BIFF version
16809 codepage: 0, // CP from CodePage record
16810 winlocked: 0, // fLockWn from WinProtect
16811 cellStyles: !!options && !!options.cellStyles,
16812 WTF: !!options && !!options.wtf
16813 });
16814 if(options.password) opts.password = options.password;
16815 var themes;
16816 var merges = [];
16817 var objects = [];
16818 var colinfo = [], rowinfo = [];
16819 // eslint-disable-next-line no-unused-vars
16820 var defwidth = 0, defheight = 0; // twips / MDW respectively
16821 var seencol = false;
16822 var supbooks = ([]); // 1-indexed, will hold extern names
16823 supbooks.SheetNames = opts.snames;
16824 supbooks.sharedf = opts.sharedf;
16825 supbooks.arrayf = opts.arrayf;
16826 supbooks.names = [];
16827 supbooks.XTI = [];
16828 var last_Rn = '';
16829 var file_depth = 0; /* TODO: make a real stack */
16830 var BIFF2Fmt = 0, BIFF2FmtTable = [];
16831 var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */
16832 var last_lbl;
16833
16834 /* explicit override for some broken writers */
16835 opts.codepage = 1200;
16836 set_cp(1200);
16837 var seen_codepage = false;
16838 while(blob.l < blob.length - 1) {
16839 var s = blob.l;
16840 var RecordType = blob.read_shift(2);
16841 if(RecordType === 0 && last_Rn === 'EOF') break;
16842 var length = (blob.l === blob.length ? 0 : blob.read_shift(2));
16843 var R = XLSRecordEnum[RecordType];
16844 //console.log(RecordType.toString(16), RecordType, R, blob.l, length, blob.length);
16845 //if(!R) console.log(blob.slice(blob.l, blob.l + length));
16846 if(R && R.f) {
16847 if(options.bookSheets) {
16848 if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
16849 }
16850 last_Rn = R.n;
16851 if(R.r === 2 || R.r == 12) {
16852 var rt = blob.read_shift(2); length -= 2;
16853 if(!opts.enc && rt !== RecordType && (((rt&0xFF)<<8)|(rt>>8)) !== RecordType) throw new Error("rt mismatch: " + rt + "!=" + RecordType);
16854 if(R.r == 12){ blob.l += 10; length -= 10; } // skip FRT
16855 }
16856 //console.error(R,blob.l,length,blob.length);
16857 var val = ({});
16858 if(R.n === 'EOF') val = R.f(blob, length, opts);
16859 else val = slurp(R, blob, length, opts);
16860 var Rn = R.n;
16861if(file_depth == 0 && Rn != 'BOF') continue;
16862 /* nested switch statements to workaround V8 128 limit */
16863 switch(Rn) {
16864 /* Workbook Options */
16865 case 'Date1904':
16866wb.opts.Date1904 = Workbook.WBProps.date1904 = val; break;
16867 case 'WriteProtect': wb.opts.WriteProtect = true; break;
16868 case 'FilePass':
16869 if(!opts.enc) blob.l = 0;
16870 opts.enc = val;
16871 if(!options.password) throw new Error("File is password-protected");
16872 if(val.valid == null) throw new Error("Encryption scheme unsupported");
16873 if(!val.valid) throw new Error("Password is incorrect");
16874 break;
16875 case 'WriteAccess': opts.lastuser = val; break;
16876 case 'FileSharing': break; //TODO
16877 case 'CodePage':
16878 var cpval = Number(val);
16879 /* overrides based on test cases */
16880 switch(cpval) {
16881 case 0x5212: cpval = 1200; break;
16882 case 0x8000: cpval = 10000; break;
16883 case 0x8001: cpval = 1252; break;
16884 }
16885 set_cp(opts.codepage = cpval);
16886 seen_codepage = true;
16887 break;
16888 case 'RRTabId': opts.rrtabid = val; break;
16889 case 'WinProtect': opts.winlocked = val; break;
16890 case 'Template': break; // TODO
16891 case 'BookBool': break; // TODO
16892 case 'UsesELFs': break;
16893 case 'MTRSettings': break;
16894 case 'RefreshAll':
16895 case 'CalcCount':
16896 case 'CalcDelta':
16897 case 'CalcIter':
16898 case 'CalcMode':
16899 case 'CalcPrecision':
16900 case 'CalcSaveRecalc':
16901 wb.opts[Rn] = val; break;
16902 case 'CalcRefMode': opts.CalcRefMode = val; break; // TODO: implement R1C1
16903 case 'Uncalced': break;
16904 case 'ForceFullCalculation': wb.opts.FullCalc = val; break;
16905 case 'WsBool':
16906 if(val.fDialog) out["!type"] = "dialog";
16907 break; // TODO
16908 case 'XF':
16909 XFs.push(val); break;
16910 case 'ExtSST': break; // TODO
16911 case 'BookExt': break; // TODO
16912 case 'RichTextStream': break;
16913 case 'BkHim': break;
16914
16915 case 'SupBook':
16916 supbooks.push([val]);
16917 supbooks[supbooks.length-1].XTI = [];
16918 break;
16919 case 'ExternName':
16920 supbooks[supbooks.length-1].push(val);
16921 break;
16922 case 'Index': break; // TODO
16923 case 'Lbl':
16924 last_lbl = ({
16925 Name: val.Name,
16926 Ref: stringify_formula(val.rgce,range,null,supbooks,opts)
16927 });
16928 if(val.itab > 0) last_lbl.Sheet = val.itab - 1;
16929 supbooks.names.push(last_lbl);
16930 if(!supbooks[0]) { supbooks[0] = []; supbooks[0].XTI = []; }
16931 supbooks[supbooks.length-1].push(val);
16932 if(val.Name == "_xlnm._FilterDatabase" && val.itab > 0)
16933 if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d')
16934 FilterDatabases[val.itab - 1] = { ref: encode_range(val.rgce[0][0][1][2]) };
16935 break;
16936 case 'ExternCount': opts.ExternCount = val; break;
16937 case 'ExternSheet':
16938 if(supbooks.length == 0) { supbooks[0] = []; supbooks[0].XTI = []; }
16939 supbooks[supbooks.length - 1].XTI = supbooks[supbooks.length - 1].XTI.concat(val); supbooks.XTI = supbooks.XTI.concat(val); break;
16940 case 'NameCmt':
16941 /* TODO: search for correct name */
16942 if(opts.biff < 8) break;
16943 if(last_lbl != null) last_lbl.Comment = val[1];
16944 break;
16945
16946 case 'Protect': out["!protect"] = val; break; /* for sheet or book */
16947 case 'Password': if(val !== 0 && opts.WTF) console.error("Password verifier: " + val); break;
16948 case 'Prot4Rev': case 'Prot4RevPass': break; /*TODO: Revision Control*/
16949
16950 case 'BoundSheet8': {
16951 Directory[val.pos] = val;
16952 opts.snames.push(val.name);
16953 } break;
16954 case 'EOF': {
16955 if(--file_depth) break;
16956 if(range.e) {
16957 if(range.e.r > 0 && range.e.c > 0) {
16958 range.e.r--; range.e.c--;
16959 out["!ref"] = encode_range(range);
16960 if(options.sheetRows && options.sheetRows <= range.e.r) {
16961 var tmpri = range.e.r;
16962 range.e.r = options.sheetRows - 1;
16963 out["!fullref"] = out["!ref"];
16964 out["!ref"] = encode_range(range);
16965 range.e.r = tmpri;
16966 }
16967 range.e.r++; range.e.c++;
16968 }
16969 if(merges.length > 0) out["!merges"] = merges;
16970 if(objects.length > 0) out["!objects"] = objects;
16971 if(colinfo.length > 0) out["!cols"] = colinfo;
16972 if(rowinfo.length > 0) out["!rows"] = rowinfo;
16973 Workbook.Sheets.push(wsprops);
16974 }
16975 if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
16976 out = ((options.dense ? [] : {}));
16977 } break;
16978 case 'BOF': {
16979 if(opts.biff === 8) opts.biff = {
169800x0009:2,
169810x0209:3,
169820x0409:4
16983 }[RecordType] || {
169840x0200:2,
169850x0300:3,
169860x0400:4,
169870x0500:5,
169880x0600:8,
169890x0002:2,
169900x0007:2
16991 }[val.BIFFVer] || 8;
16992 if(opts.biff == 8 && val.BIFFVer == 0 && val.dt == 16) opts.biff = 2;
16993 if(file_depth++) break;
16994 cell_valid = true;
16995 out = ((options.dense ? [] : {}));
16996
16997 if(opts.biff < 8 && !seen_codepage) { seen_codepage = true; set_cp(opts.codepage = options.codepage || 1252); }
16998 if(opts.biff < 5) {
16999 if(cur_sheet === "") cur_sheet = "Sheet1";
17000 range = {s:{r:0,c:0},e:{r:0,c:0}};
17001 /* fake BoundSheet8 */
17002 var fakebs8 = {pos: blob.l - length, name:cur_sheet};
17003 Directory[fakebs8.pos] = fakebs8;
17004 opts.snames.push(cur_sheet);
17005 }
17006 else cur_sheet = (Directory[s] || {name:""}).name;
17007 if(val.dt == 0x20) out["!type"] = "chart";
17008 if(val.dt == 0x40) out["!type"] = "macro";
17009 merges = [];
17010 objects = [];
17011 opts.arrayf = arrayf = [];
17012 colinfo = []; rowinfo = [];
17013 defwidth = defheight = 0;
17014 seencol = false;
17015 wsprops = {Hidden:(Directory[s]||{hs:0}).hs, name:cur_sheet };
17016 } break;
17017
17018 case 'Number': case 'BIFF2NUM': case 'BIFF2INT': {
17019 if(out["!type"] == "chart") if(options.dense ? (out[val.r]||[])[val.c]: out[encode_cell({c:val.c, r:val.r})]) ++val.c;
17020 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe]||{}, v:val.val, t:'n'});
17021 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17022 safe_format_xf(temp_val, options, wb.opts.Date1904);
17023 addcell({c:val.c, r:val.r}, temp_val, options);
17024 } break;
17025 case 'BoolErr': {
17026 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t});
17027 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17028 safe_format_xf(temp_val, options, wb.opts.Date1904);
17029 addcell({c:val.c, r:val.r}, temp_val, options);
17030 } break;
17031 case 'RK': {
17032 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'});
17033 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17034 safe_format_xf(temp_val, options, wb.opts.Date1904);
17035 addcell({c:val.c, r:val.r}, temp_val, options);
17036 } break;
17037 case 'MulRk': {
17038 for(var j = val.c; j <= val.C; ++j) {
17039 var ixfe = val.rkrec[j-val.c][0];
17040 temp_val= ({ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'});
17041 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17042 safe_format_xf(temp_val, options, wb.opts.Date1904);
17043 addcell({c:j, r:val.r}, temp_val, options);
17044 }
17045 } break;
17046 case 'Formula': {
17047 if(val.val == 'String') { last_formula = val; break; }
17048 temp_val = make_cell(val.val, val.cell.ixfe, val.tt);
17049 temp_val.XF = XFs[temp_val.ixfe];
17050 if(options.cellFormula) {
17051 var _f = val.formula;
17052 if(_f && _f[0] && _f[0][0] && _f[0][0][0] == 'PtgExp') {
17053 var _fr = _f[0][0][1][0], _fc = _f[0][0][1][1];
17054 var _fe = encode_cell({r:_fr, c:_fc});
17055 if(sharedf[_fe]) temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
17056 else temp_val.F = ((options.dense ? (out[_fr]||[])[_fc]: out[_fe]) || {}).F;
17057 } else temp_val.f = ""+stringify_formula(val.formula,range,val.cell,supbooks, opts);
17058 }
17059 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17060 safe_format_xf(temp_val, options, wb.opts.Date1904);
17061 addcell(val.cell, temp_val, options);
17062 last_formula = val;
17063 } break;
17064 case 'String': {
17065 if(last_formula) { /* technically always true */
17066 last_formula.val = val;
17067 temp_val = make_cell(val, last_formula.cell.ixfe, 's');
17068 temp_val.XF = XFs[temp_val.ixfe];
17069 if(options.cellFormula) {
17070 temp_val.f = ""+stringify_formula(last_formula.formula, range, last_formula.cell, supbooks, opts);
17071 }
17072 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17073 safe_format_xf(temp_val, options, wb.opts.Date1904);
17074 addcell(last_formula.cell, temp_val, options);
17075 last_formula = null;
17076 } else throw new Error("String record expects Formula");
17077 } break;
17078 case 'Array': {
17079 arrayf.push(val);
17080 var _arraystart = encode_cell(val[0].s);
17081 cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart];
17082 if(options.cellFormula && cc) {
17083 if(!last_formula) break; /* technically unreachable */
17084 if(!_arraystart || !cc) break;
17085 cc.f = ""+stringify_formula(val[1], range, val[0], supbooks, opts);
17086 cc.F = encode_range(val[0]);
17087 }
17088 } break;
17089 case 'ShrFmla': {
17090 if(!cell_valid) break;
17091 if(!options.cellFormula) break;
17092 if(last_cell) {
17093 /* TODO: capture range */
17094 if(!last_formula) break; /* technically unreachable */
17095 sharedf[encode_cell(last_formula.cell)]= val[0];
17096 cc = options.dense ? (out[last_formula.cell.r]||[])[last_formula.cell.c] : out[encode_cell(last_formula.cell)];
17097 (cc||{}).f = ""+stringify_formula(val[0], range, lastcell, supbooks, opts);
17098 }
17099 } break;
17100 case 'LabelSst':
17101 temp_val=make_cell(sst[val.isst].t, val.ixfe, 's');
17102 if(sst[val.isst].h) temp_val.h = sst[val.isst].h;
17103 temp_val.XF = XFs[temp_val.ixfe];
17104 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17105 safe_format_xf(temp_val, options, wb.opts.Date1904);
17106 addcell({c:val.c, r:val.r}, temp_val, options);
17107 break;
17108 case 'Blank': if(options.sheetStubs) {
17109 temp_val = ({ixfe: val.ixfe, XF: XFs[val.ixfe], t:'z'});
17110 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17111 safe_format_xf(temp_val, options, wb.opts.Date1904);
17112 addcell({c:val.c, r:val.r}, temp_val, options);
17113 } break;
17114 case 'MulBlank': if(options.sheetStubs) {
17115 for(var _j = val.c; _j <= val.C; ++_j) {
17116 var _ixfe = val.ixfe[_j-val.c];
17117 temp_val= ({ixfe:_ixfe, XF:XFs[_ixfe], t:'z'});
17118 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17119 safe_format_xf(temp_val, options, wb.opts.Date1904);
17120 addcell({c:_j, r:val.r}, temp_val, options);
17121 }
17122 } break;
17123 case 'RString':
17124 case 'Label': case 'BIFF2STR':
17125 temp_val=make_cell(val.val, val.ixfe, 's');
17126 temp_val.XF = XFs[temp_val.ixfe];
17127 if(BIFF2Fmt > 0) temp_val.z = BIFF2FmtTable[(temp_val.ixfe>>8) & 0x1F];
17128 safe_format_xf(temp_val, options, wb.opts.Date1904);
17129 addcell({c:val.c, r:val.r}, temp_val, options);
17130 break;
17131
17132 case 'Dimensions': {
17133 if(file_depth === 1) range = val; /* TODO: stack */
17134 } break;
17135 case 'SST': {
17136 sst = val;
17137 } break;
17138 case 'Format': { /* val = [id, fmt] */
17139 if(opts.biff == 4) {
17140 BIFF2FmtTable[BIFF2Fmt++] = val[1];
17141 for(var b4idx = 0; b4idx < BIFF2Fmt + 163; ++b4idx) if(SSF._table[b4idx] == val[1]) break;
17142 if(b4idx >= 163) SSF.load(val[1], BIFF2Fmt + 163);
17143 }
17144 else SSF.load(val[1], val[0]);
17145 } break;
17146 case 'BIFF2FORMAT': {
17147 BIFF2FmtTable[BIFF2Fmt++] = val;
17148 for(var b2idx = 0; b2idx < BIFF2Fmt + 163; ++b2idx) if(SSF._table[b2idx] == val) break;
17149 if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163);
17150 } break;
17151
17152 case 'MergeCells': merges = merges.concat(val); break;
17153
17154 case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break;
17155 case 'TxO': opts.lastobj.TxO = val; break;
17156 case 'ImData': opts.lastobj.ImData = val; break;
17157
17158 case 'HLink': {
17159 for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
17160 for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
17161 cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
17162 if(cc) cc.l = val[1];
17163 }
17164 } break;
17165 case 'HLinkTooltip': {
17166 for(rngR = val[0].s.r; rngR <= val[0].e.r; ++rngR)
17167 for(rngC = val[0].s.c; rngC <= val[0].e.c; ++rngC) {
17168 cc = options.dense ? (out[rngR]||[])[rngC] : out[encode_cell({c:rngC,r:rngR})];
17169 if(cc && cc.l) cc.l.Tooltip = val[1];
17170 }
17171 } break;
17172
17173 /* Comments */
17174 case 'Note': {
17175 if(opts.biff <= 5 && opts.biff >= 2) break; /* TODO: BIFF5 */
17176 cc = options.dense ? (out[val[0].r]||[])[val[0].c] : out[encode_cell(val[0])];
17177 var noteobj = objects[val[2]];
17178 if(!cc) {
17179 if(options.dense) {
17180 if(!out[val[0].r]) out[val[0].r] = [];
17181 cc = out[val[0].r][val[0].c] = ({t:"z"});
17182 } else {
17183 cc = out[encode_cell(val[0])] = ({t:"z"});
17184 }
17185 range.e.r = Math.max(range.e.r, val[0].r);
17186 range.s.r = Math.min(range.s.r, val[0].r);
17187 range.e.c = Math.max(range.e.c, val[0].c);
17188 range.s.c = Math.min(range.s.c, val[0].c);
17189 }
17190 if(!cc.c) cc.c = [];
17191 cmnt = {a:val[1],t:noteobj.TxO.t};
17192 cc.c.push(cmnt);
17193 } break;
17194
17195 default: switch(R.n) { /* nested */
17196 case 'ClrtClient': break;
17197 case 'XFExt': update_xfext(XFs[val.ixfe], val.ext); break;
17198
17199 case 'DefColWidth': defwidth = val; break;
17200 case 'DefaultRowHeight': defheight = val[1]; break; // TODO: flags
17201
17202 case 'ColInfo': {
17203 if(!opts.cellStyles) break;
17204 while(val.e >= val.s) {
17205 colinfo[val.e--] = { width: val.w/256 };
17206 if(!seencol) { seencol = true; find_mdw_colw(val.w/256); }
17207 process_col(colinfo[val.e+1]);
17208 }
17209 } break;
17210 case 'Row': {
17211 var rowobj = {};
17212 if(val.level != null) { rowinfo[val.r] = rowobj; rowobj.level = val.level; }
17213 if(val.hidden) { rowinfo[val.r] = rowobj; rowobj.hidden = true; }
17214 if(val.hpt) {
17215 rowinfo[val.r] = rowobj;
17216 rowobj.hpt = val.hpt; rowobj.hpx = pt2px(val.hpt);
17217 }
17218 } break;
17219
17220 case 'LeftMargin':
17221 case 'RightMargin':
17222 case 'TopMargin':
17223 case 'BottomMargin':
17224 if(!out['!margins']) default_margins(out['!margins'] = {});
17225 out['!margins'][Rn.slice(0,-6).toLowerCase()] = val;
17226 break;
17227
17228 case 'Setup': // TODO
17229 if(!out['!margins']) default_margins(out['!margins'] = {});
17230 out['!margins'].header = val.header;
17231 out['!margins'].footer = val.footer;
17232 break;
17233
17234 case 'Window2': // TODO
17235 // $FlowIgnore
17236 if(val.RTL) Workbook.Views[0].RTL = true;
17237 break;
17238
17239 case 'Header': break; // TODO
17240 case 'Footer': break; // TODO
17241 case 'HCenter': break; // TODO
17242 case 'VCenter': break; // TODO
17243 case 'Pls': break; // TODO
17244 case 'GCW': break;
17245 case 'LHRecord': break;
17246 case 'DBCell': break; // TODO
17247 case 'EntExU2': break; // TODO
17248 case 'SxView': break; // TODO
17249 case 'Sxvd': break; // TODO
17250 case 'SXVI': break; // TODO
17251 case 'SXVDEx': break; // TODO
17252 case 'SxIvd': break; // TODO
17253 case 'SXString': break; // TODO
17254 case 'Sync': break;
17255 case 'Addin': break;
17256 case 'SXDI': break; // TODO
17257 case 'SXLI': break; // TODO
17258 case 'SXEx': break; // TODO
17259 case 'QsiSXTag': break; // TODO
17260 case 'Selection': break;
17261 case 'Feat': break;
17262 case 'FeatHdr': case 'FeatHdr11': break;
17263 case 'Feature11': case 'Feature12': case 'List12': break;
17264 case 'Country': country = val; break;
17265 case 'RecalcId': break;
17266 case 'DxGCol': break; // TODO: htmlify
17267 case 'Fbi': case 'Fbi2': case 'GelFrame': break;
17268 case 'Font': break; // TODO
17269 case 'XFCRC': break; // TODO
17270 case 'Style': break; // TODO
17271 case 'StyleExt': break; // TODO
17272 case 'Palette': palette = val; break;
17273 case 'Theme': themes = val; break;
17274 /* Protection */
17275 case 'ScenarioProtect': break;
17276 case 'ObjProtect': break;
17277
17278 /* Conditional Formatting */
17279 case 'CondFmt12': break;
17280
17281 /* Table */
17282 case 'Table': break; // TODO
17283 case 'TableStyles': break; // TODO
17284 case 'TableStyle': break; // TODO
17285 case 'TableStyleElement': break; // TODO
17286
17287 /* PivotTable */
17288 case 'SXStreamID': break; // TODO
17289 case 'SXVS': break; // TODO
17290 case 'DConRef': break; // TODO
17291 case 'SXAddl': break; // TODO
17292 case 'DConBin': break; // TODO
17293 case 'DConName': break; // TODO
17294 case 'SXPI': break; // TODO
17295 case 'SxFormat': break; // TODO
17296 case 'SxSelect': break; // TODO
17297 case 'SxRule': break; // TODO
17298 case 'SxFilt': break; // TODO
17299 case 'SxItm': break; // TODO
17300 case 'SxDXF': break; // TODO
17301
17302 /* Scenario Manager */
17303 case 'ScenMan': break;
17304
17305 /* Data Consolidation */
17306 case 'DCon': break;
17307
17308 /* Watched Cell */
17309 case 'CellWatch': break;
17310
17311 /* Print Settings */
17312 case 'PrintRowCol': break;
17313 case 'PrintGrid': break;
17314 case 'PrintSize': break;
17315
17316 case 'XCT': break;
17317 case 'CRN': break;
17318
17319 case 'Scl': {
17320 //console.log("Zoom Level:", val[0]/val[1],val);
17321 } break;
17322 case 'SheetExt': {
17323 /* empty */
17324 } break;
17325 case 'SheetExtOptional': {
17326 /* empty */
17327 } break;
17328
17329 /* VBA */
17330 case 'ObNoMacros': {
17331 /* empty */
17332 } break;
17333 case 'ObProj': {
17334 /* empty */
17335 } break;
17336 case 'CodeName': {
17337if(!cur_sheet) Workbook.WBProps.CodeName = val || "ThisWorkbook";
17338 else wsprops.CodeName = val || wsprops.name;
17339 } break;
17340 case 'GUIDTypeLib': {
17341 /* empty */
17342 } break;
17343
17344 case 'WOpt': break; // TODO: WTF?
17345 case 'PhoneticInfo': break;
17346
17347 case 'OleObjectSize': break;
17348
17349 /* Differential Formatting */
17350 case 'DXF': case 'DXFN': case 'DXFN12': case 'DXFN12List': case 'DXFN12NoCB': break;
17351
17352 /* Data Validation */
17353 case 'Dv': case 'DVal': break;
17354
17355 /* Data Series */
17356 case 'BRAI': case 'Series': case 'SeriesText': break;
17357
17358 /* Data Connection */
17359 case 'DConn': break;
17360 case 'DbOrParamQry': break;
17361 case 'DBQueryExt': break;
17362
17363 case 'OleDbConn': break;
17364 case 'ExtString': break;
17365
17366 /* Formatting */
17367 case 'IFmtRecord': break;
17368 case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
17369
17370 /* Explicitly Ignored */
17371 case 'Excel9File': break;
17372 case 'Units': break;
17373 case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break;
17374 case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break;
17375 /* View Stuff */
17376 case 'Window1': case 'HideObj': case 'GridSet': case 'Guts':
17377 case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd': break;
17378 case 'Pane': break;
17379 default: switch(R.n) { /* nested */
17380 /* Chart */
17381 case 'Dat':
17382 case 'Begin': case 'End':
17383 case 'StartBlock': case 'EndBlock':
17384 case 'Frame': case 'Area':
17385 case 'Axis': case 'AxisLine': case 'Tick': break;
17386 case 'AxesUsed':
17387 case 'CrtLayout12': case 'CrtLayout12A': case 'CrtLink': case 'CrtLine': case 'CrtMlFrt': case 'CrtMlFrtContinue': break;
17388 case 'LineFormat': case 'AreaFormat':
17389 case 'Chart': case 'Chart3d': case 'Chart3DBarShape': case 'ChartFormat': case 'ChartFrtInfo': break;
17390 case 'PlotArea': case 'PlotGrowth': break;
17391 case 'SeriesList': case 'SerParent': case 'SerAuxTrend': break;
17392 case 'DataFormat': case 'SerToCrt': case 'FontX': break;
17393 case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
17394 case 'ShtProps': break;
17395 case 'DefaultText': case 'Text': case 'CatLab': break;
17396 case 'DataLabExtContents': break;
17397 case 'Legend': case 'LegendException': break;
17398 case 'Pie': case 'Scatter': break;
17399 case 'PieFormat': case 'MarkerFormat': break;
17400 case 'StartObject': case 'EndObject': break;
17401 case 'AlRuns': case 'ObjectLink': break;
17402 case 'SIIndex': break;
17403 case 'AttachedLabel': case 'YMult': break;
17404
17405 /* Chart Group */
17406 case 'Line': case 'Bar': break;
17407 case 'Surf': break;
17408
17409 /* Axis Group */
17410 case 'AxisParent': break;
17411 case 'Pos': break;
17412 case 'ValueRange': break;
17413
17414 /* Pivot Chart */
17415 case 'SXViewEx9': break; // TODO
17416 case 'SXViewLink': break;
17417 case 'PivotChartBits': break;
17418 case 'SBaseRef': break;
17419 case 'TextPropsStream': break;
17420
17421 /* Chart Misc */
17422 case 'LnExt': break;
17423 case 'MkrExt': break;
17424 case 'CrtCoopt': break;
17425
17426 /* Query Table */
17427 case 'Qsi': case 'Qsif': case 'Qsir': case 'QsiSXTag': break;
17428 case 'TxtQry': break;
17429
17430 /* Filter */
17431 case 'FilterMode': break;
17432 case 'AutoFilter': case 'AutoFilterInfo': break;
17433 case 'AutoFilter12': break;
17434 case 'DropDownObjIds': break;
17435 case 'Sort': break;
17436 case 'SortData': break;
17437
17438 /* Drawing */
17439 case 'ShapePropsStream': break;
17440 case 'MsoDrawing': case 'MsoDrawingGroup': case 'MsoDrawingSelection': break;
17441 /* Pub Stuff */
17442 case 'WebPub': case 'AutoWebPub': break;
17443
17444 /* Print Stuff */
17445 case 'HeaderFooter': case 'HFPicture': case 'PLV':
17446 case 'HorizontalPageBreaks': case 'VerticalPageBreaks': break;
17447 /* Behavioral */
17448 case 'Backup': case 'CompressPictures': case 'Compat12': break;
17449
17450 /* Should not Happen */
17451 case 'Continue': case 'ContinueFrt12': break;
17452
17453 /* Future Records */
17454 case 'FrtFontList': case 'FrtWrapper': break;
17455
17456 default: switch(R.n) { /* nested */
17457 /* BIFF5 records */
17458 case 'TabIdConf': case 'Radar': case 'RadarArea': case 'DropBar': case 'Intl': case 'CoordList': case 'SerAuxErrBar': break;
17459
17460 /* BIFF2-4 records */
17461 case 'BIFF2FONTCLR': case 'BIFF2FMTCNT': case 'BIFF2FONTXTRA': break;
17462 case 'BIFF2XF': case 'BIFF3XF': case 'BIFF4XF': break;
17463 case 'BIFF4FMTCNT': case 'BIFF2ROW': case 'BIFF2WINDOW2': break;
17464
17465 /* Miscellaneous */
17466 case 'SCENARIO': case 'DConBin': case 'PicF': case 'DataLabExt':
17467 case 'Lel': case 'BopPop': case 'BopPopCustom': case 'RealTimeData':
17468 case 'Name': break;
17469 case 'LHNGraph': case 'FnGroupName': case 'AddMenu': case 'LPr': break;
17470 case 'ListObj': case 'ListField': break;
17471 case 'RRSort': break;
17472 case 'BigName': break;
17473 case 'ToolbarHdr': case 'ToolbarEnd': break;
17474 case 'DDEObjName': break;
17475 case 'FRTArchId$': break;
17476 default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
17477 }}}}
17478 } else blob.l += length;
17479 }
17480 wb.SheetNames=keys(Directory).sort(function(a,b) { return Number(a) - Number(b); }).map(function(x){return Directory[x].name;});
17481 if(!options.bookSheets) wb.Sheets=Sheets;
17482 if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; });
17483 wb.Preamble=Preamble;
17484 wb.Strings = sst;
17485 wb.SSF = SSF.get_table();
17486 if(opts.enc) wb.Encryption = opts.enc;
17487 if(themes) wb.Themes = themes;
17488 wb.Metadata = {};
17489 if(country !== undefined) wb.Metadata.Country = country;
17490 if(supbooks.names.length > 0) Workbook.Names = supbooks.names;
17491 wb.Workbook = Workbook;
17492 return wb;
17493}
17494
17495/* TODO: split props*/
17496var PSCLSID = {
17497 SI: "e0859ff2f94f6810ab9108002b27b3d9",
17498 DSI: "02d5cdd59c2e1b10939708002b2cf9ae",
17499 UDI: "05d5cdd59c2e1b10939708002b2cf9ae"
17500};
17501function parse_xls_props(cfb, props, o) {
17502 /* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
17503 var DSI = CFB.find(cfb, '!DocumentSummaryInformation');
17504 if(DSI && DSI.size > 0) try {
17505 var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI, PSCLSID.DSI);
17506 for(var d in DocSummary) props[d] = DocSummary[d];
17507 } catch(e) {if(o.WTF) throw e;/* empty */}
17508
17509 /* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
17510 var SI = CFB.find(cfb, '!SummaryInformation');
17511 if(SI && SI.size > 0) try {
17512 var Summary = parse_PropertySetStream(SI, SummaryPIDSI, PSCLSID.SI);
17513 for(var s in Summary) if(props[s] == null) props[s] = Summary[s];
17514 } catch(e) {if(o.WTF) throw e;/* empty */}
17515
17516 if(props.HeadingPairs && props.TitlesOfParts) {
17517 load_props_pairs(props.HeadingPairs, props.TitlesOfParts, props, o);
17518 delete props.HeadingPairs; delete props.TitlesOfParts;
17519 }
17520}
17521function write_xls_props(wb, cfb) {
17522 var DSEntries = [], SEntries = [], CEntries = [];
17523 var i = 0, Keys;
17524 if(wb.Props) {
17525 Keys = keys(wb.Props);
17526 // $FlowIgnore
17527 for(i = 0; i < Keys.length; ++i) (Object.prototype.hasOwnProperty.call(DocSummaryRE, Keys[i]) ? DSEntries : Object.prototype.hasOwnProperty.call(SummaryRE, Keys[i]) ? SEntries : CEntries).push([Keys[i], wb.Props[Keys[i]]]);
17528 }
17529 if(wb.Custprops) {
17530 Keys = keys(wb.Custprops);
17531 // $FlowIgnore
17532 for(i = 0; i < Keys.length; ++i) if(!Object.prototype.hasOwnProperty.call((wb.Props||{}), Keys[i])) (Object.prototype.hasOwnProperty.call(DocSummaryRE, Keys[i]) ? DSEntries : Object.prototype.hasOwnProperty.call(SummaryRE, Keys[i]) ? SEntries : CEntries).push([Keys[i], wb.Custprops[Keys[i]]]);
17533 }
17534 var CEntries2 = [];
17535 for(i = 0; i < CEntries.length; ++i) {
17536 if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue;
17537 if(CEntries[i][1] == null) continue;
17538 CEntries2.push(CEntries[i]);
17539 }
17540 if(SEntries.length) CFB.utils.cfb_add(cfb, "/\u0005SummaryInformation", write_PropertySetStream(SEntries, PSCLSID.SI, SummaryRE, SummaryPIDSI));
17541 if(DSEntries.length || CEntries2.length) CFB.utils.cfb_add(cfb, "/\u0005DocumentSummaryInformation", write_PropertySetStream(DSEntries, PSCLSID.DSI, DocSummaryRE, DocSummaryPIDDSI, CEntries2.length ? CEntries2 : null, PSCLSID.UDI));
17542}
17543
17544function parse_xlscfb(cfb, options) {
17545if(!options) options = {};
17546fix_read_opts(options);
17547reset_cp();
17548if(options.codepage) set_ansi(options.codepage);
17549var CompObj, WB;
17550if(cfb.FullPaths) {
17551 if(CFB.find(cfb, '/encryption')) throw new Error("File is password-protected");
17552 CompObj = CFB.find(cfb, '!CompObj');
17553 WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book');
17554} else {
17555 switch(options.type) {
17556 case 'base64': cfb = s2a(Base64.decode(cfb)); break;
17557 case 'binary': cfb = s2a(cfb); break;
17558 case 'buffer': break;
17559 case 'array': if(!Array.isArray(cfb)) cfb = Array.prototype.slice.call(cfb); break;
17560 }
17561 prep_blob(cfb, 0);
17562 WB = ({content: cfb});
17563}
17564var WorkbookP;
17565
17566var _data;
17567if(CompObj) parse_compobj(CompObj);
17568if(options.bookProps && !options.bookSheets) WorkbookP = ({});
17569else {
17570 var T = has_buf ? 'buffer' : 'array';
17571 if(WB && WB.content) WorkbookP = parse_workbook(WB.content, options);
17572 /* Quattro Pro 7-8 */
17573 else if((_data=CFB.find(cfb, 'PerfectOffice_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
17574 /* Quattro Pro 9 */
17575 else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
17576 else throw new Error("Cannot find Workbook stream");
17577 if(options.bookVBA && cfb.FullPaths && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb);
17578}
17579
17580var props = {};
17581if(cfb.FullPaths) parse_xls_props(cfb, props, options);
17582
17583WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
17584if(options.bookFiles) WorkbookP.cfb = cfb;
17585/*WorkbookP.CompObjP = CompObjP; // TODO: storage? */
17586return WorkbookP;
17587}
17588
17589
17590function write_xlscfb(wb, opts) {
17591 var o = opts || {};
17592 var cfb = CFB.utils.cfb_new({root:"R"});
17593 var wbpath = "/Workbook";
17594 switch(o.bookType || "xls") {
17595 case "xls": o.bookType = "biff8";
17596 /* falls through */
17597 case "xla": if(!o.bookType) o.bookType = "xla";
17598 /* falls through */
17599 case "biff8": wbpath = "/Workbook"; o.biff = 8; break;
17600 case "biff5": wbpath = "/Book"; o.biff = 5; break;
17601 default: throw new Error("invalid type " + o.bookType + " for XLS CFB");
17602 }
17603 CFB.utils.cfb_add(cfb, wbpath, write_biff_buf(wb, o));
17604 if(o.biff == 8 && (wb.Props || wb.Custprops)) write_xls_props(wb, cfb);
17605 // TODO: SI, DSI, CO
17606 if(o.biff == 8 && wb.vbaraw) fill_vba_xls(cfb, CFB.read(wb.vbaraw, {type: typeof wb.vbaraw == "string" ? "binary" : "buffer"}));
17607 return cfb;
17608}
17609/* [MS-XLSB] 2.3 Record Enumeration */
17610var XLSBRecordEnum = {
176110x0000: { n:"BrtRowHdr", f:parse_BrtRowHdr },
176120x0001: { n:"BrtCellBlank", f:parse_BrtCellBlank },
176130x0002: { n:"BrtCellRk", f:parse_BrtCellRk },
176140x0003: { n:"BrtCellError", f:parse_BrtCellError },
176150x0004: { n:"BrtCellBool", f:parse_BrtCellBool },
176160x0005: { n:"BrtCellReal", f:parse_BrtCellReal },
176170x0006: { n:"BrtCellSt", f:parse_BrtCellSt },
176180x0007: { n:"BrtCellIsst", f:parse_BrtCellIsst },
176190x0008: { n:"BrtFmlaString", f:parse_BrtFmlaString },
176200x0009: { n:"BrtFmlaNum", f:parse_BrtFmlaNum },
176210x000A: { n:"BrtFmlaBool", f:parse_BrtFmlaBool },
176220x000B: { n:"BrtFmlaError", f:parse_BrtFmlaError },
176230x0010: { n:"BrtFRTArchID$", f:parse_BrtFRTArchID$ },
176240x0013: { n:"BrtSSTItem", f:parse_RichStr },
176250x0014: { n:"BrtPCDIMissing" },
176260x0015: { n:"BrtPCDINumber" },
176270x0016: { n:"BrtPCDIBoolean" },
176280x0017: { n:"BrtPCDIError" },
176290x0018: { n:"BrtPCDIString" },
176300x0019: { n:"BrtPCDIDatetime" },
176310x001A: { n:"BrtPCDIIndex" },
176320x001B: { n:"BrtPCDIAMissing" },
176330x001C: { n:"BrtPCDIANumber" },
176340x001D: { n:"BrtPCDIABoolean" },
176350x001E: { n:"BrtPCDIAError" },
176360x001F: { n:"BrtPCDIAString" },
176370x0020: { n:"BrtPCDIADatetime" },
176380x0021: { n:"BrtPCRRecord" },
176390x0022: { n:"BrtPCRRecordDt" },
176400x0023: { n:"BrtFRTBegin" },
176410x0024: { n:"BrtFRTEnd" },
176420x0025: { n:"BrtACBegin" },
176430x0026: { n:"BrtACEnd" },
176440x0027: { n:"BrtName", f:parse_BrtName },
176450x0028: { n:"BrtIndexRowBlock" },
176460x002A: { n:"BrtIndexBlock" },
176470x002B: { n:"BrtFont", f:parse_BrtFont },
176480x002C: { n:"BrtFmt", f:parse_BrtFmt },
176490x002D: { n:"BrtFill", f:parse_BrtFill },
176500x002E: { n:"BrtBorder", f:parse_BrtBorder },
176510x002F: { n:"BrtXF", f:parse_BrtXF },
176520x0030: { n:"BrtStyle" },
176530x0031: { n:"BrtCellMeta" },
176540x0032: { n:"BrtValueMeta" },
176550x0033: { n:"BrtMdb" },
176560x0034: { n:"BrtBeginFmd" },
176570x0035: { n:"BrtEndFmd" },
176580x0036: { n:"BrtBeginMdx" },
176590x0037: { n:"BrtEndMdx" },
176600x0038: { n:"BrtBeginMdxTuple" },
176610x0039: { n:"BrtEndMdxTuple" },
176620x003A: { n:"BrtMdxMbrIstr" },
176630x003B: { n:"BrtStr" },
176640x003C: { n:"BrtColInfo", f:parse_ColInfo },
176650x003E: { n:"BrtCellRString" },
176660x003F: { n:"BrtCalcChainItem$", f:parse_BrtCalcChainItem$ },
176670x0040: { n:"BrtDVal", f:parse_BrtDVal },
176680x0041: { n:"BrtSxvcellNum" },
176690x0042: { n:"BrtSxvcellStr" },
176700x0043: { n:"BrtSxvcellBool" },
176710x0044: { n:"BrtSxvcellErr" },
176720x0045: { n:"BrtSxvcellDate" },
176730x0046: { n:"BrtSxvcellNil" },
176740x0080: { n:"BrtFileVersion" },
176750x0081: { n:"BrtBeginSheet" },
176760x0082: { n:"BrtEndSheet" },
176770x0083: { n:"BrtBeginBook", f:parsenoop, p:0 },
176780x0084: { n:"BrtEndBook" },
176790x0085: { n:"BrtBeginWsViews" },
176800x0086: { n:"BrtEndWsViews" },
176810x0087: { n:"BrtBeginBookViews" },
176820x0088: { n:"BrtEndBookViews" },
176830x0089: { n:"BrtBeginWsView", f:parse_BrtBeginWsView },
176840x008A: { n:"BrtEndWsView" },
176850x008B: { n:"BrtBeginCsViews" },
176860x008C: { n:"BrtEndCsViews" },
176870x008D: { n:"BrtBeginCsView" },
176880x008E: { n:"BrtEndCsView" },
176890x008F: { n:"BrtBeginBundleShs" },
176900x0090: { n:"BrtEndBundleShs" },
176910x0091: { n:"BrtBeginSheetData" },
176920x0092: { n:"BrtEndSheetData" },
176930x0093: { n:"BrtWsProp", f:parse_BrtWsProp },
176940x0094: { n:"BrtWsDim", f:parse_BrtWsDim, p:16 },
176950x0097: { n:"BrtPane", f:parse_BrtPane },
176960x0098: { n:"BrtSel" },
176970x0099: { n:"BrtWbProp", f:parse_BrtWbProp },
176980x009A: { n:"BrtWbFactoid" },
176990x009B: { n:"BrtFileRecover" },
177000x009C: { n:"BrtBundleSh", f:parse_BrtBundleSh },
177010x009D: { n:"BrtCalcProp" },
177020x009E: { n:"BrtBookView" },
177030x009F: { n:"BrtBeginSst", f:parse_BrtBeginSst },
177040x00A0: { n:"BrtEndSst" },
177050x00A1: { n:"BrtBeginAFilter", f:parse_UncheckedRfX },
177060x00A2: { n:"BrtEndAFilter" },
177070x00A3: { n:"BrtBeginFilterColumn" },
177080x00A4: { n:"BrtEndFilterColumn" },
177090x00A5: { n:"BrtBeginFilters" },
177100x00A6: { n:"BrtEndFilters" },
177110x00A7: { n:"BrtFilter" },
177120x00A8: { n:"BrtColorFilter" },
177130x00A9: { n:"BrtIconFilter" },
177140x00AA: { n:"BrtTop10Filter" },
177150x00AB: { n:"BrtDynamicFilter" },
177160x00AC: { n:"BrtBeginCustomFilters" },
177170x00AD: { n:"BrtEndCustomFilters" },
177180x00AE: { n:"BrtCustomFilter" },
177190x00AF: { n:"BrtAFilterDateGroupItem" },
177200x00B0: { n:"BrtMergeCell", f:parse_BrtMergeCell },
177210x00B1: { n:"BrtBeginMergeCells" },
177220x00B2: { n:"BrtEndMergeCells" },
177230x00B3: { n:"BrtBeginPivotCacheDef" },
177240x00B4: { n:"BrtEndPivotCacheDef" },
177250x00B5: { n:"BrtBeginPCDFields" },
177260x00B6: { n:"BrtEndPCDFields" },
177270x00B7: { n:"BrtBeginPCDField" },
177280x00B8: { n:"BrtEndPCDField" },
177290x00B9: { n:"BrtBeginPCDSource" },
177300x00BA: { n:"BrtEndPCDSource" },
177310x00BB: { n:"BrtBeginPCDSRange" },
177320x00BC: { n:"BrtEndPCDSRange" },
177330x00BD: { n:"BrtBeginPCDFAtbl" },
177340x00BE: { n:"BrtEndPCDFAtbl" },
177350x00BF: { n:"BrtBeginPCDIRun" },
177360x00C0: { n:"BrtEndPCDIRun" },
177370x00C1: { n:"BrtBeginPivotCacheRecords" },
177380x00C2: { n:"BrtEndPivotCacheRecords" },
177390x00C3: { n:"BrtBeginPCDHierarchies" },
177400x00C4: { n:"BrtEndPCDHierarchies" },
177410x00C5: { n:"BrtBeginPCDHierarchy" },
177420x00C6: { n:"BrtEndPCDHierarchy" },
177430x00C7: { n:"BrtBeginPCDHFieldsUsage" },
177440x00C8: { n:"BrtEndPCDHFieldsUsage" },
177450x00C9: { n:"BrtBeginExtConnection" },
177460x00CA: { n:"BrtEndExtConnection" },
177470x00CB: { n:"BrtBeginECDbProps" },
177480x00CC: { n:"BrtEndECDbProps" },
177490x00CD: { n:"BrtBeginECOlapProps" },
177500x00CE: { n:"BrtEndECOlapProps" },
177510x00CF: { n:"BrtBeginPCDSConsol" },
177520x00D0: { n:"BrtEndPCDSConsol" },
177530x00D1: { n:"BrtBeginPCDSCPages" },
177540x00D2: { n:"BrtEndPCDSCPages" },
177550x00D3: { n:"BrtBeginPCDSCPage" },
177560x00D4: { n:"BrtEndPCDSCPage" },
177570x00D5: { n:"BrtBeginPCDSCPItem" },
177580x00D6: { n:"BrtEndPCDSCPItem" },
177590x00D7: { n:"BrtBeginPCDSCSets" },
177600x00D8: { n:"BrtEndPCDSCSets" },
177610x00D9: { n:"BrtBeginPCDSCSet" },
177620x00DA: { n:"BrtEndPCDSCSet" },
177630x00DB: { n:"BrtBeginPCDFGroup" },
177640x00DC: { n:"BrtEndPCDFGroup" },
177650x00DD: { n:"BrtBeginPCDFGItems" },
177660x00DE: { n:"BrtEndPCDFGItems" },
177670x00DF: { n:"BrtBeginPCDFGRange" },
177680x00E0: { n:"BrtEndPCDFGRange" },
177690x00E1: { n:"BrtBeginPCDFGDiscrete" },
177700x00E2: { n:"BrtEndPCDFGDiscrete" },
177710x00E3: { n:"BrtBeginPCDSDTupleCache" },
177720x00E4: { n:"BrtEndPCDSDTupleCache" },
177730x00E5: { n:"BrtBeginPCDSDTCEntries" },
177740x00E6: { n:"BrtEndPCDSDTCEntries" },
177750x00E7: { n:"BrtBeginPCDSDTCEMembers" },
177760x00E8: { n:"BrtEndPCDSDTCEMembers" },
177770x00E9: { n:"BrtBeginPCDSDTCEMember" },
177780x00EA: { n:"BrtEndPCDSDTCEMember" },
177790x00EB: { n:"BrtBeginPCDSDTCQueries" },
177800x00EC: { n:"BrtEndPCDSDTCQueries" },
177810x00ED: { n:"BrtBeginPCDSDTCQuery" },
177820x00EE: { n:"BrtEndPCDSDTCQuery" },
177830x00EF: { n:"BrtBeginPCDSDTCSets" },
177840x00F0: { n:"BrtEndPCDSDTCSets" },
177850x00F1: { n:"BrtBeginPCDSDTCSet" },
177860x00F2: { n:"BrtEndPCDSDTCSet" },
177870x00F3: { n:"BrtBeginPCDCalcItems" },
177880x00F4: { n:"BrtEndPCDCalcItems" },
177890x00F5: { n:"BrtBeginPCDCalcItem" },
177900x00F6: { n:"BrtEndPCDCalcItem" },
177910x00F7: { n:"BrtBeginPRule" },
177920x00F8: { n:"BrtEndPRule" },
177930x00F9: { n:"BrtBeginPRFilters" },
177940x00FA: { n:"BrtEndPRFilters" },
177950x00FB: { n:"BrtBeginPRFilter" },
177960x00FC: { n:"BrtEndPRFilter" },
177970x00FD: { n:"BrtBeginPNames" },
177980x00FE: { n:"BrtEndPNames" },
177990x00FF: { n:"BrtBeginPName" },
178000x0100: { n:"BrtEndPName" },
178010x0101: { n:"BrtBeginPNPairs" },
178020x0102: { n:"BrtEndPNPairs" },
178030x0103: { n:"BrtBeginPNPair" },
178040x0104: { n:"BrtEndPNPair" },
178050x0105: { n:"BrtBeginECWebProps" },
178060x0106: { n:"BrtEndECWebProps" },
178070x0107: { n:"BrtBeginEcWpTables" },
178080x0108: { n:"BrtEndECWPTables" },
178090x0109: { n:"BrtBeginECParams" },
178100x010A: { n:"BrtEndECParams" },
178110x010B: { n:"BrtBeginECParam" },
178120x010C: { n:"BrtEndECParam" },
178130x010D: { n:"BrtBeginPCDKPIs" },
178140x010E: { n:"BrtEndPCDKPIs" },
178150x010F: { n:"BrtBeginPCDKPI" },
178160x0110: { n:"BrtEndPCDKPI" },
178170x0111: { n:"BrtBeginDims" },
178180x0112: { n:"BrtEndDims" },
178190x0113: { n:"BrtBeginDim" },
178200x0114: { n:"BrtEndDim" },
178210x0115: { n:"BrtIndexPartEnd" },
178220x0116: { n:"BrtBeginStyleSheet" },
178230x0117: { n:"BrtEndStyleSheet" },
178240x0118: { n:"BrtBeginSXView" },
178250x0119: { n:"BrtEndSXVI" },
178260x011A: { n:"BrtBeginSXVI" },
178270x011B: { n:"BrtBeginSXVIs" },
178280x011C: { n:"BrtEndSXVIs" },
178290x011D: { n:"BrtBeginSXVD" },
178300x011E: { n:"BrtEndSXVD" },
178310x011F: { n:"BrtBeginSXVDs" },
178320x0120: { n:"BrtEndSXVDs" },
178330x0121: { n:"BrtBeginSXPI" },
178340x0122: { n:"BrtEndSXPI" },
178350x0123: { n:"BrtBeginSXPIs" },
178360x0124: { n:"BrtEndSXPIs" },
178370x0125: { n:"BrtBeginSXDI" },
178380x0126: { n:"BrtEndSXDI" },
178390x0127: { n:"BrtBeginSXDIs" },
178400x0128: { n:"BrtEndSXDIs" },
178410x0129: { n:"BrtBeginSXLI" },
178420x012A: { n:"BrtEndSXLI" },
178430x012B: { n:"BrtBeginSXLIRws" },
178440x012C: { n:"BrtEndSXLIRws" },
178450x012D: { n:"BrtBeginSXLICols" },
178460x012E: { n:"BrtEndSXLICols" },
178470x012F: { n:"BrtBeginSXFormat" },
178480x0130: { n:"BrtEndSXFormat" },
178490x0131: { n:"BrtBeginSXFormats" },
178500x0132: { n:"BrtEndSxFormats" },
178510x0133: { n:"BrtBeginSxSelect" },
178520x0134: { n:"BrtEndSxSelect" },
178530x0135: { n:"BrtBeginISXVDRws" },
178540x0136: { n:"BrtEndISXVDRws" },
178550x0137: { n:"BrtBeginISXVDCols" },
178560x0138: { n:"BrtEndISXVDCols" },
178570x0139: { n:"BrtEndSXLocation" },
178580x013A: { n:"BrtBeginSXLocation" },
178590x013B: { n:"BrtEndSXView" },
178600x013C: { n:"BrtBeginSXTHs" },
178610x013D: { n:"BrtEndSXTHs" },
178620x013E: { n:"BrtBeginSXTH" },
178630x013F: { n:"BrtEndSXTH" },
178640x0140: { n:"BrtBeginISXTHRws" },
178650x0141: { n:"BrtEndISXTHRws" },
178660x0142: { n:"BrtBeginISXTHCols" },
178670x0143: { n:"BrtEndISXTHCols" },
178680x0144: { n:"BrtBeginSXTDMPS" },
178690x0145: { n:"BrtEndSXTDMPs" },
178700x0146: { n:"BrtBeginSXTDMP" },
178710x0147: { n:"BrtEndSXTDMP" },
178720x0148: { n:"BrtBeginSXTHItems" },
178730x0149: { n:"BrtEndSXTHItems" },
178740x014A: { n:"BrtBeginSXTHItem" },
178750x014B: { n:"BrtEndSXTHItem" },
178760x014C: { n:"BrtBeginMetadata" },
178770x014D: { n:"BrtEndMetadata" },
178780x014E: { n:"BrtBeginEsmdtinfo" },
178790x014F: { n:"BrtMdtinfo" },
178800x0150: { n:"BrtEndEsmdtinfo" },
178810x0151: { n:"BrtBeginEsmdb" },
178820x0152: { n:"BrtEndEsmdb" },
178830x0153: { n:"BrtBeginEsfmd" },
178840x0154: { n:"BrtEndEsfmd" },
178850x0155: { n:"BrtBeginSingleCells" },
178860x0156: { n:"BrtEndSingleCells" },
178870x0157: { n:"BrtBeginList" },
178880x0158: { n:"BrtEndList" },
178890x0159: { n:"BrtBeginListCols" },
178900x015A: { n:"BrtEndListCols" },
178910x015B: { n:"BrtBeginListCol" },
178920x015C: { n:"BrtEndListCol" },
178930x015D: { n:"BrtBeginListXmlCPr" },
178940x015E: { n:"BrtEndListXmlCPr" },
178950x015F: { n:"BrtListCCFmla" },
178960x0160: { n:"BrtListTrFmla" },
178970x0161: { n:"BrtBeginExternals" },
178980x0162: { n:"BrtEndExternals" },
178990x0163: { n:"BrtSupBookSrc", f:parse_RelID},
179000x0165: { n:"BrtSupSelf" },
179010x0166: { n:"BrtSupSame" },
179020x0167: { n:"BrtSupTabs" },
179030x0168: { n:"BrtBeginSupBook" },
179040x0169: { n:"BrtPlaceholderName" },
179050x016A: { n:"BrtExternSheet", f:parse_ExternSheet },
179060x016B: { n:"BrtExternTableStart" },
179070x016C: { n:"BrtExternTableEnd" },
179080x016E: { n:"BrtExternRowHdr" },
179090x016F: { n:"BrtExternCellBlank" },
179100x0170: { n:"BrtExternCellReal" },
179110x0171: { n:"BrtExternCellBool" },
179120x0172: { n:"BrtExternCellError" },
179130x0173: { n:"BrtExternCellString" },
179140x0174: { n:"BrtBeginEsmdx" },
179150x0175: { n:"BrtEndEsmdx" },
179160x0176: { n:"BrtBeginMdxSet" },
179170x0177: { n:"BrtEndMdxSet" },
179180x0178: { n:"BrtBeginMdxMbrProp" },
179190x0179: { n:"BrtEndMdxMbrProp" },
179200x017A: { n:"BrtBeginMdxKPI" },
179210x017B: { n:"BrtEndMdxKPI" },
179220x017C: { n:"BrtBeginEsstr" },
179230x017D: { n:"BrtEndEsstr" },
179240x017E: { n:"BrtBeginPRFItem" },
179250x017F: { n:"BrtEndPRFItem" },
179260x0180: { n:"BrtBeginPivotCacheIDs" },
179270x0181: { n:"BrtEndPivotCacheIDs" },
179280x0182: { n:"BrtBeginPivotCacheID" },
179290x0183: { n:"BrtEndPivotCacheID" },
179300x0184: { n:"BrtBeginISXVIs" },
179310x0185: { n:"BrtEndISXVIs" },
179320x0186: { n:"BrtBeginColInfos" },
179330x0187: { n:"BrtEndColInfos" },
179340x0188: { n:"BrtBeginRwBrk" },
179350x0189: { n:"BrtEndRwBrk" },
179360x018A: { n:"BrtBeginColBrk" },
179370x018B: { n:"BrtEndColBrk" },
179380x018C: { n:"BrtBrk" },
179390x018D: { n:"BrtUserBookView" },
179400x018E: { n:"BrtInfo" },
179410x018F: { n:"BrtCUsr" },
179420x0190: { n:"BrtUsr" },
179430x0191: { n:"BrtBeginUsers" },
179440x0193: { n:"BrtEOF" },
179450x0194: { n:"BrtUCR" },
179460x0195: { n:"BrtRRInsDel" },
179470x0196: { n:"BrtRREndInsDel" },
179480x0197: { n:"BrtRRMove" },
179490x0198: { n:"BrtRREndMove" },
179500x0199: { n:"BrtRRChgCell" },
179510x019A: { n:"BrtRREndChgCell" },
179520x019B: { n:"BrtRRHeader" },
179530x019C: { n:"BrtRRUserView" },
179540x019D: { n:"BrtRRRenSheet" },
179550x019E: { n:"BrtRRInsertSh" },
179560x019F: { n:"BrtRRDefName" },
179570x01A0: { n:"BrtRRNote" },
179580x01A1: { n:"BrtRRConflict" },
179590x01A2: { n:"BrtRRTQSIF" },
179600x01A3: { n:"BrtRRFormat" },
179610x01A4: { n:"BrtRREndFormat" },
179620x01A5: { n:"BrtRRAutoFmt" },
179630x01A6: { n:"BrtBeginUserShViews" },
179640x01A7: { n:"BrtBeginUserShView" },
179650x01A8: { n:"BrtEndUserShView" },
179660x01A9: { n:"BrtEndUserShViews" },
179670x01AA: { n:"BrtArrFmla", f:parse_BrtArrFmla },
179680x01AB: { n:"BrtShrFmla", f:parse_BrtShrFmla },
179690x01AC: { n:"BrtTable" },
179700x01AD: { n:"BrtBeginExtConnections" },
179710x01AE: { n:"BrtEndExtConnections" },
179720x01AF: { n:"BrtBeginPCDCalcMems" },
179730x01B0: { n:"BrtEndPCDCalcMems" },
179740x01B1: { n:"BrtBeginPCDCalcMem" },
179750x01B2: { n:"BrtEndPCDCalcMem" },
179760x01B3: { n:"BrtBeginPCDHGLevels" },
179770x01B4: { n:"BrtEndPCDHGLevels" },
179780x01B5: { n:"BrtBeginPCDHGLevel" },
179790x01B6: { n:"BrtEndPCDHGLevel" },
179800x01B7: { n:"BrtBeginPCDHGLGroups" },
179810x01B8: { n:"BrtEndPCDHGLGroups" },
179820x01B9: { n:"BrtBeginPCDHGLGroup" },
179830x01BA: { n:"BrtEndPCDHGLGroup" },
179840x01BB: { n:"BrtBeginPCDHGLGMembers" },
179850x01BC: { n:"BrtEndPCDHGLGMembers" },
179860x01BD: { n:"BrtBeginPCDHGLGMember" },
179870x01BE: { n:"BrtEndPCDHGLGMember" },
179880x01BF: { n:"BrtBeginQSI" },
179890x01C0: { n:"BrtEndQSI" },
179900x01C1: { n:"BrtBeginQSIR" },
179910x01C2: { n:"BrtEndQSIR" },
179920x01C3: { n:"BrtBeginDeletedNames" },
179930x01C4: { n:"BrtEndDeletedNames" },
179940x01C5: { n:"BrtBeginDeletedName" },
179950x01C6: { n:"BrtEndDeletedName" },
179960x01C7: { n:"BrtBeginQSIFs" },
179970x01C8: { n:"BrtEndQSIFs" },
179980x01C9: { n:"BrtBeginQSIF" },
179990x01CA: { n:"BrtEndQSIF" },
180000x01CB: { n:"BrtBeginAutoSortScope" },
180010x01CC: { n:"BrtEndAutoSortScope" },
180020x01CD: { n:"BrtBeginConditionalFormatting" },
180030x01CE: { n:"BrtEndConditionalFormatting" },
180040x01CF: { n:"BrtBeginCFRule" },
180050x01D0: { n:"BrtEndCFRule" },
180060x01D1: { n:"BrtBeginIconSet" },
180070x01D2: { n:"BrtEndIconSet" },
180080x01D3: { n:"BrtBeginDatabar" },
180090x01D4: { n:"BrtEndDatabar" },
180100x01D5: { n:"BrtBeginColorScale" },
180110x01D6: { n:"BrtEndColorScale" },
180120x01D7: { n:"BrtCFVO" },
180130x01D8: { n:"BrtExternValueMeta" },
180140x01D9: { n:"BrtBeginColorPalette" },
180150x01DA: { n:"BrtEndColorPalette" },
180160x01DB: { n:"BrtIndexedColor" },
180170x01DC: { n:"BrtMargins", f:parse_BrtMargins },
180180x01DD: { n:"BrtPrintOptions" },
180190x01DE: { n:"BrtPageSetup" },
180200x01DF: { n:"BrtBeginHeaderFooter" },
180210x01E0: { n:"BrtEndHeaderFooter" },
180220x01E1: { n:"BrtBeginSXCrtFormat" },
180230x01E2: { n:"BrtEndSXCrtFormat" },
180240x01E3: { n:"BrtBeginSXCrtFormats" },
180250x01E4: { n:"BrtEndSXCrtFormats" },
180260x01E5: { n:"BrtWsFmtInfo", f:parse_BrtWsFmtInfo },
180270x01E6: { n:"BrtBeginMgs" },
180280x01E7: { n:"BrtEndMGs" },
180290x01E8: { n:"BrtBeginMGMaps" },
180300x01E9: { n:"BrtEndMGMaps" },
180310x01EA: { n:"BrtBeginMG" },
180320x01EB: { n:"BrtEndMG" },
180330x01EC: { n:"BrtBeginMap" },
180340x01ED: { n:"BrtEndMap" },
180350x01EE: { n:"BrtHLink", f:parse_BrtHLink },
180360x01EF: { n:"BrtBeginDCon" },
180370x01F0: { n:"BrtEndDCon" },
180380x01F1: { n:"BrtBeginDRefs" },
180390x01F2: { n:"BrtEndDRefs" },
180400x01F3: { n:"BrtDRef" },
180410x01F4: { n:"BrtBeginScenMan" },
180420x01F5: { n:"BrtEndScenMan" },
180430x01F6: { n:"BrtBeginSct" },
180440x01F7: { n:"BrtEndSct" },
180450x01F8: { n:"BrtSlc" },
180460x01F9: { n:"BrtBeginDXFs" },
180470x01FA: { n:"BrtEndDXFs" },
180480x01FB: { n:"BrtDXF" },
180490x01FC: { n:"BrtBeginTableStyles" },
180500x01FD: { n:"BrtEndTableStyles" },
180510x01FE: { n:"BrtBeginTableStyle" },
180520x01FF: { n:"BrtEndTableStyle" },
180530x0200: { n:"BrtTableStyleElement" },
180540x0201: { n:"BrtTableStyleClient" },
180550x0202: { n:"BrtBeginVolDeps" },
180560x0203: { n:"BrtEndVolDeps" },
180570x0204: { n:"BrtBeginVolType" },
180580x0205: { n:"BrtEndVolType" },
180590x0206: { n:"BrtBeginVolMain" },
180600x0207: { n:"BrtEndVolMain" },
180610x0208: { n:"BrtBeginVolTopic" },
180620x0209: { n:"BrtEndVolTopic" },
180630x020A: { n:"BrtVolSubtopic" },
180640x020B: { n:"BrtVolRef" },
180650x020C: { n:"BrtVolNum" },
180660x020D: { n:"BrtVolErr" },
180670x020E: { n:"BrtVolStr" },
180680x020F: { n:"BrtVolBool" },
180690x0210: { n:"BrtBeginCalcChain$" },
180700x0211: { n:"BrtEndCalcChain$" },
180710x0212: { n:"BrtBeginSortState" },
180720x0213: { n:"BrtEndSortState" },
180730x0214: { n:"BrtBeginSortCond" },
180740x0215: { n:"BrtEndSortCond" },
180750x0216: { n:"BrtBookProtection" },
180760x0217: { n:"BrtSheetProtection" },
180770x0218: { n:"BrtRangeProtection" },
180780x0219: { n:"BrtPhoneticInfo" },
180790x021A: { n:"BrtBeginECTxtWiz" },
180800x021B: { n:"BrtEndECTxtWiz" },
180810x021C: { n:"BrtBeginECTWFldInfoLst" },
180820x021D: { n:"BrtEndECTWFldInfoLst" },
180830x021E: { n:"BrtBeginECTwFldInfo" },
180840x0224: { n:"BrtFileSharing" },
180850x0225: { n:"BrtOleSize" },
180860x0226: { n:"BrtDrawing", f:parse_RelID },
180870x0227: { n:"BrtLegacyDrawing" },
180880x0228: { n:"BrtLegacyDrawingHF" },
180890x0229: { n:"BrtWebOpt" },
180900x022A: { n:"BrtBeginWebPubItems" },
180910x022B: { n:"BrtEndWebPubItems" },
180920x022C: { n:"BrtBeginWebPubItem" },
180930x022D: { n:"BrtEndWebPubItem" },
180940x022E: { n:"BrtBeginSXCondFmt" },
180950x022F: { n:"BrtEndSXCondFmt" },
180960x0230: { n:"BrtBeginSXCondFmts" },
180970x0231: { n:"BrtEndSXCondFmts" },
180980x0232: { n:"BrtBkHim" },
180990x0234: { n:"BrtColor" },
181000x0235: { n:"BrtBeginIndexedColors" },
181010x0236: { n:"BrtEndIndexedColors" },
181020x0239: { n:"BrtBeginMRUColors" },
181030x023A: { n:"BrtEndMRUColors" },
181040x023C: { n:"BrtMRUColor" },
181050x023D: { n:"BrtBeginDVals" },
181060x023E: { n:"BrtEndDVals" },
181070x0241: { n:"BrtSupNameStart" },
181080x0242: { n:"BrtSupNameValueStart" },
181090x0243: { n:"BrtSupNameValueEnd" },
181100x0244: { n:"BrtSupNameNum" },
181110x0245: { n:"BrtSupNameErr" },
181120x0246: { n:"BrtSupNameSt" },
181130x0247: { n:"BrtSupNameNil" },
181140x0248: { n:"BrtSupNameBool" },
181150x0249: { n:"BrtSupNameFmla" },
181160x024A: { n:"BrtSupNameBits" },
181170x024B: { n:"BrtSupNameEnd" },
181180x024C: { n:"BrtEndSupBook" },
181190x024D: { n:"BrtCellSmartTagProperty" },
181200x024E: { n:"BrtBeginCellSmartTag" },
181210x024F: { n:"BrtEndCellSmartTag" },
181220x0250: { n:"BrtBeginCellSmartTags" },
181230x0251: { n:"BrtEndCellSmartTags" },
181240x0252: { n:"BrtBeginSmartTags" },
181250x0253: { n:"BrtEndSmartTags" },
181260x0254: { n:"BrtSmartTagType" },
181270x0255: { n:"BrtBeginSmartTagTypes" },
181280x0256: { n:"BrtEndSmartTagTypes" },
181290x0257: { n:"BrtBeginSXFilters" },
181300x0258: { n:"BrtEndSXFilters" },
181310x0259: { n:"BrtBeginSXFILTER" },
181320x025A: { n:"BrtEndSXFilter" },
181330x025B: { n:"BrtBeginFills" },
181340x025C: { n:"BrtEndFills" },
181350x025D: { n:"BrtBeginCellWatches" },
181360x025E: { n:"BrtEndCellWatches" },
181370x025F: { n:"BrtCellWatch" },
181380x0260: { n:"BrtBeginCRErrs" },
181390x0261: { n:"BrtEndCRErrs" },
181400x0262: { n:"BrtCrashRecErr" },
181410x0263: { n:"BrtBeginFonts" },
181420x0264: { n:"BrtEndFonts" },
181430x0265: { n:"BrtBeginBorders" },
181440x0266: { n:"BrtEndBorders" },
181450x0267: { n:"BrtBeginFmts" },
181460x0268: { n:"BrtEndFmts" },
181470x0269: { n:"BrtBeginCellXFs" },
181480x026A: { n:"BrtEndCellXFs" },
181490x026B: { n:"BrtBeginStyles" },
181500x026C: { n:"BrtEndStyles" },
181510x0271: { n:"BrtBigName" },
181520x0272: { n:"BrtBeginCellStyleXFs" },
181530x0273: { n:"BrtEndCellStyleXFs" },
181540x0274: { n:"BrtBeginComments" },
181550x0275: { n:"BrtEndComments" },
181560x0276: { n:"BrtBeginCommentAuthors" },
181570x0277: { n:"BrtEndCommentAuthors" },
181580x0278: { n:"BrtCommentAuthor", f:parse_BrtCommentAuthor },
181590x0279: { n:"BrtBeginCommentList" },
181600x027A: { n:"BrtEndCommentList" },
181610x027B: { n:"BrtBeginComment", f:parse_BrtBeginComment},
181620x027C: { n:"BrtEndComment" },
181630x027D: { n:"BrtCommentText", f:parse_BrtCommentText },
181640x027E: { n:"BrtBeginOleObjects" },
181650x027F: { n:"BrtOleObject" },
181660x0280: { n:"BrtEndOleObjects" },
181670x0281: { n:"BrtBeginSxrules" },
181680x0282: { n:"BrtEndSxRules" },
181690x0283: { n:"BrtBeginActiveXControls" },
181700x0284: { n:"BrtActiveX" },
181710x0285: { n:"BrtEndActiveXControls" },
181720x0286: { n:"BrtBeginPCDSDTCEMembersSortBy" },
181730x0288: { n:"BrtBeginCellIgnoreECs" },
181740x0289: { n:"BrtCellIgnoreEC" },
181750x028A: { n:"BrtEndCellIgnoreECs" },
181760x028B: { n:"BrtCsProp", f:parse_BrtCsProp },
181770x028C: { n:"BrtCsPageSetup" },
181780x028D: { n:"BrtBeginUserCsViews" },
181790x028E: { n:"BrtEndUserCsViews" },
181800x028F: { n:"BrtBeginUserCsView" },
181810x0290: { n:"BrtEndUserCsView" },
181820x0291: { n:"BrtBeginPcdSFCIEntries" },
181830x0292: { n:"BrtEndPCDSFCIEntries" },
181840x0293: { n:"BrtPCDSFCIEntry" },
181850x0294: { n:"BrtBeginListParts" },
181860x0295: { n:"BrtListPart" },
181870x0296: { n:"BrtEndListParts" },
181880x0297: { n:"BrtSheetCalcProp" },
181890x0298: { n:"BrtBeginFnGroup" },
181900x0299: { n:"BrtFnGroup" },
181910x029A: { n:"BrtEndFnGroup" },
181920x029B: { n:"BrtSupAddin" },
181930x029C: { n:"BrtSXTDMPOrder" },
181940x029D: { n:"BrtCsProtection" },
181950x029F: { n:"BrtBeginWsSortMap" },
181960x02A0: { n:"BrtEndWsSortMap" },
181970x02A1: { n:"BrtBeginRRSort" },
181980x02A2: { n:"BrtEndRRSort" },
181990x02A3: { n:"BrtRRSortItem" },
182000x02A4: { n:"BrtFileSharingIso" },
182010x02A5: { n:"BrtBookProtectionIso" },
182020x02A6: { n:"BrtSheetProtectionIso" },
182030x02A7: { n:"BrtCsProtectionIso" },
182040x02A8: { n:"BrtRangeProtectionIso" },
182050x02A9: { n:"BrtDValList" },
182060x0400: { n:"BrtRwDescent" },
182070x0401: { n:"BrtKnownFonts" },
182080x0402: { n:"BrtBeginSXTupleSet" },
182090x0403: { n:"BrtEndSXTupleSet" },
182100x0404: { n:"BrtBeginSXTupleSetHeader" },
182110x0405: { n:"BrtEndSXTupleSetHeader" },
182120x0406: { n:"BrtSXTupleSetHeaderItem" },
182130x0407: { n:"BrtBeginSXTupleSetData" },
182140x0408: { n:"BrtEndSXTupleSetData" },
182150x0409: { n:"BrtBeginSXTupleSetRow" },
182160x040A: { n:"BrtEndSXTupleSetRow" },
182170x040B: { n:"BrtSXTupleSetRowItem" },
182180x040C: { n:"BrtNameExt" },
182190x040D: { n:"BrtPCDH14" },
182200x040E: { n:"BrtBeginPCDCalcMem14" },
182210x040F: { n:"BrtEndPCDCalcMem14" },
182220x0410: { n:"BrtSXTH14" },
182230x0411: { n:"BrtBeginSparklineGroup" },
182240x0412: { n:"BrtEndSparklineGroup" },
182250x0413: { n:"BrtSparkline" },
182260x0414: { n:"BrtSXDI14" },
182270x0415: { n:"BrtWsFmtInfoEx14" },
182280x0416: { n:"BrtBeginConditionalFormatting14" },
182290x0417: { n:"BrtEndConditionalFormatting14" },
182300x0418: { n:"BrtBeginCFRule14" },
182310x0419: { n:"BrtEndCFRule14" },
182320x041A: { n:"BrtCFVO14" },
182330x041B: { n:"BrtBeginDatabar14" },
182340x041C: { n:"BrtBeginIconSet14" },
182350x041D: { n:"BrtDVal14", f: parse_BrtDVal14 },
182360x041E: { n:"BrtBeginDVals14" },
182370x041F: { n:"BrtColor14" },
182380x0420: { n:"BrtBeginSparklines" },
182390x0421: { n:"BrtEndSparklines" },
182400x0422: { n:"BrtBeginSparklineGroups" },
182410x0423: { n:"BrtEndSparklineGroups" },
182420x0425: { n:"BrtSXVD14" },
182430x0426: { n:"BrtBeginSXView14" },
182440x0427: { n:"BrtEndSXView14" },
182450x0428: { n:"BrtBeginSXView16" },
182460x0429: { n:"BrtEndSXView16" },
182470x042A: { n:"BrtBeginPCD14" },
182480x042B: { n:"BrtEndPCD14" },
182490x042C: { n:"BrtBeginExtConn14" },
182500x042D: { n:"BrtEndExtConn14" },
182510x042E: { n:"BrtBeginSlicerCacheIDs" },
182520x042F: { n:"BrtEndSlicerCacheIDs" },
182530x0430: { n:"BrtBeginSlicerCacheID" },
182540x0431: { n:"BrtEndSlicerCacheID" },
182550x0433: { n:"BrtBeginSlicerCache" },
182560x0434: { n:"BrtEndSlicerCache" },
182570x0435: { n:"BrtBeginSlicerCacheDef" },
182580x0436: { n:"BrtEndSlicerCacheDef" },
182590x0437: { n:"BrtBeginSlicersEx" },
182600x0438: { n:"BrtEndSlicersEx" },
182610x0439: { n:"BrtBeginSlicerEx" },
182620x043A: { n:"BrtEndSlicerEx" },
182630x043B: { n:"BrtBeginSlicer" },
182640x043C: { n:"BrtEndSlicer" },
182650x043D: { n:"BrtSlicerCachePivotTables" },
182660x043E: { n:"BrtBeginSlicerCacheOlapImpl" },
182670x043F: { n:"BrtEndSlicerCacheOlapImpl" },
182680x0440: { n:"BrtBeginSlicerCacheLevelsData" },
182690x0441: { n:"BrtEndSlicerCacheLevelsData" },
182700x0442: { n:"BrtBeginSlicerCacheLevelData" },
182710x0443: { n:"BrtEndSlicerCacheLevelData" },
182720x0444: { n:"BrtBeginSlicerCacheSiRanges" },
182730x0445: { n:"BrtEndSlicerCacheSiRanges" },
182740x0446: { n:"BrtBeginSlicerCacheSiRange" },
182750x0447: { n:"BrtEndSlicerCacheSiRange" },
182760x0448: { n:"BrtSlicerCacheOlapItem" },
182770x0449: { n:"BrtBeginSlicerCacheSelections" },
182780x044A: { n:"BrtSlicerCacheSelection" },
182790x044B: { n:"BrtEndSlicerCacheSelections" },
182800x044C: { n:"BrtBeginSlicerCacheNative" },
182810x044D: { n:"BrtEndSlicerCacheNative" },
182820x044E: { n:"BrtSlicerCacheNativeItem" },
182830x044F: { n:"BrtRangeProtection14" },
182840x0450: { n:"BrtRangeProtectionIso14" },
182850x0451: { n:"BrtCellIgnoreEC14" },
182860x0457: { n:"BrtList14" },
182870x0458: { n:"BrtCFIcon" },
182880x0459: { n:"BrtBeginSlicerCachesPivotCacheIDs" },
182890x045A: { n:"BrtEndSlicerCachesPivotCacheIDs" },
182900x045B: { n:"BrtBeginSlicers" },
182910x045C: { n:"BrtEndSlicers" },
182920x045D: { n:"BrtWbProp14" },
182930x045E: { n:"BrtBeginSXEdit" },
182940x045F: { n:"BrtEndSXEdit" },
182950x0460: { n:"BrtBeginSXEdits" },
182960x0461: { n:"BrtEndSXEdits" },
182970x0462: { n:"BrtBeginSXChange" },
182980x0463: { n:"BrtEndSXChange" },
182990x0464: { n:"BrtBeginSXChanges" },
183000x0465: { n:"BrtEndSXChanges" },
183010x0466: { n:"BrtSXTupleItems" },
183020x0468: { n:"BrtBeginSlicerStyle" },
183030x0469: { n:"BrtEndSlicerStyle" },
183040x046A: { n:"BrtSlicerStyleElement" },
183050x046B: { n:"BrtBeginStyleSheetExt14" },
183060x046C: { n:"BrtEndStyleSheetExt14" },
183070x046D: { n:"BrtBeginSlicerCachesPivotCacheID" },
183080x046E: { n:"BrtEndSlicerCachesPivotCacheID" },
183090x046F: { n:"BrtBeginConditionalFormattings" },
183100x0470: { n:"BrtEndConditionalFormattings" },
183110x0471: { n:"BrtBeginPCDCalcMemExt" },
183120x0472: { n:"BrtEndPCDCalcMemExt" },
183130x0473: { n:"BrtBeginPCDCalcMemsExt" },
183140x0474: { n:"BrtEndPCDCalcMemsExt" },
183150x0475: { n:"BrtPCDField14" },
183160x0476: { n:"BrtBeginSlicerStyles" },
183170x0477: { n:"BrtEndSlicerStyles" },
183180x0478: { n:"BrtBeginSlicerStyleElements" },
183190x0479: { n:"BrtEndSlicerStyleElements" },
183200x047A: { n:"BrtCFRuleExt" },
183210x047B: { n:"BrtBeginSXCondFmt14" },
183220x047C: { n:"BrtEndSXCondFmt14" },
183230x047D: { n:"BrtBeginSXCondFmts14" },
183240x047E: { n:"BrtEndSXCondFmts14" },
183250x0480: { n:"BrtBeginSortCond14" },
183260x0481: { n:"BrtEndSortCond14" },
183270x0482: { n:"BrtEndDVals14" },
183280x0483: { n:"BrtEndIconSet14" },
183290x0484: { n:"BrtEndDatabar14" },
183300x0485: { n:"BrtBeginColorScale14" },
183310x0486: { n:"BrtEndColorScale14" },
183320x0487: { n:"BrtBeginSxrules14" },
183330x0488: { n:"BrtEndSxrules14" },
183340x0489: { n:"BrtBeginPRule14" },
183350x048A: { n:"BrtEndPRule14" },
183360x048B: { n:"BrtBeginPRFilters14" },
183370x048C: { n:"BrtEndPRFilters14" },
183380x048D: { n:"BrtBeginPRFilter14" },
183390x048E: { n:"BrtEndPRFilter14" },
183400x048F: { n:"BrtBeginPRFItem14" },
183410x0490: { n:"BrtEndPRFItem14" },
183420x0491: { n:"BrtBeginCellIgnoreECs14" },
183430x0492: { n:"BrtEndCellIgnoreECs14" },
183440x0493: { n:"BrtDxf14" },
183450x0494: { n:"BrtBeginDxF14s" },
183460x0495: { n:"BrtEndDxf14s" },
183470x0499: { n:"BrtFilter14" },
183480x049A: { n:"BrtBeginCustomFilters14" },
183490x049C: { n:"BrtCustomFilter14" },
183500x049D: { n:"BrtIconFilter14" },
183510x049E: { n:"BrtPivotCacheConnectionName" },
183520x0800: { n:"BrtBeginDecoupledPivotCacheIDs" },
183530x0801: { n:"BrtEndDecoupledPivotCacheIDs" },
183540x0802: { n:"BrtDecoupledPivotCacheID" },
183550x0803: { n:"BrtBeginPivotTableRefs" },
183560x0804: { n:"BrtEndPivotTableRefs" },
183570x0805: { n:"BrtPivotTableRef" },
183580x0806: { n:"BrtSlicerCacheBookPivotTables" },
183590x0807: { n:"BrtBeginSxvcells" },
183600x0808: { n:"BrtEndSxvcells" },
183610x0809: { n:"BrtBeginSxRow" },
183620x080A: { n:"BrtEndSxRow" },
183630x080C: { n:"BrtPcdCalcMem15" },
183640x0813: { n:"BrtQsi15" },
183650x0814: { n:"BrtBeginWebExtensions" },
183660x0815: { n:"BrtEndWebExtensions" },
183670x0816: { n:"BrtWebExtension" },
183680x0817: { n:"BrtAbsPath15" },
183690x0818: { n:"BrtBeginPivotTableUISettings" },
183700x0819: { n:"BrtEndPivotTableUISettings" },
183710x081B: { n:"BrtTableSlicerCacheIDs" },
183720x081C: { n:"BrtTableSlicerCacheID" },
183730x081D: { n:"BrtBeginTableSlicerCache" },
183740x081E: { n:"BrtEndTableSlicerCache" },
183750x081F: { n:"BrtSxFilter15" },
183760x0820: { n:"BrtBeginTimelineCachePivotCacheIDs" },
183770x0821: { n:"BrtEndTimelineCachePivotCacheIDs" },
183780x0822: { n:"BrtTimelineCachePivotCacheID" },
183790x0823: { n:"BrtBeginTimelineCacheIDs" },
183800x0824: { n:"BrtEndTimelineCacheIDs" },
183810x0825: { n:"BrtBeginTimelineCacheID" },
183820x0826: { n:"BrtEndTimelineCacheID" },
183830x0827: { n:"BrtBeginTimelinesEx" },
183840x0828: { n:"BrtEndTimelinesEx" },
183850x0829: { n:"BrtBeginTimelineEx" },
183860x082A: { n:"BrtEndTimelineEx" },
183870x082B: { n:"BrtWorkBookPr15" },
183880x082C: { n:"BrtPCDH15" },
183890x082D: { n:"BrtBeginTimelineStyle" },
183900x082E: { n:"BrtEndTimelineStyle" },
183910x082F: { n:"BrtTimelineStyleElement" },
183920x0830: { n:"BrtBeginTimelineStylesheetExt15" },
183930x0831: { n:"BrtEndTimelineStylesheetExt15" },
183940x0832: { n:"BrtBeginTimelineStyles" },
183950x0833: { n:"BrtEndTimelineStyles" },
183960x0834: { n:"BrtBeginTimelineStyleElements" },
183970x0835: { n:"BrtEndTimelineStyleElements" },
183980x0836: { n:"BrtDxf15" },
183990x0837: { n:"BrtBeginDxfs15" },
184000x0838: { n:"brtEndDxfs15" },
184010x0839: { n:"BrtSlicerCacheHideItemsWithNoData" },
184020x083A: { n:"BrtBeginItemUniqueNames" },
184030x083B: { n:"BrtEndItemUniqueNames" },
184040x083C: { n:"BrtItemUniqueName" },
184050x083D: { n:"BrtBeginExtConn15" },
184060x083E: { n:"BrtEndExtConn15" },
184070x083F: { n:"BrtBeginOledbPr15" },
184080x0840: { n:"BrtEndOledbPr15" },
184090x0841: { n:"BrtBeginDataFeedPr15" },
184100x0842: { n:"BrtEndDataFeedPr15" },
184110x0843: { n:"BrtTextPr15" },
184120x0844: { n:"BrtRangePr15" },
184130x0845: { n:"BrtDbCommand15" },
184140x0846: { n:"BrtBeginDbTables15" },
184150x0847: { n:"BrtEndDbTables15" },
184160x0848: { n:"BrtDbTable15" },
184170x0849: { n:"BrtBeginDataModel" },
184180x084A: { n:"BrtEndDataModel" },
184190x084B: { n:"BrtBeginModelTables" },
184200x084C: { n:"BrtEndModelTables" },
184210x084D: { n:"BrtModelTable" },
184220x084E: { n:"BrtBeginModelRelationships" },
184230x084F: { n:"BrtEndModelRelationships" },
184240x0850: { n:"BrtModelRelationship" },
184250x0851: { n:"BrtBeginECTxtWiz15" },
184260x0852: { n:"BrtEndECTxtWiz15" },
184270x0853: { n:"BrtBeginECTWFldInfoLst15" },
184280x0854: { n:"BrtEndECTWFldInfoLst15" },
184290x0855: { n:"BrtBeginECTWFldInfo15" },
184300x0856: { n:"BrtFieldListActiveItem" },
184310x0857: { n:"BrtPivotCacheIdVersion" },
184320x0858: { n:"BrtSXDI15" },
184330x0859: { n:"BrtBeginModelTimeGroupings" },
184340x085A: { n:"BrtEndModelTimeGroupings" },
184350x085B: { n:"BrtBeginModelTimeGrouping" },
184360x085C: { n:"BrtEndModelTimeGrouping" },
184370x085D: { n:"BrtModelTimeGroupingCalcCol" },
184380x0C00: { n:"BrtUid" },
184390x0C01: { n:"BrtRevisionPtr" },
184400x13e7: { n:"BrtBeginCalcFeatures" },
184410x13e8: { n:"BrtEndCalcFeatures" },
184420x13e9: { n:"BrtCalcFeature" },
184430xFFFF: { n:"" }
18444};
18445
18446var XLSBRE = evert_key(XLSBRecordEnum, 'n');
18447
18448/* [MS-XLS] 2.3 Record Enumeration */
18449var XLSRecordEnum = {
184500x0003: { n:"BIFF2NUM", f:parse_BIFF2NUM },
184510x0004: { n:"BIFF2STR", f:parse_BIFF2STR },
184520x0006: { n:"Formula", f:parse_Formula },
184530x0009: { n:'BOF', f:parse_BOF },
184540x000a: { n:'EOF', f:parsenoop2 },
184550x000c: { n:"CalcCount", f:parseuint16 },
184560x000d: { n:"CalcMode", f:parseuint16 },
184570x000e: { n:"CalcPrecision", f:parsebool },
184580x000f: { n:"CalcRefMode", f:parsebool },
184590x0010: { n:"CalcDelta", f:parse_Xnum },
184600x0011: { n:"CalcIter", f:parsebool },
184610x0012: { n:"Protect", f:parsebool },
184620x0013: { n:"Password", f:parseuint16 },
184630x0014: { n:"Header", f:parse_XLHeaderFooter },
184640x0015: { n:"Footer", f:parse_XLHeaderFooter },
184650x0017: { n:"ExternSheet", f:parse_ExternSheet },
184660x0018: { n:"Lbl", f:parse_Lbl },
184670x0019: { n:"WinProtect", f:parsebool },
184680x001a: { n:"VerticalPageBreaks" },
184690x001b: { n:"HorizontalPageBreaks" },
184700x001c: { n:"Note", f:parse_Note },
184710x001d: { n:"Selection" },
184720x0022: { n:"Date1904", f:parsebool },
184730x0023: { n:"ExternName", f:parse_ExternName },
184740x0024: { n:"COLWIDTH" },
184750x0026: { n:"LeftMargin", f:parse_Xnum },
184760x0027: { n:"RightMargin", f:parse_Xnum },
184770x0028: { n:"TopMargin", f:parse_Xnum },
184780x0029: { n:"BottomMargin", f:parse_Xnum },
184790x002a: { n:"PrintRowCol", f:parsebool },
184800x002b: { n:"PrintGrid", f:parsebool },
184810x002f: { n:"FilePass", f:parse_FilePass },
184820x0031: { n:"Font", f:parse_Font },
184830x0033: { n:"PrintSize", f:parseuint16 },
184840x003c: { n:"Continue" },
184850x003d: { n:"Window1", f:parse_Window1 },
184860x0040: { n:"Backup", f:parsebool },
184870x0041: { n:"Pane", f:parse_Pane },
184880x0042: { n:'CodePage', f:parseuint16 },
184890x004d: { n:"Pls" },
184900x0050: { n:"DCon" },
184910x0051: { n:"DConRef" },
184920x0052: { n:"DConName" },
184930x0055: { n:"DefColWidth", f:parseuint16 },
184940x0059: { n:"XCT" },
184950x005a: { n:"CRN" },
184960x005b: { n:"FileSharing" },
184970x005c: { n:'WriteAccess', f:parse_WriteAccess },
184980x005d: { n:"Obj", f:parse_Obj },
184990x005e: { n:"Uncalced" },
185000x005f: { n:"CalcSaveRecalc", f:parsebool },
185010x0060: { n:"Template" },
185020x0061: { n:"Intl" },
185030x0063: { n:"ObjProtect", f:parsebool },
185040x007d: { n:"ColInfo", f:parse_ColInfo },
185050x0080: { n:"Guts", f:parse_Guts },
185060x0081: { n:"WsBool", f:parse_WsBool },
185070x0082: { n:"GridSet", f:parseuint16 },
185080x0083: { n:"HCenter", f:parsebool },
185090x0084: { n:"VCenter", f:parsebool },
185100x0085: { n:'BoundSheet8', f:parse_BoundSheet8 },
185110x0086: { n:"WriteProtect" },
185120x008c: { n:"Country", f:parse_Country },
185130x008d: { n:"HideObj", f:parseuint16 },
185140x0090: { n:"Sort" },
185150x0092: { n:"Palette", f:parse_Palette },
185160x0097: { n:"Sync" },
185170x0098: { n:"LPr" },
185180x0099: { n:"DxGCol" },
185190x009a: { n:"FnGroupName" },
185200x009b: { n:"FilterMode" },
185210x009c: { n:"BuiltInFnGroupCount", f:parseuint16 },
185220x009d: { n:"AutoFilterInfo" },
185230x009e: { n:"AutoFilter" },
185240x00a0: { n:"Scl", f:parse_Scl },
185250x00a1: { n:"Setup", f:parse_Setup },
185260x00ae: { n:"ScenMan" },
185270x00af: { n:"SCENARIO" },
185280x00b0: { n:"SxView" },
185290x00b1: { n:"Sxvd" },
185300x00b2: { n:"SXVI" },
185310x00b4: { n:"SxIvd" },
185320x00b5: { n:"SXLI" },
185330x00b6: { n:"SXPI" },
185340x00b8: { n:"DocRoute" },
185350x00b9: { n:"RecipName" },
185360x00bd: { n:"MulRk", f:parse_MulRk },
185370x00be: { n:"MulBlank", f:parse_MulBlank },
185380x00c1: { n:'Mms', f:parsenoop2 },
185390x00c5: { n:"SXDI" },
185400x00c6: { n:"SXDB" },
185410x00c7: { n:"SXFDB" },
185420x00c8: { n:"SXDBB" },
185430x00c9: { n:"SXNum" },
185440x00ca: { n:"SxBool", f:parsebool },
185450x00cb: { n:"SxErr" },
185460x00cc: { n:"SXInt" },
185470x00cd: { n:"SXString" },
185480x00ce: { n:"SXDtr" },
185490x00cf: { n:"SxNil" },
185500x00d0: { n:"SXTbl" },
185510x00d1: { n:"SXTBRGIITM" },
185520x00d2: { n:"SxTbpg" },
185530x00d3: { n:"ObProj" },
185540x00d5: { n:"SXStreamID" },
185550x00d7: { n:"DBCell" },
185560x00d8: { n:"SXRng" },
185570x00d9: { n:"SxIsxoper" },
185580x00da: { n:"BookBool", f:parseuint16 },
185590x00dc: { n:"DbOrParamQry" },
185600x00dd: { n:"ScenarioProtect", f:parsebool },
185610x00de: { n:"OleObjectSize" },
185620x00e0: { n:"XF", f:parse_XF },
185630x00e1: { n:'InterfaceHdr', f:parse_InterfaceHdr },
185640x00e2: { n:'InterfaceEnd', f:parsenoop2 },
185650x00e3: { n:"SXVS" },
185660x00e5: { n:"MergeCells", f:parse_MergeCells },
185670x00e9: { n:"BkHim" },
185680x00eb: { n:"MsoDrawingGroup" },
185690x00ec: { n:"MsoDrawing" },
185700x00ed: { n:"MsoDrawingSelection" },
185710x00ef: { n:"PhoneticInfo" },
185720x00f0: { n:"SxRule" },
185730x00f1: { n:"SXEx" },
185740x00f2: { n:"SxFilt" },
185750x00f4: { n:"SxDXF" },
185760x00f5: { n:"SxItm" },
185770x00f6: { n:"SxName" },
185780x00f7: { n:"SxSelect" },
185790x00f8: { n:"SXPair" },
185800x00f9: { n:"SxFmla" },
185810x00fb: { n:"SxFormat" },
185820x00fc: { n:"SST", f:parse_SST },
185830x00fd: { n:"LabelSst", f:parse_LabelSst },
185840x00ff: { n:"ExtSST", f:parse_ExtSST },
185850x0100: { n:"SXVDEx" },
185860x0103: { n:"SXFormula" },
185870x0122: { n:"SXDBEx" },
185880x0137: { n:"RRDInsDel" },
185890x0138: { n:"RRDHead" },
185900x013b: { n:"RRDChgCell" },
185910x013d: { n:"RRTabId", f:parseuint16a },
185920x013e: { n:"RRDRenSheet" },
185930x013f: { n:"RRSort" },
185940x0140: { n:"RRDMove" },
185950x014a: { n:"RRFormat" },
185960x014b: { n:"RRAutoFmt" },
185970x014d: { n:"RRInsertSh" },
185980x014e: { n:"RRDMoveBegin" },
185990x014f: { n:"RRDMoveEnd" },
186000x0150: { n:"RRDInsDelBegin" },
186010x0151: { n:"RRDInsDelEnd" },
186020x0152: { n:"RRDConflict" },
186030x0153: { n:"RRDDefName" },
186040x0154: { n:"RRDRstEtxp" },
186050x015f: { n:"LRng" },
186060x0160: { n:"UsesELFs", f:parsebool },
186070x0161: { n:"DSF", f:parsenoop2 },
186080x0191: { n:"CUsr" },
186090x0192: { n:"CbUsr" },
186100x0193: { n:"UsrInfo" },
186110x0194: { n:"UsrExcl" },
186120x0195: { n:"FileLock" },
186130x0196: { n:"RRDInfo" },
186140x0197: { n:"BCUsrs" },
186150x0198: { n:"UsrChk" },
186160x01a9: { n:"UserBView" },
186170x01aa: { n:"UserSViewBegin" },
186180x01ab: { n:"UserSViewEnd" },
186190x01ac: { n:"RRDUserView" },
186200x01ad: { n:"Qsi" },
186210x01ae: { n:"SupBook", f:parse_SupBook },
186220x01af: { n:"Prot4Rev", f:parsebool },
186230x01b0: { n:"CondFmt" },
186240x01b1: { n:"CF" },
186250x01b2: { n:"DVal" },
186260x01b5: { n:"DConBin" },
186270x01b6: { n:"TxO", f:parse_TxO },
186280x01b7: { n:"RefreshAll", f:parsebool },
186290x01b8: { n:"HLink", f:parse_HLink },
186300x01b9: { n:"Lel" },
186310x01ba: { n:"CodeName", f:parse_XLUnicodeString },
186320x01bb: { n:"SXFDBType" },
186330x01bc: { n:"Prot4RevPass", f:parseuint16 },
186340x01bd: { n:"ObNoMacros" },
186350x01be: { n:"Dv" },
186360x01c0: { n:"Excel9File", f:parsenoop2 },
186370x01c1: { n:"RecalcId", f:parse_RecalcId, r:2},
186380x01c2: { n:"EntExU2", f:parsenoop2 },
186390x0200: { n:"Dimensions", f:parse_Dimensions },
186400x0201: { n:"Blank", f:parse_Blank },
186410x0203: { n:"Number", f:parse_Number },
186420x0204: { n:"Label", f:parse_Label },
186430x0205: { n:"BoolErr", f:parse_BoolErr },
186440x0206: { n:"Formula", f:parse_Formula },
186450x0207: { n:"String", f:parse_String },
186460x0208: { n:'Row', f:parse_Row },
186470x020b: { n:"Index" },
186480x0221: { n:"Array", f:parse_Array },
186490x0225: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
186500x0236: { n:"Table" },
186510x023e: { n:"Window2", f:parse_Window2 },
186520x027e: { n:"RK", f:parse_RK },
186530x0293: { n:"Style" },
186540x0406: { n:"Formula", f:parse_Formula },
186550x0418: { n:"BigName" },
186560x041e: { n:"Format", f:parse_Format },
186570x043c: { n:"ContinueBigName" },
186580x04bc: { n:"ShrFmla", f:parse_ShrFmla },
186590x0800: { n:"HLinkTooltip", f:parse_HLinkTooltip },
186600x0801: { n:"WebPub" },
186610x0802: { n:"QsiSXTag" },
186620x0803: { n:"DBQueryExt" },
186630x0804: { n:"ExtString" },
186640x0805: { n:"TxtQry" },
186650x0806: { n:"Qsir" },
186660x0807: { n:"Qsif" },
186670x0808: { n:"RRDTQSIF" },
186680x0809: { n:'BOF', f:parse_BOF },
186690x080a: { n:"OleDbConn" },
186700x080b: { n:"WOpt" },
186710x080c: { n:"SXViewEx" },
186720x080d: { n:"SXTH" },
186730x080e: { n:"SXPIEx" },
186740x080f: { n:"SXVDTEx" },
186750x0810: { n:"SXViewEx9" },
186760x0812: { n:"ContinueFrt" },
186770x0813: { n:"RealTimeData" },
186780x0850: { n:"ChartFrtInfo" },
186790x0851: { n:"FrtWrapper" },
186800x0852: { n:"StartBlock" },
186810x0853: { n:"EndBlock" },
186820x0854: { n:"StartObject" },
186830x0855: { n:"EndObject" },
186840x0856: { n:"CatLab" },
186850x0857: { n:"YMult" },
186860x0858: { n:"SXViewLink" },
186870x0859: { n:"PivotChartBits" },
186880x085a: { n:"FrtFontList" },
186890x0862: { n:"SheetExt" },
186900x0863: { n:"BookExt", r:12},
186910x0864: { n:"SXAddl" },
186920x0865: { n:"CrErr" },
186930x0866: { n:"HFPicture" },
186940x0867: { n:'FeatHdr', f:parsenoop2 },
186950x0868: { n:"Feat" },
186960x086a: { n:"DataLabExt" },
186970x086b: { n:"DataLabExtContents" },
186980x086c: { n:"CellWatch" },
186990x0871: { n:"FeatHdr11" },
187000x0872: { n:"Feature11" },
187010x0874: { n:"DropDownObjIds" },
187020x0875: { n:"ContinueFrt11" },
187030x0876: { n:"DConn" },
187040x0877: { n:"List12" },
187050x0878: { n:"Feature12" },
187060x0879: { n:"CondFmt12" },
187070x087a: { n:"CF12" },
187080x087b: { n:"CFEx" },
187090x087c: { n:"XFCRC", f:parse_XFCRC, r:12 },
187100x087d: { n:"XFExt", f:parse_XFExt, r:12 },
187110x087e: { n:"AutoFilter12" },
187120x087f: { n:"ContinueFrt12" },
187130x0884: { n:"MDTInfo" },
187140x0885: { n:"MDXStr" },
187150x0886: { n:"MDXTuple" },
187160x0887: { n:"MDXSet" },
187170x0888: { n:"MDXProp" },
187180x0889: { n:"MDXKPI" },
187190x088a: { n:"MDB" },
187200x088b: { n:"PLV" },
187210x088c: { n:"Compat12", f:parsebool, r:12 },
187220x088d: { n:"DXF" },
187230x088e: { n:"TableStyles", r:12 },
187240x088f: { n:"TableStyle" },
187250x0890: { n:"TableStyleElement" },
187260x0892: { n:"StyleExt" },
187270x0893: { n:"NamePublish" },
187280x0894: { n:"NameCmt", f:parse_NameCmt, r:12 },
187290x0895: { n:"SortData" },
187300x0896: { n:"Theme", f:parse_Theme, r:12 },
187310x0897: { n:"GUIDTypeLib" },
187320x0898: { n:"FnGrp12" },
187330x0899: { n:"NameFnGrp12" },
187340x089a: { n:"MTRSettings", f:parse_MTRSettings, r:12 },
187350x089b: { n:"CompressPictures", f:parsenoop2 },
187360x089c: { n:"HeaderFooter" },
187370x089d: { n:"CrtLayout12" },
187380x089e: { n:"CrtMlFrt" },
187390x089f: { n:"CrtMlFrtContinue" },
187400x08a3: { n:"ForceFullCalculation", f:parse_ForceFullCalculation },
187410x08a4: { n:"ShapePropsStream" },
187420x08a5: { n:"TextPropsStream" },
187430x08a6: { n:"RichTextStream" },
187440x08a7: { n:"CrtLayout12A" },
187450x1001: { n:"Units" },
187460x1002: { n:"Chart" },
187470x1003: { n:"Series" },
187480x1006: { n:"DataFormat" },
187490x1007: { n:"LineFormat" },
187500x1009: { n:"MarkerFormat" },
187510x100a: { n:"AreaFormat" },
187520x100b: { n:"PieFormat" },
187530x100c: { n:"AttachedLabel" },
187540x100d: { n:"SeriesText" },
187550x1014: { n:"ChartFormat" },
187560x1015: { n:"Legend" },
187570x1016: { n:"SeriesList" },
187580x1017: { n:"Bar" },
187590x1018: { n:"Line" },
187600x1019: { n:"Pie" },
187610x101a: { n:"Area" },
187620x101b: { n:"Scatter" },
187630x101c: { n:"CrtLine" },
187640x101d: { n:"Axis" },
187650x101e: { n:"Tick" },
187660x101f: { n:"ValueRange" },
187670x1020: { n:"CatSerRange" },
187680x1021: { n:"AxisLine" },
187690x1022: { n:"CrtLink" },
187700x1024: { n:"DefaultText" },
187710x1025: { n:"Text" },
187720x1026: { n:"FontX", f:parseuint16 },
187730x1027: { n:"ObjectLink" },
187740x1032: { n:"Frame" },
187750x1033: { n:"Begin" },
187760x1034: { n:"End" },
187770x1035: { n:"PlotArea" },
187780x103a: { n:"Chart3d" },
187790x103c: { n:"PicF" },
187800x103d: { n:"DropBar" },
187810x103e: { n:"Radar" },
187820x103f: { n:"Surf" },
187830x1040: { n:"RadarArea" },
187840x1041: { n:"AxisParent" },
187850x1043: { n:"LegendException" },
187860x1044: { n:"ShtProps", f:parse_ShtProps },
187870x1045: { n:"SerToCrt" },
187880x1046: { n:"AxesUsed" },
187890x1048: { n:"SBaseRef" },
187900x104a: { n:"SerParent" },
187910x104b: { n:"SerAuxTrend" },
187920x104e: { n:"IFmtRecord" },
187930x104f: { n:"Pos" },
187940x1050: { n:"AlRuns" },
187950x1051: { n:"BRAI" },
187960x105b: { n:"SerAuxErrBar" },
187970x105c: { n:"ClrtClient", f:parse_ClrtClient },
187980x105d: { n:"SerFmt" },
187990x105f: { n:"Chart3DBarShape" },
188000x1060: { n:"Fbi" },
188010x1061: { n:"BopPop" },
188020x1062: { n:"AxcExt" },
188030x1063: { n:"Dat" },
188040x1064: { n:"PlotGrowth" },
188050x1065: { n:"SIIndex" },
188060x1066: { n:"GelFrame" },
188070x1067: { n:"BopPopCustom" },
188080x1068: { n:"Fbi2" },
18809
188100x0000: { n:"Dimensions", f:parse_Dimensions },
188110x0002: { n:"BIFF2INT", f:parse_BIFF2INT },
188120x0005: { n:"BoolErr", f:parse_BoolErr },
188130x0007: { n:"String", f:parse_BIFF2STRING },
188140x0008: { n:"BIFF2ROW" },
188150x000b: { n:"Index" },
188160x0016: { n:"ExternCount", f:parseuint16 },
188170x001e: { n:"BIFF2FORMAT", f:parse_BIFF2Format },
188180x001f: { n:"BIFF2FMTCNT" }, /* 16-bit cnt of BIFF2FORMAT records */
188190x0020: { n:"BIFF2COLINFO" },
188200x0021: { n:"Array", f:parse_Array },
188210x0025: { n:"DefaultRowHeight", f:parse_DefaultRowHeight },
188220x0032: { n:"BIFF2FONTXTRA", f:parse_BIFF2FONTXTRA },
188230x0034: { n:"DDEObjName" },
188240x003e: { n:"BIFF2WINDOW2" },
188250x0043: { n:"BIFF2XF" },
188260x0045: { n:"BIFF2FONTCLR" },
188270x0056: { n:"BIFF4FMTCNT" }, /* 16-bit cnt, similar to BIFF2 */
188280x007e: { n:"RK" }, /* Not necessarily same as 0x027e */
188290x007f: { n:"ImData", f:parse_ImData },
188300x0087: { n:"Addin" },
188310x0088: { n:"Edg" },
188320x0089: { n:"Pub" },
188330x0091: { n:"Sub" },
188340x0094: { n:"LHRecord" },
188350x0095: { n:"LHNGraph" },
188360x0096: { n:"Sound" },
188370x00a9: { n:"CoordList" },
188380x00ab: { n:"GCW" },
188390x00bc: { n:"ShrFmla" }, /* Not necessarily same as 0x04bc */
188400x00bf: { n:"ToolbarHdr" },
188410x00c0: { n:"ToolbarEnd" },
188420x00c2: { n:"AddMenu" },
188430x00c3: { n:"DelMenu" },
188440x00d6: { n:"RString", f:parse_RString },
188450x00df: { n:"UDDesc" },
188460x00ea: { n:"TabIdConf" },
188470x0162: { n:"XL5Modify" },
188480x01a5: { n:"FileSharing2" },
188490x0209: { n:'BOF', f:parse_BOF },
188500x0218: { n:"Lbl", f:parse_Lbl },
188510x0223: { n:"ExternName", f:parse_ExternName },
188520x0231: { n:"Font" },
188530x0243: { n:"BIFF3XF" },
188540x0409: { n:'BOF', f:parse_BOF },
188550x0443: { n:"BIFF4XF" },
188560x086d: { n:"FeatInfo" },
188570x0873: { n:"FeatInfo11" },
188580x0881: { n:"SXAddl12" },
188590x08c0: { n:"AutoWebPub" },
188600x08c1: { n:"ListObj" },
188610x08c2: { n:"ListField" },
188620x08c3: { n:"ListDV" },
188630x08c4: { n:"ListCondFmt" },
188640x08c5: { n:"ListCF" },
188650x08c6: { n:"FMQry" },
188660x08c7: { n:"FMSQry" },
188670x08c8: { n:"PLV" },
188680x08c9: { n:"LnExt" },
188690x08ca: { n:"MkrExt" },
188700x08cb: { n:"CrtCoopt" },
188710x08d6: { n:"FRTArchId$", r:12 },
18872
188730x7262: {}
18874};
18875
18876var XLSRE = evert_key(XLSRecordEnum, 'n');
18877function write_biff_rec(ba, type, payload, length) {
18878 var t = +type || +XLSRE[type];
18879 if(isNaN(t)) return;
18880 var len = length || (payload||[]).length || 0;
18881 var o = ba.next(4);
18882 o.write_shift(2, t);
18883 o.write_shift(2, len);
18884 if(len > 0 && is_buf(payload)) ba.push(payload);
18885}
18886
18887//function write_biff_continue(ba, type, payload, length) {
18888// var len = length || (payload||[]).length || 0;
18889// if(len <= 8224) return write_biff_rec(ba, type, payload, len);
18890// var t = +type || +XLSRE[type];
18891// if(isNaN(t)) return;
18892// var parts = payload.parts || [], sidx = 0;
18893// var i = 0, w = 0;
18894// while(w + (parts[sidx] || 8224) <= 8224) { w+= (parts[sidx] || 8224); sidx++; }
18895// var o = ba.next(4);
18896// o.write_shift(2, t);
18897// o.write_shift(2, w);
18898// ba.push(payload.slice(i, i + w));
18899// i += w;
18900// while(i < len) {
18901// o = ba.next(4);
18902// o.write_shift(2, 0x3c); // TODO: figure out correct continue type
18903// w = 0;
18904// while(w + (parts[sidx] || 8224) <= 8224) { w+= (parts[sidx] || 8224); sidx++; }
18905// o.write_shift(2, w);
18906// ba.push(payload.slice(i, i+w)); i+= w;
18907// }
18908//}
18909
18910function write_BIFF2Cell(out, r, c) {
18911 if(!out) out = new_buf(7);
18912 out.write_shift(2, r);
18913 out.write_shift(2, c);
18914 out.write_shift(2, 0);
18915 out.write_shift(1, 0);
18916 return out;
18917}
18918
18919function write_BIFF2BERR(r, c, val, t) {
18920 var out = new_buf(9);
18921 write_BIFF2Cell(out, r, c);
18922 if(t == 'e') { out.write_shift(1, val); out.write_shift(1, 1); }
18923 else { out.write_shift(1, val?1:0); out.write_shift(1, 0); }
18924 return out;
18925}
18926
18927/* TODO: codepage, large strings */
18928function write_BIFF2LABEL(r, c, val) {
18929 var out = new_buf(8 + 2*val.length);
18930 write_BIFF2Cell(out, r, c);
18931 out.write_shift(1, val.length);
18932 out.write_shift(val.length, val, 'sbcs');
18933 return out.l < out.length ? out.slice(0, out.l) : out;
18934}
18935
18936function write_ws_biff2_cell(ba, cell, R, C) {
18937 if(cell.v != null) switch(cell.t) {
18938 case 'd': case 'n':
18939 var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
18940 if((v == (v|0)) && (v >= 0) && (v < 65536))
18941 write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
18942 else
18943 write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
18944 return;
18945 case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
18946 /* TODO: codepage, sst */
18947 case 's': case 'str':
18948 write_biff_rec(ba, 0x0004, write_BIFF2LABEL(R, C, cell.v));
18949 return;
18950 }
18951 write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
18952}
18953
18954function write_ws_biff2(ba, ws, idx, opts) {
18955 var dense = Array.isArray(ws);
18956 var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
18957 if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
18958 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
18959 range.e.c = Math.min(range.e.c, 0xFF);
18960 range.e.r = Math.min(range.e.c, 0x3FFF);
18961 ref = encode_range(range);
18962 }
18963 for(var R = range.s.r; R <= range.e.r; ++R) {
18964 rr = encode_row(R);
18965 for(var C = range.s.c; C <= range.e.c; ++C) {
18966 if(R === range.s.r) cols[C] = encode_col(C);
18967 ref = cols[C] + rr;
18968 var cell = dense ? (ws[R]||[])[C] : ws[ref];
18969 if(!cell) continue;
18970 /* write cell */
18971 write_ws_biff2_cell(ba, cell, R, C, opts);
18972 }
18973 }
18974}
18975
18976/* Based on test files */
18977function write_biff2_buf(wb, opts) {
18978 var o = opts || {};
18979 if(DENSE != null && o.dense == null) o.dense = DENSE;
18980 var ba = buf_array();
18981 var idx = 0;
18982 for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
18983 if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
18984 write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o));
18985 /* ... */
18986 write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
18987 /* ... */
18988 write_biff_rec(ba, 0x000A);
18989 return ba.end();
18990}
18991
18992function write_FONTS_biff8(ba, data, opts) {
18993 write_biff_rec(ba, "Font", write_Font({
18994 sz:12,
18995 color: {theme:1},
18996 name: "Arial",
18997 family: 2,
18998 scheme: "minor"
18999 }, opts));
19000}
19001
19002
19003function write_FMTS_biff8(ba, NF, opts) {
19004 if(!NF) return;
19005 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
19006for(var i = r[0]; i <= r[1]; ++i) if(NF[i] != null) write_biff_rec(ba, "Format", write_Format(i, NF[i], opts));
19007 });
19008}
19009
19010function write_FEAT(ba, ws) {
19011 /* [MS-XLS] 2.4.112 */
19012 var o = new_buf(19);
19013 o.write_shift(4, 0x867); o.write_shift(4, 0); o.write_shift(4, 0);
19014 o.write_shift(2, 3); o.write_shift(1, 1); o.write_shift(4, 0);
19015 write_biff_rec(ba, "FeatHdr", o);
19016 /* [MS-XLS] 2.4.111 */
19017 o = new_buf(39);
19018 o.write_shift(4, 0x868); o.write_shift(4, 0); o.write_shift(4, 0);
19019 o.write_shift(2, 3); o.write_shift(1, 0); o.write_shift(4, 0);
19020 o.write_shift(2, 1); o.write_shift(4, 4); o.write_shift(2, 0);
19021 write_Ref8U(safe_decode_range(ws['!ref']||"A1"), o);
19022 o.write_shift(4, 4);
19023 write_biff_rec(ba, "Feat", o);
19024}
19025
19026function write_CELLXFS_biff8(ba, opts) {
19027 for(var i = 0; i < 16; ++i) write_biff_rec(ba, "XF", write_XF({numFmtId:0, style:true}, 0, opts));
19028 opts.cellXfs.forEach(function(c) {
19029 write_biff_rec(ba, "XF", write_XF(c, 0, opts));
19030 });
19031}
19032
19033function write_ws_biff8_hlinks(ba, ws) {
19034 for(var R=0; R<ws['!links'].length; ++R) {
19035 var HL = ws['!links'][R];
19036 write_biff_rec(ba, "HLink", write_HLink(HL));
19037 if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
19038 }
19039 delete ws['!links'];
19040}
19041
19042function write_ws_biff8_cell(ba, cell, R, C, opts) {
19043 var os = 16 + get_cell_style(opts.cellXfs, cell, opts);
19044 if(cell.v == null && !cell.bf) {
19045 write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
19046 return;
19047 }
19048 if(cell.bf) write_biff_rec(ba, "Formula", write_Formula(cell, R, C, opts, os));
19049 else switch(cell.t) {
19050 case 'd': case 'n':
19051 var v = cell.t == 'd' ? datenum(parseDate(cell.v)) : cell.v;
19052 /* TODO: emit RK as appropriate */
19053 write_biff_rec(ba, "Number", write_Number(R, C, v, os, opts));
19054 break;
19055 case 'b': case 'e':
19056 write_biff_rec(ba, 0x0205, write_BoolErr(R, C, cell.v, os, opts, cell.t));
19057 break;
19058 /* TODO: codepage, sst */
19059 case 's': case 'str':
19060 write_biff_rec(ba, "Label", write_Label(R, C, cell.v, os, opts));
19061 break;
19062 default:
19063 write_biff_rec(ba, "Blank", write_XLSCell(R, C, os));
19064 }
19065}
19066
19067/* [MS-XLS] 2.1.7.20.5 */
19068function write_ws_biff8(idx, opts, wb) {
19069 var ba = buf_array();
19070 var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
19071 var _WB = ((wb||{}).Workbook||{});
19072 var _sheet = ((_WB.Sheets||[])[idx]||{});
19073 var dense = Array.isArray(ws);
19074 var b8 = opts.biff == 8;
19075 var ref, rr = "", cols = [];
19076 var range = safe_decode_range(ws['!ref'] || "A1");
19077 var MAX_ROWS = b8 ? 65536 : 16384;
19078 if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
19079 if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
19080 range.e.c = Math.min(range.e.c, 0xFF);
19081 range.e.r = Math.min(range.e.c, MAX_ROWS-1);
19082 }
19083
19084 write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
19085 /* [Uncalced] Index */
19086 write_biff_rec(ba, "CalcMode", writeuint16(1));
19087 write_biff_rec(ba, "CalcCount", writeuint16(100));
19088 write_biff_rec(ba, "CalcRefMode", writebool(true));
19089 write_biff_rec(ba, "CalcIter", writebool(false));
19090 write_biff_rec(ba, "CalcDelta", write_Xnum(0.001));
19091 write_biff_rec(ba, "CalcSaveRecalc", writebool(true));
19092 write_biff_rec(ba, "PrintRowCol", writebool(false));
19093 write_biff_rec(ba, "PrintGrid", writebool(false));
19094 write_biff_rec(ba, "GridSet", writeuint16(1));
19095 write_biff_rec(ba, "Guts", write_Guts([0,0]));
19096 /* DefaultRowHeight WsBool [Sync] [LPr] [HorizontalPageBreaks] [VerticalPageBreaks] */
19097 /* Header (string) */
19098 /* Footer (string) */
19099 write_biff_rec(ba, "HCenter", writebool(false));
19100 write_biff_rec(ba, "VCenter", writebool(false));
19101 /* ... */
19102 write_biff_rec(ba, 0x200, write_Dimensions(range, opts));
19103 /* ... */
19104
19105 if(b8) ws['!links'] = [];
19106 for(var R = range.s.r; R <= range.e.r; ++R) {
19107 rr = encode_row(R);
19108 for(var C = range.s.c; C <= range.e.c; ++C) {
19109 if(R === range.s.r) cols[C] = encode_col(C);
19110 ref = cols[C] + rr;
19111 var cell = dense ? (ws[R]||[])[C] : ws[ref];
19112 if(!cell) continue;
19113 /* write cell */
19114 write_ws_biff8_cell(ba, cell, R, C, opts);
19115 if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
19116 }
19117 }
19118 var cname = _sheet.CodeName || _sheet.name || s;
19119 /* ... */
19120 if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0]));
19121 /* ... */
19122 if(b8 && (ws['!merges']||[]).length) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']));
19123 /* [LRng] *QUERYTABLE [PHONETICINFO] CONDFMTS */
19124 if(b8) write_ws_biff8_hlinks(ba, ws);
19125 /* [DVAL] */
19126 write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
19127 /* *WebPub *CellWatch [SheetExt] */
19128 if(b8) write_FEAT(ba, ws);
19129 /* *FEAT11 *RECORD12 */
19130 write_biff_rec(ba, "EOF");
19131 return ba.end();
19132}
19133
19134/* [MS-XLS] 2.1.7.20.3 */
19135function write_biff8_global(wb, bufs, opts) {
19136 var A = buf_array();
19137 var _WB = ((wb||{}).Workbook||{});
19138 var _sheets = (_WB.Sheets||[]);
19139 var _wb = _WB.WBProps||{};
19140 var b8 = opts.biff == 8, b5 = opts.biff == 5;
19141 write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
19142 if(opts.bookType == "xla") write_biff_rec(A, "Addin");
19143 write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null);
19144 write_biff_rec(A, "Mms", writezeroes(2));
19145 if(b5) write_biff_rec(A, "ToolbarHdr");
19146 if(b5) write_biff_rec(A, "ToolbarEnd");
19147 write_biff_rec(A, "InterfaceEnd");
19148 write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
19149 /* [FileSharing] */
19150 write_biff_rec(A, "CodePage", writeuint16(b8 ? 0x04b0 : 0x04E4));
19151 /* *2047 Lel */
19152 if(b8) write_biff_rec(A, "DSF", writeuint16(0));
19153 if(b8) write_biff_rec(A, "Excel9File");
19154 write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
19155 if(b8 && wb.vbaraw) write_biff_rec(A, "ObProj");
19156 /* [ObNoMacros] */
19157 if(b8 && wb.vbaraw) {
19158 var cname = _wb.CodeName || "ThisWorkbook";
19159 write_biff_rec(A, "CodeName", write_XLUnicodeString(cname, opts));
19160 }
19161 write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11));
19162 /* *FnGroupName *FnGrp12 */
19163 /* *Lbl */
19164 /* [OleObjectSize] */
19165 write_biff_rec(A, "WinProtect", writebool(false));
19166 write_biff_rec(A, "Protect", writebool(false));
19167 write_biff_rec(A, "Password", writeuint16(0));
19168 if(b8) write_biff_rec(A, "Prot4Rev", writebool(false));
19169 if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0));
19170 write_biff_rec(A, "Window1", write_Window1(opts));
19171 write_biff_rec(A, "Backup", writebool(false));
19172 write_biff_rec(A, "HideObj", writeuint16(0));
19173 write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true"));
19174 write_biff_rec(A, "CalcPrecision", writebool(true));
19175 if(b8) write_biff_rec(A, "RefreshAll", writebool(false));
19176 write_biff_rec(A, "BookBool", writeuint16(0));
19177 /* ... */
19178 write_FONTS_biff8(A, wb, opts);
19179 write_FMTS_biff8(A, wb.SSF, opts);
19180 write_CELLXFS_biff8(A, opts);
19181 /* ... */
19182 if(b8) write_biff_rec(A, "UsesELFs", writebool(false));
19183 var a = A.end();
19184
19185 var C = buf_array();
19186 /* METADATA [MTRSettings] [ForceFullCalculation] */
19187 if(b8) write_biff_rec(C, "Country", write_Country());
19188 /* *SUPBOOK *LBL *RTD [RecalcId] *HFPicture *MSODRAWINGGROUP */
19189 /* BIFF8: [SST *Continue] ExtSST */
19190 /* *WebPub [WOpt] [CrErr] [BookExt] *FeatHdr *DConn [THEME] [CompressPictures] [Compat12] [GUIDTypeLib] */
19191 write_biff_rec(C, "EOF");
19192 var c = C.end();
19193
19194 var B = buf_array();
19195 var blen = 0, j = 0;
19196 for(j = 0; j < wb.SheetNames.length; ++j) blen += (b8 ? 12 : 11) + (b8 ? 2 : 1) * wb.SheetNames[j].length;
19197 var start = a.length + blen + c.length;
19198 for(j = 0; j < wb.SheetNames.length; ++j) {
19199 var _sheet = _sheets[j] || ({});
19200 write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:_sheet.Hidden||0, dt:0, name:wb.SheetNames[j]}, opts));
19201 start += bufs[j].length;
19202 }
19203 /* 1*BoundSheet8 */
19204 var b = B.end();
19205 if(blen != b.length) throw new Error("BS8 " + blen + " != " + b.length);
19206
19207 var out = [];
19208 if(a.length) out.push(a);
19209 if(b.length) out.push(b);
19210 if(c.length) out.push(c);
19211 return __toBuffer([out]);
19212}
19213
19214/* [MS-XLS] 2.1.7.20 Workbook Stream */
19215function write_biff8_buf(wb, opts) {
19216 var o = opts || {};
19217 var bufs = [];
19218
19219 if(wb && !wb.SSF) {
19220 wb.SSF = SSF.get_table();
19221 }
19222 if(wb && wb.SSF) {
19223 make_ssf(SSF); SSF.load_table(wb.SSF);
19224 // $FlowIgnore
19225 o.revssf = evert_num(wb.SSF); o.revssf[wb.SSF[65535]] = 0;
19226 o.ssf = wb.SSF;
19227 }
19228
19229 o.Strings = []; o.Strings.Count = 0; o.Strings.Unique = 0;
19230 fix_write_opts(o);
19231
19232 o.cellXfs = [];
19233 get_cell_style(o.cellXfs, {}, {revssf:{"General":0}});
19234
19235 if(!wb.Props) wb.Props = {};
19236
19237 for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb);
19238 bufs.unshift(write_biff8_global(wb, bufs, o));
19239 return __toBuffer([bufs]);
19240}
19241
19242function write_biff_buf(wb, opts) {
19243 var o = opts || {};
19244 switch(o.biff || 2) {
19245 case 8: case 5: return write_biff8_buf(wb, opts);
19246 case 4: case 3: case 2: return write_biff2_buf(wb, opts);
19247 }
19248 throw new Error("invalid type " + o.bookType + " for BIFF");
19249}
19250/* note: browser DOM element cannot see mso- style attrs, must parse */
19251var HTML_ = (function() {
19252 function html_to_sheet(str, _opts) {
19253 var opts = _opts || {};
19254 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
19255 var ws = opts.dense ? ([]) : ({});
19256 str = str.replace(/<!--.*?-->/g, "");
19257 var mtch = str.match(/<table/i);
19258 if(!mtch) throw new Error("Invalid HTML: could not find <table>");
19259 var mtch2 = str.match(/<\/table/i);
19260 var i = mtch.index, j = mtch2 && mtch2.index || str.length;
19261 var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
19262 var R = -1, C = 0, RS = 0, CS = 0;
19263 var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
19264 var merges = [];
19265 for(i = 0; i < rows.length; ++i) {
19266 var row = rows[i].trim();
19267 var hd = row.slice(0,3).toLowerCase();
19268 if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
19269 if(hd != "<td" && hd != "<th") continue;
19270 var cells = row.split(/<\/t[dh]>/i);
19271 for(j = 0; j < cells.length; ++j) {
19272 var cell = cells[j].trim();
19273 if(!cell.match(/<t[dh]/i)) continue;
19274 var m = cell, cc = 0;
19275 /* TODO: parse styles etc */
19276 while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
19277 for(var midx = 0; midx < merges.length; ++midx) {
19278 var _merge = merges[midx];
19279 if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; }
19280 }
19281 var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
19282 CS = tag.colspan ? +tag.colspan : 1;
19283 if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
19284 var _t = tag.t || "";
19285 /* TODO: generate stub cells */
19286 if(!m.length) { C += CS; continue; }
19287 m = htmldecode(m);
19288 if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
19289 if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
19290 if(!m.length) continue;
19291 var o = {t:'s', v:m};
19292 if(opts.raw || !m.trim().length || _t == 's'){}
19293 else if(m === 'TRUE') o = {t:'b', v:true};
19294 else if(m === 'FALSE') o = {t:'b', v:false};
19295 else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
19296 else if(!isNaN(fuzzydate(m).getDate())) {
19297 o = ({t:'d', v:parseDate(m)});
19298 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
19299 o.z = opts.dateNF || SSF._table[14];
19300 }
19301 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
19302 else ws[encode_cell({r:R, c:C})] = o;
19303 C += CS;
19304 }
19305 }
19306 ws['!ref'] = encode_range(range);
19307 if(merges.length) ws["!merges"] = merges;
19308 return ws;
19309 }
19310 function html_to_book(str, opts) {
19311 return sheet_to_workbook(html_to_sheet(str, opts), opts);
19312 }
19313 function make_html_row(ws, r, R, o) {
19314 var M = (ws['!merges'] ||[]);
19315 var oo = [];
19316 for(var C = r.s.c; C <= r.e.c; ++C) {
19317 var RS = 0, CS = 0;
19318 for(var j = 0; j < M.length; ++j) {
19319 if(M[j].s.r > R || M[j].s.c > C) continue;
19320 if(M[j].e.r < R || M[j].e.c < C) continue;
19321 if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
19322 RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
19323 }
19324 if(RS < 0) continue;
19325 var coord = encode_cell({r:R,c:C});
19326 var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
19327 /* TODO: html entities */
19328 var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
19329 var sp = ({});
19330 if(RS > 1) sp.rowspan = RS;
19331 if(CS > 1) sp.colspan = CS;
19332 sp.t = cell && cell.t || 'z';
19333 if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
19334 sp.id = (o.id || "sjs") + "-" + coord;
19335 oo.push(writextag('td', w, sp));
19336 }
19337 var preamble = "<tr>";
19338 return preamble + oo.join("") + "</tr>";
19339 }
19340 function make_html_preamble(ws, R, o) {
19341 var out = [];
19342 return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
19343 }
19344 var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
19345 var _END = '</body></html>';
19346 function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
19347 var o = opts || {};
19348 var header = o.header != null ? o.header : _BEGIN;
19349 var footer = o.footer != null ? o.footer : _END;
19350 var out = [header];
19351 var r = decode_range(ws['!ref']);
19352 o.dense = Array.isArray(ws);
19353 out.push(make_html_preamble(ws, r, o));
19354 for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
19355 out.push("</table>" + footer);
19356 return out.join("");
19357 }
19358
19359 return {
19360 to_workbook: html_to_book,
19361 to_sheet: html_to_sheet,
19362 _row: make_html_row,
19363 BEGIN: _BEGIN,
19364 END: _END,
19365 _preamble: make_html_preamble,
19366 from_sheet: sheet_to_html
19367 };
19368})();
19369
19370function parse_dom_table(table, _opts) {
19371 var opts = _opts || {};
19372 if(DENSE != null) opts.dense = DENSE;
19373 var ws = opts.dense ? ([]) : ({});
19374 var rows = table.getElementsByTagName('tr');
19375 var sheetRows = opts.sheetRows || 10000000;
19376 var range = {s:{r:0,c:0},e:{r:0,c:0}};
19377 var merges = [], midx = 0;
19378 var rowinfo = [];
19379 var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
19380 for(; _R < rows.length && R < sheetRows; ++_R) {
19381 var row = rows[_R];
19382 if (is_dom_element_hidden(row)) {
19383 if (opts.display) continue;
19384 rowinfo[R] = {hidden: true};
19385 }
19386 var elts = (row.children);
19387 for(_C = C = 0; _C < elts.length; ++_C) {
19388 var elt = elts[_C];
19389 if (opts.display && is_dom_element_hidden(elt)) continue;
19390 var v = htmldecode(elt.innerHTML);
19391 for(midx = 0; midx < merges.length; ++midx) {
19392 var m = merges[midx];
19393 if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
19394 }
19395 /* TODO: figure out how to extract nonstandard mso- style */
19396 CS = +elt.getAttribute("colspan") || 1;
19397 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}});
19398 var o = {t:'s', v:v};
19399 var _t = elt.getAttribute("t") || "";
19400 if(v != null) {
19401 if(v.length == 0) o.t = _t || 'z';
19402 else if(opts.raw || v.trim().length == 0 || _t == "s"){}
19403 else if(v === 'TRUE') o = {t:'b', v:true};
19404 else if(v === 'FALSE') o = {t:'b', v:false};
19405 else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
19406 else if(!isNaN(fuzzydate(v).getDate())) {
19407 o = ({t:'d', v:parseDate(v)});
19408 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
19409 o.z = opts.dateNF || SSF._table[14];
19410 }
19411 }
19412 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
19413 else ws[encode_cell({c:C, r:R})] = o;
19414 if(range.e.c < C) range.e.c = C;
19415 C += CS;
19416 }
19417 ++R;
19418 }
19419 if(merges.length) ws['!merges'] = merges;
19420 if(rowinfo.length) ws['!rows'] = rowinfo;
19421 range.e.r = R - 1;
19422 ws['!ref'] = encode_range(range);
19423 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
19424 return ws;
19425}
19426
19427function table_to_book(table, opts) {
19428 return sheet_to_workbook(parse_dom_table(table, opts), opts);
19429}
19430
19431function is_dom_element_hidden(element) {
19432 var display = '';
19433 var get_computed_style = get_get_computed_style_function(element);
19434 if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
19435 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)
19436 return display === 'none';
19437}
19438
19439/* global getComputedStyle */
19440function get_get_computed_style_function(element) {
19441 // The proper getComputedStyle implementation is the one defined in the element window
19442 if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
19443 // If it is not available, try to get one from the global namespace
19444 if(typeof getComputedStyle === 'function') return getComputedStyle;
19445 return null;
19446}
19447/* OpenDocument */
19448var parse_content_xml = (function() {
19449
19450 var parse_text_p = function(text) {
19451 /* 6.1.2 White Space Characters */
19452 var fixed = text
19453 .replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
19454 .replace(/<text:s\/>/g," ")
19455 .replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
19456 .replace(/<text:tab[^>]*\/>/g,"\t")
19457 .replace(/<text:line-break\/>/g,"\n");
19458 var v = unescapexml(fixed.replace(/<[^>]*>/g,""));
19459
19460 return [v];
19461 };
19462
19463 var number_formats = {
19464 /* ods name: [short ssf fmt, long ssf fmt] */
19465 day: ["d", "dd"],
19466 month: ["m", "mm"],
19467 year: ["y", "yy"],
19468 hours: ["h", "hh"],
19469 minutes: ["m", "mm"],
19470 seconds: ["s", "ss"],
19471 "am-pm": ["A/P", "AM/PM"],
19472 "day-of-week": ["ddd", "dddd"],
19473 era: ["e", "ee"],
19474 /* there is no native representation of LO "Q" format */
19475 quarter: ["\\Qm", "m\\\"th quarter\""]
19476 };
19477
19478 return function pcx(d, _opts) {
19479 var opts = _opts || {};
19480 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
19481 var str = xlml_normalize(d);
19482 var state = [], tmp;
19483 var tag;
19484 var NFtag = {name:""}, NF = "", pidx = 0;
19485 var sheetag;
19486 var rowtag;
19487 var Sheets = {}, SheetNames = [];
19488 var ws = opts.dense ? ([]) : ({});
19489 var Rn, q;
19490 var ctag = ({value:""});
19491 var textp = "", textpidx = 0, textptag;
19492 var textR = [];
19493 var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
19494 var row_ol = 0;
19495 var number_format_map = {};
19496 var merges = [], mrange = {}, mR = 0, mC = 0;
19497 var rowinfo = [], rowpeat = 1, colpeat = 1;
19498 var arrayf = [];
19499 var WB = {Names:[]};
19500 var atag = ({});
19501 var _Ref = ["", ""];
19502 var comments = [], comment = ({});
19503 var creator = "", creatoridx = 0;
19504 var isstub = false, intable = false;
19505 var i = 0;
19506 xlmlregex.lastIndex = 0;
19507 str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
19508 while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
19509
19510 case 'table': case '工作表': // 9.1.2 <table:table>
19511 if(Rn[1]==='/') {
19512 if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
19513 if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
19514 ws['!fullref'] = ws['!ref'];
19515 range.e.r = opts.sheetRows - 1;
19516 ws['!ref'] = encode_range(range);
19517 }
19518 if(merges.length) ws['!merges'] = merges;
19519 if(rowinfo.length) ws["!rows"] = rowinfo;
19520 sheetag.name = sheetag['名称'] || sheetag.name;
19521 if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
19522 SheetNames.push(sheetag.name);
19523 Sheets[sheetag.name] = ws;
19524 intable = false;
19525 }
19526 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
19527 sheetag = parsexmltag(Rn[0], false);
19528 R = C = -1;
19529 range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
19530 ws = opts.dense ? ([]) : ({}); merges = [];
19531 rowinfo = [];
19532 intable = true;
19533 }
19534 break;
19535
19536 case 'table-row-group': // 9.1.9 <table:table-row-group>
19537 if(Rn[1] === "/") --row_ol; else ++row_ol;
19538 break;
19539 case 'table-row': case '行': // 9.1.3 <table:table-row>
19540 if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
19541 rowtag = parsexmltag(Rn[0], false);
19542 if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
19543 rowpeat = +rowtag['number-rows-repeated'] || 1;
19544 /* TODO: remove magic */
19545 if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
19546 C = -1; break;
19547 case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
19548 if(Rn[1] !== '/') ++C;
19549 if(opts.sheetStubs) {
19550 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
19551 else ws[encode_cell({r:R,c:C})] = {t:'z'};
19552 }
19553 textp = ""; textR = [];
19554 break; /* stub */
19555 case 'table-cell': case '数据':
19556 if(Rn[0].charAt(Rn[0].length-2) === '/') {
19557 ++C;
19558 ctag = parsexmltag(Rn[0], false);
19559 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19560 q = ({t:'z', v:null});
19561 if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
19562 if((ctag['数据类型'] || ctag['value-type']) == "string") {
19563 q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
19564 if(opts.dense) {
19565 if(!ws[R]) ws[R] = [];
19566 ws[R][C] = q;
19567 } else {
19568 ws[encode_cell({r:R,c:C})] = q;
19569 }
19570 }
19571 C+= colpeat-1;
19572 } else if(Rn[1]!=='/') {
19573 ++C;
19574 colpeat = 1;
19575 var rptR = rowpeat ? R + rowpeat - 1 : R;
19576 if(C > range.e.c) range.e.c = C;
19577 if(C < range.s.c) range.s.c = C;
19578 if(R < range.s.r) range.s.r = R;
19579 if(rptR > range.e.r) range.e.r = rptR;
19580 ctag = parsexmltag(Rn[0], false);
19581 comments = []; comment = ({});
19582 q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
19583 if(opts.cellFormula) {
19584 if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
19585 if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
19586 mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
19587 mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
19588 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
19589 q.F = encode_range(mrange);
19590 arrayf.push([mrange, q.F]);
19591 }
19592 if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
19593 else for(i = 0; i < arrayf.length; ++i)
19594 if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
19595 if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
19596 q.F = arrayf[i][1];
19597 }
19598 if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
19599 mR = parseInt(ctag['number-rows-spanned'],10) || 0;
19600 mC = parseInt(ctag['number-columns-spanned'],10) || 0;
19601 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
19602 merges.push(mrange);
19603 }
19604
19605 /* 19.675.2 table:number-columns-repeated */
19606 if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
19607
19608 /* 19.385 office:value-type */
19609 switch(q.t) {
19610 case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
19611 case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19612 case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19613 case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
19614 case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
19615 if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
19616 q.z = 'm/d/yy'; break;
19617 case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
19618 case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
19619 default:
19620 if(q.t === 'string' || q.t === 'text' || !q.t) {
19621 q.t = 's';
19622 if(ctag['string-value'] != null) { textp = unescapexml(ctag['string-value']); textR = []; }
19623 } else throw new Error('Unsupported value type ' + q.t);
19624 }
19625 } else {
19626 isstub = false;
19627 if(q.t === 's') {
19628 q.v = textp || '';
19629 if(textR.length) q.R = textR;
19630 isstub = textpidx == 0;
19631 }
19632 if(atag.Target) q.l = atag;
19633 if(comments.length > 0) { q.c = comments; comments = []; }
19634 if(textp && opts.cellText !== false) q.w = textp;
19635 if(isstub) { q.t = "z"; delete q.v; }
19636 if(!isstub || opts.sheetStubs) {
19637 if(!(opts.sheetRows && opts.sheetRows <= R)) {
19638 for(var rpt = 0; rpt < rowpeat; ++rpt) {
19639 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19640 if(opts.dense) {
19641 if(!ws[R + rpt]) ws[R + rpt] = [];
19642 ws[R + rpt][C] = rpt == 0 ? q : dup(q);
19643 while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
19644 } else {
19645 ws[encode_cell({r:R + rpt,c:C})] = q;
19646 while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
19647 }
19648 if(range.e.c <= C) range.e.c = C;
19649 }
19650 }
19651 }
19652 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
19653 C += colpeat-1; colpeat = 0;
19654 q = {};
19655 textp = ""; textR = [];
19656 }
19657 atag = ({});
19658 break; // 9.1.4 <table:table-cell>
19659
19660 /* pure state */
19661 case 'document': // TODO: <office:document> is the root for FODS
19662 case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
19663 case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
19664 case 'scripts': // 3.12 <office:scripts>
19665 case 'styles': // TODO <office:styles>
19666 case 'font-face-decls': // 3.14 <office:font-face-decls>
19667 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
19668 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
19669 break;
19670
19671 case 'annotation': // 14.1 <office:annotation>
19672 if(Rn[1]==='/'){
19673 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
19674 comment.t = textp;
19675 if(textR.length) comment.R = textR;
19676 comment.a = creator;
19677 comments.push(comment);
19678 }
19679 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
19680 creator = ""; creatoridx = 0;
19681 textp = ""; textpidx = 0; textR = [];
19682 break;
19683
19684 case 'creator': // 4.3.2.7 <dc:creator>
19685 if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
19686 else creatoridx = Rn.index + Rn[0].length;
19687 break;
19688
19689 /* ignore state */
19690 case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
19691 case 'settings': // TODO: <office:settings>
19692 case 'config-item-set': // TODO: <office:config-item-set>
19693 case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
19694 case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
19695 case 'config-item-map-named': // TODO: <office:config-item-map-entry>
19696 case 'shapes': // 9.2.8 <table:shapes>
19697 case 'frame': // 10.4.2 <draw:frame>
19698 case 'text-box': // 10.4.3 <draw:text-box>
19699 case 'image': // 10.4.4 <draw:image>
19700 case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
19701 case 'list-style': // 16.30 <text:list-style>
19702 case 'form': // 13.13 <form:form>
19703 case 'dde-links': // 9.8 <table:dde-links>
19704 case 'event-listeners': // TODO
19705 case 'chart': // TODO
19706 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
19707 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
19708 textp = ""; textpidx = 0; textR = [];
19709 break;
19710
19711 case 'scientific-number': // TODO: <number:scientific-number>
19712 break;
19713 case 'currency-symbol': // TODO: <number:currency-symbol>
19714 break;
19715 case 'currency-style': // TODO: <number:currency-style>
19716 break;
19717 case 'number-style': // 16.27.2 <number:number-style>
19718 case 'percentage-style': // 16.27.9 <number:percentage-style>
19719 case 'date-style': // 16.27.10 <number:date-style>
19720 case 'time-style': // 16.27.18 <number:time-style>
19721 if(Rn[1]==='/'){
19722 number_format_map[NFtag.name] = NF;
19723 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
19724 } else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
19725 NF = "";
19726 NFtag = parsexmltag(Rn[0], false);
19727 state.push([Rn[3], true]);
19728 } break;
19729
19730 case 'script': break; // 3.13 <office:script>
19731 case 'libraries': break; // TODO: <ooo:libraries>
19732 case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
19733 case 'master-styles': break; // TODO: <office:master-styles>
19734
19735 case 'default-style': // TODO: <style:default-style>
19736 case 'page-layout': break; // TODO: <style:page-layout>
19737 case 'style': // 16.2 <style:style>
19738 break;
19739 case 'map': break; // 16.3 <style:map>
19740 case 'font-face': break; // 16.21 <style:font-face>
19741
19742 case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
19743 case 'table-properties': break; // 17.15 <style:table-properties>
19744 case 'table-column-properties': break; // 17.16 <style:table-column-properties>
19745 case 'table-row-properties': break; // 17.17 <style:table-row-properties>
19746 case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
19747
19748 case 'number': // 16.27.3 <number:number>
19749 switch(state[state.length-1][0]) {
19750 case 'time-style':
19751 case 'date-style':
19752 tag = parsexmltag(Rn[0], false);
19753 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
19754 } break;
19755
19756 case 'fraction': break; // TODO 16.27.6 <number:fraction>
19757
19758 case 'day': // 16.27.11 <number:day>
19759 case 'month': // 16.27.12 <number:month>
19760 case 'year': // 16.27.13 <number:year>
19761 case 'era': // 16.27.14 <number:era>
19762 case 'day-of-week': // 16.27.15 <number:day-of-week>
19763 case 'week-of-year': // 16.27.16 <number:week-of-year>
19764 case 'quarter': // 16.27.17 <number:quarter>
19765 case 'hours': // 16.27.19 <number:hours>
19766 case 'minutes': // 16.27.20 <number:minutes>
19767 case 'seconds': // 16.27.21 <number:seconds>
19768 case 'am-pm': // 16.27.22 <number:am-pm>
19769 switch(state[state.length-1][0]) {
19770 case 'time-style':
19771 case 'date-style':
19772 tag = parsexmltag(Rn[0], false);
19773 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
19774 } break;
19775
19776 case 'boolean-style': break; // 16.27.23 <number:boolean-style>
19777 case 'boolean': break; // 16.27.24 <number:boolean>
19778 case 'text-style': break; // 16.27.25 <number:text-style>
19779 case 'text': // 16.27.26 <number:text>
19780 if(Rn[0].slice(-2) === "/>") break;
19781 else if(Rn[1]==="/") switch(state[state.length-1][0]) {
19782 case 'number-style':
19783 case 'date-style':
19784 case 'time-style':
19785 NF += str.slice(pidx, Rn.index);
19786 break;
19787 }
19788 else pidx = Rn.index + Rn[0].length;
19789 break;
19790
19791 case 'named-range': // 9.4.12 <table:named-range>
19792 tag = parsexmltag(Rn[0], false);
19793 _Ref = ods_to_csf_3D(tag['cell-range-address']);
19794 var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
19795 if(intable) nrange.Sheet = SheetNames.length;
19796 WB.Names.push(nrange);
19797 break;
19798
19799 case 'text-content': break; // 16.27.27 <number:text-content>
19800 case 'text-properties': break; // 16.27.27 <style:text-properties>
19801 case 'embedded-text': break; // 16.27.4 <number:embedded-text>
19802
19803 case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
19804
19805 case 'forms': break; // 12.25.2 13.2
19806 case 'table-column': break; // 9.1.6 <table:table-column>
19807 case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
19808 case 'table-rows': break; // 9.1.12 <table:table-rows>
19809 /* TODO: outline levels */
19810 case 'table-column-group': break; // 9.1.10 <table:table-column-group>
19811 case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
19812 case 'table-columns': break; // 9.1.12 <table:table-columns>
19813
19814 case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
19815
19816 case 'graphic-properties': break; // 17.21 <style:graphic-properties>
19817 case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
19818 case 'named-expressions': break; // 9.4.11 <table:named-expressions>
19819 case 'label-range': break; // 9.4.9 <table:label-range>
19820 case 'label-ranges': break; // 9.4.10 <table:label-ranges>
19821 case 'named-expression': break; // 9.4.13 <table:named-expression>
19822 case 'sort': break; // 9.4.19 <table:sort>
19823 case 'sort-by': break; // 9.4.20 <table:sort-by>
19824 case 'sort-groups': break; // 9.4.22 <table:sort-groups>
19825
19826 case 'tab': break; // 6.1.4 <text:tab>
19827 case 'line-break': break; // 6.1.5 <text:line-break>
19828 case 'span': break; // 6.1.7 <text:span>
19829 case 'p': case '文本串': // 5.1.3 <text:p>
19830 if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) {
19831 var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
19832 textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0];
19833 } else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
19834 break; // <text:p>
19835 case 's': break; // <text:s>
19836
19837 case 'database-range': // 9.4.15 <table:database-range>
19838 if(Rn[1]==='/') break;
19839 try {
19840 _Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
19841 Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
19842 } catch(e) {/* empty */}
19843 break;
19844
19845 case 'date': break; // <*:date>
19846
19847 case 'object': break; // 10.4.6.2 <draw:object>
19848 case 'title': case '标题': break; // <*:title> OR <uof:标题>
19849 case 'desc': break; // <*:desc>
19850 case 'binary-data': break; // 10.4.5 TODO: b64 blob
19851
19852 /* 9.2 Advanced Tables */
19853 case 'table-source': break; // 9.2.6
19854 case 'scenario': break; // 9.2.6
19855
19856 case 'iteration': break; // 9.4.3 <table:iteration>
19857 case 'content-validations': break; // 9.4.4 <table:
19858 case 'content-validation': break; // 9.4.5 <table:
19859 case 'help-message': break; // 9.4.6 <table:
19860 case 'error-message': break; // 9.4.7 <table:
19861 case 'database-ranges': break; // 9.4.14 <table:database-ranges>
19862 case 'filter': break; // 9.5.2 <table:filter>
19863 case 'filter-and': break; // 9.5.3 <table:filter-and>
19864 case 'filter-or': break; // 9.5.4 <table:filter-or>
19865 case 'filter-condition': break; // 9.5.5 <table:filter-condition>
19866
19867 case 'list-level-style-bullet': break; // 16.31 <text:
19868 case 'list-level-style-number': break; // 16.32 <text:
19869 case 'list-level-properties': break; // 17.19 <style:
19870
19871 /* 7.3 Document Fields */
19872 case 'sender-firstname': // 7.3.6.2
19873 case 'sender-lastname': // 7.3.6.3
19874 case 'sender-initials': // 7.3.6.4
19875 case 'sender-title': // 7.3.6.5
19876 case 'sender-position': // 7.3.6.6
19877 case 'sender-email': // 7.3.6.7
19878 case 'sender-phone-private': // 7.3.6.8
19879 case 'sender-fax': // 7.3.6.9
19880 case 'sender-company': // 7.3.6.10
19881 case 'sender-phone-work': // 7.3.6.11
19882 case 'sender-street': // 7.3.6.12
19883 case 'sender-city': // 7.3.6.13
19884 case 'sender-postal-code': // 7.3.6.14
19885 case 'sender-country': // 7.3.6.15
19886 case 'sender-state-or-province': // 7.3.6.16
19887 case 'author-name': // 7.3.7.1
19888 case 'author-initials': // 7.3.7.2
19889 case 'chapter': // 7.3.8
19890 case 'file-name': // 7.3.9
19891 case 'template-name': // 7.3.9
19892 case 'sheet-name': // 7.3.9
19893 break;
19894
19895 case 'event-listener':
19896 break;
19897 /* TODO: FODS Properties */
19898 case 'initial-creator':
19899 case 'creation-date':
19900 case 'print-date':
19901 case 'generator':
19902 case 'document-statistic':
19903 case 'user-defined':
19904 case 'editing-duration':
19905 case 'editing-cycles':
19906 break;
19907
19908 /* TODO: FODS Config */
19909 case 'config-item':
19910 break;
19911
19912 /* TODO: style tokens */
19913 case 'page-number': break; // TODO <text:page-number>
19914 case 'page-count': break; // TODO <text:page-count>
19915 case 'time': break; // TODO <text:time>
19916
19917 /* 9.3 Advanced Table Cells */
19918 case 'cell-range-source': break; // 9.3.1 <table:
19919 case 'detective': break; // 9.3.2 <table:
19920 case 'operation': break; // 9.3.3 <table:
19921 case 'highlighted-range': break; // 9.3.4 <table:
19922
19923 /* 9.6 Data Pilot Tables <table: */
19924 case 'data-pilot-table': // 9.6.3
19925 case 'source-cell-range': // 9.6.5
19926 case 'source-service': // 9.6.6
19927 case 'data-pilot-field': // 9.6.7
19928 case 'data-pilot-level': // 9.6.8
19929 case 'data-pilot-subtotals': // 9.6.9
19930 case 'data-pilot-subtotal': // 9.6.10
19931 case 'data-pilot-members': // 9.6.11
19932 case 'data-pilot-member': // 9.6.12
19933 case 'data-pilot-display-info': // 9.6.13
19934 case 'data-pilot-sort-info': // 9.6.14
19935 case 'data-pilot-layout-info': // 9.6.15
19936 case 'data-pilot-field-reference': // 9.6.16
19937 case 'data-pilot-groups': // 9.6.17
19938 case 'data-pilot-group': // 9.6.18
19939 case 'data-pilot-group-member': // 9.6.19
19940 break;
19941
19942 /* 10.3 Drawing Shapes */
19943 case 'rect': // 10.3.2
19944 break;
19945
19946 /* 14.6 DDE Connections */
19947 case 'dde-connection-decls': // 14.6.2 <text:
19948 case 'dde-connection-decl': // 14.6.3 <text:
19949 case 'dde-link': // 14.6.4 <table:
19950 case 'dde-source': // 14.6.5 <office:
19951 break;
19952
19953 case 'properties': break; // 13.7 <form:properties>
19954 case 'property': break; // 13.8 <form:property>
19955
19956 case 'a': // 6.1.8 hyperlink
19957 if(Rn[1]!== '/') {
19958 atag = parsexmltag(Rn[0], false);
19959 if(!atag.href) break;
19960 atag.Target = atag.href; delete atag.href;
19961 if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
19962 _Ref = ods_to_csf_3D(atag.Target.slice(1));
19963 atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
19964 }
19965 }
19966 break;
19967
19968 /* non-standard */
19969 case 'table-protection': break;
19970 case 'data-pilot-grand-total': break; // <table:
19971 case 'office-document-common-attrs': break; // bare
19972 default: switch(Rn[2]) {
19973 case 'dc:': // TODO: properties
19974 case 'calcext:': // ignore undocumented extensions
19975 case 'loext:': // ignore undocumented extensions
19976 case 'ooo:': // ignore undocumented extensions
19977 case 'chartooo:': // ignore undocumented extensions
19978 case 'draw:': // TODO: drawing
19979 case 'style:': // TODO: styles
19980 case 'chart:': // TODO: charts
19981 case 'form:': // TODO: forms
19982 case 'uof:': // TODO: uof
19983 case '表:': // TODO: uof
19984 case '字:': // TODO: uof
19985 break;
19986 default: if(opts.WTF) throw new Error(Rn);
19987 }
19988 }
19989 var out = ({
19990 Sheets: Sheets,
19991 SheetNames: SheetNames,
19992 Workbook: WB
19993 });
19994 if(opts.bookSheets) delete out.Sheets;
19995 return out;
19996 };
19997})();
19998
19999function parse_ods(zip, opts) {
20000 opts = opts || ({});
20001 var ods = !!safegetzipfile(zip, 'objectdata');
20002 if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
20003 var content = getzipstr(zip, 'content.xml');
20004 if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
20005 var wb = parse_content_xml(ods ? content : utf8read(content), opts);
20006 if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
20007 return wb;
20008}
20009function parse_fods(data, opts) {
20010 return parse_content_xml(data, opts);
20011}
20012
20013/* OpenDocument */
20014var write_styles_ods = (function() {
20015 var payload = '<office:document-styles ' + wxt_helper({
20016 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
20017 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
20018 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
20019 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
20020 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
20021 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
20022 'xmlns:xlink': "http://www.w3.org/1999/xlink",
20023 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
20024 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
20025 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
20026 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
20027 'office:version': "1.2"
20028 }) + '></office:document-styles>';
20029 return function wso() {
20030 return XML_HEADER + payload;
20031 };
20032})();
20033var write_content_ods = (function() {
20034 /* 6.1.2 White Space Characters */
20035 var write_text_p = function(text) {
20036 return escapexml(text)
20037 .replace(/ +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
20038 .replace(/\t/g, "<text:tab/>")
20039 .replace(/\n/g, "<text:line-break/>")
20040 .replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
20041 };
20042
20043 var null_cell_xml = ' <table:table-cell />\n';
20044 var covered_cell_xml = ' <table:covered-table-cell/>\n';
20045 var write_ws = function(ws, wb, i) {
20046 /* Section 9 Tables */
20047 var o = [];
20048 o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '">\n');
20049 var R=0,C=0, range = decode_range(ws['!ref']);
20050 var marr = ws['!merges'] || [], mi = 0;
20051 var dense = Array.isArray(ws);
20052 for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
20053 for(; R <= range.e.r; ++R) {
20054 o.push(' <table:table-row>\n');
20055 for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
20056 for(; C <= range.e.c; ++C) {
20057 var skip = false, ct = {}, textp = "";
20058 for(mi = 0; mi != marr.length; ++mi) {
20059 if(marr[mi].s.c > C) continue;
20060 if(marr[mi].s.r > R) continue;
20061 if(marr[mi].e.c < C) continue;
20062 if(marr[mi].e.r < R) continue;
20063 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
20064 ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
20065 ct['table:number-rows-spanned'] = (marr[mi].e.r - marr[mi].s.r + 1);
20066 break;
20067 }
20068 if(skip) { o.push(covered_cell_xml); continue; }
20069 var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
20070 if(cell && cell.f) {
20071 ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
20072 if(cell.F) {
20073 if(cell.F.slice(0, ref.length) == ref) {
20074 var _Fref = decode_range(cell.F);
20075 ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
20076 ct['table:number-matrix-rows-spanned'] = (_Fref.e.r - _Fref.s.r + 1);
20077 }
20078 }
20079 }
20080 if(!cell) { o.push(null_cell_xml); continue; }
20081 switch(cell.t) {
20082 case 'b':
20083 textp = (cell.v ? 'TRUE' : 'FALSE');
20084 ct['office:value-type'] = "boolean";
20085 ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
20086 break;
20087 case 'n':
20088 textp = (cell.w||String(cell.v||0));
20089 ct['office:value-type'] = "float";
20090 ct['office:value'] = (cell.v||0);
20091 break;
20092 case 's': case 'str':
20093 textp = cell.v;
20094 ct['office:value-type'] = "string";
20095 break;
20096 case 'd':
20097 textp = (cell.w||(parseDate(cell.v).toISOString()));
20098 ct['office:value-type'] = "date";
20099 ct['office:date-value'] = (parseDate(cell.v).toISOString());
20100 ct['table:style-name'] = "ce1";
20101 break;
20102 //case 'e':
20103 default: o.push(null_cell_xml); continue;
20104 }
20105 var text_p = write_text_p(textp);
20106 if(cell.l && cell.l.Target) {
20107 var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
20108 text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
20109 }
20110 o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
20111 }
20112 o.push(' </table:table-row>\n');
20113 }
20114 o.push(' </table:table>\n');
20115 return o.join("");
20116 };
20117
20118 var write_automatic_styles_ods = function(o) {
20119 o.push(' <office:automatic-styles>\n');
20120 o.push(' <number:date-style style:name="N37" number:automatic-order="true">\n');
20121 o.push(' <number:month number:style="long"/>\n');
20122 o.push(' <number:text>/</number:text>\n');
20123 o.push(' <number:day number:style="long"/>\n');
20124 o.push(' <number:text>/</number:text>\n');
20125 o.push(' <number:year/>\n');
20126 o.push(' </number:date-style>\n');
20127
20128 o.push(' <style:style style:name="ta1" style:family="table">\n'); // style:master-page-name="mp1">\n');
20129 o.push(' <style:table-properties table:display="true" style:writing-mode="lr-tb"/>\n');
20130 o.push(' </style:style>\n');
20131
20132 o.push(' <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
20133 o.push(' </office:automatic-styles>\n');
20134 };
20135
20136 return function wcx(wb, opts) {
20137 var o = [XML_HEADER];
20138 /* 3.1.3.2 */
20139 var attr = wxt_helper({
20140 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
20141 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
20142 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
20143 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
20144 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
20145 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
20146 'xmlns:xlink': "http://www.w3.org/1999/xlink",
20147 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
20148 'xmlns:meta': "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
20149 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
20150 'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
20151 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
20152 'xmlns:chart': "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
20153 'xmlns:dr3d': "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
20154 'xmlns:math': "http://www.w3.org/1998/Math/MathML",
20155 'xmlns:form': "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
20156 'xmlns:script': "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
20157 'xmlns:ooo': "http://openoffice.org/2004/office",
20158 'xmlns:ooow': "http://openoffice.org/2004/writer",
20159 'xmlns:oooc': "http://openoffice.org/2004/calc",
20160 'xmlns:dom': "http://www.w3.org/2001/xml-events",
20161 'xmlns:xforms': "http://www.w3.org/2002/xforms",
20162 'xmlns:xsd': "http://www.w3.org/2001/XMLSchema",
20163 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
20164 'xmlns:sheet': "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
20165 'xmlns:rpt': "http://openoffice.org/2005/report",
20166 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
20167 'xmlns:xhtml': "http://www.w3.org/1999/xhtml",
20168 'xmlns:grddl': "http://www.w3.org/2003/g/data-view#",
20169 'xmlns:tableooo': "http://openoffice.org/2009/table",
20170 'xmlns:drawooo': "http://openoffice.org/2010/draw",
20171 'xmlns:calcext': "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
20172 'xmlns:loext': "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
20173 'xmlns:field': "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
20174 'xmlns:formx': "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
20175 'xmlns:css3t': "http://www.w3.org/TR/css3-text/",
20176 'office:version': "1.2"
20177 });
20178
20179 var fods = wxt_helper({
20180 'xmlns:config': "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
20181 'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
20182 });
20183
20184 if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n');
20185 else o.push('<office:document-content' + attr + '>\n');
20186 write_automatic_styles_ods(o);
20187 o.push(' <office:body>\n');
20188 o.push(' <office:spreadsheet>\n');
20189 for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
20190 o.push(' </office:spreadsheet>\n');
20191 o.push(' </office:body>\n');
20192 if(opts.bookType == "fods") o.push('</office:document>');
20193 else o.push('</office:document-content>');
20194 return o.join("");
20195 };
20196})();
20197
20198function write_ods(wb, opts) {
20199 if(opts.bookType == "fods") return write_content_ods(wb, opts);
20200
20201var zip = zip_new();
20202 var f = "";
20203
20204 var manifest = [];
20205 var rdf = [];
20206
20207 /* Part 3 Section 3.3 MIME Media Type */
20208 f = "mimetype";
20209 zip_add_file(zip, f, "application/vnd.oasis.opendocument.spreadsheet");
20210
20211 /* Part 1 Section 2.2 Documents */
20212 f = "content.xml";
20213 zip_add_file(zip, f, write_content_ods(wb, opts));
20214 manifest.push([f, "text/xml"]);
20215 rdf.push([f, "ContentFile"]);
20216
20217 /* TODO: these are hard-coded styles to satiate excel */
20218 f = "styles.xml";
20219 zip_add_file(zip, f, write_styles_ods(wb, opts));
20220 manifest.push([f, "text/xml"]);
20221 rdf.push([f, "StylesFile"]);
20222
20223 /* TODO: this is hard-coded to satiate excel */
20224 f = "meta.xml";
20225 zip_add_file(zip, f, write_meta_ods());
20226 manifest.push([f, "text/xml"]);
20227 rdf.push([f, "MetadataFile"]);
20228
20229 /* Part 3 Section 6 Metadata Manifest File */
20230 f = "manifest.rdf";
20231 zip_add_file(zip, f, write_rdf(rdf/*, opts*/));
20232 manifest.push([f, "application/rdf+xml"]);
20233
20234 /* Part 3 Section 4 Manifest File */
20235 f = "META-INF/manifest.xml";
20236 zip_add_file(zip, f, write_manifest(manifest/*, opts*/));
20237
20238 return zip;
20239}
20240
20241function write_sheet_index(wb, sheet) {
20242 if(!sheet) return 0;
20243 var idx = wb.SheetNames.indexOf(sheet);
20244 if(idx == -1) throw new Error("Sheet not found: " + sheet);
20245 return idx;
20246}
20247
20248function write_obj_str(factory) {
20249 return function write_str(wb, o) {
20250 var idx = write_sheet_index(wb, o.sheet);
20251 return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
20252 };
20253}
20254
20255var write_htm_str = write_obj_str(HTML_);
20256var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
20257var write_slk_str = write_obj_str(typeof SYLK !== "undefined" ? SYLK : {});
20258var write_dif_str = write_obj_str(typeof DIF !== "undefined" ? DIF : {});
20259var write_prn_str = write_obj_str(typeof PRN !== "undefined" ? PRN : {});
20260var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {});
20261var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
20262var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {});
20263var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {});
20264
20265function fix_opts_func(defaults) {
20266 return function fix_opts(opts) {
20267 for(var i = 0; i != defaults.length; ++i) {
20268 var d = defaults[i];
20269 if(opts[d[0]] === undefined) opts[d[0]] = d[1];
20270 if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
20271 }
20272 };
20273}
20274
20275var fix_read_opts = fix_opts_func([
20276 ['cellNF', false], /* emit cell number format string as .z */
20277 ['cellHTML', true], /* emit html string as .h */
20278 ['cellFormula', true], /* emit formulae as .f */
20279 ['cellStyles', false], /* emits style/theme as .s */
20280 ['cellText', true], /* emit formatted text as .w */
20281 ['cellDates', false], /* emit date cells with type `d` */
20282
20283 ['sheetStubs', false], /* emit empty cells */
20284 ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
20285
20286 ['bookDeps', false], /* parse calculation chains */
20287 ['bookSheets', false], /* only try to get sheet names (no Sheets) */
20288 ['bookProps', false], /* only try to get properties (no Sheets) */
20289 ['bookFiles', false], /* include raw file structure (keys, files, cfb) */
20290 ['bookVBA', false], /* include vba raw data (vbaraw) */
20291
20292 ['password',''], /* password */
20293 ['WTF', false] /* WTF mode (throws errors) */
20294]);
20295
20296
20297var fix_write_opts = fix_opts_func([
20298 ['cellDates', false], /* write date cells with type `d` */
20299
20300 ['bookSST', false], /* Generate Shared String Table */
20301
20302 ['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
20303
20304 ['compression', false], /* Use file compression */
20305
20306 ['WTF', false] /* WTF mode (throws errors) */
20307]);
20308function get_sheet_type(n) {
20309 if(RELS.WS.indexOf(n) > -1) return "sheet";
20310 if(RELS.CS && n == RELS.CS) return "chart";
20311 if(RELS.DS && n == RELS.DS) return "dialog";
20312 if(RELS.MS && n == RELS.MS) return "macro";
20313 return (n && n.length) ? n : "sheet";
20314}
20315function safe_parse_wbrels(wbrels, sheets) {
20316 if(!wbrels) return 0;
20317 try {
20318 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)]; });
20319 } catch(e) { return null; }
20320 return !wbrels || wbrels.length === 0 ? null : wbrels;
20321}
20322
20323function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
20324 try {
20325 sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
20326 var data = getzipdata(zip, path);
20327 var _ws;
20328 switch(stype) {
20329 case 'sheet': _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
20330 case 'chart': _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
20331 if(!_ws || !_ws['!drawel']) break;
20332 var dfile = resolve_path(_ws['!drawel'].Target, path);
20333 var drelsp = get_rels_path(dfile);
20334 var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
20335 var chartp = resolve_path(draw, dfile);
20336 var crelsp = get_rels_path(chartp);
20337 _ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
20338 break;
20339 case 'macro': _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
20340 case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
20341 default: throw new Error("Unrecognized sheet type " + stype);
20342 }
20343 sheets[sheet] = _ws;
20344
20345 /* scan rels for comments */
20346 var comments = [];
20347 if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) {
20348 if(sheetRels[sheet][n].Type == RELS.CMNT) {
20349 var dfile = resolve_path(sheetRels[sheet][n].Target, path);
20350 comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
20351 if(!comments || !comments.length) return;
20352 sheet_insert_comments(_ws, comments);
20353 }
20354 });
20355 } catch(e) { if(opts.WTF) throw e; }
20356}
20357
20358function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
20359
20360function parse_zip(zip, opts) {
20361 make_ssf(SSF);
20362 opts = opts || {};
20363 fix_read_opts(opts);
20364
20365 /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
20366 if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
20367 /* UOC */
20368 if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
20369 /* Numbers */
20370 if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
20371
20372 var entries = zipentries(zip);
20373 var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
20374 var xlsb = false;
20375 var sheets, binname;
20376 if(dir.workbooks.length === 0) {
20377 binname = "xl/workbook.xml";
20378 if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
20379 }
20380 if(dir.workbooks.length === 0) {
20381 binname = "xl/workbook.bin";
20382 if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
20383 dir.workbooks.push(binname);
20384 xlsb = true;
20385 }
20386 if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
20387
20388 var themes = ({});
20389 var styles = ({});
20390 if(!opts.bookSheets && !opts.bookProps) {
20391 strs = [];
20392 if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
20393
20394 if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
20395
20396 if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
20397 }
20398
20399 /*var externbooks = */dir.links.map(function(link) {
20400 try {
20401 var rels = parse_rels(getzipstr(zip, get_rels_path(strip_front_slash(link))), link);
20402 return parse_xlink(getzipdata(zip, strip_front_slash(link)), rels, link, opts);
20403 } catch(e) {}
20404 });
20405
20406 var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
20407
20408 var props = {}, propdata = "";
20409
20410 if(dir.coreprops.length) {
20411 propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
20412 if(propdata) props = parse_core_props(propdata);
20413 if(dir.extprops.length !== 0) {
20414 propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
20415 if(propdata) parse_ext_props(propdata, props, opts);
20416 }
20417 }
20418
20419 var custprops = {};
20420 if(!opts.bookSheets || opts.bookProps) {
20421 if (dir.custprops.length !== 0) {
20422 propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
20423 if(propdata) custprops = parse_cust_props(propdata, opts);
20424 }
20425 }
20426
20427 var out = ({});
20428 if(opts.bookSheets || opts.bookProps) {
20429 if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
20430 else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
20431 if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
20432 if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
20433 if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
20434 }
20435 sheets = {};
20436
20437 var deps = {};
20438 if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
20439
20440 var i=0;
20441 var sheetRels = ({});
20442 var path, relsPath;
20443
20444 {
20445 var wbsheets = wb.Sheets;
20446 props.Worksheets = wbsheets.length;
20447 props.SheetNames = [];
20448 for(var j = 0; j != wbsheets.length; ++j) {
20449 props.SheetNames[j] = wbsheets[j].name;
20450 }
20451 }
20452
20453 var wbext = xlsb ? "bin" : "xml";
20454 var wbrelsi = dir.workbooks[0].lastIndexOf("/");
20455 var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
20456 if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
20457 var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
20458 if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
20459
20460 /* Numbers iOS hack */
20461 var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
20462 wsloop: for(i = 0; i != props.Worksheets; ++i) {
20463 var stype = "sheet";
20464 if(wbrels && wbrels[i]) {
20465 path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
20466 if(!safegetzipfile(zip, path)) path = wbrels[i][1];
20467 if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
20468 stype = wbrels[i][2];
20469 } else {
20470 path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
20471 path = path.replace(/sheet0\./,"sheet.");
20472 }
20473 relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
20474 if(opts && opts.sheets != null) switch(typeof opts.sheets) {
20475 case "number": if(i != opts.sheets) continue wsloop; break;
20476 case "string": if(props.SheetNames[i].toLowerCase() != opts.sheets.toLowerCase()) continue wsloop; break;
20477 default: if(Array.isArray && Array.isArray(opts.sheets)) {
20478 var snjseen = false;
20479 for(var snj = 0; snj != opts.sheets.length; ++snj) {
20480 if(typeof opts.sheets[snj] == "number" && opts.sheets[snj] == i) snjseen=1;
20481 if(typeof opts.sheets[snj] == "string" && opts.sheets[snj].toLowerCase() == props.SheetNames[i].toLowerCase()) snjseen = 1;
20482 }
20483 if(!snjseen) continue wsloop;
20484 }
20485 }
20486 safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
20487 }
20488
20489 out = ({
20490 Directory: dir,
20491 Workbook: wb,
20492 Props: props,
20493 Custprops: custprops,
20494 Deps: deps,
20495 Sheets: sheets,
20496 SheetNames: props.SheetNames,
20497 Strings: strs,
20498 Styles: styles,
20499 Themes: themes,
20500 SSF: SSF.get_table()
20501 });
20502 if(opts && opts.bookFiles) {
20503 out.keys = entries;
20504 out.files = zip.files;
20505 }
20506 if(opts && opts.bookVBA) {
20507 if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
20508 else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
20509 }
20510 return out;
20511}
20512
20513/* [MS-OFFCRYPTO] 2.1.1 */
20514function parse_xlsxcfb(cfb, _opts) {
20515 var opts = _opts || {};
20516 var f = 'Workbook', data = CFB.find(cfb, f);
20517 try {
20518 f = '/!DataSpaces/Version';
20519 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20520 /*var version = */parse_DataSpaceVersionInfo(data.content);
20521
20522 /* 2.3.4.1 */
20523 f = '/!DataSpaces/DataSpaceMap';
20524 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20525 var dsm = parse_DataSpaceMap(data.content);
20526 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")
20527 throw new Error("ECMA-376 Encrypted file bad " + f);
20528
20529 /* 2.3.4.2 */
20530 f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
20531 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20532 var seds = parse_DataSpaceDefinition(data.content);
20533 if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
20534 throw new Error("ECMA-376 Encrypted file bad " + f);
20535
20536 /* 2.3.4.3 */
20537 f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
20538 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20539 /*var hdr = */parse_Primary(data.content);
20540 } catch(e) {}
20541
20542 f = '/EncryptionInfo';
20543 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20544 var einfo = parse_EncryptionInfo(data.content);
20545
20546 /* 2.3.4.4 */
20547 f = '/EncryptedPackage';
20548 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
20549
20550/*global decrypt_agile */
20551if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
20552/*global decrypt_std76 */
20553if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
20554 throw new Error("File is password-protected");
20555}
20556
20557function write_zip(wb, opts) {
20558 _shapeid = 1024;
20559 if(opts.bookType == "ods") return write_ods(wb, opts);
20560 if(wb && !wb.SSF) {
20561 wb.SSF = SSF.get_table();
20562 }
20563 if(wb && wb.SSF) {
20564 make_ssf(SSF); SSF.load_table(wb.SSF);
20565 // $FlowIgnore
20566 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
20567 opts.ssf = wb.SSF;
20568 }
20569 opts.rels = {}; opts.wbrels = {};
20570 opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
20571 if(browser_has_Map) opts.revStrings = new Map();
20572 else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
20573 var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
20574 var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
20575 var ct = new_ct();
20576 fix_write_opts(opts = opts || {});
20577var zip = zip_new();
20578 var f = "", rId = 0;
20579
20580 opts.cellXfs = [];
20581 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
20582
20583 if(!wb.Props) wb.Props = {};
20584
20585 f = "docProps/core.xml";
20586 zip_add_file(zip, f, write_core_props(wb.Props, opts));
20587 ct.coreprops.push(f);
20588 add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
20589
20590f = "docProps/app.xml";
20591 if(wb.Props && wb.Props.SheetNames){/* empty */}
20592 else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
20593 else {
20594 var _sn = [];
20595 for(var _i = 0; _i < wb.SheetNames.length; ++_i)
20596 if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
20597 wb.Props.SheetNames = _sn;
20598 }
20599 wb.Props.Worksheets = wb.Props.SheetNames.length;
20600 zip_add_file(zip, f, write_ext_props(wb.Props, opts));
20601 ct.extprops.push(f);
20602 add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
20603
20604 if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
20605 f = "docProps/custom.xml";
20606 zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
20607 ct.custprops.push(f);
20608 add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
20609 }
20610
20611 for(rId=1;rId <= wb.SheetNames.length; ++rId) {
20612 var wsrels = {'!id':{}};
20613 var ws = wb.Sheets[wb.SheetNames[rId-1]];
20614 var _type = (ws || {})["!type"] || "sheet";
20615 switch(_type) {
20616 case "chart":
20617 /* falls through */
20618 default:
20619 f = "xl/worksheets/sheet" + rId + "." + wbext;
20620 zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels));
20621 ct.sheets.push(f);
20622 add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
20623 }
20624
20625 if(ws) {
20626 var comments = ws['!comments'];
20627 var need_vml = false;
20628 if(comments && comments.length > 0) {
20629 var cf = "xl/comments" + rId + "." + wbext;
20630 zip_add_file(zip, cf, write_cmnt(comments, cf, opts));
20631 ct.comments.push(cf);
20632 add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
20633 need_vml = true;
20634 }
20635 if(ws['!legacy']) {
20636 if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
20637 }
20638 delete ws['!comments'];
20639 delete ws['!legacy'];
20640 }
20641
20642 if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
20643 }
20644
20645 if(opts.Strings != null && opts.Strings.length > 0) {
20646 f = "xl/sharedStrings." + wbext;
20647 zip_add_file(zip, f, write_sst(opts.Strings, f, opts));
20648 ct.strs.push(f);
20649 add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
20650 }
20651
20652 f = "xl/workbook." + wbext;
20653 zip_add_file(zip, f, write_wb(wb, f, opts));
20654 ct.workbooks.push(f);
20655 add_rels(opts.rels, 1, f, RELS.WB);
20656
20657 /* TODO: something more intelligent with themes */
20658
20659 f = "xl/theme/theme1.xml";
20660 zip_add_file(zip, f, write_theme(wb.Themes, opts));
20661 ct.themes.push(f);
20662 add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
20663
20664 /* TODO: something more intelligent with styles */
20665
20666 f = "xl/styles." + wbext;
20667 zip_add_file(zip, f, write_sty(wb, f, opts));
20668 ct.styles.push(f);
20669 add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
20670
20671 if(wb.vbaraw && vbafmt) {
20672 f = "xl/vbaProject.bin";
20673 zip_add_file(zip, f, wb.vbaraw);
20674 ct.vba.push(f);
20675 add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
20676 }
20677
20678 zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
20679 zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
20680 zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
20681
20682 delete opts.revssf; delete opts.ssf;
20683 return zip;
20684}
20685function firstbyte(f,o) {
20686 var x = "";
20687 switch((o||{}).type || "base64") {
20688 case 'buffer': return [f[0], f[1], f[2], f[3]];
20689 case 'base64': x = Base64.decode(f.slice(0,24)); break;
20690 case 'binary': x = f; break;
20691 case 'array': return [f[0], f[1], f[2], f[3]];
20692 default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
20693 }
20694 return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)];
20695}
20696
20697function read_cfb(cfb, opts) {
20698 if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
20699 return parse_xlscfb(cfb, opts);
20700}
20701
20702function read_zip(data, opts) {
20703var zip, d = data;
20704 var o = opts||{};
20705 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
20706 zip = zip_read(d, o);
20707 return parse_zip(zip, o);
20708}
20709
20710function read_plaintext(data, o) {
20711 var i = 0;
20712 main: while(i < data.length) switch(data.charCodeAt(i)) {
20713 case 0x0A: case 0x0D: case 0x20: ++i; break;
20714 case 0x3C: return parse_xlml(data.slice(i),o);
20715 default: break main;
20716 }
20717 return PRN.to_workbook(data, o);
20718}
20719
20720function read_plaintext_raw(data, o) {
20721 var str = "", bytes = firstbyte(data, o);
20722 switch(o.type) {
20723 case 'base64': str = Base64.decode(data); break;
20724 case 'binary': str = data; break;
20725 case 'buffer': str = data.toString('binary'); break;
20726 case 'array': str = cc2str(data); break;
20727 default: throw new Error("Unrecognized type " + o.type);
20728 }
20729 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
20730 return read_plaintext(str, o);
20731}
20732
20733function read_utf16(data, o) {
20734 var d = data;
20735 if(o.type == 'base64') d = Base64.decode(d);
20736 d = cptable.utils.decode(1200, d.slice(2), 'str');
20737 o.type = "binary";
20738 return read_plaintext(d, o);
20739}
20740
20741function bstrify(data) {
20742 return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
20743}
20744
20745function read_prn(data, d, o, str) {
20746 if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
20747 return PRN.to_workbook(d, o);
20748}
20749
20750function readSync(data, opts) {
20751 reset_cp();
20752 if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
20753 var d = data, n = [0,0,0,0], str = false;
20754 var o = opts||{};
20755 if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
20756 _ssfopts = {};
20757 if(o.dateNF) _ssfopts.dateNF = o.dateNF;
20758 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
20759 if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
20760 if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
20761 if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
20762 // $FlowIgnore
20763 var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
20764 // $FlowIgnore
20765 if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
20766 }
20767 switch((n = firstbyte(d, o))[0]) {
20768 case 0xD0: return read_cfb(CFB.read(d, o), o);
20769 case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break;
20770 case 0x3C: return parse_xlml(d, o);
20771 case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
20772 case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
20773 case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
20774 case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
20775 case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
20776 case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
20777 case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
20778 case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
20779 case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
20780 }
20781 if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
20782 return read_prn(data, d, o, str);
20783}
20784
20785function readFileSync(filename, opts) {
20786 var o = opts||{}; o.type = 'file';
20787 return readSync(filename, o);
20788}
20789function write_cfb_ctr(cfb, o) {
20790 switch(o.type) {
20791 case "base64": case "binary": break;
20792 case "buffer": case "array": o.type = ""; break;
20793 case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
20794 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
20795 default: throw new Error("Unrecognized type " + o.type);
20796 }
20797 return CFB.write(cfb, o);
20798}
20799
20800function write_zip_type(wb, opts) {
20801 var o = opts||{};
20802 var z = write_zip(wb, o);
20803 var oopts = {};
20804 if(o.compression) oopts.compression = 'DEFLATE';
20805 if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
20806 else switch(o.type) {
20807 case "base64": oopts.type = "base64"; break;
20808 case "binary": oopts.type = "string"; break;
20809 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
20810 case "buffer":
20811 case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
20812 default: throw new Error("Unrecognized type " + o.type);
20813 }
20814 var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type}) : z.generate(oopts);
20815/*jshint -W083 */
20816 if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o); // eslint-disable-line no-undef
20817/*jshint +W083 */
20818 if(o.type === "file") return write_dl(o.file, out);
20819 return o.type == "string" ? utf8read(out) : out;
20820}
20821
20822function write_cfb_type(wb, opts) {
20823 var o = opts||{};
20824 var cfb = write_xlscfb(wb, o);
20825 return write_cfb_ctr(cfb, o);
20826}
20827
20828function write_string_type(out, opts, bom) {
20829 if(!bom) bom = "";
20830 var o = bom + out;
20831 switch(opts.type) {
20832 case "base64": return Base64.encode(utf8write(o));
20833 case "binary": return utf8write(o);
20834 case "string": return out;
20835 case "file": return write_dl(opts.file, o, 'utf8');
20836 case "buffer": {
20837 if(has_buf) return Buffer_from(o, 'utf8');
20838 else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
20839 }
20840 }
20841 throw new Error("Unrecognized type " + opts.type);
20842}
20843
20844function write_stxt_type(out, opts) {
20845 switch(opts.type) {
20846 case "base64": return Base64.encode(out);
20847 case "binary": return out;
20848 case "string": return out; /* override in sheet_to_txt */
20849 case "file": return write_dl(opts.file, out, 'binary');
20850 case "buffer": {
20851 if(has_buf) return Buffer_from(out, 'binary');
20852 else return out.split("").map(function(c) { return c.charCodeAt(0); });
20853 }
20854 }
20855 throw new Error("Unrecognized type " + opts.type);
20856}
20857
20858/* TODO: test consistency */
20859function write_binary_type(out, opts) {
20860 switch(opts.type) {
20861 case "string":
20862 case "base64":
20863 case "binary":
20864 var bstr = "";
20865 // $FlowIgnore
20866 for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
20867 return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
20868 case "file": return write_dl(opts.file, out);
20869 case "buffer": return out;
20870 default: throw new Error("Unrecognized type " + opts.type);
20871 }
20872}
20873
20874function writeSync(wb, opts) {
20875 reset_cp();
20876 check_wb(wb);
20877 var o = opts||{};
20878 if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
20879 if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
20880 switch(o.bookType || 'xlsb') {
20881 case 'xml':
20882 case 'xlml': return write_string_type(write_xlml(wb, o), o);
20883 case 'slk':
20884 case 'sylk': return write_string_type(write_slk_str(wb, o), o);
20885 case 'htm':
20886 case 'html': return write_string_type(write_htm_str(wb, o), o);
20887 case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
20888 case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
20889 case 'dif': return write_string_type(write_dif_str(wb, o), o);
20890 case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
20891 case 'prn': return write_string_type(write_prn_str(wb, o), o);
20892 case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
20893 case 'eth': return write_string_type(write_eth_str(wb, o), o);
20894 case 'fods': return write_string_type(write_ods(wb, o), o);
20895 case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
20896 case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
20897 case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
20898 case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
20899 case 'biff8':
20900 case 'xla':
20901 case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
20902 case 'xlsx':
20903 case 'xlsm':
20904 case 'xlam':
20905 case 'xlsb':
20906 case 'ods': return write_zip_type(wb, o);
20907 default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
20908 }
20909}
20910
20911function resolve_book_type(o) {
20912 if(o.bookType) return;
20913 var _BT = {
20914 "xls": "biff8",
20915 "htm": "html",
20916 "slk": "sylk",
20917 "socialcalc": "eth",
20918 "Sh33tJS": "WTF"
20919 };
20920 var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
20921 if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
20922 o.bookType = _BT[o.bookType] || o.bookType;
20923}
20924
20925function writeFileSync(wb, filename, opts) {
20926 var o = opts||{}; o.type = 'file';
20927 o.file = filename;
20928 resolve_book_type(o);
20929 return writeSync(wb, o);
20930}
20931
20932function writeFileAsync(filename, wb, opts, cb) {
20933 var o = opts||{}; o.type = 'file';
20934 o.file = filename;
20935 resolve_book_type(o);
20936 o.type = 'buffer';
20937 var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
20938 return _fs.writeFile(filename, writeSync(wb, o), _cb);
20939}
20940function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
20941 var rr = encode_row(R);
20942 var defval = o.defval, raw = o.raw || !Object.prototype.hasOwnProperty.call(o, "raw");
20943 var isempty = true;
20944 var row = (header === 1) ? [] : {};
20945 if(header !== 1) {
20946 if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
20947 else row.__rowNum__ = R;
20948 }
20949 if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
20950 var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
20951 if(val === undefined || val.t === undefined) {
20952 if(defval === undefined) continue;
20953 if(hdr[C] != null) { row[hdr[C]] = defval; }
20954 continue;
20955 }
20956 var v = val.v;
20957 switch(val.t){
20958 case 'z': if(v == null) break; continue;
20959 case 'e': v = void 0; break;
20960 case 's': case 'd': case 'b': case 'n': break;
20961 default: throw new Error('unrecognized type ' + val.t);
20962 }
20963 if(hdr[C] != null) {
20964 if(v == null) {
20965 if(defval !== undefined) row[hdr[C]] = defval;
20966 else if(raw && v === null) row[hdr[C]] = null;
20967 else continue;
20968 } else {
20969 row[hdr[C]] = raw ? v : format_cell(val,v,o);
20970 }
20971 if(v != null) isempty = false;
20972 }
20973 }
20974 return { row: row, isempty: isempty };
20975}
20976
20977
20978function sheet_to_json(sheet, opts) {
20979 if(sheet == null || sheet["!ref"] == null) return [];
20980 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
20981 var r = {s:{r:0,c:0},e:{r:0,c:0}};
20982 var o = opts || {};
20983 var range = o.range != null ? o.range : sheet["!ref"];
20984 if(o.header === 1) header = 1;
20985 else if(o.header === "A") header = 2;
20986 else if(Array.isArray(o.header)) header = 3;
20987 else if(o.header == null) header = 0;
20988 switch(typeof range) {
20989 case 'string': r = safe_decode_range(range); break;
20990 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
20991 default: r = range;
20992 }
20993 if(header > 0) offset = 0;
20994 var rr = encode_row(r.s.r);
20995 var cols = [];
20996 var out = [];
20997 var outi = 0, counter = 0;
20998 var dense = Array.isArray(sheet);
20999 var R = r.s.r, C = 0, CC = 0;
21000 if(dense && !sheet[R]) sheet[R] = [];
21001 for(C = r.s.c; C <= r.e.c; ++C) {
21002 cols[C] = encode_col(C);
21003 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
21004 switch(header) {
21005 case 1: hdr[C] = C - r.s.c; break;
21006 case 2: hdr[C] = cols[C]; break;
21007 case 3: hdr[C] = o.header[C - r.s.c]; break;
21008 default:
21009 if(val == null) val = {w: "__EMPTY", t: "s"};
21010 vv = v = format_cell(val, null, o);
21011 counter = 0;
21012 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
21013 hdr[C] = vv;
21014 }
21015 }
21016 for (R = r.s.r + offset; R <= r.e.r; ++R) {
21017 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
21018 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
21019 }
21020 out.length = outi;
21021 return out;
21022}
21023
21024var qreg = /"/g;
21025function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
21026 var isempty = true;
21027 var row = [], txt = "", rr = encode_row(R);
21028 for(var C = r.s.c; C <= r.e.c; ++C) {
21029 if (!cols[C]) continue;
21030 var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
21031 if(val == null) txt = "";
21032 else if(val.v != null) {
21033 isempty = false;
21034 txt = ''+format_cell(val, null, o);
21035 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; }
21036 if(txt == "ID") txt = '"ID"';
21037 } else if(val.f != null && !val.F) {
21038 isempty = false;
21039 txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
21040 } else txt = "";
21041 /* NOTE: Excel CSV does not support array formulae */
21042 row.push(txt);
21043 }
21044 if(o.blankrows === false && isempty) return null;
21045 return row.join(FS);
21046}
21047
21048function sheet_to_csv(sheet, opts) {
21049 var out = [];
21050 var o = opts == null ? {} : opts;
21051 if(sheet == null || sheet["!ref"] == null) return "";
21052 var r = safe_decode_range(sheet["!ref"]);
21053 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
21054 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
21055 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
21056 var row = "", cols = [];
21057 o.dense = Array.isArray(sheet);
21058 var colinfo = o.skipHidden && sheet["!cols"] || [];
21059 var rowinfo = o.skipHidden && sheet["!rows"] || [];
21060 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
21061 for(var R = r.s.r; R <= r.e.r; ++R) {
21062 if ((rowinfo[R]||{}).hidden) continue;
21063 row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
21064 if(row == null) { continue; }
21065 if(o.strip) row = row.replace(endregex,"");
21066 out.push(row + RS);
21067 }
21068 delete o.dense;
21069 return out.join("");
21070}
21071
21072function sheet_to_txt(sheet, opts) {
21073 if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
21074 var s = sheet_to_csv(sheet, opts);
21075 if(typeof cptable == 'undefined' || opts.type == 'string') return s;
21076 var o = cptable.utils.encode(1200, s, 'str');
21077 return String.fromCharCode(255) + String.fromCharCode(254) + o;
21078}
21079
21080function sheet_to_formulae(sheet) {
21081 var y = "", x, val="";
21082 if(sheet == null || sheet["!ref"] == null) return [];
21083 var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
21084 var cmds = [];
21085 var dense = Array.isArray(sheet);
21086 for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
21087 for(var R = r.s.r; R <= r.e.r; ++R) {
21088 rr = encode_row(R);
21089 for(C = r.s.c; C <= r.e.c; ++C) {
21090 y = cols[C] + rr;
21091 x = dense ? (sheet[R]||[])[C] : sheet[y];
21092 val = "";
21093 if(x === undefined) continue;
21094 else if(x.F != null) {
21095 y = x.F;
21096 if(!x.f) continue;
21097 val = x.f;
21098 if(y.indexOf(":") == -1) y = y + ":" + y;
21099 }
21100 if(x.f != null) val = x.f;
21101 else if(x.t == 'z') continue;
21102 else if(x.t == 'n' && x.v != null) val = "" + x.v;
21103 else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
21104 else if(x.w !== undefined) val = "'" + x.w;
21105 else if(x.v === undefined) continue;
21106 else if(x.t == 's') val = "'" + x.v;
21107 else val = ""+x.v;
21108 cmds[cmds.length] = y + "=" + val;
21109 }
21110 }
21111 return cmds;
21112}
21113
21114function sheet_add_json(_ws, js, opts) {
21115 var o = opts || {};
21116 var offset = +!o.skipHeader;
21117 var ws = _ws || ({});
21118 var _R = 0, _C = 0;
21119 if(ws && o.origin != null) {
21120 if(typeof o.origin == 'number') _R = o.origin;
21121 else {
21122 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
21123 _R = _origin.r; _C = _origin.c;
21124 }
21125 }
21126 var cell;
21127 var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
21128 if(ws['!ref']) {
21129 var _range = safe_decode_range(ws['!ref']);
21130 range.e.c = Math.max(range.e.c, _range.e.c);
21131 range.e.r = Math.max(range.e.r, _range.e.r);
21132 if(_R == -1) { _R = range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
21133 }
21134 var hdr = o.header || [], C = 0;
21135
21136 js.forEach(function (JS, R) {
21137 keys(JS).forEach(function(k) {
21138 if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
21139 var v = JS[k];
21140 var t = 'z';
21141 var z = "";
21142 var ref = encode_cell({c:_C + C,r:_R + R + offset});
21143 cell = utils.sheet_get_cell(ws, ref);
21144 if(v && typeof v === 'object' && !(v instanceof Date)){
21145 ws[ref] = v;
21146 } else {
21147 if(typeof v == 'number') t = 'n';
21148 else if(typeof v == 'boolean') t = 'b';
21149 else if(typeof v == 'string') t = 's';
21150 else if(v instanceof Date) {
21151 t = 'd';
21152 if(!o.cellDates) { t = 'n'; v = datenum(v); }
21153 z = (o.dateNF || SSF._table[14]);
21154 }
21155 if(!cell) ws[ref] = cell = ({t:t, v:v});
21156 else {
21157 cell.t = t; cell.v = v;
21158 delete cell.w; delete cell.R;
21159 if(z) cell.z = z;
21160 }
21161 if(z) cell.z = z;
21162 }
21163 });
21164 });
21165 range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
21166 var __R = encode_row(_R);
21167 if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
21168 ws['!ref'] = encode_range(range);
21169 return ws;
21170}
21171function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
21172
21173var utils = {
21174 encode_col: encode_col,
21175 encode_row: encode_row,
21176 encode_cell: encode_cell,
21177 encode_range: encode_range,
21178 decode_col: decode_col,
21179 decode_row: decode_row,
21180 split_cell: split_cell,
21181 decode_cell: decode_cell,
21182 decode_range: decode_range,
21183 format_cell: format_cell,
21184 get_formulae: sheet_to_formulae,
21185 make_csv: sheet_to_csv,
21186 make_json: sheet_to_json,
21187 make_formulae: sheet_to_formulae,
21188 sheet_add_aoa: sheet_add_aoa,
21189 sheet_add_json: sheet_add_json,
21190 aoa_to_sheet: aoa_to_sheet,
21191 json_to_sheet: json_to_sheet,
21192 table_to_sheet: parse_dom_table,
21193 table_to_book: table_to_book,
21194 sheet_to_csv: sheet_to_csv,
21195 sheet_to_txt: sheet_to_txt,
21196 sheet_to_json: sheet_to_json,
21197 sheet_to_html: HTML_.from_sheet,
21198 sheet_to_formulae: sheet_to_formulae,
21199 sheet_to_row_object_array: sheet_to_json
21200};
21201
21202(function(utils) {
21203utils.consts = utils.consts || {};
21204function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
21205
21206function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
21207
21208/* get cell, creating a stub if necessary */
21209function ws_get_cell_stub(ws, R, C) {
21210 /* A1 cell address */
21211 if(typeof R == "string") {
21212 /* dense */
21213 if(Array.isArray(ws)) {
21214 var RC = decode_cell(R);
21215 if(!ws[RC.r]) ws[RC.r] = [];
21216 return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
21217 }
21218 return ws[R] || (ws[R] = {t:'z'});
21219 }
21220 /* cell address object */
21221 if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
21222 /* R and C are 0-based indices */
21223 return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
21224}
21225utils.sheet_get_cell = ws_get_cell_stub;
21226
21227/* find sheet index for given name / validate index */
21228function wb_sheet_idx(wb, sh) {
21229 if(typeof sh == "number") {
21230 if(sh >= 0 && wb.SheetNames.length > sh) return sh;
21231 throw new Error("Cannot find sheet # " + sh);
21232 } else if(typeof sh == "string") {
21233 var idx = wb.SheetNames.indexOf(sh);
21234 if(idx > -1) return idx;
21235 throw new Error("Cannot find sheet name |" + sh + "|");
21236 } else throw new Error("Cannot find sheet |" + sh + "|");
21237}
21238
21239/* simple blank workbook object */
21240utils.book_new = function() {
21241 return { SheetNames: [], Sheets: {} };
21242};
21243
21244/* add a worksheet to the end of a given workbook */
21245utils.book_append_sheet = function(wb, ws, name) {
21246 if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
21247 if(!name) throw new Error("Too many worksheets");
21248 check_ws_name(name);
21249 if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
21250
21251 wb.SheetNames.push(name);
21252 wb.Sheets[name] = ws;
21253};
21254
21255/* set sheet visibility (visible/hidden/very hidden) */
21256utils.book_set_sheet_visibility = function(wb, sh, vis) {
21257 get_default(wb,"Workbook",{});
21258 get_default(wb.Workbook,"Sheets",[]);
21259
21260 var idx = wb_sheet_idx(wb, sh);
21261 // $FlowIgnore
21262 get_default(wb.Workbook.Sheets,idx, {});
21263
21264 switch(vis) {
21265 case 0: case 1: case 2: break;
21266 default: throw new Error("Bad sheet visibility setting " + vis);
21267 }
21268 // $FlowIgnore
21269 wb.Workbook.Sheets[idx].Hidden = vis;
21270};
21271add_consts([
21272 ["SHEET_VISIBLE", 0],
21273 ["SHEET_HIDDEN", 1],
21274 ["SHEET_VERY_HIDDEN", 2]
21275]);
21276
21277/* set number format */
21278utils.cell_set_number_format = function(cell, fmt) {
21279 cell.z = fmt;
21280 return cell;
21281};
21282
21283/* set cell hyperlink */
21284utils.cell_set_hyperlink = function(cell, target, tooltip) {
21285 if(!target) {
21286 delete cell.l;
21287 } else {
21288 cell.l = ({ Target: target });
21289 if(tooltip) cell.l.Tooltip = tooltip;
21290 }
21291 return cell;
21292};
21293utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
21294
21295/* add to cell comments */
21296utils.cell_add_comment = function(cell, text, author) {
21297 if(!cell.c) cell.c = [];
21298 cell.c.push({t:text, a:author||"SheetJS"});
21299};
21300
21301/* set array formula and flush related cells */
21302utils.sheet_set_array_formula = function(ws, range, formula) {
21303 var rng = typeof range != "string" ? range : safe_decode_range(range);
21304 var rngstr = typeof range == "string" ? range : encode_range(range);
21305 for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
21306 var cell = ws_get_cell_stub(ws, R, C);
21307 cell.t = 'n';
21308 cell.F = rngstr;
21309 delete cell.v;
21310 if(R == rng.s.r && C == rng.s.c) cell.f = formula;
21311 }
21312 return ws;
21313};
21314
21315return utils;
21316})(utils);
21317
21318if(has_buf && typeof require != 'undefined') (function() {
21319 var Readable = require('stream').Readable;
21320
21321 var write_csv_stream = function(sheet, opts) {
21322 var stream = Readable();
21323 var o = opts == null ? {} : opts;
21324 if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
21325 var r = safe_decode_range(sheet["!ref"]);
21326 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
21327 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
21328 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
21329 var row = "", cols = [];
21330 o.dense = Array.isArray(sheet);
21331 var colinfo = o.skipHidden && sheet["!cols"] || [];
21332 var rowinfo = o.skipHidden && sheet["!rows"] || [];
21333 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
21334 var R = r.s.r;
21335 var BOM = false;
21336 stream._read = function() {
21337 if(!BOM) { BOM = true; return stream.push("\uFEFF"); }
21338 while(R <= r.e.r) {
21339 ++R;
21340 if ((rowinfo[R-1]||{}).hidden) continue;
21341 row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o);
21342 if(row != null) {
21343 if(o.strip) row = row.replace(endregex,"");
21344 stream.push(row + RS);
21345 break;
21346 }
21347 }
21348 if(R > r.e.r) return stream.push(null);
21349 };
21350 return stream;
21351 };
21352
21353 var write_html_stream = function(ws, opts) {
21354 var stream = Readable();
21355
21356 var o = opts || {};
21357 var header = o.header != null ? o.header : HTML_.BEGIN;
21358 var footer = o.footer != null ? o.footer : HTML_.END;
21359 stream.push(header);
21360 var r = decode_range(ws['!ref']);
21361 o.dense = Array.isArray(ws);
21362 stream.push(HTML_._preamble(ws, r, o));
21363 var R = r.s.r;
21364 var end = false;
21365 stream._read = function() {
21366 if(R > r.e.r) {
21367 if(!end) { end = true; stream.push("</table>" + footer); }
21368 return stream.push(null);
21369 }
21370 while(R <= r.e.r) {
21371 stream.push(HTML_._row(ws, r, R, o));
21372 ++R;
21373 break;
21374 }
21375 };
21376 return stream;
21377 };
21378
21379 var write_json_stream = function(sheet, opts) {
21380 var stream = Readable({objectMode:true});
21381
21382 if(sheet == null || sheet["!ref"] == null) { stream.push(null); return stream; }
21383 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
21384 var r = {s:{r:0,c:0},e:{r:0,c:0}};
21385 var o = opts || {};
21386 var range = o.range != null ? o.range : sheet["!ref"];
21387 if(o.header === 1) header = 1;
21388 else if(o.header === "A") header = 2;
21389 else if(Array.isArray(o.header)) header = 3;
21390 switch(typeof range) {
21391 case 'string': r = safe_decode_range(range); break;
21392 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
21393 default: r = range;
21394 }
21395 if(header > 0) offset = 0;
21396 var rr = encode_row(r.s.r);
21397 var cols = [];
21398 var counter = 0;
21399 var dense = Array.isArray(sheet);
21400 var R = r.s.r, C = 0, CC = 0;
21401 if(dense && !sheet[R]) sheet[R] = [];
21402 for(C = r.s.c; C <= r.e.c; ++C) {
21403 cols[C] = encode_col(C);
21404 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
21405 switch(header) {
21406 case 1: hdr[C] = C - r.s.c; break;
21407 case 2: hdr[C] = cols[C]; break;
21408 case 3: hdr[C] = o.header[C - r.s.c]; break;
21409 default:
21410 if(val == null) val = {w: "__EMPTY", t: "s"};
21411 vv = v = format_cell(val, null, o);
21412 counter = 0;
21413 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
21414 hdr[C] = vv;
21415 }
21416 }
21417 R = r.s.r + offset;
21418 stream._read = function() {
21419 if(R > r.e.r) return stream.push(null);
21420 while(R <= r.e.r) {
21421 //if ((rowinfo[R-1]||{}).hidden) continue;
21422 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
21423 ++R;
21424 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
21425 stream.push(row.row);
21426 break;
21427 }
21428 }
21429 };
21430 return stream;
21431 };
21432
21433 XLSX.stream = {
21434 to_json: write_json_stream,
21435 to_html: write_html_stream,
21436 to_csv: write_csv_stream
21437 };
21438})();
21439
21440if(typeof parse_xlscfb !== "undefined") XLSX.parse_xlscfb = parse_xlscfb;
21441XLSX.parse_zip = parse_zip;
21442XLSX.read = readSync; //xlsread
21443XLSX.readFile = readFileSync; //readFile
21444XLSX.readFileSync = readFileSync;
21445XLSX.write = writeSync;
21446XLSX.writeFile = writeFileSync;
21447XLSX.writeFileSync = writeFileSync;
21448XLSX.writeFileAsync = writeFileAsync;
21449XLSX.utils = utils;
21450XLSX.SSF = SSF;
21451if(typeof CFB !== "undefined") XLSX.CFB = CFB;
21452}
21453/*global define */
21454if(typeof exports !== 'undefined') make_xlsx_lib(exports);
21455else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
21456else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
21457else make_xlsx_lib(XLSX);
21458/*exported XLS, ODS */
21459var XLS = XLSX, ODS = XLSX;