use super::{read_u16, BinaryDeserializerError, CharsetFamily, Endianness, FormatVersion};
#[repr(C)]
pub(super) struct BinHeader {
pub size: u16,
pub magic: [u8; 2],
pub repr_info: BinReprInfo,
}
#[repr(C)]
pub(super) struct BinReprInfo {
pub size: u16,
pub reserved_word: u16,
pub endianness: Endianness,
pub charset_family: CharsetFamily,
pub size_of_char: u8,
pub reserved_byte: u8,
pub data_format: [u8; 4],
pub format_version: FormatVersion,
pub data_version: [u8; 4],
}
impl TryFrom<&[u8]> for BinHeader {
type Error = BinaryDeserializerError;
#[expect(clippy::indexing_slicing)]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() < size_of::<BinHeader>() {
return Err(BinaryDeserializerError::invalid_data(
"input is too short to contain file header",
));
}
let (size, value) = read_u16(value)?;
let (magic, value) = ([value[0], value[1]], &value[2..]);
match magic {
[0xda, 0x27] => (),
_ => {
return Err(BinaryDeserializerError::invalid_data(
"magic word does not match",
))
}
}
let repr_info = BinReprInfo::try_from(value)?;
if (size as usize) < size_of::<BinHeader>() {
return Err(BinaryDeserializerError::invalid_data(
"header size specified in file is smaller than expected",
));
}
Ok(BinHeader {
size,
magic,
repr_info,
})
}
}
impl TryFrom<&[u8]> for BinReprInfo {
type Error = BinaryDeserializerError;
#[expect(clippy::indexing_slicing)]
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
if value.len() < size_of::<BinReprInfo>() {
return Err(BinaryDeserializerError::invalid_data(
"input is too short to contain representation info",
));
}
let (size, value) = read_u16(value)?;
let (reserved_word, value) = read_u16(value)?;
let (endianness, value) = (Endianness::try_from(value[0])?, &value[1..]);
if (endianness == Endianness::Little) != cfg!(target_endian = "little") {
return Err(BinaryDeserializerError::unsupported_format(
"bundle endianness does not match platform endianness",
));
}
let (charset_family, value) = (CharsetFamily::try_from(value[0])?, &value[1..]);
let (size_of_char, value) = (value[0], &value[1..]);
let (reserved_byte, value) = (value[0], &value[1..]);
let (data_format, value) = ([value[0], value[1], value[2], value[3]], &value[4..]);
if &data_format != b"ResB" {
return Err(BinaryDeserializerError::invalid_data(
"unexpected data format value",
));
}
let (format_version, value) = (FormatVersion::try_from(&value[..4])?, &value[4..]);
let (data_version, _) = ([value[0], value[1], value[2], value[3]], &value[4..]);
Ok(BinReprInfo {
size,
reserved_word,
endianness,
charset_family,
size_of_char,
reserved_byte,
data_format,
format_version,
data_version,
})
}
}