|
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180 |
- //
- // 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;
- }
-
- 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);
- }
-
- appendReferences(file, 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;
- }
-
- 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 = this.unescapeName(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(':');
- fileName = fileName.join(':');
- 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(/(\\\\|\\[0-9]{3})/g, (_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8))));
- }
-
- 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;
- }
- }*/
- getFile(path) {
- if (typeof(path) === 'string')
- path = path.split('/');
- if (path.length < 2)
- throw Error('Invalid file path');
- let name = path[path.length - 1];
- let dir = this.findDir(path.slice(0, path.length - 1));
- if (!(name in dir))
- throw Error('File not found');
- if (!(dir[name] instanceof Array))
- throw Error('Path points to a directory not a file');
- return dir[name];
- }
- }
-
- export { WBManifestReader };
|