code wiki / (root) / nx_assetprobe_lib.nx

nx_assetprobe_lib.nx source

↩ module page · 251 lines · 10405 B

1// nx_assetprobe_lib.nx -- THE ONE CONTENT-TYPE RULER FOR INGESTION (extracted 2026-09-06 from nx_assetprobe.nx, byte-for-byte 2// where the functions already existed, so the program and the bundle walker share ONE identify/classify/claim and cannot 3// drift). AN EXTENSION IS A CLAIM. THE MAGIC BYTES ARE THE MEASUREMENT. Binary formats match at an EXACT offset; text formats 4// get a BOUNDED scan of the first AP_TEXTWIN bytes. 5// GROWN in the extraction, each an exact-offset magic or a bounded keyword pair, never a guess: OBJ and MTL (Wavefront text -- 6// the first ingest fixture on /compare/modding MD1 is an OBJ plus its MTL and four maps, and a walker that cannot type them by 7// content would fall back to the filename it exists to distrust), DDS (the texture container every Bethesda mod ships), NIF 8// (the Bethesda mesh container nx_nif_lib already decodes), 7z and RAR (the archives Nexus files usually arrive in, typed as 9// BUNDLE so a walker can REPORT them by name rather than read them as noise -- their readers are owed, not faked). 10// license_tier: ORIGINAL No hw writes (Rule 26). 11import "nx_syscalls.nx" 12 13const AP_TEXTWIN: i64 = 4096 14 15const AP_UNKNOWN: i64 = 0 16const AP_PMX: i64 = 1 17const AP_PMD: i64 = 2 18const AP_FBXB: i64 = 3 19const AP_GLB: i64 = 4 20const AP_PNG: i64 = 5 21const AP_JPG: i64 = 6 22const AP_HDR: i64 = 7 23const AP_OGG: i64 = 8 24const AP_MP3: i64 = 9 25const AP_MP4: i64 = 10 26const AP_WAV: i64 = 11 27const AP_ZIP: i64 = 12 28const AP_VMD: i64 = 13 29const AP_BVH: i64 = 14 30const AP_OBJ: i64 = 15 31const AP_MTL: i64 = 16 32const AP_DDS: i64 = 17 33const AP_NIF: i64 = 18 34const AP_7Z: i64 = 19 35const AP_RAR: i64 = 20 36 37const AP_C_UNKNOWN: i64 = 0 38const AP_C_MODEL: i64 = 1 39const AP_C_MOTION: i64 = 2 40const AP_C_AUDIO: i64 = 3 41const AP_C_VIDEO: i64 = 4 42const AP_C_TEXTURE: i64 = 5 43const AP_C_BUNDLE: i64 = 6 44const AP_C_MATERIAL: i64 = 7 45 46func ap_slen(s: *u8) -> i64 { var i: i64 = 0; while s[i] != (0 as u8) { i = i + 1 } return i } 47 48func ap_u16(b: *u8, o: i64) -> i64 { return ((b[o] & 0xff) as i64) | (((b[o+1] & 0xff) as i64) << 8) } 49func ap_u32(b: *u8, o: i64) -> i64 { 50 return ((b[o] & 0xff) as i64) | (((b[o+1] & 0xff) as i64) << 8) 51 | (((b[o+2] & 0xff) as i64) << 16) | (((b[o+3] & 0xff) as i64) << 24) 52} 53 54// exact-offset magic 55func ap_at(b: *u8, len: i64, off: i64, pat: *u8) -> i64 { 56 let n: i64 = ap_slen(pat) 57 if off + n > len { return 0 } 58 var i: i64 = 0 59 while i < n { if b[off + i] != pat[i] { return 0 } i = i + 1 } 60 return 1 61} 62 63// bounded text scan: a keyword within the first AP_TEXTWIN bytes 64func ap_scan(b: *u8, len: i64, pat: *u8) -> i64 { 65 let n: i64 = ap_slen(pat) 66 var win: i64 = AP_TEXTWIN 67 if len < win { win = len } 68 if n > win { return 0 } 69 var i: i64 = 0 70 while i + n <= win { 71 var k: i64 = 0 72 var ok: i64 = 1 73 while k < n { 74 if b[i + k] != pat[k] { ok = 0; k = n } else { k = k + 1 } 75 } 76 if ok == 1 { return 1 } 77 i = i + 1 78 } 79 return 0 80} 81 82// a keyword at the START of a line inside the text window: at offset 0, or preceded by a newline 83func ap_scan_bol(b: *u8, len: i64, pat: *u8) -> i64 { 84 let n: i64 = ap_slen(pat) 85 var win: i64 = AP_TEXTWIN 86 if len < win { win = len } 87 if n > win { return 0 } 88 var i: i64 = 0 89 while i + n <= win { 90 var bol: i64 = 0 91 if i == 0 { bol = 1 } else { if b[i - 1] == (10 as u8) { bol = 1 } } 92 if bol == 1 { 93 var k: i64 = 0 94 var ok: i64 = 1 95 while k < n { 96 if b[i + k] != pat[k] { ok = 0; k = n } else { k = k + 1 } 97 } 98 if ok == 1 { return 1 } 99 } 100 i = i + 1 101 } 102 return 0 103} 104 105func ap_identify(b: *u8, len: i64) -> i64 { 106 if len < 4 { return AP_UNKNOWN } 107 // byte-exact binary magics first (numeric compares avoid non-ASCII literals) 108 if (b[0] & 0xff) as i64 == 0x89 { 109 if ap_at(b, len, 1, "PNG" as *u8) == 1 { return AP_PNG } 110 } 111 if (b[0] & 0xff) as i64 == 0xff { 112 if (b[1] & 0xff) as i64 == 0xd8 { if (b[2] & 0xff) as i64 == 0xff { return AP_JPG } } 113 } 114 if (b[0] & 0xff) as i64 == 0x50 { 115 if (b[1] & 0xff) as i64 == 0x4b { 116 if (b[2] & 0xff) as i64 == 0x03 { if (b[3] & 0xff) as i64 == 0x04 { return AP_ZIP } } 117 } 118 } 119 // 7z: 37 7A BC AF 27 1C at offset 0 120 if (b[0] & 0xff) as i64 == 0x37 { 121 if (b[1] & 0xff) as i64 == 0x7a { if (b[2] & 0xff) as i64 == 0xbc { if (b[3] & 0xff) as i64 == 0xaf { return AP_7Z } } } 122 } 123 if ap_at(b, len, 0, "Rar!" as *u8) == 1 { return AP_RAR } 124 if ap_at(b, len, 0, "DDS " as *u8) == 1 { return AP_DDS } 125 if ap_at(b, len, 0, "Gamebryo File Format" as *u8) == 1 { return AP_NIF } 126 if ap_at(b, len, 0, "NetImmerse File Format" as *u8) == 1 { return AP_NIF } 127 if ap_at(b, len, 0, "PMX " as *u8) == 1 { return AP_PMX } 128 if ap_at(b, len, 0, "Pmd" as *u8) == 1 { return AP_PMD } 129 if ap_at(b, len, 0, "Kaydara FBX Binary" as *u8) == 1 { return AP_FBXB } 130 if ap_at(b, len, 0, "glTF" as *u8) == 1 { return AP_GLB } 131 if ap_at(b, len, 0, "OggS" as *u8) == 1 { return AP_OGG } 132 if ap_at(b, len, 0, "ID3" as *u8) == 1 { return AP_MP3 } 133 if ap_at(b, len, 4, "ftyp" as *u8) == 1 { return AP_MP4 } 134 if ap_at(b, len, 0, "RIFF" as *u8) == 1 { 135 if ap_at(b, len, 8, "WAVE" as *u8) == 1 { return AP_WAV } 136 } 137 if ap_at(b, len, 0, "Vocaloid Motion Data" as *u8) == 1 { return AP_VMD } 138 // text formats: bounded scan (BOMs, comments, transport preambles precede the keyword) 139 if ap_scan(b, len, "#?RADIANCE" as *u8) == 1 { return AP_HDR } 140 if ap_scan(b, len, "HIERARCHY" as *u8) == 1 { return AP_BVH } 141 if ap_scan(b, len, "; FBX" as *u8) == 1 { return AP_FBXB } 142 // Wavefront: a material library declares newmtl at a line start; a mesh declares vertices (v ) AND faces or texture 143 // coordinates at line starts -- one keyword alone is a comment away from a false positive, two is a shape 144 if ap_scan_bol(b, len, "newmtl " as *u8) == 1 { return AP_MTL } 145 if ap_scan_bol(b, len, "v " as *u8) == 1 { 146 if ap_scan_bol(b, len, "f " as *u8) == 1 { return AP_OBJ } 147 if ap_scan_bol(b, len, "vt " as *u8) == 1 { return AP_OBJ } 148 if ap_scan_bol(b, len, "vn " as *u8) == 1 { return AP_OBJ } 149 } 150 return AP_UNKNOWN 151} 152 153func ap_name(c: i64) -> *u8 { 154 if c == AP_PMX { return "PMX" as *u8 } 155 if c == AP_PMD { return "PMD" as *u8 } 156 if c == AP_FBXB { return "FBX" as *u8 } 157 if c == AP_GLB { return "GLB" as *u8 } 158 if c == AP_PNG { return "PNG" as *u8 } 159 if c == AP_JPG { return "JPG" as *u8 } 160 if c == AP_HDR { return "HDR" as *u8 } 161 if c == AP_OGG { return "OGG" as *u8 } 162 if c == AP_MP3 { return "MP3" as *u8 } 163 if c == AP_MP4 { return "MP4" as *u8 } 164 if c == AP_WAV { return "WAV" as *u8 } 165 if c == AP_ZIP { return "ZIP" as *u8 } 166 if c == AP_VMD { return "VMD" as *u8 } 167 if c == AP_BVH { return "BVH" as *u8 } 168 if c == AP_OBJ { return "OBJ" as *u8 } 169 if c == AP_MTL { return "MTL" as *u8 } 170 if c == AP_DDS { return "DDS" as *u8 } 171 if c == AP_NIF { return "NIF" as *u8 } 172 if c == AP_7Z { return "7Z" as *u8 } 173 if c == AP_RAR { return "RAR" as *u8 } 174 return "UNKNOWN" as *u8 175} 176 177func ap_cat(c: i64) -> i64 { 178 if c == AP_PMX { return AP_C_MODEL } 179 if c == AP_PMD { return AP_C_MODEL } 180 if c == AP_FBXB { return AP_C_MODEL } 181 if c == AP_GLB { return AP_C_MODEL } 182 if c == AP_OBJ { return AP_C_MODEL } 183 if c == AP_NIF { return AP_C_MODEL } 184 if c == AP_MTL { return AP_C_MATERIAL } 185 if c == AP_VMD { return AP_C_MOTION } 186 if c == AP_BVH { return AP_C_MOTION } 187 if c == AP_OGG { return AP_C_AUDIO } 188 if c == AP_MP3 { return AP_C_AUDIO } 189 if c == AP_WAV { return AP_C_AUDIO } 190 if c == AP_MP4 { return AP_C_VIDEO } 191 if c == AP_PNG { return AP_C_TEXTURE } 192 if c == AP_JPG { return AP_C_TEXTURE } 193 if c == AP_HDR { return AP_C_TEXTURE } 194 if c == AP_DDS { return AP_C_TEXTURE } 195 if c == AP_ZIP { return AP_C_BUNDLE } 196 if c == AP_7Z { return AP_C_BUNDLE } 197 if c == AP_RAR { return AP_C_BUNDLE } 198 return AP_C_UNKNOWN 199} 200 201func ap_catname(k: i64) -> *u8 { 202 if k == AP_C_MODEL { return "model" as *u8 } 203 if k == AP_C_MOTION { return "motion" as *u8 } 204 if k == AP_C_AUDIO { return "audio" as *u8 } 205 if k == AP_C_VIDEO { return "video" as *u8 } 206 if k == AP_C_TEXTURE { return "texture" as *u8 } 207 if k == AP_C_BUNDLE { return "bundle" as *u8 } 208 if k == AP_C_MATERIAL { return "material" as *u8 } 209 return "unknown" as *u8 210} 211 212// lowercase-insensitive suffix test 213func ap_lc(c: i64) -> i64 { if c >= 65 { if c <= 90 { return c + 32 } } return c } 214func ap_ends(path: *u8, ext: *u8) -> i64 { 215 let pn: i64 = ap_slen(path) 216 let en: i64 = ap_slen(ext) 217 if en > pn { return 0 } 218 var i: i64 = 0 219 while i < en { 220 if ap_lc((path[pn - en + i] & 0xff) as i64) != ap_lc((ext[i] & 0xff) as i64) { return 0 } 221 i = i + 1 222 } 223 return 1 224} 225 226// the EXTENSION'S CLAIM -- never the answer, only the thing the answer is checked against 227func ap_claim(path: *u8) -> i64 { 228 if ap_ends(path, ".pmx" as *u8) == 1 { return AP_PMX } 229 if ap_ends(path, ".pmd" as *u8) == 1 { return AP_PMD } 230 if ap_ends(path, ".fbx" as *u8) == 1 { return AP_FBXB } 231 if ap_ends(path, ".glb" as *u8) == 1 { return AP_GLB } 232 if ap_ends(path, ".vrm" as *u8) == 1 { return AP_GLB } 233 if ap_ends(path, ".png" as *u8) == 1 { return AP_PNG } 234 if ap_ends(path, ".jpg" as *u8) == 1 { return AP_JPG } 235 if ap_ends(path, ".jpeg" as *u8) == 1 { return AP_JPG } 236 if ap_ends(path, ".hdr" as *u8) == 1 { return AP_HDR } 237 if ap_ends(path, ".ogg" as *u8) == 1 { return AP_OGG } 238 if ap_ends(path, ".mp3" as *u8) == 1 { return AP_MP3 } 239 if ap_ends(path, ".mp4" as *u8) == 1 { return AP_MP4 } 240 if ap_ends(path, ".wav" as *u8) == 1 { return AP_WAV } 241 if ap_ends(path, ".zip" as *u8) == 1 { return AP_ZIP } 242 if ap_ends(path, ".vmd" as *u8) == 1 { return AP_VMD } 243 if ap_ends(path, ".bvh" as *u8) == 1 { return AP_BVH } 244 if ap_ends(path, ".obj" as *u8) == 1 { return AP_OBJ } 245 if ap_ends(path, ".mtl" as *u8) == 1 { return AP_MTL } 246 if ap_ends(path, ".dds" as *u8) == 1 { return AP_DDS } 247 if ap_ends(path, ".nif" as *u8) == 1 { return AP_NIF } 248 if ap_ends(path, ".7z" as *u8) == 1 { return AP_7Z } 249 if ap_ends(path, ".rar" as *u8) == 1 { return AP_RAR } 250 return AP_UNKNOWN 251}