use crate::{error::Error, Result};
use core::{marker::PhantomPinned, pin::Pin, ptr};
use memmap2::{Mmap, MmapOptions};
use std::{fs, path::Path};
pub(crate) struct BinaryParser {
bytes: Mmap,
object: Option<goblin::Object<'static>>,
_pin: PhantomPinned,
}
impl BinaryParser {
pub(crate) fn open(path: impl AsRef<Path>) -> Result<Pin<Box<Self>>> {
let file = fs::File::open(&path).map_err(Error::IoError)?;
let bytes = unsafe { MmapOptions::new().map(&file) }.map_err(Error::IoError)?;
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() };
let object = goblin::Object::parse(bytes_ref).map_err(Error::ParseError)?;
result.as_mut().set_object(Some(object));
Ok(result)
}
pub(crate) fn object(&self) -> &goblin::Object {
self.object.as_ref().unwrap()
}
pub(crate) 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();
}
}