js-xls-rails 0.5.0 → 0.6.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: e52ed40aeb2c846ad73d0768f4991f6787bcb29e
4
- data.tar.gz: 31a8c821c07e70e54098e846a770a0651ba1209e
3
+ metadata.gz: 92c7ac66d0955c7a92d4aaea434b283a4fac8171
4
+ data.tar.gz: 3a053528aeb1d0fca9665a906a8201dd23895db2
5
5
  SHA512:
6
- metadata.gz: 848731767864e368d3d3b6f267aae3317db16d4a5a18222acfad33b250443903fe07b7f9dc523bf917f54e137fc1c6b12e683a4fc7523e12a7834e9839b015af
7
- data.tar.gz: 0fb9156551c66343a4aaed33379176f17c93dd601a470834b886f13d836e24e4ab21d4de7c9b6da3482259998cf8bbe36ae2b97fee9e8b976f4d80cbc03ee84e
6
+ metadata.gz: 1967ca1d89c011d4677adb481e93382c06510124d239c67e55e8f30289a806d5806b649be57a566d7d175ce9b56f820e10da71a096624a62d214d71b343b79c4
7
+ data.tar.gz: f4f7741e282d3bd7446f6f64ee314a0e9cdc7dcc81bb43dc5c892034295a0fa34bb5d4fa3572ae3243e175e90633b00f2512f7d89b428ed8e8379eaf3a2fe5b0
@@ -1,5 +1,5 @@
1
1
  module Jsxls
2
2
  module Rails
3
- VERSION = "0.5.0"
3
+ VERSION = "0.6.9"
4
4
  end
5
5
  end
@@ -1,8 +1,9 @@
1
- /* xls.js (C) 2013 SheetJS -- http://sheetjs.com */
1
+ /* xls.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
2
2
  /* vim: set ts=2: */
3
3
  /*jshint eqnull:true, funcscope:true */
4
4
  var XLS = {};
5
5
  (function(XLS){
6
+ XLS.version = '0.6.9';
6
7
  if(typeof module !== "undefined" && typeof require !== 'undefined') {
7
8
  if(typeof cptable === 'undefined') var cptable = require('codepage');
8
9
  var current_codepage = 1252, current_cptable = cptable[1252];
@@ -12,41 +13,8 @@ function reset_cp() {
12
13
  }
13
14
  function _getchar(x) { return String.fromCharCode(x); }
14
15
 
15
- /* Buffer.concat was added in the 0.8 series, so this is for older versions */
16
- if(typeof Buffer !== "undefined" && !Buffer.concat)
17
- Buffer.concat = function(list, length) {
18
- if (!Array.isArray(list)) {
19
- throw new TypeError('Usage: Buffer.concat(list, [length])');
20
- }
21
-
22
- if (list.length === 0) {
23
- return new Buffer(0);
24
- } else if (list.length === 1) {
25
- return list[0];
26
- }
27
- var i, buf;
28
- if (typeof length !== 'number') {
29
- length = 0;
30
- for (i = 0; i < list.length; i++) {
31
- buf = list[i];
32
- length += buf.length;
33
- }
34
- }
35
-
36
- var buffer = new Buffer(length);
37
- var pos = 0;
38
- for (i = 0; i < list.length; i++) {
39
- buf = list[i];
40
- buf.copy(buffer, pos);
41
- pos += buf.length;
42
- }
43
- return buffer;
44
- };
45
-
46
- var Buffers = Array;
47
-
48
16
  function readIEEE754(buf, idx, isLE, nl, ml) {
49
- if(isLE === undefined) isLE = true;
17
+ if(typeof isLE === 'undefined') isLE = true;
50
18
  if(!nl) nl = 8;
51
19
  if(!ml && nl === 8) ml = 52;
52
20
  var e, m, el = nl * 8 - ml - 1, eMax = (1 << el) - 1, eBias = eMax >> 1;
@@ -111,6 +79,7 @@ function s2a(s) {
111
79
  return w;
112
80
  }
113
81
 
82
+ var __toBuffer;
114
83
  if(typeof Buffer !== "undefined") {
115
84
  Buffer.prototype.hexlify= function() { return this.toString('hex'); };
116
85
  Buffer.prototype.utf16le= function(s,e){return this.toString('utf16le',s,e).replace(/\u0000/,'').replace(/[\u0001-\u0006]/,'!');};
@@ -122,7 +91,6 @@ if(typeof Buffer !== "undefined") {
122
91
  if(len === 0) return "";
123
92
  if(typeof current_cptable === "undefined") return this.utf8(i+4,i+4+len-1);
124
93
  var t = Array(this.slice(i+4,i+4+len-1));
125
- //1console.log("start", this.l, len, t);
126
94
  var c, j = i+4, o = "", cc;
127
95
  for(;j!=i+4+len;++j) {
128
96
  c = this.readUInt8(j);
@@ -134,27 +102,33 @@ if(typeof Buffer !== "undefined") {
134
102
  if(typeof cc === 'undefined') throw "Unrecognized character " + c.toString(16);
135
103
  if(c === 0) break;
136
104
  o += cc;
137
- //1console.log(cc, cc.charCodeAt(0), o, this.l);
138
105
  }
139
106
  return o;
140
107
  };
108
+ __toBuffer = function(bufs) { return Buffer.concat(bufs[0]); };
109
+ } else {
110
+ __toBuffer = function(bufs) {
111
+ var x = [];
112
+ for(var i = 0; i != bufs[0].length; ++i) { x = x.concat(bufs[0][i]); }
113
+ return x;
114
+ };
141
115
  }
142
116
 
143
- Array.prototype.readUInt8 = function(idx) { return this[idx]; };
144
- Array.prototype.readUInt16LE = function(idx) { return this[idx+1]*(1<<8)+this[idx]; };
145
- Array.prototype.readInt16LE = function(idx) { var u = this.readUInt16LE(idx); if(!(u & 0x8000)) return u; return (0xffff - u + 1) * -1; };
146
- Array.prototype.readUInt32LE = function(idx) { return this[idx+3]*(1<<24)+this[idx+2]*(1<<16)+this[idx+1]*(1<<8)+this[idx]; };
147
- Array.prototype.readInt32LE = function(idx) { var u = this.readUInt32LE(idx); if(!(u & 0x80000000)) return u; return (0xffffffff - u + 1) * -1; };
148
- Array.prototype.readDoubleLE = function(idx) { return readIEEE754(this, idx||0);};
117
+ var __readUInt8 = function(b, idx) { return b.readUInt8 ? b.readUInt8(idx) : b[idx]; };
118
+ var __readUInt16LE = function(b, idx) { return b.readUInt16LE ? b.readUInt16LE(idx) : b[idx+1]*(1<<8)+b[idx]; };
119
+ var __readInt16LE = function(b, idx) { var u = __readUInt16LE(b,idx); if(!(u & 0x8000)) return u; return (0xffff - u + 1) * -1; };
120
+ var __readUInt32LE = function(b, idx) { return b.readUInt32LE ? b.readUInt32LE(idx) : b[idx+3]*(1<<24)+b[idx+2]*(1<<16)+b[idx+1]*(1<<8)+b[idx]; };
121
+ 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; };
122
+ var __readDoubleLE = function(b, idx) { return b.readDoubleLE ? b.readDoubleLE(idx) : readIEEE754(b, idx||0);};
149
123
 
150
- Array.prototype.hexlify = function() { return this.map(function(x){return (x<16?"0":"") + x.toString(16);}).join(""); };
124
+ var __hexlify = function(b) { return b.map(function(x){return (x<16?"0":"") + x.toString(16);}).join(""); };
151
125
 
152
- Array.prototype.utf16le = function(s,e) { var str = ""; for(var i=s; i<e; i+=2) str += String.fromCharCode(this.readUInt16LE(i)); return str.replace(/\u0000/,'').replace(/[\u0001-\u0006]/,'!'); };
126
+ 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]/,'!'); };
153
127
 
154
- Array.prototype.utf8 = function(s,e) { var str = ""; for(var i=s; i<e; i++) str += String.fromCharCode(this.readUInt8(i)); return str; };
128
+ 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; };
155
129
 
156
- Array.prototype.lpstr = function(i) { var len = this.readUInt32LE(i); return len > 0 ? this.utf8(i+4,i+4+len-1) : "";};
157
- Array.prototype.lpwstr = function(i) { var len = 2*this.readUInt32LE(i); return this.utf8(i+4,i+4+len-1);};
130
+ 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) : "";};
131
+ 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);};
158
132
 
159
133
  function bconcat(bufs) { return (typeof Buffer !== 'undefined') ? Buffer.concat(bufs) : [].concat.apply([], bufs); }
160
134
 
