From 17b1a8de5a305342bd23cf02567df1fe99eff59b Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sun, 4 Mar 2018 22:49:40 -0500 Subject: [PATCH] version bump 1.05: non-display char strict search --- .eslintrc | 8 +- Makefile | 4 +- README.md | 1 + bits/04_base64.js | 7 +- bits/30_cfbheader.js | 2 +- bits/31_version.js | 2 +- bits/40_parse.js | 1 + bits/43_rbtree.js | 2 +- bits/70_find.js | 9 +- cfb.flow.js | 23 ++- cfb.js | 23 ++- dist/cfb.js | 23 ++- dist/cfb.min.js | 2 +- dist/cfb.min.map | 2 +- dist/xlscfb.js | 16 +- index.html | 8 +- package.json | 10 +- shim.js | 388 ++++++------------------------------------- test.js | 28 +++- types/bin_cfb.ts | 9 +- xlscfb.flow.js | 16 +- xlscfb.js | 16 +- 22 files changed, 171 insertions(+), 429 deletions(-) diff --git a/.eslintrc b/.eslintrc index 8dc3744..f020fa2 100644 --- a/.eslintrc +++ b/.eslintrc @@ -2,7 +2,7 @@ "env": { "shared-node-browser":true }, "globals": {}, "parserOptions": { - "ecmaVersion": 3, + "ecmaVersion": 3 }, "plugins": [ "html", "json" ], "extends": "eslint:recommended", @@ -12,7 +12,13 @@ "curly": 0, "no-bitwise": 0, "no-console": 0, + "no-control-regex": 0, + "no-empty": 0, "no-trailing-spaces": 2, + "no-use-before-define": [ 1, { + "functions":false, "classes":true, "variables":false + }], + "no-useless-escape": 0, "semi": [ 2, "always" ] } } diff --git a/Makefile b/Makefile index aa68235..4b778de 100644 --- a/Makefile +++ b/Makefile @@ -39,9 +39,9 @@ clean-data: .PHONY: init init: ## Initial setup for development - if [ ! -e test_files ]; then git clone https://github.com/SheetJS/test_files; fi + if [ ! -e test_files ]; then git clone --depth=1 https://github.com/SheetJS/test_files; fi cd test_files; git pull; make - if [ ! -e test_files_pres ]; then git clone https://github.com/SheetJS/test_files_pres; fi + if [ ! -e test_files_pres ]; then git clone --depth=1 https://github.com/SheetJS/test_files_pres; fi cd test_files_pres; git pull .PHONY: dist diff --git a/README.md b/README.md index 877839d..33c1c04 100644 --- a/README.md +++ b/README.md @@ -98,6 +98,7 @@ controls the behavior: |------------|-----------------------------------------------------------------| | `"base64"` | string: Base64 encoding of the file | | `"binary"` | string: binary string (byte `n` is `data.charCodeAt(n)`) | +| `"file"` | string: path of file that will be created (nodejs only) | | (default) | buffer if available, array of 8-bit unsigned int otherwise | `CFB.writeFile(cfb, filename, opts)` creates a file with the specified name. diff --git a/bits/04_base64.js b/bits/04_base64.js index 9b922a4..a334d48 100644 --- a/bits/04_base64.js +++ b/bits/04_base64.js @@ -3,8 +3,7 @@ var Base64 = (function make_b64(){ return { encode: function(input/*:string*/)/*:string*/ { var o = ""; - var c1/*:number*/, c2/*:number*/, c3/*:number*/; - var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/; + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; for(var i = 0; i < input.length; ) { c1 = input.charCodeAt(i++); e1 = (c1 >> 2); @@ -23,9 +22,7 @@ var Base64 = (function make_b64(){ }, decode: function b64_decode(input/*:string*/)/*:string*/ { var o = ""; - var c1/*:number*/, c2/*:number*/, c3/*:number*/; - var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/; - // eslint-disable-next-line no-useless-escape + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; input = input.replace(/[^\w\+\/\=]/g, ""); for(var i = 0; i < input.length;) { e1 = map.indexOf(input.charAt(i++)); diff --git a/bits/30_cfbheader.js b/bits/30_cfbheader.js index 52e13d6..8f9c004 100644 --- a/bits/30_cfbheader.js +++ b/bits/30_cfbheader.js @@ -1,3 +1,3 @@ -/* [MS-CFB] v20130118 */ +/* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/; diff --git a/bits/31_version.js b/bits/31_version.js index cf1bf4a..062399d 100644 --- a/bits/31_version.js +++ b/bits/31_version.js @@ -1 +1 @@ -exports.version = '1.0.3'; +exports.version = '1.0.5'; diff --git a/bits/40_parse.js b/bits/40_parse.js index 7f133e1..1dc1d78 100644 --- a/bits/40_parse.js +++ b/bits/40_parse.js @@ -1,4 +1,5 @@ function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { +if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); var mver = 3; var ssz = 512; var nmfs = 0; // number of mini FAT sectors diff --git a/bits/43_rbtree.js b/bits/43_rbtree.js index 7e95175..52cc1f0 100644 --- a/bits/43_rbtree.js +++ b/bits/43_rbtree.js @@ -16,7 +16,7 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array*/, Paths/*:Arr if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } diff --git a/bits/70_find.js b/bits/70_find.js index 93c6d9a..b40de10 100644 --- a/bits/70_find.js +++ b/bits/70_find.js @@ -1,6 +1,5 @@ /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { - //return cfb.find(path); var UCFullPaths/*:Array*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths/*:Array*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k/*:boolean*/ = false; @@ -10,10 +9,12 @@ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; } diff --git a/cfb.flow.js b/cfb.flow.js index 6bf3436..e15022d 100644 --- a/cfb.flow.js +++ b/cfb.flow.js @@ -9,8 +9,7 @@ var Base64 = (function make_b64(){ return { encode: function(input/*:string*/)/*:string*/ { var o = ""; - var c1/*:number*/, c2/*:number*/, c3/*:number*/; - var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/; + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; for(var i = 0; i < input.length; ) { c1 = input.charCodeAt(i++); e1 = (c1 >> 2); @@ -29,9 +28,7 @@ var Base64 = (function make_b64(){ }, decode: function b64_decode(input/*:string*/)/*:string*/ { var o = ""; - var c1/*:number*/, c2/*:number*/, c3/*:number*/; - var e1/*:number*/, e2/*:number*/, e3/*:number*/, e4/*:number*/; - // eslint-disable-next-line no-useless-escape + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; input = input.replace(/[^\w\+\/\=]/g, ""); for(var i = 0; i < input.length;) { e1 = map.indexOf(input.charAt(i++)); @@ -177,10 +174,10 @@ type SectorList = { } type CFBFiles = {[n:string]:CFBEntry}; */ -/* [MS-CFB] v20130118 */ +/* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/; -exports.version = '1.0.3'; +exports.version = '1.0.5'; /* [MS-CFB] 2.6.4 */ function namecmp(l/*:string*/, r/*:string*/)/*:number*/ { var L = l.split("/"), R = r.split("/"); @@ -204,6 +201,7 @@ function filename(p/*:string*/)/*:string*/ { var fs/*:: = require('fs'); */; function get_fs() { return fs || (fs = require('fs')); } function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { +if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); var mver = 3; var ssz = 512; var nmfs = 0; // number of mini FAT sectors @@ -360,7 +358,7 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array*/, Paths/*:Arr if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } @@ -752,7 +750,6 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ { } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { - //return cfb.find(path); var UCFullPaths/*:Array*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths/*:Array*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k/*:boolean*/ = false; @@ -762,10 +759,12 @@ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; } diff --git a/cfb.js b/cfb.js index 3078b62..8bc6fd0 100644 --- a/cfb.js +++ b/cfb.js @@ -9,8 +9,7 @@ var Base64 = (function make_b64(){ return { encode: function(input) { var o = ""; - var c1, c2, c3; - var e1, e2, e3, e4; + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; for(var i = 0; i < input.length; ) { c1 = input.charCodeAt(i++); e1 = (c1 >> 2); @@ -29,9 +28,7 @@ var Base64 = (function make_b64(){ }, decode: function b64_decode(input) { var o = ""; - var c1, c2, c3; - var e1, e2, e3, e4; - // eslint-disable-next-line no-useless-escape + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; input = input.replace(/[^\w\+\/\=]/g, ""); for(var i = 0; i < input.length;) { e1 = map.indexOf(input.charAt(i++)); @@ -159,10 +156,10 @@ function new_buf(sz) { return o; } -/* [MS-CFB] v20130118 */ +/* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '1.0.3'; +exports.version = '1.0.5'; /* [MS-CFB] 2.6.4 */ function namecmp(l, r) { var L = l.split("/"), R = r.split("/"); @@ -186,6 +183,7 @@ function filename(p) { var fs; function get_fs() { return fs || (fs = require('fs')); } function parse(file, options) { +if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); var mver = 3; var ssz = 512; var nmfs = 0; // number of mini FAT sectors @@ -342,7 +340,7 @@ function build_full_paths(FI, FP, Paths) { if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } @@ -729,7 +727,6 @@ if(file.size > 0 && file.size < 0x1000) { } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb, path) { - //return cfb.find(path); var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k = false; @@ -739,10 +736,12 @@ function find(cfb, path) { var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; } diff --git a/dist/cfb.js b/dist/cfb.js index 3078b62..8bc6fd0 100644 --- a/dist/cfb.js +++ b/dist/cfb.js @@ -9,8 +9,7 @@ var Base64 = (function make_b64(){ return { encode: function(input) { var o = ""; - var c1, c2, c3; - var e1, e2, e3, e4; + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; for(var i = 0; i < input.length; ) { c1 = input.charCodeAt(i++); e1 = (c1 >> 2); @@ -29,9 +28,7 @@ var Base64 = (function make_b64(){ }, decode: function b64_decode(input) { var o = ""; - var c1, c2, c3; - var e1, e2, e3, e4; - // eslint-disable-next-line no-useless-escape + var c1=0, c2=0, c3=0, e1=0, e2=0, e3=0, e4=0; input = input.replace(/[^\w\+\/\=]/g, ""); for(var i = 0; i < input.length;) { e1 = map.indexOf(input.charAt(i++)); @@ -159,10 +156,10 @@ function new_buf(sz) { return o; } -/* [MS-CFB] v20130118 */ +/* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '1.0.3'; +exports.version = '1.0.5'; /* [MS-CFB] 2.6.4 */ function namecmp(l, r) { var L = l.split("/"), R = r.split("/"); @@ -186,6 +183,7 @@ function filename(p) { var fs; function get_fs() { return fs || (fs = require('fs')); } function parse(file, options) { +if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); var mver = 3; var ssz = 512; var nmfs = 0; // number of mini FAT sectors @@ -342,7 +340,7 @@ function build_full_paths(FI, FP, Paths) { if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } @@ -729,7 +727,6 @@ if(file.size > 0 && file.size < 0x1000) { } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb, path) { - //return cfb.find(path); var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k = false; @@ -739,10 +736,12 @@ function find(cfb, path) { var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; } diff --git a/dist/cfb.min.js b/dist/cfb.min.js index f2304a6..14a7ee5 100644 --- a/dist/cfb.min.js +++ b/dist/cfb.min.js @@ -1,2 +1,2 @@ /* cfb.js (C) 2013-present SheetJS -- http://sheetjs.com */ -var Base64=function e(){var e="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";return{encode:function(r){var t="";var i,n,a;var f,s,h,l;for(var o=0;o>2;n=r.charCodeAt(o++);s=(i&3)<<4|n>>4;a=r.charCodeAt(o++);h=(n&15)<<2|a>>6;l=a&63;if(isNaN(n)){h=l=64}else if(isNaN(a)){l=64}t+=e.charAt(f)+e.charAt(s)+e.charAt(h)+e.charAt(l)}return t},decode:function r(t){var i="";var n,a,f;var s,h,l,o;t=t.replace(/[^\w\+\/\=]/g,"");for(var c=0;c>4;i+=String.fromCharCode(n);l=e.indexOf(t.charAt(c++));a=(h&15)<<4|l>>2;if(l!==64){i+=String.fromCharCode(a)}o=e.indexOf(t.charAt(c++));f=(l&3)<<6|o;if(o!==64){i+=String.fromCharCode(f)}}return i}}}();var has_buf=typeof Buffer!=="undefined"&&typeof process!=="undefined"&&typeof process.versions!=="undefined"&&process.versions.node;function new_raw_buf(e){return new(has_buf?Buffer:Array)(e)}var s2a=function r(e){if(has_buf)return new Buffer(e,"binary");return e.split("").map(function(e){return e.charCodeAt(0)&255})};var chr0=/\u0000/g,chr1=/[\u0001-\u0006]/g;var __toBuffer=function(e){var r=[];for(var t=0;t0&&Buffer.isBuffer(e[0][0])?Buffer.concat(e[0]):___toBuffer(e)};s2a=function(e){return new Buffer(e,"binary")};bconcat=function(e){return Buffer.isBuffer(e[0])?Buffer.concat(e):__bconcat(e)}}var __readUInt8=function(e,r){return e[r]};var __readUInt16LE=function(e,r){return e[r+1]*(1<<8)+e[r]};var __readInt16LE=function(e,r){var t=e[r+1]*(1<<8)+e[r];return t<32768?t:(65535-t+1)*-1};var __readUInt32LE=function(e,r){return e[r+3]*(1<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};var __readInt32LE=function(e,r){return(e[r+3]<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};function ReadShift(e,r){var t,i,n=0;switch(e){case 1:t=__readUInt8(this,this.l);break;case 2:t=(r!=="i"?__readUInt16LE:__readInt16LE)(this,this.l);break;case 4:t=__readInt32LE(this,this.l);break;case 16:n=2;i=__hexlify(this,this.l,e);}this.l+=e;if(n===0)return t;return i}var __writeUInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>>8&255;e[t+2]=r>>>16&255;e[t+3]=r>>>24&255};var __writeInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>8&255;e[t+2]=r>>16&255;e[t+3]=r>>24&255};function WriteShift(e,r,t){var i=0,n=0;switch(t){case"hex":for(;n>8}while(this.l>>=8;this[this.l+1]=r&255;break;case 4:i=4;__writeUInt32LE(this,r,this.l);break;case-4:i=4;__writeInt32LE(this,r,this.l);break;}this.l+=i;return this}function CheckField(e,r){var t=__hexlify(this,this.l,e.length>>1);if(t!==e)throw new Error(r+"Expected "+e+" saw "+t);this.l+=e.length>>1}function prep_blob(e,r){e.l=r;e.read_shift=ReadShift;e.chk=CheckField;e.write_shift=WriteShift}function new_buf(e){var r=new_raw_buf(e);prep_blob(r,0);return r}var CFB=function t(){var e={};e.version="1.0.3";function r(e,r){var t=e.split("/"),i=r.split("/");for(var n=0,a=0,f=Math.min(t.length,i.length);n0&&c!==y)C[c].name="!MiniFAT";C[w[0]].name="!FAT";C.fat_addrs=w;C.ssz=i;var S={},A=[],m=[],B=[];v(f,C,E,A,n,S,m,c);o(m,B,A);A.shift();var L={FileIndex:m,FullPaths:B};if(r&&r.raw)L.raw={header:g,sectors:E};return L}function s(e){e.chk(S,"Header Signature: ");e.chk(m,"CLSID: ");var r=e.read_shift(2,"u");return[e.read_shift(2,"u"),r]}function h(e,r){var t=9;e.l+=2;switch(t=e.read_shift(2)){case 9:if(r!=3)throw new Error("Sector Shift: Expected 9 saw "+t);break;case 12:if(r!=4)throw new Error("Sector Shift: Expected 12 saw "+t);break;default:throw new Error("Sector Shift: Expected 9 or 12 saw "+t);}e.chk("0600","Mini Sector Shift: ");e.chk("000000000000","Reserved: ")}function l(e,r){var t=Math.ceil(e.length/r)-1;var i=[];for(var n=1;n0&&f>=0){a.push(r.slice(f*C,f*C+C));n-=C;f=__readInt32LE(t,f*4)}if(a.length===0)return new_buf(0);return bconcat(a).slice(0,e.size)}function u(e,r,t,i,n){var a=y;if(e===y){if(r!==0)throw new Error("DIFAT chain shorter than expected")}else if(e!==-1){var f=t[e],s=(i>>>2)-1;if(!f)return;for(var h=0;h=0;){n[h]=true;a[a.length]=h;f.push(e[h]);var o=t[Math.floor(h*4/i)];l=h*4&s;if(i<4+l)throw new Error("FAT boundary crossed: "+h+" 4 "+i);if(!e[o])break;h=__readInt32LE(e[o],l)}return{nodes:a,data:__toBuffer([f])}}function d(e,r,t,i){var n=e.length,a=[];var f=[],s=[],h=[];var l=i-1,o=0,c=0,u=0,_=0;for(o=0;o=n)u-=n;if(f[u])continue;h=[];for(c=u;c>=0;){f[c]=true;s[s.length]=c;h.push(e[c]);var d=t[Math.floor(c*4/i)];_=c*4&l;if(i<4+_)throw new Error("FAT boundary crossed: "+c+" 4 "+i);if(!e[d])break;c=__readInt32LE(e[d],_)}a[u]={nodes:s,data:__toBuffer([h])}}return a}function v(e,r,t,i,n,a,f,s){var h=0,l=i.length?2:0;var o=r[e].data;var u=0,d=0,v;for(;u0&&h!==y)r[h].name="!StreamData"}else if(F.size>=4096){F.storage="fat";if(r[F.start]===undefined)r[F.start]=_(t,F.start,r.fat_addrs,r.ssz);r[F.start].name=F.name;F.content=r[F.start].data.slice(0,F.size)}else{F.storage="minifat";if(F.size<0)F.size=0;else if(h!==y&&F.start!==y&&r[h]){F.content=c(F,r[h].data,(r[s]||{}).data)}}if(F.content)prep_blob(F.content,0);a[v]=F;f.push(F)}}function w(e,r){return new Date((__readUInt32LE(e,r+4)/1e7*Math.pow(2,32)+__readUInt32LE(e,r)/1e7-11644473600)*1e3)}function p(e,r){a();return f(n.readFileSync(e),r)}function F(e,r){switch(r&&r.type||"base64"){case"file":return p(e,r);case"base64":return f(s2a(Base64.decode(e)),r);case"binary":return f(s2a(e),r);}return f(e,r)}function g(e,r){var t=r||{},i=t.root||"Root Entry";if(!e.FullPaths)e.FullPaths=[];if(!e.FileIndex)e.FileIndex=[];if(e.FullPaths.length!==e.FileIndex.length)throw new Error("inconsistent CFB structure");if(e.FullPaths.length===0){e.FullPaths[0]=i+"/";e.FileIndex[0]={name:i,type:5}}if(t.CLSID)e.FileIndex[0].clsid=t.CLSID;I(e)}function I(e){var r="Sh33tJ5";if(CFB.find(e,"/"+r))return;var t=new_buf(4);t[0]=55;t[1]=t[3]=50;t[2]=54;e.FileIndex.push({name:r,type:2,content:t,size:4,L:69,R:69,C:69});e.FullPaths.push(e.FullPaths[0]+r);b(e)}function b(e,n){g(e);var a=false,f=false;for(var s=e.FullPaths.length-1;s>=0;--s){var h=e.FileIndex[s];switch(h.type){case 0:if(f)a=true;else{e.FileIndex.pop();e.FullPaths.pop()}break;case 1:;case 2:;case 5:f=true;if(isNaN(h.R*h.L*h.C))a=true;if(h.R>-1&&h.L>-1&&h.R==h.L)a=true;break;default:a=true;break;}}if(!a&&!n)return;var l=new Date(1987,1,19),o=0;var c=[];for(s=0;s1?1:-1;_.size=0;_.type=5}else if(d.slice(-1)=="/"){for(o=s+1;o=c.length?-1:o;for(o=s+1;o=c.length?-1:o;_.type=1}else{if(t(e.FullPaths[s+1]||"")==t(d))_.R=s+1;_.type=2}}}function x(e,r){var t=r||{};b(e);var i=function(e){var r=0,t=0;for(var i=0;i0){if(a<4096)r+=a+63>>6;else t+=a+511>>9}}var f=e.FullPaths.length+3>>2;var s=r+7>>3;var h=r+127>>7;var l=s+t+f+h;var o=l+127>>7;var c=o<=109?0:Math.ceil((o-109)/127);while(l+o+c+127>>7>o)c=++o<=109?0:Math.ceil((o-109)/127);var u=[1,c,o,h,f,t,r,0];e.FileIndex[0].size=r<<6;u[7]=(e.FileIndex[0].start=u[0]+u[1]+u[2]+u[3]+u[4]+u[5])+(u[6]+7>>3);return u}(e);var n=new_buf(i[7]<<9);var a=0,f=0;{for(a=0;a<8;++a)n.write_shift(1,A[a]);for(a=0;a<8;++a)n.write_shift(2,0);n.write_shift(2,62);n.write_shift(2,3);n.write_shift(2,65534);n.write_shift(2,9);n.write_shift(2,6);for(a=0;a<3;++a)n.write_shift(2,0);n.write_shift(4,0);n.write_shift(4,i[2]);n.write_shift(4,i[0]+i[1]+i[2]+i[3]-1);n.write_shift(4,0);n.write_shift(4,1<<12);n.write_shift(4,i[3]?i[0]+i[1]+i[2]-1:y);n.write_shift(4,i[3]);n.write_shift(-4,i[1]?i[0]-1:y);n.write_shift(4,i[1]);for(a=0;a<109;++a)n.write_shift(-4,a>9)}s(i[6]+7>>3);while(n.l&511)n.write_shift(-4,B.ENDOFCHAIN);f=a=0;for(h=0;h=4096)continue;o.start=f;s(l+63>>6)}while(n.l&511)n.write_shift(-4,B.ENDOFCHAIN);for(a=0;a=4096){n.l=o.start+1<<9;for(h=0;h0&&o.size<4096){for(h=0;h>2;n=r.charCodeAt(o++);s=(i&3)<<4|n>>4;a=r.charCodeAt(o++);h=(n&15)<<2|a>>6;l=a&63;if(isNaN(n)){h=l=64}else if(isNaN(a)){l=64}t+=e.charAt(f)+e.charAt(s)+e.charAt(h)+e.charAt(l)}return t},decode:function r(t){var i="";var n=0,a=0,f=0,s=0,h=0,l=0,o=0;t=t.replace(/[^\w\+\/\=]/g,"");for(var c=0;c>4;i+=String.fromCharCode(n);l=e.indexOf(t.charAt(c++));a=(h&15)<<4|l>>2;if(l!==64){i+=String.fromCharCode(a)}o=e.indexOf(t.charAt(c++));f=(l&3)<<6|o;if(o!==64){i+=String.fromCharCode(f)}}return i}}}();var has_buf=typeof Buffer!=="undefined"&&typeof process!=="undefined"&&typeof process.versions!=="undefined"&&process.versions.node;function new_raw_buf(e){return new(has_buf?Buffer:Array)(e)}var s2a=function r(e){if(has_buf)return new Buffer(e,"binary");return e.split("").map(function(e){return e.charCodeAt(0)&255})};var chr0=/\u0000/g,chr1=/[\u0001-\u0006]/g;var __toBuffer=function(e){var r=[];for(var t=0;t0&&Buffer.isBuffer(e[0][0])?Buffer.concat(e[0]):___toBuffer(e)};s2a=function(e){return new Buffer(e,"binary")};bconcat=function(e){return Buffer.isBuffer(e[0])?Buffer.concat(e):__bconcat(e)}}var __readUInt8=function(e,r){return e[r]};var __readUInt16LE=function(e,r){return e[r+1]*(1<<8)+e[r]};var __readInt16LE=function(e,r){var t=e[r+1]*(1<<8)+e[r];return t<32768?t:(65535-t+1)*-1};var __readUInt32LE=function(e,r){return e[r+3]*(1<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};var __readInt32LE=function(e,r){return(e[r+3]<<24)+(e[r+2]<<16)+(e[r+1]<<8)+e[r]};function ReadShift(e,r){var t,i,n=0;switch(e){case 1:t=__readUInt8(this,this.l);break;case 2:t=(r!=="i"?__readUInt16LE:__readInt16LE)(this,this.l);break;case 4:t=__readInt32LE(this,this.l);break;case 16:n=2;i=__hexlify(this,this.l,e);}this.l+=e;if(n===0)return t;return i}var __writeUInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>>8&255;e[t+2]=r>>>16&255;e[t+3]=r>>>24&255};var __writeInt32LE=function(e,r,t){e[t]=r&255;e[t+1]=r>>8&255;e[t+2]=r>>16&255;e[t+3]=r>>24&255};function WriteShift(e,r,t){var i=0,n=0;switch(t){case"hex":for(;n>8}while(this.l>>=8;this[this.l+1]=r&255;break;case 4:i=4;__writeUInt32LE(this,r,this.l);break;case-4:i=4;__writeInt32LE(this,r,this.l);break;}this.l+=i;return this}function CheckField(e,r){var t=__hexlify(this,this.l,e.length>>1);if(t!==e)throw new Error(r+"Expected "+e+" saw "+t);this.l+=e.length>>1}function prep_blob(e,r){e.l=r;e.read_shift=ReadShift;e.chk=CheckField;e.write_shift=WriteShift}function new_buf(e){var r=new_raw_buf(e);prep_blob(r,0);return r}var CFB=function t(){var e={};e.version="1.0.5";function r(e,r){var t=e.split("/"),i=r.split("/");for(var n=0,a=0,f=Math.min(t.length,i.length);n0&&c!==y)C[c].name="!MiniFAT";C[w[0]].name="!FAT";C.fat_addrs=w;C.ssz=i;var S={},A=[],m=[],B=[];v(f,C,E,A,n,S,m,c);o(m,B,A);A.shift();var L={FileIndex:m,FullPaths:B};if(r&&r.raw)L.raw={header:g,sectors:E};return L}function s(e){e.chk(S,"Header Signature: ");e.chk(m,"CLSID: ");var r=e.read_shift(2,"u");return[e.read_shift(2,"u"),r]}function h(e,r){var t=9;e.l+=2;switch(t=e.read_shift(2)){case 9:if(r!=3)throw new Error("Sector Shift: Expected 9 saw "+t);break;case 12:if(r!=4)throw new Error("Sector Shift: Expected 12 saw "+t);break;default:throw new Error("Sector Shift: Expected 9 or 12 saw "+t);}e.chk("0600","Mini Sector Shift: ");e.chk("000000000000","Reserved: ")}function l(e,r){var t=Math.ceil(e.length/r)-1;var i=[];for(var n=1;n0&&f>=0){a.push(r.slice(f*C,f*C+C));n-=C;f=__readInt32LE(t,f*4)}if(a.length===0)return new_buf(0);return bconcat(a).slice(0,e.size)}function u(e,r,t,i,n){var a=y;if(e===y){if(r!==0)throw new Error("DIFAT chain shorter than expected")}else if(e!==-1){var f=t[e],s=(i>>>2)-1;if(!f)return;for(var h=0;h=0;){n[h]=true;a[a.length]=h;f.push(e[h]);var o=t[Math.floor(h*4/i)];l=h*4&s;if(i<4+l)throw new Error("FAT boundary crossed: "+h+" 4 "+i);if(!e[o])break;h=__readInt32LE(e[o],l)}return{nodes:a,data:__toBuffer([f])}}function d(e,r,t,i){var n=e.length,a=[];var f=[],s=[],h=[];var l=i-1,o=0,c=0,u=0,_=0;for(o=0;o=n)u-=n;if(f[u])continue;h=[];for(c=u;c>=0;){f[c]=true;s[s.length]=c;h.push(e[c]);var d=t[Math.floor(c*4/i)];_=c*4&l;if(i<4+_)throw new Error("FAT boundary crossed: "+c+" 4 "+i);if(!e[d])break;c=__readInt32LE(e[d],_)}a[u]={nodes:s,data:__toBuffer([h])}}return a}function v(e,r,t,i,n,a,f,s){var h=0,l=i.length?2:0;var o=r[e].data;var u=0,d=0,v;for(;u0&&h!==y)r[h].name="!StreamData"}else if(F.size>=4096){F.storage="fat";if(r[F.start]===undefined)r[F.start]=_(t,F.start,r.fat_addrs,r.ssz);r[F.start].name=F.name;F.content=r[F.start].data.slice(0,F.size)}else{F.storage="minifat";if(F.size<0)F.size=0;else if(h!==y&&F.start!==y&&r[h]){F.content=c(F,r[h].data,(r[s]||{}).data)}}if(F.content)prep_blob(F.content,0);a[v]=F;f.push(F)}}function w(e,r){return new Date((__readUInt32LE(e,r+4)/1e7*Math.pow(2,32)+__readUInt32LE(e,r)/1e7-11644473600)*1e3)}function p(e,r){a();return f(n.readFileSync(e),r)}function F(e,r){switch(r&&r.type||"base64"){case"file":return p(e,r);case"base64":return f(s2a(Base64.decode(e)),r);case"binary":return f(s2a(e),r);}return f(e,r)}function g(e,r){var t=r||{},i=t.root||"Root Entry";if(!e.FullPaths)e.FullPaths=[];if(!e.FileIndex)e.FileIndex=[];if(e.FullPaths.length!==e.FileIndex.length)throw new Error("inconsistent CFB structure");if(e.FullPaths.length===0){e.FullPaths[0]=i+"/";e.FileIndex[0]={name:i,type:5}}if(t.CLSID)e.FileIndex[0].clsid=t.CLSID;I(e)}function I(e){var r="Sh33tJ5";if(CFB.find(e,"/"+r))return;var t=new_buf(4);t[0]=55;t[1]=t[3]=50;t[2]=54;e.FileIndex.push({name:r,type:2,content:t,size:4,L:69,R:69,C:69});e.FullPaths.push(e.FullPaths[0]+r);b(e)}function b(e,n){g(e);var a=false,f=false;for(var s=e.FullPaths.length-1;s>=0;--s){var h=e.FileIndex[s];switch(h.type){case 0:if(f)a=true;else{e.FileIndex.pop();e.FullPaths.pop()}break;case 1:;case 2:;case 5:f=true;if(isNaN(h.R*h.L*h.C))a=true;if(h.R>-1&&h.L>-1&&h.R==h.L)a=true;break;default:a=true;break;}}if(!a&&!n)return;var l=new Date(1987,1,19),o=0;var c=[];for(s=0;s1?1:-1;_.size=0;_.type=5}else if(d.slice(-1)=="/"){for(o=s+1;o=c.length?-1:o;for(o=s+1;o=c.length?-1:o;_.type=1}else{if(t(e.FullPaths[s+1]||"")==t(d))_.R=s+1;_.type=2}}}function x(e,r){var t=r||{};b(e);var i=function(e){var r=0,t=0;for(var i=0;i0){if(a<4096)r+=a+63>>6;else t+=a+511>>9}}var f=e.FullPaths.length+3>>2;var s=r+7>>3;var h=r+127>>7;var l=s+t+f+h;var o=l+127>>7;var c=o<=109?0:Math.ceil((o-109)/127);while(l+o+c+127>>7>o)c=++o<=109?0:Math.ceil((o-109)/127);var u=[1,c,o,h,f,t,r,0];e.FileIndex[0].size=r<<6;u[7]=(e.FileIndex[0].start=u[0]+u[1]+u[2]+u[3]+u[4]+u[5])+(u[6]+7>>3);return u}(e);var n=new_buf(i[7]<<9);var a=0,f=0;{for(a=0;a<8;++a)n.write_shift(1,A[a]);for(a=0;a<8;++a)n.write_shift(2,0);n.write_shift(2,62);n.write_shift(2,3);n.write_shift(2,65534);n.write_shift(2,9);n.write_shift(2,6);for(a=0;a<3;++a)n.write_shift(2,0);n.write_shift(4,0);n.write_shift(4,i[2]);n.write_shift(4,i[0]+i[1]+i[2]+i[3]-1);n.write_shift(4,0);n.write_shift(4,1<<12);n.write_shift(4,i[3]?i[0]+i[1]+i[2]-1:y);n.write_shift(4,i[3]);n.write_shift(-4,i[1]?i[0]-1:y);n.write_shift(4,i[1]);for(a=0;a<109;++a)n.write_shift(-4,a>9)}s(i[6]+7>>3);while(n.l&511)n.write_shift(-4,B.ENDOFCHAIN);f=a=0;for(h=0;h=4096)continue;o.start=f;s(l+63>>6)}while(n.l&511)n.write_shift(-4,B.ENDOFCHAIN);for(a=0;a=4096){n.l=o.start+1<<9;for(h=0;h0&&o.size<4096){for(h=0;h*/, Paths/*:Arr if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } @@ -610,7 +611,6 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ { } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { - //return cfb.find(path); var UCFullPaths/*:Array*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths/*:Array*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k/*:boolean*/ = false; @@ -620,10 +620,12 @@ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; } diff --git a/index.html b/index.html index 0fd0fe0..3bce815 100644 --- a/index.html +++ b/index.html @@ -44,7 +44,7 @@ Use readAsBinaryString: (when available) /*jshint browser:true */ /* eslint-env browser */ -/*global Uint8Array, ArrayBuffer, console */ +/*global Uint8Array, ArrayBuffer, console, alert */ /*global CFB, out, PRINTJ, saveAs */ /* exported savefile, download_file */ /* eslint no-use-before-define:0 */ @@ -151,9 +151,9 @@ var savefile = (function() { return function savefile() { if(!global_cfb) return alert("Must load a file first!"); - console.log(global_cfb); + if(typeof console !== 'undefined') console.log(global_cfb); var data = CFB.write(global_cfb, {type:'binary'}); - console.log(data); + if(typeof console !== 'undefined') console.log(data); saveAs(new Blob([s2ab(data)],{type:"application/octet-stream"}), "sheetjs.xls"); }; })(); @@ -168,7 +168,7 @@ var download_file = (function() { return function download_file(i) { if(!global_cfb) return alert("Must load a file first!"); - console.log(global_cfb); + if(typeof console !== 'undefined') console.log(global_cfb); var file = global_cfb.FileIndex[i], data = file.content; saveAs(new Blob([a2ab(data)],{type:"application/octet-stream"}), file.name); }; diff --git a/package.json b/package.json index 20bea51..4ec1091 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cfb", - "version": "1.0.4", + "version": "1.0.5", "author": "sheetjs", "description": "Compound File Binary File Format extractor", "keywords": [ @@ -19,15 +19,15 @@ "fs": false }, "dependencies": { - "commander": "^2.12.1", - "printj": "~1.1.1" + "commander": "^2.14.1", + "printj": "~1.1.2" }, "devDependencies": { - "crc-32": "~1.1.1", + "crc-32": "~1.2.0", "mocha": "~2.5.3", "blanket": "~1.2.3", "@sheetjs/uglify-js": "~2.7.3", - "@types/node": "^8.0.7", + "@types/node": "^8.5.9", "@types/commander": "^2.9.0", "dtslint": "~0.1.2", "typescript": "2.2.0" diff --git a/shim.js b/shim.js index 30740ec..61a6eaf 100644 --- a/shim.js +++ b/shim.js @@ -1,343 +1,49 @@ -// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys -if (!Object.keys) { - Object.keys = (function () { - var hasOwnProperty = Object.prototype.hasOwnProperty, - hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'), - dontEnums = [ - 'toString', - 'toLocaleString', - 'valueOf', - 'hasOwnProperty', - 'isPrototypeOf', - 'propertyIsEnumerable', - 'constructor' - ], - dontEnumsLength = dontEnums.length; +/* shim.js (C) 2013-present SheetJS -- http://sheetjs.com */ +/* ES3/5 Compatibility shims and other utilities for older browsers. */ - return function (obj) { - if (typeof obj !== 'object' && typeof obj !== 'function' || obj === null) throw new TypeError('Object.keys called on non-object'); - - var result = []; - - for (var prop in obj) { - if (hasOwnProperty.call(obj, prop)) result.push(prop); - } - - if (hasDontEnumBug) { - for (var i=0; i < dontEnumsLength; i++) { - if (hasOwnProperty.call(obj, dontEnums[i])) result.push(dontEnums[i]); - } - } - return result; - }; - })(); -} - -// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter -if (!Array.prototype.filter) -{ - Array.prototype.filter = function(fun /*, thisp */) - { - "use strict"; - - if (this == null) - throw new TypeError(); - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun != "function") - throw new TypeError(); - - var res = []; - var thisp = arguments[1]; - for (var i = 0; i < len; i++) - { - if (i in t) - { - var val = t[i]; // in case fun mutates this - if (fun.call(thisp, val, i, t)) - res.push(val); - } - } - - return res; - }; -} - -// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/Trim -if (!String.prototype.trim) { - String.prototype.trim = function () { - return this.replace(/^\s+|\s+$/g, ''); - }; -} - -// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/forEach -if (!Array.prototype.forEach) -{ - Array.prototype.forEach = function(fun /*, thisArg */) - { - "use strict"; - - if (this === void 0 || this === null) - throw new TypeError(); - - var t = Object(this); - var len = t.length >>> 0; - if (typeof fun !== "function") - throw new TypeError(); - - var thisArg = arguments.length >= 2 ? arguments[1] : void 0; - for (var i = 0; i < len; i++) - { - if (i in t) - fun.call(thisArg, t[i], i, t); - } - }; -} - -// Production steps of ECMA-262, Edition 5, 15.4.4.19 -// Reference: http://es5.github.com/#x15.4.4.19 -if (!Array.prototype.map) { - Array.prototype.map = function(callback, thisArg) { - - var T, A, k; - - if (this == null) { - throw new TypeError(" this is null or not defined"); - } - - // 1. Let O be the result of calling ToObject passing the |this| value as the argument. - var O = Object(this); - - // 2. Let lenValue be the result of calling the Get internal method of O with the argument "length". - // 3. Let len be ToUint32(lenValue). - var len = O.length >>> 0; - - // 4. If IsCallable(callback) is false, throw a TypeError exception. - // See: http://es5.github.com/#x9.11 - if (typeof callback !== "function") { - throw new TypeError(callback + " is not a function"); - } - - // 5. If thisArg was supplied, let T be thisArg; else let T be undefined. - if (thisArg) { - T = thisArg; - } - - // 6. Let A be a new array created as if by the expression new Array(len) where Array is - // the standard built-in constructor with that name and len is the value of len. - A = new Array(len); - - // 7. Let k be 0 - k = 0; - - // 8. Repeat, while k < len - while(k < len) { - - var kValue, mappedValue; - - // a. Let Pk be ToString(k). - // This is implicit for LHS operands of the in operator - // b. Let kPresent be the result of calling the HasProperty internal method of O with argument Pk. - // This step can be combined with c - // c. If kPresent is true, then - if (k in O) { - - // i. Let kValue be the result of calling the Get internal method of O with argument Pk. - kValue = O[ k ]; - - // ii. Let mappedValue be the result of calling the Call internal method of callback - // with T as the this value and argument list containing kValue, k, and O. - mappedValue = callback.call(T, kValue, k, O); - - // iii. Call the DefineOwnProperty internal method of A with arguments - // Pk, Property Descriptor {Value: mappedValue, : true, Enumerable: true, Configurable: true}, - // and false. - - // In browsers that support Object.defineProperty, use the following: - // Object.defineProperty(A, Pk, { value: mappedValue, writable: true, enumerable: true, configurable: true }); - - // For best browser support, use the following: - A[ k ] = mappedValue; - } - // d. Increase k by 1. - k++; - } - - // 9. return A - return A; - }; -} - -// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/indexOf -if (!Array.prototype.indexOf) { - Array.prototype.indexOf = function (searchElement, fromIndex) { - if ( this === undefined || this === null ) { - throw new TypeError( '"this" is null or not defined' ); - } - - var length = this.length >>> 0; // Hack to convert object.length to a UInt32 - - fromIndex = +fromIndex || 0; - - if (Math.abs(fromIndex) === Infinity) { - fromIndex = 0; - } - - if (fromIndex < 0) { - fromIndex += length; - if (fromIndex < 0) { - fromIndex = 0; - } - } - - for (;fromIndex < length; fromIndex++) { - if (this[fromIndex] === searchElement) { - return fromIndex; - } - } - - return -1; - }; -} -// Based on https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/isArray - -if (! Array.isArray) { - Array.isArray = function(obj) { - return Object.prototype.toString.call(obj) === "[object Array]"; - }; -} - -// https://github.com/ttaubert/node-arraybuffer-slice -// (c) 2013 Tim Taubert -// arraybuffer-slice may be freely distributed under the MIT license. - -"use strict"; - -if (typeof ArrayBuffer !== 'undefined' && !ArrayBuffer.prototype.slice) { - ArrayBuffer.prototype.slice = function (begin, end) { - begin = (begin|0) || 0; - var num = this.byteLength; - end = end === (void 0) ? num : (end|0); - - // Handle negative values. - if (begin < 0) begin += num; - if (end < 0) end += num; - - if (num === 0 || begin >= num || begin >= end) { - return new ArrayBuffer(0); - } - - var length = Math.min(num - begin, end - begin); - var target = new ArrayBuffer(length); - var targetArray = new Uint8Array(target); - targetArray.set(new Uint8Array(this, begin, length)); - return target; - }; -} - -// https://github.com/davidchambers/Base64.js -// (C) 2015 David Chambers -// Base64.js may be freely distributed under the Apache 2.0 License. -;(function () { - - var object = - typeof exports != 'undefined' ? exports : - typeof self != 'undefined' ? self : // #8: web workers - $.global; // #31: ExtendScript - - var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/='; - - function InvalidCharacterError(message) { - this.message = message; - } - InvalidCharacterError.prototype = new Error; - InvalidCharacterError.prototype.name = 'InvalidCharacterError'; - - // encoder - // [https://gist.github.com/999166] by [https://github.com/nignag] - object.btoa || ( - object.btoa = function (input) { - var str = String(input); - for ( - // initialize result and counter - var block, charCode, idx = 0, map = chars, output = ''; - // if the next str index does not exist: - // change the mapping table to "=" - // check if d has no fractional digits - str.charAt(idx | 0) || (map = '=', idx % 1); - // "8 - idx % 1 * 8" generates the sequence 2, 4, 6, 8 - output += map.charAt(63 & block >> 8 - idx % 1 * 8) - ) { - charCode = str.charCodeAt(idx += 3/4); - if (charCode > 0xFF) { - throw new InvalidCharacterError("'btoa' failed: The string to be encoded contains characters outside of the Latin1 range."); - } - block = block << 8 | charCode; - } - return output; - }); - - // decoder - // [https://gist.github.com/1020396] by [https://github.com/atk] - object.atob || ( - object.atob = function (input) { - var str = String(input).replace(/[=]+$/, ''); // #31: ExtendScript bad parse of /= - if (str.length % 4 == 1) { - throw new InvalidCharacterError("'atob' failed: The string to be decoded is not correctly encoded."); - } - for ( - // initialize result and counters - var bc = 0, bs, buffer, idx = 0, output = ''; - // get next character - buffer = str.charAt(idx++); - // character found in table? initialize bit storage and add its ascii value; - ~buffer && (bs = bc % 4 ? bs * 64 + buffer : buffer, - // and if not first of each 4 characters, - // convert the first 8 bits to one ascii character - bc++ % 4) ? output += String.fromCharCode(255 & bs >> (-2 * bc & 6)) : 0 - ) { - // try to find character in table (0-63, not found => -1) - buffer = chars.indexOf(buffer); - } - return output; - }); -}()); - - -// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Date/toISOString -if (!Date.prototype.toISOString) { - (function() { - - function pad(number) { - if (number < 10) { - return '0' + number; - } - return number; - } - - Date.prototype.toISOString = function() { - return this.getUTCFullYear() + - '-' + pad(this.getUTCMonth() + 1) + - '-' + pad(this.getUTCDate()) + - 'T' + pad(this.getUTCHours()) + - ':' + pad(this.getUTCMinutes()) + - ':' + pad(this.getUTCSeconds()) + - '.' + (this.getUTCMilliseconds() / 1000).toFixed(3).slice(2, 5) + - 'Z'; - }; - - }()); -} - -// note: MDN shim will not work in IE -if(typeof Uint8Array !== 'undefined' && !Uint8Array.prototype.slice) Uint8Array.prototype.slice = function(start, end) { - if(start < 0) { start += this.length; if(start < 0) start = 0; } - if(start >= this.length) return new Uint8Array(0); - if(end == null) end = this.length; - if(end < 0) { end += this.length; if(end < 0) end = 0; } - if(end > this.length) end = this.length; - var out = new Uint8Array(end - start); - while(start <= --end) out[end - start] = this[end]; - return out; +if(!Array.prototype.forEach) Array.prototype.forEach = function(cb) { + var len = (this.length>>>0), self = (arguments[1]||void 0); + for(var i=0; i>>0), self = (arguments[1]||void 0), A = new Array(len); + for(var i=0; i>>0), i = ((arguments[1]|0)||0); + for(i<0 && (i+=len)<0 && (i=0); i= this.byteLength) return new Uint8Array(0); + if(end == null) end = this.byteLength; + if(end < 0) { end += this.byteLength; if(end < 0) end = 0; } + if(end > this.byteLength) end = this.byteLength; + if(start > end) return new Uint8Array(0); + var out = new ArrayBuffer(end - start); + var view = new Uint8Array(out); + var data = new Uint8Array(this, start, end - start) + /* IE10 should have Uint8Array#set */ + if(view.set) view.set(data); else while(start <= --end) view[end - start] = data[end]; + return out; +}; +if(typeof Uint8Array !== 'undefined' && !Uint8Array.prototype.slice) Uint8Array.prototype.slice = function(start, end) { + if(start == null) start = 0; + if(start < 0) { start += this.length; if(start < 0) start = 0; } + if(start >= this.length) return new Uint8Array(0); + if(end == null) end = this.length; + if(end < 0) { end += this.length; if(end < 0) end = 0; } + if(end > this.length) end = this.length; + if(start > end) return new Uint8Array(0); + var out = new Uint8Array(end - start); + while(start <= --end) out[end - start] = this[end]; + return out; }; diff --git a/test.js b/test.js index 94c3acf..5a384f9 100644 --- a/test.js +++ b/test.js @@ -26,6 +26,7 @@ var files = fs.readdirSync('test_files').filter(ffunc); var f2011 = fs.readdirSync('test_files/2011').filter(ffunc); var f2013 = fs.readdirSync('test_files/2013').filter(ffunc); var fpres = fs.readdirSync('test_files_pres').filter(ffunc); +var fxlsx = fs.readdirSync('test_files').filter(function(x) { return x.slice(-5) == ".xlsx"; }); var dir = "./test_files/"; var TYPE = "buffer"; @@ -34,7 +35,7 @@ var names = [ ["!DocumentSummaryInformation", "\u0005"], ["!SummaryInformation", "\u0005"], ["!CompObj", "\u0001"], - ["!DataSpaces", "\u0006"], + ["/!DataSpaces/Version", "\u0006"], ["!DRMContent", "\u0009"], ["!DRMViewerContent", "\u0009"], ["!Ole", "\u0001"] @@ -47,6 +48,7 @@ function parsetest(x, cfb) { case '.xls': if(!CFB.find(cfb, 'Workbook') && !CFB.find(cfb, 'Book')) throw new Error("Cannot find workbook for " + x); break; case '.ppt': if(!CFB.find(cfb, 'PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break; case '.doc': if(!CFB.find(cfb, 'WordDocument') && !CFB.find(cfb, 'Word Document')) throw new Error("Cannot find doc for " + x); break; + case 'xlsx': if(!CFB.find(cfb, 'Workbook') && !CFB.find(cfb, 'Book') && !CFB.find(cfb, 'WordDocument') && !CFB.find(cfb, 'EncryptedPackage') && !CFB.find(cfb, 'EncryptionInfo')) throw new Error("Cannot find workbook or encryption for " + x); break; } }); it('should find absolute path', function() { @@ -54,6 +56,7 @@ function parsetest(x, cfb) { case '.xls': if(!CFB.find(cfb, '/Workbook') && !CFB.find(cfb, '/Book')) throw new Error("Cannot find workbook for " + x); break; case '.ppt': if(!CFB.find(cfb, '/PowerPoint Document')) throw new Error("Cannot find presentation for " + x); break; case '.doc': if(!CFB.find(cfb, '/WordDocument') && !CFB.find(cfb, '/Word Document')) throw new Error("Cannot find doc for " + x); break; + case 'xlsx': if(!CFB.find(cfb, '/Workbook') && !CFB.find(cfb, '/Book') && !CFB.find(cfb, '/WordDocument') && !CFB.find(cfb, '/EncryptedPackage') && !CFB.find(cfb, '/EncryptionInfo')) throw new Error("Cannot find workbook or encryption for " + x); break; } }); it('should handle "!" aliases', function() { @@ -69,7 +72,7 @@ function parsetest(x, cfb) { data = CFB.write(cfb, {type:TYPE}); newcfb = CFB.read(data, {type:TYPE}); }); - it('should preserve content', function() { + if(x.substr(-4) !== "xlsx") it('should preserve content', function() { var _old, _new; switch(x.substr(-4)) { case '.xls': @@ -120,6 +123,27 @@ describe('should parse test files', function() { parsetest(x, cfb); }); }); + fxlsx.forEach(function(x) { + it('should parse ' + x, function() { + try { + var cfb = CFB.read('./test_files/' + x, {type: "file"}); + parsetest(x, cfb); + } catch(e) { + if(e.message.match(/CFB file size /)) return; + if(!e.message.match(/Header Signature: Expected d0cf11e0a1b11ae1 saw /)) throw e; + } + }); + }); + it('should recognize correct magic number', function() { + var cfb = CFB.read('./test_files/AutoFilter.xls', {type: "file"}); + if(!CFB.find(cfb, '!CompObj')) throw new Error("Could not find !CompObj"); + if(!CFB.find(cfb, '\u0001CompObj')) throw new Error("Could not find 1CompObj"); + if(CFB.find(cfb, '\u0005CompObj')) throw new Error("Found 5CompObj"); + + if(!CFB.find(cfb, '!DocumentSummaryInformation')) throw new Error("Could not find !DSI"); + if(!CFB.find(cfb, '\u0005DocumentSummaryInformation')) throw new Error("Could not find 5DSI"); + if(CFB.find(cfb, '\u0001DocumentSummaryInformation')) throw new Error("Found 1DSI"); + }); }); var cp = 'custom_properties.xls'; diff --git a/types/bin_cfb.ts b/types/bin_cfb.ts index 1d233e3..a888b5a 100755 --- a/types/bin_cfb.ts +++ b/types/bin_cfb.ts @@ -10,13 +10,14 @@ const sprintf = PRINTJ.sprintf; program .version(X.version) .usage('[options] [subfiles...]') - .option('-q, --quiet', 'process but do not report') .option('-l, --list-files', 'list files') - .option('-z, --dump', 'dump internal representation but do not extract') .option('-r, --repair', 'attempt to repair and garbage-collect archive') .option('-c, --create', 'create file') .option('-a, --append', 'add files to CFB (overwrite existing data)') .option('-d, --delete', 'delete files from CFB') + .option('-O, --to-stdout', 'extract raw contents to stdout') + .option('-z, --dump', 'dump internal representation but do not extract') + .option('-q, --quiet', 'process but do not report') .option('--dev', 'development mode') .option('--read', 'read but do not print out contents'); @@ -110,16 +111,18 @@ if(program.delete) { if(program.args.length > 1) { program.args.slice(1).forEach((x: string) => { - const data: X.CFB$Entry = X.find(cfb, x); + const data: X.CFB$Entry = X.find(cfb, x.replace(/\\u000\d/g,"!")); if(!data) { console.error(x + ": file not found"); return; } if(data.type !== 2) { console.error(x + ": not a file"); return; } const idx = cfb.FileIndex.indexOf(data), path = cfb.FullPaths[idx]; + if(program.toStdout) return process.stdout.write(new Buffer(data.content)); mkdirp(path.slice(0, path.lastIndexOf("/"))); write(path, data); }); exit(0); } +if(program.toStdout) exit(0); for(let i=0; i!==cfb.FullPaths.length; ++i) { if(!cfb.FileIndex[i].name) continue; if(cfb.FullPaths[i].slice(-1) === "/") mkdirp(cfb.FullPaths[i]); diff --git a/xlscfb.flow.js b/xlscfb.flow.js index b9d8bbe..7324ed9 100644 --- a/xlscfb.flow.js +++ b/xlscfb.flow.js @@ -35,10 +35,10 @@ type SectorList = { } type CFBFiles = {[n:string]:CFBEntry}; */ -/* [MS-CFB] v20130118 */ +/* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports/*:CFBModule*/ = /*::(*/{}/*:: :any)*/; -exports.version = '1.0.3'; +exports.version = '1.0.5'; /* [MS-CFB] 2.6.4 */ function namecmp(l/*:string*/, r/*:string*/)/*:number*/ { var L = l.split("/"), R = r.split("/"); @@ -62,6 +62,7 @@ function filename(p/*:string*/)/*:string*/ { var fs/*:: = require('fs'); */; function get_fs() { return fs || (fs = require('fs')); } function parse(file/*:RawBytes*/, options/*:CFBReadOpts*/)/*:CFBContainer*/ { +if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); var mver = 3; var ssz = 512; var nmfs = 0; // number of mini FAT sectors @@ -218,7 +219,7 @@ function build_full_paths(FI/*:CFBFileIndex*/, FP/*:Array*/, Paths/*:Arr if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } @@ -610,7 +611,6 @@ function _write(cfb/*:CFBContainer*/, options/*:CFBWriteOpts*/)/*:RawBytes*/ { } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { - //return cfb.find(path); var UCFullPaths/*:Array*/ = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths/*:Array*/ = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k/*:boolean*/ = false; @@ -620,10 +620,12 @@ function find(cfb/*:CFBContainer*/, path/*:string*/)/*:?CFBEntry*/ { var w/*:number*/ = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; } diff --git a/xlscfb.js b/xlscfb.js index f1612a9..c6d9b58 100644 --- a/xlscfb.js +++ b/xlscfb.js @@ -5,10 +5,10 @@ var DO_NOT_EXPORT_CFB = true; /*exported CFB */ /*global module, require:false, process:false, Buffer:false, Uint8Array:false */ -/* [MS-CFB] v20130118 */ +/* [MS-CFB] v20171201 */ var CFB = (function _CFB(){ var exports = {}; -exports.version = '1.0.3'; +exports.version = '1.0.5'; /* [MS-CFB] 2.6.4 */ function namecmp(l, r) { var L = l.split("/"), R = r.split("/"); @@ -32,6 +32,7 @@ function filename(p) { var fs; function get_fs() { return fs || (fs = require('fs')); } function parse(file, options) { +if(file.length < 512) throw new Error("CFB file size " + file.length + " < 512"); var mver = 3; var ssz = 512; var nmfs = 0; // number of mini FAT sectors @@ -188,7 +189,7 @@ function build_full_paths(FI, FP, Paths) { if(L !== -1) { dad[L] = dad[i]; q.push(L); } if(R !== -1) { dad[R] = dad[i]; q.push(R); } } - for(i=1; i !== pl; ++i) if(dad[i] === i) { + for(i=1; i < pl; ++i) if(dad[i] === i) { if(R !== -1 /*NOSTREAM*/ && dad[R] !== R) dad[i] = dad[R]; else if(L !== -1 && dad[L] !== L) dad[i] = dad[L]; } @@ -575,7 +576,6 @@ if(file.size > 0 && file.size < 0x1000) { } /* [MS-CFB] 2.6.4 (Unicode 3.0.1 case conversion) */ function find(cfb, path) { - //return cfb.find(path); var UCFullPaths = cfb.FullPaths.map(function(x) { return x.toUpperCase(); }); var UCPaths = UCFullPaths.map(function(x) { var y = x.split("/"); return y[y.length - (x.slice(-1) == "/" ? 2 : 1)]; }); var k = false; @@ -585,10 +585,12 @@ function find(cfb, path) { var w = k === true ? UCFullPaths.indexOf(UCPath) : UCPaths.indexOf(UCPath); if(w !== -1) return cfb.FileIndex[w]; - UCPath = UCPath.replace(chr0,'').replace(chr1,'!'); + var m = !UCPath.match(chr1); + UCPath = UCPath.replace(chr0,''); + if(m) UCPath = UCPath.replace(chr1,'!'); for(w = 0; w < UCFullPaths.length; ++w) { - if(UCFullPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; - if(UCPaths[w].replace(chr0,'').replace(chr1,'!') == UCPath) return cfb.FileIndex[w]; + if((m ? UCFullPaths[w].replace(chr1,'!') : UCFullPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; + if((m ? UCPaths[w].replace(chr1,'!') : UCPaths[w]).replace(chr0,'') == UCPath) return cfb.FileIndex[w]; } return null; }