npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

binutils64

v0.3.0

Published

A .NET-like BinaryReader and BinaryWriter with endianness support.

Downloads

6,145

Readme

binutils64

A .NET-style BinaryReader and BinaryWriter for Node.js, with selectable endianness.

npm version npm downloads Tests node version license types install size

binutils64 provides two small classes — BinaryReader and BinaryWriter — that make it easy to parse and produce binary data sequentially, with an API modelled on the corresponding .NET classes. Both classes let you choose the byte order (big- or little-endian) and support 8-, 16-, 32- and 64-bit integers, floats, doubles, raw byte runs, and encoded strings.

Table of contents

Features

  • Sequential Read* / Write* methods for every common fixed-width type.
  • Per-instance endianness (big by default, or little).
  • 64-bit integers via JavaScript BigInt.
  • Signed and unsigned integers, IEEE-754 float and double, raw byte runs, and strings in any Buffer encoding.
  • Zero runtime dependencies.
  • Bundled TypeScript type definitions.

Installation

npm install binutils64

Then require it:

const binutils = require('binutils64');
// const { BinaryReader, BinaryWriter } = require('binutils64');

Quick start

const { BinaryReader, BinaryWriter } = require('binutils64');

// --- Writing ---
const writer = new BinaryWriter();      // big-endian by default
writer.WriteUInt16(65535);
writer.WriteUInt32(0);
writer.WriteInt32(-1);
writer.WriteBytes([5, 4, 3, 2, 1]);

console.log(writer.ByteBuffer);
// <Buffer ff ff 00 00 00 00 ff ff ff ff 05 04 03 02 01>
console.log(writer.Length); // 15

// --- Reading ---
const reader = new BinaryReader(writer.ByteBuffer);
console.log(reader.ReadUInt16()); // 65535
console.log(reader.ReadUInt32()); // 0
console.log(reader.ReadInt32());  // -1
console.log(reader.ReadBytes(5)); // <Buffer 05 04 03 02 01>

API reference

BinaryReader

A reader wraps an immutable copy of the input data and consumes it from the front as you read.

new BinaryReader(input, [endianness], [encoding])

| Parameter | Type | Default | Description | | ------------ | ----------------------------- | ------- | ------------------------------------------------------------------ | | input | Buffer | number[] | string | — | The data to read. A Buffer is copied so the source is never mutated. | | endianness | 'big' | 'little' | 'big' | Byte order used by all multi-byte reads. | | encoding | string | 'ascii' | Used to turn a string input into bytes, and by ReadString. |

Throws Error if input is not a Buffer, array, or string.

Read methods

| Method | Bytes | Returns | Notes | | ----------------- | ----- | --------- | ---------------------------------------------- | | ReadUInt8() | 1 | number | Unsigned. | | ReadInt8() | 1 | number | Signed. | | ReadUInt16() | 2 | number | Honors endianness. | | ReadInt16() | 2 | number | Honors endianness. | | ReadUInt32() | 4 | number | Honors endianness. | | ReadInt32() | 4 | number | Honors endianness. | | ReadUInt64() | 8 | BigInt | Honors endianness. Returns a BigInt. | | ReadInt64() | 8 | BigInt | Honors endianness. Returns a BigInt. | | ReadFloat() | 4 | number | IEEE-754 single precision. | | ReadDouble() | 8 | number | IEEE-754 double precision. | | ReadBytes(count)| count | Buffer| Copies count bytes into a new Buffer. | | ReadString(count)| count | string| Decodes count bytes using the instance's Encoding. |

If fewer than the required number of bytes remain, integer/float reads return 0 (or 0.0), and ReadBytes/ReadString return an empty Buffer/stringwithout throwing or advancing the position. See Behavior and best practices.

Reader properties

| Property | Type | Description | | ------------ | -------- | ------------------------------------------------------------------- | | ByteBuffer | Buffer | The remaining unread data. Shrinks as you read. | | Position | number | Number of bytes consumed so far (starts at 0). | | Length | number | The length of the original input. Does not change as you read. | | Endianness | string | 'big' or 'little'. | | Encoding | string | The encoding passed to the constructor. |

BinaryWriter

A writer accumulates bytes in an internal buffer that grows with every write.

new BinaryWriter([endianness], [encoding])

| Parameter | Type | Default | Description | | ------------ | --------------------- | --------- | ---------------------------------------- | | endianness | 'big' | 'little' | 'big' | Byte order used by all multi-byte writes.| | encoding | string | 'ascii' | Used by WriteString to encode strings. |

Write methods

| Method | Bytes | Accepts | Notes | | --------------------- | ----- | ------------------- | -------------------------------------------------- | | WriteUInt8(value) | 1 | number | Unsigned. | | WriteInt8(value) | 1 | number | Signed. | | WriteUInt16(value) | 2 | number | Honors endianness. | | WriteInt16(value) | 2 | number | Honors endianness. | | WriteUInt32(value) | 4 | number | Honors endianness. | | WriteInt32(value) | 4 | number | Honors endianness. | | WriteUInt64(value) | 8 | number | BigInt| Coerced with BigInt(value); honors endianness. | | WriteInt64(value) | 8 | number | BigInt| Coerced with BigInt(value); honors endianness. | | WriteFloat(value) | 4 | number | IEEE-754 single precision. | | WriteDouble(value) | 8 | number | IEEE-754 double precision. | | WriteBytes(value) | varies| Buffer | number[] | string | Strings are written as one byte per character code. Throws on any other type. | | WriteString(value) | varies| string | Encodes the string using the instance's Encoding. Throws on any other type. |

