binaryninja/binary_view/
reader.rs1use binaryninjacore_sys::*;
18use std::fmt::Debug;
19
20use crate::binary_view::{BinaryView, BinaryViewBase};
21use crate::Endianness;
22
23use crate::rc::Ref;
24use std::io::{ErrorKind, Read, Seek, SeekFrom};
25
26pub struct BinaryReader {
27 view: Ref<BinaryView>,
28 handle: *mut BNBinaryReader,
29}
30
31impl BinaryReader {
32 pub fn new(view: &BinaryView) -> Self {
33 let handle = unsafe { BNCreateBinaryReader(view.handle) };
34 Self {
35 view: view.to_owned(),
36 handle,
37 }
38 }
39
40 pub fn new_with_opts(view: &BinaryView, options: &BinaryReaderOptions) -> Self {
41 let mut reader = Self::new(view);
42 if let Some(endianness) = options.endianness {
43 reader.set_endianness(endianness);
44 }
45 if let Some(virtual_base) = options.virtual_base {
47 reader.set_virtual_base(virtual_base);
48 }
49 if let Some(address) = options.address {
50 reader.seek_to_offset(address);
51 }
52 reader
53 }
54
55 pub fn endianness(&self) -> Endianness {
56 unsafe { BNGetBinaryReaderEndianness(self.handle) }
57 }
58
59 pub fn set_endianness(&mut self, endianness: Endianness) {
60 unsafe { BNSetBinaryReaderEndianness(self.handle, endianness) }
61 }
62
63 pub fn virtual_base(&self) -> u64 {
64 unsafe { BNGetBinaryReaderVirtualBase(self.handle) }
65 }
66
67 pub fn set_virtual_base(&mut self, virtual_base_addr: u64) {
68 unsafe { BNSetBinaryReaderVirtualBase(self.handle, virtual_base_addr) }
69 }
70
71 pub fn seek_to_offset(&mut self, offset: u64) {
73 unsafe { BNSeekBinaryReader(self.handle, offset) }
74 }
75
76 pub fn seek_to_relative_offset(&mut self, offset: i64) {
78 unsafe { BNSeekBinaryReaderRelative(self.handle, offset) }
79 }
80
81 pub fn offset(&self) -> u64 {
82 unsafe { BNGetReaderPosition(self.handle) }
83 }
84
85 pub fn is_eof(&self) -> bool {
87 unsafe { BNIsEndOfFile(self.handle) }
88 }
89}
90
91impl Debug for BinaryReader {
92 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
93 f.debug_struct("BinaryReader")
94 .field("offset", &self.offset())
95 .field("virtual_base", &self.virtual_base())
96 .field("endianness", &self.endianness())
97 .finish()
98 }
99}
100
101impl Seek for BinaryReader {
102 fn seek(&mut self, pos: SeekFrom) -> std::io::Result<u64> {
104 match pos {
105 SeekFrom::Current(offset) => self.seek_to_relative_offset(offset),
106 SeekFrom::Start(offset) => self.seek_to_offset(offset),
107 SeekFrom::End(end_offset) => {
108 let offset =
111 self.view
112 .len()
113 .checked_add_signed(end_offset)
114 .ok_or(std::io::Error::new(
115 ErrorKind::Other,
116 "Seeking from end overflowed",
117 ))?;
118 self.seek_to_offset(offset);
119 }
120 };
121
122 Ok(self.offset())
123 }
124}
125
126impl Read for BinaryReader {
127 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
128 let len = buf.len();
129
130 let result = unsafe { BNReadData(self.handle, buf.as_mut_ptr() as *mut _, len) };
131
132 if !result {
133 Err(std::io::Error::new(ErrorKind::Other, "Read out of bounds"))
134 } else {
135 Ok(len)
136 }
137 }
138}
139
140impl Drop for BinaryReader {
141 fn drop(&mut self) {
142 unsafe { BNFreeBinaryReader(self.handle) }
143 }
144}
145
146unsafe impl Sync for BinaryReader {}
147unsafe impl Send for BinaryReader {}
148
149#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
150pub struct BinaryReaderOptions {
151 endianness: Option<Endianness>,
152 virtual_base: Option<u64>,
153 address: Option<u64>,
154}
155
156impl BinaryReaderOptions {
157 pub fn new() -> Self {
158 Self::default()
159 }
160
161 pub fn with_endianness(mut self, endian: Endianness) -> Self {
162 self.endianness = Some(endian);
163 self
164 }
165
166 pub fn with_virtual_base(mut self, virtual_base_addr: u64) -> Self {
167 self.virtual_base = Some(virtual_base_addr);
168 self
169 }
170
171 pub fn with_address(mut self, address: u64) -> Self {
172 self.address = Some(address);
173 self
174 }
175}