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.

396 lines
8.6 KiB

4 years ago
  1. var Buffer = require('buffer').Buffer;
  2. function OffsetBuffer() {
  3. this.offset = 0;
  4. this.size = 0;
  5. this.buffers = [];
  6. }
  7. module.exports = OffsetBuffer;
  8. OffsetBuffer.prototype.isEmpty = function isEmpty() {
  9. return this.size === 0;
  10. };
  11. OffsetBuffer.prototype.clone = function clone(size) {
  12. var r = new OffsetBuffer();
  13. r.offset = this.offset;
  14. r.size = size;
  15. r.buffers = this.buffers.slice();
  16. return r;
  17. };
  18. OffsetBuffer.prototype.toChunks = function toChunks() {
  19. if (this.size === 0)
  20. return [];
  21. // We are going to slice it anyway
  22. if (this.offset !== 0) {
  23. this.buffers[0] = this.buffers[0].slice(this.offset);
  24. this.offset = 0;
  25. }
  26. var chunks = [ ];
  27. var off = 0;
  28. for (var i = 0; off <= this.size && i < this.buffers.length; i++) {
  29. var buf = this.buffers[i];
  30. off += buf.length;
  31. // Slice off last buffer
  32. if (off > this.size) {
  33. buf = buf.slice(0, buf.length - (off - this.size));
  34. this.buffers[i] = buf;
  35. }
  36. chunks.push(buf);
  37. }
  38. // If some buffers were skipped - trim length
  39. if (i < this.buffers.length)
  40. this.buffers.length = i;
  41. return chunks;
  42. };
  43. OffsetBuffer.prototype.toString = function toString(enc) {
  44. return this.toChunks().map(function(c) {
  45. return c.toString(enc);
  46. }).join('');
  47. };
  48. OffsetBuffer.prototype.use = function use(buf, off, n) {
  49. this.buffers = [ buf ];
  50. this.offset = off;
  51. this.size = n;
  52. };
  53. OffsetBuffer.prototype.push = function push(data) {
  54. // Ignore empty writes
  55. if (data.length === 0)
  56. return;
  57. this.size += data.length;
  58. this.buffers.push(data);
  59. };
  60. OffsetBuffer.prototype.has = function has(n) {
  61. return this.size >= n;
  62. };
  63. OffsetBuffer.prototype.skip = function skip(n) {
  64. if (this.size === 0)
  65. return;
  66. this.size -= n;
  67. // Fast case, skip bytes in a first buffer
  68. if (this.offset + n < this.buffers[0].length) {
  69. this.offset += n;
  70. return;
  71. }
  72. var left = n - (this.buffers[0].length - this.offset);
  73. this.offset = 0;
  74. for (var shift = 1; left > 0 && shift < this.buffers.length; shift++) {
  75. var buf = this.buffers[shift];
  76. if (buf.length > left) {
  77. this.offset = left;
  78. break;
  79. }
  80. left -= buf.length;
  81. }
  82. this.buffers = this.buffers.slice(shift);
  83. };
  84. OffsetBuffer.prototype.copy = function copy(target, targetOff, off, n) {
  85. if (this.size === 0)
  86. return;
  87. if (off !== 0)
  88. throw new Error('Unsupported offset in .copy()');
  89. var toff = targetOff;
  90. var first = this.buffers[0];
  91. var toCopy = Math.min(n, first.length - this.offset);
  92. first.copy(target, toff, this.offset, this.offset + toCopy);
  93. toff += toCopy;
  94. var left = n - toCopy;
  95. for (var i = 1; left > 0 && i < this.buffers.length; i++) {
  96. var buf = this.buffers[i];
  97. var toCopy = Math.min(left, buf.length);
  98. buf.copy(target, toff, 0, toCopy);
  99. toff += toCopy;
  100. left -= toCopy;
  101. }
  102. };
  103. OffsetBuffer.prototype.take = function take(n) {
  104. if (n === 0)
  105. return new Buffer(0);
  106. this.size -= n;
  107. // Fast cases
  108. var first = this.buffers[0].length - this.offset;
  109. if (first === n) {
  110. var r = this.buffers.shift();
  111. if (this.offset !== 0) {
  112. r = r.slice(this.offset);
  113. this.offset = 0;
  114. }
  115. return r;
  116. } else if (first > n) {
  117. var r = this.buffers[0].slice(this.offset, this.offset + n);
  118. this.offset += n;
  119. return r;
  120. }
  121. // Allocate and fill buffer
  122. var out = new Buffer(n);
  123. var toOff = 0;
  124. var startOff = this.offset;
  125. for (var i = 0; toOff !== n && i < this.buffers.length; i++) {
  126. var buf = this.buffers[i];
  127. var toCopy = Math.min(buf.length - startOff, n - toOff);
  128. buf.copy(out, toOff, startOff, startOff + toCopy);
  129. if (startOff + toCopy < buf.length) {
  130. this.offset = startOff + toCopy;
  131. break;
  132. } else {
  133. toOff += toCopy;
  134. startOff = 0;
  135. }
  136. }
  137. this.buffers = this.buffers.slice(i);
  138. if (this.buffers.length === 0)
  139. this.offset = 0;
  140. return out;
  141. };
  142. OffsetBuffer.prototype.peekUInt8 = function peekUInt8() {
  143. return this.buffers[0][this.offset];
  144. };
  145. OffsetBuffer.prototype.readUInt8 = function readUInt8() {
  146. this.size -= 1;
  147. var first = this.buffers[0];
  148. var r = first[this.offset];
  149. if (++this.offset === first.length) {
  150. this.offset = 0;
  151. this.buffers.shift();
  152. }
  153. return r;
  154. };
  155. OffsetBuffer.prototype.readUInt16LE = function readUInt16LE() {
  156. var first = this.buffers[0];
  157. this.size -= 2;
  158. var r;
  159. var shift;
  160. // Fast case - first buffer has all bytes
  161. if (first.length - this.offset >= 2) {
  162. r = first.readUInt16LE(this.offset);
  163. shift = 0;
  164. this.offset += 2;
  165. // One byte here - one byte there
  166. } else {
  167. r = first[this.offset] | (this.buffers[1][0] << 8);
  168. shift = 1;
  169. this.offset = 1;
  170. }
  171. if (this.offset === this.buffers[shift].length) {
  172. this.offset = 0;
  173. shift++;
  174. }
  175. if (shift !== 0)
  176. this.buffers = this.buffers.slice(shift);
  177. return r;
  178. };
  179. OffsetBuffer.prototype.readUInt24LE = function readUInt24LE() {
  180. var first = this.buffers[0];
  181. var r;
  182. var shift;
  183. var firstHas = first.length - this.offset;
  184. // Fast case - first buffer has all bytes
  185. if (firstHas >= 3) {
  186. r = first.readUInt16LE(this.offset) | (first[this.offset + 2] << 16);
  187. shift = 0;
  188. this.offset += 3;
  189. // First buffer has 2 of 3 bytes
  190. } else if (firstHas >= 2) {
  191. r = first.readUInt16LE(this.offset) | (this.buffers[1][0] << 16);
  192. shift = 1;
  193. this.offset = 1;
  194. // Slow case: First buffer has 1 of 3 bytes
  195. } else {
  196. r = first[this.offset];
  197. this.offset = 0;
  198. this.buffers.shift();
  199. this.size -= 1;
  200. r |= this.readUInt16LE() << 8;
  201. return r;
  202. }
  203. this.size -= 3;
  204. if (this.offset === this.buffers[shift].length) {
  205. this.offset = 0;
  206. shift++;
  207. }
  208. if (shift !== 0)
  209. this.buffers = this.buffers.slice(shift);
  210. return r;
  211. };
  212. OffsetBuffer.prototype.readUInt32LE = function readUInt32LE() {
  213. var first = this.buffers[0];
  214. var r;
  215. var shift;
  216. var firstHas = first.length - this.offset;
  217. // Fast case - first buffer has all bytes
  218. if (firstHas >= 4) {
  219. r = first.readUInt32LE(this.offset);
  220. shift = 0;
  221. this.offset += 4;
  222. // First buffer has 3 of 4 bytes
  223. } else if (firstHas >= 3) {
  224. r = (first.readUInt16LE(this.offset) |
  225. (first[this.offset + 2] << 16)) +
  226. (this.buffers[1][0] * 0x1000000);
  227. shift = 1;
  228. this.offset = 1;
  229. // Slow case: First buffer has 2 of 4 bytes
  230. } else if (firstHas >= 2) {
  231. r = first.readUInt16LE(this.offset);
  232. this.offset = 0;
  233. this.buffers.shift();
  234. this.size -= 2;
  235. r += this.readUInt16LE() * 0x10000;
  236. return r;
  237. // Slow case: First buffer has 1 of 4 bytes
  238. } else {
  239. r = first[this.offset];
  240. this.offset = 0;
  241. this.buffers.shift();
  242. this.size -= 1;
  243. r += this.readUInt24LE() * 0x100;
  244. return r;
  245. }
  246. this.size -= 4;
  247. if (this.offset === this.buffers[shift].length) {
  248. this.offset = 0;
  249. shift++;
  250. }
  251. if (shift !== 0)
  252. this.buffers = this.buffers.slice(shift);
  253. return r;
  254. };
  255. OffsetBuffer.prototype.readUInt16BE = function readUInt16BE() {
  256. var r = this.readUInt16LE();
  257. return ((r & 0xff) << 8) | (r >> 8);
  258. };
  259. OffsetBuffer.prototype.readUInt24BE = function readUInt24BE() {
  260. var r = this.readUInt24LE();
  261. return ((r & 0xff) << 16) | (((r >> 8) & 0xff) << 8) | (r >> 16);
  262. };
  263. OffsetBuffer.prototype.readUInt32BE = function readUInt32BE() {
  264. var r = this.readUInt32LE();
  265. return (((r & 0xff) << 24) |
  266. (((r >>> 8) & 0xff) << 16) |
  267. (((r >>> 16) & 0xff) << 8) |
  268. (r >>> 24)) >>> 0;
  269. };
  270. // Signed number APIs
  271. function signedInt8(num) {
  272. if (num >= 0x80)
  273. return -(0xff ^ num) - 1;
  274. else
  275. return num;
  276. }
  277. OffsetBuffer.prototype.peekInt8 = function peekInt8() {
  278. return signedInt8(this.peekUInt8());
  279. };
  280. OffsetBuffer.prototype.readInt8 = function readInt8() {
  281. return signedInt8(this.readUInt8());
  282. };
  283. function signedInt16(num) {
  284. if (num >= 0x8000)
  285. return -(0xffff ^ num) - 1;
  286. else
  287. return num;
  288. }
  289. OffsetBuffer.prototype.readInt16BE = function readInt16BE() {
  290. return signedInt16(this.readUInt16BE());
  291. };
  292. OffsetBuffer.prototype.readInt16LE = function readInt16LE() {
  293. return signedInt16(this.readUInt16LE());
  294. };
  295. function signedInt24(num) {
  296. if (num >= 0x800000)
  297. return -(0xffffff ^ num) - 1;
  298. else
  299. return num;
  300. }
  301. OffsetBuffer.prototype.readInt24BE = function readInt24BE() {
  302. return signedInt24(this.readUInt24BE());
  303. };
  304. OffsetBuffer.prototype.readInt24LE = function readInt24LE() {
  305. return signedInt24(this.readUInt24LE());
  306. };
  307. function signedInt32(num) {
  308. if (num >= 0x80000000)
  309. return -(0xffffffff ^ num) - 1;
  310. else
  311. return num;
  312. }
  313. OffsetBuffer.prototype.readInt32BE = function readInt32BE() {
  314. return signedInt32(this.readUInt32BE());
  315. };
  316. OffsetBuffer.prototype.readInt32LE = function readInt32LE() {
  317. return signedInt32(this.readUInt32LE());
  318. };