use std::borrow::Cow;
use std::ffi::{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;
pub(crate) fn raw_to_string(ptr: *const raw::c_char) -> Option<String> {
if ptr.is_null() {
None
} else {
Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
}
}
#[repr(transparent)]
pub struct BnString {
raw: *mut raw::c_char,
}
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),
}
}
}
pub(crate) unsafe fn from_raw(raw: *mut raw::c_char) -> Self {
Self { raw }
}
pub(crate) fn into_raw(self) -> *mut raw::c_char {
let res = self.raw;
mem::forget(self);
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() }
}
pub fn as_bytes(&self) -> &[u8] {
self.as_str().as_bytes()
}
pub fn as_bytes_with_null(&self) -> &[u8] {
self.deref().to_bytes()
}
pub fn len(&self) -> usize {
self.as_ref().len()
}
pub fn is_empty(&self) -> bool {
self.as_ref().is_empty()
}
}
impl Drop for BnString {
fn drop(&mut self) {
use binaryninjacore_sys::BNFreeString;
unsafe {
BNFreeString(self.raw);
}
}
}
impl Clone for BnString {
fn clone(&self) -> Self {
use binaryninjacore_sys::BNAllocString;
unsafe {
Self {
raw: BNAllocString(self.raw),
}
}
}
}
impl Deref for BnString {
type Target = CStr;
fn deref(&self) -> &CStr {
unsafe { CStr::from_ptr(self.raw) }
}
}
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::Display for BnString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_string_lossy())
}
}
impl fmt::Debug for BnString {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
write!(f, "{}", self.to_string_lossy())
}
}
impl CoreArrayProvider for BnString {
type Raw = *mut raw::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) {
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()
}
}
pub unsafe trait BnStrCompatible {
type Result: AsRef<[u8]>;
fn into_bytes_with_nul(self) -> Self::Result;
}
unsafe impl<'a> BnStrCompatible for &'a CStr {
type Result = &'a [u8];
fn into_bytes_with_nul(self) -> Self::Result {
self.to_bytes_with_nul()
}
}
unsafe impl BnStrCompatible for BnString {
type Result = Self;
fn into_bytes_with_nul(self) -> Self::Result {
self
}
}
unsafe impl BnStrCompatible for CString {
type Result = Vec<u8>;
fn into_bytes_with_nul(self) -> Self::Result {
self.into_bytes_with_nul()
}
}
unsafe impl<'a> BnStrCompatible for &'a str {
type Result = Vec<u8>;
fn into_bytes_with_nul(self) -> Self::Result {
let ret = CString::new(self).expect("can't pass strings with internal nul bytes to core!");
ret.into_bytes_with_nul()
}
}
unsafe impl BnStrCompatible for String {
type Result = Vec<u8>;
fn into_bytes_with_nul(self) -> Self::Result {
self.as_str().into_bytes_with_nul()
}
}
unsafe impl<'a> BnStrCompatible for &'a String {
type Result = Vec<u8>;
fn into_bytes_with_nul(self) -> Self::Result {
self.as_str().into_bytes_with_nul()
}
}
unsafe impl<'a> BnStrCompatible for &'a Cow<'a, 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()
}
}
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)
}
}