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!
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

188 lignes
5.4KB

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