use binaryninjacore_sys::*;
use std::borrow::Cow;
use std::ffi::{c_char, CStr, CString};
use std::fmt;
use std::hash::{Hash, Hasher};
use std::mem;
use std::ops::Deref;
use std::path::{Path, PathBuf};
use crate::rc::*;
use crate::type_archive::TypeArchiveSnapshotId;
use crate::types::QualifiedName;
pub(crate) fn raw_to_string(ptr: *const c_char) -> Option<String> {
if ptr.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
}
}
pub(crate) fn strings_to_string_list<I, S>(strings: I) -> *mut *mut c_char
where
I: IntoIterator<Item = S>,
S: AsRef<str>,
{
use binaryninjacore_sys::BNAllocStringList;
let bn_str_list = strings
.into_iter()
.map(|s| BnString::new(s.as_ref()))
.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()) }
}
#[repr(transparent)]
pub struct BnString {
raw: *mut c_char,
}
impl BnString {
pub fn new(s: impl IntoCStr) -> Self {
let raw = s.to_cstr();
unsafe { Self::from_raw(BNAllocString(raw.as_ptr())) }
}
pub unsafe fn into_string(raw: *mut c_char) -> String {
Self::from_raw(raw).to_string_lossy().to_string()
}
pub(crate) unsafe fn from_raw(raw: *mut c_char) -> Self {
Self { raw }
}
pub(crate) unsafe fn free_raw(raw: *mut c_char) {
if !raw.is_null() {
BNFreeString(raw);
}
}
pub fn into_raw(value: Self) -> *mut c_char {
let res = value.raw;
mem::forget(value);
res
}
}
impl Drop for BnString {
fn drop(&mut self) {
unsafe { BnString::free_raw(self.raw) };
}
}
impl Clone for BnString {
fn clone(&self) -> Self {
unsafe {
Self {
raw: BNAllocString(self.raw),
}
}
}
}
impl Deref for BnString {
type Target = CStr;
fn deref(&self) -> &CStr {
unsafe { CStr::from_ptr(self.raw) }
}
}
impl From<String> for BnString {
fn from(s: String) -> Self {
Self::new(s)
}
}
impl From<&str> for BnString {
fn from(s: &str) -> Self {
Self::new(s)
}
}
impl AsRef<[u8]> for BnString {
fn as_ref(&self) -> &[u8] {
self.to_bytes_with_nul()
}
}
impl Hash for BnString {
fn hash<H: Hasher>(&self, state: &mut H) {
self.raw.hash(state)
}
}
impl PartialEq for BnString {
fn eq(&self, other: &Self) -> bool {
self.deref() == other.deref()
}
}
impl Eq for BnString {}
impl fmt::Debug for BnString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.to_string_lossy().fmt(f)
}
}
impl CoreArrayProvider for BnString {
type Raw = *mut c_char;
type Context = ();
type Wrapped<'a> = &'a str;
}
unsafe impl CoreArrayProviderInner for BnString {
unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
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()
}
}
pub trait IntoCStr {
type Result: Deref<Target = CStr>;
fn to_cstr(self) -> Self::Result;
}
impl IntoCStr for &CStr {
type Result = Self;
fn to_cstr(self) -> Self::Result {
self
}
}
impl IntoCStr for BnString {
type Result = Self;
fn to_cstr(self) -> Self::Result {
self
}
}
impl IntoCStr for &BnString {
type Result = BnString;
fn to_cstr(self) -> Self::Result {
self.clone()
}
}
impl IntoCStr for CString {
type Result = Self;
fn to_cstr(self) -> Self::Result {
self
}
}
impl IntoCStr for &str {
type Result = CString;
fn to_cstr(self) -> Self::Result {
CString::new(self).expect("can't pass strings with internal nul bytes to core!")
}
}
impl IntoCStr for String {
type Result = CString;
fn to_cstr(self) -> Self::Result {
CString::new(self).expect("can't pass strings with internal nul bytes to core!")
}
}
impl IntoCStr for &String {
type Result = CString;
fn to_cstr(self) -> Self::Result {
self.clone().to_cstr()
}
}
impl<'a> IntoCStr for &'a Cow<'a, str> {
type Result = CString;
fn to_cstr(self) -> Self::Result {
self.to_string().to_cstr()
}
}
impl IntoCStr for Cow<'_, str> {
type Result = CString;
fn to_cstr(self) -> Self::Result {
self.to_string().to_cstr()
}
}
impl IntoCStr for &QualifiedName {
type Result = CString;
fn to_cstr(self) -> Self::Result {
self.to_string().to_cstr()
}
}
impl IntoCStr for PathBuf {
type Result = CString;
fn to_cstr(self) -> Self::Result {
self.as_path().to_cstr()
}
}
impl IntoCStr for &Path {
type Result = CString;
fn to_cstr(self) -> Self::Result {
CString::new(self.as_os_str().as_encoded_bytes())
.expect("can't pass paths with internal nul bytes to core!")
}
}
impl IntoCStr for TypeArchiveSnapshotId {
type Result = CString;
fn to_cstr(self) -> Self::Result {
self.to_string().to_cstr()
}
}
pub trait IntoJson {
type Output: IntoCStr;
fn get_json_string(self) -> Result<Self::Output, ()>;
}
impl<S: IntoCStr> IntoJson for S {
type Output = S;
fn get_json_string(self) -> Result<Self::Output, ()> {
Ok(self)
}
}