@@ -162,69 +136,64 @@ function ReadShift(size, t) {
162
136
  var o, w, vv, i, loc; t = t || 'u';
163
137
  if(size === 'ieee754') { size = 8; t = 'f'; }
164
138
  switch(size) {
165
- case 1: o = this.readUInt8(this.l); break;
166
- case 2: o=t==='u'?this.readUInt16LE(this.l):this.readInt16LE(this.l);break;
167
- case 4: o = this.readUInt32LE(this.l); break;
168
- case 8: if(t === 'f') { o = this.readDoubleLE(this.l); break; }
139
+ case 1: o = __readUInt8(this, this.l); break;
140
+ case 2: o=(t==='u' ? __readUInt16LE : __readInt16LE)(this, this.l); break;
141
+ case 4: o = __readUInt32LE(this, this.l); break;
142
+ case 8: if(t === 'f') { o = __readDoubleLE(this, this.l); break; }
169
143
  /* falls through */
170
144
  case 16: o = this.toString('hex', this.l,this.l+size); break;
171
145
 
172
- case 'utf8': size = t; o = this.utf8(this.l, this.l + size); break;
173
- case 'utf16le': size = 2*t; o = this.utf16le(this.l, this.l + size); break;
146
+ case 'utf8': size = t; o = __utf8(this, this.l, this.l + size); break;
147
+ case 'utf16le': size=2*t; o = __utf16le(this, this.l, this.l + size); break;
174
148
 
175
149
  /* [MS-OLEDS] 2.1.4 LengthPrefixedAnsiString */
176
- case 'lpstr': o = this.lpstr(this.l); size = 5 + o.length; break;
150
+ case 'lpstr': o = __lpstr(this, this.l); size = 5 + o.length; break;
177
151
 
178
- case 'lpwstr': o = this.lpwstr(this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break;
152
+ case 'lpwstr': o = __lpwstr(this, this.l); size = 5 + o.length; if(o[o.length-1] == '\u0000') size += 2; break;
179
153
 
180
154
  /* sbcs and dbcs support continue records in the SST way TODO codepages */
181
155
  /* TODO: DBCS http://msdn.microsoft.com/en-us/library/cc194788.aspx */
182
156
  case 'dbcs': size = 2*t; o = ""; loc = this.l;
183
157
  for(i = 0; i != t; ++i) {
184
158
  if(this.lens && this.lens.indexOf(loc) !== -1) {
185
- w = this.readUInt8(loc);
159
+ w = __readUInt8(this, loc);
186
160
  this.l = loc + 1;
187
161
  vv = ReadShift.call(this, w ? 'dbcs' : 'sbcs', t-i);
188
162
  return o + vv;
189
163
  }
190
- o += _getchar(this.readUInt16LE(loc));
164
+ o += _getchar(__readUInt16LE(this, loc));
191
165
  loc+=2;
192
166
  } break;
193
167
 
194
168
  case 'sbcs': size = t; o = ""; loc = this.l;
195
169
  for(i = 0; i != t; ++i) {
196
170
  if(this.lens && this.lens.indexOf(loc) !== -1) {
197
- w = this.readUInt8(loc);
171
+ w = __readUInt8(this, loc);
198
172
  this.l = loc + 1;
199
173
  vv = ReadShift.call(this, w ? 'dbcs' : 'sbcs', t-i);
200
174
  return o + vv;
201
175
  }
202
- o += _getchar(this.readUInt8(loc));
176
+ o += _getchar(__readUInt8(this, loc));
203
177
  loc+=1;
204
178
  } break;
205
179
 
206
180
  case 'cstr': size = 0; o = "";
207
- while((w=this.readUInt8(this.l + size++))!==0) o+= _getchar(w);
181
+ while((w=__readUInt8(this, this.l + size++))!==0) o+= _getchar(w);
208
182
  break;
209
183
  case 'wstr': size = 0; o = "";
210
- while((w=this.readUInt16LE(this.l +size))!==0){o+= _getchar(w);size+=2;}
184
+ while((w=__readUInt16LE(this,this.l +size))!==0){o+= _getchar(w);size+=2;}
211
185
  size+=2; break;
212
186
  }
213
187
  this.l+=size; return o;
214
188
  }
215
189
 
216
190
  function CheckField(hexstr, fld) {
217
- var m = this.slice(this.l, this.l+hexstr.length/2).hexlify('hex');
191
+ var b = this.slice(this.l, this.l+hexstr.length/2);
192
+ var m = b.hexlify ? b.hexlify() : __hexlify(b);
218
193
  if(m !== hexstr) throw (fld||"") + 'Expected ' + hexstr + ' saw ' + m;
219
194
  this.l += hexstr.length/2;
220
195
  }
221
196
 
222
- function WarnField(hexstr, fld) {
223
- var m = this.slice(this.l, this.l+hexstr.length/2).hexlify('hex');
224
- if(m !== hexstr) console.error((fld||"") + 'Expected ' + hexstr +' saw ' + m);
225
- this.l += hexstr.length/2;
226
- }
227
-
228
197
  function prep_blob(blob, pos) {
229
198
  blob.read_shift = ReadShift.bind(blob);
230
199
  blob.chk = CheckField;
@@ -233,14 +202,14 @@ function prep_blob(blob, pos) {
233
202
  return [read, chk];
234
203
  }
235
204
 
236
- /* ssf.js (C) 2013 SheetJS -- http://sheetjs.com */
205
+ /* ssf.js (C) 2013-2014 SheetJS -- http://sheetjs.com */
237
206
  var SSF = {};
238
207
  var make_ssf = function(SSF){
239
- String.prototype.reverse=function(){return this.split("").reverse().join("");};
240
- var _strrev = function(x) { return String(x).reverse(); };
208
+ var _strrev = function(x) { return String(x).split("").reverse().join("");};
241
209
  function fill(c,l) { return new Array(l+1).join(c); }
242
210
  function pad(v,d,c){var t=String(v);return t.length>=d?t:(fill(c||0,d-t.length)+t);}
243
211
  function rpad(v,d,c){var t=String(v);return t.length>=d?t:(t+fill(c||0,d-t.length));}
212
+ SSF.version = '0.5.8';
244
213
  /* Options */
245
214
  var opts_fmt = {};
246
215
  function fixopts(o){for(var y in opts_fmt) if(o[y]===undefined) o[y]=opts_fmt[y];}
@@ -249,6 +218,7 @@ opts_fmt.date1904 = 0;
249
218
  opts_fmt.output = "";
250
219
  opts_fmt.mode = "";
251
220
  var table_fmt = {
221
+ 0: 'General',
252
222
  1: '0',
253
223
  2: '0.00',
254
224
  3: '#,##0',
@@ -275,7 +245,9 @@ var table_fmt = {
275
245
  46: '[h]:mm:ss',
276
246
  47: 'mmss.0',
277
247
  48: '##0.0E+0',
278
- 49: '@'
248
+ 49: '@',
249
+ 56: '"上午/下午 "hh"時"mm"分"ss"秒 "',
250
+ 65535: 'General'
279
251
  };
280
252
  var days = [
281
253
  ['Sun', 'Sunday'],
@@ -305,12 +277,12 @@ var frac = function frac(x, D, mixed) {
305
277
  var B = x * sgn;
306
278
  var P_2 = 0, P_1 = 1, P = 0;
307
279
  var Q_2 = 1, Q_1 = 0, Q = 0;
308
- var A = B|0;
280
+ var A = Math.floor(B);
309
281
  while(Q_1 < D) {
310
- A = B|0;
282
+ A = Math.floor(B);
311
283
  P = A * P_1 + P_2;
312
284
  Q = A * Q_1 + Q_2;
313
- if((B - A) < 0.0000000001) break;
285
+ if((B - A) < 0.0000000005) break;
314
286
  B = 1 / (B - A);
315
287
  P_2 = P_1; P_1 = P;
316
288
  Q_2 = Q_1; Q_1 = Q;
@@ -318,6 +290,7 @@ var frac = function frac(x, D, mixed) {
318
290
  if(Q > D) { Q = Q_1; P = P_1; }
319
291
  if(Q > D) { Q = Q_2; P = P_2; }
320
292
  if(!mixed) return [0, sgn * P, Q];
293
+ if(Q===0) throw "Unexpected state: "+P+" "+P_1+" "+P_2+" "+Q+" "+Q_1+" "+Q_2;
321
294
  var q = Math.floor(sgn * P/Q);
322
295
  return [q, sgn*P - q*Q, Q];
323
296
  };
@@ -331,25 +304,26 @@ var general_fmt = function(v) {
331
304
  else if(V >= 0.0001 && V < 0.001) o = v.toPrecision(6);
332
305
  else if(V >= Math.pow(10,10) && V < Math.pow(10,11)) o = v.toFixed(10).substr(0,12);
333
306
  else if(V > Math.pow(10,-9) && V < Math.pow(10,11)) {
334
- o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
307
+ o = v.toFixed(12).replace(/(\.[0-9]*[1-9])0*$/,"$1").replace(/\.$/,"");
335
308
  if(o.length > 11+(v<0?1:0)) o = v.toPrecision(10);
336
309
  if(o.length > 11+(v<0?1:0)) o = v.toExponential(5);
337
310
  }
338
311
  else {
339
312
  o = v.toFixed(11).replace(/(\.[0-9]*[1-9])0*$/,"$1");
340
- if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
313
+ if(o.length > 11 + (v<0?1:0)) o = v.toPrecision(6);
341
314
  }
342
315
  o = o.replace(/(\.[0-9]*[1-9])0+e/,"$1e").replace(/\.0*e/,"e");
343
316
  return o.replace("e","E").replace(/\.0*$/,"").replace(/\.([0-9]*[^0])0*$/,".$1").replace(/(E[+-])([0-9])$/,"$1"+"0"+"$2");
344
317
  }
345
318
  if(typeof v === 'string') return v;
346
- throw "unsupported value in General format: " + v;
319
+ throw new Error("unsupported value in General format: " + v);
347
320
  };
348
321
  SSF._general = general_fmt;
349
322
  var parse_date_code = function parse_date_code(v,opts) {
350
- var date = Math.floor(v), time = Math.round(86400 * (v - date)), dow=0;
323
+ var date = Math.floor(v), time = Math.floor(86400 * (v - date)+1e-6), dow=0;
351
324
  var dout=[], out={D:date, T:time, u:86400*(v-date)-time}; fixopts(opts = (opts||{}));
352
325
  if(opts.date1904) date += 1462;
326
+ if(date > 2958465) return null;
353
327
  if(date === 60) {dout = [1900,2,29]; dow=3;}
354
328
  else if(date === 0) {dout = [1900,1,0]; dow=6;}
355
329
  else {
@@ -359,7 +333,7 @@ var parse_date_code = function parse_date_code(v,opts) {
359
333
  d.setDate(d.getDate() + date - 1);
360
334
  dout = [d.getFullYear(), d.getMonth()+1,d.getDate()];
361
335
  dow = d.getDay();
362
- if(opts.mode === 'excel' && date < 60) dow = (dow + 6) % 7;
336
+ if(/* opts.mode === 'excel' && */ date < 60) dow = (dow + 6) % 7;
363
337
  }
364
338
  out.y = dout[0]; out.m = dout[1]; out.d = dout[2];
365
339
  out.S = time % 60; time = Math.floor(time / 60);
@@ -369,61 +343,63 @@ var parse_date_code = function parse_date_code(v,opts) {
369
343
  return out;
370
344
  };
371
345
  SSF.parse_date_code = parse_date_code;
346
+ /*jshint -W086 */
372
347
  var write_date = function(type, fmt, val) {
373
348
  if(val < 0) return "";
349
+ var o;
374
350
  switch(type) {
375
351
  case 'y': switch(fmt) { /* year */
376
352
  case 'y': case 'yy': return pad(val.y % 100,2);
377
- default: return val.y;
378
- } break;
353
+ default: return pad(val.y % 10000,4);
354
+ }
379
355
  case 'm': switch(fmt) { /* month */
380
356
  case 'm': return val.m;
381
357
  case 'mm': return pad(val.m,2);
382
358
  case 'mmm': return months[val.m-1][1];
383
- case 'mmmm': return months[val.m-1][2];
384
359
  case 'mmmmm': return months[val.m-1][0];
385
- default: throw 'bad month format: ' + fmt;
386
- } break;
360
+ default: return months[val.m-1][2];
361
+ }
387
362
  case 'd': switch(fmt) { /* day */
388
363
  case 'd': return val.d;
389
364
  case 'dd': return pad(val.d,2);
390
365
  case 'ddd': return days[val.q][0];
391
- case 'dddd': return days[val.q][1];
392
- default: throw 'bad day format: ' + fmt;
393
- } break;
366
+ default: return days[val.q][1];
367
+ }
394
368
  case 'h': switch(fmt) { /* 12-hour */
395
369
  case 'h': return 1+(val.H+11)%12;
396
370
  case 'hh': return pad(1+(val.H+11)%12, 2);
397
371
  default: throw 'bad hour format: ' + fmt;
398
- } break;
372
+ }
399
373
  case 'H': switch(fmt) { /* 24-hour */
400
374
  case 'h': return val.H;
401
375
  case 'hh': return pad(val.H, 2);
402
376
  default: throw 'bad hour format: ' + fmt;
403
- } break;
377
+ }
404
378
  case 'M': switch(fmt) { /* minutes */
405
379
  case 'm': return val.M;
406
380
  case 'mm': return pad(val.M, 2);
407
381
  default: throw 'bad minute format: ' + fmt;
408
- } break;
382
+ }
409
383
  case 's': switch(fmt) { /* seconds */
410
- case 's': return val.S;
411
- case 'ss': return pad(val.S, 2);
412
- case 'ss.0': return pad(val.S,2) + "." + Math.round(10*val.u);
384
+ case 's': return Math.round(val.S+val.u);
385
+ case 'ss': return pad(Math.round(val.S+val.u), 2);
386
+ case 'ss.0': o = pad(Math.round(10*(val.S+val.u)),3); return o.substr(0,2)+"." + o.substr(2);
387
+ case 'ss.00': o = pad(Math.round(100*(val.S+val.u)),4); return o.substr(0,2)+"." + o.substr(2);
388
+ case 'ss.000': o = pad(Math.round(1000*(val.S+val.u)),5); return o.substr(0,2)+"." + o.substr(2);
413
389
  default: throw 'bad second format: ' + fmt;
414
- } break;
390
+ }
415
391
  case 'Z': switch(fmt) {
416
- case '[h]': return val.D*24+val.H;
392
+ case '[h]': case '[hh]': o = val.D*24+val.H; break;
393
+ case '[m]': case '[mm]': o = (val.D*24+val.H)*60+val.M; break;
394
+ case '[s]': case '[ss]': o = ((val.D*24+val.H)*60+val.M)*60+Math.round(val.S+val.u); break;
417
395
  default: throw 'bad abstime format: ' + fmt;
418
- } break;
396
+ } return fmt.length === 3 ? o : pad(o, 2);
419
397
  /* TODO: handle the ECMA spec format ee -> yy */
420
398
  case 'e': { return val.y; } break;
421
- case 'A': return (val.h>=12 ? 'P' : 'A') + fmt.substr(1);
422
- default: throw 'bad format type ' + type + ' in ' + fmt;
423
399
  }
424
400
  };
