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.

188 line
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 };