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.

128 lines
3.0KB

  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 appendFile(dir, name, sidx, seg) {
  20. if (name in dir && (!(dir[name] instanceof Array)))
  21. throw Error('Directory with the same name already exists');
  22. if (!(name in dir))
  23. dir[name] = [];
  24. const f = dir[name];
  25. f.push([ sidx, seg[0], seg[1] ]);
  26. return f;
  27. }
  28. function process(streams) {
  29. const rootDir = {};
  30. streams.map((s, sidx) => {
  31. const [ streamName, locators, segments ] = s;
  32. const streamDir = mkpath(rootDir, streamName);
  33. segments.map((seg, segidx) => {
  34. let name = seg[2].split('/');
  35. const dir = (name.length === 1 ? streamDir :
  36. mkpath(streamDir, ['.'].concat(name.slice(0, name.length - 1))));
  37. name = name[name.length - 1];
  38. appendFile(dir, name, sidx, seg);
  39. });
  40. });
  41. return rootDir;
  42. }
  43. function parse(manifestText) {
  44. const M_STREAM_NAME = 0;
  45. const M_LOCATORS = 1;
  46. const M_FILE_SEGMENTS = 2;
  47. let mode = M_STREAM_NAME;
  48. const streams = [];
  49. let locators = [];
  50. let segments = [];
  51. let streamName;
  52. let accum = '';
  53. let tokenStart = 0;
  54. for (let i = 0; i < manifestText.length; i++) {
  55. const c = manifestText[i];
  56. if (mode === M_STREAM_NAME) {
  57. if (c === ' ') {
  58. mode = M_LOCATORS;
  59. streamName = accum;
  60. accum = '';
  61. tokenStart = i + 1;
  62. } else {
  63. accum += c;
  64. }
  65. } else if (mode === M_LOCATORS) {
  66. if (c === ':') {
  67. mode = M_FILE_SEGMENTS;
  68. accum = '';
  69. i = tokenStart - 1;
  70. let pos = 0;
  71. locators = locators.map(loc => {
  72. const r = loc.concat([ pos, pos + loc[1] ]);
  73. pos += loc[1];
  74. return r;
  75. });
  76. } else if (c === ' ') {
  77. const sz = Number(accum.split('+')[1]);
  78. locators.push([accum, sz]);
  79. accum = '';
  80. tokenStart = i + 1;
  81. } else {
  82. accum += c;
  83. }
  84. } else if (mode === M_FILE_SEGMENTS) {
  85. if (c === ' ' || c === '\n') {
  86. let seg = accum.split(':');
  87. seg = [Number(seg[0]), Number(seg[1]), seg[2]];
  88. segments.push(seg);
  89. accum = '';
  90. tokenStart = i + 1;
  91. if (c === '\n') {
  92. streams.push([streamName, locators, segments]);
  93. locators = [];
  94. segments = [];
  95. mode = M_STREAM_NAME;
  96. }
  97. } else {
  98. accum += c;
  99. }
  100. }
  101. }
  102. return streams;
  103. }
  104. class WBManifestReader {
  105. constructor(manifestText) {
  106. this.streams = parse(manifestText);
  107. this.rootDir = process(this.streams);
  108. }
  109. }
  110. export default WBManifestReader;