use crate::errors::FileParseError;
use crate::field::Field;
use crate::utils::extract_u32;
pub struct RuntimeFunction {
pub begin_address: Field<u32>,
pub end_address: Field<u32>,
pub unwind_data: Field<u32>,
}
impl RuntimeFunction {
pub const SIZE: usize = 12;
pub fn parse(buffer: &[u8], offset: usize) -> Result<Self, FileParseError> {
if buffer.len() < offset + Self::SIZE {
return Err(FileParseError::BufferOverflow);
}
Ok(RuntimeFunction {
begin_address: Field::new(extract_u32(buffer, offset)?, offset, 4),
end_address: Field::new(extract_u32(buffer, offset + 4)?, offset + 4, 4),
unwind_data: Field::new(extract_u32(buffer, offset + 8)?, offset + 8, 4),
})
}
}
pub struct ExceptionDirectory {
pub offset: usize,
pub entries: Vec<RuntimeFunction>,
}
impl ExceptionDirectory {
pub fn parse(buffer: &[u8], offset: usize, size: usize) -> Result<Self, FileParseError> {
if size == 0 {
return Ok(ExceptionDirectory {
offset,
entries: Vec::new(),
});
}
if !size.is_multiple_of(RuntimeFunction::SIZE) {
return Err(FileParseError::InvalidFileFormat);
}
let end = offset
.checked_add(size)
.ok_or(FileParseError::BufferOverflow)?;
if buffer.len() < end {
return Err(FileParseError::BufferOverflow);
}
let count = size / RuntimeFunction::SIZE;
let mut entries = Vec::with_capacity(count);
for i in 0..count {
entries.push(RuntimeFunction::parse(
buffer,
offset + i * RuntimeFunction::SIZE,
)?);
}
Ok(ExceptionDirectory { offset, entries })
}
}