├── docs
├── ROADMAP.md
├── CHANGELOG.md
└── README_v3.md
├── .prettierrc.yaml
├── .npmignore
├── .vscode
├── settings.json
├── tasks.json.old
└── tasks.json
├── .travis.yml
├── .gitignore
├── tsconfig.json
├── LICENSE
├── tslint.json
├── package.json
├── typings
├── utils.d.ts
└── smartbuffer.d.ts
├── src
├── utils.ts
└── smartbuffer.ts
├── README.md
└── test
└── smartbuffer.test.ts
/docs/ROADMAP.md:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.prettierrc.yaml:
--------------------------------------------------------------------------------
1 | parser: typescript
2 | printWidth: 120
3 | tabWidth: 2
4 | singleQuote: true
5 | trailingComma: none
--------------------------------------------------------------------------------
/.npmignore:
--------------------------------------------------------------------------------
1 | .git*
2 | .idea*
3 | node_modules/
4 | npm-debug.log
5 | coverage
6 | src
7 | test
8 | tslint.json
9 | tsconfig.json
10 | .vscode
11 | .nyc_output
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | // Place your settings in this file to overwrite default and user settings.
2 | {
3 | "tslint.exclude": "node_modules",
4 | "prettier.printWidth": 120,
5 | "prettier.singleQuote": true
6 | }
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: node_js
2 | node_js:
3 | - 6
4 | - 8
5 | - 10
6 | - 12
7 | - stable
8 |
9 | before_script:
10 | - npm install -g typescript
11 | - tsc -p ./
12 |
13 | script: "npm run coveralls"
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | lib-cov
2 | *.seed
3 | *.log
4 | *.csv
5 | *.dat
6 | *.out
7 | *.pid
8 | *.gz
9 |
10 | .idea*
11 |
12 | pids
13 | logs
14 | results
15 | node_modules
16 | npm-debug.log
17 | coverage
18 | build
19 | .nyc_output
20 | .DS_Store
--------------------------------------------------------------------------------
/.vscode/tasks.json.old:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "0.1.0",
5 | "command": "tsc",
6 | "isShellCommand": true,
7 | "args": ["-p", "./"],
8 | "showOutput": "silent",
9 | "problemMatcher": "$tsc"
10 | }
--------------------------------------------------------------------------------
/.vscode/tasks.json:
--------------------------------------------------------------------------------
1 | {
2 | // See https://go.microsoft.com/fwlink/?LinkId=733558
3 | // for the documentation about the tasks.json format
4 | "version": "2.0.0",
5 | "command": "tsc",
6 | "args": [
7 | "-p",
8 | "./"
9 | ],
10 | "problemMatcher": "$tsc",
11 | "tasks": [
12 | {
13 | "label": "tsc",
14 | "type": "shell",
15 | "command": "tsc",
16 | "args": [
17 | "-p",
18 | "./"
19 | ],
20 | "problemMatcher": "$tsc",
21 | "group": "build"
22 | }
23 | ]
24 | }
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compileOnSave": true,
3 | "compilerOptions": {
4 | "target": "es6",
5 | "module": "commonjs",
6 | "sourceMap": true,
7 | "moduleResolution": "node",
8 | "outDir": "build",
9 | "watch": false,
10 | "declaration": true,
11 | "declarationDir": "typings",
12 | "removeComments":false,
13 | "noImplicitAny": true,
14 | "typeRoots": [
15 | "node_modules/@types"
16 | ]
17 | },
18 | "include": [
19 | "src/**/*.ts"
20 | ],
21 | "exclude": [
22 | "node_modules",
23 | ".idea",
24 | "build",
25 | "typings",
26 | "test"
27 | ]
28 | }
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2013-2017 Josh Glazebrook
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy of
6 | this software and associated documentation files (the "Software"), to deal in
7 | the Software without restriction, including without limitation the rights to
8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
9 | the Software, and to permit persons to whom the Software is furnished to do so,
10 | subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21 |
--------------------------------------------------------------------------------
/tslint.json:
--------------------------------------------------------------------------------
1 | {
2 | "rules": {
3 | "class-name": true,
4 | "curly": true,
5 | "eofline": true,
6 | "forin": false,
7 | "indent": [
8 | true,
9 | "spaces"
10 | ],
11 | "label-position": true,
12 | "max-line-length": [
13 | true,
14 | 140
15 | ],
16 | "member-ordering": [
17 | true,
18 | {
19 | "order": [
20 | "public-static-field",
21 | "protected-static-field",
22 | "private-static-field",
23 | "public-instance-field",
24 | "protected-instance-field",
25 | "private-instance-field",
26 | "constructor",
27 | "public-static-method",
28 | "protected-static-method",
29 | "private-static-method",
30 | "public-instance-method",
31 | "protected-instance-method",
32 | "private-instance-method"
33 | ]
34 | }
35 | ],
36 | "no-arg": true,
37 | "no-conditional-assignment": true,
38 | "no-console": [
39 | true,
40 | "debug",
41 | "info",
42 | "time",
43 | "timeEnd",
44 | "trace"
45 | ],
46 | "no-namespace": true,
47 | "no-reference": true,
48 | "no-construct": true,
49 | "no-invalid-this": true,
50 | "no-internal-module": true,
51 | "no-debugger": true,
52 | "no-duplicate-variable": true,
53 | "no-empty": true,
54 | "no-eval": true,
55 | "no-shadowed-variable": true,
56 | "no-string-literal": false,
57 | "no-switch-case-fall-through": false,
58 | "no-consecutive-blank-lines": [
59 | true,
60 | 1
61 | ],
62 | "no-trailing-whitespace": true,
63 | "no-unused-variable": true,
64 | "no-use-before-declare": true,
65 | "no-var-keyword": true,
66 | "one-line": [
67 | true,
68 | "check-catch",
69 | "check-else",
70 | "check-whitespace"
71 | ],
72 | "quotemark": [
73 | true,
74 | "single"
75 | ],
76 | "radix": true,
77 | "semicolon": [
78 | true,
79 | "always"
80 | ],
81 | "triple-equals": [
82 | true,
83 | "allow-null-check"
84 | ],
85 | "variable-name": false,
86 | "switch-default": true,
87 | "whitespace": [
88 | true,
89 | "check-branch",
90 | "check-decl",
91 | "check-operator",
92 | "check-separator",
93 | "check-type"
94 | ]
95 | }
96 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "smart-buffer",
3 | "version": "4.2.0",
4 | "description": "smart-buffer is a Buffer wrapper that adds automatic read & write offset tracking, string operations, data insertions, and more.",
5 | "main": "build/smartbuffer.js",
6 | "contributors": ["syvita"],
7 | "homepage": "https://github.com/JoshGlazebrook/smart-buffer/",
8 | "repository": {
9 | "type": "git",
10 | "url": "https://github.com/JoshGlazebrook/smart-buffer.git"
11 | },
12 | "bugs": {
13 | "url": "https://github.com/JoshGlazebrook/smart-buffer/issues"
14 | },
15 | "keywords": [
16 | "buffer",
17 | "smart",
18 | "packet",
19 | "serialize",
20 | "network",
21 | "cursor",
22 | "simple"
23 | ],
24 | "engines": {
25 | "node": ">= 6.0.0",
26 | "npm": ">= 3.0.0"
27 | },
28 | "author": "Josh Glazebrook",
29 | "license": "MIT",
30 | "readmeFilename": "README.md",
31 | "devDependencies": {
32 | "@types/chai": "4.1.7",
33 | "@types/mocha": "5.2.7",
34 | "@types/node": "^12.0.0",
35 | "chai": "4.2.0",
36 | "coveralls": "3.0.5",
37 | "istanbul": "^0.4.5",
38 | "mocha": "6.2.0",
39 | "mocha-lcov-reporter": "^1.3.0",
40 | "nyc": "14.1.1",
41 | "source-map-support": "0.5.12",
42 | "ts-node": "8.3.0",
43 | "tslint": "5.18.0",
44 | "typescript": "^3.2.1"
45 | },
46 | "typings": "typings/smartbuffer.d.ts",
47 | "dependencies": {},
48 | "scripts": {
49 | "prepublish": "npm install -g typescript && npm run build",
50 | "test": "NODE_ENV=test mocha --recursive --require ts-node/register test/**/*.ts",
51 | "coverage": "NODE_ENV=test nyc npm test",
52 | "coveralls": "NODE_ENV=test nyc npm test && nyc report --reporter=text-lcov | coveralls",
53 | "lint": "tslint --type-check --project tsconfig.json 'src/**/*.ts'",
54 | "build": "tsc -p ./"
55 | },
56 | "nyc": {
57 | "extension": [
58 | ".ts",
59 | ".tsx"
60 | ],
61 | "include": [
62 | "src/*.ts",
63 | "src/**/*.ts"
64 | ],
65 | "exclude": [
66 | "**.*.d.ts",
67 | "node_modules",
68 | "typings"
69 | ],
70 | "require": [
71 | "ts-node/register"
72 | ],
73 | "reporter": [
74 | "json",
75 | "html"
76 | ],
77 | "all": true
78 | }
79 | }
80 |
--------------------------------------------------------------------------------
/docs/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | # Change Log
2 | ## 4.1.0
3 | > Released 07/24/2019
4 | * Adds int64 support for node v12+
5 | * Drops support for node v4
6 |
7 | ## 4.0
8 | > Released 10/21/2017
9 | * Major breaking changes arriving in v4.
10 |
11 | ### New Features
12 | * Ability to read data from a specific offset. ex: readInt8(5)
13 | * Ability to write over data when an offset is given (see breaking changes) ex: writeInt8(5, 0);
14 | * Ability to set internal read and write offsets.
15 |
16 |
17 |
18 | ### Breaking Changes
19 |
20 | * Old constructor patterns have been completely removed. It's now required to use the SmartBuffer.fromXXX() factory constructors. Read more on the v4 docs.
21 | * rewind(), skip(), moveTo() have been removed.
22 | * Internal private properties are now prefixed with underscores (_).
23 | * **All** writeXXX() methods that are given an offset will now **overwrite data** instead of insert
24 | * 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)
25 |
26 |
27 | ### Other Changes
28 | * Standardizd error messaging
29 | * Standardized offset/length bounds and sanity checking
30 | * General overall cleanup of code.
31 |
32 | ## 3.0.3
33 | > Released 02/19/2017
34 | * Adds missing type definitions for some internal functions.
35 |
36 | ## 3.0.2
37 | > Released 02/17/2017
38 |
39 | ### Bug Fixes
40 | * Fixes a bug where using readString with a length of zero resulted in reading the remaining data instead of returning an empty string. (Fixed by Seldszar)
41 |
42 | ## 3.0.1
43 | > Released 02/15/2017
44 |
45 | ### Bug Fixes
46 | * Fixes a bug leftover from the TypeScript refactor where .readIntXXX() resulted in .readUIntXXX() being called by mistake.
47 |
48 | ## 3.0
49 | > Released 02/12/2017
50 |
51 | ### Bug Fixes
52 | * readUIntXXXX() methods will now throw an exception if they attempt to read beyond the bounds of the valid buffer data available.
53 | * **Note** This is technically a breaking change, so version is bumped to 3.x.
54 |
55 | ## 2.0
56 | > Relased 01/30/2017
57 |
58 | ### New Features:
59 |
60 | * Entire package re-written in TypeScript (2.1)
61 | * Backwards compatibility is preserved for now
62 | * New factory methods for creating SmartBuffer instances
63 | * SmartBuffer.fromSize()
64 | * SmartBuffer.fromBuffer()
65 | * SmartBuffer.fromOptions()
66 | * New SmartBufferOptions constructor options
67 | * Added additional tests
68 |
69 | ### Bug Fixes:
70 | * Fixes a bug where reading null terminated strings may result in an exception.
71 |
--------------------------------------------------------------------------------
/typings/utils.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | import { SmartBuffer } from './smartbuffer';
3 | import { Buffer } from 'buffer';
4 | /**
5 | * Error strings
6 | */
7 | declare const ERRORS: {
8 | INVALID_ENCODING: string;
9 | INVALID_SMARTBUFFER_SIZE: string;
10 | INVALID_SMARTBUFFER_BUFFER: string;
11 | INVALID_SMARTBUFFER_OBJECT: string;
12 | INVALID_OFFSET: string;
13 | INVALID_OFFSET_NON_NUMBER: string;
14 | INVALID_LENGTH: string;
15 | INVALID_LENGTH_NON_NUMBER: string;
16 | INVALID_TARGET_OFFSET: string;
17 | INVALID_TARGET_LENGTH: string;
18 | INVALID_READ_BEYOND_BOUNDS: string;
19 | INVALID_WRITE_BEYOND_BOUNDS: string;
20 | };
21 | /**
22 | * Checks if a given encoding is a valid Buffer encoding. (Throws an exception if check fails)
23 | *
24 | * @param { String } encoding The encoding string to check.
25 | */
26 | declare function checkEncoding(encoding: BufferEncoding): void;
27 | /**
28 | * Checks if a given number is a finite integer. (Throws an exception if check fails)
29 | *
30 | * @param { Number } value The number value to check.
31 | */
32 | declare function isFiniteInteger(value: number): boolean;
33 | /**
34 | * Checks if a length value is valid. (Throws an exception if check fails)
35 | *
36 | * @param { Number } length The value to check.
37 | */
38 | declare function checkLengthValue(length: any): void;
39 | /**
40 | * Checks if a offset value is valid. (Throws an exception if check fails)
41 | *
42 | * @param { Number } offset The value to check.
43 | */
44 | declare function checkOffsetValue(offset: any): void;
45 | /**
46 | * Checks if a target offset value is out of bounds. (Throws an exception if check fails)
47 | *
48 | * @param { Number } offset The offset value to check.
49 | * @param { SmartBuffer } buff The SmartBuffer instance to check against.
50 | */
51 | declare function checkTargetOffset(offset: number, buff: SmartBuffer): void;
52 | interface Buffer {
53 | readBigInt64BE(offset?: number): bigint;
54 | readBigInt64LE(offset?: number): bigint;
55 | readBigUInt64BE(offset?: number): bigint;
56 | readBigUInt64LE(offset?: number): bigint;
57 | writeBigInt64BE(value: bigint, offset?: number): number;
58 | writeBigInt64LE(value: bigint, offset?: number): number;
59 | writeBigUInt64BE(value: bigint, offset?: number): number;
60 | writeBigUInt64LE(value: bigint, offset?: number): number;
61 | }
62 | /**
63 | * Throws if Node.js version is too low to support bigint
64 | */
65 | declare function bigIntAndBufferInt64Check(bufferMethod: keyof Buffer): void;
66 | export { ERRORS, isFiniteInteger, checkEncoding, checkOffsetValue, checkLengthValue, checkTargetOffset, bigIntAndBufferInt64Check };
67 |
--------------------------------------------------------------------------------
/src/utils.ts:
--------------------------------------------------------------------------------
1 | import { SmartBuffer } from './smartbuffer';
2 | import { Buffer } from 'buffer';
3 |
4 | /**
5 | * Error strings
6 | */
7 | const ERRORS = {
8 | INVALID_ENCODING: 'Invalid encoding provided. Please specify a valid encoding the internal Node.js Buffer supports.',
9 | INVALID_SMARTBUFFER_SIZE: 'Invalid size provided. Size must be a valid integer greater than zero.',
10 | INVALID_SMARTBUFFER_BUFFER: 'Invalid Buffer provided in SmartBufferOptions.',
11 | INVALID_SMARTBUFFER_OBJECT: 'Invalid SmartBufferOptions object supplied to SmartBuffer constructor or factory methods.',
12 | INVALID_OFFSET: 'An invalid offset value was provided.',
13 | INVALID_OFFSET_NON_NUMBER: 'An invalid offset value was provided. A numeric value is required.',
14 | INVALID_LENGTH: 'An invalid length value was provided.',
15 | INVALID_LENGTH_NON_NUMBER: 'An invalid length value was provived. A numeric value is required.',
16 | INVALID_TARGET_OFFSET: 'Target offset is beyond the bounds of the internal SmartBuffer data.',
17 | INVALID_TARGET_LENGTH: 'Specified length value moves cursor beyong the bounds of the internal SmartBuffer data.',
18 | INVALID_READ_BEYOND_BOUNDS: 'Attempted to read beyond the bounds of the managed data.',
19 | INVALID_WRITE_BEYOND_BOUNDS: 'Attempted to write beyond the bounds of the managed data.'
20 | };
21 |
22 | /**
23 | * Checks if a given encoding is a valid Buffer encoding. (Throws an exception if check fails)
24 | *
25 | * @param { String } encoding The encoding string to check.
26 | */
27 | function checkEncoding(encoding: BufferEncoding) {
28 | if (!Buffer.isEncoding(encoding)) {
29 | throw new Error(ERRORS.INVALID_ENCODING);
30 | }
31 | }
32 |
33 | /**
34 | * Checks if a given number is a finite integer. (Throws an exception if check fails)
35 | *
36 | * @param { Number } value The number value to check.
37 | */
38 | function isFiniteInteger(value: number): boolean {
39 | return typeof value === 'number' && isFinite(value) && isInteger(value);
40 | }
41 |
42 | /**
43 | * Checks if an offset/length value is valid. (Throws an exception if check fails)
44 | *
45 | * @param value The value to check.
46 | * @param offset True if checking an offset, false if checking a length.
47 | */
48 | function checkOffsetOrLengthValue(value: any, offset: boolean) {
49 | if (typeof value === 'number') {
50 | // Check for non finite/non integers
51 | if (!isFiniteInteger(value) || value < 0) {
52 | throw new Error(offset ? ERRORS.INVALID_OFFSET : ERRORS.INVALID_LENGTH);
53 | }
54 | } else {
55 | throw new Error(offset ? ERRORS.INVALID_OFFSET_NON_NUMBER : ERRORS.INVALID_LENGTH_NON_NUMBER);
56 | }
57 | }
58 |
59 | /**
60 | * Checks if a length value is valid. (Throws an exception if check fails)
61 | *
62 | * @param { Number } length The value to check.
63 | */
64 | function checkLengthValue(length: any) {
65 | checkOffsetOrLengthValue(length, false);
66 | }
67 |
68 | /**
69 | * Checks if a offset value is valid. (Throws an exception if check fails)
70 | *
71 | * @param { Number } offset The value to check.
72 | */
73 | function checkOffsetValue(offset: any) {
74 | checkOffsetOrLengthValue(offset, true);
75 | }
76 |
77 | /**
78 | * Checks if a target offset value is out of bounds. (Throws an exception if check fails)
79 | *
80 | * @param { Number } offset The offset value to check.
81 | * @param { SmartBuffer } buff The SmartBuffer instance to check against.
82 | */
83 | function checkTargetOffset(offset: number, buff: SmartBuffer) {
84 | if (offset < 0 || offset > buff.length) {
85 | throw new Error(ERRORS.INVALID_TARGET_OFFSET);
86 | }
87 | }
88 |
89 | /**
90 | * Determines whether a given number is a integer.
91 | * @param value The number to check.
92 | */
93 | function isInteger(value: number) {
94 | return typeof value === 'number' && isFinite(value) && Math.floor(value) === value;
95 | }
96 |
97 | interface Buffer {
98 | readBigInt64BE(offset?: number): bigint;
99 | readBigInt64LE(offset?: number): bigint;
100 | readBigUInt64BE(offset?: number): bigint;
101 | readBigUInt64LE(offset?: number): bigint;
102 |
103 | writeBigInt64BE(value: bigint, offset?: number): number;
104 | writeBigInt64LE(value: bigint, offset?: number): number;
105 | writeBigUInt64BE(value: bigint, offset?: number): number;
106 | writeBigUInt64LE(value: bigint, offset?: number): number;
107 | }
108 |
109 | /**
110 | * Throws if Node.js version is too low to support bigint
111 | */
112 | function bigIntAndBufferInt64Check(bufferMethod: keyof Buffer) {
113 | if (typeof BigInt === 'undefined') {
114 | throw new Error('Platform does not support JS BigInt type.');
115 | }
116 |
117 | if (typeof Buffer.prototype[bufferMethod] === 'undefined') {
118 | throw new Error(`Platform does not support Buffer.prototype.${bufferMethod}.`);
119 | }
120 | }
121 |
122 | export {
123 | ERRORS, isFiniteInteger, checkEncoding, checkOffsetValue,
124 | checkLengthValue, checkTargetOffset, bigIntAndBufferInt64Check
125 | };
126 |
--------------------------------------------------------------------------------
/docs/README_v3.md:
--------------------------------------------------------------------------------
1 | smart-buffer [](https://travis-ci.org/JoshGlazebrook/smart-buffer) [](https://coveralls.io/github/JoshGlazebrook/smart-buffer?branch=master)
2 | =============
3 |
4 | smart-buffer is a light Buffer wrapper that takes away the need to keep track of what position to read and write data to and from the underlying Buffer. It also adds null terminating string operations and **grows** as you add more data.
5 |
6 | 
7 |
8 | ### What it's useful for:
9 |
10 | I created smart-buffer because I wanted to simplify the process of using Buffer for building and reading network packets to send over a socket. Rather than having to keep track of which position I need to write a UInt16 to after adding a string of variable length, I simply don't have to.
11 |
12 | Key Features:
13 | * Proxies all of the Buffer write and read functions.
14 | * Keeps track of read and write positions for you.
15 | * Grows the internal Buffer as you add data to it.
16 | * Useful string operations. (Null terminating strings)
17 | * Allows for inserting values at specific points in the internal Buffer.
18 | * Built in TypeScript
19 | * Type Definitions Provided
20 |
21 | Requirements:
22 | * Node v4.0+ is supported at this time. (Versions prior to 2.0 will work on node 0.10)
23 |
24 |
25 | #### Note:
26 | smart-buffer can be used for writing to an underlying buffer as well as reading from it. It however does not function correctly if you're mixing both read and write operations with each other.
27 |
28 | ## Breaking Changes with 2.0
29 | The latest version (2.0+) is written in TypeScript, and are compiled to ES6 Javascript. This means the earliest Node.js it supports will be 4.x (in strict mode.) If you're using version 6 and above it will work without any issues. From an API standpoint, 2.0 is backwards compatible. The only difference is SmartBuffer is not exported directly as the root module.
30 |
31 | ## Breaking Changes with 3.0
32 | Starting with 3.0, if any of the readIntXXXX() methods are called and the requested data is larger than the bounds of the internally managed valid buffer data, an exception will now be thrown.
33 |
34 | ## Installing:
35 |
36 | `npm install smart-buffer`
37 |
38 | or
39 |
40 | `yarn add smart-buffer`
41 |
42 | Note: The published NPM package includes the built javascript library.
43 | If you cloned this repo and wish to build the library manually use:
44 |
45 | `tsc -p ./`
46 |
47 | ## Using smart-buffer
48 |
49 | ### Example
50 |
51 | Say you were building a packet that had to conform to the following protocol:
52 |
53 | `[PacketType:2][PacketLength:2][Data:XX]`
54 |
55 | To 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.
56 |
57 | ```javascript
58 | // 1.x (javascript)
59 | var SmartBuffer = require('smart-buffer');
60 |
61 | // 1.x (typescript)
62 | import SmartBuffer = require('smart-buffer');
63 |
64 | // 2.x+ (javascript)
65 | const SmartBuffer = require('smart-buffer').SmartBuffer;
66 |
67 | // 2.x+ (typescript)
68 | import { SmartBuffer, SmartBufferOptions} from 'smart-buffer';
69 |
70 | function createLoginPacket(username, password, age, country) {
71 | let packet = new SmartBuffer();
72 | packet.writeUInt16LE(0x0060); // Login Packet Type/ID
73 | packet.writeStringNT(username);
74 | packet.writeStringNT(password);
75 | packet.writeUInt8(age);
76 | packet.writeStringNT(country);
77 | packet.writeUInt16LE(packet.length - 2, 2);
78 |
79 | return packet.toBuffer();
80 | }
81 | ```
82 | With the above function, you now can do this:
83 | ```javascript
84 | let login = createLoginPacket("Josh", "secret123", 22, "United States");
85 |
86 | //
87 | ```
88 | Notice that the `[PacketLength:2]` part of the packet was inserted after we had added everything else, and as shown in the Buffer dump above, is in the correct location along with everything else.
89 |
90 | Reading back the packet we created above is just as easy:
91 | ```javascript
92 |
93 | let reader = SmartBuffer.fromBuffer(login);
94 |
95 | let logininfo = {
96 | packetType: reader.readUInt16LE(),
97 | packetLength: reader.readUInt16LE(),
98 | username: reader.readStringNT(),
99 | password: reader.readStringNT(),
100 | age: reader.readUInt8(),
101 | country: reader.readStringNT()
102 | };
103 |
104 | /*
105 | {
106 | packetType: 96, (0x0060)
107 | packetLength: 30,
108 | username: 'Josh',
109 | password: 'secret123',
110 | age: 22,
111 | country: 'United States'
112 | };
113 | */
114 | ```
115 |
116 | # Api Reference:
117 |
118 | ### Constructing a smart-buffer
119 |
120 | smart-buffer has a few different ways to construct an instance. Starting with version 2.0, the following factory methods are preffered.
121 |
122 | ```javascript
123 | let SmartBuffer = require('smart-buffer');
124 |
125 | // Creating SmartBuffer from existing Buffer
126 | let buff = SmartBuffer.fromBuffer(buffer); // Creates instance from buffer. (Uses default utf8 encoding)
127 | let buff = SmartBuffer.fromBuffer(buffer, 'ascii'); // Creates instance from buffer with ascii encoding for Strings.
128 |
129 | // Creating SmartBuffer with specified internal Buffer size.
130 | let buff = SmartBuffer.fromSize(1024); // Creates instance with internal Buffer size of 1024.
131 | let buff = SmartBuffer.fromSize(1024, 'utf8'); // Creates instance with intenral Buffer size of 1024, and utf8 encoding.
132 |
133 | // Creating SmartBuffer with options object. This one specifies size and encoding.
134 | let buff = SmartBuffer.fromOptions({
135 | size: 1024,
136 | encoding: 'ascii'
137 | });
138 |
139 | // Creating SmartBuffer with options object. This one specified an existing Buffer.
140 | let buff = SmartBuffer.fromOptions({
141 | buff: buffer
142 | });
143 |
144 | // Just want a regular SmartBuffer with all default options?
145 | let buff = new SmartBuffer();
146 | ```
147 |
148 | ## Backwards Compatibility:
149 |
150 | All constructors used prior to 2.0 still are supported. However it's not recommended to use these.
151 |
152 | ```javascript
153 | let writer = new SmartBuffer(); // Defaults to utf8, 4096 length internal Buffer.
154 | let writer = new SmartBuffer(1024); // Defaults to utf8, 1024 length internal Buffer.
155 | let writer = new SmartBuffer('ascii'); // Sets to ascii encoding, 4096 length internal buffer.
156 | let writer = new SmartBuffer(1024, 'ascii'); // Sets to ascii encoding, 1024 length internal buffer.
157 | ```
158 |
159 | ## Reading Data
160 |
161 | smart-buffer supports all of the common read functions you will find in the vanilla Buffer class. The only difference is, you do not need to specify which location to start reading from. This is possible because as you read data out of a smart-buffer, it automatically progresses an internal read offset/position to know where to pick up from on the next read.
162 |
163 | ## Reading Numeric Values
164 |
165 | When numeric values, you simply need to call the function you want, and the data is returned.
166 |
167 | Supported Operations:
168 | * readInt8
169 | * readInt16BE
170 | * readInt16LE
171 | * readInt32BE
172 | * readInt32LE
173 | * readBigInt64LE
174 | * readBigInt64BE
175 | * readUInt8
176 | * readUInt16BE
177 | * readUInt16LE
178 | * readUInt32BE
179 | * readUInt32LE
180 | * readBigUInt64LE
181 | * readBigUInt64BE
182 | * readFloatBE
183 | * readFloatLE
184 | * readDoubleBE
185 | * readDoubleLE
186 |
187 | ```javascript
188 | let reader = new SmartBuffer(somebuffer);
189 | let num = reader.readInt8();
190 | ```
191 |
192 | ## Reading String Values
193 |
194 | When reading String values, you can either choose to read a null terminated string, or a string of a specified length.
195 |
196 | ### SmartBuffer.readStringNT( [encoding] )
197 | > `String` **String encoding to use** - Defaults to the encoding set in the constructor.
198 |
199 | returns `String`
200 |
201 | > Note: When readStringNT is called and there is no null character found, smart-buffer will read to the end of the internal Buffer.
202 |
203 | ### SmartBuffer.readString( [length] )
204 | ### SmartBuffer.readString( [encoding] )
205 | ### SmartBuffer.readString( [length], [encoding] )
206 | > `Number` **Length of the string to read**
207 |
208 | > `String` **String encoding to use** - Defaults to the encoding set in the constructor, or utf8.
209 |
210 | returns `String`
211 |
212 | > Note: When readString is called without a specified length, smart-buffer will read to the end of the internal Buffer.
213 |
214 |
215 |
216 | ## Reading Buffer Values
217 |
218 | ### SmartBuffer.readBuffer( length )
219 | > `Number` **Length of data to read into a Buffer**
220 |
221 | returns `Buffer`
222 |
223 | > Note: This function uses `slice` to retrieve the Buffer.
224 |
225 |
226 | ### SmartBuffer.readBufferNT()
227 |
228 | returns `Buffer`
229 |
230 | > Note: This reads the next sequence of bytes in the buffer until a null (0x00) value is found. (Null terminated buffer)
231 | > Note: This function uses `slice` to retrieve the Buffer.
232 |
233 |
234 | ## Writing Data
235 |
236 | smart-buffer supports all of the common write functions you will find in the vanilla Buffer class. The only difference is, you do not need to specify which location to write to in your Buffer by default. You do however have the option of **inserting** a piece of data into your smart-buffer at a given location.
237 |
238 |
239 | ## Writing Numeric Values
240 |
241 |
242 | For numeric values, you simply need to call the function you want, and the data is written at the end of the internal Buffer's current write position. You can specify a offset/position to **insert** the given value at, but keep in mind this does not override data at the given position. This feature also does not work properly when inserting a value beyond the current internal length of the smart-buffer (length being the .length property of the smart-buffer instance you're writing to)
243 |
244 | Supported Operations:
245 | * writeInt8
246 | * writeInt16BE
247 | * writeInt16LE
248 | * writeInt32BE
249 | * writeInt32LE
250 | * writeBigInt64BE
251 | * writeBigInt64LE
252 | * writeUInt8
253 | * writeUInt16BE
254 | * writeUInt16LE
255 | * writeUInt32BE
256 | * writeUInt32LE
257 | * writeBigUInt64BE
258 | * writeBigUInt64LE
259 | * writeFloatBE
260 | * writeFloatLE
261 | * writeDoubleBE
262 | * writeDoubleLE
263 |
264 | The following signature is the same for all the above functions:
265 |
266 | ### SmartBuffer.writeInt8( value, [offset] )
267 | > `Number` **A valid Int8 number**
268 |
269 | > `Number` **The position to insert this value at**
270 |
271 | returns this
272 |
273 | > Note: All write operations return `this` to allow for chaining.
274 |
275 | ## Writing String Values
276 |
277 | When reading String values, you can either choose to write a null terminated string, or a non null terminated string.
278 |
279 | ### SmartBuffer.writeStringNT( value, [offset], [encoding] )
280 | ### SmartBuffer.writeStringNT( value, [offset] )
281 | ### SmartBuffer.writeStringNT( value, [encoding] )
282 | > `String` **String value to write**
283 |
284 | > `Number` **The position to insert this String at**
285 |
286 | > `String` **The String encoding to use.** - Defaults to the encoding set in the constructor, or utf8.
287 |
288 | returns this
289 |
290 | ### SmartBuffer.writeString( value, [offset], [encoding] )
291 | ### SmartBuffer.writeString( value, [offset] )
292 | ### SmartBuffer.writeString( value, [encoding] )
293 | > `String` **String value to write**
294 |
295 | > `Number` **The position to insert this String at**
296 |
297 | > `String` **The String encoding to use** - Defaults to the encoding set in the constructor, or utf8.
298 |
299 | returns this
300 |
301 |
302 | ## Writing Buffer Values
303 |
304 | ### SmartBuffer.writeBuffer( value, [offset] )
305 | > `Buffer` **Buffer value to write**
306 |
307 | > `Number` **The position to insert this Buffer's content at**
308 |
309 | returns this
310 |
311 | ### SmartBuffer.writeBufferNT( value, [offset] )
312 | > `Buffer` **Buffer value to write**
313 |
314 | > `Number` **The position to insert this Buffer's content at**
315 |
316 | returns this
317 |
318 |
319 | ## Utility Functions
320 |
321 | ### SmartBuffer.clear()
322 | Resets the SmartBuffer to its default state where it can be reused for reading or writing.
323 |
324 | ### SmartBuffer.remaining()
325 |
326 | returns `Number` The amount of data left to read based on the current read Position.
327 |
328 | ### SmartBuffer.skip( value )
329 | > `Number` **The amount of bytes to skip ahead**
330 |
331 | Skips the read position ahead by the given value.
332 |
333 | returns this
334 |
335 | ### SmartBuffer.rewind( value )
336 | > `Number` **The amount of bytes to reward backwards**
337 |
338 | Rewinds the read position backwards by the given value.
339 |
340 | returns this
341 |
342 | ### SmartBuffer.moveTo( position )
343 | > `Number` **The point to skip the read position to**
344 |
345 | Moves the read position to the given point.
346 | returns this
347 |
348 | ### SmartBuffer.toBuffer()
349 |
350 | returns `Buffer` A Buffer containing the contents of the internal Buffer.
351 |
352 | > Note: This uses the slice function.
353 |
354 | ### SmartBuffer.toString( [encoding] )
355 | > `String` **The String encoding to use** - Defaults to the encoding set in the constructor, or utf8.
356 |
357 | returns `String` The internal Buffer in String representation.
358 |
359 | ## Properties
360 |
361 | ### SmartBuffer.length
362 |
363 | returns `Number` **The length of the data that is being tracked in the internal Buffer** - Does NOT return the absolute length of the internal Buffer being written to.
364 |
365 | ## License
366 |
367 | This work is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | smart-buffer [](https://travis-ci.org/JoshGlazebrook/smart-buffer) [](https://coveralls.io/github/JoshGlazebrook/smart-buffer?branch=master)
2 | =============
3 |
4 | smart-buffer is a Buffer wrapper that adds automatic read & write offset tracking, string operations, data insertions, and more.
5 |
6 | 
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 |
35 | Legacy 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 |
41 | or
42 |
43 | `npm install smart-buffer`
44 |
45 | Note: The published NPM package includes the built javascript library.
46 | If 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
54 | const SmartBuffer = require('smart-buffer').SmartBuffer;
55 |
56 | // Typescript
57 | import { SmartBuffer, SmartBufferOptions} from 'smart-buffer';
58 | ```
59 |
60 | ### Simple Example
61 |
62 | Building a packet that uses the following protocol specification:
63 |
64 | `[PacketType:2][PacketLength:2][Data:XX]`
65 |
66 | To 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
69 | function 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 | ```
81 | With the above function, you now can do this:
82 | ```javascript
83 | const login = createLoginPacket("Josh", "secret123", 22, "United States");
84 |
85 | //
86 | ```
87 | Notice that the `[PacketLength:2]` value (1e 00) was inserted at position 2.
88 |
89 | Reading back the packet we created above is just as easy:
90 | ```javascript
91 |
92 | const reader = SmartBuffer.fromBuffer(login);
93 |
94 | const 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
117 | In 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
121 | const buff = SmartBuffer.fromBuffer(new Buffer([1,2,3,4,5,6]));
122 | buff.writeInt8(7, 2);
123 | console.log(buff.toBuffer())
124 |
125 | //
126 | ```
127 |
128 | **SmartBuffer v4**:
129 | ```javascript
130 | const buff = SmartBuffer.fromBuffer(new Buffer([1,2,3,4,5,6]));
131 | buff.writeInt8(7, 2);
132 | console.log(buff.toBuffer());
133 |
134 | //
135 | ```
136 |
137 | To insert you instead should use:
138 | ```javascript
139 | const buff = SmartBuffer.fromBuffer(new Buffer([1,2,3,4,5,6]));
140 | buff.insertInt8(7, 2);
141 | console.log(buff.toBuffer());
142 |
143 | //
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 |
150 | There are a few different ways to construct a SmartBuffer instance.
151 |
152 | ```javascript
153 | // Creating SmartBuffer from existing Buffer
154 | const buff = SmartBuffer.fromBuffer(buffer); // Creates instance from buffer. (Uses default utf8 encoding)
155 | const 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).
158 | const buff = SmartBuffer.fromSize(1024); // Creates instance with internal Buffer size of 1024.
159 | const 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.
162 | const buff = SmartBuffer.fromOptions({
163 | size: 1024,
164 | encoding: 'ascii'
165 | });
166 |
167 | // Creating SmartBuffer with options object. This one specified an existing Buffer.
168 | const buff = SmartBuffer.fromOptions({
169 | buff: buffer
170 | });
171 |
172 | // Creating SmartBuffer from a string.
173 | const buff = SmartBuffer.fromBuffer(Buffer.from('some string', 'utf8'));
174 |
175 | // Just want a regular SmartBuffer with all default options?
176 | const 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 |
185 | 1. [Constructing](#constructing)
186 | 2. **Numbers**
187 | 1. [Integers](#integers)
188 | 2. [Floating Points](#floating-point-numbers)
189 | 3. **Strings**
190 | 1. [Strings](#strings)
191 | 2. [Null Terminated Strings](#null-terminated-strings)
192 | 4. [Buffers](#buffers)
193 | 5. [Offsets](#offsets)
194 | 6. [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 |
203 | Examples:
204 | ```javascript
205 | const buff = new SmartBuffer();
206 | const 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 |
216 | Examples:
217 | ```javascript
218 | const someBuffer = Buffer.from('some string');
219 | const buff = SmartBuffer.fromBuffer(someBuffer); // Defaults to utf8
220 | const 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 |
227 | Examples:
228 | ```javascript
229 | const buff = SmartBuffer.fromSize(1024); // Defaults to utf8
230 | const buff = SmartBuffer.fromSize(1024, 'ascii');
231 | ```
232 |
233 | ### Class Method: fromOptions(options)
234 | - ```options``` *{SmartBufferOptions}* The Buffer instance to wrap.
235 |
236 | ```typescript
237 | interface SmartBufferOptions {
238 | encoding?: BufferEncoding; // Defaults to utf8
239 | size?: number; // Defaults to 4096
240 | buff?: Buffer;
241 | }
242 | ```
243 |
244 | Examples:
245 | ```javascript
246 | const buff = SmartBuffer.fromOptions({
247 | size: 1024
248 | };
249 | const buff = SmartBuffer.fromOptions({
250 | size: 1024,
251 | encoding: 'utf8'
252 | });
253 | const buff = SmartBuffer.fromOptions({
254 | encoding: 'utf8'
255 | });
256 |
257 | const someBuff = Buffer.from('some string', 'utf8');
258 | const buff = SmartBuffer.fromOptions({
259 | buffer: someBuff,
260 | encoding: 'utf8'
261 | });
262 | ```
263 |
264 | ## Integers
265 |
266 | ### buff.readInt8([offset])
267 | ### buff.readUInt8([offset])
268 | - ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset```
269 | - Returns *{number}*
270 |
271 | Read a Int8 value.
272 |
273 | ### buff.readInt16BE([offset])
274 | ### buff.readInt16LE([offset])
275 | ### buff.readUInt16BE([offset])
276 | ### buff.readUInt16LE([offset])
277 | - ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset```
278 | - Returns *{number}*
279 |
280 | Read a 16 bit integer value.
281 |
282 | ### buff.readInt32BE([offset])
283 | ### buff.readInt32LE([offset])
284 | ### buff.readUInt32BE([offset])
285 | ### buff.readUInt32LE([offset])
286 | - ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset```
287 | - Returns *{number}*
288 |
289 | Read a 32 bit integer value.
290 |
291 |
292 | ### buff.writeInt8(value[, offset])
293 | ### buff.writeUInt8(value[, offset])
294 | - ```value``` *{number}* The value to write.
295 | - ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset```
296 | - Returns *{this}*
297 |
298 | Write a Int8 value.
299 |
300 | ### buff.insertInt8(value, offset)
301 | ### buff.insertUInt8(value, offset)
302 | - ```value``` *{number}* The value to insert.
303 | - ```offset``` *{number}* The offset to insert this data at.
304 | - Returns *{this}*
305 |
306 | Insert a Int8 value.
307 |
308 |
309 | ### buff.writeInt16BE(value[, offset])
310 | ### buff.writeInt16LE(value[, offset])
311 | ### buff.writeUInt16BE(value[, offset])
312 | ### buff.writeUInt16LE(value[, offset])
313 | - ```value``` *{number}* The value to write.
314 | - ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset```
315 | - Returns *{this}*
316 |
317 | Write a 16 bit integer value.
318 |
319 | ### buff.insertInt16BE(value, offset)
320 | ### buff.insertInt16LE(value, offset)
321 | ### buff.insertUInt16BE(value, offset)
322 | ### buff.insertUInt16LE(value, offset)
323 | - ```value``` *{number}* The value to insert.
324 | - ```offset``` *{number}* The offset to insert this data at.
325 | - Returns *{this}*
326 |
327 | Insert a 16 bit integer value.
328 |
329 |
330 | ### buff.writeInt32BE(value[, offset])
331 | ### buff.writeInt32LE(value[, offset])
332 | ### buff.writeUInt32BE(value[, offset])
333 | ### buff.writeUInt32LE(value[, offset])
334 | - ```value``` *{number}* The value to write.
335 | - ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset```
336 | - Returns *{this}*
337 |
338 | Write a 32 bit integer value.
339 |
340 | ### buff.insertInt32BE(value, offset)
341 | ### buff.insertInt32LE(value, offset)
342 | ### buff.insertUInt32BE(value, offset)
343 | ### buff.nsertUInt32LE(value, offset)
344 | - ```value``` *{number}* The value to insert.
345 | - ```offset``` *{number}* The offset to insert this data at.
346 | - Returns *{this}*
347 |
348 | Insert a 32 bit integer value.
349 |
350 |
351 | ## Floating Point Numbers
352 |
353 | ### buff.readFloatBE([offset])
354 | ### buff.readFloatLE([offset])
355 | - ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset```
356 | - Returns *{number}*
357 |
358 | Read a Float value.
359 |
360 | ### buff.readDoubleBE([offset])
361 | ### buff.readDoubleLE([offset])
362 | - ```offset``` *{number}* Optional position to start reading data from. **Default**: ```Auto managed offset```
363 | - Returns *{number}*
364 |
365 | Read a Double value.
366 |
367 |
368 | ### buff.writeFloatBE(value[, offset])
369 | ### buff.writeFloatLE(value[, offset])
370 | - ```value``` *{number}* The value to write.
371 | - ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset```
372 | - Returns *{this}*
373 |
374 | Write a Float value.
375 |
376 | ### buff.insertFloatBE(value, offset)
377 | ### buff.insertFloatLE(value, offset)
378 | - ```value``` *{number}* The value to insert.
379 | - ```offset``` *{number}* The offset to insert this data at.
380 | - Returns *{this}*
381 |
382 | Insert a Float value.
383 |
384 |
385 | ### buff.writeDoubleBE(value[, offset])
386 | ### buff.writeDoubleLE(value[, offset])
387 | - ```value``` *{number}* The value to write.
388 | - ```offset``` *{number}* An optional offset to write this value to. **Default:** ```Auto managed offset```
389 | - Returns *{this}*
390 |
391 | Write a Double value.
392 |
393 | ### buff.insertDoubleBE(value, offset)
394 | ### buff.insertDoubleLE(value, offset)
395 | - ```value``` *{number}* The value to insert.
396 | - ```offset``` *{number}* The offset to insert this data at.
397 | - Returns *{this}*
398 |
399 | Insert a Double value.
400 |
401 | ## Strings
402 |
403 | ### buff.readString()
404 | ### buff.readString(size[, encoding])
405 | ### buff.readString(encoding)
406 | - ```size``` *{number}* The number of bytes to read. **Default:** ```Reads to the end of the Buffer.```
407 | - ```encoding``` *{string}* The string encoding to use. **Default:** ```utf8```.
408 |
409 | Read a string value.
410 |
411 | Examples:
412 | ```javascript
413 | const buff = SmartBuffer.fromBuffer(Buffer.from('hello there', 'utf8'));
414 | buff.readString(); // 'hello there'
415 | buff.readString(2); // 'he'
416 | buff.readString(2, 'utf8'); // 'he'
417 | buff.readString('utf8'); // 'hello there'
418 | ```
419 |
420 | ### buff.writeString(value)
421 | ### buff.writeString(value[, offset])
422 | ### buff.writeString(value[, encoding])
423 | ### buff.writeString(value[, offset[, encoding]])
424 | - ```value``` *{string}* The string value to write.
425 | - ```offset``` *{number}* The offset to write this value to. **Default:** ```Auto managed offset```
426 | - ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8```
427 |
428 | Write a string value.
429 |
430 | Examples:
431 | ```javascript
432 | buff.writeString('hello'); // Auto managed offset
433 | buff.writeString('hello', 2);
434 | buff.writeString('hello', 'utf8') // Auto managed offset
435 | buff.writeString('hello', 2, 'utf8');
436 | ```
437 |
438 | ### buff.insertString(value, offset[, encoding])
439 | - ```value``` *{string}* The string value to write.
440 | - ```offset``` *{number}* The offset to write this value to.
441 | - ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8```
442 |
443 | Insert a string value.
444 |
445 | Examples:
446 | ```javascript
447 | buff.insertString('hello', 2);
448 | buff.insertString('hello', 2, 'utf8');
449 | ```
450 |
451 | ## Null Terminated Strings
452 |
453 | ### buff.readStringNT()
454 | ### buff.readStringNT(encoding)
455 | - ```encoding``` *{string}* The string encoding to use. **Default:** ```utf8```.
456 |
457 | Read a null terminated string value. (If a null is not found, it will read to the end of the Buffer).
458 |
459 | Examples:
460 | ```javascript
461 | const buff = SmartBuffer.fromBuffer(Buffer.from('hello\0 there', 'utf8'));
462 | buff.readStringNT(); // 'hello'
463 |
464 | // If we called this again:
465 | buff.readStringNT(); // ' there'
466 | ```
467 |
468 | ### buff.writeStringNT(value)
469 | ### buff.writeStringNT(value[, offset])
470 | ### buff.writeStringNT(value[, encoding])
471 | ### buff.writeStringNT(value[, offset[, encoding]])
472 | - ```value``` *{string}* The string value to write.
473 | - ```offset``` *{number}* The offset to write this value to. **Default:** ```Auto managed offset```
474 | - ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8```
475 |
476 | Write a null terminated string value.
477 |
478 | Examples:
479 | ```javascript
480 | buff.writeStringNT('hello'); // Auto managed offset
481 | buff.writeStringNT('hello', 2); //
482 | buff.writeStringNT('hello', 'utf8') // Auto managed offset
483 | buff.writeStringNT('hello', 2, 'utf8');
484 | ```
485 |
486 | ### buff.insertStringNT(value, offset[, encoding])
487 | - ```value``` *{string}* The string value to write.
488 | - ```offset``` *{number}* The offset to write this value to.
489 | - ```encoding``` *{string}* An optional string encoding to use. **Default:** ```utf8```
490 |
491 | Insert a null terminated string value.
492 |
493 | Examples:
494 | ```javascript
495 | buff.insertStringNT('hello', 2);
496 | buff.insertStringNT('hello', 2, 'utf8');
497 | ```
498 |
499 | ## Buffers
500 |
501 | ### buff.readBuffer([length])
502 | - ```length``` *{number}* The number of bytes to read into a Buffer. **Default:** ```Reads to the end of the Buffer```
503 |
504 | Read a Buffer of a specified size.
505 |
506 | ### buff.writeBuffer(value[, offset])
507 | - ```value``` *{Buffer}* The buffer value to write.
508 | - ```offset``` *{number}* An optional offset to write the value to. **Default:** ```Auto managed offset```
509 |
510 | ### buff.insertBuffer(value, offset)
511 | - ```value``` *{Buffer}* The buffer value to write.
512 | - ```offset``` *{number}* The offset to write the value to.
513 |
514 |
515 | ### buff.readBufferNT()
516 |
517 | Read a null terminated Buffer.
518 |
519 | ### buff.writeBufferNT(value[, offset])
520 | - ```value``` *{Buffer}* The buffer value to write.
521 | - ```offset``` *{number}* An optional offset to write the value to. **Default:** ```Auto managed offset```
522 |
523 | Write a null terminated Buffer.
524 |
525 |
526 | ### buff.insertBufferNT(value, offset)
527 | - ```value``` *{Buffer}* The buffer value to write.
528 | - ```offset``` *{number}* The offset to write the value to.
529 |
530 | Insert a null terminated Buffer.
531 |
532 |
533 | ## Offsets
534 |
535 | ### buff.readOffset
536 | ### buff.readOffset(offset)
537 | - ```offset``` *{number}* The new read offset value to set.
538 | - Returns: ```The current read offset```
539 |
540 | Gets or sets the current read offset.
541 |
542 | Examples:
543 | ```javascript
544 | const currentOffset = buff.readOffset; // 5
545 |
546 | buff.readOffset = 10;
547 |
548 | console.log(buff.readOffset) // 10
549 | ```
550 |
551 | ### buff.writeOffset
552 | ### buff.writeOffset(offset)
553 | - ```offset``` *{number}* The new write offset value to set.
554 | - Returns: ```The current write offset```
555 |
556 | Gets or sets the current write offset.
557 |
558 | Examples:
559 | ```javascript
560 | const currentOffset = buff.writeOffset; // 5
561 |
562 | buff.writeOffset = 10;
563 |
564 | console.log(buff.writeOffset) // 10
565 | ```
566 |
567 | ### buff.encoding
568 | ### buff.encoding(encoding)
569 | - ```encoding``` *{string}* The new string encoding to set.
570 | - Returns: ```The current string encoding```
571 |
572 | Gets or sets the current string encoding.
573 |
574 | Examples:
575 | ```javascript
576 | const currentEncoding = buff.encoding; // 'utf8'
577 |
578 | buff.encoding = 'ascii';
579 |
580 | console.log(buff.encoding) // 'ascii'
581 | ```
582 |
583 | ## Other
584 |
585 | ### buff.clear()
586 |
587 | Clear and resets the SmartBuffer instance.
588 |
589 | ### buff.remaining()
590 | - Returns ```Remaining data left to be read```
591 |
592 | Gets the number of remaining bytes to be read.
593 |
594 |
595 | ### buff.internalBuffer
596 | - Returns: *{Buffer}*
597 |
598 | Gets the internally managed Buffer (Includes unmanaged data).
599 |
600 | Examples:
601 | ```javascript
602 | const buff = SmartBuffer.fromSize(16);
603 | buff.writeString('hello');
604 | console.log(buff.InternalBuffer); //
605 | ```
606 |
607 | ### buff.toBuffer()
608 | - Returns: *{Buffer}*
609 |
610 | Gets a sliced Buffer instance of the internally managed Buffer. (Only includes managed data)
611 |
612 | Examples:
613 | ```javascript
614 | const buff = SmartBuffer.fromSize(16);
615 | buff.writeString('hello');
616 | console.log(buff.toBuffer()); //
617 | ```
618 |
619 | ### buff.toString([encoding])
620 | - ```encoding``` *{string}* The string encoding to use when converting to a string. **Default:** ```utf8```
621 | - Returns *{string}*
622 |
623 | Gets a string representation of all data in the SmartBuffer.
624 |
625 | ### buff.destroy()
626 |
627 | Destroys the SmartBuffer instance.
628 |
629 |
630 |
631 | ## License
632 |
633 | This work is licensed under the [MIT license](http://en.wikipedia.org/wiki/MIT_License).
634 |
--------------------------------------------------------------------------------
/typings/smartbuffer.d.ts:
--------------------------------------------------------------------------------
1 | ///
2 | /**
3 | * Object interface for constructing new SmartBuffer instances.
4 | */
5 | interface SmartBufferOptions {
6 | encoding?: BufferEncoding;
7 | size?: number;
8 | buff?: Buffer;
9 | }
10 | declare class SmartBuffer {
11 | length: number;
12 | private _encoding;
13 | private _buff;
14 | private _writeOffset;
15 | private _readOffset;
16 | /**
17 | * Creates a new SmartBuffer instance.
18 | *
19 | * @param options { SmartBufferOptions } The SmartBufferOptions to apply to this instance.
20 | */
21 | constructor(options?: SmartBufferOptions);
22 | /**
23 | * Creates a new SmartBuffer instance with the provided internal Buffer size and optional encoding.
24 | *
25 | * @param size { Number } The size of the internal Buffer.
26 | * @param encoding { String } The BufferEncoding to use for strings.
27 | *
28 | * @return { SmartBuffer }
29 | */
30 | static fromSize(size: number, encoding?: BufferEncoding): SmartBuffer;
31 | /**
32 | * Creates a new SmartBuffer instance with the provided Buffer and optional encoding.
33 | *
34 | * @param buffer { Buffer } The Buffer to use as the internal Buffer value.
35 | * @param encoding { String } The BufferEncoding to use for strings.
36 | *
37 | * @return { SmartBuffer }
38 | */
39 | static fromBuffer(buff: Buffer, encoding?: BufferEncoding): SmartBuffer;
40 | /**
41 | * Creates a new SmartBuffer instance with the provided SmartBufferOptions options.
42 | *
43 | * @param options { SmartBufferOptions } The options to use when creating the SmartBuffer instance.
44 | */
45 | static fromOptions(options: SmartBufferOptions): SmartBuffer;
46 | /**
47 | * Type checking function that determines if an object is a SmartBufferOptions object.
48 | */
49 | static isSmartBufferOptions(options: SmartBufferOptions): options is SmartBufferOptions;
50 | /**
51 | * Reads an Int8 value from the current read position or an optionally provided offset.
52 | *
53 | * @param offset { Number } The offset to read data from (optional)
54 | * @return { Number }
55 | */
56 | readInt8(offset?: number): number;
57 | /**
58 | * Reads an Int16BE value from the current read position or an optionally provided offset.
59 | *
60 | * @param offset { Number } The offset to read data from (optional)
61 | * @return { Number }
62 | */
63 | readInt16BE(offset?: number): number;
64 | /**
65 | * Reads an Int16LE value from the current read position or an optionally provided offset.
66 | *
67 | * @param offset { Number } The offset to read data from (optional)
68 | * @return { Number }
69 | */
70 | readInt16LE(offset?: number): number;
71 | /**
72 | * Reads an Int32BE value from the current read position or an optionally provided offset.
73 | *
74 | * @param offset { Number } The offset to read data from (optional)
75 | * @return { Number }
76 | */
77 | readInt32BE(offset?: number): number;
78 | /**
79 | * Reads an Int32LE value from the current read position or an optionally provided offset.
80 | *
81 | * @param offset { Number } The offset to read data from (optional)
82 | * @return { Number }
83 | */
84 | readInt32LE(offset?: number): number;
85 | /**
86 | * Reads a BigInt64BE value from the current read position or an optionally provided offset.
87 | *
88 | * @param offset { Number } The offset to read data from (optional)
89 | * @return { BigInt }
90 | */
91 | readBigInt64BE(offset?: number): bigint;
92 | /**
93 | * Reads a BigInt64LE value from the current read position or an optionally provided offset.
94 | *
95 | * @param offset { Number } The offset to read data from (optional)
96 | * @return { BigInt }
97 | */
98 | readBigInt64LE(offset?: number): bigint;
99 | /**
100 | * Writes an Int8 value to the current write position (or at optional offset).
101 | *
102 | * @param value { Number } The value to write.
103 | * @param offset { Number } The offset to write the value at.
104 | *
105 | * @return this
106 | */
107 | writeInt8(value: number, offset?: number): SmartBuffer;
108 | /**
109 | * Inserts an Int8 value at the given offset value.
110 | *
111 | * @param value { Number } The value to insert.
112 | * @param offset { Number } The offset to insert the value at.
113 | *
114 | * @return this
115 | */
116 | insertInt8(value: number, offset: number): SmartBuffer;
117 | /**
118 | * Writes an Int16BE value to the current write position (or at optional offset).
119 | *
120 | * @param value { Number } The value to write.
121 | * @param offset { Number } The offset to write the value at.
122 | *
123 | * @return this
124 | */
125 | writeInt16BE(value: number, offset?: number): SmartBuffer;
126 | /**
127 | * Inserts an Int16BE value at the given offset value.
128 | *
129 | * @param value { Number } The value to insert.
130 | * @param offset { Number } The offset to insert the value at.
131 | *
132 | * @return this
133 | */
134 | insertInt16BE(value: number, offset: number): SmartBuffer;
135 | /**
136 | * Writes an Int16LE value to the current write position (or at optional offset).
137 | *
138 | * @param value { Number } The value to write.
139 | * @param offset { Number } The offset to write the value at.
140 | *
141 | * @return this
142 | */
143 | writeInt16LE(value: number, offset?: number): SmartBuffer;
144 | /**
145 | * Inserts an Int16LE value at the given offset value.
146 | *
147 | * @param value { Number } The value to insert.
148 | * @param offset { Number } The offset to insert the value at.
149 | *
150 | * @return this
151 | */
152 | insertInt16LE(value: number, offset: number): SmartBuffer;
153 | /**
154 | * Writes an Int32BE value to the current write position (or at optional offset).
155 | *
156 | * @param value { Number } The value to write.
157 | * @param offset { Number } The offset to write the value at.
158 | *
159 | * @return this
160 | */
161 | writeInt32BE(value: number, offset?: number): SmartBuffer;
162 | /**
163 | * Inserts an Int32BE value at the given offset value.
164 | *
165 | * @param value { Number } The value to insert.
166 | * @param offset { Number } The offset to insert the value at.
167 | *
168 | * @return this
169 | */
170 | insertInt32BE(value: number, offset: number): SmartBuffer;
171 | /**
172 | * Writes an Int32LE value to the current write position (or at optional offset).
173 | *
174 | * @param value { Number } The value to write.
175 | * @param offset { Number } The offset to write the value at.
176 | *
177 | * @return this
178 | */
179 | writeInt32LE(value: number, offset?: number): SmartBuffer;
180 | /**
181 | * Inserts an Int32LE value at the given offset value.
182 | *
183 | * @param value { Number } The value to insert.
184 | * @param offset { Number } The offset to insert the value at.
185 | *
186 | * @return this
187 | */
188 | insertInt32LE(value: number, offset: number): SmartBuffer;
189 | /**
190 | * Writes a BigInt64BE value to the current write position (or at optional offset).
191 | *
192 | * @param value { BigInt } The value to write.
193 | * @param offset { Number } The offset to write the value at.
194 | *
195 | * @return this
196 | */
197 | writeBigInt64BE(value: bigint, offset?: number): SmartBuffer;
198 | /**
199 | * Inserts a BigInt64BE value at the given offset value.
200 | *
201 | * @param value { BigInt } The value to insert.
202 | * @param offset { Number } The offset to insert the value at.
203 | *
204 | * @return this
205 | */
206 | insertBigInt64BE(value: bigint, offset: number): SmartBuffer;
207 | /**
208 | * Writes a BigInt64LE value to the current write position (or at optional offset).
209 | *
210 | * @param value { BigInt } The value to write.
211 | * @param offset { Number } The offset to write the value at.
212 | *
213 | * @return this
214 | */
215 | writeBigInt64LE(value: bigint, offset?: number): SmartBuffer;
216 | /**
217 | * Inserts a Int64LE value at the given offset value.
218 | *
219 | * @param value { BigInt } The value to insert.
220 | * @param offset { Number } The offset to insert the value at.
221 | *
222 | * @return this
223 | */
224 | insertBigInt64LE(value: bigint, offset: number): SmartBuffer;
225 | /**
226 | * Reads an UInt8 value from the current read position or an optionally provided offset.
227 | *
228 | * @param offset { Number } The offset to read data from (optional)
229 | * @return { Number }
230 | */
231 | readUInt8(offset?: number): number;
232 | /**
233 | * Reads an UInt16BE value from the current read position or an optionally provided offset.
234 | *
235 | * @param offset { Number } The offset to read data from (optional)
236 | * @return { Number }
237 | */
238 | readUInt16BE(offset?: number): number;
239 | /**
240 | * Reads an UInt16LE value from the current read position or an optionally provided offset.
241 | *
242 | * @param offset { Number } The offset to read data from (optional)
243 | * @return { Number }
244 | */
245 | readUInt16LE(offset?: number): number;
246 | /**
247 | * Reads an UInt32BE value from the current read position or an optionally provided offset.
248 | *
249 | * @param offset { Number } The offset to read data from (optional)
250 | * @return { Number }
251 | */
252 | readUInt32BE(offset?: number): number;
253 | /**
254 | * Reads an UInt32LE value from the current read position or an optionally provided offset.
255 | *
256 | * @param offset { Number } The offset to read data from (optional)
257 | * @return { Number }
258 | */
259 | readUInt32LE(offset?: number): number;
260 | /**
261 | * Reads a BigUInt64BE value from the current read position or an optionally provided offset.
262 | *
263 | * @param offset { Number } The offset to read data from (optional)
264 | * @return { BigInt }
265 | */
266 | readBigUInt64BE(offset?: number): bigint;
267 | /**
268 | * Reads a BigUInt64LE value from the current read position or an optionally provided offset.
269 | *
270 | * @param offset { Number } The offset to read data from (optional)
271 | * @return { BigInt }
272 | */
273 | readBigUInt64LE(offset?: number): bigint;
274 | /**
275 | * Writes an UInt8 value to the current write position (or at optional offset).
276 | *
277 | * @param value { Number } The value to write.
278 | * @param offset { Number } The offset to write the value at.
279 | *
280 | * @return this
281 | */
282 | writeUInt8(value: number, offset?: number): SmartBuffer;
283 | /**
284 | * Inserts an UInt8 value at the given offset value.
285 | *
286 | * @param value { Number } The value to insert.
287 | * @param offset { Number } The offset to insert the value at.
288 | *
289 | * @return this
290 | */
291 | insertUInt8(value: number, offset: number): SmartBuffer;
292 | /**
293 | * Writes an UInt16BE value to the current write position (or at optional offset).
294 | *
295 | * @param value { Number } The value to write.
296 | * @param offset { Number } The offset to write the value at.
297 | *
298 | * @return this
299 | */
300 | writeUInt16BE(value: number, offset?: number): SmartBuffer;
301 | /**
302 | * Inserts an UInt16BE value at the given offset value.
303 | *
304 | * @param value { Number } The value to insert.
305 | * @param offset { Number } The offset to insert the value at.
306 | *
307 | * @return this
308 | */
309 | insertUInt16BE(value: number, offset: number): SmartBuffer;
310 | /**
311 | * Writes an UInt16LE value to the current write position (or at optional offset).
312 | *
313 | * @param value { Number } The value to write.
314 | * @param offset { Number } The offset to write the value at.
315 | *
316 | * @return this
317 | */
318 | writeUInt16LE(value: number, offset?: number): SmartBuffer;
319 | /**
320 | * Inserts an UInt16LE value at the given offset value.
321 | *
322 | * @param value { Number } The value to insert.
323 | * @param offset { Number } The offset to insert the value at.
324 | *
325 | * @return this
326 | */
327 | insertUInt16LE(value: number, offset: number): SmartBuffer;
328 | /**
329 | * Writes an UInt32BE value to the current write position (or at optional offset).
330 | *
331 | * @param value { Number } The value to write.
332 | * @param offset { Number } The offset to write the value at.
333 | *
334 | * @return this
335 | */
336 | writeUInt32BE(value: number, offset?: number): SmartBuffer;
337 | /**
338 | * Inserts an UInt32BE value at the given offset value.
339 | *
340 | * @param value { Number } The value to insert.
341 | * @param offset { Number } The offset to insert the value at.
342 | *
343 | * @return this
344 | */
345 | insertUInt32BE(value: number, offset: number): SmartBuffer;
346 | /**
347 | * Writes an UInt32LE value to the current write position (or at optional offset).
348 | *
349 | * @param value { Number } The value to write.
350 | * @param offset { Number } The offset to write the value at.
351 | *
352 | * @return this
353 | */
354 | writeUInt32LE(value: number, offset?: number): SmartBuffer;
355 | /**
356 | * Inserts an UInt32LE value at the given offset value.
357 | *
358 | * @param value { Number } The value to insert.
359 | * @param offset { Number } The offset to insert the value at.
360 | *
361 | * @return this
362 | */
363 | insertUInt32LE(value: number, offset: number): SmartBuffer;
364 | /**
365 | * Writes a BigUInt64BE value to the current write position (or at optional offset).
366 | *
367 | * @param value { Number } The value to write.
368 | * @param offset { Number } The offset to write the value at.
369 | *
370 | * @return this
371 | */
372 | writeBigUInt64BE(value: bigint, offset?: number): SmartBuffer;
373 | /**
374 | * Inserts a BigUInt64BE value at the given offset value.
375 | *
376 | * @param value { Number } The value to insert.
377 | * @param offset { Number } The offset to insert the value at.
378 | *
379 | * @return this
380 | */
381 | insertBigUInt64BE(value: bigint, offset: number): SmartBuffer;
382 | /**
383 | * Writes a BigUInt64LE value to the current write position (or at optional offset).
384 | *
385 | * @param value { Number } The value to write.
386 | * @param offset { Number } The offset to write the value at.
387 | *
388 | * @return this
389 | */
390 | writeBigUInt64LE(value: bigint, offset?: number): SmartBuffer;
391 | /**
392 | * Inserts a BigUInt64LE value at the given offset value.
393 | *
394 | * @param value { Number } The value to insert.
395 | * @param offset { Number } The offset to insert the value at.
396 | *
397 | * @return this
398 | */
399 | insertBigUInt64LE(value: bigint, offset: number): SmartBuffer;
400 | /**
401 | * Reads an FloatBE value from the current read position or an optionally provided offset.
402 | *
403 | * @param offset { Number } The offset to read data from (optional)
404 | * @return { Number }
405 | */
406 | readFloatBE(offset?: number): number;
407 | /**
408 | * Reads an FloatLE value from the current read position or an optionally provided offset.
409 | *
410 | * @param offset { Number } The offset to read data from (optional)
411 | * @return { Number }
412 | */
413 | readFloatLE(offset?: number): number;
414 | /**
415 | * Writes a FloatBE value to the current write position (or at optional offset).
416 | *
417 | * @param value { Number } The value to write.
418 | * @param offset { Number } The offset to write the value at.
419 | *
420 | * @return this
421 | */
422 | writeFloatBE(value: number, offset?: number): SmartBuffer;
423 | /**
424 | * Inserts a FloatBE value at the given offset value.
425 | *
426 | * @param value { Number } The value to insert.
427 | * @param offset { Number } The offset to insert the value at.
428 | *
429 | * @return this
430 | */
431 | insertFloatBE(value: number, offset: number): SmartBuffer;
432 | /**
433 | * Writes a FloatLE value to the current write position (or at optional offset).
434 | *
435 | * @param value { Number } The value to write.
436 | * @param offset { Number } The offset to write the value at.
437 | *
438 | * @return this
439 | */
440 | writeFloatLE(value: number, offset?: number): SmartBuffer;
441 | /**
442 | * Inserts a FloatLE value at the given offset value.
443 | *
444 | * @param value { Number } The value to insert.
445 | * @param offset { Number } The offset to insert the value at.
446 | *
447 | * @return this
448 | */
449 | insertFloatLE(value: number, offset: number): SmartBuffer;
450 | /**
451 | * Reads an DoublEBE value from the current read position or an optionally provided offset.
452 | *
453 | * @param offset { Number } The offset to read data from (optional)
454 | * @return { Number }
455 | */
456 | readDoubleBE(offset?: number): number;
457 | /**
458 | * Reads an DoubleLE value from the current read position or an optionally provided offset.
459 | *
460 | * @param offset { Number } The offset to read data from (optional)
461 | * @return { Number }
462 | */
463 | readDoubleLE(offset?: number): number;
464 | /**
465 | * Writes a DoubleBE value to the current write position (or at optional offset).
466 | *
467 | * @param value { Number } The value to write.
468 | * @param offset { Number } The offset to write the value at.
469 | *
470 | * @return this
471 | */
472 | writeDoubleBE(value: number, offset?: number): SmartBuffer;
473 | /**
474 | * Inserts a DoubleBE value at the given offset value.
475 | *
476 | * @param value { Number } The value to insert.
477 | * @param offset { Number } The offset to insert the value at.
478 | *
479 | * @return this
480 | */
481 | insertDoubleBE(value: number, offset: number): SmartBuffer;
482 | /**
483 | * Writes a DoubleLE value to the current write position (or at optional offset).
484 | *
485 | * @param value { Number } The value to write.
486 | * @param offset { Number } The offset to write the value at.
487 | *
488 | * @return this
489 | */
490 | writeDoubleLE(value: number, offset?: number): SmartBuffer;
491 | /**
492 | * Inserts a DoubleLE value at the given offset value.
493 | *
494 | * @param value { Number } The value to insert.
495 | * @param offset { Number } The offset to insert the value at.
496 | *
497 | * @return this
498 | */
499 | insertDoubleLE(value: number, offset: number): SmartBuffer;
500 | /**
501 | * Reads a String from the current read position.
502 | *
503 | * @param arg1 { Number | String } The number of bytes to read as a String, or the BufferEncoding to use for
504 | * the string (Defaults to instance level encoding).
505 | * @param encoding { String } The BufferEncoding to use for the string (Defaults to instance level encoding).
506 | *
507 | * @return { String }
508 | */
509 | readString(arg1?: number | BufferEncoding, encoding?: BufferEncoding): string;
510 | /**
511 | * Inserts a String
512 | *
513 | * @param value { String } The String value to insert.
514 | * @param offset { Number } The offset to insert the string at.
515 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
516 | *
517 | * @return this
518 | */
519 | insertString(value: string, offset: number, encoding?: BufferEncoding): SmartBuffer;
520 | /**
521 | * Writes a String
522 | *
523 | * @param value { String } The String value to write.
524 | * @param arg2 { Number | String } The offset to write the string at, or the BufferEncoding to use.
525 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
526 | *
527 | * @return this
528 | */
529 | writeString(value: string, arg2?: number | BufferEncoding, encoding?: BufferEncoding): SmartBuffer;
530 | /**
531 | * Reads a null-terminated String from the current read position.
532 | *
533 | * @param encoding { String } The BufferEncoding to use for the string (Defaults to instance level encoding).
534 | *
535 | * @return { String }
536 | */
537 | readStringNT(encoding?: BufferEncoding): string;
538 | /**
539 | * Inserts a null-terminated String.
540 | *
541 | * @param value { String } The String value to write.
542 | * @param arg2 { Number | String } The offset to write the string to, or the BufferEncoding to use.
543 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
544 | *
545 | * @return this
546 | */
547 | insertStringNT(value: string, offset: number, encoding?: BufferEncoding): SmartBuffer;
548 | /**
549 | * Writes a null-terminated String.
550 | *
551 | * @param value { String } The String value to write.
552 | * @param arg2 { Number | String } The offset to write the string to, or the BufferEncoding to use.
553 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
554 | *
555 | * @return this
556 | */
557 | writeStringNT(value: string, arg2?: number | BufferEncoding, encoding?: BufferEncoding): SmartBuffer;
558 | /**
559 | * Reads a Buffer from the internal read position.
560 | *
561 | * @param length { Number } The length of data to read as a Buffer.
562 | *
563 | * @return { Buffer }
564 | */
565 | readBuffer(length?: number): Buffer;
566 | /**
567 | * Writes a Buffer to the current write position.
568 | *
569 | * @param value { Buffer } The Buffer to write.
570 | * @param offset { Number } The offset to write the Buffer to.
571 | *
572 | * @return this
573 | */
574 | insertBuffer(value: Buffer, offset: number): SmartBuffer;
575 | /**
576 | * Writes a Buffer to the current write position.
577 | *
578 | * @param value { Buffer } The Buffer to write.
579 | * @param offset { Number } The offset to write the Buffer to.
580 | *
581 | * @return this
582 | */
583 | writeBuffer(value: Buffer, offset?: number): SmartBuffer;
584 | /**
585 | * Reads a null-terminated Buffer from the current read poisiton.
586 | *
587 | * @return { Buffer }
588 | */
589 | readBufferNT(): Buffer;
590 | /**
591 | * Inserts a null-terminated Buffer.
592 | *
593 | * @param value { Buffer } The Buffer to write.
594 | * @param offset { Number } The offset to write the Buffer to.
595 | *
596 | * @return this
597 | */
598 | insertBufferNT(value: Buffer, offset: number): SmartBuffer;
599 | /**
600 | * Writes a null-terminated Buffer.
601 | *
602 | * @param value { Buffer } The Buffer to write.
603 | * @param offset { Number } The offset to write the Buffer to.
604 | *
605 | * @return this
606 | */
607 | writeBufferNT(value: Buffer, offset?: number): SmartBuffer;
608 | /**
609 | * Clears the SmartBuffer instance to its original empty state.
610 | */
611 | clear(): SmartBuffer;
612 | /**
613 | * Gets the remaining data left to be read from the SmartBuffer instance.
614 | *
615 | * @return { Number }
616 | */
617 | remaining(): number;
618 | /**
619 | * Gets the current read offset value of the SmartBuffer instance.
620 | *
621 | * @return { Number }
622 | */
623 | /**
624 | * Sets the read offset value of the SmartBuffer instance.
625 | *
626 | * @param offset { Number } - The offset value to set.
627 | */
628 | readOffset: number;
629 | /**
630 | * Gets the current write offset value of the SmartBuffer instance.
631 | *
632 | * @return { Number }
633 | */
634 | /**
635 | * Sets the write offset value of the SmartBuffer instance.
636 | *
637 | * @param offset { Number } - The offset value to set.
638 | */
639 | writeOffset: number;
640 | /**
641 | * Gets the currently set string encoding of the SmartBuffer instance.
642 | *
643 | * @return { BufferEncoding } The string Buffer encoding currently set.
644 | */
645 | /**
646 | * Sets the string encoding of the SmartBuffer instance.
647 | *
648 | * @param encoding { BufferEncoding } The string Buffer encoding to set.
649 | */
650 | encoding: BufferEncoding;
651 | /**
652 | * Gets the underlying internal Buffer. (This includes unmanaged data in the Buffer)
653 | *
654 | * @return { Buffer } The Buffer value.
655 | */
656 | readonly internalBuffer: Buffer;
657 | /**
658 | * Gets the value of the internal managed Buffer (Includes managed data only)
659 | *
660 | * @param { Buffer }
661 | */
662 | toBuffer(): Buffer;
663 | /**
664 | * Gets the String value of the internal managed Buffer
665 | *
666 | * @param encoding { String } The BufferEncoding to display the Buffer as (defaults to instance level encoding).
667 | */
668 | toString(encoding?: BufferEncoding): string;
669 | /**
670 | * Destroys the SmartBuffer instance.
671 | */
672 | destroy(): SmartBuffer;
673 | /**
674 | * Handles inserting and writing strings.
675 | *
676 | * @param value { String } The String value to insert.
677 | * @param isInsert { Boolean } True if inserting a string, false if writing.
678 | * @param arg2 { Number | String } The offset to insert the string at, or the BufferEncoding to use.
679 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
680 | */
681 | private _handleString;
682 | /**
683 | * Handles writing or insert of a Buffer.
684 | *
685 | * @param value { Buffer } The Buffer to write.
686 | * @param offset { Number } The offset to write the Buffer to.
687 | */
688 | private _handleBuffer;
689 | /**
690 | * Ensures that the internal Buffer is large enough to read data.
691 | *
692 | * @param length { Number } The length of the data that needs to be read.
693 | * @param offset { Number } The offset of the data that needs to be read.
694 | */
695 | private ensureReadable;
696 | /**
697 | * Ensures that the internal Buffer is large enough to insert data.
698 | *
699 | * @param dataLength { Number } The length of the data that needs to be written.
700 | * @param offset { Number } The offset of the data to be written.
701 | */
702 | private ensureInsertable;
703 | /**
704 | * Ensures that the internal Buffer is large enough to write data.
705 | *
706 | * @param dataLength { Number } The length of the data that needs to be written.
707 | * @param offset { Number } The offset of the data to be written (defaults to writeOffset).
708 | */
709 | private _ensureWriteable;
710 | /**
711 | * Ensures that the internal Buffer is large enough to write at least the given amount of data.
712 | *
713 | * @param minLength { Number } The minimum length of the data needs to be written.
714 | */
715 | private _ensureCapacity;
716 | /**
717 | * Reads a numeric number value using the provided function.
718 | *
719 | * @typeparam T { number | bigint } The type of the value to be read
720 | *
721 | * @param func { Function(offset: number) => number } The function to read data on the internal Buffer with.
722 | * @param byteSize { Number } The number of bytes read.
723 | * @param offset { Number } The offset to read from (optional). When this is not provided, the managed readOffset is used instead.
724 | *
725 | * @returns { T } the number value
726 | */
727 | private _readNumberValue;
728 | /**
729 | * Inserts a numeric number value based on the given offset and value.
730 | *
731 | * @typeparam T { number | bigint } The type of the value to be written
732 | *
733 | * @param func { Function(offset: T, offset?) => number} The function to write data on the internal Buffer with.
734 | * @param byteSize { Number } The number of bytes written.
735 | * @param value { T } The number value to write.
736 | * @param offset { Number } the offset to write the number at (REQUIRED).
737 | *
738 | * @returns SmartBuffer this buffer
739 | */
740 | private _insertNumberValue;
741 | /**
742 | * Writes a numeric number value based on the given offset and value.
743 | *
744 | * @typeparam T { number | bigint } The type of the value to be written
745 | *
746 | * @param func { Function(offset: T, offset?) => number} The function to write data on the internal Buffer with.
747 | * @param byteSize { Number } The number of bytes written.
748 | * @param value { T } The number value to write.
749 | * @param offset { Number } the offset to write the number at (REQUIRED).
750 | *
751 | * @returns SmartBuffer this buffer
752 | */
753 | private _writeNumberValue;
754 | }
755 | export { SmartBufferOptions, SmartBuffer };
756 |
--------------------------------------------------------------------------------
/test/smartbuffer.test.ts:
--------------------------------------------------------------------------------
1 | import { SmartBuffer, SmartBufferOptions } from '../src/smartbuffer';
2 | import { ERRORS, isFiniteInteger, checkEncoding, checkOffsetValue, checkLengthValue, checkTargetOffset } from '../src/utils';
3 | import { assert } from 'chai';
4 | import 'mocha';
5 |
6 | describe('Constructing a SmartBuffer', () => {
7 | describe('Constructing with an existing Buffer', () => {
8 | const buff = new Buffer([0xaa, 0xbb, 0xcc, 0xdd, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99]);
9 | const reader = SmartBuffer.fromBuffer(buff);
10 |
11 | it('should have the exact same internal Buffer when constructed with a Buffer', () => {
12 | assert.strictEqual(reader.internalBuffer, buff);
13 | });
14 |
15 | it('should return a buffer with the same content', () => {
16 | assert.deepEqual(reader.toBuffer(), buff);
17 | });
18 | });
19 |
20 | describe('Constructing with an existing Buffer and setting the encoding', () => {
21 | const buff = new Buffer([0xaa, 0xbb, 0xcc, 0xdd, 0xff, 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99]);
22 | const reader = SmartBuffer.fromBuffer(buff, 'ascii');
23 |
24 | it('should have the exact same internal Buffer', () => {
25 | assert.strictEqual(reader.internalBuffer, buff);
26 | });
27 |
28 | it('should have the same encoding that was set', () => {
29 | assert.strictEqual(reader.encoding, 'ascii');
30 | });
31 | });
32 |
33 | describe('Constructing with a specified size', () => {
34 | const size = 128;
35 | const reader = SmartBuffer.fromSize(size);
36 |
37 | it('should have an internal Buffer with the same length as the size defined in the constructor', () => {
38 | assert.strictEqual(reader.internalBuffer.length, size);
39 | });
40 | });
41 |
42 | describe('Constructing with a specified encoding', () => {
43 | const encoding: BufferEncoding = 'utf8';
44 |
45 | it('should have an internal encoding with the encoding given to the constructor (1st argument)', () => {
46 | const reader = SmartBuffer.fromOptions({
47 | encoding
48 | });
49 | assert.strictEqual(reader.encoding, encoding);
50 | });
51 |
52 | it('should have an internal encoding with the encoding given to the constructor (2nd argument)', () => {
53 | const reader = SmartBuffer.fromSize(1024, encoding);
54 | assert.strictEqual(reader.encoding, encoding);
55 | });
56 | });
57 |
58 | describe('Constructing with SmartBufferOptions', () => {
59 | const validOptions1: SmartBufferOptions = {
60 | size: 1024,
61 | encoding: 'ascii'
62 | };
63 |
64 | const validOptions2: SmartBufferOptions = {
65 | buff: Buffer.alloc(1024)
66 | };
67 |
68 | const validOptions3: SmartBufferOptions = {
69 | encoding: 'utf8'
70 | };
71 |
72 | const invalidOptions1: any = {
73 | encoding: 'invalid'
74 | };
75 |
76 | const invalidOptions2: any = {
77 | size: -1
78 | };
79 |
80 | const invalidOptions3: any = {
81 | buff: 'notabuffer'
82 | };
83 |
84 | it('should create a SmartBuffer with size 1024 and ascii encoding', () => {
85 | const sbuff = SmartBuffer.fromOptions(validOptions1);
86 | assert.strictEqual(sbuff.encoding, validOptions1.encoding);
87 | assert.strictEqual(sbuff.internalBuffer.length, validOptions1.size);
88 | });
89 |
90 | it('should create a SmartBuffer with the provided buffer as the initial value', () => {
91 | const sbuff = SmartBuffer.fromOptions(validOptions2);
92 | assert.deepEqual(sbuff.internalBuffer, validOptions2.buff);
93 | });
94 |
95 | it('should create a SmartBuffer with the provided ascii encoding, and create a default buffer size', () => {
96 | const sbuff = SmartBuffer.fromOptions(validOptions3);
97 | assert.strictEqual(sbuff.encoding, validOptions3.encoding);
98 | assert.strictEqual(sbuff.internalBuffer.length, 4096);
99 | });
100 |
101 | it('should throw an error when given an options object with an invalid encoding', () => {
102 | assert.throws(() => {
103 | // tslint:disable-next-line:no-unused-variable
104 | const sbuff = SmartBuffer.fromOptions(invalidOptions1);
105 | });
106 | });
107 |
108 | it('should throw an error when given an options object with an invalid size', () => {
109 | assert.throws(() => {
110 | // tslint:disable-next-line:no-unused-variable
111 | const sbuff = SmartBuffer.fromOptions(invalidOptions2);
112 | });
113 | });
114 |
115 | it('should throw an error when given an options object with an invalid buffer', () => {
116 | assert.throws(() => {
117 | // tslint:disable-next-line:no-unused-variable
118 | const sbuff = SmartBuffer.fromOptions(invalidOptions3);
119 | });
120 | });
121 | });
122 |
123 | describe('Constructing with invalid parameters', () => {
124 | it('should throw an exception when given an object that is not a valid SmartBufferOptions object', () => {
125 | assert.throws(() => {
126 | const invalidOptions: object = {};
127 | const reader = SmartBuffer.fromOptions(invalidOptions);
128 | });
129 | });
130 |
131 | it('should throw an exception when given an invalid number size', () => {
132 | assert.throws(() => {
133 | // tslint:disable-next-line:no-unused-variable
134 | const reader = SmartBuffer.fromOptions({
135 | size: -100
136 | });
137 | }, Error);
138 | });
139 |
140 | it('should throw an exception when give a invalid encoding', () => {
141 | assert.throws(() => {
142 | const invalidEncoding: any = 'invalid';
143 | // tslint:disable-next-line:no-unused-variable
144 | const reader = SmartBuffer.fromOptions({
145 | encoding: invalidEncoding
146 | });
147 | }, Error);
148 |
149 | assert.throws(() => {
150 | const invalidEncoding: any = 'invalid';
151 | // tslint:disable-next-line:no-unused-variable
152 | const reader = SmartBuffer.fromSize(1024, invalidEncoding);
153 | }, Error);
154 | });
155 |
156 | it('should throw and exception when given an object that is not a SmartBufferOptions', () => {
157 | assert.throws(() => {
158 | // tslint:disable-next-line:no-unused-variable
159 | const reader = SmartBuffer.fromOptions(null);
160 | }, Error);
161 | });
162 | });
163 |
164 | describe('Constructing with factory methods', () => {
165 | const originalBuffer = new Buffer(10);
166 |
167 | const sbuff1 = SmartBuffer.fromBuffer(originalBuffer);
168 |
169 | it('Should create a SmartBuffer with a provided internal Buffer as the initial value', () => {
170 | assert.deepEqual(sbuff1.internalBuffer, originalBuffer);
171 | });
172 |
173 | const sbuff2 = SmartBuffer.fromSize(1024);
174 |
175 | it('Should create a SmartBuffer with a set provided initial Buffer size', () => {
176 | assert.strictEqual(sbuff2.internalBuffer.length, 1024);
177 | });
178 |
179 | const options: any = {
180 | size: 1024,
181 | encoding: 'ascii'
182 | };
183 |
184 | const sbuff3 = SmartBuffer.fromOptions(options);
185 |
186 | it('Should create a SmartBuffer instance with a given SmartBufferOptions object', () => {
187 | assert.strictEqual(sbuff3.encoding, options.encoding);
188 | assert.strictEqual(sbuff3.internalBuffer.length, options.size);
189 | });
190 | });
191 | });
192 |
193 | describe('Reading/Writing To/From SmartBuffer', () => {
194 | /**
195 | * Technically, if one of these works, they all should. But they're all here anyways.
196 | */
197 | describe('Numeric Values', () => {
198 | let reader = new SmartBuffer();
199 | reader.writeInt8(0x44);
200 | reader.writeUInt8(0xff);
201 | reader.writeInt16BE(0x6699);
202 | reader.writeInt16LE(0x6699);
203 | reader.writeUInt16BE(0xffdd);
204 | reader.writeUInt16LE(0xffdd);
205 | reader.writeInt32BE(0x77889900);
206 | reader.writeInt32LE(0x77889900);
207 | reader.writeUInt32BE(0xffddccbb);
208 | reader.writeUInt32LE(0xffddccbb);
209 | reader.writeFloatBE(1.234);
210 | reader.writeFloatLE(1.234);
211 | reader.writeDoubleBE(1.23456789);
212 | reader.writeDoubleLE(1.23456789);
213 | reader.writeUInt8(0xc8, 0);
214 | reader.writeUInt16LE(0xc8, 4);
215 | reader.insertUInt16LE(0x6699, 6);
216 | reader.writeUInt16BE(0x6699);
217 | reader.insertUInt16BE(0x6699, reader.length - 1);
218 |
219 | let iReader = new SmartBuffer();
220 |
221 | iReader.insertInt8(0x44, 0);
222 | iReader.insertUInt8(0x44, 0);
223 | iReader.insertInt16BE(0x6699, 0);
224 | iReader.insertInt16LE(0x6699, 0);
225 | iReader.insertUInt16BE(0x6699, 0);
226 | iReader.insertUInt16LE(0x6699, 0);
227 | iReader.insertInt32BE(0x6699, 0);
228 | iReader.insertInt32LE(0x6699, 0);
229 | iReader.insertUInt32BE(0x6699, 0);
230 | iReader.insertUInt32LE(0x6699, 0);
231 | iReader.insertFloatBE(0x6699, 0);
232 | iReader.insertFloatLE(0x6699, 0);
233 | iReader.insertDoubleBE(0x6699, 0);
234 | iReader.insertDoubleLE(0x6699, 0);
235 | iReader.writeStringNT('h', 2);
236 | iReader.insertBuffer(new Buffer('he'), 2);
237 | iReader.insertBufferNT(new Buffer('he'), 2);
238 | iReader.readInt8(0);
239 |
240 | it('should equal the correct values that were written above', () => {
241 | assert.strictEqual(reader.readUInt8(), 0xc8);
242 | assert.strictEqual(reader.readUInt8(), 0xff);
243 | assert.strictEqual(reader.readInt16BE(), 0x6699);
244 | assert.strictEqual(reader.readInt16LE(), 0xc8);
245 | assert.strictEqual(reader.readInt16LE(), 0x6699);
246 | assert.strictEqual(reader.readUInt16BE(), 0xffdd);
247 | assert.strictEqual(reader.readUInt16LE(), 0xffdd);
248 | assert.strictEqual(reader.readInt32BE(), 0x77889900);
249 | assert.strictEqual(reader.readInt32LE(), 0x77889900);
250 | assert.strictEqual(reader.readUInt32BE(), 0xffddccbb);
251 | assert.strictEqual(reader.readUInt32LE(), 0xffddccbb);
252 | assert.closeTo(reader.readFloatBE(), 1.234, 0.001);
253 | assert.closeTo(reader.readFloatLE(), 1.234, 0.001);
254 | assert.closeTo(reader.readDoubleBE(), 1.23456789, 0.001);
255 | assert.closeTo(reader.readDoubleLE(), 1.23456789, 0.001);
256 | assert.equal(reader.readUInt8(0), 0xc8);
257 | });
258 |
259 | it('should throw an exception if attempting to read numeric values from a buffer with not enough data left', () => {
260 | assert.throws(() => {
261 | reader.readUInt32BE();
262 | });
263 | });
264 |
265 | it('should throw an exception if attempting to write numeric values to a negative offset.', () => {
266 | assert.throws(() => {
267 | reader.writeUInt16BE(20, -5);
268 | });
269 | });
270 | });
271 |
272 |
273 | describe('BigInt values', () => {
274 | describe('When BigInt is available and so are Buffer methods', () => {
275 | before(function() {
276 | if (typeof BigInt === 'undefined' ||
277 | typeof Buffer.prototype.writeBigInt64BE === 'undefined') {
278 | this.skip();
279 | }
280 | });
281 |
282 | it('Reading written-to buffer should read back the results of the insert', () => {
283 | const wBuffer = new SmartBuffer();
284 | wBuffer.writeBigInt64LE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(2));
285 | wBuffer.writeBigInt64BE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(3));
286 | wBuffer.writeBigUInt64LE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(4));
287 | wBuffer.writeBigUInt64BE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(5));
288 |
289 | assert.equal(wBuffer.readBigInt64LE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(2));
290 | assert.equal(wBuffer.readBigInt64BE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(3));
291 | assert.equal(wBuffer.readBigUInt64LE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(4));
292 | assert.equal(wBuffer.readBigUInt64BE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(5));
293 | });
294 |
295 | it('Reading inserted-into buffer should read back the results of the insert', () => {
296 | const iBuffer = new SmartBuffer();
297 | iBuffer.insertBigInt64LE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(6), 0);
298 | iBuffer.insertBigInt64BE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(7), 0);
299 | iBuffer.insertBigUInt64LE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(8), 0);
300 | iBuffer.insertBigUInt64BE(BigInt(Number.MAX_SAFE_INTEGER) * BigInt(9), 0);
301 |
302 | assert.equal(iBuffer.readBigInt64BE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(9));
303 | assert.equal(iBuffer.readBigInt64LE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(8));
304 | assert.equal(iBuffer.readBigUInt64BE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(7));
305 | assert.equal(iBuffer.readBigUInt64LE(), BigInt(Number.MAX_SAFE_INTEGER) * BigInt(6));
306 | });
307 | });
308 |
309 | describe('When BigInt is available but buffer methods are not', () => {
310 | beforeEach(function () {
311 | if (typeof BigInt === 'undefined' ||
312 | typeof Buffer.prototype.readBigInt64BE === 'function') {
313 | this.skip();
314 | }
315 | });
316 | const buffer = new SmartBuffer();
317 |
318 | // Taking a Number to a BigInt as we do below is semantically invalid,
319 | // and implicit casting between Number and BigInt throws a TypeError in
320 | // JavaScript. However here, these methods immediately throw the platform
321 | // exception, and no cast really takes place. These casts are solely to
322 | // satisfy the type checker, as BigInt doesn't exist at runtime in these tests
323 |
324 | it('Writing throws an exception', () => {
325 | assert.throws(() => buffer.writeBigInt64LE(1 as any as bigint), 'Platform does not support Buffer.prototype.writeBigInt64LE.');
326 | assert.throws(() => buffer.writeBigInt64BE(2 as any as bigint), 'Platform does not support Buffer.prototype.writeBigInt64BE.');
327 | assert.throws(() => buffer.writeBigUInt64LE(1 as any as bigint), 'Platform does not support Buffer.prototype.writeBigUInt64LE.');
328 | assert.throws(() => buffer.writeBigUInt64BE(2 as any as bigint), 'Platform does not support Buffer.prototype.writeBigUInt64BE.');
329 | });
330 |
331 | it('Inserting throws an exception', () => {
332 | assert.throws(
333 | () => buffer.insertBigInt64LE(1 as any as bigint, 0), 'Platform does not support Buffer.prototype.writeBigInt64LE.');
334 | assert.throws(
335 | () => buffer.insertBigInt64BE(2 as any as bigint, 0), 'Platform does not support Buffer.prototype.writeBigInt64BE.');
336 | assert.throws(
337 | () => buffer.insertBigUInt64LE(1 as any as bigint, 0), 'Platform does not support Buffer.prototype.writeBigUInt64LE.');
338 | assert.throws(
339 | () => buffer.insertBigUInt64BE(2 as any as bigint, 0), 'Platform does not support Buffer.prototype.writeBigUInt64BE.');
340 | });
341 |
342 | it('Reading throws an exception', () => {
343 | assert.throws(() => buffer.readBigInt64LE(), 'Platform does not support Buffer.prototype.readBigInt64LE.');
344 | assert.throws(() => buffer.readBigInt64BE(), 'Platform does not support Buffer.prototype.readBigInt64BE.');
345 | assert.throws(() => buffer.readBigUInt64LE(), 'Platform does not support Buffer.prototype.readBigUInt64LE.');
346 | assert.throws(() => buffer.readBigUInt64BE(), 'Platform does not support Buffer.prototype.readBigUInt64BE.');
347 | });
348 | });
349 |
350 | describe('When BigInt is unavailable', () => {
351 | beforeEach(function () {
352 | if (typeof BigInt === 'function') {
353 | this.skip();
354 | }
355 | });
356 | const buffer = new SmartBuffer();
357 |
358 | // Taking a Number to a BigInt as we do below is semantically invalid,
359 | // and implicit casting between Number and BigInt throws a TypeError in
360 | // JavaScript. However here, these methods immediately throw the platform
361 | // exception, and no cast really takes place. These casts are solely to
362 | // satisfy the type checker, as BigInt doesn't exist at runtime in these tests
363 |
364 | it('Writing throws an exception', () => {
365 | assert.throws(() => buffer.writeBigInt64LE(1 as any as bigint), 'Platform does not support JS BigInt type.');
366 | assert.throws(() => buffer.writeBigInt64BE(2 as any as bigint), 'Platform does not support JS BigInt type.');
367 | assert.throws(() => buffer.writeBigUInt64LE(1 as any as bigint), 'Platform does not support JS BigInt type.');
368 | assert.throws(() => buffer.writeBigUInt64BE(2 as any as bigint), 'Platform does not support JS BigInt type.');
369 | });
370 |
371 | it('Inserting throws an exception', () => {
372 | assert.throws(() => buffer.insertBigInt64LE(1 as any as bigint, 0), 'Platform does not support JS BigInt type.');
373 | assert.throws(() => buffer.insertBigInt64BE(2 as any as bigint, 0), 'Platform does not support JS BigInt type.');
374 | assert.throws(() => buffer.insertBigUInt64LE(1 as any as bigint, 0), 'Platform does not support JS BigInt type.');
375 | assert.throws(() => buffer.insertBigUInt64BE(2 as any as bigint, 0), 'Platform does not support JS BigInt type.');
376 | });
377 |
378 | it('Reading throws an exception', () => {
379 | assert.throws(() => buffer.readBigInt64LE(), 'Platform does not support JS BigInt type.');
380 | assert.throws(() => buffer.readBigInt64BE(), 'Platform does not support JS BigInt type.');
381 | assert.throws(() => buffer.readBigUInt64LE(), 'Platform does not support JS BigInt type.');
382 | assert.throws(() => buffer.readBigUInt64BE(), 'Platform does not support JS BigInt type.');
383 | });
384 | });
385 | });
386 |
387 | describe('Basic String Values', () => {
388 | let reader = new SmartBuffer();
389 | reader.writeStringNT('hello');
390 | reader.writeString('world');
391 | reader.writeStringNT('✎✏✎✏✎✏');
392 | reader.insertStringNT('first', 0);
393 | reader.writeString('hello', 'ascii');
394 | reader.writeString('hello');
395 |
396 | it('should equal the correct strings that were written prior', () => {
397 | assert.strictEqual(reader.readStringNT(), 'first');
398 | assert.strictEqual(reader.readStringNT(), 'hello');
399 | assert.strictEqual(reader.readString(5), 'world');
400 | assert.strictEqual(reader.readStringNT(), '✎✏✎✏✎✏');
401 | assert.strictEqual(reader.readString(5, 'ascii'), 'hello');
402 | });
403 |
404 | it('should throw an exception if passing in an invalid string length to read (infinite)', () => {
405 | assert.throws(() => {
406 | reader.readString(NaN);
407 | });
408 | });
409 |
410 | it('should throw an exception if passing in an invalid string length to read (negative)', () => {
411 | assert.throws(() => {
412 | reader.readString(-5);
413 | });
414 | });
415 |
416 | it('should throw an exception if passing in an invalid string offset to insert (non number)', () => {
417 | assert.throws(() => {
418 | const invalidNumber: any = 'sdfdf';
419 | reader.insertString('hello', invalidNumber);
420 | });
421 | });
422 | });
423 |
424 | describe('Mixed Encoding Strings', () => {
425 | let reader = SmartBuffer.fromOptions({
426 | encoding: 'ascii'
427 | });
428 | reader.writeStringNT('some ascii text');
429 | reader.writeStringNT('ѕσмє υтƒ8 тєχт', 'utf8');
430 | reader.insertStringNT('first', 0, 'ascii');
431 |
432 | it('should equal the correct strings that were written above', () => {
433 | assert.strictEqual(reader.readStringNT(), 'first');
434 | assert.strictEqual(reader.readStringNT(), 'some ascii text');
435 | assert.strictEqual(reader.readStringNT('utf8'), 'ѕσмє υтƒ8 тєχт');
436 | });
437 |
438 | it('should throw an error when an invalid encoding is provided', () => {
439 | assert.throws(() => {
440 | // tslint:disable-next-line
441 | const invalidBufferType: any = 'invalid';
442 | reader.writeString('hello', invalidBufferType);
443 | });
444 | });
445 |
446 | it('should throw an error when an invalid encoding is provided along with a valid offset', () => {
447 | assert.throws(() => {
448 | const invalidBufferType: any = 'invalid';
449 | reader.writeString('hellothere', 2, invalidBufferType);
450 | });
451 | });
452 | });
453 |
454 | describe('Null/non-null terminating strings', () => {
455 | let reader = new SmartBuffer();
456 | reader.writeString('hello\0test\0bleh');
457 |
458 | it('should equal hello', () => {
459 | assert.strictEqual(reader.readStringNT(), 'hello');
460 | });
461 |
462 | it('should equal: test', () => {
463 | assert.strictEqual(reader.readString(4), 'test');
464 | });
465 |
466 | it('should have a length of zero', () => {
467 | assert.strictEqual(reader.readStringNT().length, 0);
468 | });
469 |
470 | it('should return an empty string', () => {
471 | assert.strictEqual(reader.readString(0), '');
472 | });
473 |
474 | it('should equal: bleh', () => {
475 | assert.strictEqual(reader.readStringNT(), 'bleh');
476 | });
477 | });
478 |
479 | describe('Reading string without specifying length', () => {
480 | let str = 'hello123';
481 | let writer = new SmartBuffer();
482 | writer.writeString(str);
483 |
484 | let reader = SmartBuffer.fromBuffer(writer.toBuffer());
485 |
486 | assert.strictEqual(reader.readString(), str);
487 | });
488 |
489 | describe('Write string as specific position', () => {
490 | let str = 'hello123';
491 | let writer = new SmartBuffer();
492 | writer.writeString(str, 10);
493 |
494 | let reader = SmartBuffer.fromBuffer(writer.toBuffer());
495 |
496 | reader.readOffset = 10;
497 | it('Should read the correct string from the original position it was written to.', () => {
498 | assert.strictEqual(reader.readString(), str);
499 | });
500 | });
501 |
502 | describe('Buffer Values', () => {
503 | describe('Writing buffer to position 0', () => {
504 | let buff = new SmartBuffer();
505 | let frontBuff = new Buffer([1, 2, 3, 4, 5, 6]);
506 | buff.writeStringNT('hello');
507 | buff.writeBuffer(frontBuff, 0);
508 |
509 | it('should write the buffer to the front of the smart buffer instance', () => {
510 | let readBuff = buff.readBuffer(frontBuff.length);
511 | assert.deepEqual(readBuff, frontBuff);
512 | });
513 | });
514 |
515 | describe('Writing null terminated buffer to position 0', () => {
516 | let buff = new SmartBuffer();
517 | let frontBuff = new Buffer([1, 2, 3, 4, 5, 6]);
518 | buff.writeStringNT('hello');
519 | buff.writeBufferNT(frontBuff, 0);
520 |
521 | it('should write the buffer to the front of the smart buffer instance', () => {
522 | let readBuff = buff.readBufferNT();
523 | assert.deepEqual(readBuff, frontBuff);
524 | });
525 | });
526 |
527 | describe('Explicit lengths', () => {
528 | let buff = new Buffer([0x01, 0x02, 0x04, 0x08, 0x16, 0x32, 0x64]);
529 | let reader = new SmartBuffer();
530 | reader.writeBuffer(buff);
531 |
532 | it('should equal the buffer that was written above.', () => {
533 | assert.deepEqual(reader.readBuffer(7), buff);
534 | });
535 | });
536 |
537 | describe('Implicit lengths', () => {
538 | let buff = new Buffer([0x01, 0x02, 0x04, 0x08, 0x16, 0x32, 0x64]);
539 | let reader = new SmartBuffer();
540 | reader.writeBuffer(buff);
541 |
542 | it('should equal the buffer that was written above.', () => {
543 | assert.deepEqual(reader.readBuffer(), buff);
544 | });
545 | });
546 |
547 | describe('Null Terminated Buffer Reading', () => {
548 | let buff = new SmartBuffer();
549 | buff.writeBuffer(new Buffer([0x01, 0x02, 0x03, 0x04, 0x00, 0x01, 0x02, 0x03]));
550 |
551 | let read1 = buff.readBufferNT();
552 | let read2 = buff.readBufferNT();
553 |
554 | it('Should return a length of 4 for the four bytes before the first null in the buffer.', () => {
555 | assert.equal(read1.length, 4);
556 | });
557 |
558 | it('Should return a length of 3 for the three bytes after the first null in the buffer after reading to end.', () => {
559 | assert.equal(read2.length, 3);
560 | });
561 | });
562 |
563 | describe('Null Terminated Buffer Writing', () => {
564 | let buff = new SmartBuffer();
565 | buff.writeBufferNT(new Buffer([0x01, 0x02, 0x03, 0x04]));
566 |
567 | let read1 = buff.readBufferNT();
568 |
569 | it('Should read the correct null terminated buffer data.', () => {
570 | assert.equal(read1.length, 4);
571 | });
572 | });
573 |
574 | describe('Reading buffer from invalid offset', () => {
575 | let buff = new SmartBuffer();
576 | buff.writeBuffer(Buffer.from([1, 2, 3, 4, 5, 6]));
577 |
578 | it('Should throw an exception if attempting to read a Buffer from an invalid offset', () => {
579 | assert.throws(() => {
580 | const invalidOffset: any = 'sfsdf';
581 | buff.readBuffer(invalidOffset);
582 | });
583 | });
584 | });
585 |
586 | describe('Inserting values into specific positions', () => {
587 | let reader = new SmartBuffer();
588 |
589 | reader.writeUInt16LE(0x0060);
590 | reader.writeStringNT('something');
591 | reader.writeUInt32LE(8485934);
592 | reader.writeUInt16LE(6699);
593 | reader.writeStringNT('else');
594 | reader.insertUInt16LE(reader.length - 2, 2);
595 |
596 | it('should equal the size of the remaining data in the buffer', () => {
597 | reader.readUInt16LE();
598 | let size = reader.readUInt16LE();
599 | assert.strictEqual(reader.remaining(), size);
600 | });
601 | });
602 |
603 | describe('Adding more data to the buffer than the internal buffer currently allows.', () => {
604 | it('Should automatically adjust internal buffer size when needed', () => {
605 | let writer = new SmartBuffer();
606 | let largeBuff = new Buffer(10000);
607 |
608 | writer.writeBuffer(largeBuff);
609 |
610 | assert.strictEqual(writer.length, largeBuff.length);
611 | });
612 | });
613 | });
614 | });
615 |
616 | describe('Skipping around data', () => {
617 | let writer = new SmartBuffer();
618 | writer.writeStringNT('hello');
619 | writer.writeUInt16LE(6699);
620 | writer.writeStringNT('world!');
621 |
622 | it('Should equal the UInt16 that was written above', () => {
623 | let reader = SmartBuffer.fromBuffer(writer.toBuffer());
624 | reader.readOffset += 6;
625 | assert.strictEqual(reader.readUInt16LE(), 6699);
626 | reader.readOffset = 0;
627 | assert.strictEqual(reader.readStringNT(), 'hello');
628 | reader.readOffset -= 6;
629 | assert.strictEqual(reader.readStringNT(), 'hello');
630 | });
631 |
632 | it('Should throw an error when attempting to skip more bytes than actually exist.', () => {
633 | let reader = SmartBuffer.fromBuffer(writer.toBuffer());
634 |
635 | assert.throws(() => {
636 | reader.readOffset = 10000;
637 | });
638 | });
639 | });
640 |
641 | describe('Setting write and read offsets', () => {
642 | const writer = SmartBuffer.fromSize(100);
643 | writer.writeString('hellotheremynameisjosh');
644 |
645 | it('should set the write offset to 10', () => {
646 | writer.writeOffset = 10;
647 | assert.strictEqual(writer.writeOffset, 10);
648 | });
649 |
650 | it('should set the read offset to 10', () => {
651 | writer.readOffset = 10;
652 | assert.strictEqual(writer.readOffset, 10);
653 | });
654 |
655 | it('should throw an error when given an offset that is out of bounds', () => {
656 | assert.throws(() => {
657 | writer.readOffset = -1;
658 | });
659 | });
660 |
661 | it('should throw an error when given an offset that is out of bounds', () => {
662 | assert.throws(() => {
663 | writer.writeOffset = 1000;
664 | });
665 | });
666 | });
667 |
668 | describe('Setting encoding', () => {
669 | const writer = SmartBuffer.fromSize(100);
670 | it('should have utf8 encoding by default', () => {
671 | assert.strictEqual(writer.encoding, 'utf8');
672 | });
673 |
674 | it('should have ascii encoding after being set', () => {
675 | writer.encoding = 'ascii';
676 | assert.strictEqual(writer.encoding, 'ascii');
677 | });
678 | });
679 |
680 | describe('Automatic internal buffer resizing', () => {
681 | let writer = new SmartBuffer();
682 |
683 | it('Should not throw an error when adding data that is larger than current buffer size (internal resize algo fails)', () => {
684 | let str = 'String larger than one byte';
685 | writer = SmartBuffer.fromSize(1);
686 | writer.writeString(str);
687 |
688 | assert.strictEqual(writer.internalBuffer.length, str.length);
689 | });
690 |
691 | it('Should not throw an error when adding data that is larger than current buffer size (internal resize algo succeeds)', () => {
692 | writer = SmartBuffer.fromSize(100);
693 | let buff = new Buffer(105);
694 |
695 | writer.writeBuffer(buff);
696 |
697 | // Test internal array growth algo.
698 | assert.strictEqual(writer.internalBuffer.length, 100 * 3 / 2 + 1);
699 | });
700 | });
701 |
702 | describe('Clearing the buffer', () => {
703 | let writer = new SmartBuffer();
704 | writer.writeString('somedata');
705 |
706 | it('Should contain some data.', () => {
707 | assert.notStrictEqual(writer.length, 0);
708 | });
709 |
710 | it('Should contain zero data after being cleared.', () => {
711 | writer.clear();
712 | assert.strictEqual(writer.length, 0);
713 | });
714 | });
715 |
716 | describe('Displaying the buffer as a string', () => {
717 | let buff = new Buffer([1, 2, 3, 4]);
718 | let sbuff = SmartBuffer.fromBuffer(buff);
719 |
720 | let str = buff.toString();
721 | let str64 = buff.toString('binary');
722 |
723 | it('Should return a valid string representing the internal buffer', () => {
724 | assert.strictEqual(str, sbuff.toString());
725 | });
726 |
727 | it('Should return a valid base64 string representing the internal buffer', () => {
728 | assert.strictEqual(str64, sbuff.toString('binary'));
729 | });
730 |
731 | it('Should throw an error if an invalid encoding is provided', () => {
732 | assert.throws(() => {
733 | const invalidencoding: any = 'invalid';
734 | let strError = sbuff.toString(invalidencoding);
735 | });
736 | });
737 | });
738 |
739 | describe('Destroying the buffer', () => {
740 | let writer = new SmartBuffer();
741 | writer.writeString('hello123');
742 |
743 | writer.destroy();
744 |
745 | it('Should have a length of zero when buffer is destroyed', () => {
746 | assert.strictEqual(0, writer.length);
747 | });
748 | });
749 |
750 | describe('ensureWritable()', () => {
751 | let sbuff: any = SmartBuffer.fromSize(10);
752 |
753 | it('should increase the internal buffer size to accomodate given size.', () => {
754 | sbuff._ensureWriteable(100);
755 |
756 | assert.strictEqual(sbuff.internalBuffer.length >= 100, true);
757 | });
758 | });
759 |
760 | describe('isSmartBufferOptions()', () => {
761 | it('should return true when encoding is defined', () => {
762 | assert.strictEqual(
763 | SmartBuffer.isSmartBufferOptions({
764 | encoding: 'utf8'
765 | }),
766 | true
767 | );
768 | });
769 |
770 | it('should return true when size is defined', () => {
771 | assert.strictEqual(
772 | SmartBuffer.isSmartBufferOptions({
773 | size: 1024
774 | }),
775 | true
776 | );
777 | });
778 |
779 | it('should return true when buff is defined', () => {
780 | assert.strictEqual(
781 | SmartBuffer.isSmartBufferOptions({
782 | buff: Buffer.alloc(4096)
783 | }),
784 | true
785 | );
786 | });
787 | });
788 |
789 | describe('utils', () => {
790 | describe('isFiniteInteger', () => {
791 | it('should return true for a number that is finite and an integer', () => {
792 | assert.equal(isFiniteInteger(10), true);
793 | });
794 |
795 | it('should return false for a number that is infinite', () => {
796 | assert.equal(isFiniteInteger(NaN), false);
797 | });
798 |
799 | it('should return false for a number that is not an integer', () => {
800 | assert.equal(isFiniteInteger(10.1), false);
801 | });
802 | });
803 |
804 | describe('checkEncoding', () => {
805 | it('should throw an exception if a given string is not a valid BufferEncoding', () => {
806 | assert.throws(() => {
807 | const invalidEncoding: any = 'sdfdf';
808 | checkEncoding(invalidEncoding);
809 | });
810 | });
811 | });
812 | });
813 |
--------------------------------------------------------------------------------
/src/smartbuffer.ts:
--------------------------------------------------------------------------------
1 | import {
2 | ERRORS, checkOffsetValue, checkLengthValue, checkTargetOffset,
3 | checkEncoding, isFiniteInteger, bigIntAndBufferInt64Check
4 | } from './utils';
5 |
6 | /**
7 | * Object interface for constructing new SmartBuffer instances.
8 | */
9 | interface SmartBufferOptions {
10 | // Buffer Encoding to use for reading/writing strings if one is not provided.
11 | encoding?: BufferEncoding;
12 | // The initial size of the internal Buffer.
13 | size?: number;
14 | // If a Buffer is provided, this Buffer's value will be used as the internal Buffer.
15 | buff?: Buffer;
16 | }
17 |
18 | // The default Buffer size if one is not provided.
19 | const DEFAULT_SMARTBUFFER_SIZE: number = 4096;
20 |
21 | // The default string encoding to use for reading/writing strings.
22 | const DEFAULT_SMARTBUFFER_ENCODING: BufferEncoding = 'utf8';
23 |
24 | class SmartBuffer {
25 | public length: number = 0;
26 |
27 | private _encoding: BufferEncoding = DEFAULT_SMARTBUFFER_ENCODING;
28 | private _buff: Buffer;
29 | private _writeOffset: number = 0;
30 | private _readOffset: number = 0;
31 |
32 | /**
33 | * Creates a new SmartBuffer instance.
34 | *
35 | * @param options { SmartBufferOptions } The SmartBufferOptions to apply to this instance.
36 | */
37 | constructor(options?: SmartBufferOptions) {
38 | if (SmartBuffer.isSmartBufferOptions(options)) {
39 | // Checks for encoding
40 | if (options.encoding) {
41 | checkEncoding(options.encoding);
42 | this._encoding = options.encoding;
43 | }
44 |
45 | // Checks for initial size length
46 | if (options.size) {
47 | if (isFiniteInteger(options.size) && options.size > 0) {
48 | this._buff = Buffer.allocUnsafe(options.size);
49 | } else {
50 | throw new Error(ERRORS.INVALID_SMARTBUFFER_SIZE);
51 | }
52 | // Check for initial Buffer
53 | } else if (options.buff) {
54 | if (Buffer.isBuffer(options.buff)) {
55 | this._buff = options.buff;
56 | this.length = options.buff.length;
57 | } else {
58 | throw new Error(ERRORS.INVALID_SMARTBUFFER_BUFFER);
59 | }
60 | } else {
61 | this._buff = Buffer.allocUnsafe(DEFAULT_SMARTBUFFER_SIZE);
62 | }
63 | } else {
64 | // If something was passed but it's not a SmartBufferOptions object
65 | if (typeof options !== 'undefined') {
66 | throw new Error(ERRORS.INVALID_SMARTBUFFER_OBJECT);
67 | }
68 |
69 | // Otherwise default to sane options
70 | this._buff = Buffer.allocUnsafe(DEFAULT_SMARTBUFFER_SIZE);
71 | }
72 | }
73 |
74 | /**
75 | * Creates a new SmartBuffer instance with the provided internal Buffer size and optional encoding.
76 | *
77 | * @param size { Number } The size of the internal Buffer.
78 | * @param encoding { String } The BufferEncoding to use for strings.
79 | *
80 | * @return { SmartBuffer }
81 | */
82 | public static fromSize(size: number, encoding?: BufferEncoding): SmartBuffer {
83 | return new this({
84 | size: size,
85 | encoding: encoding
86 | });
87 | }
88 |
89 | /**
90 | * Creates a new SmartBuffer instance with the provided Buffer and optional encoding.
91 | *
92 | * @param buffer { Buffer } The Buffer to use as the internal Buffer value.
93 | * @param encoding { String } The BufferEncoding to use for strings.
94 | *
95 | * @return { SmartBuffer }
96 | */
97 | public static fromBuffer(buff: Buffer, encoding?: BufferEncoding): SmartBuffer {
98 | return new this({
99 | buff: buff,
100 | encoding: encoding
101 | });
102 | }
103 |
104 | /**
105 | * Creates a new SmartBuffer instance with the provided SmartBufferOptions options.
106 | *
107 | * @param options { SmartBufferOptions } The options to use when creating the SmartBuffer instance.
108 | */
109 | public static fromOptions(options: SmartBufferOptions): SmartBuffer {
110 | return new this(options);
111 | }
112 |
113 | /**
114 | * Type checking function that determines if an object is a SmartBufferOptions object.
115 | */
116 | static isSmartBufferOptions(options: SmartBufferOptions): options is SmartBufferOptions {
117 | const castOptions = options;
118 |
119 | return (
120 | castOptions &&
121 | (castOptions.encoding !== undefined || castOptions.size !== undefined || castOptions.buff !== undefined)
122 | );
123 | }
124 |
125 | // Signed integers
126 |
127 | /**
128 | * Reads an Int8 value from the current read position or an optionally provided offset.
129 | *
130 | * @param offset { Number } The offset to read data from (optional)
131 | * @return { Number }
132 | */
133 | readInt8(offset?: number): number {
134 | return this._readNumberValue(Buffer.prototype.readInt8, 1, offset);
135 | }
136 |
137 | /**
138 | * Reads an Int16BE value from the current read position or an optionally provided offset.
139 | *
140 | * @param offset { Number } The offset to read data from (optional)
141 | * @return { Number }
142 | */
143 | readInt16BE(offset?: number): number {
144 | return this._readNumberValue(Buffer.prototype.readInt16BE, 2, offset);
145 | }
146 |
147 | /**
148 | * Reads an Int16LE value from the current read position or an optionally provided offset.
149 | *
150 | * @param offset { Number } The offset to read data from (optional)
151 | * @return { Number }
152 | */
153 | readInt16LE(offset?: number): number {
154 | return this._readNumberValue(Buffer.prototype.readInt16LE, 2, offset);
155 | }
156 |
157 | /**
158 | * Reads an Int32BE value from the current read position or an optionally provided offset.
159 | *
160 | * @param offset { Number } The offset to read data from (optional)
161 | * @return { Number }
162 | */
163 | readInt32BE(offset?: number): number {
164 | return this._readNumberValue(Buffer.prototype.readInt32BE, 4, offset);
165 | }
166 |
167 | /**
168 | * Reads an Int32LE value from the current read position or an optionally provided offset.
169 | *
170 | * @param offset { Number } The offset to read data from (optional)
171 | * @return { Number }
172 | */
173 | readInt32LE(offset?: number): number {
174 | return this._readNumberValue(Buffer.prototype.readInt32LE, 4, offset);
175 | }
176 |
177 | /**
178 | * Reads a BigInt64BE value from the current read position or an optionally provided offset.
179 | *
180 | * @param offset { Number } The offset to read data from (optional)
181 | * @return { BigInt }
182 | */
183 | readBigInt64BE(offset?: number): bigint {
184 | bigIntAndBufferInt64Check('readBigInt64BE');
185 | return this._readNumberValue(Buffer.prototype.readBigInt64BE, 8, offset);
186 | }
187 |
188 | /**
189 | * Reads a BigInt64LE value from the current read position or an optionally provided offset.
190 | *
191 | * @param offset { Number } The offset to read data from (optional)
192 | * @return { BigInt }
193 | */
194 | readBigInt64LE(offset?: number): bigint {
195 | bigIntAndBufferInt64Check('readBigInt64LE');
196 | return this._readNumberValue(Buffer.prototype.readBigInt64LE, 8, offset);
197 | }
198 |
199 | /**
200 | * Writes an Int8 value to the current write position (or at optional offset).
201 | *
202 | * @param value { Number } The value to write.
203 | * @param offset { Number } The offset to write the value at.
204 | *
205 | * @return this
206 | */
207 | writeInt8(value: number, offset?: number): SmartBuffer {
208 | this._writeNumberValue(Buffer.prototype.writeInt8, 1, value, offset);
209 | return this;
210 | }
211 |
212 | /**
213 | * Inserts an Int8 value at the given offset value.
214 | *
215 | * @param value { Number } The value to insert.
216 | * @param offset { Number } The offset to insert the value at.
217 | *
218 | * @return this
219 | */
220 | insertInt8(value: number, offset: number): SmartBuffer {
221 | return this._insertNumberValue(Buffer.prototype.writeInt8, 1, value, offset);
222 | }
223 |
224 | /**
225 | * Writes an Int16BE value to the current write position (or at optional offset).
226 | *
227 | * @param value { Number } The value to write.
228 | * @param offset { Number } The offset to write the value at.
229 | *
230 | * @return this
231 | */
232 | writeInt16BE(value: number, offset?: number): SmartBuffer {
233 | return this._writeNumberValue(Buffer.prototype.writeInt16BE, 2, value, offset);
234 | }
235 |
236 | /**
237 | * Inserts an Int16BE value at the given offset value.
238 | *
239 | * @param value { Number } The value to insert.
240 | * @param offset { Number } The offset to insert the value at.
241 | *
242 | * @return this
243 | */
244 | insertInt16BE(value: number, offset: number): SmartBuffer {
245 | return this._insertNumberValue(Buffer.prototype.writeInt16BE, 2, value, offset);
246 | }
247 |
248 | /**
249 | * Writes an Int16LE value to the current write position (or at optional offset).
250 | *
251 | * @param value { Number } The value to write.
252 | * @param offset { Number } The offset to write the value at.
253 | *
254 | * @return this
255 | */
256 | writeInt16LE(value: number, offset?: number): SmartBuffer {
257 | return this._writeNumberValue(Buffer.prototype.writeInt16LE, 2, value, offset);
258 | }
259 |
260 | /**
261 | * Inserts an Int16LE value at the given offset value.
262 | *
263 | * @param value { Number } The value to insert.
264 | * @param offset { Number } The offset to insert the value at.
265 | *
266 | * @return this
267 | */
268 | insertInt16LE(value: number, offset: number): SmartBuffer {
269 | return this._insertNumberValue(Buffer.prototype.writeInt16LE, 2, value, offset);
270 | }
271 |
272 | /**
273 | * Writes an Int32BE value to the current write position (or at optional offset).
274 | *
275 | * @param value { Number } The value to write.
276 | * @param offset { Number } The offset to write the value at.
277 | *
278 | * @return this
279 | */
280 | writeInt32BE(value: number, offset?: number): SmartBuffer {
281 | return this._writeNumberValue(Buffer.prototype.writeInt32BE, 4, value, offset);
282 | }
283 |
284 | /**
285 | * Inserts an Int32BE value at the given offset value.
286 | *
287 | * @param value { Number } The value to insert.
288 | * @param offset { Number } The offset to insert the value at.
289 | *
290 | * @return this
291 | */
292 | insertInt32BE(value: number, offset: number): SmartBuffer {
293 | return this._insertNumberValue(Buffer.prototype.writeInt32BE, 4, value, offset);
294 | }
295 |
296 | /**
297 | * Writes an Int32LE value to the current write position (or at optional offset).
298 | *
299 | * @param value { Number } The value to write.
300 | * @param offset { Number } The offset to write the value at.
301 | *
302 | * @return this
303 | */
304 | writeInt32LE(value: number, offset?: number): SmartBuffer {
305 | return this._writeNumberValue(Buffer.prototype.writeInt32LE, 4, value, offset);
306 | }
307 |
308 | /**
309 | * Inserts an Int32LE value at the given offset value.
310 | *
311 | * @param value { Number } The value to insert.
312 | * @param offset { Number } The offset to insert the value at.
313 | *
314 | * @return this
315 | */
316 | insertInt32LE(value: number, offset: number): SmartBuffer {
317 | return this._insertNumberValue(Buffer.prototype.writeInt32LE, 4, value, offset);
318 | }
319 |
320 | /**
321 | * Writes a BigInt64BE value to the current write position (or at optional offset).
322 | *
323 | * @param value { BigInt } The value to write.
324 | * @param offset { Number } The offset to write the value at.
325 | *
326 | * @return this
327 | */
328 | writeBigInt64BE(value: bigint, offset?: number): SmartBuffer {
329 | bigIntAndBufferInt64Check('writeBigInt64BE');
330 | return this._writeNumberValue(Buffer.prototype.writeBigInt64BE, 8, value, offset);
331 | }
332 |
333 | /**
334 | * Inserts a BigInt64BE value at the given offset value.
335 | *
336 | * @param value { BigInt } The value to insert.
337 | * @param offset { Number } The offset to insert the value at.
338 | *
339 | * @return this
340 | */
341 | insertBigInt64BE(value: bigint, offset: number): SmartBuffer {
342 | bigIntAndBufferInt64Check('writeBigInt64BE');
343 | return this._insertNumberValue(Buffer.prototype.writeBigInt64BE, 8, value, offset);
344 | }
345 |
346 | /**
347 | * Writes a BigInt64LE value to the current write position (or at optional offset).
348 | *
349 | * @param value { BigInt } The value to write.
350 | * @param offset { Number } The offset to write the value at.
351 | *
352 | * @return this
353 | */
354 | writeBigInt64LE(value: bigint, offset?: number): SmartBuffer {
355 | bigIntAndBufferInt64Check('writeBigInt64LE');
356 | return this._writeNumberValue(Buffer.prototype.writeBigInt64LE, 8, value, offset);
357 | }
358 |
359 | /**
360 | * Inserts a Int64LE value at the given offset value.
361 | *
362 | * @param value { BigInt } The value to insert.
363 | * @param offset { Number } The offset to insert the value at.
364 | *
365 | * @return this
366 | */
367 | insertBigInt64LE(value: bigint, offset: number): SmartBuffer {
368 | bigIntAndBufferInt64Check('writeBigInt64LE');
369 | return this._insertNumberValue(Buffer.prototype.writeBigInt64LE, 8, value, offset);
370 | }
371 |
372 | // Unsigned Integers
373 |
374 | /**
375 | * Reads an UInt8 value from the current read position or an optionally provided offset.
376 | *
377 | * @param offset { Number } The offset to read data from (optional)
378 | * @return { Number }
379 | */
380 | readUInt8(offset?: number): number {
381 | return this._readNumberValue(Buffer.prototype.readUInt8, 1, offset);
382 | }
383 |
384 | /**
385 | * Reads an UInt16BE value from the current read position or an optionally provided offset.
386 | *
387 | * @param offset { Number } The offset to read data from (optional)
388 | * @return { Number }
389 | */
390 | readUInt16BE(offset?: number): number {
391 | return this._readNumberValue(Buffer.prototype.readUInt16BE, 2, offset);
392 | }
393 |
394 | /**
395 | * Reads an UInt16LE value from the current read position or an optionally provided offset.
396 | *
397 | * @param offset { Number } The offset to read data from (optional)
398 | * @return { Number }
399 | */
400 | readUInt16LE(offset?: number): number {
401 | return this._readNumberValue(Buffer.prototype.readUInt16LE, 2, offset);
402 | }
403 |
404 | /**
405 | * Reads an UInt32BE value from the current read position or an optionally provided offset.
406 | *
407 | * @param offset { Number } The offset to read data from (optional)
408 | * @return { Number }
409 | */
410 | readUInt32BE(offset?: number): number {
411 | return this._readNumberValue(Buffer.prototype.readUInt32BE, 4, offset);
412 | }
413 |
414 | /**
415 | * Reads an UInt32LE value from the current read position or an optionally provided offset.
416 | *
417 | * @param offset { Number } The offset to read data from (optional)
418 | * @return { Number }
419 | */
420 | readUInt32LE(offset?: number): number {
421 | return this._readNumberValue(Buffer.prototype.readUInt32LE, 4, offset);
422 | }
423 |
424 | /**
425 | * Reads a BigUInt64BE value from the current read position or an optionally provided offset.
426 | *
427 | * @param offset { Number } The offset to read data from (optional)
428 | * @return { BigInt }
429 | */
430 | readBigUInt64BE(offset?: number): bigint {
431 | bigIntAndBufferInt64Check('readBigUInt64BE');
432 | return this._readNumberValue(Buffer.prototype.readBigUInt64BE, 8, offset);
433 | }
434 |
435 | /**
436 | * Reads a BigUInt64LE value from the current read position or an optionally provided offset.
437 | *
438 | * @param offset { Number } The offset to read data from (optional)
439 | * @return { BigInt }
440 | */
441 | readBigUInt64LE(offset?: number): bigint {
442 | bigIntAndBufferInt64Check('readBigUInt64LE');
443 | return this._readNumberValue(Buffer.prototype.readBigUInt64LE, 8, offset);
444 | }
445 |
446 | /**
447 | * Writes an UInt8 value to the current write position (or at optional offset).
448 | *
449 | * @param value { Number } The value to write.
450 | * @param offset { Number } The offset to write the value at.
451 | *
452 | * @return this
453 | */
454 | writeUInt8(value: number, offset?: number): SmartBuffer {
455 | return this._writeNumberValue(Buffer.prototype.writeUInt8, 1, value, offset);
456 | }
457 |
458 | /**
459 | * Inserts an UInt8 value at the given offset value.
460 | *
461 | * @param value { Number } The value to insert.
462 | * @param offset { Number } The offset to insert the value at.
463 | *
464 | * @return this
465 | */
466 | insertUInt8(value: number, offset: number): SmartBuffer {
467 | return this._insertNumberValue(Buffer.prototype.writeUInt8, 1, value, offset);
468 | }
469 |
470 | /**
471 | * Writes an UInt16BE value to the current write position (or at optional offset).
472 | *
473 | * @param value { Number } The value to write.
474 | * @param offset { Number } The offset to write the value at.
475 | *
476 | * @return this
477 | */
478 | writeUInt16BE(value: number, offset?: number): SmartBuffer {
479 | return this._writeNumberValue(Buffer.prototype.writeUInt16BE, 2, value, offset);
480 | }
481 |
482 | /**
483 | * Inserts an UInt16BE value at the given offset value.
484 | *
485 | * @param value { Number } The value to insert.
486 | * @param offset { Number } The offset to insert the value at.
487 | *
488 | * @return this
489 | */
490 | insertUInt16BE(value: number, offset: number): SmartBuffer {
491 | return this._insertNumberValue(Buffer.prototype.writeUInt16BE, 2, value, offset);
492 | }
493 |
494 | /**
495 | * Writes an UInt16LE value to the current write position (or at optional offset).
496 | *
497 | * @param value { Number } The value to write.
498 | * @param offset { Number } The offset to write the value at.
499 | *
500 | * @return this
501 | */
502 | writeUInt16LE(value: number, offset?: number): SmartBuffer {
503 | return this._writeNumberValue(Buffer.prototype.writeUInt16LE, 2, value, offset);
504 | }
505 |
506 | /**
507 | * Inserts an UInt16LE value at the given offset value.
508 | *
509 | * @param value { Number } The value to insert.
510 | * @param offset { Number } The offset to insert the value at.
511 | *
512 | * @return this
513 | */
514 | insertUInt16LE(value: number, offset: number): SmartBuffer {
515 | return this._insertNumberValue(Buffer.prototype.writeUInt16LE, 2, value, offset);
516 | }
517 |
518 | /**
519 | * Writes an UInt32BE value to the current write position (or at optional offset).
520 | *
521 | * @param value { Number } The value to write.
522 | * @param offset { Number } The offset to write the value at.
523 | *
524 | * @return this
525 | */
526 | writeUInt32BE(value: number, offset?: number): SmartBuffer {
527 | return this._writeNumberValue(Buffer.prototype.writeUInt32BE, 4, value, offset);
528 | }
529 |
530 | /**
531 | * Inserts an UInt32BE value at the given offset value.
532 | *
533 | * @param value { Number } The value to insert.
534 | * @param offset { Number } The offset to insert the value at.
535 | *
536 | * @return this
537 | */
538 | insertUInt32BE(value: number, offset: number): SmartBuffer {
539 | return this._insertNumberValue(Buffer.prototype.writeUInt32BE, 4, value, offset);
540 | }
541 |
542 | /**
543 | * Writes an UInt32LE value to the current write position (or at optional offset).
544 | *
545 | * @param value { Number } The value to write.
546 | * @param offset { Number } The offset to write the value at.
547 | *
548 | * @return this
549 | */
550 | writeUInt32LE(value: number, offset?: number): SmartBuffer {
551 | return this._writeNumberValue(Buffer.prototype.writeUInt32LE, 4, value, offset);
552 | }
553 |
554 | /**
555 | * Inserts an UInt32LE value at the given offset value.
556 | *
557 | * @param value { Number } The value to insert.
558 | * @param offset { Number } The offset to insert the value at.
559 | *
560 | * @return this
561 | */
562 | insertUInt32LE(value: number, offset: number): SmartBuffer {
563 | return this._insertNumberValue(Buffer.prototype.writeUInt32LE, 4, value, offset);
564 | }
565 |
566 | /**
567 | * Writes a BigUInt64BE value to the current write position (or at optional offset).
568 | *
569 | * @param value { Number } The value to write.
570 | * @param offset { Number } The offset to write the value at.
571 | *
572 | * @return this
573 | */
574 | writeBigUInt64BE(value: bigint, offset?: number): SmartBuffer {
575 | bigIntAndBufferInt64Check('writeBigUInt64BE');
576 | return this._writeNumberValue(Buffer.prototype.writeBigUInt64BE, 8, value, offset);
577 | }
578 |
579 | /**
580 | * Inserts a BigUInt64BE value at the given offset value.
581 | *
582 | * @param value { Number } The value to insert.
583 | * @param offset { Number } The offset to insert the value at.
584 | *
585 | * @return this
586 | */
587 | insertBigUInt64BE(value: bigint, offset: number): SmartBuffer {
588 | bigIntAndBufferInt64Check('writeBigUInt64BE');
589 | return this._insertNumberValue(Buffer.prototype.writeBigUInt64BE, 8, value, offset);
590 | }
591 |
592 | /**
593 | * Writes a BigUInt64LE value to the current write position (or at optional offset).
594 | *
595 | * @param value { Number } The value to write.
596 | * @param offset { Number } The offset to write the value at.
597 | *
598 | * @return this
599 | */
600 | writeBigUInt64LE(value: bigint, offset?: number): SmartBuffer {
601 | bigIntAndBufferInt64Check('writeBigUInt64LE');
602 | return this._writeNumberValue(Buffer.prototype.writeBigUInt64LE, 8, value, offset);
603 | }
604 |
605 | /**
606 | * Inserts a BigUInt64LE value at the given offset value.
607 | *
608 | * @param value { Number } The value to insert.
609 | * @param offset { Number } The offset to insert the value at.
610 | *
611 | * @return this
612 | */
613 | insertBigUInt64LE(value: bigint, offset: number): SmartBuffer {
614 | bigIntAndBufferInt64Check('writeBigUInt64LE');
615 | return this._insertNumberValue(Buffer.prototype.writeBigUInt64LE, 8, value, offset);
616 | }
617 |
618 | // Floating Point
619 |
620 | /**
621 | * Reads an FloatBE value from the current read position or an optionally provided offset.
622 | *
623 | * @param offset { Number } The offset to read data from (optional)
624 | * @return { Number }
625 | */
626 | readFloatBE(offset?: number): number {
627 | return this._readNumberValue(Buffer.prototype.readFloatBE, 4, offset);
628 | }
629 |
630 | /**
631 | * Reads an FloatLE value from the current read position or an optionally provided offset.
632 | *
633 | * @param offset { Number } The offset to read data from (optional)
634 | * @return { Number }
635 | */
636 | readFloatLE(offset?: number): number {
637 | return this._readNumberValue(Buffer.prototype.readFloatLE, 4, offset);
638 | }
639 |
640 | /**
641 | * Writes a FloatBE value to the current write position (or at optional offset).
642 | *
643 | * @param value { Number } The value to write.
644 | * @param offset { Number } The offset to write the value at.
645 | *
646 | * @return this
647 | */
648 | writeFloatBE(value: number, offset?: number): SmartBuffer {
649 | return this._writeNumberValue(Buffer.prototype.writeFloatBE, 4, value, offset);
650 | }
651 |
652 | /**
653 | * Inserts a FloatBE value at the given offset value.
654 | *
655 | * @param value { Number } The value to insert.
656 | * @param offset { Number } The offset to insert the value at.
657 | *
658 | * @return this
659 | */
660 | insertFloatBE(value: number, offset: number): SmartBuffer {
661 | return this._insertNumberValue(Buffer.prototype.writeFloatBE, 4, value, offset);
662 | }
663 |
664 | /**
665 | * Writes a FloatLE value to the current write position (or at optional offset).
666 | *
667 | * @param value { Number } The value to write.
668 | * @param offset { Number } The offset to write the value at.
669 | *
670 | * @return this
671 | */
672 | writeFloatLE(value: number, offset?: number): SmartBuffer {
673 | return this._writeNumberValue(Buffer.prototype.writeFloatLE, 4, value, offset);
674 | }
675 |
676 | /**
677 | * Inserts a FloatLE value at the given offset value.
678 | *
679 | * @param value { Number } The value to insert.
680 | * @param offset { Number } The offset to insert the value at.
681 | *
682 | * @return this
683 | */
684 | insertFloatLE(value: number, offset: number): SmartBuffer {
685 | return this._insertNumberValue(Buffer.prototype.writeFloatLE, 4, value, offset);
686 | }
687 |
688 | // Double Floating Point
689 |
690 | /**
691 | * Reads an DoublEBE value from the current read position or an optionally provided offset.
692 | *
693 | * @param offset { Number } The offset to read data from (optional)
694 | * @return { Number }
695 | */
696 | readDoubleBE(offset?: number): number {
697 | return this._readNumberValue(Buffer.prototype.readDoubleBE, 8, offset);
698 | }
699 |
700 | /**
701 | * Reads an DoubleLE value from the current read position or an optionally provided offset.
702 | *
703 | * @param offset { Number } The offset to read data from (optional)
704 | * @return { Number }
705 | */
706 | readDoubleLE(offset?: number): number {
707 | return this._readNumberValue(Buffer.prototype.readDoubleLE, 8, offset);
708 | }
709 |
710 | /**
711 | * Writes a DoubleBE value to the current write position (or at optional offset).
712 | *
713 | * @param value { Number } The value to write.
714 | * @param offset { Number } The offset to write the value at.
715 | *
716 | * @return this
717 | */
718 | writeDoubleBE(value: number, offset?: number): SmartBuffer {
719 | return this._writeNumberValue(Buffer.prototype.writeDoubleBE, 8, value, offset);
720 | }
721 |
722 | /**
723 | * Inserts a DoubleBE value at the given offset value.
724 | *
725 | * @param value { Number } The value to insert.
726 | * @param offset { Number } The offset to insert the value at.
727 | *
728 | * @return this
729 | */
730 | insertDoubleBE(value: number, offset: number): SmartBuffer {
731 | return this._insertNumberValue(Buffer.prototype.writeDoubleBE, 8, value, offset);
732 | }
733 |
734 | /**
735 | * Writes a DoubleLE value to the current write position (or at optional offset).
736 | *
737 | * @param value { Number } The value to write.
738 | * @param offset { Number } The offset to write the value at.
739 | *
740 | * @return this
741 | */
742 | writeDoubleLE(value: number, offset?: number): SmartBuffer {
743 | return this._writeNumberValue(Buffer.prototype.writeDoubleLE, 8, value, offset);
744 | }
745 |
746 | /**
747 | * Inserts a DoubleLE value at the given offset value.
748 | *
749 | * @param value { Number } The value to insert.
750 | * @param offset { Number } The offset to insert the value at.
751 | *
752 | * @return this
753 | */
754 | insertDoubleLE(value: number, offset: number): SmartBuffer {
755 | return this._insertNumberValue(Buffer.prototype.writeDoubleLE, 8, value, offset);
756 | }
757 |
758 | // Strings
759 |
760 | /**
761 | * Reads a String from the current read position.
762 | *
763 | * @param arg1 { Number | String } The number of bytes to read as a String, or the BufferEncoding to use for
764 | * the string (Defaults to instance level encoding).
765 | * @param encoding { String } The BufferEncoding to use for the string (Defaults to instance level encoding).
766 | *
767 | * @return { String }
768 | */
769 | readString(arg1?: number | BufferEncoding, encoding?: BufferEncoding): string {
770 | let lengthVal;
771 |
772 | // Length provided
773 | if (typeof arg1 === 'number') {
774 | checkLengthValue(arg1);
775 | lengthVal = Math.min(arg1, this.length - this._readOffset);
776 | } else {
777 | encoding = arg1;
778 | lengthVal = this.length - this._readOffset;
779 | }
780 |
781 | // Check encoding
782 | if (typeof encoding !== 'undefined') {
783 | checkEncoding(encoding);
784 | }
785 |
786 | const value = this._buff.slice(this._readOffset, this._readOffset + lengthVal).toString(encoding || this._encoding);
787 |
788 | this._readOffset += lengthVal;
789 | return value;
790 | }
791 |
792 | /**
793 | * Inserts a String
794 | *
795 | * @param value { String } The String value to insert.
796 | * @param offset { Number } The offset to insert the string at.
797 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
798 | *
799 | * @return this
800 | */
801 | insertString(value: string, offset: number, encoding?: BufferEncoding): SmartBuffer {
802 | checkOffsetValue(offset);
803 |
804 | return this._handleString(value, true, offset, encoding);
805 | }
806 |
807 | /**
808 | * Writes a String
809 | *
810 | * @param value { String } The String value to write.
811 | * @param arg2 { Number | String } The offset to write the string at, or the BufferEncoding to use.
812 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
813 | *
814 | * @return this
815 | */
816 | writeString(value: string, arg2?: number | BufferEncoding, encoding?: BufferEncoding): SmartBuffer {
817 | return this._handleString(value, false, arg2, encoding);
818 | }
819 |
820 | /**
821 | * Reads a null-terminated String from the current read position.
822 | *
823 | * @param encoding { String } The BufferEncoding to use for the string (Defaults to instance level encoding).
824 | *
825 | * @return { String }
826 | */
827 | readStringNT(encoding?: BufferEncoding): string {
828 | if (typeof encoding !== 'undefined') {
829 | checkEncoding(encoding);
830 | }
831 |
832 | // Set null character position to the end SmartBuffer instance.
833 | let nullPos = this.length;
834 |
835 | // Find next null character (if one is not found, default from above is used)
836 | for (let i = this._readOffset; i < this.length; i++) {
837 | if (this._buff[i] === 0x00) {
838 | nullPos = i;
839 | break;
840 | }
841 | }
842 |
843 | // Read string value
844 | const value = this._buff.slice(this._readOffset, nullPos);
845 |
846 | // Increment internal Buffer read offset
847 | this._readOffset = nullPos + 1;
848 |
849 | return value.toString(encoding || this._encoding);
850 | }
851 |
852 | /**
853 | * Inserts a null-terminated String.
854 | *
855 | * @param value { String } The String value to write.
856 | * @param arg2 { Number | String } The offset to write the string to, or the BufferEncoding to use.
857 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
858 | *
859 | * @return this
860 | */
861 | insertStringNT(value: string, offset: number, encoding?: BufferEncoding): SmartBuffer {
862 | checkOffsetValue(offset);
863 |
864 | // Write Values
865 | this.insertString(value, offset, encoding);
866 | this.insertUInt8(0x00, offset + value.length);
867 | return this;
868 | }
869 |
870 | /**
871 | * Writes a null-terminated String.
872 | *
873 | * @param value { String } The String value to write.
874 | * @param arg2 { Number | String } The offset to write the string to, or the BufferEncoding to use.
875 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
876 | *
877 | * @return this
878 | */
879 | writeStringNT(value: string, arg2?: number | BufferEncoding, encoding?: BufferEncoding): SmartBuffer {
880 | // Write Values
881 | this.writeString(value, arg2, encoding);
882 | this.writeUInt8(0x00, typeof arg2 === 'number' ? arg2 + value.length : this.writeOffset);
883 | return this;
884 | }
885 |
886 | // Buffers
887 |
888 | /**
889 | * Reads a Buffer from the internal read position.
890 | *
891 | * @param length { Number } The length of data to read as a Buffer.
892 | *
893 | * @return { Buffer }
894 | */
895 | readBuffer(length?: number): Buffer {
896 | if (typeof length !== 'undefined') {
897 | checkLengthValue(length);
898 | }
899 |
900 | const lengthVal = typeof length === 'number' ? length : this.length;
901 | const endPoint = Math.min(this.length, this._readOffset + lengthVal);
902 |
903 | // Read buffer value
904 | const value = this._buff.slice(this._readOffset, endPoint);
905 |
906 | // Increment internal Buffer read offset
907 | this._readOffset = endPoint;
908 | return value;
909 | }
910 |
911 | /**
912 | * Writes a Buffer to the current write position.
913 | *
914 | * @param value { Buffer } The Buffer to write.
915 | * @param offset { Number } The offset to write the Buffer to.
916 | *
917 | * @return this
918 | */
919 | insertBuffer(value: Buffer, offset: number): SmartBuffer {
920 | checkOffsetValue(offset);
921 |
922 | return this._handleBuffer(value, true, offset);
923 | }
924 |
925 | /**
926 | * Writes a Buffer to the current write position.
927 | *
928 | * @param value { Buffer } The Buffer to write.
929 | * @param offset { Number } The offset to write the Buffer to.
930 | *
931 | * @return this
932 | */
933 | writeBuffer(value: Buffer, offset?: number): SmartBuffer {
934 | return this._handleBuffer(value, false, offset);
935 | }
936 |
937 | /**
938 | * Reads a null-terminated Buffer from the current read poisiton.
939 | *
940 | * @return { Buffer }
941 | */
942 | readBufferNT(): Buffer {
943 | // Set null character position to the end SmartBuffer instance.
944 | let nullPos = this.length;
945 |
946 | // Find next null character (if one is not found, default from above is used)
947 | for (let i = this._readOffset; i < this.length; i++) {
948 | if (this._buff[i] === 0x00) {
949 | nullPos = i;
950 | break;
951 | }
952 | }
953 |
954 | // Read value
955 | const value = this._buff.slice(this._readOffset, nullPos);
956 |
957 | // Increment internal Buffer read offset
958 | this._readOffset = nullPos + 1;
959 | return value;
960 | }
961 |
962 | /**
963 | * Inserts a null-terminated Buffer.
964 | *
965 | * @param value { Buffer } The Buffer to write.
966 | * @param offset { Number } The offset to write the Buffer to.
967 | *
968 | * @return this
969 | */
970 | insertBufferNT(value: Buffer, offset: number): SmartBuffer {
971 | checkOffsetValue(offset);
972 |
973 | // Write Values
974 | this.insertBuffer(value, offset);
975 | this.insertUInt8(0x00, offset + value.length);
976 |
977 | return this;
978 | }
979 |
980 | /**
981 | * Writes a null-terminated Buffer.
982 | *
983 | * @param value { Buffer } The Buffer to write.
984 | * @param offset { Number } The offset to write the Buffer to.
985 | *
986 | * @return this
987 | */
988 | writeBufferNT(value: Buffer, offset?: number): SmartBuffer {
989 | // Checks for valid numberic value;
990 | if (typeof offset !== 'undefined') {
991 | checkOffsetValue(offset);
992 | }
993 |
994 | // Write Values
995 | this.writeBuffer(value, offset);
996 | this.writeUInt8(0x00, typeof offset === 'number' ? offset + value.length : this._writeOffset);
997 |
998 | return this;
999 | }
1000 |
1001 | /**
1002 | * Clears the SmartBuffer instance to its original empty state.
1003 | */
1004 | clear(): SmartBuffer {
1005 | this._writeOffset = 0;
1006 | this._readOffset = 0;
1007 | this.length = 0;
1008 | return this;
1009 | }
1010 |
1011 | /**
1012 | * Gets the remaining data left to be read from the SmartBuffer instance.
1013 | *
1014 | * @return { Number }
1015 | */
1016 | remaining(): number {
1017 | return this.length - this._readOffset;
1018 | }
1019 |
1020 | /**
1021 | * Gets the current read offset value of the SmartBuffer instance.
1022 | *
1023 | * @return { Number }
1024 | */
1025 | get readOffset(): number {
1026 | return this._readOffset;
1027 | }
1028 |
1029 | /**
1030 | * Sets the read offset value of the SmartBuffer instance.
1031 | *
1032 | * @param offset { Number } - The offset value to set.
1033 | */
1034 | set readOffset(offset: number) {
1035 | checkOffsetValue(offset);
1036 |
1037 | // Check for bounds.
1038 | checkTargetOffset(offset, this);
1039 |
1040 | this._readOffset = offset;
1041 | }
1042 |
1043 | /**
1044 | * Gets the current write offset value of the SmartBuffer instance.
1045 | *
1046 | * @return { Number }
1047 | */
1048 | get writeOffset(): number {
1049 | return this._writeOffset;
1050 | }
1051 |
1052 | /**
1053 | * Sets the write offset value of the SmartBuffer instance.
1054 | *
1055 | * @param offset { Number } - The offset value to set.
1056 | */
1057 | set writeOffset(offset: number) {
1058 | checkOffsetValue(offset);
1059 |
1060 | // Check for bounds.
1061 | checkTargetOffset(offset, this);
1062 |
1063 | this._writeOffset = offset;
1064 | }
1065 |
1066 | /**
1067 | * Gets the currently set string encoding of the SmartBuffer instance.
1068 | *
1069 | * @return { BufferEncoding } The string Buffer encoding currently set.
1070 | */
1071 | get encoding() {
1072 | return this._encoding;
1073 | }
1074 |
1075 | /**
1076 | * Sets the string encoding of the SmartBuffer instance.
1077 | *
1078 | * @param encoding { BufferEncoding } The string Buffer encoding to set.
1079 | */
1080 | set encoding(encoding: BufferEncoding) {
1081 | checkEncoding(encoding);
1082 |
1083 | this._encoding = encoding;
1084 | }
1085 |
1086 | /**
1087 | * Gets the underlying internal Buffer. (This includes unmanaged data in the Buffer)
1088 | *
1089 | * @return { Buffer } The Buffer value.
1090 | */
1091 | get internalBuffer(): Buffer {
1092 | return this._buff;
1093 | }
1094 |
1095 | /**
1096 | * Gets the value of the internal managed Buffer (Includes managed data only)
1097 | *
1098 | * @param { Buffer }
1099 | */
1100 | toBuffer(): Buffer {
1101 | return this._buff.slice(0, this.length);
1102 | }
1103 |
1104 | /**
1105 | * Gets the String value of the internal managed Buffer
1106 | *
1107 | * @param encoding { String } The BufferEncoding to display the Buffer as (defaults to instance level encoding).
1108 | */
1109 | toString(encoding?: BufferEncoding): string {
1110 | const encodingVal = typeof encoding === 'string' ? encoding : this._encoding;
1111 |
1112 | // Check for invalid encoding.
1113 | checkEncoding(encodingVal);
1114 |
1115 | return this._buff.toString(encodingVal, 0, this.length);
1116 | }
1117 |
1118 | /**
1119 | * Destroys the SmartBuffer instance.
1120 | */
1121 | destroy(): SmartBuffer {
1122 | this.clear();
1123 | return this;
1124 | }
1125 |
1126 | /**
1127 | * Handles inserting and writing strings.
1128 | *
1129 | * @param value { String } The String value to insert.
1130 | * @param isInsert { Boolean } True if inserting a string, false if writing.
1131 | * @param arg2 { Number | String } The offset to insert the string at, or the BufferEncoding to use.
1132 | * @param encoding { String } The BufferEncoding to use for writing strings (defaults to instance encoding).
1133 | */
1134 | private _handleString(
1135 | value: string,
1136 | isInsert: boolean,
1137 | arg3?: number | BufferEncoding,
1138 | encoding?: BufferEncoding
1139 | ): SmartBuffer {
1140 | let offsetVal = this._writeOffset;
1141 | let encodingVal = this._encoding;
1142 |
1143 | // Check for offset
1144 | if (typeof arg3 === 'number') {
1145 | offsetVal = arg3;
1146 | // Check for encoding
1147 | } else if (typeof arg3 === 'string') {
1148 | checkEncoding(arg3);
1149 | encodingVal = arg3;
1150 | }
1151 |
1152 | // Check for encoding (third param)
1153 | if (typeof encoding === 'string') {
1154 | checkEncoding(encoding);
1155 | encodingVal = encoding;
1156 | }
1157 |
1158 | // Calculate bytelength of string.
1159 | const byteLength = Buffer.byteLength(value, encodingVal);
1160 |
1161 | // Ensure there is enough internal Buffer capacity.
1162 | if (isInsert) {
1163 | this.ensureInsertable(byteLength, offsetVal);
1164 | } else {
1165 | this._ensureWriteable(byteLength, offsetVal);
1166 | }
1167 |
1168 | // Write value
1169 | this._buff.write(value, offsetVal, byteLength, encodingVal);
1170 |
1171 | // Increment internal Buffer write offset;
1172 | if (isInsert) {
1173 | this._writeOffset += byteLength;
1174 | } else {
1175 | // If an offset was given, check to see if we wrote beyond the current writeOffset.
1176 | if (typeof arg3 === 'number') {
1177 | this._writeOffset = Math.max(this._writeOffset, offsetVal + byteLength);
1178 | } else {
1179 | // If no offset was given, we wrote to the end of the SmartBuffer so increment writeOffset.
1180 | this._writeOffset += byteLength;
1181 | }
1182 | }
1183 |
1184 | return this;
1185 | }
1186 |
1187 | /**
1188 | * Handles writing or insert of a Buffer.
1189 | *
1190 | * @param value { Buffer } The Buffer to write.
1191 | * @param offset { Number } The offset to write the Buffer to.
1192 | */
1193 | private _handleBuffer(value: Buffer, isInsert: boolean, offset?: number): SmartBuffer {
1194 | const offsetVal = typeof offset === 'number' ? offset : this._writeOffset;
1195 |
1196 | // Ensure there is enough internal Buffer capacity.
1197 | if (isInsert) {
1198 | this.ensureInsertable(value.length, offsetVal);
1199 | } else {
1200 | this._ensureWriteable(value.length, offsetVal);
1201 | }
1202 |
1203 | // Write buffer value
1204 | value.copy(this._buff, offsetVal);
1205 |
1206 | // Increment internal Buffer write offset;
1207 | if (isInsert) {
1208 | this._writeOffset += value.length;
1209 | } else {
1210 | // If an offset was given, check to see if we wrote beyond the current writeOffset.
1211 | if (typeof offset === 'number') {
1212 | this._writeOffset = Math.max(this._writeOffset, offsetVal + value.length);
1213 | } else {
1214 | // If no offset was given, we wrote to the end of the SmartBuffer so increment writeOffset.
1215 | this._writeOffset += value.length;
1216 | }
1217 | }
1218 |
1219 | return this;
1220 | }
1221 |
1222 | /**
1223 | * Ensures that the internal Buffer is large enough to read data.
1224 | *
1225 | * @param length { Number } The length of the data that needs to be read.
1226 | * @param offset { Number } The offset of the data that needs to be read.
1227 | */
1228 | private ensureReadable(length: number, offset?: number) {
1229 | // Offset value defaults to managed read offset.
1230 | let offsetVal = this._readOffset;
1231 |
1232 | // If an offset was provided, use it.
1233 | if (typeof offset !== 'undefined') {
1234 | // Checks for valid numberic value;
1235 | checkOffsetValue(offset);
1236 |
1237 | // Overide with custom offset.
1238 | offsetVal = offset;
1239 | }
1240 |
1241 | // Checks if offset is below zero, or the offset+length offset is beyond the total length of the managed data.
1242 | if (offsetVal < 0 || offsetVal + length > this.length) {
1243 | throw new Error(ERRORS.INVALID_READ_BEYOND_BOUNDS);
1244 | }
1245 | }
1246 |
1247 | /**
1248 | * Ensures that the internal Buffer is large enough to insert data.
1249 | *
1250 | * @param dataLength { Number } The length of the data that needs to be written.
1251 | * @param offset { Number } The offset of the data to be written.
1252 | */
1253 | private ensureInsertable(dataLength: number, offset: number) {
1254 | // Checks for valid numberic value;
1255 | checkOffsetValue(offset);
1256 |
1257 | // Ensure there is enough internal Buffer capacity.
1258 | this._ensureCapacity(this.length + dataLength);
1259 |
1260 | // If an offset was provided and its not the very end of the buffer, copy data into appropriate location in regards to the offset.
1261 | if (offset < this.length) {
1262 | this._buff.copy(this._buff, offset + dataLength, offset, this._buff.length);
1263 | }
1264 |
1265 | // Adjust tracked smart buffer length
1266 | if (offset + dataLength > this.length) {
1267 | this.length = offset + dataLength;
1268 | } else {
1269 | this.length += dataLength;
1270 | }
1271 | }
1272 |
1273 | /**
1274 | * Ensures that the internal Buffer is large enough to write data.
1275 | *
1276 | * @param dataLength { Number } The length of the data that needs to be written.
1277 | * @param offset { Number } The offset of the data to be written (defaults to writeOffset).
1278 | */
1279 | private _ensureWriteable(dataLength: number, offset?: number) {
1280 | const offsetVal = typeof offset === 'number' ? offset : this._writeOffset;
1281 |
1282 | // Ensure enough capacity to write data.
1283 | this._ensureCapacity(offsetVal + dataLength);
1284 |
1285 | // Adjust SmartBuffer length (if offset + length is larger than managed length, adjust length)
1286 | if (offsetVal + dataLength > this.length) {
1287 | this.length = offsetVal + dataLength;
1288 | }
1289 | }
1290 |
1291 | /**
1292 | * Ensures that the internal Buffer is large enough to write at least the given amount of data.
1293 | *
1294 | * @param minLength { Number } The minimum length of the data needs to be written.
1295 | */
1296 | private _ensureCapacity(minLength: number) {
1297 | const oldLength = this._buff.length;
1298 |
1299 | if (minLength > oldLength) {
1300 | let data = this._buff;
1301 | let newLength = (oldLength * 3) / 2 + 1;
1302 | if (newLength < minLength) {
1303 | newLength = minLength;
1304 | }
1305 | this._buff = Buffer.allocUnsafe(newLength);
1306 |
1307 | data.copy(this._buff, 0, 0, oldLength);
1308 | }
1309 | }
1310 |
1311 | /**
1312 | * Reads a numeric number value using the provided function.
1313 | *
1314 | * @typeparam T { number | bigint } The type of the value to be read
1315 | *
1316 | * @param func { Function(offset: number) => number } The function to read data on the internal Buffer with.
1317 | * @param byteSize { Number } The number of bytes read.
1318 | * @param offset { Number } The offset to read from (optional). When this is not provided, the managed readOffset is used instead.
1319 | *
1320 | * @returns { T } the number value
1321 | */
1322 | private _readNumberValue(func: (offset: number) => T, byteSize: number, offset?: number): T {
1323 | this.ensureReadable(byteSize, offset);
1324 |
1325 | // Call Buffer.readXXXX();
1326 | const value = func.call(this._buff, typeof offset === 'number' ? offset : this._readOffset);
1327 |
1328 | // Adjust internal read offset if an optional read offset was not provided.
1329 | if (typeof offset === 'undefined') {
1330 | this._readOffset += byteSize;
1331 | }
1332 |
1333 | return value;
1334 | }
1335 |
1336 | /**
1337 | * Inserts a numeric number value based on the given offset and value.
1338 | *
1339 | * @typeparam T { number | bigint } The type of the value to be written
1340 | *
1341 | * @param func { Function(offset: T, offset?) => number} The function to write data on the internal Buffer with.
1342 | * @param byteSize { Number } The number of bytes written.
1343 | * @param value { T } The number value to write.
1344 | * @param offset { Number } the offset to write the number at (REQUIRED).
1345 | *
1346 | * @returns SmartBuffer this buffer
1347 | */
1348 | private _insertNumberValue(
1349 | func: (value: T, offset?: number) => number,
1350 | byteSize: number,
1351 | value: T,
1352 | offset: number
1353 | ): SmartBuffer {
1354 | // Check for invalid offset values.
1355 | checkOffsetValue(offset);
1356 |
1357 | // Ensure there is enough internal Buffer capacity. (raw offset is passed)
1358 | this.ensureInsertable(byteSize, offset);
1359 |
1360 | // Call buffer.writeXXXX();
1361 | func.call(this._buff, value, offset);
1362 |
1363 | // Adjusts internally managed write offset.
1364 | this._writeOffset += byteSize;
1365 | return this;
1366 | }
1367 |
1368 | /**
1369 | * Writes a numeric number value based on the given offset and value.
1370 | *
1371 | * @typeparam T { number | bigint } The type of the value to be written
1372 | *
1373 | * @param func { Function(offset: T, offset?) => number} The function to write data on the internal Buffer with.
1374 | * @param byteSize { Number } The number of bytes written.
1375 | * @param value { T } The number value to write.
1376 | * @param offset { Number } the offset to write the number at (REQUIRED).
1377 | *
1378 | * @returns SmartBuffer this buffer
1379 | */
1380 | private _writeNumberValue(
1381 | func: (value: T, offset?: number) => number,
1382 | byteSize: number,
1383 | value: T,
1384 | offset?: number
1385 | ): SmartBuffer {
1386 | // If an offset was provided, validate it.
1387 | if (typeof offset === 'number') {
1388 | // Check if we're writing beyond the bounds of the managed data.
1389 | if (offset < 0) {
1390 | throw new Error(ERRORS.INVALID_WRITE_BEYOND_BOUNDS);
1391 | }
1392 |
1393 | checkOffsetValue(offset);
1394 | }
1395 |
1396 | // Default to writeOffset if no offset value was given.
1397 | const offsetVal = typeof offset === 'number' ? offset : this._writeOffset;
1398 |
1399 | // Ensure there is enough internal Buffer capacity. (raw offset is passed)
1400 | this._ensureWriteable(byteSize, offsetVal);
1401 |
1402 | func.call(this._buff, value, offsetVal);
1403 |
1404 | // If an offset was given, check to see if we wrote beyond the current writeOffset.
1405 | if (typeof offset === 'number') {
1406 | this._writeOffset = Math.max(this._writeOffset, offsetVal + byteSize);
1407 | } else {
1408 | // If no numeric offset was given, we wrote to the end of the SmartBuffer so increment writeOffset.
1409 | this._writeOffset += byteSize;
1410 | }
1411 |
1412 | return this;
1413 | }
1414 | }
1415 |
1416 | export { SmartBufferOptions, SmartBuffer };
1417 |
--------------------------------------------------------------------------------