//! Build script: parse xenia's xboxkrnl_table.inc and xam_table.inc to generate //! ordinal->name lookup tables at compile time. use std::env; use std::fs; use std::io::Write; use std::path::Path; fn parse_table(path: &Path) -> Vec<(u32, String, String)> { let content = match fs::read_to_string(path) { Ok(c) => c, Err(e) => { eprintln!("cargo:warning=could not read {}: {}", path.display(), e); return Vec::new(); } }; let mut entries = Vec::new(); for line in content.lines() { let line = line.trim(); // XE_EXPORT(module, 0xNNNNNNNN, Name, kType), if !line.starts_with("XE_EXPORT(") { continue; } let inner = match line.strip_prefix("XE_EXPORT(").and_then(|s| s.strip_suffix("),")) { Some(s) => s, None => continue, }; let parts: Vec<&str> = inner.splitn(4, ',').map(|s| s.trim()).collect(); if parts.len() < 4 { continue; } let module = parts[0].to_string(); let ordinal = match u32::from_str_radix(parts[1].trim_start_matches("0x").trim_start_matches("0X"), 16) { Ok(n) => n, Err(_) => continue, }; let name = parts[2].to_string(); entries.push((ordinal, name, module)); } entries } fn main() { let out_dir = env::var("OUT_DIR").unwrap(); let dest = Path::new(&out_dir).join("ordinals.rs"); let mut f = fs::File::create(&dest).unwrap(); // Locate xenia tables relative to the workspace root // crates/xenia-analysis/ -> ../../ -> workspace root -> ../xenia-canary/ let manifest = env::var("CARGO_MANIFEST_DIR").unwrap(); let workspace_root = Path::new(&manifest).parent().unwrap().parent().unwrap(); let project_root = workspace_root.parent().unwrap(); let krnl_path = project_root .join("xenia-canary/src/xenia/kernel/xboxkrnl/xboxkrnl_table.inc"); let xam_path = project_root .join("xenia-canary/src/xenia/kernel/xam/xam_table.inc"); println!("cargo:rerun-if-changed={}", krnl_path.display()); println!("cargo:rerun-if-changed={}", xam_path.display()); let krnl = parse_table(&krnl_path); let xam = parse_table(&xam_path); writeln!(f, "/// Auto-generated from xenia's export tables.").unwrap(); writeln!(f, "pub fn resolve_ordinal(lib: &str, ordinal: u16) -> Option<&'static str> {{").unwrap(); writeln!(f, " match lib {{").unwrap(); // xboxkrnl.exe writeln!(f, " \"xboxkrnl.exe\" => match ordinal {{").unwrap(); for (ord, name, _) in &krnl { writeln!(f, " 0x{ord:04X} => Some(\"{name}\"),").unwrap(); } writeln!(f, " _ => None,").unwrap(); writeln!(f, " }},").unwrap(); // xam.xex writeln!(f, " \"xam.xex\" => match ordinal {{").unwrap(); for (ord, name, _) in &xam { writeln!(f, " 0x{ord:04X} => Some(\"{name}\"),").unwrap(); } writeln!(f, " _ => None,").unwrap(); writeln!(f, " }},").unwrap(); writeln!(f, " _ => None,").unwrap(); writeln!(f, " }}").unwrap(); writeln!(f, "}}").unwrap(); eprintln!("ordinals.rs: {} xboxkrnl + {} xam entries", krnl.len(), xam.len()); }