1use crate::binary_view::{BinaryView, BinaryViewExt};
2use crate::function::Function;
3use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
4use crate::string::{BnString, IntoCStr};
5use crate::types::ComponentReferencedType;
6use std::ffi::c_char;
7use std::fmt::Debug;
8use std::ptr::NonNull;
9
10use crate::variable::DataVariable;
11use binaryninjacore_sys::*;
12
13pub struct ComponentBuilder {
14 view: Ref<BinaryView>,
15 parent: Option<String>,
16 name: Option<String>,
17}
18
19impl ComponentBuilder {
20 pub fn new(view: Ref<BinaryView>) -> Self {
21 Self {
22 view,
23 parent: None,
24 name: None,
25 }
26 }
27
28 pub fn parent(mut self, parent_guid: impl Into<String>) -> Self {
29 self.parent = Some(parent_guid.into());
30 self
31 }
32
33 pub fn name(mut self, name: impl Into<String>) -> Self {
34 self.name = Some(name.into());
35 self
36 }
37
38 pub fn finalize(self) -> Ref<Component> {
39 let result = match (&self.parent, &self.name) {
40 (None, None) => unsafe { BNCreateComponent(self.view.handle) },
41 (None, Some(name)) => {
42 let name_raw = name.to_cstr();
43 unsafe {
44 BNCreateComponentWithName(self.view.handle, name_raw.as_ptr() as *mut c_char)
45 }
46 }
47 (Some(guid), None) => {
48 let guid_raw = guid.to_cstr();
49 unsafe {
50 BNCreateComponentWithParent(self.view.handle, guid_raw.as_ptr() as *mut c_char)
51 }
52 }
53 (Some(guid), Some(name)) => {
54 let guid_raw = guid.to_cstr();
55 let name_raw = name.to_cstr();
56 unsafe {
57 BNCreateComponentWithParentAndName(
58 self.view.handle,
59 guid_raw.as_ptr() as *mut c_char,
60 name_raw.as_ptr() as *mut c_char,
61 )
62 }
63 }
64 };
65 unsafe { Component::ref_from_raw(NonNull::new(result).unwrap()) }
66 }
67}
68
69#[repr(transparent)]
76pub struct Component {
77 pub(crate) handle: NonNull<BNComponent>,
78}
79
80impl Component {
81 pub(crate) unsafe fn from_raw(handle: NonNull<BNComponent>) -> Self {
82 Self { handle }
83 }
84
85 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNComponent>) -> Ref<Self> {
86 Ref::new(Self { handle })
87 }
88
89 pub fn guid(&self) -> String {
90 let result = unsafe { BNComponentGetGuid(self.handle.as_ptr()) };
91 assert!(!result.is_null());
92 unsafe { BnString::into_string(result) }
93 }
94
95 pub fn add_function(&self, func: &Function) -> bool {
97 unsafe { BNComponentAddFunctionReference(self.handle.as_ptr(), func.handle) }
98 }
99
100 pub fn contains_function(&self, func: &Function) -> bool {
102 unsafe { BNComponentContainsFunction(self.handle.as_ptr(), func.handle) }
103 }
104
105 pub fn remove_function(&self, func: &Function) -> bool {
107 unsafe { BNComponentRemoveFunctionReference(self.handle.as_ptr(), func.handle) }
108 }
109
110 pub fn add_component(&self, component: &Component) -> bool {
112 unsafe { BNComponentAddComponent(self.handle.as_ptr(), component.handle.as_ptr()) }
113 }
114
115 pub fn contains_component(&self, component: &Component) -> bool {
117 unsafe { BNComponentContainsComponent(self.handle.as_ptr(), component.handle.as_ptr()) }
118 }
119
120 pub fn remove_component(&self, component: &Component) -> bool {
125 self.view()
126 .unwrap()
127 .root_component()
128 .unwrap()
129 .add_component(component)
130 }
131
132 pub fn add_data_variable(&self, data_variable: &DataVariable) -> bool {
134 unsafe { BNComponentAddDataVariable(self.handle.as_ptr(), data_variable.address) }
135 }
136
137 pub fn contains_data_variable(&self, data_variable: &DataVariable) -> bool {
139 unsafe { BNComponentContainsDataVariable(self.handle.as_ptr(), data_variable.address) }
140 }
141
142 pub fn remove_data_variable(&self, data_variable: &DataVariable) -> bool {
144 unsafe { BNComponentRemoveDataVariable(self.handle.as_ptr(), data_variable.address) }
145 }
146
147 pub fn display_name(&self) -> String {
149 let result = unsafe { BNComponentGetDisplayName(self.handle.as_ptr()) };
150 assert!(!result.is_null());
151 unsafe { BnString::into_string(result) }
152 }
153
154 pub fn name(&self) -> String {
162 let result = unsafe { BNComponentGetOriginalName(self.handle.as_ptr()) };
163 assert!(!result.is_null());
164 unsafe { BnString::into_string(result) }
165 }
166
167 pub fn set_name(&self, name: &str) {
168 let name = name.to_cstr();
169 unsafe { BNComponentSetName(self.handle.as_ptr(), name.as_ptr()) }
170 }
171
172 pub fn parent(&self) -> Option<Ref<Component>> {
174 let result = unsafe { BNComponentGetParent(self.handle.as_ptr()) };
175 NonNull::new(result).map(|h| unsafe { Self::ref_from_raw(h) })
176 }
177
178 pub fn view(&self) -> Option<Ref<BinaryView>> {
179 let result = unsafe { BNComponentGetView(self.handle.as_ptr()) };
180 (!result.is_null()).then(|| unsafe { BinaryView::ref_from_raw(result) })
181 }
182
183 pub fn components(&self) -> Array<Component> {
185 let mut count = 0;
186 let result = unsafe { BNComponentGetContainedComponents(self.handle.as_ptr(), &mut count) };
187 assert!(!result.is_null());
188 unsafe { Array::new(result, count, ()) }
189 }
190
191 pub fn functions(&self) -> Array<Function> {
193 let mut count = 0;
194 let result = unsafe { BNComponentGetContainedFunctions(self.handle.as_ptr(), &mut count) };
195 assert!(!result.is_null());
196 unsafe { Array::new(result, count, ()) }
197 }
198
199 pub fn data_variables(&self) -> Array<DataVariable> {
201 let mut count = 0;
202 let result =
203 unsafe { BNComponentGetContainedDataVariables(self.handle.as_ptr(), &mut count) };
204 assert!(!result.is_null());
205 unsafe { Array::new(result, count, ()) }
206 }
207
208 pub fn referenced_data_variables(&self, recursive: bool) -> Array<DataVariable> {
212 let mut count = 0;
213 let result = if recursive {
214 unsafe {
215 BNComponentGetReferencedDataVariablesRecursive(self.handle.as_ptr(), &mut count)
216 }
217 } else {
218 unsafe { BNComponentGetReferencedDataVariables(self.handle.as_ptr(), &mut count) }
219 };
220 unsafe { Array::new(result, count, ()) }
221 }
222
223 pub fn referenced_types(&self, recursive: bool) -> Array<ComponentReferencedType> {
227 let mut count = 0;
228 let result = if recursive {
229 unsafe { BNComponentGetReferencedTypesRecursive(self.handle.as_ptr(), &mut count) }
230 } else {
231 unsafe { BNComponentGetReferencedTypes(self.handle.as_ptr(), &mut count) }
232 };
233 unsafe { Array::new(result, count, ()) }
234 }
235
236 pub fn remove_all_functions(&self) {
237 unsafe { BNComponentRemoveAllFunctions(self.handle.as_ptr()) }
238 }
239
240 pub fn add_all_members_from(&self, component: &Component) {
241 unsafe {
242 BNComponentAddAllMembersFromComponent(self.handle.as_ptr(), component.handle.as_ptr())
243 }
244 }
245}
246
247impl Debug for Component {
248 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
249 f.debug_struct("Component")
250 .field("guid", &self.guid())
251 .field("display_name", &self.display_name())
252 .field("name", &self.name())
253 .field("components", &self.components().to_vec())
254 .finish()
255 }
256}
257
258impl PartialEq for Component {
259 fn eq(&self, other: &Self) -> bool {
260 unsafe { BNComponentsEqual(self.handle.as_ptr(), other.handle.as_ptr()) }
261 }
262
263 #[allow(clippy::partialeq_ne_impl)]
264 fn ne(&self, other: &Self) -> bool {
265 unsafe { BNComponentsNotEqual(self.handle.as_ptr(), other.handle.as_ptr()) }
266 }
267}
268
269impl Eq for Component {}
270
271impl ToOwned for Component {
272 type Owned = Ref<Self>;
273
274 fn to_owned(&self) -> Self::Owned {
275 unsafe { RefCountable::inc_ref(self) }
276 }
277}
278
279unsafe impl RefCountable for Component {
280 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
281 Ref::new(Self {
282 handle: NonNull::new(BNNewComponentReference(handle.handle.as_ptr())).unwrap(),
283 })
284 }
285
286 unsafe fn dec_ref(handle: &Self) {
287 BNFreeComponent(handle.handle.as_ptr());
288 }
289}
290
291impl CoreArrayProvider for Component {
292 type Raw = *mut BNComponent;
293 type Context = ();
294 type Wrapped<'a> = Guard<'a, Self>;
295}
296
297unsafe impl CoreArrayProviderInner for Component {
298 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
299 BNFreeComponents(raw, count)
300 }
301
302 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
303 let raw_ptr = NonNull::new(*raw).unwrap();
304 Guard::new(Self::from_raw(raw_ptr), context)
305 }
306}