code wiki / (root) / nx_zip_deflate_lib.nx

nx_zip_deflate_lib.nx source

↩ module page · 82 lines · 4592 B

1// nx_zip_deflate_lib.nx -- ZIP method-8 (DEFLATE) ENTRY WRITER, composing the two incumbents the estate already proves: 2// nx_zip.nx (the STORED writer + reader, its reflected CRC-32 and its central-directory shape) and nx_deflate_enc.nx (the 3// sovereign RFC 1951 compressor). nx_zip.nx names this exact rung in its own header ("wiring nx_deflate_enc.nx in as method 8 is 4// a compression improvement"); it lands as a SIBLING lib rather than an edit of nx_zip.nx so the writer's many importers do not 5// grow the compressor into their closures. Same state vector (st[NX_ZIP_ST_*]), same finalize (nxzip_finalize): a caller mixes 6// nxzip_add_stored and nxzip_add_deflated entries freely. 7// WHY (2026-09-06, /compare/modding MD1): a bundle walker that reads only STORED entries is the DanceXR-class reader the rung 8// exists to exceed; its gate needs a REAL method-8 fixture to prove the DEFLATE path and to make a STORED-only reader fail. 9// A compressed member that would GROW is stored instead (csize would exceed usize): every real archiver does the same, and a 10// caller can read the method back from the central directory to see which it got. 11// license_tier: ORIGINAL No hw writes (Rule 26). 12import "nx_syscalls.nx" 13import "nx_zip.nx" 14import "nx_deflate_enc.nx" 15 16const NX_ZIP_METHOD_DEFLATE: i64 = 8 17const NXZD_FLAG_NONE: i64 = 0 18const NXZD_ENC_HEADROOM: i64 = 64 // fixed-Huffman framing above the input for an incompressible member before the STORED fallback wins 19 20// scratch large enough for any dfe_compress output over `len` input bytes: an incompressible run costs ~1/8 extra under fixed 21// Huffman (9-bit literals for the 144..255 half), so len + len/4 + headroom bounds it 22func nxzd_scratch_bytes(len: i64) -> i64 { return len + len / 4 + NXZD_ENC_HEADROOM } 23 24// Writes one entry compressed with DEFLATE (method 8) when that is smaller than STORED, else falls back to nxzip_add_stored. 25// Returns 1 on success, 0 if a buffer cannot hold the entry (never a partial entry). method_out[0] reports which method landed. 26func nxzip_add_deflated(out: *u8, cap: i64, cd: *u8, cdcap: i64, st: *i64, 27 name: *u8, data: *u8, len: i64, method_out: *i64) -> i64 { 28 if len < 0 { return 0 } 29 let nlen: i64 = nxzip_strlen(name) 30 if nlen <= 0 { return 0 } 31 let scratch: *u8 = sys_mmap(nxzd_scratch_bytes(len) + 16) 32 var clen: i64 = 0 33 if len > 0 { clen = dfe_compress(data, len, scratch) } 34 if clen <= 0 { method_out[0] = NX_ZIP_METHOD_STORE; return nxzip_add_stored(out, cap, cd, cdcap, st, name, data, len) } 35 if clen >= len { method_out[0] = NX_ZIP_METHOD_STORE; return nxzip_add_stored(out, cap, cd, cdcap, st, name, data, len) } 36 let off: i64 = st[NX_ZIP_ST_OFF] 37 let cdoff: i64 = st[NX_ZIP_ST_CDOFF] 38 if off + NX_ZIP_LOCAL_LEN + nlen + clen > cap { return 0 } 39 if cdoff + NX_ZIP_CD_LEN + nlen > cdcap { return 0 } 40 // the CRC is over the UNCOMPRESSED bytes (PKWARE APPNOTE 4.4.7), the sizes are compressed then uncompressed 41 let crc: i64 = nxzip_crc32(data, len) 42 nxzip_w32(out, off, NX_ZIP_SIG_LOCAL) 43 nxzip_w16(out, off + 4, NX_ZIP_VERSION) 44 nxzip_w16(out, off + 6, NXZD_FLAG_NONE) 45 nxzip_w16(out, off + 8, NX_ZIP_METHOD_DEFLATE) 46 nxzip_w16(out, off + 10, 0) 47 nxzip_w16(out, off + 12, 0) 48 nxzip_w32(out, off + 14, crc) 49 nxzip_w32(out, off + 18, clen) 50 nxzip_w32(out, off + 22, len) 51 nxzip_w16(out, off + 26, nlen) 52 nxzip_w16(out, off + 28, 0) 53 var i: i64 = 0 54 while i < nlen { out[off + NX_ZIP_LOCAL_LEN + i] = name[i]; i = i + 1 } 55 let dstart: i64 = off + NX_ZIP_LOCAL_LEN + nlen 56 i = 0 57 while i < clen { out[dstart + i] = scratch[i]; i = i + 1 } 58 nxzip_w32(cd, cdoff, NX_ZIP_SIG_CD) 59 nxzip_w16(cd, cdoff + 4, NX_ZIP_VERSION) 60 nxzip_w16(cd, cdoff + 6, NX_ZIP_VERSION) 61 nxzip_w16(cd, cdoff + 8, NXZD_FLAG_NONE) 62 nxzip_w16(cd, cdoff + 10, NX_ZIP_METHOD_DEFLATE) 63 nxzip_w16(cd, cdoff + 12, 0) 64 nxzip_w16(cd, cdoff + 14, 0) 65 nxzip_w32(cd, cdoff + 16, crc) 66 nxzip_w32(cd, cdoff + 20, clen) 67 nxzip_w32(cd, cdoff + 24, len) 68 nxzip_w16(cd, cdoff + 28, nlen) 69 nxzip_w16(cd, cdoff + 30, 0) 70 nxzip_w16(cd, cdoff + 32, 0) 71 nxzip_w16(cd, cdoff + 34, 0) 72 nxzip_w16(cd, cdoff + 36, 0) 73 nxzip_w32(cd, cdoff + 38, 0) 74 nxzip_w32(cd, cdoff + 42, off) 75 i = 0 76 while i < nlen { cd[cdoff + NX_ZIP_CD_LEN + i] = name[i]; i = i + 1 } 77 st[NX_ZIP_ST_OFF] = dstart + clen 78 st[NX_ZIP_ST_CDOFF] = cdoff + NX_ZIP_CD_LEN + nlen 79 st[NX_ZIP_ST_COUNT] = st[NX_ZIP_ST_COUNT] + 1 80 method_out[0] = NX_ZIP_METHOD_DEFLATE 81 return 1 82}