seq_stream.js 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. import { ByteStream } from "./byte_stream";
  2. const pow2_24 = 16777216;
  3. export class SeqStream {
  4. constructor(parameters = {}) {
  5. this._stream = new ByteStream();
  6. this._length = 0;
  7. this._start = 0;
  8. this.backward = false;
  9. this.appendBlock = 0;
  10. this.prevLength = 0;
  11. this.prevStart = 0;
  12. if ("view" in parameters) {
  13. this.stream = new ByteStream({ view: parameters.view });
  14. }
  15. else if ("buffer" in parameters) {
  16. this.stream = new ByteStream({ buffer: parameters.buffer });
  17. }
  18. else if ("string" in parameters) {
  19. this.stream = new ByteStream({ string: parameters.string });
  20. }
  21. else if ("hexstring" in parameters) {
  22. this.stream = new ByteStream({ hexstring: parameters.hexstring });
  23. }
  24. else if ("stream" in parameters) {
  25. this.stream = parameters.stream.slice();
  26. }
  27. else {
  28. this.stream = new ByteStream();
  29. }
  30. if ("backward" in parameters && parameters.backward) {
  31. this.backward = parameters.backward;
  32. this._start = this.stream.length;
  33. }
  34. if ("length" in parameters && parameters.length > 0) {
  35. this._length = parameters.length;
  36. }
  37. if ("start" in parameters && parameters.start && parameters.start > 0) {
  38. this._start = parameters.start;
  39. }
  40. if ("appendBlock" in parameters && parameters.appendBlock && parameters.appendBlock > 0) {
  41. this.appendBlock = parameters.appendBlock;
  42. }
  43. }
  44. set stream(value) {
  45. this._stream = value;
  46. this.prevLength = this._length;
  47. this._length = value.length;
  48. this.prevStart = this._start;
  49. this._start = 0;
  50. }
  51. get stream() {
  52. return this._stream;
  53. }
  54. set length(value) {
  55. this.prevLength = this._length;
  56. this._length = value;
  57. }
  58. get length() {
  59. if (this.appendBlock) {
  60. return this.start;
  61. }
  62. return this._length;
  63. }
  64. set start(value) {
  65. if (value > this.stream.length)
  66. return;
  67. this.prevStart = this._start;
  68. this.prevLength = this._length;
  69. this._length -= (this.backward) ? (this._start - value) : (value - this._start);
  70. this._start = value;
  71. }
  72. get start() {
  73. return this._start;
  74. }
  75. get buffer() {
  76. return this._stream.buffer.slice(0, this._length);
  77. }
  78. resetPosition() {
  79. this._start = this.prevStart;
  80. this._length = this.prevLength;
  81. }
  82. findPattern(pattern, gap = null) {
  83. if ((gap == null) || (gap > this.length)) {
  84. gap = this.length;
  85. }
  86. const result = this.stream.findPattern(pattern, this.start, this.length, this.backward);
  87. if (result == (-1))
  88. return result;
  89. if (this.backward) {
  90. if (result < (this.start - pattern.length - gap)) {
  91. return (-1);
  92. }
  93. }
  94. else {
  95. if (result > (this.start + pattern.length + gap)) {
  96. return (-1);
  97. }
  98. }
  99. this.start = result;
  100. return result;
  101. }
  102. findFirstIn(patterns, gap = null) {
  103. if ((gap == null) || (gap > this.length)) {
  104. gap = this.length;
  105. }
  106. const result = this.stream.findFirstIn(patterns, this.start, this.length, this.backward);
  107. if (result.id == (-1))
  108. return result;
  109. if (this.backward) {
  110. if (result.position < (this.start - patterns[result.id].length - gap)) {
  111. return {
  112. id: (-1),
  113. position: (this.backward) ? 0 : (this.start + this.length)
  114. };
  115. }
  116. }
  117. else {
  118. if (result.position > (this.start + patterns[result.id].length + gap)) {
  119. return {
  120. id: (-1),
  121. position: (this.backward) ? 0 : (this.start + this.length)
  122. };
  123. }
  124. }
  125. this.start = result.position;
  126. return result;
  127. }
  128. findAllIn(patterns) {
  129. const start = (this.backward) ? (this.start - this.length) : this.start;
  130. return this.stream.findAllIn(patterns, start, this.length);
  131. }
  132. findFirstNotIn(patterns, gap = null) {
  133. if ((gap == null) || (gap > this._length)) {
  134. gap = this._length;
  135. }
  136. const result = this._stream.findFirstNotIn(patterns, this._start, this._length, this.backward);
  137. if ((result.left.id == (-1)) && (result.right.id == (-1))) {
  138. return result;
  139. }
  140. if (this.backward) {
  141. if (result.right.id != (-1)) {
  142. if (result.right.position < (this._start - patterns[result.right.id].length - gap)) {
  143. return {
  144. left: {
  145. id: (-1),
  146. position: this._start
  147. },
  148. right: {
  149. id: (-1),
  150. position: 0
  151. },
  152. value: new ByteStream()
  153. };
  154. }
  155. }
  156. }
  157. else {
  158. if (result.left.id != (-1)) {
  159. if (result.left.position > (this._start + patterns[result.left.id].length + gap)) {
  160. return {
  161. left: {
  162. id: (-1),
  163. position: this._start
  164. },
  165. right: {
  166. id: (-1),
  167. position: 0
  168. },
  169. value: new ByteStream()
  170. };
  171. }
  172. }
  173. }
  174. if (this.backward) {
  175. if (result.left.id == (-1)) {
  176. this.start = 0;
  177. }
  178. else {
  179. this.start = result.left.position;
  180. }
  181. }
  182. else {
  183. if (result.right.id == (-1)) {
  184. this.start = (this._start + this._length);
  185. }
  186. else {
  187. this.start = result.right.position;
  188. }
  189. }
  190. return result;
  191. }
  192. findAllNotIn(patterns) {
  193. const start = (this.backward) ? (this._start - this._length) : this._start;
  194. return this._stream.findAllNotIn(patterns, start, this._length);
  195. }
  196. findFirstSequence(patterns, length = null, gap = null) {
  197. if ((length == null) || (length > this._length)) {
  198. length = this._length;
  199. }
  200. if ((gap == null) || (gap > length)) {
  201. gap = length;
  202. }
  203. const result = this._stream.findFirstSequence(patterns, this._start, length, this.backward);
  204. if (result.value.length == 0) {
  205. return result;
  206. }
  207. if (this.backward) {
  208. if (result.position < (this._start - result.value.length - gap)) {
  209. return {
  210. position: (-1),
  211. value: new ByteStream()
  212. };
  213. }
  214. }
  215. else {
  216. if (result.position > (this._start + result.value.length + gap)) {
  217. return {
  218. position: (-1),
  219. value: new ByteStream()
  220. };
  221. }
  222. }
  223. this.start = result.position;
  224. return result;
  225. }
  226. findAllSequences(patterns) {
  227. const start = (this.backward) ? (this.start - this.length) : this.start;
  228. return this.stream.findAllSequences(patterns, start, this.length);
  229. }
  230. findPairedPatterns(leftPattern, rightPattern, gap = null) {
  231. if ((gap == null) || (gap > this.length)) {
  232. gap = this.length;
  233. }
  234. const start = (this.backward) ? (this.start - this.length) : this.start;
  235. const result = this.stream.findPairedPatterns(leftPattern, rightPattern, start, this.length);
  236. if (result.length) {
  237. if (this.backward) {
  238. if (result[0].right < (this.start - rightPattern.length - gap)) {
  239. return [];
  240. }
  241. }
  242. else {
  243. if (result[0].left > (this.start + leftPattern.length + gap)) {
  244. return [];
  245. }
  246. }
  247. }
  248. return result;
  249. }
  250. findPairedArrays(leftPatterns, rightPatterns, gap = null) {
  251. if ((gap == null) || (gap > this.length)) {
  252. gap = this.length;
  253. }
  254. const start = (this.backward) ? (this.start - this.length) : this.start;
  255. const result = this.stream.findPairedArrays(leftPatterns, rightPatterns, start, this.length);
  256. if (result.length) {
  257. if (this.backward) {
  258. if (result[0].right.position < (this.start - rightPatterns[result[0].right.id].length - gap)) {
  259. return [];
  260. }
  261. }
  262. else {
  263. if (result[0].left.position > (this.start + leftPatterns[result[0].left.id].length + gap)) {
  264. return [];
  265. }
  266. }
  267. }
  268. return result;
  269. }
  270. replacePattern(searchPattern, replacePattern) {
  271. const start = (this.backward) ? (this.start - this.length) : this.start;
  272. return this.stream.replacePattern(searchPattern, replacePattern, start, this.length);
  273. }
  274. skipPatterns(patterns) {
  275. const result = this.stream.skipPatterns(patterns, this.start, this.length, this.backward);
  276. this.start = result;
  277. return result;
  278. }
  279. skipNotPatterns(patterns) {
  280. const result = this.stream.skipNotPatterns(patterns, this.start, this.length, this.backward);
  281. if (result == (-1))
  282. return (-1);
  283. this.start = result;
  284. return result;
  285. }
  286. append(stream) {
  287. this.beforeAppend(stream.length);
  288. this._stream.view.set(stream.view, this._start);
  289. this._length += (stream.length * 2);
  290. this.start = (this._start + stream.length);
  291. this.prevLength -= (stream.length * 2);
  292. }
  293. appendView(view) {
  294. this.beforeAppend(view.length);
  295. this._stream.view.set(view, this._start);
  296. this._length += (view.length * 2);
  297. this.start = (this._start + view.length);
  298. this.prevLength -= (view.length * 2);
  299. }
  300. appendChar(char) {
  301. this.beforeAppend(1);
  302. this._stream.view[this._start] = char;
  303. this._length += 2;
  304. this.start = (this._start + 1);
  305. this.prevLength -= 2;
  306. }
  307. appendUint16(number) {
  308. this.beforeAppend(2);
  309. const value = new Uint16Array([number]);
  310. const view = new Uint8Array(value.buffer);
  311. this.stream.view[this._start] = view[1];
  312. this._stream.view[this._start + 1] = view[0];
  313. this._length += 4;
  314. this.start = this._start + 2;
  315. this.prevLength -= 4;
  316. }
  317. appendUint24(number) {
  318. this.beforeAppend(3);
  319. const value = new Uint32Array([number]);
  320. const view = new Uint8Array(value.buffer);
  321. this._stream.view[this._start] = view[2];
  322. this._stream.view[this._start + 1] = view[1];
  323. this._stream.view[this._start + 2] = view[0];
  324. this._length += 6;
  325. this.start = (this._start + 3);
  326. this.prevLength -= 6;
  327. }
  328. appendUint32(number) {
  329. this.beforeAppend(4);
  330. const value = new Uint32Array([number]);
  331. const view = new Uint8Array(value.buffer);
  332. this._stream.view[this._start] = view[3];
  333. this._stream.view[this._start + 1] = view[2];
  334. this._stream.view[this._start + 2] = view[1];
  335. this._stream.view[this._start + 3] = view[0];
  336. this._length += 8;
  337. this.start = (this._start + 4);
  338. this.prevLength -= 8;
  339. }
  340. appendInt16(number) {
  341. this.beforeAppend(2);
  342. const value = new Int16Array([number]);
  343. const view = new Uint8Array(value.buffer);
  344. this._stream.view[this._start] = view[1];
  345. this._stream.view[this._start + 1] = view[0];
  346. this._length += 4;
  347. this.start = (this._start + 2);
  348. this.prevLength -= 4;
  349. }
  350. appendInt32(number) {
  351. this.beforeAppend(4);
  352. const value = new Int32Array([number]);
  353. const view = new Uint8Array(value.buffer);
  354. this._stream.view[this._start] = view[3];
  355. this._stream.view[this._start + 1] = view[2];
  356. this._stream.view[this._start + 2] = view[1];
  357. this._stream.view[this._start + 3] = view[0];
  358. this._length += 8;
  359. this.start = (this._start + 4);
  360. this.prevLength -= 8;
  361. }
  362. getBlock(size, changeLength = true) {
  363. if (this._length <= 0) {
  364. return new Uint8Array(0);
  365. }
  366. if (this._length < size) {
  367. size = this._length;
  368. }
  369. let result;
  370. if (this.backward) {
  371. const view = this._stream.view.subarray(this._length - size, this._length);
  372. result = new Uint8Array(size);
  373. for (let i = 0; i < size; i++) {
  374. result[size - 1 - i] = view[i];
  375. }
  376. }
  377. else {
  378. result = this._stream.view.subarray(this._start, this._start + size);
  379. }
  380. if (changeLength) {
  381. this.start += ((this.backward) ? ((-1) * size) : size);
  382. }
  383. return result;
  384. }
  385. getUint16(changeLength = true) {
  386. const block = this.getBlock(2, changeLength);
  387. if (block.length < 2)
  388. return 0;
  389. return (block[0] << 8) | block[1];
  390. }
  391. getInt16(changeLength = true) {
  392. const num = this.getUint16(changeLength);
  393. const negative = 0x8000;
  394. if (num & negative) {
  395. return -(negative - (num ^ negative));
  396. }
  397. return num;
  398. }
  399. getUint24(changeLength = true) {
  400. const block = this.getBlock(4, changeLength);
  401. if (block.length < 3)
  402. return 0;
  403. return (block[0] << 16) |
  404. (block[1] << 8) |
  405. block[2];
  406. }
  407. getUint32(changeLength = true) {
  408. const block = this.getBlock(4, changeLength);
  409. if (block.length < 4)
  410. return 0;
  411. return (block[0] * pow2_24) +
  412. (block[1] << 16) +
  413. (block[2] << 8) +
  414. block[3];
  415. }
  416. getInt32(changeLength = true) {
  417. const num = this.getUint32(changeLength);
  418. const negative = 0x80000000;
  419. if (num & negative) {
  420. return -(negative - (num ^ negative));
  421. }
  422. return num;
  423. }
  424. beforeAppend(size) {
  425. if ((this._start + size) > this._stream.length) {
  426. if (size > this.appendBlock) {
  427. this.appendBlock = size + SeqStream.APPEND_BLOCK;
  428. }
  429. this._stream.realloc(this._stream.length + this.appendBlock);
  430. }
  431. }
  432. }
  433. SeqStream.APPEND_BLOCK = 1000;