1use binaryninjacore_sys::*;
18use std::borrow::Cow;
19use std::ffi::{c_char, CStr, CString};
20use std::fmt;
21use std::hash::{Hash, Hasher};
22use std::mem;
23use std::ops::Deref;
24use std::path::{Path, PathBuf};
25
26use crate::rc::*;
27use crate::types::QualifiedName;
28
29pub(crate) fn raw_to_string(ptr: *const c_char) -> Option<String> {
31 if ptr.is_null() {
32 None
33 } else {
34 Some(unsafe { CStr::from_ptr(ptr).to_string_lossy().into_owned() })
35 }
36}
37
38pub fn strings_to_string_list<I, S>(strings: I) -> *mut *mut c_char
39where
40 I: IntoIterator<Item = S>,
41 S: AsRef<str>,
43{
44 use binaryninjacore_sys::BNAllocStringList;
45 let bn_str_list = strings
46 .into_iter()
47 .map(|s| BnString::new(s.as_ref()))
48 .collect::<Vec<_>>();
49 let mut raw_str_list = bn_str_list.iter().map(|s| s.as_ptr()).collect::<Vec<_>>();
50 unsafe { BNAllocStringList(raw_str_list.as_mut_ptr(), raw_str_list.len()) }
51}
52
53#[repr(transparent)]
65pub struct BnString {
66 raw: *mut c_char,
67}
68
69impl BnString {
70 pub fn new(s: impl IntoCStr) -> Self {
71 let raw = s.to_cstr();
72 unsafe { Self::from_raw(BNAllocString(raw.as_ptr())) }
73 }
74
75 pub unsafe fn into_string(raw: *mut c_char) -> String {
79 Self::from_raw(raw).to_string_lossy().to_string()
80 }
81
82 pub(crate) unsafe fn from_raw(raw: *mut c_char) -> Self {
84 Self { raw }
85 }
86
87 pub unsafe fn free_raw(raw: *mut c_char) {
89 if !raw.is_null() {
90 BNFreeString(raw);
91 }
92 }
93
94 pub fn into_raw(value: Self) -> *mut c_char {
101 let res = value.raw;
102 mem::forget(value);
105 res
106 }
107}
108
109impl Drop for BnString {
110 fn drop(&mut self) {
111 unsafe { BnString::free_raw(self.raw) };
112 }
113}
114
115impl Clone for BnString {
116 fn clone(&self) -> Self {
117 unsafe {
118 Self {
119 raw: BNAllocString(self.raw),
120 }
121 }
122 }
123}
124
125impl Deref for BnString {
126 type Target = CStr;
127
128 fn deref(&self) -> &CStr {
129 unsafe { CStr::from_ptr(self.raw) }
130 }
131}
132
133impl From<String> for BnString {
134 fn from(s: String) -> Self {
135 Self::new(s)
136 }
137}
138
139impl From<&str> for BnString {
140 fn from(s: &str) -> Self {
141 Self::new(s)
142 }
143}
144
145impl AsRef<[u8]> for BnString {
146 fn as_ref(&self) -> &[u8] {
147 self.to_bytes_with_nul()
148 }
149}
150
151impl Hash for BnString {
152 fn hash<H: Hasher>(&self, state: &mut H) {
153 self.raw.hash(state)
154 }
155}
156
157impl PartialEq for BnString {
158 fn eq(&self, other: &Self) -> bool {
159 self.deref() == other.deref()
160 }
161}
162
163impl Eq for BnString {}
164
165impl fmt::Debug for BnString {
166 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
167 self.to_string_lossy().fmt(f)
168 }
169}
170
171impl CoreArrayProvider for BnString {
172 type Raw = *mut c_char;
173 type Context = ();
174 type Wrapped<'a> = &'a str;
175}
176
177unsafe impl CoreArrayProviderInner for BnString {
178 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
179 BNFreeStringList(raw, count);
180 }
181
182 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, _context: &'a Self::Context) -> Self::Wrapped<'a> {
183 CStr::from_ptr(*raw).to_str().unwrap()
184 }
185}
186
187pub trait IntoCStr {
188 type Result: Deref<Target = CStr>;
189
190 fn to_cstr(self) -> Self::Result;
191}
192
193impl IntoCStr for &CStr {
194 type Result = Self;
195
196 fn to_cstr(self) -> Self::Result {
197 self
198 }
199}
200
201impl IntoCStr for BnString {
202 type Result = Self;
203
204 fn to_cstr(self) -> Self::Result {
205 self
206 }
207}
208
209impl IntoCStr for &BnString {
210 type Result = BnString;
211
212 fn to_cstr(self) -> Self::Result {
213 self.clone()
214 }
215}
216
217impl IntoCStr for CString {
218 type Result = Self;
219
220 fn to_cstr(self) -> Self::Result {
221 self
222 }
223}
224
225impl IntoCStr for &str {
226 type Result = CString;
227
228 fn to_cstr(self) -> Self::Result {
229 CString::new(self).expect("can't pass strings with internal nul bytes to core!")
230 }
231}
232
233impl IntoCStr for String {
234 type Result = CString;
235
236 fn to_cstr(self) -> Self::Result {
237 CString::new(self).expect("can't pass strings with internal nul bytes to core!")
238 }
239}
240
241impl IntoCStr for &String {
242 type Result = CString;
243
244 fn to_cstr(self) -> Self::Result {
245 self.clone().to_cstr()
246 }
247}
248
249impl<'a> IntoCStr for &'a Cow<'a, str> {
250 type Result = CString;
251
252 fn to_cstr(self) -> Self::Result {
253 self.to_string().to_cstr()
254 }
255}
256
257impl IntoCStr for Cow<'_, str> {
258 type Result = CString;
259
260 fn to_cstr(self) -> Self::Result {
261 self.to_string().to_cstr()
262 }
263}
264
265impl IntoCStr for &QualifiedName {
266 type Result = CString;
267
268 fn to_cstr(self) -> Self::Result {
269 self.to_string().to_cstr()
270 }
271}
272
273impl IntoCStr for PathBuf {
274 type Result = CString;
275
276 fn to_cstr(self) -> Self::Result {
277 self.as_path().to_cstr()
278 }
279}
280
281impl IntoCStr for &Path {
282 type Result = CString;
283
284 fn to_cstr(self) -> Self::Result {
285 CString::new(self.as_os_str().as_encoded_bytes())
286 .expect("can't pass paths with internal nul bytes to core!")
287 }
288}
289
290pub trait IntoJson {
291 type Output: IntoCStr;
292
293 fn get_json_string(self) -> Result<Self::Output, ()>;
294}
295
296impl<S: IntoCStr> IntoJson for S {
297 type Output = S;
298
299 fn get_json_string(self) -> Result<Self::Output, ()> {
300 Ok(self)
301 }
302}