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::{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 = self
111 .view
112 .len()
113 .checked_add_signed(end_offset)
114 .ok_or(std::io::Error::other("Seeking from end overflowed"))?;
115 self.seek_to_offset(offset);
116 }
117 };
118
119 Ok(self.offset())
120 }
121}
122
123impl Read for BinaryReader {
124 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
125 let len = buf.len();
126
127 let result = unsafe { BNReadData(self.handle, buf.as_mut_ptr() as *mut _, len) };
128
129 if !result {
130 Err(std::io::Error::other("Read out of bounds"))
131 } else {
132 Ok(len)
133 }
134 }
135}
136
137impl Drop for BinaryReader {
138 fn drop(&mut self) {
139 unsafe { BNFreeBinaryReader(self.handle) }
140 }
141}
142
143unsafe impl Sync for BinaryReader {}
144unsafe impl Send for BinaryReader {}
145
146#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Default)]
147pub struct BinaryReaderOptions {
148 endianness: Option<Endianness>,
149 virtual_base: Option<u64>,
150 address: Option<u64>,
151}
152
153impl BinaryReaderOptions {
154 pub fn new() -> Self {
155 Self::default()
156 }
157
158 pub fn with_endianness(mut self, endian: Endianness) -> Self {
159 self.endianness = Some(endian);
160 self
161 }
162
163 pub fn with_virtual_base(mut self, virtual_base_addr: u64) -> Self {
164 self.virtual_base = Some(virtual_base_addr);
165 self
166 }
167
168 pub fn with_address(mut self, address: u64) -> Self {
169 self.address = Some(address);
170 self
171 }
172}