nx_zstd_bits.nx
buildroot/runtime/nx_zstd_bits.nx
about
nx_zstd_bits.nx -- Zstandard's BACKWARD bitstream reader + Huffman weights.
The piece between nx_zstd_fse.nx (entropy tables) and a working literals
section. Both zstd's Huffman streams and its FSE streams are read BACKWARDS
from the end of the buffer, which is unlike every other format in this tree
-- DEFLATE, VP8L, FLAC, VP8 and AV1 all read forward.
THE STREAM ENDS WITH A MARKER BIT, NOT A LENGTH. The final byte's highest
SET bit is a sentinel: it and everything above it is padding, and the real
data ends immediately below it. So initialisation must find that bit and
start there. A reader that begins at the top of the last byte consumes
padding as data and every symbol after it is wrong; a reader that assumes a
fixed padding width works only when the payload happens to end byte-aligned.
A final byte of ZERO has no marker at all and is corrupt by definition --
it is REFUSED here rather than treated as eight padding bits.
BITS ARE PACKED LSB-FIRST WITHIN A BYTE, AND READ HIGH-TO-LOW OVERALL. Those
two facts together are the whole trick: absolute bit k lives at
data[k >> 3] bit (k & 7) counting from the LSB, and reading walks k DOWNWARD
with the first bit taken becoming the MOST significant of the result.
THE LAST HUFFMAN WEIGHT IS NOT STORED. Weights encode 2^(w-1) each, and the
total must reach the next power of two exactly; the final symbol's weight is
whatever completes it. A decoder that reads only the stored weights builds a
table missing its last symbol, which decodes most literals correctly and
then produces one wrong byte wherever that symbol appears.
genealogy_id: zstandard_rfc8878_bitstream
lineage_id: nx_zstd_bits_v1
license_tier: ORIGINAL
dependencies 1 imports · 11 importers
diagram shows first 10 each side; +0 more imports, +1 more importers in the complete lists below.
imports: nx_syscalls.nx
imported by: nx_zstd_bits_gate.nxnx_zstd_block.nxnx_zstd_block_gate.nxnx_zstd_fse_dec.nxnx_zstd_fse_dec_gate.nxnx_zstd_huf.nxnx_zstd_huf_gate.nxnx_zstd_lit.nxnx_zstd_lit_gate.nxnx_zstd_seqdec.nxnx_zstd_seqdec_gate.nx
structs
| 38 | struct NxZstdBits |
consts
| 34 | const NX_ZB_READER_BYTES: i64 = 40 |
| 35 | const NX_ZB_MAX_WEIGHTS: i64 = 256 |
| 36 | const NX_ZB_MAX_TABLELOG: i64 = 12 |
functions
| 45 | func nx_zb_at(d: *u8, i: i64) -> i64 { return (d[i] as i64) & 255 } |
| 48 | func nx_zb_highbit8(v: i64) -> i64 |
| 64 | func nx_zstd_bits_init(d: *u8, n: i64) -> *NxZstdBits called by 6: mainnx_zstd_block_decompressmainmainnx_zstd_lit_hufmain calls 3: nx_zb_atnx_zb_highbit8sys_mmap |
| 78 | func nx_zstd_bits_remaining(b: *NxZstdBits) -> i64 |
| 84 | func nx_zstd_bits_read(b: *NxZstdBits, nbits: i64) -> i64 |
| 106 | func nx_zstd_bits_peek(b: *NxZstdBits, nbits: i64) -> i64 |
| 127 | func nx_zstd_bits_skip(b: *NxZstdBits, nbits: i64) -> i64 |
| 141 | func nx_zstd_weights_direct(d: *u8, n: i64, off: i64, hdr: i64, out: *i64) -> i64 |
| 168 | func nx_zstd_weights_complete(out: *i64, count: i64) -> i64 |
| 202 | func nx_zstd_weights_tablelog(out: *i64, total_count: i64) -> i64 |
| 220 | func nx_zstd_weights_to_lengths(w: *i64, count: i64, table_log: i64, out_len: *i64) -> i64 called by 1: main |