binutils64 0.1.4 → 0.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +56 -0
- package/LICENSE +21 -0
- package/README.md +19 -6
- package/binutils.d.ts +83 -0
- package/binutils.js +16 -16
- package/package.json +54 -17
- package/.claude/agents/binutils-reviewer.md +0 -58
- package/.claude/settings.local.json +0 -21
- package/.claude/skills/add-binary-type/SKILL.md +0 -93
- package/.claude/skills/test-binutils/SKILL.md +0 -91
- package/.github/workflows/test.yml +0 -22
- package/CLAUDE.md +0 -54
- package/test/edge-cases.test.js +0 -76
- package/test/reader.test.js +0 -106
- package/test/readme-examples.test.js +0 -33
- package/test/roundtrip.test.js +0 -120
- package/test/writer.test.js +0 -115
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project are documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [0.2.0] - 2026-07-02
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
|
|
12
|
+
- MIT license (`LICENSE` file and `license` field in `package.json`).
|
|
13
|
+
- Bundled TypeScript type definitions (`binutils.d.ts`).
|
|
14
|
+
- `CHANGELOG.md` (this file).
|
|
15
|
+
- ESLint configuration that locks `binutils.js` to ES5 syntax, an `npm run lint`
|
|
16
|
+
script, and a CI lint job.
|
|
17
|
+
- GitHub Actions publish workflow that releases to npm with provenance.
|
|
18
|
+
- Package metadata: `files` whitelist, `exports` map, `keywords`, `bugs`, `homepage`.
|
|
19
|
+
- `.editorconfig`.
|
|
20
|
+
|
|
21
|
+
### Changed
|
|
22
|
+
|
|
23
|
+
- Raised the declared Node.js floor (`engines.node`) from `>=0.12` to `>=12`,
|
|
24
|
+
matching the actual requirement of the 64-bit `BigInt` methods.
|
|
25
|
+
- Replaced the deprecated `new Buffer(...)` constructor with
|
|
26
|
+
`Buffer.alloc()`/`Buffer.from()`; the `DEP0005` deprecation warning is gone.
|
|
27
|
+
No behavior change.
|
|
28
|
+
- `repository.url` now uses `git+https://` instead of the retired `git://` protocol.
|
|
29
|
+
|
|
30
|
+
## [0.1.4] - 2026-05-28
|
|
31
|
+
|
|
32
|
+
### Added
|
|
33
|
+
|
|
34
|
+
- Test suite using the built-in `node:test` runner: reader, writer, round-trip,
|
|
35
|
+
edge-case and README-example coverage.
|
|
36
|
+
- GitHub Actions CI running the tests on Node.js 20, 22 and 24.
|
|
37
|
+
|
|
38
|
+
## [0.1.3] - 2024-11-01
|
|
39
|
+
|
|
40
|
+
### Fixed
|
|
41
|
+
|
|
42
|
+
- `ReadInt64` returning incorrect values.
|
|
43
|
+
|
|
44
|
+
## [0.1.2] - 2018-06-15
|
|
45
|
+
|
|
46
|
+
### Changed
|
|
47
|
+
|
|
48
|
+
- README updates.
|
|
49
|
+
|
|
50
|
+
## [0.1.1] - 2018-06-15
|
|
51
|
+
|
|
52
|
+
### Added
|
|
53
|
+
|
|
54
|
+
- First release of `binutils64`: `BinaryReader` and `BinaryWriter` with selectable
|
|
55
|
+
endianness, signed/unsigned 8/16/32-bit integers, floats, doubles, raw byte runs,
|
|
56
|
+
and 64-bit integers via `BigInt`.
|
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2013-2026 Mihail Shumilov
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, 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,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
CHANGED
|
@@ -3,7 +3,12 @@
|
|
|
3
3
|
> A .NET-style `BinaryReader` and `BinaryWriter` for Node.js, with selectable endianness.
|
|
4
4
|
|
|
5
5
|
[](https://www.npmjs.com/package/binutils64)
|
|
6
|
+
[](https://www.npmjs.com/package/binutils64)
|
|
6
7
|
[](https://github.com/mihailShumilov/node-binutils/actions/workflows/test.yml)
|
|
8
|
+
[](https://www.npmjs.com/package/binutils64)
|
|
9
|
+
[](https://github.com/mihailShumilov/node-binutils/blob/master/LICENSE)
|
|
10
|
+
[](https://www.npmjs.com/package/binutils64)
|
|
11
|
+
[](https://packagephobia.com/result?p=binutils64)
|
|
7
12
|
|
|
8
13
|
`binutils64` provides two small classes — `BinaryReader` and `BinaryWriter` — that
|
|
9
14
|
make it easy to parse and produce binary data sequentially, with an API modelled on
|
|
@@ -24,6 +29,7 @@ doubles, and raw byte runs.
|
|
|
24
29
|
- [Requirements and compatibility](#requirements-and-compatibility)
|
|
25
30
|
- [Testing](#testing)
|
|
26
31
|
- [Contributing](#contributing)
|
|
32
|
+
- [License](#license)
|
|
27
33
|
|
|
28
34
|
## Features
|
|
29
35
|
|
|
@@ -32,6 +38,7 @@ doubles, and raw byte runs.
|
|
|
32
38
|
- 64-bit integers via JavaScript `BigInt`.
|
|
33
39
|
- Signed and unsigned integers, IEEE-754 `float` and `double`, and raw byte runs.
|
|
34
40
|
- Zero runtime dependencies.
|
|
41
|
+
- Bundled TypeScript type definitions.
|
|
35
42
|
|
|
36
43
|
## Installation
|
|
37
44
|
|
|
@@ -232,11 +239,11 @@ console.log(record, 'read', reader.Position, 'of', reader.Length, 'bytes');
|
|
|
232
239
|
|
|
233
240
|
## Requirements and compatibility
|
|
234
241
|
|
|
235
|
-
- **Node.js
|
|
236
|
-
|
|
237
|
-
`
|
|
238
|
-
-
|
|
239
|
-
|
|
242
|
+
- **Node.js 12 or newer** (declared in `package.json` `engines`). The 64-bit methods
|
|
243
|
+
(`ReadUInt64`, `ReadInt64`, `WriteUInt64`, `WriteInt64`) rely on `BigInt` and the
|
|
244
|
+
`Buffer` big-integer methods introduced in Node.js 12.
|
|
245
|
+
- **TypeScript typings are bundled** (`binutils.d.ts`) — no separate `@types`
|
|
246
|
+
package is needed.
|
|
240
247
|
- Running the test suite uses the built-in `node:test` runner, which requires
|
|
241
248
|
**Node.js 18 or newer**.
|
|
242
249
|
|
|
@@ -253,4 +260,10 @@ the documented examples. Continuous integration runs it on Node.js 20, 22 and 24
|
|
|
253
260
|
## Contributing
|
|
254
261
|
|
|
255
262
|
Issues and pull requests are welcome. Please add or update tests for any behavioral
|
|
256
|
-
change and make sure `npm test`
|
|
263
|
+
change, note it in `CHANGELOG.md` under *Unreleased*, and make sure `npm test` and
|
|
264
|
+
`npm run lint` pass before opening a pull request (run `npm ci` once to install the
|
|
265
|
+
linter).
|
|
266
|
+
|
|
267
|
+
## License
|
|
268
|
+
|
|
269
|
+
[MIT](LICENSE)
|
package/binutils.d.ts
ADDED
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
|
|
3
|
+
export = binutils;
|
|
4
|
+
|
|
5
|
+
declare namespace binutils {
|
|
6
|
+
type Endianness = 'big' | 'little';
|
|
7
|
+
|
|
8
|
+
class BinaryReader {
|
|
9
|
+
/**
|
|
10
|
+
* Wraps a copy of the input data and consumes it from the front as you read.
|
|
11
|
+
* A `Buffer` input is copied, so the source is never mutated.
|
|
12
|
+
* Throws if `input` is not a `Buffer`, array, or string.
|
|
13
|
+
*/
|
|
14
|
+
constructor(
|
|
15
|
+
input: Buffer | ReadonlyArray<number> | string,
|
|
16
|
+
endianness?: Endianness,
|
|
17
|
+
encoding?: BufferEncoding
|
|
18
|
+
);
|
|
19
|
+
|
|
20
|
+
/** The remaining unread bytes. Shrinks as `Read*` methods consume it. */
|
|
21
|
+
ByteBuffer: Buffer;
|
|
22
|
+
/** Byte order used by all multi-byte reads. */
|
|
23
|
+
Endianness: Endianness;
|
|
24
|
+
/** Encoding used to turn a string input into bytes. */
|
|
25
|
+
Encoding: BufferEncoding;
|
|
26
|
+
/** Length of the original input in bytes. Never changes as you read. */
|
|
27
|
+
Length: number;
|
|
28
|
+
/** Number of bytes consumed so far. */
|
|
29
|
+
Position: number;
|
|
30
|
+
|
|
31
|
+
/** Reads 1 byte. Returns 0 (without advancing) if no bytes remain. */
|
|
32
|
+
ReadUInt8(): number;
|
|
33
|
+
/** Reads 2 bytes. Returns 0 (without advancing) if fewer than 2 bytes remain. */
|
|
34
|
+
ReadUInt16(): number;
|
|
35
|
+
/** Reads 4 bytes. Returns 0 (without advancing) if fewer than 4 bytes remain. */
|
|
36
|
+
ReadUInt32(): number;
|
|
37
|
+
/** Reads 8 bytes as an unsigned BigInt. Returns the number 0 (without advancing) if fewer than 8 bytes remain. */
|
|
38
|
+
ReadUInt64(): bigint | 0;
|
|
39
|
+
/** Reads 1 byte, signed. Returns 0 (without advancing) if no bytes remain. */
|
|
40
|
+
ReadInt8(): number;
|
|
41
|
+
/** Reads 2 bytes, signed. Returns 0 (without advancing) if fewer than 2 bytes remain. */
|
|
42
|
+
ReadInt16(): number;
|
|
43
|
+
/** Reads 4 bytes, signed. Returns 0 (without advancing) if fewer than 4 bytes remain. */
|
|
44
|
+
ReadInt32(): number;
|
|
45
|
+
/** Reads 8 bytes as a signed BigInt. Returns the number 0 (without advancing) if fewer than 8 bytes remain. */
|
|
46
|
+
ReadInt64(): bigint | 0;
|
|
47
|
+
/** Reads 4 bytes as an IEEE-754 single. Returns 0 (without advancing) if fewer than 4 bytes remain. */
|
|
48
|
+
ReadFloat(): number;
|
|
49
|
+
/** Reads 8 bytes as an IEEE-754 double. Returns 0 (without advancing) if fewer than 8 bytes remain. */
|
|
50
|
+
ReadDouble(): number;
|
|
51
|
+
/** Copies `count` bytes into a new Buffer. Returns an empty Buffer (without advancing) if fewer than `count` bytes remain. */
|
|
52
|
+
ReadBytes(count: number): Buffer;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
class BinaryWriter {
|
|
56
|
+
/** Accumulates bytes in an internal buffer that grows with every write. */
|
|
57
|
+
constructor(endianness?: Endianness, encoding?: BufferEncoding);
|
|
58
|
+
|
|
59
|
+
/** All bytes written so far. */
|
|
60
|
+
ByteBuffer: Buffer;
|
|
61
|
+
/** Byte order used by all multi-byte writes. */
|
|
62
|
+
Endianness: Endianness;
|
|
63
|
+
/** Stored on the instance; reserved. */
|
|
64
|
+
Encoding: BufferEncoding;
|
|
65
|
+
/** The current length of `ByteBuffer`. */
|
|
66
|
+
Length: number;
|
|
67
|
+
|
|
68
|
+
WriteUInt8(value: number): void;
|
|
69
|
+
WriteUInt16(value: number): void;
|
|
70
|
+
WriteUInt32(value: number): void;
|
|
71
|
+
/** Accepts a number or BigInt; the value is coerced with `BigInt(value)`. */
|
|
72
|
+
WriteUInt64(value: number | bigint): void;
|
|
73
|
+
WriteInt8(value: number): void;
|
|
74
|
+
WriteInt16(value: number): void;
|
|
75
|
+
WriteInt32(value: number): void;
|
|
76
|
+
/** Accepts a number or BigInt; the value is coerced with `BigInt(value)`. */
|
|
77
|
+
WriteInt64(value: number | bigint): void;
|
|
78
|
+
WriteFloat(value: number): void;
|
|
79
|
+
WriteDouble(value: number): void;
|
|
80
|
+
/** Strings are written as one byte per character code. Throws on any other input type. */
|
|
81
|
+
WriteBytes(value: Buffer | ReadonlyArray<number> | string): void;
|
|
82
|
+
}
|
|
83
|
+
}
|
package/binutils.js
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
var BinaryReader = function(p_InputBuffer, p_Endianness, p_Encoding) {
|
|
2
2
|
// Instantiate the buffer (if needed)
|
|
3
3
|
if (p_InputBuffer instanceof Buffer) {
|
|
4
|
-
this.ByteBuffer =
|
|
4
|
+
this.ByteBuffer = Buffer.from(p_InputBuffer);
|
|
5
5
|
} else if (p_InputBuffer instanceof Array || typeof p_InputBuffer == 'string') {
|
|
6
|
-
this.ByteBuffer =
|
|
6
|
+
this.ByteBuffer = Buffer.from(p_InputBuffer, p_Encoding);
|
|
7
7
|
} else {
|
|
8
8
|
throw new Error('Invalid buffer input for BinaryReader (' + typeof p_InputBuffer + ')');
|
|
9
9
|
}
|
|
@@ -134,10 +134,10 @@ BinaryReader.prototype = {
|
|
|
134
134
|
|
|
135
135
|
ReadBytes: function(p_Count) {
|
|
136
136
|
if (p_Count > this.ByteBuffer.length) {
|
|
137
|
-
return
|
|
137
|
+
return Buffer.alloc(0);
|
|
138
138
|
}
|
|
139
139
|
|
|
140
|
-
var s_Val =
|
|
140
|
+
var s_Val = Buffer.alloc(p_Count);
|
|
141
141
|
this.ByteBuffer.copy(s_Val, 0, 0, p_Count);
|
|
142
142
|
|
|
143
143
|
this.ByteBuffer = this.ByteBuffer.slice(p_Count);
|
|
@@ -151,7 +151,7 @@ BinaryReader.prototype = {
|
|
|
151
151
|
|
|
152
152
|
var BinaryWriter = function(p_Endianness, p_Encoding) {
|
|
153
153
|
// Instantiate the buffer
|
|
154
|
-
this.ByteBuffer =
|
|
154
|
+
this.ByteBuffer = Buffer.alloc(0);
|
|
155
155
|
|
|
156
156
|
// Set the endianness
|
|
157
157
|
this.Endianness = p_Endianness || 'big';
|
|
@@ -165,14 +165,14 @@ var BinaryWriter = function(p_Endianness, p_Encoding) {
|
|
|
165
165
|
|
|
166
166
|
BinaryWriter.prototype = {
|
|
167
167
|
WriteUInt8: function(p_Value) {
|
|
168
|
-
var s_TempBuffer =
|
|
168
|
+
var s_TempBuffer = Buffer.alloc(1);
|
|
169
169
|
s_TempBuffer.writeUInt8(p_Value, 0);
|
|
170
170
|
this.Length += 1;
|
|
171
171
|
this.ByteBuffer = Buffer.concat([this.ByteBuffer, s_TempBuffer], this.Length);
|
|
172
172
|
},
|
|
173
173
|
|
|
174
174
|
WriteUInt16: function(p_Value) {
|
|
175
|
-
var s_TempBuffer =
|
|
175
|
+
var s_TempBuffer = Buffer.alloc(2);
|
|
176
176
|
if (this.Endianness == 'little') {
|
|
177
177
|
s_TempBuffer.writeUInt16LE(p_Value, 0);
|
|
178
178
|
} else {
|
|
@@ -183,7 +183,7 @@ BinaryWriter.prototype = {
|
|
|
183
183
|
},
|
|
184
184
|
|
|
185
185
|
WriteUInt32: function(p_Value) {
|
|
186
|
-
var s_TempBuffer =
|
|
186
|
+
var s_TempBuffer = Buffer.alloc(4);
|
|
187
187
|
if (this.Endianness == 'little') {
|
|
188
188
|
s_TempBuffer.writeUInt32LE(p_Value, 0);
|
|
189
189
|
} else {
|
|
@@ -194,7 +194,7 @@ BinaryWriter.prototype = {
|
|
|
194
194
|
},
|
|
195
195
|
|
|
196
196
|
WriteUInt64: function(p_Value) {
|
|
197
|
-
var s_TempBuffer =
|
|
197
|
+
var s_TempBuffer = Buffer.alloc(8);
|
|
198
198
|
var s_Value = BigInt(p_Value);
|
|
199
199
|
if (this.Endianness == 'little') {
|
|
200
200
|
s_TempBuffer.writeBigUInt64LE(s_Value, 0);
|
|
@@ -206,14 +206,14 @@ BinaryWriter.prototype = {
|
|
|
206
206
|
},
|
|
207
207
|
|
|
208
208
|
WriteInt8: function(p_Value) {
|
|
209
|
-
var s_TempBuffer =
|
|
209
|
+
var s_TempBuffer = Buffer.alloc(1);
|
|
210
210
|
s_TempBuffer.writeInt8(p_Value, 0);
|
|
211
211
|
this.Length += 1;
|
|
212
212
|
this.ByteBuffer = Buffer.concat([this.ByteBuffer, s_TempBuffer], this.Length);
|
|
213
213
|
},
|
|
214
214
|
|
|
215
215
|
WriteInt16: function(p_Value) {
|
|
216
|
-
var s_TempBuffer =
|
|
216
|
+
var s_TempBuffer = Buffer.alloc(2);
|
|
217
217
|
if (this.Endianness == 'little') {
|
|
218
218
|
s_TempBuffer.writeInt16LE(p_Value, 0);
|
|
219
219
|
} else {
|
|
@@ -224,7 +224,7 @@ BinaryWriter.prototype = {
|
|
|
224
224
|
},
|
|
225
225
|
|
|
226
226
|
WriteInt32: function(p_Value) {
|
|
227
|
-
var s_TempBuffer =
|
|
227
|
+
var s_TempBuffer = Buffer.alloc(4);
|
|
228
228
|
if (this.Endianness == 'little') {
|
|
229
229
|
s_TempBuffer.writeInt32LE(p_Value, 0);
|
|
230
230
|
} else {
|
|
@@ -235,7 +235,7 @@ BinaryWriter.prototype = {
|
|
|
235
235
|
},
|
|
236
236
|
|
|
237
237
|
WriteInt64: function(p_Value) {
|
|
238
|
-
var s_TempBuffer =
|
|
238
|
+
var s_TempBuffer = Buffer.alloc(8);
|
|
239
239
|
var s_Value = BigInt(p_Value);
|
|
240
240
|
if (this.Endianness == 'little') {
|
|
241
241
|
s_TempBuffer.writeBigInt64LE(s_Value, 0);
|
|
@@ -247,7 +247,7 @@ BinaryWriter.prototype = {
|
|
|
247
247
|
},
|
|
248
248
|
|
|
249
249
|
WriteFloat: function(p_Value) {
|
|
250
|
-
var s_TempBuffer =
|
|
250
|
+
var s_TempBuffer = Buffer.alloc(4);
|
|
251
251
|
if (this.Endianness == 'little') {
|
|
252
252
|
s_TempBuffer.writeFloatLE(p_Value, 0);
|
|
253
253
|
} else {
|
|
@@ -258,7 +258,7 @@ BinaryWriter.prototype = {
|
|
|
258
258
|
},
|
|
259
259
|
|
|
260
260
|
WriteDouble: function(p_Value) {
|
|
261
|
-
var s_TempBuffer =
|
|
261
|
+
var s_TempBuffer = Buffer.alloc(8);
|
|
262
262
|
if (this.Endianness == 'little') {
|
|
263
263
|
s_TempBuffer.writeDoubleLE(p_Value, 0);
|
|
264
264
|
} else {
|
|
@@ -285,7 +285,7 @@ BinaryWriter.prototype = {
|
|
|
285
285
|
throw new Error("Invalid Buffer object provided.");
|
|
286
286
|
}
|
|
287
287
|
|
|
288
|
-
var s_TempBuffer = (p_Value instanceof Buffer) ? p_Value :
|
|
288
|
+
var s_TempBuffer = (p_Value instanceof Buffer) ? p_Value : Buffer.from(p_Value);
|
|
289
289
|
|
|
290
290
|
this.Length += s_TempBuffer.length;
|
|
291
291
|
this.ByteBuffer = Buffer.concat([this.ByteBuffer, s_TempBuffer], this.Length);
|
package/package.json
CHANGED
|
@@ -1,17 +1,54 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "binutils64",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"author": "Mihail Shumilov <mschumilow@gmail.com>",
|
|
5
|
-
"description": "A .NET-like BinaryReader and BinaryWriter with endianness support.",
|
|
6
|
-
"
|
|
7
|
-
"
|
|
8
|
-
"
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
"
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
"
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
|
|
1
|
+
{
|
|
2
|
+
"name": "binutils64",
|
|
3
|
+
"version": "0.2.0",
|
|
4
|
+
"author": "Mihail Shumilov <mschumilow@gmail.com>",
|
|
5
|
+
"description": "A .NET-like BinaryReader and BinaryWriter with endianness support.",
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"keywords": [
|
|
8
|
+
"binary",
|
|
9
|
+
"buffer",
|
|
10
|
+
"binaryreader",
|
|
11
|
+
"binarywriter",
|
|
12
|
+
"reader",
|
|
13
|
+
"writer",
|
|
14
|
+
"endianness",
|
|
15
|
+
"endian",
|
|
16
|
+
"bigint",
|
|
17
|
+
"int64",
|
|
18
|
+
"uint64",
|
|
19
|
+
"parse",
|
|
20
|
+
"serialize"
|
|
21
|
+
],
|
|
22
|
+
"main": "./binutils.js",
|
|
23
|
+
"types": "./binutils.d.ts",
|
|
24
|
+
"exports": {
|
|
25
|
+
".": {
|
|
26
|
+
"types": "./binutils.d.ts",
|
|
27
|
+
"default": "./binutils.js"
|
|
28
|
+
}
|
|
29
|
+
},
|
|
30
|
+
"files": [
|
|
31
|
+
"binutils.js",
|
|
32
|
+
"binutils.d.ts",
|
|
33
|
+
"CHANGELOG.md"
|
|
34
|
+
],
|
|
35
|
+
"scripts": {
|
|
36
|
+
"test": "node --test",
|
|
37
|
+
"lint": "eslint ."
|
|
38
|
+
},
|
|
39
|
+
"engines": {
|
|
40
|
+
"node": ">=12"
|
|
41
|
+
},
|
|
42
|
+
"repository": {
|
|
43
|
+
"type": "git",
|
|
44
|
+
"url": "git+https://github.com/mihailShumilov/node-binutils.git"
|
|
45
|
+
},
|
|
46
|
+
"bugs": {
|
|
47
|
+
"url": "https://github.com/mihailShumilov/node-binutils/issues"
|
|
48
|
+
},
|
|
49
|
+
"homepage": "https://github.com/mihailShumilov/node-binutils#readme",
|
|
50
|
+
"devDependencies": {
|
|
51
|
+
"@eslint/js": "^10.0.1",
|
|
52
|
+
"eslint": "^10.6.0"
|
|
53
|
+
}
|
|
54
|
+
}
|
|
@@ -1,58 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: binutils-reviewer
|
|
3
|
-
description: Reviews changes to the binutils64 library (binutils.js, README.md, tests) for binary-correctness bugs and convention adherence. Use proactively after any edit to binutils.js or when asked to review a Read/Write change, a new type, or a PR touching this library.
|
|
4
|
-
tools: Read, Grep, Glob, Bash
|
|
5
|
-
model: sonnet
|
|
6
|
-
---
|
|
7
|
-
|
|
8
|
-
You are a focused code reviewer for **binutils64**, a single-file ES5 CommonJS
|
|
9
|
-
library (`binutils.js`) providing .NET-style `BinaryReader` and `BinaryWriter`
|
|
10
|
-
with selectable endianness. Your job is to catch binary-correctness bugs and
|
|
11
|
-
convention drift in changes to this library. Be precise and skeptical — this code
|
|
12
|
-
already shipped a real width-mismatch bug (the 64-bit writers emit only 32 bits).
|
|
13
|
-
|
|
14
|
-
## What to review
|
|
15
|
-
|
|
16
|
-
Read `binutils.js`, the relevant `README.md` sections, and any `test/` files. Use
|
|
17
|
-
`git diff` (via Bash) to scope the change when reviewing edits. If a round-trip is
|
|
18
|
-
in doubt, actually run it: `node -e "..."` or `node --test`.
|
|
19
|
-
|
|
20
|
-
## Correctness checklist (highest priority)
|
|
21
|
-
|
|
22
|
-
1. **Write width == read width.** For every `WriteX`/`ReadX` pair, the number of
|
|
23
|
-
bytes written must equal the bytes read and the declared width `N`. Flag any
|
|
24
|
-
writer using a narrower method than its buffer size (e.g. `writeUInt32LE` into
|
|
25
|
-
an 8-byte buffer — this was the original `WriteUInt64`/`WriteInt64` bug, since
|
|
26
|
-
fixed). 64-bit writers use `writeBigUInt64*`/`writeBigInt64*` and coerce with
|
|
27
|
-
`BigInt(p_Value)`. Prefer confirming with a real round-trip.
|
|
28
|
-
2. **Endianness branches** present and correct for every multi-byte method: the
|
|
29
|
-
`'little'` branch uses the `*LE` variant, the else branch uses `*BE`. Single-byte
|
|
30
|
-
methods (`*UInt8`/`*Int8`) must NOT have an endianness branch.
|
|
31
|
-
3. **Reader is destructive and consistent**: each `ReadX` slices exactly `N` bytes
|
|
32
|
-
off `this.ByteBuffer` and advances `this.Position` by exactly `N`. `this.Length`
|
|
33
|
-
must NOT change on reads (it reflects the original buffer length).
|
|
34
|
-
4. **Writer accounting**: each `WriteX` increases `this.Length` by exactly `N` and
|
|
35
|
-
passes the updated `this.Length` as the `Buffer.concat` total-length argument.
|
|
36
|
-
5. **Out-of-range reads return the zero value** (`0`, `0.0`, or empty `Buffer`) and
|
|
37
|
-
never throw. Verify the length guard matches the width.
|
|
38
|
-
6. **Signed/unsigned and BigInt**: signed types use the signed Buffer methods;
|
|
39
|
-
64-bit reads return `bigint` (`readBig*64*`). Watch for sign/precision errors.
|
|
40
|
-
|
|
41
|
-
## Convention checklist
|
|
42
|
-
|
|
43
|
-
- ES5 only: `var`, prototype assignment. No `let`/`const`/classes/arrow functions.
|
|
44
|
-
- `PascalCase` method and property names; parameters prefixed `p_`; locals `s_`.
|
|
45
|
-
- `new Buffer(...)` is intentional for `node >=0.12`. Do NOT recommend
|
|
46
|
-
`Buffer.alloc`/`Buffer.from` unless the change also raises `engines.node`.
|
|
47
|
-
- New/changed public methods must have matching `README.md` entries with the
|
|
48
|
-
existing phrasing, and a round-trip test.
|
|
49
|
-
- Methods placed beside their family in the file, ordered consistently.
|
|
50
|
-
|
|
51
|
-
## Output format
|
|
52
|
-
|
|
53
|
-
Report findings grouped by severity. For each: a one-line title, the
|
|
54
|
-
`binutils.js:line` reference, why it is wrong, and the concrete fix. Lead with
|
|
55
|
-
**Correctness** issues, then **Conventions**, then **Docs/Tests**. State a
|
|
56
|
-
confidence level and only raise convention nits if no correctness issue is
|
|
57
|
-
outstanding. If you ran a round-trip to confirm, show the command and result. If
|
|
58
|
-
nothing is wrong, say so plainly — do not invent issues.
|
|
@@ -1,21 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"permissions": {
|
|
3
|
-
"allow": [
|
|
4
|
-
"Bash(git checkout *)",
|
|
5
|
-
"Bash(node *)",
|
|
6
|
-
"Bash(echo \"exit code: $?\")",
|
|
7
|
-
"Read(//tmp/**)",
|
|
8
|
-
"Bash(echo \"exit: $?\")",
|
|
9
|
-
"mcp__claude_ai_Context7__resolve-library-id",
|
|
10
|
-
"mcp__claude_ai_Context7__query-docs",
|
|
11
|
-
"Bash(python3 -c \"import yaml,sys; yaml.safe_load\\(open\\('.github/workflows/test.yml'\\)\\); print\\('YAML OK'\\)\")",
|
|
12
|
-
"Bash(git add *)",
|
|
13
|
-
"Bash(git commit -m 'fix 64-bit writers and WriteBytes type guard *)",
|
|
14
|
-
"Bash(git commit -m 'add test suite using node:test *)",
|
|
15
|
-
"Bash(git commit -m 'add github actions workflow to run tests *)",
|
|
16
|
-
"Bash(git commit -m 'add project docs and claude tooling *)",
|
|
17
|
-
"Bash(git push *)",
|
|
18
|
-
"Bash(git commit -m 'rewrite readme with full api reference and examples *)"
|
|
19
|
-
]
|
|
20
|
-
}
|
|
21
|
-
}
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: add-binary-type
|
|
3
|
-
description: Add a new matched Read/Write method pair to binutils.js following the library's exact ES5 conventions, then update README.md and add a round-trip test. Use when asked to support a new numeric/binary type (e.g. a new width, a string type, a boolean) in the BinaryReader/BinaryWriter classes.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Adding a binary type to binutils64
|
|
7
|
-
|
|
8
|
-
This library exposes mirrored methods on `BinaryReader` and `BinaryWriter` in the
|
|
9
|
-
single file `binutils.js`. Every supported type has a `ReadX` and a matching
|
|
10
|
-
`WriteX`. Adding a type means editing both prototypes, updating `README.md`, and
|
|
11
|
-
adding a round-trip test. Follow the templates below **exactly** — style
|
|
12
|
-
deviations and width mismatches are the main source of bugs here (this library
|
|
13
|
-
previously shipped a low-32-bit width bug in the 64-bit writers — don't repeat it).
|
|
14
|
-
|
|
15
|
-
## Hard rules (match existing code)
|
|
16
|
-
|
|
17
|
-
- ES5 only: `var`, prototype assignment. No `let`/`const`/classes/arrow functions.
|
|
18
|
-
- Method names are `PascalCase`: `ReadUInt24`, `WriteBool`, etc.
|
|
19
|
-
- Parameters are prefixed `p_` (`p_Value`); locals are prefixed `s_` (`s_Val`,
|
|
20
|
-
`s_TempBuffer`).
|
|
21
|
-
- Keep `new Buffer(...)` — the package targets `node >=0.12`. Do not switch to
|
|
22
|
-
`Buffer.alloc`/`Buffer.from` unless `package.json` `engines.node` is also raised.
|
|
23
|
-
- **The write width MUST equal the read width.** When the type is wider than 32
|
|
24
|
-
bits, use the correct wide Buffer method (`writeBigUInt64LE`, etc.), NOT
|
|
25
|
-
`writeUInt32LE` — using a 32-bit write into an 8-byte buffer was the original
|
|
26
|
-
64-bit writer bug (now fixed). 64-bit values are `BigInt`; coerce with
|
|
27
|
-
`BigInt(p_Value)` so both `Number` and `BigInt` arguments work.
|
|
28
|
-
|
|
29
|
-
## Reader method template
|
|
30
|
-
|
|
31
|
-
Out-of-range reads return `0` (or `0.0` / empty `Buffer`) — they do not throw.
|
|
32
|
-
Reads are destructive: slice the consumed bytes off `this.ByteBuffer` and advance
|
|
33
|
-
`this.Position` by the byte width `N`.
|
|
34
|
-
|
|
35
|
-
```javascript
|
|
36
|
-
ReadTYPE: function() {
|
|
37
|
-
if (this.ByteBuffer.length < N) {
|
|
38
|
-
return 0;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
var s_Val = (this.Endianness == 'little') ? this.ByteBuffer.readTYPELE(0) : this.ByteBuffer.readTYPEBE(0);
|
|
42
|
-
this.ByteBuffer = this.ByteBuffer.slice(N);
|
|
43
|
-
this.Position += N;
|
|
44
|
-
return s_Val;
|
|
45
|
-
},
|
|
46
|
-
```
|
|
47
|
-
|
|
48
|
-
For a single-byte type there is no endianness branch (see `ReadUInt8`/`ReadInt8`),
|
|
49
|
-
and use `++this.Position;`.
|
|
50
|
-
|
|
51
|
-
## Writer method template
|
|
52
|
-
|
|
53
|
-
Allocate an `N`-byte temp buffer, write with the correct-width method honoring
|
|
54
|
-
endianness, grow `this.Length` by `N`, and concat.
|
|
55
|
-
|
|
56
|
-
```javascript
|
|
57
|
-
WriteTYPE: function(p_Value) {
|
|
58
|
-
var s_TempBuffer = new Buffer(N);
|
|
59
|
-
if (this.Endianness == 'little') {
|
|
60
|
-
s_TempBuffer.writeTYPELE(p_Value, 0);
|
|
61
|
-
} else {
|
|
62
|
-
s_TempBuffer.writeTYPEBE(p_Value, 0);
|
|
63
|
-
}
|
|
64
|
-
this.Length += N;
|
|
65
|
-
this.ByteBuffer = Buffer.concat([this.ByteBuffer, s_TempBuffer], this.Length);
|
|
66
|
-
},
|
|
67
|
-
```
|
|
68
|
-
|
|
69
|
-
For a single-byte type, drop the endianness branch (see `WriteUInt8`/`WriteInt8`).
|
|
70
|
-
|
|
71
|
-
## Placement
|
|
72
|
-
|
|
73
|
-
Keep the read/write methods grouped by family and ordered as in the existing file
|
|
74
|
-
(unsigned ascending width, then signed ascending width, then float/double, then
|
|
75
|
-
bytes). Add the new method next to its siblings, not at the end.
|
|
76
|
-
|
|
77
|
-
## After editing binutils.js
|
|
78
|
-
|
|
79
|
-
1. **README.md** — add a `### ReadX(...)` and `### WriteX(value)` entry in the
|
|
80
|
-
matching BinaryReader / BinaryWriter sections, mirroring the existing phrasing
|
|
81
|
-
("Reads/Writes a … and advances the current position by N bytes").
|
|
82
|
-
2. **Test** — add a round-trip test (see the `test-binutils` skill): write a value
|
|
83
|
-
in both `'big'` and `'little'`, read it back, assert equality. Include a min/max
|
|
84
|
-
or negative boundary value for signed/wide types. For 64-bit values assert the
|
|
85
|
-
returned type is `bigint`.
|
|
86
|
-
3. Run the tests: `node --test`.
|
|
87
|
-
|
|
88
|
-
## Verify before finishing
|
|
89
|
-
|
|
90
|
-
- Write width == read width (round-trip test passes for both endiannesses).
|
|
91
|
-
- `Position`/`Length` advance by exactly `N`.
|
|
92
|
-
- Out-of-range read returns the documented zero value, not a throw.
|
|
93
|
-
- README entries added; method placed beside its family.
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: test-binutils
|
|
3
|
-
description: Author and run tests for the binutils64 library using node:test and node:assert. Use when asked to add test coverage, write tests for a Read/Write method, verify a change, or set up the test suite for this project.
|
|
4
|
-
---
|
|
5
|
-
|
|
6
|
-
# Testing binutils64
|
|
7
|
-
|
|
8
|
-
The library ships with no test framework today. Use the built-in `node:test`
|
|
9
|
-
runner + `node:assert/strict` — zero dependencies. (The library's runtime floor
|
|
10
|
-
stays `node >=0.12`; `node:test` only affects the dev/test environment, which
|
|
11
|
-
needs Node >= 18.)
|
|
12
|
-
|
|
13
|
-
## Layout & running
|
|
14
|
-
|
|
15
|
-
- Put tests in `test/`, named `*.test.js`.
|
|
16
|
-
- Run the whole suite: `node --test`.
|
|
17
|
-
- Add to `package.json` if missing:
|
|
18
|
-
```json
|
|
19
|
-
"scripts": { "test": "node --test" }
|
|
20
|
-
```
|
|
21
|
-
|
|
22
|
-
## Test file skeleton
|
|
23
|
-
|
|
24
|
-
```javascript
|
|
25
|
-
var test = require('node:test');
|
|
26
|
-
var assert = require('node:assert/strict');
|
|
27
|
-
var binutils = require('../binutils.js');
|
|
28
|
-
|
|
29
|
-
test('UInt32 round-trips both endiannesses', function() {
|
|
30
|
-
['big', 'little'].forEach(function(endian) {
|
|
31
|
-
var w = new binutils.BinaryWriter(endian);
|
|
32
|
-
w.WriteUInt32(0xDEADBEEF);
|
|
33
|
-
var r = new binutils.BinaryReader(w.ByteBuffer, endian);
|
|
34
|
-
assert.equal(r.ReadUInt32(), 0xDEADBEEF);
|
|
35
|
-
});
|
|
36
|
-
});
|
|
37
|
-
```
|
|
38
|
-
|
|
39
|
-
Keep test code ES5-compatible in spirit (`var`, `function`) to match repo style,
|
|
40
|
-
though the test runner itself requires modern Node.
|
|
41
|
-
|
|
42
|
-
## Coverage priorities (highest value first)
|
|
43
|
-
|
|
44
|
-
### 1. Round-trips — write then read back
|
|
45
|
-
For every type, both `'big'` and `'little'`: write a value, feed `writer.ByteBuffer`
|
|
46
|
-
into a reader, assert the read value equals the written one.
|
|
47
|
-
- `UInt8/16/32`, `Int8/16/32`, `Float`, `Double`, `Bytes`.
|
|
48
|
-
- `UInt64/Int64`: assert against the correct BigInt value. The writers accept a
|
|
49
|
-
`Number` or a `BigInt` and emit all 8 bytes; the reader returns a `BigInt`, so
|
|
50
|
-
compare against a `BigInt` literal (`123n`), not a `Number` (`123n !== 123` under
|
|
51
|
-
strict equality).
|
|
52
|
-
- Signed boundaries: `Int32` min `-2147483648` and max `2147483647`, negatives for
|
|
53
|
-
`Int8/16`.
|
|
54
|
-
- `Float`: compare with tolerance (`assert.ok(Math.abs(got - want) < 1e-6)`) due to
|
|
55
|
-
precision loss. `Double` is exact for representable values.
|
|
56
|
-
|
|
57
|
-
### 2. BinaryReader behavior
|
|
58
|
-
- **Endianness**: identical bytes read as `'big'` vs `'little'` produce the expected
|
|
59
|
-
swapped values; default (no arg) is `'big'`.
|
|
60
|
-
- **Invariants**: after reads, `Position` advanced by the right byte count, `Length`
|
|
61
|
-
unchanged at the original size, `ByteBuffer` shrank by the consumed bytes.
|
|
62
|
-
- **Out-of-range** reads return `0` / `0.0` / empty `Buffer` (never throw) — read
|
|
63
|
-
past the end for each method.
|
|
64
|
-
- **Constructor inputs**: `Buffer`, `Array`, and `string` (+ encoding) all build;
|
|
65
|
-
an invalid input (e.g. a number) throws.
|
|
66
|
-
- **Constructor copies input**: mutate the caller's original buffer after
|
|
67
|
-
constructing and confirm reader output is unaffected.
|
|
68
|
-
- `ReadUInt64`/`ReadInt64` return a `bigint` (`assert.equal(typeof v, 'bigint')`).
|
|
69
|
-
- README reader example: bytes `[1,0,2,0,0,0,3,1,2,3,4,5,6]` yield `1`, `2`, `3`,
|
|
70
|
-
a 6-byte buffer, then `Position` and `Length` both `13`.
|
|
71
|
-
|
|
72
|
-
### 3. BinaryWriter behavior
|
|
73
|
-
- Defaults: endianness `'big'`, encoding `'ascii'`.
|
|
74
|
-
- `Length` increments by the correct width per write; emitted bytes match expected
|
|
75
|
-
hex for both endiannesses.
|
|
76
|
-
- `WriteBytes` accepts `string`, `Array`, and `Buffer`, producing identical bytes,
|
|
77
|
-
and throws on any other input type.
|
|
78
|
-
- README writer example yields `<Buffer ff ff 00 00 00 00 ff ff ff ff 05 04 03 02 01>`,
|
|
79
|
-
`Length` 15.
|
|
80
|
-
|
|
81
|
-
### 4. Maintaining bug-documentation tests
|
|
82
|
-
There are no open known bugs at the moment. When you discover one, pin its current
|
|
83
|
-
behavior with a clearly-commented test so regressions are noticed. When a bug is
|
|
84
|
-
fixed, delete its pinned test and convert any matching TODO round-trip into a normal
|
|
85
|
-
assertion — this is how the former 64-bit writer bug (low-32-bit truncation) and the
|
|
86
|
-
`WriteBytes` guard bug (`!p_Value instanceof Buffer` mis-parsing, which let invalid
|
|
87
|
-
input through) were retired.
|
|
88
|
-
|
|
89
|
-
## Verify before finishing
|
|
90
|
-
- `node --test` passes (except intentionally-`todo` bug tests).
|
|
91
|
-
- New types added via the `add-binary-type` skill have a matching round-trip test.
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
name: Tests
|
|
2
|
-
|
|
3
|
-
on:
|
|
4
|
-
push:
|
|
5
|
-
branches: [master]
|
|
6
|
-
pull_request:
|
|
7
|
-
|
|
8
|
-
jobs:
|
|
9
|
-
test:
|
|
10
|
-
runs-on: ubuntu-latest
|
|
11
|
-
strategy:
|
|
12
|
-
fail-fast: false
|
|
13
|
-
matrix:
|
|
14
|
-
node: [20, 22, 24]
|
|
15
|
-
name: Node ${{ matrix.node }}
|
|
16
|
-
steps:
|
|
17
|
-
- uses: actions/checkout@v6
|
|
18
|
-
- uses: actions/setup-node@v6
|
|
19
|
-
with:
|
|
20
|
-
node-version: ${{ matrix.node }}
|
|
21
|
-
# No install step: the package has zero dependencies and no lockfile.
|
|
22
|
-
- run: npm test
|
package/CLAUDE.md
DELETED
|
@@ -1,54 +0,0 @@
|
|
|
1
|
-
# CLAUDE.md
|
|
2
|
-
|
|
3
|
-
Guidance for working in this repository.
|
|
4
|
-
|
|
5
|
-
## What this is
|
|
6
|
-
|
|
7
|
-
`binutils64` — a small npm package providing .NET-style `BinaryReader` and
|
|
8
|
-
`BinaryWriter` classes for Node.js, with selectable endianness (`'big'` default
|
|
9
|
-
or `'little'`). All logic lives in a single file: `binutils.js`. Published to npm
|
|
10
|
-
as `binutils64`.
|
|
11
|
-
|
|
12
|
-
## Layout
|
|
13
|
-
|
|
14
|
-
- `binutils.js` — the entire library. Two ES5 prototype-based "classes"
|
|
15
|
-
(`BinaryReader`, `BinaryWriter`) exported via `module.exports`.
|
|
16
|
-
- `README.md` — the public API reference (keep in sync when adding/changing methods).
|
|
17
|
-
- No `src/`, no build step, no dependencies, no test suite.
|
|
18
|
-
|
|
19
|
-
## Running / testing
|
|
20
|
-
|
|
21
|
-
There is no test framework, lint config, or build. To verify a change, write an
|
|
22
|
-
ad-hoc script and run it with node, e.g.:
|
|
23
|
-
|
|
24
|
-
```bash
|
|
25
|
-
node -e "var b=require('./binutils.js'); var w=new b.BinaryWriter('little'); w.WriteUInt32(3); console.log(w.ByteBuffer);"
|
|
26
|
-
```
|
|
27
|
-
|
|
28
|
-
When you add or change a public method, update the matching section in `README.md`.
|
|
29
|
-
|
|
30
|
-
## Code conventions (match the existing style exactly)
|
|
31
|
-
|
|
32
|
-
- ES5 only: `var`, prototype assignment, no classes/arrow functions/`let`/`const`.
|
|
33
|
-
- Method and property names are `PascalCase` (`ReadUInt32`, `ByteBuffer`, `Position`).
|
|
34
|
-
- Function parameters are prefixed `p_` (`p_InputBuffer`, `p_Value`).
|
|
35
|
-
- Local variables are prefixed `s_` (`s_Val`, `s_TempBuffer`).
|
|
36
|
-
- Targets `node >=0.12`, so `new Buffer(...)` is used deliberately despite being
|
|
37
|
-
deprecated in modern Node. Don't "fix" it to `Buffer.alloc`/`Buffer.from` unless
|
|
38
|
-
the engines floor is also raised.
|
|
39
|
-
- Commit messages are short, lowercase, imperative (e.g. `add read/write 64 bit values`,
|
|
40
|
-
`fix read int64`). No AI/Claude attribution.
|
|
41
|
-
|
|
42
|
-
## Behavior to preserve
|
|
43
|
-
|
|
44
|
-
- **Reads are destructive.** Each `Read*` slices the consumed bytes off
|
|
45
|
-
`this.ByteBuffer` and advances `this.Position`. `Length` stays at the original
|
|
46
|
-
buffer length; `ByteBuffer` shrinks as you read.
|
|
47
|
-
- **Out-of-range reads return `0` (or `0.0`/empty Buffer), they do not throw.**
|
|
48
|
-
- `ReadUInt64`/`ReadInt64` return a `BigInt` (via `readBigUInt64*`/`readBigInt64*`).
|
|
49
|
-
- The constructor copies the input buffer (`new Buffer(p_InputBuffer)`) so the
|
|
50
|
-
caller's buffer is not mutated — preserve this.
|
|
51
|
-
- `WriteUInt64`/`WriteInt64` accept a `Number` or `BigInt` (coerced via
|
|
52
|
-
`BigInt(p_Value)`) and emit all 8 bytes via `writeBigUInt64*`/`writeBigInt64*`.
|
|
53
|
-
- `WriteBytes` accepts a `Buffer`, `Array`, or `string`, and throws on any other
|
|
54
|
-
input type.
|
package/test/edge-cases.test.js
DELETED
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
var test = require('node:test');
|
|
2
|
-
var assert = require('node:assert/strict');
|
|
3
|
-
var binutils = require('../binutils.js');
|
|
4
|
-
var BinaryReader = binutils.BinaryReader;
|
|
5
|
-
|
|
6
|
-
test('constructor accepts a Buffer', function() {
|
|
7
|
-
var r = new BinaryReader(Buffer.from([1, 2, 3]));
|
|
8
|
-
assert.equal(r.Length, 3);
|
|
9
|
-
assert.equal(r.ReadUInt8(), 1);
|
|
10
|
-
});
|
|
11
|
-
|
|
12
|
-
test('constructor accepts an Array', function() {
|
|
13
|
-
var r = new BinaryReader([1, 2, 3]);
|
|
14
|
-
assert.equal(r.Length, 3);
|
|
15
|
-
assert.equal(r.ReadUInt8(), 1);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('constructor accepts a string with encoding', function() {
|
|
19
|
-
var r = new BinaryReader('ABC', 'big', 'ascii');
|
|
20
|
-
assert.equal(r.Length, 3);
|
|
21
|
-
assert.equal(r.ReadUInt8(), 65);
|
|
22
|
-
});
|
|
23
|
-
|
|
24
|
-
test('constructor rejects invalid input types', function() {
|
|
25
|
-
assert.throws(function() { new BinaryReader(42); }, /Invalid buffer input/);
|
|
26
|
-
assert.throws(function() { new BinaryReader({}); }, /Invalid buffer input/);
|
|
27
|
-
assert.throws(function() { new BinaryReader(null); }, /Invalid buffer input/);
|
|
28
|
-
});
|
|
29
|
-
|
|
30
|
-
test('constructor copies the input buffer (no aliasing)', function() {
|
|
31
|
-
var src = Buffer.from([1, 2, 3]);
|
|
32
|
-
var r = new BinaryReader(src);
|
|
33
|
-
src[0] = 99; // mutate the caller's buffer after construction
|
|
34
|
-
assert.equal(r.ReadUInt8(), 1, 'reader is unaffected by later mutation of the source');
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('out-of-range integer reads return 0 without advancing Position', function() {
|
|
38
|
-
var r = new BinaryReader([0x01], 'big'); // only 1 byte available
|
|
39
|
-
assert.equal(r.ReadUInt16(), 0);
|
|
40
|
-
assert.equal(r.ReadUInt32(), 0);
|
|
41
|
-
assert.equal(r.ReadUInt64(), 0);
|
|
42
|
-
assert.equal(r.ReadInt16(), 0);
|
|
43
|
-
assert.equal(r.ReadInt32(), 0);
|
|
44
|
-
assert.equal(r.ReadInt64(), 0);
|
|
45
|
-
assert.equal(r.Position, 0, 'failed reads do not advance Position');
|
|
46
|
-
assert.equal(r.ByteBuffer.length, 1, 'failed reads do not consume bytes');
|
|
47
|
-
});
|
|
48
|
-
|
|
49
|
-
test('out-of-range float/double reads return 0', function() {
|
|
50
|
-
var r = new BinaryReader([0x01], 'big');
|
|
51
|
-
assert.equal(r.ReadFloat(), 0);
|
|
52
|
-
assert.equal(r.ReadDouble(), 0);
|
|
53
|
-
});
|
|
54
|
-
|
|
55
|
-
test('ReadUInt8 on an empty buffer returns 0', function() {
|
|
56
|
-
var r = new BinaryReader([], 'big');
|
|
57
|
-
assert.equal(r.Length, 0);
|
|
58
|
-
assert.equal(r.ReadUInt8(), 0);
|
|
59
|
-
assert.equal(r.ReadInt8(), 0);
|
|
60
|
-
});
|
|
61
|
-
|
|
62
|
-
test('ReadBytes returns an empty Buffer when count exceeds remaining', function() {
|
|
63
|
-
var r = new BinaryReader([1, 2, 3], 'big');
|
|
64
|
-
var out = r.ReadBytes(5);
|
|
65
|
-
assert.ok(Buffer.isBuffer(out));
|
|
66
|
-
assert.equal(out.length, 0);
|
|
67
|
-
assert.equal(r.Position, 0, 'over-long ReadBytes does not advance');
|
|
68
|
-
assert.equal(r.ByteBuffer.length, 3);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('ReadBytes reading exactly the remaining length succeeds', function() {
|
|
72
|
-
var r = new BinaryReader([1, 2, 3], 'big');
|
|
73
|
-
assert.deepEqual(Array.from(r.ReadBytes(3)), [1, 2, 3]);
|
|
74
|
-
assert.equal(r.Position, 3);
|
|
75
|
-
assert.equal(r.ByteBuffer.length, 0);
|
|
76
|
-
});
|
package/test/reader.test.js
DELETED
|
@@ -1,106 +0,0 @@
|
|
|
1
|
-
var test = require('node:test');
|
|
2
|
-
var assert = require('node:assert/strict');
|
|
3
|
-
var binutils = require('../binutils.js');
|
|
4
|
-
var BinaryReader = binutils.BinaryReader;
|
|
5
|
-
|
|
6
|
-
function reader(arr, endian) {
|
|
7
|
-
return new BinaryReader(Buffer.from(arr), endian);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
test('BinaryReader: constructor defaults', function() {
|
|
11
|
-
var r = reader([1, 2, 3]);
|
|
12
|
-
assert.equal(r.Endianness, 'big', 'defaults to big-endian');
|
|
13
|
-
assert.equal(r.Encoding, 'ascii', 'defaults to ascii encoding');
|
|
14
|
-
assert.equal(r.Length, 3, 'Length is the original buffer length');
|
|
15
|
-
assert.equal(r.Position, 0, 'Position starts at 0');
|
|
16
|
-
assert.equal(r.ByteBuffer.length, 3);
|
|
17
|
-
});
|
|
18
|
-
|
|
19
|
-
test('BinaryReader: ReadUInt8', function() {
|
|
20
|
-
var r = reader([200, 5]);
|
|
21
|
-
assert.equal(r.ReadUInt8(), 200);
|
|
22
|
-
assert.equal(r.ReadUInt8(), 5);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('BinaryReader: ReadInt8 (signed)', function() {
|
|
26
|
-
var r = reader([0xFF, 0x80, 0x7F]);
|
|
27
|
-
assert.equal(r.ReadInt8(), -1);
|
|
28
|
-
assert.equal(r.ReadInt8(), -128);
|
|
29
|
-
assert.equal(r.ReadInt8(), 127);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('BinaryReader: ReadUInt16 honors endianness', function() {
|
|
33
|
-
assert.equal(reader([0x12, 0x34], 'big').ReadUInt16(), 0x1234);
|
|
34
|
-
assert.equal(reader([0x12, 0x34], 'little').ReadUInt16(), 0x3412);
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
test('BinaryReader: ReadInt16 (signed)', function() {
|
|
38
|
-
assert.equal(reader([0xFF, 0xFF], 'big').ReadInt16(), -1);
|
|
39
|
-
assert.equal(reader([0x80, 0x00], 'big').ReadInt16(), -32768);
|
|
40
|
-
assert.equal(reader([0x00, 0x80], 'little').ReadInt16(), -32768);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('BinaryReader: ReadUInt32 honors endianness', function() {
|
|
44
|
-
assert.equal(reader([0x12, 0x34, 0x56, 0x78], 'big').ReadUInt32(), 0x12345678);
|
|
45
|
-
assert.equal(reader([0x78, 0x56, 0x34, 0x12], 'little').ReadUInt32(), 0x12345678);
|
|
46
|
-
});
|
|
47
|
-
|
|
48
|
-
test('BinaryReader: ReadInt32 (signed)', function() {
|
|
49
|
-
assert.equal(reader([0xFF, 0xFF, 0xFF, 0xFF], 'big').ReadInt32(), -1);
|
|
50
|
-
assert.equal(reader([0x80, 0x00, 0x00, 0x00], 'big').ReadInt32(), -2147483648);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('BinaryReader: ReadUInt64 returns a BigInt', function() {
|
|
54
|
-
var r = reader([0, 0, 0, 0, 0, 0, 0, 5], 'big');
|
|
55
|
-
var v = r.ReadUInt64();
|
|
56
|
-
assert.equal(typeof v, 'bigint');
|
|
57
|
-
assert.equal(v, 5n);
|
|
58
|
-
assert.equal(reader([5, 0, 0, 0, 0, 0, 0, 0], 'little').ReadUInt64(), 5n);
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
test('BinaryReader: ReadInt64 returns a signed BigInt', function() {
|
|
62
|
-
assert.equal(reader([0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF], 'big').ReadInt64(), -1n);
|
|
63
|
-
});
|
|
64
|
-
|
|
65
|
-
test('BinaryReader: ReadFloat', function() {
|
|
66
|
-
// 1.5 as IEEE-754 single precision = 0x3FC00000
|
|
67
|
-
assert.equal(reader([0x3F, 0xC0, 0x00, 0x00], 'big').ReadFloat(), 1.5);
|
|
68
|
-
assert.equal(reader([0x00, 0x00, 0xC0, 0x3F], 'little').ReadFloat(), 1.5);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('BinaryReader: ReadDouble', function() {
|
|
72
|
-
// 1.5 as IEEE-754 double precision = 0x3FF8000000000000
|
|
73
|
-
assert.equal(reader([0x3F, 0xF8, 0, 0, 0, 0, 0, 0], 'big').ReadDouble(), 1.5);
|
|
74
|
-
});
|
|
75
|
-
|
|
76
|
-
test('BinaryReader: ReadBytes returns a Buffer of the requested length', function() {
|
|
77
|
-
var r = reader([1, 2, 3, 4, 5, 6]);
|
|
78
|
-
var out = r.ReadBytes(4);
|
|
79
|
-
assert.ok(Buffer.isBuffer(out));
|
|
80
|
-
assert.deepEqual(Array.from(out), [1, 2, 3, 4]);
|
|
81
|
-
assert.equal(r.Position, 4);
|
|
82
|
-
assert.equal(r.ByteBuffer.length, 2);
|
|
83
|
-
});
|
|
84
|
-
|
|
85
|
-
test('BinaryReader: Position advances and Length stays constant; ByteBuffer shrinks', function() {
|
|
86
|
-
var r = reader([1, 2, 3, 4, 5, 6, 7, 8], 'big');
|
|
87
|
-
|
|
88
|
-
assert.equal(r.ReadUInt8(), 1);
|
|
89
|
-
assert.equal(r.Position, 1);
|
|
90
|
-
assert.equal(r.Length, 8, 'Length never changes on reads');
|
|
91
|
-
assert.equal(r.ByteBuffer.length, 7, 'ByteBuffer shrinks by consumed bytes');
|
|
92
|
-
|
|
93
|
-
assert.equal(r.ReadUInt16(), 0x0203);
|
|
94
|
-
assert.equal(r.Position, 3);
|
|
95
|
-
assert.equal(r.ByteBuffer.length, 5);
|
|
96
|
-
|
|
97
|
-
assert.equal(r.ReadUInt32(), 0x04050607);
|
|
98
|
-
assert.equal(r.Position, 7);
|
|
99
|
-
assert.equal(r.ByteBuffer.length, 1);
|
|
100
|
-
});
|
|
101
|
-
|
|
102
|
-
test('BinaryReader: same bytes decode differently per endianness', function() {
|
|
103
|
-
var b = [0x00, 0x00, 0x00, 0x01];
|
|
104
|
-
assert.equal(reader(b, 'big').ReadUInt32(), 1);
|
|
105
|
-
assert.equal(reader(b, 'little').ReadUInt32(), 0x01000000);
|
|
106
|
-
});
|
|
@@ -1,33 +0,0 @@
|
|
|
1
|
-
var test = require('node:test');
|
|
2
|
-
var assert = require('node:assert/strict');
|
|
3
|
-
var binutils = require('../binutils.js');
|
|
4
|
-
|
|
5
|
-
// These mirror the worked examples in README.md. If the documented output ever
|
|
6
|
-
// changes, the docs and these tests must change together.
|
|
7
|
-
|
|
8
|
-
test('README reader example', function() {
|
|
9
|
-
var buffer = Buffer.from([1, 0, 2, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6]);
|
|
10
|
-
var reader = new binutils.BinaryReader(buffer);
|
|
11
|
-
|
|
12
|
-
assert.equal(reader.ReadUInt8(), 1);
|
|
13
|
-
assert.equal(reader.ReadUInt16(), 2);
|
|
14
|
-
assert.equal(reader.ReadUInt32(), 3);
|
|
15
|
-
assert.deepEqual(Array.from(reader.ReadBytes(6)), [1, 2, 3, 4, 5, 6]);
|
|
16
|
-
assert.equal(reader.Position, 13);
|
|
17
|
-
assert.equal(reader.Length, 13);
|
|
18
|
-
});
|
|
19
|
-
|
|
20
|
-
test('README writer example', function() {
|
|
21
|
-
var writer = new binutils.BinaryWriter();
|
|
22
|
-
|
|
23
|
-
writer.WriteUInt16(65535);
|
|
24
|
-
writer.WriteUInt32(0);
|
|
25
|
-
writer.WriteInt32(-1);
|
|
26
|
-
writer.WriteBytes([5, 4, 3, 2, 1]);
|
|
27
|
-
|
|
28
|
-
assert.deepEqual(
|
|
29
|
-
Array.from(writer.ByteBuffer),
|
|
30
|
-
[0xFF, 0xFF, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF, 5, 4, 3, 2, 1]
|
|
31
|
-
);
|
|
32
|
-
assert.equal(writer.Length, 15);
|
|
33
|
-
});
|
package/test/roundtrip.test.js
DELETED
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
var test = require('node:test');
|
|
2
|
-
var assert = require('node:assert/strict');
|
|
3
|
-
var binutils = require('../binutils.js');
|
|
4
|
-
var BinaryReader = binutils.BinaryReader;
|
|
5
|
-
var BinaryWriter = binutils.BinaryWriter;
|
|
6
|
-
|
|
7
|
-
// Write a value with WriteMethod, then read it back with ReadMethod, asserting
|
|
8
|
-
// equality across both endiannesses.
|
|
9
|
-
function roundTrip(writeMethod, readMethod, value, compare) {
|
|
10
|
-
['big', 'little'].forEach(function(endian) {
|
|
11
|
-
var w = new BinaryWriter(endian);
|
|
12
|
-
w[writeMethod](value);
|
|
13
|
-
var r = new BinaryReader(w.ByteBuffer, endian);
|
|
14
|
-
var got = r[readMethod]();
|
|
15
|
-
if (compare) {
|
|
16
|
-
compare(got, value, endian);
|
|
17
|
-
} else {
|
|
18
|
-
assert.equal(got, value, writeMethod + '/' + readMethod + ' (' + endian + ')');
|
|
19
|
-
}
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
test('round-trip: UInt8', function() {
|
|
24
|
-
roundTrip('WriteUInt8', 'ReadUInt8', 0);
|
|
25
|
-
roundTrip('WriteUInt8', 'ReadUInt8', 200);
|
|
26
|
-
roundTrip('WriteUInt8', 'ReadUInt8', 255);
|
|
27
|
-
});
|
|
28
|
-
|
|
29
|
-
test('round-trip: Int8', function() {
|
|
30
|
-
roundTrip('WriteInt8', 'ReadInt8', -128);
|
|
31
|
-
roundTrip('WriteInt8', 'ReadInt8', -1);
|
|
32
|
-
roundTrip('WriteInt8', 'ReadInt8', 127);
|
|
33
|
-
});
|
|
34
|
-
|
|
35
|
-
test('round-trip: UInt16', function() {
|
|
36
|
-
roundTrip('WriteUInt16', 'ReadUInt16', 0);
|
|
37
|
-
roundTrip('WriteUInt16', 'ReadUInt16', 0xBEEF);
|
|
38
|
-
roundTrip('WriteUInt16', 'ReadUInt16', 0xFFFF);
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
test('round-trip: Int16', function() {
|
|
42
|
-
roundTrip('WriteInt16', 'ReadInt16', -32768);
|
|
43
|
-
roundTrip('WriteInt16', 'ReadInt16', -1);
|
|
44
|
-
roundTrip('WriteInt16', 'ReadInt16', 32767);
|
|
45
|
-
});
|
|
46
|
-
|
|
47
|
-
test('round-trip: UInt32', function() {
|
|
48
|
-
roundTrip('WriteUInt32', 'ReadUInt32', 0);
|
|
49
|
-
roundTrip('WriteUInt32', 'ReadUInt32', 0xDEADBEEF);
|
|
50
|
-
roundTrip('WriteUInt32', 'ReadUInt32', 0xFFFFFFFF);
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
test('round-trip: Int32', function() {
|
|
54
|
-
roundTrip('WriteInt32', 'ReadInt32', -2147483648);
|
|
55
|
-
roundTrip('WriteInt32', 'ReadInt32', -1);
|
|
56
|
-
roundTrip('WriteInt32', 'ReadInt32', 2147483647);
|
|
57
|
-
});
|
|
58
|
-
|
|
59
|
-
test('round-trip: Float (within single-precision tolerance)', function() {
|
|
60
|
-
roundTrip('WriteFloat', 'ReadFloat', 1.5);
|
|
61
|
-
roundTrip('WriteFloat', 'ReadFloat', 3.14, function(got, want, endian) {
|
|
62
|
-
assert.ok(Math.abs(got - want) < 1e-5, 'Float ~3.14 (' + endian + '), got ' + got);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
test('round-trip: Double (exact)', function() {
|
|
67
|
-
roundTrip('WriteDouble', 'ReadDouble', Math.PI);
|
|
68
|
-
roundTrip('WriteDouble', 'ReadDouble', -123456.789);
|
|
69
|
-
});
|
|
70
|
-
|
|
71
|
-
test('round-trip: Bytes', function() {
|
|
72
|
-
['big', 'little'].forEach(function(endian) {
|
|
73
|
-
var payload = [1, 2, 3, 4, 5];
|
|
74
|
-
var w = new BinaryWriter(endian);
|
|
75
|
-
w.WriteBytes(payload);
|
|
76
|
-
var r = new BinaryReader(w.ByteBuffer, endian);
|
|
77
|
-
assert.deepEqual(Array.from(r.ReadBytes(payload.length)), payload);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// 64-bit round-trips. The writers accept a Number or a BigInt and emit all 8
|
|
82
|
-
// bytes; the reader always returns a BigInt.
|
|
83
|
-
|
|
84
|
-
test('round-trip: UInt64 (BigInt argument)', function() {
|
|
85
|
-
var value = 0x1234567890ABCDEFn;
|
|
86
|
-
['big', 'little'].forEach(function(endian) {
|
|
87
|
-
var w = new BinaryWriter(endian);
|
|
88
|
-
w.WriteUInt64(value);
|
|
89
|
-
var r = new BinaryReader(w.ByteBuffer, endian);
|
|
90
|
-
assert.equal(r.ReadUInt64(), value);
|
|
91
|
-
});
|
|
92
|
-
});
|
|
93
|
-
|
|
94
|
-
test('round-trip: UInt64 (Number argument is coerced)', function() {
|
|
95
|
-
['big', 'little'].forEach(function(endian) {
|
|
96
|
-
var w = new BinaryWriter(endian);
|
|
97
|
-
w.WriteUInt64(123);
|
|
98
|
-
var r = new BinaryReader(w.ByteBuffer, endian);
|
|
99
|
-
assert.equal(r.ReadUInt64(), 123n);
|
|
100
|
-
});
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('round-trip: Int64 (BigInt argument)', function() {
|
|
104
|
-
var value = -81985529216486896n;
|
|
105
|
-
['big', 'little'].forEach(function(endian) {
|
|
106
|
-
var w = new BinaryWriter(endian);
|
|
107
|
-
w.WriteInt64(value);
|
|
108
|
-
var r = new BinaryReader(w.ByteBuffer, endian);
|
|
109
|
-
assert.equal(r.ReadInt64(), value);
|
|
110
|
-
});
|
|
111
|
-
});
|
|
112
|
-
|
|
113
|
-
test('round-trip: Int64 (negative Number argument is coerced)', function() {
|
|
114
|
-
['big', 'little'].forEach(function(endian) {
|
|
115
|
-
var w = new BinaryWriter(endian);
|
|
116
|
-
w.WriteInt64(-123);
|
|
117
|
-
var r = new BinaryReader(w.ByteBuffer, endian);
|
|
118
|
-
assert.equal(r.ReadInt64(), -123n);
|
|
119
|
-
});
|
|
120
|
-
});
|
package/test/writer.test.js
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
var test = require('node:test');
|
|
2
|
-
var assert = require('node:assert/strict');
|
|
3
|
-
var binutils = require('../binutils.js');
|
|
4
|
-
var BinaryWriter = binutils.BinaryWriter;
|
|
5
|
-
|
|
6
|
-
function bytes(writer) {
|
|
7
|
-
return Array.from(writer.ByteBuffer);
|
|
8
|
-
}
|
|
9
|
-
|
|
10
|
-
test('BinaryWriter: constructor defaults', function() {
|
|
11
|
-
var w = new BinaryWriter();
|
|
12
|
-
assert.equal(w.Endianness, 'big');
|
|
13
|
-
assert.equal(w.Encoding, 'ascii');
|
|
14
|
-
assert.equal(w.Length, 0);
|
|
15
|
-
assert.equal(w.ByteBuffer.length, 0);
|
|
16
|
-
});
|
|
17
|
-
|
|
18
|
-
test('BinaryWriter: WriteUInt8', function() {
|
|
19
|
-
var w = new BinaryWriter();
|
|
20
|
-
w.WriteUInt8(200);
|
|
21
|
-
assert.deepEqual(bytes(w), [200]);
|
|
22
|
-
assert.equal(w.Length, 1);
|
|
23
|
-
});
|
|
24
|
-
|
|
25
|
-
test('BinaryWriter: WriteInt8 (signed)', function() {
|
|
26
|
-
var w = new BinaryWriter();
|
|
27
|
-
w.WriteInt8(-1);
|
|
28
|
-
assert.deepEqual(bytes(w), [0xFF]);
|
|
29
|
-
assert.equal(w.Length, 1);
|
|
30
|
-
});
|
|
31
|
-
|
|
32
|
-
test('BinaryWriter: WriteUInt16 honors endianness', function() {
|
|
33
|
-
var big = new BinaryWriter('big');
|
|
34
|
-
big.WriteUInt16(0x1234);
|
|
35
|
-
assert.deepEqual(bytes(big), [0x12, 0x34]);
|
|
36
|
-
assert.equal(big.Length, 2);
|
|
37
|
-
|
|
38
|
-
var little = new BinaryWriter('little');
|
|
39
|
-
little.WriteUInt16(0x1234);
|
|
40
|
-
assert.deepEqual(bytes(little), [0x34, 0x12]);
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
test('BinaryWriter: WriteUInt32 honors endianness', function() {
|
|
44
|
-
var big = new BinaryWriter('big');
|
|
45
|
-
big.WriteUInt32(0x12345678);
|
|
46
|
-
assert.deepEqual(bytes(big), [0x12, 0x34, 0x56, 0x78]);
|
|
47
|
-
assert.equal(big.Length, 4);
|
|
48
|
-
|
|
49
|
-
var little = new BinaryWriter('little');
|
|
50
|
-
little.WriteUInt32(0x12345678);
|
|
51
|
-
assert.deepEqual(bytes(little), [0x78, 0x56, 0x34, 0x12]);
|
|
52
|
-
});
|
|
53
|
-
|
|
54
|
-
test('BinaryWriter: WriteInt16 / WriteInt32 (signed)', function() {
|
|
55
|
-
var w16 = new BinaryWriter('big');
|
|
56
|
-
w16.WriteInt16(-2);
|
|
57
|
-
assert.deepEqual(bytes(w16), [0xFF, 0xFE]);
|
|
58
|
-
|
|
59
|
-
var w32 = new BinaryWriter('little');
|
|
60
|
-
w32.WriteInt32(-1);
|
|
61
|
-
assert.deepEqual(bytes(w32), [0xFF, 0xFF, 0xFF, 0xFF]);
|
|
62
|
-
});
|
|
63
|
-
|
|
64
|
-
test('BinaryWriter: WriteFloat', function() {
|
|
65
|
-
var big = new BinaryWriter('big');
|
|
66
|
-
big.WriteFloat(1.5);
|
|
67
|
-
assert.deepEqual(bytes(big), [0x3F, 0xC0, 0x00, 0x00]);
|
|
68
|
-
assert.equal(big.Length, 4);
|
|
69
|
-
|
|
70
|
-
var little = new BinaryWriter('little');
|
|
71
|
-
little.WriteFloat(1.5);
|
|
72
|
-
assert.deepEqual(bytes(little), [0x00, 0x00, 0xC0, 0x3F]);
|
|
73
|
-
});
|
|
74
|
-
|
|
75
|
-
test('BinaryWriter: WriteDouble', function() {
|
|
76
|
-
var w = new BinaryWriter('big');
|
|
77
|
-
w.WriteDouble(1.5);
|
|
78
|
-
assert.deepEqual(bytes(w), [0x3F, 0xF8, 0, 0, 0, 0, 0, 0]);
|
|
79
|
-
assert.equal(w.Length, 8);
|
|
80
|
-
});
|
|
81
|
-
|
|
82
|
-
test('BinaryWriter: WriteBytes accepts an array', function() {
|
|
83
|
-
var w = new BinaryWriter();
|
|
84
|
-
w.WriteBytes([1, 2, 3]);
|
|
85
|
-
assert.deepEqual(bytes(w), [1, 2, 3]);
|
|
86
|
-
assert.equal(w.Length, 3);
|
|
87
|
-
});
|
|
88
|
-
|
|
89
|
-
test('BinaryWriter: WriteBytes accepts a Buffer', function() {
|
|
90
|
-
var w = new BinaryWriter();
|
|
91
|
-
w.WriteBytes(Buffer.from([9, 8, 7]));
|
|
92
|
-
assert.deepEqual(bytes(w), [9, 8, 7]);
|
|
93
|
-
assert.equal(w.Length, 3);
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
test('BinaryWriter: WriteBytes accepts a string (per-char codes)', function() {
|
|
97
|
-
var w = new BinaryWriter();
|
|
98
|
-
w.WriteBytes('ABC');
|
|
99
|
-
assert.deepEqual(bytes(w), [65, 66, 67]);
|
|
100
|
-
assert.equal(w.Length, 3);
|
|
101
|
-
});
|
|
102
|
-
|
|
103
|
-
test('BinaryWriter: WriteBytes rejects non-Buffer/non-Array input', function() {
|
|
104
|
-
assert.throws(function() { new BinaryWriter().WriteBytes(4); }, /Invalid Buffer object/);
|
|
105
|
-
assert.throws(function() { new BinaryWriter().WriteBytes({}); }, /Invalid Buffer object/);
|
|
106
|
-
});
|
|
107
|
-
|
|
108
|
-
test('BinaryWriter: multiple writes accumulate and track Length', function() {
|
|
109
|
-
var w = new BinaryWriter('big');
|
|
110
|
-
w.WriteUInt8(1);
|
|
111
|
-
w.WriteUInt16(0x0203);
|
|
112
|
-
w.WriteUInt32(0x04050607);
|
|
113
|
-
assert.deepEqual(bytes(w), [1, 2, 3, 4, 5, 6, 7]);
|
|
114
|
-
assert.equal(w.Length, 7);
|
|
115
|
-
});
|