From be82857abacd28d49c0ba8687297655c757376f8 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Mon, 24 Feb 2025 18:15:54 -0500 Subject: [PATCH] Find the magical missing bytes at the end of Persistent.sav Turns out there can be multiple compressed blocks in a single .sav file, so now we read all of them. --- src/bin/ireko.rs | 17 +------------- src/lib.rs | 58 ++++++++++++++++++++++++++++++++++++++++++------ 2 files changed, 52 insertions(+), 23 deletions(-) diff --git a/src/bin/ireko.rs b/src/bin/ireko.rs index 962ba6e..a288fe8 100644 --- a/src/bin/ireko.rs +++ b/src/bin/ireko.rs @@ -11,22 +11,7 @@ fn main() -> Result<(), Box> { let mut data = Cursor::new(std::fs::read(&args[1])?); let compressed = CompressedSaveFile::read_le(&mut data)?; - - let mut output = vec![]; - - let mut uncompressed = vec![0; compressed.a_uncompresed_size as usize]; - - let decompress = Decompress::new(true); - - let mut d = ZlibDecoder::new_with_decompress(&*compressed.compressed_data, decompress); - let size = d.read(&mut uncompressed)?; - output.extend_from_slice(&uncompressed[..size]); - std::fs::write("output.bin", &output)?; - - let mut cursor = Cursor::new(&uncompressed); - - let save_data = TaggedSerialization::read_le(&mut cursor); - println!("{:#?}", save_data); + println!("{:#?}", compressed); Ok(()) } diff --git a/src/lib.rs b/src/lib.rs index 772899e..38b79d4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -15,18 +15,22 @@ pub mod str_property; pub mod struct_property; mod structs; +use std::fs::write; +use std::io::{Cursor, Read}; use binrw::helpers::until_eof; -use crate::array_property::ArrayProperty; +use crate::array_property::{ArrayEntry, ArrayKeyData, ArrayProperty}; use crate::bool_property::BoolProperty; use crate::common::{read_string_with_length, write_string_with_length}; use crate::float_property::FloatProperty; use crate::int_property::IntProperty; -use crate::map_property::MapProperty; +use crate::map_property::{KeyType, MapProperty}; use crate::set_property::SetProperty; use crate::str_property::StrProperty; use crate::struct_property::StructProperty; use binrw::{BinRead, BinResult, binrw}; +use flate2::bufread::ZlibDecoder; +use flate2::Decompress; // Used in ArrayProperty exclusively, but could be used instead of magic above #[binrw] @@ -113,16 +117,56 @@ pub struct TaggedSerialization { pub objs: Vec, } +#[binrw::parser(reader, endian)] +fn read_compressed_data( + compressed_size: u64, + uncompressed_size: u64, +) -> BinResult> { + let mut compressed_data = vec![0; compressed_size as usize]; + reader.read_exact(&mut compressed_data)?; + + let mut uncompressed = vec![0; uncompressed_size as usize]; + + let mut d = ZlibDecoder::new(&*compressed_data); + let size = d.read(&mut uncompressed)?; + + Ok(uncompressed[..size].to_vec()) +} + +// TODO: there's no point in using a parser, we should just use map() +#[binrw::parser(reader, endian)] +fn read_tagged_data( + data_blocks: &Vec +) -> BinResult { + let data_vecs: Vec> = data_blocks.iter().map(|x| x.data.clone()).collect(); + let combined_data = data_vecs.concat(); + write("output.bin", &combined_data); + + let mut cursor = Cursor::new(&combined_data); + + TaggedSerialization::read_le(&mut cursor) +} + #[binrw] #[brw(magic = 0x9e2a83c1u32)] #[derive(Debug)] -pub struct CompressedSaveFile { - #[br(pad_before = 4)] - pub compressed_size: u64, +pub struct CompressedBlock { + #[br(pad_before = 6)] + #[br(pad_after = 5)] + pub unk: u8, // always 2 pub a_compresed_size: u64, pub a_uncompresed_size: u64, pub b_compresed_size: u64, pub b_uncompresed_size: u64, - #[br(count = a_compresed_size)] - pub compressed_data: Vec, + #[br(parse_with = read_compressed_data, args(a_compresed_size, a_uncompresed_size))] + pub data: Vec, +} + +#[binrw] +#[derive(Debug)] +pub struct CompressedSaveFile { + #[br(parse_with = until_eof)] + pub data: Vec, + #[br(parse_with = read_tagged_data, args(&data))] + pub value: TaggedSerialization, }