1use binaryninjacore_sys::*;
2use std::fmt::{Debug, Formatter};
3
4use crate::rc::{Guard, RefCountable};
5use crate::{
6 architecture::CoreArchitecture,
7 metadata::Metadata,
8 platform::Platform,
9 rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Ref},
10 string::{BnString, IntoCStr},
11 types::{QualifiedName, QualifiedNameAndType, Type},
12};
13use std::path::Path;
14use std::ptr::NonNull;
15
16#[repr(transparent)]
17pub struct TypeLibrary {
18 handle: NonNull<BNTypeLibrary>,
19}
20
21impl TypeLibrary {
22 pub(crate) unsafe fn from_raw(handle: NonNull<BNTypeLibrary>) -> Self {
23 Self { handle }
24 }
25
26 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNTypeLibrary>) -> Ref<Self> {
27 Ref::new(Self { handle })
28 }
29
30 #[allow(clippy::mut_from_ref)]
31 pub(crate) unsafe fn as_raw(&self) -> &mut BNTypeLibrary {
32 &mut *self.handle.as_ptr()
33 }
34
35 pub fn new_duplicated(&self) -> Ref<Self> {
36 unsafe { Self::ref_from_raw(NonNull::new(BNDuplicateTypeLibrary(self.as_raw())).unwrap()) }
37 }
38
39 pub fn new(arch: CoreArchitecture, name: &str) -> Ref<TypeLibrary> {
41 let name = name.to_cstr();
42 let new_lib = unsafe { BNNewTypeLibrary(arch.handle, name.as_ptr()) };
43 unsafe { TypeLibrary::ref_from_raw(NonNull::new(new_lib).unwrap()) }
44 }
45
46 pub fn all(arch: CoreArchitecture) -> Array<TypeLibrary> {
47 let mut count = 0;
48 let result = unsafe { BNGetArchitectureTypeLibraries(arch.handle, &mut count) };
49 assert!(!result.is_null());
50 unsafe { Array::new(result, count, ()) }
51 }
52
53 pub fn decompress_to_file(path: &Path, output_path: &Path) -> bool {
55 let path = path.to_cstr();
56 let output = output_path.to_cstr();
57 unsafe { BNTypeLibraryDecompressToFile(path.as_ptr(), output.as_ptr()) }
58 }
59
60 pub fn load_from_file(path: &Path) -> Option<Ref<TypeLibrary>> {
62 let path = path.to_cstr();
63 let handle = unsafe { BNLoadTypeLibraryFromFile(path.as_ptr()) };
64 NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
65 }
66
67 pub fn write_to_file(&self, path: &Path) -> bool {
69 let path = path.to_cstr();
70 unsafe { BNWriteTypeLibraryToFile(self.as_raw(), path.as_ptr()) }
71 }
72
73 pub fn from_name(arch: CoreArchitecture, name: &str) -> Option<Ref<TypeLibrary>> {
80 let name = name.to_cstr();
81 let handle = unsafe { BNLookupTypeLibraryByName(arch.handle, name.as_ptr()) };
82 NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
83 }
84
85 pub fn from_guid(arch: CoreArchitecture, guid: &str) -> Option<Ref<TypeLibrary>> {
90 let guid = guid.to_cstr();
91 let handle = unsafe { BNLookupTypeLibraryByGuid(arch.handle, guid.as_ptr()) };
92 NonNull::new(handle).map(|h| unsafe { TypeLibrary::ref_from_raw(h) })
93 }
94
95 pub fn arch(&self) -> CoreArchitecture {
97 let arch = unsafe { BNGetTypeLibraryArchitecture(self.as_raw()) };
98 assert!(!arch.is_null());
99 unsafe { CoreArchitecture::from_raw(arch) }
100 }
101
102 pub fn name(&self) -> String {
104 let result = unsafe { BNGetTypeLibraryName(self.as_raw()) };
105 assert!(!result.is_null());
106 unsafe { BnString::into_string(result) }
107 }
108
109 pub fn set_name(&self, value: &str) {
111 let value = value.to_cstr();
112 unsafe { BNSetTypeLibraryName(self.as_raw(), value.as_ptr()) }
113 }
114
115 pub fn dependency_name(&self) -> String {
121 let result = unsafe { BNGetTypeLibraryDependencyName(self.as_raw()) };
122 assert!(!result.is_null());
123 unsafe { BnString::into_string(result) }
124 }
125
126 pub fn set_dependency_name(&self, value: &str) {
128 let value = value.to_cstr();
129 unsafe { BNSetTypeLibraryDependencyName(self.as_raw(), value.as_ptr()) }
130 }
131
132 pub fn guid(&self) -> String {
134 let result = unsafe { BNGetTypeLibraryGuid(self.as_raw()) };
135 assert!(!result.is_null());
136 unsafe { BnString::into_string(result) }
137 }
138
139 pub fn set_guid(&self, value: &str) {
141 let value = value.to_cstr();
142 unsafe { BNSetTypeLibraryGuid(self.as_raw(), value.as_ptr()) }
143 }
144
145 pub fn alternate_names(&self) -> Array<BnString> {
147 let mut count = 0;
148 let result = unsafe { BNGetTypeLibraryAlternateNames(self.as_raw(), &mut count) };
149 assert!(!result.is_null());
150 unsafe { Array::new(result, count, ()) }
151 }
152
153 pub fn add_alternate_name(&self, value: &str) {
155 let value = value.to_cstr();
156 unsafe { BNAddTypeLibraryAlternateName(self.as_raw(), value.as_ptr()) }
157 }
158
159 pub fn platform_names(&self) -> Array<BnString> {
165 let mut count = 0;
166 let result = unsafe { BNGetTypeLibraryPlatforms(self.as_raw(), &mut count) };
167 assert!(!result.is_null());
168 unsafe { Array::new(result, count, ()) }
169 }
170
171 pub fn add_platform(&self, plat: &Platform) {
178 unsafe { BNAddTypeLibraryPlatform(self.as_raw(), plat.handle) }
179 }
180
181 pub fn clear_platforms(&self) {
183 unsafe { BNClearTypeLibraryPlatforms(self.as_raw()) }
184 }
185
186 pub fn finalize(&self) -> bool {
189 unsafe { BNFinalizeTypeLibrary(self.as_raw()) }
190 }
191
192 pub fn query_metadata(&self, key: &str) -> Option<Ref<Metadata>> {
194 let key = key.to_cstr();
195 let result = unsafe { BNTypeLibraryQueryMetadata(self.as_raw(), key.as_ptr()) };
196 (!result.is_null()).then(|| unsafe { Metadata::ref_from_raw(result) })
197 }
198
199 pub fn store_metadata(&self, key: &str, md: &Metadata) {
211 let key = key.to_cstr();
212 unsafe { BNTypeLibraryStoreMetadata(self.as_raw(), key.as_ptr(), md.handle) }
213 }
214
215 pub fn remove_metadata(&self, key: &str) {
217 let key = key.to_cstr();
218 unsafe { BNTypeLibraryRemoveMetadata(self.as_raw(), key.as_ptr()) }
219 }
220
221 pub fn metadata(&self) -> Ref<Metadata> {
223 let md_handle = unsafe { BNTypeLibraryGetMetadata(self.as_raw()) };
224 assert!(!md_handle.is_null());
225 unsafe { Metadata::ref_from_raw(md_handle) }
226 }
227
228 pub fn add_named_object(&self, name: QualifiedName, type_: &Type) {
244 let mut raw_name = QualifiedName::into_raw(name);
245 unsafe { BNAddTypeLibraryNamedObject(self.as_raw(), &mut raw_name, type_.handle) }
246 QualifiedName::free_raw(raw_name);
247 }
248
249 pub fn add_named_type(&self, name: QualifiedName, type_: &Type) {
257 let mut raw_name = QualifiedName::into_raw(name);
258 unsafe { BNAddTypeLibraryNamedType(self.as_raw(), &mut raw_name, type_.handle) }
259 QualifiedName::free_raw(raw_name);
260 }
261
262 pub fn add_type_source(&self, name: QualifiedName, source: &str) {
271 let source = source.to_cstr();
272 let mut raw_name = QualifiedName::into_raw(name);
273 unsafe { BNAddTypeLibraryNamedTypeSource(self.as_raw(), &mut raw_name, source.as_ptr()) }
274 QualifiedName::free_raw(raw_name);
275 }
276
277 pub fn get_named_object(&self, name: QualifiedName) -> Option<Ref<Type>> {
281 let mut raw_name = QualifiedName::into_raw(name);
282 let t = unsafe { BNGetTypeLibraryNamedObject(self.as_raw(), &mut raw_name) };
283 QualifiedName::free_raw(raw_name);
284 (!t.is_null()).then(|| unsafe { Type::ref_from_raw(t) })
285 }
286
287 pub fn get_named_type(&self, name: QualifiedName) -> Option<Ref<Type>> {
291 let mut raw_name = QualifiedName::into_raw(name);
292 let t = unsafe { BNGetTypeLibraryNamedType(self.as_raw(), &mut raw_name) };
293 QualifiedName::free_raw(raw_name);
294 (!t.is_null()).then(|| unsafe { Type::ref_from_raw(t) })
295 }
296
297 pub fn named_objects(&self) -> Array<QualifiedNameAndType> {
299 let mut count = 0;
300 let result = unsafe { BNGetTypeLibraryNamedObjects(self.as_raw(), &mut count) };
301 assert!(!result.is_null());
302 unsafe { Array::new(result, count, ()) }
303 }
304
305 pub fn named_types(&self) -> Array<QualifiedNameAndType> {
307 let mut count = 0;
308 let result = unsafe { BNGetTypeLibraryNamedTypes(self.as_raw(), &mut count) };
309 assert!(!result.is_null());
310 unsafe { Array::new(result, count, ()) }
311 }
312}
313
314impl Debug for TypeLibrary {
315 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
316 f.debug_struct("TypeLibrary")
317 .field("name", &self.name())
318 .field("dependency_name", &self.dependency_name())
319 .field("arch", &self.arch())
320 .field("guid", &self.guid())
321 .field("alternate_names", &self.alternate_names().to_vec())
322 .field("platform_names", &self.platform_names().to_vec())
323 .field("metadata", &self.metadata())
324 .finish()
328 }
329}
330
331unsafe impl RefCountable for TypeLibrary {
332 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
333 Ref::new(Self {
334 handle: NonNull::new(BNNewTypeLibraryReference(handle.handle.as_ptr())).unwrap(),
335 })
336 }
337
338 unsafe fn dec_ref(handle: &Self) {
339 BNFreeTypeLibrary(handle.handle.as_ptr());
340 }
341}
342
343impl ToOwned for TypeLibrary {
344 type Owned = Ref<Self>;
345
346 fn to_owned(&self) -> Self::Owned {
347 unsafe { RefCountable::inc_ref(self) }
348 }
349}
350
351impl CoreArrayProvider for TypeLibrary {
352 type Raw = *mut BNTypeLibrary;
353 type Context = ();
354 type Wrapped<'a> = Guard<'a, Self>;
355}
356
357unsafe impl CoreArrayProviderInner for TypeLibrary {
358 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
359 BNFreeTypeLibraryList(raw, count)
360 }
361
362 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
363 Guard::new(Self::from_raw(NonNull::new(*raw).unwrap()), context)
364 }
365}