use super::LITTLE_ENDIAN;
use crate::dbg_dmp;
use nom::bytes::complete::take;
use nom::number::complete::u32;
use nom::*;
#[derive(Debug, Default)]
pub struct MPQUserData {
pub user_data_size: u32, pub archive_header_offset: u32,
pub user_data_header_size: u32,
pub content: Vec<u8>,
}
impl MPQUserData {
pub fn parse(input: &[u8]) -> IResult<&[u8], Self> {
let (input, user_data_size) = Self::parse_user_data_size(input)?;
let (input, archive_header_offset) = Self::parse_archive_header_offset(input)?;
let (input, user_data_header_size) = Self::parse_user_data_header_size(input)?;
let (input, content) = Self::parse_content(input, user_data_header_size)?;
let (input, _) =
Self::consume_until_header_offset(input, user_data_header_size, archive_header_offset)?;
Ok((
input,
MPQUserData {
user_data_size,
archive_header_offset,
user_data_header_size,
content,
},
))
}
pub fn parse_user_data_size(input: &[u8]) -> IResult<&[u8], u32> {
dbg_dmp(u32(LITTLE_ENDIAN), "user_data_size")(input)
}
pub fn parse_archive_header_offset(input: &[u8]) -> IResult<&[u8], u32> {
dbg_dmp(u32(LITTLE_ENDIAN), "archive_header_offset")(input)
}
pub fn parse_user_data_header_size(input: &[u8]) -> IResult<&[u8], u32> {
dbg_dmp(u32(LITTLE_ENDIAN), "user_data_size")(input)
}
pub fn parse_content(input: &[u8], user_data_header_size: u32) -> IResult<&[u8], Vec<u8>> {
let (input, content) = dbg_dmp(take(user_data_header_size as usize), "content")(input)?;
Ok((input, content.to_vec()))
}
pub fn consume_until_header_offset(
input: &[u8],
user_data_header_size: u32,
archive_header_offset: u32,
) -> IResult<&[u8], ()> {
let curr_read_byte_count = 16;
if archive_header_offset < user_data_header_size + curr_read_byte_count {
tracing::error!(
"Invalid archive_header_offset: {}, should be bigger than {}",
archive_header_offset,
user_data_header_size + curr_read_byte_count
);
return Err(nom::Err::Incomplete(nom::Needed::new(
(user_data_header_size + curr_read_byte_count) as usize,
)));
}
let (input, _) = dbg_dmp(
take((archive_header_offset - (user_data_header_size + curr_read_byte_count)) as usize),
"content",
)(input)?;
Ok((input, ()))
}
}
#[cfg(test)]
pub mod tests {
use super::*;
use crate::parser::*;
pub fn basic_user_header() -> Vec<u8> {
vec![
b'M',
b'P',
b'Q', MPQ_USER_DATA_HEADER_TYPE,
0x00,
0x00,
0x00,
0x00, 0x18,
0x00,
0x00,
0x00, 0x04,
0x00,
0x00,
0x00, 0xbe,
0xef,
0xca,
0x4e, 0x00,
0x00,
0x00,
0x00, ]
}
#[test]
fn it_parses_header() {
let user_data_header_input = basic_user_header();
let (input, header_type) = get_header_type(&user_data_header_input).unwrap();
assert_eq!(header_type, MPQSectionType::UserData);
let (input, user_data) = MPQUserData::parse(input).unwrap();
assert_eq!(user_data.archive_header_offset, 0x18);
assert_eq!(user_data.user_data_header_size, 0x04);
assert_eq!(user_data.content, vec![0xbe, 0xef, 0xca, 0x4e]);
assert_eq!(input, &b""[..]);
}
}