/** * Parse Oodle0's 36-byte LZ header into a 3-block decode plan : per-block * arith-model sizing + the decoded-byte ranges each block must emit. * * Used internally by {@link decompressOodle0} ; exposed for unit testing. * * @param {Oodle0SectionInput} section * @param {Uint8Array} compressed — the 36-byte LZ header + bitstream. * @returns {Oodle0Plan} */ export function parseOodle0Plan(section: Oodle0SectionInput, compressed: Uint8Array): Oodle0Plan; /** * Reverse the low `nbits` of `value`. Used at multiple points in the arith * decoder where byte / nibble groups need to be read MSB-first : * `code = bitReverse(get(31), 31)` on init, plus byte / nibble swaps * inside `ArithBits.remove()`. Missing one bit-reverse = silent mismatch. * * @param {number} value * @param {number} nbits — 0..31. * @returns {number} */ export function bitReverse(value: number, nbits: number): number; /** * Decompress one Oodle0-tagged section. * * Walks `parseOodle0Plan(section, compressed)`'s 3 blocks back-to-back, * each with its own {@link LZState}, into a pre-allocated * `Uint8Array(section.expanded_size)`. Throws if the decoded length * doesn't match `section.expanded_size` — full byte-exact check, no * "close enough" per [`feedback_no_empirical_closure_re`]. * * @param {Oodle0SectionInput} section — section header from `parseGR2File(...).sections[i]`. * @param {Uint8Array} compressed — raw section bytes (`file.sectionBytes(section)`). * @returns {Uint8Array} of length `section.expanded_size`. * @throws {DecompressionError} on malformed input or length mismatch. */ export function decompressOodle0(section: Oodle0SectionInput, compressed: Uint8Array): Uint8Array; /** * Structural subset of {@link import('./GrannyFile.js').GR2Section} actually * consumed by the Oodle0 codec. A full `GR2Section` is assignable wherever * this is expected — but a hand-built object with just these 4 fields works * too (useful for unit tests that don't want to mock the full section table). * * @typedef {object} Oodle0SectionInput * @property {number} index * @property {number} expanded_size * @property {number} first_16bit — decoded-byte offset where the 16-bit length context block ends. * @property {number} first_8bit — decoded-byte offset where the 8-bit length context block ends. */ /** * One of the three blocks an Oodle0 section is split into. * * @typedef {object} Oodle0Block * @property {0 | 1 | 2} index * @property {number} output_start — decoded-byte offset where this block starts emitting. * @property {number} output_end — decoded-byte offset where this block stops. * @property {number} output_size — `max(0, output_end - output_start)`. * @property {boolean} is_empty * @property {Oodle0LZHeader} header */ /** * Decode plan for one Oodle0 section — 3 blocks back-to-back. * * @typedef {object} Oodle0Plan * @property {number} section_index * @property {number} expanded_size * @property {readonly Oodle0Block[]} blocks — always {@link OODLE0_BLOCK_COUNT} (3) entries. * @property {36} bitstream_offset — constant 36 ; bitstream begins right after * the 3 × 12-byte block headers. */ /** Size of the Oodle0 LZ header block (3 × 12 bytes = 9 × u32). */ export const OODLE0_HEADER_SIZE: 36; /** Number of LZ blocks an Oodle0 section is split into. */ export const OODLE0_BLOCK_COUNT: 3; /** Bit width of the low-offset alphabet ; back-distance = `low + 1 + (high << OFFSET_SPLIT_SHIFT)`. */ export const OFFSET_SPLIT_SHIFT: 2; /** Mask covering the `OFFSET_SPLIT_SHIFT` low bits of the low-offset alphabet. */ export const LOW_OFFSET_MASK: number; /** Largest LZ77 length-context symbol. */ export const MAX_LENS: 64; /** Special-case length lookup for symbols ≥ `MAX_LENS - 3` (= 61, 62, 63, 64). */ export const LONG_LENGTHS: number[]; /** Absolute ceiling on a section's decompressed size. 256 MiB. */ export const OODLE0_MAX_EXPANDED_SIZE: number; /** Max `expanded_size` as a multiple of the compressed input length. */ export const OODLE0_MAX_EXPAND_RATIO: 1024; /** Ceiling on an arith model's alphabet size (blocks the 23-bit 8.4M field). */ export const OODLE0_MAX_ALPHABET: number; /** Raised by the Oodle0 decoder on malformed or out-of-spec input. */ export class DecompressionError extends Error { constructor(message: any); } /** * Per-block LZ header — 12 bytes laid out as 3 × u32. Three of these are * packed at the start of every Oodle0 section. See `docs/gr2-format.md` § * Oodle0 bitstream for the field-by-field bit split. */ export class Oodle0LZHeader { /** * @param {number} maxOffsetAndByte — raw u32 ; low 9 bits = max literal value, high 23 = max back-distance. * @param {number} uniqOffsetAndByte — raw u32 ; low 9 bits = literal alphabet size, high 23 = offset alphabet size. * @param {number} uniqLens — raw u32 ; 4 × u8 unique-symbol count, one per length-context group. */ constructor(maxOffsetAndByte: number, uniqOffsetAndByte: number, uniqLens: number); max_offset_and_byte: number; uniq_offset_and_byte: number; uniq_lens: number; /** Max literal value the block emits — low 9 bits of `max_offset_and_byte`. */ get max_byte_value(): number; /** Max LZ77 back-distance — high 23 bits of `max_offset_and_byte`. */ get max_offset(): number; /** Literal-alphabet size for the block's `bytes` arith model. */ get unique_byte_values(): number; /** Offset-alphabet size for the block's `offset_high` arith model. */ get unique_offsets(): number; /** * Per-length-context unique-symbol count. The 65 length symbols * (`0..MAX_LENS`) split into 4 groups of 16 ; each group gets its * own arith-model sizing taken from one of the 4 bytes of `uniq_lens` * (MSB-first per group). * * @param {number} index — 0-based length symbol (`0..MAX_LENS`). * @returns {number} unique-symbol count for the containing group. */ length_unique(index: number): number; } export namespace __test__ { export { VarBits }; export { ArithBits }; export { ArithModel }; export { EscapeSymbol }; export { LZState }; export { u32lePadded }; export { blockStops }; export { clampStop }; export { alignedCount }; export { bestShift }; } /** * Structural subset of {@link import ('./GrannyFile.js').GR2Section} actually * consumed by the Oodle0 codec. A full `GR2Section` is assignable wherever * this is expected — but a hand-built object with just these 4 fields works * too (useful for unit tests that don't want to mock the full section table). */ export type Oodle0SectionInput = { index: number; expanded_size: number; /** * — decoded-byte offset where the 16-bit length context block ends. */ first_16bit: number; /** * — decoded-byte offset where the 8-bit length context block ends. */ first_8bit: number; }; /** * One of the three blocks an Oodle0 section is split into. */ export type Oodle0Block = { index: 0 | 1 | 2; /** * — decoded-byte offset where this block starts emitting. */ output_start: number; /** * — decoded-byte offset where this block stops. */ output_end: number; /** * — `max(0, output_end - output_start)`. */ output_size: number; is_empty: boolean; header: Oodle0LZHeader; }; /** * Decode plan for one Oodle0 section — 3 blocks back-to-back. */ export type Oodle0Plan = { section_index: number; expanded_size: number; /** * — always {@link OODLE0_BLOCK_COUNT} (3) entries. */ blocks: readonly Oodle0Block[]; /** * — constant 36 ; bitstream begins right after * the 3 × 12-byte block headers. */ bitstream_offset: 36; }; declare class VarBits { constructor(data: any, offset: any); data: any; cur: any; bits: number; bitlen: number; /** Consume `nbits` bits ; return them as an unsigned int (`0..2^nbits - 1`). */ get(nbits: any): number; /** Consume exactly 1 bit (`0` or `1`). Fast path for the inner decode loop. */ get1(): number; } declare class ArithBits { constructor(data: any, offset: any); vbits: VarBits; high: number; low: number; code: number; /** Compute the cumulative count `c` such that the current code falls in `[start, start+c]` for a given `scale`. */ getCount(scale: any): number; /** Decode an integer value in `[0, scale)` directly (used for escape symbols). */ getValue(scale: any): number; /** * Advance the decoder by removing the `[start, start+count)` interval * from the current `[low, high]` range. Performs the standard arith- * coding renormalization (8-bit + 4-bit + 1-bit unscaled rounds, then * the underflow loop) — see RAD's leaked source for asm-cite parity. */ remove(start: any, count: any, scale: any): void; } declare class ArithModel { constructor(uniqueValues: any); unique_values: any; totals: any[]; counts: any[]; values: any[]; number: number; bin_size: number; bin_shift: number; last_bin_start: number; /** * Decode one symbol from `bits`. Returns the symbol value as a plain * number, or an {@link EscapeSymbol} marker when a new alphabet * entry is being introduced. * * @throws DecompressionError if the model overflows its capacity */ decompress(bits: any): any; /** Register the value behind an escape marker so subsequent reads find it. */ setEscaped(marker: any, value: any): void; /** * Find the position whose cumulative count contains `count`. * * Two-stage : first a 4-compare binary search over the 16-entry * cumulative `totals` to find the right bin, then a bounded linear * scan within that bin's `counts` slice. The bin layout is what * {@link bestShift} was designed for — bin sizes are picked so the * within-bin scan stays small. */ _findPos(count: any): any[]; /** * Increment `counts[value]` AND `totals[bin(value)..15]` by `delta`. * * The original RAD code packed two parallel u16 increments into a * single u32 add ; in our codepaths the packed amount always had * identical hi and lo halves (0x10001, 0x20002, 0x30003), so a * straight per-bin u16 add gives the same result without the * packing dance. {@link _decrementCounts} handles the asymmetric * negative-pair case directly. */ _quickIncrement(value: any, delta: any): void; /** Add `delta` (u16) to `totals[bin(value)..15]` cumulatively. */ _incrementTotals(value: any, delta: any): void; /** Decrement `counts[value]` AND `totals[bin(value)..15]` by `amount`. */ _decrementCounts(value: any, amount: any): void; /** * Halve every `counts` entry and rebuild `totals`. Triggered when the * cumulative tally hits 16384. Also drops entries that fall to ≤ 1 * and re-bins the survivors based on the updated alphabet size. */ _rescale(): void; } declare class EscapeSymbol { constructor(index: any); index: any; } declare class LZState { constructor(header: any); max_bytes: any; max_offsets: any; max_offset_low: number; bytes: ArithModel; lengths: any[]; offset_low: ArithModel; offset_high: ArithModel; bytes_decompressed: number; last_length: number; } declare function u32lePadded(data: any, offset: any): number; declare function blockStops(section: any): any[]; declare function clampStop(value: any, expandedSize: any): any; declare function alignedCount(uniqueValues: any): number; declare function bestShift(value: any): number[]; export {};