version bump 0.11.4: BIFF8 XLS write

- xlsx bin script takes `-8, --xls` options for writing BIFF8
- updated CFB to 0.12.1, CRC32 to 1.1.1
- test file spelling error (h/t @jsoref)
- minified script renames write_shift / read_shift
- UTF8 and XML entity processing

Issues:
- fixes #815 h/t @Neroth
- fixes #739 h/t @LittleBreak @PWDream
- fixes #553 h/t @keyiis
- fixes #492 h/t @FlyingSailor @simonchan2013
This commit is contained in:
SheetJS 2017-09-22 18:18:51 -04:00
parent f03e32fc9a
commit d02650055d
45 changed files with 7607 additions and 6374 deletions

1
.gitignore vendored

@ -20,6 +20,7 @@ tmp
*.[uU][oO][sS]
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
*.[bB][iI][fF][fF][23458]
*.123
*.htm
*.html

@ -22,6 +22,7 @@ tmp
*.[uU][oO][sS]
*.[wW][kKqQbB][S1234567890]
*.[qQ][pP][wW]
*.[bB][iI][fF][fF][23458]
*.123
*.htm
*.html

@ -1564,7 +1564,8 @@ output formats. The specific file type is controlled with `bookType` option:
| `xlsx` | `.xlsx` | ZIP | multi | Excel 2007+ XML Format |
| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet format |
| `biff8` | `.xls` | CFB | multi | Excel 97-2004 Workbook Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
@ -1887,7 +1888,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Excel 2007+ XML Formats (XLSX/XLSM) | :o: | :o: |
| Excel 2007+ Binary Format (XLSB BIFF12) | :o: | :o: |
| Excel 2003-2004 XML Format (XML "SpreadsheetML") | :o: | :o: |
| Excel 97-2004 (XLS BIFF8) | :o: | |
| Excel 97-2004 (XLS BIFF8) | :o: | :o: |
| Excel 5.0/95 (XLS BIFF5) | :o: | |
| Excel 4.0 (XLS/XLW BIFF4) | :o: | |
| Excel 3.0 (XLS BIFF3) | :o: | |

@ -20,6 +20,10 @@ 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('-5, --biff5','emit XLS to <sheetname> or <file>.xls (BIFF5)')
//.option('-4, --biff4','emit XLS to <sheetname> or <file>.xls (BIFF4)')
//.option('-3, --biff3','emit XLS to <sheetname> or <file>.xls (BIFF3)')
.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)')
@ -52,15 +56,22 @@ program.on('--help', function() {
console.log(' Web Demo: http://oss.sheetjs.com/js-'+n+'/');
});
/* output formats, update list with full option name */
var workbook_formats = ['xlsx', 'xlsm', 'xlsb', 'ods', 'fods'];
/* flag, bookType, default ext */
var workbook_formats = [
['xlsx', 'xlsx', 'xlsx'],
['xlsm', 'xlsm', 'xlsm'],
['xlsb', 'xlsb', 'xlsb'],
['xls', 'xls', 'xls'],
//['biff5', 'biff5', 'xls'],
['ods', 'ods', 'ods'],
['fods', 'fods', 'fods']
];
var wb_formats_2 = [
['xlml', 'xlml', 'xls']
['xlml', 'xlml', 'xls']
];
program.parse(process.argv);
var filename = "", sheetname = '';
var filename = '', sheetname = '';
if(program.args[0]) {
filename = program.args[0];
if(program.args[1]) sheetname = program.args[1];
@ -89,13 +100,12 @@ function wb_fmt() {
opts.cellNF = true;
if(program.output) sheetname = program.output;
}
function isfmt(m) {
function isfmt(m/*:string*/)/*:boolean*/ {
if(!program.output) return false;
var t = m.charAt(0) == "." ? m : "." + m;
console.log(m);
return program.output.slice(-m.length) == m;
var 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;
@ -135,8 +145,9 @@ var wopts = ({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 = m[1];
X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m[2]), wopts);
process.exit(0);
} });
@ -169,6 +180,8 @@ if(program.readOnly) process.exit(0);
/* single worksheet formats */
[
['biff2', '.xls'],
//['biff3', '.xls'],
//['biff4', '.xls'],
['sylk', '.slk'],
['html', '.html'],
['prn', '.prn'],
@ -180,8 +193,7 @@ if(program.readOnly) process.exit(0);
process.exit(0);
} });
var oo = "";
var strm = false;
var oo = "", strm = false;
if(!program.quiet) console.error(target_sheet);
if(program.formulae) oo = X.utils.sheet_to_formulae(ws).join("\n");
else if(program.json) oo = JSON.stringify(X.utils.sheet_to_json(ws));

@ -1 +1 @@
XLSX.version = '0.11.3';
XLSX.version = '0.11.4';

