diff --git a/.npmignore b/.npmignore index 8ff5b6c..d75628a 100644 --- a/.npmignore +++ b/.npmignore @@ -14,8 +14,8 @@ tmp *.[pP][rR][nN] *.[sS][lL][kK] *.socialcalc -*.[xX][lL][sSwWcC] -*.[xX][lL][sS][xXmMbB] +*.[xX][lL][sSwWcCaAtT] +*.[xX][lL][sSaAtT][xXmMbB] *.[oO][dD][sS] *.[fF][oO][dD][sS] *.[xX][mM][lL] diff --git a/.spelling b/.spelling index ef7dbdb..7f551c1 100644 --- a/.spelling +++ b/.spelling @@ -53,6 +53,7 @@ weex # Other terms APIs +ArrayBuffer Base64 Booleans JS diff --git a/CHANGELOG.md b/CHANGELOG.md index 80784a7..92e3aac 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,11 @@ This log is intended to keep track of backwards-incompatible changes, including but not limited to API changes and file location changes. Minor behavioral changes may not be included if they are not expected to break existing code. +## 0.11.16 (2017-12-30) + +* XLS ANSI/CP separation +* 'array' write type and ArrayBuffer processing + ## 0.11.6 (2017-10-16) * Semicolon-delimited files are detected diff --git a/README.md b/README.md index be2c04a..046e104 100644 --- a/README.md +++ b/README.md @@ -84,6 +84,7 @@ enhancements, additional features by request, and dedicated support. + [Workbook File Properties](#workbook-file-properties) * [Workbook-Level Attributes](#workbook-level-attributes) + [Defined Names](#defined-names) + + [Workbook Views](#workbook-views) + [Miscellaneous Workbook Properties](#miscellaneous-workbook-properties) * [Document Features](#document-features) + [Formulae](#formulae) @@ -621,19 +622,12 @@ example uses [FileSaver](https://github.com/eligrey/FileSaver.js/): ```js /* bookType can be any supported output type */ -var wopts = { bookType:'xlsx', bookSST:false, type:'binary' }; +var wopts = { bookType:'xlsx', bookSST:false, type:'array' }; var wbout = XLSX.write(workbook,wopts); -function s2ab(s) { - var buf = new ArrayBuffer(s.length); - var view = new Uint8Array(buf); - for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; -} - /* the saveAs call downloads a file on the local machine */ -saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "test.xlsx"); +saveAs(new Blob([wbout],{type:"application/octet-stream"}), "test.xlsx"); ``` @@ -1081,6 +1075,14 @@ Excel allows two sheet-scoped defined names to share the same name. However, a sheet-scoped name cannot collide with a workbook-scope name. Workbook writers may not enforce this constraint. +#### Workbook Views + +`wb.Workbook.Views` is an array of workbook view objects which have the keys: + +| Key | Description | +|:----------------|:----------------------------------------------------| +| `RTL` | If true, display right-to-left | + #### Miscellaneous Workbook Properties `wb.Workbook.WBProps` holds other workbook properties: @@ -1693,6 +1695,7 @@ The `type` argument for `write` mirrors the `type` argument for `read`: | `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) | | `"string"` | string: JS string (characters interpreted as UTF8) | | `"buffer"` | nodejs Buffer | +| `"array"` | ArrayBuffer, fallback array of 8-bit unsigned int | | `"file"` | string: path of file that will be created (nodejs only) | ## Utility Functions diff --git a/bin/xlsx.njs b/bin/xlsx.njs index 2a02c5b..8886155 100755 --- a/bin/xlsx.njs +++ b/bin/xlsx.njs @@ -19,12 +19,14 @@ program .option('-B, --xlsb', 'emit XLSB to or .xlsb') .option('-M, --xlsm', 'emit XLSM to or .xlsm') .option('-X, --xlsx', 'emit XLSX to or .xlsx') + .option('-I, --xlam', 'emit XLAM to or .xlam') .option('-Y, --ods', 'emit ODS to or .ods') .option('-8, --xls', 'emit XLS to or .xls (BIFF8)') .option('-5, --biff5','emit XLS to or .xls (BIFF5)') //.option('-4, --biff4','emit XLS to or .xls (BIFF4)') //.option('-3, --biff3','emit XLS to or .xls (BIFF3)') .option('-2, --biff2','emit XLS to or .xls (BIFF2)') + .option('-i, --xla', 'emit XLA to or .xla') .option('-6, --xlml', 'emit SSML to or .xls (2003 XML)') .option('-T, --fods', 'emit FODS to or .fods (Flat ODS)') @@ -65,8 +67,10 @@ program.on('--help', function() { var workbook_formats = [ ['xlsx', 'xlsx', 'xlsx'], ['xlsm', 'xlsm', 'xlsm'], + ['xlam', 'xlam', 'xlam'], ['xlsb', 'xlsb', 'xlsb'], ['xls', 'xls', 'xls'], + ['xla', 'xla', 'xla'], ['biff5', 'biff5', 'xls'], ['ods', 'ods', 'ods'], ['fods', 'fods', 'fods'] diff --git a/bits/01_version.js b/bits/01_version.js index 3cd85f0..2568c89 100644 --- a/bits/01_version.js +++ b/bits/01_version.js @@ -1 +1 @@ -XLSX.version = '0.11.15'; +XLSX.version = '0.11.16'; diff --git a/bits/02_codepage.js b/bits/02_codepage.js index 3b24e01..9c4b3de 100644 --- a/bits/02_codepage.js +++ b/bits/02_codepage.js @@ -1,21 +1,51 @@ -var current_codepage = 1200; +var current_codepage = 1200, current_ansi = 1252; /*:: declare var cptable:any; */ /*global cptable:true */ if(typeof module !== "undefined" && typeof require !== 'undefined') { if(typeof cptable === 'undefined') global.cptable = require('./dist/cpexcel.js'); } -function reset_cp() { set_cp(1200); } -var set_cp = function(cp) { current_codepage = cp; }; -function char_codes(data) { var o = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; } +var VALID_ANSI = [ 874, 932, 936, 949, 950 ]; +for(var i = 0; i <= 8; ++i) VALID_ANSI.push(1250 + i); +/* ECMA-376 Part I 18.4.1 charset to codepage mapping */ +var CS2CP = ({ + /*::[*/0/*::]*/: 1252, /* ANSI */ + /*::[*/1/*::]*/: 65001, /* DEFAULT */ + /*::[*/2/*::]*/: 65001, /* SYMBOL */ + /*::[*/77/*::]*/: 10000, /* MAC */ + /*::[*/128/*::]*/: 932, /* SHIFTJIS */ + /*::[*/129/*::]*/: 949, /* HANGUL */ + /*::[*/130/*::]*/: 1361, /* JOHAB */ + /*::[*/134/*::]*/: 936, /* GB2312 */ + /*::[*/136/*::]*/: 950, /* CHINESEBIG5 */ + /*::[*/161/*::]*/: 1253, /* GREEK */ + /*::[*/162/*::]*/: 1254, /* TURKISH */ + /*::[*/163/*::]*/: 1258, /* VIETNAMESE */ + /*::[*/177/*::]*/: 1255, /* HEBREW */ + /*::[*/178/*::]*/: 1256, /* ARABIC */ + /*::[*/186/*::]*/: 1257, /* BALTIC */ + /*::[*/204/*::]*/: 1251, /* RUSSIAN */ + /*::[*/222/*::]*/: 874, /* THAI */ + /*::[*/238/*::]*/: 1250, /* EASTEUROPE */ + /*::[*/255/*::]*/: 1252, /* OEM */ + /*::[*/69/*::]*/: 6969 /* MISC */ +}/*:any*/); + +var set_ansi = function(cp/*:number*/) { if(VALID_ANSI.indexOf(cp) == -1) return; current_ansi = CS2CP[0] = cp; }; +function reset_ansi() { set_ansi(1252); } + +var set_cp = function(cp/*:number*/) { current_codepage = cp; set_ansi(cp); }; +function reset_cp() { set_cp(1200); reset_ansi(); } + +function char_codes(data/*:string*/)/*:Array*/ { var o/*:Array*/ = []; for(var i = 0, len = data.length; i < len; ++i) o[i] = data.charCodeAt(i); return o; } function utf16leread(data/*:string*/)/*:string*/ { - var o = []; + var o/*:Array*/ = []; for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i) + (data.charCodeAt(2*i+1)<<8)); return o.join(""); } function utf16beread(data/*:string*/)/*:string*/ { - var o = []; + var o/*:Array*/ = []; for(var i = 0; i < (data.length>>1); ++i) o[i] = String.fromCharCode(data.charCodeAt(2*i+1) + (data.charCodeAt(2*i)<<8)); return o.join(""); } diff --git a/bits/05_buf.js b/bits/05_buf.js index 92d7182..c0722c5 100644 --- a/bits/05_buf.js +++ b/bits/05_buf.js @@ -12,6 +12,18 @@ function s2a(s/*:string*/) { return s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; }); } +function s2ab(s/*:string*/) { + if(typeof ArrayBuffer === 'undefined') return s2a(s); + var buf = new ArrayBuffer(s.length), view = new Uint8Array(buf); + for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; + return buf; +} + +function arr2str(data/*:any*/)/*:string*/ { + if(Array.isArray(data)) return data.map(_chr).join(""); + var o/*:Array*/ = []; for(var i = 0; i < data.length; ++i) o[i] = _chr(data[i]); return o.join(""); +} + var bconcat = function(bufs) { return [].concat.apply([], bufs); }; var chr0 = /\u0000/g, chr1 = /[\u0001-\u0006]/g; diff --git a/bits/20_jsutils.js b/bits/20_jsutils.js index a36c9c5..df2571f 100644 --- a/bits/20_jsutils.js +++ b/bits/20_jsutils.js @@ -1,5 +1,3 @@ -function isval(x/*:?any*/)/*:boolean*/ { return x !== undefined && x !== null; } - function keys(o/*:any*/)/*:Array*/ { return Object.keys(o); } function evert_key(obj/*:any*/, key/*:string*/)/*:EvertType*/ { @@ -99,12 +97,6 @@ function cc2str(arr/*:Array*/)/*:string*/ { return o; } -function str2cc(str) { - var o = []; - for(var i = 0; i != str.length; ++i) o.push(str.charCodeAt(i)); - return o; -} - function dup(o/*:any*/)/*:any*/ { if(typeof JSON != 'undefined' && !Array.isArray(o)) return JSON.parse(JSON.stringify(o)); if(typeof o != 'object' || o == null) return o; diff --git a/bits/21_ziputils.js b/bits/21_ziputils.js index d402139..ba25d0c 100644 --- a/bits/21_ziputils.js +++ b/bits/21_ziputils.js @@ -13,7 +13,7 @@ function getdatabin(data) { if(data.asNodeBuffer && has_buf) return data.asNodeBuffer(); if(data._data && data._data.getContent) { var o = data._data.getContent(); - if(typeof o == "string") return str2cc(o); + if(typeof o == "string") return char_codes(o); return Array.prototype.slice.call(o); } return null; diff --git a/bits/22_xmlutils.js b/bits/22_xmlutils.js index a435b90..01e9961 100644 --- a/bits/22_xmlutils.js +++ b/bits/22_xmlutils.js @@ -1,6 +1,6 @@ var XML_HEADER = '\r\n'; -var attregexg=/([^"\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g; -var tagregex=/<[\/\?]?[a-zA-Z0-9:]+(?:\s+[^"\s?>\/]+=(?:"[^"]*"|'[^']*'|[^'">\s]+))*\s?[\/\?]?>/g; +var attregexg=/([^"\s?>\/]+)\s*=\s*((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g; +var tagregex=/<[\/\?]?[a-zA-Z0-9:]+(?:\s+[^"\s?>\/]+\s*=\s*(?:"[^"]*"|'[^']*'|[^'">\s]+))*\s?[\/\?]?>/g; if(!(XML_HEADER.match(tagregex))) tagregex = /<[^>]*>/g; var nsregex=/<\w*:/, nsregex2 = /<(\/?)\w+:/; function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ { @@ -13,7 +13,8 @@ function parsexmltag(tag/*:string*/, skip_root/*:?boolean*/)/*:any*/ { if(m) for(i = 0; i != m.length; ++i) { cc = m[i]; for(c=0; c != cc.length; ++c) if(cc.charCodeAt(c) === 61) break; - q = cc.substr(0,c); + q = cc.substr(0,c).trim(); + while(cc.charCodeAt(c+1) == 32) ++c; quot = ((eq=cc.charCodeAt(c+1)) == 34 || eq == 39) ? 1 : 0; v = cc.substring(c+1+quot, cc.length-quot); for(j=0;j!=q.length;++j) if(q.charCodeAt(j) === 58) break; @@ -84,7 +85,7 @@ function parsexmlbool(value/*:any*/, tag/*:?string*/)/*:boolean*/ { } } -var utf8read/*:StringConv*/ = function utf8reada(orig) { +var utf8read/*:StringConv*/ = function utf8reada(orig/*:string*/)/*:string*/ { var out = "", i = 0, c = 0, d = 0, e = 0, f = 0, w = 0; while (i < orig.length) { c = orig.charCodeAt(i++); @@ -101,7 +102,7 @@ var utf8read/*:StringConv*/ = function utf8reada(orig) { return out; }; -var utf8write/*:StringConv*/ = function(orig) { +var utf8write/*:StringConv*/ = function(orig/*:string*/)/*:string*/ { var out/*:Array*/ = [], i = 0, c = 0, d = 0; while(i < orig.length) { c = orig.charCodeAt(i++); @@ -156,18 +157,18 @@ if(has_buf) { // matches ... extracts content var matchtag = (function() { var mtcache/*:{[k:string]:RegExp}*/ = ({}/*:any*/); - return function matchtag(f,g/*:?string*/)/*:RegExp*/ { + return function matchtag(f/*:string*/,g/*:?string*/)/*:RegExp*/ { var t = f+"|"+(g||""); if(mtcache[t]) return mtcache[t]; return (mtcache[t] = new RegExp('<(?:\\w+:)?'+f+'(?: xml:space="preserve")?(?:[^>]*)>([\\s\\S]*?)',((g||"")/*:any*/))); }; })(); -var htmldecode = (function() { - var entities = [ +var htmldecode/*:{(s:string):string}*/ = (function() { + var entities/*:Array<[RegExp, string]>*/ = [ ['nbsp', ' '], ['middot', '·'], ['quot', '"'], ['apos', "'"], ['gt', '>'], ['lt', '<'], ['amp', '&'] - ].map(function(x) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; }); + ].map(function(x/*:[string, string]*/) { return [new RegExp('&' + x[0] + ';', "g"), x[1]]; }); return function htmldecode(str/*:string*/)/*:string*/ { var o = str.trim().replace(/\s+/g, " ").replace(/<\s*[bB][rR]\s*\/?>/g,"\n").replace(/<[^>]*>/g,""); for(var i = 0; i < entities.length; ++i) o = o.replace(entities[i][0], entities[i][1]); @@ -181,27 +182,27 @@ var vtregex = (function(){ var vt_cache = {}; return (vt_cache[bt] = new RegExp("<(?:vt:)?" + bt + ">([\\s\\S]*?)", 'g') ); };})(); var vtvregex = /<\/?(?:vt:)?variant>/g, vtmregex = /<(?:vt:)([^>]*)>([\s\S]*)*/ { var h = parsexmltag(data); - var matches = data.match(vtregex(h.baseType))||[]; - var res = []; + var matches/*:Array*/ = data.match(vtregex(h.baseType))||[]; + var res/*:Array*/ = []; if(matches.length != h.size) { if(opts.WTF) throw new Error("unexpected vector length " + matches.length + " != " + h.size); return res; } - matches.forEach(function(x) { + matches.forEach(function(x/*:string*/) { var v = x.replace(vtvregex,"").match(vtmregex); - res.push({v:utf8read(v[2]), t:v[1]}); + if(v) res.push({v:utf8read(v[2]), t:v[1]}); }); return res; } var wtregex = /(^\s|\s$|\n)/; -function writetag(f,g) {return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '';} +function writetag(f/*:string*/,g/*:string*/)/*:string*/ { return '<' + f + (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + ''; } function wxt_helper(h)/*:string*/ { return keys(h).map(function(k) { return " " + k + '="' + h[k] + '"';}).join(""); } -function writextag(f,g,h) { return '<' + f + (isval(h) /*:: && h */? wxt_helper(h) : "") + (isval(g) /*:: && g */? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '';} +function writextag(f/*:string*/,g/*:?string*/,h) { return '<' + f + ((h != null) ? wxt_helper(h) : "") + ((g != null) ? (g.match(wtregex)?' xml:space="preserve"' : "") + '>' + g + '';} function write_w3cdtf(d/*:Date*/, t/*:?boolean*/)/*:string*/ { try { return d.toISOString().replace(/\.\d*/,""); } catch(e) { if(t) throw e; } return ""; } diff --git a/bits/23_binutils.js b/bits/23_binutils.js index 8959554..b9f6e65 100644 --- a/bits/23_binutils.js +++ b/bits/23_binutils.js @@ -35,6 +35,8 @@ var __utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { var ss= var ___utf8 = __utf8; var __lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";}; var ___lpstr = __lpstr; +var __cpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";}; +var ___cpstr = __cpstr; var __lpwstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = 2*__readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";}; var ___lpwstr = __lpwstr; var __lpp4, ___lpp4; @@ -49,6 +51,7 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) { __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___utf16le(b,s,e); return b.toString('utf16le',s,e).replace(chr0,'')/*.replace(chr1,'!')*/; }; __hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { return Buffer.isBuffer(b)/*:: && b instanceof Buffer*/ ? b.toString('hex',s,s+l) : ___hexlify(b,s,l); }; __lpstr = function lpstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";}; + __cpstr = function cpstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___cpstr(b, i); var len = b.readUInt32LE(i); return len > 0 ? b.toString('utf8',i+4,i+4+len-1) : "";}; __lpwstr = function lpwstr_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpwstr(b, i); var len = 2*b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len-1);}; __lpp4 = function lpp4_b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf16le',i+4,i+4+len);}; __8lpp4 = function lpp4_8b(b/*:RawBytes|CFBlob*/, i/*:number*/) { if(!Buffer.isBuffer(b)/*:: || !(b instanceof Buffer)*/) return ___8lpp4(b, i); var len = b.readUInt32LE(i); return b.toString('utf8',i+4,i+4+len);}; @@ -63,7 +66,8 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) { if(typeof cptable !== 'undefined') { __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(1200, b.slice(s,e)).replace(chr0, ''); }; __utf8 = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(65001, b.slice(s,e)); }; - __lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";}; + __lpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_ansi, b.slice(i+4, i+4+len-1)) : "";}; + __cpstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(current_codepage, b.slice(i+4, i+4+len-1)) : "";}; __lpwstr = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = 2*__readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len-1)) : "";}; __lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(1200, b.slice(i+4,i+4+len)) : "";}; __8lpp4 = function(b/*:RawBytes|CFBlob*/,i/*:number*/) { var len = __readUInt32LE(b,i); return len > 0 ? cptable.utils.decode(65001, b.slice(i+4,i+4+len)) : "";}; @@ -98,9 +102,10 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ { size = 2 * size; break; /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */ - case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break; + case 'lpstr-ansi': o = __lpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break; + case 'lpstr-cp': o = __cpstr(this, this.l); size = 4 + __readUInt32LE(this, this.l); break; /* [MS-OLEDS] 2.1.5 LengthPrefixedUnicodeString */ - case 'lpwstr': o = __lpwstr(this, this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break; + case 'lpwstr': o = __lpwstr(this, this.l); size = 4 + 2 * __readUInt32LE(this, this.l); break; /* [MS-OFFCRYPTO] 2.1.2 Length-Prefixed Padded Unicode String (UNICODE-LP-P4) */ case 'lpp4': size = 4 + __readUInt32LE(this, this.l); o = __lpp4(this, this.l); if(size & 0x02) size += 2; break; /* [MS-OFFCRYPTO] 2.1.3 Length-Prefixed UTF-8 String (UTF-8-LP-P4) */ @@ -222,9 +227,6 @@ function prep_blob(blob, pos/*:number*/)/*:void*/ { } function parsenoop(blob, length/*:: :number, opts?:any */) { blob.l += length; } -function parsenooplog(blob, length/*:number*/) { if(typeof console != 'undefined') console.log(blob.slice(blob.l, blob.l + length)); blob.l += length; } - -function writenoop(blob, length/*:number*/) { blob.l += length; } function new_buf(sz/*:number*/)/*:Block*/ { var o = new_raw_buf(sz); diff --git a/bits/24_hoppers.js b/bits/24_hoppers.js index 0e47272..af774cd 100644 --- a/bits/24_hoppers.js +++ b/bits/24_hoppers.js @@ -20,14 +20,14 @@ function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) { /* control buffer usage for fixed-length buffers */ function buf_array()/*:BufArray*/ { - var bufs = [], blksz = has_buf ? 256 : 2048; - var newblk = function ba_newblk(sz) { + var bufs/*:Array*/ = [], blksz = has_buf ? 256 : 2048; + var newblk = function ba_newblk(sz/*:number*/)/*:Block*/ { var o/*:Block*/ = (new_buf(sz)/*:any*/); prep_blob(o, 0); return o; }; - var curbuf = newblk(blksz); + var curbuf/*:Block*/ = newblk(blksz); var endbuf = function ba_endbuf() { if(!curbuf) return; @@ -36,7 +36,7 @@ function buf_array()/*:BufArray*/ { curbuf = null; }; - var next = function ba_next(sz) { + var next = function ba_next(sz/*:number*/)/*:Block*/ { if(curbuf && sz < curbuf.length - curbuf.l) return curbuf; endbuf(); return (curbuf = newblk(Math.max(sz+1, blksz))); @@ -56,7 +56,7 @@ function write_record(ba/*:BufArray*/, type/*:string*/, payload, length/*:?numbe var t/*:number*/ = +XLSBRE[type], l; if(isNaN(t)) return; // TODO: throw something here? if(!length) length = XLSBRecordEnum[t].p || (payload||[]).length || 0; - l = 1 + (t >= 0x80 ? 1 : 0) + 1 + length; + l = 1 + (t >= 0x80 ? 1 : 0) + 1/* + length*/; if(length >= 0x80) ++l; if(length >= 0x4000) ++l; if(length >= 0x200000) ++l; var o = ba.next(l); if(t <= 0x7F) o.write_shift(1, t); diff --git a/bits/28_binstructs.js b/bits/28_binstructs.js index 1033d03..3a3b004 100644 --- a/bits/28_binstructs.js +++ b/bits/28_binstructs.js @@ -265,3 +265,19 @@ function write_FontFlags(font, o) { return o; } +/* [MS-OLEDS] 2.3.1 and 2.3.2 */ +function parse_ClipboardFormatOrString(o, w/*:number*/)/*:string*/ { + // $FlowIgnore + var ClipFmt = {2:"BITMAP",3:"METAFILEPICT",8:"DIB",14:"ENHMETAFILE"}; + var m/*:number*/ = o.read_shift(4); + switch(m) { + case 0x00000000: return ""; + case 0xffffffff: case 0xfffffffe: return ClipFmt[o.read_shift(4)]||""; + } + if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16)); + o.l -= 4; + return o.read_shift(0, w == 1 ? "lpstr" : "lpwstr"); +} +function parse_ClipboardFormatOrAnsiString(o) { return parse_ClipboardFormatOrString(o, 1); } +function parse_ClipboardFormatOrUnicodeString(o) { return parse_ClipboardFormatOrString(o, 2); } + diff --git a/bits/29_xlsenum.js b/bits/29_xlsenum.js index 47a0fd1..a75bab3 100644 --- a/bits/29_xlsenum.js +++ b/bits/29_xlsenum.js @@ -87,7 +87,7 @@ var SummaryPIDSI = { /*::[*/0x0F/*::]*/: { n: 'WordCount', t: VT_I4 }, /*::[*/0x10/*::]*/: { n: 'CharCount', t: VT_I4 }, /*::[*/0x11/*::]*/: { n: 'Thumbnail', t: VT_CF }, - /*::[*/0x12/*::]*/: { n: 'ApplicationName', t: VT_LPSTR }, + /*::[*/0x12/*::]*/: { n: 'ApplicationName', t: VT_STRING }, /*::[*/0x13/*::]*/: { n: 'DocumentSecurity', t: VT_I4 }, /*::[*/0xFF/*::]*/: {} }; diff --git a/bits/30_ctype.js b/bits/30_ctype.js index 258f43b..58beaa1 100644 --- a/bits/30_ctype.js +++ b/bits/30_ctype.js @@ -180,7 +180,7 @@ var CT_LIST = (function(){ xlsb: "application/vnd.ms-excel.styles" } }; - keys(o).forEach(function(k) { if(!o[k].xlsm) o[k].xlsm = o[k].xlsx; }); + keys(o).forEach(function(k) { ["xlsm", "xlam"].forEach(function(v) { if(!o[k][v]) o[k][v] = o[k].xlsx; }); }); keys(o).forEach(function(k){ keys(o[k]).forEach(function(v) { ct2type[o[k][v]] = k; }); }); return o; })(); diff --git a/bits/34_extprops.js b/bits/34_extprops.js index 8204ec7..6530980 100644 --- a/bits/34_extprops.js +++ b/bits/34_extprops.js @@ -84,7 +84,7 @@ var EXT_PROPS_XML_ROOT = writextag('Properties', null, { }); function write_ext_props(cp, opts)/*:string*/ { - var o = [], p = {}, W = writextag; + var o/*:Array*/ = [], p = {}, W = writextag; if(!cp) cp = {}; cp.Application = "SheetJS"; o[o.length] = (XML_HEADER); diff --git a/bits/36_xlsprops.js b/bits/36_xlsprops.js index 02a491d..af5fe5c 100644 --- a/bits/36_xlsprops.js +++ b/bits/36_xlsprops.js @@ -39,7 +39,7 @@ function xlml_set_prop(Props, tag/*:string*/, val) { } function xlml_write_docprops(Props, opts) { - var o = []; + var o/*:Array*/ = []; keys(XLMLDocPropsMap).map(function(m) { for(var i = 0; i < CORE_PROPS.length; ++i) if(CORE_PROPS[i][1] == m) return CORE_PROPS[i]; for(i = 0; i < EXT_PROPS.length; ++i) if(EXT_PROPS[i][1] == m) return EXT_PROPS[i]; @@ -60,7 +60,7 @@ function xlml_write_docprops(Props, opts) { function xlml_write_custprops(Props, Custprops, opts) { var BLACKLIST = ["Worksheets","SheetNames"]; var T = 'CustomDocumentProperties'; - var o = []; + var o/*:Array*/ = []; if(Props) keys(Props).forEach(function(k) { /*:: if(!Props) return; */ if(!Props.hasOwnProperty(k)) return; diff --git a/bits/38_xlstypes.js b/bits/38_xlstypes.js index 5359e8b..afbd4b3 100644 --- a/bits/38_xlstypes.js +++ b/bits/38_xlstypes.js @@ -8,8 +8,9 @@ function parse_FILETIME(blob) { /* [MS-OSHARED] 2.3.3.1.4 Lpstr */ function parse_lpstr(blob, type, pad/*:?number*/) { - var str = blob.read_shift(0, 'lpstr'); - if(pad) blob.l += (4 - ((str.length+1) & 3)) & 3; + var start = blob.l; + var str = blob.read_shift(0, 'lpstr-cp'); + if(pad) while((blob.l - start) & 3) ++blob.l; return str; } @@ -32,15 +33,15 @@ function parse_VtString(blob, t/*:number*/, pad/*:?boolean*/) { return parse_VtS function parse_VtUnalignedString(blob, t/*:number*/) { if(!t) throw new Error("VtUnalignedString must have positive length"); return parse_VtStringBase(blob, t, 0); } /* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */ -function parse_VtVecUnalignedLpstrValue(blob) { +function parse_VtVecUnalignedLpstrValue(blob)/*:Array*/ { var length = blob.read_shift(4); - var ret = []; - for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr'); + var ret/*:Array*/ = []; + for(var i = 0; i != length; ++i) ret[i] = blob.read_shift(0, 'lpstr-cp').replace(chr0,''); return ret; } /* [MS-OSHARED] 2.3.3.1.10 VtVecUnalignedLpstr */ -function parse_VtVecUnalignedLpstr(blob) { +function parse_VtVecUnalignedLpstr(blob)/*:Array*/ { return parse_VtVecUnalignedLpstrValue(blob); } @@ -155,16 +156,17 @@ function parse_PropertySet(blob, PIDSI) { var Offset = blob.read_shift(4); Props[i] = [PropID, Offset + start_addr]; } + Props.sort(function(x,y) { return x[1] - y[1]; }); var PropH = {}; for(i = 0; i != NumProps; ++i) { if(blob.l !== Props[i][1]) { var fail = true; if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) { - case 0x02 /*VT_I2*/: if(blob.l +2 === Props[i][1]) { blob.l+=2; fail = false; } break; + case 0x02 /*VT_I2*/: if(blob.l+2 === Props[i][1]) { blob.l+=2; fail = false; } break; case 0x50 /*VT_STRING*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break; case 0x100C /*VT_VECTOR|VT_VARIANT*/: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break; } - if(!PIDSI && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; } + if((!PIDSI||i==0) && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; } if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i); } if(PIDSI) { @@ -326,7 +328,7 @@ function parse_XLUnicodeRichExtendedString(blob) { var z = {}; if(fRichSt) cRun = blob.read_shift(2); if(fExtSt) cbExtRst = blob.read_shift(4); - var encoding = (flags & 0x1) ? 'dbcs-cont' : 'sbcs-cont'; + var encoding = width == 2 ? 'dbcs-cont' : 'sbcs-cont'; var msg = cch === 0 ? "" : blob.read_shift(cch, encoding); if(fRichSt) blob.l += 4 * cRun; //TODO: parse this if(fExtSt) blob.l += cbExtRst; //TODO: parse this @@ -398,15 +400,14 @@ function parse_URLMoniker(blob/*::, length, opts*/) { /* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */ function parse_FileMoniker(blob, length) { var cAnti = blob.read_shift(2); - var ansiLength = blob.read_shift(4); - var ansiPath = blob.read_shift(ansiLength, 'cstr'); + var ansiPath = blob.read_shift(0, 'lpstr-ansi'); var endServer = blob.read_shift(2); - var versionNumber = blob.read_shift(2); - var cbUnicodePathSize = blob.read_shift(4); - if(cbUnicodePathSize === 0) return ansiPath.replace(/\\/g,"/"); - var cbUnicodePathBytes = blob.read_shift(4); - var usKeyValue = blob.read_shift(2); - var unicodePath = blob.read_shift(cbUnicodePathBytes>>1, 'utf16le').replace(chr0,""); + if(blob.read_shift(2) != 0xDEAD) throw new Error("Bad FileMoniker"); + var sz = blob.read_shift(4); + if(sz === 0) return ansiPath.replace(/\\/g,"/"); + var bytes = blob.read_shift(4); + if(blob.read_shift(2) != 3) throw new Error("Bad FileMoniker"); + var unicodePath = blob.read_shift(bytes>>1, 'utf16le').replace(chr0,""); return unicodePath; } diff --git a/bits/39_xlsbiff.js b/bits/39_xlsbiff.js index 0458201..acc0480 100644 --- a/bits/39_xlsbiff.js +++ b/bits/39_xlsbiff.js @@ -61,6 +61,14 @@ function parse_Ref8U(blob, length) { var colLast = blob.read_shift(2); return {s:{c:colFirst, r:rwFirst}, e:{c:colLast,r:rwLast}}; } +function write_Ref8U(r/*:Range*/, o) { + if(!o) o = new_buf(8); + o.write_shift(2, r.s.r); + o.write_shift(2, r.e.r); + o.write_shift(2, r.s.c); + o.write_shift(2, r.e.c); + return o; +} /* 2.5.211 */ function parse_RefU(blob, length) { @@ -165,6 +173,7 @@ function write_BOF(wb/*:Workbook*/, t/*:number*/, o) { case 'biff4': h = 0x0004; w = 6; break; case 'biff3': h = 0x0003; w = 6; break; case 'biff2': h = 0x0002; w = 4; break; + case 'xla': break; default: throw new Error("unsupported BIFF version"); } var out = new_buf(w); @@ -337,6 +346,22 @@ function write_Window1(opts) { o.write_shift(2, 0x01f4); return o; } +/* 2.4.346 TODO */ +function parse_Window2(blob, length, opts) { + if(opts && opts.biff >= 2 && opts.biff < 8) return {}; + var f = blob.read_shift(2); + return { RTL: f & 0x40 }; +} +function write_Window2(view) { + var o = new_buf(18), f = 0x6b6; + if(view && view.RTL) f |= 0x40; + o.write_shift(2, f); + o.write_shift(4, 0); + o.write_shift(4, 64); + o.write_shift(4, 0); + o.write_shift(4, 0); + return o; +} /* 2.4.122 TODO */ function parse_Font(blob, length, opts) { @@ -624,7 +649,6 @@ function parse_ExternSheet(blob, length, opts) { var o = [], target = blob.l + length, len = blob.read_shift(opts.biff > 8 ? 4 : 2); while(len-- !== 0) o.push(parse_XTI(blob, opts.biff > 8 ? 12 : 6, opts)); // [iSupBook, itabFirst, itabLast]; - var oo = []; return o; } function parse_BIFF5ExternSheet(blob, length, opts) { @@ -689,12 +713,18 @@ function parse_Note(blob, length, opts) { } /* 2.4.168 */ -function parse_MergeCells(blob, length) { - var merges = []; +function parse_MergeCells(blob, length)/*:Array*/ { + var merges/*:Array*/ = []; var cmcs = blob.read_shift(2); while (cmcs--) merges.push(parse_Ref8U(blob,length)); return merges; } +function write_MergeCells(merges/*:Array*/) { + var o = new_buf(2 + merges.length * 8); + o.write_shift(2, merges.length); + for(var i = 0; i < merges.length; ++i) write_Ref8U(merges[i], o); + return o; +} /* 2.4.181 TODO: parse all the things! */ function parse_Obj(blob, length, opts) { @@ -821,8 +851,8 @@ function write_HLinkTooltip(hl) { } /* 2.4.63 */ -function parse_Country(blob, length) { - var o = [], d; +function parse_Country(blob, length)/*:[string|number, string|number]*/ { + var o = [0,0], d; d = blob.read_shift(2); o[0] = CountryEnum[d] || d; d = blob.read_shift(2); o[1] = CountryEnum[d] || d; return o; diff --git a/bits/40_harb.js b/bits/40_harb.js index f7bf969..13d65ef 100644 --- a/bits/40_harb.js +++ b/bits/40_harb.js @@ -86,10 +86,11 @@ function dbf_to_aoa(buf, opts)/*:AOA*/ { d.l+=2; } if(l7) d.l += 36; - var fields = [], field = {}; +/*:: type DBFField = { name:string; len:number; type:string; } */ + var fields/*:Array*/ = [], field/*:DBFField*/ = ({}/*:any*/); var hend = fpos - 10 - (vfp ? 264 : 0), ww = l7 ? 32 : 11; while(ft == 0x02 ? d.l < d.length && d[d.l] != 0x0d: d.l < hend) { - field = {}; + field = ({}/*:any*/); field.name = cptable.utils.decode(current_cp, d.slice(d.l, d.l+ww)).replace(/[\u0000\r\n].*$/g,""); d.l += ww; field.type = String.fromCharCode(d.read_shift(1)); @@ -210,7 +211,7 @@ function sheet_to_dbf(ws/*:Worksheet*/, opts/*:WriteOpts*/) { if(headers.indexOf(headers[i] + "_" + j) == -1) { headers[i] += "_" + j; break; } } var range = safe_decode_range(ws['!ref']); - var coltypes = []; + var coltypes/*:Array*/ = []; for(i = 0; i <= range.e.c - range.s.c; ++i) { var col/*:Array*/ = []; for(j=0; j < data.length; ++j) { @@ -307,10 +308,10 @@ var SYLK = (function() { throw new Error("Unrecognized type " + opts.type); } function sylk_to_aoa_str(str/*:string*/, opts)/*:[AOA, Worksheet]*/ { - var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr = []; - var formats = []; - var next_cell_format = null; - var sht = {}, rowinfo = [], colinfo = [], cw = []; + var records = str.split(/[\n\r]+/), R = -1, C = -1, ri = 0, rj = 0, arr/*:AOA*/ = []; + var formats/*:Array*/ = []; + var next_cell_format/*:string|null*/ = null; + var sht = {}, rowinfo/*:Array*/ = [], colinfo/*:Array*/ = [], cw/*:Array*/ = []; var Mval = 0, j; for (; ri !== records.length; ++ri) { Mval = 0; @@ -484,7 +485,7 @@ var DIF = (function() { throw new Error("Unrecognized type " + opts.type); } function dif_to_aoa_str(str/*:string*/, opts)/*:AOA*/ { - var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = []; + var records = str.split('\n'), R = -1, C = -1, ri = 0, arr/*:AOA*/ = []; for (; ri !== records.length; ++ri) { if (records[ri].trim() === 'BOT') { arr[++R] = []; C = 0; continue; } if (R < 0) continue; @@ -585,7 +586,7 @@ var ETH = (function() { function encode(s/*:string*/)/*:string*/ { return s.replace(/\\/g, "\\b").replace(/:/g, "\\c").replace(/\n/g,"\\n"); } function eth_to_aoa(str/*:string*/, opts)/*:AOA*/ { - var records = str.split('\n'), R = -1, C = -1, ri = 0, arr = []; + var records = str.split('\n'), R = -1, C = -1, ri = 0, arr/*:AOA*/ = []; for (; ri !== records.length; ++ri) { var record = records[ri].trim().split(":"); if(record[0] !== 'cell') continue; @@ -632,7 +633,7 @@ var ETH = (function() { function sheet_to_eth_data(ws/*:Worksheet*/)/*:string*/ { if(!ws || !ws['!ref']) return ""; - var o = [], oo = [], cell, coord; + var o/*:Array*/ = [], oo/*:Array*/ = [], cell, coord = ""; var r = decode_range(ws['!ref']); var dense = Array.isArray(ws); for(var R = r.s.r; R <= r.e.r; ++R) { @@ -648,12 +649,12 @@ var ETH = (function() { else { oo[2]='vtf'; oo[3]='n'; oo[4]=cell.v; oo[5]=encode(cell.f); } break; case 'b': - oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=+!!cell.v; + oo[2] = 'vt'+(cell.f?'f':'c'); oo[3]='nl'; oo[4]=cell.v?"1":"0"; oo[5] = encode(cell.f||(cell.v?'TRUE':'FALSE')); break; case 'd': var t = datenum(parseDate(cell.v)); - oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = t; + oo[2] = 'vtc'; oo[3] = 'nd'; oo[4] = ""+t; oo[5] = cell.w || SSF.format(cell.z || SSF._table[14], t); break; case 'e': continue; @@ -840,7 +841,7 @@ var PRN = (function() { var r = safe_decode_range(ws['!ref']), cell/*:Cell*/; var dense = Array.isArray(ws); for(var R = r.s.r; R <= r.e.r; ++R) { - var oo = []; + var oo/*:Array*/ = []; for(var C = r.s.c; C <= r.e.c; ++C) { var coord = encode_cell({r:R,c:C}); cell = dense ? (ws[R]||[])[C] : ws[coord]; diff --git a/bits/42_sstxml.js b/bits/42_sstxml.js index be2aea0..c36cb2f 100644 --- a/bits/42_sstxml.js +++ b/bits/42_sstxml.js @@ -1,27 +1,3 @@ -/* 18.4.1 charset to codepage mapping */ -var CS2CP = ({ - /*::[*/0/*::]*/: 1252, /* ANSI */ - /*::[*/1/*::]*/: 65001, /* DEFAULT */ - /*::[*/2/*::]*/: 65001, /* SYMBOL */ - /*::[*/77/*::]*/: 10000, /* MAC */ - /*::[*/128/*::]*/: 932, /* SHIFTJIS */ - /*::[*/129/*::]*/: 949, /* HANGUL */ - /*::[*/130/*::]*/: 1361, /* JOHAB */ - /*::[*/134/*::]*/: 936, /* GB2312 */ - /*::[*/136/*::]*/: 950, /* CHINESEBIG5 */ - /*::[*/161/*::]*/: 1253, /* GREEK */ - /*::[*/162/*::]*/: 1254, /* TURKISH */ - /*::[*/163/*::]*/: 1258, /* VIETNAMESE */ - /*::[*/177/*::]*/: 1255, /* HEBREW */ - /*::[*/178/*::]*/: 1256, /* ARABIC */ - /*::[*/186/*::]*/: 1257, /* BALTIC */ - /*::[*/204/*::]*/: 1251, /* RUSSIAN */ - /*::[*/222/*::]*/: 874, /* THAI */ - /*::[*/238/*::]*/: 1250, /* EASTEUROPE */ - /*::[*/255/*::]*/: 1252, /* OEM */ - /*::[*/69/*::]*/: 6969 /* MISC */ -}/*:any*/); - /* Parse a list of tags */ var parse_rs = (function parse_rs_factory() { var tregex = matchtag("t"), rpregex = matchtag("rPr"), rregex = /<(?:\w+:)?r>/g, rend = /<\/(?:\w+:)?r>/, nlregex = /\r\n/g; @@ -122,7 +98,7 @@ var parse_rs = (function parse_rs_factory() { if(y[0].charCodeAt(1) !== 47) throw 'Unrecognized rich format ' + y[0]; } } - var style = []; + var style/*:Array*/ = []; if(font.u) style.push("text-decoration: underline;"); if(font.uval) style.push("text-underline-style:" + font.uval + ";"); @@ -145,14 +121,14 @@ var parse_rs = (function parse_rs_factory() { /* 18.4.4 r CT_RElt */ function parse_r(r) { - var terms = [[],"",[]]; + var terms/*:[Array, string, Array]*/ = [[],"",[]]; /* 18.4.12 t ST_Xstring */ var t = r.match(tregex), cp = 65001; - if(!isval(t)/*:: || !t*/) return ""; + if(!t) return ""; terms[1] = t[1]; var rpr = r.match(rpregex); - if(isval(rpr)/*:: && rpr*/) cp = parse_rpr(rpr[1], terms[0], terms[2]); + if(rpr) cp = parse_rpr(rpr[1], terms[0], terms[2]); return terms[0].join("") + terms[1].replace(nlregex,'
') + terms[2].join(""); } @@ -196,7 +172,7 @@ function parse_sst_xml(data/*:string*/, opts)/*:SST*/ { if(!data) return s; /* 18.4.9 sst CT_Sst */ var sst = data.match(sstr0); - if(isval(sst)/*:: && sst*/) { + if(sst) { ss = sst[2].replace(sstr1,"").split(sstr2); for(var i = 0; i != ss.length; ++i) { var o = parse_si(ss[i].trim(), opts); diff --git a/bits/44_offcrypto.js b/bits/44_offcrypto.js index 617f636..d4185e4 100644 --- a/bits/44_offcrypto.js +++ b/bits/44_offcrypto.js @@ -1,6 +1,6 @@ function _JS2ANSI(str/*:string*/)/*:Array*/ { - if(typeof cptable !== 'undefined') return cptable.utils.encode(1252, str); - var o = [], oo = str.split(""); + if(typeof cptable !== 'undefined') return cptable.utils.encode(current_ansi, str); + var o/*:Array*/ = [], oo = str.split(""); for(var i = 0; i < oo.length; ++i) o[i] = oo[i].charCodeAt(0); return o; } @@ -31,14 +31,9 @@ function parse_DataSpaceMapEntry(blob) { var end = blob.l + len - 4; var o = {}; var cnt = blob.read_shift(4); - var comps = []; - while(cnt-- > 0) { - /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */ - var rc = {}; - rc.t = blob.read_shift(4); - rc.v = blob.read_shift(0, 'lpp4'); - comps.push(rc); - } + var comps/*:Array<{t:number, v:string}>*/ = []; + /* [MS-OFFCRYPTO] 2.1.6.2 DataSpaceReferenceComponent Structure */ + while(cnt-- > 0) comps.push({ t: blob.read_shift(4), v: blob.read_shift(0, 'lpp4') }); o.name = blob.read_shift(0, 'lpp4'); o.comps = comps; if(blob.l != end) throw new Error("Bad DataSpaceMapEntry: " + blob.l + " != " + end); @@ -55,8 +50,8 @@ function parse_DataSpaceMap(blob, length) { } /* [MS-OFFCRYPTO] 2.1.7 DataSpaceDefinition */ -function parse_DataSpaceDefinition(blob, length) { - var o = []; +function parse_DataSpaceDefinition(blob, length)/*:Array*/ { + var o/*:Array*/ = []; blob.l += 4; // must be 0x8 var cnt = blob.read_shift(4); while(cnt-- > 0) o.push(blob.read_shift(0, 'lpp4')); diff --git a/bits/47_styxml.js b/bits/47_styxml.js index 95ad262..349890e 100644 --- a/bits/47_styxml.js +++ b/bits/47_styxml.js @@ -321,7 +321,7 @@ function parse_cellXfs(t, styles, opts) { } function write_cellXfs(cellXfs)/*:string*/ { - var o = []; + var o/*:Array*/ = []; o[o.length] = (writextag('cellXfs',null)); cellXfs.forEach(function(c) { o[o.length] = (writextag('xf', null, c)); }); o[o.length] = (""); diff --git a/bits/48_stybin.js b/bits/48_stybin.js index f7f4664..ba2979a 100644 --- a/bits/48_stybin.js +++ b/bits/48_stybin.js @@ -206,7 +206,7 @@ function parse_sty_bin(data, themes, opts) { styles.CellXf = []; styles.Fonts = []; - var state = []; + var state/*:Array*/ = []; var pass = false; recordhopper(data, function hopper_sty(val, R_n, RT) { switch(RT) { diff --git a/bits/50_styxls.js b/bits/50_styxls.js index 5125c1b..1957e13 100644 --- a/bits/50_styxls.js +++ b/bits/50_styxls.js @@ -1,8 +1,15 @@ /* [MS-XLS] 2.4.326 TODO: payload is a zip file */ function parse_Theme(blob, length, opts) { + var end = blob.l + length; var dwThemeVersion = blob.read_shift(4); if(dwThemeVersion === 124226) return; - blob.l += length-4; + if(!opts.cellStyles || !jszip) { blob.l = end; return; } + var data = blob.slice(blob.l); + blob.l = end; + var zip; try { zip = new jszip(data); } catch(e) { return; } + var themeXML = getzipstr(zip, "theme/theme/theme1.xml", true); + if(!themeXML) return; + return parse_theme_xml(themeXML, opts); } /* 2.5.49 */ @@ -35,7 +42,7 @@ function parse_XFExtGradient(blob, length) { } /* 2.5.108 */ -function parse_ExtProp(blob, length) { +function parse_ExtProp(blob, length)/*:Array*/ { var extType = blob.read_shift(2); var cb = blob.read_shift(2); var o = [extType]; @@ -57,7 +64,7 @@ function parse_XFExt(blob, length) { var ixfe = blob.read_shift(2); blob.l += 2; var cexts = blob.read_shift(2); - var ext = []; + var ext/*:AOA*/ = []; while(cexts-- > 0) ext.push(parse_ExtProp(blob, end-blob.l)); return {ixfe:ixfe, ext:ext}; } diff --git a/bits/56_cmntcommon.js b/bits/56_cmntcommon.js index 4931e96..cce3e65 100644 --- a/bits/56_cmntcommon.js +++ b/bits/56_cmntcommon.js @@ -18,9 +18,9 @@ function parse_comments(zip, dirComments, sheets, sheetRels, opts) { } } -function insertCommentsIntoSheet(sheetName, sheet, comments) { +function insertCommentsIntoSheet(sheetName, sheet, comments/*:Array*/) { var dense = Array.isArray(sheet); - var cell, r; + var cell/*:Cell*/, r; comments.forEach(function(comment) { if(dense) { r = decode_cell(comment.ref); @@ -42,7 +42,7 @@ function insertCommentsIntoSheet(sheetName, sheet, comments) { } if (!cell.c) cell.c = []; - var o = ({a: comment.author, t: comment.t, r: comment.r}/*:any*/); + var o/*:Comment*/ = ({a: comment.author, t: comment.t, r: comment.r}); if(comment.h) o.h = comment.h; cell.c.push(o); }); diff --git a/bits/57_cmntxml.js b/bits/57_cmntxml.js index 87e5854..2630988 100644 --- a/bits/57_cmntxml.js +++ b/bits/57_cmntxml.js @@ -1,9 +1,9 @@ /* 18.7 Comments */ -function parse_comments_xml(data/*:string*/, opts)/*:Array*/ { +function parse_comments_xml(data/*:string*/, opts)/*:Array*/ { /* 18.7.6 CT_Comments */ if(data.match(/<(?:\w+:)?comments *\/>/)) return []; - var authors = []; - var commentList = []; + var authors/*:Array*/ = []; + var commentList/*:Array*/ = []; var authtag = data.match(/<(?:\w+:)?authors>([\s\S]*)<\/(?:\w+:)?authors>/); if(authtag && authtag[1]) authtag[1].split(/<\/\w*:?author>/).forEach(function(x) { if(x === "" || x.trim() === "") return; @@ -16,7 +16,7 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array*/ { var cm = x.match(/<(?:\w+:)?comment[^>]*>/); if(!cm) return; var y = parsexmltag(cm[0]); - var comment/*:Comment*/ = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/); + var comment/*:RawComment*/ = ({ author: y.authorId && authors[y.authorId] || "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/); var cell = decode_cell(y.ref); if(opts.sheetRows && opts.sheetRows <= cell.r) return; var textMatch = x.match(/<(?:\w+:)?text>([\s\S]*)<\/(?:\w+:)?text>/); @@ -34,7 +34,7 @@ var CMNT_XML_ROOT = writextag('comments', null, { 'xmlns': XMLNS.main[0] }); function write_comments_xml(data, opts) { var o = [XML_HEADER, CMNT_XML_ROOT]; - var iauthor = []; + var iauthor/*:Array*/ = []; o.push(""); data.map(function(x) { return x[1]; }).forEach(function(comment) { comment.map(function(x) { return escapexml(x.a); }).forEach(function(a) { diff --git a/bits/58_cmntbin.js b/bits/58_cmntbin.js index a44ba37..a44222e 100644 --- a/bits/58_cmntbin.js +++ b/bits/58_cmntbin.js @@ -24,9 +24,9 @@ var parse_BrtCommentAuthor = parse_XLWideString; function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); } /* [MS-XLSB] 2.1.7.8 Comments */ -function parse_comments_bin(data, opts) { - var out = []; - var authors = []; +function parse_comments_bin(data, opts)/*:Array*/ { + var out/*:Array*/ = []; + var authors/*:Array*/ = []; var c = {}; var pass = false; recordhopper(data, function hopper_cmnt(val, R_n, RT) { @@ -65,33 +65,32 @@ function parse_comments_bin(data, opts) { function write_comments_bin(data, opts) { var ba = buf_array(); - var iauthor = []; + var iauthor/*:Array*/ = []; write_record(ba, "BrtBeginComments"); - { /* COMMENTAUTHORS */ - write_record(ba, "BrtBeginCommentAuthors"); - data.forEach(function(comment) { - comment[1].forEach(function(c) { - if(iauthor.indexOf(c.a) > -1) return; - iauthor.push(c.a.slice(0,54)); - write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a)); - }); + + write_record(ba, "BrtBeginCommentAuthors"); + data.forEach(function(comment) { + comment[1].forEach(function(c) { + if(iauthor.indexOf(c.a) > -1) return; + iauthor.push(c.a.slice(0,54)); + write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a)); }); - write_record(ba, "BrtEndCommentAuthors"); - } - { /* COMMENTLIST */ - write_record(ba, "BrtBeginCommentList"); - data.forEach(function(comment) { - comment[1].forEach(function(c) { - c.iauthor = iauthor.indexOf(c.a); - var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])}; - write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c])); - if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c)); - write_record(ba, "BrtEndComment"); - delete c.iauthor; - }); + }); + write_record(ba, "BrtEndCommentAuthors"); + + write_record(ba, "BrtBeginCommentList"); + data.forEach(function(comment) { + comment[1].forEach(function(c) { + c.iauthor = iauthor.indexOf(c.a); + var range = {s:decode_cell(comment[0]),e:decode_cell(comment[0])}; + write_record(ba, "BrtBeginComment", write_BrtBeginComment([range, c])); + if(c.t && c.t.length > 0) write_record(ba, "BrtCommentText", write_BrtCommentText(c)); + write_record(ba, "BrtEndComment"); + delete c.iauthor; }); - write_record(ba, "BrtEndCommentList"); - } + }); + write_record(ba, "BrtEndCommentList"); + write_record(ba, "BrtEndComments"); return ba.end(); } diff --git a/bits/59_vba.js b/bits/59_vba.js index 342cbd2..cb0fdec 100644 --- a/bits/59_vba.js +++ b/bits/59_vba.js @@ -16,3 +16,5 @@ function fill_vba_xls(cfb/*:CFBContainer*/, vba/*:CFBContainer*/)/*:void*/ { }); } +var VBAFMTS = [ "xlsb", "xlsm", "xlam", "biff8", "xla" ]; + diff --git a/bits/61_fcommon.js b/bits/61_fcommon.js index 1590c40..dfc10b8 100644 --- a/bits/61_fcommon.js +++ b/bits/61_fcommon.js @@ -46,3 +46,7 @@ function fuzzyfmla(f/*:string*/)/*:boolean*/ { if(f.length == 1) return false; return true; } + +function _xlfn(f/*:string*/)/*:string*/ { + return f.replace(/_xlfn\./g,""); +} diff --git a/bits/62_fxls.js b/bits/62_fxls.js index a3873ff..73af107 100644 --- a/bits/62_fxls.js +++ b/bits/62_fxls.js @@ -149,10 +149,10 @@ function parse_PtgAttrBaxcel(blob, length) { } /* 2.5.198.34 */ -function parse_PtgAttrChoose(blob, length, opts) { +function parse_PtgAttrChoose(blob, length, opts)/*:Array*/ { blob.l +=2; var offset = blob.read_shift(opts && opts.biff == 2 ? 1 : 2); - var o = []; + var o/*:Array*/ = []; /* offset is 1 less than the number of elements */ for(var i = 0; i <= offset; ++i) o.push(blob.read_shift(opts && opts.biff == 2 ? 1 : 2)); return o; @@ -318,7 +318,7 @@ function parse_SerAr(blob, biff/*:number*/) { /* 2.5.198.61 */ function parse_PtgExtraMem(blob, cce) { var count = blob.read_shift(2); - var out = []; + var out/*:Array*/ = []; for(var i = 0; i != count; ++i) out.push(parse_Ref8U(blob, 8)); return out; } @@ -335,7 +335,7 @@ function parse_PtgExtraArray(blob, length, opts) { } if(opts.biff >= 2 && opts.biff < 8) { --rows; if(--cols == 0) cols = 0x100; } // $FlowIgnore - for(var i = 0, o/*:Array >*/=[]; i != rows && (o[i] = []); ++i) + for(var i = 0, o/*:Array>*/ = []; i != rows && (o[i] = []); ++i) for(var j = 0; j != cols; ++j) o[i][j] = parse_SerAr(blob, opts.biff); return o; } @@ -655,10 +655,10 @@ function parse_Rgce(blob, length, opts) { return ptgs; } -function stringify_array(f/*:Array>*/)/*:string*/ { - var o = []; +function stringify_array(f/*:Array>*/)/*:string*/ { + var o/*:Array*/ = []; for(var i = 0; i < f.length; ++i) { - var x = f[i], r = []; + var x = f[i], r/*:Array*/ = []; for(var j = 0; j < x.length; ++j) { var y = x[j]; if(y) switch(y[0]) { @@ -713,10 +713,10 @@ function get_ixti_raw(supbooks, ixti/*:number*/, opts)/*:string*/ { return XTI[1] == XTI[2] ? o : o + ":" + supbooks.SheetNames[XTI[2]]; case 0x0166: /* 'BrtSupSame' */ if(opts.SID != null) return supbooks.SheetNames[opts.SID]; - return "SH33TJSERR" + supbooks[XTI[0]][0]; + return "SH33TJSSAME" + supbooks[XTI[0]][0]; case 0x0163: /* 'BrtSupBookSrc' */ /* falls through */ - default: return "SH33TJSERR" + supbooks[XTI[0]][0]; + default: return "SH33TJSSRC" + supbooks[XTI[0]][0]; } switch(supbooks[XTI[0]][0][0]) { case 0x0401: @@ -863,7 +863,7 @@ function stringify_formula(formula/*Array*/, range, cell/*:any*/, supbooks, /* f[1] = type, 0, nameindex */ nameidx = (f[1][2]/*:any*/); var lbl = (supbooks.names||[])[nameidx-1] || (supbooks[0]||[])[nameidx]; - var name = lbl ? lbl.Name : "SH33TJSERR7" + String(nameidx); + var name = lbl ? lbl.Name : "SH33TJSNAME" + String(nameidx); if(name in XLSXFutureFunctions) name = XLSXFutureFunctions[name]; stack.push(name); break; @@ -944,7 +944,7 @@ function stringify_formula(formula/*Array*/, range, cell/*:any*/, supbooks, break; case 'PtgArray': /* 2.5.198.32 TODO */ - stack.push("{" + stringify_array(f[1]) + "}"); + stack.push("{" + stringify_array(/*::(*/f[1]/*:: :any)*/) + "}"); break; case 'PtgMemArea': /* 2.5.198.70 TODO: confirm this is a non-display */ diff --git a/bits/64_ftab.js b/bits/64_ftab.js index 502cf7d..7577485 100644 --- a/bits/64_ftab.js +++ b/bits/64_ftab.js @@ -1158,6 +1158,7 @@ var XLSXFutureFunctions = { "_xlfn.CHISQ.INV.RT": "CHISQ.INV.RT", "_xlfn.CHISQ.TEST": "CHISQ.TEST", "_xlfn.COMBINA": "COMBINA", + "_xlfn.CONCAT": "CONCAT", "_xlfn.CONFIDENCE.NORM": "CONFIDENCE.NORM", "_xlfn.CONFIDENCE.T": "CONFIDENCE.T", "_xlfn.COT": "COT", @@ -1181,6 +1182,11 @@ var XLSXFutureFunctions = { "_xlfn.FILTERXML": "FILTERXML", "_xlfn.FLOOR.MATH": "FLOOR.MATH", "_xlfn.FLOOR.PRECISE": "FLOOR.PRECISE", + "_xlfn.FORECAST.ETS": "FORECAST.ETS", + "_xlfn.FORECAST.ETS.CONFINT": "FORECAST.ETS.CONFINT", + "_xlfn.FORECAST.ETS.SEASONALITY": "FORECAST.ETS.SEASONALITY", + "_xlfn.FORECAST.ETS.STAT": "FORECAST.ETS.STAT", + "_xlfn.FORECAST.LINEAR": "FORECAST.LINEAR", "_xlfn.FORMULATEXT": "FORMULATEXT", "_xlfn.GAMMA": "GAMMA", "_xlfn.GAMMA.DIST": "GAMMA.DIST", @@ -1188,8 +1194,8 @@ var XLSXFutureFunctions = { "_xlfn.GAMMALN.PRECISE": "GAMMALN.PRECISE", "_xlfn.GAUSS": "GAUSS", "_xlfn.HYPGEOM.DIST": "HYPGEOM.DIST", - "_xlfn.IFNA": "IFNA", "_xlfn.IFERROR": "IFERROR", + "_xlfn.IFNA": "IFNA", "_xlfn.IMCOSH": "IMCOSH", "_xlfn.IMCOT": "IMCOT", "_xlfn.IMCSC": "IMCSC", @@ -1203,6 +1209,8 @@ var XLSXFutureFunctions = { "_xlfn.ISOWEEKNUM": "ISOWEEKNUM", "_xlfn.LOGNORM.DIST": "LOGNORM.DIST", "_xlfn.LOGNORM.INV": "LOGNORM.INV", + "_xlfn.MAXIFS": "MAXIFS", + "_xlfn.MINIFS": "MINIFS", "_xlfn.MODE.MULT": "MODE.MULT", "_xlfn.MODE.SNGL": "MODE.SNGL", "_xlfn.MUNIT": "MUNIT", @@ -1242,6 +1250,7 @@ var XLSXFutureFunctions = { "_xlfn.T.INV": "T.INV", "_xlfn.T.INV.2T": "T.INV.2T", "_xlfn.T.TEST": "T.TEST", + "_xlfn.TEXTJOIN": "TEXTJOIN", "_xlfn.UNICHAR": "UNICHAR", "_xlfn.UNICODE": "UNICODE", "_xlfn.VAR.P": "VAR.P", diff --git a/bits/66_wscommon.js b/bits/66_wscommon.js index d70cd70..2bd5422 100644 --- a/bits/66_wscommon.js +++ b/bits/66_wscommon.js @@ -37,12 +37,13 @@ function default_margins(margins/*:Margins*/, mode/*:?string*/) { if(margins.footer == null) margins.footer = defs[5]; } -function get_cell_style(styles, cell, opts) { +function get_cell_style(styles/*:Array*/, cell/*:Cell*/, opts) { var z = opts.revssf[cell.z != null ? cell.z : "General"]; var i = 0x3c, len = styles.length; if(z == null && opts.ssf) { for(; i < 0x188; ++i) if(opts.ssf[i] == null) { SSF.load(cell.z, i); + // $FlowIgnore opts.ssf[i] = cell.z; opts.revssf[cell.z] = z = i; break; @@ -60,7 +61,7 @@ function get_cell_style(styles, cell, opts) { return len; } -function safe_format(p, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles) { +function safe_format(p/*:Cell*/, fmtid/*:number*/, fillid/*:?number*/, opts, themes, styles) { if(p.t === 'z') return; if(p.t === 'd' && typeof p.v === 'string') p.v = parseDate(p.v); try { diff --git a/bits/67_wsxml.js b/bits/67_wsxml.js index aa3566a..10dc5be 100644 --- a/bits/67_wsxml.js +++ b/bits/67_wsxml.js @@ -1,4 +1,4 @@ -function parse_ws_xml_dim(ws, s) { +function parse_ws_xml_dim(ws/*:Worksheet*/, s/*:string*/) { var d = safe_decode_range(s); if(d.s.r<=d.e.r && d.s.c<=d.e.c && d.s.r>=0 && d.s.c>=0) ws["!ref"] = encode_range(d); } @@ -10,8 +10,9 @@ var colregex = /<(?:\w:)?col[^>]*[\/]?>/g; var afregex = /<(?:\w:)?autoFilter[^>]*([\/]|>([\s\S]*)<\/(?:\w:)?autoFilter)>/g; var marginregex= /<(?:\w:)?pageMargins[^>]*\/>/g; var sheetprregex = /<(?:\w:)?sheetPr(?:[^>a-z][^>]*)?\/>/; +var svsregex = /<(?:\w:)?sheetViews[^>]*(?:[\/]|>([\s\S]*)<\/(?:\w:)?sheetViews)>/; /* 18.3 Worksheets */ -function parse_ws_xml(data/*:?string*/, opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ { +function parse_ws_xml(data/*:?string*/, opts, idx/*:number*/, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ { if(!data) return data; if(DENSE != null && opts.dense == null) opts.dense = DENSE; @@ -30,7 +31,7 @@ function parse_ws_xml(data/*:?string*/, opts, idx, rels, wb/*:WBWBProps*/, theme var sheetPr = data1.match(sheetprregex); if(sheetPr) parse_ws_xml_sheetpr(sheetPr[0], s, wb, idx); - /* 18.3.1.35 dimension CT_SheetDimension ? */ + /* 18.3.1.35 dimension CT_SheetDimension */ // $FlowIgnore var ridx = (data1.match(/<(?:\w*:)?dimension/)||{index:-1}).index; if(ridx > 0) { @@ -38,8 +39,12 @@ function parse_ws_xml(data/*:?string*/, opts, idx, rels, wb/*:WBWBProps*/, theme if(ref) parse_ws_xml_dim(s, ref[1]); } + /* 18.3.1.88 sheetViews CT_SheetViews */ + var svs = data1.match(svsregex); + if(svs && svs[1]) parse_ws_xml_sheetviews(svs[1], wb); + /* 18.3.1.17 cols CT_Cols */ - var columns = []; + var columns/*:Array*/ = []; if(opts.cellStyles) { /* 18.3.1.13 col CT_Col */ var cols = data1.match(colregex); @@ -54,10 +59,10 @@ function parse_ws_xml(data/*:?string*/, opts, idx, rels, wb/*:WBWBProps*/, theme if(afilter) s['!autofilter'] = parse_ws_xml_autofilter(afilter[0]); /* 18.3.1.55 mergeCells CT_MergeCells */ - var mergecells = []; - var merges = data2.match(mergecregex); - if(merges) for(ridx = 0; ridx != merges.length; ++ridx) - mergecells[ridx] = safe_decode_range(merges[ridx].substr(merges[ridx].indexOf("\"")+1)); + var merges/*:Array*/ = []; + var _merge = data2.match(mergecregex); + if(_merge) for(ridx = 0; ridx != _merge.length; ++ridx) + merges[ridx] = safe_decode_range(_merge[ridx].substr(_merge[ridx].indexOf("\"")+1)); /* 18.3.1.48 hyperlinks CT_Hyperlinks */ var hlink = data2.match(hlinkregex); @@ -81,11 +86,11 @@ function parse_ws_xml(data/*:?string*/, opts, idx, rels, wb/*:WBWBProps*/, theme } } if(columns.length > 0) s["!cols"] = columns; - if(mergecells.length > 0) s["!merges"] = mergecells; + if(merges.length > 0) s["!merges"] = merges; return s; } -function write_ws_xml_merges(merges) { +function write_ws_xml_merges(merges/*:Array*/)/*:string*/ { if(merges.length === 0) return ""; var o = ''; for(var i = 0; i != merges.length; ++i) o += ''; @@ -154,7 +159,7 @@ function parse_ws_xml_margins(margin) { }); return o; } -function write_ws_xml_margins(margin) { +function write_ws_xml_margins(margin)/*:string*/ { default_margins(margin); return writextag('pageMargins', null, margin); } @@ -182,7 +187,7 @@ function write_ws_xml_cols(ws, cols)/*:string*/ { return o.join(""); } -function parse_ws_xml_autofilter(data) { +function parse_ws_xml_autofilter(data/*:string*/) { var o = { ref: (data.match(/ref="([^"]*)"/)||[])[1]}; return o; } @@ -192,6 +197,17 @@ function write_ws_xml_autofilter(data)/*:string*/ { /* 18.3.1.88 sheetViews CT_SheetViews */ /* 18.3.1.87 sheetView CT_SheetView */ +var sviewregex = /<(?:\w:)?sheetView(?:[^>a-z][^>]*)?\/>/; +function parse_ws_xml_sheetviews(data, wb/*:WBWBProps*/) { + (data.match(sviewregex)||[]).forEach(function(r/*:string*/) { + var tag = parsexmltag(r); + if(parsexmlbool(tag.rightToLeft)) { + if(!wb.Views) wb.Views = [{}]; + if(!wb.Views[0]) wb.Views[0] = {}; + wb.Views[0].RTL = true; + } + }); +} function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ { var sview = {workbookViewId:"0"}; // $FlowIgnore @@ -199,7 +215,7 @@ function write_ws_xml_sheetviews(ws, opts, idx, wb)/*:string*/ { return writextag("sheetViews", writextag("sheetView", null, sview), {}); } -function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) { +function write_ws_xml_cell(cell/*:Cell*/, ref, ws, opts, idx, wb)/*:string*/ { if(cell.v === undefined && cell.f === undefined || cell.t === 'z') return ""; var vv = ""; var oldt = cell.t, oldv = cell.v; @@ -244,22 +260,22 @@ function write_ws_xml_cell(cell, ref, ws, opts, idx, wb) { return writextag('c', v, o); } -var parse_ws_xml_data = (function parse_ws_xml_data_factory() { +var parse_ws_xml_data = (function() { var cellregex = /<(?:\w+:)?c[ >]/, rowregex = /<\/(?:\w+:)?row>/; var rregex = /r=["']([^"']*)["']/, isregex = /<(?:\w+:)?is>([\S\s]*?)<\/(?:\w+:)?is>/; var refregex = /ref=["']([^"']*)["']/; var match_v = matchtag("v"), match_f = matchtag("f"); -return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { - var ri = 0, x = "", cells = [], cref = [], idx=0, i=0, cc=0, d="", p/*:any*/; +return function parse_ws_xml_data(sdata/*:string*/, s, opts, guess/*:Range*/, themes, styles) { + var ri = 0, x = "", cells/*:Array*/ = [], cref/*:?Array*/ = [], idx=0, i=0, cc=0, d="", p/*:any*/; var tag, tagr = 0, tagc = 0; var sstr, ftag; var fmtid = 0, fillid = 0; var do_format = Array.isArray(styles.CellXf), cf; - var arrayf = []; + var arrayf/*:Array<[Range, string]>*/ = []; var sharedf = []; var dense = Array.isArray(s); - var rows = [], rowobj = {}, rowrite = false; + var rows/*:Array*/ = [], rowobj = {}, rowrite = false; for(var marr = sdata.split(rowregex), mt = 0, marrlen = marr.length; mt != marrlen; ++mt) { x = marr[mt].trim(); var xlen = x.length; @@ -307,14 +323,14 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { if(opts.cellFormula) { if((cref=d.match(match_f))!= null && /*::cref != null && */cref[1] !== '') { /* TODO: match against XLSXFutureFunctions */ - p.f=unescapexml(utf8read(cref[1])).replace(/_xlfn\./,""); + p.f=_xlfn(unescapexml(utf8read(cref[1]))); if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="array"') > -1) { p.F = (d.match(refregex)||[])[1]; if(p.F.indexOf(":") > -1) arrayf.push([safe_decode_range(p.F), p.F]); } else if(/*::cref != null && cref[0] != null && */cref[0].indexOf('t="shared"') > -1) { // TODO: parse formula ftag = parsexmltag(cref[0]); - sharedf[parseInt(ftag.si, 10)] = [ftag, unescapexml(utf8read(cref[1]))]; + sharedf[parseInt(ftag.si, 10)] = [ftag, _xlfn(unescapexml(utf8read(cref[1])))]; } } else if((cref=d.match(/]*\/>/))) { ftag = parsexmltag(cref[0]); @@ -400,7 +416,7 @@ return function parse_ws_xml_data(sdata, s, opts, guess, themes, styles) { }; })(); function write_ws_xml_data(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/, rels)/*:string*/ { - var o = [], r = [], range = safe_decode_range(ws['!ref']), cell, ref, rr = "", cols = [], R=0, C=0, rows = ws['!rows']; + var o/*:Array*/ = [], r/*:Array*/ = [], range = safe_decode_range(ws['!ref']), cell="", ref, rr = "", cols/*:Array*/ = [], R=0, C=0, rows = ws['!rows']; var dense = Array.isArray(ws); var params = ({r:rr}/*:any*/), row/*:RowInfo*/, height = -1; for(C = range.s.c; C <= range.e.c; ++C) cols[C] = encode_col(C); diff --git a/bits/68_wsbin.js b/bits/68_wsbin.js index f2a24a1..360f6d0 100644 --- a/bits/68_wsbin.js +++ b/bits/68_wsbin.js @@ -335,6 +335,11 @@ function write_BrtMargins(margins/*:Margins*/, o) { } /* [MS-XLSB] 2.4.292 BrtBeginWsView */ +function parse_BrtBeginWsView(data, length, opts) { + var f = data.read_shift(2); + data.l += 28; + return { RTL: f & 0x20 }; +} function write_BrtBeginWsView(ws, Workbook, o) { if(o == null) o = new_buf(30); var f = 0x39c; @@ -385,7 +390,7 @@ function write_BrtSheetProtection(sp, o) { } /* [MS-XLSB] 2.1.7.61 Worksheet */ -function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ { +function parse_ws_bin(data, _opts, idx, rels, wb/*:WBWBProps*/, themes, styles)/*:Worksheet*/ { if(!data) return data; var opts = _opts || {}; if(!rels) rels = {'!id':{}}; @@ -397,24 +402,24 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ var pass = false, end = false; var row, p, cf, R, C, addr, sstr, rr, cell/*:Cell*/; - var mergecells = []; + var merges/*:Array*/ = []; opts.biff = 12; opts['!row'] = 0; var ai = 0, af = false; - var array_formulae = []; - var shared_formulae = {}; + var arrayf/*:Array<[Range, string]>*/ = []; + var sharedf = {}; var supbooks = opts.supbooks || ([[]]/*:any*/); - supbooks.sharedf = shared_formulae; - supbooks.arrayf = array_formulae; + supbooks.sharedf = sharedf; + supbooks.arrayf = arrayf; supbooks.SheetNames = wb.SheetNames || wb.Sheets.map(function(x) { return x.name; }); if(!opts.supbooks) { opts.supbooks = supbooks; - for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i]; + if(wb.Names) for(var i = 0; i < wb.Names.length; ++i) supbooks[0][i+1] = wb.Names[i]; } - var colinfo = [], rowinfo = []; + var colinfo/*:Array*/ = [], rowinfo/*:Array*/ = []; var seencol = false; recordhopper(data, function ws_parse(val, R_n, RT) { @@ -457,8 +462,8 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ else s[encode_col(C) + rr] = p; if(opts.cellFormula) { af = false; - for(ai = 0; ai < array_formulae.length; ++ai) { - var aii = array_formulae[ai]; + for(ai = 0; ai < arrayf.length; ++ai) { + var aii = arrayf[ai]; if(row.r >= aii[0].s.r && row.r <= aii[0].e.r) if(C >= aii[0].s.c && C <= aii[0].e.c) { p.F = encode_range(aii[0]); af = true; @@ -488,7 +493,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ break; case 0x00B0: /* 'BrtMergeCell' */ - mergecells.push(val); break; + merges.push(val); break; case 0x01EE: /* 'BrtHLink' */ var rel = rels['!id'][val.relId]; @@ -514,14 +519,14 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ case 0x01AA: /* 'BrtArrFmla' */ if(!opts.cellFormula) break; - array_formulae.push(val); + arrayf.push(val); cell = ((opts.dense ? s[R][C] : s[encode_col(C) + rr])/*:any*/); cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); cell.F = encode_range(val[0]); break; case 0x01AB: /* 'BrtShrFmla' */ if(!opts.cellFormula) break; - shared_formulae[encode_cell(val[0].s)] = val[1]; + sharedf[encode_cell(val[0].s)] = val[1]; cell = (opts.dense ? s[R][C] : s[encode_col(C) + rr]); cell.f = stringify_formula(val[1], refguess, {r:row.r, c:C}, supbooks, opts); break; @@ -549,6 +554,12 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ if(val.name) wb.Sheets[idx].CodeName = val.name; break; + case 0x0089: /* 'BrtBeginWsView' */ + if(!wb.Views) wb.Views = [{}]; + if(!wb.Views[0]) wb.Views[0] = {}; + if(val.RTL) wb.Views[0].RTL = true; + break; + case 0x01E5: /* 'BrtWsFmtInfo' */ /* case 'BrtUid' */ case 0x00AF: /* 'BrtAFilterDateGroupItem' */ @@ -635,7 +646,7 @@ function parse_ws_bin(data, _opts, idx, rels, wb, themes, styles)/*:Worksheet*/ s["!ref"] = encode_range(tmpref); } } - if(mergecells.length > 0) s["!merges"] = mergecells; + if(merges.length > 0) s["!merges"] = merges; if(colinfo.length > 0) s["!cols"] = colinfo; if(rowinfo.length > 0) s["!rows"] = rowinfo; return s; @@ -687,7 +698,7 @@ function write_ws_bin_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:num } function write_CELLTABLE(ba, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) { - var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols = []; + var range = safe_decode_range(ws['!ref'] || "A1"), ref, rr = "", cols/*:Array*/ = []; write_record(ba, 'BrtBeginSheetData'); var dense = Array.isArray(ws); var cap = range.e.r; diff --git a/bits/69_chartxml.js b/bits/69_chartxml.js index 5cd988e..8b2d0d3 100644 --- a/bits/69_chartxml.js +++ b/bits/69_chartxml.js @@ -1,5 +1,5 @@ -function parse_numCache(data) { - var col = []; +function parse_numCache(data/*:string*/)/*:[Array, string]*/ { + var col/*:Array*/ = []; /* 21.2.2.150 pt CT_NumVal */ (data.match(/(.*?)<\/c:pt>/mg)||[]).forEach(function(pt) { @@ -15,8 +15,8 @@ function parse_numCache(data) { } /* 21.2 DrawingML - Charts */ -function parse_chart(data, name/*:string*/, opts, rels, wb, csheet) { - var cs = ((csheet || {"!type":"chart"})/*:any*/); +function parse_chart(data/*:?string*/, name/*:string*/, opts, rels, wb, csheet) { + var cs/*:Worksheet*/ = ((csheet || {"!type":"chart"})/*:any*/); if(!data) return csheet; /* 21.2.2.27 chart CT_Chart */ diff --git a/bits/70_csheet.js b/bits/70_csheet.js index ffe0b15..151a8d9 100644 --- a/bits/70_csheet.js +++ b/bits/70_csheet.js @@ -43,7 +43,7 @@ function parse_cs_bin(data, opts, idx/*:number*/, rels, wb, themes, styles)/*:Wo if(!data) return data; if(!rels) rels = {'!id':{}}; var s = {'!type':"chart", '!chart':null, '!rel':""}; - var state = []; + var state/*:Array*/ = []; var pass = false; recordhopper(data, function cs_parse(val, R_n, RT) { switch(RT) { diff --git a/bits/72_wbxml.js b/bits/72_wbxml.js index 94c7e08..477fb0d 100644 --- a/bits/72_wbxml.js +++ b/bits/72_wbxml.js @@ -5,7 +5,6 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ { var wb = { AppVersion:{}, WBProps:{}, WBView:[], Sheets:[], CalcPr:{}, Names:[], xmlns: "" }; var pass = false, xmlns = "xmlns"; var dname = {}, dnstart = 0; - /*(data.match(tagregex)||[]).forEach */ data.replace(tagregex, function xml_wb(x, idx) { var y/*:any*/ = parsexmltag(x); switch(strip_ns(y[0])) { diff --git a/bits/74_xmlbin.js b/bits/74_xmlbin.js index 0deff68..5bf9bae 100644 --- a/bits/74_xmlbin.js +++ b/bits/74_xmlbin.js @@ -37,7 +37,7 @@ function parse_sst(data, name/*:string*/, opts)/*:SST*/ { return parse_sst_xml((data/*:any*/), opts); } -function parse_cmnt(data, name/*:string*/, opts) { +function parse_cmnt(data, name/*:string*/, opts)/*:Array*/ { if(name.slice(-4)===".bin") return parse_comments_bin((data/*:any*/), opts); return parse_comments_xml((data/*:any*/), opts); } diff --git a/bits/75_xlml.js b/bits/75_xlml.js index 260def9..9e11359 100644 --- a/bits/75_xlml.js +++ b/bits/75_xlml.js @@ -44,7 +44,7 @@ function xlml_format(format, value)/*:string*/ { return SSF.format(fmt, value); } -function xlml_set_custprop(Custprops, Rn, cp, val/*:string*/) { +function xlml_set_custprop(Custprops, key, cp, val/*:string*/) { var oval/*:any*/ = val; switch((cp[0].match(/dt:dt="([\w.]+)"/)||["",""])[1]) { case "boolean": oval = parsexmlbool(val); break; @@ -54,7 +54,7 @@ function xlml_set_custprop(Custprops, Rn, cp, val/*:string*/) { case "i8": case "string": case "fixed": case "uuid": case "bin.base64": break; default: throw new Error("bad custprop:" + cp[0]); } - Custprops[unescapexml(Rn[3])] = oval; + Custprops[unescapexml(key)] = oval; } function safe_format_xlml(cell/*:Cell*/, nf, o) { @@ -174,7 +174,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { var opts = _opts || {}; make_ssf(SSF); var str = debom(xlml_normalize(d)); - if(opts.type == 'binary' || opts.type == 'base64') { + if(opts.type == 'binary' || opts.type == 'array' || opts.type == 'base64') { if(typeof cptable !== 'undefined') str = cptable.utils.decode(65001, char_codes(str)); else str = utf8read(str); } @@ -184,19 +184,19 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { var Rn; var state = [], tmp; if(DENSE != null && opts.dense == null) opts.dense = DENSE; - var sheets = {}, sheetnames = [], cursheet/*:Worksheet*/ = (opts.dense ? [] : {}), sheetname = ""; + var sheets = {}, sheetnames/*:Array*/ = [], cursheet/*:Worksheet*/ = (opts.dense ? [] : {}), sheetname = ""; var table = {}, cell = ({}/*:any*/), row = {}; var dtag = xlml_parsexmltag(''), didx = 0; var c = 0, r = 0; - var refguess = {s: {r:2000000, c:2000000}, e: {r:0, c:0} }; + var refguess/*:Range*/ = {s: {r:2000000, c:2000000}, e: {r:0, c:0} }; var styles = {}, stag = {}; var ss = "", fidx = 0; - var mergecells = []; - var Props = {}, Custprops = {}, pidx = 0, cp = {}; - var comments = [], comment = {}; + var merges/*:Array*/ = []; + var Props = {}, Custprops = {}, pidx = 0, cp = []; + var comments/*:Array*/ = [], comment/*:Comment*/ = ({}/*:any*/); var cstys = [], csty, seencol = false; - var arrayf = []; - var rowinfo = [], rowobj = {}, cc = 0, rr = 0; + var arrayf/*:Array<[Range, string]>*/ = []; + var rowinfo/*:Array*/ = [], rowobj = {}, cc = 0, rr = 0; var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false} }/*:any*/), wsprops = {}; xlmlregex.lastIndex = 0; str = str.replace(//mg,""); @@ -223,7 +223,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { if(cell.MergeAcross || cell.MergeDown) { cc = c + (parseInt(cell.MergeAcross,10)|0); rr = r + (parseInt(cell.MergeDown,10)|0); - mergecells.push({s:{c:c,r:r},e:{c:cc,r:rr}}); + merges.push({s:{c:c,r:r},e:{c:cc,r:rr}}); } if(!opts.sheetStubs) { if(cell.MergeAcross) c = cc + 1; else ++c; } else if(cell.MergeAcross || cell.MergeDown) { @@ -275,7 +275,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { if((tmp=state.pop())[0]!==Rn[3]) throw new Error("Bad state: "+tmp.join("|")); sheetnames.push(sheetname); if(refguess.s.r <= refguess.e.r && refguess.s.c <= refguess.e.c) cursheet["!ref"] = encode_range(refguess); - if(mergecells.length) cursheet["!merges"] = mergecells; + if(merges.length) cursheet["!merges"] = merges; if(cstys.length > 0) cursheet["!cols"] = cstys; if(rowinfo.length > 0) cursheet["!rows"] = rowinfo; sheets[sheetname] = cursheet; @@ -286,7 +286,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { tmp = xlml_parsexmltag(Rn[0]); sheetname = unescapexml(tmp.Name); cursheet = (opts.dense ? [] : {}); - mergecells = []; + merges = []; arrayf = []; rowinfo = []; wsprops = {name:sheetname, Hidden:0}; @@ -402,7 +402,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { } else { state.push([Rn[3], false]); tmp = xlml_parsexmltag(Rn[0]); - comment = {a:tmp.Author}; + comment = ({a:tmp.Author}/*:any*/); } break; @@ -565,6 +565,12 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { if(pagemargins.Right) cursheet['!margins'].right = pagemargins.Right; if(pagemargins.Bottom) cursheet['!margins'].bottom = pagemargins.Bottom; break; + case 'DisplayRightToLeft': + if(!Workbook.Views) Workbook.Views = []; + if(!Workbook.Views[0]) Workbook.Views[0] = {}; + Workbook.Views[0].RTL = true; + break; + case 'Unsynced': break; case 'Print': break; case 'Panes': break; @@ -806,7 +812,7 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { if(!state[state.length-1][1]) throw 'Unrecognized tag: ' + Rn[3] + "|" + state.join("|"); if(state[state.length-1][0]==='CustomDocumentProperties') { if(Rn[0].slice(-2) === "/>") break; - else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn, cp, str.slice(pidx, Rn.index)); + else if(Rn[1]==="/") xlml_set_custprop(Custprops, Rn[3], cp, str.slice(pidx, Rn.index)); else { cp = Rn; pidx = Rn.index + Rn[0].length; } break; } @@ -822,11 +828,6 @@ function parse_xlml_xml(d, _opts)/*:Workbook*/ { return out; } -function arr2str(data/*:any*/)/*:string*/ { - if(Array.isArray(data)) return data.map(_chr).join(""); - var o = []; for(var i = 0; i < data.length; ++i) o[i] = _chr(data[i]); return o.join(""); -} - function parse_xlml(data/*:RawBytes|string*/, opts)/*:Workbook*/ { fix_read_opts(opts=opts||{}); switch(opts.type||"base64") { @@ -838,8 +839,8 @@ function parse_xlml(data/*:RawBytes|string*/, opts)/*:Workbook*/ { } /* TODO */ -function write_props_xlml(wb, opts) { - var o = []; +function write_props_xlml(wb/*:Workbook*/, opts)/*:string*/ { + var o/*:Array*/ = []; /* DocumentProperties */ if(wb.Props) o.push(xlml_write_docprops(wb.Props, opts)); /* CustomDocumentProperties */ @@ -847,7 +848,7 @@ function write_props_xlml(wb, opts) { return o.join(""); } /* TODO */ -function write_wb_xlml(wb, opts) { +function write_wb_xlml(wb, opts)/*:string*/ { /* OfficeDocumentSettings */ /* ExcelWorkbook */ return ""; @@ -855,12 +856,18 @@ function write_wb_xlml(wb, opts) { /* TODO */ function write_sty_xlml(wb, opts)/*:string*/ { /* Styles */ - return ""; + var styles/*:Array*/ = ['']; + opts.cellXfs.forEach(function(xf, id) { + var payload/*:Array*/ = []; + payload.push(writextag('NumberFormat', null, {"ss:Format": escapexml(SSF._table[xf.numFmtId])})); + styles.push(writextag('Style', payload.join(""), {"ss:ID": "s" + (21+id)})); + }); + return writextag("Styles", styles.join("")); } /* WorksheetOptions */ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ { if(!ws) return ""; - var o = []; + var o/*:Array*/ = []; /* NOTE: spec technically allows any order, but stick with implied order */ /* FitToPage */ @@ -913,7 +920,10 @@ function write_ws_xlml_wsopts(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workb } /* LeftColumnVisible */ - /* DisplayRightToLeft */ + + // $FlowIgnore + if(((((wb||{}).Workbook||{}).Views||[])[0]||{}).RTL) o.push(""); + /* GridlineColorIndex */ /* DisplayFormulas */ /* DoNotDisplayGridlines */ @@ -1001,9 +1011,12 @@ function write_ws_xlml_cell(cell, ref/*:string*/, ws, opts, idx/*:number*/, wb, case 'n': t = 'Number'; p = String(cell.v); break; case 'b': t = 'Boolean'; p = (cell.v ? "1" : "0"); break; case 'e': t = 'Error'; p = BErr[cell.v]; break; - case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); break; + case 'd': t = 'DateTime'; p = new Date(cell.v).toISOString(); if(cell.z == null) cell.z = cell.z || SSF._table[14]; break; case 's': t = 'String'; p = escapexml(cell.v||""); break; } + /* TODO: cell style */ + var os = get_cell_style(opts.cellXfs, cell, opts); + attr["ss:StyleID"] = "s" + (21+os); var _v = (cell.v != null ? p : ""); var m = '' + _v + ''; @@ -1023,9 +1036,9 @@ function write_ws_xlml_row(R/*:number*/, row)/*:string*/ { /* TODO */ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbook*/)/*:string*/ { if(!ws['!ref']) return ""; - var range = safe_decode_range(ws['!ref']); - var marr = ws['!merges'] || [], mi = 0; - var o = []; + var range/*:Range*/ = safe_decode_range(ws['!ref']); + var marr/*:Array*/ = ws['!merges'] || [], mi = 0; + var o/*:Array*/ = []; if(ws['!cols']) ws['!cols'].forEach(function(n, i) { process_col(n); var w = !!n.width; @@ -1059,7 +1072,7 @@ function write_ws_xlml_table(ws/*:Worksheet*/, opts, idx/*:number*/, wb/*:Workbo return o.join(""); } function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ { - var o = []; + var o/*:Array*/ = []; var s = wb.SheetNames[idx]; var ws = wb.Sheets[s]; @@ -1073,12 +1086,23 @@ function write_ws_xlml(idx/*:number*/, opts, wb/*:Workbook*/)/*:string*/ { return o.join(""); } function write_xlml(wb, opts)/*:string*/ { - var d = []; + if(!opts) opts = {}; + if(!wb.SSF) wb.SSF = SSF.get_table(); + if(wb.SSF) { + make_ssf(SSF); SSF.load_table(wb.SSF); + // $FlowIgnore + opts.revssf = evert_num(wb.SSF); opts.revssf[wb.SSF[65535]] = 0; + opts.ssf = wb.SSF; + opts.cellXfs = []; + get_cell_style(opts.cellXfs, {}, {revssf:{"General":0}}); + } + var d/*:Array*/ = []; d.push(write_props_xlml(wb, opts)); d.push(write_wb_xlml(wb, opts)); - d.push(write_sty_xlml(wb, opts)); + d.push(""); for(var i = 0; i < wb.SheetNames.length; ++i) d.push(writextag("Worksheet", write_ws_xlml(i, opts, wb), {"ss:Name":escapexml(wb.SheetNames[i])})); + d[2] = write_sty_xlml(wb, opts); return XML_HEADER + writextag("Workbook", d.join(""), { 'xmlns': XLMLNS.ss, 'xmlns:o': XLMLNS.o, diff --git a/bits/76_xls.js b/bits/76_xls.js index 62399f7..47b1711 100644 --- a/bits/76_xls.js +++ b/bits/76_xls.js @@ -5,25 +5,25 @@ function parse_compobj(obj/*:CFBEntry*/) { /*:: if(o == null) return; */ /* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */ - var l = 28, m; - m = __lpstr(o, l); - l += 4 + __readUInt32LE(o,l); - v.UserType = m; + o.l = 28; - /* [MS-OLEDS] 2.3.1 ClipboardFormatOrAnsiString */ - m = __readUInt32LE(o,l); l+= 4; - switch(m) { - case 0x00000000: break; - case 0xffffffff: case 0xfffffffe: l+=4; break; - default: - if(m > 0x190) throw new Error("Unsupported Clipboard: " + m.toString(16)); - l += m; - } + v.AnsiUserType = o.read_shift(0, "lpstr-ansi"); + v.AnsiClipboardFormat = parse_ClipboardFormatOrAnsiString(o); - m = __lpstr(o, l); l += m.length === 0 ? 0 : 5 + m.length; v.Reserved1 = m; + if(o.length - o.l <= 4) return v; - if((m = __readUInt32LE(o,l)) !== 0x71b2e9f4) return v; - throw new Error("Unsupported Unicode Extension"); + var m/*:number*/ = o.read_shift(4); + if(m == 0 || m > 40) return v; + o.l-=4; v.Reserved1 = o.read_shift(0, "lpstr-ansi"); + + if(o.length - o.l <= 4) return v; + m = o.read_shift(4); + if(m !== 0x71b239f4) return v; + v.UnicodeClipboardFormat = parse_ClipboardFormatOrUnicodeString(o); + + m = o.read_shift(4); + if(m == 0 || m > 40) return v; + o.l-=4; v.Reserved2 = o.read_shift(0, "lpwstr"); } /* @@ -99,21 +99,20 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { if(DENSE != null && options.dense == null) options.dense = DENSE; var out/*:Worksheet*/ = ((options.dense ? [] : {})/*:any*/); var Directory = {}; - var found_sheet = false; var range/*:Range*/ = ({}/*:any*/); var last_formula = null; - var sst = []; + var sst/*:SST*/ = ([]/*:any*/); var cur_sheet = ""; var Preamble = {}; - var lastcell, last_cell = "", cc, cmnt, rng, rngC, rngR; + var lastcell, last_cell = "", cc, cmnt, rngC, rngR; var shared_formulae = {}; - var array_formulae = []; /* TODO: something more clever */ + var arrayf/*:Array<[Range, string]>*/ = []; var temp_val/*:Cell*/; var country; var cell_valid = true; var XFs = []; /* XF records */ var palette = []; - var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false} }/*:any*/), wsprops = {}; + var Workbook/*:WBWBProps*/ = ({ Sheets:[], WBProps:{date1904:false}, Views:[{}] }/*:any*/), wsprops = {}; var get_rgb = function getrgb(icv) { if(icv < 8) return XLSIcv[icv]; if(icv < 64) return palette[icv-8] || XLSIcv[icv]; @@ -144,15 +143,15 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { if(cell.c + 1 > range.e.c) range.e.c = cell.c + 1; } if(options.cellFormula && line.f) { - for(var afi = 0; afi < array_formulae.length; ++afi) { - if(array_formulae[afi][0].s.c > cell.c) continue; - if(array_formulae[afi][0].s.r > cell.r) continue; - if(array_formulae[afi][0].e.c < cell.c) continue; - if(array_formulae[afi][0].e.r < cell.r) continue; - line.F = encode_range(array_formulae[afi][0]); - if(array_formulae[afi][0].s.c != cell.c) delete line.f; - if(array_formulae[afi][0].s.r != cell.r) delete line.f; - if(line.f) line.f = "" + stringify_formula(array_formulae[afi][1], range, cell, supbooks, opts); + for(var afi = 0; afi < arrayf.length; ++afi) { + if(arrayf[afi][0].s.c > cell.c) continue; + if(arrayf[afi][0].s.r > cell.r) continue; + if(arrayf[afi][0].e.c < cell.c) continue; + if(arrayf[afi][0].e.r < cell.r) continue; + line.F = encode_range(arrayf[afi][0]); + if(arrayf[afi][0].s.c != cell.c) delete line.f; + if(arrayf[afi][0].s.r != cell.r) delete line.f; + if(line.f) line.f = "" + stringify_formula(arrayf[afi][1], range, cell, supbooks, opts); break; } } @@ -169,7 +168,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { sbcch: 0, // cch in the preceding SupBook snames: [], // sheetnames sharedf: shared_formulae, // shared formulae by address - arrayf: array_formulae, // array formulae array + arrayf: arrayf, // array formulae array rrtabid: [], // RRTabId lastuser: "", // Last User from WriteAccess biff: 8, // BIFF version @@ -179,9 +178,10 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { WTF: !!options && !!options.wtf }/*:any*/); if(options.password) opts.password = options.password; - var mergecells = []; + var themes; + var merges/*:Array*/ = []; var objects = []; - var colinfo = [], rowinfo = []; + var colinfo/*:Array*/ = [], rowinfo/*:Array*/ = []; var defwidth = 0, defheight = 0; // twips / MDW respectively var seencol = false; var supbooks = ([]/*:any*/); // 1-indexed, will hold extern names @@ -192,8 +192,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { supbooks.XTI = []; var last_Rn = ''; var file_depth = 0; /* TODO: make a real stack */ - var BIFF2Fmt = 0; - var BIFF2FmtTable/*:Array*/ = []; + var BIFF2Fmt = 0, BIFF2FmtTable/*:Array*/ = []; var FilterDatabases = []; /* TODO: sort out supbooks and process elsewhere */ var last_lbl/*:?DefinedName*/; @@ -291,7 +290,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { }/*:DefinedName*/); if(val.itab > 0) last_lbl.Sheet = val.itab - 1; supbooks.names.push(last_lbl); - if(!supbooks[0]) supbooks[0] = []; + if(!supbooks[0]) { supbooks[0] = []; supbooks[0].XTI = []; } supbooks[supbooks.length-1].push(val); if(val.Name == "_xlnm._FilterDatabase" && val.itab > 0) if(val.rgce && val.rgce[0] && val.rgce[0][0] && val.rgce[0][0][0] == 'PtgArea3d') @@ -323,7 +322,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { out["!ref"] = encode_range(range); range.e.r++; range.e.c++; } - if(mergecells.length > 0) out["!merges"] = mergecells; + if(merges.length > 0) out["!merges"] = merges; if(objects.length > 0) out["!objects"] = objects; if(colinfo.length > 0) out["!cols"] = colinfo; if(rowinfo.length > 0) out["!rows"] = rowinfo; @@ -333,16 +332,16 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { out = ((options.dense ? [] : {})/*:any*/); } break; case 'BOF': { - if(opts.biff === 8) switch(RecordType) { - case 0x0009: opts.biff = 2; break; - case 0x0209: opts.biff = 3; break; - case 0x0409: opts.biff = 4; break; - default: switch(val.BIFFVer) { - case 0x0500: opts.biff = 5; break; - case 0x0600: opts.biff = 8; break; - case 0x0002: opts.biff = 2; break; - case 0x0007: opts.biff = 2; break; - }} + if(opts.biff === 8) opts.biff = { + /*::[*/0x0009/*::]*/:2, + /*::[*/0x0209/*::]*/:3, + /*::[*/0x0409/*::]*/:4 + }[RecordType] || { + /*::[*/0x0500/*::]*/:5, + /*::[*/0x0600/*::]*/:8, + /*::[*/0x0002/*::]*/:2, + /*::[*/0x0007/*::]*/:2 + }[val.BIFFVer] || 8; if(file_depth++) break; cell_valid = true; out = ((options.dense ? [] : {})/*:any*/); @@ -359,9 +358,9 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { else cur_sheet = (Directory[s] || {name:""}).name; if(val.dt == 0x20) out["!type"] = "chart"; if(val.dt == 0x40) out["!type"] = "macro"; - mergecells = []; + merges = []; objects = []; - array_formulae = []; opts.arrayf = array_formulae; + opts.arrayf = arrayf = []; colinfo = []; rowinfo = []; defwidth = defheight = 0; seencol = false; @@ -429,7 +428,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { } else throw new Error("String record expects Formula"); } break; case 'Array': { - array_formulae.push(val); + arrayf.push(val); var _arraystart = encode_cell(val[0].s); cc = options.dense ? (out[val[0].s.r]||[])[val[0].s.c] : out[_arraystart]; if(options.cellFormula && cc) { @@ -501,7 +500,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { if(b2idx >= 163) SSF.load(val, BIFF2Fmt + 163); } break; - case 'MergeCells': mergecells = mergecells.concat(val); break; + case 'MergeCells': merges = merges.concat(val); break; case 'Obj': objects[val.cmo[0]] = opts.lastobj = val; break; case 'TxO': opts.lastobj.TxO = val; break; @@ -572,6 +571,11 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { out['!margins'].footer = val.footer; break; + case 'Window2': // TODO + // $FlowIgnore + if(val.RTL) Workbook.Views[0].RTL = true; + break; + case 'Header': break; // TODO case 'Footer': break; // TODO case 'HCenter': break; // TODO @@ -605,8 +609,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { case 'XFCRC': break; // TODO case 'Style': break; // TODO case 'StyleExt': break; // TODO - case 'Palette': palette = val; break; // TODO - case 'Theme': break; // TODO + case 'Palette': palette = val; break; + case 'Theme': themes = val; break; /* Protection */ case 'ScenarioProtect': break; case 'ObjProtect': break; @@ -710,7 +714,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': break; case 'BuiltInFnGroupCount': /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */ break; /* View Stuff */ - case 'Window1': case 'Window2': case 'HideObj': case 'GridSet': case 'Guts': + case 'Window1': case 'HideObj': case 'GridSet': case 'Guts': case 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd': case 'Pane': break; default: switch(R.n) { /* nested */ @@ -824,6 +828,7 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ { wb.Strings = sst; wb.SSF = SSF.get_table(); if(opts.enc) wb.Encryption = opts.enc; + if(themes) wb.Themes = themes; wb.Metadata = {}; if(country !== undefined) wb.Metadata.Country = country; if(supbooks.names.length > 0) Workbook.Names = supbooks.names; @@ -838,22 +843,24 @@ function parse_props(cfb/*:CFBContainer*/, props, o) { if(DSI) try { var DocSummary = parse_PropertySetStream(DSI, DocSummaryPIDDSI); for(var d in DocSummary) props[d] = DocSummary[d]; - } catch(e) {if(o.WTF == 2) throw e;/* empty */} + } catch(e) {if(o.WTF) throw e;/* empty */} /* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/ var SI = CFB.find(cfb, '!SummaryInformation'); if(SI) try { var Summary = parse_PropertySetStream(SI, SummaryPIDSI); for(var s in Summary) if(props[s] == null) props[s] = Summary[s]; - } catch(e) {if(o.WTF == 2) throw e;/* empty */} + } catch(e) {if(o.WTF) throw e;/* empty */} } function parse_xlscfb(cfb/*:any*/, options/*:?ParseOpts*/)/*:Workbook*/ { if(!options) options = {}; fix_read_opts(options); reset_cp(); +if(options.codepage) set_ansi(options.codepage); var CompObj/*:?CFBEntry*/, Summary, WB/*:?any*/; if(cfb.FullPaths) { + if(CFB.find(cfb, '/encryption')) throw new Error("File is password-protected"); CompObj = CFB.find(cfb, '!CompObj'); Summary = CFB.find(cfb, '!SummaryInformation'); WB = CFB.find(cfb, '/Workbook') || CFB.find(cfb, '/Book'); @@ -900,6 +907,8 @@ function write_xlscfb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:CFBContainer*/ { switch(o.bookType || "xls") { case "xls": o.bookType = "biff8"; /* falls through */ + case "xla": if(!o.bookType) o.bookType = "xla"; + /* falls through */ case "biff8": wbpath = "/Workbook"; o.biff = 8; break; case "biff5": wbpath = "/Book"; o.biff = 5; break; default: throw new Error("invalid type " + o.bookType + " for XLS CFB"); diff --git a/bits/77_parsetab.js b/bits/77_parsetab.js index ce6451a..de94cf4 100644 --- a/bits/77_parsetab.js +++ b/bits/77_parsetab.js @@ -72,7 +72,7 @@ var XLSBRecordEnum = { /*::[*/0x0086/*::]*/: { n:"BrtEndWsViews" }, /*::[*/0x0087/*::]*/: { n:"BrtBeginBookViews" }, /*::[*/0x0088/*::]*/: { n:"BrtEndBookViews" }, - /*::[*/0x0089/*::]*/: { n:"BrtBeginWsView" }, + /*::[*/0x0089/*::]*/: { n:"BrtBeginWsView", f:parse_BrtBeginWsView }, /*::[*/0x008A/*::]*/: { n:"BrtEndWsView" }, /*::[*/0x008B/*::]*/: { n:"BrtBeginCsViews" }, /*::[*/0x008C/*::]*/: { n:"BrtEndCsViews" }, @@ -1026,7 +1026,7 @@ var XLSRecordEnum = { /*::[*/0x0221/*::]*/: { n:"Array", f:parse_Array }, /*::[*/0x0225/*::]*/: { n:"DefaultRowHeight", f:parse_DefaultRowHeight }, /*::[*/0x0236/*::]*/: { n:"Table" }, - /*::[*/0x023e/*::]*/: { n:"Window2" }, + /*::[*/0x023e/*::]*/: { n:"Window2", f:parse_Window2 }, /*::[*/0x027e/*::]*/: { n:"RK", f:parse_RK }, /*::[*/0x0293/*::]*/: { n:"Style" }, /*::[*/0x0406/*::]*/: { n:"Formula", f:parse_Formula }, diff --git a/bits/78_writebiff.js b/bits/78_writebiff.js index 1300960..4613766 100644 --- a/bits/78_writebiff.js +++ b/bits/78_writebiff.js @@ -1,8 +1,8 @@ -function write_biff_rec(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/) { +function write_biff_rec(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/)/*:void*/ { var t/*:number*/ = +type || +XLSRE[/*::String(*/type/*::)*/]; if(isNaN(t)) return; var len = length || (payload||[]).length || 0; - var o = ba.next(4 + len); + var o = ba.next(4); o.write_shift(2, t); o.write_shift(2, len); if(/*:: len != null &&*/len > 0 && is_buf(payload)) ba.push(payload); @@ -12,8 +12,7 @@ function write_BIFF2Cell(out, r/*:number*/, c/*:number*/) { if(!out) out = new_buf(7); out.write_shift(2, r); out.write_shift(2, c); - out.write_shift(1, 0); - out.write_shift(1, 0); + out.write_shift(2, 0); out.write_shift(1, 0); return out; } @@ -114,7 +113,8 @@ function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:n function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) { var ba = buf_array(); var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {}; - var _sheet/*:WBWSProp*/ = ((((wb||{}).Workbook||{}).Sheets||[])[idx]||{}/*:any*/); + var _WB/*:WBWBProps*/ = ((wb||{}).Workbook||{}/*:any*/); + var _sheet/*:WBWSProp*/ = ((_WB.Sheets||[])[idx]||{}/*:any*/); var dense = Array.isArray(ws); var ref/*:string*/, rr = "", cols/*:Array*/ = []; var range = safe_decode_range(ws['!ref'] || "A1"); @@ -153,6 +153,10 @@ function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) { } var cname/*:string*/ = _sheet.CodeName || _sheet.name || s; /* ... */ + if(b8 && _WB.Views) write_biff_rec(ba, "Window2", write_Window2(_WB.Views[0])); + /* ... */ + if(b8) write_biff_rec(ba, "MergeCells", write_MergeCells(ws['!merges']||[])); + /* ... */ if(b8) write_ws_biff8_hlinks(ba, ws); /* ... */ write_biff_rec(ba, "CodeName", write_XLUnicodeString(cname, opts)); @@ -167,6 +171,7 @@ function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) { var _wb/*:WBWBProps*/ = /*::((*/(wb.Workbook||{}).WBProps||{/*::CodeName:"ThisWorkbook"*/}/*:: ):any)*/; var b8 = opts.biff == 8, b5 = opts.biff == 5; write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts)); + if(opts.bookType == "xla") write_biff_rec(A, "Addin"); write_biff_rec(A, "InterfaceHdr", b8 ? writeuint16(0x04b0) : null); write_biff_rec(A, "Mms", writezeroes(2)); if(b5) write_biff_rec(A, "ToolbarHdr"); diff --git a/bits/79_html.js b/bits/79_html.js index ccaf712..e3a7b97 100644 --- a/bits/79_html.js +++ b/bits/79_html.js @@ -10,8 +10,8 @@ var HTML_ = (function() { var i/*:number*/ = mtch.index, j/*:number*/ = mtch2 && mtch2.index || str.length; var rows = split_regex(str.slice(i, j), /(:?]*>)/i, ""); var R = -1, C = 0, RS = 0, CS = 0; - var range = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; - var merges = [], midx = 0; + var range/*:Range*/ = {s:{r:10000000, c:10000000},e:{r:0,c:0}}; + var merges/*:Array*/ = [], midx = 0; for(i = 0; i < rows.length; ++i) { var row = rows[i].trim(); var hd = row.substr(0,3).toLowerCase(); @@ -56,8 +56,8 @@ var HTML_ = (function() { return sheet_to_workbook(html_to_sheet(str, opts), opts); } function make_html_row(ws/*:Worksheet*/, r/*:Range*/, R/*:number*/, o/*:Sheet2HTMLOpts*/)/*:string*/ { - var M = (ws['!merges'] ||[]); - var oo = []; + var M/*:Array*/ = (ws['!merges'] ||[]); + var oo/*:Array*/ = []; var nullcell = "" + (o.editable ? '' : "" ) + ""; for(var C = r.s.c; C <= r.e.c; ++C) { var RS = 0, CS = 0; @@ -85,7 +85,7 @@ var HTML_ = (function() { return preamble + oo.join("") + ""; } function make_html_preamble(ws/*:Worksheet*/, R/*:Range*/, o/*:Sheet2HTMLOpts*/)/*:string*/ { - var out = []; + var out/*:Array*/ = []; return out.join("") + ''; } var _BEGIN = 'SheetJS Table Export'; @@ -118,17 +118,17 @@ function parse_dom_table(table/*:HTMLElement*/, _opts/*:?any*/)/*:Worksheet*/ { var opts = _opts || {}; if(DENSE != null) opts.dense = DENSE; var ws/*:Worksheet*/ = opts.dense ? ([]/*:any*/) : ({}/*:any*/); - var rows = table.getElementsByTagName('tr'); - var range = {s:{r:0,c:0},e:{r:rows.length - 1,c:0}}; - var merges = [], midx = 0; + var rows/*:HTMLCollection*/ = table.getElementsByTagName('tr'); + var range/*:Range*/ = {s:{r:0,c:0},e:{r:rows.length - 1,c:0}}; + var merges/*:Array*/ = [], midx = 0; var R = 0, _C = 0, C = 0, RS = 0, CS = 0; for(; R < rows.length; ++R) { - var row = rows[R]; - var elts = row.children; + var row/*:HTMLTableRowElement*/ = rows[R]; + var elts/*:HTMLCollection*/ = (row.children/*:any*/); for(_C = C = 0; _C < elts.length; ++_C) { - var elt = elts[_C], v = htmldecode(elts[_C].innerHTML); + var elt/*:HTMLTableCellElement*/ = elts[_C], v = htmldecode(elts[_C].innerHTML); for(midx = 0; midx < merges.length; ++midx) { - var m = merges[midx]; + var m/*:Range*/ = merges[midx]; if(m.s.c == C && m.s.r <= R && R <= m.e.r) { C = m.e.c+1; midx = -1; } } /* TODO: figure out how to extract nonstandard mso- style */ diff --git a/bits/80_parseods.js b/bits/80_parseods.js index 5361a76..9610424 100644 --- a/bits/80_parseods.js +++ b/bits/80_parseods.js @@ -45,13 +45,13 @@ var parse_content_xml = (function() { var R = -1, C = -1, range = {s: {r:1000000,c:10000000}, e: {r:0, c:0}}; var row_ol = 0; var number_format_map = {}; - var merges = [], mrange = {}, mR = 0, mC = 0; - var rowinfo = [], rowpeat = 1, colpeat = 1; - var arrayf = []; + var merges/*:Array*/ = [], mrange = {}, mR = 0, mC = 0; + var rowinfo/*:Array*/ = [], rowpeat = 1, colpeat = 1; + var arrayf/*:Array<[Range, string]>*/ = []; var WB = {Names:[]}; var atag = ({}/*:any*/); var _Ref/*:[string, string]*/ = ["", ""]; - var comments = [], comment = {}; + var comments/*:Array*/ = [], comment/*:Comment*/ = ({}/*:any*/); var creator = "", creatoridx = 0; var isstub = false, intable = false; var i = 0; @@ -122,7 +122,7 @@ var parse_content_xml = (function() { if(C < range.s.c) range.s.c = C; if(R < range.s.r) range.s.r = R; ctag = parsexmltag(Rn[0], false); - comments = []; comment = {}; + comments = []; comment = ({}/*:any*/); q = ({t:ctag['数据类型'] || ctag['value-type'], v:null/*:: , z:null, w:"",c:[]*/}/*:any*/); if(opts.cellFormula) { if(ctag.formula) ctag.formula = unescapexml(ctag.formula); diff --git a/bits/81_writeods.js b/bits/81_writeods.js index 229ff2b..10a69d3 100644 --- a/bits/81_writeods.js +++ b/bits/81_writeods.js @@ -32,10 +32,10 @@ var write_content_ods/*:{(wb:any, opts:any):string}*/ = (function() { var covered_cell_xml = ' \n'; var write_ws = function(ws, wb/*:Workbook*/, i/*:number*/, opts)/*:string*/ { /* Section 9 Tables */ - var o = []; + var o/*:Array*/ = []; o.push(' \n'); var R=0,C=0, range = decode_range(ws['!ref']); - var marr = ws['!merges'] || [], mi = 0; + var marr/*:Array*/ = ws['!merges'] || [], mi = 0; var dense = Array.isArray(ws); for(R = 0; R < range.s.r; ++R) o.push(' \n'); for(; R <= range.e.r; ++R) { @@ -186,7 +186,7 @@ function write_ods(wb/*:any*/, opts/*:any*/) { var f = ""; var manifest/*:Array >*/ = []; - var rdf = []; + var rdf/*:Array<[string, string]>*/ = []; /* Part 3 Section 3.3 MIME Media Type */ f = "mimetype"; diff --git a/bits/85_parsezip.js b/bits/85_parsezip.js index c9fce27..c519ade 100644 --- a/bits/85_parsezip.js +++ b/bits/85_parsezip.js @@ -43,7 +43,6 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { make_ssf(SSF); opts = opts || {}; fix_read_opts(opts); - reset_cp(); /* OpenDocument Part 3 Section 2.2.1 OpenDocument Package */ if(safegetzipfile(zip, 'META-INF/manifest.xml')) return parse_ods(zip, opts); @@ -67,7 +66,6 @@ function parse_zip(zip/*:ZIP*/, opts/*:?ParseOpts*/)/*:Workbook*/ { xlsb = true; } if(dir.workbooks[0].slice(-3) == "bin") xlsb = true; - if(xlsb) set_cp(1200); var themes = ({}/*:any*/); var styles = ({}/*:any*/); diff --git a/bits/86_writezip.js b/bits/86_writezip.js index 197c592..65e58ef 100644 --- a/bits/86_writezip.js +++ b/bits/86_writezip.js @@ -13,7 +13,7 @@ function write_zip(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:ZIP*/ { opts.rels = {}; opts.wbrels = {}; opts.Strings = /*::((*/[]/*:: :any):SST)*/; opts.Strings.Count = 0; opts.Strings.Unique = 0; var wbext = opts.bookType == "xlsb" ? "bin" : "xml"; - var vbafmt = opts.bookType == "xlsb" || opts.bookType == "xlsm"; + var vbafmt = VBAFMTS.indexOf(opts.bookType) > -1; var ct = new_ct(); fix_write_opts(opts = opts || {}); /*:: if(!jszip) throw new Error("JSZip is not available"); */ diff --git a/bits/87_read.js b/bits/87_read.js index af50754..b78e9d7 100644 --- a/bits/87_read.js +++ b/bits/87_read.js @@ -70,7 +70,9 @@ function read_prn(data, d, o, str) { } function readSync(data/*:RawData*/, opts/*:?ParseOpts*/)/*:Workbook*/ { - var zip, d = data, n = [0,0,0,0], str = false; + reset_cp(); + if(typeof ArrayBuffer !== 'undefined' && data instanceof ArrayBuffer) return readSync(new Uint8Array(data), opts); + var d = data, n = [0,0,0,0], str = false; var o = opts||{}; _ssfopts = {}; if(o.dateNF) _ssfopts.dateNF = o.dateNF; diff --git a/bits/88_write.js b/bits/88_write.js index a973acd..250ae2c 100644 --- a/bits/88_write.js +++ b/bits/88_write.js @@ -79,6 +79,7 @@ function write_binary_type(out, opts/*:WriteOpts*/)/*:any*/ { function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { check_wb(wb); var o = opts||{}; + if(o.type == "array") { o.type = "binary"; var out/*:string*/ = (writeSync(wb, o)/*:any*/); o.type = "array"; return s2ab(out); } switch(o.bookType || 'xlsb') { case 'xml': case 'xlml': return write_string_type(write_xlml(wb, o), o); @@ -99,9 +100,11 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) { case 'biff4': if(!o.biff) o.biff = 4; return write_binary_type(write_biff_buf(wb, o), o); case 'biff5': if(!o.biff) o.biff = 5; /* falls through */ case 'biff8': + case 'xla': case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o); case 'xlsx': case 'xlsm': + case 'xlam': case 'xlsb': case 'ods': return write_zip_type(wb, o); default: throw new Error ("Unrecognized bookType |" + o.bookType + "|"); diff --git a/bits/90_utils.js b/bits/90_utils.js index 6feb4ef..8068ced 100644 --- a/bits/90_utils.js +++ b/bits/90_utils.js @@ -103,20 +103,20 @@ function make_csv_row(sheet/*:Worksheet*/, r/*:Range*/, R/*:number*/, cols/*:Arr } function sheet_to_csv(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/)/*:string*/ { - var out = []; + var out/*:Array*/ = []; var o = opts == null ? {} : opts; if(sheet == null || sheet["!ref"] == null) return ""; var r = safe_decode_range(sheet["!ref"]); var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0); var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0); var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$"); - var row = "", cols = []; + var row = "", cols/*:Array*/ = []; o.dense = Array.isArray(sheet); - var colInfos = o.skipHidden && sheet["!cols"] || []; - var rowInfos = o.skipHidden && sheet["!rows"] || []; - for(var C = r.s.c; C <= r.e.c; ++C) if (!((colInfos[C]||{}).hidden)) cols[C] = encode_col(C); + var colinfo/*:Array*/ = o.skipHidden && sheet["!cols"] || []; + var rowinfo/*:Array*/ = o.skipHidden && sheet["!rows"] || []; + for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C); for(var R = r.s.r; R <= r.e.r; ++R) { - if ((rowInfos[R]||{}).hidden) continue; + if ((rowinfo[R]||{}).hidden) continue; row = make_csv_row(sheet, r, R, cols, fs, rs, FS, o); if(row == null) { continue; } if(o.strip) row = row.replace(endregex,""); @@ -137,7 +137,7 @@ function sheet_to_txt(sheet/*:Worksheet*/, opts/*:?Sheet2CSVOpts*/) { function sheet_to_formulae(sheet/*:Worksheet*/)/*:Array*/ { var y = "", x, val=""; if(sheet == null || sheet["!ref"] == null) return []; - var r = safe_decode_range(sheet['!ref']), rr = "", cols = [], C; + var r = safe_decode_range(sheet['!ref']), rr = "", cols/*:Array*/ = [], C; var cmds/*:Array*/ = []; var dense = Array.isArray(sheet); for(C = r.s.c; C <= r.e.c; ++C) cols[C] = encode_col(C); @@ -173,7 +173,7 @@ function json_to_sheet(js/*:Array*/, opts)/*:Worksheet*/ { var ws = ({}/*:any*/); var cell/*:Cell*/; var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:js.length}}/*:any*/); - var hdr = o.header || [], C = 0; + var hdr/*:Array*/ = o.header || [], C = 0; js.forEach(function (JS, R) { keys(JS).filter(function(x) { return JS.hasOwnProperty(x); }).forEach(function(k) { diff --git a/bits/97_node.js b/bits/97_node.js index b7c668d..0338b22 100644 --- a/bits/97_node.js +++ b/bits/97_node.js @@ -10,17 +10,17 @@ if(has_buf && typeof require != 'undefined') (function() { var FS = o.FS !== undefined ? o.FS : ",", fs = FS.charCodeAt(0); var RS = o.RS !== undefined ? o.RS : "\n", rs = RS.charCodeAt(0); var endregex = new RegExp((FS=="|" ? "\\|" : FS)+"+$"); - var row/*:?string*/ = "", cols = []; + var row/*:?string*/ = "", cols/*:Array*/ = []; o.dense = Array.isArray(sheet); - var colInfos = o.skipHidden && sheet["!cols"] || []; - var rowInfos = o.skipHidden && sheet["!rows"] || []; - for(var C = r.s.c; C <= r.e.c; ++C) if (!((colInfos[C]||{}).hidden)) cols[C] = encode_col(C); + var colinfo/*:Array*/ = o.skipHidden && sheet["!cols"] || []; + var rowinfo/*:Array*/ = o.skipHidden && sheet["!rows"] || []; + for(var C = r.s.c; C <= r.e.c; ++C) if (!((colinfo[C]||{}).hidden)) cols[C] = encode_col(C); var R = r.s.r; stream._read = function() { if(R > r.e.r) return stream.push(null); while(R <= r.e.r) { ++R; - if ((rowInfos[R-1]||{}).hidden) continue; + if ((rowinfo[R-1]||{}).hidden) continue; row = make_csv_row(sheet, r, R-1, cols, fs, rs, FS, o); if(row != null) { if(o.strip) row = row.replace(endregex,""); diff --git a/bits/99_footer.js b/bits/99_footer.js index 0670c54..294595a 100644 --- a/bits/99_footer.js +++ b/bits/99_footer.js @@ -1,5 +1,3 @@ })(typeof exports !== 'undefined' ? exports : XLSX); -/*exported XLS */ -var XLS = XLSX; -/*exported ODS */ -var ODS = XLSX; +/*exported XLS, ODS */ +var XLS = XLSX, ODS = XLSX; diff --git a/demos/angular/README.md b/demos/angular/README.md index 569a6de..1df7d35 100644 --- a/demos/angular/README.md +++ b/demos/angular/README.md @@ -81,18 +81,11 @@ var ws = XLSX.utils.json_to_sheet(data); var wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "Presidents"); -/* write workbook (use type 'binary') */ -var wbout = XLSX.write(wb, {bookType:'xlsx', type:'binary'}); +/* write workbook (use type 'array' for ArrayBuffer) */ +var wbout = XLSX.write(wb, {bookType:'xlsx', type:'array'}); /* generate a download */ -function s2ab(s) { - var buf = new ArrayBuffer(s.length); - var view = new Uint8Array(buf); - for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; -} - -saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "sheetjs.xlsx"); +saveAs(new Blob([wbout],{type:"application/octet-stream"}), "sheetjs.xlsx"); ``` diff --git a/demos/angular/SheetJS-angular.js b/demos/angular/SheetJS-angular.js index 1ab37ea..9330799 100644 --- a/demos/angular/SheetJS-angular.js +++ b/demos/angular/SheetJS-angular.js @@ -13,12 +13,12 @@ function SheetJSExportService(uiGridExporterService) { var wb = XLSX.utils.book_new(), ws = uigrid_to_sheet(data, columns); XLSX.utils.book_append_sheet(wb, ws, sheetName); var wbout = XLSX.write(wb, wopts); - saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), fileName); + saveAs(new Blob([wbout], { type: 'application/octet-stream' }), fileName); } var service = {}; - service.exportXLSB = function exportXLSB(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsb', bookSST: true, type: 'binary' }); }; - service.exportXLSX = function exportXLSX(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsx', bookSST: true, type: 'binary' }); } + service.exportXLSB = function exportXLSB(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsb', bookSST: true, type: 'array' }); }; + service.exportXLSX = function exportXLSX(gridApi) { return exportSheetJS(gridApi, { bookType: 'xlsx', bookSST: true, type: 'array' }); } return service; @@ -47,19 +47,6 @@ function SheetJSExportService(uiGridExporterService) { if(col.name) return col.name; return null; } - - function s2ab(s) { - if(typeof ArrayBuffer !== 'undefined') { - var buf = new ArrayBuffer(s.length); - var view = new Uint8Array(buf); - for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; - } else { - var buf = new Array(s.length); - for (var i=0; i!=s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF; - return buf; - } - } } var SheetJSImportDirective = function() { diff --git a/demos/angular2/README.md b/demos/angular2/README.md index eed24ec..7eac6e0 100644 --- a/demos/angular2/README.md +++ b/demos/angular2/README.md @@ -35,8 +35,8 @@ const wb: XLSX.WorkBook = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); /* save to file */ -const wbout: string = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' }); -saveAs(new Blob([s2ab(wbout)]), 'SheetJS.xlsx'); +const wbout: string = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); +saveAs(new Blob([wbout]), 'SheetJS.xlsx'); ``` `sheet_to_json` with the option `header:1` makes importing simple: diff --git a/demos/angular2/src/app/sheetjs.component.ts b/demos/angular2/src/app/sheetjs.component.ts index fa06559..12e57ae 100644 --- a/demos/angular2/src/app/sheetjs.component.ts +++ b/demos/angular2/src/app/sheetjs.component.ts @@ -8,13 +8,6 @@ import { saveAs } from 'file-saver'; type AOA = Array>; -function s2ab(s: string): ArrayBuffer { - const buf: ArrayBuffer = new ArrayBuffer(s.length); - const view: Uint8Array = new Uint8Array(buf); - for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; -} - @Component({ selector: 'sheetjs', template: ` @@ -32,7 +25,7 @@ function s2ab(s: string): ArrayBuffer { export class SheetJSComponent { data: AOA = [ [1, 2], [3, 4] ]; - wopts: XLSX.WritingOptions = { bookType: 'xlsx', type: 'binary' }; + wopts: XLSX.WritingOptions = { bookType: 'xlsx', type: 'array' }; fileName: string = 'SheetJS.xlsx'; onFileChange(evt: any) { @@ -64,7 +57,7 @@ export class SheetJSComponent { XLSX.utils.book_append_sheet(wb, ws, 'Sheet1'); /* save to file */ - const wbout: string = XLSX.write(wb, this.wopts); - saveAs(new Blob([s2ab(wbout)]), this.fileName); + const wbout: ArrayBuffer = XLSX.write(wb, this.wopts); + saveAs(new Blob([wbout], { type: 'application/octet-stream' }), this.fileName); } } diff --git a/demos/datagrid/index.html b/demos/datagrid/index.html index 5fa77fb..c2f50e1 100644 --- a/demos/datagrid/index.html +++ b/demos/datagrid/index.html @@ -71,6 +71,9 @@ var process_wb = (function() { var range = XLSX.utils.decode_range(ws['!ref']); for(var i = range.s.c; i <= range.e.c; ++i) cDg.schema[i - range.s.c].title = XLSX.utils.encode_col(i); + HTMLOUT.style.height = (window.innerHeight - 400) + "px"; + HTMLOUT.style.width = (window.innerWidth - 50) + "px"; + if(typeof console !== 'undefined') console.log("output", new Date()); }; })(); @@ -136,12 +139,6 @@ var export_xlsx = (function() { return out; } - function s2ab(s) { - var b = new ArrayBuffer(s.length), v = new Uint8Array(b); - for (var i=0; i != s.length; ++i) v[i] = s.charCodeAt(i) & 0xFF; - return b; - } - return function export_xlsx() { if(!cDg) return; /* convert canvas-datagrid data to worksheet */ @@ -152,10 +149,10 @@ var export_xlsx = (function() { XLSX.utils.book_append_sheet(new_wb, new_ws, 'SheetJS'); /* write file and trigger a download */ - var wbout = XLSX.write(new_wb, {bookType:'xlsx', bookSST:true, type:'binary'}); + var wbout = XLSX.write(new_wb, {bookType:'xlsx', bookSST:true, type:'array'}); var fname = 'sheetjs.xlsx'; try { - saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), fname); + saveAs(new Blob([wbout],{type:"application/octet-stream"}), fname); } catch(e) { if(typeof console != 'undefined') console.log(e, wbout); } }; })(); diff --git a/demos/meteor/README.md b/demos/meteor/README.md index a2b83b3..6ef87f6 100644 --- a/demos/meteor/README.md +++ b/demos/meteor/README.md @@ -61,8 +61,8 @@ const html = document.getElementById('out').innerHTML; // SERVER SIDE const wb = XLSX.read(html, { type: 'binary' }); // CLIENT SIDE -const o = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' }); -saveAs(new Blob([s2ab(o)], {type:'application/octet-stream'}), 'sheetjs.xlsx'); +const o = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); +saveAs(new Blob([o], {type:'application/octet-stream'}), 'sheetjs.xlsx'); ``` This demo uses the FileSaver library for writing files, installed through the diff --git a/demos/meteor/client/main.js b/demos/meteor/client/main.js index 249134e..aafddd0 100644 --- a/demos/meteor/client/main.js +++ b/demos/meteor/client/main.js @@ -34,16 +34,9 @@ Template.sheetjs.events({ Meteor.call('download', html, function(err, wb) { if (err) throw err; /* "Browser download file" from SheetJS README */ - const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' }); - saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), 'sheetjs.xlsx'); + const wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); + saveAs(new Blob([wbout], { type: 'application/octet-stream' }), 'sheetjs.xlsx'); }); }, }); -/* eslint no-bitwise:0, no-plusplus:0 */ -function s2ab(s) { - const buf = new ArrayBuffer(s.length); - const view = new Uint8Array(buf); - for (let i = 0; i !== s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; -} diff --git a/demos/react/index.html b/demos/react/index.html index 4a1f85b..4d051dc 100644 --- a/demos/react/index.html +++ b/demos/react/index.html @@ -9,7 +9,7 @@ - + diff --git a/demos/react/sheetjs.jsx b/demos/react/sheetjs.jsx index f5c5bc1..c8216b9 100644 --- a/demos/react/sheetjs.jsx +++ b/demos/react/sheetjs.jsx @@ -38,9 +38,9 @@ class SheetJSApp extends React.Component { const wb = XLSX.utils.book_new(); XLSX.utils.book_append_sheet(wb, ws, "SheetJS"); /* generate XLSX file */ - const wbout = XLSX.write(wb, {type:"binary", bookType:"xlsx"}); + const wbout = XLSX.write(wb, {type:"array", bookType:"xlsx"}); /* send to client */ - saveAs(new Blob([s2ab(wbout)],{type:"application/octet-stream"}), "sheetjs.xlsx"); + saveAs(new Blob([wbout],{type:"application/octet-stream"}), "sheetjs.xlsx"); }; render() { return ( @@ -136,13 +136,5 @@ const SheetJSFT = [ "xlsx", "xlsb", "xlsm", "xls", "xml", "csv", "txt", "ods", "fods", "uos", "sylk", "dif", "dbf", "prn", "qpw", "123", "wb*", "wq*", "html", "htm" ].map(function(x) { return "." + x; }).join(","); -/* see Browser download file example in docs */ -function s2ab(s/*:string*/)/*:ArrayBuffer*/ { - const buf = new ArrayBuffer(s.length); - const view = new Uint8Array(buf); - for (let i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; -} - /* generate an array of column objects */ const make_cols = refstr => Array(XLSX.utils.decode_range(refstr).e.c + 1).fill(0).map((x,i) => ({name:XLSX.utils.encode_col(i), key:i})); diff --git a/demos/vue/README.md b/demos/vue/README.md index d9ab680..4380d50 100644 --- a/demos/vue/README.md +++ b/demos/vue/README.md @@ -95,13 +95,17 @@ fs.writeFileSync("sheetjs.xls", new Buffer(str, "base64")); #### Server-Rendered VueJS Components with Nuxt.js -Due to webpack configuration issues on client/server bundles, the library should -be explicitly included in the layout HTML (as script tag) and in the component: +The scripts should be treated as external resources in `nuxt.config.js`: ```js -const _XLSX = require('xlsx'); -const X = typeof XLSX !== 'undefined' ? XLSX : _XLSX; -/* use the variable X rather than XLSX in the component */ +module.exports = { + head: { + script: [ + { src: "https://unpkg.com/xlsx/dist/xlsx.full.min.js" }, // library + { src: "https://unpkg.com/file-saver/FileSaver.js" } // saveAs shim + ] + } +}; ``` [![Analytics](https://ga-beacon.appspot.com/UA-36810333-1/SheetJS/js-xlsx?pixel)](https://github.com/SheetJS/js-xlsx) diff --git a/demos/vue/SheetJS-vue.js b/demos/vue/SheetJS-vue.js index 70a8e1d..0e6c546 100644 --- a/demos/vue/SheetJS-vue.js +++ b/demos/vue/SheetJS-vue.js @@ -13,19 +13,6 @@ var SJSTemplate = [ '' ].join(""); -function s2ab(s) { - if(typeof ArrayBuffer !== 'undefined') { - var buf = new ArrayBuffer(s.length); - var view = new Uint8Array(buf); - for (var i=0; i!=s.length; ++i) view[i] = s.charCodeAt(i) & 0xFF; - return buf; - } else { - var buf = new Array(s.length); - for (var i=0; i!=s.length; ++i) buf[i] = s.charCodeAt(i) & 0xFF; - return buf; - } -} - Vue.component('html-preview', { template: SJSTemplate, methods: { @@ -69,10 +56,10 @@ Vue.component('html-preview', { /* generate workbook object from table */ var wb = XLSX.utils.table_to_book(document.getElementById('out-table')); /* get binary string as output */ - var wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'binary' }); + var wbout = XLSX.write(wb, { bookType: 'xlsx', type: 'array' }); /* force a download */ - saveAs(new Blob([s2ab(wbout)], { type: 'application/octet-stream' }), "sheetjs.xlsx"); + saveAs(new Blob([wbout], { type: 'application/octet-stream' }), "sheetjs.xlsx"); } } }); diff --git a/demos/vue/nuxt.config.js b/demos/vue/nuxt.config.js new file mode 100644 index 0000000..b02cf96 --- /dev/null +++ b/demos/vue/nuxt.config.js @@ -0,0 +1,9 @@ +module.exports = { + head: { + script: [ + // { src: "https://unpkg.com/xlsx/dist/xlsx.full.min.js" }, // CDN + { src: "xlsx.full.min.js" }, // development + { src: "https://unpkg.com/file-saver/FileSaver.js" } + ] + } +}; diff --git a/demos/vue/pages/index.vue b/demos/vue/pages/index.vue index 5874cd8..14537d4 100644 --- a/demos/vue/pages/index.vue +++ b/demos/vue/pages/index.vue @@ -30,17 +30,7 @@