Massively enhance this program. Add way more features
use eframe::{egui, Theme};
use std::fs::File;
use std::io::Read;

use capstone::prelude::*;
use goblin::Object;
use rfd::FileDialog;

#[derive(PartialEq, Clone)]
enum Architecture {
    X86,
    X86_64,
}
#[derive(Clone)]
struct BinaryAnalyzerApp {
    instructions: Vec<Instruction>,
    error_message: Option<String>,
    arch: Architecture,
    file_path: Option<String>,
    search_query: String,
    filtered_instructions: Vec<Instruction>,
}
#[derive(Clone)]

struct Instruction {
    address: u64,
    mnemonic: String,
    op_str: String,
}

#[derive(Clone)]
struct Section {
    start: u64,
    size: u64,
}

impl Default for BinaryAnalyzerApp {
    fn default() -> Self {
        Self {
            instructions: Vec::new(),
            error_message: None,
            arch: Architecture::X86, // Default to x86
            file_path: None,
            search_query: String::new(),
            filtered_instructions: Vec::new(),
        }
    }
}

impl eframe::App for BinaryAnalyzerApp {

    fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {

        egui::TopBottomPanel::top("header").show(ctx, |ui| {
            ui.horizontal(|ui| {
                ui.heading("Advanced x86/x86_64 Binary Analyzer");
            });
        });

        egui::SidePanel::left("controls_panel")
            .resizable(false)
            .default_width(200.0)
            .show(ctx, |ui| {
                ui.group(|ui| {
                    ui.heading("Controls");

                    if ui.button("Load Binary").clicked() {
                        self.load_binary();
                    }

                    ui.separator();

                    ui.label("Architecture:");
                    ui.horizontal(|ui| {
                        if ui
                            .radio_value(&mut self.arch, Architecture::X86, "x86 (32-bit)")
                            .clicked()
                        {
                            self.update_disassembly();
                        }
                        if ui
                            .radio_value(&mut self.arch, Architecture::X86_64, "x86_64 (64-bit)")
                            .clicked()
                        {
                            self.update_disassembly();
                        }
                    });

                    ui.separator();

                    ui.label("Search Instructions:");
                    if ui.text_edit_singleline(&mut self.search_query).changed() {
                        self.update_filtered_instructions();
                    }
                });

                if let Some(error) = &self.error_message {
                    ui.add_space(10.0);
                    ui.group(|ui| {
                        ui.colored_label(egui::Color32::RED, error);
                    });
                }
            });

        egui::CentralPanel::default().show(ctx, |ui| {
            if let Some(path) = &self.file_path {
                ui.horizontal(|ui| {
                    ui.label("Loaded File:");
                    ui.monospace(path);
                });
            }

            ui.separator();

            ui.heading("Disassembled Instructions");
            egui::ScrollArea::vertical().show(ui, |ui| {
                for instruction in &self.filtered_instructions {
                    ui.horizontal(|ui| {
                        ui.monospace(format!("0x{:08x}:", instruction.address));

                        // Syntax Highlighting
                        ui.style_mut().visuals.override_text_color = Some(egui::Color32::LIGHT_BLUE);
                        ui.monospace(&instruction.mnemonic);
                        ui.style_mut().visuals.override_text_color = Some(egui::Color32::WHITE);
                        ui.monospace(&instruction.op_str);
                    });
                }
            });
        });
    }
}


