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.

187 lines
4.9KB

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