UNPKG

375 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.0';
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 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(!isNaN(v)) return v;
2842 if(!/\d/.test(s)) return v;
2843 var wt = 1;
2844 var ss = s.replace(/([\d]),([\d])/g,"$1$2").replace(/[$]/g,"").replace(/[%]/g, function() { wt *= 100; return "";});
2845 if(!isNaN(v = Number(ss))) return v / wt;
2846 ss = ss.replace(/[(](.*)[)]/,function($$, $1) { wt = -wt; return $1;});
2847 if(!isNaN(v = Number(ss))) return v / wt;
2848 return v;
2849}
2850function fuzzydate(s) {
2851 var o = new Date(s), n = new Date(NaN);
2852 var y = o.getYear(), m = o.getMonth(), d = o.getDate();
2853 if(isNaN(d)) return n;
2854 if(y < 0 || y > 8099) return n;
2855 if((m > 0 || d > 1) && y != 101) return o;
2856 if(s.toLowerCase().match(/jan|feb|mar|apr|may|jun|jul|aug|sep|oct|nov|dec/)) return o;
2857 if(s.match(/[^-0-9:,\/\\]/)) return n;
2858 return o;
2859}
2860
2861var safe_split_regex = "abacaba".split(/(:?b)/i).length == 5;
2862function split_regex(str, re, def) {
2863 if(safe_split_regex || typeof re == "string") return str.split(re);
2864 var p = str.split(re), o = [p[0]];
2865 for(var i = 1; i < p.length; ++i) { o.push(def); o.push(p[i]); }
2866 return o;
2867}
2868function getdatastr(data) {
2869 if(!data) return null;
2870 if(data.data) return debom(data.data);
2871 if(data.asNodeBuffer && has_buf) return debom(data.asNodeBuffer().toString('binary'));
2872 if(data.asBinary) return debom(data.asBinary());
2873 if(data._data && data._data.getContent) return debom(cc2str(Array.prototype.slice.call(data._data.getContent(),0)));
2874 if(data.content && data.type) return debom(cc2str(data.content));
2875 return null;
2876}
2877
2878function getdatabin(data) {
2879 if(!data) return null;
2880 if(data.data) return char_codes(data.data);
2881 if(data.asNodeBuffer && has_buf) return data.asNodeBuffer();
2882 if(data._data && data._data.getContent) {
2883 var o = data._data.getContent();
2884 if(typeof o == "string") return char_codes(o);
2885 return Array.prototype.slice.call(o);
2886 }
2887 if(data.content && data.type) return data.content;
2888 return null;
2889}
2890
2891function getdata(data) { return (data && data.name.slice(-4) === ".bin") ? getdatabin(data) : getdatastr(data); }
2892
2893/* Part 2 Section 10.1.2 "Mapping Content Types" Names are case-insensitive */
2894/* OASIS does not comment on filename case sensitivity */
2895function safegetzipfile(zip, file) {
2896 var k = zip.FullPaths || keys(zip.files);
2897 var f = file.toLowerCase(), g = f.replace(/\\/g,'\/');
2898 for(var i=0; i<k.length; ++i) {
2899 var n = k[i].replace(/^Root Entry[\/]/,"").toLowerCase();
2900 if(f == n || g == n) return zip.FileIndex[i];
2901 }
2902 return null;
2903}
2904
2905function getzipfile(zip, file) {
2906 var o = safegetzipfile(zip, file);
2907 if(o == null) throw new Error("Cannot find file " + file + " in zip");
2908 return o;
2909}
2910
2911function getzipdata(zip, file, safe) {
2912 if(!safe) return getdata(getzipfile(zip, file));
2913 if(!file) return null;
2914 try { return getzipdata(zip, file); } catch(e) { return null; }
2915}
2916
2917function getzipstr(zip, file, safe) {
2918 if(!safe) return getdatastr(getzipfile(zip, file));
2919 if(!file) return null;
2920 try { return getzipstr(zip, file); } catch(e) { return null; }
2921}
2922
2923function zipentries(zip) {
2924 var k = zip.FullPaths || keys(zip.files), o = [];
2925 for(var i = 0; i < k.length; ++i) if(k[i].slice(-1) != '/') o.push(k[i].replace(/^Root Entry[\/]/, ""));
2926 return o.sort();
2927}
2928
2929function zip_add_file(zip, path, content) {
2930 if(zip.FullPaths) CFB.utils.cfb_add(zip, path, typeof content == "string" ? (has_buf ? Buffer_from(content) : s2a(utf8write(content))) : content);
2931 else zip.file(path, content);
2932}
2933
2934
2935function zip_new() {
2936 return CFB.utils.cfb_new();
2937}
2938
2939function zip_read(d, o) {
2940 var zip;
2941 switch(o.type) {
2942 case "base64": zip = CFB.read(d, { type: "base64" }); break;
2943 case "binary": zip = CFB.read(d, { type: "binary" }); break;
2944 case "buffer": case "array": zip = CFB.read(d, { type: "buffer" }); break;
2945 default: throw new Error("Unrecognized type " + o.type);
2946 }
2947 return zip;
2948}
2949
2950function resolve_path(path, base) {
2951 if(path.charAt(0) == "/") return path.slice(1);
2952 var result = base.split('/');
2953 if(base.slice(-1) != "/") result.pop(); // folder path
2954 var target = path.split('/');
2955 while (target.length !== 0) {
2956 var step = target.shift();
2957 if (step === '..') result.pop();
2958 else if (step !== '.') result.push(step);
2959 }
2960 return result.join('/');
2961}
2962var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
2963var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
2964var tagregex=/<[\/\?]?[a-zA-Z0-9:_-]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s=]+))*\s*[\/\?]?>/mg;
2965
2966if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g;
2967var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/;
2968function parsexmltag(tag, skip_root, skip_LC) {
2969 var z = ({});
2970 var eq = 0, c = 0;
2971 for(; eq !== tag.length; ++eq) if((c = tag.charCodeAt(eq)) === 32 || c === 10 || c === 13) break;
2972 if(!skip_root) z[0] = tag.slice(0, eq);
2973 if(eq === tag.length) return z;
2974 var m = tag.match(attregexg), j=0, v="", i=0, q="", cc="", quot = 1;
2975 if(m) for(i = 0; i != m.length; ++i) {
2976 cc = m[i];
2977 for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break;
2978 q = cc.slice(0,c).trim();
2979 while(cc.charCodeAt(c+1) == 32) ++c;
2980 quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0;
2981 v = cc.slice(c+1+quot, cc.length-quot);
2982 for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break;
2983 if(j===q.length) {
2984 if(q.indexOf("_") > 0) q = q.slice(0, q.indexOf("_")); // from ods
2985 z[q] = v;
2986 if(!skip_LC) z[q.toLowerCase()] = v;
2987 }
2988 else {
2989 var k = (j===5 && q.slice(0,5)==="xmlns"?"xmlns":"")+q.slice(j+1);
2990 if(z[k] && q.slice(j-3,j) == "ext") continue; // from ods
2991 z[k] = v;
2992 if(!skip_LC) z[k.toLowerCase()] = v;
2993 }
2994 }
2995 return z;
2996}
2997function strip_ns(x) { return x.replace(nsregex2, "<$1"); }
2998
2999var encodings = {
3000 '&quot;': '"',
3001 '&apos;': "'",
3002 '&gt;': '>',
3003 '&lt;': '<',
3004 '&amp;': '&'
3005};
3006var rencoding = evert(encodings);
3007//var rencstr = "&<>'\"".split("");
3008
3009// TODO: CP remap (need to read file version to determine OS)
3010var unescapexml = (function() {
3011 /* 22.4.2.4 bstr (Basic String) */
3012 var encregex = /&(?:quot|apos|gt|lt|amp|#x?([\da-fA-F]+));/ig, coderegex = /_x([\da-fA-F]{4})_/ig;
3013 return function unescapexml(text) {
3014 var s = text + '', i = s.indexOf("<![CDATA[");
3015 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));});
3016 var j = s.indexOf("]]>");
3017 return unescapexml(s.slice(0, i)) + s.slice(i+9,j) + unescapexml(s.slice(j+3));
3018 };
3019})();
3020
3021var decregex=/[&<>'"]/g, charegex = /[\u0000-\u0008\u000b-\u001f]/g;
3022function escapexml(text){
3023 var s = text + '';
3024 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(charegex,function(s) { return "_x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + "_";});
3025}
3026function escapexmltag(text){ return escapexml(text).replace(/ /g,"_x0020_"); }
3027
3028var htmlcharegex = /[\u0000-\u001f]/g;
3029function escapehtml(text){
3030 var s = text + '';
3031 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) + ";"; });
3032}
3033
3034function escapexlml(text){
3035 var s = text + '';
3036 return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
3037}
3038
3039/* TODO: handle codepages */
3040var xlml_fixstr = (function() {
3041 var entregex = /&#(\d+);/g;
3042 function entrepl($$,$1) { return String.fromCharCode(parseInt($1,10)); }
3043 return function xlml_fixstr(str) { return str.replace(entregex,entrepl); };
3044})();
3045var xlml_unfixstr = (function() {
3046 return function xlml_unfixstr(str) { return str.replace(/(\r\n|[\r\n])/g,"\&#10;"); };
3047})();
3048
3049function parsexmlbool(value) {
3050 switch(value) {
3051 case 1: case true: case '1': case 'true': case 'TRUE': return true;
3052 /* case '0': case 'false': case 'FALSE':*/
3053 default: return false;
3054 }
3055}
3056
3057var utf8read = function utf8reada(orig) {
3058 var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0;
3059 while (i < orig.length) {
3060 c = orig.charCodeAt(i++);
3061 if (c < 128) { out += String.fromCharCode(c); continue; }
3062 d = orig.charCodeAt(i++);
3063 if (c>191 && c<224) { f = ((c & 31) << 6); f |= (d & 63); out += String.fromCharCode(f); continue; }
3064 e = orig.charCodeAt(i++);
3065 if (c < 240) { out += String.fromCharCode(((c & 15) << 12) | ((d & 63) << 6) | (e & 63)); continue; }
3066 f = orig.charCodeAt(i++);
3067 w = (((c & 7) << 18) | ((d & 63) << 12) | ((e & 63) << 6) | (f & 63))-65536;
3068 out += String.fromCharCode(0xD800 + ((w>>>10)&1023));
3069 out += String.fromCharCode(0xDC00 + (w&1023));
3070 }
3071 return out;
3072};
3073
3074var utf8write = function(orig) {
3075 var out = [], i = 0, c = 0, d = 0;
3076 while(i < orig.length) {
3077 c = orig.charCodeAt(i++);
3078 switch(true) {
3079 case c < 128: out.push(String.fromCharCode(c)); break;
3080 case c < 2048:
3081 out.push(String.fromCharCode(192 + (c >> 6)));
3082 out.push(String.fromCharCode(128 + (c & 63)));
3083 break;
3084 case c >= 55296 && c < 57344:
3085 c -= 55296; d = orig.charCodeAt(i++) - 56320 + (c<<10);
3086 out.push(String.fromCharCode(240 + ((d >>18) & 7)));
3087 out.push(String.fromCharCode(144 + ((d >>12) & 63)));
3088 out.push(String.fromCharCode(128 + ((d >> 6) & 63)));
3089 out.push(String.fromCharCode(128 + (d & 63)));
3090 break;
3091 default:
3092 out.push(String.fromCharCode(224 + (c >> 12)));
3093 out.push(String.fromCharCode(128 + ((c >> 6) & 63)));
3094 out.push(String.fromCharCode(128 + (c & 63)));
3095 }
3096 }
3097 return out.join("");
3098};
3099
3100if(has_buf) {
3101 var utf8readb = function utf8readb(data) {
3102 var out = Buffer.alloc(2*data.length), w, i, j = 1, k = 0, ww=0, c;
3103 for(i = 0; i < data.length; i+=j) {
3104 j = 1;
3105 if((c=data.charCodeAt(i)) < 128) w = c;
3106 else if(c < 224) { w = (c&31)*64+(data.charCodeAt(i+1)&63); j=2; }
3107 else if(c < 240) { w=(c&15)*4096+(data.charCodeAt(i+1)&63)*64+(data.charCodeAt(i+2)&63); j=3; }
3108 else { j = 4;
3109 w = (c & 7)*262144+(data.charCodeAt(i+1)&63)*4096+(data.charCodeAt(i+2)&63)*64+(data.charCodeAt(i+3)&63);
3110 w -= 65536; ww = 0xD800 + ((w>>>10)&1023); w = 0xDC00 + (w&1023);
3111 }
3112 if(ww !== 0) { out[k++] = ww&255; out[k++] = ww>>>8; ww = 0; }
3113 out[k++] = w%256; out[k++] = w>>>8;
3114 }
3115 return out.slice(0,k).toString('ucs2');
3116 };
3117 var corpus = "foo bar baz\u00e2\u0098\u0083\u00f0\u009f\u008d\u00a3";
3118 if(utf8read(corpus) == utf8readb(corpus)) utf8read = utf8readb;
3119 var utf8readc = function utf8readc(data) { return Buffer_from(data, 'binary').toString('utf8'); };
3120 if(utf8read(corpus) == utf8readc(corpus)) utf8read = utf8readc;
3121
3122 utf8write = function(data) { return Buffer_from(data, 'utf8').toString("binary"); };
3123}
3124
3125// matches <foo>...</foo> extracts content
3126var matchtag = (function() {
3127 var mtcache = ({});
3128 return function matchtag(f,g) {
3129 var t = f+"|"+(g||"");
3130 if(mtcache[t]) return mtcache[t];
3131 return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)</(?:\\w+:)?'+f+'>',((g||""))));
3132 };
3133})();
3134
3135var htmldecode = (function() {
3136 var entities = [
3137 ['nbsp', ' '], ['middot', '·'],
3138 ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&']
3139 ].map(function(x) { return [new RegExp('&' + x[0] + ';', "ig"), x[1]]; });
3140 return function htmldecode(str) {
3141 var o = str
3142 // Remove new lines and spaces from start of content
3143 .replace(/^[\t\n\r ]+/, "")
3144 // Remove new lines and spaces from end of content
3145 .replace(/[\t\n\r ]+$/,"")
3146 // Added line which removes any white space characters after and before html tags
3147 .replace(/>\s+/g,">").replace(/\s+</g,"<")
3148 // Replace remaining new lines and spaces with space
3149 .replace(/[\t\n\r ]+/g, " ")
3150 // Replace <br> tags with new lines
3151 .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
3152 // Strip HTML elements
3153 .replace(/<[^>]*>/g,"");
3154 for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
3155 return o;
3156 };
3157})();
3158
3159var vtregex = (function(){ var vt_cache = {};
3160 return function vt_regex(bt) {
3161 if(vt_cache[bt] !== undefined) return vt_cache[bt];
3162 return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)</(?:vt:)?" + bt + ">", 'g') );
3163};})();
3164var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)</;
3165function parseVector(data, opts) {
3166 var h = parsexmltag(data);
3167
3168 var matches = data.match(vtregex(h.baseType))||[];
3169 var res = [];
3170 if(matches.length != h.size) {
3171 if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size);
3172 return res;
3173 }
3174 matches.forEach(function(x) {
3175 var v = x.replace(vtvregex,"").match(vtmregex);
3176 if(v) res.push({v:utf8read(v[2]), t:v[1]});
3177 });
3178 return res;
3179}
3180
3181var wtregex = /(^\s|\s$|\n)/;
3182function writetag(f,g) { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f + '>'; }
3183
3184function wxt_helper(h) { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); }
3185function writextag(f,g,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '</' + f : "/") + '>';}
3186
3187function write_w3cdtf(d, t) { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; }
3188
3189function write_vt(s, xlsx) {
3190 switch(typeof s) {
3191 case 'string':
3192 var o = writextag('vt:lpwstr', escapexml(s));
3193 if(xlsx) o = o.replace(/&quot;/g, "_x0022_");
3194 return o;
3195 case 'number': return writextag((s|0)==s?'vt:i4':'vt:r8', escapexml(String(s)));
3196 case 'boolean': return writextag('vt:bool',s?'true':'false');
3197 }
3198 if(s instanceof Date) return writextag('vt:filetime', write_w3cdtf(s));
3199 throw new Error("Unable to serialize " + s);
3200}
3201
3202var XMLNS = ({
3203 'dc': 'http://purl.org/dc/elements/1.1/',
3204 'dcterms': 'http://purl.org/dc/terms/',
3205 'dcmitype': 'http://purl.org/dc/dcmitype/',
3206 'mx': 'http://schemas.microsoft.com/office/mac/excel/2008/main',
3207 'r': 'http://schemas.openxmlformats.org/officeDocument/2006/relationships',
3208 'sjs': 'http://schemas.openxmlformats.org/package/2006/sheetjs/core-properties',
3209 'vt': 'http://schemas.openxmlformats.org/officeDocument/2006/docPropsVTypes',
3210 'xsi': 'http://www.w3.org/2001/XMLSchema-instance',
3211 'xsd': 'http://www.w3.org/2001/XMLSchema'
3212});
3213
3214XMLNS.main = [
3215 'http://schemas.openxmlformats.org/spreadsheetml/2006/main',
3216 'http://purl.oclc.org/ooxml/spreadsheetml/main',
3217 'http://schemas.microsoft.com/office/excel/2006/main',
3218 'http://schemas.microsoft.com/office/excel/2006/2'
3219];
3220
3221var XLMLNS = ({
3222 'o': 'urn:schemas-microsoft-com:office:office',
3223 'x': 'urn:schemas-microsoft-com:office:excel',
3224 'ss': 'urn:schemas-microsoft-com:office:spreadsheet',
3225 'dt': 'uuid:C2F41010-65B3-11d1-A29F-00AA00C14882',
3226 'mv': 'http://macVmlSchemaUri',
3227 'v': 'urn:schemas-microsoft-com:vml',
3228 'html': 'http://www.w3.org/TR/REC-html40'
3229});
3230function read_double_le(b, idx) {
3231 var s = 1 - 2 * (b[idx + 7] >>> 7);
3232 var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
3233 var m = (b[idx+6]&0x0f);
3234 for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
3235 if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
3236 if(e == 0) e = -1022;
3237 else { e -= 1023; m += Math.pow(2,52); }
3238 return s * Math.pow(2, e - 52) * m;
3239}
3240
3241function write_double_le(b, v, idx) {
3242 var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
3243 var av = bs ? (-v) : v;
3244 if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
3245 else if(av == 0) e = m = 0;
3246 else {
3247 e = Math.floor(Math.log(av) / Math.LN2);
3248 m = av * Math.pow(2, 52 - e);
3249 if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
3250 else { m -= Math.pow(2,52); e+=1023; }
3251 }
3252 for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
3253 b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
3254 b[idx + 7] = (e >> 4) | bs;
3255}
3256
3257var __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; };
3258var ___toBuffer = __toBuffer;
3259var __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,''); };
3260var ___utf16le = __utf16le;
3261var __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(""); };
3262var ___hexlify = __hexlify;
3263var __utf8 = function(b,s,e) { var ss=[]; for(var i=s; i<e; i++) ss.push(String.fromCharCode(__readUInt8(b,i))); return ss.join(""); };
3264var ___utf8 = __utf8;
3265var __lpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3266var ___lpstr = __lpstr;
3267var __cpstr = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3268var ___cpstr = __cpstr;
3269var __lpwstr = function(b,i) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
3270var ___lpwstr = __lpwstr;
3271var __lpp4, ___lpp4;
3272__lpp4 = ___lpp4 = function lpp4_(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf16le(b, i+4,i+4+len) : "";};
3273var __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len) : "";};
3274var ___8lpp4 = __8lpp4;
3275var __double, ___double;
3276__double = ___double = function(b, idx) { return read_double_le(b, idx);};
3277var is_buf = function is_buf_a(a) { return Array.isArray(a); };
3278
3279if(has_buf) {
3280 __utf16le = function(b,s,e) { if(!Buffer.isBuffer(b)) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; };
3281 __hexlify = function(b,s,l) { return Buffer.isBuffer(b) ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); };
3282 __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) : "";};
3283 __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) : "";};
3284 __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);};
3285 __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);};
3286 __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);};
3287 __utf8 = function utf8_b(b, s, e) { return (Buffer.isBuffer(b)) ? b.toString('utf8',s,e) : ___utf8(b,s,e); };
3288 __toBuffer = function(bufs) { return (bufs[0].length > 0 && Buffer.isBuffer(bufs[0][0])) ? Buffer.concat(bufs[0]) : ___toBuffer(bufs);};
3289 bconcat = function(bufs) { return Buffer.isBuffer(bufs[0]) ? Buffer.concat(bufs) : [].concat.apply([], bufs); };
3290 __double = function double_(b, i) { if(Buffer.isBuffer(b)) return b.readDoubleLE(i); return ___double(b,i); };
3291 is_buf = function is_buf_b(a) { return Buffer.isBuffer(a) || Array.isArray(a); };
3292}
3293
3294/* from js-xls */
3295if(typeof cptable !== 'undefined') {
3296 __utf16le = function(b,s,e) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); };
3297 __utf8 = function(b,s,e) { return cptable.utils.decode(65001, b.slice(s,e)); };
3298 __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)) : "";};
3299 __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)) : "";};
3300 __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)) : "";};
3301 __lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";};
3302 __8lpp4 = function(b,i) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";};
3303}
3304
3305var __readUInt8 = function(b, idx) { return b[idx]; };
3306var __readUInt16LE = function(b, idx) { return (b[idx+1]*(1<<8))+b[idx]; };
3307var __readInt16LE = function(b, idx) { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
3308var __readUInt32LE = function(b, idx) { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
3309var __readInt32LE = function(b, idx) { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
3310var __readInt32BE = function(b, idx) { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
3311
3312function ReadShift(size, t) {
3313 var o="", oI, oR, oo=[], w, vv, i, loc;
3314 switch(t) {
3315 case 'dbcs':
3316 loc = this.l;
3317 if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
3318 else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
3319 size *= 2;
3320 break;
3321
3322 case 'utf8': o = __utf8(this, this.l, this.l + size); break;
3323 case 'utf16le': size *= 2; o = __utf16le(this, this.l, this.l + size); break;
3324
3325 case 'wstr':
3326 if(typeof cptable !== 'undefined') o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l+2*size));
3327 else return ReadShift.call(this, size, 'dbcs');
3328 size = 2 * size; break;
3329
3330 /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
3331 case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3332 case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break;
3333 /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */
3334 case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break;
3335 /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */
3336 case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break;
3337 /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */
3338 case '8lpp4': size = 4 + __readUInt32LE(this, this.l); o = __8lpp4(this, this.l); if(size & 0x03) size += 4 - (size & 0x03); break;
3339
3340 case 'cstr': size = 0; o = "";
3341 while((w=__readUInt8(this, this.l + size++))!==0) oo.push(_getchar(w));
3342 o = oo.join(""); break;
3343 case '_wstr': size = 0; o = "";
3344 while((w=__readUInt16LE(this,this.l +size))!==0){oo.push(_getchar(w));size+=2;}
3345 size+=2; o = oo.join(""); break;
3346
3347 /* sbcs and dbcs support continue records in the SST way TODO codepages */
3348 case 'dbcs-cont': o = ""; loc = this.l;
3349 for(i = 0; i < size; ++i) {
3350 if(this.lens && this.lens.indexOf(loc) !== -1) {
3351 w = __readUInt8(this, loc);
3352 this.l = loc + 1;
3353 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3354 return oo.join("") + vv;
3355 }
3356 oo.push(_getchar(__readUInt16LE(this, loc)));
3357 loc+=2;
3358 } o = oo.join(""); size *= 2; break;
3359
3360 case 'cpstr':
3361 if(typeof cptable !== 'undefined') {
3362 o = cptable.utils.decode(current_codepage, this.slice(this.l, this.l + size));
3363 break;
3364 }
3365 /* falls through */
3366 case 'sbcs-cont': o = ""; loc = this.l;
3367 for(i = 0; i != size; ++i) {
3368 if(this.lens && this.lens.indexOf(loc) !== -1) {
3369 w = __readUInt8(this, loc);
3370 this.l = loc + 1;
3371 vv = ReadShift.call(this, size-i, w ? 'dbcs-cont' : 'sbcs-cont');
3372 return oo.join("") + vv;
3373 }
3374 oo.push(_getchar(__readUInt8(this, loc)));
3375 loc+=1;
3376 } o = oo.join(""); break;
3377
3378 default:
3379 switch(size) {
3380 case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
3381 case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
3382 case 4: case -4:
3383 if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
3384 else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
3385 case 8: case -8:
3386 if(t === 'f') {
3387 if(size == 8) oR = __double(this, this.l);
3388 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);
3389 this.l += 8; return oR;
3390 } else size = 8;
3391 /* falls through */
3392 case 16: o = __hexlify(this, this.l, size); break;
3393 }}
3394 this.l+=size; return o;
3395}
3396
3397var __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); };
3398var __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); };
3399var __writeUInt16LE = function(b, val, idx) { b[idx] = (val & 0xFF); b[idx+1] = ((val >>> 8) & 0xFF); };
3400
3401function WriteShift(t, val, f) {
3402 var size = 0, i = 0;
3403 if(f === 'dbcs') {
3404for(i = 0; i != val.length; ++i) __writeUInt16LE(this, val.charCodeAt(i), this.l + 2 * i);
3405 size = 2 * val.length;
3406 } else if(f === 'sbcs') {
3407 if(typeof cptable !== 'undefined' && current_ansi == 874) {
3408 /* TODO: use tables directly, don't encode */
3409for(i = 0; i != val.length; ++i) {
3410 var cppayload = cptable.utils.encode(current_ansi, val.charAt(i));
3411 this[this.l + i] = cppayload[0];
3412 }
3413 } else {
3414val = val.replace(/[^\x00-\x7F]/g, "_");
3415for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
3416 }
3417 size = val.length;
3418 } else if(f === 'hex') {
3419 for(; i < t; ++i) {
3420this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
3421 } return this;
3422 } else if(f === 'utf16le') {
3423var end = Math.min(this.l + t, this.length);
3424 for(i = 0; i < Math.min(val.length, t); ++i) {
3425 var cc = val.charCodeAt(i);
3426 this[this.l++] = (cc & 0xff);
3427 this[this.l++] = (cc >> 8);
3428 }
3429 while(this.l < end) this[this.l++] = 0;
3430 return this;
3431 } else switch(t) {
3432 case 1: size = 1; this[this.l] = val&0xFF; break;
3433 case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;
3434 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;
3435 case 4: size = 4; __writeUInt32LE(this, val, this.l); break;
3436 case 8: size = 8; if(f === 'f') { write_double_le(this, val, this.l); break; }
3437 /* falls through */
3438 case 16: break;
3439 case -4: size = 4; __writeInt32LE(this, val, this.l); break;
3440 }
3441 this.l += size; return this;
3442}
3443
3444function CheckField(hexstr, fld) {
3445 var m = __hexlify(this,this.l,hexstr.length>>1);
3446 if(m !== hexstr) throw new Error(fld + 'Expected ' + hexstr + ' saw ' + m);
3447 this.l += hexstr.length>>1;
3448}
3449
3450function prep_blob(blob, pos) {
3451 blob.l = pos;
3452 blob.read_shift = ReadShift;
3453 blob.chk = CheckField;
3454 blob.write_shift = WriteShift;
3455}
3456
3457function parsenoop(blob, length) { blob.l += length; }
3458
3459function new_buf(sz) {
3460 var o = new_raw_buf(sz);
3461 prep_blob(o, 0);
3462 return o;
3463}
3464
3465/* [MS-XLSB] 2.1.4 Record */
3466function recordhopper(data, cb, opts) {
3467 if(!data) return;
3468 var tmpbyte, cntbyte, length;
3469 prep_blob(data, data.l || 0);
3470 var L = data.length, RT = 0, tgt = 0;
3471 while(data.l < L) {
3472 RT = data.read_shift(1);
3473 if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
3474 var R = XLSBRecordEnum[RT] || XLSBRecordEnum[0xFFFF];
3475 tmpbyte = data.read_shift(1);
3476 length = tmpbyte & 0x7F;
3477 for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
3478 tgt = data.l + length;
3479 var d = (R.f||parsenoop)(data, length, opts);
3480 data.l = tgt;
3481 if(cb(d, R.n, RT)) return;
3482 }
3483}
3484
3485/* control buffer usage for fixed-length buffers */
3486function buf_array() {
3487 var bufs = [], blksz = has_buf ? 256 : 2048;
3488 var newblk = function ba_newblk(sz) {
3489 var o = (new_buf(sz));
3490 prep_blob(o, 0);
3491 return o;
3492 };
3493
3494 var curbuf = newblk(blksz);
3495
3496 var endbuf = function ba_endbuf() {
3497 if(!curbuf) return;
3498 if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3499 if(curbuf.length > 0) bufs.push(curbuf);
3500 curbuf = null;
3501 };
3502
3503 var next = function ba_next(sz) {
3504 if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
3505 endbuf();
3506 return (curbuf = newblk(Math.max(sz+1, blksz)));
3507 };
3508
3509 var end = function ba_end() {
3510 endbuf();
3511 return __toBuffer([bufs]);
3512 };
3513
3514 var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
3515
3516 return ({ next:next, push:push, end:end, _bufs:bufs });
3517}
3518
3519function write_record(ba, type, payload, length) {
3520 var t = +XLSBRE[type], l;
3521 if(isNaN(t)) return; // TODO: throw something here?
3522 if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0;
3523 l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/;
3524 if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l;
3525 var o = ba.next(l);
3526 if(t <= 0x7F) o.write_shift(1, t);
3527 else {
3528 o.write_shift(1, (t & 0x7F) + 0x80);
3529 o.write_shift(1, (t >> 7));
3530 }
3531 for(var i = 0; i != 4; ++i) {
3532 if(length >= 0x80) { o.write_shift(1, (length & 0x7F)+0x80); length >>= 7; }
3533 else { o.write_shift(1, length); break; }
3534 }
3535 if(length > 0 && is_buf(payload)) ba.push(payload);
3536}
3537/* XLS ranges enforced */
3538function shift_cell_xls(cell, tgt, opts) {
3539 var out = dup(cell);
3540 if(tgt.s) {
3541 if(out.cRel) out.c += tgt.s.c;
3542 if(out.rRel) out.r += tgt.s.r;
3543 } else {
3544 if(out.cRel) out.c += tgt.c;
3545 if(out.rRel) out.r += tgt.r;
3546 }
3547 if(!opts || opts.biff < 12) {
3548 while(out.c >= 0x100) out.c -= 0x100;
3549 while(out.r >= 0x10000) out.r -= 0x10000;
3550 }
3551 return out;
3552}
3553
3554function shift_range_xls(cell, range, opts) {
3555 var out = dup(cell);
3556 out.s = shift_cell_xls(out.s, range.s, opts);
3557 out.e = shift_cell_xls(out.e, range.s, opts);
3558 return out;
3559}
3560
3561function encode_cell_xls(c, biff) {
3562 if(c.cRel && c.c < 0) { c = dup(c); while(c.c < 0) c.c += (biff > 8) ? 0x4000 : 0x100; }
3563 if(c.rRel && c.r < 0) { c = dup(c); while(c.r < 0) c.r += (biff > 8) ? 0x100000 : ((biff > 5) ? 0x10000 : 0x4000); }
3564 var s = encode_cell(c);
3565 if(!c.cRel && c.cRel != null) s = fix_col(s);
3566 if(!c.rRel && c.rRel != null) s = fix_row(s);
3567 return s;
3568}
3569
3570function encode_range_xls(r, opts) {
3571 if(r.s.r == 0 && !r.s.rRel) {
3572 if(r.e.r == (opts.biff >= 12 ? 0xFFFFF : (opts.biff >= 8 ? 0x10000 : 0x4000)) && !r.e.rRel) {
3573 return (r.s.cRel ? "" : "$") + encode_col(r.s.c) + ":" + (r.e.cRel ? "" : "$") + encode_col(r.e.c);
3574 }
3575 }
3576 if(r.s.c == 0 && !r.s.cRel) {
3577 if(r.e.c == (opts.biff >= 12 ? 0x3FFF : 0xFF) && !r.e.cRel) {
3578 return (r.s.rRel ? "" : "$") + encode_row(r.s.r) + ":" + (r.e.rRel ? "" : "$") + encode_row(r.e.r);
3579 }
3580 }
3581 return encode_cell_xls(r.s, opts.biff) + ":" + encode_cell_xls(r.e, opts.biff);
3582}
3583function decode_row(rowstr) { return parseInt(unfix_row(rowstr),10) - 1; }
3584function encode_row(row) { return "" + (row + 1); }
3585function fix_row(cstr) { return cstr.replace(/([A-Z]|^)(\d+)$/,"$1$$$2"); }
3586function unfix_row(cstr) { return cstr.replace(/\$(\d+)$/,"$1"); }
3587
3588function 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; }
3589function 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; }
3590function fix_col(cstr) { return cstr.replace(/^([A-Z])/,"$$$1"); }
3591function unfix_col(cstr) { return cstr.replace(/^\$([A-Z])/,"$1"); }
3592
3593function split_cell(cstr) { return cstr.replace(/(\$?[A-Z]*)(\$?\d*)/,"$1,$2").split(","); }
3594//function decode_cell(cstr) { var splt = split_cell(cstr); return { c:decode_col(splt[0]), r:decode_row(splt[1]) }; }
3595function decode_cell(cstr) {
3596 var R = 0, C = 0;
3597 for(var i = 0; i < cstr.length; ++i) {
3598 var cc = cstr.charCodeAt(i);
3599 if(cc >= 48 && cc <= 57) R = 10 * R + (cc - 48);
3600 else if(cc >= 65 && cc <= 90) C = 26 * C + (cc - 64);
3601 }
3602 return { c: C - 1, r:R - 1 };
3603}
3604//function encode_cell(cell) { return encode_col(cell.c) + encode_row(cell.r); }
3605function encode_cell(cell) {
3606 var col = cell.c + 1;
3607 var s="";
3608 for(; col; col=((col-1)/26)|0) s = String.fromCharCode(((col-1)%26) + 65) + s;
3609 return s + (cell.r + 1);
3610}
3611function decode_range(range) {
3612 var idx = range.indexOf(":");
3613 if(idx == -1) return { s: decode_cell(range), e: decode_cell(range) };
3614 return { s: decode_cell(range.slice(0, idx)), e: decode_cell(range.slice(idx + 1)) };
3615}
3616function encode_range(cs,ce) {
3617 if(typeof ce === 'undefined' || typeof ce === 'number') {
3618return encode_range(cs.s, cs.e);
3619 }
3620if(typeof cs !== 'string') cs = encode_cell((cs));
3621 if(typeof ce !== 'string') ce = encode_cell((ce));
3622return cs == ce ? cs : cs + ":" + ce;
3623}
3624
3625function safe_decode_range(range) {
3626 var o = {s:{c:0,r:0},e:{c:0,r:0}};
3627 var idx = 0, i = 0, cc = 0;
3628 var len = range.length;
3629 for(idx = 0; i < len; ++i) {
3630 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3631 idx = 26*idx + cc;
3632 }
3633 o.s.c = --idx;
3634
3635 for(idx = 0; i < len; ++i) {
3636 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3637 idx = 10*idx + cc;
3638 }
3639 o.s.r = --idx;
3640
3641 if(i === len || range.charCodeAt(++i) === 58) { o.e.c=o.s.c; o.e.r=o.s.r; return o; }
3642
3643 for(idx = 0; i != len; ++i) {
3644 if((cc=range.charCodeAt(i)-64) < 1 || cc > 26) break;
3645 idx = 26*idx + cc;
3646 }
3647 o.e.c = --idx;
3648
3649 for(idx = 0; i != len; ++i) {
3650 if((cc=range.charCodeAt(i)-48) < 0 || cc > 9) break;
3651 idx = 10*idx + cc;
3652 }
3653 o.e.r = --idx;
3654 return o;
3655}
3656
3657function safe_format_cell(cell, v) {
3658 var q = (cell.t == 'd' && v instanceof Date);
3659 if(cell.z != null) try { return (cell.w = SSF.format(cell.z, q ? datenum(v) : v)); } catch(e) { }
3660 try { return (cell.w = SSF.format((cell.XF||{}).numFmtId||(q ? 14 : 0), q ? datenum(v) : v)); } catch(e) { return ''+v; }
3661}
3662
3663function format_cell(cell, v, o) {
3664 if(cell == null || cell.t == null || cell.t == 'z') return "";
3665 if(cell.w !== undefined) return cell.w;
3666 if(cell.t == 'd' && !cell.z && o && o.dateNF) cell.z = o.dateNF;
3667 if(v == undefined) return safe_format_cell(cell, cell.v);
3668 return safe_format_cell(cell, v);
3669}
3670
3671function sheet_to_workbook(sheet, opts) {
3672 var n = opts && opts.sheet ? opts.sheet : "Sheet1";
3673 var sheets = {}; sheets[n] = sheet;
3674 return { SheetNames: [n], Sheets: sheets };
3675}
3676
3677function sheet_add_aoa(_ws, data, opts) {
3678 var o = opts || {};
3679 var dense = _ws ? Array.isArray(_ws) : o.dense;
3680 if(DENSE != null && dense == null) dense = DENSE;
3681 var ws = _ws || (dense ? ([]) : ({}));
3682 var _R = 0, _C = 0;
3683 if(ws && o.origin != null) {
3684 if(typeof o.origin == 'number') _R = o.origin;
3685 else {
3686 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
3687 _R = _origin.r; _C = _origin.c;
3688 }
3689 if(!ws["!ref"]) ws["!ref"] = "A1:A1";
3690 }
3691 var range = ({s: {c:10000000, r:10000000}, e: {c:0, r:0}});
3692 if(ws['!ref']) {
3693 var _range = safe_decode_range(ws['!ref']);
3694 range.s.c = _range.s.c;
3695 range.s.r = _range.s.r;
3696 range.e.c = Math.max(range.e.c, _range.e.c);
3697 range.e.r = Math.max(range.e.r, _range.e.r);
3698 if(_R == -1) range.e.r = _R = _range.e.r + 1;
3699 }
3700 for(var R = 0; R != data.length; ++R) {
3701 if(!data[R]) continue;
3702 if(!Array.isArray(data[R])) throw new Error("aoa_to_sheet expects an array of arrays");
3703 for(var C = 0; C != data[R].length; ++C) {
3704 if(typeof data[R][C] === 'undefined') continue;
3705 var cell = ({v: data[R][C] });
3706 var __R = _R + R, __C = _C + C;
3707 if(range.s.r > __R) range.s.r = __R;
3708 if(range.s.c > __C) range.s.c = __C;
3709 if(range.e.r < __R) range.e.r = __R;
3710 if(range.e.c < __C) range.e.c = __C;
3711 if(data[R][C] && typeof data[R][C] === 'object' && !Array.isArray(data[R][C]) && !(data[R][C] instanceof Date)) cell = data[R][C];
3712 else {
3713 if(Array.isArray(cell.v)) { cell.f = data[R][C][1]; cell.v = cell.v[0]; }
3714 if(cell.v === null) { if(cell.f) cell.t = 'n'; else if(!o.sheetStubs) continue; else cell.t = 'z'; }
3715 else if(typeof cell.v === 'number') cell.t = 'n';
3716 else if(typeof cell.v === 'boolean') cell.t = 'b';
3717 else if(cell.v instanceof Date) {
3718 cell.z = o.dateNF || SSF._table[14];
3719 if(o.cellDates) { cell.t = 'd'; cell.w = SSF.format(cell.z, datenum(cell.v)); }
3720 else { cell.t = 'n'; cell.v = datenum(cell.v); cell.w = SSF.format(cell.z, cell.v); }
3721 }
3722 else cell.t = 's';
3723 }
3724 if(dense) {
3725 if(!ws[__R]) ws[__R] = [];
3726 if(ws[__R][__C] && ws[__R][__C].z) cell.z = ws[__R][__C].z;
3727 ws[__R][__C] = cell;
3728 } else {
3729 var cell_ref = encode_cell(({c:__C,r:__R}));
3730 if(ws[cell_ref] && ws[cell_ref].z) cell.z = ws[cell_ref].z;
3731 ws[cell_ref] = cell;
3732 }
3733 }
3734 }
3735 if(range.s.c < 10000000) ws['!ref'] = encode_range(range);
3736 return ws;
3737}
3738function aoa_to_sheet(data, opts) { return sheet_add_aoa(null, data, opts); }
3739
3740/* [MS-OLEPS] 2.2 PropertyType */
3741//var VT_EMPTY = 0x0000;
3742//var VT_NULL = 0x0001;
3743var VT_I2 = 0x0002;
3744var VT_I4 = 0x0003;
3745//var VT_R4 = 0x0004;
3746//var VT_R8 = 0x0005;
3747//var VT_CY = 0x0006;
3748//var VT_DATE = 0x0007;
3749//var VT_BSTR = 0x0008;
3750//var VT_ERROR = 0x000A;
3751var VT_BOOL = 0x000B;
3752var VT_VARIANT = 0x000C;
3753//var VT_DECIMAL = 0x000E;
3754//var VT_I1 = 0x0010;
3755//var VT_UI1 = 0x0011;
3756//var VT_UI2 = 0x0012;
3757var VT_UI4 = 0x0013;
3758//var VT_I8 = 0x0014;
3759//var VT_UI8 = 0x0015;
3760//var VT_INT = 0x0016;
3761//var VT_UINT = 0x0017;
3762var VT_LPSTR = 0x001E;
3763//var VT_LPWSTR = 0x001F;
3764var VT_FILETIME = 0x0040;
3765var VT_BLOB = 0x0041;
3766//var VT_STREAM = 0x0042;
3767//var VT_STORAGE = 0x0043;
3768//var VT_STREAMED_Object = 0x0044;
3769//var VT_STORED_Object = 0x0045;
3770//var VT_BLOB_Object = 0x0046;
3771var VT_CF = 0x0047;
3772//var VT_CLSID = 0x0048;
3773//var VT_VERSIONED_STREAM = 0x0049;
3774var VT_VECTOR = 0x1000;
3775//var VT_ARRAY = 0x2000;
3776
3777var VT_STRING = 0x0050; // 2.3.3.1.11 VtString
3778var VT_USTR = 0x0051; // 2.3.3.1.12 VtUnalignedString
3779var VT_CUSTOM = [VT_STRING, VT_USTR];
3780
3781/* [MS-OSHARED] 2.3.3.2.2.1 Document Summary Information PIDDSI */
3782var DocSummaryPIDDSI = {
37830x01: { n: 'CodePage', t: VT_I2 },
37840x02: { n: 'Category', t: VT_STRING },
37850x03: { n: 'PresentationFormat', t: VT_STRING },
37860x04: { n: 'ByteCount', t: VT_I4 },
37870x05: { n: 'LineCount', t: VT_I4 },
37880x06: { n: 'ParagraphCount', t: VT_I4 },
37890x07: { n: 'SlideCount', t: VT_I4 },
37900x08: { n: 'NoteCount', t: VT_I4 },
37910x09: { n: 'HiddenCount', t: VT_I4 },
37920x0a: { n: 'MultimediaClipCount', t: VT_I4 },
37930x0b: { n: 'ScaleCrop', t: VT_BOOL },
37940x0c: { n: 'HeadingPairs', t: VT_VECTOR | VT_VARIANT },
37950x0d: { n: 'TitlesOfParts', t: VT_VECTOR | VT_LPSTR },
37960x0e: { n: 'Manager', t: VT_STRING },
37970x0f: { n: 'Company', t: VT_STRING },
37980x10: { n: 'LinksUpToDate', t: VT_BOOL },
37990x11: { n: 'CharacterCount', t: VT_I4 },
38000x13: { n: 'SharedDoc', t: VT_BOOL },
38010x16: { n: 'HyperlinksChanged', t: VT_BOOL },
38020x17: { n: 'AppVersion', t: VT_I4, p: 'version' },
38030x18: { n: 'DigSig', t: VT_BLOB },
38040x1A: { n: 'ContentType', t: VT_STRING },
38050x1B: { n: 'ContentStatus', t: VT_STRING },
38060x1C: { n: 'Language', t: VT_STRING },
38070x1D: { n: 'Version', t: VT_STRING },
38080xFF: {}
3809};
3810
3811/* [MS-OSHARED] 2.3.3.2.1.1 Summary Information Property Set PIDSI */
3812var SummaryPIDSI = {
38130x01: { n: 'CodePage', t: VT_I2 },
38140x02: { n: 'Title', t: VT_STRING },
38150x03: { n: 'Subject', t: VT_STRING },
38160x04: { n: 'Author', t: VT_STRING },
38170x05: { n: 'Keywords', t: VT_STRING },
38180x06: { n: 'Comments', t: VT_STRING },
38190x07: { n: 'Template', t: VT_STRING },
38200x08: { n: 'LastAuthor', t: VT_STRING },
38210x09: { n: 'RevNumber', t: VT_STRING },
38220x0A: { n: 'EditTime', t: VT_FILETIME },
38230x0B: { n: 'LastPrinted', t: VT_FILETIME },
38240x0C: { n: 'CreatedDate', t: VT_FILETIME },
38250x0D: { n: 'ModifiedDate', t: VT_FILETIME },
38260x0E: { n: 'PageCount', t: VT_I4 },
38270x0F: { n: 'WordCount', t: VT_I4 },
38280x10: { n: 'CharCount', t: VT_I4 },
38290x11: { n: 'Thumbnail', t: VT_CF },
38300x12: { n: 'Application', t: VT_STRING },
38310x13: { n: 'DocSecurity', t: VT_I4 },
38320xFF: {}
3833};
3834
3835/* [MS-OLEPS] 2.18 */
3836var SpecialProperties = {
38370x80000000: { n: 'Locale', t: VT_UI4 },
38380x80000003: { n: 'Behavior', t: VT_UI4 },
38390x72627262: {}
3840};
3841
3842(function() {
3843 for(var y in SpecialProperties) if(Object.prototype.hasOwnProperty.call(SpecialProperties, y))
3844 DocSummaryPIDDSI[y] = SummaryPIDSI[y] = SpecialProperties[y];
3845})();
3846
3847var DocSummaryRE = evert_key(DocSummaryPIDDSI, "n");
3848var SummaryRE = evert_key(SummaryPIDSI, "n");
3849
3850/* [MS-XLS] 2.4.63 Country/Region codes */
3851var CountryEnum = {
38520x0001: "US", // United States
38530x0002: "CA", // Canada
38540x0003: "", // Latin America (except Brazil)
38550x0007: "RU", // Russia
38560x0014: "EG", // Egypt
38570x001E: "GR", // Greece
38580x001F: "NL", // Netherlands
38590x0020: "BE", // Belgium
38600x0021: "FR", // France
38610x0022: "ES", // Spain
38620x0024: "HU", // Hungary
38630x0027: "IT", // Italy
38640x0029: "CH", // Switzerland
38650x002B: "AT", // Austria
38660x002C: "GB", // United Kingdom
38670x002D: "DK", // Denmark
38680x002E: "SE", // Sweden
38690x002F: "NO", // Norway
38700x0030: "PL", // Poland
38710x0031: "DE", // Germany
38720x0034: "MX", // Mexico
38730x0037: "BR", // Brazil
38740x003d: "AU", // Australia
38750x0040: "NZ", // New Zealand
38760x0042: "TH", // Thailand
38770x0051: "JP", // Japan
38780x0052: "KR", // Korea
38790x0054: "VN", // Viet Nam
38800x0056: "CN", // China
38810x005A: "TR", // Turkey
38820x0069: "JS", // Ramastan
38830x00D5: "DZ", // Algeria
38840x00D8: "MA", // Morocco
38850x00DA: "LY", // Libya
38860x015F: "PT", // Portugal
38870x0162: "IS", // Iceland
38880x0166: "FI", // Finland
38890x01A4: "CZ", // Czech Republic
38900x0376: "TW", // Taiwan
38910x03C1: "LB", // Lebanon
38920x03C2: "JO", // Jordan
38930x03C3: "SY", // Syria
38940x03C4: "IQ", // Iraq
38950x03C5: "KW", // Kuwait
38960x03C6: "SA", // Saudi Arabia
38970x03CB: "AE", // United Arab Emirates
38980x03CC: "IL", // Israel
38990x03CE: "QA", // Qatar
39000x03D5: "IR", // Iran
39010xFFFF: "US" // United States
3902};
3903
3904/* [MS-XLS] 2.5.127 */
3905var XLSFillPattern = [
3906 null,
3907 'solid',
3908 'mediumGray',
3909 'darkGray',
3910 'lightGray',
3911 'darkHorizontal',
3912 'darkVertical',
3913 'darkDown',
3914 'darkUp',
3915 'darkGrid',
3916 'darkTrellis',
3917 'lightHorizontal',
3918 'lightVertical',
3919 'lightDown',
3920 'lightUp',
3921 'lightGrid',
3922 'lightTrellis',
3923 'gray125',
3924 'gray0625'
3925];
3926
3927function rgbify(arr) { return arr.map(function(x) { return [(x>>16)&255,(x>>8)&255,x&255]; }); }
3928
3929/* [MS-XLS] 2.5.161 */
3930/* [MS-XLSB] 2.5.75 Icv */
3931var _XLSIcv = rgbify([
3932 /* Color Constants */
3933 0x000000,
3934 0xFFFFFF,
3935 0xFF0000,
3936 0x00FF00,
3937 0x0000FF,
3938 0xFFFF00,
3939 0xFF00FF,
3940 0x00FFFF,
3941
3942 /* Overridable Defaults */
3943 0x000000,
3944 0xFFFFFF,
3945 0xFF0000,
3946 0x00FF00,
3947 0x0000FF,
3948 0xFFFF00,
3949 0xFF00FF,
3950 0x00FFFF,
3951
3952 0x800000,
3953 0x008000,
3954 0x000080,
3955 0x808000,
3956 0x800080,
3957 0x008080,
3958 0xC0C0C0,
3959 0x808080,
3960 0x9999FF,
3961 0x993366,
3962 0xFFFFCC,
3963 0xCCFFFF,
3964 0x660066,
3965 0xFF8080,
3966 0x0066CC,
3967 0xCCCCFF,
3968
3969 0x000080,
3970 0xFF00FF,
3971 0xFFFF00,
3972 0x00FFFF,
3973 0x800080,
3974 0x800000,
3975 0x008080,
3976 0x0000FF,
3977 0x00CCFF,
3978 0xCCFFFF,
3979 0xCCFFCC,
3980 0xFFFF99,
3981 0x99CCFF,
3982 0xFF99CC,
3983 0xCC99FF,
3984 0xFFCC99,
3985
3986 0x3366FF,
3987 0x33CCCC,
3988 0x99CC00,
3989 0xFFCC00,
3990 0xFF9900,
3991 0xFF6600,
3992 0x666699,
3993 0x969696,
3994 0x003366,
3995 0x339966,
3996 0x003300,
3997 0x333300,
3998 0x993300,
3999 0x993366,
4000 0x333399,
4001 0x333333,
4002
4003 /* Other entries to appease BIFF8/12 */
4004 0xFFFFFF, /* 0x40 icvForeground ?? */
4005 0x000000, /* 0x41 icvBackground ?? */
4006 0x000000, /* 0x42 icvFrame ?? */
4007 0x000000, /* 0x43 icv3D ?? */
4008 0x000000, /* 0x44 icv3DText ?? */
4009 0x000000, /* 0x45 icv3DHilite ?? */
4010 0x000000, /* 0x46 icv3DShadow ?? */
4011 0x000000, /* 0x47 icvHilite ?? */
4012 0x000000, /* 0x48 icvCtlText ?? */
4013 0x000000, /* 0x49 icvCtlScrl ?? */
4014 0x000000, /* 0x4A icvCtlInv ?? */
4015 0x000000, /* 0x4B icvCtlBody ?? */
4016 0x000000, /* 0x4C icvCtlFrame ?? */
4017 0x000000, /* 0x4D icvCtlFore ?? */
4018 0x000000, /* 0x4E icvCtlBack ?? */
4019 0x000000, /* 0x4F icvCtlNeutral */
4020 0x000000, /* 0x50 icvInfoBk ?? */
4021 0x000000 /* 0x51 icvInfoText ?? */
4022]);
4023var XLSIcv = dup(_XLSIcv);
4024
4025/* [MS-XLSB] 2.5.97.2 */
4026var BErr = {
40270x00: "#NULL!",
40280x07: "#DIV/0!",
40290x0F: "#VALUE!",
40300x17: "#REF!",
40310x1D: "#NAME?",
40320x24: "#NUM!",
40330x2A: "#N/A",
40340x2B: "#GETTING_DATA",
40350xFF: "#WTF?"
4036};
4037var RBErr = evert_num(BErr);
4038/* Parts enumerated in OPC spec, MS-XLSB and MS-XLSX */
4039/* 12.3 Part Summary <SpreadsheetML> */
4040/* 14.2 Part Summary <DrawingML> */
4041/* [MS-XLSX] 2.1 Part Enumerations ; [MS-XLSB] 2.1.7 Part Enumeration */
4042var ct2type/*{[string]:string}*/ = ({
4043 /* Workbook */
4044 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml": "workbooks",
4045
4046 /* Worksheet */
4047 "application/vnd.ms-excel.binIndexWs": "TODO", /* Binary Index */
4048
4049 /* Macrosheet */
4050 "application/vnd.ms-excel.intlmacrosheet": "TODO",
4051 "application/vnd.ms-excel.binIndexMs": "TODO", /* Binary Index */
4052
4053 /* File Properties */
4054 "application/vnd.openxmlformats-package.core-properties+xml": "coreprops",
4055 "application/vnd.openxmlformats-officedocument.custom-properties+xml": "custprops",
4056 "application/vnd.openxmlformats-officedocument.extended-properties+xml": "extprops",
4057
4058 /* Custom Data Properties */
4059 "application/vnd.openxmlformats-officedocument.customXmlProperties+xml": "TODO",
4060 "application/vnd.openxmlformats-officedocument.spreadsheetml.customProperty": "TODO",
4061
4062 /* PivotTable */
4063 "application/vnd.ms-excel.pivotTable": "TODO",
4064 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotTable+xml": "TODO",
4065
4066 /* Chart Objects */
4067 "application/vnd.openxmlformats-officedocument.drawingml.chart+xml": "TODO",
4068
4069 /* Chart Colors */
4070 "application/vnd.ms-office.chartcolorstyle+xml": "TODO",
4071
4072 /* Chart Style */
4073 "application/vnd.ms-office.chartstyle+xml": "TODO",
4074
4075 /* Chart Advanced */
4076 "application/vnd.ms-office.chartex+xml": "TODO",
4077
4078 /* Calculation Chain */
4079 "application/vnd.ms-excel.calcChain": "calcchains",
4080 "application/vnd.openxmlformats-officedocument.spreadsheetml.calcChain+xml": "calcchains",
4081
4082 /* Printer Settings */
4083 "application/vnd.openxmlformats-officedocument.spreadsheetml.printerSettings": "TODO",
4084
4085 /* ActiveX */
4086 "application/vnd.ms-office.activeX": "TODO",
4087 "application/vnd.ms-office.activeX+xml": "TODO",
4088
4089 /* Custom Toolbars */
4090 "application/vnd.ms-excel.attachedToolbars": "TODO",
4091
4092 /* External Data Connections */
4093 "application/vnd.ms-excel.connections": "TODO",
4094 "application/vnd.openxmlformats-officedocument.spreadsheetml.connections+xml": "TODO",
4095
4096 /* External Links */
4097 "application/vnd.ms-excel.externalLink": "links",
4098 "application/vnd.openxmlformats-officedocument.spreadsheetml.externalLink+xml": "links",
4099
4100 /* Metadata */
4101 "application/vnd.ms-excel.sheetMetadata": "TODO",
4102 "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "TODO",
4103
4104 /* PivotCache */
4105 "application/vnd.ms-excel.pivotCacheDefinition": "TODO",
4106 "application/vnd.ms-excel.pivotCacheRecords": "TODO",
4107 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheDefinition+xml": "TODO",
4108 "application/vnd.openxmlformats-officedocument.spreadsheetml.pivotCacheRecords+xml": "TODO",
4109
4110 /* Query Table */
4111 "application/vnd.ms-excel.queryTable": "TODO",
4112 "application/vnd.openxmlformats-officedocument.spreadsheetml.queryTable+xml": "TODO",
4113
4114 /* Shared Workbook */
4115 "application/vnd.ms-excel.userNames": "TODO",
4116 "application/vnd.ms-excel.revisionHeaders": "TODO",
4117 "application/vnd.ms-excel.revisionLog": "TODO",
4118 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionHeaders+xml": "TODO",
4119 "application/vnd.openxmlformats-officedocument.spreadsheetml.revisionLog+xml": "TODO",
4120 "application/vnd.openxmlformats-officedocument.spreadsheetml.userNames+xml": "TODO",
4121
4122 /* Single Cell Table */
4123 "application/vnd.ms-excel.tableSingleCells": "TODO",
4124 "application/vnd.openxmlformats-officedocument.spreadsheetml.tableSingleCells+xml": "TODO",
4125
4126 /* Slicer */
4127 "application/vnd.ms-excel.slicer": "TODO",
4128 "application/vnd.ms-excel.slicerCache": "TODO",
4129 "application/vnd.ms-excel.slicer+xml": "TODO",
4130 "application/vnd.ms-excel.slicerCache+xml": "TODO",
4131
4132 /* Sort Map */
4133 "application/vnd.ms-excel.wsSortMap": "TODO",
4134
4135 /* Table */
4136 "application/vnd.ms-excel.table": "TODO",
4137 "application/vnd.openxmlformats-officedocument.spreadsheetml.table+xml": "TODO",
4138
4139 /* Themes */
4140 "application/vnd.openxmlformats-officedocument.theme+xml": "themes",
4141
4142 /* Theme Override */
4143 "application/vnd.openxmlformats-officedocument.themeOverride+xml": "TODO",
4144
4145 /* Timeline */
4146 "application/vnd.ms-excel.Timeline+xml": "TODO", /* verify */
4147 "application/vnd.ms-excel.TimelineCache+xml": "TODO", /* verify */
4148
4149 /* VBA */
4150 "application/vnd.ms-office.vbaProject": "vba",
4151 "application/vnd.ms-office.vbaProjectSignature": "vba",
4152
4153 /* Volatile Dependencies */
4154 "application/vnd.ms-office.volatileDependencies": "TODO",
4155 "application/vnd.openxmlformats-officedocument.spreadsheetml.volatileDependencies+xml": "TODO",
4156
4157 /* Control Properties */
4158 "application/vnd.ms-excel.controlproperties+xml": "TODO",
4159
4160 /* Data Model */
4161 "application/vnd.openxmlformats-officedocument.model+data": "TODO",
4162
4163 /* Survey */
4164 "application/vnd.ms-excel.Survey+xml": "TODO",
4165
4166 /* Drawing */
4167 "application/vnd.openxmlformats-officedocument.drawing+xml": "drawings",
4168 "application/vnd.openxmlformats-officedocument.drawingml.chartshapes+xml": "TODO",
4169 "application/vnd.openxmlformats-officedocument.drawingml.diagramColors+xml": "TODO",
4170 "application/vnd.openxmlformats-officedocument.drawingml.diagramData+xml": "TODO",
4171 "application/vnd.openxmlformats-officedocument.drawingml.diagramLayout+xml": "TODO",
4172 "application/vnd.openxmlformats-officedocument.drawingml.diagramStyle+xml": "TODO",
4173
4174 /* VML */
4175 "application/vnd.openxmlformats-officedocument.vmlDrawing": "TODO",
4176
4177 "application/vnd.openxmlformats-package.relationships+xml": "rels",
4178 "application/vnd.openxmlformats-officedocument.oleObject": "TODO",
4179
4180 /* Image */
4181 "image/png": "TODO",
4182
4183 "sheet": "js"
4184});
4185
4186var CT_LIST = (function(){
4187 var o = {
4188 workbooks: {
4189 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet.main+xml",
4190 xlsm: "application/vnd.ms-excel.sheet.macroEnabled.main+xml",
4191 xlsb: "application/vnd.ms-excel.sheet.binary.macroEnabled.main",
4192 xlam: "application/vnd.ms-excel.addin.macroEnabled.main+xml",
4193 xltx: "application/vnd.openxmlformats-officedocument.spreadsheetml.template.main+xml"
4194 },
4195 strs: { /* Shared Strings */
4196 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.sharedStrings+xml",
4197 xlsb: "application/vnd.ms-excel.sharedStrings"
4198 },
4199 comments: { /* Comments */
4200 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml",
4201 xlsb: "application/vnd.ms-excel.comments"
4202 },
4203 sheets: { /* Worksheet */
4204 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.worksheet+xml",
4205 xlsb: "application/vnd.ms-excel.worksheet"
4206 },
4207 charts: { /* Chartsheet */
4208 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.chartsheet+xml",
4209 xlsb: "application/vnd.ms-excel.chartsheet"
4210 },
4211 dialogs: { /* Dialogsheet */
4212 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.dialogsheet+xml",
4213 xlsb: "application/vnd.ms-excel.dialogsheet"
4214 },
4215 macros: { /* Macrosheet (Excel 4.0 Macros) */
4216 xlsx: "application/vnd.ms-excel.macrosheet+xml",
4217 xlsb: "application/vnd.ms-excel.macrosheet"
4218 },
4219 styles: { /* Styles */
4220 xlsx: "application/vnd.openxmlformats-officedocument.spreadsheetml.styles+xml",
4221 xlsb: "application/vnd.ms-excel.styles"
4222 }
4223 };
4224 keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); });
4225 keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); });
4226 return o;
4227})();
4228
4229var type2ct/*{[string]:Array<string>}*/ = evert_arr(ct2type);
4230
4231XMLNS.CT = 'http://schemas.openxmlformats.org/package/2006/content-types';
4232
4233function new_ct() {
4234 return ({
4235 workbooks:[], sheets:[], charts:[], dialogs:[], macros:[],
4236 rels:[], strs:[], comments:[], links:[],
4237 coreprops:[], extprops:[], custprops:[], themes:[], styles:[],
4238 calcchains:[], vba: [], drawings: [],
4239 TODO:[], xmlns: "" });
4240}
4241
4242function parse_ct(data) {
4243 var ct = new_ct();
4244 if(!data || !data.match) return ct;
4245 var ctext = {};
4246 (data.match(tagregex)||[]).forEach(function(x) {
4247 var y = parsexmltag(x);
4248 switch(y[0].replace(nsregex,"<")) {
4249 case '<?xml': break;
4250 case '<Types': ct.xmlns = y['xmlns' + (y[0].match(/<(\w+):/)||["",""])[1] ]; break;
4251 case '<Default': ctext[y.Extension] = y.ContentType; break;
4252 case '<Override':
4253 if(ct[ct2type[y.ContentType]] !== undefined) ct[ct2type[y.ContentType]].push(y.PartName);
4254 break;
4255 }
4256 });
4257 if(ct.xmlns !== XMLNS.CT) throw new Error("Unknown Namespace: " + ct.xmlns);
4258 ct.calcchain = ct.calcchains.length > 0 ? ct.calcchains[0] : "";
4259 ct.sst = ct.strs.length > 0 ? ct.strs[0] : "";
4260 ct.style = ct.styles.length > 0 ? ct.styles[0] : "";
4261 ct.defaults = ctext;
4262 delete ct.calcchains;
4263 return ct;
4264}
4265
4266var CTYPE_XML_ROOT = writextag('Types', null, {
4267 'xmlns': XMLNS.CT,
4268 'xmlns:xsd': XMLNS.xsd,
4269 'xmlns:xsi': XMLNS.xsi
4270});
4271
4272var CTYPE_DEFAULTS = [
4273 ['xml', 'application/xml'],
4274 ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'],
4275 ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'],
4276 ['data', 'application/vnd.openxmlformats-officedocument.model+data'],
4277 /* from test files */
4278 ['bmp', 'image/bmp'],
4279 ['png', 'image/png'],
4280 ['gif', 'image/gif'],
4281 ['emf', 'image/x-emf'],
4282 ['wmf', 'image/x-wmf'],
4283 ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'],
4284 ['tif', 'image/tiff'], ['tiff', 'image/tiff'],
4285 ['pdf', 'application/pdf'],
4286 ['rels', type2ct.rels[0]]
4287].map(function(x) {
4288 return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]});
4289});
4290
4291function write_ct(ct, opts) {
4292 var o = [], v;
4293 o[o.length] = (XML_HEADER);
4294 o[o.length] = (CTYPE_XML_ROOT);
4295 o = o.concat(CTYPE_DEFAULTS);
4296
4297 /* only write first instance */
4298 var f1 = function(w) {
4299 if(ct[w] && ct[w].length > 0) {
4300 v = ct[w][0];
4301 o[o.length] = (writextag('Override', null, {
4302 'PartName': (v[0] == '/' ? "":"/") + v,
4303 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4304 }));
4305 }
4306 };
4307
4308 /* book type-specific */
4309 var f2 = function(w) {
4310 (ct[w]||[]).forEach(function(v) {
4311 o[o.length] = (writextag('Override', null, {
4312 'PartName': (v[0] == '/' ? "":"/") + v,
4313 'ContentType': CT_LIST[w][opts.bookType || 'xlsx']
4314 }));
4315 });
4316 };
4317
4318 /* standard type */
4319 var f3 = function(t) {
4320 (ct[t]||[]).forEach(function(v) {
4321 o[o.length] = (writextag('Override', null, {
4322 'PartName': (v[0] == '/' ? "":"/") + v,
4323 'ContentType': type2ct[t][0]
4324 }));
4325 });
4326 };
4327
4328 f1('workbooks');
4329 f2('sheets');
4330 f2('charts');
4331 f3('themes');
4332 ['strs', 'styles'].forEach(f1);
4333 ['coreprops', 'extprops', 'custprops'].forEach(f3);
4334 f3('vba');
4335 f3('comments');
4336 f3('drawings');
4337 if(o.length>2){ o[o.length] = ('</Types>'); o[1]=o[1].replace("/>",">"); }
4338 return o.join("");
4339}
4340/* 9.3 Relationships */
4341var RELS = ({
4342 WB: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4343 SHEET: "http://sheetjs.openxmlformats.org/officeDocument/2006/relationships/officeDocument",
4344 HLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/hyperlink",
4345 VML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/vmlDrawing",
4346 XPATH: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLinkPath",
4347 XMISS: "http://schemas.microsoft.com/office/2006/relationships/xlExternalLinkPath/xlPathMissing",
4348 XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink",
4349 CXML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml",
4350 CXMLP: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps",
4351 VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject"
4352});
4353
4354/* 9.3.3 Representing Relationships */
4355function get_rels_path(file) {
4356 var n = file.lastIndexOf("/");
4357 return file.slice(0,n+1) + '_rels/' + file.slice(n+1) + ".rels";
4358}
4359
4360function parse_rels(data, currentFilePath) {
4361 var rels = {"!id":{}};
4362 if (!data) return rels;
4363 if (currentFilePath.charAt(0) !== '/') {
4364 currentFilePath = '/'+currentFilePath;
4365 }
4366 var hash = {};
4367
4368 (data.match(tagregex)||[]).forEach(function(x) {
4369 var y = parsexmltag(x);
4370 /* 9.3.2.2 OPC_Relationships */
4371 if (y[0] === '<Relationship') {
4372 var rel = {}; rel.Type = y.Type; rel.Target = y.Target; rel.Id = y.Id; rel.TargetMode = y.TargetMode;
4373 var canonictarget = y.TargetMode === 'External' ? y.Target : resolve_path(y.Target, currentFilePath);
4374 rels[canonictarget] = rel;
4375 hash[y.Id] = rel;
4376 }
4377 });
4378 rels["!id"] = hash;
4379 return rels;
4380}
4381
4382XMLNS.RELS = 'http://schemas.openxmlformats.org/package/2006/relationships';
4383
4384var RELS_ROOT = writextag('Relationships', null, {
4385 //'xmlns:ns0': XMLNS.RELS,
4386 'xmlns': XMLNS.RELS
4387});
4388
4389/* TODO */
4390function write_rels(rels) {
4391 var o = [XML_HEADER, RELS_ROOT];
4392 keys(rels['!id']).forEach(function(rid) {
4393 o[o.length] = (writextag('Relationship', null, rels['!id'][rid]));
4394 });
4395 if(o.length>2){ o[o.length] = ('</Relationships>'); o[1]=o[1].replace("/>",">"); }
4396 return o.join("");
4397}
4398
4399var RELS_EXTERN = [RELS.HLINK, RELS.XPATH, RELS.XMISS];
4400function add_rels(rels, rId, f, type, relobj, targetmode) {
4401 if(!relobj) relobj = {};
4402 if(!rels['!id']) rels['!id'] = {};
4403 if(rId < 0) for(rId = 1; rels['!id']['rId' + rId]; ++rId){/* empty */}
4404 relobj.Id = 'rId' + rId;
4405 relobj.Type = type;
4406 relobj.Target = f;
4407 if(targetmode) relobj.TargetMode = targetmode;
4408 else if(RELS_EXTERN.indexOf(relobj.Type) > -1) relobj.TargetMode = "External";
4409 if(rels['!id'][relobj.Id]) throw new Error("Cannot rewrite rId " + rId);
4410 rels['!id'][relobj.Id] = relobj;
4411 rels[('/' + relobj.Target).replace("//","/")] = relobj;
4412 return rId;
4413}
4414/* ECMA-376 Part II 11.1 Core Properties Part */
4415/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4416var CORE_PROPS = [
4417 ["cp:category", "Category"],
4418 ["cp:contentStatus", "ContentStatus"],
4419 ["cp:keywords", "Keywords"],
4420 ["cp:lastModifiedBy", "LastAuthor"],
4421 ["cp:lastPrinted", "LastPrinted"],
4422 ["cp:revision", "RevNumber"],
4423 ["cp:version", "Version"],
4424 ["dc:creator", "Author"],
4425 ["dc:description", "Comments"],
4426 ["dc:identifier", "Identifier"],
4427 ["dc:language", "Language"],
4428 ["dc:subject", "Subject"],
4429 ["dc:title", "Title"],
4430 ["dcterms:created", "CreatedDate", 'date'],
4431 ["dcterms:modified", "ModifiedDate", 'date']
4432];
4433
4434XMLNS.CORE_PROPS = "http://schemas.openxmlformats.org/package/2006/metadata/core-properties";
4435RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties';
4436
4437var CORE_PROPS_REGEX = (function() {
4438 var r = new Array(CORE_PROPS.length);
4439 for(var i = 0; i < CORE_PROPS.length; ++i) {
4440 var f = CORE_PROPS[i];
4441 var g = "(?:"+ f[0].slice(0,f[0].indexOf(":")) +":)"+ f[0].slice(f[0].indexOf(":")+1);
4442 r[i] = new RegExp("<" + g + "[^>]*>([\\s\\S]*?)<\/" + g + ">");
4443 }
4444 return r;
4445})();
4446
4447function parse_core_props(data) {
4448 var p = {};
4449 data = utf8read(data);
4450
4451 for(var i = 0; i < CORE_PROPS.length; ++i) {
4452 var f = CORE_PROPS[i], cur = data.match(CORE_PROPS_REGEX[i]);
4453 if(cur != null && cur.length > 0) p[f[1]] = unescapexml(cur[1]);
4454 if(f[2] === 'date' && p[f[1]]) p[f[1]] = parseDate(p[f[1]]);
4455 }
4456
4457 return p;
4458}
4459
4460var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, {
4461 //'xmlns': XMLNS.CORE_PROPS,
4462 'xmlns:cp': XMLNS.CORE_PROPS,
4463 'xmlns:dc': XMLNS.dc,
4464 'xmlns:dcterms': XMLNS.dcterms,
4465 'xmlns:dcmitype': XMLNS.dcmitype,
4466 'xmlns:xsi': XMLNS.xsi
4467});
4468
4469function cp_doit(f, g, h, o, p) {
4470 if(p[f] != null || g == null || g === "") return;
4471 p[f] = g;
4472 g = escapexml(g);
4473 o[o.length] = (h ? writextag(f,g,h) : writetag(f,g));
4474}
4475
4476function write_core_props(cp, _opts) {
4477 var opts = _opts || {};
4478 var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {};
4479 if(!cp && !opts.Props) return o.join("");
4480
4481 if(cp) {
4482 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);
4483 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);
4484 }
4485
4486 for(var i = 0; i != CORE_PROPS.length; ++i) {
4487 var f = CORE_PROPS[i];
4488 var v = opts.Props && opts.Props[f[1]] != null ? opts.Props[f[1]] : cp ? cp[f[1]] : null;
4489 if(v === true) v = "1";
4490 else if(v === false) v = "0";
4491 else if(typeof v == "number") v = String(v);
4492 if(v != null) cp_doit(f[0], v, null, o, p);
4493 }
4494 if(o.length>2){ o[o.length] = ('</cp:coreProperties>'); o[1]=o[1].replace("/>",">"); }
4495 return o.join("");
4496}
4497/* 15.2.12.3 Extended File Properties Part */
4498/* [MS-OSHARED] 2.3.3.2.[1-2].1 (PIDSI/PIDDSI) */
4499var EXT_PROPS = [
4500 ["Application", "Application", "string"],
4501 ["AppVersion", "AppVersion", "string"],
4502 ["Company", "Company", "string"],
4503 ["DocSecurity", "DocSecurity", "string"],
4504 ["Manager", "Manager", "string"],
4505 ["HyperlinksChanged", "HyperlinksChanged", "bool"],
4506 ["SharedDoc", "SharedDoc", "bool"],
4507 ["LinksUpToDate", "LinksUpToDate", "bool"],
4508 ["ScaleCrop", "ScaleCrop", "bool"],
4509 ["HeadingPairs", "HeadingPairs", "raw"],
4510 ["TitlesOfParts", "TitlesOfParts", "raw"]
4511];
4512
4513XMLNS.EXT_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties";
4514RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties';
4515
4516var PseudoPropsPairs = [
4517 "Worksheets", "SheetNames",
4518 "NamedRanges", "DefinedNames",
4519 "Chartsheets", "ChartNames"
4520];
4521function load_props_pairs(HP, TOP, props, opts) {
4522 var v = [];
4523 if(typeof HP == "string") v = parseVector(HP, opts);
4524 else for(var j = 0; j < HP.length; ++j) v = v.concat(HP[j].map(function(hp) { return {v:hp}; }));
4525 var parts = (typeof TOP == "string") ? parseVector(TOP, opts).map(function (x) { return x.v; }) : TOP;
4526 var idx = 0, len = 0;
4527 if(parts.length > 0) for(var i = 0; i !== v.length; i += 2) {
4528 len = +(v[i+1].v);
4529 switch(v[i].v) {
4530 case "Worksheets":
4531 case "工作表":
4532 case "Листы":
4533 case "أوراق العمل":
4534 case "ワークシート":
4535 case "גליונות עבודה":
4536 case "Arbeitsblätter":
4537 case "Çalışma Sayfaları":
4538 case "Feuilles de calcul":
4539 case "Fogli di lavoro":
4540 case "Folhas de cálculo":
4541 case "Planilhas":
4542 case "Regneark":
4543 case "Hojas de cálculo":
4544 case "Werkbladen":
4545 props.Worksheets = len;
4546 props.SheetNames = parts.slice(idx, idx + len);
4547 break;
4548
4549 case "Named Ranges":
4550 case "Rangos con nombre":
4551 case "名前付き一覧":
4552 case "Benannte Bereiche":
4553 case "Navngivne områder":
4554 props.NamedRanges = len;
4555 props.DefinedNames = parts.slice(idx, idx + len);
4556 break;
4557
4558 case "Charts":
4559 case "Diagramme":
4560 props.Chartsheets = len;
4561 props.ChartNames = parts.slice(idx, idx + len);
4562 break;
4563 }
4564 idx += len;
4565 }
4566}
4567
4568function parse_ext_props(data, p, opts) {
4569 var q = {}; if(!p) p = {};
4570 data = utf8read(data);
4571
4572 EXT_PROPS.forEach(function(f) {
4573 var xml = (data.match(matchtag(f[0]))||[])[1];
4574 switch(f[2]) {
4575 case "string": if(xml) p[f[1]] = unescapexml(xml); break;
4576 case "bool": p[f[1]] = xml === "true"; break;
4577 case "raw":
4578 var cur = data.match(new RegExp("<" + f[0] + "[^>]*>([\\s\\S]*?)<\/" + f[0] + ">"));
4579 if(cur && cur.length > 0) q[f[1]] = cur[1];
4580 break;
4581 }
4582 });
4583
4584 if(q.HeadingPairs && q.TitlesOfParts) load_props_pairs(q.HeadingPairs, q.TitlesOfParts, p, opts);
4585
4586 return p;
4587}
4588
4589var EXT_PROPS_XML_ROOT = writextag('Properties', null, {
4590 'xmlns': XMLNS.EXT_PROPS,
4591 'xmlns:vt': XMLNS.vt
4592});
4593
4594function write_ext_props(cp) {
4595 var o = [], W = writextag;
4596 if(!cp) cp = {};
4597 cp.Application = "SheetJS";
4598 o[o.length] = (XML_HEADER);
4599 o[o.length] = (EXT_PROPS_XML_ROOT);
4600
4601 EXT_PROPS.forEach(function(f) {
4602 if(cp[f[1]] === undefined) return;
4603 var v;
4604 switch(f[2]) {
4605 case 'string': v = escapexml(String(cp[f[1]])); break;
4606 case 'bool': v = cp[f[1]] ? 'true' : 'false'; break;
4607 }
4608 if(v !== undefined) o[o.length] = (W(f[0], v));
4609 });
4610
4611 /* TODO: HeadingPairs, TitlesOfParts */
4612 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"})));
4613 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"})));
4614 if(o.length>2){ o[o.length] = ('</Properties>'); o[1]=o[1].replace("/>",">"); }
4615 return o.join("");
4616}
4617/* 15.2.12.2 Custom File Properties Part */
4618XMLNS.CUST_PROPS = "http://schemas.openxmlformats.org/officeDocument/2006/custom-properties";
4619RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties';
4620
4621var custregex = /<[^>]+>[^<]*/g;
4622function parse_cust_props(data, opts) {
4623 var p = {}, name = "";
4624 var m = data.match(custregex);
4625 if(m) for(var i = 0; i != m.length; ++i) {
4626 var x = m[i], y = parsexmltag(x);
4627 switch(y[0]) {
4628 case '<?xml': break;
4629 case '<Properties': break;
4630 case '<property': name = unescapexml(y.name); break;
4631 case '</property>': name = null; break;
4632 default: if (x.indexOf('<vt:') === 0) {
4633 var toks = x.split('>');
4634 var type = toks[0].slice(4), text = toks[1];
4635 /* 22.4.2.32 (CT_Variant). Omit the binary types from 22.4 (Variant Types) */
4636 switch(type) {
4637 case 'lpstr': case 'bstr': case 'lpwstr':
4638 p[name] = unescapexml(text);
4639 break;
4640 case 'bool':
4641 p[name] = parsexmlbool(text);
4642 break;
4643 case 'i1': case 'i2': case 'i4': case 'i8': case 'int': case 'uint':
4644 p[name] = parseInt(text, 10);
4645 break;
4646 case 'r4': case 'r8': case 'decimal':
4647 p[name] = parseFloat(text);
4648 break;
4649 case 'filetime': case 'date':
4650 p[name] = parseDate(text);
4651 break;
4652 case 'cy': case 'error':
4653 p[name] = unescapexml(text);
4654 break;
4655 default:
4656 if(type.slice(-1) == '/') break;
4657 if(opts.WTF && typeof console !== 'undefined') console.warn('Unexpected', x, type, toks);
4658 }
4659 } else if(x.slice(0,2) === "</") {/* empty */
4660 } else if(opts.WTF) throw new Error(x);
4661 }
4662 }
4663 return p;
4664}
4665
4666var CUST_PROPS_XML_ROOT = writextag('Properties', null, {
4667 'xmlns': XMLNS.CUST_PROPS,
4668 'xmlns:vt': XMLNS.vt
4669});
4670
4671function write_cust_props(cp) {
4672 var o = [XML_HEADER, CUST_PROPS_XML_ROOT];
4673 if(!cp) return o.join("");
4674 var pid = 1;
4675 keys(cp).forEach(function custprop(k) { ++pid;
4676 o[o.length] = (writextag('property', write_vt(cp[k], true), {
4677 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
4678 'pid': pid,
4679 'name': escapexml(k)
4680 }));
4681 });
4682 if(o.length>2){ o[o.length] = '</Properties>'; o[1]=o[1].replace("/>",">"); }
4683 return o.join("");
4684}
4685/* from js-harb (C) 2014-present SheetJS */
4686var DBF = (function() {
4687var dbf_codepage_map = {
4688 /* Code Pages Supported by Visual FoxPro */
46890x01: 437, 0x02: 850,
46900x03: 1252, 0x04: 10000,
46910x64: 852, 0x65: 866,
46920x66: 865, 0x67: 861,
46930x68: 895, 0x69: 620,
46940x6A: 737, 0x6B: 857,
46950x78: 950, 0x79: 949,
46960x7A: 936, 0x7B: 932,
46970x7C: 874, 0x7D: 1255,
46980x7E: 1256, 0x96: 10007,
46990x97: 10029, 0x98: 10006,
47000xC8: 1250, 0xC9: 1251,
47010xCA: 1254, 0xCB: 1253,
4702
4703 /* shapefile DBF extension */
47040x00: 20127, 0x08: 865,
47050x09: 437, 0x0A: 850,
47060x0B: 437, 0x0D: 437,
47070x0E: 850, 0x0F: 437,
47080x10: 850, 0x11: 437,
47090x12: 850, 0x13: 932,
47100x14: 850, 0x15: 437,
47110x16: 850, 0x17: 865,
47120x18: 437, 0x19: 437,
47130x1A: 850, 0x1B: 437,
47140x1C: 863, 0x1D: 850,
47150x1F: 852, 0x22: 852,
47160x23: 852, 0x24: 860,
47170x25: 850, 0x26: 866,
47180x37: 850, 0x40: 852,
47190x4D: 936, 0x4E: 949,
47200x4F: 950, 0x50: 874,
47210x57: 1252, 0x58: 1252,
47220x59: 1252,
4723
47240xFF: 16969
4725};
4726var dbf_reverse_map = evert({
47270x01: 437, 0x02: 850,
47280x03: 1252, 0x04: 10000,
47290x64: 852, 0x65: 866,
47300x66: 865, 0x67: 861,
47310x68: 895, 0x69: 620,
47320x6A: 737, 0x6B: 857,
47330x78: 950, 0x79: 949,
47340x7A: 936, 0x7B: 932,
47350x7C: 874, 0x7D: 1255,
47360x7E: 1256, 0x96: 10007,
47370x97: 10029, 0x98: 10006,
47380xC8: 1250, 0xC9: 1251,
47390xCA: 1254, 0xCB: 1253,
47400x00: 20127
4741});
4742var DBF_SUPPORTED_VERSIONS = [0x02, 0x03, 0x30, 0x31, 0x83, 0x8B, 0x8C, 0xF5];
4743/* TODO: find an actual specification */
4744function dbf_to_aoa(buf, opts) {
4745 var out = [];
4746 /* TODO: browser based */
4747 var d = (new_raw_buf(1));
4748 switch(opts.type) {
4749 case 'base64': d = s2a(Base64.decode(buf)); break;
4750 case 'binary': d = s2a(buf); break;
4751 case 'buffer':
4752 case 'array': d = buf; break;
4753 }
4754 prep_blob(d, 0);
4755 /* header */
4756 var ft = d.read_shift(1);
4757 var memo = false;
4758 var vfp = false, l7 = false;
4759 switch(ft) {
4760 case 0x02: case 0x03: break;
4761 case 0x30: vfp = true; memo = true; break;
4762 case 0x31: vfp = true; break;
4763 case 0x83: memo = true; break;
4764 case 0x8B: memo = true; break;
4765 case 0x8C: memo = true; l7 = true; break;
4766 case 0xF5: memo = true; break;
4767 default: throw new Error("DBF Unsupported Version: " + ft.toString(16));
4768 }
4769 var /*filedate = new Date(),*/ nrow = 0, fpos = 0;
4770 if(ft == 0x02) nrow = d.read_shift(2);
4771 /*filedate = new Date(d.read_shift(1) + 1900, d.read_shift(1) - 1, d.read_shift(1));*/d.l += 3;
4772 if(ft != 0x02) nrow = d.read_shift(4); if(nrow > 1048576) nrow = 1e6;
4773 if(ft != 0x02) fpos = d.read_shift(2);
4774 var rlen = d.read_shift(2);
4775
4776 var /*flags = 0,*/ current_cp = 1252;
4777 if(ft != 0x02) {
4778 d.l+=16;
4779 /*flags = */d.read_shift(1);
4780 //if(memo && ((flags & 0x02) === 0)) throw new Error("DBF Flags " + flags.toString(16) + " ft " + ft.toString(16));
4781
4782 /* codepage present in FoxPro */
4783 if(d[d.l] !== 0) current_cp = dbf_codepage_map[d[d.l]];
4784 d.l+=1;
4785
4786 d.l+=2;
4787 }
4788 if(l7) d.l += 36;
4789var fields = [], field = ({});
4790 var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11;
4791 while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) {
4792 field = ({});
4793 field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,"");
4794 d.l += ww;
4795 field.type = String.fromCharCode(d.read_shift(1));
4796 if(ft != 0x02 && !l7) field.offset = d.read_shift(4);
4797 field.len = d.read_shift(1);
4798 if(ft == 0x02) field.offset = d.read_shift(2);
4799 field.dec = d.read_shift(1);
4800 if(field.name.length) fields.push(field);
4801 if(ft != 0x02) d.l += l7 ? 13 : 14;
4802 switch(field.type) {
4803 case 'B': // VFP Double
4804 if((!vfp || field.len != 8) && opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
4805 break;
4806 case 'G': // General
4807 case 'P': // Picture
4808 if(opts.WTF) console.log('Skipping ' + field.name + ':' + field.type);
4809 break;
4810 case 'C': // character
4811 case 'D': // date
4812 case 'F': // floating point
4813 case 'I': // long
4814 case 'L': // boolean
4815 case 'M': // memo
4816 case 'N': // number
4817 case 'O': // double
4818 case 'T': // datetime
4819 case 'Y': // currency
4820 case '0': // VFP _NullFlags
4821 case '@': // timestamp
4822 case '+': // autoincrement
4823 break;
4824 default: throw new Error('Unknown Field Type: ' + field.type);
4825 }
4826 }
4827 if(d[d.l] !== 0x0D) d.l = fpos-1;
4828 else if(ft == 0x02) d.l = 0x209;
4829 if(ft != 0x02) {
4830 if(d.read_shift(1) !== 0x0D) throw new Error("DBF Terminator not found " + d.l + " " + d[d.l]);
4831 d.l = fpos;
4832 }
4833 /* data */
4834 var R = 0, C = 0;
4835 out[0] = [];
4836 for(C = 0; C != fields.length; ++C) out[0][C] = fields[C].name;
4837 while(nrow-- > 0) {
4838 if(d[d.l] === 0x2A) { d.l+=rlen; continue; }
4839 ++d.l;
4840 out[++R] = []; C = 0;
4841 for(C = 0; C != fields.length; ++C) {
4842 var dd = d.slice(d.l, d.l+fields[C].len); d.l+=fields[C].len;
4843 prep_blob(dd, 0);
4844 var s = cptable.utils.decode(current_cp, dd);
4845 switch(fields[C].type) {
4846 case 'C':
4847 out[R][C] = cptable.utils.decode(current_cp, dd);
4848 out[R][C] = out[R][C].trim();
4849 break;
4850 case 'D':
4851 if(s.length === 8) out[R][C] = new Date(+s.slice(0,4), +s.slice(4,6)-1, +s.slice(6,8));
4852 else out[R][C] = s;
4853 break;
4854 case 'F': out[R][C] = parseFloat(s.trim()); break;
4855 case '+': case 'I': out[R][C] = l7 ? dd.read_shift(-4, 'i') ^ 0x80000000 : dd.read_shift(4, 'i'); break;
4856 case 'L': switch(s.toUpperCase()) {
4857 case 'Y': case 'T': out[R][C] = true; break;
4858 case 'N': case 'F': out[R][C] = false; break;
4859 case ' ': case '?': out[R][C] = false; break; /* NOTE: technically uninitialized */
4860 default: throw new Error("DBF Unrecognized L:|" + s + "|");
4861 } break;
4862 case 'M': /* TODO: handle memo files */
4863 if(!memo) throw new Error("DBF Unexpected MEMO for type " + ft.toString(16));
4864 out[R][C] = "##MEMO##" + (l7 ? parseInt(s.trim(), 10): dd.read_shift(4));
4865 break;
4866 case 'N': out[R][C] = +s.replace(/\u0000/g,"").trim(); break;
4867 case '@': out[R][C] = new Date(dd.read_shift(-8, 'f') - 0x388317533400); break;
4868 case 'T': out[R][C] = new Date((dd.read_shift(4) - 0x253D8C) * 0x5265C00 + dd.read_shift(4)); break;
4869 case 'Y': out[R][C] = dd.read_shift(4,'i')/1e4; break;
4870 case 'O': out[R][C] = -dd.read_shift(-8, 'f'); break;
4871 case 'B': if(vfp && fields[C].len == 8) { out[R][C] = dd.read_shift(8,'f'); break; }
4872 /* falls through */
4873 case 'G': case 'P': dd.l += fields[C].len; break;
4874 case '0':
4875 if(fields[C].name === '_NullFlags') break;
4876 /* falls through */
4877 default: throw new Error("DBF Unsupported data type " + fields[C].type);
4878 }
4879 }
4880 }
4881 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));
4882 if(opts && opts.sheetRows) out = out.slice(0, opts.sheetRows);
4883 return out;
4884}
4885
4886function dbf_to_sheet(buf, opts) {
4887 var o = opts || {};
4888 if(!o.dateNF) o.dateNF = "yyyymmdd";
4889 return aoa_to_sheet(dbf_to_aoa(buf, o), o);
4890}
4891
4892function dbf_to_workbook(buf, opts) {
4893 try { return sheet_to_workbook(dbf_to_sheet(buf, opts), opts); }
4894 catch(e) { if(opts && opts.WTF) throw e; }
4895 return ({SheetNames:[],Sheets:{}});
4896}
4897
4898var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
4899function sheet_to_dbf(ws, opts) {
4900 var o = opts || {};
4901 if(+o.codepage >= 0) set_cp(+o.codepage);
4902 if(o.type == "string") throw new Error("Cannot write DBF to JS string");
4903 var ba = buf_array();
4904 var aoa = sheet_to_json(ws, {header:1, raw:true, cellDates:true});
4905 var headers = aoa[0], data = aoa.slice(1);
4906 var i = 0, j = 0, hcnt = 0, rlen = 1;
4907 for(i = 0; i < headers.length; ++i) {
4908 if(i == null) continue;
4909 ++hcnt;
4910 if(typeof headers[i] === 'number') headers[i] = headers[i].toString(10);
4911 if(typeof headers[i] !== 'string') throw new Error("DBF Invalid column name " + headers[i] + " |" + (typeof headers[i]) + "|");
4912 if(headers.indexOf(headers[i]) !== i) for(j=0; j<1024;++j)
4913 if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; }
4914 }
4915 var range = safe_decode_range(ws['!ref']);
4916 var coltypes = [];
4917 for(i = 0; i <= range.e.c - range.s.c; ++i) {
4918 var col = [];
4919 for(j=0; j < data.length; ++j) {
4920 if(data[j][i] != null) col.push(data[j][i]);
4921 }
4922 if(col.length == 0 || headers[i] == null) { coltypes[i] = '?'; continue; }
4923 var guess = '', _guess = '';
4924 for(j = 0; j < col.length; ++j) {
4925 switch(typeof col[j]) {
4926 /* TODO: check if L2 compat is desired */
4927 case 'number': _guess = 'B'; break;
4928 case 'string': _guess = 'C'; break;
4929 case 'boolean': _guess = 'L'; break;
4930 case 'object': _guess = col[j] instanceof Date ? 'D' : 'C'; break;
4931 default: _guess = 'C';
4932 }
4933 guess = guess && guess != _guess ? 'C' : _guess;
4934 if(guess == 'C') break;
4935 }
4936 rlen += _RLEN[guess] || 0;
4937 coltypes[i] = guess;
4938 }
4939
4940 var h = ba.next(32);
4941 h.write_shift(4, 0x13021130);
4942 h.write_shift(4, data.length);
4943 h.write_shift(2, 296 + 32 * hcnt);
4944 h.write_shift(2, rlen);
4945 for(i=0; i < 4; ++i) h.write_shift(4, 0);
4946 h.write_shift(4, 0x00000000 | ((+dbf_reverse_map[current_ansi] || 0x03)<<8));
4947
4948 for(i = 0, j = 0; i < headers.length; ++i) {
4949 if(headers[i] == null) continue;
4950 var hf = ba.next(32);
4951 var _f = (headers[i].slice(-10) + "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00").slice(0, 11);
4952 hf.write_shift(1, _f, "sbcs");
4953 hf.write_shift(1, coltypes[i] == '?' ? 'C' : coltypes[i], "sbcs");
4954 hf.write_shift(4, j);
4955 hf.write_shift(1, _RLEN[coltypes[i]] || 0);
4956 hf.write_shift(1, 0);
4957 hf.write_shift(1, 0x02);
4958 hf.write_shift(4, 0);
4959 hf.write_shift(1, 0);
4960 hf.write_shift(4, 0);
4961 hf.write_shift(4, 0);
4962 j += _RLEN[coltypes[i]] || 0;
4963 }
4964
4965 var hb = ba.next(264);
4966 hb.write_shift(4, 0x0000000D);
4967 for(i=0; i < 65;++i) hb.write_shift(4, 0x00000000);
4968 for(i=0; i < data.length; ++i) {
4969 var rout = ba.next(rlen);
4970 rout.write_shift(1, 0);
4971 for(j=0; j<headers.length; ++j) {
4972 if(headers[j] == null) continue;
4973 switch(coltypes[j]) {
4974 case 'L': rout.write_shift(1, data[i][j] == null ? 0x3F : data[i][j] ? 0x54 : 0x46); break;
4975 case 'B': rout.write_shift(8, data[i][j]||0, 'f'); break;
4976 case 'D':
4977 if(!data[i][j]) rout.write_shift(8, "00000000", "sbcs");
4978 else {
4979 rout.write_shift(4, ("0000"+data[i][j].getFullYear()).slice(-4), "sbcs");
4980 rout.write_shift(2, ("00"+(data[i][j].getMonth()+1)).slice(-2), "sbcs");
4981 rout.write_shift(2, ("00"+data[i][j].getDate()).slice(-2), "sbcs");
4982 } break;
4983 case 'C':
4984 var _s = String(data[i][j]||"");
4985 rout.write_shift(1, _s, "sbcs");
4986 for(hcnt=0; hcnt < 250-_s.length; ++hcnt) rout.write_shift(1, 0x20); break;
4987 }
4988 }
4989 // data
4990 }
4991 ba.next(1).write_shift(1, 0x1A);
4992 return ba.end();
4993}
4994 return {
4995 versions: DBF_SUPPORTED_VERSIONS,
4996 to_workbook: dbf_to_workbook,
4997 to_sheet: dbf_to_sheet,
4998 from_sheet: sheet_to_dbf
4999 };
5000})();
5001
5002var SYLK = (function() {
5003 /* TODO: stress test sequences */
5004 var sylk_escapes = ({
5005 AA:'À', BA:'Á', CA:'Â', DA:195, HA:'Ä', JA:197,
5006 AE:'È', BE:'É', CE:'Ê', HE:'Ë',
5007 AI:'Ì', BI:'Í', CI:'Î', HI:'Ï',
5008 AO:'Ò', BO:'Ó', CO:'Ô', DO:213, HO:'Ö',
5009 AU:'Ù', BU:'Ú', CU:'Û', HU:'Ü',
5010 Aa:'à', Ba:'á', Ca:'â', Da:227, Ha:'ä', Ja:229,
5011 Ae:'è', Be:'é', Ce:'ê', He:'ë',
5012 Ai:'ì', Bi:'í', Ci:'î', Hi:'ï',
5013 Ao:'ò', Bo:'ó', Co:'ô', Do:245, Ho:'ö',
5014 Au:'ù', Bu:'ú', Cu:'û', Hu:'ü',
5015 KC:'Ç', Kc:'ç', q:'æ', z:'œ', a:'Æ', j:'Œ',
5016 DN:209, Dn:241, Hy:255,
5017 S:169, c:170, R:174, B:180,
50180:176, 1:177, 2:178,
50193:179, 5:181, 6:182,
50207:183, Q:185, k:186, b:208, i:216, l:222, s:240, y:248,
5021 "!":161, '"':162, "#":163, "(":164, "%":165, "'":167, "H ":168,
5022 "+":171, ";":187, "<":188, "=":189, ">":190, "?":191, "{":223
5023 });
5024 var sylk_char_regex = new RegExp("\u001BN(" + keys(sylk_escapes).join("|").replace(/\|\|\|/, "|\\||").replace(/([?()+])/g,"\\$1") + "|\\|)", "gm");
5025 var sylk_char_fn = function(_, $1){ var o = sylk_escapes[$1]; return typeof o == "number" ? _getansi(o) : o; };
5026 var decode_sylk_char = function($$, $1, $2) { var newcc = (($1.charCodeAt(0) - 0x20)<<4) | ($2.charCodeAt(0) - 0x30); return newcc == 59 ? $$ : _getansi(newcc); };
5027 sylk_escapes["|"] = 254;
5028 /* TODO: find an actual specification */
5029 function sylk_to_aoa(d, opts) {
5030 switch(opts.type) {
5031 case 'base64': return sylk_to_aoa_str(Base64.decode(d), opts);
5032 case 'binary': return sylk_to_aoa_str(d, opts);
5033 case 'buffer': return sylk_to_aoa_str(d.toString('binary'), opts);
5034 case 'array': return sylk_to_aoa_str(cc2str(d), opts);
5035 }
5036 throw new Error("Unrecognized type " + opts.type);
5037 }
5038 function sylk_to_aoa_str(str, opts) {
5039 var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = [];
5040 var formats = [];
5041 var next_cell_format = null;
5042 var sht = {}, rowinfo = [], colinfo = [], cw = [];
5043 var Mval = 0, j;
5044 if(+opts.codepage >= 0) set_cp(+opts.codepage);
5045 for (; ri !== records.length; ++ri) {
5046 Mval = 0;
5047 var rstr=records[ri].trim().replace(/\x1B([\x20-\x2F])([\x30-\x3F])/g, decode_sylk_char).replace(sylk_char_regex, sylk_char_fn);
5048 var record=rstr.replace(/;;/g, "\u0000").split(";").map(function(x) { return x.replace(/\u0000/g, ";"); });
5049 var RT=record[0], val;
5050 if(rstr.length > 0) switch(RT) {
5051 case 'ID': break; /* header */
5052 case 'E': break; /* EOF */
5053 case 'B': break; /* dimensions */
5054 case 'O': break; /* options? */
5055 case 'P':
5056 if(record[1].charAt(0) == 'P')
5057 formats.push(rstr.slice(3).replace(/;;/g, ";"));
5058 break;
5059 case 'C':
5060 var C_seen_K = false, C_seen_X = false;
5061 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
5062 case 'X': C = parseInt(record[rj].slice(1))-1; C_seen_X = true; break;
5063 case 'Y':
5064 R = parseInt(record[rj].slice(1))-1; if(!C_seen_X) C = 0;
5065 for(j = arr.length; j <= R; ++j) arr[j] = [];
5066 break;
5067 case 'K':
5068 val = record[rj].slice(1);
5069 if(val.charAt(0) === '"') val = val.slice(1,val.length - 1);
5070 else if(val === 'TRUE') val = true;
5071 else if(val === 'FALSE') val = false;
5072 else if(!isNaN(fuzzynum(val))) {
5073 val = fuzzynum(val);
5074 if(next_cell_format !== null && SSF.is_date(next_cell_format)) val = numdate(val);
5075 } else if(!isNaN(fuzzydate(val).getDate())) {
5076 val = parseDate(val);
5077 }
5078 if(typeof cptable !== 'undefined' && typeof val == "string" && ((opts||{}).type != "string") && (opts||{}).codepage) val = cptable.utils.decode(opts.codepage, val);
5079 C_seen_K = true;
5080 break;
5081 case 'E':
5082 var formula = rc_to_a1(record[rj].slice(1), {r:R,c:C});
5083 arr[R][C] = [arr[R][C], formula];
5084 break;
5085 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
5086 }
5087 if(C_seen_K) { arr[R][C] = val; next_cell_format = null; }
5088 break;
5089 case 'F':
5090 var F_seen = 0;
5091 for(rj=1; rj<record.length; ++rj) switch(record[rj].charAt(0)) {
5092 case 'X': C = parseInt(record[rj].slice(1))-1; ++F_seen; break;
5093 case 'Y':
5094 R = parseInt(record[rj].slice(1))-1; /*C = 0;*/
5095 for(j = arr.length; j <= R; ++j) arr[j] = [];
5096 break;
5097 case 'M': Mval = parseInt(record[rj].slice(1)) / 20; break;
5098 case 'F': break; /* ??? */
5099 case 'G': break; /* hide grid */
5100 case 'P':
5101 next_cell_format = formats[parseInt(record[rj].slice(1))];
5102 break;
5103 case 'S': break; /* cell style */
5104 case 'D': break; /* column */
5105 case 'N': break; /* font */
5106 case 'W':
5107 cw = record[rj].slice(1).split(" ");
5108 for(j = parseInt(cw[0], 10); j <= parseInt(cw[1], 10); ++j) {
5109 Mval = parseInt(cw[2], 10);
5110 colinfo[j-1] = Mval === 0 ? {hidden:true}: {wch:Mval}; process_col(colinfo[j-1]);
5111 } break;
5112 case 'C': /* default column format */
5113 C = parseInt(record[rj].slice(1))-1;
5114 if(!colinfo[C]) colinfo[C] = {};
5115 break;
5116 case 'R': /* row properties */
5117 R = parseInt(record[rj].slice(1))-1;
5118 if(!rowinfo[R]) rowinfo[R] = {};
5119 if(Mval > 0) { rowinfo[R].hpt = Mval; rowinfo[R].hpx = pt2px(Mval); }
5120 else if(Mval === 0) rowinfo[R].hidden = true;
5121 break;
5122 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
5123 }
5124 if(F_seen < 1) next_cell_format = null; break;
5125 default: if(opts && opts.WTF) throw new Error("SYLK bad record " + rstr);
5126 }
5127 }
5128 if(rowinfo.length > 0) sht['!rows'] = rowinfo;
5129 if(colinfo.length > 0) sht['!cols'] = colinfo;
5130 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
5131 return [arr, sht];
5132 }
5133
5134 function sylk_to_sheet(d, opts) {
5135 var aoasht = sylk_to_aoa(d, opts);
5136 var aoa = aoasht[0], ws = aoasht[1];
5137 var o = aoa_to_sheet(aoa, opts);
5138 keys(ws).forEach(function(k) { o[k] = ws[k]; });
5139 return o;
5140 }
5141
5142 function sylk_to_workbook(d, opts) { return sheet_to_workbook(sylk_to_sheet(d, opts), opts); }
5143
5144 function write_ws_cell_sylk(cell, ws, R, C) {
5145 var o = "C;Y" + (R+1) + ";X" + (C+1) + ";K";
5146 switch(cell.t) {
5147 case 'n':
5148 o += (cell.v||0);
5149 if(cell.f && !cell.F) o += ";E" + a1_to_rc(cell.f, {r:R, c:C}); break;
5150 case 'b': o += cell.v ? "TRUE" : "FALSE"; break;
5151 case 'e': o += cell.w || cell.v; break;
5152 case 'd': o += '"' + (cell.w || cell.v) + '"'; break;
5153 case 's': o += '"' + cell.v.replace(/"/g,"") + '"'; break;
5154 }
5155 return o;
5156 }
5157
5158 function write_ws_cols_sylk(out, cols) {
5159 cols.forEach(function(col, i) {
5160 var rec = "F;W" + (i+1) + " " + (i+1) + " ";
5161 if(col.hidden) rec += "0";
5162 else {
5163 if(typeof col.width == 'number') col.wpx = width2px(col.width);
5164 if(typeof col.wpx == 'number') col.wch = px2char(col.wpx);
5165 if(typeof col.wch == 'number') rec += Math.round(col.wch);
5166 }
5167 if(rec.charAt(rec.length - 1) != " ") out.push(rec);
5168 });
5169 }
5170
5171 function write_ws_rows_sylk(out, rows) {
5172 rows.forEach(function(row, i) {
5173 var rec = "F;";
5174 if(row.hidden) rec += "M0;";
5175 else if(row.hpt) rec += "M" + 20 * row.hpt + ";";
5176 else if(row.hpx) rec += "M" + 20 * px2pt(row.hpx) + ";";
5177 if(rec.length > 2) out.push(rec + "R" + (i+1));
5178 });
5179 }
5180
5181 function sheet_to_sylk(ws, opts) {
5182 var preamble = ["ID;PWXL;N;E"], o = [];
5183 var r = safe_decode_range(ws['!ref']), cell;
5184 var dense = Array.isArray(ws);
5185 var RS = "\r\n";
5186
5187 preamble.push("P;PGeneral");
5188 preamble.push("F;P0;DG0G8;M255");
5189 if(ws['!cols']) write_ws_cols_sylk(preamble, ws['!cols']);
5190 if(ws['!rows']) write_ws_rows_sylk(preamble, ws['!rows']);
5191
5192 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(" "));
5193 for(var R = r.s.r; R <= r.e.r; ++R) {
5194 for(var C = r.s.c; C <= r.e.c; ++C) {
5195 var coord = encode_cell({r:R,c:C});
5196 cell = dense ? (ws[R]||[])[C]: ws[coord];
5197 if(!cell || (cell.v == null && (!cell.f || cell.F))) continue;
5198 o.push(write_ws_cell_sylk(cell, ws, R, C, opts));
5199 }
5200 }
5201 return preamble.join(RS) + RS + o.join(RS) + RS + "E" + RS;
5202 }
5203
5204 return {
5205 to_workbook: sylk_to_workbook,
5206 to_sheet: sylk_to_sheet,
5207 from_sheet: sheet_to_sylk
5208 };
5209})();
5210
5211var DIF = (function() {
5212 function dif_to_aoa(d, opts) {
5213 switch(opts.type) {
5214 case 'base64': return dif_to_aoa_str(Base64.decode(d), opts);
5215 case 'binary': return dif_to_aoa_str(d, opts);
5216 case 'buffer': return dif_to_aoa_str(d.toString('binary'), opts);
5217 case 'array': return dif_to_aoa_str(cc2str(d), opts);
5218 }
5219 throw new Error("Unrecognized type " + opts.type);
5220 }
5221 function dif_to_aoa_str(str, opts) {
5222 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
5223 for (; ri !== records.length; ++ri) {
5224 if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; }
5225 if (R < 0) continue;
5226 var metadata = records[ri].trim().split(",");
5227 var type = metadata[0], value = metadata[1];
5228 ++ri;
5229 var data = records[ri].trim();
5230 switch (+type) {
5231 case -1:
5232 if (data === 'BOT') { arr[++R] = []; C = 0; continue; }
5233 else if (data !== 'EOD') throw new Error("Unrecognized DIF special command " + data);
5234 break;
5235 case 0:
5236 if(data === 'TRUE') arr[R][C] = true;
5237 else if(data === 'FALSE') arr[R][C] = false;
5238 else if(!isNaN(fuzzynum(value))) arr[R][C] = fuzzynum(value);
5239 else if(!isNaN(fuzzydate(value).getDate())) arr[R][C] = parseDate(value);
5240 else arr[R][C] = value;
5241 ++C; break;
5242 case 1:
5243 data = data.slice(1,data.length-1);
5244 arr[R][C++] = data !== '' ? data : null;
5245 break;
5246 }
5247 if (data === 'EOD') break;
5248 }
5249 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
5250 return arr;
5251 }
5252
5253 function dif_to_sheet(str, opts) { return aoa_to_sheet(dif_to_aoa(str, opts), opts); }
5254 function dif_to_workbook(str, opts) { return sheet_to_workbook(dif_to_sheet(str, opts), opts); }
5255
5256 var sheet_to_dif = (function() {
5257 var push_field = function pf(o, topic, v, n, s) {
5258 o.push(topic);
5259 o.push(v + "," + n);
5260 o.push('"' + s.replace(/"/g,'""') + '"');
5261 };
5262 var push_value = function po(o, type, v, s) {
5263 o.push(type + "," + v);
5264 o.push(type == 1 ? '"' + s.replace(/"/g,'""') + '"' : s);
5265 };
5266 return function sheet_to_dif(ws) {
5267 var o = [];
5268 var r = safe_decode_range(ws['!ref']), cell;
5269 var dense = Array.isArray(ws);
5270 push_field(o, "TABLE", 0, 1, "sheetjs");
5271 push_field(o, "VECTORS", 0, r.e.r - r.s.r + 1,"");
5272 push_field(o, "TUPLES", 0, r.e.c - r.s.c + 1,"");
5273 push_field(o, "DATA", 0, 0,"");
5274 for(var R = r.s.r; R <= r.e.r; ++R) {
5275 push_value(o, -1, 0, "BOT");
5276 for(var C = r.s.c; C <= r.e.c; ++C) {
5277 var coord = encode_cell({r:R,c:C});
5278 cell = dense ? (ws[R]||[])[C] : ws[coord];
5279 if(!cell) { push_value(o, 1, 0, ""); continue;}
5280 switch(cell.t) {
5281 case 'n':
5282 var val = DIF_XL ? cell.w : cell.v;
5283 if(!val && cell.v != null) val = cell.v;
5284 if(val == null) {
5285 if(DIF_XL && cell.f && !cell.F) push_value(o, 1, 0, "=" + cell.f);
5286 else push_value(o, 1, 0, "");
5287 }
5288 else push_value(o, 0, val, "V");
5289 break;
5290 case 'b':
5291 push_value(o, 0, cell.v ? 1 : 0, cell.v ? "TRUE" : "FALSE");
5292 break;
5293 case 's':
5294 push_value(o, 1, 0, (!DIF_XL || isNaN(cell.v)) ? cell.v : '="' + cell.v + '"');
5295 break;
5296 case 'd':
5297 if(!cell.w) cell.w = SSF.format(cell.z || SSF._table[14], datenum(parseDate(cell.v)));
5298 if(DIF_XL) push_value(o, 0, cell.w, "V");
5299 else push_value(o, 1, 0, cell.w);
5300 break;
5301 default: push_value(o, 1, 0, "");
5302 }
5303 }
5304 }
5305 push_value(o, -1, 0, "EOD");
5306 var RS = "\r\n";
5307 var oo = o.join(RS);
5308 //while((oo.length & 0x7F) != 0) oo += "\0";
5309 return oo;
5310 };
5311 })();
5312 return {
5313 to_workbook: dif_to_workbook,
5314 to_sheet: dif_to_sheet,
5315 from_sheet: sheet_to_dif
5316 };
5317})();
5318
5319var ETH = (function() {
5320 function decode(s) { return s.replace(/\\b/g,"\\").replace(/\\c/g,":").replace(/\\n/g,"\n"); }
5321 function encode(s) { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); }
5322
5323 function eth_to_aoa(str, opts) {
5324 var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = [];
5325 for (; ri !== records.length; ++ri) {
5326 var record = records[ri].trim().split(":");
5327 if(record[0] !== 'cell') continue;
5328 var addr = decode_cell(record[1]);
5329 if(arr.length <= addr.r) for(R = arr.length; R <= addr.r; ++R) if(!arr[R]) arr[R] = [];
5330 R = addr.r; C = addr.c;
5331 switch(record[2]) {
5332 case 't': arr[R][C] = decode(record[3]); break;
5333 case 'v': arr[R][C] = +record[3]; break;
5334 case 'vtf': var _f = record[record.length - 1];
5335 /* falls through */
5336 case 'vtc':
5337 switch(record[3]) {
5338 case 'nl': arr[R][C] = +record[4] ? true : false; break;
5339 default: arr[R][C] = +record[4]; break;
5340 }
5341 if(record[2] == 'vtf') arr[R][C] = [arr[R][C], _f];
5342 }
5343 }
5344 if(opts && opts.sheetRows) arr = arr.slice(0, opts.sheetRows);
5345 return arr;
5346 }
5347
5348 function eth_to_sheet(d, opts) { return aoa_to_sheet(eth_to_aoa(d, opts), opts); }
5349 function eth_to_workbook(d, opts) { return sheet_to_workbook(eth_to_sheet(d, opts), opts); }
5350
5351 var header = [
5352 "socialcalc:version:1.5",
5353 "MIME-Version: 1.0",
5354 "Content-Type: multipart/mixed; boundary=SocialCalcSpreadsheetControlSave"
5355 ].join("\n");
5356
5357 var sep = [
5358 "--SocialCalcSpreadsheetControlSave",
5359 "Content-type: text/plain; charset=UTF-8"
5360 ].join("\n") + "\n";
5361
5362 /* TODO: the other parts */
5363 var meta = [
5364 "# SocialCalc Spreadsheet Control Save",
5365 "part:sheet"
5366 ].join("\n");
5367
5368 var end = "--SocialCalcSpreadsheetControlSave--";
5369
5370 function sheet_to_eth_data(ws) {
5371 if(!ws || !ws['!ref']) return "";
5372 var o = [], oo = [], cell, coord = "";
5373 var r = decode_range(ws['!ref']);
5374 var dense = Array.isArray(ws);
5375 for(var R = r.s.r; R <= r.e.r; ++R) {
5376 for(var C = r.s.c; C <= r.e.c; ++C) {
5377 coord = encode_cell({r:R,c:C});
5378 cell = dense ? (ws[R]||[])[C] : ws[coord];
5379 if(!cell || cell.v == null || cell.t === 'z') continue;
5380 oo = ["cell", coord, 't'];
5381 switch(cell.t) {
5382 case 's': case 'str': oo.push(encode(cell.v)); break;
5383 case 'n':
5384 if(!cell.f) { oo[2]='v'; oo[3]=cell.v; }
5385 else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); }
5386 break;
5387 case 'b':
5388 oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0";
5389 oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE'));
5390 break;
5391 case 'd':
5392 var t = datenum(parseDate(cell.v));
5393 oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t;
5394 oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t);
5395 break;
5396 case 'e': continue;
5397 }
5398 o.push(oo.join(":"));
5399 }
5400 }
5401 o.push("sheet:c:" + (r.e.c-r.s.c+1) + ":r:" + (r.e.r-r.s.r+1) + ":tvf:1");
5402 o.push("valueformat:1:text-wiki");
5403 //o.push("copiedfrom:" + ws['!ref']); // clipboard only
5404 return o.join("\n");
5405 }
5406
5407 function sheet_to_eth(ws) {
5408 return [header, sep, meta, sep, sheet_to_eth_data(ws), end].join("\n");
5409 // return ["version:1.5", sheet_to_eth_data(ws)].join("\n"); // clipboard form
5410 }
5411
5412 return {
5413 to_workbook: eth_to_workbook,
5414 to_sheet: eth_to_sheet,
5415 from_sheet: sheet_to_eth
5416 };
5417})();
5418
5419var PRN = (function() {
5420 function set_text_arr(data, arr, R, C, o) {
5421 if(o.raw) arr[R][C] = data;
5422 else if(data === 'TRUE') arr[R][C] = true;
5423 else if(data === 'FALSE') arr[R][C] = false;
5424 else if(data === ""){/* empty */}
5425 else if(!isNaN(fuzzynum(data))) arr[R][C] = fuzzynum(data);
5426 else if(!isNaN(fuzzydate(data).getDate())) arr[R][C] = parseDate(data);
5427 else arr[R][C] = data;
5428 }
5429
5430 function prn_to_aoa_str(f, opts) {
5431 var o = opts || {};
5432 var arr = ([]);
5433 if(!f || f.length === 0) return arr;
5434 var lines = f.split(/[\r\n]/);
5435 var L = lines.length - 1;
5436 while(L >= 0 && lines[L].length === 0) --L;
5437 var start = 10, idx = 0;
5438 var R = 0;
5439 for(; R <= L; ++R) {
5440 idx = lines[R].indexOf(" ");
5441 if(idx == -1) idx = lines[R].length; else idx++;
5442 start = Math.max(start, idx);
5443 }
5444 for(R = 0; R <= L; ++R) {
5445 arr[R] = [];
5446 /* TODO: confirm that widths are always 10 */
5447 var C = 0;
5448 set_text_arr(lines[R].slice(0, start).trim(), arr, R, C, o);
5449 for(C = 1; C <= (lines[R].length - start)/10 + 1; ++C)
5450 set_text_arr(lines[R].slice(start+(C-1)*10,start+C*10).trim(),arr,R,C,o);
5451 }
5452 if(o.sheetRows) arr = arr.slice(0, o.sheetRows);
5453 return arr;
5454 }
5455
5456 // List of accepted CSV separators
5457 var guess_seps = {
54580x2C: ',',
54590x09: "\t",
54600x3B: ';'
5461 };
5462
5463 // CSV separator weights to be used in case of equal numbers
5464 var guess_sep_weights = {
54650x2C: 3,
54660x09: 2,
54670x3B: 1
5468 };
5469
5470 function guess_sep(str) {
5471 var cnt = {}, instr = false, end = 0, cc = 0;
5472 for(;end < str.length;++end) {
5473 if((cc=str.charCodeAt(end)) == 0x22) instr = !instr;
5474 else if(!instr && cc in guess_seps) cnt[cc] = (cnt[cc]||0)+1;
5475 }
5476
5477 cc = [];
5478 for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
5479 cc.push([ cnt[end], end ]);
5480 }
5481
5482 if ( !cc.length ) {
5483 cnt = guess_sep_weights;
5484 for(end in cnt) if ( Object.prototype.hasOwnProperty.call(cnt, end) ) {
5485 cc.push([ cnt[end], end ]);
5486 }
5487 }
5488
5489 cc.sort(function(a, b) { return a[0] - b[0] || guess_sep_weights[a[1]] - guess_sep_weights[b[1]]; });
5490
5491 return guess_seps[cc.pop()[1]];
5492 }
5493
5494 function dsv_to_sheet_str(str, opts) {
5495 var o = opts || {};
5496 var sep = "";
5497 if(DENSE != null && o.dense == null) o.dense = DENSE;
5498 var ws = o.dense ? ([]) : ({});
5499 var range = ({s: {c:0, r:0}, e: {c:0, r:0}});
5500
5501 if(str.slice(0,4) == "sep=") {
5502 // If the line ends in \r\n
5503 if(str.charCodeAt(5) == 13 && str.charCodeAt(6) == 10 ) {
5504 sep = str.charAt(4); str = str.slice(7);
5505 }
5506 // If line ends in \r OR \n
5507 else if(str.charCodeAt(5) == 13 || str.charCodeAt(5) == 10 ) {
5508 sep = str.charAt(4); str = str.slice(6);
5509 }
5510 }
5511 else sep = guess_sep(str.slice(0,1024));
5512 var R = 0, C = 0, v = 0;
5513 var start = 0, end = 0, sepcc = sep.charCodeAt(0), instr = false, cc=0;
5514 str = str.replace(/\r\n/mg, "\n");
5515 var _re = o.dateNF != null ? dateNF_regex(o.dateNF) : null;
5516 function finish_cell() {
5517 var s = str.slice(start, end);
5518 var cell = ({});
5519 if(s.charAt(0) == '"' && s.charAt(s.length - 1) == '"') s = s.slice(1,-1).replace(/""/g,'"');
5520 if(s.length === 0) cell.t = 'z';
5521 else if(o.raw) { cell.t = 's'; cell.v = s; }
5522 else if(s.trim().length === 0) { cell.t = 's'; cell.v = s; }
5523 else if(s.charCodeAt(0) == 0x3D) {
5524 if(s.charCodeAt(1) == 0x22 && s.charCodeAt(s.length - 1) == 0x22) { cell.t = 's'; cell.v = s.slice(2,-1).replace(/""/g,'"'); }
5525 else if(fuzzyfmla(s)) { cell.t = 'n'; cell.f = s.slice(1); }
5526 else { cell.t = 's'; cell.v = s; } }
5527 else if(s == "TRUE") { cell.t = 'b'; cell.v = true; }
5528 else if(s == "FALSE") { cell.t = 'b'; cell.v = false; }
5529 else if(!isNaN(v = fuzzynum(s))) { cell.t = 'n'; if(o.cellText !== false) cell.w = s; cell.v = v; }
5530 else if(!isNaN(fuzzydate(s).getDate()) || _re && s.match(_re)) {
5531 cell.z = o.dateNF || SSF._table[14];
5532 var k = 0;
5533 if(_re && s.match(_re)){ s=dateNF_fix(s, o.dateNF, (s.match(_re)||[])); k=1; }
5534 if(o.cellDates) { cell.t = 'd'; cell.v = parseDate(s, k); }
5535 else { cell.t = 'n'; cell.v = datenum(parseDate(s, k)); }
5536 if(o.cellText !== false) cell.w = SSF.format(cell.z, cell.v instanceof Date ? datenum(cell.v):cell.v);
5537 if(!o.cellNF) delete cell.z;
5538 } else {
5539 cell.t = 's';
5540 cell.v = s;
5541 }
5542 if(cell.t == 'z'){}
5543 else if(o.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = cell; }
5544 else ws[encode_cell({c:C,r:R})] = cell;
5545 start = end+1;
5546 if(range.e.c < C) range.e.c = C;
5547 if(range.e.r < R) range.e.r = R;
5548 if(cc == sepcc) ++C; else { C = 0; ++R; if(o.sheetRows && o.sheetRows <= R) return true; }
5549 }
5550 outer: for(;end < str.length;++end) switch((cc=str.charCodeAt(end))) {
5551 case 0x22: instr = !instr; break;
5552 case sepcc: case 0x0a: case 0x0d: if(!instr && finish_cell()) break outer; break;
5553 default: break;
5554 }
5555 if(end - start > 0) finish_cell();
5556
5557 ws['!ref'] = encode_range(range);
5558 return ws;
5559 }
5560
5561 function prn_to_sheet_str(str, opts) {
5562 if(!(opts && opts.PRN)) return dsv_to_sheet_str(str, opts);
5563 if(str.slice(0,4) == "sep=") return dsv_to_sheet_str(str, opts);
5564 if(str.indexOf("\t") >= 0 || str.indexOf(",") >= 0 || str.indexOf(";") >= 0) return dsv_to_sheet_str(str, opts);
5565 return aoa_to_sheet(prn_to_aoa_str(str, opts), opts);
5566 }
5567
5568 function prn_to_sheet(d, opts) {
5569 var str = "", bytes = opts.type == 'string' ? [0,0,0,0] : firstbyte(d, opts);
5570 switch(opts.type) {
5571 case 'base64': str = Base64.decode(d); break;
5572 case 'binary': str = d; break;
5573 case 'buffer':
5574 if(opts.codepage == 65001) str = d.toString('utf8');
5575 else if(opts.codepage && typeof cptable !== 'undefined') str = cptable.utils.decode(opts.codepage, d);
5576 else str = d.toString('binary');
5577 break;
5578 case 'array': str = cc2str(d); break;
5579 case 'string': str = d; break;
5580 default: throw new Error("Unrecognized type " + opts.type);
5581 }
5582 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str.slice(3));
5583 else if((opts.type == 'binary') && typeof cptable !== 'undefined' && opts.codepage) str = cptable.utils.decode(opts.codepage, cptable.utils.encode(1252,str));
5584 if(str.slice(0,19) == "socialcalc:version:") return ETH.to_sheet(opts.type == 'string' ? str : utf8read(str), opts);
5585 return prn_to_sheet_str(str, opts);
5586 }
5587
5588 function prn_to_workbook(d, opts) { return sheet_to_workbook(prn_to_sheet(d, opts), opts); }
5589
5590 function sheet_to_prn(ws) {
5591 var o = [];
5592 var r = safe_decode_range(ws['!ref']), cell;
5593 var dense = Array.isArray(ws);
5594 for(var R = r.s.r; R <= r.e.r; ++R) {
5595 var oo = [];
5596 for(var C = r.s.c; C <= r.e.c; ++C) {
5597 var coord = encode_cell({r:R,c:C});
5598 cell = dense ? (ws[R]||[])[C] : ws[coord];
5599 if(!cell || cell.v == null) { oo.push(" "); continue; }
5600 var w = (cell.w || (format_cell(cell), cell.w) || "").slice(0,10);
5601 while(w.length < 10) w += " ";
5602 oo.push(w + (C === 0 ? " " : ""));
5603 }
5604 o.push(oo.join(""));
5605 }
5606 return o.join("\n");
5607 }
5608
5609 return {
5610 to_workbook: prn_to_workbook,
5611 to_sheet: prn_to_sheet,
5612 from_sheet: sheet_to_prn
5613 };
5614})();
5615
5616/* Excel defaults to SYLK but warns if data is not valid */
5617function read_wb_ID(d, opts) {
5618 var o = opts || {}, OLD_WTF = !!o.WTF; o.WTF = true;
5619 try {
5620 var out = SYLK.to_workbook(d, o);
5621 o.WTF = OLD_WTF;
5622 return out;
5623 } catch(e) {
5624 o.WTF = OLD_WTF;
5625 if(!e.message.match(/SYLK bad record ID/) && OLD_WTF) throw e;
5626 return PRN.to_workbook(d, opts);
5627 }
5628}
5629
5630/* 18.4.7 rPr CT_RPrElt */
5631function parse_rpr(rpr) {
5632 var font = {}, m = rpr.match(tagregex), i = 0;
5633 var pass = false;
5634 if(m) for(;i!=m.length; ++i) {
5635 var y = parsexmltag(m[i]);
5636 switch(y[0].replace(/\w*:/g,"")) {
5637 /* 18.8.12 condense CT_BooleanProperty */
5638 /* ** not required . */
5639 case '<condense': break;
5640 /* 18.8.17 extend CT_BooleanProperty */
5641 /* ** not required . */
5642 case '<extend': break;
5643 /* 18.8.36 shadow CT_BooleanProperty */
5644 /* ** not required . */
5645 case '<shadow':
5646 if(!y.val) break;
5647 /* falls through */
5648 case '<shadow>':
5649 case '<shadow/>': font.shadow = 1; break;
5650 case '</shadow>': break;
5651
5652 /* 18.4.1 charset CT_IntProperty TODO */
5653 case '<charset':
5654 if(y.val == '1') break;
5655 font.cp = CS2CP[parseInt(y.val, 10)];
5656 break;
5657
5658 /* 18.4.2 outline CT_BooleanProperty TODO */
5659 case '<outline':
5660 if(!y.val) break;
5661 /* falls through */
5662 case '<outline>':
5663 case '<outline/>': font.outline = 1; break;
5664 case '</outline>': break;
5665
5666 /* 18.4.5 rFont CT_FontName */
5667 case '<rFont': font.name = y.val; break;
5668
5669 /* 18.4.11 sz CT_FontSize */
5670 case '<sz': font.sz = y.val; break;
5671
5672 /* 18.4.10 strike CT_BooleanProperty */
5673 case '<strike':
5674 if(!y.val) break;
5675 /* falls through */
5676 case '<strike>':
5677 case '<strike/>': font.strike = 1; break;
5678 case '</strike>': break;
5679
5680 /* 18.4.13 u CT_UnderlineProperty */
5681 case '<u':
5682 if(!y.val) break;
5683 switch(y.val) {
5684 case 'double': font.uval = "double"; break;
5685 case 'singleAccounting': font.uval = "single-accounting"; break;
5686 case 'doubleAccounting': font.uval = "double-accounting"; break;
5687 }
5688 /* falls through */
5689 case '<u>':
5690 case '<u/>': font.u = 1; break;
5691 case '</u>': break;
5692
5693 /* 18.8.2 b */
5694 case '<b':
5695 if(y.val == '0') break;
5696 /* falls through */
5697 case '<b>':
5698 case '<b/>': font.b = 1; break;
5699 case '</b>': break;
5700
5701 /* 18.8.26 i */
5702 case '<i':
5703 if(y.val == '0') break;
5704 /* falls through */
5705 case '<i>':
5706 case '<i/>': font.i = 1; break;
5707 case '</i>': break;
5708
5709 /* 18.3.1.15 color CT_Color TODO: tint, theme, auto, indexed */
5710 case '<color':
5711 if(y.rgb) font.color = y.rgb.slice(2,8);
5712 break;
5713
5714 /* 18.8.18 family ST_FontFamily */
5715 case '<family': font.family = y.val; break;
5716
5717 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty TODO */
5718 case '<vertAlign': font.valign = y.val; break;
5719
5720 /* 18.8.35 scheme CT_FontScheme TODO */
5721 case '<scheme': break;
5722
5723 /* 18.2.10 extLst CT_ExtensionList ? */
5724 case '<extLst': case '<extLst>': case '</extLst>': break;
5725 case '<ext': pass = true; break;
5726 case '</ext>': pass = false; break;
5727 default:
5728 if(y[0].charCodeAt(1) !== 47 && !pass) throw new Error('Unrecognized rich format ' + y[0]);
5729 }
5730 }
5731 return font;
5732}
5733
5734var parse_rs = (function() {
5735 var tregex = matchtag("t"), rpregex = matchtag("rPr");
5736 /* 18.4.4 r CT_RElt */
5737 function parse_r(r) {
5738 /* 18.4.12 t ST_Xstring */
5739 var t = r.match(tregex)/*, cp = 65001*/;
5740 if(!t) return {t:"s", v:""};
5741
5742 var o = ({t:'s', v:unescapexml(t[1])});
5743 var rpr = r.match(rpregex);
5744 if(rpr) o.s = parse_rpr(rpr[1]);
5745 return o;
5746 }
5747 var rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/;
5748 return function parse_rs(rs) {
5749 return rs.replace(rregex,"").split(rend).map(parse_r).filter(function(r) { return r.v; });
5750 };
5751})();
5752
5753
5754/* Parse a list of <r> tags */
5755var rs_to_html = (function parse_rs_factory() {
5756 var nlregex = /(\r\n|\n)/g;
5757 function parse_rpr2(font, intro, outro) {
5758 var style = [];
5759
5760 if(font.u) style.push("text-decoration: underline;");
5761 if(font.uval) style.push("text-underline-style:" + font.uval + ";");
5762 if(font.sz) style.push("font-size:" + font.sz + "pt;");
5763 if(font.outline) style.push("text-effect: outline;");
5764 if(font.shadow) style.push("text-shadow: auto;");
5765 intro.push('<span style="' + style.join("") + '">');
5766
5767 if(font.b) { intro.push("<b>"); outro.push("</b>"); }
5768 if(font.i) { intro.push("<i>"); outro.push("</i>"); }
5769 if(font.strike) { intro.push("<s>"); outro.push("</s>"); }
5770
5771 var align = font.valign || "";
5772 if(align == "superscript" || align == "super") align = "sup";
5773 else if(align == "subscript") align = "sub";
5774 if(align != "") { intro.push("<" + align + ">"); outro.push("</" + align + ">"); }
5775
5776 outro.push("</span>");
5777 return font;
5778 }
5779
5780 /* 18.4.4 r CT_RElt */
5781 function r_to_html(r) {
5782 var terms = [[],r.v,[]];
5783 if(!r.v) return "";
5784
5785 if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
5786
5787 return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
5788 }
5789
5790 return function parse_rs(rs) {
5791 return rs.map(r_to_html).join("");
5792 };
5793})();
5794
5795/* 18.4.8 si CT_Rst */
5796var sitregex = /<(?:\w+:)?t[^>]*>([^<]*)<\/(?:\w+:)?t>/g, sirregex = /<(?:\w+:)?r>/;
5797var sirphregex = /<(?:\w+:)?rPh.*?>([\s\S]*?)<\/(?:\w+:)?rPh>/g;
5798function parse_si(x, opts) {
5799 var html = opts ? opts.cellHTML : true;
5800 var z = {};
5801 if(!x) return { t: "" };
5802 //var y;
5803 /* 18.4.12 t ST_Xstring (Plaintext String) */
5804 // TODO: is whitespace actually valid here?
5805 if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
5806 z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
5807 z.r = utf8read(x);
5808 if(html) z.h = escapehtml(z.t);
5809 }
5810 /* 18.4.4 r CT_RElt (Rich Text Run) */
5811 else if((/*y = */x.match(sirregex))) {
5812 z.r = utf8read(x);
5813 z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
5814 if(html) z.h = rs_to_html(parse_rs(z.r));
5815 }
5816 /* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
5817 /* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
5818 return z;
5819}
5820
5821/* 18.4 Shared String Table */
5822var sstr0 = /<(?:\w+:)?sst([^>]*)>([\s\S]*)<\/(?:\w+:)?sst>/;
5823var sstr1 = /<(?:\w+:)?(?:si|sstItem)>/g;
5824var sstr2 = /<\/(?:\w+:)?(?:si|sstItem)>/;
5825function parse_sst_xml(data, opts) {
5826 var s = ([]), ss = "";
5827 if(!data) return s;
5828 /* 18.4.9 sst CT_Sst */
5829 var sst = data.match(sstr0);
5830 if(sst) {
5831 ss = sst[2].replace(sstr1,"").split(sstr2);
5832 for(var i = 0; i != ss.length; ++i) {
5833 var o = parse_si(ss[i].trim(), opts);
5834 if(o != null) s[s.length] = o;
5835 }
5836 sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
5837 }
5838 return s;
5839}
5840
5841RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings";
5842var straywsregex = /^\s|\s$|[\t\n\r]/;
5843function write_sst_xml(sst, opts) {
5844 if(!opts.bookSST) return "";
5845 var o = [XML_HEADER];
5846 o[o.length] = (writextag('sst', null, {
5847 xmlns: XMLNS.main[0],
5848 count: sst.Count,
5849 uniqueCount: sst.Unique
5850 }));
5851 for(var i = 0; i != sst.length; ++i) { if(sst[i] == null) continue;
5852 var s = sst[i];
5853 var sitag = "<si>";
5854 if(s.r) sitag += s.r;
5855 else {
5856 sitag += "<t";
5857 if(!s.t) s.t = "";
5858 if(s.t.match(straywsregex)) sitag += ' xml:space="preserve"';
5859 sitag += ">" + escapexml(s.t) + "</t>";
5860 }
5861 sitag += "</si>";
5862 o[o.length] = (sitag);
5863 }
5864 if(o.length>2){ o[o.length] = ('</sst>'); o[1]=o[1].replace("/>",">"); }
5865 return o.join("");
5866}
5867function hex2RGB(h) {
5868 var o = h.slice(h[0]==="#"?1:0).slice(0,6);
5869 return [parseInt(o.slice(0,2),16),parseInt(o.slice(2,4),16),parseInt(o.slice(4,6),16)];
5870}
5871function rgb2Hex(rgb) {
5872 for(var i=0,o=1; i!=3; ++i) o = o*256 + (rgb[i]>255?255:rgb[i]<0?0:rgb[i]);
5873 return o.toString(16).toUpperCase().slice(1);
5874}
5875
5876function rgb2HSL(rgb) {
5877 var R = rgb[0]/255, G = rgb[1]/255, B=rgb[2]/255;
5878 var M = Math.max(R, G, B), m = Math.min(R, G, B), C = M - m;
5879 if(C === 0) return [0, 0, R];
5880
5881 var H6 = 0, S = 0, L2 = (M + m);
5882 S = C / (L2 > 1 ? 2 - L2 : L2);
5883 switch(M){
5884 case R: H6 = ((G - B) / C + 6)%6; break;
5885 case G: H6 = ((B - R) / C + 2); break;
5886 case B: H6 = ((R - G) / C + 4); break;
5887 }
5888 return [H6 / 6, S, L2 / 2];
5889}
5890
5891function hsl2RGB(hsl){
5892 var H = hsl[0], S = hsl[1], L = hsl[2];
5893 var C = S * 2 * (L < 0.5 ? L : 1 - L), m = L - C/2;
5894 var rgb = [m,m,m], h6 = 6*H;
5895
5896 var X;
5897 if(S !== 0) switch(h6|0) {
5898 case 0: case 6: X = C * h6; rgb[0] += C; rgb[1] += X; break;
5899 case 1: X = C * (2 - h6); rgb[0] += X; rgb[1] += C; break;
5900 case 2: X = C * (h6 - 2); rgb[1] += C; rgb[2] += X; break;
5901 case 3: X = C * (4 - h6); rgb[1] += X; rgb[2] += C; break;
5902 case 4: X = C * (h6 - 4); rgb[2] += C; rgb[0] += X; break;
5903 case 5: X = C * (6 - h6); rgb[2] += X; rgb[0] += C; break;
5904 }
5905 for(var i = 0; i != 3; ++i) rgb[i] = Math.round(rgb[i]*255);
5906 return rgb;
5907}
5908
5909/* 18.8.3 bgColor tint algorithm */
5910function rgb_tint(hex, tint) {
5911 if(tint === 0) return hex;
5912 var hsl = rgb2HSL(hex2RGB(hex));
5913 if (tint < 0) hsl[2] = hsl[2] * (1 + tint);
5914 else hsl[2] = 1 - (1 - hsl[2]) * (1 - tint);
5915 return rgb2Hex(hsl2RGB(hsl));
5916}
5917
5918/* 18.3.1.13 width calculations */
5919/* [MS-OI29500] 2.1.595 Column Width & Formatting */
5920var DEF_MDW = 6, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
5921function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
5922function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
5923function char2width(chr) { return (Math.round((chr * MDW + 5)/MDW*256))/256; }
5924//function px2char_(px) { return (((px - 5)/MDW * 100 + 0.5))/100; }
5925//function char2width_(chr) { return (((chr * MDW + 5)/MDW*256))/256; }
5926function cycle_width(collw) { return char2width(px2char(width2px(collw))); }
5927/* XLSX/XLSB/XLS specify width in units of MDW */
5928function find_mdw_colw(collw) {
5929 var delta = Math.abs(collw - cycle_width(collw)), _MDW = MDW;
5930 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; }
5931 MDW = _MDW;
5932}
5933/* XLML specifies width in terms of pixels */
5934/*function find_mdw_wpx(wpx) {
5935 var delta = Infinity, guess = 0, _MDW = MIN_MDW;
5936 for(MDW=MIN_MDW; MDW<MAX_MDW; ++MDW) {
5937 guess = char2width_(px2char_(wpx))*256;
5938 guess = (guess) % 1;
5939 if(guess > 0.5) guess--;
5940 if(Math.abs(guess) < delta) { delta = Math.abs(guess); _MDW = MDW; }
5941 }
5942 MDW = _MDW;
5943}*/
5944
5945function process_col(coll) {
5946 if(coll.width) {
5947 coll.wpx = width2px(coll.width);
5948 coll.wch = px2char(coll.wpx);
5949 coll.MDW = MDW;
5950 } else if(coll.wpx) {
5951 coll.wch = px2char(coll.wpx);
5952 coll.width = char2width(coll.wch);
5953 coll.MDW = MDW;
5954 } else if(typeof coll.wch == 'number') {
5955 coll.width = char2width(coll.wch);
5956 coll.wpx = width2px(coll.width);
5957 coll.MDW = MDW;
5958 }
5959 if(coll.customWidth) delete coll.customWidth;
5960}
5961
5962var DEF_PPI = 96, PPI = DEF_PPI;
5963function px2pt(px) { return px * 96 / PPI; }
5964function pt2px(pt) { return pt * PPI / 96; }
5965
5966/* [MS-EXSPXML3] 2.4.54 ST_enmPattern */
5967var XLMLPatternTypeMap = {
5968 "None": "none",
5969 "Solid": "solid",
5970 "Gray50": "mediumGray",
5971 "Gray75": "darkGray",
5972 "Gray25": "lightGray",
5973 "HorzStripe": "darkHorizontal",
5974 "VertStripe": "darkVertical",
5975 "ReverseDiagStripe": "darkDown",
5976 "DiagStripe": "darkUp",
5977 "DiagCross": "darkGrid",
5978 "ThickDiagCross": "darkTrellis",
5979 "ThinHorzStripe": "lightHorizontal",
5980 "ThinVertStripe": "lightVertical",
5981 "ThinReverseDiagStripe": "lightDown",
5982 "ThinHorzCross": "lightGrid"
5983};
5984
5985/* 18.8.5 borders CT_Borders */
5986function parse_borders(t, styles, themes, opts) {
5987 styles.Borders = [];
5988 var border = {};
5989 var pass = false;
5990 (t[0].match(tagregex)||[]).forEach(function(x) {
5991 var y = parsexmltag(x);
5992 switch(strip_ns(y[0])) {
5993 case '<borders': case '<borders>': case '</borders>': break;
5994
5995 /* 18.8.4 border CT_Border */
5996 case '<border': case '<border>': case '<border/>':
5997 border = {};
5998 if(y.diagonalUp) border.diagonalUp = parsexmlbool(y.diagonalUp);
5999 if(y.diagonalDown) border.diagonalDown = parsexmlbool(y.diagonalDown);
6000 styles.Borders.push(border);
6001 break;
6002 case '</border>': break;
6003
6004 /* note: not in spec, appears to be CT_BorderPr */
6005 case '<left/>': break;
6006 case '<left': case '<left>': break;
6007 case '</left>': break;
6008
6009 /* note: not in spec, appears to be CT_BorderPr */
6010 case '<right/>': break;
6011 case '<right': case '<right>': break;
6012 case '</right>': break;
6013
6014 /* 18.8.43 top CT_BorderPr */
6015 case '<top/>': break;
6016 case '<top': case '<top>': break;
6017 case '</top>': break;
6018
6019 /* 18.8.6 bottom CT_BorderPr */
6020 case '<bottom/>': break;
6021 case '<bottom': case '<bottom>': break;
6022 case '</bottom>': break;
6023
6024 /* 18.8.13 diagonal CT_BorderPr */
6025 case '<diagonal': case '<diagonal>': case '<diagonal/>': break;
6026 case '</diagonal>': break;
6027
6028 /* 18.8.25 horizontal CT_BorderPr */
6029 case '<horizontal': case '<horizontal>': case '<horizontal/>': break;
6030 case '</horizontal>': break;
6031
6032 /* 18.8.44 vertical CT_BorderPr */
6033 case '<vertical': case '<vertical>': case '<vertical/>': break;
6034 case '</vertical>': break;
6035
6036 /* 18.8.37 start CT_BorderPr */
6037 case '<start': case '<start>': case '<start/>': break;
6038 case '</start>': break;
6039
6040 /* 18.8.16 end CT_BorderPr */
6041 case '<end': case '<end>': case '<end/>': break;
6042 case '</end>': break;
6043
6044 /* 18.8.? color CT_Color */
6045 case '<color': case '<color>':
6046 break;
6047 case '<color/>': case '</color>': break;
6048
6049 /* 18.2.10 extLst CT_ExtensionList ? */
6050 case '<extLst': case '<extLst>': case '</extLst>': break;
6051 case '<ext': pass = true; break;
6052 case '</ext>': pass = false; break;
6053 default: if(opts && opts.WTF) {
6054 if(!pass) throw new Error('unrecognized ' + y[0] + ' in borders');
6055 }
6056 }
6057 });
6058}
6059
6060/* 18.8.21 fills CT_Fills */
6061function parse_fills(t, styles, themes, opts) {
6062 styles.Fills = [];
6063 var fill = {};
6064 var pass = false;
6065 (t[0].match(tagregex)||[]).forEach(function(x) {
6066 var y = parsexmltag(x);
6067 switch(strip_ns(y[0])) {
6068 case '<fills': case '<fills>': case '</fills>': break;
6069
6070 /* 18.8.20 fill CT_Fill */
6071 case '<fill>': case '<fill': case '<fill/>':
6072 fill = {}; styles.Fills.push(fill); break;
6073 case '</fill>': break;
6074
6075 /* 18.8.24 gradientFill CT_GradientFill */
6076 case '<gradientFill>': break;
6077 case '<gradientFill':
6078 case '</gradientFill>': styles.Fills.push(fill); fill = {}; break;
6079
6080 /* 18.8.32 patternFill CT_PatternFill */
6081 case '<patternFill': case '<patternFill>':
6082 if(y.patternType) fill.patternType = y.patternType;
6083 break;
6084 case '<patternFill/>': case '</patternFill>': break;
6085
6086 /* 18.8.3 bgColor CT_Color */
6087 case '<bgColor':
6088 if(!fill.bgColor) fill.bgColor = {};
6089 if(y.indexed) fill.bgColor.indexed = parseInt(y.indexed, 10);
6090 if(y.theme) fill.bgColor.theme = parseInt(y.theme, 10);
6091 if(y.tint) fill.bgColor.tint = parseFloat(y.tint);
6092 /* Excel uses ARGB strings */
6093 if(y.rgb) fill.bgColor.rgb = y.rgb.slice(-6);
6094 break;
6095 case '<bgColor/>': case '</bgColor>': break;
6096
6097 /* 18.8.19 fgColor CT_Color */
6098 case '<fgColor':
6099 if(!fill.fgColor) fill.fgColor = {};
6100 if(y.theme) fill.fgColor.theme = parseInt(y.theme, 10);
6101 if(y.tint) fill.fgColor.tint = parseFloat(y.tint);
6102 /* Excel uses ARGB strings */
6103 if(y.rgb != null) fill.fgColor.rgb = y.rgb.slice(-6);
6104 break;
6105 case '<fgColor/>': case '</fgColor>': break;
6106
6107 /* 18.8.38 stop CT_GradientStop */
6108 case '<stop': case '<stop/>': break;
6109 case '</stop>': break;
6110
6111 /* 18.8.? color CT_Color */
6112 case '<color': case '<color/>': break;
6113 case '</color>': break;
6114
6115 /* 18.2.10 extLst CT_ExtensionList ? */
6116 case '<extLst': case '<extLst>': case '</extLst>': break;
6117 case '<ext': pass = true; break;
6118 case '</ext>': pass = false; break;
6119 default: if(opts && opts.WTF) {
6120 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fills');
6121 }
6122 }
6123 });
6124}
6125
6126/* 18.8.23 fonts CT_Fonts */
6127function parse_fonts(t, styles, themes, opts) {
6128 styles.Fonts = [];
6129 var font = {};
6130 var pass = false;
6131 (t[0].match(tagregex)||[]).forEach(function(x) {
6132 var y = parsexmltag(x);
6133 switch(strip_ns(y[0])) {
6134 case '<fonts': case '<fonts>': case '</fonts>': break;
6135
6136 /* 18.8.22 font CT_Font */
6137 case '<font': case '<font>': break;
6138 case '</font>': case '<font/>':
6139 styles.Fonts.push(font);
6140 font = {};
6141 break;
6142
6143 /* 18.8.29 name CT_FontName */
6144 case '<name': if(y.val) font.name = utf8read(y.val); break;
6145 case '<name/>': case '</name>': break;
6146
6147 /* 18.8.2 b CT_BooleanProperty */
6148 case '<b': font.bold = y.val ? parsexmlbool(y.val) : 1; break;
6149 case '<b/>': font.bold = 1; break;
6150
6151 /* 18.8.26 i CT_BooleanProperty */
6152 case '<i': font.italic = y.val ? parsexmlbool(y.val) : 1; break;
6153 case '<i/>': font.italic = 1; break;
6154
6155 /* 18.4.13 u CT_UnderlineProperty */
6156 case '<u':
6157 switch(y.val) {
6158 case "none": font.underline = 0x00; break;
6159 case "single": font.underline = 0x01; break;
6160 case "double": font.underline = 0x02; break;
6161 case "singleAccounting": font.underline = 0x21; break;
6162 case "doubleAccounting": font.underline = 0x22; break;
6163 } break;
6164 case '<u/>': font.underline = 1; break;
6165
6166 /* 18.4.10 strike CT_BooleanProperty */
6167 case '<strike': font.strike = y.val ? parsexmlbool(y.val) : 1; break;
6168 case '<strike/>': font.strike = 1; break;
6169
6170 /* 18.4.2 outline CT_BooleanProperty */
6171 case '<outline': font.outline = y.val ? parsexmlbool(y.val) : 1; break;
6172 case '<outline/>': font.outline = 1; break;
6173
6174 /* 18.8.36 shadow CT_BooleanProperty */
6175 case '<shadow': font.shadow = y.val ? parsexmlbool(y.val) : 1; break;
6176 case '<shadow/>': font.shadow = 1; break;
6177
6178 /* 18.8.12 condense CT_BooleanProperty */
6179 case '<condense': font.condense = y.val ? parsexmlbool(y.val) : 1; break;
6180 case '<condense/>': font.condense = 1; break;
6181
6182 /* 18.8.17 extend CT_BooleanProperty */
6183 case '<extend': font.extend = y.val ? parsexmlbool(y.val) : 1; break;
6184 case '<extend/>': font.extend = 1; break;
6185
6186 /* 18.4.11 sz CT_FontSize */
6187 case '<sz': if(y.val) font.sz = +y.val; break;
6188 case '<sz/>': case '</sz>': break;
6189
6190 /* 18.4.14 vertAlign CT_VerticalAlignFontProperty */
6191 case '<vertAlign': if(y.val) font.vertAlign = y.val; break;
6192 case '<vertAlign/>': case '</vertAlign>': break;
6193
6194 /* 18.8.18 family CT_FontFamily */
6195 case '<family': if(y.val) font.family = parseInt(y.val,10); break;
6196 case '<family/>': case '</family>': break;
6197
6198 /* 18.8.35 scheme CT_FontScheme */
6199 case '<scheme': if(y.val) font.scheme = y.val; break;
6200 case '<scheme/>': case '</scheme>': break;
6201
6202 /* 18.4.1 charset CT_IntProperty */
6203 case '<charset':
6204 if(y.val == '1') break;
6205 y.codepage = CS2CP[parseInt(y.val, 10)];
6206 break;
6207
6208 /* 18.?.? color CT_Color */
6209 case '<color':
6210 if(!font.color) font.color = {};
6211 if(y.auto) font.color.auto = parsexmlbool(y.auto);
6212
6213 if(y.rgb) font.color.rgb = y.rgb.slice(-6);
6214 else if(y.indexed) {
6215 font.color.index = parseInt(y.indexed, 10);
6216 var icv = XLSIcv[font.color.index];
6217 if(font.color.index == 81) icv = XLSIcv[1];
6218 if(!icv) throw new Error(x);
6219 font.color.rgb = icv[0].toString(16) + icv[1].toString(16) + icv[2].toString(16);
6220 } else if(y.theme) {
6221 font.color.theme = parseInt(y.theme, 10);
6222 if(y.tint) font.color.tint = parseFloat(y.tint);
6223 if(y.theme && themes.themeElements && themes.themeElements.clrScheme) {
6224 font.color.rgb = rgb_tint(themes.themeElements.clrScheme[font.color.theme].rgb, font.color.tint || 0);
6225 }
6226 }
6227
6228 break;
6229 case '<color/>': case '</color>': break;
6230
6231 /* note: sometimes mc:AlternateContent appears bare */
6232 case '<AlternateContent': pass = true; break;
6233 case '</AlternateContent>': pass = false; break;
6234
6235 /* 18.2.10 extLst CT_ExtensionList ? */
6236 case '<extLst': case '<extLst>': case '</extLst>': break;
6237 case '<ext': pass = true; break;
6238 case '</ext>': pass = false; break;
6239 default: if(opts && opts.WTF) {
6240 if(!pass) throw new Error('unrecognized ' + y[0] + ' in fonts');
6241 }
6242 }
6243 });
6244}
6245
6246/* 18.8.31 numFmts CT_NumFmts */
6247function parse_numFmts(t, styles, opts) {
6248 styles.NumberFmt = [];
6249 var k/*Array<number>*/ = (keys(SSF._table));
6250 for(var i=0; i < k.length; ++i) styles.NumberFmt[k[i]] = SSF._table[k[i]];
6251 var m = t[0].match(tagregex);
6252 if(!m) return;
6253 for(i=0; i < m.length; ++i) {
6254 var y = parsexmltag(m[i]);
6255 switch(strip_ns(y[0])) {
6256 case '<numFmts': case '</numFmts>': case '<numFmts/>': case '<numFmts>': break;
6257 case '<numFmt': {
6258 var f=unescapexml(utf8read(y.formatCode)), j=parseInt(y.numFmtId,10);
6259 styles.NumberFmt[j] = f;
6260 if(j>0) {
6261 if(j > 0x188) {
6262 for(j = 0x188; j > 0x3c; --j) if(styles.NumberFmt[j] == null) break;
6263 styles.NumberFmt[j] = f;
6264 }
6265 SSF.load(f,j);
6266 }
6267 } break;
6268 case '</numFmt>': break;
6269 default: if(opts.WTF) throw new Error('unrecognized ' + y[0] + ' in numFmts');
6270 }
6271 }
6272}
6273
6274function write_numFmts(NF) {
6275 var o = ["<numFmts>"];
6276 [[5,8],[23,26],[41,44],[/*63*/50,/*66],[164,*/392]].forEach(function(r) {
6277 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])}));
6278 });
6279 if(o.length === 1) return "";
6280 o[o.length] = ("</numFmts>");
6281 o[0] = writextag('numFmts', null, { count:o.length-2 }).replace("/>", ">");
6282 return o.join("");
6283}
6284
6285/* 18.8.10 cellXfs CT_CellXfs */
6286var cellXF_uint = [ "numFmtId", "fillId", "fontId", "borderId", "xfId" ];
6287var cellXF_bool = [ "applyAlignment", "applyBorder", "applyFill", "applyFont", "applyNumberFormat", "applyProtection", "pivotButton", "quotePrefix" ];
6288function parse_cellXfs(t, styles, opts) {
6289 styles.CellXf = [];
6290 var xf;
6291 var pass = false;
6292 (t[0].match(tagregex)||[]).forEach(function(x) {
6293 var y = parsexmltag(x), i = 0;
6294 switch(strip_ns(y[0])) {
6295 case '<cellXfs': case '<cellXfs>': case '<cellXfs/>': case '</cellXfs>': break;
6296
6297 /* 18.8.45 xf CT_Xf */
6298 case '<xf': case '<xf/>':
6299 xf = y;
6300 delete xf[0];
6301 for(i = 0; i < cellXF_uint.length; ++i) if(xf[cellXF_uint[i]])
6302 xf[cellXF_uint[i]] = parseInt(xf[cellXF_uint[i]], 10);
6303 for(i = 0; i < cellXF_bool.length; ++i) if(xf[cellXF_bool[i]])
6304 xf[cellXF_bool[i]] = parsexmlbool(xf[cellXF_bool[i]]);
6305 if(xf.numFmtId > 0x188) {
6306 for(i = 0x188; i > 0x3c; --i) if(styles.NumberFmt[xf.numFmtId] == styles.NumberFmt[i]) { xf.numFmtId = i; break; }
6307 }
6308 styles.CellXf.push(xf); break;
6309 case '</xf>': break;
6310
6311 /* 18.8.1 alignment CT_CellAlignment */
6312 case '<alignment': case '<alignment/>':
6313 var alignment = {};
6314 if(y.vertical) alignment.vertical = y.vertical;
6315 if(y.horizontal) alignment.horizontal = y.horizontal;
6316 if(y.textRotation != null) alignment.textRotation = y.textRotation;
6317 if(y.indent) alignment.indent = y.indent;
6318 if(y.wrapText) alignment.wrapText = parsexmlbool(y.wrapText);
6319 xf.alignment = alignment;
6320 break;
6321 case '</alignment>': break;
6322
6323 /* 18.8.33 protection CT_CellProtection */
6324 case '<protection':
6325 break;
6326 case '</protection>': case '<protection/>': break;
6327
6328 /* note: sometimes mc:AlternateContent appears bare */
6329 case '<AlternateContent': pass = true; break;
6330 case '</AlternateContent>': pass = false; break;
6331
6332 /* 18.2.10 extLst CT_ExtensionList ? */
6333 case '<extLst': case '<extLst>': case '</extLst>': break;
6334 case '<ext': pass = true; break;
6335 case '</ext>': pass = false; break;
6336 default: if(opts && opts.WTF) {
6337 if(!pass) throw new Error('unrecognized ' + y[0] + ' in cellXfs');
6338 }
6339 }
6340 });
6341}
6342
6343function write_cellXfs(cellXfs) {
6344 var o = [];
6345 o[o.length] = (writextag('cellXfs',null));
6346 cellXfs.forEach(function(c) {
6347 o[o.length] = (writextag('xf', null, c));
6348 });
6349 o[o.length] = ("</cellXfs>");
6350 if(o.length === 2) return "";
6351 o[0] = writextag('cellXfs',null, {count:o.length-2}).replace("/>",">");
6352 return o.join("");
6353}
6354
6355/* 18.8 Styles CT_Stylesheet*/
6356var parse_sty_xml= (function make_pstyx() {
6357var numFmtRegex = /<(?:\w+:)?numFmts([^>]*)>[\S\s]*?<\/(?:\w+:)?numFmts>/;
6358var cellXfRegex = /<(?:\w+:)?cellXfs([^>]*)>[\S\s]*?<\/(?:\w+:)?cellXfs>/;
6359var fillsRegex = /<(?:\w+:)?fills([^>]*)>[\S\s]*?<\/(?:\w+:)?fills>/;
6360var fontsRegex = /<(?:\w+:)?fonts([^>]*)>[\S\s]*?<\/(?:\w+:)?fonts>/;
6361var bordersRegex = /<(?:\w+:)?borders([^>]*)>[\S\s]*?<\/(?:\w+:)?borders>/;
6362
6363return function parse_sty_xml(data, themes, opts) {
6364 var styles = {};
6365 if(!data) return styles;
6366 data = data.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
6367 /* 18.8.39 styleSheet CT_Stylesheet */
6368 var t;
6369
6370 /* 18.8.31 numFmts CT_NumFmts ? */
6371 if((t=data.match(numFmtRegex))) parse_numFmts(t, styles, opts);
6372
6373 /* 18.8.23 fonts CT_Fonts ? */
6374 if((t=data.match(fontsRegex))) parse_fonts(t, styles, themes, opts);
6375
6376 /* 18.8.21 fills CT_Fills ? */
6377 if((t=data.match(fillsRegex))) parse_fills(t, styles, themes, opts);
6378
6379 /* 18.8.5 borders CT_Borders ? */
6380 if((t=data.match(bordersRegex))) parse_borders(t, styles, themes, opts);
6381
6382 /* 18.8.9 cellStyleXfs CT_CellStyleXfs ? */
6383 /* 18.8.8 cellStyles CT_CellStyles ? */
6384
6385 /* 18.8.10 cellXfs CT_CellXfs ? */
6386 if((t=data.match(cellXfRegex))) parse_cellXfs(t, styles, opts);
6387
6388 /* 18.8.15 dxfs CT_Dxfs ? */
6389 /* 18.8.42 tableStyles CT_TableStyles ? */
6390 /* 18.8.11 colors CT_Colors ? */
6391 /* 18.2.10 extLst CT_ExtensionList ? */
6392
6393 return styles;
6394};
6395})();
6396
6397var STYLES_XML_ROOT = writextag('styleSheet', null, {
6398 'xmlns': XMLNS.main[0],
6399 'xmlns:vt': XMLNS.vt
6400});
6401
6402RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles";
6403
6404function write_sty_xml(wb, opts) {
6405 var o = [XML_HEADER, STYLES_XML_ROOT], w;
6406 if(wb.SSF && (w = write_numFmts(wb.SSF)) != null) o[o.length] = w;
6407 o[o.length] = ('<fonts count="1"><font><sz val="12"/><color theme="1"/><name val="Calibri"/><family val="2"/><scheme val="minor"/></font></fonts>');
6408 o[o.length] = ('<fills count="2"><fill><patternFill patternType="none"/></fill><fill><patternFill patternType="gray125"/></fill></fills>');
6409 o[o.length] = ('<borders count="1"><border><left/><right/><top/><bottom/><diagonal/></border></borders>');
6410 o[o.length] = ('<cellStyleXfs count="1"><xf numFmtId="0" fontId="0" fillId="0" borderId="0"/></cellStyleXfs>');
6411 if((w = write_cellXfs(opts.cellXfs))) o[o.length] = (w);
6412 o[o.length] = ('<cellStyles count="1"><cellStyle name="Normal" xfId="0" builtinId="0"/></cellStyles>');
6413 o[o.length] = ('<dxfs count="0"/>');
6414 o[o.length] = ('<tableStyles count="0" defaultTableStyle="TableStyleMedium9" defaultPivotStyle="PivotStyleMedium4"/>');
6415
6416 if(o.length>2){ o[o.length] = ('</styleSheet>'); o[1]=o[1].replace("/>",">"); }
6417 return o.join("");
6418}
6419RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme";
6420
6421/* Even though theme layout is dk1 lt1 dk2 lt2, true order is lt1 dk1 lt2 dk2 */
6422var XLSXThemeClrScheme = [
6423 '</a:lt1>', '</a:dk1>', '</a:lt2>', '</a:dk2>',
6424 '</a:accent1>', '</a:accent2>', '</a:accent3>',
6425 '</a:accent4>', '</a:accent5>', '</a:accent6>',
6426 '</a:hlink>', '</a:folHlink>'
6427];
6428/* 20.1.6.2 clrScheme CT_ColorScheme */
6429function parse_clrScheme(t, themes, opts) {
6430 themes.themeElements.clrScheme = [];
6431 var color = {};
6432 (t[0].match(tagregex)||[]).forEach(function(x) {
6433 var y = parsexmltag(x);
6434 switch(y[0]) {
6435 /* 20.1.6.2 clrScheme (Color Scheme) CT_ColorScheme */
6436 case '<a:clrScheme': case '</a:clrScheme>': break;
6437
6438 /* 20.1.2.3.32 srgbClr CT_SRgbColor */
6439 case '<a:srgbClr':
6440 color.rgb = y.val; break;
6441
6442 /* 20.1.2.3.33 sysClr CT_SystemColor */
6443 case '<a:sysClr':
6444 color.rgb = y.lastClr; break;
6445
6446 /* 20.1.4.1.1 accent1 (Accent 1) */
6447 /* 20.1.4.1.2 accent2 (Accent 2) */
6448 /* 20.1.4.1.3 accent3 (Accent 3) */
6449 /* 20.1.4.1.4 accent4 (Accent 4) */
6450 /* 20.1.4.1.5 accent5 (Accent 5) */
6451 /* 20.1.4.1.6 accent6 (Accent 6) */
6452 /* 20.1.4.1.9 dk1 (Dark 1) */
6453 /* 20.1.4.1.10 dk2 (Dark 2) */
6454 /* 20.1.4.1.15 folHlink (Followed Hyperlink) */
6455 /* 20.1.4.1.19 hlink (Hyperlink) */
6456 /* 20.1.4.1.22 lt1 (Light 1) */
6457 /* 20.1.4.1.23 lt2 (Light 2) */
6458 case '<a:dk1>': case '</a:dk1>':
6459 case '<a:lt1>': case '</a:lt1>':
6460 case '<a:dk2>': case '</a:dk2>':
6461 case '<a:lt2>': case '</a:lt2>':
6462 case '<a:accent1>': case '</a:accent1>':
6463 case '<a:accent2>': case '</a:accent2>':
6464 case '<a:accent3>': case '</a:accent3>':
6465 case '<a:accent4>': case '</a:accent4>':
6466 case '<a:accent5>': case '</a:accent5>':
6467 case '<a:accent6>': case '</a:accent6>':
6468 case '<a:hlink>': case '</a:hlink>':
6469 case '<a:folHlink>': case '</a:folHlink>':
6470 if (y[0].charAt(1) === '/') {
6471 themes.themeElements.clrScheme[XLSXThemeClrScheme.indexOf(y[0])] = color;
6472 color = {};
6473 } else {
6474 color.name = y[0].slice(3, y[0].length - 1);
6475 }
6476 break;
6477
6478 default: if(opts && opts.WTF) throw new Error('Unrecognized ' + y[0] + ' in clrScheme');
6479 }
6480 });
6481}
6482
6483/* 20.1.4.1.18 fontScheme CT_FontScheme */
6484function parse_fontScheme() { }
6485
6486/* 20.1.4.1.15 fmtScheme CT_StyleMatrix */
6487function parse_fmtScheme() { }
6488
6489var clrsregex = /<a:clrScheme([^>]*)>[\s\S]*<\/a:clrScheme>/;
6490var fntsregex = /<a:fontScheme([^>]*)>[\s\S]*<\/a:fontScheme>/;
6491var fmtsregex = /<a:fmtScheme([^>]*)>[\s\S]*<\/a:fmtScheme>/;
6492
6493/* 20.1.6.10 themeElements CT_BaseStyles */
6494function parse_themeElements(data, themes, opts) {
6495 themes.themeElements = {};
6496
6497 var t;
6498
6499 [
6500 /* clrScheme CT_ColorScheme */
6501 ['clrScheme', clrsregex, parse_clrScheme],
6502 /* fontScheme CT_FontScheme */
6503 ['fontScheme', fntsregex, parse_fontScheme],
6504 /* fmtScheme CT_StyleMatrix */
6505 ['fmtScheme', fmtsregex, parse_fmtScheme]
6506 ].forEach(function(m) {
6507 if(!(t=data.match(m[1]))) throw new Error(m[0] + ' not found in themeElements');
6508 m[2](t, themes, opts);
6509 });
6510}
6511
6512var themeltregex = /<a:themeElements([^>]*)>[\s\S]*<\/a:themeElements>/;
6513
6514/* 14.2.7 Theme Part */
6515function parse_theme_xml(data, opts) {
6516 /* 20.1.6.9 theme CT_OfficeStyleSheet */
6517 if(!data || data.length === 0) return parse_theme_xml(write_theme());
6518
6519 var t;
6520 var themes = {};
6521
6522 /* themeElements CT_BaseStyles */
6523 if(!(t=data.match(themeltregex))) throw new Error('themeElements not found in theme');
6524 parse_themeElements(t[0], themes, opts);
6525 themes.raw = data;
6526 return themes;
6527}
6528
6529function write_theme(Themes, opts) {
6530 if(opts && opts.themeXLSX) return opts.themeXLSX;
6531 if(Themes && typeof Themes.raw == "string") return Themes.raw;
6532 var o = [XML_HEADER];
6533 o[o.length] = '<a:theme xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main" name="Office Theme">';
6534 o[o.length] = '<a:themeElements>';
6535
6536 o[o.length] = '<a:clrScheme name="Office">';
6537 o[o.length] = '<a:dk1><a:sysClr val="windowText" lastClr="000000"/></a:dk1>';
6538 o[o.length] = '<a:lt1><a:sysClr val="window" lastClr="FFFFFF"/></a:lt1>';
6539 o[o.length] = '<a:dk2><a:srgbClr val="1F497D"/></a:dk2>';
6540 o[o.length] = '<a:lt2><a:srgbClr val="EEECE1"/></a:lt2>';
6541 o[o.length] = '<a:accent1><a:srgbClr val="4F81BD"/></a:accent1>';
6542 o[o.length] = '<a:accent2><a:srgbClr val="C0504D"/></a:accent2>';
6543 o[o.length] = '<a:accent3><a:srgbClr val="9BBB59"/></a:accent3>';
6544 o[o.length] = '<a:accent4><a:srgbClr val="8064A2"/></a:accent4>';
6545 o[o.length] = '<a:accent5><a:srgbClr val="4BACC6"/></a:accent5>';
6546 o[o.length] = '<a:accent6><a:srgbClr val="F79646"/></a:accent6>';
6547 o[o.length] = '<a:hlink><a:srgbClr val="0000FF"/></a:hlink>';
6548 o[o.length] = '<a:folHlink><a:srgbClr val="800080"/></a:folHlink>';
6549 o[o.length] = '</a:clrScheme>';
6550
6551 o[o.length] = '<a:fontScheme name="Office">';
6552 o[o.length] = '<a:majorFont>';
6553 o[o.length] = '<a:latin typeface="Cambria"/>';
6554 o[o.length] = '<a:ea typeface=""/>';
6555 o[o.length] = '<a:cs typeface=""/>';
6556 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
6557 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
6558 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
6559 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
6560 o[o.length] = '<a:font script="Arab" typeface="Times New Roman"/>';
6561 o[o.length] = '<a:font script="Hebr" typeface="Times New Roman"/>';
6562 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
6563 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
6564 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
6565 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
6566 o[o.length] = '<a:font script="Khmr" typeface="MoolBoran"/>';
6567 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
6568 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
6569 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
6570 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
6571 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
6572 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
6573 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
6574 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
6575 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
6576 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
6577 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
6578 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
6579 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
6580 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
6581 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
6582 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
6583 o[o.length] = '<a:font script="Viet" typeface="Times New Roman"/>';
6584 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
6585 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
6586 o[o.length] = '</a:majorFont>';
6587 o[o.length] = '<a:minorFont>';
6588 o[o.length] = '<a:latin typeface="Calibri"/>';
6589 o[o.length] = '<a:ea typeface=""/>';
6590 o[o.length] = '<a:cs typeface=""/>';
6591 o[o.length] = '<a:font script="Jpan" typeface="MS Pゴシック"/>';
6592 o[o.length] = '<a:font script="Hang" typeface="맑은 고딕"/>';
6593 o[o.length] = '<a:font script="Hans" typeface="宋体"/>';
6594 o[o.length] = '<a:font script="Hant" typeface="新細明體"/>';
6595 o[o.length] = '<a:font script="Arab" typeface="Arial"/>';
6596 o[o.length] = '<a:font script="Hebr" typeface="Arial"/>';
6597 o[o.length] = '<a:font script="Thai" typeface="Tahoma"/>';
6598 o[o.length] = '<a:font script="Ethi" typeface="Nyala"/>';
6599 o[o.length] = '<a:font script="Beng" typeface="Vrinda"/>';
6600 o[o.length] = '<a:font script="Gujr" typeface="Shruti"/>';
6601 o[o.length] = '<a:font script="Khmr" typeface="DaunPenh"/>';
6602 o[o.length] = '<a:font script="Knda" typeface="Tunga"/>';
6603 o[o.length] = '<a:font script="Guru" typeface="Raavi"/>';
6604 o[o.length] = '<a:font script="Cans" typeface="Euphemia"/>';
6605 o[o.length] = '<a:font script="Cher" typeface="Plantagenet Cherokee"/>';
6606 o[o.length] = '<a:font script="Yiii" typeface="Microsoft Yi Baiti"/>';
6607 o[o.length] = '<a:font script="Tibt" typeface="Microsoft Himalaya"/>';
6608 o[o.length] = '<a:font script="Thaa" typeface="MV Boli"/>';
6609 o[o.length] = '<a:font script="Deva" typeface="Mangal"/>';
6610 o[o.length] = '<a:font script="Telu" typeface="Gautami"/>';
6611 o[o.length] = '<a:font script="Taml" typeface="Latha"/>';
6612 o[o.length] = '<a:font script="Syrc" typeface="Estrangelo Edessa"/>';
6613 o[o.length] = '<a:font script="Orya" typeface="Kalinga"/>';
6614 o[o.length] = '<a:font script="Mlym" typeface="Kartika"/>';
6615 o[o.length] = '<a:font script="Laoo" typeface="DokChampa"/>';
6616 o[o.length] = '<a:font script="Sinh" typeface="Iskoola Pota"/>';
6617 o[o.length] = '<a:font script="Mong" typeface="Mongolian Baiti"/>';
6618 o[o.length] = '<a:font script="Viet" typeface="Arial"/>';
6619 o[o.length] = '<a:font script="Uigh" typeface="Microsoft Uighur"/>';
6620 o[o.length] = '<a:font script="Geor" typeface="Sylfaen"/>';
6621 o[o.length] = '</a:minorFont>';
6622 o[o.length] = '</a:fontScheme>';
6623
6624 o[o.length] = '<a:fmtScheme name="Office">';
6625 o[o.length] = '<a:fillStyleLst>';
6626 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
6627 o[o.length] = '<a:gradFill rotWithShape="1">';
6628 o[o.length] = '<a:gsLst>';
6629 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="50000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
6630 o[o.length] = '<a:gs pos="35000"><a:schemeClr val="phClr"><a:tint val="37000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
6631 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:tint val="15000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
6632 o[o.length] = '</a:gsLst>';
6633 o[o.length] = '<a:lin ang="16200000" scaled="1"/>';
6634 o[o.length] = '</a:gradFill>';
6635 o[o.length] = '<a:gradFill rotWithShape="1">';
6636 o[o.length] = '<a:gsLst>';
6637 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>';
6638 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>';
6639 o[o.length] = '</a:gsLst>';
6640 o[o.length] = '<a:lin ang="16200000" scaled="0"/>';
6641 o[o.length] = '</a:gradFill>';
6642 o[o.length] = '</a:fillStyleLst>';
6643 o[o.length] = '<a:lnStyleLst>';
6644 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>';
6645 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>';
6646 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>';
6647 o[o.length] = '</a:lnStyleLst>';
6648 o[o.length] = '<a:effectStyleLst>';
6649 o[o.length] = '<a:effectStyle>';
6650 o[o.length] = '<a:effectLst>';
6651 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>';
6652 o[o.length] = '</a:effectLst>';
6653 o[o.length] = '</a:effectStyle>';
6654 o[o.length] = '<a:effectStyle>';
6655 o[o.length] = '<a:effectLst>';
6656 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>';
6657 o[o.length] = '</a:effectLst>';
6658 o[o.length] = '</a:effectStyle>';
6659 o[o.length] = '<a:effectStyle>';
6660 o[o.length] = '<a:effectLst>';
6661 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>';
6662 o[o.length] = '</a:effectLst>';
6663 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>';
6664 o[o.length] = '<a:sp3d><a:bevelT w="63500" h="25400"/></a:sp3d>';
6665 o[o.length] = '</a:effectStyle>';
6666 o[o.length] = '</a:effectStyleLst>';
6667 o[o.length] = '<a:bgFillStyleLst>';
6668 o[o.length] = '<a:solidFill><a:schemeClr val="phClr"/></a:solidFill>';
6669 o[o.length] = '<a:gradFill rotWithShape="1">';
6670 o[o.length] = '<a:gsLst>';
6671 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="40000"/><a:satMod val="350000"/></a:schemeClr></a:gs>';
6672 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>';
6673 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="20000"/><a:satMod val="255000"/></a:schemeClr></a:gs>';
6674 o[o.length] = '</a:gsLst>';
6675 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="-80000" r="50000" b="180000"/></a:path>';
6676 o[o.length] = '</a:gradFill>';
6677 o[o.length] = '<a:gradFill rotWithShape="1">';
6678 o[o.length] = '<a:gsLst>';
6679 o[o.length] = '<a:gs pos="0"><a:schemeClr val="phClr"><a:tint val="80000"/><a:satMod val="300000"/></a:schemeClr></a:gs>';
6680 o[o.length] = '<a:gs pos="100000"><a:schemeClr val="phClr"><a:shade val="30000"/><a:satMod val="200000"/></a:schemeClr></a:gs>';
6681 o[o.length] = '</a:gsLst>';
6682 o[o.length] = '<a:path path="circle"><a:fillToRect l="50000" t="50000" r="50000" b="50000"/></a:path>';
6683 o[o.length] = '</a:gradFill>';
6684 o[o.length] = '</a:bgFillStyleLst>';
6685 o[o.length] = '</a:fmtScheme>';
6686 o[o.length] = '</a:themeElements>';
6687
6688 o[o.length] = '<a:objectDefaults>';
6689 o[o.length] = '<a:spDef>';
6690 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>';
6691 o[o.length] = '</a:spDef>';
6692 o[o.length] = '<a:lnDef>';
6693 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>';
6694 o[o.length] = '</a:lnDef>';
6695 o[o.length] = '</a:objectDefaults>';
6696 o[o.length] = '<a:extraClrSchemeLst/>';
6697 o[o.length] = '</a:theme>';
6698 return o.join("");
6699}
6700/* 18.14 Supplementary Workbook Data */
6701function parse_xlink_xml() {
6702 //var opts = _opts || {};
6703 //if(opts.WTF) throw "XLSX External Link";
6704}
6705
6706/* [MS-XLSB] 2.1.7.25 External Link */
6707function parse_xlink_bin(data, rel, name, _opts) {
6708 if(!data) return data;
6709 var opts = _opts || {};
6710
6711 var pass = false, end = false;
6712
6713 recordhopper(data, function xlink_parse(val, R_n, RT) {
6714 if(end) return;
6715 switch(RT) {
6716 case 0x0167: /* 'BrtSupTabs' */
6717 case 0x016B: /* 'BrtExternTableStart' */
6718 case 0x016C: /* 'BrtExternTableEnd' */
6719 case 0x016E: /* 'BrtExternRowHdr' */
6720 case 0x016F: /* 'BrtExternCellBlank' */
6721 case 0x0170: /* 'BrtExternCellReal' */
6722 case 0x0171: /* 'BrtExternCellBool' */
6723 case 0x0172: /* 'BrtExternCellError' */
6724 case 0x0173: /* 'BrtExternCellString' */
6725 case 0x01D8: /* 'BrtExternValueMeta' */
6726 case 0x0241: /* 'BrtSupNameStart' */
6727 case 0x0242: /* 'BrtSupNameValueStart' */
6728 case 0x0243: /* 'BrtSupNameValueEnd' */
6729 case 0x0244: /* 'BrtSupNameNum' */
6730 case 0x0245: /* 'BrtSupNameErr' */
6731 case 0x0246: /* 'BrtSupNameSt' */
6732 case 0x0247: /* 'BrtSupNameNil' */
6733 case 0x0248: /* 'BrtSupNameBool' */
6734 case 0x0249: /* 'BrtSupNameFmla' */
6735 case 0x024A: /* 'BrtSupNameBits' */
6736 case 0x024B: /* 'BrtSupNameEnd' */
6737 break;
6738
6739 case 0x0023: /* 'BrtFRTBegin' */
6740 pass = true; break;
6741 case 0x0024: /* 'BrtFRTEnd' */
6742 pass = false; break;
6743
6744 default:
6745 if((R_n||"").indexOf("Begin") > 0){/* empty */}
6746 else if((R_n||"").indexOf("End") > 0){/* empty */}
6747 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT.toString(16) + " " + R_n);
6748 }
6749 }, opts);
6750}
6751/* 20.5 DrawingML - SpreadsheetML Drawing */
6752RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image";
6753RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing";
6754
6755/* 20.5.2.35 wsDr CT_Drawing */
6756function parse_drawing(data, rels) {
6757 if(!data) return "??";
6758 /*
6759 Chartsheet Drawing:
6760 - 20.5.2.35 wsDr CT_Drawing
6761 - 20.5.2.1 absoluteAnchor CT_AbsoluteAnchor
6762 - 20.5.2.16 graphicFrame CT_GraphicalObjectFrame
6763 - 20.1.2.2.16 graphic CT_GraphicalObject
6764 - 20.1.2.2.17 graphicData CT_GraphicalObjectData
6765 - chart reference
6766 the actual type is based on the URI of the graphicData
6767 TODO: handle embedded charts and other types of graphics
6768 */
6769 var id = (data.match(/<c:chart [^>]*r:id="([^"]*)"/)||["",""])[1];
6770
6771 return rels['!id'][id].Target;
6772}
6773
6774/* L.5.5.2 SpreadsheetML Comments + VML Schema */
6775var _shapeid = 1024;
6776function write_comments_vml(rId, comments) {
6777 var csize = [21600, 21600];
6778 /* L.5.2.1.2 Path Attribute */
6779 var bbox = ["m0,0l0",csize[1],csize[0],csize[1],csize[0],"0xe"].join(",");
6780 var o = [
6781 writextag("xml", null, { 'xmlns:v': XLMLNS.v, 'xmlns:o': XLMLNS.o, 'xmlns:x': XLMLNS.x, 'xmlns:mv': XLMLNS.mv }).replace(/\/>/,">"),
6782 writextag("o:shapelayout", writextag("o:idmap", null, {'v:ext':"edit", 'data':rId}), {'v:ext':"edit"}),
6783 writextag("v:shapetype", [
6784 writextag("v:stroke", null, {joinstyle:"miter"}),
6785 writextag("v:path", null, {gradientshapeok:"t", 'o:connecttype':"rect"})
6786 ].join(""), {id:"_x0000_t202", 'o:spt':202, coordsize:csize.join(","),path:bbox})
6787 ];
6788 while(_shapeid < rId * 1000) _shapeid += 1000;
6789
6790 comments.forEach(function(x) {
6791 var c = decode_cell(x[0]);
6792 var fillopts = {'color2':"#BEFF82", 'type':"gradient"};
6793 if(fillopts.type == "gradient") fillopts.angle = "-180";
6794 var fillparm = fillopts.type == "gradient" ? writextag("o:fill", null, {type:"gradientUnscaled", 'v:ext':"view"}) : null;
6795 var fillxml = writextag('v:fill', fillparm, fillopts);
6796
6797 var shadata = ({on:"t", 'obscured':"t"});
6798 ++_shapeid;
6799
6800 o = o.concat([
6801 '<v:shape' + wxt_helper({
6802 id:'_x0000_s' + _shapeid,
6803 type:"#_x0000_t202",
6804 style:"position:absolute; margin-left:80pt;margin-top:5pt;width:104pt;height:64pt;z-index:10" + (x[1].hidden ? ";visibility:hidden" : "") ,
6805 fillcolor:"#ECFAD4",
6806 strokecolor:"#edeaa1"
6807 }) + '>',
6808 fillxml,
6809 writextag("v:shadow", null, shadata),
6810 writextag("v:path", null, {'o:connecttype':"none"}),
6811 '<v:textbox><div style="text-align:left"></div></v:textbox>',
6812 '<x:ClientData ObjectType="Note">',
6813 '<x:MoveWithCells/>',
6814 '<x:SizeWithCells/>',
6815 /* Part 4 19.4.2.3 Anchor (Anchor) */
6816 writetag('x:Anchor', [c.c+1, 0, c.r+1, 0, c.c+3, 20, c.r+5, 20].join(",")),
6817 writetag('x:AutoFill', "False"),
6818 writetag('x:Row', String(c.r)),
6819 writetag('x:Column', String(c.c)),
6820 x[1].hidden ? '' : '<x:Visible/>',
6821 '</x:ClientData>',
6822 '</v:shape>'
6823 ]); });
6824 o.push('</xml>');
6825 return o.join("");
6826}
6827RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments";
6828
6829function sheet_insert_comments(sheet, comments) {
6830 var dense = Array.isArray(sheet);
6831 var cell;
6832 comments.forEach(function(comment) {
6833 var r = decode_cell(comment.ref);
6834 if(dense) {
6835 if(!sheet[r.r]) sheet[r.r] = [];
6836 cell = sheet[r.r][r.c];
6837 } else cell = sheet[comment.ref];
6838 if (!cell) {
6839 cell = ({t:"z"});
6840 if(dense) sheet[r.r][r.c] = cell;
6841 else sheet[comment.ref] = cell;
6842 var range = safe_decode_range(sheet["!ref"]||"BDWGO1000001:A1");
6843 if(range.s.r > r.r) range.s.r = r.r;
6844 if(range.e.r < r.r) range.e.r = r.r;
6845 if(range.s.c > r.c) range.s.c = r.c;
6846 if(range.e.c < r.c) range.e.c = r.c;
6847 var encoded = encode_range(range);
6848 if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
6849 }
6850
6851 if (!cell.c) cell.c = [];
6852 var o = ({a: comment.author, t: comment.t, r: comment.r});
6853 if(comment.h) o.h = comment.h;
6854 cell.c.push(o);
6855 });
6856}
6857
6858/* 18.7 Comments */
6859function parse_comments_xml(data, opts) {
6860 /* 18.7.6 CT_Comments */
6861 if(data.match(/<(?:\w+:)?comments *\/>/)) return [];
6862 var authors = [];
6863 var commentList = [];
6864 var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/);
6865 if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) {
6866 if(x === "" || x.trim() === "") return;
6867 var a = x.match(/<(?:\w+:)?author[^>]*>(.*)/);
6868 if(a) authors.push(a[1]);
6869 });
6870 var cmnttag = data.match(/<(?:\w+:)?commentList>([\s\S]*)<\/(?:\w+:)?commentList>/);
6871 if(cmnttag && cmnttag[1]) cmnttag[1].split(/<\/\w*:?comment>/).forEach(function(x) {
6872 if(x === "" || x.trim() === "") return;
6873 var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
6874 if(!cm) return;
6875 var y = parsexmltag(cm[0]);
6876 var comment = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid });
6877 var cell = decode_cell(y.ref);
6878 if(opts.sheetRows && opts.sheetRows <= cell.r) return;
6879 var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/);
6880 var rt = !!textMatch && !!textMatch[1] && parse_si(textMatch[1]) || {r:"",t:"",h:""};
6881 comment.r = rt.r;
6882 if(rt.r == "<t></t>") rt.t = rt.h = "";
6883 comment.t = rt.t.replace(/\r\n/g,"\n").replace(/\r/g,"\n");
6884 if(opts.cellHTML) comment.h = rt.h;
6885 commentList.push(comment);
6886 });
6887 return commentList;
6888}
6889
6890var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] });
6891function write_comments_xml(data) {
6892 var o = [XML_HEADER, CMNT_XML_ROOT];
6893
6894 var iauthor = [];
6895 o.push("<authors>");
6896 data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a);
6897 if(iauthor.indexOf(a) > -1) return;
6898 iauthor.push(a);
6899 o.push("<author>" + a + "</author>");
6900 }); });
6901 o.push("</authors>");
6902 o.push("<commentList>");
6903 data.forEach(function(d) {
6904 d[1].forEach(function(c) {
6905 /* 18.7.3 CT_Comment */
6906 o.push('<comment ref="' + d[0] + '" authorId="' + iauthor.indexOf(escapexml(c.a)) + '"><text>');
6907 o.push(writetag("t", c.t == null ? "" : escapexml(c.t)));
6908 o.push('</text></comment>');
6909 });
6910 });
6911 o.push("</commentList>");
6912 if(o.length>2) { o[o.length] = ('</comments>'); o[1]=o[1].replace("/>",">"); }
6913 return o.join("");
6914}
6915var CT_VBA = "application/vnd.ms-office.vbaProject";
6916function make_vba_xls(cfb) {
6917 var newcfb = CFB.utils.cfb_new({root:"R"});
6918 cfb.FullPaths.forEach(function(p, i) {
6919 if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
6920 var newpath = p.replace(/^[^\/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
6921 CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
6922 });
6923 return CFB.write(newcfb);
6924}
6925
6926function fill_vba_xls(cfb, vba) {
6927 vba.FullPaths.forEach(function(p, i) {
6928 if(i == 0) return;
6929 var newpath = p.replace(/[^\/]*[\/]/, "/_VBA_PROJECT_CUR/");
6930 if(newpath.slice(-1) !== "/") CFB.utils.cfb_add(cfb, newpath, vba.FileIndex[i].content);
6931 });
6932}
6933
6934var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ];
6935
6936RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
6937RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
6938
6939/* macro and dialog sheet stubs */
6940function parse_ds_bin() { return {'!type':'dialog'}; }
6941function parse_ds_xml() { return {'!type':'dialog'}; }
6942function parse_ms_bin() { return {'!type':'macro'}; }
6943function parse_ms_xml() { return {'!type':'macro'}; }
6944/* TODO: it will be useful to parse the function str */
6945var rc_to_a1 = (function(){
6946 var rcregex = /(^|[^A-Za-z_])R(\[?-?\d+\]|[1-9]\d*|)C(\[?-?\d+\]|[1-9]\d*|)(?![A-Za-z0-9_])/g;
6947 var rcbase = ({r:0,c:0});
6948 function rcfunc($$,$1,$2,$3) {
6949 var cRel = false, rRel = false;
6950
6951 if($2.length == 0) rRel = true;
6952 else if($2.charAt(0) == "[") { rRel = true; $2 = $2.slice(1, -1); }
6953
6954 if($3.length == 0) cRel = true;
6955 else if($3.charAt(0) == "[") { cRel = true; $3 = $3.slice(1, -1); }
6956
6957 var R = $2.length>0?parseInt($2,10)|0:0, C = $3.length>0?parseInt($3,10)|0:0;
6958
6959 if(cRel) C += rcbase.c; else --C;
6960 if(rRel) R += rcbase.r; else --R;
6961 return $1 + (cRel ? "" : "$") + encode_col(C) + (rRel ? "" : "$") + encode_row(R);
6962 }
6963 return function rc_to_a1(fstr, base) {
6964 rcbase = base;
6965 return fstr.replace(rcregex, rcfunc);
6966 };
6967})();
6968
6969var 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;
6970var a1_to_rc =(function(){
6971 return function a1_to_rc(fstr, base) {
6972 return fstr.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
6973 var c = decode_col($3) - ($2 ? 0 : base.c);
6974 var r = decode_row($5) - ($4 ? 0 : base.r);
6975 var R = (r == 0 ? "" : !$4 ? "[" + r + "]" : (r+1));
6976 var C = (c == 0 ? "" : !$2 ? "[" + c + "]" : (c+1));
6977 return $1 + "R" + R + "C" + C;
6978 });
6979 };
6980})();
6981
6982/* no defined name can collide with a valid cell address A1:XFD1048576 ... except LOG10! */
6983function shift_formula_str(f, delta) {
6984 return f.replace(crefregex, function($0, $1, $2, $3, $4, $5) {
6985 return $1+($2=="$" ? $2+$3 : encode_col(decode_col($3)+delta.c))+($4=="$" ? $4+$5 : encode_row(decode_row($5) + delta.r));
6986 });
6987}
6988
6989function shift_formula_xlsx(f, range, cell) {
6990 var r = decode_range(range), s = r.s, c = decode_cell(cell);
6991 var delta = {r:c.r - s.r, c:c.c - s.c};
6992 return shift_formula_str(f, delta);
6993}
6994
6995/* TODO: parse formula */
6996function fuzzyfmla(f) {
6997 if(f.length == 1) return false;
6998 return true;
6999}
7000
7001function _xlfn(f) {
7002 return f.replace(/_xlfn\./g,"");
7003}
7004var strs = {}; // shared strings
7005var _ssfopts = {}; // spreadsheet formatting options
7006
7007RELS.WS = [
7008 "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet",
7009 "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet"
7010];
7011
7012/*global Map */
7013var browser_has_Map = typeof Map !== 'undefined';
7014
7015function get_sst_id(sst, str, rev) {
7016 var i = 0, len = sst.length;
7017 if(rev) {
7018 if(browser_has_Map ? rev.has(str) : Object.prototype.hasOwnProperty.call(rev, str)) {
7019 var revarr = browser_has_Map ? rev.get(str) : rev[str];
7020 for(; i < revarr.length; ++i) {
7021 if(sst[revarr[i]].t === str) { sst.Count ++; return revarr[i]; }
7022 }
7023 }
7024 } else for(; i < len; ++i) {
7025 if(sst[i].t === str) { sst.Count ++; return i; }
7026 }
7027 sst[len] = ({t:str}); sst.Count ++; sst.Unique ++;
7028 if(rev) {
7029 if(browser_has_Map) {
7030 if(!rev.has(str)) rev.set(str, []);
7031 rev.get(str).push(len);
7032 } else {
7033 if(!Object.prototype.hasOwnProperty.call(rev, str)) rev[str] = [];
7034 rev[str].push(len);
7035 }
7036 }
7037 return len;
7038}
7039
7040function col_obj_w(C, col) {
7041 var p = ({min:C+1,max:C+1});
7042 /* wch (chars), wpx (pixels) */
7043 var wch = -1;
7044 if(col.MDW) MDW = col.MDW;
7045 if(col.width != null) p.customWidth = 1;
7046 else if(col.wpx != null) wch = px2char(col.wpx);
7047 else if(col.wch != null) wch = col.wch;
7048 if(wch > -1) { p.width = char2width(wch); p.customWidth = 1; }
7049 else if(col.width != null) p.width = col.width;
7050 if(col.hidden) p.hidden = true;
7051 return p;
7052}
7053
7054function default_margins(margins, mode) {
7055 if(!margins) return;
7056 var defs = [0.7, 0.7, 0.75, 0.75, 0.3, 0.3];
7057 if(mode == 'xlml') defs = [1, 1, 1, 1, 0.5, 0.5];
7058 if(margins.left == null) margins.left = defs[0];
7059 if(margins.right == null) margins.right = defs[1];
7060 if(margins.top == null) margins.top = defs[2];
7061 if(margins.bottom == null) margins.bottom = defs[3];
7062 if(margins.header == null) margins.header = defs[4];
7063 if(margins.footer == null) margins.footer = defs[5];
7064}
7065
7066function get_cell_style(styles, cell, opts) {
7067 var z = opts.revssf[cell.z != null ? cell.z : "General"];
7068 var i = 0x3c, len = styles.length;
7069 if(z == null && opts.ssf) {
7070 for(; i < 0x188; ++i) if(opts.ssf[i] == null) {
7071 SSF.load(cell.z, i);
7072 // $FlowIgnore
7073 opts.ssf[i] = cell.z;
7074 opts.revssf[cell.z] = z = i;
7075 break;
7076 }
7077 }
7078 for(i = 0; i != len; ++i) if(styles[i].numFmtId === z) return i;
7079 styles[len] = {
7080 numFmtId:z,
7081 fontId:0,
7082 fillId:0,
7083 borderId:0,
7084 xfId:0,
7085 applyNumberFormat:1
7086 };
7087 return len;
7088}
7089
7090function safe_format(p, fmtid, fillid, opts, themes, styles) {
7091 try {
7092 if(opts.cellNF) p.z = SSF._table[fmtid];
7093 } catch(e) { if(opts.WTF) throw e; }
7094 if(p.t === 'z') return;
7095 if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v);
7096 if(!opts || opts.cellText !== false) try {
7097 if(SSF._table[fmtid] == null) SSF.load(SSFImplicit[fmtid] || "General", fmtid);
7098 if(p.t === 'e') p.w = p.w || BErr[p.v];
7099 else if(fmtid === 0) {
7100 if(p.t === 'n') {
7101 if((p.v|0) === p.v) p.w = SSF._general_int(p.v);
7102 else p.w = SSF._general_num(p.v);
7103 }
7104 else if(p.t === 'd') {
7105 var dd = datenum(p.v);
7106 if((dd|0) === dd) p.w = SSF._general_int(dd);
7107 else p.w = SSF._general_num(dd);
7108 }
7109 else if(p.v === undefined) return "";
7110 else p.w = SSF._general(p.v,_ssfopts);
7111 }
7112 else if(p.t === 'd') p.w = SSF.format(fmtid,datenum(p.v),_ssfopts);
7113 else p.w = SSF.format(fmtid,p.v,_ssfopts);
7114 } catch(e) { if(opts.WTF) throw e; }
7115 if(!opts.cellStyles) return;
7116 if(fillid != null) try {
7117 p.s = styles.Fills[fillid];
7118 if (p.s.fgColor && p.s.fgColor.theme && !p.s.fgColor.rgb) {
7119 p.s.fgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.fgColor.theme].rgb, p.s.fgColor.tint || 0);
7120 if(opts.WTF) p.s.fgColor.raw_rgb = themes.themeElements.clrScheme[p.s.fgColor.theme].rgb;
7121 }
7122 if (p.s.bgColor && p.s.bgColor.theme) {
7123 p.s.bgColor.rgb = rgb_tint(themes.themeElements.clrScheme[p.s.bgColor.theme].rgb, p.s.bgColor.tint || 0);
7124 if(opts.WTF) p.s.bgColor.raw_rgb = themes.themeElements.clrScheme[p.s.bgColor.theme].rgb;
7125 }
7126 } catch(e) { if(opts.WTF && styles.Fills) throw e; }
7127}
7128
7129function check_ws(ws, sname, i) {
7130 if(ws && ws['!ref']) {
7131 var range = safe_decode_range(ws['!ref']);
7132 if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
7133 }
7134}
7135function parse_ws_xml_dim(ws, s) {
7136 var d = safe_decode_range(s);
7137 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);
7138}
7139var mergecregex = /<(?:\w:)?mergeCell ref="[A-Z0-9:]+"\s*[\/]?>/g;
7140var sheetdataregex = /<(?:\w+:)?sheetData[^>]*>([\s\S]*)<\/(?:\w+:)?sheetData>/;
7141var hlinkregex = /<(?:\w:)?hyperlink [^>]*>/mg;
7142var dimregex = /"(\w*:\w*)"/;
7143var colregex = /<(?:\w:)?col\b[^>]*[\/]?>/g;
7144var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
7145var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g;
7146var sheetprregex = /<(?:\w:)?sheetPr\b(?:[^>a-z][^>]*)?\/>/;
7147var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/;
7148
7149/* 18.3 Worksheets */
7150function parse_ws_xml(data, opts, idx, rels, wb, themes, styles) {
7151 if(!data) return data;
7152 if(!rels) rels = {'!id':{}};
7153 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
7154
7155 /* 18.3.1.99 worksheet CT_Worksheet */
7156 var s = opts.dense ? ([]) : ({});
7157 var refguess = ({s: {r:2000000, c:2000000}, e: {r:0, c:0} });
7158
7159 var data1 = "", data2 = "";
7160 var mtch = data.match(sheetdataregex);
7161 if(mtch) {
7162 data1 = data.slice(0, mtch.index);
7163 data2 = data.slice(mtch.index + mtch[0].length);
7164 } else data1 = data2 = data;
7165
7166 /* 18.3.1.82 sheetPr CT_SheetPr */
7167 var sheetPr = data1.match(sheetprregex);
7168 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
7169
7170 /* 18.3.1.35 dimension CT_SheetDimension */
7171 var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index;
7172 if(ridx > 0) {
7173 var ref = data1.slice(ridx,ridx+50).match(dimregex);
7174 if(ref) parse_ws_xml_dim(s, ref[1]);
7175 }
7176
7177 /* 18.3.1.88 sheetViews CT_SheetViews */
7178 var svs = data1.match(svsregex);
7179 if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb);
7180
7181 /* 18.3.1.17 cols CT_Cols */
7182 var columns = [];
7183 if(opts.cellStyles) {
7184 /* 18.3.1.13 col CT_Col */
7185 var cols = data1.match(colregex);
7186 if(cols) parse_ws_xml_cols(columns, cols);
7187 }
7188
7189 /* 18.3.1.80 sheetData CT_SheetData ? */
7190 if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles);
7191
7192 /* 18.3.1.2 autoFilter CT_AutoFilter */
7193 var afilter = data2.match(afregex);
7194 if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
7195
7196 /* 18.3.1.55 mergeCells CT_MergeCells */
7197 var merges = [];
7198 var _merge = data2.match(mergecregex);
7199 if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx)
7200 merges[ridx] = safe_decode_range(_merge[ridx].slice(_merge[ridx].indexOf("\"")+1));
7201
7202 /* 18.3.1.48 hyperlinks CT_Hyperlinks */
7203 var hlink = data2.match(hlinkregex);
7204 if(hlink) parse_ws_xml_hlinks(s, hlink, rels);
7205
7206 /* 18.3.1.62 pageMargins CT_PageMargins */
7207 var margins = data2.match(marginregex);
7208 if(margins) s['!margins'] = parse_ws_xml_margins(parsexmltag(margins[0]));
7209
7210 if(!s["!ref"] && refguess.e.c >= refguess.s.c && refguess.e.r >= refguess.s.r) s["!ref"] = encode_range(refguess);
7211 if(opts.sheetRows > 0 && s["!ref"]) {
7212 var tmpref = safe_decode_range(s["!ref"]);
7213 if(opts.sheetRows <= +tmpref.e.r) {
7214 tmpref.e.r = opts.sheetRows - 1;
7215 if(tmpref.e.r > refguess.e.r) tmpref.e.r = refguess.e.r;
7216 if(tmpref.e.r < tmpref.s.r) tmpref.s.r = tmpref.e.r;
7217 if(tmpref.e.c > refguess.e.c) tmpref.e.c = refguess.e.c;
7218 if(tmpref.e.c < tmpref.s.c) tmpref.s.c = tmpref.e.c;
7219 s["!fullref"] = s["!ref"];
7220 s["!ref"] = encode_range(tmpref);
7221 }
7222 }
7223 if(columns.length > 0) s["!cols"] = columns;
7224 if(merges.length > 0) s["!merges"] = merges;
7225 return s;
7226}
7227
7228function write_ws_xml_merges(merges) {
7229 if(merges.length === 0) return "";
7230 var o = '<mergeCells count="' + merges.length + '">';
7231 for(var i = 0; i != merges.length; ++i) o += '<mergeCell ref="' + encode_range(merges[i]) + '"/>';
7232 return o + '</mergeCells>';
7233}
7234
7235/* 18.3.1.82-3 sheetPr CT_ChartsheetPr / CT_SheetPr */
7236function parse_ws_xml_sheetpr(sheetPr, s, wb, idx) {
7237 var data = parsexmltag(sheetPr);
7238 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
7239 if(data.codeName) wb.Sheets[idx].CodeName = unescapexml(utf8read(data.codeName));
7240}
7241function write_ws_xml_sheetpr(ws, wb, idx, opts, o) {
7242 var needed = false;
7243 var props = {}, payload = null;
7244 if(opts.bookType !== 'xlsx' && wb.vbaraw) {
7245 var cname = wb.SheetNames[idx];
7246 try { if(wb.Workbook) cname = wb.Workbook.Sheets[idx].CodeName || cname; } catch(e) {}
7247 needed = true;
7248 props.codeName = utf8write(escapexml(cname));
7249 }
7250
7251 if(ws && ws["!outline"]) {
7252 var outlineprops = {summaryBelow:1, summaryRight:1};
7253 if(ws["!outline"].above) outlineprops.summaryBelow = 0;
7254 if(ws["!outline"].left) outlineprops.summaryRight = 0;
7255 payload = (payload||"") + writextag('outlinePr', null, outlineprops);
7256 }
7257
7258 if(!needed && !payload) return;
7259 o[o.length] = (writextag('sheetPr', payload, props));
7260}
7261
7262/* 18.3.1.85 sheetProtection CT_SheetProtection */
7263var sheetprot_deffalse = ["objects", "scenarios", "selectLockedCells", "selectUnlockedCells"];
7264var sheetprot_deftrue = [
7265 "formatColumns", "formatRows", "formatCells",
7266 "insertColumns", "insertRows", "insertHyperlinks",
7267 "deleteColumns", "deleteRows",
7268 "sort", "autoFilter", "pivotTables"
7269];
7270function write_ws_xml_protection(sp) {
7271 // algorithmName, hashValue, saltValue, spinCount
7272 var o = ({sheet:1});
7273 sheetprot_deffalse.forEach(function(n) { if(sp[n] != null && sp[n]) o[n] = "1"; });
7274 sheetprot_deftrue.forEach(function(n) { if(sp[n] != null && !sp[n]) o[n] = "0"; });
7275 /* TODO: algorithm */
7276 if(sp.password) o.password = crypto_CreatePasswordVerifier_Method1(sp.password).toString(16).toUpperCase();
7277 return writextag('sheetProtection', null, o);
7278}
7279
7280function parse_ws_xml_hlinks(s, data, rels) {
7281 var dense = Array.isArray(s);
7282 for(var i = 0; i != data.length; ++i) {
7283 var val = parsexmltag(utf8read(data[i]), true);
7284 if(!val.ref) return;
7285 var rel = ((rels || {})['!id']||[])[val.id];
7286 if(rel) {
7287 val.Target = rel.Target;
7288 if(val.location) val.Target += "#"+val.location;
7289 } else {
7290 val.Target = "#" + val.location;
7291 rel = {Target: val.Target, TargetMode: 'Internal'};
7292 }
7293 val.Rel = rel;
7294 if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
7295 var rng = safe_decode_range(val.ref);
7296 for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
7297 var addr = encode_cell({c:C,r:R});
7298 if(dense) {
7299 if(!s[R]) s[R] = [];
7300 if(!s[R][C]) s[R][C] = {t:"z",v:undefined};
7301 s[R][C].l = val;
7302 } else {
7303 if(!s[addr]) s[addr] = {t:"z",v:undefined};
7304 s[addr].l = val;
7305 }
7306 }
7307 }
7308}
7309
7310function parse_ws_xml_margins(margin) {
7311 var o = {};
7312 ["left", "right", "top", "bottom", "header", "footer"].forEach(function(k) {
7313 if(margin[k]) o[k] = parseFloat(margin[k]);
7314 });
7315 return o;
7316}
7317function write_ws_xml_margins(margin) {
7318 default_margins(margin);
7319 return writextag('pageMargins', null, margin);
7320}
7321
7322function parse_ws_xml_cols(columns, cols) {
7323 var seencol = false;
7324 for(var coli = 0; coli != cols.length; ++coli) {
7325 var coll = parsexmltag(cols[coli], true);
7326 if(coll.hidden) coll.hidden = parsexmlbool(coll.hidden);
7327 var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
7328 delete coll.min; delete coll.max; coll.width = +coll.width;
7329 if(!seencol && coll.width) { seencol = true; find_mdw_colw(coll.width); }
7330 process_col(coll);
7331 while(colm <= colM) columns[colm++] = dup(coll);
7332 }
7333}
7334function write_ws_xml_cols(ws, cols) {
7335 var o = ["<cols>"], col;
7336 for(var i = 0; i != cols.length; ++i) {
7337 if(!(col = cols[i])) continue;
7338 o[o.length] = (writextag('col', null, col_obj_w(i, col)));
7339 }
7340 o[o.length] = "</cols>";
7341 return o.join("");
7342}
7343
7344function parse_ws_xml_autofilter(data) {
7345 var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]};
7346 return o;
7347}
7348function write_ws_xml_autofilter(data, ws, wb, idx) {
7349 var ref = typeof data.ref == "string" ? data.ref : encode_range(data.ref);
7350 if(!wb.Workbook) wb.Workbook = ({Sheets:[]});
7351 if(!wb.Workbook.Names) wb.Workbook.Names = [];
7352 var names = wb.Workbook.Names;
7353 var range = decode_range(ref);
7354 if(range.s.r == range.e.r) { range.e.r = decode_range(ws["!ref"]).e.r; ref = encode_range(range); }
7355 for(var i = 0; i < names.length; ++i) {
7356 var name = names[i];
7357 if(name.Name != '_xlnm._FilterDatabase') continue;
7358 if(name.Sheet != idx) continue;
7359 name.Ref = "'" + wb.SheetNames[idx] + "'!" + ref; break;
7360 }
7361 if(i == names.length) names.push({ Name: '_xlnm._FilterDatabase', Sheet: idx, Ref: "'" + wb.SheetNames[idx] + "'!" + ref });
7362 return writextag("autoFilter", null, {ref:ref});
7363}
7364
7365/* 18.3.1.88 sheetViews CT_SheetViews */
7366/* 18.3.1.87 sheetView CT_SheetView */
7367var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/?>/;
7368function parse_ws_xml_sheetviews(data, wb) {
7369 if(!wb.Views) wb.Views = [{}];
7370 (data.match(sviewregex)||[]).forEach(function(r, i) {
7371 var tag = parsexmltag(r);
7372 // $FlowIgnore
7373 if(!wb.Views[i]) wb.Views[i] = {};
7374 // $FlowIgnore
7375 if(+tag.zoomScale) wb.Views[i].zoom = +tag.zoomScale;
7376 // $FlowIgnore
7377 if(parsexmlbool(tag.rightToLeft)) wb.Views[i].RTL = true;
7378 });
7379}
7380function write_ws_xml_sheetviews(ws, opts, idx, wb) {
7381 var sview = ({workbookViewId:"0"});
7382 // $FlowIgnore
7383 if((((wb||{}).Workbook||{}).Views||[])[0]) sview.rightToLeft = wb.Workbook.Views[0].RTL ? "1" : "0";
7384 return writextag("sheetViews", writextag("sheetView", null, sview), {});
7385}
7386
7387function write_ws_xml_cell(cell, ref, ws, opts) {
7388 if(cell.v === undefined && typeof cell.f !== "string" || cell.t === 'z') return "";
7389 var vv = "";
7390 var oldt = cell.t, oldv = cell.v;
7391 if(cell.t !== "z") switch(cell.t) {
7392 case 'b': vv = cell.v ? "1" : "0"; break;
7393 case 'n': vv = ''+cell.v; break;
7394 case 'e': vv = BErr[cell.v]; break;
7395 case 'd':
7396 if(opts && opts.cellDates) vv = parseDate(cell.v, -1).toISOString();
7397 else {
7398 cell = dup(cell);
7399 cell.t = 'n';
7400 vv = ''+(cell.v = datenum(parseDate(cell.v)));
7401 }
7402 if(typeof cell.z === 'undefined') cell.z = SSF._table[14];
7403 break;
7404 default: vv = cell.v; break;
7405 }
7406 var v = writetag('v', escapexml(vv)), o = ({r:ref});
7407 /* TODO: cell style */
7408 var os = get_cell_style(opts.cellXfs, cell, opts);
7409 if(os !== 0) o.s = os;
7410 switch(cell.t) {
7411 case 'n': break;
7412 case 'd': o.t = "d"; break;
7413 case 'b': o.t = "b"; break;
7414 case 'e': o.t = "e"; break;
7415 case 'z': break;
7416 default: if(cell.v == null) { delete cell.t; break; }
7417 if(opts && opts.bookSST) {
7418 v = writetag('v', ''+get_sst_id(opts.Strings, cell.v, opts.revStrings));
7419 o.t = "s"; break;
7420 }
7421 o.t = "str"; break;
7422 }
7423 if(cell.t != oldt) { cell.t = oldt; cell.v = oldv; }
7424 if(typeof cell.f == "string" && cell.f) {
7425 var ff = cell.F && cell.F.slice(0, ref.length) == ref ? {t:"array", ref:cell.F} : null;
7426 v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : "");
7427 }
7428 if(cell.l) ws['!links'].push([ref, cell.l]);
7429 if(cell.c) ws['!comments'].push([ref, cell.c]);
7430 return writextag('c', v, o);
7431}
7432
7433var parse_ws_xml_data = (function() {
7434 var cellregex = /<(?:\w+:)?c[ \/>]/, rowregex = /<\/(?:\w+:)?row>/;
7435 var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/;
7436 var refregex = /ref=["']([^"']*)["']/;
7437 var match_v = matchtag("v"), match_f = matchtag("f");
7438
7439return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) {
7440 var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p;
7441 var tag, tagr = 0, tagc = 0;
7442 var sstr, ftag;
7443 var fmtid = 0, fillid = 0;
7444 var do_format = Array.isArray(styles.CellXf), cf;
7445 var arrayf = [];
7446 var sharedf = [];
7447 var dense = Array.isArray(s);
7448 var rows = [], rowobj = {}, rowrite = false;
7449 var sheetStubs = !!opts.sheetStubs;
7450 for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) {
7451 x = marr[mt].trim();
7452 var xlen = x.length;
7453 if(xlen === 0) continue;
7454
7455 /* 18.3.1.73 row CT_Row */
7456 for(ri = 0; ri < xlen; ++ri) if(x.charCodeAt(ri) === 62) break; ++ri;
7457 tag = parsexmltag(x.slice(0,ri), true);
7458 tagr = tag.r != null ? parseInt(tag.r, 10) : tagr+1; tagc = -1;
7459 if(opts.sheetRows && opts.sheetRows < tagr) continue;
7460 if(guess.s.r > tagr - 1) guess.s.r = tagr - 1;
7461 if(guess.e.r < tagr - 1) guess.e.r = tagr - 1;
7462
7463 if(opts && opts.cellStyles) {
7464 rowobj = {}; rowrite = false;
7465 if(tag.ht) { rowrite = true; rowobj.hpt = parseFloat(tag.ht); rowobj.hpx = pt2px(rowobj.hpt); }
7466 if(tag.hidden == "1") { rowrite = true; rowobj.hidden = true; }
7467 if(tag.outlineLevel != null) { rowrite = true; rowobj.level = +tag.outlineLevel; }
7468 if(rowrite) rows[tagr-1] = rowobj;
7469 }
7470
7471 /* 18.3.1.4 c CT_Cell */
7472 cells = x.slice(ri).split(cellregex);
7473 for(var rslice = 0; rslice != cells.length; ++rslice) if(cells[rslice].trim().charAt(0) != "<") break;
7474 cells = cells.slice(rslice);
7475 for(ri = 0; ri != cells.length; ++ri) {
7476 x = cells[ri].trim();
7477 if(x.length === 0) continue;
7478 cref = x.match(rregex); idx = ri; i=0; cc=0;
7479 x = "<c " + (x.slice(0,1)=="<"?">":"") + x;
7480 if(cref != null && cref.length === 2) {
7481 idx = 0; d=cref[1];
7482 for(i=0; i != d.length; ++i) {
7483 if((cc=d.charCodeAt(i)-64) < 1 || cc > 26) break;
7484 idx = 26*idx + cc;
7485 }
7486 --idx;
7487 tagc = idx;
7488 } else ++tagc;
7489 for(i = 0; i != x.length; ++i) if(x.charCodeAt(i) === 62) break; ++i;
7490 tag = parsexmltag(x.slice(0,i), true);
7491 if(!tag.r) tag.r = encode_cell({r:tagr-1, c:tagc});
7492 d = x.slice(i);
7493 p = ({t:""});
7494
7495 if((cref=d.match(match_v))!= null && cref[1] !== '') p.v=unescapexml(cref[1]);
7496 if(opts.cellFormula) {
7497 if((cref=d.match(match_f))!= null && cref[1] !== '') {
7498 /* TODO: match against XLSXFutureFunctions */
7499 p.f=unescapexml(utf8read(cref[1])).replace(/\r\n/g, "\n");
7500 if(!opts.xlfn) p.f = _xlfn(p.f);
7501 if(cref[0].indexOf('t="array"') > -1) {
7502 p.F = (d.match(refregex)||[])[1];
7503 if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]);
7504 } else if(cref[0].indexOf('t="shared"') > -1) {
7505 // TODO: parse formula
7506 ftag = parsexmltag(cref[0]);
7507 var ___f = unescapexml(utf8read(cref[1]));
7508 if(!opts.xlfn) ___f = _xlfn(___f);
7509 sharedf[parseInt(ftag.si, 10)] = [ftag, ___f, tag.r];
7510 }
7511 } else if((cref=d.match(/<f[^>]*\/>/))) {
7512 ftag = parsexmltag(cref[0]);
7513 if(sharedf[ftag.si]) p.f = shift_formula_xlsx(sharedf[ftag.si][1], sharedf[ftag.si][2]/*[0].ref*/, tag.r);
7514 }
7515 /* TODO: factor out contains logic */
7516 var _tag = decode_cell(tag.r);
7517 for(i = 0; i < arrayf.length; ++i)
7518 if(_tag.r >= arrayf[i][0].s.r && _tag.r <= arrayf[i][0].e.r)
7519 if(_tag.c >= arrayf[i][0].s.c && _tag.c <= arrayf[i][0].e.c)
7520 p.F = arrayf[i][1];
7521 }
7522
7523 if(tag.t == null && p.v === undefined) {
7524 if(p.f || p.F) {
7525 p.v = 0; p.t = "n";
7526 } else if(!sheetStubs) continue;
7527 else p.t = "z";
7528 }
7529 else p.t = tag.t || "n";
7530 if(guess.s.c > tagc) guess.s.c = tagc;
7531 if(guess.e.c < tagc) guess.e.c = tagc;
7532 /* 18.18.11 t ST_CellType */
7533 switch(p.t) {
7534 case 'n':
7535 if(p.v == "" || p.v == null) {
7536 if(!sheetStubs) continue;
7537 p.t = 'z';
7538 } else p.v = parseFloat(p.v);
7539 break;
7540 case 's':
7541 if(typeof p.v == 'undefined') {
7542 if(!sheetStubs) continue;
7543 p.t = 'z';
7544 } else {
7545 sstr = strs[parseInt(p.v, 10)];
7546 p.v = sstr.t;
7547 p.r = sstr.r;
7548 if(opts.cellHTML) p.h = sstr.h;
7549 }
7550 break;
7551 case 'str':
7552 p.t = "s";
7553 p.v = (p.v!=null) ? utf8read(p.v) : '';
7554 if(opts.cellHTML) p.h = escapehtml(p.v);
7555 break;
7556 case 'inlineStr':
7557 cref = d.match(isregex);
7558 p.t = 's';
7559 if(cref != null && (sstr = parse_si(cref[1]))) {
7560 p.v = sstr.t;
7561 if(opts.cellHTML) p.h = sstr.h;
7562 } else p.v = "";
7563 break;
7564 case 'b': p.v = parsexmlbool(p.v); break;
7565 case 'd':
7566 if(opts.cellDates) p.v = parseDate(p.v, 1);
7567 else { p.v = datenum(parseDate(p.v, 1)); p.t = 'n'; }
7568 break;
7569 /* error string in .w, number in .v */
7570 case 'e':
7571 if(!opts || opts.cellText !== false) p.w = p.v;
7572 p.v = RBErr[p.v]; break;
7573 }
7574 /* formatting */
7575 fmtid = fillid = 0;
7576 cf = null;
7577 if(do_format && tag.s !== undefined) {
7578 cf = styles.CellXf[tag.s];
7579 if(cf != null) {
7580 if(cf.numFmtId != null) fmtid = cf.numFmtId;
7581 if(opts.cellStyles) {
7582 if(cf.fillId != null) fillid = cf.fillId;
7583 }
7584 }
7585 }
7586 safe_format(p, fmtid, fillid, opts, themes, styles);
7587 if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); }
7588 if(dense) {
7589 var _r = decode_cell(tag.r);
7590 if(!s[_r.r]) s[_r.r] = [];
7591 s[_r.r][_r.c] = p;
7592 } else s[tag.r] = p;
7593 }
7594 }
7595 if(rows.length > 0) s['!rows'] = rows;
7596}; })();
7597
7598function write_ws_xml_data(ws, opts, idx, wb) {
7599 var o = [], r = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows'];
7600 var dense = Array.isArray(ws);
7601 var params = ({r:rr}), row, height = -1;
7602 for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C);
7603 for(R = range.s.r; R <= range.e.r; ++R) {
7604 r = [];
7605 rr = encode_row(R);
7606 for(C = range.s.c; C <= range.e.c; ++C) {
7607 ref = cols[C] + rr;
7608 var _cell = dense ? (ws[R]||[])[C]: ws[ref];
7609 if(_cell === undefined) continue;
7610 if((cell = write_ws_xml_cell(_cell, ref, ws, opts, idx, wb)) != null) r.push(cell);
7611 }
7612 if(r.length > 0 || (rows && rows[R])) {
7613 params = ({r:rr});
7614 if(rows && rows[R]) {
7615 row = rows[R];
7616 if(row.hidden) params.hidden = 1;
7617 height = -1;
7618 if(row.hpx) height = px2pt(row.hpx);
7619 else if(row.hpt) height = row.hpt;
7620 if(height > -1) { params.ht = height; params.customHeight = 1; }
7621 if(row.level) { params.outlineLevel = row.level; }
7622 }
7623 o[o.length] = (writextag('row', r.join(""), params));
7624 }
7625 }
7626 if(rows) for(; R < rows.length; ++R) {
7627 if(rows && rows[R]) {
7628 params = ({r:R+1});
7629 row = rows[R];
7630 if(row.hidden) params.hidden = 1;
7631 height = -1;
7632 if (row.hpx) height = px2pt(row.hpx);
7633 else if (row.hpt) height = row.hpt;
7634 if (height > -1) { params.ht = height; params.customHeight = 1; }
7635 if (row.level) { params.outlineLevel = row.level; }
7636 o[o.length] = (writextag('row', "", params));
7637 }
7638 }
7639 return o.join("");
7640}
7641
7642var WS_XML_ROOT = writextag('worksheet', null, {
7643 'xmlns': XMLNS.main[0],
7644 'xmlns:r': XMLNS.r
7645});
7646
7647function write_ws_xml(idx, opts, wb, rels) {
7648 var o = [XML_HEADER, WS_XML_ROOT];
7649 var s = wb.SheetNames[idx], sidx = 0, rdata = "";
7650 var ws = wb.Sheets[s];
7651 if(ws == null) ws = {};
7652 var ref = ws['!ref'] || 'A1';
7653 var range = safe_decode_range(ref);
7654 if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
7655 if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
7656 range.e.c = Math.min(range.e.c, 0x3FFF);
7657 range.e.r = Math.min(range.e.c, 0xFFFFF);
7658 ref = encode_range(range);
7659 }
7660 if(!rels) rels = {};
7661 ws['!comments'] = [];
7662 var _drawing = [];
7663
7664 write_ws_xml_sheetpr(ws, wb, idx, opts, o);
7665
7666 o[o.length] = (writextag('dimension', null, {'ref': ref}));
7667
7668 o[o.length] = write_ws_xml_sheetviews(ws, opts, idx, wb);
7669
7670 /* TODO: store in WB, process styles */
7671 if(opts.sheetFormat) o[o.length] = (writextag('sheetFormatPr', null, {
7672 defaultRowHeight:opts.sheetFormat.defaultRowHeight||'16',
7673 baseColWidth:opts.sheetFormat.baseColWidth||'10',
7674 outlineLevelRow:opts.sheetFormat.outlineLevelRow||'7'
7675 }));
7676
7677 if(ws['!cols'] != null && ws['!cols'].length > 0) o[o.length] = (write_ws_xml_cols(ws, ws['!cols']));
7678
7679 o[sidx = o.length] = '<sheetData/>';
7680 ws['!links'] = [];
7681 if(ws['!ref'] != null) {
7682 rdata = write_ws_xml_data(ws, opts, idx, wb, rels);
7683 if(rdata.length > 0) o[o.length] = (rdata);
7684 }
7685 if(o.length>sidx+1) { o[o.length] = ('</sheetData>'); o[sidx]=o[sidx].replace("/>",">"); }
7686
7687 /* sheetCalcPr */
7688
7689 if(ws['!protect'] != null) o[o.length] = write_ws_xml_protection(ws['!protect']);
7690
7691 /* protectedRanges */
7692 /* scenarios */
7693
7694 if(ws['!autofilter'] != null) o[o.length] = write_ws_xml_autofilter(ws['!autofilter'], ws, wb, idx);
7695
7696 /* sortState */
7697 /* dataConsolidate */
7698 /* customSheetViews */
7699
7700 if(ws['!merges'] != null && ws['!merges'].length > 0) o[o.length] = (write_ws_xml_merges(ws['!merges']));
7701
7702 /* phoneticPr */
7703 /* conditionalFormatting */
7704 /* dataValidations */
7705
7706 var relc = -1, rel, rId = -1;
7707 if(ws['!links'].length > 0) {
7708 o[o.length] = "<hyperlinks>";
7709ws['!links'].forEach(function(l) {
7710 if(!l[1].Target) return;
7711 rel = ({"ref":l[0]});
7712 if(l[1].Target.charAt(0) != "#") {
7713 rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
7714 rel["r:id"] = "rId"+rId;
7715 }
7716 if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.slice(relc+1));
7717 if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
7718 o[o.length] = writextag("hyperlink",null,rel);
7719 });
7720 o[o.length] = "</hyperlinks>";
7721 }
7722 delete ws['!links'];
7723
7724 /* printOptions */
7725
7726 if(ws['!margins'] != null) o[o.length] = write_ws_xml_margins(ws['!margins']);
7727
7728 /* pageSetup */
7729 /* headerFooter */
7730 /* rowBreaks */
7731 /* colBreaks */
7732 /* customProperties */
7733 /* cellWatches */
7734
7735 if(!opts || opts.ignoreEC || (opts.ignoreEC == (void 0))) o[o.length] = writetag("ignoredErrors", writextag("ignoredError", null, {numberStoredAsText:1, sqref:ref}));
7736
7737 /* smartTags */
7738
7739 if(_drawing.length > 0) {
7740 rId = add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
7741 o[o.length] = writextag("drawing", null, {"r:id":"rId" + rId});
7742 ws['!drawing'] = _drawing;
7743 }
7744
7745 if(ws['!comments'].length > 0) {
7746 rId = add_rels(rels, -1, "../drawings/vmlDrawing" + (idx+1) + ".vml", RELS.VML);
7747 o[o.length] = writextag("legacyDrawing", null, {"r:id":"rId" + rId});
7748 ws['!legacy'] = rId;
7749 }
7750
7751 /* legacyDrawingHF */
7752 /* picture */
7753 /* oleObjects */
7754 /* controls */
7755 /* webPublishItems */
7756 /* tableParts */
7757 /* extLst */
7758
7759 if(o.length>1) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
7760 return o.join("");
7761}
7762RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart";
7763RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx";
7764
7765function parse_Cache(data) {
7766 var col = [];
7767 var num = data.match(/^<c:numCache>/);
7768 var f;
7769
7770 /* 21.2.2.150 pt CT_NumVal */
7771 (data.match(/<c:pt idx="(\d*)">(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) {
7772 var q = pt.match(/<c:pt idx="(\d*?)"><c:v>(.*)<\/c:v><\/c:pt>/);
7773 if(!q) return;
7774 col[+q[1]] = num ? +q[2] : q[2];
7775 });
7776
7777 /* 21.2.2.71 formatCode CT_Xstring */
7778 var nf = unescapexml((data.match(/<c:formatCode>([\s\S]*?)<\/c:formatCode>/) || ["","General"])[1]);
7779
7780 (data.match(/<c:f>(.*?)<\/c:f>/mg)||[]).forEach(function(F) { f = F.replace(/<.*?>/g,""); });
7781
7782 return [col, nf, f];
7783}
7784
7785/* 21.2 DrawingML - Charts */
7786function parse_chart(data, name, opts, rels, wb, csheet) {
7787 var cs = ((csheet || {"!type":"chart"}));
7788 if(!data) return csheet;
7789 /* 21.2.2.27 chart CT_Chart */
7790
7791 var C = 0, R = 0, col = "A";
7792 var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
7793
7794 /* 21.2.2.120 numCache CT_NumData */
7795 (data.match(/<c:numCache>[\s\S]*?<\/c:numCache>/gm)||[]).forEach(function(nc) {
7796 var cache = parse_Cache(nc);
7797 refguess.s.r = refguess.s.c = 0;
7798 refguess.e.c = C;
7799 col = encode_col(C);
7800 cache[0].forEach(function(n,i) {
7801 cs[col + encode_row(i)] = {t:'n', v:n, z:cache[1] };
7802 R = i;
7803 });
7804 if(refguess.e.r < R) refguess.e.r = R;
7805 ++C;
7806 });
7807 if(C > 0) cs["!ref"] = encode_range(refguess);
7808 return cs;
7809}
7810RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet";
7811
7812var CS_XML_ROOT = writextag('chartsheet', null, {
7813 'xmlns': XMLNS.main[0],
7814 'xmlns:r': XMLNS.r
7815});
7816
7817/* 18.3 Worksheets also covers Chartsheets */
7818function parse_cs_xml(data, opts, idx, rels, wb) {
7819 if(!data) return data;
7820 /* 18.3.1.12 chartsheet CT_ChartSheet */
7821 if(!rels) rels = {'!id':{}};
7822 var s = ({'!type':"chart", '!drawel':null, '!rel':""});
7823 var m;
7824
7825 /* 18.3.1.83 sheetPr CT_ChartsheetPr */
7826 var sheetPr = data.match(sheetprregex);
7827 if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx);
7828
7829 /* 18.3.1.36 drawing CT_Drawing */
7830 if((m = data.match(/drawing r:id="(.*?)"/))) s['!rel'] = m[1];
7831
7832 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
7833 return s;
7834}
7835function write_cs_xml(idx, opts, wb, rels) {
7836 var o = [XML_HEADER, CS_XML_ROOT];
7837 o[o.length] = writextag("drawing", null, {"r:id": "rId1"});
7838 add_rels(rels, -1, "../drawings/drawing" + (idx+1) + ".xml", RELS.DRAW);
7839 if(o.length>2) { o[o.length] = ('</chartsheet>'); o[1]=o[1].replace("/>",">"); }
7840 return o.join("");
7841}
7842
7843/* [MS-XLSB] 2.4.331 BrtCsProp */
7844function parse_BrtCsProp(data, length) {
7845 data.l += 10;
7846 var name = parse_XLWideString(data, length - 10);
7847 return { name: name };
7848}
7849
7850/* [MS-XLSB] 2.1.7.7 Chart Sheet */
7851function parse_cs_bin(data, opts, idx, rels, wb) {
7852 if(!data) return data;
7853 if(!rels) rels = {'!id':{}};
7854 var s = {'!type':"chart", '!drawel':null, '!rel':""};
7855 var state = [];
7856 var pass = false;
7857 recordhopper(data, function cs_parse(val, R_n, RT) {
7858 switch(RT) {
7859
7860 case 0x0226: /* 'BrtDrawing' */
7861 s['!rel'] = val; break;
7862
7863 case 0x028B: /* 'BrtCsProp' */
7864 if(!wb.Sheets[idx]) wb.Sheets[idx] = {};
7865 if(val.name) wb.Sheets[idx].CodeName = val.name;
7866 break;
7867
7868 case 0x0232: /* 'BrtBkHim' */
7869 case 0x028C: /* 'BrtCsPageSetup' */
7870 case 0x029D: /* 'BrtCsProtection' */
7871 case 0x02A7: /* 'BrtCsProtectionIso' */
7872 case 0x0227: /* 'BrtLegacyDrawing' */
7873 case 0x0228: /* 'BrtLegacyDrawingHF' */
7874 case 0x01DC: /* 'BrtMargins' */
7875 case 0x0C00: /* 'BrtUid' */
7876 break;
7877
7878 case 0x0023: /* 'BrtFRTBegin' */
7879 pass = true; break;
7880 case 0x0024: /* 'BrtFRTEnd' */
7881 pass = false; break;
7882 case 0x0025: /* 'BrtACBegin' */
7883 state.push(R_n); break;
7884 case 0x0026: /* 'BrtACEnd' */
7885 state.pop(); break;
7886
7887 default:
7888 if((R_n||"").indexOf("Begin") > 0) state.push(R_n);
7889 else if((R_n||"").indexOf("End") > 0) state.pop();
7890 else if(!pass || opts.WTF) throw new Error("Unexpected record " + RT + " " + R_n);
7891 }
7892 }, opts);
7893
7894 if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
7895 return s;
7896}
7897function write_cs_bin() {
7898 var ba = buf_array();
7899 write_record(ba, "BrtBeginSheet");
7900 /* [BrtCsProp] */
7901 /* CSVIEWS */
7902 /* [[BrtCsProtectionIso] BrtCsProtection] */
7903 /* [USERCSVIEWS] */
7904 /* [BrtMargins] */
7905 /* [BrtCsPageSetup] */
7906 /* [HEADERFOOTER] */
7907 /* BrtDrawing */
7908 /* [BrtLegacyDrawing] */
7909 /* [BrtLegacyDrawingHF] */
7910 /* [BrtBkHim] */
7911 /* [WEBPUBITEMS] */
7912 /* FRTCHARTSHEET */
7913 write_record(ba, "BrtEndSheet");
7914 return ba.end();
7915}
7916/* 18.2.28 (CT_WorkbookProtection) Defaults */
7917var WBPropsDef = [
7918 ['allowRefreshQuery', false, "bool"],
7919 ['autoCompressPictures', true, "bool"],
7920 ['backupFile', false, "bool"],
7921 ['checkCompatibility', false, "bool"],
7922 ['CodeName', ''],
7923 ['date1904', false, "bool"],
7924 ['defaultThemeVersion', 0, "int"],
7925 ['filterPrivacy', false, "bool"],
7926 ['hidePivotFieldList', false, "bool"],
7927 ['promptedSolutions', false, "bool"],
7928 ['publishItems', false, "bool"],
7929 ['refreshAllConnections', false, "bool"],
7930 ['saveExternalLinkValues', true, "bool"],
7931 ['showBorderUnselectedTables', true, "bool"],
7932 ['showInkAnnotation', true, "bool"],
7933 ['showObjects', 'all'],
7934 ['showPivotChartFilter', false, "bool"],
7935 ['updateLinks', 'userSet']
7936];
7937
7938/* 18.2.30 (CT_BookView) Defaults */
7939var WBViewDef = [
7940 ['activeTab', 0, "int"],
7941 ['autoFilterDateGrouping', true, "bool"],
7942 ['firstSheet', 0, "int"],
7943 ['minimized', false, "bool"],
7944 ['showHorizontalScroll', true, "bool"],
7945 ['showSheetTabs', true, "bool"],
7946 ['showVerticalScroll', true, "bool"],
7947 ['tabRatio', 600, "int"],
7948 ['visibility', 'visible']
7949 //window{Height,Width}, {x,y}Window
7950];
7951
7952/* 18.2.19 (CT_Sheet) Defaults */
7953var SheetDef = [
7954 //['state', 'visible']
7955];
7956
7957/* 18.2.2 (CT_CalcPr) Defaults */
7958var CalcPrDef = [
7959 ['calcCompleted', 'true'],
7960 ['calcMode', 'auto'],
7961 ['calcOnSave', 'true'],
7962 ['concurrentCalc', 'true'],
7963 ['fullCalcOnLoad', 'false'],
7964 ['fullPrecision', 'true'],
7965 ['iterate', 'false'],
7966 ['iterateCount', '100'],
7967 ['iterateDelta', '0.001'],
7968 ['refMode', 'A1']
7969];
7970
7971/* 18.2.3 (CT_CustomWorkbookView) Defaults */
7972/*var CustomWBViewDef = [
7973 ['autoUpdate', 'false'],
7974 ['changesSavedWin', 'false'],
7975 ['includeHiddenRowCol', 'true'],
7976 ['includePrintSettings', 'true'],
7977 ['maximized', 'false'],
7978 ['minimized', 'false'],
7979 ['onlySync', 'false'],
7980 ['personalView', 'false'],
7981 ['showComments', 'commIndicator'],
7982 ['showFormulaBar', 'true'],
7983 ['showHorizontalScroll', 'true'],
7984 ['showObjects', 'all'],
7985 ['showSheetTabs', 'true'],
7986 ['showStatusbar', 'true'],
7987 ['showVerticalScroll', 'true'],
7988 ['tabRatio', '600'],
7989 ['xWindow', '0'],
7990 ['yWindow', '0']
7991];*/
7992
7993function push_defaults_array(target, defaults) {
7994 for(var j = 0; j != target.length; ++j) { var w = target[j];
7995 for(var i=0; i != defaults.length; ++i) { var z = defaults[i];
7996 if(w[z[0]] == null) w[z[0]] = z[1];
7997 else switch(z[2]) {
7998 case "bool": if(typeof w[z[0]] == "string") w[z[0]] = parsexmlbool(w[z[0]]); break;
7999 case "int": if(typeof w[z[0]] == "string") w[z[0]] = parseInt(w[z[0]], 10); break;
8000 }
8001 }
8002 }
8003}
8004function push_defaults(target, defaults) {
8005 for(var i = 0; i != defaults.length; ++i) { var z = defaults[i];
8006 if(target[z[0]] == null) target[z[0]] = z[1];
8007 else switch(z[2]) {
8008 case "bool": if(typeof target[z[0]] == "string") target[z[0]] = parsexmlbool(target[z[0]]); break;
8009 case "int": if(typeof target[z[0]] == "string") target[z[0]] = parseInt(target[z[0]], 10); break;
8010 }
8011 }
8012}
8013
8014function parse_wb_defaults(wb) {
8015 push_defaults(wb.WBProps, WBPropsDef);
8016 push_defaults(wb.CalcPr, CalcPrDef);
8017
8018 push_defaults_array(wb.WBView, WBViewDef);
8019 push_defaults_array(wb.Sheets, SheetDef);
8020
8021 _ssfopts.date1904 = parsexmlbool(wb.WBProps.date1904);
8022}
8023
8024function safe1904(wb) {
8025 /* TODO: store date1904 somewhere else */
8026 if(!wb.Workbook) return "false";
8027 if(!wb.Workbook.WBProps) return "false";
8028 return parsexmlbool(wb.Workbook.WBProps.date1904) ? "true" : "false";
8029}
8030
8031var badchars = "][*?\/\\".split("");
8032function check_ws_name(n, safe) {
8033 if(n.length > 31) { if(safe) return false; throw new Error("Sheet names cannot exceed 31 chars"); }
8034 var _good = true;
8035 badchars.forEach(function(c) {
8036 if(n.indexOf(c) == -1) return;
8037 if(!safe) throw new Error("Sheet name cannot contain : \\ / ? * [ ]");
8038 _good = false;
8039 });
8040 return _good;
8041}
8042function check_wb_names(N, S, codes) {
8043 N.forEach(function(n,i) {
8044 check_ws_name(n);
8045 for(var j = 0; j < i; ++j) if(n == N[j]) throw new Error("Duplicate Sheet Name: " + n);
8046 if(codes) {
8047 var cn = (S && S[i] && S[i].CodeName) || n;
8048 if(cn.charCodeAt(0) == 95 && cn.length > 22) throw new Error("Bad Code Name: Worksheet" + cn);
8049 }
8050 });
8051}
8052function check_wb(wb) {
8053 if(!wb || !wb.SheetNames || !wb.Sheets) throw new Error("Invalid Workbook");
8054 if(!wb.SheetNames.length) throw new Error("Workbook is empty");
8055 var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
8056 check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
8057 for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
8058 /* TODO: validate workbook */
8059}
8060/* 18.2 Workbook */
8061var wbnsregex = /<\w+:workbook/;
8062function parse_wb_xml(data, opts) {
8063 if(!data) throw new Error("Could not find file");
8064 var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" };
8065 var pass = false, xmlns = "xmlns";
8066 var dname = {}, dnstart = 0;
8067 data.replace(tagregex, function xml_wb(x, idx) {
8068 var y = parsexmltag(x);
8069 switch(strip_ns(y[0])) {
8070 case '<?xml': break;
8071
8072 /* 18.2.27 workbook CT_Workbook 1 */
8073 case '<workbook':
8074 if(x.match(wbnsregex)) xmlns = "xmlns" + x.match(/<(\w+):/)[1];
8075 wb.xmlns = y[xmlns];
8076 break;
8077 case '</workbook>': break;
8078
8079 /* 18.2.13 fileVersion CT_FileVersion ? */
8080 case '<fileVersion': delete y[0]; wb.AppVersion = y; break;
8081 case '<fileVersion/>': case '</fileVersion>': break;
8082
8083 /* 18.2.12 fileSharing CT_FileSharing ? */
8084 case '<fileSharing':
8085 break;
8086 case '<fileSharing/>': break;
8087
8088 /* 18.2.28 workbookPr CT_WorkbookPr ? */
8089 case '<workbookPr':
8090 case '<workbookPr/>':
8091 WBPropsDef.forEach(function(w) {
8092 if(y[w[0]] == null) return;
8093 switch(w[2]) {
8094 case "bool": wb.WBProps[w[0]] = parsexmlbool(y[w[0]]); break;
8095 case "int": wb.WBProps[w[0]] = parseInt(y[w[0]], 10); break;
8096 default: wb.WBProps[w[0]] = y[w[0]];
8097 }
8098 });
8099 if(y.codeName) wb.WBProps.CodeName = utf8read(y.codeName);
8100 break;
8101 case '</workbookPr>': break;
8102
8103 /* 18.2.29 workbookProtection CT_WorkbookProtection ? */
8104 case '<workbookProtection':
8105 break;
8106 case '<workbookProtection/>': break;
8107
8108 /* 18.2.1 bookViews CT_BookViews ? */
8109 case '<bookViews': case '<bookViews>': case '</bookViews>': break;
8110 /* 18.2.30 workbookView CT_BookView + */
8111 case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
8112 case '</workbookView>': break;
8113
8114 /* 18.2.20 sheets CT_Sheets 1 */
8115 case '<sheets': case '<sheets>': case '</sheets>': break; // aggregate sheet
8116 /* 18.2.19 sheet CT_Sheet + */
8117 case '<sheet':
8118 switch(y.state) {
8119 case "hidden": y.Hidden = 1; break;
8120 case "veryHidden": y.Hidden = 2; break;
8121 default: y.Hidden = 0;
8122 }
8123 delete y.state;
8124 y.name = unescapexml(utf8read(y.name));
8125 delete y[0]; wb.Sheets.push(y); break;
8126 case '</sheet>': break;
8127
8128 /* 18.2.15 functionGroups CT_FunctionGroups ? */
8129 case '<functionGroups': case '<functionGroups/>': break;
8130 /* 18.2.14 functionGroup CT_FunctionGroup + */
8131 case '<functionGroup': break;
8132
8133 /* 18.2.9 externalReferences CT_ExternalReferences ? */
8134 case '<externalReferences': case '</externalReferences>': case '<externalReferences>': break;
8135 /* 18.2.8 externalReference CT_ExternalReference + */
8136 case '<externalReference': break;
8137
8138 /* 18.2.6 definedNames CT_DefinedNames ? */
8139 case '<definedNames/>': break;
8140 case '<definedNames>': case '<definedNames': pass=true; break;
8141 case '</definedNames>': pass=false; break;
8142 /* 18.2.5 definedName CT_DefinedName + */
8143 case '<definedName': {
8144 dname = {};
8145 dname.Name = utf8read(y.name);
8146 if(y.comment) dname.Comment = y.comment;
8147 if(y.localSheetId) dname.Sheet = +y.localSheetId;
8148 if(parsexmlbool(y.hidden||"0")) dname.Hidden = true;
8149 dnstart = idx + x.length;
8150 } break;
8151 case '</definedName>': {
8152 dname.Ref = unescapexml(utf8read(data.slice(dnstart, idx)));
8153 wb.Names.push(dname);
8154 } break;
8155 case '<definedName/>': break;
8156
8157 /* 18.2.2 calcPr CT_CalcPr ? */
8158 case '<calcPr': delete y[0]; wb.CalcPr = y; break;
8159 case '<calcPr/>': delete y[0]; wb.CalcPr = y; break;
8160 case '</calcPr>': break;
8161
8162 /* 18.2.16 oleSize CT_OleSize ? (ref required) */
8163 case '<oleSize': break;
8164
8165 /* 18.2.4 customWorkbookViews CT_CustomWorkbookViews ? */
8166 case '<customWorkbookViews>': case '</customWorkbookViews>': case '<customWorkbookViews': break;
8167 /* 18.2.3 customWorkbookView CT_CustomWorkbookView + */
8168 case '<customWorkbookView': case '</customWorkbookView>': break;
8169
8170 /* 18.2.18 pivotCaches CT_PivotCaches ? */
8171 case '<pivotCaches>': case '</pivotCaches>': case '<pivotCaches': break;
8172 /* 18.2.17 pivotCache CT_PivotCache ? */
8173 case '<pivotCache': break;
8174
8175 /* 18.2.21 smartTagPr CT_SmartTagPr ? */
8176 case '<smartTagPr': case '<smartTagPr/>': break;
8177
8178 /* 18.2.23 smartTagTypes CT_SmartTagTypes ? */
8179 case '<smartTagTypes': case '<smartTagTypes>': case '</smartTagTypes>': break;
8180 /* 18.2.22 smartTagType CT_SmartTagType ? */
8181 case '<smartTagType': break;
8182
8183 /* 18.2.24 webPublishing CT_WebPublishing ? */
8184 case '<webPublishing': case '<webPublishing/>': break;
8185
8186 /* 18.2.11 fileRecoveryPr CT_FileRecoveryPr ? */
8187 case '<fileRecoveryPr': case '<fileRecoveryPr/>': break;
8188
8189 /* 18.2.26 webPublishObjects CT_WebPublishObjects ? */
8190 case '<webPublishObjects>': case '<webPublishObjects': case '</webPublishObjects>': break;
8191 /* 18.2.25 webPublishObject CT_WebPublishObject ? */
8192 case '<webPublishObject': break;
8193
8194 /* 18.2.10 extLst CT_ExtensionList ? */
8195 case '<extLst': case '<extLst>': case '</extLst>': case '<extLst/>': break;
8196 /* 18.2.7 ext CT_Extension + */
8197 case '<ext': pass=true; break; //TODO: check with versions of excel
8198 case '</ext>': pass=false; break;
8199
8200 /* Others */
8201 case '<ArchID': break;
8202 case '<AlternateContent':
8203 case '<AlternateContent>': pass=true; break;
8204 case '</AlternateContent>': pass=false; break;
8205
8206 /* TODO */
8207 case '<revisionPtr': break;
8208
8209 default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in workbook');
8210 }
8211 return x;
8212 });
8213 if(XMLNS.main.indexOf(wb.xmlns) === -1) throw new Error("Unknown Namespace: " + wb.xmlns);
8214
8215 parse_wb_defaults(wb);
8216
8217 return wb;
8218}
8219
8220var WB_XML_ROOT = writextag('workbook', null, {
8221 'xmlns': XMLNS.main[0],
8222 //'xmlns:mx': XMLNS.mx,
8223 //'xmlns:s': XMLNS.main[0],
8224 'xmlns:r': XMLNS.r
8225});
8226
8227function write_wb_xml(wb) {
8228 var o = [XML_HEADER];
8229 o[o.length] = WB_XML_ROOT;
8230
8231 var write_names = (wb.Workbook && (wb.Workbook.Names||[]).length > 0);
8232
8233 /* fileVersion */
8234 /* fileSharing */
8235
8236 var workbookPr = ({codeName:"ThisWorkbook"});
8237 if(wb.Workbook && wb.Workbook.WBProps) {
8238 WBPropsDef.forEach(function(x) {
8239if((wb.Workbook.WBProps[x[0]]) == null) return;
8240 if((wb.Workbook.WBProps[x[0]]) == x[1]) return;
8241 workbookPr[x[0]] = (wb.Workbook.WBProps[x[0]]);
8242 });
8243if(wb.Workbook.WBProps.CodeName) { workbookPr.codeName = wb.Workbook.WBProps.CodeName; delete workbookPr.CodeName; }
8244 }
8245 o[o.length] = (writextag('workbookPr', null, workbookPr));
8246
8247 /* workbookProtection */
8248
8249 var sheets = wb.Workbook && wb.Workbook.Sheets || [];
8250 var i = 0;
8251
8252 /* bookViews only written if first worksheet is hidden */
8253 if(sheets && sheets[0] && !!sheets[0].Hidden) {
8254 o[o.length] = "<bookViews>";
8255 for(i = 0; i != wb.SheetNames.length; ++i) {
8256 if(!sheets[i]) break;
8257 if(!sheets[i].Hidden) break;
8258 }
8259 if(i == wb.SheetNames.length) i = 0;
8260 o[o.length] = '<workbookView firstSheet="' + i + '" activeTab="' + i + '"/>';
8261 o[o.length] = "</bookViews>";
8262 }
8263
8264 o[o.length] = "<sheets>";
8265 for(i = 0; i != wb.SheetNames.length; ++i) {
8266 var sht = ({name:escapexml(wb.SheetNames[i].slice(0,31))});
8267 sht.sheetId = ""+(i+1);
8268 sht["r:id"] = "rId"+(i+1);
8269 if(sheets[i]) switch(sheets[i].Hidden) {
8270 case 1: sht.state = "hidden"; break;
8271 case 2: sht.state = "veryHidden"; break;
8272 }
8273 o[o.length] = (writextag('sheet',null,sht));
8274 }
8275 o[o.length] = "</sheets>";
8276
8277 /* functionGroups */
8278 /* externalReferences */
8279
8280 if(write_names) {
8281 o[o.length] = "<definedNames>";
8282 if(wb.Workbook && wb.Workbook.Names) wb.Workbook.Names.forEach(function(n) {
8283 var d = {name:n.Name};
8284 if(n.Comment) d.comment = n.Comment;
8285 if(n.Sheet != null) d.localSheetId = ""+n.Sheet;
8286 if(n.Hidden) d.hidden = "1";
8287 if(!n.Ref) return;
8288 o[o.length] = writextag('definedName', escapexml(n.Ref), d);
8289 });
8290 o[o.length] = "</definedNames>";
8291 }
8292
8293 /* calcPr */
8294 /* oleSize */
8295 /* customWorkbookViews */
8296 /* pivotCaches */
8297 /* smartTagPr */
8298 /* smartTagTypes */
8299 /* webPublishing */
8300 /* fileRecoveryPr */
8301 /* webPublishObjects */
8302 /* extLst */
8303
8304 if(o.length>2){ o[o.length] = '</workbook>'; o[1]=o[1].replace("/>",">"); }
8305 return o.join("");
8306}
8307function parse_wb(data, name, opts) {
8308 if(name.slice(-4)===".bin") return parse_wb_bin((data), opts);
8309 return parse_wb_xml((data), opts);
8310}
8311
8312function parse_ws(data, name, idx, opts, rels, wb, themes, styles) {
8313 if(name.slice(-4)===".bin") return parse_ws_bin((data), opts, idx, rels, wb, themes, styles);
8314 return parse_ws_xml((data), opts, idx, rels, wb, themes, styles);
8315}
8316
8317function parse_cs(data, name, idx, opts, rels, wb, themes, styles) {
8318 if(name.slice(-4)===".bin") return parse_cs_bin((data), opts, idx, rels, wb, themes, styles);
8319 return parse_cs_xml((data), opts, idx, rels, wb, themes, styles);
8320}
8321
8322function parse_ms(data, name, idx, opts, rels, wb, themes, styles) {
8323 if(name.slice(-4)===".bin") return parse_ms_bin((data), opts, idx, rels, wb, themes, styles);
8324 return parse_ms_xml((data), opts, idx, rels, wb, themes, styles);
8325}
8326
8327function parse_ds(data, name, idx, opts, rels, wb, themes, styles) {
8328 if(name.slice(-4)===".bin") return parse_ds_bin((data), opts, idx, rels, wb, themes, styles);
8329 return parse_ds_xml((data), opts, idx, rels, wb, themes, styles);
8330}
8331
8332function parse_sty(data, name, themes, opts) {
8333 if(name.slice(-4)===".bin") return parse_sty_bin((data), themes, opts);
8334 return parse_sty_xml((data), themes, opts);
8335}
8336
8337function parse_theme(data, name, opts) {
8338 return parse_theme_xml(data, opts);
8339}
8340
8341function parse_sst(data, name, opts) {
8342 if(name.slice(-4)===".bin") return parse_sst_bin((data), opts);
8343 return parse_sst_xml((data), opts);
8344}
8345
8346function parse_cmnt(data, name, opts) {
8347 if(name.slice(-4)===".bin") return parse_comments_bin((data), opts);
8348 return parse_comments_xml((data), opts);
8349}
8350
8351function parse_cc(data, name, opts) {
8352 if(name.slice(-4)===".bin") return parse_cc_bin((data), name, opts);
8353 return parse_cc_xml((data), name, opts);
8354}
8355
8356function parse_xlink(data, rel, name, opts) {
8357 if(name.slice(-4)===".bin") return parse_xlink_bin((data), rel, name, opts);
8358 return parse_xlink_xml((data), rel, name, opts);
8359}
8360
8361function write_wb(wb, name, opts) {
8362 return (name.slice(-4)===".bin" ? write_wb_bin : write_wb_xml)(wb, opts);
8363}
8364
8365function write_ws(data, name, opts, wb, rels) {
8366 return (name.slice(-4)===".bin" ? write_ws_bin : write_ws_xml)(data, opts, wb, rels);
8367}
8368
8369// eslint-disable-next-line no-unused-vars
8370function write_cs(data, name, opts, wb, rels) {
8371 return (name.slice(-4)===".bin" ? write_cs_bin : write_cs_xml)(data, opts, wb, rels);
8372}
8373
8374function write_sty(data, name, opts) {
8375 return (name.slice(-4)===".bin" ? write_sty_bin : write_sty_xml)(data, opts);
8376}
8377
8378function write_sst(data, name, opts) {
8379 return (name.slice(-4)===".bin" ? write_sst_bin : write_sst_xml)(data, opts);
8380}
8381
8382function write_cmnt(data, name, opts) {
8383 return (name.slice(-4)===".bin" ? write_comments_bin : write_comments_xml)(data, opts);
8384}
8385/*
8386function write_cc(data, name:string, opts) {
8387 return (name.slice(-4)===".bin" ? write_cc_bin : write_cc_xml)(data, opts);
8388}
8389*/
8390/* note: browser DOM element cannot see mso- style attrs, must parse */
8391var HTML_ = (function() {
8392 function html_to_sheet(str, _opts) {
8393 var opts = _opts || {};
8394 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
8395 var ws = opts.dense ? ([]) : ({});
8396 str = str.replace(/<!--.*?-->/g, "");
8397 var mtch = str.match(/<table/i);
8398 if(!mtch) throw new Error("Invalid HTML: could not find <table>");
8399 var mtch2 = str.match(/<\/table/i);
8400 var i = mtch.index, j = mtch2 && mtch2.index || str.length;
8401 var rows = split_regex(str.slice(i, j), /(:?<tr[^>]*>)/i, "<tr>");
8402 var R = -1, C = 0, RS = 0, CS = 0;
8403 var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}};
8404 var merges = [];
8405 for(i = 0; i < rows.length; ++i) {
8406 var row = rows[i].trim();
8407 var hd = row.slice(0,3).toLowerCase();
8408 if(hd == "<tr") { ++R; if(opts.sheetRows && opts.sheetRows <= R) { --R; break; } C = 0; continue; }
8409 if(hd != "<td" && hd != "<th") continue;
8410 var cells = row.split(/<\/t[dh]>/i);
8411 for(j = 0; j < cells.length; ++j) {
8412 var cell = cells[j].trim();
8413 if(!cell.match(/<t[dh]/i)) continue;
8414 var m = cell, cc = 0;
8415 /* TODO: parse styles etc */
8416 while(m.charAt(0) == "<" && (cc = m.indexOf(">")) > -1) m = m.slice(cc+1);
8417 for(var midx = 0; midx < merges.length; ++midx) {
8418 var _merge = merges[midx];
8419 if(_merge.s.c == C && _merge.s.r < R && R <= _merge.e.r) { C = _merge.e.c + 1; midx = -1; }
8420 }
8421 var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
8422 CS = tag.colspan ? +tag.colspan : 1;
8423 if((RS = +tag.rowspan)>1 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
8424 var _t = tag.t || "";
8425 /* TODO: generate stub cells */
8426 if(!m.length) { C += CS; continue; }
8427 m = htmldecode(m);
8428 if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
8429 if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
8430 if(!m.length) continue;
8431 var o = {t:'s', v:m};
8432 if(opts.raw || !m.trim().length || _t == 's'){}
8433 else if(m === 'TRUE') o = {t:'b', v:true};
8434 else if(m === 'FALSE') o = {t:'b', v:false};
8435 else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
8436 else if(!isNaN(fuzzydate(m).getDate())) {
8437 o = ({t:'d', v:parseDate(m)});
8438 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
8439 o.z = opts.dateNF || SSF._table[14];
8440 }
8441 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
8442 else ws[encode_cell({r:R, c:C})] = o;
8443 C += CS;
8444 }
8445 }
8446 ws['!ref'] = encode_range(range);
8447 if(merges.length) ws["!merges"] = merges;
8448 return ws;
8449 }
8450 function html_to_book(str, opts) {
8451 return sheet_to_workbook(html_to_sheet(str, opts), opts);
8452 }
8453 function make_html_row(ws, r, R, o) {
8454 var M = (ws['!merges'] ||[]);
8455 var oo = [];
8456 for(var C = r.s.c; C <= r.e.c; ++C) {
8457 var RS = 0, CS = 0;
8458 for(var j = 0; j < M.length; ++j) {
8459 if(M[j].s.r > R || M[j].s.c > C) continue;
8460 if(M[j].e.r < R || M[j].e.c < C) continue;
8461 if(M[j].s.r < R || M[j].s.c < C) { RS = -1; break; }
8462 RS = M[j].e.r - M[j].s.r + 1; CS = M[j].e.c - M[j].s.c + 1; break;
8463 }
8464 if(RS < 0) continue;
8465 var coord = encode_cell({r:R,c:C});
8466 var cell = o.dense ? (ws[R]||[])[C] : ws[coord];
8467 /* TODO: html entities */
8468 var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
8469 var sp = ({});
8470 if(RS > 1) sp.rowspan = RS;
8471 if(CS > 1) sp.colspan = CS;
8472 sp.t = cell && cell.t || 'z';
8473 if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
8474 sp.id = (o.id || "sjs") + "-" + coord;
8475 if(sp.t != "z") { sp.v = cell.v; if(cell.z != null) sp.z = cell.z; }
8476 oo.push(writextag('td', w, sp));
8477 }
8478 var preamble = "<tr>";
8479 return preamble + oo.join("") + "</tr>";
8480 }
8481 function make_html_preamble(ws, R, o) {
8482 var out = [];
8483 return out.join("") + '<table' + (o && o.id ? ' id="' + o.id + '"' : "") + '>';
8484 }
8485 var _BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
8486 var _END = '</body></html>';
8487 function sheet_to_html(ws, opts/*, wb:?Workbook*/) {
8488 var o = opts || {};
8489 var header = o.header != null ? o.header : _BEGIN;
8490 var footer = o.footer != null ? o.footer : _END;
8491 var out = [header];
8492 var r = decode_range(ws['!ref']);
8493 o.dense = Array.isArray(ws);
8494 out.push(make_html_preamble(ws, r, o));
8495 for(var R = r.s.r; R <= r.e.r; ++R) out.push(make_html_row(ws, r, R, o));
8496 out.push("</table>" + footer);
8497 return out.join("");
8498
8499 }
8500 return {
8501 to_workbook: html_to_book,
8502 to_sheet: html_to_sheet,
8503 _row: make_html_row,
8504 BEGIN: _BEGIN,
8505 END: _END,
8506 _preamble: make_html_preamble,
8507 from_sheet: sheet_to_html
8508 };
8509})();
8510
8511function sheet_add_dom(ws, table, _opts) {
8512 var opts = _opts || {};
8513 if(DENSE != null) opts.dense = DENSE;
8514 var or_R = 0, or_C = 0;
8515 if(opts.origin != null) {
8516 if(typeof opts.origin == 'number') or_R = opts.origin;
8517 else {
8518 var _origin = typeof opts.origin == "string" ? decode_cell(opts.origin) : opts.origin;
8519 or_R = _origin.r; or_C = _origin.c;
8520 }
8521 }
8522 var rows = table.getElementsByTagName('tr');
8523 var sheetRows = Math.min(opts.sheetRows||10000000, rows.length);
8524 var range = {s:{r:0,c:0},e:{r:or_R,c:or_C}};
8525 if(ws["!ref"]) {
8526 var _range = decode_range(ws["!ref"]);
8527 range.s.r = Math.min(range.s.r, _range.s.r);
8528 range.s.c = Math.min(range.s.c, _range.s.c);
8529 range.e.r = Math.max(range.e.r, _range.e.r);
8530 range.e.c = Math.max(range.e.c, _range.e.c);
8531 if(or_R == -1) range.e.r = or_R = _range.e.r + 1;
8532 }
8533 var merges = [], midx = 0;
8534 var rowinfo = ws["!rows"] || (ws["!rows"] = []);
8535 var _R = 0, R = 0, _C = 0, C = 0, RS = 0, CS = 0;
8536 if(!ws["!cols"]) ws['!cols'] = [];
8537 for(; _R < rows.length && R < sheetRows; ++_R) {
8538 var row = rows[_R];
8539 if (is_dom_element_hidden(row)) {
8540 if (opts.display) continue;
8541 rowinfo[R] = {hidden: true};
8542 }
8543 var elts = (row.children);
8544 for(_C = C = 0; _C < elts.length; ++_C) {
8545 var elt = elts[_C];
8546 if (opts.display && is_dom_element_hidden(elt)) continue;
8547 var v = elt.hasAttribute('v') ? elt.getAttribute('v') : htmldecode(elt.innerHTML);
8548 var z = elt.getAttribute('z');
8549 for(midx = 0; midx < merges.length; ++midx) {
8550 var m = merges[midx];
8551 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; }
8552 }
8553 /* TODO: figure out how to extract nonstandard mso- style */
8554 CS = +elt.getAttribute("colspan") || 1;
8555 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}});
8556 var o = {t:'s', v:v};
8557 var _t = elt.getAttribute("t") || "";
8558 if(v != null) {
8559 if(v.length == 0) o.t = _t || 'z';
8560 else if(opts.raw || v.trim().length == 0 || _t == "s"){}
8561 else if(v === 'TRUE') o = {t:'b', v:true};
8562 else if(v === 'FALSE') o = {t:'b', v:false};
8563 else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
8564 else if(!isNaN(fuzzydate(v).getDate())) {
8565 o = ({t:'d', v:parseDate(v)});
8566 if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
8567 o.z = opts.dateNF || SSF._table[14];
8568 }
8569 }
8570 if(o.z === undefined && z != null) o.z = z;
8571 if(opts.dense) { if(!ws[R + or_R]) ws[R + or_R] = []; ws[R + or_R][C + or_C] = o; }
8572 else ws[encode_cell({c:C + or_C, r:R + or_R})] = o;
8573 if(range.e.c < C + or_C) range.e.c = C + or_C;
8574 C += CS;
8575 }
8576 ++R;
8577 }
8578 if(merges.length) ws['!merges'] = (ws["!merges"] || []).concat(merges);
8579 range.e.r = Math.max(range.e.r, R - 1 + or_R);
8580 ws['!ref'] = encode_range(range);
8581 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
8582 return ws;
8583}
8584
8585function parse_dom_table(table, _opts) {
8586 var opts = _opts || {};
8587 var ws = opts.dense ? ([]) : ({});
8588 return sheet_add_dom(ws, table, _opts);
8589}
8590
8591function table_to_book(table, opts) {
8592 return sheet_to_workbook(parse_dom_table(table, opts), opts);
8593}
8594
8595function is_dom_element_hidden(element) {
8596 var display = '';
8597 var get_computed_style = get_get_computed_style_function(element);
8598 if(get_computed_style) display = get_computed_style(element).getPropertyValue('display');
8599 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)
8600 return display === 'none';
8601}
8602
8603/* global getComputedStyle */
8604function get_get_computed_style_function(element) {
8605 // The proper getComputedStyle implementation is the one defined in the element window
8606 if(element.ownerDocument.defaultView && typeof element.ownerDocument.defaultView.getComputedStyle === 'function') return element.ownerDocument.defaultView.getComputedStyle;
8607 // If it is not available, try to get one from the global namespace
8608 if(typeof getComputedStyle === 'function') return getComputedStyle;
8609 return null;
8610}
8611/* OpenDocument */
8612var parse_content_xml = (function() {
8613
8614 var parse_text_p = function(text) {
8615 /* 6.1.2 White Space Characters */
8616 var fixed = text
8617 .replace(/[\t\r\n]/g, " ").trim().replace(/ +/g, " ")
8618 .replace(/<text:s\/>/g," ")
8619 .replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
8620 .replace(/<text:tab[^>]*\/>/g,"\t")
8621 .replace(/<text:line-break\/>/g,"\n");
8622 var v = unescapexml(fixed.replace(/<[^>]*>/g,""));
8623
8624 return [v];
8625 };
8626
8627 var number_formats = {
8628 /* ods name: [short ssf fmt, long ssf fmt] */
8629 day: ["d", "dd"],
8630 month: ["m", "mm"],
8631 year: ["y", "yy"],
8632 hours: ["h", "hh"],
8633 minutes: ["m", "mm"],
8634 seconds: ["s", "ss"],
8635 "am-pm": ["A/P", "AM/PM"],
8636 "day-of-week": ["ddd", "dddd"],
8637 era: ["e", "ee"],
8638 /* there is no native representation of LO "Q" format */
8639 quarter: ["\\Qm", "m\\\"th quarter\""]
8640 };
8641
8642 return function pcx(d, _opts) {
8643 var opts = _opts || {};
8644 if(DENSE != null && opts.dense == null) opts.dense = DENSE;
8645 var str = xlml_normalize(d);
8646 var state = [], tmp;
8647 var tag;
8648 var NFtag = {name:""}, NF = "", pidx = 0;
8649 var sheetag;
8650 var rowtag;
8651 var Sheets = {}, SheetNames = [];
8652 var ws = opts.dense ? ([]) : ({});
8653 var Rn, q;
8654 var ctag = ({value:""});
8655 var textp = "", textpidx = 0, textptag;
8656 var textR = [];
8657 var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
8658 var row_ol = 0;
8659 var number_format_map = {};
8660 var merges = [], mrange = {}, mR = 0, mC = 0;
8661 var rowinfo = [], rowpeat = 1, colpeat = 1;
8662 var arrayf = [];
8663 var WB = {Names:[]};
8664 var atag = ({});
8665 var _Ref = ["", ""];
8666 var comments = [], comment = ({});
8667 var creator = "", creatoridx = 0;
8668 var isstub = false, intable = false;
8669 var i = 0;
8670 xlmlregex.lastIndex = 0;
8671 str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
8672 while((Rn = xlmlregex.exec(str))) switch((Rn[3]=Rn[3].replace(/_.*$/,""))) {
8673
8674 case 'table': case '工作表': // 9.1.2 <table:table>
8675 if(Rn[1]==='/') {
8676 if(range.e.c >= range.s.c && range.e.r >= range.s.r) ws['!ref'] = encode_range(range);
8677 else ws['!ref'] = "A1:A1";
8678 if(opts.sheetRows > 0 && opts.sheetRows <= range.e.r) {
8679 ws['!fullref'] = ws['!ref'];
8680 range.e.r = opts.sheetRows - 1;
8681 ws['!ref'] = encode_range(range);
8682 }
8683 if(merges.length) ws['!merges'] = merges;
8684 if(rowinfo.length) ws["!rows"] = rowinfo;
8685 sheetag.name = sheetag['名称'] || sheetag.name;
8686 if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
8687 SheetNames.push(sheetag.name);
8688 Sheets[sheetag.name] = ws;
8689 intable = false;
8690 }
8691 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
8692 sheetag = parsexmltag(Rn[0], false);
8693 R = C = -1;
8694 range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
8695 ws = opts.dense ? ([]) : ({}); merges = [];
8696 rowinfo = [];
8697 intable = true;
8698 }
8699 break;
8700
8701 case 'table-row-group': // 9.1.9 <table:table-row-group>
8702 if(Rn[1] === "/") --row_ol; else ++row_ol;
8703 break;
8704 case 'table-row': case '行': // 9.1.3 <table:table-row>
8705 if(Rn[1] === '/') { R+=rowpeat; rowpeat = 1; break; }
8706 rowtag = parsexmltag(Rn[0], false);
8707 if(rowtag['行号']) R = rowtag['行号'] - 1; else if(R == -1) R = 0;
8708 rowpeat = +rowtag['number-rows-repeated'] || 1;
8709 /* TODO: remove magic */
8710 if(rowpeat < 10) for(i = 0; i < rowpeat; ++i) if(row_ol > 0) rowinfo[R + i] = {level: row_ol};
8711 C = -1; break;
8712 case 'covered-table-cell': // 9.1.5 <table:covered-table-cell>
8713 if(Rn[1] !== '/') ++C;
8714 if(opts.sheetStubs) {
8715 if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = {t:'z'}; }
8716 else ws[encode_cell({r:R,c:C})] = {t:'z'};
8717 }
8718 textp = ""; textR = [];
8719 break; /* stub */
8720 case 'table-cell': case '数据':
8721 if(Rn[0].charAt(Rn[0].length-2) === '/') {
8722 ++C;
8723 ctag = parsexmltag(Rn[0], false);
8724 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
8725 q = ({t:'z', v:null});
8726 if(ctag.formula && opts.cellFormula != false) q.f = ods_to_csf_formula(unescapexml(ctag.formula));
8727 if((ctag['数据类型'] || ctag['value-type']) == "string") {
8728 q.t = "s"; q.v = unescapexml(ctag['string-value'] || "");
8729 if(opts.dense) {
8730 if(!ws[R]) ws[R] = [];
8731 ws[R][C] = q;
8732 } else {
8733 ws[encode_cell({r:R,c:C})] = q;
8734 }
8735 }
8736 C+= colpeat-1;
8737 } else if(Rn[1]!=='/') {
8738 ++C;
8739 colpeat = 1;
8740 var rptR = rowpeat ? R + rowpeat - 1 : R;
8741 if(C > range.e.c) range.e.c = C;
8742 if(C < range.s.c) range.s.c = C;
8743 if(R < range.s.r) range.s.r = R;
8744 if(rptR > range.e.r) range.e.r = rptR;
8745 ctag = parsexmltag(Rn[0], false);
8746 comments = []; comment = ({});
8747 q = ({t:ctag['数据类型'] || ctag['value-type'], v:null});
8748 if(opts.cellFormula) {
8749 if(ctag.formula) ctag.formula = unescapexml(ctag.formula);
8750 if(ctag['number-matrix-columns-spanned'] && ctag['number-matrix-rows-spanned']) {
8751 mR = parseInt(ctag['number-matrix-rows-spanned'],10) || 0;
8752 mC = parseInt(ctag['number-matrix-columns-spanned'],10) || 0;
8753 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
8754 q.F = encode_range(mrange);
8755 arrayf.push([mrange, q.F]);
8756 }
8757 if(ctag.formula) q.f = ods_to_csf_formula(ctag.formula);
8758 else for(i = 0; i < arrayf.length; ++i)
8759 if(R >= arrayf[i][0].s.r && R <= arrayf[i][0].e.r)
8760 if(C >= arrayf[i][0].s.c && C <= arrayf[i][0].e.c)
8761 q.F = arrayf[i][1];
8762 }
8763 if(ctag['number-columns-spanned'] || ctag['number-rows-spanned']) {
8764 mR = parseInt(ctag['number-rows-spanned'],10) || 0;
8765 mC = parseInt(ctag['number-columns-spanned'],10) || 0;
8766 mrange = {s: {r:R,c:C}, e:{r:R + mR-1,c:C + mC-1}};
8767 merges.push(mrange);
8768 }
8769
8770 /* 19.675.2 table:number-columns-repeated */
8771 if(ctag['number-columns-repeated']) colpeat = parseInt(ctag['number-columns-repeated'], 10);
8772
8773 /* 19.385 office:value-type */
8774 switch(q.t) {
8775 case 'boolean': q.t = 'b'; q.v = parsexmlbool(ctag['boolean-value']); break;
8776 case 'float': q.t = 'n'; q.v = parseFloat(ctag.value); break;
8777 case 'percentage': q.t = 'n'; q.v = parseFloat(ctag.value); break;
8778 case 'currency': q.t = 'n'; q.v = parseFloat(ctag.value); break;
8779 case 'date': q.t = 'd'; q.v = parseDate(ctag['date-value']);
8780 if(!opts.cellDates) { q.t = 'n'; q.v = datenum(q.v); }
8781 q.z = 'm/d/yy'; break;
8782 case 'time': q.t = 'n'; q.v = parse_isodur(ctag['time-value'])/86400; break;
8783 case 'number': q.t = 'n'; q.v = parseFloat(ctag['数据数值']); break;
8784 default:
8785 if(q.t === 'string' || q.t === 'text' || !q.t) {
8786 q.t = 's';
8787 if(ctag['string-value'] != null) { textp = unescapexml(ctag['string-value']); textR = []; }
8788 } else throw new Error('Unsupported value type ' + q.t);
8789 }
8790 } else {
8791 isstub = false;
8792 if(q.t === 's') {
8793 q.v = textp || '';
8794 if(textR.length) q.R = textR;
8795 isstub = textpidx == 0;
8796 }
8797 if(atag.Target) q.l = atag;
8798 if(comments.length > 0) { q.c = comments; comments = []; }
8799 if(textp && opts.cellText !== false) q.w = textp;
8800 if(isstub) { q.t = "z"; delete q.v; }
8801 if(!isstub || opts.sheetStubs) {
8802 if(!(opts.sheetRows && opts.sheetRows <= R)) {
8803 for(var rpt = 0; rpt < rowpeat; ++rpt) {
8804 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
8805 if(opts.dense) {
8806 if(!ws[R + rpt]) ws[R + rpt] = [];
8807 ws[R + rpt][C] = rpt == 0 ? q : dup(q);
8808 while(--colpeat > 0) ws[R + rpt][C + colpeat] = dup(q);
8809 } else {
8810 ws[encode_cell({r:R + rpt,c:C})] = q;
8811 while(--colpeat > 0) ws[encode_cell({r:R + rpt,c:C + colpeat})] = dup(q);
8812 }
8813 if(range.e.c <= C) range.e.c = C;
8814 }
8815 }
8816 }
8817 colpeat = parseInt(ctag['number-columns-repeated']||"1", 10);
8818 C += colpeat-1; colpeat = 0;
8819 q = {};
8820 textp = ""; textR = [];
8821 }
8822 atag = ({});
8823 break; // 9.1.4 <table:table-cell>
8824
8825 /* pure state */
8826 case 'document': // TODO: <office:document> is the root for FODS
8827 case 'document-content': case '电子表格文档': // 3.1.3.2 <office:document-content>
8828 case 'spreadsheet': case '主体': // 3.7 <office:spreadsheet>
8829 case 'scripts': // 3.12 <office:scripts>
8830 case 'styles': // TODO <office:styles>
8831 case 'font-face-decls': // 3.14 <office:font-face-decls>
8832 case 'master-styles': //3.15.4 <office:master-styles> -- relevant for FODS
8833 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
8834 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], true]);
8835 break;
8836
8837 case 'annotation': // 14.1 <office:annotation>
8838 if(Rn[1]==='/'){
8839 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
8840 comment.t = textp;
8841 if(textR.length) comment.R = textR;
8842 comment.a = creator;
8843 comments.push(comment);
8844 }
8845 else if(Rn[0].charAt(Rn[0].length-2) !== '/') {state.push([Rn[3], false]);}
8846 creator = ""; creatoridx = 0;
8847 textp = ""; textpidx = 0; textR = [];
8848 break;
8849
8850 case 'creator': // 4.3.2.7 <dc:creator>
8851 if(Rn[1]==='/') { creator = str.slice(creatoridx,Rn.index); }
8852 else creatoridx = Rn.index + Rn[0].length;
8853 break;
8854
8855 /* ignore state */
8856 case 'meta': case '元数据': // TODO: <office:meta> <uof:元数据> FODS/UOF
8857 case 'settings': // TODO: <office:settings>
8858 case 'config-item-set': // TODO: <office:config-item-set>
8859 case 'config-item-map-indexed': // TODO: <office:config-item-map-indexed>
8860 case 'config-item-map-entry': // TODO: <office:config-item-map-entry>
8861 case 'config-item-map-named': // TODO: <office:config-item-map-entry>
8862 case 'shapes': // 9.2.8 <table:shapes>
8863 case 'frame': // 10.4.2 <draw:frame>
8864 case 'text-box': // 10.4.3 <draw:text-box>
8865 case 'image': // 10.4.4 <draw:image>
8866 case 'data-pilot-tables': // 9.6.2 <table:data-pilot-tables>
8867 case 'list-style': // 16.30 <text:list-style>
8868 case 'form': // 13.13 <form:form>
8869 case 'dde-links': // 9.8 <table:dde-links>
8870 case 'event-listeners': // TODO
8871 case 'chart': // TODO
8872 if(Rn[1]==='/'){if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;}
8873 else if(Rn[0].charAt(Rn[0].length-2) !== '/') state.push([Rn[3], false]);
8874 textp = ""; textpidx = 0; textR = [];
8875 break;
8876
8877 case 'scientific-number': // TODO: <number:scientific-number>
8878 break;
8879 case 'currency-symbol': // TODO: <number:currency-symbol>
8880 break;
8881 case 'currency-style': // TODO: <number:currency-style>
8882 break;
8883 case 'number-style': // 16.27.2 <number:number-style>
8884 case 'percentage-style': // 16.27.9 <number:percentage-style>
8885 case 'date-style': // 16.27.10 <number:date-style>
8886 case 'time-style': // 16.27.18 <number:time-style>
8887 if(Rn[1]==='/'){
8888 number_format_map[NFtag.name] = NF;
8889 if((tmp=state.pop())[0]!==Rn[3]) throw "Bad state: "+tmp;
8890 } else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
8891 NF = "";
8892 NFtag = parsexmltag(Rn[0], false);
8893 state.push([Rn[3], true]);
8894 } break;
8895
8896 case 'script': break; // 3.13 <office:script>
8897 case 'libraries': break; // TODO: <ooo:libraries>
8898 case 'automatic-styles': break; // 3.15.3 <office:automatic-styles>
8899
8900 case 'default-style': // TODO: <style:default-style>
8901 case 'page-layout': break; // TODO: <style:page-layout>
8902 case 'style': // 16.2 <style:style>
8903 break;
8904 case 'map': break; // 16.3 <style:map>
8905 case 'font-face': break; // 16.21 <style:font-face>
8906
8907 case 'paragraph-properties': break; // 17.6 <style:paragraph-properties>
8908 case 'table-properties': break; // 17.15 <style:table-properties>
8909 case 'table-column-properties': break; // 17.16 <style:table-column-properties>
8910 case 'table-row-properties': break; // 17.17 <style:table-row-properties>
8911 case 'table-cell-properties': break; // 17.18 <style:table-cell-properties>
8912
8913 case 'number': // 16.27.3 <number:number>
8914 switch(state[state.length-1][0]) {
8915 case 'time-style':
8916 case 'date-style':
8917 tag = parsexmltag(Rn[0], false);
8918 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
8919 } break;
8920
8921 case 'fraction': break; // TODO 16.27.6 <number:fraction>
8922
8923 case 'day': // 16.27.11 <number:day>
8924 case 'month': // 16.27.12 <number:month>
8925 case 'year': // 16.27.13 <number:year>
8926 case 'era': // 16.27.14 <number:era>
8927 case 'day-of-week': // 16.27.15 <number:day-of-week>
8928 case 'week-of-year': // 16.27.16 <number:week-of-year>
8929 case 'quarter': // 16.27.17 <number:quarter>
8930 case 'hours': // 16.27.19 <number:hours>
8931 case 'minutes': // 16.27.20 <number:minutes>
8932 case 'seconds': // 16.27.21 <number:seconds>
8933 case 'am-pm': // 16.27.22 <number:am-pm>
8934 switch(state[state.length-1][0]) {
8935 case 'time-style':
8936 case 'date-style':
8937 tag = parsexmltag(Rn[0], false);
8938 NF += number_formats[Rn[3]][tag.style==='long'?1:0]; break;
8939 } break;
8940
8941 case 'boolean-style': break; // 16.27.23 <number:boolean-style>
8942 case 'boolean': break; // 16.27.24 <number:boolean>
8943 case 'text-style': break; // 16.27.25 <number:text-style>
8944 case 'text': // 16.27.26 <number:text>
8945 if(Rn[0].slice(-2) === "/>") break;
8946 else if(Rn[1]==="/") switch(state[state.length-1][0]) {
8947 case 'number-style':
8948 case 'date-style':
8949 case 'time-style':
8950 NF += str.slice(pidx, Rn.index);
8951 break;
8952 }
8953 else pidx = Rn.index + Rn[0].length;
8954 break;
8955
8956 case 'named-range': // 9.4.12 <table:named-range>
8957 tag = parsexmltag(Rn[0], false);
8958 _Ref = ods_to_csf_3D(tag['cell-range-address']);
8959 var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
8960 if(intable) nrange.Sheet = SheetNames.length;
8961 WB.Names.push(nrange);
8962 break;
8963
8964 case 'text-content': break; // 16.27.27 <number:text-content>
8965 case 'text-properties': break; // 16.27.27 <style:text-properties>
8966 case 'embedded-text': break; // 16.27.4 <number:embedded-text>
8967
8968 case 'body': case '电子表格': break; // 3.3 16.9.6 19.726.3
8969
8970 case 'forms': break; // 12.25.2 13.2
8971 case 'table-column': break; // 9.1.6 <table:table-column>
8972 case 'table-header-rows': break; // 9.1.7 <table:table-header-rows>
8973 case 'table-rows': break; // 9.1.12 <table:table-rows>
8974 /* TODO: outline levels */
8975 case 'table-column-group': break; // 9.1.10 <table:table-column-group>
8976 case 'table-header-columns': break; // 9.1.11 <table:table-header-columns>
8977 case 'table-columns': break; // 9.1.12 <table:table-columns>
8978
8979 case 'null-date': break; // 9.4.2 <table:null-date> TODO: date1904
8980
8981 case 'graphic-properties': break; // 17.21 <style:graphic-properties>
8982 case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
8983 case 'named-expressions': break; // 9.4.11 <table:named-expressions>
8984 case 'label-range': break; // 9.4.9 <table:label-range>
8985 case 'label-ranges': break; // 9.4.10 <table:label-ranges>
8986 case 'named-expression': break; // 9.4.13 <table:named-expression>
8987 case 'sort': break; // 9.4.19 <table:sort>
8988 case 'sort-by': break; // 9.4.20 <table:sort-by>
8989 case 'sort-groups': break; // 9.4.22 <table:sort-groups>
8990
8991 case 'tab': break; // 6.1.4 <text:tab>
8992 case 'line-break': break; // 6.1.5 <text:line-break>
8993 case 'span': break; // 6.1.7 <text:span>
8994 case 'p': case '文本串': // 5.1.3 <text:p>
8995 if(['master-styles'].indexOf(state[state.length-1][0]) > -1) break;
8996 if(Rn[1]==='/' && (!ctag || !ctag['string-value'])) {
8997 var ptp = parse_text_p(str.slice(textpidx,Rn.index), textptag);
8998 textp = (textp.length > 0 ? textp + "\n" : "") + ptp[0];
8999 } else { textptag = parsexmltag(Rn[0], false); textpidx = Rn.index + Rn[0].length; }
9000 break; // <text:p>
9001 case 's': break; // <text:s>
9002
9003 case 'database-range': // 9.4.15 <table:database-range>
9004 if(Rn[1]==='/') break;
9005 try {
9006 _Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
9007 Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
9008 } catch(e) {/* empty */}
9009 break;
9010
9011 case 'date': break; // <*:date>
9012
9013 case 'object': break; // 10.4.6.2 <draw:object>
9014 case 'title': case '标题': break; // <*:title> OR <uof:标题>
9015 case 'desc': break; // <*:desc>
9016 case 'binary-data': break; // 10.4.5 TODO: b64 blob
9017
9018 /* 9.2 Advanced Tables */
9019 case 'table-source': break; // 9.2.6
9020 case 'scenario': break; // 9.2.6
9021
9022 case 'iteration': break; // 9.4.3 <table:iteration>
9023 case 'content-validations': break; // 9.4.4 <table:
9024 case 'content-validation': break; // 9.4.5 <table:
9025 case 'help-message': break; // 9.4.6 <table:
9026 case 'error-message': break; // 9.4.7 <table:
9027 case 'database-ranges': break; // 9.4.14 <table:database-ranges>
9028 case 'filter': break; // 9.5.2 <table:filter>
9029 case 'filter-and': break; // 9.5.3 <table:filter-and>
9030 case 'filter-or': break; // 9.5.4 <table:filter-or>
9031 case 'filter-condition': break; // 9.5.5 <table:filter-condition>
9032
9033 case 'list-level-style-bullet': break; // 16.31 <text:
9034 case 'list-level-style-number': break; // 16.32 <text:
9035 case 'list-level-properties': break; // 17.19 <style:
9036
9037 /* 7.3 Document Fields */
9038 case 'sender-firstname': // 7.3.6.2
9039 case 'sender-lastname': // 7.3.6.3
9040 case 'sender-initials': // 7.3.6.4
9041 case 'sender-title': // 7.3.6.5
9042 case 'sender-position': // 7.3.6.6
9043 case 'sender-email': // 7.3.6.7
9044 case 'sender-phone-private': // 7.3.6.8
9045 case 'sender-fax': // 7.3.6.9
9046 case 'sender-company': // 7.3.6.10
9047 case 'sender-phone-work': // 7.3.6.11
9048 case 'sender-street': // 7.3.6.12
9049 case 'sender-city': // 7.3.6.13
9050 case 'sender-postal-code': // 7.3.6.14
9051 case 'sender-country': // 7.3.6.15
9052 case 'sender-state-or-province': // 7.3.6.16
9053 case 'author-name': // 7.3.7.1
9054 case 'author-initials': // 7.3.7.2
9055 case 'chapter': // 7.3.8
9056 case 'file-name': // 7.3.9
9057 case 'template-name': // 7.3.9
9058 case 'sheet-name': // 7.3.9
9059 break;
9060
9061 case 'event-listener':
9062 break;
9063 /* TODO: FODS Properties */
9064 case 'initial-creator':
9065 case 'creation-date':
9066 case 'print-date':
9067 case 'generator':
9068 case 'document-statistic':
9069 case 'user-defined':
9070 case 'editing-duration':
9071 case 'editing-cycles':
9072 break;
9073
9074 /* TODO: FODS Config */
9075 case 'config-item':
9076 break;
9077
9078 /* TODO: style tokens */
9079 case 'page-number': break; // TODO <text:page-number>
9080 case 'page-count': break; // TODO <text:page-count>
9081 case 'time': break; // TODO <text:time>
9082
9083 /* 9.3 Advanced Table Cells */
9084 case 'cell-range-source': break; // 9.3.1 <table:
9085 case 'detective': break; // 9.3.2 <table:
9086 case 'operation': break; // 9.3.3 <table:
9087 case 'highlighted-range': break; // 9.3.4 <table:
9088
9089 /* 9.6 Data Pilot Tables <table: */
9090 case 'data-pilot-table': // 9.6.3
9091 case 'source-cell-range': // 9.6.5
9092 case 'source-service': // 9.6.6
9093 case 'data-pilot-field': // 9.6.7
9094 case 'data-pilot-level': // 9.6.8
9095 case 'data-pilot-subtotals': // 9.6.9
9096 case 'data-pilot-subtotal': // 9.6.10
9097 case 'data-pilot-members': // 9.6.11
9098 case 'data-pilot-member': // 9.6.12
9099 case 'data-pilot-display-info': // 9.6.13
9100 case 'data-pilot-sort-info': // 9.6.14
9101 case 'data-pilot-layout-info': // 9.6.15
9102 case 'data-pilot-field-reference': // 9.6.16
9103 case 'data-pilot-groups': // 9.6.17
9104 case 'data-pilot-group': // 9.6.18
9105 case 'data-pilot-group-member': // 9.6.19
9106 break;
9107
9108 /* 10.3 Drawing Shapes */
9109 case 'rect': // 10.3.2
9110 break;
9111
9112 /* 14.6 DDE Connections */
9113 case 'dde-connection-decls': // 14.6.2 <text:
9114 case 'dde-connection-decl': // 14.6.3 <text:
9115 case 'dde-link': // 14.6.4 <table:
9116 case 'dde-source': // 14.6.5 <office:
9117 break;
9118
9119 case 'properties': break; // 13.7 <form:properties>
9120 case 'property': break; // 13.8 <form:property>
9121
9122 case 'a': // 6.1.8 hyperlink
9123 if(Rn[1]!== '/') {
9124 atag = parsexmltag(Rn[0], false);
9125 if(!atag.href) break;
9126 atag.Target = atag.href; delete atag.href;
9127 if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
9128 _Ref = ods_to_csf_3D(atag.Target.slice(1));
9129 atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
9130 }
9131 }
9132 break;
9133
9134 /* non-standard */
9135 case 'table-protection': break;
9136 case 'data-pilot-grand-total': break; // <table:
9137 case 'office-document-common-attrs': break; // bare
9138 default: switch(Rn[2]) {
9139 case 'dc:': // TODO: properties
9140 case 'calcext:': // ignore undocumented extensions
9141 case 'loext:': // ignore undocumented extensions
9142 case 'ooo:': // ignore undocumented extensions
9143 case 'chartooo:': // ignore undocumented extensions
9144 case 'draw:': // TODO: drawing
9145 case 'style:': // TODO: styles
9146 case 'chart:': // TODO: charts
9147 case 'form:': // TODO: forms
9148 case 'uof:': // TODO: uof
9149 case '表:': // TODO: uof
9150 case '字:': // TODO: uof
9151 break;
9152 default: if(opts.WTF) throw new Error(Rn);
9153 }
9154 }
9155 var out = ({
9156 Sheets: Sheets,
9157 SheetNames: SheetNames,
9158 Workbook: WB
9159 });
9160 if(opts.bookSheets) delete out.Sheets;
9161 return out;
9162 };
9163})();
9164
9165function parse_ods(zip, opts) {
9166 opts = opts || ({});
9167 var ods = !!safegetzipfile(zip, 'objectdata');
9168 if(ods) parse_manifest(getzipdata(zip, 'META-INF/manifest.xml'), opts);
9169 var content = getzipstr(zip, 'content.xml');
9170 if(!content) throw new Error("Missing content.xml in " + (ods ? "ODS" : "UOF")+ " file");
9171 var wb = parse_content_xml(ods ? content : utf8read(content), opts);
9172 if(safegetzipfile(zip, 'meta.xml')) wb.Props = parse_core_props(getzipdata(zip, 'meta.xml'));
9173 return wb;
9174}
9175function parse_fods(data, opts) {
9176 return parse_content_xml(data, opts);
9177}
9178
9179/* OpenDocument */
9180var write_styles_ods = (function() {
9181 var payload = '<office:document-styles ' + wxt_helper({
9182 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
9183 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
9184 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
9185 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
9186 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
9187 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
9188 'xmlns:xlink': "http://www.w3.org/1999/xlink",
9189 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
9190 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
9191 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
9192 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
9193 'office:version': "1.2"
9194 }) + '></office:document-styles>';
9195 return function wso() {
9196 return XML_HEADER + payload;
9197 };
9198})();
9199var write_content_ods = (function() {
9200 /* 6.1.2 White Space Characters */
9201 var write_text_p = function(text) {
9202 return escapexml(text)
9203 .replace(/ +/g, function($$){return '<text:s text:c="'+$$.length+'"/>';})
9204 .replace(/\t/g, "<text:tab/>")
9205 .replace(/\n/g, "<text:line-break/>")
9206 .replace(/^ /, "<text:s/>").replace(/ $/, "<text:s/>");
9207 };
9208
9209 var null_cell_xml = ' <table:table-cell />\n';
9210 var covered_cell_xml = ' <table:covered-table-cell/>\n';
9211 var write_ws = function(ws, wb, i) {
9212 /* Section 9 Tables */
9213 var o = [];
9214 o.push(' <table:table table:name="' + escapexml(wb.SheetNames[i]) + '" table:style-name="ta1">\n');
9215 var R=0,C=0, range = decode_range(ws['!ref']);
9216 var marr = ws['!merges'] || [], mi = 0;
9217 var dense = Array.isArray(ws);
9218 for(R = 0; R < range.s.r; ++R) o.push(' <table:table-row></table:table-row>\n');
9219 for(; R <= range.e.r; ++R) {
9220 o.push(' <table:table-row>\n');
9221 for(C=0; C < range.s.c; ++C) o.push(null_cell_xml);
9222 for(; C <= range.e.c; ++C) {
9223 var skip = false, ct = {}, textp = "";
9224 for(mi = 0; mi != marr.length; ++mi) {
9225 if(marr[mi].s.c > C) continue;
9226 if(marr[mi].s.r > R) continue;
9227 if(marr[mi].e.c < C) continue;
9228 if(marr[mi].e.r < R) continue;
9229 if(marr[mi].s.c != C || marr[mi].s.r != R) skip = true;
9230 ct['table:number-columns-spanned'] = (marr[mi].e.c - marr[mi].s.c + 1);
9231 ct['table:number-rows-spanned'] = (marr[mi].e.r - marr[mi].s.r + 1);
9232 break;
9233 }
9234 if(skip) { o.push(covered_cell_xml); continue; }
9235 var ref = encode_cell({r:R, c:C}), cell = dense ? (ws[R]||[])[C]: ws[ref];
9236 if(cell && cell.f) {
9237 ct['table:formula'] = escapexml(csf_to_ods_formula(cell.f));
9238 if(cell.F) {
9239 if(cell.F.slice(0, ref.length) == ref) {
9240 var _Fref = decode_range(cell.F);
9241 ct['table:number-matrix-columns-spanned'] = (_Fref.e.c - _Fref.s.c + 1);
9242 ct['table:number-matrix-rows-spanned'] = (_Fref.e.r - _Fref.s.r + 1);
9243 }
9244 }
9245 }
9246 if(!cell) { o.push(null_cell_xml); continue; }
9247 switch(cell.t) {
9248 case 'b':
9249 textp = (cell.v ? 'TRUE' : 'FALSE');
9250 ct['office:value-type'] = "boolean";
9251 ct['office:boolean-value'] = (cell.v ? 'true' : 'false');
9252 break;
9253 case 'n':
9254 textp = (cell.w||String(cell.v||0));
9255 ct['office:value-type'] = "float";
9256 ct['office:value'] = (cell.v||0);
9257 break;
9258 case 's': case 'str':
9259 textp = cell.v == null ? "" : cell.v;
9260 ct['office:value-type'] = "string";
9261 break;
9262 case 'd':
9263 textp = (cell.w||(parseDate(cell.v).toISOString()));
9264 ct['office:value-type'] = "date";
9265 ct['office:date-value'] = (parseDate(cell.v).toISOString());
9266 ct['table:style-name'] = "ce1";
9267 break;
9268 //case 'e':
9269 default: o.push(null_cell_xml); continue;
9270 }
9271 var text_p = write_text_p(textp);
9272 if(cell.l && cell.l.Target) {
9273 var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
9274 text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
9275 }
9276 o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
9277 }
9278 o.push(' </table:table-row>\n');
9279 }
9280 o.push(' </table:table>\n');
9281 return o.join("");
9282 };
9283
9284 var write_automatic_styles_ods = function(o) {
9285 o.push(' <office:automatic-styles>\n');
9286
9287 o.push(' <number:date-style style:name="N37" number:automatic-order="true">\n');
9288 o.push(' <number:month number:style="long"/>\n');
9289 o.push(' <number:text>/</number:text>\n');
9290 o.push(' <number:day number:style="long"/>\n');
9291 o.push(' <number:text>/</number:text>\n');
9292 o.push(' <number:year/>\n');
9293 o.push(' </number:date-style>\n');
9294
9295 /* table */
9296 o.push(' <style:style style:name="ta1" style:family="table">\n'); // style:master-page-name="mp1">\n');
9297 o.push(' <style:table-properties table:display="true" style:writing-mode="lr-tb"/>\n');
9298 o.push(' </style:style>\n');
9299
9300 /* table cells, text */
9301 o.push(' <style:style style:name="ce1" style:family="table-cell" style:parent-style-name="Default" style:data-style-name="N37"/>\n');
9302
9303 /* page-layout */
9304
9305 o.push(' </office:automatic-styles>\n');
9306 };
9307
9308 return function wcx(wb, opts) {
9309 var o = [XML_HEADER];
9310 /* 3.1.3.2 */
9311 var attr = wxt_helper({
9312 'xmlns:office': "urn:oasis:names:tc:opendocument:xmlns:office:1.0",
9313 'xmlns:table': "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
9314 'xmlns:style': "urn:oasis:names:tc:opendocument:xmlns:style:1.0",
9315 'xmlns:text': "urn:oasis:names:tc:opendocument:xmlns:text:1.0",
9316 'xmlns:draw': "urn:oasis:names:tc:opendocument:xmlns:drawing:1.0",
9317 'xmlns:fo': "urn:oasis:names:tc:opendocument:xmlns:xsl-fo-compatible:1.0",
9318 'xmlns:xlink': "http://www.w3.org/1999/xlink",
9319 'xmlns:dc': "http://purl.org/dc/elements/1.1/",
9320 'xmlns:meta': "urn:oasis:names:tc:opendocument:xmlns:meta:1.0",
9321 'xmlns:number': "urn:oasis:names:tc:opendocument:xmlns:datastyle:1.0",
9322 'xmlns:presentation': "urn:oasis:names:tc:opendocument:xmlns:presentation:1.0",
9323 'xmlns:svg': "urn:oasis:names:tc:opendocument:xmlns:svg-compatible:1.0",
9324 'xmlns:chart': "urn:oasis:names:tc:opendocument:xmlns:chart:1.0",
9325 'xmlns:dr3d': "urn:oasis:names:tc:opendocument:xmlns:dr3d:1.0",
9326 'xmlns:math': "http://www.w3.org/1998/Math/MathML",
9327 'xmlns:form': "urn:oasis:names:tc:opendocument:xmlns:form:1.0",
9328 'xmlns:script': "urn:oasis:names:tc:opendocument:xmlns:script:1.0",
9329 'xmlns:ooo': "http://openoffice.org/2004/office",
9330 'xmlns:ooow': "http://openoffice.org/2004/writer",
9331 'xmlns:oooc': "http://openoffice.org/2004/calc",
9332 'xmlns:dom': "http://www.w3.org/2001/xml-events",
9333 'xmlns:xforms': "http://www.w3.org/2002/xforms",
9334 'xmlns:xsd': "http://www.w3.org/2001/XMLSchema",
9335 'xmlns:xsi': "http://www.w3.org/2001/XMLSchema-instance",
9336 'xmlns:sheet': "urn:oasis:names:tc:opendocument:sh33tjs:1.0",
9337 'xmlns:rpt': "http://openoffice.org/2005/report",
9338 'xmlns:of': "urn:oasis:names:tc:opendocument:xmlns:of:1.2",
9339 'xmlns:xhtml': "http://www.w3.org/1999/xhtml",
9340 'xmlns:grddl': "http://www.w3.org/2003/g/data-view#",
9341 'xmlns:tableooo': "http://openoffice.org/2009/table",
9342 'xmlns:drawooo': "http://openoffice.org/2010/draw",
9343 'xmlns:calcext': "urn:org:documentfoundation:names:experimental:calc:xmlns:calcext:1.0",
9344 'xmlns:loext': "urn:org:documentfoundation:names:experimental:office:xmlns:loext:1.0",
9345 'xmlns:field': "urn:openoffice:names:experimental:ooo-ms-interop:xmlns:field:1.0",
9346 'xmlns:formx': "urn:openoffice:names:experimental:ooxml-odf-interop:xmlns:form:1.0",
9347 'xmlns:css3t': "http://www.w3.org/TR/css3-text/",
9348 'office:version': "1.2"
9349 });
9350
9351 var fods = wxt_helper({
9352 'xmlns:config': "urn:oasis:names:tc:opendocument:xmlns:config:1.0",
9353 'office:mimetype': "application/vnd.oasis.opendocument.spreadsheet"
9354 });
9355
9356 if(opts.bookType == "fods") o.push('<office:document' + attr + fods + '>\n');
9357 else o.push('<office:document-content' + attr + '>\n');
9358 write_automatic_styles_ods(o);
9359 o.push(' <office:body>\n');
9360 o.push(' <office:spreadsheet>\n');
9361 for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts));
9362 o.push(' </office:spreadsheet>\n');
9363 o.push(' </office:body>\n');
9364 if(opts.bookType == "fods") o.push('</office:document>');
9365 else o.push('</office:document-content>');
9366 return o.join("");
9367 };
9368})();
9369
9370function write_ods(wb, opts) {
9371 if(opts.bookType == "fods") return write_content_ods(wb, opts);
9372
9373var zip = zip_new();
9374 var f = "";
9375
9376 var manifest = [];
9377 var rdf = [];
9378
9379 /* Part 3 Section 3.3 MIME Media Type */
9380 f = "mimetype";
9381 zip_add_file(zip, f, "application/vnd.oasis.opendocument.spreadsheet");
9382
9383 /* Part 1 Section 2.2 Documents */
9384 f = "content.xml";
9385 zip_add_file(zip, f, write_content_ods(wb, opts));
9386 manifest.push([f, "text/xml"]);
9387 rdf.push([f, "ContentFile"]);
9388
9389 /* TODO: these are hard-coded styles to satiate excel */
9390 f = "styles.xml";
9391 zip_add_file(zip, f, write_styles_ods(wb, opts));
9392 manifest.push([f, "text/xml"]);
9393 rdf.push([f, "StylesFile"]);
9394
9395 /* TODO: this is hard-coded to satiate excel */
9396 f = "meta.xml";
9397 zip_add_file(zip, f, write_meta_ods());
9398 manifest.push([f, "text/xml"]);
9399 rdf.push([f, "MetadataFile"]);
9400
9401 /* Part 3 Section 6 Metadata Manifest File */
9402 f = "manifest.rdf";
9403 zip_add_file(zip, f, write_rdf(rdf/*, opts*/));
9404 manifest.push([f, "application/rdf+xml"]);
9405
9406 /* Part 3 Section 4 Manifest File */
9407 f = "META-INF/manifest.xml";
9408 zip_add_file(zip, f, write_manifest(manifest/*, opts*/));
9409
9410 return zip;
9411}
9412
9413function write_sheet_index(wb, sheet) {
9414 if(!sheet) return 0;
9415 var idx = wb.SheetNames.indexOf(sheet);
9416 if(idx == -1) throw new Error("Sheet not found: " + sheet);
9417 return idx;
9418}
9419
9420function write_obj_str(factory) {
9421 return function write_str(wb, o) {
9422 var idx = write_sheet_index(wb, o.sheet);
9423 return factory.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb);
9424 };
9425}
9426
9427var write_htm_str = write_obj_str(HTML_);
9428var write_csv_str = write_obj_str({from_sheet:sheet_to_csv});
9429var write_slk_str = write_obj_str(typeof SYLK !== "undefined" ? SYLK : {});
9430var write_dif_str = write_obj_str(typeof DIF !== "undefined" ? DIF : {});
9431var write_prn_str = write_obj_str(typeof PRN !== "undefined" ? PRN : {});
9432var write_rtf_str = write_obj_str(typeof RTF !== "undefined" ? RTF : {});
9433var write_txt_str = write_obj_str({from_sheet:sheet_to_txt});
9434var write_dbf_buf = write_obj_str(typeof DBF !== "undefined" ? DBF : {});
9435var write_eth_str = write_obj_str(typeof ETH !== "undefined" ? ETH : {});
9436
9437function fix_opts_func(defaults) {
9438 return function fix_opts(opts) {
9439 for(var i = 0; i != defaults.length; ++i) {
9440 var d = defaults[i];
9441 if(opts[d[0]] === undefined) opts[d[0]] = d[1];
9442 if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
9443 }
9444 };
9445}
9446
9447var fix_read_opts = function(opts) {
9448fix_opts_func([
9449 ['cellNF', false], /* emit cell number format string as .z */
9450 ['cellHTML', true], /* emit html string as .h */
9451 ['cellFormula', true], /* emit formulae as .f */
9452 ['cellStyles', false], /* emits style/theme as .s */
9453 ['cellText', true], /* emit formatted text as .w */
9454 ['cellDates', false], /* emit date cells with type `d` */
9455
9456 ['sheetStubs', false], /* emit empty cells */
9457 ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
9458
9459 ['bookDeps', false], /* parse calculation chains */
9460 ['bookSheets', false], /* only try to get sheet names (no Sheets) */
9461 ['bookProps', false], /* only try to get properties (no Sheets) */
9462 ['bookFiles', false], /* include raw file structure (keys, files, cfb) */
9463 ['bookVBA', false], /* include vba raw data (vbaraw) */
9464
9465 ['password',''], /* password */
9466 ['WTF', false] /* WTF mode (throws errors) */
9467])(opts);
9468};
9469
9470var fix_write_opts = fix_opts_func([
9471 ['cellDates', false], /* write date cells with type `d` */
9472
9473 ['bookSST', false], /* Generate Shared String Table */
9474
9475 ['bookType', 'xlsx'], /* Type of workbook (xlsx/m/b) */
9476
9477 ['compression', false], /* Use file compression */
9478
9479 ['WTF', false] /* WTF mode (throws errors) */
9480]);
9481function get_sheet_type(n) {
9482 if(RELS.WS.indexOf(n) > -1) return "sheet";
9483 if(RELS.CS && n == RELS.CS) return "chart";
9484 if(RELS.DS && n == RELS.DS) return "dialog";
9485 if(RELS.MS && n == RELS.MS) return "macro";
9486 return (n && n.length) ? n : "sheet";
9487}
9488function safe_parse_wbrels(wbrels, sheets) {
9489 if(!wbrels) return 0;
9490 try {
9491 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)]; });
9492 } catch(e) { return null; }
9493 return !wbrels || wbrels.length === 0 ? null : wbrels;
9494}
9495
9496function safe_parse_sheet(zip, path, relsPath, sheet, idx, sheetRels, sheets, stype, opts, wb, themes, styles) {
9497 try {
9498 sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path);
9499 var data = getzipdata(zip, path);
9500 var _ws;
9501 switch(stype) {
9502 case 'sheet': _ws = parse_ws(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
9503 case 'chart': _ws = parse_cs(data, path, idx, opts, sheetRels[sheet], wb, themes, styles);
9504 if(!_ws || !_ws['!drawel']) break;
9505 var dfile = resolve_path(_ws['!drawel'].Target, path);
9506 var drelsp = get_rels_path(dfile);
9507 var draw = parse_drawing(getzipstr(zip, dfile, true), parse_rels(getzipstr(zip, drelsp, true), dfile));
9508 var chartp = resolve_path(draw, dfile);
9509 var crelsp = get_rels_path(chartp);
9510 _ws = parse_chart(getzipstr(zip, chartp, true), chartp, opts, parse_rels(getzipstr(zip, crelsp, true), chartp), wb, _ws);
9511 break;
9512 case 'macro': _ws = parse_ms(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
9513 case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
9514 default: throw new Error("Unrecognized sheet type " + stype);
9515 }
9516 sheets[sheet] = _ws;
9517
9518 /* scan rels for comments */
9519 var comments = [];
9520 if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) {
9521 if(sheetRels[sheet][n].Type == RELS.CMNT) {
9522 var dfile = resolve_path(sheetRels[sheet][n].Target, path);
9523 comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts);
9524 if(!comments || !comments.length) return;
9525 sheet_insert_comments(_ws, comments);
9526 }
9527 });
9528 } catch(e) { if(opts.WTF) throw e; }
9529}
9530
9531function strip_front_slash(x) { return x.charAt(0) == '/' ? x.slice(1) : x; }
9532
9533function parse_zip(zip, opts) {
9534 make_ssf(SSF);
9535 opts = opts || {};
9536 fix_read_opts(opts);
9537
9538 /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */
9539 if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts);
9540 /* UOC */
9541 if(safegetzipfile(zip, 'objectdata.xml')) return parse_ods(zip, opts);
9542 /* Numbers */
9543 if(safegetzipfile(zip, 'Index/Document.iwa')) throw new Error('Unsupported NUMBERS file');
9544
9545 var entries = zipentries(zip);
9546 var dir = parse_ct((getzipstr(zip, '[Content_Types].xml')));
9547 var xlsb = false;
9548 var sheets, binname;
9549 if(dir.workbooks.length === 0) {
9550 binname = "xl/workbook.xml";
9551 if(getzipdata(zip,binname, true)) dir.workbooks.push(binname);
9552 }
9553 if(dir.workbooks.length === 0) {
9554 binname = "xl/workbook.bin";
9555 if(!getzipdata(zip,binname,true)) throw new Error("Could not find workbook");
9556 dir.workbooks.push(binname);
9557 xlsb = true;
9558 }
9559 if(dir.workbooks[0].slice(-3) == "bin") xlsb = true;
9560
9561 var themes = ({});
9562 var styles = ({});
9563 if(!opts.bookSheets && !opts.bookProps) {
9564 strs = [];
9565 if(dir.sst) try { strs=parse_sst(getzipdata(zip, strip_front_slash(dir.sst)), dir.sst, opts); } catch(e) { if(opts.WTF) throw e; }
9566
9567 if(opts.cellStyles && dir.themes.length) themes = parse_theme(getzipstr(zip, dir.themes[0].replace(/^\//,''), true)||"",dir.themes[0], opts);
9568
9569 if(dir.style) styles = parse_sty(getzipdata(zip, strip_front_slash(dir.style)), dir.style, themes, opts);
9570 }
9571
9572 /*var externbooks = */dir.links.map(function(link) {
9573 try {
9574 var rels = parse_rels(getzipstr(zip, get_rels_path(strip_front_slash(link))), link);
9575 return parse_xlink(getzipdata(zip, strip_front_slash(link)), rels, link, opts);
9576 } catch(e) {}
9577 });
9578
9579 var wb = parse_wb(getzipdata(zip, strip_front_slash(dir.workbooks[0])), dir.workbooks[0], opts);
9580
9581 var props = {}, propdata = "";
9582
9583 if(dir.coreprops.length) {
9584 propdata = getzipdata(zip, strip_front_slash(dir.coreprops[0]), true);
9585 if(propdata) props = parse_core_props(propdata);
9586 if(dir.extprops.length !== 0) {
9587 propdata = getzipdata(zip, strip_front_slash(dir.extprops[0]), true);
9588 if(propdata) parse_ext_props(propdata, props, opts);
9589 }
9590 }
9591
9592 var custprops = {};
9593 if(!opts.bookSheets || opts.bookProps) {
9594 if (dir.custprops.length !== 0) {
9595 propdata = getzipstr(zip, strip_front_slash(dir.custprops[0]), true);
9596 if(propdata) custprops = parse_cust_props(propdata, opts);
9597 }
9598 }
9599
9600 var out = ({});
9601 if(opts.bookSheets || opts.bookProps) {
9602 if(wb.Sheets) sheets = wb.Sheets.map(function pluck(x){ return x.name; });
9603 else if(props.Worksheets && props.SheetNames.length > 0) sheets=props.SheetNames;
9604 if(opts.bookProps) { out.Props = props; out.Custprops = custprops; }
9605 if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
9606 if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
9607 }
9608 sheets = {};
9609
9610 var deps = {};
9611 if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
9612
9613 var i=0;
9614 var sheetRels = ({});
9615 var path, relsPath;
9616
9617 {
9618 var wbsheets = wb.Sheets;
9619 props.Worksheets = wbsheets.length;
9620 props.SheetNames = [];
9621 for(var j = 0; j != wbsheets.length; ++j) {
9622 props.SheetNames[j] = wbsheets[j].name;
9623 }
9624 }
9625
9626 var wbext = xlsb ? "bin" : "xml";
9627 var wbrelsi = dir.workbooks[0].lastIndexOf("/");
9628 var wbrelsfile = (dir.workbooks[0].slice(0, wbrelsi+1) + "_rels/" + dir.workbooks[0].slice(wbrelsi+1) + ".rels").replace(/^\//,"");
9629 if(!safegetzipfile(zip, wbrelsfile)) wbrelsfile = 'xl/_rels/workbook.' + wbext + '.rels';
9630 var wbrels = parse_rels(getzipstr(zip, wbrelsfile, true), wbrelsfile);
9631 if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets);
9632
9633 /* Numbers iOS hack */
9634 var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0;
9635 wsloop: for(i = 0; i != props.Worksheets; ++i) {
9636 var stype = "sheet";
9637 if(wbrels && wbrels[i]) {
9638 path = 'xl/' + (wbrels[i][1]).replace(/[\/]?xl\//, "");
9639 if(!safegetzipfile(zip, path)) path = wbrels[i][1];
9640 if(!safegetzipfile(zip, path)) path = wbrelsfile.replace(/_rels\/.*$/,"") + wbrels[i][1];
9641 stype = wbrels[i][2];
9642 } else {
9643 path = 'xl/worksheets/sheet'+(i+1-nmode)+"." + wbext;
9644 path = path.replace(/sheet0\./,"sheet.");
9645 }
9646 relsPath = path.replace(/^(.*)(\/)([^\/]*)$/, "$1/_rels/$3.rels");
9647 if(opts && opts.sheets != null) switch(typeof opts.sheets) {
9648 case "number": if(i != opts.sheets) continue wsloop; break;
9649 case "string": if(props.SheetNames[i].toLowerCase() != opts.sheets.toLowerCase()) continue wsloop; break;
9650 default: if(Array.isArray && Array.isArray(opts.sheets)) {
9651 var snjseen = false;
9652 for(var snj = 0; snj != opts.sheets.length; ++snj) {
9653 if(typeof opts.sheets[snj] == "number" && opts.sheets[snj] == i) snjseen=1;
9654 if(typeof opts.sheets[snj] == "string" && opts.sheets[snj].toLowerCase() == props.SheetNames[i].toLowerCase()) snjseen = 1;
9655 }
9656 if(!snjseen) continue wsloop;
9657 }
9658 }
9659 safe_parse_sheet(zip, path, relsPath, props.SheetNames[i], i, sheetRels, sheets, stype, opts, wb, themes, styles);
9660 }
9661
9662 out = ({
9663 Directory: dir,
9664 Workbook: wb,
9665 Props: props,
9666 Custprops: custprops,
9667 Deps: deps,
9668 Sheets: sheets,
9669 SheetNames: props.SheetNames,
9670 Strings: strs,
9671 Styles: styles,
9672 Themes: themes,
9673 SSF: SSF.get_table()
9674 });
9675 if(opts && opts.bookFiles) {
9676 out.keys = entries;
9677 out.files = zip.files;
9678 }
9679 if(opts && opts.bookVBA) {
9680 if(dir.vba.length > 0) out.vbaraw = getzipdata(zip,strip_front_slash(dir.vba[0]),true);
9681 else if(dir.defaults && dir.defaults.bin === CT_VBA) out.vbaraw = getzipdata(zip, 'xl/vbaProject.bin',true);
9682 }
9683 return out;
9684}
9685
9686/* [MS-OFFCRYPTO] 2.1.1 */
9687function parse_xlsxcfb(cfb, _opts) {
9688 var opts = _opts || {};
9689 var f = 'Workbook', data = CFB.find(cfb, f);
9690 try {
9691 f = '/!DataSpaces/Version';
9692 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9693 /*var version = */parse_DataSpaceVersionInfo(data.content);
9694
9695 /* 2.3.4.1 */
9696 f = '/!DataSpaces/DataSpaceMap';
9697 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9698 var dsm = parse_DataSpaceMap(data.content);
9699 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")
9700 throw new Error("ECMA-376 Encrypted file bad " + f);
9701
9702 /* 2.3.4.2 */
9703 f = '/!DataSpaces/DataSpaceInfo/StrongEncryptionDataSpace';
9704 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9705 var seds = parse_DataSpaceDefinition(data.content);
9706 if(seds.length != 1 || seds[0] != "StrongEncryptionTransform")
9707 throw new Error("ECMA-376 Encrypted file bad " + f);
9708
9709 /* 2.3.4.3 */
9710 f = '/!DataSpaces/TransformInfo/StrongEncryptionTransform/!Primary';
9711 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9712 /*var hdr = */parse_Primary(data.content);
9713 } catch(e) {}
9714
9715 f = '/EncryptionInfo';
9716 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9717 var einfo = parse_EncryptionInfo(data.content);
9718
9719 /* 2.3.4.4 */
9720 f = '/EncryptedPackage';
9721 data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
9722
9723/*global decrypt_agile */
9724if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
9725/*global decrypt_std76 */
9726if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
9727 throw new Error("File is password-protected");
9728}
9729
9730function write_zip(wb, opts) {
9731 _shapeid = 1024;
9732 if(opts.bookType == "ods") return write_ods(wb, opts);
9733 if(wb && !wb.SSF) {
9734 wb.SSF = SSF.get_table();
9735 }
9736 if(wb && wb.SSF) {
9737 make_ssf(SSF); SSF.load_table(wb.SSF);
9738 // $FlowIgnore
9739 opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0;
9740 opts.ssf = wb.SSF;
9741 }
9742 opts.rels = {}; opts.wbrels = {};
9743 opts.Strings = []; opts.Strings.Count = 0; opts.Strings.Unique = 0;
9744 if(browser_has_Map) opts.revStrings = new Map();
9745 else { opts.revStrings = {}; opts.revStrings.foo = []; delete opts.revStrings.foo; }
9746 var wbext = opts.bookType == "xlsb" ? "bin" : "xml";
9747 var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1;
9748 var ct = new_ct();
9749 fix_write_opts(opts = opts || {});
9750var zip = zip_new();
9751 var f = "", rId = 0;
9752
9753 opts.cellXfs = [];
9754 get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}});
9755
9756 if(!wb.Props) wb.Props = {};
9757
9758 f = "docProps/core.xml";
9759 zip_add_file(zip, f, write_core_props(wb.Props, opts));
9760 ct.coreprops.push(f);
9761 add_rels(opts.rels, 2, f, RELS.CORE_PROPS);
9762
9763f = "docProps/app.xml";
9764 if(wb.Props && wb.Props.SheetNames){/* empty */}
9765 else if(!wb.Workbook || !wb.Workbook.Sheets) wb.Props.SheetNames = wb.SheetNames;
9766 else {
9767 var _sn = [];
9768 for(var _i = 0; _i < wb.SheetNames.length; ++_i)
9769 if((wb.Workbook.Sheets[_i]||{}).Hidden != 2) _sn.push(wb.SheetNames[_i]);
9770 wb.Props.SheetNames = _sn;
9771 }
9772 wb.Props.Worksheets = wb.Props.SheetNames.length;
9773 zip_add_file(zip, f, write_ext_props(wb.Props, opts));
9774 ct.extprops.push(f);
9775 add_rels(opts.rels, 3, f, RELS.EXT_PROPS);
9776
9777 if(wb.Custprops !== wb.Props && keys(wb.Custprops||{}).length > 0) {
9778 f = "docProps/custom.xml";
9779 zip_add_file(zip, f, write_cust_props(wb.Custprops, opts));
9780 ct.custprops.push(f);
9781 add_rels(opts.rels, 4, f, RELS.CUST_PROPS);
9782 }
9783
9784 for(rId=1;rId <= wb.SheetNames.length; ++rId) {
9785 var wsrels = {'!id':{}};
9786 var ws = wb.Sheets[wb.SheetNames[rId-1]];
9787 var _type = (ws || {})["!type"] || "sheet";
9788 switch(_type) {
9789 case "chart":
9790 /* falls through */
9791 default:
9792 f = "xl/worksheets/sheet" + rId + "." + wbext;
9793 zip_add_file(zip, f, write_ws(rId-1, f, opts, wb, wsrels));
9794 ct.sheets.push(f);
9795 add_rels(opts.wbrels, -1, "worksheets/sheet" + rId + "." + wbext, RELS.WS[0]);
9796 }
9797
9798 if(ws) {
9799 var comments = ws['!comments'];
9800 var need_vml = false;
9801 if(comments && comments.length > 0) {
9802 var cf = "xl/comments" + rId + "." + wbext;
9803 zip_add_file(zip, cf, write_cmnt(comments, cf, opts));
9804 ct.comments.push(cf);
9805 add_rels(wsrels, -1, "../comments" + rId + "." + wbext, RELS.CMNT);
9806 need_vml = true;
9807 }
9808 if(ws['!legacy']) {
9809 if(need_vml) zip_add_file(zip, "xl/drawings/vmlDrawing" + (rId) + ".vml", write_comments_vml(rId, ws['!comments']));
9810 }
9811 delete ws['!comments'];
9812 delete ws['!legacy'];
9813 }
9814
9815 if(wsrels['!id'].rId1) zip_add_file(zip, get_rels_path(f), write_rels(wsrels));
9816 }
9817
9818 if(opts.Strings != null && opts.Strings.length > 0) {
9819 f = "xl/sharedStrings." + wbext;
9820 zip_add_file(zip, f, write_sst(opts.Strings, f, opts));
9821 ct.strs.push(f);
9822 add_rels(opts.wbrels, -1, "sharedStrings." + wbext, RELS.SST);
9823 }
9824
9825 f = "xl/workbook." + wbext;
9826 zip_add_file(zip, f, write_wb(wb, f, opts));
9827 ct.workbooks.push(f);
9828 add_rels(opts.rels, 1, f, RELS.WB);
9829
9830 /* TODO: something more intelligent with themes */
9831
9832 f = "xl/theme/theme1.xml";
9833 zip_add_file(zip, f, write_theme(wb.Themes, opts));
9834 ct.themes.push(f);
9835 add_rels(opts.wbrels, -1, "theme/theme1.xml", RELS.THEME);
9836
9837 /* TODO: something more intelligent with styles */
9838
9839 f = "xl/styles." + wbext;
9840 zip_add_file(zip, f, write_sty(wb, f, opts));
9841 ct.styles.push(f);
9842 add_rels(opts.wbrels, -1, "styles." + wbext, RELS.STY);
9843
9844 if(wb.vbaraw && vbafmt) {
9845 f = "xl/vbaProject.bin";
9846 zip_add_file(zip, f, wb.vbaraw);
9847 ct.vba.push(f);
9848 add_rels(opts.wbrels, -1, "vbaProject.bin", RELS.VBA);
9849 }
9850
9851 zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts));
9852 zip_add_file(zip, '_rels/.rels', write_rels(opts.rels));
9853 zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels));
9854
9855 delete opts.revssf; delete opts.ssf;
9856 return zip;
9857}
9858function firstbyte(f,o) {
9859 var x = "";
9860 switch((o||{}).type || "base64") {
9861 case 'buffer': return [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]];
9862 case 'base64': x = Base64.decode(f.slice(0,12)); break;
9863 case 'binary': x = f; break;
9864 case 'array': return [f[0], f[1], f[2], f[3], f[4], f[5], f[6], f[7]];
9865 default: throw new Error("Unrecognized type " + (o && o.type || "undefined"));
9866 }
9867 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)];
9868}
9869
9870function read_cfb(cfb, opts) {
9871 if(CFB.find(cfb, "EncryptedPackage")) return parse_xlsxcfb(cfb, opts);
9872 return parse_xlscfb(cfb, opts);
9873}
9874
9875function read_zip(data, opts) {
9876var zip, d = data;
9877 var o = opts||{};
9878 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
9879 zip = zip_read(d, o);
9880 return parse_zip(zip, o);
9881}
9882
9883function read_plaintext(data, o) {
9884 var i = 0;
9885 main: while(i < data.length) switch(data.charCodeAt(i)) {
9886 case 0x0A: case 0x0D: case 0x20: ++i; break;
9887 case 0x3C: return parse_xlml(data.slice(i),o);
9888 default: break main;
9889 }
9890 return PRN.to_workbook(data, o);
9891}
9892
9893function read_plaintext_raw(data, o) {
9894 var str = "", bytes = firstbyte(data, o);
9895 switch(o.type) {
9896 case 'base64': str = Base64.decode(data); break;
9897 case 'binary': str = data; break;
9898 case 'buffer': str = data.toString('binary'); break;
9899 case 'array': str = cc2str(data); break;
9900 default: throw new Error("Unrecognized type " + o.type);
9901 }
9902 if(bytes[0] == 0xEF && bytes[1] == 0xBB && bytes[2] == 0xBF) str = utf8read(str);
9903 return read_plaintext(str, o);
9904}
9905
9906function read_utf16(data, o) {
9907 var d = data;
9908 if(o.type == 'base64') d = Base64.decode(d);
9909 d = cptable.utils.decode(1200, d.slice(2), 'str');
9910 o.type = "binary";
9911 return read_plaintext(d, o);
9912}
9913
9914function bstrify(data) {
9915 return !data.match(/[^\x00-\x7F]/) ? data : utf8write(data);
9916}
9917
9918function read_prn(data, d, o, str) {
9919 if(str) { o.type = "string"; return PRN.to_workbook(data, o); }
9920 return PRN.to_workbook(d, o);
9921}
9922
9923function readSync(data, opts) {
9924 reset_cp();
9925 if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts);
9926 var d = data, n = [0,0,0,0], str = false;
9927 var o = opts||{};
9928 if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
9929 _ssfopts = {};
9930 if(o.dateNF) _ssfopts.dateNF = o.dateNF;
9931 if(!o.type) o.type = (has_buf && Buffer.isBuffer(data)) ? "buffer" : "base64";
9932 if(o.type == "file") { o.type = has_buf ? "buffer" : "binary"; d = read_binary(data); }
9933 if(o.type == "string") { str = true; o.type = "binary"; o.codepage = 65001; d = bstrify(data); }
9934 if(o.type == 'array' && typeof Uint8Array !== 'undefined' && data instanceof Uint8Array && typeof ArrayBuffer !== 'undefined') {
9935 // $FlowIgnore
9936 var ab=new ArrayBuffer(3), vu=new Uint8Array(ab); vu.foo="bar";
9937 // $FlowIgnore
9938 if(!vu.foo) {o=dup(o); o.type='array'; return readSync(ab2a(d), o);}
9939 }
9940 switch((n = firstbyte(d, o))[0]) {
9941 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;
9942 case 0x09: if(n[1] <= 0x04) return parse_xlscfb(d, o); break;
9943 case 0x3C: return parse_xlml(d, o);
9944 case 0x49: if(n[1] === 0x44) return read_wb_ID(d, o); break;
9945 case 0x54: if(n[1] === 0x41 && n[2] === 0x42 && n[3] === 0x4C) return DIF.to_workbook(d, o); break;
9946 case 0x50: return (n[1] === 0x4B && n[2] < 0x09 && n[3] < 0x09) ? read_zip(d, o) : read_prn(data, d, o, str);
9947 case 0xEF: return n[3] === 0x3C ? parse_xlml(d, o) : read_prn(data, d, o, str);
9948 case 0xFF: if(n[1] === 0xFE) { return read_utf16(d, o); } break;
9949 case 0x00: if(n[1] === 0x00 && n[2] >= 0x02 && n[3] === 0x00) return WK_.to_workbook(d, o); break;
9950 case 0x03: case 0x83: case 0x8B: case 0x8C: return DBF.to_workbook(d, o);
9951 case 0x7B: if(n[1] === 0x5C && n[2] === 0x72 && n[3] === 0x74) return RTF.to_workbook(d, o); break;
9952 case 0x0A: case 0x0D: case 0x20: return read_plaintext_raw(d, o);
9953 }
9954 if(DBF.versions.indexOf(n[0]) > -1 && n[2] <= 12 && n[3] <= 31) return DBF.to_workbook(d, o);
9955 return read_prn(data, d, o, str);
9956}
9957
9958function readFileSync(filename, opts) {
9959 var o = opts||{}; o.type = 'file';
9960 return readSync(filename, o);
9961}
9962function write_cfb_ctr(cfb, o) {
9963 switch(o.type) {
9964 case "base64": case "binary": break;
9965 case "buffer": case "array": o.type = ""; break;
9966 case "file": return write_dl(o.file, CFB.write(cfb, {type:has_buf ? 'buffer' : ""}));
9967 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
9968 default: throw new Error("Unrecognized type " + o.type);
9969 }
9970 return CFB.write(cfb, o);
9971}
9972
9973function write_zip_type(wb, opts) {
9974 var o = opts||{};
9975 var z = write_zip(wb, o);
9976 var oopts = {};
9977 if(o.compression) oopts.compression = 'DEFLATE';
9978 if(o.password) oopts.type = has_buf ? "nodebuffer" : "string";
9979 else switch(o.type) {
9980 case "base64": oopts.type = "base64"; break;
9981 case "binary": oopts.type = "string"; break;
9982 case "string": throw new Error("'string' output type invalid for '" + o.bookType + "' files");
9983 case "buffer":
9984 case "file": oopts.type = has_buf ? "nodebuffer" : "string"; break;
9985 default: throw new Error("Unrecognized type " + o.type);
9986 }
9987 var out = z.FullPaths ? CFB.write(z, {fileType:"zip", type: {"nodebuffer": "buffer", "string": "binary"}[oopts.type] || oopts.type}) : z.generate(oopts);
9988/*jshint -W083 */
9989 if(o.password && typeof encrypt_agile !== 'undefined') return write_cfb_ctr(encrypt_agile(out, o.password), o); // eslint-disable-line no-undef
9990/*jshint +W083 */
9991 if(o.type === "file") return write_dl(o.file, out);
9992 return o.type == "string" ? utf8read(out) : out;
9993}
9994
9995function write_cfb_type(wb, opts) {
9996 var o = opts||{};
9997 var cfb = write_xlscfb(wb, o);
9998 return write_cfb_ctr(cfb, o);
9999}
10000
10001function write_string_type(out, opts, bom) {
10002 if(!bom) bom = "";
10003 var o = bom + out;
10004 switch(opts.type) {
10005 case "base64": return Base64.encode(utf8write(o));
10006 case "binary": return utf8write(o);
10007 case "string": return out;
10008 case "file": return write_dl(opts.file, o, 'utf8');
10009 case "buffer": {
10010 if(has_buf) return Buffer_from(o, 'utf8');
10011 else return write_string_type(o, {type:'binary'}).split("").map(function(c) { return c.charCodeAt(0); });
10012 }
10013 }
10014 throw new Error("Unrecognized type " + opts.type);
10015}
10016
10017function write_stxt_type(out, opts) {
10018 switch(opts.type) {
10019 case "base64": return Base64.encode(out);
10020 case "binary": return out;
10021 case "string": return out; /* override in sheet_to_txt */
10022 case "file": return write_dl(opts.file, out, 'binary');
10023 case "buffer": {
10024 if(has_buf) return Buffer_from(out, 'binary');
10025 else return out.split("").map(function(c) { return c.charCodeAt(0); });
10026 }
10027 }
10028 throw new Error("Unrecognized type " + opts.type);
10029}
10030
10031/* TODO: test consistency */
10032function write_binary_type(out, opts) {
10033 switch(opts.type) {
10034 case "string":
10035 case "base64":
10036 case "binary":
10037 var bstr = "";
10038 // $FlowIgnore
10039 for(var i = 0; i < out.length; ++i) bstr += String.fromCharCode(out[i]);
10040 return opts.type == 'base64' ? Base64.encode(bstr) : opts.type == 'string' ? utf8read(bstr) : bstr;
10041 case "file": return write_dl(opts.file, out);
10042 case "buffer": return out;
10043 default: throw new Error("Unrecognized type " + opts.type);
10044 }
10045}
10046
10047function writeSync(wb, opts) {
10048 reset_cp();
10049 check_wb(wb);
10050 var o = opts||{};
10051 if(o.cellStyles) { o.cellNF = true; o.sheetStubs = true; }
10052 if(o.type == "array") { o.type = "binary"; var out = (writeSync(wb, o)); o.type = "array"; return s2ab(out); }
10053 switch(o.bookType || 'xlsb') {
10054 case 'xml':
10055 case 'xlml': return write_string_type(write_xlml(wb, o), o);
10056 case 'slk':
10057 case 'sylk': return write_string_type(write_slk_str(wb, o), o);
10058 case 'htm':
10059 case 'html': return write_string_type(write_htm_str(wb, o), o);
10060 case 'txt': return write_stxt_type(write_txt_str(wb, o), o);
10061 case 'csv': return write_string_type(write_csv_str(wb, o), o, "\ufeff");
10062 case 'dif': return write_string_type(write_dif_str(wb, o), o);
10063 case 'dbf': return write_binary_type(write_dbf_buf(wb, o), o);
10064 case 'prn': return write_string_type(write_prn_str(wb, o), o);
10065 case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
10066 case 'eth': return write_string_type(write_eth_str(wb, o), o);
10067 case 'fods': return write_string_type(write_ods(wb, o), o);
10068 case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
10069 case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
10070 case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o);
10071 case 'biff5': if(!o.biff) o.biff = 5; /* falls through */
10072 case 'biff8':
10073 case 'xla':
10074 case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
10075 case 'xlsx':
10076 case 'xlsm':
10077 case 'xlam':
10078 case 'xlsb':
10079 case 'ods': return write_zip_type(wb, o);
10080 default: throw new Error ("Unrecognized bookType |" + o.bookType + "|");
10081 }
10082}
10083
10084function resolve_book_type(o) {
10085 if(o.bookType) return;
10086 var _BT = {
10087 "xls": "biff8",
10088 "htm": "html",
10089 "slk": "sylk",
10090 "socialcalc": "eth",
10091 "Sh33tJS": "WTF"
10092 };
10093 var ext = o.file.slice(o.file.lastIndexOf(".")).toLowerCase();
10094 if(ext.match(/^\.[a-z]+$/)) o.bookType = ext.slice(1);
10095 o.bookType = _BT[o.bookType] || o.bookType;
10096}
10097
10098function writeFileSync(wb, filename, opts) {
10099 var o = opts||{}; o.type = 'file';
10100 o.file = filename;
10101 resolve_book_type(o);
10102 return writeSync(wb, o);
10103}
10104
10105function writeFileAsync(filename, wb, opts, cb) {
10106 var o = opts||{}; o.type = 'file';
10107 o.file = filename;
10108 resolve_book_type(o);
10109 o.type = 'buffer';
10110 var _cb = cb; if(!(_cb instanceof Function)) _cb = (opts);
10111 return _fs.writeFile(filename, writeSync(wb, o), _cb);
10112}
10113function make_json_row(sheet, r, R, cols, header, hdr, dense, o) {
10114 var rr = encode_row(R);
10115 var defval = o.defval, raw = o.raw || !Object.prototype.hasOwnProperty.call(o, "raw");
10116 var isempty = true;
10117 var row = (header === 1) ? [] : {};
10118 if(header !== 1) {
10119 if(Object.defineProperty) try { Object.defineProperty(row, '__rowNum__', {value:R, enumerable:false}); } catch(e) { row.__rowNum__ = R; }
10120 else row.__rowNum__ = R;
10121 }
10122 if(!dense || sheet[R]) for (var C = r.s.c; C <= r.e.c; ++C) {
10123 var val = dense ? sheet[R][C] : sheet[cols[C] + rr];
10124 if(val === undefined || val.t === undefined) {
10125 if(defval === undefined) continue;
10126 if(hdr[C] != null) { row[hdr[C]] = defval; }
10127 continue;
10128 }
10129 var v = val.v;
10130 switch(val.t){
10131 case 'z': if(v == null) break; continue;
10132 case 'e': v = void 0; break;
10133 case 's': case 'd': case 'b': case 'n': break;
10134 default: throw new Error('unrecognized type ' + val.t);
10135 }
10136 if(hdr[C] != null) {
10137 if(v == null) {
10138 if(defval !== undefined) row[hdr[C]] = defval;
10139 else if(raw && v === null) row[hdr[C]] = null;
10140 else continue;
10141 } else {
10142 row[hdr[C]] = raw || (o.rawNumbers && val.t == "n") ? v : format_cell(val,v,o);
10143 }
10144 if(v != null) isempty = false;
10145 }
10146 }
10147 return { row: row, isempty: isempty };
10148}
10149
10150
10151function sheet_to_json(sheet, opts) {
10152 if(sheet == null || sheet["!ref"] == null) return [];
10153 var val = {t:'n',v:0}, header = 0, offset = 1, hdr = [], v=0, vv="";
10154 var r = {s:{r:0,c:0},e:{r:0,c:0}};
10155 var o = opts || {};
10156 var range = o.range != null ? o.range : sheet["!ref"];
10157 if(o.header === 1) header = 1;
10158 else if(o.header === "A") header = 2;
10159 else if(Array.isArray(o.header)) header = 3;
10160 else if(o.header == null) header = 0;
10161 switch(typeof range) {
10162 case 'string': r = safe_decode_range(range); break;
10163 case 'number': r = safe_decode_range(sheet["!ref"]); r.s.r = range; break;
10164 default: r = range;
10165 }
10166 if(header > 0) offset = 0;
10167 var rr = encode_row(r.s.r);
10168 var cols = [];
10169 var out = [];
10170 var outi = 0, counter = 0;
10171 var dense = Array.isArray(sheet);
10172 var R = r.s.r, C = 0, CC = 0;
10173 if(dense && !sheet[R]) sheet[R] = [];
10174 for(C = r.s.c; C <= r.e.c; ++C) {
10175 cols[C] = encode_col(C);
10176 val = dense ? sheet[R][C] : sheet[cols[C] + rr];
10177 switch(header) {
10178 case 1: hdr[C] = C - r.s.c; break;
10179 case 2: hdr[C] = cols[C]; break;
10180 case 3: hdr[C] = o.header[C - r.s.c]; break;
10181 default:
10182 if(val == null) val = {w: "__EMPTY", t: "s"};
10183 vv = v = format_cell(val, null, o);
10184 counter = 0;
10185 for(CC = 0; CC < hdr.length; ++CC) if(hdr[CC] == vv) vv = v + "_" + (++counter);
10186 hdr[C] = vv;
10187 }
10188 }
10189 for (R = r.s.r + offset; R <= r.e.r; ++R) {
10190 var row = make_json_row(sheet, r, R, cols, header, hdr, dense, o);
10191 if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) out[outi++] = row.row;
10192 }
10193 out.length = outi;
10194 return out;
10195}
10196
10197var qreg = /"/g;
10198function make_csv_row(sheet, r, R, cols, fs, rs, FS, o) {
10199 var isempty = true;
10200 var row = [], txt = "", rr = encode_row(R);
10201 for(var C = r.s.c; C <= r.e.c; ++C) {
10202 if (!cols[C]) continue;
10203 var val = o.dense ? (sheet[R]||[])[C]: sheet[cols[C] + rr];
10204 if(val == null) txt = "";
10205 else if(val.v != null) {
10206 isempty = false;
10207 txt = ''+(o.rawNumbers && val.t == "n" ? val.v : format_cell(val, null, o));
10208 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; }
10209 if(txt == "ID") txt = '"ID"';
10210 } else if(val.f != null && !val.F) {
10211 isempty = false;
10212 txt = '=' + val.f; if(txt.indexOf(",") >= 0) txt = '"' + txt.replace(qreg, '""') + '"';
10213 } else txt = "";
10214 /* NOTE: Excel CSV does not support array formulae */
10215 row.push(txt);
10216 }
10217 if(o.blankrows === false && isempty) return null;
10218 return row.join(FS);
10219}
10220
10221function sheet_to_csv(sheet, opts) {
10222 var out = [];
10223 var o = opts == null ? {} : opts;
10224 if(sheet == null || sheet["!ref"] == null) return "";
10225 var r = safe_decode_range(sheet["!ref"]);
10226 var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0);
10227 var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0);
10228 var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$");
10229 var row = "", cols = [];
10230 o.dense = Array.isArray(sheet);
10231 var colinfo = o.skipHidden && sheet["!cols"] || [];
10232 var rowinfo = o.skipHidden && sheet["!rows"] || [];
10233 for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C);
10234 for(var R = r.s.r; R <= r.e.r; ++R) {
10235 if ((rowinfo[R]||{}).hidden) continue;
10236 row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o);
10237 if(row == null) { continue; }
10238 if(o.strip) row = row.replace(endregex,"");
10239 out.push(row + RS);
10240 }
10241 delete o.dense;
10242 return out.join("");
10243}
10244
10245function sheet_to_txt(sheet, opts) {
10246 if(!opts) opts = {}; opts.FS = "\t"; opts.RS = "\n";
10247 var s = sheet_to_csv(sheet, opts);
10248 if(typeof cptable == 'undefined' || opts.type == 'string') return s;
10249 var o = cptable.utils.encode(1200, s, 'str');
10250 return String.fromCharCode(255) + String.fromCharCode(254) + o;
10251}
10252
10253function sheet_to_formulae(sheet) {
10254 var y = "", x, val="";
10255 if(sheet == null || sheet["!ref"] == null) return [];
10256 var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C;
10257 var cmds = [];
10258 var dense = Array.isArray(sheet);
10259 for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C);
10260 for(var R = r.s.r; R <= r.e.r; ++R) {
10261 rr = encode_row(R);
10262 for(C = r.s.c; C <= r.e.c; ++C) {
10263 y = cols[C] + rr;
10264 x = dense ? (sheet[R]||[])[C] : sheet[y];
10265 val = "";
10266 if(x === undefined) continue;
10267 else if(x.F != null) {
10268 y = x.F;
10269 if(!x.f) continue;
10270 val = x.f;
10271 if(y.indexOf(":") == -1) y = y + ":" + y;
10272 }
10273 if(x.f != null) val = x.f;
10274 else if(x.t == 'z') continue;
10275 else if(x.t == 'n' && x.v != null) val = "" + x.v;
10276 else if(x.t == 'b') val = x.v ? "TRUE" : "FALSE";
10277 else if(x.w !== undefined) val = "'" + x.w;
10278 else if(x.v === undefined) continue;
10279 else if(x.t == 's') val = "'" + x.v;
10280 else val = ""+x.v;
10281 cmds[cmds.length] = y + "=" + val;
10282 }
10283 }
10284 return cmds;
10285}
10286
10287function sheet_add_json(_ws, js, opts) {
10288 var o = opts || {};
10289 var offset = +!o.skipHeader;
10290 var ws = _ws || ({});
10291 var _R = 0, _C = 0;
10292 if(ws && o.origin != null) {
10293 if(typeof o.origin == 'number') _R = o.origin;
10294 else {
10295 var _origin = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
10296 _R = _origin.r; _C = _origin.c;
10297 }
10298 }
10299 var cell;
10300 var range = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}});
10301 if(ws['!ref']) {
10302 var _range = safe_decode_range(ws['!ref']);
10303 range.e.c = Math.max(range.e.c, _range.e.c);
10304 range.e.r = Math.max(range.e.r, _range.e.r);
10305 if(_R == -1) { _R = _range.e.r + 1; range.e.r = _R + js.length - 1 + offset; }
10306 } else {
10307 if(_R == -1) { _R = 0; range.e.r = js.length - 1 + offset; }
10308 }
10309 var hdr = o.header || [], C = 0;
10310
10311 js.forEach(function (JS, R) {
10312 keys(JS).forEach(function(k) {
10313 if((C=hdr.indexOf(k)) == -1) hdr[C=hdr.length] = k;
10314 var v = JS[k];
10315 var t = 'z';
10316 var z = "";
10317 var ref = encode_cell({c:_C + C,r:_R + R + offset});
10318 cell = utils.sheet_get_cell(ws, ref);
10319 if(v && typeof v === 'object' && !(v instanceof Date)){
10320 ws[ref] = v;
10321 } else {
10322 if(typeof v == 'number') t = 'n';
10323 else if(typeof v == 'boolean') t = 'b';
10324 else if(typeof v == 'string') t = 's';
10325 else if(v instanceof Date) {
10326 t = 'd';
10327 if(!o.cellDates) { t = 'n'; v = datenum(v); }
10328 z = (o.dateNF || SSF._table[14]);
10329 }
10330 if(!cell) ws[ref] = cell = ({t:t, v:v});
10331 else {
10332 cell.t = t; cell.v = v;
10333 delete cell.w; delete cell.R;
10334 if(z) cell.z = z;
10335 }
10336 if(z) cell.z = z;
10337 }
10338 });
10339 });
10340 range.e.c = Math.max(range.e.c, _C + hdr.length - 1);
10341 var __R = encode_row(_R);
10342 if(offset) for(C = 0; C < hdr.length; ++C) ws[encode_col(C + _C) + __R] = {t:'s', v:hdr[C]};
10343 ws['!ref'] = encode_range(range);
10344 return ws;
10345}
10346function json_to_sheet(js, opts) { return sheet_add_json(null, js, opts); }
10347
10348var utils = {
10349 encode_col: encode_col,
10350 encode_row: encode_row,
10351 encode_cell: encode_cell,
10352 encode_range: encode_range,
10353 decode_col: decode_col,
10354 decode_row: decode_row,
10355 split_cell: split_cell,
10356 decode_cell: decode_cell,
10357 decode_range: decode_range,
10358 format_cell: format_cell,
10359 get_formulae: sheet_to_formulae,
10360 make_csv: sheet_to_csv,
10361 make_json: sheet_to_json,
10362 make_formulae: sheet_to_formulae,
10363 sheet_add_aoa: sheet_add_aoa,
10364 sheet_add_json: sheet_add_json,
10365 sheet_add_dom: sheet_add_dom,
10366 aoa_to_sheet: aoa_to_sheet,
10367 json_to_sheet: json_to_sheet,
10368 table_to_sheet: parse_dom_table,
10369 table_to_book: table_to_book,
10370 sheet_to_csv: sheet_to_csv,
10371 sheet_to_txt: sheet_to_txt,
10372 sheet_to_json: sheet_to_json,
10373 sheet_to_html: HTML_.from_sheet,
10374 sheet_to_formulae: sheet_to_formulae,
10375 sheet_to_row_object_array: sheet_to_json
10376};
10377
10378(function(utils) {
10379utils.consts = utils.consts || {};
10380function add_consts(R/*Array<any>*/) { R.forEach(function(a){ utils.consts[a[0]] = a[1]; }); }
10381
10382function get_default(x, y, z) { return x[y] != null ? x[y] : (x[y] = z); }
10383
10384/* get cell, creating a stub if necessary */
10385function ws_get_cell_stub(ws, R, C) {
10386 /* A1 cell address */
10387 if(typeof R == "string") {
10388 /* dense */
10389 if(Array.isArray(ws)) {
10390 var RC = decode_cell(R);
10391 if(!ws[RC.r]) ws[RC.r] = [];
10392 return ws[RC.r][RC.c] || (ws[RC.r][RC.c] = {t:'z'});
10393 }
10394 return ws[R] || (ws[R] = {t:'z'});
10395 }
10396 /* cell address object */
10397 if(typeof R != "number") return ws_get_cell_stub(ws, encode_cell(R));
10398 /* R and C are 0-based indices */
10399 return ws_get_cell_stub(ws, encode_cell({r:R,c:C||0}));
10400}
10401utils.sheet_get_cell = ws_get_cell_stub;
10402
10403/* find sheet index for given name / validate index */
10404function wb_sheet_idx(wb, sh) {
10405 if(typeof sh == "number") {
10406 if(sh >= 0 && wb.SheetNames.length > sh) return sh;
10407 throw new Error("Cannot find sheet # " + sh);
10408 } else if(typeof sh == "string") {
10409 var idx = wb.SheetNames.indexOf(sh);
10410 if(idx > -1) return idx;
10411 throw new Error("Cannot find sheet name |" + sh + "|");
10412 } else throw new Error("Cannot find sheet |" + sh + "|");
10413}
10414
10415/* simple blank workbook object */
10416utils.book_new = function() {
10417 return { SheetNames: [], Sheets: {} };
10418};
10419
10420/* add a worksheet to the end of a given workbook */
10421utils.book_append_sheet = function(wb, ws, name) {
10422 if(!name) for(var i = 1; i <= 0xFFFF; ++i, name = undefined) if(wb.SheetNames.indexOf(name = "Sheet" + i) == -1) break;
10423 if(!name || wb.SheetNames.length >= 0xFFFF) throw new Error("Too many worksheets");
10424 check_ws_name(name);
10425 if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
10426
10427 wb.SheetNames.push(name);
10428 wb.Sheets[name] = ws;
10429};
10430
10431/* set sheet visibility (visible/hidden/very hidden) */
10432utils.book_set_sheet_visibility = function(wb, sh, vis) {
10433 get_default(wb,"Workbook",{});
10434 get_default(wb.Workbook,"Sheets",[]);
10435
10436 var idx = wb_sheet_idx(wb, sh);
10437 // $FlowIgnore
10438 get_default(wb.Workbook.Sheets,idx, {});
10439
10440 switch(vis) {
10441 case 0: case 1: case 2: break;
10442 default: throw new Error("Bad sheet visibility setting " + vis);
10443 }
10444 // $FlowIgnore
10445 wb.Workbook.Sheets[idx].Hidden = vis;
10446};
10447add_consts([
10448 ["SHEET_VISIBLE", 0],
10449 ["SHEET_HIDDEN", 1],
10450 ["SHEET_VERY_HIDDEN", 2]
10451]);
10452
10453/* set number format */
10454utils.cell_set_number_format = function(cell, fmt) {
10455 cell.z = fmt;
10456 return cell;
10457};
10458
10459/* set cell hyperlink */
10460utils.cell_set_hyperlink = function(cell, target, tooltip) {
10461 if(!target) {
10462 delete cell.l;
10463 } else {
10464 cell.l = ({ Target: target });
10465 if(tooltip) cell.l.Tooltip = tooltip;
10466 }
10467 return cell;
10468};
10469utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
10470
10471/* add to cell comments */
10472utils.cell_add_comment = function(cell, text, author) {
10473 if(!cell.c) cell.c = [];
10474 cell.c.push({t:text, a:author||"SheetJS"});
10475};
10476
10477/* set array formula and flush related cells */
10478utils.sheet_set_array_formula = function(ws, range, formula) {
10479 var rng = typeof range != "string" ? range : safe_decode_range(range);
10480 var rngstr = typeof range == "string" ? range : encode_range(range);
10481 for(var R = rng.s.r; R <= rng.e.r; ++R) for(var C = rng.s.c; C <= rng.e.c; ++C) {
10482 var cell = ws_get_cell_stub(ws, R, C);
10483 cell.t = 'n';
10484 cell.F = rngstr;
10485 delete cell.v;
10486 if(R == rng.s.r && C == rng.s.c) cell.f = formula;
10487 }
10488 return ws;
10489};
10490
10491return utils;
10492})(utils);
10493
10494if(typeof parse_xlscfb !== "undefined") XLSX.parse_xlscfb = parse_xlscfb;
10495XLSX.parse_zip = parse_zip;
10496XLSX.read = readSync; //xlsread
10497XLSX.readFile = readFileSync; //readFile
10498XLSX.readFileSync = readFileSync;
10499XLSX.write = writeSync;
10500XLSX.writeFile = writeFileSync;
10501XLSX.writeFileSync = writeFileSync;
10502XLSX.writeFileAsync = writeFileAsync;
10503XLSX.utils = utils;
10504XLSX.SSF = SSF;
10505if(typeof CFB !== "undefined") XLSX.CFB = CFB;
10506}
10507/*global define */
10508if(typeof exports !== 'undefined') make_xlsx_lib(exports);
10509else if(typeof module !== 'undefined' && module.exports) make_xlsx_lib(module.exports);
10510else if(typeof define === 'function' && define.amd) define(function() { if(!XLSX.version) make_xlsx_lib(XLSX); return XLSX; });
10511else make_xlsx_lib(XLSX);
10512/*exported XLS, ODS */
10513var XLS = XLSX, ODS = XLSX;