From 3bc292382611b35c607f652e24be1a24b15c6128 Mon Sep 17 00:00:00 2001 From: SheetJS Date: Sat, 26 Oct 2013 13:20:19 -0700 Subject: [PATCH] version bump 0.4.0: Fixes from JS-XLS + travis --- .travis.yml | 8 ++++++++ Makefile | 10 ++++++++++ cfb.js | 42 ++++++++++++++++++++++++++++-------------- package.json | 5 ++++- test.js | 11 +++++++++++ 5 files changed, 61 insertions(+), 15 deletions(-) create mode 100644 .travis.yml create mode 100644 Makefile create mode 100644 test.js diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..52d7eba --- /dev/null +++ b/.travis.yml @@ -0,0 +1,8 @@ +language: node_js +node_js: + - "0.10" + - "0.8" +before_install: + - "npm install -g mocha" +before_script: + - "make init" diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..fd2287a --- /dev/null +++ b/Makefile @@ -0,0 +1,10 @@ +.PHONY: init test clean +test: init + mocha -R spec + +init: + if [ ! -e test_files ]; then git clone https://github.com/Niggler/test_files; fi + cd test_files; make + +clean: + rm -rf ./test_files/ diff --git a/cfb.js b/cfb.js index 0cbf0b4..068846b 100644 --- a/cfb.js +++ b/cfb.js @@ -112,16 +112,19 @@ function ReadShift(size, t) { } this.l+=size; return o; } + function CheckField(hexstr, fld) { var m = this.slice(this.l, this.l+hexstr.length/2).hexlify('hex'); if(m !== hexstr) throw (fld||"") + 'Expected ' + hexstr + ' saw ' + m; this.l += hexstr.length/2; } + function WarnField(hexstr, fld) { var m = this.slice(this.l, this.l+hexstr.length/2).hexlify('hex'); if(m !== hexstr) console.error((fld||"") + 'Expected ' + hexstr +' saw ' + m); this.l += hexstr.length/2; } + function prep_blob(blob, pos) { blob.read_shift = ReadShift.bind(blob); blob.chk = CheckField; @@ -237,9 +240,9 @@ for(j = 0; blob.l != 512; ) { /** Break the file up into sectors */ -if(file.length%ssz!==0) throw "File Length: Expected multiple of "+ssz; +if(file.length%ssz!==0) console.error("CFB: size " + file.length + " % "+ssz); -var nsectors = (file.length - ssz)/ssz; +var nsectors = Math.ceil((file.length - ssz)/ssz); var sectors = []; for(var i=1; i != nsectors + 1; ++i) sectors[i-1] = file.slice(i*ssz,(i+1)*ssz); @@ -250,12 +253,14 @@ function sleuth_fat(idx, cnt) { if(cnt !== 0) throw "DIFAT chain shorter than expected"; return; } - var sector = sectors[idx]; - for(var i = 0; i != ssz/4-1; ++i) { - if((q = sector.readUInt32LE(i*4)) === ENDOFCHAIN) break; - fat_addrs.push(q); + if(idx !== FREESECT) { + var sector = sectors[idx]; + for(var i = 0; i != ssz/4-1; ++i) { + if((q = sector.readUInt32LE(i*4)) === ENDOFCHAIN) break; + fat_addrs.push(q); + } + sleuth_fat(sector.readUInt32LE(ssz-4),cnt - 1); } - sleuth_fat(sector.readUInt32LE(ssz-4),cnt - 1); } sleuth_fat(difat_start, ndfs); @@ -284,7 +289,7 @@ for(i=0; i != sectors.length; ++i) { sector_list[i].data = Array(buf.map(get_sector)).toBuffer(); } sector_list[dir_start].name = "!Directory"; -if(nmfs > 0) sector_list[minifat_start].name = "!MiniFAT"; +if(nmfs > 0 && minifat_start !== ENDOFCHAIN) sector_list[minifat_start].name = "!MiniFAT"; sector_list[fat_addrs[0]].name = "!FAT"; /* [MS-CFB] 2.6.1 Compound File Directory Entry */ @@ -314,18 +319,26 @@ function read_directory(idx) { o.size = read(4); if(o.type === 'root') { //root entry minifat_store = o.start; - if(nmfs > 0) sector_list[minifat_store].name = "!StreamData"; + if(nmfs > 0 && minifat_store !== ENDOFCHAIN) sector_list[minifat_store].name = "!StreamData"; minifat_size = o.size; } else if(o.size >= ms_cutoff_size) { o.storage = 'fat'; + try { + sector_list[o.start].name = o.name; + o.content = sector_list[o.start].data.slice(0,o.size); + } catch(e) { + o.start = o.start - 1; sector_list[o.start].name = o.name; o.content = sector_list[o.start].data.slice(0,o.size); + } prep_blob(o.content); } else { o.storage = 'minifat'; w = o.start * mssz; - o.content = sector_list[minifat_store].data.slice(w,w+o.size); - prep_blob(o.content); + if(minifat_store !== ENDOFCHAIN) { + o.content = sector_list[minifat_store].data.slice(w,w+o.size); + prep_blob(o.content); + } } if(o.ctime) { var ct = blob.slice(blob.l-24, blob.l-16); @@ -351,13 +364,14 @@ function build_full_paths(Dir, pathobj, paths, patharr) { for(i=0; i != dad.length; ++i) { dad[i]=q[i]=i; paths[i]=patharr[i]; } - for(i = q[0]; q.length !== 0; i = q.shift()) { + for(i = q[0]; typeof i !== "undefined"; i = q.shift()) { if(Dir[i].child) dad[Dir[i].child] = i; if(Dir[i].left) { dad[Dir[i].left] = dad[i]; q.push(Dir[i].left); } if(Dir[i].right) { dad[Dir[i].right] = dad[i]; q.push(Dir[i].right); } } for(i=1; i !== paths.length; ++i) { + if(Dir[i].type === "unknown") continue; var j = dad[i]; if(j === 0) paths[i] = paths[0] + "/" + paths[i]; else while(j != 0) { @@ -426,14 +440,14 @@ return this; var NOSTREAM = 0xFFFFFFFF; var HEADER_CLSID = '00000000000000000000000000000000'; /* 2.6.1 Compound File Directory Entry */ - var EntryTypes = ['unknown','storage','stream',null,null,'root']; + var EntryTypes = ['unknown','storage','stream','lockbytes','property','root']; } var CFB_utils = { ReadShift: ReadShift, WarnField: WarnField, CheckField: CheckField, - prep_blob: prep_blob, + prep_blob: prep_blob, bconcat: bconcat }; diff --git a/package.json b/package.json index 420ee7e..aa87b11 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "cfb", - "version": "0.3.0", + "version": "0.4.0", "author": "Niggler", "description": "Compound File Binary File Format extractor", "keywords": [ "cfb", "compression", "office" ], @@ -9,6 +9,9 @@ }, "main": "./cfb", "repository": { "type":"git", "url":"git://github.com/Niggler/js-cfb.git" }, + "scripts": { + "test": "make test" + }, "bugs": { "url": "https://github.com/Niggler/js-cfb/issues" }, "license": "Apache 2.0" } diff --git a/test.js b/test.js new file mode 100644 index 0000000..8500605 --- /dev/null +++ b/test.js @@ -0,0 +1,11 @@ +var CFB; +var fs = require('fs'); +describe('source', function() { it('should load', function() { CFB = require('./'); }); }); +var files = fs.readdirSync('test_files').filter(function(x){return x.substr(-4)==".xls";}); +files.forEach(function(x) { + describe(x, function() { + it('should parse ' + x, function() { + var cfb = CFB.read('./test_files/' + x, {type: "file"}); + }); + }); +});