binaryninja/
data_buffer.rs

1// Copyright 2021-2026 Vector 35 Inc.
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15//! A basic wrapper around an array of binary data
16
17use binaryninjacore_sys::*;
18
19use std::ffi::c_void;
20use std::slice;
21
22use crate::string::{BnString, IntoCStr};
23
24pub struct DataBuffer(*mut BNDataBuffer);
25
26impl DataBuffer {
27    pub(crate) fn from_raw(raw: *mut BNDataBuffer) -> Self {
28        DataBuffer(raw)
29    }
30
31    pub(crate) fn as_raw(&self) -> *mut BNDataBuffer {
32        self.0
33    }
34
35    /// Return the raw pointer to the underlying data buffer, to be freed later with `BNFreeDataBuffer`.
36    pub fn into_raw(self) -> *mut BNDataBuffer {
37        let ptr = self.0;
38        std::mem::forget(self);
39        ptr
40    }
41
42    pub fn new(data: &[u8]) -> Self {
43        let buffer = unsafe { BNCreateDataBuffer(data.as_ptr() as *const c_void, data.len()) };
44        assert!(!buffer.is_null());
45        DataBuffer::from_raw(buffer)
46    }
47
48    pub fn get_data(&self) -> &[u8] {
49        let buffer = unsafe { BNGetDataBufferContents(self.0) };
50        if buffer.is_null() {
51            &[]
52        } else {
53            unsafe { slice::from_raw_parts(buffer as *const _, self.len()) }
54        }
55    }
56
57    pub fn get_data_at(&self, offset: usize) -> &[u8] {
58        let len = self.len();
59        if offset > len {
60            panic!();
61        }
62        let slice_len = len - offset;
63        let buffer = unsafe { BNGetDataBufferContentsAt(self.0, offset) };
64        if buffer.is_null() {
65            &[]
66        } else {
67            unsafe { slice::from_raw_parts(buffer as *const _, slice_len) }
68        }
69    }
70
71    /// Create a copy of a especified part of the data
72    pub fn get_slice(&self, start: usize, len: usize) -> Option<Self> {
73        if start + len > self.len() {
74            return None;
75        }
76        let ptr = unsafe { BNGetDataBufferSlice(self.0, start, len) };
77        (!ptr.is_null()).then(|| Self(ptr))
78    }
79
80    /// change the size of the allocated data, if new size is bigger data is
81    /// need to be initialized
82    pub unsafe fn set_len(&mut self, len: usize) {
83        unsafe { BNSetDataBufferLength(self.0, len) }
84    }
85
86    /// set the size to 0
87    pub fn clear(&self) {
88        unsafe { BNClearDataBuffer(self.0) }
89    }
90
91    /// Copy the contents of `src` into `dst`
92    pub fn assign(dst: &mut Self, src: &Self) {
93        unsafe { BNAssignDataBuffer(dst.0, src.0) }
94    }
95
96    /// Concat the contents of `src` into `dst`
97    pub fn append(dst: &mut Self, src: &Self) {
98        unsafe { BNAppendDataBuffer(dst.0, src.0) }
99    }
100
101    /// concat the contents of `data` into self
102    pub fn append_data(&self, data: &[u8]) {
103        unsafe { BNAppendDataBufferContents(self.0, data.as_ptr() as *const c_void, data.len()) }
104    }
105
106    /// Return the byte at `offset`
107    pub unsafe fn byte_at(&self, offset: usize) -> u8 {
108        unsafe { BNGetDataBufferByte(self.0, offset) }
109    }
110
111    /// Set the value of the byte at `offset`
112    pub unsafe fn set_byte_at(&mut self, offset: usize, byte: u8) {
113        unsafe { BNSetDataBufferByte(self.0, offset, byte) }
114    }
115
116    pub fn set_data(&mut self, data: &[u8]) {
117        unsafe {
118            BNSetDataBufferContents(
119                self.0,
120                data.as_ptr() as *const c_void as *mut c_void,
121                data.len(),
122            );
123        }
124    }
125
126    pub fn to_escaped_string(&self, null_terminates: bool, escape_printable: bool) -> String {
127        unsafe {
128            BnString::into_string(BNDataBufferToEscapedString(
129                self.0,
130                null_terminates,
131                escape_printable,
132            ))
133        }
134    }
135
136    pub fn from_escaped_string(value: &str) -> Self {
137        let value = value.to_cstr();
138        Self(unsafe { BNDecodeEscapedString(value.as_ptr()) })
139    }
140
141    pub fn to_base64(&self) -> String {
142        unsafe { BnString::into_string(BNDataBufferToBase64(self.0)) }
143    }
144
145    pub fn from_base64(value: &str) -> Self {
146        let t = value.to_cstr();
147        Self(unsafe { BNDecodeBase64(t.as_ptr()) })
148    }
149
150    pub fn zlib_compress(&self) -> Self {
151        Self(unsafe { BNZlibCompress(self.0) })
152    }
153
154    pub fn zlib_decompress(&self) -> Self {
155        Self(unsafe { BNZlibDecompress(self.0) })
156    }
157
158    pub fn lzma_decompress(&self) -> Self {
159        Self(unsafe { BNLzmaDecompress(self.0) })
160    }
161
162    pub fn lzma2_decompress(&self) -> Self {
163        Self(unsafe { BNLzma2Decompress(self.0) })
164    }
165
166    pub fn xz_decompress(&self) -> Self {
167        Self(unsafe { BNXzDecompress(self.0) })
168    }
169
170    pub fn len(&self) -> usize {
171        unsafe { BNGetDataBufferLength(self.0) }
172    }
173
174    pub fn is_empty(&self) -> bool {
175        self.len() == 0
176    }
177}
178
179impl Default for DataBuffer {
180    fn default() -> Self {
181        Self(unsafe { BNCreateDataBuffer([].as_ptr(), 0) })
182    }
183}
184
185impl Drop for DataBuffer {
186    fn drop(&mut self) {
187        unsafe {
188            BNFreeDataBuffer(self.0);
189        }
190    }
191}
192
193impl Clone for DataBuffer {
194    fn clone(&self) -> Self {
195        Self::from_raw(unsafe { BNDuplicateDataBuffer(self.0) })
196    }
197}
198
199impl From<&[u8]> for DataBuffer {
200    fn from(value: &[u8]) -> Self {
201        DataBuffer::new(value)
202    }
203}
204
205impl AsRef<[u8]> for DataBuffer {
206    fn as_ref(&self) -> &[u8] {
207        self.get_data()
208    }
209}
210
211impl std::borrow::Borrow<[u8]> for DataBuffer {
212    fn borrow(&self) -> &[u8] {
213        self.as_ref()
214    }
215}
216
217macro_rules! data_buffer_index {
218    ($range:ty, $output:ty) => {
219        impl std::ops::Index<$range> for DataBuffer {
220            type Output = $output;
221
222            fn index(&self, index: $range) -> &Self::Output {
223                &self.get_data()[index]
224            }
225        }
226    };
227}
228
229data_buffer_index!(usize, u8);
230data_buffer_index!(std::ops::Range<usize>, [u8]);
231data_buffer_index!(std::ops::RangeInclusive<usize>, [u8]);
232data_buffer_index!(std::ops::RangeTo<usize>, [u8]);
233data_buffer_index!(std::ops::RangeFull, [u8]);
234
235impl PartialEq for DataBuffer {
236    fn eq(&self, other: &Self) -> bool {
237        self.as_ref() == other.as_ref()
238    }
239}
240impl Eq for DataBuffer {}
241
242impl PartialOrd for DataBuffer {
243    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
244        Some(self.cmp(other))
245    }
246}
247
248impl Ord for DataBuffer {
249    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
250        self.as_ref().cmp(other.as_ref())
251    }
252}