Skip to content
BSD
Esc
navigateopen⌘Jpreview
On this page

Misc

Define constants, inspect offsets, scan input, skip padding, and implement custom schemas.

These constructors cover cursor control, lookahead, and low-level decoding.

Constructor Cursor effect Result
offset() None Absolute byte offset
find(schema, predicate) Scans, then restores Absolute match offset
padded(byteLength, schema) Skips before decoding Inner schema result
custom(decoder) Decoder-controlled Decoder result

offset()

offset() returns the current absolute cursor without advancing it. This is mostly useful when reverse engineering a binary layout. startsAt identifies the first byte consumed by id.

const Entry = struct({ startsAt: offset(), id: u32() });

find()

find(schema, predicate) repeatedly decodes schema as lookahead. It returns the absolute offset immediately before the first matching value, then restores the original cursor.

find() locates the terminator, .pipe() consumes the text, and .pad(2) consumes the terminator. If scanning cannot decode another value, find() returns the offset after the last successful non-match.

const NullTerminatedUtf16Text = find(u16(), (v) => v === 0)
    .pipe((o, r) => bytes(o - r.byteOffset).utf16())
    .pad(2);

padded()

padded(byteLength, schema) skips byteLength bytes before decoding schema. Use schema.pad(byteLength) to skip bytes after decoding instead.

The record consumes a 16-bit tag, two padding bytes, then a 32-bit value.

const AlignedRecord = struct({
    tag: u16(),
    value: padded(2, u32()),
});

custom()

custom(decoder) creates a schema from a BsdReader callback. The decoder owns cursor advancement and must preserve path state when it decodes nested values.

const CString = custom((reader) => {
    const start = reader.byteOffset;
    let end = start;

    while (end < reader.limit && reader.buffer[end] !== 0) end++;
    if (end === reader.limit) throw reader.fail("unterminated C string");

    reader.byteOffset = end + 1;
    return new TextDecoder().decode(reader.buffer.subarray(start, end));
});

Was this page helpful?