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 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
  [![npm version](https://img.shields.io/npm/v/binutils64.svg)](https://www.npmjs.com/package/binutils64)
6
+ [![npm downloads](https://img.shields.io/npm/dm/binutils64.svg)](https://www.npmjs.com/package/binutils64)
6
7
  [![Tests](https://github.com/mihailShumilov/node-binutils/actions/workflows/test.yml/badge.svg)](https://github.com/mihailShumilov/node-binutils/actions/workflows/test.yml)
8
+ [![node version](https://img.shields.io/node/v/binutils64.svg)](https://www.npmjs.com/package/binutils64)
9
+ [![license](https://img.shields.io/github/license/mihailShumilov/node-binutils.svg)](https://github.com/mihailShumilov/node-binutils/blob/master/LICENSE)
10
+ [![types](https://img.shields.io/npm/types/binutils64.svg)](https://www.npmjs.com/package/binutils64)
11
+ [![install size](https://packagephobia.com/badge?p=binutils64)](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.** The 8-, 16- and 32-bit methods run on very old Node.js versions, but
236
- the 64-bit methods (`ReadUInt64`, `ReadInt64`, `WriteUInt64`, `WriteInt64`) rely on
237
- `BigInt` and the `Buffer` big-integer methods, which require **Node.js 12 or newer**.
238
- - The library uses the legacy `Buffer` constructor internally; on modern Node.js you
239
- may see a one-time `DEP0005` deprecation warning. This does not affect behavior.
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` passes before opening a pull request.
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 = new Buffer(p_InputBuffer);
4
+ this.ByteBuffer = Buffer.from(p_InputBuffer);
5
5
  } else if (p_InputBuffer instanceof Array || typeof p_InputBuffer == 'string') {
6
- this.ByteBuffer = new Buffer(p_InputBuffer, p_Encoding);
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 new Buffer(0);
137
+ return Buffer.alloc(0);
138
138
  }
139
139
 
140
- var s_Val = new Buffer(p_Count);
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 = new Buffer(0);
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 = new Buffer(1);
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 = new Buffer(2);
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 = new Buffer(4);
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 = new Buffer(8);
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 = new Buffer(1);
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 = new Buffer(2);
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 = new Buffer(4);
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 = new Buffer(8);
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 = new Buffer(4);
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 = new Buffer(8);
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 : new 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.1.4",
4
- "author": "Mihail Shumilov <mschumilow@gmail.com>",
5
- "description": "A .NET-like BinaryReader and BinaryWriter with endianness support.",
6
- "main": "./binutils.js",
7
- "scripts": {
8
- "test": "node --test"
9
- },
10
- "engines": {
11
- "node": ">=0.12"
12
- },
13
- "repository": {
14
- "type" : "git",
15
- "url" : "git://github.com/mihailShumilov/node-binutils.git"
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.
@@ -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
- });
@@ -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
- });
@@ -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
- });
@@ -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
- });