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.
This commit is contained in:
parent
153c8610c9
commit
be82857aba
2 changed files with 52 additions and 23 deletions
|
@ -11,22 +11,7 @@ fn main() -> Result<(), Box<dyn std::error::Error>> {
|
|||
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(())
|
||||
}
|
||||
|
|
58
src/lib.rs
58
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<TaggedObject>,
|
||||
}
|
||||
|
||||
#[binrw::parser(reader, endian)]
|
||||
fn read_compressed_data(
|
||||
compressed_size: u64,
|
||||
uncompressed_size: u64,
|
||||
) -> BinResult<Vec<u8>> {
|
||||
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<CompressedBlock>
|
||||
) -> BinResult<TaggedSerialization> {
|
||||
let data_vecs: Vec<Vec<u8>> = 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<u8>,
|
||||
#[br(parse_with = read_compressed_data, args(a_compresed_size, a_uncompresed_size))]
|
||||
pub data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct CompressedSaveFile {
|
||||
#[br(parse_with = until_eof)]
|
||||
pub data: Vec<CompressedBlock>,
|
||||
#[br(parse_with = read_tagged_data, args(&data))]
|
||||
pub value: TaggedSerialization,
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue