summaryrefslogtreecommitdiff
path: root/rust/src/command.rs
diff options
context:
space:
mode:
authorMason Reed <mason@vector35.com>2025-06-18 00:14:48 -0400
committerMason Reed <mason@vector35.com>2025-07-02 01:56:54 -0400
commitba6d08199b0067adf3222559363a819f4b11c502 (patch)
tree7cf917dfbc757d757a9bc4b48c0a5aa6d80b6d3e /rust/src/command.rs
parent00686dfc68ee40b9b7378febadf3c27eb657dff9 (diff)
Add PluginCommand for projects and hide non-contextual commands in linear/graph view
Diffstat (limited to 'rust/src/command.rs')
-rw-r--r--rust/src/command.rs65
1 files changed, 60 insertions, 5 deletions
diff --git a/rust/src/command.rs b/rust/src/command.rs
index 46f43bbd..eecdf4a8 100644
--- a/rust/src/command.rs
+++ b/rust/src/command.rs
@@ -33,16 +33,18 @@
//! The return value of these functions should indicate whether they successfully initialized themselves.
use binaryninjacore_sys::{
- BNBinaryView, BNFunction, BNRegisterPluginCommand, BNRegisterPluginCommandForAddress,
- BNRegisterPluginCommandForFunction, BNRegisterPluginCommandForRange,
+ BNBinaryView, BNFunction, BNProject, BNRegisterPluginCommand,
+ BNRegisterPluginCommandForAddress, BNRegisterPluginCommandForFunction,
+ BNRegisterPluginCommandForProject, BNRegisterPluginCommandForRange,
};
-use std::ops::Range;
-use std::os::raw::c_void;
-
use crate::binary_view::BinaryView;
use crate::function::Function;
+use crate::project::Project;
use crate::string::IntoCStr;
+use std::ops::Range;
+use std::os::raw::c_void;
+use std::ptr::NonNull;
/// The trait required for generic commands. See [register_command] for example usage.
pub trait Command: 'static + Sync {
@@ -451,3 +453,56 @@ pub fn register_command_for_function<C: FunctionCommand>(name: &str, desc: &str,
);
}
}
+
+pub trait ProjectCommand: 'static + Sync {
+ fn action(&self, project: &Project);
+ fn valid(&self, project: &Project) -> bool;
+}
+
+pub fn register_command_for_project<C: ProjectCommand>(name: &str, desc: &str, command: C) {
+ extern "C" fn cb_action<C>(ctxt: *mut c_void, project: *mut BNProject)
+ where
+ C: ProjectCommand,
+ {
+ ffi_wrap!("Command::action", unsafe {
+ let cmd = &*(ctxt as *const C);
+
+ let handle = NonNull::new(project).expect("project handle is null");
+ let project = Project { handle };
+
+ cmd.action(&project);
+ })
+ }
+
+ extern "C" fn cb_valid<C>(ctxt: *mut c_void, project: *mut BNProject) -> bool
+ where
+ C: ProjectCommand,
+ {
+ ffi_wrap!("Command::valid", unsafe {
+ let cmd = &*(ctxt as *const C);
+
+ let handle = NonNull::new(project).expect("project handle is null");
+ let project = Project { handle };
+
+ cmd.valid(&project)
+ })
+ }
+
+ let name = name.to_cstr();
+ let desc = desc.to_cstr();
+
+ let name_ptr = name.as_ptr();
+ let desc_ptr = desc.as_ptr();
+
+ let ctxt = Box::into_raw(Box::new(command));
+
+ unsafe {
+ BNRegisterPluginCommandForProject(
+ name_ptr,
+ desc_ptr,
+ Some(cb_action::<C>),
+ Some(cb_valid::<C>),
+ ctxt as *mut _,
+ );
+ }
+}