impl BinaryAnalyzerApp {
    fn load_binary(&mut self) {
        self.error_message = None; // Clear previous errors
        self.instructions.clear();
        self.filtered_instructions.clear();

        if let Some(path) = FileDialog::new()
            .add_filter("Executable Files", &["exe", "bin", "out", "elf"])
            .pick_file()
        {
            self.file_path = Some(path.display().to_string());
            match File::open(&path) {
                Ok(mut file) => {
                    let mut buffer = Vec::new();
                    if let Err(e) = file.read_to_end(&mut buffer) {
                        self.error_message = Some(format!("Failed to read file: {}", e));
                        return;
                    }

                    // Use goblin to parse the binary format
                    match Object::parse(&buffer) {
                        Ok(object) => {
                            let (entry_point, code_sections) = match object {
                                Object::Elf(elf) => {
                                    self.arch = if elf.is_64 { Architecture::X86_64 } else { Architecture::X86 };
                                    let entry = elf.entry;
                                    let sections = elf.section_headers
                                        .iter()
                                        .filter(|s| s.is_executable())
                                        .map(|s| Section { start: s.sh_addr, size: s.sh_size })
                                        .collect::<Vec<_>>();
                                    (entry, sections)
                                }
                                Object::PE(pe) => {
                                    self.arch = if pe.is_64 { Architecture::X86_64 } else { Architecture::X86 };
                                    let entry = pe.entry as u64;
                                    let sections = pe.sections
                                        .iter()
                                        .filter(|s| s.characteristics & 0x20000000 != 0)
                                        .map(|s| Section { start: s.virtual_address as u64, size: s.size_of_raw_data as u64 })
                                        .collect::<Vec<_>>();
                                    (entry, sections)
                                }
                                _ => {
                                    self.error_message =
                                        Some("Unsupported binary format".to_string());
                                    return;
                                }
                            };

                            let code_bytes = &buffer;

                            let cs = match Capstone::new()
                                .x86()
                                .mode(match self.arch {
                                    Architecture::X86 => arch::x86::ArchMode::Mode32,
                                    Architecture::X86_64 => arch::x86::ArchMode::Mode64,
                                })
                                .syntax(arch::x86::ArchSyntax::Intel)
                                .detail(false)
                                .build()
                            {
                                Ok(cs) => cs,
                                Err(e) => {
                                    self.error_message =
                                        Some(format!("Capstone error: {}", e));
                                    return;
                                }
                            };

                            match cs.disasm_all(code_bytes, entry_point) {
                                Ok(insns) => {
                                    self.instructions.clear();
                                    for i in insns.iter() {
                                        let instruction = Instruction {
                                            address: i.address(),
                                            mnemonic: i.mnemonic().unwrap_or("").to_string(),
                                            op_str: i.op_str().unwrap_or("").to_string(),
                                        };
                                        self.instructions.push(instruction);
                                    }

                                    self.update_filtered_instructions();
                                }
                                Err(e) => {
                                    self.error_message =
                                        Some(format!("Disassembly error: {}", e));
                                }
                            };
                        }
                        Err(e) => {
                            self.error_message =
                                Some(format!("Failed to parse binary: {}", e));
                        }
                    }
                }
                Err(e) => {
                    self.error_message = Some(format!("Failed to open file: {}", e));
                }
            }
        }
    }

    fn update_disassembly(&mut self) {
        if let Some(path) = &self.file_path {
            match File::open(path) {
                Ok(mut file) => {
                    let mut buffer = Vec::new();
                    if let Err(e) = file.read_to_end(&mut buffer) {
                        self.error_message = Some(format!("Failed to read file: {}", e));
                        return;
                    }

                    let entry_point = 0x0; // Default entry point if not parsed
                    let code_bytes = &buffer;

                    let cs = match Capstone::new()
                        .x86()
                        .mode(match self.arch {
                            Architecture::X86 => arch::x86::ArchMode::Mode32,
                            Architecture::X86_64 => arch::x86::ArchMode::Mode64,
                        })
                        .syntax(arch::x86::ArchSyntax::Intel)
                        .detail(false)
                        .build()
                    {
                        Ok(cs) => cs,
                        Err(e) => {
                            self.error_message = Some(format!("Capstone error: {}", e));
                            return;
                        }
                    };

                    match cs.disasm_all(code_bytes, entry_point) {
                        Ok(insns) => {
                            self.instructions.clear();
                            for i in insns.iter() {
                                let instruction = Instruction {
                                    address: i.address(),
                                    mnemonic: i.mnemonic().unwrap_or("").to_string(),
                                    op_str: i.op_str().unwrap_or("").to_string(),
                                };
                                self.instructions.push(instruction);
                            }

                            self.update_filtered_instructions();
                        }
                        Err(e) => {
                            self.error_message = Some(format!("Disassembly error: {}", e));
                        }
                    };
                }
                Err(e) => {
                    self.error_message = Some(format!("Failed to open file: {}", e));
                }
            }
        }
    }

    fn update_filtered_instructions(&mut self) {
        if self.search_query.is_empty() {
            self.filtered_instructions = self.instructions.clone();
        } else {
            let query = self.search_query.to_lowercase();
            self.filtered_instructions = self
                .instructions
                .iter()
                .filter(|instr| {
                    instr.mnemonic.to_lowercase().contains(&query)
                        || instr.op_str.to_lowercase().contains(&query)
                })
                .cloned()
                .collect();
        }
    }
}

fn main() {
    let app: BinaryAnalyzerApp = BinaryAnalyzerApp::default();
    let options = eframe::NativeOptions {
        default_theme: Theme::Dark,
        ..Default::default()
    };
    eframe::run_native("Binary Analyzer", options, Box::new(|_cc| Ok(Box::new(app)))).unwrap();
}