Skip to content

Commit f002afa

Browse files
committed
version bump 0.12.0: extendscript fixes
- ExtendScript write quirks (fixes #986 h/t @grefel) - BIFF8 write number formats (fixes #987 h/t @scwood) - xlsx.extendscript.js library script - readFile / writeFile support ExtendScript - flow update
1 parent fb97bf1 commit f002afa

44 files changed

Lines changed: 29922 additions & 260 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

.flowconfig

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,3 +36,6 @@ module.file_ext=.js
3636
module.file_ext=.njs
3737
module.ignore_non_literal_requires=true
3838
suppress_comment= \\(.\\|\n\\)*\\$FlowIgnore
39+
40+
[lints]
41+
deprecated-declare-exports=off

CHANGELOG.md

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,11 @@ This log is intended to keep track of backwards-incompatible changes, including
44
but not limited to API changes and file location changes. Minor behavioral
55
changes may not be included if they are not expected to break existing code.
66

7-
## 0.11.19
7+
## 0.12.0 (2018-02-08)
8+
9+
* Extendscript target script in NPM package
10+
11+
## 0.11.19 (2018-02-03)
812

913
* Error on empty workbook
1014

Makefile

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ dist: dist-deps $(TARGET) bower.json ## Prepare JS files for distribution
6363
misc/strip_sourcemap.sh dist/$(LIB).core.min.js
6464
uglifyjs $(DISTHDR) $(REQS) $(ADDONS) dist/$(TARGET) $(AUXTARGETS) $(UGLIFYOPTS) -o dist/$(LIB).full.min.js --source-map dist/$(LIB).full.min.map --preamble "$$(head -n 1 bits/00_header.js)"
6565
misc/strip_sourcemap.sh dist/$(LIB).full.min.js
66+
cat <(head -n 1 bits/00_header.js) shim.js $(DISTHDR) $(REQS) dist/$(TARGET) > dist/$(LIB).extendscript.js
6667

6768
.PHONY: dist-deps
6869
dist-deps: ## Copy dependencies for distribution
@@ -73,7 +74,7 @@ dist-deps: ## Copy dependencies for distribution
7374
.PHONY: aux
7475
aux: $(AUXTARGETS)
7576

76-
BYTEFILE=dist/xlsx.min.js dist/xlsx.{core,full}.min.js
77+
BYTEFILE=dist/xlsx.min.js dist/xlsx.{core,full}.min.js dist/xlsx.extendscript.js
7778
.PHONY: bytes
7879
bytes: ## Display minified and gzipped file sizes
7980
for i in $(BYTEFILE); do printj "%-30s %7d %10d" $$i $$(wc -c < $$i) $$(gzip --best --stdout $$i | wc -c); done

README.md

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,6 +316,23 @@ var workbook = XLSX.readFile('test.xlsx');
316316

317317
</details>
318318

319+
<details>
320+
<summary><b>Photoshop ExtendScript read a file</b> (click to show)</summary>
321+
322+
`readFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
323+
The specified path should be an absolute path:
324+
325+
```js
326+
#include "xlsx.extendscript.js"
327+
/* Read test.xlsx from the Documents folder */
328+
var workbook = XLSX.readFile(Folder.myDocuments + '/' + 'test.xlsx');
329+
/* DO SOMETHING WITH workbook HERE */
330+
```
331+
332+
The [`extendscript` demo](demos/extendscript/) includes a more complex example.
333+
334+
</details>
335+
319336
<details>
320337
<summary><b>Browser read TABLE element from page</b> (click to show)</summary>
321338

@@ -604,6 +621,23 @@ XLSX.writeFile(workbook, 'out.xlsb');
604621

605622
</details>
606623

624+
<details>
625+
<summary><b>Photoshop ExtendScript write a file</b> (click to show)</summary>
626+
627+
`writeFile` wraps the `File` logic in Photoshop and other ExtendScript targets.
628+
The specified path should be an absolute path:
629+
630+
```js
631+
#include "xlsx.extendscript.js"
632+
/* output format determined by filename */
633+
XLSX.writeFile(workbook, 'out.xlsx');
634+
/* at this point, out.xlsx is a file that you can distribute */
635+
```
636+
637+
The [`extendscript` demo](demos/extendscript/) includes a more complex example.
638+
639+
</details>
640+
607641
<details>
608642
<summary><b>Browser add TABLE element to page</b> (click to show)</summary>
609643

bits/01_version.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
XLSX.version = '0.11.19';
1+
XLSX.version = '0.12.0';

bits/19_fsutils.js

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ function blobify(data) {
99
}
1010
/* write or download file */
1111
function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
12-
/*global IE_SaveFile, Blob, navigator, saveAs, URL, document */
12+
/*global IE_SaveFile, Blob, navigator, saveAs, URL, document, File */
1313
if(typeof _fs !== 'undefined' && _fs.writeFileSync) return enc ? _fs.writeFileSync(fname, payload, enc) : _fs.writeFileSync(fname, payload);
1414
var data = (enc == "utf8") ? utf8write(payload) : payload;
1515
/*:: declare var IE_SaveFile: any; */
@@ -32,6 +32,25 @@ function write_dl(fname/*:string*/, payload/*:any*/, enc/*:?string*/) {
3232
}
3333
}
3434
}
35-
throw new Error("cannot initiate download");
35+
// $FlowIgnore
36+
if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
37+
// $FlowIgnore
38+
var out = File(fname); out.open("w"); out.encoding = "binary";
39+
if(Array.isArray(payload)) payload = a2s(payload);
40+
out.write(payload); out.close(); return payload;
41+
} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
42+
throw new Error("cannot save file " + fname);
3643
}
3744

45+
/* read binary data from file */
46+
function read_binary(path/*:string*/) {
47+
if(typeof _fs !== 'undefined') return _fs.readFileSync(path);
48+
// $FlowIgnore
49+
if(typeof $ !== 'undefined' && typeof File !== 'undefined' && typeof Folder !== 'undefined') try { // extendscript
50+
// $FlowIgnore
51+
var infile = File(path); infile.open("r"); infile.encoding = "binary";
52+
var data = infile.read(); infile.close();
53+
return data;
54+
} catch(e) { if(!e.message || !e.message.match(/onstruct/)) throw e; }
55+
throw new Error("Cannot access file " + path);
56+
}

bits/23_binutils.js

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,25 +3,25 @@ function read_double_le(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ {
33
var e = ((b[idx + 7] & 0x7f) << 4) + ((b[idx + 6] >>> 4) & 0x0f);
44
var m = (b[idx+6]&0x0f);
55
for(var i = 5; i >= 0; --i) m = m * 256 + b[idx + i];
6-
if(e == 0x7ff) return m == 0 ? s * Infinity : NaN;
6+
if(e == 0x7ff) return m == 0 ? (s * Infinity) : NaN;
77
if(e == 0) e = -1022;
88
else { e -= 1023; m += Math.pow(2,52); }
99
return s * Math.pow(2, e - 52) * m;
1010
}
1111

1212
function write_double_le(b/*:RawBytes|CFBlob*/, v/*:number*/, idx/*:number*/) {
13-
var bs = ((v < 0 || 1/v == -Infinity) ? 1 : 0) << 7, e = 0, m = 0;
14-
var av = bs ? -v : v;
13+
var bs = ((((v < 0) || (1/v == -Infinity)) ? 1 : 0) << 7), e = 0, m = 0;
14+
var av = bs ? (-v) : v;
1515
if(!isFinite(av)) { e = 0x7ff; m = isNaN(v) ? 0x6969 : 0; }
1616
else if(av == 0) e = m = 0;
1717
else {
1818
e = Math.floor(Math.log(av) / Math.LN2);
1919
m = av * Math.pow(2, 52 - e);
20-
if(e <= -1023 && (!isFinite(m) || m < Math.pow(2,52))) { e = -1022; }
20+
if((e <= -1023) && (!isFinite(m) || (m < Math.pow(2,52)))) { e = -1022; }
2121
else { m -= Math.pow(2,52); e+=1023; }
2222
}
2323
for(var i = 0; i <= 5; ++i, m/=256) b[idx + i] = m & 0xff;
24-
b[idx + 6] = ((e & 0x0f) << 4) | m & 0xf;
24+
b[idx + 6] = ((e & 0x0f) << 4) | (m & 0xf);
2525
b[idx + 7] = (e >> 4) | bs;
2626
}
2727

@@ -73,8 +73,8 @@ if(typeof cptable !== 'undefined') {
7373
}
7474

7575
var __readUInt8 = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx]; };
76-
var __readUInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+1]*(1<<8)+b[idx]; };
77-
var __readInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { var u = b[idx+1]*(1<<8)+b[idx]; return (u < 0x8000) ? u : (0xffff - u + 1) * -1; };
76+
var __readUInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+1]*(1<<8))+b[idx]; };
77+
var __readInt16LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { var u = (b[idx+1]*(1<<8))+b[idx]; return (u < 0x8000) ? u : ((0xffff - u + 1) * -1); };
7878
var __readUInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return b[idx+3]*(1<<24)+(b[idx+2]<<16)+(b[idx+1]<<8)+b[idx]; };
7979
var __readInt32LE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx+3]<<24)|(b[idx+2]<<16)|(b[idx+1]<<8)|b[idx]; };
8080
var __readInt32BE = function(b/*:RawBytes|CFBlob*/, idx/*:number*/)/*:number*/ { return (b[idx]<<24)|(b[idx+1]<<16)|(b[idx+2]<<8)|b[idx+3]; };
@@ -85,7 +85,7 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
8585
case 'dbcs':
8686
loc = this.l;
8787
if(has_buf && Buffer.isBuffer(this)) o = this.slice(this.l, this.l+2*size).toString("utf16le");
88-
else for(i = 0; i != size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
88+
else for(i = 0; i < size; ++i) { o+=String.fromCharCode(__readUInt16LE(this, loc)); loc+=2; }
8989
size *= 2;
9090
break;
9191

@@ -116,7 +116,7 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
116116

117117
/* sbcs and dbcs support continue records in the SST way TODO codepages */
118118
case 'dbcs-cont': o = ""; loc = this.l;
119-
for(i = 0; i != size; ++i) {
119+
for(i = 0; i < size; ++i) {
120120
if(this.lens && this.lens.indexOf(loc) !== -1) {
121121
w = __readUInt8(this, loc);
122122
this.l = loc + 1;
@@ -150,7 +150,7 @@ function ReadShift(size/*:number*/, t/*:?string*/)/*:number|string*/ {
150150
case 1: oI = __readUInt8(this, this.l); this.l++; return oI;
151151
case 2: oI = (t === 'i' ? __readInt16LE : __readUInt16LE)(this, this.l); this.l += 2; return oI;
152152
case 4: case -4:
153-
if(t === 'i' || (this[this.l+3] & 0x80)===0) { oI = (size > 0 ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
153+
if(t === 'i' || ((this[this.l+3] & 0x80)===0)) { oI = ((size > 0) ? __readInt32LE : __readInt32BE)(this, this.l); this.l += 4; return oI; }
154154
else { oR = __readUInt32LE(this, this.l); this.l += 4; } return oR;
155155
case 8: case -8:
156156
if(t === 'f') {
@@ -179,20 +179,20 @@ function WriteShift(t/*:number*/, val/*:string|number*/, f/*:?string*/)/*:any*/
179179
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
180180
val = val.replace(/[^\x00-\x7F]/g, "_");
181181
/*:: if(typeof val !== 'string') throw new Error("unreachable"); */
182-
for(i = 0; i != val.length; ++i) this[this.l + i] = val.charCodeAt(i) & 0xFF;
182+
for(i = 0; i != val.length; ++i) this[this.l + i] = (val.charCodeAt(i) & 0xFF);
183183
size = val.length;
184184
} else if(f === 'hex') {
185185
for(; i < t; ++i) {
186186
/*:: if(typeof val !== "string") throw new Error("unreachable"); */
187-
this[this.l++] = parseInt(val.slice(2*i, 2*i+2), 16)||0;
187+
this[this.l++] = (parseInt(val.slice(2*i, 2*i+2), 16)||0);
188188
} return this;
189189
} else if(f === 'utf16le') {
190190
/*:: if(typeof val !== "string") throw new Error("unreachable"); */
191191
var end/*:number*/ = this.l + t;
192192
for(i = 0; i < Math.min(val.length, t); ++i) {
193193
var cc = val.charCodeAt(i);
194-
this[this.l++] = cc & 0xff;
195-
this[this.l++] = cc >> 8;
194+
this[this.l++] = (cc & 0xff);
195+
this[this.l++] = (cc >> 8);
196196
}
197197
while(this.l < end) this[this.l++] = 0;
198198
return this;

bits/24_hoppers.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,13 @@ function buf_array()/*:BufArray*/ {
3131

3232
var endbuf = function ba_endbuf() {
3333
if(!curbuf) return;
34-
if(curbuf.length > curbuf.l) curbuf = curbuf.slice(0, curbuf.l);
34+
if(curbuf.length > curbuf.l) { curbuf = curbuf.slice(0, curbuf.l); curbuf.l = curbuf.length; }
3535
if(curbuf.length > 0) bufs.push(curbuf);
3636
curbuf = null;
3737
};
3838

3939
var next = function ba_next(sz/*:number*/)/*:Block*/ {
40-
if(curbuf && sz < curbuf.length - curbuf.l) return curbuf;
40+
if(curbuf && (sz < (curbuf.length - curbuf.l))) return curbuf;
4141
endbuf();
4242
return (curbuf = newblk(Math.max(sz+1, blksz)));
4343
};
@@ -47,7 +47,7 @@ function buf_array()/*:BufArray*/ {
4747
return __toBuffer([bufs]);
4848
};
4949

50-
var push = function ba_push(buf) { endbuf(); curbuf = buf; next(blksz); };
50+
var push = function ba_push(buf) { endbuf(); curbuf = buf; if(curbuf.l == null) curbuf.l = curbuf.length; next(blksz); };
5151

5252
return ({ next:next, push:push, end:end, _bufs:bufs }/*:any*/);
5353
}

bits/28_binstructs.js

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -112,17 +112,17 @@ var write_RelID = write_XLNullableWideString;
112112
/* [MS-XLS] 2.5.217 */
113113
function parse_RkNumber(data)/*:number*/ {
114114
var b = data.slice(data.l, data.l+4);
115-
var fX100 = b[0] & 1, fInt = b[0] & 2;
115+
var fX100 = (b[0] & 1), fInt = (b[0] & 2);
116116
data.l+=4;
117117
b[0] &= 0xFC; // b[0] &= ~3;
118118
var RK = fInt === 0 ? __double([0,0,0,0,b[0],b[1],b[2],b[3]],0) : __readInt32LE(b,0)>>2;
119-
return fX100 ? RK/100 : RK;
119+
return fX100 ? (RK/100) : RK;
120120
}
121121
function write_RkNumber(data/*:number*/, o) {
122122
if(o == null) o = new_buf(4);
123123
var fX100 = 0, fInt = 0, d100 = data * 100;
124-
if(data == (data | 0) && data >= -(1<<29) && data < (1 << 29)) { fInt = 1; }
125-
else if(d100 == (d100 | 0) && d100 >= -(1<<29) && d100 < (1 << 29)) { fInt = 1; fX100 = 1; }
124+
if((data == (data | 0)) && (data >= -(1<<29)) && (data < (1 << 29))) { fInt = 1; }
125+
else if((d100 == (d100 | 0)) && (d100 >= -(1<<29)) && (d100 < (1 << 29))) { fInt = 1; fX100 = 1; }
126126
if(fInt) o.write_shift(-4, ((fX100 ? d100 : data) << 2) + (fX100 + 2));
127127
else throw new Error("unsupported RkNumber " + data); // TODO
128128
}

bits/39_xlsbiff.js

Lines changed: 27 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -249,7 +249,8 @@ function write_BoundSheet8(data, opts) {
249249
o.write_shift(1, data.name.length);
250250
if(opts.biff >= 8) o.write_shift(1, 1);
251251
o.write_shift(w * data.name.length, data.name, opts.biff < 8 ? 'sbcs' : 'utf16le');
252-
return o.slice(0, o.l);
252+
var out = o.slice(0, o.l);
253+
out.l = o.l; return out;
253254
}
254255

255256
/* 2.4.265 TODO */
@@ -393,10 +394,10 @@ function parse_Label(blob, length, opts) {
393394
cell.val = str;
394395
return cell;
395396
}
396-
function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, opts) {
397+
function write_Label(R/*:number*/, C/*:number*/, v/*:string*/, os/*:number*/, opts) {
397398
var b8 = !opts || opts.biff == 8;
398399
var o = new_buf(6 + 2 + (+b8) + (1 + b8) * v.length);
399-
write_XLSCell(R, C, 0, o);
400+
write_XLSCell(R, C, os, o);
400401
o.write_shift(2, v.length);
401402
if(b8) o.write_shift(1, 1);
402403
o.write_shift((1 + b8) * v.length, v, b8 ? 'utf16le' : 'sbcs');
@@ -410,6 +411,14 @@ function parse_Format(blob, length, opts) {
410411
var fmtstr = parse_XLUnicodeString2(blob, 0, opts);
411412
return [numFmtId, fmtstr];
412413
}
414+
function write_Format(i/*:number*/, f/*:string*/, o) {
415+
if(!o) o = new_buf(6 + 4 * f.length);
416+
o.write_shift(2, i);
417+
write_XLUnicodeString(f, null, o);
418+
var out = (o.length > o.l) ? o.slice(0, o.l) : o;
419+
if(o.l == null) o.l = o.length;
420+
return out;
421+
}
413422
var parse_BIFF2Format = parse_XLUnicodeString2;
414423

415424
/* 2.4.90 */
@@ -515,6 +524,17 @@ function parse_XF(blob, length, opts) {
515524
o.data = parse_CellStyleXF(blob, length, o.fStyle, opts);
516525
return o;
517526
}
527+
function write_XF(data, ixfeP, o) {
528+
if(!o) o = new_buf(20);
529+
o.write_shift(2, 0);
530+
o.write_shift(2, data.numFmtId||0);
531+
o.write_shift(2, 0);
532+
o.write_shift(4, 0);
533+
o.write_shift(4, 0);
534+
o.write_shift(4, 0);
535+
o.write_shift(2, 0);
536+
return o;
537+
}
518538

519539
/* 2.4.134 */
520540
function parse_Guts(blob) {
@@ -542,9 +562,9 @@ function parse_BoolErr(blob, length, opts) {
542562
cell.t = (val === true || val === false) ? 'b' : 'e';
543563
return cell;
544564
}
545-
function write_BoolErr(R/*:number*/, C/*:number*/, v, opts, t/*:string*/) {
565+
function write_BoolErr(R/*:number*/, C/*:number*/, v, os/*:number*/, opts, t/*:string*/) {
546566
var o = new_buf(8);
547-
write_XLSCell(R, C, 0, o);
567+
write_XLSCell(R, C, os, o);
548568
write_Bes(v, t, o);
549569
return o;
550570
}
@@ -556,9 +576,9 @@ function parse_Number(blob) {
556576
cell.val = xnum;
557577
return cell;
558578
}
559-
function write_Number(R/*:number*/, C/*:number*/, v/*::, opts*/) {
579+
function write_Number(R/*:number*/, C/*:number*/, v, os/*:: :number, opts*/) {
560580
var o = new_buf(14);
561-
write_XLSCell(R, C, 0, o);
581+
write_XLSCell(R, C, os, o);
562582
write_Xnum(v, o);
563583
return o;
564584
}

0 commit comments

Comments
 (0)