🚀 Big News: Socket Acquires Coana to Bring Reachability Analysis to Every Appsec Team.Learn more
Socket
Sign inDemoInstall
Socket

@dlenroc/binary-decoder

Package Overview
Dependencies
Maintainers
0
Versions
4
Alerts
File Explorer

Advanced tools

Socket logo

Install Socket

Detect and block malicious and high-risk dependencies

Install

@dlenroc/binary-decoder

Incremental binary data parser powered by generators.

0.3.0
latest
Source
npm
Version published
Weekly downloads
0
Maintainers
0
Weekly downloads
 
Created
Source

@dlenroc/binary-decoder · NPM Version

A library for implementing incremental binary data parsers using generators.

Installation

npm install @dlenroc/binary-decoder

Usage

The BinaryDecoder class enables streaming binary decoding using a generator function. It leverages yield to read bytes, return unused data, and produce the decoded result.

import { BinaryDecoder } from '@dlenroc/binary-decoder';

const decoder = new BinaryDecoder(function* () {
  // ✨ N ≥ 0 | Read exactly N bytes.
  const fixedLengthBytes: Uint8Array = yield 2;

  // ✨ N < 0 | Read at most |N| bytes, at least 1 byte.
  const variableLengthBytes: Uint8Array = yield -2;

  // ✨ ArrayBufferView | Pushback bytes to the internal buffer.
  yield Uint8Array.of(40, 50);

  // ✨ Other | Enqueue parsed data.
  yield { fixedLengthBytes, variableLengthBytes, extraBytes: yield -Infinity };
});

console.log([...decoder.decode(Uint8Array.of(10, 20, 30))]);
// [
//   {
//     fixedLengthBytes: Uint8Array(2) [ 10, 20 ],
//     variableLengthBytes: Uint8Array(1) [ 30 ],
//     extraBytes: Uint8Array(2) [ 40, 50 ]
//   }
// ]

Examples

Stateful Parsing

Suppose we need to parse a simple protocol defined as follows:

No. of bytesType [Value]Description
4U32length
lengthU8 arraytext
import type { Decoder } from '@dlenroc/binary-decoder';
import { BinaryDecoder, getUint32 } from '@dlenroc/binary-decoder';

function* parse(): Decoder<string> {
  while (true) {
    const length = yield* getUint32();
    const bytes = yield length;

    yield new TextDecoder().decode(bytes);
  }
}

const decoder = new BinaryDecoder(parse);

// create a message
const textBytes = new TextEncoder().encode('Hello, World!');
const chunk = new Uint8Array([...new Uint8Array(4), ...textBytes]);
new DataView(chunk.buffer).setUint32(0, textBytes.byteLength);

// [1] Parse a message
console.log([...decoder.decode(chunk)]);
// [ 'Hello, World!' ]

// [2] Parse multiple messages
console.log([...decoder.decode(Uint8Array.of(...chunk, ...chunk))]);
// [ 'Hello, World!', 'Hello, World!' ]

// [3] Parse a message split across chunks
console.log([...decoder.decode(chunk.subarray(0, 3))]);
// []
console.log([...decoder.decode(chunk.subarray(3, 5))]);
// []
console.log([...decoder.decode(chunk.subarray(5))]);
// [ 'Hello, World!' ]

Handling Large Messages

Update the decoder to stream decoded chunks directly, avoiding buffering.

import { getUint32, streamBytes } from '@dlenroc/binary-decoder';

function* parse(): Decoder<TextDecoderStream> {
  while (true) {
    const length = yield* getUint32();
    const stream = new TextDecoderStream();
    const writer = stream.writable.getWriter();

    try {
      yield stream;
      yield* streamBytes(length, (chunk) => writer.write(chunk));
    } finally {
      writer.close();
    }
  }
}

// ... 👀 See previous example

// [3] Parse a message split across chunks (streaming output)
console.log([...decoder.decode(chunk.subarray(0, 3))]);
// []
console.log([...decoder.decode(chunk.subarray(3, 5))]);
// [ TextDecoderStream { ... } ]
console.log([...decoder.decode(chunk.subarray(5))]);
// []

Keywords

incremental

FAQs

Package last updated on 02 Jan 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