UNPKG

384 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.17.4';
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.11.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}
239
240var table_fmt = {};
241init_table(table_fmt);
242/* Defaults determined by systematically testing in Excel 2019 */
243
244/* These formats appear to default to other formats in the table */
245var default_map = [];
246var defi = 0;
247
248// 5 -> 37 ... 8 -> 40
249for(defi = 5; defi <= 8; ++defi) default_map[defi] = 32 + defi;
250
251// 23 -> 0 ... 26 -> 0
252for(defi = 23; defi <= 26; ++defi) default_map[defi] = 0;
253
254// 27 -> 14 ... 31 -> 14
255for(defi = 27; defi <= 31; ++defi) default_map[defi] = 14;
256// 50 -> 14 ... 58 -> 14
257for(defi = 50; defi <= 58; ++defi) default_map[defi] = 14;
258
259// 59 -> 1 ... 62 -> 4
260for(defi = 59; defi <= 62; ++defi) default_map[defi] = defi - 58;
261// 67 -> 9 ... 68 -> 10
262for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 58;
263// 72 -> 14 ... 75 -> 17
264for(defi = 72; defi <= 75; ++defi) default_map[defi] = defi - 58;
265
266// 69 -> 12 ... 71 -> 14
267for(defi = 67; defi <= 68; ++defi) default_map[defi] = defi - 57;
268
269// 76 -> 20 ... 78 -> 22
270for(defi = 76; defi <= 78; ++defi) default_map[defi] = defi - 56;
271
272// 79 -> 45 ... 81 -> 47
273for(defi = 79; defi <= 81; ++defi) default_map[defi] = defi - 34;
274
275// 82 -> 0 ... 65536 -> 0 (omitted)
276
277/* These formats technically refer to Accounting formats with no equivalent */
278var default_str = [];
279
280// 5 -- Currency, 0 decimal, black negative
281default_str[5] = default_str[63] = '"$"#,##0_);\\("$"#,##0\\)';
282// 6 -- Currency, 0 decimal, red negative
283default_str[6] = default_str[64] = '"$"#,##0_);[Red]\\("$"#,##0\\)';
284// 7 -- Currency, 2 decimal, black negative
285default_str[7] = default_str[65] = '"$"#,##0.00_);\\("$"#,##0.00\\)';
286// 8 -- Currency, 2 decimal, red negative
287default_str[8] = default_str[66] = '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)';
288
289// 41 -- Accounting, 0 decimal, No Symbol
290default_str[41] = '_(* #,##0_);_(* \\(#,##0\\);_(* "-"_);_(@_)';
291// 42 -- Accounting, 0 decimal, $ Symbol
292default_str[42] = '_("$"* #,##0_);_("$"* \\(#,##0\\);_("$"* "-"_);_(@_)';
293// 43 -- Accounting, 2 decimal, No Symbol
294default_str[43] = '_(* #,##0.00_);_(* \\(#,##0.00\\);_(* "-"??_);_(@_)';
295// 44 -- Accounting, 2 decimal, $ Symbol
296default_str[44] = '_("$"* #,##0.00_);_("$"* \\(#,##0.00\\);_("$"* "-"??_);_(@_)';
297function frac(x, D, mixed) {
298 var sgn = x < 0 ? -1 : 1;
299 var B = x * sgn;
300 var P_2 = 0, P_1 = 1, P = 0;
301 var Q_2 = 1, Q_1 = 0, Q = 0;
302 var A = Math.floor(B);
303 while(Q_1 < D) {
304 A = Math.floor(B);
305 P = A * P_1 + P_2;
306 Q = A * Q_1 + Q_2;
307 if((B - A) < 0.00000005) break;
308 B = 1 / (B - A);
309 P_2 = P_1; P_1 = P;
310 Q_2 = Q_1; Q_1 = Q;
311 }
312 if(Q > D) { if(Q_1 > D) { Q = Q_2; P = P_2; } else { Q = Q_1; P = P_1; } }
313 if(!mixed) return [0, sgn * P, Q];
314 var q = Math.floor(sgn * P/Q);
315 return [q, sgn*P - q*Q, Q];
316}
317function parse_date_code(v,opts,b2) {
318 if(v > 2958465 || v < 0) return null;
319 var date = (v|0), time = Math.floor(86400 * (v - date)), dow=0;
320 var dout=[];
321 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};
322 if(Math.abs(out.u) < 1e-6) out.u = 0;
323 if(opts && opts.date1904) date += 1462;
324 if(out.u > 0.9999) {
325 out.u = 0;
326 if(++time == 86400) { out.T = time = 0; ++date; ++out.D; }
327 }
328 if(date === 60) {dout = b2 ? [1317,10,29] : [1900,2,29]; dow=3;}
329 else if(date === 0) {dout = b2 ? [1317,8,29] : [1900,1,0]; dow=6;}
330 else {
331 if(date > 60) --date;
332 /* 1 = Jan 1 1900 in Gregorian */
333 var d = new Date(1900, 0, 1);
334 d.setDate(d.getDate() + date - 1);
335 dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
336 dow = d.getDay();
337 if(date < 60) dow = (dow + 6) % 7;
338 if(b2) dow = fix_hijri(d, dout);
339 }
340 out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
341 out.S = time % 60; time = Math.floor(time / 60);
342 out.M = time % 60; time = Math.floor(time / 60);
343 out.H = time;
344 out.q = dow;
345 return out;
346}
347SSF.parse_date_code = parse_date_code;
348var basedate = new Date(1899, 11, 31, 0, 0, 0);
349var dnthresh = basedate.getTime();
350var base1904 = new Date(1900, 2, 1, 0, 0, 0);
351function datenum_local(v, date1904) {
352 var epoch = v.getTime();
353 if(date1904) epoch -= 1461*24*60*60*1000;
354 else if(v >= base1904) epoch += 24*60*60*1000;
355 return (epoch - (dnthresh + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000)) / (24 * 60 * 60 * 1000);
356}
357/* The longest 32-bit integer text is "-4294967296", exactly 11 chars */
358function general_fmt_int(v) { return v.toString(10); }
359SSF._general_int = general_fmt_int;
360
361/* ECMA-376 18.8.30 numFmt*/
362/* Note: `toPrecision` uses standard form when prec > E and E >= -6 */
363var general_fmt_num = (function make_general_fmt_num() {
364 var trailing_zeroes_and_decimal = /(?:\.0*|(\.\d*[1-9])0+)$/;
365 function strip_decimal(o) {
366 return (o.indexOf(".") == -1) ? o : o.replace(trailing_zeroes_and_decimal, "$1");
367 }
368
369 /* General Exponential always shows 2 digits exp and trims the mantissa */
370 var mantissa_zeroes_and_decimal = /(?:\.0*|(\.\d*[1-9])0+)[Ee]/;
371 var exp_with_single_digit = /(E[+-])(\d)$/;
372 function normalize_exp(o) {
373 if(o.indexOf("E") == -1) return o;
374 return o.replace(mantissa_zeroes_and_decimal,"$1E").replace(exp_with_single_digit,"$10$2");
375 }
376
377 /* exponent >= -9 and <= 9 */
378 function small_exp(v) {
379 var w = (v<0?12:11);
380 var o = strip_decimal(v.toFixed(12)); if(o.length <= w) return o;
381 o = v.toPrecision(10); if(o.length <= w) return o;
382 return v.toExponential(5);
383 }
384
385 /* exponent >= 11 or <= -10 likely exponential */
386 function large_exp(v) {
387 var o = strip_decimal(v.toFixed(11));
388 return (o.length > (v<0?12:11) || o === "0" || o === "-0") ? v.toPrecision(6) : o;
389 }
390
391 function general_fmt_num_base(v) {
392 var V = Math.floor(Math.log(Math.abs(v))*Math.LOG10E), o;
393
394 if(V >= -4 && V <= -1) o = v.toPrecision(10+V);
395 else if(Math.abs(V) <= 9) o = small_exp(v);
396 else if(V === 10) o = v.toFixed(10).substr(0,12);
397 else o = large_exp(v);
398
399 return strip_decimal(normalize_exp(o.toUpperCase()));
400 }
401
402 return general_fmt_num_base;
403})();
404SSF._general_num = general_fmt_num;
405
406/*
407 "General" rules:
408 - text is passed through ("@")
409 - booleans are rendered as TRUE/FALSE
410 - "up to 11 characters" displayed for numbers
411 - Default date format (code 14) used for Dates
412
413 TODO: technically the display depends on the width of the cell
414*/
415function general_fmt(v, opts) {
416 switch(typeof v) {
417 case 'string': return v;
418 case 'boolean': return v ? "TRUE" : "FALSE";
419 case 'number': return (v|0) === v ? v.toString(10) : general_fmt_num(v);
420 case 'undefined': return "";
421 case 'object':
422 if(v == null) return "";
423 if(v instanceof Date) return format(14, datenum_local(v, opts && opts.date1904), opts);
424 }
425 throw new Error("unsupported value in General format: " + v);
426}
427SSF._general = general_fmt;
428function fix_hijri(date, o) {
429 /* TODO: properly adjust y/m/d and */
430 o[0] -= 581;
431 var dow = date.getDay();
432 if(date < 60) dow = (dow + 6) % 7;
433 return dow;
434}
435//var THAI_DIGITS = "\u0E50\u0E51\u0E52\u0E53\u0E54\u0E55\u0E56\u0E57\u0E58\u0E59".split("");
436/*jshint -W086 */
437function write_date(type, fmt, val, ss0) {
438 var o="", ss=0, tt=0, y = val.y, out, outl = 0;
439 switch(type) {
440 case 98: /* 'b' buddhist year */
441 y = val.y + 543;
442 /* falls through */
443 case 121: /* 'y' year */
444 switch(fmt.length) {
445 case 1: case 2: out = y % 100; outl = 2; break;
446 default: out = y % 10000; outl = 4; break;
447 } break;
448 case 109: /* 'm' month */
449 switch(fmt.length) {
450 case 1: case 2: out = val.m; outl = fmt.length; break;
451 case 3: return months[val.m-1][1];
452 case 5: return months[val.m-1][0];
453 default: return months[val.m-1][2];
454 } break;
455 case 100: /* 'd' day */
456 switch(fmt.length) {
457 case 1: case 2: out = val.d; outl = fmt.length; break;
458 case 3: return days[val.q][0];
459 default: return days[val.q][1];
460 } break;
461 case 104: /* 'h' 12-hour */
462 switch(fmt.length) {
463 case 1: case 2: out = 1+(val.H+11)%12; outl = fmt.length; break;
464 default: throw 'bad hour format: ' + fmt;
465 } break;
466 case 72: /* 'H' 24-hour */
467 switch(fmt.length) {
468 case 1: case 2: out = val.H; outl = fmt.length; break;
469 default: throw 'bad hour format: ' + fmt;
470 } break;
471 case 77: /* 'M' minutes */
472 switch(fmt.length) {
473 case 1: case 2: out = val.M; outl = fmt.length; break;
474 default: throw 'bad minute format: ' + fmt;
475 } break;
476 case 115: /* 's' seconds */
477 if(fmt != 's' && fmt != 'ss' && fmt != '.0' && fmt != '.00' && fmt != '.000') throw 'bad second format: ' + fmt;
478 if(val.u === 0 && (fmt == "s" || fmt == "ss")) return pad0(val.S, fmt.length);
479if(ss0 >= 2) tt = ss0 === 3 ? 1000 : 100;
480 else tt = ss0 === 1 ? 10 : 1;
481 ss = Math.round((tt)*(val.S + val.u));
482 if(ss >= 60*tt) ss = 0;
483 if(fmt === 's') return ss === 0 ? "0" : ""+ss/tt;
484 o = pad0(ss,2 + ss0);
485 if(fmt === 'ss') return o.substr(0,2);
486 return "." + o.substr(2,fmt.length-1);
487 case 90: /* 'Z' absolute time */
488 switch(fmt) {
489 case '[h]': case '[hh]': out = val.D*24+val.H; break;
490 case '[m]': case '[mm]': out = (val.D*24+val.H)*60+val.M; break;
491 case '[s]': case '[ss]': out = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
492 default: throw 'bad abstime format: ' + fmt;
493 } outl = fmt.length === 3 ? 1 : 2; break;
494 case 101: /* 'e' era */
495 out = y; outl = 1; break;
496 }
497 var outstr = outl > 0 ? pad0(out, outl) : "";
498 return outstr;
499}
500/*jshint +W086 */
501function commaify(s) {
502 var w = 3;
503 if(s.length <= w) return s;
504 var j = (s.length % w), o = s.substr(0,j);
505 for(; j!=s.length; j+=w) o+=(o.length > 0 ? "," : "") + s.substr(j,w);
506 return o;
507}
508var write_num = (function make_write_num(){
509var pct1 = /%/g;
510function write_num_pct(type, fmt, val){
511 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
512 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
513}
514function write_num_cm(type, fmt, val){
515 var idx = fmt.length - 1;
516 while(fmt.charCodeAt(idx-1) === 44) --idx;
517 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
518}
519function write_num_exp(fmt, val){
520 var o;
521 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
522 if(fmt.match(/^#+0.0E\+0$/)) {
523 if(val == 0) return "0.0E+0";
524 else if(val < 0) return "-" + write_num_exp(fmt, -val);
525 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
526 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
527 if(ee < 0) ee += period;
528 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
529 if(o.indexOf("e") === -1) {
530 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
531 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
532 else o += "E+" + (fakee - ee);
533 while(o.substr(0,2) === "0.") {
534 o = o.charAt(0) + o.substr(2,period) + "." + o.substr(2+period);
535 o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
536 }
537 o = o.replace(/\+-/,"-");
538 }
539 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
540 } else o = val.toExponential(idx);
541 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
542 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
543 return o.replace("e","E");
544}
545var frac1 = /# (\?+)( ?)\/( ?)(\d+)/;
546function write_num_f1(r, aval, sign) {
547 var den = parseInt(r[4],10), rr = Math.round(aval * den), base = Math.floor(rr/den);
548 var myn = (rr - base*den), myd = den;
549 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));
550}
551function write_num_f2(r, aval, sign) {
552 return sign + (aval === 0 ? "" : ""+aval) + fill(" ", r[1].length + 2 + r[4].length);
553}
554var dec1 = /^#*0*\.([0#]+)/;
555var closeparen = /\).*[0#]/;
556var phone = /\(###\) ###\\?-####/;
557function hashq(str) {
558 var o = "", cc;
559 for(var i = 0; i != str.length; ++i) switch((cc=str.charCodeAt(i))) {
560 case 35: break;
561 case 63: o+= " "; break;
562 case 48: o+= "0"; break;
563 default: o+= String.fromCharCode(cc);
564 }
565 return o;
566}
567function rnd(val, d) { var dd = Math.pow(10,d); return ""+(Math.round(val * dd)/dd); }
568function dec(val, d) {
569 var _frac = val - Math.floor(val), dd = Math.pow(10,d);
570 if (d < ('' + Math.round(_frac * dd)).length) return 0;
571 return Math.round(_frac * dd);
572}
573function carry(val, d) {
574 if (d < ('' + Math.round((val-Math.floor(val))*Math.pow(10,d))).length) {
575 return 1;
576 }
577 return 0;
578}
579function flr(val) {
580 if(val < 2147483647 && val > -2147483648) return ""+(val >= 0 ? (val|0) : (val-1|0));
581 return ""+Math.floor(val);
582}
583function write_num_flt(type, fmt, val) {
584 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
585 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
586 if(val >= 0) return write_num_flt('n', ffmt, val);
587 return '(' + write_num_flt('n', ffmt, -val) + ')';
588 }
589 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm(type, fmt, val);
590 if(fmt.indexOf('%') !== -1) return write_num_pct(type, fmt, val);
591 if(fmt.indexOf('E') !== -1) return write_num_exp(fmt, val);
592 if(fmt.charCodeAt(0) === 36) return "$"+write_num_flt(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
593 var o;
594 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
595 if(fmt.match(/^00+$/)) return sign + pad0r(aval,fmt.length);
596 if(fmt.match(/^[#?]+$/)) {
597 o = pad0r(val,0); if(o === "0") o = "";
598 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
599 }
600 if((r = fmt.match(frac1))) return write_num_f1(r, aval, sign);
601 if(fmt.match(/^#+0+$/)) return sign + pad0r(aval,fmt.length - fmt.indexOf("0"));
602 if((r = fmt.match(dec1))) {
603 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); });
604 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
605 }
606 fmt = fmt.replace(/^#+([0.])/, "$1");
607 if((r = fmt.match(/^(0*)\.(#*)$/))) {
608 return sign + rnd(aval, r[2].length).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
609 }
610 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify(pad0r(aval,0));
611 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
612 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);
613 }
614 if((r = fmt.match(/^#,#*,#0/))) return write_num_flt(type,fmt.replace(/^#,#*,/,""),val);
615 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
616 o = _strrev(write_num_flt(type, fmt.replace(/[\\-]/g,""), val));
617 ri = 0;
618 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
619 }
620 if(fmt.match(phone)) {
621 o = write_num_flt(type, "##########", val);
622 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
623 }
624 var oa = "";
625 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
626 ri = Math.min(r[4].length,7);
627 ff = frac(aval, Math.pow(10,ri)-1, false);
628 o = "" + sign;
629 oa = write_num("n", r[1], ff[1]);
630 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
631 o += oa + r[2] + "/" + r[3];
632 oa = rpad_(ff[2],ri);
633 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
634 o += oa;
635 return o;
636 }
637 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
638 ri = Math.min(Math.max(r[1].length, r[4].length),7);
639 ff = frac(aval, Math.pow(10,ri)-1, true);
640 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));
641 }
642 if((r = fmt.match(/^[#0?]+$/))) {
643 o = pad0r(val, 0);
644 if(fmt.length <= o.length) return o;
645 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
646 }
647 if((r = fmt.match(/^([#0?]+)\.([#0]+)$/))) {
648 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
649 ri = o.indexOf(".");
650 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
651 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
652 }
653 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
654 ri = dec(val, r[1].length);
655 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);
656 }
657 switch(fmt) {
658 case "###,##0.00": return write_num_flt(type, "#,##0.00", val);
659 case "###,###":
660 case "##,###":
661 case "#,###": var x = commaify(pad0r(aval,0)); return x !== "0" ? sign + x : "";
662 case "###,###.00": return write_num_flt(type, "###,##0.00",val).replace(/^0\./,".");
663 case "#,###.00": return write_num_flt(type, "#,##0.00",val).replace(/^0\./,".");
664 default:
665 }
666 throw new Error("unsupported format |" + fmt + "|");
667}
668function write_num_cm2(type, fmt, val){
669 var idx = fmt.length - 1;
670 while(fmt.charCodeAt(idx-1) === 44) --idx;
671 return write_num(type, fmt.substr(0,idx), val / Math.pow(10,3*(fmt.length-idx)));
672}
673function write_num_pct2(type, fmt, val){
674 var sfmt = fmt.replace(pct1,""), mul = fmt.length - sfmt.length;
675 return write_num(type, sfmt, val * Math.pow(10,2*mul)) + fill("%",mul);
676}
677function write_num_exp2(fmt, val){
678 var o;
679 var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
680 if(fmt.match(/^#+0.0E\+0$/)) {
681 if(val == 0) return "0.0E+0";
682 else if(val < 0) return "-" + write_num_exp2(fmt, -val);
683 var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
684 var ee = Math.floor(Math.log(val)*Math.LOG10E)%period;
685 if(ee < 0) ee += period;
686 o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
687 if(!o.match(/[Ee]/)) {
688 var fakee = Math.floor(Math.log(val)*Math.LOG10E);
689 if(o.indexOf(".") === -1) o = o.charAt(0) + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
690 else o += "E+" + (fakee - ee);
691 o = o.replace(/\+-/,"-");
692 }
693 o = o.replace(/^([+-]?)(\d*)\.(\d*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
694 } else o = val.toExponential(idx);
695 if(fmt.match(/E\+00$/) && o.match(/e[+-]\d$/)) o = o.substr(0,o.length-1) + "0" + o.charAt(o.length-1);
696 if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
697 return o.replace("e","E");
698}
699function write_num_int(type, fmt, val) {
700 if(type.charCodeAt(0) === 40 && !fmt.match(closeparen)) {
701 var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
702 if(val >= 0) return write_num_int('n', ffmt, val);
703 return '(' + write_num_int('n', ffmt, -val) + ')';
704 }
705 if(fmt.charCodeAt(fmt.length - 1) === 44) return write_num_cm2(type, fmt, val);
706 if(fmt.indexOf('%') !== -1) return write_num_pct2(type, fmt, val);
707 if(fmt.indexOf('E') !== -1) return write_num_exp2(fmt, val);
708 if(fmt.charCodeAt(0) === 36) return "$"+write_num_int(type,fmt.substr(fmt.charAt(1)==' '?2:1),val);
709 var o;
710 var r, ri, ff, aval = Math.abs(val), sign = val < 0 ? "-" : "";
711 if(fmt.match(/^00+$/)) return sign + pad0(aval,fmt.length);
712 if(fmt.match(/^[#?]+$/)) {
713 o = (""+val); if(val === 0) o = "";
714 return o.length > fmt.length ? o : hashq(fmt.substr(0,fmt.length-o.length)) + o;
715 }
716 if((r = fmt.match(frac1))) return write_num_f2(r, aval, sign);
717 if(fmt.match(/^#+0+$/)) return sign + pad0(aval,fmt.length - fmt.indexOf("0"));
718 if((r = fmt.match(dec1))) {
719o = (""+val).replace(/^([^\.]+)$/,"$1."+hashq(r[1])).replace(/\.$/,"."+hashq(r[1]));
720 o = o.replace(/\.(\d*)$/,function($$, $1) {
721return "." + $1 + fill("0", hashq(r[1]).length-$1.length); });
722 return fmt.indexOf("0.") !== -1 ? o : o.replace(/^0\./,".");
723 }
724 fmt = fmt.replace(/^#+([0.])/, "$1");
725 if((r = fmt.match(/^(0*)\.(#*)$/))) {
726 return sign + (""+aval).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^(-?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
727 }
728 if((r = fmt.match(/^#{1,3},##0(\.?)$/))) return sign + commaify((""+aval));
729 if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
730 return val < 0 ? "-" + write_num_int(type, fmt, -val) : commaify((""+val)) + "." + fill('0',r[1].length);
731 }
732 if((r = fmt.match(/^#,#*,#0/))) return write_num_int(type,fmt.replace(/^#,#*,/,""),val);
733 if((r = fmt.match(/^([0#]+)(\\?-([0#]+))+$/))) {
734 o = _strrev(write_num_int(type, fmt.replace(/[\\-]/g,""), val));
735 ri = 0;
736 return _strrev(_strrev(fmt.replace(/\\/g,"")).replace(/[0#]/g,function(x){return ri<o.length?o.charAt(ri++):x==='0'?'0':"";}));
737 }
738 if(fmt.match(phone)) {
739 o = write_num_int(type, "##########", val);
740 return "(" + o.substr(0,3) + ") " + o.substr(3, 3) + "-" + o.substr(6);
741 }
742 var oa = "";
743 if((r = fmt.match(/^([#0?]+)( ?)\/( ?)([#0?]+)/))) {
744 ri = Math.min(r[4].length,7);
745 ff = frac(aval, Math.pow(10,ri)-1, false);
746 o = "" + sign;
747 oa = write_num("n", r[1], ff[1]);
748 if(oa.charAt(oa.length-1) == " ") oa = oa.substr(0,oa.length-1) + "0";
749 o += oa + r[2] + "/" + r[3];
750 oa = rpad_(ff[2],ri);
751 if(oa.length < r[4].length) oa = hashq(r[4].substr(r[4].length-oa.length)) + oa;
752 o += oa;
753 return o;
754 }
755 if((r = fmt.match(/^# ([#0?]+)( ?)\/( ?)([#0?]+)/))) {
756 ri = Math.min(Math.max(r[1].length, r[4].length),7);
757 ff = frac(aval, Math.pow(10,ri)-1, true);
758 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));
759 }
760 if((r = fmt.match(/^[#0?]+$/))) {
761 o = "" + val;
762 if(fmt.length <= o.length) return o;
763 return hashq(fmt.substr(0,fmt.length-o.length)) + o;
764 }
765 if((r = fmt.match(/^([#0]+)\.([#0]+)$/))) {
766 o = "" + val.toFixed(Math.min(r[2].length,10)).replace(/([^0])0+$/,"$1");
767 ri = o.indexOf(".");
768 var lres = fmt.indexOf(".") - ri, rres = fmt.length - o.length - lres;
769 return hashq(fmt.substr(0,lres) + o + fmt.substr(fmt.length-rres));
770 }
771 if((r = fmt.match(/^00,000\.([#0]*0)$/))) {
772 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);
773 }
774 switch(fmt) {
775 case "###,###":
776 case "##,###":
777 case "#,###": var x = commaify(""+aval); return x !== "0" ? sign + x : "";
778 default:
779 if(fmt.match(/\.[0#?]*$/)) return write_num_int(type, fmt.slice(0,fmt.lastIndexOf(".")), val) + hashq(fmt.slice(fmt.lastIndexOf(".")));
780 }
781 throw new Error("unsupported format |" + fmt + "|");
782}
783return function write_num(type, fmt, val) {
784 return (val|0) === val ? write_num_int(type, fmt, val) : write_num_flt(type, fmt, val);
785};})();
786function split_fmt(fmt) {
787 var out = [];
788 var in_str = false/*, cc*/;
789 for(var i = 0, j = 0; i < fmt.length; ++i) switch((/*cc=*/fmt.charCodeAt(i))) {
790 case 34: /* '"' */
791 in_str = !in_str; break;
792 case 95: case 42: case 92: /* '_' '*' '\\' */
793 ++i; break;
794 case 59: /* ';' */
795 out[out.length] = fmt.substr(j,i-j);
796 j = i+1;
797 }
798 out[out.length] = fmt.substr(j);
799 if(in_str === true) throw new Error("Format |" + fmt + "| unterminated string ");
800 return out;
801}
802SSF._split = split_fmt;
803var abstime = /\[[HhMmSs\u0E0A\u0E19\u0E17]*\]/;
804function fmt_is_date(fmt) {
805 var i = 0, /*cc = 0,*/ c = "", o = "";
806 while(i < fmt.length) {
807 switch((c = fmt.charAt(i))) {
808 case 'G': if(isgeneral(fmt, i)) i+= 6; i++; break;
809 case '"': for(;(/*cc=*/fmt.charCodeAt(++i)) !== 34 && i < fmt.length;){/*empty*/} ++i; break;
810 case '\\': i+=2; break;
811 case '_': i+=2; break;
812 case '@': ++i; break;
813 case 'B': case 'b':
814 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") return true;
815 /* falls through */
816 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
817 /* falls through */
818 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g': return true;
819 case 'A': case 'a': case '上':
820 if(fmt.substr(i, 3).toUpperCase() === "A/P") return true;
821 if(fmt.substr(i, 5).toUpperCase() === "AM/PM") return true;
822 if(fmt.substr(i, 5).toUpperCase() === "上午/下午") return true;
823 ++i; break;
824 case '[':
825 o = c;
826 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
827 if(o.match(abstime)) return true;
828 break;
829 case '.':
830 /* falls through */
831 case '0': case '#':
832 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 */}
833 break;
834 case '?': while(fmt.charAt(++i) === c){/* empty */} break;
835 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break;
836 case '(': case ')': ++i; break;
837 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
838 while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1){/* empty */} break;
839 case ' ': ++i; break;
840 default: ++i; break;
841 }
842 }
843 return false;
844}
845SSF.is_date = fmt_is_date;
846function eval_fmt(fmt, v, opts, flen) {
847 var out = [], o = "", i = 0, c = "", lst='t', dt, j, cc;
848 var hr='H';
849 /* Tokenize */
850 while(i < fmt.length) {
851 switch((c = fmt.charAt(i))) {
852 case 'G': /* General */
853 if(!isgeneral(fmt, i)) throw new Error('unrecognized character ' + c + ' in ' +fmt);
854 out[out.length] = {t:'G', v:'General'}; i+=7; break;
855 case '"': /* Literal text */
856 for(o="";(cc=fmt.charCodeAt(++i)) !== 34 && i < fmt.length;) o += String.fromCharCode(cc);
857 out[out.length] = {t:'t', v:o}; ++i; break;
858 case '\\': var w = fmt.charAt(++i), t = (w === "(" || w === ")") ? w : 't';
859 out[out.length] = {t:t, v:w}; ++i; break;
860 case '_': out[out.length] = {t:'t', v:" "}; i+=2; break;
861 case '@': /* Text Placeholder */
862 out[out.length] = {t:'T', v:v}; ++i; break;
863 case 'B': case 'b':
864 if(fmt.charAt(i+1) === "1" || fmt.charAt(i+1) === "2") {
865 if(dt==null) { dt=parse_date_code(v, opts, fmt.charAt(i+1) === "2"); if(dt==null) return ""; }
866 out[out.length] = {t:'X', v:fmt.substr(i,2)}; lst = c; i+=2; break;
867 }
868 /* falls through */
869 case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
870 c = c.toLowerCase();
871 /* falls through */
872 case 'm': case 'd': case 'y': case 'h': case 's': case 'e': case 'g':
873 if(v < 0) return "";
874 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
875 o = c; while(++i < fmt.length && fmt.charAt(i).toLowerCase() === c) o+=c;
876 if(c === 'm' && lst.toLowerCase() === 'h') c = 'M';
877 if(c === 'h') c = hr;
878 out[out.length] = {t:c, v:o}; lst = c; break;
879 case 'A': case 'a': case '上':
880 var q={t:c, v:c};
881 if(dt==null) dt=parse_date_code(v, opts);
882 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;}
883 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'; }
884 else if(fmt.substr(i,5).toUpperCase() === "上午/下午") { if(dt!=null) q.v = dt.H >= 12 ? "下午" : "上午"; q.t = 'T'; i+=5; hr='h'; }
885 else { q.t = "t"; ++i; }
886 if(dt==null && q.t === 'T') return "";
887 out[out.length] = q; lst = c; break;
888 case '[':
889 o = c;
890 while(fmt.charAt(i++) !== ']' && i < fmt.length) o += fmt.charAt(i);
891 if(o.slice(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
892 if(o.match(abstime)) {
893 if(dt==null) { dt=parse_date_code(v, opts); if(dt==null) return ""; }
894 out[out.length] = {t:'Z', v:o.toLowerCase()};
895 lst = o.charAt(1);
896 } else if(o.indexOf("$") > -1) {
897 o = (o.match(/\$([^-\[\]]*)/)||[])[1]||"$";
898 if(!fmt_is_date(fmt)) out[out.length] = {t:'t',v:o};
899 }
900 break;
901 /* Numbers */
902 case '.':
903 if(dt != null) {
904 o = c; while(++i < fmt.length && (c=fmt.charAt(i)) === "0") o += c;
905 out[out.length] = {t:'s', v:o}; break;
906 }
907 /* falls through */
908 case '0': case '#':
909 o = c; while(++i < fmt.length && "0#?.,E+-%".indexOf(c=fmt.charAt(i)) > -1) o += c;
910 out[out.length] = {t:'n', v:o}; break;
911 case '?':
912 o = c; while(fmt.charAt(++i) === c) o+=c;
913 out[out.length] = {t:c, v:o}; lst = c; break;
914 case '*': ++i; if(fmt.charAt(i) == ' ' || fmt.charAt(i) == '*') ++i; break; // **
915 case '(': case ')': out[out.length] = {t:(flen===1?'t':c), v:c}; ++i; break;
916 case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9':
917 o = c; while(i < fmt.length && "0123456789".indexOf(fmt.charAt(++i)) > -1) o+=fmt.charAt(i);
918 out[out.length] = {t:'D', v:o}; break;
919 case ' ': out[out.length] = {t:c, v:c}; ++i; break;
920 case '$': out[out.length] = {t:'t', v:'$'}; ++i; break;
921 default:
922 if(",$-+/():!^&'~{}<>=€acfijklopqrtuvwxzP".indexOf(c) === -1) throw new Error('unrecognized character ' + c + ' in ' + fmt);
923 out[out.length] = {t:'t', v:c}; ++i; break;
924 }
925 }
926
927 /* Scan for date/time parts */
928 var bt = 0, ss0 = 0, ssm;
929 for(i=out.length-1, lst='t'; i >= 0; --i) {
930 switch(out[i].t) {
931 case 'h': case 'H': out[i].t = hr; lst='h'; if(bt < 1) bt = 1; break;
932 case 's':
933 if((ssm=out[i].v.match(/\.0+$/))) ss0=Math.max(ss0,ssm[0].length-1);
934 if(bt < 3) bt = 3;
935 /* falls through */
936 case 'd': case 'y': case 'M': case 'e': lst=out[i].t; break;
937 case 'm': if(lst === 's') { out[i].t = 'M'; if(bt < 2) bt = 2; } break;
938 case 'X': /*if(out[i].v === "B2");*/
939 break;
940 case 'Z':
941 if(bt < 1 && out[i].v.match(/[Hh]/)) bt = 1;
942 if(bt < 2 && out[i].v.match(/[Mm]/)) bt = 2;
943 if(bt < 3 && out[i].v.match(/[Ss]/)) bt = 3;
944 }
945 }
946 /* time rounding depends on presence of minute / second / usec fields */
947 switch(bt) {
948 case 0: break;
949 case 1:
950if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
951 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
952 if(dt.M >= 60) { dt.M = 0; ++dt.H; }
953 break;
954 case 2:
955if(dt.u >= 0.5) { dt.u = 0; ++dt.S; }
956 if(dt.S >= 60) { dt.S = 0; ++dt.M; }
957 break;
958 }
959
960 /* replace fields */
961 var nstr = "", jj;
962 for(i=0; i < out.length; ++i) {
963 switch(out[i].t) {
964 case 't': case 'T': case ' ': case 'D': break;
965 case 'X': out[i].v = ""; out[i].t = ";"; break;
966 case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'b': case 'Z':
967out[i].v = write_date(out[i].t.charCodeAt(0), out[i].v, dt, ss0);
968 out[i].t = 't'; break;
969 case 'n': case '?':
970 jj = i+1;
971 while(out[jj] != null && (
972 (c=out[jj].t) === "?" || c === "D" ||
973 ((c === " " || c === "t") && out[jj+1] != null && (out[jj+1].t === '?' || out[jj+1].t === "t" && out[jj+1].v === '/')) ||
974 (out[i].t === '(' && (c === ' ' || c === 'n' || c === ')')) ||
975 (c === 't' && (out[jj].v === '/' || out[jj].v === ' ' && out[jj+1] != null && out[jj+1].t == '?'))
976 )) {
977 out[i].v += out[jj].v;
978 out[jj] = {v:"", t:";"}; ++jj;
979 }
980 nstr += out[i].v;
981 i = jj-1; break;
982 case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
983 }
984 }
985 var vv = "", myv, ostr;
986 if(nstr.length > 0) {
987 if(nstr.charCodeAt(0) == 40) /* '(' */ {
988 myv = (v<0&&nstr.charCodeAt(0) === 45 ? -v : v);
989 ostr = write_num('n', nstr, myv);
990 } else {
991 myv = (v<0 && flen > 1 ? -v : v);
992 ostr = write_num('n', nstr, myv);
993 if(myv < 0 && out[0] && out[0].t == 't') {
994 ostr = ostr.substr(1);
995 out[0].v = "-" + out[0].v;
996 }
997 }
998 jj=ostr.length-1;
999 var decpt = out.length;
1000 for(i=0; i < out.length; ++i) if(out[i] != null && out[i].t != 't' && out[i].v.indexOf(".") > -1) { decpt = i; break; }
1001 var lasti=out.length;
1002 if(decpt === out.length && ostr.indexOf("E") === -1) {
1003 for(i=out.length-1; i>= 0;--i) {
1004 if(out[i] == null || 'n?'.indexOf(out[i].t) === -1) continue;
1005 if(jj>=out[i].v.length-1) { jj -= out[i].v.length; out[i].v = ostr.substr(jj+1, out[i].v.length); }
1006 else if(jj < 0) out[i].v = "";
1007 else { out[i].v = ostr.substr(0, jj+1); jj = -1; }
1008 out[i].t = 't';
1009 lasti = i;
1010 }
1011 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
1012 }
1013 else if(decpt !== out.length && ostr.indexOf("E") === -1) {
1014 jj = ostr.indexOf(".")-1;
1015 for(i=decpt; i>= 0; --i) {
1016 if(out[i] == null || 'n?'.indexOf(out[i].t) === -1) continue;
1017 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")-1:out[i].v.length-1;
1018 vv = out[i].v.substr(j+1);
1019 for(; j>=0; --j) {
1020 if(jj>=0 && (out[i].v.charAt(j) === "0" || out[i].v.charAt(j) === "#")) vv = ostr.charAt(jj--) + vv;
1021 }
1022 out[i].v = vv;
1023 out[i].t = 't';
1024 lasti = i;
1025 }
1026 if(jj>=0 && lasti<out.length) out[lasti].v = ostr.substr(0,jj+1) + out[lasti].v;
1027 jj = ostr.indexOf(".")+1;
1028 for(i=decpt; i<out.length; ++i) {
1029 if(out[i] == null || ('n?('.indexOf(out[i].t) === -1 && i !== decpt)) continue;
1030 j=out[i].v.indexOf(".")>-1&&i===decpt?out[i].v.indexOf(".")+1:0;
1031 vv = out[i].v.substr(0,j);
1032 for(; j<out[i].v.length; ++j) {
1033 if(jj<ostr.length) vv += ostr.charAt(jj++);
1034 }
1035 out[i].v = vv;
1036 out[i].t = 't';
1037 lasti = i;
1038 }
1039 }
1040 }
1041 for(i=0; i<out.length; ++i) if(out[i] != null && 'n?'.indexOf(out[i].t)>-1) {
1042 myv = (flen >1 && v < 0 && i>0 && out[i-1].v === "-" ? -v:v);
1043 out[i].v = write_num(out[i].t, out[i].v, myv);
1044 out[i].t = 't';
1045 }
1046 var retval = "";
1047 for(i=0; i !== out.length; ++i) if(out[i] != null) retval += out[i].v;
1048 return retval;
1049}
1050SSF._eval = eval_fmt;
1051var cfregex = /\[[=<>]/;
1052var cfregex2 = /\[(=|>[=]?|<[>=]?)(-?\d+(?:\.\d*)?)\]/;
1053function chkcond(v, rr) {
1054 if(rr == null) return false;
1055 var thresh = parseFloat(rr[2]);
1056 switch(rr[1]) {
1057 case "=": if(v == thresh) return true; break;
1058 case ">": if(v > thresh) return true; break;
1059 case "<": if(v < thresh) return true; break;
1060 case "<>": if(v != thresh) return true; break;
1061 case ">=": if(v >= thresh) return true; break;
1062 case "<=": if(v <= thresh) return true; break;
1063 }
1064 return false;
1065}
1066function choose_fmt(f, v) {
1067 var fmt = split_fmt(f);
1068 var l = fmt.length, lat = fmt[l-1].indexOf("@");
1069 if(l<4 && lat>-1) --l;
1070 if(fmt.length > 4) throw new Error("cannot find right format for |" + fmt.join("|") + "|");
1071 if(typeof v !== "number") return [4, fmt.length === 4 || lat>-1?fmt[fmt.length-1]:"@"];
1072 switch(fmt.length) {
1073 case 1: fmt = lat>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
1074 case 2: fmt = lat>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
1075 case 3: fmt = lat>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
1076 case 4: break;
1077 }
1078 var ff = v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2];
1079 if(fmt[0].indexOf("[") === -1 && fmt[1].indexOf("[") === -1) return [l, ff];
1080 if(fmt[0].match(cfregex) != null || fmt[1].match(cfregex) != null) {
1081 var m1 = fmt[0].match(cfregex2);
1082 var m2 = fmt[1].match(cfregex2);
1083 return chkcond(v, m1) ? [l, fmt[0]] : chkcond(v, m2) ? [l, fmt[1]] : [l, fmt[m1 != null && m2 != null ? 2 : 1]];
1084 }
1085 return [l, ff];
1086}
1087function format(fmt,v,o) {
1088 if(o == null) o = {};
1089 var sfmt = "";
1090 switch(typeof fmt) {
1091 case "string":
1092 if(fmt == "m/d/yy" && o.dateNF) sfmt = o.dateNF;
1093 else sfmt = fmt;
1094 break;
1095 case "number":
1096 if(fmt == 14 && o.dateNF) sfmt = o.dateNF;
1097 else sfmt = (o.table != null ? (o.table) : table_fmt)[fmt];
1098 if(sfmt == null) sfmt = (o.table && o.table[default_map[fmt]]) || table_fmt[default_map[fmt]];
1099 if(sfmt == null) sfmt = default_str[fmt] || "General";
1100 break;
1101 }
1102 if(isgeneral(sfmt,0)) return general_fmt(v, o);
1103 if(v instanceof Date) v = datenum_local(v, o.date1904);
1104 var f = choose_fmt(sfmt, v);
1105 if(isgeneral(f[1])) return general_fmt(v, o);
1106 if(v === true) v = "TRUE"; else if(v === false) v = "FALSE";
1107 else if(v === "" || v == null) return "";
1108 return eval_fmt(f[1], v, o, f[0]);
1109}
1110function load_entry(fmt, idx) {
1111 if(typeof idx != 'number') {
1112 idx = +idx || -1;
1113for(var i = 0; i < 0x0188; ++i) {
1114if(table_fmt[i] == undefined) { if(idx < 0) idx = i; continue; }
1115 if(table_fmt[i] == fmt) { idx = i; break; }
1116 }
1117if(idx < 0) idx = 0x187;
1118 }
1119table_fmt[idx] = fmt;
1120 return idx;
1121}
1122SSF.load = load_entry;
1123SSF._table = table_fmt;
1124SSF.get_table = function get_table() { return table_fmt; };
1125SSF.load_table = function load_table(tbl) {
1126 for(var i=0; i!=0x0188; ++i)
1127 if(tbl[i] !== undefined) load_entry(tbl[i], i);
1128};
1129SSF.init_table = init_table;
1130SSF.format = format;
1131};
1132make_ssf(SSF);
1133/* map from xlml named formats to SSF TODO: localize */
1134var XLMLFormatMap/*{[string]:string}*/ = ({
1135 "General Number": "General",
1136 "General Date": SSF._table[22],
1137 "Long Date": "dddd, mmmm dd, yyyy",
1138 "Medium Date": SSF._table[15],
1139 "Short Date": SSF._table[14],
1140 "Long Time": SSF._table[19],
1141 "Medium Time": SSF._table[18],
1142 "Short Time": SSF._table[20],
1143 "Currency": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1144 "Fixed": SSF._table[2],
1145 "Standard": SSF._table[4],
1146 "Percent": SSF._table[10],
1147 "Scientific": SSF._table[11],
1148 "Yes/No": '"Yes";"Yes";"No";@',
1149 "True/False": '"True";"True";"False";@',
1150 "On/Off": '"Yes";"Yes";"No";@'
1151});
1152
1153var SSFImplicit/*{[number]:string}*/ = ({
1154 "5": '"$"#,##0_);\\("$"#,##0\\)',
1155 "6": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1156 "7": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1157 "8": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1158 "23": 'General', "24": 'General', "25": 'General', "26": 'General',
1159 "27": 'm/d/yy', "28": 'm/d/yy', "29": 'm/d/yy', "30": 'm/d/yy', "31": 'm/d/yy',
1160 "32": 'h:mm:ss', "33": 'h:mm:ss', "34": 'h:mm:ss', "35": 'h:mm:ss',
1161 "36": 'm/d/yy',
1162 "41": '_(* #,##0_);_(* \(#,##0\);_(* "-"_);_(@_)',
1163 "42": '_("$"* #,##0_);_("$"* \(#,##0\);_("$"* "-"_);_(@_)',
1164 "43": '_(* #,##0.00_);_(* \(#,##0.00\);_(* "-"??_);_(@_)',
1165 "44": '_("$"* #,##0.00_);_("$"* \(#,##0.00\);_("$"* "-"??_);_(@_)',
1166 "50": 'm/d/yy', "51": 'm/d/yy', "52": 'm/d/yy', "53": 'm/d/yy', "54": 'm/d/yy',
1167 "55": 'm/d/yy', "56": 'm/d/yy', "57": 'm/d/yy', "58": 'm/d/yy',
1168 "59": '0',
1169 "60": '0.00',
1170 "61": '#,##0',
1171 "62": '#,##0.00',
1172 "63": '"$"#,##0_);\\("$"#,##0\\)',
1173 "64": '"$"#,##0_);[Red]\\("$"#,##0\\)',
1174 "65": '"$"#,##0.00_);\\("$"#,##0.00\\)',
1175 "66": '"$"#,##0.00_);[Red]\\("$"#,##0.00\\)',
1176 "67": '0%',
1177 "68": '0.00%',
1178 "69": '# ?/?',
1179 "70": '# ??/??',
1180 "71": 'm/d/yy',
1181 "72": 'm/d/yy',
1182 "73": 'd-mmm-yy',
1183 "74": 'd-mmm',
1184 "75": 'mmm-yy',
1185 "76": 'h:mm',
1186 "77": 'h:mm:ss',
1187 "78": 'm/d/yy h:mm',
1188 "79": 'mm:ss',
1189 "80": '[h]:mm:ss',
1190 "81": 'mmss.0'
1191});
1192
1193/* dateNF parse TODO: move to SSF */
1194var dateNFregex = /[dD]+|[mM]+|[yYeE]+|[Hh]+|[Ss]+/g;
1195function dateNF_regex(dateNF) {
1196 var fmt = typeof dateNF == "number" ? SSF._table[dateNF] : dateNF;
1197 fmt = fmt.replace(dateNFregex, "(\\d+)");
1198 return new RegExp("^" + fmt + "$");
1199}
1200function dateNF_fix(str, dateNF, match) {
1201 var Y = -1, m = -1, d = -1, H = -1, M = -1, S = -1;
1202 (dateNF.match(dateNFregex)||[]).forEach(function(n, i) {
1203 var v = parseInt(match[i+1], 10);
1204 switch(n.toLowerCase().charAt(0)) {
1205 case 'y': Y = v; break; case 'd': d = v; break;
1206 case 'h': H = v; break; case 's': S = v; break;
1207 case 'm': if(H >= 0) M = v; else m = v; break;
1208 }
1209 });
1210 if(S >= 0 && M == -1 && m >= 0) { M = m; m = -1; }
1211 var datestr = (("" + (Y>=0?Y: new Date().getFullYear())).slice(-4) + "-" + ("00" + (m>=1?m:1)).slice(-2) + "-" + ("00" + (d>=1?d:1)).slice(-2));
1212 if(datestr.length == 7) datestr = "0" + datestr;
1213 if(datestr.length == 8) datestr = "20" + datestr;
1214 var timestr = (("00" + (H>=0?H:0)).slice(-2) + ":" + ("00" + (M>=0?M:0)).slice(-2) + ":" + ("00" + (S>=0?S:0)).slice(-2));
1215 if(H == -1 && M == -1 && S == -1) return datestr;
1216 if(Y == -1 && m == -1 && d == -1) return timestr;
1217 return datestr + "T" + timestr;
1218}
1219
1220var DO_NOT_EXPORT_CFB = true;
1221/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
1222/* vim: set ts=2: */
1223/*jshint eqnull:true */
1224/*exported CFB */
1225/*global Uint8Array:false, Uint16Array:false */
1226
1227/* crc32.js (C) 2014-present SheetJS -- http://sheetjs.com */
1228/* vim: set ts=2: */
1229/*exported CRC32 */
1230var CRC32;
1231(function (factory) {
1232 /*jshint ignore:start */
1233 /*eslint-disable */
1234 factory(CRC32 = {});
1235 /*eslint-enable */
1236 /*jshint ignore:end */
1237}(function(CRC32) {
1238CRC32.version = '1.2.0';
1239/* see perf/crc32table.js */
1240/*global Int32Array */
1241function signed_crc_table() {
1242 var c = 0, table = new Array(256);
1243
1244 for(var n =0; n != 256; ++n){
1245 c = n;
1246 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1247 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1248 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1249 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1250 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1251 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1252 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1253 c = ((c&1) ? (-306674912 ^ (c >>> 1)) : (c >>> 1));
1254 table[n] = c;
1255 }
1256
1257 return typeof Int32Array !== 'undefined' ? new Int32Array(table) : table;
1258}
1259
1260var T = signed_crc_table();
1261function crc32_bstr(bstr, seed) {
1262 var C = seed ^ -1, L = bstr.length - 1;
1263 for(var i = 0; i < L;) {
1264 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1265 C = (C>>>8) ^ T[(C^bstr.charCodeAt(i++))&0xFF];
1266 }
1267 if(i === L) C = (C>>>8) ^ T[(C ^ bstr.charCodeAt(i))&0xFF];
1268 return C ^ -1;
1269}
1270
1271function crc32_buf(buf, seed) {
1272 if(buf.length > 10000) return crc32_buf_8(buf, seed);
1273 var C = seed ^ -1, L = buf.length - 3;
1274 for(var i = 0; i < L;) {
1275 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1276 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1277 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1278 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1279 }
1280 while(i < L+3) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1281 return C ^ -1;
1282}
1283
1284function crc32_buf_8(buf, seed) {
1285 var C = seed ^ -1, L = buf.length - 7;
1286 for(var i = 0; i < L;) {
1287 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1288 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1289 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1290 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1291 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1292 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1293 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1294 C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1295 }
1296 while(i < L+7) C = (C>>>8) ^ T[(C^buf[i++])&0xFF];
1297 return C ^ -1;
1298}
1299
1300function crc32_str(str, seed) {
1301 var C = seed ^ -1;
1302 for(var i = 0, L=str.length, c, d; i < L;) {
1303 c = str.charCodeAt(i++);
1304 if(c < 0x80) {
1305 C = (C>>>8) ^ T[(C ^ c)&0xFF];
1306 } else if(c < 0x800) {
1307 C = (C>>>8) ^ T[(C ^ (192|((c>>6)&31)))&0xFF];
1308 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1309 } else if(c >= 0xD800 && c < 0xE000) {
1310 c = (c&1023)+64; d = str.charCodeAt(i++)&1023;
1311 C = (C>>>8) ^ T[(C ^ (240|((c>>8)&7)))&0xFF];
1312 C = (C>>>8) ^ T[(C ^ (128|((c>>2)&63)))&0xFF];
1313 C = (C>>>8) ^ T[(C ^ (128|((d>>6)&15)|((c&3)<<4)))&0xFF];
1314 C = (C>>>8) ^ T[(C ^ (128|(d&63)))&0xFF];
1315 } else {
1316 C = (C>>>8) ^ T[(C ^ (224|((c>>12)&15)))&0xFF];
1317 C = (C>>>8) ^ T[(C ^ (128|((c>>6)&63)))&0xFF];
1318 C = (C>>>8) ^ T[(C ^ (128|(c&63)))&0xFF];
1319 }
1320 }
1321 return C ^ -1;
1322}
1323CRC32.table = T;
1324CRC32.bstr = crc32_bstr;
1325CRC32.buf = crc32_buf;
1326CRC32.str = crc32_str;
1327}));
1328/* [MS-CFB] v20171201 */
1329var CFB = (function _CFB(){
1330var exports = {};
1331exports.version = '1.1.4';
1332/* [MS-CFB] 2.6.4 */
1333function namecmp(l, r) {
1334 var L = l.split("/"), R = r.split("/");
1335 for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
1336 if((c = L[i].length - R[i].length)) return c;
1337 if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
1338 }
1339 return L.length - R.length;
1340}
1341function dirname(p) {
1342 if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
1343 var c = p.lastIndexOf("/");
1344 return (c === -1) ? p : p.slice(0, c+1);
1345}
1346
1347function filename(p) {
1348 if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
1349 var c = p.lastIndexOf("/");
1350 return (c === -1) ? p : p.slice(c+1);
1351}
1352/* -------------------------------------------------------------------------- */
1353/* DOS Date format:
1354 high|YYYYYYYm.mmmddddd.HHHHHMMM.MMMSSSSS|low
1355 add 1980 to stored year
1356 stored second should be doubled
1357*/
1358
1359/* write JS date to buf as a DOS date */
1360function write_dos_date(buf, date) {
1361 if(typeof date === "string") date = new Date(date);
1362 var hms = date.getHours();
1363 hms = hms << 6 | date.getMinutes();
1364 hms = hms << 5 | (date.getSeconds()>>>1);
1365 buf.write_shift(2, hms);
1366 var ymd = (date.getFullYear() - 1980);
1367 ymd = ymd << 4 | (date.getMonth()+1);
1368 ymd = ymd << 5 | date.getDate();
1369 buf.write_shift(2, ymd);
1370}
1371
1372/* read four bytes from buf and interpret as a DOS date */
1373function parse_dos_date(buf) {
1374 var hms = buf.read_shift(2) & 0xFFFF;
1375 var ymd = buf.read_shift(2) & 0xFFFF;
1376 var val = new Date();
1377 var d = ymd & 0x1F; ymd >>>= 5;
1378 var m = ymd & 0x0F; ymd >>>= 4;
1379 val.setMilliseconds(0);
1380 val.setFullYear(ymd + 1980);
1381 val.setMonth(m-1);
1382 val.setDate(d);
1383 var S = hms & 0x1F; hms >>>= 5;
1384 var M = hms & 0x3F; hms >>>= 6;
1385 val.setHours(hms);
1386 val.setMinutes(M);
1387 val.setSeconds(S<<1);
1388 return val;
1389}
1390function parse_extra_field(blob) {
1391 prep_blob(blob, 0);
1392 var o = {};
1393 var flags = 0;
1394 while(blob.l <= blob.length - 4) {
1395 var type = blob.read_shift(2);
1396 var sz = blob.read_shift(2), tgt = blob.l + sz;
1397 var p = {};
1398 switch(type) {
1399 /* UNIX-style Timestamps */
1400 case 0x5455: {
1401 flags = blob.read_shift(1);
1402 if(flags & 1) p.mtime = blob.read_shift(4);
1403 /* for some reason, CD flag corresponds to LFH */
1404 if(sz > 5) {
1405 if(flags & 2) p.atime = blob.read_shift(4);
1406 if(flags & 4) p.ctime = blob.read_shift(4);
1407 }
1408 if(p.mtime) p.mt = new Date(p.mtime*1000);
1409 }
1410 break;
1411 }
1412 blob.l = tgt;
1413 o[type] = p;
1414 }
1415 return o;
1416}
1417var fs;
1418function get_fs() { return fs || (fs = require('fs')); }
1419function parse(file, options) {
1420if(file[0] == 0x50 && file[1] == 0x4b) return parse_zip(file, options);
1421if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512");
1422var mver = 3;
1423var ssz = 512;
1424var nmfs = 0; // number of mini FAT sectors
1425var difat_sec_cnt = 0;
1426var dir_start = 0;
1427var minifat_start = 0;
1428var difat_start = 0;
1429
1430var fat_addrs = []; // locations of FAT sectors
1431
1432/* [MS-CFB] 2.2 Compound File Header */
1433var blob = file.slice(0,512);
1434prep_blob(blob, 0);
1435
1436/* major version */
1437var mv = check_get_mver(blob);
1438mver = mv[0];
1439switch(mver) {
1440 case 3: ssz = 512; break; case 4: ssz = 4096; break;
1441 case 0: if(mv[1] == 0) return parse_zip(file, options);
1442 /* falls through */
1443 default: throw new Error("Major Version: Expected 3 or 4 saw " + mver);
1444}
1445
1446/* reprocess header */
1447if(ssz !== 512) { blob = file.slice(0,ssz); prep_blob(blob, 28 /* blob.l */); }
1448/* Save header for final object */
1449var header = file.slice(0,ssz);
1450
1451check_shifts(blob, mver);
1452
1453// Number of Directory Sectors
1454var dir_cnt = blob.read_shift(4, 'i');
1455if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
1456
1457// Number of FAT Sectors
1458blob.l += 4;
1459
1460// First Directory Sector Location
1461dir_start = blob.read_shift(4, 'i');
1462
1463// Transaction Signature
1464blob.l += 4;
1465
1466// Mini Stream Cutoff Size
1467blob.chk('00100000', 'Mini Stream Cutoff Size: ');
1468
1469// First Mini FAT Sector Location
1470minifat_start = blob.read_shift(4, 'i');
1471
1472// Number of Mini FAT Sectors
1473nmfs = blob.read_shift(4, 'i');
1474
1475// First DIFAT sector location
1476difat_start = blob.read_shift(4, 'i');
1477
1478// Number of DIFAT Sectors
1479difat_sec_cnt = blob.read_shift(4, 'i');
1480
1481// Grab FAT Sector Locations
1482for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
1483 q = blob.read_shift(4, 'i');
1484 if(q<0) break;
1485 fat_addrs[j] = q;
1486}
1487
1488/** Break the file up into sectors */
1489var sectors = sectorify(file, ssz);
1490
1491sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
1492
1493/** Chains */
1494var sector_list = make_sector_list(sectors, dir_start, fat_addrs, ssz);
1495
1496sector_list[dir_start].name = "!Directory";
1497if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
1498sector_list[fat_addrs[0]].name = "!FAT";
1499sector_list.fat_addrs = fat_addrs;
1500sector_list.ssz = ssz;
1501
1502/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1503var files = {}, Paths = [], FileIndex = [], FullPaths = [];
1504read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, minifat_start);
1505
1506build_full_paths(FileIndex, FullPaths, Paths);
1507Paths.shift();
1508
1509var o = {
1510 FileIndex: FileIndex,
1511 FullPaths: FullPaths
1512};
1513
1514// $FlowIgnore
1515if(options && options.raw) o.raw = {header: header, sectors: sectors};
1516return o;
1517} // parse
1518
1519/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
1520function check_get_mver(blob) {
1521 if(blob[blob.l] == 0x50 && blob[blob.l + 1] == 0x4b) return [0, 0];
1522 // header signature 8
1523 blob.chk(HEADER_SIGNATURE, 'Header Signature: ');
1524
1525 // clsid 16
1526 //blob.chk(HEADER_CLSID, 'CLSID: ');
1527 blob.l += 16;
1528
1529 // minor version 2
1530 var mver = blob.read_shift(2, 'u');
1531
1532 return [blob.read_shift(2,'u'), mver];
1533}
1534function check_shifts(blob, mver) {
1535 var shift = 0x09;
1536
1537 // Byte Order
1538 //blob.chk('feff', 'Byte Order: '); // note: some writers put 0xffff
1539 blob.l += 2;
1540
1541 // Sector Shift
1542 switch((shift = blob.read_shift(2))) {
1543 case 0x09: if(mver != 3) throw new Error('Sector Shift: Expected 9 saw ' + shift); break;
1544 case 0x0c: if(mver != 4) throw new Error('Sector Shift: Expected 12 saw ' + shift); break;
1545 default: throw new Error('Sector Shift: Expected 9 or 12 saw ' + shift);
1546 }
1547
1548 // Mini Sector Shift
1549 blob.chk('0600', 'Mini Sector Shift: ');
1550
1551 // Reserved
1552 blob.chk('000000000000', 'Reserved: ');
1553}
1554
1555/** Break the file up into sectors */
1556function sectorify(file, ssz) {
1557 var nsectors = Math.ceil(file.length/ssz)-1;
1558 var sectors = [];
1559 for(var i=1; i < nsectors; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz);
1560 sectors[nsectors-1] = file.slice(nsectors*ssz);
1561 return sectors;
1562}
1563
1564/* [MS-CFB] 2.6.4 Red-Black Tree */
1565function build_full_paths(FI, FP, Paths) {
1566 var i = 0, L = 0, R = 0, C = 0, j = 0, pl = Paths.length;
1567 var dad = [], q = [];
1568
1569 for(; i < pl; ++i) { dad[i]=q[i]=i; FP[i]=Paths[i]; }
1570
1571 for(; j < q.length; ++j) {
1572 i = q[j];
1573 L = FI[i].L; R = FI[i].R; C = FI[i].C;
1574 if(dad[i] === i) {
1575 if(L !== -1 /*NOSTREAM*/ && dad[L] !== L) dad[i] = dad[L];
1576 if(R !== -1 && dad[R] !== R) dad[i] = dad[R];
1577 }
1578 if(C !== -1 /*NOSTREAM*/) dad[C] = i;
1579 if(L !== -1 && i != dad[i]) { dad[L] = dad[i]; if(q.lastIndexOf(L) < j) q.push(L); }
1580 if(R !== -1 && i != dad[i]) { dad[R] = dad[i]; if(q.lastIndexOf(R) < j) q.push(R); }
1581 }
1582 for(i=1; i < pl; ++i) if(dad[i] === i) {
1583 if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R];
1584 else if(L !== -1 && dad[L] !== L) dad[i] = dad[L];
1585 }
1586
1587 for(i=1; i < pl; ++i) {
1588 if(FI[i].type === 0 /* unknown */) continue;
1589 j = i;
1590 if(j != dad[j]) do {
1591 j = dad[j];
1592 FP[i] = FP[j] + "/" + FP[i];
1593 } while (j !== 0 && -1 !== dad[j] && j != dad[j]);
1594 dad[i] = -1;
1595 }
1596
1597 FP[0] += "/";
1598 for(i=1; i < pl; ++i) {
1599 if(FI[i].type !== 2 /* stream */) FP[i] += "/";
1600 }
1601}
1602
1603function get_mfat_entry(entry, payload, mini) {
1604 var start = entry.start, size = entry.size;
1605 //return (payload.slice(start*MSSZ, start*MSSZ + size));
1606 var o = [];
1607 var idx = start;
1608 while(mini && size > 0 && idx >= 0) {
1609 o.push(payload.slice(idx * MSSZ, idx * MSSZ + MSSZ));
1610 size -= MSSZ;
1611 idx = __readInt32LE(mini, idx * 4);
1612 }
1613 if(o.length === 0) return (new_buf(0));
1614 return (bconcat(o).slice(0, entry.size));
1615}
1616
1617/** Chase down the rest of the DIFAT chain to build a comprehensive list
1618 DIFAT chains by storing the next sector number as the last 32 bits */
1619function sleuth_fat(idx, cnt, sectors, ssz, fat_addrs) {
1620 var q = ENDOFCHAIN;
1621 if(idx === ENDOFCHAIN) {
1622 if(cnt !== 0) throw new Error("DIFAT chain shorter than expected");
1623 } else if(idx !== -1 /*FREESECT*/) {
1624 var sector = sectors[idx], m = (ssz>>>2)-1;
1625 if(!sector) return;
1626 for(var i = 0; i < m; ++i) {
1627 if((q = __readInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1628 fat_addrs.push(q);
1629 }
1630 if(cnt >= 1) sleuth_fat(__readInt32LE(sector,ssz-4),cnt - 1, sectors, ssz, fat_addrs);
1631 }
1632}
1633
1634/** Follow the linked list of sectors for a given starting point */
1635function get_sector_list(sectors, start, fat_addrs, ssz, chkd) {
1636 var buf = [], buf_chain = [];
1637 if(!chkd) chkd = [];
1638 var modulus = ssz - 1, j = 0, jj = 0;
1639 for(j=start; j>=0;) {
1640 chkd[j] = true;
1641 buf[buf.length] = j;
1642 buf_chain.push(sectors[j]);
1643 var addr = fat_addrs[Math.floor(j*4/ssz)];
1644 jj = ((j*4) & modulus);
1645 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1646 if(!sectors[addr]) break;
1647 j = __readInt32LE(sectors[addr], jj);
1648 }
1649 return {nodes: buf, data:__toBuffer([buf_chain])};
1650}
1651
1652/** Chase down the sector linked lists */
1653function make_sector_list(sectors, dir_start, fat_addrs, ssz) {
1654 var sl = sectors.length, sector_list = ([]);
1655 var chkd = [], buf = [], buf_chain = [];
1656 var modulus = ssz - 1, i=0, j=0, k=0, jj=0;
1657 for(i=0; i < sl; ++i) {
1658 buf = ([]);
1659 k = (i + dir_start); if(k >= sl) k-=sl;
1660 if(chkd[k]) continue;
1661 buf_chain = [];
1662 var seen = [];
1663 for(j=k; j>=0;) {
1664 seen[j] = true;
1665 chkd[j] = true;
1666 buf[buf.length] = j;
1667 buf_chain.push(sectors[j]);
1668 var addr = fat_addrs[Math.floor(j*4/ssz)];
1669 jj = ((j*4) & modulus);
1670 if(ssz < 4 + jj) throw new Error("FAT boundary crossed: " + j + " 4 "+ssz);
1671 if(!sectors[addr]) break;
1672 j = __readInt32LE(sectors[addr], jj);
1673 if(seen[j]) break;
1674 }
1675 sector_list[k] = ({nodes: buf, data:__toBuffer([buf_chain])});
1676 }
1677 return sector_list;
1678}
1679
1680/* [MS-CFB] 2.6.1 Compound File Directory Entry */
1681function read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex, mini) {
1682 var minifat_store = 0, pl = (Paths.length?2:0);
1683 var sector = sector_list[dir_start].data;
1684 var i = 0, namelen = 0, name;
1685 for(; i < sector.length; i+= 128) {
1686 var blob = sector.slice(i, i+128);
1687 prep_blob(blob, 64);
1688 namelen = blob.read_shift(2);
1689 name = __utf16le(blob,0,namelen-pl);
1690 Paths.push(name);
1691 var o = ({
1692 name: name,
1693 type: blob.read_shift(1),
1694 color: blob.read_shift(1),
1695 L: blob.read_shift(4, 'i'),
1696 R: blob.read_shift(4, 'i'),
1697 C: blob.read_shift(4, 'i'),
1698 clsid: blob.read_shift(16),
1699 state: blob.read_shift(4, 'i'),
1700 start: 0,
1701 size: 0
1702 });
1703 var ctime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1704 if(ctime !== 0) o.ct = read_date(blob, blob.l-8);
1705 var mtime = blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2) + blob.read_shift(2);
1706 if(mtime !== 0) o.mt = read_date(blob, blob.l-8);
1707 o.start = blob.read_shift(4, 'i');
1708 o.size = blob.read_shift(4, 'i');
1709 if(o.size < 0 && o.start < 0) { o.size = o.type = 0; o.start = ENDOFCHAIN; o.name = ""; }
1710 if(o.type === 5) { /* root */
1711 minifat_store = o.start;
1712 if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData";
1713 /*minifat_size = o.size;*/
1714 } else if(o.size >= 4096 /* MSCSZ */) {
1715 o.storage = 'fat';
1716 if(sector_list[o.start] === undefined) sector_list[o.start] = get_sector_list(sectors, o.start, sector_list.fat_addrs, sector_list.ssz);
1717 sector_list[o.start].name = o.name;
1718 o.content = (sector_list[o.start].data.slice(0,o.size));
1719 } else {
1720 o.storage = 'minifat';
1721 if(o.size < 0) o.size = 0;
1722 else if(minifat_store !== ENDOFCHAIN && o.start !== ENDOFCHAIN && sector_list[minifat_store]) {
1723 o.content = get_mfat_entry(o, sector_list[minifat_store].data, (sector_list[mini]||{}).data);
1724 }
1725 }
1726 if(o.content) prep_blob(o.content, 0);
1727 files[name] = o;
1728 FileIndex.push(o);
1729 }
1730}
1731
1732function read_date(blob, offset) {
1733 return new Date(( ( (__readUInt32LE(blob,offset+4)/1e7)*Math.pow(2,32)+__readUInt32LE(blob,offset)/1e7 ) - 11644473600)*1000);
1734}
1735
1736function read_file(filename, options) {
1737 get_fs();
1738 return parse(fs.readFileSync(filename), options);
1739}
1740
1741function read(blob, options) {
1742 switch(options && options.type || "base64") {
1743 case "file": return read_file(blob, options);
1744 case "base64": return parse(s2a(Base64.decode(blob)), options);
1745 case "binary": return parse(s2a(blob), options);
1746 }
1747 return parse(blob, options);
1748}
1749
1750function init_cfb(cfb, opts) {
1751 var o = opts || {}, root = o.root || "Root Entry";
1752 if(!cfb.FullPaths) cfb.FullPaths = [];
1753 if(!cfb.FileIndex) cfb.FileIndex = [];
1754 if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
1755 if(cfb.FullPaths.length === 0) {
1756 cfb.FullPaths[0] = root + "/";
1757 cfb.FileIndex[0] = ({ name: root, type: 5 });
1758 }
1759 if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
1760 seed_cfb(cfb);
1761}
1762function seed_cfb(cfb) {
1763 var nm = "\u0001Sh33tJ5";
1764 if(CFB.find(cfb, "/" + nm)) return;
1765 var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
1766 cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }));
1767 cfb.FullPaths.push(cfb.FullPaths[0] + nm);
1768 rebuild_cfb(cfb);
1769}
1770function rebuild_cfb(cfb, f) {
1771 init_cfb(cfb);
1772 var gc = false, s = false;
1773 for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
1774 var _file = cfb.FileIndex[i];
1775 switch(_file.type) {
1776 case 0:
1777 if(s) gc = true;
1778 else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
1779 break;
1780 case 1: case 2: case 5:
1781 s = true;
1782 if(isNaN(_file.R * _file.L * _file.C)) gc = true;
1783 if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
1784 break;
1785 default: gc = true; break;
1786 }
1787 }
1788 if(!gc && !f) return;
1789
1790 var now = new Date(1987, 1, 19), j = 0;
1791 var data = [];
1792 for(i = 0; i < cfb.FullPaths.length; ++i) {
1793 if(cfb.FileIndex[i].type === 0) continue;
1794 data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
1795 }
1796 for(i = 0; i < data.length; ++i) {
1797 var dad = dirname(data[i][0]);
1798 s = false;
1799 for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
1800 if(!s) data.push([dad, ({
1801 name: filename(dad).replace("/",""),
1802 type: 1,
1803 clsid: HEADER_CLSID,
1804 ct: now, mt: now,
1805 content: null
1806 })]);
1807 }
1808
1809 data.sort(function(x,y) { return namecmp(x[0], y[0]); });
1810 cfb.FullPaths = []; cfb.FileIndex = [];
1811 for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
1812 for(i = 0; i < data.length; ++i) {
1813 var elt = cfb.FileIndex[i];
1814 var nm = cfb.FullPaths[i];
1815
1816 elt.name = filename(nm).replace("/","");
1817 elt.L = elt.R = elt.C = -(elt.color = 1);
1818 elt.size = elt.content ? elt.content.length : 0;
1819 elt.start = 0;
1820 elt.clsid = (elt.clsid || HEADER_CLSID);
1821 if(i === 0) {
1822 elt.C = data.length > 1 ? 1 : -1;
1823 elt.size = 0;
1824 elt.type = 5;
1825 } else if(nm.slice(-1) == "/") {
1826 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
1827 elt.C = j >= data.length ? -1 : j;
1828 for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
1829 elt.R = j >= data.length ? -1 : j;
1830 elt.type = 1;
1831 } else {
1832 if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
1833 elt.type = 2;
1834 }
1835 }
1836
1837}
1838
1839function _write(cfb, options) {
1840 var _opts = options || {};
1841 rebuild_cfb(cfb);
1842 if(_opts.fileType == 'zip') return write_zip(cfb, _opts);
1843 var L = (function(cfb){
1844 var mini_size = 0, fat_size = 0;
1845 for(var i = 0; i < cfb.FileIndex.length; ++i) {
1846 var file = cfb.FileIndex[i];
1847 if(!file.content) continue;
1848var flen = file.content.length;
1849 if(flen > 0){
1850 if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
1851 else fat_size += (flen + 0x01FF) >> 9;
1852 }
1853 }
1854 var dir_cnt = (cfb.FullPaths.length +3) >> 2;
1855 var mini_cnt = (mini_size + 7) >> 3;
1856 var mfat_cnt = (mini_size + 0x7F) >> 7;
1857 var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
1858 var fat_cnt = (fat_base + 0x7F) >> 7;
1859 var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1860 while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
1861 var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
1862 cfb.FileIndex[0].size = mini_size << 6;
1863 L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
1864 return L;
1865 })(cfb);
1866 var o = new_buf(L[7] << 9);
1867 var i = 0, T = 0;
1868 {
1869 for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
1870 for(i = 0; i < 8; ++i) o.write_shift(2, 0);
1871 o.write_shift(2, 0x003E);
1872 o.write_shift(2, 0x0003);
1873 o.write_shift(2, 0xFFFE);
1874 o.write_shift(2, 0x0009);
1875 o.write_shift(2, 0x0006);
1876 for(i = 0; i < 3; ++i) o.write_shift(2, 0);
1877 o.write_shift(4, 0);
1878 o.write_shift(4, L[2]);
1879 o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
1880 o.write_shift(4, 0);
1881 o.write_shift(4, 1<<12);
1882 o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
1883 o.write_shift(4, L[3]);
1884 o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
1885 o.write_shift(4, L[1]);
1886 for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1887 }
1888 if(L[1]) {
1889 for(T = 0; T < L[1]; ++T) {
1890 for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
1891 o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
1892 }
1893 }
1894 var chainit = function(w) {
1895 for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
1896 if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
1897 };
1898 T = i = 0;
1899 for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
1900 for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
1901 chainit(L[3]);
1902 chainit(L[4]);
1903 var j = 0, flen = 0;
1904 var file = cfb.FileIndex[0];
1905 for(; j < cfb.FileIndex.length; ++j) {
1906 file = cfb.FileIndex[j];
1907 if(!file.content) continue;
1908flen = file.content.length;
1909 if(flen < 0x1000) continue;
1910 file.start = T;
1911 chainit((flen + 0x01FF) >> 9);
1912 }
1913 chainit((L[6] + 7) >> 3);
1914 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1915 T = i = 0;
1916 for(j = 0; j < cfb.FileIndex.length; ++j) {
1917 file = cfb.FileIndex[j];
1918 if(!file.content) continue;
1919flen = file.content.length;
1920 if(!flen || flen >= 0x1000) continue;
1921 file.start = T;
1922 chainit((flen + 0x3F) >> 6);
1923 }
1924 while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
1925 for(i = 0; i < L[4]<<2; ++i) {
1926 var nm = cfb.FullPaths[i];
1927 if(!nm || nm.length === 0) {
1928 for(j = 0; j < 17; ++j) o.write_shift(4, 0);
1929 for(j = 0; j < 3; ++j) o.write_shift(4, -1);
1930 for(j = 0; j < 12; ++j) o.write_shift(4, 0);
1931 continue;
1932 }
1933 file = cfb.FileIndex[i];
1934 if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
1935 var _nm = (i === 0 && _opts.root) || file.name;
1936 flen = 2*(_nm.length+1);
1937 o.write_shift(64, _nm, "utf16le");
1938 o.write_shift(2, flen);
1939 o.write_shift(1, file.type);
1940 o.write_shift(1, file.color);
1941 o.write_shift(-4, file.L);
1942 o.write_shift(-4, file.R);
1943 o.write_shift(-4, file.C);
1944 if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
1945 else o.write_shift(16, file.clsid, "hex");
1946 o.write_shift(4, file.state || 0);
1947 o.write_shift(4, 0); o.write_shift(4, 0);
1948 o.write_shift(4, 0); o.write_shift(4, 0);
1949 o.write_shift(4, file.start);
1950 o.write_shift(4, file.size); o.write_shift(4, 0);
1951 }
1952 for(i = 1; i < cfb.FileIndex.length; ++i) {
1953 file = cfb.FileIndex[i];
1954if(file.size >= 0x1000) {
1955 o.l = (file.start+1) << 9;
1956 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1957 for(; j & 0x1FF; ++j) o.write_shift(1, 0);
1958 }
1959 }
1960 for(i = 1; i < cfb.FileIndex.length; ++i) {
1961 file = cfb.FileIndex[i];
1962if(file.size > 0 && file.size < 0x1000) {
1963 for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
1964 for(; j & 0x3F; ++j) o.write_shift(1, 0);
1965 }
1966 }
1967 while(o.l < o.length) o.write_shift(1, 0);
1968 return o;
1969}
1970/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
1971function find(cfb, path) {
1972 var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
1973 var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
1974 var k = false;
1975 if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
1976 else k = path.indexOf("/") !== -1;
1977 var UCPath = path.toUpperCase();
1978 var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
1979 if(w !== -1) return cfb.FileIndex[w];
1980
1981 var m = !UCPath.match(chr1);
1982 UCPath = UCPath.replace(chr0,'');
1983 if(m) UCPath = UCPath.replace(chr1,'!');
1984 for(w = 0; w < UCFullPaths.length; ++w) {
1985 if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1986 if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w];
1987 }
1988 return null;
1989}
1990/** CFB Constants */
1991var MSSZ = 64; /* Mini Sector Size = 1<<6 */
1992//var MSCSZ = 4096; /* Mini Stream Cutoff Size */
1993/* 2.1 Compound File Sector Numbers and Types */
1994var ENDOFCHAIN = -2;
1995/* 2.2 Compound File Header */
1996var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
1997var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
1998var HEADER_CLSID = '00000000000000000000000000000000';
1999var consts = {
2000 /* 2.1 Compund File Sector Numbers and Types */
2001 MAXREGSECT: -6,
2002 DIFSECT: -4,
2003 FATSECT: -3,
2004 ENDOFCHAIN: ENDOFCHAIN,
2005 FREESECT: -1,
2006 /* 2.2 Compound File Header */
2007 HEADER_SIGNATURE: HEADER_SIGNATURE,
2008 HEADER_MINOR_VERSION: '3e00',
2009 MAXREGSID: -6,
2010 NOSTREAM: -1,
2011 HEADER_CLSID: HEADER_CLSID,
2012 /* 2.6.1 Compound File Directory Entry */
2013 EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
2014};
2015
2016function write_file(cfb, filename, options) {
2017 get_fs();
2018 var o = _write(cfb, options);
2019fs.writeFileSync(filename, o);
2020}
2021
2022function a2s(o) {
2023 var out = new Array(o.length);
2024 for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
2025 return out.join("");
2026}
2027
2028function write(cfb, options) {
2029 var o = _write(cfb, options);
2030 switch(options && options.type) {
2031 case "file": get_fs(); fs.writeFileSync(options.filename, (o)); return o;
2032 case "binary": return a2s(o);
2033 case "base64": return Base64.encode(a2s(o));
2034 }
2035 return o;
2036}
2037/* node < 8.1 zlib does not expose bytesRead, so default to pure JS */
2038var _zlib;
2039function use_zlib(zlib) { try {
2040 var InflateRaw = zlib.InflateRaw;
2041 var InflRaw = new InflateRaw();
2042 InflRaw._processChunk(new Uint8Array([3, 0]), InflRaw._finishFlushFlag);
2043 if(InflRaw.bytesRead) _zlib = zlib;
2044 else throw new Error("zlib does not expose bytesRead");
2045} catch(e) {console.error("cannot use native zlib: " + (e.message || e)); } }
2046
2047function _inflateRawSync(payload, usz) {
2048 if(!_zlib) return _inflate(payload, usz);
2049 var InflateRaw = _zlib.InflateRaw;
2050 var InflRaw = new InflateRaw();
2051 var out = InflRaw._processChunk(payload.slice(payload.l), InflRaw._finishFlushFlag);
2052 payload.l += InflRaw.bytesRead;
2053 return out;
2054}
2055
2056function _deflateRawSync(payload) {
2057 return _zlib ? _zlib.deflateRawSync(payload) : _deflate(payload);
2058}
2059var CLEN_ORDER = [ 16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 1, 15 ];
2060
2061/* 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 ]; */
2062var 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 ];
2063
2064/* 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 ]; */
2065var 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 ];
2066
2067function bit_swap_8(n) { var t = (((((n<<1)|(n<<11)) & 0x22110) | (((n<<5)|(n<<15)) & 0x88440))); return ((t>>16) | (t>>8) |t)&0xFF; }
2068
2069var use_typed_arrays = typeof Uint8Array !== 'undefined';
2070
2071var bitswap8 = use_typed_arrays ? new Uint8Array(1<<8) : [];
2072for(var q = 0; q < (1<<8); ++q) bitswap8[q] = bit_swap_8(q);
2073
2074function bit_swap_n(n, b) {
2075 var rev = bitswap8[n & 0xFF];
2076 if(b <= 8) return rev >>> (8-b);
2077 rev = (rev << 8) | bitswap8[(n>>8)&0xFF];
2078 if(b <= 16) return rev >>> (16-b);
2079 rev = (rev << 8) | bitswap8[(n>>16)&0xFF];
2080 return rev >>> (24-b);
2081}
2082
2083/* helpers for unaligned bit reads */
2084function read_bits_2(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 6 ? 0 : buf[h+1]<<8))>>>w)& 0x03; }
2085function read_bits_3(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 5 ? 0 : buf[h+1]<<8))>>>w)& 0x07; }
2086function read_bits_4(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 4 ? 0 : buf[h+1]<<8))>>>w)& 0x0F; }
2087function read_bits_5(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 3 ? 0 : buf[h+1]<<8))>>>w)& 0x1F; }
2088function read_bits_7(buf, bl) { var w = (bl&7), h = (bl>>>3); return ((buf[h]|(w <= 1 ? 0 : buf[h+1]<<8))>>>w)& 0x7F; }
2089
2090/* works up to n = 3 * 8 + 1 = 25 */
2091function read_bits_n(buf, bl, n) {
2092 var w = (bl&7), h = (bl>>>3), f = ((1<<n)-1);
2093 var v = buf[h] >>> w;
2094 if(n < 8 - w) return v & f;
2095 v |= buf[h+1]<<(8-w);
2096 if(n < 16 - w) return v & f;
2097 v |= buf[h+2]<<(16-w);
2098 if(n < 24 - w) return v & f;
2099 v |= buf[h+3]<<(24-w);
2100 return v & f;
2101}
2102
2103/* until ArrayBuffer#realloc is a thing, fake a realloc */
2104function realloc(b, sz) {
2105 var L = b.length, M = 2*L > sz ? 2*L : sz + 5, i = 0;
2106 if(L >= sz) return b;
2107 if(has_buf) {
2108 var o = new_unsafe_buf(M);
2109 // $FlowIgnore
2110 if(b.copy) b.copy(o);
2111 else for(; i < b.length; ++i) o[i] = b[i];
2112 return o;
2113 } else if(use_typed_arrays) {
2114 var a = new Uint8Array(M);
2115 if(a.set) a.set(b);
2116 else for(; i < b.length; ++i) a[i] = b[i];
2117 return a;
2118 }
2119 b.length = M;
2120 return b;
2121}
2122
2123/* zero-filled arrays for older browsers */
2124function zero_fill_array(n) {
2125 var o = new Array(n);
2126 for(var i = 0; i < n; ++i) o[i] = 0;
2127 return o;
2128}var _deflate = (function() {
2129var _deflateRaw = (function() {
2130 return function deflateRaw(data, out) {
2131 var boff = 0;
2132 while(boff < data.length) {
2133 var L = Math.min(0xFFFF, data.length - boff);
2134 var h = boff + L == data.length;
2135 /* TODO: this is only type 0 stored */
2136 out.write_shift(1, +h);
2137 out.write_shift(2, L);
2138 out.write_shift(2, (~L) & 0xFFFF);
2139 while(L-- > 0) out[out.l++] = data[boff++];
2140 }
2141 return out.l;
2142 };
2143})();
2144
2145return function(data) {
2146 var buf = new_buf(50+Math.floor(data.length*1.1));
2147 var off = _deflateRaw(data, buf);
2148 return buf.slice(0, off);
2149};
2150})();
2151/* modified inflate function also moves original read head */
2152
2153/* build tree (used for literals and lengths) */
2154function build_tree(clens, cmap, MAX) {
2155 var maxlen = 1, w = 0, i = 0, j = 0, ccode = 0, L = clens.length;
2156
2157 var bl_count = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2158 for(i = 0; i < 32; ++i) bl_count[i] = 0;
2159
2160 for(i = L; i < MAX; ++i) clens[i] = 0;
2161 L = clens.length;
2162
2163 var ctree = use_typed_arrays ? new Uint16Array(L) : zero_fill_array(L); // []
2164
2165 /* build code tree */
2166 for(i = 0; i < L; ++i) {
2167 bl_count[(w = clens[i])]++;
2168 if(maxlen < w) maxlen = w;
2169 ctree[i] = 0;
2170 }
2171 bl_count[0] = 0;
2172 for(i = 1; i <= maxlen; ++i) bl_count[i+16] = (ccode = (ccode + bl_count[i-1])<<1);
2173 for(i = 0; i < L; ++i) {
2174 ccode = clens[i];
2175 if(ccode != 0) ctree[i] = bl_count[ccode+16]++;
2176 }
2177
2178 /* cmap[maxlen + 4 bits] = (off&15) + (lit<<4) reverse mapping */
2179 var cleni = 0;
2180 for(i = 0; i < L; ++i) {
2181 cleni = clens[i];
2182 if(cleni != 0) {
2183 ccode = bit_swap_n(ctree[i], maxlen)>>(maxlen-cleni);
2184 for(j = (1<<(maxlen + 4 - cleni)) - 1; j>=0; --j)
2185 cmap[ccode|(j<<cleni)] = (cleni&15) | (i<<4);
2186 }
2187 }
2188 return maxlen;
2189}
2190
2191var fix_lmap = use_typed_arrays ? new Uint16Array(512) : zero_fill_array(512);
2192var fix_dmap = use_typed_arrays ? new Uint16Array(32) : zero_fill_array(32);
2193if(!use_typed_arrays) {
2194 for(var i = 0; i < 512; ++i) fix_lmap[i] = 0;
2195 for(i = 0; i < 32; ++i) fix_dmap[i] = 0;
2196}
2197(function() {
2198 var dlens = [];
2199 var i = 0;
2200 for(;i<32; i++) dlens.push(5);
2201 build_tree(dlens, fix_dmap, 32);
2202
2203 var clens = [];
2204 i = 0;
2205 for(; i<=143; i++) clens.push(8);
2206 for(; i<=255; i++) clens.push(9);
2207 for(; i<=279; i++) clens.push(7);
2208 for(; i<=287; i++) clens.push(8);
2209 build_tree(clens, fix_lmap, 288);
2210})();
2211
2212var dyn_lmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2213var dyn_dmap = use_typed_arrays ? new Uint16Array(32768) : zero_fill_array(32768);
2214var dyn_cmap = use_typed_arrays ? new Uint16Array(128) : zero_fill_array(128);
2215var dyn_len_1 = 1, dyn_len_2 = 1;
2216
2217/* 5.5.3 Expanding Huffman Codes */
2218function dyn(data, boff) {
2219 /* nomenclature from RFC1951 refers to bit values; these are offset by the implicit constant */
2220 var _HLIT = read_bits_5(data, boff) + 257; boff += 5;
2221 var _HDIST = read_bits_5(data, boff) + 1; boff += 5;
2222 var _HCLEN = read_bits_4(data, boff) + 4; boff += 4;
2223 var w = 0;
2224
2225 /* grab and store code lengths */
2226 var clens = use_typed_arrays ? new Uint8Array(19) : zero_fill_array(19);
2227 var ctree = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ];
2228 var maxlen = 1;
2229 var bl_count = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2230 var next_code = use_typed_arrays ? new Uint8Array(8) : zero_fill_array(8);
2231 var L = clens.length; /* 19 */
2232 for(var i = 0; i < _HCLEN; ++i) {
2233 clens[CLEN_ORDER[i]] = w = read_bits_3(data, boff);
2234 if(maxlen < w) maxlen = w;
2235 bl_count[w]++;
2236 boff += 3;
2237 }
2238
2239 /* build code tree */
2240 var ccode = 0;
2241 bl_count[0] = 0;
2242 for(i = 1; i <= maxlen; ++i) next_code[i] = ccode = (ccode + bl_count[i-1])<<1;
2243 for(i = 0; i < L; ++i) if((ccode = clens[i]) != 0) ctree[i] = next_code[ccode]++;
2244 /* cmap[7 bits from stream] = (off&7) + (lit<<3) */
2245 var cleni = 0;
2246 for(i = 0; i < L; ++i) {
2247 cleni = clens[i];
2248 if(cleni != 0) {
2249 ccode = bitswap8[ctree[i]]>>(8-cleni);
2250 for(var j = (1<<(7-cleni))-1; j>=0; --j) dyn_cmap[ccode|(j<<cleni)] = (cleni&7) | (i<<3);
2251 }
2252 }
2253
2254 /* read literal and dist codes at once */
2255 var hcodes = [];
2256 maxlen = 1;
2257 for(; hcodes.length < _HLIT + _HDIST;) {
2258 ccode = dyn_cmap[read_bits_7(data, boff)];
2259 boff += ccode & 7;
2260 switch((ccode >>>= 3)) {
2261 case 16:
2262 w = 3 + read_bits_2(data, boff); boff += 2;
2263 ccode = hcodes[hcodes.length - 1];
2264 while(w-- > 0) hcodes.push(ccode);
2265 break;
2266 case 17:
2267 w = 3 + read_bits_3(data, boff); boff += 3;
2268 while(w-- > 0) hcodes.push(0);
2269 break;
2270 case 18:
2271 w = 11 + read_bits_7(data, boff); boff += 7;
2272 while(w -- > 0) hcodes.push(0);
2273 break;
2274 default:
2275 hcodes.push(ccode);
2276 if(maxlen < ccode) maxlen = ccode;
2277 break;
2278 }
2279 }
2280
2281 /* build literal / length trees */
2282 var h1 = hcodes.slice(0, _HLIT), h2 = hcodes.slice(_HLIT);
2283 for(i = _HLIT; i < 286; ++i) h1[i] = 0;
2284 for(i = _HDIST; i < 30; ++i) h2[i] = 0;
2285 dyn_len_1 = build_tree(h1, dyn_lmap, 286);
2286 dyn_len_2 = build_tree(h2, dyn_dmap, 30);
2287 return boff;
2288}
2289
2290/* return [ data, bytesRead ] */
2291function inflate(data, usz) {
2292 /* shortcircuit for empty buffer [0x03, 0x00] */
2293 if(data[0] == 3 && !(data[1] & 0x3)) { return [new_raw_buf(usz), 2]; }
2294
2295 /* bit offset */
2296 var boff = 0;
2297
2298 /* header includes final bit and type bits */
2299 var header = 0;
2300
2301 var outbuf = new_unsafe_buf(usz ? usz : (1<<18));
2302 var woff = 0;
2303 var OL = outbuf.length>>>0;
2304 var max_len_1 = 0, max_len_2 = 0;
2305
2306 while((header&1) == 0) {
2307 header = read_bits_3(data, boff); boff += 3;
2308 if((header >>> 1) == 0) {
2309 /* Stored block */
2310 if(boff & 7) boff += 8 - (boff&7);
2311 /* 2 bytes sz, 2 bytes bit inverse */
2312 var sz = data[boff>>>3] | data[(boff>>>3)+1]<<8;
2313 boff += 32;
2314 /* push sz bytes */
2315 if(!usz && OL < woff + sz) { outbuf = realloc(outbuf, woff + sz); OL = outbuf.length; }
2316 if(typeof data.copy === 'function') {
2317 // $FlowIgnore
2318 data.copy(outbuf, woff, boff>>>3, (boff>>>3)+sz);
2319 woff += sz; boff += 8*sz;
2320 } else while(sz-- > 0) { outbuf[woff++] = data[boff>>>3]; boff += 8; }
2321 continue;
2322 } else if((header >>> 1) == 1) {
2323 /* Fixed Huffman */
2324 max_len_1 = 9; max_len_2 = 5;
2325 } else {
2326 /* Dynamic Huffman */
2327 boff = dyn(data, boff);
2328 max_len_1 = dyn_len_1; max_len_2 = dyn_len_2;
2329 }
2330 if(!usz && (OL < woff + 32767)) { outbuf = realloc(outbuf, woff + 32767); OL = outbuf.length; }
2331 for(;;) { // while(true) is apparently out of vogue in modern JS circles
2332 /* ingest code and move read head */
2333 var bits = read_bits_n(data, boff, max_len_1);
2334 var code = (header>>>1) == 1 ? fix_lmap[bits] : dyn_lmap[bits];
2335 boff += code & 15; code >>>= 4;
2336 /* 0-255 are literals, 256 is end of block token, 257+ are copy tokens */
2337 if(((code>>>8)&0xFF) === 0) outbuf[woff++] = code;
2338 else if(code == 256) break;
2339 else {
2340 code -= 257;
2341 var len_eb = (code < 8) ? 0 : ((code-4)>>2); if(len_eb > 5) len_eb = 0;
2342 var tgt = woff + LEN_LN[code];
2343 /* length extra bits */
2344 if(len_eb > 0) {
2345 tgt += read_bits_n(data, boff, len_eb);
2346 boff += len_eb;
2347 }
2348
2349 /* dist code */
2350 bits = read_bits_n(data, boff, max_len_2);
2351 code = (header>>>1) == 1 ? fix_dmap[bits] : dyn_dmap[bits];
2352 boff += code & 15; code >>>= 4;
2353 var dst_eb = (code < 4 ? 0 : (code-2)>>1);
2354 var dst = DST_LN[code];
2355 /* dist extra bits */
2356 if(dst_eb > 0) {
2357 dst += read_bits_n(data, boff, dst_eb);
2358 boff += dst_eb;
2359 }
2360
2361 /* in the common case, manual byte copy is faster than TA set / Buffer copy */
2362 if(!usz && OL < tgt) { outbuf = realloc(outbuf, tgt); OL = outbuf.length; }
2363 while(woff < tgt) { outbuf[woff] = outbuf[woff - dst]; ++woff; }
2364 }
2365 }
2366 }
2367 return [usz ? outbuf : outbuf.slice(0, woff), (boff+7)>>>3];
2368}
2369
2370function _inflate(payload, usz) {
2371 var data = payload.slice(payload.l||0);
2372 var out = inflate(data, usz);
2373 payload.l += out[1];
2374 return out[0];
2375}
2376
2377function warn_or_throw(wrn, msg) {
2378 if(wrn) { if(typeof console !== 'undefined') console.error(msg); }
2379 else throw new Error(msg);
2380}
2381
2382function parse_zip(file, options) {
2383 var blob = file;
2384 prep_blob(blob, 0);
2385
2386 var FileIndex = [], FullPaths = [];
2387 var o = {
2388 FileIndex: FileIndex,
2389 FullPaths: FullPaths
2390 };
2391 init_cfb(o, { root: options.root });
2392
2393 /* find end of central directory, start just after signature */
2394 var i = blob.length - 4;
2395 while((blob[i] != 0x50 || blob[i+1] != 0x4b || blob[i+2] != 0x05 || blob[i+3] != 0x06) && i >= 0) --i;
2396 blob.l = i + 4;
2397
2398 /* parse end of central directory */
2399 blob.l += 4;
2400 var fcnt = blob.read_shift(2);
2401 blob.l += 6;
2402 var start_cd = blob.read_shift(4);
2403
2404 /* parse central directory */
2405 blob.l = start_cd;
2406
2407 for(i = 0; i < fcnt; ++i) {
2408 /* trust local file header instead of CD entry */
2409 blob.l += 20;
2410 var csz = blob.read_shift(4);
2411 var usz = blob.read_shift(4);
2412 var namelen = blob.read_shift(2);
2413 var efsz = blob.read_shift(2);
2414 var fcsz = blob.read_shift(2);
2415 blob.l += 8;
2416 var offset = blob.read_shift(4);
2417 var EF = parse_extra_field(blob.slice(blob.l+namelen, blob.l+namelen+efsz));
2418 blob.l += namelen + efsz + fcsz;
2419
2420 var L = blob.l;
2421 blob.l = offset + 4;
2422 parse_local_file(blob, csz, usz, o, EF);
2423 blob.l = L;
2424 }
2425
2426 return o;
2427}
2428
2429
2430/* head starts just after local file header signature */
2431function parse_local_file(blob, csz, usz, o, EF) {
2432 /* [local file header] */
2433 blob.l += 2;
2434 var flags = blob.read_shift(2);
2435 var meth = blob.read_shift(2);
2436 var date = parse_dos_date(blob);
2437
2438 if(flags & 0x2041) throw new Error("Unsupported ZIP encryption");
2439 var crc32 = blob.read_shift(4);
2440 var _csz = blob.read_shift(4);
2441 var _usz = blob.read_shift(4);
2442
2443 var namelen = blob.read_shift(2);
2444 var efsz = blob.read_shift(2);
2445
2446 // TODO: flags & (1<<11) // UTF8
2447 var name = ""; for(var i = 0; i < namelen; ++i) name += String.fromCharCode(blob[blob.l++]);
2448 if(efsz) {
2449 var ef = parse_extra_field(blob.slice(blob.l, blob.l + efsz));
2450 if((ef[0x5455]||{}).mt) date = ef[0x5455].mt;
2451 if(((EF||{})[0x5455]||{}).mt) date = EF[0x5455].mt;
2452 }
2453 blob.l += efsz;
2454
2455 /* [encryption header] */
2456
2457 /* [file data] */
2458 var data = blob.slice(blob.l, blob.l + _csz);
2459 switch(meth) {
2460 case 8: data = _inflateRawSync(blob, _usz); break;
2461 case 0: break;
2462 default: throw new Error("Unsupported ZIP Compression method " + meth);
2463 }
2464
2465 /* [data descriptor] */
2466 var wrn = false;
2467 if(flags & 8) {
2468 crc32 = blob.read_shift(4);
2469 if(crc32 == 0x08074b50) { crc32 = blob.read_shift(4); wrn = true; }
2470 _csz = blob.read_shift(4);
2471 _usz = blob.read_shift(4);
2472 }
2473
2474 if(_csz != csz) warn_or_throw(wrn, "Bad compressed size: " + csz + " != " + _csz);
2475 if(_usz != usz) warn_or_throw(wrn, "Bad uncompressed size: " + usz + " != " + _usz);
2476 var _crc32 = CRC32.buf(data, 0);
2477 if((crc32>>0) != (_crc32>>0)) warn_or_throw(wrn, "Bad CRC32 checksum: " + crc32 + " != " + _crc32);
2478 cfb_add(o, name, data, {unsafe: true, mt: date});
2479}
2480function write_zip(cfb, options) {
2481 var _opts = options || {};
2482 var out = [], cdirs = [];
2483 var o = new_buf(1);
2484 var method = (_opts.compression ? 8 : 0), flags = 0;
2485 var desc = false;
2486 if(desc) flags |= 8;
2487 var i = 0, j = 0;
2488
2489 var start_cd = 0, fcnt = 0;
2490 var root = cfb.FullPaths[0], fp = root, fi = cfb.FileIndex[0];
2491 var crcs = [];
2492 var sz_cd = 0;
2493
2494 for(i = 1; i < cfb.FullPaths.length; ++i) {
2495 fp = cfb.FullPaths[i].slice(root.length); fi = cfb.FileIndex[i];
2496 if(!fi.size || !fi.content || fp == "\u0001Sh33tJ5") continue;
2497 var start = start_cd;
2498
2499 /* TODO: CP437 filename */
2500 var namebuf = new_buf(fp.length);
2501 for(j = 0; j < fp.length; ++j) namebuf.write_shift(1, fp.charCodeAt(j) & 0x7F);
2502 namebuf = namebuf.slice(0, namebuf.l);
2503 crcs[fcnt] = CRC32.buf(fi.content, 0);
2504
2505 var outbuf = fi.content;
2506 if(method == 8) outbuf = _deflateRawSync(outbuf);
2507
2508 /* local file header */
2509 o = new_buf(30);
2510 o.write_shift(4, 0x04034b50);
2511 o.write_shift(2, 20);
2512 o.write_shift(2, flags);
2513 o.write_shift(2, method);
2514 /* TODO: last mod file time/date */
2515 if(fi.mt) write_dos_date(o, fi.mt);
2516 else o.write_shift(4, 0);
2517 o.write_shift(-4, (flags & 8) ? 0 : crcs[fcnt]);
2518 o.write_shift(4, (flags & 8) ? 0 : outbuf.length);
2519 o.write_shift(4, (flags & 8) ? 0 : fi.content.length);
2520 o.write_shift(2, namebuf.length);
2521 o.write_shift(2, 0);
2522
2523 start_cd += o.length;
2524 out.push(o);
2525 start_cd += namebuf.length;
2526 out.push(namebuf);
2527
2528 /* TODO: encryption header ? */
2529 start_cd += outbuf.length;
2530 out.push(outbuf);
2531
2532 /* data descriptor */
2533 if(flags & 8) {
2534 o = new_buf(12);
2535 o.write_shift(-4, crcs[fcnt]);
2536 o.write_shift(4, outbuf.length);
2537 o.write_shift(4, fi.content.length);
2538 start_cd += o.l;
2539 out.push(o);
2540 }
2541
2542 /* central directory */
2543 o = new_buf(46);
2544 o.write_shift(4, 0x02014b50);
2545 o.write_shift(2, 0);
2546 o.write_shift(2, 20);
2547 o.write_shift(2, flags);
2548 o.write_shift(2, method);
2549 o.write_shift(4, 0); /* TODO: last mod file time/date */
2550 o.write_shift(-4, crcs[fcnt]);
2551
2552 o.write_shift(4, outbuf.length);
2553 o.write_shift(4, fi.content.length);
2554 o.write_shift(2, namebuf.length);
2555 o.write_shift(2, 0);
2556 o.write_shift(2, 0);
2557 o.write_shift(2, 0);
2558 o.write_shift(2, 0);
2559 o.write_shift(4, 0);
2560 o.write_shift(4, start);
2561
2562 sz_cd += o.l;
2563 cdirs.push(o);
2564 sz_cd += namebuf.length;
2565 cdirs.push(namebuf);
2566 ++fcnt;
2567 }
2568
2569 /* end of central directory */
2570 o = new_buf(22);
2571 o.write_shift(4, 0x06054b50);
2572 o.write_shift(2, 0);
2573 o.write_shift(2, 0);
2574 o.write_shift(2, fcnt);
2575 o.write_shift(2, fcnt);
2576 o.write_shift(4, sz_cd);
2577 o.write_shift(4, start_cd);
2578 o.write_shift(2, 0);
2579
2580 return bconcat(([bconcat((out)), bconcat(cdirs), o]));
2581}
2582function cfb_new(opts) {
2583 var o = ({});
2584 init_cfb(o, opts);
2585 return o;
2586}
2587
2588function cfb_add(cfb, name, content, opts) {
2589 var unsafe = opts && opts.unsafe;
2590 if(!unsafe) init_cfb(cfb);
2591 var file = !unsafe && CFB.find(cfb, name);
2592 if(!file) {
2593 var fpath = cfb.FullPaths[0];
2594 if(name.slice(0, fpath.length) == fpath) fpath = name;
2595 else {
2596 if(fpath.slice(-1) != "/") fpath += "/";
2597 fpath = (fpath + name).replace("//","/");
2598 }
2599 file = ({name: filename(name), type: 2});
2600 cfb.FileIndex.push(file);
2601 cfb.FullPaths.push(fpath);
2602 if(!unsafe) CFB.utils.cfb_gc(cfb);
2603 }
2604file.content = (content);
2605 file.size = content ? content.length : 0;
2606 if(opts) {
2607 if(opts.CLSID) file.clsid = opts.CLSID;
2608 if(opts.mt) file.mt = opts.mt;
2609 if(opts.ct) file.ct = opts.ct;
2610 }
2611 return file;
2612}
2613
2614function cfb_del(cfb, name) {
2615 init_cfb(cfb);
2616 var file = CFB.find(cfb, name);
2617 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2618 cfb.FileIndex.splice(j, 1);
2619 cfb.FullPaths.splice(j, 1);
2620 return true;
2621 }
2622 return false;
2623}
2624
2625function cfb_mov(cfb, old_name, new_name) {
2626 init_cfb(cfb);
2627 var file = CFB.find(cfb, old_name);
2628 if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
2629 cfb.FileIndex[j].name = filename(new_name);
2630 cfb.FullPaths[j] = new_name;
2631 return true;
2632 }
2633 return false;
2634}
2635
2636function cfb_gc(cfb) { rebuild_cfb(cfb, true); }
2637
2638exports.find = find;
2639exports.read = read;
2640exports.parse = parse;
2641exports.write = write;
2642exports.writeFile = write_file;
2643exports.utils = {
2644 cfb_new: cfb_new,
2645 cfb_add: cfb_add,
2646 cfb_del: cfb_del,
2647 cfb_mov: cfb_mov,
2648 cfb_gc: cfb_gc,
2649 ReadShift: ReadShift,
2650 CheckField: CheckField,
2651 prep_blob: prep_blob,
2652 bconcat: bconcat,
2653 use_zlib: use_zlib,
2654 _deflateRaw: _deflate,
2655 _inflateRaw: _inflate,
2656 consts: consts
2657};
2658
2659return exports;
2660})();
2661
2662if(typeof require !== 'undefined' && typeof module !== 'undefined' && typeof DO_NOT_EXPORT_CFB === 'undefined') { module.exports = CFB; }
2663var _fs;
2664if(typeof require !== 'undefined') try { _fs = require('fs'); } catch(e) {}
2665
2666/* normalize data for blob ctor */
2667function blobify(data) {
2668 if(typeof data === "string") return s2ab(data);
2669 if(Array.isArray(data)) return a2u(data);
2670 return data;
2671}
2672/* write or download file */
2673function write_dl(fname, payload, enc) {
2674 /*global IE_SaveFile, Blob, navigator, saveAs, document, File, chrome */
2675 if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
2676 var data = (enc == "utf8") ? utf8write(payload) : payload;
2677if(typeof IE_SaveFile !== 'undefined') return IE_SaveFile(data, fname);
2678 if(typeof Blob !== 'undefined') {
2679 var blob = new Blob([blobify(data)], {type:"application/octet-stream"});
2680if(typeof navigator !== 'undefined' && navigator.msSaveBlob) return navigator.msSaveBlob(blob, fname);
2681if(typeof saveAs !== 'undefined') return saveAs(blob, fname);
2682 if(typeof URL !== 'undefined' && typeof document !== 'undefined' && document.createElement && URL.createObjectURL) {
2683 var url = URL.createObjectURL(blob);
2684if(typeof chrome === 'object' && typeof (chrome.downloads||{}).download == "function") {
2685 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2686 return chrome.downloads.download({ url: url, filename: fname, saveAs: true});
2687 }
2688 var a = document.createElement("a");
2689 if(a.download != null) {
2690a.download = fname; a.href = url; document.body.appendChild(a); a.click();
2691document.body.removeChild(a);
2692 if(URL.revokeObjectURL && typeof setTimeout !== 'undefined') setTimeout(function() { URL.revokeObjectURL(url); }, 60000);
2693 return url;
2694 }
2695 }
2696 }
2697 // $FlowIgnore
2698 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2699 // $FlowIgnore
2700 var out = File(fname); out.open("w"); out.encoding = "binary";
2701 if(Array.isArray(payload)) payload = a2s(payload);
2702 out.write(payload); out.close(); return payload;
2703 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2704 throw new Error("cannot save file " + fname);
2705}
2706
2707/* read binary data from file */
2708function read_binary(path) {
2709 if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
2710 // $FlowIgnore
2711 if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
2712 // $FlowIgnore
2713 var infile = File(path); infile.open("r"); infile.encoding = "binary";
2714 var data = infile.read(); infile.close();
2715 return data;
2716 } catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
2717 throw new Error("Cannot access file " + path);
2718}
2719function keys(o) {
2720 var ks = Object.keys(o), o2 = [];
2721 for(var i = 0; i < ks.length; ++i) if(Object.prototype.hasOwnProperty.call(o, ks[i])) o2.push(ks[i]);
2722 return o2;
2723}
2724
2725function evert_key(obj, key) {
2726 var o = ([]), K = keys(obj);
2727 for(var i = 0; i !== K.length; ++i) if(o[obj[K[i]][key]] == null) o[obj[K[i]][key]] = K[i];
2728 return o;
2729}
2730
2731function evert(obj) {
2732 var o = ([]), K = keys(obj);
2733 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = K[i];
2734 return o;
2735}
2736
2737function evert_num(obj) {
2738 var o = ([]), K = keys(obj);
2739 for(var i = 0; i !== K.length; ++i) o[obj[K[i]]] = parseInt(K[i],10);
2740 return o;
2741}
2742
2743function evert_arr(obj) {
2744 var o = ([]), K = keys(obj);
2745 for(var i = 0; i !== K.length; ++i) {
2746 if(o[obj[K[i]]] == null) o[obj[K[i]]] = [];
2747 o[obj[K[i]]].push(K[i]);
2748 }
2749 return o;
2750}
2751
2752var basedate = new Date(1899, 11, 30, 0, 0, 0); // 2209161600000
2753function datenum(v, date1904) {
2754 var epoch = v.getTime();
2755 if(date1904) epoch -= 1462*24*60*60*1000;
2756 var dnthresh = basedate.getTime() + (v.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2757 return (epoch - dnthresh) / (24 * 60 * 60 * 1000);
2758}
2759var refdate = new Date();
2760var dnthresh = basedate.getTime() + (refdate.getTimezoneOffset() - basedate.getTimezoneOffset()) * 60000;
2761var refoffset = refdate.getTimezoneOffset();
2762function numdate(v) {
2763 var out = new Date();
2764 out.setTime(v * 24 * 60 * 60 * 1000 + dnthresh);
2765 if (out.getTimezoneOffset() !== refoffset) {
2766 out.setTime(out.getTime() + (out.getTimezoneOffset() - refoffset) * 60000);
2767 }
2768 return out;
2769}
2770
2771/* ISO 8601 Duration */
2772function parse_isodur(s) {
2773 var sec = 0, mt = 0, time = false;
2774 var m = s.match(/P([0-9\.]+Y)?([0-9\.]+M)?([0-9\.]+D)?T([0-9\.]+H)?([0-9\.]+M)?([0-9\.]+S)?/);
2775 if(!m) throw new Error("|" + s + "| is not an ISO8601 Duration");
2776 for(var i = 1; i != m.length; ++i) {
2777 if(!m[i]) continue;
2778 mt = 1;
2779 if(i > 3) time = true;
2780 switch(m[i].slice(m[i].length-1)) {
2781 case 'Y':
2782 throw new Error("Unsupported ISO Duration Field: " + m[i].slice(m[i].length-1));
2783 case 'D': mt *= 24;
2784 /* falls through */
2785 case 'H': mt *= 60;
2786 /* falls through */
2787 case 'M':
2788 if(!time) throw new Error("Unsupported ISO Duration Field: M");
2789 else mt *= 60;
2790 /* falls through */
2791 case 'S': break;
2792 }
2793 sec += mt * parseInt(m[i], 10);
2794 }
2795 return sec;
2796}
2797
2798var good_pd_date = new Date('2017-02-19T19:06:09.000Z');
2799if(isNaN(good_pd_date.getFullYear())) good_pd_date = new Date('2/19/17');
2800var good_pd = good_pd_date.getFullYear() == 2017;
2801/* parses a date as a local date */
2802function parseDate(str, fixdate) {
2803 var d = new Date(str);
2804 if(good_pd) {
2805if(fixdate > 0) d.setTime(d.getTime() + d.getTimezoneOffset() * 60 * 1000);
2806 else if(fixdate < 0) d.setTime(d.getTime() - d.getTimezoneOffset() * 60 * 1000);
2807 return d;
2808 }
2809 if(str instanceof Date) return str;
2810 if(good_pd_date.getFullYear() == 1917 && !isNaN(d.getFullYear())) {
2811 var s = d.getFullYear();
2812 if(str.indexOf("" + s) > -1) return d;
2813 d.setFullYear(d.getFullYear() + 100); return d;
2814 }
2815 var n = str.match(/\d+/g)||["2017","2","19","0","0","0"];
2816 var out = new Date(+n[0], +n[1] - 1, +n[2], (+n[3]||0), (+n[4]||0), (+n[5]||0));
2817 if(str.indexOf("Z") > -1) out = new Date(out.getTime() - out.getTimezoneOffset() * 60 * 1000);
2818 return out;
2819}
2820
2821function cc2str(arr) {
2822 var o = "";
2823 for(var i = 0; i != arr.length; ++i) o += String.fromCharCode(arr[i]);
2824 return o;
2825}
2826
2827function dup(o) {
2828 if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o));
2829 if(typeof o != 'object' || o == null) return o;
2830 if(o instanceof Date) return new Date(o.getTime());
2831 var out = {};
2832 for(var k in o) if(Object.prototype.hasOwnProperty.call(o, k)) out[k] = dup(o[k]);
2833 return out;
2834}
2835
2836function fill(c,l) { var o = ""; while(o.length < l) o+=c; return o; }
2837
2838/* TODO: stress test */
2839function fuzzynum(s) {
2840 var v = Number(s);
2841 if(isFinite(v)) return v;
2842 if(!isNaN(v)) return NaN;
2843 if(!/\d/.test(s)) return v;
2844 var wt = 1;
2845 var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2846 if(!isNaN(v = Number(ss))) return v / wt;
2847 ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2848 if(!isNaN(v = Number(ss))) return v / wt;
2849 return v;
2850}
2851function fuzzydate(s) {
2852 var o = new Date(s), n = new Date(NaN);
2853 var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2854 if(isNaN(d)) return n;
2855 if(y < 0 || y > 8099) return n;
2856 if((m > 0 || d > 1) && y != 101) return o;
2857 if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2858 if(s.match(/[^-0-9:,\/\\]/)) return n;
2859 return o;
2860}
2861
2862var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2863function split_regex(str, re, def) {
2864 if(safe_split_regex || typeof re == "string") return str.split(re);
2865 var p = str.split(re), o = [p[0]];
2866 for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2867 return o;
2868}
2869function getdatastr(data) {
2870 if(!data) return null;
2871 if(data.data) return debom(data.data);
2872 if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2873 if(data.asBinary) return debom(data.asBinary());
2874 if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2875 if(data.content && data.type) return debom(cc2str(data.content));
2876 return null;
2877}
2878
2879function getdatabin(data) {
2880 if(!data) return null;
2881 if(data.data) return char_codes(data.data);
2882 if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2883 if(data._data && data._data.getContent) {
2884 var o = data._data.getContent();
2885 if(typeof o == "string") return char_codes(o);
2886 return Array.prototype.slice.call(o);
2887 }
2888 if(data.content && data.type) return data.content;
2889 return null;
2890}
2891
2892function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2893
2894/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2895/* OASIS does not comment on filename case sensitivity */
2896function safegetzipfile(zip, file) {
2897 var k = zip.FullPaths || keys(zip.files);
2898 var f = file.toLowerCase().replace(/[\/]/g, '\\'), g = f.replace(/\\/g,'\/');
2899 for(var i=0; i<k.length; ++i) {
2900 var n = k[i].replace(/^Root Entry[\/]/,"").toLowerCase();
2901 if(f == n || g == n) return zip.files ? zip.files[k[i]] : zip.FileIndex[i];
2902 }
2903 return null;
2904}
2905
2906function getzipfile(zip, file) {
2907 var o = safegetzipfile(zip, file);
2908 if(o == null) throw new Error("Cannot find file " + file + " in zip");
2909 return o;
2910}
2911
2912function getzipdata(zip, file, safe) {
2913 if(!safe) return getdata(getzipfile(zip, file));
2914 if(!file) return null;
2915 try { return getzipdata(zip, file); } catch(e) { return null; }
2916}
2917
2918function getzipstr(zip, file, safe) {
2919 if(!safe) return getdatastr(getzipfile(zip, file));
2920 if(!file) return null;
2921 try { return getzipstr(zip, file); } catch(e) { return null; }
2922}
2923
2924function zipentries(zip) {
2925 var k = zip.FullPaths || keys(zip.files), o = [];
2926 for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i].replace(/^Root Entry[\/]/, ""));
2927 return o.sort();
2928}
2929
2930function zip_add_file(zip, path, content) {
2931 if(zip.FullPaths) CFB.utils.cfb_add(zip, path, typeof content == "string" ? (has_buf ? Buffer_from(content) : s2a(utf8write(content))) : content);
2932 else zip.file(path, content);
2933}
2934
2935var jszip;
2936
2937function zip_new() {
2938 return CFB.utils.cfb_new();
2939}
2940
2941function zip_read(d, o) {
2942 var zip;
2943 switch(o.type) {
2944 case "base64": zip = CFB.read(d, { type: "base64" }); break;
2945 case "binary": zip = CFB.read(d, { type: "binary" }); break;
2946 case "buffer": case "array": zip = CFB.read(d, { type: "buffer" }); break;
2947 default: throw new Error("Unrecognized type " + o.type);
2948 }
2949 return zip;
2950}
2951
2952function resolve_path(path, base) {
2953 if(path.charAt(0) == "/") return path.slice(1);
2954 var result = base.split('/');
2955 if(base.slice(-1) != "/") result.pop(); // folder path
2956 var target = path.split('/');
2957 while (target.length !== 0) {
2958 var step = target.shift();
2959 if (step === '..') result.pop();
2960 else if (step !== '.') result.push(step);
2961 }
2962 return result.join('/');
2963}
2964var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2965var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2966var tagregex=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s*[\/\?]?>/mg;
2967
2968if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2969var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2970function parsexmltag(tag, skip_root, skip_LC) {
2971 var z = ({});
2972 var eq = 0, c = 0;
2973 for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2974 if(!skip_root) z[0] = tag.slice(0, eq);
2975 if(eq === tag.length) return z;
2976 var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2977 if(m) for(i = 0; i != m.length; ++i) {
2978 cc = m[i];
2979 for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2980 q = cc.slice(0,c).trim();
2981 while(cc.charCodeAt(c+1) == 32) ++c;
2982 quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2983 v = cc.slice(c+1+quot, cc.length-quot);
2984 for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2985 if(j===q.length) {
2986 if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2987 z[q] = v;
2988 if(!skip_LC) z[q.toLowerCase()] = v;
2989 }
2990 else {
2991 var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2992 if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2993 z[k] = v;
2994 if(!skip_LC) z[k.toLowerCase()] = v;
2995 }
2996 }
2997 return z;
2998}
2999function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
3000
3001var encodings = {
3002 '&quot;': '"',
3003 '&apos;': "'",
3004 '&gt;': '>',
3005 '&lt;': '<',
3006 '&amp;': '&'
3007};
3008var rencoding = evert(encodings);
3009//var rencstr = "&<>'\"".split("");
3010
3011// TODO: CP remap (need to read file version to determine OS)
3012var unescapexml = (function() {
3013 /* 22.4.2.4 bstr (Basic String) */
3014 var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/ig;
3015 return function unescapexml(text) {
3016 var s = text + '', i = s.indexOf("<![CDATA[");
3017 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));});
3018 var j = s.indexOf("]]>");
3019 return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
3020 };
3021})();
3022
3023var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
3024function escapexml(text){
3025 var s = text + '';
3026 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
3027}
3028function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
3029
3030var htmlcharegex = /[\u0000-\u001f]/g;
3031function escapehtml(text){
3032 var s = text + '';
3033 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) + ";"; });
3034}
3035
3036function escapexlml(text){
3037 var s = text + '';
3038 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
3039}
3040
3041/* TODO: handle codepages */
3042var xlml_fixstr = (function() {
3043 var entregex = /&#(\d+);/g;
3044 function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
3045 return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
3046})();
3047var xlml_unfixstr = (function() {
3048 return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
3049})();
3050
3051function parsexmlbool(value) {
3052 switch(value) {
3053 case 1: case true: case '1': case 'true': case 'TRUE': return true;
3054 /* case '0': case 'false': case 'FALSE':*/
3055 default: return false;
3056 }
3057}
3058
3059var utf8read = function utf8reada(orig) {
3060 var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
3061 while (i < orig.length) {
3062 c = orig.charCodeAt(i++);
3063 if (c < 128) { out += String.fromCharCode(c); continue; }
3064 d = orig.charCodeAt(i++);
3065 if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
3066 e = orig.charCodeAt(i++);
3067 if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
3068 f = orig.charCodeAt(i++);
3069 w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
3070 out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
3071 out += String.fromCharCode(0xDC00 + (w&1023));
3072 }
3073 return out;
3074};
3075
3076var utf8write = function(orig) {
3077 var out = [], i = 0, c = 0, d = 0;
3078 while(i < orig.length) {
3079 c = orig.charCodeAt(i++);
3080 switch(true) {
3081 case c < 128: out.push(String.fromCharCode(c)); break;
3082 case c < 2048:
3083 out.push(String.fromCharCode(192 + (c >> 6)));
3084 out.push(String.fromCharCode(128 + (c & 63)));
3085 break;
3086 case c >= 55296 && c < 57344:
3087 c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
3088 out.push(String.fromCharCode(240 + ((d >>18) & 7)));
3089 out.push(String.fromCharCode(144 + ((d >>12) & 63)));
3090 out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
3091 out.push(String.fromCharCode(128 + (d & 63)));
3092 break;
3093 default:
3094 out.push(String.fromCharCode(224 + (c >> 12)));
3095 out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
3096 out.push(String.fromCharCode(128 + (c & 63)));
3097 }
3098 }
3099 return out.join("");
3100};
3101
3102if(has_buf) {
3103 var utf8readb = function utf8readb(data) {
3104 var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
3105 for(i = 0; i < data.length; i+=j) {
3106 j = 1;
3107 if((c=data.charCodeAt(i)) < 128) w = c;
3108 else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
3109 else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
3110 else { j = 4;
3111 w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
3112 w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
3113 }
3114 if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
3115 out[k++] = w%256; out[k++] = w>>>8;
3116 }
3117 return out.slice(0,k).toString('ucs2');
3118 };
3119 var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
3120 if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
3121 var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
3122 if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
3123
3124 utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
3125}
3126
3127// matches <foo>...</foo> extracts content
3128var matchtag = (function() {
3129 var mtcache = ({});
3130 return function matchtag(f,g) {
3131 var t = f+"|"+(g||"");
3132 if(mtcache[t]) return mtcache[t];
3133 return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
3134 };
3135})();
3136
3137var htmldecode = (function() {
3138 var entities = [
3139 ['nbsp', ' '], ['middot', '·'],
3140 ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
3141 ].map(function(x) { return [new RegExp('&' + x[0] + ';', "ig"), x[1]]; });
3142 return function htmldecode(str) {
3143 var o = str
3144 // Remove new lines and spaces from start of content
3145 .replace(/^[\t\n\r ]+/, "")
3146 // Remove new lines and spaces from end of content
3147 .replace(/[\t\n\r ]+$/,"")
3148 // Added line which removes any white space characters after and before html tags
3149 .replace(/>\s+/g,">").replace(/\s+</g,"<")
3150 // Replace remaining new lines and spaces with space
3151 .replace(/[\t\n\r ]+/g, " ")
3152 // Replace <br> tags with new lines
3153 .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
3154 // Strip HTML elements
3155 .replace(/<[^>]*>/g,"");
3156 for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
3157 return o;
3158 };
3159})();
3160
3161var vtregex = (function(){ var vt_cache = {};
3162 return function vt_regex(bt) {
3163 if(vt_cache[bt] !== undefined) return vt_cache[bt];
3164 return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
3165};})();
3166var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
3167function parseVector(data, opts) {
3168 var h = parsexmltag(data);
3169
3170 var matches = data.match(vtregex(h.baseType))||[];
3171 var res = [];
3172 if(matches.length != h.size) {
3173 if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
3174 return res;
3175 }
3176 matches.forEach(function(x) {
3177 var v = x.replace(vtvregex,"").match(vtmregex);
3178 if(v) res.push({v:utf8read(v[2]), t:v[1]});
3179 });
3180 return res;
3181}
3182
3183var wtregex = /(^\s|\s$|\n)/;
3184function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
3185
3186function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
3187function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
3188
3189function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
3190
3191function write_vt(s, xlsx) {
3192 switch(typeof s) {
3193 case 'string':
3194 var o = writextag('vt:lpwstr', escapexml(s));
3195 if(xlsx) o = o.replace(/&quot;/g, "_x0022_");
3196 return o;
3197 case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', escapexml(String(s)));
3198 case 'boolean': return writextag('vt:bool',s?'true':'false');
3199 }
3200 if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
3201 throw new Error("Unable to serialize " + s);
3202}
3203
3204var XMLNS = ({
3205 'dc': 'http://purl.org/dc/elements/1.1/',
3206 'dcterms': 'http://purl.org/dc/terms/',
3207 'dcmitype': 'http://purl.org/dc/dcmitype/',
3208 'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
3209 'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
3210 'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
3211 'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
3212 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
3213 'xsd': 'http://www.w3.org/2001/XMLSchema'
3214});
3215
3216XMLNS.main = [
3217 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
3218 'http://purl.oclc.org/ooxml/spreadsheetml/main',
3219 'http://schemas.microsoft.com/office/excel/2006/main',
3220 'http://schemas.microsoft.com/office/excel/2006/2'
3221];
3222
3223var XLMLNS = ({
3224 'o': 'urn:schemas-microsoft-com:office:office',
3225 'x': 'urn:schemas-microsoft-com:office:excel',
3226 'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
3227 'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
3228 'mv': 'http://macVmlSchemaUri',
3229 'v': 'urn:schemas-microsoft-com:vml',
3230 'html': 'http://www.w3.org/TR/REC-html40'
3231});
3232function read_double_le(b, idx) {
3233 var s = 1 - 2 * (b[idx + 7] >>> 7);
3234 var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
3235 var m = (b[idx+6]&0x0f);
3236 for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
3237 if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
3238 if(e == 0) e = -1022;
3239 else { e -= 1023; m += Math.pow(2,52); }
3240 return s * Math.pow(2, e - 52) * m;
3241}
3242
3243function write_double_le(b, v, idx) {
3244 var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
3245 var av = bs ? (-v) : v;
3246 if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
3247 else if(av == 0) e = m = 0;
3248 else {
3249 e = Math.floor(Math.log(av) / Math.LN2);
3250 m = av * Math.pow(2, 52 - e);
3251 if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
3252 else { m -= Math.pow(2,52); e+=1023; }
3253 }
3254 for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
3255 b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
3256 b[idx + 7] = (e >> 4) | bs;
3257}
3258
3259var __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; };
3260var ___toBuffer = __toBuffer;
3261var __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,''); };
3262var ___utf16le = __utf16le;
3263var __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(""); };
3264var ___hexlify = __hexlify;
3265var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
3266var ___utf8 = __utf8;
3267var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3268var ___lpstr = __lpstr;
3269var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3270var ___cpstr = __cpstr;
3271var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3272var ___lpwstr = __lpwstr;
3273var __lpp4, ___lpp4;
3274__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
3275var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
3276var ___8lpp4 = __8lpp4;
3277var __double, ___double;
3278__double = ___double = function(b, idx) { return read_double_le(b, idx);};
3279var is_buf = function is_buf_a(a) { return Array.isArray(a); };
3280
3281if(has_buf) {
3282 __utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
3283 __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
3284 __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) : "";};
3285 __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) : "";};
3286 __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);};
3287 __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);};
3288 __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);};
3289 __utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
3290 __toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
3291 bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
3292 __double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
3293 is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
3294}
3295
3296/* from js-xls */
3297if(typeof cptable !== 'undefined') {
3298 __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
3299 __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
3300 __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)) : "";};
3301 __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)) : "";};
3302 __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)) : "";};
3303 __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
3304 __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
3305}
3306
3307var __readUInt8 = function(b, idx) { return b[idx]; };
3308var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
3309var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
3310var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
3311var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
3312var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
3313
3314function ReadShift(size, t) {
3315 var o="", oI, oR, oo=[], w, vv, i, loc;
3316 switch(t) {
3317 case 'dbcs':
3318 loc = this.l;
3319 if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
3320 else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
3321 size *= 2;
3322 break;
3323
3324 case 'utf8': o = __utf8(this, this.l, this.l + size); break;
3325 case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
3326
3327 case 'wstr':
3328 if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
3329 else return ReadShift.call(this, size, 'dbcs');
3330 size = 2 * size; break;
3331
3332 /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
3333 case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3334 case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3335 /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
3336 case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
3337 /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
3338 case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
3339 /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
3340 case '8lpp4': size = 4 + __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
3341
3342 case 'cstr': size = 0; o = "";
3343 while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
3344 o = oo.join(""); break;
3345 case '_wstr': size = 0; o = "";
3346 while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
3347 size+=2; o = oo.join(""); break;
3348
3349 /* sbcs and dbcs support continue records in the SST way TODO codepages */
3350 case 'dbcs-cont': o = ""; loc = this.l;
3351 for(i = 0; i < size; ++i) {
3352 if(this.lens && this.lens.indexOf(loc) !== -1) {
3353 w = __readUInt8(this, loc);
3354 this.l = loc + 1;
3355 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3356 return oo.join("") + vv;
3357 }
3358 oo.push(_getchar(__readUInt16LE(this, loc)));
3359 loc+=2;
3360 } o = oo.join(""); size *= 2; break;
3361
3362 case 'cpstr':
3363 if(typeof cptable !== 'undefined') {
3364 o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
3365 break;
3366 }
3367 /* falls through */
3368 case 'sbcs-cont': o = ""; loc = this.l;
3369 for(i = 0; i != size; ++i) {
3370 if(this.lens && this.lens.indexOf(loc) !== -1) {
3371 w = __readUInt8(this, loc);
3372 this.l = loc + 1;
3373 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3374 return oo.join("") + vv;
3375 }
3376 oo.push(_getchar(__readUInt8(this, loc)));
3377 loc+=1;
3378 } o = oo.join(""); break;
3379
3380 default:
3381 switch(size) {
3382 case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
3383 case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
3384 case 4: case -4:
3385 if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
3386 else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
3387 case 8: case -8:
3388 if(t === 'f') {
3389 if(size == 8) oR = __double(this, this.l);
3390 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);
3391 this.l += 8; return oR;
3392 } else size = 8;
3393 /* falls through */
3394 case 16: o = __hexlify(this, this.l, size); break;
3395 }}
3396 this.l+=size; return o;
3397}
3398
3399var __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); };
3400var __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); };
3401var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
3402
3403function WriteShift(t, val, f) {
3404 var size = 0, i = 0;
3405 if(f === 'dbcs') {
3406for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
3407 size = 2 * val.length;
3408 } else if(f === 'sbcs') {
3409 if(typeof cptable !== 'undefined' && current_ansi == 874) {
3410 /* TODO: use tables directly, don't encode */
3411for(i = 0; i != val.length; ++i) {
3412 var cppayload = cptable.utils.encode(current_ansi, val.charAt(i));
3413 this[this.l + i] = cppayload[0];
3414 }
3415 } else {
3416val = val.replace(/[^\x00-\x7F]/g, "_");
3417for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
3418 }
3419 size = val.length;
3420 } else if(f === 'hex') {
3421 for(; i < t; ++i) {
3422this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
3423 } return this;
3424 } else if(f === 'utf16le') {
3425var end = Math.min(this.l + t, this.length);
3426 for(i = 0; i < Math.min(val.length, t); ++i) {
3427 var cc = val.charCodeAt(i);
3428 this[this.l++] = (cc & 0xff);
3429 this[this.l++] = (cc >> 8);
3430 }
3431 while(this.l < end) this[this.l++] = 0;
3432 return this;
3433 } else switch(t) {
3434 case 1: size = 1; this[this.l] = val&0xFF; break;
3435 case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
3436 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;
3437 case 4: size = 4; __writeUInt32LE(this, val, this.l); break;
3438 case 8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
3439 /* falls through */
3440 case 16: break;
3441 case -4: size = 4; __writeInt32LE(this, val, this.l); break;
3442 }
3443 this.l += size; return this;
3444}
3445
3446function CheckField(hexstr, fld) {
3447 var m = __hexlify(this,this.l,hexstr.length>>1);
3448 if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
3449 this.l += hexstr.length>>1;
3450}
3451
3452function prep_blob(blob, pos) {
3453 blob.l = pos;
3454 blob.read_shift = ReadShift;
3455 blob.chk = CheckField;
3456 blob.write_shift = WriteShift;
3457}
3458
3459function parsenoop(blob, length) { blob.l += length; }
3460
3461function new_buf(sz) {
3462 var o = new_raw_buf(sz);
3463 prep_blob(o, 0);
3464 return o;
3465}
3466
3467/* [MS-XLSB] 2.1.4 Record */
3468function recordhopper(data, cb, opts) {
3469 if(!data) return;
3470 var tmpbyte, cntbyte, length;
3471 prep_blob(data, data.l || 0);
3472 var L = data.length, RT = 0, tgt = 0;
3473 while(data.l < L) {
3474 RT = data.read_shift(1);
3475 if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
3476 var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
3477 tmpbyte = data.read_shift(1);
3478 length = tmpbyte & 0x7F;
3479 for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
3480 tgt = data.l + length;
3481 var d = R.f && R.f(data, length, opts);
3482 data.l = tgt;
3483 if(cb(d, R.n, RT)) return;
3484 }
3485}
3486
3487/* control buffer usage for fixed-length buffers */
3488function buf_array() {
3489 var bufs = [], blksz = has_buf ? 256 : 2048;
3490 var newblk = function ba_newblk(sz) {
3491 var o = (new_buf(sz));
3492 prep_blob(o, 0);
3493 return o;
3494 };
3495
3496 var curbuf = newblk(blksz);
3497
3498 var endbuf = function ba_endbuf() {
3499 if(!curbuf) return;
3500 if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3501 if(curbuf.length > 0) bufs.push(curbuf);
3502 curbuf = null;
3503 };
3504
3505 var next = function ba_next(sz) {
3506 if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
3507 endbuf();
3508 return (curbuf = newblk(Math.max(sz+1, blksz)));
3509 };
3510
3511 var end = function ba_end() {
3512 endbuf();
3513 return __toBuffer([bufs]);
3514 };
3515
3516 var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
3517
3518 return ({ next:next, push:push, end:end, _bufs:bufs });
3519}
3520
3521function write_record(ba, type, payload, length) {
3522 var t = +XLSBRE[type], l;
3523 if(isNaN(t)) return; // TODO: throw something here?
3524 if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
3525 l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
3526 if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
3527 var o = ba.next(l);
3528 if(t <= 0x7F) o.write_shift(1, t);
3529 else {
3530 o.write_shift(1, (t & 0x7F) + 0x80);
3531 o.write_shift(1, (t >> 7));
3532 }
3533 for(var i = 0; i != 4; ++i) {
3534 if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
3535 else { o.write_shift(1, length); break; }
3536 }
3537 if(length > 0 && is_buf(payload)) ba.push(payload);
3538}
3539/* XLS ranges enforced */
3540function shift_cell_xls(cell, tgt, opts) {
3541 var out = dup(cell);
3542 if(tgt.s) {
3543 if(out.cRel) out.c += tgt.s.c;
3544 if(out.rRel) out.r += tgt.s.r;
3545 } else {
3546 if(out.cRel) out.c += tgt.c;
3547 if(out.rRel) out.r += tgt.r;
3548 }
3549 if(!opts || opts.biff < 12) {
3550 while(out.c >= 0x100) out.c -= 0x100;
3551 while(out.r >= 0x10000) out.r -= 0x10000;
3552 }
3553 return out;
3554}
3555
3556function shift_range_xls(cell, range, opts) {
3557 var out = dup(cell);
3558 out.s = shift_cell_xls(out.s, range.s, opts);
3559 out.e = shift_cell_xls(out.e, range.s, opts);
3560 return out;
3561}
3562
3563function encode_cell_xls(c, biff) {
3564 if(c.cRel && c.c < 0) { c = dup(c); while(c.c < 0) c.c += (biff > 8) ? 0x4000 : 0x100; }
3565 if(c.rRel && c.r < 0) { c = dup(c); while(c.r < 0) c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
3566 var s = encode_cell(c);
3567 if(!c.cRel && c.cRel != null) s = fix_col(s);
3568 if(!c.rRel && c.rRel != null) s = fix_row(s);
3569 return s;
3570}
3571
3572function encode_range_xls(r, opts) {
3573 if(r.s.r == 0 && !r.s.rRel) {
3574 if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
3575 return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
3576 }
3577 }
3578 if(r.s.c == 0 && !r.s.cRel) {
3579 if(r.e.c == (opts.biff >= 12 ? 0x3FFF : 0xFF) && !r.e.cRel) {
3580 return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
3581 }
3582 }
3583 return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
3584}
3585function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
3586function encode_row(row) { return "" + (row + 1); }
3587function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
3588function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
3589
3590function 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; }
3591function 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; }
3592function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
3593function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
3594
3595function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
3596//function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
3597function decode_cell(cstr) {
3598 var R = 0, C = 0;
3599 for(var i = 0; i < cstr.length; ++i) {
3600 var cc = cstr.charCodeAt(i);
3601 if(cc >= 48 && cc <= 57) R = 10 * R + (cc - 48);
3602 else if(cc >= 65 && cc <= 90) C = 26 * C + (cc - 64);
3603 }
3604 return { c: C - 1, r:R - 1 };
3605}
3606//function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
3607function encode_cell(cell) {
3608 var col = cell.c + 1;
3609 var s="";
3610 for(; col; col=((col-1)/26)|0) s = String.fromCharCode(((col-1)%26) + 65) + s;
3611 return s + (cell.r + 1);
3612}
3613function decode_range(range) {
3614 var idx = range.indexOf(":");
3615 if(idx == -1) return { s: decode_cell(range), e: decode_cell(range) };
3616 return { s: decode_cell(range.slice(0, idx)), e: decode_cell(range.slice(idx + 1)) };
3617}
3618function encode_range(cs,ce) {
3619 if(typeof ce === 'undefined' || typeof ce === 'number') {
3620return encode_range(cs.s, cs.e);
3621 }
3622if(typeof cs !== 'string') cs = encode_cell((cs));
3623 if(typeof ce !== 'string') ce = encode_cell((ce));
3624return cs == ce ? cs : cs + ":" + ce;
3625}
3626
3627function safe_decode_range(range) {
3628 var o = {s:{c:0,r:0},e:{c:0,r:0}};
3629 var idx = 0, i = 0, cc = 0;
3630 var len = range.length;
3631 for(idx = 0; i < len; ++i) {
3632 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3633 idx = 26*idx + cc;
3634 }
3635 o.s.c = --idx;
3636
3637 for(idx = 0; i < len; ++i) {
3638 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3639 idx = 10*idx + cc;
3640 }
3641 o.s.r = --idx;
3642
3643 if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
3644
3645 for(idx = 0; i != len; ++i) {
3646 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3647 idx = 26*idx + cc;
3648 }
3649 o.e.c = --idx;
3650
3651 for(idx = 0; i != len; ++i) {
3652 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3653 idx = 10*idx + cc;
3654 }
3655 o.e.r = --idx;
3656 return o;
3657}
3658
3659function safe_format_cell(cell, v) {
3660 var q = (cell.t == 'd' && v instanceof Date);
3661 if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
3662 try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
3663}
3664
3665function format_cell(cell, v, o) {
3666 if(cell == null || cell.t == null || cell.t == 'z') return "";
3667 if(cell.w !== undefined) return cell.w;
3668 if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
3669 if(cell.t == "e") return BErr[cell.v] || cell.v;
3670 if(v == undefined) return safe_format_cell(cell, cell.v);
3671 return safe_format_cell(cell, v);
3672}
3673
3674function sheet_to_workbook(sheet, opts) {
3675 var n = opts && opts.sheet ? opts.sheet : "Sheet1";
3676 var sheets = {}; sheets[n] = sheet;
3677 return { SheetNames: [n], Sheets: sheets };
3678}
3679
3680function sheet_add_aoa(_ws, data, opts) {
3681 var o = opts || {};
3682 var dense = _ws ? Array.isArray(_ws) : o.dense;
3683 if(DENSE != null && dense == null) dense = DENSE;
3684 var ws = _ws || (dense ? ([]) : ({}));
3685 var _R = 0, _C = 0;
3686 if(ws && o.origin != null) {
3687 if(typeof o.origin == 'number') _R = o.origin;
3688 else {
3689 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
3690 _R = _origin.r; _C = _origin.c;
3691 }
3692 if(!ws["!ref"]) ws["!ref"] = "A1:A1";
3693 }
3694 var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
3695 if(ws['!ref']) {
3696 var _range = safe_decode_range(ws['!ref']);
3697 range.s.c = _range.s.c;
3698 range.s.r = _range.s.r;
3699 range.e.c = Math.max(range.e.c, _range.e.c);
3700 range.e.r = Math.max(range.e.r, _range.e.r);
3701 if(_R == -1) range.e.r = _R = _range.e.r + 1;
3702 }
3703 for(var R = 0; R != data.length; ++R) {
3704 if(!data[R]) continue;
3705 if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
3706 for(var C = 0; C != data[R].length; ++C) {
3707 if(typeof data[R][C] === 'undefined') continue;
3708 var cell = ({v: data[R][C] });
3709 var __R = _R + R, __C = _C + C;
3710 if(range.s.r > __R) range.s.r = __R;
3711 if(range.s.c > __C) range.s.c = __C;
3712 if(range.e.r < __R) range.e.r = __R;
3713 if(range.e.c < __C) range.e.c = __C;
3714 if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
3715 else {
3716 if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
3717 if(cell.v === null) {
3718 if(cell.f) cell.t = 'n';
3719 else if(o.nullError) { cell.t = 'e'; cell.v = 0; }
3720 else if(!o.sheetStubs) continue;
3721 else cell.t = 'z';
3722 }
3723 else if(typeof cell.v === 'number') cell.t = 'n';
3724 else if(typeof cell.v === 'boolean') cell.t = 'b';
3725 else if(cell.v instanceof Date) {
3726 cell.z = o.dateNF || SSF._table[14];
3727 if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
3728 else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
3729 }
3730 else cell.t = 's';
3731 }
3732 if(dense) {
3733 if(!ws[__R]) ws[__R] = [];
3734 if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z;
3735 ws[__R][__C] = cell;
3736 } else {
3737 var cell_ref = encode_cell(({c:__C,r:__R}));
3738 if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z;
3739 ws[cell_ref] = cell;
3740 }
3741 }
3742 }
3743 if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
3744 return ws;
3745}
3746function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
3747
3748/* [MS-OLEPS] 2.2 PropertyType */
3749//var VT_EMPTY = 0x0000;
3750//var VT_NULL = 0x0001;
3751var VT_I2 = 0x0002;
3752var VT_I4 = 0x0003;
3753//var VT_R4 = 0x0004;
3754//var VT_R8 = 0x0005;
3755//var VT_CY = 0x0006;
3756//var VT_DATE = 0x0007;
3757//var VT_BSTR = 0x0008;
3758//var VT_ERROR = 0x000A;
3759var VT_BOOL = 0x000B;
3760var VT_VARIANT = 0x000C;
3761//var VT_DECIMAL = 0x000E;
3762//var VT_I1 = 0x0010;
3763//var VT_UI1 = 0x0011;
3764//var VT_UI2 = 0x0012;
3765var VT_UI4 = 0x0013;
3766//var VT_I8 = 0x0014;
3767//var VT_UI8 = 0x0015;
3768//var VT_INT = 0x0016;
3769//var VT_UINT = 0x0017;
3770var VT_LPSTR = 0x001E;
3771//var VT_LPWSTR = 0x001F;
3772var VT_FILETIME = 0x0040;
3773var VT_BLOB = 0x0041;
3774//var VT_STREAM = 0x0042;
3775//var VT_STORAGE = 0x0043;
3776//var VT_STREAMED_Object = 0x0044;
3777//var VT_STORED_Object = 0x0045;
3778//var VT_BLOB_Object = 0x0046;
3779var VT_CF = 0x0047;
3780//var VT_CLSID = 0x0048;
3781//var VT_VERSIONED_STREAM = 0x0049;
3782var VT_VECTOR = 0x1000;
3783//var VT_ARRAY = 0x2000;
3784
3785var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
3786var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
3787var VT_CUSTOM = [VT_STRING, VT_USTR];
3788
3789/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
3790var DocSummaryPIDDSI = {
37910x01: { n: 'CodePage', t: VT_I2 },
37920x02: { n: 'Category', t: VT_STRING },
37930x03: { n: 'PresentationFormat', t: VT_STRING },
37940x04: { n: 'ByteCount', t: VT_I4 },
37950x05: { n: 'LineCount', t: VT_I4 },
37960x06: { n: 'ParagraphCount', t: VT_I4 },
37970x07: { n: 'SlideCount', t: VT_I4 },
37980x08: { n: 'NoteCount', t: VT_I4 },
37990x09: { n: 'HiddenCount', t: VT_I4 },
38000x0a: { n: 'MultimediaClipCount', t: VT_I4 },
38010x0b: { n: 'ScaleCrop', t: VT_BOOL },
38020x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
38030x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
38040x0e: { n: 'Manager', t: VT_STRING },
38050x0f: { n: 'Company', t: VT_STRING },
38060x10: { n: 'LinksUpToDate', t: VT_BOOL },
38070x11: { n: 'CharacterCount', t: VT_I4 },
38080x13: { n: 'SharedDoc', t: VT_BOOL },
38090x16: { n: 'HyperlinksChanged', t: VT_BOOL },
38100x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
38110x18: { n: 'DigSig', t: VT_BLOB },
38120x1A: { n: 'ContentType', t: VT_STRING },
38130x1B: { n: 'ContentStatus', t: VT_STRING },
38140x1C: { n: 'Language', t: VT_STRING },
38150x1D: { n: 'Version', t: VT_STRING },
38160xFF: {},
3817 /* [MS-OLEPS] 2.18 */
38180x80000000: { n: 'Locale', t: VT_UI4 },
38190x80000003: { n: 'Behavior', t: VT_UI4 },
38200x72627262: {}
3821};
3822
3823/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
3824var SummaryPIDSI = {
38250x01: { n: 'CodePage', t: VT_I2 },
38260x02: { n: 'Title', t: VT_STRING },
38270x03: { n: 'Subject', t: VT_STRING },
38280x04: { n: 'Author', t: VT_STRING },
38290x05: { n: 'Keywords', t: VT_STRING },
38300x06: { n: 'Comments', t: VT_STRING },
38310x07: { n: 'Template', t: VT_STRING },
38320x08: { n: 'LastAuthor', t: VT_STRING },
38330x09: { n: 'RevNumber', t: VT_STRING },
38340x0A: { n: 'EditTime', t: VT_FILETIME },
38350x0B: { n: 'LastPrinted', t: VT_FILETIME },
38360x0C: { n: 'CreatedDate', t: VT_FILETIME },
38370x0D: { n: 'ModifiedDate', t: VT_FILETIME },
38380x0E: { n: 'PageCount', t: VT_I4 },
38390x0F: { n: 'WordCount', t: VT_I4 },
38400x10: { n: 'CharCount', t: VT_I4 },
38410x11: { n: 'Thumbnail', t: VT_CF },
38420x12: { n: 'Application', t: VT_STRING },
38430x13: { n: 'DocSecurity', t: VT_I4 },
38440xFF: {},
3845 /* [MS-OLEPS] 2.18 */
38460x80000000: { n: 'Locale', t: VT_UI4 },
38470x80000003: { n: 'Behavior', t: VT_UI4 },
38480x72627262: {}
3849};
3850
3851var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
3852var SummaryRE = evert_key(SummaryPIDSI, "n");
3853
3854/* [MS-XLS] 2.4.63 Country/Region codes */
3855var CountryEnum = {
38560x0001: "US", // United States
38570x0002: "CA", // Canada
38580x0003: "", // Latin America (except Brazil)
38590x0007: "RU", // Russia
38600x0014: "EG", // Egypt
38610x001E: "GR", // Greece
38620x001F: "NL", // Netherlands
38630x0020: "BE", // Belgium
38640x0021: "FR", // France
38650x0022: "ES", // Spain
38660x0024: "HU", // Hungary
38670x0027: "IT", // Italy
38680x0029: "CH", // Switzerland
38690x002B: "AT", // Austria
38700x002C: "GB", // United Kingdom
38710x002D: "DK", // Denmark
38720x002E: "SE", // Sweden
38730x002F: "NO", // Norway
38740x0030: "PL", // Poland
38750x0031: "DE", // Germany
38760x0034: "MX", // Mexico
38770x0037: "BR", // Brazil
38780x003d: "AU", // Australia
38790x0040: "NZ", // New Zealand
38800x0042: "TH", // Thailand
38810x0051: "JP", // Japan
38820x0052: "KR", // Korea
38830x0054: "VN", // Viet Nam
38840x0056: "CN", // China
38850x005A: "TR", // Turkey
38860x0069: "JS", // Ramastan
38870x00D5: "DZ", // Algeria
38880x00D8: "MA", // Morocco
38890x00DA: "LY", // Libya
38900x015F: "PT", // Portugal
38910x0162: "IS", // Iceland
38920x0166: "FI", // Finland
38930x01A4: "CZ", // Czech Republic
38940x0376: "TW", // Taiwan
38950x03C1: "LB", // Lebanon
38960x03C2: "JO", // Jordan
38970x03C3: "SY", // Syria
38980x03C4: "IQ", // Iraq
38990x03C5: "KW", // Kuwait
39000x03C6: "SA", // Saudi Arabia
39010x03CB: "AE", // United Arab Emirates
39020x03CC: "IL", // Israel
39030x03CE: "QA", // Qatar
39040x03D5: "IR", // Iran
39050xFFFF: "US" // United States
3906};
3907
3908/* [MS-XLS] 2.5.127 */
3909var XLSFillPattern = [
3910 null,
3911 'solid',
3912 'mediumGray',
3913 'darkGray',
3914 'lightGray',
3915 'darkHorizontal',
3916 'darkVertical',
3917 'darkDown',
3918 'darkUp',
3919 'darkGrid',
3920 'darkTrellis',
3921 'lightHorizontal',
3922 'lightVertical',
3923 'lightDown',
3924 'lightUp',
3925 'lightGrid',
3926 'lightTrellis',
3927 'gray125',
3928 'gray0625'
3929];
3930
3931function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
3932
3933/* [MS-XLS] 2.5.161 */
3934/* [MS-XLSB] 2.5.75 Icv */
3935var _XLSIcv = rgbify([
3936 /* Color Constants */
3937 0x000000,
3938 0xFFFFFF,
3939 0xFF0000,
3940 0x00FF00,
3941 0x0000FF,
3942 0xFFFF00,
3943 0xFF00FF,
3944 0x00FFFF,
3945
3946 /* Overridable Defaults */
3947 0x000000,
3948 0xFFFFFF,
3949 0xFF0000,
3950 0x00FF00,
3951 0x0000FF,
3952 0xFFFF00,
3953 0xFF00FF,
3954 0x00FFFF,
3955
3956 0x800000,
3957 0x008000,
3958 0x000080,
3959 0x808000,
3960 0x800080,
3961 0x008080,
3962 0xC0C0C0,
3963 0x808080,
3964 0x9999FF,
3965 0x993366,
3966 0xFFFFCC,
3967 0xCCFFFF,
3968 0x660066,
3969 0xFF8080,
3970 0x0066CC,
3971 0xCCCCFF,
3972
3973 0x000080,
3974 0xFF00FF,
3975 0xFFFF00,
3976 0x00FFFF,
3977 0x800080,
3978 0x800000,
3979 0x008080,
3980 0x0000FF,
3981 0x00CCFF,
3982 0xCCFFFF,
3983 0xCCFFCC,
3984 0xFFFF99,
3985 0x99CCFF,
3986 0xFF99CC,
3987 0xCC99FF,
3988 0xFFCC99,
3989
3990 0x3366FF,
3991 0x33CCCC,
3992 0x99CC00,
3993 0xFFCC00,
3994 0xFF9900,
3995 0xFF6600,
3996 0x666699,
3997 0x969696,
3998 0x003366,
3999 0x339966,
4000 0x003300,
4001 0x333300,
4002 0x993300,
4003 0x993366,
4004 0x333399,
4005 0x333333,
4006
4007 /* Other entries to appease BIFF8/12 */
4008 0xFFFFFF, /* 0x40 icvForeground ?? */
4009 0x000000, /* 0x41 icvBackground ?? */
4010 0x000000, /* 0x42 icvFrame ?? */
4011 0x000000, /* 0x43 icv3D ?? */
4012 0x000000, /* 0x44 icv3DText ?? */
4013 0x000000, /* 0x45 icv3DHilite ?? */
4014 0x000000, /* 0x46 icv3DShadow ?? */
4015 0x000000, /* 0x47 icvHilite ?? */
4016 0x000000, /* 0x48 icvCtlText ?? */
4017 0x000000, /* 0x49 icvCtlScrl ?? */
4018 0x000000, /* 0x4A icvCtlInv ?? */
4019 0x000000, /* 0x4B icvCtlBody ?? */
4020 0x000000, /* 0x4C icvCtlFrame ?? */
4021 0x000000, /* 0x4D icvCtlFore ?? */
4022 0x000000, /* 0x4E icvCtlBack ?? */
4023 0x000000, /* 0x4F icvCtlNeutral */
4024 0x000000, /* 0x50 icvInfoBk ?? */
4025 0x000000 /* 0x51 icvInfoText ?? */
4026]);
4027var XLSIcv = dup(_XLSIcv);
4028
4029/* [MS-XLSB] 2.5.97.2 */
4030var BErr = {
40310x00: "#NULL!",
40320x07: "#DIV/0!",
40330x0F: "#VALUE!",
40340x17: "#REF!",
40350x1D: "#NAME?",
40360x24: "#NUM!",
40370x2A: "#N/A",
40380x2B: "#GETTING_DATA",
40390xFF: "#WTF?"
4040};
4041var RBErr = evert_num(BErr);
4042/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
4043/* 12.3 Part Summary <SpreadsheetML> */
4044/* 14.2 Part Summary <DrawingML> */
4045/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
4046var ct2type/*{[string]:string}*/ = ({
4047 /* Workbook */
4048 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
4049
4050 /* Worksheet */
4051 "application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
4052
4053 /* Macrosheet */
4054 "application/vnd.ms-excel.intlmacrosheet": "TODO",
4055 "application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
4056
4057 /* File Properties */
4058 "application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
4059 "application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
4060 "application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
4061
4062 /* Custom Data Properties */
4063 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
4064 "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
4065
4066 /* PivotTable */
4067 "application/vnd.ms-excel.pivotTable": "TODO",
4068 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
4069
4070 /* Chart Objects */
4071 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
4072
4073 /* Chart Colors */
4074 "application/vnd.ms-office.chartcolorstyle+xml": "TODO",
4075
4076 /* Chart Style */
4077 "application/vnd.ms-office.chartstyle+xml": "TODO",
4078
4079 /* Chart Advanced */
4080 "application/vnd.ms-office.chartex+xml": "TODO",
4081
4082 /* Calculation Chain */
4083 "application/vnd.ms-excel.calcChain": "calcchains",
4084 "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
4085
4086 /* Printer Settings */
4087 "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
4088
4089 /* ActiveX */
4090 "application/vnd.ms-office.activeX": "TODO",
4091 "application/vnd.ms-office.activeX+xml": "TODO",
4092
4093 /* Custom Toolbars */
4094 "application/vnd.ms-excel.attachedToolbars": "TODO",
4095
4096 /* External Data Connections */
4097 "application/vnd.ms-excel.connections": "TODO",
4098 "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
4099
4100 /* External Links */
4101 "application/vnd.ms-excel.externalLink": "links",
4102 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
4103
4104 /* Metadata */
4105 "application/vnd.ms-excel.sheetMetadata": "TODO",
4106 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
4107
4108 /* PivotCache */
4109 "application/vnd.ms-excel.pivotCacheDefinition": "TODO",
4110 "application/vnd.ms-excel.pivotCacheRecords": "TODO",
4111 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
4112 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
4113
4114 /* Query Table */
4115 "application/vnd.ms-excel.queryTable": "TODO",
4116 "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
4117
4118 /* Shared Workbook */
4119 "application/vnd.ms-excel.userNames": "TODO",
4120 "application/vnd.ms-excel.revisionHeaders": "TODO",
4121 "application/vnd.ms-excel.revisionLog": "TODO",
4122 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
4123 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
4124 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
4125
4126 /* Single Cell Table */
4127 "application/vnd.ms-excel.tableSingleCells": "TODO",
4128 "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
4129
4130 /* Slicer */
4131 "application/vnd.ms-excel.slicer": "TODO",
4132 "application/vnd.ms-excel.slicerCache": "TODO",
4133 "application/vnd.ms-excel.slicer+xml": "TODO",
4134 "application/vnd.ms-excel.slicerCache+xml": "TODO",
4135
4136 /* Sort Map */
4137 "application/vnd.ms-excel.wsSortMap": "TODO",
4138
4139 /* Table */
4140 "application/vnd.ms-excel.table": "TODO",
4141 "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
4142
4143 /* Themes */
4144 "application/vnd.openxmlformats-officedocument.theme+xml": "themes",
4145
4146 /* Theme Override */
4147 "application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
4148
4149 /* Timeline */
4150 "application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
4151 "application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
4152
4153 /* VBA */
4154 "application/vnd.ms-office.vbaProject": "vba",
4155 "application/vnd.ms-office.vbaProjectSignature": "vba",
4156
4157 /* Volatile Dependencies */
4158 "application/vnd.ms-office.volatileDependencies": "TODO",
4159 "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
4160
4161 /* Control Properties */
4162 "application/vnd.ms-excel.controlproperties+xml": "TODO",
4163
4164 /* Data Model */
4165 "application/vnd.openxmlformats-officedocument.model+data": "TODO",
4166
4167 /* Survey */
4168 "application/vnd.ms-excel.Survey+xml": "TODO",
4169
4170 /* Drawing */
4171 "application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
4172 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
4173 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
4174 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
4175 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
4176 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
4177
4178 /* VML */
4179 "application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
4180
4181 "application/vnd.openxmlformats-package.relationships+xml": "rels",
4182 "application/vnd.openxmlformats-officedocument.oleObject": "TODO",
4183
4184 /* Image */
4185 "image/png": "TODO",
4186
4187 "sheet": "js"
4188});
4189
4190var CT_LIST = (function(){
4191 var o = {
4192 workbooks: {
4193 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
4194 xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
4195 xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
4196 xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
4197 xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
4198 },
4199 strs: { /* Shared Strings */
4200 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
4201 xlsb: "application/vnd.ms-excel.sharedStrings"
4202 },
4203 comments: { /* Comments */
4204 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
4205 xlsb: "application/vnd.ms-excel.comments"
4206 },
4207 sheets: { /* Worksheet */
4208 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
4209 xlsb: "application/vnd.ms-excel.worksheet"
4210 },
4211 charts: { /* Chartsheet */
4212 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
4213 xlsb: "application/vnd.ms-excel.chartsheet"
4214 },
4215 dialogs: { /* Dialogsheet */
4216 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
4217 xlsb: "application/vnd.ms-excel.dialogsheet"
4218 },
4219 macros: { /* Macrosheet (Excel 4.0 Macros) */
4220 xlsx: "application/vnd.ms-excel.macrosheet+xml",
4221 xlsb: "application/vnd.ms-excel.macrosheet"
4222 },
4223 styles: { /* Styles */
4224 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
4225 xlsb: "application/vnd.ms-excel.styles"
4226 }
4227 };
4228 keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
4229 keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
4230 return o;
4231})();
4232
4233var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
4234
4235XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
4236
4237function new_ct() {
4238 return ({
4239 workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
4240 rels:[], strs:[], comments:[], links:[],
4241 coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
4242 calcchains:[], vba: [], drawings: [],
4243 TODO:[], xmlns: "" });
4244}
4245
4246function parse_ct(data) {
4247 var ct = new_ct();
4248 if(!data || !data.match) return ct;
4249 var ctext = {};
4250 (data.match(tagregex)||[]).forEach(function(x) {
4251 var y = parsexmltag(x);
4252 switch(y[0].replace(nsregex,"<")) {
4253 case '<?xml': break;
4254 case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
4255 case '<Default': ctext[y.Extension] = y.ContentType; break;
4256 case '<Override':
4257 if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
4258 break;
4259 }
4260 });
4261 if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
4262 ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
4263 ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
4264 ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
4265 ct.defaults = ctext;
4266 delete ct.calcchains;
4267 return ct;
4268}
4269
4270var CTYPE_XML_ROOT = writextag('Types', null, {
4271 'xmlns': XMLNS.CT,
4272 'xmlns:xsd': XMLNS.xsd,
4273 'xmlns:xsi': XMLNS.xsi
4274});
4275
4276var CTYPE_DEFAULTS = [
4277 ['xml', 'application/xml'],
4278 ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
4279 ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
4280 ['data', 'application/vnd.openxmlformats-officedocument.model+data'],
4281 /* from test files */
4282 ['bmp', 'image/bmp'],
4283 ['png', 'image/png'],
4284 ['gif', 'image/gif'],
4285 ['emf', 'image/x-emf'],
4286 ['wmf', 'image/x-wmf'],
4287 ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
4288 ['tif', 'image/tiff'], ['tiff', 'image/tiff'],
4289 ['pdf', 'application/pdf'],
4290 ['rels', type2ct.rels[0]]
4291].map(function(x) {
4292 return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
4293});
4294
4295function write_ct(ct, opts) {
4296 var o = [], v;
4297 o[o.length] = (XML_HEADER);
4298 o[o.length] = (CTYPE_XML_ROOT);
4299 o = o.concat(CTYPE_DEFAULTS);
4300
4301 /* only write first instance */
4302 var f1 = function(w) {
4303 if(ct[w] && ct[w].length > 0) {
4304 v = ct[w][0];
4305 o[o.length] = (writextag('Override', null, {
4306 'PartName': (v[0] == '/' ? "":"/") + v,
4307 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4308 }));
4309 }
4310 };
4311
4312 /* book type-specific */
4313 var f2 = function(w) {
4314 (ct[w]||[]).forEach(function(v) {
4315 o[o.length] = (writextag('Override', null, {
4316 'PartName': (v[0] == '/' ? "":"/") + v,
4317 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4318 }));
4319 });
4320 };
4321
4322 /* standard type */
4323 var f3 = function(t) {
4324 (ct[t]||[]).forEach(function(v) {
4325 o[o.length] = (writextag('Override', null, {
4326 'PartName': (v[0] == '/' ? "":"/") + v,
4327 'ContentType': type2ct[t][0]
4328 }));
4329 });
4330 };
4331
4332 f1('workbooks');
4333 f2('sheets');
4334 f2('charts');
4335 f3('themes');
4336 ['strs', 'styles'].forEach(f1);
4337 ['coreprops', 'extprops', 'custprops'].forEach(f3);
4338 f3('vba');
4339 f3('comments');
4340 f3('drawings');
4341 if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
4342 return o.join("");
4343}
4344/* 9.3 Relationships */
4345var RELS = ({
4346 WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4347 SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4348 HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
4349 VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
4350 XPATH: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",
4351 XMISS: "http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",
4352 XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
4353 CXML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",
4354 CXMLP: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",
4355 VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
4356});
4357
4358/* 9.3.3 Representing Relationships */
4359function get_rels_path(file) {
4360 var n = file.lastIndexOf("/");
4361 return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
4362}
4363
4364function parse_rels(data, currentFilePath) {
4365 var rels = {"!id":{}};
4366 if (!data) return rels;
4367 if (currentFilePath.charAt(0) !== '/') {
4368 currentFilePath = '/'+currentFilePath;
4369 }
4370 var hash = {};
4371
4372 (data.match(tagregex)||[]).forEach(function(x) {
4373 var y = parsexmltag(x);
4374 /* 9.3.2.2 OPC_Relationships */
4375 if (y[0] === '<Relationship') {
4376 var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
4377 var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
4378 rels[canonictarget] = rel;
4379 hash[y.Id] = rel;
4380 }
4381 });
4382 rels["!id"] = hash;
4383 return rels;
4384}
4385
4386XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
4387
4388var RELS_ROOT = writextag('Relationships', null, {
4389 //'xmlns:ns0': XMLNS.RELS,
4390 'xmlns': XMLNS.RELS
4391});
4392
4393/* TODO */
4394function write_rels(rels) {
4395 var o = [XML_HEADER, RELS_ROOT];
4396 keys(rels['!id']).forEach(function(rid) {
4397 o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
4398 });
4399 if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
4400 return o.join("");
4401}
4402
4403var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
4404function add_rels(rels, rId, f, type, relobj, targetmode) {
4405 if(!relobj) relobj = {};
4406 if(!rels['!id']) rels['!id'] = {};
4407 if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
4408 relobj.Id = 'rId' + rId;
4409 relobj.Type = type;
4410 relobj.Target = f;
4411 if(targetmode) relobj.TargetMode = targetmode;
4412 else if(RELS_EXTERN.indexOf(relobj.Type) > -1) relobj.TargetMode = "External";
4413 if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
4414 rels['!id'][relobj.Id] = relobj;
4415 rels[('/' + relobj.Target).replace("//","/")] = relobj;
4416 return rId;
4417}
4418/* ECMA-376 Part II 11.1 Core Properties Part */
4419/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4420var CORE_PROPS = [
4421 ["cp:category", "Category"],
4422 ["cp:contentStatus", "ContentStatus"],
4423 ["cp:keywords", "Keywords"],
4424 ["cp:lastModifiedBy", "LastAuthor"],
4425 ["cp:lastPrinted", "LastPrinted"],
4426 ["cp:revision", "RevNumber"],
4427 ["cp:version", "Version"],
4428 ["dc:creator", "Author"],
4429 ["dc:description", "Comments"],
4430 ["dc:identifier", "Identifier"],
4431 ["dc:language", "Language"],
4432 ["dc:subject", "Subject"],
4433 ["dc:title", "Title"],
4434 ["dcterms:created", "CreatedDate", 'date'],
4435 ["dcterms:modified", "ModifiedDate", 'date']
4436];
4437
4438XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
4439RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
4440
4441var CORE_PROPS_REGEX = (function() {
4442 var r = new Array(CORE_PROPS.length);
4443 for(var i = 0; i < CORE_PROPS.length; ++i) {
4444 var f = CORE_PROPS[i];
4445 var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
4446 r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
4447 }
4448 return r;
4449})();
4450
4451function parse_core_props(data) {
4452 var p = {};
4453 data = utf8read(data);
4454
4455 for(var i = 0; i < CORE_PROPS.length; ++i) {
4456 var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4457 if(cur != null && cur.length > 0) p[f[1]] = unescapexml(cur[1]);
4458 if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4459 }
4460
4461 return p;
4462}
4463
4464var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4465 //'xmlns': XMLNS.CORE_PROPS,
4466 'xmlns:cp': XMLNS.CORE_PROPS,
4467 'xmlns:dc': XMLNS.dc,
4468 'xmlns:dcterms': XMLNS.dcterms,
4469 'xmlns:dcmitype': XMLNS.dcmitype,
4470 'xmlns:xsi': XMLNS.xsi
4471});
4472
4473function cp_doit(f, g, h, o, p) {
4474 if(p[f] != null || g == null || g === "") return;
4475 p[f] = g;
4476 g = escapexml(g);
4477 o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4478}
4479
4480function write_core_props(cp, _opts) {
4481 var opts = _opts || {};
4482 var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4483 if(!cp && !opts.Props) return o.join("");
4484
4485 if(cp) {
4486 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);
4487 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);
4488 }
4489
4490 for(var i = 0; i != CORE_PROPS.length; ++i) {
4491 var f = CORE_PROPS[i];
4492 var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4493 if(v === true) v = "1";
4494 else if(v === false) v = "0";
4495 else if(typeof v == "number") v = String(v);
4496 if(v != null) cp_doit(f[0], v, null, o, p);
4497 }
4498 if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4499 return o.join("");
4500}
4501/* 15.2.12.3 Extended File Properties Part */
4502/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4503var EXT_PROPS = [
4504 ["Application", "Application", "string"],
4505 ["AppVersion", "AppVersion", "string"],
4506 ["Company", "Company", "string"],
4507 ["DocSecurity", "DocSecurity", "string"],
4508 ["Manager", "Manager", "string"],
4509 ["HyperlinksChanged", "HyperlinksChanged", "bool"],
4510 ["SharedDoc", "SharedDoc", "bool"],
4511 ["LinksUpToDate", "LinksUpToDate", "bool"],
4512 ["ScaleCrop", "ScaleCrop", "bool"],
4513 ["HeadingPairs", "HeadingPairs", "raw"],
4514 ["TitlesOfParts", "TitlesOfParts", "raw"]
4515];
4516
4517XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4518RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4519
4520var PseudoPropsPairs = [
4521 "Worksheets", "SheetNames",
4522 "NamedRanges", "DefinedNames",
4523 "Chartsheets", "ChartNames"
4524];
4525function load_props_pairs(HP, TOP, props, opts) {
4526 var v = [];
4527 if(typeof HP == "string") v = parseVector(HP, opts);
4528 else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4529 var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4530 var idx = 0, len = 0;
4531 if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4532 len = +(v[i+1].v);
4533 switch(v[i].v) {
4534 case "Worksheets":
4535 case "工作表":
4536 case "Листы":
4537 case "أوراق العمل":
4538 case "ワークシート":
4539 case "גליונות עבודה":
4540 case "Arbeitsblätter":
4541 case "Çalışma Sayfaları":
4542 case "Feuilles de calcul":
4543 case "Fogli di lavoro":
4544 case "Folhas de cálculo":
4545 case "Planilhas":
4546 case "Regneark":
4547 case "Hojas de cálculo":
4548 case "Werkbladen":
4549 props.Worksheets = len;
4550 props.SheetNames = parts.slice(idx, idx + len);
4551 break;
4552
4553 case "Named Ranges":
4554 case "Rangos con nombre":
4555 case "名前付き一覧":
4556 case "Benannte Bereiche":
4557 case "Navngivne områder":
4558 props.NamedRanges = len;
4559 props.DefinedNames = parts.slice(idx, idx + len);
4560 break;
4561
4562 case "Charts":
4563 case "Diagramme":
4564 props.Chartsheets = len;
4565 props.ChartNames = parts.slice(idx, idx + len);
4566 break;
4567 }
4568 idx += len;
4569 }
4570}
4571
4572function parse_ext_props(data, p, opts) {
4573 var q = {}; if(!p) p = {};
4574 data = utf8read(data);
4575
4576 EXT_PROPS.forEach(function(f) {
4577 var xml = (data.match(matchtag(f[0]))||[])[1];
4578 switch(f[2]) {
4579 case "string": if(xml) p[f[1]] = unescapexml(xml); break;
4580 case "bool": p[f[1]] = xml === "true"; break;
4581 case "raw":
4582 var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4583 if(cur && cur.length > 0) q[f[1]] = cur[1];
4584 break;
4585 }
4586 });
4587
4588 if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4589
4590 return p;
4591}
4592
4593var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4594 'xmlns': XMLNS.EXT_PROPS,
4595 'xmlns:vt': XMLNS.vt
4596});
4597
4598function write_ext_props(cp) {
4599 var o = [], W = writextag;
4600 if(!cp) cp = {};
4601 cp.Application = "SheetJS";
4602 o[o.length] = (XML_HEADER);
4603 o[o.length] = (EXT_PROPS_XML_ROOT);
4604
4605 EXT_PROPS.forEach(function(f) {
4606 if(cp[f[1]] === undefined) return;
4607 var v;
4608 switch(f[2]) {
4609 case 'string': v = escapexml(String(cp[f[1]])); break;
4610 case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4611 }
4612 if(v !== undefined) o[o.length] = (W(f[0], v));
4613 });
4614
4615 /* TODO: HeadingPairs, TitlesOfParts */
4616 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"})));
4617 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"})));
4618 if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4619 return o.join("");
4620}
4621/* 15.2.12.2 Custom File Properties Part */
4622XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4623RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4624
4625var custregex = /<[^>]+>[^<]*/g;
4626function parse_cust_props(data, opts) {
4627 var p = {}, name = "";
4628 var m = data.match(custregex);
4629 if(m) for(var i = 0; i != m.length; ++i) {
4630 var x = m[i], y = parsexmltag(x);
4631 switch(y[0]) {
4632 case '<?xml': break;
4633 case '<Properties': break;
4634 case '<property': name = unescapexml(y.name); break;
4635 case '</property>': name = null; break;
4636 default: if (x.indexOf('<vt:') === 0) {
4637 var toks = x.split('>');
4638 var type = toks[0].slice(4), text = toks[1];
4639 /* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4640 switch(type) {
4641 case 'lpstr': case 'bstr': case 'lpwstr':
4642 p[name] = unescapexml(text);
4643 break;
4644 case 'bool':
4645 p[name] = parsexmlbool(text);
4646 break;
4647 case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4648 p[name] = parseInt(text, 10);
4649 break;
4650 case 'r4': case 'r8': case 'decimal':
4651 p[name] = parseFloat(text);
4652 break;
4653 case 'filetime': case 'date':
4654 p[name] = parseDate(text);
4655 break;
4656 case 'cy': case 'error':
4657 p[name] = unescapexml(text);
4658 break;
4659 default:
4660 if(type.slice(-1) == '/') break;
4661 if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4662 }
4663 } else if(x.slice(0,2) === "</") {/* empty */
4664 } else if(opts.WTF) throw new Error(x);
4665 }
4666 }
4667 return p;
4668}
4669
4670var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4671 'xmlns': XMLNS.CUST_PROPS,
4672 'xmlns:vt': XMLNS.vt
4673});
4674
4675function write_cust_props(cp) {
4676 var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4677 if(!cp) return o.join("");
4678 var pid = 1;
4679 keys(cp).forEach(function custprop(k) { ++pid;
4680 o[o.length] = (writextag('property', write_vt(cp[k], true), {
4681 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4682 'pid': pid,
4683 'name': escapexml(k)
4684 }));
4685 });
4686 if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4687 return o.join("");
4688}
4689/* from js-harb (C) 2014-present SheetJS */
4690var DBF = (function() {
4691var dbf_codepage_map = {
4692 /* Code Pages Supported by Visual FoxPro */
46930x01: 437, 0x02: 850,
46940x03: 1252, 0x04: 10000,
46950x64: 852, 0x65: 866,
46960x66: 865, 0x67: 861,
46970x68: 895, 0x69: 620,
46980x6A: 737, 0x6B: 857,
46990x78: 950, 0x79: 949,
47000x7A: 936, 0x7B: 932,
47010x7C: 874, 0x7D: 1255,
47020x7E: 1256, 0x96: 10007,
47030x97: 10029, 0x98: 10006,
47040xC8: 1250, 0xC9: 1251,
47050xCA: 1254, 0xCB: 1253,
4706
4707 /* shapefile DBF extension */
47080x00: 20127, 0x08: 865,
47090x09: 437, 0x0A: 850,
47100x0B: 437, 0x0D: 437,
47110x0E: 850, 0x0F: 437,
47120x10: 850, 0x11: 437,
47130x12: 850, 0x13: 932,
47140x14: 850, 0x15: 437,
47150x16: 850, 0x17: 865,
47160x18: 437, 0x19: 437,
47170x1A: 850, 0x1B: 437,
47180x1C: 863, 0x1D: 850,
47190x1F: 852, 0x22: 852,
47200x23: 852, 0x24: 860,
47210x25: 850, 0x26: 866,
47220x37: 850, 0x40: 852,
47230x4D: 936, 0x4E: 949,
47240x4F: 950, 0x50: 874,
47250x57: 1252, 0x58: 1252,
47260x59: 1252, 0x6C: 863,
47270x86: 737, 0x87: 852,
47280x88: 857, 0xCC: 1257,
4729
47300xFF: 16969
4731};
4732var dbf_reverse_map = evert({
47330x01: 437, 0x02: 850,
47340x03: 1252, 0x04: 10000,
47350x64: 852, 0x65: 866,
47360x66: 865, 0x67: 861,
47370x68: 895, 0x69: 620,
47380x6A: 737, 0x6B: 857,
47390x78: 950, 0x79: 949,
47400x7A: 936, 0x7B: 932,
47410x7C: 874, 0x7D: 1255,
47420x7E: 1256, 0x96: 10007,
47430x97: 10029, 0x98: 10006,
47440xC8: 1250, 0xC9: 1251,
47450xCA: 1254, 0xCB: 1253,
47460x00: 20127
4747});
4748var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5];
4749/* TODO: find an actual specification */
4750function dbf_to_aoa(buf, opts) {
4751 var out = [];
4752 var d = (new_raw_buf(1));
4753 switch(opts.type) {
4754 case 'base64': d = s2a(Base64.decode(buf)); break;
4755 case 'binary': d = s2a(buf); break;
4756 case 'buffer':
4757 case 'array': d = buf; break;
4758 }
4759 prep_blob(d, 0);
4760
4761 /* header */
4762 var ft = d.read_shift(1);
4763 var memo = !!(ft & 0x88);
4764 var vfp = false, l7 = false;
4765 switch(ft) {
4766 case 0x02: break; // dBASE II
4767 case 0x03: break; // dBASE III
4768 case 0x30: vfp = true; memo = true; break; // VFP
4769 case 0x31: vfp = true; memo = true; break; // VFP with autoincrement
4770 // 0x43 dBASE IV SQL table files
4771 // 0x63 dBASE IV SQL system files
4772 case 0x83: break; // dBASE III with memo
4773 case 0x8B: break; // dBASE IV with memo
4774 case 0x8C: l7 = true; break; // dBASE Level 7 with memo
4775 // case 0xCB dBASE IV SQL table files with memo
4776 case 0xF5: break; // FoxPro 2.x with memo
4777 // case 0xFB FoxBASE
4778 default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
4779 }
4780
4781 var nrow = 0, fpos = 0x0209;
4782 if(ft == 0x02) nrow = d.read_shift(2);
4783 d.l += 3; // dBASE II stores DDMMYY date, others use YYMMDD
4784 if(ft != 0x02) nrow = d.read_shift(4);
4785 if(nrow > 1048576) nrow = 1e6;
4786
4787 if(ft != 0x02) fpos = d.read_shift(2); // header length
4788 var rlen = d.read_shift(2); // record length
4789
4790 var /*flags = 0,*/ current_cp = opts.codepage || 1252;
4791 if(ft != 0x02) { // 20 reserved bytes
4792 d.l+=16;
4793 /*flags = */d.read_shift(1);
4794 //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
4795
4796 /* codepage present in FoxPro and dBASE Level 7 */
4797 if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
4798 d.l+=1;
4799
4800 d.l+=2;
4801 }
4802 if(l7) d.l += 36; // Level 7: 32 byte "Language driver name", 4 byte reserved
4803
4804var fields = [], field = ({});
4805 var hend = Math.min(d.length, (ft == 0x02 ? 0x209 : (fpos - 10 - (vfp ? 264 : 0))));
4806 var ww = l7 ? 32 : 11;
4807 while(d.l < hend && d[d.l] != 0x0d) {
4808 field = ({});
4809 field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
4810 d.l += ww;
4811 field.type = String.fromCharCode(d.read_shift(1));
4812 if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
4813 field.len = d.read_shift(1);
4814 if(ft == 0x02) field.offset = d.read_shift(2);
4815 field.dec = d.read_shift(1);
4816 if(field.name.length) fields.push(field);
4817 if(ft != 0x02) d.l += l7 ? 13 : 14;
4818 switch(field.type) {
4819 case 'B': // Double (VFP) / Binary (dBASE L7)
4820 if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
4821 break;
4822 case 'G': // General (FoxPro and dBASE L7)
4823 case 'P': // Picture (FoxPro and dBASE L7)
4824 if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
4825 break;
4826 case '+': // Autoincrement (dBASE L7 only)
4827 case '0': // _NullFlags (VFP only)
4828 case '@': // Timestamp (dBASE L7 only)
4829 case 'C': // Character (dBASE II)
4830 case 'D': // Date (dBASE III)
4831 case 'F': // Float (dBASE IV)
4832 case 'I': // Long (VFP and dBASE L7)
4833 case 'L': // Logical (dBASE II)
4834 case 'M': // Memo (dBASE III)
4835 case 'N': // Number (dBASE II)
4836 case 'O': // Double (dBASE L7 only)
4837 case 'T': // Datetime (VFP only)
4838 case 'Y': // Currency (VFP only)
4839 break;
4840 default: throw new Error('Unknown Field Type: ' + field.type);
4841 }
4842 }
4843
4844 if(d[d.l] !== 0x0D) d.l = fpos-1;
4845 if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
4846 d.l = fpos;
4847
4848 /* data */
4849 var R = 0, C = 0;
4850 out[0] = [];
4851 for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
4852 while(nrow-- > 0) {
4853 if(d[d.l] === 0x2A) {
4854 // TODO: record marked as deleted -- create a hidden row?
4855 d.l+=rlen;
4856 continue;
4857 }
4858 ++d.l;
4859 out[++R] = []; C = 0;
4860 for(C = 0; C != fields.length; ++C) {
4861 var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
4862 prep_blob(dd, 0);
4863 var s = cptable.utils.decode(current_cp, dd);
4864 switch(fields[C].type) {
4865 case 'C':
4866 // NOTE: it is conventional to write ' / / ' for empty dates
4867 if(s.trim().length) out[R][C] = s.replace(/\s+$/,"");
4868 break;
4869 case 'D':
4870 if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
4871 else out[R][C] = s;
4872 break;
4873 case 'F': out[R][C] = parseFloat(s.trim()); break;
4874 case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
4875 case 'L': switch(s.trim().toUpperCase()) {
4876 case 'Y': case 'T': out[R][C] = true; break;
4877 case 'N': case 'F': out[R][C] = false; break;
4878 case '': case '?': break;
4879 default: throw new Error("DBF Unrecognized L:|" + s + "|");
4880 } break;
4881 case 'M': /* TODO: handle memo files */
4882 if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
4883 out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
4884 break;
4885 case 'N':
4886 s = s.replace(/\u0000/g,"").trim();
4887 // NOTE: dBASE II interprets " . " as 0
4888 if(s && s != ".") out[R][C] = +s || 0; break;
4889 case '@':
4890 // NOTE: dBASE specs appear to be incorrect
4891 out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400);
4892 break;
4893 case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
4894 case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
4895 case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
4896 case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
4897 /* falls through */
4898 case 'G': case 'P': dd.l += fields[C].len; break;
4899 case '0':
4900 if(fields[C].name === '_NullFlags') break;
4901 /* falls through */
4902 default: throw new Error("DBF Unsupported data type " + fields[C].type);
4903 }
4904 }
4905 }
4906 if(ft != 0x02) if(d.l < d.length && d[d.l++] != 0x1A) throw new Error("DBF EOF Marker missing " + (d.l-1) + " of " + d.length + " " + d[d.l-1].toString(16));
4907 if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
4908 return out;
4909}
4910
4911function dbf_to_sheet(buf, opts) {
4912 var o = opts || {};
4913 if(!o.dateNF) o.dateNF = "yyyymmdd";
4914 return aoa_to_sheet(dbf_to_aoa(buf, o), o);
4915}
4916
4917function dbf_to_workbook(buf, opts) {
4918 try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
4919 catch(e) { if(opts && opts.WTF) throw e; }
4920 return ({SheetNames:[],Sheets:{}});
4921}
4922
4923var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
4924function sheet_to_dbf(ws, opts) {
4925 var o = opts || {};
4926 if(+o.codepage >= 0) set_cp(+o.codepage);
4927 if(o.type == "string") throw new Error("Cannot write DBF to JS string");
4928 var ba = buf_array();
4929 var aoa = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
4930 var headers = aoa[0], data = aoa.slice(1);
4931 var i = 0, j = 0, hcnt = 0, rlen = 1;
4932 for(i = 0; i < headers.length; ++i) {
4933 if(i == null) continue;
4934 ++hcnt;
4935 if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
4936 if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
4937 if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
4938 if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
4939 }
4940 var range = safe_decode_range(ws['!ref']);
4941 var coltypes = [];
4942 for(i = 0; i <= range.e.c - range.s.c; ++i) {
4943 var col = [];
4944 for(j=0; j < data.length; ++j) {
4945 if(data[j][i] != null) col.push(data[j][i]);
4946 }
4947 if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
4948 var guess = '', _guess = '';
4949 for(j = 0; j < col.length; ++j) {
4950 switch(typeof col[j]) {
4951 /* TODO: check if L2 compat is desired */
4952 case 'number': _guess = 'B'; break;
4953 case 'string': _guess = 'C'; break;
4954 case 'boolean': _guess = 'L'; break;
4955 case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
4956 default: _guess = 'C';
4957 }
4958 guess = guess && guess != _guess ? 'C' : _guess;
4959 if(guess == 'C') break;
4960 }
4961 rlen += _RLEN[guess] || 0;
4962 coltypes[i] = guess;
4963 }
4964
4965 var h = ba.next(32);
4966 h.write_shift(4, 0x13021130);
4967 h.write_shift(4, data.length);
4968 h.write_shift(2, 296 + 32 * hcnt);
4969 h.write_shift(2, rlen);
4970 for(i=0; i < 4; ++i) h.write_shift(4, 0);
4971 h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[current_ansi] || 0x03)<<8));
4972
4973 for(i = 0, j = 0; i < headers.length; ++i) {
4974 if(headers[i] == null) continue;
4975 var hf = ba.next(32);
4976 var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
4977 hf.write_shift(1, _f, "sbcs");
4978 hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
4979 hf.write_shift(4, j);
4980 hf.write_shift(1, _RLEN[coltypes[i]] || 0);
4981 hf.write_shift(1, 0);
4982 hf.write_shift(1, 0x02);
4983 hf.write_shift(4, 0);
4984 hf.write_shift(1, 0);
4985 hf.write_shift(4, 0);
4986 hf.write_shift(4, 0);
4987 j += _RLEN[coltypes[i]] || 0;
4988 }
4989
4990 var hb = ba.next(264);
4991 hb.write_shift(4, 0x0000000D);
4992 for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
4993 for(i=0; i < data.length; ++i) {
4994 var rout = ba.next(rlen);
4995 rout.write_shift(1, 0);
4996 for(j=0; j<headers.length; ++j) {
4997 if(headers[j] == null) continue;
4998 switch(coltypes[j]) {
4999 case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
5000 case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
5001 case 'D':
5002 if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
5003 else {
5004 rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
5005 rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
5006 rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
5007 } break;
5008 case 'C':
5009 var _s = String(data[i][j]||"");
5010 rout.write_shift(1, _s, "sbcs");
5011 for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
5012 }
5013 }
5014 // data
5015 }
5016 ba.next(1).write_shift(1, 0x1A);
5017 return ba.end();
5018}
5019 return {
5020 versions: DBF_SUPPORTED_VERSIONS,
5021 to_workbook: dbf_to_workbook,
5022 to_sheet: dbf_to_sheet,
5023 from_sheet: sheet_to_dbf
5024 };
5025})();
5026
5027var SYLK = (function() {
5028 /* TODO: stress test sequences */
5029 var sylk_escapes = ({
5030 AA:'À', BA:'Á', CA:'Â', DA:195, HA:'Ä', JA:197,
5031 AE:'È', BE:'É', CE:'Ê', HE:'Ë',
5032 AI:'Ì', BI:'Í', CI:'Î', HI:'Ï',
5033 AO:'Ò', BO:'Ó', CO:'Ô', DO:213, HO:'Ö',
5034 AU:'Ù', BU:'Ú', CU:'Û', HU:'Ü',
5035 Aa:'à', Ba:'á', Ca:'â', Da:227, Ha:'ä', Ja:229,
5036 Ae:'è', Be:'é', Ce:'ê', He:'ë',
5037 Ai:'ì', Bi:'í', Ci:'î', Hi:'ï',
5038 Ao:'ò', Bo:'ó', Co:'ô', Do:245, Ho:'ö',
5039 Au:'ù', Bu:'ú', Cu:'û', Hu:'ü',
5040 KC:'Ç', Kc:'ç', q:'æ', z:'œ', a:'Æ', j:'Œ',
5041 DN:209, Dn:241, Hy:255,
5042 S:169, c:170, R:174, "B ":180,
50430:176, 1:177, 2:178,
50443:179, 5:181, 6:182,
50457:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
5046 "!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
5047 "+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
5048 });
5049 var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
5050 var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
5051 var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
5052 sylk_escapes["|"] = 254;
5053 /* TODO: find an actual specification */
5054 function sylk_to_aoa(d, opts) {
5055 switch(opts.type) {
5056 case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
5057 case 'binary': return sylk_to_aoa_str(d, opts);
5058 case 'buffer': return sylk_to_aoa_str(has_buf && Buffer.isBuffer(d) ? d.toString('binary') : a2s(d), opts);
5059 case 'array': return sylk_to_aoa_str(cc2str(d), opts);
5060 }
5061 throw new Error("Unrecognized type " + opts.type);
5062 }
5063 function sylk_to_aoa_str(str, opts) {
5064 var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
5065 var formats = [];
5066 var next_cell_format = null;
5067 var sht = {}, rowinfo = [], colinfo = [], cw = [];
5068 var Mval = 0, j;
5069 if(+opts.codepage >= 0) set_cp(+opts.codepage);
5070 for (; ri !== records.length; ++ri) {
5071 Mval = 0;
5072 var rstr=records[ri].trim().replace(/\x1B([\x20-\x2F])([\x30-\x3F])/g, decode_sylk_char).replace(sylk_char_regex, sylk_char_fn);
5073 var record=rstr.replace(/;;/g, "\u0000").split(";").map(function(x) { return x.replace(/\u0000/g, ";"); });
5074 var RT=record[0], val;
5075 if(rstr.length > 0) switch(RT) {
5076 case 'ID': break; /* header */
5077 case 'E': break; /* EOF */
5078 case 'B': break; /* dimensions */
5079 case 'O': break; /* options? */
5080 case 'W': break; /* window? */
5081 case 'P':
5082 if(record[1].charAt(0) == 'P')
5083 formats.push(rstr.slice(3).replace(/;;/g, ";"));
5084 break;
5085 case 'C':
5086 var C_seen_K = false, C_seen_X = false, C_seen_S = false, C_seen_E = false, _R = -1, _C = -1;
5087 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
5088 case 'A': break; // TODO: comment
5089 case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
5090 case 'Y':
5091 R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
5092 for(j = arr.length; j <= R; ++j) arr[j] = [];
5093 break;
5094 case 'K':
5095 val = record[rj].slice(1);
5096 if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
5097 else if(val === 'TRUE') val = true;
5098 else if(val === 'FALSE') val = false;
5099 else if(!isNaN(fuzzynum(val))) {
5100 val = fuzzynum(val);
5101 if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
5102 } else if(!isNaN(fuzzydate(val).getDate())) {
5103 val = parseDate(val);
5104 }
5105 if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
5106 C_seen_K = true;
5107 break;
5108 case 'E':
5109 C_seen_E = true;
5110 var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
5111 arr[R][C] = [arr[R][C], formula];
5112 break;
5113 case 'S':
5114 C_seen_S = true;
5115 arr[R][C] = [arr[R][C], "S5S"];
5116 break;
5117 case 'G': break; // unknown
5118 case 'R': _R = parseInt(record[rj].slice(1))-1; break;
5119 case 'C': _C = parseInt(record[rj].slice(1))-1; break;
5120 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
5121 }
5122 if(C_seen_K) {
5123 if(arr[R][C] && arr[R][C].length == 2) arr[R][C][0] = val;
5124 else arr[R][C] = val;
5125 next_cell_format = null;
5126 }
5127 if(C_seen_S) {
5128 if(C_seen_E) throw new Error("SYLK shared formula cannot have own formula");
5129 var shrbase = _R > -1 && arr[_R][_C];
5130 if(!shrbase || !shrbase[1]) throw new Error("SYLK shared formula cannot find base");
5131 arr[R][C][1] = shift_formula_str(shrbase[1], {r: R - _R, c: C - _C});
5132 }
5133 break;
5134 case 'F':
5135 var F_seen = 0;
5136 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
5137 case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
5138 case 'Y':
5139 R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
5140 for(j = arr.length; j <= R; ++j) arr[j] = [];
5141 break;
5142 case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
5143 case 'F': break; /* ??? */
5144 case 'G': break; /* hide grid */
5145 case 'P':
5146 next_cell_format = formats[parseInt(record[rj].slice(1))];
5147 break;
5148 case 'S': break; /* cell style */
5149 case 'D': break; /* column */
5150 case 'N': break; /* font */
5151 case 'W':
5152 cw = record[rj].slice(1).split(" ");
5153 for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
5154 Mval = parseInt(cw[2], 10);
5155 colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
5156 } break;
5157 case 'C': /* default column format */
5158 C = parseInt(record[rj].slice(1))-1;
5159 if(!colinfo[C]) colinfo[C] = {};
5160 break;
5161 case 'R': /* row properties */
5162 R = parseInt(record[rj].slice(1))-1;
5163 if(!rowinfo[R]) rowinfo[R] = {};
5164 if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
5165 else if(Mval === 0) rowinfo[R].hidden = true;
5166 break;
5167 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
5168 }
5169 if(F_seen < 1) next_cell_format = null; break;
5170 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
5171 }
5172 }
5173 if(rowinfo.length > 0) sht['!rows'] = rowinfo;
5174 if(colinfo.length > 0) sht['!cols'] = colinfo;
5175 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
5176 return [arr, sht];
5177 }
5178
5179 function sylk_to_sheet(d, opts) {
5180 var aoasht = sylk_to_aoa(d, opts);
5181 var aoa = aoasht[0], ws = aoasht[1];
5182 var o = aoa_to_sheet(aoa, opts);
5183 keys(ws).forEach(function(k) { o[k] = ws[k]; });
5184 return o;
5185 }
5186
5187 function sylk_to_workbook(d, opts) { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
5188
5189 function write_ws_cell_sylk(cell, ws, R, C) {
5190 var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
5191 switch(cell.t) {
5192 case 'n':
5193 o += (cell.v||0);
5194 if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
5195 case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
5196 case 'e': o += cell.w || cell.v; break;
5197 case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
5198 case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
5199 }
5200 return o;
5201 }
5202
5203 function write_ws_cols_sylk(out, cols) {
5204 cols.forEach(function(col, i) {
5205 var rec = "F;W" + (i+1) + " " + (i+1) + " ";
5206 if(col.hidden) rec += "0";
5207 else {
5208 if(typeof col.width == 'number' && !col.wpx) col.wpx = width2px(col.width);
5209 if(typeof col.wpx == 'number' && !col.wch) col.wch = px2char(col.wpx);
5210 if(typeof col.wch == 'number') rec += Math.round(col.wch);
5211 }
5212 if(rec.charAt(rec.length - 1) != " ") out.push(rec);
5213 });
5214 }
5215
5216 function write_ws_rows_sylk(out, rows) {
5217 rows.forEach(function(row, i) {
5218 var rec = "F;";
5219 if(row.hidden) rec += "M0;";
5220 else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
5221 else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
5222 if(rec.length > 2) out.push(rec + "R" + (i+1));
5223 });
5224 }
5225
5226 function sheet_to_sylk(ws, opts) {
5227 var preamble = ["ID;PWXL;N;E"], o = [];
5228 var r = safe_decode_range(ws['!ref']), cell;
5229 var dense = Array.isArray(ws);
5230 var RS = "\r\n";
5231
5232 preamble.push("P;PGeneral");
5233 preamble.push("F;P0;DG0G8;M255");
5234 if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
5235 if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
5236
5237 preamble.push("B;Y" + (r.e.r - r.s.r + 1) + ";X" + (r.e.c - r.s.c + 1) + ";D" + [r.s.c,r.s.r,r.e.c,r.e.r].join(" "));
5238 for(var R = r.s.r; R <= r.e.r; ++R) {
5239 for(var C = r.s.c; C <= r.e.c; ++C) {
5240 var coord = encode_cell({r:R,c:C});
5241 cell = dense ? (ws[R]||[])[C]: ws[coord];
5242 if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
5243 o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
5244 }
5245 }
5246 return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
5247 }
5248
5249 return {
5250 to_workbook: sylk_to_workbook,
5251 to_sheet: sylk_to_sheet,
5252 from_sheet: sheet_to_sylk
5253 };
5254})();
5255
5256var DIF = (function() {
5257 function dif_to_aoa(d, opts) {
5258 switch(opts.type) {
5259 case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
5260 case 'binary': return dif_to_aoa_str(d, opts);
5261 case 'buffer': return dif_to_aoa_str(has_buf && Buffer.isBuffer(d) ? d.toString('binary') : a2s(d), opts);
5262 case 'array': return dif_to_aoa_str(cc2str(d), opts);
5263 }
5264 throw new Error("Unrecognized type " + opts.type);
5265 }
5266 function dif_to_aoa_str(str, opts) {
5267 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
5268 for (; ri !== records.length; ++ri) {
5269 if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
5270 if (R < 0) continue;
5271 var metadata = records[ri].trim().split(",");
5272 var type = metadata[0], value = metadata[1];
5273 ++ri;
5274 var data = records[ri] || "";
5275 while(((data.match(/["]/g)||[]).length & 1) && ri < records.length - 1) data += "\n" + records[++ri];
5276 data = data.trim();
5277 switch (+type) {
5278 case -1:
5279 if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
5280 else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
5281 break;
5282 case 0:
5283 if(data === 'TRUE') arr[R][C] = true;
5284 else if(data === 'FALSE') arr[R][C] = false;
5285 else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
5286 else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
5287 else arr[R][C] = value;
5288 ++C; break;
5289 case 1:
5290 data = data.slice(1,data.length-1);
5291 data = data.replace(/""/g, '"');
5292 if(DIF_XL && data && data.match(/^=".*"$/)) data = data.slice(2, -1);
5293 arr[R][C++] = data !== '' ? data : null;
5294 break;
5295 }
5296 if (data === 'EOD') break;
5297 }
5298 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
5299 return arr;
5300 }
5301
5302 function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
5303 function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
5304
5305 var sheet_to_dif = (function() {
5306 var push_field = function pf(o, topic, v, n, s) {
5307 o.push(topic);
5308 o.push(v + "," + n);
5309 o.push('"' + s.replace(/"/g,'""') + '"');
5310 };
5311 var push_value = function po(o, type, v, s) {
5312 o.push(type + "," + v);
5313 o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
5314 };
5315 return function sheet_to_dif(ws) {
5316 var o = [];
5317 var r = safe_decode_range(ws['!ref']), cell;
5318 var dense = Array.isArray(ws);
5319 push_field(o, "TABLE", 0, 1, "sheetjs");
5320 push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
5321 push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
5322 push_field(o, "DATA", 0, 0,"");
5323 for(var R = r.s.r; R <= r.e.r; ++R) {
5324 push_value(o, -1, 0, "BOT");
5325 for(var C = r.s.c; C <= r.e.c; ++C) {
5326 var coord = encode_cell({r:R,c:C});
5327 cell = dense ? (ws[R]||[])[C] : ws[coord];
5328 if(!cell) { push_value(o, 1, 0, ""); continue;}
5329 switch(cell.t) {
5330 case 'n':
5331 var val = DIF_XL ? cell.w : cell.v;
5332 if(!val && cell.v != null) val = cell.v;
5333 if(val == null) {
5334 if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
5335 else push_value(o, 1, 0, "");
5336 }
5337 else push_value(o, 0, val, "V");
5338 break;
5339 case 'b':
5340 push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
5341 break;
5342 case 's':
5343 push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
5344 break;
5345 case 'd':
5346 if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
5347 if(DIF_XL) push_value(o, 0, cell.w, "V");
5348 else push_value(o, 1, 0, cell.w);
5349 break;
5350 default: push_value(o, 1, 0, "");
5351 }
5352 }
5353 }
5354 push_value(o, -1, 0, "EOD");
5355 var RS = "\r\n";
5356 var oo = o.join(RS);
5357 //while((oo.length & 0x7F) != 0) oo += "\0";
5358 return oo;
5359 };
5360 })();
5361 return {
5362 to_workbook: dif_to_workbook,
5363 to_sheet: dif_to_sheet,
5364 from_sheet: sheet_to_dif
5365 };
5366})();
5367
5368var ETH = (function() {
5369 function decode(s) { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
5370 function encode(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
5371
5372 function eth_to_aoa(str, opts) {
5373 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
5374 for (; ri !== records.length; ++ri) {
5375 var record = records[ri].trim().split(":");
5376 if(record[0] !== 'cell') continue;
5377 var addr = decode_cell(record[1]);
5378 if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
5379 R = addr.r; C = addr.c;
5380 switch(record[2]) {
5381 case 't': arr[R][C] = decode(record[3]); break;
5382 case 'v': arr[R][C] = +record[3]; break;
5383 case 'vtf': var _f = record[record.length - 1];
5384 /* falls through */
5385 case 'vtc':
5386 switch(record[3]) {
5387 case 'nl': arr[R][C] = +record[4] ? true : false; break;
5388 default: arr[R][C] = +record[4]; break;
5389 }
5390 if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
5391 }
5392 }
5393 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
5394 return arr;
5395 }
5396
5397 function eth_to_sheet(d, opts) { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
5398 function eth_to_workbook(d, opts) { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
5399
5400 var header = [
5401 "socialcalc:version:1.5",
5402 "MIME-Version: 1.0",
5403 "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
5404 ].join("\n");
5405
5406 var sep = [
5407 "--SocialCalcSpreadsheetControlSave",
5408 "Content-type: text/plain; charset=UTF-8"
5409 ].join("\n") + "\n";
5410
5411 /* TODO: the other parts */
5412 var meta = [
5413 "# SocialCalc Spreadsheet Control Save",
5414 "part:sheet"
5415 ].join("\n");
5416
5417 var end = "--SocialCalcSpreadsheetControlSave--";
5418
5419 function sheet_to_eth_data(ws) {
5420 if(!ws || !ws['!ref']) return "";
5421 var o = [], oo = [], cell, coord = "";
5422 var r = decode_range(ws['!ref']);
5423 var dense = Array.isArray(ws);
5424 for(var R = r.s.r; R <= r.e.r; ++R) {
5425 for(var C = r.s.c; C <= r.e.c; ++C) {
5426 coord = encode_cell({r:R,c:C});
5427 cell = dense ? (ws[R]||[])[C] : ws[coord];
5428 if(!cell || cell.v == null || cell.t === 'z') continue;
5429 oo = ["cell", coord, 't'];
5430 switch(cell.t) {
5431 case 's': case 'str': oo.push(encode(cell.v)); break;
5432 case 'n':
5433 if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
5434 else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
5435 break;
5436 case 'b':
5437 oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
5438 oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
5439 break;
5440 case 'd':
5441 var t = datenum(parseDate(cell.v));
5442 oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
5443 oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
5444 break;
5445 case 'e': continue;
5446 }
5447 o.push(oo.join(":"));
5448 }
5449 }
5450 o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
5451 o.push("valueformat:1:text-wiki");
5452 //o.push("copiedfrom:" + ws['!ref']); // clipboard only
5453 return o.join("\n");
5454 }
5455
5456 function sheet_to_eth(ws) {
5457 return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
5458 // return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
5459 }
5460
5461 return {
5462 to_workbook: eth_to_workbook,
5463 to_sheet: eth_to_sheet,
5464 from_sheet: sheet_to_eth
5465 };
5466})();
5467
5468var PRN = (function() {
5469 function set_text_arr(data, arr, R, C, o) {
5470 if(o.raw) arr[R][C] = data;
5471 else if(data === ""){/* empty */}
5472 else if(data === 'TRUE') arr[R][C] = true;
5473 else if(data === 'FALSE') arr[R][C] = false;
5474 else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
5475 else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
5476 else arr[R][C] = data;
5477 }
5478
5479 function prn_to_aoa_str(f, opts) {
5480 var o = opts || {};
5481 var arr = ([]);
5482 if(!f || f.length === 0) return arr;
5483 var lines = f.split(/[\r\n]/);
5484 var L = lines.length - 1;
5485 while(L >= 0 && lines[L].length === 0) --L;
5486 var start = 10, idx = 0;
5487 var R = 0;
5488 for(; R <= L; ++R) {
5489 idx = lines[R].indexOf(" ");
5490 if(idx == -1) idx = lines[R].length; else idx++;
5491 start = Math.max(start, idx);
5492 }
5493 for(R = 0; R <= L; ++R) {
5494 arr[R] = [];
5495 /* TODO: confirm that widths are always 10 */
5496 var C = 0;
5497 set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
5498 for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
5499 set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
5500 }
5501 if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
5502 return arr;
5503 }
5504
5505 // List of accepted CSV separators
5506 var guess_seps = {
55070x2C: ',',
55080x09: "\t",
55090x3B: ';',
55100x7C: '|'
5511 };
5512
5513 // CSV separator weights to be used in case of equal numbers
5514 var guess_sep_weights = {
55150x2C: 3,
55160x09: 2,
55170x3B: 1,
55180x7C: 0
5519 };
5520
5521 function guess_sep(str) {
5522 var cnt = {}, instr = false, end = 0, cc = 0;
5523 for(;end < str.length;++end) {
5524 if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
5525 else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
5526 }
5527
5528 cc = [];
5529 for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
5530 cc.push([ cnt[end], end ]);
5531 }
5532
5533 if ( !cc.length ) {
5534 cnt = guess_sep_weights;
5535 for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
5536 cc.push([ cnt[end], end ]);
5537 }
5538 }
5539
5540 cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
5541
5542 return guess_seps[cc.pop()[1]] || 0x2C;
5543 }
5544
5545 function dsv_to_sheet_str(str, opts) {
5546 var o = opts || {};
5547 var sep = "";
5548 if(DENSE != null && o.dense == null) o.dense = DENSE;
5549 var ws = o.dense ? ([]) : ({});
5550 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
5551
5552 if(str.slice(0,4) == "sep=") {
5553 // If the line ends in \r\n
5554 if(str.charCodeAt(5) == 13 && str.charCodeAt(6) == 10 ) {
5555 sep = str.charAt(4); str = str.slice(7);
5556 }
5557 // If line ends in \r OR \n
5558 else if(str.charCodeAt(5) == 13 || str.charCodeAt(5) == 10 ) {
5559 sep = str.charAt(4); str = str.slice(6);
5560 }
5561 else sep = guess_sep(str.slice(0,1024));
5562 }
5563 else if(o && o.FS) sep = o.FS;
5564 else sep = guess_sep(str.slice(0,1024));
5565 var R = 0, C = 0, v = 0;
5566 var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0, startcc=str.charCodeAt(0);
5567 str = str.replace(/\r\n/mg, "\n");
5568 var _re = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
5569 function finish_cell() {
5570 var s = str.slice(start, end);
5571 var cell = ({});
5572 if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
5573 if(s.length === 0) cell.t = 'z';
5574 else if(o.raw) { cell.t = 's'; cell.v = s; }
5575 else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
5576 else if(s.charCodeAt(0) == 0x3D) {
5577 if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
5578 else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
5579 else { cell.t = 's'; cell.v = s; } }
5580 else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
5581 else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
5582 else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
5583 else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
5584 cell.z = o.dateNF || SSF._table[14];
5585 var k = 0;
5586 if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
5587 if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
5588 else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
5589 if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
5590 if(!o.cellNF) delete cell.z;
5591 } else {
5592 cell.t = 's';
5593 cell.v = s;
5594 }
5595 if(cell.t == 'z'){}
5596 else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
5597 else ws[encode_cell({c:C,r:R})] = cell;
5598 start = end+1; startcc = str.charCodeAt(start);
5599 if(range.e.c < C) range.e.c = C;
5600 if(range.e.r < R) range.e.r = R;
5601 if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
5602 }
5603 outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
5604 case 0x22: if(startcc === 0x22) instr = !instr; break;
5605 case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
5606 default: break;
5607 }
5608 if(end - start > 0) finish_cell();
5609
5610 ws['!ref'] = encode_range(range);
5611 return ws;
5612 }
5613
5614 function prn_to_sheet_str(str, opts) {
5615 if(!(opts && opts.PRN)) return dsv_to_sheet_str(str, opts);
5616 if(opts.FS) return dsv_to_sheet_str(str, opts);
5617 if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
5618 if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
5619 return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
5620 }
5621
5622 function prn_to_sheet(d, opts) {
5623 var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
5624 switch(opts.type) {
5625 case 'base64': str = Base64.decode(d); break;
5626 case 'binary': str = d; break;
5627 case 'buffer':
5628 if(opts.codepage == 65001) str = d.toString('utf8'); // TODO: test if buf
5629 else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
5630 else str = has_buf && Buffer.isBuffer(d) ? d.toString('binary') : a2s(d);
5631 break;
5632 case 'array': str = cc2str(d); break;
5633 case 'string': str = d; break;
5634 default: throw new Error("Unrecognized type " + opts.type);
5635 }
5636 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
5637 else if(opts.type != 'string' && opts.codepage == 65001) str = utf8read(str);
5638 else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage) str = cptable.utils.decode(opts.codepage, cptable.utils.encode(28591,str));
5639 if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
5640 return prn_to_sheet_str(str, opts);
5641 }
5642
5643 function prn_to_workbook(d, opts) { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
5644
5645 function sheet_to_prn(ws) {
5646 var o = [];
5647 var r = safe_decode_range(ws['!ref']), cell;
5648 var dense = Array.isArray(ws);
5649 for(var R = r.s.r; R <= r.e.r; ++R) {
5650 var oo = [];
5651 for(var C = r.s.c; C <= r.e.c; ++C) {
5652 var coord = encode_cell({r:R,c:C});
5653 cell = dense ? (ws[R]||[])[C] : ws[coord];
5654 if(!cell || cell.v == null) { oo.push(" "); continue; }
5655 var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
5656 while(w.length < 10) w += " ";
5657 oo.push(w + (C === 0 ? " " : ""));
5658 }
5659 o.push(oo.join(""));
5660 }
5661 return o.join("\n");
5662 }
5663
5664 return {
5665 to_workbook: prn_to_workbook,
5666 to_sheet: prn_to_sheet,
5667 from_sheet: sheet_to_prn
5668 };
5669})();
5670
5671/* Excel defaults to SYLK but warns if data is not valid */
5672function read_wb_ID(d, opts) {
5673 var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
5674 try {
5675 var out = SYLK.to_workbook(d, o);
5676 o.WTF = OLD_WTF;
5677 return out;
5678 } catch(e) {
5679 o.WTF = OLD_WTF;
5680 if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
5681 return PRN.to_workbook(d, opts);
5682 }
5683}
5684
5685/* 18.4.7 rPr CT_RPrElt */
5686function parse_rpr(rpr) {
5687 var font = {}, m = rpr.match(tagregex), i = 0;
5688 var pass = false;
5689 if(m) for(;i!=m.length; ++i) {
5690 var y = parsexmltag(m[i]);
5691 switch(y[0].replace(/\w*:/g,"")) {
5692 /* 18.8.12 condense CT_BooleanProperty */
5693 /* ** not required . */
5694 case '<condense': break;
5695 /* 18.8.17 extend CT_BooleanProperty */
5696 /* ** not required . */
5697 case '<extend': break;
5698 /* 18.8.36 shadow CT_BooleanProperty */
5699 /* ** not required . */
5700 case '<shadow':
5701 if(!y.val) break;
5702 /* falls through */
5703 case '<shadow>':
5704 case '<shadow/>': font.shadow = 1; break;
5705 case '</shadow>': break;
5706
5707 /* 18.4.1 charset CT_IntProperty TODO */
5708 case '<charset':
5709 if(y.val == '1') break;
5710 font.cp = CS2CP[parseInt(y.val, 10)];
5711 break;
5712
5713 /* 18.4.2 outline CT_BooleanProperty TODO */
5714 case '<outline':
5715 if(!y.val) break;
5716 /* falls through */
5717 case '<outline>':
5718 case '<outline/>': font.outline = 1; break;
5719 case '</outline>': break;
5720
5721 /* 18.4.5 rFont CT_FontName */
5722 case '<rFont': font.name = y.val; break;
5723
5724 /* 18.4.11 sz CT_FontSize */
5725 case '<sz': font.sz = y.val; break;
5726
5727 /* 18.4.10 strike CT_BooleanProperty */
5728 case '<strike':
5729 if(!y.val) break;
5730 /* falls through */
5731 case '<strike>':
5732 case '<strike/>': font.strike = 1; break;
5733 case '</strike>': break;
5734
5735 /* 18.4.13 u CT_UnderlineProperty */
5736 case '<u':
5737 if(!y.val) break;
5738 switch(y.val) {
5739 case 'double': font.uval = "double"; break;
5740 case 'singleAccounting': font.uval = "single-accounting"; break;
5741 case 'doubleAccounting': font.uval = "double-accounting"; break;
5742 }
5743 /* falls through */
5744 case '<u>':
5745 case '<u/>': font.u = 1; break;
5746 case '</u>': break;
5747
5748 /* 18.8.2 b */
5749 case '<b':
5750 if(y.val == '0') break;
5751 /* falls through */
5752 case '<b>':
5753 case '<b/>': font.b = 1; break;
5754 case '</b>': break;
5755
5756 /* 18.8.26 i */
5757 case '<i':
5758 if(y.val == '0') break;
5759 /* falls through */
5760 case '<i>':
5761 case '<i/>': font.i = 1; break;
5762 case '</i>': break;
5763
5764 /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
5765 case '<color':
5766 if(y.rgb) font.color = y.rgb.slice(2,8);
5767 break;
5768
5769 /* 18.8.18 family ST_FontFamily */
5770 case '<family': font.family = y.val; break;
5771
5772 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
5773 case '<vertAlign': font.valign = y.val; break;
5774
5775 /* 18.8.35 scheme CT_FontScheme TODO */
5776 case '<scheme': break;
5777
5778 /* 18.2.10 extLst CT_ExtensionList ? */
5779 case '<extLst': case '<extLst>': case '</extLst>': break;
5780 case '<ext': pass = true; break;
5781 case '</ext>': pass = false; break;
5782 default:
5783 if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
5784 }
5785 }
5786 return font;
5787}
5788
5789var parse_rs = (function() {
5790 var tregex = matchtag("t"), rpregex = matchtag("rPr");
5791 /* 18.4.4 r CT_RElt */
5792 function parse_r(r) {
5793 /* 18.4.12 t ST_Xstring */
5794 var t = r.match(tregex)/*, cp = 65001*/;
5795 if(!t) return {t:"s", v:""};
5796
5797 var o = ({t:'s', v:unescapexml(t[1])});
5798 var rpr = r.match(rpregex);
5799 if(rpr) o.s = parse_rpr(rpr[1]);
5800 return o;
5801 }
5802 var rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/;
5803 return function parse_rs(rs) {
5804 return rs.replace(rregex,"").split(rend).map(parse_r).filter(function(r) { return r.v; });
5805 };
5806})();
5807
5808
5809/* Parse a list of <r> tags */
5810var rs_to_html = (function parse_rs_factory() {
5811 var nlregex = /(\r\n|\n)/g;
5812 function parse_rpr2(font, intro, outro) {
5813 var style = [];
5814
5815 if(font.u) style.push("text-decoration: underline;");
5816 if(font.uval) style.push("text-underline-style:" + font.uval + ";");
5817 if(font.sz) style.push("font-size:" + font.sz + "pt;");
5818 if(font.outline) style.push("text-effect: outline;");
5819 if(font.shadow) style.push("text-shadow: auto;");
5820 intro.push('<span style="' + style.join("") + '">');
5821
5822 if(font.b) { intro.push("<b>"); outro.push("</b>"); }
5823 if(font.i) { intro.push("<i>"); outro.push("</i>"); }
5824 if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
5825
5826 var align = font.valign || "";
5827 if(align == "superscript" || align == "super") align = "sup";
5828 else if(align == "subscript") align = "sub";
5829 if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
5830
5831 outro.push("</span>");
5832 return font;
5833 }
5834
5835 /* 18.4.4 r CT_RElt */
5836 function r_to_html(r) {
5837 var terms = [[],r.v,[]];
5838 if(!r.v) return "";
5839
5840 if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
5841
5842 return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
5843 }
5844
5845 return function parse_rs(rs) {
5846 return rs.map(r_to_html).join("");
5847 };
5848})();
5849
5850/* 18.4.8 si CT_Rst */
5851var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
5852var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
5853function parse_si(x, opts) {
5854 var html = opts ? opts.cellHTML : true;
5855 var z = {};
5856 if(!x) return { t: "" };
5857 //var y;
5858 /* 18.4.12 t ST_Xstring (Plaintext String) */
5859 // TODO: is whitespace actually valid here?
5860 if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
5861 z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
5862 z.r = utf8read(x);
5863 if(html) z.h = escapehtml(z.t);
5864 }
5865 /* 18.4.4 r CT_RElt (Rich Text Run) */
5866 else if((/*y = */x.match(sirregex))) {
5867 z.r = utf8read(x);
5868 z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
5869 if(html) z.h = rs_to_html(parse_rs(z.r));
5870 }
5871 /* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
5872 /* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
5873 return z;
5874}
5875
5876/* 18.4 Shared String Table */
5877var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
5878var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
5879var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
5880function parse_sst_xml(data, opts) {
5881 var s = ([]), ss = "";
5882 if(!data) return s;
5883 /* 18.4.9 sst CT_Sst */
5884 var sst = data.match(sstr0);
5885 if(sst) {
5886 ss = sst[2].replace(sstr1,"").split(sstr2);
5887 for(var i = 0; i != ss.length; ++i) {
5888 var o = parse_si(ss[i].trim(), opts);
5889 if(o != null) s[s.length] = o;
5890 }
5891 sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
5892 }
5893 return s;
5894}
5895
5896RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
5897var straywsregex = /^\s|\s$|[\t\n\r]/;
5898function write_sst_xml(sst, opts) {
5899 if(!opts.bookSST) return "";
5900 var o = [XML_HEADER];
5901 o[o.length] = (writextag('sst', null, {
5902 xmlns: XMLNS.main[0],
5903 count: sst.Count,
5904 uniqueCount: sst.Unique
5905 }));
5906 for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
5907 var s = sst[i];
5908 var sitag = "<si>";
5909 if(s.r) sitag += s.r;
5910 else {
5911 sitag += "<t";
5912 if(!s.t) s.t = "";
5913 if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
5914 sitag += ">" + escapexml(s.t) + "</t>";
5915 }
5916 sitag += "</si>";
5917 o[o.length] = (sitag);
5918 }
5919 if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
5920 return o.join("");
5921}
5922function hex2RGB(h) {
5923 var o = h.slice(h[0]==="#"?1:0).slice(0,6);
5924 return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
5925}
5926function rgb2Hex(rgb) {
5927 for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
5928 return o.toString(16).toUpperCase().slice(1);
5929}
5930
5931function rgb2HSL(rgb) {
5932 var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
5933 var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
5934 if(C === 0) return [0, 0, R];
5935
5936 var H6 = 0, S = 0, L2 = (M + m);
5937 S = C / (L2 > 1 ? 2 - L2 : L2);
5938 switch(M){
5939 case R: H6 = ((G - B) / C + 6)%6; break;
5940 case G: H6 = ((B - R) / C + 2); break;
5941 case B: H6 = ((R - G) / C + 4); break;
5942 }
5943 return [H6 / 6, S, L2 / 2];
5944}
5945
5946function hsl2RGB(hsl){
5947 var H = hsl[0], S = hsl[1], L = hsl[2];
5948 var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
5949 var rgb = [m,m,m], h6 = 6*H;
5950
5951 var X;
5952 if(S !== 0) switch(h6|0) {
5953 case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
5954 case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
5955 case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
5956 case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
5957 case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
5958 case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
5959 }
5960 for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
5961 return rgb;
5962}
5963
5964/* 18.8.3 bgColor tint algorithm */
5965function rgb_tint(hex, tint) {
5966 if(tint === 0) return hex;
5967 var hsl = rgb2HSL(hex2RGB(hex));
5968 if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
5969 else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
5970 return rgb2Hex(hsl2RGB(hsl));
5971}
5972
5973/* 18.3.1.13 width calculations */
5974/* [MS-OI29500] 2.1.595 Column Width & Formatting */
5975var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
5976function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
5977function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
5978function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
5979//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
5980//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
5981function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
5982/* XLSX/XLSB/XLS specify width in units of MDW */
5983function find_mdw_colw(collw) {
5984 var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
5985 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; }
5986 MDW = _MDW;
5987}
5988/* XLML specifies width in terms of pixels */
5989/*function find_mdw_wpx(wpx) {
5990 var delta = Infinity, guess = 0, _MDW = MIN_MDW;
5991 for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
5992 guess = char2width_(px2char_(wpx))*256;
5993 guess = (guess) % 1;
5994 if(guess > 0.5) guess--;
5995 if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
5996 }
5997 MDW = _MDW;
5998}*/
5999
6000function process_col(coll) {
6001 if(coll.width) {
6002 coll.wpx = width2px(coll.width);
6003 coll.wch = px2char(coll.wpx);
6004 coll.MDW = MDW;
6005 } else if(coll.wpx) {
6006 coll.wch = px2char(coll.wpx);
6007 coll.width = char2width(coll.wch);
6008 coll.MDW = MDW;
6009 } else if(typeof coll.wch == 'number') {
6010 coll.width = char2width(coll.wch);
6011 coll.wpx = width2px(coll.width);
6012 coll.MDW = MDW;
6013 }
6014 if(coll.customWidth) delete coll.customWidth;
6015}
6016
6017var DEF_PPI = 96, PPI = DEF_PPI;
6018function px2pt(px) { return px * 96 / PPI; }
6019function pt2px(pt) { return pt * PPI / 96; }
6020
6021/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
6022var XLMLPatternTypeMap = {
6023 "None": "none",
6024 "Solid": "solid",
6025 "Gray50": "mediumGray",
6026 "Gray75": "darkGray",
6027 "Gray25": "lightGray",
6028 "HorzStripe": "darkHorizontal",
6029 "VertStripe": "darkVertical",
6030 "ReverseDiagStripe": "darkDown",
6031 "DiagStripe": "darkUp",
6032 "DiagCross": "darkGrid",
6033 "ThickDiagCross": "darkTrellis",
6034 "ThinHorzStripe": "lightHorizontal",
6035 "ThinVertStripe": "lightVertical",
6036 "ThinReverseDiagStripe": "lightDown",
6037 "ThinHorzCross": "lightGrid"
6038};
6039
6040/* 18.8.5 borders CT_Borders */
6041function parse_borders(t, styles, themes, opts) {
6042 styles.Borders = [];
6043 var border = {};
6044 var pass = false;
6045 (t[0].match(tagregex)||[]).forEach(function(x) {
6046 var y = parsexmltag(x);
6047 switch(strip_ns(y[0])) {
6048 case '<borders': case '<borders>': case '</borders>': break;
6049
6050 /* 18.8.4 border CT_Border */
6051 case '<border': case '<border>': case '<border/>':
6052 border = {};
6053 if(y.diagonalUp) border.diagonalUp = parsexmlbool(y.diagonalUp);
6054 if(y.diagonalDown) border.diagonalDown = parsexmlbool(y.diagonalDown);
6055 styles.Borders.push(border);
6056 break;
6057 case '</border>': break;
6058
6059 /* note: not in spec, appears to be CT_BorderPr */
6060 case '<left/>': break;
6061 case '<left': case '<left>': break;
6062 case '</left>': break;
6063
6064 /* note: not in spec, appears to be CT_BorderPr */
6065 case '<right/>': break;
6066 case '<right': case '<right>': break;
6067 case '</right>': break;
6068
6069 /* 18.8.43 top CT_BorderPr */
6070 case '<top/>': break;
6071 case '<top': case '<top>': break;
6072 case '</top>': break;
6073
6074 /* 18.8.6 bottom CT_BorderPr */
6075 case '<bottom/>': break;
6076 case '<bottom': case '<bottom>': break;
6077 case '</bottom>': break;
6078
6079 /* 18.8.13 diagonal CT_BorderPr */
6080 case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
6081 case '</diagonal>': break;
6082
6083 /* 18.8.25 horizontal CT_BorderPr */
6084 case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
6085 case '</horizontal>': break;
6086
6087 /* 18.8.44 vertical CT_BorderPr */
6088 case '<vertical': case '<vertical>': case '<vertical/>': break;
6089 case '</vertical>': break;
6090
6091 /* 18.8.37 start CT_BorderPr */
6092 case '<start': case '<start>': case '<start/>': break;
6093 case '</start>': break;
6094
6095 /* 18.8.16 end CT_BorderPr */
6096 case '<end': case '<end>': case '<end/>': break;
6097 case '</end>': break;
6098
6099 /* 18.8.? color CT_Color */
6100 case '<color': case '<color>':
6101 break;
6102 case '<color/>': case '</color>': break;
6103
6104 /* 18.2.10 extLst CT_ExtensionList ? */
6105 case '<extLst': case '<extLst>': case '</extLst>': break;
6106 case '<ext': pass = true; break;
6107 case '</ext>': pass = false; break;
6108 default: if(opts && opts.WTF) {
6109 if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
6110 }
6111 }
6112 });
6113}
6114
6115/* 18.8.21 fills CT_Fills */
6116function parse_fills(t, styles, themes, opts) {
6117 styles.Fills = [];
6118 var fill = {};
6119 var pass = false;
6120 (t[0].match(tagregex)||[]).forEach(function(x) {
6121 var y = parsexmltag(x);
6122 switch(strip_ns(y[0])) {
6123 case '<fills': case '<fills>': case '</fills>': break;
6124
6125 /* 18.8.20 fill CT_Fill */
6126 case '<fill>': case '<fill': case '<fill/>':
6127 fill = {}; styles.Fills.push(fill); break;
6128 case '</fill>': break;
6129
6130 /* 18.8.24 gradientFill CT_GradientFill */
6131 case '<gradientFill>': break;
6132 case '<gradientFill':
6133 case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
6134
6135 /* 18.8.32 patternFill CT_PatternFill */
6136 case '<patternFill': case '<patternFill>':
6137 if(y.patternType) fill.patternType = y.patternType;
6138 break;
6139 case '<patternFill/>': case '</patternFill>': break;
6140
6141 /* 18.8.3 bgColor CT_Color */
6142 case '<bgColor':
6143 if(!fill.bgColor) fill.bgColor = {};
6144 if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
6145 if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
6146 if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
6147 /* Excel uses ARGB strings */
6148 if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
6149 break;
6150 case '<bgColor/>': case '</bgColor>': break;
6151
6152 /* 18.8.19 fgColor CT_Color */
6153 case '<fgColor':
6154 if(!fill.fgColor) fill.fgColor = {};
6155 if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
6156 if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
6157 /* Excel uses ARGB strings */
6158 if(y.rgb != null) fill.fgColor.rgb = y.rgb.slice(-6);
6159 break;
6160 case '<fgColor/>': case '</fgColor>': break;
6161
6162 /* 18.8.38 stop CT_GradientStop */
6163 case '<stop': case '<stop/>': break;
6164 case '</stop>': break;
6165
6166 /* 18.8.? color CT_Color */
6167 case '<color': case '<color/>': break;
6168 case '</color>': break;
6169
6170 /* 18.2.10 extLst CT_ExtensionList ? */
6171 case '<extLst': case '<extLst>': case '</extLst>': break;
6172 case '<ext': pass = true; break;
6173 case '</ext>': pass = false; break;
6174 default: if(opts && opts.WTF) {
6175 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
6176 }
6177 }
6178 });
6179}
6180
6181/* 18.8.23 fonts CT_Fonts */
6182function parse_fonts(t, styles, themes, opts) {
6183 styles.Fonts = [];
6184 var font = {};
6185 var pass = false;
6186 (t[0].match(tagregex)||[]).forEach(function(x) {
6187 var y = parsexmltag(x);
6188 switch(strip_ns(y[0])) {
6189 case '<fonts': case '<fonts>': case '</fonts>': break;
6190
6191 /* 18.8.22 font CT_Font */
6192 case '<font': case '<font>': break;
6193 case '</font>': case '<font/>':
6194 styles.Fonts.push(font);
6195 font = {};
6196 break;
6197
6198 /* 18.8.29 name CT_FontName */
6199 case '<name': if(y.val) font.name = utf8read(y.val); break;
6200 case '<name/>': case '</name>': break;
6201
6202 /* 18.8.2 b CT_BooleanProperty */
6203 case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
6204 case '<b/>': font.bold = 1; break;
6205
6206 /* 18.8.26 i CT_BooleanProperty */
6207 case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
6208 case '<i/>': font.italic = 1; break;
6209
6210 /* 18.4.13 u CT_UnderlineProperty */
6211 case '<u':
6212 switch(y.val) {
6213 case "none": font.underline = 0x00; break;
6214 case "single": font.underline = 0x01; break;
6215 case "double": font.underline = 0x02; break;
6216 case "singleAccounting": font.underline = 0x21; break;
6217 case "doubleAccounting": font.underline = 0x22; break;
6218 } break;
6219 case '<u/>': font.underline = 1; break;
6220
6221 /* 18.4.10 strike CT_BooleanProperty */
6222 case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
6223 case '<strike/>': font.strike = 1; break;
6224
6225 /* 18.4.2 outline CT_BooleanProperty */
6226 case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
6227 case '<outline/>': font.outline = 1; break;
6228
6229 /* 18.8.36 shadow CT_BooleanProperty */
6230 case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
6231 case '<shadow/>': font.shadow = 1; break;
6232
6233 /* 18.8.12 condense CT_BooleanProperty */
6234 case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
6235 case '<condense/>': font.condense = 1; break;
6236
6237 /* 18.8.17 extend CT_BooleanProperty */
6238 case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
6239 case '<extend/>': font.extend = 1; break;
6240
6241 /* 18.4.11 sz CT_FontSize */
6242 case '<sz': if(y.val) font.sz = +y.val; break;
6243 case '<sz/>': case '</sz>': break;
6244
6245 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
6246 case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
6247 case '<vertAlign/>': case '</vertAlign>': break;
6248
6249 /* 18.8.18 family CT_FontFamily */
6250 case '<family': if(y.val) font.family = parseInt(y.val,10); break;
6251 case '<family/>': case '</family>': break;
6252
6253 /* 18.8.35 scheme CT_FontScheme */
6254 case '<scheme': if(y.val) font.scheme = y.val; break;
6255 case '<scheme/>': case '</scheme>': break;
6256
6257 /* 18.4.1 charset CT_IntProperty */
6258 case '<charset':
6259 if(y.val == '1') break;
6260 y.codepage = CS2CP[parseInt(y.val, 10)];
6261 break;
6262
6263 /* 18.?.? color CT_Color */
6264 case '<color':
6265 if(!font.color) font.color = {};
6266 if(y.auto) font.color.auto = parsexmlbool(y.auto);
6267
6268 if(y.rgb) font.color.rgb = y.rgb.slice(-6);
6269 else if(y.indexed) {
6270 font.color.index = parseInt(y.indexed, 10);
6271 var icv = XLSIcv[font.color.index];
6272 if(font.color.index == 81) icv = XLSIcv[1];
6273 if(!icv) icv = XLSIcv[1]; //throw new Error(x); // note: 206 is valid
6274 font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
6275 } else if(y.theme) {
6276 font.color.theme = parseInt(y.theme, 10);
6277 if(y.tint) font.color.tint = parseFloat(y.tint);
6278 if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
6279 font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
6280 }
6281 }
6282
6283 break;
6284 case '<color/>': case '</color>': break;
6285
6286 /* note: sometimes mc:AlternateContent appears bare */
6287 case '<AlternateContent': pass = true; break;
6288 case '</AlternateContent>': pass = false; break;
6289
6290 /* 18.2.10 extLst CT_ExtensionList ? */
6291 case '<extLst': case '<extLst>': case '</extLst>': break;
6292 case '<ext': pass = true; break;
6293 case '</ext>': pass = false; break;
6294 default: if(opts && opts.WTF) {
6295 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
6296 }
6297 }
6298 });
6299}
6300
6301/* 18.8.31 numFmts CT_NumFmts */
6302function parse_numFmts(t, styles, opts) {
6303 styles.NumberFmt = [];
6304 var k/*Array<number>*/ = (keys(SSF._table));
6305 for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
6306 var m = t[0].match(tagregex);
6307 if(!m) return;
6308 for(i=0; i < m.length; ++i) {
6309 var y = parsexmltag(m[i]);
6310 switch(strip_ns(y[0])) {
6311 case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
6312 case '<numFmt': {
6313 var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
6314 styles.NumberFmt[j] = f;
6315 if(j>0) {
6316 if(j > 0x188) {
6317 for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
6318 styles.NumberFmt[j] = f;
6319 }
6320 SSF.load(f,j);
6321 }
6322 } break;
6323 case '</numFmt>': break;
6324 default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
6325 }
6326 }
6327}
6328
6329function write_numFmts(NF) {
6330 var o = ["<numFmts>"];
6331 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
6332 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])}));
6333 });
6334 if(o.length === 1) return "";
6335 o[o.length] = ("</numFmts>");
6336 o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
6337 return o.join("");
6338}
6339
6340/* 18.8.10 cellXfs CT_CellXfs */
6341var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
6342var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
6343function parse_cellXfs(t, styles, opts) {
6344 styles.CellXf = [];
6345 var xf;
6346 var pass = false;
6347 (t[0].match(tagregex)||[]).forEach(function(x) {
6348 var y = parsexmltag(x), i = 0;
6349 switch(strip_ns(y[0])) {
6350 case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
6351
6352 /* 18.8.45 xf CT_Xf */
6353 case '<xf': case '<xf/>':
6354 xf = y;
6355 delete xf[0];
6356 for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
6357 xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
6358 for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
6359 xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
6360 if(styles.NumberFmt && xf.numFmtId > 0x188) {
6361 for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
6362 }
6363 styles.CellXf.push(xf); break;
6364 case '</xf>': break;
6365
6366 /* 18.8.1 alignment CT_CellAlignment */
6367 case '<alignment': case '<alignment/>':
6368 var alignment = {};
6369 if(y.vertical) alignment.vertical = y.vertical;
6370 if(y.horizontal) alignment.horizontal = y.horizontal;
6371 if(y.textRotation != null) alignment.textRotation = y.textRotation;
6372 if(y.indent) alignment.indent = y.indent;
6373 if(y.wrapText) alignment.wrapText = parsexmlbool(y.wrapText);
6374 xf.alignment = alignment;
6375 break;
6376 case '</alignment>': break;
6377
6378 /* 18.8.33 protection CT_CellProtection */
6379 case '<protection':
6380 break;
6381 case '</protection>': case '<protection/>': break;
6382
6383 /* note: sometimes mc:AlternateContent appears bare */
6384 case '<AlternateContent': pass = true; break;
6385 case '</AlternateContent>': pass = false; break;
6386
6387 /* 18.2.10 extLst CT_ExtensionList ? */
6388 case '<extLst': case '<extLst>': case '</extLst>': break;
6389 case '<ext': pass = true; break;
6390 case '</ext>': pass = false; break;
6391 default: if(opts && opts.WTF) {
6392 if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
6393 }
6394 }
6395 });
6396}
6397
6398function write_cellXfs(cellXfs) {
6399 var o = [];
6400 o[o.length] = (writextag('cellXfs',null));
6401 cellXfs.forEach(function(c) {
6402 o[o.length] = (writextag('xf', null, c));
6403 });
6404 o[o.length] = ("</cellXfs>");
6405 if(o.length === 2) return "";
6406 o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
6407 return o.join("");
6408}
6409
6410/* 18.8 Styles CT_Stylesheet*/
6411var parse_sty_xml= (function make_pstyx() {
6412var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
6413var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
6414var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
6415var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
6416var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
6417
6418return function parse_sty_xml(data, themes, opts) {
6419 var styles = {};
6420 if(!data) return styles;
6421 data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
6422 /* 18.8.39 styleSheet CT_Stylesheet */
6423 var t;
6424
6425 /* 18.8.31 numFmts CT_NumFmts ? */
6426 if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
6427
6428 /* 18.8.23 fonts CT_Fonts ? */
6429 if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
6430
6431 /* 18.8.21 fills CT_Fills ? */
6432 if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
6433
6434 /* 18.8.5 borders CT_Borders ? */
6435 if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
6436
6437 /* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
6438 /* 18.8.8 cellStyles CT_CellStyles ? */
6439
6440 /* 18.8.10 cellXfs CT_CellXfs ? */
6441 if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
6442
6443 /* 18.8.15 dxfs CT_Dxfs ? */
6444 /* 18.8.42 tableStyles CT_TableStyles ? */
6445 /* 18.8.11 colors CT_Colors ? */
6446 /* 18.2.10 extLst CT_ExtensionList ? */
6447
6448 return styles;
6449};
6450})();
6451
6452var STYLES_XML_ROOT = writextag('styleSheet', null, {
6453 'xmlns': XMLNS.main[0],
6454 'xmlns:vt': XMLNS.vt
6455});
6456
6457RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
6458
6459function write_sty_xml(wb, opts) {
6460 var o = [XML_HEADER, STYLES_XML_ROOT], w;
6461 if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
6462 o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
6463 o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
6464 o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
6465 o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
6466 if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
6467 o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
6468 o[o.length] = ('<dxfs count="0"/>');
6469 o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
6470
6471 if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
6472 return o.join("");
6473}
6474RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
6475
6476/* Even though theme layout is dk1 lt1 dk2 lt2, true order is lt1 dk1 lt2 dk2 */
6477var XLSXThemeClrScheme = [
6478 '</a:lt1>', '</a:dk1>', '</a:lt2>', '</a:dk2>',
6479 '</a:accent1>', '</a:accent2>', '</a:accent3>',
6480 '</a:accent4>', '</a:accent5>', '</a:accent6>',
6481 '</a:hlink>', '</a:folHlink>'
6482];
6483/* 20.1.6.2 clrScheme CT_ColorScheme */
6484function parse_clrScheme(t, themes, opts) {
6485 themes.themeElements.clrScheme = [];
6486 var color = {};
6487 (t[0].match(tagregex)||[]).forEach(function(x) {
6488 var y = parsexmltag(x);
6489 switch(y[0]) {
6490 /* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
6491 case '<a:clrScheme': case '</a:clrScheme>': break;
6492
6493 /* 20.1.2.3.32 srgbClr CT_SRgbColor */
6494 case '<a:srgbClr':
6495 color.rgb = y.val; break;
6496
6497 /* 20.1.2.3.33 sysClr CT_SystemColor */
6498 case '<a:sysClr':
6499 color.rgb = y.lastClr; break;
6500
6501 /* 20.1.4.1.1 accent1 (Accent 1) */
6502 /* 20.1.4.1.2 accent2 (Accent 2) */
6503 /* 20.1.4.1.3 accent3 (Accent 3) */
6504 /* 20.1.4.1.4 accent4 (Accent 4) */
6505 /* 20.1.4.1.5 accent5 (Accent 5) */
6506 /* 20.1.4.1.6 accent6 (Accent 6) */
6507 /* 20.1.4.1.9 dk1 (Dark 1) */
6508 /* 20.1.4.1.10 dk2 (Dark 2) */
6509 /* 20.1.4.1.15 folHlink (Followed Hyperlink) */
6510 /* 20.1.4.1.19 hlink (Hyperlink) */
6511 /* 20.1.4.1.22 lt1 (Light 1) */
6512 /* 20.1.4.1.23 lt2 (Light 2) */
6513 case '<a:dk1>': case '</a:dk1>':
6514 case '<a:lt1>': case '</a:lt1>':
6515 case '<a:dk2>': case '</a:dk2>':
6516 case '<a:lt2>': case '</a:lt2>':
6517 case '<a:accent1>': case '</a:accent1>':
6518 case '<a:accent2>': case '</a:accent2>':
6519 case '<a:accent3>': case '</a:accent3>':
6520 case '<a:accent4>': case '</a:accent4>':
6521 case '<a:accent5>': case '</a:accent5>':
6522 case '<a:accent6>': case '</a:accent6>':
6523 case '<a:hlink>': case '</a:hlink>':
6524 case '<a:folHlink>': case '</a:folHlink>':
6525 if (y[0].charAt(1) === '/') {
6526 themes.themeElements.clrScheme[XLSXThemeClrScheme.indexOf(y[0])] = color;
6527 color = {};
6528 } else {
6529 color.name = y[0].slice(3, y[0].length - 1);
6530 }
6531 break;
6532
6533 default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
6534 }
6535 });
6536}
6537
6538/* 20.1.4.1.18 fontScheme CT_FontScheme */
6539function parse_fontScheme() { }
6540
6541/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
6542function parse_fmtScheme() { }
6543
6544var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
6545var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
6546var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
6547
6548/* 20.1.6.10 themeElements CT_BaseStyles */
6549function parse_themeElements(data, themes, opts) {
6550 themes.themeElements = {};
6551
6552 var t;
6553
6554 [
6555 /* clrScheme CT_ColorScheme */
6556 ['clrScheme', clrsregex, parse_clrScheme],
6557 /* fontScheme CT_FontScheme */
6558 ['fontScheme', fntsregex, parse_fontScheme],
6559 /* fmtScheme CT_StyleMatrix */
6560 ['fmtScheme', fmtsregex, parse_fmtScheme]
6561 ].forEach(function(m) {
6562 if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
6563 m[2](t, themes, opts);
6564 });
6565}
6566
6567var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
6568
6569/* 14.2.7 Theme Part */
6570function parse_theme_xml(data, opts) {
6571 /* 20.1.6.9 theme CT_OfficeStyleSheet */
6572 if(!data || data.length === 0) return parse_theme_xml(write_theme());
6573
6574 var t;
6575 var themes = {};
6576
6577 /* themeElements CT_BaseStyles */
6578 if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
6579 parse_themeElements(t[0], themes, opts);
6580 themes.raw = data;
6581 return themes;
6582}
6583
6584function write_theme(Themes, opts) {
6585 if(opts && opts.themeXLSX) return opts.themeXLSX;
6586 if(Themes && typeof Themes.raw == "string") return Themes.raw;
6587 var o = [XML_HEADER];
6588 o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
6589 o[o.length] = '<a:themeElements>';
6590
6591 o[o.length] = '<a:clrScheme name="Office">';
6592 o[o.length] = '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
6593 o[o.length] = '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
6594 o[o.length] = '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
6595 o[o.length] = '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
6596 o[o.length] = '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
6597 o[o.length] = '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
6598 o[o.length] = '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
6599 o[o.length] = '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
6600 o[o.length] = '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
6601 o[o.length] = '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
6602 o[o.length] = '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
6603 o[o.length] = '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
6604 o[o.length] = '</a:clrScheme>';
6605
6606 o[o.length] = '<a:fontScheme name="Office">';
6607 o[o.length] = '<a:majorFont>';
6608 o[o.length] = '<a:latin typeface="Cambria"/>';
6609 o[o.length] = '<a:ea typeface=""/>';
6610 o[o.length] = '<a:cs typeface=""/>';
6611 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
6612 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
6613 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
6614 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
6615 o[o.length] = '<a:font script="Arab" typeface="Times New Roman"/>';
6616 o[o.length] = '<a:font script="Hebr" typeface="Times New Roman"/>';
6617 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
6618 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
6619 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
6620 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
6621 o[o.length] = '<a:font script="Khmr" typeface="MoolBoran"/>';
6622 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
6623 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
6624 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
6625 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
6626 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
6627 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
6628 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
6629 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
6630 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
6631 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
6632 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
6633 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
6634 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
6635 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
6636 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
6637 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
6638 o[o.length] = '<a:font script="Viet" typeface="Times New Roman"/>';
6639 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
6640 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
6641 o[o.length] = '</a:majorFont>';
6642 o[o.length] = '<a:minorFont>';
6643 o[o.length] = '<a:latin typeface="Calibri"/>';
6644 o[o.length] = '<a:ea typeface=""/>';
6645 o[o.length] = '<a:cs typeface=""/>';
6646 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
6647 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
6648 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
6649 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
6650 o[o.length] = '<a:font script="Arab" typeface="Arial"/>';
6651 o[o.length] = '<a:font script="Hebr" typeface="Arial"/>';
6652 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
6653 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
6654 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
6655 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
6656 o[o.length] = '<a:font script="Khmr" typeface="DaunPenh"/>';
6657 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
6658 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
6659 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
6660 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
6661 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
6662 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
6663 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
6664 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
6665 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
6666 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
6667 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
6668 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
6669 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
6670 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
6671 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
6672 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
6673 o[o.length] = '<a:font script="Viet" typeface="Arial"/>';
6674 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
6675 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
6676 o[o.length] = '</a:minorFont>';
6677 o[o.length] = '</a:fontScheme>';
6678
6679 o[o.length] = '<a:fmtScheme name="Office">';
6680 o[o.length] = '<a:fillStyleLst>';
6681 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
6682 o[o.length] = '<a:gradFill rotWithShape="1">';
6683 o[o.length] = '<a:gsLst>';
6684 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
6685 o[o.length] = '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
6686 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
6687 o[o.length] = '</a:gsLst>';
6688 o[o.length] = '<a:lin ang="16200000" scaled="1"/>';
6689 o[o.length] = '</a:gradFill>';
6690 o[o.length] = '<a:gradFill rotWithShape="1">';
6691 o[o.length] = '<a:gsLst>';
6692 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>';
6693 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>';
6694 o[o.length] = '</a:gsLst>';
6695 o[o.length] = '<a:lin ang="16200000" scaled="0"/>';
6696 o[o.length] = '</a:gradFill>';
6697 o[o.length] = '</a:fillStyleLst>';
6698 o[o.length] = '<a:lnStyleLst>';
6699 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>';
6700 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>';
6701 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>';
6702 o[o.length] = '</a:lnStyleLst>';
6703 o[o.length] = '<a:effectStyleLst>';
6704 o[o.length] = '<a:effectStyle>';
6705 o[o.length] = '<a:effectLst>';
6706 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>';
6707 o[o.length] = '</a:effectLst>';
6708 o[o.length] = '</a:effectStyle>';
6709 o[o.length] = '<a:effectStyle>';
6710 o[o.length] = '<a:effectLst>';
6711 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>';
6712 o[o.length] = '</a:effectLst>';
6713 o[o.length] = '</a:effectStyle>';
6714 o[o.length] = '<a:effectStyle>';
6715 o[o.length] = '<a:effectLst>';
6716 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>';
6717 o[o.length] = '</a:effectLst>';
6718 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>';
6719 o[o.length] = '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
6720 o[o.length] = '</a:effectStyle>';
6721 o[o.length] = '</a:effectStyleLst>';
6722 o[o.length] = '<a:bgFillStyleLst>';
6723 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
6724 o[o.length] = '<a:gradFill rotWithShape="1">';
6725 o[o.length] = '<a:gsLst>';
6726 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
6727 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>';
6728 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
6729 o[o.length] = '</a:gsLst>';
6730 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
6731 o[o.length] = '</a:gradFill>';
6732 o[o.length] = '<a:gradFill rotWithShape="1">';
6733 o[o.length] = '<a:gsLst>';
6734 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
6735 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
6736 o[o.length] = '</a:gsLst>';
6737 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
6738 o[o.length] = '</a:gradFill>';
6739 o[o.length] = '</a:bgFillStyleLst>';
6740 o[o.length] = '</a:fmtScheme>';
6741 o[o.length] = '</a:themeElements>';
6742
6743 o[o.length] = '<a:objectDefaults>';
6744 o[o.length] = '<a:spDef>';
6745 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>';
6746 o[o.length] = '</a:spDef>';
6747 o[o.length] = '<a:lnDef>';
6748 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>';
6749 o[o.length] = '</a:lnDef>';
6750 o[o.length] = '</a:objectDefaults>';
6751 o[o.length] = '<a:extraClrSchemeLst/>';
6752 o[o.length] = '</a:theme>';
6753 return o.join("");
6754}
6755/* 18.14 Supplementary Workbook Data */
6756function parse_xlink_xml() {
6757 //var opts = _opts || {};
6758 //if(opts.WTF) throw "XLSX External Link";
6759}
6760
6761/* [MS-XLSB] 2.1.7.25 External Link */
6762function parse_xlink_bin(data, rel, name, _opts) {
6763 if(!data) return data;
6764 var opts = _opts || {};
6765
6766 var pass = false, end = false;
6767
6768 recordhopper(data, function xlink_parse(val, R_n, RT) {
6769 if(end) return;
6770 switch(RT) {
6771 case 0x0167: /* 'BrtSupTabs' */
6772 case 0x016B: /* 'BrtExternTableStart' */
6773 case 0x016C: /* 'BrtExternTableEnd' */
6774 case 0x016E: /* 'BrtExternRowHdr' */
6775 case 0x016F: /* 'BrtExternCellBlank' */
6776 case 0x0170: /* 'BrtExternCellReal' */
6777 case 0x0171: /* 'BrtExternCellBool' */
6778 case 0x0172: /* 'BrtExternCellError' */
6779 case 0x0173: /* 'BrtExternCellString' */
6780 case 0x01D8: /* 'BrtExternValueMeta' */
6781 case 0x0241: /* 'BrtSupNameStart' */
6782 case 0x0242: /* 'BrtSupNameValueStart' */
6783 case 0x0243: /* 'BrtSupNameValueEnd' */
6784 case 0x0244: /* 'BrtSupNameNum' */
6785 case 0x0245: /* 'BrtSupNameErr' */
6786 case 0x0246: /* 'BrtSupNameSt' */
6787 case 0x0247: /* 'BrtSupNameNil' */
6788 case 0x0248: /* 'BrtSupNameBool' */
6789 case 0x0249: /* 'BrtSupNameFmla' */
6790 case 0x024A: /* 'BrtSupNameBits' */
6791 case 0x024B: /* 'BrtSupNameEnd' */
6792 break;
6793
6794 case 0x0023: /* 'BrtFRTBegin' */
6795 pass = true; break;
6796 case 0x0024: /* 'BrtFRTEnd' */
6797 pass = false; break;
6798
6799 default:
6800 if((R_n||"").indexOf("Begin") > 0){/* empty */}
6801 else if((R_n||"").indexOf("End") > 0){/* empty */}
6802 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
6803 }
6804 }, opts);
6805}
6806/* 20.5 DrawingML - SpreadsheetML Drawing */
6807RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
6808RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
6809
6810/* 20.5.2.35 wsDr CT_Drawing */
6811function parse_drawing(data, rels) {
6812 if(!data) return "??";
6813 /*
6814 Chartsheet Drawing:
6815 - 20.5.2.35 wsDr CT_Drawing
6816 - 20.5.2.1 absoluteAnchor CT_AbsoluteAnchor
6817 - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
6818 - 20.1.2.2.16 graphic CT_GraphicalObject
6819 - 20.1.2.2.17 graphicData CT_GraphicalObjectData
6820 - chart reference
6821 the actual type is based on the URI of the graphicData
6822 TODO: handle embedded charts and other types of graphics
6823 */
6824 var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
6825
6826 return rels['!id'][id].Target;
6827}
6828
6829/* L.5.5.2 SpreadsheetML Comments + VML Schema */
6830var _shapeid = 1024;
6831function write_comments_vml(rId, comments) {
6832 var csize = [21600, 21600];
6833 /* L.5.2.1.2 Path Attribute */
6834 var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
6835 var o = [
6836 writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
6837 writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
6838 writextag("v:shapetype", [
6839 writextag("v:stroke", null, {joinstyle:"miter"}),
6840 writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
6841 ].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
6842 ];
6843 while(_shapeid < rId * 1000) _shapeid += 1000;
6844
6845 comments.forEach(function(x) {
6846 var c = decode_cell(x[0]);
6847 var fillopts = {'color2':"#BEFF82", 'type':"gradient"};
6848 if(fillopts.type == "gradient") fillopts.angle = "-180";
6849 var fillparm = fillopts.type == "gradient" ? writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}) : null;
6850 var fillxml = writextag('v:fill', fillparm, fillopts);
6851
6852 var shadata = ({on:"t", 'obscured':"t"});
6853 ++_shapeid;
6854
6855 o = o.concat([
6856 '<v:shape' + wxt_helper({
6857 id:'_x0000_s' + _shapeid,
6858 type:"#_x0000_t202",
6859 style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
6860 fillcolor:"#ECFAD4",
6861 strokecolor:"#edeaa1"
6862 }) + '>',
6863 fillxml,
6864 writextag("v:shadow", null, shadata),
6865 writextag("v:path", null, {'o:connecttype':"none"}),
6866 '<v:textbox><div style="text-align:left"></div></v:textbox>',
6867 '<x:ClientData ObjectType="Note">',
6868 '<x:MoveWithCells/>',
6869 '<x:SizeWithCells/>',
6870 /* Part 4 19.4.2.3 Anchor (Anchor) */
6871 writetag('x:Anchor', [c.c+1, 0, c.r+1, 0, c.c+3, 20, c.r+5, 20].join(",")),
6872 writetag('x:AutoFill', "False"),
6873 writetag('x:Row', String(c.r)),
6874 writetag('x:Column', String(c.c)),
6875 x[1].hidden ? '' : '<x:Visible/>',
6876 '</x:ClientData>',
6877 '</v:shape>'
6878 ]); });
6879 o.push('</xml>');
6880 return o.join("");
6881}
6882RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
6883
6884function sheet_insert_comments(sheet, comments) {
6885 var dense = Array.isArray(sheet);
6886 var cell;
6887 comments.forEach(function(comment) {
6888 var r = decode_cell(comment.ref);
6889 if(dense) {
6890 if(!sheet[r.r]) sheet[r.r] = [];
6891 cell = sheet[r.r][r.c];
6892 } else cell = sheet[comment.ref];
6893 if (!cell) {
6894 cell = ({t:"z"});
6895 if(dense) sheet[r.r][r.c] = cell;
6896 else sheet[comment.ref] = cell;
6897 var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
6898 if(range.s.r > r.r) range.s.r = r.r;
6899 if(range.e.r < r.r) range.e.r = r.r;
6900 if(range.s.c > r.c) range.s.c = r.c;
6901 if(range.e.c < r.c) range.e.c = r.c;
6902 var encoded = encode_range(range);
6903 if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
6904 }
6905
6906 if (!cell.c) cell.c = [];
6907 var o = ({a: comment.author, t: comment.t, r: comment.r});
6908 if(comment.h) o.h = comment.h;
6909 cell.c.push(o);
6910 });
6911}
6912
6913/* 18.7 Comments */
6914function parse_comments_xml(data, opts) {
6915 /* 18.7.6 CT_Comments */
6916 if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
6917 var authors = [];
6918 var commentList = [];
6919 var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
6920 if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
6921 if(x === "" || x.trim() === "") return;
6922 var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
6923 if(a) authors.push(a[1]);
6924 });
6925 var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
6926 if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
6927 if(x === "" || x.trim() === "") return;
6928 var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
6929 if(!cm) return;
6930 var y = parsexmltag(cm[0]);
6931 var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
6932 var cell = decode_cell(y.ref);
6933 if(opts.sheetRows && opts.sheetRows <= cell.r) return;
6934 var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
6935 var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
6936 comment.r = rt.r;
6937 if(rt.r == "<t></t>") rt.t = rt.h = "";
6938 comment.t = (rt.t||"").replace(/\r\n/g,"\n").replace(/\r/g,"\n");
6939 if(opts.cellHTML) comment.h = rt.h;
6940 commentList.push(comment);
6941 });
6942 return commentList;
6943}
6944
6945var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
6946function write_comments_xml(data) {
6947 var o = [XML_HEADER, CMNT_XML_ROOT];
6948
6949 var iauthor = [];
6950 o.push("<authors>");
6951 data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
6952 if(iauthor.indexOf(a) > -1) return;
6953 iauthor.push(a);
6954 o.push("<author>" + a + "</author>");
6955 }); });
6956 o.push("</authors>");
6957 o.push("<commentList>");
6958 data.forEach(function(d) {
6959 d[1].forEach(function(c) {
6960 /* 18.7.3 CT_Comment */
6961 o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
6962 o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
6963 o.push('</text></comment>');
6964 });
6965 });
6966 o.push("</commentList>");
6967 if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
6968 return o.join("");
6969}
6970var CT_VBA = "application/vnd.ms-office.vbaProject";
6971function make_vba_xls(cfb) {
6972 var newcfb = CFB.utils.cfb_new({root:"R"});
6973 cfb.FullPaths.forEach(function(p, i) {
6974 if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
6975 var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
6976 CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
6977 });
6978 return CFB.write(newcfb);
6979}
6980
6981function fill_vba_xls(cfb, vba) {
6982 vba.FullPaths.forEach(function(p, i) {
6983 if(i == 0) return;
6984 var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
6985 if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
6986 });
6987}
6988
6989var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
6990
6991RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
6992RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
6993
6994/* macro and dialog sheet stubs */
6995function parse_ds_bin() { return {'!type':'dialog'}; }
6996function parse_ds_xml() { return {'!type':'dialog'}; }
6997function parse_ms_bin() { return {'!type':'macro'}; }
6998function parse_ms_xml() { return {'!type':'macro'}; }
6999/* TODO: it will be useful to parse the function str */
7000var rc_to_a1 = (function(){
7001 var rcregex = /(^|[^A-Za-z_])R(\[?-?\d+\]|[1-9]\d*|)C(\[?-?\d+\]|[1-9]\d*|)(?![A-Za-z0-9_])/g;
7002 var rcbase = ({r:0,c:0});
7003 function rcfunc($$,$1,$2,$3) {
7004 var cRel = false, rRel = false;
7005
7006 if($2.length == 0) rRel = true;
7007 else if($2.charAt(0) == "[") { rRel = true; $2 = $2.slice(1, -1); }
7008
7009 if($3.length == 0) cRel = true;
7010 else if($3.charAt(0) == "[") { cRel = true; $3 = $3.slice(1, -1); }
7011
7012 var R = $2.length>0?parseInt($2,10)|0:0, C = $3.length>0?parseInt($3,10)|0:0;
7013
7014 if(cRel) C += rcbase.c; else --C;
7015 if(rRel) R += rcbase.r; else --R;
7016 return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
7017 }
7018 return function rc_to_a1(fstr, base) {
7019 rcbase = base;
7020 return fstr.replace(rcregex, rcfunc);
7021 };
7022})();
7023
7024var crefregex = /(^|[^._A-Z0-9])([$]?)([A-Z]{1,2}|[A-W][A-Z]{2}|X[A-E][A-Z]|XF[A-D])([$]?)(10[0-3]\d{4}|104[0-7]\d{3}|1048[0-4]\d{2}|10485[0-6]\d|104857[0-6]|[1-9]\d{0,5})(?![_.\(A-Za-z0-9])/g;
7025var a1_to_rc =(function(){
7026 return function a1_to_rc(fstr, base) {
7027 return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
7028 var c = decode_col($3) - ($2 ? 0 : base.c);
7029 var r = decode_row($5) - ($4 ? 0 : base.r);
7030 var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
7031 var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
7032 return $1 + "R" + R + "C" + C;
7033 });
7034 };
7035})();
7036
7037/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
7038function shift_formula_str(f, delta) {
7039 return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
7040 return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
7041 });
7042}
7043
7044function shift_formula_xlsx(f, range, cell) {
7045 var r = decode_range(range), s = r.s, c = decode_cell(cell);
7046 var delta = {r:c.r - s.r, c:c.c - s.c};
7047 return shift_formula_str(f, delta);
7048}
7049
7050/* TODO: parse formula */
7051function fuzzyfmla(f) {
7052 if(f.length == 1) return false;
7053 return true;
7054}
7055
7056function _xlfn(f) {
7057 return f.replace(/_xlfn\./g,"");
7058}
7059var strs = {}; // shared strings
7060var _ssfopts = {}; // spreadsheet formatting options
7061
7062RELS.WS = [
7063 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
7064 "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
7065];
7066
7067/*global Map */
7068var browser_has_Map = typeof Map !== 'undefined';
7069
7070function get_sst_id(sst, str, rev) {
7071 var i = 0, len = sst.length;
7072 if(rev) {
7073 if(browser_has_Map ? rev.has(str) : Object.prototype.hasOwnProperty.call(rev, str)) {
7074 var revarr = browser_has_Map ? rev.get(str) : rev[str];
7075 for(; i < revarr.length; ++i) {
7076 if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
7077 }
7078 }
7079 } else for(; i < len; ++i) {
7080 if(sst[i].t === str) { sst.Count ++; return i; }
7081 }
7082 sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
7083 if(rev) {
7084 if(browser_has_Map) {
7085 if(!rev.has(str)) rev.set(str, []);
7086 rev.get(str).push(len);
7087 } else {
7088 if(!Object.prototype.hasOwnProperty.call(rev, str)) rev[str] = [];
7089 rev[str].push(len);
7090 }
7091 }
7092 return len;
7093}
7094
7095function col_obj_w(C, col) {
7096 var p = ({min:C+1,max:C+1});
7097 /* wch (chars), wpx (pixels) */
7098 var wch = -1;
7099 if(col.MDW) MDW = col.MDW;
7100 if(col.width != null) p.customWidth = 1;
7101 else if(col.wpx != null) wch = px2char(col.wpx);
7102 else if(col.wch != null) wch = col.wch;
7103 if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
7104 else if(col.width != null) p.width = col.width;
7105 if(col.hidden) p.hidden = true;
7106 if(col.level != null) { p.outlineLevel = p.level = col.level; }
7107 return p;
7108}
7109
7110function default_margins(margins, mode) {
7111 if(!margins) return;
7112 var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
7113 if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
7114 if(margins.left == null) margins.left = defs[0];
7115 if(margins.right == null) margins.right = defs[1];
7116 if(margins.top == null) margins.top = defs[2];
7117 if(margins.bottom == null) margins.bottom = defs[3];
7118 if(margins.header == null) margins.header = defs[4];
7119 if(margins.footer == null) margins.footer = defs[5];
7120}
7121
7122function get_cell_style(styles, cell, opts) {
7123 var z = opts.revssf[cell.z != null ? cell.z : "General"];
7124 var i = 0x3c, len = styles.length;
7125 if(z == null && opts.ssf) {
7126 for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
7127 SSF.load(cell.z, i);
7128 // $FlowIgnore
7129 opts.ssf[i] = cell.z;
7130 opts.revssf[cell.z] = z = i;
7131 break;
7132 }
7133 }
7134 for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
7135 styles[len] = {
7136 numFmtId:z,
7137 fontId:0,
7138 fillId:0,
7139 borderId:0,
7140 xfId:0,
7141 applyNumberFormat:1
7142 };
7143 return len;
7144}
7145
7146function safe_format(p, fmtid, fillid, opts, themes, styles) {
7147 try {
7148 if(opts.cellNF) p.z = SSF._table[fmtid];
7149 } catch(e) { if(opts.WTF) throw e; }
7150 if(p.t === 'z' && !opts.cellStyles) return;
7151 if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
7152 if((!opts || opts.cellText !== false) && p.t !== 'z') try {
7153 if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
7154 if(p.t === 'e') p.w = p.w || BErr[p.v];
7155 else if(fmtid === 0) {
7156 if(p.t === 'n') {
7157 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
7158 else p.w = SSF._general_num(p.v);
7159 }
7160 else if(p.t === 'd') {
7161 var dd = datenum(p.v);
7162 if((dd|0) === dd) p.w = SSF._general_int(dd);
7163 else p.w = SSF._general_num(dd);
7164 }
7165 else if(p.v === undefined) return "";
7166 else p.w = SSF._general(p.v,_ssfopts);
7167 }
7168 else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
7169 else p.w = SSF.format(fmtid,p.v,_ssfopts);
7170 } catch(e) { if(opts.WTF) throw e; }
7171 if(!opts.cellStyles) return;
7172 if(fillid != null) try {
7173 p.s = styles.Fills[fillid];
7174 if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
7175 p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
7176 if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
7177 }
7178 if (p.s.bgColor && p.s.bgColor.theme) {
7179 p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
7180 if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
7181 }
7182 } catch(e) { if(opts.WTF && styles.Fills) throw e; }
7183}
7184
7185function check_ws(ws, sname, i) {
7186 if(ws && ws['!ref']) {
7187 var range = safe_decode_range(ws['!ref']);
7188 if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
7189 }
7190}
7191function parse_ws_xml_dim(ws, s) {
7192 var d = safe_decode_range(s);
7193 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);
7194}
7195var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
7196var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
7197var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
7198var dimregex = /"(\w*:\w*)"/;
7199var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
7200var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
7201var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
7202var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
7203var sheetprregex2= /<(?:\w:)?sheetPr[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetPr)>/;
7204var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
7205
7206/* 18.3 Worksheets */
7207function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
7208 if(!data) return data;
7209 if(!rels) rels = {'!id':{}};
7210 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
7211
7212 /* 18.3.1.99 worksheet CT_Worksheet */
7213 var s = opts.dense ? ([]) : ({});
7214 var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
7215
7216 var data1 = "", data2 = "";
7217 var mtch = data.match(sheetdataregex);
7218 if(mtch) {
7219 data1 = data.slice(0, mtch.index);
7220 data2 = data.slice(mtch.index + mtch[0].length);
7221 } else data1 = data2 = data;
7222
7223 /* 18.3.1.82 sheetPr CT_SheetPr */
7224 var sheetPr = data1.match(sheetprregex);
7225 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
7226 else if((sheetPr = data1.match(sheetprregex2))) parse_ws_xml_sheetpr2(sheetPr[0], sheetPr[1]||"", s, wb, idx, styles, themes);
7227
7228 /* 18.3.1.35 dimension CT_SheetDimension */
7229 var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
7230 if(ridx > 0) {
7231 var ref = data1.slice(ridx,ridx+50).match(dimregex);
7232 if(ref) parse_ws_xml_dim(s, ref[1]);
7233 }
7234
7235 /* 18.3.1.88 sheetViews CT_SheetViews */
7236 var svs = data1.match(svsregex);
7237 if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
7238
7239 /* 18.3.1.17 cols CT_Cols */
7240 var columns = [];
7241 if(opts.cellStyles) {
7242 /* 18.3.1.13 col CT_Col */
7243 var cols = data1.match(colregex);
7244 if(cols) parse_ws_xml_cols(columns, cols);
7245 }
7246
7247 /* 18.3.1.80 sheetData CT_SheetData ? */
7248 if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
7249
7250 /* 18.3.1.2 autoFilter CT_AutoFilter */
7251 var afilter = data2.match(afregex);
7252 if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
7253
7254 /* 18.3.1.55 mergeCells CT_MergeCells */
7255 var merges = [];
7256 var _merge = data2.match(mergecregex);
7257 if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
7258 merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
7259
7260 /* 18.3.1.48 hyperlinks CT_Hyperlinks */
7261 var hlink = data2.match(hlinkregex);
7262 if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
7263
7264 /* 18.3.1.62 pageMargins CT_PageMargins */
7265 var margins = data2.match(marginregex);
7266 if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
7267
7268 if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
7269 if(opts.sheetRows > 0 && s["!ref"]) {
7270 var tmpref = safe_decode_range(s["!ref"]);
7271 if(opts.sheetRows <= +tmpref.e.r) {
7272 tmpref.e.r = opts.sheetRows - 1;
7273 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
7274 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
7275 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
7276 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
7277 s["!fullref"] = s["!ref"];
7278 s["!ref"] = encode_range(tmpref);
7279 }
7280 }
7281 if(columns.length > 0) s["!cols"] = columns;
7282 if(merges.length > 0) s["!merges"] = merges;
7283 return s;
7284}
7285
7286function write_ws_xml_merges(merges) {
7287 if(merges.length === 0) return "";
7288 var o = '<mergeCells count="' + merges.length + '">';
7289 for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
7290 return o + '</mergeCells>';
7291}
7292
7293/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
7294function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
7295 var data = parsexmltag(sheetPr);
7296 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
7297 if(data.codeName) wb.Sheets[idx].CodeName = unescapexml(utf8read(data.codeName));
7298}
7299function parse_ws_xml_sheetpr2(sheetPr, body, s, wb, idx, styles, themes) {
7300 parse_ws_xml_sheetpr(sheetPr.slice(0, sheetPr.indexOf(">")), s, wb, idx);
7301}
7302function write_ws_xml_sheetpr(ws, wb, idx, opts, o) {
7303 var needed = false;
7304 var props = {}, payload = null;
7305 if(opts.bookType !== 'xlsx' && wb.vbaraw) {
7306 var cname = wb.SheetNames[idx];
7307 try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
7308 needed = true;
7309 props.codeName = utf8write(escapexml(cname));
7310 }
7311
7312 if(ws && ws["!outline"]) {
7313 var outlineprops = {summaryBelow:1, summaryRight:1};
7314 if(ws["!outline"].above) outlineprops.summaryBelow = 0;
7315 if(ws["!outline"].left) outlineprops.summaryRight = 0;
7316 payload = (payload||"") + writextag('outlinePr', null, outlineprops);
7317 }
7318
7319 if(!needed && !payload) return;
7320 o[o.length] = (writextag('sheetPr', payload, props));
7321}
7322
7323/* 18.3.1.85 sheetProtection CT_SheetProtection */
7324var sheetprot_deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
7325var sheetprot_deftrue = [
7326 "formatColumns", "formatRows", "formatCells",
7327 "insertColumns", "insertRows", "insertHyperlinks",
7328 "deleteColumns", "deleteRows",
7329 "sort", "autoFilter", "pivotTables"
7330];
7331function write_ws_xml_protection(sp) {
7332 // algorithmName, hashValue, saltValue, spinCount
7333 var o = ({sheet:1});
7334 sheetprot_deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
7335 sheetprot_deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
7336 /* TODO: algorithm */
7337 if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
7338 return writextag('sheetProtection', null, o);
7339}
7340
7341function parse_ws_xml_hlinks(s, data, rels) {
7342 var dense = Array.isArray(s);
7343 for(var i = 0; i != data.length; ++i) {
7344 var val = parsexmltag(utf8read(data[i]), true);
7345 if(!val.ref) return;
7346 var rel = ((rels || {})['!id']||[])[val.id];
7347 if(rel) {
7348 val.Target = rel.Target;
7349 if(val.location) val.Target += "#"+unescapexml(val.location);
7350 } else {
7351 val.Target = "#" + unescapexml(val.location);
7352 rel = {Target: val.Target, TargetMode: 'Internal'};
7353 }
7354 val.Rel = rel;
7355 if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
7356 var rng = safe_decode_range(val.ref);
7357 for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
7358 var addr = encode_cell({c:C,r:R});
7359 if(dense) {
7360 if(!s[R]) s[R] = [];
7361 if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
7362 s[R][C].l = val;
7363 } else {
7364 if(!s[addr]) s[addr] = {t:"z",v:undefined};
7365 s[addr].l = val;
7366 }
7367 }
7368 }
7369}
7370
7371function parse_ws_xml_margins(margin) {
7372 var o = {};
7373 ["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
7374 if(margin[k]) o[k] = parseFloat(margin[k]);
7375 });
7376 return o;
7377}
7378function write_ws_xml_margins(margin) {
7379 default_margins(margin);
7380 return writextag('pageMargins', null, margin);
7381}
7382
7383function parse_ws_xml_cols(columns, cols) {
7384 var seencol = false;
7385 for(var coli = 0; coli != cols.length; ++coli) {
7386 var coll = parsexmltag(cols[coli], true);
7387 if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
7388 var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
7389 if(coll.outlineLevel) coll.level = (+coll.outlineLevel || 0);
7390 delete coll.min; delete coll.max; coll.width = +coll.width;
7391 if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
7392 process_col(coll);
7393 while(colm <= colM) columns[colm++] = dup(coll);
7394 }
7395}
7396function write_ws_xml_cols(ws, cols) {
7397 var o = ["<cols>"], col;
7398 for(var i = 0; i != cols.length; ++i) {
7399 if(!(col = cols[i])) continue;
7400 o[o.length] = (writextag('col', null, col_obj_w(i, col)));
7401 }
7402 o[o.length] = "</cols>";
7403 return o.join("");
7404}
7405
7406function parse_ws_xml_autofilter(data) {
7407 var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
7408 return o;
7409}
7410function write_ws_xml_autofilter(data, ws, wb, idx) {
7411 var ref = typeof data.ref == "string" ? data.ref : encode_range(data.ref);
7412 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
7413 if(!wb.Workbook.Names) wb.Workbook.Names = [];
7414 var names = wb.Workbook.Names;
7415 var range = decode_range(ref);
7416 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
7417 for(var i = 0; i < names.length; ++i) {
7418 var name = names[i];
7419 if(name.Name != '_xlnm._FilterDatabase') continue;
7420 if(name.Sheet != idx) continue;
7421 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
7422 }
7423 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
7424 return writextag("autoFilter", null, {ref:ref});
7425}
7426
7427/* 18.3.1.88 sheetViews CT_SheetViews */
7428/* 18.3.1.87 sheetView CT_SheetView */
7429var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/;
7430function parse_ws_xml_sheetviews(data, wb) {
7431 if(!wb.Views) wb.Views = [{}];
7432 (data.match(sviewregex)||[]).forEach(function(r, i) {
7433 var tag = parsexmltag(r);
7434 // $FlowIgnore
7435 if(!wb.Views[i]) wb.Views[i] = {};
7436 // $FlowIgnore
7437 if(+tag.zoomScale) wb.Views[i].zoom = +tag.zoomScale;
7438 // $FlowIgnore
7439 if(parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true;
7440 });
7441}
7442function write_ws_xml_sheetviews(ws, opts, idx, wb) {
7443 var sview = ({workbookViewId:"0"});
7444 // $FlowIgnore
7445 if((((wb||{}).Workbook||{}).Views||[])[0]) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
7446 return writextag("sheetViews", writextag("sheetView", null, sview), {});
7447}
7448
7449function write_ws_xml_cell(cell, ref, ws, opts) {
7450 if(cell.v === undefined && typeof cell.f !== "string" || cell.t === 'z') return "";
7451 var vv = "";
7452 var oldt = cell.t, oldv = cell.v;
7453 if(cell.t !== "z") switch(cell.t) {
7454 case 'b': vv = cell.v ? "1" : "0"; break;
7455 case 'n': vv = ''+cell.v; break;
7456 case 'e': vv = BErr[cell.v]; break;
7457 case 'd':
7458 if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
7459 else {
7460 cell = dup(cell);
7461 cell.t = 'n';
7462 vv = ''+(cell.v = datenum(parseDate(cell.v)));
7463 }
7464 if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
7465 break;
7466 default: vv = cell.v; break;
7467 }
7468 var v = writetag('v', escapexml(vv)), o = ({r:ref});
7469 /* TODO: cell style */
7470 var os = get_cell_style(opts.cellXfs, cell, opts);
7471 if(os !== 0) o.s = os;
7472 switch(cell.t) {
7473 case 'n': break;
7474 case 'd': o.t = "d"; break;
7475 case 'b': o.t = "b"; break;
7476 case 'e': o.t = "e"; break;
7477 case 'z': break;
7478 default: if(cell.v == null) { delete cell.t; break; }
7479 if(cell.v.length > 32767) throw new Error("Text length must not exceed 32767 characters");
7480 if(opts && opts.bookSST) {
7481 v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
7482 o.t = "s"; break;
7483 }
7484 o.t = "str"; break;
7485 }
7486 if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
7487 if(typeof cell.f == "string" && cell.f) {
7488 var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
7489 v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
7490 }
7491 if(cell.l) ws['!links'].push([ref, cell.l]);
7492 if(cell.c) ws['!comments'].push([ref, cell.c]);
7493 return writextag('c', v, o);
7494}
7495
7496var parse_ws_xml_data = (function() {
7497 var cellregex = /<(?:\w+:)?c[ \/>]/, rowregex = /<\/(?:\w+:)?row>/;
7498 var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
7499 var refregex = /ref=["']([^"']*)["']/;
7500 var match_v = matchtag("v"), match_f = matchtag("f");
7501
7502return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
7503 var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
7504 var tag, tagr = 0, tagc = 0;
7505 var sstr, ftag;
7506 var fmtid = 0, fillid = 0;
7507 var do_format = Array.isArray(styles.CellXf), cf;
7508 var arrayf = [];
7509 var sharedf = [];
7510 var dense = Array.isArray(s);
7511 var rows = [], rowobj = {}, rowrite = false;
7512 var sheetStubs = !!opts.sheetStubs;
7513 for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
7514 x = marr[mt].trim();
7515 var xlen = x.length;
7516 if(xlen === 0) continue;
7517
7518 /* 18.3.1.73 row CT_Row */
7519 var rstarti = 0;
7520 outa: for(ri = 0; ri < xlen; ++ri) switch(/*x.charCodeAt(ri)*/x[ri]) {
7521 case ">" /*62*/:
7522 if(/*x.charCodeAt(ri-1) != 47*/x[ri-1] != "/") { ++ri; break outa; }
7523 if(opts && opts.cellStyles) {
7524 // TODO: avoid duplication
7525 tag = parsexmltag(x.slice(rstarti,ri), true);
7526 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
7527 if(opts.sheetRows && opts.sheetRows < tagr) continue;
7528 rowobj = {}; rowrite = false;
7529 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
7530 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
7531 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
7532 if(rowrite) rows[tagr-1] = rowobj;
7533 }
7534 break;
7535 case "<" /*60*/: rstarti = ri; break;
7536 }
7537 if(rstarti >= ri) break;
7538 tag = parsexmltag(x.slice(rstarti,ri), true);
7539 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
7540 if(opts.sheetRows && opts.sheetRows < tagr) continue;
7541 if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
7542 if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
7543
7544 if(opts && opts.cellStyles) {
7545 rowobj = {}; rowrite = false;
7546 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
7547 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
7548 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
7549 if(rowrite) rows[tagr-1] = rowobj;
7550 }
7551
7552 /* 18.3.1.4 c CT_Cell */
7553 cells = x.slice(ri).split(cellregex);
7554 for(var rslice = 0; rslice != cells.length; ++rslice) if(cells[rslice].trim().charAt(0) != "<") break;
7555 cells = cells.slice(rslice);
7556 for(ri = 0; ri != cells.length; ++ri) {
7557 x = cells[ri].trim();
7558 if(x.length === 0) continue;
7559 cref = x.match(rregex); idx = ri; i=0; cc=0;
7560 x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
7561 if(cref != null && cref.length === 2) {
7562 idx = 0; d=cref[1];
7563 for(i=0; i != d.length; ++i) {
7564 if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
7565 idx = 26*idx + cc;
7566 }
7567 --idx;
7568 tagc = idx;
7569 } else ++tagc;
7570 for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
7571 tag = parsexmltag(x.slice(0,i), true);
7572 if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
7573 d = x.slice(i);
7574 p = ({t:""});
7575
7576 if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
7577 if(opts.cellFormula) {
7578 if((cref=d.match(match_f))!= null && cref[1] !== '') {
7579 /* TODO: match against XLSXFutureFunctions */
7580 p.f=unescapexml(utf8read(cref[1])).replace(/\r\n/g, "\n");
7581 if(!opts.xlfn) p.f = _xlfn(p.f);
7582 if(cref[0].indexOf('t="array"') > -1) {
7583 p.F = (d.match(refregex)||[])[1];
7584 if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
7585 } else if(cref[0].indexOf('t="shared"') > -1) {
7586 // TODO: parse formula
7587 ftag = parsexmltag(cref[0]);
7588 var ___f = unescapexml(utf8read(cref[1]));
7589 if(!opts.xlfn) ___f = _xlfn(___f);
7590 sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r];
7591 }
7592 } else if((cref=d.match(/<f[^>]*\/>/))) {
7593 ftag = parsexmltag(cref[0]);
7594 if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
7595 }
7596 /* TODO: factor out contains logic */
7597 var _tag = decode_cell(tag.r);
7598 for(i = 0; i < arrayf.length; ++i)
7599 if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
7600 if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
7601 p.F = arrayf[i][1];
7602 }
7603
7604 if(tag.t == null && p.v === undefined) {
7605 if(p.f || p.F) {
7606 p.v = 0; p.t = "n";
7607 } else if(!sheetStubs) continue;
7608 else p.t = "z";
7609 }
7610 else p.t = tag.t || "n";
7611 if(guess.s.c > tagc) guess.s.c = tagc;
7612 if(guess.e.c < tagc) guess.e.c = tagc;
7613 /* 18.18.11 t ST_CellType */
7614 switch(p.t) {
7615 case 'n':
7616 if(p.v == "" || p.v == null) {
7617 if(!sheetStubs) continue;
7618 p.t = 'z';
7619 } else p.v = parseFloat(p.v);
7620 break;
7621 case 's':
7622 if(typeof p.v == 'undefined') {
7623 if(!sheetStubs) continue;
7624 p.t = 'z';
7625 } else {
7626 sstr = strs[parseInt(p.v, 10)];
7627 p.v = sstr.t;
7628 p.r = sstr.r;
7629 if(opts.cellHTML) p.h = sstr.h;
7630 }
7631 break;
7632 case 'str':
7633 p.t = "s";
7634 p.v = (p.v!=null) ? utf8read(p.v) : '';
7635 if(opts.cellHTML) p.h = escapehtml(p.v);
7636 break;
7637 case 'inlineStr':
7638 cref = d.match(isregex);
7639 p.t = 's';
7640 if(cref != null && (sstr = parse_si(cref[1]))) {
7641 p.v = sstr.t;
7642 if(opts.cellHTML) p.h = sstr.h;
7643 } else p.v = "";
7644 break;
7645 case 'b': p.v = parsexmlbool(p.v); break;
7646 case 'd':
7647 if(opts.cellDates) p.v = parseDate(p.v, 1);
7648 else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
7649 break;
7650 /* error string in .w, number in .v */
7651 case 'e':
7652 if(!opts || opts.cellText !== false) p.w = p.v;
7653 p.v = RBErr[p.v]; break;
7654 }
7655 /* formatting */
7656 fmtid = fillid = 0;
7657 cf = null;
7658 if(do_format && tag.s !== undefined) {
7659 cf = styles.CellXf[tag.s];
7660 if(cf != null) {
7661 if(cf.numFmtId != null) fmtid = cf.numFmtId;
7662 if(opts.cellStyles) {
7663 if(cf.fillId != null) fillid = cf.fillId;
7664 }
7665 }
7666 }
7667 safe_format(p, fmtid, fillid, opts, themes, styles);
7668 if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
7669 if(dense) {
7670 var _r = decode_cell(tag.r);
7671 if(!s[_r.r]) s[_r.r] = [];
7672 s[_r.r][_r.c] = p;
7673 } else s[tag.r] = p;
7674 }
7675 }
7676 if(rows.length > 0) s['!rows'] = rows;
7677}; })();
7678
7679function write_ws_xml_data(ws, opts, idx, wb) {
7680 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
7681 var dense = Array.isArray(ws);
7682 var params = ({r:rr}), row, height = -1;
7683 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
7684 for(R = range.s.r; R <= range.e.r; ++R) {
7685 r = [];
7686 rr = encode_row(R);
7687 for(C = range.s.c; C <= range.e.c; ++C) {
7688 ref = cols[C] + rr;
7689 var _cell = dense ? (ws[R]||[])[C]: ws[ref];
7690 if(_cell === undefined) continue;
7691 if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
7692 }
7693 if(r.length > 0 || (rows && rows[R])) {
7694 params = ({r:rr});
7695 if(rows && rows[R]) {
7696 row = rows[R];
7697 if(row.hidden) params.hidden = 1;
7698 height = -1;
7699 if(row.hpx) height = px2pt(row.hpx);
7700 else if(row.hpt) height = row.hpt;
7701 if(height > -1) { params.ht = height; params.customHeight = 1; }
7702 if(row.level) { params.outlineLevel = row.level; }
7703 }
7704 o[o.length] = (writextag('row', r.join(""), params));
7705 }
7706 }
7707 if(rows) for(; R < rows.length; ++R) {
7708 if(rows && rows[R]) {
7709 params = ({r:R+1});
7710 row = rows[R];
7711 if(row.hidden) params.hidden = 1;
7712 height = -1;
7713 if (row.hpx) height = px2pt(row.hpx);
7714 else if (row.hpt) height = row.hpt;
7715 if (height > -1) { params.ht = height; params.customHeight = 1; }
7716 if (row.level) { params.outlineLevel = row.level; }
7717 o[o.length] = (writextag('row', "", params));
7718 }
7719 }
7720 return o.join("");
7721}
7722
7723var WS_XML_ROOT = writextag('worksheet', null, {
7724 'xmlns': XMLNS.main[0],
7725 'xmlns:r': XMLNS.r
7726});
7727
7728function write_ws_xml(idx, opts, wb, rels) {
7729 var o = [XML_HEADER, WS_XML_ROOT];
7730 var s = wb.SheetNames[idx], sidx = 0, rdata = "";
7731 var ws = wb.Sheets[s];
7732 if(ws == null) ws = {};
7733 var ref = ws['!ref'] || 'A1';
7734 var range = safe_decode_range(ref);
7735 if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
7736 if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
7737 range.e.c = Math.min(range.e.c, 0x3FFF);
7738 range.e.r = Math.min(range.e.c, 0xFFFFF);
7739 ref = encode_range(range);
7740 }
7741 if(!rels) rels = {};
7742 ws['!comments'] = [];
7743 var _drawing = [];
7744
7745 write_ws_xml_sheetpr(ws, wb, idx, opts, o);
7746
7747 o[o.length] = (writextag('dimension', null, {'ref': ref}));
7748
7749 o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
7750
7751 /* TODO: store in WB, process styles */
7752 if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
7753 defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
7754 baseColWidth:opts.sheetFormat.baseColWidth||'10',
7755 outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
7756 }));
7757
7758 if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
7759
7760 o[sidx = o.length] = '<sheetData/>';
7761 ws['!links'] = [];
7762 if(ws['!ref'] != null) {
7763 rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
7764 if(rdata.length > 0) o[o.length] = (rdata);
7765 }
7766 if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
7767
7768 /* sheetCalcPr */
7769
7770 if(ws['!protect']) o[o.length] = write_ws_xml_protection(ws['!protect']);
7771
7772 /* protectedRanges */
7773 /* scenarios */
7774
7775 if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter'], ws, wb, idx);
7776
7777 /* sortState */
7778 /* dataConsolidate */
7779 /* customSheetViews */
7780
7781 if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
7782
7783 /* phoneticPr */
7784 /* conditionalFormatting */
7785 /* dataValidations */
7786
7787 var relc = -1, rel, rId = -1;
7788 if(ws['!links'].length > 0) {
7789 o[o.length] = "<hyperlinks>";
7790ws['!links'].forEach(function(l) {
7791 if(!l[1].Target) return;
7792 rel = ({"ref":l[0]});
7793 if(l[1].Target.charAt(0) != "#") {
7794 rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
7795 rel["r:id"] = "rId"+rId;
7796 }
7797 if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
7798 if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
7799 o[o.length] = writextag("hyperlink",null,rel);
7800 });
7801 o[o.length] = "</hyperlinks>";
7802 }
7803 delete ws['!links'];
7804
7805 /* printOptions */
7806
7807 if(ws['!margins'] != null) o[o.length] = write_ws_xml_margins(ws['!margins']);
7808
7809 /* pageSetup */
7810 /* headerFooter */
7811 /* rowBreaks */
7812 /* colBreaks */
7813 /* customProperties */
7814 /* cellWatches */
7815
7816 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
7817
7818 /* smartTags */
7819
7820 if(_drawing.length > 0) {
7821 rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
7822 o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
7823 ws['!drawing'] = _drawing;
7824 }
7825
7826 if(ws['!comments'].length > 0) {
7827 rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
7828 o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
7829 ws['!legacy'] = rId;
7830 }
7831
7832 /* legacyDrawingHF */
7833 /* picture */
7834 /* oleObjects */
7835 /* controls */
7836 /* webPublishItems */
7837 /* tableParts */
7838 /* extLst */
7839
7840 if(o.length>1) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
7841 return o.join("");
7842}
7843RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
7844RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
7845
7846function parse_Cache(data) {
7847 var col = [];
7848 var num = data.match(/^<c:numCache>/);
7849 var f;
7850
7851 /* 21.2.2.150 pt CT_NumVal */
7852 (data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
7853 var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
7854 if(!q) return;
7855 col[+q[1]] = num ? +q[2] : q[2];
7856 });
7857
7858 /* 21.2.2.71 formatCode CT_Xstring */
7859 var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
7860
7861 (data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); });
7862
7863 return [col, nf, f];
7864}
7865
7866/* 21.2 DrawingML - Charts */
7867function parse_chart(data, name, opts, rels, wb, csheet) {
7868 var cs = ((csheet || {"!type":"chart"}));
7869 if(!data) return csheet;
7870 /* 21.2.2.27 chart CT_Chart */
7871
7872 var C = 0, R = 0, col = "A";
7873 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
7874
7875 /* 21.2.2.120 numCache CT_NumData */
7876 (data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
7877 var cache = parse_Cache(nc);
7878 refguess.s.r = refguess.s.c = 0;
7879 refguess.e.c = C;
7880 col = encode_col(C);
7881 cache[0].forEach(function(n,i) {
7882 cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
7883 R = i;
7884 });
7885 if(refguess.e.r < R) refguess.e.r = R;
7886 ++C;
7887 });
7888 if(C > 0) cs["!ref"] = encode_range(refguess);
7889 return cs;
7890}
7891RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
7892
7893var CS_XML_ROOT = writextag('chartsheet', null, {
7894 'xmlns': XMLNS.main[0],
7895 'xmlns:r': XMLNS.r
7896});
7897
7898/* 18.3 Worksheets also covers Chartsheets */
7899function parse_cs_xml(data, opts, idx, rels, wb) {
7900 if(!data) return data;
7901 /* 18.3.1.12 chartsheet CT_ChartSheet */
7902 if(!rels) rels = {'!id':{}};
7903 var s = ({'!type':"chart", '!drawel':null, '!rel':""});
7904 var m;
7905
7906 /* 18.3.1.83 sheetPr CT_ChartsheetPr */
7907 var sheetPr = data.match(sheetprregex);
7908 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
7909
7910 /* 18.3.1.36 drawing CT_Drawing */
7911 if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
7912
7913 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
7914 return s;
7915}
7916function write_cs_xml(idx, opts, wb, rels) {
7917 var o = [XML_HEADER, CS_XML_ROOT];
7918 o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
7919 add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
7920 if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
7921 return o.join("");
7922}
7923
7924/* [MS-XLSB] 2.4.331 BrtCsProp */
7925function parse_BrtCsProp(data, length) {
7926 data.l += 10;
7927 var name = parse_XLWideString(data, length - 10);
7928 return { name: name };
7929}
7930
7931/* [MS-XLSB] 2.1.7.7 Chart Sheet */
7932function parse_cs_bin(data, opts, idx, rels, wb) {
7933 if(!data) return data;
7934 if(!rels) rels = {'!id':{}};
7935 var s = {'!type':"chart", '!drawel':null, '!rel':""};
7936 var state = [];
7937 var pass = false;
7938 recordhopper(data, function cs_parse(val, R_n, RT) {
7939 switch(RT) {
7940
7941 case 0x0226: /* 'BrtDrawing' */
7942 s['!rel'] = val; break;
7943
7944 case 0x028B: /* 'BrtCsProp' */
7945 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
7946 if(val.name) wb.Sheets[idx].CodeName = val.name;
7947 break;
7948
7949 case 0x0232: /* 'BrtBkHim' */
7950 case 0x028C: /* 'BrtCsPageSetup' */
7951 case 0x029D: /* 'BrtCsProtection' */
7952 case 0x02A7: /* 'BrtCsProtectionIso' */
7953 case 0x0227: /* 'BrtLegacyDrawing' */
7954 case 0x0228: /* 'BrtLegacyDrawingHF' */
7955 case 0x01DC: /* 'BrtMargins' */
7956 case 0x0C00: /* 'BrtUid' */
7957 break;
7958
7959 case 0x0023: /* 'BrtFRTBegin' */
7960 pass = true; break;
7961 case 0x0024: /* 'BrtFRTEnd' */
7962 pass = false; break;
7963 case 0x0025: /* 'BrtACBegin' */
7964 state.push(R_n); break;
7965 case 0x0026: /* 'BrtACEnd' */
7966 state.pop(); break;
7967
7968 default:
7969 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
7970 else if((R_n||"").indexOf("End") > 0) state.pop();
7971 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
7972 }
7973 }, opts);
7974
7975 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
7976 return s;
7977}
7978function write_cs_bin() {
7979 var ba = buf_array();
7980 write_record(ba, "BrtBeginSheet");
7981 /* [BrtCsProp] */
7982 /* CSVIEWS */
7983 /* [[BrtCsProtectionIso] BrtCsProtection] */
7984 /* [USERCSVIEWS] */
7985 /* [BrtMargins] */
7986 /* [BrtCsPageSetup] */
7987 /* [HEADERFOOTER] */
7988 /* BrtDrawing */
7989 /* [BrtLegacyDrawing] */
7990 /* [BrtLegacyDrawingHF] */
7991 /* [BrtBkHim] */
7992 /* [WEBPUBITEMS] */
7993 /* FRTCHARTSHEET */
7994 write_record(ba, "BrtEndSheet");
7995 return ba.end();
7996}
7997/* 18.2.28 (CT_WorkbookProtection) Defaults */
7998var WBPropsDef = [
7999 ['allowRefreshQuery', false, "bool"],
8000 ['autoCompressPictures', true, "bool"],
8001 ['backupFile', false, "bool"],
8002 ['checkCompatibility', false, "bool"],
8003 ['CodeName', ''],
8004 ['date1904', false, "bool"],
8005 ['defaultThemeVersion', 0, "int"],
8006 ['filterPrivacy', false, "bool"],
8007 ['hidePivotFieldList', false, "bool"],
8008 ['promptedSolutions', false, "bool"],
8009 ['publishItems', false, "bool"],
8010 ['refreshAllConnections', false, "bool"],
8011 ['saveExternalLinkValues', true, "bool"],
8012 ['showBorderUnselectedTables', true, "bool"],
8013 ['showInkAnnotation', true, "bool"],
8014 ['showObjects', 'all'],
8015 ['showPivotChartFilter', false, "bool"],
8016 ['updateLinks', 'userSet']
8017];
8018
8019/* 18.2.30 (CT_BookView) Defaults */
8020var WBViewDef = [
8021 ['activeTab', 0, "int"],
8022 ['autoFilterDateGrouping', true, "bool"],
8023 ['firstSheet', 0, "int"],
8024 ['minimized', false, "bool"],
8025 ['showHorizontalScroll', true, "bool"],
8026 ['showSheetTabs', true, "bool"],
8027 ['showVerticalScroll', true, "bool"],
8028 ['tabRatio', 600, "int"],
8029 ['visibility', 'visible']
8030 //window{Height,Width}, {x,y}Window
8031];
8032
8033/* 18.2.19 (CT_Sheet) Defaults */
8034var SheetDef = [
8035 //['state', 'visible']
8036];
8037
8038/* 18.2.2 (CT_CalcPr) Defaults */
8039var CalcPrDef = [
8040 ['calcCompleted', 'true'],
8041 ['calcMode', 'auto'],
8042 ['calcOnSave', 'true'],
8043 ['concurrentCalc', 'true'],
8044 ['fullCalcOnLoad', 'false'],
8045 ['fullPrecision', 'true'],
8046 ['iterate', 'false'],
8047 ['iterateCount', '100'],
8048 ['iterateDelta', '0.001'],
8049 ['refMode', 'A1']
8050];
8051
8052/* 18.2.3 (CT_CustomWorkbookView) Defaults */
8053/*var CustomWBViewDef = [
8054 ['autoUpdate', 'false'],
8055 ['changesSavedWin', 'false'],
8056 ['includeHiddenRowCol', 'true'],
8057 ['includePrintSettings', 'true'],
8058 ['maximized', 'false'],
8059 ['minimized', 'false'],
8060 ['onlySync', 'false'],
8061 ['personalView', 'false'],
8062 ['showComments', 'commIndicator'],
8063 ['showFormulaBar', 'true'],
8064 ['showHorizontalScroll', 'true'],
8065 ['showObjects', 'all'],
8066 ['showSheetTabs', 'true'],
8067 ['showStatusbar', 'true'],
8068 ['showVerticalScroll', 'true'],
8069 ['tabRatio', '600'],
8070 ['xWindow', '0'],
8071 ['yWindow', '0']
8072];*/
8073
8074function push_defaults_array(target, defaults) {
8075 for(var j = 0; j != target.length; ++j) { var w = target[j];
8076 for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
8077 if(w[z[0]] == null) w[z[0]] = z[1];
8078 else switch(z[2]) {
8079 case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
8080 case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
8081 }
8082 }
8083 }
8084}
8085function push_defaults(target, defaults) {
8086 for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
8087 if(target[z[0]] == null) target[z[0]] = z[1];
8088 else switch(z[2]) {
8089 case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
8090 case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
8091 }
8092 }
8093}
8094
8095function parse_wb_defaults(wb) {
8096 push_defaults(wb.WBProps, WBPropsDef);
8097 push_defaults(wb.CalcPr, CalcPrDef);
8098
8099 push_defaults_array(wb.WBView, WBViewDef);
8100 push_defaults_array(wb.Sheets, SheetDef);
8101
8102 _ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
8103}
8104
8105function safe1904(wb) {
8106 /* TODO: store date1904 somewhere else */
8107 if(!wb.Workbook) return "false";
8108 if(!wb.Workbook.WBProps) return "false";
8109 return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
8110}
8111
8112var badchars = "][*?\/\\".split("");
8113function check_ws_name(n, safe) {
8114 if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
8115 var _good = true;
8116 badchars.forEach(function(c) {
8117 if(n.indexOf(c) == -1) return;
8118 if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
8119 _good = false;
8120 });
8121 return _good;
8122}
8123function check_wb_names(N, S, codes) {
8124 N.forEach(function(n,i) {
8125 check_ws_name(n);
8126 for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
8127 if(codes) {
8128 var cn = (S && S[i] && S[i].CodeName) || n;
8129 if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
8130 }
8131 });
8132}
8133function check_wb(wb) {
8134 if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
8135 if(!wb.SheetNames.length) throw new Error("Workbook is empty");
8136 var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
8137 check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
8138 for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
8139 /* TODO: validate workbook */
8140}
8141/* 18.2 Workbook */
8142var wbnsregex = /<\w+:workbook/;
8143function parse_wb_xml(data, opts) {
8144 if(!data) throw new Error("Could not find file");
8145 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
8146 var pass = false, xmlns = "xmlns";
8147 var dname = {}, dnstart = 0;
8148 data.replace(tagregex, function xml_wb(x, idx) {
8149 var y = parsexmltag(x);
8150 switch(strip_ns(y[0])) {
8151 case '<?xml': break;
8152
8153 /* 18.2.27 workbook CT_Workbook 1 */
8154 case '<workbook':
8155 if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
8156 wb.xmlns = y[xmlns];
8157 break;
8158 case '</workbook>': break;
8159
8160 /* 18.2.13 fileVersion CT_FileVersion ? */
8161 case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
8162 case '<fileVersion/>': case '</fileVersion>': break;
8163
8164 /* 18.2.12 fileSharing CT_FileSharing ? */
8165 case '<fileSharing':
8166 break;
8167 case '<fileSharing/>': break;
8168
8169 /* 18.2.28 workbookPr CT_WorkbookPr ? */
8170 case '<workbookPr':
8171 case '<workbookPr/>':
8172 WBPropsDef.forEach(function(w) {
8173 if(y[w[0]] == null) return;
8174 switch(w[2]) {
8175 case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
8176 case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
8177 default: wb.WBProps[w[0]] = y[w[0]];
8178 }
8179 });
8180 if(y.codeName) wb.WBProps.CodeName = utf8read(y.codeName);
8181 break;
8182 case '</workbookPr>': break;
8183
8184 /* 18.2.29 workbookProtection CT_WorkbookProtection ? */
8185 case '<workbookProtection':
8186 break;
8187 case '<workbookProtection/>': break;
8188
8189 /* 18.2.1 bookViews CT_BookViews ? */
8190 case '<bookViews': case '<bookViews>': case '</bookViews>': break;
8191 /* 18.2.30 workbookView CT_BookView + */
8192 case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
8193 case '</workbookView>': break;
8194
8195 /* 18.2.20 sheets CT_Sheets 1 */
8196 case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
8197 /* 18.2.19 sheet CT_Sheet + */
8198 case '<sheet':
8199 switch(y.state) {
8200 case "hidden": y.Hidden = 1; break;
8201 case "veryHidden": y.Hidden = 2; break;
8202 default: y.Hidden = 0;
8203 }
8204 delete y.state;
8205 y.name = unescapexml(utf8read(y.name));
8206 delete y[0]; wb.Sheets.push(y); break;
8207 case '</sheet>': break;
8208
8209 /* 18.2.15 functionGroups CT_FunctionGroups ? */
8210 case '<functionGroups': case '<functionGroups/>': break;
8211 /* 18.2.14 functionGroup CT_FunctionGroup + */
8212 case '<functionGroup': break;
8213
8214 /* 18.2.9 externalReferences CT_ExternalReferences ? */
8215 case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
8216 /* 18.2.8 externalReference CT_ExternalReference + */
8217 case '<externalReference': break;
8218
8219 /* 18.2.6 definedNames CT_DefinedNames ? */
8220 case '<definedNames/>': break;
8221 case '<definedNames>': case '<definedNames': pass=true; break;
8222 case '</definedNames>': pass=false; break;
8223 /* 18.2.5 definedName CT_DefinedName + */
8224 case '<definedName': {
8225 dname = {};
8226 dname.Name = utf8read(y.name);
8227 if(y.comment) dname.Comment = y.comment;
8228 if(y.localSheetId) dname.Sheet = +y.localSheetId;
8229 if(parsexmlbool(y.hidden||"0")) dname.Hidden = true;
8230 dnstart = idx + x.length;
8231 } break;
8232 case '</definedName>': {
8233 dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
8234 wb.Names.push(dname);
8235 } break;
8236 case '<definedName/>': break;
8237
8238 /* 18.2.2 calcPr CT_CalcPr ? */
8239 case '<calcPr': delete y[0]; wb.CalcPr = y; break;
8240 case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
8241 case '</calcPr>': break;
8242
8243 /* 18.2.16 oleSize CT_OleSize ? (ref required) */
8244 case '<oleSize': break;
8245
8246 /* 18.2.4 customWorkbookViews CT_CustomWorkbookViews ? */
8247 case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
8248 /* 18.2.3 customWorkbookView CT_CustomWorkbookView + */
8249 case '<customWorkbookView': case '</customWorkbookView>': break;
8250
8251 /* 18.2.18 pivotCaches CT_PivotCaches ? */
8252 case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
8253 /* 18.2.17 pivotCache CT_PivotCache ? */
8254 case '<pivotCache': break;
8255
8256 /* 18.2.21 smartTagPr CT_SmartTagPr ? */
8257 case '<smartTagPr': case '<smartTagPr/>': break;
8258
8259 /* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
8260 case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
8261 /* 18.2.22 smartTagType CT_SmartTagType ? */
8262 case '<smartTagType': break;
8263
8264 /* 18.2.24 webPublishing CT_WebPublishing ? */
8265 case '<webPublishing': case '<webPublishing/>': break;
8266
8267 /* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
8268 case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
8269
8270 /* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
8271 case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
8272 /* 18.2.25 webPublishObject CT_WebPublishObject ? */
8273 case '<webPublishObject': break;
8274
8275 /* 18.2.10 extLst CT_ExtensionList ? */
8276 case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
8277 /* 18.2.7 ext CT_Extension + */
8278 case '<ext': pass=true; break; //TODO: check with versions of excel
8279 case '</ext>': pass=false; break;
8280
8281 /* Others */
8282 case '<ArchID': break;
8283 case '<AlternateContent':
8284 case '<AlternateContent>': pass=true; break;
8285 case '</AlternateContent>': pass=false; break;
8286
8287 /* TODO */
8288 case '<revisionPtr': break;
8289
8290 default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
8291 }
8292 return x;
8293 });
8294 if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
8295
8296 parse_wb_defaults(wb);
8297
8298 return wb;
8299}
8300
8301var WB_XML_ROOT = writextag('workbook', null, {
8302 'xmlns': XMLNS.main[0],
8303 //'xmlns:mx': XMLNS.mx,
8304 //'xmlns:s': XMLNS.main[0],
8305 'xmlns:r': XMLNS.r
8306});
8307
8308function write_wb_xml(wb) {
8309 var o = [XML_HEADER];
8310 o[o.length] = WB_XML_ROOT;
8311
8312 var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
8313
8314 /* fileVersion */
8315 /* fileSharing */
8316
8317 var workbookPr = ({codeName:"ThisWorkbook"});
8318 if(wb.Workbook && wb.Workbook.WBProps) {
8319 WBPropsDef.forEach(function(x) {
8320if((wb.Workbook.WBProps[x[0]]) == null) return;
8321 if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
8322 workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
8323 });
8324if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
8325 }
8326 o[o.length] = (writextag('workbookPr', null, workbookPr));
8327
8328 /* workbookProtection */
8329
8330 var sheets = wb.Workbook && wb.Workbook.Sheets || [];
8331 var i = 0;
8332
8333 /* bookViews only written if first worksheet is hidden */
8334 if(sheets && sheets[0] && !!sheets[0].Hidden) {
8335 o[o.length] = "<bookViews>";
8336 for(i = 0; i != wb.SheetNames.length; ++i) {
8337 if(!sheets[i]) break;
8338 if(!sheets[i].Hidden) break;
8339 }
8340 if(i == wb.SheetNames.length) i = 0;
8341 o[o.length] = '<workbookView firstSheet="' + i + '" activeTab="' + i + '"/>';
8342 o[o.length] = "</bookViews>";
8343 }
8344
8345 o[o.length] = "<sheets>";
8346 for(i = 0; i != wb.SheetNames.length; ++i) {
8347 var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
8348 sht.sheetId = ""+(i+1);
8349 sht["r:id"] = "rId"+(i+1);
8350 if(sheets[i]) switch(sheets[i].Hidden) {
8351 case 1: sht.state = "hidden"; break;
8352 case 2: sht.state = "veryHidden"; break;
8353 }
8354 o[o.length] = (writextag('sheet',null,sht));
8355 }
8356 o[o.length] = "</sheets>";
8357
8358 /* functionGroups */
8359 /* externalReferences */
8360
8361 if(write_names) {
8362 o[o.length] = "<definedNames>";
8363 if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
8364 var d = {name:n.Name};
8365 if(n.Comment) d.comment = n.Comment;
8366 if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
8367 if(n.Hidden) d.hidden = "1";
8368 if(!n.Ref) return;
8369 o[o.length] = writextag('definedName', escapexml(n.Ref), d);
8370 });
8371 o[o.length] = "</definedNames>";
8372 }
8373
8374 /* calcPr */
8375 /* oleSize */
8376 /* customWorkbookViews */
8377 /* pivotCaches */
8378 /* smartTagPr */
8379 /* smartTagTypes */
8380 /* webPublishing */
8381 /* fileRecoveryPr */
8382 /* webPublishObjects */
8383 /* extLst */
8384
8385 if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
8386 return o.join("");
8387}
8388function parse_wb(data, name, opts) {
8389 if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
8390 return parse_wb_xml((data), opts);
8391}
8392
8393function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
8394 if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
8395 return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
8396}
8397
8398function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
8399 if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
8400 return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
8401}
8402
8403function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
8404 if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
8405 return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
8406}
8407
8408function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
8409 if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
8410 return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
8411}
8412
8413function parse_sty(data, name, themes, opts) {
8414 if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
8415 return parse_sty_xml((data), themes, opts);
8416}
8417
8418function parse_theme(data, name, opts) {
8419 return parse_theme_xml(data, opts);
8420}
8421
8422function parse_sst(data, name, opts) {
8423 if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
8424 return parse_sst_xml((data), opts);
8425}
8426
8427function parse_cmnt(data, name, opts) {
8428 if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
8429 return parse_comments_xml((data), opts);
8430}
8431
8432function parse_cc(data, name, opts) {
8433 if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
8434 return parse_cc_xml((data), name, opts);
8435}
8436
8437function parse_xlink(data, rel, name, opts) {
8438 if(name.slice(-4)===".bin") return parse_xlink_bin((data), rel, name, opts);
8439 return parse_xlink_xml((data), rel, name, opts);
8440}
8441
8442function write_wb(wb, name, opts) {
8443 return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
8444}
8445
8446function write_ws(data, name, opts, wb, rels) {
8447 return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
8448}
8449
8450// eslint-disable-next-line no-unused-vars
8451function write_cs(data, name, opts, wb, rels) {
8452 return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
8453}
8454
8455function write_sty(data, name, opts) {
8456 return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
8457}
8458
8459function write_sst(data, name, opts) {
8460 return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
8461}
8462
8463function write_cmnt(data, name, opts) {
8464 return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
8465}
8466/*
8467function write_cc(data, name:string, opts) {
8468 return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
8469}
8470*/
8471/* note: browser DOM element cannot see mso- style attrs, must parse */
8472var HTML_ = (function() {
8473 function html_to_sheet(str, _opts) {
8474 var opts = _opts || {};
8475 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
8476 var ws = opts.dense ? ([]) : ({});
8477 str = str.replace(/<!--.*?-->/g, "");
8478 var mtch = str.match(/<table/i);
8479 if(!mtch) throw new Error("Invalid HTML: could not find <table>");
8480 var mtch2 = str.match(/<\/table/i);
8481 var i = mtch.index, j = mtch2 && mtch2.index || str.length;
8482 var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
8483 var R = -1, C = 0, RS = 0, CS = 0;
8484 var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
8485 var merges = [];
8486 for(i = 0; i < rows.length; ++i) {
8487 var row = rows[i].trim();
8488 var hd = row.slice(0,3).toLowerCase();
8489 if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
8490 if(hd != "<td" && hd != "<th") continue;
8491 var cells = row.split(/<\/t[dh]>/i);
8492 for(j = 0; j < cells.length; ++j) {
8493 var cell = cells[j].trim();
8494 if(!cell.match(/<t[dh]/i)) continue;
8495 var m = cell, cc = 0;
8496 /* TODO: parse styles etc */
8497 while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
8498 for(var midx = 0; midx < merges.length; ++midx) {
8499 var _merge = merges[midx];
8500 if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; }
8501 }
8502 var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
8503 CS = tag.colspan ? +tag.colspan : 1;
8504 if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
8505 var _t = tag.t || tag["data-t"] || "";
8506 /* TODO: generate stub cells */
8507 if(!m.length) { C += CS; continue; }
8508 m = htmldecode(m);
8509 if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
8510 if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
8511 if(!m.length) continue;
8512 var o = {t:'s', v:m};
8513 if(opts.raw || !m.trim().length || _t == 's'){}
8514 else if(m === 'TRUE') o = {t:'b', v:true};
8515 else if(m === 'FALSE') o = {t:'b', v:false};
8516 else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
8517 else if(!isNaN(fuzzydate(m).getDate())) {
8518 o = ({t:'d', v:parseDate(m)});
8519 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
8520 o.z = opts.dateNF || SSF._table[14];
8521 }
8522 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
8523 else ws[encode_cell({r:R, c:C})] = o;
8524 C += CS;
8525 }
8526 }
8527 ws['!ref'] = encode_range(range);
8528 if(merges.length) ws["!merges"] = merges;
8529 return ws;
8530 }
8531 function html_to_book(str, opts) {
8532 var mtch = str.match(/<table.*?>[\s\S]*?<\/table>/gi);
8533 if(!mtch || mtch.length == 0) throw new Error("Invalid HTML: could not find <table>");
8534 if(mtch.length == 1) return sheet_to_workbook(html_to_sheet(mtch[0], opts), opts);
8535 var wb = utils.book_new();
8536 mtch.forEach(function(s, idx) { utils.book_append_sheet(wb, html_to_sheet(s, opts), "Sheet" + (idx+1)); });
8537 return wb;
8538 }
8539 function make_html_row(ws, r, R, o) {
8540 var M = (ws['!merges'] ||[]);
8541 var oo = [];
8542 for(var C = r.s.c; C <= r.e.c; ++C) {
8543 var RS = 0, CS = 0;
8544 for(var j = 0; j < M.length; ++j) {
8545 if(M[j].s.r > R || M[j].s.c > C) continue;
8546 if(M[j].e.r < R || M[j].e.c < C) continue;
8547 if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
8548 RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
8549 }
8550 if(RS < 0) continue;
8551 var coord = encode_cell({r:R,c:C});
8552 var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
8553 /* TODO: html entities */
8554 var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
8555 var sp = ({});
8556 if(RS > 1) sp.rowspan = RS;
8557 if(CS > 1) sp.colspan = CS;
8558 if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
8559 else if(cell) {
8560 sp["data-t"] = cell && cell.t || 'z';
8561 if(cell.v != null) sp["data-v"] = cell.v;
8562 if(cell.z != null) sp["data-z"] = cell.z;
8563 if(cell.l && (cell.l.Target || "#").charAt(0) != "#") w = '<a href="' + cell.l.Target +'">' + w + '</a>';
8564 }
8565 sp.id = (o.id || "sjs") + "-" + coord;
8566 oo.push(writextag('td', w, sp));
8567 }
8568 var preamble = "<tr>";
8569 return preamble + oo.join("") + "</tr>";
8570 }
8571 function make_html_preamble(ws, R, o) {
8572 var out = [];
8573 return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
8574 }
8575 var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
8576 var _END = '</body></html>';
8577 function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
8578 var o = opts || {};
8579 var header = o.header != null ? o.header : _BEGIN;
8580 var footer = o.footer != null ? o.footer : _END;
8581 var out = [header];
8582 var r = decode_range(ws['!ref']);
8583 o.dense = Array.isArray(ws);
8584 out.push(make_html_preamble(ws, r, o));
8585 for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
8586 out.push("</table>" + footer);
8587 return out.join("");
8588
8589 }
8590 return {
8591 to_workbook: html_to_book,
8592 to_sheet: html_to_sheet,
8593 _row: make_html_row,
8594 BEGIN: _BEGIN,
8595 END: _END,
8596 _preamble: make_html_preamble,
8597 from_sheet: sheet_to_html
8598 };
8599})();
8600
8601function sheet_add_dom(ws, table, _opts) {
8602 var opts = _opts || {};
8603 if(DENSE != null) opts.dense = DENSE;
8604 var or_R = 0, or_C = 0;
8605 if(opts.origin != null) {
8606 if(typeof opts.origin == 'number') or_R = opts.origin;
8607 else {
8608 var _origin = typeof opts.origin == "string" ? decode_cell(opts.origin) : opts.origin;
8609 or_R = _origin.r; or_C = _origin.c;
8610 }
8611 }
8612 var rows = table.getElementsByTagName('tr');
8613 var sheetRows = Math.min(opts.sheetRows||10000000, rows.length);
8614 var range = {s:{r:0,c:0},e:{r:or_R,c:or_C}};
8615 if(ws["!ref"]) {
8616 var _range = decode_range(ws["!ref"]);
8617 range.s.r = Math.min(range.s.r, _range.s.r);
8618 range.s.c = Math.min(range.s.c, _range.s.c);
8619 range.e.r = Math.max(range.e.r, _range.e.r);
8620 range.e.c = Math.max(range.e.c, _range.e.c);
8621 if(or_R == -1) range.e.r = or_R = _range.e.r + 1;
8622 }
8623 var merges = [], midx = 0;
8624 var rowinfo = ws["!rows"] || (ws["!rows"] = []);
8625 var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
8626 if(!ws["!cols"]) ws['!cols'] = [];
8627 for(; _R < rows.length && R < sheetRows; ++_R) {
8628 var row = rows[_R];
8629 if (is_dom_element_hidden(row)) {
8630 if (opts.display) continue;
8631 rowinfo[R] = {hidden: true};
8632 }
8633 var elts = (row.children);
8634 for(_C = C = 0; _C < elts.length; ++_C) {
8635 var elt = elts[_C];
8636 if (opts.display && is_dom_element_hidden(elt)) continue;
8637 var v = elt.hasAttribute('data-v') ? elt.getAttribute('data-v') : elt.hasAttribute('v') ? elt.getAttribute('v') : htmldecode(elt.innerHTML);
8638 var z = elt.getAttribute('data-z') || elt.getAttribute('z');
8639 for(midx = 0; midx < merges.length; ++midx) {
8640 var m = merges[midx];
8641 if(m.s.c == C + or_C && m.s.r < R + or_R && R + or_R <= m.e.r) { C = m.e.c+1 - or_C; midx = -1; }
8642 }
8643 /* TODO: figure out how to extract nonstandard mso- style */
8644 CS = +elt.getAttribute("colspan") || 1;
8645 if( ((RS = (+elt.getAttribute("rowspan") || 1)))>1 || CS>1) merges.push({s:{r:R + or_R,c:C + or_C},e:{r:R + or_R + (RS||1) - 1, c:C + or_C + (CS||1) - 1}});
8646 var o = {t:'s', v:v};
8647 var _t = elt.getAttribute("data-t") || elt.getAttribute("t") || "";
8648 if(v != null) {
8649 if(v.length == 0) o.t = _t || 'z';
8650 else if(opts.raw || v.trim().length == 0 || _t == "s"){}
8651 else if(v === 'TRUE') o = {t:'b', v:true};
8652 else if(v === 'FALSE') o = {t:'b', v:false};
8653 else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
8654 else if(!isNaN(fuzzydate(v).getDate())) {
8655 o = ({t:'d', v:parseDate(v)});
8656 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
8657 o.z = opts.dateNF || SSF._table[14];
8658 }
8659 }
8660 if(o.z === undefined && z != null) o.z = z;
8661 /* The first link is used. Links are assumed to be fully specified.
8662 * TODO: The right way to process relative links is to make a new <a> */
8663 var l = "", Aelts = elt.getElementsByTagName("A");
8664 if(Aelts && Aelts.length) for(var Aelti = 0; Aelti < Aelts.length; ++Aelti) if(Aelts[Aelti].hasAttribute("href")) {
8665 l = Aelts[Aelti].getAttribute("href"); if(l.charAt(0) != "#") break;
8666 }
8667 if(l && l.charAt(0) != "#") o.l = ({ Target: l });
8668 if(opts.dense) { if(!ws[R + or_R]) ws[R + or_R] = []; ws[R + or_R][C + or_C] = o; }
8669 else ws[encode_cell({c:C + or_C, r:R + or_R})] = o;
8670 if(range.e.c < C + or_C) range.e.c = C + or_C;
8671 C += CS;
8672 }
8673 ++R;
8674 }
8675 if(merges.length) ws['!merges'] = (ws["!merges"] || []).concat(merges);
8676 range.e.r = Math.max(range.e.r, R - 1 + or_R);
8677 ws['!ref'] = encode_range(range);
8678 if(R >= sheetRows) ws['!fullref'] = encode_range((range.e.r = rows.length-_R+R-1 + or_R,range)); // We can count the real number of rows to parse but we don't to improve the performance
8679 return ws;
8680}
8681
8682function parse_dom_table(table, _opts) {
8683 var opts = _opts || {};
8684 var ws = opts.dense ? ([]) : ({});
8685 return sheet_add_dom(ws, table, _opts);
8686}
8687
8688function table_to_book(table, opts) {
8689 return sheet_to_workbook(parse_dom_table(table, opts), opts);
8690}
8691
8692function is_dom_element_hidden(element) {
8693 var display = '';
8694 var get_computed_style = get_get_computed_style_function(element);
8695 if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
8696 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)
8697 return display === 'none';
8698}
8699
8700/* global getComputedStyle */
8701function get_get_computed_style_function(element) {
8702 // The proper getComputedStyle implementation is the one defined in the element window
8703 if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
8704 // If it is not available, try to get one from the global namespace
8705 if(typeof getComputedStyle === 'function') return getComputedStyle;
8706 return null;
8707}
8708/* OpenDocument */
8709var parse_content_xml = (function() {
8710
8711 var parse_text_p = function(text) {
8712 /* 6.1.2 White Space Characters */
8713 var fixed = text
8714 .replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
8715 .replace(/<text:s\/>/g," ")
8716 .replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
8717 .replace(/<text:tab[^>]*\/>/g,"\t")
8718 .replace(/<text:line-break\/>/g,"\n");
8719 var v = unescapexml(fixed.replace(/<[^>]*>/g,""));
8720
8721 return [v];
8722 };
8723
8724 var number_formats = {
8725 /* ods name: [short ssf fmt, long ssf fmt] */
8726 day: ["d", "dd"],
8727 month: ["m", "mm"],
8728 year: ["y", "yy"],
8729 hours: ["h", "hh"],
8730 minutes: ["m", "mm"],
8731 seconds: ["s", "ss"],
8732 "am-pm": ["A/P", "AM/PM"],
8733 "day-of-week": ["ddd", "dddd"],
8734 era: ["e", "ee"],
8735 /* there is no native representation of LO "Q" format */
8736 quarter: ["\\Qm", "m\\\"th quarter\""]
8737 };
8738
8739 return function pcx(d, _opts) {
8740 var opts = _opts || {};
8741 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
8742 var str = xlml_normalize(d);
8743 var state = [], tmp;
8744 var tag;
8745 var NFtag = {name:""}, NF = "", pidx = 0;
8746 var sheetag;
8747 var rowtag;
8748 var Sheets = {}, SheetNames = [];
8749 var ws = opts.dense ? ([]) : ({});
8750 var Rn, q;
8751 var ctag = ({value:""});
8752 var textp = "", textpidx = 0, textptag;
8753 var textR = [];
8754 var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
8755 var row_ol = 0;
8756 var number_format_map = {};
8757 var merges = [], mrange = {}, mR = 0, mC = 0;
8758 var rowinfo = [], rowpeat = 1, colpeat = 1;
8759 var arrayf = [];
8760 var WB = {Names:[]};
8761 var atag = ({});
8762 var _Ref = ["", ""];
8763 var comments = [], comment = ({});
8764 var creator = "", creatoridx = 0;
8765 var isstub = false, intable = false;
8766 var i = 0;
8767 xlmlregex.lastIndex = 0;
8768 str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
8769 while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
8770
8771 case 'table': case '工作表': // 9.1.2 <table:table>
8772 if(Rn[1]==='/') {
8773 if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
8774 else ws['!ref'] = "A1:A1";
8775 if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
8776 ws['!fullref'] = ws['!ref'];
8777 range.e.r = opts.sheetRows - 1;
8778 ws['!ref'] = encode_range(range);
8779 }
8780 if(merges.length) ws['!merges'] = merges;
8781 if(rowinfo.length) ws["!rows"] = rowinfo;
8782 sheetag.name = sheetag['名称'] || sheetag.name;
8783 if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
8784 SheetNames.push(sheetag.name);
8785 Sheets[sheetag.name] = ws;
8786 intable = false;
8787 }
8788 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
8789 sheetag = parsexmltag(Rn[0], false);
8790 R = C = -1;
8791 range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
8792 ws = opts.dense ? ([]) : ({}); merges = [];
8793 rowinfo = [];
8794 intable = true;
8795 }
8796 break;
8797
8798 case 'table-row-group': // 9.1.9 <table:table-row-group>
8799 if(Rn[1] === "/") --row_ol; else ++row_ol;
8800 break;
8801 case 'table-row': case '行': // 9.1.3 <table:table-row>
8802 if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
8803 rowtag = parsexmltag(Rn[0], false);
8804 if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
8805 rowpeat = +rowtag['number-rows-repeated'] || 1;
8806 /* TODO: remove magic */
8807 if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
8808 C = -1; break;
8809 case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
8810 if(Rn[1] !== '/') ++C;
8811 if(opts.sheetStubs) {
8812 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
8813 else ws[encode_cell({r:R,c:C})] = {t:'z'};
8814 }
8815 textp = ""; textR = [];
8816 break; /* stub */
8817 case 'table-cell': case '数据':
8818 if(Rn[0].charAt(Rn[0].length-2) === '/') {
8819 ++C;
8820 ctag = parsexmltag(Rn[0], false);
8821 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
8822 q = ({t:'z', v:null});
8823 if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
8824 if((ctag['数据类型'] || ctag['value-type']) == "string") {
8825 q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
8826 if(opts.dense) {
8827 if(!ws[R]) ws[R] = [];
8828 ws[R][C] = q;
8829 } else {
8830 ws[encode_cell({r:R,c:C})] = q;
8831 }
8832 }
8833 C+= colpeat-1;
8834 } else if(Rn[1]!=='/') {
8835 ++C;
8836 textp = ""; textpidx = 0; textR = [];
8837 colpeat = 1;
8838 var rptR = rowpeat ? R + rowpeat - 1 : R;
8839 if(C > range.e.c) range.e.c = C;
8840 if(C < range.s.c) range.s.c = C;
8841 if(R < range.s.r) range.s.r = R;
8842 if(rptR > range.e.r) range.e.r = rptR;
8843 ctag = parsexmltag(Rn[0], false);
8844 comments = []; comment = ({});
8845 q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
8846 if(opts.cellFormula) {
8847 if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
8848 if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
8849 mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
8850 mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
8851 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
8852 q.F = encode_range(mrange);
8853 arrayf.push([mrange, q.F]);
8854 }
8855 if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
8856 else for(i = 0; i < arrayf.length; ++i)
8857 if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
8858 if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
8859 q.F = arrayf[i][1];
8860 }
8861 if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
8862 mR = parseInt(ctag['number-rows-spanned'],10) || 0;
8863 mC = parseInt(ctag['number-columns-spanned'],10) || 0;
8864 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
8865 merges.push(mrange);
8866 }
8867
8868 /* 19.675.2 table:number-columns-repeated */
8869 if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
8870
8871 /* 19.385 office:value-type */
8872 switch(q.t) {
8873 case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
8874 case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
8875 case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
8876 case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
8877 case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
8878 if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
8879 q.z = 'm/d/yy'; break;
8880 case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400;
8881 if(opts.cellDates) { q.t = 'd'; q.v = numdate(q.v); }
8882 q.z = 'HH:MM:SS'; break;
8883 case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
8884 default:
8885 if(q.t === 'string' || q.t === 'text' || !q.t) {
8886 q.t = 's';
8887 if(ctag['string-value'] != null) { textp = unescapexml(ctag['string-value']); textR = []; }
8888 } else throw new Error('Unsupported value type ' + q.t);
8889 }
8890 } else {
8891 isstub = false;
8892 if(q.t === 's') {
8893 q.v = textp || '';
8894 if(textR.length) q.R = textR;
8895 isstub = textpidx == 0;
8896 }
8897 if(atag.Target) q.l = atag;
8898 if(comments.length > 0) { q.c = comments; comments = []; }
8899 if(textp && opts.cellText !== false) q.w = textp;
8900 if(isstub) { q.t = "z"; delete q.v; }
8901 if(!isstub || opts.sheetStubs) {
8902 if(!(opts.sheetRows && opts.sheetRows <= R)) {
8903 for(var rpt = 0; rpt < rowpeat; ++rpt) {
8904 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
8905 if(opts.dense) {
8906 if(!ws[R + rpt]) ws[R + rpt] = [];
8907 ws[R + rpt][C] = rpt == 0 ? q : dup(q);
8908 while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
8909 } else {
8910 ws[encode_cell({r:R + rpt,c:C})] = q;
8911 while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
8912 }
8913 if(range.e.c <= C) range.e.c = C;
8914 }
8915 }
8916 }
8917 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
8918 C += colpeat-1; colpeat = 0;
8919 q = {};
8920 textp = ""; textR = [];
8921 }
8922 atag = ({});
8923 break; // 9.1.4 <table:table-cell>
8924
8925 /* pure state */
8926 case 'document': // TODO: <office:document> is the root for FODS
8927 case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
8928 case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
8929 case 'scripts': // 3.12 <office:scripts>
8930 case 'styles': // TODO <office:styles>
8931 case 'font-face-decls': // 3.14 <office:font-face-decls>
8932 case 'master-styles': // 3.15.4 <office:master-styles> -- relevant for FODS
8933 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
8934 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
8935 break;
8936
8937 case 'annotation': // 14.1 <office:annotation>
8938 if(Rn[1]==='/'){
8939 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
8940 comment.t = textp;
8941 if(textR.length) comment.R = textR;
8942 comment.a = creator;
8943 comments.push(comment);
8944 }
8945 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
8946 creator = ""; creatoridx = 0;
8947 textp = ""; textpidx = 0; textR = [];
8948 break;
8949
8950 case 'creator': // 4.3.2.7 <dc:creator>
8951 if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
8952 else creatoridx = Rn.index + Rn[0].length;
8953 break;
8954
8955 /* ignore state */
8956 case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
8957 case 'settings': // TODO: <office:settings>
8958 case 'config-item-set': // TODO: <office:config-item-set>
8959 case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
8960 case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
8961 case 'config-item-map-named': // TODO: <office:config-item-map-entry>
8962 case 'shapes': // 9.2.8 <table:shapes>
8963 case 'frame': // 10.4.2 <draw:frame>
8964 case 'text-box': // 10.4.3 <draw:text-box>
8965 case 'image': // 10.4.4 <draw:image>
8966 case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
8967 case 'list-style': // 16.30 <text:list-style>
8968 case 'form': // 13.13 <form:form>
8969 case 'dde-links': // 9.8 <table:dde-links>
8970 case 'event-listeners': // TODO
8971 case 'chart': // TODO
8972 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
8973 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
8974 textp = ""; textpidx = 0; textR = [];
8975 break;
8976
8977 case 'scientific-number': // TODO: <number:scientific-number>
8978 break;
8979 case 'currency-symbol': // TODO: <number:currency-symbol>
8980 break;
8981 case 'currency-style': // TODO: <number:currency-style>
8982 break;
8983 case 'number-style': // 16.27.2 <number:number-style>
8984 case 'percentage-style': // 16.27.9 <number:percentage-style>
8985 case 'date-style': // 16.27.10 <number:date-style>
8986 case 'time-style': // 16.27.18 <number:time-style>
8987 if(Rn[1]==='/'){
8988 number_format_map[NFtag.name] = NF;
8989 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
8990 } else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
8991 NF = "";
8992 NFtag = parsexmltag(Rn[0], false);
8993 state.push([Rn[3], true]);
8994 } break;
8995
8996 case 'script': break; // 3.13 <office:script>
8997 case 'libraries': break; // TODO: <ooo:libraries>
8998 case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
8999
9000 case 'default-style': // TODO: <style:default-style>
9001 case 'page-layout': break; // TODO: <style:page-layout>
9002 case 'style': // 16.2 <style:style>
9003 break;
9004 case 'map': break; // 16.3 <style:map>
9005 case 'font-face': break; // 16.21 <style:font-face>
9006
9007 case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
9008 case 'table-properties': break; // 17.15 <style:table-properties>
9009 case 'table-column-properties': break; // 17.16 <style:table-column-properties>
9010 case 'table-row-properties': break; // 17.17 <style:table-row-properties>
9011 case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
9012
9013 case 'number': // 16.27.3 <number:number>
9014 switch(state[state.length-1][0]) {
9015 case 'time-style':
9016 case 'date-style':
9017 tag = parsexmltag(Rn[0], false);
9018 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
9019 } break;
9020
9021 case 'fraction': break; // TODO 16.27.6 <number:fraction>
9022
9023 case 'day': // 16.27.11 <number:day>
9024 case 'month': // 16.27.12 <number:month>
9025 case 'year': // 16.27.13 <number:year>
9026 case 'era': // 16.27.14 <number:era>
9027 case 'day-of-week': // 16.27.15 <number:day-of-week>
9028 case 'week-of-year': // 16.27.16 <number:week-of-year>
9029 case 'quarter': // 16.27.17 <number:quarter>
9030 case 'hours': // 16.27.19 <number:hours>
9031 case 'minutes': // 16.27.20 <number:minutes>
9032 case 'seconds': // 16.27.21 <number:seconds>
9033 case 'am-pm': // 16.27.22 <number:am-pm>
9034 switch(state[state.length-1][0]) {
9035 case 'time-style':
9036 case 'date-style':
9037 tag = parsexmltag(Rn[0], false);
9038 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
9039 } break;
9040
9041 case 'boolean-style': break; // 16.27.23 <number:boolean-style>
9042 case 'boolean': break; // 16.27.24 <number:boolean>
9043 case 'text-style': break; // 16.27.25 <number:text-style>
9044 case 'text': // 16.27.26 <number:text>
9045 if(Rn[0].slice(-2) === "/>") break;
9046 else if(Rn[1]==="/") switch(state[state.length-1][0]) {
9047 case 'number-style':
9048 case 'date-style':
9049 case 'time-style':
9050 NF += str.slice(pidx, Rn.index);
9051 break;
9052 }
9053 else pidx = Rn.index + Rn[0].length;
9054 break;
9055
9056 case 'named-range': // 9.4.12 <table:named-range>
9057 tag = parsexmltag(Rn[0], false);
9058 _Ref = ods_to_csf_3D(tag['cell-range-address']);
9059 var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
9060 if(intable) nrange.Sheet = SheetNames.length;
9061 WB.Names.push(nrange);
9062 break;
9063
9064 case 'text-content': break; // 16.27.27 <number:text-content>
9065 case 'text-properties': break; // 16.27.27 <style:text-properties>
9066 case 'embedded-text': break; // 16.27.4 <number:embedded-text>
9067
9068 case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
9069
9070 case 'forms': break; // 12.25.2 13.2
9071 case 'table-column': break; // 9.1.6 <table:table-column>
9072 case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
9073 case 'table-rows': break; // 9.1.12 <table:table-rows>
9074 /* TODO: outline levels */
9075 case 'table-column-group': break; // 9.1.10 <table:table-column-group>
9076 case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
9077 case 'table-columns': break; // 9.1.12 <table:table-columns>
9078
9079 case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
9080
9081 case 'graphic-properties': break; // 17.21 <style:graphic-properties>
9082 case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
9083 case 'named-expressions': break; // 9.4.11 <table:named-expressions>
9084 case 'label-range': break; // 9.4.9 <table:label-range>
9085 case 'label-ranges': break; // 9.4.10 <table:label-ranges>
9086 case 'named-expression': break; // 9.4.13 <table:named-expression>
9087 case 'sort': break; // 9.4.19 <table:sort>
9088 case 'sort-by': break; // 9.4.20 <table:sort-by>
9089 case 'sort-groups': break; // 9.4.22 <table:sort-groups>
9090
9091 case 'tab': break; // 6.1.4 <text:tab>
9092 case 'line-break': break; // 6.1.5 <text:line-break>
9093 case 'span': break; // 6.1.7 <text:span>
9094 case 'p': case '文本串': // 5.1.3 <text:p>
9095 if(['master-styles'].indexOf(state[state.length-1][0]) > -1) break;
9096 if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) {
9097 var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
9098 textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0];
9099 } else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
9100 break; // <text:p>
9101 case 's': break; // <text:s>
9102
9103 case 'database-range': // 9.4.15 <table:database-range>
9104 if(Rn[1]==='/') break;
9105 try {
9106 _Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
9107 Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
9108 } catch(e) {/* empty */}
9109 break;
9110
9111 case 'date': break; // <*:date>
9112
9113 case 'object': break; // 10.4.6.2 <draw:object>
9114 case 'title': case '标题': break; // <*:title> OR <uof:标题>
9115 case 'desc': break; // <*:desc>
9116 case 'binary-data': break; // 10.4.5 TODO: b64 blob
9117
9118 /* 9.2 Advanced Tables */
9119 case 'table-source': break; // 9.2.6
9120 case 'scenario': break; // 9.2.6
9121
9122 case 'iteration': break; // 9.4.3 <table:iteration>
9123 case 'content-validations': break; // 9.4.4 <table:
9124 case 'content-validation': break; // 9.4.5 <table:
9125 case 'help-message': break; // 9.4.6 <table:
9126 case 'error-message': break; // 9.4.7 <table:
9127 case 'database-ranges': break; // 9.4.14 <table:database-ranges>
9128 case 'filter': break; // 9.5.2 <table:filter>
9129 case 'filter-and': break; // 9.5.3 <table:filter-and>
9130 case 'filter-or': break; // 9.5.4 <table:filter-or>
9131 case 'filter-condition': break; // 9.5.5 <table:filter-condition>
9132
9133 case 'list-level-style-bullet': break; // 16.31 <text:
9134 case 'list-level-style-number': break; // 16.32 <text:
9135 case 'list-level-properties': break; // 17.19 <style:
9136
9137 /* 7.3 Document Fields */
9138 case 'sender-firstname': // 7.3.6.2
9139 case 'sender-lastname': // 7.3.6.3
9140 case 'sender-initials': // 7.3.6.4
9141 case 'sender-title': // 7.3.6.5
9142 case 'sender-position': // 7.3.6.6
9143 case 'sender-email': // 7.3.6.7
9144 case 'sender-phone-private': // 7.3.6.8
9145 case 'sender-fax': // 7.3.6.9
9146 case 'sender-company': // 7.3.6.10
9147 case 'sender-phone-work': // 7.3.6.11
9148 case 'sender-street': // 7.3.6.12
9149 case 'sender-city': // 7.3.6.13
9150 case 'sender-postal-code': // 7.3.6.14
9151 case 'sender-country': // 7.3.6.15
9152 case 'sender-state-or-province': // 7.3.6.16
9153 case 'author-name': // 7.3.7.1
9154 case 'author-initials': // 7.3.7.2
9155 case 'chapter': // 7.3.8
9156 case 'file-name': // 7.3.9
9157 case 'template-name': // 7.3.9
9158 case 'sheet-name': // 7.3.9
9159 break;
9160
9161 case 'event-listener':
9162 break;
9163 /* TODO: FODS Properties */
9164 case 'initial-creator':
9165 case 'creation-date':
9166 case 'print-date':
9167 case 'generator':
9168 case 'document-statistic':
9169 case 'user-defined':
9170 case 'editing-duration':
9171 case 'editing-cycles':
9172 break;
9173
9174 /* TODO: FODS Config */
9175 case 'config-item':
9176 break;
9177
9178 /* TODO: style tokens */
9179 case 'page-number': break; // TODO <text:page-number>
9180 case 'page-count': break; // TODO <text:page-count>
9181 case 'time': break; // TODO <text:time>
9182
9183 /* 9.3 Advanced Table Cells */
9184 case 'cell-range-source': break; // 9.3.1 <table:
9185 case 'detective': break; // 9.3.2 <table:
9186 case 'operation': break; // 9.3.3 <table:
9187 case 'highlighted-range': break; // 9.3.4 <table:
9188
9189 /* 9.6 Data Pilot Tables <table: */
9190 case 'data-pilot-table': // 9.6.3
9191 case 'source-cell-range': // 9.6.5
9192 case 'source-service': // 9.6.6
9193 case 'data-pilot-field': // 9.6.7
9194 case 'data-pilot-level': // 9.6.8
9195 case 'data-pilot-subtotals': // 9.6.9
9196 case 'data-pilot-subtotal': // 9.6.10
9197 case 'data-pilot-members': // 9.6.11
9198 case 'data-pilot-member': // 9.6.12
9199 case 'data-pilot-display-info': // 9.6.13
9200 case 'data-pilot-sort-info': // 9.6.14
9201 case 'data-pilot-layout-info': // 9.6.15
9202 case 'data-pilot-field-reference': // 9.6.16
9203 case 'data-pilot-groups': // 9.6.17
9204 case 'data-pilot-group': // 9.6.18
9205 case 'data-pilot-group-member': // 9.6.19
9206 break;
9207
9208 /* 10.3 Drawing Shapes */
9209 case 'rect': // 10.3.2
9210 break;
9211
9212 /* 14.6 DDE Connections */
9213 case 'dde-connection-decls': // 14.6.2 <text:
9214 case 'dde-connection-decl': // 14.6.3 <text:
9215 case 'dde-link': // 14.6.4 <table:
9216 case 'dde-source': // 14.6.5 <office:
9217 break;
9218
9219 case 'properties': break; // 13.7 <form:properties>
9220 case 'property': break; // 13.8 <form:property>
9221
9222 case 'a': // 6.1.8 hyperlink
9223 if(Rn[1]!== '/') {
9224 atag = parsexmltag(Rn[0], false);
9225 if(!atag.href) break;
9226 atag.Target = unescapexml(atag.href); delete atag.href;
9227 if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
9228 _Ref = ods_to_csf_3D(atag.Target.slice(1));
9229 atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
9230 } else if(atag.Target.match(/^\.\.[\\\/]/)) atag.Target = atag.Target.slice(3);
9231 }
9232 break;
9233
9234 /* non-standard */
9235 case 'table-protection': break;
9236 case 'data-pilot-grand-total': break; // <table:
9237 case 'office-document-common-attrs': break; // bare
9238 default: switch(Rn[2]) {
9239 case 'dc:': // TODO: properties
9240 case 'calcext:': // ignore undocumented extensions
9241 case 'loext:': // ignore undocumented extensions
9242 case 'ooo:': // ignore undocumented extensions
9243 case 'chartooo:': // ignore undocumented extensions
9244 case 'draw:': // TODO: drawing
9245 case 'style:': // TODO: styles
9246 case 'chart:': // TODO: charts
9247 case 'form:': // TODO: forms
9248 case 'uof:': // TODO: uof
9249 case '表:': // TODO: uof
9250 case '字:': // TODO: uof
9251 break;
9252 default: if(opts.WTF) throw new Error(Rn);
9253 }
9254 }
9255 var out = ({
9256 Sheets: Sheets,
9257 SheetNames: SheetNames,
9258 Workbook: WB
9259 });
9260 if(opts.bookSheets) delete out.Sheets;
9261 return out;
9262 };
9263})();
9264
9265function parse_ods(zip, opts) {
9266 opts = opts || ({});
9267 if(safegetzipfile(zip, 'META-INF/manifest.xml')) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
9268 var content = getzipstr(zip, 'content.xml');
9269 if(!content) throw new Error("Missing content.xml in ODS / UOF file");
9270 var wb = parse_content_xml(utf8read(content), opts);
9271 if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
9272 return wb;
9273}
9274function parse_fods(data, opts) {
9275 return parse_content_xml(data, opts);
9276}
9277
9278/* OpenDocument */
9279var write_styles_ods = (function() {
9280 var master_styles = '<office:master-styles>'
9281 + '<style:master-page style:name="mp1" style:page-layout-name="mp1">'
9282 + '<style:header/>'
9283 + '<style:header-left style:display="false"/>'
9284 + '<style:footer/>'
9285 + '<style:footer-left style:display="false"/>'
9286 + '</style:master-page>'
9287 + '</office:master-styles>';
9288
9289 var payload = '<office:document-styles ' + wxt_helper({
9290 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
9291 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
9292 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
9293 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
9294 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
9295 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
9296 'xmlns:xlink': "http://www.w3.org/1999/xlink",
9297 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
9298 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
9299 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
9300 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
9301 'office:version': "1.2"
9302 }) + '>' + master_styles + '</office:document-styles>';
9303
9304 return function wso() {
9305 return XML_HEADER + payload;
9306 };
9307})();
9308var write_content_ods = (function() {
9309 /* 6.1.2 White Space Characters */
9310 var write_text_p = function(text) {
9311 return escapexml(text)
9312 .replace(/ +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
9313 .replace(/\t/g, "<text:tab/>")
9314 .replace(/\n/g, "</text:p><text:p>")
9315 .replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
9316 };
9317
9318 var null_cell_xml = ' <table:table-cell />\n';
9319 var covered_cell_xml = ' <table:covered-table-cell/>\n';
9320 var write_ws = function(ws, wb, i) {
9321 /* Section 9 Tables */
9322 var o = [];
9323 o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="ta1">\n');
9324 var R=0,C=0, range = decode_range(ws['!ref']||"A1");
9325 var marr = ws['!merges'] || [], mi = 0;
9326 var dense = Array.isArray(ws);
9327 if(ws["!cols"]) {
9328 for(C = 0; C <= range.e.c; ++C) o.push(' <table:table-column' + (ws["!cols"][C] ? ' table:style-name="co' + ws["!cols"][C].ods + '"' : '') + '></table:table-column>\n');
9329 }
9330 var H = "", ROWS = ws["!rows"]||[];
9331 for(R = 0; R < range.s.r; ++R) {
9332 H = ROWS[R] ? ' table:style-name="ro' + ROWS[R].ods + '"' : "";
9333 o.push(' <table:table-row' + H + '></table:table-row>\n');
9334 }
9335 for(; R <= range.e.r; ++R) {
9336 H = ROWS[R] ? ' table:style-name="ro' + ROWS[R].ods + '"' : "";
9337 o.push(' <table:table-row' + H + '>\n');
9338 for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
9339 for(; C <= range.e.c; ++C) {
9340 var skip = false, ct = {}, textp = "";
9341 for(mi = 0; mi != marr.length; ++mi) {
9342 if(marr[mi].s.c > C) continue;
9343 if(marr[mi].s.r > R) continue;
9344 if(marr[mi].e.c < C) continue;
9345 if(marr[mi].e.r < R) continue;
9346 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
9347 ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
9348 ct['table:number-rows-spanned'] = (marr[mi].e.r - marr[mi].s.r + 1);
9349 break;
9350 }
9351 if(skip) { o.push(covered_cell_xml); continue; }
9352 var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
9353 if(cell && cell.f) {
9354 ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
9355 if(cell.F) {
9356 if(cell.F.slice(0, ref.length) == ref) {
9357 var _Fref = decode_range(cell.F);
9358 ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
9359 ct['table:number-matrix-rows-spanned'] = (_Fref.e.r - _Fref.s.r + 1);
9360 }
9361 }
9362 }
9363 if(!cell) { o.push(null_cell_xml); continue; }
9364 switch(cell.t) {
9365 case 'b':
9366 textp = (cell.v ? 'TRUE' : 'FALSE');
9367 ct['office:value-type'] = "boolean";
9368 ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
9369 break;
9370 case 'n':
9371 textp = (cell.w||String(cell.v||0));
9372 ct['office:value-type'] = "float";
9373 ct['office:value'] = (cell.v||0);
9374 break;
9375 case 's': case 'str':
9376 textp = cell.v == null ? "" : cell.v;
9377 ct['office:value-type'] = "string";
9378 break;
9379 case 'd':
9380 textp = (cell.w||(parseDate(cell.v).toISOString()));
9381 ct['office:value-type'] = "date";
9382 ct['office:date-value'] = (parseDate(cell.v).toISOString());
9383 ct['table:style-name'] = "ce1";
9384 break;
9385 //case 'e':
9386 default: o.push(null_cell_xml); continue;
9387 }
9388 var text_p = write_text_p(textp);
9389 if(cell.l && cell.l.Target) {
9390 var _tgt = cell.l.Target;
9391 _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
9392 // TODO: choose correct parent path format based on link delimiters
9393 if(_tgt.charAt(0) != "#" && !_tgt.match(/^\w+:/)) _tgt = '../' + _tgt;
9394 text_p = writextag('text:a', text_p, {'xlink:href': _tgt.replace(/&/g, "&amp;")});
9395 }
9396 o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
9397 }
9398 o.push(' </table:table-row>\n');
9399 }
9400 o.push(' </table:table>\n');
9401 return o.join("");
9402 };
9403
9404 var write_automatic_styles_ods = function(o, wb) {
9405 o.push(' <office:automatic-styles>\n');
9406
9407 o.push(' <number:date-style style:name="N37" number:automatic-order="true">\n');
9408 o.push(' <number:month number:style="long"/>\n');
9409 o.push(' <number:text>/</number:text>\n');
9410 o.push(' <number:day number:style="long"/>\n');
9411 o.push(' <number:text>/</number:text>\n');
9412 o.push(' <number:year/>\n');
9413 o.push(' </number:date-style>\n');
9414
9415 /* column styles */
9416 var cidx = 0;
9417 wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
9418 if(!ws) return;
9419 if(ws["!cols"]) {
9420 for(var C = 0; C < ws["!cols"].length; ++C) if(ws["!cols"][C]) {
9421 var colobj = ws["!cols"][C];
9422 if(colobj.width == null && colobj.wpx == null && colobj.wch == null) continue;
9423 process_col(colobj);
9424 colobj.ods = cidx;
9425 var w = ws["!cols"][C].wpx + "px";
9426 o.push(' <style:style style:name="co' + cidx + '" style:family="table-column">\n');
9427 o.push(' <style:table-column-properties fo:break-before="auto" style:column-width="' + w + '"/>\n');
9428 o.push(' </style:style>\n');
9429 ++cidx;
9430 }
9431 }
9432 });
9433
9434 /* row styles */
9435 var ridx = 0;
9436 wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
9437 if(!ws) return;
9438 if(ws["!rows"]) {
9439 for(var R = 0; R < ws["!rows"].length; ++R) if(ws["!rows"][R]) {
9440 ws["!rows"][R].ods = ridx;
9441 var h = ws["!rows"][R].hpx + "px";
9442 o.push(' <style:style style:name="ro' + ridx + '" style:family="table-row">\n');
9443 o.push(' <style:table-row-properties fo:break-before="auto" style:row-height="' + h + '"/>\n');
9444 o.push(' </style:style>\n');
9445 ++ridx;
9446 }
9447 }
9448 });
9449
9450 /* table */
9451 o.push(' <style:style style:name="ta1" style:family="table" style:master-page-name="mp1">\n');
9452 o.push(' <style:table-properties table:display="true" style:writing-mode="lr-tb"/>\n');
9453 o.push(' </style:style>\n');
9454
9455 /* table cells, text */
9456 o.push(' <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
9457
9458 /* page-layout */
9459
9460 o.push(' </office:automatic-styles>\n');
9461 };
9462
9463 return function wcx(wb, opts) {
9464 var o = [XML_HEADER];
9465 /* 3.1.3.2 */
9466 var attr = wxt_helper({
9467 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
9468 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
9469 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
9470 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
9471 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
9472 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
9473 'xmlns:xlink': "http://www.w3.org/1999/xlink",
9474 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
9475 'xmlns:meta': "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
9476 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
9477 'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
9478 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
9479 'xmlns:chart': "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
9480 'xmlns:dr3d': "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
9481 'xmlns:math': "http://www.w3.org/1998/Math/MathML",
9482 'xmlns:form': "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
9483 'xmlns:script': "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
9484 'xmlns:ooo': "http://openoffice.org/2004/office",
9485 'xmlns:ooow': "http://openoffice.org/2004/writer",
9486 'xmlns:oooc': "http://openoffice.org/2004/calc",
9487 'xmlns:dom': "http://www.w3.org/2001/xml-events",
9488 'xmlns:xforms': "http://www.w3.org/2002/xforms",
9489 'xmlns:xsd': "http://www.w3.org/2001/XMLSchema",
9490 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
9491 'xmlns:sheet': "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
9492 'xmlns:rpt': "http://openoffice.org/2005/report",
9493 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
9494 'xmlns:xhtml': "http://www.w3.org/1999/xhtml",
9495 'xmlns:grddl': "http://www.w3.org/2003/g/data-view#",
9496 'xmlns:tableooo': "http://openoffice.org/2009/table",
9497 'xmlns:drawooo': "http://openoffice.org/2010/draw",
9498 'xmlns:calcext': "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
9499 'xmlns:loext': "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
9500 'xmlns:field': "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
9501 'xmlns:formx': "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
9502 'xmlns:css3t': "http://www.w3.org/TR/css3-text/",
9503 'office:version': "1.2"
9504 });
9505
9506 var fods = wxt_helper({
9507 'xmlns:config': "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
9508 'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
9509 });
9510
9511 if(opts.bookType == "fods") {
9512 o.push('<office:document' + attr + fods + '>\n');
9513 o.push(write_meta_ods().replace(/office:document-meta/g, "office:meta"));
9514 // TODO: settings (equiv of settings.xml for ODS)
9515 } else o.push('<office:document-content' + attr + '>\n');
9516 // o.push(' <office:scripts/>\n');
9517 write_automatic_styles_ods(o, wb);
9518 o.push(' <office:body>\n');
9519 o.push(' <office:spreadsheet>\n');
9520 for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
9521 o.push(' </office:spreadsheet>\n');
9522 o.push(' </office:body>\n');
9523 if(opts.bookType == "fods") o.push('</office:document>');
9524 else o.push('</office:document-content>');
9525 return o.join("");
9526 };
9527})();
9528
9529function write_ods(wb, opts) {
9530 if(opts.bookType == "fods") return write_content_ods(wb, opts);
9531
9532 var zip = zip_new();
9533 var f = "";
9534
9535 var manifest = [];
9536 var rdf = [];
9537
9538 /* Part 3 Section 3.3 MIME Media Type */
9539 f = "mimetype";
9540 zip_add_file(zip, f, "application/vnd.oasis.opendocument.spreadsheet");
9541
9542 /* Part 1 Section 2.2 Documents */
9543 f = "content.xml";
9544 zip_add_file(zip, f, write_content_ods(wb, opts));
9545 manifest.push([f, "text/xml"]);
9546 rdf.push([f, "ContentFile"]);
9547
9548 /* TODO: these are hard-coded styles to satiate excel */
9549 f = "styles.xml";
9550 zip_add_file(zip, f, write_styles_ods(wb, opts));
9551 manifest.push([f, "text/xml"]);
9552 rdf.push([f, "StylesFile"]);
9553
9554 /* TODO: this is hard-coded to satiate excel */
9555 f = "meta.xml";
9556 zip_add_file(zip, f, XML_HEADER + write_meta_ods());
9557 manifest.push([f, "text/xml"]);
9558 rdf.push([f, "MetadataFile"]);
9559
9560 /* Part 3 Section 6 Metadata Manifest File */
9561 f = "manifest.rdf";
9562 zip_add_file(zip, f, write_rdf(rdf/*, opts*/));
9563 manifest.push([f, "application/rdf+xml"]);
9564
9565 /* Part 3 Section 4 Manifest File */
9566 f = "META-INF/manifest.xml";
9567 zip_add_file(zip, f, write_manifest(manifest/*, opts*/));
9568
9569 return zip;
9570}
9571
9572function write_sheet_index(wb, sheet) {
9573 if(!sheet) return 0;
9574 var idx = wb.SheetNames.indexOf(sheet);
9575 if(idx == -1) throw new Error("Sheet not found: " + sheet);
9576 return idx;
9577}
9578
9579function write_obj_str(factory) {
9580 return function write_str(wb, o) {
9581 var idx = write_sheet_index(wb, o.sheet);
9582 return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
9583 };
9584}
9585
9586var write_htm_str = write_obj_str(HTML_);
9587var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
9588var write_slk_str = write_obj_str(typeof SYLK !== "undefined" ? SYLK : {});
9589var write_dif_str = write_obj_str(typeof DIF !== "undefined" ? DIF : {});
9590var write_prn_str = write_obj_str(typeof PRN !== "undefined" ? PRN : {});
9591var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {});
9592var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
9593var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {});
9594var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {});
9595var write_wk1_buf = write_obj_str(typeof WK_ !== "undefined" ? {from_sheet:WK_.sheet_to_wk1} : {});
9596
9597function fix_opts_func(defaults) {
9598 return function fix_opts(opts) {
9599 for(var i = 0; i != defaults.length; ++i) {
9600 var d = defaults[i];
9601 if(opts[d[0]] === undefined) opts[d[0]] = d[1];
9602 if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
9603 }
9604 };
9605}
9606
9607var fix_read_opts = function(opts) {
9608fix_opts_func([
9609 ['cellNF', false], /* emit cell number format string as .z */
9610 ['cellHTML', true], /* emit html string as .h */
9611 ['cellFormula', true], /* emit formulae as .f */
9612 ['cellStyles', false], /* emits style/theme as .s */
9613 ['cellText', true], /* emit formatted text as .w */
9614 ['cellDates', false], /* emit date cells with type `d` */
9615
9616 ['sheetStubs', false], /* emit empty cells */
9617 ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
9618
9619 ['bookDeps', false], /* parse calculation chains */
9620 ['bookSheets', false], /* only try to get sheet names (no Sheets) */
9621 ['bookProps', false], /* only try to get properties (no Sheets) */
9622 ['bookFiles', false], /* include raw file structure (keys, files, cfb) */
9623 ['bookVBA', false], /* include vba raw data (vbaraw) */
9624
9625 ['password',''], /* password */
9626 ['WTF', false] /* WTF mode (throws errors) */
9627])(opts);
9628};
9629
9630var fix_write_opts = fix_opts_func([
9631 ['cellDates', false], /* write date cells with type `d` */
9632
9633 ['bookSST', false], /* Generate Shared String Table */
9634
9635 ['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
9636
9637 ['compression', false], /* Use file compression */
9638
9639 ['WTF', false] /* WTF mode (throws errors) */
9640]);
9641function get_sheet_type(n) {
9642 if(RELS.WS.indexOf(n) > -1) return "sheet";
9643 if(RELS.CS && n == RELS.CS) return "chart";
9644 if(RELS.DS && n == RELS.DS) return "dialog";
9645 if(RELS.MS && n == RELS.MS) return "macro";
9646 return (n && n.length) ? n : "sheet";
9647}
9648function safe_parse_wbrels(wbrels, sheets) {
9649 if(!wbrels) return 0;
9650 try {
9651 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)]; });
9652 } catch(e) { return null; }
9653 return !wbrels || wbrels.length === 0 ? null : wbrels;
9654}
9655
9656function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
9657 try {
9658 sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
9659 var data = getzipdata(zip, path);
9660 var _ws;
9661 switch(stype) {
9662 case 'sheet': _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
9663 case 'chart': _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
9664 if(!_ws || !_ws['!drawel']) break;
9665 var dfile = resolve_path(_ws['!drawel'].Target, path);
9666 var drelsp = get_rels_path(dfile);
9667 var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
9668 var chartp = resolve_path(draw, dfile);
9669 var crelsp = get_rels_path(chartp);
9670 _ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
9671 break;
9672 case 'macro': _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
9673 case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
9674 default: throw new Error("Unrecognized sheet type " + stype);
9675 }
9676 sheets[sheet] = _ws;
9677
9678 /* scan rels for comments */
9679 var comments = [];
9680 if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) {
9681 if(sheetRels[sheet][n].Type == RELS.CMNT) {
9682 var dfile = resolve_path(sheetRels[sheet][n].Target, path);
9683 comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
9684 if(!comments || !comments.length) return;
9685 sheet_insert_comments(_ws, comments);
9686 }
9687 });
9688 } catch(e) { if(opts.WTF) throw e; }
9689}
9690
9691function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
9692
9693function parse_zip(zip, opts) {
9694 make_ssf(SSF);
9695 opts = opts || {};
9696 fix_read_opts(opts);
9697
9698 /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
9699 if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
9700 /* UOC */
9701 if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
9702 /* Numbers */
9703 if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
9704
9705 var entries = zipentries(zip);
9706 var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
9707 var xlsb = false;
9708 var sheets, binname;
9709 if(dir.workbooks.length === 0) {
9710 binname = "xl/workbook.xml";
9711 if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
9712 }
9713 if(dir.workbooks.length === 0) {
9714 binname = "xl/workbook.bin";
9715 if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
9716 dir.workbooks.push(binname);
9717 xlsb = true;
9718 }
9719 if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
9720
9721 var themes = ({});
9722 var styles = ({});
9723 if(!opts.bookSheets && !opts.bookProps) {
9724 strs = [];
9725 if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
9726
9727 if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
9728
9729 if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
9730 }
9731
9732 /*var externbooks = */dir.links.map(function(link) {
9733 try {
9734 var rels = parse_rels(getzipstr(zip, get_rels_path(strip_front_slash(link))), link);
9735 return parse_xlink(getzipdata(zip, strip_front_slash(link)), rels, link, opts);
9736 } catch(e) {}
9737 });
9738
9739 var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
9740
9741 var props = {}, propdata = "";
9742
9743 if(dir.coreprops.length) {
9744 propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
9745 if(propdata) props = parse_core_props(propdata);
9746 if(dir.extprops.length !== 0) {
9747 propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
9748 if(propdata) parse_ext_props(propdata, props, opts);
9749 }
9750 }
9751
9752 var custprops = {};
9753 if(!opts.bookSheets || opts.bookProps) {
9754 if (dir.custprops.length !== 0) {
9755 propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
9756 if(propdata) custprops = parse_cust_props(propdata, opts);
9757 }
9758 }
9759
9760 var out = ({});
9761 if(opts.bookSheets || opts.bookProps) {
9762 if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
9763 else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
9764 if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
9765 if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
9766 if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
9767 }
9768 sheets = {};
9769
9770 var deps = {};
9771 if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
9772
9773 var i=0;
9774 var sheetRels = ({});
9775 var path, relsPath;
9776
9777 {
9778 var wbsheets = wb.Sheets;
9779 props.Worksheets = wbsheets.length;
9780 props.SheetNames = [];
9781 for(var j = 0; j != wbsheets.length; ++j) {
9782 props.SheetNames[j] = wbsheets[j].name;
9783 }
9784 }
9785
9786 var wbext = xlsb ? "bin" : "xml";
9787 var wbrelsi = dir.workbooks[0].lastIndexOf("/");
9788 var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
9789 if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
9790 var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
9791 if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
9792
9793 /* Numbers iOS hack */
9794 var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
9795 wsloop: for(i = 0; i != props.Worksheets; ++i) {
9796 var stype = "sheet";
9797 if(wbrels && wbrels[i]) {
9798 path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
9799 if(!safegetzipfile(zip, path)) path = wbrels[i][1];
9800 if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
9801 stype = wbrels[i][2];
9802 } else {
9803 path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
9804 path = path.replace(/sheet0\./,"sheet.");
9805 }
9806 relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
9807 if(opts && opts.sheets != null) switch(typeof opts.sheets) {
9808 case "number": if(i != opts.sheets) continue wsloop; break;
9809 case "string": if(props.SheetNames[i].toLowerCase() != opts.sheets.toLowerCase()) continue wsloop; break;
9810 default: if(Array.isArray && Array.isArray(opts.sheets)) {
9811 var snjseen = false;
9812 for(var snj = 0; snj != opts.sheets.length; ++snj) {
9813 if(typeof opts.sheets[snj] == "number" && opts.sheets[snj] == i) snjseen=1;
9814 if(typeof opts.sheets[snj] == "string" && opts.sheets[snj].toLowerCase() == props.SheetNames[i].toLowerCase()) snjseen = 1;
9815 }
9816 if(!snjseen) continue wsloop;
9817 }
9818 }
9819 safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
9820 }
9821
9822 out = ({
9823 Directory: dir,
9824 Workbook: wb,
9825 Props: props,
9826 Custprops: custprops,
9827 Deps: deps,
9828 Sheets: sheets,
9829 SheetNames: props.SheetNames,
9830 Strings: strs,
9831 Styles: styles,
9832 Themes: themes,
9833 SSF: SSF.get_table()
9834 });
9835 if(opts && opts.bookFiles) {
9836 if(zip.files) {
9837 out.keys = entries;
9838 out.files = zip.files;
9839 } else {
9840 out.keys = [];
9841 out.files = {};
9842 zip.FullPaths.forEach(function(p, idx) {
9843 p = p.replace(/^Root Entry[\/]/, "");
9844 out.keys.push(p);
9845 out.files[p] = zip.FileIndex[idx];
9846 });
9847 }
9848 }
9849 if(opts && opts.bookVBA) {
9850 if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
9851 else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
9852 }
9853 return out;
9854}
9855
9856/* [MS-OFFCRYPTO] 2.1.1 */
9857function parse_xlsxcfb(cfb, _opts) {
9858 var opts = _opts || {};
9859 var f = 'Workbook', data = CFB.find(cfb, f);
9860 try {
9861 f = '/!DataSpaces/Version';
9862 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9863 /*var version = */parse_DataSpaceVersionInfo(data.content);
9864
9865 /* 2.3.4.1 */
9866 f = '/!DataSpaces/DataSpaceMap';
9867 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9868 var dsm = parse_DataSpaceMap(data.content);
9869 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")
9870 throw new Error("ECMA-376 Encrypted file bad " + f);
9871
9872 /* 2.3.4.2 */
9873 f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
9874 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9875 var seds = parse_DataSpaceDefinition(data.content);
9876 if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
9877 throw new Error("ECMA-376 Encrypted file bad " + f);
9878
9879 /* 2.3.4.3 */
9880 f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
9881 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9882 /*var hdr = */parse_Primary(data.content);
9883 } catch(e) {}
9884
9885 f = '/EncryptionInfo';
9886 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9887 var einfo = parse_EncryptionInfo(data.content);
9888
9889 /* 2.3.4.4 */
9890 f = '/EncryptedPackage';
9891 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9892
9893/*global decrypt_agile */
9894if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
9895/*global decrypt_std76 */
9896if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
9897 throw new Error("File is password-protected");
9898}
9899
9900function write_zip(wb, opts) {
9901 _shapeid = 1024;
9902 if(opts.bookType == "ods") return write_ods(wb, opts);
9903 if(wb && !wb.SSF) {
9904 wb.SSF = SSF.get_table();
9905 }
9906 if(wb && wb.SSF) {
9907 make_ssf(SSF); SSF.load_table(wb.SSF);
9908 // $FlowIgnore
9909 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
9910 opts.ssf = wb.SSF;
9911 }
9912 opts.rels = {}; opts.wbrels = {};
9913 opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
9914 if(browser_has_Map) opts.revStrings = new Map();
9915 else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
9916 var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
9917 var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
9918 var ct = new_ct();
9919 fix_write_opts(opts = opts || {});
9920 var zip = zip_new();
9921 var f = "", rId = 0;
9922
9923 opts.cellXfs = [];
9924 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
9925
9926 if(!wb.Props) wb.Props = {};
9927
9928 f = "docProps/core.xml";
9929 zip_add_file(zip, f, write_core_props(wb.Props, opts));
9930 ct.coreprops.push(f);
9931 add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
9932
9933f = "docProps/app.xml";
9934 if(wb.Props && wb.Props.SheetNames){/* empty */}
9935 else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
9936 else {
9937 var _sn = [];
9938 for(var _i = 0; _i < wb.SheetNames.length; ++_i)
9939 if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
9940 wb.Props.SheetNames = _sn;
9941 }
9942 wb.Props.Worksheets = wb.Props.SheetNames.length;
9943 zip_add_file(zip, f, write_ext_props(wb.Props, opts));
9944 ct.extprops.push(f);
9945 add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
9946
9947 if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
9948 f = "docProps/custom.xml";
9949 zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
9950 ct.custprops.push(f);
9951 add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
9952 }
9953
9954 for(rId=1;rId <= wb.SheetNames.length; ++rId) {
9955 var wsrels = {'!id':{}};
9956 var ws = wb.Sheets[wb.SheetNames[rId-1]];
9957 var _type = (ws || {})["!type"] || "sheet";
9958 switch(_type) {
9959 case "chart":
9960 /* falls through */
9961 default:
9962 f = "xl/worksheets/sheet" + rId + "." + wbext;
9963 zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels));
9964 ct.sheets.push(f);
9965 add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
9966 }
9967
9968 if(ws) {
9969 var comments = ws['!comments'];
9970 var need_vml = false;
9971 if(comments && comments.length > 0) {
9972 var cf = "xl/comments" + rId + "." + wbext;
9973 zip_add_file(zip, cf, write_cmnt(comments, cf, opts));
9974 ct.comments.push(cf);
9975 add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
9976 need_vml = true;
9977 }
9978 if(ws['!legacy']) {
9979 if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
9980 }
9981 delete ws['!comments'];
9982 delete ws['!legacy'];
9983 }
9984
9985 if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
9986 }
9987
9988 if(opts.Strings != null && opts.Strings.length > 0) {
9989 f = "xl/sharedStrings." + wbext;
9990 zip_add_file(zip, f, write_sst(opts.Strings, f, opts));
9991 ct.strs.push(f);
9992 add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
9993 }
9994
9995 f = "xl/workbook." + wbext;
9996 zip_add_file(zip, f, write_wb(wb, f, opts));
9997 ct.workbooks.push(f);
9998 add_rels(opts.rels, 1, f, RELS.WB);
9999
10000 /* TODO: something more intelligent with themes */
10001
10002 f = "xl/theme/theme1.xml";
10003 zip_add_file(zip, f, write_theme(wb.Themes, opts));
10004 ct.themes.push(f);
10005 add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
10006
10007 /* TODO: something more intelligent with styles */
10008
10009 f = "xl/styles." + wbext;
10010 zip_add_file(zip, f, write_sty(wb, f, opts));
10011 ct.styles.push(f);
10012 add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
10013
10014 if(wb.vbaraw && vbafmt) {
10015 f = "xl/vbaProject.bin";
10016 zip_add_file(zip, f, wb.vbaraw);
10017 ct.vba.push(f);
10018 add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
10019 }
10020
10021 zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
10022 zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
10023 zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
10024
10025 delete opts.revssf; delete opts.ssf;
10026 return zip;
10027}
10028function firstbyte(f,o) {
10029 var x = "";
10030 switch((o||{}).type || "base64") {
10031 case 'buffer': return [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]];
10032 case 'base64': x = Base64.decode(f.slice(0,12)); break;
10033 case 'binary': x = f; break;
10034 case 'array': return [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]];
10035 default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
10036 }
10037 return [x.charCodeAt(0), x.charCodeAt(1), x.charCodeAt(2), x.charCodeAt(3), x.charCodeAt(4), x.charCodeAt(5), x.charCodeAt(6), x.charCodeAt(7)];
10038}
10039
10040function read_cfb(cfb, opts) {
10041 if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
10042 return parse_xlscfb(cfb, opts);
10043}
10044
10045function read_zip(data, opts) {
10046 var zip, d = data;
10047 var o = opts||{};
10048 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
10049 zip = zip_read(d, o);
10050 return parse_zip(zip, o);
10051}
10052
10053function read_plaintext(data, o) {
10054 var i = 0;
10055 main: while(i < data.length) switch(data.charCodeAt(i)) {
10056 case 0x0A: case 0x0D: case 0x20: ++i; break;
10057 case 0x3C: return parse_xlml(data.slice(i),o);
10058 default: break main;
10059 }
10060 return PRN.to_workbook(data, o);
10061}
10062
10063function read_plaintext_raw(data, o) {
10064 var str = "", bytes = firstbyte(data, o);
10065 switch(o.type) {
10066 case 'base64': str = Base64.decode(data); break;
10067 case 'binary': str = data; break;
10068 case 'buffer': str = data.toString('binary'); break;
10069 case 'array': str = cc2str(data); break;
10070 default: throw new Error("Unrecognized type " + o.type);
10071 }
10072 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
10073 return read_plaintext(str, o);
10074}
10075
10076function read_utf16(data, o) {
10077 var d = data;
10078 if(o.type == 'base64') d = Base64.decode(d);
10079 d = cptable.utils.decode(1200, d.slice(2), 'str');
10080 o.type = "binary";
10081 return read_plaintext(d, o);
10082}
10083
10084function bstrify(data) {
10085 return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
10086}
10087
10088function read_prn(data, d, o, str) {
10089 if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
10090 return PRN.to_workbook(d, o);
10091}
10092
10093function readSync(data, opts) {
10094 reset_cp();
10095 var o = opts||{};
10096 if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), (o = dup(o), o.type = "array", o));
10097 var d = data, n = [0,0,0,0], str = false;
10098 if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
10099 _ssfopts = {};
10100 if(o.dateNF) _ssfopts.dateNF = o.dateNF;
10101 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
10102 if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
10103 if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
10104 if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
10105 // $FlowIgnore
10106 var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
10107 // $FlowIgnore
10108 if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
10109 }
10110 switch((n = firstbyte(d, o))[0]) {
10111 case 0xD0: if(n[1] === 0xCF && n[2] === 0x11 && n[3] === 0xE0 && n[4] === 0xA1 && n[5] === 0xB1 && n[6] === 0x1A && n[7] === 0xE1) return read_cfb(CFB.read(d, o), o); break;
10112 case 0x09: if(n[1] <= 0x08) return parse_xlscfb(d, o); break;
10113 case 0x3C: return parse_xlml(d, o);
10114 case 0x49:
10115 if(n[1] === 0x49 && n[2] === 0x2a && n[3] === 0x00) throw new Error("TIFF Image File is not a spreadsheet");
10116 if(n[1] === 0x44) return read_wb_ID(d, o);
10117 break;
10118 case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
10119 case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
10120 case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
10121 case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
10122 case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
10123 case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
10124 case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
10125 case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
10126 case 0x89: if(n[1] === 0x50 && n[2] === 0x4E && n[3] === 0x47) throw new Error("PNG Image File is not a spreadsheet"); break;
10127 }
10128 if(DBF.versions.indexOf(n[0]) > -1 && n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
10129 return read_prn(data, d, o, str);
10130}
10131
10132function readFileSync(filename, opts) {
10133 var o = opts||{}; o.type = 'file';
10134 return readSync(filename, o);
10135}
10136function write_cfb_ctr(cfb, o) {
10137 switch(o.type) {
10138 case "base64": case "binary": break;
10139 case "buffer": case "array": o.type = ""; break;
10140 case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
10141 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
10142 default: throw new Error("Unrecognized type " + o.type);
10143 }
10144 return CFB.write(cfb, o);
10145}
10146
10147function write_zip_type(wb, opts) {
10148 var o = dup(opts||{});
10149 var z = write_zip(wb, o);
10150 var oopts = {};
10151 if(o.compression) oopts.compression = 'DEFLATE';
10152 if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
10153 else switch(o.type) {
10154 case "base64": oopts.type = "base64"; break;
10155 case "binary": oopts.type = "string"; break;
10156 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
10157 case "buffer":
10158 case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
10159 default: throw new Error("Unrecognized type " + o.type);
10160 }
10161 var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type}) : z.generate(oopts);
10162/*jshint -W083 */
10163 if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o); // eslint-disable-line no-undef
10164/*jshint +W083 */
10165 if(o.type === "file") return write_dl(o.file, out);
10166 return o.type == "string" ? utf8read(out) : out;
10167}
10168
10169function write_cfb_type(wb, opts) {
10170 var o = opts||{};
10171 var cfb = write_xlscfb(wb, o);
10172 return write_cfb_ctr(cfb, o);
10173}
10174
10175function write_string_type(out, opts, bom) {
10176 if(!bom) bom = "";
10177 var o = bom + out;
10178 switch(opts.type) {
10179 case "base64": return Base64.encode(utf8write(o));
10180 case "binary": return utf8write(o);
10181 case "string": return out;
10182 case "file": return write_dl(opts.file, o, 'utf8');
10183 case "buffer": {
10184 if(has_buf) return Buffer_from(o, 'utf8');
10185 else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
10186 }
10187 }
10188 throw new Error("Unrecognized type " + opts.type);
10189}
10190
10191function write_stxt_type(out, opts) {
10192 switch(opts.type) {
10193 case "base64": return Base64.encode(out);
10194 case "binary": return out;
10195 case "string": return out; /* override in sheet_to_txt */
10196 case "file": return write_dl(opts.file, out, 'binary');
10197 case "buffer": {
10198 if(has_buf) return Buffer_from(out, 'binary');
10199 else return out.split("").map(function(c) { return c.charCodeAt(0); });
10200 }
10201 }
10202 throw new Error("Unrecognized type " + opts.type);
10203}
10204
10205/* TODO: test consistency */
10206function write_binary_type(out, opts) {
10207 switch(opts.type) {
10208 case "string":
10209 case "base64":
10210 case "binary":
10211 var bstr = "";
10212 // $FlowIgnore
10213 for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
10214 return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
10215 case "file": return write_dl(opts.file, out);
10216 case "buffer": return out;
10217 default: throw new Error("Unrecognized type " + opts.type);
10218 }
10219}
10220
10221function writeSync(wb, opts) {
10222 reset_cp();
10223 check_wb(wb);
10224 var o = dup(opts||{});
10225 if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
10226 if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
10227 switch(o.bookType || 'xlsb') {
10228 case 'xml':
10229 case 'xlml': return write_string_type(write_xlml(wb, o), o);
10230 case 'slk':
10231 case 'sylk': return write_string_type(write_slk_str(wb, o), o);
10232 case 'htm':
10233 case 'html': return write_string_type(write_htm_str(wb, o), o);
10234 case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
10235 case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
10236 case 'dif': return write_string_type(write_dif_str(wb, o), o);
10237 case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
10238 case 'prn': return write_string_type(write_prn_str(wb, o), o);
10239 case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
10240 case 'eth': return write_string_type(write_eth_str(wb, o), o);
10241 case 'fods': return write_string_type(write_ods(wb, o), o);
10242 case 'wk1': return write_binary_type(write_wk1_buf(wb, o), o);
10243 case 'wk3': return write_binary_type(WK_.book_to_wk3(wb, o), o);
10244 case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
10245 case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
10246 case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
10247 case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
10248 case 'biff8':
10249 case 'xla':
10250 case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
10251 case 'xlsx':
10252 case 'xlsm':
10253 case 'xlam':
10254 case 'xlsb':
10255 case 'ods': return write_zip_type(wb, o);
10256 default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
10257 }
10258}
10259
10260function resolve_book_type(o) {
10261 if(o.bookType) return;
10262 var _BT = {
10263 "xls": "biff8",
10264 "htm": "html",
10265 "slk": "sylk",
10266 "socialcalc": "eth",
10267 "Sh33tJS": "WTF"
10268 };
10269 var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
10270 if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
10271 o.bookType = _BT[o.bookType] || o.bookType;
10272}
10273
10274function writeFileSync(wb, filename, opts) {
10275 var o = opts||{}; o.type = 'file';
10276 o.file = filename;
10277 resolve_book_type(o);
10278 return writeSync(wb, o);
10279}
10280
10281function writeFileAsync(filename, wb, opts, cb) {
10282 var o = opts||{}; o.type = 'file';
10283 o.file = filename;
10284 resolve_book_type(o);
10285 o.type = 'buffer';
10286 var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
10287 return _fs.writeFile(filename, writeSync(wb, o), _cb);
10288}
10289function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
10290 var rr = encode_row(R);
10291 var defval = o.defval, raw = o.raw || !Object.prototype.hasOwnProperty.call(o, "raw");
10292 var isempty = true;
10293 var row = (header === 1) ? [] : {};
10294 if(header !== 1) {
10295 if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
10296 else row.__rowNum__ = R;
10297 }
10298 if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
10299 var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
10300 if(val === undefined || val.t === undefined) {
10301 if(defval === undefined) continue;
10302 if(hdr[C] != null) { row[hdr[C]] = defval; }
10303 continue;
10304 }
10305 var v = val.v;
10306 switch(val.t){
10307 case 'z': if(v == null) break; continue;
10308 case 'e': v = (v == 0 ? null : void 0); break;
10309 case 's': case 'd': case 'b': case 'n': break;
10310 default: throw new Error('unrecognized type ' + val.t);
10311 }
10312 if(hdr[C] != null) {
10313 if(v == null) {
10314 if(val.t == "e" && v === null) row[hdr[C]] = null;
10315 else if(defval !== undefined) row[hdr[C]] = defval;
10316 else if(raw && v === null) row[hdr[C]] = null;
10317 else continue;
10318 } else {
10319 row[hdr[C]] = raw || (o.rawNumbers && val.t == "n") ? v : format_cell(val,v,o);
10320 }
10321 if(v != null) isempty = false;
10322 }
10323 }
10324 return { row: row, isempty: isempty };
10325}
10326
10327
10328function sheet_to_json(sheet, opts) {
10329 if(sheet == null || sheet["!ref"] == null) return [];
10330 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
10331 var r = {s:{r:0,c:0},e:{r:0,c:0}};
10332 var o = opts || {};
10333 var range = o.range != null ? o.range : sheet["!ref"];
10334 if(o.header === 1) header = 1;
10335 else if(o.header === "A") header = 2;
10336 else if(Array.isArray(o.header)) header = 3;
10337 else if(o.header == null) header = 0;
10338 switch(typeof range) {
10339 case 'string': r = safe_decode_range(range); break;
10340 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
10341 default: r = range;
10342 }
10343 if(header > 0) offset = 0;
10344 var rr = encode_row(r.s.r);
10345 var cols = [];
10346 var out = [];
10347 var outi = 0, counter = 0;
10348 var dense = Array.isArray(sheet);
10349 var R = r.s.r, C = 0, CC = 0;
10350 if(dense && !sheet[R]) sheet[R] = [];
10351 for(C = r.s.c; C <= r.e.c; ++C) {
10352 cols[C] = encode_col(C);
10353 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
10354 switch(header) {
10355 case 1: hdr[C] = C - r.s.c; break;
10356 case 2: hdr[C] = cols[C]; break;
10357 case 3: hdr[C] = o.header[C - r.s.c]; break;
10358 default:
10359 if(val == null) val = {w: "__EMPTY", t: "s"};
10360 vv = v = format_cell(val, null, o);
10361 counter = 0;
10362 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
10363 hdr[C] = vv;
10364 }
10365 }
10366 for (R = r.s.r + offset; R <= r.e.r; ++R) {
10367 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
10368 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
10369 }
10370 out.length = outi;
10371 return out;
10372}
10373
10374var qreg = /"/g;
10375function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
10376 var isempty = true;
10377 var row = [], txt = "", rr = encode_row(R);
10378 for(var C = r.s.c; C <= r.e.c; ++C) {
10379 if (!cols[C]) continue;
10380 var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
10381 if(val == null) txt = "";
10382 else if(val.v != null) {
10383 isempty = false;
10384 txt = ''+(o.rawNumbers && val.t == "n" ? val.v : format_cell(val, null, o));
10385 for(var i = 0, cc = 0; i !== txt.length; ++i) if((cc = txt.charCodeAt(i)) === fs || cc === rs || cc === 34 || o.forceQuotes) {txt = "\"" + txt.replace(qreg, '""') + "\""; break; }
10386 if(txt == "ID") txt = '"ID"';
10387 } else if(val.f != null && !val.F) {
10388 isempty = false;
10389 txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
10390 } else txt = "";
10391 /* NOTE: Excel CSV does not support array formulae */
10392 row.push(txt);
10393 }
10394 if(o.blankrows === false && isempty) return null;
10395 return row.join(FS);
10396}
10397
10398function sheet_to_csv(sheet, opts) {
10399 var out = [];
10400 var o = opts == null ? {} : opts;
10401 if(sheet == null || sheet["!ref"] == null) return "";
10402 var r = safe_decode_range(sheet["!ref"]);
10403 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
10404 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
10405 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
10406 var row = "", cols = [];
10407 o.dense = Array.isArray(sheet);
10408 var colinfo = o.skipHidden && sheet["!cols"] || [];
10409 var rowinfo = o.skipHidden && sheet["!rows"] || [];
10410 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
10411 for(var R = r.s.r; R <= r.e.r; ++R) {
10412 if ((rowinfo[R]||{}).hidden) continue;
10413 row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
10414 if(row == null) { continue; }
10415 if(o.strip) row = row.replace(endregex,"");
10416 out.push(row + RS);
10417 }
10418 delete o.dense;
10419 return out.join("");
10420}
10421
10422function sheet_to_txt(sheet, opts) {
10423 if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
10424 var s = sheet_to_csv(sheet, opts);
10425 if(typeof cptable == 'undefined' || opts.type == 'string') return s;
10426 var o = cptable.utils.encode(1200, s, 'str');
10427 return String.fromCharCode(255) + String.fromCharCode(254) + o;
10428}
10429
10430function sheet_to_formulae(sheet) {
10431 var y = "", x, val="";
10432 if(sheet == null || sheet["!ref"] == null) return [];
10433 var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
10434 var cmds = [];
10435 var dense = Array.isArray(sheet);
10436 for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
10437 for(var R = r.s.r; R <= r.e.r; ++R) {
10438 rr = encode_row(R);
10439 for(C = r.s.c; C <= r.e.c; ++C) {
10440 y = cols[C] + rr;
10441 x = dense ? (sheet[R]||[])[C] : sheet[y];
10442 val = "";
10443 if(x === undefined) continue;
10444 else if(x.F != null) {
10445 y = x.F;
10446 if(!x.f) continue;
10447 val = x.f;
10448 if(y.indexOf(":") == -1) y = y + ":" + y;
10449 }
10450 if(x.f != null) val = x.f;
10451 else if(x.t == 'z') continue;
10452 else if(x.t == 'n' && x.v != null) val = "" + x.v;
10453 else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
10454 else if(x.w !== undefined) val = "'" + x.w;
10455 else if(x.v === undefined) continue;
10456 else if(x.t == 's') val = "'" + x.v;
10457 else val = ""+x.v;
10458 cmds[cmds.length] = y + "=" + val;
10459 }
10460 }
10461 return cmds;
10462}
10463
10464function sheet_add_json(_ws, js, opts) {
10465 var o = opts || {};
10466 var offset = +!o.skipHeader;
10467 var ws = _ws || ({});
10468 var _R = 0, _C = 0;
10469 if(ws && o.origin != null) {
10470 if(typeof o.origin == 'number') _R = o.origin;
10471 else {
10472 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
10473 _R = _origin.r; _C = _origin.c;
10474 }
10475 }
10476 var cell;
10477 var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
10478 if(ws['!ref']) {
10479 var _range = safe_decode_range(ws['!ref']);
10480 range.e.c = Math.max(range.e.c, _range.e.c);
10481 range.e.r = Math.max(range.e.r, _range.e.r);
10482 if(_R == -1) { _R = _range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
10483 } else {
10484 if(_R == -1) { _R = 0; range.e.r = js.length - 1 + offset; }
10485 }
10486 var hdr = o.header || [], C = 0;
10487
10488 js.forEach(function (JS, R) {
10489 keys(JS).forEach(function(k) {
10490 if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
10491 var v = JS[k];
10492 var t = 'z';
10493 var z = "";
10494 var ref = encode_cell({c:_C + C,r:_R + R + offset});
10495 cell = utils.sheet_get_cell(ws, ref);
10496 if(v && typeof v === 'object' && !(v instanceof Date)){
10497 ws[ref] = v;
10498 } else {
10499 if(typeof v == 'number') t = 'n';
10500 else if(typeof v == 'boolean') t = 'b';
10501 else if(typeof v == 'string') t = 's';
10502 else if(v instanceof Date) {
10503 t = 'd';
10504 if(!o.cellDates) { t = 'n'; v = datenum(v); }
10505 z = (o.dateNF || SSF._table[14]);
10506 }
10507 else if(v === null && o.nullError) { t = 'e'; v = 0; }
10508 if(!cell) ws[ref] = cell = ({t:t, v:v});
10509 else {
10510 cell.t = t; cell.v = v;
10511 delete cell.w; delete cell.R;
10512 if(z) cell.z = z;
10513 }
10514 if(z) cell.z = z;
10515 }
10516 });
10517 });
10518 range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
10519 var __R = encode_row(_R);
10520 if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
10521 ws['!ref'] = encode_range(range);
10522 return ws;
10523}
10524function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
10525
10526var utils = {
10527 encode_col: encode_col,
10528 encode_row: encode_row,
10529 encode_cell: encode_cell,
10530 encode_range: encode_range,
10531 decode_col: decode_col,
10532 decode_row: decode_row,
10533 split_cell: split_cell,
10534 decode_cell: decode_cell,
10535 decode_range: decode_range,
10536 format_cell: format_cell,
10537 get_formulae: sheet_to_formulae,
10538 make_csv: sheet_to_csv,
10539 make_json: sheet_to_json,
10540 make_formulae: sheet_to_formulae,
10541 sheet_add_aoa: sheet_add_aoa,
10542 sheet_add_json: sheet_add_json,
10543 sheet_add_dom: sheet_add_dom,
10544 aoa_to_sheet: aoa_to_sheet,
10545 json_to_sheet: json_to_sheet,
10546 table_to_sheet: parse_dom_table,
10547 table_to_book: table_to_book,
10548 sheet_to_csv: sheet_to_csv,
10549 sheet_to_txt: sheet_to_txt,
10550 sheet_to_json: sheet_to_json,
10551 sheet_to_html: HTML_.from_sheet,
10552 sheet_to_formulae: sheet_to_formulae,
10553 sheet_to_row_object_array: sheet_to_json
10554};
10555
10556(function(utils) {
10557utils.consts = utils.consts || {};
10558function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
10559
10560function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
10561
10562/* get cell, creating a stub if necessary */
10563function ws_get_cell_stub(ws, R, C) {
10564 /* A1 cell address */
10565 if(typeof R == "string") {
10566 /* dense */
10567 if(Array.isArray(ws)) {
10568 var RC = decode_cell(R);
10569 if(!ws[RC.r]) ws[RC.r] = [];
10570 return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
10571 }
10572 return ws[R] || (ws[R] = {t:'z'});
10573 }
10574 /* cell address object */
10575 if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
10576 /* R and C are 0-based indices */
10577 return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
10578}
10579utils.sheet_get_cell = ws_get_cell_stub;
10580
10581/* find sheet index for given name / validate index */
10582function wb_sheet_idx(wb, sh) {
10583 if(typeof sh == "number") {
10584 if(sh >= 0 && wb.SheetNames.length > sh) return sh;
10585 throw new Error("Cannot find sheet # " + sh);
10586 } else if(typeof sh == "string") {
10587 var idx = wb.SheetNames.indexOf(sh);
10588 if(idx > -1) return idx;
10589 throw new Error("Cannot find sheet name |" + sh + "|");
10590 } else throw new Error("Cannot find sheet |" + sh + "|");
10591}
10592
10593/* simple blank workbook object */
10594utils.book_new = function() {
10595 return { SheetNames: [], Sheets: {} };
10596};
10597
10598/* add a worksheet to the end of a given workbook */
10599utils.book_append_sheet = function(wb, ws, name) {
10600 if(!name) for(var i = 1; i <= 0xFFFF; ++i, name = undefined) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
10601 if(!name || wb.SheetNames.length >= 0xFFFF) throw new Error("Too many worksheets");
10602 check_ws_name(name);
10603 if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
10604
10605 wb.SheetNames.push(name);
10606 wb.Sheets[name] = ws;
10607};
10608
10609/* set sheet visibility (visible/hidden/very hidden) */
10610utils.book_set_sheet_visibility = function(wb, sh, vis) {
10611 get_default(wb,"Workbook",{});
10612 get_default(wb.Workbook,"Sheets",[]);
10613
10614 var idx = wb_sheet_idx(wb, sh);
10615 // $FlowIgnore
10616 get_default(wb.Workbook.Sheets,idx, {});
10617
10618 switch(vis) {
10619 case 0: case 1: case 2: break;
10620 default: throw new Error("Bad sheet visibility setting " + vis);
10621 }
10622 // $FlowIgnore
10623 wb.Workbook.Sheets[idx].Hidden = vis;
10624};
10625add_consts([
10626 ["SHEET_VISIBLE", 0],
10627 ["SHEET_HIDDEN", 1],
10628 ["SHEET_VERY_HIDDEN", 2]
10629]);
10630
10631/* set number format */
10632utils.cell_set_number_format = function(cell, fmt) {
10633 cell.z = fmt;
10634 return cell;
10635};
10636
10637/* set cell hyperlink */
10638utils.cell_set_hyperlink = function(cell, target, tooltip) {
10639 if(!target) {
10640 delete cell.l;
10641 } else {
10642 cell.l = ({ Target: target });
10643 if(tooltip) cell.l.Tooltip = tooltip;
10644 }
10645 return cell;
10646};
10647utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
10648
10649/* add to cell comments */
10650utils.cell_add_comment = function(cell, text, author) {
10651 if(!cell.c) cell.c = [];
10652 cell.c.push({t:text, a:author||"SheetJS"});
10653};
10654
10655/* set array formula and flush related cells */
10656utils.sheet_set_array_formula = function(ws, range, formula) {
10657 var rng = typeof range != "string" ? range : safe_decode_range(range);
10658 var rngstr = typeof range == "string" ? range : encode_range(range);
10659 for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
10660 var cell = ws_get_cell_stub(ws, R, C);
10661 cell.t = 'n';
10662 cell.F = rngstr;
10663 delete cell.v;
10664 if(R == rng.s.r && C == rng.s.c) cell.f = formula;
10665 }
10666 return ws;
10667};
10668
10669return utils;
10670})(utils);
10671
10672if(typeof parse_xlscfb !== "undefined") XLSX.parse_xlscfb = parse_xlscfb;
10673XLSX.parse_zip = parse_zip;
10674XLSX.read = readSync; //xlsread
10675XLSX.readFile = readFileSync; //readFile
10676XLSX.readFileSync = readFileSync;
10677XLSX.write = writeSync;
10678XLSX.writeFile = writeFileSync;
10679XLSX.writeFileSync = writeFileSync;
10680XLSX.writeFileAsync = writeFileAsync;
10681XLSX.utils = utils;
10682XLSX.SSF = SSF;
10683if(typeof CFB !== "undefined") XLSX.CFB = CFB;
10684}
10685/*global define */
10686if(typeof exports !== 'undefined') make_xlsx_lib(exports);
10687else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
10688else if(typeof define === 'function' && define.amd) define('xlsx', function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
10689else make_xlsx_lib(XLSX);
10690/* NOTE: the following extra line is needed for "Lightning Locker Service" */
10691if(typeof window !== 'undefined' && !window.XLSX) window.XLSX = XLSX;
10692/*exported XLS, ODS */
10693var XLS = XLSX, ODS = XLSX;