1
forked from sheetjs/sheetjs

version bump 0.12.11: file format range limits

This commit is contained in:
SheetJS 2018-04-27 16:11:18 -04:00
parent 75c49ddbe8
commit eb5fc87be4
26 changed files with 323 additions and 70 deletions

@ -1,5 +1,6 @@
language: node_js language: node_js
node_js: node_js:
- "10"
- "9" - "9"
- "8" - "8"
- "7" - "7"

@ -4,6 +4,10 @@ This log is intended to keep track of backwards-incompatible changes, including
but not limited to API changes and file location changes. Minor behavioral but not limited to API changes and file location changes. Minor behavioral
changes may not be included if they are not expected to break existing code. changes may not be included if they are not expected to break existing code.
## 0.12.11 (2018-04-27)
* XLS/XLSX/XLSB range truncation (errors in `WTF` mode)
## 0.12.4 (2018-03-04) ## 0.12.4 (2018-03-04)
* `JSZip` renamed to `JSZipSync` * `JSZip` renamed to `JSZipSync`

@ -2286,6 +2286,20 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Rich Text Format tables (RTF) | | :o: | | Rich Text Format tables (RTF) | | :o: |
| Ethercalc Record Format (ETH) | :o: | :o: | | Ethercalc Record Format (ETH) | :o: | :o: |
Features not supported by a given file format will not be written. Formats with
range limits will be silently truncated:
| Format | Last Cell | Max Cols | Max Rows |
|:------------------------------------------|:-----------|---------:|---------:|
| Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
| Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
| Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
| Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
| Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
Excel 2003 SpreadsheetML range limits are governed by the version of Excel and
are not enforced by the writer.
### Excel 2007+ XML (XLSX/XLSM) ### Excel 2007+ XML (XLSX/XLSM)
<details> <details>

@ -1 +1 @@
XLSX.version = '0.12.10'; XLSX.version = '0.12.11';

@ -99,3 +99,10 @@ function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, the
} }
} catch(e) { if(opts.WTF && styles.Fills) throw e; } } catch(e) { if(opts.WTF && styles.Fills) throw e; }
} }
function check_ws(ws/*:Worksheet*/, sname/*:string*/, i/*:number*/) {
if(ws && ws['!ref']) {
var range = safe_decode_range(ws['!ref']);
if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
}
}

@ -469,7 +469,14 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
var s = wb.SheetNames[idx], sidx = 0, rdata = ""; var s = wb.SheetNames[idx], sidx = 0, rdata = "";
var ws = wb.Sheets[s]; var ws = wb.Sheets[s];
if(ws == null) ws = {}; if(ws == null) ws = {};
var ref = ws['!ref']; if(ref == null) ref = 'A1'; var ref = ws['!ref'] || 'A1';
var range = safe_decode_range(ref);
if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
range.e.c = Math.min(range.e.c, 0x3FFF);
range.e.r = Math.min(range.e.c, 0xFFFFF);
ref = encode_range(range);
}
if(!rels) rels = {}; if(!rels) rels = {};
ws['!comments'] = []; ws['!comments'] = [];
ws['!drawing'] = []; ws['!drawing'] = [];

@ -809,6 +809,11 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var c/*:string*/ = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {} var c/*:string*/ = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
var r = safe_decode_range(ws['!ref'] || "A1"); var r = safe_decode_range(ws['!ref'] || "A1");
if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
r.e.c = Math.min(r.e.c, 0x3FFF);
r.e.r = Math.min(r.e.c, 0xFFFFF);
}
ws['!links'] = []; ws['!links'] = [];
/* passed back to write_zip and removed there */ /* passed back to write_zip and removed there */
ws['!comments'] = []; ws['!comments'] = [];

@ -139,5 +139,6 @@ function check_wb(wb) {
if(!wb.SheetNames.length) throw new Error("Workbook is empty"); if(!wb.SheetNames.length) throw new Error("Workbook is empty");
var Sheets = (wb.Workbook && wb.Workbook.Sheets) || []; var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw); check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
/* TODO: validate workbook */ /* TODO: validate workbook */
} }

