@@ 48,26 48,32 @@ pub fn parse(data: &[u8]) -> Option<AlDat> {
let unk2 = reader.read_chunk::<4>()?;
let script_name = reader.read_c_ascii_str().ok()?;
+ println!("offset after script name = 0x{:x}, table list offset = 0x{:?}", reader.offset(), table_list_offset);
+
// read offsets of table names and data
reader.set_offset(usize::try_from(table_list_offset).unwrap());
let mut table_name_offsets = std::vec::Vec::with_capacity(n_tables);
let mut table_data_offsets = std::vec::Vec::with_capacity(n_tables);
+ println!("before data offsets 0x{:x}", reader.offset());
for _ in 0..n_tables {
let off = reader.read_u32_le()?;
ensure!(off % 4 == 0);
table_data_offsets.push(off);
}
+ println!("after data offsets 0x{:x}", reader.offset());
for _ in 0..n_tables {
table_name_offsets.push(reader.read_u16_le()?);
}
+ println!("after name offsets 0x{:x}", reader.offset());
+
// read table names and contents, record alignments
let mut tables = std::vec::Vec::with_capacity(n_tables);
let mut alignment = std::collections::BTreeMap::new();
for i in 0..n_tables {
- println!("start {i}");
+ println!("start {i} (name offset 0x{:x})", table_name_offsets[i]);
let name = reader.clone_at_offset(table_name_offsets[i].try_into().unwrap()).read_c_ascii_str().ok()?;
// we assume the table data is always sorted. it seems to work out.
@@ 20,6 20,7 @@ pub fn serialize(aldat: &AlDat) -> Option<std::vec::Vec<u8>> {
};
let table_list_offset: usize = 33 + aldat.name.len_with_padding().get() + padding_before_table_list;
+ println!("ser table_list_offset = 0x{table_list_offset:x}");
writer.write_u32_le(table_list_offset.try_into().unwrap());
// redundant stuff
@@ 32,6 33,7 @@ pub fn serialize(aldat: &AlDat) -> Option<std::vec::Vec<u8>> {
// calculate table data offsets and name offsets
let table_names_offset: usize = table_list_offset + 6 * aldat.entries.len();
+ dbg!(table_names_offset);
let table_names_end_offset = table_names_offset + aldat.entries.iter().map(|ent| ent.name_len_with_padding()).sum::<usize>();
let table_data_padding = if table_names_end_offset % 4 == 0 { 0 } else { 4 - table_names_end_offset % 4 };
let table_data_offset = table_names_end_offset + table_data_padding;
@@ 11,48 11,61 @@ fn compare_data(expected: &[u8], actual: &[u8]) {
}
#[test]
-fn test_battle_scripts_reverie() {
- let dir = "private-test-data/cs5/nisa-pc-1.0.6/scripts/battle/dat_en/";
- //let dir = "private-test-data/cs5/nisa-pc-1.0.6/scripts/scena/dat_en/";
- //let dir = "private-test-data/cs5/nisa-pc-1.0.6/scripts/ani/dat_en/";
- for dirent in std::fs::read_dir(dir).unwrap() {
- let path = dirent.unwrap().path();
- println!("{}", path.display());
- let data = std::fs::read(path).unwrap();
- let aldat = parse(data.as_slice()).unwrap();
- //println!("{:?}", aldat);
- let roundtripped = serialize(&aldat).unwrap();
- std::fs::write("/tmp/foo.tmp", &roundtripped).unwrap();
- compare_data(&data, &roundtripped);
- }
-}
+fn test_scripts_reverie() {
+ let roundtrip_fails: std::collections::BTreeSet<&'static str> = [
+ "ani/dat_en/chr003_mg16.dat",
+ "ani/dat_en/chr970_c00.dat",
+ "ani/dat_en/mon000s.dat",
+ "ani/dat_en/mon027_c00.dat",
+ "ani/dat_en/mon037_c00.dat",
+ "ani/dat_en/mon042_c00.dat",
+ "ani/dat_en/mon042_c01.dat",
+ "ani/dat_en/mon046_c00.dat",
+ "ani/dat_en/mon093.dat",
+ "ani/dat_en/mon426.dat",
+ "ani/dat_en/mon_171.dat",
+ "ani/dat_en/mon_template.dat",
+ "ani/dat_en/npcx00.dat",
+ "ani/dat_en/npcx02.dat",
+ "ani/dat_en/npcx03.dat",
+ "ani/dat_en/npcx04.dat",
+ "ani/dat_en/ply000.dat",
+ "ani/dat_en/rob030.dat",
+ "ani/dat_en/chr_enemy_template.dat",
+ "ani/dat_en/rob013_c00.dat",
+ "ani/dat_en/ply001.dat",
+ "scena/dat_en/a0106.dat",
+ ]
+ .into_iter()
+ .collect();
-#[test]
-fn test_tmp() {
- /*
- let dir = "private-test-data/cs5/nisa-pc-1.0.6/scripts/battle/dat_en/";
- let skip = [
- "btl1000.dat",
- "btl1001.dat",
- "btlwin.dat",
- "btl_00_01_02.dat",
- "btl_A1_11_01.dat",
- "btl_A4_20_01.dat",
- "btl_TU_00_00_00.dat",
- "btl_TU_00_02_00.dat",
- "btl_TU_00_03_00.dat",
- "btl_TU_A1_03_00.dat",
- "btl_TU_B1_06_00.dat",
- "btlsys.dat",
- ];
- for dirent in std::fs::read_dir(dir).unwrap() {
- let path = dirent.unwrap().path();
- if skip.iter().any(|f| path.ends_with(f)) {
- println!("{}", path.display());
+ let base = std::path::Path::new("private-test-data/cs5/nisa-pc-1.0.6/scripts/");
+ for script_folder_dirent in std::fs::read_dir(base).unwrap() {
+ let dir = script_folder_dirent.unwrap().path().join("dat_en");
+ for dirent in std::fs::read_dir(dir).unwrap() {
+ let path = dirent.unwrap().path();
+ let relative_path = path.strip_prefix(base).unwrap().to_str().unwrap();
+ if roundtrip_fails.contains(relative_path) {
+ println!("SKIPPING {relative_path}");
+ continue;
+ }
+ println!("{relative_path}");
let data = std::fs::read(path).unwrap();
- assert!(parse(data.as_slice()).is_none());
+ let aldat = parse(data.as_slice()).unwrap();
+ //println!("{:?}", aldat);
+ let roundtripped = serialize(&aldat).unwrap();
+ //std::fs::write("/tmp/foo.tmp", &roundtripped).unwrap();
+ compare_data(&data, &roundtripped);
}
}
- todo!()
- */
+
+ for relative_path in roundtrip_fails.iter().copied() {
+ let path = base.join(relative_path);
+ println!("{relative_path}");
+ let data = std::fs::read(&path).unwrap();
+ let aldat = parse(data.as_slice()).unwrap();
+ //println!("{:?}", aldat);
+ let roundtripped = serialize(&aldat).unwrap();
+ assert!(data != roundtripped);
+ }
}