use core::slice;
use crate::endian::{LittleEndian as LE, U16};
use crate::pe;
use crate::read::{Bytes, Error, ReadError, Result};
#[derive(Debug, Default, Clone, Copy)]
pub struct RelocationBlockIterator<'data> {
data: Bytes<'data>,
}
impl<'data> RelocationBlockIterator<'data> {
pub fn new(data: &'data [u8]) -> Self {
RelocationBlockIterator { data: Bytes(data) }
}
pub fn next(&mut self) -> Result<Option<RelocationIterator<'data>>> {
if self.data.is_empty() {
return Ok(None);
}
let header = self
.data
.read::<pe::ImageBaseRelocation>()
.read_error("Invalid PE reloc section size")?;
let virtual_address = header.virtual_address.get(LE);
let size = header.size_of_block.get(LE);
if size <= 8 || size & 3 != 0 {
return Err(Error("Invalid PE reloc block size"));
}
let count = (size - 8) / 2;
let relocs = self
.data
.read_slice::<U16<LE>>(count as usize)
.read_error("Invalid PE reloc block size")?
.iter();
Ok(Some(RelocationIterator {
virtual_address,
size,
relocs,
}))
}
}
#[derive(Debug, Clone)]
pub struct RelocationIterator<'data> {
virtual_address: u32,
size: u32,
relocs: slice::Iter<'data, U16<LE>>,
}
impl<'data> RelocationIterator<'data> {
pub fn virtual_address(&self) -> u32 {
self.virtual_address
}
pub fn size(&self) -> u32 {
self.size
}
}
impl<'data> Iterator for RelocationIterator<'data> {
type Item = Relocation;
fn next(&mut self) -> Option<Relocation> {
loop {
let reloc = self.relocs.next()?.get(LE);
if reloc != 0 {
return Some(Relocation {
virtual_address: self.virtual_address.wrapping_add((reloc & 0xfff) as u32),
typ: reloc >> 12,
});
}
}
}
}
#[derive(Debug, Default, Clone, Copy)]
pub struct Relocation {
pub virtual_address: u32,
pub typ: u16,
}