binaryninja/project/
file.rs1use crate::project::{systime_from_bntime, Project, ProjectFolder};
2use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable};
3use crate::string::{BnString, IntoCStr};
4use binaryninjacore_sys::{
5 BNFreeProjectFile, BNFreeProjectFileList, BNNewProjectFileReference, BNProjectFile,
6 BNProjectFileAddDependency, BNProjectFileExistsOnDisk, BNProjectFileExport,
7 BNProjectFileGetCreationTimestamp, BNProjectFileGetDependencies, BNProjectFileGetDescription,
8 BNProjectFileGetFolder, BNProjectFileGetId, BNProjectFileGetName,
9 BNProjectFileGetPathInProject, BNProjectFileGetPathOnDisk, BNProjectFileGetProject,
10 BNProjectFileGetRequiredBy, BNProjectFileRemoveDependency, BNProjectFileSetDescription,
11 BNProjectFileSetFolder, BNProjectFileSetName,
12};
13use std::fmt::Debug;
14use std::hash::Hash;
15use std::path::{Path, PathBuf};
16use std::ptr::{null_mut, NonNull};
17use std::time::SystemTime;
18
19#[repr(transparent)]
20pub struct ProjectFile {
21 pub(crate) handle: NonNull<BNProjectFile>,
22}
23
24impl ProjectFile {
25 pub unsafe fn from_raw(handle: NonNull<BNProjectFile>) -> Self {
26 Self { handle }
27 }
28
29 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNProjectFile>) -> Ref<Self> {
30 Ref::new(Self { handle })
31 }
32
33 pub fn project(&self) -> Ref<Project> {
35 unsafe {
36 Project::ref_from_raw(
37 NonNull::new(BNProjectFileGetProject(self.handle.as_ptr())).unwrap(),
38 )
39 }
40 }
41
42 pub fn path_on_disk(&self) -> Option<PathBuf> {
44 if !self.exists_on_disk() {
45 return None;
46 }
47 let path_str =
48 unsafe { BnString::into_string(BNProjectFileGetPathOnDisk(self.handle.as_ptr())) };
49 Some(PathBuf::from(path_str))
50 }
51
52 pub fn path_in_project(&self) -> PathBuf {
54 let path_str =
55 unsafe { BnString::into_string(BNProjectFileGetPathInProject(self.handle.as_ptr())) };
56 PathBuf::from(path_str)
57 }
58
59 pub fn exists_on_disk(&self) -> bool {
61 unsafe { BNProjectFileExistsOnDisk(self.handle.as_ptr()) }
62 }
63
64 pub fn id(&self) -> String {
66 unsafe { BnString::into_string(BNProjectFileGetId(self.handle.as_ptr())) }
67 }
68
69 pub fn name(&self) -> String {
71 unsafe { BnString::into_string(BNProjectFileGetName(self.handle.as_ptr())) }
72 }
73
74 pub fn set_name(&self, value: &str) -> bool {
76 let value_raw = value.to_cstr();
77 unsafe { BNProjectFileSetName(self.handle.as_ptr(), value_raw.as_ptr()) }
78 }
79
80 pub fn description(&self) -> String {
82 unsafe { BnString::into_string(BNProjectFileGetDescription(self.handle.as_ptr())) }
83 }
84
85 pub fn set_description(&self, value: &str) -> bool {
87 let value_raw = value.to_cstr();
88 unsafe { BNProjectFileSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) }
89 }
90
91 pub fn creation_time(&self) -> SystemTime {
93 systime_from_bntime(unsafe { BNProjectFileGetCreationTimestamp(self.handle.as_ptr()) })
94 .unwrap()
95 }
96
97 pub fn folder(&self) -> Option<Ref<ProjectFolder>> {
99 let result = unsafe { BNProjectFileGetFolder(self.handle.as_ptr()) };
100 NonNull::new(result).map(|handle| unsafe { ProjectFolder::ref_from_raw(handle) })
101 }
102
103 pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool {
105 let folder_handle = folder.map(|x| x.handle.as_ptr()).unwrap_or(null_mut());
106 unsafe { BNProjectFileSetFolder(self.handle.as_ptr(), folder_handle) }
107 }
108
109 pub fn export(&self, dest: &Path) -> bool {
113 let dest_raw = dest.to_cstr();
114 unsafe { BNProjectFileExport(self.handle.as_ptr(), dest_raw.as_ptr()) }
115 }
116
117 pub fn add_dependency(&self, file: Ref<ProjectFile>) -> bool {
119 unsafe { BNProjectFileAddDependency(self.handle.as_ptr(), file.handle.as_ptr()) }
120 }
121
122 pub fn remove_dependency(&self, file: Ref<ProjectFile>) -> bool {
124 unsafe { BNProjectFileRemoveDependency(self.handle.as_ptr(), file.handle.as_ptr()) }
125 }
126
127 pub fn get_dependencies(&self) -> Array<ProjectFile> {
129 let mut count = 0;
130 let result = unsafe { BNProjectFileGetDependencies(self.handle.as_ptr(), &mut count) };
131 unsafe { Array::new(result, count, ()) }
132 }
133
134 pub fn get_required_by(&self) -> Array<ProjectFile> {
136 let mut count = 0;
137 let result = unsafe { BNProjectFileGetRequiredBy(self.handle.as_ptr(), &mut count) };
138 unsafe { Array::new(result, count, ()) }
139 }
140}
141
142impl Debug for ProjectFile {
143 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
144 f.debug_struct("ProjectFile")
145 .field("id", &self.id())
146 .field("name", &self.name())
147 .field("description", &self.description())
148 .field("creation_time", &self.creation_time())
149 .field("exists_on_disk", &self.exists_on_disk())
150 .field("project", &self.project())
151 .field("folder", &self.folder())
152 .finish()
153 }
154}
155
156unsafe impl Send for ProjectFile {}
157unsafe impl Sync for ProjectFile {}
158
159impl PartialEq for ProjectFile {
160 fn eq(&self, other: &Self) -> bool {
161 self.id() == other.id()
162 }
163}
164
165impl Eq for ProjectFile {}
166
167impl Hash for ProjectFile {
168 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
169 self.id().hash(state);
170 }
171}
172
173impl ToOwned for ProjectFile {
174 type Owned = Ref<Self>;
175
176 fn to_owned(&self) -> Self::Owned {
177 unsafe { RefCountable::inc_ref(self) }
178 }
179}
180
181unsafe impl RefCountable for ProjectFile {
182 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
183 Ref::new(Self {
184 handle: NonNull::new(BNNewProjectFileReference(handle.handle.as_ptr())).unwrap(),
185 })
186 }
187
188 unsafe fn dec_ref(handle: &Self) {
189 BNFreeProjectFile(handle.handle.as_ptr());
190 }
191}
192
193impl CoreArrayProvider for ProjectFile {
194 type Raw = *mut BNProjectFile;
195 type Context = ();
196 type Wrapped<'a> = Guard<'a, Self>;
197}
198
199unsafe impl CoreArrayProviderInner for ProjectFile {
200 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
201 BNFreeProjectFileList(raw, count)
202 }
203
204 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
205 let raw_ptr = NonNull::new(*raw).unwrap();
206 Guard::new(Self::from_raw(raw_ptr), context)
207 }
208}