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.
This commit is contained in:
parent
6b7d4c66dd
commit
21ab9f2cb0
2 changed files with 62 additions and 8 deletions
|
@ -1,3 +1,4 @@
|
||||||
|
use std::io::Seek;
|
||||||
use binrw::{BinRead, BinReaderExt, BinResult};
|
use binrw::{BinRead, BinReaderExt, BinResult};
|
||||||
|
|
||||||
pub(crate) fn read_bool_from<T: From<u8> + PartialEq>(x: T) -> bool {
|
pub(crate) fn read_bool_from<T: From<u8> + PartialEq>(x: T) -> bool {
|
||||||
|
@ -6,8 +7,12 @@ pub(crate) fn read_bool_from<T: From<u8> + PartialEq>(x: T) -> bool {
|
||||||
|
|
||||||
#[binrw::parser(reader, endian)]
|
#[binrw::parser(reader, endian)]
|
||||||
pub(crate) fn read_string_with_length() -> BinResult<String> {
|
pub(crate) fn read_string_with_length() -> BinResult<String> {
|
||||||
|
let length = u32::read_le(reader)? as usize;
|
||||||
|
if length == 0 {
|
||||||
|
return Ok(String::default());;
|
||||||
|
}
|
||||||
// last byte is the null terminator which Rust ignores
|
// 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<u8> = vec![0u8; length];
|
let mut bytes: Vec<u8> = vec![0u8; length];
|
||||||
// TODO: there was to be way to read this all in one go?
|
// TODO: there was to be way to read this all in one go?
|
||||||
for i in 0..length {
|
for i in 0..length {
|
||||||
|
|
|
@ -1,14 +1,63 @@
|
||||||
use binrw::binrw;
|
use binrw::binrw;
|
||||||
|
use crate::common::read_string_with_length;
|
||||||
|
|
||||||
#[binrw]
|
#[binrw]
|
||||||
#[derive(Debug)]
|
#[derive(Debug)]
|
||||||
pub struct StrProperty {
|
pub struct StrProperty {
|
||||||
#[br(temp)]
|
|
||||||
#[bw(ignore)]
|
|
||||||
#[br(pad_after = 5)]
|
#[br(pad_after = 5)]
|
||||||
pub name_length: u32,
|
pub size_in_bytes: u32,
|
||||||
#[br(count = name_length)]
|
|
||||||
#[bw(map = |x : &String | x.as_bytes())]
|
#[br(parse_with = read_string_with_length)]
|
||||||
#[br(map = | x: Vec<u8> | String::from_utf8(x).unwrap().trim_matches(char::from(0)).to_string())]
|
#[bw(ignore)]
|
||||||
pub name: String,
|
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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue