nx_sevenz_lib.nx source
↩ module page · 835 lines · 40454 B
1// nx_sevenz_lib.nx -- THE 7z CONTAINER READER (/compare/modding MD29 sz_walk, 2026-09-06), written from the mirrored format
2// document (knowledge/fetched/cmp_modding_7zFormat.txt, pin 395ad336) and method table (cmp_modding_7z_Methods.txt, pin
3// 418d0748), both READ first. It composes the incumbents and adds no second ruler: nx_lzma_lib (LZMA and LZMA2 coders, the
4// x86 BCJ branch converter), nxzip_crc32 from nx_zip (the reflected CRC-32 the 7z digests use), and nx_bundle_ingest_lib's
5// record table, so a 7z walks to the SAME typed rows the zip walker fills and the texture binder and the partition run
6// unchanged over both.
7// WHAT IT READS: the 32-byte signature header (its own CRC verified), the next header (CRC verified), an ENCODED header
8// (decoded through the folder that carries it, then parsed as the plain header), pack info, coders info (folders with
9// their coder ids, properties, bind pairs and unpack sizes), substreams info (sizes and digests), and files info (empty-stream
10// and empty-file bit vectors, UTF-16LE names converted to UTF-8). Directories are counted and left out of the table; empty
11// files are rows with no bytes. Every member's bytes are CRC-checked against the archive's OWN digest -- the container is
12// the oracle for the decoder. Coders: Copy (00), LZMA (03 01 01), LZMA2 (21), and the two-coder folder 7-Zip writes for
13// executables, x86 BCJ (03 03 01 03) over LZMA or LZMA2 with the one bind pair in0 <- out1; any other coder or chain is
14// REPORTED unsupported by name on every member it holds, never guessed at. Solid folders decode once into one buffer sized
15// from the folder's declared unpack size and every member is a window into it.
16// license_tier: ORIGINAL No hw writes (Rule 26).
17import "nx_syscalls.nx"
18import "nx_lzma_lib.nx"
19import "nx_bundle_ingest_lib.nx"
20
21const SZ_SIG_LEN: i64 = 32
22const SZ_START_HDR_OFF: i64 = 12
23const SZ_START_HDR_LEN: i64 = 20
24const SZ_NID_END: i64 = 0
25const SZ_NID_HEADER: i64 = 1
26const SZ_NID_ARCHIVE_PROPS: i64 = 2
27const SZ_NID_ADDITIONAL: i64 = 3
28const SZ_NID_MAIN: i64 = 4
29const SZ_NID_FILES: i64 = 5
30const SZ_NID_PACK: i64 = 6
31const SZ_NID_UNPACK: i64 = 7
32const SZ_NID_SUBSTREAMS: i64 = 8
33const SZ_NID_SIZE: i64 = 9
34const SZ_NID_CRC: i64 = 10
35const SZ_NID_FOLDER: i64 = 11
36const SZ_NID_CODERS_UNPACK: i64 = 12
37const SZ_NID_NUM_UNPACK: i64 = 13
38const SZ_NID_EMPTY_STREAM: i64 = 14
39const SZ_NID_EMPTY_FILE: i64 = 15
40const SZ_NID_NAME: i64 = 17
41const SZ_NID_ENCODED: i64 = 23
42const SZ_CODER_COPY: i64 = 0
43const SZ_CODER_LZMA: i64 = 196865 // 03 01 01 = 3*65536 + 1*256 + 1 (the first cut wrote 197121 = 03 02 01 and read every LZMA header as unsupported)
44const SZ_CODER_LZMA2: i64 = 33 // 21
45const SZ_CODER_BCJ_X86: i64 = 50528515 // 03 03 01 03 = 3*16777216 + 3*65536 + 256 + 3; as a CLASS it means BCJ x86 over an LZMA-family second coder
46const SZ_CODER_UNSUPPORTED: i64 = 0 - 1
47const SZ_CODER_CHAIN: i64 = 0 - 2
48const SZ_MAX_FOLDERS_PER_BYTES: i64 = 8 // derived caps: a folder or a file costs at least this many header bytes
49const SZ_MAX_FILES_PER_BYTES: i64 = 2
50// parse errors
51const SZ_OK: i64 = 0
52const SZ_ERR_NOT_7Z: i64 = 0 - 1
53const SZ_ERR_START_CRC: i64 = 0 - 2
54const SZ_ERR_TRUNCATED: i64 = 0 - 3
55const SZ_ERR_HEADER_CRC: i64 = 0 - 4
56const SZ_ERR_HEADER_CODER: i64 = 0 - 5
57const SZ_ERR_SYNTAX: i64 = 0 - 6
58const SZ_ERR_EXTERNAL: i64 = 0 - 7
59const SZ_ERR_HEADER_DECODE: i64 = 0 - 8
60// model slots
61const SZ_M_ERR: i64 = 0
62const SZ_M_NPACK: i64 = 1
63const SZ_M_PACKPOS: i64 = 2
64const SZ_M_PACKSIZES: i64 = 3
65const SZ_M_NFOLD: i64 = 4
66const SZ_M_FCODER: i64 = 5
67const SZ_M_FPROPS_OFF: i64 = 6
68const SZ_M_FPROPS_LEN: i64 = 7
69const SZ_M_FUNPACK: i64 = 8
70const SZ_M_FCRC: i64 = 9
71const SZ_M_FCRCDEF: i64 = 10
72const SZ_M_FNSUB: i64 = 11
73const SZ_M_FPACKIDX: i64 = 12
74const SZ_M_FNCODERS: i64 = 13
75const SZ_M_NSUB: i64 = 14
76const SZ_M_SUBSIZE: i64 = 15
77const SZ_M_SUBCRC: i64 = 16
78const SZ_M_SUBCRCDEF: i64 = 17
79const SZ_M_NFILES: i64 = 18
80const SZ_M_FILE_EMPTYSTREAM: i64 = 19
81const SZ_M_FILE_EMPTYFILE: i64 = 20
82const SZ_M_NAMES: i64 = 21
83const SZ_M_NAMEOFF: i64 = 22
84const SZ_M_NAMELEN: i64 = 23
85const SZ_M_ENCODED: i64 = 24
86const SZ_M_DIRS: i64 = 25
87const SZ_M_EMPTYFILES: i64 = 26
88const SZ_M_DATAFILES: i64 = 27
89const SZ_M_HDRBUF: i64 = 28
90const SZ_M_HDRLEN: i64 = 29
91const SZ_M_BASE: i64 = 30
92const SZ_M_NEMPTYSTREAMS: i64 = 31
93const SZ_M_HDR_CODERID: i64 = 32
94const SZ_M_HDR_NCODERS: i64 = 33
95const SZ_M_FCODER0RAW: i64 = 34
96const SZ_M_FCODER1RAW: i64 = 35
97const SZ_M_FPROPS2_OFF: i64 = 36
98const SZ_M_FPROPS2_LEN: i64 = 37
99const SZ_M_FUNPACK2: i64 = 38
100const SZ_M_FBIND_IN: i64 = 39
101const SZ_M_FBIND_OUT: i64 = 40
102const SZ_M_N: i64 = 48
103
104func sz_is_7z(b: *u8, n: i64) -> i64 {
105 if n < SZ_SIG_LEN { return 0 }
106 if (b[0] as i64) != 55 { return 0 }
107 if (b[1] as i64) != 122 { return 0 }
108 if ((b[2] & 0xff) as i64) != 188 { return 0 }
109 if ((b[3] & 0xff) as i64) != 175 { return 0 }
110 if ((b[4] & 0xff) as i64) != 39 { return 0 }
111 if ((b[5] & 0xff) as i64) != 28 { return 0 }
112 return 1
113}
114func sz_u32(b: *u8, o: i64) -> i64 { return ((b[o] & 0xff) as i64) | (((b[o + 1] & 0xff) as i64) * 256) | (((b[o + 2] & 0xff) as i64) * 65536) | (((b[o + 3] & 0xff) as i64) * 16777216) }
115func sz_u64(b: *u8, o: i64) -> i64 { return sz_u32(b, o) + sz_u32(b, o + 4) * 4294967296 }
116// cursor reads over [p[0], end): every read is bounds-checked and a short read flags the model
117func sz_rd8(b: *u8, p: *i64, end: i64, m: *i64) -> i64 {
118 if p[0] >= end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
119 let v: i64 = (b[p[0]] & 0xff) as i64
120 p[0] = p[0] + 1
121 return v
122}
123// the 7z UINT64: the count of leading one bits in the first byte is the count of extra little-endian bytes
124func sz_num(b: *u8, p: *i64, end: i64, m: *i64) -> i64 {
125 let first: i64 = sz_rd8(b, p, end, m)
126 var mask: i64 = 128
127 var extra: i64 = 0
128 while extra < 8 { if (first & mask) != 0 { extra = extra + 1; mask = mask / 2 } else { break } }
129 if p[0] + extra > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
130 var v: i64 = 0
131 var i: i64 = 0
132 while i < extra { v = v + ((b[p[0] + i] & 0xff) as i64) * lz_pow2(8 * i); i = i + 1 }
133 p[0] = p[0] + extra
134 if extra < 7 { v = v + (first & (mask - 1)) * lz_pow2(8 * extra) }
135 return v
136}
137func sz_skip(p: *i64, end: i64, n: i64, m: *i64) -> i64 {
138 if n < 0 { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
139 if p[0] + n > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
140 p[0] = p[0] + n
141 return 1
142}
143func sz_bit(v: *u8, i: i64) -> i64 { return (((v[i / 8] & 0xff) as i64) / lz_pow2(7 - (i % 8))) & 1 }
144// Digests(n): allAreDefined then an optional bit vector then a CRC per defined stream -> def[] and crc[] arrays of n
145func sz_digests(b: *u8, p: *i64, end: i64, m: *i64, n: i64, def: *i64, crc: *i64) -> i64 {
146 let all: i64 = sz_rd8(b, p, end, m)
147 var i: i64 = 0
148 if all == 0 {
149 let nbytes: i64 = (n + 7) / 8
150 if p[0] + nbytes > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
151 while i < n { def[i] = sz_bit(b + p[0], i); i = i + 1 }
152 p[0] = p[0] + nbytes
153 } else { while i < n { def[i] = 1; i = i + 1 } }
154 i = 0
155 while i < n {
156 if def[i] == 1 { if p[0] + 4 > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 } crc[i] = sz_u32(b, p[0]); p[0] = p[0] + 4 } else { crc[i] = 0 }
157 i = i + 1
158 }
159 return 1
160}
161// StreamsInfo: PackInfo, CodersInfo (folders), SubStreamsInfo, each optional, then kEnd. Fills the model's stream arrays.
162func sz_streams_info(b: *u8, p: *i64, end: i64, m: *i64) -> i64 {
163 var nid: i64 = sz_rd8(b, p, end, m)
164 if nid == SZ_NID_PACK {
165 m[SZ_M_PACKPOS] = sz_num(b, p, end, m)
166 let np: i64 = sz_num(b, p, end, m)
167 if m[SZ_M_ERR] < 0 { return 0 }
168 if np > (end - p[0]) + 1 { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
169 m[SZ_M_NPACK] = np
170 let sizes: *i64 = sys_mmap(8 * (np + 1)) as *i64
171 m[SZ_M_PACKSIZES] = sizes as i64
172 var t: i64 = sz_rd8(b, p, end, m)
173 if t == SZ_NID_SIZE {
174 var i: i64 = 0
175 while i < np { sizes[i] = sz_num(b, p, end, m); i = i + 1 }
176 t = sz_rd8(b, p, end, m)
177 }
178 if t == SZ_NID_CRC {
179 let def: *i64 = sys_mmap(8 * (np + 1)) as *i64
180 let crc: *i64 = sys_mmap(8 * (np + 1)) as *i64
181 sz_digests(b, p, end, m, np, def, crc)
182 t = sz_rd8(b, p, end, m)
183 }
184 if t != SZ_NID_END { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
185 nid = sz_rd8(b, p, end, m)
186 }
187 if nid == SZ_NID_UNPACK {
188 if sz_rd8(b, p, end, m) != SZ_NID_FOLDER { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
189 let nf: i64 = sz_num(b, p, end, m)
190 if m[SZ_M_ERR] < 0 { return 0 }
191 if nf > (end - p[0]) / SZ_MAX_FOLDERS_PER_BYTES + 1 { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
192 if sz_rd8(b, p, end, m) != 0 { m[SZ_M_ERR] = SZ_ERR_EXTERNAL; return 0 }
193 m[SZ_M_NFOLD] = nf
194 let fc: *i64 = sys_mmap(8 * (nf + 1)) as *i64
195 let fpo: *i64 = sys_mmap(8 * (nf + 1)) as *i64
196 let fpl: *i64 = sys_mmap(8 * (nf + 1)) as *i64
197 let fu: *i64 = sys_mmap(8 * (nf + 1)) as *i64
198 let fcrc: *i64 = sys_mmap(8 * (nf + 1)) as *i64
199 let fcrcdef: *i64 = sys_mmap(8 * (nf + 1)) as *i64
200 let fnsub: *i64 = sys_mmap(8 * (nf + 1)) as *i64
201 let fpack: *i64 = sys_mmap(8 * (nf + 1)) as *i64
202 let fnc: *i64 = sys_mmap(8 * (nf + 1)) as *i64
203 let fr0: *i64 = sys_mmap(8 * (nf + 1)) as *i64
204 let fr1: *i64 = sys_mmap(8 * (nf + 1)) as *i64
205 let fpo2: *i64 = sys_mmap(8 * (nf + 1)) as *i64
206 let fpl2: *i64 = sys_mmap(8 * (nf + 1)) as *i64
207 let fu2: *i64 = sys_mmap(8 * (nf + 1)) as *i64
208 let fbi: *i64 = sys_mmap(8 * (nf + 1)) as *i64
209 let fbo: *i64 = sys_mmap(8 * (nf + 1)) as *i64
210 m[SZ_M_FCODER] = fc as i64; m[SZ_M_FPROPS_OFF] = fpo as i64; m[SZ_M_FPROPS_LEN] = fpl as i64; m[SZ_M_FUNPACK] = fu as i64
211 m[SZ_M_FCRC] = fcrc as i64; m[SZ_M_FCRCDEF] = fcrcdef as i64; m[SZ_M_FNSUB] = fnsub as i64; m[SZ_M_FPACKIDX] = fpack as i64; m[SZ_M_FNCODERS] = fnc as i64
212 m[SZ_M_FCODER0RAW] = fr0 as i64; m[SZ_M_FCODER1RAW] = fr1 as i64; m[SZ_M_FPROPS2_OFF] = fpo2 as i64; m[SZ_M_FPROPS2_LEN] = fpl2 as i64
213 m[SZ_M_FUNPACK2] = fu2 as i64; m[SZ_M_FBIND_IN] = fbi as i64; m[SZ_M_FBIND_OUT] = fbo as i64
214 var packidx: i64 = 0
215 var f: i64 = 0
216 while f < nf {
217 let nc: i64 = sz_num(b, p, end, m)
218 if m[SZ_M_ERR] < 0 { return 0 }
219 fnc[f] = nc
220 var in_total: i64 = 0
221 var out_total: i64 = 0
222 var c: i64 = 0
223 var coder: i64 = SZ_CODER_UNSUPPORTED
224 fpo[f] = 0; fpl[f] = 0; fpo2[f] = 0; fpl2[f] = 0; fr0[f] = 0 - 1; fr1[f] = 0 - 1; fbi[f] = 0 - 1; fbo[f] = 0 - 1; fu2[f] = 0
225 while c < nc {
226 let flag: i64 = sz_rd8(b, p, end, m)
227 let idsz: i64 = flag & 15
228 if p[0] + idsz > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
229 var id: i64 = 0
230 var k: i64 = 0
231 while k < idsz { id = id * 256 + ((b[p[0] + k] & 0xff) as i64); k = k + 1 }
232 p[0] = p[0] + idsz
233 if f == 0 { if c == 0 { m[SZ_M_HDR_CODERID] = id; m[SZ_M_HDR_NCODERS] = nc } }
234 if c == 0 { fr0[f] = id }
235 if c == 1 { fr1[f] = id }
236 var nin: i64 = 1
237 var nout: i64 = 1
238 if (flag & 16) != 0 { nin = sz_num(b, p, end, m); nout = sz_num(b, p, end, m) }
239 in_total = in_total + nin
240 out_total = out_total + nout
241 if (flag & 32) != 0 {
242 let plen: i64 = sz_num(b, p, end, m)
243 if m[SZ_M_ERR] < 0 { return 0 }
244 if p[0] + plen > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
245 if c == 0 { fpo[f] = p[0]; fpl[f] = plen }
246 if c == 1 { fpo2[f] = p[0]; fpl2[f] = plen }
247 p[0] = p[0] + plen
248 }
249 if c == 0 {
250 coder = SZ_CODER_UNSUPPORTED
251 if id == SZ_CODER_COPY { coder = SZ_CODER_COPY }
252 if id == SZ_CODER_LZMA { coder = SZ_CODER_LZMA }
253 if id == SZ_CODER_LZMA2 { coder = SZ_CODER_LZMA2 }
254 if nin != 1 { coder = SZ_CODER_UNSUPPORTED }
255 if nout != 1 { coder = SZ_CODER_UNSUPPORTED }
256 }
257 c = c + 1
258 }
259 // bind pairs (in <- out), then the packed-stream indices when there are several
260 let nbind: i64 = out_total - 1
261 var q: i64 = 0
262 while q < nbind {
263 let bin: i64 = sz_num(b, p, end, m)
264 let bout: i64 = sz_num(b, p, end, m)
265 if q == 0 { fbi[f] = bin; fbo[f] = bout }
266 q = q + 1
267 }
268 let npacked: i64 = in_total - nbind
269 if npacked > 1 { q = 0; while q < npacked { sz_num(b, p, end, m); q = q + 1 } }
270 // a two-coder folder is supported in exactly the shape 7-Zip writes for executables: BCJ x86 first, an LZMA-family
271 // coder second, one bind pair in0 <- out1, one packed stream; every other chain is reported by name
272 if nc > 1 {
273 coder = SZ_CODER_CHAIN
274 if nc == 2 { if fr0[f] == SZ_CODER_BCJ_X86 { if fbi[f] == 0 { if fbo[f] == 1 { if npacked == 1 {
275 if fr1[f] == SZ_CODER_LZMA { coder = SZ_CODER_BCJ_X86 }
276 if fr1[f] == SZ_CODER_LZMA2 { coder = SZ_CODER_BCJ_X86 }
277 } } } } }
278 }
279 fc[f] = coder
280 fpack[f] = packidx
281 packidx = packidx + npacked
282 fnsub[f] = 1
283 fcrcdef[f] = 0
284 if m[SZ_M_ERR] < 0 { return 0 }
285 f = f + 1
286 }
287 if sz_rd8(b, p, end, m) != SZ_NID_CODERS_UNPACK { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
288 f = 0
289 while f < nf {
290 // one unpack size per OUT stream of the folder, in coder order; the folder's MAIN output is the out stream no bind
291 // pair consumes (out 0 for a single coder and for the BCJ chain), the bound one is the inner coder's intermediate
292 var outs: i64 = 1
293 if fnc[f] > 1 { outs = fnc[f] }
294 var q2: i64 = 0
295 var mainsz: i64 = 0
296 var second: i64 = 0
297 while q2 < outs {
298 let u: i64 = sz_num(b, p, end, m)
299 if outs == 1 { mainsz = u }
300 else { if q2 == fbo[f] { second = u } else { if q2 == 0 { mainsz = u } else { if mainsz == 0 { mainsz = u } } } }
301 q2 = q2 + 1
302 }
303 fu[f] = mainsz
304 fu2[f] = second
305 f = f + 1
306 }
307 var t2: i64 = sz_rd8(b, p, end, m)
308 if t2 == SZ_NID_CRC {
309 sz_digests(b, p, end, m, nf, fcrcdef, fcrc)
310 t2 = sz_rd8(b, p, end, m)
311 }
312 if t2 != SZ_NID_END { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
313 nid = sz_rd8(b, p, end, m)
314 }
315 // substreams: default one per folder inheriting the folder's size and digest
316 let nf2: i64 = m[SZ_M_NFOLD]
317 let fnsub2: *i64 = m[SZ_M_FNSUB] as *i64
318 let fu2b: *i64 = m[SZ_M_FUNPACK] as *i64
319 let fcrc2: *i64 = m[SZ_M_FCRC] as *i64
320 let fcrcdef2: *i64 = m[SZ_M_FCRCDEF] as *i64
321 var have_sizes: i64 = 0
322 var t3: i64 = nid
323 var sub_sizes: *i64 = 0 as *i64
324 var nsub_total: i64 = nf2
325 if nid == SZ_NID_SUBSTREAMS {
326 t3 = sz_rd8(b, p, end, m)
327 if t3 == SZ_NID_NUM_UNPACK {
328 var f2: i64 = 0
329 nsub_total = 0
330 while f2 < nf2 { fnsub2[f2] = sz_num(b, p, end, m); nsub_total = nsub_total + fnsub2[f2]; f2 = f2 + 1 }
331 if m[SZ_M_ERR] < 0 { return 0 }
332 if nsub_total > (end - p[0]) + nf2 + 1 { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
333 t3 = sz_rd8(b, p, end, m)
334 }
335 sub_sizes = sys_mmap(8 * (nsub_total + 1)) as *i64
336 var si: i64 = 0
337 var f3: i64 = 0
338 if t3 == SZ_NID_SIZE {
339 while f3 < nf2 {
340 var sum: i64 = 0
341 var k3: i64 = 0
342 while k3 + 1 < fnsub2[f3] { let s: i64 = sz_num(b, p, end, m); sub_sizes[si] = s; sum = sum + s; si = si + 1; k3 = k3 + 1 }
343 if fnsub2[f3] > 0 { sub_sizes[si] = fu2b[f3] - sum; si = si + 1 }
344 f3 = f3 + 1
345 }
346 have_sizes = 1
347 t3 = sz_rd8(b, p, end, m)
348 }
349 }
350 if have_sizes == 0 {
351 sub_sizes = sys_mmap(8 * (nsub_total + 1)) as *i64
352 var si2: i64 = 0
353 var f4: i64 = 0
354 while f4 < nf2 {
355 var k4: i64 = 0
356 while k4 < fnsub2[f4] { sub_sizes[si2] = fu2b[f4]; si2 = si2 + 1; k4 = k4 + 1 }
357 f4 = f4 + 1
358 }
359 }
360 m[SZ_M_NSUB] = nsub_total
361 m[SZ_M_SUBSIZE] = sub_sizes as i64
362 // digests: streams whose CRC the folder does not already carry (every substream of a multi-substream folder, and
363 // the single substream of a folder without a folder CRC); folder CRCs cover single-substream folders
364 let sub_crc: *i64 = sys_mmap(8 * (nsub_total + 1)) as *i64
365 let sub_def: *i64 = sys_mmap(8 * (nsub_total + 1)) as *i64
366 var unknown: i64 = 0
367 var f5: i64 = 0
368 var si3: i64 = 0
369 while f5 < nf2 {
370 if fnsub2[f5] == 1 { if fcrcdef2[f5] == 1 { sub_def[si3] = 1; sub_crc[si3] = fcrc2[f5] } else { sub_def[si3] = 0; unknown = unknown + 1 } si3 = si3 + 1 }
371 else { var k5: i64 = 0; while k5 < fnsub2[f5] { sub_def[si3] = 0; unknown = unknown + 1; si3 = si3 + 1; k5 = k5 + 1 } }
372 f5 = f5 + 1
373 }
374 if nid == SZ_NID_SUBSTREAMS {
375 if t3 == SZ_NID_CRC {
376 let udef: *i64 = sys_mmap(8 * (unknown + 1)) as *i64
377 let ucrc: *i64 = sys_mmap(8 * (unknown + 1)) as *i64
378 sz_digests(b, p, end, m, unknown, udef, ucrc)
379 var ui: i64 = 0
380 var s6: i64 = 0
381 while s6 < nsub_total { if sub_def[s6] == 0 { if ui < unknown { sub_def[s6] = udef[ui]; sub_crc[s6] = ucrc[ui]; ui = ui + 1 } } s6 = s6 + 1 }
382 t3 = sz_rd8(b, p, end, m)
383 }
384 if t3 != SZ_NID_END { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
385 nid = sz_rd8(b, p, end, m)
386 }
387 m[SZ_M_SUBCRC] = sub_crc as i64
388 m[SZ_M_SUBCRCDEF] = sub_def as i64
389 if nid != SZ_NID_END { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
390 return 1
391}
392// UTF-16LE (with surrogate pairs) to UTF-8 into the arena; returns the byte length written
393func sz_utf16_to_utf8(b: *u8, off: i64, units: i64, out: *u8, o0: i64, cap: i64) -> i64 {
394 var o: i64 = o0
395 var i: i64 = 0
396 while i < units {
397 var cp: i64 = ((b[off + i * 2] & 0xff) as i64) | (((b[off + i * 2 + 1] & 0xff) as i64) * 256)
398 i = i + 1
399 if cp >= 55296 { if cp <= 56319 { if i < units {
400 let lo: i64 = ((b[off + i * 2] & 0xff) as i64) | (((b[off + i * 2 + 1] & 0xff) as i64) * 256)
401 if lo >= 56320 { if lo <= 57343 { cp = 65536 + (cp - 55296) * 1024 + (lo - 56320); i = i + 1 } }
402 } } }
403 if cp < 128 { if o < cap - 1 { out[o] = cp as u8; o = o + 1 } }
404 else { if cp < 2048 { if o < cap - 2 { out[o] = (192 + cp / 64) as u8; out[o + 1] = (128 + (cp & 63)) as u8; o = o + 2 } }
405 else { if cp < 65536 { if o < cap - 3 { out[o] = (224 + cp / 4096) as u8; out[o + 1] = (128 + ((cp / 64) & 63)) as u8; out[o + 2] = (128 + (cp & 63)) as u8; o = o + 3 } }
406 else { if o < cap - 4 { out[o] = (240 + cp / 262144) as u8; out[o + 1] = (128 + ((cp / 4096) & 63)) as u8; out[o + 2] = (128 + ((cp / 64) & 63)) as u8; out[o + 3] = (128 + (cp & 63)) as u8; o = o + 4 } } } }
407 }
408 return o - o0
409}
410// the plain header: archive properties (skipped), additional streams (skipped), main streams, files info
411func sz_header(b: *u8, p: *i64, end: i64, m: *i64) -> i64 {
412 var nid: i64 = sz_rd8(b, p, end, m)
413 if nid == SZ_NID_ARCHIVE_PROPS {
414 var t: i64 = sz_rd8(b, p, end, m)
415 while t != 0 { let sz: i64 = sz_num(b, p, end, m); if sz_skip(p, end, sz, m) == 0 { return 0 } t = sz_rd8(b, p, end, m); if m[SZ_M_ERR] < 0 { return 0 } }
416 nid = sz_rd8(b, p, end, m)
417 }
418 if nid == SZ_NID_ADDITIONAL {
419 // parsed and then discarded: the model keeps the MAIN streams only
420 let keep: *i64 = sys_mmap(8 * SZ_M_N) as *i64
421 var k: i64 = 0
422 while k < SZ_M_N { keep[k] = m[k]; k = k + 1 }
423 if sz_streams_info(b, p, end, m) == 0 { return 0 }
424 k = 1
425 while k < SZ_M_N { m[k] = keep[k]; k = k + 1 }
426 nid = sz_rd8(b, p, end, m)
427 }
428 if nid == SZ_NID_MAIN {
429 if sz_streams_info(b, p, end, m) == 0 { return 0 }
430 nid = sz_rd8(b, p, end, m)
431 }
432 if nid == SZ_NID_FILES {
433 let nfiles: i64 = sz_num(b, p, end, m)
434 if m[SZ_M_ERR] < 0 { return 0 }
435 if nfiles > (end - p[0]) / SZ_MAX_FILES_PER_BYTES + 1 { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
436 m[SZ_M_NFILES] = nfiles
437 let es: *i64 = sys_mmap(8 * (nfiles + 1)) as *i64
438 let ef: *i64 = sys_mmap(8 * (nfiles + 1)) as *i64
439 let noff: *i64 = sys_mmap(8 * (nfiles + 1)) as *i64
440 let nlen: *i64 = sys_mmap(8 * (nfiles + 1)) as *i64
441 m[SZ_M_FILE_EMPTYSTREAM] = es as i64; m[SZ_M_FILE_EMPTYFILE] = ef as i64; m[SZ_M_NAMEOFF] = noff as i64; m[SZ_M_NAMELEN] = nlen as i64
442 let ncap: i64 = (end - p[0]) * 2 + 4 * nfiles + 16 // UTF-8 never needs more than 1.5x the UTF-16 bytes; 2x is the bound
443 let names: *u8 = sys_mmap(ncap)
444 m[SZ_M_NAMES] = names as i64
445 var nempty: i64 = 0
446 var t: i64 = sz_rd8(b, p, end, m)
447 while t != 0 {
448 let sz: i64 = sz_num(b, p, end, m)
449 if m[SZ_M_ERR] < 0 { return 0 }
450 if p[0] + sz > end { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return 0 }
451 let q0: i64 = p[0]
452 if t == SZ_NID_EMPTY_STREAM {
453 var i: i64 = 0
454 nempty = 0
455 while i < nfiles { if i / 8 < sz { es[i] = sz_bit(b + q0, i) } else { es[i] = 0 } if es[i] == 1 { nempty = nempty + 1 } i = i + 1 }
456 } else { if t == SZ_NID_EMPTY_FILE {
457 var i2: i64 = 0
458 var ei: i64 = 0
459 while i2 < nfiles { if es[i2] == 1 { if ei / 8 < sz { ef[i2] = sz_bit(b + q0, ei) } ei = ei + 1 } i2 = i2 + 1 }
460 } else { if t == SZ_NID_NAME {
461 let ext: i64 = (b[q0] & 0xff) as i64
462 if ext != 0 { m[SZ_M_ERR] = SZ_ERR_EXTERNAL; return 0 }
463 var q: i64 = q0 + 1
464 var fi: i64 = 0
465 var wo: i64 = 0
466 while fi < nfiles {
467 var start: i64 = q
468 var units: i64 = 0
469 while q + 1 < q0 + sz { let u: i64 = ((b[q] & 0xff) as i64) | (((b[q + 1] & 0xff) as i64) * 256); q = q + 2; if u == 0 { break } units = units + 1 }
470 noff[fi] = wo
471 let wrote: i64 = sz_utf16_to_utf8(b, start, units, names, wo, ncap)
472 nlen[fi] = wrote
473 wo = wo + wrote
474 if wo < ncap { names[wo] = 0 as u8; wo = wo + 1 }
475 fi = fi + 1
476 }
477 } } }
478 p[0] = q0 + sz
479 t = sz_rd8(b, p, end, m)
480 if m[SZ_M_ERR] < 0 { return 0 }
481 }
482 m[SZ_M_NEMPTYSTREAMS] = nempty
483 nid = sz_rd8(b, p, end, m)
484 }
485 if nid != SZ_NID_END { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return 0 }
486 return 1
487}
488// decode folder f of the model whose packed streams sit in b at m[SZ_M_BASE] + packpos; returns the buffer or 0 (named in rc)
489func sz_decode_folder(b: *u8, n: i64, m: *i64, f: i64, rc: *i64) -> *u8 {
490 let fc: *i64 = m[SZ_M_FCODER] as *i64
491 let fu: *i64 = m[SZ_M_FUNPACK] as *i64
492 let fpack: *i64 = m[SZ_M_FPACKIDX] as *i64
493 let sizes: *i64 = m[SZ_M_PACKSIZES] as *i64
494 let fpo: *i64 = m[SZ_M_FPROPS_OFF] as *i64
495 let fpl: *i64 = m[SZ_M_FPROPS_LEN] as *i64
496 rc[0] = 0
497 if fc[f] < 0 { rc[0] = BI_INF_UNSUPPORTED; return 0 as *u8 }
498 var off: i64 = m[SZ_M_BASE] + m[SZ_M_PACKPOS]
499 var k: i64 = 0
500 while k < fpack[f] { off = off + sizes[k]; k = k + 1 }
501 let psz: i64 = sizes[fpack[f]]
502 if off + psz > n { rc[0] = BI_INF_FAILED; return 0 as *u8 }
503 let unpack: i64 = fu[f]
504 if fc[f] == SZ_CODER_COPY {
505 if psz != unpack { rc[0] = BI_INF_FAILED; return 0 as *u8 }
506 rc[0] = BI_INF_STORED
507 return b + off
508 }
509 let out: *u8 = sys_mmap(unpack + 16)
510 var got: i64 = 0
511 let hb: *u8 = m[SZ_M_HDRBUF] as *u8
512 if fc[f] == SZ_CODER_BCJ_X86 {
513 // the inner LZMA-family coder first (its properties are the SECOND coder's), then the branch converter in place
514 let fr1: *i64 = m[SZ_M_FCODER1RAW] as *i64
515 let fpo2: *i64 = m[SZ_M_FPROPS2_OFF] as *i64
516 let fpl2: *i64 = m[SZ_M_FPROPS2_LEN] as *i64
517 let fu2: *i64 = m[SZ_M_FUNPACK2] as *i64
518 let inner: i64 = fu2[f]
519 if inner != unpack { rc[0] = BI_INF_FAILED; return 0 as *u8 }
520 var g2: i64 = 0
521 if fr1[f] == SZ_CODER_LZMA {
522 if fpl2[f] < 5 { rc[0] = BI_INF_FAILED; return 0 as *u8 }
523 g2 = lz_lzma_decode(b + off, psz, hb + fpo2[f], out, inner)
524 } else {
525 if fpl2[f] < 1 { rc[0] = BI_INF_FAILED; return 0 as *u8 }
526 g2 = lz_lzma2_decode(b + off, psz, (hb[fpo2[f]] & 0xff) as i64, out, inner)
527 }
528 if g2 != inner { rc[0] = BI_INF_FAILED; rc[1] = g2; return 0 as *u8 }
529 let st: *i64 = sys_mmap(16) as *i64
530 st[0] = 0
531 lz_bcj_x86(out, inner, 0, st, 0)
532 rc[0] = BI_INF_OK
533 return out
534 }
535 if fc[f] == SZ_CODER_LZMA {
536 if fpl[f] < 5 { rc[0] = BI_INF_FAILED; return 0 as *u8 }
537 got = lz_lzma_decode(b + off, psz, hb + fpo[f], out, unpack)
538 } else {
539 if fpl[f] < 1 { rc[0] = BI_INF_FAILED; return 0 as *u8 }
540 got = lz_lzma2_decode(b + off, psz, (hb[fpo[f]] & 0xff) as i64, out, unpack)
541 }
542 if got != unpack { rc[0] = BI_INF_FAILED; rc[1] = got; return 0 as *u8 }
543 rc[0] = BI_INF_OK
544 return out
545}
546// parse the whole archive into the model; returns SZ_OK or a named error
547func sz_parse(b: *u8, n: i64, m: *i64) -> i64 {
548 var i: i64 = 0
549 while i < SZ_M_N { m[i] = 0; i = i + 1 }
550 if sz_is_7z(b, n) == 0 { m[SZ_M_ERR] = SZ_ERR_NOT_7Z; return SZ_ERR_NOT_7Z }
551 if nxzip_crc32(b + SZ_START_HDR_OFF, SZ_START_HDR_LEN) != sz_u32(b, 8) { m[SZ_M_ERR] = SZ_ERR_START_CRC; return SZ_ERR_START_CRC }
552 let hoff: i64 = SZ_SIG_LEN + sz_u64(b, 12)
553 let hsz: i64 = sz_u64(b, 20)
554 if hoff + hsz > n { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return SZ_ERR_TRUNCATED }
555 if hsz < 1 { m[SZ_M_ERR] = SZ_ERR_TRUNCATED; return SZ_ERR_TRUNCATED }
556 if nxzip_crc32(b + hoff, hsz) != sz_u32(b, 28) { m[SZ_M_ERR] = SZ_ERR_HEADER_CRC; return SZ_ERR_HEADER_CRC }
557 m[SZ_M_BASE] = SZ_SIG_LEN
558 let p: *i64 = sys_mmap(16) as *i64
559 var hb: *u8 = b + hoff
560 var hlen: i64 = hsz
561 m[SZ_M_HDRBUF] = hb as i64
562 m[SZ_M_HDRLEN] = hlen
563 p[0] = 0
564 var nid: i64 = sz_rd8(hb, p, hlen, m)
565 if nid == SZ_NID_ENCODED {
566 m[SZ_M_ENCODED] = 1
567 if sz_streams_info(hb, p, hlen, m) == 0 { return m[SZ_M_ERR] }
568 if m[SZ_M_NFOLD] < 1 { m[SZ_M_ERR] = SZ_ERR_HEADER_CODER; return SZ_ERR_HEADER_CODER }
569 let rc: *i64 = sys_mmap(16) as *i64
570 let dec: *u8 = sz_decode_folder(b, n, m, 0, rc)
571 if (dec as i64) == 0 { if rc[0] == BI_INF_UNSUPPORTED { m[SZ_M_ERR] = SZ_ERR_HEADER_CODER; return SZ_ERR_HEADER_CODER } m[SZ_M_ERR] = SZ_ERR_HEADER_DECODE; return SZ_ERR_HEADER_DECODE }
572 let fu: *i64 = m[SZ_M_FUNPACK] as *i64
573 let fcrcdef: *i64 = m[SZ_M_FCRCDEF] as *i64
574 let fcrc: *i64 = m[SZ_M_FCRC] as *i64
575 if fcrcdef[0] == 1 { if nxzip_crc32(dec, fu[0]) != fcrc[0] { m[SZ_M_ERR] = SZ_ERR_HEADER_CRC; return SZ_ERR_HEADER_CRC } }
576 hb = dec
577 hlen = fu[0]
578 // the decoded header is a fresh model: clear the stream arrays the encoded header used (the header-coder detail stays)
579 let hid: i64 = m[SZ_M_HDR_CODERID]
580 let hnc: i64 = m[SZ_M_HDR_NCODERS]
581 i = 1
582 while i < SZ_M_N { m[i] = 0; i = i + 1 }
583 m[SZ_M_BASE] = SZ_SIG_LEN
584 m[SZ_M_ENCODED] = 1
585 m[SZ_M_HDRBUF] = hb as i64
586 m[SZ_M_HDRLEN] = hlen
587 m[SZ_M_HDR_CODERID] = hid
588 m[SZ_M_HDR_NCODERS] = hnc
589 p[0] = 0
590 nid = sz_rd8(hb, p, hlen, m)
591 }
592 if nid != SZ_NID_HEADER { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return SZ_ERR_SYNTAX }
593 if sz_header(hb, p, hlen, m) == 0 { return m[SZ_M_ERR] }
594 // census: directories (empty stream, not empty file), empty files, data files
595 let es: *i64 = m[SZ_M_FILE_EMPTYSTREAM] as *i64
596 let ef: *i64 = m[SZ_M_FILE_EMPTYFILE] as *i64
597 var d: i64 = 0
598 var e: i64 = 0
599 var df: i64 = 0
600 i = 0
601 while i < m[SZ_M_NFILES] {
602 if (es as i64) != 0 { if es[i] == 1 { if ef[i] == 1 { e = e + 1 } else { d = d + 1 } } else { df = df + 1 } } else { df = df + 1 }
603 i = i + 1
604 }
605 m[SZ_M_DIRS] = d; m[SZ_M_EMPTYFILES] = e; m[SZ_M_DATAFILES] = df
606 if df != m[SZ_M_NSUB] { m[SZ_M_ERR] = SZ_ERR_SYNTAX; return SZ_ERR_SYNTAX }
607 return SZ_OK
608}
609func sz_err_name(e: i64) -> *u8 {
610 if e == SZ_ERR_NOT_7Z { return "not-a-7z-signature" as *u8 }
611 if e == SZ_ERR_START_CRC { return "start-header-crc-mismatch" as *u8 }
612 if e == SZ_ERR_TRUNCATED { return "truncated" as *u8 }
613 if e == SZ_ERR_HEADER_CRC { return "header-crc-mismatch" as *u8 }
614 if e == SZ_ERR_HEADER_CODER { return "encoded-header-coder-unsupported" as *u8 }
615 if e == SZ_ERR_SYNTAX { return "header-syntax" as *u8 }
616 if e == SZ_ERR_EXTERNAL { return "external-data-reference-unsupported" as *u8 }
617 if e == SZ_ERR_HEADER_DECODE { return "encoded-header-decode-failed" as *u8 }
618 return "unnamed" as *u8
619}
620func sz_coder_name(c: i64) -> *u8 {
621 if c == SZ_CODER_COPY { return "copy" as *u8 }
622 if c == SZ_CODER_LZMA { return "lzma" as *u8 }
623 if c == SZ_CODER_LZMA2 { return "lzma2" as *u8 }
624 if c == SZ_CODER_BCJ_X86 { return "bcj-x86+lzma" as *u8 }
625 if c == SZ_CODER_CHAIN { return "coder-chain-unsupported" as *u8 }
626 return "coder-unsupported" as *u8
627}
628// member count (files with data plus empty files), or a named negative error -- the walker's table is sized from this
629func sz_count(b: *u8, n: i64) -> i64 {
630 let m: *i64 = sys_mmap(8 * SZ_M_N) as *i64
631 let rc: i64 = sz_parse(b, n, m)
632 if rc < 0 { return rc }
633 return m[SZ_M_DATAFILES] + m[SZ_M_EMPTYFILES]
634}
635// Walk the archive into the bundle walker's table (BI_F_N slots per row, at most maxm rows), names into the arena.
636// Rows are the archive's non-directory files in header order; BI_F_METHOD carries the folder's coder code, BI_F_CSIZE the
637// folder's pack size, BI_F_INFLATE the decode outcome, BI_F_CRC the archive's own digest (0 when it declared none).
638// Returns the row count, or a named negative error; st[0..3] = dirs, empty files, folders, encoded-header flag.
639func sz_walk(b: *u8, n: i64, tbl: *i64, maxm: i64, names: *u8, ncap: i64, st: *i64) -> i64 {
640 let m: *i64 = sys_mmap(8 * SZ_M_N) as *i64
641 let rc: i64 = sz_parse(b, n, m)
642 if rc < 0 { return rc }
643 let total: i64 = m[SZ_M_DATAFILES] + m[SZ_M_EMPTYFILES]
644 if total > maxm { return SZ_ERR_SYNTAX }
645 st[0] = m[SZ_M_DIRS]; st[1] = m[SZ_M_EMPTYFILES]; st[2] = m[SZ_M_NFOLD]; st[3] = m[SZ_M_ENCODED]
646 let es: *i64 = m[SZ_M_FILE_EMPTYSTREAM] as *i64
647 let ef: *i64 = m[SZ_M_FILE_EMPTYFILE] as *i64
648 let noff: *i64 = m[SZ_M_NAMEOFF] as *i64
649 let nlen: *i64 = m[SZ_M_NAMELEN] as *i64
650 let arena: *u8 = m[SZ_M_NAMES] as *u8
651 let fc: *i64 = m[SZ_M_FCODER] as *i64
652 let fnsub: *i64 = m[SZ_M_FNSUB] as *i64
653 let fpack: *i64 = m[SZ_M_FPACKIDX] as *i64
654 let sizes: *i64 = m[SZ_M_PACKSIZES] as *i64
655 let subsz: *i64 = m[SZ_M_SUBSIZE] as *i64
656 let subcrc: *i64 = m[SZ_M_SUBCRC] as *i64
657 let subdef: *i64 = m[SZ_M_SUBCRCDEF] as *i64
658 let rcb: *i64 = sys_mmap(16) as *i64
659 var row: i64 = 0
660 var wo: i64 = 0
661 var folder: i64 = 0
662 var sub_in_folder: i64 = 0
663 var sub: i64 = 0
664 var fbuf: *u8 = 0 as *u8
665 var foff: i64 = 0
666 var fstate: i64 = 0
667 var loaded: i64 = 0 - 1
668 var fi: i64 = 0
669 while fi < m[SZ_M_NFILES] {
670 var is_empty_stream: i64 = 0
671 if (es as i64) != 0 { is_empty_stream = es[fi] }
672 var is_dir: i64 = 0
673 if is_empty_stream == 1 { if ef[fi] == 0 { is_dir = 1 } }
674 if is_dir == 0 {
675 let r: *i64 = bi_rec(tbl, row)
676 var q: i64 = 0
677 while q < BI_F_N { r[q] = 0; q = q + 1 }
678 r[BI_F_NAMEOFF] = wo
679 r[BI_F_NAMELEN] = nlen[fi]
680 var k: i64 = 0
681 if (arena as i64) != 0 { while k < nlen[fi] { if wo + k < ncap - 1 { names[wo + k] = arena[noff[fi] + k] } k = k + 1 } }
682 if wo + nlen[fi] < ncap { names[wo + nlen[fi]] = 0 as u8 }
683 wo = wo + nlen[fi] + 1
684 r[BI_F_BIND] = BI_BIND_NA
685 r[BI_F_BOUND_TO] = 0 - 1
686 if is_empty_stream == 1 {
687 r[BI_F_METHOD] = SZ_CODER_COPY
688 r[BI_F_INFLATE] = BI_INF_STORED
689 r[BI_F_DLEN] = 0
690 } else {
691 // advance to the folder that holds this substream
692 while folder < m[SZ_M_NFOLD] { if sub_in_folder < fnsub[folder] { break } folder = folder + 1; sub_in_folder = 0; foff = 0 }
693 if folder >= m[SZ_M_NFOLD] { return SZ_ERR_SYNTAX }
694 if loaded != folder {
695 fbuf = sz_decode_folder(b, n, m, folder, rcb)
696 fstate = rcb[0]
697 loaded = folder
698 foff = 0
699 }
700 r[BI_F_METHOD] = fc[folder]
701 r[BI_F_CSIZE] = sizes[fpack[folder]]
702 r[BI_F_USIZE] = subsz[sub]
703 r[BI_F_CRC] = subcrc[sub]
704 if (fbuf as i64) != 0 {
705 let data: *u8 = fbuf + foff
706 var crc_ok: i64 = 1
707 if subdef[sub] == 1 { if nxzip_crc32(data, subsz[sub]) != subcrc[sub] { crc_ok = 0 } }
708 if crc_ok == 1 { r[BI_F_INFLATE] = fstate; r[BI_F_DATA] = data as i64; r[BI_F_DLEN] = subsz[sub] }
709 else { r[BI_F_INFLATE] = BI_INF_FAILED }
710 } else { r[BI_F_INFLATE] = fstate; if fstate == BI_INF_STORED { r[BI_F_INFLATE] = BI_INF_FAILED } }
711 foff = foff + subsz[sub]
712 sub = sub + 1
713 sub_in_folder = sub_in_folder + 1
714 }
715 // the ONE ruler: content first, the name only as the claim it is checked against
716 r[BI_F_CLAIM] = ap_claim(names + r[BI_F_NAMEOFF])
717 if r[BI_F_DLEN] > 0 {
718 r[BI_F_MAGIC] = ap_identify(r[BI_F_DATA] as *u8, r[BI_F_DLEN])
719 r[BI_F_CAT] = ap_cat(r[BI_F_MAGIC])
720 if r[BI_F_MAGIC] == AP_UNKNOWN { r[BI_F_VERDICT] = BI_V_UNIDENTIFIED }
721 else { if r[BI_F_CLAIM] == AP_UNKNOWN { r[BI_F_VERDICT] = BI_V_UNCLAIMED }
722 else { if r[BI_F_CLAIM] == r[BI_F_MAGIC] { r[BI_F_VERDICT] = BI_V_AGREE } else { r[BI_F_VERDICT] = BI_V_DISAGREE } } }
723 } else {
724 r[BI_F_MAGIC] = AP_UNKNOWN
725 r[BI_F_CAT] = AP_C_UNKNOWN
726 r[BI_F_VERDICT] = BI_V_UNREAD
727 }
728 row = row + 1
729 }
730 fi = fi + 1
731 }
732 return row
733}
734// ---- THE COPY-CODER 7z WRITER (fixtures only): one folder, one Copy coder, one packed stream holding every member's bytes in
735// order, nfiles substreams with their sizes and CRC-32 digests, a plain (never encoded) header, both header CRCs written.
736// It exists so a gate can build a 7z holding typed members (an OBJ, its MTL, PNG maps, a VMD) at runtime through the estate's
737// own bytes; it is NOT the proof of the decoder -- the real archives written by an outside encoder are. Returns the byte count
738// or a negative error (SZ_ERR_SYNTAX when the output capacity is too small; sizes are derived from the inputs, never guessed).
739func sz_put8(o: *u8, p: *i64, v: i64) -> i64 { o[p[0]] = (v & 255) as u8; p[0] = p[0] + 1; return 1 }
740func sz_put32(o: *u8, p: *i64, v: i64) -> i64 { var i: i64 = 0; var x: i64 = v; while i < 4 { sz_put8(o, p, x & 255); x = x / 256; i = i + 1 } return 4 }
741func sz_put64(o: *u8, p: *i64, v: i64) -> i64 { var i: i64 = 0; var x: i64 = v; while i < 8 { sz_put8(o, p, x & 255); x = x / 256; i = i + 1 } return 8 }
742// the 7z UINT64: n extra little-endian bytes announced by n leading one bits, the high part in the first byte's low bits
743func sz_putnum(o: *u8, p: *i64, v: i64) -> i64 {
744 var n: i64 = 0
745 while n < 8 {
746 let high: i64 = v / lz_pow2(8 * n)
747 if high < lz_pow2(7 - n) {
748 var first: i64 = 0
749 var k: i64 = 0
750 while k < n { first = first + lz_pow2(7 - k); k = k + 1 }
751 first = first + high
752 sz_put8(o, p, first)
753 var i: i64 = 0
754 var x: i64 = v
755 while i < n { sz_put8(o, p, x & 255); x = x / 256; i = i + 1 }
756 return n + 1
757 }
758 n = n + 1
759 }
760 sz_put8(o, p, 255)
761 sz_put64(o, p, v)
762 return 9
763}
764func sz_write_copy(names: *i64, datas: *i64, lens: *i64, nfiles: i64, out: *u8, outcap: i64) -> i64 {
765 var total: i64 = 0
766 var namebytes: i64 = 0
767 var i: i64 = 0
768 while i < nfiles {
769 total = total + lens[i]
770 var k: i64 = 0
771 let nm: *u8 = names[i] as *u8
772 while nm[k] != (0 as u8) { k = k + 1 }
773 namebytes = namebytes + (k + 1) * 2
774 i = i + 1
775 }
776 // header bound: fixed frame + 9 bytes per UINT64 (sizes, counts) + 4 per digest + the names
777 let hcap: i64 = 64 + nfiles * 32 + namebytes
778 if SZ_SIG_LEN + total + hcap > outcap { return SZ_ERR_SYNTAX }
779 // packed streams straight after the signature header
780 var pos: i64 = SZ_SIG_LEN
781 i = 0
782 while i < nfiles {
783 let d: *u8 = datas[i] as *u8
784 var k: i64 = 0
785 while k < lens[i] { out[pos + k] = d[k]; k = k + 1 }
786 pos = pos + lens[i]
787 i = i + 1
788 }
789 let hstart: i64 = pos
790 let p: *i64 = sys_mmap(16) as *i64
791 p[0] = pos
792 sz_put8(out, p, SZ_NID_HEADER)
793 sz_put8(out, p, SZ_NID_MAIN)
794 sz_put8(out, p, SZ_NID_PACK); sz_putnum(out, p, 0); sz_putnum(out, p, 1)
795 sz_put8(out, p, SZ_NID_SIZE); sz_putnum(out, p, total)
796 sz_put8(out, p, SZ_NID_END)
797 sz_put8(out, p, SZ_NID_UNPACK); sz_put8(out, p, SZ_NID_FOLDER); sz_putnum(out, p, 1); sz_put8(out, p, 0)
798 sz_putnum(out, p, 1) // one coder
799 sz_put8(out, p, 1) // flag: id size 1, simple, no properties
800 sz_put8(out, p, SZ_CODER_COPY)
801 sz_put8(out, p, SZ_NID_CODERS_UNPACK); sz_putnum(out, p, total)
802 sz_put8(out, p, SZ_NID_END)
803 sz_put8(out, p, SZ_NID_SUBSTREAMS)
804 sz_put8(out, p, SZ_NID_NUM_UNPACK); sz_putnum(out, p, nfiles)
805 if nfiles > 1 { sz_put8(out, p, SZ_NID_SIZE); i = 0; while i + 1 < nfiles { sz_putnum(out, p, lens[i]); i = i + 1 } }
806 sz_put8(out, p, SZ_NID_CRC); sz_put8(out, p, 1)
807 i = 0
808 while i < nfiles { sz_put32(out, p, nxzip_crc32(datas[i] as *u8, lens[i])); i = i + 1 }
809 sz_put8(out, p, SZ_NID_END)
810 sz_put8(out, p, SZ_NID_END)
811 sz_put8(out, p, SZ_NID_FILES); sz_putnum(out, p, nfiles)
812 sz_put8(out, p, SZ_NID_NAME); sz_putnum(out, p, 1 + namebytes); sz_put8(out, p, 0)
813 i = 0
814 while i < nfiles {
815 let nm: *u8 = names[i] as *u8
816 var k: i64 = 0
817 while nm[k] != (0 as u8) { sz_put8(out, p, (nm[k] & 0xff) as i64); sz_put8(out, p, 0); k = k + 1 }
818 sz_put8(out, p, 0); sz_put8(out, p, 0)
819 i = i + 1
820 }
821 sz_put8(out, p, SZ_NID_END)
822 sz_put8(out, p, SZ_NID_END)
823 let hlen: i64 = p[0] - hstart
824 // signature header: magic, version 0.4, start-header CRC over the 20 bytes that follow it, next header offset/size/CRC
825 out[0] = 55 as u8; out[1] = 122 as u8; out[2] = 188 as u8; out[3] = 175 as u8; out[4] = 39 as u8; out[5] = 28 as u8
826 out[6] = 0 as u8; out[7] = 4 as u8
827 let q: *i64 = sys_mmap(16) as *i64
828 q[0] = SZ_START_HDR_OFF
829 sz_put64(out, q, hstart - SZ_SIG_LEN)
830 sz_put64(out, q, hlen)
831 sz_put32(out, q, nxzip_crc32(out + hstart, hlen))
832 q[0] = 8
833 sz_put32(out, q, nxzip_crc32(out + SZ_START_HDR_OFF, SZ_START_HDR_LEN))
834 return p[0]
835}