Skip to content

Commit 3615742

Browse files
rbranemesare
authored andcommitted
Finish the DataBuffer implementation
1 parent 031456e commit 3615742

File tree

2 files changed

+254
-12
lines changed

2 files changed

+254
-12
lines changed

rust/src/databuffer.rs

Lines changed: 250 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,10 @@
1717
use binaryninjacore_sys::*;
1818

1919
use std::ffi::c_void;
20-
use std::ptr;
2120
use std::slice;
2221

22+
use crate::string::BnString;
23+
2324
pub struct DataBuffer(*mut BNDataBuffer);
2425

2526
impl DataBuffer {
@@ -31,10 +32,6 @@ impl DataBuffer {
3132
}
3233

3334
pub fn get_data(&self) -> &[u8] {
34-
if self.0.is_null() {
35-
// TODO : Change the default value and remove this
36-
return &[];
37-
}
3835
let buffer = unsafe { BNGetDataBufferContents(self.0) };
3936
if buffer.is_null() {
4037
&[]
@@ -43,6 +40,65 @@ impl DataBuffer {
4340
}
4441
}
4542

43+
pub fn get_data_at(&self, offset: usize) -> &[u8] {
44+
let len = self.len();
45+
if offset > len {
46+
panic!();
47+
}
48+
let slice_len = len - offset;
49+
let buffer = unsafe { BNGetDataBufferContentsAt(self.0, offset) };
50+
if buffer.is_null() {
51+
&[]
52+
} else {
53+
unsafe { slice::from_raw_parts(buffer as *const _, slice_len) }
54+
}
55+
}
56+
57+
/// Create a copy of a especified part of the data
58+
pub fn get_slice(&self, start: usize, len: usize) -> Option<Self> {
59+
if start + len > self.len() {
60+
return None;
61+
}
62+
let ptr = unsafe { BNGetDataBufferSlice(self.0, start, len) };
63+
(!ptr.is_null()).then(|| Self(ptr))
64+
}
65+
66+
/// change the size of the allocated data, if new size is bigger data is
67+
/// need to be initialized
68+
pub unsafe fn set_len(&mut self, len: usize) {
69+
unsafe { BNSetDataBufferLength(self.0, len) }
70+
}
71+
72+
/// set the size to 0
73+
pub fn clear(&self) {
74+
unsafe { BNClearDataBuffer(self.0) }
75+
}
76+
77+
/// Copy the contents of `src` into `dst`
78+
pub fn assign(dst: &mut Self, src: &Self) {
79+
unsafe { BNAssignDataBuffer(dst.0, src.0) }
80+
}
81+
82+
/// Concat the contents of `src` into `dst`
83+
pub fn append(dst: &mut Self, src: &Self) {
84+
unsafe { BNAppendDataBuffer(dst.0, src.0) }
85+
}
86+
87+
/// concat the contents of `data` into self
88+
pub fn append_data(&self, data: &[u8]) {
89+
unsafe { BNAppendDataBufferContents(self.0, data.as_ptr() as *const c_void, data.len()) }
90+
}
91+
92+
/// Return the byte at `offset`
93+
pub unsafe fn byte_at(&self, offset: usize) -> u8 {
94+
unsafe { BNGetDataBufferByte(self.0, offset) }
95+
}
96+
97+
/// Set the value of the byte at `offset`
98+
pub unsafe fn set_byte_at(&mut self, offset: usize, byte: u8) {
99+
unsafe { BNSetDataBufferByte(self.0, offset, byte) }
100+
}
101+
46102
pub fn set_data(&mut self, data: &[u8]) {
47103
unsafe {
48104
BNSetDataBufferContents(
@@ -53,12 +109,48 @@ impl DataBuffer {
53109
}
54110
}
55111

112+
pub fn to_escaped_string(&self, null_terminates: bool) -> BnString {
113+
unsafe { BnString::from_raw(BNDataBufferToEscapedString(self.0, null_terminates)) }
114+
}
115+
116+
pub fn from_escaped_string(value: &BnString) -> Self {
117+
Self(unsafe { BNDecodeEscapedString(value.as_raw()) })
118+
}
119+
120+
pub fn to_base64(&self) -> BnString {
121+
unsafe { BnString::from_raw(BNDataBufferToBase64(self.0)) }
122+
}
123+
124+
pub fn from_base64(value: &BnString) -> Self {
125+
Self(unsafe { BNDecodeBase64(value.as_raw()) })
126+
}
127+
128+
pub fn zlib_compress(&self) -> Self {
129+
Self(unsafe { BNZlibCompress(self.0) })
130+
}
131+
132+
pub fn zlib_decompress(&self) -> Self {
133+
Self(unsafe { BNZlibDecompress(self.0) })
134+
}
135+
136+
pub fn lzma_decompress(&self) -> Self {
137+
Self(unsafe { BNLzmaDecompress(self.0) })
138+
}
139+
140+
pub fn lzma2_decompress(&self) -> Self {
141+
Self(unsafe { BNLzma2Decompress(self.0) })
142+
}
143+
144+
pub fn xz_decompress(&self) -> Self {
145+
Self(unsafe { BNXzDecompress(self.0) })
146+
}
147+
56148
pub fn len(&self) -> usize {
57149
unsafe { BNGetDataBufferLength(self.0) }
58150
}
59151

60152
pub fn is_empty(&self) -> bool {
61-
unsafe { BNGetDataBufferLength(self.0) == 0 }
153+
self.len() == 0
62154
}
63155

64156
pub fn new(data: &[u8]) -> Result<Self, ()> {
@@ -71,19 +163,16 @@ impl DataBuffer {
71163
}
72164
}
73165

74-
// TODO : delete this
75166
impl Default for DataBuffer {
76167
fn default() -> Self {
77-
DataBuffer::from_raw(ptr::null_mut())
168+
Self(unsafe { BNCreateDataBuffer([].as_ptr() as *const c_void, 0) })
78169
}
79170
}
80171

81172
impl Drop for DataBuffer {
82173
fn drop(&mut self) {
83-
if !self.0.is_null() {
84-
unsafe {
85-
BNFreeDataBuffer(self.0);
86-
}
174+
unsafe {
175+
BNFreeDataBuffer(self.0);
87176
}
88177
}
89178
}
@@ -93,3 +182,152 @@ impl Clone for DataBuffer {
93182
Self::from_raw(unsafe { BNDuplicateDataBuffer(self.0) })
94183
}
95184
}
185+
186+
impl TryFrom<&[u8]> for DataBuffer {
187+
type Error = ();
188+
189+
fn try_from(value: &[u8]) -> Result<Self, Self::Error> {
190+
DataBuffer::new(value)
191+
}
192+
}
193+
194+
impl AsRef<[u8]> for DataBuffer {
195+
fn as_ref(&self) -> &[u8] {
196+
self.get_data()
197+
}
198+
}
199+
200+
impl std::borrow::Borrow<[u8]> for DataBuffer {
201+
fn borrow(&self) -> &[u8] {
202+
self.as_ref()
203+
}
204+
}
205+
206+
macro_rules! data_buffer_index {
207+
($range:ty, $output:ty) => {
208+
impl std::ops::Index<$range> for DataBuffer {
209+
type Output = $output;
210+
211+
fn index(&self, index: $range) -> &Self::Output {
212+
&self.get_data()[index]
213+
}
214+
}
215+
};
216+
}
217+
218+
data_buffer_index!(usize, u8);
219+
data_buffer_index!(std::ops::Range<usize>, [u8]);
220+
data_buffer_index!(std::ops::RangeInclusive<usize>, [u8]);
221+
data_buffer_index!(std::ops::RangeTo<usize>, [u8]);
222+
data_buffer_index!(std::ops::RangeFull, [u8]);
223+
224+
impl PartialEq for DataBuffer {
225+
fn eq(&self, other: &Self) -> bool {
226+
self.as_ref() == other.as_ref()
227+
}
228+
}
229+
impl Eq for DataBuffer {}
230+
231+
impl PartialOrd for DataBuffer {
232+
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
233+
Some(self.as_ref().cmp(other.as_ref()))
234+
}
235+
}
236+
237+
impl Ord for DataBuffer {
238+
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
239+
self.as_ref().cmp(other.as_ref())
240+
}
241+
}
242+
243+
#[cfg(test)]
244+
mod test {
245+
use super::DataBuffer;
246+
247+
const DUMMY_DATA_0: &[u8] = b"0123456789\x00\x01\x02\x03\x04\x05\x06\x07\x08\x09\x09\xFF";
248+
const DUMMY_DATA_1: &[u8] = b"qwertyuiopasdfghjkl\xE7zxcvbnm\x00\x01\x00";
249+
250+
#[test]
251+
fn get_slice() {
252+
let data = DataBuffer::new(DUMMY_DATA_0).unwrap();
253+
let slice = data.get_slice(9, 10).unwrap();
254+
assert_eq!(slice.get_data(), &DUMMY_DATA_0[9..19]);
255+
}
256+
257+
#[test]
258+
fn set_len_write() {
259+
let mut data = DataBuffer::default();
260+
assert_eq!(data.get_data(), &[]);
261+
unsafe { data.set_len(DUMMY_DATA_0.len()) };
262+
assert_eq!(data.len(), DUMMY_DATA_0.len());
263+
let mut contents = DUMMY_DATA_0.to_vec();
264+
data.set_data(&contents);
265+
// modify the orinal contents, to make sure DataBuffer copied the data
266+
// and is not using the original pointer
267+
contents.as_mut_slice().fill(0x55);
268+
drop(contents);
269+
assert_eq!(data.get_data(), &DUMMY_DATA_0[..]);
270+
271+
// make sure the new len truncate the original data
272+
unsafe { data.set_len(13) };
273+
assert_eq!(data.get_data(), &DUMMY_DATA_0[..13]);
274+
275+
data.clear();
276+
assert_eq!(data.get_data(), &[]);
277+
}
278+
279+
#[test]
280+
fn assign_append() {
281+
let mut dst = DataBuffer::new(DUMMY_DATA_0).unwrap();
282+
let mut src = DataBuffer::new(DUMMY_DATA_1).unwrap();
283+
DataBuffer::assign(&mut dst, &src);
284+
285+
assert_eq!(dst.get_data(), DUMMY_DATA_1);
286+
assert_eq!(src.get_data(), DUMMY_DATA_1);
287+
// overwrite the src, to make sure that src is copied to dst, and not
288+
// moved into it
289+
src.set_data(DUMMY_DATA_0);
290+
assert_eq!(dst.get_data(), DUMMY_DATA_1);
291+
assert_eq!(src.get_data(), DUMMY_DATA_0);
292+
293+
DataBuffer::append(&mut dst, &src);
294+
let result: Vec<_> = DUMMY_DATA_1.iter().chain(DUMMY_DATA_0).copied().collect();
295+
assert_eq!(dst.get_data(), &result);
296+
297+
assert_eq!(src.get_data(), DUMMY_DATA_0);
298+
src.set_data(DUMMY_DATA_1);
299+
assert_eq!(src.get_data(), DUMMY_DATA_1);
300+
assert_eq!(dst.get_data(), &result);
301+
}
302+
303+
#[test]
304+
fn to_from_formats() {
305+
let data = DataBuffer::new(DUMMY_DATA_0).unwrap();
306+
let escaped = data.to_escaped_string(false);
307+
let unescaped = DataBuffer::from_escaped_string(&escaped);
308+
drop(escaped);
309+
let escaped_part = data.to_escaped_string(true);
310+
let unescaped_part = DataBuffer::from_escaped_string(&escaped_part);
311+
drop(escaped_part);
312+
313+
let part = &DUMMY_DATA_0[0..DUMMY_DATA_0
314+
.iter()
315+
.position(|x| *x == 0)
316+
.unwrap_or(DUMMY_DATA_0.len())];
317+
assert_eq!(data.get_data(), DUMMY_DATA_0);
318+
assert_eq!(unescaped.get_data(), DUMMY_DATA_0);
319+
assert_eq!(unescaped_part.get_data(), part);
320+
321+
let escaped = data.to_base64();
322+
let unescaped = DataBuffer::from_base64(&escaped);
323+
drop(escaped);
324+
assert_eq!(data.get_data(), DUMMY_DATA_0);
325+
assert_eq!(unescaped.get_data(), DUMMY_DATA_0);
326+
327+
let compressed = data.zlib_compress();
328+
let decompressed = compressed.zlib_decompress();
329+
drop(compressed);
330+
assert_eq!(data.get_data(), DUMMY_DATA_0);
331+
assert_eq!(decompressed.get_data(), DUMMY_DATA_0);
332+
}
333+
}

rust/src/string.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,10 @@ impl BnString {
7979
res
8080
}
8181

82+
pub(crate) fn as_raw(&self) -> &raw::c_char {
83+
unsafe { &*self.raw }
84+
}
85+
8286
pub fn as_str(&self) -> &str {
8387
unsafe { CStr::from_ptr(self.raw).to_str().unwrap() }
8488
}

0 commit comments

Comments
 (0)