StreamingOctetReader.js 5.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. "use strict";
  2. Object.defineProperty(exports, "__esModule", { value: true });
  3. exports.StreamingOctetReader = void 0;
  4. const fromCharCode = String.fromCharCode;
  5. /**
  6. * A streaming reader which internally manages multiple chunks of
  7. * Uint8Array instances. For performance it does not merge the chunks into
  8. * a single Uint8Array instance. Instead it keeps track of the chunks and
  9. * reads across chunk boundaries as needed.
  10. */
  11. class StreamingOctetReader {
  12. constructor() {
  13. this.chunks = [];
  14. /** Total size of all chunks. */
  15. this.chunkSize = 0;
  16. this.x = 0;
  17. }
  18. size() {
  19. return this.chunkSize - this.x;
  20. }
  21. push(chunk) {
  22. this.chunks.push(chunk);
  23. this.chunkSize += chunk.length;
  24. }
  25. assertSize(size) {
  26. if (size > this.size())
  27. throw new RangeError('OUT_OF_BOUNDS');
  28. }
  29. u8() {
  30. this.assertSize(1);
  31. const chunk = this.chunks[0];
  32. let x = this.x;
  33. const octet = chunk[x++];
  34. if (x === chunk.length) {
  35. this.chunks.shift();
  36. this.chunkSize -= chunk.length;
  37. x = 0;
  38. }
  39. this.x = x;
  40. return octet;
  41. }
  42. u32() {
  43. const octet0 = this.u8();
  44. const octet1 = this.u8();
  45. const octet2 = this.u8();
  46. const octet3 = this.u8();
  47. return (octet0 * 0x1000000 + (octet1 << 16) + (octet2 << 8)) | octet3;
  48. }
  49. copy(size, dst, pos) {
  50. if (!size)
  51. return;
  52. this.assertSize(size);
  53. const chunk0 = this.chunks[0];
  54. const size0 = Math.min(chunk0.length - this.x, size);
  55. dst.set(chunk0.subarray(this.x, this.x + size0), pos);
  56. size -= size0;
  57. if (size <= 0) {
  58. this.skipUnsafe(size0);
  59. return;
  60. }
  61. let chunkIndex = 1;
  62. while (size > 0) {
  63. const chunk1 = this.chunks[chunkIndex];
  64. const size1 = Math.min(chunk1.length, size);
  65. dst.set(chunk1.subarray(0, size1), pos + size0);
  66. size -= size1;
  67. chunkIndex++;
  68. }
  69. this.skipUnsafe(size);
  70. }
  71. copyXor(size, dst, pos, mask, maskIndex) {
  72. if (!size)
  73. return;
  74. this.assertSize(size);
  75. const chunk0 = this.chunks[0];
  76. let x = this.x;
  77. const size0 = Math.min(chunk0.length - x, size);
  78. const end = x + size0;
  79. for (; x < end;)
  80. dst[pos++] = chunk0[x++] ^ mask[maskIndex++ % 4];
  81. size -= size0;
  82. if (size <= 0) {
  83. this.skipUnsafe(size0);
  84. return;
  85. }
  86. let chunkIndex = 1;
  87. while (size > 0) {
  88. const chunk1 = this.chunks[chunkIndex++];
  89. const size1 = Math.min(chunk1.length, size);
  90. for (let x = 0; x < size1;)
  91. dst[pos++] = chunk1[x++] ^ mask[maskIndex++ % 4];
  92. size -= size1;
  93. }
  94. this.skipUnsafe(size);
  95. }
  96. buf(size) {
  97. this.assertSize(size);
  98. const buf = new Uint8Array(size);
  99. this.copy(size, buf, 0);
  100. return buf;
  101. }
  102. bufXor(size, mask, maskIndex) {
  103. this.assertSize(size);
  104. const buf = new Uint8Array(size);
  105. this.copyXor(size, buf, 0, mask, maskIndex);
  106. return buf;
  107. }
  108. skipUnsafe(n) {
  109. if (!n)
  110. return;
  111. const chunk = this.chunks[0];
  112. const chunkLength = chunk.length;
  113. const remaining = chunkLength - this.x;
  114. if (remaining > n) {
  115. this.x = this.x + n;
  116. return;
  117. }
  118. this.x = 0;
  119. this.chunks.shift();
  120. this.chunkSize -= chunkLength;
  121. n -= remaining;
  122. this.skipUnsafe(n);
  123. }
  124. skip(n) {
  125. this.assertSize(n);
  126. this.skipUnsafe(n);
  127. }
  128. peek() {
  129. this.assertSize(1);
  130. return this.chunks[0][this.x];
  131. }
  132. /**
  133. * Get current byte value without advancing the cursor.
  134. * @deprecated Use peek() instead.
  135. */
  136. peak() {
  137. return this.peek();
  138. }
  139. utf8(length, mask, maskIndex) {
  140. this.assertSize(length);
  141. let i = 0;
  142. const points = [];
  143. while (i < length) {
  144. let code = this.u8() ^ mask[maskIndex++ % 4];
  145. i++;
  146. if ((code & 0x80) !== 0) {
  147. const octet2 = (this.u8() ^ mask[maskIndex++ % 4]) & 0x3f;
  148. i++;
  149. if ((code & 0xe0) === 0xc0) {
  150. code = ((code & 0x1f) << 6) | octet2;
  151. }
  152. else {
  153. const octet3 = (this.u8() ^ mask[maskIndex++ % 4]) & 0x3f;
  154. i++;
  155. if ((code & 0xf0) === 0xe0) {
  156. code = ((code & 0x1f) << 12) | (octet2 << 6) | octet3;
  157. }
  158. else {
  159. if ((code & 0xf8) === 0xf0) {
  160. const octet4 = (this.u8() ^ mask[maskIndex++ % 4]) & 0x3f;
  161. i++;
  162. let unit = ((code & 0x07) << 0x12) | (octet2 << 0x0c) | (octet3 << 0x06) | octet4;
  163. if (unit > 0xffff) {
  164. unit -= 0x10000;
  165. const unit0 = ((unit >>> 10) & 0x3ff) | 0xd800;
  166. code = 0xdc00 | (unit & 0x3ff);
  167. points.push(unit0);
  168. }
  169. else {
  170. code = unit;
  171. }
  172. }
  173. }
  174. }
  175. }
  176. points.push(code);
  177. }
  178. return fromCharCode.apply(String, points);
  179. }
  180. }
  181. exports.StreamingOctetReader = StreamingOctetReader;
  182. //# sourceMappingURL=StreamingOctetReader.js.map