Socket
Book a DemoInstallSign in
Socket

binpat

Package Overview
Dependencies
Maintainers
1
Versions
7
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

binpat

Parse binary data using declarative patterns.

latest
Source
npmnpm
Version
0.1.2
Version published
Maintainers
1
Created
Source

Binpat

GitHub Action Codecov License File size

Binpat simplifies parsing binary data in JavaScript by allowing you to define the data structure using declarative patterns.

  • Declarative: Define what your data looks like, no more manual DataView operations and offsets.
  • Readable: Patterns often closely resemble the desired output object structure.
  • Type Safe: Built with TypeScript, providing inferred return types based on your patterns.

Features

  • Common types: u8...u64, i8...i64, f16...f64, bool, string, bitfield and array(pattern, size).
  • Conditional parsing with ternary(condition, truthy, falsy).
  • Transform parsed values using convert(pattern, fn).
  • Control parsing offset with skip(offset), seek(offset) and peek(offset, pattern).
  • Modify output structure with omit() (exclude fields) and spread() (flatten fields).

Installation

Install from NPM Version

npm i binpat

Install from JSR

deno add jsr:@aho/binpat

Import from CDN jsDelivr or

import Binpat from 'https://cdn.jsdelivr.net/npm/binpat/dist/binpat.js';
import Binpat from 'https://unpkg.com/binpat/dist/binpat.js';

Usage

import Binpat, { u8, u16, string, array } from 'binpat';

const filePattern = {
  fileType: string(4),  // e.g., 'DATA'
  version: u8(),        // e.g., 1
  numRecords: u16(),    // e.g., 2 records
  // Read 'numRecords' count of { id: u8, value: u8 }
  records: array({ id: u8(), value: u8() }, (ctx) => ctx.data.numRecords)
};

const binpat = new Binpat(filePattern);

const sampleData = new Uint8Array([
  0x44, 0x41, 0x54, 0x41, // 'DATA'
  0x01,                   // version 1
  0x00, 0x02,             // numRecords 2 (Big Endian)
  0x01, 0x64,             // Record 1: id=1, value=100
  0x02, 0xC8              // Record 2: id=2, value=200
]);

const result = binpat.exec(sampleData.buffer);

console.log(result);
/*
{
  fileType: 'DATA',
  version: 1,
  numRecords: 2,
  records: [
    { id: 1, value: 100 },
    { id: 2, value: 200 },
  ],
}
*/

Find more complex examples in the examples directory.

API

Find the full API details in the docs.

new Binpat(pattern[, option])

pattern can be native object, native array or binpat functions.

new Binpat({ foo: u8() });
new Binpat([u8(), u8()]);
new Binpat(array(u8(), 10));

option can set the global endianness:

{
  // The global endianness.
  // 'big' | 'little'
  endian: 'big', // default
}

u8, u16, u32, u64, i8, i16, i32, i64, f16, f32, f64

All these functions except u8 and i8 accept a boolean param to set endian. They will use the global endianness by default.

import Binpat, { u8, u16 } from 'binpat';

const binpat = new Binpat({
  a: u8(),
  b: u16(),
  // use little endian
  c: u16(true),
});

bool()

import Binpat, { bool } from 'binpat';

const binpat = new Binpat({
  flag: bool(),
});

string(size[, encoding])

You can parse binary to string with a specific text encoding:

const utf8 = Uint8Array.from(new TextEncoder().encode('binpat'));
console.log(new Binpat(string(6)).exec(utf8.buffer));
// 'binpat'

const gbk = new Uint8Array([214, 208, 206, 196]);
console.log(new Binpat(string(4, 'gbk')).exec(gbk.buffer));
// '中文'

And the string size can be read from context dynamicly:

new Binpat({
  size: u8(),
  text: string((ctx) => ctx.data.size),
});

bitfield(layout[, option])

Define layout with native object:

import Binpat, { bitfield, omit } from 'binpat';

const binpat = new Binpat(bitfield({
  a: 3, // unsigned, 3 bits
  b: bitfield.u(3), // unsigned, 3 bits
  [omit('padding')]: 4, // padding, 4 bits
  c: bitfield.i(5), // signed, 5 bits
  d: bitfield.bool(), // boolean, 1 bit
}));
//                                   aaabbbpp    ppcccccd
const { buffer } = new Uint8Array([0b01010101, 0b11001100]);
console.log(binpat.exec(buffer));
// {
//   a: 2,     // 0b010
//   b: 5,     // 0b101
//             // 0b0111 (padding)
//   c: 6,     // 0b00110
//   d: false, // 0b0
// }

option can set endian and Bit numbering:

