2025-02-19 19:34:13 -05:00
|
|
|
pub mod array_property;
|
|
|
|
pub mod bool_property;
|
2025-02-24 00:30:16 -05:00
|
|
|
mod build_data;
|
2025-02-23 15:25:50 -05:00
|
|
|
mod common;
|
2025-02-19 19:34:13 -05:00
|
|
|
pub mod float_property;
|
2025-02-24 00:30:16 -05:00
|
|
|
mod guid;
|
2025-02-19 19:34:13 -05:00
|
|
|
pub mod int_property;
|
2025-02-24 00:30:16 -05:00
|
|
|
mod linear_color;
|
2025-02-19 19:34:13 -05:00
|
|
|
pub mod map_property;
|
2025-02-24 00:30:16 -05:00
|
|
|
mod name_property;
|
|
|
|
mod primary_asset_id;
|
|
|
|
mod primary_asset_type;
|
2025-02-19 19:34:13 -05:00
|
|
|
pub mod set_property;
|
|
|
|
pub mod str_property;
|
|
|
|
pub mod struct_property;
|
|
|
|
mod structs;
|
2025-02-25 19:45:36 -05:00
|
|
|
mod enum_property;
|
2025-02-19 19:34:13 -05:00
|
|
|
|
2025-02-24 18:33:32 -05:00
|
|
|
use binrw::helpers::until_eof;
|
2025-02-24 18:15:54 -05:00
|
|
|
use std::fs::write;
|
|
|
|
use std::io::{Cursor, Read};
|
2025-02-19 19:34:13 -05:00
|
|
|
|
2025-02-24 18:33:32 -05:00
|
|
|
use crate::array_property::ArrayProperty;
|
2025-02-19 19:34:13 -05:00
|
|
|
use crate::bool_property::BoolProperty;
|
2025-02-23 17:04:26 -05:00
|
|
|
use crate::common::{read_string_with_length, write_string_with_length};
|
2025-02-19 19:34:13 -05:00
|
|
|
use crate::float_property::FloatProperty;
|
|
|
|
use crate::int_property::IntProperty;
|
2025-02-24 18:33:32 -05:00
|
|
|
use crate::map_property::MapProperty;
|
2025-02-25 19:30:16 -05:00
|
|
|
use crate::name_property::NameProperty;
|
2025-02-19 19:34:13 -05:00
|
|
|
use crate::set_property::SetProperty;
|
|
|
|
use crate::str_property::StrProperty;
|
|
|
|
use crate::struct_property::StructProperty;
|
2025-02-24 00:30:16 -05:00
|
|
|
use binrw::{BinRead, BinResult, binrw};
|
2025-02-24 18:15:54 -05:00
|
|
|
use flate2::bufread::ZlibDecoder;
|
2025-02-19 19:34:13 -05:00
|
|
|
|
|
|
|
// Used in ArrayProperty exclusively, but could be used instead of magic above
|
|
|
|
#[binrw]
|
|
|
|
#[derive(Debug)]
|
2025-02-24 00:30:16 -05:00
|
|
|
#[br(import { magic: &str, name: &str })]
|
2025-02-23 16:03:08 -05:00
|
|
|
pub enum Property {
|
2025-02-19 19:34:13 -05:00
|
|
|
#[br(pre_assert("NameProperty" == magic))]
|
2025-02-25 19:30:16 -05:00
|
|
|
Name(NameProperty),
|
2025-02-19 19:34:13 -05:00
|
|
|
#[br(pre_assert("StructProperty" == magic))]
|
|
|
|
Struct(StructProperty),
|
|
|
|
#[br(pre_assert("FloatProperty" == magic))]
|
|
|
|
Float(FloatProperty),
|
|
|
|
#[br(pre_assert("StrProperty" == magic))]
|
|
|
|
String(StrProperty),
|
|
|
|
#[br(pre_assert("BoolProperty" == magic))]
|
|
|
|
Bool(BoolProperty),
|
|
|
|
#[br(pre_assert("IntProperty" == magic))]
|
|
|
|
Int(IntProperty),
|
2025-02-23 16:00:35 -05:00
|
|
|
#[br(pre_assert("ArrayProperty" == magic))]
|
|
|
|
Array(ArrayProperty),
|
2025-02-19 19:34:13 -05:00
|
|
|
#[br(pre_assert("MapProperty" == magic))]
|
|
|
|
Map(MapProperty),
|
2025-02-23 14:38:35 -05:00
|
|
|
#[br(pre_assert("SetProperty" == magic))]
|
2025-02-24 00:30:16 -05:00
|
|
|
Set {
|
|
|
|
#[br(args(name))]
|
|
|
|
value: SetProperty,
|
|
|
|
},
|
2025-02-19 19:34:13 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[binrw]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct Entry {
|
2025-02-23 16:00:35 -05:00
|
|
|
#[br(parse_with = read_string_with_length)]
|
2025-02-23 17:04:26 -05:00
|
|
|
#[bw(write_with = write_string_with_length)]
|
2025-02-19 19:34:13 -05:00
|
|
|
pub name: String,
|
2025-02-23 16:00:35 -05:00
|
|
|
|
|
|
|
#[br(parse_with = read_string_with_length)]
|
2025-02-23 17:04:26 -05:00
|
|
|
#[bw(write_with = write_string_with_length)]
|
|
|
|
#[br(if(name != "None"))]
|
2025-02-23 16:00:35 -05:00
|
|
|
pub type_name: String,
|
|
|
|
|
2025-02-24 00:30:16 -05:00
|
|
|
#[br(if(name != "None"), args { magic: &type_name, name: &name })]
|
2025-02-23 16:03:08 -05:00
|
|
|
pub r#type: Option<Property>,
|
2025-02-19 19:34:13 -05:00
|
|
|
}
|
|
|
|
|
2025-02-24 00:30:16 -05:00
|
|
|
#[binrw::parser(reader, endian)]
|
|
|
|
fn custom_tagged_object_parser(size_in_bytes: u32) -> BinResult<Vec<Entry>> {
|
|
|
|
let mut result = Vec::<Entry>::new();
|
|
|
|
|
2025-02-24 18:33:32 -05:00
|
|
|
let mut current = reader.stream_position()?;
|
|
|
|
let end = current + size_in_bytes as u64 - 4; // for the size bits
|
|
|
|
|
|
|
|
while current < end {
|
|
|
|
let entry = Entry::read_options(reader, endian, ())?;
|
|
|
|
if entry.name == "None" {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
result.push(entry);
|
|
|
|
current = reader.stream_position()?;
|
|
|
|
}
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
|
|
|
#[binrw::parser(reader, endian)]
|
|
|
|
fn custom_parser(size_in_bytes: u32) -> BinResult<Vec<TaggedObject>> {
|
|
|
|
let mut result = Vec::<TaggedObject>::new();
|
|
|
|
|
2025-02-24 00:30:16 -05:00
|
|
|
let mut current = reader.stream_position()?;
|
|
|
|
let end = current + size_in_bytes as u64;
|
|
|
|
|
|
|
|
while current < end {
|
2025-02-24 18:33:32 -05:00
|
|
|
let obj = TaggedObject::read_options(reader, endian, ())?;
|
|
|
|
if obj.size_in_bytes == 0 {
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
result.push(obj);
|
2025-02-24 00:30:16 -05:00
|
|
|
current = reader.stream_position()?;
|
|
|
|
}
|
|
|
|
Ok(result)
|
|
|
|
}
|
|
|
|
|
2025-02-19 19:34:13 -05:00
|
|
|
#[binrw]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TaggedObject {
|
|
|
|
pub size_in_bytes: u32,
|
2025-02-24 18:33:32 -05:00
|
|
|
#[br(parse_with = custom_tagged_object_parser, args(size_in_bytes))]
|
2025-02-19 19:34:13 -05:00
|
|
|
pub entries: Vec<Entry>,
|
|
|
|
}
|
|
|
|
|
2025-02-23 17:04:26 -05:00
|
|
|
impl TaggedObject {
|
|
|
|
pub fn entry(&self, key: &str) -> Option<&Entry> {
|
|
|
|
let entries: Vec<&Entry> = self.entries.iter().filter(|e| e.name == key).collect();
|
|
|
|
entries.first().copied()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-02-19 19:34:13 -05:00
|
|
|
#[binrw]
|
|
|
|
#[derive(Debug)]
|
|
|
|
pub struct TaggedSerialization {
|
|
|
|
pub size_in_bytes: u32,
|
2025-02-24 18:33:32 -05:00
|
|
|
#[br(parse_with = custom_parser, args(size_in_bytes))]
|
2025-02-19 19:34:13 -05:00
|
|
|
pub objs: Vec<TaggedObject>,
|
|
|
|
}
|
|
|
|
|
2025-02-24 18:15:54 -05:00
|
|
|
#[binrw::parser(reader, endian)]
|
2025-02-24 18:33:32 -05:00
|
|
|
fn read_compressed_data(compressed_size: u64, uncompressed_size: u64) -> BinResult<Vec<u8>> {
|
2025-02-24 18:15:54 -05:00
|
|
|
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)]
|
2025-02-24 18:33:32 -05:00
|
|
|
fn read_tagged_data(data_blocks: &Vec<CompressedBlock>) -> BinResult<TaggedSerialization> {
|
2025-02-24 18:15:54 -05:00
|
|
|
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)
|
|
|
|
}
|
|
|
|
|
2025-02-19 19:34:13 -05:00
|
|
|
#[binrw]
|
2025-02-24 17:48:17 -05:00
|
|
|
#[brw(magic = 0x9e2a83c1u32)]
|
2025-02-19 19:34:13 -05:00
|
|
|
#[derive(Debug)]
|
2025-02-24 18:15:54 -05:00
|
|
|
pub struct CompressedBlock {
|
|
|
|
#[br(pad_before = 6)]
|
|
|
|
#[br(pad_after = 5)]
|
|
|
|
pub unk: u8, // always 2
|
2025-02-19 19:34:13 -05:00
|
|
|
pub a_compresed_size: u64,
|
|
|
|
pub a_uncompresed_size: u64,
|
|
|
|
pub b_compresed_size: u64,
|
|
|
|
pub b_uncompresed_size: u64,
|
2025-02-24 18:15:54 -05:00
|
|
|
#[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)]
|
2025-02-24 18:21:25 -05:00
|
|
|
#[br(temp)]
|
|
|
|
#[bw(ignore)]
|
2025-02-24 18:15:54 -05:00
|
|
|
pub data: Vec<CompressedBlock>,
|
|
|
|
#[br(parse_with = read_tagged_data, args(&data))]
|
|
|
|
pub value: TaggedSerialization,
|
2025-02-19 19:34:13 -05:00
|
|
|
}
|