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 0
50 } else {
51 f.read(dest).unwrap_or(0)
52 }
53 }
54
55 extern "C" fn cb_write<A: Accessor>(
56 ctxt: *mut c_void,
57 offset: u64,
58 src: *const c_void,
59 len: usize,
60 ) -> usize {
61 let f = unsafe { &mut *(ctxt as *mut A) };
62 let src = unsafe { slice::from_raw_parts(src as *const u8, len) };
63
64 if f.seek(SeekFrom::Start(offset)).is_err() {
65 0
66 } else {
67 f.write(src).unwrap_or(0)
68 }
69 }
70
71 let boxed_accessor = Box::new(accessor);
72 let leaked_accessor = Box::leak(boxed_accessor);
73
74 Self {
75 raw: BNFileAccessor {
76 context: leaked_accessor as *mut A as *mut _,
77 getLength: Some(cb_get_length::<A>),
78 read: Some(cb_read::<A>),
79 write: Some(cb_write::<A>),
80 },
81 accessor: PhantomData,
82 }
83 }
84
85 pub fn read(&self, addr: u64, len: usize) -> Result<Vec<u8>, ErrorKind> {
86 let cb_read = self.raw.read.unwrap();
87 let mut buf = vec![0; len];
88 let read_len = unsafe { cb_read(self.raw.context, buf.as_mut_ptr() as *mut _, addr, len) };
89 if read_len != len {
90 return Err(ErrorKind::UnexpectedEof);
91 }
92 Ok(buf)
93 }
94
95 pub fn write(&self, addr: u64, data: &[u8]) -> usize {
96 let cb_write = self.raw.write.unwrap();
97 unsafe {
98 cb_write(
99 self.raw.context,
100 addr,
101 data.as_ptr() as *const _,
102 data.len(),
103 )
104 }
105 }
106
107 pub fn length(&self) -> u64 {
108 let cb_get_length = self.raw.getLength.unwrap();
109 unsafe { cb_get_length(self.raw.context) }
110 }
111}
112
113impl<A: Accessor> Drop for FileAccessor<A> {
114 fn drop(&mut self) {
115 unsafe {
116 let _ = Box::from_raw(self.raw.context as *mut A);
117 }
118 }
119}