{
  // The endianness of the bitfield.
  // Allow values: 'big' | 'little'
  // If not specified, it will use the global endianness.
  endian: 'big',
  // Which bit comes first, allow values:
  // + 'MSb': Most Significant Bit (left-to-right).
  // + 'LSb': Least Significant Bit (right-to-left).
  // If not specified:
  // + When endian is 'big', the first bit is 'MSb'.
  // + When endian is 'little', the first bit is 'LSb'.
  first: 'MSb',
}

array(pattern, size)

pattern can be native object or binpat functions.

If the pattern is a primitive type, it will return a TypedArray instance.

import Binpat, { array, u16, u8 } from 'binpat';

const binpat = new Binpat({
  // pattern can be object
  bar: array({ x: u8(), y: u8() }, 4),
  // It will return Uint16Array
  foo: array(u16(), 4),
});

And the array size can be read from context dynamicly:

new Binpat({
  count: u32(),
  items: array(u8(), (ctx) => ctx.data.count),
});

ternary(condition, truthy[, falsy])

It works like condition ? truthy : falsy

import Binpat, { ternary, bool, u16, u8 } from 'binpat';

const binpat = new Binpat({
  flag: bool(),
  value: ternary(
    (ctx) => ctx.data.flag,
    [u8(), u8()],
    [u16()],
  ),
});
console.log(binpat.exec(new Uint8Array([1, 0, 0]).buffer));
// { flag: true, value: [0, 0] }
console.log(binpat.exec(new Uint8Array([0, 0, 0]).buffer));
// { flag: false, value: [0] }

convert(pattern, fn)

Convert the result value with custom function:

import Binpat, { convert, u16 } from 'binpat';

const binpat = new Binpat({
  type: convert(u16(), (value) => ['', 'ico', 'cur'][value] || 'unknown'),
});
console.log(binpat.exec(new Uint8Array([0, 1]).buffer));
// { type: 'ico' }
console.log(binpat.exec(new Uint8Array([0, 2]).buffer));
// { type: 'cur' }
console.log(binpat.exec(new Uint8Array([0, 0]).buffer));
// { type: 'unknown' }

seek(offset)

Move current offset to the given offset.

offset can be number or a function returns a number.

import Binpat, { seek, omit, u8 } from 'binpat';

const binpat = new Binpat({
  foo: u8(),
  [omit('padding')]: seek((ctx) => ctx.offset + 4),
  bar: u8(),
});
const { buffer } = new Uint8Array([1, 0, 0, 0, 0, 2]);
console.log(binpat.exec(buffer));
// { foo: 1, bar: 2 }

peek(offset, pattern)

Reads pattern from the given offset, and doesn't move current offset.

offset can be number or a function returns a number.

import Binpat, { array, peek, u8 } from 'binpat';

const binpat = new Binpat(array({
  size: u32(),
  address: u32(),
  data: peek(
    (ctx) => ctx.data.address,
    array(u8(), (ctx) => ctx.data.size),
  ),
}, 4));

skip(offset)

Move forward with the given offset.

skip(x) is same as seek((ctx) => ctx.offset + x)

import Binpat, { skip, omit, u8 } from 'binpat';

const binpat = new Binpat({
  foo: u8(),
  [omit('padding')]: skip(4),
  bar: u8(),
});
const { buffer } = new Uint8Array([1, 0, 0, 0, 0, 2]);
console.log(binpat.exec(buffer));
// { foo: 1, bar: 2 }

omit(comment?)

Omit the key-value in result.

comment can be any value.

import Binpat, { omit, u16 } from 'binpat';

const binpat = new Binpat({
  [omit('reserved')]: u16(),
  type: u16(),
  count: u16(),
});
const { buffer } = new Uint8Array([0, 0, 0, 1, 0, 1]);
console.log(binpat.exec(buffer));
// { type: 1, count: 1 }

Due to a TypeScript bug, you'll get wrong type with omit(). To solve it, you can use string literal starts with // as object key:

const binpat = new Binpat({
  '// reserved': u16(),
  type: u16(),
  count: u16(),
  // and you should avoid duplicate key
  '// another reserved': u16(),
});

spread(comment?)

It works like spread syntax ..., and usually be used with ternary().

import Binpat, { spread, ternary, bool, u8 } from 'binpat';

const binpat = new Binpat({
  flag: bool(),
  [spread()]: ternary(
    (ctx) => ctx.data.flag,
    { truthy: u8() },
    { falsy: u8() },
  ),
});
console.log(binpat.exec(new Uint8Array([1, 0]).buffer));
// { flag: true, truthy: 0 }
console.log(binpat.exec(new Uint8Array([0, 0]).buffer));
// { flag: false, falsy: 0 }

And like omit(), you can use string literal starts with ... as object key to get correct type inference:

const binpat = new Binpat({
  flag: bool(),
  '...foo': ternary(
    (ctx) => ctx.data.flag,
    { truthy: u8() },
    { falsy: u8() },
  ),
});

Keywords

binary

FAQs

Package last updated on 19 Oct 2025

Did you know?

Socket

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Install

Related posts