use crate::progress::{NoProgressCallback, ProgressCallback}; use crate::project::file::ProjectFile; use crate::project::Project; use crate::rc::{Array, CoreArrayProvider, CoreArrayProviderInner, Guard, Ref, RefCountable}; use crate::string::{BnString, IntoCStr}; use binaryninjacore_sys::{ BNFreeProjectFolder, BNFreeProjectFolderList, BNNewProjectFolderReference, BNProjectFolder, BNProjectFolderExport, BNProjectFolderGetDescription, BNProjectFolderGetFiles, BNProjectFolderGetId, BNProjectFolderGetName, BNProjectFolderGetParent, BNProjectFolderGetProject, BNProjectFolderSetDescription, BNProjectFolderSetName, BNProjectFolderSetParent, }; use std::ffi::c_void; use std::fmt::Debug; use std::path::Path; use std::ptr::{null_mut, NonNull}; #[repr(transparent)] pub struct ProjectFolder { pub(crate) handle: NonNull, } impl ProjectFolder { pub(crate) unsafe fn from_raw(handle: NonNull) -> Self { Self { handle } } pub(crate) unsafe fn ref_from_raw(handle: NonNull) -> Ref { Ref::new(Self { handle }) } /// Get the project that owns this folder pub fn project(&self) -> Ref { unsafe { Project::ref_from_raw( NonNull::new(BNProjectFolderGetProject(self.handle.as_ptr())).unwrap(), ) } } /// Get the unique id of this folder pub fn id(&self) -> String { unsafe { BnString::into_string(BNProjectFolderGetId(self.handle.as_ptr())) } } /// Get the name of this folder pub fn name(&self) -> String { unsafe { BnString::into_string(BNProjectFolderGetName(self.handle.as_ptr())) } } /// Set the name of this folder pub fn set_name(&self, value: &str) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetName(self.handle.as_ptr(), value_raw.as_ptr()) } } /// Get the description of this folder pub fn description(&self) -> String { unsafe { BnString::into_string(BNProjectFolderGetDescription(self.handle.as_ptr())) } } /// Set the description of this folder pub fn set_description(&self, value: &str) -> bool { let value_raw = value.to_cstr(); unsafe { BNProjectFolderSetDescription(self.handle.as_ptr(), value_raw.as_ptr()) } } /// Get the folder that contains this folder pub fn parent(&self) -> Option> { let result = unsafe { BNProjectFolderGetParent(self.handle.as_ptr()) }; NonNull::new(result).map(|handle| unsafe { ProjectFolder::ref_from_raw(handle) }) } /// Set the folder that contains this folder pub fn set_folder(&self, folder: Option<&ProjectFolder>) -> bool { let folder_handle = folder.map(|x| x.handle.as_ptr()).unwrap_or(null_mut()); unsafe { BNProjectFolderSetParent(self.handle.as_ptr(), folder_handle) } } /// Recursively export this folder to disk, returns `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents pub fn export(&self, dest: &Path) -> bool { self.export_with_progress(dest, NoProgressCallback) } /// Recursively export this folder to disk, returns `true' if the export succeeded /// /// * `dest` - Destination path for the exported contents /// * `progress` - [`ProgressCallback`] that will be called as contents are exporting pub fn export_with_progress

(&self, dest: &Path, mut progress: P) -> bool where P: ProgressCallback, { let dest_raw = dest.to_cstr(); unsafe { BNProjectFolderExport( self.handle.as_ptr(), dest_raw.as_ptr(), &mut progress as *mut P as *mut c_void, Some(P::cb_progress_callback), ) } } /// Get the files contained in this folder pub fn files(&self) -> Array { let mut count = 0; let result = unsafe { BNProjectFolderGetFiles(self.handle.as_ptr(), &mut count) }; unsafe { Array::new(result, count, ()) } } } impl PartialEq for ProjectFolder { fn eq(&self, other: &Self) -> bool { self.id() == other.id() } } impl Debug for ProjectFolder { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("ProjectFolder") .field("id", &self.id()) .field("name", &self.name()) .field("description", &self.description()) .finish() } } unsafe impl Send for ProjectFolder {} unsafe impl Sync for ProjectFolder {} impl ToOwned for ProjectFolder { type Owned = Ref; fn to_owned(&self) -> Self::Owned { unsafe { RefCountable::inc_ref(self) } } } unsafe impl RefCountable for ProjectFolder { unsafe fn inc_ref(handle: &Self) -> Ref { Ref::new(Self { handle: NonNull::new(BNNewProjectFolderReference(handle.handle.as_ptr())).unwrap(), }) } unsafe fn dec_ref(handle: &Self) { BNFreeProjectFolder(handle.handle.as_ptr()); } } impl CoreArrayProvider for ProjectFolder { type Raw = *mut BNProjectFolder; type Context = (); type Wrapped<'a> = Guard<'a, Self>; } unsafe impl CoreArrayProviderInner for ProjectFolder { unsafe fn free(raw: *mut Self::Raw, count: usize, _context: &Self::Context) { BNFreeProjectFolderList(raw, count) } unsafe fn wrap_raw<'a>(raw: &'a Self::Raw, context: &'a Self::Context) -> Self::Wrapped<'a> { let raw_ptr = NonNull::new(*raw).unwrap(); Guard::new(Self::from_raw(raw_ptr), context) } }