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.

182 lines
4.6KB

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