From 21ab9f2cb0d901f2fe9bde154e30b06d253953bb Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 23 Feb 2025 15:52:21 -0500 Subject: [PATCH] Fix and simplify string property parsing, add test I figured out what the actual layout of this property is (instead of guessing, which created some bad results.) And added tests of course! Also fixed a bug in read_string_with_length() that didn't handle the case where the string length is zero. --- src/common.rs | 7 ++++- src/str_property.rs | 63 ++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 62 insertions(+), 8 deletions(-) diff --git a/src/common.rs b/src/common.rs index be6462d..be5bea9 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,3 +1,4 @@ +use std::io::Seek; use binrw::{BinRead, BinReaderExt, BinResult}; pub(crate) fn read_bool_from + PartialEq>(x: T) -> bool { @@ -6,8 +7,12 @@ pub(crate) fn read_bool_from + PartialEq>(x: T) -> bool { #[binrw::parser(reader, endian)] pub(crate) fn read_string_with_length() -> BinResult { + let length = u32::read_le(reader)? as usize; + if length == 0 { + return Ok(String::default());; + } // last byte is the null terminator which Rust ignores - let length = u32::read_le(reader)? as usize - 1; + let length = length - 1; let mut bytes: Vec = vec![0u8; length]; // TODO: there was to be way to read this all in one go? for i in 0..length { diff --git a/src/str_property.rs b/src/str_property.rs index efb6972..fec676f 100644 --- a/src/str_property.rs +++ b/src/str_property.rs @@ -1,14 +1,63 @@ use binrw::binrw; +use crate::common::read_string_with_length; #[binrw] #[derive(Debug)] pub struct StrProperty { - #[br(temp)] - #[bw(ignore)] #[br(pad_after = 5)] - pub name_length: u32, - #[br(count = name_length)] - #[bw(map = |x : &String | x.as_bytes())] - #[br(map = | x: Vec | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())] - pub name: String, + pub size_in_bytes: u32, + + #[br(parse_with = read_string_with_length)] + #[bw(ignore)] + pub value: String, +} + +#[cfg(test)] +mod tests { + use super::*; + use binrw::BinRead; + use std::io::Cursor; + + #[test] + fn empty_string() { + // From Slot.sav + let data = [ + 0x04, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x0b, 0x00, + 0x00, 0x00, 0x4c, + 0x6f, 0x61, 0x64, + 0x4f, 0x70, 0x74, + 0x69, 0x6f, 0x6e, + 0x00, + ]; + let mut cursor = Cursor::new(data); + let decoded = StrProperty::read_le(&mut cursor).unwrap(); + assert_eq!(decoded.value, ""); + } + + #[test] + fn regular_string() { + // From Slot.sav + let data = [ + 0x1e, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, + 0x1a, 0x00, 0x00, + 0x00, 0x41, 0x52, + 0x30, 0x58, 0x4a, + 0x47, 0x46, 0x57, + 0x41, 0x36, 0x48, + 0x4e, 0x49, 0x51, + 0x31, 0x41, 0x41, + 0x55, 0x4a, 0x39, + 0x55, 0x52, 0x38, + 0x32, 0x38, 0x00, + ]; + let mut cursor = Cursor::new(data); + let decoded = StrProperty::read_le(&mut cursor).unwrap(); + assert_eq!(decoded.value, "AR0XJGFWA6HNIQ1AAUJ9UR828"); + } }