code wiki / (root) / nx_jpeg_dht_test.nx

nx_jpeg_dht_test.nx source

↩ module page · 195 lines · 8561 B

1// nx_jpeg_dht_test.nx -- KAT for DHT parser + Huffman decode. 2// 3// Test cases: 4// A. Synthetic 2-symbol table: BITS={1,1,0...}, HUFFVAL={0x05, 0x06}. 5// Symbol 0x05 -> code "0" (1 bit); symbol 0x06 -> code "10" (2 bits). 6// B. Decode test: bitstream "0 10 0 0" packed MSB-first = 0x40, 7// should yield symbols [0x05, 0x06, 0x05, 0x05]. 8// C. Dual-table payload (luma DC + luma AC stacked). 9// D. Malformed -- BITS sum >256 truncation. 10// 11// expect_exit: 0 12// license_tier: ORIGINAL 13 14import "nx_syscalls.nx" 15import "nx_jpeg_dht.nx" 16 17func _fail(n: i64) -> i64 { 18 let b: *u8 = sys_mmap(16) 19 b[0]=0x46; b[1]=0x41; b[2]=0x49; b[3]=0x4C; b[4]=0x3D 20 sys_write(2, b, 5) 21 var x: i64 = n 22 if x < 0 { let m: *u8 = sys_mmap(4); m[0]=0x2D; sys_write(2, m, 1); x = 0 - x } 23 if x == 0 { let z: *u8 = sys_mmap(4); z[0]=0x30; sys_write(2, z, 1) } 24 else { 25 let buf: *u8 = sys_mmap(16) 26 var pos: i64 = 0 27 while x > 0 { buf[pos] = (0x30 + (x % 10)) as u8; x = x / 10; pos = pos + 1 } 28 let out: *u8 = sys_mmap(16) 29 var i: i64 = 0 30 while i < pos { out[i] = buf[pos - 1 - i]; i = i + 1 } 31 sys_write(2, out, pos) 32 } 33 let nl: *u8 = sys_mmap(4); nl[0]=0x0A; sys_write(2, nl, 1) 34 return 0 35} 36 37func main() -> i64 { 38 let tables: *NxJpegHTable = sys_mmap(NX_JPEG_HTABLE_BYTES * 4) as *NxJpegHTable 39 let bits_pool: *i64 = sys_mmap(4 * 17 * 8) as *i64 40 let hv_pool: *i64 = sys_mmap(4 * 256 * 8) as *i64 41 let mc_pool: *i64 = sys_mmap(4 * 17 * 8) as *i64 42 let xc_pool: *i64 = sys_mmap(4 * 17 * 8) as *i64 43 let vp_pool: *i64 = sys_mmap(4 * 17 * 8) as *i64 44 let count_p: *i64 = sys_mmap(8) as *i64 45 46 // ============================================================ 47 // Section A: synthetic 2-symbol DHT 48 // Tc=0 (DC), Th=0 -> tc_th = 0x00 49 // BITS = {1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0} 50 // HUFFVAL = {0x05, 0x06} 51 // Total payload bytes = 1 + 16 + 2 = 19 52 // ============================================================ 53 let p_a: *u8 = sys_mmap(32) 54 p_a[0] = 0x00 // Tc=0, Th=0 55 p_a[1] = 1 // BITS[1] 56 p_a[2] = 1 // BITS[2] 57 var i: i64 = 3 58 while i <= 16 { p_a[i] = 0; i = i + 1 } 59 p_a[17] = 0x05 // HUFFVAL[0] 60 p_a[18] = 0x06 // HUFFVAL[1] 61 62 let rc_a: i64 = nx_jpeg_dht_parse(p_a, 19, tables, bits_pool, hv_pool, mc_pool, xc_pool, vp_pool, count_p) 63 if rc_a != NX_JPEG_DHT_OK { _fail(1); return 1 } 64 if count_p[0] != 1 { _fail(2); return 2 } 65 66 let t0: *NxJpegHTable = tables 67 if t0.tc != 0 { _fail(3); return 3 } 68 if t0.th != 0 { _fail(4); return 4 } 69 if t0.n_symbols != 2 { _fail(5); return 5 } 70 if t0.huffval[0] != 0x05 { _fail(6); return 6 } 71 if t0.huffval[1] != 0x06 { _fail(7); return 7 } 72 73 // Decode-table assertions per T.81 Fig C.3. 74 if t0.mincode[1] != 0 { _fail(10); return 10 } 75 if t0.maxcode[1] != 0 { _fail(11); return 11 } 76 if t0.valptr[1] != 0 { _fail(12); return 12 } 77 if t0.mincode[2] != 2 { _fail(13); return 13 } 78 if t0.maxcode[2] != 2 { _fail(14); return 14 } 79 if t0.valptr[2] != 1 { _fail(15); return 15 } 80 if t0.maxcode[3] != (0 - 1) { _fail(16); return 16 } 81 if t0.maxcode[16] != (0 - 1) { _fail(17); return 17 } 82 83 // ============================================================ 84 // Section B: decode bitstream 85 // bits: 0 10 0 0 (MSB-first) = 0b01000000 = 0x40 86 // expected symbols: 0x05, 0x06, 0x05, 0x05 87 // ============================================================ 88 let bit_src: *u8 = sys_mmap(8) 89 bit_src[0] = 0x40 90 bit_src[1] = 0x00 // padding (not consumed) 91 92 let bit_off_p: *i64 = sys_mmap(8) as *i64 93 let byte_idx_p: *i64 = sys_mmap(8) as *i64 94 bit_off_p[0] = 0 95 byte_idx_p[0] = 0 96 97 let s1: i64 = nx_jpeg_huff_decode_symbol(t0, bit_src, bit_off_p, byte_idx_p, 2) 98 if s1 != 0x05 { _fail(20); return 20 } 99 let s2: i64 = nx_jpeg_huff_decode_symbol(t0, bit_src, bit_off_p, byte_idx_p, 2) 100 if s2 != 0x06 { _fail(21); return 21 } 101 let s3: i64 = nx_jpeg_huff_decode_symbol(t0, bit_src, bit_off_p, byte_idx_p, 2) 102 if s3 != 0x05 { _fail(22); return 22 } 103 let s4: i64 = nx_jpeg_huff_decode_symbol(t0, bit_src, bit_off_p, byte_idx_p, 2) 104 if s4 != 0x05 { _fail(23); return 23 } 105 106 // ============================================================ 107 // Section C: dual-table payload (DC + AC). 108 // First: same as Section A (Tc=0, Th=0, 2 symbols). 109 // Second: Tc=1 Th=0, BITS={2,0...}, HUFFVAL={0x11, 0x22}. 110 // ============================================================ 111 let p_c: *u8 = sys_mmap(64) 112 p_c[0] = 0x00; p_c[1] = 1; p_c[2] = 1 113 i = 3 114 while i <= 16 { p_c[i] = 0; i = i + 1 } 115 p_c[17] = 0x05; p_c[18] = 0x06 116 p_c[19] = 0x10 // Tc=1 (AC), Th=0 117 p_c[20] = 2 // BITS[1]=2 -- two codes of length 1 118 i = 21 119 while i <= 35 { p_c[i] = 0; i = i + 1 } 120 p_c[36] = 0x11 121 p_c[37] = 0x22 122 123 let rc_c: i64 = nx_jpeg_dht_parse(p_c, 38, tables, bits_pool, hv_pool, mc_pool, xc_pool, vp_pool, count_p) 124 if rc_c != NX_JPEG_DHT_OK { _fail(30); return 30 } 125 if count_p[0] != 2 { _fail(31); return 31 } 126 127 let tc0: *NxJpegHTable = tables 128 let tc1: *NxJpegHTable = (tables as i64 + NX_JPEG_HTABLE_BYTES) as *NxJpegHTable 129 if tc0.tc != 0 { _fail(32); return 32 } 130 if tc1.tc != 1 { _fail(33); return 33 } 131 if tc1.n_symbols != 2 { _fail(34); return 34 } 132 if tc1.huffval[0] != 0x11 { _fail(35); return 35 } 133 if tc1.huffval[1] != 0x22 { _fail(36); return 36 } 134 // AC table has 2 codes of length 1: 0 -> 0x11, 1 -> 0x22. 135 if tc1.mincode[1] != 0 { _fail(37); return 37 } 136 if tc1.maxcode[1] != 1 { _fail(38); return 38 } 137 138 // ============================================================ 139 // Section D: malformed -- truncated payload 140 // ============================================================ 141 let p_d: *u8 = sys_mmap(16) 142 p_d[0] = 0x00; p_d[1] = 1; p_d[2] = 1 143 i = 3 144 while i <= 16 { p_d[i] = 0; i = i + 1 } 145 // claim 2 symbols but only provide 1 byte 146 p_d[17] = 0x05 147 let rc_d: i64 = nx_jpeg_dht_parse(p_d, 18, tables, bits_pool, hv_pool, mc_pool, xc_pool, vp_pool, count_p) 148 if rc_d != NX_JPEG_DHT_TRUNC { _fail(40); return 40 } 149 150 // ============================================================ 151 // Section E: 0xFF 0x00 byte-stuffing skip during decode 152 // Construct a bitstream that puts a 0xFF byte mid-stream 153 // followed by 0x00 stuffing. Decoder should skip the 0x00. 154 // ============================================================ 155 // table from Section A is in `t0`. Bitstream: 8 ones followed by 156 // another byte that starts with another code. 157 // With t0 (sym 0x05 = "0", sym 0x06 = "10"), an all-1s byte 0xFF 158 // followed by 0x00 stuffing then 0x40 means: each 1 starts a 159 // failed match in length 1, so they cascade. Simpler: just put 160 // bits "0 0 0 0 0 0 0 0" = 0x00 then a stuffed 0xFF that should 161 // be parsed as data byte 0xFF (not a marker) but we don't have 162 // raw 0xFF here -- we'd have to manually inject FF 00 sequence. 163 // 164 // Easiest test: arrange bits so first 8 symbols consume exactly 165 // one byte, hitting boundary. bitstream = 0xFF 0x00 0x40 means: 166 // - read byte 0xFF (8 bits of 1s) 167 // - encounter stuffing: skip 0x00 168 // - read byte 0x40 (= "01000000") 169 // With t0: 8 ones means decode tries len 1 (1>0 fail), len 2 170 // (3>maxcode[2]=2 fail), all 16 lengths fail -> returns -1. 171 // We don't want that. Use the AC table (tc1) which has codes 172 // of length 1: 0 -> 0x11, 1 -> 0x22. So 8 ones decode to 173 // eight 0x22 symbols. 174 let bs2: *u8 = sys_mmap(8) 175 bs2[0] = 0xFF 176 bs2[1] = 0x00 // stuffing byte (should be skipped) 177 bs2[2] = 0xFF // 8 more ones 178 bs2[3] = 0x00 // stuffing 179 bit_off_p[0] = 0 180 byte_idx_p[0] = 0 181 var n_decoded: i64 = 0 182 var loop_i: i64 = 0 183 while loop_i < 16 { 184 let s: i64 = nx_jpeg_huff_decode_symbol(tc1, bs2, bit_off_p, byte_idx_p, 4) 185 if s != 0x22 { _fail(50 + loop_i); return 50 } 186 n_decoded = n_decoded + 1 187 loop_i = loop_i + 1 188 } 189 if n_decoded != 16 { _fail(70); return 70 } 190 191 let pass: *u8 = sys_mmap(16) 192 pass[0]=0x50; pass[1]=0x41; pass[2]=0x53; pass[3]=0x53; pass[4]=0x0A 193 sys_write(1, pass, 5) 194 return 0 195}