1use crate::platform::Platform;
12use crate::progress::{NoProgressCallback, ProgressCallback};
13use crate::rc::{Array, Ref};
14use crate::string::{raw_to_string, BnString, IntoCStr};
15use crate::type_parser::{TypeParserError, TypeParserResult};
16use crate::types::{QualifiedName, QualifiedNameAndType, Type};
17use binaryninjacore_sys::*;
18use std::collections::HashMap;
19use std::ffi::{c_char, c_void};
20use std::fmt::{Debug, Formatter};
21use std::ptr::NonNull;
22
23pub type TypeContainerType = BNTypeContainerType;
24
25#[repr(transparent)]
28pub struct TypeContainer {
29 pub handle: NonNull<BNTypeContainer>,
30}
31
32impl TypeContainer {
33 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeContainer>) -> Self {
34 let cloned_ptr = NonNull::new(BNDuplicateTypeContainer(handle.as_ptr()));
40 Self {
41 handle: cloned_ptr.unwrap(),
42 }
43 }
44
45 pub fn empty() -> TypeContainer {
47 let result = unsafe { BNGetEmptyTypeContainer() };
48 unsafe { Self::from_raw(NonNull::new(result).unwrap()) }
49 }
50
51 pub fn id(&self) -> String {
54 let result = unsafe { BNTypeContainerGetId(self.handle.as_ptr()) };
55 assert!(!result.is_null());
56 unsafe { BnString::into_string(result) }
57 }
58
59 pub fn name(&self) -> String {
61 let result = unsafe { BNTypeContainerGetName(self.handle.as_ptr()) };
62 assert!(!result.is_null());
63 unsafe { BnString::into_string(result) }
64 }
65
66 pub fn container_type(&self) -> TypeContainerType {
68 unsafe { BNTypeContainerGetType(self.handle.as_ptr()) }
69 }
70
71 pub fn is_mutable(&self) -> bool {
73 unsafe { BNTypeContainerIsMutable(self.handle.as_ptr()) }
74 }
75
76 pub fn platform(&self) -> Ref<Platform> {
79 let result = unsafe { BNTypeContainerGetPlatform(self.handle.as_ptr()) };
80 assert!(!result.is_null());
81 unsafe { Platform::ref_from_raw(result) }
82 }
83
84 pub fn add_types<I, T>(&self, types: I) -> bool
89 where
90 I: IntoIterator<Item = T>,
91 T: Into<QualifiedNameAndType>,
92 {
93 self.add_types_with_progress(types, NoProgressCallback)
94 }
95
96 pub fn add_types_with_progress<I, T, P>(&self, types: I, mut progress: P) -> bool
97 where
98 I: IntoIterator<Item = T>,
99 T: Into<QualifiedNameAndType>,
100 P: ProgressCallback,
101 {
102 let (raw_names, mut raw_types): (Vec<BNQualifiedName>, Vec<_>) = types
104 .into_iter()
105 .map(|t| {
106 let t = t.into();
107 (
109 QualifiedName::into_raw(t.name),
110 unsafe { Ref::into_raw(t.ty) }.handle,
111 )
112 })
113 .unzip();
114
115 let mut result_names = std::ptr::null_mut();
116 let mut result_ids = std::ptr::null_mut();
117 let mut result_count = 0;
118
119 let success = unsafe {
120 BNTypeContainerAddTypes(
121 self.handle.as_ptr(),
122 raw_names.as_ptr(),
123 raw_types.as_mut_ptr(),
124 raw_types.len(),
125 Some(P::cb_progress_callback),
126 &mut progress as *mut P as *mut c_void,
127 &mut result_names,
128 &mut result_ids,
129 &mut result_count,
130 )
131 };
132
133 for name in raw_names {
134 QualifiedName::free_raw(name);
135 }
136 for ty in raw_types {
137 let _ = unsafe { Type::ref_from_raw(ty) };
138 }
139 success
140 }
141
142 pub fn rename_type<T: Into<QualifiedName>>(&self, name: T, type_id: &str) -> bool {
147 let type_id = type_id.to_cstr();
148 let raw_name = QualifiedName::into_raw(name.into());
149 let success =
150 unsafe { BNTypeContainerRenameType(self.handle.as_ptr(), type_id.as_ptr(), &raw_name) };
151 QualifiedName::free_raw(raw_name);
152 success
153 }
154
155 pub fn delete_type(&self, type_id: &str) -> bool {
160 let type_id = type_id.to_cstr();
161 unsafe { BNTypeContainerDeleteType(self.handle.as_ptr(), type_id.as_ptr()) }
162 }
163
164 pub fn type_id<T: Into<QualifiedName>>(&self, name: T) -> Option<String> {
168 let mut result = std::ptr::null_mut();
169 let raw_name = QualifiedName::into_raw(name.into());
170 let success =
171 unsafe { BNTypeContainerGetTypeId(self.handle.as_ptr(), &raw_name, &mut result) };
172 QualifiedName::free_raw(raw_name);
173 success.then(|| unsafe { BnString::into_string(result) })
174 }
175
176 pub fn type_name(&self, type_id: &str) -> Option<QualifiedName> {
180 let type_id = type_id.to_cstr();
181 let mut result = BNQualifiedName::default();
182 let success = unsafe {
183 BNTypeContainerGetTypeName(self.handle.as_ptr(), type_id.as_ptr(), &mut result)
184 };
185 success.then(|| QualifiedName::from_owned_raw(result))
186 }
187
188 pub fn type_by_id(&self, type_id: &str) -> Option<Ref<Type>> {
192 let type_id = type_id.to_cstr();
193 let mut result = std::ptr::null_mut();
194 let success = unsafe {
195 BNTypeContainerGetTypeById(self.handle.as_ptr(), type_id.as_ptr(), &mut result)
196 };
197 success.then(|| unsafe { Type::ref_from_raw(result) })
198 }
199
200 pub fn type_by_name<T: Into<QualifiedName>>(&self, name: T) -> Option<Ref<Type>> {
204 let mut result = std::ptr::null_mut();
205 let raw_name = QualifiedName::into_raw(name.into());
206 let success =
207 unsafe { BNTypeContainerGetTypeByName(self.handle.as_ptr(), &raw_name, &mut result) };
208 QualifiedName::free_raw(raw_name);
209 success.then(|| unsafe { Type::ref_from_raw(result) })
210 }
211
212 pub fn types(&self) -> Option<HashMap<String, (QualifiedName, Ref<Type>)>> {
214 let mut type_ids = std::ptr::null_mut();
215 let mut type_names = std::ptr::null_mut();
216 let mut type_types = std::ptr::null_mut();
217 let mut type_count = 0;
218 let success = unsafe {
219 BNTypeContainerGetTypes(
220 self.handle.as_ptr(),
221 &mut type_ids,
222 &mut type_names,
223 &mut type_types,
224 &mut type_count,
225 )
226 };
227 success.then(|| unsafe {
228 let raw_ids = std::slice::from_raw_parts(type_ids, type_count);
229 let raw_names = std::slice::from_raw_parts(type_names, type_count);
230 let raw_types = std::slice::from_raw_parts(type_types, type_count);
231 let mut map = HashMap::new();
232 for (idx, raw_id) in raw_ids.iter().enumerate() {
233 let id = raw_to_string(*raw_id).expect("Valid string");
234 let name = QualifiedName::from_raw(&raw_names[idx]);
236 let ty = Type::from_raw(raw_types[idx]).to_owned();
238 map.insert(id, (name, ty));
239 }
240 BNFreeStringList(type_ids, type_count);
241 BNFreeTypeNameList(type_names, type_count);
242 BNFreeTypeList(type_types, type_count);
243 map
244 })
245 }
246
247 pub fn type_ids(&self) -> Option<Array<BnString>> {
249 let mut type_ids = std::ptr::null_mut();
250 let mut type_count = 0;
251 let success = unsafe {
252 BNTypeContainerGetTypeIds(self.handle.as_ptr(), &mut type_ids, &mut type_count)
253 };
254 success.then(|| unsafe { Array::new(type_ids, type_count, ()) })
255 }
256
257 pub fn type_names(&self) -> Option<Array<QualifiedName>> {
259 let mut type_ids = std::ptr::null_mut();
260 let mut type_count = 0;
261 let success = unsafe {
262 BNTypeContainerGetTypeNames(self.handle.as_ptr(), &mut type_ids, &mut type_count)
263 };
264 success.then(|| unsafe { Array::new(type_ids, type_count, ()) })
265 }
266
267 pub fn type_names_and_ids(&self) -> Option<(Array<BnString>, Array<QualifiedName>)> {
269 let mut type_ids = std::ptr::null_mut();
270 let mut type_names = std::ptr::null_mut();
271 let mut type_count = 0;
272 let success = unsafe {
273 BNTypeContainerGetTypeNamesAndIds(
274 self.handle.as_ptr(),
275 &mut type_ids,
276 &mut type_names,
277 &mut type_count,
278 )
279 };
280 success.then(|| unsafe {
281 let ids = Array::new(type_ids, type_count, ());
282 let names = Array::new(type_names, type_count, ());
283 (ids, names)
284 })
285 }
286
287 pub fn parse_type_string(
293 &self,
294 source: &str,
295 import_dependencies: bool,
296 ) -> Result<QualifiedNameAndType, Array<TypeParserError>> {
297 let source = source.to_cstr();
298 let mut result = BNQualifiedNameAndType::default();
299 let mut errors = std::ptr::null_mut();
300 let mut error_count = 0;
301 let success = unsafe {
302 BNTypeContainerParseTypeString(
303 self.handle.as_ptr(),
304 source.as_ptr(),
305 import_dependencies,
306 &mut result,
307 &mut errors,
308 &mut error_count,
309 )
310 };
311 if success {
312 Ok(QualifiedNameAndType::from_owned_raw(result))
313 } else {
314 assert!(!errors.is_null());
315 Err(unsafe { Array::new(errors, error_count, ()) })
316 }
317 }
318
319 pub fn parse_types_from_source<O, I>(
329 &self,
330 source: &str,
331 filename: &str,
332 options: O,
333 include_directories: I,
334 auto_type_source: &str,
335 import_dependencies: bool,
336 ) -> Result<TypeParserResult, Array<TypeParserError>>
337 where
338 O: IntoIterator<Item = String>,
339 I: IntoIterator<Item = String>,
340 {
341 let source = source.to_cstr();
342 let filename = filename.to_cstr();
343 let options: Vec<_> = options.into_iter().map(|o| o.to_cstr()).collect();
344 let options_raw: Vec<*const c_char> = options.iter().map(|o| o.as_ptr()).collect();
345 let include_directories: Vec<_> = include_directories
346 .into_iter()
347 .map(|d| d.to_cstr())
348 .collect();
349 let include_directories_raw: Vec<*const c_char> =
350 include_directories.iter().map(|d| d.as_ptr()).collect();
351 let auto_type_source = auto_type_source.to_cstr();
352 let mut raw_result = BNTypeParserResult::default();
353 let mut errors = std::ptr::null_mut();
354 let mut error_count = 0;
355 let success = unsafe {
356 BNTypeContainerParseTypesFromSource(
357 self.handle.as_ptr(),
358 source.as_ptr(),
359 filename.as_ptr(),
360 options_raw.as_ptr(),
361 options_raw.len(),
362 include_directories_raw.as_ptr(),
363 include_directories_raw.len(),
364 auto_type_source.as_ptr(),
365 import_dependencies,
366 &mut raw_result,
367 &mut errors,
368 &mut error_count,
369 )
370 };
371 if success {
372 let result = TypeParserResult::from_raw(&raw_result);
373 TypeParserResult::free_raw(raw_result);
375 Ok(result)
376 } else {
377 assert!(!errors.is_null());
378 Err(unsafe { Array::new(errors, error_count, ()) })
379 }
380 }
381}
382
383impl Debug for TypeContainer {
384 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
385 f.debug_struct("TypeContainer")
386 .field("id", &self.id())
387 .field("name", &self.name())
388 .field("container_type", &self.container_type())
389 .field("is_mutable", &self.is_mutable())
390 .field("type_names", &self.type_names().unwrap().to_vec())
391 .finish()
392 }
393}
394
395impl Drop for TypeContainer {
396 fn drop(&mut self) {
397 unsafe { BNFreeTypeContainer(self.handle.as_ptr()) }
398 }
399}
400
401impl Clone for TypeContainer {
402 fn clone(&self) -> Self {
403 unsafe {
404 let cloned_ptr = NonNull::new(BNDuplicateTypeContainer(self.handle.as_ptr()));
405 Self {
406 handle: cloned_ptr.unwrap(),
407 }
408 }
409 }
410}