//! Scratch: confirm the `.rat` layout record offsets against a real screen pak. //! Run: cargo run -p sylpheed-formats --example rat_inspect -- use sylpheed_formats::{pak::PakArchive, ratc, t8ad}; fn be32(b: &[u8], o: usize) -> u32 { u32::from_be_bytes([b[o], b[o + 1], b[o + 2], b[o + 3]]) } fn main() { let path = std::env::args().nth(1).expect("pak path"); let ar = PakArchive::open(&path).expect("open pak"); println!("entries: {}", ar.len()); let mut decoded: Vec> = Vec::new(); for (i, e) in ar.entries().iter().enumerate() { let d = ar.read(e).unwrap_or_default(); let magic = String::from_utf8_lossy(&d[..4.min(d.len())]).to_string(); let (nt, nr) = if ratc::is_ratc(&d) { let k = ratc::parse(&d).unwrap_or_default(); ( k.iter().filter(|c| c.kind == "T8aD").count(), k.iter() .filter(|c| c.name.to_lowercase().ends_with(".rat")) .count(), ) } else { (0, 0) }; println!( " entry[{:2}] {:>8} B magic={:4} t32={:2} rat={:2}", i, d.len(), magic, nt, nr ); decoded.push(d); } // Pick the entry with the most children as "build0". let bi = (0..decoded.len()) .filter(|&i| ratc::is_ratc(&decoded[i])) .max_by_key(|&i| ratc::parse(&decoded[i]).map(|k| k.len()).unwrap_or(0)) .unwrap(); println!("=> inspecting richest build: entry[{}]", bi); let bundle = &decoded[bi]; let kids = ratc::parse(bundle).unwrap_or_default(); let t32: Vec<_> = kids.iter().filter(|c| c.kind == "T8aD").collect(); let rat: Vec<_> = kids .iter() .filter(|c| c.name.to_lowercase().ends_with(".rat")) .collect(); println!( "build0: {} children, {} t32 sprites, {} rat records", kids.len(), t32.len(), rat.len() ); for c in t32.iter().take(5) { let b = &bundle[c.offset..(c.offset + c.size).min(bundle.len())]; if let Some(img) = t8ad::parse(b) { println!(" T8aD {:28} {}x{}", c.name, img.width, img.height); } } println!(" -- .rat records --"); for c in rat.iter().take(10) { let r = &bundle[c.offset..(c.offset + c.size).min(bundle.len())]; if r.len() < 0x60 { println!(" .rat {:20} (len {}, too short)", c.name, r.len()); continue; } let (dw, dh) = (be32(r, 0x18), be32(r, 0x1c)); let sprite = { let s = &r[0x20..0x30.min(r.len())]; let end = s.iter().position(|&b| b == 0).unwrap_or(s.len()); String::from_utf8_lossy(&s[..end]).to_string() }; let (pvx, pvy) = (be32(r, 0x50), be32(r, 0x54)); // scan for placement block [scaleX=100, scaleY=100, tint, X