|
|
@@ -1,17 +1,52 @@ |
|
|
|
class CMDirectory {
|
|
|
|
constructor() {
|
|
|
|
this.directories = {};
|
|
|
|
this.files = {};
|
|
|
|
//
|
|
|
|
// Directory: Hash[string, [Directory, File]]
|
|
|
|
// File = [blockRefs, size]
|
|
|
|
// blockRefs: Array[blockRef]
|
|
|
|
// blockRef: [locator, position, size]
|
|
|
|
// locator: String
|
|
|
|
// position: Number
|
|
|
|
// size: Number
|
|
|
|
//
|
|
|
|
|
|
|
|
class WBManifestReader {
|
|
|
|
constructor(manifest_text) {
|
|
|
|
this.rootDir = {};
|
|
|
|
|
|
|
|
if (!manifest_text)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.parse(manifest_text);
|
|
|
|
}
|
|
|
|
|
|
|
|
makeDir(parent, name) {
|
|
|
|
if (!(name in parent))
|
|
|
|
parent[name] = {};
|
|
|
|
if (parent[name] instanceof Array)
|
|
|
|
throw Error('Conflict trying to create a directory - a file with the same name already exists: ' + name);
|
|
|
|
return parent[name];
|
|
|
|
}
|
|
|
|
|
|
|
|
makePath(path) {
|
|
|
|
if (typeof(path) === 'string')
|
|
|
|
path = path.split('/');
|
|
|
|
let dir = this.rootDir;
|
|
|
|
for (let i = 1; i < path.length; i++)
|
|
|
|
dir = this.makeDir(dir, path[i]);
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class CMFile {
|
|
|
|
constructor() {
|
|
|
|
this.blockRefs = [];
|
|
|
|
this.size = 0;
|
|
|
|
appendFile(streamName, locators, position, size, fileName) {
|
|
|
|
let path = streamName + '/' + fileName;
|
|
|
|
path = path.split('/');
|
|
|
|
let dir = this.makePath(path.slice(0, path.length - 1));
|
|
|
|
if (!(fileName in dir))
|
|
|
|
dir[fileName] = [[], 0];
|
|
|
|
if (!(dir[fileName] instanceof Array))
|
|
|
|
throw Error('Conflict trying to create a file - a directory with the same name already exists: ' + fileName);
|
|
|
|
this.appendReferences(dir[fileName], locators, position, size);
|
|
|
|
}
|
|
|
|
|
|
|
|
append(locators, position, size) {
|
|
|
|
appendReferences(file, locators, position, size) {
|
|
|
|
if (size === 0)
|
|
|
|
return;
|
|
|
|
|
|
|
@@ -30,7 +65,7 @@ class CMFile { |
|
|
|
let startBlock = used.indexOf(true);
|
|
|
|
let endBlock = used.lastIndexOf(true) + 1;
|
|
|
|
|
|
|
|
console.log('startBlock: ' + startBlock + ', endBlock: ' + endBlock);
|
|
|
|
// console.log('startBlock: ' + startBlock + ', endBlock: ' + endBlock);
|
|
|
|
|
|
|
|
if (startBlock === -1)
|
|
|
|
return;
|
|
|
@@ -47,53 +82,20 @@ class CMFile { |
|
|
|
runSize -= blockSize;
|
|
|
|
}
|
|
|
|
|
|
|
|
this.blockRefs = this.blockRefs.concat(blockRefs);
|
|
|
|
this.size += size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class WBManifestReader {
|
|
|
|
constructor(manifest_text) {
|
|
|
|
this.rootDir = new CMDirectory();
|
|
|
|
|
|
|
|
if (!manifest_text)
|
|
|
|
return;
|
|
|
|
|
|
|
|
this.parse(manifest_text);
|
|
|
|
}
|
|
|
|
|
|
|
|
makeDir(parent, name) {
|
|
|
|
if (!(name in parent.directories))
|
|
|
|
parent.directories[name] = new CMDirectory();
|
|
|
|
return parent.directories[name];
|
|
|
|
}
|
|
|
|
|
|
|
|
makePath(path) {
|
|
|
|
if (typeof(path) === 'string')
|
|
|
|
path = path.split('/');
|
|
|
|
let dir = this.rootDir;
|
|
|
|
for (let i = 1; i < path.length; i++)
|
|
|
|
dir = this.makeDir(dir, path[i]);
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
appendFile(streamName, locators, position, size, fileName) {
|
|
|
|
let path = streamName + '/' + fileName;
|
|
|
|
path = path.split('/');
|
|
|
|
let dir = this.makePath(path.slice(0, path.length - 1));
|
|
|
|
if (!(fileName in dir.files))
|
|
|
|
dir.files[fileName] = new CMFile();
|
|
|
|
dir.files[fileName].append(locators, position, size);
|
|
|
|
file[0] = file[0].concat(blockRefs);
|
|
|
|
file[1] += size;
|
|
|
|
}
|
|
|
|
|
|
|
|
parse(manifest_text) {
|
|
|
|
let rx = /^[a-f0-9]{32}\+[0-9]+/;
|
|
|
|
|
|
|
|
let streams = manifest_text.split('\n');
|
|
|
|
if (!streams[streams.length - 1])
|
|
|
|
streams = streams.slice(0, streams.length - 1);
|
|
|
|
|
|
|
|
streams.map(s => {
|
|
|
|
let tokens = s.split(' ');
|
|
|
|
let streamName = tokens[0];
|
|
|
|
let streamName = this.unescapeName(tokens[0]);
|
|
|
|
|
|
|
|
let n = tokens.map(t => rx.exec(t));
|
|
|
|
n = n.indexOf(null, 1);
|
|
|
@@ -104,11 +106,61 @@ class WBManifestReader { |
|
|
|
let fileTokens = tokens.slice(n);
|
|
|
|
fileTokens.map(t => {
|
|
|
|
let [ position, size, fileName ] = t.split(':');
|
|
|
|
fileName = this.unescapeName(fileName);
|
|
|
|
this.appendFile(streamName, locators,
|
|
|
|
Number(position), Number(size), fileName);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
findDir(path) {
|
|
|
|
if (typeof(path) === 'string')
|
|
|
|
path = path.split('/');
|
|
|
|
if (path[0] !== '.')
|
|
|
|
throw Error('Path must begin with a dot component');
|
|
|
|
let dir = this.rootDir;
|
|
|
|
for (let i = 1; i < path.length; i++) {
|
|
|
|
if (!(path[i] in dir))
|
|
|
|
throw Error('Directory not found');
|
|
|
|
if (dir[path[i]] instanceof Array)
|
|
|
|
throw Error('Path is a file not directory');
|
|
|
|
dir = dir[path[i]];
|
|
|
|
}
|
|
|
|
return dir;
|
|
|
|
}
|
|
|
|
|
|
|
|
listDirectory(path) {
|
|
|
|
let dir = this.findDir(path);
|
|
|
|
let keys = Object.keys(dir);
|
|
|
|
keys.sort();
|
|
|
|
let subdirs = keys.filter(k => !(dir[k] instanceof Array));
|
|
|
|
let files = keys.filter(k => (dir[k] instanceof Array));
|
|
|
|
let res = subdirs.map(k => [ 'd', k, null ]);
|
|
|
|
res = res.concat(files.map(k => [ 'f', k, dir[k][1] ]));
|
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
unescapeName(name) {
|
|
|
|
return name.replace(/(\\\\|\\040)/g, (_, $1) => ($1 === '\\\\' ? '\\' : ' '));
|
|
|
|
}
|
|
|
|
|
|
|
|
escapeName(name) {
|
|
|
|
return name.replace(/ /g, '\\040');
|
|
|
|
}
|
|
|
|
/* let ids = { '\\': 1, '0': 2, '4': 3 };
|
|
|
|
let transitions = [
|
|
|
|
[ [0, 0], [1, ''], [0, 0], [0, 0] ],
|
|
|
|
[ [0, 0], [0, '\\'], [2, ''], [0, 0] ],
|
|
|
|
];
|
|
|
|
let mode = 0;
|
|
|
|
for (let i = 0; i < name.length; i++) {
|
|
|
|
let b = name[i];
|
|
|
|
let tokenId = Number(ids[b]);
|
|
|
|
[ mode, out ] = transitions[mode][tokenId];
|
|
|
|
if (out === 0)
|
|
|
|
out = b;
|
|
|
|
}
|
|
|
|
}*/
|
|
|
|
}
|
|
|
|
|
|
|
|
export { WBManifestReader };
|