binaryninja/
data_buffer.rs

1// Copyright 2021-2025 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    pub fn new(data: &[u8]) -> Self {
36        let buffer = unsafe { BNCreateDataBuffer(data.as_ptr() as *const c_void, data.len()) };
37        assert!(!buffer.is_null());
38        DataBuffer::from_raw(buffer)
39    }
40
41    pub fn get_data(&self) -> &[u8] {
42        let buffer = unsafe { BNGetDataBufferContents(self.0) };
43        if buffer.is_null() {
44            &[]
45        } else {
46            unsafe { slice::from_raw_parts(buffer as *const _, self.len()) }
47        }
48    }
49
50    pub fn get_data_at(&self, offset: usize) -> &[u8] {
51        let len = self.len();
52        if offset > len {
53            panic!();
54        }
55        let slice_len = len - offset;
56        let buffer = unsafe { BNGetDataBufferContentsAt(self.0, offset) };
57        if buffer.is_null() {
58            &[]
59        } else {
60            unsafe { slice::from_raw_parts(buffer as *const _, slice_len) }
61        }
62    }
63
64    /// Create a copy of a especified part of the data
65    pub fn get_slice(&self, start: usize, len: usize) -> Option<Self> {
66        if start + len > self.len() {
67            return None;
68        }
69        let ptr = unsafe { BNGetDataBufferSlice(self.0, start, len) };
70        (!ptr.is_null()).then(|| Self(ptr))
71    }
72
73    /// change the size of the allocated data, if new size is bigger data is
74    /// need to be initialized
75    pub unsafe fn set_len(&mut self, len: usize) {
76        unsafe { BNSetDataBufferLength(self.0, len) }
77    }
78
79    /// set the size to 0
80    pub fn clear(&self) {
81        unsafe { BNClearDataBuffer(self.0) }
82    }
83
84    /// Copy the contents of `src` into `dst`
85    pub fn assign(dst: &mut Self, src: &Self) {
86        unsafe { BNAssignDataBuffer(dst.0, src.0) }
87    }
88
89    /// Concat the contents of `src` into `dst`
90    pub fn append(dst: &mut Self, src: &Self) {
91        unsafe { BNAppendDataBuffer(dst.0, src.0) }
92    }
93
94    /// concat the contents of `data` into self
95    pub fn append_data(&self, data: &[u8]) {
96        unsafe { BNAppendDataBufferContents(self.0, data.as_ptr() as *const c_void, data.len()) }
97    }
98
99    /// Return the byte at `offset`
100    pub unsafe fn byte_at(&self, offset: usize) -> u8 {
101        unsafe { BNGetDataBufferByte(self.0, offset) }
102    }
103
104    /// Set the value of the byte at `offset`
105    pub unsafe fn set_byte_at(&mut self, offset: usize, byte: u8) {
106        unsafe { BNSetDataBufferByte(self.0, offset, byte) }
107    }
108
109    pub fn set_data(&mut self, data: &[u8]) {
110        unsafe {
111            BNSetDataBufferContents(
112                self.0,
113                data.as_ptr() as *const c_void as *mut c_void,
114                data.len(),
115            );
116        }
117    }
118
119    pub fn to_escaped_string(&self, null_terminates: bool, escape_printable: bool) -> String {
120        unsafe {
121            BnString::into_string(BNDataBufferToEscapedString(
122                self.0,
123                null_terminates,
124                escape_printable,
125            ))
126        }
127    }
128
129    pub fn from_escaped_string(value: &str) -> Self {
130        let value = value.to_cstr();
131        Self(unsafe { BNDecodeEscapedString(value.as_ptr()) })
132    }
133
134    pub fn to_base64(&self) -> String {
135        unsafe { BnString::into_string(BNDataBufferToBase64(self.0)) }
136    }
137
138    pub fn from_base64(value: &str) -> Self {
139        let t = value.to_cstr();
140        Self(unsafe { BNDecodeBase64(t.as_ptr()) })
141    }
142
143    pub fn zlib_compress(&self) -> Self {
144        Self(unsafe { BNZlibCompress(self.0) })
145    }
146
147    pub fn zlib_decompress(&self) -> Self {
148        Self(unsafe { BNZlibDecompress(self.0) })
149    }
150
151    pub fn lzma_decompress(&self) -> Self {
152        Self(unsafe { BNLzmaDecompress(self.0) })
153    }
154
155    pub fn lzma2_decompress(&self) -> Self {
156        Self(unsafe { BNLzma2Decompress(self.0) })
157    }
158
159    pub fn xz_decompress(&self) -> Self {
160        Self(unsafe { BNXzDecompress(self.0) })
161    }
162
163    pub fn len(&self) -> usize {
164        unsafe { BNGetDataBufferLength(self.0) }
165    }
166
167    pub fn is_empty(&self) -> bool {
168        self.len() == 0
169    }
170}
171
172impl Default for DataBuffer {
173    fn default() -> Self {
174        Self(unsafe { BNCreateDataBuffer([].as_ptr(), 0) })
175    }
176}
177
178impl Drop for DataBuffer {
179    fn drop(&mut self) {
180        unsafe {
181            BNFreeDataBuffer(self.0);
182        }
183    }
184}
185
186impl Clone for DataBuffer {
187    fn clone(&self) -> Self {
188        Self::from_raw(unsafe { BNDuplicateDataBuffer(self.0) })
189    }
190}
191
192impl From<&[u8]> for DataBuffer {
193    fn from(value: &[u8]) -> Self {
194        DataBuffer::new(value)
195    }
196}
197
198impl AsRef<[u8]> for DataBuffer {
199    fn as_ref(&self) -> &[u8] {
200        self.get_data()
201    }
202}
203
204impl std::borrow::Borrow<[u8]> for DataBuffer {
205    fn borrow(&self) -> &[u8] {
206        self.as_ref()
207    }
208}
209
210macro_rules! data_buffer_index {
211    ($range:ty, $output:ty) => {
212        impl std::ops::Index<$range> for DataBuffer {
213            type Output = $output;
214
215            fn index(&self, index: $range) -> &Self::Output {
216                &self.get_data()[index]
217            }
218        }
219    };
220}
221
222data_buffer_index!(usize, u8);
223data_buffer_index!(std::ops::Range<usize>, [u8]);
224data_buffer_index!(std::ops::RangeInclusive<usize>, [u8]);
225data_buffer_index!(std::ops::RangeTo<usize>, [u8]);
226data_buffer_index!(std::ops::RangeFull, [u8]);
227
228impl PartialEq for DataBuffer {
229    fn eq(&self, other: &Self) -> bool {
230        self.as_ref() == other.as_ref()
231    }
232}
233impl Eq for DataBuffer {}
234
235impl PartialOrd for DataBuffer {
236    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
237        Some(self.as_ref().cmp(other.as_ref()))
238    }
239}
240
241impl Ord for DataBuffer {
242    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
243        self.as_ref().cmp(other.as_ref())
244    }
245}