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