nx_jpeg_tables_gate.nx source
↩ module page · 191 lines · 11493 B
1// nx_jpeg_tables_gate.nx -- the referee for the decoder's table slots (debt 1789603770, 2026-09-16). T.81 B.2.4.2 names every
2// DHT and DQT table and a later definition REPLACES it. The decoders appended tables by order of appearance into four slots,
3// so a progressive file (one DHT per scan: ri_diora_baird_1 carries 7 tables over 6 scans, ri_diora_baird_4 ten over ten)
4// wrote past the array (ARENA-OVERRUN prev_alloc_size=256 on every real decode) and a redefined table lost to its stale first
5// definition. In-process teeth on hand-built payloads: slots are keyed by name, a redefinition wins, twelve definitions leave
6// the slot count at eight, an undefined name reads absent, a class the standard lacks is refused by name and places nothing.
7// End-to-end teeth on two mirrored progressive stills: the decode agrees with an OUTSIDE decoder (libjpeg-turbo through
8// OpenCV 5.0.0 on the laptop, 2026-09-16) on the channel means -- the liar-killer no in-process tooth can supply; that
9// decoder never enters a build or run path, only its numbers do. Values are printed with gv_kv.
10// license_tier: ORIGINAL No hw writes (Rule 26).
11import "nx_syscalls.nx"
12import "nx_gate_verdict.nx"
13import "nx_jpeg_ascii.nx"
14
15const JT_I64: i64 = 8
16const JT_BYTE: i64 = 255
17const JT_BPP: i64 = 3
18const JT_DHT_HDR: i64 = 17
19const JT_BITS_N: i64 = 16
20const JT_DQT_VALUES: i64 = 64
21const JT_PAYLOAD_B: i64 = 128
22const JT_MEANS_N: i64 = 5
23const JT_ROUNDS: i64 = 3
24const JT_TOL_MEAN: i64 = 4
25const JT_FIX1: *u8 = "knowledge/fetched/ri_diora_baird_1.jpg"
26const JT_FIX1_W: i64 = 405
27const JT_FIX1_H: i64 = 500
28const JT_FIX1_R: i64 = 171
29const JT_FIX1_G: i64 = 156
30const JT_FIX1_B: i64 = 146
31const JT_FIX2: *u8 = "knowledge/fetched/ri_diora_baird_4.jpg"
32const JT_FIX2_W: i64 = 831
33const JT_FIX2_H: i64 = 1200
34const JT_FIX2_R: i64 = 119
35const JT_FIX2_G: i64 = 117
36const JT_FIX2_B: i64 = 80
37const JT_TC_DC: i64 = 0
38const JT_TC_AC: i64 = 1
39const JT_TC_BAD: i64 = 2
40const JT_TH_NEVER: i64 = 2
41const JT_TQ_A: i64 = 1
42const JT_TQ_NEVER: i64 = 0
43const JT_VAL_A: i64 = 7
44const JT_VAL_B: i64 = 9
45const JT_SYM_A: i64 = 0
46const JT_SYM_B: i64 = 5
47const JT_SYM_B2: i64 = 7
48const JT_SYM_C: i64 = 8
49const JT_E_UNREADABLE: i64 = 0 - 1
50
51func jt_abs(v: i64) -> i64 { if v < 0 { return 0 - v } return v }
52func jt_near(a: i64, b: i64, tol: i64) -> i64 { if jt_abs(a - b) <= tol { return 1 } return 0 }
53// one DHT table at buf+o: class/id byte, BITS with n1 codes of length 1 and n2 of length 2, then the symbols sym0.. ; returns its byte length
54func jt_dht_table(buf: *u8, o: i64, tc: i64, th: i64, n1: i64, n2: i64, sym0: i64) -> i64 {
55 buf[o] = (tc * 16 + th) as u8
56 var i: i64 = 1
57 while i <= JT_BITS_N { buf[o + i] = 0 as u8; i = i + 1 }
58 buf[o + 1] = n1 as u8
59 buf[o + 2] = n2 as u8
60 var k: i64 = 0
61 while k < n1 + n2 { buf[o + JT_DHT_HDR + k] = (sym0 + k) as u8; k = k + 1 }
62 return JT_DHT_HDR + n1 + n2
63}
64// one 8-bit DQT table at buf+o with every value equal; returns its byte length
65func jt_dqt_table(buf: *u8, o: i64, tq: i64, value: i64) -> i64 {
66 buf[o] = tq as u8
67 var k: i64 = 0
68 while k < JT_DQT_VALUES { buf[o + 1 + k] = value as u8; k = k + 1 }
69 return 1 + JT_DQT_VALUES
70}
71// decode a mirrored still: out = w, h, mean R, mean G, mean B; returns the decoder's verdict, or JT_E_UNREADABLE
72func jt_decode_means(path: *u8, out: *i64) -> i64 {
73 let fl: *i64 = sys_mmap(16) as *i64
74 fl[0] = 0
75 let jpeg: *u8 = sys_read_file(path, fl)
76 if (jpeg as i64) == 0 { return JT_E_UNREADABLE }
77 if fl[0] <= 0 { return JT_E_UNREADABLE }
78 let orgb: *i64 = sys_mmap(JT_I64) as *i64
79 let ow: *i64 = sys_mmap(JT_I64) as *i64
80 let oh: *i64 = sys_mmap(JT_I64) as *i64
81 let rc: i64 = nx_jpeg_decode_rgb(jpeg, fl[0], orgb, ow, oh)
82 if rc != NX_JPEG_ASCII_OK { return rc }
83 let rgb: *u8 = orgb[0] as *u8
84 let n: i64 = ow[0] * oh[0]
85 var sr: i64 = 0
86 var sg: i64 = 0
87 var sb: i64 = 0
88 var i: i64 = 0
89 while i < n {
90 let o: i64 = i * JT_BPP
91 sr = sr + ((rgb[o] as i64) & JT_BYTE)
92 sg = sg + ((rgb[o + 1] as i64) & JT_BYTE)
93 sb = sb + ((rgb[o + 2] as i64) & JT_BYTE)
94 i = i + 1
95 }
96 out[0] = ow[0]
97 out[1] = oh[0]
98 out[2] = sr / n
99 out[3] = sg / n
100 out[4] = sb / n
101 return rc
102}
103func main() -> i64 {
104 let ctr: *i64 = gv_ctr()
105 let ctx: *NxJpegDecCtx = sys_mmap(NX_JPEG_DEC_CTX_BYTES) as *NxJpegDecCtx
106 nx_jpeg_dec_ctx_init(ctx)
107 gv_check("fresh-context-eight-keyed-huffman-slots" as *u8, (ctx.n_htables == NX_JPEG_HSLOTS) as i64, ctr)
108 gv_check("fresh-context-four-keyed-quant-slots" as *u8, (ctx.n_qtables == NX_JPEG_QSLOTS) as i64, ctr)
109 gv_check("undefined-name-reads-absent" as *u8, ((nx_jpeg_ctx_htable(ctx, JT_TC_DC, 0) as i64) == 0) as i64, ctr)
110 // payload A: DC0 with three codes; payload B: DC0 redefined with two codes plus AC1 with one; payload C: AC0 with two
111 let pa: *u8 = sys_mmap(JT_PAYLOAD_B)
112 let la: i64 = jt_dht_table(pa, 0, JT_TC_DC, 0, 1, 2, JT_SYM_A)
113 let pb: *u8 = sys_mmap(JT_PAYLOAD_B)
114 var lb: i64 = jt_dht_table(pb, 0, JT_TC_DC, 0, 2, 0, JT_SYM_B)
115 lb = lb + jt_dht_table(pb, lb, JT_TC_AC, 1, 1, 0, JT_SYM_B2)
116 let pc: *u8 = sys_mmap(JT_PAYLOAD_B)
117 let lc: i64 = jt_dht_table(pc, 0, JT_TC_AC, 0, 1, 1, JT_SYM_C)
118 gv_check("payload-a-parses" as *u8, (nx_jpeg_ctx_parse_dht(ctx, pa, la) == NX_JPEG_DHT_OK) as i64, ctr)
119 let t0: *NxJpegHTable = nx_jpeg_ctx_htable(ctx, JT_TC_DC, 0)
120 gv_check("dc0-defined-by-payload-a" as *u8, ((t0 as i64) != 0) as i64, ctr)
121 gv_check("dc0-three-symbols-after-a" as *u8, (t0.n_symbols == 3) as i64, ctr)
122 gv_check("payload-b-parses" as *u8, (nx_jpeg_ctx_parse_dht(ctx, pb, lb) == NX_JPEG_DHT_OK) as i64, ctr)
123 let t0b: *NxJpegHTable = nx_jpeg_ctx_htable(ctx, JT_TC_DC, 0)
124 gv_check("redefinition-wins-dc0-two-symbols-after-b" as *u8, (t0b.n_symbols == 2) as i64, ctr)
125 gv_check("redefinition-wins-dc0-first-symbol-is-b" as *u8, (t0b.huffval[0] == JT_SYM_B) as i64, ctr)
126 gv_check("redefinition-lands-in-the-same-slot" as *u8, ((t0b as i64) == (t0 as i64)) as i64, ctr)
127 let t11: *NxJpegHTable = nx_jpeg_ctx_htable(ctx, JT_TC_AC, 1)
128 gv_check("ac1-defined-by-payload-b" as *u8, ((t11 as i64) != 0) as i64, ctr)
129 gv_check("payload-c-parses" as *u8, (nx_jpeg_ctx_parse_dht(ctx, pc, lc) == NX_JPEG_DHT_OK) as i64, ctr)
130 let t10: *NxJpegHTable = nx_jpeg_ctx_htable(ctx, JT_TC_AC, 0)
131 gv_check("ac0-two-symbols-after-c" as *u8, (t10.n_symbols == 2) as i64, ctr)
132 // twelve definitions in all: the old append ran eight tables past a four-slot array; the keyed area does not move
133 var rounds: i64 = 0
134 var okall: i64 = 1
135 while rounds < JT_ROUNDS {
136 if nx_jpeg_ctx_parse_dht(ctx, pa, la) != NX_JPEG_DHT_OK { okall = 0 }
137 if nx_jpeg_ctx_parse_dht(ctx, pb, lb) != NX_JPEG_DHT_OK { okall = 0 }
138 if nx_jpeg_ctx_parse_dht(ctx, pc, lc) != NX_JPEG_DHT_OK { okall = 0 }
139 rounds = rounds + 1
140 }
141 gv_check("twelve-definitions-all-parse" as *u8, okall, ctr)
142 gv_check("slot-count-unchanged-after-twelve-definitions" as *u8, (ctx.n_htables == NX_JPEG_HSLOTS) as i64, ctr)
143 let t0c: *NxJpegHTable = nx_jpeg_ctx_htable(ctx, JT_TC_DC, 0)
144 gv_check("dc0-still-the-latest-definition" as *u8, (t0c.n_symbols == 2) as i64, ctr)
145 gv_check("never-defined-dc2-stays-absent" as *u8, ((nx_jpeg_ctx_htable(ctx, JT_TC_DC, JT_TH_NEVER) as i64) == 0) as i64, ctr)
146 // neg-control: a class the standard does not have is refused by name and changes no slot
147 let pbad: *u8 = sys_mmap(JT_PAYLOAD_B)
148 let lbad: i64 = jt_dht_table(pbad, 0, JT_TC_BAD, 0, 1, 0, 1)
149 gv_check("neg-control-bad-class-refused-by-name" as *u8, (nx_jpeg_ctx_parse_dht(ctx, pbad, lbad) == NX_JPEG_DHT_BAD_TC) as i64, ctr)
150 let t0d: *NxJpegHTable = nx_jpeg_ctx_htable(ctx, JT_TC_DC, 0)
151 gv_check("neg-control-refusal-changes-no-slot" as *u8, (t0d.n_symbols == 2) as i64, ctr)
152 // quantisation tables: keyed by Tq, a redefinition wins, the count is fixed
153 let qa: *u8 = sys_mmap(JT_PAYLOAD_B)
154 let lqa: i64 = jt_dqt_table(qa, 0, JT_TQ_A, JT_VAL_A)
155 let qb: *u8 = sys_mmap(JT_PAYLOAD_B)
156 let lqb: i64 = jt_dqt_table(qb, 0, JT_TQ_A, JT_VAL_B)
157 gv_check("dqt-a-parses" as *u8, (nx_jpeg_ctx_parse_dqt(ctx, qa, lqa) == NX_JPEG_DQT_OK) as i64, ctr)
158 let q1: *NxJpegQTable = nx_jpeg_ctx_qtable(ctx, JT_TQ_A)
159 gv_check("tq1-defined-by-dqt-a" as *u8, ((q1 as i64) != 0) as i64, ctr)
160 gv_check("tq1-first-value-after-a" as *u8, (q1.values[0] == JT_VAL_A) as i64, ctr)
161 gv_check("dqt-b-parses" as *u8, (nx_jpeg_ctx_parse_dqt(ctx, qb, lqb) == NX_JPEG_DQT_OK) as i64, ctr)
162 let q1b: *NxJpegQTable = nx_jpeg_ctx_qtable(ctx, JT_TQ_A)
163 gv_check("redefinition-wins-tq1-first-value-after-b" as *u8, (q1b.values[0] == JT_VAL_B) as i64, ctr)
164 gv_check("never-defined-tq0-stays-absent" as *u8, ((nx_jpeg_ctx_qtable(ctx, JT_TQ_NEVER) as i64) == 0) as i64, ctr)
165 gv_check("quant-slot-count-unchanged" as *u8, (ctx.n_qtables == NX_JPEG_QSLOTS) as i64, ctr)
166 // end to end on the mirrored stills, against the outside decoder's channel means
167 let m1: *i64 = sys_mmap(JT_MEANS_N * JT_I64) as *i64
168 let rc1: i64 = jt_decode_means(JT_FIX1, m1)
169 gv_check("fixture-ri-1-readable" as *u8, (rc1 != JT_E_UNREADABLE) as i64, ctr)
170 gv_check("ri-1-progressive-seven-tables-decodes" as *u8, (rc1 == NX_JPEG_ASCII_OK) as i64, ctr)
171 gv_check("ri-1-width" as *u8, (m1[0] == JT_FIX1_W) as i64, ctr)
172 gv_check("ri-1-height" as *u8, (m1[1] == JT_FIX1_H) as i64, ctr)
173 gv_check("ri-1-mean-red-agrees-with-outside-decoder" as *u8, jt_near(m1[2], JT_FIX1_R, JT_TOL_MEAN), ctr)
174 gv_check("ri-1-mean-green-agrees-with-outside-decoder" as *u8, jt_near(m1[3], JT_FIX1_G, JT_TOL_MEAN), ctr)
175 gv_check("ri-1-mean-blue-agrees-with-outside-decoder" as *u8, jt_near(m1[4], JT_FIX1_B, JT_TOL_MEAN), ctr)
176 let m2: *i64 = sys_mmap(JT_MEANS_N * JT_I64) as *i64
177 let rc2: i64 = jt_decode_means(JT_FIX2, m2)
178 gv_check("fixture-ri-4-readable" as *u8, (rc2 != JT_E_UNREADABLE) as i64, ctr)
179 gv_check("ri-4-progressive-ten-tables-decodes" as *u8, (rc2 == NX_JPEG_ASCII_OK) as i64, ctr)
180 gv_check("ri-4-width" as *u8, (m2[0] == JT_FIX2_W) as i64, ctr)
181 gv_check("ri-4-height" as *u8, (m2[1] == JT_FIX2_H) as i64, ctr)
182 gv_check("ri-4-mean-red-agrees-with-outside-decoder" as *u8, jt_near(m2[2], JT_FIX2_R, JT_TOL_MEAN), ctr)
183 gv_check("ri-4-mean-green-agrees-with-outside-decoder" as *u8, jt_near(m2[3], JT_FIX2_G, JT_TOL_MEAN), ctr)
184 gv_check("ri-4-mean-blue-agrees-with-outside-decoder" as *u8, jt_near(m2[4], JT_FIX2_B, JT_TOL_MEAN), ctr)
185 gv_values_head()
186 gv_kv("huffman_slots" as *u8, ctx.n_htables)
187 gv_kv("quant_slots" as *u8, ctx.n_qtables)
188 gv_kv("ri1_rc" as *u8, rc1); gv_kv("ri1_w" as *u8, m1[0]); gv_kv("ri1_h" as *u8, m1[1]); gv_kv("ri1_mean_r" as *u8, m1[2]); gv_kv("ri1_mean_g" as *u8, m1[3]); gv_kv("ri1_mean_b" as *u8, m1[4])
189 gv_kv("ri4_rc" as *u8, rc2); gv_kv("ri4_w" as *u8, m2[0]); gv_kv("ri4_h" as *u8, m2[1]); gv_kv("ri4_mean_r" as *u8, m2[2]); gv_kv("ri4_mean_g" as *u8, m2[3]); gv_kv("ri4_mean_b" as *u8, m2[4])
190 return gv_verdict("nx_jpeg_tables_gate" as *u8, ctr, "decoder table slots keyed by the name T.81 gives them: a redefinition replaces, twelve definitions leave eight slots, an undefined name reads absent, a class the standard lacks is refused, and two progressive stills with seven and ten tables decode to the outside decoder's channel means" as *u8)
191}