use lief_ffi as ffi;
use crate::common::into_optional;
use crate::common::{AsFFI, FromFFI};
use crate::declare_iterator;
use crate::generic;
use std::pin::Pin;
use std::marker::PhantomData;
pub struct Export<'a> {
ptr: cxx::UniquePtr<ffi::PE_Export>,
_owner: PhantomData<&'a ffi::PE_Binary>,
}
impl Export<'_> {
pub fn new() -> Export<'static> {
Export::from_ffi(ffi::PE_Export::create())
}
pub fn export_flags(&self) -> u32 {
self.ptr.export_flags()
}
pub fn timestamp(&self) -> u32 {
self.ptr.timestamp()
}
pub fn major_version(&self) -> u16 {
self.ptr.major_version()
}
pub fn minor_version(&self) -> u16 {
self.ptr.minor_version()
}
pub fn ordinal_base(&self) -> u32 {
self.ptr.ordinal_base()
}
pub fn name(&self) -> String {
self.ptr.name().to_string()
}
pub fn entries(&self) -> ExportEntries<'_> {
ExportEntries::new(self.ptr.entries())
}
pub fn name_rva(&self) -> u32 {
self.ptr.name_rva()
}
pub fn names_addr_table_rva(&self) -> u32 {
self.ptr.names_addr_table_rva()
}
pub fn names_addr_table_cnt(&self) -> u32 {
self.ptr.names_addr_table_cnt()
}
pub fn export_addr_table_rva(&self) -> u32 {
self.ptr.export_addr_table_rva()
}
pub fn export_addr_table_cnt(&self) -> u32 {
self.ptr.export_addr_table_cnt()
}
pub fn ord_addr_table_rva(&self) -> u32 {
self.ptr.ord_addr_table_rva()
}
pub fn set_export_flags(&mut self, flags: u32) -> &mut Self {
self.ptr.pin_mut().set_export_flags(flags);
self
}
pub fn set_timestamp(&mut self, timestamp: u32) -> &mut Self {
self.ptr.pin_mut().set_export_flags(timestamp);
self
}
pub fn set_major_version(&mut self, version: u32) -> &mut Self {
self.ptr.pin_mut().set_major_version(version);
self
}
pub fn set_minor_version(&mut self, version: u32) -> &mut Self {
self.ptr.pin_mut().set_minor_version(version);
self
}
pub fn set_name(&mut self, name: &str) -> &mut Self {
cxx::let_cxx_string!(__cxx_s = name);
self.ptr.pin_mut().set_name(&__cxx_s);
self
}
pub fn entry_by_name(&self, name: &str) -> Option<Entry<'_>> {
cxx::let_cxx_string!(__cxx_s = name);
into_optional(self.ptr.entry_by_name(&__cxx_s))
}
pub fn entry_by_ordinal(&self, ordinal: u32) -> Option<Entry<'_>> {
into_optional(self.ptr.entry_by_ordinal(ordinal))
}
pub fn entry_at_rva(&self, rva: u32) -> Option<Entry<'_>> {
into_optional(self.ptr.entry_at_rva(rva))
}
pub fn add_entry(&mut self, entry: &Entry) -> Entry<'_> {
Entry::from_ffi(self.ptr.pin_mut().add_entry(entry.ptr.as_ref().unwrap()))
}
pub fn add_entry_by_name(&mut self, name: &str, rva: u32) -> Entry<'_> {
cxx::let_cxx_string!(__cxx_s = name);
Entry::from_ffi(self.ptr.pin_mut().add_entry_by_name(&__cxx_s, rva))
}
pub fn remove_entry(&mut self, entry: Entry) -> bool {
self.ptr.pin_mut().remove_entry(entry.ptr)
}
pub fn remove_entry_at(&mut self, rva: u32) -> bool {
self.ptr.pin_mut().remove_entry_at(rva)
}
pub fn remove_entry_by_name(&mut self, name: &str) -> bool {
cxx::let_cxx_string!(__cxx_s = name);
self.ptr.pin_mut().remove_entry_by_name(&__cxx_s)
}
}
impl std::fmt::Debug for Export<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("Export")
.field("export_flags", &self.export_flags())
.field("timestamp", &self.timestamp())
.field("major_version", &self.major_version())
.field("minor_version", &self.minor_version())
.field("ordinal_base", &self.ordinal_base())
.field("name", &self.name())
.finish()
}
}
impl<'a> FromFFI<ffi::PE_Export> for Export<'a> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_Export>) -> Self {
Export {
ptr,
_owner: PhantomData,
}
}
}
impl<'a> AsFFI<ffi::PE_Export> for Export<'a> {
fn as_ffi(&self) -> &ffi::PE_Export {
self.ptr.as_ref().unwrap()
}
fn as_mut_ffi(&mut self) -> std::pin::Pin<&mut ffi::PE_Export> {
self.ptr.pin_mut()
}
}
pub struct Entry<'a> {
ptr: cxx::UniquePtr<ffi::PE_ExportEntry>,
_owner: PhantomData<&'a ffi::PE_Export>,
}
impl Entry<'_> {
pub fn ordinal(&self) -> u16 {
self.ptr.ordinal()
}
pub fn address(&self) -> u32 {
self.ptr.address()
}
pub fn function_rva(&self) -> u32 {
self.ptr.function_rva()
}
pub fn is_extern(&self) -> bool {
self.ptr.is_extern()
}
pub fn is_forwarded(&self) -> bool {
self.ptr.is_forwarded()
}
pub fn demangled_name(&self) -> String {
self.ptr.demangled_name().to_string()
}
pub fn forward_info(&self) -> Option<ForwardInfo> {
if !self.ptr.is_forwarded() {
return None;
}
Some(ForwardInfo::with_values(
self.ptr.fwd_library().to_string(),
self.ptr.fwd_function().to_string(),
))
}
pub fn set_ordinal(&mut self, ordinal: u16) -> &mut Self {
self.ptr.pin_mut().set_ordinal(ordinal);
self
}
pub fn set_address(&mut self, address: u32) -> &mut Self {
self.ptr.pin_mut().set_address(address);
self
}
}
impl generic::Symbol for Entry<'_> {
fn as_generic(&self) -> &ffi::AbstractSymbol {
self.ptr.as_ref().unwrap().as_ref()
}
fn as_pin_mut_generic(&mut self) -> Pin<&mut ffi::AbstractSymbol> {
unsafe {
Pin::new_unchecked({
(self.ptr.as_ref().unwrap().as_ref() as *const ffi::AbstractSymbol
as *mut ffi::AbstractSymbol)
.as_mut()
.unwrap()
})
}
}
}
impl std::fmt::Debug for Entry<'_> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
let base = self as &dyn generic::Symbol;
f.debug_struct("ExportEntry")
.field("base", &base)
.field("ordinal", &self.ordinal())
.field("address", &self.address())
.finish()
}
}
impl<'a> FromFFI<ffi::PE_ExportEntry> for Entry<'a> {
fn from_ffi(ptr: cxx::UniquePtr<ffi::PE_ExportEntry>) -> Self {
Entry {
ptr,
_owner: PhantomData,
}
}
}
pub struct ForwardInfo {
pub library: String,
pub function: String,
}
impl ForwardInfo {
pub fn with_values(library: String, function: String) -> Self {
Self { library, function }
}
}
declare_iterator!(
ExportEntries,
Entry<'a>,
ffi::PE_ExportEntry,
ffi::PE_Export,
ffi::PE_Export_it_entries
);