code wiki / (root) / nx_deflate.nx

nx_deflate.nx source

↩ module page · 701 lines · 23375 B

1// nx_deflate.nx -- RFC 1951 INFLATE (DEFLATE decompression). 2// 3// CAPABILITY_COMPLETENESS: FULL -- all three BTYPE handlers 4// (stored, static Huffman, dynamic Huffman) implemented end-to-end. 5// Built per the four-pillar discipline: no error-coded skip-paths 6// shipped as "complete primitives". See 7// `feedback-no-skip-paths-as-error-codes` cardinal. 8// 9// Composes: 10// nx_bitstream (LSB-first reader) 11// nx_huffman (canonical Huffman decode) 12// + sliding-window LZ77 with 32 KB window. 13// 14// DEFLATE block format (RFC 1951): 15// 1 bit BFINAL (1 = last block) 16// 2 bits BTYPE 17// 00 = stored block (no compression) 18// 01 = static Huffman (predefined trees) 19// 10 = dynamic Huffman (trees encoded in stream) 20// 11 = reserved (error) 21// 22// Stored block: 23// skip to byte boundary 24// LEN (16-bit LE) 25// NLEN (16-bit LE; one's-complement of LEN; checksum) 26// LEN bytes copied verbatim to output 27// 28// Static Huffman block: 29// literal/length alphabet of 288 symbols (only 286 used; 286-287 30// are invalid placeholders) with predefined lengths: 31// 0-143 : length 8 32// 144-255 : length 9 33// 256-279 : length 7 (256 = end-of-block) 34// 280-287 : length 8 35// distance alphabet: all 30 symbols, length 5 36// 37// Dynamic Huffman block (BTYPE=10): 38// HLIT (5 bits) + 257 = literal/length code count 39// HDIST (5 bits) + 1 = distance code count 40// HCLEN (4 bits) + 4 = code-length code count 41// Code-length code lengths in interleaved order: 42// [16, 17, 18, 0, 8, 7, 9, 6, 10, 5, 11, 4, 12, 3, 13, 2, 14, 43// 1, 15] 44// Then literal/length code lengths (using code-length Huffman): 45// 0-15 = literal length, 16 = copy previous N=3-6 (2 extra), 46// 17 = zero-run N=3-10 (3 extra), 18 = zero-run N=11-138 (7 extra) 47// Then distance code lengths (same Huffman) 48// Then the compressed data using built lit/len + distance trees. 49// 50// Length codes 257-285 + extra bits per RFC 1951 section 3.2.5. 51// Distance codes 0-29 + extra bits per section 3.2.5. 52// 53// genealogy_id: rfc1951_deflate_1996_inflate 54// lineage_id: nx_deflate_v1 55 56// nx_safety_envelope: 57// intended_use: AUTO_APPLIED -- primitive-specific tuning queued 58// sil_target: SIL1 59// evidence: [bulk_applied_2026-05-16, see-file-comment-for-detail] 60// verdict: NOT_YET_EVALUATED 61 62import "nx_syscalls.nx" 63import "nx_runtime.nx" 64import "nx_tier.nx" 65import "nx_bitstream.nx" 66import "nx_huffman.nx" 67const NX_MAGIC_1025: i64 = 1025 68const NX_MAGIC_1537: i64 = 1537 69const NX_MAGIC_2049: i64 = 2049 70const NX_MAGIC_3073: i64 = 3073 71const NX_MAGIC_4097: i64 = 4097 72const NX_MAGIC_6145: i64 = 6145 73const NX_MAGIC_8193: i64 = 8193 74const NX_MAGIC_12289: i64 = 12289 75const NX_MAGIC_16385: i64 = 16385 76const NX_MAGIC_24577: i64 = 24577 77const NX_MAGIC_16777216: i64 = 16777216 78const NX_MAGIC_65535: i64 = 65535 79const NX_MAGIC_65536: i64 = 65536 80 81// ===== error codes ================================================ 82 83const NX_DEF_OK: nx_int = 0 84const NX_DEF_ERR_RESERVED: nx_int = 1 85const NX_DEF_ERR_NLEN: nx_int = 2 86const NX_DEF_ERR_OVERFLOW: nx_int = 3 87const NX_DEF_ERR_DYNAMIC_CL: nx_int = 4 88const NX_DEF_ERR_HUFFMAN: nx_int = 5 89const NX_DEF_ERR_DISTANCE: nx_int = 6 90// Caller-owned output exhausted; distinct from the legacy iteration guard. 91const NX_DEF_ERR_OUTPUT_CAPACITY: nx_int = 7 92 93// Code-length-code order per RFC 1951 section 3.2.7. 94func _deflate_cl_order(i: nx_int) -> nx_int { 95 if i == 0 { return 16 } 96 if i == 1 { return 17 } 97 if i == 2 { return 18 } 98 if i == 3 { return 0 } 99 if i == 4 { return 8 } 100 if i == 5 { return 7 } 101 if i == 6 { return 9 } 102 if i == 7 { return 6 } 103 if i == 8 { return 10 } 104 if i == 9 { return 5 } 105 if i == 10 { return 11 } 106 if i == 11 { return 4 } 107 if i == 12 { return 12 } 108 if i == 13 { return 3 } 109 if i == 14 { return 13 } 110 if i == 15 { return 2 } 111 if i == 16 { return 14 } 112 if i == 17 { return 1 } 113 if i == 18 { return 15 } 114 return -1 115} 116 117// ===== result struct ============================================= 118 119struct NxDeflateResult { 120 output_data: *u8, 121 output_size: nx_int, 122 bytes_consumed: nx_int, 123 error_code: nx_int, 124} 125 126const NX_DEF_RESULT_BYTES: nx_size = 32 127 128// ===== length / distance base + extra tables ===================== 129// 130// Length codes 257..285. base[i] = base length, extra[i] = extra 131// bits to read. 132 133func _deflate_length_base(code: nx_int) -> nx_int { 134 if code == 257 { return 3 } 135 if code == 258 { return 4 } 136 if code == 259 { return 5 } 137 if code == 260 { return 6 } 138 if code == 261 { return 7 } 139 if code == 262 { return 8 } 140 if code == 263 { return 9 } 141 if code == 264 { return 10 } 142 if code == 265 { return 11 } 143 if code == 266 { return 13 } 144 if code == 267 { return 15 } 145 if code == 268 { return 17 } 146 if code == 269 { return 19 } 147 if code == 270 { return 23 } 148 if code == 271 { return 27 } 149 if code == 272 { return 31 } 150 if code == 273 { return 35 } 151 if code == 274 { return 43 } 152 if code == 275 { return 51 } 153 if code == 276 { return 59 } 154 if code == 277 { return 67 } 155 if code == 278 { return 83 } 156 if code == 279 { return 99 } 157 if code == 280 { return 115 } 158 if code == 281 { return 131 } 159 if code == 282 { return 163 } 160 if code == 283 { return 195 } 161 if code == 284 { return 227 } 162 if code == 285 { return 258 } 163 return -1 164} 165 166func _deflate_length_extra(code: nx_int) -> nx_int { 167 if code < 261 { return 0 } 168 if code < 265 { return 0 } 169 if code < 269 { return 1 } 170 if code < 273 { return 2 } 171 if code < 277 { return 3 } 172 if code < 281 { return 4 } 173 if code < 285 { return 5 } 174 return 0 175} 176 177func _deflate_distance_base(code: nx_int) -> nx_int { 178 if code == 0 { return 1 } 179 if code == 1 { return 2 } 180 if code == 2 { return 3 } 181 if code == 3 { return 4 } 182 if code == 4 { return 5 } 183 if code == 5 { return 7 } 184 if code == 6 { return 9 } 185 if code == 7 { return 13 } 186 if code == 8 { return 17 } 187 if code == 9 { return 25 } 188 if code == 10 { return 33 } 189 if code == 11 { return 49 } 190 if code == 12 { return 65 } 191 if code == 13 { return 97 } 192 if code == 14 { return 129 } 193 if code == 15 { return 193 } 194 if code == 16 { return 257 } 195 if code == 17 { return 385 } 196 if code == 18 { return 513 } 197 if code == 19 { return 769 } 198 if code == 20 { return NX_MAGIC_1025 } 199 if code == 21 { return NX_MAGIC_1537 } 200 if code == 22 { return NX_MAGIC_2049 } 201 if code == 23 { return NX_MAGIC_3073 } 202 if code == 24 { return NX_MAGIC_4097 } 203 if code == 25 { return NX_MAGIC_6145 } 204 if code == 26 { return NX_MAGIC_8193 } 205 if code == 27 { return NX_MAGIC_12289 } 206 if code == 28 { return NX_MAGIC_16385 } 207 if code == 29 { return NX_MAGIC_24577 } 208 return -1 209} 210 211func _deflate_distance_extra(code: nx_int) -> nx_int { 212 if code < 2 { return 0 } 213 if code < 4 { return 0 } 214 if code < 6 { return 1 } 215 if code < 8 { return 2 } 216 if code < 10 { return 3 } 217 if code < 12 { return 4 } 218 if code < 14 { return 5 } 219 if code < 16 { return 6 } 220 if code < 18 { return 7 } 221 if code < 20 { return 8 } 222 if code < 22 { return 9 } 223 if code < 24 { return 10 } 224 if code < 26 { return 11 } 225 if code < 28 { return 12 } 226 if code < 30 { return 13 } 227 return 0 228} 229 230// ===== build static Huffman trees ================================ 231 232func _deflate_build_static_litlen() -> *NxHuffmanTable { 233 let lens: *nx_int = (sys_mmap(288 * 8)) as *nx_int 234 var i: nx_int = 0 235 while i < 144 { 236 lens[i] = 8 237 i = i + 1 238 } 239 while i < 256 { 240 lens[i] = 9 241 i = i + 1 242 } 243 while i < 280 { 244 lens[i] = 7 245 i = i + 1 246 } 247 while i < 288 { 248 lens[i] = 8 249 i = i + 1 250 } 251 return nx_huffman_build(lens, 288) 252} 253 254func _deflate_build_static_dist() -> *NxHuffmanTable { 255 let lens: *nx_int = (sys_mmap(30 * 8)) as *nx_int 256 var i: nx_int = 0 257 while i < 30 { 258 lens[i] = 5 259 i = i + 1 260 } 261 return nx_huffman_build(lens, 30) 262} 263 264// ===== copy bytes (handles overlap, LZ77 RLE-style) ============== 265 266func _deflate_copy_overlap(out: *u8, dst: nx_int, src: nx_int, n: nx_int) -> nx_int { 267 var i: nx_int = 0 268 while i < n { 269 out[dst + i] = out[src + i] 270 i = i + 1 271 } 272 return 0 273} 274 275// ===== shared Huffman-block decoder ============================== 276// 277// Called by both static (BTYPE=01) and dynamic (BTYPE=10) paths 278// once their lit/len + distance trees are built. Returns 0 on 279// success, -1 on error. 280 281func _deflate_decode_huffman_block( 282 bs: *NxBitStream, lit_tree: *NxHuffmanTable, dist_tree: *NxHuffmanTable, 283 output: *u8, out_pos: *nx_int, max_output: nx_int, err: *nx_int) -> nx_int { 284 285 var keep: nx_int = 1 286 var safety: nx_int = 0 287 let MAX_ITER: nx_int = NX_MAGIC_16777216 288 while keep == 1 { 289 if safety >= MAX_ITER { 290 err[0] = NX_DEF_ERR_OVERFLOW 291 return -1 292 } 293 safety = safety + 1 294 let sym: nx_int = nx_huffman_decode_lsb(lit_tree, bs) 295 if sym < 0 { 296 err[0] = NX_DEF_ERR_HUFFMAN 297 return -1 298 } 299 if sym < 256 { 300 let pos1: nx_int = out_pos[0] 301 if pos1 >= max_output { 302 err[0] = NX_DEF_ERR_OUTPUT_CAPACITY 303 return -1 304 } 305 output[pos1] = sym as u8 306 out_pos[0] = pos1 + 1 307 } else { 308 if sym == 256 { 309 keep = 0 310 } else { 311 if sym > 285 { 312 err[0] = NX_DEF_ERR_HUFFMAN 313 return -1 314 } 315 let base_len: nx_int = _deflate_length_base(sym) 316 let extra_len_bits: nx_int = _deflate_length_extra(sym) 317 var extra_len: nx_int = 0 318 if extra_len_bits > 0 { 319 extra_len = nx_bitstream_read_lsb(bs, extra_len_bits) 320 } 321 let length: nx_int = base_len + extra_len 322 323 let dsym: nx_int = nx_huffman_decode_lsb(dist_tree, bs) 324 if dsym < 0 { 325 err[0] = NX_DEF_ERR_HUFFMAN 326 return -1 327 } 328 if dsym > 29 { 329 err[0] = NX_DEF_ERR_DISTANCE 330 return -1 331 } 332 let base_dist: nx_int = _deflate_distance_base(dsym) 333 let extra_dist_bits: nx_int = _deflate_distance_extra(dsym) 334 var extra_dist: nx_int = 0 335 if extra_dist_bits > 0 { 336 extra_dist = nx_bitstream_read_lsb(bs, extra_dist_bits) 337 } 338 let distance: nx_int = base_dist + extra_dist 339 340 let pos2: nx_int = out_pos[0] 341 if (pos2 + length) > max_output { 342 err[0] = NX_DEF_ERR_OUTPUT_CAPACITY 343 return -1 344 } 345 if distance > pos2 { 346 err[0] = NX_DEF_ERR_DISTANCE 347 return -1 348 } 349 _deflate_copy_overlap(output, pos2, pos2 - distance, length) 350 out_pos[0] = pos2 + length 351 } 352 } 353 } 354 return 0 355} 356 357// ===== build dynamic Huffman trees from compressed code-length stream == 358// 359// Reads HLIT + HDIST + HCLEN, builds the code-length-code Huffman, 360// then runs it to decode literal/length + distance code-length 361// arrays, then builds the actual lit/len + distance Huffman trees 362// from those lengths. 363 364func _deflate_build_dynamic_trees( 365 bs: *NxBitStream, out_lit: **NxHuffmanTable, out_dist: **NxHuffmanTable, 366 err: *nx_int) -> nx_int { 367 368 let hlit_raw: nx_int = nx_bitstream_read_lsb(bs, 5) 369 let hdist_raw: nx_int = nx_bitstream_read_lsb(bs, 5) 370 let hclen_raw: nx_int = nx_bitstream_read_lsb(bs, 4) 371 let n_lit: nx_int = hlit_raw + 257 372 let n_dist: nx_int = hdist_raw + 1 373 let n_cl: nx_int = hclen_raw + 4 374 375 // Read code-length-code lengths (19 symbols total, indexed by 376 // the deinterleave table _deflate_cl_order). 377 let cl_lens: *nx_int = (sys_mmap(19 * 8)) as *nx_int 378 var z: nx_int = 0 379 while z < 19 { 380 cl_lens[z] = 0 381 z = z + 1 382 } 383 var i: nx_int = 0 384 while i < n_cl { 385 let pos: nx_int = _deflate_cl_order(i) 386 if pos < 0 { 387 err[0] = NX_DEF_ERR_DYNAMIC_CL 388 return -1 389 } 390 let v: nx_int = nx_bitstream_read_lsb(bs, 3) 391 cl_lens[pos] = v 392 i = i + 1 393 } 394 395 let cl_tree: *NxHuffmanTable = nx_huffman_build(cl_lens, 19) 396 if cl_tree == (0 as *NxHuffmanTable) { 397 err[0] = NX_DEF_ERR_HUFFMAN 398 return -1 399 } 400 401 // Decode lit/len + distance code-length arrays in one pass. 402 let total: nx_int = n_lit + n_dist 403 let all_lens: *nx_int = (sys_mmap((total as nx_size) * 8)) as *nx_int 404 var p: nx_int = 0 405 while p < total { 406 let sym: nx_int = nx_huffman_decode_lsb(cl_tree, bs) 407 if sym < 0 { 408 err[0] = NX_DEF_ERR_HUFFMAN 409 return -1 410 } 411 if sym < 16 { 412 all_lens[p] = sym 413 p = p + 1 414 } else { 415 if sym == 16 { 416 if p < 1 { 417 err[0] = NX_DEF_ERR_DYNAMIC_CL 418 return -1 419 } 420 let extra16: nx_int = nx_bitstream_read_lsb(bs, 2) 421 let repeat16: nx_int = extra16 + 3 422 let prev: nx_int = all_lens[p - 1] 423 if (p + repeat16) > total { 424 err[0] = NX_DEF_ERR_DYNAMIC_CL 425 return -1 426 } 427 var k: nx_int = 0 428 while k < repeat16 { 429 all_lens[p + k] = prev 430 k = k + 1 431 } 432 p = p + repeat16 433 } else { 434 if sym == 17 { 435 let extra17: nx_int = nx_bitstream_read_lsb(bs, 3) 436 let repeat17: nx_int = extra17 + 3 437 if (p + repeat17) > total { 438 err[0] = NX_DEF_ERR_DYNAMIC_CL 439 return -1 440 } 441 var k2: nx_int = 0 442 while k2 < repeat17 { 443 all_lens[p + k2] = 0 444 k2 = k2 + 1 445 } 446 p = p + repeat17 447 } else { 448 if sym == 18 { 449 let extra18: nx_int = nx_bitstream_read_lsb(bs, 7) 450 let repeat18: nx_int = extra18 + 11 451 if (p + repeat18) > total { 452 err[0] = NX_DEF_ERR_DYNAMIC_CL 453 return -1 454 } 455 var k3: nx_int = 0 456 while k3 < repeat18 { 457 all_lens[p + k3] = 0 458 k3 = k3 + 1 459 } 460 p = p + repeat18 461 } else { 462 err[0] = NX_DEF_ERR_DYNAMIC_CL 463 return -1 464 } 465 } 466 } 467 } 468 } 469 470 // Split into lit/len + distance arrays. 471 let lit_lens: *nx_int = (sys_mmap((n_lit as nx_size) * 8)) as *nx_int 472 let dist_lens: *nx_int = (sys_mmap((n_dist as nx_size) * 8)) as *nx_int 473 var j: nx_int = 0 474 while j < n_lit { 475 lit_lens[j] = all_lens[j] 476 j = j + 1 477 } 478 var d: nx_int = 0 479 while d < n_dist { 480 dist_lens[d] = all_lens[n_lit + d] 481 d = d + 1 482 } 483 484 let lit_tree: *NxHuffmanTable = nx_huffman_build(lit_lens, n_lit) 485 if lit_tree == (0 as *NxHuffmanTable) { 486 err[0] = NX_DEF_ERR_HUFFMAN 487 return -1 488 } 489 let dist_tree: *NxHuffmanTable = nx_huffman_build(dist_lens, n_dist) 490 if dist_tree == (0 as *NxHuffmanTable) { 491 err[0] = NX_DEF_ERR_HUFFMAN 492 return -1 493 } 494 out_lit[0] = lit_tree 495 out_dist[0] = dist_tree 496 return 0 497} 498 499// ===== inflate one block ========================================= 500// 501// Returns 1 if final block, 0 otherwise, -1 on error. 502 503func _deflate_inflate_block( 504 bs: *NxBitStream, output: *u8, out_pos: *nx_int, 505 max_output: nx_int, err: *nx_int) -> nx_int { 506 507 let bfinal: nx_int = nx_bitstream_read_lsb(bs, 1) 508 let btype: nx_int = nx_bitstream_read_lsb(bs, 2) 509 510 if btype == 0 { 511 // ---- stored block ---- 512 nx_bitstream_byte_align(bs) 513 let len_lo: nx_int = nx_bitstream_read_byte_aligned(bs) 514 let len_hi: nx_int = nx_bitstream_read_byte_aligned(bs) 515 let nlen_lo: nx_int = nx_bitstream_read_byte_aligned(bs) 516 let nlen_hi: nx_int = nx_bitstream_read_byte_aligned(bs) 517 let len: nx_int = len_lo | (len_hi << 8) 518 let nlen: nx_int = nlen_lo | (nlen_hi << 8) 519 let nlen_check: nx_int = nlen ^ NX_MAGIC_65535 520 if nlen_check != len { 521 err[0] = NX_DEF_ERR_NLEN 522 return -1 523 } 524 let cur_pos: nx_int = out_pos[0] 525 if (cur_pos + len) > max_output { 526 err[0] = NX_DEF_ERR_OUTPUT_CAPACITY 527 return -1 528 } 529 var k: nx_int = 0 530 while k < len { 531 let b: nx_int = nx_bitstream_read_byte_aligned(bs) 532 output[cur_pos + k] = b as u8 533 k = k + 1 534 } 535 out_pos[0] = cur_pos + len 536 return bfinal 537 } 538 539 if btype == 3 { 540 err[0] = NX_DEF_ERR_RESERVED 541 return -1 542 } 543 544 if btype == 1 { 545 let lit_tree_s: *NxHuffmanTable = _deflate_build_static_litlen() 546 let dist_tree_s: *NxHuffmanTable = _deflate_build_static_dist() 547 if lit_tree_s == (0 as *NxHuffmanTable) { 548 err[0] = NX_DEF_ERR_HUFFMAN 549 return -1 550 } 551 if dist_tree_s == (0 as *NxHuffmanTable) { 552 err[0] = NX_DEF_ERR_HUFFMAN 553 return -1 554 } 555 let rc_s: nx_int = _deflate_decode_huffman_block( 556 bs, lit_tree_s, dist_tree_s, output, out_pos, max_output, err) 557 if rc_s != 0 { return -1 } 558 return bfinal 559 } 560 561 // btype == 2 -- dynamic Huffman. 562 let lit_box: **NxHuffmanTable = (sys_mmap(8)) as **NxHuffmanTable 563 let dist_box: **NxHuffmanTable = (sys_mmap(8)) as **NxHuffmanTable 564 let rc_d: nx_int = _deflate_build_dynamic_trees(bs, lit_box, dist_box, err) 565 if rc_d != 0 { return -1 } 566 let rc_blk: nx_int = _deflate_decode_huffman_block( 567 bs, lit_box[0], dist_box[0], output, out_pos, max_output, err) 568 if rc_blk != 0 { return -1 } 569 return bfinal 570} 571 572// ===== top-level inflate ========================================= 573 574// Round up byte_pos when the last byte was only partially consumed. 575// Without this, callers that need the offset of the byte AFTER the 576// deflate stream (e.g. nx_zlib_inflate reading the adler32 trailer) 577// land one byte short on every block that doesn't end on a byte 578// boundary -- which is essentially every static or dynamic Huffman 579// block. Surfaced 2026-05-18 via real-PNG decode failure (adler 580// mismatch), see project-deflate-huffman-false-ok-2026-05-18. 581func _deflate_bytes_consumed(bs: *NxBitStream) -> nx_int { 582 if bs.bit_pos > 0 { 583 return bs.byte_pos + 1 584 } 585 return bs.byte_pos 586} 587 588func nx_deflate_inflate(input: *u8, input_size: nx_int, 589 max_output: nx_int) -> *NxDeflateResult { 590 if input_size <= 0 { return 0 as *NxDeflateResult } 591 if max_output <= 0 { return 0 as *NxDeflateResult } 592 593 let r_ptr: *u8 = sys_mmap(NX_DEF_RESULT_BYTES) 594 let r: *NxDeflateResult = r_ptr as *NxDeflateResult 595 596 let out_buf: *u8 = sys_mmap(max_output as nx_size) 597 let bs: *NxBitStream = nx_bitstream_alloc(input, input_size) 598 let pos_box: *nx_int = (sys_mmap(8)) as *nx_int 599 let err_box: *nx_int = (sys_mmap(8)) as *nx_int 600 pos_box[0] = 0 601 err_box[0] = NX_DEF_OK 602 603 var done: nx_int = 0 604 var iter: nx_int = 0 605 let MAX_BLOCKS: nx_int = NX_MAGIC_65536 606 while done == 0 { 607 if iter >= MAX_BLOCKS { break } 608 let final_block: nx_int = _deflate_inflate_block( 609 bs, out_buf, pos_box, max_output, err_box) 610 if final_block < 0 { 611 r.error_code = err_box[0] 612 r.output_data = out_buf 613 r.output_size = pos_box[0] 614 r.bytes_consumed = _deflate_bytes_consumed(bs) 615 return r 616 } 617 if final_block == 1 { done = 1 } 618 iter = iter + 1 619 } 620 621 r.output_data = out_buf 622 r.output_size = pos_box[0] 623 r.bytes_consumed = _deflate_bytes_consumed(bs) 624 r.error_code = NX_DEF_OK 625 return r 626} 627 628// ===== self-test ================================================= 629 630func main() -> nx_int { 631 // ---- STORED block decoding "Nishi" (5 bytes) ---- 632 // 633 // Block header: BFINAL=1, BTYPE=00 -> bits 1 0 0 = first byte's 634 // low 3 bits = 001 -> byte 0 = 0x01 (with padding). 635 // 636 // After byte-align, LEN_lo LEN_hi NLEN_lo NLEN_hi then 5 bytes. 637 // 638 // byte 0: 0x01 (BFINAL=1, BTYPE=00, pad to byte boundary) 639 // byte 1: 0x05 (LEN low) 640 // byte 2: 0x00 (LEN high; LEN = 5) 641 // byte 3: 0xFA (NLEN low; NLEN = ~5 = 0xFFFA) 642 // byte 4: 0xFF (NLEN high) 643 // bytes 5-9: 'N','i','s','h','i' = 0x4E 0x69 0x73 0x68 0x69 644 let buf: *u8 = (sys_mmap(10)) as *u8 645 buf[0] = 0x01 as u8 646 buf[1] = 0x05 as u8 647 buf[2] = 0x00 as u8 648 buf[3] = 0xFA as u8 649 buf[4] = 0xFF as u8 650 buf[5] = 0x4E as u8 651 buf[6] = 0x69 as u8 652 buf[7] = 0x73 as u8 653 buf[8] = 0x68 as u8 654 buf[9] = 0x69 as u8 655 656 let r1: *NxDeflateResult = nx_deflate_inflate(buf, 10, 64) 657 if r1 == (0 as *NxDeflateResult) { return 1 } 658 if r1.error_code != NX_DEF_OK { return 2 } 659 if r1.output_size != 5 { return 3 } 660 if r1.output_data[0] != (0x4E as u8) { return 4 } 661 if r1.output_data[1] != (0x69 as u8) { return 5 } 662 if r1.output_data[2] != (0x73 as u8) { return 6 } 663 if r1.output_data[3] != (0x68 as u8) { return 7 } 664 if r1.output_data[4] != (0x69 as u8) { return 8 } 665 666 // ---- STATIC Huffman empty-block: BFINAL=1 BTYPE=01 + EOB code 256 667 // 668 // Static Huffman literal/length 256 has length 7 + canonical 669 // code 0000000 (it's the FIRST 7-bit code; first_code[7] = 0). 670 // 671 // Bit-stream LSB-first: 672 // bit 0: BFINAL=1 673 // bit 1: BTYPE low=1 674 // bit 2: BTYPE high=0 675 // bits 3..9: 0000000 (EOB code) 676 // (any trailing pad bits) 677 // 678 // byte 0 LSB-first = bit0|bit1<<1|bit2<<2|bit3<<3|bit4<<4|... 679 // = 1 | 1<<1 | 0<<2 | 0<<3 | 0<<4 | 0<<5 | 0<<6 | 0<<7 = 0x03 680 // byte 1: bit 8 = 0, bit 9 = 0, rest pad = 0 -> 0x00 681 let buf2: *u8 = (sys_mmap(2)) as *u8 682 buf2[0] = 0x03 as u8 683 buf2[1] = 0x00 as u8 684 685 let r2: *NxDeflateResult = nx_deflate_inflate(buf2, 2, 64) 686 if r2 == (0 as *NxDeflateResult) { return 20 } 687 if r2.error_code != NX_DEF_OK { return 21 } 688 if r2.output_size != 0 { return 22 } 689 690 // ---- NLEN mismatch error path ---- 691 let bad: *u8 = (sys_mmap(10)) as *u8 692 bad[0] = 0x01 as u8 693 bad[1] = 0x05 as u8 694 bad[2] = 0x00 as u8 695 bad[3] = 0x00 as u8 // wrong NLEN 696 bad[4] = 0x00 as u8 697 let rb: *NxDeflateResult = nx_deflate_inflate(bad, 10, 64) 698 if rb.error_code != NX_DEF_ERR_NLEN { return 30 } 699 700 return 0 701}