LEB128 Encoding and Decoding Utilities
The `leb` Node.js module provides a suite of utility functions for encoding and decoding integers using the LEB128 (Little-Endian Base 128) variable-length representation format. It supports both signed and unsigned values, with options for 32-bit integers, 64-bit integers (which return a `lossy` flag due to JavaScript's number precision limitations), and arbitrary-length buffer representations. Currently at `v1.0.0`, the package was recently resurrected and aims to provide a reliable, dependency-free solution for LEB128, a format notably used in the DWARF 3 debugging format and Android's DEX file format. The package maintains a stable API with no breaking changes in its recent major release and focuses on direct encoding/decoding operations for binary data within Node.js environments.
Common errors
-
TypeError: Buffer is not defined
cause Attempting to use `leb` in a browser environment without providing a global `Buffer` polyfill.fixIn a browser environment, you need to install and configure a `Buffer` polyfill (e.g., `npm install buffer` and import it) or ensure your bundler (Webpack, Rollup) includes one. -
Error: Value out of range for 32-bit signed integer
cause An input number provided to `encodeInt32` or `encodeUInt32` exceeds the representable range for its target 32-bit type.fixEnsure the input integer falls within the valid range for a 32-bit signed integer (-2,147,483,648 to 2,147,483,647) or a 32-bit unsigned integer (0 to 4,294,967,295). Use the appropriate 64-bit encoding functions (`encodeInt64`, `encodeUInt64`) for larger numbers. -
Error: Ran out of bytes while decoding LEB128 value
cause The `Buffer` provided to a decode function (e.g., `decodeInt32`) does not contain enough bytes to complete the LEB128 sequence, or the last byte has its high bit set, indicating an incomplete sequence.fixVerify that the input `Buffer` contains a complete LEB128 encoded value starting from the given index. Ensure the buffer is not truncated and includes the final byte with its high bit unset.
Warnings
- gotcha When decoding 64-bit integers, JavaScript's native number type cannot represent all possible 64-bit integer values precisely. The `decodeInt64` and `decodeUInt64` methods will return a `lossy` flag, which developers must check to determine if the decoded number exactly matches the encoded form.
- gotcha The `leb` package is designed for Node.js environments and relies on the Node.js `Buffer` API. It is not directly usable in a browser environment without a `Buffer` polyfill or a bundling process that handles Node.js-specific APIs.
- gotcha Attempting to decode an LEB128 sequence from a `Buffer` that is too short, or contains an incomplete/malformed sequence at the specified index, will result in an exception (e.g., 'Ran out of bytes').
Install
-
npm install leb -
yarn add leb -
pnpm add leb
Imports
- decodeInt32
const { decodeInt32 } = require('leb')import { decodeInt32 } from 'leb' - encodeInt32
const { encodeInt32 } = require('leb')import { encodeInt32 } from 'leb' - decodeUInt32
const { decodeUInt32 } = require('leb')import { decodeUInt32 } from 'leb' - encodeUInt32
const { encodeUInt32 } = require('leb')import { encodeUInt32 } from 'leb'
Quickstart
import { encodeInt32, decodeInt32, encodeUInt32, decodeUInt32 } from 'leb';
// Example: Encoding and decoding a signed 32-bit integer
const signedNumber = -1234567;
const encodedSigned = encodeInt32(signedNumber);
console.log(`Encoded signed ${signedNumber}: ${encodedSigned.toString('hex')}`);
const decodedSigned = decodeInt32(encodedSigned);
console.log(`Decoded signed: ${decodedSigned.value} (nextIndex: ${decodedSigned.nextIndex})`);
// Example: Encoding and decoding an unsigned 32-bit integer
const unsignedNumber = 4294967295; // Max UInt32
const encodedUnsigned = encodeUInt32(unsignedNumber);
console.log(`Encoded unsigned ${unsignedNumber}: ${encodedUnsigned.toString('hex')}`);
const decodedUnsigned = decodeUInt32(encodedUnsigned);
console.log(`Decoded unsigned: ${decodedUnsigned.value} (nextIndex: ${decodedUnsigned.nextIndex})`);
// Example with an offset in a larger buffer
const multiValueBuffer = Buffer.concat([
encodeInt32(100),
encodeInt32(-500),
encodeUInt32(250)
]);
let currentOffset = 0;
let result1 = decodeInt32(multiValueBuffer, currentOffset);
console.log(`
Value 1: ${result1.value}`);
currentOffset = result1.nextIndex;
let result2 = decodeInt32(multiValueBuffer, currentOffset);
console.log(`Value 2: ${result2.value}`);
currentOffset = result2.nextIndex;
let result3 = decodeUInt32(multiValueBuffer, currentOffset);
console.log(`Value 3: ${result3.value}`);
console.log(`Final offset: ${result3.nextIndex}`);