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.

194 linhas
5.1KB

  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. const rx = /^[a-f0-9]{32}\+[0-9]+/;
  8. const rootDir = {};
  9. const streams = [];
  10. onmessage = function(e) {
  11. switch (e.data[0]) {
  12. case 'precreatePaths':
  13. precreatePaths(e.data[1]);
  14. postMessage([ 'precreatePathsResult' ]);
  15. break;
  16. case 'parseStream':
  17. parseStream(e.data[1]);
  18. postMessage([ 'parseStreamResult' ]);
  19. break;
  20. case 'listDirectory': {
  21. const lst = listDirectory(rootDir, e.data[1], e.data[2]);
  22. postMessage([ 'listDirectoryResult', lst ])
  23. break; }
  24. case 'getData':
  25. postMessage([ 'getDataResult', rootDir, streams ]);
  26. break;
  27. case 'getFile':
  28. postMessage([ 'getFileResult', getFile(rootDir, streams, e.data[1]) ]);
  29. break;
  30. default: {
  31. const err = Error('Unknown verb: ' + e.data[0]);
  32. postMessage([ 'error', err.message ]);
  33. throw err; }
  34. }
  35. }
  36. function precreatePaths(paths) {
  37. for (let i = 0; i < paths.length; i++) {
  38. mkpath(rootDir, paths[i]);
  39. }
  40. }
  41. function parseStream(s) {
  42. if (!s) return;
  43. const tokens = s.split(' ');
  44. const streamName = unescapeName(tokens[0]);
  45. let n = tokens.map(t => rx.exec(t));
  46. n = n.indexOf(null, 1);
  47. let locators = tokens.slice(1, n);
  48. let pos = 0;
  49. locators = locators.map(loc => {
  50. const sz = parseInt(loc.split('+')[1], 10);
  51. return [ loc, pos, pos += sz ];
  52. });
  53. let fileTokens = tokens.slice(n);
  54. let lastFile = null;
  55. let lastPath = null;
  56. fileTokens.map(t => {
  57. let seg = t.split(':');
  58. seg = [ parseInt(seg[0], 10), parseInt(seg[1], 10),
  59. unescapeName(seg.slice(2).join(':')) ]
  60. const path = streamName + '/' + seg[2];
  61. let f;
  62. if (path === lastPath) {
  63. f = lastFile;
  64. } else {
  65. let dirName = path.split('/');
  66. const name = dirName[dirName.length - 1];
  67. dirName = dirName.slice(0, dirName.length - 1);
  68. const d = mkpath(rootDir, dirName);
  69. lastFile = f = makeFile(d, name);
  70. lastPath = path;
  71. }
  72. appendFile(f, streams.length, seg);
  73. });
  74. streams.push(locators);
  75. }
  76. function mkdir(parent, name) {
  77. if (name in parent && (parent[name] instanceof Array))
  78. throw Error('File with the same name already exists');
  79. if (name in parent)
  80. return parent[name];
  81. const dir = {};
  82. parent[name] = dir;
  83. return dir;
  84. }
  85. function mkpath(parent, path) {
  86. if (typeof(path) === 'string')
  87. path = path.split('/');
  88. let dir = parent;
  89. for (let i = 1; i < path.length; i++) {
  90. dir = mkdir(dir, path[i]);
  91. }
  92. return dir;
  93. }
  94. function makeFile(dir, name) {
  95. if (name in dir) {
  96. if (!(dir[name] instanceof Array))
  97. throw Error('Directory with the same name already exists');
  98. return dir[name];
  99. }
  100. const f = [[], 0];
  101. dir[name] = f;
  102. return f;
  103. }
  104. function appendFile(f, sidx, seg) {
  105. f[0].push([ sidx, seg[0], seg[1] ]);
  106. f[1] += seg[1];
  107. return f;
  108. }
  109. function unescapeName(name) {
  110. return name.replace(/(\\\\|\\[0-9]{3})/g,
  111. (_, $1) => ($1 === '\\\\' ? '\\' : String.fromCharCode(parseInt($1.substr(1), 8))));
  112. }
  113. function findDir(parent, path, lenient=false) {
  114. if (typeof(path) === 'string')
  115. path = path.split('/');
  116. if (path[0] !== '.')
  117. throw Error('Path must start with a dot (.)');
  118. let dir = parent;
  119. for (let i = 1; i < path.length; i++) {
  120. if (!(path[i] in dir)) {
  121. if (lenient)
  122. return {};
  123. else
  124. throw Error('Directory not found');
  125. }
  126. dir = dir[path[i]];
  127. }
  128. return dir;
  129. }
  130. function listDirectory(rootDir, path, lenient=false) {
  131. let dir = findDir(rootDir, path, lenient);
  132. let keys = Object.keys(dir);
  133. keys.sort();
  134. let subdirs = keys.filter(k => !(dir[k] instanceof Array));
  135. let files = keys.filter(k => (dir[k] instanceof Array));
  136. let res = subdirs.map(k => [ 'd', k, null ]);
  137. res = res.concat(files.map(k => [ 'f', k, dir[k][1] ]));
  138. return res;
  139. }
  140. function getFile(rootDir, streams, path) {
  141. if (typeof(path) === 'string')
  142. path = path.split('/');
  143. if (path.length < 2)
  144. throw Error('Invalid file path');
  145. const name = path[path.length - 1];
  146. const dir = findDir(rootDir, path.slice(0, path.length - 1));
  147. if (!(name in dir))
  148. throw Error('File not found');
  149. if (!(dir[name] instanceof Array))
  150. throw Error('Path points to a directory not a file');
  151. let file = dir[name];
  152. file = [ file[0].map(seg => {
  153. const stm = streams[seg[0]];
  154. const used = stm.map(loc => !( loc[2] <= seg[1] || loc[1] >= seg[1] + seg[2] ) );
  155. const start = used.indexOf(true);
  156. const end = used.lastIndexOf(true) + 1;
  157. if (start === -1)
  158. return [];
  159. const res = [];
  160. for (let i = start; i < end; i++) {
  161. const loc = stm[i];
  162. res.push([ loc[0], Math.max(0, seg[1] - loc[1]),
  163. Math.min(loc[2] - loc[1], seg[1] + seg[2] - loc[1]) ]);
  164. }
  165. return res;
  166. }), file[1] ];
  167. file[0] = file[0].reduce((a, b) => a.concat(b));
  168. return file;
  169. }