use std::collections::BTreeMap; use sylpheed_formats::{idxd::IdxdObject, ratc, PakArchive}; fn main() { let disc = std::env::var("SYLPHEED_DISC").unwrap(); // 1. RATC child-type census across the big RATC paks let mut childtypes: BTreeMap = BTreeMap::new(); let mut ratc_unparsed = 0u64; for pk in [ "GP_READY_ROOM", "GP_MOVIE_THEATER", "GP_DIALOG", "GP_DEBRIEFING_PILOTLOG", "GP_TITLE", "GP_BUNK", ] { let Ok(arc) = PakArchive::open(format!("{disc}/dat/{pk}.pak")) else { continue; }; for e in arc.entries() { let Ok(b) = arc.read(e) else { continue }; if !ratc::is_ratc(&b) { continue; } match ratc::parse(&b) { Some(kids) => { for k in kids { let ext = k.name.rsplit('.').next().unwrap_or("?").to_lowercase(); *childtypes.entry(ext).or_default() += 1; } } None => ratc_unparsed += 1, } } } println!("=== RATC child-type census (big RATC paks) ==="); let mut cv: Vec<_> = childtypes.into_iter().collect(); cv.sort_by_key(|x| std::cmp::Reverse(x.1)); for (e, c) in &cv { println!(" .{e:8} ×{c}"); } println!(" (RATC bundles that failed to parse: {ratc_unparsed})"); // 2. The 00000002 mystery format (GP_MAIN_GAME_E) let arc = PakArchive::open(format!("{disc}/dat/GP_MAIN_GAME_E.pak")).unwrap(); for e in arc.entries() { let Ok(b) = arc.read(e) else { continue }; if b.len() >= 4 && b[0..4] == [0, 0, 0, 2] { let hx: String = b[..48.min(b.len())] .iter() .map(|x| format!("{x:02x}")) .collect::>() .join(" "); let asc: String = b[..64.min(b.len())] .iter() .map(|&x| { if (0x20..0x7f).contains(&x) { x as char } else { '.' } }) .collect(); println!( "\n=== 00000002 format sample ({}B) ===\n{hx}\n{asc}", b.len() ); break; } } // 3. Sample the top undecoded IDXD schemas: first tokens (guess semantics) println!("\n=== top undecoded IDXD schemas — sample tokens (semantic hints) ==="); let targets: [u32; 6] = [ 0xb412e6d8, 0x026379ab, 0x43faa517, 0x3c5b0549, 0x6ab4825a, 0x0426e81d, ]; for want in targets { let mut shown = false; for e in arc.entries() { if shown { break; } let Ok(b) = arc.read(e) else { continue }; if b.len() < 12 || &b[0..4] != b"IDXD" { continue; } let s = u32::from_be_bytes([b[8], b[9], b[10], b[11]]); if s != want { continue; } if let Ok(o) = IdxdObject::parse(&b) { let t = o.tokens(); let sample: Vec = t .iter() .take(14) .map(|s| { let s = s.chars().take(18).collect::(); s }) .collect(); println!(" {want:08x}: {sample:?}"); shown = true; } } if !shown { println!(" {want:08x}: (parse failed / not found)"); } } }