UNPKG

301 kBJavaScriptView Raw
1/*! xlsx.js (C) 2013-present SheetJS -- http://sheetjs.com */
2/* vim: set ts=2: */
3/*exported XLSX */
4/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
5var XLSX = {};
6function make_xlsx_lib(XLSX){
7XLSX.version = '0.15.2';
8var current_codepage = 1200, current_ansi = 1252;
9
10var VALID_ANSI = [ 874, 932, 936, 949, 950 ];
11for(var i = 0; i <= 8; ++i) VALID_ANSI.push(1250 + i);
12/* ECMA-376 Part I 18.4.1 charset to codepage mapping */
13var CS2CP = ({
140: 1252, /* ANSI */
151: 65001, /* DEFAULT */
162: 65001, /* SYMBOL */
1777: 10000, /* MAC */
18128: 932, /* SHIFTJIS */
19129: 949, /* HANGUL */
20130: 1361, /* JOHAB */
21134: 936, /* GB2312 */
22136: 950, /* CHINESEBIG5 */
23161: 1253, /* GREEK */
24162: 1254, /* TURKISH */
25163: 1258, /* VIETNAMESE */
26177: 1255, /* HEBREW */
27178: 1256, /* ARABIC */
28186: 1257, /* BALTIC */
29204: 1251, /* RUSSIAN */
30222: 874, /* THAI */
31238: 1250, /* EASTEUROPE */
32255: 1252, /* OEM */
3369: 6969 /* MISC */
34});
35
36var set_ansi = function(cp) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; };
37function reset_ansi() { set_ansi(1252); }
38
39var set_cp = function(cp) { current_codepage = cp; set_ansi(cp); };
40function reset_cp() { set_cp(1200); reset_ansi(); }
41
42function char_codes(data) { var o = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; }
43
44function utf16leread(data) {
45 var o = [];
46 for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8));
47 return o.join("");
48}
49function utf16beread(data) {
50 var o = [];
51 for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8));
52 return o.join("");
53}
54
55var debom = function(data) {
56 var c1 = data.charCodeAt(0), c2 = data.charCodeAt(1);
57 if(c1 == 0xFF && c2 == 0xFE) return utf16leread(data.slice(2));
58 if(c1 == 0xFE && c2 == 0xFF) return utf16beread(data.slice(2));
59 if(c1 == 0xFEFF) return data.slice(1);
60 return data;
61};
62
63var _getchar = function _gc1(x) { return String.fromCharCode(x); };
64var _getansi = function _ga1(x) { return String.fromCharCode(x); };
65var DENSE = null;
66var DIF_XL = true;
67var Base64 = (function make_b64(){
68 var map = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
69 return {
70 encode: function(input) {
71 var o = "";
72 var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
73 for(var i = 0; i < input.length; ) {
74 c1 = input.charCodeAt(i++);
75 e1 = (c1 >> 2);
76
77 c2 = input.charCodeAt(i++);
78 e2 = ((c1 & 3) << 4) | (c2 >> 4);
79
80 c3 = input.charCodeAt(i++);
81 e3 = ((c2 & 15) << 2) | (c3 >> 6);
82 e4 = (c3 & 63);
83 if (isNaN(c2)) { e3 = e4 = 64; }
84 else if (isNaN(c3)) { e4 = 64; }
85 o += map.charAt(e1) + map.charAt(e2) + map.charAt(e3) + map.charAt(e4);
86 }
87 return o;
88 },
89 decode: function b64_decode(input) {
90 var o = "";
91 var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0;
92 input = input.replace(/[^\w\+\/\=]/g, "");
93 for(var i = 0; i < input.length;) {
94 e1 = map.indexOf(input.charAt(i++));
95 e2 = map.indexOf(input.charAt(i++));
96 c1 = (e1 << 2) | (e2 >> 4);
97 o += String.fromCharCode(c1);
98
99 e3 = map.indexOf(input.charAt(i++));
100 c2 = ((e2 & 15) << 4) | (e3 >> 2);
101 if (e3 !== 64) { o += String.fromCharCode(c2); }
102
103 e4 = map.indexOf(input.charAt(i++));
104 c3 = ((e3 & 3) << 6) | e4;
105 if (e4 !== 64) { o += String.fromCharCode(c3); }
106 }
107 return o;
108 }
109 };
110})();
111var has_buf = (typeof Buffer !== 'undefined' && typeof process !== 'undefined' && typeof process.versions !== 'undefined' && !!process.versions.node);
112
113var Buffer_from = function(){};
114
115if(typeof Buffer !== 'undefined') {
116 var nbfs = !Buffer.from;
117 if(!nbfs) try { Buffer.from("foo", "utf8"); } catch(e) { nbfs = true; }
118 Buffer_from = nbfs ? function(buf, enc) { return (enc) ? new Buffer(buf, enc) : new Buffer(buf); } : Buffer.from.bind(Buffer);
119 // $FlowIgnore
120 if(!Buffer.alloc) Buffer.alloc = function(n) { return new Buffer(n); };
121 // $FlowIgnore
122 if(!Buffer.allocUnsafe) Buffer.allocUnsafe = function(n) { return new Buffer(n); };
123}
124
125function new_raw_buf(len) {
126 /* jshint -W056 */
127 return has_buf ? Buffer.alloc(len) : new Array(len);
128 /* jshint +W056 */
129}
130
131function new_unsafe_buf(len) {
132 /* jshint -W056 */
133 return has_buf ? Buffer.allocUnsafe(len) : new Array(len);
134 /* jshint +W056 */
135}
136
137var s2a = function s2a(s) {
138 if(has_buf) return Buffer_from(s, "binary");
139 return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
140};
141
142function s2ab(s) {
143 if(typeof ArrayBuffer === 'undefined') return s2a(s);
144 var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf);
145 for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF;
146 return buf;
147}
148
149function a2s(data) {
150 if(Array.isArray(data)) return data.map(function(c) { return String.fromCharCode(c); }).join("");
151 var o = []; for(var i = 0; i < data.length; ++i) o[i] = String.fromCharCode(data[i]); return o.join("");
152}
153
154function a2u(data) {
155 if(typeof Uint8Array === 'undefined') throw new Error("Unsupported");
156 return new Uint8Array(data);
157}
158
159function ab2a(data) {
160 if(typeof ArrayBuffer == 'undefined') throw new Error("Unsupported");
161 if(data instanceof ArrayBuffer) return ab2a(new Uint8Array(data));
162var o = new Array(data.length);
163 for(var i = 0; i < data.length; ++i) o[i] = data[i];
164 return o;
165}
166
167var bconcat = function(bufs) { return [].concat.apply([], bufs); };
168
169var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g;
170/* ssf.js (C) 2013-present SheetJS -- http://sheetjs.com */
171/*jshint -W041 */
172var SSF = ({});
173var make_ssf = function make_ssf(SSF){
174SSF.version = '0.10.2';
175function _strrev(x) { var o = "", i = x.length-1; while(i>=0) o += x.charAt(i--); return o; }
176function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
177function pad0(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
178function pad_(v,d){var t=""+v;return t.length>=d?t:fill(' ',d-t.length)+t;}
179function rpad_(v,d){var t=""+v; return t.length>=d?t:t+fill(' ',d-t.length);}
180function pad0r1(v,d){var t=""+Math.round(v); return t.length>=d?t:fill('0',d-t.length)+t;}
181function pad0r2(v,d){var t=""+v; return t.length>=d?t:fill('0',d-t.length)+t;}
182var p2_32 = Math.pow(2,32);
183function pad0r(v,d){if(v>p2_32||v<-p2_32) return pad0r1(v,d); var i = Math.round(v); return pad0r2(i,d); }
184function 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; }
185var days = [
186 ['Sun', 'Sunday'],
187 ['Mon', 'Monday'],
188 ['Tue', 'Tuesday'],
189 ['Wed', 'Wednesday'],
190 ['Thu', 'Thursday'],
191 ['Fri', 'Friday'],
192 ['Sat', 'Saturday']
193];
194var months = [
195 ['J', 'Jan', 'January'],
196 ['F', 'Feb', 'February'],
197 ['M', 'Mar', 'March'],
198 ['A', 'Apr', 'April'],
199 ['M', 'May', 'May'],
200 ['J', 'Jun', 'June'],
201 ['J', 'Jul', 'July'],
202 ['A', 'Aug', 'August'],
203 ['S', 'Sep', 'September'],
204 ['O', 'Oct', 'October'],
205 ['N', 'Nov', 'November'],
206 ['D', 'Dec', 'December']
207];
208function init_table(t) {
209 t[0]= 'General';
210 t[1]= '0';
211 t[2]= '0.00';
212 t[3]= '#,##0';
213 t[4]= '#,##0.00';
214 t[9]= '0%';
215 t[10]= '0.00%';
216 t[11]= '0.00E+00';
217 t[12]= '# ?/?';
218 t[13]= '# ??/??';
219 t[14]= 'm/d/yy';
220 t[15]= 'd-mmm-yy';
221 t[16]= 'd-mmm';
222 t[17]= 'mmm-yy';
223 t[18]= 'h:mm AM/PM';
224 t[19]= 'h:mm:ss AM/PM';
225 t[20]= 'h:mm';
226 t[21]= 'h:mm:ss';
227 t[22]= 'm/d/yy h:mm';
228 t[37]= '#,##0 ;(#,##0)';
229 t[38]= '#,##0 ;[Red](#,##0)';
230 t[39]= '#,##0.00;(#,##0.00)';
231 t[40]= '#,##0.00;[Red](#,##0.00)';
232 t[45]= 'mm:ss';
233 t[46]= '[h]:mm:ss';
234 t[47]= 'mmss.0';
235 t[48]= '##0.0E+0';
236 t[49]= '@';
237 t[56]= '"上午/下午 "hh"時"mm"分"ss"秒 "';
238 t[65535]= 'General';
239}
240
241var table_fmt = {};
242init_table(table_fmt);
243function frac(x, D, mixed) {
244 var sgn = x < 0 ? -1 : 1;
245 var B = x * sgn;
246 var P_2 = 0, P_1 = 1, P = 0;
247 var Q_2 = 1, Q_1 = 0, Q = 0;
248 var A = Math.floor(B);
249 while(Q_1 < D) {
250 A = Math.floor(B);
251 P = A * P_1 + P_2;
252 Q = A * Q_1 + Q_2;
253 if((B - A) < 0.00000005) break;
254 B = 1 / (B - A);
255 P_2 = P_1; P_1 = P;
256 Q_2 = Q_1; Q_1 = Q;
257 }
258 if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
259 if(!mixed) return [0, sgn * P, Q];
260 var q = Math.floor(sgn * P/Q);
261 return [q, sgn*P - q*Q, Q];
262}
263function parse_date_code(v,opts,b2) {
264 if(v > 2958465 || v < 0) return null;
265 var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
266 var dout=[];
267 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};
268 if(Math.abs(out.u) < 1e-6) out.u = 0;
269 if(opts && opts.date1904) date += 1462;
270 if(out.u > 0.9999) {
271 out.u = 0;
272 if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
273 }
274 if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
275 else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
276 else {
277 if(date > 60) --date;
278 /* 1 = Jan 1 1900 in Gregorian */
279 var d = new Date(1900, 0, 1);
280 d.setDate(d.getDate() + date - 1);
281 dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
282 dow = d.getDay();
283 if(date < 60) dow = (dow + 6) % 7;
284 if(b2) dow = fix_hijri(d, dout);
285 }
286 out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
287 out.S = time % 60; time = Math.floor(time / 60);
288 out.M = time % 60; time = Math.floor(time / 60);
289 out.H = time;
290 out.q = dow;
291 return out;
292}
293SSF.parse_date_code = parse_date_code;
294var basedate = new Date(1899, 11, 31, 0, 0, 0);
295var dnthresh = basedate.getTime();
296var base1904 = new Date(1900, 2, 1, 0, 0, 0);
297function datenum_local(v, date1904) {
298 var epoch = v.getTime();
299 if(date1904) epoch -= 1461*24*60*60*1000;
300 else if(v >= base1904) epoch += 24*60*60*1000;
301 return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
302}
303function general_fmt_int(v) { return v.toString(10); }
304SSF._general_int = general_fmt_int;
305var general_fmt_num = (function make_general_fmt_num() {
306var gnr1 = /\.(\d*[1-9])0+$/, gnr2 = /\.0*$/, gnr4 = /\.(\d*[1-9])0+/, gnr5 = /\.0*[Ee]/, gnr6 = /(E[+-])(\d)$/;
307function gfn2(v) {
308 var w = (v<0?12:11);
309 var o = gfn5(v.toFixed(12)); if(o.length <= w) return o;
310 o = v.toPrecision(10); if(o.length <= w) return o;
311 return v.toExponential(5);
312}
313function gfn3(v) {
314 var o = v.toFixed(11).replace(gnr1,".$1");
315 if(o.length > (v<0?12:11)) o = v.toPrecision(6);
316 return o;
317}
318function gfn4(o) {
319 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");
320 return o;
321}
322function gfn5(o) {
323 return o.indexOf(".") > -1 ? o.replace(gnr2,"").replace(gnr1,".$1") : o;
324}
325return function general_fmt_num(v) {
326 var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
327 if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
328 else if(Math.abs(V) <= 9) o = gfn2(v);
329 else if(V === 10) o = v.toFixed(10).substr(0,12);
330 else o = gfn3(v);
331 return gfn5(gfn4(o));
332};})();
333SSF._general_num = general_fmt_num;
334function general_fmt(v, opts) {
335 switch(typeof v) {
336 case 'string': return v;
337 case 'boolean': return v ? "TRUE" : "FALSE";
338 case 'number': return (v|0) === v ? general_fmt_int(v) : general_fmt_num(v);
339 case 'undefined': return "";
340 case 'object':
341 if(v == null) return "";
342 if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
343 }
344 throw new Error("unsupported value in General format: " + v);
345}
346SSF._general = general_fmt;
347function fix_hijri() { return 0; }
348/*jshint -W086 */
349function write_date(type, fmt, val, ss0) {
350 var o="", ss=0, tt=0, y = val.y, out, outl = 0;
351 switch(type) {
352 case 98: /* 'b' buddhist year */
353 y = val.y + 543;
354 /* falls through */
355 case 121: /* 'y' year */
356 switch(fmt.length) {
357 case 1: case 2: out = y % 100; outl = 2; break;
358 default: out = y % 10000; outl = 4; break;
359 } break;
360 case 109: /* 'm' month */
361 switch(fmt.length) {
362 case 1: case 2: out = val.m; outl = fmt.length; break;
363 case 3: return months[val.m-1][1];
364 case 5: return months[val.m-1][0];
365 default: return months[val.m-1][2];
366 } break;
367 case 100: /* 'd' day */
368 switch(fmt.length) {
369 case 1: case 2: out = val.d; outl = fmt.length; break;
370 case 3: return days[val.q][0];
371 default: return days[val.q][1];
372 } break;
373 case 104: /* 'h' 12-hour */
374 switch(fmt.length) {
375 case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
376 default: throw 'bad hour format: ' + fmt;
377 } break;
378 case 72: /* 'H' 24-hour */
379 switch(fmt.length) {
380 case 1: case 2: out = val.H; outl = fmt.length; break;
381 default: throw 'bad hour format: ' + fmt;
382 } break;
383 case 77: /* 'M' minutes */
384 switch(fmt.length) {
385 case 1: case 2: out = val.M; outl = fmt.length; break;
386 default: throw 'bad minute format: ' + fmt;
387 } break;
388 case 115: /* 's' seconds */
389 if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
390 if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
391if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
392 else tt = ss0 === 1 ? 10 : 1;
393 ss = Math.round((tt)*(val.S + val.u));
394 if(ss >= 60*tt) ss = 0;
395 if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
396 o = pad0(ss,2 + ss0);
397 if(fmt === 'ss') return o.substr(0,2);
398 return "." + o.substr(2,fmt.length-1);
399 case 90: /* 'Z' absolute time */
400 switch(fmt) {
401 case '[h]': case '[hh]': out = val.D*24+val.H; break;
402 case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
403 case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
404 default: throw 'bad abstime format: ' + fmt;
405 } outl = fmt.length === 3 ? 1 : 2; break;
406 case 101: /* 'e' era */
407 out = y; outl = 1;
408 }
409 if(outl > 0) return pad0(out, outl); else return "";
410}
411/*jshint +W086 */
412function commaify(s) {
413 var w = 3;
414 if(s.length <= w) return s;
415 var j = (s.length % w), o = s.substr(0,j);
416 for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
417 return o;
418}
419var write_num = (function make_write_num(){
420var pct1 = /%/g;
421function write_num_pct(type, fmt, val){
422 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
423 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
424}
425function write_num_cm(type, fmt, val){
426 var idx = fmt.length - 1;
427 while(fmt.charCodeAt(idx-1) === 44) --idx;
428 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
429}
430function write_num_exp(fmt, val){
431 var o;
432 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
433 if(fmt.match(/^#+0.0E\+0$/)) {
434 if(val == 0) return "0.0E+0";
435 else if(val < 0) return "-" + write_num_exp(fmt, -val);
436 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
437 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
438 if(ee < 0) ee += period;
439 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
440 if(o.indexOf("e") === -1) {
441 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
442 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
443 else o += "E+" + (fakee - ee);
444 while(o.substr(0,2) === "0.") {
445 o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
446 o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
447 }
448 o = o.replace(/\+-/,"-");
449 }
450 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
451 } else o = val.toExponential(idx);
452 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
453 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
454 return o.replace("e","E");
455}
456var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
457function write_num_f1(r, aval, sign) {
458 var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
459 var myn = (rr - base*den), myd = den;
460 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));
461}
462function write_num_f2(r, aval, sign) {
463 return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
464}
465var dec1 = /^#*0*\.([0#]+)/;
466var closeparen = /\).*[0#]/;
467var phone = /\(###\) ###\\?-####/;
468function hashq(str) {
469 var o = "", cc;
470 for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
471 case 35: break;
472 case 63: o+= " "; break;
473 case 48: o+= "0"; break;
474 default: o+= String.fromCharCode(cc);
475 }
476 return o;
477}
478function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
479function dec(val, d) {
480 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
481 return 0;
482 }
483 return Math.round((val-Math.floor(val))*Math.pow(10,d));
484}
485function carry(val, d) {
486 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
487 return 1;
488 }
489 return 0;
490}
491function flr(val) { if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0)); return ""+Math.floor(val); }
492function write_num_flt(type, fmt, val) {
493 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
494 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
495 if(val >= 0) return write_num_flt('n', ffmt, val);
496 return '(' + write_num_flt('n', ffmt, -val) + ')';
497 }
498 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
499 if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
500 if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
501 if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
502 var o;
503 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
504 if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
505 if(fmt.match(/^[#?]+$/)) {
506 o = pad0r(val,0); if(o === "0") o = "";
507 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
508 }
509 if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
510 if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
511 if((r = fmt.match(dec1))) {
512 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); });
513 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
514 }
515 fmt = fmt.replace(/^#+([0.])/, "$1");
516 if((r = fmt.match(/^(0*)\.(#*)$/))) {
517 return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
518 }
519 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
520 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
521 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);
522 }
523 if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
524 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
525 o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
526 ri = 0;
527 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
528 }
529 if(fmt.match(phone)) {
530 o = write_num_flt(type, "##########", val);
531 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
532 }
533 var oa = "";
534 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
535 ri = Math.min(r[4].length,7);
536 ff = frac(aval, Math.pow(10,ri)-1, false);
537 o = "" + sign;
538 oa = write_num("n", r[1], ff[1]);
539 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
540 o += oa + r[2] + "/" + r[3];
541 oa = rpad_(ff[2],ri);
542 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
543 o += oa;
544 return o;
545 }
546 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
547 ri = Math.min(Math.max(r[1].length, r[4].length),7);
548 ff = frac(aval, Math.pow(10,ri)-1, true);
549 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));
550 }
551 if((r = fmt.match(/^[#0?]+$/))) {
552 o = pad0r(val, 0);
553 if(fmt.length <= o.length) return o;
554 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
555 }
556 if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
557 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
558 ri = o.indexOf(".");
559 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
560 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
561 }
562 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
563 ri = dec(val, r[1].length);
564 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);
565 }
566 switch(fmt) {
567 case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
568 case "###,###":
569 case "##,###":
570 case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
571 case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
572 case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
573 default:
574 }
575 throw new Error("unsupported format |" + fmt + "|");
576}
577function write_num_cm2(type, fmt, val){
578 var idx = fmt.length - 1;
579 while(fmt.charCodeAt(idx-1) === 44) --idx;
580 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
581}
582function write_num_pct2(type, fmt, val){
583 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
584 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
585}
586function write_num_exp2(fmt, val){
587 var o;
588 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
589 if(fmt.match(/^#+0.0E\+0$/)) {
590 if(val == 0) return "0.0E+0";
591 else if(val < 0) return "-" + write_num_exp2(fmt, -val);
592 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
593 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
594 if(ee < 0) ee += period;
595 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
596 if(!o.match(/[Ee]/)) {
597 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
598 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
599 else o += "E+" + (fakee - ee);
600 o = o.replace(/\+-/,"-");
601 }
602 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
603 } else o = val.toExponential(idx);
604 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
605 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
606 return o.replace("e","E");
607}
608function write_num_int(type, fmt, val) {
609 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
610 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
611 if(val >= 0) return write_num_int('n', ffmt, val);
612 return '(' + write_num_int('n', ffmt, -val) + ')';
613 }
614 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
615 if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
616 if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
617 if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
618 var o;
619 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
620 if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
621 if(fmt.match(/^[#?]+$/)) {
622 o = (""+val); if(val === 0) o = "";
623 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
624 }
625 if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
626 if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
627 if((r = fmt.match(dec1))) {
628o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
629 o = o.replace(/\.(\d*)$/,function($$, $1) {
630return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
631 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
632 }
633 fmt = fmt.replace(/^#+([0.])/, "$1");
634 if((r = fmt.match(/^(0*)\.(#*)$/))) {
635 return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
636 }
637 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
638 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
639 return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
640 }
641 if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
642 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
643 o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
644 ri = 0;
645 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
646 }
647 if(fmt.match(phone)) {
648 o = write_num_int(type, "##########", val);
649 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
650 }
651 var oa = "";
652 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
653 ri = Math.min(r[4].length,7);
654 ff = frac(aval, Math.pow(10,ri)-1, false);
655 o = "" + sign;
656 oa = write_num("n", r[1], ff[1]);
657 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
658 o += oa + r[2] + "/" + r[3];
659 oa = rpad_(ff[2],ri);
660 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
661 o += oa;
662 return o;
663 }
664 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
665 ri = Math.min(Math.max(r[1].length, r[4].length),7);
666 ff = frac(aval, Math.pow(10,ri)-1, true);
667 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));
668 }
669 if((r = fmt.match(/^[#0?]+$/))) {
670 o = "" + val;
671 if(fmt.length <= o.length) return o;
672 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
673 }
674 if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
675 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
676 ri = o.indexOf(".");
677 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
678 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
679 }
680 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
681 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);
682 }
683 switch(fmt) {
684 case "###,###":
685 case "##,###":
686 case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
687 default:
688 if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
689 }
690 throw new Error("unsupported format |" + fmt + "|");
691}
692return function write_num(type, fmt, val) {
693 return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
694};})();
695function split_fmt(fmt) {
696 var out = [];
697 var in_str = false/*, cc*/;
698 for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
699 case 34: /* '"' */
700 in_str = !in_str; break;
701 case 95: case 42: case 92: /* '_' '*' '\\' */
702 ++i; break;
703 case 59: /* ';' */
704 out[out.length] = fmt.substr(j,i-j);
705 j = i+1;
706 }
707 out[out.length] = fmt.substr(j);
708 if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
709 return out;
710}
711SSF._split = split_fmt;
712var abstime = /\[[HhMmSs]*\]/;
713function fmt_is_date(fmt) {
714 var i = 0, /*cc = 0,*/ c = "", o = "";
715 while(i < fmt.length) {
716 switch((c = fmt.charAt(i))) {
717 case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
718 case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) ++i; ++i; break;
719 case '\\': i+=2; break;
720 case '_': i+=2; break;
721 case '@': ++i; break;
722 case 'B': case 'b':
723 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
724 /* falls through */
725 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
726 /* falls through */
727 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
728 case 'A': case 'a':
729 if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
730 if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
731 ++i; break;
732 case '[':
733 o = c;
734 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
735 if(o.match(abstime)) return true;
736 break;
737 case '.':
738 /* falls through */
739 case '0': case '#':
740 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 */}
741 break;
742 case '?': while(fmt.charAt(++i) === c){/* empty */} break;
743 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
744 case '(': case ')': ++i; break;
745 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
746 while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
747 case ' ': ++i; break;
748 default: ++i; break;
749 }
750 }
751 return false;
752}
753SSF.is_date = fmt_is_date;
754function eval_fmt(fmt, v, opts, flen) {
755 var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
756 var hr='H';
757 /* Tokenize */
758 while(i < fmt.length) {
759 switch((c = fmt.charAt(i))) {
760 case 'G': /* General */
761 if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
762 out[out.length] = {t:'G', v:'General'}; i+=7; break;
763 case '"': /* Literal text */
764 for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
765 out[out.length] = {t:'t', v:o}; ++i; break;
766 case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
767 out[out.length] = {t:t, v:w}; ++i; break;
768 case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
769 case '@': /* Text Placeholder */
770 out[out.length] = {t:'T', v:v}; ++i; break;
771 case 'B': case 'b':
772 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
773 if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
774 out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
775 }
776 /* falls through */
777 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
778 c = c.toLowerCase();
779 /* falls through */
780 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
781 if(v < 0) return "";
782 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
783 o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
784 if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
785 if(c === 'h') c = hr;
786 out[out.length] = {t:c, v:o}; lst = c; break;
787 case 'A': case 'a':
788 var q={t:c, v:c};
789 if(dt==null) dt=parse_date_code(v, opts);
790 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;}
791 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'; }
792 else { q.t = "t"; ++i; }
793 if(dt==null && q.t === 'T') return "";
794 out[out.length] = q; lst = c; break;
795 case '[':
796 o = c;
797 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
798 if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
799 if(o.match(abstime)) {
800 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
801 out[out.length] = {t:'Z', v:o.toLowerCase()};
802 lst = o.charAt(1);
803 } else if(o.indexOf("$") > -1) {
804 o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
805 if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
806 }
807 break;
808 /* Numbers */
809 case '.':
810 if(dt != null) {
811 o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
812 out[out.length] = {t:'s', v:o}; break;
813 }
814 /* falls through */
815 case '0': case '#':
816 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;
817 out[out.length] = {t:'n', v:o}; break;
818 case '?':
819 o = c; while(fmt.charAt(++i) === c) o+=c;
820 out[out.length] = {t:c, v:o}; lst = c; break;
821 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
822 case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
823 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
824 o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
825 out[out.length] = {t:'D', v:o}; break;
826 case ' ': out[out.length] = {t:c, v:c}; ++i; break;
827 default:
828 if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
829 out[out.length] = {t:'t', v:c}; ++i; break;
830 }
831 }
832 var bt = 0, ss0 = 0, ssm;
833 for(i=out.length-1, lst='t'; i >= 0; --i) {
834 switch(out[i].t) {
835 case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
836 case 's':
837 if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
838 if(bt < 3) bt = 3;
839 /* falls through */
840 case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
841 case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
842 case 'X': /*if(out[i].v === "B2");*/
843 break;
844 case 'Z':
845 if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
846 if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
847 if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
848 }
849 }
850 switch(bt) {
851 case 0: break;
852 case 1:
853if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
854 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
855 if(dt.M >= 60) { dt.M = 0; ++dt.H; }
856 break;
857 case 2:
858if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
859 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
860 break;
861 }
862 /* replace fields */
863 var nstr = "", jj;
864 for(i=0; i < out.length; ++i) {
865 switch(out[i].t) {
866 case 't': case 'T': case ' ': case 'D': break;
867 case 'X': out[i].v = ""; out[i].t = ";"; break;
868 case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
869out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
870 out[i].t = 't'; break;
871 case 'n': case '(': case '?':
872 jj = i+1;
873 while(out[jj] != null && (
874 (c=out[jj].t) === "?" || c === "D" ||
875 ((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
876 (out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
877 (c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
878 )) {
879 out[i].v += out[jj].v;
880 out[jj] = {v:"", t:";"}; ++jj;
881 }
882 nstr += out[i].v;
883 i = jj-1; break;
884 case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
885 }
886 }
887 var vv = "", myv, ostr;
888 if(nstr.length > 0) {
889 if(nstr.charCodeAt(0) == 40) /* '(' */ {
890 myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
891 ostr = write_num('(', nstr, myv);
892 } else {
893 myv = (v<0 && flen > 1 ? -v : v);
894 ostr = write_num('n', nstr, myv);
895 if(myv < 0 && out[0] && out[0].t == 't') {
896 ostr = ostr.substr(1);
897 out[0].v = "-" + out[0].v;
898 }
899 }
900 jj=ostr.length-1;
901 var decpt = out.length;
902 for(i=0; i < out.length; ++i) if(out[i] != null && out[i].t != 't' && out[i].v.indexOf(".") > -1) { decpt = i; break; }
903 var lasti=out.length;
904 if(decpt === out.length && ostr.indexOf("E") === -1) {
905 for(i=out.length-1; i>= 0;--i) {
906 if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
907 if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
908 else if(jj < 0) out[i].v = "";
909 else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
910 out[i].t = 't';
911 lasti = i;
912 }
913 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
914 }
915 else if(decpt !== out.length && ostr.indexOf("E") === -1) {
916 jj = ostr.indexOf(".")-1;
917 for(i=decpt; i>= 0; --i) {
918 if(out[i] == null || 'n?('.indexOf(out[i].t) === -1) continue;
919 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
920 vv = out[i].v.substr(j+1);
921 for(; j>=0; --j) {
922 if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
923 }
924 out[i].v = vv;
925 out[i].t = 't';
926 lasti = i;
927 }
928 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
929 jj = ostr.indexOf(".")+1;
930 for(i=decpt; i<out.length; ++i) {
931 if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
932 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
933 vv = out[i].v.substr(0,j);
934 for(; j<out[i].v.length; ++j) {
935 if(jj<ostr.length) vv += ostr.charAt(jj++);
936 }
937 out[i].v = vv;
938 out[i].t = 't';
939 lasti = i;
940 }
941 }
942 }
943 for(i=0; i<out.length; ++i) if(out[i] != null && 'n(?'.indexOf(out[i].t)>-1) {
944 myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
945 out[i].v = write_num(out[i].t, out[i].v, myv);
946 out[i].t = 't';
947 }
948 var retval = "";
949 for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
950 return retval;
951}
952SSF._eval = eval_fmt;
953var cfregex = /\[[=<>]/;
954var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
955function chkcond(v, rr) {
956 if(rr == null) return false;
957 var thresh = parseFloat(rr[2]);
958 switch(rr[1]) {
959 case "=": if(v == thresh) return true; break;
960 case ">": if(v > thresh) return true; break;
961 case "<": if(v < thresh) return true; break;
962 case "<>": if(v != thresh) return true; break;
963 case ">=": if(v >= thresh) return true; break;
964 case "<=": if(v <= thresh) return true; break;
965 }
966 return false;
967}
968function choose_fmt(f, v) {
969 var fmt = split_fmt(f);
970 var l = fmt.length, lat = fmt[l-1].indexOf("@");
971 if(l<4 && lat>-1) --l;
972 if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
973 if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
974 switch(fmt.length) {
975 case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
976 case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
977 case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
978 case 4: break;
979 }
980 var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
981 if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
982 if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
983 var m1 = fmt[0].match(cfregex2);
984 var m2 = fmt[1].match(cfregex2);
985 return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
986 }
987 return [l, ff];
988}
989function format(fmt,v,o) {
990 if(o == null) o = {};
991 var sfmt = "";
992 switch(typeof fmt) {
993 case "string":
994 if(fmt == "m/d/yy" && o.dateNF) sfmt = o.dateNF;
995 else sfmt = fmt;
996 break;
997 case "number":
998 if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
999 else sfmt = (o.table != null ? (o.table) : table_fmt)[fmt];
1000 break;
1001 }
1002 if(isgeneral(sfmt,0)) return general_fmt(v, o);
1003 if(v instanceof Date) v = datenum_local(v, o.date1904);
1004 var f = choose_fmt(sfmt, v);
1005 if(isgeneral(f[1])) return general_fmt(v, o);
1006 if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
1007 else if(v === "" || v == null) return "";
1008 return eval_fmt(f[1], v, o, f[0]);
1009}
1010function load_entry(fmt, idx) {
1011 if(typeof idx != 'number') {
1012 idx = +idx || -1;
1013for(var i = 0; i < 0x0188; ++i) {
1014if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
1015 if(table_fmt[i] == fmt) { idx = i; break; }
1016 }
1017if(idx < 0) idx = 0x187;
1018 }
1019table_fmt[idx] = fmt;
1020 return idx;
1021}
1022SSF.load = load_entry;
1023SSF._table = table_fmt;
1024SSF.get_table = function get_table() { return table_fmt; };
1025SSF.load_table = function load_table(tbl) {
1026 for(var i=0; i!=0x0188; ++i)
1027 if(tbl[i] !== undefined) load_entry(tbl[i], i);
1028};
1029SSF.init_table = init_table;
1030SSF.format = format;
1031};
1032make_ssf(SSF);
1033/* map from xlml named formats to SSF TODO: localize */
1034var XLMLFormatMap/*{[string]:string}*/ = ({
1035 "General Number": "General",
1036 "General Date": SSF._table[22],
1037 "Long Date": "dddd, mmmm dd, yyyy",
1038 "Medium Date": SSF._table[15],
1039 "Short Date": SSF._table[14],
1040 "Long Time": SSF._table[19],
1041 "Medium Time": SSF._table[18],
1042 "Short Time": SSF._table[20],
1043 "Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1044 "Fixed": SSF._table[2],
1045 "Standard": SSF._table[4],
1046 "Percent": SSF._table[10],
1047 "Scientific": SSF._table[11],
1048 "Yes/No": '"Yes";"Yes";"No";@',
1049 "True/False": '"True";"True";"False";@',
1050 "On/Off": '"Yes";"Yes";"No";@'
1051});
1052
1053var SSFImplicit/*{[number]:string}*/ = ({
1054 "5": '"$"#,##0_);\\("$"#,##0\\)',
1055 "6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1056 "7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1057 "8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1058 "23": 'General', "24": 'General', "25": 'General', "26": 'General',
1059 "27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
1060 "32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
1061 "36": 'm/d/yy',
1062 "41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
1063 "42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
1064 "43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
1065 "44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
1066 "50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
1067 "55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
1068 "59": '0',
1069 "60": '0.00',
1070 "61": '#,##0',
1071 "62": '#,##0.00',
1072 "63": '"$"#,##0_);\\("$"#,##0\\)',
1073 "64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1074 "65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1075 "66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1076 "67": '0%',
1077 "68": '0.00%',
1078 "69": '# ?/?',
1079 "70": '# ??/??',
1080 "71": 'm/d/yy',
1081 "72": 'm/d/yy',
1082 "73": 'd-mmm-yy',
1083 "74": 'd-mmm',
1084 "75": 'mmm-yy',
1085 "76": 'h:mm',
1086 "77": 'h:mm:ss',
1087 "78": 'm/d/yy h:mm',
1088 "79": 'mm:ss',
1089 "80": '[h]:mm:ss',
1090 "81": 'mmss.0'
1091});
1092
1093/* dateNF parse TODO: move to SSF */
1094var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
1095function dateNF_regex(dateNF) {
1096 var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF;
1097 fmt = fmt.replace(dateNFregex, "(\\d+)");
1098 return new RegExp("^" + fmt + "$");
1099}
1100function dateNF_fix(str, dateNF, match) {
1101 var Y = -1, m = -1, d = -1, H = -1, M = -1, S = -1;
1102 (dateNF.match(dateNFregex)||[]).forEach(function(n, i) {
1103 var v = parseInt(match[i+1], 10);
1104 switch(n.toLowerCase().charAt(0)) {
1105 case 'y': Y = v; break; case 'd': d = v; break;
1106 case 'h': H = v; break; case 's': S = v; break;
1107 case 'm': if(H >= 0) M = v; else m = v; break;
1108 }
1109 });
1110 if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
1111 var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
1112 if(datestr.length == 7) datestr = "0" + datestr;
1113 if(datestr.length == 8) datestr = "20" + datestr;
1114 var timestr = (("00" + (H>=0?H:0)).slice(-2) + ":" + ("00" + (M>=0?M:0)).slice(-2) + ":" + ("00" + (S>=0?S:0)).slice(-2));
1115 if(H == -1 && M == -1 && S == -1) return datestr;
1116 if(Y == -1 && m == -1 && d == -1) return timestr;
1117 return datestr + "T" + timestr;
1118}
1119
1120var DO_NOT_EXPORT_CFB = true;
1121/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
1122/* vim: set ts=2: */
1123/*jshint eqnull:true */
1124/*exported CFB */
1125/*global module, require:false, process:false, Buffer:false, Uint8Array:false, Uint16Array:false */
1126
1127/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
1128/* vim: set ts=2: */
1129/*exported CRC32 */
1130var CRC32;
1131(function (factory) {
1132 /*jshint ignore:start */
1133 /*eslint-disable */
1134 factory(CRC32 = {});
1135 /*eslint-enable */
1136 /*jshint ignore:end */
1137}(function(CRC32) {
1138CRC32.version = '1.2.0';
1139/* see perf/crc32table.js */
1140/*global Int32Array */
1141function signed_crc_table() {
1142 var c = 0, table = new Array(256);
1143
1144 for(var n =0; n != 256; ++n){
1145 c = n;
1146 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1147 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1148 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1149 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1150 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1151 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1152 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1153 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1154 table[n] = c;
1155 }
1156
1157 return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
1158}
1159
1160var T = signed_crc_table();
1161function crc32_bstr(bstr, seed) {
1162 var C = seed ^ -1, L = bstr.length - 1;
1163 for(var i = 0; i < L;) {
1164 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1165 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1166 }
1167 if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
1168 return C ^ -1;
1169}
1170
1171function crc32_buf(buf, seed) {
1172 if(buf.length > 10000) return crc32_buf_8(buf, seed);
1173 var C = seed ^ -1, L = buf.length - 3;
1174 for(var i = 0; i < L;) {
1175 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1176 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1177 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1178 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1179 }
1180 while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1181 return C ^ -1;
1182}
1183
1184function crc32_buf_8(buf, seed) {
1185 var C = seed ^ -1, L = buf.length - 7;
1186 for(var i = 0; i < L;) {
1187 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1188 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1189 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1190 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1191 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1192 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1193 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1194 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1195 }
1196 while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1197 return C ^ -1;
1198}
1199
1200function crc32_str(str, seed) {
1201 var C = seed ^ -1;
1202 for(var i = 0, L=str.length, c, d; i < L;) {
1203 c = str.charCodeAt(i++);
1204 if(c < 0x80) {
1205 C = (C>>>8) ^ T[(C ^ c)&0xFF];
1206 } else if(c < 0x800) {
1207 C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
1208 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1209 } else if(c >= 0xD800 && c < 0xE000) {
1210 c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
1211 C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
1212 C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
1213 C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
1214 C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
1215 } else {
1216 C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
1217 C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
1218 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1219 }
1220 }
1221 return C ^ -1;
1222}
1223CRC32.table = T;
1224CRC32.bstr = crc32_bstr;
1225CRC32.buf = crc32_buf;
1226CRC32.str = crc32_str;
1227}));
1228/* [MS-CFB] v20171201 */
1229var CFB = (function _CFB(){
1230var exports = {};
1231exports.version = '1.1.3';
1232/* [MS-CFB] 2.6.4 */
1233function namecmp(l, r) {
1234 var L = l.split("/"), R = r.split("/");
1235 for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
1236 if((c = L[i].length - R[i].length)) return c;
1237 if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
1238 }
1239 return L.length - R.length;
1240}
1241function dirname(p) {
1242 if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
1243 var c = p.lastIndexOf("/");
1244 return (c === -1) ? p : p.slice(0, c+1);
1245}
1246
1247function filename(p) {
1248 if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
1249 var c = p.lastIndexOf("/");
1250 return (c === -1) ? p : p.slice(c+1);
1251}
1252/* -------------------------------------------------------------------------- */
1253/* DOS Date format:
1254 high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
1255 add 1980 to stored year
1256 stored second should be doubled
1257*/
1258
1259/* write JS date to buf as a DOS date */
1260function write_dos_date(buf, date) {
1261 if(typeof date === "string") date = new Date(date);
1262 var hms = date.getHours();
1263 hms = hms << 6 | date.getMinutes();
1264 hms = hms << 5 | (date.getSeconds()>>>1);
1265 buf.write_shift(2, hms);
1266 var ymd = (date.getFullYear() - 1980);
1267 ymd = ymd << 4 | (date.getMonth()+1);
1268 ymd = ymd << 5 | date.getDate();
1269 buf.write_shift(2, ymd);
1270}
1271
1272/* read four bytes from buf and interpret as a DOS date */
1273function parse_dos_date(buf) {
1274 var hms = buf.read_shift(2) & 0xFFFF;
1275 var ymd = buf.read_shift(2) & 0xFFFF;
1276 var val = new Date();
1277 var d = ymd & 0x1F; ymd >>>= 5;
1278 var m = ymd & 0x0F; ymd >>>= 4;
1279 val.setMilliseconds(0);
1280 val.setFullYear(ymd + 1980);
1281 val.setMonth(m-1);
1282 val.setDate(d);
1283 var S = hms & 0x1F; hms >>>= 5;
1284 var M = hms & 0x3F; hms >>>= 6;
1285 val.setHours(hms);
1286 val.setMinutes(M);
1287 val.setSeconds(S<<1);
1288 return val;
1289}
1290function parse_extra_field(blob) {
1291 prep_blob(blob, 0);
1292 var o = {};
1293 var flags = 0;
1294 while(blob.l <= blob.length - 4) {
1295 var type = blob.read_shift(2);
1296 var sz = blob.read_shift(2), tgt = blob.l + sz;
1297 var p = {};
1298 switch(type) {
1299 /* UNIX-style Timestamps */
1300 case 0x5455: {
1301 flags = blob.read_shift(1);
1302 if(flags & 1) p.mtime = blob.read_shift(4);
1303 /* for some reason, CD flag corresponds to LFH */
1304 if(sz > 5) {
1305 if(flags & 2) p.atime = blob.read_shift(4);
1306 if(flags & 4) p.ctime = blob.read_shift(4);
1307 }
1308 if(p.mtime) p.mt = new Date(p.mtime*1000);
1309 }
1310 break;
1311 }
1312 blob.l = tgt;
1313 o[type] = p;
1314 }
1315 return o;
1316}
1317var fs;
1318function get_fs() { return fs || (fs = require('fs')); }
1319function parse(file, options) {
1320if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
1321if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
1322var mver = 3;
1323var ssz = 512;
1324var nmfs = 0; // number of mini FAT sectors
1325var difat_sec_cnt = 0;
1326var dir_start = 0;
1327var minifat_start = 0;
1328var difat_start = 0;
1329
1330var fat_addrs = []; // locations of FAT sectors
1331
1332/* [MS-CFB] 2.2 Compound File Header */
1333var blob = file.slice(0,512);
1334prep_blob(blob, 0);
1335
1336/* major version */
1337var mv = check_get_mver(blob);
1338mver = mv[0];
1339switch(mver) {
1340 case 3: ssz = 512; break; case 4: ssz = 4096; break;
1341 case 0: if(mv[1] == 0) return parse_zip(file, options);
1342 /* falls through */
1343 default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
1344}
1345
1346/* reprocess header */
1347if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
1348/* Save header for final object */
1349var header = file.slice(0,ssz);
1350
1351check_shifts(blob, mver);
1352
1353// Number of Directory Sectors
1354var dir_cnt = blob.read_shift(4, 'i');
1355if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
1356
1357// Number of FAT Sectors
1358blob.l += 4;
1359
1360// First Directory Sector Location
1361dir_start = blob.read_shift(4, 'i');
1362
1363// Transaction Signature
1364blob.l += 4;
1365
1366// Mini Stream Cutoff Size
1367blob.chk('00100000', 'Mini Stream Cutoff Size: ');
1368
1369// First Mini FAT Sector Location
1370minifat_start = blob.read_shift(4, 'i');
1371
1372// Number of Mini FAT Sectors
1373nmfs = blob.read_shift(4, 'i');
1374
1375// First DIFAT sector location
1376difat_start = blob.read_shift(4, 'i');
1377
1378// Number of DIFAT Sectors
1379difat_sec_cnt = blob.read_shift(4, 'i');
1380
1381// Grab FAT Sector Locations
1382for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
1383 q = blob.read_shift(4, 'i');
1384 if(q<0) break;
1385 fat_addrs[j] = q;
1386}
1387
1388/** Break the file up into sectors */
1389var sectors = sectorify(file, ssz);
1390
1391sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
1392
1393/** Chains */
1394var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);
1395
1396sector_list[dir_start].name = "!Directory";
1397if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
1398sector_list[fat_addrs[0]].name = "!FAT";
1399sector_list.fat_addrs = fat_addrs;
1400sector_list.ssz = ssz;
1401
1402/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1403var files = {}, Paths = [], FileIndex = [], FullPaths = [];
1404read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
1405
1406build_full_paths(FileIndex, FullPaths, Paths);
1407Paths.shift();
1408
1409var o = {
1410 FileIndex: FileIndex,
1411 FullPaths: FullPaths
1412};
1413
1414// $FlowIgnore
1415if(options && options.raw) o.raw = {header: header, sectors: sectors};
1416return o;
1417} // parse
1418
1419/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
1420function check_get_mver(blob) {
1421 if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
1422 // header signature 8
1423 blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
1424
1425 // clsid 16
1426 //blob.chk(HEADER_CLSID, 'CLSID: ');
1427 blob.l += 16;
1428
1429 // minor version 2
1430 var mver = blob.read_shift(2, 'u');
1431
1432 return [blob.read_shift(2,'u'), mver];
1433}
1434function check_shifts(blob, mver) {
1435 var shift = 0x09;
1436
1437 // Byte Order
1438 //blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff
1439 blob.l += 2;
1440
1441 // Sector Shift
1442 switch((shift = blob.read_shift(2))) {
1443 case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;
1444 case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;
1445 default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);
1446 }
1447
1448 // Mini Sector Shift
1449 blob.chk('0600', 'Mini Sector Shift: ');
1450
1451 // Reserved
1452 blob.chk('000000000000', 'Reserved: ');
1453}
1454
1455/** Break the file up into sectors */
1456function sectorify(file, ssz) {
1457 var nsectors = Math.ceil(file.length/ssz)-1;
1458 var sectors = [];
1459 for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
1460 sectors[nsectors-1] = file.slice(nsectors*ssz);
1461 return sectors;
1462}
1463
1464/* [MS-CFB] 2.6.4 Red-Black Tree */
1465function build_full_paths(FI, FP, Paths) {
1466 var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
1467 var dad = [], q = [];
1468
1469 for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
1470
1471 for(; j < q.length; ++j) {
1472 i = q[j];
1473 L = FI[i].L; R = FI[i].R; C = FI[i].C;
1474 if(dad[i] === i) {
1475 if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
1476 if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
1477 }
1478 if(C !== -1 /*NOSTREAM*/) dad[C] = i;
1479 if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
1480 if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
1481 }
1482 for(i=1; i < pl; ++i) if(dad[i] === i) {
1483 if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
1484 else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
1485 }
1486
1487 for(i=1; i < pl; ++i) {
1488 if(FI[i].type === 0 /* unknown */) continue;
1489 j = i;
1490 if(j != dad[j]) do {
1491 j = dad[j];
1492 FP[i] = FP[j] + "/" + FP[i];
1493 } while (j !== 0 && -1 !== dad[j] && j != dad[j]);
1494 dad[i] = -1;
1495 }
1496
1497 FP[0] += "/";
1498 for(i=1; i < pl; ++i) {
1499 if(FI[i].type !== 2 /* stream */) FP[i] += "/";
1500 }
1501}
1502
1503function get_mfat_entry(entry, payload, mini) {
1504 var start = entry.start, size = entry.size;
1505 //return (payload.slice(start*MSSZ, start*MSSZ + size));
1506 var o = [];
1507 var idx = start;
1508 while(mini && size > 0 && idx >= 0) {
1509 o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
1510 size -= MSSZ;
1511 idx = __readInt32LE(mini, idx * 4);
1512 }
1513 if(o.length === 0) return (new_buf(0));
1514 return (bconcat(o).slice(0, entry.size));
1515}
1516
1517/** Chase down the rest of the DIFAT chain to build a comprehensive list
1518 DIFAT chains by storing the next sector number as the last 32 bits */
1519function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
1520 var q = ENDOFCHAIN;
1521 if(idx === ENDOFCHAIN) {
1522 if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
1523 } else if(idx !== -1 /*FREESECT*/) {
1524 var sector = sectors[idx], m = (ssz>>>2)-1;
1525 if(!sector) return;
1526 for(var i = 0; i < m; ++i) {
1527 if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1528 fat_addrs.push(q);
1529 }
1530 sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
1531 }
1532}
1533
1534/** Follow the linked list of sectors for a given starting point */
1535function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
1536 var buf = [], buf_chain = [];
1537 if(!chkd) chkd = [];
1538 var modulus = ssz - 1, j = 0, jj = 0;
1539 for(j=start; j>=0;) {
1540 chkd[j] = true;
1541 buf[buf.length] = j;
1542 buf_chain.push(sectors[j]);
1543 var addr = fat_addrs[Math.floor(j*4/ssz)];
1544 jj = ((j*4) & modulus);
1545 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1546 if(!sectors[addr]) break;
1547 j = __readInt32LE(sectors[addr], jj);
1548 }
1549 return {nodes: buf, data:__toBuffer([buf_chain])};
1550}
1551
1552/** Chase down the sector linked lists */
1553function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
1554 var sl = sectors.length, sector_list = ([]);
1555 var chkd = [], buf = [], buf_chain = [];
1556 var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
1557 for(i=0; i < sl; ++i) {
1558 buf = ([]);
1559 k = (i + dir_start); if(k >= sl) k-=sl;
1560 if(chkd[k]) continue;
1561 buf_chain = [];
1562 for(j=k; j>=0;) {
1563 chkd[j] = true;
1564 buf[buf.length] = j;
1565 buf_chain.push(sectors[j]);
1566 var addr = fat_addrs[Math.floor(j*4/ssz)];
1567 jj = ((j*4) & modulus);
1568 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1569 if(!sectors[addr]) break;
1570 j = __readInt32LE(sectors[addr], jj);
1571 }
1572 sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
1573 }
1574 return sector_list;
1575}
1576
1577/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1578function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {
1579 var minifat_store = 0, pl = (Paths.length?2:0);
1580 var sector = sector_list[dir_start].data;
1581 var i = 0, namelen = 0, name;
1582 for(; i < sector.length; i+= 128) {
1583 var blob = sector.slice(i, i+128);
1584 prep_blob(blob, 64);
1585 namelen = blob.read_shift(2);
1586 name = __utf16le(blob,0,namelen-pl);
1587 Paths.push(name);
1588 var o = ({
1589 name: name,
1590 type: blob.read_shift(1),
1591 color: blob.read_shift(1),
1592 L: blob.read_shift(4, 'i'),
1593 R: blob.read_shift(4, 'i'),
1594 C: blob.read_shift(4, 'i'),
1595 clsid: blob.read_shift(16),
1596 state: blob.read_shift(4, 'i'),
1597 start: 0,
1598 size: 0
1599 });
1600 var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1601 if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1602 var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1603 if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1604 o.start = blob.read_shift(4, 'i');
1605 o.size = blob.read_shift(4, 'i');
1606 if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1607 if(o.type === 5) { /* root */
1608 minifat_store = o.start;
1609 if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1610 /*minifat_size = o.size;*/
1611 } else if(o.size >= 4096 /* MSCSZ */) {
1612 o.storage = 'fat';
1613 if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1614 sector_list[o.start].name = o.name;
1615 o.content = (sector_list[o.start].data.slice(0,o.size));
1616 } else {
1617 o.storage = 'minifat';
1618 if(o.size < 0) o.size = 0;
1619 else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1620 o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1621 }
1622 }
1623 if(o.content) prep_blob(o.content, 0);
1624 files[name] = o;
1625 FileIndex.push(o);
1626 }
1627}
1628
1629function read_date(blob, offset) {
1630 return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1631}
1632
1633function read_file(filename, options) {
1634 get_fs();
1635 return parse(fs.readFileSync(filename), options);
1636}
1637
1638function read(blob, options) {
1639 switch(options && options.type || "base64") {
1640 case "file": return read_file(blob, options);
1641 case "base64": return parse(s2a(Base64.decode(blob)), options);
1642 case "binary": return parse(s2a(blob), options);
1643 }
1644 return parse(blob, options);
1645}
1646
1647function init_cfb(cfb, opts) {
1648 var o = opts || {}, root = o.root || "Root Entry";
1649 if(!cfb.FullPaths) cfb.FullPaths = [];
1650 if(!cfb.FileIndex) cfb.FileIndex = [];
1651 if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1652 if(cfb.FullPaths.length === 0) {
1653 cfb.FullPaths[0] = root + "/";
1654 cfb.FileIndex[0] = ({ name: root, type: 5 });
1655 }
1656 if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1657 seed_cfb(cfb);
1658}
1659function seed_cfb(cfb) {
1660 var nm = "\u0001Sh33tJ5";
1661 if(CFB.find(cfb, "/" + nm)) return;
1662 var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1663 cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));
1664 cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1665 rebuild_cfb(cfb);
1666}
1667function rebuild_cfb(cfb, f) {
1668 init_cfb(cfb);
1669 var gc = false, s = false;
1670 for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1671 var _file = cfb.FileIndex[i];
1672 switch(_file.type) {
1673 case 0:
1674 if(s) gc = true;
1675 else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1676 break;
1677 case 1: case 2: case 5:
1678 s = true;
1679 if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1680 if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1681 break;
1682 default: gc = true; break;
1683 }
1684 }
1685 if(!gc && !f) return;
1686
1687 var now = new Date(1987, 1, 19), j = 0;
1688 var data = [];
1689 for(i = 0; i < cfb.FullPaths.length; ++i) {
1690 if(cfb.FileIndex[i].type === 0) continue;
1691 data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1692 }
1693 for(i = 0; i < data.length; ++i) {
1694 var dad = dirname(data[i][0]);
1695 s = false;
1696 for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1697 if(!s) data.push([dad, ({
1698 name: filename(dad).replace("/",""),
1699 type: 1,
1700 clsid: HEADER_CLSID,
1701 ct: now, mt: now,
1702 content: null
1703 })]);
1704 }
1705
1706 data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1707 cfb.FullPaths = []; cfb.FileIndex = [];
1708 for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1709 for(i = 0; i < data.length; ++i) {
1710 var elt = cfb.FileIndex[i];
1711 var nm = cfb.FullPaths[i];
1712
1713 elt.name = filename(nm).replace("/","");
1714 elt.L = elt.R = elt.C = -(elt.color = 1);
1715 elt.size = elt.content ? elt.content.length : 0;
1716 elt.start = 0;
1717 elt.clsid = (elt.clsid || HEADER_CLSID);
1718 if(i === 0) {
1719 elt.C = data.length > 1 ? 1 : -1;
1720 elt.size = 0;
1721 elt.type = 5;
1722 } else if(nm.slice(-1) == "/") {
1723 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1724 elt.C = j >= data.length ? -1 : j;
1725 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1726 elt.R = j >= data.length ? -1 : j;
1727 elt.type = 1;
1728 } else {
1729 if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1730 elt.type = 2;
1731 }
1732 }
1733
1734}
1735
1736function _write(cfb, options) {
1737 var _opts = options || {};
1738 rebuild_cfb(cfb);
1739 if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
1740 var L = (function(cfb){
1741 var mini_size = 0, fat_size = 0;
1742 for(var i = 0; i < cfb.FileIndex.length; ++i) {
1743 var file = cfb.FileIndex[i];
1744 if(!file.content) continue;
1745var flen = file.content.length;
1746 if(flen > 0){
1747 if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1748 else fat_size += (flen + 0x01FF) >> 9;
1749 }
1750 }
1751 var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1752 var mini_cnt = (mini_size + 7) >> 3;
1753 var mfat_cnt = (mini_size + 0x7F) >> 7;
1754 var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1755 var fat_cnt = (fat_base + 0x7F) >> 7;
1756 var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1757 while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1758 var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1759 cfb.FileIndex[0].size = mini_size << 6;
1760 L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1761 return L;
1762 })(cfb);
1763 var o = new_buf(L[7] << 9);
1764 var i = 0, T = 0;
1765 {
1766 for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1767 for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1768 o.write_shift(2, 0x003E);
1769 o.write_shift(2, 0x0003);
1770 o.write_shift(2, 0xFFFE);
1771 o.write_shift(2, 0x0009);
1772 o.write_shift(2, 0x0006);
1773 for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1774 o.write_shift(4, 0);
1775 o.write_shift(4, L[2]);
1776 o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1777 o.write_shift(4, 0);
1778 o.write_shift(4, 1<<12);
1779 o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1780 o.write_shift(4, L[3]);
1781 o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1782 o.write_shift(4, L[1]);
1783 for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1784 }
1785 if(L[1]) {
1786 for(T = 0; T < L[1]; ++T) {
1787 for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1788 o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1789 }
1790 }
1791 var chainit = function(w) {
1792 for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1793 if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1794 };
1795 T = i = 0;
1796 for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1797 for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1798 chainit(L[3]);
1799 chainit(L[4]);
1800 var j = 0, flen = 0;
1801 var file = cfb.FileIndex[0];
1802 for(; j < cfb.FileIndex.length; ++j) {
1803 file = cfb.FileIndex[j];
1804 if(!file.content) continue;
1805flen = file.content.length;
1806 if(flen < 0x1000) continue;
1807 file.start = T;
1808 chainit((flen + 0x01FF) >> 9);
1809 }
1810 chainit((L[6] + 7) >> 3);
1811 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1812 T = i = 0;
1813 for(j = 0; j < cfb.FileIndex.length; ++j) {
1814 file = cfb.FileIndex[j];
1815 if(!file.content) continue;
1816flen = file.content.length;
1817 if(!flen || flen >= 0x1000) continue;
1818 file.start = T;
1819 chainit((flen + 0x3F) >> 6);
1820 }
1821 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1822 for(i = 0; i < L[4]<<2; ++i) {
1823 var nm = cfb.FullPaths[i];
1824 if(!nm || nm.length === 0) {
1825 for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1826 for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1827 for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1828 continue;
1829 }
1830 file = cfb.FileIndex[i];
1831 if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1832 var _nm = (i === 0 && _opts.root) || file.name;
1833 flen = 2*(_nm.length+1);
1834 o.write_shift(64, _nm, "utf16le");
1835 o.write_shift(2, flen);
1836 o.write_shift(1, file.type);
1837 o.write_shift(1, file.color);
1838 o.write_shift(-4, file.L);
1839 o.write_shift(-4, file.R);
1840 o.write_shift(-4, file.C);
1841 if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1842 else o.write_shift(16, file.clsid, "hex");
1843 o.write_shift(4, file.state || 0);
1844 o.write_shift(4, 0); o.write_shift(4, 0);
1845 o.write_shift(4, 0); o.write_shift(4, 0);
1846 o.write_shift(4, file.start);
1847 o.write_shift(4, file.size); o.write_shift(4, 0);
1848 }
1849 for(i = 1; i < cfb.FileIndex.length; ++i) {
1850 file = cfb.FileIndex[i];
1851if(file.size >= 0x1000) {
1852 o.l = (file.start+1) << 9;
1853 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1854 for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1855 }
1856 }
1857 for(i = 1; i < cfb.FileIndex.length; ++i) {
1858 file = cfb.FileIndex[i];
1859if(file.size > 0 && file.size < 0x1000) {
1860 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1861 for(; j & 0x3F; ++j) o.write_shift(1, 0);
1862 }
1863 }
1864 while(o.l < o.length) o.write_shift(1, 0);
1865 return o;
1866}
1867/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1868function find(cfb, path) {
1869 var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1870 var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1871 var k = false;
1872 if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1873 else k = path.indexOf("/") !== -1;
1874 var UCPath = path.toUpperCase();
1875 var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1876 if(w !== -1) return cfb.FileIndex[w];
1877
1878 var m = !UCPath.match(chr1);
1879 UCPath = UCPath.replace(chr0,'');
1880 if(m) UCPath = UCPath.replace(chr1,'!');
1881 for(w = 0; w < UCFullPaths.length; ++w) {
1882 if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1883 if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1884 }
1885 return null;
1886}
1887/** CFB Constants */
1888var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1889//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1890/* 2.1 Compound File Sector Numbers and Types */
1891var ENDOFCHAIN = -2;
1892/* 2.2 Compound File Header */
1893var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1894var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1895var HEADER_CLSID = '00000000000000000000000000000000';
1896var consts = {
1897 /* 2.1 Compund File Sector Numbers and Types */
1898 MAXREGSECT: -6,
1899 DIFSECT: -4,
1900 FATSECT: -3,
1901 ENDOFCHAIN: ENDOFCHAIN,
1902 FREESECT: -1,
1903 /* 2.2 Compound File Header */
1904 HEADER_SIGNATURE: HEADER_SIGNATURE,
1905 HEADER_MINOR_VERSION: '3e00',
1906 MAXREGSID: -6,
1907 NOSTREAM: -1,
1908 HEADER_CLSID: HEADER_CLSID,
1909 /* 2.6.1 Compound File Directory Entry */
1910 EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
1911};
1912
1913function write_file(cfb, filename, options) {
1914 get_fs();
1915 var o = _write(cfb, options);
1916fs.writeFileSync(filename, o);
1917}
1918
1919function a2s(o) {
1920 var out = new Array(o.length);
1921 for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
1922 return out.join("");
1923}
1924
1925function write(cfb, options) {
1926 var o = _write(cfb, options);
1927 switch(options && options.type) {
1928 case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
1929 case "binary": return a2s(o);
1930 case "base64": return Base64.encode(a2s(o));
1931 }
1932 return o;
1933}
1934/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
1935var _zlib;
1936function use_zlib(zlib) { try {
1937 var InflateRaw = zlib.InflateRaw;
1938 var InflRaw = new InflateRaw();
1939 InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
1940 if(InflRaw.bytesRead) _zlib = zlib;
1941 else throw new Error("zlib does not expose bytesRead");
1942} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
1943
1944function _inflateRawSync(payload, usz) {
1945 if(!_zlib) return _inflate(payload, usz);
1946 var InflateRaw = _zlib.InflateRaw;
1947 var InflRaw = new InflateRaw();
1948 var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
1949 payload.l += InflRaw.bytesRead;
1950 return out;
1951}
1952
1953function _deflateRawSync(payload) {
1954 return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
1955}
1956var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
1957
1958/* 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 ]; */
1959var 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 ];
1960
1961/* 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 ]; */
1962var 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 ];
1963
1964function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
1965
1966var use_typed_arrays = typeof Uint8Array !== 'undefined';
1967
1968var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
1969for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
1970
1971function bit_swap_n(n, b) {
1972 var rev = bitswap8[n & 0xFF];
1973 if(b <= 8) return rev >>> (8-b);
1974 rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
1975 if(b <= 16) return rev >>> (16-b);
1976 rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
1977 return rev >>> (24-b);
1978}
1979
1980/* helpers for unaligned bit reads */
1981function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
1982function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
1983function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
1984function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
1985function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
1986
1987/* works up to n = 3 * 8 + 1 = 25 */
1988function read_bits_n(buf, bl, n) {
1989 var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
1990 var v = buf[h] >>> w;
1991 if(n < 8 - w) return v & f;
1992 v |= buf[h+1]<<(8-w);
1993 if(n < 16 - w) return v & f;
1994 v |= buf[h+2]<<(16-w);
1995 if(n < 24 - w) return v & f;
1996 v |= buf[h+3]<<(24-w);
1997 return v & f;
1998}
1999
2000/* until ArrayBuffer#realloc is a thing, fake a realloc */
2001function realloc(b, sz) {
2002 var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
2003 if(L >= sz) return b;
2004 if(has_buf) {
2005 var o = new_unsafe_buf(M);
2006 // $FlowIgnore
2007 if(b.copy) b.copy(o);
2008 else for(; i < b.length; ++i) o[i] = b[i];
2009 return o;
2010 } else if(use_typed_arrays) {
2011 var a = new Uint8Array(M);
2012 if(a.set) a.set(b);
2013 else for(; i < b.length; ++i) a[i] = b[i];
2014 return a;
2015 }
2016 b.length = M;
2017 return b;
2018}
2019
2020/* zero-filled arrays for older browsers */
2021function zero_fill_array(n) {
2022 var o = new Array(n);
2023 for(var i = 0; i < n; ++i) o[i] = 0;
2024 return o;
2025}var _deflate = (function() {
2026var _deflateRaw = (function() {
2027 return function deflateRaw(data, out) {
2028 var boff = 0;
2029 while(boff < data.length) {
2030 var L = Math.min(0xFFFF, data.length - boff);
2031 var h = boff + L == data.length;
2032 /* TODO: this is only type 0 stored */
2033 out.write_shift(1, +h);
2034 out.write_shift(2, L);
2035 out.write_shift(2, (~L) & 0xFFFF);
2036 while(L-- > 0) out[out.l++] = data[boff++];
2037 }
2038 return out.l;
2039 };
2040})();
2041
2042return function(data) {
2043 var buf = new_buf(50+Math.floor(data.length*1.1));
2044 var off = _deflateRaw(data, buf);
2045 return buf.slice(0, off);
2046};
2047})();
2048/* modified inflate function also moves original read head */
2049
2050/* build tree (used for literals and lengths) */
2051function build_tree(clens, cmap, MAX) {
2052 var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
2053
2054 var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2055 for(i = 0; i < 32; ++i) bl_count[i] = 0;
2056
2057 for(i = L; i < MAX; ++i) clens[i] = 0;
2058 L = clens.length;
2059
2060 var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
2061
2062 /* build code tree */
2063 for(i = 0; i < L; ++i) {
2064 bl_count[(w = clens[i])]++;
2065 if(maxlen < w) maxlen = w;
2066 ctree[i] = 0;
2067 }
2068 bl_count[0] = 0;
2069 for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
2070 for(i = 0; i < L; ++i) {
2071 ccode = clens[i];
2072 if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
2073 }
2074
2075 /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
2076 var cleni = 0;
2077 for(i = 0; i < L; ++i) {
2078 cleni = clens[i];
2079 if(cleni != 0) {
2080 ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
2081 for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
2082 cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
2083 }
2084 }
2085 return maxlen;
2086}
2087
2088var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
2089var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2090if(!use_typed_arrays) {
2091 for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
2092 for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
2093}
2094(function() {
2095 var dlens = [];
2096 var i = 0;
2097 for(;i<32; i++) dlens.push(5);
2098 build_tree(dlens, fix_dmap, 32);
2099
2100 var clens = [];
2101 i = 0;
2102 for(; i<=143; i++) clens.push(8);
2103 for(; i<=255; i++) clens.push(9);
2104 for(; i<=279; i++) clens.push(7);
2105 for(; i<=287; i++) clens.push(8);
2106 build_tree(clens, fix_lmap, 288);
2107})();
2108
2109var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2110var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2111var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
2112var dyn_len_1 = 1, dyn_len_2 = 1;
2113
2114/* 5.5.3 Expanding Huffman Codes */
2115function dyn(data, boff) {
2116 /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
2117 var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
2118 var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
2119 var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
2120 var w = 0;
2121
2122 /* grab and store code lengths */
2123 var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
2124 var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2125 var maxlen = 1;
2126 var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2127 var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2128 var L = clens.length; /* 19 */
2129 for(var i = 0; i < _HCLEN; ++i) {
2130 clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
2131 if(maxlen < w) maxlen = w;
2132 bl_count[w]++;
2133 boff += 3;
2134 }
2135
2136 /* build code tree */
2137 var ccode = 0;
2138 bl_count[0] = 0;
2139 for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
2140 for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
2141 /* cmap[7 bits from stream] = (off&7) + (lit<<3) */
2142 var cleni = 0;
2143 for(i = 0; i < L; ++i) {
2144 cleni = clens[i];
2145 if(cleni != 0) {
2146 ccode = bitswap8[ctree[i]]>>(8-cleni);
2147 for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
2148 }
2149 }
2150
2151 /* read literal and dist codes at once */
2152 var hcodes = [];
2153 maxlen = 1;
2154 for(; hcodes.length < _HLIT + _HDIST;) {
2155 ccode = dyn_cmap[read_bits_7(data, boff)];
2156 boff += ccode & 7;
2157 switch((ccode >>>= 3)) {
2158 case 16:
2159 w = 3 + read_bits_2(data, boff); boff += 2;
2160 ccode = hcodes[hcodes.length - 1];
2161 while(w-- > 0) hcodes.push(ccode);
2162 break;
2163 case 17:
2164 w = 3 + read_bits_3(data, boff); boff += 3;
2165 while(w-- > 0) hcodes.push(0);
2166 break;
2167 case 18:
2168 w = 11 + read_bits_7(data, boff); boff += 7;
2169 while(w -- > 0) hcodes.push(0);
2170 break;
2171 default:
2172 hcodes.push(ccode);
2173 if(maxlen < ccode) maxlen = ccode;
2174 break;
2175 }
2176 }
2177
2178 /* build literal / length trees */
2179 var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
2180 for(i = _HLIT; i < 286; ++i) h1[i] = 0;
2181 for(i = _HDIST; i < 30; ++i) h2[i] = 0;
2182 dyn_len_1 = build_tree(h1, dyn_lmap, 286);
2183 dyn_len_2 = build_tree(h2, dyn_dmap, 30);
2184 return boff;
2185}
2186
2187/* return [ data, bytesRead ] */
2188function inflate(data, usz) {
2189 /* shortcircuit for empty buffer [0x03, 0x00] */
2190 if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
2191
2192 /* bit offset */
2193 var boff = 0;
2194
2195 /* header includes final bit and type bits */
2196 var header = 0;
2197
2198 var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
2199 var woff = 0;
2200 var OL = outbuf.length>>>0;
2201 var max_len_1 = 0, max_len_2 = 0;
2202
2203 while((header&1) == 0) {
2204 header = read_bits_3(data, boff); boff += 3;
2205 if((header >>> 1) == 0) {
2206 /* Stored block */
2207 if(boff & 7) boff += 8 - (boff&7);
2208 /* 2 bytes sz, 2 bytes bit inverse */
2209 var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
2210 boff += 32;
2211 /* push sz bytes */
2212 if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
2213 if(typeof data.copy === 'function') {
2214 // $FlowIgnore
2215 data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
2216 woff += sz; boff += 8*sz;
2217 } else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
2218 continue;
2219 } else if((header >>> 1) == 1) {
2220 /* Fixed Huffman */
2221 max_len_1 = 9; max_len_2 = 5;
2222 } else {
2223 /* Dynamic Huffman */
2224 boff = dyn(data, boff);
2225 max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
2226 }
2227 if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
2228 for(;;) { // while(true) is apparently out of vogue in modern JS circles
2229 /* ingest code and move read head */
2230 var bits = read_bits_n(data, boff, max_len_1);
2231 var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
2232 boff += code & 15; code >>>= 4;
2233 /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
2234 if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
2235 else if(code == 256) break;
2236 else {
2237 code -= 257;
2238 var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
2239 var tgt = woff + LEN_LN[code];
2240 /* length extra bits */
2241 if(len_eb > 0) {
2242 tgt += read_bits_n(data, boff, len_eb);
2243 boff += len_eb;
2244 }
2245
2246 /* dist code */
2247 bits = read_bits_n(data, boff, max_len_2);
2248 code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
2249 boff += code & 15; code >>>= 4;
2250 var dst_eb = (code < 4 ? 0 : (code-2)>>1);
2251 var dst = DST_LN[code];
2252 /* dist extra bits */
2253 if(dst_eb > 0) {
2254 dst += read_bits_n(data, boff, dst_eb);
2255 boff += dst_eb;
2256 }
2257
2258 /* in the common case, manual byte copy is faster than TA set / Buffer copy */
2259 if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
2260 while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
2261 }
2262 }
2263 }
2264 return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
2265}
2266
2267function _inflate(payload, usz) {
2268 var data = payload.slice(payload.l||0);
2269 var out = inflate(data, usz);
2270 payload.l += out[1];
2271 return out[0];
2272}
2273
2274function warn_or_throw(wrn, msg) {
2275 if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
2276 else throw new Error(msg);
2277}
2278
2279function parse_zip(file, options) {
2280 var blob = file;
2281 prep_blob(blob, 0);
2282
2283 var FileIndex = [], FullPaths = [];
2284 var o = {
2285 FileIndex: FileIndex,
2286 FullPaths: FullPaths
2287 };
2288 init_cfb(o, { root: options.root });
2289
2290 /* find end of central directory, start just after signature */
2291 var i = blob.length - 4;
2292 while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
2293 blob.l = i + 4;
2294
2295 /* parse end of central directory */
2296 blob.l += 4;
2297 var fcnt = blob.read_shift(2);
2298 blob.l += 6;
2299 var start_cd = blob.read_shift(4);
2300
2301 /* parse central directory */
2302 blob.l = start_cd;
2303
2304 for(i = 0; i < fcnt; ++i) {
2305 /* trust local file header instead of CD entry */
2306 blob.l += 20;
2307 var csz = blob.read_shift(4);
2308 var usz = blob.read_shift(4);
2309 var namelen = blob.read_shift(2);
2310 var efsz = blob.read_shift(2);
2311 var fcsz = blob.read_shift(2);
2312 blob.l += 8;
2313 var offset = blob.read_shift(4);
2314 var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
2315 blob.l += namelen + efsz + fcsz;
2316
2317 var L = blob.l;
2318 blob.l = offset + 4;
2319 parse_local_file(blob, csz, usz, o, EF);
2320 blob.l = L;
2321 }
2322
2323 return o;
2324}
2325
2326
2327/* head starts just after local file header signature */
2328function parse_local_file(blob, csz, usz, o, EF) {
2329 /* [local file header] */
2330 blob.l += 2;
2331 var flags = blob.read_shift(2);
2332 var meth = blob.read_shift(2);
2333 var date = parse_dos_date(blob);
2334
2335 if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
2336 var crc32 = blob.read_shift(4);
2337 var _csz = blob.read_shift(4);
2338 var _usz = blob.read_shift(4);
2339
2340 var namelen = blob.read_shift(2);
2341 var efsz = blob.read_shift(2);
2342
2343 // TODO: flags & (1<<11) // UTF8
2344 var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
2345 if(efsz) {
2346 var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
2347 if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
2348 if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
2349 }
2350 blob.l += efsz;
2351
2352 /* [encryption header] */
2353
2354 /* [file data] */
2355 var data = blob.slice(blob.l, blob.l + _csz);
2356 switch(meth) {
2357 case 8: data = _inflateRawSync(blob, _usz); break;
2358 case 0: break;
2359 default: throw new Error("Unsupported ZIP Compression method " + meth);
2360 }
2361
2362 /* [data descriptor] */
2363 var wrn = false;
2364 if(flags & 8) {
2365 crc32 = blob.read_shift(4);
2366 if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
2367 _csz = blob.read_shift(4);
2368 _usz = blob.read_shift(4);
2369 }
2370
2371 if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
2372 if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
2373 var _crc32 = CRC32.buf(data, 0);
2374 if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
2375 cfb_add(o, name, data, {unsafe: true, mt: date});
2376}
2377function write_zip(cfb, options) {
2378 var _opts = options || {};
2379 var out = [], cdirs = [];
2380 var o = new_buf(1);
2381 var method = (_opts.compression ? 8 : 0), flags = 0;
2382 var desc = false;
2383 if(desc) flags |= 8;
2384 var i = 0, j = 0;
2385
2386 var start_cd = 0, fcnt = 0;
2387 var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
2388 var crcs = [];
2389 var sz_cd = 0;
2390
2391 for(i = 1; i < cfb.FullPaths.length; ++i) {
2392 fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
2393 if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
2394 var start = start_cd;
2395
2396 /* TODO: CP437 filename */
2397 var namebuf = new_buf(fp.length);
2398 for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
2399 namebuf = namebuf.slice(0, namebuf.l);
2400 crcs[fcnt] = CRC32.buf(fi.content, 0);
2401
2402 var outbuf = fi.content;
2403 if(method == 8) outbuf = _deflateRawSync(outbuf);
2404
2405 /* local file header */
2406 o = new_buf(30);
2407 o.write_shift(4, 0x04034b50);
2408 o.write_shift(2, 20);
2409 o.write_shift(2, flags);
2410 o.write_shift(2, method);
2411 /* TODO: last mod file time/date */
2412 if(fi.mt) write_dos_date(o, fi.mt);
2413 else o.write_shift(4, 0);
2414 o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
2415 o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
2416 o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
2417 o.write_shift(2, namebuf.length);
2418 o.write_shift(2, 0);
2419
2420 start_cd += o.length;
2421 out.push(o);
2422 start_cd += namebuf.length;
2423 out.push(namebuf);
2424
2425 /* TODO: encryption header ? */
2426 start_cd += outbuf.length;
2427 out.push(outbuf);
2428
2429 /* data descriptor */
2430 if(flags & 8) {
2431 o = new_buf(12);
2432 o.write_shift(-4, crcs[fcnt]);
2433 o.write_shift(4, outbuf.length);
2434 o.write_shift(4, fi.content.length);
2435 start_cd += o.l;
2436 out.push(o);
2437 }
2438
2439 /* central directory */
2440 o = new_buf(46);
2441 o.write_shift(4, 0x02014b50);
2442 o.write_shift(2, 0);
2443 o.write_shift(2, 20);
2444 o.write_shift(2, flags);
2445 o.write_shift(2, method);
2446 o.write_shift(4, 0); /* TODO: last mod file time/date */
2447 o.write_shift(-4, crcs[fcnt]);
2448
2449 o.write_shift(4, outbuf.length);
2450 o.write_shift(4, fi.content.length);
2451 o.write_shift(2, namebuf.length);
2452 o.write_shift(2, 0);
2453 o.write_shift(2, 0);
2454 o.write_shift(2, 0);
2455 o.write_shift(2, 0);
2456 o.write_shift(4, 0);
2457 o.write_shift(4, start);
2458
2459 sz_cd += o.l;
2460 cdirs.push(o);
2461 sz_cd += namebuf.length;
2462 cdirs.push(namebuf);
2463 ++fcnt;
2464 }
2465
2466 /* end of central directory */
2467 o = new_buf(22);
2468 o.write_shift(4, 0x06054b50);
2469 o.write_shift(2, 0);
2470 o.write_shift(2, 0);
2471 o.write_shift(2, fcnt);
2472 o.write_shift(2, fcnt);
2473 o.write_shift(4, sz_cd);
2474 o.write_shift(4, start_cd);
2475 o.write_shift(2, 0);
2476
2477 return bconcat(([bconcat((out)), bconcat(cdirs), o]));
2478}
2479function cfb_new(opts) {
2480 var o = ({});
2481 init_cfb(o, opts);
2482 return o;
2483}
2484
2485function cfb_add(cfb, name, content, opts) {
2486 var unsafe = opts && opts.unsafe;
2487 if(!unsafe) init_cfb(cfb);
2488 var file = !unsafe && CFB.find(cfb, name);
2489 if(!file) {
2490 var fpath = cfb.FullPaths[0];
2491 if(name.slice(0, fpath.length) == fpath) fpath = name;
2492 else {
2493 if(fpath.slice(-1) != "/") fpath += "/";
2494 fpath = (fpath + name).replace("//","/");
2495 }
2496 file = ({name: filename(name), type: 2});
2497 cfb.FileIndex.push(file);
2498 cfb.FullPaths.push(fpath);
2499 if(!unsafe) CFB.utils.cfb_gc(cfb);
2500 }
2501file.content = (content);
2502 file.size = content ? content.length : 0;
2503 if(opts) {
2504 if(opts.CLSID) file.clsid = opts.CLSID;
2505 if(opts.mt) file.mt = opts.mt;
2506 if(opts.ct) file.ct = opts.ct;
2507 }
2508 return file;
2509}
2510
2511function cfb_del(cfb, name) {
2512 init_cfb(cfb);
2513 var file = CFB.find(cfb, name);
2514 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2515 cfb.FileIndex.splice(j, 1);
2516 cfb.FullPaths.splice(j, 1);
2517 return true;
2518 }
2519 return false;
2520}
2521
2522function cfb_mov(cfb, old_name, new_name) {
2523 init_cfb(cfb);
2524 var file = CFB.find(cfb, old_name);
2525 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2526 cfb.FileIndex[j].name = filename(new_name);
2527 cfb.FullPaths[j] = new_name;
2528 return true;
2529 }
2530 return false;
2531}
2532
2533function cfb_gc(cfb) { rebuild_cfb(cfb, true); }
2534
2535exports.find = find;
2536exports.read = read;
2537exports.parse = parse;
2538exports.write = write;
2539exports.writeFile = write_file;
2540exports.utils = {
2541 cfb_new: cfb_new,
2542 cfb_add: cfb_add,
2543 cfb_del: cfb_del,
2544 cfb_mov: cfb_mov,
2545 cfb_gc: cfb_gc,
2546 ReadShift: ReadShift,
2547 CheckField: CheckField,
2548 prep_blob: prep_blob,
2549 bconcat: bconcat,
2550 use_zlib: use_zlib,
2551 _deflateRaw: _deflate,
2552 _inflateRaw: _inflate,
2553 consts: consts
2554};
2555
2556return exports;
2557})();
2558
2559if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
2560var _fs;
2561if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
2562
2563/* normalize data for blob ctor */
2564function blobify(data) {
2565 if(typeof data === "string") return s2ab(data);
2566 if(Array.isArray(data)) return a2u(data);
2567 return data;
2568}
2569/* write or download file */
2570function write_dl(fname, payload, enc) {
2571 /*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File, chrome */
2572 if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
2573 var data = (enc == "utf8") ? utf8write(payload) : payload;
2574if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
2575 if(typeof Blob !== 'undefined') {
2576 var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
2577if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
2578if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
2579 if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
2580 var url = URL.createObjectURL(blob);
2581if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
2582 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2583 return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
2584 }
2585 var a = document.createElement("a");
2586 if(a.download != null) {
2587a.download = fname; a.href = url; document.body.appendChild(a); a.click();
2588document.body.removeChild(a);
2589 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2590 return url;
2591 }
2592 }
2593 }
2594 // $FlowIgnore
2595 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2596 // $FlowIgnore
2597 var out = File(fname); out.open("w"); out.encoding = "binary";
2598 if(Array.isArray(payload)) payload = a2s(payload);
2599 out.write(payload); out.close(); return payload;
2600 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2601 throw new Error("cannot save file " + fname);
2602}
2603
2604/* read binary data from file */
2605function read_binary(path) {
2606 if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
2607 // $FlowIgnore
2608 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2609 // $FlowIgnore
2610 var infile = File(path); infile.open("r"); infile.encoding = "binary";
2611 var data = infile.read(); infile.close();
2612 return data;
2613 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2614 throw new Error("Cannot access file " + path);
2615}
2616function keys(o) {
2617 var ks = Object.keys(o), o2 = [];
2618 for(var i = 0; i < ks.length; ++i) if(o.hasOwnProperty(ks[i])) o2.push(ks[i]);
2619 return o2;
2620}
2621
2622function evert_key(obj, key) {
2623 var o = ([]), K = keys(obj);
2624 for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
2625 return o;
2626}
2627
2628function evert(obj) {
2629 var o = ([]), K = keys(obj);
2630 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
2631 return o;
2632}
2633
2634function evert_num(obj) {
2635 var o = ([]), K = keys(obj);
2636 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
2637 return o;
2638}
2639
2640function evert_arr(obj) {
2641 var o = ([]), K = keys(obj);
2642 for(var i = 0; i !== K.length; ++i) {
2643 if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
2644 o[obj[K[i]]].push(K[i]);
2645 }
2646 return o;
2647}
2648
2649var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
2650var dnthresh = basedate.getTime() + (new Date().getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2651function datenum(v, date1904) {
2652 var epoch = v.getTime();
2653 if(date1904) epoch -= 1462*24*60*60*1000;
2654 return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
2655}
2656function numdate(v) {
2657 var out = new Date();
2658 out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
2659 return out;
2660}
2661
2662/* ISO 8601 Duration */
2663function parse_isodur(s) {
2664 var sec = 0, mt = 0, time = false;
2665 var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
2666 if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
2667 for(var i = 1; i != m.length; ++i) {
2668 if(!m[i]) continue;
2669 mt = 1;
2670 if(i > 3) time = true;
2671 switch(m[i].slice(m[i].length-1)) {
2672 case 'Y':
2673 throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
2674 case 'D': mt *= 24;
2675 /* falls through */
2676 case 'H': mt *= 60;
2677 /* falls through */
2678 case 'M':
2679 if(!time) throw new Error("Unsupported ISO Duration Field: M");
2680 else mt *= 60;
2681 /* falls through */
2682 case 'S': break;
2683 }
2684 sec += mt * parseInt(m[i], 10);
2685 }
2686 return sec;
2687}
2688
2689var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
2690if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
2691var good_pd = good_pd_date.getFullYear() == 2017;
2692/* parses a date as a local date */
2693function parseDate(str, fixdate) {
2694 var d = new Date(str);
2695 if(good_pd) {
2696if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
2697 else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
2698 return d;
2699 }
2700 if(str instanceof Date) return str;
2701 if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
2702 var s = d.getFullYear();
2703 if(str.indexOf("" + s) > -1) return d;
2704 d.setFullYear(d.getFullYear() + 100); return d;
2705 }
2706 var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
2707 var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
2708 if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
2709 return out;
2710}
2711
2712function cc2str(arr) {
2713 var o = "";
2714 for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2715 return o;
2716}
2717
2718function dup(o) {
2719 if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2720 if(typeof o != 'object' || o == null) return o;
2721 if(o instanceof Date) return new Date(o.getTime());
2722 var out = {};
2723 for(var k in o) if(o.hasOwnProperty(k)) out[k] = dup(o[k]);
2724 return out;
2725}
2726
2727function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
2728
2729/* TODO: stress test */
2730function fuzzynum(s) {
2731 var v = Number(s);
2732 if(!isNaN(v)) return v;
2733 var wt = 1;
2734 var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2735 if(!isNaN(v = Number(ss))) return v / wt;
2736 ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2737 if(!isNaN(v = Number(ss))) return v / wt;
2738 return v;
2739}
2740function fuzzydate(s) {
2741 var o = new Date(s), n = new Date(NaN);
2742 var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2743 if(isNaN(d)) return n;
2744 if(y < 0 || y > 8099) return n;
2745 if((m > 0 || d > 1) && y != 101) return o;
2746 if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2747 if(s.match(/[^-0-9:,\/\\]/)) return n;
2748 return o;
2749}
2750
2751var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2752function split_regex(str, re, def) {
2753 if(safe_split_regex || typeof re == "string") return str.split(re);
2754 var p = str.split(re), o = [p[0]];
2755 for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2756 return o;
2757}
2758function getdatastr(data) {
2759 if(!data) return null;
2760 if(data.data) return debom(data.data);
2761 if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2762 if(data.asBinary) return debom(data.asBinary());
2763 if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2764 if(data.content && data.type) return debom(cc2str(data.content));
2765 return null;
2766}
2767
2768function getdatabin(data) {
2769 if(!data) return null;
2770 if(data.data) return char_codes(data.data);
2771 if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2772 if(data._data && data._data.getContent) {
2773 var o = data._data.getContent();
2774 if(typeof o == "string") return char_codes(o);
2775 return Array.prototype.slice.call(o);
2776 }
2777 if(data.content && data.type) return data.content;
2778 return null;
2779}
2780
2781function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2782
2783/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2784/* OASIS does not comment on filename case sensitivity */
2785function safegetzipfile(zip, file) {
2786 var k = zip.FullPaths || keys(zip.files);
2787 var f = file.toLowerCase(), g = f.replace(/\\/g,'\/');
2788 for(var i=0; i<k.length; ++i) {
2789 var n = k[i].replace(/^Root Entry[\/]/,"").toLowerCase();
2790 if(f == n || g == n) return zip.FileIndex[i];
2791 }
2792 return null;
2793}
2794
2795function getzipfile(zip, file) {
2796 var o = safegetzipfile(zip, file);
2797 if(o == null) throw new Error("Cannot find file " + file + " in zip");
2798 return o;
2799}
2800
2801function getzipdata(zip, file, safe) {
2802 if(!safe) return getdata(getzipfile(zip, file));
2803 if(!file) return null;
2804 try { return getzipdata(zip, file); } catch(e) { return null; }
2805}
2806
2807function getzipstr(zip, file, safe) {
2808 if(!safe) return getdatastr(getzipfile(zip, file));
2809 if(!file) return null;
2810 try { return getzipstr(zip, file); } catch(e) { return null; }
2811}
2812
2813function zipentries(zip) {
2814 var k = zip.FullPaths || keys(zip.files), o = [];
2815 for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i].replace(/^Root Entry[\/]/, ""));
2816 return o.sort();
2817}
2818
2819function zip_add_file(zip, path, content) {
2820 if(zip.FullPaths) CFB.utils.cfb_add(zip, path, typeof content == "string" ? (has_buf ? Buffer_from(content) : s2a(utf8write(content))) : content);
2821 else zip.file(path, content);
2822}
2823
2824
2825function zip_new() {
2826 return CFB.utils.cfb_new();
2827}
2828
2829function zip_read(d, o) {
2830 var zip;
2831 switch(o.type) {
2832 case "base64": zip = CFB.read(d, { type: "base64" }); break;
2833 case "binary": zip = CFB.read(d, { type: "binary" }); break;
2834 case "buffer": case "array": zip = CFB.read(d, { type: "buffer" }); break;
2835 default: throw new Error("Unrecognized type " + o.type);
2836 }
2837 return zip;
2838}
2839
2840function resolve_path(path, base) {
2841 if(path.charAt(0) == "/") return path.slice(1);
2842 var result = base.split('/');
2843 if(base.slice(-1) != "/") result.pop(); // folder path
2844 var target = path.split('/');
2845 while (target.length !== 0) {
2846 var step = target.shift();
2847 if (step === '..') result.pop();
2848 else if (step !== '.') result.push(step);
2849 }
2850 return result.join('/');
2851}
2852var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2853var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2854var tagregex=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s?[\/\?]?>/g;
2855
2856if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2857var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2858function parsexmltag(tag, skip_root, skip_LC) {
2859 var z = ({});
2860 var eq = 0, c = 0;
2861 for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2862 if(!skip_root) z[0] = tag.slice(0, eq);
2863 if(eq === tag.length) return z;
2864 var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2865 if(m) for(i = 0; i != m.length; ++i) {
2866 cc = m[i];
2867 for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2868 q = cc.slice(0,c).trim();
2869 while(cc.charCodeAt(c+1) == 32) ++c;
2870 quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2871 v = cc.slice(c+1+quot, cc.length-quot);
2872 for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2873 if(j===q.length) {
2874 if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2875 z[q] = v;
2876 if(!skip_LC) z[q.toLowerCase()] = v;
2877 }
2878 else {
2879 var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2880 if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2881 z[k] = v;
2882 if(!skip_LC) z[k.toLowerCase()] = v;
2883 }
2884 }
2885 return z;
2886}
2887function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
2888
2889var encodings = {
2890 '&quot;': '"',
2891 '&apos;': "'",
2892 '&gt;': '>',
2893 '&lt;': '<',
2894 '&amp;': '&'
2895};
2896var rencoding = evert(encodings);
2897//var rencstr = "&<>'\"".split("");
2898
2899// TODO: CP remap (need to read file version to determine OS)
2900var unescapexml = (function() {
2901 /* 22.4.2.4 bstr (Basic String) */
2902 var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/g, coderegex = /_x([\da-fA-F]{4})_/g;
2903 return function unescapexml(text) {
2904 var s = text + '', i = s.indexOf("<![CDATA[");
2905 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));});
2906 var j = s.indexOf("]]>");
2907 return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
2908 };
2909})();
2910
2911var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
2912function escapexml(text){
2913 var s = text + '';
2914 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
2915}
2916function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
2917
2918var htmlcharegex = /[\u0000-\u001f]/g;
2919function escapehtml(text){
2920 var s = text + '';
2921 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) + ";"; });
2922}
2923
2924function escapexlml(text){
2925 var s = text + '';
2926 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
2927}
2928
2929/* TODO: handle codepages */
2930var xlml_fixstr = (function() {
2931 var entregex = /&#(\d+);/g;
2932 function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
2933 return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
2934})();
2935var xlml_unfixstr = (function() {
2936 return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
2937})();
2938
2939function parsexmlbool(value) {
2940 switch(value) {
2941 case 1: case true: case '1': case 'true': case 'TRUE': return true;
2942 /* case '0': case 'false': case 'FALSE':*/
2943 default: return false;
2944 }
2945}
2946
2947var utf8read = function utf8reada(orig) {
2948 var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
2949 while (i < orig.length) {
2950 c = orig.charCodeAt(i++);
2951 if (c < 128) { out += String.fromCharCode(c); continue; }
2952 d = orig.charCodeAt(i++);
2953 if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
2954 e = orig.charCodeAt(i++);
2955 if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
2956 f = orig.charCodeAt(i++);
2957 w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
2958 out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
2959 out += String.fromCharCode(0xDC00 + (w&1023));
2960 }
2961 return out;
2962};
2963
2964var utf8write = function(orig) {
2965 var out = [], i = 0, c = 0, d = 0;
2966 while(i < orig.length) {
2967 c = orig.charCodeAt(i++);
2968 switch(true) {
2969 case c < 128: out.push(String.fromCharCode(c)); break;
2970 case c < 2048:
2971 out.push(String.fromCharCode(192 + (c >> 6)));
2972 out.push(String.fromCharCode(128 + (c & 63)));
2973 break;
2974 case c >= 55296 && c < 57344:
2975 c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
2976 out.push(String.fromCharCode(240 + ((d >>18) & 7)));
2977 out.push(String.fromCharCode(144 + ((d >>12) & 63)));
2978 out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
2979 out.push(String.fromCharCode(128 + (d & 63)));
2980 break;
2981 default:
2982 out.push(String.fromCharCode(224 + (c >> 12)));
2983 out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
2984 out.push(String.fromCharCode(128 + (c & 63)));
2985 }
2986 }
2987 return out.join("");
2988};
2989
2990if(has_buf) {
2991 var utf8readb = function utf8readb(data) {
2992 var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
2993 for(i = 0; i < data.length; i+=j) {
2994 j = 1;
2995 if((c=data.charCodeAt(i)) < 128) w = c;
2996 else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
2997 else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
2998 else { j = 4;
2999 w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
3000 w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
3001 }
3002 if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
3003 out[k++] = w%256; out[k++] = w>>>8;
3004 }
3005 return out.slice(0,k).toString('ucs2');
3006 };
3007 var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
3008 if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
3009 var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
3010 if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
3011
3012 utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
3013}
3014
3015// matches <foo>...</foo> extracts content
3016var matchtag = (function() {
3017 var mtcache = ({});
3018 return function matchtag(f,g) {
3019 var t = f+"|"+(g||"");
3020 if(mtcache[t]) return mtcache[t];
3021 return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
3022 };
3023})();
3024
3025var htmldecode = (function() {
3026 var entities = [
3027 ['nbsp', ' '], ['middot', '·'],
3028 ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
3029 ].map(function(x) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; });
3030 return function htmldecode(str) {
3031 var o = str
3032 // Remove new lines and spaces from start of content
3033 .replace(/^[\t\n\r ]+/, "")
3034 // Remove new lines and spaces from end of content
3035 .replace(/[\t\n\r ]+$/,"")
3036 // Added line which removes any white space characters after and before html tags
3037 .replace(/>\s+/g,">").replace(/\s+</g,"<")
3038 // Replace remaining new lines and spaces with space
3039 .replace(/[\t\n\r ]+/g, " ")
3040 // Replace <br> tags with new lines
3041 .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
3042 // Strip HTML elements
3043 .replace(/<[^>]*>/g,"");
3044 for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
3045 return o;
3046 };
3047})();
3048
3049var vtregex = (function(){ var vt_cache = {};
3050 return function vt_regex(bt) {
3051 if(vt_cache[bt] !== undefined) return vt_cache[bt];
3052 return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
3053};})();
3054var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
3055function parseVector(data, opts) {
3056 var h = parsexmltag(data);
3057
3058 var matches = data.match(vtregex(h.baseType))||[];
3059 var res = [];
3060 if(matches.length != h.size) {
3061 if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
3062 return res;
3063 }
3064 matches.forEach(function(x) {
3065 var v = x.replace(vtvregex,"").match(vtmregex);
3066 if(v) res.push({v:utf8read(v[2]), t:v[1]});
3067 });
3068 return res;
3069}
3070
3071var wtregex = /(^\s|\s$|\n)/;
3072function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
3073
3074function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
3075function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
3076
3077function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
3078
3079function write_vt(s) {
3080 switch(typeof s) {
3081 case 'string': return writextag('vt:lpwstr', s);
3082 case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', String(s));
3083 case 'boolean': return writextag('vt:bool',s?'true':'false');
3084 }
3085 if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
3086 throw new Error("Unable to serialize " + s);
3087}
3088
3089var XMLNS = ({
3090 'dc': 'http://purl.org/dc/elements/1.1/',
3091 'dcterms': 'http://purl.org/dc/terms/',
3092 'dcmitype': 'http://purl.org/dc/dcmitype/',
3093 'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
3094 'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
3095 'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
3096 'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
3097 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
3098 'xsd': 'http://www.w3.org/2001/XMLSchema'
3099});
3100
3101XMLNS.main = [
3102 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
3103 'http://purl.oclc.org/ooxml/spreadsheetml/main',
3104 'http://schemas.microsoft.com/office/excel/2006/main',
3105 'http://schemas.microsoft.com/office/excel/2006/2'
3106];
3107
3108var XLMLNS = ({
3109 'o': 'urn:schemas-microsoft-com:office:office',
3110 'x': 'urn:schemas-microsoft-com:office:excel',
3111 'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
3112 'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
3113 'mv': 'http://macVmlSchemaUri',
3114 'v': 'urn:schemas-microsoft-com:vml',
3115 'html': 'http://www.w3.org/TR/REC-html40'
3116});
3117function read_double_le(b, idx) {
3118 var s = 1 - 2 * (b[idx + 7] >>> 7);
3119 var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
3120 var m = (b[idx+6]&0x0f);
3121 for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
3122 if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
3123 if(e == 0) e = -1022;
3124 else { e -= 1023; m += Math.pow(2,52); }
3125 return s * Math.pow(2, e - 52) * m;
3126}
3127
3128function write_double_le(b, v, idx) {
3129 var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
3130 var av = bs ? (-v) : v;
3131 if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
3132 else if(av == 0) e = m = 0;
3133 else {
3134 e = Math.floor(Math.log(av) / Math.LN2);
3135 m = av * Math.pow(2, 52 - e);
3136 if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
3137 else { m -= Math.pow(2,52); e+=1023; }
3138 }
3139 for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
3140 b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
3141 b[idx + 7] = (e >> 4) | bs;
3142}
3143
3144var __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; };
3145var ___toBuffer = __toBuffer;
3146var __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,''); };
3147var ___utf16le = __utf16le;
3148var __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(""); };
3149var ___hexlify = __hexlify;
3150var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
3151var ___utf8 = __utf8;
3152var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3153var ___lpstr = __lpstr;
3154var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3155var ___cpstr = __cpstr;
3156var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3157var ___lpwstr = __lpwstr;
3158var __lpp4, ___lpp4;
3159__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
3160var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
3161var ___8lpp4 = __8lpp4;
3162var __double, ___double;
3163__double = ___double = function(b, idx) { return read_double_le(b, idx);};
3164var is_buf = function is_buf_a(a) { return Array.isArray(a); };
3165
3166if(has_buf) {
3167 __utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
3168 __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
3169 __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) : "";};
3170 __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) : "";};
3171 __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);};
3172 __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);};
3173 __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);};
3174 __utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
3175 __toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
3176 bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
3177 __double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
3178 is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
3179}
3180
3181/* from js-xls */
3182if(typeof cptable !== 'undefined') {
3183 __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
3184 __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
3185 __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)) : "";};
3186 __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)) : "";};
3187 __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)) : "";};
3188 __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
3189 __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
3190}
3191
3192var __readUInt8 = function(b, idx) { return b[idx]; };
3193var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
3194var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
3195var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
3196var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
3197var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
3198
3199function ReadShift(size, t) {
3200 var o="", oI, oR, oo=[], w, vv, i, loc;
3201 switch(t) {
3202 case 'dbcs':
3203 loc = this.l;
3204 if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
3205 else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
3206 size *= 2;
3207 break;
3208
3209 case 'utf8': o = __utf8(this, this.l, this.l + size); break;
3210 case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
3211
3212 case 'wstr':
3213 if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
3214 else return ReadShift.call(this, size, 'dbcs');
3215 size = 2 * size; break;
3216
3217 /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
3218 case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3219 case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3220 /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
3221 case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
3222 /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
3223 case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
3224 /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
3225 case '8lpp4': size = 4 + __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
3226
3227 case 'cstr': size = 0; o = "";
3228 while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
3229 o = oo.join(""); break;
3230 case '_wstr': size = 0; o = "";
3231 while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
3232 size+=2; o = oo.join(""); break;
3233
3234 /* sbcs and dbcs support continue records in the SST way TODO codepages */
3235 case 'dbcs-cont': o = ""; loc = this.l;
3236 for(i = 0; i < size; ++i) {
3237 if(this.lens && this.lens.indexOf(loc) !== -1) {
3238 w = __readUInt8(this, loc);
3239 this.l = loc + 1;
3240 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3241 return oo.join("") + vv;
3242 }
3243 oo.push(_getchar(__readUInt16LE(this, loc)));
3244 loc+=2;
3245 } o = oo.join(""); size *= 2; break;
3246
3247 case 'cpstr':
3248 if(typeof cptable !== 'undefined') {
3249 o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
3250 break;
3251 }
3252 /* falls through */
3253 case 'sbcs-cont': o = ""; loc = this.l;
3254 for(i = 0; i != size; ++i) {
3255 if(this.lens && this.lens.indexOf(loc) !== -1) {
3256 w = __readUInt8(this, loc);
3257 this.l = loc + 1;
3258 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3259 return oo.join("") + vv;
3260 }
3261 oo.push(_getchar(__readUInt8(this, loc)));
3262 loc+=1;
3263 } o = oo.join(""); break;
3264
3265 default:
3266 switch(size) {
3267 case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
3268 case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
3269 case 4: case -4:
3270 if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
3271 else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
3272 case 8: case -8:
3273 if(t === 'f') {
3274 if(size == 8) oR = __double(this, this.l);
3275 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);
3276 this.l += 8; return oR;
3277 } else size = 8;
3278 /* falls through */
3279 case 16: o = __hexlify(this, this.l, size); break;
3280 }}
3281 this.l+=size; return o;
3282}
3283
3284var __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); };
3285var __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); };
3286var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
3287
3288function WriteShift(t, val, f) {
3289 var size = 0, i = 0;
3290 if(f === 'dbcs') {
3291for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
3292 size = 2 * val.length;
3293 } else if(f === 'sbcs') {
3294 if(typeof cptable !== 'undefined' && current_ansi == 874) {
3295 /* TODO: use tables directly, don't encode */
3296for(i = 0; i != val.length; ++i) {
3297 var cppayload = cptable.utils.encode(current_ansi, val.charAt(i));
3298 this[this.l + i] = cppayload[0];
3299 }
3300 } else {
3301val = val.replace(/[^\x00-\x7F]/g, "_");
3302for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
3303 }
3304 size = val.length;
3305 } else if(f === 'hex') {
3306 for(; i < t; ++i) {
3307this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
3308 } return this;
3309 } else if(f === 'utf16le') {
3310var end = Math.min(this.l + t, this.length);
3311 for(i = 0; i < Math.min(val.length, t); ++i) {
3312 var cc = val.charCodeAt(i);
3313 this[this.l++] = (cc & 0xff);
3314 this[this.l++] = (cc >> 8);
3315 }
3316 while(this.l < end) this[this.l++] = 0;
3317 return this;
3318 } else switch(t) {
3319 case 1: size = 1; this[this.l] = val&0xFF; break;
3320 case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
3321 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;
3322 case 4: size = 4; __writeUInt32LE(this, val, this.l); break;
3323 case 8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
3324 /* falls through */
3325 case 16: break;
3326 case -4: size = 4; __writeInt32LE(this, val, this.l); break;
3327 }
3328 this.l += size; return this;
3329}
3330
3331function CheckField(hexstr, fld) {
3332 var m = __hexlify(this,this.l,hexstr.length>>1);
3333 if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
3334 this.l += hexstr.length>>1;
3335}
3336
3337function prep_blob(blob, pos) {
3338 blob.l = pos;
3339 blob.read_shift = ReadShift;
3340 blob.chk = CheckField;
3341 blob.write_shift = WriteShift;
3342}
3343
3344function parsenoop(blob, length) { blob.l += length; }
3345
3346function new_buf(sz) {
3347 var o = new_raw_buf(sz);
3348 prep_blob(o, 0);
3349 return o;
3350}
3351
3352/* [MS-XLSB] 2.1.4 Record */
3353function recordhopper(data, cb, opts) {
3354 if(!data) return;
3355 var tmpbyte, cntbyte, length;
3356 prep_blob(data, data.l || 0);
3357 var L = data.length, RT = 0, tgt = 0;
3358 while(data.l < L) {
3359 RT = data.read_shift(1);
3360 if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
3361 var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
3362 tmpbyte = data.read_shift(1);
3363 length = tmpbyte & 0x7F;
3364 for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
3365 tgt = data.l + length;
3366 var d = (R.f||parsenoop)(data, length, opts);
3367 data.l = tgt;
3368 if(cb(d, R.n, RT)) return;
3369 }
3370}
3371
3372/* control buffer usage for fixed-length buffers */
3373function buf_array() {
3374 var bufs = [], blksz = has_buf ? 256 : 2048;
3375 var newblk = function ba_newblk(sz) {
3376 var o = (new_buf(sz));
3377 prep_blob(o, 0);
3378 return o;
3379 };
3380
3381 var curbuf = newblk(blksz);
3382
3383 var endbuf = function ba_endbuf() {
3384 if(!curbuf) return;
3385 if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3386 if(curbuf.length > 0) bufs.push(curbuf);
3387 curbuf = null;
3388 };
3389
3390 var next = function ba_next(sz) {
3391 if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
3392 endbuf();
3393 return (curbuf = newblk(Math.max(sz+1, blksz)));
3394 };
3395
3396 var end = function ba_end() {
3397 endbuf();
3398 return __toBuffer([bufs]);
3399 };
3400
3401 var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
3402
3403 return ({ next:next, push:push, end:end, _bufs:bufs });
3404}
3405
3406function write_record(ba, type, payload, length) {
3407 var t = +XLSBRE[type], l;
3408 if(isNaN(t)) return; // TODO: throw something here?
3409 if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
3410 l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
3411 if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
3412 var o = ba.next(l);
3413 if(t <= 0x7F) o.write_shift(1, t);
3414 else {
3415 o.write_shift(1, (t & 0x7F) + 0x80);
3416 o.write_shift(1, (t >> 7));
3417 }
3418 for(var i = 0; i != 4; ++i) {
3419 if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
3420 else { o.write_shift(1, length); break; }
3421 }
3422 if(length > 0 && is_buf(payload)) ba.push(payload);
3423}
3424/* XLS ranges enforced */
3425function shift_cell_xls(cell, tgt, opts) {
3426 var out = dup(cell);
3427 if(tgt.s) {
3428 if(out.cRel) out.c += tgt.s.c;
3429 if(out.rRel) out.r += tgt.s.r;
3430 } else {
3431 if(out.cRel) out.c += tgt.c;
3432 if(out.rRel) out.r += tgt.r;
3433 }
3434 if(!opts || opts.biff < 12) {
3435 while(out.c >= 0x100) out.c -= 0x100;
3436 while(out.r >= 0x10000) out.r -= 0x10000;
3437 }
3438 return out;
3439}
3440
3441function shift_range_xls(cell, range, opts) {
3442 var out = dup(cell);
3443 out.s = shift_cell_xls(out.s, range.s, opts);
3444 out.e = shift_cell_xls(out.e, range.s, opts);
3445 return out;
3446}
3447
3448function encode_cell_xls(c, biff) {
3449 if(c.cRel && c.c < 0) { c = dup(c); while(c.c < 0) c.c += (biff > 8) ? 0x4000 : 0x100; }
3450 if(c.rRel && c.r < 0) { c = dup(c); while(c.r < 0) c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
3451 var s = encode_cell(c);
3452 if(!c.cRel && c.cRel != null) s = fix_col(s);
3453 if(!c.rRel && c.rRel != null) s = fix_row(s);
3454 return s;
3455}
3456
3457function encode_range_xls(r, opts) {
3458 if(r.s.r == 0 && !r.s.rRel) {
3459 if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
3460 return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
3461 }
3462 }
3463 if(r.s.c == 0 && !r.s.cRel) {
3464 if(r.e.c == (opts.biff >= 12 ? 0xFFFF : 0xFF) && !r.e.cRel) {
3465 return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
3466 }
3467 }
3468 return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
3469}
3470function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
3471function encode_row(row) { return "" + (row + 1); }
3472function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
3473function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
3474
3475function 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; }
3476function 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; }
3477function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
3478function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
3479
3480function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
3481function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
3482function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
3483function decode_range(range) { var x =range.split(":").map(decode_cell); return {s:x[0],e:x[x.length-1]}; }
3484function encode_range(cs,ce) {
3485 if(typeof ce === 'undefined' || typeof ce === 'number') {
3486return encode_range(cs.s, cs.e);
3487 }
3488if(typeof cs !== 'string') cs = encode_cell((cs));
3489 if(typeof ce !== 'string') ce = encode_cell((ce));
3490return cs == ce ? cs : cs + ":" + ce;
3491}
3492
3493function safe_decode_range(range) {
3494 var o = {s:{c:0,r:0},e:{c:0,r:0}};
3495 var idx = 0, i = 0, cc = 0;
3496 var len = range.length;
3497 for(idx = 0; i < len; ++i) {
3498 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3499 idx = 26*idx + cc;
3500 }
3501 o.s.c = --idx;
3502
3503 for(idx = 0; i < len; ++i) {
3504 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3505 idx = 10*idx + cc;
3506 }
3507 o.s.r = --idx;
3508
3509 if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
3510
3511 for(idx = 0; i != len; ++i) {
3512 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3513 idx = 26*idx + cc;
3514 }
3515 o.e.c = --idx;
3516
3517 for(idx = 0; i != len; ++i) {
3518 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3519 idx = 10*idx + cc;
3520 }
3521 o.e.r = --idx;
3522 return o;
3523}
3524
3525function safe_format_cell(cell, v) {
3526 var q = (cell.t == 'd' && v instanceof Date);
3527 if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
3528 try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
3529}
3530
3531function format_cell(cell, v, o) {
3532 if(cell == null || cell.t == null || cell.t == 'z') return "";
3533 if(cell.w !== undefined) return cell.w;
3534 if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
3535 if(v == undefined) return safe_format_cell(cell, cell.v);
3536 return safe_format_cell(cell, v);
3537}
3538
3539function sheet_to_workbook(sheet, opts) {
3540 var n = opts && opts.sheet ? opts.sheet : "Sheet1";
3541 var sheets = {}; sheets[n] = sheet;
3542 return { SheetNames: [n], Sheets: sheets };
3543}
3544
3545function sheet_add_aoa(_ws, data, opts) {
3546 var o = opts || {};
3547 var dense = _ws ? Array.isArray(_ws) : o.dense;
3548 if(DENSE != null && dense == null) dense = DENSE;
3549 var ws = _ws || (dense ? ([]) : ({}));
3550 var _R = 0, _C = 0;
3551 if(ws && o.origin != null) {
3552 if(typeof o.origin == 'number') _R = o.origin;
3553 else {
3554 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
3555 _R = _origin.r; _C = _origin.c;
3556 }
3557 }
3558 var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
3559 if(ws['!ref']) {
3560 var _range = safe_decode_range(ws['!ref']);
3561 range.s.c = _range.s.c;
3562 range.s.r = _range.s.r;
3563 range.e.c = Math.max(range.e.c, _range.e.c);
3564 range.e.r = Math.max(range.e.r, _range.e.r);
3565 if(_R == -1) range.e.r = _R = _range.e.r + 1;
3566 }
3567 for(var R = 0; R != data.length; ++R) {
3568 if(!data[R]) continue;
3569 if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
3570 for(var C = 0; C != data[R].length; ++C) {
3571 if(typeof data[R][C] === 'undefined') continue;
3572 var cell = ({v: data[R][C] });
3573 var __R = _R + R, __C = _C + C;
3574 if(range.s.r > __R) range.s.r = __R;
3575 if(range.s.c > __C) range.s.c = __C;
3576 if(range.e.r < __R) range.e.r = __R;
3577 if(range.e.c < __C) range.e.c = __C;
3578 if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
3579 else {
3580 if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
3581 if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.sheetStubs) continue; else cell.t = 'z'; }
3582 else if(typeof cell.v === 'number') cell.t = 'n';
3583 else if(typeof cell.v === 'boolean') cell.t = 'b';
3584 else if(cell.v instanceof Date) {
3585 cell.z = o.dateNF || SSF._table[14];
3586 if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
3587 else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
3588 }
3589 else cell.t = 's';
3590 }
3591 if(dense) {
3592 if(!ws[__R]) ws[__R] = [];
3593 ws[__R][__C] = cell;
3594 } else {
3595 var cell_ref = encode_cell(({c:__C,r:__R}));
3596 ws[cell_ref] = cell;
3597 }
3598 }
3599 }
3600 if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
3601 return ws;
3602}
3603function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
3604
3605/* [MS-OLEPS] 2.2 PropertyType */
3606//var VT_EMPTY = 0x0000;
3607//var VT_NULL = 0x0001;
3608var VT_I2 = 0x0002;
3609var VT_I4 = 0x0003;
3610//var VT_R4 = 0x0004;
3611//var VT_R8 = 0x0005;
3612//var VT_CY = 0x0006;
3613//var VT_DATE = 0x0007;
3614//var VT_BSTR = 0x0008;
3615//var VT_ERROR = 0x000A;
3616var VT_BOOL = 0x000B;
3617var VT_VARIANT = 0x000C;
3618//var VT_DECIMAL = 0x000E;
3619//var VT_I1 = 0x0010;
3620//var VT_UI1 = 0x0011;
3621//var VT_UI2 = 0x0012;
3622var VT_UI4 = 0x0013;
3623//var VT_I8 = 0x0014;
3624//var VT_UI8 = 0x0015;
3625//var VT_INT = 0x0016;
3626//var VT_UINT = 0x0017;
3627var VT_LPSTR = 0x001E;
3628//var VT_LPWSTR = 0x001F;
3629var VT_FILETIME = 0x0040;
3630var VT_BLOB = 0x0041;
3631//var VT_STREAM = 0x0042;
3632//var VT_STORAGE = 0x0043;
3633//var VT_STREAMED_Object = 0x0044;
3634//var VT_STORED_Object = 0x0045;
3635//var VT_BLOB_Object = 0x0046;
3636var VT_CF = 0x0047;
3637//var VT_CLSID = 0x0048;
3638//var VT_VERSIONED_STREAM = 0x0049;
3639var VT_VECTOR = 0x1000;
3640//var VT_ARRAY = 0x2000;
3641
3642var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
3643var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
3644var VT_CUSTOM = [VT_STRING, VT_USTR];
3645
3646/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
3647var DocSummaryPIDDSI = {
36480x01: { n: 'CodePage', t: VT_I2 },
36490x02: { n: 'Category', t: VT_STRING },
36500x03: { n: 'PresentationFormat', t: VT_STRING },
36510x04: { n: 'ByteCount', t: VT_I4 },
36520x05: { n: 'LineCount', t: VT_I4 },
36530x06: { n: 'ParagraphCount', t: VT_I4 },
36540x07: { n: 'SlideCount', t: VT_I4 },
36550x08: { n: 'NoteCount', t: VT_I4 },
36560x09: { n: 'HiddenCount', t: VT_I4 },
36570x0a: { n: 'MultimediaClipCount', t: VT_I4 },
36580x0b: { n: 'ScaleCrop', t: VT_BOOL },
36590x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
36600x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
36610x0e: { n: 'Manager', t: VT_STRING },
36620x0f: { n: 'Company', t: VT_STRING },
36630x10: { n: 'LinksUpToDate', t: VT_BOOL },
36640x11: { n: 'CharacterCount', t: VT_I4 },
36650x13: { n: 'SharedDoc', t: VT_BOOL },
36660x16: { n: 'HyperlinksChanged', t: VT_BOOL },
36670x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
36680x18: { n: 'DigSig', t: VT_BLOB },
36690x1A: { n: 'ContentType', t: VT_STRING },
36700x1B: { n: 'ContentStatus', t: VT_STRING },
36710x1C: { n: 'Language', t: VT_STRING },
36720x1D: { n: 'Version', t: VT_STRING },
36730xFF: {}
3674};
3675
3676/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
3677var SummaryPIDSI = {
36780x01: { n: 'CodePage', t: VT_I2 },
36790x02: { n: 'Title', t: VT_STRING },
36800x03: { n: 'Subject', t: VT_STRING },
36810x04: { n: 'Author', t: VT_STRING },
36820x05: { n: 'Keywords', t: VT_STRING },
36830x06: { n: 'Comments', t: VT_STRING },
36840x07: { n: 'Template', t: VT_STRING },
36850x08: { n: 'LastAuthor', t: VT_STRING },
36860x09: { n: 'RevNumber', t: VT_STRING },
36870x0A: { n: 'EditTime', t: VT_FILETIME },
36880x0B: { n: 'LastPrinted', t: VT_FILETIME },
36890x0C: { n: 'CreatedDate', t: VT_FILETIME },
36900x0D: { n: 'ModifiedDate', t: VT_FILETIME },
36910x0E: { n: 'PageCount', t: VT_I4 },
36920x0F: { n: 'WordCount', t: VT_I4 },
36930x10: { n: 'CharCount', t: VT_I4 },
36940x11: { n: 'Thumbnail', t: VT_CF },
36950x12: { n: 'Application', t: VT_STRING },
36960x13: { n: 'DocSecurity', t: VT_I4 },
36970xFF: {}
3698};
3699
3700/* [MS-OLEPS] 2.18 */
3701var SpecialProperties = {
37020x80000000: { n: 'Locale', t: VT_UI4 },
37030x80000003: { n: 'Behavior', t: VT_UI4 },
37040x72627262: {}
3705};
3706
3707(function() {
3708 for(var y in SpecialProperties) if(SpecialProperties.hasOwnProperty(y))
3709 DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
3710})();
3711
3712var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
3713var SummaryRE = evert_key(SummaryPIDSI, "n");
3714
3715/* [MS-XLS] 2.4.63 Country/Region codes */
3716var CountryEnum = {
37170x0001: "US", // United States
37180x0002: "CA", // Canada
37190x0003: "", // Latin America (except Brazil)
37200x0007: "RU", // Russia
37210x0014: "EG", // Egypt
37220x001E: "GR", // Greece
37230x001F: "NL", // Netherlands
37240x0020: "BE", // Belgium
37250x0021: "FR", // France
37260x0022: "ES", // Spain
37270x0024: "HU", // Hungary
37280x0027: "IT", // Italy
37290x0029: "CH", // Switzerland
37300x002B: "AT", // Austria
37310x002C: "GB", // United Kingdom
37320x002D: "DK", // Denmark
37330x002E: "SE", // Sweden
37340x002F: "NO", // Norway
37350x0030: "PL", // Poland
37360x0031: "DE", // Germany
37370x0034: "MX", // Mexico
37380x0037: "BR", // Brazil
37390x003d: "AU", // Australia
37400x0040: "NZ", // New Zealand
37410x0042: "TH", // Thailand
37420x0051: "JP", // Japan
37430x0052: "KR", // Korea
37440x0054: "VN", // Viet Nam
37450x0056: "CN", // China
37460x005A: "TR", // Turkey
37470x0069: "JS", // Ramastan
37480x00D5: "DZ", // Algeria
37490x00D8: "MA", // Morocco
37500x00DA: "LY", // Libya
37510x015F: "PT", // Portugal
37520x0162: "IS", // Iceland
37530x0166: "FI", // Finland
37540x01A4: "CZ", // Czech Republic
37550x0376: "TW", // Taiwan
37560x03C1: "LB", // Lebanon
37570x03C2: "JO", // Jordan
37580x03C3: "SY", // Syria
37590x03C4: "IQ", // Iraq
37600x03C5: "KW", // Kuwait
37610x03C6: "SA", // Saudi Arabia
37620x03CB: "AE", // United Arab Emirates
37630x03CC: "IL", // Israel
37640x03CE: "QA", // Qatar
37650x03D5: "IR", // Iran
37660xFFFF: "US" // United States
3767};
3768
3769/* [MS-XLS] 2.5.127 */
3770var XLSFillPattern = [
3771 null,
3772 'solid',
3773 'mediumGray',
3774 'darkGray',
3775 'lightGray',
3776 'darkHorizontal',
3777 'darkVertical',
3778 'darkDown',
3779 'darkUp',
3780 'darkGrid',
3781 'darkTrellis',
3782 'lightHorizontal',
3783 'lightVertical',
3784 'lightDown',
3785 'lightUp',
3786 'lightGrid',
3787 'lightTrellis',
3788 'gray125',
3789 'gray0625'
3790];
3791
3792function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
3793
3794/* [MS-XLS] 2.5.161 */
3795/* [MS-XLSB] 2.5.75 Icv */
3796var _XLSIcv = rgbify([
3797 /* Color Constants */
3798 0x000000,
3799 0xFFFFFF,
3800 0xFF0000,
3801 0x00FF00,
3802 0x0000FF,
3803 0xFFFF00,
3804 0xFF00FF,
3805 0x00FFFF,
3806
3807 /* Overridable Defaults */
3808 0x000000,
3809 0xFFFFFF,
3810 0xFF0000,
3811 0x00FF00,
3812 0x0000FF,
3813 0xFFFF00,
3814 0xFF00FF,
3815 0x00FFFF,
3816
3817 0x800000,
3818 0x008000,
3819 0x000080,
3820 0x808000,
3821 0x800080,
3822 0x008080,
3823 0xC0C0C0,
3824 0x808080,
3825 0x9999FF,
3826 0x993366,
3827 0xFFFFCC,
3828 0xCCFFFF,
3829 0x660066,
3830 0xFF8080,
3831 0x0066CC,
3832 0xCCCCFF,
3833
3834 0x000080,
3835 0xFF00FF,
3836 0xFFFF00,
3837 0x00FFFF,
3838 0x800080,
3839 0x800000,
3840 0x008080,
3841 0x0000FF,
3842 0x00CCFF,
3843 0xCCFFFF,
3844 0xCCFFCC,
3845 0xFFFF99,
3846 0x99CCFF,
3847 0xFF99CC,
3848 0xCC99FF,
3849 0xFFCC99,
3850
3851 0x3366FF,
3852 0x33CCCC,
3853 0x99CC00,
3854 0xFFCC00,
3855 0xFF9900,
3856 0xFF6600,
3857 0x666699,
3858 0x969696,
3859 0x003366,
3860 0x339966,
3861 0x003300,
3862 0x333300,
3863 0x993300,
3864 0x993366,
3865 0x333399,
3866 0x333333,
3867
3868 /* Other entries to appease BIFF8/12 */
3869 0xFFFFFF, /* 0x40 icvForeground ?? */
3870 0x000000, /* 0x41 icvBackground ?? */
3871 0x000000, /* 0x42 icvFrame ?? */
3872 0x000000, /* 0x43 icv3D ?? */
3873 0x000000, /* 0x44 icv3DText ?? */
3874 0x000000, /* 0x45 icv3DHilite ?? */
3875 0x000000, /* 0x46 icv3DShadow ?? */
3876 0x000000, /* 0x47 icvHilite ?? */
3877 0x000000, /* 0x48 icvCtlText ?? */
3878 0x000000, /* 0x49 icvCtlScrl ?? */
3879 0x000000, /* 0x4A icvCtlInv ?? */
3880 0x000000, /* 0x4B icvCtlBody ?? */
3881 0x000000, /* 0x4C icvCtlFrame ?? */
3882 0x000000, /* 0x4D icvCtlFore ?? */
3883 0x000000, /* 0x4E icvCtlBack ?? */
3884 0x000000, /* 0x4F icvCtlNeutral */
3885 0x000000, /* 0x50 icvInfoBk ?? */
3886 0x000000 /* 0x51 icvInfoText ?? */
3887]);
3888var XLSIcv = dup(_XLSIcv);
3889/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
3890/* 12.3 Part Summary <SpreadsheetML> */
3891/* 14.2 Part Summary <DrawingML> */
3892/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
3893var ct2type/*{[string]:string}*/ = ({
3894 /* Workbook */
3895 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
3896
3897 /* Worksheet */
3898 "application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
3899
3900 /* Macrosheet */
3901 "application/vnd.ms-excel.intlmacrosheet": "TODO",
3902 "application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
3903
3904 /* File Properties */
3905 "application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
3906 "application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
3907 "application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
3908
3909 /* Custom Data Properties */
3910 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
3911 "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
3912
3913 /* PivotTable */
3914 "application/vnd.ms-excel.pivotTable": "TODO",
3915 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
3916
3917 /* Chart Objects */
3918 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
3919
3920 /* Chart Colors */
3921 "application/vnd.ms-office.chartcolorstyle+xml": "TODO",
3922
3923 /* Chart Style */
3924 "application/vnd.ms-office.chartstyle+xml": "TODO",
3925
3926 /* Chart Advanced */
3927 "application/vnd.ms-office.chartex+xml": "TODO",
3928
3929 /* Calculation Chain */
3930 "application/vnd.ms-excel.calcChain": "calcchains",
3931 "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
3932
3933 /* Printer Settings */
3934 "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
3935
3936 /* ActiveX */
3937 "application/vnd.ms-office.activeX": "TODO",
3938 "application/vnd.ms-office.activeX+xml": "TODO",
3939
3940 /* Custom Toolbars */
3941 "application/vnd.ms-excel.attachedToolbars": "TODO",
3942
3943 /* External Data Connections */
3944 "application/vnd.ms-excel.connections": "TODO",
3945 "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
3946
3947 /* External Links */
3948 "application/vnd.ms-excel.externalLink": "links",
3949 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
3950
3951 /* Metadata */
3952 "application/vnd.ms-excel.sheetMetadata": "TODO",
3953 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
3954
3955 /* PivotCache */
3956 "application/vnd.ms-excel.pivotCacheDefinition": "TODO",
3957 "application/vnd.ms-excel.pivotCacheRecords": "TODO",
3958 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
3959 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
3960
3961 /* Query Table */
3962 "application/vnd.ms-excel.queryTable": "TODO",
3963 "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
3964
3965 /* Shared Workbook */
3966 "application/vnd.ms-excel.userNames": "TODO",
3967 "application/vnd.ms-excel.revisionHeaders": "TODO",
3968 "application/vnd.ms-excel.revisionLog": "TODO",
3969 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
3970 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
3971 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
3972
3973 /* Single Cell Table */
3974 "application/vnd.ms-excel.tableSingleCells": "TODO",
3975 "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
3976
3977 /* Slicer */
3978 "application/vnd.ms-excel.slicer": "TODO",
3979 "application/vnd.ms-excel.slicerCache": "TODO",
3980 "application/vnd.ms-excel.slicer+xml": "TODO",
3981 "application/vnd.ms-excel.slicerCache+xml": "TODO",
3982
3983 /* Sort Map */
3984 "application/vnd.ms-excel.wsSortMap": "TODO",
3985
3986 /* Table */
3987 "application/vnd.ms-excel.table": "TODO",
3988 "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
3989
3990 /* Themes */
3991 "application/vnd.openxmlformats-officedocument.theme+xml": "themes",
3992
3993 /* Theme Override */
3994 "application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
3995
3996 /* Timeline */
3997 "application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
3998 "application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
3999
4000 /* VBA */
4001 "application/vnd.ms-office.vbaProject": "vba",
4002 "application/vnd.ms-office.vbaProjectSignature": "vba",
4003
4004 /* Volatile Dependencies */
4005 "application/vnd.ms-office.volatileDependencies": "TODO",
4006 "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
4007
4008 /* Control Properties */
4009 "application/vnd.ms-excel.controlproperties+xml": "TODO",
4010
4011 /* Data Model */
4012 "application/vnd.openxmlformats-officedocument.model+data": "TODO",
4013
4014 /* Survey */
4015 "application/vnd.ms-excel.Survey+xml": "TODO",
4016
4017 /* Drawing */
4018 "application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
4019 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
4020 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
4021 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
4022 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
4023 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
4024
4025 /* VML */
4026 "application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
4027
4028 "application/vnd.openxmlformats-package.relationships+xml": "rels",
4029 "application/vnd.openxmlformats-officedocument.oleObject": "TODO",
4030
4031 /* Image */
4032 "image/png": "TODO",
4033
4034 "sheet": "js"
4035});
4036
4037var CT_LIST = (function(){
4038 var o = {
4039 workbooks: {
4040 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
4041 xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
4042 xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
4043 xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
4044 xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
4045 },
4046 strs: { /* Shared Strings */
4047 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
4048 xlsb: "application/vnd.ms-excel.sharedStrings"
4049 },
4050 comments: { /* Comments */
4051 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
4052 xlsb: "application/vnd.ms-excel.comments"
4053 },
4054 sheets: { /* Worksheet */
4055 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
4056 xlsb: "application/vnd.ms-excel.worksheet"
4057 },
4058 charts: { /* Chartsheet */
4059 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
4060 xlsb: "application/vnd.ms-excel.chartsheet"
4061 },
4062 dialogs: { /* Dialogsheet */
4063 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
4064 xlsb: "application/vnd.ms-excel.dialogsheet"
4065 },
4066 macros: { /* Macrosheet (Excel 4.0 Macros) */
4067 xlsx: "application/vnd.ms-excel.macrosheet+xml",
4068 xlsb: "application/vnd.ms-excel.macrosheet"
4069 },
4070 styles: { /* Styles */
4071 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
4072 xlsb: "application/vnd.ms-excel.styles"
4073 }
4074 };
4075 keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
4076 keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
4077 return o;
4078})();
4079
4080var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
4081
4082XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
4083
4084function new_ct() {
4085 return ({
4086 workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
4087 rels:[], strs:[], comments:[], links:[],
4088 coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
4089 calcchains:[], vba: [], drawings: [],
4090 TODO:[], xmlns: "" });
4091}
4092
4093function parse_ct(data) {
4094 var ct = new_ct();
4095 if(!data || !data.match) return ct;
4096 var ctext = {};
4097 (data.match(tagregex)||[]).forEach(function(x) {
4098 var y = parsexmltag(x);
4099 switch(y[0].replace(nsregex,"<")) {
4100 case '<?xml': break;
4101 case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
4102 case '<Default': ctext[y.Extension] = y.ContentType; break;
4103 case '<Override':
4104 if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
4105 break;
4106 }
4107 });
4108 if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
4109 ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
4110 ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
4111 ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
4112 ct.defaults = ctext;
4113 delete ct.calcchains;
4114 return ct;
4115}
4116
4117var CTYPE_XML_ROOT = writextag('Types', null, {
4118 'xmlns': XMLNS.CT,
4119 'xmlns:xsd': XMLNS.xsd,
4120 'xmlns:xsi': XMLNS.xsi
4121});
4122
4123var CTYPE_DEFAULTS = [
4124 ['xml', 'application/xml'],
4125 ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
4126 ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
4127 ['data', 'application/vnd.openxmlformats-officedocument.model+data'],
4128 /* from test files */
4129 ['bmp', 'image/bmp'],
4130 ['png', 'image/png'],
4131 ['gif', 'image/gif'],
4132 ['emf', 'image/x-emf'],
4133 ['wmf', 'image/x-wmf'],
4134 ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
4135 ['tif', 'image/tiff'], ['tiff', 'image/tiff'],
4136 ['pdf', 'application/pdf'],
4137 ['rels', type2ct.rels[0]]
4138].map(function(x) {
4139 return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
4140});
4141
4142function write_ct(ct, opts) {
4143 var o = [], v;
4144 o[o.length] = (XML_HEADER);
4145 o[o.length] = (CTYPE_XML_ROOT);
4146 o = o.concat(CTYPE_DEFAULTS);
4147
4148 /* only write first instance */
4149 var f1 = function(w) {
4150 if(ct[w] && ct[w].length > 0) {
4151 v = ct[w][0];
4152 o[o.length] = (writextag('Override', null, {
4153 'PartName': (v[0] == '/' ? "":"/") + v,
4154 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4155 }));
4156 }
4157 };
4158
4159 /* book type-specific */
4160 var f2 = function(w) {
4161 (ct[w]||[]).forEach(function(v) {
4162 o[o.length] = (writextag('Override', null, {
4163 'PartName': (v[0] == '/' ? "":"/") + v,
4164 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4165 }));
4166 });
4167 };
4168
4169 /* standard type */
4170 var f3 = function(t) {
4171 (ct[t]||[]).forEach(function(v) {
4172 o[o.length] = (writextag('Override', null, {
4173 'PartName': (v[0] == '/' ? "":"/") + v,
4174 'ContentType': type2ct[t][0]
4175 }));
4176 });
4177 };
4178
4179 f1('workbooks');
4180 f2('sheets');
4181 f2('charts');
4182 f3('themes');
4183 ['strs', 'styles'].forEach(f1);
4184 ['coreprops', 'extprops', 'custprops'].forEach(f3);
4185 f3('vba');
4186 f3('comments');
4187 f3('drawings');
4188 if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
4189 return o.join("");
4190}
4191/* 9.3 Relationships */
4192var RELS = ({
4193 WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4194 SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4195 HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
4196 VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
4197 XPATH: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",
4198 XMISS: "http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",
4199 XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
4200 VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
4201});
4202
4203/* 9.3.3 Representing Relationships */
4204function get_rels_path(file) {
4205 var n = file.lastIndexOf("/");
4206 return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
4207}
4208
4209function parse_rels(data, currentFilePath) {
4210 var rels = {"!id":{}};
4211 if (!data) return rels;
4212 if (currentFilePath.charAt(0) !== '/') {
4213 currentFilePath = '/'+currentFilePath;
4214 }
4215 var hash = {};
4216
4217 (data.match(tagregex)||[]).forEach(function(x) {
4218 var y = parsexmltag(x);
4219 /* 9.3.2.2 OPC_Relationships */
4220 if (y[0] === '<Relationship') {
4221 var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
4222 var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
4223 rels[canonictarget] = rel;
4224 hash[y.Id] = rel;
4225 }
4226 });
4227 rels["!id"] = hash;
4228 return rels;
4229}
4230
4231XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
4232
4233var RELS_ROOT = writextag('Relationships', null, {
4234 //'xmlns:ns0': XMLNS.RELS,
4235 'xmlns': XMLNS.RELS
4236});
4237
4238/* TODO */
4239function write_rels(rels) {
4240 var o = [XML_HEADER, RELS_ROOT];
4241 keys(rels['!id']).forEach(function(rid) {
4242 o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
4243 });
4244 if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
4245 return o.join("");
4246}
4247
4248var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
4249function add_rels(rels, rId, f, type, relobj, targetmode) {
4250 if(!relobj) relobj = {};
4251 if(!rels['!id']) rels['!id'] = {};
4252 if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
4253 relobj.Id = 'rId' + rId;
4254 relobj.Type = type;
4255 relobj.Target = f;
4256 if(targetmode) relobj.TargetMode = targetmode;
4257 else if(RELS_EXTERN.indexOf(relobj.Type) > -1) relobj.TargetMode = "External";
4258 if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
4259 rels['!id'][relobj.Id] = relobj;
4260 rels[('/' + relobj.Target).replace("//","/")] = relobj;
4261 return rId;
4262}
4263/* ECMA-376 Part II 11.1 Core Properties Part */
4264/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4265var CORE_PROPS = [
4266 ["cp:category", "Category"],
4267 ["cp:contentStatus", "ContentStatus"],
4268 ["cp:keywords", "Keywords"],
4269 ["cp:lastModifiedBy", "LastAuthor"],
4270 ["cp:lastPrinted", "LastPrinted"],
4271 ["cp:revision", "RevNumber"],
4272 ["cp:version", "Version"],
4273 ["dc:creator", "Author"],
4274 ["dc:description", "Comments"],
4275 ["dc:identifier", "Identifier"],
4276 ["dc:language", "Language"],
4277 ["dc:subject", "Subject"],
4278 ["dc:title", "Title"],
4279 ["dcterms:created", "CreatedDate", 'date'],
4280 ["dcterms:modified", "ModifiedDate", 'date']
4281];
4282
4283XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
4284RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
4285
4286var CORE_PROPS_REGEX = (function() {
4287 var r = new Array(CORE_PROPS.length);
4288 for(var i = 0; i < CORE_PROPS.length; ++i) {
4289 var f = CORE_PROPS[i];
4290 var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
4291 r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
4292 }
4293 return r;
4294})();
4295
4296function parse_core_props(data) {
4297 var p = {};
4298 data = utf8read(data);
4299
4300 for(var i = 0; i < CORE_PROPS.length; ++i) {
4301 var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4302 if(cur != null && cur.length > 0) p[f[1]] = cur[1];
4303 if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4304 }
4305
4306 return p;
4307}
4308
4309var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4310 //'xmlns': XMLNS.CORE_PROPS,
4311 'xmlns:cp': XMLNS.CORE_PROPS,
4312 'xmlns:dc': XMLNS.dc,
4313 'xmlns:dcterms': XMLNS.dcterms,
4314 'xmlns:dcmitype': XMLNS.dcmitype,
4315 'xmlns:xsi': XMLNS.xsi
4316});
4317
4318function cp_doit(f, g, h, o, p) {
4319 if(p[f] != null || g == null || g === "") return;
4320 p[f] = g;
4321 o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4322}
4323
4324function write_core_props(cp, _opts) {
4325 var opts = _opts || {};
4326 var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4327 if(!cp && !opts.Props) return o.join("");
4328
4329 if(cp) {
4330 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);
4331 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);
4332 }
4333
4334 for(var i = 0; i != CORE_PROPS.length; ++i) {
4335 var f = CORE_PROPS[i];
4336 var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4337 if(v === true) v = "1";
4338 else if(v === false) v = "0";
4339 else if(typeof v == "number") v = String(v);
4340 if(v != null) cp_doit(f[0], v, null, o, p);
4341 }
4342 if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4343 return o.join("");
4344}
4345/* 15.2.12.3 Extended File Properties Part */
4346/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4347var EXT_PROPS = [
4348 ["Application", "Application", "string"],
4349 ["AppVersion", "AppVersion", "string"],
4350 ["Company", "Company", "string"],
4351 ["DocSecurity", "DocSecurity", "string"],
4352 ["Manager", "Manager", "string"],
4353 ["HyperlinksChanged", "HyperlinksChanged", "bool"],
4354 ["SharedDoc", "SharedDoc", "bool"],
4355 ["LinksUpToDate", "LinksUpToDate", "bool"],
4356 ["ScaleCrop", "ScaleCrop", "bool"],
4357 ["HeadingPairs", "HeadingPairs", "raw"],
4358 ["TitlesOfParts", "TitlesOfParts", "raw"]
4359];
4360
4361XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4362RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4363
4364var PseudoPropsPairs = [
4365 "Worksheets", "SheetNames",
4366 "NamedRanges", "DefinedNames",
4367 "Chartsheets", "ChartNames"
4368];
4369function load_props_pairs(HP, TOP, props, opts) {
4370 var v = [];
4371 if(typeof HP == "string") v = parseVector(HP, opts);
4372 else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4373 var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4374 var idx = 0, len = 0;
4375 if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4376 len = +(v[i+1].v);
4377 switch(v[i].v) {
4378 case "Worksheets":
4379 case "工作表":
4380 case "Листы":
4381 case "أوراق العمل":
4382 case "ワークシート":
4383 case "גליונות עבודה":
4384 case "Arbeitsblätter":
4385 case "Çalışma Sayfaları":
4386 case "Feuilles de calcul":
4387 case "Fogli di lavoro":
4388 case "Folhas de cálculo":
4389 case "Planilhas":
4390 case "Regneark":
4391 case "Hojas de cálculo":
4392 case "Werkbladen":
4393 props.Worksheets = len;
4394 props.SheetNames = parts.slice(idx, idx + len);
4395 break;
4396
4397 case "Named Ranges":
4398 case "Rangos con nombre":
4399 case "名前付き一覧":
4400 case "Benannte Bereiche":
4401 case "Navngivne områder":
4402 props.NamedRanges = len;
4403 props.DefinedNames = parts.slice(idx, idx + len);
4404 break;
4405
4406 case "Charts":
4407 case "Diagramme":
4408 props.Chartsheets = len;
4409 props.ChartNames = parts.slice(idx, idx + len);
4410 break;
4411 }
4412 idx += len;
4413 }
4414}
4415
4416function parse_ext_props(data, p, opts) {
4417 var q = {}; if(!p) p = {};
4418 data = utf8read(data);
4419
4420 EXT_PROPS.forEach(function(f) {
4421 switch(f[2]) {
4422 case "string": p[f[1]] = (data.match(matchtag(f[0]))||[])[1]; break;
4423 case "bool": p[f[1]] = (data.match(matchtag(f[0]))||[])[1] === "true"; break;
4424 case "raw":
4425 var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4426 if(cur && cur.length > 0) q[f[1]] = cur[1];
4427 break;
4428 }
4429 });
4430
4431 if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4432
4433 return p;
4434}
4435
4436var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4437 'xmlns': XMLNS.EXT_PROPS,
4438 'xmlns:vt': XMLNS.vt
4439});
4440
4441function write_ext_props(cp) {
4442 var o = [], W = writextag;
4443 if(!cp) cp = {};
4444 cp.Application = "SheetJS";
4445 o[o.length] = (XML_HEADER);
4446 o[o.length] = (EXT_PROPS_XML_ROOT);
4447
4448 EXT_PROPS.forEach(function(f) {
4449 if(cp[f[1]] === undefined) return;
4450 var v;
4451 switch(f[2]) {
4452 case 'string': v = String(cp[f[1]]); break;
4453 case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4454 }
4455 if(v !== undefined) o[o.length] = (W(f[0], v));
4456 });
4457
4458 /* TODO: HeadingPairs, TitlesOfParts */
4459 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"})));
4460 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"})));
4461 if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4462 return o.join("");
4463}
4464/* 15.2.12.2 Custom File Properties Part */
4465XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4466RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4467
4468var custregex = /<[^>]+>[^<]*/g;
4469function parse_cust_props(data, opts) {
4470 var p = {}, name = "";
4471 var m = data.match(custregex);
4472 if(m) for(var i = 0; i != m.length; ++i) {
4473 var x = m[i], y = parsexmltag(x);
4474 switch(y[0]) {
4475 case '<?xml': break;
4476 case '<Properties': break;
4477 case '<property': name = y.name; break;
4478 case '</property>': name = null; break;
4479 default: if (x.indexOf('<vt:') === 0) {
4480 var toks = x.split('>');
4481 var type = toks[0].slice(4), text = toks[1];
4482 /* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4483 switch(type) {
4484 case 'lpstr': case 'bstr': case 'lpwstr':
4485 p[name] = unescapexml(text);
4486 break;
4487 case 'bool':
4488 p[name] = parsexmlbool(text);
4489 break;
4490 case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4491 p[name] = parseInt(text, 10);
4492 break;
4493 case 'r4': case 'r8': case 'decimal':
4494 p[name] = parseFloat(text);
4495 break;
4496 case 'filetime': case 'date':
4497 p[name] = parseDate(text);
4498 break;
4499 case 'cy': case 'error':
4500 p[name] = unescapexml(text);
4501 break;
4502 default:
4503 if(type.slice(-1) == '/') break;
4504 if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4505 }
4506 } else if(x.slice(0,2) === "</") {/* empty */
4507 } else if(opts.WTF) throw new Error(x);
4508 }
4509 }
4510 return p;
4511}
4512
4513var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4514 'xmlns': XMLNS.CUST_PROPS,
4515 'xmlns:vt': XMLNS.vt
4516});
4517
4518function write_cust_props(cp) {
4519 var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4520 if(!cp) return o.join("");
4521 var pid = 1;
4522 keys(cp).forEach(function custprop(k) { ++pid;
4523 o[o.length] = (writextag('property', write_vt(cp[k]), {
4524 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4525 'pid': pid,
4526 'name': k
4527 }));
4528 });
4529 if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4530 return o.join("");
4531}
4532/* 18.4.7 rPr CT_RPrElt */
4533function parse_rpr(rpr) {
4534 var font = {}, m = rpr.match(tagregex), i = 0;
4535 var pass = false;
4536 if(m) for(;i!=m.length; ++i) {
4537 var y = parsexmltag(m[i]);
4538 switch(y[0].replace(/\w*:/g,"")) {
4539 /* 18.8.12 condense CT_BooleanProperty */
4540 /* ** not required . */
4541 case '<condense': break;
4542 /* 18.8.17 extend CT_BooleanProperty */
4543 /* ** not required . */
4544 case '<extend': break;
4545 /* 18.8.36 shadow CT_BooleanProperty */
4546 /* ** not required . */
4547 case '<shadow':
4548 if(!y.val) break;
4549 /* falls through */
4550 case '<shadow>':
4551 case '<shadow/>': font.shadow = 1; break;
4552 case '</shadow>': break;
4553
4554 /* 18.4.1 charset CT_IntProperty TODO */
4555 case '<charset':
4556 if(y.val == '1') break;
4557 font.cp = CS2CP[parseInt(y.val, 10)];
4558 break;
4559
4560 /* 18.4.2 outline CT_BooleanProperty TODO */
4561 case '<outline':
4562 if(!y.val) break;
4563 /* falls through */
4564 case '<outline>':
4565 case '<outline/>': font.outline = 1; break;
4566 case '</outline>': break;
4567
4568 /* 18.4.5 rFont CT_FontName */
4569 case '<rFont': font.name = y.val; break;
4570
4571 /* 18.4.11 sz CT_FontSize */
4572 case '<sz': font.sz = y.val; break;
4573
4574 /* 18.4.10 strike CT_BooleanProperty */
4575 case '<strike':
4576 if(!y.val) break;
4577 /* falls through */
4578 case '<strike>':
4579 case '<strike/>': font.strike = 1; break;
4580 case '</strike>': break;
4581
4582 /* 18.4.13 u CT_UnderlineProperty */
4583 case '<u':
4584 if(!y.val) break;
4585 switch(y.val) {
4586 case 'double': font.uval = "double"; break;
4587 case 'singleAccounting': font.uval = "single-accounting"; break;
4588 case 'doubleAccounting': font.uval = "double-accounting"; break;
4589 }
4590 /* falls through */
4591 case '<u>':
4592 case '<u/>': font.u = 1; break;
4593 case '</u>': break;
4594
4595 /* 18.8.2 b */
4596 case '<b':
4597 if(y.val == '0') break;
4598 /* falls through */
4599 case '<b>':
4600 case '<b/>': font.b = 1; break;
4601 case '</b>': break;
4602
4603 /* 18.8.26 i */
4604 case '<i':
4605 if(y.val == '0') break;
4606 /* falls through */
4607 case '<i>':
4608 case '<i/>': font.i = 1; break;
4609 case '</i>': break;
4610
4611 /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
4612 case '<color':
4613 if(y.rgb) font.color = y.rgb.slice(2,8);
4614 break;
4615
4616 /* 18.8.18 family ST_FontFamily */
4617 case '<family': font.family = y.val; break;
4618
4619 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
4620 case '<vertAlign': font.valign = y.val; break;
4621
4622 /* 18.8.35 scheme CT_FontScheme TODO */
4623 case '<scheme': break;
4624
4625 /* 18.2.10 extLst CT_ExtensionList ? */
4626 case '<extLst': case '<extLst>': case '</extLst>': break;
4627 case '<ext': pass = true; break;
4628 case '</ext>': pass = false; break;
4629 default:
4630 if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
4631 }
4632 }
4633 return font;
4634}
4635
4636var parse_rs = (function() {
4637 var tregex = matchtag("t"), rpregex = matchtag("rPr");
4638 /* 18.4.4 r CT_RElt */
4639 function parse_r(r) {
4640 /* 18.4.12 t ST_Xstring */
4641 var t = r.match(tregex)/*, cp = 65001*/;
4642 if(!t) return {t:"s", v:""};
4643
4644 var o = ({t:'s', v:unescapexml(t[1])});
4645 var rpr = r.match(rpregex);
4646 if(rpr) o.s = parse_rpr(rpr[1]);
4647 return o;
4648 }
4649 var rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/;
4650 return function parse_rs(rs) {
4651 return rs.replace(rregex,"").split(rend).map(parse_r).filter(function(r) { return r.v; });
4652 };
4653})();
4654
4655
4656/* Parse a list of <r> tags */
4657var rs_to_html = (function parse_rs_factory() {
4658 var nlregex = /(\r\n|\n)/g;
4659 function parse_rpr2(font, intro, outro) {
4660 var style = [];
4661
4662 if(font.u) style.push("text-decoration: underline;");
4663 if(font.uval) style.push("text-underline-style:" + font.uval + ";");
4664 if(font.sz) style.push("font-size:" + font.sz + "pt;");
4665 if(font.outline) style.push("text-effect: outline;");
4666 if(font.shadow) style.push("text-shadow: auto;");
4667 intro.push('<span style="' + style.join("") + '">');
4668
4669 if(font.b) { intro.push("<b>"); outro.push("</b>"); }
4670 if(font.i) { intro.push("<i>"); outro.push("</i>"); }
4671 if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
4672
4673 var align = font.valign || "";
4674 if(align == "superscript" || align == "super") align = "sup";
4675 else if(align == "subscript") align = "sub";
4676 if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
4677
4678 outro.push("</span>");
4679 return font;
4680 }
4681
4682 /* 18.4.4 r CT_RElt */
4683 function r_to_html(r) {
4684 var terms = [[],r.v,[]];
4685 if(!r.v) return "";
4686
4687 if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
4688
4689 return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
4690 }
4691
4692 return function parse_rs(rs) {
4693 return rs.map(r_to_html).join("");
4694 };
4695})();
4696
4697/* 18.4.8 si CT_Rst */
4698var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
4699var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
4700function parse_si(x, opts) {
4701 var html = opts ? opts.cellHTML : true;
4702 var z = {};
4703 if(!x) return null;
4704 //var y;
4705 /* 18.4.12 t ST_Xstring (Plaintext String) */
4706 // TODO: is whitespace actually valid here?
4707 if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
4708 z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
4709 z.r = utf8read(x);
4710 if(html) z.h = escapehtml(z.t);
4711 }
4712 /* 18.4.4 r CT_RElt (Rich Text Run) */
4713 else if((/*y = */x.match(sirregex))) {
4714 z.r = utf8read(x);
4715 z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
4716 if(html) z.h = rs_to_html(parse_rs(z.r));
4717 }
4718 /* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
4719 /* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
4720 return z;
4721}
4722
4723/* 18.4 Shared String Table */
4724var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
4725var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
4726var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
4727function parse_sst_xml(data, opts) {
4728 var s = ([]), ss = "";
4729 if(!data) return s;
4730 /* 18.4.9 sst CT_Sst */
4731 var sst = data.match(sstr0);
4732 if(sst) {
4733 ss = sst[2].replace(sstr1,"").split(sstr2);
4734 for(var i = 0; i != ss.length; ++i) {
4735 var o = parse_si(ss[i].trim(), opts);
4736 if(o != null) s[s.length] = o;
4737 }
4738 sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
4739 }
4740 return s;
4741}
4742
4743RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
4744var straywsregex = /^\s|\s$|[\t\n\r]/;
4745function write_sst_xml(sst, opts) {
4746 if(!opts.bookSST) return "";
4747 var o = [XML_HEADER];
4748 o[o.length] = (writextag('sst', null, {
4749 xmlns: XMLNS.main[0],
4750 count: sst.Count,
4751 uniqueCount: sst.Unique
4752 }));
4753 for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
4754 var s = sst[i];
4755 var sitag = "<si>";
4756 if(s.r) sitag += s.r;
4757 else {
4758 sitag += "<t";
4759 if(!s.t) s.t = "";
4760 if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
4761 sitag += ">" + escapexml(s.t) + "</t>";
4762 }
4763 sitag += "</si>";
4764 o[o.length] = (sitag);
4765 }
4766 if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
4767 return o.join("");
4768}
4769function hex2RGB(h) {
4770 var o = h.slice(h[0]==="#"?1:0).slice(0,6);
4771 return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
4772}
4773function rgb2Hex(rgb) {
4774 for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
4775 return o.toString(16).toUpperCase().slice(1);
4776}
4777
4778function rgb2HSL(rgb) {
4779 var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
4780 var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
4781 if(C === 0) return [0, 0, R];
4782
4783 var H6 = 0, S = 0, L2 = (M + m);
4784 S = C / (L2 > 1 ? 2 - L2 : L2);
4785 switch(M){
4786 case R: H6 = ((G - B) / C + 6)%6; break;
4787 case G: H6 = ((B - R) / C + 2); break;
4788 case B: H6 = ((R - G) / C + 4); break;
4789 }
4790 return [H6 / 6, S, L2 / 2];
4791}
4792
4793function hsl2RGB(hsl){
4794 var H = hsl[0], S = hsl[1], L = hsl[2];
4795 var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
4796 var rgb = [m,m,m], h6 = 6*H;
4797
4798 var X;
4799 if(S !== 0) switch(h6|0) {
4800 case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
4801 case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
4802 case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
4803 case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
4804 case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
4805 case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
4806 }
4807 for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
4808 return rgb;
4809}
4810
4811/* 18.8.3 bgColor tint algorithm */
4812function rgb_tint(hex, tint) {
4813 if(tint === 0) return hex;
4814 var hsl = rgb2HSL(hex2RGB(hex));
4815 if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
4816 else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
4817 return rgb2Hex(hsl2RGB(hsl));
4818}
4819
4820/* 18.3.1.13 width calculations */
4821/* [MS-OI29500] 2.1.595 Column Width & Formatting */
4822var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
4823function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
4824function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
4825function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
4826//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
4827//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
4828function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
4829/* XLSX/XLSB/XLS specify width in units of MDW */
4830function find_mdw_colw(collw) {
4831 var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
4832 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; }
4833 MDW = _MDW;
4834}
4835/* XLML specifies width in terms of pixels */
4836/*function find_mdw_wpx(wpx) {
4837 var delta = Infinity, guess = 0, _MDW = MIN_MDW;
4838 for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
4839 guess = char2width_(px2char_(wpx))*256;
4840 guess = (guess) % 1;
4841 if(guess > 0.5) guess--;
4842 if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
4843 }
4844 MDW = _MDW;
4845}*/
4846
4847function process_col(coll) {
4848 if(coll.width) {
4849 coll.wpx = width2px(coll.width);
4850 coll.wch = px2char(coll.wpx);
4851 coll.MDW = MDW;
4852 } else if(coll.wpx) {
4853 coll.wch = px2char(coll.wpx);
4854 coll.width = char2width(coll.wch);
4855 coll.MDW = MDW;
4856 } else if(typeof coll.wch == 'number') {
4857 coll.width = char2width(coll.wch);
4858 coll.wpx = width2px(coll.width);
4859 coll.MDW = MDW;
4860 }
4861 if(coll.customWidth) delete coll.customWidth;
4862}
4863
4864var DEF_PPI = 96, PPI = DEF_PPI;
4865function px2pt(px) { return px * 96 / PPI; }
4866function pt2px(pt) { return pt * PPI / 96; }
4867
4868/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
4869var XLMLPatternTypeMap = {
4870 "None": "none",
4871 "Solid": "solid",
4872 "Gray50": "mediumGray",
4873 "Gray75": "darkGray",
4874 "Gray25": "lightGray",
4875 "HorzStripe": "darkHorizontal",
4876 "VertStripe": "darkVertical",
4877 "ReverseDiagStripe": "darkDown",
4878 "DiagStripe": "darkUp",
4879 "DiagCross": "darkGrid",
4880 "ThickDiagCross": "darkTrellis",
4881 "ThinHorzStripe": "lightHorizontal",
4882 "ThinVertStripe": "lightVertical",
4883 "ThinReverseDiagStripe": "lightDown",
4884 "ThinHorzCross": "lightGrid"
4885};
4886
4887/* 18.8.5 borders CT_Borders */
4888function parse_borders(t, styles, themes, opts) {
4889 styles.Borders = [];
4890 var border = {};
4891 var pass = false;
4892 (t[0].match(tagregex)||[]).forEach(function(x) {
4893 var y = parsexmltag(x);
4894 switch(strip_ns(y[0])) {
4895 case '<borders': case '<borders>': case '</borders>': break;
4896
4897 /* 18.8.4 border CT_Border */
4898 case '<border': case '<border>': case '<border/>':
4899 border = {};
4900 if(y.diagonalUp) border.diagonalUp = parsexmlbool(y.diagonalUp);
4901 if(y.diagonalDown) border.diagonalDown = parsexmlbool(y.diagonalDown);
4902 styles.Borders.push(border);
4903 break;
4904 case '</border>': break;
4905
4906 /* note: not in spec, appears to be CT_BorderPr */
4907 case '<left/>': break;
4908 case '<left': case '<left>': break;
4909 case '</left>': break;
4910
4911 /* note: not in spec, appears to be CT_BorderPr */
4912 case '<right/>': break;
4913 case '<right': case '<right>': break;
4914 case '</right>': break;
4915
4916 /* 18.8.43 top CT_BorderPr */
4917 case '<top/>': break;
4918 case '<top': case '<top>': break;
4919 case '</top>': break;
4920
4921 /* 18.8.6 bottom CT_BorderPr */
4922 case '<bottom/>': break;
4923 case '<bottom': case '<bottom>': break;
4924 case '</bottom>': break;
4925
4926 /* 18.8.13 diagonal CT_BorderPr */
4927 case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
4928 case '</diagonal>': break;
4929
4930 /* 18.8.25 horizontal CT_BorderPr */
4931 case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
4932 case '</horizontal>': break;
4933
4934 /* 18.8.44 vertical CT_BorderPr */
4935 case '<vertical': case '<vertical>': case '<vertical/>': break;
4936 case '</vertical>': break;
4937
4938 /* 18.8.37 start CT_BorderPr */
4939 case '<start': case '<start>': case '<start/>': break;
4940 case '</start>': break;
4941
4942 /* 18.8.16 end CT_BorderPr */
4943 case '<end': case '<end>': case '<end/>': break;
4944 case '</end>': break;
4945
4946 /* 18.8.? color CT_Color */
4947 case '<color': case '<color>':
4948 break;
4949 case '<color/>': case '</color>': break;
4950
4951 /* 18.2.10 extLst CT_ExtensionList ? */
4952 case '<extLst': case '<extLst>': case '</extLst>': break;
4953 case '<ext': pass = true; break;
4954 case '</ext>': pass = false; break;
4955 default: if(opts && opts.WTF) {
4956 if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
4957 }
4958 }
4959 });
4960}
4961
4962/* 18.8.21 fills CT_Fills */
4963function parse_fills(t, styles, themes, opts) {
4964 styles.Fills = [];
4965 var fill = {};
4966 var pass = false;
4967 (t[0].match(tagregex)||[]).forEach(function(x) {
4968 var y = parsexmltag(x);
4969 switch(strip_ns(y[0])) {
4970 case '<fills': case '<fills>': case '</fills>': break;
4971
4972 /* 18.8.20 fill CT_Fill */
4973 case '<fill>': case '<fill': case '<fill/>':
4974 fill = {}; styles.Fills.push(fill); break;
4975 case '</fill>': break;
4976
4977 /* 18.8.24 gradientFill CT_GradientFill */
4978 case '<gradientFill>': break;
4979 case '<gradientFill':
4980 case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
4981
4982 /* 18.8.32 patternFill CT_PatternFill */
4983 case '<patternFill': case '<patternFill>':
4984 if(y.patternType) fill.patternType = y.patternType;
4985 break;
4986 case '<patternFill/>': case '</patternFill>': break;
4987
4988 /* 18.8.3 bgColor CT_Color */
4989 case '<bgColor':
4990 if(!fill.bgColor) fill.bgColor = {};
4991 if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
4992 if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
4993 if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
4994 /* Excel uses ARGB strings */
4995 if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
4996 break;
4997 case '<bgColor/>': case '</bgColor>': break;
4998
4999 /* 18.8.19 fgColor CT_Color */
5000 case '<fgColor':
5001 if(!fill.fgColor) fill.fgColor = {};
5002 if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
5003 if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
5004 /* Excel uses ARGB strings */
5005 if(y.rgb != null) fill.fgColor.rgb = y.rgb.slice(-6);
5006 break;
5007 case '<fgColor/>': case '</fgColor>': break;
5008
5009 /* 18.8.38 stop CT_GradientStop */
5010 case '<stop': case '<stop/>': break;
5011 case '</stop>': break;
5012
5013 /* 18.8.? color CT_Color */
5014 case '<color': case '<color/>': break;
5015 case '</color>': break;
5016
5017 /* 18.2.10 extLst CT_ExtensionList ? */
5018 case '<extLst': case '<extLst>': case '</extLst>': break;
5019 case '<ext': pass = true; break;
5020 case '</ext>': pass = false; break;
5021 default: if(opts && opts.WTF) {
5022 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
5023 }
5024 }
5025 });
5026}
5027
5028/* 18.8.23 fonts CT_Fonts */
5029function parse_fonts(t, styles, themes, opts) {
5030 styles.Fonts = [];
5031 var font = {};
5032 var pass = false;
5033 (t[0].match(tagregex)||[]).forEach(function(x) {
5034 var y = parsexmltag(x);
5035 switch(strip_ns(y[0])) {
5036 case '<fonts': case '<fonts>': case '</fonts>': break;
5037
5038 /* 18.8.22 font CT_Font */
5039 case '<font': case '<font>': break;
5040 case '</font>': case '<font/>':
5041 styles.Fonts.push(font);
5042 font = {};
5043 break;
5044
5045 /* 18.8.29 name CT_FontName */
5046 case '<name': if(y.val) font.name = y.val; break;
5047 case '<name/>': case '</name>': break;
5048
5049 /* 18.8.2 b CT_BooleanProperty */
5050 case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
5051 case '<b/>': font.bold = 1; break;
5052
5053 /* 18.8.26 i CT_BooleanProperty */
5054 case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
5055 case '<i/>': font.italic = 1; break;
5056
5057 /* 18.4.13 u CT_UnderlineProperty */
5058 case '<u':
5059 switch(y.val) {
5060 case "none": font.underline = 0x00; break;
5061 case "single": font.underline = 0x01; break;
5062 case "double": font.underline = 0x02; break;
5063 case "singleAccounting": font.underline = 0x21; break;
5064 case "doubleAccounting": font.underline = 0x22; break;
5065 } break;
5066 case '<u/>': font.underline = 1; break;
5067
5068 /* 18.4.10 strike CT_BooleanProperty */
5069 case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
5070 case '<strike/>': font.strike = 1; break;
5071
5072 /* 18.4.2 outline CT_BooleanProperty */
5073 case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
5074 case '<outline/>': font.outline = 1; break;
5075
5076 /* 18.8.36 shadow CT_BooleanProperty */
5077 case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
5078 case '<shadow/>': font.shadow = 1; break;
5079
5080 /* 18.8.12 condense CT_BooleanProperty */
5081 case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
5082 case '<condense/>': font.condense = 1; break;
5083
5084 /* 18.8.17 extend CT_BooleanProperty */
5085 case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
5086 case '<extend/>': font.extend = 1; break;
5087
5088 /* 18.4.11 sz CT_FontSize */
5089 case '<sz': if(y.val) font.sz = +y.val; break;
5090 case '<sz/>': case '</sz>': break;
5091
5092 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
5093 case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
5094 case '<vertAlign/>': case '</vertAlign>': break;
5095
5096 /* 18.8.18 family CT_FontFamily */
5097 case '<family': if(y.val) font.family = parseInt(y.val,10); break;
5098 case '<family/>': case '</family>': break;
5099
5100 /* 18.8.35 scheme CT_FontScheme */
5101 case '<scheme': if(y.val) font.scheme = y.val; break;
5102 case '<scheme/>': case '</scheme>': break;
5103
5104 /* 18.4.1 charset CT_IntProperty */
5105 case '<charset':
5106 if(y.val == '1') break;
5107 y.codepage = CS2CP[parseInt(y.val, 10)];
5108 break;
5109
5110 /* 18.?.? color CT_Color */
5111 case '<color':
5112 if(!font.color) font.color = {};
5113 if(y.auto) font.color.auto = parsexmlbool(y.auto);
5114
5115 if(y.rgb) font.color.rgb = y.rgb.slice(-6);
5116 else if(y.indexed) {
5117 font.color.index = parseInt(y.indexed, 10);
5118 var icv = XLSIcv[font.color.index];
5119 if(font.color.index == 81) icv = XLSIcv[1];
5120 if(!icv) throw new Error(x);
5121 font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
5122 } else if(y.theme) {
5123 font.color.theme = parseInt(y.theme, 10);
5124 if(y.tint) font.color.tint = parseFloat(y.tint);
5125 if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
5126 font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
5127 }
5128 }
5129
5130 break;
5131 case '<color/>': case '</color>': break;
5132
5133 /* note: sometimes mc:AlternateContent appears bare */
5134 case '<AlternateContent': pass = true; break;
5135 case '</AlternateContent>': pass = false; break;
5136
5137 /* 18.2.10 extLst CT_ExtensionList ? */
5138 case '<extLst': case '<extLst>': case '</extLst>': break;
5139 case '<ext': pass = true; break;
5140 case '</ext>': pass = false; break;
5141 default: if(opts && opts.WTF) {
5142 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
5143 }
5144 }
5145 });
5146}
5147
5148/* 18.8.31 numFmts CT_NumFmts */
5149function parse_numFmts(t, styles, opts) {
5150 styles.NumberFmt = [];
5151 var k/*Array<number>*/ = (keys(SSF._table));
5152 for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
5153 var m = t[0].match(tagregex);
5154 if(!m) return;
5155 for(i=0; i < m.length; ++i) {
5156 var y = parsexmltag(m[i]);
5157 switch(strip_ns(y[0])) {
5158 case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
5159 case '<numFmt': {
5160 var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
5161 styles.NumberFmt[j] = f;
5162 if(j>0) {
5163 if(j > 0x188) {
5164 for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
5165 styles.NumberFmt[j] = f;
5166 }
5167 SSF.load(f,j);
5168 }
5169 } break;
5170 case '</numFmt>': break;
5171 default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
5172 }
5173 }
5174}
5175
5176function write_numFmts(NF) {
5177 var o = ["<numFmts>"];
5178 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
5179 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])}));
5180 });
5181 if(o.length === 1) return "";
5182 o[o.length] = ("</numFmts>");
5183 o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
5184 return o.join("");
5185}
5186
5187/* 18.8.10 cellXfs CT_CellXfs */
5188var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
5189var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
5190function parse_cellXfs(t, styles, opts) {
5191 styles.CellXf = [];
5192 var xf;
5193 var pass = false;
5194 (t[0].match(tagregex)||[]).forEach(function(x) {
5195 var y = parsexmltag(x), i = 0;
5196 switch(strip_ns(y[0])) {
5197 case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
5198
5199 /* 18.8.45 xf CT_Xf */
5200 case '<xf': case '<xf/>':
5201 xf = y;
5202 delete xf[0];
5203 for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
5204 xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
5205 for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
5206 xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
5207 if(xf.numFmtId > 0x188) {
5208 for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
5209 }
5210 styles.CellXf.push(xf); break;
5211 case '</xf>': break;
5212
5213 /* 18.8.1 alignment CT_CellAlignment */
5214 case '<alignment': case '<alignment/>':
5215 var alignment = {};
5216 if(y.vertical) alignment.vertical = y.vertical;
5217 if(y.horizontal) alignment.horizontal = y.horizontal;
5218 if(y.textRotation != null) alignment.textRotation = y.textRotation;
5219 if(y.indent) alignment.indent = y.indent;
5220 if(y.wrapText) alignment.wrapText = parsexmlbool(y.wrapText);
5221 xf.alignment = alignment;
5222 break;
5223 case '</alignment>': break;
5224
5225 /* 18.8.33 protection CT_CellProtection */
5226 case '<protection':
5227 break;
5228 case '</protection>': case '<protection/>': break;
5229
5230 /* note: sometimes mc:AlternateContent appears bare */
5231 case '<AlternateContent': pass = true; break;
5232 case '</AlternateContent>': pass = false; break;
5233
5234 /* 18.2.10 extLst CT_ExtensionList ? */
5235 case '<extLst': case '<extLst>': case '</extLst>': break;
5236 case '<ext': pass = true; break;
5237 case '</ext>': pass = false; break;
5238 default: if(opts && opts.WTF) {
5239 if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
5240 }
5241 }
5242 });
5243}
5244
5245function write_cellXfs(cellXfs) {
5246 var o = [];
5247 o[o.length] = (writextag('cellXfs',null));
5248 cellXfs.forEach(function(c) {
5249 o[o.length] = (writextag('xf', null, c));
5250 });
5251 o[o.length] = ("</cellXfs>");
5252 if(o.length === 2) return "";
5253 o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
5254 return o.join("");
5255}
5256
5257/* 18.8 Styles CT_Stylesheet*/
5258var parse_sty_xml= (function make_pstyx() {
5259var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
5260var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
5261var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
5262var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
5263var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
5264
5265return function parse_sty_xml(data, themes, opts) {
5266 var styles = {};
5267 if(!data) return styles;
5268 data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
5269 /* 18.8.39 styleSheet CT_Stylesheet */
5270 var t;
5271
5272 /* 18.8.31 numFmts CT_NumFmts ? */
5273 if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
5274
5275 /* 18.8.23 fonts CT_Fonts ? */
5276 if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
5277
5278 /* 18.8.21 fills CT_Fills ? */
5279 if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
5280
5281 /* 18.8.5 borders CT_Borders ? */
5282 if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
5283
5284 /* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
5285
5286 /* 18.8.10 cellXfs CT_CellXfs ? */
5287 if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
5288
5289 /* 18.8.8 cellStyles CT_CellStyles ? */
5290 /* 18.8.15 dxfs CT_Dxfs ? */
5291 /* 18.8.42 tableStyles CT_TableStyles ? */
5292 /* 18.8.11 colors CT_Colors ? */
5293 /* 18.2.10 extLst CT_ExtensionList ? */
5294
5295 return styles;
5296};
5297})();
5298
5299var STYLES_XML_ROOT = writextag('styleSheet', null, {
5300 'xmlns': XMLNS.main[0],
5301 'xmlns:vt': XMLNS.vt
5302});
5303
5304RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
5305
5306function write_sty_xml(wb, opts) {
5307 var o = [XML_HEADER, STYLES_XML_ROOT], w;
5308 if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
5309 o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
5310 o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
5311 o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
5312 o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
5313 if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
5314 o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
5315 o[o.length] = ('<dxfs count="0"/>');
5316 o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
5317
5318 if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
5319 return o.join("");
5320}
5321RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
5322
5323/* 20.1.6.2 clrScheme CT_ColorScheme */
5324function parse_clrScheme(t, themes, opts) {
5325 themes.themeElements.clrScheme = [];
5326 var color = {};
5327 (t[0].match(tagregex)||[]).forEach(function(x) {
5328 var y = parsexmltag(x);
5329 switch(y[0]) {
5330 /* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
5331 case '<a:clrScheme': case '</a:clrScheme>': break;
5332
5333 /* 20.1.2.3.32 srgbClr CT_SRgbColor */
5334 case '<a:srgbClr':
5335 color.rgb = y.val; break;
5336
5337 /* 20.1.2.3.33 sysClr CT_SystemColor */
5338 case '<a:sysClr':
5339 color.rgb = y.lastClr; break;
5340
5341 /* 20.1.4.1.1 accent1 (Accent 1) */
5342 /* 20.1.4.1.2 accent2 (Accent 2) */
5343 /* 20.1.4.1.3 accent3 (Accent 3) */
5344 /* 20.1.4.1.4 accent4 (Accent 4) */
5345 /* 20.1.4.1.5 accent5 (Accent 5) */
5346 /* 20.1.4.1.6 accent6 (Accent 6) */
5347 /* 20.1.4.1.9 dk1 (Dark 1) */
5348 /* 20.1.4.1.10 dk2 (Dark 2) */
5349 /* 20.1.4.1.15 folHlink (Followed Hyperlink) */
5350 /* 20.1.4.1.19 hlink (Hyperlink) */
5351 /* 20.1.4.1.22 lt1 (Light 1) */
5352 /* 20.1.4.1.23 lt2 (Light 2) */
5353 case '<a:dk1>': case '</a:dk1>':
5354 case '<a:lt1>': case '</a:lt1>':
5355 case '<a:dk2>': case '</a:dk2>':
5356 case '<a:lt2>': case '</a:lt2>':
5357 case '<a:accent1>': case '</a:accent1>':
5358 case '<a:accent2>': case '</a:accent2>':
5359 case '<a:accent3>': case '</a:accent3>':
5360 case '<a:accent4>': case '</a:accent4>':
5361 case '<a:accent5>': case '</a:accent5>':
5362 case '<a:accent6>': case '</a:accent6>':
5363 case '<a:hlink>': case '</a:hlink>':
5364 case '<a:folHlink>': case '</a:folHlink>':
5365 if (y[0].charAt(1) === '/') {
5366 themes.themeElements.clrScheme.push(color);
5367 color = {};
5368 } else {
5369 color.name = y[0].slice(3, y[0].length - 1);
5370 }
5371 break;
5372
5373 default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
5374 }
5375 });
5376}
5377
5378/* 20.1.4.1.18 fontScheme CT_FontScheme */
5379function parse_fontScheme() { }
5380
5381/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
5382function parse_fmtScheme() { }
5383
5384var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
5385var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
5386var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
5387
5388/* 20.1.6.10 themeElements CT_BaseStyles */
5389function parse_themeElements(data, themes, opts) {
5390 themes.themeElements = {};
5391
5392 var t;
5393
5394 [
5395 /* clrScheme CT_ColorScheme */
5396 ['clrScheme', clrsregex, parse_clrScheme],
5397 /* fontScheme CT_FontScheme */
5398 ['fontScheme', fntsregex, parse_fontScheme],
5399 /* fmtScheme CT_StyleMatrix */
5400 ['fmtScheme', fmtsregex, parse_fmtScheme]
5401 ].forEach(function(m) {
5402 if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
5403 m[2](t, themes, opts);
5404 });
5405}
5406
5407var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
5408
5409/* 14.2.7 Theme Part */
5410function parse_theme_xml(data, opts) {
5411 /* 20.1.6.9 theme CT_OfficeStyleSheet */
5412 if(!data || data.length === 0) return parse_theme_xml(write_theme());
5413
5414 var t;
5415 var themes = {};
5416
5417 /* themeElements CT_BaseStyles */
5418 if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
5419 parse_themeElements(t[0], themes, opts);
5420 themes.raw = data;
5421 return themes;
5422}
5423
5424function write_theme(Themes, opts) {
5425 if(opts && opts.themeXLSX) return opts.themeXLSX;
5426 if(Themes && typeof Themes.raw == "string") return Themes.raw;
5427 var o = [XML_HEADER];
5428 o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
5429 o[o.length] = '<a:themeElements>';
5430
5431 o[o.length] = '<a:clrScheme name="Office">';
5432 o[o.length] = '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
5433 o[o.length] = '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
5434 o[o.length] = '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
5435 o[o.length] = '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
5436 o[o.length] = '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
5437 o[o.length] = '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
5438 o[o.length] = '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
5439 o[o.length] = '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
5440 o[o.length] = '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
5441 o[o.length] = '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
5442 o[o.length] = '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
5443 o[o.length] = '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
5444 o[o.length] = '</a:clrScheme>';
5445
5446 o[o.length] = '<a:fontScheme name="Office">';
5447 o[o.length] = '<a:majorFont>';
5448 o[o.length] = '<a:latin typeface="Cambria"/>';
5449 o[o.length] = '<a:ea typeface=""/>';
5450 o[o.length] = '<a:cs typeface=""/>';
5451 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
5452 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
5453 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
5454 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
5455 o[o.length] = '<a:font script="Arab" typeface="Times New Roman"/>';
5456 o[o.length] = '<a:font script="Hebr" typeface="Times New Roman"/>';
5457 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
5458 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
5459 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
5460 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
5461 o[o.length] = '<a:font script="Khmr" typeface="MoolBoran"/>';
5462 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
5463 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
5464 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
5465 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
5466 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
5467 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
5468 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
5469 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
5470 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
5471 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
5472 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
5473 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
5474 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
5475 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
5476 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
5477 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
5478 o[o.length] = '<a:font script="Viet" typeface="Times New Roman"/>';
5479 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
5480 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
5481 o[o.length] = '</a:majorFont>';
5482 o[o.length] = '<a:minorFont>';
5483 o[o.length] = '<a:latin typeface="Calibri"/>';
5484 o[o.length] = '<a:ea typeface=""/>';
5485 o[o.length] = '<a:cs typeface=""/>';
5486 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
5487 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
5488 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
5489 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
5490 o[o.length] = '<a:font script="Arab" typeface="Arial"/>';
5491 o[o.length] = '<a:font script="Hebr" typeface="Arial"/>';
5492 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
5493 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
5494 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
5495 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
5496 o[o.length] = '<a:font script="Khmr" typeface="DaunPenh"/>';
5497 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
5498 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
5499 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
5500 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
5501 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
5502 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
5503 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
5504 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
5505 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
5506 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
5507 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
5508 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
5509 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
5510 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
5511 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
5512 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
5513 o[o.length] = '<a:font script="Viet" typeface="Arial"/>';
5514 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
5515 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
5516 o[o.length] = '</a:minorFont>';
5517 o[o.length] = '</a:fontScheme>';
5518
5519 o[o.length] = '<a:fmtScheme name="Office">';
5520 o[o.length] = '<a:fillStyleLst>';
5521 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
5522 o[o.length] = '<a:gradFill rotWithShape="1">';
5523 o[o.length] = '<a:gsLst>';
5524 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
5525 o[o.length] = '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
5526 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
5527 o[o.length] = '</a:gsLst>';
5528 o[o.length] = '<a:lin ang="16200000" scaled="1"/>';
5529 o[o.length] = '</a:gradFill>';
5530 o[o.length] = '<a:gradFill rotWithShape="1">';
5531 o[o.length] = '<a:gsLst>';
5532 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>';
5533 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>';
5534 o[o.length] = '</a:gsLst>';
5535 o[o.length] = '<a:lin ang="16200000" scaled="0"/>';
5536 o[o.length] = '</a:gradFill>';
5537 o[o.length] = '</a:fillStyleLst>';
5538 o[o.length] = '<a:lnStyleLst>';
5539 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>';
5540 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>';
5541 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>';
5542 o[o.length] = '</a:lnStyleLst>';
5543 o[o.length] = '<a:effectStyleLst>';
5544 o[o.length] = '<a:effectStyle>';
5545 o[o.length] = '<a:effectLst>';
5546 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>';
5547 o[o.length] = '</a:effectLst>';
5548 o[o.length] = '</a:effectStyle>';
5549 o[o.length] = '<a:effectStyle>';
5550 o[o.length] = '<a:effectLst>';
5551 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>';
5552 o[o.length] = '</a:effectLst>';
5553 o[o.length] = '</a:effectStyle>';
5554 o[o.length] = '<a:effectStyle>';
5555 o[o.length] = '<a:effectLst>';
5556 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>';
5557 o[o.length] = '</a:effectLst>';
5558 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>';
5559 o[o.length] = '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
5560 o[o.length] = '</a:effectStyle>';
5561 o[o.length] = '</a:effectStyleLst>';
5562 o[o.length] = '<a:bgFillStyleLst>';
5563 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
5564 o[o.length] = '<a:gradFill rotWithShape="1">';
5565 o[o.length] = '<a:gsLst>';
5566 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
5567 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>';
5568 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
5569 o[o.length] = '</a:gsLst>';
5570 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
5571 o[o.length] = '</a:gradFill>';
5572 o[o.length] = '<a:gradFill rotWithShape="1">';
5573 o[o.length] = '<a:gsLst>';
5574 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
5575 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
5576 o[o.length] = '</a:gsLst>';
5577 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
5578 o[o.length] = '</a:gradFill>';
5579 o[o.length] = '</a:bgFillStyleLst>';
5580 o[o.length] = '</a:fmtScheme>';
5581 o[o.length] = '</a:themeElements>';
5582
5583 o[o.length] = '<a:objectDefaults>';
5584 o[o.length] = '<a:spDef>';
5585 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>';
5586 o[o.length] = '</a:spDef>';
5587 o[o.length] = '<a:lnDef>';
5588 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>';
5589 o[o.length] = '</a:lnDef>';
5590 o[o.length] = '</a:objectDefaults>';
5591 o[o.length] = '<a:extraClrSchemeLst/>';
5592 o[o.length] = '</a:theme>';
5593 return o.join("");
5594}
5595/* 18.14 Supplementary Workbook Data */
5596function parse_xlink_xml() {
5597 //var opts = _opts || {};
5598 //if(opts.WTF) throw "XLSX External Link";
5599}
5600
5601/* [MS-XLSB] 2.1.7.25 External Link */
5602function parse_xlink_bin(data, rel, name, _opts) {
5603 if(!data) return data;
5604 var opts = _opts || {};
5605
5606 var pass = false, end = false;
5607
5608 recordhopper(data, function xlink_parse(val, R_n, RT) {
5609 if(end) return;
5610 switch(RT) {
5611 case 0x0167: /* 'BrtSupTabs' */
5612 case 0x016B: /* 'BrtExternTableStart' */
5613 case 0x016C: /* 'BrtExternTableEnd' */
5614 case 0x016E: /* 'BrtExternRowHdr' */
5615 case 0x016F: /* 'BrtExternCellBlank' */
5616 case 0x0170: /* 'BrtExternCellReal' */
5617 case 0x0171: /* 'BrtExternCellBool' */
5618 case 0x0172: /* 'BrtExternCellError' */
5619 case 0x0173: /* 'BrtExternCellString' */
5620 case 0x01D8: /* 'BrtExternValueMeta' */
5621 case 0x0241: /* 'BrtSupNameStart' */
5622 case 0x0242: /* 'BrtSupNameValueStart' */
5623 case 0x0243: /* 'BrtSupNameValueEnd' */
5624 case 0x0244: /* 'BrtSupNameNum' */
5625 case 0x0245: /* 'BrtSupNameErr' */
5626 case 0x0246: /* 'BrtSupNameSt' */
5627 case 0x0247: /* 'BrtSupNameNil' */
5628 case 0x0248: /* 'BrtSupNameBool' */
5629 case 0x0249: /* 'BrtSupNameFmla' */
5630 case 0x024A: /* 'BrtSupNameBits' */
5631 case 0x024B: /* 'BrtSupNameEnd' */
5632 break;
5633
5634 case 0x0023: /* 'BrtFRTBegin' */
5635 pass = true; break;
5636 case 0x0024: /* 'BrtFRTEnd' */
5637 pass = false; break;
5638
5639 default:
5640 if((R_n||"").indexOf("Begin") > 0){/* empty */}
5641 else if((R_n||"").indexOf("End") > 0){/* empty */}
5642 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
5643 }
5644 }, opts);
5645}
5646/* 20.5 DrawingML - SpreadsheetML Drawing */
5647RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
5648RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
5649
5650/* 20.5.2.35 wsDr CT_Drawing */
5651function parse_drawing(data, rels) {
5652 if(!data) return "??";
5653 /*
5654 Chartsheet Drawing:
5655 - 20.5.2.35 wsDr CT_Drawing
5656 - 20.5.2.1 absoluteAnchor CT_AbsoluteAnchor
5657 - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
5658 - 20.1.2.2.16 graphic CT_GraphicalObject
5659 - 20.1.2.2.17 graphicData CT_GraphicalObjectData
5660 - chart reference
5661 the actual type is based on the URI of the graphicData
5662 TODO: handle embedded charts and other types of graphics
5663 */
5664 var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
5665
5666 return rels['!id'][id].Target;
5667}
5668
5669/* L.5.5.2 SpreadsheetML Comments + VML Schema */
5670var _shapeid = 1024;
5671function write_comments_vml(rId, comments) {
5672 var csize = [21600, 21600];
5673 /* L.5.2.1.2 Path Attribute */
5674 var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
5675 var o = [
5676 writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
5677 writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
5678 writextag("v:shapetype", [
5679 writextag("v:stroke", null, {joinstyle:"miter"}),
5680 writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
5681 ].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
5682 ];
5683 while(_shapeid < rId * 1000) _shapeid += 1000;
5684
5685 comments.forEach(function(x) {
5686 var c = decode_cell(x[0]);
5687 var fillopts = {'color2':"#BEFF82", 'type':"gradient"};
5688 if(fillopts.type == "gradient") fillopts.angle = "-180";
5689 var fillparm = fillopts.type == "gradient" ? writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}) : null;
5690 var fillxml = writextag('v:fill', fillparm, fillopts);
5691
5692 var shadata = ({on:"t", 'obscured':"t"});
5693 ++_shapeid;
5694
5695 o = o.concat([
5696 '<v:shape' + wxt_helper({
5697 id:'_x0000_s' + _shapeid,
5698 type:"#_x0000_t202",
5699 style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
5700 fillcolor:"#ECFAD4",
5701 strokecolor:"#edeaa1"
5702 }) + '>',
5703 fillxml,
5704 writextag("v:shadow", null, shadata),
5705 writextag("v:path", null, {'o:connecttype':"none"}),
5706 '<v:textbox><div style="text-align:left"></div></v:textbox>',
5707 '<x:ClientData ObjectType="Note">',
5708 '<x:MoveWithCells/>',
5709 '<x:SizeWithCells/>',
5710 /* Part 4 19.4.2.3 Anchor (Anchor) */
5711 writetag('x:Anchor', [c.c+1, 0, c.r+1, 0, c.c+3, 20, c.r+5, 20].join(",")),
5712 writetag('x:AutoFill', "False"),
5713 writetag('x:Row', String(c.r)),
5714 writetag('x:Column', String(c.c)),
5715 x[1].hidden ? '' : '<x:Visible/>',
5716 '</x:ClientData>',
5717 '</v:shape>'
5718 ]); });
5719 o.push('</xml>');
5720 return o.join("");
5721}
5722RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
5723
5724function sheet_insert_comments(sheet, comments) {
5725 var dense = Array.isArray(sheet);
5726 var cell;
5727 comments.forEach(function(comment) {
5728 var r = decode_cell(comment.ref);
5729 if(dense) {
5730 if(!sheet[r.r]) sheet[r.r] = [];
5731 cell = sheet[r.r][r.c];
5732 } else cell = sheet[comment.ref];
5733 if (!cell) {
5734 cell = ({t:"z"});
5735 if(dense) sheet[r.r][r.c] = cell;
5736 else sheet[comment.ref] = cell;
5737 var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
5738 if(range.s.r > r.r) range.s.r = r.r;
5739 if(range.e.r < r.r) range.e.r = r.r;
5740 if(range.s.c > r.c) range.s.c = r.c;
5741 if(range.e.c < r.c) range.e.c = r.c;
5742 var encoded = encode_range(range);
5743 if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
5744 }
5745
5746 if (!cell.c) cell.c = [];
5747 var o = ({a: comment.author, t: comment.t, r: comment.r});
5748 if(comment.h) o.h = comment.h;
5749 cell.c.push(o);
5750 });
5751}
5752
5753/* 18.7 Comments */
5754function parse_comments_xml(data, opts) {
5755 /* 18.7.6 CT_Comments */
5756 if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
5757 var authors = [];
5758 var commentList = [];
5759 var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
5760 if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
5761 if(x === "" || x.trim() === "") return;
5762 var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
5763 if(a) authors.push(a[1]);
5764 });
5765 var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
5766 if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
5767 if(x === "" || x.trim() === "") return;
5768 var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
5769 if(!cm) return;
5770 var y = parsexmltag(cm[0]);
5771 var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
5772 var cell = decode_cell(y.ref);
5773 if(opts.sheetRows && opts.sheetRows <= cell.r) return;
5774 var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
5775 var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
5776 comment.r = rt.r;
5777 if(rt.r == "<t></t>") rt.t = rt.h = "";
5778 comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
5779 if(opts.cellHTML) comment.h = rt.h;
5780 commentList.push(comment);
5781 });
5782 return commentList;
5783}
5784
5785var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
5786function write_comments_xml(data) {
5787 var o = [XML_HEADER, CMNT_XML_ROOT];
5788
5789 var iauthor = [];
5790 o.push("<authors>");
5791 data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
5792 if(iauthor.indexOf(a) > -1) return;
5793 iauthor.push(a);
5794 o.push("<author>" + a + "</author>");
5795 }); });
5796 o.push("</authors>");
5797 o.push("<commentList>");
5798 data.forEach(function(d) {
5799 d[1].forEach(function(c) {
5800 /* 18.7.3 CT_Comment */
5801 o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
5802 o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
5803 o.push('</text></comment>');
5804 });
5805 });
5806 o.push("</commentList>");
5807 if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
5808 return o.join("");
5809}
5810var CT_VBA = "application/vnd.ms-office.vbaProject";
5811function make_vba_xls(cfb) {
5812 var newcfb = CFB.utils.cfb_new({root:"R"});
5813 cfb.FullPaths.forEach(function(p, i) {
5814 if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
5815 var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
5816 CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
5817 });
5818 return CFB.write(newcfb);
5819}
5820
5821function fill_vba_xls(cfb, vba) {
5822 vba.FullPaths.forEach(function(p, i) {
5823 if(i == 0) return;
5824 var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
5825 if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
5826 });
5827}
5828
5829var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
5830
5831RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
5832RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
5833
5834/* macro and dialog sheet stubs */
5835function parse_ds_bin() { return {'!type':'dialog'}; }
5836function parse_ds_xml() { return {'!type':'dialog'}; }
5837function parse_ms_bin() { return {'!type':'macro'}; }
5838function parse_ms_xml() { return {'!type':'macro'}; }
5839/* TODO: it will be useful to parse the function str */
5840var rc_to_a1 = (function(){
5841 var rcregex = /(^|[^A-Za-z_])R(\[?-?\d+\]|[1-9]\d*|)C(\[?-?\d+\]|[1-9]\d*|)(?![A-Za-z0-9_])/g;
5842 var rcbase = ({r:0,c:0});
5843 function rcfunc($$,$1,$2,$3) {
5844 var cRel = false, rRel = false;
5845
5846 if($2.length == 0) rRel = true;
5847 else if($2.charAt(0) == "[") { rRel = true; $2 = $2.slice(1, -1); }
5848
5849 if($3.length == 0) cRel = true;
5850 else if($3.charAt(0) == "[") { cRel = true; $3 = $3.slice(1, -1); }
5851
5852 var R = $2.length>0?parseInt($2,10)|0:0, C = $3.length>0?parseInt($3,10)|0:0;
5853
5854 if(cRel) C += rcbase.c; else --C;
5855 if(rRel) R += rcbase.r; else --R;
5856 return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
5857 }
5858 return function rc_to_a1(fstr, base) {
5859 rcbase = base;
5860 return fstr.replace(rcregex, rcfunc);
5861 };
5862})();
5863
5864var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)([1-9]\d{0,5}|10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6])(?![_.\(A-Za-z0-9])/g;
5865var a1_to_rc =(function(){
5866 return function a1_to_rc(fstr, base) {
5867 return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
5868 var c = decode_col($3) - ($2 ? 0 : base.c);
5869 var r = decode_row($5) - ($4 ? 0 : base.r);
5870 var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
5871 var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
5872 return $1 + "R" + R + "C" + C;
5873 });
5874 };
5875})();
5876
5877/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
5878function shift_formula_str(f, delta) {
5879 return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
5880 return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
5881 });
5882}
5883
5884function shift_formula_xlsx(f, range, cell) {
5885 var r = decode_range(range), s = r.s, c = decode_cell(cell);
5886 var delta = {r:c.r - s.r, c:c.c - s.c};
5887 return shift_formula_str(f, delta);
5888}
5889
5890/* TODO: parse formula */
5891function fuzzyfmla(f) {
5892 if(f.length == 1) return false;
5893 return true;
5894}
5895
5896function _xlfn(f) {
5897 return f.replace(/_xlfn\./g,"");
5898}
5899var strs = {}; // shared strings
5900var _ssfopts = {}; // spreadsheet formatting options
5901
5902RELS.WS = [
5903 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
5904 "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
5905];
5906
5907/*global Map */
5908var browser_has_Map = typeof Map !== 'undefined';
5909
5910function get_sst_id(sst, str, rev) {
5911 var i = 0, len = sst.length;
5912 if(rev) {
5913 if(browser_has_Map ? rev.has(str) : rev.hasOwnProperty(str)) {
5914 var revarr = browser_has_Map ? rev.get(str) : rev[str];
5915 for(; i < revarr.length; ++i) {
5916 if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
5917 }
5918 }
5919 } else for(; i < len; ++i) {
5920 if(sst[i].t === str) { sst.Count ++; return i; }
5921 }
5922 sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
5923 if(rev) {
5924 if(browser_has_Map) {
5925 if(!rev.has(str)) rev.set(str, []);
5926 rev.get(str).push(len);
5927 } else {
5928 if(!rev.hasOwnProperty(str)) rev[str] = [];
5929 rev[str].push(len);
5930 }
5931 }
5932 return len;
5933}
5934
5935function col_obj_w(C, col) {
5936 var p = ({min:C+1,max:C+1});
5937 /* wch (chars), wpx (pixels) */
5938 var wch = -1;
5939 if(col.MDW) MDW = col.MDW;
5940 if(col.width != null) p.customWidth = 1;
5941 else if(col.wpx != null) wch = px2char(col.wpx);
5942 else if(col.wch != null) wch = col.wch;
5943 if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
5944 else if(col.width != null) p.width = col.width;
5945 if(col.hidden) p.hidden = true;
5946 return p;
5947}
5948
5949function default_margins(margins, mode) {
5950 if(!margins) return;
5951 var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
5952 if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
5953 if(margins.left == null) margins.left = defs[0];
5954 if(margins.right == null) margins.right = defs[1];
5955 if(margins.top == null) margins.top = defs[2];
5956 if(margins.bottom == null) margins.bottom = defs[3];
5957 if(margins.header == null) margins.header = defs[4];
5958 if(margins.footer == null) margins.footer = defs[5];
5959}
5960
5961function get_cell_style(styles, cell, opts) {
5962 var z = opts.revssf[cell.z != null ? cell.z : "General"];
5963 var i = 0x3c, len = styles.length;
5964 if(z == null && opts.ssf) {
5965 for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
5966 SSF.load(cell.z, i);
5967 // $FlowIgnore
5968 opts.ssf[i] = cell.z;
5969 opts.revssf[cell.z] = z = i;
5970 break;
5971 }
5972 }
5973 for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
5974 styles[len] = {
5975 numFmtId:z,
5976 fontId:0,
5977 fillId:0,
5978 borderId:0,
5979 xfId:0,
5980 applyNumberFormat:1
5981 };
5982 return len;
5983}
5984
5985function safe_format(p, fmtid, fillid, opts, themes, styles) {
5986 if(p.t === 'z') return;
5987 if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
5988 try {
5989 if(opts.cellNF) p.z = SSF._table[fmtid];
5990 } catch(e) { if(opts.WTF) throw e; }
5991 if(!opts || opts.cellText !== false) try {
5992 if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
5993 if(p.t === 'e') p.w = p.w || BErr[p.v];
5994 else if(fmtid === 0) {
5995 if(p.t === 'n') {
5996 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
5997 else p.w = SSF._general_num(p.v);
5998 }
5999 else if(p.t === 'd') {
6000 var dd = datenum(p.v);
6001 if((dd|0) === dd) p.w = SSF._general_int(dd);
6002 else p.w = SSF._general_num(dd);
6003 }
6004 else if(p.v === undefined) return "";
6005 else p.w = SSF._general(p.v,_ssfopts);
6006 }
6007 else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
6008 else p.w = SSF.format(fmtid,p.v,_ssfopts);
6009 } catch(e) { if(opts.WTF) throw e; }
6010 if(!opts.cellStyles) return;
6011 if(fillid != null) try {
6012 p.s = styles.Fills[fillid];
6013 if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
6014 p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
6015 if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
6016 }
6017 if (p.s.bgColor && p.s.bgColor.theme) {
6018 p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
6019 if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
6020 }
6021 } catch(e) { if(opts.WTF && styles.Fills) throw e; }
6022}
6023
6024function check_ws(ws, sname, i) {
6025 if(ws && ws['!ref']) {
6026 var range = safe_decode_range(ws['!ref']);
6027 if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
6028 }
6029}
6030function parse_ws_xml_dim(ws, s) {
6031 var d = safe_decode_range(s);
6032 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);
6033}
6034var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
6035var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
6036var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
6037var dimregex = /"(\w*:\w*)"/;
6038var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
6039var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
6040var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
6041var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
6042var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
6043
6044/* 18.3 Worksheets */
6045function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
6046 if(!data) return data;
6047 if(!rels) rels = {'!id':{}};
6048 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
6049
6050 /* 18.3.1.99 worksheet CT_Worksheet */
6051 var s = opts.dense ? ([]) : ({});
6052 var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
6053
6054 var data1 = "", data2 = "";
6055 var mtch = data.match(sheetdataregex);
6056 if(mtch) {
6057 data1 = data.slice(0, mtch.index);
6058 data2 = data.slice(mtch.index + mtch[0].length);
6059 } else data1 = data2 = data;
6060
6061 /* 18.3.1.82 sheetPr CT_SheetPr */
6062 var sheetPr = data1.match(sheetprregex);
6063 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
6064
6065 /* 18.3.1.35 dimension CT_SheetDimension */
6066 var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
6067 if(ridx > 0) {
6068 var ref = data1.slice(ridx,ridx+50).match(dimregex);
6069 if(ref) parse_ws_xml_dim(s, ref[1]);
6070 }
6071
6072 /* 18.3.1.88 sheetViews CT_SheetViews */
6073 var svs = data1.match(svsregex);
6074 if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
6075
6076 /* 18.3.1.17 cols CT_Cols */
6077 var columns = [];
6078 if(opts.cellStyles) {
6079 /* 18.3.1.13 col CT_Col */
6080 var cols = data1.match(colregex);
6081 if(cols) parse_ws_xml_cols(columns, cols);
6082 }
6083
6084 /* 18.3.1.80 sheetData CT_SheetData ? */
6085 if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
6086
6087 /* 18.3.1.2 autoFilter CT_AutoFilter */
6088 var afilter = data2.match(afregex);
6089 if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
6090
6091 /* 18.3.1.55 mergeCells CT_MergeCells */
6092 var merges = [];
6093 var _merge = data2.match(mergecregex);
6094 if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
6095 merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
6096
6097 /* 18.3.1.48 hyperlinks CT_Hyperlinks */
6098 var hlink = data2.match(hlinkregex);
6099 if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
6100
6101 /* 18.3.1.62 pageMargins CT_PageMargins */
6102 var margins = data2.match(marginregex);
6103 if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
6104
6105 if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
6106 if(opts.sheetRows > 0 && s["!ref"]) {
6107 var tmpref = safe_decode_range(s["!ref"]);
6108 if(opts.sheetRows <= +tmpref.e.r) {
6109 tmpref.e.r = opts.sheetRows - 1;
6110 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
6111 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
6112 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
6113 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
6114 s["!fullref"] = s["!ref"];
6115 s["!ref"] = encode_range(tmpref);
6116 }
6117 }
6118 if(columns.length > 0) s["!cols"] = columns;
6119 if(merges.length > 0) s["!merges"] = merges;
6120 return s;
6121}
6122
6123function write_ws_xml_merges(merges) {
6124 if(merges.length === 0) return "";
6125 var o = '<mergeCells count="' + merges.length + '">';
6126 for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
6127 return o + '</mergeCells>';
6128}
6129
6130/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
6131function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
6132 var data = parsexmltag(sheetPr);
6133 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
6134 if(data.codeName) wb.Sheets[idx].CodeName = data.codeName;
6135}
6136function write_ws_xml_sheetpr(ws, wb, idx, opts, o) {
6137 var needed = false;
6138 var props = {}, payload = null;
6139 if(opts.bookType !== 'xlsx' && wb.vbaraw) {
6140 var cname = wb.SheetNames[idx];
6141 try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
6142 needed = true;
6143 props.codeName = escapexml(cname);
6144 }
6145
6146 if(!needed && !payload) return;
6147 o[o.length] = (writextag('sheetPr', payload, props));
6148}
6149
6150/* 18.3.1.85 sheetProtection CT_SheetProtection */
6151var sheetprot_deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
6152var sheetprot_deftrue = [
6153 "formatColumns", "formatRows", "formatCells",
6154 "insertColumns", "insertRows", "insertHyperlinks",
6155 "deleteColumns", "deleteRows",
6156 "sort", "autoFilter", "pivotTables"
6157];
6158function write_ws_xml_protection(sp) {
6159 // algorithmName, hashValue, saltValue, spinCountpassword
6160 var o = ({sheet:1});
6161 sheetprot_deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
6162 sheetprot_deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
6163 /* TODO: algorithm */
6164 if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
6165 return writextag('sheetProtection', null, o);
6166}
6167
6168function parse_ws_xml_hlinks(s, data, rels) {
6169 var dense = Array.isArray(s);
6170 for(var i = 0; i != data.length; ++i) {
6171 var val = parsexmltag(utf8read(data[i]), true);
6172 if(!val.ref) return;
6173 var rel = ((rels || {})['!id']||[])[val.id];
6174 if(rel) {
6175 val.Target = rel.Target;
6176 if(val.location) val.Target += "#"+val.location;
6177 } else {
6178 val.Target = "#" + val.location;
6179 rel = {Target: val.Target, TargetMode: 'Internal'};
6180 }
6181 val.Rel = rel;
6182 if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
6183 var rng = safe_decode_range(val.ref);
6184 for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
6185 var addr = encode_cell({c:C,r:R});
6186 if(dense) {
6187 if(!s[R]) s[R] = [];
6188 if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
6189 s[R][C].l = val;
6190 } else {
6191 if(!s[addr]) s[addr] = {t:"z",v:undefined};
6192 s[addr].l = val;
6193 }
6194 }
6195 }
6196}
6197
6198function parse_ws_xml_margins(margin) {
6199 var o = {};
6200 ["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
6201 if(margin[k]) o[k] = parseFloat(margin[k]);
6202 });
6203 return o;
6204}
6205function write_ws_xml_margins(margin) {
6206 default_margins(margin);
6207 return writextag('pageMargins', null, margin);
6208}
6209
6210function parse_ws_xml_cols(columns, cols) {
6211 var seencol = false;
6212 for(var coli = 0; coli != cols.length; ++coli) {
6213 var coll = parsexmltag(cols[coli], true);
6214 if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
6215 var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
6216 delete coll.min; delete coll.max; coll.width = +coll.width;
6217 if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
6218 process_col(coll);
6219 while(colm <= colM) columns[colm++] = dup(coll);
6220 }
6221}
6222function write_ws_xml_cols(ws, cols) {
6223 var o = ["<cols>"], col;
6224 for(var i = 0; i != cols.length; ++i) {
6225 if(!(col = cols[i])) continue;
6226 o[o.length] = (writextag('col', null, col_obj_w(i, col)));
6227 }
6228 o[o.length] = "</cols>";
6229 return o.join("");
6230}
6231
6232function parse_ws_xml_autofilter(data) {
6233 var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
6234 return o;
6235}
6236function write_ws_xml_autofilter(data, ws, wb, idx) {
6237 var ref = typeof data.ref == "string" ? data.ref : encode_range(data.ref);
6238 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
6239 if(!wb.Workbook.Names) wb.Workbook.Names = [];
6240 var names = wb.Workbook.Names;
6241 var range = decode_range(ref);
6242 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
6243 for(var i = 0; i < names.length; ++i) {
6244 var name = names[i];
6245 if(name.Name != '_xlnm._FilterDatabase') continue;
6246 if(name.Sheet != idx) continue;
6247 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
6248 }
6249 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
6250 return writextag("autoFilter", null, {ref:ref});
6251}
6252
6253/* 18.3.1.88 sheetViews CT_SheetViews */
6254/* 18.3.1.87 sheetView CT_SheetView */
6255var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/;
6256function parse_ws_xml_sheetviews(data, wb) {
6257 if(!wb.Views) wb.Views = [{}];
6258 (data.match(sviewregex)||[]).forEach(function(r, i) {
6259 var tag = parsexmltag(r);
6260 // $FlowIgnore
6261 if(!wb.Views[i]) wb.Views[i] = {};
6262 // $FlowIgnore
6263 if(parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true;
6264 });
6265}
6266function write_ws_xml_sheetviews(ws, opts, idx, wb) {
6267 var sview = ({workbookViewId:"0"});
6268 // $FlowIgnore
6269 if((((wb||{}).Workbook||{}).Views||[])[0]) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
6270 return writextag("sheetViews", writextag("sheetView", null, sview), {});
6271}
6272
6273function write_ws_xml_cell(cell, ref, ws, opts) {
6274 if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return "";
6275 var vv = "";
6276 var oldt = cell.t, oldv = cell.v;
6277 if(cell.t !== "z") switch(cell.t) {
6278 case 'b': vv = cell.v ? "1" : "0"; break;
6279 case 'n': vv = ''+cell.v; break;
6280 case 'e': vv = BErr[cell.v]; break;
6281 case 'd':
6282 if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
6283 else {
6284 cell = dup(cell);
6285 cell.t = 'n';
6286 vv = ''+(cell.v = datenum(parseDate(cell.v)));
6287 }
6288 if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
6289 break;
6290 default: vv = cell.v; break;
6291 }
6292 var v = writetag('v', escapexml(vv)), o = ({r:ref});
6293 /* TODO: cell style */
6294 var os = get_cell_style(opts.cellXfs, cell, opts);
6295 if(os !== 0) o.s = os;
6296 switch(cell.t) {
6297 case 'n': break;
6298 case 'd': o.t = "d"; break;
6299 case 'b': o.t = "b"; break;
6300 case 'e': o.t = "e"; break;
6301 case 'z': break;
6302 default: if(cell.v == null) { delete cell.t; break; }
6303 if(opts && opts.bookSST) {
6304 v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
6305 o.t = "s"; break;
6306 }
6307 o.t = "str"; break;
6308 }
6309 if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
6310 if(cell.f) {
6311 var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
6312 v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
6313 }
6314 if(cell.l) ws['!links'].push([ref, cell.l]);
6315 if(cell.c) ws['!comments'].push([ref, cell.c]);
6316 return writextag('c', v, o);
6317}
6318
6319var parse_ws_xml_data = (function() {
6320 var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/;
6321 var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
6322 var refregex = /ref=["']([^"']*)["']/;
6323 var match_v = matchtag("v"), match_f = matchtag("f");
6324
6325return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
6326 var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
6327 var tag, tagr = 0, tagc = 0;
6328 var sstr, ftag;
6329 var fmtid = 0, fillid = 0;
6330 var do_format = Array.isArray(styles.CellXf), cf;
6331 var arrayf = [];
6332 var sharedf = [];
6333 var dense = Array.isArray(s);
6334 var rows = [], rowobj = {}, rowrite = false;
6335 for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
6336 x = marr[mt].trim();
6337 var xlen = x.length;
6338 if(xlen === 0) continue;
6339
6340 /* 18.3.1.73 row CT_Row */
6341 for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
6342 tag = parsexmltag(x.slice(0,ri), true);
6343 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
6344 if(opts.sheetRows && opts.sheetRows < tagr) continue;
6345 if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
6346 if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
6347
6348 if(opts && opts.cellStyles) {
6349 rowobj = {}; rowrite = false;
6350 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
6351 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
6352 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
6353 if(rowrite) rows[tagr-1] = rowobj;
6354 }
6355
6356 /* 18.3.1.4 c CT_Cell */
6357 cells = x.slice(ri).split(cellregex);
6358 for(var rslice = 0; rslice != cells.length; ++rslice) if(cells[rslice].trim().charAt(0) != "<") break;
6359 cells = cells.slice(rslice);
6360 for(ri = 0; ri != cells.length; ++ri) {
6361 x = cells[ri].trim();
6362 if(x.length === 0) continue;
6363 cref = x.match(rregex); idx = ri; i=0; cc=0;
6364 x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
6365 if(cref != null && cref.length === 2) {
6366 idx = 0; d=cref[1];
6367 for(i=0; i != d.length; ++i) {
6368 if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
6369 idx = 26*idx + cc;
6370 }
6371 --idx;
6372 tagc = idx;
6373 } else ++tagc;
6374 for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
6375 tag = parsexmltag(x.slice(0,i), true);
6376 if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
6377 d = x.slice(i);
6378 p = ({t:""});
6379
6380 if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
6381 if(opts.cellFormula) {
6382 if((cref=d.match(match_f))!= null && cref[1] !== '') {
6383 /* TODO: match against XLSXFutureFunctions */
6384 p.f=_xlfn(unescapexml(utf8read(cref[1])));
6385 if(cref[0].indexOf('t="array"') > -1) {
6386 p.F = (d.match(refregex)||[])[1];
6387 if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
6388 } else if(cref[0].indexOf('t="shared"') > -1) {
6389 // TODO: parse formula
6390 ftag = parsexmltag(cref[0]);
6391 sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1]))), tag.r];
6392 }
6393 } else if((cref=d.match(/<f[^>]*\/>/))) {
6394 ftag = parsexmltag(cref[0]);
6395 if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
6396 }
6397 /* TODO: factor out contains logic */
6398 var _tag = decode_cell(tag.r);
6399 for(i = 0; i < arrayf.length; ++i)
6400 if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
6401 if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
6402 p.F = arrayf[i][1];
6403 }
6404
6405 if(tag.t == null && p.v === undefined) {
6406 if(p.f || p.F) {
6407 p.v = 0; p.t = "n";
6408 } else if(!opts.sheetStubs) continue;
6409 else p.t = "z";
6410 }
6411 else p.t = tag.t || "n";
6412 if(guess.s.c > tagc) guess.s.c = tagc;
6413 if(guess.e.c < tagc) guess.e.c = tagc;
6414 /* 18.18.11 t ST_CellType */
6415 switch(p.t) {
6416 case 'n':
6417 if(p.v == "" || p.v == null) {
6418 if(!opts.sheetStubs) continue;
6419 p.t = 'z';
6420 } else p.v = parseFloat(p.v);
6421 break;
6422 case 's':
6423 if(typeof p.v == 'undefined') {
6424 if(!opts.sheetStubs) continue;
6425 p.t = 'z';
6426 } else {
6427 sstr = strs[parseInt(p.v, 10)];
6428 p.v = sstr.t;
6429 p.r = sstr.r;
6430 if(opts.cellHTML) p.h = sstr.h;
6431 }
6432 break;
6433 case 'str':
6434 p.t = "s";
6435 p.v = (p.v!=null) ? utf8read(p.v) : '';
6436 if(opts.cellHTML) p.h = escapehtml(p.v);
6437 break;
6438 case 'inlineStr':
6439 cref = d.match(isregex);
6440 p.t = 's';
6441 if(cref != null && (sstr = parse_si(cref[1]))) {
6442 p.v = sstr.t;
6443 if(opts.cellHTML) p.h = sstr.h;
6444 } else p.v = "";
6445 break;
6446 case 'b': p.v = parsexmlbool(p.v); break;
6447 case 'd':
6448 if(opts.cellDates) p.v = parseDate(p.v, 1);
6449 else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
6450 break;
6451 /* error string in .w, number in .v */
6452 case 'e':
6453 if(!opts || opts.cellText !== false) p.w = p.v;
6454 p.v = RBErr[p.v]; break;
6455 }
6456 /* formatting */
6457 fmtid = fillid = 0;
6458 cf = null;
6459 if(do_format && tag.s !== undefined) {
6460 cf = styles.CellXf[tag.s];
6461 if(cf != null) {
6462 if(cf.numFmtId != null) fmtid = cf.numFmtId;
6463 if(opts.cellStyles) {
6464 if(cf.fillId != null) fillid = cf.fillId;
6465 }
6466 }
6467 }
6468 safe_format(p, fmtid, fillid, opts, themes, styles);
6469 if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
6470 if(dense) {
6471 var _r = decode_cell(tag.r);
6472 if(!s[_r.r]) s[_r.r] = [];
6473 s[_r.r][_r.c] = p;
6474 } else s[tag.r] = p;
6475 }
6476 }
6477 if(rows.length > 0) s['!rows'] = rows;
6478}; })();
6479
6480function write_ws_xml_data(ws, opts, idx, wb) {
6481 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
6482 var dense = Array.isArray(ws);
6483 var params = ({r:rr}), row, height = -1;
6484 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
6485 for(R = range.s.r; R <= range.e.r; ++R) {
6486 r = [];
6487 rr = encode_row(R);
6488 for(C = range.s.c; C <= range.e.c; ++C) {
6489 ref = cols[C] + rr;
6490 var _cell = dense ? (ws[R]||[])[C]: ws[ref];
6491 if(_cell === undefined) continue;
6492 if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
6493 }
6494 if(r.length > 0 || (rows && rows[R])) {
6495 params = ({r:rr});
6496 if(rows && rows[R]) {
6497 row = rows[R];
6498 if(row.hidden) params.hidden = 1;
6499 height = -1;
6500 if(row.hpx) height = px2pt(row.hpx);
6501 else if(row.hpt) height = row.hpt;
6502 if(height > -1) { params.ht = height; params.customHeight = 1; }
6503 if(row.level) { params.outlineLevel = row.level; }
6504 }
6505 o[o.length] = (writextag('row', r.join(""), params));
6506 }
6507 }
6508 if(rows) for(; R < rows.length; ++R) {
6509 if(rows && rows[R]) {
6510 params = ({r:R+1});
6511 row = rows[R];
6512 if(row.hidden) params.hidden = 1;
6513 height = -1;
6514 if (row.hpx) height = px2pt(row.hpx);
6515 else if (row.hpt) height = row.hpt;
6516 if (height > -1) { params.ht = height; params.customHeight = 1; }
6517 if (row.level) { params.outlineLevel = row.level; }
6518 o[o.length] = (writextag('row', "", params));
6519 }
6520 }
6521 return o.join("");
6522}
6523
6524var WS_XML_ROOT = writextag('worksheet', null, {
6525 'xmlns': XMLNS.main[0],
6526 'xmlns:r': XMLNS.r
6527});
6528
6529function write_ws_xml(idx, opts, wb, rels) {
6530 var o = [XML_HEADER, WS_XML_ROOT];
6531 var s = wb.SheetNames[idx], sidx = 0, rdata = "";
6532 var ws = wb.Sheets[s];
6533 if(ws == null) ws = {};
6534 var ref = ws['!ref'] || 'A1';
6535 var range = safe_decode_range(ref);
6536 if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
6537 if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
6538 range.e.c = Math.min(range.e.c, 0x3FFF);
6539 range.e.r = Math.min(range.e.c, 0xFFFFF);
6540 ref = encode_range(range);
6541 }
6542 if(!rels) rels = {};
6543 ws['!comments'] = [];
6544 var _drawing = [];
6545
6546 write_ws_xml_sheetpr(ws, wb, idx, opts, o);
6547
6548 o[o.length] = (writextag('dimension', null, {'ref': ref}));
6549
6550 o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
6551
6552 /* TODO: store in WB, process styles */
6553 if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
6554 defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
6555 baseColWidth:opts.sheetFormat.baseColWidth||'10',
6556 outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
6557 }));
6558
6559 if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
6560
6561 o[sidx = o.length] = '<sheetData/>';
6562 ws['!links'] = [];
6563 if(ws['!ref'] != null) {
6564 rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
6565 if(rdata.length > 0) o[o.length] = (rdata);
6566 }
6567 if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
6568
6569 /* sheetCalcPr */
6570
6571 if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
6572
6573 /* protectedRanges */
6574 /* scenarios */
6575
6576 if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter'], ws, wb, idx);
6577
6578 /* sortState */
6579 /* dataConsolidate */
6580 /* customSheetViews */
6581
6582 if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
6583
6584 /* phoneticPr */
6585 /* conditionalFormatting */
6586 /* dataValidations */
6587
6588 var relc = -1, rel, rId = -1;
6589 if(ws['!links'].length > 0) {
6590 o[o.length] = "<hyperlinks>";
6591ws['!links'].forEach(function(l) {
6592 if(!l[1].Target) return;
6593 rel = ({"ref":l[0]});
6594 if(l[1].Target.charAt(0) != "#") {
6595 rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
6596 rel["r:id"] = "rId"+rId;
6597 }
6598 if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
6599 if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
6600 o[o.length] = writextag("hyperlink",null,rel);
6601 });
6602 o[o.length] = "</hyperlinks>";
6603 }
6604 delete ws['!links'];
6605
6606 /* printOptions */
6607
6608 if(ws['!margins'] != null) o[o.length] = write_ws_xml_margins(ws['!margins']);
6609
6610 /* pageSetup */
6611 /* headerFooter */
6612 /* rowBreaks */
6613 /* colBreaks */
6614 /* customProperties */
6615 /* cellWatches */
6616
6617 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
6618
6619 /* smartTags */
6620
6621 if(_drawing.length > 0) {
6622 rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
6623 o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
6624 ws['!drawing'] = _drawing;
6625 }
6626
6627 if(ws['!comments'].length > 0) {
6628 rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
6629 o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
6630 ws['!legacy'] = rId;
6631 }
6632
6633 /* legacyDrawingHF */
6634 /* picture */
6635 /* oleObjects */
6636 /* controls */
6637 /* webPublishItems */
6638 /* tableParts */
6639 /* extLst */
6640
6641 if(o.length>1) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
6642 return o.join("");
6643}
6644RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
6645RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
6646
6647function parse_Cache(data) {
6648 var col = [];
6649 var num = data.match(/^<c:numCache>/);
6650 var f;
6651
6652 /* 21.2.2.150 pt CT_NumVal */
6653 (data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
6654 var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
6655 if(!q) return;
6656 col[+q[1]] = num ? +q[2] : q[2];
6657 });
6658
6659 /* 21.2.2.71 formatCode CT_Xstring */
6660 var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
6661
6662 (data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); });
6663
6664 return [col, nf, f];
6665}
6666
6667/* 21.2 DrawingML - Charts */
6668function parse_chart(data, name, opts, rels, wb, csheet) {
6669 var cs = ((csheet || {"!type":"chart"}));
6670 if(!data) return csheet;
6671 /* 21.2.2.27 chart CT_Chart */
6672
6673 var C = 0, R = 0, col = "A";
6674 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
6675
6676 /* 21.2.2.120 numCache CT_NumData */
6677 (data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
6678 var cache = parse_Cache(nc);
6679 refguess.s.r = refguess.s.c = 0;
6680 refguess.e.c = C;
6681 col = encode_col(C);
6682 cache[0].forEach(function(n,i) {
6683 cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
6684 R = i;
6685 });
6686 if(refguess.e.r < R) refguess.e.r = R;
6687 ++C;
6688 });
6689 if(C > 0) cs["!ref"] = encode_range(refguess);
6690 return cs;
6691}
6692RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
6693
6694var CS_XML_ROOT = writextag('chartsheet', null, {
6695 'xmlns': XMLNS.main[0],
6696 'xmlns:r': XMLNS.r
6697});
6698
6699/* 18.3 Worksheets also covers Chartsheets */
6700function parse_cs_xml(data, opts, idx, rels, wb) {
6701 if(!data) return data;
6702 /* 18.3.1.12 chartsheet CT_ChartSheet */
6703 if(!rels) rels = {'!id':{}};
6704 var s = ({'!type':"chart", '!drawel':null, '!rel':""});
6705 var m;
6706
6707 /* 18.3.1.83 sheetPr CT_ChartsheetPr */
6708 var sheetPr = data.match(sheetprregex);
6709 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
6710
6711 /* 18.3.1.36 drawing CT_Drawing */
6712 if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
6713
6714 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
6715 return s;
6716}
6717function write_cs_xml(idx, opts, wb, rels) {
6718 var o = [XML_HEADER, CS_XML_ROOT];
6719 o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
6720 add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
6721 if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
6722 return o.join("");
6723}
6724
6725/* [MS-XLSB] 2.4.331 BrtCsProp */
6726function parse_BrtCsProp(data, length) {
6727 data.l += 10;
6728 var name = parse_XLWideString(data, length - 10);
6729 return { name: name };
6730}
6731
6732/* [MS-XLSB] 2.1.7.7 Chart Sheet */
6733function parse_cs_bin(data, opts, idx, rels, wb) {
6734 if(!data) return data;
6735 if(!rels) rels = {'!id':{}};
6736 var s = {'!type':"chart", '!drawel':null, '!rel':""};
6737 var state = [];
6738 var pass = false;
6739 recordhopper(data, function cs_parse(val, R_n, RT) {
6740 switch(RT) {
6741
6742 case 0x0226: /* 'BrtDrawing' */
6743 s['!rel'] = val; break;
6744
6745 case 0x028B: /* 'BrtCsProp' */
6746 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
6747 if(val.name) wb.Sheets[idx].CodeName = val.name;
6748 break;
6749
6750 case 0x0232: /* 'BrtBkHim' */
6751 case 0x028C: /* 'BrtCsPageSetup' */
6752 case 0x029D: /* 'BrtCsProtection' */
6753 case 0x02A7: /* 'BrtCsProtectionIso' */
6754 case 0x0227: /* 'BrtLegacyDrawing' */
6755 case 0x0228: /* 'BrtLegacyDrawingHF' */
6756 case 0x01DC: /* 'BrtMargins' */
6757 case 0x0C00: /* 'BrtUid' */
6758 break;
6759
6760 case 0x0023: /* 'BrtFRTBegin' */
6761 pass = true; break;
6762 case 0x0024: /* 'BrtFRTEnd' */
6763 pass = false; break;
6764 case 0x0025: /* 'BrtACBegin' */
6765 state.push(R_n); break;
6766 case 0x0026: /* 'BrtACEnd' */
6767 state.pop(); break;
6768
6769 default:
6770 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
6771 else if((R_n||"").indexOf("End") > 0) state.pop();
6772 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
6773 }
6774 }, opts);
6775
6776 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
6777 return s;
6778}
6779function write_cs_bin() {
6780 var ba = buf_array();
6781 write_record(ba, "BrtBeginSheet");
6782 /* [BrtCsProp] */
6783 /* CSVIEWS */
6784 /* [[BrtCsProtectionIso] BrtCsProtection] */
6785 /* [USERCSVIEWS] */
6786 /* [BrtMargins] */
6787 /* [BrtCsPageSetup] */
6788 /* [HEADERFOOTER] */
6789 /* BrtDrawing */
6790 /* [BrtLegacyDrawing] */
6791 /* [BrtLegacyDrawingHF] */
6792 /* [BrtBkHim] */
6793 /* [WEBPUBITEMS] */
6794 /* FRTCHARTSHEET */
6795 write_record(ba, "BrtEndSheet");
6796 return ba.end();
6797}
6798/* 18.2.28 (CT_WorkbookProtection) Defaults */
6799var WBPropsDef = [
6800 ['allowRefreshQuery', false, "bool"],
6801 ['autoCompressPictures', true, "bool"],
6802 ['backupFile', false, "bool"],
6803 ['checkCompatibility', false, "bool"],
6804 ['CodeName', ''],
6805 ['date1904', false, "bool"],
6806 ['defaultThemeVersion', 0, "int"],
6807 ['filterPrivacy', false, "bool"],
6808 ['hidePivotFieldList', false, "bool"],
6809 ['promptedSolutions', false, "bool"],
6810 ['publishItems', false, "bool"],
6811 ['refreshAllConnections', false, "bool"],
6812 ['saveExternalLinkValues', true, "bool"],
6813 ['showBorderUnselectedTables', true, "bool"],
6814 ['showInkAnnotation', true, "bool"],
6815 ['showObjects', 'all'],
6816 ['showPivotChartFilter', false, "bool"],
6817 ['updateLinks', 'userSet']
6818];
6819
6820/* 18.2.30 (CT_BookView) Defaults */
6821var WBViewDef = [
6822 ['activeTab', 0, "int"],
6823 ['autoFilterDateGrouping', true, "bool"],
6824 ['firstSheet', 0, "int"],
6825 ['minimized', false, "bool"],
6826 ['showHorizontalScroll', true, "bool"],
6827 ['showSheetTabs', true, "bool"],
6828 ['showVerticalScroll', true, "bool"],
6829 ['tabRatio', 600, "int"],
6830 ['visibility', 'visible']
6831 //window{Height,Width}, {x,y}Window
6832];
6833
6834/* 18.2.19 (CT_Sheet) Defaults */
6835var SheetDef = [
6836 //['state', 'visible']
6837];
6838
6839/* 18.2.2 (CT_CalcPr) Defaults */
6840var CalcPrDef = [
6841 ['calcCompleted', 'true'],
6842 ['calcMode', 'auto'],
6843 ['calcOnSave', 'true'],
6844 ['concurrentCalc', 'true'],
6845 ['fullCalcOnLoad', 'false'],
6846 ['fullPrecision', 'true'],
6847 ['iterate', 'false'],
6848 ['iterateCount', '100'],
6849 ['iterateDelta', '0.001'],
6850 ['refMode', 'A1']
6851];
6852
6853/* 18.2.3 (CT_CustomWorkbookView) Defaults */
6854/*var CustomWBViewDef = [
6855 ['autoUpdate', 'false'],
6856 ['changesSavedWin', 'false'],
6857 ['includeHiddenRowCol', 'true'],
6858 ['includePrintSettings', 'true'],
6859 ['maximized', 'false'],
6860 ['minimized', 'false'],
6861 ['onlySync', 'false'],
6862 ['personalView', 'false'],
6863 ['showComments', 'commIndicator'],
6864 ['showFormulaBar', 'true'],
6865 ['showHorizontalScroll', 'true'],
6866 ['showObjects', 'all'],
6867 ['showSheetTabs', 'true'],
6868 ['showStatusbar', 'true'],
6869 ['showVerticalScroll', 'true'],
6870 ['tabRatio', '600'],
6871 ['xWindow', '0'],
6872 ['yWindow', '0']
6873];*/
6874
6875function push_defaults_array(target, defaults) {
6876 for(var j = 0; j != target.length; ++j) { var w = target[j];
6877 for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
6878 if(w[z[0]] == null) w[z[0]] = z[1];
6879 else switch(z[2]) {
6880 case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
6881 case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
6882 }
6883 }
6884 }
6885}
6886function push_defaults(target, defaults) {
6887 for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
6888 if(target[z[0]] == null) target[z[0]] = z[1];
6889 else switch(z[2]) {
6890 case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
6891 case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
6892 }
6893 }
6894}
6895
6896function parse_wb_defaults(wb) {
6897 push_defaults(wb.WBProps, WBPropsDef);
6898 push_defaults(wb.CalcPr, CalcPrDef);
6899
6900 push_defaults_array(wb.WBView, WBViewDef);
6901 push_defaults_array(wb.Sheets, SheetDef);
6902
6903 _ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
6904}
6905
6906function safe1904(wb) {
6907 /* TODO: store date1904 somewhere else */
6908 if(!wb.Workbook) return "false";
6909 if(!wb.Workbook.WBProps) return "false";
6910 return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
6911}
6912
6913var badchars = "][*?\/\\".split("");
6914function check_ws_name(n, safe) {
6915 if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
6916 var _good = true;
6917 badchars.forEach(function(c) {
6918 if(n.indexOf(c) == -1) return;
6919 if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
6920 _good = false;
6921 });
6922 return _good;
6923}
6924function check_wb_names(N, S, codes) {
6925 N.forEach(function(n,i) {
6926 check_ws_name(n);
6927 for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
6928 if(codes) {
6929 var cn = (S && S[i] && S[i].CodeName) || n;
6930 if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
6931 }
6932 });
6933}
6934function check_wb(wb) {
6935 if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
6936 if(!wb.SheetNames.length) throw new Error("Workbook is empty");
6937 var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
6938 check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
6939 for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
6940 /* TODO: validate workbook */
6941}
6942/* 18.2 Workbook */
6943var wbnsregex = /<\w+:workbook/;
6944function parse_wb_xml(data, opts) {
6945 if(!data) throw new Error("Could not find file");
6946 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
6947 var pass = false, xmlns = "xmlns";
6948 var dname = {}, dnstart = 0;
6949 data.replace(tagregex, function xml_wb(x, idx) {
6950 var y = parsexmltag(x);
6951 switch(strip_ns(y[0])) {
6952 case '<?xml': break;
6953
6954 /* 18.2.27 workbook CT_Workbook 1 */
6955 case '<workbook':
6956 if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
6957 wb.xmlns = y[xmlns];
6958 break;
6959 case '</workbook>': break;
6960
6961 /* 18.2.13 fileVersion CT_FileVersion ? */
6962 case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
6963 case '<fileVersion/>': case '</fileVersion>': break;
6964
6965 /* 18.2.12 fileSharing CT_FileSharing ? */
6966 case '<fileSharing':
6967 break;
6968 case '<fileSharing/>': break;
6969
6970 /* 18.2.28 workbookPr CT_WorkbookPr ? */
6971 case '<workbookPr':
6972 case '<workbookPr/>':
6973 WBPropsDef.forEach(function(w) {
6974 if(y[w[0]] == null) return;
6975 switch(w[2]) {
6976 case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
6977 case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
6978 default: wb.WBProps[w[0]] = y[w[0]];
6979 }
6980 });
6981 if(y.codeName) wb.WBProps.CodeName = y.codeName;
6982 break;
6983 case '</workbookPr>': break;
6984
6985 /* 18.2.29 workbookProtection CT_WorkbookProtection ? */
6986 case '<workbookProtection':
6987 break;
6988 case '<workbookProtection/>': break;
6989
6990 /* 18.2.1 bookViews CT_BookViews ? */
6991 case '<bookViews': case '<bookViews>': case '</bookViews>': break;
6992 /* 18.2.30 workbookView CT_BookView + */
6993 case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
6994 case '</workbookView>': break;
6995
6996 /* 18.2.20 sheets CT_Sheets 1 */
6997 case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
6998 /* 18.2.19 sheet CT_Sheet + */
6999 case '<sheet':
7000 switch(y.state) {
7001 case "hidden": y.Hidden = 1; break;
7002 case "veryHidden": y.Hidden = 2; break;
7003 default: y.Hidden = 0;
7004 }
7005 delete y.state;
7006 y.name = unescapexml(utf8read(y.name));
7007 delete y[0]; wb.Sheets.push(y); break;
7008 case '</sheet>': break;
7009
7010 /* 18.2.15 functionGroups CT_FunctionGroups ? */
7011 case '<functionGroups': case '<functionGroups/>': break;
7012 /* 18.2.14 functionGroup CT_FunctionGroup + */
7013 case '<functionGroup': break;
7014
7015 /* 18.2.9 externalReferences CT_ExternalReferences ? */
7016 case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
7017 /* 18.2.8 externalReference CT_ExternalReference + */
7018 case '<externalReference': break;
7019
7020 /* 18.2.6 definedNames CT_DefinedNames ? */
7021 case '<definedNames/>': break;
7022 case '<definedNames>': case '<definedNames': pass=true; break;
7023 case '</definedNames>': pass=false; break;
7024 /* 18.2.5 definedName CT_DefinedName + */
7025 case '<definedName': {
7026 dname = {};
7027 dname.Name = utf8read(y.name);
7028 if(y.comment) dname.Comment = y.comment;
7029 if(y.localSheetId) dname.Sheet = +y.localSheetId;
7030 if(parsexmlbool(y.hidden||"0")) dname.Hidden = true;
7031 dnstart = idx + x.length;
7032 } break;
7033 case '</definedName>': {
7034 dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
7035 wb.Names.push(dname);
7036 } break;
7037 case '<definedName/>': break;
7038
7039 /* 18.2.2 calcPr CT_CalcPr ? */
7040 case '<calcPr': delete y[0]; wb.CalcPr = y; break;
7041 case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
7042 case '</calcPr>': break;
7043
7044 /* 18.2.16 oleSize CT_OleSize ? (ref required) */
7045 case '<oleSize': break;
7046
7047 /* 18.2.4 customWorkbookViews CT_CustomWorkbookViews ? */
7048 case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
7049 /* 18.2.3 customWorkbookView CT_CustomWorkbookView + */
7050 case '<customWorkbookView': case '</customWorkbookView>': break;
7051
7052 /* 18.2.18 pivotCaches CT_PivotCaches ? */
7053 case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
7054 /* 18.2.17 pivotCache CT_PivotCache ? */
7055 case '<pivotCache': break;
7056
7057 /* 18.2.21 smartTagPr CT_SmartTagPr ? */
7058 case '<smartTagPr': case '<smartTagPr/>': break;
7059
7060 /* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
7061 case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
7062 /* 18.2.22 smartTagType CT_SmartTagType ? */
7063 case '<smartTagType': break;
7064
7065 /* 18.2.24 webPublishing CT_WebPublishing ? */
7066 case '<webPublishing': case '<webPublishing/>': break;
7067
7068 /* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
7069 case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
7070
7071 /* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
7072 case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
7073 /* 18.2.25 webPublishObject CT_WebPublishObject ? */
7074 case '<webPublishObject': break;
7075
7076 /* 18.2.10 extLst CT_ExtensionList ? */
7077 case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
7078 /* 18.2.7 ext CT_Extension + */
7079 case '<ext': pass=true; break; //TODO: check with versions of excel
7080 case '</ext>': pass=false; break;
7081
7082 /* Others */
7083 case '<ArchID': break;
7084 case '<AlternateContent':
7085 case '<AlternateContent>': pass=true; break;
7086 case '</AlternateContent>': pass=false; break;
7087
7088 /* TODO */
7089 case '<revisionPtr': break;
7090
7091 default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
7092 }
7093 return x;
7094 });
7095 if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
7096
7097 parse_wb_defaults(wb);
7098
7099 return wb;
7100}
7101
7102var WB_XML_ROOT = writextag('workbook', null, {
7103 'xmlns': XMLNS.main[0],
7104 //'xmlns:mx': XMLNS.mx,
7105 //'xmlns:s': XMLNS.main[0],
7106 'xmlns:r': XMLNS.r
7107});
7108
7109function write_wb_xml(wb) {
7110 var o = [XML_HEADER];
7111 o[o.length] = WB_XML_ROOT;
7112
7113 var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
7114
7115 /* fileVersion */
7116 /* fileSharing */
7117
7118 var workbookPr = ({codeName:"ThisWorkbook"});
7119 if(wb.Workbook && wb.Workbook.WBProps) {
7120 WBPropsDef.forEach(function(x) {
7121if((wb.Workbook.WBProps[x[0]]) == null) return;
7122 if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
7123 workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
7124 });
7125if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
7126 }
7127 o[o.length] = (writextag('workbookPr', null, workbookPr));
7128
7129 /* workbookProtection */
7130
7131 var sheets = wb.Workbook && wb.Workbook.Sheets || [];
7132 var i = 0;
7133
7134 /* bookViews */
7135
7136 o[o.length] = "<sheets>";
7137 for(i = 0; i != wb.SheetNames.length; ++i) {
7138 var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
7139 sht.sheetId = ""+(i+1);
7140 sht["r:id"] = "rId"+(i+1);
7141 if(sheets[i]) switch(sheets[i].Hidden) {
7142 case 1: sht.state = "hidden"; break;
7143 case 2: sht.state = "veryHidden"; break;
7144 }
7145 o[o.length] = (writextag('sheet',null,sht));
7146 }
7147 o[o.length] = "</sheets>";
7148
7149 /* functionGroups */
7150 /* externalReferences */
7151
7152 if(write_names) {
7153 o[o.length] = "<definedNames>";
7154 if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
7155 var d = {name:n.Name};
7156 if(n.Comment) d.comment = n.Comment;
7157 if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
7158 if(n.Hidden) d.hidden = "1";
7159 if(!n.Ref) return;
7160 o[o.length] = writextag('definedName', String(n.Ref).replace(/</g, "&lt;").replace(/>/g, "&gt;"), d);
7161 });
7162 o[o.length] = "</definedNames>";
7163 }
7164
7165 /* calcPr */
7166 /* oleSize */
7167 /* customWorkbookViews */
7168 /* pivotCaches */
7169 /* smartTagPr */
7170 /* smartTagTypes */
7171 /* webPublishing */
7172 /* fileRecoveryPr */
7173 /* webPublishObjects */
7174 /* extLst */
7175
7176 if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
7177 return o.join("");
7178}
7179function parse_wb(data, name, opts) {
7180 if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
7181 return parse_wb_xml((data), opts);
7182}
7183
7184function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
7185 if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
7186 return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
7187}
7188
7189function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
7190 if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
7191 return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
7192}
7193
7194function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
7195 if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
7196 return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
7197}
7198
7199function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
7200 if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
7201 return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
7202}
7203
7204function parse_sty(data, name, themes, opts) {
7205 if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
7206 return parse_sty_xml((data), themes, opts);
7207}
7208
7209function parse_theme(data, name, opts) {
7210 return parse_theme_xml(data, opts);
7211}
7212
7213function parse_sst(data, name, opts) {
7214 if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
7215 return parse_sst_xml((data), opts);
7216}
7217
7218function parse_cmnt(data, name, opts) {
7219 if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
7220 return parse_comments_xml((data), opts);
7221}
7222
7223function parse_cc(data, name, opts) {
7224 if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
7225 return parse_cc_xml((data), name, opts);
7226}
7227
7228function parse_xlink(data, rel, name, opts) {
7229 if(name.slice(-4)===".bin") return parse_xlink_bin((data), rel, name, opts);
7230 return parse_xlink_xml((data), rel, name, opts);
7231}
7232
7233function write_wb(wb, name, opts) {
7234 return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
7235}
7236
7237function write_ws(data, name, opts, wb, rels) {
7238 return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
7239}
7240
7241// eslint-disable-next-line no-unused-vars
7242function write_cs(data, name, opts, wb, rels) {
7243 return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
7244}
7245
7246function write_sty(data, name, opts) {
7247 return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
7248}
7249
7250function write_sst(data, name, opts) {
7251 return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
7252}
7253
7254function write_cmnt(data, name, opts) {
7255 return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
7256}
7257/*
7258function write_cc(data, name:string, opts) {
7259 return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
7260}
7261*/
7262/* note: browser DOM element cannot see mso- style attrs, must parse */
7263var HTML_ = (function() {
7264 function html_to_sheet(str, _opts) {
7265 var opts = _opts || {};
7266 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
7267 var ws = opts.dense ? ([]) : ({});
7268 str = str.replace(/<!--.*?-->/g, "");
7269 var mtch = str.match(/<table/i);
7270 if(!mtch) throw new Error("Invalid HTML: could not find <table>");
7271 var mtch2 = str.match(/<\/table/i);
7272 var i = mtch.index, j = mtch2 && mtch2.index || str.length;
7273 var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
7274 var R = -1, C = 0, RS = 0, CS = 0;
7275 var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
7276 var merges = [];
7277 for(i = 0; i < rows.length; ++i) {
7278 var row = rows[i].trim();
7279 var hd = row.slice(0,3).toLowerCase();
7280 if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
7281 if(hd != "<td" && hd != "<th") continue;
7282 var cells = row.split(/<\/t[dh]>/i);
7283 for(j = 0; j < cells.length; ++j) {
7284 var cell = cells[j].trim();
7285 if(!cell.match(/<t[dh]/i)) continue;
7286 var m = cell, cc = 0;
7287 /* TODO: parse styles etc */
7288 while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
7289 for(var midx = 0; midx < merges.length; ++midx) {
7290 var _merge = merges[midx];
7291 if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; }
7292 }
7293 var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
7294 CS = tag.colspan ? +tag.colspan : 1;
7295 if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
7296 var _t = tag.t || "";
7297 /* TODO: generate stub cells */
7298 if(!m.length) { C += CS; continue; }
7299 m = htmldecode(m);
7300 if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
7301 if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
7302 if(!m.length) continue;
7303 var o = {t:'s', v:m};
7304 if(opts.raw || !m.trim().length || _t == 's'){}
7305 else if(m === 'TRUE') o = {t:'b', v:true};
7306 else if(m === 'FALSE') o = {t:'b', v:false};
7307 else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
7308 else if(!isNaN(fuzzydate(m).getDate())) {
7309 o = ({t:'d', v:parseDate(m)});
7310 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
7311 o.z = opts.dateNF || SSF._table[14];
7312 }
7313 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
7314 else ws[encode_cell({r:R, c:C})] = o;
7315 C += CS;
7316 }
7317 }
7318 ws['!ref'] = encode_range(range);
7319 if(merges.length) ws["!merges"] = merges;
7320 return ws;
7321 }
7322 function html_to_book(str, opts) {
7323 return sheet_to_workbook(html_to_sheet(str, opts), opts);
7324 }
7325 function make_html_row(ws, r, R, o) {
7326 var M = (ws['!merges'] ||[]);
7327 var oo = [];
7328 for(var C = r.s.c; C <= r.e.c; ++C) {
7329 var RS = 0, CS = 0;
7330 for(var j = 0; j < M.length; ++j) {
7331 if(M[j].s.r > R || M[j].s.c > C) continue;
7332 if(M[j].e.r < R || M[j].e.c < C) continue;
7333 if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
7334 RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
7335 }
7336 if(RS < 0) continue;
7337 var coord = encode_cell({r:R,c:C});
7338 var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
7339 /* TODO: html entities */
7340 var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
7341 var sp = ({});
7342 if(RS > 1) sp.rowspan = RS;
7343 if(CS > 1) sp.colspan = CS;
7344 sp.t = cell && cell.t || 'z';
7345 if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
7346 sp.id = (o.id || "sjs") + "-" + coord;
7347 oo.push(writextag('td', w, sp));
7348 }
7349 var preamble = "<tr>";
7350 return preamble + oo.join("") + "</tr>";
7351 }
7352 function make_html_preamble(ws, R, o) {
7353 var out = [];
7354 return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
7355 }
7356 var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
7357 var _END = '</body></html>';
7358 function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
7359 var o = opts || {};
7360 var header = o.header != null ? o.header : _BEGIN;
7361 var footer = o.footer != null ? o.footer : _END;
7362 var out = [header];
7363 var r = decode_range(ws['!ref']);
7364 o.dense = Array.isArray(ws);
7365 out.push(make_html_preamble(ws, r, o));
7366 for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
7367 out.push("</table>" + footer);
7368 return out.join("");
7369 }
7370
7371 return {
7372 to_workbook: html_to_book,
7373 to_sheet: html_to_sheet,
7374 _row: make_html_row,
7375 BEGIN: _BEGIN,
7376 END: _END,
7377 _preamble: make_html_preamble,
7378 from_sheet: sheet_to_html
7379 };
7380})();
7381
7382function parse_dom_table(table, _opts) {
7383 var opts = _opts || {};
7384 if(DENSE != null) opts.dense = DENSE;
7385 var ws = opts.dense ? ([]) : ({});
7386 var rows = table.getElementsByTagName('tr');
7387 var sheetRows = opts.sheetRows || 10000000;
7388 var range = {s:{r:0,c:0},e:{r:0,c:0}};
7389 var merges = [], midx = 0;
7390 var rowinfo = [];
7391 var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
7392 for(; _R < rows.length && R < sheetRows; ++_R) {
7393 var row = rows[_R];
7394 if (is_dom_element_hidden(row)) {
7395 if (opts.display) continue;
7396 rowinfo[R] = {hidden: true};
7397 }
7398 var elts = (row.children);
7399 for(_C = C = 0; _C < elts.length; ++_C) {
7400 var elt = elts[_C];
7401 if (opts.display && is_dom_element_hidden(elt)) continue;
7402 var v = htmldecode(elt.innerHTML);
7403 for(midx = 0; midx < merges.length; ++midx) {
7404 var m = merges[midx];
7405 if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; }
7406 }
7407 /* TODO: figure out how to extract nonstandard mso- style */
7408 CS = +elt.getAttribute("colspan") || 1;
7409 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}});
7410 var o = {t:'s', v:v};
7411 var _t = elt.getAttribute("t") || "";
7412 if(v != null) {
7413 if(v.length == 0) o.t = _t || 'z';
7414 else if(opts.raw || v.trim().length == 0 || _t == "s"){}
7415 else if(v === 'TRUE') o = {t:'b', v:true};
7416 else if(v === 'FALSE') o = {t:'b', v:false};
7417 else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
7418 else if(!isNaN(fuzzydate(v).getDate())) {
7419 o = ({t:'d', v:parseDate(v)});
7420 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
7421 o.z = opts.dateNF || SSF._table[14];
7422 }
7423 }
7424 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
7425 else ws[encode_cell({c:C, r:R})] = o;
7426 if(range.e.c < C) range.e.c = C;
7427 C += CS;
7428 }
7429 ++R;
7430 }
7431 if(merges.length) ws['!merges'] = merges;
7432 if(rowinfo.length) ws['!rows'] = rowinfo;
7433 range.e.r = R - 1;
7434 ws['!ref'] = encode_range(range);
7435 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
7436 return ws;
7437}
7438
7439function table_to_book(table, opts) {
7440 return sheet_to_workbook(parse_dom_table(table, opts), opts);
7441}
7442
7443function is_dom_element_hidden(element) {
7444 var display = '';
7445 var get_computed_style = get_get_computed_style_function(element);
7446 if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
7447 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)
7448 return display === 'none';
7449}
7450
7451/* global getComputedStyle */
7452function get_get_computed_style_function(element) {
7453 // The proper getComputedStyle implementation is the one defined in the element window
7454 if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
7455 // If it is not available, try to get one from the global namespace
7456 if(typeof getComputedStyle === 'function') return getComputedStyle;
7457 return null;
7458}
7459function write_sheet_index(wb, sheet) {
7460 if(!sheet) return 0;
7461 var idx = wb.SheetNames.indexOf(sheet);
7462 if(idx == -1) throw new Error("Sheet not found: " + sheet);
7463 return idx;
7464}
7465
7466function write_obj_str(factory) {
7467 return function write_str(wb, o) {
7468 var idx = write_sheet_index(wb, o.sheet);
7469 return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
7470 };
7471}
7472
7473var write_htm_str = write_obj_str(HTML_);
7474var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
7475var write_slk_str = write_obj_str(typeof SYLK !== "undefined" ? SYLK : {});
7476var write_dif_str = write_obj_str(typeof DIF !== "undefined" ? DIF : {});
7477var write_prn_str = write_obj_str(typeof PRN !== "undefined" ? PRN : {});
7478var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {});
7479var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
7480var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {});
7481var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {});
7482
7483function fix_opts_func(defaults) {
7484 return function fix_opts(opts) {
7485 for(var i = 0; i != defaults.length; ++i) {
7486 var d = defaults[i];
7487 if(opts[d[0]] === undefined) opts[d[0]] = d[1];
7488 if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
7489 }
7490 };
7491}
7492
7493var fix_read_opts = fix_opts_func([
7494 ['cellNF', false], /* emit cell number format string as .z */
7495 ['cellHTML', true], /* emit html string as .h */
7496 ['cellFormula', true], /* emit formulae as .f */
7497 ['cellStyles', false], /* emits style/theme as .s */
7498 ['cellText', true], /* emit formatted text as .w */
7499 ['cellDates', false], /* emit date cells with type `d` */
7500
7501 ['sheetStubs', false], /* emit empty cells */
7502 ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
7503
7504 ['bookDeps', false], /* parse calculation chains */
7505 ['bookSheets', false], /* only try to get sheet names (no Sheets) */
7506 ['bookProps', false], /* only try to get properties (no Sheets) */
7507 ['bookFiles', false], /* include raw file structure (keys, files, cfb) */
7508 ['bookVBA', false], /* include vba raw data (vbaraw) */
7509
7510 ['password',''], /* password */
7511 ['WTF', false] /* WTF mode (throws errors) */
7512]);
7513
7514
7515var fix_write_opts = fix_opts_func([
7516 ['cellDates', false], /* write date cells with type `d` */
7517
7518 ['bookSST', false], /* Generate Shared String Table */
7519
7520 ['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
7521
7522 ['compression', false], /* Use file compression */
7523
7524 ['WTF', false] /* WTF mode (throws errors) */
7525]);
7526function get_sheet_type(n) {
7527 if(RELS.WS.indexOf(n) > -1) return "sheet";
7528 if(RELS.CS && n == RELS.CS) return "chart";
7529 if(RELS.DS && n == RELS.DS) return "dialog";
7530 if(RELS.MS && n == RELS.MS) return "macro";
7531 return (n && n.length) ? n : "sheet";
7532}
7533function safe_parse_wbrels(wbrels, sheets) {
7534 if(!wbrels) return 0;
7535 try {
7536 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)]; });
7537 } catch(e) { return null; }
7538 return !wbrels || wbrels.length === 0 ? null : wbrels;
7539}
7540
7541function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
7542 try {
7543 sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
7544 var data = getzipdata(zip, path);
7545 var _ws;
7546 switch(stype) {
7547 case 'sheet': _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
7548 case 'chart': _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
7549 if(!_ws || !_ws['!drawel']) break;
7550 var dfile = resolve_path(_ws['!drawel'].Target, path);
7551 var drelsp = get_rels_path(dfile);
7552 var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
7553 var chartp = resolve_path(draw, dfile);
7554 var crelsp = get_rels_path(chartp);
7555 _ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
7556 break;
7557 case 'macro': _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
7558 case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
7559 default: throw new Error("Unrecognized sheet type " + stype);
7560 }
7561 sheets[sheet] = _ws;
7562
7563 /* scan rels for comments */
7564 var comments = [];
7565 if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) {
7566 if(sheetRels[sheet][n].Type == RELS.CMNT) {
7567 var dfile = resolve_path(sheetRels[sheet][n].Target, path);
7568 comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
7569 if(!comments || !comments.length) return;
7570 sheet_insert_comments(_ws, comments);
7571 }
7572 });
7573 } catch(e) { if(opts.WTF) throw e; }
7574}
7575
7576function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
7577
7578function parse_zip(zip, opts) {
7579 make_ssf(SSF);
7580 opts = opts || {};
7581 fix_read_opts(opts);
7582
7583 /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
7584 if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
7585 /* UOC */
7586 if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
7587 /* Numbers */
7588 if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
7589
7590 var entries = zipentries(zip);
7591 var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
7592 var xlsb = false;
7593 var sheets, binname;
7594 if(dir.workbooks.length === 0) {
7595 binname = "xl/workbook.xml";
7596 if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
7597 }
7598 if(dir.workbooks.length === 0) {
7599 binname = "xl/workbook.bin";
7600 if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
7601 dir.workbooks.push(binname);
7602 xlsb = true;
7603 }
7604 if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
7605
7606 var themes = ({});
7607 var styles = ({});
7608 if(!opts.bookSheets && !opts.bookProps) {
7609 strs = [];
7610 if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
7611
7612 if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
7613
7614 if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
7615 }
7616
7617 /*var externbooks = */dir.links.map(function(link) {
7618 try {
7619 var rels = parse_rels(getzipstr(zip, get_rels_path(strip_front_slash(link))), link);
7620 return parse_xlink(getzipdata(zip, strip_front_slash(link)), rels, link, opts);
7621 } catch(e) {}
7622 });
7623
7624 var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
7625
7626 var props = {}, propdata = "";
7627
7628 if(dir.coreprops.length) {
7629 propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
7630 if(propdata) props = parse_core_props(propdata);
7631 if(dir.extprops.length !== 0) {
7632 propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
7633 if(propdata) parse_ext_props(propdata, props, opts);
7634 }
7635 }
7636
7637 var custprops = {};
7638 if(!opts.bookSheets || opts.bookProps) {
7639 if (dir.custprops.length !== 0) {
7640 propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
7641 if(propdata) custprops = parse_cust_props(propdata, opts);
7642 }
7643 }
7644
7645 var out = ({});
7646 if(opts.bookSheets || opts.bookProps) {
7647 if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
7648 else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
7649 if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
7650 if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
7651 if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
7652 }
7653 sheets = {};
7654
7655 var deps = {};
7656 if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
7657
7658 var i=0;
7659 var sheetRels = ({});
7660 var path, relsPath;
7661
7662 {
7663 var wbsheets = wb.Sheets;
7664 props.Worksheets = wbsheets.length;
7665 props.SheetNames = [];
7666 for(var j = 0; j != wbsheets.length; ++j) {
7667 props.SheetNames[j] = wbsheets[j].name;
7668 }
7669 }
7670
7671 var wbext = xlsb ? "bin" : "xml";
7672 var wbrelsi = dir.workbooks[0].lastIndexOf("/");
7673 var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
7674 if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
7675 var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
7676 if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
7677
7678 /* Numbers iOS hack */
7679 var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
7680 for(i = 0; i != props.Worksheets; ++i) {
7681 var stype = "sheet";
7682 if(wbrels && wbrels[i]) {
7683 path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
7684 if(!safegetzipfile(zip, path)) path = wbrels[i][1];
7685 if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
7686 stype = wbrels[i][2];
7687 } else {
7688 path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
7689 path = path.replace(/sheet0\./,"sheet.");
7690 }
7691 relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
7692 safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
7693 }
7694
7695 out = ({
7696 Directory: dir,
7697 Workbook: wb,
7698 Props: props,
7699 Custprops: custprops,
7700 Deps: deps,
7701 Sheets: sheets,
7702 SheetNames: props.SheetNames,
7703 Strings: strs,
7704 Styles: styles,
7705 Themes: themes,
7706 SSF: SSF.get_table()
7707 });
7708 if(opts.bookFiles) {
7709 out.keys = entries;
7710 out.files = zip.files;
7711 }
7712 if(opts.bookVBA) {
7713 if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
7714 else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
7715 }
7716 return out;
7717}
7718
7719/* [MS-OFFCRYPTO] 2.1.1 */
7720function parse_xlsxcfb(cfb, _opts) {
7721 var opts = _opts || {};
7722 var f = 'Workbook', data = CFB.find(cfb, f);
7723 try {
7724 f = '/!DataSpaces/Version';
7725 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
7726 /*var version = */parse_DataSpaceVersionInfo(data.content);
7727
7728 /* 2.3.4.1 */
7729 f = '/!DataSpaces/DataSpaceMap';
7730 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
7731 var dsm = parse_DataSpaceMap(data.content);
7732 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")
7733 throw new Error("ECMA-376 Encrypted file bad " + f);
7734
7735 /* 2.3.4.2 */
7736 f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
7737 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
7738 var seds = parse_DataSpaceDefinition(data.content);
7739 if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
7740 throw new Error("ECMA-376 Encrypted file bad " + f);
7741
7742 /* 2.3.4.3 */
7743 f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
7744 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
7745 /*var hdr = */parse_Primary(data.content);
7746 } catch(e) {}
7747
7748 f = '/EncryptionInfo';
7749 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
7750 var einfo = parse_EncryptionInfo(data.content);
7751
7752 /* 2.3.4.4 */
7753 f = '/EncryptedPackage';
7754 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
7755
7756/*global decrypt_agile */
7757if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
7758/*global decrypt_std76 */
7759if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
7760 throw new Error("File is password-protected");
7761}
7762
7763function write_zip(wb, opts) {
7764 _shapeid = 1024;
7765 if(opts.bookType == "ods") return write_ods(wb, opts);
7766 if(wb && !wb.SSF) {
7767 wb.SSF = SSF.get_table();
7768 }
7769 if(wb && wb.SSF) {
7770 make_ssf(SSF); SSF.load_table(wb.SSF);
7771 // $FlowIgnore
7772 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
7773 opts.ssf = wb.SSF;
7774 }
7775 opts.rels = {}; opts.wbrels = {};
7776 opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
7777 if(browser_has_Map) opts.revStrings = new Map();
7778 else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
7779 var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
7780 var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
7781 var ct = new_ct();
7782 fix_write_opts(opts = opts || {});
7783var zip = zip_new();
7784 var f = "", rId = 0;
7785
7786 opts.cellXfs = [];
7787 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
7788
7789 if(!wb.Props) wb.Props = {};
7790
7791 f = "docProps/core.xml";
7792 zip_add_file(zip, f, write_core_props(wb.Props, opts));
7793 ct.coreprops.push(f);
7794 add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
7795
7796f = "docProps/app.xml";
7797 if(wb.Props && wb.Props.SheetNames){/* empty */}
7798 else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
7799 else {
7800 var _sn = [];
7801 for(var _i = 0; _i < wb.SheetNames.length; ++_i)
7802 if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
7803 wb.Props.SheetNames = _sn;
7804 }
7805 wb.Props.Worksheets = wb.Props.SheetNames.length;
7806 zip_add_file(zip, f, write_ext_props(wb.Props, opts));
7807 ct.extprops.push(f);
7808 add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
7809
7810 if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
7811 f = "docProps/custom.xml";
7812 zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
7813 ct.custprops.push(f);
7814 add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
7815 }
7816
7817 for(rId=1;rId <= wb.SheetNames.length; ++rId) {
7818 var wsrels = {'!id':{}};
7819 var ws = wb.Sheets[wb.SheetNames[rId-1]];
7820 var _type = (ws || {})["!type"] || "sheet";
7821 switch(_type) {
7822 case "chart":
7823 /* falls through */
7824 default:
7825 f = "xl/worksheets/sheet" + rId + "." + wbext;
7826 zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels));
7827 ct.sheets.push(f);
7828 add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
7829 }
7830
7831 if(ws) {
7832 var comments = ws['!comments'];
7833 var need_vml = false;
7834 if(comments && comments.length > 0) {
7835 var cf = "xl/comments" + rId + "." + wbext;
7836 zip_add_file(zip, cf, write_cmnt(comments, cf, opts));
7837 ct.comments.push(cf);
7838 add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
7839 need_vml = true;
7840 }
7841 if(ws['!legacy']) {
7842 if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
7843 }
7844 delete ws['!comments'];
7845 delete ws['!legacy'];
7846 }
7847
7848 if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
7849 }
7850
7851 if(opts.Strings != null && opts.Strings.length > 0) {
7852 f = "xl/sharedStrings." + wbext;
7853 zip_add_file(zip, f, write_sst(opts.Strings, f, opts));
7854 ct.strs.push(f);
7855 add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
7856 }
7857
7858 f = "xl/workbook." + wbext;
7859 zip_add_file(zip, f, write_wb(wb, f, opts));
7860 ct.workbooks.push(f);
7861 add_rels(opts.rels, 1, f, RELS.WB);
7862
7863 /* TODO: something more intelligent with themes */
7864
7865 f = "xl/theme/theme1.xml";
7866 zip_add_file(zip, f, write_theme(wb.Themes, opts));
7867 ct.themes.push(f);
7868 add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
7869
7870 /* TODO: something more intelligent with styles */
7871
7872 f = "xl/styles." + wbext;
7873 zip_add_file(zip, f, write_sty(wb, f, opts));
7874 ct.styles.push(f);
7875 add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
7876
7877 if(wb.vbaraw && vbafmt) {
7878 f = "xl/vbaProject.bin";
7879 zip_add_file(zip, f, wb.vbaraw);
7880 ct.vba.push(f);
7881 add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
7882 }
7883
7884 zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
7885 zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
7886 zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
7887
7888 delete opts.revssf; delete opts.ssf;
7889 return zip;
7890}
7891function firstbyte(f,o) {
7892 var x = "";
7893 switch((o||{}).type || "base64") {
7894 case 'buffer': return [f[0], f[1], f[2], f[3]];
7895 case 'base64': x = Base64.decode(f.slice(0,24)); break;
7896 case 'binary': x = f; break;
7897 case 'array': return [f[0], f[1], f[2], f[3]];
7898 default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
7899 }
7900 return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3)];
7901}
7902
7903function read_cfb(cfb, opts) {
7904 if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
7905 return parse_xlscfb(cfb, opts);
7906}
7907
7908function read_zip(data, opts) {
7909var zip, d = data;
7910 var o = opts||{};
7911 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
7912 zip = zip_read(d, o);
7913 return parse_zip(zip, o);
7914}
7915
7916function read_plaintext(data, o) {
7917 var i = 0;
7918 main: while(i < data.length) switch(data.charCodeAt(i)) {
7919 case 0x0A: case 0x0D: case 0x20: ++i; break;
7920 case 0x3C: return parse_xlml(data.slice(i),o);
7921 default: break main;
7922 }
7923 return PRN.to_workbook(data, o);
7924}
7925
7926function read_plaintext_raw(data, o) {
7927 var str = "", bytes = firstbyte(data, o);
7928 switch(o.type) {
7929 case 'base64': str = Base64.decode(data); break;
7930 case 'binary': str = data; break;
7931 case 'buffer': str = data.toString('binary'); break;
7932 case 'array': str = cc2str(data); break;
7933 default: throw new Error("Unrecognized type " + o.type);
7934 }
7935 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
7936 return read_plaintext(str, o);
7937}
7938
7939function read_utf16(data, o) {
7940 var d = data;
7941 if(o.type == 'base64') d = Base64.decode(d);
7942 d = cptable.utils.decode(1200, d.slice(2), 'str');
7943 o.type = "binary";
7944 return read_plaintext(d, o);
7945}
7946
7947function bstrify(data) {
7948 return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
7949}
7950
7951function read_prn(data, d, o, str) {
7952 if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
7953 return PRN.to_workbook(d, o);
7954}
7955
7956function readSync(data, opts) {
7957 reset_cp();
7958 if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
7959 var d = data, n = [0,0,0,0], str = false;
7960 var o = opts||{};
7961 if(o.cellStyles) { o.cellNF = true; }
7962 _ssfopts = {};
7963 if(o.dateNF) _ssfopts.dateNF = o.dateNF;
7964 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
7965 if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
7966 if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
7967 if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
7968 // $FlowIgnore
7969 var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
7970 // $FlowIgnore
7971 if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
7972 }
7973 switch((n = firstbyte(d, o))[0]) {
7974 case 0xD0: return read_cfb(CFB.read(d, o), o);
7975 case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break;
7976 case 0x3C: return parse_xlml(d, o);
7977 case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
7978 case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
7979 case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
7980 case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
7981 case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
7982 case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
7983 case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
7984 case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
7985 case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
7986 }
7987 if(n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
7988 return read_prn(data, d, o, str);
7989}
7990
7991function readFileSync(filename, opts) {
7992 var o = opts||{}; o.type = 'file';
7993 return readSync(filename, o);
7994}
7995function write_cfb_ctr(cfb, o) {
7996 switch(o.type) {
7997 case "base64": case "binary": break;
7998 case "buffer": case "array": o.type = ""; break;
7999 case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
8000 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
8001 default: throw new Error("Unrecognized type " + o.type);
8002 }
8003 return CFB.write(cfb, o);
8004}
8005
8006/*global encrypt_agile */
8007function write_zip_type(wb, opts) {
8008 var o = opts||{};
8009 var z = write_zip(wb, o);
8010 var oopts = {};
8011 if(o.compression) oopts.compression = 'DEFLATE';
8012 if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
8013 else switch(o.type) {
8014 case "base64": oopts.type = "base64"; break;
8015 case "binary": oopts.type = "string"; break;
8016 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
8017 case "buffer":
8018 case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
8019 default: throw new Error("Unrecognized type " + o.type);
8020 }
8021 var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type}) : z.generate(oopts);
8022 if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o);
8023 if(o.type === "file") return write_dl(o.file, out);
8024 return o.type == "string" ? utf8read(out) : out;
8025}
8026
8027function write_cfb_type(wb, opts) {
8028 var o = opts||{};
8029 var cfb = write_xlscfb(wb, o);
8030 return write_cfb_ctr(cfb, o);
8031}
8032
8033function write_string_type(out, opts, bom) {
8034 if(!bom) bom = "";
8035 var o = bom + out;
8036 switch(opts.type) {
8037 case "base64": return Base64.encode(utf8write(o));
8038 case "binary": return utf8write(o);
8039 case "string": return out;
8040 case "file": return write_dl(opts.file, o, 'utf8');
8041 case "buffer": {
8042 if(has_buf) return Buffer_from(o, 'utf8');
8043 else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
8044 }
8045 }
8046 throw new Error("Unrecognized type " + opts.type);
8047}
8048
8049function write_stxt_type(out, opts) {
8050 switch(opts.type) {
8051 case "base64": return Base64.encode(out);
8052 case "binary": return out;
8053 case "string": return out; /* override in sheet_to_txt */
8054 case "file": return write_dl(opts.file, out, 'binary');
8055 case "buffer": {
8056 if(has_buf) return Buffer_from(out, 'binary');
8057 else return out.split("").map(function(c) { return c.charCodeAt(0); });
8058 }
8059 }
8060 throw new Error("Unrecognized type " + opts.type);
8061}
8062
8063/* TODO: test consistency */
8064function write_binary_type(out, opts) {
8065 switch(opts.type) {
8066 case "string":
8067 case "base64":
8068 case "binary":
8069 var bstr = "";
8070 // $FlowIgnore
8071 for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
8072 return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
8073 case "file": return write_dl(opts.file, out);
8074 case "buffer": return out;
8075 default: throw new Error("Unrecognized type " + opts.type);
8076 }
8077}
8078
8079function writeSync(wb, opts) {
8080 reset_cp();
8081 check_wb(wb);
8082 var o = opts||{};
8083 if(o.cellStyles) { o.cellNF = true; }
8084 if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
8085 switch(o.bookType || 'xlsb') {
8086 case 'xml':
8087 case 'xlml': return write_string_type(write_xlml(wb, o), o);
8088 case 'slk':
8089 case 'sylk': return write_string_type(write_slk_str(wb, o), o);
8090 case 'htm':
8091 case 'html': return write_string_type(write_htm_str(wb, o), o);
8092 case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
8093 case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
8094 case 'dif': return write_string_type(write_dif_str(wb, o), o);
8095 case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
8096 case 'prn': return write_string_type(write_prn_str(wb, o), o);
8097 case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
8098 case 'eth': return write_string_type(write_eth_str(wb, o), o);
8099 case 'fods': return write_string_type(write_ods(wb, o), o);
8100 case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
8101 case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
8102 case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
8103 case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
8104 case 'biff8':
8105 case 'xla':
8106 case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
8107 case 'xlsx':
8108 case 'xlsm':
8109 case 'xlam':
8110 case 'xlsb':
8111 case 'ods': return write_zip_type(wb, o);
8112 default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
8113 }
8114}
8115
8116function resolve_book_type(o) {
8117 if(o.bookType) return;
8118 var _BT = {
8119 "xls": "biff8",
8120 "htm": "html",
8121 "slk": "sylk",
8122 "socialcalc": "eth",
8123 "Sh33tJS": "WTF"
8124 };
8125 var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
8126 if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
8127 o.bookType = _BT[o.bookType] || o.bookType;
8128}
8129
8130function writeFileSync(wb, filename, opts) {
8131 var o = opts||{}; o.type = 'file';
8132 o.file = filename;
8133 resolve_book_type(o);
8134 return writeSync(wb, o);
8135}
8136
8137function writeFileAsync(filename, wb, opts, cb) {
8138 var o = opts||{}; o.type = 'file';
8139 o.file = filename;
8140 resolve_book_type(o);
8141 o.type = 'buffer';
8142 var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
8143 return _fs.writeFile(filename, writeSync(wb, o), _cb);
8144}
8145function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
8146 var rr = encode_row(R);
8147 var defval = o.defval, raw = o.raw || !o.hasOwnProperty("raw");
8148 var isempty = true;
8149 var row = (header === 1) ? [] : {};
8150 if(header !== 1) {
8151 if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
8152 else row.__rowNum__ = R;
8153 }
8154 if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
8155 var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
8156 if(val === undefined || val.t === undefined) {
8157 if(defval === undefined) continue;
8158 if(hdr[C] != null) { row[hdr[C]] = defval; }
8159 continue;
8160 }
8161 var v = val.v;
8162 switch(val.t){
8163 case 'z': if(v == null) break; continue;
8164 case 'e': v = void 0; break;
8165 case 's': case 'd': case 'b': case 'n': break;
8166 default: throw new Error('unrecognized type ' + val.t);
8167 }
8168 if(hdr[C] != null) {
8169 if(v == null) {
8170 if(defval !== undefined) row[hdr[C]] = defval;
8171 else if(raw && v === null) row[hdr[C]] = null;
8172 else continue;
8173 } else {
8174 row[hdr[C]] = raw ? v : format_cell(val,v,o);
8175 }
8176 if(v != null) isempty = false;
8177 }
8178 }
8179 return { row: row, isempty: isempty };
8180}
8181
8182
8183function sheet_to_json(sheet, opts) {
8184 if(sheet == null || sheet["!ref"] == null) return [];
8185 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
8186 var r = {s:{r:0,c:0},e:{r:0,c:0}};
8187 var o = opts || {};
8188 var range = o.range != null ? o.range : sheet["!ref"];
8189 if(o.header === 1) header = 1;
8190 else if(o.header === "A") header = 2;
8191 else if(Array.isArray(o.header)) header = 3;
8192 else if(o.header == null) header = 0;
8193 switch(typeof range) {
8194 case 'string': r = safe_decode_range(range); break;
8195 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
8196 default: r = range;
8197 }
8198 if(header > 0) offset = 0;
8199 var rr = encode_row(r.s.r);
8200 var cols = [];
8201 var out = [];
8202 var outi = 0, counter = 0;
8203 var dense = Array.isArray(sheet);
8204 var R = r.s.r, C = 0, CC = 0;
8205 if(dense && !sheet[R]) sheet[R] = [];
8206 for(C = r.s.c; C <= r.e.c; ++C) {
8207 cols[C] = encode_col(C);
8208 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
8209 switch(header) {
8210 case 1: hdr[C] = C - r.s.c; break;
8211 case 2: hdr[C] = cols[C]; break;
8212 case 3: hdr[C] = o.header[C - r.s.c]; break;
8213 default:
8214 if(val == null) val = {w: "__EMPTY", t: "s"};
8215 vv = v = format_cell(val, null, o);
8216 counter = 0;
8217 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
8218 hdr[C] = vv;
8219 }
8220 }
8221 for (R = r.s.r + offset; R <= r.e.r; ++R) {
8222 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
8223 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
8224 }
8225 out.length = outi;
8226 return out;
8227}
8228
8229var qreg = /"/g;
8230function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
8231 var isempty = true;
8232 var row = [], txt = "", rr = encode_row(R);
8233 for(var C = r.s.c; C <= r.e.c; ++C) {
8234 if (!cols[C]) continue;
8235 var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
8236 if(val == null) txt = "";
8237 else if(val.v != null) {
8238 isempty = false;
8239 txt = ''+format_cell(val, null, o);
8240 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; }
8241 if(txt == "ID") txt = '"ID"';
8242 } else if(val.f != null && !val.F) {
8243 isempty = false;
8244 txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
8245 } else txt = "";
8246 /* NOTE: Excel CSV does not support array formulae */
8247 row.push(txt);
8248 }
8249 if(o.blankrows === false && isempty) return null;
8250 return row.join(FS);
8251}
8252
8253function sheet_to_csv(sheet, opts) {
8254 var out = [];
8255 var o = opts == null ? {} : opts;
8256 if(sheet == null || sheet["!ref"] == null) return "";
8257 var r = safe_decode_range(sheet["!ref"]);
8258 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
8259 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
8260 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
8261 var row = "", cols = [];
8262 o.dense = Array.isArray(sheet);
8263 var colinfo = o.skipHidden && sheet["!cols"] || [];
8264 var rowinfo = o.skipHidden && sheet["!rows"] || [];
8265 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
8266 for(var R = r.s.r; R <= r.e.r; ++R) {
8267 if ((rowinfo[R]||{}).hidden) continue;
8268 row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
8269 if(row == null) { continue; }
8270 if(o.strip) row = row.replace(endregex,"");
8271 out.push(row + RS);
8272 }
8273 delete o.dense;
8274 return out.join("");
8275}
8276
8277function sheet_to_txt(sheet, opts) {
8278 if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
8279 var s = sheet_to_csv(sheet, opts);
8280 if(typeof cptable == 'undefined' || opts.type == 'string') return s;
8281 var o = cptable.utils.encode(1200, s, 'str');
8282 return String.fromCharCode(255) + String.fromCharCode(254) + o;
8283}
8284
8285function sheet_to_formulae(sheet) {
8286 var y = "", x, val="";
8287 if(sheet == null || sheet["!ref"] == null) return [];
8288 var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
8289 var cmds = [];
8290 var dense = Array.isArray(sheet);
8291 for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
8292 for(var R = r.s.r; R <= r.e.r; ++R) {
8293 rr = encode_row(R);
8294 for(C = r.s.c; C <= r.e.c; ++C) {
8295 y = cols[C] + rr;
8296 x = dense ? (sheet[R]||[])[C] : sheet[y];
8297 val = "";
8298 if(x === undefined) continue;
8299 else if(x.F != null) {
8300 y = x.F;
8301 if(!x.f) continue;
8302 val = x.f;
8303 if(y.indexOf(":") == -1) y = y + ":" + y;
8304 }
8305 if(x.f != null) val = x.f;
8306 else if(x.t == 'z') continue;
8307 else if(x.t == 'n' && x.v != null) val = "" + x.v;
8308 else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
8309 else if(x.w !== undefined) val = "'" + x.w;
8310 else if(x.v === undefined) continue;
8311 else if(x.t == 's') val = "'" + x.v;
8312 else val = ""+x.v;
8313 cmds[cmds.length] = y + "=" + val;
8314 }
8315 }
8316 return cmds;
8317}
8318
8319function sheet_add_json(_ws, js, opts) {
8320 var o = opts || {};
8321 var offset = +!o.skipHeader;
8322 var ws = _ws || ({});
8323 var _R = 0, _C = 0;
8324 if(ws && o.origin != null) {
8325 if(typeof o.origin == 'number') _R = o.origin;
8326 else {
8327 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
8328 _R = _origin.r; _C = _origin.c;
8329 }
8330 }
8331 var cell;
8332 var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
8333 if(ws['!ref']) {
8334 var _range = safe_decode_range(ws['!ref']);
8335 range.e.c = Math.max(range.e.c, _range.e.c);
8336 range.e.r = Math.max(range.e.r, _range.e.r);
8337 if(_R == -1) { _R = range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
8338 }
8339 var hdr = o.header || [], C = 0;
8340
8341 js.forEach(function (JS, R) {
8342 keys(JS).forEach(function(k) {
8343 if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
8344 var v = JS[k];
8345 var t = 'z';
8346 var z = "";
8347 var ref = encode_cell({c:_C + C,r:_R + R + offset});
8348 cell = utils.sheet_get_cell(ws, ref);
8349 if(v && typeof v === 'object' && !(v instanceof Date)){
8350 ws[ref] = v;
8351 } else {
8352 if(typeof v == 'number') t = 'n';
8353 else if(typeof v == 'boolean') t = 'b';
8354 else if(typeof v == 'string') t = 's';
8355 else if(v instanceof Date) {
8356 t = 'd';
8357 if(!o.cellDates) { t = 'n'; v = datenum(v); }
8358 z = (o.dateNF || SSF._table[14]);
8359 }
8360 if(!cell) ws[ref] = cell = ({t:t, v:v});
8361 else {
8362 cell.t = t; cell.v = v;
8363 delete cell.w; delete cell.R;
8364 if(z) cell.z = z;
8365 }
8366 if(z) cell.z = z;
8367 }
8368 });
8369 });
8370 range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
8371 var __R = encode_row(_R);
8372 if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
8373 ws['!ref'] = encode_range(range);
8374 return ws;
8375}
8376function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
8377
8378var utils = {
8379 encode_col: encode_col,
8380 encode_row: encode_row,
8381 encode_cell: encode_cell,
8382 encode_range: encode_range,
8383 decode_col: decode_col,
8384 decode_row: decode_row,
8385 split_cell: split_cell,
8386 decode_cell: decode_cell,
8387 decode_range: decode_range,
8388 format_cell: format_cell,
8389 get_formulae: sheet_to_formulae,
8390 make_csv: sheet_to_csv,
8391 make_json: sheet_to_json,
8392 make_formulae: sheet_to_formulae,
8393 sheet_add_aoa: sheet_add_aoa,
8394 sheet_add_json: sheet_add_json,
8395 aoa_to_sheet: aoa_to_sheet,
8396 json_to_sheet: json_to_sheet,
8397 table_to_sheet: parse_dom_table,
8398 table_to_book: table_to_book,
8399 sheet_to_csv: sheet_to_csv,
8400 sheet_to_txt: sheet_to_txt,
8401 sheet_to_json: sheet_to_json,
8402 sheet_to_html: HTML_.from_sheet,
8403 sheet_to_formulae: sheet_to_formulae,
8404 sheet_to_row_object_array: sheet_to_json
8405};
8406
8407(function(utils) {
8408utils.consts = utils.consts || {};
8409function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
8410
8411function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
8412
8413/* get cell, creating a stub if necessary */
8414function ws_get_cell_stub(ws, R, C) {
8415 /* A1 cell address */
8416 if(typeof R == "string") {
8417 /* dense */
8418 if(Array.isArray(ws)) {
8419 var RC = decode_cell(R);
8420 if(!ws[RC.r]) ws[RC.r] = [];
8421 return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
8422 }
8423 return ws[R] || (ws[R] = {t:'z'});
8424 }
8425 /* cell address object */
8426 if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
8427 /* R and C are 0-based indices */
8428 return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
8429}
8430utils.sheet_get_cell = ws_get_cell_stub;
8431
8432/* find sheet index for given name / validate index */
8433function wb_sheet_idx(wb, sh) {
8434 if(typeof sh == "number") {
8435 if(sh >= 0 && wb.SheetNames.length > sh) return sh;
8436 throw new Error("Cannot find sheet # " + sh);
8437 } else if(typeof sh == "string") {
8438 var idx = wb.SheetNames.indexOf(sh);
8439 if(idx > -1) return idx;
8440 throw new Error("Cannot find sheet name |" + sh + "|");
8441 } else throw new Error("Cannot find sheet |" + sh + "|");
8442}
8443
8444/* simple blank workbook object */
8445utils.book_new = function() {
8446 return { SheetNames: [], Sheets: {} };
8447};
8448
8449/* add a worksheet to the end of a given workbook */
8450utils.book_append_sheet = function(wb, ws, name) {
8451 if(!name) for(var i = 1; i <= 0xFFFF; ++i) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
8452 if(!name) throw new Error("Too many worksheets");
8453 check_ws_name(name);
8454 if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
8455
8456 wb.SheetNames.push(name);
8457 wb.Sheets[name] = ws;
8458};
8459
8460/* set sheet visibility (visible/hidden/very hidden) */
8461utils.book_set_sheet_visibility = function(wb, sh, vis) {
8462 get_default(wb,"Workbook",{});
8463 get_default(wb.Workbook,"Sheets",[]);
8464
8465 var idx = wb_sheet_idx(wb, sh);
8466 // $FlowIgnore
8467 get_default(wb.Workbook.Sheets,idx, {});
8468
8469 switch(vis) {
8470 case 0: case 1: case 2: break;
8471 default: throw new Error("Bad sheet visibility setting " + vis);
8472 }
8473 // $FlowIgnore
8474 wb.Workbook.Sheets[idx].Hidden = vis;
8475};
8476add_consts([
8477 ["SHEET_VISIBLE", 0],
8478 ["SHEET_HIDDEN", 1],
8479 ["SHEET_VERY_HIDDEN", 2]
8480]);
8481
8482/* set number format */
8483utils.cell_set_number_format = function(cell, fmt) {
8484 cell.z = fmt;
8485 return cell;
8486};
8487
8488/* set cell hyperlink */
8489utils.cell_set_hyperlink = function(cell, target, tooltip) {
8490 if(!target) {
8491 delete cell.l;
8492 } else {
8493 cell.l = ({ Target: target });
8494 if(tooltip) cell.l.Tooltip = tooltip;
8495 }
8496 return cell;
8497};
8498utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
8499
8500/* add to cell comments */
8501utils.cell_add_comment = function(cell, text, author) {
8502 if(!cell.c) cell.c = [];
8503 cell.c.push({t:text, a:author||"SheetJS"});
8504};
8505
8506/* set array formula and flush related cells */
8507utils.sheet_set_array_formula = function(ws, range, formula) {
8508 var rng = typeof range != "string" ? range : safe_decode_range(range);
8509 var rngstr = typeof range == "string" ? range : encode_range(range);
8510 for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
8511 var cell = ws_get_cell_stub(ws, R, C);
8512 cell.t = 'n';
8513 cell.F = rngstr;
8514 delete cell.v;
8515 if(R == rng.s.r && C == rng.s.c) cell.f = formula;
8516 }
8517 return ws;
8518};
8519
8520return utils;
8521})(utils);
8522
8523if(typeof parse_xlscfb !== "undefined") XLSX.parse_xlscfb = parse_xlscfb;
8524XLSX.parse_zip = parse_zip;
8525XLSX.read = readSync; //xlsread
8526XLSX.readFile = readFileSync; //readFile
8527XLSX.readFileSync = readFileSync;
8528XLSX.write = writeSync;
8529XLSX.writeFile = writeFileSync;
8530XLSX.writeFileSync = writeFileSync;
8531XLSX.writeFileAsync = writeFileAsync;
8532XLSX.utils = utils;
8533XLSX.SSF = SSF;
8534if(typeof CFB !== "undefined") XLSX.CFB = CFB;
8535}
8536/*global define */
8537if(typeof exports !== 'undefined') make_xlsx_lib(exports);
8538else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
8539else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
8540else make_xlsx_lib(XLSX);
8541/*exported XLS, ODS */
8542var XLS = XLSX, ODS = XLSX;