code wiki / (root) / nx_sevenz_lib.nx

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}