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