summaryrefslogtreecommitdiff
path: root/plugins/bntl_utils/src/command/diff.rs
diff options
context:
space:
mode:
Diffstat (limited to 'plugins/bntl_utils/src/command/diff.rs')
-rw-r--r--plugins/bntl_utils/src/command/diff.rs103
1 files changed, 103 insertions, 0 deletions
diff --git a/plugins/bntl_utils/src/command/diff.rs b/plugins/bntl_utils/src/command/diff.rs
new file mode 100644
index 00000000..ae93dafe
--- /dev/null
+++ b/plugins/bntl_utils/src/command/diff.rs
@@ -0,0 +1,103 @@
+use crate::command::OutputDirectoryField;
+use crate::diff::TILDiff;
+use binaryninja::background_task::BackgroundTask;
+use binaryninja::binary_view::BinaryView;
+use binaryninja::command::Command;
+use binaryninja::interaction::{Form, FormInputField};
+use binaryninja::types::TypeLibrary;
+use std::path::PathBuf;
+use std::thread;
+
+pub struct InputFileAField;
+
+impl InputFileAField {
+ pub fn field() -> FormInputField {
+ FormInputField::OpenFileName {
+ prompt: "Library A".to_string(),
+ // TODO: This is called extension but is really a filter.
+ extension: Some("*.bntl".to_string()),
+ default: None,
+ value: None,
+ }
+ }
+
+ pub fn from_form(form: &Form) -> Option<PathBuf> {
+ let field = form.get_field_with_name("Library A")?;
+ let field_value = field.try_value_string()?;
+ Some(PathBuf::from(field_value))
+ }
+}
+
+pub struct InputFileBField;
+
+impl InputFileBField {
+ pub fn field() -> FormInputField {
+ FormInputField::OpenFileName {
+ prompt: "Library B".to_string(),
+ // TODO: This is called extension but is really a filter.
+ extension: Some("*.bntl".to_string()),
+ default: None,
+ value: None,
+ }
+ }
+
+ pub fn from_form(form: &Form) -> Option<PathBuf> {
+ let field = form.get_field_with_name("Library B")?;
+ let field_value = field.try_value_string()?;
+ Some(PathBuf::from(field_value))
+ }
+}
+
+pub struct Diff;
+
+impl Diff {
+ pub fn execute() {
+ let mut form = Form::new("Diff type libraries");
+ form.add_field(InputFileAField::field());
+ form.add_field(InputFileBField::field());
+ form.add_field(OutputDirectoryField::field());
+ if !form.prompt() {
+ return;
+ }
+ let a_path = InputFileAField::from_form(&form).unwrap();
+ let b_path = InputFileBField::from_form(&form).unwrap();
+ let output_dir = OutputDirectoryField::from_form(&form).unwrap();
+
+ let _bg_task = BackgroundTask::new("Diffing type libraries...", false).enter();
+ let Some(type_lib_a) = TypeLibrary::load_from_file(&a_path) else {
+ tracing::error!("Failed to load type library: {}", a_path.display());
+ return;
+ };
+ let Some(type_lib_b) = TypeLibrary::load_from_file(&b_path) else {
+ tracing::error!("Failed to load type library: {}", b_path.display());
+ return;
+ };
+
+ let diff_result = match TILDiff::new().diff((&a_path, &type_lib_a), (&b_path, &type_lib_b))
+ {
+ Ok(diff_result) => diff_result,
+ Err(err) => {
+ tracing::error!("Failed to diff type libraries: {}", err);
+ return;
+ }
+ };
+ tracing::info!("Similarity Ratio: {}", diff_result.ratio);
+ let output_path = output_dir
+ .join(type_lib_a.dependency_name())
+ .with_extension("diff");
+ std::fs::write(&output_path, diff_result.diff).unwrap();
+ tracing::info!("Diff written to: {}", output_path.display());
+ }
+}
+
+impl Command for Diff {
+ fn action(&self, _view: &BinaryView) {
+ thread::spawn(move || {
+ Diff::execute();
+ });
+ }
+
+ fn valid(&self, _view: &BinaryView) -> bool {
+ true
+ }
+}