diff options
| author | Glenn Smith <glenn@vector35.com> | 2022-07-18 19:53:47 -0400 |
|---|---|---|
| committer | Glenn Smith <glenn@vector35.com> | 2022-09-29 21:02:21 -0400 |
| commit | ad27532d344d3bf2995f623002753d2845c6ce20 (patch) | |
| tree | 772db0ae0fc09993fcd3f13f62628cba3414d95b /rust/src/metadata.rs | |
| parent | 90a3729620e85f66b8fa5d385ead21ac581a1cc5 (diff) | |
[Rust API] Add support for Metadata
Diffstat (limited to 'rust/src/metadata.rs')
| -rw-r--r-- | rust/src/metadata.rs | 652 |
1 files changed, 652 insertions, 0 deletions
diff --git a/rust/src/metadata.rs b/rust/src/metadata.rs new file mode 100644 index 00000000..f7d5e45e --- /dev/null +++ b/rust/src/metadata.rs @@ -0,0 +1,652 @@ +#[allow(non_snake_case)] +use crate::rc::{ + Array, CoreArrayProvider, CoreArrayWrapper, CoreOwnedArrayProvider, Guard, Ref, RefCountable, +}; +use crate::string::{BnStrCompatible, BnString}; +use binaryninjacore_sys::*; +use std::collections::HashMap; +use std::convert::TryFrom; +use std::ffi::CStr; +use std::ops::Index; +use std::os::raw::c_char; +use std::slice; + +pub type MetadataType = BNMetadataType; + +pub struct Metadata { + handle: *mut BNMetadata, +} + +impl Metadata { + pub(crate) unsafe fn from_raw(handle: *mut BNMetadata) -> Self { + debug_assert!(!handle.is_null()); + + Self { handle } + } + + pub(crate) unsafe fn ref_from_raw(handle: *mut BNMetadata) -> Ref<Self> { + Ref::new(Self::from_raw(handle)) + } + + pub fn get_type(&self) -> MetadataType { + unsafe { BNMetadataGetType(self.handle) } + } + + pub fn get_boolean(&self) -> Result<bool, ()> { + match self.get_type() { + MetadataType::BooleanDataType => Ok(unsafe { BNMetadataGetBoolean(self.handle) }), + _ => Err(()), + } + } + + pub fn get_unsigned_integer(&self) -> Result<u64, ()> { + match self.get_type() { + MetadataType::UnsignedIntegerDataType => { + Ok(unsafe { BNMetadataGetUnsignedInteger(self.handle) }) + } + _ => Err(()), + } + } + + pub fn get_signed_integer(&self) -> Result<i64, ()> { + match self.get_type() { + MetadataType::SignedIntegerDataType => { + Ok(unsafe { BNMetadataGetSignedInteger(self.handle) }) + } + _ => Err(()), + } + } + + pub fn get_double(&self) -> Result<f64, ()> { + match self.get_type() { + MetadataType::DoubleDataType => Ok(unsafe { BNMetadataGetDouble(self.handle) }), + _ => Err(()), + } + } + + pub fn get_string(&self) -> Result<BnString, ()> { + match self.get_type() { + MetadataType::StringDataType => { + let ptr: *mut c_char = unsafe { BNMetadataGetString(self.handle) }; + if ptr.is_null() { + return Err(()); + } + Ok(unsafe { BnString::from_raw(ptr) }) + } + _ => Err(()), + } + } + + pub fn get_boolean_list(&self) -> Result<Vec<bool>, ()> { + match self.get_type() { + MetadataType::ArrayDataType => { + let mut size: usize = 0; + let ptr: *mut bool = unsafe { BNMetadataGetBooleanList(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + let list = unsafe { slice::from_raw_parts(ptr, size) }; + let vec = Vec::from(list); + unsafe { BNFreeMetadataBooleanList(ptr, size) }; + Ok(vec) + } + _ => Err(()), + } + } + + pub fn get_unsigned_integer_list(&self) -> Result<Vec<u64>, ()> { + match self.get_type() { + MetadataType::ArrayDataType => { + let mut size: usize = 0; + let ptr: *mut u64 = + unsafe { BNMetadataGetUnsignedIntegerList(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + let list = unsafe { slice::from_raw_parts(ptr, size) }; + let vec = Vec::from(list); + unsafe { BNFreeMetadataUnsignedIntegerList(ptr, size) }; + Ok(vec) + } + _ => Err(()), + } + } + + pub fn get_signed_integer_list(&self) -> Result<Vec<i64>, ()> { + match self.get_type() { + MetadataType::ArrayDataType => { + let mut size: usize = 0; + let ptr: *mut i64 = + unsafe { BNMetadataGetSignedIntegerList(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + let list = unsafe { slice::from_raw_parts(ptr, size) }; + let vec = Vec::from(list); + unsafe { BNFreeMetadataSignedIntegerList(ptr, size) }; + Ok(vec) + } + _ => Err(()), + } + } + + pub fn get_double_list(&self) -> Result<Vec<f64>, ()> { + match self.get_type() { + MetadataType::ArrayDataType => { + let mut size: usize = 0; + let ptr: *mut f64 = unsafe { BNMetadataGetDoubleList(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + let list = unsafe { slice::from_raw_parts(ptr, size) }; + let vec = Vec::from(list); + unsafe { BNFreeMetadataDoubleList(ptr, size) }; + Ok(vec) + } + _ => Err(()), + } + } + + pub fn get_string_list(&self) -> Result<Vec<BnString>, ()> { + match self.get_type() { + MetadataType::ArrayDataType => { + let mut size: usize = 0; + let ptr: *mut *mut c_char = + unsafe { BNMetadataGetStringList(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + let list = unsafe { slice::from_raw_parts(ptr, size) }; + let vec = list + .iter() + .map(|ptr| unsafe { BnString::from_raw(*ptr) }) + .collect::<Vec<_>>(); + unsafe { BNFreeMetadataStringList(ptr, size) }; + Ok(vec) + } + _ => Err(()), + } + } + + pub fn get_raw(&self) -> Result<Vec<u8>, ()> { + match self.get_type() { + MetadataType::RawDataType => { + let mut size: usize = 0; + let ptr: *mut u8 = unsafe { BNMetadataGetRaw(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + + let list = unsafe { slice::from_raw_parts(ptr, size) }; + let vec = Vec::from(list); + unsafe { BNFreeMetadataRaw(ptr) }; + Ok(vec) + } + _ => Err(()), + } + } + + pub fn get_array(&self) -> Result<Array<Metadata>, ()> { + match self.get_type() { + MetadataType::ArrayDataType => { + let mut size: usize = 0; + let ptr: *mut *mut BNMetadata = + unsafe { BNMetadataGetArray(self.handle, &mut size) }; + if ptr.is_null() { + return Err(()); + } + + Ok(unsafe { Array::new(ptr, size, ()) }) + } + _ => Err(()), + } + } + + pub fn get_value_store(&self) -> Result<HashMap<BnString, Ref<Metadata>>, ()> { + match self.get_type() { + MetadataType::KeyValueDataType => { + let ptr: *mut BNMetadataValueStore = + unsafe { BNMetadataGetValueStore(self.handle) }; + if ptr.is_null() { + return Err(()); + } + + let size = unsafe { (*ptr).size }; + let keys_ptr: *mut *mut c_char = unsafe { (*ptr).keys }; + let keys = unsafe { slice::from_raw_parts(keys_ptr, size) }; + let values_ptr: *mut *mut BNMetadata = unsafe { (*ptr).values }; + let values: &[*mut BNMetadata] = unsafe { slice::from_raw_parts(values_ptr, size) }; + + let mut map = HashMap::new(); + for i in 0..size { + let key = unsafe { BnString::from_raw(keys[i]) }; + + let value = unsafe { + Ref::<Metadata>::new(Self { + handle: BNNewMetadataReference(values[i]), + }) + }; + map.insert(key, value); + } + + Ok(map) + } + _ => Err(()), + } + } + + pub fn len(&self) -> usize { + unsafe { BNMetadataSize(self.handle) } + } + + pub fn index(&self, index: usize) -> Result<Option<Ref<Metadata>>, ()> { + if self.get_type() != MetadataType::ArrayDataType { + return Err(()); + } + let ptr: *mut BNMetadata = unsafe { BNMetadataGetForIndex(self.handle, index) }; + if ptr.is_null() { + return Ok(None); + } + Ok(Some(unsafe { Self::ref_from_raw(ptr) })) + } + + pub fn get<S: BnStrCompatible>(&self, key: S) -> Result<Option<Ref<Metadata>>, ()> { + if self.get_type() != MetadataType::KeyValueDataType { + return Err(()); + } + let ptr: *mut BNMetadata = unsafe { + BNMetadataGetForKey( + self.handle, + key.as_bytes_with_nul().as_ref().as_ptr() as *const c_char, + ) + }; + if ptr.is_null() { + return Ok(None); + } + Ok(Some(unsafe { Self::ref_from_raw(ptr) })) + } + + pub fn push(&self, value: &Metadata) -> Result<(), ()> { + if self.get_type() != MetadataType::ArrayDataType { + return Err(()); + } + unsafe { BNMetadataArrayAppend(self.handle, value.handle) }; + Ok(()) + } + + pub fn insert<S: BnStrCompatible>(&self, key: S, value: &Metadata) -> Result<(), ()> { + if self.get_type() != MetadataType::KeyValueDataType { + return Err(()); + } + + unsafe { + BNMetadataSetValueForKey( + self.handle, + key.as_bytes_with_nul().as_ref().as_ptr() as *const c_char, + value.handle, + ) + }; + Ok(()) + } + + pub fn remove_index(&self, index: usize) -> Result<(), ()> { + if self.get_type() != MetadataType::ArrayDataType { + return Err(()); + } + + unsafe { BNMetadataRemoveIndex(self.handle, index) }; + Ok(()) + } + + pub fn remove_key<S: BnStrCompatible>(&self, key: S) -> Result<(), ()> { + if self.get_type() != MetadataType::KeyValueDataType { + return Err(()); + } + + unsafe { + BNMetadataRemoveKey( + self.handle, + key.as_bytes_with_nul().as_ref().as_ptr() as *const c_char, + ) + }; + Ok(()) + } +} + +unsafe impl Sync for Metadata {} +unsafe impl Send for Metadata {} + +unsafe impl RefCountable for Metadata { + unsafe fn inc_ref(handle: &Self) -> Ref<Self> { + Ref::new(Self { + handle: BNNewMetadataReference(handle.handle), + }) + } + + unsafe fn dec_ref(handle: &Self) { + BNFreeMetadata(handle.handle); + } +} + +impl CoreArrayProvider for Metadata { + type Raw = *mut BNMetadata; + type Context = (); +} + +unsafe impl CoreOwnedArrayProvider for Metadata { + unsafe fn free(raw: *mut *mut BNMetadata, _count: usize, _context: &()) { + BNFreeMetadataArray(raw); + } +} + +unsafe impl<'a> CoreArrayWrapper<'a> for Metadata { + type Wrapped = Guard<'a, Metadata>; + + unsafe fn wrap_raw(raw: &'a *mut BNMetadata, context: &'a ()) -> Guard<'a, Metadata> { + Guard::new(Metadata::from_raw(*raw), context) + } +} + +impl AsRef<Metadata> for Metadata { + fn as_ref(&self) -> &Self { + self + } +} + +impl ToOwned for Metadata { + type Owned = Ref<Self>; + + fn to_owned(&self) -> Self::Owned { + unsafe { RefCountable::inc_ref(self) } + } +} + +impl From<bool> for Ref<Metadata> { + fn from(value: bool) -> Self { + unsafe { Metadata::ref_from_raw(BNCreateMetadataBooleanData(value)) } + } +} + +impl From<u64> for Ref<Metadata> { + fn from(value: u64) -> Self { + unsafe { Metadata::ref_from_raw(BNCreateMetadataUnsignedIntegerData(value)) } + } +} + +impl From<i64> for Ref<Metadata> { + fn from(value: i64) -> Self { + unsafe { Metadata::ref_from_raw(BNCreateMetadataSignedIntegerData(value)) } + } +} + +impl From<f64> for Ref<Metadata> { + fn from(value: f64) -> Self { + unsafe { Metadata::ref_from_raw(BNCreateMetadataDoubleData(value)) } + } +} + +impl<S: BnStrCompatible> From<S> for Ref<Metadata> { + fn from(value: S) -> Self { + unsafe { + Metadata::ref_from_raw(BNCreateMetadataStringData( + value.as_bytes_with_nul().as_ref().as_ptr() as *const c_char, + )) + } + } +} + +impl From<&Vec<u8>> for Ref<Metadata> { + fn from(value: &Vec<u8>) -> Self { + unsafe { Metadata::ref_from_raw(BNCreateMetadataRawData(value.as_ptr(), value.len())) } + } +} + +impl From<&Vec<Ref<Metadata>>> for Ref<Metadata> { + fn from(value: &Vec<Ref<Metadata>>) -> Self { + let mut pointers: Vec<*mut BNMetadata> = vec![]; + for v in value.iter() { + pointers.push(v.as_ref().handle); + } + unsafe { + Metadata::ref_from_raw(BNCreateMetadataArray(pointers.as_mut_ptr(), pointers.len())) + } + } +} + +impl From<&Array<Metadata>> for Ref<Metadata> { + fn from(value: &Array<Metadata>) -> Self { + let mut pointers: Vec<*mut BNMetadata> = vec![]; + for v in value.iter() { + pointers.push(v.as_ref().handle); + } + unsafe { + Metadata::ref_from_raw(BNCreateMetadataArray(pointers.as_mut_ptr(), pointers.len())) + } + } +} + +impl<S: BnStrCompatible> From<HashMap<S, Ref<Metadata>>> for Ref<Metadata> { + fn from(value: HashMap<S, Ref<Metadata>>) -> Self { + let mut key_refs: Vec<S::Result> = vec![]; + let mut keys: Vec<*const c_char> = vec![]; + let mut values: Vec<*mut BNMetadata> = vec![]; + for (k, v) in value.into_iter() { + key_refs.push(k.as_bytes_with_nul()); + values.push(v.as_ref().handle); + } + for k in &key_refs { + keys.push(k.as_ref().as_ptr() as *const c_char); + } + + unsafe { + Metadata::ref_from_raw(BNCreateMetadataValueStore( + keys.as_mut_ptr(), + values.as_mut_ptr(), + keys.len(), + )) + } + } +} + +impl From<&Vec<bool>> for Ref<Metadata> { + fn from(value: &Vec<bool>) -> Self { + unsafe { + Metadata::ref_from_raw(BNCreateMetadataBooleanListData( + value.as_ptr() as *mut bool, + value.len(), + )) + } + } +} + +impl From<&Vec<u64>> for Ref<Metadata> { + fn from(value: &Vec<u64>) -> Self { + unsafe { + Metadata::ref_from_raw(BNCreateMetadataUnsignedIntegerListData( + value.as_ptr() as *mut u64, + value.len(), + )) + } + } +} + +impl From<&Vec<i64>> for Ref<Metadata> { + fn from(value: &Vec<i64>) -> Self { + unsafe { + Metadata::ref_from_raw(BNCreateMetadataSignedIntegerListData( + value.as_ptr() as *mut i64, + value.len(), + )) + } + } +} + +impl From<&Vec<f64>> for Ref<Metadata> { + fn from(value: &Vec<f64>) -> Self { + unsafe { + Metadata::ref_from_raw(BNCreateMetadataDoubleListData( + value.as_ptr() as *mut f64, + value.len(), + )) + } + } +} + +impl<S: BnStrCompatible> From<Vec<S>> for Ref<Metadata> { + fn from(value: Vec<S>) -> Self { + let mut refs = vec![]; + for v in value { + refs.push(v.as_bytes_with_nul()); + } + let mut pointers = vec![]; + for r in &refs { + pointers.push(r.as_ref().as_ptr() as *const c_char); + } + unsafe { + Metadata::ref_from_raw(BNCreateMetadataStringListData( + pointers.as_ptr() as *mut *const c_char, + pointers.len(), + )) + } + } +} + +impl PartialEq<Self> for Ref<Metadata> { + fn eq(&self, other: &Self) -> bool { + unsafe { BNMetadataIsEqual(self.as_ref().handle, other.as_ref().handle) } + } +} + +impl Eq for Ref<Metadata> {} + +impl TryFrom<&Metadata> for bool { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_boolean() + } +} + +impl TryFrom<&Metadata> for u64 { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_unsigned_integer() + } +} + +impl TryFrom<&Metadata> for i64 { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_signed_integer() + } +} + +impl TryFrom<&Metadata> for f64 { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_double() + } +} + +impl TryFrom<&Metadata> for BnString { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_string() + } +} + +impl TryFrom<&Metadata> for String { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_string().map(|s| s.to_string()) + } +} + +impl TryFrom<&Metadata> for Vec<bool> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_boolean_list() + } +} + +impl TryFrom<&Metadata> for Vec<u64> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_unsigned_integer_list() + } +} + +impl TryFrom<&Metadata> for Vec<i64> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_signed_integer_list() + } +} + +impl TryFrom<&Metadata> for Vec<f64> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_double_list() + } +} + +impl TryFrom<&Metadata> for Vec<BnString> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_string_list() + } +} + +impl TryFrom<&Metadata> for Vec<String> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value + .get_string_list() + .map(|v| v.into_iter().map(|s| s.to_string()).collect()) + } +} + +impl TryFrom<&Metadata> for Vec<u8> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_raw() + } +} + +impl TryFrom<&Metadata> for Array<Metadata> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_array() + } +} + +impl TryFrom<&Metadata> for HashMap<BnString, Ref<Metadata>> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value.get_value_store() + } +} + +impl TryFrom<&Metadata> for HashMap<String, Ref<Metadata>> { + type Error = (); + + fn try_from(value: &Metadata) -> Result<Self, Self::Error> { + value + .get_value_store() + .map(|m| m.into_iter().map(|(k, v)| (k.to_string(), v)).collect()) + } +} |
