binaryninja/
file_accessor.rs1use binaryninjacore_sys::BNFileAccessor;
16use std::io::{ErrorKind, Read, Seek, SeekFrom, Write};
17use std::marker::PhantomData;
18use std::slice;
19
20pub trait Accessor: Read + Write + Seek + Sized {}
21
22impl<T: Read + Write + Seek + Sized> Accessor for T {}
23
24pub struct FileAccessor<A: Accessor> {
25 pub(crate) raw: BNFileAccessor,
26 accessor: PhantomData<A>,
27}
28
29impl<A: Accessor> FileAccessor<A> {
30 pub fn new(accessor: A) -> Self {
31 use std::os::raw::c_void;
32
33 extern "C" fn cb_get_length<A: Accessor>(ctxt: *mut c_void) -> u64 {
34 let f = unsafe { &mut *(ctxt as *mut A) };
35
36 f.seek(SeekFrom::End(0)).unwrap_or(0)
37 }
38
39 extern "C" fn cb_read<A: Accessor>(
40 ctxt: *mut c_void,
41 dest: *mut c_void,
42 offset: u64,
43 len: usize,
44 ) -> usize {
45 let f = unsafe { &mut *(ctxt as *mut A) };
46 let dest = unsafe { slice::from_raw_parts_mut(dest as *mut u8, len) };
47
48 if f.seek(SeekFrom::Start(offset)).is_err() {
49 log::debug!("Failed to seek to offset {:x}", offset);
50 0
51 } else {
52 f.read(dest).unwrap_or(0)
53 }
54 }
55
56 extern "C" fn cb_write<A: Accessor>(
57 ctxt: *mut c_void,
58 offset: u64,
59 src: *const c_void,
60 len: usize,
61 ) -> usize {
62 let f = unsafe { &mut *(ctxt as *mut A) };
63 let src = unsafe { slice::from_raw_parts(src as *const u8, len) };
64
65 if f.seek(SeekFrom::Start(offset)).is_err() {
66 0
67 } else {
68 f.write(src).unwrap_or(0)
69 }
70 }
71
72 let boxed_accessor = Box::new(accessor);
73 let leaked_accessor = Box::leak(boxed_accessor);
74
75 Self {
76 raw: BNFileAccessor {
77 context: leaked_accessor as *mut A as *mut _,
78 getLength: Some(cb_get_length::<A>),
79 read: Some(cb_read::<A>),
80 write: Some(cb_write::<A>),
81 },
82 accessor: PhantomData,
83 }
84 }
85
86 pub fn read(&self, addr: u64, len: usize) -> Result<Vec<u8>, ErrorKind> {
87 let cb_read = self.raw.read.unwrap();
88 let mut buf = vec![0; len];
89 let read_len = unsafe { cb_read(self.raw.context, buf.as_mut_ptr() as *mut _, addr, len) };
90 if read_len != len {
91 return Err(ErrorKind::UnexpectedEof);
92 }
93 Ok(buf)
94 }
95
96 pub fn write(&self, addr: u64, data: &[u8]) -> usize {
97 let cb_write = self.raw.write.unwrap();
98 unsafe {
99 cb_write(
100 self.raw.context,
101 addr,
102 data.as_ptr() as *const _,
103 data.len(),
104 )
105 }
106 }
107
108 pub fn length(&self) -> u64 {
109 let cb_get_length = self.raw.getLength.unwrap();
110 unsafe { cb_get_length(self.raw.context) }
111 }
112}
113
114impl<A: Accessor> Drop for FileAccessor<A> {
115 fn drop(&mut self) {
116 unsafe {
117 let _ = Box::from_raw(self.raw.context as *mut A);
118 }
119 }
120}