code wiki / (root) / nx_deflate.nx

nx_deflate.nx source

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