Implement proper map parsing, fix array parsing
Finally finished and figured out how maps are handled. It didn't encode the number of items, it's based on how many bytes you read. I also fixed arrays so they're also correct, and we'll see if sets break.
This commit is contained in:
parent
874ca0a968
commit
9dd335f80e
5 changed files with 210 additions and 70 deletions
|
@ -1,10 +1,27 @@
|
|||
use crate::set_property::SetEntry;
|
||||
use binrw::binrw;
|
||||
use binrw::{binrw, BinRead, BinResult};
|
||||
use crate::map_property::{KeyType, MapEntry};
|
||||
|
||||
#[binrw::parser(reader, endian)]
|
||||
fn custom_parser(size_in_bytes: u32, key_name: &str) -> BinResult<Vec<SetEntry>> {
|
||||
let mut result = Vec::<SetEntry>::new();
|
||||
|
||||
let mut current = reader.stream_position().unwrap();
|
||||
let end = current + size_in_bytes as u64 - 4;
|
||||
|
||||
while current < end {
|
||||
result.push(SetEntry::read_options(reader, endian, (key_name,)).unwrap());
|
||||
current = reader.stream_position().unwrap();
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct ArrayProperty {
|
||||
pub unk: u32,
|
||||
// Plus this int
|
||||
pub size_in_bytes: u32,
|
||||
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
#[br(pad_before = 4)]
|
||||
|
@ -15,8 +32,8 @@ pub struct ArrayProperty {
|
|||
pub key_name: String,
|
||||
|
||||
#[br(pad_before = 1)]
|
||||
pub num_array_entries: u32,
|
||||
pub unk: u32,
|
||||
|
||||
#[br(count = num_array_entries, args { inner: (&*key_name,) })]
|
||||
#[br(parse_with = custom_parser, args(size_in_bytes, &key_name))]
|
||||
pub entries: Vec<SetEntry>,
|
||||
}
|
||||
|
|
|
@ -72,6 +72,8 @@ pub enum StringBasedProperty {
|
|||
Int(IntProperty),
|
||||
#[br(pre_assert("MapProperty" == magic))]
|
||||
Map(MapProperty),
|
||||
#[br(pre_assert("SetProperty" == magic))]
|
||||
Set(SetProperty),
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -79,6 +81,7 @@ pub enum StringBasedProperty {
|
|||
pub struct Entry {
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
#[br(dbg)]
|
||||
pub name_length: u32,
|
||||
#[br(count = name_length)]
|
||||
#[bw(map = |x : &String | x.as_bytes())]
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use std::io::{Read, Seek, SeekFrom};
|
||||
use crate::read_bool_from;
|
||||
use crate::struct_property::Struct;
|
||||
use crate::structs::PrimaryAssetNameProperty;
|
||||
use binrw::binrw;
|
||||
use binrw::{binrw, BinRead, BinResult};
|
||||
use binrw::helpers::until_exclusive;
|
||||
|
||||
// A struct without a name
|
||||
|
@ -15,6 +16,16 @@ pub struct AnonymousStruct {
|
|||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct MapSubStructProperty {
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
pub unk_name_length: u32,
|
||||
#[br(args { is_map: true })]
|
||||
pub r#struct: Struct,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct StructMaybeKey {
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
pub unk_name_length: u32,
|
||||
|
@ -29,11 +40,12 @@ pub struct MapSubStructProperty {
|
|||
#[br(count = unk_type_length)]
|
||||
#[bw(map = |x : &String | x.as_bytes())]
|
||||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
||||
#[br(pad_after = 8)] // nothingness and then length for the struct
|
||||
pub unk_type: String,
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
#[br(pad_before = 8)] // dunno what this is
|
||||
pub name_length: u32,
|
||||
|
||||
#[br(dbg)]
|
||||
#[br(pad_before = 4)] // type length
|
||||
#[br(args { is_map: true })]
|
||||
pub r#struct: Struct,
|
||||
}
|
||||
|
||||
|
@ -100,16 +112,12 @@ pub struct GuidStruct {
|
|||
// Used in MapProperty exclusively, seems to be a shortened version of some Properties
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
#[br(import { magic: &str, unk: &UnknownType, is_value: bool })]
|
||||
#[br(import { magic: &str, is_value: bool })]
|
||||
pub enum MabSubProperty {
|
||||
#[br(pre_assert("NameProperty" == magic))]
|
||||
Name(MapSubNameProperty),
|
||||
#[br(pre_assert("StructProperty" == magic && *unk == UnknownType::RealStruct))]
|
||||
#[br(pre_assert("StructProperty" == magic))]
|
||||
Struct(MapSubStructProperty),
|
||||
#[br(pre_assert("StructProperty" == magic && *unk == UnknownType::AnonymousStruct))]
|
||||
AnonymousStruct(AnonymousStruct), // assuming all value structs are anonymous for now
|
||||
#[br(pre_assert("StructProperty" == magic && *unk == UnknownType::Guid || *unk == UnknownType::Guid2))]
|
||||
GuidStruct(GuidStruct), // assuming all value structs are anonymous for now
|
||||
#[br(pre_assert("FloatProperty" == magic))]
|
||||
Float(MapSubFloatProperty),
|
||||
#[br(pre_assert("StrProperty" == magic))]
|
||||
|
@ -124,42 +132,102 @@ pub enum MabSubProperty {
|
|||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
#[br(import(key_type: &str, value_type: &str, key_unk: &UnknownType, value_unk: &UnknownType))]
|
||||
pub struct MapEntry {
|
||||
//#[br(pad_before = 8)]
|
||||
#[br(args { magic: key_type, unk: key_unk, is_value: true})]
|
||||
pub key: MabSubProperty,
|
||||
pub struct GuidStructThing {
|
||||
pub guid: [u8; 16],
|
||||
}
|
||||
|
||||
#[br(args {magic: value_type, unk: value_unk, is_value: true})]
|
||||
//#[br(if(!key_is_none(&key)))]
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct SomeIDStruct {
|
||||
pub guid: [u8; 16],
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct SomeID2Struct {
|
||||
pub guid: [u8; 16],
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct StringMapKey {
|
||||
pub enum_length: u32,
|
||||
#[br(count = enum_length)]
|
||||
#[bw(map = |x : &String | x.as_bytes())]
|
||||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
||||
pub r#enum: String,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
#[br(import { magic: &KeyType })]
|
||||
pub enum MapKeyProperty {
|
||||
#[br(pre_assert(*magic == KeyType::String))]
|
||||
String(StringMapKey),
|
||||
#[br(pre_assert(*magic == KeyType::StructMaybe))]
|
||||
StructMaybe(StructMaybeKey),
|
||||
#[br(pre_assert(*magic == KeyType::Enum))]
|
||||
Enum(MapSubEnumProperty),
|
||||
#[br(pre_assert(*magic == KeyType::EnumAgain))]
|
||||
EnumAgain(MapSubEnumProperty),
|
||||
#[br(pre_assert(*magic == KeyType::GUID))]
|
||||
GUID(GuidStructThing),
|
||||
#[br(pre_assert(*magic == KeyType::SomeID))]
|
||||
SomeID(SomeIDStruct),
|
||||
#[br(pre_assert(*magic == KeyType::SomeID2))]
|
||||
SomeID2(SomeID2Struct),
|
||||
}
|
||||
|
||||
fn is_empty(key: &MapKeyProperty) -> bool {
|
||||
false
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
#[br(import(key_type: &KeyType, value_type: &str))]
|
||||
pub struct MapEntry {
|
||||
#[br(args { magic: key_type})]
|
||||
#[br(dbg)]
|
||||
pub key: MapKeyProperty,
|
||||
|
||||
#[br(args {magic: value_type, is_value: true})]
|
||||
#[br(dbg)]
|
||||
pub value: MabSubProperty,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[brw(repr = u8)]
|
||||
#[derive(Debug, PartialEq)]
|
||||
pub enum UnknownType {
|
||||
// literally all guesswork, idk
|
||||
String = 0x0,
|
||||
Name = 0x31,
|
||||
Int = 0xBA,
|
||||
RealStruct = 0x51,
|
||||
Enum = 0x21,
|
||||
Guid = 0x45,
|
||||
IDK = 0x44,
|
||||
Guid2 = 0x5,
|
||||
AnonymousStruct = 0xF,
|
||||
#[brw(repr = u32)]
|
||||
#[derive(Debug)]
|
||||
#[derive(PartialEq, Clone)]
|
||||
pub enum KeyType {
|
||||
String = 0x1,
|
||||
GUID = 0x3,
|
||||
SomeID = 0x6,
|
||||
SomeID2 = 0x10,
|
||||
EnumAgain = 0x4,
|
||||
Enum = 0x7,
|
||||
StructMaybe = 0xC,
|
||||
}
|
||||
|
||||
#[binrw::parser(reader, endian)]
|
||||
fn custom_parser(size_in_bytes: u32, key_type: &KeyType, value_type: &str) -> BinResult<Vec<MapEntry>> {
|
||||
let mut result = Vec::<MapEntry>::new();
|
||||
|
||||
let mut current = reader.stream_position().unwrap();
|
||||
let end = current + size_in_bytes as u64 - 5 - 3;
|
||||
|
||||
while current < end {
|
||||
result.push(MapEntry::read_options(reader, endian, (&key_type, &value_type)).unwrap());
|
||||
current = reader.stream_position().unwrap();
|
||||
}
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct MapProperty {
|
||||
/*
|
||||
pub key_unk: UnknownType,
|
||||
#[br(pad_after = 2)] // actually might need all 4 bytes?
|
||||
|
||||
pub value_unk: UnknownType,*/
|
||||
// Plus this int
|
||||
#[br(dbg)]
|
||||
pub size_in_bytes: u32,
|
||||
|
||||
#[br(temp)]
|
||||
|
@ -179,16 +247,12 @@ pub struct MapProperty {
|
|||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
||||
pub value_name: String,
|
||||
|
||||
//#[br(pad_before = 5)]
|
||||
//
|
||||
//pub num_map_entries: u32,
|
||||
#[br(count = size_in_bytes + 1)]
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
pub dummy_data: Vec<u8>,
|
||||
// TODO: uncomment when map parsing reliably works, otherwise just dummy the data out
|
||||
//#[br(count = num_map_entries, args { inner: (&*key_name, &*value_name, &key_unk, &value_unk) })]
|
||||
//pub entries: Vec<MapEntry>,
|
||||
#[br(pad_before = 5)]
|
||||
#[br(dbg)]
|
||||
pub key_type: KeyType,
|
||||
|
||||
#[br(parse_with = custom_parser, args(size_in_bytes, &key_type, &value_name))]
|
||||
pub entries: Vec<MapEntry>,
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -215,14 +279,14 @@ mod tests {
|
|||
assert_eq!(decoded.size_in_bytes, 49);
|
||||
assert_eq!(decoded.key_name, "StrProperty");
|
||||
assert_eq!(decoded.value_name, "StrProperty");
|
||||
/*let String(key_property) = &decoded.entries.first().unwrap().key else {
|
||||
let MapKeyProperty::String(key_property) = &decoded.entries.first().unwrap().key else {
|
||||
panic!("StrProperty!")
|
||||
};
|
||||
let String(value_property) = &decoded.entries.first().unwrap().value else {
|
||||
panic!("StrProperty!")
|
||||
};
|
||||
assert_eq!(key_property.name, "AR0XJGFWA6HNIQ1AAUJ9UR828");
|
||||
assert_eq!(value_property.name, "NAME 1");*/
|
||||
assert_eq!(key_property.r#enum, "AR0XJGFWA6HNIQ1AAUJ9UR828");
|
||||
assert_eq!(value_property.name, "NAME 1");
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -252,14 +316,14 @@ mod tests {
|
|||
assert_eq!(decoded.size_in_bytes, 186);
|
||||
assert_eq!(decoded.key_name, "NameProperty");
|
||||
assert_eq!(decoded.value_name, "IntProperty");
|
||||
/*let Name(key_property) = &decoded.entries.first().unwrap().key else {
|
||||
let MapKeyProperty::Enum(key_property) = &decoded.entries.first().unwrap().key else {
|
||||
panic!("Name!")
|
||||
};
|
||||
let Int(value_property) = &decoded.entries.first().unwrap().value else {
|
||||
panic!("Int!")
|
||||
};
|
||||
assert_eq!(key_property.sub_property_name, "SelectedMachine");
|
||||
assert_eq!(value_property.value, 2);*/
|
||||
assert_eq!(key_property.r#enum, "SelectedMachine");
|
||||
assert_eq!(value_property.value, 2);
|
||||
// TODO: test the rest of the values
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,13 +1,9 @@
|
|||
use crate::structs::{
|
||||
DAAssembleIdDataStruct, DABuildDataStruct, DACharacterCommonStatusStruct, DALoadOptionStruct,
|
||||
DAMachineColoringDataStruct, DAModuleColorStruct, DAModuleItemDataStruct, DateTimeStruct,
|
||||
GuidStruct, LinearColorStruct, ParamsStruct, PrimaryAssetIdStruct, PrimaryAssetTypeStruct,
|
||||
SaveSlotInfoStruct,
|
||||
};
|
||||
use crate::structs::{CarryCountProperty, DAAssembleIdDataStruct, DABuildDataStruct, DACharacterCommonStatusStruct, DALoadOptionStruct, DAMachineColoringDataStruct, DAModuleColorStruct, DAModuleItemDataStruct, DateTimeStruct, GuidStruct, LinearColorStruct, ParamsStruct, PrimaryAssetIdStruct, PrimaryAssetNameProperty, SaveSlotInfoStruct};
|
||||
use binrw::binrw;
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
#[br(import { is_map: bool })]
|
||||
pub enum Struct {
|
||||
#[br(magic = b"DateTime\0")]
|
||||
DateTime(DateTimeStruct),
|
||||
|
@ -20,7 +16,15 @@ pub enum Struct {
|
|||
#[br(magic = b"Params\0")]
|
||||
Params(ParamsStruct),
|
||||
#[br(magic = b"PrimaryAssetType\0")]
|
||||
PrimaryAssetType(PrimaryAssetTypeStruct),
|
||||
PrimaryAssetType {
|
||||
#[br(pad_before = 17)]
|
||||
#[br(dbg)]
|
||||
name: PrimaryAssetNameProperty,
|
||||
#[br(pad_before = 9)] // "None" and it's length in bytes plus the null terminator
|
||||
#[br(pad_after = 9)] // ditto
|
||||
#[br(dbg)]
|
||||
primary_asset_name: PrimaryAssetNameProperty,
|
||||
},
|
||||
#[br(magic = b"PrimaryAssetId\0")]
|
||||
PrimaryAssetId(PrimaryAssetIdStruct),
|
||||
#[br(magic = b"DAModuleItemData\0")]
|
||||
|
@ -37,6 +41,42 @@ pub enum Struct {
|
|||
DAModuleColor(DAModuleColorStruct),
|
||||
#[br(magic = b"LinearColor\0")]
|
||||
LinearColor(LinearColorStruct),
|
||||
#[br(magic = b"CarryCount\0")]
|
||||
CarryCount {
|
||||
#[br(dbg)]
|
||||
carry_count: CarryCountProperty,
|
||||
#[br(dbg)]
|
||||
#[br(pad_before = 15)] // "StoreCount" + 4 bytes for length + 1 byte for endofstring
|
||||
#[br(pad_after = 9)] // "None" + 1 byte for endofstring + 4 bytes for length
|
||||
store_count: CarryCountProperty,
|
||||
},
|
||||
#[br(magic = b"Map\0")]
|
||||
Map {
|
||||
#[br(dbg)]
|
||||
#[br(pad_after = 9)] // "None" + 1 byte for endofstring + 4 bytes for length
|
||||
map: CarryCountProperty,
|
||||
},
|
||||
// TODO: im almost certain this isn't a struct name
|
||||
#[br(magic = b"ID\0")]
|
||||
ID {
|
||||
unk: [u8; 149], // not sure how to parse this yet
|
||||
#[br(dbg)]
|
||||
#[br(pad_after = 9)] // "None" and it's length in bytes plus the null terminator
|
||||
name: PrimaryAssetNameProperty,
|
||||
|
||||
#[br(dbg)]
|
||||
#[br(pad_after = 9)] // "None" and it's length in bytes plus the null terminator
|
||||
primary_asset_name: PrimaryAssetNameProperty,
|
||||
|
||||
#[br(dbg)]
|
||||
data: [u8; 137],
|
||||
},
|
||||
#[br(magic = b"Set\0")]
|
||||
Set {
|
||||
#[br(dbg)]
|
||||
#[br(pad_after = 9)] // "None" + 1 byte for endofstring + 4 bytes for length
|
||||
set: CarryCountProperty,
|
||||
},
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -47,5 +87,6 @@ pub struct StructProperty {
|
|||
#[bw(ignore)]
|
||||
#[br(pad_before = 4)]
|
||||
pub name_length: u32,
|
||||
#[br(args { is_map: false })]
|
||||
pub r#struct: Struct,
|
||||
}
|
||||
|
|
|
@ -38,35 +38,49 @@ pub struct ParamsStruct {
|
|||
pub struct PrimaryAssetNameProperty {
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
#[br(dbg)]
|
||||
pub property_name_length: u32,
|
||||
#[br(count = property_name_length)]
|
||||
#[bw(map = |x : &String | x.as_bytes())]
|
||||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
||||
#[br(dbg)]
|
||||
pub property_name: String,
|
||||
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
#[br(if(property_name != "None"))]
|
||||
#[br(dbg)]
|
||||
pub type_length: u32,
|
||||
#[br(count = type_length)]
|
||||
#[bw(map = |x : &String | x.as_bytes())]
|
||||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
||||
#[br(if(property_name != "None"))]
|
||||
#[br(dbg)]
|
||||
pub type_name: String,
|
||||
|
||||
#[br(if(property_name != "None"))]
|
||||
#[br(args { magic: &type_name})]
|
||||
//#[br(dbg)]
|
||||
pub key: Option<Box<StringBasedProperty>>,
|
||||
}
|
||||
|
||||
|
||||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct PrimaryAssetTypeStruct {
|
||||
#[br(pad_before = 17)]
|
||||
name: PrimaryAssetNameProperty,
|
||||
#[br(pad_before = 9)] // "None" and it's length in bytes plus the null terminator
|
||||
#[br(pad_after = 9)] // ditto
|
||||
primary_asset_name: PrimaryAssetNameProperty,
|
||||
pub struct CarryCountProperty {
|
||||
#[br(temp)]
|
||||
#[bw(ignore)]
|
||||
#[br(dbg)]
|
||||
pub property_name_length: u32,
|
||||
#[br(count = property_name_length)]
|
||||
#[bw(map = |x : &String | x.as_bytes())]
|
||||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
||||
#[br(dbg)]
|
||||
pub property_name: String,
|
||||
|
||||
#[br(args { magic: &property_name})]
|
||||
//#[br(dbg)]
|
||||
pub key: Option<Box<StringBasedProperty>>,
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
@ -79,7 +93,8 @@ pub struct PrimaryAssetIdStruct {
|
|||
#[binrw]
|
||||
#[derive(Debug)]
|
||||
pub struct DAModuleItemDataStruct {
|
||||
pub unk: [u8; 17],
|
||||
#[br(pad_before = 17)]
|
||||
pub module_level: PrimaryAssetNameProperty
|
||||
}
|
||||
|
||||
#[binrw]
|
||||
|
|
Loading…
Add table
Reference in a new issue