diff --git a/.github/workflows/node-4+.yml b/.github/workflows/node-4+.yml index ba17161..13414dd 100644 --- a/.github/workflows/node-4+.yml +++ b/.github/workflows/node-4+.yml @@ -82,6 +82,7 @@ jobs: - run: make init - run: 'cd test_files; make all; cd -' - run: npm run tests-only + - run: 'cd packages/ssf; npm install; npm run tests-only; cd -' node: name: 'node 4+' diff --git a/.github/workflows/node-iojs.yml b/.github/workflows/node-iojs.yml index 27d8d39..8d181f4 100644 --- a/.github/workflows/node-iojs.yml +++ b/.github/workflows/node-iojs.yml @@ -35,6 +35,7 @@ jobs: - run: make init - run: 'cd test_files; make all; cd -' - run: npm run tests-only + #- run: 'cd packages/ssf; npm run tests-only; cd -' node: name: 'io.js' diff --git a/.github/workflows/node-zero.yml b/.github/workflows/node-zero.yml index 4408942..a8072be 100644 --- a/.github/workflows/node-zero.yml +++ b/.github/workflows/node-zero.yml @@ -51,6 +51,7 @@ jobs: - run: make init - run: 'cd test_files; make all; cd -' - run: npm run tests-only + #- run: 'cd packages/ssf; npm run tests-only; cd -' # unstable: # needs: [matrix, stable] diff --git a/README.md b/README.md index 6d77d98..ee96f27 100644 --- a/README.md +++ b/README.md @@ -3082,6 +3082,26 @@ ws.A2.c.hidden = true; ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"}); ``` + +_Threaded Comments_ + +Introduced in Excel 365, threaded comments are plain text comment snippets with +author metadata and parent references. They are supported in XLSX and XLSB. + +To mark a comment as threaded, each comment part must have a true `T` property: + +```js +if(!ws.A1.c) ws.A1.c = []; +ws.A1.c.push({a:"SheetJS", t:"This is not threaded"}); + +if(!ws.A2.c) ws.A2.c = []; +ws.A2.c.hidden = true; +ws.A2.c.push({a:"SheetJS", t:"This is threaded", T: true}); +ws.A2.c.push({a:"JSSheet", t:"This is also threaded", T: true}); +``` + +There is no Active Directory or Office 365 metadata associated with authors in a thread. + #### Sheet Visibility Excel enables hiding sheets in the lower tab bar. The sheet data is stored in diff --git a/bin/xlsx.njs b/bin/xlsx.njs index 9527d0d..cf1471d 100755 --- a/bin/xlsx.njs +++ b/bin/xlsx.njs @@ -154,6 +154,7 @@ if(program.all) { opts.cellStyles = true; opts.sheetStubs = true; opts.cellDates = true; + wopts.cellFormula = true; wopts.cellStyles = true; wopts.sheetStubs = true; wopts.bookVBA = true; diff --git a/bits/22_xmlutils.js b/bits/22_xmlutils.js index 4963467..32db4b0 100644 --- a/bits/22_xmlutils.js +++ b/bits/22_xmlutils.js @@ -253,6 +253,7 @@ var XMLNS = ({ EXT_PROPS: "http://schemas.openxmlformats.org/officeDocument/2006/extended-properties", CT: 'http://schemas.openxmlformats.org/package/2006/content-types', RELS: 'http://schemas.openxmlformats.org/package/2006/relationships', + TCMNT: 'http://schemas.microsoft.com/office/spreadsheetml/2018/threadedcomments', 'dc': 'http://purl.org/dc/elements/1.1/', 'dcterms': 'http://purl.org/dc/terms/', 'dcmitype': 'http://purl.org/dc/dcmitype/', diff --git a/bits/29_xlsenum.js b/bits/29_xlsenum.js index 1b4b9ea..84c784c 100644 --- a/bits/29_xlsenum.js +++ b/bits/29_xlsenum.js @@ -101,9 +101,6 @@ var SummaryPIDSI = { /*::[*/0x72627262/*::]*/: {} }; -var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n"); -var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n"); - /* [MS-XLS] 2.4.63 Country/Region codes */ var CountryEnum = { /*::[*/0x0001/*::]*/: "US", // United States diff --git a/bits/30_ctype.js b/bits/30_ctype.js index bfc352b..9ecaca1 100644 --- a/bits/30_ctype.js +++ b/bits/30_ctype.js @@ -49,6 +49,8 @@ var ct2type/*{[string]:string}*/ = ({ /* Comments */ "application/vnd.openxmlformats-officedocument.spreadsheetml.comments+xml": "comments", "application/vnd.ms-excel.comments": "comments", + "application/vnd.ms-excel.threadedcomments+xml": "threadedcomments", + "application/vnd.ms-excel.person+xml": "people", /* Metadata (Stock/Geography and Dynamic Array) */ "application/vnd.openxmlformats-officedocument.spreadsheetml.sheetMetadata+xml": "metadata", @@ -223,9 +225,9 @@ var CT_LIST = { function new_ct()/*:any*/ { return ({ workbooks:[], sheets:[], charts:[], dialogs:[], macros:[], - rels:[], strs:[], comments:[], links:[], + rels:[], strs:[], comments:[], threadedcomments:[], links:[], coreprops:[], extprops:[], custprops:[], themes:[], styles:[], - calcchains:[], vba: [], drawings: [], metadata: [], + calcchains:[], vba: [], drawings: [], metadata: [], people:[], TODO:[], xmlns: "" }/*:any*/); } @@ -259,32 +261,30 @@ var CTYPE_XML_ROOT = writextag('Types', null, { 'xmlns:xsi': XMLNS.xsi }); -var CTYPE_DEFAULTS = [ - ['xml', 'application/xml'], - ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'], - ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'], - ['data', 'application/vnd.openxmlformats-officedocument.model+data'], - /* from test files */ - ['bmp', 'image/bmp'], - ['png', 'image/png'], - ['gif', 'image/gif'], - ['emf', 'image/x-emf'], - ['wmf', 'image/x-wmf'], - ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'], - ['tif', 'image/tiff'], ['tiff', 'image/tiff'], - ['pdf', 'application/pdf'], - ['rels', 'application/vnd.openxmlformats-package.relationships+xml'] -].map(function(x) { - return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]}); -}); - function write_ct(ct, opts)/*:string*/ { var type2ct/*{[string]:Array}*/ = evert_arr(ct2type); var o/*:Array*/ = [], v; o[o.length] = (XML_HEADER); o[o.length] = (CTYPE_XML_ROOT); - o = o.concat(CTYPE_DEFAULTS); + o = o.concat([ + ['xml', 'application/xml'], + ['bin', 'application/vnd.ms-excel.sheet.binary.macroEnabled.main'], + ['vml', 'application/vnd.openxmlformats-officedocument.vmlDrawing'], + ['data', 'application/vnd.openxmlformats-officedocument.model+data'], + /* from test files */ + ['bmp', 'image/bmp'], + ['png', 'image/png'], + ['gif', 'image/gif'], + ['emf', 'image/x-emf'], + ['wmf', 'image/x-wmf'], + ['jpg', 'image/jpeg'], ['jpeg', 'image/jpeg'], + ['tif', 'image/tiff'], ['tiff', 'image/tiff'], + ['pdf', 'application/pdf'], + ['rels', 'application/vnd.openxmlformats-package.relationships+xml'] + ].map(function(x) { + return writextag('Default', null, {'Extension':x[0], 'ContentType': x[1]}); + })); /* only write first instance */ var f1 = function(w) { @@ -325,8 +325,10 @@ function write_ct(ct, opts)/*:string*/ { ['coreprops', 'extprops', 'custprops'].forEach(f3); f3('vba'); f3('comments'); + f3('threadedcomments'); f3('drawings'); f2('metadata'); + f3('people'); if(o.length>2){ o[o.length] = (''); o[1]=o[1].replace("/>",">"); } return o.join(""); } diff --git a/bits/31_rels.js b/bits/31_rels.js index f9f8151..48f9918 100644 --- a/bits/31_rels.js +++ b/bits/31_rels.js @@ -9,9 +9,31 @@ var RELS = ({ XLINK: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/externalLink", CXML: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXml", CXMLP: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/customXmlProps", + CMNT: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments", + CORE_PROPS: "http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties", + EXT_PROPS: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties', + CUST_PROPS: 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties', + SST: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings", + STY: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles", + THEME: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme", + CHART: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart", + CHARTEX: "http://schemas.microsoft.com/office/2014/relationships/chartEx", + CS: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet", + WS: [ + "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", + "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet" + ], + DS: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet", + MS: "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet", + IMG: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image", + DRAW: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing", + XLMETA: "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata", + TCMNT: "http://schemas.microsoft.com/office/2017/10/relationships/threadedComment", + PEOPLE: "http://schemas.microsoft.com/office/2017/10/relationships/person", VBA: "http://schemas.microsoft.com/office/2006/relationships/vbaProject" }/*:any*/); + /* 9.3.3 Representing Relationships */ function get_rels_path(file/*:string*/)/*:string*/ { var n = file.lastIndexOf("/"); diff --git a/bits/33_coreprops.js b/bits/33_coreprops.js index 0130fbb..ad496fe 100644 --- a/bits/33_coreprops.js +++ b/bits/33_coreprops.js @@ -18,8 +18,6 @@ var CORE_PROPS/*:Array >*/ = [ ["dcterms:modified", "ModifiedDate", 'date'] ]; -RELS.CORE_PROPS = 'http://schemas.openxmlformats.org/package/2006/relationships/metadata/core-properties'; - var CORE_PROPS_REGEX/*:Array*/ = /*#__PURE__*/(function() { var r = new Array(CORE_PROPS.length); for(var i = 0; i < CORE_PROPS.length; ++i) { @@ -43,15 +41,6 @@ function parse_core_props(data) { return p; } -var CORE_PROPS_XML_ROOT = writextag('cp:coreProperties', null, { - //'xmlns': XMLNS.CORE_PROPS, - 'xmlns:cp': XMLNS.CORE_PROPS, - 'xmlns:dc': XMLNS.dc, - 'xmlns:dcterms': XMLNS.dcterms, - 'xmlns:dcmitype': XMLNS.dcmitype, - 'xmlns:xsi': XMLNS.xsi -}); - function cp_doit(f, g, h, o, p) { if(p[f] != null || g == null || g === "") return; p[f] = g; @@ -61,7 +50,14 @@ function cp_doit(f, g, h, o, p) { function write_core_props(cp, _opts) { var opts = _opts || {}; - var o = [XML_HEADER, CORE_PROPS_XML_ROOT], p = {}; + var o = [XML_HEADER, writextag('cp:coreProperties', null, { + //'xmlns': XMLNS.CORE_PROPS, + 'xmlns:cp': XMLNS.CORE_PROPS, + 'xmlns:dc': XMLNS.dc, + 'xmlns:dcterms': XMLNS.dcterms, + 'xmlns:dcmitype': XMLNS.dcmitype, + 'xmlns:xsi': XMLNS.xsi + })], p = {}; if(!cp && !opts.Props) return o.join(""); if(cp) { diff --git a/bits/34_extprops.js b/bits/34_extprops.js index c832c92..830e982 100644 --- a/bits/34_extprops.js +++ b/bits/34_extprops.js @@ -14,8 +14,6 @@ var EXT_PROPS/*:Array >*/ = [ ["TitlesOfParts", "TitlesOfParts", "raw"] ]; -RELS.EXT_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/extended-properties'; - var PseudoPropsPairs = [ "Worksheets", "SheetNames", "NamedRanges", "DefinedNames", @@ -89,17 +87,15 @@ function parse_ext_props(data, p, opts) { return p; } -var EXT_PROPS_XML_ROOT = writextag('Properties', null, { - 'xmlns': XMLNS.EXT_PROPS, - 'xmlns:vt': XMLNS.vt -}); - function write_ext_props(cp/*::, opts*/)/*:string*/ { var o/*:Array*/ = [], W = writextag; if(!cp) cp = {}; cp.Application = "SheetJS"; o[o.length] = (XML_HEADER); - o[o.length] = (EXT_PROPS_XML_ROOT); + o[o.length] = (writextag('Properties', null, { + 'xmlns': XMLNS.EXT_PROPS, + 'xmlns:vt': XMLNS.vt + })); EXT_PROPS.forEach(function(f) { if(cp[f[1]] === undefined) return; diff --git a/bits/35_custprops.js b/bits/35_custprops.js index 31e33ad..1bd5bf6 100644 --- a/bits/35_custprops.js +++ b/bits/35_custprops.js @@ -1,6 +1,4 @@ /* 15.2.12.2 Custom File Properties Part */ -RELS.CUST_PROPS = 'http://schemas.openxmlformats.org/officeDocument/2006/relationships/custom-properties'; - var custregex = /<[^>]+>[^<]*/g; function parse_cust_props(data/*:string*/, opts) { var p = {}, name = ""; @@ -46,13 +44,11 @@ function parse_cust_props(data/*:string*/, opts) { return p; } -var CUST_PROPS_XML_ROOT = writextag('Properties', null, { - 'xmlns': XMLNS.CUST_PROPS, - 'xmlns:vt': XMLNS.vt -}); - function write_cust_props(cp/*::, opts*/)/*:string*/ { - var o = [XML_HEADER, CUST_PROPS_XML_ROOT]; + var o = [XML_HEADER, writextag('Properties', null, { + 'xmlns': XMLNS.CUST_PROPS, + 'xmlns:vt': XMLNS.vt + })]; if(!cp) return o.join(""); var pid = 1; keys(cp).forEach(function custprop(k) { ++pid; diff --git a/bits/36_xlsprops.js b/bits/36_xlsprops.js index 7289aa5..679d4db 100644 --- a/bits/36_xlsprops.js +++ b/bits/36_xlsprops.js @@ -31,9 +31,10 @@ var XLMLDocPropsMap = { Identifier: 'Identifier', /* NOTE: missing from schema */ Language: 'Language' /* NOTE: missing from schema */ }; -var evert_XLMLDPM = evert(XLMLDocPropsMap); +var evert_XLMLDPM; function xlml_set_prop(Props, tag/*:string*/, val) { + if(!evert_XLMLDPM) evert_XLMLDPM = evert(XLMLDocPropsMap); tag = evert_XLMLDPM[tag] || tag; Props[tag] = val; } diff --git a/bits/38_xlstypes.js b/bits/38_xlstypes.js index b0b4106..23631c3 100644 --- a/bits/38_xlstypes.js +++ b/bits/38_xlstypes.js @@ -248,7 +248,7 @@ function parse_PropertySet(blob, PIDSI) { blob.l = start_addr + size; /* step ahead to skip padding */ return PropH; } -var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ].concat(PseudoPropsPairs); +var XLSPSSkip = [ "CodePage", "Thumbnail", "_PID_LINKBASE", "_PID_HLINKS", "SystemIdentifier", "FMTID" ]; //.concat(PseudoPropsPairs); function guess_property_type(val/*:any*/)/*:number*/ { switch(typeof val) { case "boolean": return 0x0B; @@ -292,7 +292,7 @@ function write_PropertySet(entries, RE, PIDSI) { for(i = 0; i < entries.length; ++i) { if(RE && !RE[entries[i][0]]) continue; - if(XLSPSSkip.indexOf(entries[i][0]) > -1) continue; + if(XLSPSSkip.indexOf(entries[i][0]) > -1 || PseudoPropsPairs.indexOf(entries[i][0]) > -1) continue; if(entries[i][1] == null) continue; var val = entries[i][1], idx = 0; diff --git a/bits/42_sstxml.js b/bits/42_sstxml.js index bcaa80b..0d9675f 100644 --- a/bits/42_sstxml.js +++ b/bits/42_sstxml.js @@ -213,7 +213,6 @@ function parse_sst_xml(data/*:string*/, opts)/*:SST*/ { return s; } -RELS.SST = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sharedStrings"; var straywsregex = /^\s|\s$|[\t\n\r]/; function write_sst_xml(sst/*:SST*/, opts)/*:string*/ { if(!opts.bookSST) return ""; diff --git a/bits/47_styxml.js b/bits/47_styxml.js index f6c73d0..729bc50 100644 --- a/bits/47_styxml.js +++ b/bits/47_styxml.js @@ -410,8 +410,6 @@ return function parse_sty_xml(data, themes, opts) { }; })(); -RELS.STY = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/styles"; - function write_sty_xml(wb/*:Workbook*/, opts)/*:string*/ { var o = [XML_HEADER, writextag('styleSheet', null, { 'xmlns': XMLNS_main[0], diff --git a/bits/48_stybin.js b/bits/48_stybin.js index 368ba93..fc7f2e5 100644 --- a/bits/48_stybin.js +++ b/bits/48_stybin.js @@ -102,11 +102,12 @@ var XLSBFillPTNames = [ "gray125", "gray0625" ]; -var rev_XLSBFillPTNames/*:EvertNumType*/ = (evert(XLSBFillPTNames)/*:any*/); +var rev_XLSBFillPTNames/*:EvertNumType*/ /* TODO: gradient fill representation */ var parse_BrtFill = parsenoop; function write_BrtFill(fill, o) { if(!o) o = new_buf(4*3 + 8*7 + 16*1); + if(!rev_XLSBFillPTNames) rev_XLSBFillPTNames = (evert(XLSBFillPTNames)/*:any*/); var fls/*:number*/ = rev_XLSBFillPTNames[fill.patternType]; if(fls == null) fls = 0x28; o.write_shift(4, fls); diff --git a/bits/49_theme.js b/bits/49_theme.js index 7318fe6..75a486b 100644 --- a/bits/49_theme.js +++ b/bits/49_theme.js @@ -1,5 +1,3 @@ -RELS.THEME = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/theme"; - /* Even though theme layout is dk1 lt1 dk2 lt2, true order is lt1 dk1 lt2 dk2 */ var XLSXThemeClrScheme = [ '', '', '', '', diff --git a/bits/51_xlmeta.js b/bits/51_xlmeta.js deleted file mode 100644 index 36faf35..0000000 --- a/bits/51_xlmeta.js +++ /dev/null @@ -1,150 +0,0 @@ -RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; -function parse_xlmeta_xml(data, name, opts) { - var out = { Types: [] }; - if (!data) - return out; - var pass = false; - data.replace(tagregex, function(x, idx) { - var y = parsexmltag(x); - switch (strip_ns(y[0])) { - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - case "": - case "": - break; - case "": - pass = false; - break; - default: - if (!pass && opts.WTF) - throw new Error("unrecognized " + y[0] + " in metadata"); - } - return x; - }); - return out; -} -function write_xlmeta_xml() { - var o = [XML_HEADER]; - o.push('\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n'); - return o.join(""); -} -function parse_BrtMdtinfo(data, length) { - return { - flags: data.read_shift(4), - version: data.read_shift(4), - name: parse_XLWideString(data, length - 8) - }; -} -function write_BrtMdtinfo(data) { - var o = new_buf(12 + 2 * data.name.length); - o.write_shift(4, data.flags); - o.write_shift(4, data.version); - write_XLWideString(data.name, o); - return o.slice(0, o.l); -} -function write_BrtMdb(mdb) { - var o = new_buf(4 + 8 * mdb.length); - o.write_shift(4, mdb.length); - for (var i = 0; i < mdb.length; ++i) { - o.write_shift(4, mdb[i][0]); - o.write_shift(4, mdb[i][1]); - } - return o; -} -function write_BrtBeginEsfmd(cnt, name) { - var o = new_buf(8 + 2 * name.length); - o.write_shift(4, cnt); - write_XLWideString(name, o); - return o.slice(0, o.l); -} -function write_BrtBeginEsmdb(cnt, cm) { - var o = new_buf(8); - o.write_shift(4, cnt); - o.write_shift(4, cm ? 1 : 0); - return o; -} -function parse_xlmeta_bin(data, name, _opts) { - var out = { Types: [] }; - var opts = _opts || {}; - var state = []; - var pass = false; - recordhopper(data, function(val, R, RT) { - switch (RT) { - case 335: - out.Types.push({ name: val.name }); - break; - case 51: - break; - case 35: - state.push(RT); - pass = true; - break; - case 36: - state.pop(); - pass = false; - break; - default: - if (R.T) { - } else if (!pass || opts.WTF && state[state.length - 1] != 35) - throw new Error("Unexpected record 0x" + RT.toString(16)); - } - }); - return out; -} -function write_xlmeta_bin() { - var ba = buf_array(); - write_record(ba, 332); - write_record(ba, 334, write_UInt32LE(1)); - write_record(ba, 335, write_BrtMdtinfo({ - name: "XLDAPR", - version: 12e4, - flags: 3496657072 - })); - write_record(ba, 336); - write_record(ba, 339, write_BrtBeginEsfmd(1, "XLDAPR")); - write_record(ba, 52); - write_record(ba, 35, write_UInt32LE(514)); - write_record(ba, 4096, write_UInt32LE(0)); - write_record(ba, 4097, writeuint16(1)); - write_record(ba, 36); - write_record(ba, 53); - write_record(ba, 340); - write_record(ba, 337, write_BrtBeginEsmdb(1, true)); - write_record(ba, 51, write_BrtMdb([[1, 0]])); - write_record(ba, 338); - write_record(ba, 333); - return ba.end(); -} diff --git a/bits/51_xlsbmeta.js b/bits/51_xlsbmeta.js new file mode 100644 index 0000000..903dd5a --- /dev/null +++ b/bits/51_xlsbmeta.js @@ -0,0 +1,105 @@ +function parse_BrtMdtinfo(data, length) { + return { + flags: data.read_shift(4), + version: data.read_shift(4), + name: parse_XLWideString(data, length - 8) + }; +} +function write_BrtMdtinfo(data) { + var o = new_buf(12 + 2 * data.name.length); + o.write_shift(4, data.flags); + o.write_shift(4, data.version); + write_XLWideString(data.name, o); + return o.slice(0, o.l); +} +function parse_BrtMdb(data, length) { + var out = []; + var cnt = data.read_shift(4); + while (cnt-- > 0) + out.push([data.read_shift(4), data.read_shift(4)]); + return out; +} +function write_BrtMdb(mdb) { + var o = new_buf(4 + 8 * mdb.length); + o.write_shift(4, mdb.length); + for (var i = 0; i < mdb.length; ++i) { + o.write_shift(4, mdb[i][0]); + o.write_shift(4, mdb[i][1]); + } + return o; +} +function write_BrtBeginEsfmd(cnt, name) { + var o = new_buf(8 + 2 * name.length); + o.write_shift(4, cnt); + write_XLWideString(name, o); + return o.slice(0, o.l); +} +function parse_BrtBeginEsmdb(data, length) { + data.l += 4; + return data.read_shift(4) != 0; +} +function write_BrtBeginEsmdb(cnt, cm) { + var o = new_buf(8); + o.write_shift(4, cnt); + o.write_shift(4, cm ? 1 : 0); + return o; +} +function parse_xlmeta_bin(data, name, _opts) { + var out = { Types: [], Cell: [], Value: [] }; + var opts = _opts || {}; + var state = []; + var pass = false; + var esmdb = 0; + recordhopper(data, function(val, R, RT) { + switch (RT) { + case 335: + out.Types.push({ name: val.name }); + break; + case 51: + val.forEach(function(r) { + (esmdb == 1 ? out.Cell : out.Value).push({ type: out.Types[r[0] - 1].name, index: r[1] }); + }); + break; + case 337: + esmdb = val ? 1 : 0; + break; + case 35: + state.push(RT); + pass = true; + break; + case 36: + state.pop(); + pass = false; + break; + default: + if (R.T) { + } else if (!pass || opts.WTF && state[state.length - 1] != 35) + throw new Error("Unexpected record 0x" + RT.toString(16)); + } + }); + return out; +} +function write_xlmeta_bin() { + var ba = buf_array(); + write_record(ba, 332); + write_record(ba, 334, write_UInt32LE(1)); + write_record(ba, 335, write_BrtMdtinfo({ + name: "XLDAPR", + version: 12e4, + flags: 3496657072 + })); + write_record(ba, 336); + write_record(ba, 339, write_BrtBeginEsfmd(1, "XLDAPR")); + write_record(ba, 52); + write_record(ba, 35, write_UInt32LE(514)); + write_record(ba, 4096, write_UInt32LE(0)); + write_record(ba, 4097, writeuint16(1)); + write_record(ba, 36); + write_record(ba, 53); + write_record(ba, 340); + write_record(ba, 337, write_BrtBeginEsmdb(1, true)); + write_record(ba, 51, write_BrtMdb([[1, 0]])); + write_record(ba, 338); + write_record(ba, 333); + return ba.end(); +} diff --git a/bits/51_xlsxmeta.js b/bits/51_xlsxmeta.js new file mode 100644 index 0000000..30ad251 --- /dev/null +++ b/bits/51_xlsxmeta.js @@ -0,0 +1,74 @@ +function parse_xlmeta_xml(data, name, opts) { + var out = { Types: [], Cell: [], Value: [] }; + if (!data) + return out; + var pass = false; + var metatype = ""; + data.replace(tagregex, function(x, idx) { + var y = parsexmltag(x); + switch (strip_ns(y[0])) { + case "": + break; + case "": + break; + case "": + break; + case "": + break; + case "": + break; + case "": + break; + case "": + break; + case "": + metatype = ""; + break; + case "": + metatype = ""; + break; + case "": + case "": + case "": + break; + case "": + pass = false; + break; + default: + if (!pass && opts.WTF) + throw new Error("unrecognized " + y[0] + " in metadata"); + } + return x; + }); + return out; +} +function write_xlmeta_xml() { + var o = [XML_HEADER]; + o.push('\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n'); + return o.join(""); +} diff --git a/bits/54_drawing.js b/bits/54_drawing.js index 6ac7447..328f669 100644 --- a/bits/54_drawing.js +++ b/bits/54_drawing.js @@ -1,7 +1,4 @@ /* 20.5 DrawingML - SpreadsheetML Drawing */ -RELS.IMG = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/image"; -RELS.DRAW = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/drawing"; - /* 20.5.2.35 wsDr CT_Drawing */ function parse_drawing(data, rels/*:any*/) { if(!data) return "??"; diff --git a/bits/56_cmntcommon.js b/bits/56_cmntcommon.js index 0c369ca..b87de5e 100644 --- a/bits/56_cmntcommon.js +++ b/bits/56_cmntcommon.js @@ -1,6 +1,4 @@ -RELS.CMNT = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/comments"; - -function sheet_insert_comments(sheet, comments/*:Array*/) { +function sheet_insert_comments(sheet, comments/*:Array*/, threaded/*:boolean*/, people/*:?Array*/) { var dense = Array.isArray(sheet); var cell/*:Cell*/; comments.forEach(function(comment) { @@ -23,8 +21,17 @@ function sheet_insert_comments(sheet, comments/*:Array*/) { } if (!cell.c) cell.c = []; - var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r}); + var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r, T: threaded}); if(comment.h) o.h = comment.h; + + /* threaded comments always override */ + for(var i = cell.c.length - 1; i >= 0; --i) { + if(!threaded && cell.c[i].T) return; + if(threaded && !cell.c[i].T) cell.c.splice(i, 1); + } + if(threaded && people) for(var i = 0; i < people.length; ++i) { + if(o.a == people[i].id) { o.a = people[i].name || o.a; break; } + } cell.c.push(o); }); } diff --git a/bits/57_cmntxml.js b/bits/57_cmntxml.js index cc95880..7e11c39 100644 --- a/bits/57_cmntxml.js +++ b/bits/57_cmntxml.js @@ -36,21 +36,144 @@ function write_comments_xml(data/*::, opts*/) { var iauthor/*:Array*/ = []; o.push(""); data.forEach(function(x) { x[1].forEach(function(w) { var a = escapexml(w.a); - if(iauthor.indexOf(a) > -1) return; - iauthor.push(a); - o.push("" + a + ""); + if(iauthor.indexOf(a) == -1) { + iauthor.push(a); + o.push("" + a + ""); + } + if(w.T && w.ID && iauthor.indexOf("tc=" + w.ID) == -1) { + iauthor.push("tc=" + w.ID); + o.push("" + "tc=" + w.ID + ""); + } }); }); + if(iauthor.length == 0) { iauthor.push("SheetJ5"); o.push("SheetJ5"); } o.push(""); o.push(""); data.forEach(function(d) { - d[1].forEach(function(c) { - /* 18.7.3 CT_Comment */ - o.push(''); - o.push(writetag("t", c.t == null ? "" : escapexml(c.t))); - o.push(''); + /* 18.7.3 CT_Comment */ + var lastauthor = 0, ts = []; + if(d[1][0] && d[1][0].T && d[1][0].ID) lastauthor = iauthor.indexOf("tc=" + d[1][0].ID); + else d[1].forEach(function(c) { + if(c.a) lastauthor = iauthor.indexOf(escapexml(c.a)); + ts.push(c.t||""); }); + o.push(''); + if(ts.length <= 1) o.push(writetag("t", escapexml(ts[0]||""))); + else { + /* based on Threaded Comments -> Comments projection */ + var t = "Comment:\n " + (ts[0]) + "\n"; + for(var i = 1; i < ts.length; ++i) t += "Reply:\n " + ts[i] + "\n"; + o.push(writetag("t", escapexml(t))); + } + o.push(''); }); o.push(""); if(o.length>2) { o[o.length] = (''); o[1]=o[1].replace("/>",">"); } return o.join(""); } + +/* [MS-XLSX] 2.1.17 */ +function parse_tcmnt_xml(data/*:string*/, opts)/*:Array*/ { + var out = []; + var pass = false, comment = {}, tidx = 0; + data.replace(tagregex, function xml_tcmnt(x, idx) { + var y/*:any*/ = parsexmltag(x); + switch(strip_ns(y[0])) { + case '': break; + + /* 2.6.205 threadedComment CT_ThreadedComment */ + case '': if(comment.t != null) out.push(comment); break; + + case '': case '': comment.t = data.slice(tidx, idx).replace(/\r\n/g, "\n").replace(/\r/g, "\n"); break; + + /* 2.6.206 mentions CT_ThreadedCommentMentions TODO */ + case '': pass = true; break; + case '': pass = false; break; + + /* 2.6.202 mention CT_Mention TODO */ + + /* 18.2.10 extLst CT_ExtensionList ? */ + case '': case '': case '': break; + /* 18.2.7 ext CT_Extension + */ + case '': pass=false; break; + + default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in threaded comments'); + } + return x; + }); + return out; +} + +function write_tcmnt_xml(comments, people, opts) { + var o = [XML_HEADER, writextag('ThreadedComments', null, { 'xmlns': XMLNS.TCMNT }).replace(/[\/]>/, ">")]; + comments.forEach(function(carr) { + var rootid = ""; + (carr[1] || []).forEach(function(c, idx) { + if(!c.T) { delete c.ID; return; } + if(c.a && people.indexOf(c.a) == -1) people.push(c.a); + var tcopts = { + ref: carr[0], + id: "{54EE7951-7262-4200-6969-" + ("000000000000" + opts.tcid++).slice(-12) + "}" + }; + if(idx == 0) rootid = tcopts.id; + else tcopts.parentId = rootid; + c.ID = tcopts.id; + if(c.a) tcopts.personId = "{54EE7950-7262-4200-6969-" + ("000000000000" + people.indexOf(c.a)).slice(-12) + "}"; + o.push(writextag('threadedComment', writetag('text', c.t||""), tcopts)); + }); + }); + o.push(''); + return o.join(""); +} + +/* [MS-XLSX] 2.1.18 */ +function parse_people_xml(data/*:string*/, opts) { + var out = []; + var pass = false, tidx = 0; + data.replace(tagregex, function xml_tcmnt(x, idx) { + var y/*:any*/ = parsexmltag(x); + switch(strip_ns(y[0])) { + case '': break; + + /* 2.6.203 person CT_Person TODO: providers */ + case '': break; + + /* 18.2.10 extLst CT_ExtensionList ? */ + case '': case '': case '': break; + /* 18.2.7 ext CT_Extension + */ + case '': pass=false; break; + + default: if(!pass && opts.WTF) throw new Error('unrecognized ' + y[0] + ' in threaded comments'); + } + return x; + }); + return out; +} +function write_people_xml(people, opts) { + var o = [XML_HEADER, writextag('personList', null, { + 'xmlns': XMLNS.TCMNT, + 'xmlns:x': XMLNS_main[0] + }).replace(/[\/]>/, ">")]; + people.forEach(function(person, idx) { + o.push(writextag('person', null, { + displayName: person, + id: "{54EE7950-7262-4200-6969-" + ("000000000000" + idx).slice(-12) + "}", + userId: person, + providerId: "None" + })); + }); + o.push(""); + return o.join(""); +} diff --git a/bits/60_macrovba.js b/bits/60_macrovba.js index 3492941..2d44370 100644 --- a/bits/60_macrovba.js +++ b/bits/60_macrovba.js @@ -1,6 +1,3 @@ -RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet"; -RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet"; - /* macro and dialog sheet stubs */ function parse_ds_bin(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'dialog'}; } function parse_ds_xml(/*::data:any, opts, idx:number, rels, wb, themes, styles*/)/*:Worksheet*/ { return {'!type':'dialog'}; } diff --git a/bits/62_fxls.js b/bits/62_fxls.js index a535d8f..9d7ca91 100644 --- a/bits/62_fxls.js +++ b/bits/62_fxls.js @@ -596,12 +596,12 @@ var Ptg19 = { /*::[*/0x08/*::]*/: { n:'PtgAttrGoto', f:parse_PtgAttrGoto }, /*::[*/0x10/*::]*/: { n:'PtgAttrSum', f:parse_PtgAttrSum }, /*::[*/0x20/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel }, + /*::[*/0x21/*::]*/: { n:'PtgAttrBaxcel', f:parse_PtgAttrBaxcel }, /*::[*/0x40/*::]*/: { n:'PtgAttrSpace', f:parse_PtgAttrSpace }, /*::[*/0x41/*::]*/: { n:'PtgAttrSpaceSemi', f:parse_PtgAttrSpaceSemi }, /*::[*/0x80/*::]*/: { n:'PtgAttrIfError', f:parse_PtgAttrIfError }, /*::[*/0xFF/*::]*/: {} }; -Ptg19[0x21] = Ptg19[0x20]; /* [MS-XLS] 2.5.198.103 ; [MS-XLSB] 2.5.97.87 */ function parse_RgbExtra(blob, length, rgce, opts) { diff --git a/bits/66_wscommon.js b/bits/66_wscommon.js index ce038f8..03d8122 100644 --- a/bits/66_wscommon.js +++ b/bits/66_wscommon.js @@ -1,10 +1,6 @@ var strs = {}; // shared strings var _ssfopts = {}; // spreadsheet formatting options -RELS.WS = [ - "http://schemas.openxmlformats.org/officeDocument/2006/relationships/worksheet", - "http://purl.oclc.org/ooxml/officeDocument/relationships/worksheet" -]; /*global Map */ var browser_has_Map = typeof Map !== 'undefined'; diff --git a/bits/67_wsxml.js b/bits/67_wsxml.js index e1d61be..6783f52 100644 --- a/bits/67_wsxml.js +++ b/bits/67_wsxml.js @@ -257,7 +257,8 @@ function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ { } function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string*/ { - if(cell.v === undefined && typeof cell.f !== "string" || cell.t === 'z') return ""; + if(cell.c) ws['!comments'].push([ref, cell.c]); + if(cell.v === undefined && typeof cell.f !== "string" || cell.t === 'z' && !cell.f) return ""; var vv = ""; var oldt = cell.t, oldv = cell.v; if(cell.t !== "z") switch(cell.t) { @@ -299,7 +300,6 @@ function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts/*::, idx, wb*/)/*:string v = writextag('f', escapexml(cell.f), ff) + (cell.v != null ? v : ""); } if(cell.l) ws['!links'].push([ref, cell.l]); - if(cell.c) ws['!comments'].push([ref, cell.c]); if(cell.D) o.cm = 1; return writextag('c', v, o); } @@ -478,8 +478,8 @@ return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, th safe_format(p, fmtid, fillid, opts, themes, styles); if(opts.cellDates && do_format && p.t == 'n' && SSF.is_date(SSF._table[fmtid])) { p.t = 'd'; p.v = numdate(p.v); } if(tag.cm && opts.xlmeta) { - var cm = (opts.xlmeta.Types||[])[+tag.cm-1]; - if(cm && cm.name == 'XLDAPR') p.D = true; + var cm = (opts.xlmeta.Cell||[])[+tag.cm-1]; + if(cm && cm.type == 'XLDAPR') p.D = true; } if(dense) { var _r = decode_cell(tag.r); diff --git a/bits/68_wsbin.js b/bits/68_wsbin.js index cf6e9f5..fc3c778 100644 --- a/bits/68_wsbin.js +++ b/bits/68_wsbin.js @@ -540,7 +540,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ var cm, vm; - recordhopper(data, function ws_parse(val, R, RT) { + recordhopper(data, function ws_parse(val, RR, RT) { if(end) return; switch(RT) { case 0x0094: /* 'BrtWsDim' */ @@ -606,7 +606,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ var _d = SSF.parse_date_code(p.v); if(_d) { p.t = 'd'; p.v = new Date(_d.y, _d.m-1,_d.d,_d.H,_d.M,_d.S,_d.u); } } if(cm) { - if(cm.name == 'XLDAPR') p.D = true; + if(cm.type == 'XLDAPR') p.D = true; cm = void 0; } if(vm) vm = void 0; @@ -624,7 +624,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ if(refguess.e.r < row.r) refguess.e.r = row.r; if(refguess.e.c < C) refguess.e.c = C; if(cm) { - if(cm.name == 'XLDAPR') p.D = true; + if(cm.type == 'XLDAPR') p.D = true; cm = void 0; } if(vm) vm = void 0; @@ -634,7 +634,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ merges.push(val); break; case 0x0031: { /* 'BrtCellMeta' */ - cm = ((opts.xlmeta||{}).Types||[])[val-1]; + cm = ((opts.xlmeta||{}).Cell||[])[val-1]; } break; case 0x01EE: /* 'BrtHLink' */ @@ -774,7 +774,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/ state.pop(); pass = false; break; default: - if(R.T){/* empty */} + if(RR.T){/* empty */} else if(!pass || opts.WTF) throw new Error("Unexpected record 0x" + RT.toString(16)); } }, opts); diff --git a/bits/69_chartxml.js b/bits/69_chartxml.js index aae70c2..e4a9ec7 100644 --- a/bits/69_chartxml.js +++ b/bits/69_chartxml.js @@ -1,6 +1,3 @@ -RELS.CHART = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chart"; -RELS.CHARTEX = "http://schemas.microsoft.com/office/2014/relationships/chartEx"; - function parse_Cache(data/*:string*/)/*:[Array, string, ?string]*/ { var col/*:Array*/ = []; var num = data.match(/^/); diff --git a/bits/70_csheet.js b/bits/70_csheet.js index d7db525..e8b8e5f 100644 --- a/bits/70_csheet.js +++ b/bits/70_csheet.js @@ -1,5 +1,3 @@ -RELS.CS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/chartsheet"; - /* 18.3 Worksheets also covers Chartsheets */ function parse_cs_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*::, themes, styles*/)/*:Worksheet*/ { if(!data) return data; diff --git a/bits/76_xls.js b/bits/76_xls.js index 51ef7d9..afb1aca 100644 --- a/bits/76_xls.js +++ b/bits/76_xls.js @@ -891,6 +891,8 @@ function parse_xls_props(cfb/*:CFBContainer*/, props, o) { function write_xls_props(wb/*:Workbook*/, cfb/*:CFBContainer*/) { var DSEntries = [], SEntries = [], CEntries = []; var i = 0, Keys; + var DocSummaryRE/*:{[key:string]:string}*/ = evert_key(DocSummaryPIDDSI, "n"); + var SummaryRE/*:{[key:string]:string}*/ = evert_key(SummaryPIDSI, "n"); if(wb.Props) { Keys = keys(wb.Props); // $FlowIgnore @@ -903,7 +905,7 @@ function write_xls_props(wb/*:Workbook*/, cfb/*:CFBContainer*/) { } var CEntries2 = []; for(i = 0; i < CEntries.length; ++i) { - if(XLSPSSkip.indexOf(CEntries[i][0]) > -1) continue; + if(XLSPSSkip.indexOf(CEntries[i][0]) > -1 || PseudoPropsPairs.indexOf(CEntries[i][0]) > -1) continue; if(CEntries[i][1] == null) continue; CEntries2.push(CEntries[i]); } diff --git a/bits/77_parsetab.js b/bits/77_parsetab.js index 1a72325..578204d 100644 --- a/bits/77_parsetab.js +++ b/bits/77_parsetab.js @@ -50,7 +50,7 @@ var XLSBRecordEnum = { /*::[*/0x0030/*::]*/: { /* n:"BrtStyle" */ }, /*::[*/0x0031/*::]*/: { /* n:"BrtCellMeta", */ f:parse_Int32LE }, /*::[*/0x0032/*::]*/: { /* n:"BrtValueMeta" */ }, - /*::[*/0x0033/*::]*/: { /* n:"BrtMdb" */ }, + /*::[*/0x0033/*::]*/: { /* n:"BrtMdb" */ f:parse_BrtMdb }, /*::[*/0x0034/*::]*/: { /* n:"BrtBeginFmd", */ T:1 }, /*::[*/0x0035/*::]*/: { /* n:"BrtEndFmd", */ T:-1 }, /*::[*/0x0036/*::]*/: { /* n:"BrtBeginMdx", */ T:1 }, @@ -276,7 +276,7 @@ var XLSBRecordEnum = { /*::[*/0x014E/*::]*/: { /* n:"BrtBeginEsmdtinfo", */ T:1 }, /*::[*/0x014F/*::]*/: { /* n:"BrtMdtinfo", */ f:parse_BrtMdtinfo }, /*::[*/0x0150/*::]*/: { /* n:"BrtEndEsmdtinfo", */ T:-1 }, - /*::[*/0x0151/*::]*/: { /* n:"BrtBeginEsmdb", */ T:1 }, + /*::[*/0x0151/*::]*/: { /* n:"BrtBeginEsmdb", */ f:parse_BrtBeginEsmdb, T:1 }, /*::[*/0x0152/*::]*/: { /* n:"BrtEndEsmdb", */ T:-1 }, /*::[*/0x0153/*::]*/: { /* n:"BrtBeginEsfmd", */ T:1 }, /*::[*/0x0154/*::]*/: { /* n:"BrtEndEsfmd", */ T:-1 }, diff --git a/bits/83_numbers.js b/bits/83_numbers.js index 48a6637..3fbdc88 100644 --- a/bits/83_numbers.js +++ b/bits/83_numbers.js @@ -1,668 +1,632 @@ -var NUMBERS = !Object.defineProperty ? (void 0) :(function() { - var __defProp = Object.defineProperty; - var __getOwnPropDesc = Object.getOwnPropertyDescriptor; - var __getOwnPropNames = Object.getOwnPropertyNames; - var __hasOwnProp = Object.prototype.hasOwnProperty; - var __markAsModule = function(target) { - return __defProp(target, "__esModule", { value: true }); - }; - var __export = function(target, all) { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - var __reExport = function(target, module, copyDefault, desc) { - if (module && typeof module === "object" || typeof module === "function") - for (var keys = __getOwnPropNames(module), i = 0, n = keys.length, key; i < n; i++) { - key = keys[i]; - if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default")) - __defProp(target, key, { get: function(k) { - return module[k]; - }.bind(null, key), enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable }); - } - return target; - }; - var __toCommonJS = /* @__PURE__ */ function(cache) { - return function(module, temp) { - return cache && cache.get(module) || (temp = __reExport(__markAsModule({}), module, 1), cache && cache.set(module, temp), temp); - }; - }(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0); - - // 83_numbers.ts - var numbers_exports = {}; - __export(numbers_exports, { - parse_numbers: function() { - return numbers_default; - } +/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var u8_to_dataview = function(array) { + return new DataView(array.buffer, array.byteOffset, array.byteLength); +}; +var u8str = function(u8) { + return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8)); +}; +var u8concat = function(u8a) { + var len = u8a.reduce(function(acc, x) { + return acc + x.length; + }, 0); + var out = new Uint8Array(len); + var off = 0; + u8a.forEach(function(u8) { + out.set(u8, off); + off += u8.length; }); - - // src/util.ts - var u8_to_dataview = function(array) { - return new DataView(array.buffer, array.byteOffset, array.byteLength); - }; - var u8str = function(u8) { - return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8)); - }; - var u8concat = function(u8a) { - var len = u8a.reduce(function(acc, x) { - return acc + x.length; - }, 0); - var out = new Uint8Array(len); - var off = 0; - u8a.forEach(function(u8) { - out.set(u8, off); - off += u8.length; - }); - return out; - }; - var popcnt = function(x) { - x -= x >> 1 & 1431655765; - x = (x & 858993459) + (x >> 2 & 858993459); - return (x + (x >> 4) & 252645135) * 16843009 >>> 24; - }; - var readDecimal128LE = function(buf, offset) { - var exp = (buf[offset + 15] & 127) << 7 | buf[offset + 14] >> 1; - var mantissa = buf[offset + 14] & 1; - for (var j = offset + 13; j >= offset; --j) - mantissa = mantissa * 256 + buf[j]; - return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176); - }; - - // src/proto.ts - function parse_varint49(buf, ptr) { - var l = ptr ? ptr[0] : 0; - var usz = buf[l] & 127; - varint: - if (buf[l++] >= 128) { - usz |= (buf[l] & 127) << 7; - if (buf[l++] < 128) - break varint; - usz |= (buf[l] & 127) << 14; - if (buf[l++] < 128) - break varint; - usz |= (buf[l] & 127) << 21; - if (buf[l++] < 128) - break varint; - usz += (buf[l] & 127) * Math.pow(2, 28); - ++l; - if (buf[l++] < 128) - break varint; - usz += (buf[l] & 127) * Math.pow(2, 35); - ++l; - if (buf[l++] < 128) - break varint; - usz += (buf[l] & 127) * Math.pow(2, 42); - ++l; - if (buf[l++] < 128) - break varint; - } - if (ptr) - ptr[0] = l; - return usz; - } - function varint_to_i32(buf) { - var l = 0, i32 = buf[l] & 127; - varint: - if (buf[l++] >= 128) { - i32 |= (buf[l] & 127) << 7; - if (buf[l++] < 128) - break varint; - i32 |= (buf[l] & 127) << 14; - if (buf[l++] < 128) - break varint; - i32 |= (buf[l] & 127) << 21; - if (buf[l++] < 128) - break varint; - i32 |= (buf[l] & 127) << 28; - } - return i32; - } - function parse_shallow(buf) { - var out = [], ptr = [0]; - while (ptr[0] < buf.length) { - var off = ptr[0]; - var num = parse_varint49(buf, ptr); - var type = num & 7; - num = Math.floor(num / 8); - var len = 0; - var res; - if (num == 0) - break; - switch (type) { - case 0: - { - var l = ptr[0]; - while (buf[ptr[0]++] >= 128) - ; - res = buf.slice(l, ptr[0]); - } - break; - case 5: - len = 4; - res = buf.slice(ptr[0], ptr[0] + len); - ptr[0] += len; - break; - case 1: - len = 8; - res = buf.slice(ptr[0], ptr[0] + len); - ptr[0] += len; - break; - case 2: - len = parse_varint49(buf, ptr); - res = buf.slice(ptr[0], ptr[0] + len); - ptr[0] += len; - break; - case 3: - case 4: - default: - throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off)); - } - var v = { offset: off, data: res, type: type }; - if (out[num] == null) - out[num] = [v]; - else - out[num].push(v); + return out; +}; +var popcnt = function(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + return (x + (x >> 4) & 252645135) * 16843009 >>> 24; +}; +var readDecimal128LE = function(buf, offset) { + var exp = (buf[offset + 15] & 127) << 7 | buf[offset + 14] >> 1; + var mantissa = buf[offset + 14] & 1; + for (var j = offset + 13; j >= offset; --j) + mantissa = mantissa * 256 + buf[j]; + return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176); +}; +function parse_varint49(buf, ptr) { + var l = ptr ? ptr[0] : 0; + var usz = buf[l] & 127; + varint: + if (buf[l++] >= 128) { + usz |= (buf[l] & 127) << 7; + if (buf[l++] < 128) + break varint; + usz |= (buf[l] & 127) << 14; + if (buf[l++] < 128) + break varint; + usz |= (buf[l] & 127) << 21; + if (buf[l++] < 128) + break varint; + usz += (buf[l] & 127) * Math.pow(2, 28); + ++l; + if (buf[l++] < 128) + break varint; + usz += (buf[l] & 127) * Math.pow(2, 35); + ++l; + if (buf[l++] < 128) + break varint; + usz += (buf[l] & 127) * Math.pow(2, 42); + ++l; + if (buf[l++] < 128) + break varint; } - return out; - } - function mappa(data, cb) { - if (!data) - return []; - return data.map(function(d) { - var _a; - try { - return cb(d.data); - } catch (e) { - var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/); - if (m) - e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset)); - throw e; - } - }); - } - - // src/frame.ts - function deframe(buf) { - var out = []; - var l = 0; - while (l < buf.length) { - var t = buf[l++]; - var len = buf[l] | buf[l + 1] << 8 | buf[l + 2] << 16; - l += 3; - out.push(parse_snappy_chunk(t, buf.slice(l, l + len))); - l += len; + if (ptr) + ptr[0] = l; + return usz; +} +function write_varint49(v) { + var usz = new Uint8Array(7); + usz[0] = v & 127; + var L = 1; + sz: + if (v > 127) { + usz[L - 1] |= 128; + usz[L] = v >> 7 & 127; + ++L; + if (v <= 16383) + break sz; + usz[L - 1] |= 128; + usz[L] = v >> 14 & 127; + ++L; + if (v <= 2097151) + break sz; + usz[L - 1] |= 128; + usz[L] = v >> 21 & 127; + ++L; + if (v <= 268435455) + break sz; + usz[L - 1] |= 128; + usz[L] = v / 256 >>> 21 & 127; + ++L; + if (v <= 34359738367) + break sz; + usz[L - 1] |= 128; + usz[L] = v / 65536 >>> 21 & 127; + ++L; + if (v <= 4398046511103) + break sz; + usz[L - 1] |= 128; + usz[L] = v / 16777216 >>> 21 & 127; + ++L; } - if (l !== buf.length) - throw new Error("data is not a valid framed stream!"); - return u8concat(out); - } - function parse_snappy_chunk(type, buf) { - if (type != 0) - throw new Error("Unexpected Snappy chunk type ".concat(type)); - var ptr = [0]; - var usz = parse_varint49(buf, ptr); - var chunks = []; - while (ptr[0] < buf.length) { - var tag = buf[ptr[0]] & 3; - if (tag == 0) { - var len = buf[ptr[0]++] >> 2; - if (len < 60) - ++len; - else { - var c = len - 59; - len = buf[ptr[0]]; - if (c > 1) - len |= buf[ptr[0] + 1] << 8; - if (c > 2) - len |= buf[ptr[0] + 2] << 16; - if (c > 3) - len |= buf[ptr[0] + 3] << 24; - len >>>= 0; - len++; - ptr[0] += c; + return usz.slice(0, L); +} +function varint_to_i32(buf) { + var l = 0, i32 = buf[l] & 127; + varint: + if (buf[l++] >= 128) { + i32 |= (buf[l] & 127) << 7; + if (buf[l++] < 128) + break varint; + i32 |= (buf[l] & 127) << 14; + if (buf[l++] < 128) + break varint; + i32 |= (buf[l] & 127) << 21; + if (buf[l++] < 128) + break varint; + i32 |= (buf[l] & 127) << 28; + } + return i32; +} +function parse_shallow(buf) { + var out = [], ptr = [0]; + while (ptr[0] < buf.length) { + var off = ptr[0]; + var num = parse_varint49(buf, ptr); + var type = num & 7; + num = Math.floor(num / 8); + var len = 0; + var res; + if (num == 0) + break; + switch (type) { + case 0: + { + var l = ptr[0]; + while (buf[ptr[0]++] >= 128) + ; + res = buf.slice(l, ptr[0]); } - chunks.push(buf.slice(ptr[0], ptr[0] + len)); + break; + case 5: + len = 4; + res = buf.slice(ptr[0], ptr[0] + len); + ptr[0] += len; + break; + case 1: + len = 8; + res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; - continue; - } else { - var offset = 0, length = 0; - if (tag == 1) { - length = (buf[ptr[0]] >> 2 & 7) + 4; - offset = (buf[ptr[0]++] & 224) << 3; - offset |= buf[ptr[0]++]; - } else { - length = (buf[ptr[0]++] >> 2) + 1; - if (tag == 2) { - offset = buf[ptr[0]] | buf[ptr[0] + 1] << 8; - ptr[0] += 2; - } else { - offset = (buf[ptr[0]] | buf[ptr[0] + 1] << 8 | buf[ptr[0] + 2] << 16 | buf[ptr[0] + 3] << 24) >>> 0; - ptr[0] += 4; - } - } - chunks = [u8concat(chunks)]; - if (offset == 0) - throw new Error("Invalid offset 0"); - if (offset > chunks[0].length) - throw new Error("Invalid offset beyond length"); - if (length >= offset) { - chunks.push(chunks[0].slice(-offset)); - length -= offset; - while (length >= chunks[chunks.length - 1].length) { - chunks.push(chunks[chunks.length - 1]); - length -= chunks[chunks.length - 1].length; - } - } - chunks.push(chunks[0].slice(-offset, -offset + length)); - } - } - var o = u8concat(chunks); - if (o.length != usz) - throw new Error("Unexpected length: ".concat(o.length, " != ").concat(usz)); - return o; - } - - // src/iwa.ts - function parse_iwa(buf) { - var out = [], ptr = [0]; - while (ptr[0] < buf.length) { - var len = parse_varint49(buf, ptr); - var ai = parse_shallow(buf.slice(ptr[0], ptr[0] + len)); - ptr[0] += len; - var res = { - id: varint_to_i32(ai[1][0].data), - messages: [] - }; - ai[2].forEach(function(b) { - var mi = parse_shallow(b.data); - var fl = varint_to_i32(mi[3][0].data); - res.messages.push({ - meta: mi, - data: buf.slice(ptr[0], ptr[0] + fl) - }); - ptr[0] += fl; - }); - out.push(res); - } - return out; - } - - // src/cell.ts - function parse_old_storage(buf, sst, rsst) { - var dv = u8_to_dataview(buf); - var ctype = buf[buf[0] == 4 ? 1 : 2]; - var flags = dv.getUint32(4, true); - var data_offset = 12 + popcnt(flags & 3470) * 4; - var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); - if (flags & 512) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; - } - data_offset += popcnt(flags & 12288) * 4; - if (flags & 16) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; - } - if (flags & 32) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; - } - if (flags & 64) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; - } - var ret; - switch (ctype) { - case 0: break; case 2: - ret = { t: "n", v: ieee }; + len = parse_varint49(buf, ptr); + res = buf.slice(ptr[0], ptr[0] + len); + ptr[0] += len; break; - case 3: - ret = { t: "s", v: sst[sidx] }; - break; - case 5: - ret = { t: "d", v: dt }; - break; - case 6: - ret = { t: "b", v: ieee > 0 }; - break; - case 7: - ret = { t: "n", v: ieee }; - break; - case 8: - ret = { t: "e", v: 0 }; - break; - case 9: - { - if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; - else if (sidx > -1) - ret = { t: "s", v: sst[sidx] }; - else if (!isNaN(ieee)) - ret = { t: "n", v: ieee }; - else - throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); - } - break; - default: - throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); - } - return ret; - } - function parse_storage(buf, sst, rsst) { - var dv = u8_to_dataview(buf); - var ctype = buf[1]; - var flags = dv.getUint32(8, true); - var data_offset = 12; - var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); - if (flags & 1) { - d128 = readDecimal128LE(buf, data_offset); - data_offset += 16; - } - if (flags & 2) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; - } - if (flags & 4) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; - } - if (flags & 8) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; - } - if (flags & 16) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; - } - var ret; - switch (ctype) { - case 0: - break; - case 2: - ret = { t: "n", v: d128 }; - break; - case 3: - ret = { t: "s", v: sst[sidx] }; - break; - case 5: - ret = { t: "d", v: dt }; - break; - case 6: - ret = { t: "b", v: ieee > 0 }; - break; - case 7: - ret = { t: "n", v: ieee }; - break; - case 8: - ret = { t: "e", v: 0 }; - break; - case 9: - { - if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; - else - throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); - } - break; - case 10: - ret = { t: "n", v: d128 }; - break; - default: - throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); - } - return ret; - } - function parse(buf, sst, rsst) { - switch (buf[0]) { case 3: case 4: - return parse_old_storage(buf, sst, rsst); - case 5: - return parse_storage(buf, sst, rsst); default: - throw new Error("Unsupported payload version ".concat(buf[0])); + throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off)); } + var v = { offset: off, data: res, type: type }; + if (out[num] == null) + out[num] = [v]; + else + out[num].push(v); } - - // src/numbers.ts - var encode_col = function(C) { - var s = ""; - for (++C; C; C = Math.floor((C - 1) / 26)) - s = String.fromCharCode((C - 1) % 26 + 65) + s; - return s; - }; - var encode_cell = function(c) { - return "".concat(encode_col(c.c)).concat(c.r + 1); - }; - var encode_range = function(r) { - return encode_cell(r.s) + ":" + encode_cell(r.e); - }; - var book_new = function() { - return { Sheets: {}, SheetNames: [] }; - }; - var book_append_sheet = function(wb, ws, name) { - var i = 1; - if (!name) - for (; i < 9999; ++i) { - if (wb.SheetNames.indexOf(name = "Sheet ".concat(i)) == -1) - break; - } - else if (wb.SheetNames.indexOf(name) > -1) - for (; i < 9999; ++i) { - if (wb.SheetNames.indexOf("".concat(name, "_").concat(i)) == -1) { - name = "".concat(name, "_").concat(i); - break; - } - } - wb.SheetNames.push(name); - wb.Sheets[name] = ws; - }; - function parse_numbers(cfb) { - var out = []; - cfb.FullPaths.forEach(function(p) { - if (p.match(/\.iwpv2/)) - throw new Error("Unsupported password protection"); + return out; +} +function write_shallow(proto) { + var out = []; + proto.forEach(function(field, idx) { + field.forEach(function(item) { + out.push(write_varint49(idx * 8 + item.type)); + out.push(item.data); }); - cfb.FileIndex.forEach(function(s) { - if (!s.name.match(/\.iwa$/)) - return; - var o; - try { - o = deframe(s.content); - } catch (e) { - return console.log("?? " + s.content.length + " " + (e.message || e)); - } - var packets; - try { - packets = parse_iwa(o); - } catch (e) { - return console.log("## " + (e.message || e)); - } - packets.forEach(function(packet) { - out[+packet.id] = packet.messages; - }); - }); - if (!out.length) - throw new Error("File has no messages"); - var docroot; - out.forEach(function(iwams) { - iwams.forEach(function(iwam) { - var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0; - if (mtype == 1) { - if (!docroot) - docroot = iwam; - else - throw new Error("Document has multiple roots"); - } - }); - }); - if (!docroot) - throw new Error("Cannot find Document root"); - return parse_docroot(out, docroot); - } - var numbers_default = parse_numbers; - function parse_Reference(buf) { - var pb = parse_shallow(buf); - return parse_varint49(pb[1][0].data); - } - function parse_TST_TableDataList(M, root) { - var pb = parse_shallow(root.data); - var type = varint_to_i32(pb[1][0].data); - var entries = pb[3]; - var data = []; - (entries || []).forEach(function(entry) { - var le = parse_shallow(entry.data); - var key = varint_to_i32(le[1][0].data) >>> 0; - switch (type) { - case 1: - data[key] = u8str(le[3][0].data); - break; - case 8: - { - var rt = M[parse_Reference(le[9][0].data)][0]; - var rtp = parse_shallow(rt.data); - var rtpref = M[parse_Reference(rtp[1][0].data)][0]; - var mtype = varint_to_i32(rtpref.meta[1][0].data); - if (mtype != 2001) - throw new Error("2000 unexpected reference to ".concat(mtype)); - var tswpsa = parse_shallow(rtpref.data); - data[key] = tswpsa[3].map(function(x) { - return u8str(x.data); - }).join(""); - } - break; - } - }); - return data; - } - function parse_TST_TileRowInfo(u8) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; - var pb = parse_shallow(u8); - var R = varint_to_i32(pb[1][0].data) >>> 0; - var pre_bnc = (_b = (_a = pb[3]) == null ? void 0 : _a[0]) == null ? void 0 : _b.data; - var pre_bnc_offsets = ((_d = (_c = pb[4]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && u8_to_dataview(pb[4][0].data); - var storage = (_f = (_e = pb[6]) == null ? void 0 : _e[0]) == null ? void 0 : _f.data; - var storage_offsets = ((_h = (_g = pb[7]) == null ? void 0 : _g[0]) == null ? void 0 : _h.data) && u8_to_dataview(pb[7][0].data); - var wide_offsets = ((_j = (_i = pb[8]) == null ? void 0 : _i[0]) == null ? void 0 : _j.data) && varint_to_i32(pb[8][0].data) > 0 || false; - var width = wide_offsets ? 4 : 1; - var cells = []; - var off = 0; - for (var C = 0; C < pre_bnc_offsets.byteLength / 2; ++C) { - if (storage && storage_offsets) { - off = storage_offsets.getUint16(C * 2, true) * width; - if (off < storage.length) { - cells[C] = storage.subarray(off, storage_offsets.getUint16(C * 2 + 2, true) * width); - continue; - } - } - if (pre_bnc && pre_bnc_offsets) { - off = pre_bnc_offsets.getUint16(C * 2, true) * width; - if (off < pre_bnc.length) - cells[C] = pre_bnc.subarray(off, pre_bnc_offsets.getUint16(C * 2 + 2, true) * width); - } - } - return { R: R, cells: cells }; - } - function parse_TST_Tile(M, root) { - var pb = parse_shallow(root.data); - var ri = mappa(pb[5], parse_TST_TileRowInfo); - return ri.reduce(function(acc, x) { - if (!acc[x.R]) - acc[x.R] = []; - x.cells.forEach(function(cell, C) { - if (acc[x.R][C]) - throw new Error("Duplicate cell r=".concat(x.R, " c=").concat(C)); - acc[x.R][C] = cell; - }); - return acc; - }, []); - } - function parse_TST_TableModelArchive(M, root, ws) { + }); + return u8concat(out); +} +function mappa(data, cb) { + if (!data) + return []; + return data.map(function(d) { var _a; - var pb = parse_shallow(root.data); - var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } }; - range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; - if (range.e.r < 0) - throw new Error("Invalid row varint ".concat(pb[6][0].data)); - range.e.c = (varint_to_i32(pb[7][0].data) >>> 0) - 1; - if (range.e.c < 0) - throw new Error("Invalid col varint ".concat(pb[7][0].data)); - ws["!ref"] = encode_range(range); - { - var store = parse_shallow(pb[4][0].data); - var sst = parse_TST_TableDataList(M, M[parse_Reference(store[4][0].data)][0]); - var rsst = ((_a = store[17]) == null ? void 0 : _a[0]) ? parse_TST_TableDataList(M, M[parse_Reference(store[17][0].data)][0]) : []; - { - var tile = parse_shallow(store[3][0].data); - var tiles = []; - tile[1].forEach(function(t) { - var tl = parse_shallow(t.data); - var ref = M[parse_Reference(tl[2][0].data)][0]; - var mtype = varint_to_i32(ref.meta[1][0].data); - if (mtype != 6002) - throw new Error("6001 unexpected reference to ".concat(mtype)); - tiles.push({ id: varint_to_i32(tl[1][0].data), ref: parse_TST_Tile(M, ref) }); - }); - tiles.forEach(function(tile2) { - tile2.ref.forEach(function(row, R) { - row.forEach(function(buf, C) { - var addr = encode_cell({ r: R, c: C }); - var res = parse(buf, sst, rsst); - if (res) - ws[addr] = res; - }); - }); - }); - } + try { + return cb(d.data); + } catch (e) { + var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/); + if (m) + e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset)); + throw e; } - } - function parse_TST_TableInfoArchive(M, root) { - var pb = parse_shallow(root.data); - var out = { "!ref": "A1" }; - var tableref = M[parse_Reference(pb[2][0].data)]; - var mtype = varint_to_i32(tableref[0].meta[1][0].data); - if (mtype != 6001) - throw new Error("6000 unexpected reference to ".concat(mtype)); - parse_TST_TableModelArchive(M, tableref[0], out); - return out; - } - function parse_sheetroot(M, root) { - var _a; - var pb = parse_shallow(root.data); - var out = { - name: ((_a = pb[1]) == null ? void 0 : _a[0]) ? u8str(pb[1][0].data) : "", - sheets: [] + }); +} +function parse_iwa_file(buf) { + var out = [], ptr = [0]; + while (ptr[0] < buf.length) { + var len = parse_varint49(buf, ptr); + var ai = parse_shallow(buf.slice(ptr[0], ptr[0] + len)); + ptr[0] += len; + var res = { + id: varint_to_i32(ai[1][0].data), + messages: [] }; - var shapeoffs = mappa(pb[2], parse_Reference); - shapeoffs.forEach(function(off) { - M[off].forEach(function(m) { - var mtype = varint_to_i32(m.meta[1][0].data); - if (mtype == 6e3) - out.sheets.push(parse_TST_TableInfoArchive(M, m)); + ai[2].forEach(function(b) { + var mi = parse_shallow(b.data); + var fl = varint_to_i32(mi[3][0].data); + res.messages.push({ + meta: mi, + data: buf.slice(ptr[0], ptr[0] + fl) }); + ptr[0] += fl; }); - return out; + out.push(res); } - function parse_docroot(M, root) { - var out = book_new(); - var pb = parse_shallow(root.data); - var sheetoffs = mappa(pb[1], parse_Reference); - sheetoffs.forEach(function(off) { - M[off].forEach(function(m) { - var mtype = varint_to_i32(m.meta[1][0].data); - if (mtype == 2) { - var root2 = parse_sheetroot(M, m); - root2.sheets.forEach(function(sheet) { - book_append_sheet(out, sheet, root2.name); - }); + return out; +} +function parse_snappy_chunk(type, buf) { + if (type != 0) + throw new Error("Unexpected Snappy chunk type ".concat(type)); + var ptr = [0]; + var usz = parse_varint49(buf, ptr); + var chunks = []; + while (ptr[0] < buf.length) { + var tag = buf[ptr[0]] & 3; + if (tag == 0) { + var len = buf[ptr[0]++] >> 2; + if (len < 60) + ++len; + else { + var c = len - 59; + len = buf[ptr[0]]; + if (c > 1) + len |= buf[ptr[0] + 1] << 8; + if (c > 2) + len |= buf[ptr[0] + 2] << 16; + if (c > 3) + len |= buf[ptr[0] + 3] << 24; + len >>>= 0; + len++; + ptr[0] += c; + } + chunks.push(buf.slice(ptr[0], ptr[0] + len)); + ptr[0] += len; + continue; + } else { + var offset = 0, length = 0; + if (tag == 1) { + length = (buf[ptr[0]] >> 2 & 7) + 4; + offset = (buf[ptr[0]++] & 224) << 3; + offset |= buf[ptr[0]++]; + } else { + length = (buf[ptr[0]++] >> 2) + 1; + if (tag == 2) { + offset = buf[ptr[0]] | buf[ptr[0] + 1] << 8; + ptr[0] += 2; + } else { + offset = (buf[ptr[0]] | buf[ptr[0] + 1] << 8 | buf[ptr[0] + 2] << 16 | buf[ptr[0] + 3] << 24) >>> 0; + ptr[0] += 4; } - }); - }); - if (out.SheetNames.length == 0) - throw new Error("Empty NUMBERS file"); - return out; + } + chunks = [u8concat(chunks)]; + if (offset == 0) + throw new Error("Invalid offset 0"); + if (offset > chunks[0].length) + throw new Error("Invalid offset beyond length"); + if (length >= offset) { + chunks.push(chunks[0].slice(-offset)); + length -= offset; + while (length >= chunks[chunks.length - 1].length) { + chunks.push(chunks[chunks.length - 1]); + length -= chunks[chunks.length - 1].length; + } + } + chunks.push(chunks[0].slice(-offset, -offset + length)); + } } - return __toCommonJS(numbers_exports); -})(); -/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ + var o = u8concat(chunks); + if (o.length != usz) + throw new Error("Unexpected length: ".concat(o.length, " != ").concat(usz)); + return o; +} +function deframe(buf) { + var out = []; + var l = 0; + while (l < buf.length) { + var t = buf[l++]; + var len = buf[l] | buf[l + 1] << 8 | buf[l + 2] << 16; + l += 3; + out.push(parse_snappy_chunk(t, buf.slice(l, l + len))); + l += len; + } + if (l !== buf.length) + throw new Error("data is not a valid framed stream!"); + return u8concat(out); +} +function parse_old_storage(buf, sst, rsst) { + var dv = u8_to_dataview(buf); + var ctype = buf[buf[0] == 4 ? 1 : 2]; + var flags = dv.getUint32(4, true); + var data_offset = 12 + popcnt(flags & 3470) * 4; + var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); + if (flags & 512) { + ridx = dv.getUint32(data_offset, true); + data_offset += 4; + } + data_offset += popcnt(flags & 12288) * 4; + if (flags & 16) { + sidx = dv.getUint32(data_offset, true); + data_offset += 4; + } + if (flags & 32) { + ieee = dv.getFloat64(data_offset, true); + data_offset += 8; + } + if (flags & 64) { + dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); + data_offset += 8; + } + var ret; + switch (ctype) { + case 0: + break; + case 2: + ret = { t: "n", v: ieee }; + break; + case 3: + ret = { t: "s", v: sst[sidx] }; + break; + case 5: + ret = { t: "d", v: dt }; + break; + case 6: + ret = { t: "b", v: ieee > 0 }; + break; + case 7: + ret = { t: "n", v: ieee }; + break; + case 8: + ret = { t: "e", v: 0 }; + break; + case 9: + { + if (ridx > -1) + ret = { t: "s", v: rsst[ridx] }; + else if (sidx > -1) + ret = { t: "s", v: sst[sidx] }; + else if (!isNaN(ieee)) + ret = { t: "n", v: ieee }; + else + throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); + } + break; + default: + throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); + } + return ret; +} +function parse_storage(buf, sst, rsst) { + var dv = u8_to_dataview(buf); + var ctype = buf[1]; + var flags = dv.getUint32(8, true); + var data_offset = 12; + var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); + if (flags & 1) { + d128 = readDecimal128LE(buf, data_offset); + data_offset += 16; + } + if (flags & 2) { + ieee = dv.getFloat64(data_offset, true); + data_offset += 8; + } + if (flags & 4) { + dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); + data_offset += 8; + } + if (flags & 8) { + sidx = dv.getUint32(data_offset, true); + data_offset += 4; + } + if (flags & 16) { + ridx = dv.getUint32(data_offset, true); + data_offset += 4; + } + var ret; + switch (ctype) { + case 0: + break; + case 2: + ret = { t: "n", v: d128 }; + break; + case 3: + ret = { t: "s", v: sst[sidx] }; + break; + case 5: + ret = { t: "d", v: dt }; + break; + case 6: + ret = { t: "b", v: ieee > 0 }; + break; + case 7: + ret = { t: "n", v: ieee }; + break; + case 8: + ret = { t: "e", v: 0 }; + break; + case 9: + { + if (ridx > -1) + ret = { t: "s", v: rsst[ridx] }; + else + throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); + } + break; + case 10: + ret = { t: "n", v: d128 }; + break; + default: + throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); + } + return ret; +} +function parse_cell_storage(buf, sst, rsst) { + switch (buf[0]) { + case 3: + case 4: + return parse_old_storage(buf, sst, rsst); + case 5: + return parse_storage(buf, sst, rsst); + default: + throw new Error("Unsupported payload version ".concat(buf[0])); + } +} +function parse_TSP_Reference(buf) { + var pb = parse_shallow(buf); + return parse_varint49(pb[1][0].data); +} +function parse_TST_TableDataList(M, root) { + var pb = parse_shallow(root.data); + var type = varint_to_i32(pb[1][0].data); + var entries = pb[3]; + var data = []; + (entries || []).forEach(function(entry) { + var le = parse_shallow(entry.data); + var key = varint_to_i32(le[1][0].data) >>> 0; + switch (type) { + case 1: + data[key] = u8str(le[3][0].data); + break; + case 8: + { + var rt = M[parse_TSP_Reference(le[9][0].data)][0]; + var rtp = parse_shallow(rt.data); + var rtpref = M[parse_TSP_Reference(rtp[1][0].data)][0]; + var mtype = varint_to_i32(rtpref.meta[1][0].data); + if (mtype != 2001) + throw new Error("2000 unexpected reference to ".concat(mtype)); + var tswpsa = parse_shallow(rtpref.data); + data[key] = tswpsa[3].map(function(x) { + return u8str(x.data); + }).join(""); + } + break; + } + }); + return data; +} +function parse_TST_TileRowInfo(u8) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; + var pb = parse_shallow(u8); + var R = varint_to_i32(pb[1][0].data) >>> 0; + var pre_bnc = (_b = (_a = pb[3]) == null ? void 0 : _a[0]) == null ? void 0 : _b.data; + var pre_bnc_offsets = ((_d = (_c = pb[4]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && u8_to_dataview(pb[4][0].data); + var storage = (_f = (_e = pb[6]) == null ? void 0 : _e[0]) == null ? void 0 : _f.data; + var storage_offsets = ((_h = (_g = pb[7]) == null ? void 0 : _g[0]) == null ? void 0 : _h.data) && u8_to_dataview(pb[7][0].data); + var wide_offsets = ((_j = (_i = pb[8]) == null ? void 0 : _i[0]) == null ? void 0 : _j.data) && varint_to_i32(pb[8][0].data) > 0 || false; + var width = wide_offsets ? 4 : 1; + var cells = []; + var off = 0; + for (var C = 0; C < pre_bnc_offsets.byteLength / 2; ++C) { + if (storage && storage_offsets) { + off = storage_offsets.getUint16(C * 2, true) * width; + if (off < storage.length) { + cells[C] = storage.subarray(off, storage_offsets.getUint16(C * 2 + 2, true) * width); + continue; + } + } + if (pre_bnc && pre_bnc_offsets) { + off = pre_bnc_offsets.getUint16(C * 2, true) * width; + if (off < pre_bnc.length) + cells[C] = pre_bnc.subarray(off, pre_bnc_offsets.getUint16(C * 2 + 2, true) * width); + } + } + return { R: R, cells: cells }; +} +function parse_TST_Tile(M, root) { + var pb = parse_shallow(root.data); + var ri = mappa(pb[5], parse_TST_TileRowInfo); + return ri.reduce(function(acc, x) { + if (!acc[x.R]) + acc[x.R] = []; + x.cells.forEach(function(cell, C) { + if (acc[x.R][C]) + throw new Error("Duplicate cell r=".concat(x.R, " c=").concat(C)); + acc[x.R][C] = cell; + }); + return acc; + }, []); +} +function parse_TST_TableModelArchive(M, root, ws) { + var _a; + var pb = parse_shallow(root.data); + var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } }; + range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; + if (range.e.r < 0) + throw new Error("Invalid row varint ".concat(pb[6][0].data)); + range.e.c = (varint_to_i32(pb[7][0].data) >>> 0) - 1; + if (range.e.c < 0) + throw new Error("Invalid col varint ".concat(pb[7][0].data)); + ws["!ref"] = encode_range(range); + { + var store = parse_shallow(pb[4][0].data); + var sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); + var rsst = ((_a = store[17]) == null ? void 0 : _a[0]) ? parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]) : []; + { + var tile = parse_shallow(store[3][0].data); + var tiles = []; + tile[1].forEach(function(t) { + var tl = parse_shallow(t.data); + var ref = M[parse_TSP_Reference(tl[2][0].data)][0]; + var mtype = varint_to_i32(ref.meta[1][0].data); + if (mtype != 6002) + throw new Error("6001 unexpected reference to ".concat(mtype)); + tiles.push({ id: varint_to_i32(tl[1][0].data), ref: parse_TST_Tile(M, ref) }); + }); + tiles.forEach(function(tile2) { + tile2.ref.forEach(function(row, R) { + row.forEach(function(buf, C) { + var addr = encode_cell({ r: R, c: C }); + var res = parse_cell_storage(buf, sst, rsst); + if (res) + ws[addr] = res; + }); + }); + }); + } + } +} +function parse_TST_TableInfoArchive(M, root) { + var pb = parse_shallow(root.data); + var out = { "!ref": "A1" }; + var tableref = M[parse_TSP_Reference(pb[2][0].data)]; + var mtype = varint_to_i32(tableref[0].meta[1][0].data); + if (mtype != 6001) + throw new Error("6000 unexpected reference to ".concat(mtype)); + parse_TST_TableModelArchive(M, tableref[0], out); + return out; +} +function parse_TN_SheetArchive(M, root) { + var _a; + var pb = parse_shallow(root.data); + var out = { + name: ((_a = pb[1]) == null ? void 0 : _a[0]) ? u8str(pb[1][0].data) : "", + sheets: [] + }; + var shapeoffs = mappa(pb[2], parse_TSP_Reference); + shapeoffs.forEach(function(off) { + M[off].forEach(function(m) { + var mtype = varint_to_i32(m.meta[1][0].data); + if (mtype == 6e3) + out.sheets.push(parse_TST_TableInfoArchive(M, m)); + }); + }); + return out; +} +function parse_TN_DocumentArchive(M, root) { + var out = book_new(); + var pb = parse_shallow(root.data); + var sheetoffs = mappa(pb[1], parse_TSP_Reference); + sheetoffs.forEach(function(off) { + M[off].forEach(function(m) { + var mtype = varint_to_i32(m.meta[1][0].data); + if (mtype == 2) { + var root2 = parse_TN_SheetArchive(M, m); + root2.sheets.forEach(function(sheet) { + book_append_sheet(out, sheet, root2.name); + }); + } + }); + }); + if (out.SheetNames.length == 0) + throw new Error("Empty NUMBERS file"); + return out; +} +function parse_numbers_iwa(cfb) { + var out = []; + cfb.FullPaths.forEach(function(p) { + if (p.match(/\.iwpv2/)) + throw new Error("Unsupported password protection"); + }); + cfb.FileIndex.forEach(function(s) { + if (!s.name.match(/\.iwa$/)) + return; + var o; + try { + o = deframe(s.content); + } catch (e) { + return console.log("?? " + s.content.length + " " + (e.message || e)); + } + var packets; + try { + packets = parse_iwa_file(o); + } catch (e) { + return console.log("## " + (e.message || e)); + } + packets.forEach(function(packet) { + out[+packet.id] = packet.messages; + }); + }); + if (!out.length) + throw new Error("File has no messages"); + var docroot; + out.forEach(function(iwams) { + iwams.forEach(function(iwam) { + var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0; + if (mtype == 1) { + if (!docroot) + docroot = iwam; + else + throw new Error("Document has multiple roots"); + } + }); + }); + if (!docroot) + throw new Error("Cannot find Document root"); + return parse_TN_DocumentArchive(out, docroot); +} diff --git a/bits/84_defaults.js b/bits/84_defaults.js index ef33911..dbabb01 100644 --- a/bits/84_defaults.js +++ b/bits/84_defaults.js @@ -8,7 +8,7 @@ function fix_opts_func(defaults/*:Array >*/)/*:{(o:any):void}*/ { }; } -var fix_read_opts = function(opts) { +function fix_read_opts(opts) { fix_opts_func([ ['cellNF', false], /* emit cell number format string as .z */ ['cellHTML', true], /* emit html string as .h */ @@ -29,9 +29,10 @@ fix_opts_func([ ['password',''], /* password */ ['WTF', false] /* WTF mode (throws errors) */ ])(opts); -}; +} -var fix_write_opts = fix_opts_func([ +function fix_write_opts(opts) { +fix_opts_func([ ['cellDates', false], /* write date cells with type `d` */ ['bookSST', false], /* Generate Shared String Table */ @@ -41,4 +42,5 @@ var fix_write_opts = fix_opts_func([ ['compression', false], /* Use file compression */ ['WTF', false] /* WTF mode (throws errors) */ -]); +])(opts); +} diff --git a/bits/85_parsezip.js b/bits/85_parsezip.js index 4eea8bd..0f2fcba 100644 --- a/bits/85_parsezip.js +++ b/bits/85_parsezip.js @@ -13,7 +13,7 @@ function safe_parse_wbrels(wbrels, sheets) { return !wbrels || wbrels.length === 0 ? null : wbrels; } -function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/*:number*/, sheetRels, sheets, stype/*:string*/, opts, wb, themes, styles) { +function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/*:number*/, sheetRels, sheets, stype/*:string*/, opts, wb, themes, styles, people) { try { sheetRels[sheet]=parse_rels(getzipstr(zip, relsPath, true), path); var data = getzipdata(zip, path); @@ -35,16 +35,22 @@ function safe_parse_sheet(zip, path/*:string*/, relsPath/*:string*/, sheet, idx/ } sheets[sheet] = _ws; - /* scan rels for comments */ - var comments = []; + /* scan rels for comments and threaded comments */ + var tcomments = [], tauthors = []; if(sheetRels && sheetRels[sheet]) keys(sheetRels[sheet]).forEach(function(n) { + var dfile = ""; if(sheetRels[sheet][n].Type == RELS.CMNT) { - var dfile = resolve_path(sheetRels[sheet][n].Target, path); - comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts); + dfile = resolve_path(sheetRels[sheet][n].Target, path); + var comments = parse_cmnt(getzipdata(zip, dfile, true), dfile, opts); if(!comments || !comments.length) return; - sheet_insert_comments(_ws, comments); + sheet_insert_comments(_ws, comments, false); + } + if(sheetRels[sheet][n].Type == RELS.TCMNT) { + dfile = resolve_path(sheetRels[sheet][n].Target, path); + tcomments = tcomments.concat(parse_tcmnt_xml(getzipdata(zip, dfile, true), opts)); } }); + if(tcomments && tcomments.length) sheet_insert_comments(_ws, tcomments, true, opts.people || []); } catch(e) { if(opts.WTF) throw e; } } @@ -62,11 +68,11 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { /* Numbers */ if(safegetzipfile(zip, 'Index/Document.iwa')) { if(typeof Uint8Array == "undefined") throw new Error('NUMBERS file parsing requires Uint8Array support'); - if(typeof NUMBERS != "undefined") { - if(zip.FileIndex) return NUMBERS.parse_numbers(zip); + if(typeof parse_numbers_iwa != "undefined") { + if(zip.FileIndex) return parse_numbers_iwa(zip); var _zip = CFB.utils.cfb_new(); zipentries(zip).forEach(function(e) { zip_add_file(_zip, e, getzipbin(zip, e)); }); - return NUMBERS.parse_numbers(_zip); + return parse_numbers_iwa(_zip); } throw new Error('Unsupported NUMBERS file'); } @@ -168,8 +174,11 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { opts.xlmeta = parse_xlmeta(getzipdata(zip, strip_front_slash(dir.metadata[0])),dir.metadata[0],opts); } - if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); + if((dir.people || []).length >= 1) { + opts.people = parse_people_xml(getzipdata(zip, strip_front_slash(dir.people[0])),opts); + } + if(wbrels) wbrels = safe_parse_wbrels(wbrels, wb.Sheets); /* Numbers iOS hack */ var nmode = (getzipdata(zip,"xl/worksheets/sheet.xml",true))?1:0; diff --git a/bits/86_writezip.js b/bits/86_writezip.js index 953fb76..510f58b 100644 --- a/bits/86_writezip.js +++ b/bits/86_writezip.js @@ -1,8 +1,13 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { if(opts.bookType == "ods") return write_ods(wb, opts); - return write_zip_xlsxb(wb, opts); + if(opts.bookType == "xlsb") return write_zip_xlsxb(wb, opts); + return write_zip_xlsx(wb, opts); } +/* XLSX and XLSB writing are very similar. Originally they were unified in one + export function. This is horrible for tree shaking in the common case (most + applications need to export files in one format) so this function supports + both formats while write_zip_xlsx only handles XLSX */ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { _shapeid = 1024; if(wb && !wb.SSF) { @@ -137,7 +142,6 @@ function write_zip_xlsxb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { return zip; } -/* this version does not reference XLSB write functions */ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { _shapeid = 1024; if(wb && !wb.SSF) { @@ -192,6 +196,9 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { add_rels(opts.rels, 4, f, RELS.CUST_PROPS); } + var people = ["SheetJ5"]; + opts.tcid = 0; + for(rId=1;rId <= wb.SheetNames.length; ++rId) { var wsrels = {'!id':{}}; var ws = wb.Sheets[wb.SheetNames[rId-1]]; @@ -210,6 +217,17 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { var comments = ws['!comments']; var need_vml = false; if(comments && comments.length > 0) { + var needtc = false; + comments.forEach(function(carr) { + carr[1].forEach(function(c) { if(c.T == true) needtc = true; }); + }); + if(needtc) { + cf = "xl/threadedComments/threadedComment" + rId + "." + wbext; + zip_add_file(zip, cf, write_tcmnt_xml(comments, people, opts)); + ct.threadedcomments.push(cf); + add_rels(wsrels, -1, "../threadedComments/threadedComment" + rId + "." + wbext, RELS.TCMNT); + } + var cf = "xl/comments" + rId + "." + wbext; zip_add_file(zip, cf, write_comments_xml(comments, opts)); ct.comments.push(cf); @@ -264,6 +282,13 @@ function write_zip_xlsx(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { ct.metadata.push(f); add_rels(opts.wbrels, -1, "metadata." + wbext, RELS.XLMETA); + if(people.length > 1) { + f = "xl/persons/person.xml"; + zip_add_file(zip, f, write_people_xml(people, opts)); + ct.people.push(f); + add_rels(opts.wbrels, -1, "persons/person.xml", RELS.PEOPLE); + } + zip_add_file(zip, "[Content_Types].xml", write_ct(ct, opts)); zip_add_file(zip, '_rels/.rels', write_rels(opts.rels)); zip_add_file(zip, 'xl/_rels/workbook.' + wbext + '.rels', write_rels(opts.wbrels)); diff --git a/demos/react/modify/public/index.html b/demos/react/modify/public/index.html new file mode 100644 index 0000000..aa069f2 --- /dev/null +++ b/demos/react/modify/public/index.html @@ -0,0 +1,43 @@ + + + + + + + + + + + + + React App + + + +
+ + + diff --git a/docbits/66_comments.md b/docbits/66_comments.md index 444363e..b186262 100644 --- a/docbits/66_comments.md +++ b/docbits/66_comments.md @@ -26,3 +26,23 @@ ws.A2.c.hidden = true; ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"}); ``` + +_Threaded Comments_ + +Introduced in Excel 365, threaded comments are plain text comment snippets with +author metadata and parent references. They are supported in XLSX and XLSB. + +To mark a comment as threaded, each comment part must have a true `T` property: + +```js +if(!ws.A1.c) ws.A1.c = []; +ws.A1.c.push({a:"SheetJS", t:"This is not threaded"}); + +if(!ws.A2.c) ws.A2.c = []; +ws.A2.c.hidden = true; +ws.A2.c.push({a:"SheetJS", t:"This is threaded", T: true}); +ws.A2.c.push({a:"JSSheet", t:"This is also threaded", T: true}); +``` + +There is no Active Directory or Office 365 metadata associated with authors in a thread. + diff --git a/misc/51_xlsxmeta.js b/misc/51_xlsxmeta.js index e34084e..30ad251 100644 --- a/misc/51_xlsxmeta.js +++ b/misc/51_xlsxmeta.js @@ -1,9 +1,9 @@ -RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; function parse_xlmeta_xml(data, name, opts) { - var out = { Types: [] }; + var out = { Types: [], Cell: [], Value: [] }; if (!data) return out; var pass = false; + var metatype = ""; data.replace(tagregex, function(x, idx) { var y = parsexmltag(x); switch (strip_ns(y[0])) { @@ -18,6 +18,8 @@ function parse_xlmeta_xml(data, name, opts) { case "": + break; case "": @@ -27,15 +29,24 @@ function parse_xlmeta_xml(data, name, opts) { case "": break; case "": break; case "": + metatype = ""; break; case "": + metatype = ""; break; case "": diff --git a/misc/docs/README.md b/misc/docs/README.md index d4899a2..0d52e3a 100644 --- a/misc/docs/README.md +++ b/misc/docs/README.md @@ -562,6 +562,7 @@ The [`demos` directory](demos/) includes sample projects for: - [`Headless Browsers`](demos/headless/) - [`canvas-datagrid`](demos/datagrid/) - [`x-spreadsheet`](demos/xspreadsheet/) +- [`react-data-grid`](demos/react/modify/) - [`Swift JSC and other engines`](demos/altjs/) - [`"serverless" functions`](demos/function/) - [`internet explorer`](demos/oldie/) @@ -2907,6 +2908,26 @@ ws.A2.c.hidden = true; ws.A2.c.push({a:"SheetJS", t:"This comment will be hidden"}); ``` + +_Threaded Comments_ + +Introduced in Excel 365, threaded comments are plain text comment snippets with +author metadata and parent references. They are supported in XLSX and XLSB. + +To mark a comment as threaded, each comment part must have a true `T` property: + +```js +if(!ws.A1.c) ws.A1.c = []; +ws.A1.c.push({a:"SheetJS", t:"This is not threaded"}); + +if(!ws.A2.c) ws.A2.c = []; +ws.A2.c.hidden = true; +ws.A2.c.push({a:"SheetJS", t:"This is threaded", T: true}); +ws.A2.c.push({a:"JSSheet", t:"This is also threaded", T: true}); +``` + +There is no Active Directory or Office 365 metadata associated with authors in a thread. + #### Sheet Visibility Excel enables hiding sheets in the lower tab bar. The sheet data is stored in diff --git a/misc/mjs.lst b/misc/mjs.lst index c799f6b..870006b 100644 --- a/misc/mjs.lst +++ b/misc/mjs.lst @@ -38,7 +38,8 @@ bits/47_styxml.js bits/48_stybin.js bits/49_theme.js bits/50_styxls.js -bits/51_xlmeta.js +bits/51_xlsbmeta.js +bits/51_xlsxmeta.js bits/52_calcchain.js bits/53_externlink.js bits/54_drawing.js diff --git a/modules/51_xlmeta.js b/modules/51_xlmeta.js deleted file mode 100644 index 36faf35..0000000 --- a/modules/51_xlmeta.js +++ /dev/null @@ -1,150 +0,0 @@ -RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; -function parse_xlmeta_xml(data, name, opts) { - var out = { Types: [] }; - if (!data) - return out; - var pass = false; - data.replace(tagregex, function(x, idx) { - var y = parsexmltag(x); - switch (strip_ns(y[0])) { - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - break; - case "": - case "
": - case "": - break; - case "": - pass = false; - break; - default: - if (!pass && opts.WTF) - throw new Error("unrecognized " + y[0] + " in metadata"); - } - return x; - }); - return out; -} -function write_xlmeta_xml() { - var o = [XML_HEADER]; - o.push('\n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n \n'); - return o.join(""); -} -function parse_BrtMdtinfo(data, length) { - return { - flags: data.read_shift(4), - version: data.read_shift(4), - name: parse_XLWideString(data, length - 8) - }; -} -function write_BrtMdtinfo(data) { - var o = new_buf(12 + 2 * data.name.length); - o.write_shift(4, data.flags); - o.write_shift(4, data.version); - write_XLWideString(data.name, o); - return o.slice(0, o.l); -} -function write_BrtMdb(mdb) { - var o = new_buf(4 + 8 * mdb.length); - o.write_shift(4, mdb.length); - for (var i = 0; i < mdb.length; ++i) { - o.write_shift(4, mdb[i][0]); - o.write_shift(4, mdb[i][1]); - } - return o; -} -function write_BrtBeginEsfmd(cnt, name) { - var o = new_buf(8 + 2 * name.length); - o.write_shift(4, cnt); - write_XLWideString(name, o); - return o.slice(0, o.l); -} -function write_BrtBeginEsmdb(cnt, cm) { - var o = new_buf(8); - o.write_shift(4, cnt); - o.write_shift(4, cm ? 1 : 0); - return o; -} -function parse_xlmeta_bin(data, name, _opts) { - var out = { Types: [] }; - var opts = _opts || {}; - var state = []; - var pass = false; - recordhopper(data, function(val, R, RT) { - switch (RT) { - case 335: - out.Types.push({ name: val.name }); - break; - case 51: - break; - case 35: - state.push(RT); - pass = true; - break; - case 36: - state.pop(); - pass = false; - break; - default: - if (R.T) { - } else if (!pass || opts.WTF && state[state.length - 1] != 35) - throw new Error("Unexpected record 0x" + RT.toString(16)); - } - }); - return out; -} -function write_xlmeta_bin() { - var ba = buf_array(); - write_record(ba, 332); - write_record(ba, 334, write_UInt32LE(1)); - write_record(ba, 335, write_BrtMdtinfo({ - name: "XLDAPR", - version: 12e4, - flags: 3496657072 - })); - write_record(ba, 336); - write_record(ba, 339, write_BrtBeginEsfmd(1, "XLDAPR")); - write_record(ba, 52); - write_record(ba, 35, write_UInt32LE(514)); - write_record(ba, 4096, write_UInt32LE(0)); - write_record(ba, 4097, writeuint16(1)); - write_record(ba, 36); - write_record(ba, 53); - write_record(ba, 340); - write_record(ba, 337, write_BrtBeginEsmdb(1, true)); - write_record(ba, 51, write_BrtMdb([[1, 0]])); - write_record(ba, 338); - write_record(ba, 333); - return ba.end(); -} diff --git a/modules/51_xlsbmeta.js b/modules/51_xlsbmeta.js index aca9930..903dd5a 100644 --- a/modules/51_xlsbmeta.js +++ b/modules/51_xlsbmeta.js @@ -12,6 +12,13 @@ function write_BrtMdtinfo(data) { write_XLWideString(data.name, o); return o.slice(0, o.l); } +function parse_BrtMdb(data, length) { + var out = []; + var cnt = data.read_shift(4); + while (cnt-- > 0) + out.push([data.read_shift(4), data.read_shift(4)]); + return out; +} function write_BrtMdb(mdb) { var o = new_buf(4 + 8 * mdb.length); o.write_shift(4, mdb.length); @@ -27,6 +34,10 @@ function write_BrtBeginEsfmd(cnt, name) { write_XLWideString(name, o); return o.slice(0, o.l); } +function parse_BrtBeginEsmdb(data, length) { + data.l += 4; + return data.read_shift(4) != 0; +} function write_BrtBeginEsmdb(cnt, cm) { var o = new_buf(8); o.write_shift(4, cnt); @@ -34,16 +45,23 @@ function write_BrtBeginEsmdb(cnt, cm) { return o; } function parse_xlmeta_bin(data, name, _opts) { - var out = { Types: [] }; + var out = { Types: [], Cell: [], Value: [] }; var opts = _opts || {}; var state = []; var pass = false; + var esmdb = 0; recordhopper(data, function(val, R, RT) { switch (RT) { case 335: out.Types.push({ name: val.name }); break; case 51: + val.forEach(function(r) { + (esmdb == 1 ? out.Cell : out.Value).push({ type: out.Types[r[0] - 1].name, index: r[1] }); + }); + break; + case 337: + esmdb = val ? 1 : 0; break; case 35: state.push(RT); diff --git a/modules/51_xlsbmeta.ts b/modules/51_xlsbmeta.ts index ecea6f2..31a2c81 100644 --- a/modules/51_xlsbmeta.ts +++ b/modules/51_xlsbmeta.ts @@ -24,6 +24,12 @@ function write_BrtMdtinfo(data: BrtMdtinfo): RawData { /* [MS-XLSB] 2.4.697 BrtMdb */ type Mdir = [number, number]; // "t", "v" in XLSX parlance type BrtMdb = Mdir[]; +function parse_BrtMdb(data: ReadableData, length: number): BrtMdb { + var out: Mdir[] = []; + var cnt = data.read_shift(4); + while(cnt-- > 0) out.push([data.read_shift(4), data.read_shift(4)]); + return out; +} function write_BrtMdb(mdb: BrtMdb): RawData { var o = new_buf(4 + 8 * mdb.length); o.write_shift(4, mdb.length); @@ -43,6 +49,10 @@ function write_BrtBeginEsfmd(cnt: number, name: string): RawData { } /* [MS-XLSB] 2.4.73 BrtBeginEsmdb */ +function parse_BrtBeginEsmdb(data: ReadableData, length: number): boolean { + data.l += 4; + return data.read_shift(4) != 0; +} function write_BrtBeginEsmdb(cnt: number, cm: boolean): RawData { var o = new_buf(8); o.write_shift(4, cnt); @@ -52,18 +62,17 @@ function write_BrtBeginEsmdb(cnt: number, cm: boolean): RawData { /* [MS-XLSB] 2.1.7.34 Metadata */ function parse_xlmeta_bin(data, name: string, _opts?: ParseXLMetaOptions): XLMeta { - var out: XLMeta = { Types: [] }; + var out: XLMeta = { Types: [], Cell: [], Value: [] }; var opts = _opts || {}; var state: number[] = []; var pass = false; - + var esmdb: 0 | 1 = 0; recordhopper(data, (val, R, RT) => { switch(RT) { // case 0x014C: /* BrtBeginMetadata */ // case 0x014D: /* BrtEndMetadata */ // case 0x014E: /* BrtBeginEsmdtinfo */ // case 0x0150: /* BrtEndEsmdtinfo */ - // case 0x0151: /* BrtBeginEsmdb */ // case 0x0152: /* BrtEndEsmdb */ // case 0x0153: /* BrtBeginEsfmd */ // case 0x0154: /* BrtEndEsfmd */ @@ -75,10 +84,15 @@ function parse_xlmeta_bin(data, name: string, _opts?: ParseXLMetaOptions): XLMet // case 0x138B: /* BrtEndRichValueBlock */ case 0x014F: /* BrtMdtinfo */ - out.Types.push({name: (val as BrtMdtinfo).name}); - break; + out.Types.push({name: (val as BrtMdtinfo).name}); break; + case 0x0033: /* BrtMdb */ - break; + (val as BrtMdb).forEach(r => { + (esmdb == 1 ? out.Cell : out.Value).push({type: out.Types[r[0] - 1].name, index: r[1] }); + }); break; + + case 0x0151: /* BrtBeginEsmdb */ + esmdb = (val as boolean) ? 1 /* cell */ : 0 /* value */; break; case 0x0023: /* BrtFRTBegin */ state.push(RT); pass = true; break; diff --git a/modules/51_xlsxmeta.js b/modules/51_xlsxmeta.js index e34084e..30ad251 100644 --- a/modules/51_xlsxmeta.js +++ b/modules/51_xlsxmeta.js @@ -1,9 +1,9 @@ -RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; function parse_xlmeta_xml(data, name, opts) { - var out = { Types: [] }; + var out = { Types: [], Cell: [], Value: [] }; if (!data) return out; var pass = false; + var metatype = ""; data.replace(tagregex, function(x, idx) { var y = parsexmltag(x); switch (strip_ns(y[0])) { @@ -18,6 +18,8 @@ function parse_xlmeta_xml(data, name, opts) { case "": + break; case "": @@ -27,15 +29,24 @@ function parse_xlmeta_xml(data, name, opts) { case "": break; case "": break; case "": + metatype = ""; break; case "": + metatype = ""; break; case "": diff --git a/modules/51_xlsxmeta.ts b/modules/51_xlsxmeta.ts index fc99836..285189b 100644 --- a/modules/51_xlsxmeta.ts +++ b/modules/51_xlsxmeta.ts @@ -1,12 +1,11 @@ /// -RELS.XLMETA = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/sheetMetadata"; - /* 12.3.10 Metadata Part */ function parse_xlmeta_xml(data: string, name: string, opts?: ParseXLMetaOptions): XLMeta { - var out: XLMeta = { Types: [] }; + var out: XLMeta = { Types: [], Cell: [], Value: [] }; if(!data) return out; var pass = false; + var metatype: "cell" | "value" | "" = ""; data.replace(tagregex, (x: string, idx: number) => { var y: any = parsexmltag(x); @@ -23,6 +22,7 @@ function parse_xlmeta_xml(data: string, name: string, opts?: ParseXLMetaOptions) case '': break; /* 18.9.4 */ case '': break; /* 18.9.15 */ - case '': break; /* 18.9.3 */ - case '': break; + case '': metatype = ""; break; /* 18.9.17 */ - case '': break; + case '': metatype = ""; break; /* 18.2.10 extLst CT_ExtensionList ? */ case '': case '': case '': break; diff --git a/modules/83_numbers.js b/modules/83_numbers.js index 48a6637..3fbdc88 100644 --- a/modules/83_numbers.js +++ b/modules/83_numbers.js @@ -1,668 +1,632 @@ -var NUMBERS = !Object.defineProperty ? (void 0) :(function() { - var __defProp = Object.defineProperty; - var __getOwnPropDesc = Object.getOwnPropertyDescriptor; - var __getOwnPropNames = Object.getOwnPropertyNames; - var __hasOwnProp = Object.prototype.hasOwnProperty; - var __markAsModule = function(target) { - return __defProp(target, "__esModule", { value: true }); - }; - var __export = function(target, all) { - for (var name in all) - __defProp(target, name, { get: all[name], enumerable: true }); - }; - var __reExport = function(target, module, copyDefault, desc) { - if (module && typeof module === "object" || typeof module === "function") - for (var keys = __getOwnPropNames(module), i = 0, n = keys.length, key; i < n; i++) { - key = keys[i]; - if (!__hasOwnProp.call(target, key) && (copyDefault || key !== "default")) - __defProp(target, key, { get: function(k) { - return module[k]; - }.bind(null, key), enumerable: !(desc = __getOwnPropDesc(module, key)) || desc.enumerable }); - } - return target; - }; - var __toCommonJS = /* @__PURE__ */ function(cache) { - return function(module, temp) { - return cache && cache.get(module) || (temp = __reExport(__markAsModule({}), module, 1), cache && cache.set(module, temp), temp); - }; - }(typeof WeakMap !== "undefined" ? /* @__PURE__ */ new WeakMap() : 0); - - // 83_numbers.ts - var numbers_exports = {}; - __export(numbers_exports, { - parse_numbers: function() { - return numbers_default; - } +/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var u8_to_dataview = function(array) { + return new DataView(array.buffer, array.byteOffset, array.byteLength); +}; +var u8str = function(u8) { + return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8)); +}; +var u8concat = function(u8a) { + var len = u8a.reduce(function(acc, x) { + return acc + x.length; + }, 0); + var out = new Uint8Array(len); + var off = 0; + u8a.forEach(function(u8) { + out.set(u8, off); + off += u8.length; }); - - // src/util.ts - var u8_to_dataview = function(array) { - return new DataView(array.buffer, array.byteOffset, array.byteLength); - }; - var u8str = function(u8) { - return typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8)); - }; - var u8concat = function(u8a) { - var len = u8a.reduce(function(acc, x) { - return acc + x.length; - }, 0); - var out = new Uint8Array(len); - var off = 0; - u8a.forEach(function(u8) { - out.set(u8, off); - off += u8.length; - }); - return out; - }; - var popcnt = function(x) { - x -= x >> 1 & 1431655765; - x = (x & 858993459) + (x >> 2 & 858993459); - return (x + (x >> 4) & 252645135) * 16843009 >>> 24; - }; - var readDecimal128LE = function(buf, offset) { - var exp = (buf[offset + 15] & 127) << 7 | buf[offset + 14] >> 1; - var mantissa = buf[offset + 14] & 1; - for (var j = offset + 13; j >= offset; --j) - mantissa = mantissa * 256 + buf[j]; - return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176); - }; - - // src/proto.ts - function parse_varint49(buf, ptr) { - var l = ptr ? ptr[0] : 0; - var usz = buf[l] & 127; - varint: - if (buf[l++] >= 128) { - usz |= (buf[l] & 127) << 7; - if (buf[l++] < 128) - break varint; - usz |= (buf[l] & 127) << 14; - if (buf[l++] < 128) - break varint; - usz |= (buf[l] & 127) << 21; - if (buf[l++] < 128) - break varint; - usz += (buf[l] & 127) * Math.pow(2, 28); - ++l; - if (buf[l++] < 128) - break varint; - usz += (buf[l] & 127) * Math.pow(2, 35); - ++l; - if (buf[l++] < 128) - break varint; - usz += (buf[l] & 127) * Math.pow(2, 42); - ++l; - if (buf[l++] < 128) - break varint; - } - if (ptr) - ptr[0] = l; - return usz; - } - function varint_to_i32(buf) { - var l = 0, i32 = buf[l] & 127; - varint: - if (buf[l++] >= 128) { - i32 |= (buf[l] & 127) << 7; - if (buf[l++] < 128) - break varint; - i32 |= (buf[l] & 127) << 14; - if (buf[l++] < 128) - break varint; - i32 |= (buf[l] & 127) << 21; - if (buf[l++] < 128) - break varint; - i32 |= (buf[l] & 127) << 28; - } - return i32; - } - function parse_shallow(buf) { - var out = [], ptr = [0]; - while (ptr[0] < buf.length) { - var off = ptr[0]; - var num = parse_varint49(buf, ptr); - var type = num & 7; - num = Math.floor(num / 8); - var len = 0; - var res; - if (num == 0) - break; - switch (type) { - case 0: - { - var l = ptr[0]; - while (buf[ptr[0]++] >= 128) - ; - res = buf.slice(l, ptr[0]); - } - break; - case 5: - len = 4; - res = buf.slice(ptr[0], ptr[0] + len); - ptr[0] += len; - break; - case 1: - len = 8; - res = buf.slice(ptr[0], ptr[0] + len); - ptr[0] += len; - break; - case 2: - len = parse_varint49(buf, ptr); - res = buf.slice(ptr[0], ptr[0] + len); - ptr[0] += len; - break; - case 3: - case 4: - default: - throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off)); - } - var v = { offset: off, data: res, type: type }; - if (out[num] == null) - out[num] = [v]; - else - out[num].push(v); + return out; +}; +var popcnt = function(x) { + x -= x >> 1 & 1431655765; + x = (x & 858993459) + (x >> 2 & 858993459); + return (x + (x >> 4) & 252645135) * 16843009 >>> 24; +}; +var readDecimal128LE = function(buf, offset) { + var exp = (buf[offset + 15] & 127) << 7 | buf[offset + 14] >> 1; + var mantissa = buf[offset + 14] & 1; + for (var j = offset + 13; j >= offset; --j) + mantissa = mantissa * 256 + buf[j]; + return (buf[offset + 15] & 128 ? -mantissa : mantissa) * Math.pow(10, exp - 6176); +}; +function parse_varint49(buf, ptr) { + var l = ptr ? ptr[0] : 0; + var usz = buf[l] & 127; + varint: + if (buf[l++] >= 128) { + usz |= (buf[l] & 127) << 7; + if (buf[l++] < 128) + break varint; + usz |= (buf[l] & 127) << 14; + if (buf[l++] < 128) + break varint; + usz |= (buf[l] & 127) << 21; + if (buf[l++] < 128) + break varint; + usz += (buf[l] & 127) * Math.pow(2, 28); + ++l; + if (buf[l++] < 128) + break varint; + usz += (buf[l] & 127) * Math.pow(2, 35); + ++l; + if (buf[l++] < 128) + break varint; + usz += (buf[l] & 127) * Math.pow(2, 42); + ++l; + if (buf[l++] < 128) + break varint; } - return out; - } - function mappa(data, cb) { - if (!data) - return []; - return data.map(function(d) { - var _a; - try { - return cb(d.data); - } catch (e) { - var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/); - if (m) - e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset)); - throw e; - } - }); - } - - // src/frame.ts - function deframe(buf) { - var out = []; - var l = 0; - while (l < buf.length) { - var t = buf[l++]; - var len = buf[l] | buf[l + 1] << 8 | buf[l + 2] << 16; - l += 3; - out.push(parse_snappy_chunk(t, buf.slice(l, l + len))); - l += len; + if (ptr) + ptr[0] = l; + return usz; +} +function write_varint49(v) { + var usz = new Uint8Array(7); + usz[0] = v & 127; + var L = 1; + sz: + if (v > 127) { + usz[L - 1] |= 128; + usz[L] = v >> 7 & 127; + ++L; + if (v <= 16383) + break sz; + usz[L - 1] |= 128; + usz[L] = v >> 14 & 127; + ++L; + if (v <= 2097151) + break sz; + usz[L - 1] |= 128; + usz[L] = v >> 21 & 127; + ++L; + if (v <= 268435455) + break sz; + usz[L - 1] |= 128; + usz[L] = v / 256 >>> 21 & 127; + ++L; + if (v <= 34359738367) + break sz; + usz[L - 1] |= 128; + usz[L] = v / 65536 >>> 21 & 127; + ++L; + if (v <= 4398046511103) + break sz; + usz[L - 1] |= 128; + usz[L] = v / 16777216 >>> 21 & 127; + ++L; } - if (l !== buf.length) - throw new Error("data is not a valid framed stream!"); - return u8concat(out); - } - function parse_snappy_chunk(type, buf) { - if (type != 0) - throw new Error("Unexpected Snappy chunk type ".concat(type)); - var ptr = [0]; - var usz = parse_varint49(buf, ptr); - var chunks = []; - while (ptr[0] < buf.length) { - var tag = buf[ptr[0]] & 3; - if (tag == 0) { - var len = buf[ptr[0]++] >> 2; - if (len < 60) - ++len; - else { - var c = len - 59; - len = buf[ptr[0]]; - if (c > 1) - len |= buf[ptr[0] + 1] << 8; - if (c > 2) - len |= buf[ptr[0] + 2] << 16; - if (c > 3) - len |= buf[ptr[0] + 3] << 24; - len >>>= 0; - len++; - ptr[0] += c; + return usz.slice(0, L); +} +function varint_to_i32(buf) { + var l = 0, i32 = buf[l] & 127; + varint: + if (buf[l++] >= 128) { + i32 |= (buf[l] & 127) << 7; + if (buf[l++] < 128) + break varint; + i32 |= (buf[l] & 127) << 14; + if (buf[l++] < 128) + break varint; + i32 |= (buf[l] & 127) << 21; + if (buf[l++] < 128) + break varint; + i32 |= (buf[l] & 127) << 28; + } + return i32; +} +function parse_shallow(buf) { + var out = [], ptr = [0]; + while (ptr[0] < buf.length) { + var off = ptr[0]; + var num = parse_varint49(buf, ptr); + var type = num & 7; + num = Math.floor(num / 8); + var len = 0; + var res; + if (num == 0) + break; + switch (type) { + case 0: + { + var l = ptr[0]; + while (buf[ptr[0]++] >= 128) + ; + res = buf.slice(l, ptr[0]); } - chunks.push(buf.slice(ptr[0], ptr[0] + len)); + break; + case 5: + len = 4; + res = buf.slice(ptr[0], ptr[0] + len); + ptr[0] += len; + break; + case 1: + len = 8; + res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; - continue; - } else { - var offset = 0, length = 0; - if (tag == 1) { - length = (buf[ptr[0]] >> 2 & 7) + 4; - offset = (buf[ptr[0]++] & 224) << 3; - offset |= buf[ptr[0]++]; - } else { - length = (buf[ptr[0]++] >> 2) + 1; - if (tag == 2) { - offset = buf[ptr[0]] | buf[ptr[0] + 1] << 8; - ptr[0] += 2; - } else { - offset = (buf[ptr[0]] | buf[ptr[0] + 1] << 8 | buf[ptr[0] + 2] << 16 | buf[ptr[0] + 3] << 24) >>> 0; - ptr[0] += 4; - } - } - chunks = [u8concat(chunks)]; - if (offset == 0) - throw new Error("Invalid offset 0"); - if (offset > chunks[0].length) - throw new Error("Invalid offset beyond length"); - if (length >= offset) { - chunks.push(chunks[0].slice(-offset)); - length -= offset; - while (length >= chunks[chunks.length - 1].length) { - chunks.push(chunks[chunks.length - 1]); - length -= chunks[chunks.length - 1].length; - } - } - chunks.push(chunks[0].slice(-offset, -offset + length)); - } - } - var o = u8concat(chunks); - if (o.length != usz) - throw new Error("Unexpected length: ".concat(o.length, " != ").concat(usz)); - return o; - } - - // src/iwa.ts - function parse_iwa(buf) { - var out = [], ptr = [0]; - while (ptr[0] < buf.length) { - var len = parse_varint49(buf, ptr); - var ai = parse_shallow(buf.slice(ptr[0], ptr[0] + len)); - ptr[0] += len; - var res = { - id: varint_to_i32(ai[1][0].data), - messages: [] - }; - ai[2].forEach(function(b) { - var mi = parse_shallow(b.data); - var fl = varint_to_i32(mi[3][0].data); - res.messages.push({ - meta: mi, - data: buf.slice(ptr[0], ptr[0] + fl) - }); - ptr[0] += fl; - }); - out.push(res); - } - return out; - } - - // src/cell.ts - function parse_old_storage(buf, sst, rsst) { - var dv = u8_to_dataview(buf); - var ctype = buf[buf[0] == 4 ? 1 : 2]; - var flags = dv.getUint32(4, true); - var data_offset = 12 + popcnt(flags & 3470) * 4; - var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); - if (flags & 512) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; - } - data_offset += popcnt(flags & 12288) * 4; - if (flags & 16) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; - } - if (flags & 32) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; - } - if (flags & 64) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; - } - var ret; - switch (ctype) { - case 0: break; case 2: - ret = { t: "n", v: ieee }; + len = parse_varint49(buf, ptr); + res = buf.slice(ptr[0], ptr[0] + len); + ptr[0] += len; break; - case 3: - ret = { t: "s", v: sst[sidx] }; - break; - case 5: - ret = { t: "d", v: dt }; - break; - case 6: - ret = { t: "b", v: ieee > 0 }; - break; - case 7: - ret = { t: "n", v: ieee }; - break; - case 8: - ret = { t: "e", v: 0 }; - break; - case 9: - { - if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; - else if (sidx > -1) - ret = { t: "s", v: sst[sidx] }; - else if (!isNaN(ieee)) - ret = { t: "n", v: ieee }; - else - throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); - } - break; - default: - throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); - } - return ret; - } - function parse_storage(buf, sst, rsst) { - var dv = u8_to_dataview(buf); - var ctype = buf[1]; - var flags = dv.getUint32(8, true); - var data_offset = 12; - var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); - if (flags & 1) { - d128 = readDecimal128LE(buf, data_offset); - data_offset += 16; - } - if (flags & 2) { - ieee = dv.getFloat64(data_offset, true); - data_offset += 8; - } - if (flags & 4) { - dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); - data_offset += 8; - } - if (flags & 8) { - sidx = dv.getUint32(data_offset, true); - data_offset += 4; - } - if (flags & 16) { - ridx = dv.getUint32(data_offset, true); - data_offset += 4; - } - var ret; - switch (ctype) { - case 0: - break; - case 2: - ret = { t: "n", v: d128 }; - break; - case 3: - ret = { t: "s", v: sst[sidx] }; - break; - case 5: - ret = { t: "d", v: dt }; - break; - case 6: - ret = { t: "b", v: ieee > 0 }; - break; - case 7: - ret = { t: "n", v: ieee }; - break; - case 8: - ret = { t: "e", v: 0 }; - break; - case 9: - { - if (ridx > -1) - ret = { t: "s", v: rsst[ridx] }; - else - throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); - } - break; - case 10: - ret = { t: "n", v: d128 }; - break; - default: - throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); - } - return ret; - } - function parse(buf, sst, rsst) { - switch (buf[0]) { case 3: case 4: - return parse_old_storage(buf, sst, rsst); - case 5: - return parse_storage(buf, sst, rsst); default: - throw new Error("Unsupported payload version ".concat(buf[0])); + throw new Error("PB Type ".concat(type, " for Field ").concat(num, " at offset ").concat(off)); } + var v = { offset: off, data: res, type: type }; + if (out[num] == null) + out[num] = [v]; + else + out[num].push(v); } - - // src/numbers.ts - var encode_col = function(C) { - var s = ""; - for (++C; C; C = Math.floor((C - 1) / 26)) - s = String.fromCharCode((C - 1) % 26 + 65) + s; - return s; - }; - var encode_cell = function(c) { - return "".concat(encode_col(c.c)).concat(c.r + 1); - }; - var encode_range = function(r) { - return encode_cell(r.s) + ":" + encode_cell(r.e); - }; - var book_new = function() { - return { Sheets: {}, SheetNames: [] }; - }; - var book_append_sheet = function(wb, ws, name) { - var i = 1; - if (!name) - for (; i < 9999; ++i) { - if (wb.SheetNames.indexOf(name = "Sheet ".concat(i)) == -1) - break; - } - else if (wb.SheetNames.indexOf(name) > -1) - for (; i < 9999; ++i) { - if (wb.SheetNames.indexOf("".concat(name, "_").concat(i)) == -1) { - name = "".concat(name, "_").concat(i); - break; - } - } - wb.SheetNames.push(name); - wb.Sheets[name] = ws; - }; - function parse_numbers(cfb) { - var out = []; - cfb.FullPaths.forEach(function(p) { - if (p.match(/\.iwpv2/)) - throw new Error("Unsupported password protection"); + return out; +} +function write_shallow(proto) { + var out = []; + proto.forEach(function(field, idx) { + field.forEach(function(item) { + out.push(write_varint49(idx * 8 + item.type)); + out.push(item.data); }); - cfb.FileIndex.forEach(function(s) { - if (!s.name.match(/\.iwa$/)) - return; - var o; - try { - o = deframe(s.content); - } catch (e) { - return console.log("?? " + s.content.length + " " + (e.message || e)); - } - var packets; - try { - packets = parse_iwa(o); - } catch (e) { - return console.log("## " + (e.message || e)); - } - packets.forEach(function(packet) { - out[+packet.id] = packet.messages; - }); - }); - if (!out.length) - throw new Error("File has no messages"); - var docroot; - out.forEach(function(iwams) { - iwams.forEach(function(iwam) { - var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0; - if (mtype == 1) { - if (!docroot) - docroot = iwam; - else - throw new Error("Document has multiple roots"); - } - }); - }); - if (!docroot) - throw new Error("Cannot find Document root"); - return parse_docroot(out, docroot); - } - var numbers_default = parse_numbers; - function parse_Reference(buf) { - var pb = parse_shallow(buf); - return parse_varint49(pb[1][0].data); - } - function parse_TST_TableDataList(M, root) { - var pb = parse_shallow(root.data); - var type = varint_to_i32(pb[1][0].data); - var entries = pb[3]; - var data = []; - (entries || []).forEach(function(entry) { - var le = parse_shallow(entry.data); - var key = varint_to_i32(le[1][0].data) >>> 0; - switch (type) { - case 1: - data[key] = u8str(le[3][0].data); - break; - case 8: - { - var rt = M[parse_Reference(le[9][0].data)][0]; - var rtp = parse_shallow(rt.data); - var rtpref = M[parse_Reference(rtp[1][0].data)][0]; - var mtype = varint_to_i32(rtpref.meta[1][0].data); - if (mtype != 2001) - throw new Error("2000 unexpected reference to ".concat(mtype)); - var tswpsa = parse_shallow(rtpref.data); - data[key] = tswpsa[3].map(function(x) { - return u8str(x.data); - }).join(""); - } - break; - } - }); - return data; - } - function parse_TST_TileRowInfo(u8) { - var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; - var pb = parse_shallow(u8); - var R = varint_to_i32(pb[1][0].data) >>> 0; - var pre_bnc = (_b = (_a = pb[3]) == null ? void 0 : _a[0]) == null ? void 0 : _b.data; - var pre_bnc_offsets = ((_d = (_c = pb[4]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && u8_to_dataview(pb[4][0].data); - var storage = (_f = (_e = pb[6]) == null ? void 0 : _e[0]) == null ? void 0 : _f.data; - var storage_offsets = ((_h = (_g = pb[7]) == null ? void 0 : _g[0]) == null ? void 0 : _h.data) && u8_to_dataview(pb[7][0].data); - var wide_offsets = ((_j = (_i = pb[8]) == null ? void 0 : _i[0]) == null ? void 0 : _j.data) && varint_to_i32(pb[8][0].data) > 0 || false; - var width = wide_offsets ? 4 : 1; - var cells = []; - var off = 0; - for (var C = 0; C < pre_bnc_offsets.byteLength / 2; ++C) { - if (storage && storage_offsets) { - off = storage_offsets.getUint16(C * 2, true) * width; - if (off < storage.length) { - cells[C] = storage.subarray(off, storage_offsets.getUint16(C * 2 + 2, true) * width); - continue; - } - } - if (pre_bnc && pre_bnc_offsets) { - off = pre_bnc_offsets.getUint16(C * 2, true) * width; - if (off < pre_bnc.length) - cells[C] = pre_bnc.subarray(off, pre_bnc_offsets.getUint16(C * 2 + 2, true) * width); - } - } - return { R: R, cells: cells }; - } - function parse_TST_Tile(M, root) { - var pb = parse_shallow(root.data); - var ri = mappa(pb[5], parse_TST_TileRowInfo); - return ri.reduce(function(acc, x) { - if (!acc[x.R]) - acc[x.R] = []; - x.cells.forEach(function(cell, C) { - if (acc[x.R][C]) - throw new Error("Duplicate cell r=".concat(x.R, " c=").concat(C)); - acc[x.R][C] = cell; - }); - return acc; - }, []); - } - function parse_TST_TableModelArchive(M, root, ws) { + }); + return u8concat(out); +} +function mappa(data, cb) { + if (!data) + return []; + return data.map(function(d) { var _a; - var pb = parse_shallow(root.data); - var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } }; - range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; - if (range.e.r < 0) - throw new Error("Invalid row varint ".concat(pb[6][0].data)); - range.e.c = (varint_to_i32(pb[7][0].data) >>> 0) - 1; - if (range.e.c < 0) - throw new Error("Invalid col varint ".concat(pb[7][0].data)); - ws["!ref"] = encode_range(range); - { - var store = parse_shallow(pb[4][0].data); - var sst = parse_TST_TableDataList(M, M[parse_Reference(store[4][0].data)][0]); - var rsst = ((_a = store[17]) == null ? void 0 : _a[0]) ? parse_TST_TableDataList(M, M[parse_Reference(store[17][0].data)][0]) : []; - { - var tile = parse_shallow(store[3][0].data); - var tiles = []; - tile[1].forEach(function(t) { - var tl = parse_shallow(t.data); - var ref = M[parse_Reference(tl[2][0].data)][0]; - var mtype = varint_to_i32(ref.meta[1][0].data); - if (mtype != 6002) - throw new Error("6001 unexpected reference to ".concat(mtype)); - tiles.push({ id: varint_to_i32(tl[1][0].data), ref: parse_TST_Tile(M, ref) }); - }); - tiles.forEach(function(tile2) { - tile2.ref.forEach(function(row, R) { - row.forEach(function(buf, C) { - var addr = encode_cell({ r: R, c: C }); - var res = parse(buf, sst, rsst); - if (res) - ws[addr] = res; - }); - }); - }); - } + try { + return cb(d.data); + } catch (e) { + var m = (_a = e.message) == null ? void 0 : _a.match(/at offset (\d+)/); + if (m) + e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset)); + throw e; } - } - function parse_TST_TableInfoArchive(M, root) { - var pb = parse_shallow(root.data); - var out = { "!ref": "A1" }; - var tableref = M[parse_Reference(pb[2][0].data)]; - var mtype = varint_to_i32(tableref[0].meta[1][0].data); - if (mtype != 6001) - throw new Error("6000 unexpected reference to ".concat(mtype)); - parse_TST_TableModelArchive(M, tableref[0], out); - return out; - } - function parse_sheetroot(M, root) { - var _a; - var pb = parse_shallow(root.data); - var out = { - name: ((_a = pb[1]) == null ? void 0 : _a[0]) ? u8str(pb[1][0].data) : "", - sheets: [] + }); +} +function parse_iwa_file(buf) { + var out = [], ptr = [0]; + while (ptr[0] < buf.length) { + var len = parse_varint49(buf, ptr); + var ai = parse_shallow(buf.slice(ptr[0], ptr[0] + len)); + ptr[0] += len; + var res = { + id: varint_to_i32(ai[1][0].data), + messages: [] }; - var shapeoffs = mappa(pb[2], parse_Reference); - shapeoffs.forEach(function(off) { - M[off].forEach(function(m) { - var mtype = varint_to_i32(m.meta[1][0].data); - if (mtype == 6e3) - out.sheets.push(parse_TST_TableInfoArchive(M, m)); + ai[2].forEach(function(b) { + var mi = parse_shallow(b.data); + var fl = varint_to_i32(mi[3][0].data); + res.messages.push({ + meta: mi, + data: buf.slice(ptr[0], ptr[0] + fl) }); + ptr[0] += fl; }); - return out; + out.push(res); } - function parse_docroot(M, root) { - var out = book_new(); - var pb = parse_shallow(root.data); - var sheetoffs = mappa(pb[1], parse_Reference); - sheetoffs.forEach(function(off) { - M[off].forEach(function(m) { - var mtype = varint_to_i32(m.meta[1][0].data); - if (mtype == 2) { - var root2 = parse_sheetroot(M, m); - root2.sheets.forEach(function(sheet) { - book_append_sheet(out, sheet, root2.name); - }); + return out; +} +function parse_snappy_chunk(type, buf) { + if (type != 0) + throw new Error("Unexpected Snappy chunk type ".concat(type)); + var ptr = [0]; + var usz = parse_varint49(buf, ptr); + var chunks = []; + while (ptr[0] < buf.length) { + var tag = buf[ptr[0]] & 3; + if (tag == 0) { + var len = buf[ptr[0]++] >> 2; + if (len < 60) + ++len; + else { + var c = len - 59; + len = buf[ptr[0]]; + if (c > 1) + len |= buf[ptr[0] + 1] << 8; + if (c > 2) + len |= buf[ptr[0] + 2] << 16; + if (c > 3) + len |= buf[ptr[0] + 3] << 24; + len >>>= 0; + len++; + ptr[0] += c; + } + chunks.push(buf.slice(ptr[0], ptr[0] + len)); + ptr[0] += len; + continue; + } else { + var offset = 0, length = 0; + if (tag == 1) { + length = (buf[ptr[0]] >> 2 & 7) + 4; + offset = (buf[ptr[0]++] & 224) << 3; + offset |= buf[ptr[0]++]; + } else { + length = (buf[ptr[0]++] >> 2) + 1; + if (tag == 2) { + offset = buf[ptr[0]] | buf[ptr[0] + 1] << 8; + ptr[0] += 2; + } else { + offset = (buf[ptr[0]] | buf[ptr[0] + 1] << 8 | buf[ptr[0] + 2] << 16 | buf[ptr[0] + 3] << 24) >>> 0; + ptr[0] += 4; } - }); - }); - if (out.SheetNames.length == 0) - throw new Error("Empty NUMBERS file"); - return out; + } + chunks = [u8concat(chunks)]; + if (offset == 0) + throw new Error("Invalid offset 0"); + if (offset > chunks[0].length) + throw new Error("Invalid offset beyond length"); + if (length >= offset) { + chunks.push(chunks[0].slice(-offset)); + length -= offset; + while (length >= chunks[chunks.length - 1].length) { + chunks.push(chunks[chunks.length - 1]); + length -= chunks[chunks.length - 1].length; + } + } + chunks.push(chunks[0].slice(-offset, -offset + length)); + } } - return __toCommonJS(numbers_exports); -})(); -/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ + var o = u8concat(chunks); + if (o.length != usz) + throw new Error("Unexpected length: ".concat(o.length, " != ").concat(usz)); + return o; +} +function deframe(buf) { + var out = []; + var l = 0; + while (l < buf.length) { + var t = buf[l++]; + var len = buf[l] | buf[l + 1] << 8 | buf[l + 2] << 16; + l += 3; + out.push(parse_snappy_chunk(t, buf.slice(l, l + len))); + l += len; + } + if (l !== buf.length) + throw new Error("data is not a valid framed stream!"); + return u8concat(out); +} +function parse_old_storage(buf, sst, rsst) { + var dv = u8_to_dataview(buf); + var ctype = buf[buf[0] == 4 ? 1 : 2]; + var flags = dv.getUint32(4, true); + var data_offset = 12 + popcnt(flags & 3470) * 4; + var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); + if (flags & 512) { + ridx = dv.getUint32(data_offset, true); + data_offset += 4; + } + data_offset += popcnt(flags & 12288) * 4; + if (flags & 16) { + sidx = dv.getUint32(data_offset, true); + data_offset += 4; + } + if (flags & 32) { + ieee = dv.getFloat64(data_offset, true); + data_offset += 8; + } + if (flags & 64) { + dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); + data_offset += 8; + } + var ret; + switch (ctype) { + case 0: + break; + case 2: + ret = { t: "n", v: ieee }; + break; + case 3: + ret = { t: "s", v: sst[sidx] }; + break; + case 5: + ret = { t: "d", v: dt }; + break; + case 6: + ret = { t: "b", v: ieee > 0 }; + break; + case 7: + ret = { t: "n", v: ieee }; + break; + case 8: + ret = { t: "e", v: 0 }; + break; + case 9: + { + if (ridx > -1) + ret = { t: "s", v: rsst[ridx] }; + else if (sidx > -1) + ret = { t: "s", v: sst[sidx] }; + else if (!isNaN(ieee)) + ret = { t: "n", v: ieee }; + else + throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); + } + break; + default: + throw new Error("Unsupported cell type ".concat(buf.slice(0, 4))); + } + return ret; +} +function parse_storage(buf, sst, rsst) { + var dv = u8_to_dataview(buf); + var ctype = buf[1]; + var flags = dv.getUint32(8, true); + var data_offset = 12; + var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); + if (flags & 1) { + d128 = readDecimal128LE(buf, data_offset); + data_offset += 16; + } + if (flags & 2) { + ieee = dv.getFloat64(data_offset, true); + data_offset += 8; + } + if (flags & 4) { + dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1e3); + data_offset += 8; + } + if (flags & 8) { + sidx = dv.getUint32(data_offset, true); + data_offset += 4; + } + if (flags & 16) { + ridx = dv.getUint32(data_offset, true); + data_offset += 4; + } + var ret; + switch (ctype) { + case 0: + break; + case 2: + ret = { t: "n", v: d128 }; + break; + case 3: + ret = { t: "s", v: sst[sidx] }; + break; + case 5: + ret = { t: "d", v: dt }; + break; + case 6: + ret = { t: "b", v: ieee > 0 }; + break; + case 7: + ret = { t: "n", v: ieee }; + break; + case 8: + ret = { t: "e", v: 0 }; + break; + case 9: + { + if (ridx > -1) + ret = { t: "s", v: rsst[ridx] }; + else + throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); + } + break; + case 10: + ret = { t: "n", v: d128 }; + break; + default: + throw new Error("Unsupported cell type ".concat(ctype, " : ").concat(flags & 31, " : ").concat(buf.slice(0, 4))); + } + return ret; +} +function parse_cell_storage(buf, sst, rsst) { + switch (buf[0]) { + case 3: + case 4: + return parse_old_storage(buf, sst, rsst); + case 5: + return parse_storage(buf, sst, rsst); + default: + throw new Error("Unsupported payload version ".concat(buf[0])); + } +} +function parse_TSP_Reference(buf) { + var pb = parse_shallow(buf); + return parse_varint49(pb[1][0].data); +} +function parse_TST_TableDataList(M, root) { + var pb = parse_shallow(root.data); + var type = varint_to_i32(pb[1][0].data); + var entries = pb[3]; + var data = []; + (entries || []).forEach(function(entry) { + var le = parse_shallow(entry.data); + var key = varint_to_i32(le[1][0].data) >>> 0; + switch (type) { + case 1: + data[key] = u8str(le[3][0].data); + break; + case 8: + { + var rt = M[parse_TSP_Reference(le[9][0].data)][0]; + var rtp = parse_shallow(rt.data); + var rtpref = M[parse_TSP_Reference(rtp[1][0].data)][0]; + var mtype = varint_to_i32(rtpref.meta[1][0].data); + if (mtype != 2001) + throw new Error("2000 unexpected reference to ".concat(mtype)); + var tswpsa = parse_shallow(rtpref.data); + data[key] = tswpsa[3].map(function(x) { + return u8str(x.data); + }).join(""); + } + break; + } + }); + return data; +} +function parse_TST_TileRowInfo(u8) { + var _a, _b, _c, _d, _e, _f, _g, _h, _i, _j; + var pb = parse_shallow(u8); + var R = varint_to_i32(pb[1][0].data) >>> 0; + var pre_bnc = (_b = (_a = pb[3]) == null ? void 0 : _a[0]) == null ? void 0 : _b.data; + var pre_bnc_offsets = ((_d = (_c = pb[4]) == null ? void 0 : _c[0]) == null ? void 0 : _d.data) && u8_to_dataview(pb[4][0].data); + var storage = (_f = (_e = pb[6]) == null ? void 0 : _e[0]) == null ? void 0 : _f.data; + var storage_offsets = ((_h = (_g = pb[7]) == null ? void 0 : _g[0]) == null ? void 0 : _h.data) && u8_to_dataview(pb[7][0].data); + var wide_offsets = ((_j = (_i = pb[8]) == null ? void 0 : _i[0]) == null ? void 0 : _j.data) && varint_to_i32(pb[8][0].data) > 0 || false; + var width = wide_offsets ? 4 : 1; + var cells = []; + var off = 0; + for (var C = 0; C < pre_bnc_offsets.byteLength / 2; ++C) { + if (storage && storage_offsets) { + off = storage_offsets.getUint16(C * 2, true) * width; + if (off < storage.length) { + cells[C] = storage.subarray(off, storage_offsets.getUint16(C * 2 + 2, true) * width); + continue; + } + } + if (pre_bnc && pre_bnc_offsets) { + off = pre_bnc_offsets.getUint16(C * 2, true) * width; + if (off < pre_bnc.length) + cells[C] = pre_bnc.subarray(off, pre_bnc_offsets.getUint16(C * 2 + 2, true) * width); + } + } + return { R: R, cells: cells }; +} +function parse_TST_Tile(M, root) { + var pb = parse_shallow(root.data); + var ri = mappa(pb[5], parse_TST_TileRowInfo); + return ri.reduce(function(acc, x) { + if (!acc[x.R]) + acc[x.R] = []; + x.cells.forEach(function(cell, C) { + if (acc[x.R][C]) + throw new Error("Duplicate cell r=".concat(x.R, " c=").concat(C)); + acc[x.R][C] = cell; + }); + return acc; + }, []); +} +function parse_TST_TableModelArchive(M, root, ws) { + var _a; + var pb = parse_shallow(root.data); + var range = { s: { r: 0, c: 0 }, e: { r: 0, c: 0 } }; + range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; + if (range.e.r < 0) + throw new Error("Invalid row varint ".concat(pb[6][0].data)); + range.e.c = (varint_to_i32(pb[7][0].data) >>> 0) - 1; + if (range.e.c < 0) + throw new Error("Invalid col varint ".concat(pb[7][0].data)); + ws["!ref"] = encode_range(range); + { + var store = parse_shallow(pb[4][0].data); + var sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); + var rsst = ((_a = store[17]) == null ? void 0 : _a[0]) ? parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]) : []; + { + var tile = parse_shallow(store[3][0].data); + var tiles = []; + tile[1].forEach(function(t) { + var tl = parse_shallow(t.data); + var ref = M[parse_TSP_Reference(tl[2][0].data)][0]; + var mtype = varint_to_i32(ref.meta[1][0].data); + if (mtype != 6002) + throw new Error("6001 unexpected reference to ".concat(mtype)); + tiles.push({ id: varint_to_i32(tl[1][0].data), ref: parse_TST_Tile(M, ref) }); + }); + tiles.forEach(function(tile2) { + tile2.ref.forEach(function(row, R) { + row.forEach(function(buf, C) { + var addr = encode_cell({ r: R, c: C }); + var res = parse_cell_storage(buf, sst, rsst); + if (res) + ws[addr] = res; + }); + }); + }); + } + } +} +function parse_TST_TableInfoArchive(M, root) { + var pb = parse_shallow(root.data); + var out = { "!ref": "A1" }; + var tableref = M[parse_TSP_Reference(pb[2][0].data)]; + var mtype = varint_to_i32(tableref[0].meta[1][0].data); + if (mtype != 6001) + throw new Error("6000 unexpected reference to ".concat(mtype)); + parse_TST_TableModelArchive(M, tableref[0], out); + return out; +} +function parse_TN_SheetArchive(M, root) { + var _a; + var pb = parse_shallow(root.data); + var out = { + name: ((_a = pb[1]) == null ? void 0 : _a[0]) ? u8str(pb[1][0].data) : "", + sheets: [] + }; + var shapeoffs = mappa(pb[2], parse_TSP_Reference); + shapeoffs.forEach(function(off) { + M[off].forEach(function(m) { + var mtype = varint_to_i32(m.meta[1][0].data); + if (mtype == 6e3) + out.sheets.push(parse_TST_TableInfoArchive(M, m)); + }); + }); + return out; +} +function parse_TN_DocumentArchive(M, root) { + var out = book_new(); + var pb = parse_shallow(root.data); + var sheetoffs = mappa(pb[1], parse_TSP_Reference); + sheetoffs.forEach(function(off) { + M[off].forEach(function(m) { + var mtype = varint_to_i32(m.meta[1][0].data); + if (mtype == 2) { + var root2 = parse_TN_SheetArchive(M, m); + root2.sheets.forEach(function(sheet) { + book_append_sheet(out, sheet, root2.name); + }); + } + }); + }); + if (out.SheetNames.length == 0) + throw new Error("Empty NUMBERS file"); + return out; +} +function parse_numbers_iwa(cfb) { + var out = []; + cfb.FullPaths.forEach(function(p) { + if (p.match(/\.iwpv2/)) + throw new Error("Unsupported password protection"); + }); + cfb.FileIndex.forEach(function(s) { + if (!s.name.match(/\.iwa$/)) + return; + var o; + try { + o = deframe(s.content); + } catch (e) { + return console.log("?? " + s.content.length + " " + (e.message || e)); + } + var packets; + try { + packets = parse_iwa_file(o); + } catch (e) { + return console.log("## " + (e.message || e)); + } + packets.forEach(function(packet) { + out[+packet.id] = packet.messages; + }); + }); + if (!out.length) + throw new Error("File has no messages"); + var docroot; + out.forEach(function(iwams) { + iwams.forEach(function(iwam) { + var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0; + if (mtype == 1) { + if (!docroot) + docroot = iwam; + else + throw new Error("Document has multiple roots"); + } + }); + }); + if (!docroot) + throw new Error("Cannot find Document root"); + return parse_TN_DocumentArchive(out, docroot); +} diff --git a/modules/83_numbers.ts b/modules/83_numbers.ts index 27dcbd3..876ae2e 100644 --- a/modules/83_numbers.ts +++ b/modules/83_numbers.ts @@ -1,4 +1,531 @@ /*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ -import parse_numbers from './src/numbers'; +/// -export { parse_numbers }; \ No newline at end of file +import { CFB$Container } from 'cfb'; +import { WorkBook, WorkSheet, Range, CellObject } from '../'; +import type { utils } from "../"; + +declare var encode_cell: typeof utils.encode_cell; +declare var encode_range: typeof utils.encode_range; +declare var book_new: typeof utils.book_new; +declare var book_append_sheet: typeof utils.book_append_sheet; + + +var u8_to_dataview = (array: Uint8Array): DataView => new DataView(array.buffer, array.byteOffset, array.byteLength); + +var u8str = (u8: Uint8Array): string => /* Buffer.isBuffer(u8) ? u8.toString() :*/ typeof TextDecoder != "undefined" ? new TextDecoder().decode(u8) : utf8read(a2s(u8)); + +var u8concat = (u8a: Uint8Array[]): Uint8Array => { + var len = u8a.reduce((acc: number, x: Uint8Array) => acc + x.length, 0); + var out = new Uint8Array(len); + var off = 0; + u8a.forEach(u8 => { out.set(u8, off); off += u8.length; }); + return out; +}; + +/* Hopefully one day this will be added to the language */ +var popcnt = (x: number): number => { + x -= ((x >> 1) & 0x55555555); + x = (x & 0x33333333) + ((x >> 2) & 0x33333333); + return (((x + (x >> 4)) & 0x0F0F0F0F) * 0x01010101) >>> 24; +}; + +/* Used in the modern cell storage */ +var readDecimal128LE = (buf: Uint8Array, offset: number): number => { + var exp = ((buf[offset + 15] & 0x7F) << 7) | (buf[offset + 14] >> 1); + var mantissa = buf[offset + 14] & 1; + for(var j = offset + 13; j >= offset; --j) mantissa = mantissa * 256 + buf[j]; + return ((buf[offset+15] & 0x80) ? -mantissa : mantissa) * Math.pow(10, exp - 0x1820); +}; + +type Ptr = [number]; + +/** Parse an integer from the varint that can be exactly stored in a double */ +function parse_varint49(buf: Uint8Array, ptr?: Ptr): number { + var l = ptr ? ptr[0] : 0; + var usz = buf[l] & 0x7F; + varint: if(buf[l++] >= 0x80) { + usz |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint; + usz |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint; + usz |= (buf[l] & 0x7F) << 21; if(buf[l++] < 0x80) break varint; + usz += (buf[l] & 0x7F) * Math.pow(2, 28); ++l; if(buf[l++] < 0x80) break varint; + usz += (buf[l] & 0x7F) * Math.pow(2, 35); ++l; if(buf[l++] < 0x80) break varint; + usz += (buf[l] & 0x7F) * Math.pow(2, 42); ++l; if(buf[l++] < 0x80) break varint; + } + if(ptr) ptr[0] = l; + return usz; +} +function write_varint49(v: number): Uint8Array { + var usz = new Uint8Array(7); + usz[0] = (v & 0x7F); + var L = 1; + sz: if(v > 0x7F) { + usz[L-1] |= 0x80; usz[L] = (v >> 7) & 0x7F; ++L; + if(v <= 0x3FFF) break sz; + usz[L-1] |= 0x80; usz[L] = (v >> 14) & 0x7F; ++L; + if(v <= 0x1FFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = (v >> 21) & 0x7F; ++L; + if(v <= 0xFFFFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = ((v/0x100) >>> 21) & 0x7F; ++L; + if(v <= 0x7FFFFFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = ((v/0x10000) >>> 21) & 0x7F; ++L; + if(v <= 0x3FFFFFFFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = ((v/0x1000000) >>> 21) & 0x7F; ++L; + } + return usz.slice(0, L); +} + +/** Parse a 32-bit signed integer from the raw varint */ +function varint_to_i32(buf: Uint8Array): number { + var l = 0, i32 = buf[l] & 0x7F; + varint: if(buf[l++] >= 0x80) { + i32 |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint; + i32 |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint; + i32 |= (buf[l] & 0x7F) << 21; if(buf[l++] < 0x80) break varint; + i32 |= (buf[l] & 0x7F) << 28; + } + return i32; +} + +interface ProtoItem { + offset?: number; + data: Uint8Array; + type: number; +} +type ProtoField = Array +type ProtoMessage = Array; +/** Shallow parse of a message */ +function parse_shallow(buf: Uint8Array): ProtoMessage { + var out: ProtoMessage = [], ptr: Ptr = [0]; + while(ptr[0] < buf.length) { + var off = ptr[0]; + var num = parse_varint49(buf, ptr); + var type = num & 0x07; num = Math.floor(num / 8); + var len = 0; + var res: Uint8Array; + if(num == 0) break; + switch(type) { + case 0: { + var l = ptr[0]; + while(buf[ptr[0]++] >= 0x80); + res = buf.slice(l, ptr[0]); + } break; + case 5: len = 4; res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break; + case 1: len = 8; res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break; + case 2: len = parse_varint49(buf, ptr); res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break; + case 3: // Start group + case 4: // End group + default: throw new Error(`PB Type ${type} for Field ${num} at offset ${off}`); + } + var v: ProtoItem = { offset: off, data: res, type }; + if(out[num] == null) out[num] = [v]; + else out[num].push(v); + } + return out; +} +/** Serialize a shallow parse */ +function write_shallow(proto: ProtoMessage): Uint8Array { + var out: Uint8Array[] = []; + proto.forEach((field, idx) => { + field.forEach(item => { + out.push(write_varint49(idx * 8 + item.type)); + out.push(item.data); + }); + }); + return u8concat(out); +} + +function mappa(data: ProtoField, cb:(Uint8Array) => U): U[] { + if(!data) return []; + return data.map((d) => { try { + return cb(d.data); + } catch(e) { + var m = e.message?.match(/at offset (\d+)/); + if(m) e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset)); + throw e; + }}); +} + + +interface IWAMessage { + /** Metadata in .TSP.MessageInfo */ + meta: ProtoMessage; + data: Uint8Array; +} +interface IWAArchiveInfo { + id?: number; + messages?: IWAMessage[]; +} + +function parse_iwa_file(buf: Uint8Array): IWAArchiveInfo[] { + var out: IWAArchiveInfo[] = [], ptr: Ptr = [0]; + while(ptr[0] < buf.length) { + /* .TSP.ArchiveInfo */ + var len = parse_varint49(buf, ptr); + var ai = parse_shallow(buf.slice(ptr[0], ptr[0] + len)); + ptr[0] += len; + + var res: IWAArchiveInfo = { + id: varint_to_i32(ai[1][0].data), + messages: [] + }; + ai[2].forEach(b => { + var mi = parse_shallow(b.data); + var fl = varint_to_i32(mi[3][0].data); + res.messages.push({ + meta: mi, + data: buf.slice(ptr[0], ptr[0] + fl) + }); + ptr[0] += fl; + }); + out.push(res); + } + return out; +} + +function parse_snappy_chunk(type: number, buf: Uint8Array): Uint8Array { + if(type != 0) throw new Error(`Unexpected Snappy chunk type ${type}`); + var ptr: Ptr = [0]; + + var usz = parse_varint49(buf, ptr); + var chunks = []; + while(ptr[0] < buf.length) { + var tag = buf[ptr[0]] & 0x3; + if(tag == 0) { + var len = buf[ptr[0]++] >> 2; + if(len < 60) ++len; + else { + var c = len - 59; + len = buf[ptr[0]]; + if(c > 1) len |= (buf[ptr[0]+1]<<8); + if(c > 2) len |= (buf[ptr[0]+2]<<16); + if(c > 3) len |= (buf[ptr[0]+3]<<24); + len >>>=0; len++; + ptr[0] += c; + } + chunks.push(buf.slice(ptr[0], ptr[0] + len)); ptr[0] += len; continue; + } else { + var offset = 0, length = 0; + if(tag == 1) { + length = ((buf[ptr[0]] >> 2) & 0x7) + 4; + offset = (buf[ptr[0]++] & 0xE0) << 3; + offset |= buf[ptr[0]++]; + } else { + length = (buf[ptr[0]++] >> 2) + 1; + if(tag == 2) { offset = buf[ptr[0]] | (buf[ptr[0]+1]<<8); ptr[0] += 2; } + else { offset = (buf[ptr[0]] | (buf[ptr[0]+1]<<8) | (buf[ptr[0]+2]<<16) | (buf[ptr[0]+3]<<24))>>>0; ptr[0] += 4; } + } + chunks = [u8concat(chunks)]; + if(offset == 0) throw new Error("Invalid offset 0"); + if(offset > chunks[0].length) throw new Error("Invalid offset beyond length"); + if(length >= offset) { + chunks.push(chunks[0].slice(-offset)); length -= offset; + while(length >= chunks[chunks.length-1].length) { + chunks.push(chunks[chunks.length - 1]); + length -= chunks[chunks.length - 1].length; + } + } + chunks.push(chunks[0].slice(-offset, -offset + length)); + } + } + var o = u8concat(chunks); + if(o.length != usz) throw new Error(`Unexpected length: ${o.length} != ${usz}`); + return o; +} + +function deframe(buf: Uint8Array): Uint8Array { + var out = []; + var l = 0; + while(l < buf.length) { + var t = buf[l++]; + var len = buf[l] | (buf[l+1]<<8) | (buf[l+2] << 16); l += 3; + out.push(parse_snappy_chunk(t, buf.slice(l, l + len))); + l += len; + } + if(l !== buf.length) throw new Error("data is not a valid framed stream!"); + return u8concat(out); +} + +function parse_old_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject { + var dv = u8_to_dataview(buf); + var ctype = buf[buf[0] == 4 ? 1 : 2]; + + /* TODO: find the correct field position of number formats, formulae, etc */ + var flags = dv.getUint32(4, true); + var data_offset = 12 + popcnt(flags & 0x0D8E) * 4; + + var ridx = -1, sidx = -1, ieee = NaN, dt = new Date(2001, 0, 1); + if(flags & 0x0200) { ridx = dv.getUint32(data_offset, true); data_offset += 4; } + data_offset += popcnt(flags & 0x3000) * 4; + if(flags & 0x0010) { sidx = dv.getUint32(data_offset, true); data_offset += 4; } + if(flags & 0x0020) { ieee = dv.getFloat64(data_offset, true); data_offset += 8; } + if(flags & 0x0040) { dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1000); data_offset += 8; } + + var ret: CellObject; + switch(ctype) { + case 0: break; // return { t: "z" }; // blank? + case 2: ret = { t: "n", v: ieee }; break; // number + case 3: ret = { t: "s", v: sst[sidx] }; break; // string + case 5: ret = { t: "d", v: dt }; break; // date-time + case 6: ret = { t: "b", v: ieee > 0 }; break; // boolean + case 7: ret = { t: "n", v: ieee }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value + case 8: ret = { t: "e", v: 0}; break; // "formula error" TODO: enumerate and map errors to csf equivalents + case 9: { // "automatic"? + if(ridx > -1) ret = { t: "s", v: rsst[ridx] }; + else if(sidx > -1) ret = { t: "s", v: sst[sidx] }; + else if(!isNaN(ieee)) ret = { t: "n", v: ieee }; + else throw new Error(`Unsupported cell type ${buf.slice(0,4)}`); + } break; + default: throw new Error(`Unsupported cell type ${buf.slice(0,4)}`); + } + /* TODO: Some fields appear after the cell data */ + + return ret; +} + +function parse_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject { + var dv = u8_to_dataview(buf); + var ctype = buf[1]; + + /* TODO: find the correct field position of number formats, formulae, etc */ + var flags = dv.getUint32(8, true); + var data_offset = 12; + + var ridx = -1, sidx = -1, d128 = NaN, ieee = NaN, dt = new Date(2001, 0, 1); + + if(flags & 0x0001) { d128 = readDecimal128LE(buf, data_offset); data_offset += 16; } + if(flags & 0x0002) { ieee = dv.getFloat64(data_offset, true); data_offset += 8; } + if(flags & 0x0004) { dt.setTime(dt.getTime() + dv.getFloat64(data_offset, true) * 1000); data_offset += 8; } + if(flags & 0x0008) { sidx = dv.getUint32(data_offset, true); data_offset += 4; } + if(flags & 0x0010) { ridx = dv.getUint32(data_offset, true); data_offset += 4; } + + var ret: CellObject; + switch(ctype) { + case 0: break; // return { t: "z" }; // blank? + case 2: ret = { t: "n", v: d128 }; break; // number + case 3: ret = { t: "s", v: sst[sidx] }; break; // string + case 5: ret = { t: "d", v: dt }; break; // date-time + case 6: ret = { t: "b", v: ieee > 0 }; break; // boolean + case 7: ret = { t: "n", v: ieee }; break; // duration in seconds TODO: emit [hh]:[mm] style format with adjusted value + case 8: ret = { t: "e", v: 0}; break; // "formula error" TODO: enumerate and map errors to csf equivalents + case 9: { // "automatic"? + if(ridx > -1) ret = { t: "s", v: rsst[ridx] }; + else throw new Error(`Unsupported cell type ${ctype} : ${flags & 0x1F} : ${buf.slice(0,4)}`); + } break; + case 10: ret = { t: "n", v: d128 }; break; // currency + default: throw new Error(`Unsupported cell type ${ctype} : ${flags & 0x1F} : ${buf.slice(0,4)}`); + } + /* TODO: All styling fields appear after the cell data */ + + return ret; +} + +function parse_cell_storage(buf: Uint8Array, sst: string[], rsst: string[]): CellObject { + switch(buf[0]) { + /* TODO: 0-2? */ + case 3: case 4: return parse_old_storage(buf, sst, rsst); + case 5: return parse_storage(buf, sst, rsst); + default: throw new Error(`Unsupported payload version ${buf[0]}`); + } +} + +// .TSP.Reference +function parse_TSP_Reference(buf: Uint8Array): number { + var pb = parse_shallow(buf); + return parse_varint49(pb[1][0].data); +} + +// .TST.TableDataList +function parse_TST_TableDataList(M: IWAMessage[][], root: IWAMessage): string[] { + var pb = parse_shallow(root.data); + // .TST.TableDataList.ListType + var type = varint_to_i32(pb[1][0].data); + + var entries = pb[3]; + var data = []; + (entries||[]).forEach(entry => { + // .TST.TableDataList.ListEntry + var le = parse_shallow(entry.data); + var key = varint_to_i32(le[1][0].data)>>>0; + switch(type) { + case 1: data[key] = u8str(le[3][0].data); break; + case 8: { + // .TSP.RichTextPayloadArchive + var rt = M[parse_TSP_Reference(le[9][0].data)][0]; + var rtp = parse_shallow(rt.data); + + // .TSWP.StorageArchive + var rtpref = M[parse_TSP_Reference(rtp[1][0].data)][0]; + var mtype = varint_to_i32(rtpref.meta[1][0].data); + if(mtype != 2001) throw new Error(`2000 unexpected reference to ${mtype}`); + var tswpsa = parse_shallow(rtpref.data); + + data[key] = tswpsa[3].map(x => u8str(x.data)).join(""); + } break; + } + }); + return data; +} + +interface TileRowInfo { + R: number; + cells?: Uint8Array[]; +} +// .TSP.TileRowInfo +function parse_TST_TileRowInfo(u8: Uint8Array): TileRowInfo { + var pb = parse_shallow(u8); + var R = varint_to_i32(pb[1][0].data) >>> 0; + var pre_bnc = pb[3]?.[0]?.data; + var pre_bnc_offsets = pb[4]?.[0]?.data && u8_to_dataview(pb[4][0].data); + var storage = pb[6]?.[0]?.data; + var storage_offsets = pb[7]?.[0]?.data && u8_to_dataview(pb[7][0].data); + var wide_offsets = pb[8]?.[0]?.data && varint_to_i32(pb[8][0].data) > 0 || false; + var width = wide_offsets ? 4 : 1; + var cells = []; + var off = 0; + for(var C = 0; C < pre_bnc_offsets.byteLength/2; ++C) { + /* prefer storage if it is present, otherwise fall back on pre_bnc */ + if(storage && storage_offsets) { + off = storage_offsets.getUint16(C*2, true) * width; + if(off < storage.length) { cells[C] = storage.subarray(off, storage_offsets.getUint16(C*2+2, true) * width); continue; } + } + if(pre_bnc && pre_bnc_offsets) { + off = pre_bnc_offsets.getUint16(C*2, true) * width; + if(off < pre_bnc.length) cells[C] = pre_bnc.subarray(off, pre_bnc_offsets.getUint16(C*2+2, true) * width); + } + } + return { R, cells }; +} + +// .TST.Tile +function parse_TST_Tile(M: IWAMessage[][], root: IWAMessage): Uint8Array[][] { + var pb = parse_shallow(root.data); + var ri = mappa(pb[5], parse_TST_TileRowInfo); + return ri.reduce((acc, x) => { + if(!acc[x.R]) acc[x.R] = []; + x.cells.forEach((cell, C) => { + if(acc[x.R][C]) throw new Error(`Duplicate cell r=${x.R} c=${C}`); + acc[x.R][C] = cell; + }); + return acc; + }, [] as Uint8Array[][]); +} + +// .TST.TableModelArchive +function parse_TST_TableModelArchive(M: IWAMessage[][], root: IWAMessage, ws: WorkSheet) { + var pb = parse_shallow(root.data); + var range: Range = { s: {r:0, c:0}, e: {r:0, c:0} }; + range.e.r = (varint_to_i32(pb[6][0].data) >>> 0) - 1; + if(range.e.r < 0) throw new Error(`Invalid row varint ${pb[6][0].data}`); + range.e.c = (varint_to_i32(pb[7][0].data) >>> 0) - 1; + if(range.e.c < 0) throw new Error(`Invalid col varint ${pb[7][0].data}`); + ws["!ref"] = encode_range(range); + + { + // .TST.DataStore + var store = parse_shallow(pb[4][0].data); + + var sst = parse_TST_TableDataList(M, M[parse_TSP_Reference(store[4][0].data)][0]); + var rsst: string[] = store[17]?.[0] ? parse_TST_TableDataList(M, M[parse_TSP_Reference(store[17][0].data)][0]) : []; + { + // .TST.TileStorage + var tile = parse_shallow(store[3][0].data); + var tiles: Array<{id: number, ref: Uint8Array[][]}> = []; + tile[1].forEach(t => { + var tl = (parse_shallow(t.data)); + var ref = M[parse_TSP_Reference(tl[2][0].data)][0]; + var mtype = varint_to_i32(ref.meta[1][0].data); + if(mtype != 6002) throw new Error(`6001 unexpected reference to ${mtype}`); + tiles.push({id: varint_to_i32(tl[1][0].data), ref: parse_TST_Tile(M, ref) }); + }); + tiles.forEach((tile) => { + tile.ref.forEach((row, R) => { + row.forEach((buf, C) => { + var addr = encode_cell({r:R,c:C}); + var res = parse_cell_storage(buf, sst, rsst); + if(res) ws[addr] = res; + }); + }); + }); + } + } +} + +// .TST.TableInfoArchive +function parse_TST_TableInfoArchive(M: IWAMessage[][], root: IWAMessage): WorkSheet { + var pb = parse_shallow(root.data); + var out: WorkSheet = { "!ref": "A1" }; + var tableref = M[parse_TSP_Reference(pb[2][0].data)]; + var mtype = varint_to_i32(tableref[0].meta[1][0].data); + if(mtype != 6001) throw new Error(`6000 unexpected reference to ${mtype}`); + parse_TST_TableModelArchive(M, tableref[0], out); + return out; +} + +// .TN.SheetArchive +interface NSheet { + name: string; + sheets: WorkSheet[]; +} +function parse_TN_SheetArchive(M: IWAMessage[][], root: IWAMessage): NSheet { + var pb = parse_shallow(root.data); + var out: NSheet = { + name: (pb[1]?.[0] ? u8str(pb[1][0].data) : ""), + sheets: [] + }; + var shapeoffs = mappa(pb[2], parse_TSP_Reference); + shapeoffs.forEach((off) => { + M[off].forEach((m: IWAMessage) => { + var mtype = varint_to_i32(m.meta[1][0].data); + if(mtype == 6000) out.sheets.push(parse_TST_TableInfoArchive(M, m)); + }); + }); + return out; +} + +// .TN.DocumentArchive +function parse_TN_DocumentArchive(M: IWAMessage[][], root: IWAMessage): WorkBook { + var out = book_new(); + var pb = parse_shallow(root.data); + var sheetoffs = mappa(pb[1], parse_TSP_Reference); + sheetoffs.forEach((off) => { + M[off].forEach((m: IWAMessage) => { + var mtype = varint_to_i32(m.meta[1][0].data); + if(mtype == 2) { + var root = parse_TN_SheetArchive(M, m); + root.sheets.forEach(sheet => { book_append_sheet(out, sheet, root.name); }); + } + }); + }); + if(out.SheetNames.length == 0) throw new Error("Empty NUMBERS file"); + return out; +} + +/* exported parse_numbers_iwa */ +function parse_numbers_iwa(cfb: CFB$Container): WorkBook { + var out: IWAMessage[][] = []; + cfb.FullPaths.forEach(p => { if(p.match(/\.iwpv2/)) throw new Error(`Unsupported password protection`); }); + /* collect entire message space */ + cfb.FileIndex.forEach(s => { + if(!s.name.match(/\.iwa$/)) return; + var o: Uint8Array; + try { o = deframe(s.content as Uint8Array); } catch(e) { return console.log("?? " + s.content.length + " " + (e.message || e)); } + var packets: IWAArchiveInfo[]; + try { packets = parse_iwa_file(o); } catch(e) { return console.log("## " + (e.message || e)); } + packets.forEach(packet => {out[+packet.id] = packet.messages;}); + }); + if(!out.length) throw new Error("File has no messages"); + /* find document root */ + var docroot: IWAMessage; + out.forEach((iwams) => { + iwams.forEach((iwam) => { + var mtype = varint_to_i32(iwam.meta[1][0].data) >>> 0; + if(mtype == 1) { + if(!docroot) docroot = iwam; + else throw new Error("Document has multiple roots"); + } + }); + }); + if(!docroot) throw new Error("Cannot find Document root"); + return parse_TN_DocumentArchive(out, docroot); +} diff --git a/modules/Makefile b/modules/Makefile index 16c1f79..d406d84 100644 --- a/modules/Makefile +++ b/modules/Makefile @@ -2,20 +2,17 @@ LIBFILES=$(wildcard src/*.ts) TSFILES=$(wildcard *.ts) ENTRIES=$(subst .ts,.js,$(TSFILES)) -BAREJS=04_base64.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js +BAREJS=04_base64.js 51_xlsxmeta.js 51_xlsbmeta.js 59_vba.js 64_ftab.js 83_numbers.js .PHONY: all -all: $(ENTRIES) 51_xlmeta.js - -51_xlmeta.js: 51_xlsxmeta.js 51_xlsbmeta.js - cat $^ > $@ +all: $(ENTRIES) $(BAREJS): %.js: %.ts $(LIBFILES) npx esbuild $< --outfile=$@ --platform=browser --target=es5 -83_numbers.js: 83_numbers.ts $(LIBFILES) - npx esbuild $< --bundle --outfile=$@ --platform=browser --format=iife --global-name=NUMBERS --target=es5 - sed -i '' 's/NUMBERS = /NUMBERS = !Object.defineProperty ? (void 0) :/g' $@ +#83_numbers.js: 83_numbers.ts $(LIBFILES) +# npx esbuild $< --bundle --outfile=$@ --platform=browser --format=iife --global-name=NUMBERS --target=es5 +# sed -i '' 's/NUMBERS = /NUMBERS = !Object.defineProperty ? (void 0) :/g' $@ %.node.js: %.node.ts $(LIBFILES) npx esbuild $< --bundle --external:xlsx --outfile=$@ --minify --platform=node diff --git a/modules/src/types.ts b/modules/src/types.ts index 2936204..f67327b 100644 --- a/modules/src/types.ts +++ b/modules/src/types.ts @@ -1,5 +1,14 @@ +/// + declare type RawData = Uint8Array | number[]; -declare function recordhopper(data: RawData, cb:(val: any, R_n: string, RT: number)=>void): void; +interface BinaryRecord { + n?: string; + f: any; + T?: -1 | 1; + p?: number; + r?: number; +} +declare function recordhopper(data: RawData, cb:(val: any, R: BinaryRecord, RT: number)=>void): void; declare interface ReadableData { l: number; read_shift(t: 4): number; @@ -32,6 +41,8 @@ declare function write_UInt32LE(x: number, o?: WritableData): RawData; declare function write_XLWideString(data: string, o?: WritableData): RawData; declare function writeuint16(x: number): RawData; +declare function utf8read(x: string): string; +declare function a2s(a: RawData): string; interface ParseXLMetaOptions { WTF?: number|boolean; @@ -39,6 +50,12 @@ interface ParseXLMetaOptions { interface XLMDT { name: string; } +interface XLMetaRef { + type: string; + index: number; +} interface XLMeta { Types: XLMDT[]; + Cell: XLMetaRef[]; + Value: XLMetaRef[]; } \ No newline at end of file diff --git a/packages/otorp/index.node.js b/packages/otorp/index.node.js index cd2c127..199b0cf 100644 --- a/packages/otorp/index.node.js +++ b/packages/otorp/index.node.js @@ -27,7 +27,7 @@ __export(index_node_exports, { otorp: () => otorp_default }); -// ../../modules/src/util.ts +// src/util.ts var u8_to_dataview = (array) => new DataView(array.buffer, array.byteOffset, array.byteLength); var u8str = (u8) => new TextDecoder().decode(u8); var indent = (str, depth) => str.split(/\n/g).map((x) => x && " ".repeat(depth) + x).join("\n"); @@ -100,7 +100,7 @@ var parse_macho = (buf) => { throw new Error("Unsupported file"); }; -// ../../modules/src/proto.ts +// src/proto.ts function parse_varint49(buf, ptr) { var l = ptr ? ptr[0] : 0; var usz = buf[l] & 127; @@ -189,7 +189,7 @@ function parse_shallow(buf) { default: throw new Error(`PB Type ${type} for Field ${num} at offset ${off}`); } - var v = { offset: off, data: res }; + var v = { offset: off, data: res, type }; if (out[num] == null) out[num] = [v]; else diff --git a/packages/otorp/src/descriptor.ts b/packages/otorp/src/descriptor.ts index f8b3db7..108f5f0 100644 --- a/packages/otorp/src/descriptor.ts +++ b/packages/otorp/src/descriptor.ts @@ -1,7 +1,7 @@ /*! otorp (C) 2013-present SheetJS -- http://sheetjs.com */ -import { parse_shallow, varint_to_i32, mappa } from "../../../modules/src/proto"; -import { u8str, indent } from "../../../modules/src/util"; +import { parse_shallow, varint_to_i32, mappa } from "./proto"; +import { u8str, indent } from "./util"; var TYPES = [ "error", diff --git a/packages/otorp/src/macho.ts b/packages/otorp/src/macho.ts index a932962..fdbbf9a 100644 --- a/packages/otorp/src/macho.ts +++ b/packages/otorp/src/macho.ts @@ -1,6 +1,6 @@ /*! otorp (C) 2013-present SheetJS -- http://sheetjs.com */ -import { u8_to_dataview } from "../../../modules/src/util"; +import { u8_to_dataview } from "./util"; interface MachOEntry { type: number; diff --git a/packages/otorp/src/otorp.ts b/packages/otorp/src/otorp.ts index b4917df..151fb3d 100644 --- a/packages/otorp/src/otorp.ts +++ b/packages/otorp/src/otorp.ts @@ -1,6 +1,6 @@ /*! otorp (C) 2013-present SheetJS -- http://sheetjs.com */ -import { u8indexOf, u8str, u8_to_dataview } from "../../../modules/src/util"; +import { u8indexOf, u8str, u8_to_dataview } from "./util"; import { parse_macho } from "./macho"; import { Descriptor, parse_FileDescriptor, write_FileDescriptor } from './descriptor'; diff --git a/packages/otorp/src/proto.ts b/packages/otorp/src/proto.ts new file mode 100644 index 0000000..068cf96 --- /dev/null +++ b/packages/otorp/src/proto.ts @@ -0,0 +1,118 @@ +/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +import { u8concat } from "./util"; + +type Ptr = [number]; +export { Ptr }; + +/** Parse an integer from the varint that can be exactly stored in a double */ +function parse_varint49(buf: Uint8Array, ptr?: Ptr): number { + var l = ptr ? ptr[0] : 0; + var usz = buf[l] & 0x7F; + varint: if(buf[l++] >= 0x80) { + usz |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint; + usz |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint; + usz |= (buf[l] & 0x7F) << 21; if(buf[l++] < 0x80) break varint; + usz += (buf[l] & 0x7F) * Math.pow(2, 28); ++l; if(buf[l++] < 0x80) break varint; + usz += (buf[l] & 0x7F) * Math.pow(2, 35); ++l; if(buf[l++] < 0x80) break varint; + usz += (buf[l] & 0x7F) * Math.pow(2, 42); ++l; if(buf[l++] < 0x80) break varint; + } + if(ptr) ptr[0] = l; + return usz; +} +export { parse_varint49 }; +function write_varint49(v: number): Uint8Array { + var usz = new Uint8Array(7); + usz[0] = (v & 0x7F); + var L = 1; + sz: if(v > 0x7F) { + usz[L-1] |= 0x80; usz[L] = (v >> 7) & 0x7F; ++L; + if(v <= 0x3FFF) break sz; + usz[L-1] |= 0x80; usz[L] = (v >> 14) & 0x7F; ++L; + if(v <= 0x1FFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = (v >> 21) & 0x7F; ++L; + if(v <= 0xFFFFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = ((v/0x100) >>> 21) & 0x7F; ++L; + if(v <= 0x7FFFFFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = ((v/0x10000) >>> 21) & 0x7F; ++L; + if(v <= 0x3FFFFFFFFFF) break sz; + usz[L-1] |= 0x80; usz[L] = ((v/0x1000000) >>> 21) & 0x7F; ++L; + } + return usz.slice(0, L); +} +export { write_varint49 }; + +/** Parse a 32-bit signed integer from the raw varint */ +function varint_to_i32(buf: Uint8Array): number { + var l = 0, i32 = buf[l] & 0x7F; + varint: if(buf[l++] >= 0x80) { + i32 |= (buf[l] & 0x7F) << 7; if(buf[l++] < 0x80) break varint; + i32 |= (buf[l] & 0x7F) << 14; if(buf[l++] < 0x80) break varint; + i32 |= (buf[l] & 0x7F) << 21; if(buf[l++] < 0x80) break varint; + i32 |= (buf[l] & 0x7F) << 28; + } + return i32; +} +export { varint_to_i32 }; + +interface ProtoItem { + offset?: number; + data: Uint8Array; + type: number; +} +type ProtoField = Array +type ProtoMessage = Array; +export { ProtoItem, ProtoField, ProtoMessage }; +/** Shallow parse of a message */ +function parse_shallow(buf: Uint8Array): ProtoMessage { + var out: ProtoMessage = [], ptr: Ptr = [0]; + while(ptr[0] < buf.length) { + var off = ptr[0]; + var num = parse_varint49(buf, ptr); + var type = num & 0x07; num = Math.floor(num / 8); + var len = 0; + var res: Uint8Array; + if(num == 0) break; + switch(type) { + case 0: { + var l = ptr[0]; + while(buf[ptr[0]++] >= 0x80); + res = buf.slice(l, ptr[0]); + } break; + case 5: len = 4; res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break; + case 1: len = 8; res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break; + case 2: len = parse_varint49(buf, ptr); res = buf.slice(ptr[0], ptr[0] + len); ptr[0] += len; break; + case 3: // Start group + case 4: // End group + default: throw new Error(`PB Type ${type} for Field ${num} at offset ${off}`); + } + var v: ProtoItem = { offset: off, data: res, type }; + if(out[num] == null) out[num] = [v]; + else out[num].push(v); + } + return out; +} +export { parse_shallow }; +/** Serialize a shallow parse */ +function write_shallow(proto: ProtoMessage): Uint8Array { + var out: Uint8Array[] = []; + proto.forEach((field, idx) => { + field.forEach(item => { + out.push(write_varint49(idx * 8 + item.type)); + out.push(item.data); + }); + }); + return u8concat(out); +} +export { write_shallow }; + +function mappa(data: ProtoField, cb:(Uint8Array) => U): U[] { + if(!data) return []; + return data.map((d) => { try { + return cb(d.data); + } catch(e) { + var m = e.message?.match(/at offset (\d+)/); + if(m) e.message = e.message.replace(/at offset (\d+)/, "at offset " + (+m[1] + d.offset)); + throw e; + }}); +} +export { mappa }; diff --git a/packages/otorp/src/util.ts b/packages/otorp/src/util.ts new file mode 100644 index 0000000..0825948 --- /dev/null +++ b/packages/otorp/src/util.ts @@ -0,0 +1,39 @@ +/*! sheetjs (C) 2013-present SheetJS -- http://sheetjs.com */ +var u8_to_dataview = (array: Uint8Array): DataView => new DataView(array.buffer, array.byteOffset, array.byteLength); +export { u8_to_dataview }; + +var u8str = (u8: Uint8Array): string => new TextDecoder().decode(u8); +export { u8str }; + +var u8concat = (u8a: Uint8Array[]): Uint8Array => { + var len = u8a.reduce((acc: number, x: Uint8Array) => acc + x.length, 0); + var out = new Uint8Array(len); + var off = 0; + u8a.forEach(u8 => { out.set(u8, off); off += u8.length; }); + return out; +}; +export { u8concat }; + +var indent = (str: string, depth: number /* = 1 */): string => str.split(/\n/g).map(x => x && " ".repeat(depth) + x).join("\n"); +export { indent }; + +function u8indexOf(u8: Uint8Array, data: string | number | Uint8Array, byteOffset?: number): number { + //if(Buffer.isBuffer(u8)) return u8.indexOf(data, byteOffset); + if(typeof data == "number") return u8.indexOf(data, byteOffset); + var l = byteOffset; + if(typeof data == "string") { + outs: while((l = u8.indexOf(data.charCodeAt(0), l)) > -1) { + ++l; + for(var j = 1; j < data.length; ++j) if(u8[l+j-1] != data.charCodeAt(j)) continue outs; + return l - 1; + } + } else { + outb: while((l = u8.indexOf(data[0], l)) > -1) { + ++l; + for(var j = 1; j < data.length; ++j) if(u8[l+j-1] != data[j]) continue outb; + return l - 1; + } + } + return -1; +} +export { u8indexOf }; diff --git a/packages/ssf/package.json b/packages/ssf/package.json index be6f8c9..d0862bb 100644 --- a/packages/ssf/package.json +++ b/packages/ssf/package.json @@ -28,6 +28,7 @@ }, "scripts": { "test": "make test", + "tests-only": "make travis", "build": "make", "lint": "make fullint", "dtslint": "dtslint types" diff --git a/packages/xlsx-cli/index.js b/packages/xlsx-cli/index.js index e021a0b..b9c0aeb 100644 --- a/packages/xlsx-cli/index.js +++ b/packages/xlsx-cli/index.js @@ -139,6 +139,7 @@ function run() { opts.cellStyles = true; opts.sheetStubs = true; opts.cellDates = true; + wopts.cellFormula = true; wopts.cellStyles = true; wopts.sheetStubs = true; wopts.bookVBA = true; diff --git a/test_files b/test_files index 4d30377..c0f37ad 160000 --- a/test_files +++ b/test_files @@ -1 +1 @@ -Subproject commit 4d30377c342ade6c436eee261375c2267daf0a82 +Subproject commit c0f37ad3d8a49cd5abb98dba59011ffa4d46cfc0 diff --git a/types/index.d.ts b/types/index.d.ts index f6dab36..3f696ec 100644 --- a/types/index.d.ts +++ b/types/index.d.ts @@ -584,6 +584,9 @@ export interface Comment { /** Plaintext of the comment */ t: string; + + /** If true, mark the comment as a part of a thread */ + T?: boolean; } /** Cell comments */