|
|
|
@@ -0,0 +1,114 @@ |
|
|
|
class CMDirectory {
|
|
|
|
constructor() {
|
|
|
|
this.directories = {};
|
|
|
|
this.files = {};
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
class CMFile {
|
|
|
|
constructor() {
|
|
|
|
this.blockRefs = [];
|
|
|
|
this.size = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
append(locators, position, size) {
|
|
|
|
if (size === 0)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let cum = 0;
|
|
|
|
let locHashes = locators.map(loc => loc[0]);
|
|
|
|
let locSizes = locators.map(loc => loc[1]);
|
|
|
|
let locPositions = locators.map(loc => {
|
|
|
|
let res = cum;
|
|
|
|
cum += loc[1];
|
|
|
|
return res;
|
|
|
|
});
|
|
|
|
|
|
|
|
let used = locators.map((_, i) => (locPositions[i] + locSizes[i] > position &&
|
|
|
|
locPositions[i] < position + size));
|
|
|
|
|
|
|
|
let startBlock = used.indexOf(true);
|
|
|
|
let endBlock = used.lastIndexOf(true) + 1;
|
|
|
|
|
|
|
|
console.log('startBlock: ' + startBlock + ', endBlock: ' + endBlock);
|
|
|
|
|
|
|
|
if (startBlock === -1)
|
|
|
|
return;
|
|
|
|
|
|
|
|
let blockRefs = [];
|
|
|
|
let runPos = position;
|
|
|
|
let runSize = size;
|
|
|
|
|
|
|
|
for (let i = startBlock; i < endBlock; i++) {
|
|
|
|
let blockPos = runPos - locPositions[i];
|
|
|
|
let blockSize = Math.min(runSize, locSizes[i] - blockPos);
|
|
|
|
blockRefs.push([ locHashes[i], blockPos, blockSize ]);
|
|
|
|
runPos += blockSize;
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
|
|
|
|
parse(manifest_text) {
|
|
|
|
let rx = /^[a-f0-9]{32}\+[0-9]+/;
|
|
|
|
|
|
|
|
let streams = manifest_text.split('\n');
|
|
|
|
|
|
|
|
streams.map(s => {
|
|
|
|
let tokens = s.split(' ');
|
|
|
|
let streamName = tokens[0];
|
|
|
|
|
|
|
|
let n = tokens.map(t => rx.exec(t));
|
|
|
|
n = n.indexOf(null, 1);
|
|
|
|
|
|
|
|
let locators = tokens.slice(1, n);
|
|
|
|
locators = locators.map(loc => [ loc, Number(loc.split('+')[1]) ]);
|
|
|
|
|
|
|
|
let fileTokens = tokens.slice(n);
|
|
|
|
fileTokens.map(t => {
|
|
|
|
let [ position, size, fileName ] = t.split(':');
|
|
|
|
this.appendFile(streamName, locators,
|
|
|
|
Number(position), Number(size), fileName);
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
export { WBManifestReader };
|