version bump 0.11.14: links

- BIFF5 + ODS read named ranges
- internal link range normalization
- BIFF8 + ODS link write
- internal link write (fixes #685 h/t @gawi)
This commit is contained in:
SheetJS 2017-12-14 20:18:40 -05:00
parent b17a09849a
commit b3873ea615
37 changed files with 817 additions and 264 deletions

View File

@ -102,7 +102,7 @@ pkg: bin/xlsx.njs xlsx.js ## Build pkg standalone executable
.PHONY: test mocha
test mocha: test.js ## Run test suite
mocha -R spec -t 20000
mocha -R spec -t 30000
#* To run tests for one format, make test_<fmt>
#* To run the core test suite, make test_misc
@ -203,11 +203,11 @@ $(COVFMT): cov_%:
FMTS=$* make cov
misc/coverage.html: $(TARGET) test.js
mocha --require blanket -R html-cov -t 20000 > $@
mocha --require blanket -R html-cov -t 30000 > $@
.PHONY: coveralls
coveralls: ## Coverage Test + Send to coveralls.io
mocha --require blanket --reporter mocha-lcov-reporter -t 20000 | node ./node_modules/coveralls/bin/coveralls.js
mocha --require blanket --reporter mocha-lcov-reporter -t 30000 | node ./node_modules/coveralls/bin/coveralls.js
READEPS=$(sort $(wildcard docbits/*.md))
README.md: $(READEPS)

View File

@ -1372,6 +1372,7 @@ sense when the producer and consumer of files are in the same locale, but that
is not always the case over the Internet. To get around this ambiguity, parse
functions accept the `dateNF` option to override the interpretation of that
specific format string.
#### Hyperlinks
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
@ -1389,6 +1390,13 @@ ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
Note that Excel does not automatically style hyperlinks -- they will generally
be displayed as normal text.
Links where the target is a cell or range or defined name in the same workbook
("Internal Links") are marked with a leading hash character:
```js
ws['A2'].l = { Target:"#E2" }; /* link to cell E2 */
```
#### Cell Comments
Cell comments are objects stored in the `c` array of cell objects. The actual

View File

@ -1 +1 @@
XLSX.version = '0.11.13';
XLSX.version = '0.11.14';

View File

@ -423,30 +423,64 @@ function parse_HyperlinkMoniker(blob, length) {
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
function parse_HyperlinkString(blob, length) {
var len = blob.read_shift(4);
var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
return o;
}
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
function parse_Hyperlink(blob, length) {
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
function parse_Hyperlink(blob, length)/*:Hyperlink*/ {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
var flags = blob.read_shift(2);
blob.l += 2;
var displayName, targetFrameName, moniker, oleMoniker, location, guid, fileTime;
var displayName, targetFrameName, moniker, oleMoniker, Location="", guid, fileTime;
if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0008) Location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0020) guid = blob.read_shift(16);
if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
blob.l = end;
var target = (targetFrameName||moniker||oleMoniker);
if(location) target+="#"+location;
var target = targetFrameName||moniker||oleMoniker||"";
if(target && Location) target+="#"+Location;
if(!target) target = "#" + Location;
return {Target: target};
}
function write_Hyperlink(hl) {
var out = new_buf(512), i = 0;
var Target = hl.Target;
var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
out.write_shift(4,2); out.write_shift(4, F);
var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
if(F == 0x1C) {
Target = Target.slice(1);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else if(F & 0x02) {
data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
out.write_shift(4, 2*(Target.length + 1));
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else {
data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
var P = 0;
while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
out.write_shift(2, P);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
out.write_shift(1, 0);
out.write_shift(2, 0xFFFF);
out.write_shift(2, 0xDEAD);
for(i = 0; i < 6; ++i) out.write_shift(4, 0);
}
return out.slice(0, out.l);
}
/* 2.5.178 LongRGBA */
function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }

View File

@ -601,8 +601,9 @@ function parse_Lbl(blob, length, opts) {
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
var itab = 0;
if(!opts || opts.biff >= 5) {
blob.l += 2;
if(opts.biff != 5) blob.l += 2;
itab = blob.read_shift(2);
if(opts.biff == 5) blob.l += 2;
blob.l += 4;
}
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
@ -787,6 +788,16 @@ function parse_HLink(blob, length) {
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
}
function write_HLink(hl) {
var O = new_buf(24);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
return bconcat([O, write_Hyperlink(hl[1])]);
}
/* 2.4.141 */
function parse_HLinkTooltip(blob, length) {
@ -797,6 +808,17 @@ function parse_HLinkTooltip(blob, length) {
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
}
function write_HLinkTooltip(hl) {
var TT = hl[1].Tooltip;
var O = new_buf(10 + 2 * (TT.length + 1));
O.write_shift(2, 0x0800);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
O.write_shift(2, 0);
return O;
}
/* 2.4.63 */
function parse_Country(blob, length) {

View File

@ -108,19 +108,19 @@ function parse_EncryptionHeader(blob, length/*:number*/) {
o.KeySize = blob.read_shift(4);
o.ProviderType = blob.read_shift(4);
blob.l += 8;
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le').slice(0,-1);
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
blob.l = tgt;
return o;
}
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
function parse_EncryptionVerifier(blob, length/*:number*/) {
var o = {};
var o = {}, tgt = blob.l + length;
blob.l += 4; // SaltSize must be 0x10
o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
var sz = blob.read_shift(4);
o.VerifierHash = blob.slice(blob.l, blob.l + sz); blob.l += sz;
o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
return o;
}

View File

@ -20,8 +20,13 @@ function csf_to_ods_formula(f/*:string*/)/*:string*/ {
return o.replace(/;/g, "|").replace(/,/g,";");
}
function ods_to_csf_range_3D(r/*:string*/)/*:[string, string]*/ {
function ods_to_csf_3D(r/*:string*/)/*:[string, string]*/ {
var a = r.split(":");
var s = a[0].split(".")[0];
return [s, a[0].split(".")[1] + ":" + a[1].split(".")[1]];
return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
}
function csf_to_ods_3D(r/*:string*/)/*:string*/ {
return r.replace(/\./,"!");
}

View File

@ -122,16 +122,15 @@ function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
for(var i = 0; i != data.length; ++i) {
var val = parsexmltag(utf8read(data[i]), true);
if(!val.ref) return;
var rel = rels ? rels['!id'][val.id] : null;
var rel = ((rels || {})['!id']||[])[val.id];
if(rel) {
val.Target = rel.Target;
if(val.location) val.Target += "#"+val.location;
val.Rel = rel;
} else {
val.Target = val.location;
rel = {Target: val.location, TargetMode: 'Internal'};
val.Rel = rel;
val.Target = "#" + val.location;
rel = {Target: val.Target, TargetMode: 'Internal'};
}
val.Rel = rel;
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
@ -505,8 +504,11 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
o[o.length] = "<hyperlinks>";
ws['!links'].forEach(function(l) {
if(!l[1].Target) return;
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel = ({"ref":l[0], "r:id":"rId"+rId}/*:any*/);
rel = ({"ref":l[0]}/*:any*/);
if(l[1].Target.charAt(0) != "#") {
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel["r:id"] = "rId"+rId;
}
if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.substr(relc+1));
if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
o[o.length] = writextag("hyperlink",null,rel);

View File

@ -265,8 +265,8 @@ function parse_BrtHLink(data, length, opts) {
if(tooltip) o.Tooltip = tooltip;
return o;
}
function write_BrtHLink(l, rId, o) {
if(o == null) o = new_buf(50+4*l[1].Target.length);
function write_BrtHLink(l, rId) {
var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
write_RelID("rId" + rId, o);
var locidx = l[1].Target.indexOf("#");
@ -493,6 +493,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/
val.Target = rel.Target;
if(val.loc) val.Target += "#"+val.loc;
val.Rel = rel;
} else if(val.relId == '') {
val.Target = "#" + val.loc;
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
if(opts.dense) {

View File

@ -77,8 +77,9 @@ function parse_BrtName(data, length, opts) {
// unusedstring2: XLNullableWideString
//}
data.l = end;
var out = ({Name:name, Ptg:formula, Comment:comment}/*:any*/);
var out = ({Name:name, Ptg:formula}/*:any*/);
if(itab < 0xFFFFFFF) out.Sheet = itab;
if(comment) out.Comment = comment;
return out;
}

View File

@ -216,7 +216,8 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
} else cursheet[encode_col(c) + encode_row(r)] = cell;
}
if(cell.HRef) {
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
cell.l = ({Target:cell.HRef}/*:any*/);
if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
delete cell.HRef; delete cell.HRefScreenTip;
}
if(cell.MergeAcross || cell.MergeDown) {
@ -962,7 +963,7 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb
if(o.length == 0) return "";
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
}
function write_ws_xlml_comment(comments) {
function write_ws_xlml_comment(comments/*:Array<any>*/)/*:string*/ {
return comments.map(function(c) {
// TODO: formatted text
var t = xlml_unfixstr(c.t||"");
@ -970,7 +971,7 @@ function write_ws_xlml_comment(comments) {
return writextag("Comment", d, {"ss:Author":c.a});
}).join("");
}
function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, addr)/*:string*/{
if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>";
var attr = {};

View File

@ -85,6 +85,15 @@ function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
return ba.end();
}
function write_ws_biff8_hlinks(ba/*:BufArray*/, ws) {
for(var R=0; R<ws['!links'].length; ++R) {
var HL = ws['!links'][R];
write_biff_rec(ba, "HLink", write_HLink(HL));
if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
}
delete ws['!links'];
}
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
@ -109,6 +118,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
var dense = Array.isArray(ws);
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8, b5 = opts.biff == 5;
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1));
@ -128,6 +138,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
/* ... */
if(b8) ws['!links'] = [];
for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) {
@ -137,9 +148,13 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);
if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
}
}
var cname/*:string*/ = _sheet.CodeName || _sheet.name || s;
/* ... */
if(b8) write_ws_biff8_hlinks(ba, ws);
/* ... */
write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
/* ... */
write_biff_rec(ba, "EOF");

View File

@ -39,7 +39,7 @@ var parse_content_xml = (function() {
var rowtag/*:: = {'行号':""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [];
var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var Rn, q/*:: = ({t:"", v:null, z:null, w:"",c:[]}:any)*/;
var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/;
var ctag = ({value:""}/*:any*/);
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
@ -48,9 +48,12 @@ var parse_content_xml = (function() {
var merges = [], mrange = {}, mR = 0, mC = 0;
var rowinfo = [], rowpeat = 1, colpeat = 1;
var arrayf = [];
var WB = {Names:[]};
var atag = ({}/*:any*/);
var _Ref/*:[string, string]*/ = ["", ""];
var comments = [], comment = {};
var creator = "", creatoridx = 0;
var isstub = false;
var isstub = false, intable = false;
var i = 0;
xlmlregex.lastIndex = 0;
str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
@ -64,6 +67,7 @@ var parse_content_xml = (function() {
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
intable = false;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
@ -71,6 +75,7 @@ var parse_content_xml = (function() {
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = [];
rowinfo = [];
intable = true;
}
break;
@ -167,6 +172,7 @@ var parse_content_xml = (function() {
q.v = textp || '';
isstub = textpidx == 0;
}
if(atag.Target) q.l = atag;
if(comments.length > 0) { q.c = comments; comments = []; }
if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
@ -190,6 +196,7 @@ var parse_content_xml = (function() {
q = {/*:: t:"", v:null, z:null, w:"",c:[]*/};
textp = "";
}
atag = ({}/*:any*/);
break; // 9.1.4 <table:table-cell>
/* pure state */
@ -320,6 +327,15 @@ var parse_content_xml = (function() {
}
else pidx = Rn.index + Rn[0].length;
break;
case 'named-range': // 9.4.12 <table:named-range>
tag = parsexmltag(Rn[0], false);
_Ref = ods_to_csf_3D(tag['cell-range-address']);
var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]}/*:any*/);
if(intable) nrange.Sheet = SheetNames.length;
WB.Names.push(nrange);
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'embedded-text': break; // 16.27.4 <number:embedded-text>
@ -340,7 +356,6 @@ var parse_content_xml = (function() {
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'label-range': break; // 9.4.9 <table:label-range>
case 'label-ranges': break; // 9.4.10 <table:label-ranges>
case 'named-expression': break; // 9.4.13 <table:named-expression>
@ -360,8 +375,8 @@ var parse_content_xml = (function() {
case 'database-range': // 9.4.15 <table:database-range>
if(Rn[1]==='/') break;
try {
var AutoFilter = ods_to_csf_range_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[AutoFilter[0]]['!autofilter'] = { ref: AutoFilter[1] };
_Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
} catch(e) {/* empty */}
break;
@ -476,7 +491,17 @@ var parse_content_xml = (function() {
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
case 'a': // 6.1.8 hyperlink
if(Rn[1]!== '/') {
atag = parsexmltag(Rn[0], false);
if(!atag.href) break;
atag.Target = atag.href; delete atag.href;
if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
_Ref = ods_to_csf_3D(atag.Target.slice(1));
atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
}
}
break;
/* non-standard */
case 'table-protection': break;
@ -499,10 +524,11 @@ var parse_content_xml = (function() {
default: if(opts.WTF) throw new Error(Rn);
}
}
var out = {
var out/*:Workbook*/ = ({
Sheets: Sheets,
SheetNames: SheetNames
};
SheetNames: SheetNames,
Workbook: WB
}/*:any*/);
if(opts.bookSheets) delete out.Sheets;
return out;
};

View File

@ -90,7 +90,12 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = (function() {
//case 'e':
default: o.push(null_cell_xml); continue;
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', write_text_p(textp), {}), ct) + '\n');
var text_p = write_text_p(textp);
if(cell.l && cell.l.Target) {
var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
}
o.push(' </table:table-row>\n');
}

View File

@ -212,6 +212,8 @@ function parse_xlsxcfb(cfb, _opts/*:?ParseOpts*/)/*:Workbook*/ {
/*:: declare var decrypt_agile:any; */
if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
/*:: declare var decrypt_std76:any; */
if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
throw new Error("File is password-protected");
}

View File

@ -80,6 +80,7 @@ utils.cell_set_hyperlink = function(cell/*:Cell*/, target/*:string*/, tooltip/*:
}
return cell;
};
utils.cell_set_internal_link = function(cell/*:Cell*/, range/*:string*/, tooltip/*:?string*/) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
/* add to cell comments */
utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?string*/) {

30
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

26
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

225
dist/xlsx.js generated vendored
View File

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.11.13';
XLSX.version = '0.11.14';
var current_codepage = 1200;
/*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -4428,30 +4428,64 @@ function parse_HyperlinkMoniker(blob, length) {
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
function parse_HyperlinkString(blob, length) {
var len = blob.read_shift(4);
var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
return o;
}
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
function parse_Hyperlink(blob, length) {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
var flags = blob.read_shift(2);
blob.l += 2;
var displayName, targetFrameName, moniker, oleMoniker, location, guid, fileTime;
var displayName, targetFrameName, moniker, oleMoniker, Location="", guid, fileTime;
if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0008) Location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0020) guid = blob.read_shift(16);
if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
blob.l = end;
var target = (targetFrameName||moniker||oleMoniker);
if(location) target+="#"+location;
var target = targetFrameName||moniker||oleMoniker||"";
if(target && Location) target+="#"+Location;
if(!target) target = "#" + Location;
return {Target: target};
}
function write_Hyperlink(hl) {
var out = new_buf(512), i = 0;
var Target = hl.Target;
var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
out.write_shift(4,2); out.write_shift(4, F);
var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
if(F == 0x1C) {
Target = Target.slice(1);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else if(F & 0x02) {
data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
out.write_shift(4, 2*(Target.length + 1));
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else {
data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
var P = 0;
while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
out.write_shift(2, P);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
out.write_shift(1, 0);
out.write_shift(2, 0xFFFF);
out.write_shift(2, 0xDEAD);
for(i = 0; i < 6; ++i) out.write_shift(4, 0);
}
return out.slice(0, out.l);
}
/* 2.5.178 LongRGBA */
function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
@ -5063,8 +5097,9 @@ function parse_Lbl(blob, length, opts) {
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
var itab = 0;
if(!opts || opts.biff >= 5) {
blob.l += 2;
if(opts.biff != 5) blob.l += 2;
itab = blob.read_shift(2);
if(opts.biff == 5) blob.l += 2;
blob.l += 4;
}
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
@ -5249,6 +5284,16 @@ function parse_HLink(blob, length) {
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
}
function write_HLink(hl) {
var O = new_buf(24);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
return bconcat([O, write_Hyperlink(hl[1])]);
}
/* 2.4.141 */
function parse_HLinkTooltip(blob, length) {
@ -5259,6 +5304,17 @@ function parse_HLinkTooltip(blob, length) {
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
}
function write_HLinkTooltip(hl) {
var TT = hl[1].Tooltip;
var O = new_buf(10 + 2 * (TT.length + 1));
O.write_shift(2, 0x0800);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
O.write_shift(2, 0);
return O;
}
/* 2.4.63 */
function parse_Country(blob, length) {
@ -7026,19 +7082,19 @@ function parse_EncryptionHeader(blob, length) {
o.KeySize = blob.read_shift(4);
o.ProviderType = blob.read_shift(4);
blob.l += 8;
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le').slice(0,-1);
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
blob.l = tgt;
return o;
}
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
function parse_EncryptionVerifier(blob, length) {
var o = {};
var o = {}, tgt = blob.l + length;
blob.l += 4; // SaltSize must be 0x10
o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
var sz = blob.read_shift(4);
o.VerifierHash = blob.slice(blob.l, blob.l + sz); blob.l += sz;
o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
return o;
}
@ -11387,11 +11443,16 @@ function csf_to_ods_formula(f) {
return o.replace(/;/g, "|").replace(/,/g,";");
}
function ods_to_csf_range_3D(r) {
function ods_to_csf_3D(r) {
var a = r.split(":");
var s = a[0].split(".")[0];
return [s, a[0].split(".")[1] + ":" + a[1].split(".")[1]];
return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
}
function csf_to_ods_3D(r) {
return r.replace(/\./,"!");
}
var strs = {}; // shared strings
var _ssfopts = {}; // spreadsheet formatting options
@ -11615,16 +11676,15 @@ function parse_ws_xml_hlinks(s, data, rels) {
for(var i = 0; i != data.length; ++i) {
var val = parsexmltag(utf8read(data[i]), true);
if(!val.ref) return;
var rel = rels ? rels['!id'][val.id] : null;
var rel = ((rels || {})['!id']||[])[val.id];
if(rel) {
val.Target = rel.Target;
if(val.location) val.Target += "#"+val.location;
val.Rel = rel;
} else {
val.Target = val.location;
rel = {Target: val.location, TargetMode: 'Internal'};
val.Rel = rel;
val.Target = "#" + val.location;
rel = {Target: val.Target, TargetMode: 'Internal'};
}
val.Rel = rel;
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
@ -11998,8 +12058,11 @@ function write_ws_xml(idx, opts, wb, rels) {
o[o.length] = "<hyperlinks>";
ws['!links'].forEach(function(l) {
if(!l[1].Target) return;
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel = ({"ref":l[0], "r:id":"rId"+rId});
rel = ({"ref":l[0]});
if(l[1].Target.charAt(0) != "#") {
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel["r:id"] = "rId"+rId;
}
if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.substr(relc+1));
if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
o[o.length] = writextag("hyperlink",null,rel);
@ -12312,8 +12375,8 @@ function parse_BrtHLink(data, length, opts) {
if(tooltip) o.Tooltip = tooltip;
return o;
}
function write_BrtHLink(l, rId, o) {
if(o == null) o = new_buf(50+4*l[1].Target.length);
function write_BrtHLink(l, rId) {
var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
write_RelID("rId" + rId, o);
var locidx = l[1].Target.indexOf("#");
@ -12539,6 +12602,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
val.Target = rel.Target;
if(val.loc) val.Target += "#"+val.loc;
val.Rel = rel;
} else if(val.relId == '') {
val.Target = "#" + val.loc;
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
if(opts.dense) {
@ -13461,8 +13526,9 @@ function parse_BrtName(data, length, opts) {
// unusedstring2: XLNullableWideString
//}
data.l = end;
var out = ({Name:name, Ptg:formula, Comment:comment});
var out = ({Name:name, Ptg:formula});
if(itab < 0xFFFFFFF) out.Sheet = itab;
if(comment) out.Comment = comment;
return out;
}
@ -13970,7 +14036,8 @@ function parse_xlml_xml(d, _opts) {
} else cursheet[encode_col(c) + encode_row(r)] = cell;
}
if(cell.HRef) {
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
cell.l = ({Target:cell.HRef});
if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
delete cell.HRef; delete cell.HRefScreenTip;
}
if(cell.MergeAcross || cell.MergeDown) {
@ -17086,6 +17153,15 @@ function write_biff2_buf(wb, opts) {
return ba.end();
}
function write_ws_biff8_hlinks(ba, ws) {
for(var R=0; R<ws['!links'].length; ++R) {
var HL = ws['!links'][R];
write_biff_rec(ba, "HLink", write_HLink(HL));
if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
}
delete ws['!links'];
}
function write_ws_biff8_cell(ba, cell, R, C, opts) {
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
@ -17110,6 +17186,7 @@ function write_ws_biff8(idx, opts, wb) {
var dense = Array.isArray(ws);
var ref, rr = "", cols = [];
var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8, b5 = opts.biff == 5;
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1));
@ -17129,6 +17206,7 @@ function write_ws_biff8(idx, opts, wb) {
write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
/* ... */
if(b8) ws['!links'] = [];
for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) {
@ -17138,9 +17216,13 @@ function write_ws_biff8(idx, opts, wb) {
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);
if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
}
}
var cname = _sheet.CodeName || _sheet.name || s;
/* ... */
if(b8) write_ws_biff8_hlinks(ba, ws);
/* ... */
write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
/* ... */
write_biff_rec(ba, "EOF");
@ -17257,32 +17339,25 @@ var HTML_ = (function() {
var tag = parsexmltag(cell.slice(0, cell.indexOf(">")));
CS = tag.colspan ? +tag.colspan : 1;
if((RS = +tag.rowspan)>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
var _t = tag.t || "";
/* TODO: generate stub cells */
if(!m.length) { C += CS; continue; }
m = htmldecode(unescapexml(m));
if(range.s.r > R) range.s.r = R;
if(range.e.r < R) range.e.r = R;
if(range.s.c > C) range.s.c = C;
if(range.e.c < C) range.e.c = C;
if(opts.dense) {
if(!ws[R]) ws[R] = [];
if(!m.length){}
else if(opts.raw || !m.trim().length) ws[R][C] = {t:'s', v:m};
else if(m === 'TRUE') ws[R][C] = {t:'b', v:true};
else if(m === 'FALSE') ws[R][C] = {t:'b', v:false};
else if(!isNaN(fuzzynum(m))) ws[R][C] = {t:'n', v:fuzzynum(m)};
else ws[R][C] = {t:'s', v:m};
} else {
var coord = encode_cell({r:R, c:C});
/* TODO: value parsing */
if(!m.length){}
else if(opts.raw) ws[coord] = {t:'s', v:m};
else if(opts.raw || !m.trim().length) ws[coord] = {t:'s', v:m};
else if(m === 'TRUE') ws[coord] = {t:'b', v:true};
else if(m === 'FALSE') ws[coord] = {t:'b', v:false};
else if(!isNaN(fuzzynum(m))) ws[coord] = {t:'n', v:fuzzynum(m)};
else ws[coord] = {t:'s', v:m};
if(range.s.r > R) range.s.r = R; if(range.e.r < R) range.e.r = R;
if(range.s.c > C) range.s.c = C; if(range.e.c < C) range.e.c = C;
if(!m.length) continue;
var o = {t:'s', v:m};
if(opts.raw || !m.trim().length || _t == 's'){}
else if(m === 'TRUE') o = {t:'b', v:true};
else if(m === 'FALSE') o = {t:'b', v:false};
else if(!isNaN(fuzzynum(m))) o = {t:'n', v:fuzzynum(m)};
else if(!isNaN(fuzzydate(m).getDate())) {
o = ({t:'d', v:parseDate(m)});
if(!opts.cellDates) o = ({t:'n', v:datenum(o.v)});
o.z = opts.dateNF || SSF._table[14];
}
if(opts.dense) { if(!ws[R]) ws[R] = []; ws[R][C] = o; }
else ws[encode_cell({r:R, c:C})] = o;
C += CS;
}
}
@ -17313,6 +17388,7 @@ var HTML_ = (function() {
var sp = {};
if(RS > 1) sp.rowspan = RS;
if(CS > 1) sp.colspan = CS;
sp.t = cell.t;
if(o.editable) w = '<span contenteditable="true">' + w + '</span>';
sp.id = "sjs-" + coord;
oo.push(writextag('td', w, sp));
@ -17371,10 +17447,10 @@ function parse_dom_table(table, _opts) {
CS = +elt.getAttribute("colspan") || 1;
if((RS = +elt.getAttribute("rowspan"))>0 || CS>1) merges.push({s:{r:R,c:C},e:{r:R + (RS||1) - 1, c:C + CS - 1}});
var o = {t:'s', v:v};
var _t = elt.getAttribute("t") || "";
if(v != null) {
if(v.length == 0) o.t = 'z';
else if(opts.raw){}
else if(v.trim().length == 0) o.t = 's';
if(v.length == 0) o.t = _t || 'z';
else if(opts.raw || v.trim().length == 0 || _t == "s"){}
else if(v === 'TRUE') o = {t:'b', v:true};
else if(v === 'FALSE') o = {t:'b', v:false};
else if(!isNaN(fuzzynum(v))) o = {t:'n', v:fuzzynum(v)};
@ -17448,9 +17524,12 @@ var parse_content_xml = (function() {
var merges = [], mrange = {}, mR = 0, mC = 0;
var rowinfo = [], rowpeat = 1, colpeat = 1;
var arrayf = [];
var WB = {Names:[]};
var atag = ({});
var _Ref = ["", ""];
var comments = [], comment = {};
var creator = "", creatoridx = 0;
var isstub = false;
var isstub = false, intable = false;
var i = 0;
xlmlregex.lastIndex = 0;
str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
@ -17464,6 +17543,7 @@ var parse_content_xml = (function() {
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
intable = false;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
@ -17471,6 +17551,7 @@ var parse_content_xml = (function() {
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = opts.dense ? ([]) : ({}); merges = [];
rowinfo = [];
intable = true;
}
break;
@ -17567,6 +17648,7 @@ var parse_content_xml = (function() {
q.v = textp || '';
isstub = textpidx == 0;
}
if(atag.Target) q.l = atag;
if(comments.length > 0) { q.c = comments; comments = []; }
if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
@ -17590,6 +17672,7 @@ var parse_content_xml = (function() {
q = {};
textp = "";
}
atag = ({});
break; // 9.1.4 <table:table-cell>
/* pure state */
@ -17720,6 +17803,15 @@ var parse_content_xml = (function() {
}
else pidx = Rn.index + Rn[0].length;
break;
case 'named-range': // 9.4.12 <table:named-range>
tag = parsexmltag(Rn[0], false);
_Ref = ods_to_csf_3D(tag['cell-range-address']);
var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
if(intable) nrange.Sheet = SheetNames.length;
WB.Names.push(nrange);
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'embedded-text': break; // 16.27.4 <number:embedded-text>
@ -17740,7 +17832,6 @@ var parse_content_xml = (function() {
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'label-range': break; // 9.4.9 <table:label-range>
case 'label-ranges': break; // 9.4.10 <table:label-ranges>
case 'named-expression': break; // 9.4.13 <table:named-expression>
@ -17760,8 +17851,8 @@ var parse_content_xml = (function() {
case 'database-range': // 9.4.15 <table:database-range>
if(Rn[1]==='/') break;
try {
var AutoFilter = ods_to_csf_range_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[AutoFilter[0]]['!autofilter'] = { ref: AutoFilter[1] };
_Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
} catch(e) {/* empty */}
break;
@ -17876,7 +17967,17 @@ var parse_content_xml = (function() {
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
case 'a': // 6.1.8 hyperlink
if(Rn[1]!== '/') {
atag = parsexmltag(Rn[0], false);
if(!atag.href) break;
atag.Target = atag.href; delete atag.href;
if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
_Ref = ods_to_csf_3D(atag.Target.slice(1));
atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
}
}
break;
/* non-standard */
case 'table-protection': break;
@ -17899,10 +18000,11 @@ var parse_content_xml = (function() {
default: if(opts.WTF) throw new Error(Rn);
}
}
var out = {
var out = ({
Sheets: Sheets,
SheetNames: SheetNames
};
SheetNames: SheetNames,
Workbook: WB
});
if(opts.bookSheets) delete out.Sheets;
return out;
};
@ -18014,7 +18116,12 @@ var write_content_ods = (function() {
//case 'e':
default: o.push(null_cell_xml); continue;
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', write_text_p(textp), {}), ct) + '\n');
var text_p = write_text_p(textp);
if(cell.l && cell.l.Target) {
var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
}
o.push(' </table:table-row>\n');
}
@ -18421,6 +18528,7 @@ function parse_xlsxcfb(cfb, _opts) {
data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
throw new Error("File is password-protected");
}
@ -19102,6 +19210,7 @@ utils.cell_set_hyperlink = function(cell, target, tooltip) {
}
return cell;
};
utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
/* add to cell comments */
utils.cell_add_comment = function(cell, text, author) {

24
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

View File

@ -78,3 +78,4 @@ sense when the producer and consumer of files are in the same locale, but that
is not always the case over the Internet. To get around this ambiguity, parse
functions accept the `dateNF` option to override the interpretation of that
specific format string.

View File

@ -15,3 +15,10 @@ ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
Note that Excel does not automatically style hyperlinks -- they will generally
be displayed as normal text.
Links where the target is a cell or range or defined name in the same workbook
("Internal Links") are marked with a leading hash character:
```js
ws['A2'].l = { Target:"#E2" }; /* link to cell E2 */
```

View File

@ -1255,6 +1255,7 @@ sense when the producer and consumer of files are in the same locale, but that
is not always the case over the Internet. To get around this ambiguity, parse
functions accept the `dateNF` option to override the interpretation of that
specific format string.
#### Hyperlinks
Hyperlinks are stored in the `l` key of cell objects. The `Target` field of the
@ -1272,6 +1273,13 @@ ws['A3'].l = { Target:"http://sheetjs.com", Tooltip:"Find us @ SheetJS.com!" };
Note that Excel does not automatically style hyperlinks -- they will generally
be displayed as normal text.
Links where the target is a cell or range or defined name in the same workbook
("Internal Links") are marked with a leading hash character:
```js
ws['A2'].l = { Target:"#E2" }; /* link to cell E2 */
```
#### Cell Comments
Cell comments are objects stored in the `c` array of cell objects. The actual

View File

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

76
test.js
View File

@ -129,6 +129,13 @@ var paths = {
hlxlsx: dir + 'hyperlink_stress_test_2011.xlsx',
hlxlsb: dir + 'hyperlink_stress_test_2011.xlsb',
ilxls: dir + 'internal_link.xls',
ilxls5: dir + 'internal_link.biff5',
ilxml: dir + 'internal_link.xml',
ilxlsx: dir + 'internal_link.xlsx',
ilxlsb: dir + 'internal_link.xlsb',
ilods: dir + 'internal_link.ods',
lonxls: dir + 'LONumbers.xls',
lonxlsx: dir + 'LONumbers.xlsx',
@ -183,6 +190,7 @@ var NFPaths = pathit("nf", ["xlsx", "xlsb", "xls", "xml"]);
var DTPaths = pathit("dt", ["xlsx", "xlsb", "xls", "xml"]);
var NFPaths = pathit("nf", ["xlsx", "xlsb", "xls", "xml"]);
var HLPaths = pathit("hl", ["xlsx", "xlsb", "xls", "xml"]);
var ILPaths = pathit("il", ["xlsx", "xlsb", "xls", "xml", "ods", "xls5"]);
var OLPaths = pathit("ol", ["xlsx", "xlsb", "xls", "ods", "xls5"]);
var PMPaths = pathit("pm", ["xlsx", "xlsb", "xls", "xml", "xls5"]);
var SVPaths = pathit("sv", ["xlsx", "xlsb", "xls", "xml", "xls5"]);
@ -714,20 +722,28 @@ function diffsty(ws, r1,r2) {
});
}
function hlink(ws) {
[
["A1", "http://www.sheetjs.com"],
["A2", "http://oss.sheetjs.com"],
["A3", "http://oss.sheetjs.com#foo"],
["A4", "mailto:dev@sheetjs.com"],
["A5", "mailto:dev@sheetjs.com?subject=hyperlink"],
["A6", "../../sheetjs/Documents/Test.xlsx"],
["A7", "http://sheetjs.com", "foo bar baz"]
].forEach(function(r) {
assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
assert.equal(get_cell(ws, r[0]).l.Tooltip, r[2]);
});
}
function hlink1(ws) {[
["A1", "http://www.sheetjs.com"],
["A2", "http://oss.sheetjs.com"],
["A3", "http://oss.sheetjs.com#foo"],
["A4", "mailto:dev@sheetjs.com"],
["A5", "mailto:dev@sheetjs.com?subject=hyperlink"],
["A6", "../../sheetjs/Documents/Test.xlsx"],
["A7", "http://sheetjs.com", "foo bar baz"]
].forEach(function(r) {
assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
if(r[2]) assert.equal(get_cell(ws, r[0]).l.Tooltip, r[2]);
}); }
function hlink2(ws) { [
["A1", "#Sheet2!A1"],
["A2", "#WBScope"],
["A3", "#Sheet1!WSScope1", "#Sheet1!C7:E8"],
["A5", "#Sheet1!A5"]
].forEach(function(r) {
if(r[2] && get_cell(ws, r[0]).l.Target == r[2]) return;
assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
}); }
function check_margin(margins, exp) {
["left", "right", "top", "bottom", "header", "footer"].forEach(function(m,i) {
@ -977,16 +993,20 @@ describe('parse features', function() {
});
describe('should find hyperlinks', function() {
var wbs;
var wb1, wb2;
var bef = (function() {
X = require(modp);
wbs = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
wb1 = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
wb2 = ILPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
['XLSX', 'XLSB', 'XLS', 'XML'].forEach(function(x, i) {
it(x, function() { hlink(wbs[i].Sheets.Sheet1); });
['xlsx', 'xlsb', 'xls', 'xml'].forEach(function(x, i) {
it(x + " external", function() { hlink1(wb1[i].Sheets.Sheet1); });
});
['xlsx', 'xlsb', 'xls', 'xml', 'ods'].forEach(function(x, i) {
it(x + " internal", function() { hlink2(wb2[i].Sheets.Sheet1); });
});
});
@ -1351,13 +1371,19 @@ describe('roundtrip features', function() {
}); }); });
describe('should preserve hyperlink', function() { [
['xlml', paths.hlxml],
['xlsx', paths.hlxlsx],
['xlsb', paths.hlxlsb]
].forEach(function(w) { it(w[0], function() {
var wb = X.read(fs.readFileSync(w[1]), {type:TYPE});
hlink(wb.Sheets.Sheet1);
wb = X.read(X.write(wb, {bookType:w[0], type:TYPE}), {type:TYPE});
['xlml', paths.hlxml, true],
['xls', paths.hlxls, true],
['xlsx', paths.hlxlsx, true],
['xlsb', paths.hlxlsb, true],
['xlml', paths.ilxml, false],
['xls', paths.ilxls, false],
['xlsx', paths.ilxlsx, false],
['xlsb', paths.ilxlsb, false],
['ods', paths.ilods, false]
].forEach(function(w) { it(w[0]+" "+(w[2]?"ex":"in")+ "ternal", function() {
var wb = X.read(fs.readFileSync(w[1]), {type:TYPE, WTF:opts.WTF});
var hlink = (w[2] ? hlink1 : hlink2); hlink(wb.Sheets.Sheet1);
wb = X.read(X.write(wb, {bookType:w[0], type:TYPE, WTF:opts.WTF}), {type:TYPE, WTF:opts.WTF});
hlink(wb.Sheets.Sheet1);
}); }); });

@ -1 +1 @@
Subproject commit 8b3f773774567a164c0654a0b8056db680c3e5a5
Subproject commit a889cc5c7131bce253d5e861dcdf46ae60a9c4fd

View File

@ -129,6 +129,13 @@ var paths = {
hlxlsx: dir + 'hyperlink_stress_test_2011.xlsx',
hlxlsb: dir + 'hyperlink_stress_test_2011.xlsb',
ilxls: dir + 'internal_link.xls',
ilxls5: dir + 'internal_link.biff5',
ilxml: dir + 'internal_link.xml',
ilxlsx: dir + 'internal_link.xlsx',
ilxlsb: dir + 'internal_link.xlsb',
ilods: dir + 'internal_link.ods',
lonxls: dir + 'LONumbers.xls',
lonxlsx: dir + 'LONumbers.xlsx',
@ -183,6 +190,7 @@ var NFPaths = pathit("nf", ["xlsx", "xlsb", "xls", "xml"]);
var DTPaths = pathit("dt", ["xlsx", "xlsb", "xls", "xml"]);
var NFPaths = pathit("nf", ["xlsx", "xlsb", "xls", "xml"]);
var HLPaths = pathit("hl", ["xlsx", "xlsb", "xls", "xml"]);
var ILPaths = pathit("il", ["xlsx", "xlsb", "xls", "xml", "ods", "xls5"]);
var OLPaths = pathit("ol", ["xlsx", "xlsb", "xls", "ods", "xls5"]);
var PMPaths = pathit("pm", ["xlsx", "xlsb", "xls", "xml", "xls5"]);
var SVPaths = pathit("sv", ["xlsx", "xlsb", "xls", "xml", "xls5"]);
@ -714,20 +722,28 @@ function diffsty(ws, r1,r2) {
});
}
function hlink(ws) {
[
["A1", "http://www.sheetjs.com"],
["A2", "http://oss.sheetjs.com"],
["A3", "http://oss.sheetjs.com#foo"],
["A4", "mailto:dev@sheetjs.com"],
["A5", "mailto:dev@sheetjs.com?subject=hyperlink"],
["A6", "../../sheetjs/Documents/Test.xlsx"],
["A7", "http://sheetjs.com", "foo bar baz"]
].forEach(function(r) {
assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
assert.equal(get_cell(ws, r[0]).l.Tooltip, r[2]);
});
}
function hlink1(ws) {[
["A1", "http://www.sheetjs.com"],
["A2", "http://oss.sheetjs.com"],
["A3", "http://oss.sheetjs.com#foo"],
["A4", "mailto:dev@sheetjs.com"],
["A5", "mailto:dev@sheetjs.com?subject=hyperlink"],
["A6", "../../sheetjs/Documents/Test.xlsx"],
["A7", "http://sheetjs.com", "foo bar baz"]
].forEach(function(r) {
assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
if(r[2]) assert.equal(get_cell(ws, r[0]).l.Tooltip, r[2]);
}); }
function hlink2(ws) { [
["A1", "#Sheet2!A1"],
["A2", "#WBScope"],
["A3", "#Sheet1!WSScope1", "#Sheet1!C7:E8"],
["A5", "#Sheet1!A5"]
].forEach(function(r) {
if(r[2] && get_cell(ws, r[0]).l.Target == r[2]) return;
assert.equal(get_cell(ws, r[0]).l.Target, r[1]);
}); }
function check_margin(margins, exp) {
["left", "right", "top", "bottom", "header", "footer"].forEach(function(m,i) {
@ -977,16 +993,20 @@ describe('parse features', function() {
});
describe('should find hyperlinks', function() {
var wbs;
var wb1, wb2;
var bef = (function() {
X = require(modp);
wbs = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
wb1 = HLPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
wb2 = ILPaths.map(function(p) { return X.read(fs.readFileSync(p), {type:TYPE}); });
});
if(typeof before != 'undefined') before(bef);
else it('before', bef);
['XLSX', 'XLSB', 'XLS', 'XML'].forEach(function(x, i) {
it(x, function() { hlink(wbs[i].Sheets.Sheet1); });
['xlsx', 'xlsb', 'xls', 'xml'].forEach(function(x, i) {
it(x + " external", function() { hlink1(wb1[i].Sheets.Sheet1); });
});
['xlsx', 'xlsb', 'xls', 'xml', 'ods'].forEach(function(x, i) {
it(x + " internal", function() { hlink2(wb2[i].Sheets.Sheet1); });
});
});
@ -1351,13 +1371,19 @@ describe('roundtrip features', function() {
}); }); });
describe('should preserve hyperlink', function() { [
['xlml', paths.hlxml],
['xlsx', paths.hlxlsx],
['xlsb', paths.hlxlsb]
].forEach(function(w) { it(w[0], function() {
var wb = X.read(fs.readFileSync(w[1]), {type:TYPE});
hlink(wb.Sheets.Sheet1);
wb = X.read(X.write(wb, {bookType:w[0], type:TYPE}), {type:TYPE});
['xlml', paths.hlxml, true],
['xls', paths.hlxls, true],
['xlsx', paths.hlxlsx, true],
['xlsb', paths.hlxlsb, true],
['xlml', paths.ilxml, false],
['xls', paths.ilxls, false],
['xlsx', paths.ilxlsx, false],
['xlsb', paths.ilxlsb, false],
['ods', paths.ilods, false]
].forEach(function(w) { it(w[0]+" "+(w[2]?"ex":"in")+ "ternal", function() {
var wb = X.read(fs.readFileSync(w[1]), {type:TYPE, WTF:opts.WTF});
var hlink = (w[2] ? hlink1 : hlink2); hlink(wb.Sheets.Sheet1);
wb = X.read(X.write(wb, {bookType:w[0], type:TYPE, WTF:opts.WTF}), {type:TYPE, WTF:opts.WTF});
hlink(wb.Sheets.Sheet1);
}); }); });

File diff suppressed because one or more lines are too long

View File

@ -70,6 +70,12 @@
./test_files/hyperlink_stress_test_2011.xml
./test_files/hyperlink_stress_test_2011.xlsx
./test_files/hyperlink_stress_test_2011.xlsb
./test_files/internal_link.xls
./test_files/internal_link.biff5
./test_files/internal_link.xml
./test_files/internal_link.xlsx
./test_files/internal_link.xlsb
./test_files/internal_link.ods
./test_files/LONumbers.xls
./test_files/LONumbers.xlsx
./test_files/merge_cells.xls

View File

@ -84,9 +84,13 @@ ws['!rows'] = wsrows;
/* TEST: hyperlink note: Excel does not automatically style hyperlinks */
/*
ws['A4'].l = { Target: "#E2" };
*/
XLSX.utils.cell_set_internal_link(ws['A4'], "E2");
/*
ws['A3'].l = { Target: "http://sheetjs.com", Tooltip: "Visit us <SheetJS.com!>" };
*/
XLSX.utils.cell_set_hyperlink(ws['A3'], "http://sheetjs.com", "Visit us <SheetJS.com!>" );
XLSX.utils.cell_set_hyperlink(ws['A3'], "http://sheetjs.com", "Visit us <SheetJS.com!>");
/* TEST: built-in format */
/*

3
types/index.d.ts vendored
View File

@ -718,6 +718,9 @@ export interface XLSX$Utils {
/** Set hyperlink for a cell */
cell_set_hyperlink(cell: CellObject, target: string, tooltip?: string): CellObject;
/** Set internal link for a cell */
cell_set_internal_link(cell: CellObject, target: string, tooltip?: string): CellObject;
/** Add comment to a cell */
cell_add_comment(cell: CellObject, text: string, author?: string): void;

View File

@ -79,6 +79,8 @@ ws['!cols'] = wscols;
ws['!rows'] = wsrows;
/* TEST: hyperlink note: Excel does not automatically style hyperlinks */
(<XLSX.CellObject>ws['A4']).l = { Target: "#E2" };
XLSX.utils.cell_set_internal_link(ws['A4'], "E2");
(<XLSX.CellObject>ws['A3']).l = { Target: "http://sheetjs.com", Tooltip: "Visit us <SheetJS.com!>" };
XLSX.utils.cell_set_hyperlink(ws['A3'], "http://sheetjs.com", "Visit us <SheetJS.com!>");

View File

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.11.13';
XLSX.version = '0.11.14';
var current_codepage = 1200;
/*:: declare var cptable:any; */
/*global cptable:true */
@ -4513,30 +4513,64 @@ function parse_HyperlinkMoniker(blob, length) {
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
function parse_HyperlinkString(blob, length) {
var len = blob.read_shift(4);
var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
return o;
}
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
function parse_Hyperlink(blob, length) {
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
function parse_Hyperlink(blob, length)/*:Hyperlink*/ {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
var flags = blob.read_shift(2);
blob.l += 2;
var displayName, targetFrameName, moniker, oleMoniker, location, guid, fileTime;
var displayName, targetFrameName, moniker, oleMoniker, Location="", guid, fileTime;
if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0008) Location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0020) guid = blob.read_shift(16);
if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
blob.l = end;
var target = (targetFrameName||moniker||oleMoniker);
if(location) target+="#"+location;
var target = targetFrameName||moniker||oleMoniker||"";
if(target && Location) target+="#"+Location;
if(!target) target = "#" + Location;
return {Target: target};
}
function write_Hyperlink(hl) {
var out = new_buf(512), i = 0;
var Target = hl.Target;
var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
out.write_shift(4,2); out.write_shift(4, F);
var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
if(F == 0x1C) {
Target = Target.slice(1);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else if(F & 0x02) {
data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
out.write_shift(4, 2*(Target.length + 1));
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else {
data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
var P = 0;
while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
out.write_shift(2, P);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
out.write_shift(1, 0);
out.write_shift(2, 0xFFFF);
out.write_shift(2, 0xDEAD);
for(i = 0; i < 6; ++i) out.write_shift(4, 0);
}
return out.slice(0, out.l);
}
/* 2.5.178 LongRGBA */
function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
@ -5148,8 +5182,9 @@ function parse_Lbl(blob, length, opts) {
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
var itab = 0;
if(!opts || opts.biff >= 5) {
blob.l += 2;
if(opts.biff != 5) blob.l += 2;
itab = blob.read_shift(2);
if(opts.biff == 5) blob.l += 2;
blob.l += 4;
}
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
@ -5334,6 +5369,16 @@ function parse_HLink(blob, length) {
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
}
function write_HLink(hl) {
var O = new_buf(24);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
return bconcat([O, write_Hyperlink(hl[1])]);
}
/* 2.4.141 */
function parse_HLinkTooltip(blob, length) {
@ -5344,6 +5389,17 @@ function parse_HLinkTooltip(blob, length) {
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
}
function write_HLinkTooltip(hl) {
var TT = hl[1].Tooltip;
var O = new_buf(10 + 2 * (TT.length + 1));
O.write_shift(2, 0x0800);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
O.write_shift(2, 0);
return O;
}
/* 2.4.63 */
function parse_Country(blob, length) {
@ -7112,19 +7168,19 @@ function parse_EncryptionHeader(blob, length/*:number*/) {
o.KeySize = blob.read_shift(4);
o.ProviderType = blob.read_shift(4);
blob.l += 8;
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le').slice(0,-1);
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
blob.l = tgt;
return o;
}
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
function parse_EncryptionVerifier(blob, length/*:number*/) {
var o = {};
var o = {}, tgt = blob.l + length;
blob.l += 4; // SaltSize must be 0x10
o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
var sz = blob.read_shift(4);
o.VerifierHash = blob.slice(blob.l, blob.l + sz); blob.l += sz;
o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
return o;
}
@ -11476,11 +11532,16 @@ function csf_to_ods_formula(f/*:string*/)/*:string*/ {
return o.replace(/;/g, "|").replace(/,/g,";");
}
function ods_to_csf_range_3D(r/*:string*/)/*:[string, string]*/ {
function ods_to_csf_3D(r/*:string*/)/*:[string, string]*/ {
var a = r.split(":");
var s = a[0].split(".")[0];
return [s, a[0].split(".")[1] + ":" + a[1].split(".")[1]];
return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
}
function csf_to_ods_3D(r/*:string*/)/*:string*/ {
return r.replace(/\./,"!");
}
var strs = {}; // shared strings
var _ssfopts = {}; // spreadsheet formatting options
@ -11704,16 +11765,15 @@ function parse_ws_xml_hlinks(s, data/*:Array<string>*/, rels) {
for(var i = 0; i != data.length; ++i) {
var val = parsexmltag(utf8read(data[i]), true);
if(!val.ref) return;
var rel = rels ? rels['!id'][val.id] : null;
var rel = ((rels || {})['!id']||[])[val.id];
if(rel) {
val.Target = rel.Target;
if(val.location) val.Target += "#"+val.location;
val.Rel = rel;
} else {
val.Target = val.location;
rel = {Target: val.location, TargetMode: 'Internal'};
val.Rel = rel;
val.Target = "#" + val.location;
rel = {Target: val.Target, TargetMode: 'Internal'};
}
val.Rel = rel;
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
@ -12087,8 +12147,11 @@ function write_ws_xml(idx/*:number*/, opts, wb/*:Workbook*/, rels)/*:string*/ {
o[o.length] = "<hyperlinks>";
ws['!links'].forEach(function(l) {
if(!l[1].Target) return;
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel = ({"ref":l[0], "r:id":"rId"+rId}/*:any*/);
rel = ({"ref":l[0]}/*:any*/);
if(l[1].Target.charAt(0) != "#") {
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel["r:id"] = "rId"+rId;
}
if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.substr(relc+1));
if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
o[o.length] = writextag("hyperlink",null,rel);
@ -12401,8 +12464,8 @@ function parse_BrtHLink(data, length, opts) {
if(tooltip) o.Tooltip = tooltip;
return o;
}
function write_BrtHLink(l, rId, o) {
if(o == null) o = new_buf(50+4*l[1].Target.length);
function write_BrtHLink(l, rId) {
var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
write_RelID("rId" + rId, o);
var locidx = l[1].Target.indexOf("#");
@ -12629,6 +12692,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/
val.Target = rel.Target;
if(val.loc) val.Target += "#"+val.loc;
val.Rel = rel;
} else if(val.relId == '') {
val.Target = "#" + val.loc;
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
if(opts.dense) {
@ -13553,8 +13618,9 @@ function parse_BrtName(data, length, opts) {
// unusedstring2: XLNullableWideString
//}
data.l = end;
var out = ({Name:name, Ptg:formula, Comment:comment}/*:any*/);
var out = ({Name:name, Ptg:formula}/*:any*/);
if(itab < 0xFFFFFFF) out.Sheet = itab;
if(comment) out.Comment = comment;
return out;
}
@ -14064,7 +14130,8 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ {
} else cursheet[encode_col(c) + encode_row(r)] = cell;
}
if(cell.HRef) {
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
cell.l = ({Target:cell.HRef}/*:any*/);
if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
delete cell.HRef; delete cell.HRefScreenTip;
}
if(cell.MergeAcross || cell.MergeDown) {
@ -14810,7 +14877,7 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb
if(o.length == 0) return "";
return writextag("WorksheetOptions", o.join(""), {xmlns:XLMLNS.x});
}
function write_ws_xlml_comment(comments) {
function write_ws_xlml_comment(comments/*:Array<any>*/)/*:string*/ {
return comments.map(function(c) {
// TODO: formatted text
var t = xlml_unfixstr(c.t||"");
@ -14818,7 +14885,7 @@ function write_ws_xlml_comment(comments) {
return writextag("Comment", d, {"ss:Author":c.a});
}).join("");
}
function write_ws_xlml_cell(cell, ref, ws, opts, idx, wb, addr)/*:string*/{
function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, addr)/*:string*/{
if(!cell || cell.v == undefined && cell.f == undefined) return "<Cell></Cell>";
var attr = {};
@ -17187,6 +17254,15 @@ function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
return ba.end();
}
function write_ws_biff8_hlinks(ba/*:BufArray*/, ws) {
for(var R=0; R<ws['!links'].length; ++R) {
var HL = ws['!links'][R];
write_biff_rec(ba, "HLink", write_HLink(HL));
if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
}
delete ws['!links'];
}
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
@ -17211,6 +17287,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
var dense = Array.isArray(ws);
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8, b5 = opts.biff == 5;
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1));
@ -17230,6 +17307,7 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
/* ... */
if(b8) ws['!links'] = [];
for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) {
@ -17239,9 +17317,13 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);
if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
}
}
var cname/*:string*/ = _sheet.CodeName || _sheet.name || s;
/* ... */
if(b8) write_ws_biff8_hlinks(ba, ws);
/* ... */
write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
/* ... */
write_biff_rec(ba, "EOF");
@ -17534,7 +17616,7 @@ var parse_content_xml = (function() {
var rowtag/*:: = {'行号':""}*/;
var Sheets = {}, SheetNames/*:Array<string>*/ = [];
var ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/);
var Rn, q/*:: = ({t:"", v:null, z:null, w:"",c:[]}:any)*/;
var Rn, q/*:: :any = ({t:"", v:null, z:null, w:"",c:[],}:any)*/;
var ctag = ({value:""}/*:any*/);
var textp = "", textpidx = 0, textptag/*:: = {}*/;
var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}};
@ -17543,9 +17625,12 @@ var parse_content_xml = (function() {
var merges = [], mrange = {}, mR = 0, mC = 0;
var rowinfo = [], rowpeat = 1, colpeat = 1;
var arrayf = [];
var WB = {Names:[]};
var atag = ({}/*:any*/);
var _Ref/*:[string, string]*/ = ["", ""];
var comments = [], comment = {};
var creator = "", creatoridx = 0;
var isstub = false;
var isstub = false, intable = false;
var i = 0;
xlmlregex.lastIndex = 0;
str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
@ -17559,6 +17644,7 @@ var parse_content_xml = (function() {
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
intable = false;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
@ -17566,6 +17652,7 @@ var parse_content_xml = (function() {
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = opts.dense ? ([]/*:any*/) : ({}/*:any*/); merges = [];
rowinfo = [];
intable = true;
}
break;
@ -17662,6 +17749,7 @@ var parse_content_xml = (function() {
q.v = textp || '';
isstub = textpidx == 0;
}
if(atag.Target) q.l = atag;
if(comments.length > 0) { q.c = comments; comments = []; }
if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
@ -17685,6 +17773,7 @@ var parse_content_xml = (function() {
q = {/*:: t:"", v:null, z:null, w:"",c:[]*/};
textp = "";
}
atag = ({}/*:any*/);
break; // 9.1.4 <table:table-cell>
/* pure state */
@ -17815,6 +17904,15 @@ var parse_content_xml = (function() {
}
else pidx = Rn.index + Rn[0].length;
break;
case 'named-range': // 9.4.12 <table:named-range>
tag = parsexmltag(Rn[0], false);
_Ref = ods_to_csf_3D(tag['cell-range-address']);
var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]}/*:any*/);
if(intable) nrange.Sheet = SheetNames.length;
WB.Names.push(nrange);
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'embedded-text': break; // 16.27.4 <number:embedded-text>
@ -17835,7 +17933,6 @@ var parse_content_xml = (function() {
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'label-range': break; // 9.4.9 <table:label-range>
case 'label-ranges': break; // 9.4.10 <table:label-ranges>
case 'named-expression': break; // 9.4.13 <table:named-expression>
@ -17855,8 +17952,8 @@ var parse_content_xml = (function() {
case 'database-range': // 9.4.15 <table:database-range>
if(Rn[1]==='/') break;
try {
var AutoFilter = ods_to_csf_range_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[AutoFilter[0]]['!autofilter'] = { ref: AutoFilter[1] };
_Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
} catch(e) {/* empty */}
break;
@ -17971,7 +18068,17 @@ var parse_content_xml = (function() {
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
case 'a': // 6.1.8 hyperlink
if(Rn[1]!== '/') {
atag = parsexmltag(Rn[0], false);
if(!atag.href) break;
atag.Target = atag.href; delete atag.href;
if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
_Ref = ods_to_csf_3D(atag.Target.slice(1));
atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
}
}
break;
/* non-standard */
case 'table-protection': break;
@ -17994,10 +18101,11 @@ var parse_content_xml = (function() {
default: if(opts.WTF) throw new Error(Rn);
}
}
var out = {
var out/*:Workbook*/ = ({
Sheets: Sheets,
SheetNames: SheetNames
};
SheetNames: SheetNames,
Workbook: WB
}/*:any*/);
if(opts.bookSheets) delete out.Sheets;
return out;
};
@ -18109,7 +18217,12 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = (function() {
//case 'e':
default: o.push(null_cell_xml); continue;
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', write_text_p(textp), {}), ct) + '\n');
var text_p = write_text_p(textp);
if(cell.l && cell.l.Target) {
var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
}
o.push(' </table:table-row>\n');
}
@ -18518,6 +18631,8 @@ function parse_xlsxcfb(cfb, _opts/*:?ParseOpts*/)/*:Workbook*/ {
/*:: declare var decrypt_agile:any; */
if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
/*:: declare var decrypt_std76:any; */
if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
throw new Error("File is password-protected");
}
@ -19202,6 +19317,7 @@ utils.cell_set_hyperlink = function(cell/*:Cell*/, target/*:string*/, tooltip/*:
}
return cell;
};
utils.cell_set_internal_link = function(cell/*:Cell*/, range/*:string*/, tooltip/*:?string*/) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
/* add to cell comments */
utils.cell_add_comment = function(cell/*:Cell*/, text/*:string*/, author/*:?string*/) {

181
xlsx.js generated
View File

@ -4,7 +4,7 @@
/*global global, exports, module, require:false, process:false, Buffer:false */
var XLSX = {};
(function make_xlsx(XLSX){
XLSX.version = '0.11.13';
XLSX.version = '0.11.14';
var current_codepage = 1200;
/*global cptable:true */
if(typeof module !== "undefined" && typeof require !== 'undefined') {
@ -4428,30 +4428,64 @@ function parse_HyperlinkMoniker(blob, length) {
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
function parse_HyperlinkString(blob, length) {
var len = blob.read_shift(4);
var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
var o = len > 0 ? blob.read_shift(len, 'utf16le').replace(chr0, "") : "";
return o;
}
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object */
function parse_Hyperlink(blob, length) {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
var flags = blob.read_shift(2);
blob.l += 2;
var displayName, targetFrameName, moniker, oleMoniker, location, guid, fileTime;
var displayName, targetFrameName, moniker, oleMoniker, Location="", guid, fileTime;
if(flags & 0x0010) displayName = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0080) targetFrameName = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0101) moniker = parse_HyperlinkString(blob, end - blob.l);
if((flags & 0x0101) === 0x0001) oleMoniker = parse_HyperlinkMoniker(blob, end - blob.l);
if(flags & 0x0008) location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0008) Location = parse_HyperlinkString(blob, end - blob.l);
if(flags & 0x0020) guid = blob.read_shift(16);
if(flags & 0x0040) fileTime = parse_FILETIME(blob/*, 8*/);
blob.l = end;
var target = (targetFrameName||moniker||oleMoniker);
if(location) target+="#"+location;
var target = targetFrameName||moniker||oleMoniker||"";
if(target && Location) target+="#"+Location;
if(!target) target = "#" + Location;
return {Target: target};
}
function write_Hyperlink(hl) {
var out = new_buf(512), i = 0;
var Target = hl.Target;
var F = Target.indexOf("#") > -1 ? 0x1f : 0x17;
switch(Target.charAt(0)) { case "#": F=0x1c; break; case ".": F&=~2; break; }
out.write_shift(4,2); out.write_shift(4, F);
var data = [8,6815827,6619237,4849780,83]; for(i = 0; i < data.length; ++i) out.write_shift(4, data[i]);
if(F == 0x1C) {
Target = Target.slice(1);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else if(F & 0x02) {
data = "e0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
out.write_shift(4, 2*(Target.length + 1));
for(i = 0; i < Target.length; ++i) out.write_shift(2, Target.charCodeAt(i));
out.write_shift(2, 0);
} else {
data = "03 03 00 00 00 00 00 00 c0 00 00 00 00 00 00 46".split(" ");
for(i = 0; i < data.length; ++i) out.write_shift(1, parseInt(data[i], 16));
var P = 0;
while(Target.slice(P*3,P*3+3)=="../"||Target.slice(P*3,P*3+3)=="..\\") ++P;
out.write_shift(2, P);
out.write_shift(4, Target.length + 1);
for(i = 0; i < Target.length; ++i) out.write_shift(1, Target.charCodeAt(i) & 0xFF);
out.write_shift(1, 0);
out.write_shift(2, 0xFFFF);
out.write_shift(2, 0xDEAD);
for(i = 0; i < 6; ++i) out.write_shift(4, 0);
}
return out.slice(0, out.l);
}
/* 2.5.178 LongRGBA */
function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }
@ -5063,8 +5097,9 @@ function parse_Lbl(blob, length, opts) {
var cce = blob.read_shift(opts && opts.biff == 2 ? 1 : 2);
var itab = 0;
if(!opts || opts.biff >= 5) {
blob.l += 2;
if(opts.biff != 5) blob.l += 2;
itab = blob.read_shift(2);
if(opts.biff == 5) blob.l += 2;
blob.l += 4;
}
var name = parse_XLUnicodeStringNoCch(blob, cch, opts);
@ -5249,6 +5284,16 @@ function parse_HLink(blob, length) {
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
}
function write_HLink(hl) {
var O = new_buf(24);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
var clsid = "d0 c9 ea 79 f9 ba ce 11 8c 82 00 aa 00 4b a9 0b".split(" ");
for(var i = 0; i < 16; ++i) O.write_shift(1, parseInt(clsid[i], 16));
return bconcat([O, write_Hyperlink(hl[1])]);
}
/* 2.4.141 */
function parse_HLinkTooltip(blob, length) {
@ -5259,6 +5304,17 @@ function parse_HLinkTooltip(blob, length) {
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
}
function write_HLinkTooltip(hl) {
var TT = hl[1].Tooltip;
var O = new_buf(10 + 2 * (TT.length + 1));
O.write_shift(2, 0x0800);
var ref = decode_cell(hl[0]);
O.write_shift(2, ref.r); O.write_shift(2, ref.r);
O.write_shift(2, ref.c); O.write_shift(2, ref.c);
for(var i = 0; i < TT.length; ++i) O.write_shift(2, TT.charCodeAt(i));
O.write_shift(2, 0);
return O;
}
/* 2.4.63 */
function parse_Country(blob, length) {
@ -7026,19 +7082,19 @@ function parse_EncryptionHeader(blob, length) {
o.KeySize = blob.read_shift(4);
o.ProviderType = blob.read_shift(4);
blob.l += 8;
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le').slice(0,-1);
o.CSPName = blob.read_shift((tgt-blob.l)>>1, 'utf16le');
blob.l = tgt;
return o;
}
/* [MS-OFFCRYPTO] 2.3.3 Encryption Verifier */
function parse_EncryptionVerifier(blob, length) {
var o = {};
var o = {}, tgt = blob.l + length;
blob.l += 4; // SaltSize must be 0x10
o.Salt = blob.slice(blob.l, blob.l+16); blob.l += 16;
o.Verifier = blob.slice(blob.l, blob.l+16); blob.l += 16;
var sz = blob.read_shift(4);
o.VerifierHash = blob.slice(blob.l, blob.l + sz); blob.l += sz;
o.VerifierHash = blob.slice(blob.l, tgt); blob.l = tgt;
return o;
}
@ -11387,11 +11443,16 @@ function csf_to_ods_formula(f) {
return o.replace(/;/g, "|").replace(/,/g,";");
}
function ods_to_csf_range_3D(r) {
function ods_to_csf_3D(r) {
var a = r.split(":");
var s = a[0].split(".")[0];
return [s, a[0].split(".")[1] + ":" + a[1].split(".")[1]];
return [s, a[0].split(".")[1] + (a.length > 1 ? (":" + (a[1].split(".")[1] || a[1].split(".")[0])) : "")];
}
function csf_to_ods_3D(r) {
return r.replace(/\./,"!");
}
var strs = {}; // shared strings
var _ssfopts = {}; // spreadsheet formatting options
@ -11615,16 +11676,15 @@ function parse_ws_xml_hlinks(s, data, rels) {
for(var i = 0; i != data.length; ++i) {
var val = parsexmltag(utf8read(data[i]), true);
if(!val.ref) return;
var rel = rels ? rels['!id'][val.id] : null;
var rel = ((rels || {})['!id']||[])[val.id];
if(rel) {
val.Target = rel.Target;
if(val.location) val.Target += "#"+val.location;
val.Rel = rel;
} else {
val.Target = val.location;
rel = {Target: val.location, TargetMode: 'Internal'};
val.Rel = rel;
val.Target = "#" + val.location;
rel = {Target: val.Target, TargetMode: 'Internal'};
}
val.Rel = rel;
if(val.tooltip) { val.Tooltip = val.tooltip; delete val.tooltip; }
var rng = safe_decode_range(val.ref);
for(var R=rng.s.r;R<=rng.e.r;++R) for(var C=rng.s.c;C<=rng.e.c;++C) {
@ -11998,8 +12058,11 @@ function write_ws_xml(idx, opts, wb, rels) {
o[o.length] = "<hyperlinks>";
ws['!links'].forEach(function(l) {
if(!l[1].Target) return;
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel = ({"ref":l[0], "r:id":"rId"+rId});
rel = ({"ref":l[0]});
if(l[1].Target.charAt(0) != "#") {
rId = add_rels(rels, -1, escapexml(l[1].Target).replace(/#.*$/, ""), RELS.HLINK);
rel["r:id"] = "rId"+rId;
}
if((relc = l[1].Target.indexOf("#")) > -1) rel.location = escapexml(l[1].Target.substr(relc+1));
if(l[1].Tooltip) rel.tooltip = escapexml(l[1].Tooltip);
o[o.length] = writextag("hyperlink",null,rel);
@ -12312,8 +12375,8 @@ function parse_BrtHLink(data, length, opts) {
if(tooltip) o.Tooltip = tooltip;
return o;
}
function write_BrtHLink(l, rId, o) {
if(o == null) o = new_buf(50+4*l[1].Target.length);
function write_BrtHLink(l, rId) {
var o = new_buf(50+4*(l[1].Target.length + (l[1].Tooltip || "").length));
write_UncheckedRfX({s:decode_cell(l[0]), e:decode_cell(l[0])}, o);
write_RelID("rId" + rId, o);
var locidx = l[1].Target.indexOf("#");
@ -12539,6 +12602,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles) {
val.Target = rel.Target;
if(val.loc) val.Target += "#"+val.loc;
val.Rel = rel;
} else if(val.relId == '') {
val.Target = "#" + val.loc;
}
for(R=val.rfx.s.r;R<=val.rfx.e.r;++R) for(C=val.rfx.s.c;C<=val.rfx.e.c;++C) {
if(opts.dense) {
@ -13461,8 +13526,9 @@ function parse_BrtName(data, length, opts) {
// unusedstring2: XLNullableWideString
//}
data.l = end;
var out = ({Name:name, Ptg:formula, Comment:comment});
var out = ({Name:name, Ptg:formula});
if(itab < 0xFFFFFFF) out.Sheet = itab;
if(comment) out.Comment = comment;
return out;
}
@ -13970,7 +14036,8 @@ function parse_xlml_xml(d, _opts) {
} else cursheet[encode_col(c) + encode_row(r)] = cell;
}
if(cell.HRef) {
cell.l = {Target:cell.HRef, Tooltip:cell.HRefScreenTip};
cell.l = ({Target:cell.HRef});
if(cell.HRefScreenTip) cell.l.Tooltip = cell.HRefScreenTip;
delete cell.HRef; delete cell.HRefScreenTip;
}
if(cell.MergeAcross || cell.MergeDown) {
@ -17086,6 +17153,15 @@ function write_biff2_buf(wb, opts) {
return ba.end();
}
function write_ws_biff8_hlinks(ba, ws) {
for(var R=0; R<ws['!links'].length; ++R) {
var HL = ws['!links'][R];
write_biff_rec(ba, "HLink", write_HLink(HL));
if(HL[1].Tooltip) write_biff_rec(ba, "HLinkTooltip", write_HLinkTooltip(HL));
}
delete ws['!links'];
}
function write_ws_biff8_cell(ba, cell, R, C, opts) {
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
@ -17110,6 +17186,7 @@ function write_ws_biff8(idx, opts, wb) {
var dense = Array.isArray(ws);
var ref, rr = "", cols = [];
var range = safe_decode_range(ws['!ref'] || "A1");
var b8 = opts.biff == 8, b5 = opts.biff == 5;
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1));
@ -17129,6 +17206,7 @@ function write_ws_biff8(idx, opts, wb) {
write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
/* ... */
if(b8) ws['!links'] = [];
for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) {
@ -17138,9 +17216,13 @@ function write_ws_biff8(idx, opts, wb) {
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);
if(b8 && cell.l) ws['!links'].push([ref, cell.l]);
}
}
var cname = _sheet.CodeName || _sheet.name || s;
/* ... */
if(b8) write_ws_biff8_hlinks(ba, ws);
/* ... */
write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts));
/* ... */
write_biff_rec(ba, "EOF");
@ -17442,9 +17524,12 @@ var parse_content_xml = (function() {
var merges = [], mrange = {}, mR = 0, mC = 0;
var rowinfo = [], rowpeat = 1, colpeat = 1;
var arrayf = [];
var WB = {Names:[]};
var atag = ({});
var _Ref = ["", ""];
var comments = [], comment = {};
var creator = "", creatoridx = 0;
var isstub = false;
var isstub = false, intable = false;
var i = 0;
xlmlregex.lastIndex = 0;
str = str.replace(/<!--([\s\S]*?)-->/mg,"").replace(/<!DOCTYPE[^\[]*\[[^\]]*\]>/gm,"");
@ -17458,6 +17543,7 @@ var parse_content_xml = (function() {
sheetag.name = utf8read(sheetag['名称'] || sheetag.name);
SheetNames.push(sheetag.name);
Sheets[sheetag.name] = ws;
intable = false;
}
else if(Rn[0].charAt(Rn[0].length-2) !== '/') {
sheetag = parsexmltag(Rn[0], false);
@ -17465,6 +17551,7 @@ var parse_content_xml = (function() {
range.s.r = range.s.c = 10000000; range.e.r = range.e.c = 0;
ws = opts.dense ? ([]) : ({}); merges = [];
rowinfo = [];
intable = true;
}
break;
@ -17561,6 +17648,7 @@ var parse_content_xml = (function() {
q.v = textp || '';
isstub = textpidx == 0;
}
if(atag.Target) q.l = atag;
if(comments.length > 0) { q.c = comments; comments = []; }
if(textp && opts.cellText !== false) q.w = textp;
if(!isstub || opts.sheetStubs) {
@ -17584,6 +17672,7 @@ var parse_content_xml = (function() {
q = {};
textp = "";
}
atag = ({});
break; // 9.1.4 <table:table-cell>
/* pure state */
@ -17714,6 +17803,15 @@ var parse_content_xml = (function() {
}
else pidx = Rn.index + Rn[0].length;
break;
case 'named-range': // 9.4.12 <table:named-range>
tag = parsexmltag(Rn[0], false);
_Ref = ods_to_csf_3D(tag['cell-range-address']);
var nrange = ({Name:tag.name, Ref:_Ref[0] + '!' + _Ref[1]});
if(intable) nrange.Sheet = SheetNames.length;
WB.Names.push(nrange);
break;
case 'text-content': break; // 16.27.27 <number:text-content>
case 'text-properties': break; // 16.27.27 <style:text-properties>
case 'embedded-text': break; // 16.27.4 <number:embedded-text>
@ -17734,7 +17832,6 @@ var parse_content_xml = (function() {
case 'graphic-properties': break; // 17.21 <style:graphic-properties>
case 'calculation-settings': break; // 9.4.1 <table:calculation-settings>
case 'named-expressions': break; // 9.4.11 <table:named-expressions>
case 'named-range': break; // 9.4.12 <table:named-range>
case 'label-range': break; // 9.4.9 <table:label-range>
case 'label-ranges': break; // 9.4.10 <table:label-ranges>
case 'named-expression': break; // 9.4.13 <table:named-expression>
@ -17754,8 +17851,8 @@ var parse_content_xml = (function() {
case 'database-range': // 9.4.15 <table:database-range>
if(Rn[1]==='/') break;
try {
var AutoFilter = ods_to_csf_range_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[AutoFilter[0]]['!autofilter'] = { ref: AutoFilter[1] };
_Ref = ods_to_csf_3D(parsexmltag(Rn[0])['target-range-address']);
Sheets[_Ref[0]]['!autofilter'] = { ref:_Ref[1] };
} catch(e) {/* empty */}
break;
@ -17870,7 +17967,17 @@ var parse_content_xml = (function() {
case 'properties': break; // 13.7 <form:properties>
case 'property': break; // 13.8 <form:property>
case 'a': break; // 6.1.8 hyperlink
case 'a': // 6.1.8 hyperlink
if(Rn[1]!== '/') {
atag = parsexmltag(Rn[0], false);
if(!atag.href) break;
atag.Target = atag.href; delete atag.href;
if(atag.Target.charAt(0) == "#" && atag.Target.indexOf(".") > -1) {
_Ref = ods_to_csf_3D(atag.Target.slice(1));
atag.Target = "#" + _Ref[0] + "!" + _Ref[1];
}
}
break;
/* non-standard */
case 'table-protection': break;
@ -17893,10 +18000,11 @@ var parse_content_xml = (function() {
default: if(opts.WTF) throw new Error(Rn);
}
}
var out = {
var out = ({
Sheets: Sheets,
SheetNames: SheetNames
};
SheetNames: SheetNames,
Workbook: WB
});
if(opts.bookSheets) delete out.Sheets;
return out;
};
@ -18008,7 +18116,12 @@ var write_content_ods = (function() {
//case 'e':
default: o.push(null_cell_xml); continue;
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', write_text_p(textp), {}), ct) + '\n');
var text_p = write_text_p(textp);
if(cell.l && cell.l.Target) {
var _tgt = cell.l.Target; _tgt = _tgt.charAt(0) == "#" ? "#" + csf_to_ods_3D(_tgt.slice(1)) : _tgt;
text_p = writextag('text:a', text_p, {'xlink:href': _tgt});
}
o.push(' ' + writextag('table:table-cell', writextag('text:p', text_p, {}), ct) + '\n');
}
o.push(' </table:table-row>\n');
}
@ -18415,6 +18528,7 @@ function parse_xlsxcfb(cfb, _opts) {
data = CFB.find(cfb, f); if(!data || !data.content) throw new Error("ECMA-376 Encrypted file missing " + f);
if(einfo[0] == 0x04 && typeof decrypt_agile !== 'undefined') return decrypt_agile(einfo[1], data.content, opts.password || "", opts);
if(einfo[0] == 0x02 && typeof decrypt_std76 !== 'undefined') return decrypt_std76(einfo[1], data.content, opts.password || "", opts);
throw new Error("File is password-protected");
}
@ -19096,6 +19210,7 @@ utils.cell_set_hyperlink = function(cell, target, tooltip) {
}
return cell;
};
utils.cell_set_internal_link = function(cell, range, tooltip) { return utils.cell_set_hyperlink(cell, "#" + range, tooltip); };
/* add to cell comments */
utils.cell_add_comment = function(cell, text, author) {