nx_jpeg_marker_test.nx source
↩ module page · 188 lines · 9500 B
1// nx_jpeg_marker_test.nx -- KAT for JPEG marker scanner.
2//
3// Exercises:
4// - minimal SOI/EOI document
5// - SOI, APP0 (with payload), DQT (with payload), SOF0, SOS, EOI sequence
6// - marker classification (SOF0 vs SOF2 vs SOF_OTHER)
7// - length-less markers (SOI/EOI/RSTn)
8// - 0xFF fill-byte tolerance between segments
9// - 0xFF 0x00 stuffing-byte rejection as marker (should be skipped)
10// - truncation detection (length runs past buffer)
11//
12// expect_exit: 0
13// license_tier: ORIGINAL
14
15import "nx_syscalls.nx"
16import "nx_jpeg_marker.nx"
17
18func _fail(n: i64) -> i64 {
19 let b: *u8 = sys_mmap(16)
20 b[0]=0x46; b[1]=0x41; b[2]=0x49; b[3]=0x4C; b[4]=0x3D
21 sys_write(2, b, 5)
22 var x: i64 = n
23 if x < 0 { let m: *u8 = sys_mmap(4); m[0]=0x2D; sys_write(2, m, 1); x = 0 - x }
24 if x == 0 { let z: *u8 = sys_mmap(4); z[0]=0x30; sys_write(2, z, 1) }
25 else {
26 let buf: *u8 = sys_mmap(16)
27 var pos: i64 = 0
28 while x > 0 { buf[pos] = (0x30 + (x % 10)) as u8; x = x / 10; pos = pos + 1 }
29 let out: *u8 = sys_mmap(16)
30 var i: i64 = 0
31 while i < pos { out[i] = buf[pos - 1 - i]; i = i + 1 }
32 sys_write(2, out, pos)
33 }
34 let nl: *u8 = sys_mmap(4); nl[0]=0x0A; sys_write(2, nl, 1)
35 return 0
36}
37
38func main() -> i64 {
39 // ============================================================
40 // Section A: classification + length-less predicates
41 // ============================================================
42 if nx_jpeg_classify_marker(0xD8) != NX_JPEG_M_SOI { _fail(1); return 1 }
43 if nx_jpeg_classify_marker(0xD9) != NX_JPEG_M_EOI { _fail(2); return 2 }
44 if nx_jpeg_classify_marker(0xC0) != NX_JPEG_M_SOF0 { _fail(3); return 3 }
45 if nx_jpeg_classify_marker(0xC2) != NX_JPEG_M_SOF2 { _fail(4); return 4 }
46 if nx_jpeg_classify_marker(0xC1) != NX_JPEG_M_SOF_OTHER { _fail(5); return 5 } // extended-sequential
47 if nx_jpeg_classify_marker(0xC4) != NX_JPEG_M_DHT { _fail(6); return 6 }
48 if nx_jpeg_classify_marker(0xDB) != NX_JPEG_M_DQT { _fail(7); return 7 }
49 if nx_jpeg_classify_marker(0xDA) != NX_JPEG_M_SOS { _fail(8); return 8 }
50 if nx_jpeg_classify_marker(0xDD) != NX_JPEG_M_DRI { _fail(9); return 9 }
51 if nx_jpeg_classify_marker(0xE0) != NX_JPEG_M_APP { _fail(10); return 10 }
52 if nx_jpeg_classify_marker(0xEF) != NX_JPEG_M_APP { _fail(11); return 11 }
53 if nx_jpeg_classify_marker(0xFE) != NX_JPEG_M_COM { _fail(12); return 12 }
54 if nx_jpeg_classify_marker(0xD0) != NX_JPEG_M_RST { _fail(13); return 13 }
55 if nx_jpeg_classify_marker(0xD7) != NX_JPEG_M_RST { _fail(14); return 14 }
56
57 if nx_jpeg_marker_is_lengthless(0xD8) != 1 { _fail(20); return 20 }
58 if nx_jpeg_marker_is_lengthless(0xD9) != 1 { _fail(21); return 21 }
59 if nx_jpeg_marker_is_lengthless(0xD0) != 1 { _fail(22); return 22 }
60 if nx_jpeg_marker_is_lengthless(0xD7) != 1 { _fail(23); return 23 }
61 if nx_jpeg_marker_is_lengthless(0xC0) != 0 { _fail(24); return 24 }
62 if nx_jpeg_marker_is_lengthless(0xDB) != 0 { _fail(25); return 25 }
63
64 // ============================================================
65 // Section B: minimal SOI / EOI document (4 bytes)
66 // ============================================================
67 let s_min: *u8 = sys_mmap(8)
68 s_min[0]=0xFF; s_min[1]=0xD8; s_min[2]=0xFF; s_min[3]=0xD9
69
70 let c: *NxJpegCursor = sys_mmap(NX_JPEG_CURSOR_BYTES) as *NxJpegCursor
71 let seg: *NxJpegSegment = sys_mmap(NX_JPEG_SEG_BYTES) as *NxJpegSegment
72
73 nx_jpeg_seg_init(c, s_min, 4)
74 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(30); return 30 }
75 if seg.marker != 0xD8 { _fail(31); return 31 }
76 if seg.kind != NX_JPEG_M_SOI { _fail(32); return 32 }
77 if seg.seg_off != 0 { _fail(33); return 33 }
78 if seg.seg_len != 2 { _fail(34); return 34 }
79 if seg.payload_len != 0 { _fail(35); return 35 }
80
81 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(40); return 40 }
82 if seg.marker != 0xD9 { _fail(41); return 41 }
83 if seg.kind != NX_JPEG_M_EOI { _fail(42); return 42 }
84 if seg.seg_off != 2 { _fail(43); return 43 }
85 if seg.seg_len != 2 { _fail(44); return 44 }
86
87 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_EOF { _fail(50); return 50 }
88
89 // ============================================================
90 // Section C: full canonical structure
91 // SOI(0) APP0(2..) DQT(..) SOF0(..) SOS(..) EOI(..)
92 // APP0 payload = JFIF magic (16 bytes typical, here we use 4 for test).
93 // ============================================================
94 let s: *u8 = sys_mmap(128)
95 var k: i64 = 0
96 s[k]=0xFF; k=k+1; s[k]=0xD8; k=k+1 // SOI
97 // APP0: 0xFF E0 LL LL payload(4)
98 s[k]=0xFF; k=k+1; s[k]=0xE0; k=k+1
99 s[k]=0x00; k=k+1; s[k]=0x06; k=k+1 // length=6 (incl LL)
100 s[k]=0x4A; k=k+1; s[k]=0x46; k=k+1; s[k]=0x49; k=k+1; s[k]=0x46; k=k+1 // "JFIF"
101 // DQT: 0xFF DB LL LL payload(2)
102 s[k]=0xFF; k=k+1; s[k]=0xDB; k=k+1
103 s[k]=0x00; k=k+1; s[k]=0x04; k=k+1 // length=4
104 s[k]=0x00; k=k+1; s[k]=0x10; k=k+1 // tiny payload
105 // SOF0: 0xFF C0 LL LL payload(3)
106 s[k]=0xFF; k=k+1; s[k]=0xC0; k=k+1
107 s[k]=0x00; k=k+1; s[k]=0x05; k=k+1 // length=5
108 s[k]=0x08; k=k+1; s[k]=0x00; k=k+1; s[k]=0x01; k=k+1
109 // SOS: 0xFF DA LL LL payload(2)
110 s[k]=0xFF; k=k+1; s[k]=0xDA; k=k+1
111 s[k]=0x00; k=k+1; s[k]=0x04; k=k+1
112 s[k]=0x01; k=k+1; s[k]=0x00; k=k+1
113 // EOI
114 s[k]=0xFF; k=k+1; s[k]=0xD9; k=k+1
115 let total_len: i64 = k
116
117 nx_jpeg_seg_init(c, s, total_len)
118
119 // 1: SOI
120 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(60); return 60 }
121 if seg.kind != NX_JPEG_M_SOI { _fail(61); return 61 }
122
123 // 2: APP0
124 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(70); return 70 }
125 if seg.kind != NX_JPEG_M_APP { _fail(71); return 71 }
126 if seg.marker != 0xE0 { _fail(72); return 72 }
127 if seg.payload_len != 4 { _fail(73); return 73 }
128 if s[seg.payload_off] != 0x4A { _fail(74); return 74 } // 'J'
129 if s[seg.payload_off + 3] != 0x46 { _fail(75); return 75 } // 'F'
130
131 // 3: DQT
132 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(80); return 80 }
133 if seg.kind != NX_JPEG_M_DQT { _fail(81); return 81 }
134 if seg.payload_len != 2 { _fail(82); return 82 }
135 if s[seg.payload_off] != 0x00 { _fail(83); return 83 }
136 if s[seg.payload_off + 1] != 0x10 { _fail(84); return 84 }
137
138 // 4: SOF0
139 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(90); return 90 }
140 if seg.kind != NX_JPEG_M_SOF0 { _fail(91); return 91 }
141 if seg.payload_len != 3 { _fail(92); return 92 }
142 if s[seg.payload_off] != 0x08 { _fail(93); return 93 }
143 if s[seg.payload_off + 2] != 0x01 { _fail(94); return 94 }
144
145 // 5: SOS
146 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(100); return 100 }
147 if seg.kind != NX_JPEG_M_SOS { _fail(101); return 101 }
148 if seg.payload_len != 2 { _fail(102); return 102 }
149
150 // 6: EOI
151 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(110); return 110 }
152 if seg.kind != NX_JPEG_M_EOI { _fail(111); return 111 }
153
154 // 7: EOF
155 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_EOF { _fail(120); return 120 }
156
157 // ============================================================
158 // Section D: 0xFF fill-byte tolerance + 0xFF 0x00 stuffing-byte
159 // stream = SOI 0xFF 0xFF 0xFF EOI (multiple fill bytes)
160 // ============================================================
161 let s2: *u8 = sys_mmap(16)
162 s2[0]=0xFF; s2[1]=0xD8 // SOI
163 s2[2]=0xFF; s2[3]=0xFF; s2[4]=0xFF; s2[5]=0xD9 // fill + EOI
164 nx_jpeg_seg_init(c, s2, 6)
165 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(130); return 130 }
166 if seg.kind != NX_JPEG_M_SOI { _fail(131); return 131 }
167 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(132); return 132 }
168 if seg.kind != NX_JPEG_M_EOI { _fail(133); return 133 }
169 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_EOF { _fail(134); return 134 }
170
171 // ============================================================
172 // Section E: malformed -- bogus length runs past buffer
173 // SOI then 0xFF DB with claimed length 0x00FF but only 4 bytes after
174 // ============================================================
175 let s3: *u8 = sys_mmap(16)
176 s3[0]=0xFF; s3[1]=0xD8 // SOI
177 s3[2]=0xFF; s3[3]=0xDB // DQT marker
178 s3[4]=0x00; s3[5]=0xFF // claimed length 255
179 s3[6]=0x00; s3[7]=0x00 // only 2 bytes follow
180 nx_jpeg_seg_init(c, s3, 8)
181 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_OK { _fail(140); return 140 } // SOI
182 if nx_jpeg_seg_next(c, seg) != NX_JPEG_SEG_TRUNC { _fail(141); return 141 }
183
184 let pass: *u8 = sys_mmap(16)
185 pass[0]=0x50; pass[1]=0x41; pass[2]=0x53; pass[3]=0x53; pass[4]=0x0A
186 sys_write(1, pass, 5)
187 return 0
188}