Writing a value outside the target type's range throws a RangeError (the standard Node.js Buffer write behavior) — e.g. WriteUInt8(256).

Writer properties

| Property | Type | Description | | ------------ | -------- | -------------------------------------------- | | ByteBuffer | Buffer | All bytes written so far. | | Length | number | The current length of ByteBuffer. | | Endianness | string | 'big' or 'little'. | | Encoding | string | The encoding passed to the constructor. |

Behavior and best practices

  • Reads are destructive. Each Read* call consumes bytes from the front of ByteBuffer and advances Position. If you need the original bytes again, keep your own copy before reading. Create a fresh BinaryReader to start over.

  • Length vs. Position. On a reader, Length is the original size and never changes; Position tracks how much you have consumed. The bytes left to read are Length - Position (also ByteBuffer.length).

  • Out-of-range reads do not throw. Reading past the end returns 0 / 0.0 / an empty Buffer and leaves Position unchanged. Check the remaining length yourself if a short buffer should be treated as an error:

    if (reader.ByteBuffer.length < 4) {
      throw new Error('truncated record');
    }
    const value = reader.ReadUInt32();
  • 64-bit values are BigInts. ReadUInt64/ReadInt64 always return a BigInt. When writing, pass a BigInt for any value above Number.MAX_SAFE_INTEGER (2^53 - 1) to avoid silent precision loss; smaller numbers are accepted and coerced automatically.

  • Set endianness once, at construction. All multi-byte methods follow the instance's Endianness; reader and writer must agree to round-trip correctly.

  • Constructing a reader from a string? Pass the encoding explicitly (e.g. new BinaryReader(text, 'big', 'utf8')) so the bytes are interpreted the way you expect.

  • The default 'ascii' encoding is 7-bit only. Node.js clears the high bit of every byte when decoding 'ascii', so text containing characters above 0x7F does not round-trip through WriteString/ReadString with the default encoding. Pass 'utf8' (or 'latin1') to both constructors when handling non-ASCII text.

Examples

Round-tripping a 64-bit integer

const { BinaryReader, BinaryWriter } = require('binutils64');

const writer = new BinaryWriter();             // big-endian
writer.WriteUInt64(0x1234567890ABCDEFn);       // pass a BigInt for large values
console.log(writer.ByteBuffer);                // <Buffer 12 34 56 78 90 ab cd ef>

const reader = new BinaryReader(writer.ByteBuffer);
console.log(reader.ReadUInt64());              // 1311768467294899695n

Little-endian

const { BinaryReader, BinaryWriter } = require('binutils64');

const writer = new BinaryWriter('little');
writer.WriteUInt32(0x01020304);
console.log(writer.ByteBuffer);                // <Buffer 04 03 02 01>

const reader = new BinaryReader(writer.ByteBuffer, 'little');
console.log(reader.ReadUInt32().toString(16)); // "1020304"

Writing and reading strings

const { BinaryReader, BinaryWriter } = require('binutils64');

const text = 'héllo';
const writer = new BinaryWriter('big', 'utf8');
writer.WriteUInt8(Buffer.byteLength(text, 'utf8')); // length prefix: 6
writer.WriteString(text);

const reader = new BinaryReader(writer.ByteBuffer, 'big', 'utf8');
const length = reader.ReadUInt8();                  // 6
console.log(reader.ReadString(length));             // "héllo"

Parsing a structured record

const { BinaryReader } = require('binutils64');

// type (u8), id (u32, big-endian), payload (6 bytes)
const reader = new BinaryReader(Buffer.from([1, 0, 0, 0, 3, 1, 2, 3, 4, 5, 6]));

const record = {
  type:    reader.ReadUInt8(),   // 1
  id:      reader.ReadUInt32(),  // 3
  payload: reader.ReadBytes(6),  // <Buffer 01 02 03 04 05 06>
};

console.log(record, 'read', reader.Position, 'of', reader.Length, 'bytes');

Requirements and compatibility

  • Node.js 12 or newer (declared in package.json engines). The 64-bit methods (ReadUInt64, ReadInt64, WriteUInt64, WriteInt64) rely on BigInt and the Buffer big-integer methods introduced in Node.js 12.
  • TypeScript typings are bundled (binutils.d.ts) — no separate @types package is needed.
  • Running the test suite uses the built-in node:test runner, which requires Node.js 18 or newer.

Testing

npm test     # runs `node --test`

The suite covers every reader/writer method, round-trips across both endiannesses, edge cases (out-of-range reads, constructor input types, buffer-copy isolation), and the documented examples. Continuous integration runs it on Node.js 20, 22 and 24.

Contributing

Issues and pull requests are welcome. Please add or update tests for any behavioral change, note it in CHANGELOG.md under Unreleased, and make sure npm test and npm run lint pass before opening a pull request (run npm ci once to install the linter).

License

MIT