bit_stream.js 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396
  1. import { bitsToStringArray } from "./bit";
  2. import { ByteStream } from "./byte_stream";
  3. export class BitStream {
  4. constructor(parameters) {
  5. this.buffer = new ArrayBuffer(0);
  6. this.view = new Uint8Array(this.buffer);
  7. this.bitsCount = 0;
  8. if (parameters) {
  9. if ("byteStream" in parameters) {
  10. this.fromByteStream(parameters.byteStream);
  11. }
  12. if ("view" in parameters) {
  13. this.fromUint8Array(parameters.view);
  14. }
  15. if ("buffer" in parameters) {
  16. this.fromArrayBuffer(parameters.buffer);
  17. }
  18. if ("string" in parameters) {
  19. this.fromString(parameters.string);
  20. }
  21. if ("uint32" in parameters) {
  22. this.fromUint32(parameters.uint32);
  23. }
  24. if ("bitsCount" in parameters && parameters.bitsCount) {
  25. this.bitsCount = parameters.bitsCount;
  26. }
  27. }
  28. }
  29. clear() {
  30. this.buffer = new ArrayBuffer(0);
  31. this.view = new Uint8Array(this.buffer);
  32. this.bitsCount = 0;
  33. }
  34. fromByteStream(stream) {
  35. this.fromUint8Array(stream.view);
  36. }
  37. fromArrayBuffer(array) {
  38. this.buffer = array;
  39. this.view = new Uint8Array(array);
  40. this.bitsCount = this.view.length << 3;
  41. }
  42. fromUint8Array(array) {
  43. this.fromArrayBuffer(new Uint8Array(array).buffer);
  44. }
  45. fromString(string) {
  46. const stringLength = string.length;
  47. this.buffer = new ArrayBuffer((stringLength >> 3) + ((stringLength % 8) ? 1 : 0));
  48. this.view = new Uint8Array(this.buffer);
  49. this.bitsCount = ((stringLength >> 3) + 1) << 3;
  50. let byteIndex = 0;
  51. for (let i = 0; i < stringLength; i++) {
  52. if (string[i] == "1")
  53. this.view[byteIndex] |= 1 << (7 - (i % 8));
  54. if (i && (((i + 1) % 8) == 0))
  55. byteIndex++;
  56. }
  57. if (stringLength % 8)
  58. this.shiftRight(8 - (stringLength % 8));
  59. this.bitsCount = stringLength;
  60. }
  61. fromUint32(uint32) {
  62. this.buffer = new ArrayBuffer(4);
  63. this.view = new Uint8Array(this.buffer);
  64. const value = new Uint32Array([uint32]);
  65. const view = new Uint8Array(value.buffer);
  66. for (let i = 3; i >= 0; i--)
  67. this.view[i] = view[3 - i];
  68. this.bitsCount = 32;
  69. }
  70. toString(start, length) {
  71. if (start == null) {
  72. start = 0;
  73. }
  74. if ((start >= this.view.length) || (start < 0)) {
  75. start = 0;
  76. }
  77. if (length == null) {
  78. length = this.view.length - start;
  79. }
  80. if ((length >= this.view.length) || (length < 0)) {
  81. length = this.view.length - start;
  82. }
  83. const result = [];
  84. for (let i = start; i < (start + length); i++) {
  85. result.push(bitsToStringArray[this.view[i]]);
  86. }
  87. return result.join("").substring((this.view.length << 3) - this.bitsCount);
  88. }
  89. shiftRight(shift, needShrink = true) {
  90. if (this.view.length == 0) {
  91. return;
  92. }
  93. if ((shift < 0) || (shift > 8)) {
  94. throw new Error("The \"shift\" parameter must be in range 0-8");
  95. }
  96. if (shift > this.bitsCount) {
  97. throw new Error("The \"shift\" parameter can not be bigger than \"this.bitsCount\"");
  98. }
  99. const shiftMask = 0xFF >> (8 - shift);
  100. this.view[this.view.length - 1] >>= shift;
  101. for (let i = (this.view.length - 2); i >= 0; i--) {
  102. this.view[i + 1] |= (this.view[i] & shiftMask) << (8 - shift);
  103. this.view[i] >>= shift;
  104. }
  105. this.bitsCount -= shift;
  106. if (this.bitsCount == 0) {
  107. this.clear();
  108. }
  109. if (needShrink) {
  110. this.shrink();
  111. }
  112. }
  113. shiftLeft(shift) {
  114. if (this.view.length == 0) {
  115. return;
  116. }
  117. if ((shift < 0) || (shift > 8)) {
  118. throw new Error("The \"shift\" parameter must be in range 0-8");
  119. }
  120. if (shift > this.bitsCount) {
  121. throw new Error("The \"shift\" parameter can not be bigger than \"this.bitsCount\"");
  122. }
  123. const bitsOffset = this.bitsCount & 0x07;
  124. if (bitsOffset > shift) {
  125. this.view[0] &= 0xFF >> (bitsOffset + shift);
  126. }
  127. else {
  128. const view = this.view.slice(1);
  129. view[0] &= 0xFF >> (shift - bitsOffset);
  130. this.buffer = view.buffer;
  131. this.view = view;
  132. }
  133. this.bitsCount -= shift;
  134. if (this.bitsCount == 0) {
  135. this.clear();
  136. }
  137. }
  138. slice(start = 0, end = 0) {
  139. let valueShift = 0;
  140. if (this.bitsCount % 8) {
  141. valueShift = (8 - (this.bitsCount % 8));
  142. }
  143. start += valueShift;
  144. end += valueShift;
  145. const maxEnd = (this.view.length << 3) - 1;
  146. if ((start < 0) || (start > maxEnd)) {
  147. return new BitStream();
  148. }
  149. if (!end) {
  150. end = maxEnd;
  151. }
  152. if ((end < 0) || (end > maxEnd)) {
  153. return new BitStream();
  154. }
  155. if ((end - start + 1) > this.bitsCount) {
  156. return new BitStream();
  157. }
  158. const startIndex = start >> 3;
  159. const startOffset = start & 0x07;
  160. const endIndex = end >> 3;
  161. const endOffset = end & 0x07;
  162. const bitsLength = ((endIndex - startIndex) == 0) ? 1 : (endIndex - startIndex + 1);
  163. const result = new BitStream({
  164. buffer: this.buffer.slice(startIndex, startIndex + bitsLength),
  165. bitsCount: bitsLength << 3,
  166. });
  167. result.view[0] &= (0xFF >> startOffset);
  168. result.view[bitsLength] &= (0xFF << (7 - endOffset));
  169. if (7 - endOffset) {
  170. result.shiftRight(7 - endOffset, false);
  171. }
  172. result.bitsCount = (end - start + 1);
  173. result.shrink();
  174. return result;
  175. }
  176. copy(start = 0, length = 0) {
  177. const maxEnd = (this.view.length << 3) - 1;
  178. if ((start < 0) || (start > maxEnd)) {
  179. return new BitStream();
  180. }
  181. if (!length) {
  182. length = (this.view.length << 3) - start - 1;
  183. }
  184. if (length > this.bitsCount) {
  185. return new BitStream();
  186. }
  187. return this.slice(start, start + length - 1);
  188. }
  189. shrink() {
  190. const currentLength = (this.bitsCount >> 3) + ((this.bitsCount % 8) ? 1 : 0);
  191. if (currentLength < this.view.length) {
  192. const view = this.view.slice(this.view.length - currentLength, (this.view.length - currentLength) + currentLength);
  193. this.view = view;
  194. this.buffer = view.buffer;
  195. }
  196. }
  197. reverseBytes() {
  198. for (let i = 0; i < this.view.length; i++) {
  199. this.view[i] = ((this.view[i] * 0x0802 & 0x22110) | (this.view[i] * 0x8020 & 0x88440)) * 0x10101 >> 16;
  200. }
  201. if (this.bitsCount % 8) {
  202. const currentLength = (this.bitsCount >> 3) + ((this.bitsCount % 8) ? 1 : 0);
  203. this.view[this.view.length - currentLength] >>= (8 - (this.bitsCount & 0x07));
  204. }
  205. }
  206. reverseValue() {
  207. const initialValue = this.toString();
  208. const initialValueLength = initialValue.length;
  209. const reversedValue = new Array(initialValueLength);
  210. for (let i = 0; i < initialValueLength; i++) {
  211. reversedValue[initialValueLength - 1 - i] = initialValue[i];
  212. }
  213. this.fromString(reversedValue.join(""));
  214. }
  215. getNumberValue() {
  216. const byteLength = (this.view.length - 1);
  217. if (byteLength > 3) {
  218. return (-1);
  219. }
  220. if (byteLength == (-1)) {
  221. return 0;
  222. }
  223. const value = new Uint32Array(1);
  224. const view = new Uint8Array(value.buffer);
  225. for (let i = byteLength; i >= 0; i--) {
  226. view[byteLength - i] = this.view[i];
  227. }
  228. return value[0];
  229. }
  230. findPattern(pattern, start, length, backward) {
  231. const stringStream = new ByteStream({
  232. string: this.toString(),
  233. });
  234. const stringPattern = new ByteStream({
  235. string: pattern.toString()
  236. });
  237. return stringStream.findPattern(stringPattern, start, length, backward);
  238. }
  239. findFirstIn(patterns, start, length, backward) {
  240. const stringStream = new ByteStream({
  241. string: this.toString(),
  242. });
  243. const stringPatterns = new Array(patterns.length);
  244. for (let i = 0; i < patterns.length; i++) {
  245. stringPatterns[i] = new ByteStream({
  246. string: patterns[i].toString()
  247. });
  248. }
  249. return stringStream.findFirstIn(stringPatterns, start, length, backward);
  250. }
  251. findAllIn(patterns, start, length) {
  252. const stringStream = new ByteStream({
  253. string: this.toString()
  254. });
  255. const stringPatterns = new Array(patterns.length);
  256. for (let i = 0; i < patterns.length; i++) {
  257. stringPatterns[i] = new ByteStream({
  258. string: patterns[i].toString()
  259. });
  260. }
  261. return stringStream.findAllIn(stringPatterns, start, length);
  262. }
  263. findAllPatternIn(pattern, start, length) {
  264. const stringStream = new ByteStream({
  265. string: this.toString()
  266. });
  267. const stringPattern = new ByteStream({
  268. string: pattern.toString()
  269. });
  270. return stringStream.findAllPatternIn(stringPattern, start, length);
  271. }
  272. findFirstNotIn(patterns, start, length, backward) {
  273. const stringStream = new ByteStream({
  274. string: this.toString()
  275. });
  276. const stringPatterns = new Array(patterns.length);
  277. for (let i = 0; i < patterns.length; i++) {
  278. stringPatterns[i] = new ByteStream({
  279. string: patterns[i].toString()
  280. });
  281. }
  282. return stringStream.findFirstNotIn(stringPatterns, start, length, backward);
  283. }
  284. findAllNotIn(patterns, start, length) {
  285. const stringStream = new ByteStream({
  286. string: this.toString()
  287. });
  288. const stringPatterns = new Array(patterns.length);
  289. for (let i = 0; i < patterns.length; i++) {
  290. stringPatterns[i] = new ByteStream({
  291. string: patterns[i].toString()
  292. });
  293. }
  294. return stringStream.findAllNotIn(stringPatterns, start, length);
  295. }
  296. findFirstSequence(patterns, start, length, backward) {
  297. const stringStream = new ByteStream({
  298. string: this.toString()
  299. });
  300. const stringPatterns = new Array(patterns.length);
  301. for (let i = 0; i < patterns.length; i++) {
  302. stringPatterns[i] = new ByteStream({
  303. string: patterns[i].toString()
  304. });
  305. }
  306. return stringStream.findFirstSequence(stringPatterns, start, length, backward);
  307. }
  308. findAllSequences(patterns, start, length) {
  309. const stringStream = new ByteStream({
  310. string: this.toString()
  311. });
  312. const stringPatterns = new Array(patterns.length);
  313. for (let i = 0; i < patterns.length; i++) {
  314. stringPatterns[i] = new ByteStream({
  315. string: patterns[i].toString()
  316. });
  317. }
  318. return stringStream.findAllSequences(stringPatterns, start, length);
  319. }
  320. findPairedPatterns(leftPattern, rightPattern, start, length) {
  321. const stringStream = new ByteStream({
  322. string: this.toString()
  323. });
  324. const stringLeftPattern = new ByteStream({
  325. string: leftPattern.toString()
  326. });
  327. const stringRightPattern = new ByteStream({
  328. string: rightPattern.toString()
  329. });
  330. return stringStream.findPairedPatterns(stringLeftPattern, stringRightPattern, start, length);
  331. }
  332. findPairedArrays(inputLeftPatterns, inputRightPatterns, start, length) {
  333. const stringStream = new ByteStream({
  334. string: this.toString()
  335. });
  336. const stringLeftPatterns = new Array(inputLeftPatterns.length);
  337. for (let i = 0; i < inputLeftPatterns.length; i++) {
  338. stringLeftPatterns[i] = new ByteStream({
  339. string: inputLeftPatterns[i].toString()
  340. });
  341. }
  342. const stringRightPatterns = new Array(inputRightPatterns.length);
  343. for (let i = 0; i < inputRightPatterns.length; i++) {
  344. stringRightPatterns[i] = new ByteStream({
  345. string: inputRightPatterns[i].toString()
  346. });
  347. }
  348. return stringStream.findPairedArrays(stringLeftPatterns, stringRightPatterns, start, length);
  349. }
  350. replacePattern(searchPattern, replacePattern, start, length) {
  351. const stringStream = new ByteStream({
  352. string: this.toString()
  353. });
  354. const stringSearchPattern = new ByteStream({
  355. string: searchPattern.toString()
  356. });
  357. const stringReplacePattern = new ByteStream({
  358. string: replacePattern.toString()
  359. });
  360. if (stringStream.replacePattern(stringSearchPattern, stringReplacePattern, start, length)) {
  361. this.fromString(stringStream.toString());
  362. return true;
  363. }
  364. return false;
  365. }
  366. skipPatterns(patterns, start, length, backward) {
  367. const stringStream = new ByteStream({
  368. string: this.toString()
  369. });
  370. const stringPatterns = new Array(patterns.length);
  371. for (let i = 0; i < patterns.length; i++) {
  372. stringPatterns[i] = new ByteStream({
  373. string: patterns[i].toString()
  374. });
  375. }
  376. return stringStream.skipPatterns(stringPatterns, start, length, backward);
  377. }
  378. skipNotPatterns(patterns, start, length, backward) {
  379. const stringStream = new ByteStream({
  380. string: this.toString()
  381. });
  382. const stringPatterns = new Array(patterns.length);
  383. for (let i = 0; i < patterns.length; i++) {
  384. stringPatterns[i] = new ByteStream({
  385. string: patterns[i].toString()
  386. });
  387. }
  388. return stringStream.skipNotPatterns(stringPatterns, start, length, backward);
  389. }
  390. append(stream) {
  391. this.fromString([
  392. this.toString(),
  393. stream.toString()
  394. ].join(""));
  395. }
  396. }