version bump 0.3.0: name collision resolution

It is possible for multiple streams to have the same name (albeit with different
paths), so:
- `FileIndex` is an array of the streams
- `FullPaths` is an array of the full paths
- `FullPathDir` is a full path version of `Directory`
This commit is contained in:
SheetJS 2013-09-20 15:43:02 -07:00
parent eda9dfbf13
commit 8d10376fad
3 changed files with 51 additions and 37 deletions

50
bin/cfb

@ -2,44 +2,24 @@
var CFB = require('../cfb');
var args = process.argv.slice(2);
if(args.length === 0 || !require('fs').existsSync(args[0])) {
console.error("Usage: " + process.argv[1] + " <cfb_file>");
process.exit(1);
}
var cfb = CFB.read(args[0], {type:'file'});
cfb.Paths.unshift(cfb.Paths.root);
var dir = cfb.Directory;
var dad = new Array(cfb.Paths.length);
var paths = new Array(cfb.Paths.length);
var q = new Array(paths.length);
for(var i=0; i != dad.length; ++i) { dad[i]=q[i]=i; paths[i]=cfb.Paths[i]; }
for(var i = q[0]; q.length != 0; i = q.shift()) {
if(dir[paths[i]].child) dad[dir[paths[i]].child] = i;
if(dir[paths[i]].left) { dad[dir[paths[i]].left] = dad[i]; q.push(dir[paths[i]].left); }
if(dir[paths[i]].right) { dad[dir[paths[i]].right] = dad[i]; q.push(dir[paths[i]].right); }
if(args[1] === "-q") {
console.log(cfb);
return;
}
for(var i=1; i != paths.length; ++i) {
var j = dad[i];
if(j === 0) paths[i] = paths[0] + "/" + paths[i];
else while(j != 0) {
paths[i] = paths[j] + "/" + paths[i];
j = dad[j];
}
dad[i] = 0;
}
paths[0] += "/";
for(var i=1; i != paths.length; ++i) if(dir[cfb.Paths[i]].type != 'stream') paths[i] += "/";
var fs = require('fs');
for(var i=0; i != paths.length; ++i) {
if(paths[i].slice(-1) === "/") {
console.error("mkdir " + paths[i]);
fs.mkdirSync(paths[i]);
for(var i=0; i != cfb.FullPaths.length; ++i) {
if(cfb.FullPaths[i].slice(-1) === "/") {
console.error("mkdir " + cfb.FullPaths[i]);
fs.mkdirSync(cfb.FullPaths[i]);
} else {
console.error("writing " + paths[i]);
fs.writeFile(paths[i], dir[cfb.Paths[i]].content);
console.error("writing " + cfb.FullPaths[i]);
fs.writeFileSync(cfb.FullPaths[i], cfb.FileIndex[i].content);
}
}

36
cfb.js

@ -288,7 +288,7 @@ if(nmfs > 0) sector_list[minifat_start].name = "!MiniFAT";
sector_list[fat_addrs[0]].name = "!FAT";
/* [MS-CFB] 2.6.1 Compound File Directory Entry */
var files = {}, Paths = [];
var files = {}, Paths = [], FileIndex = [], FullPaths = [], FullPathDir = {};
function read_directory(idx) {
var blob, read, w;
var sector = sector_list[idx].data;
@ -338,16 +338,50 @@ function read_directory(idx) {
o.mt = new Date((m2 - 11644473600)*1000);
}
files[name] = o;
FileIndex.push(o);
}
}
read_directory(dir_start);
function build_full_paths(Dir, pathobj, paths, patharr) {
var i;
var dad = new Array(patharr.length);
var q = new Array(patharr.length);
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()) {
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) {
var j = dad[i];
if(j === 0) paths[i] = paths[0] + "/" + paths[i];
else while(j != 0) {
paths[i] = paths[j] + "/" + paths[i];
j = dad[j];
}
dad[i] = 0;
}
paths[0] += "/";
for(i=1; i !== paths.length; ++i) if(Dir[i].type !== 'stream') paths[i] += "/";
for(i=0; i !== paths.length; ++i) pathobj[paths[i]] = FileIndex[i];
}
build_full_paths(FileIndex, FullPathDir, FullPaths, Paths);
var root_name = Paths.shift();
Paths.root = root_name;
var rval = {
raw: {header: header, sectors: sectors},
Paths: Paths,
FileIndex: FileIndex,
FullPaths: FullPaths,
FullPathDir: FullPathDir,
Directory: files
};

@ -1,6 +1,6 @@
{
"name": "cfb",
"version": "0.2.1",
"version": "0.3.0",
"author": "Niggler",
"description": "Compound File Binary File Format extractor",
"keywords": [ "cfb", "compression", "office" ],