diff options
Diffstat (limited to 'rust/src/string.rs')
| -rw-r--r-- | rust/src/string.rs | 92 |
1 files changed, 62 insertions, 30 deletions
diff --git a/rust/src/string.rs b/rust/src/string.rs index bfb998d5..dde8f550 100644 --- a/rust/src/string.rs +++ b/rust/src/string.rs @@ -14,18 +14,18 @@ //! String wrappers for core-owned strings and strings being passed to the core +use crate::rc::*; +use crate::types::QualifiedName; use std::borrow::Cow; -use std::ffi::{CStr, CString}; +use std::ffi::{c_char, CStr, CString}; use std::fmt; use std::hash::{Hash, Hasher}; use std::mem; use std::ops::Deref; -use std::os::raw; - -use crate::rc::*; -use crate::types::QualifiedName; +use std::path::{Path, PathBuf}; -pub(crate) fn raw_to_string(ptr: *const raw::c_char) -> Option<String> { +// TODO: Remove or refactor this. +pub(crate) fn raw_to_string(ptr: *const c_char) -> Option<String> { if ptr.is_null() { None } else { @@ -33,11 +33,21 @@ pub(crate) fn raw_to_string(ptr: *const raw::c_char) -> Option<String> { } } -/// Is the quivalent of `core::ffi::CString` but using the allocation and free -/// functions provided by binaryninja_sys. +// TODO: Make this pass in an iterator over something more generic... +pub(crate) fn strings_to_string_list(strings: &[String]) -> *mut *mut c_char { + use binaryninjacore_sys::BNAllocStringList; + let bn_str_list = strings + .iter() + .map(|s| BnString::new(s.as_str())) + .collect::<Vec<_>>(); + let mut raw_str_list = bn_str_list.iter().map(|s| s.as_ptr()).collect::<Vec<_>>(); + unsafe { BNAllocStringList(raw_str_list.as_mut_ptr(), raw_str_list.len()) } +} + +/// Is the equivalent of `core::ffi::CString` but using the alloc and free from `binaryninjacore-sys`. #[repr(transparent)] pub struct BnString { - raw: *mut raw::c_char, + raw: *mut c_char, } /// A nul-terminated C string allocated by the core. @@ -52,37 +62,32 @@ pub struct BnString { impl BnString { pub fn new<S: BnStrCompatible>(s: S) -> Self { use binaryninjacore_sys::BNAllocString; - let raw = s.into_bytes_with_nul(); - unsafe { let ptr = raw.as_ref().as_ptr() as *mut _; - - Self { - raw: BNAllocString(ptr), - } + Self::from_raw(BNAllocString(ptr)) } } /// Construct a BnString from an owned const char* allocated by BNAllocString - pub(crate) unsafe fn from_raw(raw: *mut raw::c_char) -> Self { + pub(crate) unsafe fn from_raw(raw: *mut c_char) -> Self { Self { raw } } - pub(crate) fn into_raw(self) -> *mut raw::c_char { - let res = self.raw; - + /// Consumes the `BnString`, returning a raw pointer to the string. + /// + /// After calling this function, the caller is responsible for the + /// memory previously managed by the `BnString`. + /// + /// This is typically used to pass a string back through the core where the core is expected to free. + pub fn into_raw(value: Self) -> *mut c_char { + let res = value.raw; // we're surrendering ownership over the *mut c_char to // the core, so ensure we don't free it - mem::forget(self); - + mem::forget(value); res } - pub(crate) fn as_raw(&self) -> &raw::c_char { - unsafe { &*self.raw } - } - pub fn as_str(&self) -> &str { unsafe { CStr::from_ptr(self.raw).to_str().unwrap() } } @@ -107,7 +112,6 @@ impl BnString { impl Drop for BnString { fn drop(&mut self) { use binaryninjacore_sys::BNFreeString; - unsafe { BNFreeString(self.raw); } @@ -166,7 +170,7 @@ impl fmt::Debug for BnString { } impl CoreArrayProvider for BnString { - type Raw = *mut raw::c_char; + type Raw = *mut c_char; type Context = (); type Wrapped<'a> = &'a str; } @@ -176,6 +180,7 @@ unsafe impl CoreArrayProviderInner for BnString { use binaryninjacore_sys::BNFreeStringList; BNFreeStringList(raw, count); } + unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> { CStr::from_ptr(*raw).to_str().unwrap() } @@ -183,6 +188,7 @@ unsafe impl CoreArrayProviderInner for BnString { pub unsafe trait BnStrCompatible { type Result: AsRef<[u8]>; + fn into_bytes_with_nul(self) -> Self::Result; } @@ -210,7 +216,7 @@ unsafe impl BnStrCompatible for CString { } } -unsafe impl<'a> BnStrCompatible for &'a str { +unsafe impl BnStrCompatible for &str { type Result = Vec<u8>; fn into_bytes_with_nul(self) -> Self::Result { @@ -227,7 +233,7 @@ unsafe impl BnStrCompatible for String { } } -unsafe impl<'a> BnStrCompatible for &'a String { +unsafe impl BnStrCompatible for &String { type Result = Vec<u8>; fn into_bytes_with_nul(self) -> Self::Result { @@ -243,21 +249,47 @@ unsafe impl<'a> BnStrCompatible for &'a Cow<'a, str> { } } +unsafe impl BnStrCompatible for Cow<'_, str> { + type Result = Vec<u8>; + + fn into_bytes_with_nul(self) -> Self::Result { + self.to_string().into_bytes_with_nul() + } +} + unsafe impl BnStrCompatible for &QualifiedName { type Result = Vec<u8>; fn into_bytes_with_nul(self) -> Self::Result { - self.string().into_bytes_with_nul() + self.to_string().into_bytes_with_nul() + } +} + +unsafe impl BnStrCompatible for PathBuf { + type Result = Vec<u8>; + + fn into_bytes_with_nul(self) -> Self::Result { + self.as_path().into_bytes_with_nul() + } +} + +unsafe impl BnStrCompatible for &Path { + type Result = Vec<u8>; + + fn into_bytes_with_nul(self) -> Self::Result { + self.as_os_str().as_encoded_bytes().to_vec() } } pub trait IntoJson { type Output: BnStrCompatible; + fn get_json_string(self) -> Result<Self::Output, ()>; } impl<S: BnStrCompatible> IntoJson for S { type Output = S; + fn get_json_string(self) -> Result<Self::Output, ()> { Ok(self) } |
