From beaa0e784f23711536ca4daf26f1ec4bfbcf0dd7 Mon Sep 17 00:00:00 2001 From: Joshua Goins Date: Sun, 23 Feb 2025 16:30:49 -0500 Subject: [PATCH] Add writing support for strings and StrProperty --- src/common.rs | 22 +++++++++++++++++- src/str_property.rs | 55 ++++++++++++++++++++++++++++++++++++++------- 2 files changed, 68 insertions(+), 9 deletions(-) diff --git a/src/common.rs b/src/common.rs index 1adc743..86bda9b 100644 --- a/src/common.rs +++ b/src/common.rs @@ -1,4 +1,4 @@ -use binrw::BinRead; +use binrw::{BinRead, BinWrite}; use binrw::BinResult; pub(crate) fn read_bool_from + PartialEq>(x: T) -> bool { @@ -25,6 +25,26 @@ pub(crate) fn read_string_with_length() -> BinResult { })) } +#[binrw::writer(writer, endian)] +pub(crate) fn write_string_with_length(string: &String) -> BinResult<()> { + if string.is_empty() { + let length = 0u32; + length.write_le(writer)?; + return Ok(()); + } + // + 1 for the null terminator + let length = string.len() as u32 + 1; + length.write_le(writer)?; + for char in string.chars() { + let byte = char as u8; + byte.write_le(writer)?; + } + let null_terminator = 0u8; + null_terminator.write_le(writer)?; + Ok(()) +} + + #[cfg(test)] mod tests { use super::*; diff --git a/src/str_property.rs b/src/str_property.rs index c198c6e..528f7ba 100644 --- a/src/str_property.rs +++ b/src/str_property.rs @@ -1,29 +1,30 @@ -use crate::common::read_string_with_length; +use crate::common::{read_string_with_length, write_string_with_length}; use binrw::binrw; #[binrw] #[derive(Debug)] pub struct StrProperty { - #[br(pad_after = 5)] + #[brw(pad_after = 5)] + // Only add + 1 for the null terminator if the string *isn't* empty. + #[bw(calc = value.len() as u32 + 4 + if value.is_empty() { 0 } else { 1})] pub size_in_bytes: u32, #[br(parse_with = read_string_with_length)] - #[bw(ignore)] + #[bw(write_with = write_string_with_length)] pub value: String, } #[cfg(test)] mod tests { use super::*; - use binrw::BinRead; + use binrw::{BinRead, BinWrite}; use std::io::Cursor; #[test] - fn empty_string() { + fn read_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, + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, ]; let mut cursor = Cursor::new(data); let decoded = StrProperty::read_le(&mut cursor).unwrap(); @@ -31,7 +32,25 @@ mod tests { } #[test] - fn regular_string() { + fn write_empty_string() { + let expected_data: [u8; 13] = [ + 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + ]; + let property = StrProperty { + value: "".to_string(), + }; + + let mut buffer: Vec = Vec::new(); + { + let mut cursor = Cursor::new(&mut buffer); + property.write_le(&mut cursor).unwrap(); + } + + assert_eq!(expected_data, &buffer[..]); + } + + #[test] + fn read_regular_string() { // From Slot.sav let data = [ 0x1e, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x00, 0x41, @@ -42,4 +61,24 @@ mod tests { let decoded = StrProperty::read_le(&mut cursor).unwrap(); assert_eq!(decoded.value, "AR0XJGFWA6HNIQ1AAUJ9UR828"); } + + #[test] + fn write_regular_string() { + let expected_data: [u8; 39] = [ + 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 property = StrProperty { + value: "AR0XJGFWA6HNIQ1AAUJ9UR828".to_string(), + }; + + let mut buffer: Vec = Vec::new(); + { + let mut cursor = Cursor::new(&mut buffer); + property.write_le(&mut cursor).unwrap(); + } + + assert_eq!(expected_data, &buffer[..]); + } }