RTF write stub

- Empty WS on RTF read, rudimentary write
- reshape XLS VBA blob
- CI adding back old nodejs versions
- refresh tests and docs
This commit is contained in:
SheetJS 2017-10-02 04:15:36 -04:00
parent af3df44633
commit c88f83940c
30 changed files with 434 additions and 75 deletions

1
.gitignore vendored

@ -21,6 +21,7 @@ tmp
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
*.[bB][iI][fF][fF][23458]
*.[rR][tT][fF]
*.123
*.htm
*.html

@ -23,6 +23,7 @@ tmp
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
*.[bB][iI][fF][fF][23458]
*.[rR][tT][fF]
*.123
*.htm
*.html
@ -30,6 +31,7 @@ tmp
*.exe
.gitignore
.fossaignore
.spelling
.eslintrc
.jshintrc
CONTRIBUTING.md

@ -18,10 +18,15 @@ PivotTable
Quattro
SpreadsheetML
Unhide
VBA
Visicalc
chartsheet
chartsheets
dialogsheet
dialogsheets
dBASE
macrosheet
macrosheets
tooltip
tooltips

@ -3,13 +3,6 @@ node_js:
- "8"
- "7"
- "6"
# note: travis has been acting up on old versions of node
# - "5"
# - "4"
# - "0.12"
# - "0.10"
# - "0.9"
# - "0.8"
matrix:
include:
- node_js: "6"
@ -26,6 +19,18 @@ matrix:
env: TZ="Asia/Shanghai"
- node_js: "8"
env: TZ="Asia/Seoul" FMTS=misc
- node_js: "5"
env: TZ="America/Anchorage" FMTS=misc
- node_js: "4"
env: TZ="America/Barbados" FMTS=misc
- node_js: "0.12"
env: TZ="America/Cayman" FMTS=misc
- node_js: "0.10"
env: TZ="Pacific/Honolulu" FMTS=misc
- node_js: "0.8"
env: TZ="America/Mexico_City" FMTS=misc
before_install:
- "npm install -g npm@4.3.0"
- "npm install -g mocha@2.x voc"

