├── .gitignore ├── LICENSE ├── README.md ├── index.js ├── package-lock.json ├── package.json └── test └── buffer-test.js /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | npm-debug.log 3 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright Fedor Indutny, 2015. 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a 4 | copy of this software and associated documentation files (the 5 | "Software"), to deal in the Software without restriction, including 6 | without limitation the rights to use, copy, modify, merge, publish, 7 | distribute, sublicense, and/or sell copies of the Software, and to permit 8 | persons to whom the Software is furnished to do so, subject to the 9 | following conditions: 10 | 11 | The above copyright notice and this permission notice shall be included 12 | in all copies or substantial portions of the Software. 13 | 14 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 | OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 16 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN 17 | NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 18 | DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR 19 | OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE 20 | USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # obuf - Offset buffer implementation. 2 | 3 | Byte buffer specialized for data in chunks with special cases for dropping 4 | bytes in the front, merging bytes in to various integer types and 5 | abandoning buffer without penalty for previous chunk merges. 6 | 7 | Used in spyd-transport, part of spdy support for http2. 8 | 9 | This software is licensed under the MIT License. 10 | 11 | By Fedor Indutny, 2015. 12 | 13 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | var Buffer = require('buffer').Buffer; 2 | 3 | function OffsetBuffer() { 4 | this.offset = 0; 5 | this.size = 0; 6 | this.buffers = []; 7 | } 8 | module.exports = OffsetBuffer; 9 | 10 | OffsetBuffer.prototype.isEmpty = function isEmpty() { 11 | return this.size === 0; 12 | }; 13 | 14 | OffsetBuffer.prototype.clone = function clone(size) { 15 | var r = new OffsetBuffer(); 16 | r.offset = this.offset; 17 | r.size = size; 18 | r.buffers = this.buffers.slice(); 19 | return r; 20 | }; 21 | 22 | OffsetBuffer.prototype.toChunks = function toChunks() { 23 | if (this.size === 0) 24 | return []; 25 | 26 | // We are going to slice it anyway 27 | if (this.offset !== 0) { 28 | this.buffers[0] = this.buffers[0].slice(this.offset); 29 | this.offset = 0; 30 | } 31 | 32 | var chunks = [ ]; 33 | var off = 0; 34 | for (var i = 0; off <= this.size && i < this.buffers.length; i++) { 35 | var buf = this.buffers[i]; 36 | off += buf.length; 37 | 38 | // Slice off last buffer 39 | if (off > this.size) { 40 | buf = buf.slice(0, buf.length - (off - this.size)); 41 | this.buffers[i] = buf; 42 | } 43 | 44 | chunks.push(buf); 45 | } 46 | 47 | // If some buffers were skipped - trim length 48 | if (i < this.buffers.length) 49 | this.buffers.length = i; 50 | 51 | return chunks; 52 | }; 53 | 54 | OffsetBuffer.prototype.toString = function toString(enc) { 55 | return this.toChunks().map(function(c) { 56 | return c.toString(enc); 57 | }).join(''); 58 | }; 59 | 60 | OffsetBuffer.prototype.use = function use(buf, off, n) { 61 | this.buffers = [ buf ]; 62 | this.offset = off; 63 | this.size = n; 64 | }; 65 | 66 | OffsetBuffer.prototype.push = function push(data) { 67 | // Ignore empty writes 68 | if (data.length === 0) 69 | return; 70 | 71 | this.size += data.length; 72 | this.buffers.push(data); 73 | }; 74 | 75 | OffsetBuffer.prototype.has = function has(n) { 76 | return this.size >= n; 77 | }; 78 | 79 | OffsetBuffer.prototype.skip = function skip(n) { 80 | if (this.size === 0) 81 | return; 82 | 83 | this.size -= n; 84 | 85 | // Fast case, skip bytes in a first buffer 86 | if (this.offset + n < this.buffers[0].length) { 87 | this.offset += n; 88 | return; 89 | } 90 | 91 | var left = n - (this.buffers[0].length - this.offset); 92 | this.offset = 0; 93 | 94 | for (var shift = 1; left > 0 && shift < this.buffers.length; shift++) { 95 | var buf = this.buffers[shift]; 96 | if (buf.length > left) { 97 | this.offset = left; 98 | break; 99 | } 100 | left -= buf.length; 101 | } 102 | this.buffers = this.buffers.slice(shift); 103 | }; 104 | 105 | OffsetBuffer.prototype.copy = function copy(target, targetOff, off, n) { 106 | if (this.size === 0) 107 | return; 108 | if (off !== 0) 109 | throw new Error('Unsupported offset in .copy()'); 110 | 111 | var toff = targetOff; 112 | var first = this.buffers[0]; 113 | var toCopy = Math.min(n, first.length - this.offset); 114 | first.copy(target, toff, this.offset, this.offset + toCopy); 115 | 116 | toff += toCopy; 117 | var left = n - toCopy; 118 | for (var i = 1; left > 0 && i < this.buffers.length; i++) { 119 | var buf = this.buffers[i]; 120 | var toCopy = Math.min(left, buf.length); 121 | 122 | buf.copy(target, toff, 0, toCopy); 123 | 124 | toff += toCopy; 125 | left -= toCopy; 126 | } 127 | }; 128 | 129 | OffsetBuffer.prototype.take = function take(n) { 130 | if (n === 0) 131 | return new Buffer(0); 132 | 133 | this.size -= n; 134 | 135 | // Fast cases 136 | var first = this.buffers[0].length - this.offset; 137 | if (first === n) { 138 | var r = this.buffers.shift(); 139 | if (this.offset !== 0) { 140 | r = r.slice(this.offset); 141 | this.offset = 0; 142 | } 143 | return r; 144 | } else if (first > n) { 145 | var r = this.buffers[0].slice(this.offset, this.offset + n); 146 | this.offset += n; 147 | return r; 148 | } 149 | 150 | // Allocate and fill buffer 151 | var out = new Buffer(n); 152 | var toOff = 0; 153 | var startOff = this.offset; 154 | for (var i = 0; toOff !== n && i < this.buffers.length; i++) { 155 | var buf = this.buffers[i]; 156 | var toCopy = Math.min(buf.length - startOff, n - toOff); 157 | 158 | buf.copy(out, toOff, startOff, startOff + toCopy); 159 | if (startOff + toCopy < buf.length) { 160 | this.offset = startOff + toCopy; 161 | break; 162 | } else { 163 | toOff += toCopy; 164 | startOff = 0; 165 | } 166 | } 167 | 168 | this.buffers = this.buffers.slice(i); 169 | if (this.buffers.length === 0) 170 | this.offset = 0; 171 | 172 | return out; 173 | }; 174 | 175 | OffsetBuffer.prototype.peekUInt8 = function peekUInt8() { 176 | return this.buffers[0][this.offset]; 177 | }; 178 | 179 | OffsetBuffer.prototype.readUInt8 = function readUInt8() { 180 | this.size -= 1; 181 | var first = this.buffers[0]; 182 | var r = first[this.offset]; 183 | if (++this.offset === first.length) { 184 | this.offset = 0; 185 | this.buffers.shift(); 186 | } 187 | 188 | return r; 189 | }; 190 | 191 | OffsetBuffer.prototype.readUInt16LE = function readUInt16LE() { 192 | var first = this.buffers[0]; 193 | this.size -= 2; 194 | 195 | var r; 196 | var shift; 197 | 198 | // Fast case - first buffer has all bytes 199 | if (first.length - this.offset >= 2) { 200 | r = first.readUInt16LE(this.offset); 201 | shift = 0; 202 | this.offset += 2; 203 | 204 | // One byte here - one byte there 205 | } else { 206 | r = first[this.offset] | (this.buffers[1][0] << 8); 207 | shift = 1; 208 | this.offset = 1; 209 | } 210 | 211 | if (this.offset === this.buffers[shift].length) { 212 | this.offset = 0; 213 | shift++; 214 | } 215 | if (shift !== 0) 216 | this.buffers = this.buffers.slice(shift); 217 | 218 | return r; 219 | }; 220 | 221 | OffsetBuffer.prototype.readUInt24LE = function readUInt24LE() { 222 | var first = this.buffers[0]; 223 | 224 | var r; 225 | var shift; 226 | var firstHas = first.length - this.offset; 227 | 228 | // Fast case - first buffer has all bytes 229 | if (firstHas >= 3) { 230 | r = first.readUInt16LE(this.offset) | (first[this.offset + 2] << 16); 231 | shift = 0; 232 | this.offset += 3; 233 | 234 | // First buffer has 2 of 3 bytes 235 | } else if (firstHas >= 2) { 236 | r = first.readUInt16LE(this.offset) | (this.buffers[1][0] << 16); 237 | shift = 1; 238 | this.offset = 1; 239 | 240 | // Slow case: First buffer has 1 of 3 bytes 241 | } else { 242 | r = first[this.offset]; 243 | this.offset = 0; 244 | this.buffers.shift(); 245 | this.size -= 1; 246 | 247 | r |= this.readUInt16LE() << 8; 248 | return r; 249 | } 250 | 251 | this.size -= 3; 252 | if (this.offset === this.buffers[shift].length) { 253 | this.offset = 0; 254 | shift++; 255 | } 256 | if (shift !== 0) 257 | this.buffers = this.buffers.slice(shift); 258 | 259 | return r; 260 | }; 261 | 262 | OffsetBuffer.prototype.readUInt32LE = function readUInt32LE() { 263 | var first = this.buffers[0]; 264 | 265 | var r; 266 | var shift; 267 | var firstHas = first.length - this.offset; 268 | 269 | // Fast case - first buffer has all bytes 270 | if (firstHas >= 4) { 271 | r = first.readUInt32LE(this.offset); 272 | shift = 0; 273 | this.offset += 4; 274 | 275 | // First buffer has 3 of 4 bytes 276 | } else if (firstHas >= 3) { 277 | r = (first.readUInt16LE(this.offset) | 278 | (first[this.offset + 2] << 16)) + 279 | (this.buffers[1][0] * 0x1000000); 280 | shift = 1; 281 | this.offset = 1; 282 | 283 | // Slow case: First buffer has 2 of 4 bytes 284 | } else if (firstHas >= 2) { 285 | r = first.readUInt16LE(this.offset); 286 | this.offset = 0; 287 | this.buffers.shift(); 288 | this.size -= 2; 289 | 290 | r += this.readUInt16LE() * 0x10000; 291 | return r; 292 | 293 | // Slow case: First buffer has 1 of 4 bytes 294 | } else { 295 | r = first[this.offset]; 296 | this.offset = 0; 297 | this.buffers.shift(); 298 | this.size -= 1; 299 | 300 | r += this.readUInt24LE() * 0x100; 301 | return r; 302 | } 303 | 304 | this.size -= 4; 305 | if (this.offset === this.buffers[shift].length) { 306 | this.offset = 0; 307 | shift++; 308 | } 309 | if (shift !== 0) 310 | this.buffers = this.buffers.slice(shift); 311 | 312 | return r; 313 | }; 314 | 315 | OffsetBuffer.prototype.readUInt16BE = function readUInt16BE() { 316 | var r = this.readUInt16LE(); 317 | 318 | return ((r & 0xff) << 8) | (r >> 8); 319 | }; 320 | 321 | OffsetBuffer.prototype.readUInt24BE = function readUInt24BE() { 322 | var r = this.readUInt24LE(); 323 | 324 | return ((r & 0xff) << 16) | (((r >> 8) & 0xff) << 8) | (r >> 16); 325 | }; 326 | 327 | OffsetBuffer.prototype.readUInt32BE = function readUInt32BE() { 328 | var r = this.readUInt32LE(); 329 | 330 | return (((r & 0xff) << 24) | 331 | (((r >>> 8) & 0xff) << 16) | 332 | (((r >>> 16) & 0xff) << 8) | 333 | (r >>> 24)) >>> 0; 334 | }; 335 | 336 | // Signed number APIs 337 | 338 | function signedInt8(num) { 339 | if (num >= 0x80) 340 | return -(0xff ^ num) - 1; 341 | else 342 | return num; 343 | } 344 | 345 | OffsetBuffer.prototype.peekInt8 = function peekInt8() { 346 | return signedInt8(this.peekUInt8()); 347 | }; 348 | 349 | OffsetBuffer.prototype.readInt8 = function readInt8() { 350 | return signedInt8(this.readUInt8()); 351 | }; 352 | 353 | function signedInt16(num) { 354 | if (num >= 0x8000) 355 | return -(0xffff ^ num) - 1; 356 | else 357 | return num; 358 | } 359 | 360 | OffsetBuffer.prototype.readInt16BE = function readInt16BE() { 361 | return signedInt16(this.readUInt16BE()); 362 | }; 363 | 364 | OffsetBuffer.prototype.readInt16LE = function readInt16LE() { 365 | return signedInt16(this.readUInt16LE()); 366 | }; 367 | 368 | function signedInt24(num) { 369 | if (num >= 0x800000) 370 | return -(0xffffff ^ num) - 1; 371 | else 372 | return num; 373 | } 374 | 375 | OffsetBuffer.prototype.readInt24BE = function readInt24BE() { 376 | return signedInt24(this.readUInt24BE()); 377 | }; 378 | 379 | OffsetBuffer.prototype.readInt24LE = function readInt24LE() { 380 | return signedInt24(this.readUInt24LE()); 381 | }; 382 | 383 | function signedInt32(num) { 384 | if (num >= 0x80000000) 385 | return -(0xffffffff ^ num) - 1; 386 | else 387 | return num; 388 | } 389 | 390 | OffsetBuffer.prototype.readInt32BE = function readInt32BE() { 391 | return signedInt32(this.readUInt32BE()); 392 | }; 393 | 394 | OffsetBuffer.prototype.readInt32LE = function readInt32LE() { 395 | return signedInt32(this.readUInt32LE()); 396 | }; 397 | -------------------------------------------------------------------------------- /package-lock.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obuf", 3 | "version": "1.1.2", 4 | "lockfileVersion": 1, 5 | "requires": true, 6 | "dependencies": { 7 | "commander": { 8 | "version": "2.3.0", 9 | "resolved": "https://registry.npmjs.org/commander/-/commander-2.3.0.tgz", 10 | "integrity": "sha1-/UMOiJgy7DU7ms0d4hfBHLPu+HM=", 11 | "dev": true 12 | }, 13 | "debug": { 14 | "version": "2.0.0", 15 | "resolved": "https://registry.npmjs.org/debug/-/debug-2.0.0.tgz", 16 | "integrity": "sha1-ib2d9nMrUSVrxnBTQrugLtEhMe8=", 17 | "dev": true, 18 | "requires": { 19 | "ms": "0.6.2" 20 | } 21 | }, 22 | "diff": { 23 | "version": "1.0.8", 24 | "resolved": "https://registry.npmjs.org/diff/-/diff-1.0.8.tgz", 25 | "integrity": "sha1-NDJ2MI7Jkbe8giZ+1VvBQR+XFmY=", 26 | "dev": true 27 | }, 28 | "escape-string-regexp": { 29 | "version": "1.0.2", 30 | "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.2.tgz", 31 | "integrity": "sha1-Tbwv5nTnGUnK8/smlc5/LcHZqNE=", 32 | "dev": true 33 | }, 34 | "glob": { 35 | "version": "3.2.3", 36 | "resolved": "https://registry.npmjs.org/glob/-/glob-3.2.3.tgz", 37 | "integrity": "sha1-4xPusknHr/qlxHUoaw4RW1mDlGc=", 38 | "dev": true, 39 | "requires": { 40 | "graceful-fs": "2.0.3", 41 | "inherits": "2.0.3", 42 | "minimatch": "0.2.14" 43 | } 44 | }, 45 | "graceful-fs": { 46 | "version": "2.0.3", 47 | "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-2.0.3.tgz", 48 | "integrity": "sha1-fNLNsiiko/Nule+mzBQt59GhNtA=", 49 | "dev": true 50 | }, 51 | "growl": { 52 | "version": "1.8.1", 53 | "resolved": "https://registry.npmjs.org/growl/-/growl-1.8.1.tgz", 54 | "integrity": "sha1-Sy3sjZB+k9szZiTc7AGDUC+MlCg=", 55 | "dev": true 56 | }, 57 | "inherits": { 58 | "version": "2.0.3", 59 | "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", 60 | "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", 61 | "dev": true 62 | }, 63 | "jade": { 64 | "version": "0.26.3", 65 | "resolved": "https://registry.npmjs.org/jade/-/jade-0.26.3.tgz", 66 | "integrity": "sha1-jxDXl32NefL2/4YqgbBRPMslaGw=", 67 | "dev": true, 68 | "requires": { 69 | "commander": "0.6.1", 70 | "mkdirp": "0.3.0" 71 | }, 72 | "dependencies": { 73 | "commander": { 74 | "version": "0.6.1", 75 | "resolved": "https://registry.npmjs.org/commander/-/commander-0.6.1.tgz", 76 | "integrity": "sha1-+mihT2qUXVTbvlDYzbMyDp47GgY=", 77 | "dev": true 78 | }, 79 | "mkdirp": { 80 | "version": "0.3.0", 81 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.3.0.tgz", 82 | "integrity": "sha1-G79asbqCevI1dRQ0kEJkVfSB/h4=", 83 | "dev": true 84 | } 85 | } 86 | }, 87 | "lru-cache": { 88 | "version": "2.7.3", 89 | "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-2.7.3.tgz", 90 | "integrity": "sha1-bUUk6LlV+V1PW1iFHOId1y+06VI=", 91 | "dev": true 92 | }, 93 | "minimatch": { 94 | "version": "0.2.14", 95 | "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-0.2.14.tgz", 96 | "integrity": "sha1-x054BXT2PG+aCQ6Q775u9TpqdWo=", 97 | "dev": true, 98 | "requires": { 99 | "lru-cache": "2.7.3", 100 | "sigmund": "1.0.1" 101 | } 102 | }, 103 | "minimist": { 104 | "version": "0.0.8", 105 | "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", 106 | "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", 107 | "dev": true 108 | }, 109 | "mkdirp": { 110 | "version": "0.5.0", 111 | "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.0.tgz", 112 | "integrity": "sha1-HXMHam35hs2TROFecfzAWkyavxI=", 113 | "dev": true, 114 | "requires": { 115 | "minimist": "0.0.8" 116 | } 117 | }, 118 | "mocha": { 119 | "version": "1.21.5", 120 | "resolved": "https://registry.npmjs.org/mocha/-/mocha-1.21.5.tgz", 121 | "integrity": "sha1-fFiwkXTfl25DSiOx6NY5hz/FKek=", 122 | "dev": true, 123 | "requires": { 124 | "commander": "2.3.0", 125 | "debug": "2.0.0", 126 | "diff": "1.0.8", 127 | "escape-string-regexp": "1.0.2", 128 | "glob": "3.2.3", 129 | "growl": "1.8.1", 130 | "jade": "0.26.3", 131 | "mkdirp": "0.5.0" 132 | } 133 | }, 134 | "ms": { 135 | "version": "0.6.2", 136 | "resolved": "https://registry.npmjs.org/ms/-/ms-0.6.2.tgz", 137 | "integrity": "sha1-2JwhJMb9wTU9Zai3e/GqxLGTcIw=", 138 | "dev": true 139 | }, 140 | "sigmund": { 141 | "version": "1.0.1", 142 | "resolved": "https://registry.npmjs.org/sigmund/-/sigmund-1.0.1.tgz", 143 | "integrity": "sha1-P/IfGYytIXX587eBhT/ZTQ0ZtZA=", 144 | "dev": true 145 | } 146 | } 147 | } 148 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "obuf", 3 | "version": "1.1.2", 4 | "description": "", 5 | "main": "index.js", 6 | "scripts": { 7 | "test": "mocha test/**/*-test.js" 8 | }, 9 | "repository": { 10 | "type": "git", 11 | "url": "git@github.com:indutny/offset-buffer" 12 | }, 13 | "keywords": [ 14 | "Offset", 15 | "Buffer", 16 | "reader" 17 | ], 18 | "author": "Fedor Indutny ", 19 | "license": "MIT", 20 | "bugs": { 21 | "url": "https://github.com/indutny/offset-buffer/issues" 22 | }, 23 | "homepage": "https://github.com/indutny/offset-buffer", 24 | "devDependencies": { 25 | "mocha": "^1.21.4" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /test/buffer-test.js: -------------------------------------------------------------------------------- 1 | var assert = require('assert'); 2 | var OffsetBuffer = require('../'); 3 | 4 | describe('OffsetBuffer', function() { 5 | var o; 6 | beforeEach(function() { 7 | o = new OffsetBuffer(); 8 | }); 9 | 10 | describe('.take()', function() { 11 | it('should return empty buffer', function() { 12 | var b = new Buffer('hello world'); 13 | o.push(b); 14 | var r = o.take(0); 15 | assert.equal(r.length, 0); 16 | assert.equal(o.size, b.length); 17 | }); 18 | 19 | it('should return the first buffer itself', function() { 20 | var b = new Buffer('hello world'); 21 | o.push(b); 22 | var r = o.take(b.length); 23 | assert(r === b); 24 | assert(o.isEmpty()); 25 | }); 26 | 27 | it('should return the slice of the buffer ', function() { 28 | var b = new Buffer('hello world'); 29 | o.push(b); 30 | assert.equal(o.take(5).toString(), 'hello'); 31 | assert.equal(o.take(1).toString(), ' '); 32 | assert.equal(o.take(5).toString(), 'world'); 33 | assert(o.isEmpty()); 34 | }); 35 | 36 | it('should concat buffers', function() { 37 | o.push(new Buffer('hello')); 38 | o.push(new Buffer(' ')); 39 | o.push(new Buffer('world!')); 40 | assert.equal(o.take(11).toString(), 'hello world'); 41 | assert.equal(o.take(1).toString(), '!'); 42 | assert(o.isEmpty()); 43 | }); 44 | }); 45 | 46 | describe('.skip', function() { 47 | it('should skip bytes', function() { 48 | o.push(new Buffer('hello ')); 49 | o.push(new Buffer('world')); 50 | o.push(new Buffer(' oh gosh')); 51 | 52 | assert.equal(o.take(2).toString(), 'he'); 53 | o.skip(1); 54 | assert.equal(o.take(2).toString(), 'lo'); 55 | o.skip(1); 56 | assert.equal(o.take(2).toString(), 'wo'); 57 | o.skip(4); 58 | assert.equal(o.take(7).toString(), 'oh gosh'); 59 | 60 | assert(o.isEmpty()); 61 | }); 62 | }); 63 | 64 | describe('.peekUInt8', function() { 65 | it('should return and not move by one byte', function() { 66 | o.push(new Buffer([ 0x1, 0x2 ])); 67 | assert.equal(o.peekUInt8(), 1); 68 | assert.equal(o.readUInt8(), 1); 69 | assert.equal(o.peekUInt8(), 2); 70 | assert.equal(o.readUInt8(), 2); 71 | assert(o.isEmpty()); 72 | }); 73 | }); 74 | 75 | describe('.peekInt8', function() { 76 | it('should return signed number', function() { 77 | o.push(new Buffer([ 0x80 ])); 78 | assert.equal(o.peekInt8(), -128); 79 | assert.equal(o.readInt8(), -128); 80 | assert(o.isEmpty()); 81 | }); 82 | }); 83 | 84 | describe('.readUInt8', function() { 85 | it('should return and move by one byte', function() { 86 | o.push(new Buffer([ 0x1, 0x2 ])); 87 | o.push(new Buffer([ 0x3, 0x4 ])); 88 | assert.equal(o.readUInt8(), 1); 89 | assert.equal(o.readUInt8(), 2); 90 | assert.equal(o.readUInt8(), 3); 91 | assert.equal(o.readUInt8(), 4); 92 | assert(o.isEmpty()); 93 | }); 94 | }); 95 | 96 | describe('.readInt8', function() { 97 | it('should return signed number', function() { 98 | o.push(new Buffer([ 0x8f, 0x7f ])); 99 | assert.equal(o.readInt8(), -113); 100 | assert.equal(o.readInt8(), 127); 101 | assert(o.isEmpty()); 102 | }); 103 | }); 104 | 105 | describe('.readUInt16LE', function() { 106 | it('should return and move by two bytes', function() { 107 | o.push(new Buffer([ 0x1, 0x2, 0x3 ])); 108 | o.push(new Buffer([ 0x4, 0x5, 0x6 ])); 109 | assert.equal(o.readUInt16LE(), 0x0201); 110 | assert.equal(o.readUInt16LE(), 0x0403); 111 | assert.equal(o.readUInt16LE(), 0x0605); 112 | assert(o.isEmpty()); 113 | }); 114 | 115 | it('should return and move by two bytes (regression #1)', function() { 116 | o.push(new Buffer([ 0x1 ])); 117 | o.push(new Buffer([ 0x2, 0x3, 0x4 ])); 118 | assert.equal(o.readUInt16LE(), 0x0201); 119 | assert.equal(o.readUInt16LE(), 0x0403); 120 | assert(o.isEmpty()); 121 | }); 122 | }); 123 | 124 | describe('.readInt16LE', function() { 125 | it('should return signed number', function() { 126 | o.push(new Buffer([ 0x23, 0x81 ])); 127 | assert.equal(o.readInt16LE(), -32477); 128 | assert(o.isEmpty()); 129 | }); 130 | }); 131 | 132 | describe('.readUInt24LE', function() { 133 | it('should return and move by three bytes', function() { 134 | o.push(new Buffer([ 0x1, 0x2, 0x3, 0x4, 0x5 ])); 135 | o.push(new Buffer([ 0x6, 0x7 ])); 136 | o.push(new Buffer([ 0x8, 0x9 ])); 137 | assert.equal(o.readUInt24LE(), 0x030201); 138 | assert.equal(o.readUInt24LE(), 0x060504); 139 | assert.equal(o.readUInt24LE(), 0x090807); 140 | assert(o.isEmpty()); 141 | }); 142 | 143 | it('should return and move by three bytes (regression #1)', function() { 144 | o.push(new Buffer([ 0x1, 0x2 ])); 145 | o.push(new Buffer([ 0x3 ])); 146 | assert.equal(o.readUInt24LE(), 0x030201); 147 | assert.equal(o.buffers.length, 0); 148 | assert(o.isEmpty()); 149 | }); 150 | }); 151 | 152 | describe('.readInt24LE', function() { 153 | it('should return signed number', function() { 154 | o.push(new Buffer([ 0x23, 0x45, 0x81 ])); 155 | assert.equal(o.readInt24LE(), -8305373); 156 | assert(o.isEmpty()); 157 | }); 158 | }); 159 | 160 | describe('.readUInt32LE', function() { 161 | it('should return and move by four bytes', function() { 162 | o.push(new Buffer([ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 ])); 163 | o.push(new Buffer([ 0x8, 0x9, 0xa ])); 164 | o.push(new Buffer([ 0xb, 0xc, 0xd ])); 165 | o.push(new Buffer([ 0xe, 0xf, 0x10 ])); 166 | assert.equal(o.readUInt32LE(), 0x04030201); 167 | assert.equal(o.readUInt32LE(), 0x08070605); 168 | assert.equal(o.readUInt32LE(), 0x0c0b0a09); 169 | assert.equal(o.readUInt32LE(), 0x100f0e0d); 170 | assert(o.isEmpty()); 171 | }); 172 | 173 | it('should return and move by four bytes (regression #1)', function() { 174 | o.push(new Buffer([ 0x1, 0x2, 0x3 ])); 175 | o.push(new Buffer([ 0x4 ])); 176 | assert.equal(o.readUInt32LE(), 0x04030201); 177 | assert.equal(o.buffers.length, 0); 178 | assert(o.isEmpty()); 179 | }); 180 | }); 181 | 182 | describe('.readInt32LE', function() { 183 | it('should return signed number', function() { 184 | o.push(new Buffer([ 0xff, 0xff, 0xff, 0xff ])); 185 | assert.equal(o.readInt32LE(), -1); 186 | assert(o.isEmpty()); 187 | }); 188 | }); 189 | 190 | describe('.readUInt16BE', function() { 191 | it('should return and move by two bytes', function() { 192 | o.push(new Buffer([ 0x1, 0x2, 0x3 ])); 193 | o.push(new Buffer([ 0x4, 0x5, 0x6 ])); 194 | assert.equal(o.readUInt16BE(), 0x0102); 195 | assert.equal(o.readUInt16BE(), 0x0304); 196 | assert.equal(o.readUInt16BE(), 0x0506); 197 | assert(o.isEmpty()); 198 | }); 199 | }); 200 | 201 | describe('.readInt16BE', function() { 202 | it('should return signed number', function() { 203 | o.push(new Buffer([ 0x81, 0x23 ])); 204 | assert.equal(o.readInt16BE(), -32477); 205 | assert(o.isEmpty()); 206 | }); 207 | }); 208 | 209 | describe('.readUInt24BE', function() { 210 | it('should return and move by three bytes', function() { 211 | o.push(new Buffer([ 0x1, 0x2, 0x3, 0x4, 0x5 ])); 212 | o.push(new Buffer([ 0x6, 0x7 ])); 213 | o.push(new Buffer([ 0x8, 0x9 ])); 214 | assert.equal(o.readUInt24BE(), 0x010203); 215 | assert.equal(o.readUInt24BE(), 0x040506); 216 | assert.equal(o.readUInt24BE(), 0x070809); 217 | assert(o.isEmpty()); 218 | }); 219 | }); 220 | 221 | describe('.readInt24BE', function() { 222 | it('should return signed number', function() { 223 | o.push(new Buffer([ 0x81, 0x45, 0x23 ])); 224 | assert.equal(o.readInt24BE(), -8305373); 225 | assert(o.isEmpty()); 226 | }); 227 | }); 228 | 229 | describe('.readUInt32BE', function() { 230 | it('should return and move by four bytes', function() { 231 | o.push(new Buffer([ 0x1, 0x2, 0x3, 0x4, 0x5, 0x6, 0x7 ])); 232 | o.push(new Buffer([ 0x8, 0x9, 0xa ])); 233 | o.push(new Buffer([ 0xb, 0xc, 0xd ])); 234 | o.push(new Buffer([ 0xe, 0xf, 0x10 ])); 235 | assert.equal(o.readUInt32BE(), 0x01020304); 236 | assert.equal(o.readUInt32BE(), 0x05060708); 237 | assert.equal(o.readUInt32BE(), 0x090a0b0c); 238 | assert.equal(o.readUInt32BE(), 0x0d0e0f10); 239 | assert(o.isEmpty()); 240 | }); 241 | 242 | it('should return positive values', function() { 243 | o.push(new Buffer([ 0xff, 0xff, 0xff, 0xff ])); 244 | assert.equal(o.readUInt32BE(), 0xffffffff); 245 | assert(o.isEmpty()); 246 | }); 247 | }); 248 | 249 | describe('.readInt32BE', function() { 250 | it('should return signed number', function() { 251 | o.push(new Buffer([ 0xff, 0xff, 0xff, 0xff ])); 252 | assert.equal(o.readInt32BE(), -1); 253 | assert(o.isEmpty()); 254 | }); 255 | }); 256 | 257 | describe('.has', function() { 258 | it('should properly check the amount of the remaining bytes', function() { 259 | o.push(new Buffer([ 1, 2, 3 ])); 260 | assert(o.has(3)); 261 | assert.equal(o.readUInt8(), 0x01); 262 | assert(!o.has(3)); 263 | assert(o.has(2)); 264 | assert.equal(o.readUInt16BE(), 0x0203); 265 | assert(!o.has(1)); 266 | }); 267 | }); 268 | }); 269 | --------------------------------------------------------------------------------