version bump 0.5.4: more options
- cellHTML controls HTML generation - cellFormula controls formula output - sheetStubs now defaults to false - cleaned up unnecessary CSV quotes (fixed #45) - updated test_files to 20140211 - updated SSF to 0.5.7 - removed unused main function - removed some dead code
This commit is contained in:
parent
27af8a6d6a
commit
7e9f218f0f
24
README.md
24
README.md
@ -17,14 +17,6 @@ In the browser:
|
||||
|
||||
## Usage
|
||||
|
||||
The node version installs a binary `xlsx2csv` which can read XLSX/XLSM/XLSB files and output the contents in various formats. The source is available at `xlsx2csv.njs` in the bin directory.
|
||||
|
||||
See <http://oss.sheetjs.com/js-xlsx/> for a browser example.
|
||||
|
||||
Note that older versions of IE does not support HTML5 File API, so the base64 mode is provided for testing. On OSX you can get the base64 encoding by running:
|
||||
|
||||
$ <target_file.xlsx base64 | pbcopy # the pbcopy puts the content in the clipboard
|
||||
|
||||
Simple usage (walks through every cell of every sheet and dumps the values):
|
||||
|
||||
var XLSX = require('xlsx')
|
||||
@ -37,6 +29,14 @@ Simple usage (walks through every cell of every sheet and dumps the values):
|
||||
}
|
||||
});
|
||||
|
||||
The node version installs a binary `xlsx2csv` which can read XLSX/XLSM/XLSB files and output the contents in various formats. The source is available at `xlsx2csv.njs` in the bin directory.
|
||||
|
||||
See <http://oss.sheetjs.com/js-xlsx/> for a browser example.
|
||||
|
||||
Note that older versions of IE does not support HTML5 File API, so the base64 mode is provided for testing. On OSX you can get the base64 encoding by running:
|
||||
|
||||
$ <target_file.xlsx base64 | pbcopy # the pbcopy puts the content in the clipboard
|
||||
|
||||
Some helper functions in `XLSX.utils` generate different views of the sheets:
|
||||
|
||||
- `XLSX.utils.sheet_to_csv` generates CSV
|
||||
@ -75,8 +75,14 @@ The exported `read` and `readFile` functions accept an options argument:
|
||||
|
||||
| Option Name | Default | Description |
|
||||
| :---------- | ------: | :---------- |
|
||||
| cellFormula | true | Save formulae to the .f field ** |
|
||||
| cellHTML | true | Parse rich text and save HTML to the .h field |
|
||||
| cellNF | false | Save number format string to the .z field |
|
||||
| sheetStubs | true | Create cell objects for stub cells |
|
||||
| sheetStubs | false | Create cell objects for stub cells |
|
||||
|
||||
- `cellFormula` only applies to constructing XLSB formulae. XLSX/XLSM formulae
|
||||
are stored in plaintext, but XLSB formulae are stored in a binary format.
|
||||
- Even if `cellNF` is false, formatted text (.w) will be generated
|
||||
|
||||
The defaults are enumerated in bits/84_defaults.js
|
||||
|
||||
|
@ -6,7 +6,7 @@ var _strrev = function(x) { return String(x).split("").reverse().join("");};
|
||||
function fill(c,l) { return new Array(l+1).join(c); }
|
||||
function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);}
|
||||
function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));}
|
||||
SSF.version = '0.5.4';
|
||||
SSF.version = '0.5.7';
|
||||
/* Options */
|
||||
var opts_fmt = {};
|
||||
function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
|
||||
@ -147,23 +147,20 @@ var write_date = function(type, fmt, val) {
|
||||
switch(type) {
|
||||
case 'y': switch(fmt) { /* year */
|
||||
case 'y': case 'yy': return pad(val.y % 100,2);
|
||||
case 'yyy': case 'yyyy': return pad(val.y % 10000,4);
|
||||
default: throw 'bad year format: ' + fmt;
|
||||
default: return pad(val.y % 10000,4);
|
||||
}
|
||||
case 'm': switch(fmt) { /* month */
|
||||
case 'm': return val.m;
|
||||
case 'mm': return pad(val.m,2);
|
||||
case 'mmm': return months[val.m-1][1];
|
||||
case 'mmmm': return months[val.m-1][2];
|
||||
case 'mmmmm': return months[val.m-1][0];
|
||||
default: throw 'bad month format: ' + fmt;
|
||||
default: return months[val.m-1][2];
|
||||
}
|
||||
case 'd': switch(fmt) { /* day */
|
||||
case 'd': return val.d;
|
||||
case 'dd': return pad(val.d,2);
|
||||
case 'ddd': return days[val.q][0];
|
||||
case 'dddd': return days[val.q][1];
|
||||
default: throw 'bad day format: ' + fmt;
|
||||
default: return days[val.q][1];
|
||||
}
|
||||
case 'h': switch(fmt) { /* 12-hour */
|
||||
case 'h': return 1+(val.H+11)%12;
|
||||
@ -196,7 +193,6 @@ var write_date = function(type, fmt, val) {
|
||||
} return fmt.length === 3 ? o : pad(o, 2);
|
||||
/* TODO: handle the ECMA spec format ee -> yy */
|
||||
case 'e': { return val.y; } break;
|
||||
default: throw 'bad format type ' + type + ' in ' + fmt;
|
||||
}
|
||||
};
|
||||
/*jshint +W086 */
|
||||
@ -212,14 +208,20 @@ var write_num = function(type, fmt, val) {
|
||||
if(mul !== 0) return write_num(type, fmt, val * Math.pow(10,2*mul)) + fill("%",mul);
|
||||
if(fmt.indexOf("E") > -1) {
|
||||
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
|
||||
if(fmt == '##0.0E+0') {
|
||||
var period = fmt.length - 5;
|
||||
if(fmt.match(/^#+0.0E\+0$/)) {
|
||||
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
|
||||
var ee = (Number(val.toExponential(0).substr(2+(val<0))))%period;
|
||||
if(ee < 0) ee += period;
|
||||
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
|
||||
if(!o.match(/[Ee]/)) {
|
||||
var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
|
||||
if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
|
||||
else throw "missing E |" + o;
|
||||
else o += "E+" + (fakee - ee);
|
||||
while(o.substr(0,2) === "0.") {
|
||||
o = o[0] + o.substr(2,period) + "." + o.substr(2+period);
|
||||
o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
|
||||
}
|
||||
o = o.replace(/\+-/,"-");
|
||||
}
|
||||
o = o.replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
|
||||
} else o = val.toExponential(idx);
|
||||
@ -234,6 +236,7 @@ var write_num = function(type, fmt, val) {
|
||||
var myn = (rnd - base*den), myd = den;
|
||||
return sign + (base?base:"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad(myn,r[1].length," ") + r[2] + "/" + r[3] + pad(myd,r[4].length));
|
||||
}
|
||||
if(fmt.match(/^#+0+$/)) fmt = fmt.replace(/#/g,"");
|
||||
if(fmt.match(/^00+$/)) return (val<0?"-":"")+pad(Math.round(aval),fmt.length);
|
||||
if(fmt.match(/^[#?]+$/)) return String(Math.round(val)).replace(/^0$/,"");
|
||||
if((r = fmt.match(/^#*0+\.(0+)/))) {
|
||||
@ -323,7 +326,8 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
out.push(q); lst = c; break;
|
||||
case '[': /* TODO: Fix this -- ignore all conditionals and formatting */
|
||||
o = c;
|
||||
while(fmt[i++] !== ']') o += fmt[i];
|
||||
while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i];
|
||||
if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
|
||||
if(o.match(/\[[HhMmSs]*\]/)) {
|
||||
if(!dt) dt = parse_date_code(v, opts);
|
||||
if(!dt) return "";
|
||||
@ -344,7 +348,7 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
out.push({t:'D', v:o}); break;
|
||||
case ' ': out.push({t:c,v:c}); ++i; break;
|
||||
default:
|
||||
if(",$-+/():!^&'~{}<>=".indexOf(c) === -1)
|
||||
if(",$-+/():!^&'~{}<>=€".indexOf(c) === -1)
|
||||
throw 'unrecognized character ' + fmt[i] + ' in ' + fmt;
|
||||
out.push({t:'t', v:c}); ++i; break;
|
||||
}
|
||||
@ -362,21 +366,20 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
/* replace fields */
|
||||
for(i=0; i < out.length; ++i) {
|
||||
switch(out[i].t) {
|
||||
case 't': case 'T': case ' ': break;
|
||||
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'A': case 'e': case 'Z':
|
||||
case 't': case 'T': case ' ': case 'D': break;
|
||||
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'Z':
|
||||
out[i].v = write_date(out[i].t, out[i].v, dt);
|
||||
out[i].t = 't'; break;
|
||||
case 'n': case '(': case '?':
|
||||
var jj = i+1;
|
||||
while(out[jj] && ("?D".indexOf(out[jj].t) > -1 || (" t".indexOf(out[jj].t) > -1 && "?t".indexOf((out[jj+1]||{}).t)>-1 && (out[jj+1].t == '?' || out[jj+1].v == '/')) || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || out[jj].v == '$' || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
|
||||
while(out[jj] && ("?D".indexOf(out[jj].t) > -1 || (" t".indexOf(out[jj].t) > -1 && "?t".indexOf((out[jj+1]||{}).t)>-1 && (out[jj+1].t == '?' || out[jj+1].v == '/')) || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || '$€'.indexOf(out[jj].v) > -1 || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
|
||||
out[i].v += out[jj].v;
|
||||
delete out[jj]; ++jj;
|
||||
}
|
||||
out[i].v = write_num(out[i].t, out[i].v, v);
|
||||
out[i].v = write_num(out[i].t, out[i].v, (flen >1 && v < 0 && i>0 && out[i-1].v == "-" ? -v:v));
|
||||
out[i].t = 't';
|
||||
i = jj-1; break;
|
||||
case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
|
||||
default: console.error(out); throw "unrecognized type " + out[i].t;
|
||||
}
|
||||
}
|
||||
return out.map(function(x){return x.v;}).join("");
|
||||
@ -386,6 +389,7 @@ function choose_fmt(fmt, v, o) {
|
||||
if(typeof fmt === 'number') fmt = ((o&&o.table) ? o.table : table_fmt)[fmt];
|
||||
if(typeof fmt === "string") fmt = split_fmt(fmt);
|
||||
var l = fmt.length;
|
||||
if(l<4 && fmt[l-1].indexOf("@")>-1) --l;
|
||||
switch(fmt.length) {
|
||||
case 1: fmt = fmt[0].indexOf("@")>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
|
||||
case 2: fmt = fmt[1].indexOf("@")>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
|
||||
|
@ -1 +1 @@
|
||||
XLSX.version = '0.5.3';
|
||||
XLSX.version = '0.5.4';
|
||||
|
@ -16,40 +16,9 @@ function readIEEE754(buf, idx, isLE, nl, ml) {
|
||||
return (s ? -1 : 1) * m * Math.pow(2, e - ml);
|
||||
}
|
||||
|
||||
function s2a(s) {
|
||||
if(typeof Buffer !== 'undefined') return new Buffer(s, "binary");
|
||||
var w = s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
|
||||
return w;
|
||||
}
|
||||
|
||||
var __toBuffer;
|
||||
if(typeof Buffer !== "undefined") {
|
||||
Buffer.prototype.hexlify= function() { return this.toString('hex'); };
|
||||
Buffer.prototype.utf16le= function(s,e){return this.toString('utf16le',s,e).replace(/\u0000/,'').replace(/[\u0001-\u0006]/,'!');};
|
||||
Buffer.prototype.utf8 = function(s,e) { return this.toString('utf8',s,e); };
|
||||
Buffer.prototype.lpstr = function(i) { var len = this.readUInt32LE(i); return len > 0 ? this.utf8(i+4,i+4+len-1) : "";};
|
||||
Buffer.prototype.lpwstr = function(i) { var len = 2*this.readUInt32LE(i); return this.utf8(i+4,i+4+len-1);};
|
||||
if(typeof cptable !== "undefined") Buffer.prototype.lpstr = function(i) {
|
||||
var len = this.readUInt32LE(i);
|
||||
if(len === 0) return "";
|
||||
if(typeof current_cptable === "undefined") return this.utf8(i+4,i+4+len-1);
|
||||
var t = Array(this.slice(i+4,i+4+len-1));
|
||||
//1console.log("start", this.l, len, t);
|
||||
var c, j = i+4, o = "", cc;
|
||||
for(;j!=i+4+len;++j) {
|
||||
c = this.readUInt8(j);
|
||||
cc = current_cptable.dec[c];
|
||||
if(typeof cc === 'undefined') {
|
||||
c = c*256 + this.readUInt8(++j);
|
||||
cc = current_cptable.dec[c];
|
||||
}
|
||||
if(typeof cc === 'undefined') throw "Unrecognized character " + c.toString(16);
|
||||
if(c === 0) break;
|
||||
o += cc;
|
||||
//1console.log(cc, cc.charCodeAt(0), o, this.l);
|
||||
}
|
||||
return o;
|
||||
};
|
||||
__toBuffer = function(bufs) { return Buffer.concat(bufs[0]); };
|
||||
} else {
|
||||
__toBuffer = function(bufs) {
|
||||
@ -66,16 +35,6 @@ var __readUInt32LE = function(b, idx) { return b.readUInt32LE ? b.readUInt32LE(i
|
||||
var __readInt32LE = function(b, idx) { if(b.readInt32LE) return b.readInt32LE(idx); var u = __readUInt32LE(b,idx); if(!(u & 0x80000000)) return u; return (0xffffffff - u + 1) * -1; };
|
||||
var __readDoubleLE = function(b, idx) { return b.readDoubleLE ? b.readDoubleLE(idx) : readIEEE754(b, idx||0);};
|
||||
|
||||
var __hexlify = function(b) { return b.map(function(x){return (x<16?"0":"") + x.toString(16);}).join(""); };
|
||||
|
||||
var __utf16le = function(b,s,e) { if(b.utf16le) return b.utf16le(s,e); var str = ""; for(var i=s; i<e; i+=2) str += String.fromCharCode(__readUInt16LE(b,i)); return str.replace(/\u0000/,'').replace(/[\u0001-\u0006]/,'!'); };
|
||||
|
||||
var __utf8 = function(b,s,e) { if(b.utf8) return b.utf8(s,e); var str = ""; for(var i=s; i<e; i++) str += String.fromCharCode(__readUInt8(b,i)); return str; };
|
||||
|
||||
var __lpstr = function(b,i) { if(b.lpstr) return b.lpstr(i); var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
|
||||
var __lpwstr = function(b,i) { if(b.lpwstr) return b.lpwstr(i); var len = 2*__readUInt32LE(b,i); return __utf8(b, i+4,i+4+len-1);};
|
||||
|
||||
function bconcat(bufs) { return (typeof Buffer !== 'undefined') ? Buffer.concat(bufs) : [].concat.apply([], bufs); }
|
||||
|
||||
function ReadShift(size, t) {
|
||||
var o, w, vv, i, loc; t = t || 'u';
|
||||
@ -88,46 +47,19 @@ function ReadShift(size, t) {
|
||||
/* falls through */
|
||||
case 16: o = this.toString('hex', this.l,this.l+size); break;
|
||||
|
||||
case 'utf8': size = t; o = __utf8(this, this.l, this.l + size); break;
|
||||
case 'utf16le': size=2*t; o = __utf16le(this, this.l, this.l + size); break;
|
||||
|
||||
/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
|
||||
case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break;
|
||||
|
||||
case 'lpwstr': o = __lpwstr(this, this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break;
|
||||
|
||||
/* sbcs and dbcs support continue records in the SST way TODO codepages */
|
||||
/* TODO: DBCS http://msdn.microsoft.com/en-us/library/cc194788.aspx */
|
||||
case 'dbcs': size = 2*t; o = ""; loc = this.l;
|
||||
for(i = 0; i != t; ++i) {
|
||||
if(this.lens && this.lens.indexOf(loc) !== -1) {
|
||||
w = __readUInt8(this, loc);
|
||||
this.l = loc + 1;
|
||||
vv = ReadShift.call(this, w ? 'dbcs' : 'sbcs', t-i);
|
||||
return o + vv;
|
||||
}
|
||||
o += _getchar(__readUInt16LE(this, loc));
|
||||
loc+=2;
|
||||
} break;
|
||||
|
||||
case 'sbcs': size = t; o = ""; loc = this.l;
|
||||
for(i = 0; i != t; ++i) {
|
||||
if(this.lens && this.lens.indexOf(loc) !== -1) {
|
||||
w = __readUInt8(this, loc);
|
||||
this.l = loc + 1;
|
||||
vv = ReadShift.call(this, w ? 'dbcs' : 'sbcs', t-i);
|
||||
return o + vv;
|
||||
}
|
||||
o += _getchar(__readUInt8(this, loc));
|
||||
loc+=1;
|
||||
} break;
|
||||
|
||||
case 'cstr': size = 0; o = "";
|
||||
while((w=__readUInt8(this, this.l + size++))!==0) o+= _getchar(w);
|
||||
break;
|
||||
case 'wstr': size = 0; o = "";
|
||||
while((w=__readUInt16LE(this,this.l +size))!==0){o+= _getchar(w);size+=2;}
|
||||
size+=2; break;
|
||||
}
|
||||
this.l+=size; return o;
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ var recordhopper = function(data, cb) {
|
||||
var RT = data.read_shift(1);
|
||||
if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
|
||||
var R = RecordEnum[RT] || RecordEnum[0xFFFF];
|
||||
length = tmpbyte = data.read_shift(1);
|
||||
tmpbyte = data.read_shift(1);
|
||||
length = tmpbyte & 0x7F;
|
||||
for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
|
||||
var d = R.f(data, length);
|
||||
if(cb(d, R, RT)) return;
|
||||
|
@ -1,9 +1,16 @@
|
||||
|
||||
/* [MS-XLSB] 2.5.143 */
|
||||
var parse_StrRun = function(data, length) {
|
||||
return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.121 */
|
||||
var parse_RichStr = function(data, length) {
|
||||
var start = data.l;
|
||||
var flags = data.read_shift(1);
|
||||
var fRichStr = flags & 1, fExtStr = flags & 2;
|
||||
var str = parse_XLWideString(data);
|
||||
var rgsStrRun = [];
|
||||
var z = {
|
||||
t: str,
|
||||
r:"<t>" + escapexml(str) + "</t>",
|
||||
@ -12,6 +19,7 @@ var parse_RichStr = function(data, length) {
|
||||
if(fRichStr) {
|
||||
/* TODO: formatted string */
|
||||
var dwSizeStrRun = data.read_shift(4);
|
||||
for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
|
||||
}
|
||||
if(fExtStr) {
|
||||
/* TODO: phonetic string */
|
||||
|
@ -105,7 +105,8 @@ var parse_rs = (function() {
|
||||
})();
|
||||
|
||||
/* 18.4.8 si CT_Rst */
|
||||
var parse_si = function(x) {
|
||||
var parse_si = function(x, opts) {
|
||||
var html = opts ? opts.cellHTML : true;
|
||||
var z = {};
|
||||
if(!x) return null;
|
||||
var y;
|
||||
@ -113,14 +114,14 @@ var parse_si = function(x) {
|
||||
if(x[1] === 't') {
|
||||
z.t = utf8read(unescapexml(x.substr(x.indexOf(">")+1).split(/<\/t>/)[0]));
|
||||
z.r = x;
|
||||
z.h = z.t;
|
||||
if(html) z.h = z.t;
|
||||
}
|
||||
/* 18.4.4 r CT_RElt (Rich Text Run) */
|
||||
else if((y = x.match(/<r>/))) {
|
||||
z.r = x;
|
||||
/* TODO: properly parse (note: no other valid child can have body text) */
|
||||
z.t = utf8read(unescapexml(x.replace(/<[^>]*>/gm,"")));
|
||||
z.h = parse_rs(x);
|
||||
if(html) z.h = parse_rs(x);
|
||||
}
|
||||
/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
|
||||
/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
|
||||
@ -128,12 +129,12 @@ var parse_si = function(x) {
|
||||
};
|
||||
|
||||
/* 18.4 Shared String Table */
|
||||
var parse_sst_xml = function(data) {
|
||||
var parse_sst_xml = function(data, opts) {
|
||||
var s = [];
|
||||
/* 18.4.9 sst CT_Sst */
|
||||
var sst = data.match(new RegExp("<sst([^>]*)>([\\s\\S]*)<\/sst>","m"));
|
||||
if(isval(sst)) {
|
||||
s = sst[2].replace(/<(?:si|sstItem)>/g,"").split(/<\/(?:si|sstItem)>/).map(parse_si).filter(function(x) { return x; });
|
||||
s = sst[2].replace(/<(?:si|sstItem)>/g,"").split(/<\/(?:si|sstItem)>/).map(function(x) { return parse_si(x, opts); }).filter(function(x) { return x; });
|
||||
sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
|
||||
}
|
||||
return s;
|
||||
|
@ -1,4 +0,0 @@
|
||||
|
||||
var parse_sst = function(data, name) {
|
||||
return name.substr(-4)===".bin" ? parse_sst_bin(data) : parse_sst_xml(data);
|
||||
};
|
@ -1,8 +1,6 @@
|
||||
/* 18.7.3 CT_Comment */
|
||||
function parseComments(data) {
|
||||
if(data.match(/<comments *\/>/)) {
|
||||
throw new Error('Not a valid comments xml');
|
||||
}
|
||||
function parse_comments_xml(data, opts) {
|
||||
if(data.match(/<comments *\/>/)) return [];
|
||||
var authors = [];
|
||||
var commentList = [];
|
||||
data.match(/<authors>([^\u2603]*)<\/authors>/m)[1].split('</author>').forEach(function(x) {
|
||||
@ -18,26 +16,24 @@ function parseComments(data) {
|
||||
var rt = parse_si(textMatch[1]);
|
||||
comment.r = rt.r;
|
||||
comment.t = rt.t;
|
||||
comment.h = rt.h;
|
||||
if(opts.cellHTML) comment.h = rt.h;
|
||||
commentList.push(comment);
|
||||
});
|
||||
return commentList;
|
||||
}
|
||||
|
||||
function parseCommentsAddToSheets(zip, dirComments, sheets, sheetRels) {
|
||||
function parse_comments(zip, dirComments, sheets, sheetRels, opts) {
|
||||
for(var i = 0; i != dirComments.length; ++i) {
|
||||
var canonicalpath=dirComments[i];
|
||||
var comments=parseComments(getdata(getzipfile(zip, canonicalpath.replace(/^\//,''))));
|
||||
var comments=parse_comments_xml(getdata(getzipfile(zip, canonicalpath.replace(/^\//,''))), opts);
|
||||
// find the sheets targeted by these comments
|
||||
var sheetNames = Object.keys(sheets);
|
||||
for(var j = 0; j != sheetNames.length; ++j) {
|
||||
var sheetName = sheetNames[j];
|
||||
var rels = sheetRels[sheetName];
|
||||
if (rels) {
|
||||
if(rels) {
|
||||
var rel = rels[canonicalpath];
|
||||
if (rel) {
|
||||
insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
|
||||
}
|
||||
if(rel) insertCommentsIntoSheet(sheetName, sheets[sheetName], comments);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -59,10 +55,10 @@ function insertCommentsIntoSheet(sheetName, sheet, comments) {
|
||||
if (encoded !== sheet["!ref"]) sheet["!ref"] = encoded;
|
||||
}
|
||||
|
||||
if (!cell.c) {
|
||||
cell.c = [];
|
||||
}
|
||||
cell.c.push({a: comment.author, t: comment.t, r: comment.r, h: comment.h});
|
||||
if (!cell.c) cell.c = [];
|
||||
var o = {a: comment.author, t: comment.t, r: comment.r};
|
||||
if(comment.h) o.h = comment.h;
|
||||
cell.c.push(o);
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -37,7 +37,7 @@ function parse_ws_xml(data, opts) {
|
||||
|
||||
/* SCHEMA IS ACTUALLY INCORRECT HERE. IF A CELL HAS NO T, EMIT "" */
|
||||
if(cell.t === undefined && p.v === undefined) {
|
||||
if(!opts.sheetEmptyCells) return;
|
||||
if(!opts.sheetStubs) return;
|
||||
p.t = "str"; p.v = undefined;
|
||||
}
|
||||
else p.t = (cell.t ? cell.t : "n"); // default is "n" in schema
|
||||
@ -49,7 +49,7 @@ function parse_ws_xml(data, opts) {
|
||||
sidx = parseInt(p.v, 10);
|
||||
p.v = strs[sidx].t;
|
||||
p.r = strs[sidx].r;
|
||||
p.h = strs[sidx].h;
|
||||
if(opts.cellHTML) p.h = strs[sidx].h;
|
||||
} break;
|
||||
case 'str': if(p.v) p.v = utf8read(p.v); break;
|
||||
case 'inlineStr':
|
||||
|
@ -60,6 +60,14 @@ var parse_BrtCellSt = function(data, length) {
|
||||
return [cell, value, 'str'];
|
||||
};
|
||||
|
||||
/* [MS-XLSB] 2.4.647 BrtFmlaBool */
|
||||
var parse_BrtFmlaBool = function(data, length) {
|
||||
var cell = parse_Cell(data);
|
||||
var value = data.read_shift(1);
|
||||
data.l += length-9;
|
||||
return [cell, value, 'b' /*, formula */];
|
||||
};
|
||||
|
||||
/* [MS-XLSB] 2.4.648 BrtFmlaError */
|
||||
var parse_BrtFmlaError = function(data, length) {
|
||||
var cell = parse_Cell(data);
|
||||
@ -76,9 +84,16 @@ var parse_BrtFmlaNum = function(data, length) {
|
||||
return [cell, value, 'n' /*, formula */];
|
||||
};
|
||||
|
||||
/* [MS-XLSB] 2.4.650 BrtFmlaString */
|
||||
var parse_BrtFmlaString = function(data, length) {
|
||||
var start = data.l;
|
||||
var cell = parse_Cell(data);
|
||||
var value = parse_XLWideString(data);
|
||||
data.l = start + length;
|
||||
return [cell, value, 'str' /*, formula */];
|
||||
};
|
||||
|
||||
var parse_BrtCellBlank = parsenoop;
|
||||
var parse_BrtFmlaBool = parsenoop;
|
||||
var parse_BrtFmlaString = parsenoop;
|
||||
|
||||
/* [MS-XLSB] 2.1.7.61 Worksheet */
|
||||
var parse_ws_bin = function(data, opts) {
|
||||
@ -92,15 +107,12 @@ var parse_ws_bin = function(data, opts) {
|
||||
recordhopper(data, function(val, R) {
|
||||
switch(R.n) {
|
||||
case 'BrtWsDim': ref = val; break;
|
||||
case 'BrtRowHdr': row = val; break;
|
||||
|
||||
case 'BrtRowHdr':
|
||||
row = val;
|
||||
break; // TODO
|
||||
|
||||
case 'BrtFmlaError': break; // TODO
|
||||
case 'BrtFmlaString': break; // TODO
|
||||
case 'BrtFmlaBool': break; // TODO
|
||||
case 'BrtFmlaBool':
|
||||
case 'BrtFmlaError':
|
||||
case 'BrtFmlaNum':
|
||||
case 'BrtFmlaString':
|
||||
case 'BrtCellBool':
|
||||
case 'BrtCellError':
|
||||
case 'BrtCellIsst':
|
||||
@ -112,9 +124,9 @@ var parse_ws_bin = function(data, opts) {
|
||||
case 's': p.v = strs[val[1]].t; p.r = strs[val[1]].r; break;
|
||||
case 'b': p.v = val[1] ? true : false; break;
|
||||
case 'e': p.raw = val[1]; p.v = BErr[p.raw]; break;
|
||||
case 'str': if(p.v) p.v = utf8read(p.v); break;
|
||||
case 'str': p.v = utf8read(val[1]); break;
|
||||
}
|
||||
if(val[3]) p.f = val[3];
|
||||
if(val[3] && opts.cellFormula) p.f = val[3];
|
||||
if((cf = styles.CellXf[val[0].iStyleRef])) try {
|
||||
p.w = SSF.format(cf.ifmt,p.v,_ssfopts);
|
||||
if(opts.cellNF) p.z = SSF._table[cf.ifmt];
|
||||
|
@ -9,3 +9,7 @@ function parse_ws(data, name, opts) {
|
||||
function parse_sty(data, name, opts) {
|
||||
return name.substr(-4)===".bin" ? parse_sty_bin(data, opts) : parse_sty_xml(data, opts);
|
||||
}
|
||||
|
||||
function parse_sst(data, name, opts) {
|
||||
return name.substr(-4)===".bin" ? parse_sst_bin(data, opts) : parse_sst_xml(data, opts);
|
||||
}
|
||||
|
@ -1,8 +1,10 @@
|
||||
function fixopts(opts) {
|
||||
var defaults = [
|
||||
['cellNF', false], /* emit cell number format string as .z */
|
||||
['cellHTML', true], /* emit html string as .h */
|
||||
['cellFormula', true], /* emit formulae as .h */
|
||||
|
||||
['sheetStubs', true], /* emit empty cells */
|
||||
['sheetStubs', false], /* emit empty cells */
|
||||
|
||||
['WTF', false] /* WTF mode (do not use) */
|
||||
];
|
||||
|
@ -13,7 +13,7 @@ function parseZip(zip, opts) {
|
||||
xlsb = true;
|
||||
}
|
||||
strs = {};
|
||||
if(dir.sst) strs=parse_sst(getdata(getzipfile(zip, dir.sst.replace(/^\//,''))), dir.sst);
|
||||
if(dir.sst) strs=parse_sst(getdata(getzipfile(zip, dir.sst.replace(/^\//,''))), dir.sst, opts);
|
||||
|
||||
styles = {};
|
||||
if(dir.style) styles = parse_sty(getdata(getzipfile(zip, dir.style.replace(/^\//,''))),dir.style);
|
||||
@ -58,7 +58,7 @@ function parseZip(zip, opts) {
|
||||
}
|
||||
}
|
||||
|
||||
if(dir.comments) parseCommentsAddToSheets(zip, dir.comments, sheets, sheetRels);
|
||||
if(dir.comments) parse_comments(zip, dir.comments, sheets, sheetRels, opts);
|
||||
|
||||
return {
|
||||
Directory: dir,
|
||||
|
@ -12,7 +12,7 @@ function decode_range(range) { var x =range.split(":").map(decode_cell); return
|
||||
function encode_range(range) { return encode_cell(range.s) + ":" + encode_cell(range.e); }
|
||||
|
||||
function sheet_to_row_object_array(sheet, opts){
|
||||
var val, row, r, hdr = {}, isempty, R, C, v;
|
||||
var val, row, r, hdr = {}, isempty, R, C;
|
||||
var out = [];
|
||||
opts = opts || {};
|
||||
if(!sheet || !sheet["!ref"]) return out;
|
||||
@ -54,12 +54,10 @@ function sheet_to_row_object_array(sheet, opts){
|
||||
function sheet_to_csv(sheet, opts) {
|
||||
var stringify = function stringify(val) {
|
||||
if(!val.t) return "";
|
||||
if(typeof val.w !== 'undefined') return '"' + val.w.replace(/"/,'""') + '"';
|
||||
if(typeof val.w !== 'undefined') return val.w;
|
||||
switch(val.t){
|
||||
case 'n': return String(val.v);
|
||||
case 's': case 'str':
|
||||
if(typeof val.v === 'undefined') return "";
|
||||
return '"' + val.v.replace(/"/,'""') + '"';
|
||||
case 's': case 'str': return typeof val.v !== 'undefined' ? val.v : "";
|
||||
case 'b': return val.v ? "TRUE" : "FALSE";
|
||||
case 'e': return val.v; /* throw out value in case of error */
|
||||
default: throw 'unrecognized type ' + val.t;
|
||||
@ -69,15 +67,18 @@ function sheet_to_csv(sheet, opts) {
|
||||
opts = opts || {};
|
||||
if(!sheet || !sheet["!ref"]) return out;
|
||||
var r = XLSX.utils.decode_range(sheet["!ref"]);
|
||||
var fs = opts.FS||",", rs = opts.RS||"\n";
|
||||
for(var R = r.s.r; R <= r.e.r; ++R) {
|
||||
var row = [];
|
||||
for(var C = r.s.c; C <= r.e.c; ++C) {
|
||||
var val = sheet[XLSX.utils.encode_cell({c:C,r:R})];
|
||||
if(!val) { row.push(""); continue; }
|
||||
txt = stringify(val);
|
||||
row.push(String(txt).replace(/\\r\\n/g,"\n").replace(/\\t/g,"\t").replace(/\\\\/g,"\\").replace("\\\"","\"\""));
|
||||
txt = String(stringify(val));
|
||||
if(txt.indexOf(fs)!==-1 || txt.indexOf(rs)!==-1 || txt.indexOf('"')!==-1)
|
||||
txt = "\"" + txt.replace(/"/g, '""') + "\"";
|
||||
row.push(txt);
|
||||
}
|
||||
out += row.join(opts.FS||",") + (opts.RS||"\n");
|
||||
out += row.join(fs) + (rs);
|
||||
}
|
||||
return out;
|
||||
}
|
||||
|
@ -4,10 +4,4 @@ if(typeof require !== 'undefined' && typeof exports !== 'undefined') {
|
||||
exports.readFile = XLSX.readFile;
|
||||
exports.utils = XLSX.utils;
|
||||
exports.version = XLSX.version;
|
||||
exports.main = function(args) {
|
||||
var zip = XLSX.read(args[0], {type:'file'});
|
||||
console.log(zip.Sheets);
|
||||
};
|
||||
if(typeof module !== 'undefined' && require.main === module)
|
||||
exports.main(process.argv.slice(2));
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "xlsx",
|
||||
"version": "0.5.3",
|
||||
"version": "0.5.4",
|
||||
"author": "sheetjs",
|
||||
"description": "XLSB / XLSX / XLSM parser",
|
||||
"keywords": [ "xlsx", "xlsb", "xlsm", "office", "excel", "spreadsheet" ],
|
||||
@ -9,7 +9,7 @@
|
||||
},
|
||||
"main": "./xlsx",
|
||||
"dependencies": {
|
||||
"ssf":">=0.5.5",
|
||||
"ssf":"~0.5.6",
|
||||
"codepage":"",
|
||||
"jszip":"~2.1.0",
|
||||
"commander":""
|
||||
|
25
test.js
25
test.js
@ -4,7 +4,7 @@ var fs = require('fs'), assert = require('assert');
|
||||
describe('source',function(){ it('should load', function(){ XLSX = require('./'); });});
|
||||
|
||||
var ex = [".xlsb", ".xlsm", ".xlsx"];
|
||||
var exp = ex.map(function(x){ return x + ".pending"; });
|
||||
var exp = ex.map(function(x){ return x + ".pending"; });
|
||||
function test_file(x){return ex.indexOf(x.substr(-5))>=0||exp.indexOf(x.substr(-13))>=0;}
|
||||
|
||||
var files = (fs.existsSync('tests.lst') ? fs.readFileSync('tests.lst', 'utf-8').split("\n") : fs.readdirSync('test_files')).filter(test_file);
|
||||
@ -84,3 +84,26 @@ describe('should have comment as part of cell\'s properties', function(){
|
||||
assert.equal(ws.B1.c[0].a, "Yegor Kozlov","must have the same author");
|
||||
});
|
||||
});
|
||||
|
||||
describe('options', function() {
|
||||
var html_cell_types = ['s'];
|
||||
before(function() {
|
||||
XLSX = require('./');
|
||||
});
|
||||
it('should generate HTML by default', function() {
|
||||
var wb = XLSX.readFile('./test_files/comments_stress_test.xlsx');
|
||||
var ws = wb.Sheets.Sheet1;
|
||||
Object.keys(ws).forEach(function(addr) {
|
||||
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
|
||||
assert(html_cell_types.indexOf(ws[addr].t) === -1 || ws[addr].h);
|
||||
});
|
||||
});
|
||||
it('should not generate HTML when requested', function() {
|
||||
var wb = XLSX.readFile('./test_files/comments_stress_test.xlsx', {cellHTML: false});
|
||||
var ws = wb.Sheets.Sheet1;
|
||||
Object.keys(ws).forEach(function(addr) {
|
||||
if(addr[0] === "!" || !ws.hasOwnProperty(addr)) return;
|
||||
assert(typeof ws[addr].h === 'undefined');
|
||||
});
|
||||
});
|
||||
});
|
||||
|
@ -1,10 +1,16 @@
|
||||
RkNumber.xlsb
|
||||
comments_stress_test.xlsb
|
||||
formula_stress_test.xlsb
|
||||
large_strings.xlsb.pending
|
||||
merge_cells.xlsb
|
||||
named_ranges_2011.xlsb
|
||||
number_format.xlsb
|
||||
rich_text_stress.xlsb
|
||||
time_stress_test_1.xlsb
|
||||
LONumbers-2010.xlsx
|
||||
LONumbers-2011.xlsx
|
||||
LONumbers.xlsx
|
||||
RkNumber.xlsx
|
||||
apachepoi_45430.xlsx
|
||||
apachepoi_45540_classic_Footer.xlsx
|
||||
apachepoi_45540_classic_Header.xlsx
|
||||
@ -153,6 +159,7 @@ jxls-core_simple.xlsx
|
||||
jxls-examples_stress1.xlsx
|
||||
jxls-examples_stress2.xlsx
|
||||
jxls-reader_departmentData.xlsx
|
||||
large_strings.xlsx.pending
|
||||
merge_cells.xlsx
|
||||
mixed_sheets.xlsx
|
||||
named_ranges_2011.xlsx
|
||||
@ -166,6 +173,7 @@ openpyxl_g_empty_with_no_properties.xlsx
|
||||
openpyxl_g_guess_types.xlsx
|
||||
openpyxl_g_libreoffice_nrt.xlsx
|
||||
openpyxl_g_merge_range.xlsx
|
||||
openpyxl_r_bigfoot.xlsx.pending
|
||||
openpyxl_r_comments.xlsx
|
||||
openpyxl_r_complex-styles.xlsx
|
||||
openpyxl_r_conditional-formatting.xlsx
|
||||
|
@ -1 +1 @@
|
||||
Subproject commit a2d49d344622e1bd657f03e829c24d9b24a942af
|
||||
Subproject commit 709d865dc7f9d7173bc4b5f5c6b0c5aea945589c
|
235
xlsx.js
235
xlsx.js
@ -9,7 +9,7 @@ var _strrev = function(x) { return String(x).split("").reverse().join("");};
|
||||
function fill(c,l) { return new Array(l+1).join(c); }
|
||||
function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);}
|
||||
function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));}
|
||||
SSF.version = '0.5.4';
|
||||
SSF.version = '0.5.7';
|
||||
/* Options */
|
||||
var opts_fmt = {};
|
||||
function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
|
||||
@ -150,23 +150,20 @@ var write_date = function(type, fmt, val) {
|
||||
switch(type) {
|
||||
case 'y': switch(fmt) { /* year */
|
||||
case 'y': case 'yy': return pad(val.y % 100,2);
|
||||
case 'yyy': case 'yyyy': return pad(val.y % 10000,4);
|
||||
default: throw 'bad year format: ' + fmt;
|
||||
default: return pad(val.y % 10000,4);
|
||||
}
|
||||
case 'm': switch(fmt) { /* month */
|
||||
case 'm': return val.m;
|
||||
case 'mm': return pad(val.m,2);
|
||||
case 'mmm': return months[val.m-1][1];
|
||||
case 'mmmm': return months[val.m-1][2];
|
||||
case 'mmmmm': return months[val.m-1][0];
|
||||
default: throw 'bad month format: ' + fmt;
|
||||
default: return months[val.m-1][2];
|
||||
}
|
||||
case 'd': switch(fmt) { /* day */
|
||||
case 'd': return val.d;
|
||||
case 'dd': return pad(val.d,2);
|
||||
case 'ddd': return days[val.q][0];
|
||||
case 'dddd': return days[val.q][1];
|
||||
default: throw 'bad day format: ' + fmt;
|
||||
default: return days[val.q][1];
|
||||
}
|
||||
case 'h': switch(fmt) { /* 12-hour */
|
||||
case 'h': return 1+(val.H+11)%12;
|
||||
@ -199,7 +196,6 @@ var write_date = function(type, fmt, val) {
|
||||
} return fmt.length === 3 ? o : pad(o, 2);
|
||||
/* TODO: handle the ECMA spec format ee -> yy */
|
||||
case 'e': { return val.y; } break;
|
||||
default: throw 'bad format type ' + type + ' in ' + fmt;
|
||||
}
|
||||
};
|
||||
/*jshint +W086 */
|
||||
@ -215,14 +211,20 @@ var write_num = function(type, fmt, val) {
|
||||
if(mul !== 0) return write_num(type, fmt, val * Math.pow(10,2*mul)) + fill("%",mul);
|
||||
if(fmt.indexOf("E") > -1) {
|
||||
var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
|
||||
if(fmt == '##0.0E+0') {
|
||||
var period = fmt.length - 5;
|
||||
if(fmt.match(/^#+0.0E\+0$/)) {
|
||||
var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
|
||||
var ee = (Number(val.toExponential(0).substr(2+(val<0))))%period;
|
||||
if(ee < 0) ee += period;
|
||||
o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
|
||||
if(!o.match(/[Ee]/)) {
|
||||
var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
|
||||
if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
|
||||
else throw "missing E |" + o;
|
||||
else o += "E+" + (fakee - ee);
|
||||
while(o.substr(0,2) === "0.") {
|
||||
o = o[0] + o.substr(2,period) + "." + o.substr(2+period);
|
||||
o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
|
||||
}
|
||||
o = o.replace(/\+-/,"-");
|
||||
}
|
||||
o = o.replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,(period+ee)%period) + "." + $3.substr(ee) + "E"; });
|
||||
} else o = val.toExponential(idx);
|
||||
@ -237,6 +239,7 @@ var write_num = function(type, fmt, val) {
|
||||
var myn = (rnd - base*den), myd = den;
|
||||
return sign + (base?base:"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[4].length) : pad(myn,r[1].length," ") + r[2] + "/" + r[3] + pad(myd,r[4].length));
|
||||
}
|
||||
if(fmt.match(/^#+0+$/)) fmt = fmt.replace(/#/g,"");
|
||||
if(fmt.match(/^00+$/)) return (val<0?"-":"")+pad(Math.round(aval),fmt.length);
|
||||
if(fmt.match(/^[#?]+$/)) return String(Math.round(val)).replace(/^0$/,"");
|
||||
if((r = fmt.match(/^#*0+\.(0+)/))) {
|
||||
@ -326,7 +329,8 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
out.push(q); lst = c; break;
|
||||
case '[': /* TODO: Fix this -- ignore all conditionals and formatting */
|
||||
o = c;
|
||||
while(fmt[i++] !== ']') o += fmt[i];
|
||||
while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i];
|
||||
if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
|
||||
if(o.match(/\[[HhMmSs]*\]/)) {
|
||||
if(!dt) dt = parse_date_code(v, opts);
|
||||
if(!dt) return "";
|
||||
@ -347,7 +351,7 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
out.push({t:'D', v:o}); break;
|
||||
case ' ': out.push({t:c,v:c}); ++i; break;
|
||||
default:
|
||||
if(",$-+/():!^&'~{}<>=".indexOf(c) === -1)
|
||||
if(",$-+/():!^&'~{}<>=€".indexOf(c) === -1)
|
||||
throw 'unrecognized character ' + fmt[i] + ' in ' + fmt;
|
||||
out.push({t:'t', v:c}); ++i; break;
|
||||
}
|
||||
@ -365,21 +369,20 @@ function eval_fmt(fmt, v, opts, flen) {
|
||||
/* replace fields */
|
||||
for(i=0; i < out.length; ++i) {
|
||||
switch(out[i].t) {
|
||||
case 't': case 'T': case ' ': break;
|
||||
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'A': case 'e': case 'Z':
|
||||
case 't': case 'T': case ' ': case 'D': break;
|
||||
case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'Z':
|
||||
out[i].v = write_date(out[i].t, out[i].v, dt);
|
||||
out[i].t = 't'; break;
|
||||
case 'n': case '(': case '?':
|
||||
var jj = i+1;
|
||||
while(out[jj] && ("?D".indexOf(out[jj].t) > -1 || (" t".indexOf(out[jj].t) > -1 && "?t".indexOf((out[jj+1]||{}).t)>-1 && (out[jj+1].t == '?' || out[jj+1].v == '/')) || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || out[jj].v == '$' || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
|
||||
while(out[jj] && ("?D".indexOf(out[jj].t) > -1 || (" t".indexOf(out[jj].t) > -1 && "?t".indexOf((out[jj+1]||{}).t)>-1 && (out[jj+1].t == '?' || out[jj+1].v == '/')) || out[i].t == '(' && (out[jj].t == ')' || out[jj].t == 'n') || out[jj].t == 't' && (out[jj].v == '/' || '$€'.indexOf(out[jj].v) > -1 || (out[jj].v == ' ' && (out[jj+1]||{}).t == '?')))) {
|
||||
out[i].v += out[jj].v;
|
||||
delete out[jj]; ++jj;
|
||||
}
|
||||
out[i].v = write_num(out[i].t, out[i].v, v);
|
||||
out[i].v = write_num(out[i].t, out[i].v, (flen >1 && v < 0 && i>0 && out[i-1].v == "-" ? -v:v));
|
||||
out[i].t = 't';
|
||||
i = jj-1; break;
|
||||
case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
|
||||
default: console.error(out); throw "unrecognized type " + out[i].t;
|
||||
}
|
||||
}
|
||||
return out.map(function(x){return x.v;}).join("");
|
||||
@ -389,6 +392,7 @@ function choose_fmt(fmt, v, o) {
|
||||
if(typeof fmt === 'number') fmt = ((o&&o.table) ? o.table : table_fmt)[fmt];
|
||||
if(typeof fmt === "string") fmt = split_fmt(fmt);
|
||||
var l = fmt.length;
|
||||
if(l<4 && fmt[l-1].indexOf("@")>-1) --l;
|
||||
switch(fmt.length) {
|
||||
case 1: fmt = fmt[0].indexOf("@")>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
|
||||
case 2: fmt = fmt[1].indexOf("@")>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
|
||||
@ -420,7 +424,7 @@ SSF.load_table = function(tbl) { for(var i=0; i!=0x0188; ++i) if(tbl[i]) SSF.loa
|
||||
make_ssf(SSF);
|
||||
var XLSX = {};
|
||||
(function(XLSX){
|
||||
XLSX.version = '0.5.3';
|
||||
XLSX.version = '0.5.4';
|
||||
var current_codepage, current_cptable, cptable;
|
||||
if(typeof module !== "undefined" && typeof require !== 'undefined') {
|
||||
if(typeof cptable === 'undefined') cptable = require('codepage');
|
||||
@ -560,40 +564,9 @@ function readIEEE754(buf, idx, isLE, nl, ml) {
|
||||
return (s ? -1 : 1) * m * Math.pow(2, e - ml);
|
||||
}
|
||||
|
||||
function s2a(s) {
|
||||
if(typeof Buffer !== 'undefined') return new Buffer(s, "binary");
|
||||
var w = s.split("").map(function(x){ return x.charCodeAt(0) & 0xff; });
|
||||
return w;
|
||||
}
|
||||
|
||||
var __toBuffer;
|
||||
if(typeof Buffer !== "undefined") {
|
||||
Buffer.prototype.hexlify= function() { return this.toString('hex'); };
|
||||
Buffer.prototype.utf16le= function(s,e){return this.toString('utf16le',s,e).replace(/\u0000/,'').replace(/[\u0001-\u0006]/,'!');};
|
||||
Buffer.prototype.utf8 = function(s,e) { return this.toString('utf8',s,e); };
|
||||
Buffer.prototype.lpstr = function(i) { var len = this.readUInt32LE(i); return len > 0 ? this.utf8(i+4,i+4+len-1) : "";};
|
||||
Buffer.prototype.lpwstr = function(i) { var len = 2*this.readUInt32LE(i); return this.utf8(i+4,i+4+len-1);};
|
||||
if(typeof cptable !== "undefined") Buffer.prototype.lpstr = function(i) {
|
||||
var len = this.readUInt32LE(i);
|
||||
if(len === 0) return "";
|
||||
if(typeof current_cptable === "undefined") return this.utf8(i+4,i+4+len-1);
|
||||
var t = Array(this.slice(i+4,i+4+len-1));
|
||||
//1console.log("start", this.l, len, t);
|
||||
var c, j = i+4, o = "", cc;
|
||||
for(;j!=i+4+len;++j) {
|
||||
c = this.readUInt8(j);
|
||||
cc = current_cptable.dec[c];
|
||||
if(typeof cc === 'undefined') {
|
||||
c = c*256 + this.readUInt8(++j);
|
||||
cc = current_cptable.dec[c];
|
||||
}
|
||||
if(typeof cc === 'undefined') throw "Unrecognized character " + c.toString(16);
|
||||
if(c === 0) break;
|
||||
o += cc;
|
||||
//1console.log(cc, cc.charCodeAt(0), o, this.l);
|
||||
}
|
||||
return o;
|
||||
};
|
||||
__toBuffer = function(bufs) { return Buffer.concat(bufs[0]); };
|
||||
} else {
|
||||
__toBuffer = function(bufs) {
|
||||
@ -610,16 +583,6 @@ var __readUInt32LE = function(b, idx) { return b.readUInt32LE ? b.readUInt32LE(i
|
||||
var __readInt32LE = function(b, idx) { if(b.readInt32LE) return b.readInt32LE(idx); var u = __readUInt32LE(b,idx); if(!(u & 0x80000000)) return u; return (0xffffffff - u + 1) * -1; };
|
||||
var __readDoubleLE = function(b, idx) { return b.readDoubleLE ? b.readDoubleLE(idx) : readIEEE754(b, idx||0);};
|
||||
|
||||
var __hexlify = function(b) { return b.map(function(x){return (x<16?"0":"") + x.toString(16);}).join(""); };
|
||||
|
||||
var __utf16le = function(b,s,e) { if(b.utf16le) return b.utf16le(s,e); var str = ""; for(var i=s; i<e; i+=2) str += String.fromCharCode(__readUInt16LE(b,i)); return str.replace(/\u0000/,'').replace(/[\u0001-\u0006]/,'!'); };
|
||||
|
||||
var __utf8 = function(b,s,e) { if(b.utf8) return b.utf8(s,e); var str = ""; for(var i=s; i<e; i++) str += String.fromCharCode(__readUInt8(b,i)); return str; };
|
||||
|
||||
var __lpstr = function(b,i) { if(b.lpstr) return b.lpstr(i); var len = __readUInt32LE(b,i); return len > 0 ? __utf8(b, i+4,i+4+len-1) : "";};
|
||||
var __lpwstr = function(b,i) { if(b.lpwstr) return b.lpwstr(i); var len = 2*__readUInt32LE(b,i); return __utf8(b, i+4,i+4+len-1);};
|
||||
|
||||
function bconcat(bufs) { return (typeof Buffer !== 'undefined') ? Buffer.concat(bufs) : [].concat.apply([], bufs); }
|
||||
|
||||
function ReadShift(size, t) {
|
||||
var o, w, vv, i, loc; t = t || 'u';
|
||||
@ -632,46 +595,19 @@ function ReadShift(size, t) {
|
||||
/* falls through */
|
||||
case 16: o = this.toString('hex', this.l,this.l+size); break;
|
||||
|
||||
case 'utf8': size = t; o = __utf8(this, this.l, this.l + size); break;
|
||||
case 'utf16le': size=2*t; o = __utf16le(this, this.l, this.l + size); break;
|
||||
|
||||
/* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
|
||||
case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break;
|
||||
|
||||
case 'lpwstr': o = __lpwstr(this, this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break;
|
||||
|
||||
/* sbcs and dbcs support continue records in the SST way TODO codepages */
|
||||
/* TODO: DBCS http://msdn.microsoft.com/en-us/library/cc194788.aspx */
|
||||
case 'dbcs': size = 2*t; o = ""; loc = this.l;
|
||||
for(i = 0; i != t; ++i) {
|
||||
if(this.lens && this.lens.indexOf(loc) !== -1) {
|
||||
w = __readUInt8(this, loc);
|
||||
this.l = loc + 1;
|
||||
vv = ReadShift.call(this, w ? 'dbcs' : 'sbcs', t-i);
|
||||
return o + vv;
|
||||
}
|
||||
o += _getchar(__readUInt16LE(this, loc));
|
||||
loc+=2;
|
||||
} break;
|
||||
|
||||
case 'sbcs': size = t; o = ""; loc = this.l;
|
||||
for(i = 0; i != t; ++i) {
|
||||
if(this.lens && this.lens.indexOf(loc) !== -1) {
|
||||
w = __readUInt8(this, loc);
|
||||
this.l = loc + 1;
|
||||
vv = ReadShift.call(this, w ? 'dbcs' : 'sbcs', t-i);
|
||||
return o + vv;
|
||||
}
|
||||
o += _getchar(__readUInt8(this, loc));
|
||||
loc+=1;
|
||||
} break;
|
||||
|
||||
case 'cstr': size = 0; o = "";
|
||||
while((w=__readUInt8(this, this.l + size++))!==0) o+= _getchar(w);
|
||||
break;
|
||||
case 'wstr': size = 0; o = "";
|
||||
while((w=__readUInt16LE(this,this.l +size))!==0){o+= _getchar(w);size+=2;}
|
||||
size+=2; break;
|
||||
}
|
||||
this.l+=size; return o;
|
||||
}
|
||||
@ -692,18 +628,26 @@ var recordhopper = function(data, cb) {
|
||||
var RT = data.read_shift(1);
|
||||
if(RT & 0x80) RT = (RT & 0x7F) + ((data.read_shift(1) & 0x7F)<<7);
|
||||
var R = RecordEnum[RT] || RecordEnum[0xFFFF];
|
||||
length = tmpbyte = data.read_shift(1);
|
||||
tmpbyte = data.read_shift(1);
|
||||
length = tmpbyte & 0x7F;
|
||||
for(cntbyte = 1; cntbyte <4 && (tmpbyte & 0x80); ++cntbyte) length += ((tmpbyte = data.read_shift(1)) & 0x7F)<<(7*cntbyte);
|
||||
var d = R.f(data, length);
|
||||
if(cb(d, R, RT)) return;
|
||||
}
|
||||
};
|
||||
|
||||
/* [MS-XLSB] 2.5.143 */
|
||||
var parse_StrRun = function(data, length) {
|
||||
return { ich: data.read_shift(2), ifnt: data.read_shift(2) };
|
||||
}
|
||||
|
||||
/* [MS-XLSB] 2.1.7.121 */
|
||||
var parse_RichStr = function(data, length) {
|
||||
var start = data.l;
|
||||
var flags = data.read_shift(1);
|
||||
var fRichStr = flags & 1, fExtStr = flags & 2;
|
||||
var str = parse_XLWideString(data);
|
||||
var rgsStrRun = [];
|
||||
var z = {
|
||||
t: str,
|
||||
r:"<t>" + escapexml(str) + "</t>",
|
||||
@ -712,6 +656,7 @@ var parse_RichStr = function(data, length) {
|
||||
if(fRichStr) {
|
||||
/* TODO: formatted string */
|
||||
var dwSizeStrRun = data.read_shift(4);
|
||||
for(var i = 0; i != dwSizeStrRun; ++i) rgsStrRun.push(parse_StrRun(data));
|
||||
}
|
||||
if(fExtStr) {
|
||||
/* TODO: phonetic string */
|
||||
@ -891,7 +836,8 @@ var parse_rs = (function() {
|
||||
})();
|
||||
|
||||
/* 18.4.8 si CT_Rst */
|
||||
var parse_si = function(x) {
|
||||
var parse_si = function(x, opts) {
|
||||
var html = opts ? opts.cellHTML : true;
|
||||
var z = {};
|
||||
if(!x) return null;
|
||||
var y;
|
||||
@ -899,14 +845,14 @@ var parse_si = function(x) {
|
||||
if(x[1] === 't') {
|
||||
z.t = utf8read(unescapexml(x.substr(x.indexOf(">")+1).split(/<\/t>/)[0]));
|
||||
z.r = x;
|
||||
z.h = z.t;
|
||||
if(html) z.h = z.t;
|
||||
}
|
||||
/* 18.4.4 r CT_RElt (Rich Text Run) */
|
||||
else if((y = x.match(/<r>/))) {
|
||||
z.r = x;
|
||||
/* TODO: properly parse (note: no other valid child can have body text) */
|
||||
z.t = utf8read(unescapexml(x.replace(/<[^>]*>/gm,"")));
|
||||
z.h = parse_rs(x);
|
||||
if(html) z.h = parse_rs(x);
|
||||
}
|
||||
/* 18.4.3 phoneticPr CT_PhoneticPr (TODO: needed for Asian support) */
|
||||
/* 18.4.6 rPh CT_PhoneticRun (TODO: needed for Asian support) */
|
||||
@ -914,12 +860,12 @@ var parse_si = function(x) {
|
||||
};
|
||||
|
||||
/* 18.4 Shared String Table */
|
||||
var parse_sst_xml = function(data) {
|
||||
var parse_sst_xml = function(data, opts) {
|
||||
var s = [];
|
||||
/* 18.4.9 sst CT_Sst */
|
||||
var sst = data.match(new RegExp("<sst([^>]*)>([\\s\\S]*)<\/sst>","m"));
|
||||
if(isval(sst)) {
|
||||
s = sst[2].replace(/<(?:si|sstItem)>/g,"").split(/<\/(?:si|sstItem)>/).map(parse_si).filter(function(x) { return x; });
|
||||
s = sst[2].replace(/<(?:si|sstItem)>/g,"").split(/<\/(?:si|sstItem)>/).map(function(x) { return parse_si(x, opts); }).filter(function(x) { return x; });
|
||||
sst = parsexmltag(sst[1]); s.Count = sst.count; s.Unique = sst.uniqueCount;
|
||||
}
|
||||
return s;
|
||||
@ -943,10 +889,6 @@ var parse_sst_bin = function(data) {
|
||||