nx_varfacts_lib.nx source
↩ module page · 193 lines · 8509 B
1// nx_varfacts_lib.nx -- VaM .var PACKAGE FACT EXTRACTION CORE (conversion tier, VaM lane).
2//
3// A .var is a ZIP archive. THE WALL THIS LANE LIVES BEHIND (standing policy 1785794796 +
4// measure-dont-ship): VaM is a CAPABILITY TARGET -- asset BYTES (meshes/textures/morph deltas)
5// never enter our products or our published plane. What this core reads is the CENTRAL DIRECTORY
6// (file NAMES + sizes = the package's own manifest) and meta.json (the package's own declared
7// license) -- the package describing itself, never its content. Extracted MEASUREMENTS flow to
8// refcorpus behind the k>=8 admission wall like every other reference corpus.
9//
10// COMPOSES INCUMBENTS: EOCD/central-directory walk = the nx_zip_read shape (that organ is a
11// hardwired PyTorch-.bin test, not a library -- the walk is factored HERE as callables); ZIP
12// method-8 members inflate via nx_deflate_inflate, the SAME raw-DEFLATE core under nx_gzip_wrap
13// and nx_zlib_wrap (capacity-bounded; NOT the retired duplicate nx_inflate, debt 1785854636).
14//
15// ★TAIL-WINDOW CONTRACT: the EOCD + central directory live at the END of a ZIP, so a 519MB .var
16// measures from its last few MB. The caller hands the TAIL bytes + the true file size; if the
17// central directory starts before the window, the probe REFUSES (ok=0) -- a partial census is a
18// plausible undercount, which is worse than absence.
19//
20// Fact slots (flat i64, VF_N_SLOTS):
21// [0] ok [1] entries [2] morphs(.vmi) [3] scenes(Saves/scene/*.json) [4] textures(jpg/png/tif)
22// [5] clothing(/Clothing/) [6] hair(/Hair/) [7] plugins(.cs/.cslist/.dll) [8] appearance(.vap)
23// [9] meta_found [10] meta_lho [11] meta_method [12] meta_csize [13] meta_usize
24// license_tier: ORIGINAL No hw writes (Rule 26).
25import "nx_syscalls.nx"
26import "nx_deflate.nx"
27const VF_MAGIC_1024: i64 = 1024
28const VF_MAGIC_4194304: i64 = 4194304
29
30const VF_N_SLOTS: i64 = 14
31
32func vf_u16(b: *u8, o: i64) -> i64 { return (b[o] as i64 & 0xff) | ((b[o+1] as i64 & 0xff) << 8) }
33func vf_u32(b: *u8, o: i64) -> i64 { return (b[o] as i64 & 0xff) | ((b[o+1] as i64 & 0xff) << 8) | ((b[o+2] as i64 & 0xff) << 16) | ((b[o+3] as i64 & 0xff) << 24) }
34
35// name[0,nl) ends with suffix?
36func vf_ends(name: *u8, nl: i64, suf: *u8) -> i64 {
37 var m: i64 = 0
38 while suf[m] != (0 as u8) { m = m + 1 }
39 if nl < m { return 0 }
40 var i: i64 = 0
41 while i < m { if (name[nl-m+i] as i64) != (suf[i] as i64) { return 0 } i = i + 1 }
42 return 1
43}
44func vf_has(name: *u8, nl: i64, sub: *u8) -> i64 {
45 var m: i64 = 0
46 while sub[m] != (0 as u8) { m = m + 1 }
47 if nl < m { return 0 }
48 var i: i64 = 0
49 while i + m <= nl {
50 var k: i64 = 0
51 while k < m { if (name[i+k] as i64) != (sub[k] as i64) { k = m + 9 } else { k = k + 1 } }
52 if k == m { return 1 }
53 i = i + 1
54 }
55 return 0
56}
57
58// probe the TAIL of a .var: tail holds the last tailn bytes, file_size is the true size.
59func vf_probe(tail: *u8, tailn: i64, file_size: i64, facts: *i64) -> i64 {
60 var i: i64 = 0
61 while i < VF_N_SLOTS { facts[i] = 0 - 1; i = i + 1 }
62 facts[0] = 0
63 if tailn < 22 { return 0 }
64 // EOCD: scan back for PK\5\6
65 var e: i64 = tailn - 22
66 var eocd: i64 = 0 - 1
67 while e >= 0 {
68 if (tail[e] as i64) == 0x50 { if (tail[e+1] as i64) == 0x4b { if (tail[e+2] as i64) == 0x05 { if (tail[e+3] as i64) == 0x06 {
69 eocd = e; e = 0 - 1
70 } } } }
71 if e >= 0 { e = e - 1 }
72 }
73 if eocd < 0 { return 0 }
74 let entries: i64 = vf_u16(tail, eocd + 10)
75 let cd_size: i64 = vf_u32(tail, eocd + 12)
76 let cd_abs: i64 = vf_u32(tail, eocd + 16)
77 if entries == 0xffff { return 0 } // ZIP64: refuse honestly, never undercount
78 let base: i64 = file_size - tailn // absolute offset of tail[0]
79 let cd: i64 = cd_abs - base
80 if cd < 0 { return 0 } // CD starts before the window: REFUSE
81 if cd + cd_size > tailn { return 0 }
82 var morphs: i64 = 0
83 var scenes: i64 = 0
84 var tex: i64 = 0
85 var cloth: i64 = 0
86 var hair: i64 = 0
87 var plug: i64 = 0
88 var vap: i64 = 0
89 var off: i64 = cd
90 var k: i64 = 0
91 while k < entries {
92 if off + 46 > tailn { facts[0] = 0; return 0 }
93 if (tail[off] as i64) != 0x50 { facts[0] = 0; return 0 }
94 if (tail[off+1] as i64) != 0x4b { facts[0] = 0; return 0 }
95 let method: i64 = vf_u16(tail, off + 10)
96 let csize: i64 = vf_u32(tail, off + 20)
97 let usize: i64 = vf_u32(tail, off + 24)
98 let fnl: i64 = vf_u16(tail, off + 28)
99 let exl: i64 = vf_u16(tail, off + 30)
100 let cml: i64 = vf_u16(tail, off + 32)
101 let lho: i64 = vf_u32(tail, off + 42)
102 let nm: *u8 = ((tail as i64) + off + 46) as *u8
103 if vf_ends(nm, fnl, ".vmi" as *u8) == 1 { morphs = morphs + 1 }
104 if vf_has(nm, fnl, "Saves/scene/" as *u8) == 1 { if vf_ends(nm, fnl, ".json" as *u8) == 1 { scenes = scenes + 1 } }
105 if vf_ends(nm, fnl, ".jpg" as *u8) == 1 { tex = tex + 1 }
106 if vf_ends(nm, fnl, ".png" as *u8) == 1 { tex = tex + 1 }
107 if vf_ends(nm, fnl, ".tif" as *u8) == 1 { tex = tex + 1 }
108 if vf_has(nm, fnl, "/Clothing/" as *u8) == 1 { cloth = cloth + 1 }
109 if vf_has(nm, fnl, "/Hair/" as *u8) == 1 { hair = hair + 1 }
110 if vf_ends(nm, fnl, ".cs" as *u8) == 1 { plug = plug + 1 }
111 if vf_ends(nm, fnl, ".cslist" as *u8) == 1 { plug = plug + 1 }
112 if vf_ends(nm, fnl, ".dll" as *u8) == 1 { plug = plug + 1 }
113 if vf_ends(nm, fnl, ".vap" as *u8) == 1 { vap = vap + 1 }
114 if fnl == 9 { if vf_has(nm, fnl, "meta.json" as *u8) == 1 {
115 facts[9] = 1
116 facts[10] = lho
117 facts[11] = method
118 facts[12] = csize
119 facts[13] = usize
120 } }
121 off = off + 46 + fnl + exl + cml
122 k = k + 1
123 }
124 facts[0] = 1
125 facts[1] = entries
126 facts[2] = morphs
127 facts[3] = scenes
128 facts[4] = tex
129 facts[5] = cloth
130 facts[6] = hair
131 facts[7] = plug
132 facts[8] = vap
133 if facts[9] != 1 { facts[9] = 0 }
134 return 0
135}
136
137// extract the declared licenseType from a meta.json BODY (already read from the archive; method 0
138// = as-is, method 8 = raw deflate via the incumbent core). Writes a NUL-terminated label (max 40
139// chars, whitelist alphabet) or "unparsed". The body is the package DESCRIBING itself -- the one
140// member this lane ever opens.
141func vf_license(body: *u8, csize: i64, method: i64, usize: i64, out: *u8) -> i64 {
142 var src: *u8 = body
143 var n: i64 = csize
144 if method == 8 {
145 var cap: i64 = usize + 64
146 if cap < VF_MAGIC_1024 { cap = VF_MAGIC_1024 }
147 if cap > VF_MAGIC_4194304 { out[0] = 0 as u8; return 0 - 1 }
148 let dr: *NxDeflateResult = nx_deflate_inflate(body, csize, cap)
149 if (dr as i64) == 0 { out[0] = 0 as u8; return 0 - 1 }
150 if dr.error_code != 0 { out[0] = 0 as u8; return 0 - 1 }
151 src = dr.output_data
152 n = dr.output_size
153 } else { if method != 0 { out[0] = 0 as u8; return 0 - 1 } }
154 // find "licenseType" then the next quoted string
155 let key: *u8 = "licenseType" as *u8
156 var at: i64 = 0 - 1
157 var i: i64 = 0
158 while i + 11 <= n {
159 var k: i64 = 0
160 while k < 11 { if (src[i+k] as i64) != (key[k] as i64) { k = 20 } else { k = k + 1 } }
161 if k == 11 { at = i + 11; i = n + 1 } else { i = i + 1 }
162 }
163 if at < 0 { out[0] = 0 as u8; return 0 - 1 }
164 // the value: first ':' after the key, then the first '"' after that opens it
165 var colon: i64 = 0 - 1
166 i = at
167 while i < n { if (src[i] as i64) == 58 { colon = i; i = n + 1 } else { i = i + 1 } }
168 if colon < 0 { out[0] = 0 as u8; return 0 - 1 }
169 var vq: i64 = 0 - 1
170 i = colon + 1
171 while i < n { if (src[i] as i64) == 34 { vq = i + 1; i = n + 1 } else { i = i + 1 } }
172 if vq < 0 { out[0] = 0 as u8; return 0 - 1 }
173 var p: i64 = 0
174 i = vq
175 while i < n {
176 let c2: i64 = src[i] as i64
177 if c2 == 34 { out[p] = 0 as u8; return p }
178 var ok: i64 = 0
179 if c2 >= 48 { if c2 <= 57 { ok = 1 } }
180 if c2 >= 65 { if c2 <= 90 { ok = 1 } }
181 if c2 >= 97 { if c2 <= 122 { ok = 1 } }
182 if c2 == 32 { ok = 1 }
183 if c2 == 45 { ok = 1 }
184 if c2 == 46 { ok = 1 }
185 if ok == 0 { out[0] = 0 as u8; return 0 - 1 }
186 if p >= 40 { out[0] = 0 as u8; return 0 - 1 }
187 out[p] = c2 as u8
188 p = p + 1
189 i = i + 1
190 }
191 out[0] = 0 as u8
192 return 0 - 1
193}