@ -78,6 +78,8 @@ enhancements, additional features by request, and dedicated support.
* [Sheet Objects](#sheet-objects)
+ [Worksheet Object](#worksheet-object)
+ [Chartsheet Object](#chartsheet-object)
+ [Macrosheet Object](#macrosheet-object)
+ [Dialogsheet Object](#dialogsheet-object)
* [Workbook Object](#workbook-object)
+ [Workbook File Properties](#workbook-file-properties)
* [Workbook-Level Attributes](#workbook-level-attributes)
@ -91,6 +93,7 @@ enhancements, additional features by request, and dedicated support.
+ [Hyperlinks](#hyperlinks)
+ [Cell Comments](#cell-comments)
+ [Sheet Visibility](#sheet-visibility)
+ [VBA and Macros](#vba-and-macros)
- [Parsing Options](#parsing-options)
* [Input Type](#input-type)
* [Guessing File Type](#guessing-file-type)
@ -124,6 +127,7 @@ enhancements, additional features by request, and dedicated support.
+ [Lotus Formatted Text (PRN)](#lotus-formatted-text-prn)
+ [Data Interchange Format (DIF)](#data-interchange-format-dif)
+ [HTML](#html)
+ [Rich Text Format (RTF)](#rich-text-format-rtf)
- [Testing](#testing)
* [Node](#node)
* [Browser](#browser)
@ -983,6 +987,16 @@ Chartsheets are represented as standard sheets. They are distinguished with the
The underlying data and `!ref` refer to the cached data in the chartsheet. The
first row of the chartsheet is the underlying header.
#### Macrosheet Object
Macrosheets are represented as standard sheets. They are distinguished with the
`!type` property set to `"macro"`.
#### Dialogsheet Object
Dialogsheets are represented as standard sheets. They are distinguished with the
`!type` property set to `"dialog"`.
### Workbook Object
`workbook.SheetNames` is an ordered list of the sheets in the workbook
@ -1421,6 +1435,37 @@ if a sheet is visible is to check if the `Hidden` property is logical truth:
```
</details>
#### VBA and Macros
VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
property of the workbook object when the `bookVBA` option is `true`. They are
supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The `XLSM` and `XLSB`
writers automatically insert the data blobs if it is present in the workbook.
<details>
<summary><b>Macrosheets</b> (click to show)</summary>
Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
stored automation commands. These are exposed in objects with the `!type`
property set to `"macro"`.
</details>
<details>
<summary><b>Detecting macros in workbooks</b> (click to show)</summary>
The `vbaraw` field will only be set if macros are present, so testing is simple:
```js
function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
if(!!wb.vbaraw) return true;
const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
return sheets.some((ws) => !!ws && ws['!type']=='macro');
}
```
</details>
## Parsing Options
The exported `read` and `readFile` functions accept an options argument:
@ -1459,7 +1504,9 @@ The exported `read` and `readFile` functions accept an options argument:
- `sheetRows-1` rows will be generated when looking at the JSON object output
(since the header row is counted as a row when parsing the data)
- `bookVBA` merely exposes the raw VBA CFB object. It does not parse the data.
XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`.
XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`. BIFF8 XLS mixes
the VBA entries alongside the core Workbook entry, so the library generates a
new XLSB-compatible blob from the XLS CFB container.
- Currently only XOR encryption is supported. Unsupported error will be thrown
for files employing other encryption methods.
- WTF is mainly for development. By default, the parser will suppress read
@ -1591,6 +1638,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
| `html` | `.html` | none | single | HTML Document |
| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
| `rtf` | `.rtf` | none | single | Rich Text Format |
| `prn` | `.prn` | none | single | Lotus Formatted Text |
- `compression` only applies to formats with ZIP containers.
@ -1928,6 +1976,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | :o: | |
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
| HTML Tables | :o: | :o: |
| RTF Tables | | :o: |
### Excel 2007+ XML (XLSX/XLSM)
@ -2151,6 +2200,17 @@ the metadata the output is valid HTML, although it does accept bare `&` symbols.
</details>
#### Rich Text Format (RTF)
<details>
<summary>(click to show)</summary>
Excel RTF worksheets are stored in clipboard when copying cells or ranges from a
worksheet. The supported codes are a subset of the Word RTF support.
</details>
## Testing
### Node
@ -2394,6 +2454,7 @@ granted by the Apache 2.0 License are reserved by the Original Author.
- `MS-XLSB`: Excel (.xlsb) Binary File Format
- `MS-XLSX`: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
- `XLS`: Microsoft Office Excel 97-2007 Binary File Format Specification
- `RTF`: Rich Text Format
</details>

@ -28,15 +28,16 @@ program
.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)')
.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)')
.option('-S, --formulae', 'print formulae')
.option('-j, --json', 'emit formatted JSON (all fields text)')
.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
.option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
.option('-H, --html', 'emit HTML')
.option('-D, --dif', 'emit data interchange format (dif)')
.option('-K, --sylk', 'emit symbolic link (sylk)')
.option('-P, --prn', 'emit formatted text (prn)')
.option('-t, --txt', 'emit delimited text (txt)')
.option('-S, --formulae', 'emit list of values and formulae')
.option('-j, --json', 'emit formatted JSON (all fields text)')
.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
.option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
.option('-H, --html', 'emit HTML to <sheetname> or <file>.html')
.option('-D, --dif', 'emit DIF to <sheetname> or <file>.dif (Lotus DIF)')
.option('-K, --sylk', 'emit SYLK to <sheetname> or <file>.slk (Excel SYLK)')
.option('-P, --prn', 'emit PRN to <sheetname> or <file>.prn (Lotus PRN)')
.option('-t, --txt', 'emit TXT to <sheetname> or <file>.txt (UTF-8 TSV)')
.option('-r, --rtf', 'emit RTF to <sheetname> or <file>.txt (Table RTF)')
.option('-F, --field-sep <sep>', 'CSV field separator', ",")
.option('-R, --row-sep <sep>', 'CSV row separator', "\n")
@ -62,7 +63,7 @@ var workbook_formats = [
['xlsm', 'xlsm', 'xlsm'],
['xlsb', 'xlsb', 'xlsb'],
['xls', 'xls', 'xls'],
//['biff5', 'biff5', 'xls'],
['biff5', 'biff5', 'xls'],
['ods', 'ods', 'ods'],
['fods', 'fods', 'fods']
];
@ -180,11 +181,12 @@ if(program.readOnly) process.exit(0);
/* single worksheet formats */
[
['biff2', '.xls'],
//['biff3', '.xls'],
//['biff4', '.xls'],
['biff3', '.xls'],
['biff4', '.xls'],
['sylk', '.slk'],
['html', '.html'],
['prn', '.prn'],
['rtf', '.rtf'],
['txt', '.txt'],
['dif', '.dif']
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {

@ -27,7 +27,7 @@ function write_double_le(b/*:RawBytes|CFBlob*/, v/*:number*/, idx/*:number*/) {
var __toBuffer = function(bufs) { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; };
var ___toBuffer = __toBuffer;
var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join(""); };
var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join("").replace(chr0,''); };
var ___utf16le = __utf16le;
var __hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<s+l; ++i) ss.push(("0" + b[i].toString(16)).slice(-2)); return ss.join(""); };
var ___hexlify = __hexlify;
@ -46,7 +46,7 @@ __double = ___double = function(b/*:RawBytes|CFBlob*/, idx/*:number*/) { return
var is_buf = function is_buf_a(a) { return Array.isArray(a); };
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); };
__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) : "";};
__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);};
@ -61,7 +61,7 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
/* from js-xls */
if(typeof cptable !== 'undefined') {
__utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(1200, b.slice(s,e)); };
__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)) : "";};
__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)) : "";};

@ -10,11 +10,39 @@ var RTF = (function() {
}
function rtf_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
throw new Error("Unsupported RTF");
var o = opts || {};
var ws/*:Worksheet*/ = ({}/*:any*/);
var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
// TODO: parse
if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
ws['!ref'] = encode_range(range);
return ws;
}
function rtf_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
function sheet_to_rtf() { throw new Error("Unsupported"); }
/* TODO: this is a stub */
function sheet_to_rtf(ws/*:Worksheet*/, opts)/*:string*/ {
var o = ["{\\rtf1\\ansi"];
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) {
o.push("\\trowd\\trautofit1");
for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
o.push("\\pard\\intbl");
for(C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws[R]||[])[C]: ws[coord];
if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
o.push(" " + (cell.w || (format_cell(cell), cell.w)));
o.push("\\cell");
}
o.push("\\pard\\intbl\\row");
}
return o.join("") + "}";
}
return {
to_workbook: rtf_to_workbook,

9
bits/59_vba.js Normal file

@ -0,0 +1,9 @@
function make_vba_xls(cfb/*:CFBContainer*/) {
var newcfb = CFB.utils.cfb_new({root:"R"});
cfb.FullPaths.forEach(function(p, i) {
if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
var newpath = p.replace(/^[^/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
});
return CFB.write(newcfb);
}

@ -136,7 +136,8 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
/* Others */
case '<ArchID': break;
case '<AlternateContent': pass=true; break;
case '<AlternateContent':
case '<AlternateContent>': pass=true; break;
case '</AlternateContent>': pass=false; break;
/* TODO */

@ -868,6 +868,7 @@ else/*:: if(cfb instanceof CFBContainer) */ {
/* Quattro Pro 9 */
else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
else throw new Error("Cannot find Workbook stream");
if(options.bookVBA && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir')) WorkbookP.vbaraw = make_vba_xls(cfb);
}
var props = {};

@ -60,3 +60,13 @@ Chartsheets are represented as standard sheets. They are distinguished with the
The underlying data and `!ref` refer to the cached data in the chartsheet. The
first row of the chartsheet is the underlying header.
#### Macrosheet Object
Macrosheets are represented as standard sheets. They are distinguished with the
`!type` property set to `"macro"`.
#### Dialogsheet Object
Dialogsheets are represented as standard sheets. They are distinguished with the
`!type` property set to `"dialog"`.

31
docbits/77_macrovba.md Normal file

@ -0,0 +1,31 @@
#### VBA and Macros
VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
property of the workbook object when the `bookVBA` option is `true`. They are
supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The `XLSM` and `XLSB`
writers automatically insert the data blobs if it is present in the workbook.
<details>
<summary><b>Macrosheets</b> (click to show)</summary>
Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
stored automation commands. These are exposed in objects with the `!type`
property set to `"macro"`.
</details>
<details>
<summary><b>Detecting macros in workbooks</b> (click to show)</summary>
The `vbaraw` field will only be set if macros are present, so testing is simple:
```js
function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
if(!!wb.vbaraw) return true;
const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
return sheets.some((ws) => !!ws && ws['!type']=='macro');
}
```
</details>

@ -36,7 +36,9 @@ The exported `read` and `readFile` functions accept an options argument:
- `sheetRows-1` rows will be generated when looking at the JSON object output
(since the header row is counted as a row when parsing the data)
- `bookVBA` merely exposes the raw VBA CFB object. It does not parse the data.
XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`.
XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`. BIFF8 XLS mixes
the VBA entries alongside the core Workbook entry, so the library generates a
new XLSB-compatible blob from the XLS CFB container.
- Currently only XOR encryption is supported. Unsupported error will be thrown
for files employing other encryption methods.
- WTF is mainly for development. By default, the parser will suppress read

@ -45,6 +45,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
| `html` | `.html` | none | single | HTML Document |
| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
| `rtf` | `.rtf` | none | single | Rich Text Format |
| `prn` | `.prn` | none | single | Lotus Formatted Text |
- `compression` only applies to formats with ZIP containers.

@ -28,6 +28,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | :o: | |
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
| HTML Tables | :o: | :o: |
| RTF Tables | | :o: |
### Excel 2007+ XML (XLSX/XLSM)
@ -251,3 +252,14 @@ the metadata the output is valid HTML, although it does accept bare `&` symbols.
</details>
#### Rich Text Format (RTF)
<details>
<summary>(click to show)</summary>
Excel RTF worksheets are stored in clipboard when copying cells or ranges from a
worksheet. The supported codes are a subset of the Word RTF support.
</details>

@ -22,6 +22,7 @@
- `MS-XLSB`: Excel (.xlsb) Binary File Format
- `MS-XLSX`: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
- `XLS`: Microsoft Office Excel 97-2007 Binary File Format Specification
- `RTF`: Rich Text Format
</details>

@ -25,6 +25,7 @@ digraph G {
dif [label="DIF"];
slk [label="SYLK"];
prn [label="PRN"];
rtf [label="RTF"];
wk1 [label="WK1/2\n123"];
wk3 [label="WK3/4"];
wqb [label="WQ*\nWB*"];
@ -62,6 +63,7 @@ digraph G {
wk1 -> csf
wqb -> csf
dif -> csf
csf -> rtf
prn -> csf
csf -> prn
csv -> csf

Binary file not shown.

Before

Width:  |  Height:  |  Size: 170 KiB

After

Width:  |  Height:  |  Size: 179 KiB

@ -73,6 +73,8 @@ enhancements, additional features by request, and dedicated support.
* [Sheet Objects](#sheet-objects)
+ [Worksheet Object](#worksheet-object)
+ [Chartsheet Object](#chartsheet-object)
+ [Macrosheet Object](#macrosheet-object)
+ [Dialogsheet Object](#dialogsheet-object)
* [Workbook Object](#workbook-object)
+ [Workbook File Properties](#workbook-file-properties)
* [Workbook-Level Attributes](#workbook-level-attributes)
@ -86,6 +88,7 @@ enhancements, additional features by request, and dedicated support.
+ [Hyperlinks](#hyperlinks)
+ [Cell Comments](#cell-comments)
+ [Sheet Visibility](#sheet-visibility)
+ [VBA and Macros](#vba-and-macros)
- [Parsing Options](#parsing-options)
* [Input Type](#input-type)
* [Guessing File Type](#guessing-file-type)
@ -119,6 +122,7 @@ enhancements, additional features by request, and dedicated support.
+ [Lotus Formatted Text (PRN)](#lotus-formatted-text-prn)
+ [Data Interchange Format (DIF)](#data-interchange-format-dif)
+ [HTML](#html)
+ [Rich Text Format (RTF)](#rich-text-format-rtf)
- [Testing](#testing)
* [Node](#node)
* [Browser](#browser)
@ -902,6 +906,16 @@ Chartsheets are represented as standard sheets. They are distinguished with the
The underlying data and `!ref` refer to the cached data in the chartsheet. The
first row of the chartsheet is the underlying header.
#### Macrosheet Object
Macrosheets are represented as standard sheets. They are distinguished with the
`!type` property set to `"macro"`.
#### Dialogsheet Object
Dialogsheets are represented as standard sheets. They are distinguished with the
`!type` property set to `"dialog"`.
### Workbook Object
`workbook.SheetNames` is an ordered list of the sheets in the workbook
@ -1301,6 +1315,31 @@ if a sheet is visible is to check if the `Hidden` property is logical truth:
[ [ 'Visible', true ], [ 'Hidden', false ], [ 'VeryHidden', false ] ]
```
#### VBA and Macros
VBA Macros are stored in a special data blob that is exposed in the `vbaraw`
property of the workbook object when the `bookVBA` option is `true`. They are
supported in `XLSM`, `XLSB`, and `BIFF8 XLS` formats. The `XLSM` and `XLSB`
writers automatically insert the data blobs if it is present in the workbook.
Older versions of Excel also supported a non-VBA "macrosheet" sheet type that
stored automation commands. These are exposed in objects with the `!type`
property set to `"macro"`.
The `vbaraw` field will only be set if macros are present, so testing is simple:
```js
function wb_has_macro(wb/*:workbook*/)/*:boolean*/ {
if(!!wb.vbaraw) return true;
const sheets = wb.SheetNames.map((n) => wb.Sheets[n]);
return sheets.some((ws) => !!ws && ws['!type']=='macro');
}
```
## Parsing Options
The exported `read` and `readFile` functions accept an options argument:
@ -1339,7 +1378,9 @@ The exported `read` and `readFile` functions accept an options argument:
- `sheetRows-1` rows will be generated when looking at the JSON object output
(since the header row is counted as a row when parsing the data)
- `bookVBA` merely exposes the raw VBA CFB object. It does not parse the data.
XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`.
XLSM and XLSB store the VBA CFB object in `xl/vbaProject.bin`. BIFF8 XLS mixes
the VBA entries alongside the core Workbook entry, so the library generates a
new XLSB-compatible blob from the XLS CFB container.
- Currently only XOR encryption is supported. Unsupported error will be thrown
for files employing other encryption methods.
- WTF is mainly for development. By default, the parser will suppress read
@ -1465,6 +1506,7 @@ output formats. The specific file type is controlled with `bookType` option:
| `sylk` | `.sylk` | none | single | Symbolic Link (SYLK) |
| `html` | `.html` | none | single | HTML Document |
| `dif` | `.dif` | none | single | Data Interchange Format (DIF) |
| `rtf` | `.rtf` | none | single | Rich Text Format |
| `prn` | `.prn` | none | single | Lotus Formatted Text |
- `compression` only applies to formats with ZIP containers.
@ -1781,6 +1823,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Quattro Pro Spreadsheet (WQ1/WQ2/WB1/WB2/WB3/QPW) | :o: | |
| **Other Common Spreadsheet Output Formats** |:-----:|:-----:|
| HTML Tables | :o: | :o: |
| RTF Tables | | :o: |
### Excel 2007+ XML (XLSX/XLSM)
@ -1956,6 +1999,14 @@ Excel HTML worksheets include special metadata encoded in styles. For example,
the metadata the output is valid HTML, although it does accept bare `&` symbols.
#### Rich Text Format (RTF)
Excel RTF worksheets are stored in clipboard when copying cells or ranges from a
worksheet. The supported codes are a subset of the Word RTF support.
## Testing
### Node
@ -2173,6 +2224,7 @@ granted by the Apache 2.0 License are reserved by the Original Author.
- `MS-XLSB`: Excel (.xlsb) Binary File Format
- `MS-XLSX`: Excel (.xlsx) Extensions to the Office Open XML SpreadsheetML File Format
- `XLS`: Microsoft Office Excel 97-2007 Binary File Format Specification
- `RTF`: Rich Text Format
- ISO/IEC 29500:2012(E) "Information technology — Document description and processing languages — Office Open XML File Formats"

@ -26,6 +26,8 @@
* [Sheet Objects](README.md#sheet-objects)
+ [Worksheet Object](README.md#worksheet-object)
+ [Chartsheet Object](README.md#chartsheet-object)
+ [Macrosheet Object](README.md#macrosheet-object)
+ [Dialogsheet Object](README.md#dialogsheet-object)
* [Workbook Object](README.md#workbook-object)
+ [Workbook File Properties](README.md#workbook-file-properties)
* [Workbook-Level Attributes](README.md#workbook-level-attributes)
@ -39,6 +41,7 @@
+ [Hyperlinks](README.md#hyperlinks)
+ [Cell Comments](README.md#cell-comments)
+ [Sheet Visibility](README.md#sheet-visibility)
+ [VBA and Macros](README.md#vba-and-macros)
- [Parsing Options](README.md#parsing-options)
* [Input Type](README.md#input-type)
* [Guessing File Type](README.md#guessing-file-type)
@ -72,6 +75,7 @@
+ [Lotus Formatted Text (PRN)](README.md#lotus-formatted-text-prn)
+ [Data Interchange Format (DIF)](README.md#data-interchange-format-dif)
+ [HTML](README.md#html)
+ [Rich Text Format (RTF)](README.md#rich-text-format-rtf)
- [Testing](README.md#testing)
* [Node](README.md#node)
* [Browser](README.md#browser)

@ -21,6 +21,7 @@ type Workbook = {
SSF?: SSFTable;
cfb?: any;
vbaraw?: any;
};
type WBWBProps = {

19
test.js

@ -576,12 +576,14 @@ describe('parse options', function() {
assert(typeof wb.vbaraw === 'undefined');
wb = X.read(fs.readFileSync(paths.nfxlsb), {type:TYPE});
assert(typeof wb.vbaraw === 'undefined');
wb = X.read(fs.readFileSync(paths.nfxls), {type:TYPE});
assert(typeof wb.vbaraw === 'undefined');
});
it('bookVBA should generate vbaraw (XLSX/XLSB)', function() {
var wb = X.read(fs.readFileSync(paths.nfxlsx),{type:TYPE, bookVBA:true});
assert(wb.vbaraw);
wb = X.read(fs.readFileSync(paths.nfxlsb),{type:TYPE, bookVBA:true});
assert(wb.vbaraw);
it('bookVBA should generate vbaraw', function() {
var wb;
wb = X.read(fs.readFileSync(paths.nfxlsx),{type:TYPE, bookVBA:true}); assert(wb.vbaraw);
wb = X.read(fs.readFileSync(paths.nfxlsb),{type:TYPE, bookVBA:true}); assert(wb.vbaraw);
wb = X.read(fs.readFileSync(paths.nfxls),{type:TYPE, bookVBA:true}); assert(wb.vbaraw);
});
});
});
@ -1068,12 +1070,9 @@ describe('parse features', function() {
assert.equal(sheet[3]['てすと'], '2/14/14');
});
it('cellDates should not affect formatted text', function() {
var wb1, ws1, wb2, ws2;
var sheetName = 'Sheet1';
wb1 = X.read(fs.readFileSync(paths.dtxlsx), {type:TYPE});
ws1 = wb1.Sheets[sheetName];
wb2 = X.read(fs.readFileSync(paths.dtxlsb), {type:TYPE});
ws2 = wb2.Sheets[sheetName];
var ws1 = X.read(fs.readFileSync(paths.dtxlsx), {type:TYPE}).Sheets[sheetName];
var ws2 = X.read(fs.readFileSync(paths.dtxlsb), {type:TYPE}).Sheets[sheetName];
assert.equal(X.utils.sheet_to_csv(ws1),X.utils.sheet_to_csv(ws2));
});
});

@ -12,6 +12,7 @@ apachepoi_hyperlink.xlsb
apachepoi_protected_passtika.xlsb.pending
apachepoi_sample.xlsb
apachepoi_testVarious.xlsb
author_snowman.xlsb
calendar_stress_test.xlsb.pending
cell_style_simple.xlsb
column_width.xlsb
@ -30,6 +31,7 @@ number_format_entities.xlsb
number_format_russian.xlsb
numfmt_1_russian.xlsb
outline.xlsb
page_margins_2016.xlsb
phonetic_text.xlsb
pivot_table_named_range.xlsb
pivot_table_test.xlsb
@ -142,6 +144,7 @@ apachepoi_56420.xlsx
apachepoi_56502.xlsx
apachepoi_56511.xlsx
apachepoi_56514.xlsx
apachepoi_56557.xlsx
apachepoi_56574.xlsx
apachepoi_56644.xlsx
apachepoi_56688_1.xlsx
@ -188,7 +191,13 @@ apachepoi_59746_NoRowNums.xlsx
apachepoi_59775.xlsx
apachepoi_60255_extra_drawingparts.xlsx
apachepoi_60289.xlsx
#apachepoi_60384.xlsx
apachepoi_60709.xlsx
#apachepoi_60825.xlsx # Missing worksheet xml file
apachepoi_61034.xlsx
apachepoi_61060-conditional-number-formatting.xlsx
apachepoi_61063.xlsx
apachepoi_61281.xlsx
apachepoi_AverageTaxRates.xlsx
apachepoi_Booleans.xlsx
apachepoi_BrNotClosed.xlsx
@ -214,6 +223,7 @@ apachepoi_FormulaSheetRange.xlsx
apachepoi_GroupTest.xlsx
apachepoi_InlineStrings.xlsx
apachepoi_Intersection-52111-xssf.xlsx
apachepoi_MatrixFormulaEvalTestData.xlsx
apachepoi_NewStyleConditionalFormattings.xlsx
apachepoi_NewlineInFormulas.xlsx
# apachepoi_NumberFormatApproxTests.xlsx # xlml
@ -231,6 +241,7 @@ apachepoi_SimpleWithComments.xlsx
apachepoi_StructuredReferences.xlsx
apachepoi_StructuredRefs-lots-with-lookups.xlsx
# apachepoi_Tables.xlsx # xlml
apachepoi_TablesWithDifferentHeaders.xlsx
apachepoi_TestShiftRowSharedFormula.xlsx
apachepoi_TextFormatTests.xlsx
apachepoi_Themes.xlsx
@ -254,15 +265,20 @@ apachepoi_atp.xlsx
apachepoi_bug60858.xlsx
apachepoi_chartTitle_noTitle.xlsx
apachepoi_chartTitle_withTitle.xlsx
apachepoi_chartTitle_withTitleFormula.xlsx
apachepoi_chart_sheet.xlsx
apachepoi_commentTest.xlsx
apachepoi_comments.xlsx
apachepoi_conditional_formatting_with_formula_on_second_sheet.xlsx
apachepoi_craftonhills.edu_programreview_report.aspx_goalpriorityreport_0011d159-1eeb-4b63-8833-867b0926e5f3.xlsx
apachepoi_customIndexedColors.xlsx
apachepoi_dataValidationTableRange.xlsx
apachepoi_evaluate_formula_with_structured_table_references.xlsx
apachepoi_headerFooterTest.xlsx
apachepoi_noSharedStringTable.xlsx
apachepoi_picture.xlsx
apachepoi_poc-shared-strings.xlsx
apachepoi_poc-xmlbomb-empty.xlsx
apachepoi_poc-xmlbomb.xlsx
# apachepoi_protected_passtika.xlsx # password
apachepoi_ref-56737.xlsx
@ -275,7 +291,10 @@ apachepoi_sample.xlsx
apachepoi_shared_formulas.xlsx
apachepoi_sheetProtection_allLocked.xlsx
apachepoi_sheetProtection_not_protected.xlsx
apachepoi_simple-monthly-budget.xlsx
# apachepoi_style-alternate-content.xlsx # bad xml
apachepoi_styles.xlsx
apachepoi_tableStyle.xlsx
apachepoi_template.xlsx
apachepoi_unicodeSheetName.xlsx
apachepoi_workbookProtection-sheet_password-2013.xlsx
@ -287,6 +306,7 @@ apachepoi_workbookProtection_workbook_structure_protected.xlsx
apachepoi_workbookProtection_workbook_windows_protected.xlsx
apachepoi_workbookProtection_worksheet_protected.xlsx
apachepoi_xlsx-jdbc.xlsx
author_snowman.xlsx
calendar_stress_test.xlsx.pending
cell_style_simple.xlsx
column_width.xlsx
@ -364,6 +384,7 @@ openpyxl_r_nonstandard_workbook_name.xlsx
openpyxl_r_null_archive.xlsx.pending
openpyxl_r_null_file.xlsx.pending
outline.xlsx
page_margins_2016.xlsx
phonetic_text.xlsx
pivot_table_named_range.xlsx
rich_text_stress.xlsx
@ -422,6 +443,7 @@ spout-xlsx_file_with_no_sheets_in_workbook_xml.xlsx
# spout-xlsx_file_with_sheet_xml_not_matching_content_types.xlsx
spout-xlsx_one_sheet_with_inline_strings.xlsx
spout-xlsx_one_sheet_with_invalid_xml_characters.xlsx
spout-xlsx_one_sheet_with_pre_encoded_html_entities.xlsx
spout-xlsx_one_sheet_with_shared_multiline_strings.xlsx
spout-xlsx_one_sheet_with_shared_strings.xlsx
spout-xlsx_one_sheet_with_shared_strings_containing_text_and_hyperlink_in_same_cell.xlsx
@ -441,15 +463,18 @@ spout-xlsx_sheet_with_lots_of_shared_strings.xlsx
spout-xlsx_sheet_with_missing_cell_reference.xlsx
spout-xlsx_sheet_with_no_cells.xlsx
spout-xlsx_sheet_with_no_shared_strings_file.xlsx
spout-xlsx_sheet_with_prefixed_shared_strings_xml.xlsx
spout-xlsx_sheet_with_prefixed_xml_files.xlsx
spout-xlsx_sheet_with_preserve_space_shared_strings.xlsx
spout-xlsx_sheet_with_pronunciation.xlsx
spout-xlsx_sheet_with_row_not_starting_at_column_a.xlsx
spout-xlsx_sheet_with_same_numeric_value_date_formatted_differently.xlsx
spout-xlsx_sheet_with_untrimmed_inline_strings.xlsx
spout-xlsx_sheet_with_zeros_in_row.xlsx
spout-xlsx_sheet_without_dimensions_and_empty_cells.xlsx
spout-xlsx_sheet_without_dimensions_but_spans_and_empty_cells.xlsx
spout-xlsx_two_sheets_with_custom_names.xlsx
spout-xlsx_two_sheets_with_custom_names_and_custom_active_tab.xlsx
spout-xlsx_two_sheets_with_inline_strings.xlsx
spout-xlsx_two_sheets_with_shared_strings.xlsx
spout-xlsx_two_sheets_with_sheets_definition_in_reverse_order.xlsx
@ -551,7 +576,9 @@ roo_whitespace.xlsm
AutoFilter.ods
BlankSheetTypes.ods
apachepoi_SampleSS.ods
author_snowman.ods
cell_style_simple.ods
comments_stress_test.ods
formula_stress_test.ods
merge_cells.ods
number_format.ods
@ -612,6 +639,7 @@ spout-ods_sheet_with_untrimmed_strings.ods
spout-ods_sheet_with_various_spaces.ods
spout-ods_sheet_with_zeros_in_row.ods
spout-ods_two_sheets_with_custom_names.ods
spout-ods_two_sheets_with_no_settings_xml_file.ods
spout-ods_two_sheets_with_strings.ods
sushi.ods
biff5/NumberFormatCondition.xls
@ -839,6 +867,9 @@ apachepoi_59830.xls
apachepoi_59858.xls
apachepoi_60273.xls
# apachepoi_60284.xls
apachepoi_61045_govdocs1_626534.xls
apachepoi_61287.xls
# apachepoi_61300.xls # node 0.8 oob
apachepoi_AbnormalSharedFormulaFlag.xls
apachepoi_AreaErrPtg.xls
# apachepoi_BOOK_in_capitals.xls # note: worksheet length exceeds 31 chars
@ -881,6 +912,7 @@ apachepoi_IrrNpvTestCaseData.xls
# apachepoi_LookupFunctionsTestCaseData.xls # xlml
apachepoi_MRExtraLines.xls
apachepoi_MatchFunctionTestCaseData.xls
apachepoi_MatrixFormulaEvalTestData.xls
apachepoi_MissingBits.xls
apachepoi_NewStyleConditionalFormattings.xls
apachepoi_NoGutsRecords.xls
@ -942,6 +974,7 @@ apachepoi_WithTwoHyperLinks.xls
apachepoi_WrongFormulaRecordType.xls
apachepoi_XRefCalc.xls
apachepoi_XRefCalcData.xls
apachepoi_angelo.edu_content_files_19555-nsse-2011-multiyear-benchmark.xls
apachepoi_ar.org.apsme.www_Form%20Inscripcion%20Curso%20NO%20Socios.xls
apachepoi_at.gv.land-oberoesterreich.www_cps_rde_xbcr_SID-4A1B954F-5C07F98E_ooe_stat_download_bp10.xls
apachepoi_atp.xls
@ -974,6 +1007,7 @@ apachepoi_ex47747-sharedFormula.xls
apachepoi_excel_with_embeded.xls
apachepoi_excelant.xls.pending
apachepoi_externalFunctionExample.xls
apachepoi_external_image.xls
# apachepoi_finance.xls # xlml
apachepoi_florida_data.ashx.xls
apachepoi_intercept.xls
@ -1008,6 +1042,7 @@ apachepoi_text.xls
apachepoi_unicodeNameRecord.xls
apachepoi_xor-encryption-abc.xls.pending
# apachepoi_yearfracExamples.xls # xlml
author_snowman.xls
calendar_stress_test.xls.pending
cell_style_simple.xls
column_width.xls
@ -1079,6 +1114,7 @@ jxls-examples_chart.xls
jxls-examples_colouring.xls
jxls-examples_department.xls
jxls-examples_dynamiccolumns.xls
jxls-examples_dynamicolumns.xls
jxls-examples_employees.xls
jxls-examples_ex_temp.xls
jxls-examples_grouping.xls
@ -1202,6 +1238,8 @@ number_format_entities.xls
number_format_russian.xls
numfmt_1_russian.xls
outline.xls
page_margins_2016.xls
page_margins_2016_5.xls
phonetic_text.xls
phpexcel_bad_cfb_dir.xls
pivot_table_named_range.xls

@ -576,12 +576,14 @@ describe('parse options', function() {
assert(typeof wb.vbaraw === 'undefined');
wb = X.read(fs.readFileSync(paths.nfxlsb), {type:TYPE});
assert(typeof wb.vbaraw === 'undefined');
wb = X.read(fs.readFileSync(paths.nfxls), {type:TYPE});
assert(typeof wb.vbaraw === 'undefined');
});
it('bookVBA should generate vbaraw (XLSX/XLSB)', function() {
var wb = X.read(fs.readFileSync(paths.nfxlsx),{type:TYPE, bookVBA:true});
assert(wb.vbaraw);
wb = X.read(fs.readFileSync(paths.nfxlsb),{type:TYPE, bookVBA:true});
assert(wb.vbaraw);
var wb;
wb = X.read(fs.readFileSync(paths.nfxlsx),{type:TYPE, bookVBA:true}); assert(wb.vbaraw);
wb = X.read(fs.readFileSync(paths.nfxlsb),{type:TYPE, bookVBA:true}); assert(wb.vbaraw);
wb = X.read(fs.readFileSync(paths.nfxls),{type:TYPE, bookVBA:true}); assert(wb.vbaraw);
});
});
});
@ -1068,12 +1070,9 @@ describe('parse features', function() {
assert.equal(sheet[3]['てすと'], '2/14/14');
});
it('cellDates should not affect formatted text', function() {
var wb1, ws1, wb2, ws2;
var sheetName = 'Sheet1';
wb1 = X.read(fs.readFileSync(paths.dtxlsx), {type:TYPE});
ws1 = wb1.Sheets[sheetName];
wb2 = X.read(fs.readFileSync(paths.dtxlsb), {type:TYPE});
ws2 = wb2.Sheets[sheetName];
var ws1 = X.read(fs.readFileSync(paths.dtxlsx), {type:TYPE}).Sheets[sheetName];
var ws2 = X.read(fs.readFileSync(paths.dtxlsb), {type:TYPE}).Sheets[sheetName];
assert.equal(X.utils.sheet_to_csv(ws1),X.utils.sheet_to_csv(ws2));
});
});

@ -172,6 +172,7 @@ var filenames = [
['sheetjs.slk'],
['sheetjs.htm'],
['sheetjs.dif'],
['sheetjs.rtf'],
['sheetjs.prn']
];

@ -20,19 +20,21 @@ program
.option('-M, --xlsm', 'emit XLSM to <sheetname> or <file>.xlsm')
.option('-X, --xlsx', 'emit XLSX to <sheetname> or <file>.xlsx')
.option('-Y, --ods', 'emit ODS to <sheetname> or <file>.ods')
.option('-8, --xls', 'emit XLS to <sheetname> or <file>.xls (BIFF8)')
.option('-2, --biff2','emit XLS to <sheetname> or <file>.xls (BIFF2)')
.option('-6, --xlml', 'emit SSML to <sheetname> or <file>.xls (2003 XML)')
.option('-T, --fods', 'emit FODS to <sheetname> or <file>.fods (Flat ODS)')
.option('-S, --formulae', 'print formulae')
.option('-j, --json', 'emit formatted JSON (all fields text)')
.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
.option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
.option('-H, --html', 'emit HTML')
.option('-D, --dif', 'emit data interchange format (dif)')
.option('-K, --sylk', 'emit symbolic link (sylk)')
.option('-P, --prn', 'emit formatted text (prn)')
.option('-t, --txt', 'emit delimited text (txt)')
.option('-S, --formulae', 'emit list of values and formulae')
.option('-j, --json', 'emit formatted JSON (all fields text)')
.option('-J, --raw-js', 'emit raw JS object (raw numbers)')
.option('-A, --arrays', 'emit rows as JS objects (raw numbers)')
.option('-H, --html', 'emit HTML to <sheetname> or <file>.html')
.option('-D, --dif', 'emit DIF to <sheetname> or <file>.dif (Lotus DIF)')
.option('-K, --sylk', 'emit SYLK to <sheetname> or <file>.slk (Excel SYLK)')
.option('-P, --prn', 'emit PRN to <sheetname> or <file>.prn (Lotus PRN)')
.option('-t, --txt', 'emit TXT to <sheetname> or <file>.txt (UTF-8 TSV)')
.option('-r, --rtf', 'emit RTF to <sheetname> or <file>.txt (Table RTF)')
.option('-F, --field-sep <sep>', 'CSV field separator', ",")
.option('-R, --row-sep <sep>', 'CSV row separator', "\n")
@ -52,11 +54,18 @@ program.on('--help', function() {
console.log(' Web Demo: http://oss.sheetjs.com/js-'+n+'/');
});
/* output formats, update list with full option name */
const workbook_formats = ['xlsx', 'xlsm', 'xlsb', 'ods', 'fods'];
/* flag, bookType, default ext */
const workbook_formats = [
['xlsx', 'xlsx', 'xlsx'],
['xlsm', 'xlsm', 'xlsm'],
['xlsb', 'xlsb', 'xlsb'],
['xls', 'xls', 'xls'],
['biff5', 'biff5', 'xls'],
['ods', 'ods', 'ods'],
['fods', 'fods', 'fods']
];
const wb_formats_2 = [
['xlml', 'xlml', 'xls']
['xlml', 'xlml', 'xls']
];
program.parse(process.argv);
@ -94,7 +103,7 @@ function isfmt(m: string): boolean {
const t = m.charAt(0) === "." ? m : "." + m;
return program.output.slice(-t.length) === t;
}
workbook_formats.forEach(function(m) { if(program[m] || isfmt(m)) { wb_fmt(); } });
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
if(seen) {
} else if(program.formulae) opts.cellFormula = true;
@ -134,8 +143,9 @@ let wopts: X.WritingOptions = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
if(program.compress) wopts.compression = true;
/* full workbook formats */
workbook_formats.forEach(function(m) { if(program[m] || isfmt(m)) {
X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m), wopts);
workbook_formats.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) {
wopts.bookType = <X.BookType>(m[1]);
X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
process.exit(0);
} });
@ -168,9 +178,12 @@ if(program.readOnly) process.exit(0);
/* single worksheet formats */
[
['biff2', '.xls'],
['biff3', '.xls'],
['biff4', '.xls'],
['sylk', '.slk'],
['html', '.html'],
['prn', '.prn'],
['rtf', '.rtf'],
['txt', '.txt'],
['dif', '.dif']
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {

2
types/index.d.ts vendored

@ -477,7 +477,7 @@ export type ExcelDataType = 'b' | 'n' | 'e' | 's' | 'd' | 'z';
* Type of generated workbook
* @default 'xlsx'
*/
export type BookType = 'xlsx' | 'xlsm' | 'xlsb' | 'xls' | 'biff8' | 'biff2' | 'xlml' | 'ods' | 'fods' | 'csv' | 'txt' | 'sylk' | 'html' | 'dif' | 'prn';
export type BookType = 'xlsx' | 'xlsm' | 'xlsb' | 'xls' | 'biff8' | 'biff2' | 'xlml' | 'ods' | 'fods' | 'csv' | 'txt' | 'sylk' | 'html' | 'dif' | 'rtf' | 'prn';
/** Comment element */
export interface Comment {

@ -2274,7 +2274,7 @@ function write_double_le(b/*:RawBytes|CFBlob*/, v/*:number*/, idx/*:number*/) {
var __toBuffer = function(bufs) { var x = []; for(var i = 0; i < bufs[0].length; ++i) { x.push.apply(x, bufs[0][i]); } return x; };
var ___toBuffer = __toBuffer;
var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join(""); };
var __utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<e; i+=2) ss.push(String.fromCharCode(__readUInt16LE(b,i))); return ss.join("").replace(chr0,''); };
var ___utf16le = __utf16le;
var __hexlify = function(b/*:RawBytes|CFBlob*/,s/*:number*/,l/*:number*/)/*:string*/ { var ss/*:Array<string>*/=[]; for(var i=s; i<s+l; ++i) ss.push(("0" + b[i].toString(16)).slice(-2)); return ss.join(""); };
var ___hexlify = __hexlify;
@ -2293,7 +2293,7 @@ __double = ___double = function(b/*:RawBytes|CFBlob*/, idx/*:number*/) { return
var is_buf = function is_buf_a(a) { return Array.isArray(a); };
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); };
__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) : "";};
__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);};
@ -2308,7 +2308,7 @@ if(has_buf/*:: && typeof Buffer !== 'undefined'*/) {
/* from js-xls */
if(typeof cptable !== 'undefined') {
__utf16le = function(b/*:RawBytes|CFBlob*/,s/*:number*/,e/*:number*/) { return cptable.utils.decode(1200, b.slice(s,e)); };
__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)) : "";};
__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)) : "";};
@ -7030,11 +7030,39 @@ var RTF = (function() {
}
function rtf_to_sheet_str(str/*:string*/, opts)/*:Worksheet*/ {
throw new Error("Unsupported RTF");
var o = opts || {};
var ws/*:Worksheet*/ = ({}/*:any*/);
var range/*:Range*/ = ({s: {c:0, r:0}, e: {c:0, r:0}}/*:any*/);
// TODO: parse
if(!str.match(/\\trowd/)) throw new Error("RTF missing table");
ws['!ref'] = encode_range(range);
return ws;
}
function rtf_to_workbook(d/*:RawData*/, opts)/*:Workbook*/ { return sheet_to_workbook(rtf_to_sheet(d, opts), opts); }
function sheet_to_rtf() { throw new Error("Unsupported"); }
/* TODO: this is a stub */
function sheet_to_rtf(ws/*:Worksheet*/, opts)/*:string*/ {
var o = ["{\\rtf1\\ansi"];
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) {
o.push("\\trowd\\trautofit1");
for(var C = r.s.c; C <= r.e.c; ++C) o.push("\\cellx" + (C+1));
o.push("\\pard\\intbl");
for(C = r.s.c; C <= r.e.c; ++C) {
var coord = encode_cell({r:R,c:C});
cell = dense ? (ws[R]||[])[C]: ws[coord];
if(!cell || cell.v == null && (!cell.f || cell.F)) continue;
o.push(" " + (cell.w || (format_cell(cell), cell.w)));
o.push("\\cell");
}
o.push("\\pard\\intbl\\row");
}
return o.join("") + "}";
}
return {
to_workbook: rtf_to_workbook,
@ -8673,6 +8701,15 @@ function write_comments_bin(data, opts) {
write_record(ba, "BrtEndComments");
return ba.end();
}
function make_vba_xls(cfb/*:CFBContainer*/) {
var newcfb = CFB.utils.cfb_new({root:"R"});
cfb.FullPaths.forEach(function(p, i) {
if(p.slice(-1) === "/" || !p.match(/_VBA_PROJECT_CUR/)) return;
var newpath = p.replace(/^[^/]*/,"R").replace(/\/_VBA_PROJECT_CUR\u0000*/, "");
CFB.utils.cfb_add(newcfb, newpath, cfb.FileIndex[i].content);
});
return CFB.write(newcfb);
}
RELS.DS = "http://schemas.openxmlformats.org/officeDocument/2006/relationships/dialogsheet";
RELS.MS = "http://schemas.microsoft.com/office/2006/relationships/xlMacrosheet";
@ -12881,7 +12918,8 @@ function parse_wb_xml(data, opts)/*:WorkbookFile*/ {
/* Others */
case '<ArchID': break;
case '<AlternateContent': pass=true; break;
case '<AlternateContent':
case '<AlternateContent>': pass=true; break;
case '</AlternateContent>': pass=false; break;
/* TODO */
@ -15291,6 +15329,7 @@ else/*:: if(cfb instanceof CFBContainer) */ {
/* Quattro Pro 9 */
else if((_data=CFB.find(cfb, 'NativeContent_MAIN')) && _data.content) WorkbookP = WK_.to_workbook(_data.content, (options.type = T, options));
else throw new Error("Cannot find Workbook stream");
if(options.bookVBA && CFB.find(cfb, '/_VBA_PROJECT_CUR/VBA/dir'))