use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
use crate::string::{BnStrCompatible, BnString, IntoJson};
use binaryninjacore_sys::*;
use std::collections::HashMap;
use std::os::raw::c_char;
use std::slice;
pub type MetadataType = BNMetadataType;
pub struct Metadata {
pub(crate) 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 new_of_type(metadata_type: MetadataType) -> Ref<Self> {
unsafe { Self::ref_from_raw(BNCreateMetadataOfType(metadata_type)) }
}
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_json_string(&self) -> Result<BnString, ()> {
match self.get_type() {
MetadataType::StringDataType => {
let ptr: *mut c_char = unsafe { BNMetadataGetJsonString(self.handle) };
if ptr.is_null() {
return Err(());
}
Ok(unsafe { BnString::from_raw(ptr) })
}
_ => 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 is_empty(&self) -> bool {
unsafe { BNMetadataSize(self.handle) == 0 }
}
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.into_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.into_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.into_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 = ();
type Wrapped<'a> = Guard<'a, Metadata>;
}
unsafe impl CoreArrayProviderInner for Metadata {
unsafe fn free(raw: *mut *mut BNMetadata, _count: usize, _context: &()) {
BNFreeMetadataArray(raw);
}
unsafe fn wrap_raw<'a>(raw: &'a *mut BNMetadata, context: &'a ()) -> Self::Wrapped<'a> {
Guard::new(Metadata::from_raw(*raw), context)
}
}
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 From<String> for Ref<Metadata> {
fn from(value: String) -> Self {
unsafe {
Metadata::ref_from_raw(BNCreateMetadataStringData(
value.into_bytes_with_nul().as_ptr() as *const c_char,
))
}
}
}
impl From<&str> for Ref<Metadata> {
fn from(value: &str) -> Self {
unsafe {
Metadata::ref_from_raw(BNCreateMetadataStringData(
value.into_bytes_with_nul().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 data: Vec<(S::Result, Ref<Metadata>)> = value
.into_iter()
.map(|(k, v)| (k.into_bytes_with_nul(), v))
.collect();
let mut keys: Vec<*const c_char> = data
.iter()
.map(|(k, _)| k.as_ref().as_ptr() as *const c_char)
.collect();
let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect();
unsafe {
Metadata::ref_from_raw(BNCreateMetadataValueStore(
keys.as_mut_ptr(),
values.as_mut_ptr(),
keys.len(),
))
}
}
}
impl<S, T> From<&[(S, T)]> for Ref<Metadata>
where
S: BnStrCompatible + Copy,
for<'a> &'a T: Into<Ref<Metadata>>,
{
fn from(value: &[(S, T)]) -> Self {
let data: Vec<(S::Result, Ref<Metadata>)> = value
.iter()
.map(|(k, v)| (k.into_bytes_with_nul(), v.into()))
.collect();
let mut keys: Vec<*const c_char> = data
.iter()
.map(|(k, _)| k.as_ref().as_ptr() as *const c_char)
.collect();
let mut values: Vec<*mut BNMetadata> = data.iter().map(|(_, v)| v.handle).collect();
unsafe {
Metadata::ref_from_raw(BNCreateMetadataValueStore(
keys.as_mut_ptr(),
values.as_mut_ptr(),
keys.len(),
))
}
}
}
impl<S, T, const N: usize> From<[(S, T); N]> for Ref<Metadata>
where
S: BnStrCompatible + Copy,
for<'a> &'a T: Into<Ref<Metadata>>,
{
fn from(value: [(S, T); N]) -> Self {
let slice = &value[..];
slice.into()
}
}
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.into_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 for Metadata {
fn eq(&self, other: &Self) -> bool {
unsafe { BNMetadataIsEqual(self.handle, other.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())
}
}
impl IntoJson for &Metadata {
type Output = BnString;
fn get_json_string(self) -> Result<BnString, ()> {
Metadata::get_json_string(self)
}
}
impl IntoJson for Ref<Metadata> {
type Output = BnString;
fn get_json_string(self) -> Result<BnString, ()> {
Metadata::get_json_string(&self)
}
}