IF YOU WOULD LIKE TO GET AN ACCOUNT, please write an email to s dot adaszewski at gmail dot com. User accounts are meant only to report issues and/or generate pull requests. This is a purpose-specific Git hosting for ADARED projects. Thank you for your understanding!
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

180 lines
5.1KB

  1. //
  2. // Directory: Hash[string, [Directory, File]]
  3. // File = [blockRefs, size]
  4. // blockRefs: Array[blockRef]
  5. // blockRef: [locator, position, size]
  6. // locator: String
  7. // position: Number
  8. // size: Number
  9. //
  10. class WBManifestReader {
  11. constructor(manifest_text) {
  12. this.rootDir = {};
  13. if (!manifest_text)
  14. return;
  15. this.parse(manifest_text);
  16. }
  17. makeDir(parent, name) {
  18. if (!(name in parent))
  19. parent[name] = {};
  20. if (parent[name] instanceof Array)
  21. throw Error('Conflict trying to create a directory - a file with the same name already exists: ' + name);
  22. return parent[name];
  23. }
  24. makePath(path) {
  25. if (typeof(path) === 'string')
  26. path = path.split('/');
  27. let dir = this.rootDir;
  28. for (let i = 1; i < path.length; i++)
  29. dir = this.makeDir(dir, path[i]);
  30. return dir;
  31. }
  32. appendFile(streamName, locators, position, size, fileName) {
  33. let path = streamName + '/' + fileName;
  34. path = path.split('/');
  35. let dir = this.makePath(path.slice(0, path.length - 1));
  36. if (!(fileName in dir))
  37. dir[fileName] = [[], 0];
  38. if (!(dir[fileName] instanceof Array))
  39. throw Error('Conflict trying to create a file - a directory with the same name already exists: ' + fileName);
  40. this.appendReferences(dir[fileName], locators, position, size);
  41. }
  42. appendReferences(file, locators, position, size) {
  43. if (size === 0)
  44. return;
  45. let cum = 0;
  46. let locHashes = locators.map(loc => loc[0]);
  47. let locSizes = locators.map(loc => loc[1]);
  48. let locPositions = locators.map(loc => {
  49. let res = cum;
  50. cum += loc[1];
  51. return res;
  52. });
  53. let used = locators.map((_, i) => (locPositions[i] + locSizes[i] > position &&
  54. locPositions[i] < position + size));
  55. let startBlock = used.indexOf(true);
  56. let endBlock = used.lastIndexOf(true) + 1;
  57. // console.log('startBlock: ' + startBlock + ', endBlock: ' + endBlock);
  58. if (startBlock === -1)
  59. return;
  60. let blockRefs = [];
  61. let runPos = position;
  62. let runSize = size;
  63. for (let i = startBlock; i < endBlock; i++) {
  64. let blockPos = runPos - locPositions[i];
  65. let blockSize = Math.min(runSize, locSizes[i] - blockPos);
  66. blockRefs.push([ locHashes[i], blockPos, blockSize ]);
  67. runPos += blockSize;
  68. runSize -= blockSize;
  69. }
  70. file[0] = file[0].concat(blockRefs);
  71. file[1] += size;
  72. }
  73. parse(manifest_text) {
  74. let rx = /^[a-f0-9]{32}\+[0-9]+/;
  75. let streams = manifest_text.split('\n');
  76. if (!streams[streams.length - 1])
  77. streams = streams.slice(0, streams.length - 1);
  78. streams.map(s => {
  79. let tokens = s.split(' ');
  80. let streamName = this.unescapeName(tokens[0]);
  81. let n = tokens.map(t => rx.exec(t));
  82. n = n.indexOf(null, 1);
  83. let locators = tokens.slice(1, n);
  84. locators = locators.map(loc => [ loc, Number(loc.split('+')[1]) ]);
  85. let fileTokens = tokens.slice(n);
  86. fileTokens.map(t => {
  87. let [ position, size, fileName ] = t.split(':');
  88. fileName = this.unescapeName(fileName);
  89. this.appendFile(streamName, locators,
  90. Number(position), Number(size), fileName);
  91. });
  92. });
  93. }
  94. findDir(path) {
  95. if (typeof(path) === 'string')
  96. path = path.split('/');
  97. if (path[0] !== '.')
  98. throw Error('Path must begin with a dot component');
  99. let dir = this.rootDir;
  100. for (let i = 1; i < path.length; i++) {
  101. if (!(path[i] in dir))
  102. throw Error('Directory not found');
  103. if (dir[path[i]] instanceof Array)
  104. throw Error('Path is a file not directory');
  105. dir = dir[path[i]];
  106. }
  107. return dir;
  108. }
  109. listDirectory(path) {
  110. let dir = this.findDir(path);
  111. let keys = Object.keys(dir);
  112. keys.sort();
  113. let subdirs = keys.filter(k => !(dir[k] instanceof Array));
  114. let files = keys.filter(k => (dir[k] instanceof Array));
  115. let res = subdirs.map(k => [ 'd', k, null ]);
  116. res = res.concat(files.map(k => [ 'f', k, dir[k][1] ]));
  117. return res;
  118. }
  119. unescapeName(name) {
  120. return name.replace(/(\\\\|\\040)/g, (_, $1) => ($1 === '\\\\' ? '\\' : ' '));
  121. }
  122. escapeName(name) {
  123. return name.replace(/ /g, '\\040');
  124. }
  125. /* let ids = { '\\': 1, '0': 2, '4': 3 };
  126. let transitions = [
  127. [ [0, 0], [1, ''], [0, 0], [0, 0] ],
  128. [ [0, 0], [0, '\\'], [2, ''], [0, 0] ],
  129. ];
  130. let mode = 0;
  131. for (let i = 0; i < name.length; i++) {
  132. let b = name[i];
  133. let tokenId = Number(ids[b]);
  134. [ mode, out ] = transitions[mode][tokenId];
  135. if (out === 0)
  136. out = b;
  137. }
  138. }*/
  139. getFile(path) {
  140. if (typeof(path) === 'string')
  141. path = path.split('/');
  142. if (path.length < 2)
  143. throw Error('Invalid file path');
  144. let name = path[path.length - 1];
  145. let dir = this.findDir(path.slice(0, path.length - 1));
  146. if (!(name in dir))
  147. throw Error('File not found');
  148. if (!(dir[name] instanceof Array))
  149. throw Error('Path points to a directory not a file');
  150. return dir[name];
  151. }
  152. }
  153. export { WBManifestReader };