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}