use std::marker::PhantomPinned;
use std::path::Path;
use std::pin::Pin;
use std::{fs, ptr};
use log::debug;
use memmap::{Mmap, MmapOptions};
use crate::errors::{Error, Result};
pub struct BinaryParser {
bytes: Mmap,
object: Option<goblin::Object<'static>>,
_pin: PhantomPinned,
}
impl BinaryParser {
pub fn open(path: impl AsRef<Path>) -> Result<Pin<Box<Self>>> {
debug!("Opening binary file '{}'.", path.as_ref().display());
let file = fs::File::open(&path)
.map_err(|r| Error::from_io1(r, "std::fs::File::open", path.as_ref()))?;
debug!("Mapping binary file '{}'.", path.as_ref().display());
let bytes = unsafe { MmapOptions::new().map(&file) }
.map_err(|r| Error::from_io1(r, "memmap::MmapOptions::map", path.as_ref()))?;
let mut result = Box::pin(Self {
bytes,
object: None,
_pin: PhantomPinned,
});
let bytes_ref: &'static Mmap =
unsafe { ptr::NonNull::from(&result.bytes).as_ptr().as_ref().unwrap() };
debug!("Parsing binary file '{}'.", path.as_ref().display());
let object = goblin::Object::parse(bytes_ref).map_err(|source| Error::Goblin {
operation: "goblin::Object::parse",
source,
})?;
result.as_mut().set_object(Some(object));
Ok(result)
}
pub fn object(&self) -> &goblin::Object {
self.object.as_ref().unwrap()
}
pub fn bytes(&self) -> &[u8] {
&self.bytes
}
fn set_object(mut self: Pin<&mut Self>, object: Option<goblin::Object<'static>>) {
let this = Pin::as_mut(&mut self);
unsafe { Pin::get_unchecked_mut(this) }.object = object;
}
fn drop_pinned(self: Pin<&mut Self>) {
self.set_object(None);
}
}
impl Drop for BinaryParser {
fn drop(&mut self) {
unsafe { Pin::new_unchecked(self) }.drop_pinned();
}
}