@ -46,7 +46,7 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
/* 18.2.1 bookViews CT_BookViews ? */ /* 18.2.1 bookViews CT_BookViews ? */
case '<bookViews': case '<bookViews>': case '</bookViews>': break; case '<bookViews': case '<bookViews>': case '</bookViews>': break;
/* 18.2.30 workbookView CT_BookView + */ /* 18.2.30 workbookView CT_BookView + */
case '<workbookView': delete y[0]; wb.WBView.push(y); break; case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
case '</workbookView>': break; case '</workbookView>': break;
/* 18.2.20 sheets CT_Sheets 1 */ /* 18.2.20 sheets CT_Sheets 1 */

@ -55,6 +55,12 @@ function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) { function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = []; var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
ref = encode_range(range);
}
for(var R = range.s.r; R <= range.e.r; ++R) { for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R); rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) { for(var C = range.s.c; C <= range.e.c; ++C) {
@ -159,9 +165,16 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/); var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/); var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/);
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var b8 = opts.biff == 8;
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = []; var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1"); var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8; var MAX_ROWS = b8 ? 65536 : 16384;
if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, MAX_ROWS-1);
}
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts)); write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */ /* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1)); write_biff_rec(ba, "CalcMode", writeuint16(1));

@ -9,7 +9,8 @@ function get_data(req, res, type) {
var work = new Worker('worker.js'); var work = new Worker('worker.js');
work.onmessage = function(e) { work.onmessage = function(e) {
if(e.data.err) console.log(e.data.err); if(e.data.err) console.log(e.data.err);
return res(e.data.data); var buf = new Buffer(e.data.data, "binary");
return res(buf);
}; };
work.postMessage({action:"write", type:type, data:data}); work.postMessage({action:"write", type:type, data:data});
} }

28
dist/xlsx.core.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.core.min.map generated vendored

File diff suppressed because one or more lines are too long

42
dist/xlsx.extendscript.js generated vendored

@ -9147,7 +9147,7 @@ module.exports = ZStream;
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
var XLSX = {}; var XLSX = {};
(function make_xlsx(XLSX){ (function make_xlsx(XLSX){
XLSX.version = '0.12.10'; XLSX.version = '0.12.11';
var current_codepage = 1200, current_ansi = 1252; var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true */ /*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') { if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -13248,7 +13248,6 @@ function write_cust_props(cp) {
if(!cp) return o.join(""); if(!cp) return o.join("");
var pid = 1; var pid = 1;
keys(cp).forEach(function custprop(k) { ++pid; keys(cp).forEach(function custprop(k) { ++pid;
// $FlowIgnore
o[o.length] = (writextag('property', write_vt(cp[k]), { o[o.length] = (writextag('property', write_vt(cp[k]), {
'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}', 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
'pid': pid, 'pid': pid,
@ -20971,6 +20970,13 @@ function safe_format(p, fmtid, fillid, opts, themes, styles) {
} }
} catch(e) { if(opts.WTF && styles.Fills) throw e; } } catch(e) { if(opts.WTF && styles.Fills) throw e; }
} }
function check_ws(ws, sname, i) {
if(ws && ws['!ref']) {
var range = safe_decode_range(ws['!ref']);
if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
}
}
function parse_ws_xml_dim(ws, s) { function parse_ws_xml_dim(ws, s) {
var d = safe_decode_range(s); var d = safe_decode_range(s);
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); 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);
@ -21442,7 +21448,14 @@ function write_ws_xml(idx, opts, wb, rels) {
var s = wb.SheetNames[idx], sidx = 0, rdata = ""; var s = wb.SheetNames[idx], sidx = 0, rdata = "";
var ws = wb.Sheets[s]; var ws = wb.Sheets[s];
if(ws == null) ws = {}; if(ws == null) ws = {};
var ref = ws['!ref']; if(ref == null) ref = 'A1'; var ref = ws['!ref'] || 'A1';
var range = safe_decode_range(ref);
if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
range.e.c = Math.min(range.e.c, 0x3FFF);
range.e.r = Math.min(range.e.c, 0xFFFFF);
ref = encode_range(range);
}
if(!rels) rels = {}; if(!rels) rels = {};
ws['!comments'] = []; ws['!comments'] = [];
ws['!drawing'] = []; ws['!drawing'] = [];
@ -22360,6 +22373,11 @@ function write_ws_bin(idx, opts, wb, rels) {
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {} var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
var r = safe_decode_range(ws['!ref'] || "A1"); var r = safe_decode_range(ws['!ref'] || "A1");
if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
r.e.c = Math.min(r.e.c, 0x3FFF);
r.e.r = Math.min(r.e.c, 0xFFFFF);
}
ws['!links'] = []; ws['!links'] = [];
/* passed back to write_zip and removed there */ /* passed back to write_zip and removed there */
ws['!comments'] = []; ws['!comments'] = [];
@ -22693,6 +22711,7 @@ function check_wb(wb) {
if(!wb.SheetNames.length) throw new Error("Workbook is empty"); if(!wb.SheetNames.length) throw new Error("Workbook is empty");
var Sheets = (wb.Workbook && wb.Workbook.Sheets) || []; var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw); check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
/* TODO: validate workbook */ /* TODO: validate workbook */
} }
/* 18.2 Workbook */ /* 18.2 Workbook */
@ -22743,7 +22762,7 @@ function parse_wb_xml(data, opts) {
/* 18.2.1 bookViews CT_BookViews ? */ /* 18.2.1 bookViews CT_BookViews ? */
case '<bookViews': case '<bookViews>': case '</bookViews>': break; case '<bookViews': case '<bookViews>': case '</bookViews>': break;
/* 18.2.30 workbookView CT_BookView + */ /* 18.2.30 workbookView CT_BookView + */
case '<workbookView': delete y[0]; wb.WBView.push(y); break; case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
case '</workbookView>': break; case '</workbookView>': break;
/* 18.2.20 sheets CT_Sheets 1 */ /* 18.2.20 sheets CT_Sheets 1 */
@ -26689,6 +26708,12 @@ function write_ws_biff2_cell(ba, cell, R, C) {
function write_ws_biff2(ba, ws, idx, opts) { function write_ws_biff2(ba, ws, idx, opts) {
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = []; var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
ref = encode_range(range);
}
for(var R = range.s.r; R <= range.e.r; ++R) { for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R); rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) { for(var C = range.s.c; C <= range.e.c; ++C) {
@ -26792,9 +26817,16 @@ function write_ws_biff8(idx, opts, wb) {
var _WB = ((wb||{}).Workbook||{}); var _WB = ((wb||{}).Workbook||{});
var _sheet = ((_WB.Sheets||[])[idx]||{}); var _sheet = ((_WB.Sheets||[])[idx]||{});
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var b8 = opts.biff == 8;
var ref, rr = "", cols = []; var ref, rr = "", cols = [];
var range = safe_decode_range(ws['!ref'] || "A1"); var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8; var MAX_ROWS = b8 ? 65536 : 16384;
if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, MAX_ROWS-1);
}
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts)); write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */ /* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1)); write_biff_rec(ba, "CalcMode", writeuint16(1));

32
dist/xlsx.full.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.full.min.map generated vendored

File diff suppressed because one or more lines are too long

42
dist/xlsx.js generated vendored

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
var XLSX = {}; var XLSX = {};
(function make_xlsx(XLSX){ (function make_xlsx(XLSX){
XLSX.version = '0.12.10'; XLSX.version = '0.12.11';
var current_codepage = 1200, current_ansi = 1252; var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true */ /*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') { if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -4105,7 +4105,6 @@ function write_cust_props(cp) {
if(!cp) return o.join(""); if(!cp) return o.join("");
var pid = 1; var pid = 1;
keys(cp).forEach(function custprop(k) { ++pid; keys(cp).forEach(function custprop(k) { ++pid;
// $FlowIgnore
o[o.length] = (writextag('property', write_vt(cp[k]), { o[o.length] = (writextag('property', write_vt(cp[k]), {
'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}', 'fmtid': '{D5CDD505-2E9C-101B-9397-08002B2CF9AE}',
'pid': pid, 'pid': pid,
@ -11828,6 +11827,13 @@ function safe_format(p, fmtid, fillid, opts, themes, styles) {
} }
} catch(e) { if(opts.WTF && styles.Fills) throw e; } } catch(e) { if(opts.WTF && styles.Fills) throw e; }
} }
function check_ws(ws, sname, i) {
if(ws && ws['!ref']) {
var range = safe_decode_range(ws['!ref']);
if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
}
}
function parse_ws_xml_dim(ws, s) { function parse_ws_xml_dim(ws, s) {
var d = safe_decode_range(s); var d = safe_decode_range(s);
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); 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);
@ -12299,7 +12305,14 @@ function write_ws_xml(idx, opts, wb, rels) {
var s = wb.SheetNames[idx], sidx = 0, rdata = ""; var s = wb.SheetNames[idx], sidx = 0, rdata = "";
var ws = wb.Sheets[s]; var ws = wb.Sheets[s];
if(ws == null) ws = {}; if(ws == null) ws = {};
var ref = ws['!ref']; if(ref == null) ref = 'A1'; var ref = ws['!ref'] || 'A1';
var range = safe_decode_range(ref);
if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
range.e.c = Math.min(range.e.c, 0x3FFF);
range.e.r = Math.min(range.e.c, 0xFFFFF);
ref = encode_range(range);
}
if(!rels) rels = {}; if(!rels) rels = {};
ws['!comments'] = []; ws['!comments'] = [];
ws['!drawing'] = []; ws['!drawing'] = [];
@ -13217,6 +13230,11 @@ function write_ws_bin(idx, opts, wb, rels) {
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {} var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
var r = safe_decode_range(ws['!ref'] || "A1"); var r = safe_decode_range(ws['!ref'] || "A1");
if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
r.e.c = Math.min(r.e.c, 0x3FFF);
r.e.r = Math.min(r.e.c, 0xFFFFF);
}
ws['!links'] = []; ws['!links'] = [];
/* passed back to write_zip and removed there */ /* passed back to write_zip and removed there */
ws['!comments'] = []; ws['!comments'] = [];
@ -13550,6 +13568,7 @@ function check_wb(wb) {
if(!wb.SheetNames.length) throw new Error("Workbook is empty"); if(!wb.SheetNames.length) throw new Error("Workbook is empty");
var Sheets = (wb.Workbook && wb.Workbook.Sheets) || []; var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw); check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
/* TODO: validate workbook */ /* TODO: validate workbook */
} }
/* 18.2 Workbook */ /* 18.2 Workbook */
@ -13600,7 +13619,7 @@ function parse_wb_xml(data, opts) {
/* 18.2.1 bookViews CT_BookViews ? */ /* 18.2.1 bookViews CT_BookViews ? */
case '<bookViews': case '<bookViews>': case '</bookViews>': break; case '<bookViews': case '<bookViews>': case '</bookViews>': break;
/* 18.2.30 workbookView CT_BookView + */ /* 18.2.30 workbookView CT_BookView + */
case '<workbookView': delete y[0]; wb.WBView.push(y); break; case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
case '</workbookView>': break; case '</workbookView>': break;
/* 18.2.20 sheets CT_Sheets 1 */ /* 18.2.20 sheets CT_Sheets 1 */
@ -17546,6 +17565,12 @@ function write_ws_biff2_cell(ba, cell, R, C) {
function write_ws_biff2(ba, ws, idx, opts) { function write_ws_biff2(ba, ws, idx, opts) {
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = []; var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
ref = encode_range(range);
}
for(var R = range.s.r; R <= range.e.r; ++R) { for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R); rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) { for(var C = range.s.c; C <= range.e.c; ++C) {
@ -17649,9 +17674,16 @@ function write_ws_biff8(idx, opts, wb) {
var _WB = ((wb||{}).Workbook||{}); var _WB = ((wb||{}).Workbook||{});
var _sheet = ((_WB.Sheets||[])[idx]||{}); var _sheet = ((_WB.Sheets||[])[idx]||{});
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var b8 = opts.biff == 8;
var ref, rr = "", cols = []; var ref, rr = "", cols = [];
var range = safe_decode_range(ws['!ref'] || "A1"); var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8; var MAX_ROWS = b8 ? 65536 : 16384;
if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, MAX_ROWS-1);
}
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts)); write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */ /* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1)); write_biff_rec(ba, "CalcMode", writeuint16(1));

26
dist/xlsx.min.js generated vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map generated vendored

File diff suppressed because one or more lines are too long

@ -31,6 +31,20 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Rich Text Format tables (RTF) | | :o: | | Rich Text Format tables (RTF) | | :o: |
| Ethercalc Record Format (ETH) | :o: | :o: | | Ethercalc Record Format (ETH) | :o: | :o: |
Features not supported by a given file format will not be written. Formats with
range limits will be silently truncated:
| Format | Last Cell | Max Cols | Max Rows |
|:------------------------------------------|:-----------|---------:|---------:|
| Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
| Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
| Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
| Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
| Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
Excel 2003 SpreadsheetML range limits are governed by the version of Excel and
are not enforced by the writer.
### Excel 2007+ XML (XLSX/XLSM) ### Excel 2007+ XML (XLSX/XLSM)
<details> <details>

@ -2112,6 +2112,20 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Rich Text Format tables (RTF) | | :o: | | Rich Text Format tables (RTF) | | :o: |
| Ethercalc Record Format (ETH) | :o: | :o: | | Ethercalc Record Format (ETH) | :o: | :o: |
Features not supported by a given file format will not be written. Formats with
range limits will be silently truncated:
| Format | Last Cell | Max Cols | Max Rows |
|:------------------------------------------|:-----------|---------:|---------:|
| Excel 2007+ XML Formats (XLSX/XLSM) | XFD1048576 | 16384 | 1048576 |
| Excel 2007+ Binary Format (XLSB BIFF12) | XFD1048576 | 16384 | 1048576 |
| Excel 97-2004 (XLS BIFF8) | IV65536 | 256 | 65536 |
| Excel 5.0/95 (XLS BIFF5) | IV16384 | 256 | 16384 |
| Excel 2.0/2.1 (XLS BIFF2) | IV16384 | 256 | 16384 |
Excel 2003 SpreadsheetML range limits are governed by the version of Excel and
are not enforced by the writer.
### Excel 2007+ XML (XLSX/XLSM) ### Excel 2007+ XML (XLSX/XLSM)

@ -1,6 +1,6 @@
{ {
"name": "xlsx", "name": "xlsx",
"version": "0.12.10", "version": "0.12.11",
"author": "sheetjs", "author": "sheetjs",
"description": "SheetJS Spreadsheet data parser and writer", "description": "SheetJS Spreadsheet data parser and writer",
"keywords": [ "keywords": [

21
test.js

@ -1326,6 +1326,27 @@ describe('write features', function() {
assert(str.indexOf("<b>abc</b>") > 0); assert(str.indexOf("<b>abc</b>") > 0);
}); });
}); });
describe('sheet range limits', function() { [
["biff2", "IV16384"],
["biff5", "IV16384"],
["biff8", "IV65536"],
["xlsx", "XFD1048576"],
["xlsb", "XFD1048576"]
].forEach(function(r) { it(r[0], function() {
var C = X.utils.decode_cell(r[1]);
var wopts = {bookType:r[0], type:'binary', WTF:1};
var wb = { SheetNames: ["Sheet1"], Sheets: { Sheet1: {} } };
wb.Sheets.Sheet1['!ref'] = "A1:" + X.utils.encode_cell({r:0, c:C.c});
X.write(wb, wopts);
wb.Sheets.Sheet1['!ref'] = "A" + X.utils.encode_row(C.r - 5) + ":" + X.utils.encode_cell({r:C.r, c:0});
X.write(wb, wopts);
wb.Sheets.Sheet1['!ref'] = "A1:" + X.utils.encode_cell({r:0, c:C.c+1});
assert.throws(function() { X.write(wb, wopts); });
wb.Sheets.Sheet1['!ref'] = "A" + X.utils.encode_row(C.r - 5) + ":" + X.utils.encode_cell({r:C.r+1, c:0});
assert.throws(function() { X.write(wb, wopts); });
}); }); });
}); });
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ { function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {

21
tests/core.js generated

@ -1326,6 +1326,27 @@ describe('write features', function() {
assert(str.indexOf("<b>abc</b>") > 0); assert(str.indexOf("<b>abc</b>") > 0);
}); });
}); });
describe('sheet range limits', function() { [
["biff2", "IV16384"],
["biff5", "IV16384"],
["biff8", "IV65536"],
["xlsx", "XFD1048576"],
["xlsb", "XFD1048576"]
].forEach(function(r) { it(r[0], function() {
var C = X.utils.decode_cell(r[1]);
var wopts = {bookType:r[0], type:'binary', WTF:1};
var wb = { SheetNames: ["Sheet1"], Sheets: { Sheet1: {} } };
wb.Sheets.Sheet1['!ref'] = "A1:" + X.utils.encode_cell({r:0, c:C.c});
X.write(wb, wopts);
wb.Sheets.Sheet1['!ref'] = "A" + X.utils.encode_row(C.r - 5) + ":" + X.utils.encode_cell({r:C.r, c:0});
X.write(wb, wopts);
wb.Sheets.Sheet1['!ref'] = "A1:" + X.utils.encode_cell({r:0, c:C.c+1});
assert.throws(function() { X.write(wb, wopts); });
wb.Sheets.Sheet1['!ref'] = "A" + X.utils.encode_row(C.r - 5) + ":" + X.utils.encode_cell({r:C.r+1, c:0});
assert.throws(function() { X.write(wb, wopts); });
}); }); });
}); });
function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ { function seq(end/*:number*/, start/*:?number*/)/*:Array<number>*/ {

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
var XLSX = {}; var XLSX = {};
(function make_xlsx(XLSX){ (function make_xlsx(XLSX){
XLSX.version = '0.12.10'; XLSX.version = '0.12.11';
var current_codepage = 1200, current_ansi = 1252; var current_codepage = 1200, current_ansi = 1252;
/*:: declare var cptable:any; */ /*:: declare var cptable:any; */
/*global cptable:true */ /*global cptable:true */
@ -11923,6 +11923,13 @@ function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, the
} }
} catch(e) { if(opts.WTF && styles.Fills) throw e; } } catch(e) { if(opts.WTF && styles.Fills) throw e; }
} }
function check_ws(ws/*:Worksheet*/, sname/*:string*/, i/*:number*/) {
if(ws && ws['!ref']) {
var range = safe_decode_range(ws['!ref']);
if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
}
}
function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) { function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) {
var d = safe_decode_range(s); var d = safe_decode_range(s);
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); 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);
@ -12394,7 +12401,14 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
var s = wb.SheetNames[idx], sidx = 0, rdata = ""; var s = wb.SheetNames[idx], sidx = 0, rdata = "";
var ws = wb.Sheets[s]; var ws = wb.Sheets[s];
if(ws == null) ws = {}; if(ws == null) ws = {};
var ref = ws['!ref']; if(ref == null) ref = 'A1'; var ref = ws['!ref'] || 'A1';
var range = safe_decode_range(ref);
if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
range.e.c = Math.min(range.e.c, 0x3FFF);
range.e.r = Math.min(range.e.c, 0xFFFFF);
ref = encode_range(range);
}
if(!rels) rels = {}; if(!rels) rels = {};
ws['!comments'] = []; ws['!comments'] = [];
ws['!drawing'] = []; ws['!drawing'] = [];
@ -13313,6 +13327,11 @@ function write_ws_bin(idx/*:number*/, opts, wb/*:Workbook*/, rels) {
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var c/*:string*/ = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {} var c/*:string*/ = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
var r = safe_decode_range(ws['!ref'] || "A1"); var r = safe_decode_range(ws['!ref'] || "A1");
if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
r.e.c = Math.min(r.e.c, 0x3FFF);
r.e.r = Math.min(r.e.c, 0xFFFFF);
}
ws['!links'] = []; ws['!links'] = [];
/* passed back to write_zip and removed there */ /* passed back to write_zip and removed there */
ws['!comments'] = []; ws['!comments'] = [];
@ -13646,6 +13665,7 @@ function check_wb(wb) {
if(!wb.SheetNames.length) throw new Error("Workbook is empty"); if(!wb.SheetNames.length) throw new Error("Workbook is empty");
var Sheets = (wb.Workbook && wb.Workbook.Sheets) || []; var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw); check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
/* TODO: validate workbook */ /* TODO: validate workbook */
} }
/* 18.2 Workbook */ /* 18.2 Workbook */
@ -13696,7 +13716,7 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
/* 18.2.1 bookViews CT_BookViews ? */ /* 18.2.1 bookViews CT_BookViews ? */
case '<bookViews': case '<bookViews>': case '</bookViews>': break; case '<bookViews': case '<bookViews>': case '</bookViews>': break;
/* 18.2.30 workbookView CT_BookView + */ /* 18.2.30 workbookView CT_BookView + */
case '<workbookView': delete y[0]; wb.WBView.push(y); break; case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
case '</workbookView>': break; case '</workbookView>': break;
/* 18.2.20 sheets CT_Sheets 1 */ /* 18.2.20 sheets CT_Sheets 1 */
@ -17655,6 +17675,12 @@ function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n
function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) { function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts/*::, wb:Workbook*/) {
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = []; var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
ref = encode_range(range);
}
for(var R = range.s.r; R <= range.e.r; ++R) { for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R); rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) { for(var C = range.s.c; C <= range.e.c; ++C) {
@ -17759,9 +17785,16 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/); var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/);
var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/); var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/);
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var b8 = opts.biff == 8;
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = []; var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1"); var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8; var MAX_ROWS = b8 ? 65536 : 16384;
if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, MAX_ROWS-1);
}
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts)); write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */ /* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1)); write_biff_rec(ba, "CalcMode", writeuint16(1));

41
xlsx.js generated

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */ /*global global, exports, module, require:false, process:false, Buffer:false, ArrayBuffer:false */
var XLSX = {}; var XLSX = {};
(function make_xlsx(XLSX){ (function make_xlsx(XLSX){
XLSX.version = '0.12.10'; XLSX.version = '0.12.11';
var current_codepage = 1200, current_ansi = 1252; var current_codepage = 1200, current_ansi = 1252;
/*global cptable:true */ /*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') { if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -11827,6 +11827,13 @@ function safe_format(p, fmtid, fillid, opts, themes, styles) {
} }
} catch(e) { if(opts.WTF && styles.Fills) throw e; } } catch(e) { if(opts.WTF && styles.Fills) throw e; }
} }
function check_ws(ws, sname, i) {
if(ws && ws['!ref']) {
var range = safe_decode_range(ws['!ref']);
if(range.e.c < range.s.c || range.e.r < range.s.r) throw new Error("Bad range (" + i + "): " + ws['!ref']);
}
}
function parse_ws_xml_dim(ws, s) { function parse_ws_xml_dim(ws, s) {
var d = safe_decode_range(s); var d = safe_decode_range(s);
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); 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);
@ -12298,7 +12305,14 @@ function write_ws_xml(idx, opts, wb, rels) {
var s = wb.SheetNames[idx], sidx = 0, rdata = ""; var s = wb.SheetNames[idx], sidx = 0, rdata = "";
var ws = wb.Sheets[s]; var ws = wb.Sheets[s];
if(ws == null) ws = {}; if(ws == null) ws = {};
var ref = ws['!ref']; if(ref == null) ref = 'A1'; var ref = ws['!ref'] || 'A1';
var range = safe_decode_range(ref);
if(range.e.c > 0x3FFF || range.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + ref + " exceeds format limit A1:XFD1048576");
range.e.c = Math.min(range.e.c, 0x3FFF);
range.e.r = Math.min(range.e.c, 0xFFFFF);
ref = encode_range(range);
}
if(!rels) rels = {}; if(!rels) rels = {};
ws['!comments'] = []; ws['!comments'] = [];
ws['!drawing'] = []; ws['!drawing'] = [];
@ -13216,6 +13230,11 @@ function write_ws_bin(idx, opts, wb, rels) {
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {} var c = s; try { if(wb && wb.Workbook) c = wb.Workbook.Sheets[idx].CodeName || c; } catch(e) {}
var r = safe_decode_range(ws['!ref'] || "A1"); var r = safe_decode_range(ws['!ref'] || "A1");
if(r.e.c > 0x3FFF || r.e.r > 0xFFFFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:XFD1048576");
r.e.c = Math.min(r.e.c, 0x3FFF);
r.e.r = Math.min(r.e.c, 0xFFFFF);
}
ws['!links'] = []; ws['!links'] = [];
/* passed back to write_zip and removed there */ /* passed back to write_zip and removed there */
ws['!comments'] = []; ws['!comments'] = [];
@ -13549,6 +13568,7 @@ function check_wb(wb) {
if(!wb.SheetNames.length) throw new Error("Workbook is empty"); if(!wb.SheetNames.length) throw new Error("Workbook is empty");
var Sheets = (wb.Workbook && wb.Workbook.Sheets) || []; var Sheets = (wb.Workbook && wb.Workbook.Sheets) || [];
check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw); check_wb_names(wb.SheetNames, Sheets, !!wb.vbaraw);
for(var i = 0; i < wb.SheetNames.length; ++i) check_ws(wb.Sheets[wb.SheetNames[i]], wb.SheetNames[i], i);
/* TODO: validate workbook */ /* TODO: validate workbook */
} }
/* 18.2 Workbook */ /* 18.2 Workbook */
@ -13599,7 +13619,7 @@ function parse_wb_xml(data, opts) {
/* 18.2.1 bookViews CT_BookViews ? */ /* 18.2.1 bookViews CT_BookViews ? */
case '<bookViews': case '<bookViews>': case '</bookViews>': break; case '<bookViews': case '<bookViews>': case '</bookViews>': break;
/* 18.2.30 workbookView CT_BookView + */ /* 18.2.30 workbookView CT_BookView + */
case '<workbookView': delete y[0]; wb.WBView.push(y); break; case '<workbookView': case '<workbookView/>': delete y[0]; wb.WBView.push(y); break;
case '</workbookView>': break; case '</workbookView>': break;
/* 18.2.20 sheets CT_Sheets 1 */ /* 18.2.20 sheets CT_Sheets 1 */
@ -17545,6 +17565,12 @@ function write_ws_biff2_cell(ba, cell, R, C) {
function write_ws_biff2(ba, ws, idx, opts) { function write_ws_biff2(ba, ws, idx, opts) {
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = []; var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = [];
if(range.e.c > 0xFF || range.e.r > 0x3FFF) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, 0x3FFF);
ref = encode_range(range);
}
for(var R = range.s.r; R <= range.e.r; ++R) { for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R); rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) { for(var C = range.s.c; C <= range.e.c; ++C) {
@ -17648,9 +17674,16 @@ function write_ws_biff8(idx, opts, wb) {
var _WB = ((wb||{}).Workbook||{}); var _WB = ((wb||{}).Workbook||{});
var _sheet = ((_WB.Sheets||[])[idx]||{}); var _sheet = ((_WB.Sheets||[])[idx]||{});
var dense = Array.isArray(ws); var dense = Array.isArray(ws);
var b8 = opts.biff == 8;
var ref, rr = "", cols = []; var ref, rr = "", cols = [];
var range = safe_decode_range(ws['!ref'] || "A1"); var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8; var MAX_ROWS = b8 ? 65536 : 16384;
if(range.e.c > 0xFF || range.e.r >= MAX_ROWS) {
if(opts.WTF) throw new Error("Range " + (ws['!ref'] || "A1") + " exceeds format limit A1:IV16384");
range.e.c = Math.min(range.e.c, 0xFF);
range.e.r = Math.min(range.e.c, MAX_ROWS-1);
}
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts)); write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */ /* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1)); write_biff_rec(ba, "CalcMode", writeuint16(1));