@ -12,10 +12,13 @@ declare var bconcat:any;
declare var s2a:any;
declare var chr0:any;
declare var chr1:any;
declare var new_buf:any;
*/
/* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */
/* vim: set ts=2: */
/*jshint eqnull:true */
/*exported CFB */
/*global module, require:false, process:false, Buffer:false, Uint8Array:false */
/*::
declare var DO_NOT_EXPORT_CFB:?boolean;
@ -35,15 +38,35 @@ type CFBFiles = {[n:string]:CFBEntry};
/* [MS-CFB] v20130118 */
var CFB = (function _CFB(){
var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/;
exports.version = '0.12.1';
exports.version = '0.13.1';
/* [MS-CFB] 2.6.4 */
function namecmp(l/*:string*/, r/*:string*/)/*:number*/ {
var L = l.split("/"), R = r.split("/");
for(var i = 0, c = 0, Z = Math.min(L.length, R.length); i < Z; ++i) {
if((c = L[i].length - R[i].length)) return c;
if(L[i] != R[i]) return L[i] < R[i] ? -1 : 1;
}
return L.length - R.length;
}
function dirname(p/*:string*/)/*:string*/ {
if(p.charAt(p.length - 1) == "/") return (p.slice(0,-1).indexOf("/") === -1) ? p : dirname(p.slice(0, -1));
var c = p.lastIndexOf("/");
return (c === -1) ? p : p.slice(0, c+1);
}
function filename(p/*:string*/)/*:string*/ {
if(p.charAt(p.length - 1) == "/") return filename(p.slice(0, -1));
var c = p.lastIndexOf("/");
return (c === -1) ? p : p.slice(c+1);
}
function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ {
var mver = 3; // major version
var ssz = 512; // sector size
var mver = 3;
var ssz = 512;
var nmfs = 0; // number of mini FAT sectors
var ndfs = 0; // number of DIFAT sectors
var dir_start = 0; // first directory sector location
var minifat_start = 0; // first mini FAT sector location
var difat_start = 0; // first mini FAT sector location
var difat_sec_cnt = 0;
var dir_start = 0;
var minifat_start = 0;
var difat_start = 0;
var fat_addrs/*:Array<number>*/ = []; // locations of FAT sectors
@ -67,11 +90,10 @@ var header/*:RawBytes*/ = file.slice(0,ssz);
check_shifts(blob, mver);
// Number of Directory Sectors
var nds/*:number*/ = blob.read_shift(4, 'i');
if(mver === 3 && nds !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + nds);
var dir_cnt/*:number*/ = blob.read_shift(4, 'i');
if(mver === 3 && dir_cnt !== 0) throw new Error('# Directory Sectors: Expected 0 saw ' + dir_cnt);
// Number of FAT Sectors
//var nfs = blob.read_shift(4, 'i');
blob.l += 4;
// First Directory Sector Location
@ -93,7 +115,7 @@ nmfs = blob.read_shift(4, 'i');
difat_start = blob.read_shift(4, 'i');
// Number of DIFAT Sectors
ndfs = blob.read_shift(4, 'i');
difat_sec_cnt = blob.read_shift(4, 'i');
// Grab FAT Sector Locations
for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
@ -105,7 +127,7 @@ for(var q = -1, j = 0; j < 109; ++j) { /* 109 = (512 - blob.l)>>>2; */
/** Break the file up into sectors */
var sectors/*:Array<RawBytes>*/ = sectorify(file, ssz);
sleuth_fat(difat_start, ndfs, sectors, ssz, fat_addrs);
sleuth_fat(difat_start, difat_sec_cnt, sectors, ssz, fat_addrs);
/** Chains */
var sector_list/*:SectorList*/ = make_sector_list(sectors, dir_start, fat_addrs, ssz);
@ -121,19 +143,17 @@ var files/*:CFBFiles*/ = {}, Paths/*:Array<string>*/ = [], FileIndex/*:CFBFileIn
read_directory(dir_start, sector_list, sectors, Paths, nmfs, files, FileIndex);
build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
Paths.shift();
var root_name/*:string*/ = Paths.shift();
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
var find_path = make_find_path(FullPaths, Paths, FileIndex, files, root_name);
return {
raw: {header: header, sectors: sectors},
var o = {
FileIndex: FileIndex,
FullPaths: FullPaths,
FullPathDir: FullPathDir,
find: find_path
FullPathDir: FullPathDir
};
// $FlowIgnore
if(options && options.raw) o.raw = {header: header, sectors: sectors};
return o;
} // parse
/* [MS-CFB] 2.2 Compound File Header -- read up to major version */
@ -220,25 +240,8 @@ function build_full_paths(FI/*:CFBFileIndex*/, FPD/*:CFBFullPathDir*/, FP/*:Arra
}
}
/* [MS-CFB] 2.6.4 */
function make_find_path(FullPaths/*:Array<string>*/, Paths/*:Array<string>*/, FileIndex/*:CFBFileIndex*/, files/*:CFBFiles*/, root_name/*:string*/)/*:CFBFindPath*/ {
var UCFullPaths/*:Array<string>*/ = [];
var UCPaths/*:Array<string>*/ = [], i = 0;
for(i = 0; i < FullPaths.length; ++i) UCFullPaths[i] = FullPaths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
for(i = 0; i < Paths.length; ++i) UCPaths[i] = Paths[i].toUpperCase().replace(chr0,'').replace(chr1,'!');
return function find_path(path/*:string*/)/*:?CFBEntry*/ {
var k/*:boolean*/ = false;
if(path.charCodeAt(0) === 47 /* "/" */) { k=true; path = root_name + path; }
else k = path.indexOf("/") !== -1;
var UCPath/*:string*/ = path.toUpperCase().replace(chr0,'').replace(chr1,'!');
var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
if(w === -1) return null;
return k === true ? FileIndex[w] : files[Paths[w]];
};
}
/** Chase down the rest of the DIFAT chain to build a comprehensive list
DIFAT chains by storing the next sector number as the last 32 bytes */
DIFAT chains by storing the next sector number as the last 32 bits */
function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/, ssz/*:number*/, fat_addrs)/*:void*/ {
var q/*:number*/ = ENDOFCHAIN;
if(idx === ENDOFCHAIN) {
@ -256,7 +259,6 @@ function sleuth_fat(idx/*:number*/, cnt/*:number*/, sectors/*:Array<RawBytes>*/,
/** Follow the linked list of sectors for a given starting point */
function get_sector_list(sectors/*:Array<RawBytes>*/, start/*:number*/, fat_addrs/*:Array<number>*/, ssz/*:number*/, chkd/*:?Array<boolean>*/)/*:SectorEntry*/ {
var sl = sectors.length;
var buf/*:Array<number>*/ = [], buf_chain/*:Array<any>*/ = [];
if(!chkd) chkd = [];
var modulus = ssz - 1, j = 0, jj = 0;
@ -355,22 +357,259 @@ function read_date(blob/*:RawBytes|CFBlob*/, offset/*:number*/)/*:Date*/ {
}
var fs/*:: = require('fs'); */;
function readFileSync(filename/*:string*/, options/*:CFBReadOpts*/) {
function read_file(filename/*:string*/, options/*:CFBReadOpts*/) {
if(fs == null) fs = require('fs');
return parse(fs.readFileSync(filename), options);
}
function readSync(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
function read(blob/*:RawBytes|string*/, options/*:CFBReadOpts*/) {
switch(options && options.type || "base64") {
case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return readFileSync(blob, options);
case "file": /*:: if(typeof blob !== 'string') throw "Must pass a filename when type='file'"; */return read_file(blob, options);
case "base64": /*:: if(typeof blob !== 'string') throw "Must pass a base64-encoded binary string when type='file'"; */return parse(s2a(Base64.decode(blob)), options);
case "binary": /*:: if(typeof blob !== 'string') throw "Must pass a binary string when type='file'"; */return parse(s2a(blob), options);
}
return parse(/*::typeof blob == 'string' ? new Buffer(blob, 'utf-8') : */blob, options);
}
function init_cfb(cfb/*:CFBContainer*/, opts/*:?any*/)/*:void*/ {
var o = opts || {}, root = o.root || "Root Entry";
if(!cfb.FullPaths) cfb.FullPaths = [];
if(!cfb.FileIndex) cfb.FileIndex = [];
if(cfb.FullPaths.length !== cfb.FileIndex.length) throw new Error("inconsistent CFB structure");
if(cfb.FullPaths.length === 0) {
cfb.FullPaths[0] = root + "/";
cfb.FileIndex[0] = ({ name: root, type: 5 }/*:any*/);
}
if(o.CLSID) cfb.FileIndex[0].clsid = o.CLSID;
seed_cfb(cfb);
}
function seed_cfb(cfb/*:CFBContainer*/)/*:void*/ {
var nm = "\u0001Sh33tJ5";
if(CFB.find(cfb, "/" + nm)) return;
var p = new_buf(4); p[0] = 55; p[1] = p[3] = 50; p[2] = 54;
cfb.FileIndex.push(({ name: nm, type: 2, content:p, size:4, L:69, R:69, C:69 }/*:any*/));
cfb.FullPaths.push(cfb.FullPaths[0] + nm);
rebuild_cfb(cfb);
}
function rebuild_cfb(cfb/*:CFBContainer*/, f/*:?boolean*/)/*:void*/ {
init_cfb(cfb);
var gc = false, s = false;
for(var i = cfb.FullPaths.length - 1; i >= 0; --i) {
var _file = cfb.FileIndex[i];
switch(_file.type) {
case 0:
if(s) gc = true;
else { cfb.FileIndex.pop(); cfb.FullPaths.pop(); }
break;
case 1: case 2: case 5:
s = true;
if(isNaN(_file.R * _file.L * _file.C)) gc = true;
if(_file.R > -1 && _file.L > -1 && _file.R == _file.L) gc = true;
break;
default: gc = true; break;
}
}
if(!gc && !f) return;
var now = new Date(1987, 1, 19), j = 0;
var data/*:Array<[string, CFBEntry]>*/ = [];
for(i = 0; i < cfb.FullPaths.length; ++i) {
if(cfb.FileIndex[i].type === 0) continue;
data.push([cfb.FullPaths[i], cfb.FileIndex[i]]);
}
for(i = 0; i < data.length; ++i) {
var dad = dirname(data[i][0]);
s = false;
for(j = 0; j < data.length; ++j) if(data[j][0] === dad) s = true;
if(!s) data.push([dad, ({
name: filename(dad).replace("/",""),
type: 1,
clsid: HEADER_CLSID,
ct: now, mt: now,
content: null
}/*:any*/)]);
}
data.sort(function(x,y) { return namecmp(x[0], y[0]); });
cfb.FullPaths = []; cfb.FileIndex = [];
for(i = 0; i < data.length; ++i) { cfb.FullPaths[i] = data[i][0]; cfb.FileIndex[i] = data[i][1]; }
for(i = 0; i < data.length; ++i) {
var elt = cfb.FileIndex[i];
var nm = cfb.FullPaths[i];
elt.name = filename(nm).replace("/","");
elt.L = elt.R = elt.C = -(elt.color = 1);
elt.size = elt.content ? elt.content.length : 0;
elt.start = 0;
elt.clsid = (elt.clsid || HEADER_CLSID);
if(i === 0) {
elt.C = data.length > 1 ? 1 : -1;
elt.size = 0;
elt.type = 5;
} else if(nm.slice(-1) == "/") {
for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==nm) break;
elt.C = j >= data.length ? -1 : j;
for(j=i+1;j < data.length; ++j) if(dirname(cfb.FullPaths[j])==dirname(nm)) break;
elt.R = j >= data.length ? -1 : j;
elt.type = 1;
} else {
if(dirname(cfb.FullPaths[i+1]||"") == dirname(nm)) elt.R = i + 1;
elt.type = 2;
}
}
}
function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ {
rebuild_cfb(cfb);
var L = (function(cfb/*:CFBContainer*/)/*:Array<number>*/{
var mini_size = 0, fat_size = 0;
for(var i = 0; i < cfb.FileIndex.length; ++i) {
var file = cfb.FileIndex[i];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
var flen = file.content.length;
if(flen === 0){}
else if(flen < 0x1000) mini_size += (flen + 0x3F) >> 6;
else fat_size += (flen + 0x01FF) >> 9;
}
var dir_cnt = (cfb.FullPaths.length +3) >> 2;
var mini_cnt = (mini_size + 7) >> 3;
var mfat_cnt = (mini_size + 0x7F) >> 7;
var fat_base = mini_cnt + fat_size + dir_cnt + mfat_cnt;
var fat_cnt = (fat_base + 0x7F) >> 7;
var difat_cnt = fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
while(((fat_base + fat_cnt + difat_cnt + 0x7F) >> 7) > fat_cnt) difat_cnt = ++fat_cnt <= 109 ? 0 : Math.ceil((fat_cnt-109)/0x7F);
var L = [1, difat_cnt, fat_cnt, mfat_cnt, dir_cnt, fat_size, mini_size, 0];
cfb.FileIndex[0].size = mini_size << 6;
L[7] = (cfb.FileIndex[0].start=L[0]+L[1]+L[2]+L[3]+L[4]+L[5])+((L[6]+7) >> 3);
return L;
})(cfb);
var o = new_buf(L[7] << 9);
var i = 0, T = 0;
{
for(i = 0; i < 8; ++i) o.write_shift(1, HEADER_SIG[i]);
for(i = 0; i < 8; ++i) o.write_shift(2, 0);
o.write_shift(2, 0x003E);
o.write_shift(2, 0x0003);
o.write_shift(2, 0xFFFE);
o.write_shift(2, 0x0009);
o.write_shift(2, 0x0006);
for(i = 0; i < 3; ++i) o.write_shift(2, 0);
o.write_shift(4, 0);
o.write_shift(4, L[2]);
o.write_shift(4, L[0] + L[1] + L[2] + L[3] - 1);
o.write_shift(4, 0);
o.write_shift(4, 1<<12);
o.write_shift(4, L[3] ? L[0] + L[1] + L[2] - 1: ENDOFCHAIN);
o.write_shift(4, L[3]);
o.write_shift(-4, L[1] ? L[0] - 1: ENDOFCHAIN);
o.write_shift(4, L[1]);
for(i = 0; i < 109; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
}
if(L[1]) {
for(T = 0; T < L[1]; ++T) {
for(; i < 236 + T * 127; ++i) o.write_shift(-4, i < L[2] ? L[1] + i : -1);
o.write_shift(-4, T === L[1] - 1 ? ENDOFCHAIN : T + 1);
}
}
var chainit = function(w/*:number*/)/*:void*/ {
for(T += w; i<T-1; ++i) o.write_shift(-4, i+1);
if(w) { ++i; o.write_shift(-4, ENDOFCHAIN); }
};
T = i = 0;
for(T+=L[1]; i<T; ++i) o.write_shift(-4, consts.DIFSECT);
for(T+=L[2]; i<T; ++i) o.write_shift(-4, consts.FATSECT);
chainit(L[3]);
chainit(L[4]);
var j/*:number*/ = 0, flen/*:number*/ = 0;
var file/*:CFBEntry*/ = cfb.FileIndex[0];
for(; j < cfb.FileIndex.length; ++j) {
file = cfb.FileIndex[j];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
flen = file.content.length;
if(flen < 0x1000) continue;
file.start = T;
chainit((flen + 0x01FF) >> 9);
}
chainit((L[6] + 7) >> 3);
while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
T = i = 0;
for(j = 0; j < cfb.FileIndex.length; ++j) {
file = cfb.FileIndex[j];
if(!file.content) continue;
/*:: if(file.content == null) throw new Error("unreachable"); */
flen = file.content.length;
if(!flen || flen >= 0x1000) continue;
file.start = T;
chainit((flen + 0x3F) >> 6);
}
while(o.l & 0x1FF) o.write_shift(-4, consts.ENDOFCHAIN);
for(i = 0; i < L[4]<<2; ++i) {
var nm = cfb.FullPaths[i];
if(!nm || nm.length === 0) {
for(j = 0; j < 17; ++j) o.write_shift(4, 0);
for(j = 0; j < 3; ++j) o.write_shift(4, -1);
for(j = 0; j < 12; ++j) o.write_shift(4, 0);
continue;
}
file = cfb.FileIndex[i];
if(i === 0) file.start = file.size ? file.start - 1 : ENDOFCHAIN;
flen = 2*(file.name.length+1);
o.write_shift(64, file.name, "utf16le");
o.write_shift(2, flen);
o.write_shift(1, file.type);
o.write_shift(1, file.color);
o.write_shift(-4, file.L);
o.write_shift(-4, file.R);
o.write_shift(-4, file.C);
if(!file.clsid) for(j = 0; j < 4; ++j) o.write_shift(4, 0);
else o.write_shift(16, file.clsid, "hex");
o.write_shift(4, file.state || 0);
o.write_shift(4, 0); o.write_shift(4, 0);
o.write_shift(4, 0); o.write_shift(4, 0);
o.write_shift(4, file.start);
o.write_shift(4, file.size); o.write_shift(4, 0);
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
/*:: if(!file.content) throw new Error("unreachable"); */
if(file.size >= 0x1000) {
o.l = (file.start+1) << 9;
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
for(; j & 0x1FF; ++j) o.write_shift(1, 0);
}
}
for(i = 1; i < cfb.FileIndex.length; ++i) {
file = cfb.FileIndex[i];
/*:: if(!file.content) throw new Error("unreachable"); */
if(file.size > 0 && file.size < 0x1000) {
for(j = 0; j < file.size; ++j) o.write_shift(1, file.content[j]);
for(; j & 0x3F; ++j) o.write_shift(1, 0);
}
}
while(o.l < o.length) o.write_shift(1, 0);
return o;
}
/* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */
function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ {
return cfb.find(path);
//return cfb.find(path);
var UCFullPaths/*:Array<string>*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); });
var UCPaths/*:Array<string>*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; });
var k/*:boolean*/ = false;
if(path.charCodeAt(0) === 47 /* "/" */) { k = true; path = UCFullPaths[0].slice(0, -1) + path; }
else k = path.indexOf("/") !== -1;
var UCPath/*:string*/ = path.toUpperCase();
var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath);
if(w !== -1) return cfb.FileIndex[w];
UCPath = UCPath.replace(chr0,'').replace(chr1,'!');
for(w = 0; w < UCFullPaths.length; ++w) {
if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w];
if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w];
}
return null;
}
/** CFB Constants */
var MSSZ = 64; /* Mini Sector Size = 1<<6 */
@ -379,9 +618,10 @@ var MSSZ = 64; /* Mini Sector Size = 1<<6 */
var ENDOFCHAIN = -2;
/* 2.2 Compound File Header */
var HEADER_SIGNATURE = 'd0cf11e0a1b11ae1';
var HEADER_SIG = [0xD0, 0xCF, 0x11, 0xE0, 0xA1, 0xB1, 0x1A, 0xE1];
var HEADER_CLSID = '00000000000000000000000000000000';
var consts = {
/* 2.1 Compound File Sector Numbers and Types */
/* 2.1 Compund File Sector Numbers and Types */
MAXREGSECT: -6,
DIFSECT: -4,
FATSECT: -3,
@ -397,10 +637,92 @@ var consts = {
EntryTypes: ['unknown','storage','stream','lockbytes','property','root']
};
function write_file(cfb/*:CFBContainer*/, filename/*:string*/, options/*:CFBWriteOpts*/)/*:void*/ {
var o = _write(cfb, options);
/*:: if(typeof Buffer == 'undefined' || !Buffer.isBuffer(o) || !(o instanceof Buffer)) throw new Error("unreachable"); */
fs.writeFileSync(filename, o);
}
function a2s(o/*:RawBytes*/)/*:string*/ {
var out = new Array(o.length);
for(var i = 0; i < o.length; ++i) out[i] = String.fromCharCode(o[i]);
return out.join("");
}
function write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes|string*/ {
var o = _write(cfb, options);
switch(options && options.type) {
case "file": fs.writeFileSync(options.filename, (o/*:any*/)); return o;
case "binary": return a2s(o);
case "base64": return Base64.encode(a2s(o));
}
return o;
}
function cfb_new(opts/*:?any*/)/*:CFBContainer*/ {
var o/*:CFBContainer*/ = ({}/*:any*/);
init_cfb(o, opts);
return o;
}
function cfb_add(cfb/*:CFBContainer*/, name/*:string*/, content/*:?RawBytes*/, opts/*:?any*/)/*:CFBEntry*/ {
init_cfb(cfb);
var file = CFB.find(cfb, name);
if(!file) {
var fpath = cfb.FullPaths[0];
if(name.slice(0, fpath.length) == fpath) fpath = name;
else {
if(fpath.slice(-1) != "/") fpath += "/";
fpath = (fpath + name).replace("//","/");
}
file = ({name: filename(name)}/*:any*/);
cfb.FileIndex.push(file);
cfb.FullPaths.push(fpath);
CFB.utils.cfb_gc(cfb);
}
/*:: if(!file) throw new Error("unreachable"); */
file.content = (content/*:any*/);
file.size = content ? content.length : 0;
if(opts) {
if(opts.CLSID) file.clsid = opts.CLSID;
}
return file;
}
function cfb_del(cfb/*:CFBContainer*/, name/*:string*/)/*:boolean*/ {
init_cfb(cfb);
var file = CFB.find(cfb, name);
if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
cfb.FileIndex.splice(j, 1);
cfb.FullPaths.splice(j, 1);
return true;
}
return false;
}
function cfb_mov(cfb/*:CFBContainer*/, old_name/*:string*/, new_name/*:string*/)/*:boolean*/ {
init_cfb(cfb);
var file = CFB.find(cfb, old_name);
if(file) for(var j = 0; j < cfb.FileIndex.length; ++j) if(cfb.FileIndex[j] == file) {
cfb.FileIndex[j].name = filename(new_name);
cfb.FullPaths[j] = new_name;
return true;
}
return false;
}
function cfb_gc(cfb/*:CFBContainer*/)/*:void*/ { rebuild_cfb(cfb, true); }
exports.find = find;
exports.read = readSync;
exports.read = read;
exports.parse = parse;
exports.write = write;
exports.writeFile = write_file;
exports.utils = {
cfb_new: cfb_new,
cfb_add: cfb_add,
cfb_del: cfb_del,
cfb_mov: cfb_mov,
cfb_gc: cfb_gc,
ReadShift: ReadShift,
CheckField: CheckField,
prep_blob: prep_blob,

@ -1,5 +1,7 @@
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
var attregexg=/([^"\s?>\/]+)=((?:")([^"]*)(?:")|(?:')([^']*)(?:')|([^'">\s]+))/g;
var tagregex=/<[\/\?]?[a-zA-Z0-9:]+(?:\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*/ {
var z = ({}/*:any*/);
@ -174,7 +176,6 @@ function write_vt(s) {
throw new Error("Unable to serialize " + s);
}
var XML_HEADER = '<?xml version="1.0" encoding="UTF-8" standalone="yes"?>\r\n';
var XMLNS = ({
'dc': 'http://purl.org/dc/elements/1.1/',
'dcterms': 'http://purl.org/dc/terms/',

@ -13,6 +13,7 @@ function write_double_le(b, v/*:number*/, idx/*:number*/) {
var bs = ((v < 0 || 1/v == -Infinity) ? 1 : 0) << 7, e = 0, m = 0;
var av = bs ? -v : v;
if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
else if(av == 0) e = m = 0;
else {
e = Math.floor(Math.log(av) / Math.LN2);
m = av * Math.pow(2, 52 - e);
@ -164,6 +165,20 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/) {
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
for(i = 0; i != val.length; ++i) this[this.l + i] = val.charCodeAt(i) & 0xFF;
size = val.length;
} else if(f === 'hex') {
for(; i < t; ++i) {
/*:: if(typeof val !== "string") throw new Error("unreachable"); */
this[this.l++] = parseInt(val.slice(2*i, 2*i+2), 16)||0;
} return this;
} else if(f === 'utf16le') {
var end/*:number*/ = this.l + t;
for(i = 0; i < Math.min(val.length, t); ++i) {
var cc = val.charCodeAt(i);
this[this.l++] = cc & 0xff;
this[this.l++] = cc >> 8;
}
while(this.l < end) this[this.l++] = 0;
return this;
} else /*:: if(typeof val === 'number') */ switch(t) {
case 1: size = 1; this[this.l] = val&0xFF; break;
case 2: size = 2; this[this.l] = val&0xFF; val >>>= 8; this[this.l+1] = val&0xFF; break;

@ -12,7 +12,7 @@ function recordhopper(data, cb/*:RecordHopperCB*/, opts/*:?any*/) {
length = tmpbyte & 0x7F;
for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
tgt = data.l + length;
var d = R.f(data, length, opts);
var d = (R.f||parsenoop)(data, length, opts);
data.l = tgt;
if(cb(d, R.n, RT)) return;
}
@ -53,7 +53,7 @@ function buf_array()/*:BufArray*/ {
}
function write_record(ba/*:BufArray*/, type/*:string*/, payload, length/*:?number*/) {
var t/*:number*/ = Number(evert_RE[type]), l;
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;

@ -267,6 +267,7 @@ function parse_PropertySetStream(file, PIDSI) {
function parsenoop2(blob, length) { blob.read_shift(length); return null; }
function writezeroes(n, o) { if(!o) o=new_buf(n); for(var j=0; j<n; ++j) o.write_shift(1, 0); return o; }
function parslurp(blob, length, cb) {
var arr = [], target = blob.l + length;
@ -275,21 +276,26 @@ function parslurp(blob, length, cb) {
return arr;
}
function parsebool(blob, length) { return blob.read_shift(length) === 0x1; }
function parsebool(blob, length/*:number*/) { return blob.read_shift(length) === 0x1; }
function writebool(v/*:any*/, o) { if(!o) o=new_buf(2); o.write_shift(2, +!!v); return o; }
function parseuint16(blob/*::, length:?number, opts:?any*/) { return blob.read_shift(2, 'u'); }
function writeuint16(v/*:number*/, o) { if(!o) o=new_buf(2); o.write_shift(2, v); return o; }
function parseuint16a(blob, length/*:: :?number, opts:?any*/) { return parslurp(blob,length,parseuint16);}
/* --- 2.5 Structures --- */
/* [MS-XLS] 2.5.14 Boolean */
var parse_Boolean = parsebool;
/* [MS-XLS] 2.5.10 Bes (boolean or error) */
function parse_Bes(blob/*::, length*/) {
var v = blob.read_shift(1), t = blob.read_shift(1);
return t === 0x01 ? v : v === 0x01;
}
function write_Bes(v, t/*:string*/, o) {
if(!o) o = new_buf(2);
o.write_shift(1, +v);
o.write_shift(1, t == 'e' ? 1 : 0);
return o;
}
/* [MS-XLS] 2.5.240 ShortXLUnicodeString */
function parse_ShortXLUnicodeString(blob, length, opts) {
@ -366,7 +372,7 @@ function parse_ControlInfo(blob, length, opts) {
}
/* [MS-OSHARED] 2.3.7.6 URLMoniker TODO: flags */
var parse_URLMoniker = function(blob/*::, length, opts*/) {
function parse_URLMoniker(blob/*::, length, opts*/) {
var len = blob.read_shift(4), start = blob.l;
var extra = false;
if(len > 24) {
@ -378,10 +384,10 @@ var parse_URLMoniker = function(blob/*::, length, opts*/) {
var url = blob.read_shift((extra?len-24:len)>>1, 'utf16le').replace(chr0,"");
if(extra) blob.l += 24;
return url;
};
}
/* [MS-OSHARED] 2.3.7.8 FileMoniker TODO: all fields */
var parse_FileMoniker = function(blob, length) {
function parse_FileMoniker(blob, length) {
var cAnti = blob.read_shift(2);
var ansiLength = blob.read_shift(4);
var ansiPath = blob.read_shift(ansiLength, 'cstr');
@ -393,27 +399,27 @@ var parse_FileMoniker = function(blob, length) {
var usKeyValue = blob.read_shift(2);
var unicodePath = blob.read_shift(cbUnicodePathBytes>>1, 'utf16le').replace(chr0,"");
return unicodePath;
};
}
/* [MS-OSHARED] 2.3.7.2 HyperlinkMoniker TODO: all the monikers */
var parse_HyperlinkMoniker = function(blob, length) {
function parse_HyperlinkMoniker(blob, length) {
var clsid = blob.read_shift(16); length -= 16;
switch(clsid) {
case "e0c9ea79f9bace118c8200aa004ba90b": return parse_URLMoniker(blob, length);
case "0303000000000000c000000000000046": return parse_FileMoniker(blob, length);
default: throw new Error("Unsupported Moniker " + clsid);
}
};
}
/* [MS-OSHARED] 2.3.7.9 HyperlinkString */
var parse_HyperlinkString = function(blob, length) {
function parse_HyperlinkString(blob, length) {
var len = blob.read_shift(4);
var o = blob.read_shift(len, 'utf16le').replace(chr0, "");
return o;
};
}
/* [MS-OSHARED] 2.3.7.1 Hyperlink Object TODO: unify params with XLSX */
var parse_Hyperlink = function(blob, length) {
function parse_Hyperlink(blob, length) {
var end = blob.l + length;
var sVer = blob.read_shift(4);
if(sVer !== 2) throw new Error("Unrecognized streamVersion: " + sVer);
@ -431,7 +437,7 @@ var parse_Hyperlink = function(blob, length) {
var target = (targetFrameName||moniker||oleMoniker);
if(location) target+="#"+location;
return {Target: target};
};
}
/* 2.5.178 LongRGBA */
function parse_LongRGBA(blob, length) { var r = blob.read_shift(1), g = blob.read_shift(1), b = blob.read_shift(1), a = blob.read_shift(1); return [r,g,b,a]; }

@ -7,6 +7,13 @@ function parse_XLSCell(blob, length)/*:Cell*/ {
var ixfe = blob.read_shift(2);
return ({r:rw, c:col, ixfe:ixfe}/*:any*/);
}
function write_XLSCell(R/*:number*/, C/*:number*/, ixfe/*:number*/, o) {
if(!o) o = new_buf(6);
o.write_shift(2, R);
o.write_shift(2, C);
o.write_shift(2, ixfe||0);
return o;
}
/* 2.5.134 */
function parse_frtHeader(blob) {
@ -20,10 +27,6 @@ function parse_frtHeader(blob) {
function parse_OptXLUnicodeString(blob, length, opts) { return length === 0 ? "" : parse_XLUnicodeString2(blob, length, opts); }
/* 2.5.158 */
//var HIDEOBJENUM = ['SHOWALL', 'SHOWPLACEHOLDER', 'HIDEALL'];
var parse_HideObjEnum = parseuint16;
/* 2.5.344 */
function parse_XTI(blob, length, opts) {
var w = opts.biff > 8 ? 4 : 2;
@ -136,9 +139,6 @@ function parse_FtArray(blob, length, ot) {
return fts;
}
/* 2.5.129 */
var parse_FontIndex = parseuint16;
/* --- 2.4 Records --- */
/* 2.4.21 */
@ -157,6 +157,29 @@ function parse_BOF(blob, length) {
blob.read_shift(length);
return o;
}
function write_BOF(wb/*:Workbook*/, t/*:number*/, o) {
var h = 0x0600, w = 16;
switch(o.bookType) {
case 'biff8': break;
case 'biff5': h = 0x0500; w = 8; break;
case 'biff4': h = 0x0004; w = 6; break;
case 'biff3': h = 0x0003; w = 6; break;
case 'biff2': h = 0x0002; w = 4; break;
default: throw new Error("unsupported BIFF version");
}
var out = new_buf(w);
out.write_shift(2, h);
out.write_shift(2, t);
if(w > 4) out.write_shift(2, 0x7262);
if(w > 6) out.write_shift(2, 0x07CD);
if(w > 8) {
out.write_shift(2, 0xC009);
out.write_shift(2, 0x0001);
out.write_shift(2, 0x0706);
out.write_shift(2, 0x0000);
}
return out;
}
/* 2.4.146 */
@ -177,6 +200,15 @@ function parse_WriteAccess(blob, length, opts) {
blob.read_shift(length + l - blob.l);
return UserName;
}
function write_WriteAccess(s/*:string*/, opts) {
var o = new_buf(112);
o.write_shift(opts.biff == 8 ? 2 : 1, 7);
o.write_shift(1, 0);
o.write_shift(4, 0x33336853);
o.write_shift(4, 0x00534A74);
while(o.l < o.length) o.write_shift(1, 0);
return o;
}
/* 2.4.28 */
function parse_BoundSheet8(blob, length, opts) {
@ -193,6 +225,16 @@ function parse_BoundSheet8(blob, length, opts) {
if(name.length === 0) name = "Sheet1";
return { pos:pos, hs:hidden, dt:dt, name:name };
}
function write_BoundSheet8(data, opts) {
var o = new_buf(8 + 2 * data.name.length);
o.write_shift(4, data.pos);
o.write_shift(1, data.hs || 0);
o.write_shift(1, data.dt);
o.write_shift(1, data.name.length);
o.write_shift(1, 1);
o.write_shift(2 * data.name.length, data.name, 'utf16le');
return o;
}
/* 2.4.265 TODO */
function parse_SST(blob, length)/*:SST*/ {
@ -243,7 +285,6 @@ function parse_ForceFullCalculation(blob, length) {
}
var parse_CompressPictures = parsenoop2; /* 2.4.55 Not interesting */
@ -275,6 +316,19 @@ function parse_Window1(blob, length) {
return { Pos: [xWn, yWn], Dim: [dxWn, dyWn], Flags: flags, CurTab: iTabCur,
FirstTab: iTabFirst, Selected: ctabSel, TabRatio: wTabRatio };
}
function write_Window1(opts) {
var o = new_buf(18);
o.write_shift(2, 0);
o.write_shift(2, 0);
o.write_shift(2, 0x7260);
o.write_shift(2, 0x44c0);
o.write_shift(2, 0x38);
o.write_shift(2, 0);
o.write_shift(2, 0);
o.write_shift(2, 1);
o.write_shift(2, 0x01f4);
return o;
}
/* 2.4.122 TODO */
function parse_Font(blob, length, opts) {
@ -307,6 +361,15 @@ function parse_Label(blob, length, opts) {
cell.val = str;
return cell;
}
function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, opts) {
var o = new_buf(6 + 3 + 2 * v.length);
write_XLSCell(R, C, 0, o);
o.write_shift(2, v.length);
o.write_shift(1, 1);
o.write_shift(2 * v.length, v, 'utf16le');
return o;
}
/* 2.4.126 Number Formats */
function parse_Format(blob, length, opts) {
@ -325,6 +388,15 @@ function parse_Dimensions(blob, length, opts) {
blob.l = end;
return {s: {r:r, c:c}, e: {r:R, c:C}};
}
function write_Dimensions(range, opts) {
var o = new_buf(14);
o.write_shift(4, range.s.r);
o.write_shift(4, range.e.r + 1);
o.write_shift(2, range.s.c);
o.write_shift(2, range.e.c + 1);
o.write_shift(2, 0);
return o;
}
/* 2.4.220 */
function parse_RK(blob, length) {
@ -419,6 +491,13 @@ function parse_Guts(blob, length) {
if(out[0] > 7 || out[1] > 7) throw new Error("Bad Gutters: " + out.join("|"));
return out;
}
function write_Guts(guts/*:Array<number>*/) {
var o = new_buf(8);
o.write_shift(4, 0);
o.write_shift(2, guts[0] ? guts[0] + 1 : 0);
o.write_shift(2, guts[1] ? guts[1] + 1 : 0);
return o;
}
/* 2.4.24 */
function parse_BoolErr(blob, length, opts) {
@ -429,6 +508,12 @@ function parse_BoolErr(blob, length, opts) {
cell.t = (val === true || val === false) ? 'b' : 'e';
return cell;
}
function write_BoolErr(R/*:number*/, C/*:number*/, v, opts, t/*:string*/) {
var o = new_buf(8);
write_XLSCell(R, C, 0, o);
write_Bes(v, t, o);
return o;
}
/* 2.4.180 Number */
function parse_Number(blob, length) {
@ -437,6 +522,12 @@ function parse_Number(blob, length) {
cell.val = xnum;
return cell;
}
function write_Number(R/*:number*/, C/*:number*/, v, opts) {
var o = new_buf(14);
write_XLSCell(R, C, 0, o);
write_Xnum(v, o);
return o;
}
var parse_XLHeaderFooter = parse_OptXLUnicodeString; // TODO: parse 2.4.136
@ -530,7 +621,6 @@ function parse_BIFF5ExternSheet(blob, length, opts) {
var o = parse_ShortXLUnicodeString(blob, length, opts);
return o.charCodeAt(0) == 0x03 ? o.slice(1) : o;
}
var parse_ExternCount = parseuint16;
/* 2.4.176 TODO: check older biff */
function parse_NameCmt(blob, length, opts) {
@ -652,7 +742,7 @@ try {
else controlInfo = parse_ControlInfo(blob, 6, opts);
var cchText = blob.read_shift(2);
var cbRuns = blob.read_shift(2);
var ifntEmpty = parse_FontIndex(blob, 2);
var ifntEmpty = parseuint16(blob, 2);
var len = blob.read_shift(2);
blob.l += len;
//var fmla = parse_ObjFmla(blob, s + length - blob.l);
@ -681,22 +771,22 @@ try {
}
/* 2.4.140 */
var parse_HLink = function(blob, length) {
function parse_HLink(blob, length) {
var ref = parse_Ref8U(blob, 8);
blob.l += 16; /* CLSID */
var hlink = parse_Hyperlink(blob, length-24);
return [ref, hlink];
};
}
/* 2.4.141 */
var parse_HLinkTooltip = function(blob, length) {
function parse_HLinkTooltip(blob, length) {
var end = blob.l + length;
blob.read_shift(2);
var ref = parse_Ref8U(blob, 8);
var wzTooltip = blob.read_shift((length-10)/2, 'dbcs-cont');
wzTooltip = wzTooltip.replace(chr0,"");
return [ref, wzTooltip];
};
}
/* 2.4.63 */
function parse_Country(blob, length) {
@ -705,6 +795,12 @@ function parse_Country(blob, length) {
d = blob.read_shift(2); o[1] = CountryEnum[d] || d;
return o;
}
function write_Country(o) {
if(!o) o = new_buf(4);
o.write_shift(2, 0x01);
o.write_shift(2, 0x01);
return o;
}
/* 2.4.50 ClrtClient */
function parse_ClrtClient(blob, length) {
@ -764,315 +860,16 @@ function parse_ShtProps(blob, length, opts) {
return def;
}
var parse_Style = parsenoop;
var parse_StyleExt = parsenoop;
/* 2.4.241 */
function write_RRTabId(n/*:number*/) {
var out = new_buf(2 * n);
for(var i = 0; i < n; ++i) out.write_shift(2, i+1);
return out;
}
var parse_Window2 = parsenoop;
var parse_Backup = parsebool; /* 2.4.14 */
var parse_Blank = parse_XLSCell; /* 2.4.20 Just the cell */
var parse_BottomMargin = parse_Xnum; /* 2.4.27 */
var parse_BuiltInFnGroupCount = parseuint16; /* 2.4.30 0x0E or 0x10 but excel 2011 generates 0x11? */
var parse_CalcCount = parseuint16; /* 2.4.31 #Iterations */
var parse_CalcDelta = parse_Xnum; /* 2.4.32 */
var parse_CalcIter = parsebool; /* 2.4.33 1=iterative calc */
var parse_CalcMode = parseuint16; /* 2.4.34 0=manual, 1=auto (def), 2=table */
var parse_CalcPrecision = parsebool; /* 2.4.35 */
var parse_CalcRefMode = parsenoop2; /* 2.4.36 */
var parse_CalcSaveRecalc = parsebool; /* 2.4.37 */
var parse_CodePage = parseuint16; /* 2.4.52 */
var parse_Compat12 = parsebool; /* 2.4.54 true = no compatibility check */
var parse_Date1904 = parsebool; /* 2.4.77 - 1=1904,0=1900 */
var parse_DefColWidth = parseuint16; /* 2.4.89 */
var parse_DSF = parsenoop2; /* 2.4.94 -- MUST be ignored */
var parse_EntExU2 = parsenoop2; /* 2.4.102 -- Explicitly says to ignore */
var parse_EOF = parsenoop2; /* 2.4.103 */
var parse_Excel9File = parsenoop2; /* 2.4.104 -- Optional and unused */
var parse_FeatHdr = parsenoop2; /* 2.4.112 */
var parse_FontX = parseuint16; /* 2.4.123 */
var parse_Footer = parse_XLHeaderFooter; /* 2.4.124 */
var parse_GridSet = parseuint16; /* 2.4.132, =1 */
var parse_HCenter = parsebool; /* 2.4.135 sheet centered horizontal on print */
var parse_Header = parse_XLHeaderFooter; /* 2.4.136 */
var parse_HideObj = parse_HideObjEnum; /* 2.4.139 */
var parse_InterfaceEnd = parsenoop2; /* 2.4.145 -- noop */
var parse_LeftMargin = parse_Xnum; /* 2.4.151 */
var parse_Mms = parsenoop2; /* 2.4.169 -- Explicitly says to ignore */
var parse_ObjProtect = parsebool; /* 2.4.183 -- must be 1 if present */
var parse_Password = parseuint16; /* 2.4.191 */
var parse_PrintGrid = parsebool; /* 2.4.202 */
var parse_PrintRowCol = parsebool; /* 2.4.203 */
var parse_PrintSize = parseuint16; /* 2.4.204 0:3 */
var parse_Prot4Rev = parsebool; /* 2.4.205 */
var parse_Prot4RevPass = parseuint16; /* 2.4.206 */
var parse_Protect = parsebool; /* 2.4.207 */
var parse_RefreshAll = parsebool; /* 2.4.217 -- must be 0 if not template */
var parse_RightMargin = parse_Xnum; /* 2.4.219 */
var parse_RRTabId = parseuint16a; /* 2.4.241 */
var parse_ScenarioProtect = parsebool; /* 2.4.245 */
var parse_Scl = parseuint16a; /* 2.4.247 num, den */
var parse_String = parse_XLUnicodeString; /* 2.4.268 */
var parse_SxBool = parsebool; /* 2.4.274 */
var parse_TopMargin = parse_Xnum; /* 2.4.328 */
var parse_UsesELFs = parsebool; /* 2.4.337 -- should be 0 */
var parse_VCenter = parsebool; /* 2.4.342 */
var parse_WinProtect = parsebool; /* 2.4.347 */
var parse_WriteProtect = parsenoop; /* 2.4.350 empty record */
/* ---- */
var parse_VerticalPageBreaks = parsenoop;
var parse_HorizontalPageBreaks = parsenoop;
var parse_Selection = parsenoop;
var parse_Continue = parsenoop;
var parse_Pane = parsenoop;
var parse_Pls = parsenoop;
var parse_DCon = parsenoop;
var parse_DConRef = parsenoop;
var parse_DConName = parsenoop;
var parse_XCT = parsenoop;
var parse_CRN = parsenoop;
var parse_FileSharing = parsenoop;
var parse_Uncalced = parsenoop;
var parse_Template = parsenoop;
var parse_Intl = parsenoop;
var parse_WsBool = parsenoop;
var parse_Sort = parsenoop;
var parse_Sync = parsenoop;
var parse_LPr = parsenoop;
var parse_DxGCol = parsenoop;
var parse_FnGroupName = parsenoop;
var parse_FilterMode = parsenoop;
var parse_AutoFilterInfo = parsenoop;
var parse_AutoFilter = parsenoop;
var parse_ScenMan = parsenoop;
var parse_SCENARIO = parsenoop;
var parse_SxView = parsenoop;
var parse_Sxvd = parsenoop;
var parse_SXVI = parsenoop;
var parse_SxIvd = parsenoop;
var parse_SXLI = parsenoop;
var parse_SXPI = parsenoop;
var parse_DocRoute = parsenoop;
var parse_RecipName = parsenoop;
var parse_SXDI = parsenoop;
var parse_SXDB = parsenoop;
var parse_SXFDB = parsenoop;
var parse_SXDBB = parsenoop;
var parse_SXNum = parsenoop;
var parse_SxErr = parsenoop;
var parse_SXInt = parsenoop;
var parse_SXString = parsenoop;
var parse_SXDtr = parsenoop;
var parse_SxNil = parsenoop;
var parse_SXTbl = parsenoop;
var parse_SXTBRGIITM = parsenoop;
var parse_SxTbpg = parsenoop;
var parse_ObProj = parsenoop;
var parse_SXStreamID = parsenoop;
var parse_DBCell = parsenoop;
var parse_SXRng = parsenoop;
var parse_SxIsxoper = parsenoop;
var parse_BookBool = parsenoop;
var parse_DbOrParamQry = parsenoop;
var parse_OleObjectSize = parsenoop;
var parse_SXVS = parsenoop;
var parse_BkHim = parsenoop;
var parse_MsoDrawingGroup = parsenoop;
var parse_MsoDrawing = parsenoop;
var parse_MsoDrawingSelection = parsenoop;
var parse_PhoneticInfo = parsenoop;
var parse_SxRule = parsenoop;
var parse_SXEx = parsenoop;
var parse_SxFilt = parsenoop;
var parse_SxDXF = parsenoop;
var parse_SxItm = parsenoop;
var parse_SxName = parsenoop;
var parse_SxSelect = parsenoop;
var parse_SXPair = parsenoop;
var parse_SxFmla = parsenoop;
var parse_SxFormat = parsenoop;
var parse_SXVDEx = parsenoop;
var parse_SXFormula = parsenoop;
var parse_SXDBEx = parsenoop;
var parse_RRDInsDel = parsenoop;
var parse_RRDHead = parsenoop;
var parse_RRDChgCell = parsenoop;
var parse_RRDRenSheet = parsenoop;
var parse_RRSort = parsenoop;
var parse_RRDMove = parsenoop;
var parse_RRFormat = parsenoop;
var parse_RRAutoFmt = parsenoop;
var parse_RRInsertSh = parsenoop;
var parse_RRDMoveBegin = parsenoop;
var parse_RRDMoveEnd = parsenoop;
var parse_RRDInsDelBegin = parsenoop;
var parse_RRDInsDelEnd = parsenoop;
var parse_RRDConflict = parsenoop;
var parse_RRDDefName = parsenoop;
var parse_RRDRstEtxp = parsenoop;
var parse_LRng = parsenoop;
var parse_CUsr = parsenoop;
var parse_CbUsr = parsenoop;
var parse_UsrInfo = parsenoop;
var parse_UsrExcl = parsenoop;
var parse_FileLock = parsenoop;
var parse_RRDInfo = parsenoop;
var parse_BCUsrs = parsenoop;
var parse_UsrChk = parsenoop;
var parse_UserBView = parsenoop;
var parse_UserSViewBegin = parsenoop; // overloaded
var parse_UserSViewEnd = parsenoop;
var parse_RRDUserView = parsenoop;
var parse_Qsi = parsenoop;
var parse_CondFmt = parsenoop;
var parse_CF = parsenoop;
var parse_DVal = parsenoop;
var parse_DConBin = parsenoop;
var parse_Lel = parsenoop;
var parse_XLSCodeName = parse_XLUnicodeString;
var parse_SXFDBType = parsenoop;
var parse_ObNoMacros = parsenoop;
var parse_Dv = parsenoop;
var parse_Index = parsenoop;
var parse_Table = parsenoop;
var parse_BigName = parsenoop;
var parse_ContinueBigName = parsenoop;
var parse_WebPub = parsenoop;
var parse_QsiSXTag = parsenoop;
var parse_DBQueryExt = parsenoop;
var parse_ExtString = parsenoop;
var parse_TxtQry = parsenoop;
var parse_Qsir = parsenoop;
var parse_Qsif = parsenoop;
var parse_RRDTQSIF = parsenoop;
var parse_OleDbConn = parsenoop;
var parse_WOpt = parsenoop;
var parse_SXViewEx = parsenoop;
var parse_SXTH = parsenoop;
var parse_SXPIEx = parsenoop;
var parse_SXVDTEx = parsenoop;
var parse_SXViewEx9 = parsenoop;
var parse_ContinueFrt = parsenoop;
var parse_RealTimeData = parsenoop;
var parse_ChartFrtInfo = parsenoop;
var parse_FrtWrapper = parsenoop;
var parse_StartBlock = parsenoop;
var parse_EndBlock = parsenoop;
var parse_StartObject = parsenoop;
var parse_EndObject = parsenoop;
var parse_CatLab = parsenoop;
var parse_YMult = parsenoop;
var parse_SXViewLink = parsenoop;
var parse_PivotChartBits = parsenoop;
var parse_FrtFontList = parsenoop;
var parse_SheetExt = parsenoop;
var parse_BookExt = parsenoop;
var parse_SXAddl = parsenoop;
var parse_CrErr = parsenoop;
var parse_HFPicture = parsenoop;
var parse_Feat = parsenoop;
var parse_DataLabExt = parsenoop;
var parse_DataLabExtContents = parsenoop;
var parse_CellWatch = parsenoop;
var parse_FeatHdr11 = parsenoop;
var parse_Feature11 = parsenoop;
var parse_DropDownObjIds = parsenoop;
var parse_ContinueFrt11 = parsenoop;
var parse_DConn = parsenoop;
var parse_List12 = parsenoop;
var parse_Feature12 = parsenoop;
var parse_CondFmt12 = parsenoop;
var parse_CF12 = parsenoop;
var parse_CFEx = parsenoop;
var parse_AutoFilter12 = parsenoop;
var parse_ContinueFrt12 = parsenoop;
var parse_MDTInfo = parsenoop;
var parse_MDXStr = parsenoop;
var parse_MDXTuple = parsenoop;
var parse_MDXSet = parsenoop;
var parse_MDXProp = parsenoop;
var parse_MDXKPI = parsenoop;
var parse_MDB = parsenoop;
var parse_PLV = parsenoop;
var parse_DXF = parsenoop;
var parse_TableStyles = parsenoop;
var parse_TableStyle = parsenoop;
var parse_TableStyleElement = parsenoop;
var parse_NamePublish = parsenoop;
var parse_SortData = parsenoop;
var parse_GUIDTypeLib = parsenoop;
var parse_FnGrp12 = parsenoop;
var parse_NameFnGrp12 = parsenoop;
var parse_HeaderFooter = parsenoop;
var parse_CrtLayout12 = parsenoop;
var parse_CrtMlFrt = parsenoop;
var parse_CrtMlFrtContinue = parsenoop;
var parse_ShapePropsStream = parsenoop;
var parse_TextPropsStream = parsenoop;
var parse_RichTextStream = parsenoop;
var parse_CrtLayout12A = parsenoop;
var parse_Units = parsenoop;
var parse_Chart = parsenoop;
var parse_Series = parsenoop;
var parse_DataFormat = parsenoop;
var parse_LineFormat = parsenoop;
var parse_MarkerFormat = parsenoop;
var parse_AreaFormat = parsenoop;
var parse_PieFormat = parsenoop;
var parse_AttachedLabel = parsenoop;
var parse_SeriesText = parsenoop;
var parse_ChartFormat = parsenoop;
var parse_Legend = parsenoop;
var parse_SeriesList = parsenoop;
var parse_Bar = parsenoop;
var parse_Line = parsenoop;
var parse_Pie = parsenoop;
var parse_Area = parsenoop;
var parse_Scatter = parsenoop;
var parse_CrtLine = parsenoop;
var parse_Axis = parsenoop;
var parse_Tick = parsenoop;
var parse_ValueRange = parsenoop;
var parse_CatSerRange = parsenoop;
var parse_AxisLine = parsenoop;
var parse_CrtLink = parsenoop;
var parse_DefaultText = parsenoop;
var parse_Text = parsenoop;
var parse_ObjectLink = parsenoop;
var parse_Frame = parsenoop;
var parse_Begin = parsenoop;
var parse_End = parsenoop;
var parse_PlotArea = parsenoop;
var parse_Chart3d = parsenoop;
var parse_PicF = parsenoop;
var parse_DropBar = parsenoop;
var parse_Radar = parsenoop;
var parse_Surf = parsenoop;
var parse_RadarArea = parsenoop;
var parse_AxisParent = parsenoop;
var parse_LegendException = parsenoop;
var parse_SerToCrt = parsenoop;
var parse_AxesUsed = parsenoop;
var parse_SBaseRef = parsenoop;
var parse_SerParent = parsenoop;
var parse_SerAuxTrend = parsenoop;
var parse_IFmtRecord = parsenoop;
var parse_Pos = parsenoop;
var parse_AlRuns = parsenoop;
var parse_BRAI = parsenoop;
var parse_SerAuxErrBar = parsenoop;
var parse_SerFmt = parsenoop;
var parse_Chart3DBarShape = parsenoop;
var parse_Fbi = parsenoop;
var parse_BopPop = parsenoop;
var parse_AxcExt = parsenoop;
var parse_Dat = parsenoop;
var parse_PlotGrowth = parsenoop;
var parse_SIIndex = parsenoop;
var parse_GelFrame = parsenoop;
var parse_BopPopCustom = parsenoop;
var parse_Fbi2 = parsenoop;
/* --- Specific to versions before BIFF8 --- */
function parse_ImData(blob, length, opts) {
@ -1108,6 +905,12 @@ function parse_BIFF2NUM(blob, length, opts) {
cell.val = num;
return cell;
}
function write_BIFF2NUM(r/*:number*/, c/*:number*/, val/*:number*/) {
var out = new_buf(15);
write_BIFF2Cell(out, r, c);
out.write_shift(8, val, 'f');
return out;
}
function parse_BIFF2INT(blob, length) {
var cell = parse_XLSCell(blob, 6);
@ -1117,6 +920,12 @@ function parse_BIFF2INT(blob, length) {
cell.val = num;
return cell;
}
function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/) {
var out = new_buf(9);
write_BIFF2Cell(out, r, c);
out.write_shift(2, val);
return out;
}
function parse_BIFF2STRING(blob, length) {
var cch = blob.read_shift(1);

@ -172,14 +172,14 @@ function parse_si(x, opts) {
/* 18.4.12 t ST_Xstring (Plaintext String) */
// TODO: is whitespace actually valid here?
if(x.match(/^\s*<(?:\w+:)?t[^>]*>/)) {
z.t = utf8read(unescapexml(x.substr(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]));
z.t = unescapexml(utf8read(x.slice(x.indexOf(">")+1).split(/<\/(?:\w+:)?t>/)[0]||""));
z.r = utf8read(x);
if(html) z.h = escapehtml(z.t);
}
/* 18.4.4 r CT_RElt (Rich Text Run) */
else if((y = x.match(sirregex))) {
z.r = utf8read(x);
z.t = utf8read(unescapexml((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
z.t = unescapexml(utf8read((x.replace(sirphregex, '').match(sitregex)||[]).join("").replace(tagregex,"")));
if(html) z.h = parse_rs(z.r);
}
/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */

@ -16,7 +16,7 @@ function parse_comments_xml(data/*:string*/, opts)/*:Array<Comment>*/ {
var cm = x.match(/<(?:\w+:)?comment[^>]*>/);
if(!cm) return;
var y = parsexmltag(cm[0]);
var comment/*:Comment*/ = ({ author: y.authorId && authors[y.authorId] ? authors[y.authorId] : "sheetjsghost", ref: y.ref, guid: y.guid }/*:any*/);
var comment/*:Comment*/ = ({ 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>/);

@ -21,7 +21,7 @@ function write_BrtBeginComment(data, o) {
/* [MS-XLSB] 2.4.324 BrtCommentAuthor */
var parse_BrtCommentAuthor = parse_XLWideString;
function write_BrtCommentAuthor(data) { return write_XLWideString(data.substr(0, 54)); }
function write_BrtCommentAuthor(data) { return write_XLWideString(data.slice(0, 54)); }
/* [MS-XLSB] 2.1.7.8 Comments */
function parse_comments_bin(data, opts) {
@ -72,7 +72,7 @@ function write_comments_bin(data, opts) {
data.forEach(function(comment) {
comment[1].forEach(function(c) {
if(iauthor.indexOf(c.a) > -1) return;
iauthor.push(c.a.substr(0,54));
iauthor.push(c.a.slice(0,54));
write_record(ba, "BrtCommentAuthor", write_BrtCommentAuthor(c.a));
});
});

@ -329,14 +329,16 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
out = ((options.dense ? [] : {})/*:any*/);
} break;
case 'BOF': {
if(opts.biff !== 8){/* empty */}
else if(RecordType === 0x0009) opts.biff = 2;
else if(RecordType === 0x0209) opts.biff = 3;
else if(RecordType === 0x0409) opts.biff = 4;
else if(val.BIFFVer === 0x0500) opts.biff = 5;
else if(val.BIFFVer === 0x0600) opts.biff = 8;
else if(val.BIFFVer === 0x0002) opts.biff = 2;
else if(val.BIFFVer === 0x0007) opts.biff = 2;
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(file_depth++) break;
cell_valid = true;
out = ((options.dense ? [] : {})/*:any*/);
@ -692,7 +694,8 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
/* Explicitly Ignored */
case 'Excel9File': break;
case 'Units': break;
case 'InterfaceHdr': case 'Mms': case 'InterfaceEnd': case 'DSF': case 'BuiltInFnGroupCount': break;
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 'UserBView': case 'UserSViewBegin': case 'UserSViewEnd':
@ -791,6 +794,9 @@ function parse_workbook(blob, options/*:ParseOpts*/)/*:Workbook*/ {
case 'ListObj': case 'ListField': break;
case 'RRSort': break;
case 'BigName': break;
case 'ToolbarHdr': case 'ToolbarEnd': break;
case 'DDEObjName': break;
case 'FRTArchId$': break;
default: if(options.WTF) throw 'Unrecognized Record ' + R.n;
}}}}
} else blob.l += length;
@ -842,7 +848,6 @@ if(cfb.FullPaths) {
prep_blob(cfb, 0);
WB = ({content: cfb}/*:any*/);
}
if(!WB) WB = CFB.find(cfb, '/Book');
var CompObjP, SummaryP, WorkbookP/*:Workbook*/;
@ -869,3 +874,19 @@ if(options.bookFiles) WorkbookP.cfb = cfb;
return WorkbookP;
}
function write_xlscfb(wb/*:Workbook*/, opts/*:WriteOpts*/)/*:CFBContainer*/ {
var o = opts || {};
var cfb = CFB.utils.cfb_new({root:"R"});
var wbpath = "/Workbook";
switch(o.bookType || "xls") {
case "xls": o.bookType = "biff8";
/* 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");
}
CFB.utils.cfb_add(cfb, wbpath, write_biff_buf(wb, o));
// TODO: SI, DSI, CO
return cfb;
}

File diff suppressed because it is too large Load Diff

@ -1,20 +1,13 @@
/* BIFF2-4 single-sheet workbooks */
function write_biff_rec(ba/*:BufArray*/, t/*:number*/, payload, length/*:?number*/) {
var len = (length || (payload||[]).length);
function write_biff_rec(ba/*:BufArray*/, type/*:number|string*/, payload, length/*:?number*/) {
var t/*:number*/ = +type || +XLSRE[type];
if(isNaN(t)) return;
var len = length || (payload||[]).length || 0;
var o = ba.next(4 + len);
o.write_shift(2, t);
o.write_shift(2, len);
if(/*:: len != null &&*/len > 0 && is_buf(payload)) ba.push(payload);
}
function write_BOF(wb/*:Workbook*/, o) {
if(o.bookType != 'biff2') throw "unsupported BIFF version";
var out = new_buf(4);
out.write_shift(2, 0x0002); // "unused"
out.write_shift(2, 0x0010); // Sheet
return out;
}
function write_BIFF2Cell(out, r/*:number*/, c/*:number*/) {
if(!out) out = new_buf(7);
out.write_shift(2, r);
@ -25,20 +18,6 @@ function write_BIFF2Cell(out, r/*:number*/, c/*:number*/) {
return out;
}
function write_BIFF2INT(r/*:number*/, c/*:number*/, val/*:number*/) {
var out = new_buf(9);
write_BIFF2Cell(out, r, c);
out.write_shift(2, val);
return out;
}
function write_BIFF2NUMBER(r/*:number*/, c/*:number*/, val/*:number*/) {
var out = new_buf(15);
write_BIFF2Cell(out, r, c);
out.write_shift(8, val, 'f');
return out;
}
function write_BIFF2BERR(r/*:number*/, c/*:number*/, val, t/*:?string*/) {
var out = new_buf(9);
write_BIFF2Cell(out, r, c);
@ -56,14 +35,14 @@ function write_BIFF2LABEL(r/*:number*/, c/*:number*/, val) {
return out.l < out.length ? out.slice(0, out.l) : out;
}
function write_ws_biff_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
function write_ws_biff2_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
var v = cell.t == 'd' ? datenum(cell.v) : cell.v;
if((v == (v|0)) && (v >= 0) && (v < 65536))
write_biff_rec(ba, 0x0002, write_BIFF2INT(R, C, v));
else
write_biff_rec(ba, 0x0003, write_BIFF2NUMBER(R,C, v));
write_biff_rec(ba, 0x0003, write_BIFF2NUM(R,C, v));
return;
case 'b': case 'e': write_biff_rec(ba, 0x0005, write_BIFF2BERR(R, C, cell.v, cell.t)); return;
/* TODO: codepage, sst */
@ -74,7 +53,7 @@ function write_ws_biff_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:nu
write_biff_rec(ba, 0x0001, write_BIFF2Cell(null, R, C));
}
function write_biff_ws(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
function write_ws_biff2(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts, wb/*:Workbook*/) {
var dense = Array.isArray(ws);
var range = safe_decode_range(ws['!ref'] || "A1"), ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
for(var R = range.s.r; R <= range.e.r; ++R) {
@ -85,24 +64,155 @@ function write_biff_ws(ba/*:BufArray*/, ws/*:Worksheet*/, idx/*:number*/, opts,
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell) continue;
/* write cell */
write_ws_biff_cell(ba, cell, R, C, opts);
write_ws_biff2_cell(ba, cell, R, C, opts);
}
}
}
/* Based on test files */
function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
function write_biff2_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
var o = opts || {};
if(DENSE != null && o.dense == null) o.dense = DENSE;
var ba = buf_array();
var idx = 0;
for(var i=0;i<wb.SheetNames.length;++i) if(wb.SheetNames[i] == o.sheet) idx=i;
if(idx == 0 && !!o.sheet && wb.SheetNames[0] != o.sheet) throw new Error("Sheet not found: " + o.sheet);
write_biff_rec(ba, 0x0009, write_BOF(wb, o));
write_biff_rec(ba, 0x0009, write_BOF(wb, 0x10, o));
/* ... */
write_biff_ws(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
write_ws_biff2(ba, wb.Sheets[wb.SheetNames[idx]], idx, o, wb);
/* ... */
write_biff_rec(ba, 0x000a);
// TODO
write_biff_rec(ba, 0x000A);
return ba.end();
}
function write_ws_biff8_cell(ba/*:BufArray*/, cell/*:Cell*/, R/*:number*/, C/*:number*/, opts) {
if(cell.v != null) switch(cell.t) {
case 'd': case 'n':
var v = cell.t == 'd' ? datenum(cell.v) : cell.v;
/* TODO: emit RK as appropriate */
write_biff_rec(ba, "Number", write_Number(R, C, v, opts));
return;
case 'b': case 'e': write_biff_rec(ba, "BoolErr", write_BoolErr(R, C, cell.v, opts, cell.t)); return;
/* TODO: codepage, sst */
case 's': case 'str':
write_biff_rec(ba, "Label", write_Label(R, C, cell.v, opts));
return;
}
write_biff_rec(ba, "Blank", write_XLSCell(R, C));
}
/* [MS-XLS] 2.1.7.20.5 */
function write_ws_biff8(idx/*:number*/, opts, wb/*:Workbook*/) {
var ba = buf_array();
var s = wb.SheetNames[idx], ws = wb.Sheets[s] || {};
var dense = Array.isArray(ws);
var ref/*:string*/, rr = "", cols/*:Array<string>*/ = [];
var range = safe_decode_range(ws['!ref'] || "A1");
write_biff_rec(ba, 0x0809, write_BOF(wb, 0x10, opts));
/* ... */
write_biff_rec(ba, "CalcMode", writeuint16(1));
write_biff_rec(ba, "CalcCount", writeuint16(100));
write_biff_rec(ba, "CalcRefMode", writebool(true));
write_biff_rec(ba, "CalcIter", writebool(false));
write_biff_rec(ba, "CalcDelta", write_Xnum(0.001));
write_biff_rec(ba, "CalcSaveRecalc", writebool(true));
write_biff_rec(ba, "PrintRowCol", writebool(false));
write_biff_rec(ba, "PrintGrid", writebool(false));
write_biff_rec(ba, "GridSet", writeuint16(1));
write_biff_rec(ba, "Guts", write_Guts([0,0]));
/* ... */
write_biff_rec(ba, "HCenter", writebool(false));
write_biff_rec(ba, "VCenter", writebool(false));
/* ... */
write_biff_rec(ba, "Dimensions", write_Dimensions(range, opts));
/* ... */
for(var R = range.s.r; R <= range.e.r; ++R) {
rr = encode_row(R);
for(var C = range.s.c; C <= range.e.c; ++C) {
if(R === range.s.r) cols[C] = encode_col(C);
ref = cols[C] + rr;
var cell = dense ? (ws[R]||[])[C] : ws[ref];
if(!cell) continue;
/* write cell */
write_ws_biff8_cell(ba, cell, R, C, opts);
}
}
/* ... */
write_biff_rec(ba, "EOF");
return ba.end();
}
/* [MS-XLS] 2.1.7.20.3 */
function write_biff8_global(wb/*:Workbook*/, bufs, opts/*:WriteOpts*/) {
var A = buf_array();
var b8 = opts.biff == 8, b5 = opts.biff == 5;
write_biff_rec(A, 0x0809, write_BOF(wb, 0x05, opts));
write_biff_rec(A, "InterfaceHdr", writeuint16(0x04b0));
write_biff_rec(A, "Mms", writezeroes(2));
if(b5) write_biff_rec(A, "ToolbarHdr");
if(b5) write_biff_rec(A, "ToolbarEnd");
write_biff_rec(A, "InterfaceEnd");
write_biff_rec(A, "WriteAccess", write_WriteAccess("SheetJS", opts));
write_biff_rec(A, "CodePage", writeuint16(0x04b0));
if(b8) write_biff_rec(A, "DSF", writeuint16(0));
if(b8) write_biff_rec(A, "RRTabId", write_RRTabId(wb.SheetNames.length));
if(b8) write_biff_rec(A, "BuiltInFnGroupCount", writeuint16(0x11));
write_biff_rec(A, "WinProtect", writebool(false));
write_biff_rec(A, "Protect", writebool(false));
write_biff_rec(A, "Password", writeuint16(0));
if(b8) write_biff_rec(A, "Prot4Rev", writebool(false));
if(b8) write_biff_rec(A, "Prot4RevPass", writeuint16(0));
write_biff_rec(A, "Window1", write_Window1(opts));
write_biff_rec(A, "Backup", writebool(false));
write_biff_rec(A, "HideObj", writeuint16(0));
write_biff_rec(A, "Date1904", writebool(safe1904(wb)=="true"));
write_biff_rec(A, "CalcPrecision", writebool(true));
write_biff_rec(A, "RefreshAll", writebool(false));
write_biff_rec(A, "BookBool", writeuint16(0));
/* ... */
write_biff_rec(A, "UsesELFs", writebool(false));
var a = A.end();
var C = buf_array();
write_biff_rec(C, "Country", write_Country());
/* BIFF8: [SST *Continue] ExtSST */
write_biff_rec(C, "EOF");
var c = C.end();
var B = buf_array();
var blen = 0, j = 0;
for(j = 0; j < wb.SheetNames.length; ++j) blen += 12 + (b8 ? 2 : 1) * wb.SheetNames[j].length;
var start = a.length + blen + c.length;
for(j = 0; j < wb.SheetNames.length; ++j) {
write_biff_rec(B, "BoundSheet8", write_BoundSheet8({pos:start, hs:0, dt:0, name:wb.SheetNames[j]}, opts));
start += bufs[j].length;
}
/* 1*BoundSheet8 */
var b = B.end();
if(blen != b.length) throw new Error("BS8 " + blen + " != " + b.length);
var out = [];
if(a.length) out.push(a);
if(b.length) out.push(b);
if(c.length) out.push(c);
return __toBuffer([out]);
}
/* [MS-XLS] 2.1.7.20 Workbook Stream */
function write_biff8_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
var o = opts || {};
var bufs = [];
for(var i = 0; i < wb.SheetNames.length; ++i) bufs[bufs.length] = write_ws_biff8(i, o, wb);
bufs.unshift(write_biff8_global(wb, bufs, o));
return __toBuffer([bufs]);
}
function write_biff_buf(wb/*:Workbook*/, opts/*:WriteOpts*/) {
var o = opts || {};
switch(o.biff || 2) {
case 8: case 5: return write_biff8_buf(wb, opts);
case 4: case 3: case 2: return write_biff2_buf(wb, opts);
}
throw new Error("invalid type " + o.bookType + " for BIFF");
}

@ -14,6 +14,18 @@ function write_zip_type(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
return z.generate(oopts);
}
function write_cfb_type(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
var o = opts||{};
var cfb/*:CFBContainer*/ = write_xlscfb(wb, o);
switch(o.type) {
case "base64": case "binary": break;
case "buffer": case "array": o.type = ""; break;
case "file": return _fs.writeFileSync(o.file, CFB.write(cfb, {type:'buffer'}));
default: throw new Error("Unrecognized type " + o.type);
}
return CFB.write(cfb, o);
}
/* TODO: test consistency */
function write_bstr_type(out/*:string*/, opts/*:WriteOpts*/) {
switch(opts.type) {
@ -71,7 +83,12 @@ function writeSync(wb/*:Workbook*/, opts/*:?WriteOpts*/) {
case 'prn': return write_string_type(write_prn_str(wb, o), o);
case 'rtf': return write_string_type(write_rtf_str(wb, o), o);
case 'fods': return write_string_type(write_ods(wb, o), o);
case 'biff2': return write_binary_type(write_biff_buf(wb, o), o);
case 'biff2': if(!o.biff) o.biff = 2; return write_binary_type(write_biff_buf(wb, o), o);
case 'biff3': if(!o.biff) o.biff = 3; return write_binary_type(write_biff_buf(wb, o), o);
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; return write_cfb_type(wb, o);
case 'biff8':
case 'xls': if(!o.biff) o.biff = 8; return write_cfb_type(wb, o);
case 'xlsx':
case 'xlsm':
case 'xlsb':
@ -89,7 +106,7 @@ function resolve_book_type(o/*?WriteFileOpts*/) {
case '.xlml': o.bookType = 'xlml'; break;
case '.sylk': o.bookType = 'sylk'; break;
case '.html': o.bookType = 'html'; break;
case '.xls': o.bookType = 'biff2'; break;
case '.xls': o.bookType = 'biff8'; break;
case '.xml': o.bookType = 'xml'; break;
case '.ods': o.bookType = 'ods'; break;
case '.csv': o.bookType = 'csv'; break;

@ -43,7 +43,9 @@ the module can be omitted by aliasing the dependency:
## Bower and minified versions
The minified versions, used in Bower, require `module.noParse` configuration:
Webpack may show a message like "This seems to be a pre-built javascript file"
when processing minified files (like the default Bower script). The message is
harmless. To suppress the message, set `module.noParse` in the webpack config:
```js
module: {

28
dist/xlsx.core.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

30
dist/xlsx.full.min.js vendored

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

3424
dist/xlsx.js vendored

File diff suppressed because it is too large Load Diff

23
dist/xlsx.min.js vendored

File diff suppressed because one or more lines are too long

2
dist/xlsx.min.map vendored

File diff suppressed because one or more lines are too long

@ -35,7 +35,8 @@ output formats. The specific file type is controlled with `bookType` option:
| `xlsx` | `.xlsx` | ZIP | multi | Excel 2007+ XML Format |
| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet format |
| `biff8` | `.xls` | CFB | multi | Excel 97-2004 Workbook Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |

@ -8,7 +8,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Excel 2007+ XML Formats (XLSX/XLSM) | :o: | :o: |
| Excel 2007+ Binary Format (XLSB BIFF12) | :o: | :o: |
| Excel 2003-2004 XML Format (XML "SpreadsheetML") | :o: | :o: |
| Excel 97-2004 (XLS BIFF8) | :o: | |
| Excel 97-2004 (XLS BIFF8) | :o: | :o: |
| Excel 5.0/95 (XLS BIFF5) | :o: | |
| Excel 4.0 (XLS/XLW BIFF4) | :o: | |
| Excel 3.0 (XLS BIFF3) | :o: | |

@ -40,6 +40,7 @@ digraph G {
csf -> xlml
xlml -> csf
xls5 -> csf
csf -> xls8
xls8 -> csf
ods -> csf
csf -> ods

Binary file not shown.

Before

Width:  |  Height:  |  Size: 168 KiB

After

Width:  |  Height:  |  Size: 170 KiB

@ -54,7 +54,6 @@ Use readAsBinaryString: (when available) <input type="checkbox" name="userabs" c
<script>
/*jshint browser:true */
/* eslint-env browser */
/* eslint no-use-before-define:0 */
/*global Uint8Array, Uint16Array, ArrayBuffer */
/*global XLSX */
var X = XLSX;
@ -215,6 +214,7 @@ var do_file = (function() {
})();
</script>
<script type="text/javascript">
/* eslint no-use-before-define:0 */
var _gaq = _gaq || [];
_gaq.push(['_setAccount', 'UA-36810333-1']);
_gaq.push(['_trackPageview']);

@ -1444,7 +1444,8 @@ output formats. The specific file type is controlled with `bookType` option:
| `xlsx` | `.xlsx` | ZIP | multi | Excel 2007+ XML Format |
| `xlsm` | `.xlsm` | ZIP | multi | Excel 2007+ Macro XML Format |
| `xlsb` | `.xlsb` | ZIP | multi | Excel 2007+ Binary Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet format |
| `biff8` | `.xls` | CFB | multi | Excel 97-2004 Workbook Format |
| `biff2` | `.xls` | none | single | Excel 2.0 Worksheet Format |
| `xlml` | `.xls` | none | multi | Excel 2003-2004 (SpreadsheetML) |
| `ods` | `.ods` | ZIP | multi | OpenDocument Spreadsheet |
| `fods` | `.fods` | none | multi | Flat OpenDocument Spreadsheet |
@ -1746,7 +1747,7 @@ Despite the library name `xlsx`, it supports numerous spreadsheet file formats:
| Excel 2007+ XML Formats (XLSX/XLSM) | :o: | :o: |
| Excel 2007+ Binary Format (XLSB BIFF12) | :o: | :o: |
| Excel 2003-2004 XML Format (XML "SpreadsheetML") | :o: | :o: |
| Excel 97-2004 (XLS BIFF8) | :o: | |
| Excel 97-2004 (XLS BIFF8) | :o: | :o: |
| Excel 5.0/95 (XLS BIFF5) | :o: | |
| Excel 4.0 (XLS/XLW BIFF4) | :o: | |
| Excel 3.0 (XLS BIFF3) | :o: | |

@ -101,6 +101,7 @@ type RowInfo = {
hpx?:number; // height in screen pixels
hpt?:number; // height in points
level?:number; // outline / group level
};
type ColInfo = {

@ -1,11 +1,13 @@
#!/bin/bash
# strip_sourcemap.sh -- strip sourcemaps from a JS file (missing from uglifyjs)
# Copyright (C) 2014-present SheetJS
# note: this version also renames write_shift / read_shift to _W / _R
if [ $# -gt 0 ]; then
if [ -e "$1" ]; then
sed -i.sheetjs '/sourceMappingURL/d' "$1"
sed -i.sheetjs 's/write_shift/_W/g; s/read_shift/_R/g' "$1"
fi
else
cat - | sed '/sourceMappingURL/d'
cat - | sed '/sourceMappingURL/d' | sed 's/write_shift/_W/g; s/read_shift/_R/g'
fi

@ -1,6 +1,6 @@
{
"name": "xlsx",
"version": "0.11.3",
"version": "0.11.4",
"author": "sheetjs",
"description": "Excel (XLSB/XLSX/XLS/XML) ODS and other spreadsheet format (CSV/DIF/DBF/SYLK) parser and writer",
"keywords": [ "excel", "xls", "xlsx", "xlsb", "xlsm", "ods", "csv", "dbf", "dif", "sylk", "office", "spreadsheet" ],
@ -20,8 +20,8 @@
"exit-on-epipe":"~1.0.1",
"ssf":"~0.10.1",
"codepage":"~1.11.0",
"cfb":"~0.12.1",
"crc-32":"~1.1.0",
"cfb":"~0.13.1",
"crc-32":"~1.1.1",
"adler-32":"~1.1.0",
"commander":"~2.11.0"
},

@ -13,7 +13,7 @@ var opts = {cellNF: true};
var TYPE = browser ? "binary" : "buffer";
opts.type = TYPE;
var fullex = [".xlsb", /*".xlsm",*/ ".xlsx"/*, ".xlml"*/];
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "xlml", "sylk", "dif"];
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "biff8", "xlml", "sylk", "dif"];
var ex = fullex.slice(); ex = ex.concat([".ods", ".xls", ".xml", ".fods"]);
if(typeof process != 'undefined' && ((process||{}).env)) {
opts.WTF = true;
@ -1458,7 +1458,7 @@ describe('roundtrip features', function() {
});
describe('should preserve column properties', function() { [
'xlml', /*'biff2', */ 'xlsx', 'xlsb', 'slk'
'xlml', /*'biff2', 'biff8', */ 'xlsx', 'xlsb', 'slk'
].forEach(function(w) { it(w, function() {
var ws1 = X.utils.aoa_to_sheet([["hpx12", "hpt24", "hpx48", "hidden"]]);
ws1['!cols'] = [{wch:9},{wpx:100},{width:80},{hidden:true}];
@ -1477,7 +1477,7 @@ describe('roundtrip features', function() {
/* TODO: ODS and BIFF5/8 */
describe('should preserve row properties', function() { [
'xlml', /*'biff2', */ 'xlsx', 'xlsb', 'slk'
'xlml', /*'biff2', 'biff8', */ 'xlsx', 'xlsb', 'slk'
].forEach(function(w) { it(w, function() {
var ws1 = X.utils.aoa_to_sheet([["hpx12"],["hpt24"],["hpx48"],["hidden"]]);
ws1['!rows'] = [{hpx:12},{hpt:24},{hpx:48},{hidden:true}];
@ -1979,6 +1979,7 @@ describe('corner cases', function() {
X.write(wb, {type: "base64", bookType: 'xlsb'});
X.write(wb, {type: "binary", bookType: 'ods'});
X.write(wb, {type: "binary", bookType: 'biff2'});
X.write(wb, {type: "binary", bookType: 'biff8'});
get_cell(ws,"A2").t = "f";
assert.throws(function() { X.utils.make_json(ws); });
});

@ -1 +1 @@
Subproject commit d0f58a9e4b0519a513a1e44d1b28109fd4a8e13e
Subproject commit a9c6bbb161ca45a077779ecbe434d8c5d614ee37

@ -1078,7 +1078,7 @@ jxls-examples_basictags.xls
jxls-examples_chart.xls
jxls-examples_colouring.xls
jxls-examples_department.xls
jxls-examples_dynamicolumns.xls
jxls-examples_dynamiccolumns.xls
jxls-examples_employees.xls
jxls-examples_ex_temp.xls
jxls-examples_grouping.xls

@ -13,7 +13,7 @@ var opts = {cellNF: true};
var TYPE = browser ? "binary" : "buffer";
opts.type = TYPE;
var fullex = [".xlsb", /*".xlsm",*/ ".xlsx"/*, ".xlml"*/];
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "xlml", "sylk", "dif"];
var ofmt = ["xlsb", "xlsm", "xlsx", "ods", "biff2", "biff8", "xlml", "sylk", "dif"];
var ex = fullex.slice(); ex = ex.concat([".ods", ".xls", ".xml", ".fods"]);
if(typeof process != 'undefined' && ((process||{}).env)) {
opts.WTF = true;
@ -1253,19 +1253,19 @@ describe('write features', function() {
X = require(modp);
ws = X.utils.aoa_to_sheet([["a","b","c"],[1,2,3]]);
baseprops = {
Category: "C4tegory",
ContentStatus: "C0ntentStatus",
Keywords: "K3ywords",
LastAuthor: "L4stAuthor",
LastPrinted: "L4stPrinted",
Category: "Newspaper",
ContentStatus: "Published",
Keywords: "print",
LastAuthor: "Perry White",
LastPrinted: "1978-12-15",
RevNumber: 6969,
AppVersion: 69,
Author: "4uth0r",
Comments: "C0mments",
Author: "Lois Lane",
Comments: "Needs work",
Identifier: "1d",
Language: "L4nguage",
Subject: "Subj3ct",
Title: "T1tle"
Language: "English",
Subject: "Superman",
Title: "Man of Steel"
};
});
if(typeof before != 'undefined') before(bef);
@ -1458,7 +1458,7 @@ describe('roundtrip features', function() {
});
describe('should preserve column properties', function() { [
'xlml', /*'biff2', */ 'xlsx', 'xlsb', 'slk'
'xlml', /*'biff2', 'biff8', */ 'xlsx', 'xlsb', 'slk'
].forEach(function(w) { it(w, function() {
var ws1 = X.utils.aoa_to_sheet([["hpx12", "hpt24", "hpx48", "hidden"]]);
ws1['!cols'] = [{wch:9},{wpx:100},{width:80},{hidden:true}];
@ -1477,7 +1477,7 @@ describe('roundtrip features', function() {
/* TODO: ODS and BIFF5/8 */
describe('should preserve row properties', function() { [
'xlml', /*'biff2', */ 'xlsx', 'xlsb', 'slk'
'xlml', /*'biff2', 'biff8', */ 'xlsx', 'xlsb', 'slk'
].forEach(function(w) { it(w, function() {
var ws1 = X.utils.aoa_to_sheet([["hpx12"],["hpt24"],["hpx48"],["hidden"]]);
ws1['!rows'] = [{hpx:12},{hpt:24},{hpx:48},{hidden:true}];
@ -1979,6 +1979,7 @@ describe('corner cases', function() {
X.write(wb, {type: "base64", bookType: 'xlsb'});
X.write(wb, {type: "binary", bookType: 'ods'});
X.write(wb, {type: "binary", bookType: 'biff2'});
X.write(wb, {type: "binary", bookType: 'biff8'});
get_cell(ws,"A2").t = "f";
assert.throws(function() { X.utils.make_json(ws); });
});

@ -14,10 +14,10 @@ var data = [
var ws_name = "SheetJS";
var wscols = [
{wch:6}, // "characters"
{wpx:50}, // "pixels"
{wch: 6}, // "characters"
{wpx: 50}, // "pixels"
,
{hidden:true} // hide column
{hidden: true} // hide column
];
/* At 96 PPI, 1 pt = 1 px */
@ -162,7 +162,8 @@ var filenames = [
['sheetjs.xlsx', {bookSST:true}],
['sheetjs.xlsm'],
['sheetjs.xlsb'],
['sheetjs.xls', {bookType:'biff2'}],
['sheetjs.xls', {bookType:'xls'}],
['sheetjs.biff2', {bookType:'biff2'}],
['sheetjs.xml.xls', {bookType:'xlml'}],
['sheetjs.ods'],
['sheetjs.fods'],

@ -2,12 +2,12 @@
/* eslint-env node */
const n = "xlsx";
/* vim: set ts=2 ft=javascript: */
import XLSX = require("xlsx");
import X = require("xlsx");
import 'exit-on-epipe';
import * as fs from 'fs';
import program = require('commander');
program
.version(XLSX.version)
.version(X.version)
.usage('[options] <file> [sheetname]')
.option('-f, --file <file>', 'use specified workbook')
.option('-s, --sheet <sheet>', 'print specified sheet (default first sheet)')
@ -42,6 +42,7 @@ program
.option('--read-only', 'do not generate output')
.option('--all', 'parse everything; write as much as possible')
.option('--dev', 'development mode')
.option('--sparse', 'sparse mode')
.option('--read', 'read but do not print out contents')
.option('-q, --quiet', 'quiet mode');
@ -77,8 +78,7 @@ if(!fs.existsSync(filename)) {
process.exit(2);
}
let opts: XLSX.ParsingOptions = {};
let wb: XLSX.WorkBook;
let opts: X.ParsingOptions = {}, wb: X.WorkBook;
if(program.listSheets) opts.bookSheets = true;
if(program.sheetRows) opts.sheetRows = program.sheetRows;
if(program.password) opts.password = program.password;
@ -89,8 +89,13 @@ function wb_fmt() {
opts.cellNF = true;
if(program.output) sheetname = program.output;
}
workbook_formats.forEach(function(m) { if(program[m]) { wb_fmt(); } });
wb_formats_2.forEach(function(m) { if(program[m[0]]) { wb_fmt(); } });
function isfmt(m: string): boolean {
if(!program.output) return false;
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(); } });
wb_formats_2.forEach(function(m) { if(program[m[0]] || isfmt(m[0])) { wb_fmt(); } });
if(seen) {
} else if(program.formulae) opts.cellFormula = true;
else opts.cellFormula = false;
@ -104,12 +109,13 @@ if(program.all) {
opts.sheetStubs = true;
opts.cellDates = true;
}
if(program.sparse) opts.dense = false; else opts.dense = true;
if(program.dev) {
opts.WTF = true;
wb = XLSX.readFile(filename, opts);
wb = X.readFile(filename, opts);
} else try {
wb = XLSX.readFile(filename, opts);
wb = X.readFile(filename, opts);
} catch(e) {
let msg = (program.quiet) ? "" : n + ": error parsing ";
msg += filename + ": " + e;
@ -124,18 +130,18 @@ if(program.listSheets) {
process.exit(0);
}
let wopts: XLSX.WritingOptions = ({WTF:opts.WTF, bookSST:program.sst}/*:any*/);
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]) {
XLSX.writeFile(wb, sheetname || ((filename || "") + "." + m), wopts);
workbook_formats.forEach(function(m) { if(program[m] || isfmt(m)) {
X.writeFile(wb, program.output || sheetname || ((filename || "") + "." + m), wopts);
process.exit(0);
} });
wb_formats_2.forEach(function(m) { if(program[m[0]]) {
wopts.bookType = <XLSX.BookType>(m[1]);
XLSX.writeFile(wb, sheetname || ((filename || "") + "." + m[2]), wopts);
wb_formats_2.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);
} });
@ -145,7 +151,7 @@ if(target_sheet === '') {
else target_sheet = (wb.SheetNames||[""])[0];
}
let ws: XLSX.WorkSheet;
let ws: X.WorkSheet;
try {
ws = wb.Sheets[target_sheet];
if(!ws) {
@ -167,22 +173,21 @@ if(program.readOnly) process.exit(0);
['prn', '.prn'],
['txt', '.txt'],
['dif', '.dif']
].forEach(function(m) { if(program[m[0]]) {
wopts.bookType = <XLSX.BookType>(m[1]);
XLSX.writeFile(wb, sheetname || ((filename || "") + m[1]), wopts);
].forEach(function(m) { if(program[m[0]] || isfmt(m[1])) {
wopts.bookType = <X.BookType>(m[0]);
X.writeFile(wb, program.output || sheetname || ((filename || "") + m[1]), wopts);
process.exit(0);
} });
let oo = "";
let strm = false;
let oo = "", strm = false;
if(!program.quiet) console.error(target_sheet);
if(program.formulae) oo = XLSX.utils.sheet_to_formulae(ws).join("\n");
else if(program.json) oo = JSON.stringify(XLSX.utils.sheet_to_json(ws));
else if(program.rawJs) oo = JSON.stringify(XLSX.utils.sheet_to_json(ws,{raw:true}));
else if(program.arrays) oo = JSON.stringify(XLSX.utils.sheet_to_json(ws,{raw:true, header:1}));
if(program.formulae) oo = X.utils.sheet_to_formulae(ws).join("\n");
else if(program.json) oo = JSON.stringify(X.utils.sheet_to_json(ws));
else if(program.rawJs) oo = JSON.stringify(X.utils.sheet_to_json(ws,{raw:true}));
else if(program.arrays) oo = JSON.stringify(X.utils.sheet_to_json(ws,{raw:true, header:1}));
else {
strm = true;
let stream: NodeJS.ReadableStream = XLSX.stream.to_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
let stream: NodeJS.ReadableStream = X.stream.to_csv(ws, {FS:program.fieldSep, RS:program.rowSep});
if(program.output) stream.pipe(fs.createWriteStream(program.output));
else stream.pipe(process.stdout);
}

7
types/index.d.ts vendored

@ -176,6 +176,8 @@ export interface ParsingOptions extends CommonOptions {
/* If true, plaintext parsing will not parse values */
raw?: boolean;
dense?: boolean;
}
/** Options for write and writeFile */
@ -308,6 +310,9 @@ export interface RowInfo {
/** height in points */
hpt?: number;
/** outline / group level */
level?: number;
}
/**
@ -472,7 +477,7 @@ export type ExcelDataType = 'b' | 'n' | 'e' | 's' | 'd' | 'z';
* Type of generated workbook
* @default 'xlsx'
*/
export type BookType = 'xlsx' | 'xlsm' | 'xlsb' | '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' | 'prn';
/** Comment element */
export interface Comment {

@ -25,7 +25,7 @@ let wsrows: XLSX.RowInfo[] = [
{hpt: 12}, // "points"
{hpx: 16}, // "pixels"
,
{hpx: 24},
{hpx: 24, level:3},
{hidden: true}, // hide row
{hidden: false}
];
@ -150,15 +150,17 @@ const filenames: Array<[string]|[string, XLSX.WritingOptions]> = [
['sheetjs.xlsx', {bookSST:true}],
['sheetjs.xlsm'],
['sheetjs.xlsb'],
['sheetjs.xls', {bookType:'biff2'}],
['sheetjs.xls', {bookType:'xls'}],
['sheetjs.biff2', {bookType:'biff2'}],
['sheetjs.xml.xls', {bookType:'xlml'}],
['sheetjs.ods'],
['sheetjs.fods'],
['sheetjs.slk'],
['sheetjs.csv'],
['sheetjs.txt'],
['sheetjs.prn'],
['sheetjs.dif']
['sheetjs.slk'],
['sheetjs.htm'],
['sheetjs.dif'],
['sheetjs.prn']
];
filenames.forEach((r) => {

File diff suppressed because it is too large Load Diff

3418
xlsx.js

File diff suppressed because it is too large Load Diff