Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,97 @@
# buffer-utils
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
Provides a compact set of pure binary-reading helpers that operate directly on `Uint8Array` values. These utilities abstract away the bit-shifting and byte-ordering arithmetic that every audio-format parser needs, reducing the risk of off-by-one errors and making parser code easier to read and test in isolation.
All helpers are environment-agnostic — they use only the `Uint8Array` and `TextDecoder` web-standard APIs, so they work identically in Node.js 18+, Deno, and modern browsers without any polyfills.
## Features
- Unsigned/signed integer readers: `readUint8`, `readUint16BE`, `readUint16LE`, `readUint32BE`, `readUint32LE`, `readInt32BE`
- String decoder with `"utf8"` (TextDecoder) and `"latin1"` (char-code loop) encodings
- `readSyncsafeInt` for ID3v2 syncsafe 28-bit integers
- `concatBuffers` for building test fixtures and merging partial reads
- Every function returns a sensible default (`0` / `""`) on out-of-bounds access rather than throwing
## Usage: Basic Example
```ts
import {
readUint32BE,
readString,
} from "@suaveplan/audio-metadata";
const buf = new Uint8Array([0x00, 0x00, 0x04, 0x00]);
const size = readUint32BE(buf, 0); // 1024
const text = new Uint8Array([0x48, 0x69]);
readString(text, 0, 2); // "Hi"
```
## Usage: Advanced Example
```ts
import {
readSyncsafeInt,
readUint16BE,
concatBuffers,
} from "@suaveplan/audio-metadata";
// Decode an ID3v2 tag size from a header
const header = new Uint8Array([0x49, 0x44, 0x33, 0x03, 0x00, 0x00, 0x00, 0x00, 0x02, 0x01]);
const tagSize = readSyncsafeInt(header, 6); // 257
// Build a larger test buffer by concatenating parts
const part1 = new Uint8Array([0x52, 0x49, 0x46, 0x46]);
const part2 = new Uint8Array([0x00, 0x10, 0x00, 0x00]);
const combined = concatBuffers(part1, part2); // "RIFF" + size bytes
```
## API Reference
### `readUint8(buf, offset)`
Returns `buf[offset]` as a number (0–255), or `0` if out of bounds.
### `readUint16BE(buf, offset)`
Reads two bytes at `offset` as a big-endian unsigned 16-bit integer.
### `readUint16LE(buf, offset)`
Reads two bytes at `offset` as a little-endian unsigned 16-bit integer.
### `readUint32BE(buf, offset)`
Reads four bytes at `offset` as a big-endian unsigned 32-bit integer.
### `readUint32LE(buf, offset)`
Reads four bytes at `offset` as a little-endian unsigned 32-bit integer.
### `readInt32BE(buf, offset)`
Reads four bytes at `offset` as a big-endian signed 32-bit integer. Converts unsigned values ≥ 0x80000000 to their negative two's-complement equivalents.
### `readString(buf, offset, length, encoding?)`
Decodes `length` bytes starting at `offset`.
- `encoding = "utf8"` (default): uses `TextDecoder("utf-8")` for correct multi-byte handling.
- `encoding = "latin1"`: maps each byte to its Unicode code point — necessary for ID3v1 and some legacy ID3v2 fields.
### `readSyncsafeInt(buf, offset)`
Reads four bytes at `offset` and decodes them as an ID3v2 syncsafe integer (28-bit value, MSB of each byte ignored). Returns a plain `number`.
### `concatBuffers(a, b)`
Returns a new `Uint8Array` containing all bytes of `a` followed by all bytes of `b`.
## Implementation Notes
The `>>> 0` cast after bit-shifting operations ensures the result is treated as an unsigned 32-bit integer in JavaScript, preventing sign-extension surprises with values whose MSB is set. The `readUint32BE` implementation uses multiplication by `0x1000000` instead of `<< 24` to avoid the signed-integer trap that `<< 24` introduces for bytes with the high bit set. Out-of-bounds array reads return `undefined` in JavaScript, which is coerced to `0` via the `?? 0` fallback — this trades silent safety for parser robustness with truncated buffers.