1smart-buffer [![Build Status](https://travis-ci.org/JoshGlazebrook/smart-buffer.svg?branch=master)](https://travis-ci.org/JoshGlazebrook/smart-buffer) [![Coverage Status](https://coveralls.io/repos/github/JoshGlazebrook/smart-buffer/badge.svg?branch=master)](https://coveralls.io/github/JoshGlazebrook/smart-buffer?branch=master) 2============= 3 4smart-buffer is a Buffer wrapper that adds automatic read & write offset tracking, string operations, data insertions, and more. 5 6![stats](https://nodei.co/npm/smart-buffer.png?downloads=true&downloadRank=true&stars=true "stats") 7 8**Key Features**: 9* Proxies all of the Buffer write and read functions 10* Keeps track of read and write offsets automatically 11* Grows the internal Buffer as needed 12* Useful string operations. (Null terminating strings) 13* Allows for inserting values at specific points in the Buffer 14* Built in TypeScript 15* Type Definitions Provided 16* Browser Support (using Webpack/Browserify) 17* Full test coverage 18 19**Requirements**: 20* Node v4.0+ is supported at this time. (Versions prior to 2.0 will work on node 0.10) 21 22 23 24## Breaking Changes in v4.0 25 26* Old constructor patterns have been completely removed. It's now required to use the SmartBuffer.fromXXX() factory constructors. 27* rewind(), skip(), moveTo() have been removed. (see [offsets](#offsets)) 28* Internal private properties are now prefixed with underscores (_) 29* **All** writeXXX() methods that are given an offset will now **overwrite data** instead of insert. (see [write vs insert](#write-vs-insert)) 30* insertXXX() methods have been added for when you want to insert data at a specific offset (this replaces the old behavior of writeXXX() when an offset was provided) 31 32 33## Looking for v3 docs? 34 35Legacy documentation for version 3 and prior can be found [here](https://github.com/JoshGlazebrook/smart-buffer/blob/master/docs/README_v3.md). 36 37## Installing: 38 39`yarn add smart-buffer` 40 41or 42 43`npm install smart-buffer` 44 45Note: The published NPM package includes the built javascript library. 46If you cloned this repo and wish to build the library manually use: 47 48`npm run build` 49 50## Using smart-buffer 51 52```javascript 53// Javascript 54const SmartBuffer = require('smart-buffer').SmartBuffer; 55 56// Typescript 57import { SmartBuffer, SmartBufferOptions} from 'smart-buffer'; 58``` 59 60### Simple Example 61 62Building a packet that uses the following protocol specification: 63 64`[PacketType:2][PacketLength:2][Data:XX]` 65 66To build this packet using the vanilla Buffer class, you would have to count up the length of the data payload beforehand. You would also need to keep track of the current "cursor" position in your Buffer so you write everything in the right places. With smart-buffer you don't have to do either of those things. 67 68```javascript 69function createLoginPacket(username, password, age, country) { 70 const packet = new SmartBuffer(); 71 packet.writeUInt16LE(0x0060); // Some packet type 72 packet.writeStringNT(username); 73 packet.writeStringNT(password); 74 packet.writeUInt8(age); 75 packet.writeStringNT(country); 76 packet.insertUInt16LE(packet.length - 2, 2); 77 78 return packet.toBuffer(); 79} 80``` 81With the above function, you now can do this: 82```javascript 83const login = createLoginPacket("Josh", "secret123", 22, "United States"); 84 85// <Buffer 60 00 1e 00 4a 6f 73 68 00 73 65 63 72 65 74 31 32 33 00 16 55 6e 69 74 65 64 20 53 74 61 74 65 73 00> 86``` 87Notice that the `[PacketLength:2]` value (1e 00) was inserted at position 2. 88 89Reading back the packet we created above is just as easy: 90```javascript 91 92const reader = SmartBuffer.fromBuffer(login); 93 94const logininfo = { 95 packetType: reader.readUInt16LE(), 96 packetLength: reader.readUInt16LE(), 97 username: reader.readStringNT(), 98 password: reader.readStringNT(), 99 age: reader.readUInt8(), 100 country: reader.readStringNT() 101}; 102 103/* 104{ 105 packetType: 96, (0x0060) 106 packetLength: 30, 107 username: 'Josh', 108 password: 'secret123', 109 age: 22, 110 country: 'United States' 111} 112*/ 113``` 114 115 116## Write vs Insert 117In prior versions of SmartBuffer, .writeXXX(value, offset) calls would insert data when an offset was provided. In version 4, this will now overwrite the data at the offset position. To insert data there are now corresponding .insertXXX(value, offset) methods. 118 119**SmartBuffer v3**: 120```javascript 121const buff = SmartBuffer.fromBuffer(new Buffer([1,2,3,4,5,6])); 122buff.writeInt8(7, 2); 123console.log(buff.toBuffer()) 124 125// <Buffer 01 02 07 03 04 05 06> 126``` 127 128**SmartBuffer v4**: 129```javascript 130const buff = SmartBuffer.fromBuffer(new Buffer([1,2,3,4,5,6])); 131buff.writeInt8(7, 2); 132console.log(buff.toBuffer()); 133 134// <Buffer 01 02 07 04 05 06> 135``` 136 137To insert you instead should use: 138```javascript 139const buff = SmartBuffer.fromBuffer(new Buffer([1,2,3,4,5,6])); 140buff.insertInt8(7, 2); 141console.log(buff.toBuffer()); 142 143// <Buffer 01 02 07 03 04 05 06> 144``` 145 146**Note:** Insert/Writing to a position beyond the currently tracked internal Buffer will zero pad to your offset. 147 148## Constructing a smart-buffer 149 150There are a few different ways to construct a SmartBuffer instance. 151 152```javascript 153// Creating SmartBuffer from existing Buffer 154const buff = SmartBuffer.fromBuffer(buffer); // Creates instance from buffer. (Uses default utf8 encoding) 155const buff = SmartBuffer.fromBuffer(buffer, 'ascii'); // Creates instance from buffer with ascii encoding for strings. 156 157// Creating SmartBuffer with specified internal Buffer size. (Note: this is not a hard cap, the internal buffer will grow as needed). 158const buff = SmartBuffer.fromSize(1024); // Creates instance with internal Buffer size of 1024. 159const buff = SmartBuffer.fromSize(1024, 'utf8'); // Creates instance with internal Buffer size of 1024, and utf8 encoding for strings. 160 161// Creating SmartBuffer with options object. This one specifies size and encoding. 162const buff = SmartBuffer.fromOptions({ 163 size: 1024, 164 encoding: 'ascii' 165}); 166 167// Creating SmartBuffer with options object. This one specified an existing Buffer. 168const buff = SmartBuffer.fromOptions({ 169 buff: buffer 170}); 171 172// Creating SmartBuffer from a string. 173const buff = SmartBuffer.fromBuffer(Buffer.from('some string', 'utf8')); 174 175// Just want a regular SmartBuffer with all default options? 176const buff = new SmartBuffer(); 177``` 178 179# Api Reference: 180 181**Note:** SmartBuffer is fully documented with Typescript definitions as well as jsdocs so your favorite editor/IDE will have intellisense. 182 183**Table of Contents** 184 1851. [Constructing](#constructing) 1862. **Numbers** 187 1. [Integers](#integers) 188 2. [Floating Points](#floating-point-numbers) 1893. **Strings** 190 1. [Strings](#strings) 191 2. [Null Terminated Strings](#null-terminated-strings) 1924. [Buffers](#buffers) 1935. [Offsets](#offsets) 1946. [Other](#other) 195 196 197## Constructing 198 199### constructor() 200### constructor([options]) 201- ```options``` *{SmartBufferOptions}* An optional options object to construct a SmartBuffer with. 202 203Examples: 204```javascript 205const buff = new SmartBuffer(); 206const buff = new SmartBuffer({ 207 size: 1024, 208 encoding: 'ascii' 209}); 210``` 211 212### Class Method: fromBuffer(buffer[, encoding]) 213- ```buffer``` *{Buffer}* The Buffer instance to wrap. 214- ```encoding``` *{string}* The string encoding to use. ```Default: 'utf8'``` 215 216Examples: 217```javascript 218const someBuffer = Buffer.from('some string'); 219const buff = SmartBuffer.fromBuffer(someBuffer); // Defaults to utf8 220const buff = SmartBuffer.fromBuffer(someBuffer, 'ascii'); 221``` 222 223### Class Method: fromSize(size[, encoding]) 224- ```size``` *{number}* The size to initialize the internal Buffer. 225- ```encoding``` *{string}* The string encoding to use. ```Default: 'utf8'``` 226 227Examples: 228```javascript 229const buff = SmartBuffer.fromSize(1024); // Defaults to utf8 230const buff = SmartBuffer.fromSize(1024, 'ascii'); 231``` 232 233### Class Method: fromOptions(options) 234- ```options``` *{SmartBufferOptions}* The Buffer instance to wrap. 235 236```typescript 237interface SmartBufferOptions { 238 encoding?: BufferEncoding; // Defaults to utf8 239 size?: number; // Defaults to 4096 240 buff?: Buffer; 241} 242``` 243 244Examples: 245```javascript 246const buff = SmartBuffer.fromOptions({ 247 size: 1024 248}; 249const buff = SmartBuffer.fromOptions({ 250 size: 1024, 251 encoding: 'utf8' 252}); 253const buff = SmartBuffer.fromOptions({ 254 encoding: 'utf8' 255}); 256 257const someBuff = Buffer.from('some string', 'utf8'); 258const buff = SmartBuffer.fromOptions({ 259 buffer: someBuff, 260 encoding: 'utf8' 261}); 262``` 263 264## Integers 265 266### readInt8([offset]) 267- ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset``` 268- Returns *{number}* 269 270Read a Int8 value. 271 272### buff.readInt16BE([offset]) 273### buff.readInt16LE([offset]) 274### buff.readUInt16BE([offset]) 275### buff.readUInt16LE([offset]) 276- ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset``` 277- Returns *{number}* 278 279Read a 16 bit integer value. 280 281### buff.readInt32BE([offset]) 282### buff.readInt32LE([offset]) 283### buff.readUInt32BE([offset]) 284### buff.readUInt32LE([offset]) 285- ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset``` 286- Returns *{number}* 287 288Read a 32 bit integer value. 289 290 291### buff.writeInt8(value[, offset]) 292### buff.writeUInt8(value[, offset]) 293- ```value``` *{number}* The value to write. 294- ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset``` 295- Returns *{this}* 296 297Write a Int8 value. 298 299### buff.insertInt8(value, offset) 300### buff.insertUInt8(value, offset) 301- ```value``` *{number}* The value to insert. 302- ```offset``` *{number}* The offset to insert this data at. 303- Returns *{this}* 304 305Insert a Int8 value. 306 307 308### buff.writeInt16BE(value[, offset]) 309### buff.writeInt16LE(value[, offset]) 310### buff.writeUInt16BE(value[, offset]) 311### buff.writeUInt16LE(value[, offset]) 312- ```value``` *{number}* The value to write. 313- ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset``` 314- Returns *{this}* 315 316Write a 16 bit integer value. 317 318### buff.insertInt16BE(value, offset) 319### buff.insertInt16LE(value, offset) 320### buff.insertUInt16BE(value, offset) 321### buff.insertUInt16LE(value, offset) 322- ```value``` *{number}* The value to insert. 323- ```offset``` *{number}* The offset to insert this data at. 324- Returns *{this}* 325 326Insert a 16 bit integer value. 327 328 329### buff.writeInt32BE(value[, offset]) 330### buff.writeInt32LE(value[, offset]) 331### buff.writeUInt32BE(value[, offset]) 332### buff.writeUInt32LE(value[, offset]) 333- ```value``` *{number}* The value to write. 334- ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset``` 335- Returns *{this}* 336 337Write a 32 bit integer value. 338 339### buff.insertInt32BE(value, offset) 340### buff.insertInt32LE(value, offset) 341### buff.insertUInt32BE(value, offset) 342### buff.nsertUInt32LE(value, offset) 343- ```value``` *{number}* The value to insert. 344- ```offset``` *{number}* The offset to insert this data at. 345- Returns *{this}* 346 347Insert a 32 bit integer value. 348 349 350## Floating Point Numbers 351 352### buff.readFloatBE([offset]) 353### buff.readFloatLE([offset]) 354- ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset``` 355- Returns *{number}* 356 357Read a Float value. 358 359### buff.eadDoubleBE([offset]) 360### buff.readDoubleLE([offset]) 361- ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset``` 362- Returns *{number}* 363 364Read a Double value. 365 366 367### buff.writeFloatBE(value[, offset]) 368### buff.writeFloatLE(value[, offset]) 369- ```value``` *{number}* The value to write. 370- ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset``` 371- Returns *{this}* 372 373Write a Float value. 374 375### buff.insertFloatBE(value, offset) 376### buff.insertFloatLE(value, offset) 377- ```value``` *{number}* The value to insert. 378- ```offset``` *{number}* The offset to insert this data at. 379- Returns *{this}* 380 381Insert a Float value. 382 383 384### buff.writeDoubleBE(value[, offset]) 385### buff.writeDoubleLE(value[, offset]) 386- ```value``` *{number}* The value to write. 387- ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset``` 388- Returns *{this}* 389 390Write a Double value. 391 392### buff.insertDoubleBE(value, offset) 393### buff.insertDoubleLE(value, offset) 394- ```value``` *{number}* The value to insert. 395- ```offset``` *{number}* The offset to insert this data at. 396- Returns *{this}* 397 398Insert a Double value. 399 400## Strings 401 402### buff.readString() 403### buff.readString(size[, encoding]) 404### buff.readString(encoding) 405- ```size``` *{number}* The number of bytes to read. **Default:** ```Reads to the end of the Buffer.``` 406- ```encoding``` *{string}* The string encoding to use. **Default:** ```utf8```. 407 408Read a string value. 409 410Examples: 411```javascript 412const buff = SmartBuffer.fromBuffer(Buffer.from('hello there', 'utf8')); 413buff.readString(); // 'hello there' 414buff.readString(2); // 'he' 415buff.readString(2, 'utf8'); // 'he' 416buff.readString('utf8'); // 'hello there' 417``` 418 419### buff.writeString(value) 420### buff.writeString(value[, offset]) 421### buff.writeString(value[, encoding]) 422### buff.writeString(value[, offset[, encoding]]) 423- ```value``` *{string}* The string value to write. 424- ```offset``` *{number}* The offset to write this value to. **Default:** ```Auto managed offset``` 425- ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8``` 426 427Write a string value. 428 429Examples: 430```javascript 431buff.writeString('hello'); // Auto managed offset 432buff.writeString('hello', 2); 433buff.writeString('hello', 'utf8') // Auto managed offset 434buff.writeString('hello', 2, 'utf8'); 435``` 436 437### buff.insertString(value, offset[, encoding]) 438- ```value``` *{string}* The string value to write. 439- ```offset``` *{number}* The offset to write this value to. 440- ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8``` 441 442Insert a string value. 443 444Examples: 445```javascript 446buff.insertString('hello', 2); 447buff.insertString('hello', 2, 'utf8'); 448``` 449 450## Null Terminated Strings 451 452### buff.readStringNT() 453### buff.readStringNT(encoding) 454- ```encoding``` *{string}* The string encoding to use. **Default:** ```utf8```. 455 456Read a null terminated string value. (If a null is not found, it will read to the end of the Buffer). 457 458Examples: 459```javascript 460const buff = SmartBuffer.fromBuffer(Buffer.from('hello\0 there', 'utf8')); 461buff.readStringNT(); // 'hello' 462 463// If we called this again: 464buff.readStringNT(); // ' there' 465``` 466 467### buff.writeStringNT(value) 468### buff.writeStringNT(value[, offset]) 469### buff.writeStringNT(value[, encoding]) 470### buff.writeStringNT(value[, offset[, encoding]]) 471- ```value``` *{string}* The string value to write. 472- ```offset``` *{number}* The offset to write this value to. **Default:** ```Auto managed offset``` 473- ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8``` 474 475Write a null terminated string value. 476 477Examples: 478```javascript 479buff.writeStringNT('hello'); // Auto managed offset <Buffer 68 65 6c 6c 6f 00> 480buff.writeStringNT('hello', 2); // <Buffer 00 00 68 65 6c 6c 6f 00> 481buff.writeStringNT('hello', 'utf8') // Auto managed offset 482buff.writeStringNT('hello', 2, 'utf8'); 483``` 484 485### buff.insertStringNT(value, offset[, encoding]) 486- ```value``` *{string}* The string value to write. 487- ```offset``` *{number}* The offset to write this value to. 488- ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8``` 489 490Insert a null terminated string value. 491 492Examples: 493```javascript 494buff.insertStringNT('hello', 2); 495buff.insertStringNT('hello', 2, 'utf8'); 496``` 497 498## Buffers 499 500### buff.readBuffer([length]) 501- ```length``` *{number}* The number of bytes to read into a Buffer. **Default:** ```Reads to the end of the Buffer``` 502 503Read a Buffer of a specified size. 504 505### buff.writeBuffer(value[, offset]) 506- ```value``` *{Buffer}* The buffer value to write. 507- ```offset``` *{number}* An optional offset to write the value to. **Default:** ```Auto managed offset``` 508 509### buff.insertBuffer(value, offset) 510- ```value``` *{Buffer}* The buffer value to write. 511- ```offset``` *{number}* The offset to write the value to. 512 513 514### buff.readBufferNT() 515 516Read a null terminated Buffer. 517 518### buff.writeBufferNT(value[, offset]) 519- ```value``` *{Buffer}* The buffer value to write. 520- ```offset``` *{number}* An optional offset to write the value to. **Default:** ```Auto managed offset``` 521 522Write a null terminated Buffer. 523 524 525### buff.insertBufferNT(value, offset) 526- ```value``` *{Buffer}* The buffer value to write. 527- ```offset``` *{number}* The offset to write the value to. 528 529Insert a null terminated Buffer. 530 531 532## Offsets 533 534### buff.readOffset 535### buff.readOffset(offset) 536- ```offset``` *{number}* The new read offset value to set. 537- Returns: ```The current read offset``` 538 539Gets or sets the current read offset. 540 541Examples: 542```javascript 543const currentOffset = buff.readOffset; // 5 544 545buff.readOffset = 10; 546 547console.log(buff.readOffset) // 10 548``` 549 550### buff.writeOffset 551### buff.writeOffset(offset) 552- ```offset``` *{number}* The new write offset value to set. 553- Returns: ```The current write offset``` 554 555Gets or sets the current write offset. 556 557Examples: 558```javascript 559const currentOffset = buff.writeOffset; // 5 560 561buff.writeOffset = 10; 562 563console.log(buff.writeOffset) // 10 564``` 565 566### buff.encoding 567### buff.encoding(encoding) 568- ```encoding``` *{string}* The new string encoding to set. 569- Returns: ```The current string encoding``` 570 571Gets or sets the current string encoding. 572 573Examples: 574```javascript 575const currentEncoding = buff.encoding; // 'utf8' 576 577buff.encoding = 'ascii'; 578 579console.log(buff.encoding) // 'ascii' 580``` 581 582## Other 583 584### buff.clear() 585 586Clear and resets the SmartBuffer instance. 587 588### buff.remaining() 589- Returns ```Remaining data left to be read``` 590 591Gets the number of remaining bytes to be read. 592 593 594### buff.internalBuffer 595- Returns: *{Buffer}* 596 597Gets the internally managed Buffer (Includes unmanaged data). 598 599Examples: 600```javascript 601const buff = SmartBuffer.fromSize(16); 602buff.writeString('hello'); 603console.log(buff.InternalBuffer); // <Buffer 68 65 6c 6c 6f 00 00 00 00 00 00 00 00 00 00 00> 604``` 605 606### buff.toBuffer() 607- Returns: *{Buffer}* 608 609Gets a sliced Buffer instance of the internally managed Buffer. (Only includes managed data) 610 611Examples: 612```javascript 613const buff = SmartBuffer.fromSize(16); 614buff.writeString('hello'); 615console.log(buff.toBuffer()); // <Buffer 68 65 6c 6c 6f> 616``` 617 618### buff.toString([encoding]) 619- ```encoding``` *{string}* The string encoding to use when converting to a string. **Default:** ```utf8``` 620- Returns *{string}* 621 622Gets a string representation of all data in the SmartBuffer. 623 624### buff.destroy() 625 626Destroys the SmartBuffer instance. 627 628 629 630## License 631 632This work is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).