nx_jpeg_marker.nx
buildroot/runtime/nx_jpeg_marker.nx
about
nx_jpeg_marker.nx -- JPEG segment marker scanner. Arc C1.1 of the
full JPEG decoder per ITU-T Rec. T.81 / ISO 10918-1 (1992).
JPEG file structure (T.81 sec B.1):
SOI marker (0xFF 0xD8)
one or more frame segments:
[misc tables: DQT, DHT, DRI, APPn, COM]
SOF (Start of Frame: 0xC0 baseline, 0xC2 progressive, etc.)
one or more scans:
SOS (Start of Scan: 0xFF 0xDA, then header, then entropy-coded segment)
[entropy-coded data with 0xFF 0x00 byte-stuffing]
EOI marker (0xFF 0xD9)
Segment format (variable-length kinds): 0xFF + marker_byte + 2-byte
big-endian length (length INCLUDES the 2 length bytes but NOT the
0xFF + marker) + (length-2) payload bytes.
Length-less markers: SOI (D8), EOI (D9), TEM (01), RSTn (D0..D7).
CRITICAL byte-stuffing rule (T.81 sec F.1.2.3): inside the
entropy-coded segment that follows SOS, a literal 0xFF in the
compressed bitstream is followed by 0x00. A real marker is
0xFF nn where nn != 0x00 and nn is not in D0..D7 (those are RSTn
markers that DO appear inside entropy data as restart points).
This primitive scans markers BEFORE the entropy stream gets
processed -- it walks from SOI through SOF/DQT/DHT segments and
stops at SOS (returning the SOS segment so caller knows where
the entropy stream begins). Decoding the entropy stream is the
job of nx_jpeg_entropy.nx (next stone).
nx_safety_envelope:
intended_use: "JPEG marker scanning for the bits-up image
decoder pipeline."
sil_target: SIL1
evidence: [t81_section_b1_canonical_basis,
sealed_marker_taxonomy,
bounded_iteration]
hazard_register: [bug-tape-jpeg-malformed-length-overflow,
bug-tape-jpeg-marker-byte-stuffing-mishandled]
dependencies 1 imports · 3 importers
imports: nx_syscalls.nx
imported by: nx_jpeg_ascii.nxnx_jpeg_decode.nxnx_jpeg_marker_test.nx
structs
| 106 | struct NxJpegSegment |
| 119 | struct NxJpegCursor |
consts
| 50 | const NX_JPEG_M_UNKNOWN: i64 = 0 |
| 51 | const NX_JPEG_M_SOI: i64 = 1 // 0xD8 start-of-image |
| 52 | const NX_JPEG_M_EOI: i64 = 2 // 0xD9 end-of-image |
| 53 | const NX_JPEG_M_SOF0: i64 = 3 // 0xC0 baseline DCT |
| 54 | const NX_JPEG_M_SOF2: i64 = 4 // 0xC2 progressive DCT |
| 55 | const NX_JPEG_M_SOF_OTHER: i64 = 5 // any other SOFn (extended/diff/lossless) |
| 56 | const NX_JPEG_M_DHT: i64 = 6 // 0xC4 Huffman table |
| 57 | const NX_JPEG_M_DQT: i64 = 7 // 0xDB quantization table |
| 58 | const NX_JPEG_M_DRI: i64 = 8 // 0xDD restart interval |
| 59 | const NX_JPEG_M_SOS: i64 = 9 // 0xDA start-of-scan |
| 60 | const NX_JPEG_M_APP: i64 = 10 // 0xE0..0xEF application segments |
| 61 | const NX_JPEG_M_COM: i64 = 11 // 0xFE comment |
| 62 | const NX_JPEG_M_RST: i64 = 12 // 0xD0..0xD7 restart markers |
| 63 | const NX_JPEG_M_OTHER: i64 = 13 // any other valid marker |
| 64 | const NX_JPEG_M_KIND_N: i64 = 14 |
| 115 | const NX_JPEG_SEG_BYTES: i64 = 48 |
| 125 | const NX_JPEG_CURSOR_BYTES: i64 = 24 |
| 129 | const NX_JPEG_SEG_OK: i64 = 0 |
| 130 | const NX_JPEG_SEG_EOF: i64 = 1 // cursor reached src_len cleanly |
| 131 | const NX_JPEG_SEG_MISALIGN: i64 = 2 // expected 0xFF but found something else |
| 132 | const NX_JPEG_SEG_TRUNC: i64 = 3 // segment length runs past src_len |
| 133 | const NX_JPEG_SEG_BAD_LEN: i64 = 4 // length field < 2 (must include itself) |
| 134 | const NX_JPEG_SEG_RESULT_N: i64 = 5 |
functions
| 66 | func nx_jpeg_m_kind_is_valid(k: i64) -> i64 |
| 73 | func nx_jpeg_classify_marker(m: i64) -> i64 |
| 96 | func nx_jpeg_marker_is_lengthless(m: i64) -> i64 |
| 136 | func nx_jpeg_seg_result_is_valid(v: i64) -> i64 |
| 144 | func nx_jpeg_seg_init(c: *NxJpegCursor, src: *u8, src_len: i64) -> i64 |
| 158 | func nx_jpeg_seg_next(c: *NxJpegCursor, out: *NxJpegSegment) -> i64 called by 3: _jpeg_ascii_probe_sofnx_jpeg_decodemain calls 2: nx_jpeg_classify_markernx_jpeg_marker_is_lengthless |