use super::binary::Binary;
use lief_ffi as ffi;
use crate::{
common::{AsFFI, FromFFI, into_optional},
macho::header::CpuType,
};
use std::path::Path;
pub struct FatBinary {
pub nb_macho: u32,
ptr: cxx::UniquePtr<ffi::MachO_FatBinary>,
}
impl FromFFI<ffi::MachO_FatBinary> for FatBinary {
fn from_ffi(ptr: cxx::UniquePtr<ffi::MachO_FatBinary>) -> Self {
Self {
nb_macho: ptr.size(),
ptr,
}
}
}
impl std::fmt::Debug for FatBinary {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("FatBinary")
.field("nb_macho", &self.nb_macho)
.finish()
}
}
pub struct FatBinaryIterator<'a> {
index: u32,
fat: &'a FatBinary,
}
impl FatBinary {
pub fn parse<P: AsRef<Path>>(path: P) -> Option<Self> {
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::MachO_FatBinary::parse(&__cxx_s);
if ffi.is_null() {
return None;
}
Some(FatBinary::from_ffi(ffi))
}
pub fn parse_with_config<P: AsRef<Path>>(
path: P,
config: &super::parser_config::Config,
) -> Option<Self> {
let ffi_config = config.to_ffi();
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::MachO_FatBinary::parse_with_config(&__cxx_s, &ffi_config);
if ffi.is_null() {
return None;
}
Some(FatBinary::from_ffi(ffi))
}
pub fn parse_from_dump<P: AsRef<Path>>(path: P, addr: u64) -> Option<Self> {
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::MachO_FatBinary::parse_from_dump(&__cxx_s, addr);
if ffi.is_null() {
return None;
}
Some(FatBinary::from_ffi(ffi))
}
pub fn parse_from_dump_with_config<P: AsRef<Path>>(
path: P,
addr: u64,
config: &super::parser_config::Config,
) -> Option<Self> {
let ffi_config = config.to_ffi();
cxx::let_cxx_string!(__cxx_s = path.as_ref().to_str().unwrap());
let ffi = ffi::MachO_FatBinary::parse_from_dump_with_config(&__cxx_s, addr, &ffi_config);
if ffi.is_null() {
return None;
}
Some(FatBinary::from_ffi(ffi))
}
pub fn with_cpu(&self, cpu: CpuType) -> Option<Binary> {
into_optional(self.ptr.binary_from_arch(cpu.into()))
}
pub fn iter(&self) -> FatBinaryIterator<'_> {
FatBinaryIterator {
index: 0,
fat: self,
}
}
pub fn write<P: AsRef<Path>>(&mut self, output: P) {
cxx::let_cxx_string!(__cxx_s = output.as_ref().to_str().unwrap());
self.ptr.as_mut().unwrap().write(&__cxx_s);
}
}
impl AsFFI<ffi::MachO_FatBinary> for FatBinary {
fn as_ffi(&self) -> &ffi::MachO_FatBinary {
self.ptr.as_ref().unwrap()
}
fn as_mut_ffi(&mut self) -> std::pin::Pin<&mut ffi::MachO_FatBinary> {
self.ptr.pin_mut()
}
}
impl<'a> Iterator for FatBinaryIterator<'a> {
type Item = Binary;
fn next(&mut self) -> Option<Self::Item> {
if self.index >= self.fat.nb_macho {
return None;
}
self.index += 1;
Some(Binary::from_ffi(self.fat.ptr.binary_at(self.index - 1)))
}
}
impl<'a> ExactSizeIterator for FatBinaryIterator<'a> {
fn len(&self) -> usize {
self.fat.nb_macho.try_into().unwrap()
}
}