styled-exceljs 0.21.2 → 0.21.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/xlsx.mjs CHANGED
@@ -3,7 +3,7 @@
3
3
  /*exported XLSX */
4
4
  /*global process:false, Buffer:false, ArrayBuffer:false, DataView:false, Deno:false */
5
5
  var XLSX = {};
6
- XLSX.version = '0.21.2';
6
+ XLSX.version = '0.21.4';
7
7
  var current_codepage = 1200, current_ansi = 1252;
8
8
  /*:: declare var cptable:any; */
9
9
  /*global cptable:true, window */
@@ -158,9 +158,9 @@ function Base64_decode(input) {
158
158
  var o = "";
159
159
  var c1 = 0, c2 = 0, c3 = 0, e1 = 0, e2 = 0, e3 = 0, e4 = 0;
160
160
  if (input.slice(0, 5) == "data:") {
161
- var i = input.slice(0, 1024).indexOf(";base64,");
162
- if (i > -1)
163
- input = input.slice(i + 8);
161
+ var sep = input.slice(0, 1024).indexOf(";base64,");
162
+ if (sep > -1)
163
+ input = input.slice(sep + 8);
164
164
  }
165
165
  input = input.replace(/[^\w\+\/\=]/g, "");
166
166
  for (var i = 0; i < input.length; ) {
@@ -3300,7 +3300,7 @@ function blobify(data) {
3300
3300
  }
3301
3301
  /* write or download file */
3302
3302
  function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
3303
- /*global IE_SaveFile, Blob, navigator, saveAs, document, File, chrome */
3303
+ /*global IE_SaveFile, navigator, saveAs, document, chrome */
3304
3304
  if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
3305
3305
  if(typeof Deno !== 'undefined') {
3306
3306
  /* in this spot, it's safe to assume typed arrays and TextEncoder/TextDecoder exist */
@@ -3945,7 +3945,7 @@ function escapexmltag(text/*:string*/)/*:string*/{ return escapexml(text).replac
3945
3945
  var htmlcharegex = /[\u0000-\u001f]/g;
3946
3946
  function escapehtml(text/*:string*/)/*:string*/{
3947
3947
  var s = text + '';
3948
- 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) + ";"; });
3948
+ return s.replace(decregex, function(y) { return rencoding[y]; }).replace(/\r\n|\r|\n/g, "<br/>").replace(htmlcharegex,function(s) { return "&#x" + ("000"+s.charCodeAt(0).toString(16)).slice(-4) + ";"; });
3949
3949
  }
3950
3950
 
3951
3951
  function escapexlml(text/*:string*/)/*:string*/{
@@ -3953,6 +3953,19 @@ function escapexlml(text/*:string*/)/*:string*/{
3953
3953
  return s.replace(decregex, function(y) { return rencoding[y]; }).replace(htmlcharegex,function(s) { return "&#x" + (s.charCodeAt(0).toString(16)).toUpperCase() + ";"; });
3954
3954
  }
3955
3955
 
3956
+ /* Extract text from XML fragments in linear time. This is a parser helper,
3957
+ * not an HTML sanitizer: text is escaped separately at HTML output boundaries. */
3958
+ function strip_xml_tags(text/*:string*/)/*:string*/ {
3959
+ var str = String(text), out = [], inTag = false;
3960
+ for(var i = 0; i < str.length; ++i) {
3961
+ var cc = str.charCodeAt(i);
3962
+ if(!inTag && cc == 60 /* < */) inTag = true;
3963
+ else if(inTag && cc == 62 /* > */) inTag = false;
3964
+ else if(!inTag) out.push(str.charAt(i));
3965
+ }
3966
+ return out.join("");
3967
+ }
3968
+
3956
3969
  /* TODO: handle codepages */
3957
3970
  var xlml_fixstr/*:StringConv*/ = /*#__PURE__*/(function() {
3958
3971
  var entregex = /&#(\d+);/g;
@@ -4059,8 +4072,8 @@ var htmldecode/*:{(s:string):string}*/ = /*#__PURE__*/(function() {
4059
4072
  .replace(/[\t\n\r ]+/g, " ")
4060
4073
  // Replace <br> tags with new lines
4061
4074
  .replace(/<\s*[bB][rR]\s*\/?>/g,"\n")
4062
- // Strip HTML elements
4063
- .replace(/<[^<>]*>/g,"");
4075
+ ;
4076
+ o = strip_xml_tags(o);
4064
4077
  for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]);
4065
4078
  return o;
4066
4079
  };
@@ -4638,9 +4651,25 @@ function format_cell(cell/*:Cell*/, v/*:any*/, o/*:any*/) {
4638
4651
  return safe_format_cell(cell, v);
4639
4652
  }
4640
4653
 
4654
+ /* Worksheet names are document-controlled. A normal object treats
4655
+ * "__proto__" as a setter, so all workbook sheet maps must use an own-property
4656
+ * preserving dictionary and all lookups must reject inherited properties. */
4657
+ function sheet_map_new() {
4658
+ return Object.create ? Object.create(null) : {};
4659
+ }
4660
+ function sheet_map_set(sheets, name/*:string*/, sheet/*:Worksheet*/) {
4661
+ if(name == "__proto__" && Object.defineProperty) Object.defineProperty(sheets, name, {
4662
+ value: sheet, configurable: true, enumerable: true, writable: true
4663
+ });
4664
+ else sheets[name] = sheet;
4665
+ }
4666
+ function sheet_map_get(sheets, name/*:string*/)/*:?Worksheet*/ {
4667
+ return sheets != null && Object.prototype.hasOwnProperty.call(sheets, name) ? sheets[name] : void 0;
4668
+ }
4669
+
4641
4670
  function sheet_to_workbook(sheet/*:Worksheet*/, opts)/*:Workbook*/ {
4642
4671
  var n = opts && opts.sheet ? opts.sheet : "Sheet1";
4643
- var sheets = {}; sheets[n] = sheet;
4672
+ var sheets = sheet_map_new(); sheet_map_set(sheets, n, sheet);
4644
4673
  return { SheetNames: [n], Sheets: sheets };
4645
4674
  }
4646
4675
 
@@ -5726,6 +5755,7 @@ var RELS = ({
5726
5755
  MS: "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet",
5727
5756
  IMG: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image",
5728
5757
  DRAW: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing",
5758
+ TABLE: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/table",
5729
5759
  XLMETA: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata",
5730
5760
  TCMNT: "http://schemas.microsoft.com/office/2017/10/relationships/threadedComment",
5731
5761
  PEOPLE: "http://schemas.microsoft.com/office/2017/10/relationships/person",
@@ -6315,8 +6345,8 @@ function parse_TypedPropertyValue(blob, type/*:number*/, _opts)/*:any*/ {
6315
6345
  case 0x03 /*VT_I4*/: ret = blob.read_shift(4, 'i'); return ret;
6316
6346
  case 0x0B /*VT_BOOL*/: return blob.read_shift(4) !== 0x0;
6317
6347
  case 0x13 /*VT_UI4*/: ret = blob.read_shift(4); return ret;
6318
- case 0x1E /*VT_LPSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break;
6319
- case 0x1F /*VT_LPWSTR*/: blob.l += 4; val = parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1"); break;
6348
+ case 0x1E /*VT_LPSTR*/: blob.l += 4; return parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1");
6349
+ case 0x1F /*VT_LPWSTR*/: blob.l += 4; return parse_VtString(blob, blob[blob.l-4]).replace(/(^|[^\u0000])\u0000+$/,"$1");
6320
6350
  case 0x40 /*VT_FILETIME*/: return parse_FILETIME(blob);
6321
6351
  case 0x41 /*VT_BLOB*/: return parse_BLOB(blob);
6322
6352
  case 0x47 /*VT_CF*/: return parse_ClipboardData(blob);
@@ -6827,7 +6857,6 @@ function parse_LongRGBA(blob/*::, length*/) { var r = blob.read_shift(1), g = bl
6827
6857
  /* 2.5.177 LongRGB */
6828
6858
  function parse_LongRGB(blob, length) { var x = parse_LongRGBA(blob, length); x[3] = 0; return x; }
6829
6859
 
6830
-
6831
6860
  /* [MS-XLS] 2.5.19 */
6832
6861
  function parse_XLSCell(blob, length, opts)/*:Cell*/ {
6833
6862
  var rw = blob.read_shift(2); // 0-indexed
@@ -8290,7 +8319,7 @@ function dbf_to_workbook(buf, opts)/*:Workbook*/ {
8290
8319
  o.bookType = "dbf";
8291
8320
  return o;
8292
8321
  } catch(e) { if(opts && opts.WTF) throw e; }
8293
- return ({SheetNames:[],Sheets:{}});
8322
+ return ({SheetNames:[],Sheets:sheet_map_new()});
8294
8323
  }
8295
8324
 
8296
8325
  var _RLEN = { 'B': 8, 'C': 250, 'L': 1, 'D': 8, '?': 0, '': 0 };
@@ -9186,7 +9215,7 @@ function read_wb_TABL(d, opts) {
9186
9215
  try {
9187
9216
  var out = DIF.to_workbook(d, o);
9188
9217
  if(!out || !out.Sheets) throw "DIF bad workbook";
9189
- var ws = out.Sheets[out.SheetNames[0]];
9218
+ var ws = sheet_map_get(out.Sheets, out.SheetNames[0]);
9190
9219
  if(!ws || !ws["!ref"]) throw "DIF empty worksheet";
9191
9220
  o.WTF = OLD_WTF;
9192
9221
  return out;
@@ -9242,7 +9271,7 @@ var WK_ = /*#__PURE__*/(function() {
9242
9271
  var o = opts || {};
9243
9272
  if(DENSE != null && o.dense == null) o.dense = DENSE;
9244
9273
  var s/*:Worksheet*/ = ({}/*:any*/), n = "Sheet1", next_n = "", sidx = 0;
9245
- var sheets = {}, snames = [], realnames = [], sdata = [];
9274
+ var sheets = sheet_map_new(), snames = [], realnames = [], sdata = [];
9246
9275
  if(o.dense) sdata = s["!data"] = [];
9247
9276
 
9248
9277
  var refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
@@ -9287,7 +9316,7 @@ var WK_ = /*#__PURE__*/(function() {
9287
9316
  if(o.qpro) {
9288
9317
  if(val[3] > sidx) {
9289
9318
  s["!ref"] = encode_range(refguess);
9290
- sheets[n] = s;
9319
+ sheet_map_set(sheets, n, s);
9291
9320
  snames.push(n);
9292
9321
  s = ({}/*:any*/); if(o.dense) sdata = s["!data"] = [];
9293
9322
  refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
@@ -9338,7 +9367,7 @@ var WK_ = /*#__PURE__*/(function() {
9338
9367
  case 0x28: /* FORMULA28 */
9339
9368
  if(val[3] > sidx) {
9340
9369
  s["!ref"] = encode_range(refguess);
9341
- sheets[n] = s;
9370
+ sheet_map_set(sheets, n, s);
9342
9371
  snames.push(n);
9343
9372
  s = ({}/*:any*/); if(o.dense) sdata = s["!data"] = [];
9344
9373
  refguess = {s: {r:0, c:0}, e: {r:0, c:0} };
@@ -9361,17 +9390,17 @@ var WK_ = /*#__PURE__*/(function() {
9361
9390
  }}, o);
9362
9391
  } else throw new Error("Unrecognized LOTUS BOF " + d[2]);
9363
9392
  s["!ref"] = encode_range(refguess);
9364
- sheets[next_n || n] = s;
9393
+ sheet_map_set(sheets, next_n || n, s);
9365
9394
  snames.push(next_n || n);
9366
9395
  if(!realnames.length) return { SheetNames: snames, Sheets: sheets };
9367
- var osheets = {}, rnames = [];
9396
+ var osheets = sheet_map_new(), rnames = [];
9368
9397
  /* TODO: verify no collisions */
9369
- for(var i = 0; i < realnames.length; ++i) if(sheets[snames[i]]) {
9398
+ for(var i = 0; i < realnames.length; ++i) if(sheet_map_get(sheets, snames[i])) {
9370
9399
  rnames.push(realnames[i] || snames[i]);
9371
- osheets[realnames[i]] = sheets[realnames[i]] || sheets[snames[i]];
9400
+ sheet_map_set(osheets, realnames[i] || snames[i], sheet_map_get(sheets, realnames[i]) || sheet_map_get(sheets, snames[i]));
9372
9401
  } else {
9373
9402
  rnames.push(realnames[i]);
9374
- osheets[realnames[i]] = ({ "!ref": "A1" });
9403
+ sheet_map_set(osheets, realnames[i], ({ "!ref": "A1" }));
9375
9404
  }
9376
9405
  return { SheetNames: rnames, Sheets: osheets };
9377
9406
  }
@@ -9425,11 +9454,11 @@ var WK_ = /*#__PURE__*/(function() {
9425
9454
 
9426
9455
  write_biff_rec(ba, 0x00, write_BOF_WK3(wb));
9427
9456
 
9428
- for(var i = 0, cnt = 0; i < wb.SheetNames.length; ++i) if((wb.Sheets[wb.SheetNames[i]] || {})["!ref"]) write_biff_rec(ba, 0x1b, write_XFORMAT_SHEETNAME(wb.SheetNames[i], cnt++));
9457
+ for(var i = 0, cnt = 0; i < wb.SheetNames.length; ++i) if((sheet_map_get(wb.Sheets, wb.SheetNames[i]) || {})["!ref"]) write_biff_rec(ba, 0x1b, write_XFORMAT_SHEETNAME(wb.SheetNames[i], cnt++));
9429
9458
 
9430
9459
  var wsidx = 0;
9431
9460
  for(i = 0; i < wb.SheetNames.length; ++i) {
9432
- var ws = wb.Sheets[wb.SheetNames[i]];
9461
+ var ws = sheet_map_get(wb.Sheets, wb.SheetNames[i]);
9433
9462
  if(!ws || !ws["!ref"]) continue;
9434
9463
  var range = safe_decode_range(ws["!ref"]);
9435
9464
  var dense = ws["!data"] != null;
@@ -9474,7 +9503,7 @@ var WK_ = /*#__PURE__*/(function() {
9474
9503
  var rows = 0, cols = 0, wscnt = 0;
9475
9504
  for(var i = 0; i < wb.SheetNames.length; ++i) {
9476
9505
  var name = wb.SheetNames[i];
9477
- var ws = wb.Sheets[name];
9506
+ var ws = sheet_map_get(wb.Sheets, name);
9478
9507
  if(!ws || !ws["!ref"]) continue;
9479
9508
  ++wscnt;
9480
9509
  var range = decode_range(ws["!ref"]);
@@ -10202,7 +10231,7 @@ var WK_ = /*#__PURE__*/(function() {
10202
10231
  var SST = [], sname = "", formulae = [];
10203
10232
  var range = {s:{r:-1,c:-1}, e:{r:-1,c:-1}};
10204
10233
  var cnt = 0, type = 0, C = 0, R = 0;
10205
- var wb = { SheetNames: [], Sheets: {} };
10234
+ var wb = { SheetNames: [], Sheets: sheet_map_new() };
10206
10235
  var FMTS = [];
10207
10236
  outer: while(d.l < d.length) {
10208
10237
  var RT = d.read_shift(2), length = d.read_shift(2);
@@ -10506,13 +10535,13 @@ var parse_rs = /*#__PURE__*/(function() {
10506
10535
 
10507
10536
  /* Parse a list of <r> tags */
10508
10537
  var rs_to_html = /*#__PURE__*/(function parse_rs_factory() {
10509
- var nlregex = /(\r\n|\n)/g;
10510
10538
  function parse_rpr2(font, intro, outro) {
10511
10539
  var style/*:Array<string>*/ = [];
10512
10540
 
10513
10541
  if(font.u) style.push("text-decoration: underline;");
10514
- if(font.uval) style.push("text-underline-style:" + font.uval + ";");
10515
- if(font.sz) style.push("font-size:" + font.sz + "pt;");
10542
+ if(font.uval && /^(?:single|double|single-accounting|double-accounting)$/.test(font.uval)) style.push("text-underline-style:" + font.uval + ";");
10543
+ var sz = +font.sz;
10544
+ if(isFinite(sz) && sz > 0) style.push("font-size:" + Math.min(sz, 409) + "pt;");
10516
10545
  if(font.outline) style.push("text-effect: outline;");
10517
10546
  if(font.shadow) style.push("text-shadow: auto;");
10518
10547
  intro.push('<span style="' + style.join("") + '">');
@@ -10537,7 +10566,7 @@ var rs_to_html = /*#__PURE__*/(function parse_rs_factory() {
10537
10566
 
10538
10567
  if(r.s) parse_rpr2(r.s, terms[0], terms[2]);
10539
10568
 
10540
- return terms[0].join("") + terms[1].replace(nlregex,'<br/>') + terms[2].join("");
10569
+ return terms[0].join("") + escapehtml(terms[1]) + terms[2].join("");
10541
10570
  }
10542
10571
 
10543
10572
  return function parse_rs(rs) {
@@ -11196,6 +11225,9 @@ function resolve_style_obj_color(obj, themes) {
11196
11225
 
11197
11226
  /* 18.3.1.13 width calculations */
11198
11227
  /* [MS-OI29500] 2.1.595 Column Width & Formatting */
11228
+ /* The file format does not store MDW directly. Seven is the Office-compatible
11229
+ * fallback when Normal-font metrics are unavailable. A single stored column
11230
+ * width is ambiguous and must not change the scale for the rest of a sheet. */
11199
11231
  var DEF_MDW = 7, MAX_MDW = 15, MIN_MDW = 1, MDW = DEF_MDW;
11200
11232
  function width2px(width) { return Math.floor(( width + (Math.round(128/MDW))/256 )* MDW ); }
11201
11233
  function px2char(px) { return (Math.floor((px - 5)/MDW * 100 + 0.5))/100; }
@@ -11272,6 +11304,15 @@ function style_font_family(style) {
11272
11304
  var font = style && style.font || {};
11273
11305
  return font.name || "Calibri";
11274
11306
  }
11307
+ function css_string_escape(value/*:any*/, quote/*:string*/)/*:string*/ {
11308
+ var str = String(value), out = [];
11309
+ for(var i = 0; i < str.length; ++i) {
11310
+ var cc = str.charCodeAt(i), ch = str.charAt(i);
11311
+ if(ch == quote || ch == "\\" || cc < 32 || cc == 127 || ch == "<" || ch == ">" || ch == "&") out.push("\\" + cc.toString(16) + " ");
11312
+ else out.push(ch);
11313
+ }
11314
+ return out.join("");
11315
+ }
11275
11316
  function css_font_from_style(style) {
11276
11317
  var font = style && style.font || {};
11277
11318
  var parts = [];
@@ -11279,7 +11320,8 @@ function css_font_from_style(style) {
11279
11320
  if(font.bold) parts.push("bold");
11280
11321
  parts.push(style_font_size_pt(style) + "pt");
11281
11322
  var name = style_font_family(style);
11282
- if(/[,\s'"]/.test(name)) name = '"' + String(name).replace(/"/g, '\\"') + '"';
11323
+ if(/[,\s'"]/.test(name)) name = '"' + css_string_escape(name, '"') + '"';
11324
+ else name = css_string_escape(name, '"');
11283
11325
  parts.push(name);
11284
11326
  return parts.join(" ");
11285
11327
  }
@@ -12019,6 +12061,47 @@ function parse_dxfs(t, styles, themes, opts) {
12019
12061
  });
12020
12062
  }
12021
12063
 
12064
+ function parse_tableStyles(t, styles, opts) {
12065
+ styles.TableStyles = {styles:[]};
12066
+ var tableStyle = null, pass = false;
12067
+ (t.match(tagregex)||[]).forEach(function(x) {
12068
+ var y = parsexmltag(x), tag = strip_ns(y[0]);
12069
+ switch(tag) {
12070
+ case '<tableStyles': case '<tableStyles>':
12071
+ if(y.defaultTableStyle) styles.TableStyles.defaultTableStyle = utf8read(unescapexml(y.defaultTableStyle));
12072
+ if(y.defaultPivotStyle) styles.TableStyles.defaultPivotStyle = utf8read(unescapexml(y.defaultPivotStyle));
12073
+ break;
12074
+ case '<tableStyles/>': case '</tableStyles>': break;
12075
+ case '<tableStyle': case '<tableStyle>': case '<tableStyle/>':
12076
+ if(styles.TableStyles.styles.length >= TABLE_STYLE_MAX_TABLES) {
12077
+ tableStyle = null;
12078
+ break;
12079
+ }
12080
+ tableStyle = {
12081
+ name:utf8read(unescapexml(y.name || "")),
12082
+ pivot:y.pivot != null ? parsexmlbool(y.pivot) : false,
12083
+ table:y.table != null ? parsexmlbool(y.table) : true,
12084
+ elements:[]
12085
+ };
12086
+ styles.TableStyles.styles.push(tableStyle);
12087
+ if(tag.slice(-2) == "/>") tableStyle = null;
12088
+ break;
12089
+ case '</tableStyle>': tableStyle = null; break;
12090
+ case '<tableStyleElement': case '<tableStyleElement>': case '<tableStyleElement/>':
12091
+ if(tableStyle && tableStyle.elements.length < 64 && table_style_element_type(y.type) && y.dxfId != null) tableStyle.elements.push({
12092
+ type:y.type,
12093
+ dxfId:parseInt(y.dxfId, 10),
12094
+ size:y.size != null ? Math.max(1, parseInt(y.size, 10) || 1) : 1
12095
+ });
12096
+ break;
12097
+ case '<extLst': case '<extLst>': case '</extLst>': break;
12098
+ case '<ext': pass = true; break;
12099
+ case '</ext>': pass = false; break;
12100
+ default: if(opts && opts.WTF && !pass) throw new Error('unrecognized ' + y[0] + ' in tableStyles');
12101
+ }
12102
+ });
12103
+ }
12104
+
12022
12105
  function parse_colors(t, styles, themes, opts) {
12023
12106
  styles.Colors = {indexedColors:[], mruColors:[], themeColors:[]};
12024
12107
  var target = null, pass = false;
@@ -12097,6 +12180,7 @@ return function parse_sty_xml(data, themes, opts) {
12097
12180
  if((t=str_match_xml_ns(data, "dxfs"))) parse_dxfs(t[0], styles, themes, opts);
12098
12181
 
12099
12182
  /* 18.8.42 tableStyles CT_TableStyles ? */
12183
+ if((t=str_match_xml_ns(data, "tableStyles"))) parse_tableStyles(t[0], styles, opts);
12100
12184
  /* 18.8.11 colors CT_Colors ? */
12101
12185
  if((t=str_match_xml_ns(data, "colors"))) parse_colors(t[0], styles, themes, opts);
12102
12186
 
@@ -13262,7 +13346,7 @@ function parse_drawing_anchor(data) {
13262
13346
  function parse_drawing_text(data) {
13263
13347
  var out = [];
13264
13348
  (data.match(/<a:t\b[^>]*>[\s\S]*?<\/a:t>/g)||[]).forEach(function(t) {
13265
- out.push(unescapexml(t.replace(/<[^>]*>/g, "")));
13349
+ out.push(unescapexml(strip_xml_tags(t)));
13266
13350
  });
13267
13351
  return out.join("");
13268
13352
  }
@@ -16625,7 +16709,11 @@ function validate_merges(ws/*:Worksheet*/, opts/*:?any*/) {
16625
16709
  errors.push({code:"E_MERGE_OVERLAP", message:"Merge ranges overlap", index:i, other:j, range:enc, otherRange:encode_range(merges[j])});
16626
16710
  }
16627
16711
  }
16628
- if(errors.length && opts && opts.WTF) throw new Error(errors[0].message + " (" + (errors[0].range || errors[0].index) + ")");
16712
+ if(errors.length && opts && opts.WTF) {
16713
+ var err/*:any*/ = new Error(errors[0].message + " (" + (errors[0].range || errors[0].index) + ")");
16714
+ err.code = errors[0].code;
16715
+ throw err;
16716
+ }
16629
16717
  return errors;
16630
16718
  }
16631
16719
 
@@ -16643,7 +16731,25 @@ var mergecregex = /<(?:\w+:)?mergeCell ref=["'][A-Z0-9:]+['"]\s*[\/]?>/g;
16643
16731
  var hlinkregex = /<(?:\w+:)?hyperlink [^<>]*>/mg;
16644
16732
  var dimregex = /"(\w*:\w*)"/;
16645
16733
  var colregex = /<(?:\w+:)?col\b[^<>]*[\/]?>/g;
16646
- var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g;
16734
+ function match_ws_xml_autofilter(data/*:string*/)/*:?string*/ {
16735
+ var paired = str_match_xml_ns(data, "autoFilter");
16736
+ if(paired) return paired[0];
16737
+ var start = 0;
16738
+ while((start = data.indexOf("<", start)) != -1) {
16739
+ var end = data.indexOf(">", start + 1);
16740
+ if(end == -1) return null;
16741
+ var tag = data.slice(start + 1, end), p = 0;
16742
+ while(p < tag.length && tag.charCodeAt(p) <= 32) ++p;
16743
+ var nameEnd = p;
16744
+ while(nameEnd < tag.length && tag.charCodeAt(nameEnd) > 32 && tag.charAt(nameEnd) != "/") ++nameEnd;
16745
+ var name = tag.slice(p, nameEnd), colon = name.indexOf(":");
16746
+ if(colon != -1) name = name.slice(colon + 1);
16747
+ var tail = tag.slice(nameEnd).trim();
16748
+ if(name == "autoFilter" && tail.charAt(tail.length - 1) == "/") return data.slice(start, end + 1);
16749
+ start = end + 1;
16750
+ }
16751
+ return null;
16752
+ }
16647
16753
  var marginregex= /<(?:\w+:)?pageMargins[^<>]*\/>/g;
16648
16754
  var sheetprregex = /<(?:\w+:)?sheetPr\b[^<>]*?\/>/;
16649
16755
 
@@ -16692,8 +16798,8 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
16692
16798
  if(mtch) parse_ws_xml_data(mtch[1], s, opts, refguess, themes, styles, wb);
16693
16799
 
16694
16800
  /* 18.3.1.2 autoFilter CT_AutoFilter */
16695
- var afilter = data2.match(afregex);
16696
- if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]);
16801
+ var afilter = match_ws_xml_autofilter(data2);
16802
+ if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter);
16697
16803
 
16698
16804
  /* 18.3.1.55 mergeCells CT_MergeCells */
16699
16805
  var merges/*:Array<Range>*/ = [];
@@ -16731,7 +16837,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBPro
16731
16837
  if(columns.length > 0) s["!cols"] = columns;
16732
16838
  if(merges.length > 0) {
16733
16839
  s["!merges"] = merges;
16734
- var mergeErrors = validate_merges(s, {WTF: !!(opts && (opts.WTF || opts.validateMerges))});
16840
+ var mergeErrors = validate_merges(s, {WTF: !!(opts && opts.validateMerges)});
16735
16841
  if(mergeErrors.length) s["!mergeErrors"] = mergeErrors;
16736
16842
  }
16737
16843
  if(rels['!id'][s['!rel']]) s['!drawel'] = rels['!id'][s['!rel']];
@@ -16846,7 +16952,8 @@ function parse_ws_xml_cols(columns, cols) {
16846
16952
  var colm=parseInt(coll.min, 10)-1, colM=parseInt(coll.max,10)-1;
16847
16953
  if(coll.outlineLevel) coll.level = (+coll.outlineLevel || 0);
16848
16954
  delete coll.min; delete coll.max; coll.width = +coll.width;
16849
- /* OOXML widths share the workbook Normal-font MDW; do not infer a different scale per sheet. */
16955
+ /* OOXML widths share the workbook Normal-font MDW. Do not infer it from
16956
+ * one ambiguous stored width or leak another worksheet's scale. */
16850
16957
  if(!seencol && coll.width) { seencol = true; MDW = DEF_MDW; }
16851
16958
  process_col(coll);
16852
16959
  while(colm <= colM) columns[colm++] = dup(coll);
@@ -17218,7 +17325,7 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
17218
17325
  'xmlns:r': XMLNS.r
17219
17326
  })];
17220
17327
  var s = wb.SheetNames[idx], sidx = 0, rdata = "";
17221
- var ws = wb.Sheets[s];
17328
+ var ws = sheet_map_get(wb.Sheets, s);
17222
17329
  if(ws == null) ws = {};
17223
17330
  var ref = ws['!ref'] || 'A1';
17224
17331
  var range = safe_decode_range(ref);
@@ -17269,7 +17376,7 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
17269
17376
  /* customSheetViews */
17270
17377
 
17271
17378
  if(ws['!merges'] != null && ws['!merges'].length > 0) {
17272
- validate_merges(ws, {WTF:true});
17379
+ validate_merges(ws, {WTF: !!(opts && opts.validateMerges)});
17273
17380
  o[o.length] = (write_ws_xml_merges(ws['!merges']));
17274
17381
  }
17275
17382
 
@@ -17334,6 +17441,312 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
17334
17441
  if(o.length>1) { o[o.length] = ('</worksheet>'); o[1]=o[1].replace("/>",">"); }
17335
17442
  return o.join("");
17336
17443
  }
17444
+ var TABLE_STYLE_MAX_TABLES = 1024;
17445
+ var TABLE_STYLE_MAX_COLUMNS = 16384;
17446
+ var TABLE_STYLE_MAX_XML_LENGTH = 5 * 1024 * 1024;
17447
+ var TABLE_STYLE_ELEMENT_TYPES = {
17448
+ wholeTable:true, headerRow:true, totalRow:true,
17449
+ firstColumn:true, lastColumn:true,
17450
+ firstRowStripe:true, secondRowStripe:true,
17451
+ firstColumnStripe:true, secondColumnStripe:true,
17452
+ firstHeaderCell:true, lastHeaderCell:true,
17453
+ firstTotalCell:true, lastTotalCell:true
17454
+ };
17455
+
17456
+ function table_style_safe_key(key) {
17457
+ return key != "__proto__" && key != "constructor" && key != "prototype";
17458
+ }
17459
+
17460
+ function table_style_element_type(type) {
17461
+ return Object.prototype.hasOwnProperty.call(TABLE_STYLE_ELEMENT_TYPES, type);
17462
+ }
17463
+
17464
+ function table_style_attr(y, name) {
17465
+ if(y[name] != null) return y[name];
17466
+ return y[name.toLowerCase()];
17467
+ }
17468
+
17469
+ function table_style_bool(y, name, fallback) {
17470
+ var value = table_style_attr(y, name);
17471
+ return value == null ? fallback : parsexmlbool(value);
17472
+ }
17473
+
17474
+ function table_style_int(y, name) {
17475
+ var value = table_style_attr(y, name);
17476
+ if(value == null || value === "") return void 0;
17477
+ value = parseInt(value, 10);
17478
+ return isFinite(value) && value >= 0 ? value : void 0;
17479
+ }
17480
+
17481
+ function table_style_merge(target, source) {
17482
+ if(!source) return target;
17483
+ if(!target) target = {};
17484
+ keys(source).forEach(function(k) {
17485
+ if(!table_style_safe_key(k)) return;
17486
+ var value = source[k];
17487
+ if(value && typeof value == "object" && !Array.isArray(value)) {
17488
+ target[k] = table_style_merge(
17489
+ target[k] && typeof target[k] == "object" && !Array.isArray(target[k]) ? table_style_merge({}, target[k]) : {},
17490
+ value
17491
+ );
17492
+ } else target[k] = value;
17493
+ });
17494
+ return target;
17495
+ }
17496
+
17497
+ function table_style_color(themes, theme, tint) {
17498
+ return style_color_from_attrs({theme:String(theme), tint:String(tint || 0)}, themes);
17499
+ }
17500
+
17501
+ function table_style_fill(color) {
17502
+ return {fill:{patternType:"solid", fgColor:color}};
17503
+ }
17504
+
17505
+ function table_style_font(color, bold) {
17506
+ var font = {};
17507
+ if(color) font.color = color;
17508
+ if(bold) font.bold = 1;
17509
+ return {font:font};
17510
+ }
17511
+
17512
+ function table_style_border(side, color, style) {
17513
+ var border = {}, out = {border:border};
17514
+ border[side] = {style:style || "thin", color:color};
17515
+ return out;
17516
+ }
17517
+
17518
+ function table_style_accent(themes, index) {
17519
+ var position = (index - 1) % 7;
17520
+ /* The first style in each seven-style family is neutral. The remaining
17521
+ * six entries use the workbook's accent1..accent6 colors. */
17522
+ return table_style_color(themes, position ? 3 + position : 1, 0);
17523
+ }
17524
+
17525
+ function built_in_table_style_rules(name, themes) {
17526
+ var match = /^TableStyle(Light|Medium|Dark)(\d+)$/i.exec(name || "");
17527
+ if(!match) return null;
17528
+ var family = match[1].toLowerCase(), index = parseInt(match[2], 10);
17529
+ var maximum = family == "light" ? 21 : family == "medium" ? 28 : 11;
17530
+ if(index < 1 || index > maximum) return null;
17531
+ var accent = table_style_accent(themes, index);
17532
+ var white = table_style_color(themes, 0, 0);
17533
+ var dark = table_style_color(themes, 1, 0);
17534
+ var rules = {};
17535
+
17536
+ if(family == "light") {
17537
+ rules.headerRow = table_style_merge(
17538
+ table_style_font(accent, true),
17539
+ table_style_border("bottom", accent, "medium")
17540
+ );
17541
+ rules.totalRow = table_style_merge(
17542
+ table_style_font(accent, true),
17543
+ table_style_border("top", accent, "double")
17544
+ );
17545
+ rules.firstRowStripe = table_style_fill(table_style_color(themes, accent.theme, 0.9));
17546
+ rules.firstColumnStripe = rules.firstRowStripe;
17547
+ } else if(family == "medium") {
17548
+ var group = Math.floor((index - 1) / 7);
17549
+ rules.headerRow = table_style_merge(table_style_fill(accent), table_style_font(white, true));
17550
+ rules.totalRow = table_style_merge(
17551
+ table_style_font(accent, true),
17552
+ table_style_border("top", accent, "double")
17553
+ );
17554
+ if(group == 1) {
17555
+ /* Medium 8..14 use two theme-derived body fills. This is the family
17556
+ * used by Excel's TableStyleMedium13. */
17557
+ rules.wholeTable = table_style_fill(table_style_color(themes, accent.theme, 0.8));
17558
+ rules.firstRowStripe = table_style_fill(table_style_color(themes, accent.theme, 0.6));
17559
+ rules.firstColumnStripe = rules.firstRowStripe;
17560
+ } else if(group == 2) {
17561
+ rules.firstRowStripe = table_style_fill(table_style_color(themes, accent.theme, 0.8));
17562
+ rules.firstColumnStripe = rules.firstRowStripe;
17563
+ rules.wholeTable = table_style_border("bottom", table_style_color(themes, accent.theme, 0.4), "thin");
17564
+ } else if(group == 3) {
17565
+ rules.wholeTable = table_style_fill(table_style_color(themes, accent.theme, 0.9));
17566
+ rules.firstRowStripe = table_style_fill(table_style_color(themes, accent.theme, 0.7));
17567
+ rules.firstColumnStripe = rules.firstRowStripe;
17568
+ } else {
17569
+ rules.firstRowStripe = table_style_fill(table_style_color(themes, accent.theme, 0.8));
17570
+ rules.firstColumnStripe = rules.firstRowStripe;
17571
+ }
17572
+ } else {
17573
+ rules.wholeTable = table_style_merge(table_style_fill(dark), table_style_font(white, false));
17574
+ rules.headerRow = table_style_merge(table_style_fill(accent), table_style_font(white, true));
17575
+ rules.firstRowStripe = table_style_fill(table_style_color(themes, accent.theme, -0.35));
17576
+ rules.firstColumnStripe = rules.firstRowStripe;
17577
+ rules.totalRow = table_style_merge(
17578
+ table_style_font(white, true),
17579
+ table_style_border("top", accent, "double")
17580
+ );
17581
+ }
17582
+
17583
+ rules.firstColumn = table_style_font(null, true);
17584
+ rules.lastColumn = table_style_font(null, true);
17585
+ return rules;
17586
+ }
17587
+
17588
+ function custom_table_style_rules(name, styles) {
17589
+ var tableStyles = styles && styles.TableStyles;
17590
+ if(!tableStyles || !tableStyles.styles) return null;
17591
+ for(var i = 0; i < tableStyles.styles.length; ++i) {
17592
+ var tableStyle = tableStyles.styles[i];
17593
+ if(tableStyle.name != name) continue;
17594
+ var rules = Object.create(null);
17595
+ (tableStyle.elements || []).forEach(function(element) {
17596
+ if(!table_style_element_type(element.type)) return;
17597
+ var dxf = styles.Dxfs && styles.Dxfs[element.dxfId];
17598
+ if(dxf) rules[element.type] = {style:dup(dxf), size:element.size || 1};
17599
+ });
17600
+ return rules;
17601
+ }
17602
+ return null;
17603
+ }
17604
+
17605
+ function parse_table_xml(data, path, themes, styles, opts) {
17606
+ if(!data || data.length > TABLE_STYLE_MAX_XML_LENGTH) return null;
17607
+ data = remove_doctype(str_remove_ng(data, "<!--", "-->"));
17608
+ var table = {columns:[]}, column = null, pass = false;
17609
+ (data.match(tagregex)||[]).forEach(function(x) {
17610
+ var y = parsexmltag(x), tag = strip_ns(y[0]);
17611
+ switch(tag) {
17612
+ case '<table': case '<table>':
17613
+ table.id = table_style_int(y, "id");
17614
+ table.name = utf8read(unescapexml(table_style_attr(y, "name") || ""));
17615
+ table.displayName = utf8read(unescapexml(table_style_attr(y, "displayName") || table.name));
17616
+ table.ref = table_style_attr(y, "ref") || "";
17617
+ table.headerRowCount = table_style_int(y, "headerRowCount");
17618
+ table.totalsRowCount = table_style_int(y, "totalsRowCount");
17619
+ table.totalsRowShown = table_style_bool(y, "totalsRowShown", false);
17620
+ table.headerRowDxfId = table_style_int(y, "headerRowDxfId");
17621
+ table.dataDxfId = table_style_int(y, "dataDxfId");
17622
+ table.totalsRowDxfId = table_style_int(y, "totalsRowDxfId");
17623
+ table.path = path;
17624
+ break;
17625
+ case '<tableColumn': case '<tableColumn>': case '<tableColumn/>':
17626
+ if(table.columns.length >= TABLE_STYLE_MAX_COLUMNS) {
17627
+ column = null;
17628
+ break;
17629
+ }
17630
+ column = {
17631
+ id:table_style_int(y, "id"),
17632
+ name:utf8read(unescapexml(table_style_attr(y, "name") || "")),
17633
+ headerRowDxfId:table_style_int(y, "headerRowDxfId"),
17634
+ dataDxfId:table_style_int(y, "dataDxfId"),
17635
+ totalsRowDxfId:table_style_int(y, "totalsRowDxfId")
17636
+ };
17637
+ table.columns.push(column);
17638
+ if(tag.slice(-2) == "/>" ) column = null;
17639
+ break;
17640
+ case '</tableColumn>': column = null; break;
17641
+ case '<tableStyleInfo': case '<tableStyleInfo>': case '<tableStyleInfo/>':
17642
+ table.styleInfo = {
17643
+ name:utf8read(unescapexml(table_style_attr(y, "name") || "")),
17644
+ showFirstColumn:table_style_bool(y, "showFirstColumn", false),
17645
+ showLastColumn:table_style_bool(y, "showLastColumn", false),
17646
+ showRowStripes:table_style_bool(y, "showRowStripes", false),
17647
+ showColumnStripes:table_style_bool(y, "showColumnStripes", false)
17648
+ };
17649
+ break;
17650
+ case '<extLst': case '<extLst>': case '</extLst>': break;
17651
+ case '<ext': pass = true; break;
17652
+ case '</ext>': pass = false; break;
17653
+ default: if(opts && opts.WTF && !pass) {
17654
+ /* Table formulas and filter metadata are intentionally preserved by
17655
+ * the raw XML parser but do not affect visual style resolution. */
17656
+ if(/^<\/?(?:tableColumns|autoFilter|sortState|calculatedColumnFormula|totalsRowFormula|xmlColumnPr)/.test(tag)) break;
17657
+ }
17658
+ }
17659
+ });
17660
+ if(!table.ref) return null;
17661
+ try {
17662
+ table.range = safe_decode_range(table.ref);
17663
+ if(table.range.s.r < 0 || table.range.s.c < 0 || table.range.e.r > 1048575 || table.range.e.c > 16383) return null;
17664
+ } catch(e) { return null; }
17665
+ var styleName = table.styleInfo && table.styleInfo.name;
17666
+ table.styleRules = custom_table_style_rules(styleName, styles) || built_in_table_style_rules(styleName, themes) || {};
17667
+ table.dxfs = styles && styles.Dxfs ? styles.Dxfs : [];
17668
+ return table;
17669
+ }
17670
+
17671
+ function parse_sheet_tables(sheet, zip, path, rels, opts, themes, styles) {
17672
+ if(!sheet || !rels || !rels['!id'] || !opts || !opts.cellStyles) return;
17673
+ var tables = [], seen = Object.create(null);
17674
+ keys(rels['!id']).forEach(function(id) {
17675
+ if(tables.length >= TABLE_STYLE_MAX_TABLES) return;
17676
+ var rel = rels['!id'][id];
17677
+ if(!rel || rel.TargetMode == "External" || typeof rel.Target != "string" || !rel.Target ||
17678
+ (rel.Type != RELS.TABLE && !/\/table$/.test(rel.Type || ""))) return;
17679
+ var tablePath = resolve_path(rel.Target, path);
17680
+ if(seen[tablePath]) return;
17681
+ seen[tablePath] = true;
17682
+ var table = parse_table_xml(getzipstr(zip, tablePath, true), tablePath, themes, styles, opts);
17683
+ if(table) tables.push(table);
17684
+ });
17685
+ if(tables.length) sheet['!tables'] = tables;
17686
+ }
17687
+
17688
+ function table_style_rule_value(rule) {
17689
+ return rule && rule.style ? rule.style : rule;
17690
+ }
17691
+
17692
+ function table_style_stripe_rule(first, second, offset) {
17693
+ var firstSize = first && first.size || 1, secondSize = second && second.size || 1;
17694
+ var period = firstSize + secondSize;
17695
+ if(!period) return null;
17696
+ return offset % period < firstSize ? first : second;
17697
+ }
17698
+
17699
+ function table_style_dxf(table, id) {
17700
+ return id == null || !table.dxfs ? null : table.dxfs[id];
17701
+ }
17702
+
17703
+ function resolve_table_cell_style(ws, row, col, baseStyle) {
17704
+ var tables = ws && ws['!tables'];
17705
+ var resolved = baseStyle ? table_style_merge({}, baseStyle) : {};
17706
+ if(!tables || !tables.length) return keys(resolved).length ? resolved : void 0;
17707
+ for(var i = 0; i < tables.length; ++i) {
17708
+ var table = tables[i], range = table.range;
17709
+ if(!range || row < range.s.r || row > range.e.r || col < range.s.c || col > range.e.c) continue;
17710
+ var rules = table.styleRules || {}, info = table.styleInfo || {};
17711
+ var rowOffset = row - range.s.r, colOffset = col - range.s.c;
17712
+ var headerRows = table.headerRowCount == null ? 1 : table.headerRowCount;
17713
+ var totalRows = table.totalsRowCount != null ? table.totalsRowCount : table.totalsRowShown ? 1 : 0;
17714
+ var dataStart = headerRows, dataEnd = range.e.r - range.s.r - totalRows;
17715
+ var isHeader = rowOffset < headerRows;
17716
+ var isTotal = totalRows > 0 && rowOffset > dataEnd;
17717
+ var dataOffset = rowOffset - dataStart;
17718
+ var column = table.columns && table.columns[colOffset];
17719
+
17720
+ resolved = table_style_merge(resolved, table_style_rule_value(rules.wholeTable));
17721
+ if(!isHeader && !isTotal && dataOffset >= 0) {
17722
+ if(info.showRowStripes) resolved = table_style_merge(resolved, table_style_rule_value(
17723
+ table_style_stripe_rule(rules.firstRowStripe, rules.secondRowStripe, dataOffset)
17724
+ ));
17725
+ if(info.showColumnStripes) resolved = table_style_merge(resolved, table_style_rule_value(
17726
+ table_style_stripe_rule(rules.firstColumnStripe, rules.secondColumnStripe, colOffset)
17727
+ ));
17728
+ }
17729
+ if(info.showFirstColumn && col == range.s.c) resolved = table_style_merge(resolved, table_style_rule_value(rules.firstColumn));
17730
+ if(info.showLastColumn && col == range.e.c) resolved = table_style_merge(resolved, table_style_rule_value(rules.lastColumn));
17731
+ if(isHeader) {
17732
+ resolved = table_style_merge(resolved, table_style_rule_value(rules.headerRow));
17733
+ if(col == range.s.c) resolved = table_style_merge(resolved, table_style_rule_value(rules.firstHeaderCell));
17734
+ if(col == range.e.c) resolved = table_style_merge(resolved, table_style_rule_value(rules.lastHeaderCell));
17735
+ resolved = table_style_merge(resolved, table_style_dxf(table, table.headerRowDxfId));
17736
+ resolved = table_style_merge(resolved, table_style_dxf(table, column && column.headerRowDxfId));
17737
+ } else if(isTotal) {
17738
+ resolved = table_style_merge(resolved, table_style_rule_value(rules.totalRow));
17739
+ if(col == range.s.c) resolved = table_style_merge(resolved, table_style_rule_value(rules.firstTotalCell));
17740
+ if(col == range.e.c) resolved = table_style_merge(resolved, table_style_rule_value(rules.lastTotalCell));
17741
+ resolved = table_style_merge(resolved, table_style_dxf(table, table.totalsRowDxfId));
17742
+ resolved = table_style_merge(resolved, table_style_dxf(table, column && column.totalsRowDxfId));
17743
+ } else {
17744
+ resolved = table_style_merge(resolved, table_style_dxf(table, table.dataDxfId));
17745
+ resolved = table_style_merge(resolved, table_style_dxf(table, column && column.dataDxfId));
17746
+ }
17747
+ }
17748
+ return keys(resolved).length ? resolved : void 0;
17749
+ }
17337
17750
 
17338
17751
  /* [MS-XLSB] 2.4.726 BrtRowHdr */
17339
17752
  function parse_BrtRowHdr(data, length) {
@@ -18332,7 +18745,7 @@ function write_SHEETPROTECT(ba, ws) {
18332
18745
 
18333
18746
  function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
18334
18747
  var ba = buf_array();
18335
- var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
18748
+ var s = wb.SheetNames[idx], ws = sheet_map_get(wb.Sheets, s) || {};
18336
18749
  var c/*:string*/ = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
18337
18750
  var r = safe_decode_range(ws['!ref'] || "A1");
18338
18751
  if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
@@ -18400,7 +18813,7 @@ function parse_Cache(data/*:string*/)/*:[Array<number|string>, string, ?string]*
18400
18813
  /* 21.2.2.71 formatCode CT_Xstring */
18401
18814
  var nf = unescapexml((str_match_xml(data, "c:formatCode") || ["","General"])[1]);
18402
18815
 
18403
- (str_match_ng(data, "<c:f>", "</c:f>")||[]).forEach(function(F) { f = F.replace(/<[^<>]*>/g,""); });
18816
+ (str_match_ng(data, "<c:f>", "</c:f>")||[]).forEach(function(F) { f = strip_xml_tags(F); });
18404
18817
 
18405
18818
  return [col, nf, f];
18406
18819
  }
@@ -18417,7 +18830,7 @@ function parse_chart_cache(data) {
18417
18830
  return {values:s[0], formatCode:s[1], formula:s[2]};
18418
18831
  }
18419
18832
  var f = (str_match_ng(data, "<c:f>", "</c:f>")||[])[0];
18420
- return {values:[], formula:f ? f.replace(/<[^<>]*>/g,"") : void 0};
18833
+ return {values:[], formula:f ? strip_xml_tags(f) : void 0};
18421
18834
  }
18422
18835
 
18423
18836
  function parse_chart_tx(data) {
@@ -18449,7 +18862,7 @@ function parse_chart_title(data) {
18449
18862
  var title = str_match_xml_ns(data, "title");
18450
18863
  if(!title) return "";
18451
18864
  var out = [];
18452
- (title[0].match(/<a:t\b[^>]*>[\s\S]*?<\/a:t>/g)||[]).forEach(function(t) { out.push(unescapexml(t.replace(/<[^>]*>/g, ""))); });
18865
+ (title[0].match(/<a:t\b[^>]*>[\s\S]*?<\/a:t>/g)||[]).forEach(function(t) { out.push(unescapexml(strip_xml_tags(t))); });
18453
18866
  return out.join("");
18454
18867
  }
18455
18868
 
@@ -18754,9 +19167,12 @@ function check_wb(wb) {
18754
19167
  if(!wb.SheetNames.length) throw new Error("Workbook is empty");
18755
19168
  var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
18756
19169
  check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
18757
- for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
19170
+ for(var i = 0; i < wb.SheetNames.length; ++i) {
19171
+ var ws = sheet_map_get(wb.Sheets, wb.SheetNames[i]);
19172
+ check_ws(ws, wb.SheetNames[i], i);
19173
+ }
18758
19174
  wb.SheetNames.forEach(function(n, i) {
18759
- var ws = wb.Sheets[n];
19175
+ var ws = sheet_map_get(wb.Sheets, n);
18760
19176
  if(!ws || !ws["!autofilter"]) return;
18761
19177
  var DN;
18762
19178
  if(!wb.Workbook) wb.Workbook = {};
@@ -19545,7 +19961,7 @@ function parse_xlml_data(xml, ss, data, cell/*:any*/, base, styles, csty, row, a
19545
19961
  break;
19546
19962
  case 'String':
19547
19963
  cell.t = 's'; cell.r = xlml_fixstr(unescapexml(xml));
19548
- cell.v = (xml.indexOf("<") > -1 ? unescapexml(ss||xml).replace(/<[^<>]*>/g, "") : cell.r); // todo: BR etc
19964
+ cell.v = (xml.indexOf("<") > -1 ? strip_xml_tags(unescapexml(ss||xml)) : cell.r); // todo: BR etc
19549
19965
  break;
19550
19966
  case 'DateTime':
19551
19967
  if(xml.slice(-1) != "Z") xml += "Z";
@@ -19640,7 +20056,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
19640
20056
  var Rn;
19641
20057
  var state = [], tmp;
19642
20058
  if(DENSE != null && opts.dense == null) opts.dense = DENSE;
19643
- var sheets = {}, sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = ({}), sheetname = ""; if(opts.dense) cursheet["!data"] = [];
20059
+ var sheets = sheet_map_new(), sheetnames/*:Array<string>*/ = [], cursheet/*:Worksheet*/ = ({}), sheetname = ""; if(opts.dense) cursheet["!data"] = [];
19644
20060
  var cell = ({}/*:any*/), row = {};// eslint-disable-line no-unused-vars
19645
20061
  var dtag = xlml_parsexmltag('<Data ss:Type="String">'), didx = 0;
19646
20062
  var c = 0, r = 0;
@@ -19747,7 +20163,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
19747
20163
  if(merges.length) cursheet["!merges"] = merges;
19748
20164
  if(cstys.length > 0) cursheet["!cols"] = cstys;
19749
20165
  if(rowinfo.length > 0) cursheet["!rows"] = rowinfo;
19750
- sheets[sheetname] = cursheet;
20166
+ sheet_map_set(sheets, sheetname, cursheet);
19751
20167
  } else {
19752
20168
  refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} };
19753
20169
  r = c = 0;
@@ -20652,7 +21068,7 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo
20652
21068
  function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ {
20653
21069
  var o/*:Array<string>*/ = [];
20654
21070
  var s = wb.SheetNames[idx];
20655
- var ws = wb.Sheets[s];
21071
+ var ws = sheet_map_get(wb.Sheets, s);
20656
21072
 
20657
21073
  var t/*:string*/ = ws ? write_ws_xlml_names(ws, opts, idx, wb) : "";
20658
21074
  if(t.length > 0) o.push("<Names>" + t + "</Names>");
@@ -20886,7 +21302,7 @@ var parse_BIFFSurface = make_BIFFChartType("surfaceChart");
20886
21302
  // 2.3.2
20887
21303
  function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
20888
21304
  var wb = ({opts:{}}/*:any*/);
20889
- var Sheets = {};
21305
+ var Sheets = sheet_map_new();
20890
21306
  if(DENSE != null && options.dense == null) options.dense = DENSE;
20891
21307
  var out/*:Worksheet*/ = ({}/*:any*/); if(options.dense) out["!data"] = [];
20892
21308
  var Directory = {};
@@ -21181,7 +21597,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
21181
21597
  };
21182
21598
  var finalize_sheet_visuals = function finalizesheetvisuals(ws) {
21183
21599
  if(ws["!merges"] && ws["!merges"].length) {
21184
- var mergeErrors = validate_merges(ws, {WTF: !!(options && (options.WTF || options.validateMerges))});
21600
+ var mergeErrors = validate_merges(ws, {WTF: !!(options && options.validateMerges)});
21185
21601
  if(mergeErrors.length) ws["!mergeErrors"] = mergeErrors;
21186
21602
  }
21187
21603
  if(drawings && (drawings.images.length || drawings.shapes.length || drawings.charts.length || drawings.raw.length)) ws["!drawings"] = drawings;
@@ -21329,7 +21745,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
21329
21745
  finalize_sheet_visuals(out);
21330
21746
  Workbook.Sheets.push(wsprops);
21331
21747
  }
21332
- if(cur_sheet === "") Preamble = out; else Sheets[cur_sheet] = out;
21748
+ if(cur_sheet === "") Preamble = out; else sheet_map_set(Sheets, cur_sheet, out);
21333
21749
  out = ({}/*:any*/); if(options.dense) out["!data"] = [];
21334
21750
  } break;
21335
21751
  case 0x0009: case 0x0209: case 0x0409: case 0x0809 /* BOF */: {
@@ -21629,10 +22045,13 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
21629
22045
  if(!wb.SheetNames.length && Preamble["!ref"]) {
21630
22046
  wb.SheetNames.push("Sheet1");
21631
22047
  /*jshint -W069 */
21632
- if(wb.Sheets) wb.Sheets["Sheet1"] = Preamble;
22048
+ if(wb.Sheets) sheet_map_set(wb.Sheets, "Sheet1", Preamble);
21633
22049
  /*jshint +W069 */
21634
22050
  } else wb.Preamble=Preamble;
21635
- if(wb.Sheets) FilterDatabases.forEach(function(r,i) { wb.Sheets[wb.SheetNames[i]]['!autofilter'] = r; });
22051
+ if(wb.Sheets) FilterDatabases.forEach(function(r,i) {
22052
+ var ws = sheet_map_get(wb.Sheets, wb.SheetNames[i]);
22053
+ if(ws) ws['!autofilter'] = r;
22054
+ });
21636
22055
  wb.Strings = sst;
21637
22056
  wb.SSF = dup(table_fmt);
21638
22057
  if(opts.enc) wb.Encryption = opts.enc;
@@ -23257,7 +23676,7 @@ function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
23257
23676
  o.cellXfs = [{numFmtId: 0}];
23258
23677
  o._BIFF2FmtTable/*:Array<string>*/ = ["General"]; o._Fonts = [];
23259
23678
  var body = buf_array();
23260
- write_ws_biff2(body, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
23679
+ write_ws_biff2(body, sheet_map_get(wb.Sheets, wb.SheetNames[idx]), idx, o, wb);
23261
23680
 
23262
23681
  o._BIFF2FmtTable.forEach(function(f) {
23263
23682
  if(o.biff <= 3) write_biff_rec(ba, 0x001E, write_BIFF2Format(f));
@@ -23668,7 +24087,7 @@ function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
23668
24087
  /* [MS-XLS] 2.1.7.20.5 */
23669
24088
  function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
23670
24089
  var ba = buf_array();
23671
- var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
24090
+ var s = wb.SheetNames[idx], ws = sheet_map_get(wb.Sheets, s) || {};
23672
24091
  var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
23673
24092
  var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/);
23674
24093
  var dense = ws["!data"] != null;
@@ -23737,7 +24156,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
23737
24156
  if(b8) write_biff_rec(ba, 0x023e /* Window2 */, write_Window2((_WB.Views||[])[0]));
23738
24157
  /* ... */
23739
24158
  if(b8 && (ws['!merges']||[]).length) {
23740
- validate_merges(ws, {WTF:true});
24159
+ validate_merges(ws, {WTF: !!(opts && opts.validateMerges)});
23741
24160
  write_biff_rec(ba, 0x00e5 /* MergeCells */, write_MergeCells(ws['!merges']));
23742
24161
  }
23743
24162
  /* [LRng] *QUERYTABLE [PHONETICINFO] CONDFMTS */
@@ -23867,7 +24286,7 @@ function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
23867
24286
 
23868
24287
  function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
23869
24288
  for(var i = 0; i <= wb.SheetNames.length; ++i) {
23870
- var ws = wb.Sheets[wb.SheetNames[i]];
24289
+ var ws = sheet_map_get(wb.Sheets, wb.SheetNames[i]);
23871
24290
  if(!ws || !ws["!ref"]) continue;
23872
24291
  var range = decode_range(ws["!ref"]);
23873
24292
  if(range.e.c > 255) { // note: 255 is IV
@@ -23949,15 +24368,66 @@ function html_to_sheet(str/*:string*/, _opts)/*:Workbook*/ {
23949
24368
  return ws;
23950
24369
  }
23951
24370
 
23952
- function cssesc(x) { return escapexml(String(x).replace(/"/g, "'")); }
23953
24371
  function css_color(color) {
23954
24372
  if(!color) return "";
23955
- if(color.rgb) return "#" + String(color.rgb).slice(-6);
24373
+ if(color.rgb && /^[0-9A-Fa-f]{6}(?:[0-9A-Fa-f]{2})?$/.test(String(color.rgb))) return "#" + String(color.rgb).slice(-6);
23956
24374
  return "";
23957
24375
  }
23958
24376
  function css_font_family(name) {
23959
24377
  if(!name) return "";
23960
- return "'" + cssesc(name).replace(/'/g, "\\'") + "'";
24378
+ return "'" + css_string_escape(name, "'") + "'";
24379
+ }
24380
+
24381
+ function html_attr_escape(value/*:any*/)/*:string*/ {
24382
+ return String(value).replace(/[&<>"']/g, function(ch) {
24383
+ return ch == "&" ? "&amp;" : ch == "<" ? "&lt;" : ch == ">" ? "&gt;" : ch == '"' ? "&quot;" : "&#39;";
24384
+ });
24385
+ }
24386
+ function html_writextag(tag/*:string*/, content/*:?string*/, attrs)/*:string*/ {
24387
+ var out = ["<", tag];
24388
+ if(attrs) keys(attrs).forEach(function(key) { out.push(" ", key, '="', html_attr_escape(attrs[key]), '"'); });
24389
+ if(content == null) { out.push("/>"); return out.join(""); }
24390
+ out.push(">", content, "</", tag, ">");
24391
+ return out.join("");
24392
+ }
24393
+ function safe_html_href(value/*:any*/)/*:?string*/ {
24394
+ var href = String(value == null ? "" : value).trim();
24395
+ if(!href || href.slice(0, 2) == "//") return null;
24396
+ var colon = href.indexOf(":"), prefix = colon == -1 ? "" : href.slice(0, colon), compact = "";
24397
+ for(var i = 0; i < prefix.length; ++i) if(prefix.charCodeAt(i) > 32 && prefix.charCodeAt(i) != 127) compact += prefix.charAt(i);
24398
+ if(colon != -1 && !/^(?:https?|mailto|tel)$/i.test(compact)) return null;
24399
+ return href;
24400
+ }
24401
+ function safe_html_image_src(value/*:any*/)/*:?string*/ {
24402
+ var src = String(value == null ? "" : value);
24403
+ return /^data:image\/[A-Za-z0-9.+-]+;base64,[A-Za-z0-9+/=\r\n]+$/.test(src) ? src : null;
24404
+ }
24405
+ function sanitize_cell_html(value/*:any*/)/*:string*/ {
24406
+ var html = String(value == null ? "" : value), out = [], pos = 0;
24407
+ while(pos < html.length) {
24408
+ var start = html.indexOf("<", pos);
24409
+ if(start == -1) { out.push(html.slice(pos)); break; }
24410
+ out.push(html.slice(pos, start));
24411
+ var end = html.indexOf(">", start + 1);
24412
+ if(end == -1) { out.push("&lt;", html.slice(start + 1)); break; }
24413
+ var raw = html.slice(start + 1, end).trim(), lower = raw.toLowerCase();
24414
+ if(/^(?:\/?(?:b|i|s|sup|sub)|br\s*\/?)$/.test(lower)) out.push("<", lower == "br" ? "br/" : lower, ">");
24415
+ else if(lower == "/span") out.push("</span>");
24416
+ else if(lower.slice(0, 12) == 'span style="' && raw.charAt(raw.length - 1) == '"') {
24417
+ var declarations = raw.slice(12, -1).split(";"), safe = [];
24418
+ declarations.forEach(function(decl) {
24419
+ var colon = decl.indexOf(":"), key = colon == -1 ? "" : decl.slice(0, colon).trim().toLowerCase(), val = colon == -1 ? "" : decl.slice(colon + 1).trim().toLowerCase();
24420
+ if(key == "text-decoration" && val == "underline") safe.push("text-decoration:underline");
24421
+ else if(key == "text-underline-style" && /^(?:single|double|single-accounting|double-accounting)$/.test(val)) safe.push("text-underline-style:" + val);
24422
+ else if(key == "font-size" && /^\d+(?:\.\d+)?pt$/.test(val)) safe.push("font-size:" + val);
24423
+ else if(key == "text-effect" && val == "outline") safe.push("text-effect:outline");
24424
+ else if(key == "text-shadow" && val == "auto") safe.push("text-shadow:auto");
24425
+ });
24426
+ out.push('<span style="', safe.join(";"), safe.length ? ";" : "", '">');
24427
+ } else out.push(html_attr_escape(html.slice(start, end + 1)));
24428
+ pos = end + 1;
24429
+ }
24430
+ return out.join("");
23961
24431
  }
23962
24432
  function html_border_style(style) {
23963
24433
  switch(style) {
@@ -23986,7 +24456,8 @@ function html_cell_style(cell/*:Cell*/, opts/*:Sheet2HTMLOpts*/) {
23986
24456
  var s = cell.s, css = [];
23987
24457
  var font = s.font || {};
23988
24458
  if(font.name) css.push("font-family:" + css_font_family(font.name));
23989
- if(font.sz) css.push("font-size:" + font.sz + "pt");
24459
+ var fontSize = +font.sz;
24460
+ if(isFinite(fontSize) && fontSize > 0) css.push("font-size:" + Math.min(fontSize, 409) + "pt");
23990
24461
  if(font.bold) css.push("font-weight:bold");
23991
24462
  if(font.italic) css.push("font-style:italic");
23992
24463
  var deco = [];
@@ -23999,8 +24470,9 @@ function html_cell_style(cell/*:Cell*/, opts/*:Sheet2HTMLOpts*/) {
23999
24470
  if(fill.patternType != "none" && fill.patternType != "gray125") fillColor = css_color(fill.fgColor) || css_color(fill.bgColor);
24000
24471
  if(fillColor) css.push("background-color:" + fillColor);
24001
24472
  var alignment = s.alignment || {};
24002
- if(alignment.horizontal) css.push("text-align:" + alignment.horizontal);
24003
- if(alignment.vertical) css.push("vertical-align:" + alignment.vertical);
24473
+ if(/^(?:left|right|center|justify|fill|distributed)$/.test(alignment.horizontal || "")) css.push("text-align:" + alignment.horizontal);
24474
+ var vertical = alignment.vertical == "center" ? "middle" : alignment.vertical;
24475
+ if(/^(?:top|middle|bottom|baseline)$/.test(vertical || "")) css.push("vertical-align:" + vertical);
24004
24476
  if(alignment.textRotation != null && alignment.textRotation !== 0) {
24005
24477
  var deg = alignment.textRotation == 255 ? 90 : alignment.textRotation > 90 ? 90 - alignment.textRotation : alignment.textRotation;
24006
24478
  css.push("transform:rotate(" + deg + "deg)");
@@ -24073,13 +24545,14 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
24073
24545
  if(cols[C] && cols[C].s) extend_style_obj(inherited, cols[C].s);
24074
24546
  if(row && row.s) extend_style_obj(inherited, row.s);
24075
24547
  if(cell && cell.s) extend_style_obj(inherited, cell.s);
24548
+ inherited = resolve_table_cell_style(ws, R, C, inherited) || inherited;
24076
24549
  if(keys(inherited).length) {
24077
24550
  stylecell = cell ? dup(cell) : {t:'z'};
24078
24551
  stylecell.s = inherited;
24079
24552
  }
24080
24553
  }
24081
24554
  /* TODO: html entities */
24082
- var w = (cell && cell.v != null) && (cell.h || escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
24555
+ var w = (cell && cell.v != null) && (cell.h ? sanitize_cell_html(cell.h) : escapehtml(cell.w || (format_cell(cell), cell.w) || "")) || "";
24083
24556
  sp = ({}/*:any*/);
24084
24557
  if(RS > 1) sp.rowspan = RS;
24085
24558
  if(CS > 1) sp.colspan = CS;
@@ -24087,17 +24560,18 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
24087
24560
  else if(cell) {
24088
24561
  sp["data-t"] = cell && cell.t || 'z';
24089
24562
  // note: data-v is unaffected by the timezone interpretation
24090
- if(cell.v != null) sp["data-v"] = escapehtml(cell.v instanceof Date ? cell.v.toISOString() : cell.v);
24563
+ if(cell.v != null) sp["data-v"] = cell.v instanceof Date ? cell.v.toISOString() : cell.v;
24091
24564
  if(cell.z != null) sp["data-z"] = cell.z;
24092
- if(cell.f != null) sp["data-f"] = escapehtml(cell.f);
24093
- if(cell.l && (cell.l.Target || "#").charAt(0) != "#" && (!o.sanitizeLinks || (cell.l.Target || "").slice(0, 11).toLowerCase() != 'javascript:')) w = '<a href="' + escapehtml(cell.l.Target) +'">' + w + '</a>';
24565
+ if(cell.f != null) sp["data-f"] = cell.f;
24566
+ var href = cell.l && safe_html_href(cell.l.Target);
24567
+ if(href) w = '<a href="' + html_attr_escape(href) +'">' + w + '</a>';
24094
24568
  }
24095
24569
  var cstyle = html_cell_style(stylecell, o);
24096
24570
  var lstyle = html_cell_layout_style(stylecell, o, C, CS, cols);
24097
24571
  if(lstyle) cstyle = cstyle ? cstyle + ";" + lstyle : lstyle;
24098
24572
  if(cstyle) sp.style = cstyle;
24099
24573
  sp.id = (o.id || "sjs") + "-" + coord;
24100
- oo.push(writextag('td', w, sp));
24574
+ oo.push(html_writextag('td', w, sp));
24101
24575
  }
24102
24576
  var rsp = ({}/*:any*/), rstyle = [];
24103
24577
  if(row) {
@@ -24105,7 +24579,7 @@ function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HT
24105
24579
  if(o.browserPixels) rstyle.push("height:" + html_row_height(row) + "px");
24106
24580
  }
24107
24581
  if(rstyle.length) rsp.style = rstyle.join(";");
24108
- return writextag('tr', oo.join(""), rsp);
24582
+ return html_writextag('tr', oo.join(""), rsp);
24109
24583
  }
24110
24584
 
24111
24585
  var HTML_BEGIN = '<html><head><meta charset="utf-8"/><title>SheetJS Table Export</title></head><body>';
@@ -24241,8 +24715,10 @@ function render_html_drawings(ws, opts) {
24241
24715
  var out = [], drawings = ws["!drawings"] || {}, charts = ws["!charts"] || [];
24242
24716
  if(opts && opts.drawings && drawings.images) drawings.images.forEach(function(img) {
24243
24717
  if(!img || !img.dataURI) return;
24718
+ var src = safe_html_image_src(img.dataURI);
24719
+ if(!src) return;
24244
24720
  var pos = html_anchor_pos(ws, img.anchor, opts);
24245
- out.push('<img class="sjs-drawing-image" src="' + img.dataURI + '" style="' + html_abs_style(pos) + '"/>');
24721
+ out.push('<img class="sjs-drawing-image" src="' + html_attr_escape(src) + '" style="' + html_abs_style(pos) + '"/>');
24246
24722
  });
24247
24723
  if(opts && opts.charts) charts.forEach(function(chart) {
24248
24724
  var pos = html_anchor_pos(ws, chart.anchor, opts);
@@ -24257,7 +24733,7 @@ function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)
24257
24733
  if(o && o.id) tattr.id = o.id;
24258
24734
  if(o && (o.browserPixels || o.autoFit)) tstyle.push("border-collapse:collapse;table-layout:fixed");
24259
24735
  if(tstyle.length) tattr.style = tstyle.join(";");
24260
- var table = writextag("table", "", tattr).replace(/<\/table>$/, "");
24736
+ var table = html_writextag("table", "", tattr).replace(/<\/table>$/, "");
24261
24737
  var cols = o && o._htmlCols || ws["!cols"];
24262
24738
  if(o && (o.browserPixels || o.autoFit) && cols) {
24263
24739
  out.push("<colgroup>");
@@ -24265,7 +24741,7 @@ function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)
24265
24741
  var col = cols[C], style = [];
24266
24742
  style.push("width:" + html_col_width(col) + "px");
24267
24743
  if(col && col.hidden) style.push("display:none");
24268
- out.push(writextag("col", null, {style:style.join(";")}));
24744
+ out.push(html_writextag("col", null, {style:style.join(";")}));
24269
24745
  }
24270
24746
  out.push("</colgroup>");
24271
24747
  }
@@ -24432,7 +24908,7 @@ function parse_text_p(text/*:string*//*::, tag*/)/*:Array<any>*/ {
24432
24908
  .replace(/<text:s text:c="(\d+)"\/>/g, function($$,$1) { return Array(parseInt($1,10)+1).join(" "); })
24433
24909
  .replace(/<text:tab[^<>]*\/>/g,"\t")
24434
24910
  .replace(/<text:line-break\/>/g,"\n");
24435
- var v = unescapexml(fixed.replace(/<[^<>]*>/g,""));
24911
+ var v = unescapexml(strip_xml_tags(fixed));
24436
24912
 
24437
24913
  return [v];
24438
24914
  }
@@ -24669,7 +25145,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
24669
25145
  var nfidx, NF = "", pidx = 0;
24670
25146
  var sheetag/*:: = {name:"", '名称':""}*/;
24671
25147
  var rowtag/*:: = {'行号':""}*/;
24672
- var Sheets = {}, SheetNames/*:Array<string>*/ = [];
25148
+ var Sheets = sheet_map_new(), SheetNames/*:Array<string>*/ = [];
24673
25149
  var ws = ({}/*:any*/); if(opts.dense) ws["!data"] = [];
24674
25150
  var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/;
24675
25151
  var ctag = ({value:""}/*:any*/), ctag2 = ({}/*:any*/);
@@ -24706,7 +25182,7 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
24706
25182
  sheetag.name = sheetag['名称'] || sheetag.name;
24707
25183
  if(typeof JSON !== 'undefined') JSON.stringify(sheetag);
24708
25184
  SheetNames.push(sheetag.name);
24709
- Sheets[sheetag.name] = ws;
25185
+ sheet_map_set(Sheets, sheetag.name, ws);
24710
25186
  WB.Sheets.push({
24711
25187
  /* TODO: CodeName */
24712
25188
  Hidden: (tstyles[sheetag["style-name"]] && tstyles[sheetag["style-name"]]["display"] ? (parsexmlbool(tstyles[sheetag["style-name"]]["display"]) ? 0 : 1) : 0)
@@ -25062,7 +25538,9 @@ function parse_content_xml(d/*:string*/, _opts, _nfm)/*:Workbook*/ {
25062
25538
  if(Rn[1]==='/') break;
25063
25539
  try {
25064
25540
  _Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
25065
- Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
25541
+ if(Object.prototype.hasOwnProperty.call(Sheets, _Ref[0]) && Sheets[_Ref[0]]) {
25542
+ Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
25543
+ }
25066
25544
  } catch(e) {/* empty */}
25067
25545
  break;
25068
25546
 
@@ -25572,7 +26050,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
25572
26050
 
25573
26051
  /* column styles */
25574
26052
  var cidx = 0;
25575
- wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
26053
+ wb.SheetNames.map(function(n) { return sheet_map_get(wb.Sheets, n); }).forEach(function(ws) {
25576
26054
  if(!ws) return;
25577
26055
  if(ws["!cols"]) {
25578
26056
  for(var C = 0; C < ws["!cols"].length; ++C) if(ws["!cols"][C]) {
@@ -25591,7 +26069,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
25591
26069
 
25592
26070
  /* row styles */
25593
26071
  var ridx = 0;
25594
- wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
26072
+ wb.SheetNames.map(function(n) { return sheet_map_get(wb.Sheets, n); }).forEach(function(ws) {
25595
26073
  if(!ws) return;
25596
26074
  if(ws["!rows"]) {
25597
26075
  for(var R = 0; R < ws["!rows"].length; ++R) if(ws["!rows"][R]) {
@@ -25624,7 +26102,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
25624
26102
  /* number formats, table cells, text */
25625
26103
  var nfs = {};
25626
26104
  var nfi = 69;
25627
- wb.SheetNames.map(function(n) { return wb.Sheets[n]; }).forEach(function(ws) {
26105
+ wb.SheetNames.map(function(n) { return sheet_map_get(wb.Sheets, n); }).forEach(function(ws) {
25628
26106
  if(!ws) return;
25629
26107
  var dense = (ws["!data"] != null);
25630
26108
  if(!ws["!ref"]) return;
@@ -25707,7 +26185,7 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = /* @__PURE__ */(function
25707
26185
  o.push(' <office:body>\n');
25708
26186
  o.push(' <office:spreadsheet>\n');
25709
26187
  if(((wb.Workbook||{}).WBProps||{}).date1904) o.push(' <table:calculation-settings table:case-sensitive="false" table:search-criteria-must-apply-to-whole-cell="true" table:use-wildcards="true" table:use-regular-expressions="false" table:automatic-find-labels="false">\n <table:null-date table:date-value="1904-01-01"/>\n </table:calculation-settings>\n');
25710
- for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(wb.Sheets[wb.SheetNames[i]], wb, i, opts, nfs, ((wb.Workbook||{}).WBProps||{}).date1904));
26188
+ for(var i = 0; i != wb.SheetNames.length; ++i) o.push(write_ws(sheet_map_get(wb.Sheets, wb.SheetNames[i]), wb, i, opts, nfs, ((wb.Workbook||{}).WBProps||{}).date1904));
25711
26189
  if((wb.Workbook||{}).Names) o.push(write_names_ods(wb.Workbook.Names, wb.SheetNames, -1));
25712
26190
  o.push(' </office:spreadsheet>\n');
25713
26191
  o.push(' </office:body>\n');
@@ -25759,7 +26237,6 @@ function write_ods(wb/*:any*/, opts/*:any*/) {
25759
26237
 
25760
26238
  return zip;
25761
26239
  }
25762
-
25763
26240
  /*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */
25764
26241
  var subarray = function() {
25765
26242
  try {
@@ -27277,7 +27754,7 @@ function write_numbers_iwa(wb, opts) {
27277
27754
  docroot = numbers_iwa_find(cfb, deps, 1);
27278
27755
  sheetrefs = mappa(parse_shallow(docroot.messages[0].data)[1], parse_TSP_Reference);
27279
27756
  }
27280
- write_numbers_ws(cfb, deps, wb.Sheets[name], name, idx, sheetrefs[idx]);
27757
+ write_numbers_ws(cfb, deps, sheet_map_get(wb.Sheets, name), name, idx, sheetrefs[idx]);
27281
27758
  });
27282
27759
  return cfb;
27283
27760
  }
@@ -28195,7 +28672,8 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/
28195
28672
  case 'dialog': _ws = parse_ds(data, path, idx, opts, sheetRels[sheet], wb, themes, styles); break;
28196
28673
  default: throw new Error("Unrecognized sheet type " + stype);
28197
28674
  }
28198
- sheets[sheet] = _ws;
28675
+ if(stype == "sheet") parse_sheet_tables(_ws, zip, path, sheetRels[sheet], opts, themes, styles);
28676
+ sheet_map_set(sheets, sheet, _ws);
28199
28677
 
28200
28678
  /* scan rels for comments and threaded comments */
28201
28679
  var comments = [], tcomments = [];
@@ -28215,7 +28693,9 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/
28215
28693
  if(tcomments && tcomments.length) sheet_insert_comments(_ws, tcomments, true, opts.people || []);
28216
28694
  if(stype == "sheet") parse_sheet_drawing(_ws, stype, zip, path, idx, opts, wb);
28217
28695
  parse_sheet_legacy_drawing(_ws, stype, zip, path, idx, opts, wb, comments);
28218
- } catch(e) { if(opts.WTF) throw e; }
28696
+ } catch(e) {
28697
+ if(opts.WTF || (opts.validateMerges && e && /^E_MERGE_/.test(e.code))) throw e;
28698
+ }
28219
28699
  }
28220
28700
 
28221
28701
  function strip_front_slash(x/*:string*/)/*:string*/ { return x.charAt(0) == '/' ? x.slice(1) : x; }
@@ -28318,7 +28798,7 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ {
28318
28798
  if(opts.bookSheets && typeof sheets !== 'undefined') out.SheetNames = sheets;
28319
28799
  if(opts.bookSheets ? out.SheetNames : opts.bookProps) return out;
28320
28800
  }
28321
- sheets = {};
28801
+ sheets = sheet_map_new();
28322
28802
 
28323
28803
  var deps = {};
28324
28804
  if(opts.bookDeps && dir.calcchain) deps=parse_cc(getzipdata(zip, strip_front_slash(dir.calcchain)),dir.calcchain,opts);
@@ -28521,7 +29001,7 @@ function write_zip_xlsb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
28521
29001
 
28522
29002
  for(rId=1;rId <= wb.SheetNames.length; ++rId) {
28523
29003
  var wsrels = {'!id':{}};
28524
- var ws = wb.Sheets[wb.SheetNames[rId-1]];
29004
+ var ws = sheet_map_get(wb.Sheets, wb.SheetNames[rId-1]);
28525
29005
  var _type = (ws || {})["!type"] || "sheet";
28526
29006
  switch(_type) {
28527
29007
  case "chart":
@@ -28677,7 +29157,7 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
28677
29157
 
28678
29158
  for(rId=1;rId <= wb.SheetNames.length; ++rId) {
28679
29159
  var wsrels = {'!id':{}};
28680
- var ws = wb.Sheets[wb.SheetNames[rId-1]];
29160
+ var ws = sheet_map_get(wb.Sheets, wb.SheetNames[rId-1]);
28681
29161
  var _type = (ws || {})["!type"] || "sheet";
28682
29162
  switch(_type) {
28683
29163
  case "chart":
@@ -28773,7 +29253,6 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ {
28773
29253
  delete opts.revssf; delete opts.ssf;
28774
29254
  return zip;
28775
29255
  }
28776
-
28777
29256
  function firstbyte(f/*:RawData*/,o/*:?TypeOpts*/)/*:Array<number>*/ {
28778
29257
  var x = "";
28779
29258
  switch((o||{}).type || "base64") {
@@ -29043,18 +29522,18 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
29043
29522
  case 'xml':
29044
29523
  case 'xlml': return write_string_type(write_xlml(wb, o), o);
29045
29524
  case 'slk':
29046
- case 'sylk': return write_string_type(SYLK.from_sheet(wb.Sheets[wb.SheetNames[idx]], o, wb), o);
29525
+ case 'sylk': return write_string_type(SYLK.from_sheet(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o, wb), o);
29047
29526
  case 'htm':
29048
- case 'html': return write_string_type(sheet_to_html(wb.Sheets[wb.SheetNames[idx]], o), o);
29049
- case 'txt': return write_stxt_type(sheet_to_txt(wb.Sheets[wb.SheetNames[idx]], o), o);
29050
- case 'csv': return write_string_type(sheet_to_csv(wb.Sheets[wb.SheetNames[idx]], o), o, "\ufeff");
29051
- case 'dif': return write_string_type(DIF.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o);
29052
- case 'dbf': return write_binary_type(DBF.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o);
29053
- case 'prn': return write_string_type(PRN.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o);
29054
- case 'rtf': return write_string_type(sheet_to_rtf(wb.Sheets[wb.SheetNames[idx]], o), o);
29055
- case 'eth': return write_string_type(ETH.from_sheet(wb.Sheets[wb.SheetNames[idx]], o), o);
29527
+ case 'html': return write_string_type(sheet_to_html(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29528
+ case 'txt': return write_stxt_type(sheet_to_txt(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29529
+ case 'csv': return write_string_type(sheet_to_csv(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o, "\ufeff");
29530
+ case 'dif': return write_string_type(DIF.from_sheet(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29531
+ case 'dbf': return write_binary_type(DBF.from_sheet(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29532
+ case 'prn': return write_string_type(PRN.from_sheet(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29533
+ case 'rtf': return write_string_type(sheet_to_rtf(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29534
+ case 'eth': return write_string_type(ETH.from_sheet(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29056
29535
  case 'fods': return write_string_type(write_ods(wb, o), o);
29057
- case 'wk1': return write_binary_type(WK_.sheet_to_wk1(wb.Sheets[wb.SheetNames[idx]], o), o);
29536
+ case 'wk1': return write_binary_type(WK_.sheet_to_wk1(sheet_map_get(wb.Sheets, wb.SheetNames[idx]), o), o);
29058
29537
  case 'wk3': return write_binary_type(WK_.book_to_wk3(wb, o), o);
29059
29538
  case 'biff2': if(!o.biff) o.biff = 2; /* falls through */
29060
29539
  case 'biff3': if(!o.biff) o.biff = 3; /* falls through */
@@ -29320,6 +29799,7 @@ function sheet_add_json(_ws/*:?Worksheet*/, js/*:Array<any>*/, opts)/*:Worksheet
29320
29799
  var _origin/*:CellAddress*/ = typeof o.origin == "string" ? decode_cell(o.origin) : o.origin;
29321
29800
  _R = _origin.r; _C = _origin.c;
29322
29801
  }
29802
+ if(!isFinite(_R) || _R !== Math.floor(_R) || _R < -1 || !isFinite(_C) || _C !== Math.floor(_C) || _C < 0) throw new Error("Invalid origin");
29323
29803
  }
29324
29804
  var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:_C, r:_R + js.length - 1 + offset}}/*:any*/);
29325
29805
  if(ws['!ref']) {
@@ -29411,7 +29891,7 @@ function wb_sheet_idx(wb/*:Workbook*/, sh/*:number|string*/) {
29411
29891
 
29412
29892
  /* simple blank or single-sheet workbook object */
29413
29893
  function book_new(ws/*:?Worksheet*/, wsname/*:?string*/)/*:Workbook*/ {
29414
- var wb = { SheetNames: [], Sheets: {} };
29894
+ var wb = { SheetNames: [], Sheets: sheet_map_new() };
29415
29895
  if(ws) book_append_sheet(wb, ws, wsname || "Sheet1");
29416
29896
  return wb;
29417
29897
  }
@@ -29431,7 +29911,7 @@ function book_append_sheet(wb/*:Workbook*/, ws/*:Worksheet*/, name/*:?string*/,
29431
29911
  if(wb.SheetNames.indexOf(name) >= 0) throw new Error("Worksheet with name |" + name + "| already exists!");
29432
29912
 
29433
29913
  wb.SheetNames.push(name);
29434
- wb.Sheets[name] = ws;
29914
+ sheet_map_set(wb.Sheets, name, ws);
29435
29915
  return name;
29436
29916
  }
29437
29917
 
@@ -29498,7 +29978,6 @@ function sheet_set_array_formula(ws/*:Worksheet*/, range, formula/*:string*/, dy
29498
29978
  ws["!ref"] = encode_range(wsr);
29499
29979
  return ws;
29500
29980
  }
29501
-
29502
29981
  var utils/*:any*/ = {
29503
29982
  encode_col: encode_col,
29504
29983
  encode_row: encode_row,
@@ -29528,6 +30007,7 @@ var utils/*:any*/ = {
29528
30007
  measure_text_width: measure_text_width,
29529
30008
  auto_fit_columns: auto_fit_columns,
29530
30009
  autofit_columns: auto_fit_columns,
30010
+ resolve_table_cell_style: resolve_table_cell_style,
29531
30011
  col_width_to_px: width2px,
29532
30012
  px_to_col_width: function(px) { return char2width(px2char(px)); },
29533
30013
  row_height_to_px: pt2px_browser,
@@ -29655,7 +30135,7 @@ function write_json_stream(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) {
29655
30135
  if ((rowinfo[R]||{}).hidden) {
29656
30136
  ++R;
29657
30137
  continue;
29658
- };
30138
+ }
29659
30139
  var row = make_json_row(sheet, r, R, cols, header, hdr, o);
29660
30140
  ++R;
29661
30141
  if((row.isempty === false) || (header === 1 ? o.blankrows !== false : !!o.blankrows)) {
@@ -29684,7 +30164,7 @@ function write_xlml_stream(wb/*:Workbook*/, o/*:?Sheet2XLMLOpts*/) {
29684
30164
 
29685
30165
  /* do one pass to determine styles since they must be added before tables */
29686
30166
  wb.SheetNames.forEach(function(n) {
29687
- var ws = wb.Sheets[n];
30167
+ var ws = sheet_map_get(wb.Sheets, n);
29688
30168
  if(!ws || !ws["!ref"]) return;
29689
30169
  var range = decode_range(ws["!ref"]);
29690
30170
  var dense = ws["!data"] != null;
@@ -29704,7 +30184,7 @@ function write_xlml_stream(wb/*:Workbook*/, o/*:?Sheet2XLMLOpts*/) {
29704
30184
  });
29705
30185
  var sty = write_sty_xlml(wb, opts);
29706
30186
 
29707
- var stage = 0, wsidx = 0, ws = wb.Sheets[wb.SheetNames[wsidx]], range = safe_decode_range(ws), R = -1, T = false;
30187
+ var stage = 0, wsidx = 0, ws = sheet_map_get(wb.Sheets, wb.SheetNames[wsidx]), range = safe_decode_range(ws), R = -1, T = false;
29708
30188
 
29709
30189
  var marr = [], mi = 0, dense = false, darr = [], addr = {r:0,c:0};
29710
30190
 
@@ -29744,7 +30224,7 @@ function write_xlml_stream(wb/*:Workbook*/, o/*:?Sheet2XLMLOpts*/) {
29744
30224
 
29745
30225
  stream.push("<Worksheet" + wxt_helper({ "ss:Name": escapexml(wb.SheetNames[wsidx])}) + ">");
29746
30226
 
29747
- ws = wb.Sheets[wb.SheetNames[wsidx]];
30227
+ ws = sheet_map_get(wb.Sheets, wb.SheetNames[wsidx]);
29748
30228
  if(!ws) { stream.push("</Worksheet>"); return void ++wsidx; }
29749
30229
 
29750
30230
  var names = write_ws_xlml_names(ws, opts, wsidx, wb);