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::path::{Path, PathBuf};
15use std::ptr::{null_mut, NonNull};
16use std::time::SystemTime;
17
18#[repr(transparent)]
19pub struct ProjectFile {
20 pub(crate) handle: NonNull<BNProjectFile>,
21}
22
23impl ProjectFile {
24 pub(crate) unsafe fn from_raw(handle: NonNull<BNProjectFile>) -> Self {
25 Self { handle }
26 }
27
28 pub(crate) unsafe fn ref_from_raw(handle: NonNull<BNProjectFile>) -> Ref<Self> {
29 Ref::new(Self { handle })
30 }
31
32 pub fn project(&self) -> Ref<Project> {
34 unsafe {
35 Project::ref_from_raw(
36 NonNull::new(BNProjectFileGetProject(self.handle.as_ptr())).unwrap(),
37 )
38 }
39 }
40
41 pub fn path_on_disk(&self) -> Option<PathBuf> {
43 if !self.exists_on_disk() {
44 return None;
45 }
46 let path_str =
47 unsafe { BnString::into_string(BNProjectFileGetPathOnDisk(self.handle.as_ptr())) };
48 Some(PathBuf::from(path_str))
49 }
50
51 pub fn path_in_project(&self) -> PathBuf {
53 let path_str =
54 unsafe { BnString::into_string(BNProjectFileGetPathInProject(self.handle.as_ptr())) };
55 PathBuf::from(path_str)
56 }
57
58 pub fn exists_on_disk(&self) -> bool {
60 unsafe { BNProjectFileExistsOnDisk(self.handle.as_ptr()) }
61 }
62
63 pub fn id(&self) -> String {
65 unsafe { BnString::into_string(BNProjectFileGetId(self.handle.as_ptr())) }
66 }
67
68 pub fn name(&self) -> String {
70 unsafe { BnString::into_string(BNProjectFileGetName(self.handle.as_ptr())) }
71 }
72
73 pub fn set_name(&self, value: &str) -> bool {
75 let value_raw = value.to_cstr();
76 unsafe { BNProjectFileSetName(self.handle.as_ptr(), value_raw.as_ptr()) }
77 }
78
79 pub fn description(&self) -> String {
81 unsafe { BnString::into_string(BNProjectFileGetDescription(self.handle.as_ptr())) }
82 }
83
84 pub fn set_description(&self, value: &str) -> bool {
86 let value_raw = value.to_cstr();
87 unsafe { BNProjectFileSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) }
88 }
89
90 pub fn creation_time(&self) -> SystemTime {
92 systime_from_bntime(unsafe { BNProjectFileGetCreationTimestamp(self.handle.as_ptr()) })
93 .unwrap()
94 }
95
96 pub fn folder(&self) -> Option<Ref<ProjectFolder>> {
98 let result = unsafe { BNProjectFileGetFolder(self.handle.as_ptr()) };
99 NonNull::new(result).map(|handle| unsafe { ProjectFolder::ref_from_raw(handle) })
100 }
101
102 pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool {
104 let folder_handle = folder.map(|x| x.handle.as_ptr()).unwrap_or(null_mut());
105 unsafe { BNProjectFileSetFolder(self.handle.as_ptr(), folder_handle) }
106 }
107
108 pub fn export(&self, dest: &Path) -> bool {
112 let dest_raw = dest.to_cstr();
113 unsafe { BNProjectFileExport(self.handle.as_ptr(), dest_raw.as_ptr()) }
114 }
115
116 pub fn add_dependency(&self, file: Ref<ProjectFile>) -> bool {
118 unsafe { BNProjectFileAddDependency(self.handle.as_ptr(), file.handle.as_ptr()) }
119 }
120
121 pub fn remove_dependency(&self, file: Ref<ProjectFile>) -> bool {
123 unsafe { BNProjectFileRemoveDependency(self.handle.as_ptr(), file.handle.as_ptr()) }
124 }
125
126 pub fn get_dependencies(&self) -> Array<ProjectFile> {
128 let mut count = 0;
129 let result = unsafe { BNProjectFileGetDependencies(self.handle.as_ptr(), &mut count) };
130 unsafe { Array::new(result, count, ()) }
131 }
132
133 pub fn get_required_by(&self) -> Array<ProjectFile> {
135 let mut count = 0;
136 let result = unsafe { BNProjectFileGetRequiredBy(self.handle.as_ptr(), &mut count) };
137 unsafe { Array::new(result, count, ()) }
138 }
139}
140
141impl Debug for ProjectFile {
142 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
143 f.debug_struct("ProjectFile")
144 .field("id", &self.id())
145 .field("name", &self.name())
146 .field("description", &self.description())
147 .field("creation_time", &self.creation_time())
148 .field("exists_on_disk", &self.exists_on_disk())
149 .field("project", &self.project())
150 .field("folder", &self.folder())
151 .finish()
152 }
153}
154
155unsafe impl Send for ProjectFile {}
156unsafe impl Sync for ProjectFile {}
157
158impl ToOwned for ProjectFile {
159 type Owned = Ref<Self>;
160
161 fn to_owned(&self) -> Self::Owned {
162 unsafe { RefCountable::inc_ref(self) }
163 }
164}
165
166unsafe impl RefCountable for ProjectFile {
167 unsafe fn inc_ref(handle: &Self) -> Ref<Self> {
168 Ref::new(Self {
169 handle: NonNull::new(BNNewProjectFileReference(handle.handle.as_ptr())).unwrap(),
170 })
171 }
172
173 unsafe fn dec_ref(handle: &Self) {
174 BNFreeProjectFile(handle.handle.as_ptr());
175 }
176}
177
178impl CoreArrayProvider for ProjectFile {
179 type Raw = *mut BNProjectFile;
180 type Context = ();
181 type Wrapped<'a> = Guard<'a, Self>;
182}
183
184unsafe impl CoreArrayProviderInner for ProjectFile {
185 unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) {
186 BNFreeProjectFileList(raw, count)
187 }
188
189 unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> {
190 let raw_ptr = NonNull::new(*raw).unwrap();
191 Guard::new(Self::from_raw(raw_ptr), context)
192 }
193}