use crate::errors::FileParseError;
use crate::field::Field;
use crate::pe::section::PeSection;
use crate::utils::{extract_u16, extract_u32};
pub const LN_FDSYM: u16 = 0xffff;
pub struct LineNumberEntry {
pub type_field: Field<u32>,
pub line_number: Field<u16>,
}
pub struct LineNumberBlock {
pub section_index: usize,
pub offset: usize,
pub entries: Vec<LineNumberEntry>,
}
impl LineNumberEntry {
pub const SIZE: usize = 6;
pub fn parse(buffer: &[u8], offset: usize) -> Result<Self, FileParseError> {
if buffer.len() < offset + Self::SIZE {
return Err(FileParseError::BufferOverflow);
}
Ok(LineNumberEntry {
type_field: Field::new(extract_u32(buffer, offset)?, offset, 4),
line_number: Field::new(extract_u16(buffer, offset + 4)?, offset + 4, 2),
})
}
pub fn is_source_file(&self) -> bool {
self.line_number.value == 0
}
pub fn is_line_mapping(&self) -> bool {
self.line_number.value != 0
}
}
impl LineNumberBlock {
pub fn parse(
buffer: &[u8],
section_index: usize,
section: &PeSection,
) -> Result<Self, FileParseError> {
let count = section.number_of_linenumbers.value as usize;
let offset = section.pointer_to_linenumbers.value as usize;
if count == 0 || offset == 0 {
return Ok(LineNumberBlock {
section_index,
offset,
entries: Vec::new(),
});
}
let end = offset
.checked_add(count * LineNumberEntry::SIZE)
.ok_or(FileParseError::BufferOverflow)?;
if buffer.len() < end {
return Err(FileParseError::BufferOverflow);
}
let mut entries = Vec::with_capacity(count);
for i in 0..count {
entries.push(LineNumberEntry::parse(
buffer,
offset + i * LineNumberEntry::SIZE,
)?);
}
Ok(LineNumberBlock {
section_index,
offset,
entries,
})
}
}