425
- String.prototype.reverse = function() { return this.split("").reverse().join(""); };
426
- var commaify = function(s) { return s.reverse().replace(/.../g,"$&,").reverse().replace(/^,/,""); };
401
+ /*jshint +W086 */
402
+ var commaify = function(s) { return _strrev(_strrev(s).replace(/.../g,"$&,")).replace(/^,/,""); };
427
403
  var write_num = function(type, fmt, val) {
428
404
  if(type === '(') {
429
405
  var ffmt = fmt.replace(/\( */,"").replace(/ \)/,"").replace(/\)/,"");
@@ -435,37 +411,60 @@ var write_num = function(type, fmt, val) {
435
411
  if(mul !== 0) return write_num(type, fmt, val * Math.pow(10,2*mul)) + fill("%",mul);
436
412
  if(fmt.indexOf("E") > -1) {
437
413
  var idx = fmt.indexOf("E") - fmt.indexOf(".") - 1;
438
- if(fmt == '##0.0E+0') {
439
- var ee = Number(val.toExponential(0).substr(3))%3;
440
- o = (val/Math.pow(10,ee%3)).toPrecision(idx+1+(ee%3)).replace(/^([+-]?)([0-9]*)\.([0-9]*)[Ee]/,function($$,$1,$2,$3) { return $1 + $2 + $3.substr(0,ee) + "." + $3.substr(ee) + "E"; });
414
+ if(fmt.match(/^#+0.0E\+0$/)) {
415
+ var period = fmt.indexOf("."); if(period === -1) period=fmt.indexOf('E');
416
+ var ee = (Number(val.toExponential(0).substr(2+(val<0))))%period;
417
+ if(ee < 0) ee += period;
418
+ o = (val/Math.pow(10,ee)).toPrecision(idx+1+(period+ee)%period);
419
+ if(!o.match(/[Ee]/)) {
420
+ var fakee = (Number(val.toExponential(0).substr(2+(val<0))));
421
+ if(o.indexOf(".") === -1) o = o[0] + "." + o.substr(1) + "E+" + (fakee - o.length+ee);
422
+ else o += "E+" + (fakee - ee);
423
+ while(o.substr(0,2) === "0.") {
424
+ o = o[0] + o.substr(2,period) + "." + o.substr(2+period);
425
+ o = o.replace(/^0+([1-9])/,"$1").replace(/^0+\./,"0.");
426
+ }
427
+ o = o.replace(/\+-/,"-");
428
+ }
429
+ 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"; });
441
430
  } else o = val.toExponential(idx);
442
431
  if(fmt.match(/E\+00$/) && o.match(/e[+-][0-9]$/)) o = o.substr(0,o.length-1) + "0" + o[o.length-1];
443
432
  if(fmt.match(/E\-/) && o.match(/e\+/)) o = o.replace(/e\+/,"e");
444
433
  return o.replace("e","E");
445
434
  }
446
435
  if(fmt[0] === "$") return "$"+write_num(type,fmt.substr(fmt[1]==' '?2:1),val);
447
- var r, ff, aval = val < 0 ? -val : val, sign = val < 0 ? "-" : "";
448
- if((r = fmt.match(/# (\?+) \/ (\d+)/))) {
449
- var den = Number(r[2]), rnd = Math.round(aval * den), base = Math.floor(rnd/den);
436
+ var r, rr, ff, aval = val < 0 ? -val : val, sign = val < 0 ? "-" : "";
437
+ if((r = fmt.match(/# (\?+)([ ]?)\/([ ]?)(\d+)/))) {
438
+ var den = Number(r[4]), rnd = Math.round(aval * den), base = Math.floor(rnd/den);
450
439
  var myn = (rnd - base*den), myd = den;
451
- return sign + (base?base:"") + " " + (myn === 0 ? fill(" ", r[1].length + 1 + r[2].length) : pad(myn,r[1].length," ") + "/" + pad(myd,r[2].length));
440
+ 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));
441
+ }
442
+ if(fmt.match(/^#+0+$/)) fmt = fmt.replace(/#/g,"");
443
+ if(fmt.match(/^00+$/)) return (val<0?"-":"")+pad(Math.round(aval),fmt.length);
444
+ if(fmt.match(/^[#?]+$/)) return String(Math.round(val)).replace(/^0$/,"");
445
+ if((r = fmt.match(/^#*0+\.(0+)/))) {
446
+ o = Math.round(val * Math.pow(10,r[1].length));
447
+ return String(o/Math.pow(10,r[1].length)).replace(/^([^\.]+)$/,"$1."+r[1]).replace(/\.$/,"."+r[1]).replace(/\.([0-9]*)$/,function($$, $1) { return "." + $1 + fill("0", r[1].length-$1.length); });
448
+ }
449
+ if((r = fmt.match(/^(0*)\.(#*)$/))) {
450
+ o = Math.round(val*Math.pow(10,r[2].length));
451
+ return String(o * Math.pow(10,-r[2].length)).replace(/\.(\d*[1-9])0*$/,".$1").replace(/^([-]?\d*)$/,"$1.").replace(/^0\./,r[1].length?"0.":".");
452
+ }
453
+ if((r = fmt.match(/^#,##0([.]?)$/))) return sign + commaify(String(Math.round(aval)));
454
+ if((r = fmt.match(/^#,##0\.([#0]*0)$/))) {
455
+ rr = Math.round((val-Math.floor(val))*Math.pow(10,r[1].length));
456
+ return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))) + "." + pad(rr,r[1].length,0);
457
+ }
458
+ if((r = fmt.match(/^# ([?]+)([ ]?)\/([ ]?)([?]+)/))) {
459
+ rr = Math.min(Math.max(r[1].length, r[4].length),7);
460
+ ff = frac(aval, Math.pow(10,rr)-1, true);
461
+ return sign + (ff[0]||(ff[1] ? "" : "0")) + " " + (ff[1] ? pad(ff[1],rr," ") + r[2] + "/" + r[3] + rpad(ff[2],rr," "): fill(" ", 2*rr+1 + r[2].length + r[3].length));
452
462
  }
453
- if(fmt.match(/^00*$/)) return (val<0?"-":"")+pad(Math.round(Math.abs(val)), fmt.length);
454
- if(fmt.match(/^####*$/)) return "dafuq";
455
463
  switch(fmt) {
456
- case "0": return Math.round(val);
457
- case "0.0": o = Math.round(val*10);
458
- return String(o/10).replace(/^([^\.]+)$/,"$1.0").replace(/\.$/,".0");
459
- case "0.00": o = Math.round(val*100);
460
- return String(o/100).replace(/^([^\.]+)$/,"$1.00").replace(/\.$/,".00").replace(/\.([0-9])$/,".$1"+"0");
461
- case "0.000": o = Math.round(val*1000);
462
- return String(o/1000).replace(/^([^\.]+)$/,"$1.000").replace(/\.$/,".000").replace(/\.([0-9])$/,".$1"+"00").replace(/\.([0-9][0-9])$/,".$1"+"0");
463
- case "#,##0": return sign + commaify(String(Math.round(aval)));
464
- case "#,##0.0": r = Math.round((val-Math.floor(val))*10); return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))) + "." + r;
465
- case "#,##0.00": r = Math.round((val-Math.floor(val))*100); return val < 0 ? "-" + write_num(type, fmt, -val) : commaify(String(Math.floor(val))) + "." + (r < 10 ? "0"+r:r);
466
- case "# ? / ?": ff = frac(aval, 9, true); return sign + (ff[0]||"") + " " + (ff[1] === 0 ? " " : ff[1] + "/" + ff[2]);
467
- case "# ?? / ??": ff = frac(aval, 99, true); return sign + (ff[0]||"") + " " + (ff[1] ? pad(ff[1],2," ") + "/" + rpad(ff[2],2," ") : " ");
468
- case "# ??? / ???": ff = frac(aval, 999, true); return sign + (ff[0]||"") + " " + (ff[1] ? pad(ff[1],3," ") + "/" + rpad(ff[2],3," ") : " ");
464
+ case "0": case "#0": return Math.round(val);
465
+ case "#.##": o = Math.round(val*100);
466
+ return String(o/100).replace(/^([^\.]+)$/,"$1.").replace(/^0\.$/,".");
467
+ case "#,###": var x = commaify(String(Math.round(aval))); return x !== "0" ? sign + x : "";
469
468
  default:
470
469
  }
471
470
  throw new Error("unsupported format |" + fmt + "|");
@@ -482,7 +481,7 @@ function split_fmt(fmt) {
482
481
  j = i+1;
483
482
  }
484
483
  out.push(fmt.slice(j));
485
- if(in_str !=-1) throw "Format |" + fmt + "| unterminated string at " + in_str;
484
+ if(in_str !=-1) throw new Error("Format |" + fmt + "| unterminated string at " + in_str);
486
485
  return out;
487
486
  }
488
487
  SSF._split = split_fmt;
@@ -493,6 +492,10 @@ function eval_fmt(fmt, v, opts, flen) {
493
492
  /* Tokenize */
494
493
  while(i < fmt.length) {
495
494
  switch((c = fmt[i])) {
495
+ case 'G': /* General */
496
+ if(fmt.substr(i, i+6).toLowerCase() !== "general")
497
+ throw new Error('unrecognized character ' + fmt[i] + ' in ' +fmt);
498
+ out.push({t:'G',v:'General'}); i+=7; break;
496
499
  case '"': /* Literal text */
497
500
  for(o="";fmt[++i] !== '"' && i < fmt.length;) o += fmt[i];
498
501
  out.push({t:'t', v:o}); ++i; break;
@@ -502,28 +505,39 @@ function eval_fmt(fmt, v, opts, flen) {
502
505
  case '@': /* Text Placeholder */
503
506
  out.push({t:'T', v:v}); ++i; break;
504
507
  /* Dates */
508
+ case 'M': case 'D': case 'Y': case 'H': case 'S': case 'E':
509
+ c = c.toLowerCase();
510
+ /* falls through */
505
511
  case 'm': case 'd': case 'y': case 'h': case 's': case 'e':
506
512
  if(v < 0) return "";
507
513
  if(!dt) dt = parse_date_code(v, opts);
508
- o = fmt[i]; while(fmt[++i] === c) o+=c;
514
+ if(!dt) return "";
515
+ o = fmt[i]; while((fmt[++i]||"").toLowerCase() === c) o+=c;
509
516
  if(c === 's' && fmt[i] === '.' && fmt[i+1] === '0') { o+='.'; while(fmt[++i] === '0') o+= '0'; }
510
517
  if(c === 'm' && lst.toLowerCase() === 'h') c = 'M'; /* m = minute */
511
518
  if(c === 'h') c = hr;
519
+ o = o.toLowerCase();
512
520
  q={t:c, v:o}; out.push(q); lst = c; break;
513
521
  case 'A':
514
522
  if(!dt) dt = parse_date_code(v, opts);
523
+ if(!dt) return "";
515
524
  q={t:c,v:"A"};
516
525
  if(fmt.substr(i, 3) === "A/P") {q.v = dt.H >= 12 ? "P" : "A"; q.t = 'T'; hr='h';i+=3;}
517
526
  else if(fmt.substr(i,5) === "AM/PM") { q.v = dt.H >= 12 ? "PM" : "AM"; q.t = 'T'; i+=5; hr='h'; }
518
- else q.t = "t";
527
+ else { q.t = "t"; i++; }
519
528
  out.push(q); lst = c; break;
520
529
  case '[': /* TODO: Fix this -- ignore all conditionals and formatting */
521
530
  o = c;
522
- while(fmt[i++] !== ']') o += fmt[i];
523
- if(o == "[h]") out.push({t:'Z', v:o});
531
+ while(fmt[i++] !== ']' && i < fmt.length) o += fmt[i];
532
+ if(o.substr(-1) !== ']') throw 'unterminated "[" block: |' + o + '|';
533
+ if(o.match(/\[[HhMmSs]*\]/)) {
534
+ if(!dt) dt = parse_date_code(v, opts);
535
+ if(!dt) return "";
536
+ out.push({t:'Z', v:o.toLowerCase()});
537
+ } else { o=""; }
524
538
  break;
525
539
  /* Numbers */
526
- case '0': case '#':
540
+ case '0': case '#': case '.':
527
541
  o = c; while("0#?.,E+-%".indexOf(c=fmt[++i]) > -1) o += c;
528
542
  out.push({t:'n', v:o}); break;
529
543
  case '?':
@@ -536,7 +550,7 @@ function eval_fmt(fmt, v, opts, flen) {
536
550
  out.push({t:'D', v:o}); break;
537
551
  case ' ': out.push({t:c,v:c}); ++i; break;
538
552
  default:
539
- if("$-+/():!^&'~{}<>=".indexOf(c) === -1)
553
+ if(",$-+/():!^&'~{}<>=€".indexOf(c) === -1)
540
554
  throw 'unrecognized character ' + fmt[i] + ' in ' + fmt;
541
555
  out.push({t:'t', v:c}); ++i; break;
542
556
  }
@@ -554,45 +568,48 @@ function eval_fmt(fmt, v, opts, flen) {
554
568
  /* replace fields */
555
569
  for(i=0; i < out.length; ++i) {
556
570
  switch(out[i].t) {
557
- case 't': case 'T': case ' ': break;
558
- case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'A': case 'e': case 'Z':
571
+ case 't': case 'T': case ' ': case 'D': break;
572
+ case 'd': case 'm': case 'y': case 'h': case 'H': case 'M': case 's': case 'e': case 'Z':
559
573
  out[i].v = write_date(out[i].t, out[i].v, dt);
560
574
  out[i].t = 't'; break;
561
- case 'n': case '(':
575
+ case 'n': case '(': case '?':
562
576
  var jj = i+1;
563
- while(out[jj] && ("? D".indexOf(out[jj].t) > -1 || 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 == '?')))) {
564
- if(out[jj].v!==' ') out[i].v += ' ' + out[jj].v;
577
+ 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 == '?')))) {
578
+ out[i].v += out[jj].v;
565
579
  delete out[jj]; ++jj;
566
580
  }
567
- out[i].v = write_num(out[i].t, out[i].v, v);
581
+ out[i].v = write_num(out[i].t, out[i].v, (flen >1 && v < 0 && i>0 && out[i-1].v == "-" ? -v:v));
568
582
  out[i].t = 't';
569
- i = jj; break;
570
- default: throw "unrecognized type " + out[i].t;
583
+ i = jj-1; break;
584
+ case 'G': out[i].t = 't'; out[i].v = general_fmt(v,opts); break;
571
585
  }
572
586
  }
573
-
574
587
  return out.map(function(x){return x.v;}).join("");
575
588
  }
576
589
  SSF._eval = eval_fmt;
577
590
  function choose_fmt(fmt, v, o) {
578
- if(typeof fmt === 'number') fmt = table_fmt[fmt];
591
+ if(typeof fmt === 'number') fmt = ((o&&o.table) ? o.table : table_fmt)[fmt];
579
592
  if(typeof fmt === "string") fmt = split_fmt(fmt);
580
593
  var l = fmt.length;
594
+ if(l<4 && fmt[l-1].indexOf("@")>-1) --l;
581
595
  switch(fmt.length) {
582
- case 1: fmt = [fmt[0], fmt[0], fmt[0], "@"]; break;
583
- case 2: fmt = [fmt[0], fmt[fmt[1] === "@"?0:1], fmt[0], "@"]; break;
596
+ case 1: fmt = fmt[0].indexOf("@")>-1 ? ["General", "General", "General", fmt[0]] : [fmt[0], fmt[0], fmt[0], "@"]; break;
597
+ case 2: fmt = fmt[1].indexOf("@")>-1 ? [fmt[0], fmt[0], fmt[0], fmt[1]] : [fmt[0], fmt[1], fmt[0], "@"]; break;
598
+ case 3: fmt = fmt[2].indexOf("@")>-1 ? [fmt[0], fmt[1], fmt[0], fmt[2]] : [fmt[0], fmt[1], fmt[2], "@"]; break;
584
599
  case 4: break;
585
600
  default: throw "cannot find right format for |" + fmt + "|";
586
601
  }
587
602
  if(typeof v !== "number") return [fmt.length, fmt[3]];
588
603
  return [l, v > 0 ? fmt[0] : v < 0 ? fmt[1] : fmt[2]];
589
604
  }
590
-
591
605
  var format = function format(fmt,v,o) {
592
606
  fixopts(o = (o||{}));
593
- if(fmt === 0) return general_fmt(v, o);
594
- if(typeof fmt === 'number') fmt = table_fmt[fmt];
607
+ if(typeof fmt === "string" && fmt.toLowerCase() === "general") return general_fmt(v, o);
608
+ if(typeof fmt === 'number') fmt = (o.table || table_fmt)[fmt];
595
609
  var f = choose_fmt(fmt, v, o);
610
+ if(f[1].toLowerCase() === "general") return general_fmt(v,o);
611
+ if(v === true) v = "TRUE"; if(v === false) v = "FALSE";
612
+ if(v === "" || typeof v === "undefined") return "";
596
613
  return eval_fmt(f[1], v, o, f[0]);
597
614
  };
598
615
 
@@ -600,6 +617,8 @@ SSF._choose = choose_fmt;
600
617
  SSF._table = table_fmt;
601
618
  SSF.load = function(fmt, idx) { table_fmt[idx] = fmt; };
602
619
  SSF.format = format;
620
+ SSF.get_table = function() { return table_fmt; };
621
+ SSF.load_table = function(tbl) { for(var i=0; i!=0x0188; ++i) if(tbl[i]) SSF.load(tbl[i], i); };
603
622
  };
604
623
  make_ssf(SSF);
605
624
  /* [MS-OLEPS] v20130118 */
@@ -746,7 +765,7 @@ function parse_VtStringBase(blob, stringType, pad) {
746
765
  else return parse_VtStringBase(blob, blob.read_shift(2), pad);
747
766
  }
748
767
 
749
- function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, 4); }
768
+ function parse_VtString(blob, t, pad) { return parse_VtStringBase(blob, t, pad === false ? null : 4); }
750
769
  function parse_VtUnalignedString(blob, t) { if(!t) throw new Error("dafuq?"); return parse_VtStringBase(blob, t, 0); }
751
770
 
752
771
  /* [MS-OSHARED] 2.3.3.1.9 VtVecUnalignedLpstrValue */
@@ -802,7 +821,7 @@ function parse_dictionary(blob,CodePage) {
802
821
  function parse_BLOB(blob) {
803
822
  var size = blob.read_shift(4);
804
823
  var bytes = blob.slice(blob.l,blob.l+size);
805
- if(blob.l % 4) blob.l += (4 - (blob.l % 4)) % 4;
824
+ if(size % 4 > 0) blob.l += (4 - (size % 4)) % 4;
806
825
  return bytes;
807
826
  }
808
827
 
@@ -828,14 +847,14 @@ function parse_VtVector(blob, cb) {
828
847
  }
829
848
 
830
849
  /* [MS-OLEPS] 2.15 TypedPropertyValue */
831
- function parse_TypedPropertyValue(blob, type) {
850
+ function parse_TypedPropertyValue(blob, type, _opts) {
832
851
  var read = ReadShift.bind(blob), chk = CheckField.bind(blob);
833
- var t = read(2), ret;
852
+ var t = read(2), ret, opts = _opts||{};
834
853
  read(2);
835
854
  if(type !== VT_VARIANT)
836
855
  if(t !== type && VT_CUSTOM.indexOf(type)===-1) throw new Error('Expected type ' + type + ' saw ' + t);
837
856
  switch(type === VT_VARIANT ? t : type) {
838
- case VT_I2: ret = read(2, 'i'); read(2); return ret;
857
+ case VT_I2: ret = read(2, 'i'); if(!opts.raw) read(2); return ret;
839
858
  case VT_I4: ret = read(4, 'i'); return ret;
840
859
  case VT_BOOL: return read(4) !== 0x0;
841
860
  case VT_UI4: ret = read(4); return ret;
@@ -844,7 +863,7 @@ function parse_TypedPropertyValue(blob, type) {
844
863
  case VT_FILETIME: return parse_FILETIME(blob);
845
864
  case VT_BLOB: return parse_BLOB(blob);
846
865
  case VT_CF: return parse_ClipboardData(blob);
847
- case VT_STRING: return parse_VtString(blob, t, 4).replace(/\u0000/g,'');
866
+ case VT_STRING: return parse_VtString(blob, t, !opts.raw && 4).replace(/\u0000/g,'');
848
867
  case VT_USTR: return parse_VtUnalignedString(blob, t, 4).replace(/\u0000/g,'');
849
868
  case VT_VECTOR | VT_VARIANT: return parse_VtVecHeadingPair(blob);
850
869
  case VT_VECTOR | VT_LPSTR: return parse_VtVecUnalignedLpstr(blob);
@@ -880,16 +899,25 @@ function parse_PropertySet(blob, PIDSI) {
880
899
  var PropH = {};
881
900
  for(i = 0; i != NumProps; ++i) {
882
901
  if(blob.l !== Props[i][1]) {
883
- throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
902
+ var fail = true;
903
+ if(i>0 && PIDSI) switch(PIDSI[Props[i-1][0]].t) {
904
+ case VT_I2: if(blob.l +2 === Props[i][1]) { blob.l+=2; fail = false; } break;
905
+ case VT_STRING: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
906
+ case VT_VECTOR | VT_VARIANT: if(blob.l <= Props[i][1]) { blob.l=Props[i][1]; fail = false; } break;
907
+ }
908
+ if(!PIDSI && blob.l <= Props[i][1]) { fail=false; blob.l = Props[i][1]; }
909
+ if(fail) throw new Error("Read Error: Expected address " + Props[i][1] + ' at ' + blob.l + ' :' + i);
884
910
  }
885
911
  if(PIDSI) {
886
912
  var piddsi = PIDSI[Props[i][0]];
887
- PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t);
913
+ PropH[piddsi.n] = parse_TypedPropertyValue(blob, piddsi.t, {raw:true});
888
914
  if(piddsi.n == "CodePage") switch(PropH[piddsi.n]) {
889
915
  /* TODO: Generate files under every codepage */
890
916
  case 10000: break; // OSX Roman
891
917
  case 1252: break; // Windows Latin
892
918
 
919
+ case 0: PropH[piddsi.n] = 1252; break; // Unknown -> default
920
+
893
921
  case 874: // SB Windows Thai
894
922
  case 1250: // SB Windows Central Europe
895
923
  case 1251: // SB Windows Cyrillic
@@ -971,14 +999,16 @@ function parse_PropertySetStream(file, PIDSI) {
971
999
  rval.FMTID = FMTID0;
972
1000
  //rval.PSet0 = PSet0;
973
1001
  if(NumSets === 1) return rval;
974
- var PSet1 = parse_PropertySet(blob, null);
1002
+ if(blob.l !== Offset1) throw "Length mismatch 2: " + blob.l + " !== " + Offset1;
1003
+ var PSet1;
1004
+ try { PSet1 = parse_PropertySet(blob, null); } catch(e) { }
975
1005
  for(y in PSet1) rval[y] = PSet1[y];
976
1006
  rval.FMTID = [FMTID0, FMTID1]; // TODO: verify FMTID0/1
977
1007
  return rval;
978
1008
  }
979
1009
  /* [MS-CFB] v20130118 */
980
- if(typeof module !== "undefined" && typeof require !== 'undefined') CFB = require('cfb');
981
- else var CFB = (function(){
1010
+ /*if(typeof module !== "undefined" && typeof require !== 'undefined') CFB = require('cfb');
1011
+ else*/ var CFB = (function(){
982
1012
  var exports = {};
983
1013
  function parse(file) {
984
1014
 
@@ -1004,7 +1034,6 @@ var fat_addrs = []; // locations of FAT sectors
1004
1034
  var blob = file.slice(0,512);
1005
1035
  prep_blob(blob);
1006
1036
  var read = ReadShift.bind(blob), chk = CheckField.bind(blob);
1007
- //var wrn = WarnField.bind(blob);
1008
1037
  var j = 0, q;
1009
1038
 
1010
1039
  // header signature 8
@@ -1014,7 +1043,6 @@ chk(HEADER_SIGNATURE, 'Header Signature: ');
1014
1043
  chk(HEADER_CLSID, 'CLSID: ');
1015
1044
 
1016
1045
  // minor version 2
1017
- //wrn(HEADER_MINOR_VERSION, 'Minor Version: ');
1018
1046
  read(2);
1019
1047
 
1020
1048
  // major version 3
@@ -1100,10 +1128,10 @@ function sleuth_fat(idx, cnt) {
1100
1128
  if(idx !== FREESECT) {
1101
1129
  var sector = sectors[idx];
1102
1130
  for(var i = 0; i != ssz/4-1; ++i) {
1103
- if((q = sector.readUInt32LE(i*4)) === ENDOFCHAIN) break;
1131
+ if((q = __readUInt32LE(sector,i*4)) === ENDOFCHAIN) break;
1104
1132
  fat_addrs.push(q);
1105
1133
  }
1106
- sleuth_fat(sector.readUInt32LE(ssz-4),cnt - 1);
1134
+ sleuth_fat(__readUInt32LE(sector,ssz-4),cnt - 1);
1107
1135
  }
1108
1136
  }
1109
1137
  sleuth_fat(difat_start, ndfs);
@@ -1117,7 +1145,7 @@ function get_buffer(byte_addr, bytes) {
1117
1145
  }
1118
1146
 
1119
1147
  function get_buffer_u32(byte_addr) {
1120
- return get_buffer(byte_addr,4).readUInt32LE(0);
1148
+ return __readUInt32LE(get_buffer(byte_addr,4), 0);
1121
1149
  }
1122
1150
 
1123
1151
  function get_next_sector(idx) { return get_buffer_u32(idx); }
@@ -1130,7 +1158,7 @@ for(i=0; i != sectors.length; ++i) {
1130
1158
  if(chkd[k]) continue;
1131
1159
  for(j=k; j<=MAXREGSECT; buf.push(j),j=get_next_sector(j)) chkd[j] = true;
1132
1160
  sector_list[k] = {nodes: buf};
1133
- sector_list[k].data = Buffers(buf.map(get_sector)).toBuffer();
1161
+ sector_list[k].data = __toBuffer(Array(buf.map(get_sector)));
1134
1162
  }
1135
1163
  sector_list[dir_start].name = "!Directory";
1136
1164
  if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT";
@@ -1147,7 +1175,7 @@ function read_directory(idx) {
1147
1175
  read = ReadShift.bind(blob);
1148
1176
  var namelen = read(2);
1149
1177
  if(namelen === 0) return;
1150
- var name = blob.utf16le(0,namelen-(Paths.length?2:0)); // OLE
1178
+ var name = __utf16le(blob,0,namelen-(Paths.length?2:0)); // OLE
1151
1179
  Paths.push(name);
1152
1180
  var o = { name: name };
1153
1181
  o.type = EntryTypes[read(1)];
@@ -1181,12 +1209,12 @@ function read_directory(idx) {
1181
1209
  }
1182
1210
  if(o.ctime) {
1183
1211
  var ct = blob.slice(blob.l-24, blob.l-16);
1184
- var c2 = (ct.readUInt32LE(4)/1e7)*Math.pow(2,32)+ct.readUInt32LE(0)/1e7;
1212
+ var c2 = (__readUInt32LE(ct,4)/1e7)*Math.pow(2,32)+__readUInt32LE(ct,0)/1e7;
1185
1213
  o.ct = new Date((c2 - 11644473600)*1000);
1186
1214
  }
1187
1215
  if(o.mtime) {
1188
1216
  var mt = blob.slice(blob.l-16, blob.l-8);
1189
- var m2 = (mt.readUInt32LE(4)/1e7)*Math.pow(2,32)+mt.readUInt32LE(0)/1e7;
1217
+ var m2 = (__readUInt32LE(mt,4)/1e7)*Math.pow(2,32)+__readUInt32LE(mt,0)/1e7;
1190
1218
  o.mt = new Date((m2 - 11644473600)*1000);
1191
1219
  }
1192
1220
  files[name] = o;
@@ -1248,16 +1276,16 @@ var rval = {
1248
1276
  find: find_path
1249
1277
  };
1250
1278
 
1251
- //for(var name in files) {
1252
- // switch(name) {
1253
- // /* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
1254
- // case '!DocumentSummaryInformation':
1255
- // rval.DocSummary = parse_PropertySetStream(files[name], DocSummaryPIDDSI); break;
1256
- // /* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
1257
- // case '!SummaryInformation':
1258
- // rval.Summary = parse_PropertySetStream(files[name], SummaryPIDSI); break;
1259
- // }
1260
- //}
1279
+ for(var name in files) {
1280
+ switch(name) {
1281
+ /* [MS-OSHARED] 2.3.3.2.2 Document Summary Information Property Set */
1282
+ case '!DocumentSummaryInformation':
1283
+ try { rval.DocSummary = parse_PropertySetStream(files[name], DocSummaryPIDDSI); } catch(e) { } break;
1284
+ /* [MS-OSHARED] 2.3.3.2.1 Summary Information Property Set*/
1285
+ case '!SummaryInformation':
1286
+ try { rval.Summary = parse_PropertySetStream(files[name], SummaryPIDSI); } catch(e) { } break;
1287
+ }
1288
+ }
1261
1289
 
1262
1290
  return rval;
1263
1291
  } // parse
@@ -1304,10 +1332,6 @@ return exports;
1304
1332
  }
1305
1333
 
1306
1334
  if(typeof require !== 'undefined' && typeof exports !== 'undefined') {
1307
- Buffers = Array;
1308
- Buffers.prototype.toBuffer = function() {
1309
- return Buffer.concat(this[0]);
1310
- };
1311
1335
  var fs = require('fs');
1312
1336
  //exports.read = CFB.read;
1313
1337
  //exports.parse = CFB.parse;
@@ -1319,13 +1343,6 @@ if(typeof require !== 'undefined' && typeof exports !== 'undefined') {
1319
1343
  };
1320
1344
  if(typeof module !== 'undefined' && require.main === module)
1321
1345
  exports.main(process.argv.slice(2));
1322
- } else {
1323
- Buffers = Array;
1324
- Buffers.prototype.toBuffer = function() {
1325
- var x = [];
1326
- for(var i = 0; i != this[0].length; ++i) { x = x.concat(this[0][i]); }
1327
- return x;
1328
- };
1329
1346
  }
1330
1347
 
1331
1348
  /* sections refer to MS-XLS unless otherwise stated */
@@ -1382,13 +1399,16 @@ function parse_XLUnicodeRichExtendedString(blob) {
1382
1399
  var fHighByte = flags & 0x1, fExtSt = flags & 0x4, fRichSt = flags & 0x8;
1383
1400
  var width = 1 + (flags & 0x1); // 0x0 -> utf8, 0x1 -> dbcs
1384
1401
  var cRun, cbExtRst;
1402
+ var z = {};
1385
1403
  if(fRichSt) cRun = read_shift(2);
1386
1404
  if(fExtSt) cbExtRst = read_shift(4);
1387
1405
  var encoding = (flags & 0x1) ? 'dbcs' : 'sbcs';
1388
1406
  var msg = cch === 0 ? "" : read_shift(encoding, cch);
1389
1407
  if(fRichSt) blob.l += 4 * cRun; //TODO: parse this
1390
1408
  if(fExtSt) blob.l += cbExtRst; //TODO: parse this
1391
- return msg;
1409
+ z.t = msg;
1410
+ if(!fRichSt) { z.raw = "<t>" + z.t + "</t>"; z.r = z.t; }
1411
+ return z;
1392
1412
  }
1393
1413
 
1394
1414
  /* 2.5.296 XLUnicodeStringNoCch */
@@ -1396,7 +1416,7 @@ function parse_XLUnicodeStringNoCch(blob, cch) {
1396
1416
  var read = blob.read_shift.bind(blob);
1397
1417
  var fHighByte = read(1);
1398
1418
  var retval;
1399
- if(fHighByte===0) { retval = blob.utf8(blob.l, blob.l+cch); blob.l += cch; }
1419
+ if(fHighByte===0) { retval = __utf8(blob,blob.l, blob.l+cch); blob.l += cch; }
1400
1420
  else { retval = blob.read_shift('dbcs', cch); }
1401
1421
  return retval;
1402
1422
  }
@@ -1451,7 +1471,7 @@ function parse_RkNumber(blob) {
1451
1471
  var fX100 = b[0] & 1, fInt = b[0] & 2;
1452
1472
  blob.l+=4;
1453
1473
  b[0] &= ~3;
1454
- var RK = fInt === 0 ? [0,0,0,0,b[0],b[1],b[2],b[3]].readDoubleLE(0) : b.readInt32LE(0)>>2;
1474
+ var RK = fInt === 0 ? __readDoubleLE([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
1455
1475
  return fX100 ? RK/100 : RK;
1456
1476
  }
1457
1477
 
@@ -1628,6 +1648,14 @@ function parse_LabelSst(blob, length) {
1628
1648
  return cell;
1629
1649
  }
1630
1650
 
1651
+ /* 2.4.148 */
1652
+ function parse_Label(blob, length) {
1653
+ var cell = parse_Cell(blob, 6);
1654
+ var str = parse_XLUnicodeString(blob, length-6);
1655
+ cell.val = str;
1656
+ return cell;
1657
+ }
1658
+
1631
1659
  /* 2.4.126 Number Formats */
1632
1660
  function parse_Format(blob, length) {
1633
1661
  var ifmt = blob.read_shift(2);
@@ -1674,7 +1702,7 @@ function parse_XF(blob, length) {
1674
1702
  o.ifnt = read(2); o.ifmt = read(2); o.flags = read(2);
1675
1703
  o.fStyle = (o.flags >> 2) & 0x01;
1676
1704
  length -= 6;
1677
- o.data = o.fStyle ? parse_StyleXF(blob, length) : parse_CellXF(blob, length);
1705
+ o.data = o.fStyle ? parse_StyleXF(blob, length) : parse_CellXF(blob, length);
1678
1706
  return o;
1679
1707
  }
1680
1708
 
@@ -1734,7 +1762,7 @@ function parse_ExternName(blob, length, opts) {
1734
1762
  };
1735
1763
  if(opts.sbcch === 0x3A01) body = parse_AddinUdf(blob, length-2);
1736
1764
  //else throw new Error("unsupported SupBook cch: " + opts.sbcch);
1737
- o.body = blob.read_shift(length-2);
1765
+ o.body = body || blob.read_shift(length-2);
1738
1766
  return o;
1739
1767
  }
1740
1768
 
@@ -1792,6 +1820,21 @@ function parse_MTRSettings(blob, length) {
1792
1820
  return [fMTREnabled, fUserSetThreadCount, cUserThreadCount];
1793
1821
  }
1794
1822
 
1823
+ /* 2.5.186 */
1824
+ function parse_NoteSh(blob, length) {
1825
+ var row = blob.read_shift(2), col = blob.read_shift(2);
1826
+ var flags = blob.read_shift(2), idObj = blob.read_shift(2);
1827
+ var stAuthor = parse_XLUnicodeString(blob);
1828
+ blob.read_shift(1);
1829
+ return stAuthor;
1830
+ }
1831
+
1832
+ /* 2.4.179 */
1833
+ function parse_Note(blob, length) {
1834
+ /* TODO: Support revisions */
1835
+ return parse_NoteSh(blob, length);
1836
+ }
1837
+
1795
1838
  var parse_Backup = parsebool; /* 2.4.14 */
1796
1839
  var parse_Blank = parse_Cell; /* 2.4.20 Just the cell */
1797
1840
  var parse_BottomMargin = parse_Xnum; /* 2.4.27 */
@@ -1847,7 +1890,6 @@ var parse_WriteProtect = parsenoop; /* 2.4.350 empty record */
1847
1890
  /* ---- */
1848
1891
  var parse_VerticalPageBreaks = parsenoop;
1849
1892
  var parse_HorizontalPageBreaks = parsenoop;
1850
- var parse_Note = parsenoop;
1851
1893
  var parse_Selection = parsenoop;
1852
1894
  var parse_Continue = parsenoop;
1853
1895
  var parse_Pane = parsenoop;
@@ -1967,7 +2009,6 @@ var parse_CodeName = parse_XLUnicodeString;
1967
2009
  var parse_SXFDBType = parsenoop;
1968
2010
  var parse_ObNoMacros = parsenoop;
1969
2011
  var parse_Dv = parsenoop;
1970
- var parse_Label = parsenoop;
1971
2012
  var parse_Index = parsenoop;
1972
2013
  var parse_Table = parsenoop;
1973
2014
  var parse_Window2 = parsenoop;
@@ -2292,8 +2333,8 @@ function parse_PtgArray(blob, length) {
2292
2333
 
2293
2334
  /* 2.5.198.33 */
2294
2335
  function parse_PtgAttrBaxcel(blob, length) {
2295
- bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
2296
- bitBaxcel = 1;
2336
+ var bitSemi = blob[blob.l+1] & 0x01; /* 1 = volatile */
2337
+ var bitBaxcel = 1;
2297
2338
  blob.l += 4;
2298
2339
  return [bitSemi, bitBaxcel];
2299
2340
  }
@@ -2310,21 +2351,21 @@ function parse_PtgAttrChoose(blob, length) {
2310
2351
 
2311
2352
  /* 2.5.198.35 */
2312
2353
  function parse_PtgAttrGoto(blob, length) {
2313
- bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
2354
+ var bitGoto = (blob[blob.l+1] & 0xFF) ? 1 : 0;
2314
2355
  blob.l += 2;
2315
2356
  return [bitGoto, blob.read_shift(2)];
2316
2357
  }
2317
2358
 
2318
2359
  /* 2.5.198.36 */
2319
2360
  function parse_PtgAttrIf(blob, length) {
2320
- bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
2361
+ var bitIf = (blob[blob.l+1] & 0xFF) ? 1 : 0;
2321
2362
  blob.l += 2;
2322
2363
  return [bitIf, blob.read_shift(2)];
2323
2364
  }
2324
2365
 
2325
2366
  /* 2.5.198.37 */
2326
2367
  function parse_PtgAttrSemi(blob, length) {
2327
- bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
2368
+ var bitSemi = (blob[blob.l+1] & 0xFF) ? 1 : 0;
2328
2369
  blob.l += 4;
2329
2370
  return [bitSemi];
2330
2371
  }
@@ -2654,7 +2695,7 @@ function parse_Formula(blob, length) {
2654
2695
  /* 2.5.133 */
2655
2696
  function parse_FormulaValue(blob) {
2656
2697
  var b;
2657
- if(blob.readUInt16LE(blob.l + 6) !== 0xFFFF) return parse_Xnum(blob);
2698
+ if(__readUInt16LE(blob,blob.l + 6) !== 0xFFFF) return parse_Xnum(blob);
2658
2699
  switch(blob[blob.l]) {
2659
2700
  case 0x00: blob.l += 8; return "String";
2660
2701
  case 0x01: b = blob[blob.l+2] === 0x1; blob.l += 8; return b;
@@ -4486,6 +4527,23 @@ var RecordEnum = {
4486
4527
  0x0000: {}
4487
4528
  };
4488
4529
 
4530
+ function fixopts(opts) {
4531
+ var defaults = [
4532
+ ['cellNF', false], /* emit cell number format string as .z */
4533
+ ['cellFormula', true], /* emit formulae as .f */
4534
+
4535
+ ['sheetRows', 0, 'n'], /* read n rows (0 = read all rows) */
4536
+
4537
+ ['bookSheets', false], /* only try to get sheet names (no Sheets) */
4538
+ ['bookProps', false], /* only try to get properties (no Sheets) */
4539
+
4540
+ ['WTF', false] /* WTF mode (throws errors) */
4541
+ ];
4542
+ defaults.forEach(function(d) {
4543
+ if(typeof opts[d[0]] === 'undefined') opts[d[0]] = d[1];
4544
+ if(d[2] === 'n') opts[d[0]] = Number(opts[d[0]]);
4545
+ });
4546
+ }
4489
4547
  /* [MS-OLEDS] 2.3.8 CompObjStream */
4490
4548
  function parse_compobj(obj) {
4491
4549
  var v = {};
@@ -4493,12 +4551,12 @@ function parse_compobj(obj) {
4493
4551
 
4494
4552
  /* [MS-OLEDS] 2.3.7 CompObjHeader -- All fields MUST be ignored */
4495
4553
  var l = 28, m;
4496
- m = o.lpstr(l);
4497
- l += 4 + o.readUInt32LE(l);
4554
+ m = __lpstr(o, l);
4555
+ l += 4 + __readUInt32LE(o,l);
4498
4556
  v.UserType = m;
4499
4557
 
4500
4558
  /* [MS-OLEDS] 2.3.1 ClipboardFormatOrAnsiString */
4501
- m = o.readUInt32LE(l); l+= 4;
4559
+ m = __readUInt32LE(o,l); l+= 4;
4502
4560
  switch(m) {
4503
4561
  case 0x00000000: break;
4504
4562
  case 0xffffffff: case 0xfffffffe: l+=4; break;
@@ -4507,14 +4565,15 @@ function parse_compobj(obj) {
4507
4565
  l += m;
4508
4566
  }
4509
4567
 
4510
- m = o.lpstr(l); l += m.length === 0 ? 0 : 5 + m.length; v.Reserved1 = m;
4568
+ m = __lpstr(o, l); l += m.length === 0 ? 0 : 5 + m.length; v.Reserved1 = m;
4511
4569
 
4512
- if((m = o.readUInt32LE(l)) !== 0x71b2e9f4) return v;
4570
+ if((m = __readUInt32LE(o,l)) !== 0x71b2e9f4) return v;
4513
4571
  throw "Unsupported Unicode Extension";
4514
4572
  }
4515
4573
 
4516
-
4517
- function parse_xlscfb(cfb) {
4574
+ function parse_xlscfb(cfb, options) {
4575
+ if(!options) options = {};
4576
+ fixopts(options);
4518
4577
  reset_cp();
4519
4578
  var CompObj = cfb.find('!CompObj');
4520
4579
  var Summary = cfb.find('!SummaryInformation');
@@ -4529,12 +4588,12 @@ function slurp(R, blob, length, opts) {
4529
4588
  var l = length;
4530
4589
  var bufs = [blob.slice(blob.l,blob.l+l)];
4531
4590
  blob.l += length;
4532
- var next = (RecordEnum[blob.readUInt16LE(blob.l)]);
4591
+ var next = (RecordEnum[__readUInt16LE(blob,blob.l)]);
4533
4592
  while(next && next.n === 'Continue') {
4534
- l = blob.readUInt16LE(blob.l+2);
4593
+ l = __readUInt16LE(blob,blob.l+2);
4535
4594
  bufs.push(blob.slice(blob.l+4,blob.l+4+l));
4536
4595
  blob.l += 4+l;
4537
- next = (RecordEnum[blob.readUInt16LE(blob.l)]);
4596
+ next = (RecordEnum[__readUInt16LE(blob, blob.l)]);
4538
4597
  }
4539
4598
  var b = bconcat(bufs);
4540
4599
  prep_blob(b);
@@ -4544,7 +4603,7 @@ function slurp(R, blob, length, opts) {
4544
4603
  }
4545
4604
 
4546
4605
  // 2.3.2
4547
- function parse_workbook(blob) {
4606
+ function parse_workbook(blob, options) {
4548
4607
  var wb = {opts:{}};
4549
4608
  var Sheets = {};
4550
4609
  var out = [];
@@ -4560,11 +4619,13 @@ function parse_workbook(blob) {
4560
4619
  var lastcell, last_cell;
4561
4620
  var shared_formulae = {};
4562
4621
  var temp_val;
4622
+ var cell_valid = true;
4563
4623
  var XFs = []; /* XF records */
4564
- function addline(cell, line) {
4624
+ function addline(cell, line, options) {
4565
4625
  lastcell = cell;
4566
4626
  last_cell = encode_cell(cell);
4567
- out[last_cell] = line;
4627
+ if(options.sheetRows && lastcell.r >= options.sheetRows) cell_valid = false;
4628
+ else out[last_cell] = line;
4568
4629
  }
4569
4630
  var opts = {
4570
4631
  enc: false, // encrypted
@@ -4590,6 +4651,9 @@ function parse_workbook(blob) {
4590
4651
  var length = (blob.l === blob.length ? 0 : read(2)), y;
4591
4652
  var R = RecordEnum[RecordType];
4592
4653
  if(R && R.f) {
4654
+ if(options.bookSheets) {
4655
+ if(last_Rn === 'BoundSheet8' && R.n !== 'BoundSheet8') break;
4656
+ }
4593
4657
  last_Rn = R.n;
4594
4658
  if(R.r === 2 || R.r == 12) {
4595
4659
  var rt = read(2); length -= 2;
@@ -4745,39 +4809,72 @@ function parse_workbook(blob) {
4745
4809
  } break;
4746
4810
  case 'BOF': {
4747
4811
  if(file_depth++) break;
4812
+ cell_valid = true;
4748
4813
  out = {};
4749
4814
  cur_sheet = (Directory[s] || {name:""}).name;
4750
4815
  lst.push([R.n, s, val, Directory[s]]);
4751
4816
  } break;
4752
4817
  case 'Number': {
4753
4818
  temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:'n'};
4754
- addline({c:val.c, r:val.r}, temp_val);
4819
+ if(temp_val.XF) try {
4820
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4821
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4822
+ } catch(e) { if(opts.WTF) throw e; }
4823
+ addline({c:val.c, r:val.r}, temp_val, options);
4755
4824
  } break;
4756
4825
  case 'BoolErr': {
4757
4826
  temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.val, t:val.t};
4758
- addline({c:val.c, r:val.r}, temp_val);
4827
+ if(temp_val.XF) try {
4828
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4829
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4830
+ } catch(e) { if(opts.WTF) throw e; }
4831
+ addline({c:val.c, r:val.r}, temp_val, options);
4759
4832
  } break;
4760
4833
  case 'RK': {
4761
- temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'};
4762
- addline({c:val.c, r:val.r}, temp_val);
4834
+ temp_val = {ixfe: val.ixfe, XF: XFs[val.ixfe], v:val.rknum, t:'n'};
4835
+ if(temp_val.XF) try {
4836
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4837
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4838
+ } catch(e) { if(opts.WTF) throw e; }
4839
+ addline({c:val.c, r:val.r}, temp_val, options);
4763
4840
  } break;
4764
4841
  case 'MulRk': {
4765
4842
  for(var j = val.c; j <= val.C; ++j) {
4766
4843
  var ixfe = val.rkrec[j-val.c][0];
4767
- addline({c:j, r:val.r}, {ixfe: ixfe, XF: XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'});
4844
+ temp_val= {ixfe:ixfe, XF:XFs[ixfe], v:val.rkrec[j-val.c][1], t:'n'};
4845
+ if(temp_val.XF) try {
4846
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4847
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4848
+ } catch(e) { if(opts.WTF) throw e; }
4849
+ addline({c:j, r:val.r}, temp_val, options);
4768
4850
  }
4769
4851
  } break;
4770
4852
  case 'Formula': {
4771
4853
  switch(val.val) {
4772
4854
  case 'String': last_formula = val; break;
4773
4855
  case 'Array Formula': throw "Array Formula unsupported";
4774
- default: addline(val.cell, {v:val.val, f:stringify_formula(val.formula, range, val.cell, supbooks), ixfe: val.cell.ixfe, XF:XFs[val.cell.ixfe], t:'n'}); // TODO: infer type from formula
4856
+ default: // TODO: infer type from formula
4857
+ temp_val = {v:val.val, ixfe:val.cell.ixfe, t:'n'};
4858
+ temp_val.XF = XFs[temp_val.ixfe];
4859
+ if(options.cellFormula) temp_val.f = stringify_formula(val.formula,range,val.cell,supbooks);
4860
+ if(temp_val.XF) try {
4861
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4862
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4863
+ } catch(e) { if(opts.WTF) throw e; }
4864
+ addline(val.cell, temp_val, options);
4775
4865
  }
4776
4866
  } break;
4777
4867
  case 'String': {
4778
4868
  if(last_formula) {
4779
4869
  last_formula.val = val;
4780
- addline(last_formula.cell, {v:last_formula.val, f:stringify_formula(last_formula.formula, range, last_formula.cell, supbooks), ixfe: last_formula.cell.ixfe, t:'s'});
4870
+ temp_val = {v:last_formula.val, ixfe:last_formula.cell.ixfe, t:'s'};
4871
+ temp_val.XF = XFs[temp_val.ixfe];
4872
+ if(options.cellFormula) temp_val.f = stringify_formula(last_formula.formula, range, last_formula.cell, supbooks);
4873
+ if(temp_val.XF) try {
4874
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4875
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4876
+ } catch(e) { if(opts.WTF) throw e; }
4877
+ addline(last_formula.cell, temp_val, options);
4781
4878
  last_formula = null;
4782
4879
  }
4783
4880
  } break;
@@ -4785,11 +4882,27 @@ function parse_workbook(blob) {
4785
4882
  /* console.error(val); */
4786
4883
  } break;
4787
4884
  case 'ShrFmla': {
4788
- out[last_cell].f = stringify_formula(val[0], range, lastcell, supbooks);
4885
+ if(!cell_valid) break;
4886
+ if(options.cellFormula) out[last_cell].f = stringify_formula(val[0], range, lastcell, supbooks);
4789
4887
  shared_formulae[last_cell] = val[0];
4790
4888
  } break;
4791
4889
  case 'LabelSst': {
4792
- addline({c:val.c, r:val.r}, {v:JSON.stringify(sst[val.isst]), ixfe:val.ixfe, t:'s'});
4890
+ temp_val={v:sst[val.isst].t, ixfe:val.ixfe, t:'s'};
4891
+ temp_val.XF = XFs[temp_val.ixfe];
4892
+ if(temp_val.XF) try {
4893
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4894
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4895
+ } catch(e) { if(opts.WTF) throw e; }
4896
+ addline({c:val.c, r:val.r}, temp_val, options);
4897
+ } break;
4898
+ case 'Label': {
4899
+ /* Some writers erroneously write Label */
4900
+ temp_val = {v:val.val, ixfe:val.ixfe, XF:XFs[val.ixfe], t:'s'};
4901
+ if(temp_val.XF) try {
4902
+ temp_val.w=SSF.format(temp_val.XF.ifmt||0, temp_val.v);
4903
+ if(options.cellNF) temp_val.z = SSF._table[temp_val.XF.ifmt||0];
4904
+ } catch(e) { if(opts.WTF) throw e; }
4905
+ addline({c:val.c, r:val.r}, temp_val, options);
4793
4906
  } break;
4794
4907
  case 'Dimensions': {
4795
4908
  range = val;
@@ -4824,7 +4937,6 @@ function parse_workbook(blob) {
4824
4937
  case 'GUIDTypeLib': {
4825
4938
 
4826
4939
  } break;
4827
- case 'Note': break;
4828
4940
 
4829
4941
  case 'MergeCells': break;
4830
4942
 
@@ -4856,6 +4968,7 @@ function parse_workbook(blob) {
4856
4968
  case 'CondFmt': case 'CF': case 'CF12': case 'CFEx': break;
4857
4969
 
4858
4970
  /* Comments */
4971
+ case 'Note': break;
4859
4972
  case 'NameCmt': break;
4860
4973
 
4861
4974
  /* Chart */
@@ -4873,7 +4986,7 @@ function parse_workbook(blob) {
4873
4986
  case 'DataFormat': case 'SerToCrt': case 'FontX': break;
4874
4987
  case 'CatSerRange': case 'AxcExt': case 'SerFmt': break;
4875
4988
  case 'ShtProps': break;
4876
- case 'DefaultText': case 'Text': case 'Label': case 'CatLab': break;
4989
+ case 'DefaultText': case 'Text': case 'CatLab': break;
4877
4990
  case 'DataLabExtContents': break;
4878
4991
  case 'Legend': case 'LegendException': break;
4879
4992
  case 'Pie': case 'Scatter': break;
@@ -4948,90 +5061,93 @@ function parse_workbook(blob) {
4948
5061
  //lst.filter(function(x) { return x[0] === 'Formula';}).forEach(function(x){console.log(x[2].cell,x[2].formula);});
4949
5062
  wb.Directory=sheetnamesraw;
4950
5063
  wb.SheetNames=sheetnamesraw;
4951
- wb.Sheets=Sheets;
5064
+ if(!options.bookSheets) wb.Sheets=Sheets;
4952
5065
  wb.Preamble=Preamble;
4953
5066
  wb.Strings = sst;
5067
+ wb.SSF = SSF.get_table();
4954
5068
  if(opts.enc) wb.Encryption = opts.enc;
4955
5069
  return wb;
4956
5070
  }
4957
- if(Workbook) WorkbookP = parse_workbook(Workbook.content);
4958
- else throw new Error("Cannot find Workbook stream");
4959
5071
  if(CompObj) CompObjP = parse_compobj(CompObj);
4960
-
5072
+ if(options.bookProps && !options.bookSheets) WorkbookP = {};
5073
+ else {
5074
+ if(Workbook) WorkbookP = parse_workbook(Workbook.content, options);
5075
+ else throw new Error("Cannot find Workbook stream");
5076
+ }
5077
+
5078
+ var props = {};
5079
+ for(var y in cfb.Summary) props[y] = cfb.Summary[y];
5080
+ for(y in cfb.DocSummary) props[y] = cfb.DocSummary[y];
5081
+ WorkbookP.Props = WorkbookP.Custprops = props; /* TODO: split up properties */
5082
+ if(options.bookFiles) WorkbookP.cfb = cfb;
5083
+ WorkbookP.CompObjP = CompObjP;
4961
5084
  return WorkbookP;
4962
5085
  }
4963
5086
 
4964
- function sheet_to_row_object_array(sheet){
4965
- var val, rowObject, range, columnHeaders, emptyRow, C;
4966
- var outSheet = [];
4967
- if (sheet["!ref"]) {
4968
- range = decode_range(sheet["!ref"]);
4969
-
4970
- columnHeaders = {};
4971
- for (C = range.s.c; C <= range.e.c; ++C) {
4972
- val = sheet[encode_cell({
4973
- c: C,
4974
- r: range.s.r
4975
- })];
4976
- if(val){
4977
- switch(val.t) {
4978
- case 's': case 'str': columnHeaders[C] = JSON.parse(val.v); break;
4979
- case 'n': columnHeaders[C] = val.v; break;
4980
- }
4981
- }
4982
- }
5087
+ function format_cell(cell, v) {
5088
+ if(!cell) return "";
5089
+ if(typeof cell.w !== 'undefined') return cell.w;
5090
+ if(typeof v === 'undefined') v = cell.v;
5091
+ if(!cell.XF) return v;
5092
+ try { cell.w = SSF.format(cell.XF.ifmt||0, v); } catch(e) { return v; }
5093
+ return cell.w;
5094
+ }
4983
5095
 
4984
- for (var R = range.s.r + 1; R <= range.e.r; ++R) {
4985
- emptyRow = true;
4986
- //Row number is recorded in the prototype
4987
- //so that it doesn't appear when stringified.
4988
- rowObject = Object.create({ __rowNum__ : R });
4989
- for (C = range.s.c; C <= range.e.c; ++C) {
4990
- val = sheet[encode_cell({
4991
- c: C,
4992
- r: R
4993
- })];
4994
- var v = (val || {}).v;
4995
- if(val !== undefined) switch(val.t){
4996
- case 's': case 'str':
4997
- if(v !== undefined) v = JSON.parse(v);
4998
- /* falls through */
4999
- case 'b': case 'n':
5000
- if(v !== undefined) {
5001
- rowObject[columnHeaders[C]] = v;
5002
- emptyRow = false;
5003
- }
5004
- break;
5005
- case 'e': break; /* throw */
5006
- default: throw 'unrecognized type ' + val.t;
5007
- }
5096
+ function sheet_to_row_object_array(sheet, opts){
5097
+ var val, row, r, hdr = {}, isempty, R, C, v;
5098
+ var out = [];
5099
+ opts = opts || {};
5100
+ if(!sheet || !sheet["!ref"]) return out;
5101
+ r = utils.decode_range(sheet["!ref"]);
5102
+ for(R=r.s.r, C = r.s.c; C <= r.e.c; ++C) {
5103
+ val = sheet[utils.encode_cell({c:C,r:R})];
5104
+ if(!val) continue;
5105
+ hdr[C] = format_cell(val);
5106
+ }
5107
+
5108
+ for (R = r.s.r + 1; R <= r.e.r; ++R) {
5109
+ isempty = true;
5110
+ /* row index available as __rowNum__ */
5111
+ row = Object.create({ __rowNum__ : R });
5112
+ for (C = r.s.c; C <= r.e.c; ++C) {
5113
+ val = sheet[utils.encode_cell({c: C,r: R})];
5114
+ if(!val || !val.t) continue;
5115
+ v = (val || {}).v;
5116
+ switch(val.t){
5117
+ case 'e': continue; /* TODO: emit error text? */
5118
+ case 's': case 'str': break;
5119
+ case 'b': case 'n': break;
5120
+ default: throw 'unrecognized type ' + val.t;
5008
5121
  }
5009
- if(!emptyRow) {
5010
- outSheet.push(rowObject);
5122
+ if(typeof v !== 'undefined') {
5123
+ row[hdr[C]] = opts.raw ? v||val.v : format_cell(val, v);
5124
+ isempty = false;
5011
5125
  }
5012
5126
  }
5127
+ if(!isempty) out.push(row);
5013
5128
  }
5014
- return outSheet;
5015
- }
5016
-
5017
- function sheet_to_csv(sheet) {
5018
- var out = "";
5019
- if(sheet["!ref"]) {
5020
- var r = utils.decode_range(sheet["!ref"]);
5021
- for(var R = r.s.r; R <= r.e.r; ++R) {
5022
- var row = [];
5023
- for(var C = r.s.c; C <= r.e.c; ++C) {
5024
- var val = sheet[utils.encode_cell({c:C,r:R})];
5025
- if(!val) { row.push(""); continue; }
5026
- var fmt = 0;
5027
- if(val.XF) {
5028
- //console.log(val.XF, SSF._table[val.XF.ifmt], val.v)
5029
- val.v = SSF.format(val.XF.ifmt||0, val.v);
5030
- }
5031
- row.push(String(val.v).replace(/\\n/g,"\n").replace(/\\t/g,"\t").replace(/\\\\/g,"\\").replace(/\\\"/g,"\"\""));
5129
+ return out;
5130
+ }
5131
+
5132
+ function sheet_to_csv(sheet, opts) {
5133
+ var out = "", txt = "";
5134
+ opts = opts || {};
5135
+ if(!sheet || !sheet["!ref"]) return out;
5136
+ var r = utils.decode_range(sheet["!ref"]);
5137
+ var fs = opts.FS||",", rs = opts.RS||"\n";
5138
+
5139
+ for(var R = r.s.r; R <= r.e.r; ++R) {
5140
+ var row = [];
5141
+ for(var C = r.s.c; C <= r.e.c; ++C) {
5142
+ var val = sheet[utils.encode_cell({c:C,r:R})];
5143
+ if(!val) { row.push(""); continue; }
5144
+ txt = String(format_cell(val));
5145
+ if(txt.indexOf(fs) !== -1 || txt.indexOf(rs) !== -1 || txt.indexOf("\"") !== -1){
5146
+ txt = "\""+txt.replace(/"/g, '""') +"\"";
5032
5147
  }
5033
- out += row.join(",") + "\n";
5148
+ row.push(txt);
5034
5149
  }
5150
+ out += row.join(fs) + (rs);
5035
5151
  }
5036
5152
  return out;
5037
5153
  }
@@ -5043,7 +5159,8 @@ function get_formulae(ws) {
5043
5159
  var x = ws[y];
5044
5160
  var val = "";
5045
5161
  if(x.f) val = x.f;
5046
- else if(typeof x.v === 'number') val = x.v;
5162
+ else if(typeof x.w !== 'undefined') val = "'" + x.w;
5163
+ else if(typeof x.v === 'undefined') continue;
5047
5164
  else val = x.v;
5048
5165
  cmds.push(y + "=" + val);
5049
5166
  }
@@ -5063,13 +5180,14 @@ var utils = {
5063
5180
  sheet_to_csv: sheet_to_csv,
5064
5181
  make_csv: sheet_to_csv,
5065
5182
  get_formulae: get_formulae,
5183
+ format_cell: format_cell,
5066
5184
  sheet_to_row_object_array: sheet_to_row_object_array
5067
5185
  };
5068
5186
 
5069
5187
  function xlsread(f, options) {
5070
- return parse_xlscfb(CFB.read(f, options));
5188
+ return parse_xlscfb(CFB.read(f, options), options);
5071
5189
  }
5072
- var readFile = function(f) { return parse_xlscfb(CFB.read(f, {type:'file'})); };
5190
+ var readFile = function(f,o){return parse_xlscfb(CFB.read(f,{type:'file'}),o);};
5073
5191
  function decode_row(rowstr) { return Number(unfix_row(rowstr)) - 1; }
5074
5192
  function encode_row(row) { return "" + (row + 1); }
5075
5193
  function fix_row(cstr) { return cstr.replace(/([A-Z]|^)([0-9]+)$/,"$1$$$2"); }
@@ -5121,13 +5239,5 @@ XLS.read = xlsread;
5121
5239
  XLS.readFile = readFile;
5122
5240
  XLS.utils = utils;
5123
5241
  XLS.CFB = CFB;
5124
- if(typeof module !== 'undefined' && require.main === module ) {
5125
- var wb = readFile(process.argv[2] || 'Book1.xls');
5126
- var target_sheet = process.argv[3] || '';
5127
- if(target_sheet === '') target_sheet = wb.Directory[0];
5128
- var ws = wb.Sheets[target_sheet];
5129
- console.log(target_sheet);
5130
- console.log(make_csv(ws));
5131
- //console.log(get_formulae(ws));
5132
- }
5242
+ XLS.SSF = SSF;
5133
5243
  })(typeof exports !== 'undefined' ? exports : XLS);