parse_tools_header decodes the post-filter chain of the TON substream in filters-factory
order (EFE-linear → ICCI → eICCI → EFE-nonlinear → LEF), each tool gated by its own
enable flag per the recursive header walk. Adds BitReader::read_max / bits_for_max: the
header's universal width rule, bits = ceil(log2(max_value+1)) (the reference
HeaderCoder::calc_bits_count). No header field has a fixed width, and some are
runtime-dependent — a max_symbol decoded earlier in a segment sets the width of the
weights after it (65535 ⇒ 16 bits, then 99 ⇒ 7).
Validated on real test256.bin, every field matching the reference and end_bit=973 —
all TON fields consumed exactly, up to the 3-bit pad closing the 63-byte segment.
The decoded parameters ARE the post-filters' fixture inputs: B1/100 = 125.61/130.91 =
efl_chroma's plane means; luma_min/max = 497/25320 and the 8 A1 weights = efn_filter's
luma_min_q/luma_max_q/weights_q15; icci_model_signalled_idx[Y]=0,[UV]=1 = the per-tile
eICCI model selection. Header parser and post-filters agree from opposite directions.
Also adds an end-to-end chain test: test256.bin → parse_container → SOZ → mANS fac
decode → −31 → z (2560 vals, 75 non-zero) → decode_hyper_scale → i_s, byte-exact
40960/40960 against the reference. Two independently-built subsystems, chained off raw
codestream bytes with no fixture input beyond the normative CDF/weight assets.
parse_tools_header takes the first filter's bit offset rather than the TON payload start:
_stream_header_part defaults to "tool_header", so other tools also emit into TON ahead of
the filter chain (two such bits precede EFE-linear here); locating that prefix in general
needs the full tool-tree walk.
Co-Authored-By: Claude Opus 4.8 <[email protected]>