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!
Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

189 linhas
4.8KB

  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. function mkdir(parent, name) {
  8. if (name in parent && (parent[name] instanceof Array))
  9. throw Error('File with the same name already exists');
  10. if (name in parent)
  11. return parent[name];
  12. const dir = {};
  13. parent[name] = dir;
  14. return dir;
  15. }
  16. function mkpath(parent, path) {
  17. if (typeof(path) === 'string')
  18. path = path.split('/');
  19. let dir = parent;
  20. for (let i = 1; i < path.length; i++) {
  21. dir = mkdir(dir, path[i]);
  22. }
  23. return dir;
  24. }
  25. function makeFile(dir, name) {
  26. if (name in dir) {
  27. if (!(dir[name] instanceof Array))
  28. throw Error('Directory with the same name already exists');
  29. return dir[name];
  30. }
  31. const f = [[], 0];
  32. dir[name] = f;
  33. return f;
  34. }
  35. function appendFile(f, sidx, seg) {
  36. f[0].push([ sidx, seg[0], seg[1] ]);
  37. //f[1] += seg[1];
  38. return f;
  39. }
  40. function unescapeName(name) {
  41. return name.replace(/(\\\\|\\[0-9]{3})/g,
  42. (_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8))));
  43. }
  44. function process(streams) {
  45. const rootDir = {};
  46. streams.map((s, sidx) => {
  47. const [ streamName, locators, segments ] = s;
  48. const streamDir = mkpath(rootDir, streamName);
  49. segments.map((seg, segidx) => {
  50. let name = seg[2].split('/');
  51. const dir = (name.length === 1 ? streamDir :
  52. mkpath(streamDir, ['.'].concat(name.slice(0, name.length - 1))));
  53. name = name[name.length - 1];
  54. appendFile(dir, name, sidx, seg);
  55. });
  56. });
  57. return rootDir;
  58. }
  59. function parse(manifestText) {
  60. const M_STREAM_NAME = 0;
  61. const M_LOCATORS = 1;
  62. const M_FILE_SEGMENTS = 2;
  63. let mode = M_STREAM_NAME;
  64. const streams = [];
  65. let locators = [];
  66. let streamName;
  67. let accum = '';
  68. let tokenStart = 0;
  69. let lastFile = null;
  70. let lastPath = null;
  71. const rootDir = {};
  72. for (let i = 0; i < manifestText.length; i++) {
  73. const c = manifestText[i];
  74. if (mode === M_STREAM_NAME) {
  75. if (c === ' ') {
  76. mode = M_LOCATORS;
  77. streamName = unescapeName(accum);
  78. accum = '';
  79. tokenStart = i + 1;
  80. } else {
  81. accum += c;
  82. }
  83. } else if (mode === M_LOCATORS) {
  84. if (c === ':') {
  85. mode = M_FILE_SEGMENTS;
  86. accum = '';
  87. i = tokenStart - 1;
  88. let pos = 0;
  89. locators = locators.map(loc => {
  90. const r = loc.concat([ pos, pos + loc[1] ]);
  91. pos += loc[1];
  92. return r;
  93. });
  94. } else if (c === ' ') {
  95. const sz = Number(accum.split('+')[1]);
  96. locators.push([accum, sz]);
  97. accum = '';
  98. tokenStart = i + 1;
  99. } else {
  100. accum += c;
  101. }
  102. } else if (mode === M_FILE_SEGMENTS) {
  103. if (c === ' ' || c === '\n') {
  104. let seg = accum.split(':');
  105. seg = [Number(seg[0]), Number(seg[1]), seg.slice(2).join(':')];
  106. const path = streamName + '/' + unescapeName(seg[2]);
  107. let f;
  108. if (path !== lastPath) {
  109. let dirName = path.split('/');
  110. const fileName = dirName[dirName.length - 1];
  111. dirName = dirName.slice(0, dirName.length - 1);
  112. const dir = mkpath(rootDir, dirName);
  113. f = makeFile(dir, fileName);
  114. lastPath = path;
  115. lastFile = f;
  116. } else {
  117. f = lastFile;
  118. }
  119. appendFile(f, streams.length, seg);
  120. accum = '';
  121. tokenStart = i + 1;
  122. if (c === '\n') {
  123. streams.push([ streamName, locators ]);
  124. locators = [];
  125. mode = M_STREAM_NAME;
  126. }
  127. } else {
  128. accum += c;
  129. }
  130. }
  131. }
  132. return { rootDir, streams };
  133. }
  134. function findDir(parent, path) {
  135. if (typeof(path) === 'string')
  136. path = path.split('/');
  137. if (path[0] !== '.')
  138. throw Error('Path must start with a dot (.)');
  139. let dir = parent;
  140. for (let i = 1; i < path.length; i++) {
  141. if (!(path[i] in dir))
  142. throw Error('Directory not found');
  143. dir = dir[path[i]];
  144. }
  145. return dir;
  146. }
  147. class WBManifestReader {
  148. constructor(manifestText) {
  149. const {rootDir, streams} = parse(manifestText);
  150. this.rootDir = rootDir;
  151. this.streams = streams;
  152. //this.rootDir = process(this.streams);
  153. }
  154. listDirectory(path) {
  155. let dir = findDir(this.rootDir, path);
  156. let keys = Object.keys(dir);
  157. keys.sort();
  158. let subdirs = keys.filter(k => !(dir[k] instanceof Array));
  159. let files = keys.filter(k => (dir[k] instanceof Array));
  160. let res = subdirs.map(k => [ 'd', k, null ]);
  161. res = res.concat(files.map(k => [ 'f', k, dir[k][1] ]));
  162. return res;
  163. }
  164. }
  165. export default WBManifestReader;