use crate::{dir::*, error::*, impl_from_bytes, mem::*};
use core::mem;
pub enum Import<'a> {
Name(u16, &'a str),
Ordinal(u16),
}
pub struct ImportModule<'a> {
dir: &'a ImportDirectoryEntry,
data: ByteReader<'a>,
}
impl<'a> ImportModule<'a> {
pub fn new(
data: &'a [u8],
data_rva: usize,
dir: &'a ImportDirectoryEntry,
) -> Self {
let mut data = ByteReader::new_with_rel(data, data_rva);
data.skip_to(Pos::Abs(dir.lookup_rva as _));
Self { data, dir }
}
pub fn time_date_stamp(&self) -> u32 {
self.dir.time_date_stamp
}
pub fn forwarder(&self) -> u32 {
self.dir.forwarder_chain
}
pub fn name(&self) -> Result<&str> {
str_from_bytes(self.data.bytes_at(self.dir.name_rva as _)?)
}
pub fn address_rva(&self) -> u32 {
self.dir.address_rva
}
}
impl<'a> Iterator for ImportModule<'a> {
type Item = Result<Import<'a>>;
fn next(&mut self) -> Option<Self::Item> {
match self.data.read::<ImportEntry>() {
Ok(entry) => {
if entry == &ImportEntry::default() {
return None;
}
let import = if entry.is_ordinal() {
Import::Ordinal(entry.value() as u16)
} else {
match (|| {
let hint = self.data.read_at::<u16>(entry.value() as _)?;
let name = str_from_bytes(self.data.bytes_at(
entry.value() as usize + mem::size_of::<u16>(),
)?)?;
Ok((*hint, name))
})() {
Ok((o, n)) => Import::Name(o, n),
Err(e) => return Some(Err(e)),
}
};
Some(Ok(import))
}
Err(e) => Some(Err(e)),
}
}
}
pub struct ImportTable<'a> {
data: ByteReader<'a>,
}
impl<'a> DataDirectoryTable<'a> for ImportTable<'a> {
fn new(bytes: &'a [u8], dir: &'a DataDirectory) -> Self {
Self {
data: ByteReader::new_with_rel(bytes, dir.addr as usize),
}
}
fn typ() -> DataDirectoryType {
DataDirectoryType::ImportTable
}
}
impl<'a> Iterator for ImportTable<'a> {
type Item = Result<ImportModule<'a>>;
fn next(&mut self) -> Option<Self::Item> {
match self.data.read::<ImportDirectoryEntry>() {
Ok(dir) => {
if dir == &ImportDirectoryEntry::default() {
return None;
}
Some(Ok(ImportModule::new(
self.data.bytes(),
self.data.rel_pos().unwrap(),
dir,
)))
}
Err(e) => Some(Err(e)),
}
}
}
#[derive(Clone, Copy, PartialEq, Eq, Default)]
#[repr(C)]
pub struct ImportDirectoryEntry {
pub lookup_rva: u32,
pub time_date_stamp: u32,
pub forwarder_chain: u32,
pub name_rva: u32,
pub address_rva: u32,
}
#[derive(Clone, Copy, PartialEq, Eq, Default)]
pub struct ImportEntry(u64);
impl ImportEntry {
pub fn value(&self) -> u32 {
(self.0 & 0x00000000FFFFFFFF) as u32
}
pub fn is_ordinal(&self) -> bool {
(self.0 >> 63) == 1
}
}
impl_from_bytes!(ImportDirectoryEntry, ImportEntry);